diff --git a/.clang-tidy b/.clang-tidy index 9ced7a88cff..9423f438d68 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -113,6 +113,56 @@ WarningsAsErrors: >- -readability-suspicious-call-argument, -modernize-*, -readability-*, + -bugprone-assignment-in-if-condition, + -bugprone-branch-clone, + -bugprone-copy-constructor-init, + -bugprone-empty-catch, + -bugprone-exception-escape, + -bugprone-fold-init-type, + -bugprone-incorrect-roundings, + -bugprone-integer-division, + -bugprone-macro-parentheses, + -bugprone-narrowing-conversions, + -bugprone-non-zero-enum-to-bool-conversion, + -bugprone-redundant-branch-condition, + -bugprone-reserved-identifier, + -bugprone-suspicious-include, + -bugprone-suspicious-missing-comma, + -bugprone-switch-missing-default-case, + -bugprone-too-small-loop-variable, + -bugprone-unchecked-optional-access, + -bugprone-unsafe-functions, + -bugprone-unused-local-non-trivial-variable, + -cppcoreguidelines-avoid-const-or-ref-data-members, + -cppcoreguidelines-avoid-non-const-global-variables, + -cppcoreguidelines-init-variables, + -cppcoreguidelines-macro-usage, + -cppcoreguidelines-missing-std-forward, + -cppcoreguidelines-prefer-member-initializer, + -cppcoreguidelines-pro-bounds-array-to-pointer-decay, + -cppcoreguidelines-pro-type-const-cast, + -cppcoreguidelines-pro-type-cstyle-cast, + -cppcoreguidelines-pro-type-member-init, + -cppcoreguidelines-pro-type-reinterpret-cast, + -cppcoreguidelines-pro-type-static-cast-downcast, + -cppcoreguidelines-pro-type-union-access, + -cppcoreguidelines-slicing, + -cppcoreguidelines-virtual-class-destructor, +# Positives for the following checks are currently being fixed and should be reported as errors. +# clang-analyzer-* +# clang-diagnostic-* +# google-default-arguments +# misc-include-cleaner +# misc-redundant-expression +# misc-unused-parameters +# performance-for-range-copy +# performance-inefficient-string-concatenation +# performance-inefficient-vector-operation +# performance-move-const-arg +# performance-no-automatic-move +# performance-type-promotion-in-math-fn +# performance-unnecessary-copy-initialization +# performance-unnecessary-value-param CheckOptions: modernize-avoid-c-arrays.AllowStringArrays: true # Common tolerated conversions diff --git a/ALICE3/Core/Decayer.h b/ALICE3/Core/Decayer.h index 52ca0a75adb..8f88e4e311b 100644 --- a/ALICE3/Core/Decayer.h +++ b/ALICE3/Core/Decayer.h @@ -31,13 +31,12 @@ #include #include +#include #include #include #include -namespace o2 -{ -namespace upgrade +namespace o2::upgrade { class Decayer @@ -47,44 +46,27 @@ class Decayer Decayer() = default; template - std::vector decayParticle(const TDatabase& pdgDB, const OTFParticle& particle) + std::vector decayParticle(const OTFParticle& particle, const TDatabase& pdgDB) { - const auto& particleInfo = pdgDB->GetParticle(particle.pdgCode()); + auto particleInfo = pdgDB->GetParticle(particle.pdgCode()); if (!particleInfo) { return {}; } const int charge = particleInfo->Charge() / 3; const double mass = particleInfo->Mass(); - - const double u = mRand3.Uniform(0.001, 0.999); - const double ctau = o2::constants::physics::LightSpeedCm2S * particleInfo->Lifetime(); // cm - const double betaGamma = particle.p() / mass; - const double rxyz = -betaGamma * ctau * std::log(1 - u); - double px, py, e; + std::array decayVtx = generateDecayVertex(particle, pdgDB); + mVx = decayVtx[0]; + mVy = decayVtx[1]; + mVz = decayVtx[2]; + double px{}, py{}, e{}; if (!charge) { - mVx = particle.vx() + rxyz * (particle.px() / particle.p()); - mVy = particle.vy() + rxyz * (particle.py() / particle.p()); - mVz = particle.vz() + rxyz * (particle.pz() / particle.p()); px = particle.px(); py = particle.py(); } else { - o2::track::TrackParCov track; - o2::math_utils::CircleXYf_t circle; - o2::upgrade::convertOTFParticleToO2Track(particle, track, pdgDB); - - float sna{}, csa{}; - track.getCircleParams(mBz, circle, sna, csa); - const double rxy = rxyz / std::sqrt(1. + track.getTgl() * track.getTgl()); - const double theta = rxy / circle.rC; - - mVx = ((particle.vx() - circle.xC) * std::cos(theta) - (particle.vy() - circle.yC) * std::sin(theta)) + circle.xC; - mVy = ((particle.vy() - circle.yC) * std::cos(theta) + (particle.vx() - circle.xC) * std::sin(theta)) + circle.yC; - mVz = particle.vz() + rxyz * (particle.pz() / track.getP()); - - px = particle.px() * std::cos(theta) - particle.py() * std::sin(theta); - py = particle.py() * std::cos(theta) + particle.px() * std::sin(theta); + px = particle.px() * std::cos(mTheta) - particle.py() * std::sin(mTheta); + py = particle.py() * std::cos(mTheta) + particle.px() * std::sin(mTheta); } double brTotal = 0.; @@ -133,6 +115,42 @@ class Decayer return decayProducts; } + template + std::array generateDecayVertex(const TParticle& particle, const TDatabase& pdgDB) + { + std::array decayVertex{}; + auto particleInfo = pdgDB->GetParticle(particle.pdgCode()); + if (!particleInfo) { + return {}; + } + + const int charge = particleInfo->Charge() / 3; + const double mass = particleInfo->Mass(); + const double u = mRand3.Uniform(0.001, 0.999); + const double ctau = o2::constants::physics::LightSpeedCm2S * particleInfo->Lifetime(); // cm + const double betaGamma = particle.p() / mass; + const double rxyz = -betaGamma * ctau * std::log(1 - u); + + if (!charge) { + decayVertex[0] = particle.vx() + rxyz * (particle.px() / particle.p()); + decayVertex[1] = particle.vy() + rxyz * (particle.py() / particle.p()); + decayVertex[2] = particle.vz() + rxyz * (particle.pz() / particle.p()); + } else { + o2::math_utils::CircleXYf_t circle; + o2::track::TrackParCov track = o2::upgrade::convertMCParticleToO2Track(particle, pdgDB); + + float sna{}, csa{}; + track.getCircleParams(mBz, circle, sna, csa); + const double rxy = rxyz / std::sqrt(1. + track.getTgl() * track.getTgl()); + mTheta = rxy / circle.rC; + + decayVertex[0] = ((particle.vx() - circle.xC) * std::cos(mTheta) - (particle.vy() - circle.yC) * std::sin(mTheta)) + circle.xC; + decayVertex[1] = ((particle.vy() - circle.yC) * std::cos(mTheta) + (particle.vx() - circle.xC) * std::sin(mTheta)) + circle.yC; + decayVertex[2] = particle.vz() + rxyz * (particle.pz() / track.getP()); + } + return decayVertex; + } + // Setters void setBField(const double b) { mBz = b; } void setSeed(const int seed) @@ -142,18 +160,18 @@ class Decayer } // Getters - float getSecondaryVertexX() const { return static_cast(mVx); } - float getSecondaryVertexY() const { return static_cast(mVy); } - float getSecondaryVertexZ() const { return static_cast(mVz); } - float getDecayRadius() const { return static_cast(std::hypot(mVx, mVy)); } + [[nodiscard]] float getSecondaryVertexX() const { return static_cast(mVx); } + [[nodiscard]] float getSecondaryVertexY() const { return static_cast(mVy); } + [[nodiscard]] float getSecondaryVertexZ() const { return static_cast(mVz); } + [[nodiscard]] float getDecayRadius() const { return static_cast(std::hypot(mVx, mVy)); } private: double mBz{20.}; // kG double mVx{-1.}, mVy{-1.}, mVz{-1.}; - TRandom3 mRand3{}; + double mTheta{}; + TRandom3 mRand3; }; -} // namespace upgrade -} // namespace o2 +} // namespace o2::upgrade #endif // ALICE3_CORE_DECAYER_H_ diff --git a/ALICE3/Core/DelphesO2LutWriter.cxx b/ALICE3/Core/DelphesO2LutWriter.cxx index c2df9431ef4..3110006d11b 100644 --- a/ALICE3/Core/DelphesO2LutWriter.cxx +++ b/ALICE3/Core/DelphesO2LutWriter.cxx @@ -376,7 +376,7 @@ void DelphesO2LutWriter::diagonalise(lutEntry_t& lutEntry) // m.Print(); TMatrixDSymEigen eigen(m); // eigenvalues vector - TVectorD eigenVal = eigen.GetEigenValues(); + const TVectorD& eigenVal = eigen.GetEigenValues(); for (int i = 0; i < kEig; ++i) lutEntry.eigval[i] = eigenVal[i]; // eigenvectors matrix diff --git a/ALICE3/Core/FastTracker.cxx b/ALICE3/Core/FastTracker.cxx index 2379cba22ac..20eb7087f16 100644 --- a/ALICE3/Core/FastTracker.cxx +++ b/ALICE3/Core/FastTracker.cxx @@ -9,6 +9,12 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file FastTracker.cxx +/// \brief On the fly implementation of DelphesO2 solveTrack +/// \author David Dobrigkeit Chinellato +/// \author Nicolò Jacazio +/// \author Jesper Karlsson Gumprecht + #include "FastTracker.h" #include "DetLayer.h" @@ -34,7 +40,6 @@ #include #include -#include #include #include @@ -44,14 +49,12 @@ #include #include -namespace o2 -{ -namespace fastsim +namespace o2::fastsim { // +-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+ -DetLayer* FastTracker::AddLayer(TString name, float r, float z, float x0, float xrho, float resRPhi, float resZ, float eff, int type) +DetLayer* FastTracker::addLayer(const TString& name, float r, float z, float x0, float xrho, float resRPhi, float resZ, float eff, int type) { LOG(debug) << "Adding layer " << name << " r=" << r << " z=" << z << " x0=" << x0 << " xrho=" << xrho << " resRPhi=" << resRPhi << " resZ=" << resZ << " eff=" << eff << " type=" << type; DetLayer newLayer(name, r, z, x0, xrho, resRPhi, resZ, eff, type); @@ -77,7 +80,7 @@ DetLayer* FastTracker::AddLayer(TString name, float r, float z, float x0, float void FastTracker::addDeadPhiRegionInLayer(const std::string& layerName, float phiStart, float phiEnd) { - const int layerIdx = GetLayerIndex(layerName); + const int layerIdx = getLayerIndex(layerName); if (layerIdx < 0) { LOG(fatal) << "Cannot add dead phi region to non-existing layer " << layerName; return; @@ -85,7 +88,7 @@ void FastTracker::addDeadPhiRegionInLayer(const std::string& layerName, float ph layers[layerIdx].addDeadPhiRegion(phiStart, phiEnd); } -int FastTracker::GetLayerIndex(const std::string& name) const +int FastTracker::getLayerIndex(const std::string& name) const { int i = 0; for (const auto& layer : layers) { @@ -98,7 +101,7 @@ int FastTracker::GetLayerIndex(const std::string& name) const return -1; } -void FastTracker::Print() +void FastTracker::print() { // print out layer setup LOG(info) << "+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+"; @@ -109,7 +112,7 @@ void FastTracker::Print() LOG(info) << "+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+"; } -void FastTracker::AddTPC(float phiResMean, float zResMean) +void FastTracker::addTPC(float phiResMean, float zResMean) { LOG(info) << " Adding standard time projection chamber"; @@ -118,12 +121,11 @@ void FastTracker::AddTPC(float phiResMean, float zResMean) // https://github.com/AliceO2Group/DelphesO2/blob/master/src/DetectorK/DetectorK.cxx#L522 // % Radiation Lengths ... Average per TPC row (i.e. total/159 ) const int kNPassiveBound = 2; - const float radLBoundary[kNPassiveBound] = {1.692612e-01, 8.711904e-02}; - const float xrhoBoundary[kNPassiveBound] = {6.795774e+00, 3.111401e+00}; - const float rBoundary[kNPassiveBound] = {50, 70.0}; // cm + const std::array radLBoundary = {1.692612e-01, 8.711904e-02}; + const std::array xrhoBoundary = {6.795774e+00, 3.111401e+00}; + const std::array rBoundary = {50, 70.0}; // cm float radLPerRow = 0.000036; - float tpcInnerRadialPitch = 0.75; // cm float tpcMiddleRadialPitch = 1.0; // cm float tpcOuterRadialPitch = 1.5; // cm @@ -139,22 +141,23 @@ void FastTracker::AddTPC(float phiResMean, float zResMean) // add boundaries between ITS and TPC for (int i = 0; i < kNPassiveBound; i++) { - AddLayer(Form("tpc_boundary%d", i), rBoundary[i], zLength, radLBoundary[i], xrhoBoundary[i], 0); // dummy errors + addLayer(Form("tpc_boundary%d", i), rBoundary[i], zLength, radLBoundary[i], xrhoBoundary[i], 0); // dummy errors } - for (Int_t k = 0; k < tpcRows; k++) { - Float_t rowRadius = 0; - if (k < innerRows) + for (int k = 0; k < tpcRows; k++) { + float rowRadius = 0; + if (k < innerRows) { rowRadius = rowOneRadius + k * tpcInnerRadialPitch; - else if (k >= innerRows && k < (innerRows + middleRows)) + } else if (k >= innerRows && k < (innerRows + middleRows)) { rowRadius = row64Radius + (k - innerRows + 1) * tpcMiddleRadialPitch; - else if (k >= (innerRows + middleRows) && k < tpcRows) + } else if (k >= (innerRows + middleRows) && k < tpcRows) { rowRadius = row128Radius + (k - innerRows - middleRows + 1) * tpcOuterRadialPitch; + } - AddLayer(Form("tpc_%d", k), rowRadius, zLength, radLPerRow, 0, phiResMean, zResMean, 1.0f, 2); + addLayer(Form("tpc_%d", k), rowRadius, zLength, radLPerRow, 0, phiResMean, zResMean, 1.0f, 2); } } -void FastTracker::AddGenericDetector(o2::fastsim::GeometryEntry configMap, o2::ccdb::BasicCCDBManager* ccdbManager) +void FastTracker::addGenericDetector(const o2::fastsim::GeometryEntry& configMap, o2::ccdb::BasicCCDBManager* ccdbManager) { // Layers for (const auto& layer : configMap.getLayerNames()) { @@ -175,19 +178,17 @@ void FastTracker::AddGenericDetector(o2::fastsim::GeometryEntry configMap, o2::c const int type = configMap.getIntValue(layer, "type"); const std::string deadPhiRegions = configMap.getValue(layer, "deadPhiRegions", false); - // void AddLayer(TString name, float r, float z, float x0, float xrho, float resRPhi = 0.0f, float resZ = 0.0f, float eff = 0.0f, int type = 0); LOG(info) << " Adding layer " << layer << " r=" << r << " z=" << z << " x0=" << x0 << " xrho=" << xrho << " resRPhi=" << resRPhi << " resZ=" << resZ << " eff=" << eff << " type=" << type << " deadPhiRegions=" << deadPhiRegions; - - DetLayer* addedLayer = AddLayer(layer.c_str(), r, z, x0, xrho, resRPhi, resZ, eff, type); + DetLayer* addedLayer = addLayer(layer.c_str(), r, z, x0, xrho, resRPhi, resZ, eff, type); if (!deadPhiRegions.empty()) { // Taking it as ccdb path or local file // Check if it begins with ccdb: - if (std::string(deadPhiRegions).rfind("ccdb:", 0) == 0) { - std::string ccdbPath = std::string(deadPhiRegions).substr(5); // remove "ccdb:" prefix + if (deadPhiRegions.starts_with("ccdb:")) { + std::string ccdbPath = deadPhiRegions.substr(5); // remove "ccdb:" prefix if (ccdbManager == nullptr) { LOG(fatal) << "CCDB manager is null, cannot retrieve file " << ccdbPath; return; } - TGraph* g = ccdbManager->getForTimeStamp(ccdbPath, 1); + auto g = ccdbManager->getForTimeStamp(ccdbPath, 1); addedLayer->setDeadPhiRegions(g); } else { // Taking it as local file @@ -196,7 +197,7 @@ void FastTracker::AddGenericDetector(o2::fastsim::GeometryEntry configMap, o2::c LOG(fatal) << "Cannot open dead phi regions file " << deadPhiRegions; return; } - TGraph* g = reinterpret_cast(infile.Get(infile.GetListOfKeys()->At(0)->GetName())); + auto g = dynamic_cast(infile.Get(infile.GetListOfKeys()->At(0)->GetName())); infile.Close(); addedLayer->setDeadPhiRegions(g); } @@ -206,32 +207,35 @@ void FastTracker::AddGenericDetector(o2::fastsim::GeometryEntry configMap, o2::c } } -float FastTracker::Dist(float z, float r) +float FastTracker::dist(float z, float r) { // porting of DetektorK::Dist // see here: // https://github.com/AliceO2Group/DelphesO2/blob/master/src/DetectorK/DetectorK.cxx#L743 int index = 1; int nSteps = 301; + const int nSigma = 4; float dist = 0.0; - float dz0 = (4 * sigmaD - (-4) * sigmaD / (nSteps = 1)); + float dz0 = (nSigma * sigmaD - (-nSigma) * sigmaD / (nSteps - 1)); float z0 = 0.0; for (int i = 0; i < nSteps; i++) { - if (i == nSteps - 1) + if (i == nSteps - 1) { index = 1; + } z0 = -4 * sigmaD + i * dz0; dist += index * (dz0 / 3.) * (1 / o2::math_utils::sqrt(o2::constants::math::TwoPI) / sigmaD) * std::exp(-z0 * z0 / 2. / sigmaD / sigmaD) * (1 / o2::math_utils::sqrt((z - z0) * (z - z0) + r * r)); - if (index != 4) - index = 4; - else + if (index != nSigma) { + index = nSigma; + } else { index = 2; + } } return dist; } -float FastTracker::OneEventHitDensity(float multiplicity, float radius) +float FastTracker::oneEventHitDensity(float multiplicity, float radius) { - // porting of DetektorK::OneEventHitDensity + // porting of DetektorK::oneEventHitDensity // see here: // https://github.com/AliceO2Group/DelphesO2/blob/master/src/DetectorK/DetectorK.cxx#L694 float den = multiplicity / (o2::constants::math::TwoPI * radius * radius); @@ -240,75 +244,75 @@ float FastTracker::OneEventHitDensity(float multiplicity, float radius) return den; } -float FastTracker::IntegratedHitDensity(float multiplicity, float radius) +float FastTracker::integratedHitDensity(float multiplicity, float radius) { // porting of DetektorK::IntegratedHitDensity // see here: // https://github.com/AliceO2Group/DelphesO2/blob/master/src/DetectorK/DetectorK.cxx#L712 float zdcHz = luminosity * 1.e24 * mCrossSectionMinB; - float den = zdcHz * integrationTime / 1000. * multiplicity * Dist(0., radius) / (o2::constants::math::TwoPI * radius); - if (den < OneEventHitDensity(multiplicity, radius)) - den = OneEventHitDensity(multiplicity, radius); + float den = zdcHz * integrationTime / 1000. * multiplicity * dist(0., radius) / (o2::constants::math::TwoPI * radius); + if (den < oneEventHitDensity(multiplicity, radius)) { + den = oneEventHitDensity(multiplicity, radius); + } return den; } -float FastTracker::UpcHitDensity(float radius) +float FastTracker::upcHitDensity(float radius) { // porting of DetektorK::UpcHitDensity // see here: // https://github.com/AliceO2Group/DelphesO2/blob/master/src/DetectorK/DetectorK.cxx#L727 - float mUPCelectrons = 0; - mUPCelectrons = lhcUPCScale * 5456 / (radius * radius) / dNdEtaMinB; - if (mUPCelectrons < 0) + float mUPCelectrons = lhcUPCScale * 5456 / (radius * radius) / dNdEtaMinB; + if (mUPCelectrons < 0) { mUPCelectrons = 0.0; - mUPCelectrons *= IntegratedHitDensity(dNdEtaMinB, radius); + } + mUPCelectrons *= integratedHitDensity(dNdEtaMinB, radius); mUPCelectrons *= upcBackgroundMultiplier; return mUPCelectrons; } -float FastTracker::HitDensity(float radius) +float FastTracker::hitDensity(float radius) { // porting of DetektorK::HitDensity // see here: // https://github.com/AliceO2Group/DelphesO2/blob/master/src/DetectorK/DetectorK.cxx#L663 float arealDensity = 0.; if (radius > maxRadiusSlowDet) { - arealDensity = OneEventHitDensity(dNdEtaCent, radius); - arealDensity += otherBackground * OneEventHitDensity(dNdEtaMinB, radius); + arealDensity = oneEventHitDensity(dNdEtaCent, radius); + arealDensity += otherBackground * oneEventHitDensity(dNdEtaMinB, radius); } // In the version of Delphes used to produce // Look-up tables, UpcHitDensity(radius) always returns 0, // hence it is left commented out for now if (radius < maxRadiusSlowDet) { - arealDensity = OneEventHitDensity(dNdEtaCent, radius); - arealDensity += otherBackground * OneEventHitDensity(dNdEtaMinB, radius) + IntegratedHitDensity(dNdEtaMinB, radius); + arealDensity = oneEventHitDensity(dNdEtaCent, radius); + arealDensity += otherBackground * oneEventHitDensity(dNdEtaMinB, radius) + integratedHitDensity(dNdEtaMinB, radius); // +UpcHitDensity(radius); } return arealDensity; } -float FastTracker::ProbGoodChiSqHit(float radius, float searchRadiusRPhi, float searchRadiusZ) +float FastTracker::probGoodChiSqHit(float radius, float searchRadiusRPhi, float searchRadiusZ) { // porting of DetektorK::ProbGoodChiSqHit // see here: // https://github.com/AliceO2Group/DelphesO2/blob/master/src/DetectorK/DetectorK.cxx#L629 - float sx, goodHit; - sx = o2::constants::math::TwoPI * searchRadiusRPhi * searchRadiusZ * HitDensity(radius); - goodHit = 1. / (1 + sx); + const float sx = o2::constants::math::TwoPI * searchRadiusRPhi * searchRadiusZ * hitDensity(radius); + const float goodHit = 1. / (1 + sx); return goodHit; } // function to provide a reconstructed track from a perfect input track // returns number of intercepts (generic for now) -int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackParCov& outputTrack, const float nch, const float maxRadius) +int FastTracker::fastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackParCov& outputTrack, const float nch, const float maxRadius) { dNdEtaCent = nch; // set the number of charged particles per unit rapidity hits.clear(); nIntercepts = 0; nSiliconPoints = 0; nGasPoints = 0; - std::array posIni; // provision for != PV + std::array posIni{}; // provision for != PV inputTrack.getXYZGlo(posIni); const float initialRadius = std::hypot(posIni[0], posIni[1]); const float kTrackingMargin = 0.1; @@ -326,6 +330,7 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa } const int xrhosteps = 100; const bool applyAngularCorrection = true; + static constexpr float InterceptFailed = 999.f; // Delphes sets this to 20 instead of the number of layers, // but does not count all points in the tpc as layers which we do here @@ -359,7 +364,7 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa // check if layer is reached float targetX = 1e+3; inputTrack.getXatLabR(layers[il].getRadius(), targetX, magneticField); - if (targetX > 999.f) { + if (targetX > InterceptFailed) { LOGF(debug, "Failed to find intercept for layer %d at radius %.2f cm", il, layers[il].getRadius()); break; // failed to find intercept } @@ -369,24 +374,24 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa ok = inputTrack.correctForMaterial(layers[il].getRadiationLength(), 0, applyAngularCorrection); } if (ok && mApplyElossCorrection && layers[il].getDensity() > 0) { // correct in small steps - for (int ise = xrhosteps; ise--;) { + for (int ise = xrhosteps; ise > 0; --ise) { ok = inputTrack.correctForMaterial(0, -layers[il].getDensity() / xrhosteps, applyAngularCorrection); - if (!ok) + if (!ok) { break; + } } } LOGF(debug, "Propagation was %s up to layer %d", ok ? "successful" : "unsuccessful", il); // was there a problem on this layer? if (!ok && il > 0) { // may fail to reach target layer due to the eloss - float rad2 = inputTrack.getX() * inputTrack.getX() + inputTrack.getY() * inputTrack.getY(); - float maxR = layers[il - 1].getRadius() + kTrackingMargin * 2; - float minRad = (fMinRadTrack > 0 && fMinRadTrack < maxR) ? fMinRadTrack : maxR; + const float rad2 = inputTrack.getX() * inputTrack.getX() + inputTrack.getY() * inputTrack.getY(); + const float maxR = layers[il - 1].getRadius() + kTrackingMargin * 2; + const float minRad = (fMinRadTrack > 0 && fMinRadTrack < maxR) ? fMinRadTrack : maxR; if (rad2 - minRad * minRad < kTrackingMargin * kTrackingMargin) { // check previously reached layer return -5; // did not reach min requested layer - } else { - break; } + break; } if (std::abs(inputTrack.getZ()) > layers[il].getZ() && mApplyZacceptance) { @@ -423,16 +428,16 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa for (int ip = 0; ip < o2::track::kNParams; ip++) { trPars[ip] = outputTrack.getParam(ip); } - static constexpr float kLargeErr2Coord = 5 * 5; - static constexpr float kLargeErr2Dir = 0.7 * 0.7; - static constexpr float kLargeErr2PtI = 30.5 * 30.5; + static constexpr float LargeErr2Coord = 5 * 5; + static constexpr float LargeErr2Dir = 0.7 * 0.7; + static constexpr float LargeErr2PtI = 30.5 * 30.5; std::array largeCov = {0.}; - for (int ic = o2::track::kCovMatSize; ic--;) { + for (int ic = o2::track::kCovMatSize; ic > 0; --ic) { largeCov[ic] = 0.; } - largeCov[o2::track::CovLabels::kSigY2] = largeCov[o2::track::CovLabels::kSigZ2] = kLargeErr2Coord; - largeCov[o2::track::CovLabels::kSigSnp2] = largeCov[o2::track::CovLabels::kSigTgl2] = kLargeErr2Dir; - largeCov[o2::track::CovLabels::kSigQ2Pt2] = kLargeErr2PtI * trPars[o2::track::ParLabels::kQ2Pt] * trPars[o2::track::ParLabels::kQ2Pt]; + largeCov[o2::track::CovLabels::kSigY2] = largeCov[o2::track::CovLabels::kSigZ2] = LargeErr2Coord; + largeCov[o2::track::CovLabels::kSigSnp2] = largeCov[o2::track::CovLabels::kSigTgl2] = LargeErr2Dir; + largeCov[o2::track::CovLabels::kSigQ2Pt2] = LargeErr2PtI * trPars[o2::track::ParLabels::kQ2Pt] * trPars[o2::track::ParLabels::kQ2Pt]; inwardTrack.setCov(largeCov); inwardTrack.checkCovariance(); @@ -443,8 +448,9 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa float targetX = 1e+3; inputTrack.getXatLabR(layers[il].getRadius(), targetX, magneticField); - if (targetX > 999) + if (targetX > InterceptFailed) { continue; // failed to find intercept + } if (!inputTrack.propagateTo(targetX, magneticField)) { continue; // failed to propagate @@ -455,25 +461,22 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa } // get perfect data point position - std::array spacePoint; + std::array spacePoint{}; inputTrack.getXYZGlo(spacePoint); std::vector thisHit = {spacePoint[0], spacePoint[1], spacePoint[2]}; // towards adding cluster: move to track alpha float alpha = inwardTrack.getAlpha(); - float xyz1[3]{ - std::cos(alpha) * spacePoint[0] + std::sin(alpha) * spacePoint[1], - -std::sin(alpha) * spacePoint[0] + std::cos(alpha) * spacePoint[1], - spacePoint[2]}; + std::array xyz1 = {std::cos(alpha) * spacePoint[0] + std::sin(alpha) * spacePoint[1], + -std::sin(alpha) * spacePoint[0] + std::cos(alpha) * spacePoint[1], + spacePoint[2]}; if (!inwardTrack.propagateTo(xyz1[0], magneticField)) { continue; } if (!layers[il].isInert()) { // only update covm for tracker hits - const o2::track::TrackParametrization::dim2_t hitpoint = { - static_cast(xyz1[1]), - static_cast(xyz1[2])}; + const o2::track::TrackParametrization::dim2_t hitpoint = {xyz1[1], xyz1[2]}; const o2::track::TrackParametrization::dim3_t hitpointcov = {layers[il].getResolutionRPhi() * layers[il].getResolutionRPhi(), 0.f, layers[il].getResolutionZ() * layers[il].getResolutionZ()}; inwardTrack.update(hitpoint, hitpointcov); @@ -489,7 +492,7 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa } } if (mApplyElossCorrection && layers[il].getDensity() > 0) { - for (int ise = xrhosteps; ise--;) { // correct in small steps + for (int ise = xrhosteps; ise > 0; --ise) { // correct in small steps if (!inputTrack.correctForMaterial(0, layers[il].getDensity() / xrhosteps, applyAngularCorrection)) { return -7; } @@ -510,7 +513,7 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa if (!layers[il].isInert()) { // good hit probability calculation float sigYCmb = o2::math_utils::sqrt(inwardTrack.getSigmaY2() + layers[il].getResolutionRPhi() * layers[il].getResolutionRPhi()); float sigZCmb = o2::math_utils::sqrt(inwardTrack.getSigmaZ2() + layers[il].getResolutionZ() * layers[il].getResolutionZ()); - goodHitProbability[il] = ProbGoodChiSqHit(layers[il].getRadius() * 100, sigYCmb * 100, sigZCmb * 100); + goodHitProbability[il] = probGoodChiSqHit(layers[il].getRadius() * 100, sigYCmb * 100, sigZCmb * 100); goodHitProbability[0] *= goodHitProbability[il]; } } @@ -518,7 +521,7 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa // backpropagate to original radius float finalX = 1e+3; bool inPropStatus = inwardTrack.getXatLabR(initialRadius, finalX, magneticField); - if (finalX > 999) { + if (finalX > InterceptFailed) { LOG(debug) << "Failed to find intercept for initial radius " << initialRadius << " cm, x = " << finalX << " and status " << inPropStatus << " and sn = " << inwardTrack.getSnp() << " r = " << inwardTrack.getY() * inwardTrack.getY(); return -3; // failed to find intercept } @@ -528,7 +531,8 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa } // only attempt to continue if intercepts are at least four - if (nIntercepts < 4) { + static constexpr int MinIntercepts = 4; + if (nIntercepts < MinIntercepts) { return nIntercepts; } @@ -556,41 +560,44 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa for (int ii = 0; ii < o2::track::kCovMatSize; ii++) { covMat[ii] = outputTrack.getCov()[ii]; } - TMatrixDSym m(5); - double fcovm[5][5]; // double precision is needed for regularisation - for (int ii = 0, k = 0; ii < 5; ++ii) { - for (int j = 0; j < ii + 1; ++j, ++k) { - fcovm[ii][j] = covMat[k]; - fcovm[j][ii] = covMat[k]; + std::array, o2::track::kNParams> fcovm{}; // double precision is needed for regularisation + TMatrixDSym m(o2::track::kNParams); + for (int ii = 0, k = 0; ii < o2::track::kNParams; ++ii) { + for (int jj = 0; jj < ii + 1; ++jj, ++k) { + fcovm[ii][jj] = covMat[k]; + fcovm[jj][ii] = covMat[k]; } } // evaluate ruben's conditional, regularise - const bool makePositiveDefinite = (covMatFactor > -1e-5); // apply fix + static constexpr float CovMatFactorThreshold = -1e-5; + const bool makePositiveDefinite = (covMatFactor > CovMatFactorThreshold); // apply fix bool rubenConditional = false; - for (int ii = 0; ii < 5; ii++) { - for (int jj = 0; jj < 5; jj++) { - if (ii == jj) + for (int ii = 0; ii < o2::track::kNParams; ii++) { + for (int jj = 0; jj < o2::track::kNParams; jj++) { + if (ii == jj) { continue; // don't evaluate diagonals + } if (fcovm[ii][jj] * fcovm[ii][jj] > std::abs(fcovm[ii][ii] * fcovm[jj][jj])) { rubenConditional = true; if (makePositiveDefinite) { - fcovm[ii][jj] = TMath::Sign(1, fcovm[ii][jj]) * covMatFactor * sqrt(std::abs(fcovm[ii][ii] * fcovm[jj][jj])); + fcovm[ii][jj] = TMath::Sign(1, fcovm[ii][jj]) * covMatFactor * std::sqrt(std::abs(fcovm[ii][ii] * fcovm[jj][jj])); } } } } // Should have a valid cov matrix now - m.SetMatrixArray(reinterpret_cast(fcovm)); + m.SetMatrixArray(fcovm[0].data()); TMatrixDSymEigen eigen(m); TMatrixD eigVec = eigen.GetEigenVectors(); - TVectorD eigVal = eigen.GetEigenValues(); + const TVectorD& eigVal = eigen.GetEigenValues(); bool negEigVal = false; - for (int ii = 0; ii < 5; ii++) { - if (eigVal[ii] < 0.0f) + for (int ii = 0; ii < o2::track::kNParams; ii++) { + if (eigVal[ii] < 0.0f) { negEigVal = true; + } } if (negEigVal && rubenConditional && makePositiveDefinite) { @@ -608,26 +615,28 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa covMatOK++; // transform parameter vector and smear - float params_[5]; - for (int ii = 0; ii < 5; ++ii) { + std::array transformedParams{}; + for (int ii = 0; ii < o2::track::kNParams; ++ii) { float val = 0.; - for (int j = 0; j < 5; ++j) - val += eigVec[j][ii] * outputTrack.getParam(j); + for (int jj = 0; jj < o2::track::kNParams; ++jj) { + val += eigVec[jj][ii] * outputTrack.getParam(jj); + } // smear parameters according to eigenvalues - params_[ii] = gRandom->Gaus(val, sqrt(eigVal[ii])); + transformedParams[ii] = gRandom->Gaus(val, std::sqrt(eigVal[ii])); } // invert eigenvector matrix eigVec.Invert(); // transform back params vector - for (int ii = 0; ii < 5; ++ii) { + for (int ii = 0; ii < o2::track::kNParams; ++ii) { float val = 0.; - for (int j = 0; j < 5; ++j) - val += eigVec[j][ii] * params_[j]; + for (int jj = 0; jj < o2::track::kNParams; ++jj) { + val += eigVec[jj][ii] * transformedParams[jj]; + } outputTrack.setParam(val, ii); } // should make a sanity check that par[2] sin(phi) is in [-1, 1] - if (fabs(outputTrack.getParam(2)) > 1.) { + if (std::abs(outputTrack.getParam(2)) > 1.) { LOG(info) << " --- smearTrack failed sin(phi) sanity check: " << outputTrack.getParam(2); return -2; } @@ -636,7 +645,6 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa } // +-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+ -} /* namespace fastsim */ -} /* namespace o2 */ +} // namespace o2::fastsim ClassImp(o2::fastsim::FastTracker); diff --git a/ALICE3/Core/FastTracker.h b/ALICE3/Core/FastTracker.h index d593c568fb9..d3d9a11d4ed 100644 --- a/ALICE3/Core/FastTracker.h +++ b/ALICE3/Core/FastTracker.h @@ -9,6 +9,12 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file FastTracker.h +/// \brief On the fly implementation of DelphesO2 solveTrack +/// \author David Dobrigkeit Chinellato +/// \author Nicolò Jacazio +/// \author Jesper Karlsson Gumprecht + #ifndef ALICE3_CORE_FASTTRACKER_H_ #define ALICE3_CORE_FASTTRACKER_H_ @@ -27,9 +33,7 @@ #include #include -namespace o2 -{ -namespace fastsim +namespace o2::fastsim { // +-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+ @@ -46,30 +50,30 @@ class FastTracker virtual ~FastTracker() {} // Layer and layer configuration - DetLayer* AddLayer(TString name, float r, float z, float x0, float xrho, float resRPhi = 0.0f, float resZ = 0.0f, float eff = 0.0f, int type = 0); + DetLayer* addLayer(const TString& name, float r, float z, float x0, float xrho, float resRPhi = 0.0f, float resZ = 0.0f, float eff = 0.0f, int type = 0); /// Add a dead region in phi for a specific layer /// \param layerName Name of the layer to modify /// \param phiStart Start angle of the dead region (in radians) /// \param phiEnd End angle of the dead region (in radians) void addDeadPhiRegionInLayer(const std::string& layerName, float phiStart, float phiEnd); - DetLayer GetLayer(const int layer) const { return layers[layer]; } - std::vector GetLayers() const { return layers; } - int GetLayerIndex(const std::string& name) const; - size_t GetNLayers() const { return layers.size(); } - bool IsLayerInert(const int layer) const { return layers[layer].isInert(); } - void ClearLayers() { layers.clear(); } - void SetRadiationLength(const std::string layerName, float x0) { layers[GetLayerIndex(layerName)].setRadiationLength(x0); } - void SetRadius(const std::string layerName, float r) { layers[GetLayerIndex(layerName)].setRadius(r); } - void SetResolutionRPhi(const std::string layerName, float resRPhi) { layers[GetLayerIndex(layerName)].setResolutionRPhi(resRPhi); } - void SetResolutionZ(const std::string layerName, float resZ) { layers[GetLayerIndex(layerName)].setResolutionZ(resZ); } - void SetResolution(const std::string layerName, float resRPhi, float resZ) + [[nodiscard]] DetLayer getLayer(const int layer) const { return layers[layer]; } + [[nodiscard]] std::vector getLayers() const { return layers; } + [[nodiscard]] int getLayerIndex(const std::string& name) const; + [[nodiscard]] size_t getNLayers() const { return layers.size(); } + [[nodiscard]] bool isLayerInert(const int layer) const { return layers[layer].isInert(); } + void clearLayers() { layers.clear(); } + void setRadiationLength(const std::string& layerName, float x0) { layers[getLayerIndex(layerName)].setRadiationLength(x0); } + void setRadius(const std::string& layerName, float r) { layers[getLayerIndex(layerName)].setRadius(r); } + void setResolutionRPhi(const std::string& layerName, float resRPhi) { layers[getLayerIndex(layerName)].setResolutionRPhi(resRPhi); } + void setResolutionZ(const std::string& layerName, float resZ) { layers[getLayerIndex(layerName)].setResolutionZ(resZ); } + void setResolution(const std::string& layerName, float resRPhi, float resZ) { - SetResolutionRPhi(layerName, resRPhi); - SetResolutionZ(layerName, resZ); + setResolutionRPhi(layerName, resRPhi); + setResolutionZ(layerName, resZ); } - void AddTPC(float phiResMean, float zResMean); + void addTPC(float phiResMean, float zResMean); /** * @brief Adds a generic detector configuration from the specified file. @@ -80,9 +84,9 @@ class FastTracker * * @param configMap Configuration map describing the detector. */ - void AddGenericDetector(o2::fastsim::GeometryEntry configMap, o2::ccdb::BasicCCDBManager* ccdbManager = nullptr); + void addGenericDetector(const o2::fastsim::GeometryEntry& configMap, o2::ccdb::BasicCCDBManager* ccdbManager = nullptr); - void Print(); + void print(); /** * @brief Performs fast tracking on the input track parameters. @@ -95,44 +99,44 @@ class FastTracker * @param nch Charged particle multiplicity (used for hit density calculations). * @return int i.e. number of intercepts (implementation-defined). */ - int FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackParCov& outputTrack, const float nch, const float maxRadius = 100.f); + int fastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackParCov& outputTrack, const float nch, const float maxRadius = 100.f); // For efficiency calculation - float Dist(float z, float radius); - float OneEventHitDensity(float multiplicity, float radius); - float IntegratedHitDensity(float multiplicity, float radius); - float UpcHitDensity(float radius); - float HitDensity(float radius); - float ProbGoodChiSqHit(float radius, float searchRadiusRPhi, float searchRadiusZ); + float dist(float z, float radius); + float oneEventHitDensity(float multiplicity, float radius); + float integratedHitDensity(float multiplicity, float radius); + float upcHitDensity(float radius); + float hitDensity(float radius); + float probGoodChiSqHit(float radius, float searchRadiusRPhi, float searchRadiusZ); // Setters and getters for configuration - void SetIntegrationTime(float t) { integrationTime = t; } - void SetMaxRadiusOfSlowDetectors(float r) { maxRadiusSlowDet = r; } - void SetAvgRapidity(float y) { avgRapidity = y; } - void SetdNdEtaCent(int d) { dNdEtaCent = d; } - void SetLhcUPCscale(float s) { lhcUPCScale = s; } - void SetBField(float b) { magneticField = b; } - void SetMinRadTrack(float r) { fMinRadTrack = r; } - void SetMagneticField(float b) { magneticField = b; } - void SetApplyZacceptance(bool b) { mApplyZacceptance = b; } - void SetApplyMSCorrection(bool b) { mApplyMSCorrection = b; } - void SetApplyElossCorrection(bool b) { mApplyElossCorrection = b; } - void SetApplyEffCorrection(bool b) { mApplyEffCorrection = b; } + void setIntegrationTime(float t) { integrationTime = t; } + void setMaxRadiusOfSlowDetectors(float r) { maxRadiusSlowDet = r; } + void setAvgRapidity(float y) { avgRapidity = y; } + void setdNdEtaCent(int d) { dNdEtaCent = d; } + void setLhcUPCscale(float s) { lhcUPCScale = s; } + void setBField(float b) { magneticField = b; } + void setMinRadTrack(float r) { fMinRadTrack = r; } + void setMagneticField(float b) { magneticField = b; } + void setApplyZacceptance(bool b) { mApplyZacceptance = b; } + void setApplyMSCorrection(bool b) { mApplyMSCorrection = b; } + void setApplyElossCorrection(bool b) { mApplyElossCorrection = b; } + void setApplyEffCorrection(bool b) { mApplyEffCorrection = b; } // Getters for the last track - int GetNIntercepts() const { return nIntercepts; } - int GetNSiliconPoints() const { return nSiliconPoints; } - int GetNGasPoints() const { return nGasPoints; } - float GetGoodHitProb(int layer) const + [[nodiscard]] int getNIntercepts() const { return nIntercepts; } + [[nodiscard]] int getNSiliconPoints() const { return nSiliconPoints; } + [[nodiscard]] int getNGasPoints() const { return nGasPoints; } + [[nodiscard]] float getGoodHitProb(int layer) const { return (layer >= 0 && static_cast(layer) < goodHitProbability.size()) ? goodHitProbability[layer] : 0.0f; } - std::size_t GetNHits() const { return hits.size(); } - float GetHitX(const int i) const { return hits[i][0]; } - float GetHitY(const int i) const { return hits[i][1]; } - float GetHitZ(const int i) const { return hits[i][2]; } - uint64_t GetCovMatOK() const { return covMatOK; } - uint64_t GetCovMatNotOK() const { return covMatNotOK; } + [[nodiscard]] std::size_t getNHits() const { return hits.size(); } + [[nodiscard]] float getHitX(const int i) const { return hits[i][0]; } + [[nodiscard]] float getHitY(const int i) const { return hits[i][1]; } + [[nodiscard]] float getHitZ(const int i) const { return hits[i][2]; } + uint64_t getCovMatOK() const { return covMatOK; } + uint64_t getCovMatNotOK() const { return covMatNotOK; } private: // Definition of detector layers @@ -146,8 +150,8 @@ class FastTracker bool mApplyEffCorrection = true; /// Apply correction for hit efficiency int mVerboseLevel = 0; /// 0: not verbose, >0 more verbose const float mCrossSectionMinB = 8; /// Minimum bias Cross section for event under study (PbPb MinBias ~ 8 Barns) - int dNdEtaCent = 2200; /// dN/deta e.g. at centrality 0-5% (for 5 TeV PbPb) - int dNdEtaMinB = 1; /// dN/deta for minimum bias events + float dNdEtaCent = 2200.f; /// dN/deta e.g. at centrality 0-5% (for 5 TeV PbPb) + float dNdEtaMinB = 1.f; /// dN/deta for minimum bias events float integrationTime = 0.02f; /// Integration time in ms float magneticField = 20.f; /// Magnetic field in kiloGauss (5 = 0.5T, 20 = 2T, etc) float covMatFactor = 0.99f; /// covmat off-diagonal factor to use for covmat fix (negative: no factor) @@ -175,7 +179,6 @@ class FastTracker // +-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+-~-<*>-~-+ -} // namespace fastsim -} // namespace o2 +} // namespace o2::fastsim #endif // ALICE3_CORE_FASTTRACKER_H_ diff --git a/ALICE3/Core/FlatLutWriter.cxx b/ALICE3/Core/FlatLutWriter.cxx index c63c1c96dd3..4fe806c4ef4 100644 --- a/ALICE3/Core/FlatLutWriter.cxx +++ b/ALICE3/Core/FlatLutWriter.cxx @@ -85,7 +85,7 @@ bool FlatLutWriter::fatSolve(lutEntry_t& lutEntry, o2::upgrade::convertTLorentzVectorToO2Track(q, tlv, {0.f, 0.f, 0.f}, trkIn); o2::track::TrackParCov trkOut; - const int status = fat.FastTrack(trkIn, trkOut, nch); + const int status = fat.fastTrack(trkIn, trkOut, nch); if (status <= mAtLeastHits) { LOGF(debug, "fatSolve: FastTrack failed with status %d (threshold %d)", status, mAtLeastHits); return false; @@ -94,8 +94,8 @@ bool FlatLutWriter::fatSolve(lutEntry_t& lutEntry, LOGF(debug, "fatSolve: FastTrack succeeded with status %d", status); lutEntry.valid = true; - lutEntry.itof = fat.GetGoodHitProb(itof); - lutEntry.otof = fat.GetGoodHitProb(otof); + lutEntry.itof = fat.getGoodHitProb(itof); + lutEntry.otof = fat.getGoodHitProb(otof); static constexpr int nCov = 15; for (int i = 0; i < nCov; ++i) @@ -104,16 +104,16 @@ bool FlatLutWriter::fatSolve(lutEntry_t& lutEntry, // Define the efficiency auto totfake = 0.f; lutEntry.eff = 1.f; - for (size_t i = 1; i < fat.GetNLayers(); ++i) { - if (fat.IsLayerInert(i)) + for (size_t i = 1; i < fat.getNLayers(); ++i) { + if (fat.isLayerInert(i)) continue; // skip inert layers - auto igoodhit = fat.GetGoodHitProb(i); + auto igoodhit = fat.getGoodHitProb(i); if (igoodhit <= 0.f || i == itof || i == otof) continue; lutEntry.eff *= igoodhit; auto pairfake = 0.f; - for (size_t j = i + 1; j < fat.GetNLayers(); ++j) { - auto jgoodhit = fat.GetGoodHitProb(j); + for (size_t j = i + 1; j < fat.getNLayers(); ++j) { + auto jgoodhit = fat.getGoodHitProb(j); if (jgoodhit <= 0.f || j == itof || j == otof) continue; pairfake = (1.f - igoodhit) * (1.f - jgoodhit); @@ -290,7 +290,7 @@ void FlatLutWriter::lutWrite(const char* filename, int pdg, float field, size_t LOGF(info, "Writing nch bin %d/%d", inch, nnch); auto nch = lutHeader.nchmap.eval(inch); lutEntry.nch = nch; - fat.SetdNdEtaCent(nch); + fat.setdNdEtaCent(nch); for (int irad = 0; irad < nrad; ++irad) { for (int ieta = 0; ieta < neta; ++ieta) { @@ -392,7 +392,7 @@ void FlatLutWriter::diagonalise(lutEntry_t& lutEntry) TMatrixDSymEigen eigen(m); // Eigenvalues - TVectorD eigenVal = eigen.GetEigenValues(); + const TVectorD& eigenVal = eigen.GetEigenValues(); for (int i = 0; i < kEig; ++i) lutEntry.eigval[i] = eigenVal[i]; diff --git a/ALICE3/Core/GeometryContainer.cxx b/ALICE3/Core/GeometryContainer.cxx index aee8e36ebd8..79f1a2d67c5 100644 --- a/ALICE3/Core/GeometryContainer.cxx +++ b/ALICE3/Core/GeometryContainer.cxx @@ -159,7 +159,7 @@ void GeometryEntry::replaceValue(const std::string& layerName, const std::string setValue(layerName, key, value); } -std::string GeometryEntry::accessFile(const std::string& path, const std::string downloadPath, o2::ccdb::BasicCCDBManager* ccdb, int timeoutSeconds) +std::string GeometryEntry::accessFile(const std::string& path, const std::string& downloadPath, o2::ccdb::BasicCCDBManager* ccdb, int timeoutSeconds) { if (path.rfind("ccdb:", 0) == 0) { diff --git a/ALICE3/Core/GeometryContainer.h b/ALICE3/Core/GeometryContainer.h index d5892b5b97b..67037c1b183 100644 --- a/ALICE3/Core/GeometryContainer.h +++ b/ALICE3/Core/GeometryContainer.h @@ -33,7 +33,7 @@ namespace o2::fastsim struct GeometryEntry { // Default constructor GeometryEntry() = default; - explicit GeometryEntry(std::string filename, o2::ccdb::BasicCCDBManager* ccdb = nullptr) + explicit GeometryEntry(const std::string& filename, o2::ccdb::BasicCCDBManager* ccdb = nullptr) { mFileName = accessFile(filename, "./.ALICE3/Configuration/", ccdb); mConfigurations = GeometryEntry::parseTEnvConfiguration(mFileName, mLayerNames); @@ -59,7 +59,7 @@ struct GeometryEntry { * @param timeoutSeconds If positive, then this function will wait for these seconds after download before removing the downloaded file. * @return The local path to the file, either the original local path or the path to the retrieved file from ccdb */ - static std::string accessFile(const std::string& path, const std::string downloadPath = "/tmp/GeometryContainer/", o2::ccdb::BasicCCDBManager* ccdb = nullptr, int timeoutSeconds = 0); + static std::string accessFile(const std::string& path, const std::string& downloadPath = "/tmp/GeometryContainer/", o2::ccdb::BasicCCDBManager* ccdb = nullptr, int timeoutSeconds = 0); std::map> getConfigurations() const { return mConfigurations; } std::map getConfiguration(const std::string& layerName) const; diff --git a/ALICE3/Core/OTFParticle.h b/ALICE3/Core/OTFParticle.h index a1c611b99c2..f96e1e16df0 100644 --- a/ALICE3/Core/OTFParticle.h +++ b/ALICE3/Core/OTFParticle.h @@ -40,21 +40,20 @@ class OTFParticle OTFParticle() = default; template - explicit OTFParticle(const TParticle& particle) + explicit OTFParticle(const TParticle& particle) : mPdgCode(particle.pdgCode()), + mGlobalIndex(particle.globalIndex()), + mCollisionId(particle.mcCollisionId()), + mVx(particle.vx()), + mVy(particle.vy()), + mVz(particle.vz()), + mVt(particle.vt()), + mPx(particle.px()), + mPy(particle.py()), + mPz(particle.pz()), + mE(particle.e()), + mStatusCode(particle.statusCode()), + mFlag(particle.flags()) { - mPdgCode = particle.pdgCode(); - mGlobalIndex = particle.globalIndex(); - mCollisionId = particle.mcCollisionId(); - mPx = particle.px(); - mPy = particle.py(); - mPz = particle.pz(); - mE = particle.e(); - mVx = particle.vx(); - mVy = particle.vy(); - mVz = particle.vz(); - mVt = particle.vt(); - mFlag = particle.flags(); - mStatusCode = particle.statusCode(); setBitOff(DecayerBits::ProducedByDecayer); if (particle.has_mothers()) { mIndicesMother = {particle.mothersIds().front(), particle.mothersIds().back()}; @@ -78,6 +77,7 @@ class OTFParticle void setIndicesDaughter(const int start, const int stop) { mIndicesDaughter = {start, stop}; } void setProductionTime(const float vt) { mVt = vt; } void setFlags(uint8_t flag) { mFlag = flag; } + void setDecayRadius(const float decayRadius) { mDecayRadius = decayRadius; } void setVxVyVz(const float vx, const float vy, const float vz) { mVx = vx; @@ -101,83 +101,82 @@ class OTFParticle } // Getters - int pdgCode() const { return mPdgCode; } - int globalIndex() const { return mGlobalIndex; } - int collisionId() const { return mCollisionId; } - bool isAlive() const { return checkBit(DecayerBits::IsAlive); } - bool isPrimary() const { return checkBit(DecayerBits::IsPrimary); } - bool isFromMcParticles() const { return !checkBit(DecayerBits::ProducedByDecayer); } - float weight() const + [[nodiscard]] int pdgCode() const { return mPdgCode; } + [[nodiscard]] int globalIndex() const { return mGlobalIndex; } + [[nodiscard]] int collisionId() const { return mCollisionId; } + [[nodiscard]] bool isAlive() const { return checkBit(DecayerBits::IsAlive); } + [[nodiscard]] bool isPrimary() const { return checkBit(DecayerBits::IsPrimary); } + [[nodiscard]] bool isFromMcParticles() const { return !checkBit(DecayerBits::ProducedByDecayer); } + [[nodiscard]] float weight() const { static constexpr float Weight = 1.f; return Weight; } - uint8_t flags() const { return mFlag; } - int statusCode() const { return mStatusCode; } - float vx() const { return mVx; } - float vy() const { return mVy; } - float vz() const { return mVz; } - float vt() const { return mVt; } - float px() const { return mPx; } - float py() const { return mPy; } - float pz() const { return mPz; } - float e() const { return mE; } - float radius() const { return std::hypot(mVx, mVy); } - float r() const { return radius(); } - float pt() const { return std::hypot(mPx, mPy); } - float p() const { return std::hypot(mPx, mPy, mPz); } - float phi() const { return o2::constants::math::PI + std::atan2(-1.0f * py(), -1.0f * px()); } - float eta() const + [[nodiscard]] uint8_t flags() const { return mFlag; } + [[nodiscard]] int statusCode() const { return mStatusCode; } + [[nodiscard]] float vx() const { return mVx; } + [[nodiscard]] float vy() const { return mVy; } + [[nodiscard]] float vz() const { return mVz; } + [[nodiscard]] float vt() const { return mVt; } + [[nodiscard]] float px() const { return mPx; } + [[nodiscard]] float py() const { return mPy; } + [[nodiscard]] float pz() const { return mPz; } + [[nodiscard]] float e() const { return mE; } + [[nodiscard]] float radius() const { return std::hypot(mVx, mVy); } + [[nodiscard]] float decayRadius() const { return mDecayRadius; } + [[nodiscard]] float r() const { return radius(); } + [[nodiscard]] float pt() const { return std::hypot(mPx, mPy); } + [[nodiscard]] float p() const { return std::hypot(mPx, mPy, mPz); } + [[nodiscard]] float phi() const { return o2::constants::math::PI + std::atan2(-1.0f * py(), -1.0f * px()); } + [[nodiscard]] float eta() const { // Conditionally defined to avoid FPEs // As https://github.com/AliceO2Group/AliceO2/blob/dev/Framework/Core/include/Framework/AnalysisDataModel.h#L1959 static constexpr float Tolerance = 1e-7f; if ((p() - mPz) < Tolerance) { return (mPz < 0.0f) ? -100.0f : 100.0f; - } else { - return 0.5f * std::log((p() + mPz) / (p() - mPz)); } + return 0.5f * std::log((p() + mPz) / (p() - mPz)); } - float y() const + [[nodiscard]] float y() const { // Conditionally defined to avoid FPEs // As https://github.com/AliceO2Group/AliceO2/blob/dev/Framework/Core/include/Framework/AnalysisDataModel.h#L1980 static constexpr float Tolerance = 1e-7f; if ((e() - mPz) < Tolerance) { return (mPz < 0.0f) ? -100.0f : 100.0f; - } else { - return 0.5f * std::log((mE + mPz) / (mE - mPz)); } + return 0.5f * std::log((mE + mPz) / (mE - mPz)); } - int getMotherIndexStart() const { return mIndicesMother[0]; } - int getMotherIndexStop() const { return mIndicesMother[1]; } - int getDaughterIndexStart() const { return mIndicesDaughter[0]; } - int getDaughterIndexStop() const { return mIndicesDaughter[1]; } - const std::array& getMothers() const { return mIndicesMother; } - const std::array& getDaughters() const { return mIndicesDaughter; } - std::span getMotherSpan() const { return hasMothers() ? std::span(mIndicesMother.data(), 2) : std::span(); } + [[nodiscard]] int getMotherIndexStart() const { return mIndicesMother[0]; } + [[nodiscard]] int getMotherIndexStop() const { return mIndicesMother[1]; } + [[nodiscard]] int getDaughterIndexStart() const { return mIndicesDaughter[0]; } + [[nodiscard]] int getDaughterIndexStop() const { return mIndicesDaughter[1]; } + [[nodiscard]] const std::array& getMothers() const { return mIndicesMother; } + [[nodiscard]] const std::array& getDaughters() const { return mIndicesDaughter; } + [[nodiscard]] std::span getMotherSpan() const { return hasMothers() ? std::span(mIndicesMother.data(), 2) : std::span(); } // Checks - bool hasDaughters() const { return (mIndicesDaughter[0] >= 0); } - bool hasMothers() const { return (mIndicesMother[0] >= 0); } - bool hasNaN() const + [[nodiscard]] bool hasDaughters() const { return (mIndicesDaughter[0] >= 0); } + [[nodiscard]] bool hasMothers() const { return (mIndicesMother[0] >= 0); } + [[nodiscard]] bool hasNaN() const { return std::isnan(mPx) || std::isnan(mPy) || std::isnan(mPz) || std::isnan(mE) || std::isnan(mVx) || std::isnan(mVy) || std::isnan(mVz); } - bool hasIndex() const + [[nodiscard]] bool hasIndex() const { return (mGlobalIndex != -1); } // Bits - bool checkBit(DecayerBits bit) const { return mBits.test(static_cast(bit)); } + [[nodiscard]] bool checkBit(DecayerBits bit) const { return mBits.test(static_cast(bit)); } void setBit(DecayerBits bit, bool value = true) { mBits.set(static_cast(bit), value); } void setBitOn(DecayerBits bit) { mBits.set(static_cast(bit), true); } void setBitOff(DecayerBits bit) { mBits.set(static_cast(bit), false); } - const std::bitset<8>& getBits() const { return mBits; } - uint8_t getBitsValue() const { return static_cast(mBits.to_ulong()); } + [[nodiscard]] const std::bitset<8>& getBits() const { return mBits; } + [[nodiscard]] uint8_t getBitsValue() const { return static_cast(mBits.to_ulong()); } void setBits(std::bitset<8> bits) { mBits = bits; } private: @@ -185,10 +184,11 @@ class OTFParticle int mCollisionId{-1}; float mVx{}, mVy{}, mVz{}, mVt{}; float mPx{}, mPy{}, mPz{}, mE{}; + float mDecayRadius{-1}; int mStatusCode{}; uint8_t mFlag{}; - std::bitset<8> mBits{}; + std::bitset<8> mBits; std::array mIndicesMother{-1, -1}, mIndicesDaughter{-1, -1}; }; diff --git a/ALICE3/DataModel/OTFTOF.h b/ALICE3/DataModel/OTFTOF.h index b4bf1f26670..8643abc959c 100644 --- a/ALICE3/DataModel/OTFTOF.h +++ b/ALICE3/DataModel/OTFTOF.h @@ -150,6 +150,26 @@ DECLARE_SOA_DYNAMIC_COLUMN(NSigmaOuterTOF, nSigmaOuterTOF, //! General function } }); +DECLARE_SOA_COLUMN(NSigmaSplusInnerTOF, nSigmaSplusInnerTOF, float); //! NSigma Sigma plus InnerTOF +DECLARE_SOA_COLUMN(NSigmaSminusInnerTOF, nSigmaSminusInnerTOF, float); //! NSigma Sigma minus InnerTOF +DECLARE_SOA_COLUMN(NSigmaXiInnerTOF, nSigmaXiInnerTOF, float); //! NSigma Xi InnerTOF +DECLARE_SOA_COLUMN(NSigmaOmegaInnerTOF, nSigmaOmegaInnerTOF, float); //! NSigma Omega InnerTOF + +DECLARE_SOA_COLUMN(NSigmaSplusOuterTOF, nSigmaSplusOuterTOF, float); //! NSigma Sigma plus OuterTOF +DECLARE_SOA_COLUMN(NSigmaSminusOuterTOF, nSigmaSminusOuterTOF, float); //! NSigma Sigma minus OuterTOF +DECLARE_SOA_COLUMN(NSigmaXiOuterTOF, nSigmaXiOuterTOF, float); //! NSigma Xi OuterTOF +DECLARE_SOA_COLUMN(NSigmaOmegaOuterTOF, nSigmaOmegaOuterTOF, float); //! NSigma Omega OuterTOF + +DECLARE_SOA_COLUMN(InnerTOFExpectedTimeSp, innerTOFExpectedTimeSp, float); //! Reconstructed expected time at the InnerTOF for the Sigma plus mass hypotheses +DECLARE_SOA_COLUMN(InnerTOFExpectedTimeSm, innerTOFExpectedTimeSm, float); //! Reconstructed expected time at the InnerTOF for the Sigma minus mass hypotheses +DECLARE_SOA_COLUMN(InnerTOFExpectedTimeXi, innerTOFExpectedTimeXi, float); //! Reconstructed expected time at the InnerTOF for the Xi mass hypotheses +DECLARE_SOA_COLUMN(InnerTOFExpectedTimeOm, innerTOFExpectedTimeOm, float); //! Reconstructed expected time at the InnerTOF for the Omega mass hypotheses + +DECLARE_SOA_COLUMN(OuterTOFExpectedTimeSp, outerTOFExpectedTimeSp, float); //! Reconstructed expected time at the OuterTOF for the Sigma plus mass hypotheses +DECLARE_SOA_COLUMN(OuterTOFExpectedTimeSm, outerTOFExpectedTimeSm, float); //! Reconstructed expected time at the OuterTOF for the Sigma minus mass hypotheses +DECLARE_SOA_COLUMN(OuterTOFExpectedTimeXi, outerTOFExpectedTimeXi, float); //! Reconstructed expected time at the OuterTOF for the Xi mass hypotheses +DECLARE_SOA_COLUMN(OuterTOFExpectedTimeOm, outerTOFExpectedTimeOm, float); //! Reconstructed expected time at the OuterTOF for the Omega mass hypotheses + } // namespace upgrade_tof DECLARE_SOA_TABLE(UpgradeTofMCs, "AOD", "UPGRADETOFMC", @@ -222,9 +242,28 @@ DECLARE_SOA_TABLE(UpgradeTofExpectedTimes, "AOD", "UPGRADETOFEXPT", upgrade_tof::OuterTOFExpectedTimeHe3, upgrade_tof::OuterTOFExpectedTimeAl); +DECLARE_SOA_TABLE(UpgradeTofShortLiveds, "AOD", "UPGRTOFSHRTLVD", + upgrade_tof::NSigmaSplusInnerTOF, + upgrade_tof::NSigmaSminusInnerTOF, + upgrade_tof::NSigmaXiInnerTOF, + upgrade_tof::NSigmaOmegaInnerTOF, + upgrade_tof::NSigmaSplusOuterTOF, + upgrade_tof::NSigmaSminusOuterTOF, + upgrade_tof::NSigmaXiOuterTOF, + upgrade_tof::NSigmaOmegaOuterTOF, + upgrade_tof::InnerTOFExpectedTimeSp, + upgrade_tof::InnerTOFExpectedTimeSm, + upgrade_tof::InnerTOFExpectedTimeXi, + upgrade_tof::InnerTOFExpectedTimeOm, + upgrade_tof::OuterTOFExpectedTimeSp, + upgrade_tof::OuterTOFExpectedTimeSm, + upgrade_tof::OuterTOFExpectedTimeXi, + upgrade_tof::OuterTOFExpectedTimeOm); + using UpgradeTofMC = UpgradeTofMCs::iterator; using UpgradeTof = UpgradeTofs::iterator; using UpgradeTofExpectedTime = UpgradeTofExpectedTimes::iterator; +using UpgradeTofShortLived = UpgradeTofShortLiveds::iterator; } // namespace o2::aod diff --git a/ALICE3/DataModel/ReducedTablesAlice3.h b/ALICE3/DataModel/ReducedTablesAlice3.h index fdc9275842c..363ba50842f 100644 --- a/ALICE3/DataModel/ReducedTablesAlice3.h +++ b/ALICE3/DataModel/ReducedTablesAlice3.h @@ -23,6 +23,9 @@ #include "ALICE3/DataModel/OTFPIDTrk.h" #include "ALICE3/DataModel/OTFRICH.h" #include "ALICE3/DataModel/OTFTOF.h" +#include "ALICE3/DataModel/collisionAlice3.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/Multiplicity.h" #include #include @@ -36,25 +39,21 @@ namespace o2::aod namespace reducedeventalice3 { DECLARE_SOA_COLUMN(MultDensity, multDensity, float); -DECLARE_SOA_COLUMN(MCPosX, mcPosX, float); //! MC event position X -DECLARE_SOA_COLUMN(MCPosY, mcPosY, float); //! MC event position Y -DECLARE_SOA_COLUMN(MCPosZ, mcPosZ, float); //! MC event position Z +DECLARE_SOA_COLUMN(McPosX, mcPosX, float); //! MC event position X +DECLARE_SOA_COLUMN(McPosY, mcPosY, float); //! MC event position Y +DECLARE_SOA_COLUMN(McPosZ, mcPosZ, float); //! MC event position Z } // namespace reducedeventalice3 -namespace reducedeventmcalice3 -{ -DECLARE_SOA_COLUMN(MultMCNParticlesEta05, multMCNParticlesEta05, float); -DECLARE_SOA_COLUMN(MultMCNParticlesEta08, multMCNParticlesEta08, float); -DECLARE_SOA_COLUMN(MultMCNParticlesEta10, multMCNParticlesEta10, float); -DECLARE_SOA_COLUMN(MultMCNParticlesEta20, multMCNParticlesEta20, float); -DECLARE_SOA_COLUMN(MultMCNParticlesEta40, multMCNParticlesEta40, float); -} // namespace reducedeventmcalice3 - DECLARE_SOA_TABLE_STAGED(ReA3Events, "REA3EVENT", //! Main event information table o2::soa::Index<>, collision::PosX, collision::PosY, collision::PosZ, collision::NumContrib, collision::CollisionTime, collision::CollisionTimeRes, reducedeventalice3::MultDensity); +DECLARE_SOA_TABLE(ReA3EventsExtended, "AOD", "REA3EVENTEXT", //! Event vertex covariance matrix + mult::MultNTracksPV, mult::MultNTracksPVeta1, mult::MultNTracksPVetaHalf, + mult::MultNTracksGlobal, mult::MultNGlobalTracksPV, + cent::CentRun2V0M); + DECLARE_SOA_TABLE(ReducedA3EventsVtxCov, "AOD", "REA3VTXCOV", //! Event vertex covariance matrix collision::CovXX, collision::CovXY, collision::CovXZ, collision::CovYY, collision::CovYZ, collision::CovZZ, collision::Chi2); @@ -64,8 +63,9 @@ DECLARE_SOA_TABLE(ReducedA3EventsInfo, "AOD", "REA3EVENTINFO", //! Main event DECLARE_SOA_TABLE(ReA3MCEvents, "AOD", "REA3MCEVENT", //! Event level MC truth information o2::soa::Index<>, - mccollision::GeneratorsID, reducedeventalice3::MCPosX, reducedeventalice3::MCPosY, reducedeventalice3::MCPosZ, - mccollision::T, mccollision::Weight, mccollision::ImpactParameter); + mccollision::GeneratorsID, reducedeventalice3::McPosX, reducedeventalice3::McPosY, reducedeventalice3::McPosZ, + mccollision::T, mccollision::Weight, mccollision::ImpactParameter, + mcmult_alice3::MultMC, mcmult_alice3::MultMC25, mcmult_alice3::MultMC125, mcmult_alice3::MultMC09); using ReducedA3MCEvent = ReA3MCEvents::iterator; using ReA3Event = ReA3Events::iterator; @@ -73,7 +73,7 @@ using ReA3Event = ReA3Events::iterator; namespace reducedtrackalice3 { // basic track information -DECLARE_SOA_INDEX_COLUMN(ReA3Event, rea3event); //! +DECLARE_SOA_INDEX_COLUMN(ReA3Event, reA3Event); //! DECLARE_SOA_INDEX_COLUMN(Track, track); //! // ---- flags reserved for storing various information during filtering DECLARE_SOA_BITMAP_COLUMN(FilteringFlags, filteringFlags, 64); //! @@ -124,7 +124,7 @@ DECLARE_SOA_TABLE(ReducedA3TracksBarrelCov, "AOD", "REA3BARRELCOV", //! track::CSnpSnp, track::CTglY, track::CTglZ, track::CTglSnp, track::CTglTgl, track::C1PtY, track::C1PtZ, track::C1PtSnp, track::C1PtTgl, track::C1Pt21Pt2); -namespace reducedA3trackMC +namespace reduceda3trackmc { DECLARE_SOA_INDEX_COLUMN(ReA3MCEvent, reA3MCEvent); //! DECLARE_SOA_COLUMN(McReducedFlags, mcReducedFlags, uint16_t); //! Flags to hold compressed MC selection information @@ -151,27 +151,26 @@ DECLARE_SOA_DYNAMIC_COLUMN(Y, y, //! Particle rapidity float pz = pt * std::sinh(eta); if ((e - pz) > static_cast(1e-7)) { return 0.5f * std::log((e + pz) / (e - pz)); - } else { - return -999.0f; } + return -999.0f; }); -} // namespace reducedA3trackMC +} // namespace reduceda3trackmc // NOTE: This table is nearly identical to the one from Framework (except that it points to the event ID, not the BC id) // This table contains all MC truth tracks (both barrel and muon) DECLARE_SOA_TABLE(ReA3MCTracks, "AOD", "REA3MCTRACK", //! MC track information (on disk) - o2::soa::Index<>, reducedA3trackMC::ReA3MCEventId, + o2::soa::Index<>, reduceda3trackmc::ReA3MCEventId, mcparticle::PdgCode, mcparticle::StatusCode, mcparticle::Flags, - reducedA3trackMC::MothersIds, reducedA3trackMC::DaughtersIdSlice, + reduceda3trackmc::MothersIds, reduceda3trackmc::DaughtersIdSlice, mcparticle::Weight, - reducedA3trackMC::Pt, reducedA3trackMC::Eta, reducedA3trackMC::Phi, reducedA3trackMC::E, + reduceda3trackmc::Pt, reduceda3trackmc::Eta, reduceda3trackmc::Phi, reduceda3trackmc::E, mcparticle::Vx, mcparticle::Vy, mcparticle::Vz, mcparticle::Vt, - reducedA3trackMC::McReducedFlags, - reducedA3trackMC::Px, - reducedA3trackMC::Py, - reducedA3trackMC::Pz, - reducedA3trackMC::P, - reducedA3trackMC::Y, + reduceda3trackmc::McReducedFlags, + reduceda3trackmc::Px, + reduceda3trackmc::Py, + reduceda3trackmc::Pz, + reduceda3trackmc::P, + reduceda3trackmc::Y, mcparticle::ProducedByGenerator, mcparticle::FromBackgroundEvent, mcparticle::GetGenStatusCode, @@ -190,7 +189,7 @@ DECLARE_SOA_COLUMN(McMask, mcMask, uint16_t); // NOTE: MC labels. This table has one entry for each reconstructed track (joinable with the track tables) // The McParticleId points to the position of the MC truth track from the ReducedTracksMC table DECLARE_SOA_TABLE(ReducedA3TracksBarrelLabels, "AOD", "REA3BARLA", //! - reduceda3barreltracklabel::ReA3MCTrackId, reduceda3barreltracklabel::McMask, reducedA3trackMC::McReducedFlags); + reduceda3barreltracklabel::ReA3MCTrackId, reduceda3barreltracklabel::McMask, reduceda3trackmc::McReducedFlags); using ReducedA3TrackBarrelLabel = ReducedA3TracksBarrelLabels::iterator; @@ -222,15 +221,15 @@ DECLARE_SOA_TABLE(ReducedA3MCEventLabels, "AOD", "REA3MCCOLLBL", //! Table joine using ReducedA3MCEventLabel = ReducedA3MCEventLabels::iterator; -namespace reducedA3track_association +namespace reduceda3trackassociation { -DECLARE_SOA_INDEX_COLUMN(ReA3Event, reA3event); //! ReducedEvent index -DECLARE_SOA_INDEX_COLUMN(ReA3Track, reA3track); //! ReducedTrack index -} // namespace reducedA3track_association +DECLARE_SOA_INDEX_COLUMN(ReA3Event, reA3Event); //! ReducedEvent index +DECLARE_SOA_INDEX_COLUMN(ReA3Track, reA3Track); //! ReducedTrack index +} // namespace reduceda3trackassociation DECLARE_SOA_TABLE(ReducedA3TracksAssoc, "AOD", "REA3ASSOC", //! Table for reducedtrack-to-reducedcollision association - reducedA3track_association::ReA3EventId, - reducedA3track_association::ReA3TrackId); + reduceda3trackassociation::ReA3EventId, + reduceda3trackassociation::ReA3TrackId); DECLARE_SOA_TABLE(ReducedA3PIDTOF, "AOD", "REA3PIDTOF", upgrade_tof::TOFEventTime, diff --git a/ALICE3/DataModel/tracksAlice3.h b/ALICE3/DataModel/tracksAlice3.h index afd491ab4b2..8e19feb0d0e 100644 --- a/ALICE3/DataModel/tracksAlice3.h +++ b/ALICE3/DataModel/tracksAlice3.h @@ -50,8 +50,9 @@ using TrackExtraA3 = TracksExtraA3::iterator; namespace mcparticle_alice3 { -DECLARE_SOA_COLUMN(NHits, nHits, int); //! number of silicon hits -DECLARE_SOA_COLUMN(Charge, charge, float); //! particle charge +DECLARE_SOA_COLUMN(NHits, nHits, int); //! number of silicon hits +DECLARE_SOA_COLUMN(Charge, charge, float); //! particle charge +DECLARE_SOA_COLUMN(DecayRadius, decayRadius, float); //! Radius for decayed particle produced by decayer (-1 if not decayed) DECLARE_SOA_BITMAP_COLUMN(DecayerBits, decayerBits, 8); //! Bit mask for particle produced by the OTF decayer } // namespace mcparticle_alice3 DECLARE_SOA_TABLE(MCParticlesExtraA3, "AOD", "MCParticlesExtraA3", @@ -59,7 +60,10 @@ DECLARE_SOA_TABLE(MCParticlesExtraA3, "AOD", "MCParticlesExtraA3", mcparticle_alice3::Charge); using MCParticleExtraA3 = MCParticlesExtraA3::iterator; -DECLARE_SOA_TABLE(OTFDecayerBits, "AOD", "OTFDecayerBits", mcparticle_alice3::DecayerBits); +DECLARE_SOA_TABLE(OTFParticleExtras, "AOD", "OTFPARTICLEEXTRA", + mcparticle_alice3::DecayerBits, + mcparticle_alice3::DecayRadius); +using OTFParticleExtra = OTFParticleExtras::iterator; } // namespace o2::aod diff --git a/ALICE3/ML/MulticharmMlResponse.h b/ALICE3/ML/MulticharmMlResponse.h new file mode 100644 index 00000000000..f20c4b1ae28 --- /dev/null +++ b/ALICE3/ML/MulticharmMlResponse.h @@ -0,0 +1,206 @@ +// 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. + +/// \file MulticharmMlResponse.h +/// \brief Class to compute the ML response for multi-charm candidates +/// \author Jesper Karlsson Gumprecht + +#ifndef ALICE3_ML_MULTICHARMMLRESPONSE_H_ +#define ALICE3_ML_MULTICHARMMLRESPONSE_H_ + +#include "Tools/ML/MlResponse.h" + +#include +#include +#include +#include + +namespace multi_charm_ml +{ + +static constexpr int NBinsPt = 10; +static constexpr int NClasses = 2; +static constexpr std::array, NBinsPt> Cuts = {{{0.5, 0.5}, + {0.5, 0.5}, + {0.5, 0.5}, + {0.5, 0.5}, + {0.5, 0.5}, + {0.5, 0.5}, + {0.5, 0.5}, + {0.5, 0.5}, + {0.5, 0.5}, + {0.5, 0.5}}}; + +static const std::vector labelsPt = {"pT bin 0", + "pT bin 1", + "pT bin 2", + "pT bin 3", + "pT bin 4", + "pT bin 5", + "pT bin 6", + "pT bin 7", + "pT bin 8", + "pT bin 9"}; + +static const std::vector labelsCutScore = {"score class 1", "score class 2"}; +static const std::vector namesInputFeatures{"xicDauDCA", + "xiccDauDCA", + "xiDCAxy", + "xicDCAxy", + "xiccDCAxy", + "xiDCAz", + "xicDCAz", + "xiccDCAz", + "pi1cDCAxy", + "pi2cDCAxy", + "piccDCAxy", + "pi1cDCAz", + "pi2cDCAz", + "piccDCAz", + "xicDecayRadius2D", + "xiccDecayRadius2D", + "xicProperLength", + "xicDistanceFromPV", + "xiccProperLength"}; + +} // namespace multi_charm_ml + +namespace o2::analysis +{ +// list of input features that can be requested via the mlConfigurations.namesInputFeatures configurable +enum class InputFeaturesMulticharm : uint8_t { + xicDauDCA = 0, + xiccDauDCA, + xiDCAxy, + xicDCAxy, + xiccDCAxy, + xiDCAz, + xicDCAz, + xiccDCAz, + pi1cDCAxy, + pi2cDCAxy, + piccDCAxy, + pi1cDCAz, + pi2cDCAz, + piccDCAz, + xicDecayRadius2D, + xiccDecayRadius2D, + xicProperLength, + xicDistanceFromPV, + xiccProperLength +}; + +template +class MulticharmMlResponse : public MlResponse +{ + public: + MulticharmMlResponse() = default; + ~MulticharmMlResponse() override = default; + + template + std::vector getInputFeatures(TMulticharm const& multicharm) + { + std::vector inputFeatures; + inputFeatures.reserve(MlResponse::mCachedIndices.size()); + + for (const auto& idx : MlResponse::mCachedIndices) { + switch (idx) { + case InputFeaturesMulticharm::xicDauDCA: + inputFeatures.emplace_back(multicharm.xicDauDCA()); + break; + case InputFeaturesMulticharm::xiccDauDCA: + inputFeatures.emplace_back(multicharm.xiccDauDCA()); + break; + case InputFeaturesMulticharm::xiDCAxy: + inputFeatures.emplace_back(multicharm.xiDCAxy()); + break; + case InputFeaturesMulticharm::xicDCAxy: + inputFeatures.emplace_back(multicharm.xicDCAxy()); + break; + case InputFeaturesMulticharm::xiccDCAxy: + inputFeatures.emplace_back(multicharm.xiccDCAxy()); + break; + case InputFeaturesMulticharm::xiDCAz: + inputFeatures.emplace_back(multicharm.xiDCAz()); + break; + case InputFeaturesMulticharm::xicDCAz: + inputFeatures.emplace_back(multicharm.xicDCAz()); + break; + case InputFeaturesMulticharm::xiccDCAz: + inputFeatures.emplace_back(multicharm.xiccDCAz()); + break; + case InputFeaturesMulticharm::pi1cDCAxy: + inputFeatures.emplace_back(multicharm.pi1cDCAxy()); + break; + case InputFeaturesMulticharm::pi2cDCAxy: + inputFeatures.emplace_back(multicharm.pi2cDCAxy()); + break; + case InputFeaturesMulticharm::piccDCAxy: + inputFeatures.emplace_back(multicharm.piccDCAxy()); + break; + case InputFeaturesMulticharm::pi1cDCAz: + inputFeatures.emplace_back(multicharm.pi1cDCAz()); + break; + case InputFeaturesMulticharm::pi2cDCAz: + inputFeatures.emplace_back(multicharm.pi2cDCAz()); + break; + case InputFeaturesMulticharm::piccDCAz: + inputFeatures.emplace_back(multicharm.piccDCAz()); + break; + case InputFeaturesMulticharm::xicDecayRadius2D: + inputFeatures.emplace_back(multicharm.xicDecayRadius2D()); + break; + case InputFeaturesMulticharm::xiccDecayRadius2D: + inputFeatures.emplace_back(multicharm.xiccDecayRadius2D()); + break; + case InputFeaturesMulticharm::xicProperLength: + inputFeatures.emplace_back(multicharm.xicProperLength()); + break; + case InputFeaturesMulticharm::xicDistanceFromPV: + inputFeatures.emplace_back(multicharm.xicDistanceFromPV()); + break; + case InputFeaturesMulticharm::xiccProperLength: + inputFeatures.emplace_back(multicharm.xiccProperLength()); + break; + } + } + return inputFeatures; + } + + protected: + void setAvailableInputFeatures() override + { + MlResponse::mAvailableInputFeatures = { + {"xicDauDCA", static_cast(InputFeaturesMulticharm::xicDauDCA)}, + {"xiccDauDCA", static_cast(InputFeaturesMulticharm::xiccDauDCA)}, + {"xiDCAxy", static_cast(InputFeaturesMulticharm::xiDCAxy)}, + {"xicDCAxy", static_cast(InputFeaturesMulticharm::xicDCAxy)}, + {"xiccDCAxy", static_cast(InputFeaturesMulticharm::xiccDCAxy)}, + {"xiDCAz", static_cast(InputFeaturesMulticharm::xiDCAz)}, + {"xicDCAz", static_cast(InputFeaturesMulticharm::xicDCAz)}, + {"xiccDCAz", static_cast(InputFeaturesMulticharm::xiccDCAz)}, + {"pi1cDCAxy", static_cast(InputFeaturesMulticharm::pi1cDCAxy)}, + {"pi2cDCAxy", static_cast(InputFeaturesMulticharm::pi2cDCAxy)}, + {"piccDCAxy", static_cast(InputFeaturesMulticharm::piccDCAxy)}, + {"pi1cDCAz", static_cast(InputFeaturesMulticharm::pi1cDCAz)}, + {"pi2cDCAz", static_cast(InputFeaturesMulticharm::pi2cDCAz)}, + {"piccDCAz", static_cast(InputFeaturesMulticharm::piccDCAz)}, + {"xicDecayRadius2D", static_cast(InputFeaturesMulticharm::xicDecayRadius2D)}, + {"xiccDecayRadius2D", static_cast(InputFeaturesMulticharm::xiccDecayRadius2D)}, + {"xicProperLength", static_cast(InputFeaturesMulticharm::xicProperLength)}, + {"xicDistanceFromPV", static_cast(InputFeaturesMulticharm::xicDistanceFromPV)}, + {"xiccProperLength", static_cast(InputFeaturesMulticharm::xiccProperLength)}}; + } +}; + +} // namespace o2::analysis + +#endif // ALICE3_ML_MULTICHARMMLRESPONSE_H_ diff --git a/ALICE3/Macros/testFastTracker.C b/ALICE3/Macros/testFastTracker.C index 857ff416919..4c8d2249a31 100644 --- a/ALICE3/Macros/testFastTracker.C +++ b/ALICE3/Macros/testFastTracker.C @@ -19,7 +19,7 @@ #include -void testFastTracker(std::string geometryFile = "a3geo.ini") +void testFastTracker(const std::string& geometryFile = "a3geo.ini") { fair::Logger::SetConsoleSeverity(fair::Severity::debug); diff --git a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx index 1b0a1a4fb6f..2c8c4dea0c9 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyDecayer.cxx @@ -88,7 +88,7 @@ O2ORIGIN("TMP"); struct OnTheFlyDecayer { Produces tableMcCollisions; Produces tableMcParticles; - Produces tableOTFDecayerBits; + Produces tableOTFParticleExtras; o2::upgrade::Decayer decayer; Service pdgDB{}; @@ -152,7 +152,7 @@ struct OnTheFlyDecayer { } particle.setBitOff(o2::upgrade::DecayerBits::IsAlive); - std::vector decayStack = decayer.decayParticle(pdgDB, particle); + std::vector decayStack = decayer.decayParticle(particle, pdgDB); if (decayStack.empty()) { continue; } @@ -172,6 +172,7 @@ struct OnTheFlyDecayer { trackLength = o2::upgrade::computeTrackLength(o2track, decayRadius, magneticField); } + particle.setDecayRadius(std::hypot(decayer.getSecondaryVertexX(), decayer.getSecondaryVertexY())); const float trackTimeNS = trackLength / trackVelocity * PicoToNano; particle.setIndicesDaughter(particlesInDataframe - indexOffset + allParticles.size(), particlesInDataframe - indexOffset + allParticles.size() + (decayStack.size() - 1)); for (auto& daughter : decayStack) { @@ -220,7 +221,7 @@ struct OnTheFlyDecayer { histos.fill(HIST("hNaNBookkeeping"), 0); } - tableOTFDecayerBits(otfParticle.getBitsValue()); + tableOTFParticleExtras(otfParticle.getBitsValue(), otfParticle.decayRadius()); tableMcParticles(tableMcCollisions.lastIndex(), otfParticle.pdgCode(), otfParticle.statusCode(), otfParticle.flags(), otfParticle.getMotherSpan(), otfParticle.getDaughters().data(), otfParticle.weight(), otfParticle.px(), otfParticle.py(), otfParticle.pz(), otfParticle.e(), diff --git a/ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx b/ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx index 13f70c2980c..ac844c857b4 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTofPid.cxx @@ -33,6 +33,7 @@ #include "Common/Core/trackUtilities.h" #include +#include #include #include #include @@ -56,6 +57,7 @@ #include #include +#include #include #include #include @@ -83,6 +85,7 @@ struct OnTheFlyTofPid { Produces upgradeTofMC; Produces upgradeTof; Produces upgradeTofExpectedTime; + Produces upgradeTofShortLived; // necessary for particle charges Service pdg; @@ -132,6 +135,7 @@ struct OnTheFlyTofPid { Configurable nBinsEta{"nBinsEta", 400, "number of bins plot relative eta error"}; Configurable nBinsMult{"nBinsMult", 200, "number of bins in multiplicity"}; Configurable maxMultRange{"maxMultRange", 1000.f, "upper limit in multiplicity plots"}; + Configurable> particlesForQa{"particlesForQa", {11, 13, 211, 321, 2212}, "pdgCodes for QA plots"}; } plotsConfig; o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; @@ -145,13 +149,64 @@ struct OnTheFlyTofPid { // for handling basic QA histograms if requested HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; OutputObj listEfficiency{"efficiency"}; - static constexpr int kParticles = 9; + + enum ParticleType : int { El = 0, // electron + Mu, // muon + Pi, // pion + Ka, // kaon + Pr, // proton + Sp, // sigma plus + Sm, // sigma minus + Xi, // xi + Om, // omega + De, // deuteron + Tr, // triton + He, // helium 3 + Al, // alpha + NParticles }; + + struct ParticleInfo { + const char* texName; + const char* name; + ParticleType type; + int pdgCode; + double mass; + float charge; + }; + + static constexpr ParticleInfo Particles[NParticles] = { + {"#it{e}", "Elec", El, PDG_t::kElectron, o2::constants::physics::MassElectron, 1.f}, + {"#it{#mu}", "Muon", Mu, PDG_t::kMuonMinus, o2::constants::physics::MassMuon, 1.f}, + {"#it{#pi}", "Pion", Pi, PDG_t::kPiPlus, o2::constants::physics::MassPionCharged, 1.f}, + {"#it{K}", "Kaon", Ka, PDG_t::kKPlus, o2::constants::physics::MassKaonCharged, 1.f}, + {"#it{p}", "Prot", Pr, PDG_t::kProton, o2::constants::physics::MassProton, 1.f}, + {"#it{#SigmaPlus}", "Sigp", Sp, PDG_t::kSigmaPlus, o2::constants::physics::MassSigmaPlus, 1.f}, + {"#it{#SigmaMinus}", "Sigm", Sm, PDG_t::kSigmaMinus, o2::constants::physics::MassSigmaMinus, 1.f}, + {"#it{#Xi}", "Xi", Xi, PDG_t::kXiMinus, o2::constants::physics::MassXiMinus, 1.f}, + {"#it{#Omega}", "Omeg", Om, PDG_t::kOmegaMinus, o2::constants::physics::MassOmegaMinus, 1.f}, + {"#it{d}", "Deut", De, o2::constants::physics::kDeuteron, o2::constants::physics::MassDeuteron, 1.f}, + {"#it{t}", "Trit", Tr, o2::constants::physics::kTriton, o2::constants::physics::MassTriton, 1.f}, + {"^{3}He", "He", He, o2::constants::physics::kHelium3, o2::constants::physics::MassHelium3, 2.f}, + {"#it{#alpha}", "Al", Al, o2::constants::physics::kAlpha, o2::constants::physics::MassAlpha, 2.f}, + }; + + bool doQaForParticle(const int pdgCode) + { + return std::find(plotsConfig.particlesForQa.value.begin(), plotsConfig.particlesForQa.value.end(), std::abs(pdgCode)) != plotsConfig.particlesForQa.value.end(); + } // Configuration defined at init time o2::fastsim::GeometryContainer mGeoContainer; float mMagneticField = 0.0f; void init(o2::framework::InitContext& initContext) { + // Check Particles: every row's declared type must match its array position. + for (int i = 0; i < NParticles; ++i) { + if (Particles[i].type != i) { + LOG(fatal) << "Particles in ParticleInfo not ordered according to enum!"; + } + } + mGeoContainer.setCcdbManager(ccdb.operator->()); mGeoContainer.init(initContext); @@ -236,14 +291,14 @@ struct OnTheFlyTofPid { histos.add("iTOF/h2dTrackLengthInnerVsPt", "h2dTrackLengthInnerVsPt", kTH2F, {axisMomentumSmall, axisTrackLengthInner}); histos.add("iTOF/h2dTrackLengthInnerRecoVsPt", "h2dTrackLengthInnerRecoVsPt", kTH2F, {axisMomentumSmall, axisTrackLengthInner}); histos.add("iTOF/h2dDeltaTrackLengthInnerVsPt", "h2dDeltaTrackLengthInnerVsPt", kTH2F, {axisMomentumSmall, axisTrackDeltaLength}); - histos.add("iTOF/h2HitMap", "h2HitMap", kTH2F, {{1000, -simConfig.innerTOFLength / 2, simConfig.innerTOFLength / 2}, {1000, 0, simConfig.innerTOFRadius * 2 * M_PI}}); + histos.add("iTOF/h2HitMap", "h2HitMap", kTH2F, {{1000, -simConfig.innerTOFLength / 2, simConfig.innerTOFLength / 2}, {1000, 0, simConfig.innerTOFRadius * o2::constants::math::TwoPI}}); histos.add("oTOF/h2dVelocityVsMomentumOuter", "h2dVelocityVsMomentumOuter", kTH2F, {axisMomentum, axisVelocity}); histos.add("oTOF/h2dVelocityVsRigidityOuter", "h2dVelocityVsRigidityOuter", kTH2F, {axisRigidity, axisVelocity}); histos.add("oTOF/h2dTrackLengthOuterVsPt", "h2dTrackLengthOuterVsPt", kTH2F, {axisMomentumSmall, axisTrackLengthOuter}); histos.add("oTOF/h2dTrackLengthOuterRecoVsPt", "h2dTrackLengthOuterRecoVsPt", kTH2F, {axisMomentumSmall, axisTrackLengthOuter}); histos.add("oTOF/h2dDeltaTrackLengthOuterVsPt", "h2dDeltaTrackLengthOuterVsPt", kTH2F, {axisMomentumSmall, axisTrackDeltaLength}); - histos.add("oTOF/h2HitMap", "h2HitMap", kTH2F, {{1000, -simConfig.outerTOFLength / 2, simConfig.outerTOFLength / 2}, {1000, 0, simConfig.outerTOFRadius * 2 * M_PI}}); + histos.add("oTOF/h2HitMap", "h2HitMap", kTH2F, {{1000, -simConfig.outerTOFLength / 2, simConfig.outerTOFLength / 2}, {1000, 0, simConfig.outerTOFRadius * o2::constants::math::TwoPI}}); const AxisSpec axisPt{static_cast(plotsConfig.nBinsP), 0.0f, +4.0f, "#it{p}_{T} (GeV/#it{c})"}; const AxisSpec axisEta{static_cast(plotsConfig.nBinsEta), -2.0f, +2.0f, "#eta"}; @@ -252,35 +307,41 @@ struct OnTheFlyTofPid { histos.add("h2dRelativePtResolution", "h2dRelativePtResolution", kTH2F, {axisPt, axisRelativePt}); histos.add("h2dRelativeEtaResolution", "h2dRelativeEtaResolution", kTH2F, {axisEta, axisRelativeEta}); - std::string particleNames[kParticles] = {"#it{e}", "#it{#mu}", "#it{#pi}", "#it{K}", "#it{p}", "#it{d}", "#it{t}", "^{3}He", "#it{#alpha}"}; - std::string particleNames2[kParticles] = {"Elec", "Muon", "Pion", "Kaon", "Prot", "Deut", "Trit", "He3", "Al"}; - for (int iTrue = 0; iTrue < kParticles; iTrue++) { + for (int iTrue = 0; iTrue < NParticles; iTrue++) { + if (!doQaForParticle(Particles[iTrue].pdgCode)) { + continue; + } + auto addHistogram = [&](const std::string& name, const AxisSpec& axis) { return histos.add(name, "", kTH2F, {axisMomentum, axis}); }; - const AxisSpec axisTrackTimeRes{plotsConfig.nBinsTimeRes, 0.0f, +200.0f, "Track time resolution - " + particleNames[iTrue] + " (ps)"}; - h2dInnerTimeResTrack[iTrue] = addHistogram("iTOF/res/h2dInnerTimeResTrack" + particleNames2[iTrue] + "VsP", axisTrackTimeRes); - h2dOuterTimeResTrack[iTrue] = addHistogram("oTOF/res/h2dOuterTimeResTrack" + particleNames2[iTrue] + "VsP", axisTrackTimeRes); - const AxisSpec axisTotalTimeRes{plotsConfig.nBinsTimeRes, 0.0f, +200.0f, "Total time resolution - " + particleNames[iTrue] + " (ps)"}; - h2dInnerTimeResTotal[iTrue] = addHistogram("iTOF/res/h2dInnerTimeResTotal" + particleNames2[iTrue] + "VsP", axisTotalTimeRes); - h2dOuterTimeResTotal[iTrue] = addHistogram("oTOF/res/h2dOuterTimeResTotal" + particleNames2[iTrue] + "VsP", axisTotalTimeRes); - for (int iHyp = 0; iHyp < kParticles; iHyp++) { - std::string nameTitleInner = "h2dInnerNsigmaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis"; - std::string nameTitleOuter = "h2dOuterNsigmaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis"; - std::string nameTitleInnerDelta = "h2dInnerDeltaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis"; - std::string nameTitleOuterDelta = "h2dOuterDeltaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis"; + const AxisSpec axisTrackTimeRes{plotsConfig.nBinsTimeRes, 0.0f, +200.0f, std::string("Track time resolution - ") + Particles[iTrue].texName + " (ps)"}; + h2dInnerTimeResTrack[iTrue] = addHistogram(std::string("iTOF/res/h2dInnerTimeResTrack") + Particles[iTrue].name + "VsP", axisTrackTimeRes); + h2dOuterTimeResTrack[iTrue] = addHistogram(std::string("oTOF/res/h2dOuterTimeResTrack") + Particles[iTrue].name + "VsP", axisTrackTimeRes); + const AxisSpec axisTotalTimeRes{plotsConfig.nBinsTimeRes, 0.0f, +200.0f, std::string("Total time resolution - ") + Particles[iTrue].texName + " (ps)"}; + h2dInnerTimeResTotal[iTrue] = addHistogram(std::string("iTOF/res/h2dInnerTimeResTotal") + Particles[iTrue].name + "VsP", axisTotalTimeRes); + h2dOuterTimeResTotal[iTrue] = addHistogram(std::string("oTOF/res/h2dOuterTimeResTotal") + Particles[iTrue].name + "VsP", axisTotalTimeRes); + for (int iHyp = 0; iHyp < NParticles; iHyp++) { + if (!doQaForParticle(Particles[iHyp].pdgCode)) { + continue; + } + + std::string nameTitleInner = std::string("h2dInnerNsigmaTrue") + Particles[iTrue].name + "Vs" + Particles[iHyp].name + "Hypothesis"; + std::string nameTitleOuter = std::string("h2dOuterNsigmaTrue") + Particles[iTrue].name + "Vs" + Particles[iHyp].name + "Hypothesis"; + std::string nameTitleInnerDelta = std::string("h2dInnerDeltaTrue") + Particles[iTrue].name + "Vs" + Particles[iHyp].name + "Hypothesis"; + std::string nameTitleOuterDelta = std::string("h2dOuterDeltaTrue") + Particles[iTrue].name + "Vs" + Particles[iHyp].name + "Hypothesis"; const AxisSpec axisX{plotsConfig.doSeparationVsPt.value ? axisPt : axisMomentum}; - const AxisSpec axisNsigmaCorrect{plotsConfig.nBinsNsigmaCorrectSpecies, plotsConfig.minNsigmaRange, plotsConfig.maxNsigmaRange, "N#sigma - True " + particleNames[iTrue] + " vs " + particleNames[iHyp] + " hypothesis"}; - const AxisSpec axisDeltaCorrect{plotsConfig.nBinsDeltaCorrectSpecies, plotsConfig.minDeltaRange, plotsConfig.maxDeltaRange, "#Delta - True " + particleNames[iTrue] + " vs " + particleNames[iHyp] + " hypothesis"}; - const AxisSpec axisNsigmaWrong{plotsConfig.nBinsNsigmaWrongSpecies, plotsConfig.minNsigmaRange, plotsConfig.maxNsigmaRange, "N#sigma - True " + particleNames[iTrue] + " vs " + particleNames[iHyp] + " hypothesis"}; - const AxisSpec axisDeltaWrong{plotsConfig.nBinsDeltaWrongSpecies, plotsConfig.minDeltaRange, plotsConfig.maxDeltaRange, "#Delta - True " + particleNames[iTrue] + " vs " + particleNames[iHyp] + " hypothesis"}; + const AxisSpec axisNsigmaCorrect{plotsConfig.nBinsNsigmaCorrectSpecies, plotsConfig.minNsigmaRange, plotsConfig.maxNsigmaRange, std::string("N#sigma - True ") + Particles[iTrue].texName + " vs " + Particles[iHyp].texName + " hypothesis"}; + const AxisSpec axisDeltaCorrect{plotsConfig.nBinsDeltaCorrectSpecies, plotsConfig.minDeltaRange, plotsConfig.maxDeltaRange, std::string("#Delta - True ") + Particles[iTrue].texName + " vs " + Particles[iHyp].texName + " hypothesis"}; + const AxisSpec axisNsigmaWrong{plotsConfig.nBinsNsigmaWrongSpecies, plotsConfig.minNsigmaRange, plotsConfig.maxNsigmaRange, std::string("N#sigma - True ") + Particles[iTrue].texName + " vs " + Particles[iHyp].texName + " hypothesis"}; + const AxisSpec axisDeltaWrong{plotsConfig.nBinsDeltaWrongSpecies, plotsConfig.minDeltaRange, plotsConfig.maxDeltaRange, std::string("#Delta - True ") + Particles[iTrue].texName + " vs " + Particles[iHyp].texName + " hypothesis"}; const AxisSpec axisNSigma{iTrue == iHyp ? axisNsigmaCorrect : axisNsigmaWrong}; const AxisSpec axisDelta{iTrue == iHyp ? axisDeltaCorrect : axisDeltaWrong}; - h2dInnerNsigmaTrue[iTrue][iHyp] = histos.add("iTOF/nsigma/h2dInnerNsigmaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis", "", kTH2F, {axisX, axisNSigma}); - h2dOuterNsigmaTrue[iTrue][iHyp] = histos.add("oTOF/nsigma/h2dOuterNsigmaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis", "", kTH2F, {axisX, axisNSigma}); - h2dInnerDeltaTrue[iTrue][iHyp] = histos.add("iTOF/delta/h2dInnerDeltaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis", "", kTH2F, {axisX, axisDelta}); - h2dOuterDeltaTrue[iTrue][iHyp] = histos.add("oTOF/delta/h2dOuterDeltaTrue" + particleNames2[iTrue] + "Vs" + particleNames2[iHyp] + "Hypothesis", "", kTH2F, {axisX, axisDelta}); + h2dInnerNsigmaTrue[iTrue][iHyp] = histos.add(std::string("iTOF/nsigma/h2dInnerNsigmaTrue") + Particles[iTrue].name + "Vs" + Particles[iHyp].name + "Hypothesis", nameTitleInner.c_str(), kTH2F, {axisX, axisNSigma}); + h2dOuterNsigmaTrue[iTrue][iHyp] = histos.add(std::string("oTOF/nsigma/h2dOuterNsigmaTrue") + Particles[iTrue].name + "Vs" + Particles[iHyp].name + "Hypothesis", nameTitleOuter.c_str(), kTH2F, {axisX, axisNSigma}); + h2dInnerDeltaTrue[iTrue][iHyp] = histos.add(std::string("iTOF/delta/h2dInnerDeltaTrue") + Particles[iTrue].name + "Vs" + Particles[iHyp].name + "Hypothesis", nameTitleInnerDelta.c_str(), kTH2F, {axisX, axisDelta}); + h2dOuterDeltaTrue[iTrue][iHyp] = histos.add(std::string("oTOF/delta/h2dOuterDeltaTrue") + Particles[iTrue].name + "Vs" + Particles[iHyp].name + "Hypothesis", nameTitleOuterDelta.c_str(), kTH2F, {axisX, axisDelta}); } } } @@ -326,19 +387,20 @@ struct OnTheFlyTofPid { : layerRadius(r), layerLength(l), pixelDimensionZ(pDimensions[0]), pixelDimensionRPhi(pDimensions[1]), fractionInactive(fIA), magField(m) { // Assuming square pixels for simplicity - const float circumference = 2.0f * M_PI * layerRadius; + const float circumference = o2::constants::math::TwoPI * layerRadius; axisZ = new TAxis(static_cast(layerLength / pixelDimensionZ), -layerLength / 2, layerLength); axisRPhi = new TAxis(static_cast(circumference / pixelDimensionRPhi), 0.f, circumference); const float inactiveBorderRPhi = pixelDimensionRPhi * std::sqrt(fractionInactive) / 2; const float inactiveBorderZ = pixelDimensionZ * std::sqrt(fractionInactive) / 2; - const double arrayRPhi[4] = {-pixelDimensionRPhi / 2, -pixelDimensionRPhi / 2 + inactiveBorderRPhi, pixelDimensionRPhi / 2 - inactiveBorderRPhi, pixelDimensionRPhi / 2}; - for (int i = 0; i < 4; i++) { + static constexpr int NDimBorderArray = 4; + const double arrayRPhi[NDimBorderArray] = {-pixelDimensionRPhi / 2, -pixelDimensionRPhi / 2 + inactiveBorderRPhi, pixelDimensionRPhi / 2 - inactiveBorderRPhi, pixelDimensionRPhi / 2}; + for (int i = 0; i < NDimBorderArray; i++) { LOG(info) << "arrayRPhi[" << i << "] = " << arrayRPhi[i]; } axisInPixelRPhi = new TAxis(3, arrayRPhi); - const double arrayZ[4] = {-pixelDimensionZ / 2, -pixelDimensionZ / 2 + inactiveBorderZ, pixelDimensionZ / 2 - inactiveBorderZ, pixelDimensionZ / 2}; - for (int i = 0; i < 4; i++) { + const double arrayZ[NDimBorderArray] = {-pixelDimensionZ / 2, -pixelDimensionZ / 2 + inactiveBorderZ, pixelDimensionZ / 2 - inactiveBorderZ, pixelDimensionZ / 2}; + for (int i = 0; i < NDimBorderArray; i++) { LOG(info) << "arrayZ[" << i << "] = " << arrayZ[i]; } axisInPixelZ = new TAxis(3, arrayZ); @@ -364,7 +426,8 @@ struct OnTheFlyTofPid { const float r = std::sqrt(hitPosition[0] * hitPosition[0] + hitPosition[1] * hitPosition[1]); // Check if hit is within layer geometric acceptance - if (std::abs(layerRadius - r) > 10.f) { + static constexpr float LayerGeometricAcceptance = 10.f; + if (std::abs(layerRadius - r) > LayerGeometricAcceptance) { LOG(debug) << "Hit out of TOF layer acceptance: r=" << r << " cm with respect to the layer radius " << layerRadius; return false; } @@ -516,10 +579,10 @@ struct OnTheFlyTofPid { sumw += w; } - static constexpr float kMaxEventTimeResolution = 200.f; - if (sumw <= 0. || tracks.size() <= 1 || std::sqrt(1. / sumw) > kMaxEventTimeResolution) { - tzero[0] = 0.; // [ps] - tzero[1] = kMaxEventTimeResolution; // [ps] + static constexpr float MaxEventTimeResolution = 200.f; + if (sumw <= 0. || tracks.size() <= 1 || std::sqrt(1. / sumw) > MaxEventTimeResolution) { + tzero[0] = 0.; // [ps] + tzero[1] = MaxEventTimeResolution; // [ps] return false; } @@ -616,12 +679,12 @@ struct OnTheFlyTofPid { o2::track::TrackParCov o2track = o2::upgrade::convertMCParticleToO2Track(mcParticle, pdg); float xPv = -100.f; - static constexpr float kTrkXThreshold = -99.f; // Threshold to consider a good propagation of the track + static constexpr float TrkXThreshold = -99.f; // Threshold to consider a good propagation of the track if (o2track.propagateToDCA(mcPvVtx, mMagneticField)) { xPv = o2track.getX(); } float trackLengthInnerTOF = -1, trackLengthOuterTOF = -1; - if (xPv > kTrkXThreshold) { + if (xPv > TrkXThreshold) { trackLengthInnerTOF = o2::upgrade::computeTrackLength(o2track, simConfig.innerTOFRadius, mMagneticField); trackLengthOuterTOF = o2::upgrade::computeTrackLength(o2track, simConfig.outerTOFRadius, mMagneticField); } @@ -673,7 +736,7 @@ struct OnTheFlyTofPid { if (recoTrack.propagateToDCA(pvVtx, mMagneticField)) { xPv = recoTrack.getX(); } - if (xPv > kTrkXThreshold) { + if (xPv > TrkXThreshold) { trackLengthRecoInnerTOF = o2::upgrade::computeTrackLength(recoTrack, simConfig.innerTOFRadius, mMagneticField); trackLengthRecoOuterTOF = o2::upgrade::computeTrackLength(recoTrack, simConfig.outerTOFRadius, mMagneticField); } @@ -733,30 +796,10 @@ struct OnTheFlyTofPid { const float noSmearingPt = trkWithTime.mNoSmearingPt; // Straight to Nsigma - static std::array expectedTimeInnerTOF, expectedTimeOuterTOF; - static std::array deltaTimeInnerTOF, deltaTimeOuterTOF; - static std::array nSigmaInnerTOF, nSigmaOuterTOF; - static constexpr int kParticlePdgs[kParticles] = {kElectron, - kMuonMinus, - kPiPlus, - kKPlus, - kProton, - o2::constants::physics::kDeuteron, - o2::constants::physics::kTriton, - o2::constants::physics::kHelium3, - o2::constants::physics::kAlpha}; - static constexpr float kParticleMasses[kParticles] = {o2::constants::physics::MassElectron, - o2::constants::physics::MassMuon, - o2::constants::physics::MassPionCharged, - o2::constants::physics::MassKaonCharged, - o2::constants::physics::MassProton, - o2::constants::physics::MassDeuteron, - o2::constants::physics::MassTriton, - o2::constants::physics::MassHelium3, - o2::constants::physics::MassAlpha}; - static constexpr float kParticleCharges[kParticles] = {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 2.f, 2.f}; - float momentumHypotheses[kParticles]; // Store momentum hypothesis for each particle - + static std::array expectedTimeInnerTOF, expectedTimeOuterTOF; + static std::array deltaTimeInnerTOF, deltaTimeOuterTOF; + static std::array nSigmaInnerTOF, nSigmaOuterTOF; + float momentumHypotheses[NParticles]; // Store momentum hypothesis for each particle auto truePdgInfo = pdg->GetParticle(mcParticle.pdgCode()); float rigidity = momentum; // fallback to momentum if charge unknown @@ -787,7 +830,7 @@ struct OnTheFlyTofPid { } // For every mass hypothesis compute the expected time, the delta with respect to it and the nsigma - for (int ii = 0; ii < kParticles; ii++) { + for (int ii = 0; ii < NParticles; ii++) { expectedTimeInnerTOF[ii] = -100; expectedTimeOuterTOF[ii] = -100; deltaTimeInnerTOF[ii] = -100; @@ -795,8 +838,8 @@ struct OnTheFlyTofPid { nSigmaInnerTOF[ii] = -100; nSigmaOuterTOF[ii] = -100; - momentumHypotheses[ii] = rigidity * kParticleCharges[ii]; // Total momentum for this hypothesis - const float v = o2::upgrade::computeParticleVelocity(momentumHypotheses[ii], kParticleMasses[ii]); + momentumHypotheses[ii] = rigidity * Particles[ii].charge; // Total momentum for this hypothesis + const float v = o2::upgrade::computeParticleVelocity(momentumHypotheses[ii], Particles[ii].mass); expectedTimeInnerTOF[ii] = trackLengthInnerTOF / v; expectedTimeOuterTOF[ii] = trackLengthOuterTOF / v; @@ -812,18 +855,18 @@ struct OnTheFlyTofPid { double ptResolution = transverseMomentum * transverseMomentum * std::sqrt(trkWithTime.mMomentum.second); double etaResolution = std::fabs(std::sin(2.0 * std::atan(std::exp(-pseudorapidity)))) * std::sqrt(trkWithTime.mPseudorapidity.second); if (simConfig.flagTOFLoadDelphesLUTs) { - if (mSmearer[collision.lutConfigId()]->hasTable(kParticlePdgs[ii])) { // Only if the LUT for this particle was loaded - ptResolution = mSmearer[collision.lutConfigId()]->getAbsPtRes(kParticlePdgs[ii], dNdEta, pseudorapidity, transverseMomentum); - etaResolution = mSmearer[collision.lutConfigId()]->getAbsEtaRes(kParticlePdgs[ii], dNdEta, pseudorapidity, transverseMomentum); + if (mSmearer[collision.lutConfigId()]->hasTable(Particles[ii].pdgCode)) { // Only if the LUT for this particle was loaded + ptResolution = mSmearer[collision.lutConfigId()]->getAbsPtRes(Particles[ii].pdgCode, dNdEta, pseudorapidity, transverseMomentum); + etaResolution = mSmearer[collision.lutConfigId()]->getAbsEtaRes(Particles[ii].pdgCode, dNdEta, pseudorapidity, transverseMomentum); } } - const float innerTrackTimeReso = calculateTrackTimeResolutionAdvanced(transverseMomentum, pseudorapidity, ptResolution, etaResolution, kParticleMasses[ii], simConfig.innerTOFRadius, mMagneticField); - const float outerTrackTimeReso = calculateTrackTimeResolutionAdvanced(transverseMomentum, pseudorapidity, ptResolution, etaResolution, kParticleMasses[ii], simConfig.outerTOFRadius, mMagneticField); + const float innerTrackTimeReso = calculateTrackTimeResolutionAdvanced(transverseMomentum, pseudorapidity, ptResolution, etaResolution, Particles[ii].mass, simConfig.innerTOFRadius, mMagneticField); + const float outerTrackTimeReso = calculateTrackTimeResolutionAdvanced(transverseMomentum, pseudorapidity, ptResolution, etaResolution, Particles[ii].mass, simConfig.outerTOFRadius, mMagneticField); innerTotalTimeReso = std::hypot(simConfig.innerTOFTimeReso, innerTrackTimeReso); outerTotalTimeReso = std::hypot(simConfig.outerTOFTimeReso, outerTrackTimeReso); if (plotsConfig.doQAplots) { - if (std::fabs(mcParticle.pdgCode()) == kParticlePdgs[ii]) { + if (doQaForParticle(Particles[ii].pdgCode) && std::fabs(mcParticle.pdgCode()) == Particles[ii].pdgCode) { if (trackLengthRecoInnerTOF > 0) { h2dInnerTimeResTrack[ii]->Fill(momentumHypotheses[ii], innerTrackTimeReso); h2dInnerTimeResTotal[ii]->Fill(momentumHypotheses[ii], innerTotalTimeReso); @@ -831,8 +874,7 @@ struct OnTheFlyTofPid { if (trackLengthRecoOuterTOF > 0) { h2dOuterTimeResTrack[ii]->Fill(momentumHypotheses[ii], outerTrackTimeReso); h2dOuterTimeResTotal[ii]->Fill(momentumHypotheses[ii], outerTotalTimeReso); - static constexpr int kIdPion = 2; - if (ii == kIdPion) { + if (ii == Pi) { histos.fill(HIST("h2dRelativePtResolution"), transverseMomentum, 100.0 * ptResolution / transverseMomentum); histos.fill(HIST("h2dRelativeEtaResolution"), pseudorapidity, 100.0 * etaResolution / (std::fabs(pseudorapidity) + 1e-6)); } @@ -844,25 +886,33 @@ struct OnTheFlyTofPid { // Fixme: assumes dominant resolution effect is the TOF resolution // and not the tracking itself. It's *probably* a fair assumption // but it should be tested further! --> FIXED IN THIS VERSION - if (trackLengthInnerTOF > 0 && trackLengthRecoInnerTOF > 0) + if (trackLengthInnerTOF > 0 && trackLengthRecoInnerTOF > 0) { nSigmaInnerTOF[ii] = deltaTimeInnerTOF[ii] / std::sqrt(innerTotalTimeReso * innerTotalTimeReso + tzero[1] * tzero[1]); - if (trackLengthOuterTOF > 0 && trackLengthRecoOuterTOF > 0) + } + if (trackLengthOuterTOF > 0 && trackLengthRecoOuterTOF > 0) { nSigmaOuterTOF[ii] = deltaTimeOuterTOF[ii] / std::sqrt(outerTotalTimeReso * outerTotalTimeReso + tzero[1] * tzero[1]); + } } if (plotsConfig.doQAplots) { - for (int ii = 0; ii < kParticles; ii++) { - if (std::fabs(mcParticle.pdgCode()) != pdg->GetParticle(kParticlePdgs[ii])->PdgCode()) { + for (int ii = 0; ii < NParticles; ii++) { + if (!doQaForParticle(Particles[ii].pdgCode) || std::fabs(mcParticle.pdgCode()) != pdg->GetParticle(Particles[ii].pdgCode)->PdgCode()) { continue; } if (trackLengthRecoInnerTOF > 0) { - for (int iii = 0; iii < kParticles; iii++) { + for (int iii = 0; iii < NParticles; iii++) { + if (!doQaForParticle(Particles[iii].pdgCode)) { + continue; + } h2dInnerNsigmaTrue[ii][iii]->Fill(momentumHypotheses[ii], nSigmaInnerTOF[iii]); h2dInnerDeltaTrue[ii][iii]->Fill(momentumHypotheses[ii], deltaTimeInnerTOF[iii]); } } if (trackLengthRecoOuterTOF > 0) { - for (int iii = 0; iii < kParticles; iii++) { + for (int iii = 0; iii < NParticles; iii++) { + if (!doQaForParticle(Particles[iii].pdgCode)) { + continue; + } h2dOuterNsigmaTrue[ii][iii]->Fill(momentumHypotheses[ii], nSigmaOuterTOF[iii]); h2dOuterDeltaTrue[ii][iii]->Fill(momentumHypotheses[ii], deltaTimeOuterTOF[iii]); } @@ -881,12 +931,16 @@ struct OnTheFlyTofPid { // Sigmas have been fully calculated. Please populate the NSigma helper table (once per track) upgradeTof(tzero[0], tzero[1], - nSigmaInnerTOF[0], nSigmaInnerTOF[1], nSigmaInnerTOF[2], nSigmaInnerTOF[3], nSigmaInnerTOF[4], nSigmaInnerTOF[5], nSigmaInnerTOF[6], nSigmaInnerTOF[7], nSigmaInnerTOF[8], + nSigmaInnerTOF[El], nSigmaInnerTOF[Mu], nSigmaInnerTOF[Pi], nSigmaInnerTOF[Ka], nSigmaInnerTOF[Pr], nSigmaInnerTOF[De], nSigmaInnerTOF[Tr], nSigmaInnerTOF[He], nSigmaInnerTOF[Al], measuredTimeInnerTOF, trackLengthRecoInnerTOF, - nSigmaOuterTOF[0], nSigmaOuterTOF[1], nSigmaOuterTOF[2], nSigmaOuterTOF[3], nSigmaOuterTOF[4], nSigmaOuterTOF[5], nSigmaOuterTOF[6], nSigmaOuterTOF[7], nSigmaOuterTOF[8], + nSigmaOuterTOF[El], nSigmaOuterTOF[Mu], nSigmaOuterTOF[Pi], nSigmaOuterTOF[Ka], nSigmaOuterTOF[Pr], nSigmaOuterTOF[De], nSigmaOuterTOF[Tr], nSigmaOuterTOF[He], nSigmaOuterTOF[Al], measuredTimeOuterTOF, trackLengthRecoOuterTOF); - upgradeTofExpectedTime(expectedTimeInnerTOF[0], expectedTimeInnerTOF[1], expectedTimeInnerTOF[2], expectedTimeInnerTOF[3], expectedTimeInnerTOF[4], expectedTimeInnerTOF[5], expectedTimeInnerTOF[6], expectedTimeInnerTOF[7], expectedTimeInnerTOF[8], - expectedTimeOuterTOF[0], expectedTimeOuterTOF[1], expectedTimeOuterTOF[2], expectedTimeOuterTOF[3], expectedTimeOuterTOF[4], expectedTimeOuterTOF[5], expectedTimeOuterTOF[6], expectedTimeOuterTOF[7], expectedTimeOuterTOF[8]); + upgradeTofExpectedTime(expectedTimeInnerTOF[El], expectedTimeInnerTOF[Mu], expectedTimeInnerTOF[Pi], expectedTimeInnerTOF[Ka], expectedTimeInnerTOF[Pr], expectedTimeInnerTOF[De], expectedTimeInnerTOF[Tr], expectedTimeInnerTOF[He], expectedTimeInnerTOF[Al], + expectedTimeOuterTOF[El], expectedTimeOuterTOF[Mu], expectedTimeOuterTOF[Pi], expectedTimeOuterTOF[Ka], expectedTimeOuterTOF[Pr], expectedTimeOuterTOF[De], expectedTimeOuterTOF[Tr], expectedTimeOuterTOF[He], expectedTimeOuterTOF[Al]); + upgradeTofShortLived(nSigmaInnerTOF[Sp], nSigmaInnerTOF[Sm], nSigmaInnerTOF[Xi], nSigmaInnerTOF[Om], + nSigmaOuterTOF[Sp], nSigmaOuterTOF[Sm], nSigmaOuterTOF[Xi], nSigmaOuterTOF[Om], + expectedTimeInnerTOF[Sp], expectedTimeInnerTOF[Sm], expectedTimeInnerTOF[Xi], expectedTimeInnerTOF[Om], + expectedTimeOuterTOF[Sp], expectedTimeOuterTOF[Sm], expectedTimeOuterTOF[Xi], expectedTimeOuterTOF[Om]); } if (trackWithTimeIndex != tracks.size()) { diff --git a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx index 5cd2c72412f..3ba58520e3b 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx @@ -23,6 +23,7 @@ /// \author Roberto Preghenella preghenella@bo.infn.it /// +#include "ALICE3/Core/Decayer.h" #include "ALICE3/Core/DetLayer.h" #include "ALICE3/Core/FastTracker.h" #include "ALICE3/Core/FlatTrackSmearer.h" @@ -101,8 +102,6 @@ #include #include -#include - using namespace o2; using namespace o2::framework; using std::array; @@ -290,9 +289,9 @@ struct OnTheFlyTracker { nSiliconHits(nSiliconHitsInput), nTPCHits(nTPCHitsInput), trackType(trackTypeInput) {} - const TimeEst& getTimeMUS() const { return timeEst; } + [[nodiscard]] const TimeEst& getTimeMUS() const { return timeEst; } int64_t mcLabel = -1; ///< MC label of the track - TimeEst timeEst{}; ///< time estimate in ns + TimeEst timeEst; ///< time estimate in ns bool isDecayDau = false; ///< is a decay daughter bool isPVContributor = false; ///< track is PV contributor bool isWeakDecayDau = false; ///< is a weak decay daughter @@ -378,6 +377,9 @@ struct OnTheFlyTracker { // Track smearer array, one per geometry std::vector> mSmearer; + // Configuration defined at init time + o2::fastsim::GeometryContainer mGeoContainer; + float mMagneticField = 0.0f; // For processing and vertexing std::vector recoPrimaries; @@ -395,10 +397,8 @@ struct OnTheFlyTracker { // For TGenPhaseSpace seed TRandom3 rand; Service ccdb{}; + o2::upgrade::Decayer decayer; - // Configuration defined at init time - o2::fastsim::GeometryContainer mGeoContainer; - float mMagneticField = 0.0f; // Time resolution constants static constexpr float timeResolutionNs = 100.f; // ns static constexpr float nsToMus = 1e-3f; @@ -423,7 +423,7 @@ struct OnTheFlyTracker { std::get>(it->second)->Fill(std::forward(args)...); } - void insertHist(const std::string& name, const std::string& title, HistType type, std::vector axisSpecs) + void insertHist(const std::string& name, const std::string& title, HistType type, const std::vector& axisSpecs) { histPointers[name] = histos.add(name.c_str(), title.c_str(), type, axisSpecs); } @@ -438,6 +438,7 @@ struct OnTheFlyTracker { const int nGeometries = mGeoContainer.getNumberOfConfigurations(); mMagneticField = mGeoContainer.getFloatValue(0, "global", "magneticfield"); + decayer.setBField(mMagneticField); for (int icfg = 0; icfg < nGeometries; ++icfg) { const std::string histPath = "Configuration_" + std::to_string(icfg) + "/"; mSmearer.emplace_back(std::make_unique()); @@ -447,7 +448,7 @@ struct OnTheFlyTracker { // load LUTs for primaries for (const auto& entry : globalConfiguration) { int pdg = 0; - if (entry.first.find("lut") != 0) { + if (!entry.first.starts_with("lut")) { continue; } if (entry.first.find("lutEl") != std::string::npos) { @@ -484,8 +485,7 @@ struct OnTheFlyTracker { if (filename.empty()) { LOG(warning) << "No LUT file passed for pdg " << pdg << ", skipping."; } - bool success = mSmearer[icfg]->loadTable(pdg, filename.c_str()); - if (!success) { + if (!mSmearer[icfg]->loadTable(pdg, filename.c_str())) { LOG(fatal) << "Having issue with loading the LUT " << pdg << " " << filename; } } @@ -497,7 +497,7 @@ struct OnTheFlyTracker { mSmearer[icfg]->skipUnreconstructed(!processUnreconstructedTracks.value); insertHist(histPath + "hPtGenerated", "hPtGenerated;#it{p}_{T} (GeV/c);Counts", kTH1D, {{axes.axisMomentum}}); - insertHist(histPath + "hPhiGenerated", "hPhiGenerated;#phi (rad);Counts", kTH1D, {{100, 0.0f, 2 * M_PI, "#phi (rad)"}}); + insertHist(histPath + "hPhiGenerated", "hPhiGenerated;#phi (rad);Counts", kTH1D, {{100, 0.0f, o2::constants::math::TwoPI, "#phi (rad)"}}); insertHist(histPath + "hPtGeneratedEl", "hPtGeneratedEl;Gen #it{p}_{T} (GeV/c);Counts", kTH1D, {{axes.axisMomentum}}); insertHist(histPath + "hPtGeneratedPi", "hPtGeneratedPi;Gen #it{p}_{T} (GeV/c);Counts", kTH1D, {{axes.axisMomentum}}); @@ -528,14 +528,16 @@ struct OnTheFlyTracker { getHist(histPath + "hVtxTrials")->GetXaxis()->SetBinLabel(2, "Succeeded"); } - if (enableSecondarySmearing) { + if (enableSecondarySmearing || + fastPrimaryTrackerSettings.fastTrackPrimaries || + fastPrimaryTrackerSettings.fastTrackShortLivedParticles) { fastTracker.emplace_back(std::make_unique()); - fastTracker[icfg]->SetMagneticField(mMagneticField); - fastTracker[icfg]->SetApplyZacceptance(fastTrackerSettings.applyZacceptance); - fastTracker[icfg]->SetApplyMSCorrection(fastTrackerSettings.applyMSCorrection); - fastTracker[icfg]->SetApplyElossCorrection(fastTrackerSettings.applyElossCorrection); - fastTracker[icfg]->AddGenericDetector(mGeoContainer.getEntry(icfg), ccdb.operator->()); - fastTracker[icfg]->Print(); // print fastTracker settings + fastTracker[icfg]->setMagneticField(mMagneticField); + fastTracker[icfg]->setApplyZacceptance(fastTrackerSettings.applyZacceptance); + fastTracker[icfg]->setApplyMSCorrection(fastTrackerSettings.applyMSCorrection); + fastTracker[icfg]->setApplyElossCorrection(fastTrackerSettings.applyElossCorrection); + fastTracker[icfg]->addGenericDetector(mGeoContainer.getEntry(icfg), ccdb.operator->()); + fastTracker[icfg]->print(); // print fastTracker settings if (cascadeDecaySettings.doXiQA) { insertHist(histPath + "hXiBuilding", "hXiBuilding", kTH1F, {{10, -0.5f, 9.5f}}); @@ -619,6 +621,14 @@ struct OnTheFlyTracker { insertHist(histPath + "h2dSecondaryKaPtRes", "h2dSecondaryKaPtRes;Gen p_{T};#Delta p_{T} / Reco p_{T}", kTH2D, {{axes.axisMomentum, axes.axisPtRes}}); insertHist(histPath + "h2dPrimaryPrPtRes", "h2dPrimaryPrPtRes;Gen p_{T};#Delta p_{T} / Reco p_{T}", kTH2D, {{axes.axisMomentum, axes.axisPtRes}}); insertHist(histPath + "h2dSecondaryPrPtRes", "h2dSecondaryPrPtRes;Gen p_{T};#Delta p_{T} / Reco p_{T}", kTH2D, {{axes.axisMomentum, axes.axisPtRes}}); + + if (fastPrimaryTrackerSettings.fastTrackShortLivedParticles) { + insertHist(histPath + "h2dGenShortLivedParticleRadius", "h2dGenShortLivedParticleRadius;Radius (cm);Momentum p_{T}", kTH2D, {{axes.axisDecayRadius, axes.axisMomentum}}); + insertHist(histPath + "h2dRecShortLivedParticleRadius", "h2dRecShortLivedParticleRadius;Radius (cm);Momentum p_{T}", kTH2D, {{axes.axisDecayRadius, axes.axisMomentum}}); + insertHist(histPath + "h2dGenRadiusIniVsDecay", "h2dGenRadiusIniVsDecay;Radius (cm);Radius (cm)", kTH2D, {{axes.axisDecayRadius, axes.axisDecayRadius}}); + insertHist(histPath + "h2dRecRadiusIniVsDecay", "h2dRecRadiusIniVsDecay;Radius (cm);Radius (cm)", kTH2D, {{axes.axisDecayRadius, axes.axisDecayRadius}}); + insertHist(histPath + "h2dDecayRadiusVsNhits", "h2dDecayRadiusVsNhits;Radius (cm);Nhits", kTH2D, {{axes.axisDecayRadius, {20, 0.5, 20}}}); + } } } // end config loop @@ -727,7 +737,7 @@ struct OnTheFlyTracker { // Cross-check LOGF(info, "Check field at (0, 0, 0): %.1f kG, nominal: %.1f", static_cast(fieldInstance->GetBz(0, 0, 0)), static_cast(field)); LOGF(info, "Initializing empty material cylinder LUT - could be better in the future"); - o2::base::MatLayerCylSet* lut = new o2::base::MatLayerCylSet(); + auto* lut = new o2::base::MatLayerCylSet(); lut->addLayer(200, 200.1, 2, 1.0f, 100.0f); LOGF(info, "MatLayerCylSet::optimizePhiSlices()"); lut->optimizePhiSlices(); @@ -1021,9 +1031,9 @@ struct OnTheFlyTracker { nSiliconHitsCascadeProngs[i] = 0; nTPCHitsCascadeProngs[i] = 0; if (enableSecondarySmearing) { - nHitsCascadeProngs[i] = fastTracker[icfg]->FastTrack(xiDaughterTrackParCovsPerfect[i], xiDaughterTrackParCovsTracked[i], dNdEta); - nSiliconHitsCascadeProngs[i] = fastTracker[icfg]->GetNSiliconPoints(); - nTPCHitsCascadeProngs[i] = fastTracker[icfg]->GetNGasPoints(); + nHitsCascadeProngs[i] = fastTracker[icfg]->fastTrack(xiDaughterTrackParCovsPerfect[i], xiDaughterTrackParCovsTracked[i], dNdEta); + nSiliconHitsCascadeProngs[i] = fastTracker[icfg]->getNSiliconPoints(); + nTPCHitsCascadeProngs[i] = fastTracker[icfg]->getNGasPoints(); if (nHitsCascadeProngs[i] < 0 && cascadeDecaySettings.doXiQA) { // QA getHist(histPath + "hFastTrackerQA")->Fill(o2::math_utils::abs(nHitsCascadeProngs[i])); @@ -1043,8 +1053,8 @@ struct OnTheFlyTracker { } isReco[i] = true; - for (uint32_t ih = 0; ih < fastTracker[icfg]->GetNHits() && cascadeDecaySettings.doXiQA; ih++) { - getHist(histPath + "hFastTrackerHits")->Fill(fastTracker[icfg]->GetHitZ(ih), std::hypot(fastTracker[icfg]->GetHitX(ih), fastTracker[icfg]->GetHitY(ih))); + for (uint32_t ih = 0; ih < fastTracker[icfg]->getNHits() && cascadeDecaySettings.doXiQA; ih++) { + getHist(histPath + "hFastTrackerHits")->Fill(fastTracker[icfg]->getHitZ(ih), std::hypot(fastTracker[icfg]->getHitX(ih), fastTracker[icfg]->getHitY(ih))); } } else { isReco[i] = true; @@ -1057,10 +1067,10 @@ struct OnTheFlyTracker { if (TMath::IsNaN(xiDaughterTrackParCovsTracked[i].getZ())) { isReco[i] = false; continue; - } else { - getHist(histPath + "hXiBuilding")->Fill(4.0f); - histos.fill(HIST("hNaNBookkeeping"), i + 1, 1.0f); } + getHist(histPath + "hXiBuilding")->Fill(4.0f); + histos.fill(HIST("hNaNBookkeeping"), i + 1, 1.0f); + trackTime = (eventCollisionTimeNS + gRandom->Gaus(0., timeResolutionNs)) * nsToMus; // TODO: add flag for whether it's a ghost track or not, currently assuming all are reconstructed tracks if they pass the fast tracker requirements TrackType trackType = isReco[i] ? TrackType::kRecoCascDaug : TrackType::kGenCascDaug; @@ -1209,8 +1219,8 @@ struct OnTheFlyTracker { if (cascadeDecaySettings.trackXi) { // optionally, add the points in the layers before the decay of the Xi // will back-track the perfect MC cascade to relevant layers, find hit, smear and add to smeared cascade - for (int i = fastTracker[icfg]->GetLayers().size() - 1; i >= 0; --i) { - o2::fastsim::DetLayer layer = fastTracker[icfg]->GetLayer(i); + for (int i = fastTracker[icfg]->getLayers().size() - 1; i >= 0; --i) { + o2::fastsim::DetLayer layer = fastTracker[icfg]->getLayer(i); if (layer.isInert()) { continue; // Not an active tracking layer } @@ -1284,8 +1294,8 @@ struct OnTheFlyTracker { if (isReco[0] && ((cascadeDecaySettings.doKinkReco == 1 && tryKinkReco) || cascadeDecaySettings.doKinkReco == 2)) { // mode 1 or 2 o2::track::TrackParCov trackedCascade; const o2::track::TrackParCov& trackedBach = xiDaughterTrackParCovsTracked[0]; - const int nCascHits = fastTracker[icfg]->FastTrack(perfectCascadeTrack, trackedCascade, dNdEta, xiDecayRadius2D); - reconstructedCascade = (fastTrackerSettings.minSiliconHitsForKinkReco < nCascHits) ? true : false; + const int nCascHits = fastTracker[icfg]->fastTrack(perfectCascadeTrack, trackedCascade, dNdEta, xiDecayRadius2D); + reconstructedCascade = fastTrackerSettings.minSiliconHitsForKinkReco < nCascHits; if (reconstructedCascade) { std::array pCasc{}; std::array pBach{}; @@ -1345,10 +1355,9 @@ struct OnTheFlyTracker { std::array{o2::constants::physics::MassPionCharged, o2::constants::physics::MassLambda}); newCascadeTrack.setPID(pdgCodeToPID(PDG_t::kXiMinus)); // FIXME: not OK for omegas float trackTime = (eventCollisionTimeNS + gRandom->Gaus(0., timeResolutionNs)) * nsToMus; - if (reconstructedCascade) { - tracksCascadeProngs[kCascProngs + 1] = TrackAlice3{newCascadeTrack, mcParticle.globalIndex(), trackTime, timeResolutionUs, false, false, false, 1, thisCascade.foundClusters, TrackType::kRecoCascDaug}; - } - tracksCascadeProngs[kCascProngs + 1] = TrackAlice3{newCascadeTrack, mcParticle.globalIndex(), trackTime, timeResolutionUs, false, false, false, 1, thisCascade.foundClusters, 0, TrackType::kRecoCascDaug}; + + tracksCascadeProngs[kCascProngs + 1] = TrackAlice3{newCascadeTrack, mcParticle.globalIndex(), trackTime, timeResolutionUs, false, false, false, 1, thisCascade.foundClusters, TrackType::kRecoCascDaug}; + fillCascadeTable = true; } // end fitter OK } // end cascade found @@ -1510,9 +1519,9 @@ struct OnTheFlyTracker { nV0SiliconHits[i] = 0; nV0TPCHits[i] = 0; if (enableSecondarySmearing) { - nV0Hits[i] = fastTracker[icfg]->FastTrack(v0DaughterTrackParCovsPerfect[i], v0DaughterTrackParCovsTracked[i], dNdEta); - nV0SiliconHits[i] = fastTracker[icfg]->GetNSiliconPoints(); - nV0TPCHits[i] = fastTracker[icfg]->GetNGasPoints(); + nV0Hits[i] = fastTracker[icfg]->fastTrack(v0DaughterTrackParCovsPerfect[i], v0DaughterTrackParCovsTracked[i], dNdEta); + nV0SiliconHits[i] = fastTracker[icfg]->getNSiliconPoints(); + nV0TPCHits[i] = fastTracker[icfg]->getNGasPoints(); if (nV0SiliconHits[i] >= fastTrackerSettings.minSiliconHits || (nV0SiliconHits[i] >= fastTrackerSettings.minSiliconHitsIfTPCUsed && @@ -1526,8 +1535,8 @@ struct OnTheFlyTracker { if (nV0Hits[i] < 0) { fillHist(Form("V0Building_Configuration_%i/hFastTrackerQA", icfg), o2::math_utils::abs(nV0Hits[i])); } - for (uint32_t ih = 0; ih < fastTracker[icfg]->GetNHits(); ih++) { - fillHist(Form("V0Building_Configuration_%i/hFastTrackerHits", icfg), fastTracker[icfg]->GetHitZ(ih), std::hypot(fastTracker[icfg]->GetHitX(ih), fastTracker[icfg]->GetHitY(ih))); + for (uint32_t ih = 0; ih < fastTracker[icfg]->getNHits(); ih++) { + fillHist(Form("V0Building_Configuration_%i/hFastTrackerHits", icfg), fastTracker[icfg]->getHitZ(ih), std::hypot(fastTracker[icfg]->getHitX(ih), fastTracker[icfg]->getHitY(ih))); } } } else { @@ -1827,57 +1836,58 @@ struct OnTheFlyTracker { /// \param trackParCov track of the particle to compute bremsstrahlung for void computeBremsstrahlungLoss(const int icfg, const auto& mcParticle, o2::track::TrackParCov& trackParCov) { - if (brSettings.radiateBR) { - const o2::fastsim::GeometryEntry geoEntry = mGeoContainer.getEntry(icfg); - - for (auto const& layerName : geoEntry.getLayerNames()) { - if (layerName.find("global") != std::string::npos) { // Layers with global tag are skipped - continue; - } + if (!brSettings.radiateBR) { + return; + } + const o2::fastsim::GeometryEntry geoEntry = mGeoContainer.getEntry(icfg); - float mass = o2::constants::physics::MassElectron; + for (auto const& layerName : geoEntry.getLayerNames()) { + if (layerName.find("global") != std::string::npos) { // Layers with global tag are skipped + continue; + } - switch (std::abs(mcParticle.pdgCode())) { - case kElectron: - mass = o2::constants::physics::MassElectron; - break; - case kMuonMinus: - mass = o2::constants::physics::MassMuon; - break; - case kPiPlus: - mass = o2::constants::physics::MassPionCharged; - break; - case kKPlus: - mass = o2::constants::physics::MassKaonCharged; - break; - case kProton: - mass = o2::constants::physics::MassProton; - break; - default: - break; - } + float mass = o2::constants::physics::MassElectron; + + switch (std::abs(mcParticle.pdgCode())) { + case kElectron: + mass = o2::constants::physics::MassElectron; + break; + case kMuonMinus: + mass = o2::constants::physics::MassMuon; + break; + case kPiPlus: + mass = o2::constants::physics::MassPionCharged; + break; + case kKPlus: + mass = o2::constants::physics::MassKaonCharged; + break; + case kProton: + mass = o2::constants::physics::MassProton; + break; + default: + break; + } - float lambda = brSettings.radiationStrength * mcParticle.e() * geoEntry.getFloatValue(layerName, "x0") / (mass * mass); - ULong64_t nPhotons = gRandom->Poisson(lambda); + float lambda = brSettings.radiationStrength * mcParticle.e() * geoEntry.getFloatValue(layerName, "x0") / (mass * mass); + ULong64_t nPhotons = gRandom->Poisson(lambda); - double initialMomentum = trackParCov.getP(); + double initialMomentum = trackParCov.getP(); - for (ULong64_t photon = 0; photon < nPhotons; ++photon) { - float radiativeLoss = 1.0f - brSettings.minBREnergyFraction * std::pow(brSettings.maxBREnergyFraction / brSettings.minBREnergyFraction, gRandom->Rndm()); - trackParCov.setQ2Pt(trackParCov.getQ2Pt() / radiativeLoss); - } + for (ULong64_t photon = 0; photon < nPhotons; ++photon) { + float radiativeLoss = 1.0f - brSettings.minBREnergyFraction * std::pow(brSettings.maxBREnergyFraction / brSettings.minBREnergyFraction, gRandom->Rndm()); + trackParCov.setQ2Pt(trackParCov.getQ2Pt() / radiativeLoss); + } - double afterRadiationMomentum = trackParCov.getP(); + double afterRadiationMomentum = trackParCov.getP(); - if (brSettings.doBRQA) { - const std::string histPath = "Configuration_" + std::to_string(icfg) + "/"; + if (brSettings.doBRQA) { + const std::string histPath = "Configuration_" + std::to_string(icfg) + "/"; - getHist(histPath + "h1dNBRPhotons")->Fill(static_cast(nPhotons)); - getHist(histPath + "h1dBREnergyLoss")->Fill((initialMomentum - afterRadiationMomentum) / afterRadiationMomentum); + getHist(histPath + "h1dNBRPhotons")->Fill(static_cast(nPhotons)); + getHist(histPath + "h1dBREnergyLoss")->Fill((initialMomentum - afterRadiationMomentum) / afterRadiationMomentum); - getHist(histPath + "h2dBRPtRes")->Fill(trackParCov.getPt(), (trackParCov.getPt() - mcParticle.pt()) / trackParCov.getPt()); - getHist(histPath + "h2dBRPtResAbs")->Fill(trackParCov.getPt(), trackParCov.getPt() - mcParticle.pt()); - } + getHist(histPath + "h2dBRPtRes")->Fill(trackParCov.getPt(), (trackParCov.getPt() - mcParticle.pt()) / trackParCov.getPt()); + getHist(histPath + "h2dBRPtResAbs")->Fill(trackParCov.getPt(), trackParCov.getPt() - mcParticle.pt()); } } } @@ -1902,7 +1912,6 @@ struct OnTheFlyTracker { uint32_t multiplicityCounter = 0; // Now that the multiplicity is known, we can process the particles to smear them for (const auto& mcParticle : mcParticles) { - if (!mcParticle.isPhysicalPrimary()) { continue; } @@ -1942,12 +1951,21 @@ struct OnTheFlyTracker { bool reconstructed = true; int nTrkHits = 0; if (enablePrimarySmearing) { - if (fastPrimaryTrackerSettings.fastTrackPrimaries || fastPrimaryTrackerSettings.fastTrackShortLivedParticles) { - o2::track::TrackParCov perfectTrackParCov; - o2::upgrade::convertMCParticleToO2Track(mcParticle, perfectTrackParCov, pdgDB); + if (fastPrimaryTrackerSettings.fastTrackPrimaries && longLivedToBeHandled) { + o2::track::TrackParCov perfectTrackParCov = o2::upgrade::convertMCParticleToO2Track(mcParticle, pdgDB); + perfectTrackParCov.setPID(pdgCodeToPID(mcParticle.pdgCode())); + computeBremsstrahlungLoss(icfg, mcParticle, perfectTrackParCov); + nTrkHits = fastTracker[icfg]->fastTrack(perfectTrackParCov, trackParCov, dNdEta); + if (nTrkHits < fastPrimaryTrackerSettings.minSiliconHits) { + reconstructed = false; + } + } else if (fastPrimaryTrackerSettings.fastTrackShortLivedParticles && shortLivedToBeHandled) { + o2::track::TrackParCov perfectTrackParCov = o2::upgrade::convertMCParticleToO2Track(mcParticle, pdgDB); perfectTrackParCov.setPID(pdgCodeToPID(mcParticle.pdgCode())); computeBremsstrahlungLoss(icfg, mcParticle, perfectTrackParCov); - nTrkHits = fastTracker[icfg]->FastTrack(perfectTrackParCov, trackParCov, dNdEta); + const std::array decayVtx = decayer.generateDecayVertex(mcParticle, pdgDB); + const float decayRadius2D = std::hypot(decayVtx[0], decayVtx[1]); + nTrkHits = fastTracker[icfg]->fastTrack(perfectTrackParCov, trackParCov, dNdEta, decayRadius2D); if (nTrkHits < fastPrimaryTrackerSettings.minSiliconHits) { reconstructed = false; } @@ -1959,28 +1977,44 @@ struct OnTheFlyTracker { } getHist(histPath + "hPtGenerated")->Fill(mcParticle.pt()); getHist(histPath + "hPhiGenerated")->Fill(mcParticle.phi()); - if (std::abs(mcParticle.pdgCode()) == kElectron) - getHist(histPath + "hPtGeneratedEl")->Fill(mcParticle.pt()); - if (std::abs(mcParticle.pdgCode()) == kPiPlus) - getHist(histPath + "hPtGeneratedPi")->Fill(mcParticle.pt()); - if (std::abs(mcParticle.pdgCode()) == kKPlus) - getHist(histPath + "hPtGeneratedKa")->Fill(mcParticle.pt()); - if (std::abs(mcParticle.pdgCode()) == kProton) - getHist(histPath + "hPtGeneratedPr")->Fill(mcParticle.pt()); + switch (std::abs(mcParticle.pdgCode())) { + case kElectron: + getHist(histPath + "hPtGeneratedEl")->Fill(mcParticle.pt()); + break; + case kPiPlus: + getHist(histPath + "hPtGeneratedPi")->Fill(mcParticle.pt()); + break; + case kKPlus: + getHist(histPath + "hPtGeneratedKa")->Fill(mcParticle.pt()); + break; + case kProton: + getHist(histPath + "hPtGeneratedPr")->Fill(mcParticle.pt()); + break; + default: + break; + } if (!reconstructed && !processUnreconstructedTracks) { continue; } getHist(histPath + "hPtReconstructed")->Fill(trackParCov.getPt()); - if (std::abs(mcParticle.pdgCode()) == kElectron) - getHist(histPath + "hPtReconstructedEl")->Fill(trackParCov.getPt()); - if (std::abs(mcParticle.pdgCode()) == kPiPlus) - getHist(histPath + "hPtReconstructedPi")->Fill(trackParCov.getPt()); - if (std::abs(mcParticle.pdgCode()) == kKPlus) - getHist(histPath + "hPtReconstructedKa")->Fill(trackParCov.getPt()); - if (std::abs(mcParticle.pdgCode()) == kProton) - getHist(histPath + "hPtReconstructedPr")->Fill(trackParCov.getPt()); + switch (std::abs(mcParticle.pdgCode())) { + case kElectron: + getHist(histPath + "hPtReconstructedEl")->Fill(mcParticle.pt()); + break; + case kPiPlus: + getHist(histPath + "hPtReconstructedPi")->Fill(mcParticle.pt()); + break; + case kKPlus: + getHist(histPath + "hPtReconstructedKa")->Fill(mcParticle.pt()); + break; + case kProton: + getHist(histPath + "hPtReconstructedPr")->Fill(mcParticle.pt()); + break; + default: + break; + } } if (doExtraQA) { getHist(histPath + "h2dPtRes")->Fill(trackParCov.getPt(), (trackParCov.getPt() - mcParticle.pt()) / trackParCov.getPt()); @@ -2051,8 +2085,8 @@ struct OnTheFlyTracker { // do bookkeeping of fastTracker tracking if (enableSecondarySmearing) { - histos.fill(HIST("hCovMatOK"), 0.0f, fastTracker[icfg]->GetCovMatNotOK()); - histos.fill(HIST("hCovMatOK"), 1.0f, fastTracker[icfg]->GetCovMatOK()); + histos.fill(HIST("hCovMatOK"), 0.0f, fastTracker[icfg]->getCovMatNotOK()); + histos.fill(HIST("hCovMatOK"), 1.0f, fastTracker[icfg]->getCovMatOK()); } if (doExtraQA) { histos.fill(HIST("hRecoVsSimMultiplicity"), multiplicityCounter, recoPrimaries.size()); @@ -2147,27 +2181,28 @@ struct OnTheFlyTracker { computeBremsstrahlungLoss(icfg, mcParticle, trackParCov); reconstructed = mSmearer[icfg]->smearTrack(trackParCov, mcParticle.pdgCode(), dNdEta); } else if (shortLivedToBeHandled && fastPrimaryTrackerSettings.fastTrackShortLivedParticles) { - o2::track::TrackParCov perfectTrackParCov; - o2::upgrade::convertMCParticleToO2Track(mcParticle, perfectTrackParCov, pdgDB); + o2::track::TrackParCov perfectTrackParCov = o2::upgrade::convertMCParticleToO2Track(mcParticle, pdgDB); perfectTrackParCov.setPID(pdgCodeToPID(mcParticle.pdgCode())); computeBremsstrahlungLoss(icfg, mcParticle, perfectTrackParCov); - nTrkHits = fastTracker[icfg]->FastTrack(perfectTrackParCov, trackParCov, dNdEta); + nTrkHits = fastTracker[icfg]->fastTrack(perfectTrackParCov, trackParCov, dNdEta, mcParticle.decayRadius()); + getHist(histPath + "h2dGenShortLivedParticleRadius")->Fill(mcParticle.decayRadius(), perfectTrackParCov.getPt()); + getHist(histPath + "h2dGenRadiusIniVsDecay")->Fill(std::hypot(perfectTrackParCov.getX(), perfectTrackParCov.getY()), mcParticle.decayRadius()); if (nTrkHits < fastPrimaryTrackerSettings.minSiliconHits) { reconstructed = false; } else { reconstructed = true; + getHist(histPath + "h2dRecShortLivedParticleRadius")->Fill(mcParticle.decayRadius(), perfectTrackParCov.getPt()); + getHist(histPath + "h2dRecRadiusIniVsDecay")->Fill(std::hypot(perfectTrackParCov.getX(), perfectTrackParCov.getY()), mcParticle.decayRadius()); + getHist(histPath + "h2dDecayRadiusVsNhits")->Fill(mcParticle.decayRadius(), nTrkHits); + LOG(info) << mcParticle.decayRadius(); } } else if (enableSecondarySmearing && isSecondary) { o2::track::TrackParCov perfectTrackParCov; o2::upgrade::convertMCParticleToO2Track(mcParticle, perfectTrackParCov, pdgDB); computeBremsstrahlungLoss(icfg, mcParticle, perfectTrackParCov); perfectTrackParCov.setPID(pdgCodeToPID(mcParticle.pdgCode())); - nTrkHits = fastTracker[icfg]->FastTrack(perfectTrackParCov, trackParCov, dNdEta); - if (nTrkHits < fastTrackerSettings.minSiliconHits) { - reconstructed = false; - } else { - reconstructed = true; - } + nTrkHits = fastTracker[icfg]->fastTrack(perfectTrackParCov, trackParCov, dNdEta); + reconstructed = nTrkHits >= fastTrackerSettings.minSiliconHits; } if (!reconstructed && !processUnreconstructedTracks) { @@ -2259,7 +2294,7 @@ struct OnTheFlyTracker { fillTracksInfo(ghostTracksAlice3, primaryVertex, icfg); } - void processDecayer(aod::McCollision const& mcCollision, soa::Join const& mcParticles) + void processDecayer(aod::McCollision const& mcCollision, soa::Join const& mcParticles) { for (size_t icfg = 0; icfg < mSmearer.size(); ++icfg) { processConfigurationDev(mcCollision, mcParticles, static_cast(icfg)); diff --git a/ALICE3/TableProducer/OTF/onTheFlyTrackerPid.cxx b/ALICE3/TableProducer/OTF/onTheFlyTrackerPid.cxx index 7fbcc3e234b..5230849ff22 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTrackerPid.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTrackerPid.cxx @@ -304,7 +304,7 @@ struct OnTheFlyTrackerPid { return (measuredToT - expectedToT) / resolution; } - float getToTMeanFromMomentumSlice(std::shared_ptr hist, float momentum) + float getToTMeanFromMomentumSlice(const std::shared_ptr& hist, float momentum) { if (!hist) return -1.f; @@ -319,7 +319,7 @@ struct OnTheFlyTrackerPid { return mean; } - float getToTResolutionFromMomentumSlice(std::shared_ptr hist, float momentum) + float getToTResolutionFromMomentumSlice(const std::shared_ptr& hist, float momentum) { if (!hist) return -1.f; diff --git a/ALICE3/TableProducer/alice3-dileptonsmearing.cxx b/ALICE3/TableProducer/alice3-dileptonsmearing.cxx index 42e6a21783e..cca45f14c38 100644 --- a/ALICE3/TableProducer/alice3-dileptonsmearing.cxx +++ b/ALICE3/TableProducer/alice3-dileptonsmearing.cxx @@ -73,7 +73,24 @@ struct alice3dileptonsmearer { Configurable cfgMinPt{"cfgMinPt", -1, "if ptgen is smaller than this threshold, this value is used as input for ptgen."}; } electron_filenames; + struct : ConfigurableGroup { + std::string prefix = "pion_filename_group"; + Configurable cfgNDSmearing{"cfgNDSmearing", false, "apply ND-correlated smearing"}; + Configurable cfgResFileName{"cfgResFileName", "", "name of resolution file"}; + Configurable cfgResNDHistName{"cfgResNDHistName", "hs_reso", "name of ND resolution file"}; + Configurable cfgResPtHistName{"cfgResPtHistName", "RelPtResArrCocktail", "histogram name for pt in resolution file"}; + Configurable cfgResEtaHistName{"cfgResEtaHistName", "EtaResArr", "histogram name for eta in resolution file"}; + Configurable cfgResPhiPosHistName{"cfgResPhiPosHistName", "PhiPosResArr", "histogram name for phi pos in resolution file"}; + Configurable cfgResPhiNegHistName{"cfgResPhiNegHistName", "PhiEleResArr", "hisogram for phi neg in resolution file"}; + Configurable cfgEffFileName{"cfgEffFileName", "", "name of efficiency file"}; + Configurable cfgEffHistName{"cfgEffHistName", "fhwEffpT", "name of efficiency histogram"}; + Configurable cfgCcdbPathRes{"cfgCcdbPathRes", "", "path to the ccdb object for resolution"}; + Configurable cfgCcdbPathEff{"cfgCcdbPathEff", "", "path to the ccdb object for efficiency"}; + Configurable cfgMinPt{"cfgMinPt", -1, "if ptgen is smaller than this threshold, this value is used as input for ptgen."}; + } pion_filenames; + MomentumSmearer smearer_Electron; + MomentumSmearer smearer_Pion; Service ccdb; void init(InitContext&) @@ -99,6 +116,19 @@ struct alice3dileptonsmearer { smearer_Electron.setDCAHistName(""); smearer_Electron.setMinPt(electron_filenames.cfgMinPt); + smearer_Pion.setNDSmearing(pion_filenames.cfgNDSmearing.value); + smearer_Pion.setResFileName(TString(pion_filenames.cfgResFileName)); + smearer_Pion.setResNDHistName(TString(pion_filenames.cfgResNDHistName)); + smearer_Pion.setResPtHistName(TString(pion_filenames.cfgResPtHistName)); + smearer_Pion.setResEtaHistName(TString(pion_filenames.cfgResEtaHistName)); + smearer_Pion.setResPhiPosHistName(TString(pion_filenames.cfgResPhiPosHistName)); + smearer_Pion.setResPhiNegHistName(TString(pion_filenames.cfgResPhiNegHistName)); + smearer_Pion.setEffFileName(TString(pion_filenames.cfgEffFileName)); + smearer_Pion.setEffHistName(TString(pion_filenames.cfgEffHistName)); + smearer_Pion.setDCAFileName(""); + smearer_Pion.setDCAHistName(""); + smearer_Pion.setMinPt(pion_filenames.cfgMinPt); + if (cfgFromCcdb) { ccdb->setURL(cfgCcdbUrl); ccdb->setCaching(true); @@ -111,8 +141,17 @@ struct alice3dileptonsmearer { smearer_Electron.setCcdbPathDCA(""); smearer_Electron.setTimestamp(timestamp); smearer_Electron.setCcdb(ccdb); + + smearer_Pion.setCcdbPathRes(TString(pion_filenames.cfgCcdbPathRes)); + smearer_Pion.setCcdbPathEff(TString(pion_filenames.cfgCcdbPathEff)); + // smearer_Pion.setCcdbPathDCA(TString(pion_filenames.fConfigCcdbPathDCA)); + smearer_Pion.setCcdbPathDCA(""); + smearer_Pion.setTimestamp(timestamp); + smearer_Pion.setCcdb(ccdb); } + smearer_Electron.init(); + smearer_Pion.init(); } void processACTSHybrid(MyTracks const& tracks, const aod::McParticles& /*mcParticles*/) @@ -148,6 +187,30 @@ struct alice3dileptonsmearer { } // fill the table smearedelectron(ptsmeared, etasmeared, phismeared, selected); + } else if (std::abs(mcParticle.pdgCode()) == PDG_t::kPiPlus) { + int ch = -1; + if (mcParticle.pdgCode() < 0) { + ch = 1; + } + float ptsmeared = 0, etasmeared = 0, phismeared = 0; + // apply smearing for electrons or muons. + smearer_Pion.applySmearing(centrality, ch, ptgen, etagen, phigen, ptsmeared, etasmeared, phismeared); + // get the efficiency if there, otherwise applied zero + if ((TString(pion_filenames.cfgCcdbPathEff).CompareTo("") != 0) || (TString(pion_filenames.cfgEffFileName).CompareTo("") != 0)) { + float efficiency = smearer_Pion.getEfficiency(ptgen, etagen, phigen); + // Generate a random double between 0 and 1 + double myRandom = gRandom->Uniform(0, 1); + // Select + if (myRandom < efficiency) { + selected = true; + } else { + selected = false; + } + } else { + selected = false; + } + // fill the table + smearedelectron(ptsmeared, etasmeared, phismeared, selected); } else { // don't apply smearing and reject completely smearedelectron(ptgen, etagen, phigen, false); @@ -213,6 +276,7 @@ struct alice3dileptonchecksmearer { } registry.addClone("Electron/", "Others/"); + registry.addClone("Electron/", "Pions/"); } void processCheckACTSHybrid(MyTracksWithSmearing const& tracks, const aod::McParticles& /*mcParticles*/) @@ -222,13 +286,13 @@ struct alice3dileptonchecksmearer { continue; } const auto mcParticle = track.mcParticle_as(); + float deltaptoverpt = -1000.f; + if (mcParticle.pt() > 0.f) { + deltaptoverpt = (mcParticle.pt() - track.ptSmeared()) / mcParticle.pt(); + } + float deltaeta = mcParticle.eta() - track.etaSmeared(); + float deltaphi = mcParticle.phi() - track.phiSmeared(); if (std::abs(mcParticle.pdgCode()) == PDG_t::kElectron) { - float deltaptoverpt = -1000.f; - if (mcParticle.pt() > 0.f) { - deltaptoverpt = (mcParticle.pt() - track.ptSmeared()) / mcParticle.pt(); - } - float deltaeta = mcParticle.eta() - track.etaSmeared(); - float deltaphi = mcParticle.phi() - track.phiSmeared(); registry.fill(HIST("Electron/PtGen_DeltaPtOverPtGen"), mcParticle.pt(), deltaptoverpt); registry.fill(HIST("Electron/PtGen_DeltaEta"), mcParticle.pt(), deltaeta); if (mcParticle.pdgCode() < 0) { // e+ @@ -244,13 +308,23 @@ struct alice3dileptonchecksmearer { if (track.selected()) { registry.fill(HIST("Electron/PtEtaRec"), mcParticle.pt(), mcParticle.eta()); } - } else { - float deltaptoverpt = -1000.f; - if (mcParticle.pt() > 0.f) { - deltaptoverpt = (mcParticle.pt() - track.ptSmeared()) / mcParticle.pt(); + } else if (std::abs(mcParticle.pdgCode()) == PDG_t::kPiPlus) { + registry.fill(HIST("Pions/PtGen_DeltaPtOverPtGen"), mcParticle.pt(), deltaptoverpt); + registry.fill(HIST("Pions/PtGen_DeltaEta"), mcParticle.pt(), deltaeta); + if (mcParticle.pdgCode() < 0) { // e+ + registry.fill(HIST("Pions/PtGen_DeltaPhi_Pos"), mcParticle.pt(), deltaphi); + } else { // e- + registry.fill(HIST("Pions/PtGen_DeltaPhi_Neg"), mcParticle.pt(), deltaphi); } - float deltaeta = mcParticle.eta() - track.etaSmeared(); - float deltaphi = mcParticle.phi() - track.phiSmeared(); + registry.fill(HIST("Pions/hCorrelation_Pt"), mcParticle.pt(), track.ptSmeared()); + registry.fill(HIST("Pions/hCorrelation_Eta"), mcParticle.eta(), track.etaSmeared()); + registry.fill(HIST("Pions/hCorrelation_Phi"), mcParticle.phi(), track.phiSmeared()); + // efficiency + registry.fill(HIST("Pions/PtEtaGen"), mcParticle.pt(), mcParticle.eta()); + if (track.selected()) { + registry.fill(HIST("Pions/PtEtaRec"), mcParticle.pt(), mcParticle.eta()); + } + } else { registry.fill(HIST("Others/PtGen_DeltaPtOverPtGen"), mcParticle.pt(), deltaptoverpt); registry.fill(HIST("Others/PtGen_DeltaEta"), mcParticle.pt(), deltaeta); if (mcParticle.pdgCode() < 0) { // e+ diff --git a/ALICE3/TableProducer/alice3DqTableMaker.cxx b/ALICE3/TableProducer/alice3DqTableMaker.cxx index e77c149aa36..041fc71ebfe 100644 --- a/ALICE3/TableProducer/alice3DqTableMaker.cxx +++ b/ALICE3/TableProducer/alice3DqTableMaker.cxx @@ -28,7 +28,9 @@ #include "ALICE3/DataModel/collisionAlice3.h" #include "ALICE3/DataModel/tracksAlice3.h" #include "Common/CCDB/EventSelectionParams.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/TrackSelectionTables.h" #include @@ -63,8 +65,8 @@ using MyBarrelTracks = soa::Join; -using MyEvents = soa::Join; -using MyEventsMC = aod::McCollisions; +using MyEvents = soa::Join; +using MyEventsMC = soa::Join; constexpr static uint32_t GkEventFillMap = VarManager::ObjTypes::Collision; constexpr static uint32_t GkEventMcFillMap = VarManager::ObjTypes::CollisionMC; @@ -84,6 +86,7 @@ struct Alice3DqTableMaker { Produces trackMC; Produces event; + Produces eventExtended; Produces eventVtxCov; Produces eventMClabels; @@ -140,8 +143,9 @@ struct Alice3DqTableMaker { { bool isProcessSkimmingEnabled = context.mOptions.get("processSkimming"); - if (!isProcessSkimmingEnabled) + if (!isProcessSkimmingEnabled) { LOG(fatal) << "No process function was enabled ALICE 3 TableMaker"; + } VarManager::SetDefaultVarNames(); // Important that this is called before defineCuts() !!! @@ -309,7 +313,7 @@ struct Alice3DqTableMaker { fStatsList->Add(histEvents); // Track statistics: one bin for each track selection and 5 bins for V0 tags (gamma, K0s, Lambda, anti-Lambda, Omega) - TH1I* histTracks = new TH1I("TrackStats", "Track statistics", fTrackCuts.size() + 5.0, -0.5, fTrackCuts.size() - 0.5 + 5.0); + TH1I* histTracks = new TH1I("TrackStats", "Track statistics", static_cast(fTrackCuts.size() + 5.0), -0.5, fTrackCuts.size() - 0.5 + 5.0); ibX = 1; for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, ibX++) { histTracks->GetXaxis()->SetBinLabel(ibX, (*cut)->GetName()); @@ -345,7 +349,8 @@ struct Alice3DqTableMaker { fHistMan->FillHistClass("Event_MCTruth", dqefficiency_helpers::varValues()); eventMC(mcCollision.generatorsID(), mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), - mcCollision.t(), mcCollision.weight(), mcCollision.impactParameter()); // TODO: Determine and fill multiplicity values + mcCollision.t(), mcCollision.weight(), mcCollision.impactParameter(), + mcCollision.multMC(), mcCollision.multMC25(), mcCollision.multMC125(), mcCollision.multMC09()); } } @@ -443,11 +448,15 @@ struct Alice3DqTableMaker { (dynamic_cast(fStatsList->At(0)))->Fill(3.0, static_cast(o2::aod::evsel::kNsel)); // Fill historams after event cuts - fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); + fHistMan->FillHistClass("Event_AfterCuts", dqefficiency_helpers::varValues()); event(collision.posX(), collision.posY(), collision.posZ(), collision.numContrib(), collision.collisionTime(), collision.collisionTimeRes(), collision.multDensity()); + eventExtended(collision.multNTracksPV(), collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf(), + collision.multNTracksGlobal(), collision.multNGlobalTracksPV(), + collision.centRun2V0M()); + eventVtxCov(collision.covXX(), collision.covXY(), collision.covXZ(), collision.covYY(), collision.covYZ(), collision.covZZ(), collision.chi2()); eventMClabels(collision.mcCollisionId(), collision.mcMask()); @@ -617,8 +626,9 @@ struct Alice3DqTableMaker { skimCollisions(collisions); - if (fCollIndexMap.empty()) + if (fCollIndexMap.empty()) { return; + } skimMCParticles(mcParticles, mcCollisions); diff --git a/ALICE3/TableProducer/alice3MulticharmFinder.cxx b/ALICE3/TableProducer/alice3MulticharmFinder.cxx index 545951013e3..b3efa1fe9b8 100644 --- a/ALICE3/TableProducer/alice3MulticharmFinder.cxx +++ b/ALICE3/TableProducer/alice3MulticharmFinder.cxx @@ -101,54 +101,103 @@ struct Alice3MulticharmFinder { Configurable doDCAplots{"doDCAplots", true, "do daughter prong DCA plots for D mesons"}; Configurable mcSameMotherCheck{"mcSameMotherCheck", true, "check if tracks come from the same MC mother"}; - Configurable posMinDCAxy{"posMinDCAxy", 0.005, "min dcaxy for positive"}; - Configurable negMinDCAxy{"negMinDCAxy", 0.005, "min dcaxy for negative"}; - Configurable bachMinDCAxy{"bachMinDCAxy", 0.005, "min dcaxy for bachelor"}; - - Configurable laMinCosPA{"laMinCosPA", 0.998, "Minimum cos(PA)"}; - Configurable laMinDecayRadius{"laMinDecayRadius", 0.5, "Minimum R2D for la decay (cm)"}; - Configurable laMassWindow{"laMassWindow", 0.012, "Mass window around La peak (GeV/c^2)"}; - Configurable laMaxDauDCA{"laMaxDauDCA", 1, "DCA between Xi daughters (cm)"}; - - Configurable xiMinConstDCAxy{"xiMinConstDCAxy", 0.0005f, "[0] in |DCAxy| > [0]+[1]/pT"}; - Configurable xiMinConstDCAz{"xiMinConstDCAz", 0.0005f, "[0] in |DCAxy| > [0]+[1]/pT"}; - Configurable xiMinPtDepDCAxy{"xiMinPtDepDCAxy", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; - Configurable xiMinPtDepDCAz{"xiMinPtDepDCAz", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; - Configurable xiMinDecayRadius{"xiMinDecayRadius", 0.5, "Minimum R2D for XiC decay (cm)"}; - Configurable xiMassWindow{"xiMassWindow", 0.005, "Mass window around Xi peak (GeV/c^2)"}; - Configurable xiMaxDauDCA{"xiMaxDauDCA", 1, "DCA between Xi daughters (cm)"}; - Configurable xiMaxNormalizedDecayLength{"xiMaxNormalizedDecayLength", 5, "Max cascade nomralized decay length (ctau/)"}; - Configurable xiMinCosPA{"xiMinCosPA", 0.980000019, "Minimum cos(PA)"}; - - Configurable picMinConstDCAxy{"picMinConstDCAxy", 0.0005f, "[0] in |DCAxy| > [0]+[1]/pT"}; - Configurable picMinConstDCAz{"picMinConstDCAz", 0.0005f, "[0] in |DCAxy| > [0]+[1]/pT"}; - Configurable picMinPtDepDCAxy{"picMinPtDepDCAxy", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; - Configurable picMinPtDepDCAz{"picMinPtDepDCAz", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; - Configurable picMinPt{"picMinPt", 0.15, "Minimum pT for XiC pions"}; - - Configurable xicMaxDauDCA{"xicMaxDauDCA", 0.005f, "DCA between XiC daughters (cm)"}; - Configurable xicMaxDCAxy{"xicMaxDCAxy", 0.0005f, "maxDCA"}; - Configurable xicMaxDCAz{"xicMaxDCAz", 0.0005f, "maxDCA"}; - Configurable xicMinDecayRadius{"xicMinDecayRadius", -1, "Minimum R2D for XiC decay (cm)"}; - Configurable xicMinDecayDistanceFromPV{"xicMinDecayDistanceFromPV", -1, "Minimum distance for XiC decay from PV (cm)"}; - Configurable xicMinProperLength{"xicMinProperLength", 0.002, "Minimum proper length for XiC decay (cm)"}; - Configurable xicMaxProperLength{"xicMaxProperLength", 0.1, "Minimum proper length for XiC decay (cm)"}; - Configurable xicMassWindow{"xicMassWindow", 0.012, "Mass window around XiC peak (GeV/c^2)"}; - - Configurable piccMinConstDCAxy{"piccMinConstDCAxy", 0.0005f, "[0] in |DCAxy| > [0]+[1]/pT"}; - Configurable piccMinConstDCAz{"piccMinConstDCAz", 0.0005f, "[0] in |DCAxy| > [0]+[1]/pT"}; - Configurable piccMinPtDepDCAxy{"piccMinPtDepDCAxy", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; - Configurable piccMinPtDepDCAz{"piccMinPtDepDCAz", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; - Configurable piccMinPt{"piccMinPt", 0.3, "Minimum pT for XiCC pions"}; - - Configurable xiccMaxDauDCA{"xiccMaxDauDCA", 0.005f, "DCA between XiCC daughters (cm)"}; - Configurable xiccMaxDCAxy{"xiccMaxDCAxy", 0.005f, "maxDCA"}; - Configurable xiccMaxDCAz{"xiccMaxDCAz", 0.005f, "maxDCA"}; - Configurable xiccMaxEta{"xiccMaxEta", 1.5, "Max eta"}; - Configurable xiccMinDecayRadius{"xiccMinDecayRadius", -1, "Minimum R2D for XiCC decay (cm)"}; - Configurable xiccMinProperLength{"xiccMinProperLength", -1, "Minimum proper length for XiCC decay (cm)"}; - Configurable xiccMaxProperLength{"xiccMaxProperLength", 999, "Minimum proper length for XiCC decay (cm)"}; - Configurable xiccMassWindow{"xiccMassWindow", 0.25, "Mass window around XiCC peak (GeV/c). Make sure that bkg region is included in this window"}; + struct : ConfigurableGroup { + std::string prefix = "selVals"; + Configurable posMinDCAxy{"posMinDCAxy", 0.005, "min dcaxy for positive"}; + Configurable negMinDCAxy{"negMinDCAxy", 0.005, "min dcaxy for negative"}; + Configurable bachMinDCAxy{"bachMinDCAxy", 0.005, "min dcaxy for bachelor"}; + + Configurable laMinCosPA{"laMinCosPA", 0.998, "Minimum cos(PA)"}; + Configurable laMinDecayRadius{"laMinDecayRadius", 0.5, "Minimum R2D for la decay (cm)"}; + Configurable laMassWindow{"laMassWindow", 0.012, "Mass window around La peak (GeV/c^2)"}; + Configurable laMaxDauDCA{"laMaxDauDCA", 1, "DCA between Xi daughters (cm)"}; + + Configurable xiMinConstDCAxy{"xiMinConstDCAxy", 0.0005f, "[0] in |DCAxy| > [0]+[1]/pT"}; + Configurable xiMinConstDCAz{"xiMinConstDCAz", 0.0005f, "[0] in |DCAxy| > [0]+[1]/pT"}; + Configurable xiMinPtDepDCAxy{"xiMinPtDepDCAxy", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; + Configurable xiMinPtDepDCAz{"xiMinPtDepDCAz", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; + Configurable xiMinDecayRadius{"xiMinDecayRadius", 0.5, "Minimum R2D for XiC decay (cm)"}; + Configurable xiMassWindow{"xiMassWindow", 0.005, "Mass window around Xi peak (GeV/c^2)"}; + Configurable xiMaxDauDCA{"xiMaxDauDCA", 1, "DCA between Xi daughters (cm)"}; + Configurable xiMaxNormalizedDecayLength{"xiMaxNormalizedDecayLength", 5, "Max cascade nomralized decay length (ctau/)"}; + Configurable xiMinCosPA{"xiMinCosPA", 0.980000019, "Minimum cos(PA)"}; + + Configurable picMinConstDCAxy{"picMinConstDCAxy", 0.0005f, "[0] in |DCAxy| > [0]+[1]/pT"}; + Configurable picMinConstDCAz{"picMinConstDCAz", 0.0005f, "[0] in |DCAxy| > [0]+[1]/pT"}; + Configurable picMinPtDepDCAxy{"picMinPtDepDCAxy", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; + Configurable picMinPtDepDCAz{"picMinPtDepDCAz", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; + Configurable picMinPt{"picMinPt", 0.15, "Minimum pT for XiC pions"}; + + Configurable xicMaxDauDCA{"xicMaxDauDCA", 0.005f, "DCA between XiC daughters (cm)"}; + Configurable xicMinDCAxy{"xicMinDCAxy", 0.0005f, "Minimum DCA"}; + Configurable xicMinDCAz{"xicMinDCAz", 0.0005f, "Minimum DCA"}; + Configurable xicMinDecayRadius{"xicMinDecayRadius", -1, "Minimum R2D for XiC decay (cm)"}; + Configurable xicMinDecayDistanceFromPV{"xicMinDecayDistanceFromPV", -1, "Minimum distance for XiC decay from PV (cm)"}; + Configurable xicMinProperLength{"xicMinProperLength", 0.002, "Minimum proper length for XiC decay (cm)"}; + Configurable xicMaxProperLength{"xicMaxProperLength", 0.1, "Minimum proper length for XiC decay (cm)"}; + Configurable xicMassWindow{"xicMassWindow", 0.012, "Mass window around XiC peak (GeV/c^2)"}; + + Configurable piccMinConstDCAxy{"piccMinConstDCAxy", 0.0005f, "[0] in |DCAxy| > [0]+[1]/pT"}; + Configurable piccMinConstDCAz{"piccMinConstDCAz", 0.0005f, "[0] in |DCAxy| > [0]+[1]/pT"}; + Configurable piccMinPtDepDCAxy{"piccMinPtDepDCAxy", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; + Configurable piccMinPtDepDCAz{"piccMinPtDepDCAz", 0.0, "[1] in |DCAxy| > [0]+[1]/pT"}; + Configurable piccMinPt{"piccMinPt", 0.3, "Minimum pT for XiCC pions"}; + + Configurable xiccMaxDauDCA{"xiccMaxDauDCA", 0.005f, "DCA between XiCC daughters (cm)"}; + Configurable xiccMaxDCAxy{"xiccMaxDCAxy", 0.005f, "maxDCA"}; + Configurable xiccMaxDCAz{"xiccMaxDCAz", 0.005f, "maxDCA"}; + Configurable xiccMaxEta{"xiccMaxEta", 1.5, "Max eta"}; + Configurable xiccMinDecayRadius{"xiccMinDecayRadius", -1, "Minimum R2D for XiCC decay (cm)"}; + Configurable xiccMinProperLength{"xiccMinProperLength", -1, "Minimum proper length for XiCC decay (cm)"}; + Configurable xiccMaxProperLength{"xiccMaxProperLength", 999, "Minimum proper length for XiCC decay (cm)"}; + Configurable xiccMassWindow{"xiccMassWindow", 0.25, "Mass window around XiCC peak (GeV/c). Make sure that bkg region is included in this window"}; + } selVals; + + struct : ConfigurableGroup { + std::string prefix = "selFlags"; + Configurable applyPosMinDCAxy{"applyPosMinDCAxy", false, "Apply min dcaxy for positive"}; + Configurable applyNegMinDCAxy{"applyNegMinDCAxy", false, "Apply min dcaxy for negative"}; + Configurable applyBachMinDCAxy{"applyBachMinDCAxy", false, "Apply min dcaxy for bachelor"}; + + Configurable applyLaMinCosPA{"applyLaMinCosPA", false, "Apply Minimum cos(PA)"}; + Configurable applyLaMinDecayRadius{"applyLaMinDecayRadius", false, "Apply Minimum R2D for la decay (cm)"}; + Configurable applyLaMassWindow{"applyLaMassWindow", true, "Apply Mass window around La peak (GeV/c^2)"}; + Configurable applyLaMaxDauDCA{"applyLaMaxDauDCA", false, "Apply DCA between Xi daughters (cm)"}; + + Configurable applyXiMinDCAxy{"applyXiMinDCAxy", true, "Apply [0] in |DCAxy| > [0]+[1]/pT"}; + Configurable applyXiMinDCAz{"applyXiMinDCAz", true, "Apply [0] in |DCAxy| > [0]+[1]/pT"}; + Configurable applyXiMinDecayRadius{"applyXiMinDecayRadius", true, "Apply Minimum R2D for XiC decay (cm)"}; + Configurable applyXiMassWindow{"applyXiMassWindow", true, "Apply Mass window around Xi peak (GeV/c^2)"}; + Configurable applyXiMaxDauDCA{"applyXiMaxDauDCA", false, "Apply DCA between Xi daughters (cm)"}; + Configurable applyXiMaxNormalizedDecayLength{"applyXiMaxNormalizedDecayLength", true, "Apply Max cascade nomralized decay length (ctau/)"}; + Configurable applyXiMinCosPA{"applyXiMinCosPA", false, "Apply Minimum cos(PA)"}; + + Configurable applyPicMinDCAxy{"applyPicMinDCAxy", true, "Apply [0] in |DCAxy| > [0]+[1]/pT"}; + Configurable applyPicMinDCAz{"applyPicMinDCAz", true, "Apply [0] in |DCAxy| > [0]+[1]/pT"}; + Configurable applyPicMinPt{"applyPicMinPt", true, "Apply Minimum pT for XiC pions"}; + + Configurable applyXicMaxDauDCA{"applyXicMaxDauDCA", true, "Apply DCA between XiC daughters (cm)"}; + Configurable applyXicMinDCAxy{"applyXicMinDCAxy", true, "Apply Minimum DCA"}; + Configurable applyXicMinDCAz{"applyXicMinDCAz", true, "Apply Minimum DCA"}; + Configurable applyXicMinDecayRadius{"applyXicMinDecayRadius", false, "Apply Minimum R2D for XiC decay (cm)"}; + Configurable applyXicMinDecayDistanceFromPV{"applyXicMinDecayDistanceFromPV", true, "Apply Minimum distance for XiC decay from PV (cm)"}; + Configurable applyXicMinProperLength{"applyXicMinProperLength", false, "Apply Minimum proper length for XiC decay (cm)"}; + Configurable applyXicMaxProperLength{"applyXicMaxProperLength", false, "Apply Minimum proper length for XiC decay (cm)"}; + Configurable applyXicMassWindow{"applyXicMassWindow", true, "Apply Mass window around XiC peak (GeV/c^2)"}; + + Configurable applyPiccMinDCAxy{"applyPiccMinDCAxy", true, "Apply [0] in |DCAxy| > [0]+[1]/pT"}; + Configurable applyPiccMinDCAz{"applyPiccMinDCAz", true, "Apply [0] in |DCAxy| > [0]+[1]/pT"}; + Configurable applyPiccMinPt{"applyPiccMinPt", true, "Apply Minimum pT for XiCC pions"}; + + Configurable applyXiccMaxDauDCA{"applyXiccMaxDauDCA", true, "Apply DCA between XiCC daughters (cm)"}; + Configurable applyXiccMaxDCAxy{"applyXiccMaxDCAxy", true, "Apply maxDCA"}; + Configurable applyXiccMaxDCAz{"applyXiccMaxDCAz", true, "Apply maxDCA"}; + Configurable applyXiccMaxEta{"applyXiccMaxEta", true, "Apply Max eta"}; + Configurable applyXiccMinDecayRadius{"applyXiccMinDecayRadius", false, "Apply Minimum R2D for XiCC decay (cm)"}; + Configurable applyXiccMinProperLength{"applyXiccMinProperLength", false, "Apply Minimum proper length for XiCC decay (cm)"}; + Configurable applyXiccMaxProperLength{"applyXiccMaxProperLength", false, "Apply Minimum proper length for XiCC decay (cm)"}; + Configurable applyXiccMassWindow{"applyXiccMassWindow", true, "Apply Mass window around XiCC peak (GeV/c). Make sure that bkg region is included in this window"}; + } selFlags; ConfigurableAxis axisEta{"axisEta", {80, -4.0f, +4.0f}, "#eta"}; ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for QA histograms"}; @@ -190,11 +239,20 @@ struct Alice3MulticharmFinder { Partition trueXiC = aod::mcparticle::pdgCode == static_cast(o2::constants::physics::kXiCPlus); Partition trueXiCC = aod::mcparticle::pdgCode == static_cast(o2::constants::physics::kXiCCPlusPlus); + const float picMinConstDCAxy = selFlags.applyPicMinDCAxy ? selVals.picMinConstDCAxy : 0; + const float picMinPtDepDCAxy = selFlags.applyPicMinDCAxy ? selVals.picMinPtDepDCAxy : 0; + const float picMinConstDCAz = selFlags.applyPicMinDCAz ? selVals.picMinConstDCAz : 0; + const float picMinPtDepDCAz = selFlags.applyPicMinDCAz ? selVals.picMinPtDepDCAz : 0; + const float piccMinConstDCAxy = selFlags.applyPiccMinDCAxy ? selVals.piccMinConstDCAxy : 0; + const float piccMinPtDepDCAxy = selFlags.applyPiccMinDCAxy ? selVals.piccMinPtDepDCAxy : 0; + const float piccMinConstDCAz = selFlags.applyPiccMinDCAz ? selVals.piccMinConstDCAz : 0; + const float piccMinPtDepDCAz = selFlags.applyPiccMinDCAz ? selVals.piccMinPtDepDCAz : 0; + Partition picTracks = - ((aod::a3DecayMap::decayMap & TrackSelectionPic) == TrackSelectionPic) && aod::track::signed1Pt > 0.0f && 1.0f / nabs(aod::track::signed1Pt) > picMinPt&& nabs(aod::track::dcaXY) > picMinConstDCAxy + picMinPtDepDCAxy* nabs(aod::track::signed1Pt) && nabs(aod::track::dcaZ) > picMinConstDCAz + picMinPtDepDCAz* nabs(aod::track::signed1Pt); + ((aod::a3DecayMap::decayMap & TrackSelectionPic) == TrackSelectionPic) && aod::track::signed1Pt > 0.0f && nabs(aod::track::dcaXY) > picMinConstDCAxy + picMinPtDepDCAxy* nabs(aod::track::signed1Pt) && nabs(aod::track::dcaZ) > picMinConstDCAz + picMinPtDepDCAz* nabs(aod::track::signed1Pt); Partition piccTracks = - ((aod::a3DecayMap::decayMap & TrackSelectionPicc) == TrackSelectionPicc) && aod::track::signed1Pt > 0.0f && 1.0f / nabs(aod::track::signed1Pt) > piccMinPt&& nabs(aod::track::dcaXY) > piccMinConstDCAxy + piccMinPtDepDCAxy* nabs(aod::track::signed1Pt) && nabs(aod::track::dcaZ) > piccMinConstDCAz + piccMinPtDepDCAz* nabs(aod::track::signed1Pt); + ((aod::a3DecayMap::decayMap & TrackSelectionPicc) == TrackSelectionPicc) && aod::track::signed1Pt > 0.0f && nabs(aod::track::dcaXY) > piccMinConstDCAxy + piccMinPtDepDCAxy* nabs(aod::track::signed1Pt) && nabs(aod::track::dcaZ) > piccMinConstDCAz + piccMinPtDepDCAz* nabs(aod::track::signed1Pt); // Helper structs to pass candidate information struct { @@ -305,13 +363,13 @@ struct Alice3MulticharmFinder { // set relevant values thisXiccCandidate.dca = std::sqrt(fitter.getChi2AtPCACandidate()); - if (thisXiccCandidate.dca > xiccMaxDauDCA) { + if (selFlags.applyXiccMaxDauDCA && thisXiccCandidate.dca > selVals.xiccMaxDauDCA) { return false; } thisXiccCandidate.mass = RecoDecay::m(std::array{std::array{thisXiccCandidate.prong0mom[0], thisXiccCandidate.prong0mom[1], thisXiccCandidate.prong0mom[2]}, std::array{thisXiccCandidate.prong1mom[0], thisXiccCandidate.prong1mom[1], thisXiccCandidate.prong1mom[2]}}, std::array{mass0, mass1}); - if (std::fabs(thisXiccCandidate.mass - o2::constants::physics::MassXiCCPlusPlus) > xiccMassWindow) { + if (selFlags.applyXiccMassWindow && std::fabs(thisXiccCandidate.mass - o2::constants::physics::MassXiCCPlusPlus) > selVals.xiccMassWindow) { return false; } @@ -384,7 +442,7 @@ struct Alice3MulticharmFinder { // set relevant values thisXicCandidate.dca = std::sqrt(fitter3.getChi2AtPCACandidate()); - if (thisXicCandidate.dca > xicMaxDauDCA) { + if (selFlags.applyXicMaxDauDCA && thisXicCandidate.dca > selVals.xicMaxDauDCA) { return false; } thisXicCandidate.mass = RecoDecay::m(std::array{std::array{thisXicCandidate.prong0mom[0], thisXicCandidate.prong0mom[1], thisXicCandidate.prong0mom[2]}, std::array{thisXicCandidate.prong1mom[0], thisXicCandidate.prong1mom[1], thisXicCandidate.prong1mom[2]}, std::array{thisXicCandidate.prong2mom[0], thisXicCandidate.prong2mom[1], thisXicCandidate.prong2mom[2]}}, std::array{p0mass, p1mass, p2mass}); @@ -458,12 +516,13 @@ struct Alice3MulticharmFinder { fitter.setBz(cfgMagneticField); fitter.setMatCorrType(o2::base::Propagator::MatCorrType::USEMatCorrNONE); + // initialize O2 3-prong fitter (only once) fitter3.setPropagateToPCA(cfgFitter.propagateToPCA); fitter3.setMaxR(cfgFitter.maxR); fitter3.setMinParamChange(cfgFitter.minParamChange); fitter3.setMinRelChi2Change(cfgFitter.minRelChi2Change); fitter3.setMaxDZIni(cfgFitter.maxDZIni); - fitter3.setMaxDZIni(cfgFitter.maxDXYIni); + fitter3.setMaxDXYIni(cfgFitter.maxDXYIni); fitter3.setMaxChi2(cfgFitter.maxVtxChi2); fitter3.setUseAbsDCA(cfgFitter.useAbsDCA); fitter3.setWeightedFinalPCA(cfgFitter.useWeightedFinalPCA); @@ -621,7 +680,7 @@ struct Alice3MulticharmFinder { continue; } - if (pi1c.pt() < picMinPt) { + if (selFlags.applyPicMinPt && pi1c.pt() < selVals.picMinPt) { continue; } @@ -639,7 +698,7 @@ struct Alice3MulticharmFinder { continue; } - if (pi2c.pt() < picMinPt) { + if (selFlags.applyPicMinPt && pi2c.pt() < selVals.picMinPt) { continue; } @@ -654,7 +713,7 @@ struct Alice3MulticharmFinder { } hist("hDCAXiCDaughters")->Fill(thisXicCandidate.dca * ToMicrons); - if (std::fabs(thisXicCandidate.mass - o2::constants::physics::MassXiCPlus) > xicMassWindow) { + if (selFlags.applyXicMassWindow && std::fabs(thisXicCandidate.mass - o2::constants::physics::MassXiCPlus) > selVals.xicMassWindow) { continue; } @@ -665,7 +724,7 @@ struct Alice3MulticharmFinder { o2::track::TrackParCov xicTrack(thisXicCandidate.xyz, momentumC, thisXicCandidate.parentTrackCovMatrix, +1); float xicDecayRadius2D = std::hypot(thisXicCandidate.xyz[0], thisXicCandidate.xyz[1]); - if (xicDecayRadius2D < xicMinDecayRadius) { + if (selFlags.applyXicMinDecayRadius && xicDecayRadius2D < selVals.xicMinDecayRadius) { continue; } @@ -688,7 +747,11 @@ struct Alice3MulticharmFinder { xicdcaZ = dcaInfo.getZ(); } - if (std::fabs(xicdcaXY) < xicMaxDCAxy || std::fabs(xicdcaZ) < xicMaxDCAz) { + if (selFlags.applyXicMinDCAxy && std::fabs(xicdcaXY) < selVals.xicMinDCAxy) { + continue; + } + + if (selFlags.applyXicMinDCAz && std::fabs(xicdcaZ) < selVals.xicMinDCAz) { continue; } @@ -707,7 +770,7 @@ struct Alice3MulticharmFinder { continue; } - if (picc.pt() < piccMinPt) { + if (selFlags.applyPiccMinPt && picc.pt() < selVals.piccMinPt) { continue; } @@ -728,7 +791,7 @@ struct Alice3MulticharmFinder { o2::track::TrackParCov xiccTrack(thisXiccCandidate.xyz, momentumCC, thisXiccCandidate.parentTrackCovMatrix, +2); float xiccDecayRadius2D = std::hypot(thisXiccCandidate.xyz[0], thisXiccCandidate.xyz[1]); - if (xiccDecayRadius2D < xiccMinDecayRadius) { + if (selFlags.applyXiccMinDecayRadius && xiccDecayRadius2D < selVals.xiccMinDecayRadius) { continue; } @@ -738,8 +801,10 @@ struct Alice3MulticharmFinder { thisXicCandidate.xyz[1] - thisXiccCandidate.xyz[1], thisXicCandidate.xyz[2] - thisXiccCandidate.xyz[2]); float xicProperLength = decayLengthXiC * thisXicCandidate.mass / totalMomentumC; - - if (xicProperLength < xicMinProperLength || xicProperLength > xicMaxProperLength) { + if (selFlags.applyXicMinProperLength && xicProperLength < selVals.xicMinProperLength) { + continue; + } + if (selFlags.applyXicMaxProperLength && xicProperLength > selVals.xicMaxProperLength) { continue; } @@ -749,7 +814,7 @@ struct Alice3MulticharmFinder { thisXicCandidate.xyz[1] - collision.posY(), thisXicCandidate.xyz[2] - collision.posZ()); float xicDecayDistanceFromPV = xicDistanceFromPV * thisXicCandidate.mass / totalMomentumC; - if (xicDecayDistanceFromPV < xicMinDecayDistanceFromPV) { + if (selFlags.applyXicMinDecayDistanceFromPV && xicDecayDistanceFromPV < selVals.xicMinDecayDistanceFromPV) { continue; } @@ -760,7 +825,10 @@ struct Alice3MulticharmFinder { thisXiccCandidate.xyz[1] - collision.posY(), thisXiccCandidate.xyz[2] - collision.posZ()); float xiccProperLength = decayLengthXiCC * thisXiccCandidate.mass / totalMomentumCC; - if (xiccProperLength < xiccMinProperLength || xiccProperLength > xiccMaxProperLength) { + if (selFlags.applyXiccMinProperLength && xiccProperLength < selVals.xiccMinProperLength) { + continue; + } + if (selFlags.applyXiccMaxProperLength && xiccProperLength > selVals.xiccMaxProperLength) { continue; } @@ -778,14 +846,17 @@ struct Alice3MulticharmFinder { xiccdcaZ = dcaInfo.getZ(); } - if (std::fabs(xiccdcaXY) > xiccMaxDCAxy || std::fabs(xiccdcaZ) > xiccMaxDCAz) { + if (selFlags.applyXiccMaxDCAxy && std::fabs(xiccdcaXY) > selVals.xiccMaxDCAxy) { + continue; + } + if (selFlags.applyXiccMaxDCAz && std::fabs(xiccdcaZ) > selVals.xiccMaxDCAz) { continue; } hist("hMultiCharmBuilding")->Fill(7.0f); hist("hDCAxyXiCC")->Fill(xiccdcaXY * ToMicrons); hist("hDCAzXiCC")->Fill(xiccdcaZ * ToMicrons); - if (std::fabs(thisXiccCandidate.eta) > xiccMaxEta) { + if (selFlags.applyXiccMaxEta && std::fabs(thisXiccCandidate.eta) > selVals.xiccMaxEta) { continue; } @@ -866,7 +937,7 @@ struct Alice3MulticharmFinder { for (const auto& xiCand : cascades) { auto xi = xiCand.cascadeTrack_as(); - if (std::fabs(xiCand.mXi() - o2::constants::physics::MassXiMinus) > xiMassWindow) { + if (selFlags.applyXiMassWindow && std::fabs(xiCand.mXi() - o2::constants::physics::MassXiMinus) > selVals.xiMassWindow) { continue; } @@ -874,11 +945,15 @@ struct Alice3MulticharmFinder { continue; } - if (std::fabs(xi.dcaXY()) < xiMinConstDCAxy || std::fabs(xi.dcaZ()) < xiMinConstDCAz) { + if (selFlags.applyXiMinDCAxy && std::fabs(xi.dcaXY()) < selVals.xiMinConstDCAxy) { + continue; + } + + if (selFlags.applyXiMinDCAz && std::fabs(xi.dcaZ()) < selVals.xiMinConstDCAz) { continue; } - if (xiCand.cascRadius() < xiMinDecayRadius) { + if (selFlags.applyXiMinDecayRadius && xiCand.cascRadius() < selVals.xiMinDecayRadius) { continue; } @@ -910,55 +985,59 @@ struct Alice3MulticharmFinder { const float distanceFromPV = std::hypot(xiCand.x() - collision.posX(), xiCand.y() - collision.posY(), xiCand.z() - collision.posZ()); const float normalizedDecayLength = o2::constants::physics::MassXiMinus * distanceFromPV / (xiCand.p() * CtauXi); - if (std::abs(positive.dcaXY()) < posMinDCAxy) { + if (selFlags.applyPosMinDCAxy && std::abs(positive.dcaXY()) < selVals.posMinDCAxy) { continue; } - if (std::abs(negative.dcaXY()) < negMinDCAxy) { + if (selFlags.applyNegMinDCAxy && std::abs(negative.dcaXY()) < selVals.negMinDCAxy) { continue; } - if (std::abs(bachelor.dcaXY()) < bachMinDCAxy) { + if (selFlags.applyBachMinDCAxy && std::abs(bachelor.dcaXY()) < selVals.bachMinDCAxy) { continue; } - if (xiCand.dcaV0daughters() > laMaxDauDCA) { + if (selFlags.applyLaMaxDauDCA && xiCand.dcaV0daughters() > selVals.laMaxDauDCA) { continue; } - if (xiCand.v0radius() < laMinDecayRadius) { + if (selFlags.applyLaMinDecayRadius && xiCand.v0radius() < selVals.laMinDecayRadius) { continue; } - if (xiCand.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < laMinCosPA) { + if (selFlags.applyLaMinCosPA && xiCand.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < selVals.laMinCosPA) { continue; } - if (std::abs(xiCand.mLambda() - o2::constants::physics::MassLambda0) > laMassWindow) { + if (selFlags.applyLaMassWindow && std::abs(xiCand.mLambda() - o2::constants::physics::MassLambda0) > selVals.laMassWindow) { continue; } - if (xiCand.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < xiMinCosPA) { - continue; // FIXME: Probably not ok + if (selFlags.applyXiMinCosPA && xiCand.casccosPA(collision.posX(), collision.posY(), collision.posZ()) < selVals.xiMinCosPA) { + continue; + } + + if (selFlags.applyXiMaxDauDCA && xiCand.dcacascdaughters() > selVals.xiMaxDauDCA) { + continue; } - if (xiCand.dcacascdaughters() > xiMaxDauDCA) { + if (selFlags.applyXiMaxNormalizedDecayLength && normalizedDecayLength > selVals.xiMaxNormalizedDecayLength) { continue; } - if (normalizedDecayLength > xiMaxNormalizedDecayLength) { + if (selFlags.applyXiMassWindow && std::fabs(xiCand.mXi() - o2::constants::physics::MassXiMinus) > selVals.xiMassWindow) { continue; } - if (std::fabs(xiCand.mXi() - o2::constants::physics::MassXiMinus) > xiMassWindow) { + if (selFlags.applyXiMinDCAxy && std::fabs(xiCand.dcaXYCascToPV()) < selVals.xiMinConstDCAxy) { continue; } - if (std::fabs(xiCand.dcaXYCascToPV()) < xiMinConstDCAxy || std::fabs(xiCand.dcaZCascToPV()) < xiMinConstDCAz) { + if (selFlags.applyXiMinDCAz && std::fabs(xiCand.dcaZCascToPV()) < selVals.xiMinConstDCAz) { continue; } - if (xiCand.cascradius() < xiMinDecayRadius) { + if (selFlags.applyXiMinDecayRadius && xiCand.cascradius() < selVals.xiMinDecayRadius) { continue; } diff --git a/ALICE3/TableProducer/alice3Multiplicity.cxx b/ALICE3/TableProducer/alice3Multiplicity.cxx index baa2fed178c..bf614e500ad 100644 --- a/ALICE3/TableProducer/alice3Multiplicity.cxx +++ b/ALICE3/TableProducer/alice3Multiplicity.cxx @@ -31,8 +31,6 @@ #include #include -#include - #include #include diff --git a/ALICE3/TableProducer/alice3TrackingTranslator.cxx b/ALICE3/TableProducer/alice3TrackingTranslator.cxx index ccdcbcf2ac0..983092eb228 100644 --- a/ALICE3/TableProducer/alice3TrackingTranslator.cxx +++ b/ALICE3/TableProducer/alice3TrackingTranslator.cxx @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -46,7 +45,6 @@ #include #include -#include #include #include #include @@ -54,6 +52,7 @@ #include #include #include +#include #include TString inputPath; @@ -65,8 +64,6 @@ namespace using Key = std::array; // barcode (vp, vs, particle, gen, sub) Key keyOf(std::uint32_t vp, std::uint32_t vs, std::uint32_t pa, std::uint32_t ge, std::uint32_t sp) { return Key{vp, vs, pa, ge, sp}; } -// struct ParticleTruthInfo { int pdg; float px, py, pz, m; }; -// struct Seg { double px, py, pz, p; }; } // namespace struct Alice3TrackingTranslator { @@ -101,10 +98,6 @@ struct Alice3TrackingTranslator { { // Initialization if needed LOG(info) << "Alice3TrackingTranslator init called"; - - histos.add("hPx", "Px distribution;Px [GeV/c];Entries", kTH1F, {{100, -5.0, 5.0}}); - histos.add("hPy", "Py distribution;Py [GeV/c];Entries", kTH1F, {{100, -5.0, 5.0}}); - histos.add("hPz", "Pz distribution;Pz [GeV/c];Entries", kTH1F, {{100, -5.0, 5.0}}); } #define SETADDRESS(branchname, branchvar) \ @@ -113,7 +106,7 @@ struct Alice3TrackingTranslator { } struct FileStruct { - FileStruct(std::string filename, std::string treename) : mFile(filename.c_str(), "READ") + FileStruct(const std::string& filename, const std::string& treename) : mFile(filename.c_str(), "READ") { if (mFile.IsZombie()) { LOG(fatal) << "Could not open file '" << filename << "'"; @@ -137,7 +130,7 @@ struct Alice3TrackingTranslator { }; struct ParticleStruct : public FileStruct { - ParticleStruct(std::string filename, std::string treename) : FileStruct(filename, treename) + ParticleStruct(const std::string& filename, const std::string& treename) : FileStruct(std::move(filename), std::move(treename)) { // mTree->Print(); SETADDRESS("particle_type", m_particle_type); @@ -180,7 +173,7 @@ struct Alice3TrackingTranslator { }; struct VertexStruct : public FileStruct { - VertexStruct(std::string filename, std::string treename) : FileStruct(filename, treename) + VertexStruct(const std::string& filename, const std::string& treename) : FileStruct(filename, treename) { SETADDRESS("vx", m_x); SETADDRESS("vy", m_y); @@ -214,7 +207,7 @@ struct Alice3TrackingTranslator { }; struct TrackStruct : public FileStruct { - TrackStruct(std::string filename, std::string treename) : FileStruct(filename, treename) + TrackStruct(const std::string& filename, const std::string& treename) : FileStruct(std::move(filename), std::move(treename)) { mTree->Print(); // Set branch addresses for ACTS track parameters @@ -225,30 +218,47 @@ struct Alice3TrackingTranslator { SETADDRESS("nHoles", m_nHoles); SETADDRESS("chi2Sum", m_chi2Sum); SETADDRESS("NDF", m_NDF); - SETADDRESS("eLOC0_fit", m_eLOC0_fit); - SETADDRESS("eLOC1_fit", m_eLOC1_fit); - SETADDRESS("ePHI_fit", m_ePHI_fit); - SETADDRESS("eTHETA_fit", m_eTHETA_fit); - SETADDRESS("eQOP_fit", m_eQOP_fit); - SETADDRESS("eT_fit", m_eT_fit); SETADDRESS("nMajorityHits", m_nMajorityHits); SETADDRESS("t_charge", m_t_charge); SETADDRESS("t_vx", m_t_vx); SETADDRESS("t_vy", m_t_vy); SETADDRESS("t_vz", m_t_vz); - SETADDRESS("t_time", m_t_time); SETADDRESS("t_px", m_t_px); SETADDRESS("t_py", m_t_py); SETADDRESS("t_pz", m_t_pz); - SETADDRESS("t_theta", m_t_theta); - SETADDRESS("t_phi", m_t_phi); - SETADDRESS("t_pT", m_t_pT); - SETADDRESS("t_eta", m_t_eta); SETADDRESS("majorityParticleId_vertex_primary", m_majorityParticleId_vertex_primary); SETADDRESS("majorityParticleId_vertex_secondary", m_majorityParticleId_vertex_secondary); SETADDRESS("majorityParticleId_generation", m_majorityParticleId_generation); SETADDRESS("majorityParticleId_sub_particle", m_majorityParticleId_sub_particle); SETADDRESS("majorityParticleId_particle", m_majorityParticleId_particle); + SETADDRESS("eQOP_fit", m_eQOP_fit); + SETADDRESS("eX_fit", m_eX_fit); + SETADDRESS("eY_fit", m_eY_fit); + SETADDRESS("eZ_fit", m_eZ_fit); + SETADDRESS("ePX_fit", m_ePX_fit); + SETADDRESS("ePY_fit", m_ePY_fit); + SETADDRESS("ePZ_fit", m_ePZ_fit); + SETADDRESS("cov_eX_eX", m_cov_eX_eX); + // SETADDRESS("cov_eY_eY", m_cov_eY_eY); + SETADDRESS("cov_eZ_eZ", m_cov_eZ_eZ); + SETADDRESS("cov_ePX_ePX", m_cov_ePX_ePX); + SETADDRESS("cov_ePY_ePY", m_cov_ePY_ePY); + SETADDRESS("cov_ePZ_ePZ", m_cov_ePZ_ePZ); + SETADDRESS("cov_eX_ePX", m_cov_eX_ePX); + SETADDRESS("cov_eY_ePY", m_cov_eY_ePY); + SETADDRESS("cov_eZ_ePZ", m_cov_eZ_ePZ); + SETADDRESS("cov_eX_eY", m_cov_eX_eY); + SETADDRESS("cov_eX_eZ", m_cov_eX_eZ); + SETADDRESS("cov_eY_eZ", m_cov_eY_eZ); + SETADDRESS("cov_ePX_ePY", m_cov_ePX_ePY); + SETADDRESS("cov_ePX_ePZ", m_cov_ePX_ePZ); + SETADDRESS("cov_ePY_ePZ", m_cov_ePY_ePZ); + SETADDRESS("cov_eX_ePY", m_cov_eX_ePY); + SETADDRESS("cov_eX_ePZ", m_cov_eX_ePZ); + SETADDRESS("cov_eY_ePX", m_cov_eY_ePX); + SETADDRESS("cov_eY_ePZ", m_cov_eY_ePZ); + SETADDRESS("cov_eZ_ePX", m_cov_eZ_ePX); + SETADDRESS("cov_eZ_ePY", m_cov_eZ_ePY); } // Define track-related members here UInt_t* m_event_nr = nullptr; @@ -258,12 +268,37 @@ struct Alice3TrackingTranslator { std::vector* m_chi2Sum = nullptr; std::vector* m_NDF = nullptr; // Fitted track parameters - std::vector* m_eLOC0_fit = nullptr; // local position 0 (typically y in local frame) - std::vector* m_eLOC1_fit = nullptr; // local position 1 (typically z in local frame) - std::vector* m_ePHI_fit = nullptr; // azimuthal angle - std::vector* m_eTHETA_fit = nullptr; // polar angle - std::vector* m_eQOP_fit = nullptr; // q/m_p (charge over momentum) - std::vector* m_eT_fit = nullptr; // time + std::vector* m_eQOP_fit = nullptr; // q/m_p (charge over momentum) + + std::vector* m_eX_fit = nullptr; // global position x + std::vector* m_eY_fit = nullptr; // global position y + std::vector* m_eZ_fit = nullptr; // global position z + std::vector* m_ePX_fit = nullptr; // global momentum px + std::vector* m_ePY_fit = nullptr; // global momentum py + std::vector* m_ePZ_fit = nullptr; // global momentum pz + + // covariance matrices for fitted track parameters (if available) + std::vector* m_cov_eX_eX = nullptr; // covariance of global position x + // std::vector* m_cov_eY_eY = nullptr; // covariance of global position y + std::vector* m_cov_eZ_eZ = nullptr; // covariance of global position z + std::vector* m_cov_ePX_ePX = nullptr; // covariance of global momentum px + std::vector* m_cov_ePY_ePY = nullptr; // covariance of global momentum py + std::vector* m_cov_ePZ_ePZ = nullptr; // covariance of global momentum pz + std::vector* m_cov_eX_ePX = nullptr; // covariance between global position x and momentum px + std::vector* m_cov_eY_ePY = nullptr; // covariance between global position y and momentum py + std::vector* m_cov_eZ_ePZ = nullptr; // covariance between global position z and momentum pz + std::vector* m_cov_eX_eY = nullptr; // covariance between global position x and y + std::vector* m_cov_eX_eZ = nullptr; // covariance between global position x and z + std::vector* m_cov_eY_eZ = nullptr; // covariance between global position y and z + std::vector* m_cov_ePX_ePY = nullptr; // covariance between global momentum px and py + std::vector* m_cov_ePX_ePZ = nullptr; // covariance between global momentum px and pz + std::vector* m_cov_ePY_ePZ = nullptr; // covariance between global momentum py and pz + std::vector* m_cov_eX_ePY = nullptr; // covariance between global position x and momentum py + std::vector* m_cov_eX_ePZ = nullptr; // covariance between global position x and momentum pz + std::vector* m_cov_eY_ePX = nullptr; // covariance between global position y and momentum px + std::vector* m_cov_eY_ePZ = nullptr; // covariance between global position y and momentum pz + std::vector* m_cov_eZ_ePX = nullptr; // covariance between global position z and momentum px + std::vector* m_cov_eZ_ePY = nullptr; // covariance between global position z and momentum py // The majority truth particle info std::vector* m_nMajorityHits = nullptr; /// The number of hits from majority particle @@ -275,10 +310,6 @@ struct Alice3TrackingTranslator { std::vector* m_t_px = nullptr; /// Initial momenta m_px of majority particle std::vector* m_t_py = nullptr; /// Initial momenta m_py of majority particle std::vector* m_t_pz = nullptr; /// Initial momenta m_pz of majority particle - std::vector* m_t_theta = nullptr; /// Initial momenta theta of majority particle - std::vector* m_t_phi = nullptr; /// Initial momenta phi of majority particle - std::vector* m_t_pT = nullptr; /// Initial momenta pT of majority particle - std::vector* m_t_eta = nullptr; /// Initial momenta eta of majority particle std::vector* m_majorityParticleId_vertex_primary = nullptr; std::vector* m_majorityParticleId_vertex_secondary = nullptr; @@ -288,7 +319,7 @@ struct Alice3TrackingTranslator { }; struct HitsStruct : public FileStruct { - HitsStruct(std::string filename, std::string treename) : FileStruct(filename, treename) + HitsStruct(const std::string& filename, const std::string& treename) : FileStruct(std::move(filename), std::move(treename)) { mTree->Print(); SETADDRESS("barcode", barcode); @@ -353,33 +384,21 @@ struct Alice3TrackingTranslator { files[justFilename.Data()] = filename; } LOG(info) << "All files loaded successfully"; - // Now open the files to translate and read the trees - // ParticleStruct fileParticles(files["particles.root"], "particles"); - // LOG(info) << "Particles loaded successfully"; ParticleStruct fileParticlesSim(files["particles_simulation.root"], "particles"); LOG(info) << "Particles Sim loaded successfully"; - // std::string daughterFileName = addDaughterInfo ? "particles_decay.root" : "particles_simulation.root"; - // ParticleStruct fileDaughterParticles(files[daughterFileName], "particles"); - // LOG(info) << "Daughter particles loaded successfully from file " << daughterFileName; // FileStruct fileVertices(files["performance_vertexing.root"], "vertexing"); TrackStruct fileTracksummary(files["tracksummary_ambi-tracks-merged.root"], "tracksummary"); - // HitsStruct fileHits(files["hits.root"], "hits"); VertexStruct fileVertices(files["vertices_gen_and_geant.root"], "vertices"); LOG(info) << "Tracks loaded successfully"; const Long64_t kEvents = fileParticlesSim.getEntries(); - // int indexOfLastParticleAfterEvent = -1; for (Long64_t iEvent = 0; iEvent < kEvents; ++iEvent) { if (iEvent > 0 && maxCollisions.value > 0 && (iEvent % maxCollisions) == 0) { LOG(info) << "Stopping at event " << iEvent << "/" << kEvents; break; } - // fileParticles.setEventEntry(iEvent); fileVertices.setEventEntry(iEvent); fileTracksummary.setEventEntry(iEvent); - // fileHits.setEventEntry(iEvent); - // if (addDaughterInfo) - // fileDaughterParticles.setEventEntry(iEvent); fileParticlesSim.setEventEntry(iEvent); LOG(info) << "Processing event " << iEvent << "/" << kEvents; @@ -398,10 +417,8 @@ struct Alice3TrackingTranslator { int collisionId = tableCollisions.lastIndex() + 1; // Convert tracks from ACTS to ALICE format - // const size_t nParticlesGen = fileParticles.m_vx->size(); const size_t nParticlesSim = fileParticlesSim.m_vx->size(); - // const size_t nDaughterParticles = fileDaughterParticles.m_vx->size(); - const size_t nTracks = fileTracksummary.m_eLOC0_fit->size(); + const size_t nTracks = fileTracksummary.m_ePX_fit->size(); std::vector idMCparticles; // local index k within this event -> global AO2D index @@ -468,7 +485,6 @@ struct Alice3TrackingTranslator { } } } - // int idPrimary = -1; for (size_t iPart = 0; iPart < nParticlesSim; ++iPart) { int globalIdx = firstIdxThisEvent + (int)iPart; int motherIdx = -1; @@ -494,20 +510,7 @@ struct Alice3TrackingTranslator { collisionY = fileVertices.m_y->at(iPart); collisionZ = fileVertices.m_z->at(iPart); flags |= o2::aod::mcparticle::enums::PhysicalPrimary; - // idPrimary += 1; } - // if(motherIdx==-1 && std::abs(fileParticlesSim.m_particle_type->at(iPart)) == 211) { - std::cout << "Adding MC particle " << iPart << ", with globalIdx " << globalIdx << ", with motherIdx " << motherIdx << ", firstDaughter " << firstDaughter << ", secondDaughter " << secondDaughter << ", pdg " << fileParticlesSim.m_particle_type->at(iPart) << std::endl; - // std::cout << "PV: " << fileVertices.m_x->at(iPart) << ", " << fileVertices.m_y->at(iPart) << ", " << fileVertices.m_z->at(iPart) << std::endl; - // std::cout << "Daughter info: "; - // if(firstDaughter != -1){ - // std::cout << "firstDaughter pdg " << fileParticlesSim.m_particle_type->at(firstDaughter) << " "; - // } - // if(secondDaughter != -1){ - // std::cout << "secondDaughter pdg " << fileParticlesSim.m_particle_type->at(secondDaughter) << " "; - // } - // std::cout << std::endl; - // } GlobalIdxToPDGCode[globalIdx] = fileParticlesSim.m_particle_type->at(iPart); GlobalToLocalIdx[globalIdx] = iPart; addMCParticle(tableMcCollisions.lastIndex(), fileParticlesSim, iPart, flags, motherIdx, firstDaughter, secondDaughter, fileParticlesSim.m_number_of_hits->at(iPart)); @@ -549,65 +552,30 @@ struct Alice3TrackingTranslator { if (iterator != barcodeToGlobalIdx.end()) { mcParticleIdx = iterator->second; } - std::cout << "Track " << iTrack << " is associated with MC particle index " << mcParticleIdx << std::endl; // Extract ACTS track parameters - float phi = fileTracksummary.m_ePHI_fit->at(iTrack); - float theta = fileTracksummary.m_eTHETA_fit->at(iTrack); float qOverP = fileTracksummary.m_eQOP_fit->at(iTrack); - float loc0 = fileTracksummary.m_eLOC0_fit->at(iTrack); - float loc1 = fileTracksummary.m_eLOC1_fit->at(iTrack); - float vx = loc0; - float vy = loc1; - float vz = 0.0f; - // auto iteratorVz = barcodeToVertexPosition.find(key); - // if (iteratorVz != barcodeToVertexPosition.end()){ - // vx = iteratorVz->second[0]; - // vy = iteratorVz->second[1]; - // vz = iteratorVz->second[2]; - // } + float x = fileTracksummary.m_eX_fit->at(iTrack); + float y = fileTracksummary.m_eY_fit->at(iTrack); + float z = fileTracksummary.m_eZ_fit->at(iTrack); + float px = fileTracksummary.m_ePX_fit->at(iTrack); + float py = fileTracksummary.m_ePY_fit->at(iTrack); + float pz = fileTracksummary.m_ePZ_fit->at(iTrack); + int localIdx = GlobalToLocalIdx[mcParticleIdx]; if (useTrueInfoForRecoTracks) { if (mcParticleIdx != -1) { - int localIdx = GlobalToLocalIdx[mcParticleIdx]; - float p = fileParticlesSim.m_p->at(localIdx); - // float m = fileParticlesSim.m_m->at(localIdx); - float pt = std::hypot(fileParticlesSim.m_px->at(localIdx), fileParticlesSim.m_py->at(localIdx)); - phi = std::acos(fileParticlesSim.m_px->at(localIdx) / pt); - theta = std::acos(fileParticlesSim.m_pz->at(localIdx) / p); - qOverP = (fileParticlesSim.m_q->at(localIdx) != 0) ? (fileParticlesSim.m_q->at(localIdx) / p) : 0.0f; - loc0 = fileParticlesSim.m_vx->at(localIdx); - loc1 = fileParticlesSim.m_vy->at(localIdx); + px = fileParticlesSim.m_px->at(localIdx); + py = fileParticlesSim.m_py->at(localIdx); + pz = fileParticlesSim.m_pz->at(localIdx); + x = fileParticlesSim.m_vx->at(localIdx); + y = fileParticlesSim.m_vy->at(localIdx); + z = fileParticlesSim.m_vz->at(localIdx); } } - - std::cout << "Track parameters: phi=" << phi << ", theta=" << theta << ", qOverP=" << qOverP << ", loc0=" << loc0 << ", loc1=" << loc1 << std::endl; - std::cout << "vx= " << vx << ", vy= " << vy << ", vz= " << vz << std::endl; // Convert to ALICE track parameters - // ALICE uses: alpha, x, y, z, snp, tgl, signed1Pt - float alpha = phi - M_PI / 2; // Track angle in global frame - float x = vx; // Local x position - float y = vy; // Local y position - float z = vz; // Will be set from DCA or collision vertex - - // Calculate snp (sin of track momentum azimuthal angle) - float snp = o2::constants::math::Almost1; // std::sin(phi);// - - // Calculate tgl (tangent of track momentum dip angle) - float tgl = 1.0f / std::tan(theta); - - // Calculate signed1Pt (charge/pt) - const float m_p = (qOverP != 0) ? std::abs(1.0f / qOverP) : 0.0f; - const float px = m_p * std::cos(phi) * std::sin(theta); - const float py = m_p * std::sin(phi) * std::sin(theta); - const float pz = m_p * std::cos(theta); - const float pt = m_p * std::sin(theta); int8_t charge = (qOverP > 0) ? 1 : -1; - const float signed1Pt = (pt != 0) ? charge / pt : 0.0f; - - if (charge > 0) { - histos.fill(HIST("hPx"), px); - histos.fill(HIST("hPy"), py); - histos.fill(HIST("hPz"), pz); + if (qOverP == 0) { + charge = 0; } // Track quality @@ -615,30 +583,34 @@ struct Alice3TrackingTranslator { uint32_t m_nMeasurements = fileTracksummary.m_nMeasurements->at(iTrack); uint32_t m_NDF = fileTracksummary.m_NDF->at(iTrack); - // Fill covariance matrices (simplified - should be extracted from ACTS if available) - float cYY = 0.1f; - float cZY = 0.0f; - float cZZ = 0.1f; - float cSnpY = 0.0f; - float cSnpZ = 0.0f; - float cSnpSnp = 0.001f; - float cTglY = 0.0f; - float cTglZ = 0.0f; - float cTglSnp = 0.0f; - float cTglTgl = 0.001f; - float c1PtY = 0.0f; - float c1PtZ = 0.0f; - float c1PtSnp = 0.0f; - float c1PtTgl = 0.0f; - float c1Pt21Pt2 = 0.001f * signed1Pt * signed1Pt; - - // Create TrackParCov object with dummy covariance matrix - std::array trackParams = {y, z, snp, tgl, signed1Pt}; - std::array trackCov = {cYY, cZY, cZZ, cSnpY, cSnpZ, cSnpSnp, - cTglY, cTglZ, cTglSnp, cTglTgl, - c1PtY, c1PtZ, c1PtSnp, c1PtTgl, c1Pt21Pt2}; - o2::track::TrackParCov trackParCov(x, alpha, trackParams, trackCov, charge); - std::cout << "TrackParCov created with parameters:" << std::endl; + // Fill covariance matrices + float cxx = fileTracksummary.m_cov_eX_eX->at(iTrack); + float cyy = cxx; // fileTracksummary.cov_eY_eY->at(iTrack); + float czz = fileTracksummary.m_cov_eZ_eZ->at(iTrack); + float cxy = fileTracksummary.m_cov_eX_eY->at(iTrack); + float cxz = fileTracksummary.m_cov_eX_eZ->at(iTrack); + float cyz = fileTracksummary.m_cov_eY_eZ->at(iTrack); + float cpxpx = fileTracksummary.m_cov_ePX_ePX->at(iTrack); + float cpypy = fileTracksummary.m_cov_ePY_ePY->at(iTrack); + float cpzpz = fileTracksummary.m_cov_ePZ_ePZ->at(iTrack); + float cpxpy = fileTracksummary.m_cov_ePX_ePY->at(iTrack); + float cpxpz = fileTracksummary.m_cov_ePX_ePZ->at(iTrack); + float cpypz = fileTracksummary.m_cov_ePY_ePZ->at(iTrack); + float cxpx = fileTracksummary.m_cov_eX_ePX->at(iTrack); + float cxpy = fileTracksummary.m_cov_eX_ePY->at(iTrack); + float cxpz = fileTracksummary.m_cov_eX_ePZ->at(iTrack); + float cypx = fileTracksummary.m_cov_eY_ePX->at(iTrack); + float cypy = fileTracksummary.m_cov_eY_ePY->at(iTrack); + float cypz = fileTracksummary.m_cov_eY_ePZ->at(iTrack); + float czpx = fileTracksummary.m_cov_eZ_ePX->at(iTrack); + float czpy = fileTracksummary.m_cov_eZ_ePY->at(iTrack); + float czpz = fileTracksummary.m_cov_eZ_ePZ->at(iTrack); + // Create TrackParCov object with covariance matrix + std::array position = {x, y, z}; + std::array momentum = {px, py, pz}; + std::array trackCov = {cxx, cxy, cyy, cxz, cyz, czz, cxpx, cypx, czpx, cpxpx, cxpy, cypy, czpy, cpxpy, cpypy, cxpz, cypz, czpz, cpxpz, cpypz, cpzpz}; + o2::track::TrackParCov trackParCov(position, momentum, trackCov, charge); + // Fill StoredTracks table (basic track parameters) tableStoredTracks(collisionId, // collisionId o2::aod::track::TrackTypeEnum::Track, // trackType @@ -649,13 +621,11 @@ struct Alice3TrackingTranslator { trackParCov.getSnp(), // snp trackParCov.getTgl(), // tgl trackParCov.getQ2Pt()); // signed1Pt - std::cout << "Filling StoredTracks table" << std::endl; // Fill TracksExtension table tableTracksExtension(trackParCov.getPt(), trackParCov.getP(), trackParCov.getEta(), trackParCov.getPhi()); - std::cout << "Filling TracksExtension table" << std::endl; tableStoredTracksCov(std::sqrt(trackParCov.getSigmaY2()), // SigmaY std::sqrt(trackParCov.getSigmaZ2()), // SigmaZ std::sqrt(trackParCov.getSigmaSnp2()), // SigmaSnp @@ -671,7 +641,6 @@ struct Alice3TrackingTranslator { 0, // Rho1PtZ 0, // Rho1PtSnp 0); // Rho1PtTgl - std::cout << "Filling StoredTracksCov table" << std::endl; // covariance matrix at collision vertex tableTracksCovExtension(trackParCov.getSigmaY2(), // sigmaY2 trackParCov.getSigmaZY(), // sigmaZY @@ -688,31 +657,25 @@ struct Alice3TrackingTranslator { trackParCov.getSigma1PtSnp(), // sigma1PtSnp trackParCov.getSigma1PtTgl(), // sigma1PtTgl trackParCov.getSigma1Pt2()); // sigma1Pt - std::cout << "Filling TracksCovExtension table" << std::endl; // Fill MC label tableMcTrackLabels(mcParticleIdx, // McParticleId 0); // mcMask - std::cout << "Filling McTrackLabels table" << std::endl; - // Fill DCA info (simplified - should be calculated properly) - tableTracksDCA(0.0f, // dcaXY - 0.0f); // dcaZ - std::cout << "Filling TracksDCA table" << std::endl; + // Fill DCA info TODO: should be calculated properly + tableTracksDCA(0.0f, // dcaXY + 0.0f); // dcaZ tableTracksDCACov(0.0f, // sigmaDcaXY2 0.0f); // sigmaDcaZ2 - std::cout << "Filling TracksDCACov table" << std::endl; // Fill ALICE3 specific tables tableTracksAlice3(true); // isReconstructed - std::cout << GlobalIdxToPDGCode[mcParticleIdx] << std::endl; if (mcParticleIdx > 0) tableTracksAlice3Pdg(GlobalIdxToPDGCode[mcParticleIdx]); // PdgCode to the linked MC truth particle else tableTracksAlice3Pdg(0); // No linked MC truth particle - std::cout << "Filling TracksAlice3 and TracksAlice3Pdg tables" << std::endl; + tableTracksExtraA3(m_nMeasurements, // nSiliconHits (using m_nMeasurements as proxy) 0, // nTPCHits 0, // trackType false); // isPVContributor - std::cout << "Filling TracksExtraA3 table" << std::endl; // Fill extra track info tableStoredTracksExtra(0.f, // TPCInnerParam static_cast(0), // Flags @@ -735,16 +698,14 @@ struct Alice3TrackingTranslator { 0.f, // TrackPhiEMCAL 0.f, // TrackTime 0.f); // TrackTimeRes - std::cout << "Filling StoredTracksExtra table" << std::endl; // Fill track selection - tableTrackSelection(false, // IsGlobalTrackSDD, - false, // TrackCutFlag, - false, // TrackCutFlagFb1, - false, // TrackCutFlagFb2, - false, // TrackCutFlagFb3, - false, // TrackCutFlagFb4, - false); // TrackCutFlagFb5, - std::cout << "Filling TrackSelection table" << std::endl; + tableTrackSelection(false, // IsGlobalTrackSDD, + false, // TrackCutFlag, + false, // TrackCutFlagFb1, + false, // TrackCutFlagFb2, + false, // TrackCutFlagFb3, + false, // TrackCutFlagFb4, + false); // TrackCutFlagFb5, tableTrackSelectionExtension(false, // PassedTrackType, false, // PassedPtRange, false, // PassedEtaRange, @@ -762,177 +723,7 @@ struct Alice3TrackingTranslator { false, // PassedDCAz, false, // PassedITSHitsFB1, false); // PassedITSHitsFB2 - std::cout << "Filling TrackSelectionExtension table" << std::endl; } - - // for (size_t iTrack = 0; iTrack < nTracks; ++iTrack) { - // LOG(info) << "Processing track " << iTrack << "/" << nTracks << " (nParticlesSim=" << nParticlesSim << ") nParticlesGen=" << nParticlesGen; - // const size_t iParticle = iTrack; - - // if (iParticle == 0) { - // tableMcCollisions(0, // mccollision::BCId, - // 0, // mccollision::GeneratorsID, - // fileParticles.m_vx->at(iParticle), // mccollision::PosX, - // fileParticles.m_vy->at(iParticle), // mccollision::PosY, - // fileParticles.m_vz->at(iParticle), // mccollision::PosZ - // fileParticles.m_vt->at(iParticle), // mccollision::T - // 1.0f, // mccollision::Weight - // 0.0f, // mccollision::ImpactParameter, - // 0.f); // mccollision::EventPlaneAngle, - // } - // uint8_t flags = 0; - - // Key majorityVertexInfo = keyOf(fileTracksummary.m_majorityParticleId_vertex_primary->at(iTrack), fileTracksummary.m_majorityParticleId_vertex_secondary->at(iTrack), (*ouPa)[j][d], - // (*ouGe)[j][d], (*ouSp)[j][d]); - - // // ULong64_t idMCTrueParticle = fileTracksummary.m_majorityParticleId->at(iParticle); - // // int32_t mcParticleId = -1; - // // int pdgCode = -1; - - // // for (size_t iMC = 0; iMC < nParticlesGen; ++iMC) { - // // if (fileParticles.m_particleId->at(iMC) == idMCTrueParticle) { - // // if (count(idMCparticles.begin(), idMCparticles.end(), fileParticles.m_particleId->at(iMC)) > 0) { - // // continue; - // // } - // // idMCparticles.push_back(fileParticles.m_particleId->at(iMC)); - // // flags |= o2::aod::mcparticle::enums::PhysicalPrimary; - // // int nHits = 0; - // // for (size_t iPartSim = 0; iPartSim < nParticlesSim; ++iPartSim) { - // // if (fileParticlesSim.m_particleId->at(iPartSim) == fileParticles.m_particleId->at(iMC)) { - // // nHits = fileParticlesSim.m_number_of_hits->at(iPartSim); - // // break; - // // } - // // } - // // addMCParticle(tableMcCollisions.lastIndex(), fileParticles, iMC, flags, -1, -1, nHits); - // // mcParticleId = tableStoredMcParticles.lastIndex(); - // // pdgCode = fileParticles.m_particle_type->at(iMC); - // // break; - // // } - // // } - // // if (addDaughterInfo) { - // // for (size_t iMC = 0; iMC < nParticlesSim; ++iMC) { - // // if (fileDaughterParticles.m_particleId->at(iMC) == idMCTrueParticle) { - // // if (count(idMCparticles.begin(), idMCparticles.end(), fileDaughterParticles.m_particleId->at(iMC)) > 0) { - // // break; - // // } - - // // int nHits = 0; - // // for (size_t iPartSim = 0; iPartSim < nParticlesSim; ++iPartSim) { - // // if (fileParticlesSim.m_particleId->at(iPartSim) == fileDaughterParticles.m_particleId->at(iMC)) { - // // nHits = fileParticlesSim.m_number_of_hits->at(iPartSim); - // // break; - // // } - // // } - // // for (size_t iMother = 0; iMother < nParticlesGen; ++iMother) { - // // if (fileDaughterParticles.m_motherId->at(iMC) == fileParticles.m_particleId->at(iMother)) { - // // if (count(idMCparticles.begin(), idMCparticles.end(), fileParticles.m_particleId->at(iMother)) > 0) { - // // break; - // // } - // // idMCparticles.push_back(fileParticles.m_particleId->at(iMother)); - // // uint8_t flagsMother = o2::aod::mcparticle::enums::PhysicalPrimary; - // // addMCParticle(tableMcCollisions.lastIndex(), fileParticles, iMother, flagsMother, -1, tableStoredMcParticles.lastIndex() + 2, 0); - // // break; - // // } - // // } - // // int motherId = -1; - // // if (count(idMCparticles.begin(), idMCparticles.end(), fileDaughterParticles.m_motherId->at(iMC)) > 0) { - // // auto it = find(idMCparticles.begin(), idMCparticles.end(), fileDaughterParticles.m_motherId->at(iMC)); - // // motherId = it - idMCparticles.begin() + indexOfLastParticleAfterEvent + 1; - // // } - // // idMCparticles.push_back(fileDaughterParticles.m_particleId->at(iMC)); - // // addMCParticle(tableMcCollisions.lastIndex(), fileDaughterParticles, iMC, flags, motherId, -1, nHits); - // // mcParticleId = tableStoredMcParticles.lastIndex(); - // // pdgCode = fileDaughterParticles.m_particle_type->at(iMC); - // // break; - // // } - // // } - // // } - // - - // - - // - - // // Fill MC track labels - // // Get particle linkage from hits using the majority hit index - // // if (fileTracksummary.nMajorityHits && iTrack < fileTracksummary.nMajorityHits->size()) { - // // unsigned int hitIndex = fileTracksummary.nMajorityHits->at(iTrack); - // // if (fileHits.barcode && hitIndex < fileHits.barcode->size()) { - // // mcParticleId = static_cast(fileHits.barcode->at(hitIndex)); - // // LOG(debug) << "Track " << iTrack << " linked to MC particle " << mcParticleId - // // << " via hit index " << hitIndex; - // // } else { - // // LOG(warning) << "Hit index " << hitIndex << " out of range for track " << iTrack - // // << " (barcode vector size: " << (fileHits.barcode ? fileHits.barcode->size() : 0) << ")"; - // // } - // // } else { - // // LOG(warning) << "No majority hit information available for track " << iTrack; - // // } - // // for ( const auto &vv : fileTracksummary.majorityParticleId->at(iTrack) ){ - // // LOG(info) << vv; - // // } - // - // } - - // for (size_t iParticle = 0; iParticle < nParticlesGen; ++iParticle) { - // if (iParticle == 0 && nTracks == 0) { - // tableMcCollisions(0, // mccollision::BCId, - // 0, // mccollision::GeneratorsID, - // fileParticles.m_vx->at(iParticle), // mccollision::PosX, - // fileParticles.m_vy->at(iParticle), // mccollision::PosY, - // fileParticles.m_vz->at(iParticle), // mccollision::PosZ - // fileParticles.m_vt->at(iParticle), // mccollision::T - // 1.0f, // mccollision::Weight - // 0.0f, // mccollision::ImpactParameter, - // 0.f); // mccollision::EventPlaneAngle, - // } - // if (idMCparticles.end() != std::find(idMCparticles.begin(), idMCparticles.end(), fileParticles.m_particleId->at(iParticle))) { - // // Already added via track - // continue; - // } - // uint8_t flags = 0; - // flags |= o2::aod::mcparticle::enums::PhysicalPrimary; - - // int nHits = 0; - // for (size_t iPartSim = 0; iPartSim < nParticlesSim; ++iPartSim) { - // if (fileParticlesSim.m_particleId->at(iPartSim) == fileParticles.m_particleId->at(iParticle)) { - // nHits = fileParticlesSim.m_number_of_hits->at(iPartSim); - // break; - // } - // } - // addMCParticle(tableMcCollisions.lastIndex(), fileParticles, iParticle, flags, -1, -1, nHits); - // idMCparticles.push_back(fileParticles.m_particleId->at(iParticle)); - // } - // // if (addDaughterInfo) { - // // for (size_t iParticle = 0; iParticle < nDaughterParticles; ++iParticle) { - // // if (idMCparticles.end() != std::find(idMCparticles.begin(), idMCparticles.end(), fileDaughterParticles.m_particleId->at(iParticle))) { - // // // Already added via track - // // continue; - // // } - // // uint8_t flags = 0; - // // int nHits = 0; - // // for (size_t iPartSim = 0; iPartSim < nParticlesSim; ++iPartSim) { - // // if (fileParticlesSim.m_particleId->at(iPartSim) == fileDaughterParticles.m_particleId->at(iParticle)) { - // // nHits = fileParticlesSim.m_number_of_hits->at(iPartSim); - // // break; - // // } - // // } - // // int motherId = -1; - // // for (size_t iMother = 0; iMother < nParticlesGen; ++iMother) { - // // if (fileDaughterParticles.m_motherId->at(iParticle) == fileParticles.m_particleId->at(iMother)) { - // // if (count(idMCparticles.begin(), idMCparticles.end(), fileDaughterParticles.m_motherId->at(iParticle)) > 0) { - // // auto it = find(idMCparticles.begin(), idMCparticles.end(), fileDaughterParticles.m_motherId->at(iParticle)); - // // motherId = it - idMCparticles.begin() + indexOfLastParticleAfterEvent + 1; - // // } - // // } - // // } - // // addMCParticle(tableMcCollisions.lastIndex(), fileDaughterParticles, iParticle, flags, motherId, -1, nHits); - // // } - // // } - - // LOG(info) << "Event " << iEvent << ": has " << nTracks << " tracks, " << nParticlesGen << " particles " << nDaughterParticles << " daughter particles, " << nParticlesSim << " propagated particles."; - // LOG(info) << "Total numbers of stored MC particles: " << tableStoredMcParticles.lastIndex() + 1; - // indexOfLastParticleAfterEvent = tableStoredMcParticles.lastIndex(); } } }; diff --git a/ALICE3/Tasks/alice3-dilepton.cxx b/ALICE3/Tasks/alice3-dilepton.cxx index b258a2cff67..f9b3d5e0d5f 100644 --- a/ALICE3/Tasks/alice3-dilepton.cxx +++ b/ALICE3/Tasks/alice3-dilepton.cxx @@ -41,6 +41,7 @@ #include #include +#include #include using namespace o2; @@ -50,11 +51,19 @@ using namespace o2::framework; using namespace o2::framework::expressions; struct Alice3Lepton { + enum HFType { + kUndef = -1, + kCe = 0, + kBe = 1, + kBCe = 2, + kPPi0 = 3, + kHFE = 4, + }; Service inspdg; Configurable pdg{"pdg", 11, "pdg code for analysis. dielectron:11, dimuon:13"}; - Configurable requireHFE{"requireHFE", false, "Require HFE"}; + Configurable requireHFE{"requireHFE", -1, "-1: no selection, 0: charm, 1: direct beauty, 2: beauty->charm->e, 3: promptPi0, 4: HFE"}; Configurable ptMin{"ptMin", 0.f, "Lower limit in pT"}; Configurable ptMax{"ptMax", 5.f, "Upper limit in pT"}; Configurable etaMin{"etaMin", -5.f, "Lower limit in eta"}; @@ -84,7 +93,8 @@ struct Alice3Lepton { const AxisSpec axisSigmaEl{200, -10, 10, "n#sigma_{El}"}; const AxisSpec axisTrackLengthOuterTOF{300, 0., 300., "Track length (cm)"}; const AxisSpec axisEta{1000, -5, 5, "#it{#eta}"}; - const AxisSpec axisDCAxy{1000, 0, 20, "DCA_{xy,ll} (#sigma)"}; + const AxisSpec axisDCAxysigma{1000, -20, 20, "DCA_{xy} (#sigma)"}; + const AxisSpec axisDCAxy{1200, -300, 300, "DCA_{xy} (#micro m)"}; const AxisSpec axisPhi{360, 0, TMath::TwoPi(), "#it{#varphi} (rad.)"}; const AxisSpec axisProdx{2000, -100, 100, "Prod. Vertex X (cm)"}; const AxisSpec axisPrody{2000, -100, 100, "Prod. Vertex Y (cm)"}; @@ -113,11 +123,18 @@ struct Alice3Lepton { registry.add("Reconstructed/Track/Eta", "Track Eta", kTH1F, {axisEta}); registry.add("Reconstructed/Track/Phi", "Track Phi", kTH1F, {axisPhi}); registry.add("Reconstructed/Track/Eta_Pt", "Eta vs. Pt", kTH2F, {axisPt, axisEta}, true); + registry.add("Reconstructed/Track/DCAxysigma", "Track DCAxy in #sigma", kTH2F, {axisPt, axisDCAxysigma}); + registry.add("Reconstructed/Track/DCAxy", "Track DCAxy in #micro m", kTH2F, {axisPt, axisDCAxy}); registry.add("Reconstructed/Track/SigmaOTofvspt", "Track #sigma oTOF", kTH2F, {axisPt, axisSigmaEl}); registry.add("Reconstructed/Track/SigmaITofvspt", "Track #sigma iTOF", kTH2F, {axisPt, axisSigmaEl}); registry.add("Reconstructed/Track/SigmaRichvspt", "Track #sigma RICH", kTH2F, {axisPt, axisSigmaEl}); registry.add("Reconstructed/Track/outerTOFTrackLength", "Track length outer TOF", kTH1F, {axisTrackLengthOuterTOF}); + registry.add("Reconstructed/Track/PtMC", "Track Pt", kTH1F, {axisPt}); + registry.add("Reconstructed/Track/EtaMC", "Track Eta", kTH1F, {axisEta}); + registry.add("Reconstructed/Track/PhiMC", "Track Phi", kTH1F, {axisPhi}); + registry.add("Reconstructed/Track/EtaMC_PtMC", "Eta vs. Pt", kTH2F, {axisPt, axisEta}, true); + registry.addClone("Reconstructed/Track/", "Reconstructed/TrackPID/"); registry.addClone("Reconstructed/Track/", "Reconstructed/TrackPIDPre/"); } @@ -131,6 +148,8 @@ struct Alice3Lepton { registry.add("Reconstructed/Track/Eta", "Track Eta", kTH1F, {axisEta}); registry.add("Reconstructed/Track/Phi", "Track Phi", kTH1F, {axisPhi}); registry.add("Reconstructed/Track/Eta_Pt", "Eta vs. Pt", kTH2F, {axisPt, axisEta}, true); + registry.add("Reconstructed/Track/DCAxysigma", "Track DCAxy in #sigma", kTH2F, {axisPt, axisDCAxysigma}); + registry.add("Reconstructed/Track/DCAxy", "Track DCAxy in #micro m", kTH2F, {axisPt, axisDCAxy}); registry.add("Reconstructed/Track/PtMC", "Track Pt", kTH1F, {axisPt}); registry.add("Reconstructed/Track/EtaMC", "Track Eta", kTH1F, {axisEta}); @@ -142,6 +161,62 @@ struct Alice3Lepton { } } + template + int IsHF(TMCParticle1 const& p1, TMCParticles const& mcparticles) + { + if (!p1.has_mothers()) { + return HFType::kUndef; + } + + int motherid_p1 = p1.mothersIds()[0]; + if (motherid_p1 > -1) { + auto mother_p1 = mcparticles.iteratorAt(motherid_p1); + int mother1_pdg = mother_p1.pdgCode(); + // direct beauty + if (((500 < std::abs(mother1_pdg) && std::abs(mother1_pdg) < 599) || (5000 < std::abs(mother1_pdg) && std::abs(mother1_pdg) < 5999))) { + return HFType::kBe; + } + // charm direct or from beauty + if (((400 < std::abs(mother1_pdg) && std::abs(mother1_pdg) < 499) || (4000 < std::abs(mother1_pdg) && std::abs(mother1_pdg) < 4999))) { + if (mother_p1.has_mothers()) { + int motherId = mother_p1.mothersIds()[0]; + while (motherId > -1) { + auto mp = mcparticles.rawIteratorAt(motherId); + if (((500 < std::abs(mp.pdgCode()) && std::abs(mp.pdgCode()) < 599) || (5000 < std::abs(mp.pdgCode()) && std::abs(mp.pdgCode()) < 5999))) { + return HFType::kBCe; + } + if (mp.has_mothers()) { + motherId = mp.mothersIds()[0]; + } else { + motherId = -999; + } + } + } + return HFType::kCe; + } + // pi0 not from HF + if (mother1_pdg == 111) { + if (mother_p1.has_mothers()) { + int motherId = mother_p1.mothersIds()[0]; + while (motherId > -1) { + auto mp = mcparticles.rawIteratorAt(motherId); + if (((500 < std::abs(mp.pdgCode()) && std::abs(mp.pdgCode()) < 599) || (5000 < std::abs(mp.pdgCode()) && std::abs(mp.pdgCode()) < 5999)) || ((400 < std::abs(mp.pdgCode()) && std::abs(mp.pdgCode()) < 499) || (4000 < std::abs(mp.pdgCode()) && std::abs(mp.pdgCode()) < 4999))) { + return HFType::kUndef; + } + if (mp.has_mothers()) { + motherId = mp.mothersIds()[0]; + } else { + motherId = -999; + } + } + } + return HFType::kPPi0; + } + return HFType::kUndef; + } + return HFType::kUndef; + } + template bool IsInAcceptance(TTrack const& track) { @@ -191,7 +266,7 @@ struct Alice3Lepton { template void FillRec(TTracks const& tracks, - const aod::McParticles& /*mcParticles*/) + const aod::McParticles& mcParticles) { for (const auto& track : tracks) { if (!track.has_mcParticle()) { @@ -213,9 +288,21 @@ struct Alice3Lepton { continue; } } - if (std::abs(mcParticle.pdgCode()) != pdg) { - continue; + if (requireHFE > -1) { + int typehfe = IsHF(mcParticle, mcParticles); + if (requireHFE < HFType::kHFE && typehfe != requireHFE) { + continue; + } + if (requireHFE == HFType::kHFE && (typehfe == HFType::kUndef || typehfe == kPPi0)) { + continue; + } } + const float dcaXY = track.dcaXY(); + const float dcaXY_res = std::sqrt(track.cYY()); + float dcaXYinSigma = dcaXY / dcaXY_res; + float dcaXYinmicrom = dcaXY * 10000.; + registry.fill(HIST("Reconstructed/Track/DCAxy"), mcParticle.pt(), dcaXYinmicrom); + registry.fill(HIST("Reconstructed/Track/DCAxysigma"), mcParticle.pt(), dcaXYinSigma); if constexpr (isWithSmearing) { registry.fill(HIST("Reconstructed/Track/Pt"), track.ptSmeared()); registry.fill(HIST("Reconstructed/Track/Eta"), track.etaSmeared()); @@ -234,10 +321,16 @@ struct Alice3Lepton { registry.fill(HIST("Reconstructed/Track/Eta"), track.eta()); registry.fill(HIST("Reconstructed/Track/Phi"), track.phi()); registry.fill(HIST("Reconstructed/Track/Eta_Pt"), track.pt(), track.eta()); + registry.fill(HIST("Reconstructed/Track/PtMC"), mcParticle.pt()); + registry.fill(HIST("Reconstructed/Track/EtaMC"), mcParticle.eta()); + registry.fill(HIST("Reconstructed/Track/PhiMC"), mcParticle.phi()); + registry.fill(HIST("Reconstructed/Track/EtaMC_PtMC"), mcParticle.pt(), mcParticle.eta()); } // implement pid if constexpr (isWithSmearing) { if (track.selected()) { + registry.fill(HIST("Reconstructed/TrackPID/DCAxy"), mcParticle.pt(), dcaXYinmicrom); + registry.fill(HIST("Reconstructed/TrackPID/DCAxysigma"), mcParticle.pt(), dcaXYinSigma); registry.fill(HIST("Reconstructed/TrackPID/Pt"), track.ptSmeared()); registry.fill(HIST("Reconstructed/TrackPID/Eta"), track.etaSmeared()); registry.fill(HIST("Reconstructed/TrackPID/Phi"), track.phiSmeared()); @@ -248,6 +341,8 @@ struct Alice3Lepton { registry.fill(HIST("Reconstructed/TrackPID/EtaMC_PtMC"), mcParticle.pt(), mcParticle.eta()); if (track.isTrackPrefilter() == 0) { + registry.fill(HIST("Reconstructed/TrackPIDPre/DCAxy"), mcParticle.pt(), dcaXYinmicrom); + registry.fill(HIST("Reconstructed/TrackPIDPre/DCAxysigma"), mcParticle.pt(), dcaXYinSigma); registry.fill(HIST("Reconstructed/TrackPIDPre/Pt"), track.ptSmeared()); registry.fill(HIST("Reconstructed/TrackPIDPre/Eta"), track.etaSmeared()); registry.fill(HIST("Reconstructed/TrackPIDPre/Phi"), track.phiSmeared()); @@ -267,20 +362,32 @@ struct Alice3Lepton { registry.fill(HIST("Reconstructed/TrackPID/SigmaITofvspt"), track.pt(), track.nSigmaElectronInnerTOF()); registry.fill(HIST("Reconstructed/TrackPID/SigmaRichvspt"), track.pt(), track.nSigmaElectronRich()); registry.fill(HIST("Reconstructed/TrackPID/outerTOFTrackLength"), track.outerTOFTrackLength()); + registry.fill(HIST("Reconstructed/TrackPID/DCAxy"), mcParticle.pt(), dcaXYinmicrom); + registry.fill(HIST("Reconstructed/TrackPID/DCAxysigma"), mcParticle.pt(), dcaXYinSigma); registry.fill(HIST("Reconstructed/TrackPID/Pt"), track.pt()); registry.fill(HIST("Reconstructed/TrackPID/Eta"), track.eta()); registry.fill(HIST("Reconstructed/TrackPID/Phi"), track.phi()); registry.fill(HIST("Reconstructed/TrackPID/Eta_Pt"), track.pt(), track.eta()); + registry.fill(HIST("Reconstructed/TrackPID/PtMC"), mcParticle.pt()); + registry.fill(HIST("Reconstructed/TrackPID/EtaMC"), mcParticle.eta()); + registry.fill(HIST("Reconstructed/TrackPID/PhiMC"), mcParticle.phi()); + registry.fill(HIST("Reconstructed/TrackPID/EtaMC_PtMC"), mcParticle.pt(), mcParticle.eta()); if (track.isTrackPrefilter() == 0) { registry.fill(HIST("Reconstructed/TrackPIDPre/SigmaOTofvspt"), track.pt(), track.nSigmaElectronOuterTOF()); registry.fill(HIST("Reconstructed/TrackPIDPre/SigmaITofvspt"), track.pt(), track.nSigmaElectronInnerTOF()); registry.fill(HIST("Reconstructed/TrackPIDPre/SigmaRichvspt"), track.pt(), track.nSigmaElectronRich()); registry.fill(HIST("Reconstructed/TrackPIDPre/outerTOFTrackLength"), track.outerTOFTrackLength()); + registry.fill(HIST("Reconstructed/TrackPIDPre/DCAxy"), mcParticle.pt(), dcaXYinmicrom); + registry.fill(HIST("Reconstructed/TrackPIDPre/DCAxysigma"), mcParticle.pt(), dcaXYinSigma); registry.fill(HIST("Reconstructed/TrackPIDPre/Pt"), track.pt()); registry.fill(HIST("Reconstructed/TrackPIDPre/Eta"), track.eta()); registry.fill(HIST("Reconstructed/TrackPIDPre/Phi"), track.phi()); registry.fill(HIST("Reconstructed/TrackPIDPre/Eta_Pt"), track.pt(), track.eta()); + registry.fill(HIST("Reconstructed/TrackPIDPre/PtMC"), mcParticle.pt()); + registry.fill(HIST("Reconstructed/TrackPIDPre/EtaMC"), mcParticle.eta()); + registry.fill(HIST("Reconstructed/TrackPIDPre/PhiMC"), mcParticle.phi()); + registry.fill(HIST("Reconstructed/TrackPIDPre/EtaMC_PtMC"), mcParticle.pt(), mcParticle.eta()); } } } @@ -322,6 +429,15 @@ struct Alice3Lepton { if (!mcParticle.isPhysicalPrimary()) { continue; } + if (requireHFE > -1) { + int typehfe = IsHF(mcParticle, mcParticles); + if (requireHFE < HFType::kHFE && typehfe != requireHFE) { + continue; + } + if (requireHFE == HFType::kHFE && (typehfe == HFType::kUndef || typehfe == kPPi0)) { + continue; + } + } if (!IsInAcceptance(mcParticle)) { continue; } @@ -412,7 +528,8 @@ struct Alice3Dilepton { SliceCache cache_rec; Configurable pdg{"pdg", 11, "pdg code for analysis. dielectron:11, dimuon:13"}; - Configurable requireHFEid{"requireHFEid", true, "Require HFE identification for both leptons"}; + Configurable requireHFEid{"requireHFEid", true, "Require HFE identification"}; + Configurable contamination{"contamination", false, "Fill only pairs with one misidentifixed electrons"}; Configurable ptMin{"ptMin", 0.f, "Lower limit in pT"}; Configurable ptMax{"ptMax", 5.f, "Upper limit in pT"}; Configurable etaMin{"etaMin", -5.f, "Lower limit in eta"}; @@ -448,8 +565,6 @@ struct Alice3Dilepton { registry.add("Reconstructed/Track/Eta", "Particle Eta", kTH1F, {axisEta}); registry.add("Reconstructed/Track/Phi", "Particle Phi", kTH1F, {axisPhi}); registry.add("Reconstructed/Track/Pre", "Particle Pre", kTH1F, {axisPre}); - } - if (doprocessRecAllWithSmearing) { registry.add("Reconstructed/Track/PtMC", "Track Pt", kTH1F, {axisPt}); registry.add("Reconstructed/Track/EtaMC", "Particle Eta", kTH1F, {axisEta}); registry.add("Reconstructed/Track/PhiMC", "Particle Phi", kTH1F, {axisPhi}); @@ -515,13 +630,40 @@ struct Alice3Dilepton { } } + template + bool IsHF(TTrack const& track, TMCParticles const& mcparticles) + { + if (!track.has_mcParticle()) { + return false; + } + const auto p1 = track.template mcParticle_as(); + if (!p1.has_mothers()) { + return false; + } + int motherId = p1.mothersIds()[0]; + while (motherId > -1) { + auto mp = mcparticles.rawIteratorAt(motherId); + if (((500 < std::abs(mp.pdgCode()) && std::abs(mp.pdgCode()) < 599) || (5000 < std::abs(mp.pdgCode()) && std::abs(mp.pdgCode()) < 5999)) || ((400 < std::abs(mp.pdgCode()) && std::abs(mp.pdgCode()) < 499) || (4000 < std::abs(mp.pdgCode()) && std::abs(mp.pdgCode()) < 4999))) { + return true; + } + if (mp.has_mothers()) { + motherId = mp.mothersIds()[0]; + } else { + motherId = -999; + } + } + return false; + } + template int IsSameMother(TMCParticle1 const& p1, TMCParticle2 const& p2, TMCParticles const& mcparticles) { - if (!p1.has_mothers()) + if (!p1.has_mothers()) { return -1; - if (!p2.has_mothers()) + } + if (!p2.has_mothers()) { return -1; + } int motherid1 = p1.mothersIds()[0]; auto mother1 = mcparticles.iteratorAt(motherid1); @@ -531,10 +673,12 @@ struct Alice3Dilepton { auto mother2 = mcparticles.iteratorAt(motherid2); int mother2_pdg = mother2.pdgCode(); - if (motherid1 != motherid2) + if (motherid1 != motherid2) { return -1; - if (mother1_pdg != mother2_pdg) + } + if (mother1_pdg != mother2_pdg) { return -1; + } if (std::abs(mother1_pdg) != PDG_t::kGamma // photon && std::abs(mother1_pdg) != PDG_t::kPi0 // pi0 @@ -560,10 +704,12 @@ struct Alice3Dilepton { // 1. b->e- and bbar->e+ (different b and bbar) // 2. b->c->e+ and bbar->cbar->e- (different b and bbar) // 3. b->c->e+ and b->e- (1 same b (or bbar)) - if (!p1.has_mothers()) + if (!p1.has_mothers()) { return HFllType::kUndef; - if (!p2.has_mothers()) + } + if (!p2.has_mothers()) { return HFllType::kUndef; + } int motherid_p1 = p1.mothersIds()[0]; int motherid_p2 = p2.mothersIds()[0]; @@ -613,10 +759,12 @@ struct Alice3Dilepton { { // in total, 1 case for LS pairs // 4. b->c->e+ and bbar->e+ - if (!p1.has_mothers()) + if (!p1.has_mothers()) { return HFllType::kUndef; - if (!p2.has_mothers()) + } + if (!p2.has_mothers()) { return HFllType::kUndef; + } int motherid_p1 = p1.mothersIds()[0]; int motherid_p2 = p2.mothersIds()[0]; @@ -674,13 +822,27 @@ struct Alice3Dilepton { } template - void FillPairRecAll(TTracks const& tracks1, TTracks const& tracks2) + void FillPairRecAll(TTracks const& tracks1, TTracks const& tracks2, const aod::McParticles& mcParticles) { if constexpr (pairtype == PairType::kULS) { for (const auto& [t1, t2] : combinations(soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { if (!IsInAcceptance(t1) || !IsInAcceptance(t2)) { continue; } + if (contamination) { + if (t1.has_mcParticle() && t2.has_mcParticle()) { + auto mct1 = t1.template mcParticle_as(); + auto mct2 = t2.template mcParticle_as(); + if (std::abs(mct1.pdgCode()) == pdg && std::abs(mct2.pdgCode()) == pdg) { + continue; + } + } + } + if (requireHFEid) { + if (!IsHF(t1, mcParticles) && !IsHF(t2, mcParticles)) { + continue; + } + } float pair_dca_xy = 999.f; ROOT::Math::PtEtaPhiMVector v12 = buildPairDCA(t1, t2, pair_dca_xy); @@ -697,6 +859,20 @@ struct Alice3Dilepton { if (!IsInAcceptance(t1) || !IsInAcceptance(t2)) { continue; } + if (contamination) { + if (t1.has_mcParticle() && t2.has_mcParticle()) { + auto mct1 = t1.template mcParticle_as(); + auto mct2 = t2.template mcParticle_as(); + if (std::abs(mct1.pdgCode()) == pdg && std::abs(mct2.pdgCode()) == pdg) { + continue; + } + } + } + if (requireHFEid) { + if (!IsHF(t1, mcParticles) && !IsHF(t2, mcParticles)) { + continue; + } + } float pair_dca_xy = 999.f; ROOT::Math::PtEtaPhiMVector v12 = buildPairDCA(t1, t2, pair_dca_xy); @@ -969,30 +1145,51 @@ struct Alice3Dilepton { } // end of processRec void processRecAll(MyFilteredAlice3Collision const& collisions, - MyFilteredTracksMC const& tracks) + MyFilteredTracksMC const&, + const aod::McParticles& mcParticles) { - - for (const auto& track : tracks) { - if (!IsInAcceptance(track)) { - continue; - } - registry.fill(HIST("Reconstructed/Track/Pt"), track.pt()); - registry.fill(HIST("Reconstructed/Track/Eta"), track.eta()); - registry.fill(HIST("Reconstructed/Track/Phi"), track.phi()); - registry.fill(HIST("Reconstructed/Track/Pre"), track.isTrackPrefilter()); - registry.fill(HIST("Reconstructed/Track/SigmaOTofvspt"), track.pt(), track.nSigmaElectronOuterTOF()); - registry.fill(HIST("Reconstructed/Track/SigmaITofvspt"), track.pt(), track.nSigmaElectronInnerTOF()); - registry.fill(HIST("Reconstructed/Track/SigmaRichvspt"), track.pt(), track.nSigmaElectronRich()); - } - for (const auto& collision : collisions) { registry.fill(HIST("Reconstructed/Event/VtxZ"), collision.posZ()); auto negTracks_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache_rec); auto posTracks_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache_rec); - FillPairRecAll(negTracks_coll, posTracks_coll); - FillPairRecAll(posTracks_coll, posTracks_coll); - FillPairRecAll(negTracks_coll, negTracks_coll); + for (const auto& track : negTracks_coll) { + if (!IsInAcceptance(track)) { + continue; + } + if (!track.has_mcParticle()) { + continue; + } + const auto mcParticle = track.template mcParticle_as(); + registry.fill(HIST("Reconstructed/Track/PtMC"), mcParticle.pt()); + registry.fill(HIST("Reconstructed/Track/EtaMC"), mcParticle.eta()); + registry.fill(HIST("Reconstructed/Track/PhiMC"), mcParticle.phi()); + registry.fill(HIST("Reconstructed/Track/Pt"), track.pt()); + registry.fill(HIST("Reconstructed/Track/Eta"), track.eta()); + registry.fill(HIST("Reconstructed/Track/Phi"), track.phi()); + registry.fill(HIST("Reconstructed/Track/Pre"), track.isTrackPrefilter()); + } + + for (const auto& track : posTracks_coll) { + if (!IsInAcceptance(track)) { + continue; + } + if (!track.has_mcParticle()) { + continue; + } + const auto mcParticle = track.template mcParticle_as(); + registry.fill(HIST("Reconstructed/Track/PtMC"), mcParticle.pt()); + registry.fill(HIST("Reconstructed/Track/EtaMC"), mcParticle.eta()); + registry.fill(HIST("Reconstructed/Track/PhiMC"), mcParticle.phi()); + registry.fill(HIST("Reconstructed/Track/Pt"), track.pt()); + registry.fill(HIST("Reconstructed/Track/Eta"), track.eta()); + registry.fill(HIST("Reconstructed/Track/Phi"), track.phi()); + registry.fill(HIST("Reconstructed/Track/Pre"), track.isTrackPrefilter()); + } + + FillPairRecAll(negTracks_coll, posTracks_coll, mcParticles); + FillPairRecAll(posTracks_coll, posTracks_coll, mcParticles); + FillPairRecAll(negTracks_coll, negTracks_coll, mcParticles); } // end of collision loop } // end of processRec @@ -1015,7 +1212,7 @@ struct Alice3Dilepton { void processRecAllWithSmearing(MyFilteredAlice3Collision const& collisions, MyFilteredTracksWithSmearing const&, - const aod::McParticles&) + const aod::McParticles& mcParticles) { for (const auto& collision : collisions) { registry.fill(HIST("Reconstructed/Event/VtxZ"), collision.posZ()); @@ -1056,9 +1253,9 @@ struct Alice3Dilepton { registry.fill(HIST("Reconstructed/Track/Pre"), track.isTrackPrefilter()); } - FillPairRecAll(negTracks_coll, posTracks_coll); - FillPairRecAll(posTracks_coll, posTracks_coll); - FillPairRecAll(negTracks_coll, negTracks_coll); + FillPairRecAll(negTracks_coll, posTracks_coll, mcParticles); + FillPairRecAll(posTracks_coll, posTracks_coll, mcParticles); + FillPairRecAll(negTracks_coll, negTracks_coll, mcParticles); } // end of collision loop } // end of processRec diff --git a/ALICE3/Tasks/alice3DqEfficiency.cxx b/ALICE3/Tasks/alice3DqEfficiency.cxx index 78d7af23f06..59757563955 100644 --- a/ALICE3/Tasks/alice3DqEfficiency.cxx +++ b/ALICE3/Tasks/alice3DqEfficiency.cxx @@ -23,12 +23,10 @@ #include "PWGDQ/Core/MixingHandler.h" #include "PWGDQ/Core/MixingLibrary.h" #include "PWGDQ/Core/VarManager.h" -#include "PWGDQ/DataModel/ReducedInfoTables.h" #include "ALICE3/DataModel/ReducedTablesAlice3.h" #include "Common/Core/TableHelper.h" -#include #include #include #include @@ -43,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -111,10 +108,9 @@ DECLARE_SOA_TABLE(OniaMCTruth, "AOD", "MCTRUTHONIA", dqanalysisflags::OniaPt, dq // TODO: USE PROPER TABLES -using MyEvents = soa::Join; -using MyEventsSelected = soa::Join; -using MyEventsVtxCov = soa::Join; -using MyEventsVtxCovSelected = soa::Join; +using MyEvents = soa::Join; +using MyEventsVtxCov = soa::Join; +using MyEventsVtxCovSelected = soa::Join; using MyBarrelAssocs = soa::Join; using MyBarrelAssocsPrefilter = soa::Join; @@ -304,7 +300,7 @@ struct Alice3DqEfficiencyAnalysisTrackSelection { Configurable cfgTrackMCsignalsJSON{"cfgTrackMCsignalsJSON", "", "Additional list of MC signals via JSON"}; HistogramManager* fHistMan = nullptr; - std::vector fTrackCuts; + std::vector fTrackCuts; std::vector fMCSignals; // list of signals to be checked std::vector fHistNamesReco; std::vector fHistNamesMCMatched; @@ -331,7 +327,7 @@ struct Alice3DqEfficiencyAnalysisTrackSelection { if (addTrackCutsStr != "") { std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); for (const auto& t : addTrackCuts) { - fTrackCuts.push_back(static_cast(t)); + fTrackCuts.push_back(t); } } VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill @@ -402,7 +398,7 @@ struct Alice3DqEfficiencyAnalysisTrackSelection { // Loop over associations for (const auto& assoc : assocs) { - auto event = assoc.template reA3event_as(); + auto event = assoc.template reA3Event_as(); if (!event.isEventSelected_bit(0)) { trackSel(0); continue; @@ -415,7 +411,7 @@ struct Alice3DqEfficiencyAnalysisTrackSelection { VarManager::FillEventAlice3(event.reA3MCEvent()); } - auto track = assoc.template reA3track_as(); + auto track = assoc.template reA3Track_as(); VarManager::FillTrackAlice3(track); // compute quantities which depend on the associated collision, such as DCA VarManager::FillTrackCollision(track, event); @@ -564,7 +560,7 @@ struct Alice3DqEfficiencyAnalysisPrefilterSelection { uint32_t fPrefilterMask = 0; int fPrefilterCutBit = -1; - PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reA3eventId; + PresliceUnsorted trackAssocsPerCollision = aod::reduceda3trackassociation::reA3EventId; void init(o2::framework::InitContext& context) { @@ -598,10 +594,10 @@ struct Alice3DqEfficiencyAnalysisPrefilterSelection { // get the list of cuts that were computed in the barrel track-selection task and create a bit mask // to mark just the ones we want to apply a prefilter on string trackCuts; - getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", trackCuts, false); + getTaskOptionValue(context, "alice3-dq-efficiency-analysis-track-selection", "cfgTrackCuts", trackCuts, false); TString allTrackCutsStr = trackCuts; // check also the cuts added via JSON and add them to the string of cuts - getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", trackCuts, false); + getTaskOptionValue(context, "alice3-dq-efficiency-analysis-track-selection", "cfgBarrelTrackCutsJSON", trackCuts, false); TString addTrackCutsStr = trackCuts; if (addTrackCutsStr != "") { std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); @@ -651,8 +647,8 @@ struct Alice3DqEfficiencyAnalysisPrefilterSelection { } for (const auto& [assoc1, assoc2] : o2::soa::combinations(assocs, assocs)) { - auto track1 = assoc1.template reA3track_as(); - auto track2 = assoc2.template reA3track_as(); + auto track1 = assoc1.template reA3Track_as(); + auto track2 = assoc2.template reA3Track_as(); // NOTE: here we restrict to just pairs of opposite sign (conversions), but in principle this can be made // a configurable and check also same-sign pairs (track splitting) @@ -708,7 +704,7 @@ struct Alice3DqEfficiencyAnalysisPrefilterSelection { } else { for (const auto& assoc : assocs) { // TODO: just use the index from the assoc (no need to cast the whole track) - auto track = assoc.template reA3track_as(); + auto track = assoc.template reA3Track_as(); mymap = -1; if (!fPrefilterMap.contains(track.globalIndex())) { // NOTE: publish the bitwise negated bits (~), so there will be zeroes for cuts that failed the prefiltering and 1 everywhere else @@ -736,12 +732,6 @@ struct Alice3DqEfficiencyAnalysisPrefilterSelection { // The task implements also process functions for running event mixing struct Alice3DqEfficiencyAnalysisSameEventPairing { - Produces dielectronList; - Produces dielectronsExtraList; - Produces dielectronAllList; - Produces mcTruthTableEffi; - - o2::base::MatLayerCylSet* fLUT = nullptr; OutputObj fOutputList{"output"}; struct : ConfigurableGroup { @@ -795,7 +785,7 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { bool fEnableBarrelHistos = false; - PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reA3eventId; + PresliceUnsorted trackAssocsPerCollision = aod::reduceda3trackassociation::reA3EventId; void init(o2::framework::InitContext& context) { @@ -852,10 +842,10 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { // get the barrel track selection cuts string tempCuts; - getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", tempCuts, false); + getTaskOptionValue(context, "alice3-dq-efficiency-analysis-track-selection", "cfgTrackCuts", tempCuts, false); TString tempCutsStr = tempCuts; // check also the cuts added via JSON and add them to the string of cuts - getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", tempCuts, false); + getTaskOptionValue(context, "alice3-dq-efficiency-analysis-track-selection", "cfgBarrelTrackCutsJSON", tempCuts, false); TString addTrackCutsStr = tempCuts; if (addTrackCutsStr != "") { std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); @@ -1021,27 +1011,6 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { bool isCorrectAssocLeg1 = false; bool isCorrectAssocLeg2 = false; - int64_t reserveSize = 0; - for (auto const& event : events) { - if (event.isEventSelected_bit(0)) { - auto groupedAssocs = assocs.sliceBy(preslice, event.globalIndex()); - size_t nGood = 0; - for (auto const& t : groupedAssocs) { - if (t.isBarrelSelected_raw() > 0u) { - nGood++; - } - } - reserveSize += nGood * (nGood - 1) / 2; - } - } - - dielectronList.reserve(reserveSize); - dielectronsExtraList.reserve(reserveSize); - - if (fConfigOptions.cfgFlatTables.value) { - dielectronAllList.reserve(reserveSize); - } - for (const auto& event : events) { if (!event.isEventSelected_bit(0)) { continue; @@ -1064,8 +1033,8 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { continue; } - auto t1 = a1.template reA3track_as(); - auto t2 = a2.template reA3track_as(); + auto t1 = a1.template reA3Track_as(); + auto t2 = a2.template reA3Track_as(); sign1 = t1.sign(); sign2 = t2.sign(); // store the ambiguity number of the two dilepton legs in the last 4 digits of the two-track filter @@ -1103,11 +1072,6 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { } VarManager::FillPairVertexingAlice3(event, t1, t2, fConfigOptions.cfgPropToPCA); - if (!fConfigMC.cfgSkimSignalOnly || mcDecision > 0) { - dielectronList(event.globalIndex(), VarManager::fgValues[VarManager::kMass], - VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], - t1.sign() + t2.sign(), twoTrackFilter, mcDecision); - } // Fill histograms bool isAmbiInBunch = false; @@ -1209,7 +1173,7 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { } // end loop over events } - PresliceUnsorted perReducedMcEvent = aod::reducedA3trackMC::reA3MCEventId; + PresliceUnsorted perReducedMcEvent = aod::reduceda3trackmc::reA3MCEventId; void runMCGenWithGrouping(MyEventsVtxCovSelected const& events, ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& mcTracks) { @@ -1254,7 +1218,6 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { for (const auto& sig : fGenMCSignals) { if (sig->CheckSignal(true, trackRaw)) { fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), dqefficiency_helpers::varValues()); - mcTruthTableEffi(VarManager::fgValues[VarManager::kMCPt], VarManager::fgValues[VarManager::kMCEta], VarManager::fgValues[VarManager::kMCY], VarManager::fgValues[VarManager::kMCPhi], VarManager::fgValues[VarManager::kMCVz], VarManager::fgValues[VarManager::kMCVtxZ], VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); } } } @@ -1325,7 +1288,7 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { runMCGenWithGrouping(events, mcEvents, mcTracks); } - PresliceUnsorted perReducedMcGenEvent = aod::reducedA3trackMC::reA3MCEventId; + PresliceUnsorted perReducedMcGenEvent = aod::reduceda3trackmc::reA3MCEventId; void processMCGen(soa::Filtered const& events, ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& mcTracks) { @@ -1361,7 +1324,6 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { for (const auto& sig : fGenMCSignals) { if (sig->CheckSignal(true, trackRaw)) { fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), dqefficiency_helpers::varValues()); - mcTruthTableEffi(VarManager::fgValues[VarManager::kMCPt], VarManager::fgValues[VarManager::kMCEta], VarManager::fgValues[VarManager::kMCY], VarManager::fgValues[VarManager::kMCPhi], VarManager::fgValues[VarManager::kMCVz], VarManager::fgValues[VarManager::kMCVtxZ], VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); } } } @@ -1447,7 +1409,6 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { for (const auto& sig : fGenMCSignals) { if (sig->CheckSignal(true, trackRaw)) { fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), dqefficiency_helpers::varValues()); - mcTruthTableEffi(VarManager::fgValues[VarManager::kMCPt], VarManager::fgValues[VarManager::kMCEta], VarManager::fgValues[VarManager::kMCY], VarManager::fgValues[VarManager::kMCPhi], VarManager::fgValues[VarManager::kMCVz], VarManager::fgValues[VarManager::kMCVtxZ], VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); } } } @@ -1510,9 +1471,6 @@ struct Alice3DqEfficiencyAnalysisSameEventPairing { struct Alice3DqEfficiencyAnalysisAsymmetricPairing { - Produces ditrackList; - Produces ditrackExtraList; - // Output objects OutputObj fOutputList{"output"}; @@ -1539,7 +1497,7 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { HistogramManager* fHistMan = nullptr; - std::vector fPairCuts; + std::vector fPairCuts; int fNPairHistPrefixes = 0; std::vector fRecMCSignals; @@ -1569,8 +1527,8 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { Filter eventFilter = aod::dqanalysisflags::isEventSelected > static_cast(0); - PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reA3eventId; - // PresliceUnsorted trackAssocsPerCollision = aod::reducedA3track_association::reA3eventId; + PresliceUnsorted trackAssocsPerCollision = aod::reduceda3trackassociation::reA3EventId; + // PresliceUnsorted trackAssocsPerCollision = aod::reduceda3trackassociation::reA3EventId; // Partitions for triplets and asymmetric pairs Partition legACandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & cfgLegAFilterMask) > static_cast(0); @@ -1610,7 +1568,7 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { if (addPairCutsStr != "") { std::vector addPairCuts = dqcuts::GetCutsFromJSON(addPairCutsStr.Data()); for (const auto& t : addPairCuts) { - fPairCuts.push_back(static_cast(t)); + fPairCuts.push_back(t); pairCutNamesStr += Form(",%s", t->GetName()); } } @@ -1649,10 +1607,10 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { // Get the barrel track selection cuts string tempCuts; - getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", tempCuts, false); + getTaskOptionValue(context, "alice3-dq-efficiency-analysis-track-selection", "cfgTrackCuts", tempCuts, false); TString tempCutsStr = tempCuts; // check also the cuts added via JSON and add them to the string of cuts - getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", tempCuts, false); + getTaskOptionValue(context, "alice3-dq-efficiency-analysis-track-selection", "cfgBarrelTrackCutsJSON", tempCuts, false); TString addTrackCutsStr = tempCuts; if (addTrackCutsStr != "") { std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); @@ -1928,8 +1886,6 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { int sign1 = 0; int sign2 = 0; uint32_t mcDecision = 0; - ditrackList.reserve(1); - ditrackExtraList.reserve(1); for (const auto& event : events) { if (!event.isEventSelected_bit(0)) { @@ -1951,8 +1907,8 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { for (const auto& [a1, a2] : combinations(soa::CombinationsFullIndexPolicy(groupedLegAAssocs, groupedLegBAssocs))) { uint32_t twoTrackFilter = 0; uint32_t twoTrackCommonFilter = 0; - uint32_t pairFilter = 0; bool isPairIdWrong = false; + for (int icut = 0; icut < fNLegCuts; ++icut) { // Find leg pair definitions both candidates participate in if (((a1.isBarrelSelected_raw() & fConstructedLegAFilterMasksMap[icut]) != 0u) && ((a2.isBarrelSelected_raw() & fConstructedLegBFilterMasksMap[icut]) != 0u)) { @@ -1973,8 +1929,8 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { // Find common track cuts both candidates pass twoTrackCommonFilter |= a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & fCommonTrackCutMask; - auto t1 = a1.template reA3track_as(); - auto t2 = a2.template reA3track_as(); + auto t1 = a1.template reA3Track_as(); + auto t2 = a2.template reA3Track_as(); // Avoid self-pairs if (t1.globalIndex() == t2.globalIndex()) { @@ -2103,7 +2059,6 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { if (!((*cut)->IsSelected(dqefficiency_helpers::varValues()))) { // apply pair cuts continue; } - pairFilter |= (static_cast(1) << iPairCut); // Histograms with pair cuts if (sign1 * sign2 < 0) { fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data()), dqefficiency_helpers::varValues()); @@ -2157,9 +2112,6 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { } // end loop (pair cuts) } } // end loop (cuts) - ditrackList(event.globalIndex(), VarManager::fgValues[VarManager::kMass], - VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], - t1.sign() + t2.sign(), twoTrackFilter, pairFilter, twoTrackCommonFilter); } // end inner assoc loop (leg A) } // end event loop } @@ -2242,9 +2194,9 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { // Find common track cuts all candidates pass threeTrackCommonFilter |= a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & a3.isBarrelSelected_raw() & fCommonTrackCutMask; - auto t1 = a1.template reA3track_as(); - auto t2 = a2.template reA3track_as(); - auto t3 = a3.template reA3track_as(); + auto t1 = a1.template reA3Track_as(); + auto t2 = a2.template reA3Track_as(); + auto t3 = a3.template reA3Track_as(); // Avoid self-pairs if (t1 == t2 || t1 == t3 || t2 == t3) { @@ -2369,7 +2321,7 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { { // loop over mc stack and fill histograms for pure MC truth signals // group all the MC tracks which belong to the MC event corresponding to the current reconstructed event - // auto groupedMCTracks = tracksMC.sliceBy(aod::reducedA3trackMC::reA3MCEventId, event.reducedMCevent().globalIndex()); + // auto groupedMCTracks = tracksMC.sliceBy(aod::reduceda3trackmc::reA3MCEventId, event.reducedMCevent().globalIndex()); for (const auto& mctrack : mcTracks) { VarManager::FillTrackMC(mcTracks, mctrack); @@ -2384,7 +2336,7 @@ struct Alice3DqEfficiencyAnalysisAsymmetricPairing { } } - PresliceUnsorted perReducedMcEvent = aod::reducedA3trackMC::reA3MCEventId; + PresliceUnsorted perReducedMcEvent = aod::reduceda3trackmc::reA3MCEventId; void processMCGenWithEventSelection(soa::Filtered const& events, ReA3MCEvents const& /*mcEvents*/, ReA3MCTracks const& mcTracks) diff --git a/ALICE3/Tasks/alice3Multicharm.cxx b/ALICE3/Tasks/alice3Multicharm.cxx index b344fe5095f..b71a376ceed 100644 --- a/ALICE3/Tasks/alice3Multicharm.cxx +++ b/ALICE3/Tasks/alice3Multicharm.cxx @@ -21,11 +21,13 @@ // HF decays. Work in progress: use at your own risk! #include "ALICE3/DataModel/OTFMulticharm.h" -#include "Tools/ML/model.h" +#include "ALICE3/ML/MulticharmMlResponse.h" +#include "Tools/ML/MlResponse.h" #include #include #include +#include #include #include #include @@ -35,36 +37,38 @@ #include +#include #include #include #include -#include #include #include using namespace o2; -using namespace o2::ml; using namespace o2::framework; using namespace o2::framework::expressions; struct Alice3Multicharm { HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - o2::ml::OnnxModel bdtMCharm{}; - std::map metadata{}; - o2::ccdb::CcdbApi ccdbApi{}; + o2::analysis::MulticharmMlResponse mlResponse; + o2::ccdb::CcdbApi ccdbApi; static constexpr float ToMicrons = 1e+4; struct : ConfigurableGroup { - std::string prefix = "bdt"; + std::string prefix = "ml"; Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable localPath{"localPath", "MCharm_BDTModel.onnx", "(std::string) Path to the local .onnx file."}; - Configurable pathCCDB{"pathCCDB", "Users/j/jekarlss/MLModels", "Path on CCDB"}; Configurable timestampCCDB{"timestampCCDB", 1695750420200, "timestamp of the ONNX file for ML model used to query in CCDB. Please use 1695750420200"}; Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; - Configurable enableOptimizations{"enableOptimizations", false, "Enables the ONNX extended model-optimization: sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED)"}; - Configurable enableML{"enableML", true, "Enables bdt model"}; - } bdt; + Configurable enableBDT{"enableBDT", false, "Enables bdt model"}; + Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{"Users/j/jekarlss/MLModels"}, "Paths of models on CCDB"}; + Configurable> ptBinEdges{"ptBinEdges", {0, 2, 4, 6, 8, 10, 15}, "Bin edges for pT dependant BDT"}; + Configurable> scoreCuts{"scoreCuts", {multi_charm_ml::Cuts[0].data(), multi_charm_ml::NBinsPt, multi_charm_ml::NClasses, multi_charm_ml::labelsPt, multi_charm_ml::labelsCutScore}, "ML selections per pT bin"}; + Configurable> cutDir{"cutDir", std::vector{o2::cuts_ml::CutDirection::CutNot}, "Whether to reject score values greater or smaller than the threshold"}; + Configurable> onnxFileNames{"onnxFileNames", std::vector{"MCharm_BDTModel.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; + Configurable> namesInputFeatures{"namesInputFeatures", std::vector(multi_charm_ml::namesInputFeatures), "Names of ML model input features"}; + } ml; ConfigurableAxis axisEta{"axisEta", {80, -4.0f, +4.0f}, "#eta"}; ConfigurableAxis axisXicMass{"axisXicMass", {200, 2.368f, 2.568f}, "Xic Inv Mass (GeV/c^{2})"}; @@ -72,7 +76,6 @@ struct Alice3Multicharm { ConfigurableAxis axisDCA{"axisDCA", {400, 0, 400}, "DCA (#mum)"}; ConfigurableAxis axisRadiusLarge{"axisRadiusLarge", {1000, 0, 20}, "Decay radius (cm)"}; ConfigurableAxis axisRadius{"axisRadius", {10000, 0, 10000}, "Decay radius (#mum)"}; - ConfigurableAxis axisTofTrackDelta{"axisTofTrackDelta", {200, 0, 1000}, "TOF track time"}; ConfigurableAxis axisNSigma{"axisNSigma", {21, -10, 10}, "nsigma"}; ConfigurableAxis axisDecayLength{"axisDecayLength", {2000, 0, 2000}, "Decay lenght (#mum)"}; ConfigurableAxis axisDcaDaughters{"axisDcaDaughters", {200, 0, 100}, "DCA (mum)"}; @@ -119,7 +122,7 @@ struct Alice3Multicharm { } selVals; struct : ConfigurableGroup { - std::string prefix = "selVals"; + std::string prefix = "selFlags"; Configurable applyXiMinDCAxy{"applyXiMinDCAxy", false, "Apply |DCAxy| > [0]+[1]/pT"}; Configurable applyXiMinDCAz{"applyXiMinDCAz", false, "Apply |DCAz| > [0]+[1]/pT"}; Configurable applyXiMinRadius{"applyXiMinRadius", false, "Apply min radius"}; @@ -150,51 +153,29 @@ struct Alice3Multicharm { void init(InitContext&) { - histos.add("CandidateQA/hDCAXicDaughters", "hDCAXicDaughters; DCA between Xic daughters (#mum)", kTH1D, {axisDcaDaughters}); - histos.add("CandidateQA/hDCAXiccDaughters", "hDCAXiccDaughters; DCA between Xicc daughters (#mum)", kTH1D, {axisDcaDaughters}); - histos.add("CandidateQA/hDCAxyXi", "hDCAxyXi; Xi DCAxy to PV (#mum)", kTH1D, {axisDCA}); - histos.add("CandidateQA/hDCAzXi", "hDCAzXi; Xi DCAz to PV (#mum)", kTH1D, {axisDCA}); - histos.add("CandidateQA/hDCAxyXic", "hDCAxyXic; Xic DCAxy to PV (#mum)", kTH1D, {axisDCA}); - histos.add("CandidateQA/hDCAzXic", "hDCAzXic; Xic DCAz to PV (#mum)", kTH1D, {axisDCA}); - histos.add("CandidateQA/hDCAxyXicc", "hDCAxyXicc; Xicc DCAxy to PV (#mum)", kTH1D, {axisDCA}); - histos.add("CandidateQA/hDCAzXicc", "hDCAzXicc; Xicc DCAz to PV (#mum)", kTH1D, {axisDCA}); - histos.add("CandidateQA/hDecayRadiusXic", "hDecayRadiusXic; Distance (#mum)", kTH1D, {axisRadius}); - histos.add("CandidateQA/hDecayRadiusXicc", "hDecayRadiusXicc; Distance (#mum)", kTH1D, {axisRadius}); - histos.add("CandidateQA/hDecayDistanceFromPVXic", "hDecayDistanceFromPVXic; Distance (#mum)", kTH1D, {axisDecayLength}); - histos.add("CandidateQA/hProperLengthXic", "hProperLengthXic; Distance (#mum)", kTH1D, {axisDecayLength}); - histos.add("CandidateQA/hProperLengthXicc", "hProperLengthXicc; Distance (#mum)", kTH1D, {axisDecayLength}); - histos.add("CandidateQA/hPi1cDCAxy", "hPi1cDCAxy; Pi1c DCAxy (#mum)", kTH1D, {axisDCA}); - histos.add("CandidateQA/hPi1cDCAz", "hPi1cDCAz; Pi1c DCAz (#mum)", kTH1D, {axisDCA}); - histos.add("CandidateQA/hPi2cDCAxy", "hPi2cDCAxy; Pi2c DCAxy (#mum)", kTH1D, {axisDCA}); - histos.add("CandidateQA/hPi2cDCAz", "hPi2cDCAz; Pi2c DCAz (#mum)", kTH1D, {axisDCA}); - histos.add("CandidateQA/hPiccDCAxy", "hPiccDCAxy; Picc DCAxy (#mum)", kTH1D, {axisDCA}); - histos.add("CandidateQA/hPiccDCAz", "hPiccDCAz; Picc DCAz (#mum)", kTH1D, {axisDCA}); - histos.add("CandidateQA/hPi1cPt", "hPi1cPt; Pi1c pT (Gev/#it(c))", kTH1D, {axisPt}); - histos.add("CandidateQA/hPi2cPt", "hPi2cPt; Pi2c pT (Gev/#it(c))", kTH1D, {axisPt}); - histos.add("CandidateQA/hPiccPt", "hPiccPt; Picc pT (Gev/#it(c))", kTH1D, {axisPt}); - - histos.add("SelectionQA/hDCAXicDaughters", "hDCAXicDaughters; DCA between Xic daughters (#mum)", kTH1D, {axisDcaDaughters}); - histos.add("SelectionQA/hDCAXiccDaughters", "hDCAXiccDaughters; DCA between Xicc daughters (#mum)", kTH1D, {axisDcaDaughters}); - histos.add("SelectionQA/hDCAxyXi", "hDCAxyXi; Xi DCAxy to PV (#mum)", kTH1D, {axisDCA}); - histos.add("SelectionQA/hDCAzXi", "hDCAzXi; Xi DCAz to PV (#mum)", kTH1D, {axisDCA}); - histos.add("SelectionQA/hDCAxyXic", "hDCAxyXic; Xic DCAxy to PV (#mum)", kTH1D, {axisDCA}); - histos.add("SelectionQA/hDCAzXic", "hDCAzXic; Xic DCAz to PV (#mum)", kTH1D, {axisDCA}); - histos.add("SelectionQA/hDCAxyXicc", "hDCAxyXicc; Xicc DCAxy to PV (#mum)", kTH1D, {axisDCA}); - histos.add("SelectionQA/hDCAzXicc", "hDCAzXicc; Xicc DCAz to PV (#mum)", kTH1D, {axisDCA}); - histos.add("SelectionQA/hDecayRadiusXic", "hDecayRadiusXic; Distance (#mum)", kTH1D, {axisRadius}); - histos.add("SelectionQA/hDecayRadiusXicc", "hDecayRadiusXicc; Distance (#mum)", kTH1D, {axisRadius}); - histos.add("SelectionQA/hDecayDistanceFromPVXic", "hDecayDistanceFromPVXic; Distance (#mum)", kTH1D, {axisDecayLength}); - histos.add("SelectionQA/hProperLengthXic", "hProperLengthXic; Distance (#mum)", kTH1D, {axisDecayLength}); - histos.add("SelectionQA/hProperLengthXicc", "hProperLengthXicc; Distance (#mum)", kTH1D, {axisDecayLength}); - histos.add("SelectionQA/hPi1cDCAxy", "hPi1cDCAxy; Pi1c DCAxy (#mum)", kTH1D, {axisDCA}); - histos.add("SelectionQA/hPi1cDCAz", "hPi1cDCAz; Pi1c DCAz (#mum)", kTH1D, {axisDCA}); - histos.add("SelectionQA/hPi2cDCAxy", "hPi2cDCAxy; Pi2c DCAxy (#mum)", kTH1D, {axisDCA}); - histos.add("SelectionQA/hPi2cDCAz", "hPi2cDCAz; Pi2c DCAz (#mum)", kTH1D, {axisDCA}); - histos.add("SelectionQA/hPiccDCAxy", "hPiccDCAxy; Picc DCAxy (#mum)", kTH1D, {axisDCA}); - histos.add("SelectionQA/hPiccDCAz", "hPiccDCAz; Picc DCAz (#mum)", kTH1D, {axisDCA}); - histos.add("SelectionQA/hPi1cPt", "hPi1cPt; Pi1c pT (Gev/#it(c))", kTH1D, {axisPt}); - histos.add("SelectionQA/hPi2cPt", "hPi2cPt; Pi2c pT (Gev/#it(c))", kTH1D, {axisPt}); - histos.add("SelectionQA/hPiccPt", "hPiccPt; Picc pT (Gev/#it(c))", kTH1D, {axisPt}); + histos.add("BeforeSel/hDCAXicDaughters", "hDCAXicDaughters; DCA between Xic daughters (#mum)", kTH1D, {axisDcaDaughters}); + histos.add("BeforeSel/hDCAXiccDaughters", "hDCAXiccDaughters; DCA between Xicc daughters (#mum)", kTH1D, {axisDcaDaughters}); + histos.add("BeforeSel/hDCAxyXi", "hDCAxyXi; Xi DCAxy to PV (#mum)", kTH1D, {axisDCA}); + histos.add("BeforeSel/hDCAzXi", "hDCAzXi; Xi DCAz to PV (#mum)", kTH1D, {axisDCA}); + histos.add("BeforeSel/hDCAxyXic", "hDCAxyXic; Xic DCAxy to PV (#mum)", kTH1D, {axisDCA}); + histos.add("BeforeSel/hDCAzXic", "hDCAzXic; Xic DCAz to PV (#mum)", kTH1D, {axisDCA}); + histos.add("BeforeSel/hDCAxyXicc", "hDCAxyXicc; Xicc DCAxy to PV (#mum)", kTH1D, {axisDCA}); + histos.add("BeforeSel/hDCAzXicc", "hDCAzXicc; Xicc DCAz to PV (#mum)", kTH1D, {axisDCA}); + histos.add("BeforeSel/hDecayRadiusXic", "hDecayRadiusXic; Distance (#mum)", kTH1D, {axisRadius}); + histos.add("BeforeSel/hDecayRadiusXicc", "hDecayRadiusXicc; Distance (#mum)", kTH1D, {axisRadius}); + histos.add("BeforeSel/hDecayDistanceFromPVXic", "hDecayDistanceFromPVXic; Distance (#mum)", kTH1D, {axisDecayLength}); + histos.add("BeforeSel/hProperLengthXic", "hProperLengthXic; Distance (#mum)", kTH1D, {axisDecayLength}); + histos.add("BeforeSel/hProperLengthXicc", "hProperLengthXicc; Distance (#mum)", kTH1D, {axisDecayLength}); + histos.add("BeforeSel/hPi1cDCAxy", "hPi1cDCAxy; Pi1c DCAxy (#mum)", kTH1D, {axisDCA}); + histos.add("BeforeSel/hPi1cDCAz", "hPi1cDCAz; Pi1c DCAz (#mum)", kTH1D, {axisDCA}); + histos.add("BeforeSel/hPi2cDCAxy", "hPi2cDCAxy; Pi2c DCAxy (#mum)", kTH1D, {axisDCA}); + histos.add("BeforeSel/hPi2cDCAz", "hPi2cDCAz; Pi2c DCAz (#mum)", kTH1D, {axisDCA}); + histos.add("BeforeSel/hPiccDCAxy", "hPiccDCAxy; Picc DCAxy (#mum)", kTH1D, {axisDCA}); + histos.add("BeforeSel/hPiccDCAz", "hPiccDCAz; Picc DCAz (#mum)", kTH1D, {axisDCA}); + histos.add("BeforeSel/hPi1cPt", "hPi1cPt; Pi1c pT (Gev/#it(c))", kTH1D, {axisPt}); + histos.add("BeforeSel/hPi2cPt", "hPi2cPt; Pi2c pT (Gev/#it(c))", kTH1D, {axisPt}); + histos.add("BeforeSel/hPiccPt", "hPiccPt; Picc pT (Gev/#it(c))", kTH1D, {axisPt}); + histos.addClone("BeforeSel/", "AfterSel/"); auto hMCharmBuilding = histos.add("hMCharmBuilding", "hMCharmBuilding", kTH1D, {{22, -0.5, 21.5}}); hMCharmBuilding->GetXaxis()->SetBinLabel(1, "nTotalCandidates"); @@ -206,10 +187,10 @@ struct Alice3Multicharm { hMCharmBuilding->GetXaxis()->SetBinLabel(7, "pi1cMinDCAz"); hMCharmBuilding->GetXaxis()->SetBinLabel(8, "pi2cMinDCAxy"); hMCharmBuilding->GetXaxis()->SetBinLabel(9, "pi2cMinDCAz"); - hMCharmBuilding->GetXaxis()->SetBinLabel(10, "piccMinConstDCAxy"); - hMCharmBuilding->GetXaxis()->SetBinLabel(11, "piccMinConstDCAz"); - hMCharmBuilding->GetXaxis()->SetBinLabel(12, "xicMinConstDCAxy"); - hMCharmBuilding->GetXaxis()->SetBinLabel(13, "xicMinConstDCAz"); + hMCharmBuilding->GetXaxis()->SetBinLabel(10, "piccMinDCAxy"); + hMCharmBuilding->GetXaxis()->SetBinLabel(11, "piccMinDCAz"); + hMCharmBuilding->GetXaxis()->SetBinLabel(12, "xicMinDCAxy"); + hMCharmBuilding->GetXaxis()->SetBinLabel(13, "xicMinDCAz"); hMCharmBuilding->GetXaxis()->SetBinLabel(14, "xiccMaxDCAxy"); hMCharmBuilding->GetXaxis()->SetBinLabel(15, "xiccMaxDCAz"); hMCharmBuilding->GetXaxis()->SetBinLabel(16, "xicMinRadius"); @@ -227,90 +208,88 @@ struct Alice3Multicharm { histos.add("h3dXicc", "h3dXicc; Xicc pT (GeV/#it(c)); Xicc #eta; Xicc mass (GeV/#it(c)^{2})", kTH3D, {axisPt, axisEta, axisXiccMass}); histos.add("hConfigId", "hConfigId", kTH1D, {{11, -0.5, 10.5}}); - if (bdt.enableML) { - if (bdt.loadModelsFromCCDB) { - ccdbApi.init(bdt.ccdbUrl); - LOG(info) << "Fetching model for timestamp: " << bdt.timestampCCDB.value; - bool retrieveSuccessMCharm = ccdbApi.retrieveBlob(bdt.pathCCDB.value, ".", metadata, bdt.timestampCCDB.value, false, bdt.localPath.value); - - if (retrieveSuccessMCharm) { - bdtMCharm.initModel(bdt.localPath.value, bdt.enableOptimizations.value); - } else { - LOG(fatal) << "Error encountered while fetching/loading the MCharm model from CCDB! Maybe the model doesn't exist yet for this runnumber/timestamp?"; - } + if (ml.enableBDT) { + mlResponse.configure(ml.ptBinEdges, ml.scoreCuts, ml.cutDir, multi_charm_ml::NClasses); + if (ml.loadModelsFromCCDB) { + ccdbApi.init(ml.ccdbUrl); + mlResponse.setModelPathsCCDB(ml.onnxFileNames, ccdbApi, ml.modelPathsCCDB, ml.timestampCCDB); } else { - bdtMCharm.initModel(bdt.localPath.value, bdt.enableOptimizations.value); + mlResponse.setModelPathsLocal(ml.onnxFileNames); } - histos.add("BDT/hBDTScoreSignalFine", "hBDTScoreSignalFine", kTH1D, {axisBDTScoreFine}); - histos.add("BDT/hBDTScoreSignal", "hBDTScoreSignal", kTH1D, {axisBDTScore}); - histos.add("BDT/hBDTScoreVsXiccMassSignal", "hBDTScoreVsXiccMassSignal", kTH2D, {axisXiccMass, axisBDTScore}); - histos.add("BDT/hBDTScoreVsXiccPtSignal", "hBDTScoreVsXiccPtSignal", kTH2D, {axisPt, axisBDTScore}); - histos.add("BDT/h3dBDTScoreSignal", "h3dBDTScoreSignal", kTH3D, {axisPt, axisXiccMass, axisBDTScore}); - histos.add("BDT/hBDTScoreBackgroundFine", "hBDTScoreBackgroundFine", kTH1D, {axisBDTScoreFine}); - histos.add("BDT/hBDTScoreBackground", "hBDTScoreBackground", kTH1D, {axisBDTScore}); - histos.add("BDT/hBDTScoreVsXiccMassBackground", "hBDTScoreVsXiccMassBackground", kTH2D, {axisXiccMass, axisBDTScore}); - histos.add("BDT/hBDTScoreVsXiccPtBackground", "hBDTScoreVsXiccPtBackground", kTH2D, {axisPt, axisBDTScore}); - histos.add("BDT/h3dBDTScoreBackground", "h3dBDTScoreBackground", kTH3D, {axisPt, axisXiccMass, axisBDTScore}); - - histos.add("BDT/hDCAXicDaughters", "hDCAXicDaughters", kTH2D, {{axisBDTScore, axisDcaDaughters}}); - histos.add("BDT/hDCAXiccDaughters", "hDCAXiccDaughters", kTH2D, {{axisBDTScore, axisDcaDaughters}}); - histos.add("BDT/hDCAxyXi", "hDCAxyXi", kTH2D, {{axisBDTScore, axisDCA}}); - histos.add("BDT/hDCAzXi", "hDCAzXi", kTH2D, {{axisBDTScore, axisDCA}}); - histos.add("BDT/hDCAxyXic", "hDCAxyXic", kTH2D, {{axisBDTScore, axisDCA}}); - histos.add("BDT/hDCAzXic", "hDCAzXic", kTH2D, {{axisBDTScore, axisDCA}}); - histos.add("BDT/hDCAxyXicc", "hDCAxyXicc", kTH2D, {{axisBDTScore, axisDCA}}); - histos.add("BDT/hDCAzXicc", "hDCAzXicc", kTH2D, {{axisBDTScore, axisDCA}}); - histos.add("BDT/hDecayRadiusXic", "hDecayRadiusXic", kTH2D, {{axisBDTScore, axisRadius}}); - histos.add("BDT/hDecayRadiusXicc", "hDecayRadiusXicc", kTH2D, {{axisBDTScore, axisRadius}}); - histos.add("BDT/hDecayDistanceFromPVXic", "hDecayDistanceFromPVXic", kTH2D, {{axisBDTScore, axisDecayLength}}); - histos.add("BDT/hProperLengthXic", "hProperLengthXic", kTH2D, {{axisBDTScore, axisDecayLength}}); - histos.add("BDT/hProperLengthXicc", "hProperLengthXicc", kTH2D, {{axisBDTScore, axisDecayLength}}); - histos.add("BDT/hPi1cDCAxy", "hPi1cDCAxy", kTH2D, {{axisBDTScore, axisDCA}}); - histos.add("BDT/hPi1cDCAz", "hPi1cDCAz", kTH2D, {{axisBDTScore, axisDCA}}); - histos.add("BDT/hPi2cDCAxy", "hPi2cDCAxy", kTH2D, {{axisBDTScore, axisDCA}}); - histos.add("BDT/hPi2cDCAz", "hPi2cDCAz", kTH2D, {{axisBDTScore, axisDCA}}); - histos.add("BDT/hPiccDCAxy", "hPiccDCAxy", kTH2D, {{axisBDTScore, axisDCA}}); - histos.add("BDT/hPiccDCAz", "hPiccDCAz", kTH2D, {{axisBDTScore, axisDCA}}); - histos.add("BDT/hPi1cPt", "hPi1cPt", kTH2D, {{axisBDTScore, axisPt}}); - histos.add("BDT/hPi2cPt", "hPi2cPt", kTH2D, {{axisBDTScore, axisPt}}); - histos.add("BDT/hPiccPt", "hPiccPt", kTH2D, {{axisBDTScore, axisPt}}); + mlResponse.cacheInputFeaturesIndices(ml.namesInputFeatures); + mlResponse.init(); + + histos.add("BDT/BeforeSel/hBDTScoreSignalFine", "hBDTScoreSignalFine", kTH1D, {axisBDTScoreFine}); + histos.add("BDT/BeforeSel/hBDTScoreSignal", "hBDTScoreSignal", kTH1D, {axisBDTScore}); + histos.add("BDT/BeforeSel/hBDTScoreVsXiccMassSignal", "hBDTScoreVsXiccMassSignal", kTH2D, {axisXiccMass, axisBDTScore}); + histos.add("BDT/BeforeSel/hBDTScoreVsXiccPtSignal", "hBDTScoreVsXiccPtSignal", kTH2D, {axisPt, axisBDTScore}); + histos.add("BDT/BeforeSel/h3dBDTScoreSignal", "h3dBDTScoreSignal", kTH3D, {axisPt, axisXiccMass, axisBDTScore}); + histos.add("BDT/BeforeSel/hBDTScoreBackgroundFine", "hBDTScoreBackgroundFine", kTH1D, {axisBDTScoreFine}); + histos.add("BDT/BeforeSel/hBDTScoreBackground", "hBDTScoreBackground", kTH1D, {axisBDTScore}); + histos.add("BDT/BeforeSel/hBDTScoreVsXiccMassBackground", "hBDTScoreVsXiccMassBackground", kTH2D, {axisXiccMass, axisBDTScore}); + histos.add("BDT/BeforeSel/hBDTScoreVsXiccPtBackground", "hBDTScoreVsXiccPtBackground", kTH2D, {axisPt, axisBDTScore}); + histos.add("BDT/BeforeSel/h3dBDTScoreBackground", "h3dBDTScoreBackground", kTH3D, {axisPt, axisXiccMass, axisBDTScore}); + histos.add("BDT/BeforeSel/hDCAXicDaughters", "hDCAXicDaughters", kTH2D, {{axisBDTScore, axisDcaDaughters}}); + histos.add("BDT/BeforeSel/hDCAXiccDaughters", "hDCAXiccDaughters", kTH2D, {{axisBDTScore, axisDcaDaughters}}); + histos.add("BDT/BeforeSel/hDCAxyXi", "hDCAxyXi", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("BDT/BeforeSel/hDCAzXi", "hDCAzXi", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("BDT/BeforeSel/hDCAxyXic", "hDCAxyXic", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("BDT/BeforeSel/hDCAzXic", "hDCAzXic", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("BDT/BeforeSel/hDCAxyXicc", "hDCAxyXicc", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("BDT/BeforeSel/hDCAzXicc", "hDCAzXicc", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("BDT/BeforeSel/hDecayRadiusXic", "hDecayRadiusXic", kTH2D, {{axisBDTScore, axisRadius}}); + histos.add("BDT/BeforeSel/hDecayRadiusXicc", "hDecayRadiusXicc", kTH2D, {{axisBDTScore, axisRadius}}); + histos.add("BDT/BeforeSel/hDecayDistanceFromPVXic", "hDecayDistanceFromPVXic", kTH2D, {{axisBDTScore, axisDecayLength}}); + histos.add("BDT/BeforeSel/hProperLengthXic", "hProperLengthXic", kTH2D, {{axisBDTScore, axisDecayLength}}); + histos.add("BDT/BeforeSel/hProperLengthXicc", "hProperLengthXicc", kTH2D, {{axisBDTScore, axisDecayLength}}); + histos.add("BDT/BeforeSel/hPi1cDCAxy", "hPi1cDCAxy", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("BDT/BeforeSel/hPi1cDCAz", "hPi1cDCAz", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("BDT/BeforeSel/hPi2cDCAxy", "hPi2cDCAxy", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("BDT/BeforeSel/hPi2cDCAz", "hPi2cDCAz", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("BDT/BeforeSel/hPiccDCAxy", "hPiccDCAxy", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("BDT/BeforeSel/hPiccDCAz", "hPiccDCAz", kTH2D, {{axisBDTScore, axisDCA}}); + histos.add("BDT/BeforeSel/hPi1cPt", "hPi1cPt", kTH2D, {{axisBDTScore, axisPt}}); + histos.add("BDT/BeforeSel/hPi2cPt", "hPi2cPt", kTH2D, {{axisBDTScore, axisPt}}); + histos.add("BDT/BeforeSel/hPiccPt", "hPiccPt", kTH2D, {{axisBDTScore, axisPt}}); + histos.addClone("BDT/BeforeSel/", "BDT/AfterSel/"); } histos.print(); } - template - void genericProcessXicc(TMCharmCands const& xiccCands) + void processXicc(soa::Filtered const& xiccCands) { for (const auto& xiccCand : xiccCands) { - const int icfg = xiccCand.lutConfigId(); - histos.fill(HIST("hConfigId"), icfg); - - histos.fill(HIST("CandidateQA/hDCAXicDaughters"), xiccCand.xicDauDCA() * ToMicrons); - histos.fill(HIST("CandidateQA/hDCAXiccDaughters"), xiccCand.xiccDauDCA() * ToMicrons); - histos.fill(HIST("CandidateQA/hDCAxyXi"), std::fabs(xiccCand.xiDCAxy() * ToMicrons)); - histos.fill(HIST("CandidateQA/hDCAzXi"), std::fabs(xiccCand.xiDCAz() * ToMicrons)); - histos.fill(HIST("CandidateQA/hDCAxyXic"), std::fabs(xiccCand.xicDCAxy() * ToMicrons)); - histos.fill(HIST("CandidateQA/hDCAzXic"), std::fabs(xiccCand.xicDCAz() * ToMicrons)); - histos.fill(HIST("CandidateQA/hDCAxyXicc"), std::fabs(xiccCand.xiccDCAxy() * ToMicrons)); - histos.fill(HIST("CandidateQA/hDCAzXicc"), std::fabs(xiccCand.xiccDCAz() * ToMicrons)); - histos.fill(HIST("CandidateQA/hDecayRadiusXic"), xiccCand.xicDecayRadius2D() * ToMicrons); - histos.fill(HIST("CandidateQA/hDecayRadiusXicc"), xiccCand.xiccDecayRadius2D() * ToMicrons); - histos.fill(HIST("CandidateQA/hDecayDistanceFromPVXic"), xiccCand.xicDistanceFromPV() * ToMicrons); - histos.fill(HIST("CandidateQA/hProperLengthXic"), xiccCand.xicProperLength() * ToMicrons); - histos.fill(HIST("CandidateQA/hProperLengthXicc"), xiccCand.xiccProperLength() * ToMicrons); - histos.fill(HIST("CandidateQA/hPi1cDCAxy"), xiccCand.pi1cDCAxy() * ToMicrons); - histos.fill(HIST("CandidateQA/hPi1cDCAz"), xiccCand.pi1cDCAz() * ToMicrons); - histos.fill(HIST("CandidateQA/hPi2cDCAxy"), xiccCand.pi2cDCAxy() * ToMicrons); - histos.fill(HIST("CandidateQA/hPi2cDCAz"), xiccCand.pi2cDCAz() * ToMicrons); - histos.fill(HIST("CandidateQA/hPiccDCAxy"), xiccCand.piccDCAxy() * ToMicrons); - histos.fill(HIST("CandidateQA/hPiccDCAz"), xiccCand.piccDCAz() * ToMicrons); - histos.fill(HIST("CandidateQA/hPi1cPt"), xiccCand.pi1cPt()); - histos.fill(HIST("CandidateQA/hPi2cPt"), xiccCand.pi2cPt()); - histos.fill(HIST("CandidateQA/hPiccPt"), xiccCand.piccPt()); - - if (bdt.enableML) { + float bdtPredictedBackground = -999.f; + float bdtPredictedSignal = -999.f; + + histos.fill(HIST("hConfigId"), xiccCand.lutConfigId()); + histos.fill(HIST("BeforeSel/hDCAXicDaughters"), xiccCand.xicDauDCA() * ToMicrons); + histos.fill(HIST("BeforeSel/hDCAXiccDaughters"), xiccCand.xiccDauDCA() * ToMicrons); + histos.fill(HIST("BeforeSel/hDCAxyXi"), std::fabs(xiccCand.xiDCAxy() * ToMicrons)); + histos.fill(HIST("BeforeSel/hDCAzXi"), std::fabs(xiccCand.xiDCAz() * ToMicrons)); + histos.fill(HIST("BeforeSel/hDCAxyXic"), std::fabs(xiccCand.xicDCAxy() * ToMicrons)); + histos.fill(HIST("BeforeSel/hDCAzXic"), std::fabs(xiccCand.xicDCAz() * ToMicrons)); + histos.fill(HIST("BeforeSel/hDCAxyXicc"), std::fabs(xiccCand.xiccDCAxy() * ToMicrons)); + histos.fill(HIST("BeforeSel/hDCAzXicc"), std::fabs(xiccCand.xiccDCAz() * ToMicrons)); + histos.fill(HIST("BeforeSel/hDecayRadiusXic"), xiccCand.xicDecayRadius2D() * ToMicrons); + histos.fill(HIST("BeforeSel/hDecayRadiusXicc"), xiccCand.xiccDecayRadius2D() * ToMicrons); + histos.fill(HIST("BeforeSel/hDecayDistanceFromPVXic"), xiccCand.xicDistanceFromPV() * ToMicrons); + histos.fill(HIST("BeforeSel/hProperLengthXic"), xiccCand.xicProperLength() * ToMicrons); + histos.fill(HIST("BeforeSel/hProperLengthXicc"), xiccCand.xiccProperLength() * ToMicrons); + histos.fill(HIST("BeforeSel/hPi1cDCAxy"), xiccCand.pi1cDCAxy() * ToMicrons); + histos.fill(HIST("BeforeSel/hPi1cDCAz"), xiccCand.pi1cDCAz() * ToMicrons); + histos.fill(HIST("BeforeSel/hPi2cDCAxy"), xiccCand.pi2cDCAxy() * ToMicrons); + histos.fill(HIST("BeforeSel/hPi2cDCAz"), xiccCand.pi2cDCAz() * ToMicrons); + histos.fill(HIST("BeforeSel/hPiccDCAxy"), xiccCand.piccDCAxy() * ToMicrons); + histos.fill(HIST("BeforeSel/hPiccDCAz"), xiccCand.piccDCAz() * ToMicrons); + histos.fill(HIST("BeforeSel/hPi1cPt"), xiccCand.pi1cPt()); + histos.fill(HIST("BeforeSel/hPi2cPt"), xiccCand.pi2cPt()); + histos.fill(HIST("BeforeSel/hPiccPt"), xiccCand.piccPt()); + + if (ml.enableBDT) { + std::vector outputScore; std::vector inputFeatures{ xiccCand.xicDauDCA(), xiccCand.xiccDauDCA(), @@ -332,43 +311,42 @@ struct Alice3Multicharm { xiccCand.xicDistanceFromPV(), xiccCand.xiccProperLength()}; - float* probabilityMCharm = bdtMCharm.evalModel(inputFeatures); - const float bdtPredictedBackground = probabilityMCharm[0]; - const float bdtPredictedSignal = probabilityMCharm[1]; - - histos.fill(HIST("BDT/hBDTScoreSignal"), bdtPredictedSignal); - histos.fill(HIST("BDT/hBDTScoreSignalFine"), bdtPredictedSignal); - histos.fill(HIST("BDT/hBDTScoreVsXiccMassSignal"), xiccCand.xiccMass(), bdtPredictedSignal); - histos.fill(HIST("BDT/hBDTScoreVsXiccPtSignal"), xiccCand.xiccPt(), bdtPredictedSignal); - histos.fill(HIST("BDT/h3dBDTScoreSignal"), xiccCand.xiccPt(), xiccCand.xiccMass(), bdtPredictedSignal); - histos.fill(HIST("BDT/hBDTScoreBackground"), bdtPredictedBackground); - histos.fill(HIST("BDT/hBDTScoreBackgroundFine"), bdtPredictedBackground); - histos.fill(HIST("BDT/hBDTScoreVsXiccMassBackground"), xiccCand.xiccMass(), bdtPredictedBackground); - histos.fill(HIST("BDT/hBDTScoreVsXiccPtBackground"), xiccCand.xiccPt(), bdtPredictedBackground); - histos.fill(HIST("BDT/h3dBDTScoreBackground"), xiccCand.xiccPt(), xiccCand.xiccMass(), bdtPredictedBackground); - - histos.fill(HIST("BDT/hDCAXicDaughters"), bdtPredictedSignal, xiccCand.xicDauDCA() * ToMicrons); - histos.fill(HIST("BDT/hDCAXiccDaughters"), bdtPredictedSignal, xiccCand.xiccDauDCA() * ToMicrons); - histos.fill(HIST("BDT/hDCAxyXi"), bdtPredictedSignal, std::fabs(xiccCand.xiDCAxy() * ToMicrons)); - histos.fill(HIST("BDT/hDCAzXi"), bdtPredictedSignal, std::fabs(xiccCand.xiDCAz() * ToMicrons)); - histos.fill(HIST("BDT/hDCAxyXic"), bdtPredictedSignal, std::fabs(xiccCand.xicDCAxy() * ToMicrons)); - histos.fill(HIST("BDT/hDCAzXic"), bdtPredictedSignal, std::fabs(xiccCand.xicDCAz() * ToMicrons)); - histos.fill(HIST("BDT/hDCAxyXicc"), bdtPredictedSignal, std::fabs(xiccCand.xiccDCAxy() * ToMicrons)); - histos.fill(HIST("BDT/hDCAzXicc"), bdtPredictedSignal, std::fabs(xiccCand.xiccDCAz() * ToMicrons)); - histos.fill(HIST("BDT/hDecayRadiusXic"), bdtPredictedSignal, xiccCand.xicDecayRadius2D() * ToMicrons); - histos.fill(HIST("BDT/hDecayRadiusXicc"), bdtPredictedSignal, xiccCand.xiccDecayRadius2D() * ToMicrons); - histos.fill(HIST("BDT/hDecayDistanceFromPVXic"), bdtPredictedSignal, xiccCand.xicDistanceFromPV() * ToMicrons); - histos.fill(HIST("BDT/hProperLengthXic"), bdtPredictedSignal, xiccCand.xicProperLength() * ToMicrons); - histos.fill(HIST("BDT/hProperLengthXicc"), bdtPredictedSignal, xiccCand.xiccProperLength() * ToMicrons); - histos.fill(HIST("BDT/hPi1cDCAxy"), bdtPredictedSignal, xiccCand.pi1cDCAxy() * ToMicrons); - histos.fill(HIST("BDT/hPi1cDCAz"), bdtPredictedSignal, xiccCand.pi1cDCAz() * ToMicrons); - histos.fill(HIST("BDT/hPi2cDCAxy"), bdtPredictedSignal, xiccCand.pi2cDCAxy() * ToMicrons); - histos.fill(HIST("BDT/hPi2cDCAz"), bdtPredictedSignal, xiccCand.pi2cDCAz() * ToMicrons); - histos.fill(HIST("BDT/hPiccDCAxy"), bdtPredictedSignal, xiccCand.piccDCAxy() * ToMicrons); - histos.fill(HIST("BDT/hPiccDCAz"), bdtPredictedSignal, xiccCand.piccDCAz() * ToMicrons); - histos.fill(HIST("BDT/hPi1cPt"), bdtPredictedSignal, xiccCand.pi1cPt()); - histos.fill(HIST("BDT/hPi2cPt"), bdtPredictedSignal, xiccCand.pi2cPt()); - histos.fill(HIST("BDT/hPiccPt"), bdtPredictedSignal, xiccCand.piccPt()); + mlResponse.isSelectedMl(inputFeatures, xiccCand.xiccPt(), outputScore); + bdtPredictedBackground = static_cast(outputScore[0]); + bdtPredictedSignal = static_cast(outputScore[1]); + + histos.fill(HIST("BDT/BeforeSel/hBDTScoreSignal"), bdtPredictedSignal); + histos.fill(HIST("BDT/BeforeSel/hBDTScoreSignalFine"), bdtPredictedSignal); + histos.fill(HIST("BDT/BeforeSel/hBDTScoreVsXiccMassSignal"), xiccCand.xiccMass(), bdtPredictedSignal); + histos.fill(HIST("BDT/BeforeSel/hBDTScoreVsXiccPtSignal"), xiccCand.xiccPt(), bdtPredictedSignal); + histos.fill(HIST("BDT/BeforeSel/h3dBDTScoreSignal"), xiccCand.xiccPt(), xiccCand.xiccMass(), bdtPredictedSignal); + histos.fill(HIST("BDT/BeforeSel/hBDTScoreBackground"), bdtPredictedBackground); + histos.fill(HIST("BDT/BeforeSel/hBDTScoreBackgroundFine"), bdtPredictedBackground); + histos.fill(HIST("BDT/BeforeSel/hBDTScoreVsXiccMassBackground"), xiccCand.xiccMass(), bdtPredictedBackground); + histos.fill(HIST("BDT/BeforeSel/hBDTScoreVsXiccPtBackground"), xiccCand.xiccPt(), bdtPredictedBackground); + histos.fill(HIST("BDT/BeforeSel/h3dBDTScoreBackground"), xiccCand.xiccPt(), xiccCand.xiccMass(), bdtPredictedBackground); + histos.fill(HIST("BDT/BeforeSel/hDCAXicDaughters"), bdtPredictedSignal, xiccCand.xicDauDCA() * ToMicrons); + histos.fill(HIST("BDT/BeforeSel/hDCAXiccDaughters"), bdtPredictedSignal, xiccCand.xiccDauDCA() * ToMicrons); + histos.fill(HIST("BDT/BeforeSel/hDCAxyXi"), bdtPredictedSignal, std::fabs(xiccCand.xiDCAxy() * ToMicrons)); + histos.fill(HIST("BDT/BeforeSel/hDCAzXi"), bdtPredictedSignal, std::fabs(xiccCand.xiDCAz() * ToMicrons)); + histos.fill(HIST("BDT/BeforeSel/hDCAxyXic"), bdtPredictedSignal, std::fabs(xiccCand.xicDCAxy() * ToMicrons)); + histos.fill(HIST("BDT/BeforeSel/hDCAzXic"), bdtPredictedSignal, std::fabs(xiccCand.xicDCAz() * ToMicrons)); + histos.fill(HIST("BDT/BeforeSel/hDCAxyXicc"), bdtPredictedSignal, std::fabs(xiccCand.xiccDCAxy() * ToMicrons)); + histos.fill(HIST("BDT/BeforeSel/hDCAzXicc"), bdtPredictedSignal, std::fabs(xiccCand.xiccDCAz() * ToMicrons)); + histos.fill(HIST("BDT/BeforeSel/hDecayRadiusXic"), bdtPredictedSignal, xiccCand.xicDecayRadius2D() * ToMicrons); + histos.fill(HIST("BDT/BeforeSel/hDecayRadiusXicc"), bdtPredictedSignal, xiccCand.xiccDecayRadius2D() * ToMicrons); + histos.fill(HIST("BDT/BeforeSel/hDecayDistanceFromPVXic"), bdtPredictedSignal, xiccCand.xicDistanceFromPV() * ToMicrons); + histos.fill(HIST("BDT/BeforeSel/hProperLengthXic"), bdtPredictedSignal, xiccCand.xicProperLength() * ToMicrons); + histos.fill(HIST("BDT/BeforeSel/hProperLengthXicc"), bdtPredictedSignal, xiccCand.xiccProperLength() * ToMicrons); + histos.fill(HIST("BDT/BeforeSel/hPi1cDCAxy"), bdtPredictedSignal, xiccCand.pi1cDCAxy() * ToMicrons); + histos.fill(HIST("BDT/BeforeSel/hPi1cDCAz"), bdtPredictedSignal, xiccCand.pi1cDCAz() * ToMicrons); + histos.fill(HIST("BDT/BeforeSel/hPi2cDCAxy"), bdtPredictedSignal, xiccCand.pi2cDCAxy() * ToMicrons); + histos.fill(HIST("BDT/BeforeSel/hPi2cDCAz"), bdtPredictedSignal, xiccCand.pi2cDCAz() * ToMicrons); + histos.fill(HIST("BDT/BeforeSel/hPiccDCAxy"), bdtPredictedSignal, xiccCand.piccDCAxy() * ToMicrons); + histos.fill(HIST("BDT/BeforeSel/hPiccDCAz"), bdtPredictedSignal, xiccCand.piccDCAz() * ToMicrons); + histos.fill(HIST("BDT/BeforeSel/hPi1cPt"), bdtPredictedSignal, xiccCand.pi1cPt()); + histos.fill(HIST("BDT/BeforeSel/hPi2cPt"), bdtPredictedSignal, xiccCand.pi2cPt()); + histos.fill(HIST("BDT/BeforeSel/hPiccPt"), bdtPredictedSignal, xiccCand.piccPt()); } histos.fill(HIST("hMCharmBuilding"), 0); @@ -477,46 +455,74 @@ struct Alice3Multicharm { } histos.fill(HIST("hMCharmBuilding"), 21); - histos.fill(HIST("SelectionQA/hDCAXicDaughters"), xiccCand.xicDauDCA() * ToMicrons); - histos.fill(HIST("SelectionQA/hDCAXiccDaughters"), xiccCand.xiccDauDCA() * ToMicrons); - histos.fill(HIST("SelectionQA/hDCAxyXi"), std::fabs(xiccCand.xiDCAxy() * ToMicrons)); - histos.fill(HIST("SelectionQA/hDCAzXi"), std::fabs(xiccCand.xiDCAz() * ToMicrons)); - histos.fill(HIST("SelectionQA/hDCAxyXic"), std::fabs(xiccCand.xicDCAxy() * ToMicrons)); - histos.fill(HIST("SelectionQA/hDCAzXic"), std::fabs(xiccCand.xicDCAz() * ToMicrons)); - histos.fill(HIST("SelectionQA/hDCAxyXicc"), std::fabs(xiccCand.xiccDCAxy() * ToMicrons)); - histos.fill(HIST("SelectionQA/hDCAzXicc"), std::fabs(xiccCand.xiccDCAz() * ToMicrons)); - histos.fill(HIST("SelectionQA/hDecayRadiusXic"), xiccCand.xicDecayRadius2D() * ToMicrons); - histos.fill(HIST("SelectionQA/hDecayRadiusXicc"), xiccCand.xiccDecayRadius2D() * ToMicrons); - histos.fill(HIST("SelectionQA/hDecayDistanceFromPVXic"), xiccCand.xicDistanceFromPV() * ToMicrons); - histos.fill(HIST("SelectionQA/hProperLengthXic"), xiccCand.xicProperLength() * ToMicrons); - histos.fill(HIST("SelectionQA/hProperLengthXicc"), xiccCand.xiccProperLength() * ToMicrons); - histos.fill(HIST("SelectionQA/hPi1cDCAxy"), xiccCand.pi1cDCAxy() * ToMicrons); - histos.fill(HIST("SelectionQA/hPi1cDCAz"), xiccCand.pi1cDCAz() * ToMicrons); - histos.fill(HIST("SelectionQA/hPi2cDCAxy"), xiccCand.pi2cDCAxy() * ToMicrons); - histos.fill(HIST("SelectionQA/hPi2cDCAz"), xiccCand.pi2cDCAz() * ToMicrons); - histos.fill(HIST("SelectionQA/hPiccDCAxy"), xiccCand.piccDCAxy() * ToMicrons); - histos.fill(HIST("SelectionQA/hPiccDCAz"), xiccCand.piccDCAz() * ToMicrons); - histos.fill(HIST("SelectionQA/hPi1cPt"), xiccCand.pi1cPt()); - histos.fill(HIST("SelectionQA/hPi2cPt"), xiccCand.pi2cPt()); - histos.fill(HIST("SelectionQA/hPiccPt"), xiccCand.piccPt()); + histos.fill(HIST("AfterSel/hDCAXicDaughters"), xiccCand.xicDauDCA() * ToMicrons); + histos.fill(HIST("AfterSel/hDCAXiccDaughters"), xiccCand.xiccDauDCA() * ToMicrons); + histos.fill(HIST("AfterSel/hDCAxyXi"), std::fabs(xiccCand.xiDCAxy() * ToMicrons)); + histos.fill(HIST("AfterSel/hDCAzXi"), std::fabs(xiccCand.xiDCAz() * ToMicrons)); + histos.fill(HIST("AfterSel/hDCAxyXic"), std::fabs(xiccCand.xicDCAxy() * ToMicrons)); + histos.fill(HIST("AfterSel/hDCAzXic"), std::fabs(xiccCand.xicDCAz() * ToMicrons)); + histos.fill(HIST("AfterSel/hDCAxyXicc"), std::fabs(xiccCand.xiccDCAxy() * ToMicrons)); + histos.fill(HIST("AfterSel/hDCAzXicc"), std::fabs(xiccCand.xiccDCAz() * ToMicrons)); + histos.fill(HIST("AfterSel/hDecayRadiusXic"), xiccCand.xicDecayRadius2D() * ToMicrons); + histos.fill(HIST("AfterSel/hDecayRadiusXicc"), xiccCand.xiccDecayRadius2D() * ToMicrons); + histos.fill(HIST("AfterSel/hDecayDistanceFromPVXic"), xiccCand.xicDistanceFromPV() * ToMicrons); + histos.fill(HIST("AfterSel/hProperLengthXic"), xiccCand.xicProperLength() * ToMicrons); + histos.fill(HIST("AfterSel/hProperLengthXicc"), xiccCand.xiccProperLength() * ToMicrons); + histos.fill(HIST("AfterSel/hPi1cDCAxy"), xiccCand.pi1cDCAxy() * ToMicrons); + histos.fill(HIST("AfterSel/hPi1cDCAz"), xiccCand.pi1cDCAz() * ToMicrons); + histos.fill(HIST("AfterSel/hPi2cDCAxy"), xiccCand.pi2cDCAxy() * ToMicrons); + histos.fill(HIST("AfterSel/hPi2cDCAz"), xiccCand.pi2cDCAz() * ToMicrons); + histos.fill(HIST("AfterSel/hPiccDCAxy"), xiccCand.piccDCAxy() * ToMicrons); + histos.fill(HIST("AfterSel/hPiccDCAz"), xiccCand.piccDCAz() * ToMicrons); + histos.fill(HIST("AfterSel/hPi1cPt"), xiccCand.pi1cPt()); + histos.fill(HIST("AfterSel/hPi2cPt"), xiccCand.pi2cPt()); + histos.fill(HIST("AfterSel/hPiccPt"), xiccCand.piccPt()); histos.fill(HIST("hXiccMass"), xiccCand.xiccMass()); histos.fill(HIST("hXicMass"), xiccCand.xicMass()); histos.fill(HIST("hXiccPt"), xiccCand.xiccPt()); histos.fill(HIST("hXicPt"), xiccCand.xicPt()); histos.fill(HIST("h3dXicc"), xiccCand.xiccPt(), xiccCand.xiccEta(), xiccCand.xiccMass()); + if (ml.enableBDT) { + histos.fill(HIST("BDT/AfterSel/hBDTScoreSignal"), bdtPredictedSignal); + histos.fill(HIST("BDT/AfterSel/hBDTScoreSignalFine"), bdtPredictedSignal); + histos.fill(HIST("BDT/AfterSel/hBDTScoreVsXiccMassSignal"), xiccCand.xiccMass(), bdtPredictedSignal); + histos.fill(HIST("BDT/AfterSel/hBDTScoreVsXiccPtSignal"), xiccCand.xiccPt(), bdtPredictedSignal); + histos.fill(HIST("BDT/AfterSel/h3dBDTScoreSignal"), xiccCand.xiccPt(), xiccCand.xiccMass(), bdtPredictedSignal); + histos.fill(HIST("BDT/AfterSel/hBDTScoreBackground"), bdtPredictedBackground); + histos.fill(HIST("BDT/AfterSel/hBDTScoreBackgroundFine"), bdtPredictedBackground); + histos.fill(HIST("BDT/AfterSel/hBDTScoreVsXiccMassBackground"), xiccCand.xiccMass(), bdtPredictedBackground); + histos.fill(HIST("BDT/AfterSel/hBDTScoreVsXiccPtBackground"), xiccCand.xiccPt(), bdtPredictedBackground); + histos.fill(HIST("BDT/AfterSel/h3dBDTScoreBackground"), xiccCand.xiccPt(), xiccCand.xiccMass(), bdtPredictedBackground); + histos.fill(HIST("BDT/AfterSel/hDCAXicDaughters"), bdtPredictedSignal, xiccCand.xicDauDCA() * ToMicrons); + histos.fill(HIST("BDT/AfterSel/hDCAXiccDaughters"), bdtPredictedSignal, xiccCand.xiccDauDCA() * ToMicrons); + histos.fill(HIST("BDT/AfterSel/hDCAxyXi"), bdtPredictedSignal, std::fabs(xiccCand.xiDCAxy() * ToMicrons)); + histos.fill(HIST("BDT/AfterSel/hDCAzXi"), bdtPredictedSignal, std::fabs(xiccCand.xiDCAz() * ToMicrons)); + histos.fill(HIST("BDT/AfterSel/hDCAxyXic"), bdtPredictedSignal, std::fabs(xiccCand.xicDCAxy() * ToMicrons)); + histos.fill(HIST("BDT/AfterSel/hDCAzXic"), bdtPredictedSignal, std::fabs(xiccCand.xicDCAz() * ToMicrons)); + histos.fill(HIST("BDT/AfterSel/hDCAxyXicc"), bdtPredictedSignal, std::fabs(xiccCand.xiccDCAxy() * ToMicrons)); + histos.fill(HIST("BDT/AfterSel/hDCAzXicc"), bdtPredictedSignal, std::fabs(xiccCand.xiccDCAz() * ToMicrons)); + histos.fill(HIST("BDT/AfterSel/hDecayRadiusXic"), bdtPredictedSignal, xiccCand.xicDecayRadius2D() * ToMicrons); + histos.fill(HIST("BDT/AfterSel/hDecayRadiusXicc"), bdtPredictedSignal, xiccCand.xiccDecayRadius2D() * ToMicrons); + histos.fill(HIST("BDT/AfterSel/hDecayDistanceFromPVXic"), bdtPredictedSignal, xiccCand.xicDistanceFromPV() * ToMicrons); + histos.fill(HIST("BDT/AfterSel/hProperLengthXic"), bdtPredictedSignal, xiccCand.xicProperLength() * ToMicrons); + histos.fill(HIST("BDT/AfterSel/hProperLengthXicc"), bdtPredictedSignal, xiccCand.xiccProperLength() * ToMicrons); + histos.fill(HIST("BDT/AfterSel/hPi1cDCAxy"), bdtPredictedSignal, xiccCand.pi1cDCAxy() * ToMicrons); + histos.fill(HIST("BDT/AfterSel/hPi1cDCAz"), bdtPredictedSignal, xiccCand.pi1cDCAz() * ToMicrons); + histos.fill(HIST("BDT/AfterSel/hPi2cDCAxy"), bdtPredictedSignal, xiccCand.pi2cDCAxy() * ToMicrons); + histos.fill(HIST("BDT/AfterSel/hPi2cDCAz"), bdtPredictedSignal, xiccCand.pi2cDCAz() * ToMicrons); + histos.fill(HIST("BDT/AfterSel/hPiccDCAxy"), bdtPredictedSignal, xiccCand.piccDCAxy() * ToMicrons); + histos.fill(HIST("BDT/AfterSel/hPiccDCAz"), bdtPredictedSignal, xiccCand.piccDCAz() * ToMicrons); + histos.fill(HIST("BDT/AfterSel/hPi1cPt"), bdtPredictedSignal, xiccCand.pi1cPt()); + histos.fill(HIST("BDT/AfterSel/hPi2cPt"), bdtPredictedSignal, xiccCand.pi2cPt()); + histos.fill(HIST("BDT/AfterSel/hPiccPt"), bdtPredictedSignal, xiccCand.piccPt()); + } } } - void processXicc(soa::Filtered const& multiCharmTracks) - { - genericProcessXicc(multiCharmTracks); - } - PROCESS_SWITCH(Alice3Multicharm, processXicc, "find Xicc baryons", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/ALICE3/Tasks/alice3TrackingPerformance.cxx b/ALICE3/Tasks/alice3TrackingPerformance.cxx index e29a914d848..77ebd8a1e3d 100644 --- a/ALICE3/Tasks/alice3TrackingPerformance.cxx +++ b/ALICE3/Tasks/alice3TrackingPerformance.cxx @@ -78,19 +78,20 @@ struct Alice3TrackingPerformance { } const std::string tag = "_" + prefix; prefix += "/"; - particlePtDistribution[pdg] = histos.add(prefix + "particlePtDistribution" + tag, "", kTH1D, {ptAxis}); - particleEtaDistribution[pdg] = histos.add(prefix + "particleEtaDistribution" + tag, "", kTH1D, {etaAxis}); + auto histoName = [&](const std::string& name) { return Form("%s%s%s", prefix.c_str(), name.c_str(), tag.c_str()); }; + particlePtDistribution[pdg] = histos.add(histoName("particlePtDistribution"), "", kTH1D, {ptAxis}); + particleEtaDistribution[pdg] = histos.add(histoName("particleEtaDistribution"), "", kTH1D, {etaAxis}); - ptDistribution[pdg] = histos.add(prefix + "ptDistribution" + tag, "", kTH1D, {ptAxis}); - ptResolutionVsPt[pdg] = histos.add(prefix + "ptResolutionVsPt" + tag, "", kTH2D, {ptAxis, axisPtDelta}); - ptResolutionVsEta[pdg] = histos.add(prefix + "ptResolutionVsEta" + tag, "", kTProfile2D, {ptAxis, etaAxis}); - invPtResolutionVsPt[pdg] = histos.add(prefix + "invPtResolutionVsPt" + tag, "", kTH2D, {ptAxis, invPtDeltaAxis}); - invPtResolutionVsEta[pdg] = histos.add(prefix + "invPtResolutionVsEta" + tag, "", kTProfile2D, {ptAxis, etaAxis}); - dcaXyResolutionVsPt[pdg] = histos.add(prefix + "dcaXyResolutionVsPt" + tag, "", kTH2D, {ptAxis, axisDcaXy}); - dcaZResolutionVsPt[pdg] = histos.add(prefix + "dcaZResolutionVsPt" + tag, "", kTH2D, {ptAxis, axisDcaZ}); - covariancePtPtVsPt[pdg] = histos.add(prefix + "covariancePtPtVsPt" + tag, "", kTH2D, {ptAxis, axisCovariancePtPt}); - covarianceDcaXyDcaXyVsPt[pdg] = histos.add(prefix + "covarianceDcaXyDcaXyVsPt" + tag, "", kTH2D, {ptAxis, axisCovarianceDcaXyDcaXy}); - covarianceDcaZDcaZVsPt[pdg] = histos.add(prefix + "covarianceDcaZDcaZVsPt" + tag, "", kTH2D, {ptAxis, axisCovarianceDcaZDcaZ}); + ptDistribution[pdg] = histos.add(histoName("ptDistribution"), "", kTH1D, {ptAxis}); + ptResolutionVsPt[pdg] = histos.add(histoName("ptResolutionVsPt"), "", kTH2D, {ptAxis, axisPtDelta}); + ptResolutionVsEta[pdg] = histos.add(histoName("ptResolutionVsEta"), "", kTProfile2D, {ptAxis, etaAxis}); + invPtResolutionVsPt[pdg] = histos.add(histoName("invPtResolutionVsPt"), "", kTH2D, {ptAxis, invPtDeltaAxis}); + invPtResolutionVsEta[pdg] = histos.add(histoName("invPtResolutionVsEta"), "", kTProfile2D, {ptAxis, etaAxis}); + dcaXyResolutionVsPt[pdg] = histos.add(histoName("dcaXyResolutionVsPt"), "", kTH2D, {ptAxis, axisDcaXy}); + dcaZResolutionVsPt[pdg] = histos.add(histoName("dcaZResolutionVsPt"), "", kTH2D, {ptAxis, axisDcaZ}); + covariancePtPtVsPt[pdg] = histos.add(histoName("covariancePtPtVsPt"), "", kTH2D, {ptAxis, axisCovariancePtPt}); + covarianceDcaXyDcaXyVsPt[pdg] = histos.add(histoName("covarianceDcaXyDcaXyVsPt"), "", kTH2D, {ptAxis, axisCovarianceDcaXyDcaXy}); + covarianceDcaZDcaZVsPt[pdg] = histos.add(histoName("covarianceDcaZDcaZVsPt"), "", kTH2D, {ptAxis, axisCovarianceDcaZDcaZ}); } } @@ -102,10 +103,7 @@ struct Alice3TrackingPerformance { return false; } const int etaBin = particleEtaDistribution[0]->GetXaxis()->FindBin(p.eta()); - if (etaBin < 1 || etaBin > particleEtaDistribution[0]->GetXaxis()->GetNbins()) { - return false; - } - return true; + return etaBin >= 1 && etaBin <= particleEtaDistribution[0]->GetXaxis()->GetNbins(); }; for (const auto& mcParticle : mcParticles) { @@ -115,7 +113,7 @@ struct Alice3TrackingPerformance { } particlePtDistribution[0]->Fill(mcParticle.pt()); particleEtaDistribution[0]->Fill(mcParticle.eta()); - if (particlePtDistribution.find(mcParticle.pdgCode()) == particlePtDistribution.end()) { + if (!particlePtDistribution.contains(mcParticle.pdgCode())) { continue; } particlePtDistribution[mcParticle.pdgCode()]->Fill(mcParticle.pt()); @@ -148,7 +146,7 @@ struct Alice3TrackingPerformance { if (!isParticleSelected(mcParticle)) { continue; } - if (ptResolutionVsPt.find(mcParticle.pdgCode()) == ptResolutionVsPt.end()) { + if (!ptResolutionVsPt.contains(mcParticle.pdgCode())) { continue; } fillResolutionHistograms(mcParticle.pdgCode()); diff --git a/CMakeLists.txt b/CMakeLists.txt index df09be9d27e..a61cc2f123b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,8 +24,46 @@ cmake_policy(SET CMP0144 NEW) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) set_property(GLOBAL PROPERTY REPORT_UNDEFINED_PROPERTIES) +# How much memory this build may actually use, in MiB. +# +# cmake_host_system_information reads the HOST, which is wrong under a container +# memory limit: there is no lxcfs in the CI images, so on a 251 GiB builder +# capped at 50 GiB it reported 251 GiB and the pool below never bound. The +# result was an OOM-killed build that looked like a compiler crash: +# +# c++: fatal error: Killed signal terminated program cc1plus +# +# So prefer the cgroup limit when there is one. cgroup v2 first, then v1; both +# report bytes, and both say "no limit" with a sentinel ("max", or a number so +# large it is really 2^63 rounded down) rather than by being absent. cmake_host_system_information(RESULT _totalmem QUERY TOTAL_PHYSICAL_MEMORY) -math(EXPR _total_analysis_jobs "(${_totalmem}-2048)/2048") +foreach(_cg /sys/fs/cgroup/memory.max /sys/fs/cgroup/memory/memory.limit_in_bytes) + if(EXISTS ${_cg}) + file(READ ${_cg} _cglimit) + string(STRIP "${_cglimit}" _cglimit) + if(_cglimit MATCHES "^[0-9]+$") + math(EXPR _cgmib "${_cglimit}/1048576") + # Anything at or above the host's own memory is "unlimited" expressed as a + # number, not a smaller budget. + if(_cgmib GREATER 0 AND _cgmib LESS ${_totalmem}) + set(_totalmem ${_cgmib}) + message(STATUS "Memory limit from ${_cg}: ${_totalmem} MiB") + break() + endif() + endif() + endif() +endforeach() + +# 8 GiB per job, not 2. Measured on the CI builders with GCC 14.2: the heaviest +# analysis producers peak at 7.4-10.1 GiB each (derivedDataWriter 10.09, +# femtoProducer 8.27, candidateCreatorXic0Omegac0 7.36), and -fmem-report shows +# ~6.4 GB of that is frontend AST held live -- template instantiation over the +# distinct soa::Join types each task subscribes to. At 2048 the pool permitted +# four times what the memory allows, and ninja builds in declaration order, so +# the heavy producers arrive as a cluster rather than spread out. +set(ANALYSIS_COMPILE_MEMORY_MB 8192 CACHE STRING + "Assumed peak memory of one analysis compilation, in MiB") +math(EXPR _total_analysis_jobs "(${_totalmem}-2048)/${ANALYSIS_COMPILE_MEMORY_MB}") if(_total_analysis_jobs LESS_EQUAL 0) set(_total_analysis_jobs 1) endif() diff --git a/Common/CCDB/macros/ctpRateF.C b/Common/CCDB/macros/ctpRateF.C index 6840b3f4e36..2a6666b8bd6 100644 --- a/Common/CCDB/macros/ctpRateF.C +++ b/Common/CCDB/macros/ctpRateF.C @@ -29,12 +29,12 @@ struct ctpRateFetcher { ctpRateFetcher() = default; - double fetch(o2::ccdb::BasicCCDBManager* ccdb, uint64_t timeStamp, int runNumber, std::string sourceName); + double fetch(o2::ccdb::BasicCCDBManager* ccdb, uint64_t timeStamp, int runNumber, const std::string& sourceName); void getCTPconfig(o2::ccdb::BasicCCDBManager* ccdb, uint64_t timeStamp, int runNumber); void getCTPscalers(o2::ccdb::BasicCCDBManager* ccdb, uint64_t timeStamp, int runNumber); void getLHCIFdata(o2::ccdb::BasicCCDBManager* ccdb, uint64_t timeStamp, int runNumber); double fetchCTPratesInputs(o2::ccdb::BasicCCDBManager* ccdb, uint64_t timeStamp, int runNumber, int input); - double fetchCTPratesClasses(o2::ccdb::BasicCCDBManager* ccdb, uint64_t timeStamp, int runNumber, std::string className, int inputType = 1); + double fetchCTPratesClasses(o2::ccdb::BasicCCDBManager* ccdb, uint64_t timeStamp, int runNumber, const std::string& className, int inputType = 1); double pileUpCorrection(double rate); int mRunNumber = -1; @@ -104,7 +104,7 @@ double ctpRateFetcher::fetchCTPratesInputs(o2::ccdb::BasicCCDBManager* ccdb, uin return -1.; } } -double ctpRateFetcher::fetchCTPratesClasses(o2::ccdb::BasicCCDBManager* ccdb, uint64_t timeStamp, int runNumber, std::string className, int inputType) +double ctpRateFetcher::fetchCTPratesClasses(o2::ccdb::BasicCCDBManager* ccdb, uint64_t timeStamp, int runNumber, const std::string& className, int inputType) { getCTPscalers(ccdb, timeStamp, runNumber); getCTPconfig(ccdb, timeStamp, runNumber); @@ -125,7 +125,7 @@ double ctpRateFetcher::fetchCTPratesClasses(o2::ccdb::BasicCCDBManager* ccdb, ui getLHCIFdata(ccdb, timeStamp, runNumber); return pileUpCorrection(rate.second); } -double ctpRateFetcher::fetch(o2::ccdb::BasicCCDBManager* ccdb, uint64_t timeStamp, int runNumber, std::string sourceName) +double ctpRateFetcher::fetch(o2::ccdb::BasicCCDBManager* ccdb, uint64_t timeStamp, int runNumber, const std::string& sourceName) { if (sourceName.find("ZNC") != std::string::npos) { if (runNumber < 544448) { diff --git a/Common/Core/EventPlaneHelper.cxx b/Common/Core/EventPlaneHelper.cxx index 49fd347c8a1..aaf839162e7 100644 --- a/Common/Core/EventPlaneHelper.cxx +++ b/Common/Core/EventPlaneHelper.cxx @@ -164,19 +164,19 @@ void EventPlaneHelper::DoRescale(float& qx, float& qy, float ap, float am) qy /= am; } -void EventPlaneHelper::GetCorrRecentering(const std::shared_ptr histQ, float& meanX, float& meanY) +void EventPlaneHelper::GetCorrRecentering(const std::shared_ptr& histQ, float& meanX, float& meanY) { meanX = histQ->GetMean(1); meanY = histQ->GetMean(2); } -void EventPlaneHelper::GetCorrWidth(const std::shared_ptr histQ, float& stdX, float& stdY) +void EventPlaneHelper::GetCorrWidth(const std::shared_ptr& histQ, float& stdX, float& stdY) { stdX = histQ->GetStdDev(1); stdY = histQ->GetStdDev(2); } -void EventPlaneHelper::GetCorrTwistRecale(const std::shared_ptr histQ, +void EventPlaneHelper::GetCorrTwistRecale(const std::shared_ptr& histQ, float& aPlus, float& aMinus, float& lambdaPlus, float& lambdaMinus) { diff --git a/Common/Core/EventPlaneHelper.h b/Common/Core/EventPlaneHelper.h index 1b1cc470db2..74597969638 100644 --- a/Common/Core/EventPlaneHelper.h +++ b/Common/Core/EventPlaneHelper.h @@ -81,13 +81,13 @@ class EventPlaneHelper void DoRescale(float& qx, float& qy, float ap, float am); // Method to get the recentering correction on the Qx-Qy distribution. - void GetCorrRecentering(const std::shared_ptr histQ, float& meanX, float& meanY); + void GetCorrRecentering(const std::shared_ptr& histQ, float& meanX, float& meanY); // Method to get the std. deviation on the Qx-Qy distribution. - void GetCorrWidth(const std::shared_ptr histQ, float& stdX, float& stdY); + void GetCorrWidth(const std::shared_ptr& histQ, float& stdX, float& stdY); // Method to get the twist and rescale correction on the Qx-Qy distribution. - void GetCorrTwistRecale(const std::shared_ptr histQ, + void GetCorrTwistRecale(const std::shared_ptr& histQ, float& aPlus, float& aMinus, float& lambdaPlus, float& lambdaMinus); diff --git a/Common/Core/PID/PIDTOFParamService.cxx b/Common/Core/PID/PIDTOFParamService.cxx index eae721fddc7..efd840273fa 100644 --- a/Common/Core/PID/PIDTOFParamService.cxx +++ b/Common/Core/PID/PIDTOFParamService.cxx @@ -46,7 +46,7 @@ o2::common::core::MetadataHelper o2::pid::tof::TOFResponseImpl::metadataInfo; bool o2::pid::tof::TOFResponseImpl::mIsInit = false; int o2::pid::tof::TOFResponseImpl::mLastRunNumber = -1; -void o2::pid::tof::TOFResponseImpl::inheritFromBaseTask(o2::framework::InitContext& initContext, const std::string task) +void o2::pid::tof::TOFResponseImpl::inheritFromBaseTask(o2::framework::InitContext& initContext, const std::string& task) { if (mIsInit) { LOG(fatal) << "TOFResponseImpl already initialized, cannot re-initialize"; @@ -70,7 +70,7 @@ void o2::pid::tof::TOFResponseImpl::inheritFromBaseTask(o2::framework::InitConte void o2::pid::tof::TOFResponseImpl::initSetup(o2::ccdb::BasicCCDBManager* ccdb, o2::framework::InitContext& initContext, - const std::string task) + const std::string& task) { if (mIsInit) { LOG(fatal) << "TOFResponseImpl already initialized, cannot re-initialize"; diff --git a/Common/Core/PID/PIDTOFParamService.h b/Common/Core/PID/PIDTOFParamService.h index f6747c598ef..dd33d250fa2 100644 --- a/Common/Core/PID/PIDTOFParamService.h +++ b/Common/Core/PID/PIDTOFParamService.h @@ -49,7 +49,7 @@ struct TOFResponseImpl { /// \note This function should be called in the init function of each task that uses the TOF response /// \note The parameters are loaded from the CCDB and stored in the static variable `parameters` /// \note The metadata information is also initialized in this function - void initSetup(o2::ccdb::BasicCCDBManager* ccdb, o2::framework::InitContext& initContext, const std::string task = "tof-signal"); + void initSetup(o2::ccdb::BasicCCDBManager* ccdb, o2::framework::InitContext& initContext, const std::string& task = "tof-signal"); /// Initialize the TOF response parameters in the init function of each task /// \param ccdb Service pointer to the CCDB manager @@ -163,7 +163,7 @@ struct TOFResponseImpl { o2::common::core::CollisionSystemType::collType cfgCollisionType() const { return mCollisionSystem; } private: - void inheritFromBaseTask(o2::framework::InitContext& initContext, const std::string task = "tof-signal"); + void inheritFromBaseTask(o2::framework::InitContext& initContext, const std::string& task = "tof-signal"); static bool mIsInit; //! Flag to check if the parameters are initialized static int mLastRunNumber; //! Last run number for which the calibration was loaded diff --git a/Common/Core/RecoDecay.h b/Common/Core/RecoDecay.h index c938280e865..075a304c2bf 100644 --- a/Common/Core/RecoDecay.h +++ b/Common/Core/RecoDecay.h @@ -569,6 +569,7 @@ struct RecoDecay { /// \param acceptAntiParticles switch to accept the antiparticle of the expected mother /// \param sign antiparticle indicator of the found mother w.r.t. pdgMother; 1 if particle, -1 if antiparticle, 0 if mother not found /// \param depthMax maximum decay tree level to check; Mothers up to this level will be considered. If -1, all levels are considered. + /// \param searchUpToQuark switch to stop searching for mothers when a quark or boson is found /// \return index of the mother particle if found, -1 otherwise template static int getMother(const T& particlesMC, @@ -576,7 +577,8 @@ struct RecoDecay { int pdgMother, bool acceptAntiParticles = false, int8_t* sign = nullptr, - int8_t depthMax = -1) + int8_t depthMax = -1, + const bool searchUpToQuark = true) { int8_t sgn = 0; // 1 if the expected mother is particle, -1 if antiparticle (w.r.t. pdgMother) int indexMother = -1; // index of the final matched mother, if found @@ -597,13 +599,18 @@ struct RecoDecay { for (auto iPart : arrayIds[-stage]) { // check all the particles that were the mothers at the previous stage, o2-linter: disable=const-ref-in-for-loop (int elements) auto particleMother = particlesMC.rawIteratorAt(iPart - particlesMC.offset()); if (particleMother.has_mothers()) { - for (auto iMother = particleMother.mothersIds().front(); iMother <= particleMother.mothersIds().back(); ++iMother) { // loop over the mother particles of the analysed particle - if (std::find(arrayIdsStage.begin(), arrayIdsStage.end(), iMother) != arrayIdsStage.end()) { // if a mother is still present in the vector, do not check it again + // If searchUpToQuark is false we only take the first mother (since decay products only have one mother) + auto lastMotherIdxToCheck = searchUpToQuark ? particleMother.mothersIds().back() : particleMother.mothersIds().front(); + for (auto iMother = particleMother.mothersIds().front(); iMother <= lastMotherIdxToCheck; ++iMother) { // loop over the mother particles of the analysed particle + if (std::find(arrayIdsStage.begin(), arrayIdsStage.end(), iMother) != arrayIdsStage.end()) { // if a mother is still present in the vector, do not check it again continue; } auto mother = particlesMC.rawIteratorAt(iMother - particlesMC.offset()); // Check mother's PDG code. auto pdgParticleIMother = mother.pdgCode(); // PDG code of the mother + if (!searchUpToQuark && (std::abs(pdgParticleIMother) <= PdgQuarkMax || (std::abs(pdgParticleIMother) >= PdgBosonMin && std::abs(pdgParticleIMother) <= PdgBosonMax))) { + continue; + } // printf("getMother: "); // for (int i = stage; i < 0; i++) // Indent to make the tree look nice. // printf(" "); @@ -729,6 +736,7 @@ struct RecoDecay { /// \param nPiToMu number of pion prongs decayed to a muon /// \param nKaToPi number of kaon prongs decayed to a pion /// \param nInteractionsWithMaterial number of daughter particles that interacted with material + /// \param searchUpToQuark switch to search for the decay up to the quark level /// \return index of the mother particle if the mother and daughters are correct, -1 otherwise template static int getMatchedMCRec(const T& particlesMC, @@ -740,7 +748,8 @@ struct RecoDecay { int depthMax = 1, int8_t* nPiToMu = nullptr, int8_t* nKaToPi = nullptr, - int8_t* nInteractionsWithMaterial = nullptr) + int8_t* nInteractionsWithMaterial = nullptr, + bool searchUpToQuark = true) { // Printf("MC Rec: Expected mother PDG: %d", pdgMother); int8_t coefFlavourOscillation = 1; // 1 if no B0(s) flavour oscillation occured, -1 else @@ -815,7 +824,7 @@ struct RecoDecay { if (iProng == 0) { // Get the mother index and its sign. // PDG code of the first daughter's mother determines whether the expected mother is a particle or antiparticle. - indexMother = getMother(particlesMC, particleI, pdgMother, acceptAntiParticles, &sgn, depthMax); + indexMother = getMother(particlesMC, particleI, pdgMother, acceptAntiParticles, &sgn, depthMax, searchUpToQuark); // Check whether mother was found. if (indexMother <= -1) { // Printf("MC Rec: Rejected: bad mother index or PDG"); diff --git a/Common/Core/TPCVDriftManager.h b/Common/Core/TPCVDriftManager.h index 3219b6189a0..8a7e29cef16 100644 --- a/Common/Core/TPCVDriftManager.h +++ b/Common/Core/TPCVDriftManager.h @@ -39,12 +39,14 @@ class TPCVDriftManager void update(uint64_t timestamp) noexcept { - // Check validity of already present obj, otherwise update - if (mVD != nullptr && (timestamp > static_cast(mVD->firstTime) || timestamp < static_cast(mVD->lastTime))) { + // Keep the object we already have if it is still valid for this timestamp. + // firstTime/lastTime are the first and last timestamps of the TFs the correction + // was derived from, so the validity range is closed on both ends. + if (mVD != nullptr && timestamp >= static_cast(mVD->firstTime) && timestamp <= static_cast(mVD->lastTime)) { return; } - // Update Obj + // Update Object mVD = mCCDB->getForTimeStamp("TPC/Calib/VDriftTgl", timestamp); if (mVD == nullptr || mVD->firstTime < 0 || mVD->lastTime < 0) { LOGP(error, "Got invalid VDriftCorrFact for {}", timestamp); @@ -58,7 +60,28 @@ class TPCVDriftManager mTPCVDriftNS = mVD->refVDrift * mVD->corrFact * 1e-3; mValid = true; - LOGP(info, "Updated VDrift for timestamp {} with vdrift={:.7f} (cm/ns)", mVD->creationTime, mTPCVDriftNS); + LOGP(debug, "Updated VDrift for timestamp {} with vdrift={:.7f} (cm/ns)", mVD->creationTime, mTPCVDriftNS); + } + + // Adopts a drift correction obtained elsewhere, typically straight from the + // aod::TpcCalibCCDBObjects column, so no CCDB manager is involved at all. + void update(const o2::tpc::VDriftCorrFact& vd) noexcept + { + if (mVD == &vd) { // same object as last time, nothing to recompute + return; + } + if (vd.firstTime < 0 || vd.lastTime < 0) { + LOGP(error, "Got invalid VDriftCorrFact created at {}", vd.creationTime); + mValid = false; + return; + } + mVD = &vd; + + // TODO account for laser calib + + mTPCVDriftNS = mVD->refVDrift * mVD->corrFact * 1e-3; + mValid = true; + LOGP(debug, "Updated VDrift for timestamp {} with vdrift={:.7f} (cm/ns)", mVD->creationTime, mTPCVDriftNS); } template diff --git a/Common/Core/TrackSelection.cxx b/Common/Core/TrackSelection.cxx index 6d73fb22d20..97de07b2bd0 100644 --- a/Common/Core/TrackSelection.cxx +++ b/Common/Core/TrackSelection.cxx @@ -119,11 +119,11 @@ void TrackSelection::SetMaxDcaZ(float maxDcaZ) void TrackSelection::SetMaxDcaXYPtDep(std::function ptDepCut) { - mMaxDcaXYPtDep = ptDepCut; + mMaxDcaXYPtDep = std::move(ptDepCut); LOG(info) << "Track selection, set max DCA xy pt dep: " << mMaxDcaXYPtDep(1.0); } -void TrackSelection::SetRequireHitsInITSLayers(int8_t minNRequiredHits, std::set requiredLayers) +void TrackSelection::SetRequireHitsInITSLayers(int8_t minNRequiredHits, const std::set& requiredLayers) { // layer 0 corresponds to the the innermost ITS layer uint8_t mask = 0; @@ -133,7 +133,7 @@ void TrackSelection::SetRequireHitsInITSLayers(int8_t minNRequiredHits, std::set mRequiredITSHits.push_back(std::make_pair(minNRequiredHits, mask)); LOG(info) << "Track selection, set require hits in ITS layers: " << static_cast(minNRequiredHits); } -void TrackSelection::SetRequireNoHitsInITSLayers(std::set excludedLayers) +void TrackSelection::SetRequireNoHitsInITSLayers(const std::set& excludedLayers) { uint8_t mask = 0; for (const auto& layer : excludedLayers) { diff --git a/Common/Core/TrackSelection.h b/Common/Core/TrackSelection.h index b618be91536..80e676c625c 100644 --- a/Common/Core/TrackSelection.h +++ b/Common/Core/TrackSelection.h @@ -249,8 +249,8 @@ class TrackSelection void SetMaxDcaXY(float maxDcaXY); void SetMaxDcaZ(float maxDcaZ); void SetMaxDcaXYPtDep(std::function ptDepCut); - void SetRequireHitsInITSLayers(int8_t minNRequiredHits, std::set requiredLayers); - void SetRequireNoHitsInITSLayers(std::set excludedLayers); + void SetRequireHitsInITSLayers(int8_t minNRequiredHits, const std::set& requiredLayers); + void SetRequireNoHitsInITSLayers(const std::set& excludedLayers); /// @brief Reset ITS requirements void ResetITSRequirements() { mRequiredITSHits.clear(); } void SetMaxTPCFractionSharedCls(float maxTPCFractionSharedCls); diff --git a/Common/Core/Zorro.cxx b/Common/Core/Zorro.cxx index 446e36e7f2b..6eb0b61c118 100644 --- a/Common/Core/Zorro.cxx +++ b/Common/Core/Zorro.cxx @@ -52,7 +52,7 @@ int findBin(TH1* hist, const std::string& label) } } // namespace -void Zorro::populateHistRegistry(o2::framework::HistogramRegistry& histRegistry, int runNumber, std::string folderName) +void Zorro::populateHistRegistry(o2::framework::HistogramRegistry& histRegistry, int runNumber, const std::string& folderName) { int runId{-1}; for (size_t i{0}; i < mRunNumberHistos.size(); ++i) { @@ -176,7 +176,7 @@ void Zorro::populateExternalHists(int runNumber, TH2* ZorroHisto, TH2* ToiHisto) mRunNumberHistos.push_back(runNumber); } -std::vector Zorro::initCCDB(o2::ccdb::BasicCCDBManager* ccdb, int runNumber, uint64_t timestamp, std::string tois, int bcRange) +std::vector Zorro::initCCDB(o2::ccdb::BasicCCDBManager* ccdb, int runNumber, uint64_t timestamp, const std::string& tois, int bcRange) { if (mRunNumber == runNumber) { return mTOIidx; diff --git a/Common/Core/Zorro.h b/Common/Core/Zorro.h index 29247b21c15..f200e099c44 100644 --- a/Common/Core/Zorro.h +++ b/Common/Core/Zorro.h @@ -46,12 +46,12 @@ class Zorro { public: Zorro() = default; - std::vector initCCDB(o2::ccdb::BasicCCDBManager* ccdb, int runNumber, uint64_t timestamp, std::string tois, int bcTolerance = 500); + std::vector initCCDB(o2::ccdb::BasicCCDBManager* ccdb, int runNumber, uint64_t timestamp, const std::string& tois, int bcTolerance = 500); std::bitset<128> fetch(uint64_t bcGlobalId, uint64_t tolerance = 100); bool isSelected(uint64_t bcGlobalId, uint64_t tolerance = 100, TH2* toiHisto = nullptr); bool isNotSelectedByAny(uint64_t bcGlobalId, uint64_t tolerance = 100); - void populateHistRegistry(o2::framework::HistogramRegistry& histRegistry, int runNumber, std::string folderName = "Zorro"); + void populateHistRegistry(o2::framework::HistogramRegistry& histRegistry, int runNumber, const std::string& folderName = "Zorro"); void populateExternalHists(int runNumber, TH2* zorroHisto = nullptr, TH2* toiHisto = nullptr); TH1D* getScalers() const { return mScalers; } diff --git a/Common/Core/fwdtrackUtilities.h b/Common/Core/fwdtrackUtilities.h index 29a9db2c194..932a77d9ae3 100644 --- a/Common/Core/fwdtrackUtilities.h +++ b/Common/Core/fwdtrackUtilities.h @@ -108,16 +108,16 @@ o2::track::TrackParCovFwd getTrackParCovFwdShift(TFwdTrack const& track, float z return getTrackParCovFwd3DShift(track, 0.f, 0.f, zshift, covOpt...); } -inline o2::track::TrackParCovFwd getTrackParCovFwdShiftManual( +inline o2::track::TrackParCovFwd getTrackParCovFwd3DShiftManual( const double x, const double y, const double phi, const double tgl, const double signed1Pt, const double cXX, const double cXY, const double cYY, const double cPhiX, const double cPhiY, const double cPhiPhi, const double cTglX, const double cTglY, const double cTglPhi, const double cTglTgl, const double c1PtX, const double c1PtY, const double c1PtPhi, const double c1PtTgl, const double c1Pt21Pt2, - const float z, const float zshift, const float chi2) + const float z, const float xshift, const float yshift, const float zshift, const float chi2) { - SMatrix5 tpars(x, y, phi, tgl, signed1Pt); + SMatrix5 tpars(x + xshift, y + yshift, phi, tgl, signed1Pt); SMatrix55 tcovs; std::vector v1{ @@ -164,15 +164,15 @@ o2::track::TrackParCovFwd getTrackParCovFwd(TFwdTrack const& track, TFwdTrackCov /// propagate fwdtrack to a certain point. template -o2::dataformats::GlobalFwdTrack propagateMuon(TFwdTrack const& muon, TFwdTrackCov const& cov, TCollision const& collision, const propagationPoint endPoint, const float matchingZ, const float bzkG, const float zshift = 0.f) +o2::dataformats::GlobalFwdTrack propagateMuon(TFwdTrack const& muon, TFwdTrackCov const& cov, TCollision const& collision, const propagationPoint endPoint, const float matchingZ, const float bzkG, const float xshift = 0.f, const float yshift = 0.f, const float zshift = 0.f) { o2::track::TrackParCovFwd trackParCovFwd; if (muon.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { - trackParCovFwd = getTrackParCovFwdShift(muon, zshift, cov); + trackParCovFwd = getTrackParCovFwd3DShift(muon, xshift, yshift, zshift, cov); } else if (muon.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { - trackParCovFwd = getTrackParCovFwdShift(muon, zshift, muon); + trackParCovFwd = getTrackParCovFwd3DShift(muon, xshift, yshift, zshift, muon); } else { - trackParCovFwd = getTrackParCovFwdShift(muon, zshift, muon); + trackParCovFwd = getTrackParCovFwd3DShift(muon, xshift, yshift, zshift, muon); } o2::dataformats::GlobalFwdTrack propmuon = propagateTrackParCovFwd(trackParCovFwd, muon.trackType(), collision, endPoint, matchingZ, bzkG); @@ -340,7 +340,7 @@ float getFwdChi2IP(TTrackParCovFwd const& inputTrk, TCollision const& collision, } template -float getFwdChi2IP(const TFullFwdTrack& fwdtrack, const TCollision& collision, const float bz, const float zShift) +float getFwdChi2IP(const TFullFwdTrack& fwdtrack, const TCollision& collision, const float bz, const float xShift, const float yShift, const float zShift) { // this function returns imcompatibility of fwdtrack respect to a given PV. // fwdtracks are never PV contributors in ALICE. @@ -348,7 +348,7 @@ float getFwdChi2IP(const TFullFwdTrack& fwdtrack, const TCollision& collision, c // chi2IP cannot be used to decide the best fwdtrack-to-collision match or MFT-MCH match, because it gives biases toward small muon impact parameter. // chi2IP should be used only after the best fwdtrack-to-collision association and the best MFT-MCH match are defined. - o2::track::TrackParCovFwd trk = getTrackParCovFwdShift(fwdtrack, zShift, fwdtrack); + o2::track::TrackParCovFwd trk = getTrackParCovFwd3DShift(fwdtrack, xShift, yShift, zShift, fwdtrack); if (std::abs(bz) < 1e-12) { trk.propagateToZlinear(collision.posZ()); diff --git a/Common/Core/macros/testMetadataHelper.C b/Common/Core/macros/testMetadataHelper.C index 9eb3a7e1e6b..dd20cba9c44 100644 --- a/Common/Core/macros/testMetadataHelper.C +++ b/Common/Core/macros/testMetadataHelper.C @@ -128,9 +128,9 @@ std::map buildMapForCommitHash(const std::string& hash) return results; } -void populateCCDBWithCommitAvailability(std::map hasHashMap, - const std::string commitHash, - const std::string ccdbUrl = "http://ccdb-test.cern.ch:8080/") +void populateCCDBWithCommitAvailability(const std::map& hasHashMap, + const std::string& commitHash, + const std::string& ccdbUrl = "http://ccdb-test.cern.ch:8080/") { // First, init the CCDB manager to test if the ccdb is already populated o2::ccdb::CcdbApi api; @@ -157,7 +157,7 @@ void populateCCDBWithCommitAvailability(std::map hasHashMap, } } -void testMetadataHelper(std::string aod = "/tmp/AO2D.root") +void testMetadataHelper(const std::string& aod = "/tmp/AO2D.root") { createO2VersionFile(); const std::string commitHash = "63bc2e3893851ef0f849bb4c98c65eae1ba21e47"; diff --git a/Common/TableProducer/PID/pidBayes.cxx b/Common/TableProducer/PID/pidBayes.cxx index dd52d06e6cb..27aec0b67b5 100644 --- a/Common/TableProducer/PID/pidBayes.cxx +++ b/Common/TableProducer/PID/pidBayes.cxx @@ -639,7 +639,7 @@ struct bayesPidQa { histos.fill(HIST("event/vertexz"), collision.posZ()); histos.fill(HIST("event/colltime"), collisionTime_ps); - for (auto t : tracks) { + for (const auto& t : tracks) { // if (!t.hasTOF()) { // Skipping tracks without TOF continue; diff --git a/Common/TableProducer/eseTableProducer.cxx b/Common/TableProducer/eseTableProducer.cxx index d6915ab9419..897659b198e 100644 --- a/Common/TableProducer/eseTableProducer.cxx +++ b/Common/TableProducer/eseTableProducer.cxx @@ -405,7 +405,7 @@ struct EseTableProducer { } template - double getEfficiency(TTrack track) + double getEfficiency(const TTrack& track) { double eff = 1.; if (cfg.mEfficiency) @@ -453,7 +453,7 @@ struct EseTableProducer { }; template - bool eventSelected(TCollision collision, const int& multTrk, const float& centrality) + bool eventSelected(const TCollision& collision, const int& multTrk, const float& centrality) { if (cfgTVXinTRD) { if (collision.alias_bit(kTVXinTRD)) { diff --git a/Common/TableProducer/match-mft-mch-data-mc.cxx b/Common/TableProducer/match-mft-mch-data-mc.cxx index 2e801bc4040..7b3be6fa633 100644 --- a/Common/TableProducer/match-mft-mch-data-mc.cxx +++ b/Common/TableProducer/match-mft-mch-data-mc.cxx @@ -503,7 +503,7 @@ struct match_mft_mch_data_mc { }; template - bool isGoodMuonQuality(MUON muontrack) + bool isGoodMuonQuality(const MUON& muontrack) { if (!muontrack.has_collision()) return false; @@ -521,7 +521,7 @@ struct match_mft_mch_data_mc { } template - bool isGoodMuonKine(MUON muontrack) + bool isGoodMuonKine(const MUON& muontrack) { if (fEtaMchLow > muontrack.getEta() || muontrack.getEta() > fEtaMchUp) return false; @@ -529,7 +529,7 @@ struct match_mft_mch_data_mc { } template - bool isGoodMFTQuality(MFT mfttrack) + bool isGoodMFTQuality(const MFT& mfttrack) { if (!mfttrack.has_collision()) return false; @@ -541,7 +541,7 @@ struct match_mft_mch_data_mc { } template - bool isGoodMFTKine(MFT mfttrack) + bool isGoodMFTKine(const MFT& mfttrack) { if (fEtaMftLow > mfttrack.getEta() || mfttrack.getEta() > fEtaMftUp) return false; @@ -556,7 +556,7 @@ struct match_mft_mch_data_mc { template void setMUONs(MUONs const& muontracks, Collisions const& collisions) { - for (auto muontrack : muontracks) { + for (const auto& muontrack : muontracks) { if (!isGoodMuonQuality(muontrack)) continue; o2::dataformats::GlobalFwdTrack muontrack_at_pv = propagateMUONtoPV(muontrack, collisions); @@ -595,7 +595,7 @@ struct match_mft_mch_data_mc { template void setMFTs(MFTs const& mfttracks, Collisions const& collisions, o2::field::MagneticField* field) { - for (auto mfttrack : mfttracks) { + for (const auto& mfttrack : mfttracks) { if (!isGoodMFTQuality(mfttrack)) continue; diff --git a/Common/TableProducer/match-mft-mch-data.cxx b/Common/TableProducer/match-mft-mch-data.cxx index 9541af4d5cc..4a6b9be135e 100644 --- a/Common/TableProducer/match-mft-mch-data.cxx +++ b/Common/TableProducer/match-mft-mch-data.cxx @@ -503,7 +503,7 @@ struct match_mft_mch_data_mc { }; template - bool isGoodMuonQuality(MUON muontrack) + bool isGoodMuonQuality(const MUON& muontrack) { if (!muontrack.has_collision()) return false; @@ -521,7 +521,7 @@ struct match_mft_mch_data_mc { } template - bool isGoodMuonKine(MUON muontrack) + bool isGoodMuonKine(const MUON& muontrack) { if (fEtaMchLow > muontrack.getEta() || muontrack.getEta() > fEtaMchUp) return false; @@ -529,7 +529,7 @@ struct match_mft_mch_data_mc { } template - bool isGoodMFTQuality(MFT mfttrack) + bool isGoodMFTQuality(const MFT& mfttrack) { if (!mfttrack.has_collision()) return false; @@ -541,7 +541,7 @@ struct match_mft_mch_data_mc { } template - bool isGoodMFTKine(MFT mfttrack) + bool isGoodMFTKine(const MFT& mfttrack) { if (fEtaMftLow > mfttrack.getEta() || mfttrack.getEta() > fEtaMftUp) return false; @@ -556,7 +556,7 @@ struct match_mft_mch_data_mc { template void setMUONs(MUONs const& muontracks, Collisions const& collisions) { - for (auto muontrack : muontracks) { + for (const auto& muontrack : muontracks) { if (!isGoodMuonQuality(muontrack)) continue; o2::dataformats::GlobalFwdTrack muontrack_at_pv = propagateMUONtoPV(muontrack, collisions); @@ -595,7 +595,7 @@ struct match_mft_mch_data_mc { template void setMFTs(MFTs const& mfttracks, Collisions const& collisions, o2::field::MagneticField* field) { - for (auto mfttrack : mfttracks) { + for (const auto& mfttrack : mfttracks) { if (!isGoodMFTQuality(mfttrack)) continue; diff --git a/Common/TableProducer/qVectorsTable.cxx b/Common/TableProducer/qVectorsTable.cxx index 79825f9c875..a4259e87079 100644 --- a/Common/TableProducer/qVectorsTable.cxx +++ b/Common/TableProducer/qVectorsTable.cxx @@ -390,7 +390,7 @@ struct QVectorsTable { } template - bool selTrack(const TrackType track) + bool selTrack(const TrackType& track) { if (track.pt() < cfgMinPtOnTPC) return false; diff --git a/Common/TableProducer/zdcTaskLightIons.cxx b/Common/TableProducer/zdcTaskLightIons.cxx index 3e188bb2dc3..d778f5087a6 100644 --- a/Common/TableProducer/zdcTaskLightIons.cxx +++ b/Common/TableProducer/zdcTaskLightIons.cxx @@ -97,7 +97,7 @@ struct ZdcTaskLightIons { } template - uint8_t eventSelected(TCollision collision) + uint8_t eventSelected(const TCollision& collision) { uint8_t selectionBits = 0; bool selected; diff --git a/Common/Tasks/centralityQa.cxx b/Common/Tasks/centralityQa.cxx index 782606a0b64..72ad8e21925 100644 --- a/Common/Tasks/centralityQa.cxx +++ b/Common/Tasks/centralityQa.cxx @@ -12,7 +12,7 @@ /// /// \file centralityQa.cxx /// \brief This task does dedicated centrality QA -/// \author ALICE +/// \author ALICE Collaboration /// #include "Common/CCDB/EventSelectionParams.h" @@ -38,6 +38,8 @@ #include #include +#include +#include #include #include @@ -45,29 +47,35 @@ #include #include #include +#include +#include #include #include +#include using namespace o2; using namespace o2::framework; +using CentRun3 = soa::Join; +using BCsWithMatching = soa::Join; + struct CentralityQa { HistogramRegistry histos{"histos"}; + std::map histPointers; Service ccdb{}; std::bitset collidingBunch; - bool isRun2 = false; - bool isMC = false; int runNumber{}; uint64_t startOfRunTimestamp{}; TList* hCentralityObjects = nullptr; - Configurable nBins{"nBins", 1050, "number of bins"}; ConfigurableAxis axisMultiplicity{"axisMultiplicity", {1000, 0, 1000}, "Multiplicity"}; ConfigurableAxis axisMultiplicityPV{"axisMultiplicityPV", {1000, 0, 1000}, "Multiplicity PV"}; ConfigurableAxis axisChannelAmplitude{"axisChannelAmplitude", {5000, 0, 5000}, "Channel Amplitude"}; ConfigurableAxis axisCentrality{"axisCentrality", {101, 0.0f, 101.0f}, "Centrality (%)"}; + Configurable loopOverMcCollisionsForMcHist{"loopOverMcCollisionsForMcHist", false, "Fill MC histograms in a loop over MC collisions? If no, they will be filled in a loop over reconstructed collisions"}; + struct : ConfigurableGroup { std::string prefix = "eventSelections"; // JSON group name Configurable requireSel8{"requireSel8", true, "require sel8 event selection"}; @@ -127,6 +135,23 @@ struct CentralityQa { Configurable rejectIsFlangeEvent{"rejectIsFlangeEvent", false, "reject is flange event"}; } bcsel; + struct : ConfigurableGroup { + std::string prefix = "studies"; + Configurable fv0a{"fv0a", true, "Enable centrality QA for fv0a"}; + Configurable ft0m{"ft0m", true, "Enable centrality QA for ft0m"}; + Configurable ft0mOuterA{"ft0mOuterA", true, "Enable centrality QA for ft0m"}; + Configurable ft0mAnchorCol{"ft0mAnchorCol", true, "Enable centrality QA for ft0m"}; + Configurable ft0mAnchorBc{"ft0mAnchorBc", true, "Enable centrality QA for ft0m"}; + Configurable ft0a{"ft0a", false, "Enable centrality QA for ft0a"}; + Configurable ft0c{"ft0c", true, "Enable centrality QA for ft0c"}; + Configurable ft0cVar1{"ft0cVar1", false, "Enable centrality QA for ft0cVar1"}; + Configurable ft0cVar2{"ft0cVar2", false, "Enable centrality QA for ft0cVar2"}; + Configurable fddm{"fddm", false, "Enable centrality QA for fddm"}; + Configurable ntpv{"ntpv", false, "Enable centrality QA for ntpv"}; + Configurable nGlo{"nGlo", true, "Enable centrality QA for nGlo"}; + Configurable mft{"mft", true, "Enable centrality QA for mft"}; + } studies; + struct : ConfigurableGroup { std::string prefix = "centrality"; Configurable useCustomCalibration{"useCustomCalibration", false, "override the centrality from the central calibration with a different calibration provided in pathCentrality"}; @@ -135,22 +160,40 @@ struct CentralityQa { Configurable generator{"generator", "", "E.g. PYTHIA"}; } centrality; + enum EstimatorIndex { FV0A, + FT0M, + FT0MAnchorCol, + FT0MAnchorBC, + FT0MOuterA, + FT0A, + FT0C, + FT0CVar1, + FT0CVar2, + FDDM, + NTPV, + NGlobal, + MFT, + NEstimators }; + static constexpr int NSuperCalibPars = 6; static constexpr float CentralityNotFound = 105.f; struct Estimator { CentralityQa* outer = nullptr; - std::string name; + bool doStudy = false; + std::string estName; + std::string histName; std::array mcScalePars{}; TH1* hCentrality = nullptr; TFormula* mcScale = nullptr; - explicit Estimator(CentralityQa* o, std::string s) : outer(o), name(std::move(s)) {} + Estimator() = default; + explicit Estimator(CentralityQa* o, bool b, std::string s0, std::string s1) : outer(o), doStudy(b), estName(std::move(s0)), histName(std::move(s1)) {} float getCentrality(const float mult, const float centTable) { if (outer->centrality.useCustomCalibration) { float lMult = mult; - if (outer->isMC && outer->hCentralityObjects != nullptr) { - mcScale = dynamic_cast(outer->hCentralityObjects->FindObject(TString::Format("%s-%s", outer->centrality.generator.value.c_str(), name.c_str()).Data())); + if (outer->doprocessRun3MonteCarlo && outer->hCentralityObjects != nullptr) { + mcScale = dynamic_cast(outer->hCentralityObjects->FindObject(TString::Format("%s-%s", outer->centrality.generator.value.c_str(), estName.c_str()).Data())); if (!mcScale) { return CentralityNotFound; } @@ -173,364 +216,312 @@ struct CentralityQa { } return centTable; } + template + void configure(const TCollision& col) + { + if (!outer->centrality.useCustomCalibration) { + return; + } + + if (!col.has_foundBC()) { + return; + } + + const auto& bc = col.template foundBC_as(); + if (bc.runNumber() != outer->runNumber) { + outer->runNumber = bc.runNumber(); + LOGF(info, "Acquiring centrality calibration for run %i", outer->runNumber); + outer->hCentralityObjects = outer->ccdb->getForRun(outer->centrality.pathCentrality, outer->runNumber); + if (!outer->hCentralityObjects) { + LOGF(info, "No centrality calibration list found for run %i", outer->runNumber); + } + } + + if (!outer->hCentralityObjects) { + hCentrality = nullptr; + return; + } + + hCentrality = dynamic_cast(outer->hCentralityObjects->FindObject(Form("hCalibZeq%s", estName.c_str()))); + if (!hCentrality) { + LOGF(debug, "Calibration missing for %s", estName.c_str()); + } else { + LOGF(debug, "Calibration loaded for %s", estName.c_str()); + } + } }; + std::vector estimators; + Estimator initEstimator(const bool doStudy, const std::string& estName, const std::string& histName) + { + return Estimator(this, doStudy, estName, histName); + } + + template + void insertHist(const std::string& name, const std::string& title, HistType type, const std::vector& axes) + { + histPointers[name] = histos.add(name.c_str(), title.c_str(), type, axes); + } + + template + std::shared_ptr& getHist(const std::string& name) + { + return std::get>(histPointers[name]); + } + + PresliceUnsorted> perMcCollision = aod::mccollisionlabel::mcCollisionId; + PresliceUnsorted> perMcCollisionNGlobal = aod::mccollisionlabel::mcCollisionId; + PresliceUnsorted> perMcCollisionMFT = aod::mccollisionlabel::mcCollisionId; + void init(o2::framework::InitContext& /*initContext*/) { ccdb->setURL(centrality.ccdbURL); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); - isRun2 = doprocessRun2PP || - doprocessRun2PPb || - doprocessRun2PbPb; - - isMC = doprocessMonteCarloRun3_FV0A || - doprocessMonteCarloRun3_FT0M || - doprocessMonteCarloRun3_FT0A || - doprocessMonteCarloRun3_FT0C || - doprocessMonteCarloRun3_FT0CVar1 || - doprocessMonteCarloRun3_FT0CVar2 || - doprocessMonteCarloRun3_MFT || - doprocessMonteCarloRun3_NGlobal || - doprocessMonteCarloRun3_NTPV || - doprocessMonteCarloRun3_FT0MAnchorCol || - doprocessMonteCarloRun3_FT0MAnchorBC; - - if (isRun2) { - histos.add("hCentRun2V0M", ";V0M centrality (%)", kTH1D, {{nBins, 0, 105.}}); - histos.add("hCentRun2V0A", ";V0A centrality (%)", kTH1D, {{nBins, 0, 105.}}); - histos.add("hCentRun2SPDTks", ";SPD tracklet centrality (%)", kTH1D, {{nBins, 0, 105.}}); - histos.add("hCentRun2SPDCls", ";SPD cluster centrality (%)", kTH1D, {{nBins, 0, 105.}}); - histos.add("hCentRun2CL0", ";CL0 centrality (%)", kTH1D, {{nBins, 0, 105.}}); - histos.add("hCentRun2CL1", ";CL1 centrality (%)", kTH1D, {{nBins, 0, 105.}}); - } else { - histos.add("hCentFV0A", ";FV0A centrality (%)", kTH1D, {{nBins, 0, 105.}}); - histos.add("hCentFT0M", ";FT0M centrality (%)", kTH1D, {{nBins, 0, 105.}}); - histos.add("hCentFT0MOuterA", ";FT0M centrality (%)", kTH1D, {{nBins, 0, 105.}}); - histos.add("hCentFT0A", ";FT0A centrality (%)", kTH1D, {{nBins, 0, 105.}}); - histos.add("hCentFT0C", ";FT0C centrality (%)", kTH1D, {{nBins, 0, 105.}}); - histos.add("hCentFT0CVar1", ";FT0CVar1 centrality (%)", kTH1D, {{nBins, 0, 105.}}); - histos.add("hCentFT0CVar2", ";FT0CVar2 centrality (%)", kTH1D, {{nBins, 0, 105.}}); - histos.add("hCentFDDM", ";FDDM centrality (%)", kTH1D, {{nBins, 0, 105.}}); - histos.add("hCentNTPV", ";NTPV centrality (%)", kTH1D, {{nBins, 0, 105.}}); - histos.add("hCentNGlobal", ";NGlobal centrality (%)", kTH1D, {{nBins, 0, 105.}}); - histos.add("hCentMFT", ";MFT centrality (%)", kTH1D, {{nBins, 0, 105.}}); - histos.add("hCentFT0MAnchorCols", ";FT0MAnchorCols centrality (%)", kTH1D, {{nBins, 0, 105.}}); - histos.add("hCentFT0MAnchorBCs", ";FT0MAnchorBCs centrality (%)", kTH1D, {{nBins, 0, 105.}}); - - // profiles of midrapidity multiplicity density - histos.add("hCentProfileFV0A", ";FV0A centrality (%)", kTProfile, {{nBins, 0, 105.}}); - histos.add("hCentProfileFT0M", ";FT0M centrality (%)", kTProfile, {{nBins, 0, 105.}}); - histos.add("hCentProfileFT0MOuterA", ";FT0M centrality (%)", kTProfile, {{nBins, 0, 105.}}); - histos.add("hCentProfileFT0A", ";FT0A centrality (%)", kTProfile, {{nBins, 0, 105.}}); - histos.add("hCentProfileFT0C", ";FT0C centrality (%)", kTProfile, {{nBins, 0, 105.}}); - histos.add("hCentProfileFT0CVar1", ";FT0CVar1 centrality (%)", kTProfile, {{nBins, 0, 105.}}); - histos.add("hCentProfileFT0CVar2", ";FT0CVar2 centrality (%)", kTProfile, {{nBins, 0, 105.}}); - histos.add("hCentProfileFDDM", ";FDDM centrality (%)", kTProfile, {{nBins, 0, 105.}}); - histos.add("hCentProfileNTPV", ";NTPV centrality (%)", kTProfile, {{nBins, 0, 105.}}); - histos.add("hCentProfileNGlobal", ";NGlobal centrality (%)", kTProfile, {{nBins, 0, 105.}}); - histos.add("hCentProfileMFT", ";MFT centrality (%)", kTProfile, {{nBins, 0, 105.}}); - histos.add("hCentProfileFT0MAnchorCols", ";FT0MAnchorCols centrality (%)", kTProfile, {{nBins, 0, 105.}}); - histos.add("hCentProfileFT0MAnchorBCs", ";FT0MAnchorBCs centrality (%)", kTProfile, {{nBins, 0, 105.}}); - - histos.add("hMultEta05VsCentFV0A", ";FV0A centrality (%); Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {{nBins, 0, 105.}, axisMultiplicityPV}); - histos.add("hMultEta05VsCentFT0M", ";FT0M centrality (%); Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {{nBins, 0, 105.}, axisMultiplicityPV}); - histos.add("hMultEta05VsCentFT0MOuterA", ";FT0M centrality (%); Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {{nBins, 0, 105.}, axisMultiplicityPV}); - histos.add("hMultEta05VsCentFT0A", ";FT0A centrality (%); Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {{nBins, 0, 105.}, axisMultiplicityPV}); - histos.add("hMultEta05VsCentFT0C", ";FT0C centrality (%); Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {{nBins, 0, 105.}, axisMultiplicityPV}); - histos.add("hMultEta05VsCentFT0CVar1", ";FT0CVar1 centrality (%); Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {{nBins, 0, 105.}, axisMultiplicityPV}); - histos.add("hMultEta05VsCentFT0CVar2", ";FT0CVar2 centrality (%); Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {{nBins, 0, 105.}, axisMultiplicityPV}); - histos.add("hMultEta05VsCentFDDM", ";FDDM centrality (%); Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {{nBins, 0, 105.}, axisMultiplicityPV}); - histos.add("hMultEta05VsCentNTPV", ";NTPV centrality (%); Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {{nBins, 0, 105.}, axisMultiplicityPV}); - histos.add("hMultEta05VsCentNGlobal", ";NGlobal centrality (%); Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {{nBins, 0, 105.}, axisMultiplicityPV}); - histos.add("hMultEta05VsCentMFT", ";MFT centrality (%); Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {{nBins, 0, 105.}, axisMultiplicityPV}); - histos.add("hMultEta05VsCentFT0MAnchorCols", ";FT0MAnchorCols centrality (%); Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {{nBins, 0, 105.}, axisMultiplicityPV}); - histos.add("hMultEta05VsCentFT0MAnchorBCs", ";FT0MAnchorBCs centrality (%); Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {{nBins, 0, 105.}, axisMultiplicityPV}); - - if (isMC) { - histos.add("hMultEta05VsGenMultFV0A", ";Multiplicity FV0A; Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {axisMultiplicity, axisMultiplicityPV}); - histos.add("hMultEta05VsGenMultFT0M", ";Multiplicity FT0M; Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {axisMultiplicity, axisMultiplicityPV}); - histos.add("hMultEta05VsGenMultFT0MAnchorCols", ";Multiplicity FT0MAnchorCols; Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {axisMultiplicity, axisMultiplicityPV}); - histos.add("hMultEta05VsGenMultFT0MAnchorBCs", ";Multiplicity FT0MAnchorBCs; Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {axisMultiplicity, axisMultiplicityPV}); - histos.add("hMultEta05VsGenMultFT0A", ";Multiplicity FT0A; Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {axisMultiplicity, axisMultiplicityPV}); - histos.add("hMultEta05VsGenMultFT0C", ";Multiplicity FT0C; Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {axisMultiplicity, axisMultiplicityPV}); - histos.add("hMultEta05VsGenMultFT0CVar1", ";Multiplicity FT0CVar1; Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {axisMultiplicity, axisMultiplicityPV}); - histos.add("hMultEta05VsGenMultFT0CVar2", ";Multiplicity FT0CVar2; Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {axisMultiplicity, axisMultiplicityPV}); - histos.add("hMultEta05VsGenMultFDDM", ";Multiplicity FDDM; Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {axisMultiplicity, axisMultiplicityPV}); - histos.add("hMultEta05VsGenMultNTPV", ";Multiplicity NTPV; Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {axisMultiplicity, axisMultiplicityPV}); - histos.add("hMultEta05VsGenMultNGlobal", ";Multiplicity NGlobal; Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {axisMultiplicity, axisMultiplicityPV}); - histos.add("hMultEta05VsGenMultMFT", ";Multiplicity MFT; Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {axisMultiplicity, axisMultiplicityPV}); - - histos.add("hGenMultEta05VsCentralityFV0A", ";FV0A Centrality (%); Generated multiplicity (|#it{#eta}| < 0.5)", kTH2D, {axisCentrality, axisMultiplicityPV}); - histos.add("hGenMultEta05VsCentralityFT0M", ";FT0M Centrality (%); Generated multiplicity (|#it{#eta}| < 0.5)", kTH2D, {axisCentrality, axisMultiplicityPV}); - histos.add("hGenMultEta05VsCentralityFT0A", ";FT0A Centrality (%); Generated multiplicity (|#it{#eta}| < 0.5)", kTH2D, {axisCentrality, axisMultiplicityPV}); - histos.add("hGenMultEta05VsCentralityFT0C", ";FT0C Centrality (%); Generated multiplicity (|#it{#eta}| < 0.5)", kTH2D, {axisCentrality, axisMultiplicityPV}); - histos.add("hGenMultEta05VsCentralityFT0CVar1", ";FT0CVar1 Centrality (%); Generated multiplicity (|#it{#eta}| < 0.5)", kTH2D, {axisCentrality, axisMultiplicityPV}); - histos.add("hGenMultEta05VsCentralityFT0CVar2", ";FT0CVar2 Centrality (%); Generated multiplicity (|#it{#eta}| < 0.5)", kTH2D, {axisCentrality, axisMultiplicityPV}); - histos.add("hGenMultEta05VsCentralityFDDM", ";FDDM Centrality (%); Generated multiplicity (|#it{#eta}| < 0.5)", kTH2D, {axisCentrality, axisMultiplicityPV}); - histos.add("hGenMultEta05VsCentralityNTPV", ";NTPV Centrality (%); Generated multiplicity (|#it{#eta}| < 0.5)", kTH2D, {axisCentrality, axisMultiplicityPV}); - histos.add("hGenMultEta05VsCentralityNGlobal", ";NGlobal Centrality (%); Generated multiplicity (|#it{#eta}| < 0.5)", kTH2D, {axisCentrality, axisMultiplicityPV}); - histos.add("hGenMultEta05VsCentralityMFT", ";MFT Centrality (%); Generated multiplicity (|#it{#eta}| < 0.5)", kTH2D, {axisCentrality, axisMultiplicityPV}); - - histos.add("hGenMultVsCentralityFV0A", ";FV0A Centrality (%); Generated multiplicity FV0A", kTH2D, {axisCentrality, axisMultiplicityPV}); - histos.add("hGenMultVsCentralityFT0M", ";FT0M Centrality (%); Generated multiplicity FT0M", kTH2D, {axisCentrality, axisMultiplicityPV}); - histos.add("hGenMultVsCentralityFT0A", ";FT0A Centrality (%); Generated multiplicity FT0A", kTH2D, {axisCentrality, axisMultiplicityPV}); - histos.add("hGenMultVsCentralityFT0C", ";FT0C Centrality (%); Generated multiplicity FT0C", kTH2D, {axisCentrality, axisMultiplicityPV}); - histos.add("hGenMultVsCentralityFT0CVar1", ";FT0CVar1 Centrality (%); Generated multiplicity FT0C", kTH2D, {axisCentrality, axisMultiplicityPV}); - histos.add("hGenMultVsCentralityFT0CVar2", ";FT0CVar2 Centrality (%); Generated multiplicity FT0C", kTH2D, {axisCentrality, axisMultiplicityPV}); - histos.add("hGenMultVsCentralityFDDM", ";FDDM Centrality (%); Generated multiplicity FDDM", kTH2D, {axisCentrality, axisMultiplicityPV}); - histos.add("hGenMultVsCentralityNTPV", ";NTPV Centrality (%); Generated multiplicity NTPV", kTH2D, {axisCentrality, axisMultiplicityPV}); - histos.add("hGenMultVsCentralityNGlobal", ";NGlobal Centrality (%); Generated multiplicity global tracks", kTH2D, {axisCentrality, axisMultiplicityPV}); - histos.add("hGenMultVsCentralityMFT", ";MFT Centrality (%); Generated multiplicity MFT", kTH2D, {axisCentrality, axisMultiplicityPV}); + estimators.resize(NEstimators); + estimators[FV0A] = initEstimator(studies.fv0a.value, "FV0", "FV0A"); + estimators[FT0M] = initEstimator(studies.ft0m.value, "FT0", "FT0M"); + estimators[FT0MAnchorCol] = initEstimator(studies.ft0mAnchorCol.value, "FT0MAnchorCol", "FT0MAnchorCol"); + estimators[FT0MAnchorBC] = initEstimator(studies.ft0mAnchorBc.value, "FT0MAnchorBc", "FT0MAnchorBc"); + estimators[FT0MOuterA] = initEstimator(studies.ft0mOuterA.value, "FT0MOuterA", "FT0MOuterA"); + estimators[FT0A] = initEstimator(studies.ft0a.value, "FT0A", "FT0A"); + estimators[FT0C] = initEstimator(studies.ft0c.value, "FT0C", "FT0C"); + estimators[FT0CVar1] = initEstimator(studies.ft0cVar1.value, "FT0CVariant1", "FT0CVariant1"); + estimators[FT0CVar2] = initEstimator(studies.ft0cVar2.value, "FT0CVariant2", "FT0CVariant2"); + estimators[FDDM] = initEstimator(studies.fddm.value, "FDDM", "FDDM"); + estimators[NTPV] = initEstimator(studies.ntpv.value, "NTracksPV", "NTPV"); + estimators[NGlobal] = initEstimator(studies.nGlo.value, "NGlobal", "NGlobal"); + estimators[MFT] = initEstimator(studies.mft.value, "MFT", "MFT"); + + if (doprocessRun2) { + insertHist("hCentRun2V0M", ";V0M centrality (%)", kTH1D, {axisCentrality}); + insertHist("hCentRun2V0A", ";V0A centrality (%)", kTH1D, {axisCentrality}); + insertHist("hCentRun2SPDTks", ";SPD tracklet centrality (%)", kTH1D, {axisCentrality}); + insertHist("hCentRun2SPDCls", ";SPD cluster centrality (%)", kTH1D, {axisCentrality}); + insertHist("hCentRun2CL0", ";CL0 centrality (%)", kTH1D, {axisCentrality}); + insertHist("hCentRun2CL1", ";CL1 centrality (%)", kTH1D, {axisCentrality}); + } + + if (doprocessRun3 || doprocessRun3MonteCarlo) { + for (int iEst = 0; iEst < NEstimators; ++iEst) { + const Estimator& est = estimators[iEst]; + if (!est.doStudy) { + continue; + } + insertHist("hCent" + est.histName, ";" + est.histName + " centrality (%)", kTH1D, {axisCentrality}); + insertHist("hCentProfile" + est.histName, ";" + est.histName + " centrality (%)", kTProfile, {axisCentrality}); + insertHist("hMultEta05VsCent" + est.histName, ";" + est.histName + " Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {axisCentrality, axisMultiplicityPV}); + if (doprocessRun3MonteCarlo) { + insertHist("hMultEta05VsGenMult" + est.histName, ";Multiplicity " + est.histName + ";Multiplicity PV contributors (|#it{#eta}| < 0.5)", kTH2D, {axisMultiplicity, axisMultiplicityPV}); + insertHist("hGenMultEta05VsCentrality" + est.histName, ";" + est.histName + " Centrality (%); Generated multiplicity (|#it{#eta}| < 0.5)", kTH2D, {axisCentrality, axisMultiplicityPV}); + insertHist("hGenMultVsCentrality" + est.histName, ";" + est.histName + " Centrality (%); Generated multiplicity " + est.estName, kTH2D, {axisCentrality, axisMultiplicityPV}); + } } } if (doprocessBunchCrossings) { - histos.add("hBCSelection", "hBCSelection", kTH1D, {{20, -0.5, 19.5f}}); - histos.get(HIST("hBCSelection"))->GetXaxis()->SetBinLabel(1, "All BCs"); - histos.get(HIST("hBCSelection"))->GetXaxis()->SetBinLabel(2, "Colliding BCs"); - histos.get(HIST("hBCSelection"))->GetXaxis()->SetBinLabel(3, "TVX"); - histos.get(HIST("hBCSelection"))->GetXaxis()->SetBinLabel(4, "FV0OrA"); - histos.get(HIST("hBCSelection"))->GetXaxis()->SetBinLabel(5, "FT0PosZ"); - histos.get(HIST("hBCSelection"))->GetXaxis()->SetBinLabel(6, "BB with FT0"); - histos.get(HIST("hBCSelection"))->GetXaxis()->SetBinLabel(7, "zdc rej"); - histos.get(HIST("hBCSelection"))->GetXaxis()->SetBinLabel(8, "isFlangeEvent"); - histos.add("hAmpVsChFT0A", "hAmpVsChFT0A;Channel; Amplitude", kTH2D, {{96, -0.5, 95.5}, axisChannelAmplitude}); - histos.add("hAmpVsChFT0C", "hAmpVsChFT0C;Channel; Amplitude", kTH2D, {{112, -0.5, 111.5}, axisChannelAmplitude}); + insertHist("hBCSelection", "hBCSelection", kTH1D, {{20, -0.5, 19.5f}}); + getHist("hBCSelection")->GetXaxis()->SetBinLabel(1, "All BCs"); + getHist("hBCSelection")->GetXaxis()->SetBinLabel(2, "Colliding BCs"); + getHist("hBCSelection")->GetXaxis()->SetBinLabel(3, "TVX"); + getHist("hBCSelection")->GetXaxis()->SetBinLabel(4, "FV0OrA"); + getHist("hBCSelection")->GetXaxis()->SetBinLabel(5, "FT0PosZ"); + getHist("hBCSelection")->GetXaxis()->SetBinLabel(6, "BB with FT0"); + getHist("hBCSelection")->GetXaxis()->SetBinLabel(7, "zdc rej"); + getHist("hBCSelection")->GetXaxis()->SetBinLabel(8, "isFlangeEvent"); + insertHist("hAmpVsChFT0A", "hAmpVsChFT0A;Channel; Amplitude", kTH2D, {{96, -0.5, 95.5}, axisChannelAmplitude}); + insertHist("hAmpVsChFT0C", "hAmpVsChFT0C;Channel; Amplitude", kTH2D, {{112, -0.5, 111.5}, axisChannelAmplitude}); } histos.print(); } template - Estimator initEstimator(const TCollision& col, const std::string& name) + bool isCollisionAccepted(TCollision const& collision) + // check whether the collision passes our collision selections { - Estimator est(this, name); - if (centrality.useCustomCalibration) { - if (!col.has_foundBC()) { - return est; - } - - const auto bc = col.template foundBC_as(); - if (bc.runNumber() != runNumber) { - runNumber = bc.runNumber(); - LOGF(info, "Acquiring centrality calibration for run %i", runNumber); - hCentralityObjects = ccdb->getForRun(centrality.pathCentrality, runNumber); - if (!hCentralityObjects) { - LOGF(info, "No centrality calibration list found for run %i", runNumber); - } - } + if (eventSelections.requireSel8 && !collision.sel8()) { + return false; + } - if (!hCentralityObjects) { - est.hCentrality = nullptr; - return est; - } + if (eventSelections.requireTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } - est.hCentrality = dynamic_cast(hCentralityObjects->FindObject(Form("hCalibZeq%s", est.name.c_str()))); - if (!est.hCentrality) { - LOGF(debug, "Calibration missing for %s", est.name.c_str()); - } else { - LOGF(debug, "Calibration loaded for %s", est.name.c_str()); - } + if (eventSelections.rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; } - return est; - } + if (eventSelections.rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } - template - bool isCollisionAccepted(TCollision const& collision) - // check whether the collision passes our collision selections - { - if constexpr ( - requires { collision.centFV0A(); } || - requires { collision.centFT0M(); } || - requires { collision.centFT0A(); } || - requires { collision.centFT0C(); } || - requires { collision.centFT0CVariant1(); } || - requires { collision.centFT0CVariant2(); } || - requires { collision.centFT0MOuterA(); } || - requires { collision.centFDDM(); } || - requires { collision.centNTPV(); } || - requires { collision.centNGlobal(); } || - requires { collision.centMFT(); } || - requires { collision.centFT0MAnchorCol(); } || - requires { collision.centFT0MAnchorBC(); }) { // check if we are in Run 3 - if (eventSelections.requireSel8 && !collision.sel8()) { - return false; - } + if (std::abs(collision.posZ()) > eventSelections.maxZVtxPosition) { + return false; + } - if (eventSelections.requireTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { - return false; - } + if (eventSelections.requireIsBBT0A && !collision.selection_bit(aod::evsel::kIsBBT0A)) { + return false; + } - if (eventSelections.rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { - return false; - } + if (eventSelections.requireIsBBT0C && !collision.selection_bit(aod::evsel::kIsBBT0C)) { + return false; + } - if (eventSelections.rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { - return false; - } + if (eventSelections.requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } - if (std::abs(collision.posZ()) > eventSelections.maxZVtxPosition) { - return false; - } + if (eventSelections.requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } - if (eventSelections.requireIsBBT0A && !collision.selection_bit(aod::evsel::kIsBBT0A)) { - return false; - } + if (eventSelections.requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + return false; + } - if (eventSelections.requireIsBBT0C && !collision.selection_bit(aod::evsel::kIsBBT0C)) { - return false; - } + if (eventSelections.requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + return false; + } - if (eventSelections.requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { - return false; - } + if (eventSelections.rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } - if (eventSelections.requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { - return false; - } + if (eventSelections.requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } - if (eventSelections.requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { - return false; - } + if (eventSelections.requireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + return false; + } - if (eventSelections.requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { - return false; - } + if (eventSelections.requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + return false; + } - if (eventSelections.rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { - return false; - } + if (eventSelections.requireNoCollInROFStd && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } - if (eventSelections.requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { - return false; - } + if (eventSelections.requireNoCollInROFStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + return false; + } - if (eventSelections.requireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { - return false; - } + static constexpr int OneTrackInEta1 = 1; + if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < OneTrackInEta1) { + return false; + } - if (eventSelections.requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { - return false; - } + static constexpr int TwoTracksInEta1 = 2; + if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < TwoTracksInEta1) { + return false; + } - if (eventSelections.requireNoCollInROFStd && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { - return false; - } + float collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + if (eventSelections.minOccupancy >= 0 && collisionOccupancy < eventSelections.minOccupancy) { + return false; + } - if (eventSelections.requireNoCollInROFStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { - return false; - } + if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { + return false; + } - static constexpr int OneTrackInEta1 = 1; - if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < OneTrackInEta1) { + if constexpr (requires { collision.has_mcCollision(); }) { // check if we are in MC + if (!collision.has_mcCollision()) { return false; } - static constexpr int TwoTracksInEta1 = 2; - if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < TwoTracksInEta1) { - return false; - } + const auto& mcCollision = collision.template mcCollision_as>(); + const auto& recoBC = collision.template bc_as(); + const auto& foundBC = collision.template foundBC_as(); + const auto& mcBC = mcCollision.template bc_as(); - float collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); - if (eventSelections.minOccupancy >= 0 && collisionOccupancy < eventSelections.minOccupancy) { + // Check that the BC in data and MC is the same + if (eventSelections.rejectMismatchedBCs && recoBC.globalBC() != mcBC.globalBC()) { return false; } - - if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { + if (eventSelections.rejectMismatchedFoundBCs && foundBC.globalBC() != mcBC.globalBC()) { return false; } + } - if constexpr (requires { collision.has_mcCollision(); }) { // check if we are in MC - if (!collision.has_mcCollision()) { - return false; - } - - const auto& mcCollision = collision.template mcCollision_as>(); - const auto& recoBC = collision.template bc_as>(); - const auto& foundBC = collision.template foundBC_as>(); - const auto& mcBC = mcCollision.template bc_as>(); + return true; + } - // Check that the BC in data and MC is the same - if (eventSelections.rejectMismatchedBCs && recoBC.globalBC() != mcBC.globalBC()) { - return false; - } - if (eventSelections.rejectMismatchedFoundBCs && foundBC.globalBC() != mcBC.globalBC()) { - return false; - } - } - } else { // we are in Run 2 - if (eventSelections.requireSel8 && !collision.sel8()) { - return false; - } + template + bool isCollisionAcceptedRun2(TCollision const& collision) + // check whether the collision passes our collision selections + { + if (eventSelections.requireSel8 && !collision.sel8()) { + return false; + } - if (eventSelections.requireSel7 && !collision.sel7()) { - return false; - } + if (eventSelections.requireSel7 && !collision.sel7()) { + return false; + } - if (eventSelections.requireINT7 && !collision.alias_bit(kINT7)) { - return false; - } + if (eventSelections.requireINT7 && !collision.alias_bit(kINT7)) { + return false; + } - if (eventSelections.requireTriggerTVX && !collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { - return false; - } + if (eventSelections.requireTriggerTVX && !collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + return false; + } - if (eventSelections.rejectIncompleteDAQ && !collision.selection_bit(o2::aod::evsel::kNoIncompleteDAQ)) { - return false; - } + if (eventSelections.rejectIncompleteDAQ && !collision.selection_bit(o2::aod::evsel::kNoIncompleteDAQ)) { + return false; + } - if (std::abs(collision.posZ()) > eventSelections.maxZVtxPosition) { - return false; - } + if (std::abs(collision.posZ()) > eventSelections.maxZVtxPosition) { + return false; + } - if (eventSelections.requireConsistentSPDAndTrackVtx && !collision.selection_bit(o2::aod::evsel::kNoInconsistentVtx)) { - return false; - } + if (eventSelections.requireConsistentSPDAndTrackVtx && !collision.selection_bit(o2::aod::evsel::kNoInconsistentVtx)) { + return false; + } - if (eventSelections.rejectPileupFromSPD && !collision.selection_bit(o2::aod::evsel::kNoPileupFromSPD)) { - return false; - } + if (eventSelections.rejectPileupFromSPD && !collision.selection_bit(o2::aod::evsel::kNoPileupFromSPD)) { + return false; + } - if (eventSelections.rejectV0PFPileup && !collision.selection_bit(o2::aod::evsel::kNoV0PFPileup)) { - return false; - } + if (eventSelections.rejectV0PFPileup && !collision.selection_bit(o2::aod::evsel::kNoV0PFPileup)) { + return false; + } - if (eventSelections.rejectPileupInMultBins && !collision.selection_bit(o2::aod::evsel::kNoPileupInMultBins)) { - return false; - } + if (eventSelections.rejectPileupInMultBins && !collision.selection_bit(o2::aod::evsel::kNoPileupInMultBins)) { + return false; + } - if (eventSelections.rejectPileupMV && !collision.selection_bit(o2::aod::evsel::kNoPileupMV)) { - return false; - } + if (eventSelections.rejectPileupMV && !collision.selection_bit(o2::aod::evsel::kNoPileupMV)) { + return false; + } - if (eventSelections.rejectTPCPileup && !collision.selection_bit(o2::aod::evsel::kNoPileupTPC)) { - return false; - } + if (eventSelections.rejectTPCPileup && !collision.selection_bit(o2::aod::evsel::kNoPileupTPC)) { + return false; + } - if (eventSelections.requireNoV0MOnVsOffPileup && !collision.selection_bit(o2::aod::evsel::kNoV0MOnVsOfPileup)) { - return false; - } + if (eventSelections.requireNoV0MOnVsOffPileup && !collision.selection_bit(o2::aod::evsel::kNoV0MOnVsOfPileup)) { + return false; + } - if (eventSelections.requireNoSPDOnVsOffPileup && !collision.selection_bit(o2::aod::evsel::kNoSPDOnVsOfPileup)) { - return false; - } + if (eventSelections.requireNoSPDOnVsOffPileup && !collision.selection_bit(o2::aod::evsel::kNoSPDOnVsOfPileup)) { + return false; + } - if (eventSelections.requireNoSPDClsVsTklBG && !collision.selection_bit(o2::aod::evsel::kNoSPDClsVsTklBG)) { - return false; - } + if (eventSelections.requireNoSPDClsVsTklBG && !collision.selection_bit(o2::aod::evsel::kNoSPDClsVsTklBG)) { + return false; + } - static constexpr int OneTrackInEta1 = 1; - if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < OneTrackInEta1) { - return false; - } + static constexpr int OneTrackInEta1 = 1; + if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < OneTrackInEta1) { + return false; + } - static constexpr int TwoTracksInEta1 = 2; - if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < TwoTracksInEta1) { - return false; - } + static constexpr int TwoTracksInEta1 = 2; + if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < TwoTracksInEta1) { + return false; } return true; @@ -636,514 +627,260 @@ struct CentralityQa { return true; } - void processRun2PP(soa::Join::iterator const& col) - { - if (!isCollisionAccepted(col)) { - return; - } - LOGF(debug, "centV0M=%.0f", col.centRun2V0M()); - LOGF(debug, "centSPDTracklets=%.0f", col.centRun2SPDTracklets()); - LOGF(debug, "centSPDClusters=%.0f", col.centRun2SPDClusters()); - // fill centrality histos - histos.fill(HIST("hCentRun2V0M"), col.centRun2V0M()); - histos.fill(HIST("hCentRun2SPDTks"), col.centRun2SPDTracklets()); - histos.fill(HIST("hCentRun2SPDCls"), col.centRun2SPDClusters()); - } - PROCESS_SWITCH(CentralityQa, processRun2PP, "Process with Run2 SPD clusters centrality/multiplicity estimation", false); - - void processRun2PbPb(soa::Join::iterator const& col) - { - if (!isCollisionAccepted(col)) { - return; - } - LOGF(debug, "centV0M=%.0f", col.centRun2V0M()); - LOGF(debug, "centSPDTracklets=%.0f", col.centRun2SPDTracklets()); - LOGF(debug, "centCL0=%.0f", col.centRun2CL0()); - LOGF(debug, "centCL1=%.0f", col.centRun2CL1()); - // fill centrality histos - histos.fill(HIST("hCentRun2V0M"), col.centRun2V0M()); - histos.fill(HIST("hCentRun2SPDTks"), col.centRun2SPDTracklets()); - histos.fill(HIST("hCentRun2CL0"), col.centRun2CL0()); - histos.fill(HIST("hCentRun2CL1"), col.centRun2CL1()); - } - PROCESS_SWITCH(CentralityQa, processRun2PbPb, "Process with Run2 CL0 and CL1 multiplicities centrality/multiplicity estimation", false); - - void processRun2PPb(soa::Join::iterator const& col) - { - if (!isCollisionAccepted(col)) { - return; - } - LOGF(debug, "centV0A=%.0f", col.centRun2V0A()); - // fill centrality histos - histos.fill(HIST("hCentRun2V0A"), col.centRun2V0A()); - } - PROCESS_SWITCH(CentralityQa, processRun2PPb, "Process with Run2 V0A multiplicitY centrality/multiplicity estimation", false); - - void processRun3_FV0A(soa::Join::iterator const& col, aod::BCs const&) - { - if (!isCollisionAccepted(col)) { - return; - } - - Estimator fv0a = initEstimator(col, "FV0"); - const float centFV0A = fv0a.getCentrality(col.multFV0A(), col.centFV0A()); - - LOGF(debug, "centFV0A=%.0f", centFV0A); - histos.fill(HIST("hCentFV0A"), centFV0A); - histos.fill(HIST("hCentProfileFV0A"), centFV0A, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentFV0A"), centFV0A, col.multNTracksPVetaHalf()); - } - PROCESS_SWITCH(CentralityQa, processRun3_FV0A, "Process with Run 3 FV0A estimator", false); - - void processRun3_FT0M(soa::Join::iterator const& col, aod::BCs const&) - { - if (!isCollisionAccepted(col)) { - return; - } - - Estimator ft0m = initEstimator(col, "FT0"); - const float centFT0M = ft0m.getCentrality(col.multFT0M(), col.centFT0M()); - - LOGF(debug, "centFT0M=%.0f", centFT0M); - histos.fill(HIST("hCentFT0M"), centFT0M); - histos.fill(HIST("hCentProfileFT0M"), centFT0M, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentFT0M"), centFT0M, col.multNTracksPVetaHalf()); - } - PROCESS_SWITCH(CentralityQa, processRun3_FT0M, "Process with Run 3 FT0M estimator", false); - - void processRun3_FT0MOuterA(soa::Join::iterator const& col, aod::BCs const&) - { - if (!isCollisionAccepted(col)) { - return; - } - - Estimator ft0mOuterA = initEstimator(col, "FT0MOuterA"); - const float centFT0MOuterA = ft0mOuterA.getCentrality(col.multFT0AOuter() + col.multFT0C(), col.centFT0MOuterA()); - - LOGF(debug, "centFT0MOuterA=%.0f", centFT0MOuterA); - histos.fill(HIST("hCentFT0MOuterA"), centFT0MOuterA); - histos.fill(HIST("hCentProfileFT0MOuterA"), centFT0MOuterA, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentFT0MOuterA"), centFT0MOuterA, col.multNTracksPVetaHalf()); - } - PROCESS_SWITCH(CentralityQa, processRun3_FT0MOuterA, "Process with Run 3 FT0M estimator", false); - - void processRun3_FT0A(soa::Join::iterator const& col) - { - if (!isCollisionAccepted(col)) { - return; - } - - Estimator ft0a = initEstimator(col, "FT0A"); - const float centFT0A = ft0a.getCentrality(col.multFT0A(), col.centFT0A()); - - LOGF(debug, "centFT0A=%.0f", centFT0A); - histos.fill(HIST("hCentFT0A"), centFT0A); - histos.fill(HIST("hCentProfileFT0A"), centFT0A, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentFT0A"), centFT0A, col.multNTracksPVetaHalf()); - } - PROCESS_SWITCH(CentralityQa, processRun3_FT0A, "Process with Run 3 FT0A estimator", false); - - void processRun3_FT0C(soa::Join::iterator const& col, aod::BCs const&) - { - if (!isCollisionAccepted(col)) { - return; - } - - Estimator ft0c = initEstimator(col, "FT0C"); - const float centFT0C = ft0c.getCentrality(col.multFT0C(), col.centFT0C()); - - LOGF(debug, "centFT0C=%.0f", centFT0C); - histos.fill(HIST("hCentFT0C"), centFT0C); - histos.fill(HIST("hCentProfileFT0C"), centFT0C, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentFT0C"), centFT0C, col.multNTracksPVetaHalf()); - } - PROCESS_SWITCH(CentralityQa, processRun3_FT0C, "Process with Run 3 FT0C estimator", false); - - void processRun3_FT0CVar1(soa::Join::iterator const& col, aod::BCs const&) - { - if (!isCollisionAccepted(col)) { - return; - } - - Estimator ft0cVar1 = initEstimator(col, "FT0CVariant1"); - const float centFT0Cvar1 = ft0cVar1.getCentrality(col.multFT0C(), col.centFT0CVariant1()); - - LOGF(debug, "centFT0Cvar1=%.0f", centFT0Cvar1); - histos.fill(HIST("hCentFT0CVar1"), centFT0Cvar1); - histos.fill(HIST("hCentProfileFT0CVar1"), centFT0Cvar1, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentFT0CVar1"), centFT0Cvar1, col.multNTracksPVetaHalf()); - } - PROCESS_SWITCH(CentralityQa, processRun3_FT0CVar1, "Process with Run 3 FT0CVar1 estimator", false); - - void processRun3_FT0CVar2(soa::Join::iterator const& col, aod::BCs const&) - { - if (!isCollisionAccepted(col)) { - return; - } - - Estimator ft0cVar2 = initEstimator(col, "FT0CVariant2"); - const float centFT0Cvar2 = ft0cVar2.getCentrality(col.multFT0C(), col.centFT0CVariant2()); - - LOGF(debug, "centFT0Cvar2=%.0f", centFT0Cvar2); - histos.fill(HIST("hCentFT0CVar2"), centFT0Cvar2); - histos.fill(HIST("hCentProfileFT0CVar2"), centFT0Cvar2, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentFT0CVar2"), centFT0Cvar2, col.multNTracksPVetaHalf()); - } - PROCESS_SWITCH(CentralityQa, processRun3_FT0CVar2, "Process with Run 3 FT0CVar2 estimator", false); - - void processRun3_FDDM(soa::Join::iterator const& col, aod::BCs const&) - { - if (!isCollisionAccepted(col)) { - return; - } - - Estimator fddm = initEstimator(col, "FDDM"); - const float centFDDM = fddm.getCentrality(col.multFDDM(), col.centFDDM()); - - LOGF(debug, "centFDDM=%.0f", centFDDM); - histos.fill(HIST("hCentFDDM"), centFDDM); - histos.fill(HIST("hCentProfileFDDM"), centFDDM, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentFDDM"), centFDDM, col.multNTracksPVetaHalf()); - } - PROCESS_SWITCH(CentralityQa, processRun3_FDDM, "Process with Run 3 FDDM estimator", false); - - void processRun3_NTPV(soa::Join::iterator const& col, aod::BCs const&) - { - if (!isCollisionAccepted(col)) { - return; - } - - Estimator ntpv = initEstimator(col, "NTPV"); - const float centNTPV = ntpv.getCentrality(col.multNTracksPV(), col.centNTPV()); - - LOGF(debug, "centNTPV=%.0f", centNTPV); - histos.fill(HIST("hCentNTPV"), centNTPV); - histos.fill(HIST("hCentProfileNTPV"), centNTPV, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentNTPV"), centNTPV, col.multNTracksPVetaHalf()); - } - PROCESS_SWITCH(CentralityQa, processRun3_NTPV, "Process with Run 3 NTPV estimator", false); - - void processRun3_NGlobal(soa::Join::iterator const& col, aod::BCs const&) - { - if (!isCollisionAccepted(col)) { - return; - } - - Estimator nGlo = initEstimator(col, "nGlo"); - const float centNGlo = nGlo.getCentrality(col.multNTracksGlobal(), col.centNGlobal()); - - LOGF(debug, "centNGlo=%.0f", centNGlo); - histos.fill(HIST("hCentNGlobal"), centNGlo); - histos.fill(HIST("hCentProfileNGlobal"), centNGlo, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentNGlobal"), centNGlo, col.multNTracksPVetaHalf()); - } - PROCESS_SWITCH(CentralityQa, processRun3_NGlobal, "Process with Run 3 NGlobal estimator", false); - - void processRun3_MFT(soa::Join::iterator const& col, aod::BCs const&) - { - if (!isCollisionAccepted(col)) { - return; - } - - Estimator mft = initEstimator(col, "MFT"); - const float centMFT = mft.getCentrality(col.mftNtracks(), col.centMFT()); - - LOGF(debug, "centMFT=%.0f", centMFT); - histos.fill(HIST("hCentMFT"), centMFT); - histos.fill(HIST("hCentProfileMFT"), centMFT, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentMFT"), centMFT, col.multNTracksPVetaHalf()); - } - PROCESS_SWITCH(CentralityQa, processRun3_MFT, "Process with Run 3 MFT estimator", false); - - void processRun3_FT0MAnchorCol(soa::Join::iterator const& col) - { - if (!isCollisionAccepted(col)) { - return; - } - - Estimator ft0mAnchorCol = initEstimator(col, "FT0MAnchorCol"); - const float centFT0MAnchorCol = ft0mAnchorCol.getCentrality(col.multFT0M(), col.centFT0MAnchorCol()); - - LOGF(debug, "centFT0MAnchorCol=%.0f", centFT0MAnchorCol); - histos.fill(HIST("hCentFT0MAnchorCols"), centFT0MAnchorCol); - histos.fill(HIST("hCentProfileFT0MAnchorCols"), centFT0MAnchorCol, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentFT0MAnchorCols"), centFT0MAnchorCol, col.multNTracksPVetaHalf()); - } - PROCESS_SWITCH(CentralityQa, processRun3_FT0MAnchorCol, "Process with Run 3 FT0MAnchorCol estimator", false); - - void processRun3_FT0MAnchorBC(soa::Join::iterator const& col) - { - if (!isCollisionAccepted(col)) { - return; - } - - Estimator ft0mAnchorBc = initEstimator(col, "FT0MAnchorBc"); - const float centFT0MAnchorBc = ft0mAnchorBc.getCentrality(col.multFT0M(), col.centFT0MAnchorBC()); - - LOGF(debug, "centFT0MAnchorBc=%.0f", centFT0MAnchorBc); - histos.fill(HIST("hCentFT0MAnchorBCs"), centFT0MAnchorBc); - histos.fill(HIST("hCentProfileFT0MAnchorBCs"), centFT0MAnchorBc, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentFT0MAnchorBCs"), centFT0MAnchorBc, col.multNTracksPVetaHalf()); - } - PROCESS_SWITCH(CentralityQa, processRun3_FT0MAnchorBC, "Process with Run 3 FT0MAnchorBC estimator", false); - - void processMonteCarloRun3_FV0A(soa::Join::iterator const& col, - soa::Join const& /*mcCollisions*/, - soa::Join const& /*bcs*/) - { - if (!isCollisionAccepted(col)) { - return; - } - - const auto& mcCol = col.mcCollision_as>(); - Estimator fv0a = initEstimator(col, "FV0"); - const float centFV0A = fv0a.getCentrality(col.multFV0A(), col.centFV0A()); - - LOGF(debug, "centFV0A=%.0f", centFV0A); - histos.fill(HIST("hCentFV0A"), centFV0A); - histos.fill(HIST("hCentProfileFV0A"), centFV0A, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentFV0A"), centFV0A, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsGenMultFV0A"), mcCol.multMCFV0A(), col.multNTracksPVetaHalf()); - histos.fill(HIST("hGenMultEta05VsCentralityFV0A"), col.centFV0A(), mcCol.multMCNParticlesEta05()); - histos.fill(HIST("hGenMultVsCentralityFV0A"), col.centFV0A(), mcCol.multMCFV0A()); - } - PROCESS_SWITCH(CentralityQa, processMonteCarloRun3_FV0A, "Process with Run 3 FV0A estimator", false); - - void processMonteCarloRun3_FT0M(soa::Join::iterator const& col, - soa::Join const& /*mcCollisions*/, - soa::Join const& /*bcs*/) - { - if (!isCollisionAccepted(col)) { - return; - } - - const auto& mcCol = col.mcCollision_as>(); - Estimator ft0m = initEstimator(col, "FT0"); - const float centFT0M = ft0m.getCentrality(col.multFT0M(), col.centFT0M()); - - LOGF(debug, "centFT0M=%.0f", centFT0M); - histos.fill(HIST("hCentFT0M"), centFT0M); - histos.fill(HIST("hCentProfileFT0M"), centFT0M, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentFT0M"), centFT0M, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsGenMultFT0M"), mcCol.multMCFT0A() + mcCol.multMCFT0C(), col.multNTracksPVetaHalf()); - histos.fill(HIST("hGenMultEta05VsCentralityFT0M"), col.centFT0M(), mcCol.multMCNParticlesEta05()); - histos.fill(HIST("hGenMultVsCentralityFT0M"), col.centFT0M(), mcCol.multMCFT0A() + mcCol.multMCFT0C()); - } - PROCESS_SWITCH(CentralityQa, processMonteCarloRun3_FT0M, "Process with Run 3 FT0M estimator", false); - - void processMonteCarloRun3_FT0A(soa::Join::iterator const& col, - soa::Join const& /*mcCollisions*/, - soa::Join const& /*bcs*/) - { - if (!isCollisionAccepted(col)) { - return; - } - - const auto& mcCol = col.mcCollision_as>(); - Estimator ft0a = initEstimator(col, "FT0A"); - const float centFT0A = ft0a.getCentrality(col.multFT0A(), col.centFT0A()); - - LOGF(debug, "centFT0M=%.0f", centFT0A); - histos.fill(HIST("hCentFT0A"), centFT0A); - histos.fill(HIST("hCentProfileFT0A"), centFT0A, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentFT0A"), centFT0A, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsGenMultFT0A"), mcCol.multMCFT0A(), col.multNTracksPVetaHalf()); - histos.fill(HIST("hGenMultEta05VsCentralityFT0A"), col.centFT0A(), mcCol.multMCNParticlesEta05()); - histos.fill(HIST("hGenMultVsCentralityFT0A"), col.centFT0A(), mcCol.multMCFT0A()); - } - PROCESS_SWITCH(CentralityQa, processMonteCarloRun3_FT0A, "Process with Run 3 FT0A estimator", false); - - void processMonteCarloRun3_FT0C(soa::Join::iterator const& col, - soa::Join const& /*mcCollisions*/, - soa::Join const& /*bcs*/) - { - if (!isCollisionAccepted(col)) { - return; - } - - const auto& mcCol = col.mcCollision_as>(); - Estimator ft0c = initEstimator(col, "FT0C"); - const float centFT0C = ft0c.getCentrality(col.multFT0C(), col.centFT0C()); - - LOGF(debug, "centFT0C=%.0f", centFT0C); - histos.fill(HIST("hCentFT0C"), centFT0C); - histos.fill(HIST("hCentProfileFT0C"), centFT0C, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentFT0C"), centFT0C, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsGenMultFT0C"), mcCol.multMCFT0C(), col.multNTracksPVetaHalf()); - histos.fill(HIST("hGenMultEta05VsCentralityFT0C"), col.centFT0C(), mcCol.multMCNParticlesEta05()); - histos.fill(HIST("hGenMultVsCentralityFT0C"), col.centFT0C(), mcCol.multMCFT0C()); - } - PROCESS_SWITCH(CentralityQa, processMonteCarloRun3_FT0C, "Process with Run 3 FT0C estimator", false); - - void processMonteCarloRun3_FT0CVar1(soa::Join::iterator const& col, - soa::Join const& /*mcCollisions*/, - soa::Join const& /*bcs*/) + template + void fillEstimatorHistos(const TCollision& col, Estimator est, const float mult, const float refCent) { - if (!isCollisionAccepted(col)) { + if (!est.doStudy) { return; } - const auto& mcCol = col.mcCollision_as>(); - Estimator ft0cVar1 = initEstimator(col, "FT0CVariant1"); - const float centFT0Cvar1 = ft0cVar1.getCentrality(col.multFT0C(), col.centFT0CVariant1()); - - LOGF(debug, "centFT0Cvar1=%.0f", centFT0Cvar1); - histos.fill(HIST("hCentFT0CVar1"), centFT0Cvar1); - histos.fill(HIST("hCentProfileFT0CVar1"), centFT0Cvar1, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentFT0CVar1"), centFT0Cvar1, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsGenMultFT0CVar1"), mcCol.multMCFT0C(), col.multNTracksPVetaHalf()); - histos.fill(HIST("hGenMultEta05VsCentralityFT0CVar1"), col.centFT0CVariant1(), mcCol.multMCNParticlesEta05()); - histos.fill(HIST("hGenMultVsCentralityFT0CVar1"), col.centFT0CVariant1(), mcCol.multMCFT0C()); + est.configure(col); + const auto cent = est.getCentrality(mult, refCent); + LOGF(debug, "cent%s=%.0f", est.histName.c_str(), cent); + getHist("hCent" + est.histName)->Fill(cent); + getHist("hMultEta05VsCent" + est.histName)->Fill(cent, col.multNTracksPVetaHalf()); + getHist("hCentProfile" + est.histName)->Fill(cent, col.multNTracksPVetaHalf()); } - PROCESS_SWITCH(CentralityQa, processMonteCarloRun3_FT0CVar1, "Process with Run 3 FT0CVar1 estimator", false); - void processMonteCarloRun3_FT0CVar2(soa::Join::iterator const& col, - soa::Join const& /*mcCollisions*/, - soa::Join const& /*bcs*/) + template + void fillEstimatorMonteCarloHistos(const TMcCollision& mcCol, const Estimator& est, const float multMC, const float cent, const float nPVContribsInEta05) { - if (!isCollisionAccepted(col)) { + if (!est.doStudy) { return; } - const auto& mcCol = col.mcCollision_as>(); - Estimator ft0cVar2 = initEstimator(col, "FT0CVariant2"); - const float centFT0Cvar2 = ft0cVar2.getCentrality(col.multFT0C(), col.centFT0CVariant2()); - - LOGF(debug, "centFT0Cvar2=%.0f", centFT0Cvar2); - histos.fill(HIST("hCentFT0CVar2"), centFT0Cvar2); - histos.fill(HIST("hCentProfileFT0CVar2"), centFT0Cvar2, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentFT0CVar2"), centFT0Cvar2, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsGenMultFT0CVar2"), mcCol.multMCFT0C(), col.multNTracksPVetaHalf()); - histos.fill(HIST("hGenMultEta05VsCentralityFT0CVar2"), col.centFT0CVariant2(), mcCol.multMCNParticlesEta05()); - histos.fill(HIST("hGenMultVsCentralityFT0CVar2"), col.centFT0CVariant2(), mcCol.multMCFT0C()); + getHist("hMultEta05VsGenMult" + est.histName)->Fill(multMC, nPVContribsInEta05); + getHist("hGenMultEta05VsCentrality" + est.histName)->Fill(cent, mcCol.multMCNParticlesEta05()); + getHist("hGenMultVsCentrality" + est.histName)->Fill(cent, multMC); } - PROCESS_SWITCH(CentralityQa, processMonteCarloRun3_FT0CVar2, "Process with Run 3 FT0CVar2 estimator", false); - void processMonteCarloRun3_FDDM(soa::Join::iterator const& col, - soa::Join const& /*mcCollisions*/, - soa::Join const& /*bcs*/) + void processRun2(soa::Join::iterator const& col) { - if (!isCollisionAccepted(col)) { + if (!isCollisionAcceptedRun2(col)) { return; } + LOGF(debug, "centV0M=%.0f", col.centRun2V0M()); + LOGF(debug, "centSPDTracklets=%.0f", col.centRun2SPDTracklets()); + LOGF(debug, "centSPDClusters=%.0f", col.centRun2SPDClusters()); + LOGF(debug, "centCL0=%.0f", col.centRun2CL0()); + LOGF(debug, "centCL1=%.0f", col.centRun2CL1()); + LOGF(debug, "centV0A=%.0f", col.centRun2V0A()); - const auto& mcCol = col.mcCollision_as>(); - Estimator fddm = initEstimator(col, "FDDM"); - const float centFDDM = fddm.getCentrality(col.multFDDM(), col.centFDDM()); - - LOGF(debug, "centFDDM=%.0f", centFDDM); - histos.fill(HIST("hCentFDDM"), centFDDM); - histos.fill(HIST("hCentProfileFDDM"), centFDDM, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentFDDM"), centFDDM, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsGenMultFDDM"), mcCol.multMCFDDA() + mcCol.multMCFDDC(), col.multNTracksPVetaHalf()); - histos.fill(HIST("hGenMultEta05VsCentralityFDDM"), col.centFDDM(), mcCol.multMCNParticlesEta05()); - histos.fill(HIST("hGenMultVsCentralityFDDM"), col.centFDDM(), mcCol.multMCFDDA() + mcCol.multMCFDDC()); + getHist("hCentRun2V0M")->Fill(col.centRun2V0M()); + getHist("hCentRun2SPDTks")->Fill(col.centRun2SPDTracklets()); + getHist("hCentRun2SPDCls")->Fill(col.centRun2SPDClusters()); + getHist("hCentRun2CL0")->Fill(col.centRun2CL0()); + getHist("hCentRun2CL1")->Fill(col.centRun2CL1()); + getHist("hCentRun2V0A")->Fill(col.centRun2V0A()); } - PROCESS_SWITCH(CentralityQa, processMonteCarloRun3_FDDM, "Process with Run 3 FDDM estimator", false); - void processMonteCarloRun3_NTPV(soa::Join::iterator const& col, - soa::Join const& /*mcCollisions*/, - soa::Join const& /*bcs*/) + void processRun3(soa::Join::iterator const& col, + soa::Join const& nGlobals, + soa::Join const& nMFTs, + BCsWithMatching const&) { if (!isCollisionAccepted(col)) { return; } - const auto& mcCol = col.mcCollision_as>(); - Estimator ntpv = initEstimator(col, "NTPV"); - const float centNTPV = ntpv.getCentrality(col.multNTracksPV(), col.centNTPV()); - - histos.fill(HIST("hCentNTPV"), centNTPV); - histos.fill(HIST("hCentProfileNTPV"), centNTPV, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentNTPV"), centNTPV, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsGenMultNTPV"), mcCol.multMCNParticlesEta08(), col.multNTracksPVetaHalf()); - histos.fill(HIST("hGenMultEta05VsCentralityNTPV"), col.centNTPV(), mcCol.multMCNParticlesEta05()); - histos.fill(HIST("hGenMultVsCentralityFDDM"), col.centNTPV(), mcCol.multMCNParticlesEta08()); - } - PROCESS_SWITCH(CentralityQa, processMonteCarloRun3_NTPV, "Process with Run 3 NTPV estimator", false); + fillEstimatorHistos(col, estimators[FV0A], col.multFV0A(), col.centFV0A()); + fillEstimatorHistos(col, estimators[FT0M], col.multFT0M(), col.centFT0M()); + fillEstimatorHistos(col, estimators[FT0MAnchorCol], col.multFT0M(), col.centFT0MAnchorCol()); + fillEstimatorHistos(col, estimators[FT0MAnchorBC], col.multFT0M(), col.centFT0MAnchorBC()); + fillEstimatorHistos(col, estimators[FT0MOuterA], col.multFT0AOuter() + col.multFT0C(), col.centFT0MOuterA()); + fillEstimatorHistos(col, estimators[FT0A], col.multFT0A(), col.centFT0A()); + fillEstimatorHistos(col, estimators[FT0C], col.multFT0C(), col.centFT0C()); + fillEstimatorHistos(col, estimators[FT0CVar1], col.multFT0C(), col.centFT0CVariant1()); + fillEstimatorHistos(col, estimators[FT0CVar2], col.multFT0C(), col.centFT0CVariant2()); + fillEstimatorHistos(col, estimators[FDDM], col.multFDDM(), col.centFDDM()); + fillEstimatorHistos(col, estimators[NTPV], col.multNTracksPV(), col.centNTPV()); + + if (nGlobals.size() > 0) { + const auto& multCentNGlo = nGlobals.rawIteratorAt(col.globalIndex()); + fillEstimatorHistos(col, estimators[NGlobal], multCentNGlo.multNTracksGlobal(), multCentNGlo.centNGlobal()); + } + + if (nMFTs.size() > 0) { + const auto& multCentNMFT = nMFTs.rawIteratorAt(col.globalIndex()); + fillEstimatorHistos(col, estimators[MFT], multCentNMFT.mftNtracks(), multCentNMFT.centMFT()); + } + } + + void processRun3MonteCarlo(soa::Join const& collisions, + soa::Join const& nGlobals, + soa::Join const& nMFTs, + soa::Join const& mcCollisions, + BCsWithMatching const& /*bcs*/) + { + for (const auto& col : collisions) { + if (!isCollisionAccepted(col)) { + continue; + } + + fillEstimatorHistos(col, estimators[FV0A], col.multFV0A(), col.centFV0A()); + fillEstimatorHistos(col, estimators[FT0M], col.multFT0M(), col.centFT0M()); + fillEstimatorHistos(col, estimators[FT0MAnchorCol], col.multFT0M(), col.centFT0MAnchorCol()); + fillEstimatorHistos(col, estimators[FT0MAnchorBC], col.multFT0M(), col.centFT0MAnchorBC()); + fillEstimatorHistos(col, estimators[FT0MOuterA], col.multFT0AOuter() + col.multFT0C(), col.centFT0MOuterA()); + fillEstimatorHistos(col, estimators[FT0A], col.multFT0A(), col.centFT0A()); + fillEstimatorHistos(col, estimators[FT0C], col.multFT0C(), col.centFT0C()); + fillEstimatorHistos(col, estimators[FT0CVar1], col.multFT0C(), col.centFT0CVariant1()); + fillEstimatorHistos(col, estimators[FT0CVar2], col.multFT0C(), col.centFT0CVariant2()); + fillEstimatorHistos(col, estimators[FDDM], col.multFDDM(), col.centFDDM()); + fillEstimatorHistos(col, estimators[NTPV], col.multNTracksPV(), col.centNTPV()); + + if (nGlobals.size() > 0) { + const auto& multCentNGlo = nGlobals.rawIteratorAt(col.globalIndex()); + fillEstimatorHistos(col, estimators[NGlobal], multCentNGlo.multNTracksGlobal(), multCentNGlo.centNGlobal()); + } + + if (nMFTs.size() > 0) { + const auto& multCentNMFT = nMFTs.rawIteratorAt(col.globalIndex()); + fillEstimatorHistos(col, estimators[MFT], multCentNMFT.mftNtracks(), multCentNMFT.centMFT()); + } + + if (!loopOverMcCollisionsForMcHist) { + const auto& mcCol = col.mcCollision_as>(); + std::vector cent; + cent.resize(NEstimators, CentralityNotFound); + + cent[FV0A] = estimators[FV0A].getCentrality(col.multFV0A(), col.centFV0A()); + cent[FT0M] = estimators[FT0M].getCentrality(col.multFT0M(), col.centFT0M()); + cent[FT0MAnchorCol] = estimators[FT0MAnchorCol].getCentrality(col.multFT0M(), col.centFT0MAnchorCol()); + cent[FT0MAnchorBC] = estimators[FT0MAnchorBC].getCentrality(col.multFT0M(), col.centFT0MAnchorBC()); + cent[FT0MOuterA] = estimators[FT0MOuterA].getCentrality(col.multFT0AOuter() + col.multFT0C(), col.centFT0MOuterA()); + cent[FT0A] = estimators[FT0A].getCentrality(col.multFT0A(), col.centFT0A()); + cent[FT0C] = estimators[FT0C].getCentrality(col.multFT0C(), col.centFT0C()); + cent[FT0CVar1] = estimators[FT0CVar1].getCentrality(col.multFT0C(), col.centFT0CVariant1()); + cent[FT0CVar2] = estimators[FT0CVar2].getCentrality(col.multFT0C(), col.centFT0CVariant2()); + cent[FDDM] = estimators[FDDM].getCentrality(col.multFDDM(), col.centFDDM()); + cent[NTPV] = estimators[NTPV].getCentrality(col.multNTracksPV(), col.centNTPV()); + + fillEstimatorMonteCarloHistos(mcCol, estimators[FV0A], mcCol.multMCFV0A(), cent[FV0A], col.multNTracksPVetaHalf()); + fillEstimatorMonteCarloHistos(mcCol, estimators[FT0M], mcCol.multMCFT0A() + mcCol.multMCFT0C(), cent[FT0M], col.multNTracksPVetaHalf()); + fillEstimatorMonteCarloHistos(mcCol, estimators[FT0MAnchorCol], mcCol.multMCFT0A() + mcCol.multMCFT0C(), cent[FT0MAnchorCol], col.multNTracksPVetaHalf()); + fillEstimatorMonteCarloHistos(mcCol, estimators[FT0MAnchorBC], mcCol.multMCFT0A() + mcCol.multMCFT0C(), cent[FT0MAnchorBC], col.multNTracksPVetaHalf()); + fillEstimatorMonteCarloHistos(mcCol, estimators[FT0MOuterA], mcCol.multMCFT0A() + mcCol.multMCFT0C(), cent[FT0MOuterA], col.multNTracksPVetaHalf()); + fillEstimatorMonteCarloHistos(mcCol, estimators[FT0A], mcCol.multMCFT0A(), cent[FT0A], col.multNTracksPVetaHalf()); + fillEstimatorMonteCarloHistos(mcCol, estimators[FT0C], mcCol.multMCFT0C(), cent[FT0C], col.multNTracksPVetaHalf()); + fillEstimatorMonteCarloHistos(mcCol, estimators[FT0CVar1], mcCol.multMCFT0C(), cent[FT0CVar1], col.multNTracksPVetaHalf()); + fillEstimatorMonteCarloHistos(mcCol, estimators[FT0CVar2], mcCol.multMCFT0C(), cent[FT0CVar2], col.multNTracksPVetaHalf()); + fillEstimatorMonteCarloHistos(mcCol, estimators[FDDM], mcCol.multMCFDDA() + mcCol.multMCFDDC(), cent[FDDM], col.multNTracksPVetaHalf()); + fillEstimatorMonteCarloHistos(mcCol, estimators[NTPV], mcCol.multMCNParticlesEta08(), cent[NTPV], col.multNTracksPVetaHalf()); + fillEstimatorMonteCarloHistos(mcCol, estimators[NGlobal], mcCol.multMCNParticlesEta08(), cent[NGlobal], col.multNTracksPVetaHalf()); + + if (nGlobals.size() > 0) { + const auto& multCentNGlo = nGlobals.rawIteratorAt(col.globalIndex()); + cent[NGlobal] = estimators[NGlobal].getCentrality(multCentNGlo.multNTracksGlobal(), multCentNGlo.centNGlobal()); + fillEstimatorMonteCarloHistos(mcCol, estimators[NGlobal], mcCol.multMCNParticlesEta08(), cent[NGlobal], col.multNTracksPVetaHalf()); + } - void processMonteCarloRun3_NGlobal(soa::Join::iterator const& col, - soa::Join const& /*mcCollisions*/, - soa::Join const& /*bcs*/) - { - if (!isCollisionAccepted(col)) { - return; + if (nMFTs.size() > 0) { + const auto& multCentNMFT = nMFTs.rawIteratorAt(col.globalIndex()); + cent[MFT] = estimators[MFT].getCentrality(multCentNMFT.mftNtracks(), multCentNMFT.centMFT()); + // fillEstimatorMonteCarloHistos(mcCol, estimators[MFT], mcCol.multMCMFT(), cent[MFT], col.multNTracksPVetaHalf()); // FIXME: uncomment when MC MFT mult is added in aod::MultMCExtras + } + } } - const auto& mcCol = col.mcCollision_as>(); - Estimator nGlo = initEstimator(col, "nGlo"); - const float centNGlo = nGlo.getCentrality(col.multNTracksGlobal(), col.centNGlobal()); + if (loopOverMcCollisionsForMcHist) { + for (const auto& mcCol : mcCollisions) { + auto groupedCollisions = collisions.sliceBy(perMcCollision, mcCol.globalIndex()); + auto groupedCollisionsNGlobal = collisions.sliceBy(perMcCollisionNGlobal, mcCol.globalIndex()); + auto groupedCollisionsMFT = collisions.sliceBy(perMcCollisionMFT, mcCol.globalIndex()); - LOGF(debug, "centNGlo=%.0f", centNGlo); - histos.fill(HIST("hCentNGlobal"), centNGlo); - histos.fill(HIST("hCentProfileNGlobal"), centNGlo, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentNGlobal"), centNGlo, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsGenMultNGlobal"), mcCol.multMCNParticlesEta08(), col.multNTracksPVetaHalf()); - histos.fill(HIST("hGenMultEta05VsCentralityNGlobal"), col.centNGlobal(), mcCol.multMCNParticlesEta05()); - histos.fill(HIST("hGenMultVsCentralityNGlobal"), col.centNGlobal(), mcCol.multMCNParticlesEta08()); - } - PROCESS_SWITCH(CentralityQa, processMonteCarloRun3_NGlobal, "Process with Run 3 NGlobal estimator", false); - - void processMonteCarloRun3_MFT(soa::Join::iterator const& col, - soa::Join const& /*mcCollisions*/, - soa::Join const& /*bcs*/) - { - if (!isCollisionAccepted(col)) { - return; - } + // Check if there is at least one of the reconstructed collisions associated to this MC collision + // If so, we consider it + int biggestNContribs = -1; + int nContribsInEta05 = -1; + std::vector cent; + cent.resize(NEstimators, CentralityNotFound); - const auto& mcCol = col.mcCollision_as>(); // FIXME: uncomment when MC MFT mult is added in aod::MultMCExtras - Estimator mft = initEstimator(col, "MFT"); - const float centMFT = mft.getCentrality(col.mftNtracks(), col.centMFT()); + for (auto const& col : groupedCollisions) { + if (!isCollisionAccepted(col)) { + continue; + } - LOGF(debug, "centMFT=%.0f", centMFT); - histos.fill(HIST("hCentMFT"), centMFT); - histos.fill(HIST("hCentProfileMFT"), centMFT, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentMFT"), centMFT, col.multNTracksPVetaHalf()); - // histos.fill(HIST("hMultEta05VsGenMultMFT"), mcCol.multMCMFT(), col.multNTracksPVetaHalf()); // FIXME: uncomment when MC MFT mult is added in aod::MultMCExtras - histos.fill(HIST("hGenMultEta05VsCentralityMFT"), col.centMFT(), mcCol.multMCNParticlesEta05()); - // histos.fill(HIST("hGenMultVsCentralityMFT"), col.centMFT(), mcCol.multMCMFT()); // FIXME: uncomment when MC MFT mult is added in aod::MultMCExtras - } - PROCESS_SWITCH(CentralityQa, processMonteCarloRun3_MFT, "Process with Run 3 MFT estimator", false); + for (int iEst = 0; iEst < NEstimators; ++iEst) { + if (iEst == NGlobal || iEst == MFT) { + continue; + } + estimators[iEst].configure(col); + } - void processMonteCarloRun3_FT0MAnchorCol(soa::Join::iterator const& col, - soa::Join const& /*mcCollisions*/, - soa::Join const& /*bcs*/) - { - if (!isCollisionAccepted(col)) { - return; - } + const float recoColCentFV0A = estimators[FV0A].getCentrality(col.multFV0A(), col.centFV0A()); + const float recoColCentFT0M = estimators[FT0M].getCentrality(col.multFT0M(), col.centFT0M()); + const float recoColCentFT0MAnchorCol = estimators[FT0MAnchorCol].getCentrality(col.multFT0M(), col.centFT0MAnchorCol()); + const float recoColCentFT0MAnchorBC = estimators[FT0MAnchorBC].getCentrality(col.multFT0M(), col.centFT0MAnchorBC()); + const float recoColCentFT0MOuterA = estimators[FT0MOuterA].getCentrality(col.multFT0AOuter() + col.multFT0C(), col.centFT0MOuterA()); + const float recoColCentFT0A = estimators[FT0A].getCentrality(col.multFT0A(), col.centFT0A()); + const float recoColCentFT0C = estimators[FT0C].getCentrality(col.multFT0C(), col.centFT0C()); + const float recoColCentFT0CVar1 = estimators[FT0CVar1].getCentrality(col.multFT0C(), col.centFT0CVariant1()); + const float recoColCentFT0CVar2 = estimators[FT0CVar2].getCentrality(col.multFT0C(), col.centFT0CVariant2()); + const float recoColCentFDDM = estimators[FDDM].getCentrality(col.multFDDM(), col.centFDDM()); + const float recoColCentNTPV = estimators[NTPV].getCentrality(col.multNTracksPV(), col.centNTPV()); + + // One McCollision can be reconstructed multiple times + // Use centrality from reconstructed collision with most PV contributors + if (biggestNContribs < col.multPVTotalContributors()) { + biggestNContribs = col.multPVTotalContributors(); + nContribsInEta05 = col.multNTracksPVetaHalf(); + cent[FV0A] = recoColCentFV0A; + cent[FT0M] = recoColCentFT0M; + cent[FT0MAnchorCol] = recoColCentFT0MAnchorCol; + cent[FT0MAnchorBC] = recoColCentFT0MAnchorBC; + cent[FT0MOuterA] = recoColCentFT0MOuterA; + cent[FT0A] = recoColCentFT0A; + cent[FT0C] = recoColCentFT0C; + cent[FT0CVar1] = recoColCentFT0CVar1; + cent[FT0CVar2] = recoColCentFT0CVar2; + cent[FDDM] = recoColCentFDDM; + cent[NTPV] = recoColCentNTPV; + } + } - const auto& mcCol = col.mcCollision_as>(); - Estimator ft0mAnchorCol = initEstimator(col, "FT0MAnchorCol"); - const float centFT0MAnchorCol = ft0mAnchorCol.getCentrality(col.multFT0M(), col.centFT0MAnchorCol()); + if (nGlobals.size() > 0 && studies.nGlo.value) { + for (auto const& col : groupedCollisionsNGlobal) { + estimators[NGlobal].configure(col); + const auto& multCentNGlo = nGlobals.rawIteratorAt(col.globalIndex()); + const float recoColCentNGlo = estimators[NGlobal].getCentrality(multCentNGlo.multNTracksGlobal(), multCentNGlo.centNGlobal()); + if (biggestNContribs < col.multPVTotalContributors()) { + biggestNContribs = col.multPVTotalContributors(); + nContribsInEta05 = col.multNTracksPVetaHalf(); + cent[NGlobal] = recoColCentNGlo; + } + } + } - LOGF(debug, "centFT0MAnchorCol=%.0f", centFT0MAnchorCol); - histos.fill(HIST("hCentFT0MAnchorCols"), centFT0MAnchorCol); - histos.fill(HIST("hCentProfileFT0MAnchorCols"), centFT0MAnchorCol, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentFT0MAnchorCols"), centFT0MAnchorCol, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsGenMultFT0MAnchorCols"), mcCol.multMCFT0A() + mcCol.multMCFT0C(), col.multNTracksPVetaHalf()); - } - PROCESS_SWITCH(CentralityQa, processMonteCarloRun3_FT0MAnchorCol, "Process with Run 3 FT0MAnchorCol estimator", false); + if (nMFTs.size() > 0 && studies.mft.value) { + for (auto const& col : groupedCollisionsMFT) { + estimators[MFT].configure(col); + const auto& multCentNMFT = nMFTs.rawIteratorAt(col.globalIndex()); + const float recoColCentNMFT = estimators[MFT].getCentrality(multCentNMFT.mftNtracks(), multCentNMFT.centMFT()); + if (biggestNContribs < col.multPVTotalContributors()) { + biggestNContribs = col.multPVTotalContributors(); + nContribsInEta05 = col.multNTracksPVetaHalf(); + cent[MFT] = recoColCentNMFT; + } + } + } - void processMonteCarloRun3_FT0MAnchorBC(soa::Join::iterator const& col, - soa::Join const& /*mcCollisions*/, - soa::Join const& /*bcs*/) - { - if (!isCollisionAccepted(col)) { - return; + fillEstimatorMonteCarloHistos(mcCol, estimators[FV0A], mcCol.multMCFV0A(), cent[FV0A], nContribsInEta05); + fillEstimatorMonteCarloHistos(mcCol, estimators[FT0M], mcCol.multMCFT0A() + mcCol.multMCFT0C(), cent[FT0M], nContribsInEta05); + fillEstimatorMonteCarloHistos(mcCol, estimators[FT0MAnchorCol], mcCol.multMCFT0A() + mcCol.multMCFT0C(), cent[FT0MAnchorCol], nContribsInEta05); + fillEstimatorMonteCarloHistos(mcCol, estimators[FT0MAnchorBC], mcCol.multMCFT0A() + mcCol.multMCFT0C(), cent[FT0MAnchorBC], nContribsInEta05); + fillEstimatorMonteCarloHistos(mcCol, estimators[FT0MOuterA], mcCol.multMCFT0A() + mcCol.multMCFT0C(), cent[FT0MOuterA], nContribsInEta05); + fillEstimatorMonteCarloHistos(mcCol, estimators[FT0A], mcCol.multMCFT0A(), cent[FT0A], nContribsInEta05); + fillEstimatorMonteCarloHistos(mcCol, estimators[FT0C], mcCol.multMCFT0C(), cent[FT0C], nContribsInEta05); + fillEstimatorMonteCarloHistos(mcCol, estimators[FT0CVar1], mcCol.multMCFT0C(), cent[FT0CVar1], nContribsInEta05); + fillEstimatorMonteCarloHistos(mcCol, estimators[FT0CVar2], mcCol.multMCFT0C(), cent[FT0CVar2], nContribsInEta05); + fillEstimatorMonteCarloHistos(mcCol, estimators[FDDM], mcCol.multMCFDDA() + mcCol.multMCFDDC(), cent[FDDM], nContribsInEta05); + fillEstimatorMonteCarloHistos(mcCol, estimators[NTPV], mcCol.multMCNParticlesEta08(), cent[NTPV], nContribsInEta05); + fillEstimatorMonteCarloHistos(mcCol, estimators[NGlobal], mcCol.multMCNParticlesEta08(), cent[NGlobal], nContribsInEta05); + // fillEstimatorMonteCarloHistos(mcCol, estimators[MFT], mcCol.multMCMFT(), cent[MFT], nContribsInEta05); // FIXME: uncomment when MC MFT mult is added in aod::MultMCExtras + } } - const auto& mcCol = col.mcCollision_as>(); - Estimator ft0mAnchorBc = initEstimator(col, "FT0MAnchorBc"); - const float centFT0MAnchorBc = ft0mAnchorBc.getCentrality(col.multFT0M(), col.centFT0MAnchorBC()); - - LOGF(debug, "centFT0MAnchorBc=%.0f", centFT0MAnchorBc); - histos.fill(HIST("hCentFT0MAnchorBCs"), centFT0MAnchorBc); - histos.fill(HIST("hCentProfileFT0MAnchorBCs"), centFT0MAnchorBc, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsCentFT0MAnchorBCs"), centFT0MAnchorBc, col.multNTracksPVetaHalf()); - histos.fill(HIST("hMultEta05VsGenMultFT0MAnchorBCs"), mcCol.multMCFT0A() + mcCol.multMCFT0C(), col.multNTracksPVetaHalf()); } - PROCESS_SWITCH(CentralityQa, processMonteCarloRun3_FT0MAnchorBC, "Process with Run 3 FT0MAnchorBC estimator", false); using BCsWithRun3Matchings = soa::Join; void processBunchCrossings(soa::Join::iterator const& bc, aod::FT0s const&, aod::FV0As const&) @@ -1163,6 +900,10 @@ struct CentralityQa { } } } + + PROCESS_SWITCH(CentralityQa, processRun2, "Process with Run 2 V0A", false); + PROCESS_SWITCH(CentralityQa, processRun3, "Process with Run 3", true); + PROCESS_SWITCH(CentralityQa, processRun3MonteCarlo, "Process with Run 3 with MC", false); PROCESS_SWITCH(CentralityQa, processBunchCrossings, "Process with Run 3 BC table", false); }; diff --git a/Common/Tasks/centralityStudy.cxx b/Common/Tasks/centralityStudy.cxx index c00be6da0d1..a8f9f7f739d 100644 --- a/Common/Tasks/centralityStudy.cxx +++ b/Common/Tasks/centralityStudy.cxx @@ -126,6 +126,7 @@ struct CentralityStudy { std::string prefix = "evsel"; Configurable applySel8{"applySel8", true, "0 - no, 1 - yes"}; Configurable applyVtxZ{"applyVtxZ", true, "0 - no, 1 - yes"}; + Configurable requireINELgtZERO{"requireINELgtZERO", true, "0 no, 1 - yes"}; Configurable selectUPCcollisions{"selectUPCcollisions", false, "select collisions tagged with UPC flag"}; Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "reject events at ITS ROF border"}; Configurable rejectTFBorder{"rejectTFBorder", true, "reject events at TF border"}; @@ -146,7 +147,7 @@ struct CentralityStudy { } evsel; // _______________________________________ - // BC Selection + // BC Selections struct : ConfigurableGroup { std::string prefix = "bcsel"; Configurable rejectZNAC{"rejectZNAC", false, "reject if !(kIsBBZNA && kIsBBZNC)"}; @@ -220,7 +221,7 @@ struct CentralityStudy { ConfigurableAxis axisMultITSTPC{"axisMultITSTPC", {200, 0, 6000}, "Number of ITSTPC matched tracks"}; // For centrality studies if requested - ConfigurableAxis axisCentrality{"axisCentrality", {100, 0, 100}, "FT0C percentile"}; + ConfigurableAxis axisCentrality{"axisCentrality", {100, 0, 100}, "FT0C percentile (%)"}; ConfigurableAxis axisImpactParameter{"axisImpactParameter", {200, 0.0f, 20.0f}, "b (fm)"}; ConfigurableAxis axisPVChi2{"axisPVChi2", {300, 0, 30}, "FT0C percentile"}; ConfigurableAxis axisDeltaTime{"axisDeltaTime", {300, 0, 300}, "#Delta time"}; @@ -535,7 +536,8 @@ struct CentralityStudy { getHist(histPath + "hCollisionSelection")->GetXaxis()->SetBinLabel(15, "rejectCollInTimeRangeNarrow"); getHist(histPath + "hCollisionSelection")->GetXaxis()->SetBinLabel(16, "em/upc rejection"); getHist(histPath + "hCollisionSelection")->GetXaxis()->SetBinLabel(17, "isFlangeEvent"); - getHist(histPath + "hCollisionSelection")->GetXaxis()->SetBinLabel(18, "bcsel"); + getHist(histPath + "hCollisionSelection")->GetXaxis()->SetBinLabel(18, "INEL>0"); + getHist(histPath + "hCollisionSelection")->GetXaxis()->SetBinLabel(19, "bcsel"); histPointers.insert({histPath + "hFT0C_Collisions", histos.add((histPath + "hFT0C_Collisions").c_str(), "hFT0C_Collisions", {kTH1D, {{axisMultUltraFineFT0C}}})}); histPointers.insert({histPath + "hFT0A_Collisions", histos.add((histPath + "hFT0A_Collisions").c_str(), "hFT0A_Collisions", {kTH1D, {{axisMultUltraFineFT0A}}})}); @@ -733,24 +735,25 @@ struct CentralityStudy { multNTracksGlobal = -1.0f; mftNtracks = -1.0f; multNTracksPV = -1.0f; - - if (hVtxZFV0A->Interpolate(collision.multPVz()) > epsilon) { - multFV0A = hVtxZFV0A->Interpolate(0.0) * collision.multFV0A() / hVtxZFV0A->Interpolate(collision.multPVz()); - } - if (hVtxZFT0A->Interpolate(collision.multPVz()) > epsilon) { - multFT0A = hVtxZFT0A->Interpolate(0.0) * collision.multFT0A() / hVtxZFT0A->Interpolate(collision.multPVz()); - } - if (hVtxZFT0C->Interpolate(collision.multPVz()) > epsilon) { - multFT0C = hVtxZFT0C->Interpolate(0.0) * collision.multFT0C() / hVtxZFT0C->Interpolate(collision.multPVz()); - } - if (hVtxZNGlobals->Interpolate(collision.multPVz()) > epsilon) { - multNTracksGlobal = hVtxZNGlobals->Interpolate(0.0) * collision.multNTracksGlobal() / hVtxZNGlobals->Interpolate(collision.multPVz()); - } - if (hVtxZMFT->Interpolate(collision.multPVz()) > epsilon) { - mftNtracks = hVtxZMFT->Interpolate(0.0) * collision.mftNtracks() / hVtxZMFT->Interpolate(collision.multPVz()); - } - if (hVtxZNTracks->Interpolate(collision.multPVz()) > epsilon) { - multNTracksPV = hVtxZNTracks->Interpolate(0.0) * collision.multNTracksPV() / hVtxZNTracks->Interpolate(collision.multPVz()); + if (std::abs(collision.multPVz()) < evsel.maxVtxZ) { + if (hVtxZFV0A && hVtxZFV0A->Interpolate(collision.multPVz()) > epsilon) { + multFV0A = hVtxZFV0A->Interpolate(0.0) * collision.multFV0A() / hVtxZFV0A->Interpolate(collision.multPVz()); + } + if (hVtxZFT0A && hVtxZFT0A->Interpolate(collision.multPVz()) > epsilon) { + multFT0A = hVtxZFT0A->Interpolate(0.0) * collision.multFT0A() / hVtxZFT0A->Interpolate(collision.multPVz()); + } + if (hVtxZFT0C && hVtxZFT0C->Interpolate(collision.multPVz()) > epsilon) { + multFT0C = hVtxZFT0C->Interpolate(0.0) * collision.multFT0C() / hVtxZFT0C->Interpolate(collision.multPVz()); + } + if (hVtxZNGlobals && hVtxZNGlobals->Interpolate(collision.multPVz()) > epsilon) { + multNTracksGlobal = hVtxZNGlobals->Interpolate(0.0) * collision.multNTracksGlobal() / hVtxZNGlobals->Interpolate(collision.multPVz()); + } + if (hVtxZMFT && hVtxZMFT->Interpolate(collision.multPVz()) > epsilon) { + mftNtracks = hVtxZMFT->Interpolate(0.0) * collision.mftNtracks() / hVtxZMFT->Interpolate(collision.multPVz()); + } + if (hVtxZNTracks && hVtxZNTracks->Interpolate(collision.multPVz()) > epsilon) { + multNTracksPV = hVtxZNTracks->Interpolate(0.0) * collision.multNTracksPV() / hVtxZNTracks->Interpolate(collision.multPVz()); + } } } @@ -765,13 +768,14 @@ struct CentralityStudy { bool passRejectITSinROFpileupStrict = !(evsel.rejectITSinROFpileupStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)); bool passSelectUPCcollisions = !(evsel.selectUPCcollisions && collision.flags() < 1); bool passRejectCollInTimeRangeNarrow = !(evsel.rejectCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)); + bool passINELgtZERO = !(evsel.requireINELgtZERO && !collision.isInelGt0()); // _______________________________________________________ // sidestep vertex-Z rejection for vertex-Z profile histograms if (studies.doRunByRunHistograms) { if (passRejectITSROFBorder && passRejectTFBorder && passRequireIsVertexITSTPC && passRequireIsGoodZvtxFT0VsPV && passRequireIsVertexTOFmatched && passRequireIsVertexTRDmatched && passRejectSameBunchPileup && passRejectITSinROFpileupStandard && passRejectITSinROFpileupStrict && - passSelectUPCcollisions && passRejectCollInTimeRangeNarrow) { + passSelectUPCcollisions && passRejectCollInTimeRangeNarrow && passINELgtZERO) { getHist(histPath + "hFT0CvsPVz_Collisions")->Fill(collision.multPVz(), multFT0C * scale.factorFT0C); getHist(histPath + "hFT0CvsPVz_Collisions")->Fill(collision.multPVz(), multFT0C * scale.factorFT0C); getHist(histPath + "hFT0AvsPVz_Collisions")->Fill(collision.multPVz(), multFT0A * scale.factorFT0C); @@ -926,6 +930,14 @@ struct CentralityStudy { getHist(histPath + "hCollisionSelection")->Fill(16); } + if (!passINELgtZERO) { + return; + } + histos.fill(HIST("hCollisionSelection"), 17 /* is INEL > 0 */); + if (studies.doRunByRunHistograms) { + getHist(histPath + "hCollisionSelection")->Fill(17); + } + if (evsel.applyBcSel) { if constexpr (requires { collision.has_multBC(); }) { if (collision.has_multBC()) { @@ -944,9 +956,9 @@ struct CentralityStudy { } } - histos.fill(HIST("hCollisionSelection"), 17 /* bc selections */); + histos.fill(HIST("hCollisionSelection"), 18 /* bc selections */); if (studies.doRunByRunHistograms) { - getHist(histPath + "hCollisionSelection")->Fill(17); + getHist(histPath + "hCollisionSelection")->Fill(18); } // if we got here, we also finally fill the FT0C histogram, please diff --git a/Common/Tasks/centralityStudypp.cxx b/Common/Tasks/centralityStudypp.cxx index 47f1e540480..f0a6ed54c33 100644 --- a/Common/Tasks/centralityStudypp.cxx +++ b/Common/Tasks/centralityStudypp.cxx @@ -221,7 +221,7 @@ struct centralityStudypp { hCentralityMFT = dynamic_cast(hCentralityObjects->FindObject("hCalibZeqMFT")); // won't capture null pointers -> explicitly check for those when attempting to evaluate - auto reportSuccess = [](TH1* a, std::string name) { + auto reportSuccess = [](TH1* a, const std::string& name) { if (!a) { LOGF(info, "Calibration missing for %s", name); } else { diff --git a/Common/Tasks/qVectorsCorrection.cxx b/Common/Tasks/qVectorsCorrection.cxx index e99017b1397..600fac9ba47 100644 --- a/Common/Tasks/qVectorsCorrection.cxx +++ b/Common/Tasks/qVectorsCorrection.cxx @@ -149,7 +149,7 @@ struct qVectorsCorrection { } template - bool SelTrack(const TrackType track) + bool SelTrack(const TrackType& track) { if (track.pt() < 0.15) return false; diff --git a/Common/Tools/EventSelectionModule.h b/Common/Tools/EventSelectionModule.h index c73255aff6f..09f114364c7 100644 --- a/Common/Tools/EventSelectionModule.h +++ b/Common/Tools/EventSelectionModule.h @@ -1323,7 +1323,7 @@ class EventSelectionModule float vZ = col.posZ(); // ### in-ROF occupancy - std::vector vAssocCollInSameROF = vCollsInSameITSROF[colIndex]; + const std::vector& vAssocCollInSameROF = vCollsInSameITSROF[colIndex]; int nITS567tracksForSameRofVetoStrict = 0; // to veto events with other collisions in the same ITS ROF int nCollsInRofWithFT0CAboveVetoStandard = 0; // to veto events with other collisions in the same ITS ROF, with per-collision multiplicity above threshold int nITS567tracksForRofVetoOnCloseVz = 0; // to veto events with nearby collisions with close vZ @@ -1341,7 +1341,7 @@ class EventSelectionModule vNoCollInSameRofWithCloseVz[colIndex] = (nITS567tracksForRofVetoOnCloseVz == 0); // ### occupancy in previous ROF - std::vector vAssocCollInPrevROF = vCollsInPrevITSROF[colIndex]; + const std::vector& vAssocCollInPrevROF = vCollsInPrevITSROF[colIndex]; float totalFT0amplInPrevROF = 0; for (uint32_t iCol = 0; iCol < vAssocCollInPrevROF.size(); iCol++) { int thisColIndex = vAssocCollInPrevROF[iCol]; @@ -1351,8 +1351,8 @@ class EventSelectionModule vNoHighMultCollInPrevRof[colIndex] = (totalFT0amplInPrevROF < evselOpts.confFT0CamplCutVetoOnCollInROF); // ### occupancy in time windows - std::vector vAssocToThisCol = vCollsInTimeWin[colIndex]; - std::vector vCollsTimeDeltaWrtGivenColl = vTimeDeltaForColls[colIndex]; + const std::vector& vAssocToThisCol = vCollsInTimeWin[colIndex]; + const std::vector& vCollsTimeDeltaWrtGivenColl = vTimeDeltaForColls[colIndex]; int nITS567tracksInFullTimeWindow = 0; float sumAmpFT0CInFullTimeWindow = 0; int nITS567tracksForVetoNarrow = 0; // to veto events with nearby collisions (narrow range) with per-collision multiplicity above threshold diff --git a/Common/Tools/Multiplicity/MultModule.h b/Common/Tools/Multiplicity/MultModule.h index beb1274b7a4..3c9151ca78c 100644 --- a/Common/Tools/Multiplicity/MultModule.h +++ b/Common/Tools/Multiplicity/MultModule.h @@ -11,7 +11,7 @@ /// \file MultModule.h /// \brief combined multiplicity + centrality module with autodetect features -/// \author ALICE +/// \author ALICE Collaboration #ifndef COMMON_TOOLS_MULTIPLICITY_MULTMODULE_H_ #define COMMON_TOOLS_MULTIPLICITY_MULTMODULE_H_ @@ -41,6 +41,7 @@ #include #include #include +#include #include //__________________________________________ @@ -429,7 +430,7 @@ class MultModule float mMCScalePars[6] = {0.0}; TFormula* mMCScale = nullptr; explicit CalibrationInfo(std::string name) - : name(name), + : name(std::move(name)), mCalibrationStored(false), mhMultSelCalib(nullptr), mMCScalePars{0.0}, @@ -1198,13 +1199,13 @@ class MultModule LOGF(info, "centrality loading procedure for timestamp=%llu, run number=%d", bc.timestamp(), bc.runNumber()); // capture the need for PYTHIA calibration in Pb-Pb runs - if (metadataInfo.isMC() && mRunNumber >= 544013 && mRunNumber <= 545367) { + if (metadataInfo.isMC() && mRunNumber >= 544013 && mRunNumber <= 545367 && internalOpts.generatorName.value.empty()) { LOGF(info, "This is MC for Pb-Pb. Setting generatorName automatically to PYTHIA"); internalOpts.generatorName.value = "PYTHIA"; } // capture the need for PYTHIA calibration in light ion runs automatically - if (metadataInfo.isMC() && mRunNumber >= 564250 && mRunNumber <= 564472) { + if (metadataInfo.isMC() && mRunNumber >= 564250 && mRunNumber <= 564472 && internalOpts.generatorName.value.empty()) { LOGF(info, "This is MC for light ion runs. Setting generatorName automatically to PYTHIA"); internalOpts.generatorName.value = "PYTHIA"; } @@ -1250,7 +1251,7 @@ class MultModule mftInfo.mCalibrationStored = false; if (callst != nullptr) { LOGF(info, "Getting new histograms with %d run number for %d run number", mRunNumber, bc.runNumber()); - auto getccdb = [callst, bc](struct CalibrationInfo& estimator, const o2::framework::Configurable generatorName) { // TODO: to consider the name inside the estimator structure + auto getccdb = [callst, bc](struct CalibrationInfo& estimator, const o2::framework::Configurable& generatorName) { // TODO: to consider the name inside the estimator structure estimator.mhMultSelCalib = reinterpret_cast(callst->FindObject(TString::Format("hCalibZeq%s", estimator.name.c_str()).Data())); estimator.mMCScale = reinterpret_cast(callst->FindObject(TString::Format("%s-%s", generatorName->c_str(), estimator.name.c_str()).Data())); if (estimator.mhMultSelCalib != nullptr) { diff --git a/Common/Tools/Multiplicity/macros/runCalibration.C b/Common/Tools/Multiplicity/macros/runCalibration.C index e442e0ef401..0620bb5e1db 100644 --- a/Common/Tools/Multiplicity/macros/runCalibration.C +++ b/Common/Tools/Multiplicity/macros/runCalibration.C @@ -33,7 +33,7 @@ /// @param anchorPointPercentage anchor point percentage to use /// @param matchRange width of region in which data/glauber matching is to be done in rolling anchoring test /// @param doNpartNcoll wether or not to attempt calculating Npart, Ncoll in centrality bins -void runCalibration(TString lInputFileName = "results/AR_544122_glauberNBD_ancestorMode2_hFT0C_BCs.root", double anchorPointPercentage = 90.0, double matchRange = 200.0, bool doNpartNcoll = false) +void runCalibration(const TString& lInputFileName = "results/AR_544122_glauberNBD_ancestorMode2_hFT0C_BCs.root", double anchorPointPercentage = 90.0, double matchRange = 200.0, bool doNpartNcoll = false) { TFile* file = new TFile(lInputFileName.Data(), "READ"); file->ls(); diff --git a/Common/Tools/Multiplicity/macros/runGlauberFit.C b/Common/Tools/Multiplicity/macros/runGlauberFit.C index e1b3fd10944..5c07a000405 100644 --- a/Common/Tools/Multiplicity/macros/runGlauberFit.C +++ b/Common/Tools/Multiplicity/macros/runGlauberFit.C @@ -87,7 +87,7 @@ Double_t GetBoundaryForPercentile(TH1* histo, Double_t lPercentileRequested) /// @param lFreef free f: keep f value free (default Pb-Pb: fixed at 0.8) /// @param lfvalue f value: the value to use for fixed f /// @param outputFile name of output file -int runGlauberFit(TString lInputFileName = "AnalysisResultsLHC24ar.root", TString histogramName = "hFT0C_BCs", int ancestorMode = 2, Bool_t lFreek = kFALSE, Bool_t use_dMu_dNanc = kFALSE, Bool_t lFreef = kFALSE, Float_t lfvalue = 0.800, TString outputFile = "output.root") +int runGlauberFit(const TString& lInputFileName = "AnalysisResultsLHC24ar.root", const TString& histogramName = "hFT0C_BCs", int ancestorMode = 2, Bool_t lFreek = kFALSE, Bool_t use_dMu_dNanc = kFALSE, Bool_t lFreef = kFALSE, Float_t lfvalue = 0.800, const TString& outputFile = "output.root") { gStyle->SetLineScalePS(1); gStyle->SetOptStat(0); diff --git a/Common/Tools/Multiplicity/macros/saveCorrelation.C b/Common/Tools/Multiplicity/macros/saveCorrelation.C index 8525aeed889..73bf8d30f29 100644 --- a/Common/Tools/Multiplicity/macros/saveCorrelation.C +++ b/Common/Tools/Multiplicity/macros/saveCorrelation.C @@ -26,7 +26,7 @@ /// @brief function to save Npart x Ncoll correlation to file for glauber fits /// @param filename input TGlauberMC ntuple file /// @param outputFile output file for Npart x Ncoll correlation TH2D -void saveCorrelation(TString filename = "gmc-PbPb-snn68.21-md0.40-nd-1.0-rc1-smax99.0.root", TString outputFile = "basehistos.root") +void saveCorrelation(const TString& filename = "gmc-PbPb-snn68.21-md0.40-nd-1.0-rc1-smax99.0.root", const TString& outputFile = "basehistos.root") { TFile* fin = new TFile(filename.Data(), "READ"); TNtuple* ntup = (TNtuple*)fin->Get("nt_Pb_Pb"); diff --git a/Common/Tools/Multiplicity/multCalibrator.cxx b/Common/Tools/Multiplicity/multCalibrator.cxx index 0d4ed69bd8d..d65f615d584 100644 --- a/Common/Tools/Multiplicity/multCalibrator.cxx +++ b/Common/Tools/Multiplicity/multCalibrator.cxx @@ -319,7 +319,7 @@ bool multCalibrator::IsBinningSane(TH1* histogram) } //________________________________________________________________ -TH1F* multCalibrator::GetCalibrationHistogram(TH1* histoRaw, TString lHistoName) +TH1F* multCalibrator::GetCalibrationHistogram(TH1* histoRaw, const TString& lHistoName) { // This function returns a calibration histogram //(pp or p-Pb like, no anchor point considered) diff --git a/Common/Tools/Multiplicity/multCalibrator.h b/Common/Tools/Multiplicity/multCalibrator.h index 6d4b24ba5e4..50e306c6d6e 100644 --- a/Common/Tools/Multiplicity/multCalibrator.h +++ b/Common/Tools/Multiplicity/multCalibrator.h @@ -43,8 +43,8 @@ class multCalibrator : public TNamed // Interface: steering functions to be used in calibration macro // Set Filenames - void SetInputFile(TString lFile) { fInputFileName = lFile.Data(); } - void SetOutputFile(TString lFile) { fOutputFileName = lFile.Data(); } + void SetInputFile(const TString& lFile) { fInputFileName = lFile.Data(); } + void SetOutputFile(const TString& lFile) { fOutputFileName = lFile.Data(); } // Set Boundaries to find void SetBoundaries(Long_t lNB, Double_t* lB) { @@ -68,7 +68,7 @@ class multCalibrator : public TNamed Bool_t Calibrate(); // Aux function. Keep public, accessible outside as rather useful utility - TH1F* GetCalibrationHistogram(TH1* histoRaw, TString lHistoName = "hCalib"); + TH1F* GetCalibrationHistogram(TH1* histoRaw, const TString& lHistoName = "hCalib"); // Auxiliary functions Double_t GetRawMax(TH1* histo); diff --git a/Common/Tools/Multiplicity/multGlauberNBDFitter.cxx b/Common/Tools/Multiplicity/multGlauberNBDFitter.cxx index ebabca167a1..330b6ce0045 100644 --- a/Common/Tools/Multiplicity/multGlauberNBDFitter.cxx +++ b/Common/Tools/Multiplicity/multGlauberNBDFitter.cxx @@ -8,7 +8,11 @@ // 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. -// + +/// \file multGlauberNBDFitter.cxx +/// \brief Helper class to perform Glauber fits +/// \author David Dobrigkeit Chinellato + /********************************************** * * Class meant to do Glauber+NBD fits @@ -27,6 +31,8 @@ #include "multGlauberNBDFitter.h" +#include + #include #include #include @@ -34,8 +40,6 @@ #include #include #include -#include -#include #include #include #include @@ -43,73 +47,28 @@ #include #include -#include - -#include // FIXME -using namespace std; +#include +#include ClassImp(multGlauberNBDFitter); -multGlauberNBDFitter::multGlauberNBDFitter() : TNamed(), - fNBD(0x0), - fhNanc(0x0), - fhNpNc(0x0), - fhV0M(0x0), - ffChanged(kTRUE), - fCurrentf(-1), - fAncestorMode(2), - fNpart(0x0), - fNcoll(0x0), - fContent(0x0), - fNNpNcPairs(-1), - fMaxNpNcPairs(1000000), - fMu(45), - fdMu(0.0), - fk(1.5), - ff(0.8), - fnorm(100), - fFitOptions("R0"), - fFitNpx(5000) -{ - // Constructor - fNpart = new Double_t[fMaxNpNcPairs]; - fNcoll = new Double_t[fMaxNpNcPairs]; - fContent = new Long_t[fMaxNpNcPairs]; - - // Ancestor histo - fhNanc = new TH1D("fhNanc", "", 1000, -0.5, 999.5); - - // NBD - fNBD = new TF1("fNBD", "ROOT::Math::negative_binomial_pdf(x,[0],[1])", 0, 45000); - fNBD->SetNpx(45000); - - // master function - fGlauberNBD = new TF1("fGlauberNBD", this, &multGlauberNBDFitter::ProbDistrib, - 0, 50000, 4, "multGlauberNBDFitter", "ProbDistrib"); - fGlauberNBD->SetParameter(0, fMu); - fGlauberNBD->SetParameter(1, fk); - fGlauberNBD->SetParameter(2, ff); - fGlauberNBD->SetParameter(3, fnorm); - - fGlauberNBD->SetParName(0, "mu"); - fGlauberNBD->SetParName(1, "k"); - fGlauberNBD->SetParName(2, "f"); - fGlauberNBD->SetParName(3, "norm"); - fGlauberNBD->SetParName(4, "dMu/dNanc"); -} - +multGlauberNBDFitter::multGlauberNBDFitter() : multGlauberNBDFitter("multGlauberNBDFitter") {} multGlauberNBDFitter::multGlauberNBDFitter(const char* name, const char* title) : TNamed(name, title), - fNBD(0x0), - fhNanc(0x0), - fhNpNc(0x0), - fhV0M(0x0), - ffChanged(kTRUE), + fNBD(new TF1("fNBD", "ROOT::Math::negative_binomial_pdf(x,[0],[1])", 0, 45000)), + fGlauberNBD(nullptr), + fTrentoNBD(nullptr), + fNBDFitterMode(NBDFitterMode::Glauber), + fhNanc(nullptr), + fhNpNc(nullptr), + fhNSources(nullptr), + fhV0M(nullptr), + ffChanged(true), fCurrentf(-1), - fAncestorMode(2), - fNpart(0x0), - fNcoll(0x0), - fContent(0x0), + fAncestorMode(AncestorMode::Continuous), + fNpart(nullptr), + fNcoll(nullptr), + fContent(nullptr), fNNpNcPairs(-1), fMaxNpNcPairs(1000000), fMu(45), @@ -121,134 +80,181 @@ multGlauberNBDFitter::multGlauberNBDFitter(const char* name, const char* title) fFitNpx(5000) { // Named constructor - fNpart = new Double_t[fMaxNpNcPairs]; - fNcoll = new Double_t[fMaxNpNcPairs]; - fContent = new Long_t[fMaxNpNcPairs]; - - // Ancestor histo - // fhNanc = new TH1D("fhNanc", "", fAncestorMode==2?10000:1000, -0.5, 999.5); + fNpart = new double[fMaxNpNcPairs]; + fNcoll = new double[fMaxNpNcPairs]; + fContent = new int64_t[fMaxNpNcPairs]; // NBD - fNBD = new TF1("fNBD", "ROOT::Math::negative_binomial_pdf(x,[0],[1])", 0, 45000); fNBD->SetNpx(45000); // master function - fGlauberNBD = new TF1("fGlauberNBD", this, &multGlauberNBDFitter::ProbDistrib, - 0, 50000, 5, "multGlauberNBDFitter", "ProbDistrib"); - fGlauberNBD->SetParameter(0, fMu); - fGlauberNBD->SetParameter(1, fk); - fGlauberNBD->SetParameter(2, ff); - fGlauberNBD->SetParameter(3, fnorm); - - fGlauberNBD->SetParName(0, "mu"); - fGlauberNBD->SetParName(1, "k"); - fGlauberNBD->SetParName(2, "f"); - fGlauberNBD->SetParName(3, "norm"); - fGlauberNBD->SetParName(4, "dMu/dNanc"); + InitGlauberNBD(fMu, fk, ff, fnorm); } + //________________________________________________________________ multGlauberNBDFitter::~multGlauberNBDFitter() { // Destructor - if (fNBD) { - delete fNBD; - fNBD = 0x0; - } - if (fhNanc) { - delete fhNanc; - fhNanc = 0x0; - } - if (fhNpNc) { - delete fhNpNc; - fhNpNc = 0x0; - } - if (fNpart) - delete[] fNpart; - if (fNcoll) - delete[] fNcoll; - if (fContent) - delete[] fContent; + delete fNBD; + delete fhNanc; + delete fhNpNc; + delete[] fNpart; + delete[] fNcoll; + delete[] fContent; +} + +void multGlauberNBDFitter::InitGlauberNBD(const float mu, const float k, const float f, const float norm) +{ + fNBDFitterMode = NBDFitterMode::Glauber; + fGlauberNBD = new TF1("fGlauberNBD", this, &multGlauberNBDFitter::GlauberProbDistrib, + 0, 50000, 5, "multGlauberNBDFitter", "GlauberProbDistrib"); + fGlauberNBD->SetParameter(Index(FitPar::mu), mu); + fGlauberNBD->SetParameter(Index(FitPar::k), k); + fGlauberNBD->SetParameter(Index(FitPar::f), f); + fGlauberNBD->SetParameter(Index(FitPar::norm), norm); + + fGlauberNBD->SetParName(Index(FitPar::mu), "mu"); + fGlauberNBD->SetParName(Index(FitPar::k), "k"); + fGlauberNBD->SetParName(Index(FitPar::f), "f"); + fGlauberNBD->SetParName(Index(FitPar::norm), "norm"); + fGlauberNBD->SetParName(Index(FitPar::dMu), "dMu/dNanc"); +} + +void multGlauberNBDFitter::InitTrentoNBD(const float mu, const float k, const float norm) +{ + fNBDFitterMode = NBDFitterMode::Trento; + fGlauberNBD = nullptr; + fTrentoNBD = new TF1("fTrentoNBD", this, &multGlauberNBDFitter::TrentoProbDistrib, + 0, 50000, 5, "multGlauberNBDFitter", "TrentoProbDistrib"); + fTrentoNBD->SetParameter(Index(FitPar::mu), mu); + fTrentoNBD->SetParameter(Index(FitPar::k), k); + fTrentoNBD->SetParameter(Index(FitPar::norm), norm); + + fTrentoNBD->SetParName(Index(FitPar::mu), "mu"); + fTrentoNBD->SetParName(Index(FitPar::k), "k"); + fTrentoNBD->SetParName(Index(FitPar::f), "f"); + fTrentoNBD->SetParName(Index(FitPar::norm), "norm"); + fTrentoNBD->SetParName(Index(FitPar::dMu), "dMu/dNanc"); } //______________________________________________________ -Double_t multGlauberNBDFitter::ProbDistrib(Double_t* x, Double_t* par) +double multGlauberNBDFitter::GlauberProbDistrib(const double* x, const double* par) // Master fitter function { - Double_t lMultValue = x[0]; - Double_t lProbability = 0.0; - ffChanged = kTRUE; - const Double_t lAlmost0 = 1.e-13; + double lMultValue = x[0]; + double lProbability = 0.0; + ffChanged = true; + static constexpr double Almost0 = 1.e-13; // Comment this line in order to make the code evaluate Nancestor all the time - if (TMath::Abs(fCurrentf - par[2]) < lAlmost0) - ffChanged = kFALSE; + if (std::abs(fCurrentf - par[Index(FitPar::f)]) < Almost0) { + ffChanged = false; + } //______________________________________________________ // Recalculate the ancestor distribution in case f changed if (ffChanged) { - fCurrentf = par[2]; + fCurrentf = par[Index(FitPar::f)]; fhNanc->Reset(); for (int ibin = 0; ibin < fNNpNcPairs; ibin++) { - Double_t lOption0 = (Int_t)(fNpart[ibin] * par[2] + fNcoll[ibin] * (1.0 - par[2])); - Double_t lOption1 = TMath::Floor(fNpart[ibin] * par[2] + fNcoll[ibin] * (1.0 - par[2]) + 0.5); - Double_t lOption2 = (fNpart[ibin] * par[2] + fNcoll[ibin] * (1.0 - par[2])); - if (fAncestorMode == 0) + double lOption0 = static_cast(fNpart[ibin] * par[Index(FitPar::f)] + fNcoll[ibin] * (1.0 - par[Index(FitPar::f)])); + double lOption1 = std::floor(fNpart[ibin] * par[Index(FitPar::f)] + fNcoll[ibin] * (1.0 - par[Index(FitPar::f)]) + 0.5); + double lOption2 = (fNpart[ibin] * par[Index(FitPar::f)] + fNcoll[ibin] * (1.0 - par[Index(FitPar::f)])); + if (fAncestorMode == AncestorMode::Truncated) { fhNanc->Fill(lOption0, fContent[ibin]); - if (fAncestorMode == 1) + } + if (fAncestorMode == AncestorMode::Rounded) { fhNanc->Fill(lOption1, fContent[ibin]); - if (fAncestorMode == 2) + } + if (fAncestorMode == AncestorMode::Continuous) { fhNanc->Fill(lOption2, fContent[ibin]); + } } if (fhNanc->Integral() < 1) { - cout << "ERROR: ANCESTOR HISTOGRAM EMPTY" << endl; - cout << "Will not do anything. Call InitializeNpNc if you want to plot without fitting" << endl; + LOG(info) << "ERROR: ANCESTOR HISTOGRAM EMPTY"; + LOG(info) << "Will not do anything. Call InitNpNc if you want to plot without fitting"; return 0; } fhNanc->Scale(1. / fhNanc->Integral()); } //______________________________________________________ // Actually evaluate function - Int_t lStartBin = fhNanc->FindBin(0.0) + 1; - for (Long_t iNanc = lStartBin; iNanc < fhNanc->GetNbinsX() + 1; iNanc++) { - Double_t lNancestors = fhNanc->GetBinCenter(iNanc); - Double_t lNancestorCount = fhNanc->GetBinContent(iNanc); - // if(lNancestorCount<1e-12&&lNancestors>10) break; + int lStartBin = fhNanc->FindBin(0.0) + 1; + for (int64_t iNanc = lStartBin; iNanc < fhNanc->GetNbinsX() + 1; ++iNanc) { + double lNancestors = fhNanc->GetBinCenter(iNanc); + double lNancestorCount = fhNanc->GetBinContent(iNanc); // allow for variable mu in case requested - Double_t lThisMu = (((Double_t)lNancestors)) * (par[0] + par[4] * lNancestors); - Double_t lThisk = (((Double_t)lNancestors)) * par[1]; - Double_t lpval = TMath::Power(1.0 + lThisMu / lThisk, -1); - fNBD->SetParameter(1, lThisk); - fNBD->SetParameter(0, lpval); - Double_t lMult = 0.0; - if (lMultValue > 1e-6) - lMult = fAncestorMode != 2 ? fNBD->Eval(lMultValue) : ContinuousNBD(lMultValue, lThisMu, lThisk); + double lThisMu = lNancestors * (par[Index(FitPar::mu)] + par[Index(FitPar::dMu)] * lNancestors); + double lThisk = lNancestors * par[Index(FitPar::k)]; + double lpval = std::pow(1.0 + lThisMu / lThisk, -1); + fNBD->SetParameter(Index(NBDPar::k), lThisk); + fNBD->SetParameter(Index(NBDPar::p), lpval); + + double lMult = 0.0; + static constexpr double MultTolerance = 1e-6; + if (lMultValue > MultTolerance) { + lMult = fAncestorMode != AncestorMode::Continuous ? fNBD->Eval(lMultValue) : ContinuousNBD(lMultValue, lThisMu, lThisk); + } lProbability += lNancestorCount * lMult; } //______________________________________________________ - return par[3] * lProbability; + return par[Index(FitPar::norm)] * lProbability; +} + +double multGlauberNBDFitter::TrentoProbDistrib(const double* x, const double* par) +// Master fitter function +{ + double lMultValue = x[0]; + double lProbability = 0.0; + //______________________________________________________ + // Actually ealuate function + for (int64_t iNSrc = 1; iNSrc < fhNSources->GetNbinsX() + 1; ++iNSrc) { + double lNsources = fhNSources->GetBinCenter(iNSrc); + double lThisMu = lNsources * par[Index(FitPar::mu)]; + double lThisk = lNsources * par[Index(FitPar::k)]; + double lpval = std::pow(1 + lThisMu / lThisk, -1); + fNBD->SetParameter(Index(NBDPar::k), lThisk); + fNBD->SetParameter(Index(NBDPar::p), lpval); + double lMult = fNBD->Eval(lMultValue); + lProbability += fhNSources->GetBinContent(iNSrc) * lMult; + } + //______________________________________________________ + return par[Index(FitPar::norm)] * lProbability; } //________________________________________________________________ -Bool_t multGlauberNBDFitter::SetNpartNcollCorrelation(TH2* hNpNc) +bool multGlauberNBDFitter::SetNpartNcollCorrelation(TH2* hNpNc) { - Bool_t lReturnValue = kTRUE; + bool lReturnValue = true; if (hNpNc) { - fhNpNc = reinterpret_cast(hNpNc); + fhNpNc = hNpNc; } else { - lReturnValue = kFALSE; + lReturnValue = false; } return lReturnValue; } //________________________________________________________________ -Bool_t multGlauberNBDFitter::SetInputV0M(TH1* hV0M) +bool multGlauberNBDFitter::SetNSources(TH1* hNSources) { - Bool_t lReturnValue = kTRUE; + bool lReturnValue = true; + if (hNSources) { + fhNSources = hNSources; + } else { + lReturnValue = false; + } + return lReturnValue; +} + +//________________________________________________________________ +bool multGlauberNBDFitter::SetInputV0M(TH1* hV0M) +{ + bool lReturnValue = true; if (hV0M) { - fhV0M = reinterpret_cast(hV0M); + fhV0M = hV0M; } else { - lReturnValue = kFALSE; + lReturnValue = false; } return lReturnValue; } @@ -265,20 +271,30 @@ TF1* multGlauberNBDFitter::GetGlauberNBD() return fGlauberNBD; } +TF1* multGlauberNBDFitter::GetTrentoNBD() +{ + return fTrentoNBD; +} + //________________________________________________________________ -void multGlauberNBDFitter::SetFitRange(Double_t lMin, Double_t lMax) +void multGlauberNBDFitter::SetFitRange(const double lMin, const double lMax) { - fGlauberNBD->SetRange(lMin, lMax); + if (fGlauberNBD) { + fGlauberNBD->SetRange(lMin, lMax); + } + if (fTrentoNBD) { + fTrentoNBD->SetRange(lMin, lMax); + } } //________________________________________________________________ -void multGlauberNBDFitter::SetFitOptions(TString lOpt) +void multGlauberNBDFitter::SetFitOptions(const TString& lOpt) { fFitOptions = lOpt; } //________________________________________________________________ -void multGlauberNBDFitter::SetFitNpx(Long_t lNpx) +void multGlauberNBDFitter::SetFitNpx(const int64_t lNpx) { fFitNpx = lNpx; } @@ -286,79 +302,120 @@ void multGlauberNBDFitter::SetFitNpx(Long_t lNpx) //________________________________________________________________ void multGlauberNBDFitter::InitAncestor() { - if (!fhNanc) - fhNanc = new TH1D("fhNanc", "", fAncestorMode == 2 ? 10000 : 1000, -0.5, 999.5); + if (!fhNanc) { + fhNanc = new TH1D("fhNanc", "", fAncestorMode == AncestorMode::Continuous ? 10000 : 1000, -0.5, 999.5); + } } //________________________________________________________________ -Bool_t multGlauberNBDFitter::DoFit() +bool multGlauberNBDFitter::DoFit() { - InitAncestor(); // Try very hard, please TVirtualFitter::SetMaxIterations(5000000); + auto timer = new TStopwatch(); + timer->Start(true); + + bool lReturnValue = false; + switch (fNBDFitterMode) { + case NBDFitterMode::Glauber: + LOG(info) << "Doing Glauber fit!!"; + lReturnValue = DoGlauberFit(); + break; + case NBDFitterMode::Trento: + LOG(info) << "Doing Trento fit!!"; + lReturnValue = DoTrentoFit(); + break; + + default: + break; + } + + timer->Stop(); + double lTotalTime = timer->RealTime(); + if (lReturnValue) { + LOG(info) << "---> Fitting succeeded after " << lTotalTime << " seconds"; + } else { + LOG(info) << "---> Fitting failed after " << lTotalTime << " seconds"; + } + return lReturnValue; +} + +bool multGlauberNBDFitter::DoGlauberFit() +{ + InitAncestor(); if (!InitializeNpNc()) { - cout << "---> Initialization of Npart x Ncoll correlation info failed!" << endl; - return kFALSE; + LOG(info) << "---> Initialization of Npart x Ncoll correlation info failed!"; + return false; } - TStopwatch* timer = new TStopwatch(); - timer->Start(kTRUE); - if (fAncestorMode == 0) - cout << "---> Config: Nancestors will be truncated" << endl; - if (fAncestorMode == 1) - cout << "---> Config: Nancestors will be rounded" << endl; - if (fAncestorMode == 2) - cout << "---> Config: Nancestors will be taken as float" << endl; - cout << "---> Now fitting, please wait..." << endl; + if (fAncestorMode == AncestorMode::Truncated) { + LOG(info) << "---> Config: Nancestors will be truncated"; + } + if (fAncestorMode == AncestorMode::Rounded) { + LOG(info) << "---> Config: Nancestors will be rounded"; + } + if (fAncestorMode == AncestorMode::Continuous) { + LOG(info) << "---> Config: Nancestors will be taken as float"; + } + LOG(info) << "---> Now fitting, please wait..."; fGlauberNBD->SetNpx(fFitNpx); TFitResultPtr fitptr; fFitOptions.Append("S"); fitptr = fhV0M->Fit("fGlauberNBD", fFitOptions.Data()); - timer->Stop(); - Double_t lTotalTime = timer->RealTime(); - cout << "---> Fitting took " << lTotalTime << " seconds" << endl; - - fMu = fGlauberNBD->GetParameter(0); - fk = fGlauberNBD->GetParameter(1); - ff = fGlauberNBD->GetParameter(2); - fnorm = fGlauberNBD->GetParameter(3); - fdMu = fGlauberNBD->GetParameter(4); + fMu = fGlauberNBD->GetParameter(Index(FitPar::mu)); + fk = fGlauberNBD->GetParameter(Index(FitPar::k)); + ff = fGlauberNBD->GetParameter(Index(FitPar::f)); + fnorm = fGlauberNBD->GetParameter(Index(FitPar::norm)); + fdMu = fGlauberNBD->GetParameter(Index(FitPar::dMu)); + return fitptr.Get()->IsValid(); +} +bool multGlauberNBDFitter::DoTrentoFit() +{ + fTrentoNBD->SetNpx(fFitNpx); + TFitResultPtr fitptr; + fFitOptions.Append("S"); + fitptr = fhV0M->Fit("fTrentoNBD", fFitOptions.Data()); + fMu = fTrentoNBD->GetParameter(Index(FitPar::mu)); + fk = fTrentoNBD->GetParameter(Index(FitPar::k)); + fnorm = fTrentoNBD->GetParameter(Index(FitPar::norm)); return fitptr.Get()->IsValid(); } //________________________________________________________________ -Bool_t multGlauberNBDFitter::InitializeNpNc() +bool multGlauberNBDFitter::InitializeNpNc() { // This function initializes fhNpNc // Warning: X == Npart, Y == Ncoll - Bool_t lReturnValue = kFALSE; + bool lReturnValue = false; if (fhNpNc) { fNNpNcPairs = 0; // Sweep all allowed values of Npart, Ncoll; find counters - for (int xbin = 1; xbin < 500; xbin++) { - for (int ybin = 1; ybin < 3000; ybin++) { + static constexpr int NBinsX = 500; + static constexpr int NBinsY = 3000; + for (int xbin = 1; xbin < NBinsX; xbin++) { + for (int ybin = 1; ybin < NBinsY; ybin++) { if (fhNpNc->GetBinContent(fhNpNc->FindBin(xbin, ybin)) != 0) { fNpart[fNNpNcPairs] = xbin; fNcoll[fNNpNcPairs] = ybin; - fContent[fNNpNcPairs] = fhNpNc->GetBinContent(fhNpNc->FindBin(xbin, ybin)); + fContent[fNNpNcPairs] = static_cast(fhNpNc->GetBinContent(fhNpNc->FindBin(xbin, ybin))); fNNpNcPairs++; } } } - cout << "Initialized with number of (Npart, Ncoll) pairs: " << fNNpNcPairs << endl; - lReturnValue = kTRUE; + LOG(info) << "Initialized with number of (Npart, Ncoll) pairs: " << fNNpNcPairs; + lReturnValue = true; } else { - cout << "Failed to initialize! Please provide input histogram with (Npart, Ncoll) info!" << endl; - cout << "Please remember to call SetNpartNcollCorrelation before doing fit!" << endl; + LOG(info) << "Failed to initialize! Please provide input histogram with (Npart, Ncoll) info!"; + LOG(info) << "Please remember to call SetNpartNcollCorrelation before doing fit!"; } return lReturnValue; } //________________________________________________________________ -Double_t multGlauberNBDFitter::ContinuousNBD(Double_t n, Double_t mu, Double_t k) +double multGlauberNBDFitter::ContinuousNBD(const double n, const double mu, const double k) { // Adaptation of the negative binomial distribution // for non-integer arguments: analytical continuation @@ -367,43 +424,44 @@ Double_t multGlauberNBDFitter::ContinuousNBD(Double_t n, Double_t mu, Double_t k // in fact it is equivalent to that if 'n' is typecast as // an integer prior to use - Double_t F; - Double_t f; + double F{}; + double f{}; - if (n + k > 100.0) { + static constexpr double NumStabilityThreshold = 100.0; + if (n + k > NumStabilityThreshold) { // log method for handling large numbers - F = TMath::LnGamma(n + k) - TMath::LnGamma(n + 1.) - TMath::LnGamma(k); - f = n * TMath::Log(mu / k) - (n + k) * TMath::Log(1.0 + mu / k); + F = std::lgamma(n + k) - std::lgamma(n + 1.) - std::lgamma(k); + f = n * std::log(mu / k) - (n + k) * std::log1p(mu / k); F = F + f; - F = TMath::Exp(F); + F = std::exp(F); } else { - F = TMath::Gamma(n + k) / (TMath::Gamma(n + 1.) * TMath::Gamma(k)); - f = n * TMath::Log(mu / k) - (n + k) * TMath::Log(1.0 + mu / k); - f = TMath::Exp(f); + F = std::tgamma(n + k) / (std::tgamma(n + 1.) * std::tgamma(k)); + f = n * std::log(mu / k) - (n + k) * std::log1p(mu / k); + f = std::exp(f); F *= f; } return F; } -void multGlauberNBDFitter::CalculateAvNpNc(TProfile* lNPartProf, TProfile* lNCollProf, TH2F* lNPart2DPlot, TH2F* lNColl2DPlot, TH1F* hPercentileMap, Double_t lLoRange, Double_t lHiRange, TH3D* lNpNcEcc, TH2F* lEcc2DPlot, TH3D* lNpNcB, TH2F* lB2DPlot, TH2F* lNancestor2DPlot, Double_t fProbabilityCutoff) +void multGlauberNBDFitter::CalculateAvNpNc(TProfile* lNPartProf, TProfile* lNCollProf, TH2F* lNPart2DPlot, TH2F* lNColl2DPlot, TH1F* hPercentileMap, double lLoRange, double lHiRange, TH3D* lNpNcEcc, TH2F* lEcc2DPlot, TH3D* lNpNcB, TH2F* lB2DPlot, TH2F* lNancestor2DPlot, double fProbabilityCutoff) { - cout << "Calculating , in centrality bins..." << endl; - cout << "Range to calculate: " << lLoRange << " to " << lHiRange << endl; + LOG(info) << "Calculating , in centrality bins..."; + LOG(info) << "Range to calculate: " << lLoRange << " to " << lHiRange; - cout << "Acquiring values from the fit function..." << endl; + LOG(info) << "Acquiring values from the fit function..."; - fMu = fGlauberNBD->GetParameter(0); - fk = fGlauberNBD->GetParameter(1); - ff = fGlauberNBD->GetParameter(2); - fnorm = fGlauberNBD->GetParameter(3); - fdMu = fGlauberNBD->GetParameter(4); + fMu = fGlauberNBD->GetParameter(Index(FitPar::mu)); + fk = fGlauberNBD->GetParameter(Index(FitPar::k)); + ff = fGlauberNBD->GetParameter(Index(FitPar::f)); + fnorm = fGlauberNBD->GetParameter(Index(FitPar::norm)); + fdMu = fGlauberNBD->GetParameter(Index(FitPar::dMu)); - cout << "Please inspect now: " << endl; - cout << "Glauber NBD mu ............: " << fMu << endl; - cout << "Glauber NBD k .............: " << fk << endl; - cout << "Glauber NBD f .............: " << ff << endl; - cout << "Glauber NBD norm ..........: " << fnorm << endl; - cout << "Glauber NBD dmu/dNanc .....: " << fdMu << endl; + LOG(info) << "Please inspect now: "; + LOG(info) << "Glauber NBD mu ............: " << fMu; + LOG(info) << "Glauber NBD k .............: " << fk; + LOG(info) << "Glauber NBD f .............: " << ff; + LOG(info) << "Glauber NBD norm ..........: " << fnorm; + LOG(info) << "Glauber NBD dmu/dNanc .....: " << fdMu; // 2-fold nested loop: // + looping over all Nancestor combinations @@ -416,31 +474,36 @@ void multGlauberNBDFitter::CalculateAvNpNc(TProfile* lNPartProf, TProfile* lNCol } // bypass to zero for (int ibin = 0; ibin < fNNpNcPairs; ibin++) { - if (ibin % 200 == 0) - cout << "At NpNc pair #" << ibin << " of " << fNNpNcPairs << "..." << endl; - Double_t lNAncestors0 = (Int_t)(fNpart[ibin] * ff + fNcoll[ibin] * (1.0 - ff)); - Double_t lNAncestors1 = TMath::Floor(fNpart[ibin] * ff + fNcoll[ibin] * (1.0 - ff) + 0.5); - Double_t lNAncestors2 = (fNpart[ibin] * ff + fNcoll[ibin] * (1.0 - ff)); + static constexpr int LogInterval = 200; + if (ibin % LogInterval == 0) { + LOG(info) << "At NpNc pair #" << ibin << " of " << fNNpNcPairs << "..."; + } + double lNAncestors0 = static_cast(fNpart[ibin] * ff + fNcoll[ibin] * (1.0 - ff)); + double lNAncestors1 = std::floor(fNpart[ibin] * ff + fNcoll[ibin] * (1.0 - ff) + 0.5); + double lNAncestors2 = (fNpart[ibin] * ff + fNcoll[ibin] * (1.0 - ff)); // define ancestors officially - Double_t lNancestors = lNAncestors0; - if (fAncestorMode == 1) + double lNancestors = lNAncestors0; + if (fAncestorMode == AncestorMode::Rounded) { lNancestors = lNAncestors1; - if (fAncestorMode == 2) + } + if (fAncestorMode == AncestorMode::Continuous) { lNancestors = lNAncestors2; + } // eccentricity handling - TH1D* hEccentricity = 0x0; + TH1D* hEccentricity = nullptr; if (lNpNcEcc) { // locate the histogram that corresponds to the eccentricity distribution in this NpNc pair lNpNcEcc->GetXaxis()->SetRange(lNpNcEcc->GetXaxis()->FindBin(fNpart[ibin]), lNpNcEcc->GetXaxis()->FindBin(fNpart[ibin])); lNpNcEcc->GetYaxis()->SetRange(lNpNcEcc->GetYaxis()->FindBin(fNcoll[ibin]), lNpNcEcc->GetYaxis()->FindBin(fNcoll[ibin])); - hEccentricity = reinterpret_cast(lNpNcEcc->Project3D("z")); + hEccentricity = dynamic_cast(lNpNcEcc->Project3D("z")); hEccentricity->SetName(Form("hEccentricity_%i", ibin)); // normalize into unitary fractions - Double_t eccIntegral = hEccentricity->Integral(1, hEccentricity->GetNbinsX() + 1); - if (eccIntegral > 1e-6) { // no counts + double eccIntegral = hEccentricity->Integral(1, hEccentricity->GetNbinsX() + 1); + static constexpr double EccTolerance = 1e-6; + if (eccIntegral > EccTolerance) { // no counts hEccentricity->Scale(1. / eccIntegral); } else { hEccentricity->Scale(0.0); @@ -448,52 +511,58 @@ void multGlauberNBDFitter::CalculateAvNpNc(TProfile* lNPartProf, TProfile* lNCol } // impact parameter handling - TH1D* hImpactParameter = 0x0; + TH1D* hImpactParameter = nullptr; if (lNpNcB) { // locate the histogram that corresponds to the eccentricity distribution in this NpNc pair lNpNcB->GetXaxis()->SetRange(lNpNcB->GetXaxis()->FindBin(fNpart[ibin]), lNpNcB->GetXaxis()->FindBin(fNpart[ibin])); lNpNcB->GetYaxis()->SetRange(lNpNcB->GetYaxis()->FindBin(fNcoll[ibin]), lNpNcB->GetYaxis()->FindBin(fNcoll[ibin])); - hImpactParameter = reinterpret_cast(lNpNcB->Project3D("z")); + hImpactParameter = dynamic_cast(lNpNcB->Project3D("z")); hImpactParameter->SetName(Form("hImpactParameter_%i", ibin)); // normalize into unitary fractions - Double_t bIntegral = hImpactParameter->Integral(1, hImpactParameter->GetNbinsX() + 1); - if (bIntegral > 1e-6) { // no counts + double bIntegral = hImpactParameter->Integral(1, hImpactParameter->GetNbinsX() + 1); + static constexpr double ImpactParTolerance = 1e-6; + if (bIntegral > ImpactParTolerance) { // no counts hImpactParameter->Scale(1. / bIntegral); } else { hImpactParameter->Scale(0.0); } } - for (Long_t lMultValue = 1; lMultValue < lHiRange; lMultValue++) { - Double_t lNancestorCount = fContent[ibin]; - Double_t lThisMu = (((Double_t)lNancestors)) * fMu; - Double_t lThisk = (((Double_t)lNancestors)) * fk; - Double_t lpval = TMath::Power(1 + lThisMu / lThisk, -1); + for (int64_t lMultValue = 1; lMultValue < lHiRange; lMultValue++) { + double lNancestorCount = fContent[ibin]; + double lThisMu = lNancestors * fMu; + double lThisk = lNancestors * fk; + double lpval = std::pow(1 + lThisMu / lThisk, -1); fNBD->SetParameter(1, lThisk); fNBD->SetParameter(0, lpval); - Double_t lMult = 0.0; - if (lMultValue > 1e-6) - lMult = fAncestorMode != 2 ? fNBD->Eval(lMultValue) : ContinuousNBD(lMultValue, lThisMu, lThisk); - Double_t lProbability = lNancestorCount * lMult; + double lMult = 0.0; + static constexpr double MultTolerance = 1e-6; + if (lMultValue > MultTolerance) { + lMult = fAncestorMode != AncestorMode::Continuous ? fNBD->Eval(lMultValue) : ContinuousNBD(lMultValue, lThisMu, lThisk); + } + double lProbability = lNancestorCount * lMult; if (lProbability < fProbabilityCutoff) { continue; // skip if probability of contributing too small } - Double_t lMultValueToFill = lMultValue; - if (hPercentileMap) + double lMultValueToFill = lMultValue; + if (hPercentileMap) { lMultValueToFill = hPercentileMap->GetBinContent(hPercentileMap->FindBin(lMultValue)); + } lNPartProf->Fill(lMultValueToFill, fNpart[ibin], lProbability); lNCollProf->Fill(lMultValueToFill, fNcoll[ibin], lProbability); if (lNancestor2DPlot) { // fill cross-check histogram with lNancestorCount at lNancestors value lNancestor2DPlot->Fill(lMultValueToFill, lNancestors, lProbability); } - if (lNPart2DPlot) + if (lNPart2DPlot) { lNPart2DPlot->Fill(lMultValueToFill, fNpart[ibin], lProbability); - if (lNColl2DPlot) + } + if (lNColl2DPlot) { lNColl2DPlot->Fill(lMultValueToFill, fNcoll[ibin], lProbability); + } if (lNpNcEcc) { // collapse the entire eccentricity distribution for this combo for (int ib = 1; ib < hEccentricity->GetNbinsX() + 1; ib++) { diff --git a/Common/Tools/Multiplicity/multGlauberNBDFitter.h b/Common/Tools/Multiplicity/multGlauberNBDFitter.h index 598ef312ce9..7bf8c5a0346 100644 --- a/Common/Tools/Multiplicity/multGlauberNBDFitter.h +++ b/Common/Tools/Multiplicity/multGlauberNBDFitter.h @@ -8,10 +8,16 @@ // 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. -// + +/// \file multGlauberNBDFitter.h +/// \brief Helper class to perform Glauber fits +/// \author David Dobrigkeit Chinellato + #ifndef COMMON_TOOLS_MULTIPLICITY_MULTGLAUBERNBDFITTER_H_ #define COMMON_TOOLS_MULTIPLICITY_MULTGLAUBERNBDFITTER_H_ +#include + #include #include #include @@ -21,67 +27,111 @@ #include #include -#include + +#include class multGlauberNBDFitter : public TNamed { - public: // basic functionality multGlauberNBDFitter(); explicit multGlauberNBDFitter(const char* name, const char* title = "Glauber+NBD fitter"); - ~multGlauberNBDFitter(); + ~multGlauberNBDFitter() override; + + enum class AncestorMode { + Truncated = 0, // Nancestors = (int) truncation + Rounded, // Nancestors = rounded to nearest integer + Continuous // Nancestors = kept as float, uses ContinuousNBD + }; + + enum class NBDFitterMode { + Glauber = 0, // Uses Npart & Ncoll from TGlauberMC + Trento // Uses trento entropy + }; + + enum class FitPar { + mu = 0, + k, + f, + norm, + dMu + }; + + enum class NBDPar { + p = 0, + k + }; + + template + static constexpr int Index(TEnum e) + { + return static_cast(e); + } // Master fitter function - Double_t ProbDistrib(Double_t* x, Double_t* par); + double GlauberProbDistrib(const double* x, const double* par); + double TrentoProbDistrib(const double* x, const double* par); void InitAncestor(); // Do Fit: where everything happens - Bool_t DoFit(); + bool DoFit(); + bool DoGlauberFit(); + bool DoTrentoFit(); // Set input characteristics: the 2D plot with Npart, Nanc - Bool_t SetNpartNcollCorrelation(TH2* hNpNc); + bool SetNpartNcollCorrelation(TH2* hNpNc); + // Set input characteristics: the 1D plot with trento entropy + bool SetNSources(TH1* hNSources); // Set main input to be fitted (the V0M distribution) - Bool_t SetInputV0M(TH1* hV0M); + bool SetInputV0M(TH1* hV0M); // Interface to get funtions if asked to TF1* GetNBD(); TF1* GetGlauberNBD(); + TF1* GetTrentoNBD(); // Helper - Bool_t InitializeNpNc(); + bool InitializeNpNc(); + void InitGlauberNBD(const float mu, const float k, const float f, const float norm); + void InitTrentoNBD(const float mu = 45, const float k = 1.5, const float norm = 100); // Interface for debug - void SetAncestorMode(Int_t lAncMode = 0) { fAncestorMode = lAncMode; } - Int_t GetAncestorMode() { return fAncestorMode; } + void SetAncestorMode(AncestorMode lAncMode = AncestorMode::Truncated) { fAncestorMode = lAncMode; } + void SetAncestorMode(int lAncMode = Index(AncestorMode::Truncated)) + { + if (lAncMode < Index(AncestorMode::Truncated) || lAncMode > Index(AncestorMode::Continuous)) { + LOG(fatal) << "Invalid ancestor mode: " << lAncMode; + return; + } + fAncestorMode = static_cast(lAncMode); + } + int GetAncestorMode() { return static_cast(fAncestorMode); } TH1D* GetAncestorHistogram() { return fhNanc; } // Interface to set vals - void SetMu(Double_t lVal) { fMu = lVal; } - void Setk(Double_t lVal) { fk = lVal; } - void Setf(Double_t lVal) { ff = lVal; } - void SetNorm(Double_t lVal) { fnorm = lVal; } + void SetMu(const double lVal) { fMu = lVal; } + void Setk(const double lVal) { fk = lVal; } + void Setf(const double lVal) { ff = lVal; } + void SetNorm(const double lVal) { fnorm = lVal; } // Interface to get vals - Double_t GetMu() { return fMu; } - Double_t Getk() { return fk; } - Double_t Getf() { return ff; } - Double_t GetNorm() { return fnorm; } + double GetMu() { return fMu; } + double Getk() { return fk; } + double Getf() { return ff; } + double GetNorm() { return fnorm; } - void SetFitRange(Double_t lMin, Double_t lMax); - void SetFitOptions(TString lOpt); - void SetFitNpx(Long_t lNpx); + void SetFitRange(const double lMin, const double lMax); + void SetFitOptions(const TString& lOpt); + void SetFitNpx(const int64_t lNpx); // For ancestor mode 2 - Double_t ContinuousNBD(Double_t n, Double_t mu, Double_t k); + double ContinuousNBD(const double n, const double mu, const double k); // For estimating Npart, Ncoll in multiplicity bins // also viable: eccentricity, impact parameter, ancestor cross-check plot - void CalculateAvNpNc(TProfile* lNPartProf, TProfile* lNCollProf, TH2F* lNPart2DPlot, TH2F* lNColl2DPlot, TH1F* hPercentileMap, Double_t lLoRange = -1, Double_t lHiRange = -1, TH3D* lNpNcEcc = 0x0, TH2F* lEcc2DPlot = 0x0, TH3D* lNpNcB = 0x0, TH2F* lB2DPlot = 0x0, TH2F* lNancestor2DPlot = 0x0, Double_t fProbabilityCutoff = -1); - - // void Print(Option_t *option="") const; + void CalculateAvNpNc(TProfile* lNPartProf, TProfile* lNCollProf, TH2F* lNPart2DPlot, TH2F* lNColl2DPlot, TH1F* hPercentileMap, double lLoRange = -1, double lHiRange = -1, TH3D* lNpNcEcc = nullptr, TH2F* lEcc2DPlot = nullptr, TH3D* lNpNcB = nullptr, TH2F* lB2DPlot = nullptr, TH2F* lNancestor2DPlot = nullptr, double fProbabilityCutoff = -1); private: // This function serves as the (analytical) NBD @@ -89,36 +139,41 @@ class multGlauberNBDFitter : public TNamed // This function is the key fitting function TF1* fGlauberNBD; + TF1* fTrentoNBD; + + // This is the fitting mode that we use + NBDFitterMode fNBDFitterMode; // Reference histo - TH1D* fhNanc; // basic ancestor distribution - TH2* fhNpNc; // correlation between Npart and Ncoll - TH1* fhV0M; // basic ancestor distribution + TH1D* fhNanc; // basic ancestor distribution + TH2* fhNpNc; // correlation between Npart and Ncoll + TH1* fhNSources; // Trento entropy + TH1* fhV0M; // basic ancestor distribution // Fitting utilities - Bool_t ffChanged; - Double_t fCurrentf; + bool ffChanged; + double fCurrentf; // 0: truncation, 1: rounding, 2: analytical continuation - Int_t fAncestorMode; + AncestorMode fAncestorMode; // Buffer for (Npart, Ncoll) pairs in memory - Double_t* fNpart; - Double_t* fNcoll; - Long_t* fContent; - Long_t fNNpNcPairs; // number of pairs to use - Long_t fMaxNpNcPairs; + double* fNpart; + double* fNcoll; + int64_t* fContent; + int64_t fNNpNcPairs; // number of pairs to use + int64_t fMaxNpNcPairs; // The actual output: mu, k, f, norm - Double_t fMu; - Double_t fdMu; // variable mu option - Double_t fk; - Double_t ff; - Double_t fnorm; + double fMu; + double fdMu; // variable mu option + double fk; + double ff; + double fnorm; TString fFitOptions; - Long_t fFitNpx; + int64_t fFitNpx; - ClassDef(multGlauberNBDFitter, 1); + ClassDefOverride(multGlauberNBDFitter, 1); }; #endif // COMMON_TOOLS_MULTIPLICITY_MULTGLAUBERNBDFITTER_H_ diff --git a/Common/Tools/Multiplicity/multMCCalibrator.h b/Common/Tools/Multiplicity/multMCCalibrator.h index c89fe728328..7f31d0bc600 100644 --- a/Common/Tools/Multiplicity/multMCCalibrator.h +++ b/Common/Tools/Multiplicity/multMCCalibrator.h @@ -41,9 +41,9 @@ class multMCCalibrator : public TNamed // Interface: steering functions to be used in calibration macro // Set Filenames - void SetDataInputFile(TString lFile) { fDataInputFileName = lFile.Data(); } - void SetSimInputFile(TString lFile) { fSimInputFileName = lFile.Data(); } - void SetOutputFile(TString lFile) { fOutputFileName = lFile.Data(); } + void SetDataInputFile(const TString& lFile) { fDataInputFileName = lFile.Data(); } + void SetSimInputFile(const TString& lFile) { fSimInputFileName = lFile.Data(); } + void SetOutputFile(const TString& lFile) { fOutputFileName = lFile.Data(); } // Master Function in this Class: To be called once filenames are set Bool_t Calibrate(); diff --git a/Common/Tools/PID/pidTPCModule.h b/Common/Tools/PID/pidTPCModule.h index de97ef65eba..9e8d93c9e43 100644 --- a/Common/Tools/PID/pidTPCModule.h +++ b/Common/Tools/PID/pidTPCModule.h @@ -309,7 +309,7 @@ class pidTPCModule o2::common::core::enableFlagIfTableRequired(context, "DEdxsCorrected", pidTPCopts.savedEdxsCorrected); // Checking the tables are requested in the workflow and enabling them - auto enableFlag = [&](const std::string particle, o2::framework::Configurable& flag) { + auto enableFlag = [&](const std::string& particle, o2::framework::Configurable& flag) { o2::common::core::enableFlagIfTableRequired(context, "pidTPC" + particle, flag); }; enableFlag("FullEl", pidTPCopts.pidFullEl); diff --git a/Common/Tools/TrackPropagationModule.h b/Common/Tools/TrackPropagationModule.h index 2fa7ea8a10b..d7f7dd6a75d 100644 --- a/Common/Tools/TrackPropagationModule.h +++ b/Common/Tools/TrackPropagationModule.h @@ -22,6 +22,7 @@ #include "Common/Tools/TrackTuner.h" #include +#include #include #include #include @@ -31,13 +32,13 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include @@ -109,7 +110,9 @@ class TrackPropagationModule bool autoDetectDcaCalib = false; // track tuner setting template - void init(TConfigurableGroup const& cGroup, TrackTuner& trackTunerObj, THistoRegistry& registry, TInitContext& initContext) + /// \param calibFromCCDBColumns the task supplies the TrackTuner calibrations from the + /// aod::TrackTunerCCDBObjects columns, so nothing is fetched from CCDB here. + void init(TConfigurableGroup const& cGroup, TrackTuner& trackTunerObj, THistoRegistry& registry, TInitContext& initContext, bool calibFromCCDBColumns = false) { // Checking if the tables are requested in the workflow and enabling them fillTracks = o2::common::core::isTableRequiredInWorkflow(initContext, "Tracks"); @@ -176,23 +179,31 @@ class TrackPropagationModule /// read the track tuner instance configurations, /// to understand whether the TrackTuner::getDcaGraphs function can be called here (input path from string/configurables) /// or inside the process function, to "auto-detect" the input file based on the run number - const auto& workflows = initContext.services().template get(); - for (o2::framework::DeviceSpec const& device : workflows.devices) { /// loop over devices - if (device.name == "propagation-service") { - // loop over the options - // to find the value of TrackTuner::autoDetectDcaCalib - for (const auto& option : device.options) { /// loop over options - if (option.name == "trackTuner.autoDetectDcaCalib") { - // found it! - autoDetectDcaCalib = option.defaultValue.get(); - break; - } - } /// end loop over options + // Read the option off the device we are actually running in. This used to search + // the workflow for a device literally named "propagation-service", which silently + // matched nothing in any other task (propagation-service-v2, -run2, ...), leaving + // autoDetectDcaCalib at its default no matter how the task was configured. + o2::framework::DeviceSpec const& device = initContext.services().template get(); + for (const auto& option : device.options) { /// loop over options + if (option.name == "trackTuner.autoDetectDcaCalib") { + // found it! + autoDetectDcaCalib = option.defaultValue.get(); break; } - } /// end loop over devices + } /// end loop over options LOG(info) << "[TrackPropagationModule] trackTuner.autoDetectDcaCalib it's equal to " << autoDetectDcaCalib; - if (!autoDetectDcaCalib) { + if (calibFromCCDBColumns && trackTunerObj.isInputFileFromCCDB) { + // The column is the single source of truth for the path: its default carries the + // per-period mapping and it is overridden through "ccdb:fTrackTunerDca". Silently + // preferring one of two path settings is how calibrations diverge unnoticed, so a + // leftover trackTuner.pathInputFile is an error rather than a shadowed value. + if (!trackTunerObj.pathInputFile.empty()) { + LOG(fatal) << "[TrackPropagationModule] trackTuner.pathInputFile is set to '" << trackTunerObj.pathInputFile + << "' while the TrackTuner calibrations are taken from the aod::TrackTunerCCDBObjects columns. " + << "Set the path through the \"ccdb:fTrackTunerDca\" option instead, or unset trackTuner.pathInputFile."; + } + LOG(info) << "[TrackPropagationModule] TrackTuner calibrations come from CCDB columns; graphs retrieved in the process function"; + } else if (!autoDetectDcaCalib) { LOG(info) << "[TrackPropagationModule] retrieve the graphs already (we are in propagationService::Init() function)"; trackTunerObj.getDcaGraphs(); } else { @@ -215,24 +226,50 @@ class TrackPropagationModule registry.template get(HIST("hPropagation"))->GetXaxis()->SetBinLabel(3, "Propagation OK"); } + /// Legacy overload for callers still holding a StandardCCDBLoader; forwards the two + /// run-scoped values actually used. Prefer the overload below, which lets the caller + /// source them from CCDB columns instead of a CCDB query. template void fillTrackTables(TConfigurableGroup const& cGroup, TrackTuner& trackTunerObj, TCCDBLoader const& ccdbLoader, TCollisions const& collisions, TTracks const& tracks, TOutputGroup& cursors, THistoRegistry& registry) + { + fillTrackTables(cGroup, trackTunerObj, ccdbLoader.runNumber, ccdbLoader.mMeanVtx, collisions, tracks, cursors, registry); + } + + /// Takes the run-scoped conditions it actually needs (run number for the TrackTuner + /// path, mean vertex for the DCA reference) rather than a CCDB loader object, so that + /// callers are free to source them from CCDB columns instead of a CCDB query. + template + void fillTrackTables(TConfigurableGroup const& cGroup, TrackTuner& trackTunerObj, int currentRunNumber, o2::dataformats::MeanVertexObject const* meanVtx, TCollisions const& collisions, TTracks const& tracks, TOutputGroup& cursors, THistoRegistry& registry) + { + fillTrackTables(cGroup, trackTunerObj, currentRunNumber, meanVtx, nullptr, nullptr, collisions, tracks, cursors, registry); + } + + /// As above, plus the TrackTuner calibration lists taken from the + /// aod::TrackTunerCCDBObjects columns. When they are given, the run-range table that + /// getPathInputFileAutomaticFromCCDB() would have walked has already been applied by + /// the CCDB fetcher, so no CCDB query happens here at all. + template + void fillTrackTables(TConfigurableGroup const& cGroup, TrackTuner& trackTunerObj, int currentRunNumber, o2::dataformats::MeanVertexObject const* meanVtx, TList* dcaCalib, TList* qOverPtCalib, TCollisions const& collisions, TTracks const& tracks, TOutputGroup& cursors, THistoRegistry& registry) { /// retrieve the TrackTuner calibration graphs *if not done yet* /// i.e. if autodetect is required - if (cGroup.useTrackTuner.value && autoDetectDcaCalib && !trackTunerObj.areGraphsConfigured) { + if (cGroup.useTrackTuner.value && !trackTunerObj.areGraphsConfigured && (autoDetectDcaCalib || dcaCalib != nullptr)) { - /// get the run number from the ccdb loader, already initialized - const int runNumber = ccdbLoader.runNumber; - trackTunerObj.setRunNumber(runNumber); + trackTunerObj.setRunNumber(currentRunNumber); - /// setup the "auto-detected" path based on the run number - trackTunerObj.getPathInputFileAutomaticFromCCDB(); - trackTunedTracks->SetTitle(trackTunerObj.outputString.c_str()); + if (dcaCalib != nullptr) { + /// the path was resolved by the CCDB fetcher from the column's run-range mapping + trackTunedTracks->SetTitle(trackTunerObj.outputString.c_str()); + trackTunerObj.getDcaGraphs(dcaCalib, qOverPtCalib); + } else { + /// setup the "auto-detected" path based on the run number + trackTunerObj.getPathInputFileAutomaticFromCCDB(); + trackTunedTracks->SetTitle(trackTunerObj.outputString.c_str()); - /// now that the path is ok, retrieve the graphs - trackTunerObj.getDcaGraphs(); + /// now that the path is ok, retrieve the graphs + trackTunerObj.getDcaGraphs(); + } } if (!fillTracks) { @@ -314,11 +351,11 @@ class TrackPropagationModule } } else { if (fillTracksCov) { - mVtx.setPos({ccdbLoader.mMeanVtx->getX(), ccdbLoader.mMeanVtx->getY(), ccdbLoader.mMeanVtx->getZ()}); - mVtx.setCov(ccdbLoader.mMeanVtx->getSigmaX() * ccdbLoader.mMeanVtx->getSigmaX(), 0.0f, ccdbLoader.mMeanVtx->getSigmaY() * ccdbLoader.mMeanVtx->getSigmaY(), 0.0f, 0.0f, ccdbLoader.mMeanVtx->getSigmaZ() * ccdbLoader.mMeanVtx->getSigmaZ()); + mVtx.setPos({meanVtx->getX(), meanVtx->getY(), meanVtx->getZ()}); + mVtx.setCov(meanVtx->getSigmaX() * meanVtx->getSigmaX(), 0.0f, meanVtx->getSigmaY() * meanVtx->getSigmaY(), 0.0f, 0.0f, meanVtx->getSigmaZ() * meanVtx->getSigmaZ()); isPropagationOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, mTrackParCov, 2.f, matCorr, &mDcaInfoCov); } else { - isPropagationOK = o2::base::Propagator::Instance()->propagateToDCABxByBz({ccdbLoader.mMeanVtx->getX(), ccdbLoader.mMeanVtx->getY(), ccdbLoader.mMeanVtx->getZ()}, mTrackPar, 2.f, matCorr, &mDcaInfo); + isPropagationOK = o2::base::Propagator::Instance()->propagateToDCABxByBz({meanVtx->getX(), meanVtx->getY(), meanVtx->getZ()}, mTrackPar, 2.f, matCorr, &mDcaInfo); } } if (isPropagationOK) { diff --git a/Common/Tools/TrackTuner.h b/Common/Tools/TrackTuner.h index 13a52e46ae7..4e1fdcd8bf9 100644 --- a/Common/Tools/TrackTuner.h +++ b/Common/Tools/TrackTuner.h @@ -19,7 +19,6 @@ #define COMMON_TOOLS_TRACKTUNER_H_ #include -#include #include #include #include @@ -390,7 +389,7 @@ struct TrackTuner : o2::framework::ConfigurableGroup { // parameter not found LOG(fatal) << "\"" << mapParNames[iPar] << "\" not found in the configuration string"; } - std::string str = *it; + const std::string& str = *it; if (str.find('=') == std::string::npos || str.back() == '=') { // value of the parameter missing in the configuration string LOG(fatal) << "Missing value for \"" << mapParNames[iPar] << "\" in the configuration string"; @@ -630,6 +629,20 @@ struct TrackTuner : o2::framework::ConfigurableGroup { ccdb_object_qoverpt = dynamic_cast(inputFileQoverPt->Get("ccdb_object")); } + getDcaGraphs(ccdb_object_dca, ccdb_object_qoverpt); + } + + /// \brief Builds the correction graphs from lists obtained elsewhere, typically straight + /// from the aod::TrackTunerCCDBObjects columns, so no CCDB client is involved. + void getDcaGraphs(TList* ccdb_object_dca, TList* ccdb_object_qoverpt) + { + /// abort if the graphs were already loaded + if (areGraphsConfigured) { + LOG(fatal) << "[TrackTuner::getDcaGraphs()] Function already called, i.e. the calibrations are already loaded. This further call should never happen. Aborting..."; + } + std::string grOneOverPtPionNameMC = "sigmaVsPtMc"; + std::string grOneOverPtPionNameData = "sigmaVsPtData"; + // choose wheter to use corrections w/ PV refit or w/o it, and retrieve the proper TList std::string dir = "woPvRefit"; if (usePvRefitCorrections) { diff --git a/DPG/Tasks/AOTEvent/detectorOccupancyQa.cxx b/DPG/Tasks/AOTEvent/detectorOccupancyQa.cxx index a79bd82a5c3..5e6cffea36d 100644 --- a/DPG/Tasks/AOTEvent/detectorOccupancyQa.cxx +++ b/DPG/Tasks/AOTEvent/detectorOccupancyQa.cxx @@ -779,8 +779,8 @@ struct DetectorOccupancyQaTask { if (!col.selection_bit(kNoITSROFrameBorder)) continue; - std::vector vCollsAssocToGivenColl = vCollsInTimeWin[colIndex]; - std::vector vCollsTimeDeltaWrtGivenColl = vTimeDeltaForColls[colIndex]; + const std::vector& vCollsAssocToGivenColl = vCollsInTimeWin[colIndex]; + const std::vector& vCollsTimeDeltaWrtGivenColl = vTimeDeltaForColls[colIndex]; LOGP(debug, " >> vCollsAssocToGivenColl.size={}", vCollsAssocToGivenColl.size()); diff --git a/DPG/Tasks/AOTEvent/eventSelectionQa.cxx b/DPG/Tasks/AOTEvent/eventSelectionQa.cxx index b9789edaab8..13278810e0c 100644 --- a/DPG/Tasks/AOTEvent/eventSelectionQa.cxx +++ b/DPG/Tasks/AOTEvent/eventSelectionQa.cxx @@ -1415,7 +1415,7 @@ struct EventSelectionQaTask { bool isVertexUPC = flags & dataformats::Vertex>::Flags::UPCMode; // is vertex with UPC settings // the second collision in ROF - std::vector vAssocToSameROF = vCollsInSameITSROF[colIndex]; + const std::vector& vAssocToSameROF = vCollsInSameITSROF[colIndex]; int thisColIndex = vAssocToSameROF[0]; float vZassoc = vCollVz[thisColIndex]; // vZ of the second collision in the same ROF float nPVassoc = vTracksITS567perColl[thisColIndex]; // n PV tracks of the second collision in the same ROF diff --git a/DPG/Tasks/AOTEvent/rofOccupancyQa.cxx b/DPG/Tasks/AOTEvent/rofOccupancyQa.cxx index c9658dce198..40cd2429928 100644 --- a/DPG/Tasks/AOTEvent/rofOccupancyQa.cxx +++ b/DPG/Tasks/AOTEvent/rofOccupancyQa.cxx @@ -754,7 +754,7 @@ struct RofOccupancyQaTask { // LOGP(info, "#### starting new coll: bc={} bcInTF={} bcInITSROF={} rofId={}; noROFborder={}; rofOffset={} rofLength={}", vFoundGlobalBC[colIndex], bcInTF, bcInITSROF, rofId, bc.selection_bit(kNoITSROFrameBorder), rofOffset, rofLength); // LOGP(info, "#### starting new coll: bcInTF={} bcInITSROF={} rofIdInTF={}; noROFborder={}, vZ={} mult={}; rofOffset={} rofLength={}", bcInTF, bcInITSROF, rofIdInTF, bc.selection_bit(kNoITSROFrameBorder), vZ, vTracksITS567perColl[colIndex], rofOffset, rofLength); - std::vector vAssocToSameROF = vCollsInSameITSROF[colIndex]; + const std::vector& vAssocToSameROF = vCollsInSameITSROF[colIndex]; int nITS567tracksForRofVetoStrict = 0; // to veto events with other collisions in the same ITS ROF float nSumAmplFT0CforRofVetoStrict = 0; // to veto events with other collisions in the same ITS ROF // int nITS567tracksForRofVetoStandard = 0; // to veto events with other collisions in the same ITS ROF, with per-collision multiplicity above threshold @@ -836,8 +836,8 @@ struct RofOccupancyQaTask { vArrNoCollInSameRofWithCloseVz.push_back(vVzCutThisColl); continue; } - std::vector vAssocToThisCol = vCollsInTimeWin[colIndex]; - std::vector vCollsTimeDeltaWrtGivenColl = vTimeDeltaForColls[colIndex]; + const std::vector& vAssocToThisCol = vCollsInTimeWin[colIndex]; + const std::vector& vCollsTimeDeltaWrtGivenColl = vTimeDeltaForColls[colIndex]; int nITS567tracksInFullTimeWindow = 0; int sumAmpFT0CInFullTimeWindow = 0; int nITS567tracksForVetoNarrow = 0; // to veto events with nearby collisions (narrower range) diff --git a/DPG/Tasks/AOTTrack/PID/HMPID/hmpidDeuteron.cxx b/DPG/Tasks/AOTTrack/PID/HMPID/hmpidDeuteron.cxx index caaf159c47d..e41e69d842c 100644 --- a/DPG/Tasks/AOTTrack/PID/HMPID/hmpidDeuteron.cxx +++ b/DPG/Tasks/AOTTrack/PID/HMPID/hmpidDeuteron.cxx @@ -9,6 +9,9 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +// \brief Analysis task for the (anti-)deuteron absorption cross section using HMPID +// \authors rocco.liotino@cern.ch + #include "tableHMPID.h" #include @@ -22,7 +25,6 @@ #include #include -#include using namespace o2; using namespace o2::framework; @@ -44,6 +46,9 @@ struct HmpidDeuteron { Configurable cutMinMomGlobalTrack{"cutMinMomGlobalTrack", 1.5f, "minimum momentum of global track"}; + Configurable offsetX{"offsetX", 0.696712f, "Residuals offset - X direction"}; + Configurable offsetY{"offsetY", 2.32849f, "Residuals offset - Y direction"}; + // Configurables for plotting // Momentum Configurable momNBins{"momNBins", 490, "Momentum bins"}; @@ -51,9 +56,9 @@ struct HmpidDeuteron { Configurable momMax{"momMax", 5.0f, "Momentum max"}; // DeltaR - Configurable deltaRNBins{"deltaRNBins", 300, "DeltaR bins"}; + Configurable deltaRNBins{"deltaRNBins", 500, "DeltaR bins"}; Configurable deltaRMin{"deltaRMin", 0.0f, "DeltaR min"}; - Configurable deltaRMax{"deltaRMax", 30.0f, "DeltaR max"}; + Configurable deltaRMax{"deltaRMax", 50.0f, "DeltaR max"}; // nSigma TPC Configurable nSigmaTPCNBins{"nSigmaTPCNBins", 20, "nSigmaTPC bins"}; @@ -86,11 +91,11 @@ struct HmpidDeuteron { Configurable massMax{"massMax", 10.0f, "Mass max"}; // variables for chamber_number and HVs/PCs - const int rich0 = 0, rich1 = 1, rich2 = 2, rich3 = 3, rich4 = 4, rich5 = 5, rich6 = 6; - static const int nCh = 7; - const float nmean = 1.28947; // meanIdxRad(); method from param not working, using value from HMPIDBase/Param.cxx + static constexpr int Rich0 = 0, Rich1 = 1, Rich2 = 2, Rich3 = 3, Rich4 = 4, Rich5 = 5, Rich6 = 6; + static constexpr int Nch = 7; + static constexpr float Nmean = 1.28947; // meanIdxRad(); method from param not working, using value from HMPIDBase/Param.cxx - void init(InitContext const&) + void init(o2::framework::InitContext const&) { // Axes for histograms @@ -120,14 +125,16 @@ struct HmpidDeuteron { registryDA.add("De_Pos_Q_8cm", "De_Pos_Q_8cm", HistType::kTH2F, {axisMom, axisCharge}); registryDA.add("De_Pos_Q_4cm", "De_Pos_Q_4cm", HistType::kTH2F, {axisMom, axisCharge}); - registryDA.add("De_Pos_momentum", "De_Pos_momentum", HistType::kTH2F, {{100, 0.0, 5.0, "#it{p}_{vtx} (GeV/#it{c})"}, {100, 0.0, 5.0, "#it{p}_{hmpid} (GeV/#it{c})"}}); - // nsigma plots - registryDA.add("nSigmaTPC_vs_momHMPID_noCut_DePos", "nSigmaTPC_vs_momHMPID_noCut_DePos", HistType::kTH2F, {axisMom, axisNsigmaTPC}); - registryDA.add("nSigmaTOF_vs_momHMPID_noCut_DePos", "nSigmaTOF_vs_momHMPID_noCut_DePos", HistType::kTH2F, {axisMom, axisNsigmaTOF}); registryDA.add("nSigmaTPC_vs_momHMPID_Cut_DePos", "nSigmaTPC_vs_momHMPID_Cut_DePos", HistType::kTH2F, {axisMom, axisNsigmaTPC}); registryDA.add("nSigmaTOF_vs_momHMPID_Cut_DePos", "nSigmaTOF_vs_momHMPID_Cut_DePos", HistType::kTH2F, {axisMom, axisNsigmaTOF}); + // check residuals distributions + registryDA.add("residualsX_Vs_momentum_Neg_8cm", "residualsX_Vs_momentum_Neg_8cm", HistType::kTH2F, {axisMom, {400, -20.0f, 20.0f, "x_{mip} - x_{track} (cm)"}}); + registryDA.add("residualsY_Vs_momentum_Neg_8cm", "residualsY_Vs_momentum_Neg_8cm", HistType::kTH2F, {axisMom, {400, -20.0f, 20.0f, "y_{mip} - y_{track} (cm)"}}); + registryDA.add("residualsX_Vs_momentum_Pos_8cm", "residualsX_Vs_momentum_Pos_8cm", HistType::kTH2F, {axisMom, {400, -20.0f, 20.0f, "x_{mip} - x_{track} (cm)"}}); + registryDA.add("residualsY_Vs_momentum_Pos_8cm", "residualsY_Vs_momentum_Pos_8cm", HistType::kTH2F, {axisMom, {400, -20.0f, 20.0f, "y_{mip} - y_{track} (cm)"}}); + // Deuteron Neg registryDA.add("incomingDe_Neg_8cm", "incomingDe_Neg_8cm", HistType::kTH1F, {axisMom}); registryDA.add("incomingDe_Neg_4cm", "incomingDe_Neg_4cm", HistType::kTH1F, {axisMom}); @@ -144,18 +151,16 @@ struct HmpidDeuteron { registryDA.add("De_Neg_Q_4cm", "De_Neg_Q_4cm", HistType::kTH2F, {axisMom, axisCharge}); registryDA.add("De_Neg_momentum", "De_Neg_momentum", HistType::kTH2F, {{100, 0.0, 5.0, "#it{p}_{vtx} (GeV/#it{c})"}, {100, 0.0, 5.0, "#it{p}_{hmpid} (GeV/#it{c})"}}); - // first step of the analysis - registryDA.add("residualsX_Vs_momentum", "residualsX_Vs_momentum", HistType::kTH2F, {axisMom, {400, -20.0f, 20.0f, "x_{mip} - x_{track} (cm)"}}); - registryDA.add("residualsY_Vs_momentum", "residualsY_Vs_momentum", HistType::kTH2F, {axisMom, {400, -20.0f, 20.0f, "y_{mip} - y_{track} (cm)"}}); + // check residuals distributions + registryDA.add("residualsX_Vs_momentum_Neg_4cm", "residualsX_Vs_momentum_Neg_4cm", HistType::kTH2F, {axisMom, {400, -20.0f, 20.0f, "x_{mip} - x_{track} (cm)"}}); + registryDA.add("residualsY_Vs_momentum_Neg_4cm", "residualsY_Vs_momentum_Neg_4cm", HistType::kTH2F, {axisMom, {400, -20.0f, 20.0f, "y_{mip} - y_{track} (cm)"}}); + registryDA.add("residualsX_Vs_momentum_Pos_4cm", "residualsX_Vs_momentum_Pos_4cm", HistType::kTH2F, {axisMom, {400, -20.0f, 20.0f, "x_{mip} - x_{track} (cm)"}}); + registryDA.add("residualsY_Vs_momentum_Pos_4cm", "residualsY_Vs_momentum_Pos_4cm", HistType::kTH2F, {axisMom, {400, -20.0f, 20.0f, "y_{mip} - y_{track} (cm)"}}); // nsigma plots - registryDA.add("nSigmaTPC_vs_momHMPID_noCut_DeNeg", "nSigmaTPC_vs_momHMPID_noCut_DeNeg", HistType::kTH2F, {axisMom, axisNsigmaTPC}); - registryDA.add("nSigmaTOF_vs_momHMPID_noCut_DeNeg", "nSigmaTOF_vs_momHMPID_noCut_DeNeg", HistType::kTH2F, {axisMom, axisNsigmaTOF}); registryDA.add("nSigmaTPC_vs_momHMPID_Cut_DeNeg", "nSigmaTPC_vs_momHMPID_Cut_DeNeg", HistType::kTH2F, {axisMom, axisNsigmaTPC}); registryDA.add("nSigmaTOF_vs_momHMPID_Cut_DeNeg", "nSigmaTOF_vs_momHMPID_Cut_DeNeg", HistType::kTH2F, {axisMom, axisNsigmaTOF}); - registryDA.add("hmpidCkovvsMom", "hmpidCkovvsMom", kTH2F, {{500, 0, 10., "#it{p} (GeV/#it{c})"}, {800, 0., 0.8, "#theta_{Ch} (rad)"}}); - // general plots registryDA.add("hEta", "hEta", kTH1F, {axisEta}); registryDA.add("hPhi", "hPhi", kTH1F, {axisPhi}); @@ -163,12 +168,9 @@ struct HmpidDeuteron { registryDA.add("hMass", "hMass", kTH1F, {axisMass}); registryDA.add("hMass_postDeuteron", "hMass_postDeuteron", kTH1F, {axisMass}); + registryDA.add("hMass_Vs_centrality", "hMass_Vs_centrality", kTH2F, {axisMass, {100, 0.0f, 100.0f, "centrality (%)"}}); - // quality check for step distributions - registryDA.add("De_Pos_deltaR_precut", "De_Pos_deltaR_precut", HistType::kTH1F, {axisDeltaR}); - registryDA.add("De_Neg_deltaR_precut", "De_Neg_deltaR_precut", HistType::kTH1F, {axisDeltaR}); - - for (int iCh = 0; iCh < nCh; iCh++) { + for (int iCh = 0; iCh < Nch; iCh++) { registryDA.add(Form("De_Pos_deltaR_%d", iCh), Form("De_Pos_deltaR_%d", iCh), HistType::kTH1F, {axisDeltaR}); registryDA.add(Form("De_Neg_deltaR_%d", iCh), Form("De_Neg_deltaR_%d", iCh), HistType::kTH1F, {axisDeltaR}); registryDA.add(Form("hEta_%d", iCh), Form("hEta_%d", iCh), HistType::kTH1F, {axisEta}); @@ -183,20 +185,27 @@ struct HmpidDeuteron { // ------------------------- // track filters // ------------------------- - if (hmpid.itsNCluster() < minReqClusterITS) + if (hmpid.itsNCluster() < minReqClusterITS) { continue; - if (hmpid.tpcNCluster() < minTPCnClsFound) + } + if (hmpid.tpcNCluster() < minTPCnClsFound) { continue; - if (hmpid.tpcNClsCrossedRows() < minNCrossedRowsTPC) + } + if (hmpid.tpcNClsCrossedRows() < minNCrossedRowsTPC) { continue; - if (hmpid.tpcChi2() > maxChi2TPC) + } + if (hmpid.tpcChi2() > maxChi2TPC) { continue; - if (hmpid.itsChi2() > maxChi2ITS) + } + if (hmpid.itsChi2() > maxChi2ITS) { continue; - if (std::abs(hmpid.dcaXY()) > maxDCAxy) + } + if (std::abs(hmpid.dcaXY()) > maxDCAxy) { continue; - if (std::abs(hmpid.dcaZ()) > maxDCAz) + } + if (std::abs(hmpid.dcaZ()) > maxDCAz) { continue; + } // ------------------------- // derived quantities @@ -206,13 +215,13 @@ struct HmpidDeuteron { const float dx = hmpid.xMip() - hmpid.xTrack(); const float dy = hmpid.yMip() - hmpid.yTrack(); - const float dr = std::hypot(dx, dy); + const float dr = std::hypot(dx - offsetX, dy - offsetY); const float mass = - std::pow(nmean * momAbs * std::cos(hmpid.chAngle()), 2) - + std::pow(Nmean * momAbs * std::cos(hmpid.chAngle()), 2) - std::pow(momAbs, 2); - const int chamber = hmpid.chamber(); + const int chamber = static_cast(hmpid.chamber()); const bool isPos = momHmpid > 0; const bool isNeg = momHmpid < 0; @@ -223,82 +232,62 @@ struct HmpidDeuteron { registryDA.fill(HIST("hPhi"), hmpid.phiTrack()); registryDA.fill(HIST("hMomentumHmpid"), momHmpid); - if (hmpid.chAngle() > 0) + if (hmpid.chAngle() > 0) { registryDA.fill(HIST("hMass"), mass); + registryDA.fill(HIST("hMass_Vs_centrality"), mass, hmpid.centrality()); + } // ------------------------- // RICH chamber maps (0–6) // ------------------------- - if (chamber == rich0) { + if (chamber == Rich0) { registryDA.fill(HIST("hEta_0"), hmpid.etaTrack()); registryDA.fill(HIST("hPhi_0"), hmpid.phiTrack()); } - if (chamber == rich1) { + if (chamber == Rich1) { registryDA.fill(HIST("hEta_1"), hmpid.etaTrack()); registryDA.fill(HIST("hPhi_1"), hmpid.phiTrack()); } - if (chamber == rich2) { + if (chamber == Rich2) { registryDA.fill(HIST("hEta_2"), hmpid.etaTrack()); registryDA.fill(HIST("hPhi_2"), hmpid.phiTrack()); } - if (chamber == rich3) { + if (chamber == Rich3) { registryDA.fill(HIST("hEta_3"), hmpid.etaTrack()); registryDA.fill(HIST("hPhi_3"), hmpid.phiTrack()); } - if (chamber == rich4) { + if (chamber == Rich4) { registryDA.fill(HIST("hEta_4"), hmpid.etaTrack()); registryDA.fill(HIST("hPhi_4"), hmpid.phiTrack()); } - if (chamber == rich5) { + if (chamber == Rich5) { registryDA.fill(HIST("hEta_5"), hmpid.etaTrack()); registryDA.fill(HIST("hPhi_5"), hmpid.phiTrack()); } - if (chamber == rich6) { + if (chamber == Rich6) { registryDA.fill(HIST("hEta_6"), hmpid.etaTrack()); registryDA.fill(HIST("hPhi_6"), hmpid.phiTrack()); } - // ------------------------- - // precut deltaR - // ------------------------- - if (isPos) - registryDA.fill(HIST("De_Pos_deltaR_precut"), dr); - if (isNeg) - registryDA.fill(HIST("De_Neg_deltaR_precut"), dr); - - // ------------------------- - // nsigma pre-cut - // ------------------------- - if (isPos) { - registryDA.fill(HIST("nSigmaTPC_vs_momHMPID_noCut_DePos"), - momAbs, hmpid.tpcNSigmaDe()); - registryDA.fill(HIST("nSigmaTOF_vs_momHMPID_noCut_DePos"), - momAbs, hmpid.tofNSigmaDe()); - } - - if (isNeg) { - registryDA.fill(HIST("nSigmaTPC_vs_momHMPID_noCut_DeNeg"), - momAbs, hmpid.tpcNSigmaDe()); - registryDA.fill(HIST("nSigmaTOF_vs_momHMPID_noCut_DeNeg"), - momAbs, hmpid.tofNSigmaDe()); - } - // ------------------------- // deuteron candidate cuts - TPC // ------------------------- if (hmpid.tpcNSigmaDe() < nsigmaTPCMin || - hmpid.tpcNSigmaDe() > nsigmaTPCMax) + hmpid.tpcNSigmaDe() > nsigmaTPCMax) { continue; + } // ------------------------- // post TPC cut // ------------------------- - if (isPos) + if (isPos) { registryDA.fill(HIST("nSigmaTPC_vs_momHMPID_Cut_DePos"), momAbs, hmpid.tpcNSigmaDe()); - if (isNeg) + } + if (isNeg) { registryDA.fill(HIST("nSigmaTPC_vs_momHMPID_Cut_DeNeg"), momAbs, hmpid.tpcNSigmaDe()); + } registryDA.fill(HIST("hMass_postDeuteron"), mass); @@ -306,8 +295,9 @@ struct HmpidDeuteron { // deuteron candidate cuts - TOF // ------------------------- if (hmpid.tofNSigmaDe() < nsigmaTOFMin || - hmpid.tofNSigmaDe() > nsigmaTOFMax) + hmpid.tofNSigmaDe() > nsigmaTOFMax) { continue; + } // ------------------------- // TOF nsigma @@ -315,8 +305,6 @@ struct HmpidDeuteron { if (isPos) { registryDA.fill(HIST("nSigmaTOF_vs_momHMPID_Cut_DePos"), momAbs, hmpid.tofNSigmaDe()); - registryDA.fill(HIST("De_Pos_momentum"), - hmpid.momentumTrack(), momAbs); } if (isNeg) { @@ -328,55 +316,64 @@ struct HmpidDeuteron { // DEUTERON CANDIDATES AFTER ALL CUTS // ------------------------- - // ------------------------- - // Ckov angle vs momentum - // ------------------------- - registryDA.fill(HIST("hmpidCkovvsMom"), momHmpid, hmpid.chAngle()); - // ------------------------- // deltaR per chamber (Pos/Neg) // ------------------------- - if (chamber == rich0) { - if (isPos) + if (chamber == Rich0) { + if (isPos) { registryDA.fill(HIST("De_Pos_deltaR_0"), dr); - if (isNeg) + } + if (isNeg) { registryDA.fill(HIST("De_Neg_deltaR_0"), dr); + } } - if (chamber == rich1) { - if (isPos) + if (chamber == Rich1) { + if (isPos) { registryDA.fill(HIST("De_Pos_deltaR_1"), dr); - if (isNeg) + } + if (isNeg) { registryDA.fill(HIST("De_Neg_deltaR_1"), dr); + } } - if (chamber == rich2) { - if (isPos) + if (chamber == Rich2) { + if (isPos) { registryDA.fill(HIST("De_Pos_deltaR_2"), dr); - if (isNeg) + } + if (isNeg) { registryDA.fill(HIST("De_Neg_deltaR_2"), dr); + } } - if (chamber == rich3) { - if (isPos) + if (chamber == Rich3) { + if (isPos) { registryDA.fill(HIST("De_Pos_deltaR_3"), dr); - if (isNeg) + } + if (isNeg) { registryDA.fill(HIST("De_Neg_deltaR_3"), dr); + } } - if (chamber == rich4) { - if (isPos) + if (chamber == Rich4) { + if (isPos) { registryDA.fill(HIST("De_Pos_deltaR_4"), dr); - if (isNeg) + } + if (isNeg) { registryDA.fill(HIST("De_Neg_deltaR_4"), dr); + } } - if (chamber == rich5) { - if (isPos) + if (chamber == Rich5) { + if (isPos) { registryDA.fill(HIST("De_Pos_deltaR_5"), dr); - if (isNeg) + } + if (isNeg) { registryDA.fill(HIST("De_Neg_deltaR_5"), dr); + } } - if (chamber == rich6) { - if (isPos) + if (chamber == Rich6) { + if (isPos) { registryDA.fill(HIST("De_Pos_deltaR_6"), dr); - if (isNeg) + } + if (isNeg) { registryDA.fill(HIST("De_Neg_deltaR_6"), dr); + } } // ------------------------- @@ -391,6 +388,9 @@ struct HmpidDeuteron { registryDA.fill(HIST("De_Pos_Q_8cm"), momAbs, hmpid.chargeMip()); registryDA.fill(HIST("De_Pos_deltaR_8cm"), dr); registryDA.fill(HIST("nSigmaTOF_vs_momHMPID_DePos_8cm"), momAbs, hmpid.tofNSigmaDe()); + + registryDA.fill(HIST("residualsX_Vs_momentum_Pos_8cm"), momAbs, dx); + registryDA.fill(HIST("residualsY_Vs_momentum_Pos_8cm"), momAbs, dy); } if (isNeg && chamber == abs8cm) { @@ -400,8 +400,8 @@ struct HmpidDeuteron { registryDA.fill(HIST("De_Neg_deltaR_8cm"), dr); registryDA.fill(HIST("nSigmaTOF_vs_momHMPID_DeNeg_8cm"), momAbs, hmpid.tofNSigmaDe()); - registryDA.fill(HIST("residualsX_Vs_momentum"), momAbs, dx); - registryDA.fill(HIST("residualsY_Vs_momentum"), momAbs, dy); + registryDA.fill(HIST("residualsX_Vs_momentum_Neg_8cm"), momAbs, dx); + registryDA.fill(HIST("residualsY_Vs_momentum_Neg_8cm"), momAbs, dy); } if (isPos && chamber == abs4cm) { @@ -410,6 +410,9 @@ struct HmpidDeuteron { registryDA.fill(HIST("De_Pos_Q_4cm"), momAbs, hmpid.chargeMip()); registryDA.fill(HIST("De_Pos_deltaR_4cm"), dr); registryDA.fill(HIST("nSigmaTOF_vs_momHMPID_DePos_4cm"), momAbs, hmpid.tofNSigmaDe()); + + registryDA.fill(HIST("residualsX_Vs_momentum_Pos_4cm"), momAbs, dx); + registryDA.fill(HIST("residualsY_Vs_momentum_Pos_4cm"), momAbs, dy); } if (isNeg && chamber == abs4cm) { @@ -418,6 +421,9 @@ struct HmpidDeuteron { registryDA.fill(HIST("De_Neg_Q_4cm"), momAbs, hmpid.chargeMip()); registryDA.fill(HIST("De_Neg_deltaR_4cm"), dr); registryDA.fill(HIST("nSigmaTOF_vs_momHMPID_DeNeg_4cm"), momAbs, hmpid.tofNSigmaDe()); + + registryDA.fill(HIST("residualsX_Vs_momentum_Neg_4cm"), momAbs, dx); + registryDA.fill(HIST("residualsY_Vs_momentum_Neg_4cm"), momAbs, dy); } } // end of loop over hmpidTable } // end of process diff --git a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOF.cxx b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOF.cxx index bbe18f83730..bb6afc2a437 100644 --- a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOF.cxx +++ b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOF.cxx @@ -379,7 +379,7 @@ struct tofPidQa { int evtimeflag = 0; if constexpr (fillHistograms) { - for (auto t : tracks) { + for (const auto& t : tracks) { if (!t.hasTOF()) { // Skipping tracks without TOF continue; } @@ -529,7 +529,7 @@ struct tofPidQa { soa::Filtered const& tracks) { isEventSelected(collision, tracks); - for (auto t : tracks) { + for (const auto& t : tracks) { isTrackSelected(collision, t); } } @@ -543,7 +543,7 @@ struct tofPidQa { return; } - for (auto t : tracks) { + for (const auto& t : tracks) { if (!isTrackSelected(collision, t)) { continue; } diff --git a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFDynamic.cxx b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFDynamic.cxx index e526840e19f..bec2f335512 100644 --- a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFDynamic.cxx +++ b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFDynamic.cxx @@ -401,7 +401,7 @@ struct tofPidQaDynamic { int evtimeflag = 0; if constexpr (fillHistograms) { - for (auto t : tracks) { + for (const auto& t : tracks) { if (!t.hasTOF()) { // Skipping tracks without TOF continue; } @@ -554,7 +554,7 @@ struct tofPidQaDynamic { tofResponse->processSetup(collision.bc_as()); isEventSelected(collision, tracks); - for (auto t : tracks) { + for (const auto& t : tracks) { isTrackSelected(collision, t); } } @@ -568,7 +568,7 @@ struct tofPidQaDynamic { return; } - for (auto t : tracks) { + for (const auto& t : tracks) { if (!isTrackSelected(collision, t)) { continue; } diff --git a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFEvTime.cxx b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFEvTime.cxx index 35c33cb64fa..f9b6f0c620a 100644 --- a/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFEvTime.cxx +++ b/DPG/Tasks/AOTTrack/PID/TOF/qaPIDTOFEvTime.cxx @@ -167,7 +167,7 @@ struct tofPidCollisionTimeQa { } listEfficiency.setObject(new THashList); - auto makeEfficiency = [&](TString effname, TString efftitle) { + auto makeEfficiency = [&](const TString& effname, const TString& efftitle) { listEfficiency->Add(new TEfficiency(effname, efftitle + ";TOF multiplicity;Efficiency", nBinsMultiplicity, 0, rangeMultiplicity)); }; diff --git a/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx b/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx index aa2f13ba744..dac01d5f092 100644 --- a/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx +++ b/DPG/Tasks/AOTTrack/V0Cascades/perfK0sResolution.cxx @@ -345,7 +345,7 @@ struct perfK0sResolution { } template - bool isEventAccepted(TCollision collision, bool fillHists) + bool isEventAccepted(const TCollision& collision, bool fillHists) // check whether the collision passes our collision selections { if (fillHists) diff --git a/DPG/Tasks/AOTTrack/qaEfficiency.cxx b/DPG/Tasks/AOTTrack/qaEfficiency.cxx index b8b5bc4631e..6a998053a8a 100644 --- a/DPG/Tasks/AOTTrack/qaEfficiency.cxx +++ b/DPG/Tasks/AOTTrack/qaEfficiency.cxx @@ -500,7 +500,7 @@ struct QaEfficiency { subList->SetName(partName); listEfficiencyMC->Add(subList); - auto makeEfficiency = [&](const TString effname, auto h) { // 1D efficiencies + auto makeEfficiency = [&](const TString& effname, const auto& h) { // 1D efficiencies LOG(debug) << " Making 1D TEfficiency " << effname << " from " << h->GetName(); const TAxis* axis = h->GetXaxis(); TString efftitle = h->GetTitle(); @@ -563,7 +563,7 @@ struct QaEfficiency { makeEfficiency("ITS-TPC_vsPhi_Prm_Trk", hPhiTrkItsTpcPrm[histogramIndex]); makeEfficiency("ITS-TPC-TOF_vsPhi_Prm", hPhiItsTpcTofPrm[histogramIndex]); - auto makeEfficiency2D = [&](const TString effname, auto h) { // 2D efficiencies + auto makeEfficiency2D = [&](const TString& effname, const auto& h) { // 2D efficiencies LOG(debug) << " Making 2D TEfficiency " << effname << " from " << h->GetName(); const TAxis* axisX = h->GetXaxis(); const TAxis* axisY = h->GetYaxis(); @@ -898,7 +898,7 @@ struct QaEfficiency { listEfficiencyData.setObject(new THashList); if (makeEff) { LOG(debug) << "Making TEfficiency for Data"; - auto makeEfficiency = [&](TString effname, TString efftitle, auto templateHisto, TEfficiency*& eff) { + auto makeEfficiency = [&](const TString& effname, const TString& efftitle, auto templateHisto, TEfficiency*& eff) { TAxis* axis = histos.get(templateHisto)->GetXaxis(); if (axis->IsVariableBinSize()) { eff = new TEfficiency(effname, efftitle, axis->GetNbins(), axis->GetXbins()->GetArray()); @@ -927,7 +927,7 @@ struct QaEfficiency { "TPC-TOF M.E. in data " + tagPhi + ";#it{#varphi} (rad);Efficiency", HIST("Data/pos/phi/its_tpc_tof"), effTPCTOFMatchingVsPhi); - auto makeEfficiency2D = [&](TString effname, TString efftitle, auto templateHistoX, auto templateHistoY, TEfficiency*& eff) { + auto makeEfficiency2D = [&](const TString& effname, const TString& efftitle, auto templateHistoX, auto templateHistoY, TEfficiency*& eff) { TAxis* axisX = histos.get(templateHistoX)->GetXaxis(); TAxis* axisY = histos.get(templateHistoY)->GetYaxis(); if (axisX->IsVariableBinSize() || axisY->IsVariableBinSize()) { @@ -1366,7 +1366,7 @@ struct QaEfficiency { } // Filling 1D efficiencies - auto doFillEfficiency = [&](const TString effname, auto num, auto den) { + auto doFillEfficiency = [&](const TString& effname, const auto& num, const auto& den) { TEfficiency* eff = static_cast(subList->FindObject(effname)); if (!eff) { LOG(warning) << "Cannot find TEfficiency " << effname; @@ -1436,7 +1436,7 @@ struct QaEfficiency { } // Filling 2D efficiencies - auto fillEfficiency2D = [&](const TString effname, auto num, auto den) { + auto fillEfficiency2D = [&](const TString& effname, const auto& num, const auto& den) { TEfficiency* eff = static_cast(subList->FindObject(effname)); if (!eff) { LOG(warning) << "Cannot find TEfficiency " << effname; diff --git a/DPG/Tasks/AOTTrack/qaEventTrackLite.cxx b/DPG/Tasks/AOTTrack/qaEventTrackLite.cxx index 34373a3e1ad..dc1f2bed237 100644 --- a/DPG/Tasks/AOTTrack/qaEventTrackLite.cxx +++ b/DPG/Tasks/AOTTrack/qaEventTrackLite.cxx @@ -154,7 +154,7 @@ struct qaEventTrackLite { /// return initBBok ? mMip * o2::common::BetheBlochAleph(x[0] / par[0], mBetheBlockAleph[0], mBetheBlockAleph[1], mBetheBlockAleph[2], mBetheBlockAleph[3], mBetheBlockAleph[4]) * std::pow(par[1], mChargeFactor) : 0.; } - void setUpBetheBlockAleph(std::string str_case) + void setUpBetheBlockAleph(const std::string& str_case) { if (str_case.find("LHC22c") != std::string::npos) { // From A. Kalteyer (2022 Jul 18) @@ -418,7 +418,7 @@ struct qaEventTrackLite { histos.fill(HIST("Tracks/TPC/dEdxvsP"), p, track.tpcSignal()); histos.fill(HIST("Tracks/TPC/dEdxvsPvsEta"), p, track.eta(), track.tpcSignal()); if (betheBlock.initBBok) { - auto tpcdEdxRes = [&](TF1 func) { return track.tpcSignal() - func.Eval(p); }; + auto tpcdEdxRes = [&](const TF1& func) { return track.tpcSignal() - func.Eval(p); }; if (b_tpcResProton) { histos.fill(HIST("Tracks/TPC/dEdxvsPproton"), p, tpcdEdxRes(funcBBproton)); histos.fill(HIST("Tracks/TPC/dEdxvsPprotonvsEta"), p, track.eta(), tpcdEdxRes(funcBBproton)); diff --git a/DPG/Tasks/AOTTrack/qaTrackSplitting.cxx b/DPG/Tasks/AOTTrack/qaTrackSplitting.cxx index 680cb819b34..5daa92f6b0a 100644 --- a/DPG/Tasks/AOTTrack/qaTrackSplitting.cxx +++ b/DPG/Tasks/AOTTrack/qaTrackSplitting.cxx @@ -134,10 +134,11 @@ struct qaTrackSplitting { if (!collision.sel8()) { return; } - typedef std::shared_ptr trkType; + using TrackType = const TrackCandidatesMC::iterator; + using TrackTypePtr = std::shared_ptr; - std::map> particleUsageCounter; - for (auto track : tracks) { + std::map> particleUsageCounter; + for (const auto& track : tracks) { histos.fill(HIST("tracks"), 0); if (!track.has_mcParticle()) { continue; @@ -156,7 +157,7 @@ struct qaTrackSplitting { continue; } histos.fill(HIST("tracks"), 4); - particleUsageCounter[track.mcParticleId()].push_back(std::make_shared(track)); + particleUsageCounter[track.mcParticleId()].push_back(std::make_shared(track)); } for (const auto& [mcId, tracksMatched] : particleUsageCounter) { histos.fill(HIST("numberOfRecoed"), tracksMatched.size()); diff --git a/DPG/Tasks/AOTTrack/tagAndProbeDmesons.cxx b/DPG/Tasks/AOTTrack/tagAndProbeDmesons.cxx index 842f167d7d2..7fbc609af28 100644 --- a/DPG/Tasks/AOTTrack/tagAndProbeDmesons.cxx +++ b/DPG/Tasks/AOTTrack/tagAndProbeDmesons.cxx @@ -1296,7 +1296,7 @@ struct ProbeThirdTrack { } template - void loopOverThirdTrack(TTrackIndices const& groupedTrackThirdIndices, TTracks const& /*tracks*/, TTrack const& trackFirst, TTrack const& trackSecond, PParticles const mcParticles, const int motherIdxTag, const float radius) + void loopOverThirdTrack(TTrackIndices const& groupedTrackThirdIndices, TTracks const& /*tracks*/, TTrack const& trackFirst, TTrack const& trackSecond, PParticles const& mcParticles, const int motherIdxTag, const float radius) { for (const auto& trackIndex : groupedTrackThirdIndices) { auto trackThird = trackIndex.template track_as(); diff --git a/DPG/Tasks/ITS/filterTracks.cxx b/DPG/Tasks/ITS/filterTracks.cxx index 6a9ee148142..9af02996211 100644 --- a/DPG/Tasks/ITS/filterTracks.cxx +++ b/DPG/Tasks/ITS/filterTracks.cxx @@ -225,7 +225,7 @@ struct FilterTracks { { } - void fillTableData(auto track) + void fillTableData(const auto& track) { filteredTracksCollIdx(track.collisionId()); @@ -235,7 +235,7 @@ struct FilterTracks { filteredTracksTableExtraDet(track.itsClusterSizes(), track.itsChi2NCl(), track.tpcChi2NCl(), track.tpcNClsFound(), track.trackTime()); } - void fillTableDataMC(auto track, aod::McParticles const& mcParticles) + void fillTableDataMC(const auto& track, aod::McParticles const& mcParticles) { fillTableData(track); diff --git a/DPG/Tasks/TPC/CMakeLists.txt b/DPG/Tasks/TPC/CMakeLists.txt index b8c68ba36fc..12030997bc6 100644 --- a/DPG/Tasks/TPC/CMakeLists.txt +++ b/DPG/Tasks/TPC/CMakeLists.txt @@ -17,4 +17,9 @@ o2physics_add_dpl_workflow(pid-tpc-skimscreation o2physics_add_dpl_workflow(pid-tpc-tree-creator-light SOURCES tpcTreeCreatorLight.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore - COMPONENT_NAME Analysis) \ No newline at end of file + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(tree-creator-pid-tpc-diagnostics + SOURCES treeCreatorPidTpcDiagnostics.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::AnalysisCCDB + COMPONENT_NAME Analysis) diff --git a/DPG/Tasks/TPC/treeCreatorPidTpcDiagnostics.cxx b/DPG/Tasks/TPC/treeCreatorPidTpcDiagnostics.cxx new file mode 100644 index 00000000000..9f30e558d2c --- /dev/null +++ b/DPG/Tasks/TPC/treeCreatorPidTpcDiagnostics.cxx @@ -0,0 +1,301 @@ +// 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. + +/// \file treeCreatorPidTpcDiagnostics.cxx +/// \brief Creates trees with PID QA variables along with variables used for NN training +/// +/// \author Ana Marin +/// \author Oleksii Lubynets + +#include "treeCreatorPidTpcDiagnostics.h" + +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/CCDB/ctpRateFetcher.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "DPG/Tasks/TPC/tpcSkimsTableCreator.h" +#include "DPG/Tasks/TPC/utilsTpcSkimsTableCreator.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::track; +using namespace o2::dpg_tpcskimstablecreator; + +#define DO_FOR_ALL_PARTICLES(MACRO) \ + MACRO(El, Electron) \ + MACRO(Mu, Muon) \ + MACRO(Pi, Pion) \ + MACRO(Ka, Kaon) \ + MACRO(Pr, Proton) \ + MACRO(De, Deuteron) \ + MACRO(Tr, Triton) \ + MACRO(He, Helium3) \ + MACRO(Al, Alpha) + +struct TreeCreatorPidTpcDiagnostics { + Produces rowPidTpcDiagnostics; + + Configurable applyEvSel{"applyEvSel", 2, "Flag to apply event selection: 0 -> no event selection, 1 -> Run 2 event selection, 2 -> Run 3 event selection"}; + Configurable cutVtxZ{"cutVtxZ", 10.f, "Cut on vertex Z position [cm]"}; + Configurable trackSelection{"trackSelection", 1, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"}; + Configurable requireGlobalTrack{"requireGlobalTrack", true, "Skip non-global tracks"}; + Configurable requireIts{"requireIts", true, "Skip tracks without ITS"}; + Configurable cutMinTPCNcls{"cutMinTPCNcls", 0, "Minimum number or TPC Clusters for tracks"}; + Configurable cutRapidity{"cutRapidity", 999.f, "Rapidity cut"}; + Configurable nClNorm{"nClNorm", 152.f, "Number of cluster normalization. Run 2: 159, Run 3 152"}; + // Configurable for the path of CCDB General Run Parameters LHC Interface information + Configurable ccdbPathGrpLhcIf{"ccdbPathGrpLhcIf", "GLO/Config/GRPLHCIF", "Path on the CCDB for the GRPLHCIF object"}; + // Configurables for output tables reservation size + Configurable reserveRatio{"reserveRatio", 1.f, "Ratio of how many rows expected in the output table to the input Tracks table size"}; + Configurable saveReserveQaHisto{"saveReserveQaHisto", true, "Flag to save the DF-wise ratio of output table size to that of input table"}; + // Configurables for run condtion table + Configurable rctLabel{"rctLabel", "CBT_hadronPID", "select 1 [CBT, CBT_hadronPID, CBT_muon_glo] see O2Physics/Common/CCDB/RCTSelectionFlags.h"}; + Configurable checkZdc{"checkZdc", false, "set ZDC flag for PbPb"}; + Configurable treatLimitedAcceptanceAsBad{"treatLimitedAcceptanceAsBad", false, "reject all events where the detectors relevant for the specified Runlist are flagged as LimitedAcceptance"}; + Configurable requireGoodRct{"requireGoodRct", false, "require good detector flag in run condtion table"}; + +#define DECLARE_PARTICLE_WISE_CONFIGURABLES(ParticleNameShort, ParticleNameLong) \ + Configurable cutTpcInnerParameterMin##ParticleNameLong{"cutTpcInnerParameterMin" #ParticleNameLong, 0.f, "Lower-value cut on tpcInnerParam for " #ParticleNameLong}; /* o2-linter: disable=name/configurable (Configurable defined in macro)*/ \ + Configurable cutTpcInnerParameterMax##ParticleNameLong{"cutTpcInnerParameterMax" #ParticleNameLong, 999.f, "Upper-value cut on tpcInnerParam for " #ParticleNameLong}; /* o2-linter: disable=name/configurable (Configurable defined in macro)*/ \ + Configurable cutNSigmaTpcAbs##ParticleNameLong{"cutNSigmaTpcAbs" #ParticleNameLong, 999.f, "Cut on absolute value of nSigmaTpc for " #ParticleNameLong}; // o2-linter: disable=name/configurable (Configurable defined in macro) + + DO_FOR_ALL_PARTICLES(DECLARE_PARTICLE_WISE_CONFIGURABLES) +#undef DECLARE_PARTICLE_WISE_CONFIGURABLES + +#define PACK_CONFIGURABLES_TO_ARRAY(ParticleNameShort, ParticleNameLong) &cutTpcInnerParameterMin##ParticleNameLong, + std::array*, PID::Alpha + 1> cutTpcInnerParameterMin{ + DO_FOR_ALL_PARTICLES(PACK_CONFIGURABLES_TO_ARRAY)}; +#undef PACK_CONFIGURABLES_TO_ARRAY + +#define PACK_CONFIGURABLES_TO_ARRAY(ParticleNameShort, ParticleNameLong) &cutTpcInnerParameterMax##ParticleNameLong, + std::array*, PID::Alpha + 1> cutTpcInnerParameterMax{ + DO_FOR_ALL_PARTICLES(PACK_CONFIGURABLES_TO_ARRAY)}; +#undef PACK_CONFIGURABLES_TO_ARRAY + +#define PACK_CONFIGURABLES_TO_ARRAY(ParticleNameShort, ParticleNameLong) &cutNSigmaTpcAbs##ParticleNameLong, + std::array*, PID::Alpha + 1> cutNSigmaTpcAbs{ + DO_FOR_ALL_PARTICLES(PACK_CONFIGURABLES_TO_ARRAY)}; +#undef PACK_CONFIGURABLES_TO_ARRAY + + HistogramRegistry registry{"registry", {}}; + + Service ccdb{}; + + ctpRateFetcher mRateFetcher; + + o2::aod::rctsel::RCTFlagsChecker rctChecker; + + using CollisionsExtra = soa::Join; + using TrackCandidates = soa::Join; + + Preslice perCollisionTracks = aod::track::collisionId; + + int mEnabledParticles{0}; + int mProcessedParticles{0}; + + template + bool initPerParticle() + { + static_assert(ParticleId >= 0 && ParticleId <= PID::Alpha && "Particle index outside limits"); + int enabledProcesses{0}; + + switch (ParticleId) { +#define INIT_PARTICLE(ParticleNameShort, ParticleNameLong) \ + case PID::ParticleNameLong: \ + if (!doprocess##ParticleNameLong && !doprocessFull##ParticleNameLong && !doprocessFullWithTOF##ParticleNameLong) { \ + return false; \ + } \ + if (doprocess##ParticleNameLong) { \ + ++enabledProcesses; \ + } \ + if (doprocessFull##ParticleNameLong) { \ + ++enabledProcesses; \ + } \ + if (doprocessFullWithTOF##ParticleNameLong) { \ + ++enabledProcesses; \ + } \ + LOG(info) << "Enabled TPC QA for " << #ParticleNameLong; \ + break; + + DO_FOR_ALL_PARTICLES(INIT_PARTICLE) +#undef INIT_PARTICLE + } + if (enabledProcesses != 1) { + LOG(fatal) << "Cannot enable more than one process function per particle, check and retry!"; + } + return true; + } + + void init(o2::framework::InitContext&) + { + static_for<0, PID::Alpha>([&](auto ParticleId) { + mEnabledParticles += static_cast(initPerParticle()); + }); + + if (mEnabledParticles == 0) { + LOG(fatal) << "At least one process function should be enabled, check and retry!"; + } + + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setFatalWhenNull(false); + + rctChecker.init(rctLabel, checkZdc, treatLimitedAcceptanceAsBad); + + if (saveReserveQaHisto) { + registry.add("hOutputRatio", "Table out/in ratio;Table out/in ratio;Entries", {HistType::kTH1F, {{100, 0, reserveRatio}}}); + } + } + + template + void processSingleParticle(CollisionsExtra const& collisions, + TrackType const& tracks) + { + if (mProcessedParticles == 0) { + rowPidTpcDiagnostics.reserve(tracks.size() * reserveRatio); + } + + std::string irSource{}; + float sqrtSNN{}; // placeholder to satisfy evaluateIrSourceAndSqrtSnn's signature + bool isFirstCollision{true}; + for (const auto& collision : collisions) { + if (!isEventSelected(collision, applyEvSel) || (std::abs(collision.posZ()) > cutVtxZ)) { + continue; + } + + const bool isGoodRctEvent = rctChecker.checkTable(collision); + if (requireGoodRct && !isGoodRctEvent) { + continue; + } + + const auto bc = collision.bc_as(); + if (isFirstCollision) { + evaluateIrSourceAndSqrtSnn(ccdb, ccdbPathGrpLhcIf, bc.timestamp(), irSource, sqrtSNN); + } + isFirstCollision = false; + const float ft0Occ = collision.ft0cOccupancyInTimeRange(); + const float multTPC = collision.multTPC() / MultiplicityNorm; + const auto hadronicRate = !irSource.empty() ? mRateFetcher.fetch(ccdb.service, bc.timestamp(), bc.runNumber(), irSource) * OneToKilo : 0.; + + const auto tracksFromCollision = tracks.sliceBy(perCollisionTracks, static_cast(collision.globalIndex())); + + for (const auto& track : tracksFromCollision) { + bool isGoodTrack = isTrackSelected(track, trackSelection); + isGoodTrack &= (!requireGlobalTrack || track.isGlobalTrack()); + isGoodTrack &= (!requireIts || track.hasITS()); + isGoodTrack &= track.hasTPC(); + isGoodTrack &= (track.tpcNClsFound() >= cutMinTPCNcls); + + const float rapidity = track.rapidity(PID::getMass(ParticleId)); + const float momentum = track.p(); + const float nClNormalized = std::sqrt(nClNorm / track.tpcNClsFound()); + const auto nclPID = static_cast(track.tpcNClsPID()); + const float phi = track.phi(); + const float tgl = track.tgl(); + const float tpcInnerParam = track.tpcInnerParam(); + const float signed1Pt = track.signed1Pt(); + const float nSigmaTpc = o2::aod::pidutils::tpcNSigma(track); + + isGoodTrack &= (std::fabs(rapidity) <= cutRapidity); + isGoodTrack &= (tpcInnerParam >= *cutTpcInnerParameterMin.at(ParticleId)); + isGoodTrack &= (tpcInnerParam <= *cutTpcInnerParameterMax.at(ParticleId)); + isGoodTrack &= (std::fabs(nSigmaTpc) <= *cutNSigmaTpcAbs.at(ParticleId)); + + if (!isGoodTrack) { + continue; + } + + float dedxDiff{UndefValueFloat}; + float dedxExpected{UndefValueFloat}; + float expSigma{UndefValueFloat}; + + if constexpr (IsFullTable) { + dedxDiff = o2::aod::pidutils::tpcExpSignalDiff(track); + dedxExpected = track.tpcSignal() - dedxDiff; + expSigma = o2::aod::pidutils::tpcExpSigma(track); + } + + float nSigmaTof{UndefValueFloat}; + + if constexpr (IsTofTable) { + nSigmaTof = o2::aod::pidutils::tofNSigma(track); + } + + rowPidTpcDiagnostics(isGoodRctEvent, ParticleId, ft0Occ, hadronicRate, multTPC, nClNormalized, nclPID, phi, tgl, tpcInnerParam, rapidity, momentum, signed1Pt, nSigmaTpc, dedxExpected, dedxDiff, expSigma, nSigmaTof); + } // tracksFromCollision + } // collisions + ++mProcessedParticles; + if (mProcessedParticles == mEnabledParticles) { + mProcessedParticles = 0; + if (saveReserveQaHisto) { + registry.fill(HIST("hOutputRatio"), static_cast((rowPidTpcDiagnostics.lastIndex() + 1)) / tracks.size()); + } + } + } + +#define MAKE_PROCESS_FUNCTIONS(ParticleNameShort, ParticleNameLong) \ + void process##ParticleNameLong(CollisionsExtra const& collisions, \ + soa::Join const& tracks, \ + aod::BCsWithTimestamps const&) \ + { \ + processSingleParticle(collisions, tracks); \ + } \ + PROCESS_SWITCH(TreeCreatorPidTpcDiagnostics, process##ParticleNameLong, Form("Process for the %s hypothesis for TPC NSigma QA", #ParticleNameLong), false); \ + \ + void processFull##ParticleNameLong(CollisionsExtra const& collisions, \ + soa::Join const& tracks, \ + aod::BCsWithTimestamps const&) \ + { \ + processSingleParticle(collisions, tracks); \ + } \ + PROCESS_SWITCH(TreeCreatorPidTpcDiagnostics, processFull##ParticleNameLong, Form("Process for the %s hypothesis for full TPC PID QA", #ParticleNameLong), false); \ + \ + void processFullWithTOF##ParticleNameLong(CollisionsExtra const& collisions, \ + soa::Join const& tracks, \ + aod::BCsWithTimestamps const&) \ + { \ + processSingleParticle(collisions, tracks); \ + } \ + PROCESS_SWITCH(TreeCreatorPidTpcDiagnostics, processFullWithTOF##ParticleNameLong, Form("Process for the %s hypothesis for full TPC PID QA with the TOF info added", #ParticleNameLong), false); + + DO_FOR_ALL_PARTICLES(MAKE_PROCESS_FUNCTIONS) +#undef MAKE_PROCESS_FUNCTIONS +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} +#undef DO_FOR_ALL_PARTICLES diff --git a/DPG/Tasks/TPC/treeCreatorPidTpcDiagnostics.h b/DPG/Tasks/TPC/treeCreatorPidTpcDiagnostics.h new file mode 100644 index 00000000000..e75aa5f7e71 --- /dev/null +++ b/DPG/Tasks/TPC/treeCreatorPidTpcDiagnostics.h @@ -0,0 +1,57 @@ +// 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. + +/// \file treeCreatorPidTpcDiagnostics.h +/// \author Ana Marin +/// \author Oleksii Lubynets +/// \brief Creates trees with PID QA variables along with variables used for NN training + +#ifndef DPG_TASKS_TPC_TREECREATORPIDTPCDIAGNOSTICS_H_ +#define DPG_TASKS_TPC_TREECREATORPIDTPCDIAGNOSTICS_H_ + +#include "DPG/Tasks/TPC/tpcSkimsTableCreator.h" + +#include +#include + +namespace o2::aod +{ +namespace dpg_tpcpiddiagnostics +{ +DECLARE_SOA_COLUMN(NSigmaTpc, nSigmaTpc, float); +DECLARE_SOA_COLUMN(DedxExpected, dedxExpected, float); +DECLARE_SOA_COLUMN(DedxDiff, dedxDiff, float); +DECLARE_SOA_COLUMN(ExpSigma, expSigma, float); +DECLARE_SOA_COLUMN(NSigmaTof, nSigmaTof, float); +} // namespace dpg_tpcpiddiagnostics + +DECLARE_SOA_TABLE(PidTpcDiagnostics, "AOD", "PIDTPCDIAG", + tpcskims::IsGoodRct, + tpcskims::PidIndex, + tpcskims::Ft0Occ, + tpcskims::HadronicRate, + tpcskims::NormMultTPC, + tpcskims::NormNClustersTPC, + tpcskims::NormNClustersTPCPID, + o2::aod::track::Phi, + o2::aod::track::Tgl, + o2::aod::track::TPCInnerParam, + o2::aod::track::Y, + o2::aod::track::P, + o2::aod::track::Signed1Pt, + dpg_tpcpiddiagnostics::NSigmaTpc, + dpg_tpcpiddiagnostics::DedxExpected, + dpg_tpcpiddiagnostics::DedxDiff, + dpg_tpcpiddiagnostics::ExpSigma, + dpg_tpcpiddiagnostics::NSigmaTof) +} // namespace o2::aod + +#endif // DPG_TASKS_TPC_TREECREATORPIDTPCDIAGNOSTICS_H_ diff --git a/EventFiltering/PWGEM/globalDimuonFilter.cxx b/EventFiltering/PWGEM/globalDimuonFilter.cxx index be71fc72cd6..f152dd22f6d 100644 --- a/EventFiltering/PWGEM/globalDimuonFilter.cxx +++ b/EventFiltering/PWGEM/globalDimuonFilter.cxx @@ -13,6 +13,7 @@ // \author daiki.sekihata@cern.ch #include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/RecoDecay.h" #include "Common/Core/fwdtrackUtilities.h" #include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.h" @@ -37,7 +38,6 @@ #include #include #include -#include #include #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) @@ -46,7 +46,9 @@ #include #include +#include #include +#include #include #include #include @@ -57,103 +59,111 @@ #include -using namespace o2; -using namespace o2::soa; -using namespace o2::aod; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::constants::physics; -using namespace o2::aod::fwdtrackutils; - struct globalDimuonFilter { - Produces tags; + o2::framework::Produces tags; // Configurables - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - Configurable minNmuon{"minNmuon", 2, "min number of global muon candidates per collision"}; + o2::framework::Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + o2::framework::Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + o2::framework::Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + o2::framework::Configurable minNmuon{"minNmuon", 2, "min number of global muon candidates per collision"}; - struct : ConfigurableGroup { + struct : o2::framework::ConfigurableGroup { std::string prefix = "eventCutGroup"; - Configurable minZvtx{"minZvtx", -11.f, "min. Zvtx of collision"}; - Configurable maxZvtx{"maxZvtx", +11.f, "max. Zvtx of collision"}; - Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND"}; - Configurable cfgRequireNoTFB{"cfgRequireNoTFB", true, "require No time frame border"}; - Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border"}; + o2::framework::Configurable cfgNcontribMin{"cfgNcontribMin", 0, "min. Ncontributors to PV"}; + o2::framework::Configurable cfgChi2PerNcontribMax{"cfgChi2PerNcontribMax", 1e+10, "max. chi2/Ncontrib of PV"}; + o2::framework::Configurable minZvtx{"minZvtx", -11.f, "min. Zvtx of collision"}; + o2::framework::Configurable maxZvtx{"maxZvtx", +11.f, "max. Zvtx of collision"}; + o2::framework::Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND"}; + o2::framework::Configurable cfgRequireNoTFB{"cfgRequireNoTFB", true, "require No time frame border"}; + o2::framework::Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border"}; + o2::framework::Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + o2::framework::Configurable cfgRequireVertexTOFmatched{"cfgRequireVertexTOFmatched", false, "require Vertex TOFmatched in event cut"}; // ITS-TPC-TOF matched track contributes PV. + o2::framework::Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + o2::framework::Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; } eventCutGroup; - struct : ConfigurableGroup { + struct : o2::framework::ConfigurableGroup { std::string prefix = "glMuonCutGroup"; - Configurable minPt{"minPt", 0.01, "min pt for muon"}; - Configurable maxPt{"maxPt", 1e+10, "max pt for muon"}; - Configurable minEta{"minEta", -3.6, "min. eta acceptance for MFT-MCH-MID"}; - Configurable maxEta{"maxEta", -2.5, "max. eta acceptance for MFT-MCH-MID"}; - Configurable minRabs{"minRabs", 17.6, "min. R at absorber end for global muon (min. eta = -3.6)"}; // std::tan(2.f * std::atan(std::exp(- -3.6)) ) * -505. = 27.6 - Configurable maxRabs{"maxRabs", 89.5, "max. R at absorber end"}; - Configurable maxDCAxy{"maxDCAxy", 0.2, "max. DCAxy for global muons"}; - Configurable maxMatchingChi2MCHMFT{"maxMatchingChi2MCHMFT", 100.f, "max. chi2 for MCH-MFT matching"}; - Configurable maxChi2{"maxChi2", 20, "max. chi2/ndf for global muon"}; - Configurable maxChi2MFT{"maxChi2MFT", 1e+10, "max. chi2/ndf for MFTsa"}; - Configurable minNclsMFT{"minNclsMFT", 5, "min ncluster of MFT"}; - Configurable minNclsMCH{"minNclsMCH", 5, "min ncluster of MCH"}; - Configurable refitGlobalMuon{"refitGlobalMuon", true, "flag to refit global muon"}; - Configurable matchingZ{"matchingZ", -77.5, "z position where matching is performed"}; - Configurable maxDEta{"maxDEta", 0.15, "max. deta between MFT-MCH-MID and MCH-MID"}; - Configurable maxDPhi{"maxDPhi", 0.15, "max. dphi between MFT-MCH-MID and MCH-MID"}; + o2::framework::Configurable minPt{"minPt", 0.55, "min pt for muon"}; + o2::framework::Configurable maxPt{"maxPt", 1e+10, "max pt for muon"}; + o2::framework::Configurable minEta{"minEta", -3.65, "min. eta acceptance for MFT-MCH-MID"}; + o2::framework::Configurable maxEta{"maxEta", -2.45, "max. eta acceptance for MFT-MCH-MID"}; + o2::framework::Configurable minRabs{"minRabs", 17.6, "min. R at absorber end for global muon"}; // std::tan(2.f * std::atan(std::exp(- -3.6)) ) * -505. = 27.6 + o2::framework::Configurable maxRabs{"maxRabs", 89.5, "max. R at absorber end"}; + o2::framework::Configurable maxDCAxy{"maxDCAxy", 0.5, "max. DCAxy for global muons"}; + o2::framework::Configurable maxMatchingChi2MCHMFT{"maxMatchingChi2MCHMFT", 100.f, "max. chi2 for MCH-MFT matching"}; + o2::framework::Configurable maxChi2{"maxChi2", 1e+10, "max. chi2/ndf for global muon"}; + o2::framework::Configurable maxChi2MFT{"maxChi2MFT", 1e+10, "max. chi2/ndf for MFTsa"}; + o2::framework::Configurable minNclsMFT{"minNclsMFT", 5, "min ncluster of MFT"}; + o2::framework::Configurable minNclsMCH{"minNclsMCH", 5, "min ncluster of MCH"}; + o2::framework::Configurable refitGlobalMuon{"refitGlobalMuon", true, "flag to refit global muon"}; + o2::framework::Configurable matchingZ{"matchingZ", -77.5, "z position where matching is performed"}; + o2::framework::Configurable maxDEta{"maxDEta", 1e+10, "max. deta between MFT-MCH-MID and MCH-MID"}; + o2::framework::Configurable maxDPhi{"maxDPhi", 1e+10, "max. dphi between MFT-MCH-MID and MCH-MID"}; } glMuonCutGroup; - struct : ConfigurableGroup { // tight cut + struct : o2::framework::ConfigurableGroup { // tight cut std::string prefix = "tagMuonCutGroup"; - Configurable minPt{"minPt", 0.4, "min pt for muon"}; - Configurable maxPt{"maxPt", 1e+10, "max pt for muon"}; - Configurable minEta{"minEta", -3.6, "min. eta acceptance for MFT-MCH-MID"}; - Configurable maxEta{"maxEta", -2.5, "max. eta acceptance for MFT-MCH-MID"}; - Configurable minRabs{"minRabs", 27.6, "min. R at absorber end for global muon (min. eta = -3.6)"}; // std::tan(2.f * std::atan(std::exp(- -3.6)) ) * -505. = 27.6 - Configurable maxRabs{"maxRabs", 89.5, "max. R at absorber end"}; - Configurable maxDCAxy{"maxDCAxy", 0.06, "max. DCAxy for global muons"}; - Configurable maxMatchingChi2MCHMFT{"maxMatchingChi2MCHMFT", 40.f, "max. chi2 for MCH-MFT matching"}; - Configurable maxChi2{"maxChi2", 4.f, "max. chi2/ndf for global muon"}; - Configurable maxChi2MFT{"maxChi2MFT", 4.f, "max. chi2/ndf for MFTsa"}; - Configurable minNclsMFT{"minNclsMFT", 5, "min ncluster of MFT"}; - Configurable minNclsMCH{"minNclsMCH", 5, "min ncluster of MCH"}; - Configurable refitGlobalMuon{"refitGlobalMuon", true, "flag to refit global muon"}; - Configurable matchingZ{"matchingZ", -77.5, "z position where matching is performed"}; - Configurable maxDEta{"maxDEta", 0.08, "max. deta between MFT-MCH-MID and MCH-MID"}; - Configurable maxDPhi{"maxDPhi", 0.08, "max. dphi between MFT-MCH-MID and MCH-MID"}; + o2::framework::Configurable minPt{"minPt", 0.8, "min pt for muon"}; + o2::framework::Configurable maxPt{"maxPt", 1e+10, "max pt for muon"}; + o2::framework::Configurable minEta{"minEta", -3.6, "min. eta acceptance for MFT-MCH-MID"}; + o2::framework::Configurable maxEta{"maxEta", -2.5, "max. eta acceptance for MFT-MCH-MID"}; + o2::framework::Configurable minRabs{"minRabs", 27.6, "min. R at absorber end for global muon (min. eta = -3.6)"}; // std::tan(2.f * std::atan(std::exp(- -3.6)) ) * -505. = 27.6 + o2::framework::Configurable maxRabs{"maxRabs", 89.5, "max. R at absorber end"}; + o2::framework::Configurable maxDCAxy{"maxDCAxy", 0.06, "max. DCAxy for global muons"}; + o2::framework::Configurable maxMatchingChi2MCHMFT{"maxMatchingChi2MCHMFT", 40.f, "max. chi2 for MCH-MFT matching"}; + o2::framework::Configurable maxChi2{"maxChi2", 4.f, "max. chi2/ndf for global muon"}; + o2::framework::Configurable maxChi2MFT{"maxChi2MFT", 4.f, "max. chi2/ndf for MFTsa"}; + o2::framework::Configurable minNclsMFT{"minNclsMFT", 5, "min ncluster of MFT"}; + o2::framework::Configurable minNclsMCH{"minNclsMCH", 5, "min ncluster of MCH"}; + o2::framework::Configurable refitGlobalMuon{"refitGlobalMuon", true, "flag to refit global muon"}; + o2::framework::Configurable matchingZ{"matchingZ", -77.5, "z position where matching is performed"}; + o2::framework::Configurable maxDEta{"maxDEta", 0.08, "max. deta between MFT-MCH-MID and MCH-MID"}; + o2::framework::Configurable maxDPhi{"maxDPhi", 0.08, "max. dphi between MFT-MCH-MID and MCH-MID"}; } tagMuonCutGroup; - struct : ConfigurableGroup { // loose cut + struct : o2::framework::ConfigurableGroup { // loose cut std::string prefix = "probeMuonCutGroup"; - Configurable minPt{"minPt", 0.01, "min pt for muon"}; - Configurable maxPt{"maxPt", 1e+10, "max pt for muon"}; - Configurable minEta{"minEta", -3.6, "min. eta acceptance for MFT-MCH-MID"}; - Configurable maxEta{"maxEta", -2.5, "max. eta acceptance for MFT-MCH-MID"}; - Configurable minRabs{"minRabs", 17.6, "min. R at absorber end for global muon (min. eta = -3.6)"}; // std::tan(2.f * std::atan(std::exp(- -3.6)) ) * -505. = 27.6 - Configurable maxRabs{"maxRabs", 89.5, "max. R at absorber end"}; - Configurable maxDCAxy{"maxDCAxy", 1e+10, "max. DCAxy for global muons"}; - Configurable maxMatchingChi2MCHMFT{"maxMatchingChi2MCHMFT", 1e+10, "max. chi2 for MCH-MFT matching"}; - Configurable maxChi2{"maxChi2", 1e+10, "max. chi2/ndf for global muon"}; - Configurable maxChi2MFT{"maxChi2MFT", 1e+10, "max. chi2/ndf for MFTsa"}; - Configurable minNclsMFT{"minNclsMFT", 5, "min ncluster of MFT"}; - Configurable minNclsMCH{"minNclsMCH", 5, "min ncluster of MCH"}; - Configurable refitGlobalMuon{"refitGlobalMuon", true, "flag to refit global muon"}; - Configurable matchingZ{"matchingZ", -77.5, "z position where matching is performed"}; - Configurable maxDEta{"maxDEta", 1e+10, "max. deta between MFT-MCH-MID and MCH-MID"}; - Configurable maxDPhi{"maxDPhi", 1e+10, "max. dphi between MFT-MCH-MID and MCH-MID"}; + o2::framework::Configurable minPt{"minPt", 0.01, "min pt for muon"}; + o2::framework::Configurable maxPt{"maxPt", 1e+10, "max pt for muon"}; + o2::framework::Configurable minEta{"minEta", -3.6, "min. eta acceptance for MFT-MCH-MID"}; + o2::framework::Configurable maxEta{"maxEta", -2.5, "max. eta acceptance for MFT-MCH-MID"}; + o2::framework::Configurable minRabs{"minRabs", 17.6, "min. R at absorber end for global muon (min. eta = -3.6)"}; // std::tan(2.f * std::atan(std::exp(- -3.6)) ) * -505. = 27.6 + o2::framework::Configurable maxRabs{"maxRabs", 89.5, "max. R at absorber end"}; + o2::framework::Configurable maxDCAxy{"maxDCAxy", 1e+10, "max. DCAxy for global muons"}; + o2::framework::Configurable maxMatchingChi2MCHMFT{"maxMatchingChi2MCHMFT", 1e+10, "max. chi2 for MCH-MFT matching"}; + o2::framework::Configurable maxChi2{"maxChi2", 1e+10, "max. chi2/ndf for global muon"}; + o2::framework::Configurable maxChi2MFT{"maxChi2MFT", 1e+10, "max. chi2/ndf for MFTsa"}; + o2::framework::Configurable minNclsMFT{"minNclsMFT", 5, "min ncluster of MFT"}; + o2::framework::Configurable minNclsMCH{"minNclsMCH", 5, "min ncluster of MCH"}; + o2::framework::Configurable refitGlobalMuon{"refitGlobalMuon", true, "flag to refit global muon"}; + o2::framework::Configurable matchingZ{"matchingZ", -77.5, "z position where matching is performed"}; + o2::framework::Configurable maxDEta{"maxDEta", 1e+10, "max. deta between MFT-MCH-MID and MCH-MID"}; + o2::framework::Configurable maxDPhi{"maxDPhi", 1e+10, "max. dphi between MFT-MCH-MID and MCH-MID"}; } probeMuonCutGroup; // for z shift for propagation - Configurable cfgApplyZShiftFromCCDB{"cfgApplyZShiftFromCCDB", false, "flag to apply z shift"}; - Configurable cfgZShiftPath{"cfgZShiftPath", "Users/m/mcoquet/ZShift", "CCDB path for z shift to apply to forward tracks"}; - Configurable cfgManualZShift{"cfgManualZShift", 0, "manual z-shift for propagation of global muon to PV"}; - - HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + o2::framework::Configurable cfgApplyZShiftFromCCDB{"cfgApplyZShiftFromCCDB", false, "flag to apply z shift"}; + o2::framework::Configurable cfgZShiftPath{"cfgZShiftPath", "Users/m/mcoquet/ZShift", "CCDB path for z shift to apply to forward tracks"}; + o2::framework::Configurable cfgManualXShiftMFTtop{"cfgManualXShiftMFTtop", 0, "manual x shift for propagation of global muon to PV"}; + o2::framework::Configurable cfgManualYShiftMFTtop{"cfgManualYShiftMFTtop", 0, "manual y shift for propagation of global muon to PV"}; + o2::framework::Configurable cfgManualZShiftMFTtop{"cfgManualZShiftMFTtop", 0, "manual z shift for propagation of global muon to PV"}; + o2::framework::Configurable cfgManualXShiftMFTbottom{"cfgManualXShiftMFTbottom", 0, "manual x shift for propagation of global muon to PV"}; + o2::framework::Configurable cfgManualYShiftMFTbottom{"cfgManualYShiftMFTbottom", 0, "manual y shift for propagation of global muon to PV"}; + o2::framework::Configurable cfgManualZShiftMFTbottom{"cfgManualZShiftMFTbottom", 0, "manual z shift for propagation of global muon to PV"}; + + o2::framework::HistogramRegistry fRegistry{"output", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject, false, false}; o2::ccdb::CcdbApi ccdbApi; - Service ccdb; + o2::framework::Service ccdb; int mRunNumber = 0; float mBz = 0; - float mZShift = 0; + float mXShiftMFTtop = 0; + float mYShiftMFTtop = 0; + float mZShiftMFTtop = 0; + float mXShiftMFTbottom = 0; + float mYShiftMFTbottom = 0; + float mZShiftMFTbottom = 0; void init(o2::framework::InitContext&) { @@ -164,7 +174,12 @@ struct globalDimuonFilter { ccdbApi.init(ccdburl); mRunNumber = 0; mBz = 0; - mZShift = 0; + mXShiftMFTtop = 0; + mYShiftMFTtop = 0; + mZShiftMFTtop = 0; + mXShiftMFTbottom = 0; + mYShiftMFTbottom = 0; + mZShiftMFTbottom = 0; addHistograms(); } @@ -187,7 +202,7 @@ struct globalDimuonFilter { } o2::mch::TrackExtrap::setField(); const double centerMFT[3] = {0, 0, -61.4}; - o2::field::MagneticField* field = static_cast(TGeoGlobalMagField::Instance()->GetField()); + o2::field::MagneticField* field = dynamic_cast(TGeoGlobalMagField::Instance()->GetField()); mBz = field->getBz(centerMFT); // Get field at centre of MFT LOGF(info, "Bz at center of MFT = %f kZG", mBz); @@ -195,20 +210,32 @@ struct globalDimuonFilter { auto* zShift = ccdb->getForTimeStamp>(cfgZShiftPath, bc.timestamp()); if (zShift != nullptr && !zShift->empty()) { LOGF(info, "reading z shift %f from %s", (*zShift)[0], cfgZShiftPath.value); - mZShift = (*zShift)[0]; + mZShiftMFTtop = (*zShift)[0]; + mZShiftMFTbottom = (*zShift)[0]; } else { LOGF(info, "z shift is not found in ccdb path %s. set to 0 cm", cfgZShiftPath.value); - mZShift = 0; + mZShiftMFTtop = 0; + mZShiftMFTbottom = 0; } } else { - LOGF(info, "z shift is manually set to %f cm", cfgManualZShift.value); - mZShift = cfgManualZShift; + LOGF(info, "X shift for MFT top is manually set to %f cm", cfgManualXShiftMFTtop.value); + LOGF(info, "X shift for MFT bottom is manually set to %f cm", cfgManualXShiftMFTbottom.value); + LOGF(info, "Y shift for MFT top is manually set to %f cm", cfgManualYShiftMFTtop.value); + LOGF(info, "Y shift for MFT bottom is manually set to %f cm", cfgManualYShiftMFTbottom.value); + LOGF(info, "Z shift for MFT top is manually set to %f cm", cfgManualZShiftMFTtop.value); + LOGF(info, "Z shift for MFT bottom is manually set to %f cm", cfgManualZShiftMFTbottom.value); + mXShiftMFTtop = cfgManualXShiftMFTtop; + mYShiftMFTtop = cfgManualYShiftMFTtop; + mZShiftMFTtop = cfgManualZShiftMFTtop; + mXShiftMFTbottom = cfgManualXShiftMFTbottom; + mYShiftMFTbottom = cfgManualYShiftMFTbottom; + mZShiftMFTbottom = cfgManualZShiftMFTbottom; } } void addHistograms() { - auto hCollisionCounter{std::get>(fRegistry.add("hCollisionCounter", "Number of collisions", HistType::kTH1D, {{10, 0.5, 10.5}}))}; + auto hCollisionCounter{std::get>(fRegistry.add("hCollisionCounter", "Number of collisions", o2::framework::HistType::kTH1D, {{10, 0.5, 10.5}}))}; hCollisionCounter->GetXaxis()->SetBinLabel(1, "all"); hCollisionCounter->GetXaxis()->SetBinLabel(2, "TVX"); hCollisionCounter->GetXaxis()->SetBinLabel(3, "No TFB"); @@ -219,73 +246,79 @@ struct globalDimuonFilter { hCollisionCounter->GetXaxis()->SetBinLabel(8, "MB && global dimuon"); hCollisionCounter->GetXaxis()->SetBinLabel(9, "MB && global dimuon for QA"); - fRegistry.add("hNmu", "#mu multiplicity;N_{#mu}^{global} candidates per collision", kTH1D, {{11, -0.5, 10.5}}, false); - - fRegistry.add("MFTMCHMID/hPt", "pT;p_{T} (GeV/c)", kTH1D, {{200, 0.0f, 10}}, false); - fRegistry.add("MFTMCHMID/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2D, {{180, 0, 2 * M_PI}, {200, -4.f, -2.f}}, false); - fRegistry.add("MFTMCHMID/hEtaPhi_MatchedMCHMID", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2D, {{180, 0, 2 * M_PI}, {200, -4.f, -2.f}}, false); - fRegistry.add("MFTMCHMID/hDEtaDPhi", "#Delta#eta vs. #Delta#varphi;#Delta#varphi (rad.);#Delta#eta", kTH2D, {{90, -M_PI / 4, M_PI / 4}, {100, -0.5, +0.5}}, false); - fRegistry.add("MFTMCHMID/hSign", "sign;sign", kTH1D, {{3, -1.5, +1.5}}, false); - fRegistry.add("MFTMCHMID/hNclusters", "Nclusters;Nclusters", kTH1D, {{21, -0.5f, 20.5}}, false); - fRegistry.add("MFTMCHMID/hNclustersMFT", "NclustersMFT;Nclusters MFT", kTH1D, {{11, -0.5f, 10.5}}, false); - fRegistry.add("MFTMCHMID/hRatAbsorberEnd", "R at absorber end;R at absorber end (cm)", kTH1D, {{200, 0, 100}}, false); - fRegistry.add("MFTMCHMID/hPDCA_Rabs", "pDCA vs. Rabs;R at absorber end (cm);p #times DCA (GeV/c #upoint cm)", kTH2D, {{200, 0, 100}, {100, 0, 1000}}, false); - fRegistry.add("MFTMCHMID/hChi2", "chi2;#chi^{2}/ndf", kTH1D, {{100, 0.0f, 10}}, false); - fRegistry.add("MFTMCHMID/hChi2MFT", "chi2 MFT;#chi^{2} MFT/ndf", kTH1D, {{100, 0.0f, 10}}, false); - fRegistry.add("MFTMCHMID/hChi2MatchMCHMID", "chi2 match MCH-MID;matching #chi^{2}/ndf between MCH-MID", kTH1D, {{200, 0.0f, 20}}, false); - fRegistry.add("MFTMCHMID/hChi2MatchMCHMFT", "chi2 match MCH-MFT;matching #chi^{2}/ndf between MFT-MCH", kTH1D, {{100, 0.0f, 100}}, false); - fRegistry.add("MFTMCHMID/hDCAxy2D", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", kTH2D, {{400, -1, 1}, {400, -1, +1}}, false); - fRegistry.add("MFTMCHMID/hDCAxy2DinSigma", "DCA x vs. y in sigma;DCA_{x} (#sigma);DCA_{y} (#sigma)", kTH2D, {{200, -10, 10}, {200, -10, +10}}, false); - fRegistry.add("MFTMCHMID/hDCAxy", "DCAxy;DCA_{xy} (cm);", kTH1D, {{100, 0, 1}}, false); - fRegistry.add("MFTMCHMID/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2D, {{100, 0, 1}, {200, -0.1, 0.1}}, false); - fRegistry.add("MFTMCHMID/hDCAxyinSigma", "DCAxy in sigma;DCA_{xy} (#sigma);", kTH1D, {{100, 0, 10}}, false); - fRegistry.add("MFTMCHMID/hDCAxResolutionvsPt", "DCA_{x} resolution vs. p_{T};p_{T} (GeV/c);DCA_{x} resolution (#mum);", kTH2D, {{100, 0, 10.f}, {500, 0, 500}}, false); - fRegistry.add("MFTMCHMID/hDCAyResolutionvsPt", "DCA_{y} resolution vs. p_{T};p_{T} (GeV/c);DCA_{y} resolution (#mum);", kTH2D, {{100, 0, 10.f}, {500, 0, 500}}, false); - fRegistry.add("MFTMCHMID/hDCAxyResolutionvsPt", "DCA_{xy} resolution vs. p_{T};p_{T} (GeV/c);DCA_{xy} resolution (#mum);", kTH2D, {{100, 0, 10.f}, {500, 0, 500}}, false); - fRegistry.add("MFTMCHMID/hDCAx_PosZ", "DCAx vs. posZ;Z_{vtx} (cm);DCA_{x} (cm)", kTH2F, {{200, -10, +10}, {400, -0.2, +0.2}}, false); - fRegistry.add("MFTMCHMID/hDCAy_PosZ", "DCAy vs. posZ;Z_{vtx} (cm);DCA_{y} (cm)", kTH2F, {{200, -10, +10}, {400, -0.2, +0.2}}, false); - fRegistry.add("MFTMCHMID/hDCAx_Phi", "DCAx vs. #varphi;#varphi (rad.);DCA_{x} (cm)", kTH2F, {{90, 0, 2 * M_PI}, {400, -0.2, +0.2}}, false); - fRegistry.add("MFTMCHMID/hDCAy_Phi", "DCAy vs. #varphi;#varphi (rad.);DCA_{y} (cm)", kTH2F, {{90, 0, 2 * M_PI}, {400, -0.2, +0.2}}, false); - fRegistry.add("MFTMCHMID/hdR_Chi2MatchMCHMFT", "dr vs. matching chi2 MCH-MFT;chi2 match MCH-MFT;#DeltaR", kTH2F, {{200, 0, 50}, {200, 0, 0.5}}, false); - fRegistry.add("MFTMCHMID/hdR_Chi2", "dr vs. chi2;global chi2/ndf;#DeltaR", kTH2F, {{100, 0, 10}, {200, 0, 0.5}}, false); - fRegistry.add("MFTMCHMID/hChi2_Chi2MatchMCHMFT", "chi2 vs. matching chi2 MCH-MFT;chi2 match MCH-MFT;global chi2/ndf", kTH2F, {{200, 0, 50}, {100, 0, 10}}, false); - - const AxisSpec axisMll{{0.20, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.30, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.40, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.50, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.60, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.70, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.80, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.90, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.00, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.10, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.10, 2.20, 2.30, 2.40, 2.50, 2.60, 2.70, 2.75, 2.80, 2.85, 2.90, 2.95, 3.00, 3.05, 3.10, 3.15, 3.20, 3.25, 3.30, 3.35, 3.40, 3.45, 3.50, 3.55, 3.60, 3.65, 3.70, 3.75, 3.80, 3.85, 3.90, 3.95, 4.00, 4.50, 5.00, 5.50, 6.00, 6.50, 7.00, 7.50, 8.00, 8.1, 8.2, 8.3, 8.4, 8.50, 8.60, 8.70, 8.80, 8.90, 9.00, 9.10, 9.20, 9.30, 9.40, 9.50, 9.60, 9.70, 9.80, 9.90, 10.00, 10.10, 10.20, 10.30, 10.40, 10.50, 10.60, 10.70, 10.80, 10.90, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.5, 11.6, 11.7, 11.8, 11.9, 12.0}, "m_{#mu#mu} (GeV/c^{2})"}; - const AxisSpec axisPtll{{0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.5, 3, 3.5, 4, 4.5, 5, 6, 7, 8, 9, 10}, "p_{T,#mu#mu} (GeV/c)"}; - const AxisSpec axisYll{40, -4.0, -2.0, "y_{#mu#mu}"}; - - fRegistry.add("Pair/same/uls/hs", "dimuon", kTHnSparseD, {axisMll, axisPtll, axisYll}, false); - fRegistry.add("Pair/same/lspp/hs", "dimuon", kTHnSparseD, {axisMll, axisPtll, axisYll}, false); - fRegistry.add("Pair/same/lsmm/hs", "dimuon", kTHnSparseD, {axisMll, axisPtll, axisYll}, false); - - const AxisSpec axisMllLMR{{0.20, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.30, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.40, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.50, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.60, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.70, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.80, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.90, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.00, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.10, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.10, 2.11, 2.12, 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.20, 2.21, 2.22, 2.23, 2.24, 2.25, 2.26, 2.27, 2.28, 2.29, 2.30, 2.31, 2.32, 2.33, 2.34, 2.35, 2.36, 2.37, 2.38, 2.39, 2.40, 2.41, 2.42, 2.43, 2.44, 2.45, 2.46, 2.47, 2.48, 2.49, 2.50, 2.51, 2.52, 2.53, 2.54, 2.55, 2.56, 2.57, 2.58, 2.59, 2.60, 2.61, 2.62, 2.63, 2.64, 2.65, 2.66, 2.67, 2.68, 2.69, 2.70, 2.71, 2.72, 2.73, 2.74, 2.75, 2.76, 2.77, 2.78, 2.79, 2.80, 2.81, 2.82, 2.83, 2.84, 2.85, 2.86, 2.87, 2.88, 2.89, 2.90, 2.91, 2.92, 2.93, 2.94, 2.95, 2.96, 2.97, 2.98, 2.99, 3.00, 3.01, 3.02, 3.03, 3.04, 3.05, 3.06, 3.07, 3.08, 3.09, 3.10, 3.11, 3.12, 3.13, 3.14, 3.15, 3.16, 3.17, 3.18, 3.19, 3.20, 3.21, 3.22, 3.23, 3.24, 3.25, 3.26, 3.27, 3.28, 3.29, 3.30, 3.31, 3.32, 3.33, 3.34, 3.35, 3.36, 3.37, 3.38, 3.39, 3.40, 3.41, 3.42, 3.43, 3.44, 3.45, 3.46, 3.47, 3.48, 3.49, 3.50, 3.51, 3.52, 3.53, 3.54, 3.55, 3.56, 3.57, 3.58, 3.59, 3.60, 3.61, 3.62, 3.63, 3.64, 3.65, 3.66, 3.67, 3.68, 3.69, 3.70, 3.71, 3.72, 3.73, 3.74, 3.75, 3.76, 3.77, 3.78, 3.79, 3.80, 3.81, 3.82, 3.83, 3.84, 3.85, 3.86, 3.87, 3.88, 3.89, 3.90, 3.91, 3.92, 3.93, 3.94, 3.95, 3.96, 3.97, 3.98, 3.99, 4.00}, "m_{#mu#mu} (GeV/c^{2})"}; - const AxisSpec axisPt{{0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.5, 3, 3.5, 4, 4.5, 5, 6, 7, 8, 9, 10}, "p_{T,#mu} (GeV/c)"}; - const AxisSpec axisEta{40, -4.0, -2.0, "#eta_{#mu}"}; - const AxisSpec axisPhi{36, 0, 2 * M_PI, "#varphi_{#mu} (rad.)"}; - const AxisSpec axisDEta{100, -0.5, 0.5, "#Delta#eta"}; - const AxisSpec axisDPhi{90, -M_PI / 4, M_PI / 4, "#Delta#varphi (rad.)"}; - const AxisSpec axisDCAxy{100, 0, 1, "DCA_{xy} (cm)"}; - const AxisSpec axisChi2{200, 0, 20, "global #chi^{2}/ndf"}; - const AxisSpec axisChi2MFT{100, 0, 10, "MFTsa #chi^{2}/ndf"}; - const AxisSpec axisChi2MFTMCH{100, 0, 100, "matching #chi^{2}/ndf between MFT-MCH"}; - const AxisSpec axisPDCA{100, 0, 1000, "p #times DCA_{xy} (GeV/c #upoint cm)"}; - const AxisSpec axisRabs{150, 15, 90, "R_{xy} at absorber end (cm)"}; - const AxisSpec axisNclsMCH{21, -0.5, 20.5, "N_{cls}^{MCH}"}; - const AxisSpec axisNclsMFT{11, -0.5, 10.5, "N_{cls}^{MFT}"}; + fRegistry.add("hNmu", "#mu multiplicity;N_{#mu}^{global} candidates per collision", o2::framework::HistType::kTH1D, {{11, -0.5, 10.5}}, false); + + fRegistry.add("Vertex/MB/hZvtx", "vertex z; Z_{vtx} (cm)", o2::framework::HistType::kTH1D, {{40, -20, +20}}, false); + fRegistry.add("Vertex/MB/hChi2vsNContrib", "vertex #chi^{2}/N_{contrib} vs. N_{contrib};N_{contrib};#chi^{2}/N_{contrib}", o2::framework::HistType::kTH2D, {{200, 0.5, 200.5}, {100, 0, 10}}, false); + fRegistry.add("Vertex/MB/hSigmaX", "vertex #sigma_{X} vs. N_{contrib};N_{contrib};#sigma_{X} (#mum)", o2::framework::HistType::kTH2D, {{200, 0.5, 200.5}, {1000, 0, 100}}, false); + fRegistry.add("Vertex/MB/hSigmaY", "vertex #sigma_{Y} vs. N_{contrib};N_{contrib};#sigma_{Y} (#mum)", o2::framework::HistType::kTH2D, {{200, 0.5, 200.5}, {1000, 0, 100}}, false); + fRegistry.add("Vertex/MB/hSigmaZ", "vertex #sigma_{Z} vs. N_{contrib};N_{contrib};#sigma_{Z} (#mum)", o2::framework::HistType::kTH2D, {{200, 0.5, 200.5}, {1000, 0, 100}}, false); + fRegistry.addClone("Vertex/MB/", "Vertex/Triggered/"); + + fRegistry.add("MFTMCHMID/positive/hPt", "pT;p_{T} (GeV/c)", o2::framework::HistType::kTH1D, {{200, 0.0f, 10}}, false); + fRegistry.add("MFTMCHMID/positive/hPtResolution", "pT;p_{T} (GeV/c);#Deltap_{T}/p_{T}", o2::framework::HistType::kTH2D, {{200, 0.0f, 10}, {200, 0, 0.1}}, false); + fRegistry.add("MFTMCHMID/positive/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", o2::framework::HistType::kTH2D, {{180, 0, 2 * M_PI}, {200, -4.f, -2.f}}, false); + fRegistry.add("MFTMCHMID/positive/hEtaPhi_MatchedMCHMID", "#eta vs. #varphi;#varphi (rad.);#eta", o2::framework::HistType::kTH2D, {{180, 0, 2 * M_PI}, {200, -4.f, -2.f}}, false); + fRegistry.add("MFTMCHMID/positive/hDEtaDPhi", "#Delta#eta vs. #Delta#varphi;#Delta#varphi (rad.);#Delta#eta", o2::framework::HistType::kTH2D, {{90, -M_PI / 4, M_PI / 4}, {100, -0.5, +0.5}}, false); + fRegistry.add("MFTMCHMID/positive/hSign", "sign;sign", o2::framework::HistType::kTH1D, {{3, -1.5, +1.5}}, false); + fRegistry.add("MFTMCHMID/positive/hNclusters", "Nclusters;Nclusters", o2::framework::HistType::kTH1D, {{21, -0.5f, 20.5}}, false); + fRegistry.add("MFTMCHMID/positive/hNclustersMFT", "NclustersMFT;Nclusters MFT", o2::framework::HistType::kTH1D, {{11, -0.5f, 10.5}}, false); + fRegistry.add("MFTMCHMID/positive/hRatAbsorberEnd", "R at absorber end;R at absorber end (cm)", o2::framework::HistType::kTH1D, {{200, 0, 100}}, false); + fRegistry.add("MFTMCHMID/positive/hPDCA_Rabs", "pDCA vs. Rabs;R at absorber end (cm);p #times DCA (GeV/c #upoint cm)", o2::framework::HistType::kTH2D, {{200, 0, 100}, {100, 0, 1000}}, false); + fRegistry.add("MFTMCHMID/positive/hChi2_Pt", "chi2;p_{T,#mu} (GeV/c);#chi^{2}/ndf", o2::framework::HistType::kTH2D, {{200, 0, 10}, {100, 0.0f, 10}}, false); + fRegistry.add("MFTMCHMID/positive/hChi2MFT_Pt", "chi2 MFT;p_{T,#mu} (GeV/c);#chi^{2} MFT/ndf", o2::framework::HistType::kTH2D, {{200, 0, 10}, {100, 0.0f, 10}}, false); + fRegistry.add("MFTMCHMID/positive/hChi2MatchMCHMID_Pt", "chi2 match MCH-MID;p_{T,#mu} (GeV/c);matching #chi^{2}/ndf between MCH-MID", o2::framework::HistType::kTH2D, {{200, 0, 10}, {200, 0.0f, 20}}, false); + fRegistry.add("MFTMCHMID/positive/hChi2MatchMCHMFT_Pt", "chi2 match MCH-MFT;p_{T,#mu} (GeV/c);matching #chi^{2}/ndf between MFT-MCH", o2::framework::HistType::kTH2D, {{200, 0, 10}, {100, 0.0f, 100}}, false); + fRegistry.add("MFTMCHMID/positive/hDCAxy2D", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", o2::framework::HistType::kTH2D, {{400, -1, 1}, {400, -1, +1}}, false); + fRegistry.add("MFTMCHMID/positive/hDCAxy2DinSigma", "DCA x vs. y in sigma;DCA_{x} (#sigma);DCA_{y} (#sigma)", o2::framework::HistType::kTH2D, {{200, -10, 10}, {200, -10, +10}}, false); + fRegistry.add("MFTMCHMID/positive/hDCAxy", "DCAxy;DCA_{xy} (cm);", o2::framework::HistType::kTH1D, {{1000, 0, 1}}, false); + fRegistry.add("MFTMCHMID/positive/hDCAxyinSigma", "DCAxy in sigma;DCA_{xy} (#sigma);", o2::framework::HistType::kTH1D, {{100, 0, 10}}, false); + fRegistry.add("MFTMCHMID/positive/hLog10Chi2IP", "chi2IP;log_{10}(#chi^{2}_{IP})", o2::framework::HistType::kTH1D, {{1000, -5, 5}}, false); + fRegistry.add("MFTMCHMID/positive/hDCAxResolutionvsPt", "DCA_{x} resolution vs. p_{T};p_{T} (GeV/c);DCA_{x} resolution (#mum);", o2::framework::HistType::kTH2D, {{100, 0, 10.f}, {500, 0, 500}}, false); + fRegistry.add("MFTMCHMID/positive/hDCAyResolutionvsPt", "DCA_{y} resolution vs. p_{T};p_{T} (GeV/c);DCA_{y} resolution (#mum);", o2::framework::HistType::kTH2D, {{100, 0, 10.f}, {500, 0, 500}}, false); + fRegistry.add("MFTMCHMID/positive/hDCAxyResolutionvsPt", "DCA_{xy} resolution vs. p_{T};p_{T} (GeV/c);DCA_{xy} resolution (#mum);", o2::framework::HistType::kTH2D, {{100, 0, 10.f}, {500, 0, 500}}, false); + fRegistry.add("MFTMCHMID/positive/hDCAx_Phi", "DCAx vs. #varphi;#varphi (rad.);DCA_{x} (cm)", o2::framework::HistType::kTH2D, {{180, -M_PI, M_PI}, {400, -0.2, +0.2}}, false); + fRegistry.add("MFTMCHMID/positive/hDCAy_Phi", "DCAy vs. #varphi;#varphi (rad.);DCA_{y} (cm)", o2::framework::HistType::kTH2D, {{180, -M_PI, M_PI}, {400, -0.2, +0.2}}, false); + fRegistry.add("MFTMCHMID/positive/hDCAx_PosZ_MFTtop", "DCAx vs. posZ for MFT top;Z_{vtx} (cm);DCA_{x} (cm)", o2::framework::HistType::kTH2D, {{200, -10, +10}, {400, -0.2, +0.2}}, false); + fRegistry.add("MFTMCHMID/positive/hDCAy_PosZ_MFTtop", "DCAy vs. posZ for MFT top;Z_{vtx} (cm);DCA_{y} (cm)", o2::framework::HistType::kTH2D, {{200, -10, +10}, {400, -0.2, +0.2}}, false); + fRegistry.add("MFTMCHMID/positive/hDCAx_PosZ_MFTbottom", "DCAx vs. posZ for MFT bottom;Z_{vtx} (cm);DCA_{x} (cm)", o2::framework::HistType::kTH2D, {{200, -10, +10}, {400, -0.2, +0.2}}, false); + fRegistry.add("MFTMCHMID/positive/hDCAy_PosZ_MFTbottom", "DCAy vs. posZ for MFT bottom;Z_{vtx} (cm);DCA_{y} (cm)", o2::framework::HistType::kTH2D, {{200, -10, +10}, {400, -0.2, +0.2}}, false); + fRegistry.addClone("MFTMCHMID/positive/", "MFTMCHMID/negative/"); + + const o2::framework::AxisSpec axisMll{{0.20, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.30, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.40, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.50, 0.505, 0.51, 0.515, 0.52, 0.525, 0.53, 0.535, 0.54, 0.545, 0.55, 0.555, 0.56, 0.565, 0.57, 0.575, 0.58, 0.585, 0.59, 0.595, 0.60, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.70, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.80, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.90, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.00, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.10, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.10, 2.20, 2.30, 2.40, 2.50, 2.60, 2.70, 2.75, 2.80, 2.85, 2.90, 2.95, 3.00, 3.05, 3.10, 3.15, 3.20, 3.25, 3.30, 3.35, 3.40, 3.45, 3.50, 3.55, 3.60, 3.65, 3.70, 3.75, 3.80, 3.85, 3.90, 3.95, 4.00, 4.50, 5.00, 5.50, 6.00, 6.50, 7.00, 7.50, 8.00, 8.1, 8.2, 8.3, 8.4, 8.50, 8.60, 8.70, 8.80, 8.90, 9.00, 9.10, 9.20, 9.30, 9.40, 9.50, 9.60, 9.70, 9.80, 9.90, 10.00, 10.10, 10.20, 10.30, 10.40, 10.50, 10.60, 10.70, 10.80, 10.90, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 11.9, 12.0}, "m_{#mu#mu} (GeV/c^{2})"}; + const o2::framework::AxisSpec axisPtll{{0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.5, 3, 3.5, 4, 4.5, 5, 6, 7, 8, 9, 10}, "p_{T,#mu#mu} (GeV/c)"}; + const o2::framework::AxisSpec axisYll{40, -4.0, -2.0, "y_{#mu#mu}"}; + + fRegistry.add("Pair/same/uls/hs", "dimuon", o2::framework::HistType::kTHnSparseD, {axisMll, axisPtll, axisYll}, false); + fRegistry.add("Pair/same/lspp/hs", "dimuon", o2::framework::HistType::kTHnSparseD, {axisMll, axisPtll, axisYll}, false); + fRegistry.add("Pair/same/lsmm/hs", "dimuon", o2::framework::HistType::kTHnSparseD, {axisMll, axisPtll, axisYll}, false); + + const o2::framework::AxisSpec axisMllLMR{{0.20, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.30, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.40, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.50, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.60, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.70, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.80, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.90, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1.00, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.10, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.10, 2.11, 2.12, 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.20, 2.21, 2.22, 2.23, 2.24, 2.25, 2.26, 2.27, 2.28, 2.29, 2.30, 2.31, 2.32, 2.33, 2.34, 2.35, 2.36, 2.37, 2.38, 2.39, 2.40, 2.41, 2.42, 2.43, 2.44, 2.45, 2.46, 2.47, 2.48, 2.49, 2.50, 2.51, 2.52, 2.53, 2.54, 2.55, 2.56, 2.57, 2.58, 2.59, 2.60, 2.61, 2.62, 2.63, 2.64, 2.65, 2.66, 2.67, 2.68, 2.69, 2.70, 2.71, 2.72, 2.73, 2.74, 2.75, 2.76, 2.77, 2.78, 2.79, 2.80, 2.81, 2.82, 2.83, 2.84, 2.85, 2.86, 2.87, 2.88, 2.89, 2.90, 2.91, 2.92, 2.93, 2.94, 2.95, 2.96, 2.97, 2.98, 2.99, 3.00, 3.01, 3.02, 3.03, 3.04, 3.05, 3.06, 3.07, 3.08, 3.09, 3.10, 3.11, 3.12, 3.13, 3.14, 3.15, 3.16, 3.17, 3.18, 3.19, 3.20, 3.21, 3.22, 3.23, 3.24, 3.25, 3.26, 3.27, 3.28, 3.29, 3.30, 3.31, 3.32, 3.33, 3.34, 3.35, 3.36, 3.37, 3.38, 3.39, 3.40, 3.41, 3.42, 3.43, 3.44, 3.45, 3.46, 3.47, 3.48, 3.49, 3.50, 3.51, 3.52, 3.53, 3.54, 3.55, 3.56, 3.57, 3.58, 3.59, 3.60, 3.61, 3.62, 3.63, 3.64, 3.65, 3.66, 3.67, 3.68, 3.69, 3.70, 3.71, 3.72, 3.73, 3.74, 3.75, 3.76, 3.77, 3.78, 3.79, 3.80, 3.81, 3.82, 3.83, 3.84, 3.85, 3.86, 3.87, 3.88, 3.89, 3.90, 3.91, 3.92, 3.93, 3.94, 3.95, 3.96, 3.97, 3.98, 3.99, 4.00}, "m_{#mu#mu} (GeV/c^{2})"}; + const o2::framework::AxisSpec axisPt{{0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.5, 3, 3.5, 4, 4.5, 5, 6, 7, 8, 9, 10}, "p_{T,#mu} (GeV/c)"}; + const o2::framework::AxisSpec axisEta{40, -4.0, -2.0, "#eta_{#mu}"}; + const o2::framework::AxisSpec axisPhi{36, 0, 2 * M_PI, "#varphi_{#mu} (rad.)"}; + const o2::framework::AxisSpec axisDEta{100, -0.5, 0.5, "#Delta#eta"}; + const o2::framework::AxisSpec axisDPhi{90, -M_PI / 4, M_PI / 4, "#Delta#varphi (rad.)"}; + const o2::framework::AxisSpec axisDCAxy{100, 0, 1, "DCA_{xy} (cm)"}; + const o2::framework::AxisSpec axisChi2{200, 0, 20, "global #chi^{2}/ndf"}; + const o2::framework::AxisSpec axisChi2MFT{100, 0, 10, "MFTsa #chi^{2}/ndf"}; + const o2::framework::AxisSpec axisChi2MFTMCH{100, 0, 100, "matching #chi^{2}/ndf between MFT-MCH"}; + const o2::framework::AxisSpec axisPDCA{100, 0, 1000, "p #times DCA_{xy} (GeV/c #upoint cm)"}; + const o2::framework::AxisSpec axisRabs{150, 15, 90, "R_{xy} at absorber end (cm)"}; + const o2::framework::AxisSpec axisNclsMCH{21, -0.5, 20.5, "N_{cls}^{MCH}"}; + const o2::framework::AxisSpec axisNclsMFT{11, -0.5, 10.5, "N_{cls}^{MFT}"}; // for track cut efficiency with tag and probe - fRegistry.add("TAP/same/uls/hs", "dimuon for T&P", kTHnSparseD, {axisMllLMR, axisPt, axisEta, axisPhi, axisDEta, axisDPhi, axisDCAxy, axisChi2, axisChi2MFT, axisChi2MFTMCH, axisPDCA, axisRabs, axisNclsMCH, axisNclsMFT}, false); - fRegistry.add("TAP/same/lspp/hs", "dimuon for T&P", kTHnSparseD, {axisMllLMR, axisPt, axisEta, axisPhi, axisDEta, axisDPhi, axisDCAxy, axisChi2, axisChi2MFT, axisChi2MFTMCH, axisPDCA, axisRabs, axisNclsMCH, axisNclsMFT}, false); - fRegistry.add("TAP/same/lsmm/hs", "dimuon for T&P", kTHnSparseD, {axisMllLMR, axisPt, axisEta, axisPhi, axisDEta, axisDPhi, axisDCAxy, axisChi2, axisChi2MFT, axisChi2MFTMCH, axisPDCA, axisRabs, axisNclsMCH, axisNclsMFT}, false); + fRegistry.add("TAP/same/uls/hs", "dimuon for T&P", o2::framework::HistType::kTHnSparseD, {axisMllLMR, axisPt, axisEta, axisPhi, axisDEta, axisDPhi, axisDCAxy, axisChi2, axisChi2MFT, axisChi2MFTMCH, axisPDCA, axisRabs, axisNclsMCH, axisNclsMFT}, false); + fRegistry.add("TAP/same/lspp/hs", "dimuon for T&P", o2::framework::HistType::kTHnSparseD, {axisMllLMR, axisPt, axisEta, axisPhi, axisDEta, axisDPhi, axisDCAxy, axisChi2, axisChi2MFT, axisChi2MFTMCH, axisPDCA, axisRabs, axisNclsMCH, axisNclsMFT}, false); + fRegistry.add("TAP/same/lsmm/hs", "dimuon for T&P", o2::framework::HistType::kTHnSparseD, {axisMllLMR, axisPt, axisEta, axisPhi, axisDEta, axisDPhi, axisDCAxy, axisChi2, axisChi2MFT, axisChi2MFTMCH, axisPDCA, axisRabs, axisNclsMCH, axisNclsMFT}, false); } - std::vector> vec_min_chi2MatchMCHMFT; // std::pair -> chi2MatchMCHMFT; + std::vector> vec_min_chi2MatchMCHMFT; template void findBestMatchPerMCHMID(TCollision const&, TFwdTrack const& fwdtrack, TFwdTracks const& fwdtracks, TMFTTracks const&) { - // make a unordered_map : globalIndex of global muon -> boolean isSelected. - if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { return; } @@ -294,30 +327,10 @@ struct globalDimuonFilter { // LOGF(info, "stanadalone: muon.globalIndex() = %d, muon.chi2MatchMCHMFT() = %f", muon.globalIndex(), muon.chi2MatchMCHMFT()); // LOGF(info, "muons_per_MCHMID.size() = %d", muons_per_MCHMID.size()); - // o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToVertex, glMuonCutGroup.matchingZ, mBz, mZShift); - // float etaMatchedMCHMID = propmuonAtPV_Matched.getEta(); - // float phiMatchedMCHMID = propmuonAtPV_Matched.getPhi(); - // o2::math_utils::bringTo02Pi(phiMatchedMCHMID); - - float min_chi2MatchMCHMFT = 1e+10; + float min_chi2MatchMCHMFT = FLT_MAX; std::tuple tupleIds_at_min_chi2mftmch; for (const auto& muon_tmp : muons_per_MCHMID) { if (muon_tmp.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { - // auto tupleId = std::make_tuple(muon_tmp.globalIndex(), muon_tmp.matchMCHTrackId(), muon_tmp.matchMFTTrackId()); - // auto mchtrack = muon_tmp.template matchMCHTrack_as(); // MCH-MID - // auto mfttrack = muon_tmp.template matchMFTTrack_as(); // MFTsa - - // o2::dataformats::GlobalFwdTrack propmuonAtPV = propagateMuon(muon_tmp, muon_tmp, collision, propagationPoint::kToVertex, glMuonCutGroup.matchingZ, mBz, mZShift); - // float eta = propmuonAtPV.getEta(); - // float phi = propmuonAtPV.getPhi(); - // o2::math_utils::bringTo02Pi(phi); - - // float deta = etaMatchedMCHMID - eta; - // float dphi = phiMatchedMCHMID - phi; - // o2::math_utils::bringToPMPi(dphi); - // float dr = std::sqrt(deta * deta + dphi * dphi); - - // LOGF(info, "muon_tmp.globalIndex() = %d, muon_tmp.matchMCHTrackId() = %d, muon_tmp.matchMFTTrackId() = %d, muon_tmp.chi2MatchMCHMFT() = %f", muon_tmp.globalIndex(), muon_tmp.matchMCHTrackId(), muon_tmp.matchMFTTrackId(), muon_tmp.chi2MatchMCHMFT()); if (0.f < muon_tmp.chi2MatchMCHMFT() && muon_tmp.chi2MatchMCHMFT() < min_chi2MatchMCHMFT) { min_chi2MatchMCHMFT = muon_tmp.chi2MatchMCHMFT(); tupleIds_at_min_chi2mftmch = std::make_tuple(muon_tmp.globalIndex(), muon_tmp.matchMCHTrackId(), muon_tmp.matchMFTTrackId()); @@ -325,7 +338,6 @@ struct globalDimuonFilter { } } vec_min_chi2MatchMCHMFT.emplace_back(tupleIds_at_min_chi2mftmch); - // LOGF(info, "min: muon_tmp.globalIndex() = %d, muon_tmp.matchMCHTrackId() = %d, muon_tmp.matchMFTTrackId() = %d, muon_tmp.chi2MatchMCHMFT() = %f", std::get<0>(tupleIds_at_min), std::get<1>(tupleIds_at_min), std::get<2>(tupleIds_at_min), min_chi2MatchMCHMFT); } template @@ -348,7 +360,6 @@ struct globalDimuonFilter { return nGoodGLPerSA; } - PresliceUnsorted perMFTTrack = o2::aod::fwdtrack::matchMFTTrackId; template bool isBestMatch(TCollision const& collision, TFwdTrack const& fwdtrack, TFwdTracks const& fwdtracks, TMFTTracks const& mfttracks) { @@ -394,7 +405,7 @@ struct globalDimuonFilter { return false; } - if (fwdtrack.chi2MatchMCHMFT() > glMuonCutGroup.maxMatchingChi2MCHMFT) { + if (fwdtrack.chi2MatchMCHMFT() < 0.f || glMuonCutGroup.maxMatchingChi2MCHMFT < fwdtrack.chi2MatchMCHMFT()) { return false; } @@ -408,6 +419,9 @@ struct globalDimuonFilter { auto mchtrack = fwdtrack.template matchMCHTrack_as(); // MCH-MID auto mfttrack = fwdtrack.template matchMFTTrack_as(); // MFTsa + float xMFT = mfttrack.x(); + float yMFT = mfttrack.y(); + float relPtResolution = 0.f; if (mfttrack.nClusters() < glMuonCutGroup.minNclsMFT) { return false; @@ -419,52 +433,64 @@ struct globalDimuonFilter { float rAtAbsorberEnd = fwdtrack.rAtAbsorberEnd(); // this works only for GlobalMuonTrack int nClustersMFT = mfttrack.nClusters(); int ndf_mchmft = 2.f * (mchtrack.nClusters() + nClustersMFT) - 5.f; - float chi2 = fwdtrack.chi2() / ndf_mchmft; - if (glMuonCutGroup.maxChi2 < chi2) { + float chi2 = fwdtrack.chi2() / static_cast(ndf_mchmft); + if (chi2 < 0.f || glMuonCutGroup.maxChi2 < chi2) { return false; } int ndf_mft = 2.f * nClustersMFT - 5.f; - float chi2mft = mfttrack.chi2() / ndf_mft; - if (glMuonCutGroup.maxChi2MFT < chi2mft) { + float chi2mft = mfttrack.chi2() / static_cast(ndf_mft); + if (chi2mft < 0.f || glMuonCutGroup.maxChi2MFT < chi2mft) { return false; } - o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToVertex, glMuonCutGroup.matchingZ, mBz, mZShift); - // float ptMatchedMCHMID = propmuonAtPV_Matched.getPt(); + o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = o2::aod::fwdtrackutils::propagateMuon(mchtrack, mchtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, glMuonCutGroup.matchingZ, mBz, 0.f, 0.f, 0.f); float etaMatchedMCHMID = propmuonAtPV_Matched.getEta(); float phiMatchedMCHMID = propmuonAtPV_Matched.getPhi(); - o2::math_utils::bringTo02Pi(phiMatchedMCHMID); + phiMatchedMCHMID = RecoDecay::constrainAngle(phiMatchedMCHMID, 0, 1U); - o2::dataformats::GlobalFwdTrack propmuonAtPV = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToVertex, glMuonCutGroup.matchingZ, mBz, mZShift); + o2::dataformats::GlobalFwdTrack propmuonAtPV = mfttrack.y() > 0.f ? o2::aod::fwdtrackutils::propagateMuon(fwdtrack, fwdtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, glMuonCutGroup.matchingZ, mBz, mXShiftMFTtop, mYShiftMFTtop, mZShiftMFTtop) : o2::aod::fwdtrackutils::propagateMuon(fwdtrack, fwdtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, glMuonCutGroup.matchingZ, mBz, mXShiftMFTbottom, mYShiftMFTbottom, mZShiftMFTbottom); pt = propmuonAtPV.getPt(); eta = propmuonAtPV.getEta(); phi = propmuonAtPV.getPhi(); - o2::math_utils::bringTo02Pi(phi); + phi = RecoDecay::constrainAngle(phi, 0, 1U); if (glMuonCutGroup.refitGlobalMuon) { pt = propmuonAtPV_Matched.getP() * std::sin(2.f * std::atan(std::exp(-eta))); } + relPtResolution = std::sqrt(propmuonAtPV.getSigma2InvQPt()) / std::fabs(propmuonAtPV.getInvQPt()); float deta = etaMatchedMCHMID - eta; float dphi = phiMatchedMCHMID - phi; - o2::math_utils::bringToPMPi(dphi); + dphi = RecoDecay::constrainAngle(dphi, -M_PI, 1U); if (std::sqrt(std::pow(deta / glMuonCutGroup.maxDEta, 2) + std::pow(dphi / glMuonCutGroup.maxDPhi, 2)) > 1.f) { return false; } - float dr = std::sqrt(deta * deta + dphi * dphi); - - float dcaX = propmuonAtPV.getX() - collision.posX(); - float dcaY = propmuonAtPV.getY() - collision.posY(); - float dcaZ = propmuonAtPV.getZ() - collision.posZ(); + o2::dataformats::GlobalFwdTrack propmuonAtDCA = mfttrack.y() > 0.f ? o2::aod::fwdtrackutils::propagateMuon(fwdtrack, fwdtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToDCA, glMuonCutGroup.matchingZ, mBz, mXShiftMFTtop, mYShiftMFTtop, mZShiftMFTtop) : o2::aod::fwdtrackutils::propagateMuon(fwdtrack, fwdtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToDCA, glMuonCutGroup.matchingZ, mBz, mXShiftMFTbottom, mYShiftMFTbottom, mZShiftMFTbottom); + float dcaX = propmuonAtDCA.getX() - collision.posX(); + float dcaY = propmuonAtDCA.getY() - collision.posY(); float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); - float cXX = propmuonAtPV.getSigma2X(); - float cYY = propmuonAtPV.getSigma2Y(); - float cXY = propmuonAtPV.getSigmaXY(); + float cXXatDCA = propmuonAtDCA.getSigma2X(); + float cYYatDCA = propmuonAtDCA.getSigma2Y(); + float cXYatDCA = propmuonAtDCA.getSigmaXY(); if (glMuonCutGroup.maxDCAxy < dcaXY) { return false; } + // add convariance matrix of vertex + float tx = std::cos(propmuonAtDCA.getPhi()) / propmuonAtDCA.getTgl(); // dx/dz + float ty = std::sin(propmuonAtDCA.getPhi()) / propmuonAtDCA.getTgl(); // dy/dz + + // PV covariance projected into the (dx, dy) residual space. + float resPVXX = collision.covXX() - 2.0 * tx * collision.covXZ() + tx * tx * collision.covZZ(); + float resPVXY = collision.covXY() - ty * collision.covXZ() - tx * collision.covYZ() + tx * ty * collision.covZZ(); + float resPVYY = collision.covYY() - 2.0 * ty * collision.covYZ() + ty * ty * collision.covZZ(); + + // Full residual covariance. + float cXX = cXXatDCA + resPVXX; + float cXY = cXYatDCA + resPVXY; + float cYY = cYYatDCA + resPVYY; + float det = cXX * cYY - cXY * cXY; // determinanat float dcaXYinSigma = 999.f; if (det < 0) { @@ -472,9 +498,9 @@ struct globalDimuonFilter { } else { dcaXYinSigma = std::sqrt(std::fabs((dcaX * dcaX * cYY + dcaY * dcaY * cXX - 2.f * dcaX * dcaY * cXY) / det / 2.f)); // dca xy in sigma } - float sigma_dcaXY = dcaXY / dcaXYinSigma; + float sigma_dcaXY = dcaXY / dcaXYinSigma / std::sqrt(2.f); - o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToDCA, glMuonCutGroup.matchingZ, mBz, mZShift); + o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = o2::aod::fwdtrackutils::propagateMuon(mchtrack, mchtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToDCA, glMuonCutGroup.matchingZ, mBz, 0.f, 0.f, 0.f); float dcaX_Matched = propmuonAtDCA_Matched.getX() - collision.posX(); float dcaY_Matched = propmuonAtDCA_Matched.getY() - collision.posY(); float dcaXY_Matched = std::sqrt(dcaX_Matched * dcaX_Matched + dcaY_Matched * dcaY_Matched); @@ -488,37 +514,75 @@ struct globalDimuonFilter { return false; } + float chi2IP = mfttrack.y() > 0.f ? o2::aod::fwdtrackutils::getFwdChi2IP(fwdtrack, collision, mBz, mXShiftMFTtop, mYShiftMFTtop, mZShiftMFTtop) : o2::aod::fwdtrackutils::getFwdChi2IP(fwdtrack, collision, mBz, mXShiftMFTbottom, mYShiftMFTbottom, mZShiftMFTbottom); + if constexpr (fillHistograms) { - fRegistry.fill(HIST("MFTMCHMID/hPt"), pt); - fRegistry.fill(HIST("MFTMCHMID/hEtaPhi"), phi, eta); - fRegistry.fill(HIST("MFTMCHMID/hEtaPhi_MatchedMCHMID"), phiMatchedMCHMID, etaMatchedMCHMID); - fRegistry.fill(HIST("MFTMCHMID/hDEtaDPhi"), dphi, deta); - fRegistry.fill(HIST("MFTMCHMID/hSign"), fwdtrack.sign()); - fRegistry.fill(HIST("MFTMCHMID/hNclusters"), fwdtrack.nClusters()); - fRegistry.fill(HIST("MFTMCHMID/hNclustersMFT"), nClustersMFT); - fRegistry.fill(HIST("MFTMCHMID/hPDCA_Rabs"), rAtAbsorberEnd, pDCA); - fRegistry.fill(HIST("MFTMCHMID/hRatAbsorberEnd"), rAtAbsorberEnd); - fRegistry.fill(HIST("MFTMCHMID/hChi2"), chi2); - fRegistry.fill(HIST("MFTMCHMID/hChi2MFT"), chi2mft); - fRegistry.fill(HIST("MFTMCHMID/hChi2MatchMCHMID"), fwdtrack.chi2MatchMCHMID()); - fRegistry.fill(HIST("MFTMCHMID/hChi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT()); - fRegistry.fill(HIST("MFTMCHMID/hDCAxy2D"), dcaX, dcaY); - fRegistry.fill(HIST("MFTMCHMID/hDCAxy2DinSigma"), dcaX / std::sqrt(cXX), dcaY / std::sqrt(cYY)); - fRegistry.fill(HIST("MFTMCHMID/hDCAxy"), dcaXY); - fRegistry.fill(HIST("MFTMCHMID/hDCAxyz"), dcaXY, dcaZ); - fRegistry.fill(HIST("MFTMCHMID/hDCAxyinSigma"), dcaXYinSigma); - fRegistry.fill(HIST("MFTMCHMID/hDCAxResolutionvsPt"), pt, std::sqrt(cXX) * 1e+4); // convert cm to um - fRegistry.fill(HIST("MFTMCHMID/hDCAyResolutionvsPt"), pt, std::sqrt(cYY) * 1e+4); // convert cm to um - fRegistry.fill(HIST("MFTMCHMID/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 1e+4); // convert cm to um - fRegistry.fill(HIST("MFTMCHMID/hDCAx_PosZ"), collision.posZ(), dcaX); - fRegistry.fill(HIST("MFTMCHMID/hDCAy_PosZ"), collision.posZ(), dcaY); - fRegistry.fill(HIST("MFTMCHMID/hDCAx_Phi"), phi, dcaX); - fRegistry.fill(HIST("MFTMCHMID/hDCAy_Phi"), phi, dcaY); - fRegistry.fill(HIST("MFTMCHMID/hdR_Chi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT(), dr); - fRegistry.fill(HIST("MFTMCHMID/hdR_Chi2"), chi2, dr); - fRegistry.fill(HIST("MFTMCHMID/hChi2_Chi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT(), chi2); + if (fwdtrack.sign() > 0) { + fRegistry.fill(HIST("MFTMCHMID/positive/hPt"), pt); + fRegistry.fill(HIST("MFTMCHMID/positive/hPtResolution"), pt, relPtResolution); + fRegistry.fill(HIST("MFTMCHMID/positive/hEtaPhi"), phi, eta); + fRegistry.fill(HIST("MFTMCHMID/positive/hEtaPhi_MatchedMCHMID"), phiMatchedMCHMID, etaMatchedMCHMID); + fRegistry.fill(HIST("MFTMCHMID/positive/hDEtaDPhi"), dphi, deta); + fRegistry.fill(HIST("MFTMCHMID/positive/hSign"), fwdtrack.sign()); + fRegistry.fill(HIST("MFTMCHMID/positive/hNclusters"), fwdtrack.nClusters()); + fRegistry.fill(HIST("MFTMCHMID/positive/hNclustersMFT"), nClustersMFT); + fRegistry.fill(HIST("MFTMCHMID/positive/hPDCA_Rabs"), rAtAbsorberEnd, pDCA); + fRegistry.fill(HIST("MFTMCHMID/positive/hRatAbsorberEnd"), rAtAbsorberEnd); + fRegistry.fill(HIST("MFTMCHMID/positive/hChi2_Pt"), pt, chi2); + fRegistry.fill(HIST("MFTMCHMID/positive/hChi2MFT_Pt"), pt, chi2mft); + fRegistry.fill(HIST("MFTMCHMID/positive/hChi2MatchMCHMID_Pt"), pt, fwdtrack.chi2MatchMCHMID()); + fRegistry.fill(HIST("MFTMCHMID/positive/hChi2MatchMCHMFT_Pt"), pt, fwdtrack.chi2MatchMCHMFT()); + fRegistry.fill(HIST("MFTMCHMID/positive/hDCAxy2D"), dcaX, dcaY); + fRegistry.fill(HIST("MFTMCHMID/positive/hDCAxy2DinSigma"), dcaX / std::sqrt(cXX), dcaY / std::sqrt(cYY)); + fRegistry.fill(HIST("MFTMCHMID/positive/hDCAxy"), dcaXY); + fRegistry.fill(HIST("MFTMCHMID/positive/hDCAxyinSigma"), dcaXYinSigma); + fRegistry.fill(HIST("MFTMCHMID/positive/hLog10Chi2IP"), std::log10(chi2IP)); + fRegistry.fill(HIST("MFTMCHMID/positive/hDCAxResolutionvsPt"), pt, std::sqrt(cXX) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/positive/hDCAyResolutionvsPt"), pt, std::sqrt(cYY) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/positive/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/positive/hDCAx_Phi"), std::atan2(yMFT, xMFT), dcaX); + fRegistry.fill(HIST("MFTMCHMID/positive/hDCAy_Phi"), std::atan2(yMFT, xMFT), dcaY); + if (std::atan2(yMFT, xMFT) > 0.f) { + fRegistry.fill(HIST("MFTMCHMID/positive/hDCAx_PosZ_MFTtop"), collision.posZ(), dcaX); + fRegistry.fill(HIST("MFTMCHMID/positive/hDCAy_PosZ_MFTtop"), collision.posZ(), dcaY); + } else { + fRegistry.fill(HIST("MFTMCHMID/positive/hDCAx_PosZ_MFTbottom"), collision.posZ(), dcaX); + fRegistry.fill(HIST("MFTMCHMID/positive/hDCAy_PosZ_MFTbottom"), collision.posZ(), dcaY); + } + } else { + fRegistry.fill(HIST("MFTMCHMID/negative/hPt"), pt); + fRegistry.fill(HIST("MFTMCHMID/negative/hPtResolution"), pt, relPtResolution); + fRegistry.fill(HIST("MFTMCHMID/negative/hEtaPhi"), phi, eta); + fRegistry.fill(HIST("MFTMCHMID/negative/hEtaPhi_MatchedMCHMID"), phiMatchedMCHMID, etaMatchedMCHMID); + fRegistry.fill(HIST("MFTMCHMID/negative/hDEtaDPhi"), dphi, deta); + fRegistry.fill(HIST("MFTMCHMID/negative/hSign"), fwdtrack.sign()); + fRegistry.fill(HIST("MFTMCHMID/negative/hNclusters"), fwdtrack.nClusters()); + fRegistry.fill(HIST("MFTMCHMID/negative/hNclustersMFT"), nClustersMFT); + fRegistry.fill(HIST("MFTMCHMID/negative/hPDCA_Rabs"), rAtAbsorberEnd, pDCA); + fRegistry.fill(HIST("MFTMCHMID/negative/hRatAbsorberEnd"), rAtAbsorberEnd); + fRegistry.fill(HIST("MFTMCHMID/negative/hChi2_Pt"), pt, chi2); + fRegistry.fill(HIST("MFTMCHMID/negative/hChi2MFT_Pt"), pt, chi2mft); + fRegistry.fill(HIST("MFTMCHMID/negative/hChi2MatchMCHMID_Pt"), pt, fwdtrack.chi2MatchMCHMID()); + fRegistry.fill(HIST("MFTMCHMID/negative/hChi2MatchMCHMFT_Pt"), pt, fwdtrack.chi2MatchMCHMFT()); + fRegistry.fill(HIST("MFTMCHMID/negative/hDCAxy2D"), dcaX, dcaY); + fRegistry.fill(HIST("MFTMCHMID/negative/hDCAxy2DinSigma"), dcaX / std::sqrt(cXX), dcaY / std::sqrt(cYY)); + fRegistry.fill(HIST("MFTMCHMID/negative/hDCAxy"), dcaXY); + fRegistry.fill(HIST("MFTMCHMID/negative/hDCAxyinSigma"), dcaXYinSigma); + fRegistry.fill(HIST("MFTMCHMID/negative/hLog10Chi2IP"), std::log10(chi2IP)); + fRegistry.fill(HIST("MFTMCHMID/negative/hDCAxResolutionvsPt"), pt, std::sqrt(cXX) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/negative/hDCAyResolutionvsPt"), pt, std::sqrt(cYY) * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/negative/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 1e+4); // convert cm to um + fRegistry.fill(HIST("MFTMCHMID/negative/hDCAx_Phi"), std::atan2(yMFT, xMFT), dcaX); + fRegistry.fill(HIST("MFTMCHMID/negative/hDCAy_Phi"), std::atan2(yMFT, xMFT), dcaY); + if (std::atan2(yMFT, xMFT) > 0.f) { + fRegistry.fill(HIST("MFTMCHMID/negative/hDCAx_PosZ_MFTtop"), collision.posZ(), dcaX); + fRegistry.fill(HIST("MFTMCHMID/negative/hDCAy_PosZ_MFTtop"), collision.posZ(), dcaY); + } else { + fRegistry.fill(HIST("MFTMCHMID/negative/hDCAx_PosZ_MFTbottom"), collision.posZ(), dcaX); + fRegistry.fill(HIST("MFTMCHMID/negative/hDCAy_PosZ_MFTbottom"), collision.posZ(), dcaY); + } + } } - return true; } @@ -556,34 +620,34 @@ struct globalDimuonFilter { int nClustersMFT = mfttrack.nClusters(); int ndf_mchmft = 2.f * (mchtrack.nClusters() + nClustersMFT) - 5.f; - float chi2 = fwdtrack.chi2() / ndf_mchmft; + float chi2 = fwdtrack.chi2() / static_cast(ndf_mchmft); if (tagMuonCutGroup.maxChi2 < chi2) { return false; } int ndf_mft = 2.f * nClustersMFT - 5.f; - float chi2mft = mfttrack.chi2() / ndf_mft; + float chi2mft = mfttrack.chi2() / static_cast(ndf_mft); if (tagMuonCutGroup.maxChi2MFT < chi2mft) { return false; } - o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToVertex, tagMuonCutGroup.matchingZ, mBz, mZShift); + o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = o2::aod::fwdtrackutils::propagateMuon(mchtrack, mchtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, tagMuonCutGroup.matchingZ, mBz, 0.f, 0.f, 0.f); float etaMatchedMCHMID = propmuonAtPV_Matched.getEta(); float phiMatchedMCHMID = propmuonAtPV_Matched.getPhi(); - o2::math_utils::bringTo02Pi(phiMatchedMCHMID); + phiMatchedMCHMID = RecoDecay::constrainAngle(phiMatchedMCHMID, 0, 1U); - o2::dataformats::GlobalFwdTrack propmuonAtPV = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToVertex, tagMuonCutGroup.matchingZ, mBz, mZShift); + o2::dataformats::GlobalFwdTrack propmuonAtPV = mfttrack.y() > 0.f ? o2::aod::fwdtrackutils::propagateMuon(fwdtrack, fwdtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, tagMuonCutGroup.matchingZ, mBz, mXShiftMFTtop, mYShiftMFTtop, mZShiftMFTtop) : o2::aod::fwdtrackutils::propagateMuon(fwdtrack, fwdtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, tagMuonCutGroup.matchingZ, mBz, mXShiftMFTbottom, mYShiftMFTbottom, mZShiftMFTbottom); pt = propmuonAtPV.getPt(); eta = propmuonAtPV.getEta(); phi = propmuonAtPV.getPhi(); - o2::math_utils::bringTo02Pi(phi); + phi = RecoDecay::constrainAngle(phi, 0, 1U); if (tagMuonCutGroup.refitGlobalMuon) { pt = propmuonAtPV_Matched.getP() * std::sin(2.f * std::atan(std::exp(-eta))); } float deta = etaMatchedMCHMID - eta; float dphi = phiMatchedMCHMID - phi; - o2::math_utils::bringToPMPi(dphi); + dphi = RecoDecay::constrainAngle(dphi, -M_PI, 1U); if (std::sqrt(std::pow(deta / tagMuonCutGroup.maxDEta, 2) + std::pow(dphi / tagMuonCutGroup.maxDPhi, 2)) > 1.f) { return false; @@ -595,24 +659,6 @@ struct globalDimuonFilter { if (tagMuonCutGroup.maxDCAxy < dcaXY) { return false; } - // float cXX = propmuonAtPV.getSigma2X(); - // float cYY = propmuonAtPV.getSigma2Y(); - // float cXY = propmuonAtPV.getSigmaXY(); - - // float det = cXX * cYY - cXY * cXY; // determinanat - // float dcaXYinSigma = 999.f; - // if (det < 0) { - // dcaXYinSigma = 999.f; - // } else { - // dcaXYinSigma = std::sqrt(std::fabs((dcaX * dcaX * cYY + dcaY * dcaY * cXX - 2.f * dcaX * dcaY * cXY) / det / 2.f)); // dca xy in sigma - // } - // float sigma_dcaXY = dcaXY / dcaXYinSigma; - - // o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToDCA, tagMuonCutGroup.matchingZ, mBz); - // float dcaX_Matched = propmuonAtDCA_Matched.getX() - collision.posX(); - // float dcaY_Matched = propmuonAtDCA_Matched.getY() - collision.posY(); - // float dcaXY_Matched = std::sqrt(dcaX_Matched * dcaX_Matched + dcaY_Matched * dcaY_Matched); - // float pDCA = mchtrack.p() * dcaXY_Matched; if (pt < tagMuonCutGroup.minPt || tagMuonCutGroup.maxPt < pt) { return false; @@ -662,34 +708,34 @@ struct globalDimuonFilter { nclsMCH = mchtrack.nClusters(); nclsMFT = mfttrack.nClusters(); int ndf_mchmft = 2.f * (nclsMCH + nclsMFT) - 5.f; - chi2 = fwdtrack.chi2() / ndf_mchmft; + chi2 = fwdtrack.chi2() / static_cast(ndf_mchmft); if (probeMuonCutGroup.maxChi2 < chi2) { return false; } int ndf_mft = 2.f * nclsMFT - 5.f; - chi2mft = mfttrack.chi2() / ndf_mft; + chi2mft = mfttrack.chi2() / static_cast(ndf_mft); if (probeMuonCutGroup.maxChi2MFT < chi2mft) { return false; } - o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToVertex, probeMuonCutGroup.matchingZ, mBz, mZShift); + o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = o2::aod::fwdtrackutils::propagateMuon(mchtrack, mchtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, probeMuonCutGroup.matchingZ, mBz, 0.f, 0.f, 0.f); float etaMatchedMCHMID = propmuonAtPV_Matched.getEta(); float phiMatchedMCHMID = propmuonAtPV_Matched.getPhi(); - o2::math_utils::bringTo02Pi(phiMatchedMCHMID); + phiMatchedMCHMID = RecoDecay::constrainAngle(phiMatchedMCHMID, 0, 1U); - o2::dataformats::GlobalFwdTrack propmuonAtPV = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToVertex, probeMuonCutGroup.matchingZ, mBz, mZShift); + o2::dataformats::GlobalFwdTrack propmuonAtPV = mfttrack.y() > 0.f ? o2::aod::fwdtrackutils::propagateMuon(fwdtrack, fwdtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, probeMuonCutGroup.matchingZ, mBz, mXShiftMFTtop, mYShiftMFTtop, mZShiftMFTtop) : o2::aod::fwdtrackutils::propagateMuon(fwdtrack, fwdtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToVertex, probeMuonCutGroup.matchingZ, mBz, mXShiftMFTbottom, mYShiftMFTbottom, mZShiftMFTbottom); pt = propmuonAtPV.getPt(); eta = propmuonAtPV.getEta(); phi = propmuonAtPV.getPhi(); - o2::math_utils::bringTo02Pi(phi); + phi = RecoDecay::constrainAngle(phi, 0, 1U); if (probeMuonCutGroup.refitGlobalMuon) { pt = propmuonAtPV_Matched.getP() * std::sin(2.f * std::atan(std::exp(-eta))); } deta = etaMatchedMCHMID - eta; dphi = phiMatchedMCHMID - phi; - o2::math_utils::bringToPMPi(dphi); + dphi = RecoDecay::constrainAngle(dphi, -M_PI, 1U); if (std::sqrt(std::pow(deta / probeMuonCutGroup.maxDEta, 2) + std::pow(dphi / probeMuonCutGroup.maxDPhi, 2)) > 1.f) { return false; @@ -701,20 +747,8 @@ struct globalDimuonFilter { if (probeMuonCutGroup.maxDCAxy < dcaXY) { return false; } - // float cXX = propmuonAtPV.getSigma2X(); - // float cYY = propmuonAtPV.getSigma2Y(); - // float cXY = propmuonAtPV.getSigmaXY(); - - // float det = cXX * cYY - cXY * cXY; // determinanat - // float dcaXYinSigma = 999.f; - // if (det < 0) { - // dcaXYinSigma = 999.f; - // } else { - // dcaXYinSigma = std::sqrt(std::fabs((dcaX * dcaX * cYY + dcaY * dcaY * cXX - 2.f * dcaX * dcaY * cXY) / det / 2.f)); // dca xy in sigma - // } - // float sigma_dcaXY = dcaXY / dcaXYinSigma; - o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToDCA, probeMuonCutGroup.matchingZ, mBz, mZShift); + o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = o2::aod::fwdtrackutils::propagateMuon(mchtrack, mchtrack, collision, o2::aod::fwdtrackutils::propagationPoint::kToDCA, probeMuonCutGroup.matchingZ, mBz, 0.f, 0.f, 0.f); float dcaX_Matched = propmuonAtDCA_Matched.getX() - collision.posX(); float dcaY_Matched = propmuonAtDCA_Matched.getY() - collision.posY(); float dcaXY_Matched = std::sqrt(dcaX_Matched * dcaX_Matched + dcaY_Matched * dcaY_Matched); @@ -872,7 +906,7 @@ struct globalDimuonFilter { } // end end of negative muon loop } // end end of positive muon loop - for (const auto pos1 : posMuons) { + for (const auto& pos1 : posMuons) { auto fwdtrack1 = fwdtracks.rawIteratorAt(pos1); if (!isBestMatch(collision, fwdtrack1, fwdtracks, mfttracks)) { continue; @@ -883,7 +917,7 @@ struct globalDimuonFilter { } ROOT::Math::PtEtaPhiMVector v1(pt1, eta1, phi1, o2::constants::physics::MassMuon); - for (const auto pos2 : posMuons) { + for (const auto& pos2 : posMuons) { auto fwdtrack2 = fwdtracks.rawIteratorAt(pos2); if (pos1 == pos2) { continue; @@ -905,7 +939,7 @@ struct globalDimuonFilter { } // end end of positive muon loop } // end end of positive muon loop - for (const auto neg1 : negMuons) { + for (const auto& neg1 : negMuons) { auto fwdtrack1 = fwdtracks.rawIteratorAt(neg1); if (!isBestMatch(collision, fwdtrack1, fwdtracks, mfttracks)) { continue; @@ -916,7 +950,7 @@ struct globalDimuonFilter { } ROOT::Math::PtEtaPhiMVector v1(pt1, eta1, phi1, o2::constants::physics::MassMuon); - for (const auto neg2 : negMuons) { + for (const auto& neg2 : negMuons) { auto fwdtrack2 = fwdtracks.rawIteratorAt(neg2); if (neg1 == neg2) { continue; @@ -954,32 +988,51 @@ struct globalDimuonFilter { if (eventCutGroup.cfgRequireNoITSROFB && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { return false; } + if (eventCutGroup.cfgRequireVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + if (eventCutGroup.cfgRequireVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + return false; + } + if (eventCutGroup.cfgRequireNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (eventCutGroup.cfgRequireGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (collision.chi2() / collision.numContrib() > eventCutGroup.cfgChi2PerNcontribMax) { + return false; + } + if (collision.numContrib() < eventCutGroup.cfgNcontribMin) { + return false; + } return true; } - using MyCollisions = soa::Join; + using MyCollisions = o2::soa::Join; using MyCollision = MyCollisions::iterator; - using MyBCs = soa::Join; + using MyBCs = o2::soa::Join; using MyBC = MyBCs::iterator; - using MyFwdTracks = soa::Join; // muon tracks are repeated. i.e. not exclusive. + using MyFwdTracks = o2::soa::Join; // muon tracks are repeated. i.e. not exclusive. using MyFwdTrack = MyFwdTracks::iterator; - SliceCache cache; - Preslice perCollision = o2::aod::fwdtrack::collisionId; - Preslice fwdtrackIndicesPerCollision = aod::track_association::collisionId; - PresliceUnsorted fwdtrackIndicesPerFwdTrack = aod::track_association::fwdtrackId; - PresliceUnsorted fwdtracksPerMCHTrack = aod::fwdtrack::matchMCHTrackId; + o2::framework::SliceCache cache; + o2::framework::Preslice perCollision = o2::aod::fwdtrack::collisionId; + o2::framework::Preslice fwdtrackIndicesPerCollision = o2::aod::track_association::collisionId; + o2::framework::PresliceUnsorted fwdtrackIndicesPerFwdTrack = o2::aod::track_association::fwdtrackId; + o2::framework::PresliceUnsorted fwdtracksPerMCHTrack = o2::aod::fwdtrack::matchMCHTrackId; + o2::framework::PresliceUnsorted perMFTTrack = o2::aod::fwdtrack::matchMFTTrackId; - std::unordered_map map_mfttrackcovs; + // std::unordered_map map_mfttrackcovs; std::unordered_map mapSelectedCollisions; - void processSA(MyCollisions const& collisions, MyBCs const&, MyFwdTracks const& fwdtracks, aod::MFTTracks const& mfttracks, aod::MFTTracksCov const& mftCovs) + void processSA(MyCollisions const& collisions, MyBCs const&, MyFwdTracks const& fwdtracks, o2::aod::MFTTracks const& mfttracks, o2::aod::MFTTracksCov const& mftCovs) { - for (const auto& mfttrackConv : mftCovs) { - map_mfttrackcovs[mfttrackConv.matchMFTTrackId()] = mfttrackConv.globalIndex(); - } + // for (const auto& mfttrackConv : mftCovs) { + // map_mfttrackcovs[mfttrackConv.matchMFTTrackId()] = mfttrackConv.globalIndex(); + // } vec_min_chi2MatchMCHMFT.reserve(fwdtracks.size()); for (const auto& collision : collisions) { @@ -1014,16 +1067,16 @@ struct globalDimuonFilter { if (isSelectedCollision(collision)) { fRegistry.fill(HIST("hCollisionCounter"), 7); + fRegistry.fill(HIST("Vertex/MB/hZvtx"), collision.posZ()); + fRegistry.fill(HIST("Vertex/MB/hChi2vsNContrib"), collision.numContrib(), collision.chi2() / collision.numContrib()); + fRegistry.fill(HIST("Vertex/MB/hSigmaX"), collision.numContrib(), std::sqrt(collision.covXX()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Vertex/MB/hSigmaY"), collision.numContrib(), std::sqrt(collision.covYY()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Vertex/MB/hSigmaZ"), collision.numContrib(), std::sqrt(collision.covZZ()) * 1e+4); // convert cm to um int nGlobalMuon = 0; // LOGF(info, "collision.globalIndex() = %d, fwdtrackIdsThisCollision = %d", collision.globalIndex(), fwdtrackIdsThisCollision.size()); auto fwdtracks_per_coll = fwdtracks.sliceBy(perCollision, collision.globalIndex()); for (const auto& fwdtrack : fwdtracks_per_coll) { - // float pt = 999.f, eta = 999.f, phi = 999.f; - // if (isSelectedGlobalMuon(collision, fwdtrack, fwdtracks, mfttracks, pt, eta, phi)) { - // nGlobalMuon++; - // } - int nGoodGLPerSA = countMatchedCandidatesPerMCHMID(collision, fwdtrack, fwdtracks, mfttracks); if (nGoodGLPerSA > 0) { nGlobalMuon++; @@ -1035,6 +1088,12 @@ struct globalDimuonFilter { if (nGlobalMuon >= minNmuon) { fRegistry.fill(HIST("hCollisionCounter"), 8); + fRegistry.fill(HIST("Vertex/Triggered/hZvtx"), collision.posZ()); + fRegistry.fill(HIST("Vertex/Triggered/hChi2vsNContrib"), collision.numContrib(), collision.chi2() / collision.numContrib()); + fRegistry.fill(HIST("Vertex/Triggered/hSigmaX"), collision.numContrib(), std::sqrt(collision.covXX()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Vertex/Triggered/hSigmaY"), collision.numContrib(), std::sqrt(collision.covYY()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Vertex/Triggered/hSigmaZ"), collision.numContrib(), std::sqrt(collision.covZZ()) * 1e+4); // convert cm to um + mapSelectedCollisions[collision.globalIndex()] = true; tags(true); } else { @@ -1117,18 +1176,18 @@ struct globalDimuonFilter { negProbeMuons.shrink_to_fit(); } // end of collision loop - map_mfttrackcovs.clear(); + // map_mfttrackcovs.clear(); mapSelectedCollisions.clear(); vec_min_chi2MatchMCHMFT.clear(); vec_min_chi2MatchMCHMFT.shrink_to_fit(); } PROCESS_SWITCH(globalDimuonFilter, processSA, "process without FTTCA", false); - void processFTTCA(MyCollisions const& collisions, MyBCs const&, MyFwdTracks const& fwdtracks, aod::MFTTracks const& mfttracks, aod::MFTTracksCov const& mftCovs, aod::FwdTrackAssoc const& fwdtrackIndices) + void processFTTCA(MyCollisions const& collisions, MyBCs const&, MyFwdTracks const& fwdtracks, o2::aod::MFTTracks const& mfttracks, o2::aod::MFTTracksCov const& mftCovs, o2::aod::FwdTrackAssoc const& fwdtrackIndices) { - for (const auto& mfttrackConv : mftCovs) { - map_mfttrackcovs[mfttrackConv.matchMFTTrackId()] = mfttrackConv.globalIndex(); - } + // for (const auto& mfttrackConv : mftCovs) { + // map_mfttrackcovs[mfttrackConv.matchMFTTrackId()] = mfttrackConv.globalIndex(); + // } vec_min_chi2MatchMCHMFT.reserve(fwdtracks.size()); for (const auto& collision : collisions) { @@ -1165,21 +1224,17 @@ struct globalDimuonFilter { if (isSelectedCollision(collision)) { fRegistry.fill(HIST("hCollisionCounter"), 7); + fRegistry.fill(HIST("Vertex/MB/hZvtx"), collision.posZ()); + fRegistry.fill(HIST("Vertex/MB/hChi2vsNContrib"), collision.numContrib(), collision.chi2() / collision.numContrib()); + fRegistry.fill(HIST("Vertex/MB/hSigmaX"), collision.numContrib(), std::sqrt(collision.covXX()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Vertex/MB/hSigmaY"), collision.numContrib(), std::sqrt(collision.covYY()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Vertex/MB/hSigmaZ"), collision.numContrib(), std::sqrt(collision.covZZ()) * 1e+4); // convert cm to um int nGlobalMuon = 0; auto fwdtrackIdsThisCollision = fwdtrackIndices.sliceBy(fwdtrackIndicesPerCollision, collision.globalIndex()); // LOGF(info, "collision.globalIndex() = %d, fwdtrackIdsThisCollision = %d", collision.globalIndex(), fwdtrackIdsThisCollision.size()); for (const auto& fwdtrackId : fwdtrackIdsThisCollision) { auto fwdtrack = fwdtrackId.template fwdtrack_as(); - - // if (std::find(vec_min_chi2MatchMCHMFT.begin(), vec_min_chi2MatchMCHMFT.end(), std::make_tuple(fwdtrack.globalIndex(), fwdtrack.matchMCHTrackId(), fwdtrack.matchMFTTrackId())) == vec_min_chi2MatchMCHMFT.end()) { - // continue; - // } - // float pt = 999.f, eta = 999.f, phi = 999.f; - // if (isSelectedGlobalMuon(collision, fwdtrack, fwdtracks, mfttracks, pt, eta, phi)) { - // nGlobalMuon++; - // } - int nGoodGLPerSA = countMatchedCandidatesPerMCHMID(collision, fwdtrack, fwdtracks, mfttracks); if (nGoodGLPerSA > 0) { nGlobalMuon++; @@ -1191,6 +1246,12 @@ struct globalDimuonFilter { if (nGlobalMuon >= minNmuon) { fRegistry.fill(HIST("hCollisionCounter"), 8); + fRegistry.fill(HIST("Vertex/Triggered/hZvtx"), collision.posZ()); + fRegistry.fill(HIST("Vertex/Triggered/hChi2vsNContrib"), collision.numContrib(), collision.chi2() / collision.numContrib()); + fRegistry.fill(HIST("Vertex/Triggered/hSigmaX"), collision.numContrib(), std::sqrt(collision.covXX()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Vertex/Triggered/hSigmaY"), collision.numContrib(), std::sqrt(collision.covYY()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Vertex/Triggered/hSigmaZ"), collision.numContrib(), std::sqrt(collision.covZZ()) * 1e+4); // convert cm to um + mapSelectedCollisions[collision.globalIndex()] = true; tags(true); } else { @@ -1279,7 +1340,7 @@ struct globalDimuonFilter { negProbeMuons.shrink_to_fit(); } // end of collision loop - map_mfttrackcovs.clear(); + // map_mfttrackcovs.clear(); mapSelectedCollisions.clear(); vec_min_chi2MatchMCHMFT.clear(); vec_min_chi2MatchMCHMFT.shrink_to_fit(); @@ -1287,8 +1348,8 @@ struct globalDimuonFilter { PROCESS_SWITCH(globalDimuonFilter, processFTTCA, "process with FTTCA", true); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfg) +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfg) { - return WorkflowSpec{ - adaptAnalysisTask(cfg, TaskName{"em-global-dimuon-filter"})}; + return o2::framework::WorkflowSpec{ + adaptAnalysisTask(cfg, o2::framework::TaskName{"em-global-dimuon-filter"})}; } diff --git a/PWGCF/DataModel/CorrelationsDerived.h b/PWGCF/DataModel/CorrelationsDerived.h index ec0f2aa11c2..4401f9cb14d 100644 --- a/PWGCF/DataModel/CorrelationsDerived.h +++ b/PWGCF/DataModel/CorrelationsDerived.h @@ -40,7 +40,7 @@ using CFMcCollisionWithExtra = CFMcCollisionsWithExtra::iterator; namespace cfmcparticle { -DECLARE_SOA_INDEX_COLUMN(CFMcCollision, cfMcCollision); //! Index to reduced MC collision +DECLARE_SOA_INDEX_COLUMN(CFMcCollision, cfMcCollision); //! Index to reduced MC collision; o2-linter: disable=name/o2-column (preserve the established derived-table API) DECLARE_SOA_COLUMN(Pt, pt, float); //! pT (GeV/c) DECLARE_SOA_COLUMN(Eta, eta, float); //! Pseudorapidity DECLARE_SOA_COLUMN(Phi, phi, float); //! Phi angle @@ -58,31 +58,42 @@ using CFMcParticle = CFMcParticles::iterator; namespace cfmultiplicity { DECLARE_SOA_COLUMN(Multiplicity, multiplicity, float); -} +} // namespace cfmultiplicity DECLARE_SOA_TABLE(CFMultiplicities, "AOD", "CFMULTIPLICITY", cfmultiplicity::Multiplicity); using CFMultiplicity = CFMultiplicities::iterator; namespace cfcollision { -DECLARE_SOA_INDEX_COLUMN(CFMcCollision, cfMcCollision); //! Index to reduced MC collision -DECLARE_SOA_COLUMN(Multiplicity, multiplicity, float); //! Centrality/multiplicity value +DECLARE_SOA_INDEX_COLUMN(CFMcCollision, cfMcCollision); //! Index to reduced MC collision; o2-linter: disable=name/o2-column (preserve the established derived-table API) +DECLARE_SOA_COLUMN(Multiplicity, multiplicity, float); //! Centrality/multiplicity value +DECLARE_SOA_COLUMN(BestRecoCollision, bestRecoCollision, bool); //! Whether this is the best reconstructed collision for the associated MC collision (largest number of contributors) } // namespace cfcollision DECLARE_SOA_TABLE(CFCollisions, "AOD", "CFCOLLISION", //! Reduced collision table o2::soa::Index<>, bc::RunNumber, collision::PosZ, cfcollision::Multiplicity, timestamp::Timestamp); DECLARE_SOA_TABLE(CFCollLabels, "AOD", "CFCOLLLABEL", //! Labels for reduced collision table - cfcollision::CFMcCollisionId); + cfcollision::CFMcCollisionId, cfcollision::BestRecoCollision); using CFCollision = CFCollisions::iterator; using CFCollLabel = CFCollLabels::iterator; using CFCollisionsWithLabel = soa::Join; using CFCollisionWithLabel = CFCollisionsWithLabel::iterator; +namespace cfcollisionextra +{ +DECLARE_SOA_COLUMN(MultiplicityCorrected, multiplicityCorrected, float); //! Efficiency-corrected track count +} // namespace cfcollisionextra +DECLARE_SOA_TABLE(CFCollisionsExtra, "AOD", "CFCOLLSEXTRA", //! Row-aligned extension of CFCollisions; filled only when multiplicity efficiency is configured + cfcollisionextra::MultiplicityCorrected); +using CFCollisionExtra = CFCollisionsExtra::iterator; +using CFCollisionsWithExtra = soa::Join; +using CFCollisionWithExtra = CFCollisionsWithExtra::iterator; + namespace cftrack { -DECLARE_SOA_INDEX_COLUMN(CFCollision, cfCollision); //! Index to collision -DECLARE_SOA_INDEX_COLUMN(CFMcParticle, cfMCParticle); //! Index to MC particle +DECLARE_SOA_INDEX_COLUMN(CFCollision, cfCollision); //! Index to collision; o2-linter: disable=name/o2-column (preserve the established derived-table API) +DECLARE_SOA_INDEX_COLUMN(CFMcParticle, cfMCParticle); //! Index to MC particle; o2-linter: disable=name/o2-column (preserve the established derived-table API) DECLARE_SOA_COLUMN(Pt, pt, float); //! pT (GeV/c) DECLARE_SOA_COLUMN(Eta, eta, float); //! Pseudorapidity DECLARE_SOA_COLUMN(Phi, phi, float); //! Phi angle @@ -114,7 +125,6 @@ enum MultiplicityEstimators : uint8_t { MultNTracksGlobal = 0x8, CentFT0M = 0x10, }; - inline constexpr uint32_t NMultiplicityEstimators = __builtin_ctz(CentFT0M) + 1; } // namespace cfmultset @@ -147,8 +157,8 @@ using CFMcParticleRef = CFMcParticleRefs::iterator; namespace cf2prongtrack { -DECLARE_SOA_INDEX_COLUMN_FULL(CFTrackProng0, cfTrackProng0, int, CFTracks, "_0"); //! Index to prong 1 CFTrack -DECLARE_SOA_INDEX_COLUMN_FULL(CFTrackProng1, cfTrackProng1, int, CFTracks, "_1"); //! Index to prong 2 CFTrack +DECLARE_SOA_INDEX_COLUMN_FULL(CFTrackProng0, cfTrackProng0, int, CFTracks, "_0"); //! Index to prong 1 CFTrack; o2-linter: disable=name/o2-column (preserve the established derived-table API) +DECLARE_SOA_INDEX_COLUMN_FULL(CFTrackProng1, cfTrackProng1, int, CFTracks, "_1"); //! Index to prong 2 CFTrack; o2-linter: disable=name/o2-column (preserve the established derived-table API) DECLARE_SOA_COLUMN(Pt, pt, float); //! pT (GeV/c) DECLARE_SOA_COLUMN(Eta, eta, float); //! Pseudorapidity DECLARE_SOA_COLUMN(Phi, phi, float); //! Phi angle @@ -201,8 +211,8 @@ using CF2ProngTrackml = CF2ProngTrackmls::iterator; namespace cf2prongmcpart { -DECLARE_SOA_INDEX_COLUMN_FULL(CFParticleDaugh0, cfParticleDaugh0, int, CFMcParticles, "_0"); //! Index to prong 1 CFMcParticle -DECLARE_SOA_INDEX_COLUMN_FULL(CFParticleDaugh1, cfParticleDaugh1, int, CFMcParticles, "_1"); //! Index to prong 2 CFMcParticle +DECLARE_SOA_INDEX_COLUMN_FULL(CFParticleDaugh0, cfParticleDaugh0, int, CFMcParticles, "_0"); //! Index to prong 1 CFMcParticle; o2-linter: disable=name/o2-column (preserve the established derived-table API) +DECLARE_SOA_INDEX_COLUMN_FULL(CFParticleDaugh1, cfParticleDaugh1, int, CFMcParticles, "_1"); //! Index to prong 2 CFMcParticle; o2-linter: disable=name/o2-column (preserve the established derived-table API) DECLARE_SOA_COLUMN(Decay, decay, uint8_t); //! Particle decay and flags DECLARE_SOA_DYNAMIC_COLUMN(McDecay, mcDecay, [](uint8_t decay) -> uint8_t { return decay & 0x3f; }); //! MC particle decay enum ParticleDecayFlags { diff --git a/PWGCF/EbyEFluctuations/Tasks/CMakeLists.txt b/PWGCF/EbyEFluctuations/Tasks/CMakeLists.txt index 25d872112b4..2ca1ae99968 100644 --- a/PWGCF/EbyEFluctuations/Tasks/CMakeLists.txt +++ b/PWGCF/EbyEFluctuations/Tasks/CMakeLists.txt @@ -10,7 +10,7 @@ # or submit itself to any jurisdiction. o2physics_add_dpl_workflow(meanpt-fluctuations - SOURCES MeanptFluctuations.cxx + SOURCES meanptFluctuations.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) @@ -88,3 +88,9 @@ o2physics_add_dpl_workflow(strongly-intensive-corr SOURCES stronglyIntensiveCorr.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(mult-and-pt-fluctuations + SOURCES multAndPtFluctuations.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) + diff --git a/PWGCF/EbyEFluctuations/Tasks/meanPtFlucId.cxx b/PWGCF/EbyEFluctuations/Tasks/meanPtFlucId.cxx index 7665f440bdb..7f4432ae05e 100644 --- a/PWGCF/EbyEFluctuations/Tasks/meanPtFlucId.cxx +++ b/PWGCF/EbyEFluctuations/Tasks/meanPtFlucId.cxx @@ -24,6 +24,7 @@ #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" +#include #include #include #include @@ -37,10 +38,15 @@ #include #include +#include +#include #include +#include #include +#include #include +#include #include #include #include @@ -53,34 +59,37 @@ using namespace std; struct MeanPtFlucId { Configurable nPBins{"nPBins", 300, ""}; - Configurable nPartBins{"nPartBins", 100, ""}; Configurable nPhiBins{"nPhiBins", 100, ""}; + Configurable nPtBins{"nPtBins", 50, "Number of pT bins"}; Configurable cfgCutPtMax{"cfgCutPtMax", 2.0, "maximum pT"}; Configurable cfgCutPtMin{"cfgCutPtMin", 0.2, "minimum pT"}; Configurable cfgCutEta{"cfgCutEta", 0.8, "Eta cut"}; - Configurable cfgCutDcaZ{"cfgCutDcaZ", 0.15, "DCAz cut"}; + Configurable cfgDcaPtDepOffset{"cfgDcaPtDepOffset", 0.004, "Offset of the pT-dependent DCA cut (cm)"}; + Configurable cfgDcaPtDepScale{"cfgDcaPtDepScale", 0.013, "1/pT coefficient of the pT-dependent DCA cut (cm GeV/c)"}; Configurable cfgCutPosZ{"cfgCutPosZ", 7.0, "cut for vertex Z"}; Configurable cfgPosZ{"cfgPosZ", true, "Position Z"}; Configurable cfgCutNSig2{"cfgCutNSig2", 2.0, "nSigma cut: 2"}; Configurable cfgCutNSig3{"cfgCutNSig3", 3.0, "nSigma cut: 3"}; Configurable cfgCutNSig5{"cfgCutNSig5", 5.0, "nSigma cut: 5"}; - Configurable cfgSelCutNSigPi{"cfgSelCutNSigPi", 2.0, "nSigma cut for pion selection"}; - Configurable cfgSelCutNSigKa{"cfgSelCutNSigKa", 3.0, "nSigma cut for kaon selection"}; - Configurable cfgSelCutNSigPr{"cfgSelCutNSigPr", 2.0, "nSigma cut for proton selection"}; + Configurable cfgCutNSigTpcTof{"cfgCutNSigTpcTof", 3.0, "nSigma TPC cut when TPC + TOF "}; + Configurable cfgSelCutNSigTpcPi{"cfgSelCutNSigTpcPi", 2.0, "nSigma TPC cut for pion selection"}; + Configurable cfgSelCutNSigTpcKa{"cfgSelCutNSigTpcKa", 2.0, "nSigma TPC cut for kaon selection"}; + Configurable cfgSelCutNSigTpcPr{"cfgSelCutNSigTpcPr", 2.0, "nSigma TPC cut for proton selection"}; + Configurable cfgSelCutNSigTofPi{"cfgSelCutNSigTofPi", 2.0, "nSigma TOF cut for pion selection"}; + Configurable cfgSelCutNSigTofKa{"cfgSelCutNSigTofKa", 2.0, "nSigma TOF cut for kaon selection"}; + Configurable cfgSelCutNSigTofPr{"cfgSelCutNSigTofPr", 2.0, "nSigma TOF cut for proton selection"}; Configurable cfgCutPiPtMin{"cfgCutPiPtMin", 0.2, "Minimum pion p_{T} cut"}; Configurable cfgCutKaPtMin{"cfgCutKaPtMin", 0.3, "Minimum kaon p_{T} cut"}; Configurable cfgCutPrPtMin{"cfgCutPrPtMin", 0.5, "Minimum proton p_{T} cut"}; - Configurable cfgCutPiThrsldP{"cfgCutPiThrsldP", 0.6, "Threshold p cut pion"}; - Configurable cfgCutKaThrsldP{"cfgCutKaThrsldP", 0.6, "Threshold p cut kaon"}; - Configurable cfgCutPrThrsldP{"cfgCutPrThrsldP", 1.0, "Threshold p cut proton "}; + Configurable cfgCutPiThrsldP{"cfgCutPiThrsldP", 0.7, "Momentum threshold for requiring pion TOF PID"}; + Configurable cfgCutKaThrsldP{"cfgCutKaThrsldP", 0.8, "Momentum threshold for requiring kaon TOF PID"}; + Configurable cfgCutPrThrsldP{"cfgCutPrThrsldP", 0.8, "Momentum threshold for requiring proton TOF PID"}; Configurable cfgP0U{"cfgP0U", 6.36269, "p_{0} for upper cut for N_{TPC} vs N{sim}"}; Configurable cfgP1U{"cfgP1U", 2.22108, "p_{1} for upper cut for N_{TPC} vs N{sim}"}; Configurable cfgP2U{"cfgP2U", -0.0118451, "p_{2} for upper cut for N_{TPC} vs N{sim}"}; Configurable cfgP0L{"cfgP0L", 23.8213, "p_{0} for lower cut for N_{TPC} vs N{sim}"}; Configurable cfgP1L{"cfgP1L", -0.402328, "p_{1} for lower cut for N_{TPC} vs N{sim}"}; Configurable cfgP2L{"cfgP2L", 0.0128423, "p_{2} for lower cut for N_{TPC} vs N{sim}"}; - Configurable cfgP0L1{"cfgP0L1", -10.5149, "p_{0} for lower cut for N_{TPC} vs N{sim}"}; - Configurable cfgP1L1{"cfgP1L1", 0.936596, "p_{1} for lower cut for N_{TPC} vs N{sim}"}; Configurable cfgP0corr{"cfgP0corr", 0.0001, "p_{0} for corrected N_{TPC} "}; Configurable cfgP1corr{"cfgP1corr", 0.0001, "p_{1} for corrected N_{TPC} "}; Configurable cfgP2corr{"cfgP2corr", 0.0001, "p_{2} for corrected N_{TPC} "}; @@ -92,25 +101,32 @@ struct MeanPtFlucId { Configurable cfgIsGoodZvtxFT0vsPV{"cfgIsGoodZvtxFT0vsPV", true, "kIsGoodZvtxFT0vsPV"}; Configurable cfgRejTrk{"cfgRejTrk", true, "Rejected Tracks"}; Configurable cfgNtpcEventCut{"cfgNtpcEventCut", true, "N_{TPC} Event Cut for reco"}; + Configurable cfgApplyEfficiencyCorrection{"cfgApplyEfficiencyCorrection", false, "Apply measured track-by-track efficiency weights"}; + Configurable cfgUseCombinedPurityEfficiencyWeight{"cfgUseCombinedPurityEfficiencyWeight", false, "Use the legacy Ngen/Nselected weight instead of the efficiency-only 1/epsilon weight"}; + Configurable cfgEfficiencyCCDBUrl{"cfgEfficiencyCCDBUrl", "http://ccdb-test.cern.ch:8080", "Efficiency CCDB URL"}; + Configurable cfgEfficiencyCCDBPath{"cfgEfficiencyCCDBPath", "Users/t/tgahlaut/weightCorr", "CCDB path containing ccdb_object"}; + Configurable cfgEfficiencyTimestamp{"cfgEfficiencyTimestamp", -1, "Efficiency CCDB timestamp; -1 selects the latest object"}; ConfigurableAxis multTPCBins{"multTPCBins", {150, 0, 150}, "TPC Multiplicity bins"}; ConfigurableAxis multMCBins{"multMCBins", {300, 0, 300}, "MC Multiplicity bins"}; ConfigurableAxis multCorrBins{"multCorrBins", {100, 0., 150.}, "Corrected TPC Multiplicity bins"}; ConfigurableAxis multFT0MBins{"multFT0MBins", {1000, 0, 5000}, "Forward Multiplicity bins"}; ConfigurableAxis dcaXYBins{"dcaXYBins", {100, -0.15, 0.15}, "dcaXY bins"}; ConfigurableAxis dcaZBins{"dcaZBins", {500, -1.2, 1.2}, "dcaZ bins"}; - ConfigurableAxis centBins{"centBins", {0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, "Centrality bins"}; + ConfigurableAxis centBins{"centBins", {VARIABLE_WIDTH, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, "Centrality bins"}; Configurable> ptBins{"ptBins", {0.20, 0.25, 0.30, 0.35, 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.05, 1.10, 1.15, 1.20, 1.25, 1.30, 1.35, 1.40, 1.45, 1.50, 1.55, 1.60, 1.65, 1.70, 1.75, 1.80, 1.85, 1.90, 1.95, 2.00}, "p_{T} bins"}; - Configurable> etaBins{"etaBins", {-0.8, -0.75, -0.7, -0.65, -0.6, -0.55, -0.5, -0.45, -0.4, -0.35, -0.3, -0.25, -0.2, -0.15, -0.1, -0.05, 0.0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8}, "#eta bins"}; - - Configurable> ptBinsPi{"ptBinsPi", {0.20, 0.225, 0.25, 0.275, 0.30, 0.325, 0.35, 0.375, 0.40, 0.425, 0.45, 0.475, 0.50, 0.525, 0.55, 0.575, 0.60, 0.70, 0.90, 1.1, 1.3, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, 1.70, 1.75, 1.80, 1.85, 1.90, 1.95, 2.00}, "p_{T} bins for pions"}; - Configurable> ptBinsKa{"ptBinsKa", {0.30, 0.325, 0.35, 0.375, 0.40, 0.425, 0.45, 0.475, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.8, 0.85, 0.90, 0.95, 1.0, 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.70, 1.80, 1.90, 2.00}, "p_{T} bins for kaons"}; - Configurable> ptBinsPr{"ptBinsPr", {0.40, 0.425, 0.45, 0.475, 0.5, 0.525, 0.55, 0.575, 0.60, 0.625, 0.65, 0.675, 0.70, 0.725, 0.75, 0.775, 0.80, 0.825, 0.85, 0.875, 0.90, 0.925, 0.95, 1.0, 1.025, 1.05, 1.075, 1.1, 1.15, 1.2, 1.4, 1.6, 1.8, 2.0}, "p_{T} bins for protons"}; + Configurable> etaBins{"etaBins", {-0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8}, "#eta bins"}; Service pdg{}; + Service ccdb{}; HistogramRegistry hist{"hist", {}, OutputObjHandlingPolicy::AnalysisObject}; + TH3* efficiencyWeightCh = nullptr; + TH3* efficiencyWeightPi = nullptr; + TH3* efficiencyWeightKa = nullptr; + TH3* efficiencyWeightPr = nullptr; + enum CollisionLabels { kTotCol = 1, kPassSelCol @@ -154,7 +170,7 @@ struct MeanPtFlucId { Gen_Proton }; - static constexpr std::array Dire{ + static constexpr std::array Directories{ "QA/after/", "QA/Pion/", "QA/Kaon/", @@ -167,10 +183,34 @@ struct MeanPtFlucId { "Gen/Pion/", "Gen/Kaon/", "Gen/Proton/"}; + static constexpr auto const& dire = Directories; + + enum CorrectedMode { + Corrected_Charged = 0, + Corrected_Pion, + Corrected_Kaon, + Corrected_Proton + }; + + static constexpr std::array CorrectedDirectories{ + "Corrected/Charged/", + "Corrected/Pion/", + "Corrected/Kaon/", + "Corrected/Proton/"}; + + static constexpr std::array TruthMatchedCorrectedDirectories{ + "CorrectedTruthMatched/Charged/", + "CorrectedTruthMatched/Pion/", + "CorrectedTruthMatched/Kaon/", + "CorrectedTruthMatched/Proton/"}; struct TrackInfo { double pt; - double eta; + }; + + struct WeightedTrackInfo { + double pt; + double weight; }; std::vector chargedTracks; @@ -183,19 +223,85 @@ struct MeanPtFlucId { std::vector kaonTracksGen; std::vector protonTracksGen; + std::vector chargedTracksCorrected; + std::vector pionTracksCorrected; + std::vector kaonTracksCorrected; + std::vector protonTracksCorrected; + std::vector chargedTracksTruthMatchedCorrected; + std::vector pionTracksTruthMatchedCorrected; + std::vector kaonTracksTruthMatchedCorrected; + std::vector protonTracksTruthMatchedCorrected; + + // Reused event-wise storage for the factorial-moment matrices. + std::vector matrixNInBin; + std::vector matrixOccupiedBins; + std::vector matrixWInBin; + std::vector matrixW2InBin; + void init(InitContext const&) { - const int nEta = etaBins->size() - 1; - const int nPtCh = ptBins->size() - 1; - const int nPtPi = ptBinsPi->size() - 1; - const int nPtKa = ptBinsKa->size() - 1; - const int nPtPr = ptBinsPr->size() - 1; + if (nPtBins <= 0 || cfgCutPtMin >= cfgCutPtMax || cfgCutPiPtMin >= cfgCutPtMax || + cfgCutKaPtMin >= cfgCutPtMax || cfgCutPrPtMin >= cfgCutPtMax) { + LOGF(fatal, "Invalid pT matrix binning: nPtBins=%d, max=%g, minima=(%g,%g,%g,%g)", + static_cast(nPtBins), static_cast(cfgCutPtMax), + static_cast(cfgCutPtMin), static_cast(cfgCutPiPtMin), + static_cast(cfgCutKaPtMin), static_cast(cfgCutPrPtMin)); + } - const AxisSpec axisKCh{nEta * nPtCh, 0, static_cast(nEta * nPtCh), "k_{ch}"}; - const AxisSpec axisKPi{nEta * nPtPi, 0, static_cast(nEta * nPtPi), "k_{#pi}"}; - const AxisSpec axisKKa{nEta * nPtKa, 0, static_cast(nEta * nPtKa), "k_{K}"}; - const AxisSpec axisKPr{nEta * nPtPr, 0, static_cast(nEta * nPtPr), "k_{p}"}; + if (cfgApplyEfficiencyCorrection) { + ccdb->setURL(cfgEfficiencyCCDBUrl.value); + ccdb->setCaching(true); + auto* efficiencyList = ccdb->getForTimeStamp(cfgEfficiencyCCDBPath.value, cfgEfficiencyTimestamp.value); + if (!efficiencyList) { + LOGF(fatal, "Cannot load ccdb_object containing the efficiency maps"); + } + + const char* chargedMapName = cfgUseCombinedPurityEfficiencyWeight ? "hWeightPtEtaCent" : "hInverseEfficiencyPtEtaCent"; + const char* pionMapName = cfgUseCombinedPurityEfficiencyWeight ? "hWeightPtEtaCentPi" : "hInverseEfficiencyPtEtaCentPi"; + const char* kaonMapName = cfgUseCombinedPurityEfficiencyWeight ? "hWeightPtEtaCentKa" : "hInverseEfficiencyPtEtaCentKa"; + const char* protonMapName = cfgUseCombinedPurityEfficiencyWeight ? "hWeightPtEtaCentPr" : "hInverseEfficiencyPtEtaCentPr"; + efficiencyWeightCh = dynamic_cast(efficiencyList->FindObject(chargedMapName)); + efficiencyWeightPi = dynamic_cast(efficiencyList->FindObject(pionMapName)); + efficiencyWeightKa = dynamic_cast(efficiencyList->FindObject(kaonMapName)); + efficiencyWeightPr = dynamic_cast(efficiencyList->FindObject(protonMapName)); + if (!efficiencyWeightCh || !efficiencyWeightPi || !efficiencyWeightKa || !efficiencyWeightPr) { + LOGF(fatal, "Missing efficiency map(s): charged=%s, pion=%s, kaon=%s, proton=%s", + chargedMapName, pionMapName, kaonMapName, protonMapName); + } + + auto validateEfficiencyMap = [&](const TH3* map, const char* name, double minPt) { + constexpr double AxisTolerance = 1.e-6; + constexpr double MaximumCentrality = 100.; + const bool coversEta = map->GetXaxis()->GetXmin() <= -cfgCutEta + AxisTolerance && + map->GetXaxis()->GetXmax() >= cfgCutEta - AxisTolerance; + const bool coversPt = map->GetYaxis()->GetXmin() <= minPt + AxisTolerance && + map->GetYaxis()->GetXmax() >= cfgCutPtMax - AxisTolerance; + const bool coversCentrality = map->GetZaxis()->GetXmin() <= AxisTolerance && + map->GetZaxis()->GetXmax() >= MaximumCentrality - AxisTolerance; + if (!coversEta || !coversPt || !coversCentrality) { + LOGF(fatal, + "Efficiency map %s does not cover the analysis phase space: " + "eta=[%g,%g], pT=[%g,%g], centrality=[%g,%g]. " + "Expected eta=[%g,%g], pT=[%g,%g], centrality=[0,100].", + name, + map->GetXaxis()->GetXmin(), map->GetXaxis()->GetXmax(), + map->GetYaxis()->GetXmin(), map->GetYaxis()->GetXmax(), + map->GetZaxis()->GetXmin(), map->GetZaxis()->GetXmax(), + -static_cast(cfgCutEta), static_cast(cfgCutEta), + minPt, static_cast(cfgCutPtMax)); + } + }; + validateEfficiencyMap(efficiencyWeightCh, chargedMapName, cfgCutPtMin); + validateEfficiencyMap(efficiencyWeightPi, pionMapName, cfgCutPiPtMin); + validateEfficiencyMap(efficiencyWeightKa, kaonMapName, cfgCutKaPtMin); + validateEfficiencyMap(efficiencyWeightPr, protonMapName, cfgCutPrPtMin); + } + + const AxisSpec axisPtCh{nPtBins, cfgCutPtMin, cfgCutPtMax, "p_{T} (GeV/c)"}; + const AxisSpec axisPtPi{nPtBins, cfgCutPiPtMin, cfgCutPtMax, "p_{T} (GeV/c)"}; + const AxisSpec axisPtKa{nPtBins, cfgCutKaPtMin, cfgCutPtMax, "p_{T} (GeV/c)"}; + const AxisSpec axisPtPr{nPtBins, cfgCutPrPtMin, cfgCutPtMax, "p_{T} (GeV/c)"}; const AxisSpec axisCol{3, 1, 4, ""}; const AxisSpec axisTrack{5, 1, 6, ""}; @@ -204,13 +310,8 @@ struct MeanPtFlucId { const AxisSpec axisPhi{nPhiBins, 0., +7., "#phi (rad)"}; const AxisSpec axisY{100, -0.6, 0.6, "y"}; const AxisSpec axisPt{ptBins, "p_{T} (GeV/c)"}; - const AxisSpec axisPtPi{ptBinsPi, "p_{T} (GeV/c)"}; - const AxisSpec axisPtKa{ptBinsKa, "p_{T}(GeV/c)"}; - const AxisSpec axisPtPr{ptBinsPr, "p_{T} (GeV/c)"}; const AxisSpec axisP{nPBins, 0., 3., "p (GeV/c)"}; const AxisSpec axisInnerParam{nPBins, 0., 3., "p_{InnerParam} (GeV/c)"}; - const AxisSpec axisPart{nPartBins, 0., 18., " "}; - const AxisSpec axisMult{100, 0, 100, "N_{ch}"}; const AxisSpec axisMultTPC{multTPCBins, "N_{TPC} "}; const AxisSpec axisMultCorr{multCorrBins, "N_{Corr} "}; const AxisSpec axisMultMC{multMCBins, "N_{Gen} "}; @@ -229,8 +330,6 @@ struct MeanPtFlucId { const AxisSpec axisM2{100, 0., 1.4, "#it{m}^{2} (GeV/#it{c}^{2})^{2}"}; const AxisSpec axisPid{300, 0, 3000, "PID"}; - HistogramConfigSpec partHistCent({HistType::kTHnSparseD, {axisCentFT0M, axisPart}}); - HistogramConfigSpec partMCHist({HistType::kTHnSparseD, {axisCentFT0M, axisPart}}); HistogramConfigSpec tofNSigmaHist({HistType::kTH2D, {axisP, axisTOFNsigma}}); HistogramConfigSpec tofSignalHist({HistType::kTH2D, {axisP, axisTOFSignal}}); HistogramConfigSpec tpcNSigmaHist({HistType::kTH2D, {axisP, axisTPCNsigma}}); @@ -238,219 +337,226 @@ struct MeanPtFlucId { HistogramConfigSpec tpcTofHist({HistType::kTH2D, {axisTPCNsigma, axisTOFNsigma}}); HistogramConfigSpec pvsM2Hist({HistType::kTH2D, {axisM2, axisP}}); HistogramConfigSpec tpcSignalHist1({HistType::kTH2D, {axisInnerParam, axisTPCSignal}}); - HistogramConfigSpec pvsM2Hist1({HistType::kTH2D, {axisM2, axisInnerParam}}); - - // QA Plots - hist.add("QA/before/h_Counts", "Counts", kTH1D, {axisEvents}); - hist.add("QA/before/h_VtxZ", "V_{Z}", kTH1D, {axisVtxZ}); - hist.add("QA/before/h_NTPC", "N_{TPC}", kTH1D, {axisMultTPC}); - hist.add("QA/before/h_NFT0M", "FT0M Multiplicity", kTH1D, {axisMultFT0M}); - hist.add("QA/before/h_CentM", "FT0M (%)", kTH1D, {axisCentFT0M}); - - hist.add("QA/before/h2_TPCSignal", "TPC Signal", tpcSignalHist); - hist.add("QA/before/h2_TOFSignal", "TOF Signal", tofSignalHist); - hist.add("QA/before/h2_pvsm2", "p vs m^{2}", pvsM2Hist); - - hist.addClone("QA/before/", "QA/after/"); - - hist.add("QA/before/h_Pt", "p_{T}", kTH1D, {axisPt}); - hist.add("QA/before/h_Eta", "#eta ", kTH1D, {axisEta}); - hist.add("QA/before/h_Phi", "#phi ", kTH1D, {axisPhi}); - hist.add("QA/before/h_DcaZ", "DCA_{Z}", kTH1D, {axisDCAz}); - hist.add("QA/before/h_DcaXY", "DCA_{XY}", kTH1D, {axisDCAxy}); - hist.add("QA/before/h2_DcaZ", "DCA_{Z}", kTH2D, {{axisPt}, {axisDCAz}}); - hist.add("QA/before/h2_DcaXY", "DCA_{XY}", kTH2D, {{axisPt}, {axisDCAxy}}); - - hist.add("QA/after/h_Ncorr", "N_{corr}", kTH1D, {axisMultCorr}); - hist.add("QA/after/h_counts_evSelCuts", "Event selection cuts", kTH1D, {axisEvents}); - hist.add("QA/after/h_TPCChi2perCluster", "TPC #Chi^{2}/Cluster", kTH1D, {axisChi2}); - hist.add("QA/after/h_ITSChi2perCluster", "ITS #Chi^{2}/Cluster", kTH1D, {axisChi2}); - hist.add("QA/after/h_crossedTPC", "Crossed TPC", kTH1D, {axisCrossedTPC}); - hist.add("QA/after/h2_NTPC_CentM", "N_{TPC} vs FT0M(%)", kTH2D, {{axisCentFT0M}, {axisMultTPC}}); - hist.add("QA/after/h2_NTPC_NFT0M", "N_{TPC} vs N_{FT0M}", kTH2D, {{axisMultFT0M}, {axisMultTPC}}); - hist.add("QA/after/p_NTPC_NFT0M", "N_{TPC} vs N_{FT0M} (Profile)", kTProfile, {axisMultFT0M}); - hist.add("QA/after/p_NTPC_CentM", "N_{TPC} vs FT0M(%) (Profile)", kTProfile, {axisCentFT0M}); - hist.add("QA/after/h_DCAxy_primary", "DCA_{XY} (Primary)", kTH1D, {axisDCAxy}); - hist.add("QA/after/h_DCAz_primary", "DCA_{Z} (Primary)", kTH1D, {axisDCAz}); - hist.add("QA/after/h_DCAxy_secondary", "DCA_{XY} (Secondary)", kTH1D, {axisDCAxy}); - hist.add("QA/after/h_DCAz_secondary", "DCA_{Z} (Secondary)", kTH1D, {axisDCAz}); - hist.add("QA/after/innerParam/h2_TPCSignal", "TPC Signal", tpcSignalHist1); - hist.add("QA/after/h2_NSim_NTPC", "Reco vs Truth Multiplicty TPC", kTH2D, {{axisMultMC}, {axisMultTPC}}); - hist.add("QA/after/h2_NTPC_NSim", "Truth vs Reco Multiplicty TPC", kTH2D, {{axisMultTPC}, {axisMultMC}}); - hist.add("QA/after/p_NTPC_NSim", "Truth vs Reco Multiplicty TPC", kTProfile, {axisMultTPC}); - hist.add("QA/after/h2_Ncorr_NSim", "Truth vs Corrected Multiplicty TPC", kTH2D, {{axisMultCorr}, {axisMultMC}}); - hist.add("QA/after/h2_Ncorr_CentM", "N_{corr} vs FT0M(%)", kTH2D, {{axisCentFT0M}, {axisMultCorr}}); - - hist.add("QA/Charged/h_Pt", "p_{T}", kTH1D, {axisPt}); - hist.add("QA/Charged/h_Eta", "#eta ", kTH1D, {axisEta}); - hist.add("QA/Charged/h_Phi", "#phi ", kTH1D, {axisPhi}); - hist.add("QA/Charged/h_DcaZ", "DCA_{Z}", kTH1D, {axisDCAz}); - hist.add("QA/Charged/h_DcaXY", "DCA_{XY}", kTH1D, {axisDCAxy}); - hist.add("QA/Charged/h2_Pt_PtMC", "p_{T} vs p_{T} (MC)", kTH2D, {{axisPt}, {axisPt}}); - hist.add("QA/Charged/h2_DcaZ", "DCA_{Z}", kTH2D, {{axisPt}, {axisDCAz}}); - hist.add("QA/Charged/h2_DcaXY", "DCA_{XY}", kTH2D, {{axisPt}, {axisDCAxy}}); - hist.add("QA/Charged/h2_Pt_centFT0M", "p_{T} in centrality Classes ", kTH2D, {{axisCentFT0M}, {axisPt}}); - hist.add("QA/Charged/h3_Pt_Eta_Phi", "p_{T}, #eta, #phi ", kTHnSparseD, {{axisPt}, {axisEta}, {axisPhi}}); - - hist.addClone("QA/Charged/", "QA/Pion/"); - - hist.add("QA/Pion/before/h2_TPCNsigma", "n #sigma_{TPC}", tpcNSigmaHist); - hist.add("QA/Pion/before/h2_TPCNsigma_nottof", "n #sigma_{TPC}", tpcNSigmaHist); - hist.add("QA/Pion/before/h2_TPCNsigma_tof", "n #sigma_{TPC}", tpcNSigmaHist); - hist.add("QA/Pion/before/h2_TOFNsigma", "n #sigma_{TOF}", tofNSigmaHist); - hist.add("QA/Pion/before/h2_TpcTofNsigma", "n #sigma_{TPC} vs n #sigma_{TOF}", tpcTofHist); - hist.add("QA/Pion/h_Rap", "y ", kTH1D, {axisY}); - hist.add("QA/Pion/h2_TPCNsigma", "n #sigma_{TPC}", tpcNSigmaHist); - hist.add("QA/Pion/h2_TOFNsigma", "n #sigma_{TOF}", tofNSigmaHist); - hist.add("QA/Pion/h2_TpcTofNsigma", "n #sigma_{TPC} vs n #sigma_{TOF}", tpcTofHist); - hist.add("QA/Pion/h2_TPCSignal", "TPC Signal ", tpcSignalHist); - hist.add("QA/Pion/h2_TOFSignal", "TOF Signal", tofSignalHist); - hist.add("QA/Pion/innerParam/h2_TPCSignal", "TPC Signal", tpcSignalHist1); - hist.add("QA/Pion/h2_pvsm2", "p vs m^{2}", pvsM2Hist); - hist.addClone("QA/Pion/", "QA/Kaon/"); - hist.addClone("QA/Pion/", "QA/Proton/"); - - hist.add("QA/Charged/h_PtMC", "p_{T} (MC)", kTH1D, {axisPt}); - hist.add("QA/Charged/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPt}}); - hist.add("QA/Charged/h3_Pt_Eta_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPt}, {axisCent}}); - hist.add("QA/Charged/h3_Pt_EtaMC_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPt}, {axisCent}}); - hist.add("QA/Charged/h2_Pt_EtaMC", "p_{T} vs #eta (MC)", kTH2D, {{axisEta}, {axisPt}}); - - hist.add("QA/Pion/h_Pt_e", "p_{T}", kTH1D, {axisPtPi}); - hist.add("QA/Pion/h_PtMC", "p_{T} (MC)", kTH1D, {axisPtPi}); - hist.add("QA/Pion/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPtPi}}); - hist.add("QA/Pion/h3_Pt_Eta_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPi}, {axisCent}}); - hist.add("QA/Pion/h3_Pt_EtaMC_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPi}, {axisCent}}); - hist.add("QA/Pion/h2_Pt_EtaMC", "p_{T} vs #eta (MC)", kTH2D, {{axisEta}, {axisPtPi}}); - hist.add("QA/Pion/h_PtPos", "p_{T} (positive) ", kTH1D, {axisPtPi}); - hist.add("QA/Pion/h_PtNeg", "p_{T} (negative) ", kTH1D, {axisPtPi}); - hist.add("QA/Pion/h_PtTruth", "p_{T} (Truth)", kTH1D, {axisPtPi}); - hist.add("QA/Pion/h_PtPosTruth", "p_{T} (positive) (Truth)", kTH1D, {axisPtPi}); - hist.add("QA/Pion/h_PtNegTruth", "p_{T} (negative) (Truth) ", kTH1D, {axisPtPi}); - hist.add("QA/Pion/h_PtTruth_primary", "p_{T} (Truth Primary)", kTH1D, {axisPtPi}); - hist.add("QA/Pion/h_PtTruth_secondary", "p_{T} (Truth Secondary)", kTH1D, {axisPtPi}); - hist.add("QA/Pion/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPtPi}}); - - hist.add("QA/Kaon/h_Pt_e", "p_{T}", kTH1D, {axisPtKa}); - hist.add("QA/Kaon/h_PtMC", "p_{T} (MC)", kTH1D, {axisPtKa}); - hist.add("QA/Kaon/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPtKa}}); - hist.add("QA/Kaon/h3_Pt_Eta_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtKa}, {axisCent}}); - hist.add("QA/Kaon/h3_Pt_EtaMC_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtKa}, {axisCent}}); - hist.add("QA/Kaon/h2_Pt_EtaMC", "p_{T} vs #eta (MC)", kTH2D, {{axisEta}, {axisPtKa}}); - hist.add("QA/Kaon/h_PtPos", "p_{T} (positive) ", kTH1D, {axisPtKa}); - hist.add("QA/Kaon/h_PtNeg", "p_{T} (negative) ", kTH1D, {axisPtKa}); - hist.add("QA/Kaon/h_PtTruth", "p_{T} (Truth)", kTH1D, {axisPtKa}); - hist.add("QA/Kaon/h_PtPosTruth", "p_{T} (positive) (Truth)", kTH1D, {axisPtKa}); - hist.add("QA/Kaon/h_PtNegTruth", "p_{T} (negative) (Truth) ", kTH1D, {axisPtKa}); - hist.add("QA/Kaon/h_PtTruth_primary", "p_{T} (Truth Primary)", kTH1D, {axisPtKa}); - hist.add("QA/Kaon/h_PtTruth_secondary", "p_{T} (Truth Secondary)", kTH1D, {axisPtKa}); - hist.add("QA/Kaon/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPtKa}}); - - hist.add("QA/Proton/h_Pt_e", "p_{T}", kTH1D, {axisPtPr}); - hist.add("QA/Proton/h_PtMC", "p_{T} (MC)", kTH1D, {axisPtPr}); - hist.add("QA/Proton/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPtPr}}); - hist.add("QA/Proton/h3_Pt_Eta_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPr}, {axisCent}}); - hist.add("QA/Proton/h3_Pt_EtaMC_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPr}, {axisCent}}); - hist.add("QA/Proton/h2_Pt_EtaMC", "p_{T} vs #eta (MC)", kTH2D, {{axisEta}, {axisPtPr}}); - hist.add("QA/Proton/h_PtPos", "p_{T} (positive) ", kTH1D, {axisPtPr}); - hist.add("QA/Proton/h_PtNeg", "p_{T} (negative) ", kTH1D, {axisPtPr}); - hist.add("QA/Proton/h_PtTruth", "p_{T} (Truth)", kTH1D, {axisPtPr}); - hist.add("QA/Proton/h_PtPosTruth", "p_{T} (positive) (Truth)", kTH1D, {axisPtPr}); - hist.add("QA/Proton/h_PtNegTruth", "p_{T} (negative) (Truth) ", kTH1D, {axisPtPr}); - hist.add("QA/Proton/h_PtTruth_primary", "p_{T} (Truth Primary)", kTH1D, {axisPtPr}); - hist.add("QA/Proton/h_PtTruth_secondary", "p_{T} (Truth Secondary)", kTH1D, {axisPtPr}); - hist.add("QA/Proton/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPtPr}}); - - // AnalysisPlots - hist.add("Analysis/Charged/h_mult", "Multiplicity", kTH1D, {axisMult}); - hist.add("Analysis/Charged/p_Q1_Mult", " Q1 vs Mult ", kTProfile, {axisMultTPC}); - hist.add("Analysis/Charged/p_Q2_Mult", " Q2 vs Mult ", kTProfile, {axisMultTPC}); - hist.add("Analysis/Charged/p_mean_pT_Mult", " vs Mult ", kTProfile, {axisMultTPC}); - hist.add("Analysis/Charged/p_mean_pT_Cent", " vs CentFT0M ", kTProfile, {axisCentFT0M}); - hist.add("Analysis/Charged/p_mean_pT_Cent_var", " vs CentFT0M ", kTProfile, {axisCentFT0M}); - hist.add("Analysis/Charged/p_twopart_Cent_var", "Twopart vs CentFT0M ", kTProfile, {axisCentFT0M}); - hist.add("Analysis/Charged/h_mean_pT_Cent", " vs CentFT0M ", kTH1D, {axisCentFT0M}); - hist.add("Analysis/Charged/h_mean_pT_Cent_var", " vs CentFT0M ", kTH1D, {axisCentFT0M}); - hist.add("Analysis/Charged/h_twopart_Cent_var", "Twopart vs CentFT0M ", kTH1D, {axisCentFT0M}); - hist.add("Analysis/Charged/p_mean_pT_Num_Cent_var", " Numerator vs CentFT0M ", kTProfile, {axisCentFT0M}); - hist.add("Analysis/Charged/p_mean_pT_Den_Cent_var", " Denominator vs CentFT0M ", kTProfile, {axisCentFT0M}); - hist.add("Analysis/Charged/p_twopart_Num_Cent_var", "Twopart Numerator vs CentFT0M ", kTProfile, {axisCentFT0M}); - hist.add("Analysis/Charged/p_twopart_Den_Cent_var", "Twopart Denominator vs CentFT0M ", kTProfile, {axisCentFT0M}); - hist.add("Analysis/Charged/h_mean_pT_Num_Cent_var", " Numerator vs CentFT0M ", kTH1D, {axisCentFT0M}); - hist.add("Analysis/Charged/h_mean_pT_Den_Cent_var", " Denominator vs CentFT0M ", kTH1D, {axisCentFT0M}); - hist.add("Analysis/Charged/h_twopart_Num_Cent_var", "Twopart Numerator vs CentFT0M ", kTH1D, {axisCentFT0M}); - hist.add("Analysis/Charged/h_twopart_Den_Cent_var", "Twopart Denominator vs CentFT0M ", kTH1D, {axisCentFT0M}); - - hist.addClone("Analysis/Charged/", "Analysis/Pion/"); - hist.addClone("Analysis/Charged/", "Analysis/Kaon/"); - hist.addClone("Analysis/Charged/", "Analysis/Proton/"); - - hist.add("Analysis/Charged/hN1Matrix", "", kTH2D, {{axisCent}, {axisKCh}}); - hist.add("Analysis/Charged/hPt1Matrix", "", kTH2D, {{axisCent}, {axisKCh}}); - hist.add("Analysis/Charged/hN2Matrix", "", kTH3D, {{axisCent}, {axisKCh}, {axisKCh}}); - hist.add("Analysis/Charged/hPtPtMatrix", "", kTH3D, {{axisCent}, {axisKCh}, {axisKCh}}); - - hist.add("Analysis/Pion/hN1Matrix", "", kTH2D, {{axisCent}, {axisKPi}}); - hist.add("Analysis/Pion/hPt1Matrix", "", kTH2D, {{axisCent}, {axisKPi}}); - hist.add("Analysis/Pion/hN2Matrix", "", kTH3D, {{axisCent}, {axisKPi}, {axisKPi}}); - hist.add("Analysis/Pion/hPtPtMatrix", "", kTH3D, {{axisCent}, {axisKPi}, {axisKPi}}); - - hist.add("Analysis/Kaon/hN1Matrix", "", kTH2D, {{axisCent}, {axisKKa}}); - hist.add("Analysis/Kaon/hPt1Matrix", "", kTH2D, {{axisCent}, {axisKKa}}); - hist.add("Analysis/Kaon/hN2Matrix", "", kTH3D, {{axisCent}, {axisKKa}, {axisKKa}}); - hist.add("Analysis/Kaon/hPtPtMatrix", "", kTH3D, {{axisCent}, {axisKKa}, {axisKKa}}); - - hist.add("Analysis/Proton/hN1Matrix", "", kTH2D, {{axisCent}, {axisKPr}}); - hist.add("Analysis/Proton/hPt1Matrix", "", kTH2D, {{axisCent}, {axisKPr}}); - hist.add("Analysis/Proton/hN2Matrix", "", kTH3D, {{axisCent}, {axisKPr}, {axisKPr}}); - hist.add("Analysis/Proton/hPtPtMatrix", "", kTH3D, {{axisCent}, {axisKPr}, {axisKPr}}); - - // MC Generated - hist.add("Gen/h_Counts", "Counts", kTH1D, {axisEvents}); - hist.add("Gen/h_VtxZ", "Vertex Z ", kTH1D, {axisVtxZ}); - hist.add("Gen/h_VtxZ_b", "Vertex Z ", kTH1D, {axisVtxZ}); - hist.add("Gen/h_NSim", "Truth Multiplicity TPC", kTH1D, {axisMultMC}); - hist.add("Gen/h2_NSim_NTPC", "Reco vs Truth Multiplicty TPC", kTH2D, {{axisMultMC}, {axisMultTPC}}); - hist.add("Gen/h2_NTPC_NSim", "Truth vs Reco Multiplicty TPC", kTH2D, {{axisMultTPC}, {axisMultMC}}); - - hist.add("Gen/Charged/h_EtaTruth", "#eta ", kTH1D, {axisEta}); - hist.add("Gen/Charged/h_PhiTruth", "#phi ", kTH1D, {axisPhi}); - hist.add("Gen/Charged/h2_PtTruth_centFT0M", "p_{T} in centrality Classes ", kTH2D, {{axisCentFT0M}, {axisPt}}); - hist.add("Gen/Charged/h3_Pt_Eta_PhiTruth", "p_{T}, #eta, #phi ", kTHnSparseD, {{axisPt}, {axisEta}, {axisPhi}}); - - hist.addClone("Gen/Charged/", "Gen/Pion/"); - - hist.add("Gen/Pion/h_RapTruth", "y", kTH1D, {axisY}); - - hist.addClone("Gen/Pion/", "Gen/Kaon/"); - hist.addClone("Gen/Pion/", "Gen/Proton/"); - - hist.addClone("Analysis/Charged/", "Gen/Charged/"); - hist.addClone("Analysis/Pion/", "Gen/Pion/"); - hist.addClone("Analysis/Kaon/", "Gen/Kaon/"); - hist.addClone("Analysis/Proton/", "Gen/Proton/"); - - hist.add("Gen/Charged/h_PtTruth", "p_{T} ", kTH1D, {axisPt}); - hist.add("Gen/Charged/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPt}}); - hist.add("Gen/Charged/h3_Pt_EtaTruth_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPt}, {axisCent}}); - - hist.add("Gen/Pion/h_PtTruth", "p_{T} ", kTH1D, {axisPtPi}); - hist.add("Gen/Pion/h_PtPosTruth", "p_{T} (positive) ", kTH1D, {axisPtPi}); - hist.add("Gen/Pion/h_PtNegTruth", "p_{T} (negative) ", kTH1D, {axisPtPi}); - hist.add("Gen/Pion/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPtPi}}); - hist.add("Gen/Pion/h3_Pt_EtaTruth_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPi}, {axisCent}}); - - hist.add("Gen/Kaon/h_PtTruth", "p_{T} ", kTH1D, {axisPtKa}); - hist.add("Gen/Kaon/h_PtPosTruth", "p_{T} (positive) ", kTH1D, {axisPtKa}); - hist.add("Gen/Kaon/h_PtNegTruth", "p_{T} (negative) ", kTH1D, {axisPtKa}); - hist.add("Gen/Kaon/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPtKa}}); - hist.add("Gen/Kaon/h3_Pt_EtaTruth_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtKa}, {axisCent}}); - - hist.add("Gen/Proton/h_PtTruth", "p_{T} ", kTH1D, {axisPtPr}); - hist.add("Gen/Proton/h_PtPosTruth", "p_{T} (positive) ", kTH1D, {axisPtPr}); - hist.add("Gen/Proton/h_PtNegTruth", "p_{T} (negative) ", kTH1D, {axisPtPr}); - hist.add("Gen/Proton/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPtPr}}); - hist.add("Gen/Proton/h3_Pt_EtaTruth_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPr}, {axisCent}}); + + auto addEventQAHistograms = [&]() { + // Event QA plots + hist.add("QA/before/h_Counts", "Counts", kTH1D, {axisEvents}); + hist.add("QA/before/h_VtxZ", "V_{Z}", kTH1D, {axisVtxZ}); + hist.add("QA/before/h_NTPC", "N_{TPC}", kTH1D, {axisMultTPC}); + hist.add("QA/before/h_NFT0M", "FT0M Multiplicity", kTH1D, {axisMultFT0M}); + hist.add("QA/before/h_CentM", "FT0M (%)", kTH1D, {axisCentFT0M}); + + hist.add("QA/before/h2_TPCSignal", "TPC Signal", tpcSignalHist); + hist.add("QA/before/h2_TOFSignal", "TOF Signal", tofSignalHist); + hist.add("QA/before/h2_pvsm2", "p vs m^{2}", pvsM2Hist); + + hist.addClone("QA/before/", "QA/after/"); + + hist.add("QA/before/h_Pt", "p_{T}", kTH1D, {axisPt}); + hist.add("QA/before/h_Eta", "#eta ", kTH1D, {axisEta}); + hist.add("QA/before/h_Phi", "#phi ", kTH1D, {axisPhi}); + hist.add("QA/before/h_DcaZ", "DCA_{Z}", kTH1D, {axisDCAz}); + hist.add("QA/before/h_DcaXY", "DCA_{XY}", kTH1D, {axisDCAxy}); + hist.add("QA/before/h2_DcaZ", "DCA_{Z}", kTH2D, {{axisPt}, {axisDCAz}}); + hist.add("QA/before/h2_DcaXY", "DCA_{XY}", kTH2D, {{axisPt}, {axisDCAxy}}); + + hist.add("QA/after/h_Ncorr", "N_{corr}", kTH1D, {axisMultCorr}); + hist.add("QA/after/h_counts_evSelCuts", "Event selection cuts", kTH1D, {axisEvents}); + hist.add("QA/after/h_TPCChi2perCluster", "TPC #Chi^{2}/Cluster", kTH1D, {axisChi2}); + hist.add("QA/after/h_ITSChi2perCluster", "ITS #Chi^{2}/Cluster", kTH1D, {axisChi2}); + hist.add("QA/after/h_crossedTPC", "Crossed TPC", kTH1D, {axisCrossedTPC}); + hist.add("QA/after/h2_NTPC_CentM", "N_{TPC} vs FT0M(%)", kTH2D, {{axisCentFT0M}, {axisMultTPC}}); + hist.add("QA/after/h2_NTPC_NFT0M", "N_{TPC} vs N_{FT0M}", kTH2D, {{axisMultFT0M}, {axisMultTPC}}); + hist.add("QA/after/p_NTPC_NFT0M", "N_{TPC} vs N_{FT0M} (Profile)", kTProfile, {axisMultFT0M}); + hist.add("QA/after/p_NTPC_CentM", "N_{TPC} vs FT0M(%) (Profile)", kTProfile, {axisCentFT0M}); + hist.add("QA/after/h_DCAxy_primary", "DCA_{XY} (Primary)", kTH1D, {axisDCAxy}); + hist.add("QA/after/h_DCAz_primary", "DCA_{Z} (Primary)", kTH1D, {axisDCAz}); + hist.add("QA/after/h_DCAxy_secondary", "DCA_{XY} (Secondary)", kTH1D, {axisDCAxy}); + hist.add("QA/after/h_DCAz_secondary", "DCA_{Z} (Secondary)", kTH1D, {axisDCAz}); + hist.add("QA/after/innerParam/h2_TPCSignal", "TPC Signal", tpcSignalHist1); + hist.add("QA/after/h2_NSim_NTPC", "Reco vs Truth Multiplicty TPC", kTH2D, {{axisMultMC}, {axisMultTPC}}); + hist.add("QA/after/h2_NTPC_NSim", "Truth vs Reco Multiplicty TPC", kTH2D, {{axisMultTPC}, {axisMultMC}}); + hist.add("QA/after/p_NTPC_NSim", "Truth vs Reco Multiplicty TPC", kTProfile, {axisMultTPC}); + hist.add("QA/after/h2_Ncorr_NSim", "Truth vs Corrected Multiplicty TPC", kTH2D, {{axisMultCorr}, {axisMultMC}}); + hist.add("QA/after/h2_Ncorr_CentM", "N_{corr} vs FT0M(%)", kTH2D, {{axisCentFT0M}, {axisMultCorr}}); + }; + addEventQAHistograms(); + + auto addTrackQAHistograms = [&]() { + hist.add("QA/Charged/h_Pt", "p_{T}", kTH1D, {axisPt}); + hist.add("QA/Charged/h_Eta", "#eta ", kTH1D, {axisEta}); + hist.add("QA/Charged/h_Phi", "#phi ", kTH1D, {axisPhi}); + hist.add("QA/Charged/h_DcaZ", "DCA_{Z}", kTH1D, {axisDCAz}); + hist.add("QA/Charged/h_DcaXY", "DCA_{XY}", kTH1D, {axisDCAxy}); + hist.add("QA/Charged/h2_Pt_PtMC", "p_{T} vs p_{T} (MC)", kTH2D, {{axisPt}, {axisPt}}); + hist.add("QA/Charged/h2_DcaZ", "DCA_{Z}", kTH2D, {{axisPt}, {axisDCAz}}); + hist.add("QA/Charged/h2_DcaXY", "DCA_{XY}", kTH2D, {{axisPt}, {axisDCAxy}}); + hist.add("QA/Charged/h2_Pt_centFT0M", "p_{T} in centrality Classes ", kTH2D, {{axisCentFT0M}, {axisPt}}); + hist.add("QA/Charged/h3_Pt_Eta_Phi", "p_{T}, #eta, #phi ", kTHnSparseD, {{axisPt}, {axisEta}, {axisPhi}}); + + hist.addClone("QA/Charged/", "QA/Pion/"); + + hist.add("QA/Pion/before/h2_TPCNsigma", "n #sigma_{TPC}", tpcNSigmaHist); + hist.add("QA/Pion/before/h2_TPCNsigma_nottof", "n #sigma_{TPC}", tpcNSigmaHist); + hist.add("QA/Pion/before/h2_TPCNsigma_tof", "n #sigma_{TPC}", tpcNSigmaHist); + hist.add("QA/Pion/before/h2_TOFNsigma", "n #sigma_{TOF}", tofNSigmaHist); + hist.add("QA/Pion/before/h2_TpcTofNsigma", "n #sigma_{TPC} vs n #sigma_{TOF}", tpcTofHist); + hist.add("QA/Pion/h_Rap", "y ", kTH1D, {axisY}); + hist.add("QA/Pion/h2_TPCNsigma", "n #sigma_{TPC}", tpcNSigmaHist); + hist.add("QA/Pion/h2_TOFNsigma", "n #sigma_{TOF}", tofNSigmaHist); + hist.add("QA/Pion/h2_TpcTofNsigma", "n #sigma_{TPC} vs n #sigma_{TOF}", tpcTofHist); + hist.add("QA/Pion/h2_TPCSignal", "TPC Signal ", tpcSignalHist); + hist.add("QA/Pion/h2_TOFSignal", "TOF Signal", tofSignalHist); + hist.add("QA/Pion/innerParam/h2_TPCSignal", "TPC Signal", tpcSignalHist1); + hist.add("QA/Pion/h2_pvsm2", "p vs m^{2}", pvsM2Hist); + hist.addClone("QA/Pion/", "QA/Kaon/"); + hist.addClone("QA/Pion/", "QA/Proton/"); + + hist.add("QA/Charged/h_Pt_e", "p_{T}", kTH1D, {axisPtCh}); + hist.add("QA/Charged/h_PtMC", "p_{T} (MC)", kTH1D, {axisPtCh}); + hist.add("QA/Charged/h_PtTruth_primary", "p_{T} (Truth Primary)", kTH1D, {axisPtCh}); + hist.add("QA/Charged/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPtCh}}); + hist.add("QA/Charged/h3_Pt_Eta_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtCh}, {axisCent}}); + hist.add("QA/Charged/h3_Pt_EtaMC_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtCh}, {axisCent}}); + hist.add("QA/Charged/h3_Pt_EtaMC_primary_centFT0M", "Selected primary MC particles;#eta_{MC};p_{T,MC};FT0M (%)", kTH3D, {{axisEta}, {axisPtCh}, {axisCent}}); + hist.add("QA/Charged/h2_Pt_EtaMC", "p_{T} vs #eta (MC)", kTH2D, {{axisEta}, {axisPtCh}}); + }; + addTrackQAHistograms(); + + auto addEfficiencyHistograms = [&]() { + hist.add("QA/Pion/h_Pt_e", "p_{T}", kTH1D, {axisPtPi}); + hist.add("QA/Pion/h_PtMC", "p_{T} (MC)", kTH1D, {axisPtPi}); + hist.add("QA/Pion/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPtPi}}); + hist.add("QA/Pion/h3_Pt_Eta_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPi}, {axisCent}}); + hist.add("QA/Pion/h3_Pt_EtaMC_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPi}, {axisCent}}); + hist.add("QA/Pion/h3_Pt_EtaMC_primary_centFT0M", "Correctly selected primary pions;#eta_{MC};p_{T,MC};FT0M (%)", kTH3D, {{axisEta}, {axisPtPi}, {axisCent}}); + hist.add("QA/Pion/h2_Pt_EtaMC", "p_{T} vs #eta (MC)", kTH2D, {{axisEta}, {axisPtPi}}); + hist.add("QA/Pion/h_PtPos", "p_{T} (positive) ", kTH1D, {axisPtPi}); + hist.add("QA/Pion/h_PtNeg", "p_{T} (negative) ", kTH1D, {axisPtPi}); + hist.add("QA/Pion/h_PtTruth", "p_{T} (Truth)", kTH1D, {axisPtPi}); + hist.add("QA/Pion/h_PtPosTruth", "p_{T} (positive) (Truth)", kTH1D, {axisPtPi}); + hist.add("QA/Pion/h_PtNegTruth", "p_{T} (negative) (Truth) ", kTH1D, {axisPtPi}); + hist.add("QA/Pion/h_PtTruth_primary", "p_{T} (Truth Primary)", kTH1D, {axisPtPi}); + hist.add("QA/Pion/h_PtTruth_secondary", "p_{T} (Truth Secondary)", kTH1D, {axisPtPi}); + hist.add("QA/Pion/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPtPi}}); + hist.add("QA/Pion/h2_Pt_EtaTruth_primary", "p_{T} vs #eta (Truth Primary)", kTH2D, {{axisEta}, {axisPtPi}}); + + hist.add("QA/Kaon/h_Pt_e", "p_{T}", kTH1D, {axisPtKa}); + hist.add("QA/Kaon/h_PtMC", "p_{T} (MC)", kTH1D, {axisPtKa}); + hist.add("QA/Kaon/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPtKa}}); + hist.add("QA/Kaon/h3_Pt_Eta_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtKa}, {axisCent}}); + hist.add("QA/Kaon/h3_Pt_EtaMC_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtKa}, {axisCent}}); + hist.add("QA/Kaon/h3_Pt_EtaMC_primary_centFT0M", "Correctly selected primary kaons;#eta_{MC};p_{T,MC};FT0M (%)", kTH3D, {{axisEta}, {axisPtKa}, {axisCent}}); + hist.add("QA/Kaon/h2_Pt_EtaMC", "p_{T} vs #eta (MC)", kTH2D, {{axisEta}, {axisPtKa}}); + hist.add("QA/Kaon/h_PtPos", "p_{T} (positive) ", kTH1D, {axisPtKa}); + hist.add("QA/Kaon/h_PtNeg", "p_{T} (negative) ", kTH1D, {axisPtKa}); + hist.add("QA/Kaon/h_PtTruth", "p_{T} (Truth)", kTH1D, {axisPtKa}); + hist.add("QA/Kaon/h_PtPosTruth", "p_{T} (positive) (Truth)", kTH1D, {axisPtKa}); + hist.add("QA/Kaon/h_PtNegTruth", "p_{T} (negative) (Truth) ", kTH1D, {axisPtKa}); + hist.add("QA/Kaon/h_PtTruth_primary", "p_{T} (Truth Primary)", kTH1D, {axisPtKa}); + hist.add("QA/Kaon/h_PtTruth_secondary", "p_{T} (Truth Secondary)", kTH1D, {axisPtKa}); + hist.add("QA/Kaon/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPtKa}}); + hist.add("QA/Kaon/h2_Pt_EtaTruth_primary", "p_{T} vs #eta (Truth Primary)", kTH2D, {{axisEta}, {axisPtKa}}); + + hist.add("QA/Proton/h_Pt_e", "p_{T}", kTH1D, {axisPtPr}); + hist.add("QA/Proton/h_PtMC", "p_{T} (MC)", kTH1D, {axisPtPr}); + hist.add("QA/Proton/h2_Pt_Eta", "p_{T} vs #eta ", kTH2D, {{axisEta}, {axisPtPr}}); + hist.add("QA/Proton/h3_Pt_Eta_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPr}, {axisCent}}); + hist.add("QA/Proton/h3_Pt_EtaMC_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPr}, {axisCent}}); + hist.add("QA/Proton/h3_Pt_EtaMC_primary_centFT0M", "Correctly selected primary protons;#eta_{MC};p_{T,MC};FT0M (%)", kTH3D, {{axisEta}, {axisPtPr}, {axisCent}}); + hist.add("QA/Proton/h2_Pt_EtaMC", "p_{T} vs #eta (MC)", kTH2D, {{axisEta}, {axisPtPr}}); + hist.add("QA/Proton/h_PtPos", "p_{T} (positive) ", kTH1D, {axisPtPr}); + hist.add("QA/Proton/h_PtNeg", "p_{T} (negative) ", kTH1D, {axisPtPr}); + hist.add("QA/Proton/h_PtTruth", "p_{T} (Truth)", kTH1D, {axisPtPr}); + hist.add("QA/Proton/h_PtPosTruth", "p_{T} (positive) (Truth)", kTH1D, {axisPtPr}); + hist.add("QA/Proton/h_PtNegTruth", "p_{T} (negative) (Truth) ", kTH1D, {axisPtPr}); + hist.add("QA/Proton/h_PtTruth_primary", "p_{T} (Truth Primary)", kTH1D, {axisPtPr}); + hist.add("QA/Proton/h_PtTruth_secondary", "p_{T} (Truth Secondary)", kTH1D, {axisPtPr}); + hist.add("QA/Proton/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPtPr}}); + hist.add("QA/Proton/h2_Pt_EtaTruth_primary", "p_{T} vs #eta (Truth Primary)", kTH2D, {{axisEta}, {axisPtPr}}); + }; + addEfficiencyHistograms(); + + auto addMatrixHistograms = [&]() { + hist.add("Analysis/Charged/hN1Matrix", "Single-particle density", kTH2D, {{axisCent}, {axisPtCh}}); + hist.add("Analysis/Charged/hN2Matrix", "Ordered-pair density", kTH3D, {{axisCent}, {axisPtCh}, {axisPtCh}}); + + hist.add("Analysis/Pion/hN1Matrix", "Single-particle density", kTH2D, {{axisCent}, {axisPtPi}}); + hist.add("Analysis/Pion/hN2Matrix", "Ordered-pair density", kTH3D, {{axisCent}, {axisPtPi}, {axisPtPi}}); + + hist.add("Analysis/Kaon/hN1Matrix", "Single-particle density", kTH2D, {{axisCent}, {axisPtKa}}); + hist.add("Analysis/Kaon/hN2Matrix", "Ordered-pair density", kTH3D, {{axisCent}, {axisPtKa}, {axisPtKa}}); + + hist.add("Analysis/Proton/hN1Matrix", "Single-particle density", kTH2D, {{axisCent}, {axisPtPr}}); + hist.add("Analysis/Proton/hN2Matrix", "Ordered-pair density", kTH3D, {{axisCent}, {axisPtPr}, {axisPtPr}}); + }; + addMatrixHistograms(); + + if (cfgApplyEfficiencyCorrection) { + auto addCorrectedHistograms = [&](const std::string& directory, const AxisSpec& axisPtId) { + hist.add(directory + "hN1Matrix", "Efficiency-corrected Single-particle density", kTH2D, {{axisCent}, {axisPtId}}); + hist.add(directory + "hN2Matrix", "Efficiency-corrected Ordered-pair density", kTH3D, {{axisCent}, {axisPtId}, {axisPtId}}); + }; + addCorrectedHistograms("Corrected/Charged/", axisPtCh); + addCorrectedHistograms("Corrected/Pion/", axisPtPi); + addCorrectedHistograms("Corrected/Kaon/", axisPtKa); + addCorrectedHistograms("Corrected/Proton/", axisPtPr); + addCorrectedHistograms("CorrectedTruthMatched/Charged/", axisPtCh); + addCorrectedHistograms("CorrectedTruthMatched/Pion/", axisPtPi); + addCorrectedHistograms("CorrectedTruthMatched/Kaon/", axisPtKa); + addCorrectedHistograms("CorrectedTruthMatched/Proton/", axisPtPr); + } + + auto addGeneratedHistograms = [&]() { + // MC generated + hist.add("Gen/h_Counts", "Counts", kTH1D, {axisEvents}); + hist.add("Gen/h_VtxZ", "Vertex Z ", kTH1D, {axisVtxZ}); + hist.add("Gen/h_VtxZ_b", "Vertex Z ", kTH1D, {axisVtxZ}); + hist.add("Gen/h_NSim", "Truth Multiplicity TPC", kTH1D, {axisMultMC}); + hist.add("Gen/h2_NSim_NTPC", "Reco vs Truth Multiplicty TPC", kTH2D, {{axisMultMC}, {axisMultTPC}}); + hist.add("Gen/h2_NTPC_NSim", "Truth vs Reco Multiplicty TPC", kTH2D, {{axisMultTPC}, {axisMultMC}}); + + hist.add("Gen/Charged/h_PtTruth", "p_{T} ", kTH1D, {axisPt}); + hist.add("Gen/Charged/h_EtaTruth", "#eta ", kTH1D, {axisEta}); + hist.add("Gen/Charged/h_PhiTruth", "#phi ", kTH1D, {axisPhi}); + hist.add("Gen/Charged/h2_PtTruth_centFT0M", "p_{T} in centrality Classes ", kTH2D, {{axisCentFT0M}, {axisPt}}); + hist.add("Gen/Charged/h3_Pt_Eta_PhiTruth", "p_{T}, #eta, #phi ", kTHnSparseD, {{axisPt}, {axisEta}, {axisPhi}}); + + hist.addClone("Gen/Charged/", "Gen/Pion/"); + + hist.add("Gen/Pion/h_RapTruth", "y", kTH1D, {axisY}); + + hist.addClone("Gen/Pion/", "Gen/Kaon/"); + hist.addClone("Gen/Pion/", "Gen/Proton/"); + + hist.addClone("Analysis/Charged/", "Gen/Charged/"); + hist.addClone("Analysis/Pion/", "Gen/Pion/"); + hist.addClone("Analysis/Kaon/", "Gen/Kaon/"); + hist.addClone("Analysis/Proton/", "Gen/Proton/"); + + hist.add("Gen/Charged/h_PtTruth_e", "p_{T} ", kTH1D, {axisPtCh}); + hist.add("Gen/Charged/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPtCh}}); + hist.add("Gen/Charged/h3_Pt_EtaTruth_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtCh}, {axisCent}}); + + hist.add("Gen/Pion/h_PtTruth_e", "p_{T} ", kTH1D, {axisPtPi}); + hist.add("Gen/Pion/h_PtPosTruth", "p_{T} (positive) ", kTH1D, {axisPtPi}); + hist.add("Gen/Pion/h_PtNegTruth", "p_{T} (negative) ", kTH1D, {axisPtPi}); + hist.add("Gen/Pion/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPtPi}}); + hist.add("Gen/Pion/h3_Pt_EtaTruth_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPi}, {axisCent}}); + + hist.add("Gen/Kaon/h_PtTruth_e", "p_{T} ", kTH1D, {axisPtKa}); + hist.add("Gen/Kaon/h_PtPosTruth", "p_{T} (positive) ", kTH1D, {axisPtKa}); + hist.add("Gen/Kaon/h_PtNegTruth", "p_{T} (negative) ", kTH1D, {axisPtKa}); + hist.add("Gen/Kaon/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPtKa}}); + hist.add("Gen/Kaon/h3_Pt_EtaTruth_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtKa}, {axisCent}}); + + hist.add("Gen/Proton/h_PtTruth_e", "p_{T} ", kTH1D, {axisPtPr}); + hist.add("Gen/Proton/h_PtPosTruth", "p_{T} (positive) ", kTH1D, {axisPtPr}); + hist.add("Gen/Proton/h_PtNegTruth", "p_{T} (negative) ", kTH1D, {axisPtPr}); + hist.add("Gen/Proton/h2_Pt_EtaTruth", "p_{T} vs #eta", kTH2D, {{axisEta}, {axisPtPr}}); + hist.add("Gen/Proton/h3_Pt_EtaTruth_centFT0M", "p_{T} vs #eta in centrality classes", kTH3D, {{axisEta}, {axisPtPr}, {axisCent}}); + }; + addGeneratedHistograms(); hist.add("QA/h_collisions_info", "Collisions info", kTH1D, {axisCol}); hist.add("Gen/h_collisions_info", "Collisions info", kTH1D, {axisCol}); @@ -556,11 +662,12 @@ struct MeanPtFlucId { return false; } - if (std::fabs(track.dcaZ()) > cfgCutDcaZ) { - return false; - } + const float maxDca = cfgDcaPtDepOffset + cfgDcaPtDepScale / track.pt(); + // if (std::abs(track.dcaXY()) >= maxDca) { + // return false; + // } - if (std::fabs(track.dcaZ()) > (0.0105 + 0.035 / std::pow(track.p(), 1.1))) { + if (std::abs(track.dcaZ()) >= maxDca) { return false; } @@ -586,62 +693,50 @@ struct MeanPtFlucId { template bool identifyParticle(T const& track, PIDType species, PIDType reject1, PIDType reject2, float p, float momThreshold) { - std::vector vTpcNSigma = {-999.f, track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; - std::vector vTofNSigma = {-999.f, track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()}; - - const int sp = static_cast(species); - const int sq = static_cast(reject1); - const int sr = static_cast(reject2); + const std::array tpcNSigma = {-999.f, track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr()}; + const std::array tofNSigma = {-999.f, track.tofNSigmaPi(), track.tofNSigmaKa(), track.tofNSigmaPr()}; - bool isTofPidFlag = false; - bool isTpcPidFlag = false; + const int selSpecies = static_cast(species); + const int rejSpecies1 = static_cast(reject1); + const int rejSpecies2 = static_cast(reject2); - float nSigmaSelCut = 0.f; + float tpcSelectionCut = 0.f; + float tofSelectionCut = 0.f; switch (species) { case PIDType::kPions: - nSigmaSelCut = cfgSelCutNSigPi; + tpcSelectionCut = cfgSelCutNSigTpcPi; + tofSelectionCut = cfgSelCutNSigTofPi; break; - case PIDType::kKaons: - nSigmaSelCut = cfgSelCutNSigKa; + tpcSelectionCut = cfgSelCutNSigTpcKa; + tofSelectionCut = cfgSelCutNSigTofKa; break; - case PIDType::kProtons: - nSigmaSelCut = cfgSelCutNSigPr; + tpcSelectionCut = cfgSelCutNSigTpcPr; + tofSelectionCut = cfgSelCutNSigTofPr; break; - default: return false; } if (track.hasTOF()) { + const float selectedTofNSigma = std::abs(tofNSigma[selSpecies]); + const bool passesTOF = selectedTofNSigma < tofSelectionCut && + std::abs(tofNSigma[rejSpecies1]) > selectedTofNSigma && + std::abs(tofNSigma[rejSpecies2]) > selectedTofNSigma; + const bool passesTPC = std::abs(tpcNSigma[selSpecies]) < cfgCutNSigTpcTof; + return passesTPC && passesTOF; + } - if (std::abs(vTofNSigma[sp]) < nSigmaSelCut && - std::abs(vTofNSigma[sq]) > std::abs(vTofNSigma[sp]) && - std::abs(vTofNSigma[sr]) > std::abs(vTofNSigma[sp])) { - isTofPidFlag = true; - } - - if (std::abs(vTpcNSigma[sp]) < cfgCutNSig2) { - isTpcPidFlag = true; - } - - } else { - - if (p >= momThreshold) { - return false; - } - - if (std::abs(vTpcNSigma[sp]) < nSigmaSelCut && - std::abs(vTpcNSigma[sq]) > std::abs(vTpcNSigma[sp]) && - std::abs(vTpcNSigma[sr]) > std::abs(vTpcNSigma[sp])) { - isTofPidFlag = true; - isTpcPidFlag = true; - } + if (p >= momThreshold) { + return false; } - return (isTofPidFlag && isTpcPidFlag); + const float selTpcNSigma = std::abs(tpcNSigma[selSpecies]); + return selTpcNSigma < tpcSelectionCut && + std::abs(tpcNSigma[rejSpecies1]) > selTpcNSigma && + std::abs(tpcNSigma[rejSpecies2]) > selTpcNSigma; } // Fill QA histograms before selection cuts: @@ -706,82 +801,95 @@ struct MeanPtFlucId { template void fillBeforePIDQAHistos(T const& track) { - hist.fill(HIST("QA/before/h2_TOFSignal"), track.p(), track.beta()); hist.fill(HIST("QA/before/h2_TPCSignal"), track.p(), track.tpcSignal()); - hist.fill(HIST("QA/before/h2_pvsm2"), track.mass() * track.mass(), track.p()); + if (track.hasTOF()) { + hist.fill(HIST("QA/before/h2_TOFSignal"), track.p(), track.beta()); + hist.fill(HIST("QA/before/h2_pvsm2"), track.mass() * track.mass(), track.p()); + } hist.fill(HIST("QA/Pion/before/h2_TPCNsigma"), track.p(), track.tpcNSigmaPi()); - if (!track.hasTOF()) + if (!track.hasTOF()) { hist.fill(HIST("QA/Pion/before/h2_TPCNsigma_nottof"), track.p(), track.tpcNSigmaPi()); - if (track.hasTOF()) + } + if (track.hasTOF()) { hist.fill(HIST("QA/Pion/before/h2_TPCNsigma_tof"), track.p(), track.tpcNSigmaPi()); - hist.fill(HIST("QA/Pion/before/h2_TOFNsigma"), track.p(), track.tofNSigmaPi()); - hist.fill(HIST("QA/Pion/before/h2_TpcTofNsigma"), track.tpcNSigmaPi(), track.tofNSigmaPi()); + hist.fill(HIST("QA/Pion/before/h2_TOFNsigma"), track.p(), track.tofNSigmaPi()); + hist.fill(HIST("QA/Pion/before/h2_TpcTofNsigma"), track.tpcNSigmaPi(), track.tofNSigmaPi()); + } hist.fill(HIST("QA/Kaon/before/h2_TPCNsigma"), track.p(), track.tpcNSigmaKa()); - if (!track.hasTOF()) + if (!track.hasTOF()) { hist.fill(HIST("QA/Kaon/before/h2_TPCNsigma_nottof"), track.p(), track.tpcNSigmaKa()); - if (track.hasTOF()) + } + if (track.hasTOF()) { hist.fill(HIST("QA/Kaon/before/h2_TPCNsigma_tof"), track.p(), track.tpcNSigmaKa()); - hist.fill(HIST("QA/Kaon/before/h2_TOFNsigma"), track.p(), track.tofNSigmaKa()); - hist.fill(HIST("QA/Kaon/before/h2_TpcTofNsigma"), track.tpcNSigmaKa(), track.tofNSigmaKa()); + hist.fill(HIST("QA/Kaon/before/h2_TOFNsigma"), track.p(), track.tofNSigmaKa()); + hist.fill(HIST("QA/Kaon/before/h2_TpcTofNsigma"), track.tpcNSigmaKa(), track.tofNSigmaKa()); + } hist.fill(HIST("QA/Proton/before/h2_TPCNsigma"), track.p(), track.tpcNSigmaPr()); - if (!track.hasTOF()) + if (!track.hasTOF()) { hist.fill(HIST("QA/Proton/before/h2_TPCNsigma_nottof"), track.p(), track.tpcNSigmaPr()); - if (track.hasTOF()) + } + if (track.hasTOF()) { hist.fill(HIST("QA/Proton/before/h2_TPCNsigma_tof"), track.p(), track.tpcNSigmaPr()); - hist.fill(HIST("QA/Proton/before/h2_TOFNsigma"), track.p(), track.tofNSigmaPr()); - hist.fill(HIST("QA/Proton/before/h2_TpcTofNsigma"), track.tpcNSigmaPr(), track.tofNSigmaPr()); + hist.fill(HIST("QA/Proton/before/h2_TOFNsigma"), track.p(), track.tofNSigmaPr()); + hist.fill(HIST("QA/Proton/before/h2_TpcTofNsigma"), track.tpcNSigmaPr(), track.tofNSigmaPr()); + } } // Fill identified QA histograms after PID cuts: template - void fillIdParticleQAHistos(T const& track, float ptMC, float etaMC, float rap, float nSigmaTPC, float nSigmaTOF, std::vector& Tracks) + void fillIdParticleQAHistos(T const& track, float ptMC, float etaMC, float rap, float nSigmaTPC, float nSigmaTOF, std::vector& tracks) { float pt = track.pt(); float eta = track.eta(); float phi = track.phi(); - Tracks.push_back({pt, eta}); + tracks.push_back({pt}); if (track.sign() > 0) { - hist.fill(HIST(Dire[Mode]) + HIST("h_PtPos"), pt); + hist.fill(HIST(dire[Mode]) + HIST("h_PtPos"), pt); } if (track.sign() < 0) { - hist.fill(HIST(Dire[Mode]) + HIST("h_PtNeg"), pt); + hist.fill(HIST(dire[Mode]) + HIST("h_PtNeg"), pt); } - hist.fill(HIST(Dire[Mode]) + HIST("h_Pt"), pt); - hist.fill(HIST(Dire[Mode]) + HIST("h_PtMC"), ptMC); - hist.fill(HIST(Dire[Mode]) + HIST("h2_Pt_PtMC"), ptMC, pt); - hist.fill(HIST(Dire[Mode]) + HIST("h2_Pt_centFT0M"), centFT0M, pt); - hist.fill(HIST(Dire[Mode]) + HIST("h3_Pt_Eta_Phi"), pt, eta, phi); - hist.fill(HIST(Dire[Mode]) + HIST("h2_Pt_Eta"), eta, pt); - hist.fill(HIST(Dire[Mode]) + HIST("h3_Pt_Eta_centFT0M"), eta, pt, centFT0M); - hist.fill(HIST(Dire[Mode]) + HIST("h2_Pt_EtaMC"), etaMC, ptMC); - hist.fill(HIST(Dire[Mode]) + HIST("h3_Pt_EtaMC_centFT0M"), etaMC, ptMC, centFT0M); - hist.fill(HIST(Dire[Mode]) + HIST("h_Eta"), eta); - hist.fill(HIST(Dire[Mode]) + HIST("h_Phi"), phi); - hist.fill(HIST(Dire[Mode]) + HIST("h_Rap"), rap); - hist.fill(HIST(Dire[Mode]) + HIST("h_DcaZ"), track.dcaZ()); - hist.fill(HIST(Dire[Mode]) + HIST("h_DcaXY"), track.dcaXY()); - hist.fill(HIST(Dire[Mode]) + HIST("h2_DcaZ"), pt, track.dcaZ()); - hist.fill(HIST(Dire[Mode]) + HIST("h2_DcaXY"), pt, track.dcaXY()); - - hist.fill(HIST(Dire[Mode]) + HIST("h2_TPCNsigma"), track.p(), nSigmaTPC); - hist.fill(HIST(Dire[Mode]) + HIST("h2_TOFNsigma"), track.p(), nSigmaTOF); - hist.fill(HIST(Dire[Mode]) + HIST("h2_TpcTofNsigma"), nSigmaTPC, nSigmaTOF); - hist.fill(HIST(Dire[Mode]) + HIST("h2_TPCSignal"), track.p(), track.tpcSignal()); - hist.fill(HIST(Dire[Mode]) + HIST("innerParam/h2_TPCSignal"), track.tpcInnerParam(), track.tpcSignal()); - hist.fill(HIST(Dire[Mode]) + HIST("h2_TOFSignal"), track.p(), track.beta()); - hist.fill(HIST(Dire[Mode]) + HIST("h2_pvsm2"), track.mass() * track.mass(), track.p()); + hist.fill(HIST(dire[Mode]) + HIST("h_Pt"), pt); + hist.fill(HIST(dire[Mode]) + HIST("h_Pt_e"), pt); + hist.fill(HIST(dire[Mode]) + HIST("h_PtMC"), ptMC); + hist.fill(HIST(dire[Mode]) + HIST("h2_Pt_PtMC"), ptMC, pt); + hist.fill(HIST(dire[Mode]) + HIST("h2_Pt_centFT0M"), centFT0M, pt); + hist.fill(HIST(dire[Mode]) + HIST("h3_Pt_Eta_Phi"), pt, eta, phi); + hist.fill(HIST(dire[Mode]) + HIST("h2_Pt_Eta"), eta, pt); + hist.fill(HIST(dire[Mode]) + HIST("h3_Pt_Eta_centFT0M"), eta, pt, centFT0M); + hist.fill(HIST(dire[Mode]) + HIST("h2_Pt_EtaMC"), etaMC, ptMC); + hist.fill(HIST(dire[Mode]) + HIST("h3_Pt_EtaMC_centFT0M"), etaMC, ptMC, centFT0M); + hist.fill(HIST(dire[Mode]) + HIST("h_Eta"), eta); + hist.fill(HIST(dire[Mode]) + HIST("h_Phi"), phi); + hist.fill(HIST(dire[Mode]) + HIST("h_Rap"), rap); + hist.fill(HIST(dire[Mode]) + HIST("h_DcaZ"), track.dcaZ()); + hist.fill(HIST(dire[Mode]) + HIST("h_DcaXY"), track.dcaXY()); + hist.fill(HIST(dire[Mode]) + HIST("h2_DcaZ"), pt, track.dcaZ()); + hist.fill(HIST(dire[Mode]) + HIST("h2_DcaXY"), pt, track.dcaXY()); + + hist.fill(HIST(dire[Mode]) + HIST("h2_TPCNsigma"), track.p(), nSigmaTPC); + hist.fill(HIST(dire[Mode]) + HIST("h2_TPCSignal"), track.p(), track.tpcSignal()); + hist.fill(HIST(dire[Mode]) + HIST("innerParam/h2_TPCSignal"), track.tpcInnerParam(), track.tpcSignal()); + if (track.hasTOF()) { + hist.fill(HIST(dire[Mode]) + HIST("h2_TOFNsigma"), track.p(), nSigmaTOF); + hist.fill(HIST(dire[Mode]) + HIST("h2_TpcTofNsigma"), nSigmaTPC, nSigmaTOF); + hist.fill(HIST(dire[Mode]) + HIST("h2_TOFSignal"), track.p(), track.beta()); + hist.fill(HIST(dire[Mode]) + HIST("h2_pvsm2"), track.mass() * track.mass(), track.p()); + } hist.fill(HIST("QA/after/h2_TPCSignal"), track.p(), track.tpcSignal()); hist.fill(HIST("QA/after/innerParam/h2_TPCSignal"), track.tpcInnerParam(), track.tpcSignal()); - hist.fill(HIST("QA/after/h2_TOFSignal"), track.p(), track.beta()); - hist.fill(HIST("QA/after/h2_pvsm2"), track.mass() * track.mass(), track.p()); + if (track.hasTOF()) { + hist.fill(HIST("QA/after/h2_TOFSignal"), track.p(), track.beta()); + hist.fill(HIST("QA/after/h2_pvsm2"), track.mass() * track.mass(), track.p()); + } } // Fill Truth identified particles histograms @@ -789,142 +897,158 @@ struct MeanPtFlucId { void fillPtMCHist(bool cfgGen, float pt, float eta, float rap, float phi, int pid, int pdgCodePos, int pdgCodeNeg) { if (cfgGen) { - hist.fill(HIST(Dire[Mode]) + HIST("h_PtTruth"), pt); - hist.fill(HIST(Dire[Mode]) + HIST("h_EtaTruth"), eta); - hist.fill(HIST(Dire[Mode]) + HIST("h_RapTruth"), rap); - hist.fill(HIST(Dire[Mode]) + HIST("h_PhiTruth"), phi); - hist.fill(HIST(Dire[Mode]) + HIST("h2_PtTruth_centFT0M"), centFT0M, pt); - hist.fill(HIST(Dire[Mode]) + HIST("h3_Pt_EtaTruth_centFT0M"), eta, pt, centFT0M); - hist.fill(HIST(Dire[Mode]) + HIST("h3_Pt_Eta_PhiTruth"), pt, eta, phi); + hist.fill(HIST(dire[Mode]) + HIST("h_PtTruth"), pt); + hist.fill(HIST(dire[Mode]) + HIST("h_PtTruth_e"), pt); + hist.fill(HIST(dire[Mode]) + HIST("h_EtaTruth"), eta); + hist.fill(HIST(dire[Mode]) + HIST("h_RapTruth"), rap); + hist.fill(HIST(dire[Mode]) + HIST("h_PhiTruth"), phi); + hist.fill(HIST(dire[Mode]) + HIST("h2_PtTruth_centFT0M"), centFT0M, pt); + hist.fill(HIST(dire[Mode]) + HIST("h3_Pt_EtaTruth_centFT0M"), eta, pt, centFT0M); + hist.fill(HIST(dire[Mode]) + HIST("h3_Pt_Eta_PhiTruth"), pt, eta, phi); } - hist.fill(HIST(Dire[Mode]) + HIST("h2_Pt_EtaTruth"), eta, pt); + hist.fill(HIST(dire[Mode]) + HIST("h2_Pt_EtaTruth"), eta, pt); if (pid == pdgCodePos) { - hist.fill(HIST(Dire[Mode]) + HIST("h_PtPosTruth"), pt); + hist.fill(HIST(dire[Mode]) + HIST("h_PtPosTruth"), pt); } if (pid == pdgCodeNeg) { - hist.fill(HIST(Dire[Mode]) + HIST("h_PtNegTruth"), pt); - } - } - - int getPtBin(double pt, const std::vector& ptB) - { - for (size_t i = 0; i < ptB.size() - 1; ++i) { - if (pt >= ptB[i] && pt < ptB[i + 1]) { - return i; - } - } - return -1; - } - - int getEtaBin(double eta) - { - for (size_t i = 0; i < etaBins->size() - 1; ++i) { - if (eta >= etaBins->at(i) && eta < etaBins->at(i + 1)) { - return i; - } + hist.fill(HIST(dire[Mode]) + HIST("h_PtNegTruth"), pt); } - return -1; } - // fill differential matrices for two-particle analysis template - void fillDifferentialMatrices(const std::vector& tracks, const std::vector& ptB) + void fillMatrices(const std::vector& tracks, double ptMin) { - const int nPtBins = ptB.size() - 1; - - auto getK = [&](int ipt, int ieta) { - return ieta * nPtBins + ipt; - }; + const int nBins = nPtBins; + const double binWidth = (cfgCutPtMax - ptMin) / nBins; + matrixNInBin.assign(nBins, 0); + matrixOccupiedBins.clear(); + matrixOccupiedBins.reserve(std::min(static_cast(nBins), tracks.size())); - for (const auto& trk : tracks) { - int ipt = getPtBin(trk.pt, ptB); - int ieta = getEtaBin(trk.eta); - - if (ipt < 0 || ieta < 0) + for (const auto& track : tracks) { + const int ptBin = static_cast((track.pt - ptMin) / binWidth); + if (ptBin < 0 || ptBin >= nBins) { continue; - - int k = getK(ipt, ieta); - - hist.fill(HIST(Dire[Mode]) + HIST("hN1Matrix"), centFT0M, k, 1.0); - hist.fill(HIST(Dire[Mode]) + HIST("hPt1Matrix"), centFT0M, k, trk.pt); + } + if (matrixNInBin[ptBin] == 0) { + matrixOccupiedBins.push_back(ptBin); + } + ++matrixNInBin[ptBin]; } - for (size_t i = 0; i < tracks.size(); ++i) { - int ipt1 = getPtBin(tracks[i].pt, ptB); - int ieta1 = getEtaBin(tracks[i].eta); - - if (ipt1 < 0 || ieta1 < 0) - continue; - - int k1 = getK(ipt1, ieta1); - - for (size_t j = i + 1; j < tracks.size(); ++j) { - int ipt2 = getPtBin(tracks[j].pt, ptB); - int ieta2 = getEtaBin(tracks[j].eta); - - if (ipt2 < 0 || ieta2 < 0) - continue; + for (const int& ptBin : matrixOccupiedBins) { + const double ptCenter = ptMin + (ptBin + 0.5) * binWidth; + hist.fill(HIST(dire[Mode]) + HIST("hN1Matrix"), centFT0M, ptCenter, static_cast(matrixNInBin[ptBin])); + } - int k2 = getK(ipt2, ieta2); + for (size_t i = 0; i < matrixOccupiedBins.size(); ++i) { + const int ptBin1 = matrixOccupiedBins[i]; + const double ptCenter1 = ptMin + (ptBin1 + 0.5) * binWidth; + const double nPairDiagonal = static_cast(matrixNInBin[ptBin1]) * (matrixNInBin[ptBin1] - 1); + if (nPairDiagonal > 0.0) { + hist.fill(HIST(dire[Mode]) + HIST("hN2Matrix"), centFT0M, ptCenter1, ptCenter1, nPairDiagonal); + } - hist.fill(HIST(Dire[Mode]) + HIST("hN2Matrix"), centFT0M, k1, k2, 1.0); - hist.fill(HIST(Dire[Mode]) + HIST("hN2Matrix"), centFT0M, k2, k1, 1.0); - hist.fill(HIST(Dire[Mode]) + HIST("hPtPtMatrix"), centFT0M, k1, k2, tracks[i].pt * tracks[j].pt); - hist.fill(HIST(Dire[Mode]) + HIST("hPtPtMatrix"), centFT0M, k2, k1, tracks[j].pt * tracks[i].pt); + for (size_t j = i + 1; j < matrixOccupiedBins.size(); ++j) { + const int ptBin2 = matrixOccupiedBins[j]; + const double ptCenter2 = ptMin + (ptBin2 + 0.5) * binWidth; + const double nPair = static_cast(matrixNInBin[ptBin1]) * matrixNInBin[ptBin2]; + hist.fill(HIST(dire[Mode]) + HIST("hN2Matrix"), centFT0M, ptCenter1, ptCenter2, nPair); + hist.fill(HIST(dire[Mode]) + HIST("hN2Matrix"), centFT0M, ptCenter2, ptCenter1, nPair); } } } - // Calculate moments for two-particle correlations - void moments(double pt, int& n, double& q1, double& q2) - { - n++; - q1 += pt; - q2 += pt * pt; - } - - // Fill terms calculted from moments method for two-particle correlations - template - void fillAnalysis(int n, double q1, double q2) + bool getEfficiencyWeight(PIDType species, double pt, double eta, double& weight) const { + TH3* weightMap = nullptr; + switch (species) { + case PIDType::kNone: + weightMap = efficiencyWeightCh; + break; + case PIDType::kPions: + weightMap = efficiencyWeightPi; + break; + case PIDType::kKaons: + weightMap = efficiencyWeightKa; + break; + case PIDType::kProtons: + weightMap = efficiencyWeightPr; + break; + } + if (!weightMap) { + return false; + } - double npair = n * (n - 1); - - if (n > 0) { - double meanPt = q1 / n; - - hist.fill(HIST(Dire[Mode]) + HIST("h_mult"), n); - - hist.fill(HIST(Dire[Mode]) + HIST("h_mean_pT_Cent"), centFT0M, meanPt); - hist.fill(HIST(Dire[Mode]) + HIST("p_mean_pT_Cent"), centFT0M, meanPt); + const int etaBin = weightMap->GetXaxis()->FindFixBin(eta); + const int ptBin = weightMap->GetYaxis()->FindFixBin(pt); + const int centBin = weightMap->GetZaxis()->FindFixBin(centFT0M); + if (etaBin < 1 || etaBin > weightMap->GetNbinsX() || + ptBin < 1 || ptBin > weightMap->GetNbinsY() || + centBin < 1 || centBin > weightMap->GetNbinsZ()) { + return false; + } - hist.fill(HIST(Dire[Mode]) + HIST("p_mean_pT_Num_Cent_var"), centFT0M, q1); - hist.fill(HIST(Dire[Mode]) + HIST("p_mean_pT_Den_Cent_var"), centFT0M, n); + weight = weightMap->GetBinContent(etaBin, ptBin, centBin); + return std::isfinite(weight) && weight > 0.; + } - hist.fill(HIST(Dire[Mode]) + HIST("h_mean_pT_Num_Cent_var"), centFT0M, q1); - hist.fill(HIST(Dire[Mode]) + HIST("h_mean_pT_Den_Cent_var"), centFT0M, n); + template + void fillCorrectedMatrices(const std::vector& tracks, double ptMin) + { + const int nBins = nPtBins; + const double binWidth = (cfgCutPtMax - ptMin) / nBins; + matrixWInBin.assign(nBins, 0.); + matrixW2InBin.assign(nBins, 0.); + matrixOccupiedBins.clear(); + matrixOccupiedBins.reserve(std::min(static_cast(nBins), tracks.size())); - hist.fill(HIST(Dire[Mode]) + HIST("p_Q1_Mult"), n, q1); - hist.fill(HIST(Dire[Mode]) + HIST("p_Q2_Mult"), n, q2); - hist.fill(HIST(Dire[Mode]) + HIST("p_mean_pT_Mult"), n, meanPt); + for (const auto& track : tracks) { + const int ptBin = static_cast((track.pt - ptMin) / binWidth); + if (ptBin < 0 || ptBin >= nBins) { + continue; + } + if (matrixWInBin[ptBin] == 0.) { + matrixOccupiedBins.push_back(ptBin); + } + matrixWInBin[ptBin] += track.weight; + matrixW2InBin[ptBin] += track.weight * track.weight; } - if (npair != 0) { - double meanPt = q1 / n; - double twopart = (q1 * q1 - q2); - double varPt = twopart / npair; - hist.fill(HIST(Dire[Mode]) + HIST("p_twopart_Num_Cent_var"), centFT0M, twopart); - hist.fill(HIST(Dire[Mode]) + HIST("p_twopart_Den_Cent_var"), centFT0M, npair); + for (const int& ptBin : matrixOccupiedBins) { + const double ptCenter = ptMin + (ptBin + 0.5) * binWidth; + if constexpr (TruthMatched) { + hist.fill(HIST(TruthMatchedCorrectedDirectories[Mode]) + HIST("hN1Matrix"), centFT0M, ptCenter, matrixWInBin[ptBin]); + } else { + hist.fill(HIST(CorrectedDirectories[Mode]) + HIST("hN1Matrix"), centFT0M, ptCenter, matrixWInBin[ptBin]); + } + } - hist.fill(HIST(Dire[Mode]) + HIST("h_twopart_Num_Cent_var"), centFT0M, twopart); - hist.fill(HIST(Dire[Mode]) + HIST("h_twopart_Den_Cent_var"), centFT0M, npair); + for (size_t i = 0; i < matrixOccupiedBins.size(); ++i) { + const int ptBin1 = matrixOccupiedBins[i]; + const double ptCenter1 = ptMin + (ptBin1 + 0.5) * binWidth; + const double diagonalPairDensity = matrixWInBin[ptBin1] * matrixWInBin[ptBin1] - matrixW2InBin[ptBin1]; + if (diagonalPairDensity > 0.) { + if constexpr (TruthMatched) { + hist.fill(HIST(TruthMatchedCorrectedDirectories[Mode]) + HIST("hN2Matrix"), centFT0M, ptCenter1, ptCenter1, diagonalPairDensity); + } else { + hist.fill(HIST(CorrectedDirectories[Mode]) + HIST("hN2Matrix"), centFT0M, ptCenter1, ptCenter1, diagonalPairDensity); + } + } - hist.fill(HIST(Dire[Mode]) + HIST("p_mean_pT_Cent_var"), centFT0M, meanPt); - hist.fill(HIST(Dire[Mode]) + HIST("p_twopart_Cent_var"), centFT0M, varPt); - hist.fill(HIST(Dire[Mode]) + HIST("h_twopart_Cent_var"), centFT0M, varPt); - hist.fill(HIST(Dire[Mode]) + HIST("h_mean_pT_Cent_var"), centFT0M, meanPt); + for (size_t j = i + 1; j < matrixOccupiedBins.size(); ++j) { + const int ptBin2 = matrixOccupiedBins[j]; + const double ptCenter2 = ptMin + (ptBin2 + 0.5) * binWidth; + const double pairDensity = matrixWInBin[ptBin1] * matrixWInBin[ptBin2]; + if constexpr (TruthMatched) { + hist.fill(HIST(TruthMatchedCorrectedDirectories[Mode]) + HIST("hN2Matrix"), centFT0M, ptCenter1, ptCenter2, pairDensity); + hist.fill(HIST(TruthMatchedCorrectedDirectories[Mode]) + HIST("hN2Matrix"), centFT0M, ptCenter2, ptCenter1, pairDensity); + } else { + hist.fill(HIST(CorrectedDirectories[Mode]) + HIST("hN2Matrix"), centFT0M, ptCenter1, ptCenter2, pairDensity); + hist.fill(HIST(CorrectedDirectories[Mode]) + HIST("hN2Matrix"), centFT0M, ptCenter2, ptCenter1, pairDensity); + } + } } } @@ -936,10 +1060,16 @@ struct MeanPtFlucId { pionTracks.clear(); kaonTracks.clear(); protonTracks.clear(); + chargedTracksCorrected.clear(); + pionTracksCorrected.clear(); + kaonTracksCorrected.clear(); + protonTracksCorrected.clear(); + chargedTracksTruthMatchedCorrected.clear(); + pionTracksTruthMatchedCorrected.clear(); + kaonTracksTruthMatchedCorrected.clear(); + protonTracksTruthMatchedCorrected.clear(); - int nCh = 0, nPi = 0, nKa = 0, nPr = 0; float pt = 0., eta = 0., phi = 0., p = 0.; - double q1Ch = 0., q2Ch = 0., q1Pi = 0., q2Pi = 0., q1Ka = 0., q2Ka = 0., q1Pr = 0., q2Pr = 0.; hist.fill(HIST("QA/h_collisions_info"), kTotCol); @@ -949,14 +1079,6 @@ struct MeanPtFlucId { } } - if constexpr (RecoFlag) { - float lower = cfgP2L * nSim * nSim + cfgP1L * nSim - cfgP0L; - float upper = cfgP2U * nSim * nSim + cfgP1U * nSim + cfgP0U; - if (cfgNtpcEventCut && (nTPC < lower || nTPC > upper)) { - return; // Reject event - } - } - hist.fill(HIST("QA/h_collisions_info"), kPassSelCol); fillAfterQAHistos(col); @@ -1002,22 +1124,39 @@ struct MeanPtFlucId { auto mc = track.template mcParticle_as(); ptMC = mc.pt(); etaMC = mc.eta(); - p = mc.p(); if (mc.isPhysicalPrimary()) { hist.fill(HIST("QA/after/h_DCAxy_primary"), track.dcaXY()); hist.fill(HIST("QA/after/h_DCAz_primary"), track.dcaZ()); + hist.fill(HIST("QA/Charged/h_PtTruth_primary"), track.pt()); + const bool mcInChargedAcceptance = ptMC >= cfgCutPtMin && ptMC < cfgCutPtMax && std::abs(etaMC) < cfgCutEta; + if (mcInChargedAcceptance) { + hist.fill(HIST("QA/Charged/h3_Pt_EtaMC_primary_centFT0M"), etaMC, ptMC, centFT0M); + if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) { + double weight = 0.; + if (!getEfficiencyWeight(PIDType::kNone, ptMC, etaMC, weight)) { + LOGF(fatal, "Undefined truth-matched charged efficiency weight at pT=%g, eta=%g, centrality=%g", ptMC, etaMC, centFT0M); + } + chargedTracksTruthMatchedCorrected.push_back({ptMC, weight}); + } + } } else { hist.fill(HIST("QA/after/h_DCAxy_secondary"), track.dcaXY()); hist.fill(HIST("QA/after/h_DCAz_secondary"), track.dcaZ()); } } - nCh++; - chargedTracks.push_back({pt, eta}); - moments(pt, nCh, q1Ch, q2Ch); + if (cfgApplyEfficiencyCorrection) { + double weight = 0.; + if (!getEfficiencyWeight(PIDType::kNone, pt, eta, weight)) { + LOGF(fatal, "Undefined charged-particle efficiency weight at pT=%g, eta=%g, centrality=%g", pt, eta, centFT0M); + } + chargedTracksCorrected.push_back({pt, weight}); + } + chargedTracks.push_back({pt}); hist.fill(HIST("QA/Charged/h_Pt"), pt); + hist.fill(HIST("QA/Charged/h_Pt_e"), pt); hist.fill(HIST("QA/Charged/h_PtMC"), ptMC); hist.fill(HIST("QA/Charged/h2_Pt_PtMC"), ptMC, pt); hist.fill(HIST("QA/Charged/h2_Pt_EtaMC"), etaMC, ptMC); @@ -1035,15 +1174,33 @@ struct MeanPtFlucId { auto selIDProton = identifyParticle(track, PIDType::kProtons, PIDType::kPions, PIDType::kKaons, p, cfgCutPrThrsldP); if (selIDPion && track.pt() >= cfgCutPiPtMin) { - moments(pt, nPi, q1Pi, q2Pi); + if (cfgApplyEfficiencyCorrection) { + double weight = 0.; + if (!getEfficiencyWeight(PIDType::kPions, pt, eta, weight)) { + LOGF(fatal, "Undefined pion efficiency weight at pT=%g, eta=%g, centrality=%g", pt, eta, centFT0M); + } + pionTracksCorrected.push_back({pt, weight}); + } fillIdParticleQAHistos(track, ptMC, etaMC, rapPi, nSigmaTPCPi, nSigmaTOFPi, pionTracks); } if (selIDKaon && track.pt() >= cfgCutKaPtMin) { - moments(pt, nKa, q1Ka, q2Ka); + if (cfgApplyEfficiencyCorrection) { + double weight = 0.; + if (!getEfficiencyWeight(PIDType::kKaons, pt, eta, weight)) { + LOGF(fatal, "Undefined kaon efficiency weight at pT=%g, eta=%g, centrality=%g", pt, eta, centFT0M); + } + kaonTracksCorrected.push_back({pt, weight}); + } fillIdParticleQAHistos(track, ptMC, etaMC, rapKa, nSigmaTPCKa, nSigmaTOFKa, kaonTracks); } if (selIDProton && track.pt() >= cfgCutPrPtMin) { - moments(pt, nPr, q1Pr, q2Pr); + if (cfgApplyEfficiencyCorrection) { + double weight = 0.; + if (!getEfficiencyWeight(PIDType::kProtons, pt, eta, weight)) { + LOGF(fatal, "Undefined proton efficiency weight at pT=%g, eta=%g, centrality=%g", pt, eta, centFT0M); + } + protonTracksCorrected.push_back({pt, weight}); + } fillIdParticleQAHistos(track, ptMC, etaMC, rapPr, nSigmaTPCPr, nSigmaTOFPr, protonTracks); } @@ -1056,6 +1213,18 @@ struct MeanPtFlucId { fillPtMCHist(false, pt, eta, rapPi, phi, pid, kPiPlus, kPiMinus); if (mc.isPhysicalPrimary()) { hist.fill(HIST("QA/Pion/h_PtTruth_primary"), track.pt()); + hist.fill(HIST("QA/Pion/h2_Pt_EtaTruth_primary"), track.eta(), track.pt()); + const bool mcInPionAcceptance = ptMC >= cfgCutPiPtMin && ptMC < cfgCutPtMax && std::abs(etaMC) < cfgCutEta; + if (mcInPionAcceptance) { + hist.fill(HIST("QA/Pion/h3_Pt_EtaMC_primary_centFT0M"), etaMC, ptMC, centFT0M); + if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) { + double weight = 0.; + if (!getEfficiencyWeight(PIDType::kPions, ptMC, etaMC, weight)) { + LOGF(fatal, "Undefined truth-matched pion efficiency weight at pT=%g, eta=%g, centrality=%g", ptMC, etaMC, centFT0M); + } + pionTracksTruthMatchedCorrected.push_back({ptMC, weight}); + } + } } else { hist.fill(HIST("QA/Pion/h_PtTruth_secondary"), track.pt()); } @@ -1067,6 +1236,18 @@ struct MeanPtFlucId { fillPtMCHist(false, pt, eta, rapKa, phi, pid, kKPlus, kKMinus); if (mc.isPhysicalPrimary()) { hist.fill(HIST("QA/Kaon/h_PtTruth_primary"), track.pt()); + hist.fill(HIST("QA/Kaon/h2_Pt_EtaTruth_primary"), track.eta(), track.pt()); + const bool mcInKaonAcceptance = ptMC >= cfgCutKaPtMin && ptMC < cfgCutPtMax && std::abs(etaMC) < cfgCutEta; + if (mcInKaonAcceptance) { + hist.fill(HIST("QA/Kaon/h3_Pt_EtaMC_primary_centFT0M"), etaMC, ptMC, centFT0M); + if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) { + double weight = 0.; + if (!getEfficiencyWeight(PIDType::kKaons, ptMC, etaMC, weight)) { + LOGF(fatal, "Undefined truth-matched kaon efficiency weight at pT=%g, eta=%g, centrality=%g", ptMC, etaMC, centFT0M); + } + kaonTracksTruthMatchedCorrected.push_back({ptMC, weight}); + } + } } else { hist.fill(HIST("QA/Kaon/h_PtTruth_secondary"), track.pt()); } @@ -1078,6 +1259,18 @@ struct MeanPtFlucId { fillPtMCHist(false, pt, eta, rapPr, phi, pid, kProton, kProtonBar); if (mc.isPhysicalPrimary()) { hist.fill(HIST("QA/Proton/h_PtTruth_primary"), track.pt()); + hist.fill(HIST("QA/Proton/h2_Pt_EtaTruth_primary"), track.eta(), track.pt()); + const bool mcInProtonAcceptance = ptMC >= cfgCutPrPtMin && ptMC < cfgCutPtMax && std::abs(etaMC) < cfgCutEta; + if (mcInProtonAcceptance) { + hist.fill(HIST("QA/Proton/h3_Pt_EtaMC_primary_centFT0M"), etaMC, ptMC, centFT0M); + if (cfgApplyEfficiencyCorrection && !cfgUseCombinedPurityEfficiencyWeight) { + double weight = 0.; + if (!getEfficiencyWeight(PIDType::kProtons, ptMC, etaMC, weight)) { + LOGF(fatal, "Undefined truth-matched proton efficiency weight at pT=%g, eta=%g, centrality=%g", ptMC, etaMC, centFT0M); + } + protonTracksTruthMatchedCorrected.push_back({ptMC, weight}); + } + } } else { hist.fill(HIST("QA/Proton/h_PtTruth_secondary"), track.pt()); } @@ -1085,14 +1278,51 @@ struct MeanPtFlucId { } } } - fillDifferentialMatrices(chargedTracks, ptBins.value); - fillDifferentialMatrices(pionTracks, ptBinsPi.value); - fillDifferentialMatrices(kaonTracks, ptBinsKa.value); - fillDifferentialMatrices(protonTracks, ptBinsPr.value); - fillAnalysis(nCh, q1Ch, q2Ch); - fillAnalysis(nPi, q1Pi, q2Pi); - fillAnalysis(nKa, q1Ka, q2Ka); - fillAnalysis(nPr, q1Pr, q2Pr); + fillMatrices(chargedTracks, cfgCutPtMin); + fillMatrices(pionTracks, cfgCutPiPtMin); + fillMatrices(kaonTracks, cfgCutKaPtMin); + fillMatrices(protonTracks, cfgCutPrPtMin); + + if (cfgApplyEfficiencyCorrection) { + fillCorrectedMatrices(chargedTracksCorrected, cfgCutPtMin); + fillCorrectedMatrices(pionTracksCorrected, cfgCutPiPtMin); + fillCorrectedMatrices(kaonTracksCorrected, cfgCutKaPtMin); + fillCorrectedMatrices(protonTracksCorrected, cfgCutPrPtMin); + if constexpr (RecoFlag) { + if (!cfgUseCombinedPurityEfficiencyWeight) { + fillCorrectedMatrices(chargedTracksTruthMatchedCorrected, cfgCutPtMin); + fillCorrectedMatrices(pionTracksTruthMatchedCorrected, cfgCutPiPtMin); + fillCorrectedMatrices(kaonTracksTruthMatchedCorrected, cfgCutKaPtMin); + fillCorrectedMatrices(protonTracksTruthMatchedCorrected, cfgCutPrPtMin); + } + } + } + } + + template + int countSimMultiplicity(M const& mcParticles) + { + int multiplicity = 0; + for (auto const& mcPart : mcParticles) { + if (!mcPart.isPhysicalPrimary() || std::abs(mcPart.eta()) >= cfgCutEta) { + continue; + } + auto* particle = pdg->GetParticle(mcPart.pdgCode()); + if (particle && particle->Charge() != 0.) { + ++multiplicity; + } + } + return multiplicity; + } + + bool passesNtpcEventCut() + { + if (!cfgNtpcEventCut) { + return true; + } + const float lower = cfgP2L * nSim * nSim + cfgP1L * nSim - cfgP0L; + const float upper = cfgP2U * nSim * nSim + cfgP1U * nSim + cfgP0U; + return nTPC >= lower && nTPC <= upper; } template @@ -1102,10 +1332,9 @@ struct MeanPtFlucId { pionTracksGen.clear(); kaonTracksGen.clear(); protonTracksGen.clear(); + nSim = 0; - int nChSim = 0, nPiSim = 0, nKaSim = 0, nPrSim = 0; float pt = 0., eta = 0, phi = 0., rap = 0.; - double q1Ch = 0., q2Ch = 0., q1Pi = 0., q2Pi = 0., q1Ka = 0., q2Ka = 0., q1Pr = 0., q2Pr = 0.; for (auto const& mcPart : mcParticles) { if (!mcPart.isPhysicalPrimary()) { continue; @@ -1113,11 +1342,13 @@ struct MeanPtFlucId { auto* particle = pdg->GetParticle(mcPart.pdgCode()); - if (!particle) + if (!particle) { continue; + } - if (particle->Charge() == 0) + if (particle->Charge() == 0) { continue; + } pt = mcPart.pt(); eta = mcPart.eta(); @@ -1127,15 +1358,10 @@ struct MeanPtFlucId { nSim++; } - auto pid = mcPart.pdgCode(); - if (std::abs(pid) != kElectron && std::abs(pid) != kMuonMinus && std::abs(pid) != kPiPlus && std::abs(pid) != kKPlus && std::abs(pid) != kProton) { - continue; - } - if (pt >= cfgCutPtMin && pt < cfgCutPtMax && std::abs(eta) < cfgCutEta) { - moments(pt, nChSim, q1Ch, q2Ch); - chargedTracksGen.push_back({pt, eta}); + chargedTracksGen.push_back({pt}); hist.fill(HIST("Gen/Charged/h_PtTruth"), pt); + hist.fill(HIST("Gen/Charged/h_PtTruth_e"), pt); hist.fill(HIST("Gen/Charged/h_EtaTruth"), eta); hist.fill(HIST("Gen/Charged/h_PhiTruth"), phi); hist.fill(HIST("Gen/Charged/h2_Pt_EtaTruth"), eta, pt); @@ -1144,32 +1370,26 @@ struct MeanPtFlucId { hist.fill(HIST("Gen/Charged/h3_Pt_Eta_PhiTruth"), pt, eta, phi); rap = mcPart.y(); + auto pid = mcPart.pdgCode(); if (std::abs(pid) == kPiPlus && pt >= cfgCutPiPtMin) { - moments(pt, nPiSim, q1Pi, q2Pi); - pionTracksGen.push_back({pt, eta}); - fillPtMCHist(true, pt, eta, rap, phi, pid, kPiMinus, kPiMinus); + pionTracksGen.push_back({pt}); + fillPtMCHist(true, pt, eta, rap, phi, pid, kPiPlus, kPiMinus); } if (std::abs(pid) == kKPlus && pt >= cfgCutKaPtMin) { - moments(pt, nKaSim, q1Ka, q2Ka); - kaonTracksGen.push_back({pt, eta}); - fillPtMCHist(true, pt, eta, rap, phi, pid, kKMinus, kKMinus); + kaonTracksGen.push_back({pt}); + fillPtMCHist(true, pt, eta, rap, phi, pid, kKPlus, kKMinus); } if (std::abs(pid) == kProton && pt >= cfgCutPrPtMin) { - moments(pt, nPrSim, q1Pr, q2Pr); - protonTracksGen.push_back({pt, eta}); - fillPtMCHist(true, pt, eta, rap, phi, pid, kProtonBar, kProtonBar); + protonTracksGen.push_back({pt}); + fillPtMCHist(true, pt, eta, rap, phi, pid, kProton, kProtonBar); } } } - fillDifferentialMatrices(chargedTracksGen, ptBins.value); - fillDifferentialMatrices(pionTracksGen, ptBinsPi.value); - fillDifferentialMatrices(kaonTracksGen, ptBinsKa.value); - fillDifferentialMatrices(protonTracksGen, ptBinsPr.value); - fillAnalysis(nChSim, q1Ch, q2Ch); - fillAnalysis(nPiSim, q1Pi, q2Pi); - fillAnalysis(nKaSim, q1Ka, q2Ka); - fillAnalysis(nPrSim, q1Pr, q2Pr); + fillMatrices(chargedTracksGen, cfgCutPtMin); + fillMatrices(pionTracksGen, cfgCutPiPtMin); + fillMatrices(kaonTracksGen, cfgCutKaPtMin); + fillMatrices(protonTracksGen, cfgCutPrPtMin); hist.fill(HIST("Gen/h_Counts"), 2); hist.fill(HIST("Gen/h_VtxZ"), mcCol.posZ()); @@ -1200,6 +1420,14 @@ struct MeanPtFlucId { hist.fill(HIST("Gen/h_collisions_info"), kPassSelCol); hist.fill(HIST("Gen/h2_collision_posZ"), mcCol.posZ(), cols.begin().posZ()); + // The generated and reconstructed moments must be evaluated for the same + // event ensemble. Determine nSim and apply the correlated multiplicity cut + // before filling either level. + nSim = countSimMultiplicity(mcParts); + if (!passesNtpcEventCut()) { + return; + } + auto sTracks = tracks.sliceBy(perCollision, cols.begin().globalIndex()); fillGenHistos(mcCol, mcParts); fillRecoHistos(cols.begin(), sTracks); @@ -1209,8 +1437,8 @@ struct MeanPtFlucId { aod::pidTOFFullPi, aod::pidTPCFullPi, aod::pidTOFFullPr, aod::pidTPCFullPr, aod::pidTOFFullKa, aod::pidTPCFullKa, aod::pidTOFFullEl, aod::pidTPCFullEl, aod::pidTOFbeta, aod::pidTOFmass>; - using MyRun3Collisions = soa::Join; - using MyRun3MCCollisions = soa::Join; + using MyRun3Collisions = soa::Join; + using MyRun3MCCollisions = soa::Join; using MyMCTracks = soa::Join(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(context)}; } diff --git a/PWGCF/EbyEFluctuations/Tasks/MeanptFluctuations.cxx b/PWGCF/EbyEFluctuations/Tasks/meanptFluctuations.cxx similarity index 86% rename from PWGCF/EbyEFluctuations/Tasks/MeanptFluctuations.cxx rename to PWGCF/EbyEFluctuations/Tasks/meanptFluctuations.cxx index e6a2d4c1225..6181d4a8b3f 100644 --- a/PWGCF/EbyEFluctuations/Tasks/MeanptFluctuations.cxx +++ b/PWGCF/EbyEFluctuations/Tasks/meanptFluctuations.cxx @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file MeanptFluctuations.cxx +/// \file meanptFluctuations.cxx /// \brief Task for analyzing fluctuation upto fourth order of inclusive hadrons /// \author Swati Saha @@ -34,7 +34,6 @@ #include #include -#include #include #include #include @@ -56,9 +55,9 @@ 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}; +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, (DEFAULT), (HELP)}; -struct MeanptFluctuationsAnalysis { +struct MeanptFluctuations { // MC Configurable cfgIsMC{"cfgIsMC", true, "Run MC"}; @@ -89,6 +88,7 @@ struct MeanptFluctuationsAnalysis { Configurable cfgEvSelkNoTimeFrameBorder{"cfgEvSelkNoTimeFrameBorder", true, "TimeFrame border event selection cut"}; Configurable cfgEvSelUseGoodZvtxFT0vsPV{"cfgEvSelUseGoodZvtxFT0vsPV", true, "GoodZvertex and FT0 vs PV cut"}; Configurable cfgCentralityEstimator{"cfgCentralityEstimator", 1, "Centrlaity estimatore choice: 1-->FT0C, 2-->FT0A; 3-->FT0M, 4-->FV0A"}; + Configurable cfgUseParticlePDGsInProcessMcReco{"cfgUseParticlePDGsInProcessMcReco", true, "Check partcile PDG codes in reco"}; // pT dep DCAxy and DCAz cuts Configurable cfgUsePtDepDCAxy{"cfgUsePtDepDCAxy", true, "Use pt-dependent DCAxy cut"}; @@ -144,7 +144,7 @@ struct MeanptFluctuationsAnalysis { Filter trackFilter = (nabs(aod::track::eta) < cfgCutPreSelEta) && (aod::track::pt > cfgCutPtLower) && (aod::track::pt < cfgCutPreSelPt) && (requireGlobalTrackInFilter()) && (aod::track::tpcChi2NCl < cfgCutTpcChi2NCl) && (aod::track::itsChi2NCl < cfgCutItsChi2NCl) && (nabs(aod::track::dcaZ) < cfgCutTrackDcaZ); // Connect to ccdb - Service ccdb; + Service ccdb{}; Configurable ccdbnolaterthan{"ccdbnolaterthan", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; Configurable ccdburl{"ccdburl", "http://ccdb-test.cern.ch:8080", "url of the ccdb repository"}; @@ -225,6 +225,7 @@ struct MeanptFluctuationsAnalysis { histos.add("AnalysisProfiles/Prof_skew_t1", "", {HistType::kTProfile2D, {centAxis, multAxis}}); histos.add("AnalysisProfiles/Prof_kurt_t1", "", {HistType::kTProfile2D, {centAxis, multAxis}}); histos.add("AnalysisProfiles/Hist2D_Nch_centrality", "", {HistType::kTH2D, {centAxis, multAxis}}); + histos.add("AnalysisProfiles/Hist2D_Ngen_centrality", "", {HistType::kTH2D, {centAxis, multAxis}}); histos.add("AnalysisProfiles/Hist2D_meanpt_centrality", "", {HistType::kTH2D, {centAxis, meanpTAxis}}); // Analysis Profiles for error (reconstructed data) @@ -319,21 +320,21 @@ struct MeanptFluctuationsAnalysis { cfgFuncParas.multGlobalPVCutPars = cfgFuncParas.cfgMultGlobalPVCutPars; cfgFuncParas.multMultV0ACutPars = cfgFuncParas.cfgMultMultV0ACutPars; cfgFuncParas.fMultPVT0CCutLow = new TF1("fMultPVT0CCutLow", cfgFuncParas.cfgMultCentLowCutFunction->c_str(), 0, 100); - cfgFuncParas.fMultPVT0CCutLow->SetParameters(&(cfgFuncParas.multPVT0CCutPars[0])); + cfgFuncParas.fMultPVT0CCutLow->SetParameters(cfgFuncParas.multPVT0CCutPars.data()); cfgFuncParas.fMultPVT0CCutHigh = new TF1("fMultPVT0CCutHigh", cfgFuncParas.cfgMultCentHighCutFunction->c_str(), 0, 100); - cfgFuncParas.fMultPVT0CCutHigh->SetParameters(&(cfgFuncParas.multPVT0CCutPars[0])); + cfgFuncParas.fMultPVT0CCutHigh->SetParameters(cfgFuncParas.multPVT0CCutPars.data()); cfgFuncParas.fMultT0CCutLow = new TF1("fMultT0CCutLow", cfgFuncParas.cfgMultCentLowCutFunction->c_str(), 0, 100); - cfgFuncParas.fMultT0CCutLow->SetParameters(&(cfgFuncParas.multT0CCutPars[0])); + cfgFuncParas.fMultT0CCutLow->SetParameters(cfgFuncParas.multT0CCutPars.data()); cfgFuncParas.fMultT0CCutHigh = new TF1("fMultT0CCutHigh", cfgFuncParas.cfgMultCentHighCutFunction->c_str(), 0, 100); - cfgFuncParas.fMultT0CCutHigh->SetParameters(&(cfgFuncParas.multT0CCutPars[0])); + cfgFuncParas.fMultT0CCutHigh->SetParameters(cfgFuncParas.multT0CCutPars.data()); cfgFuncParas.fMultGlobalPVCutLow = new TF1("fMultGlobalPVCutLow", cfgFuncParas.cfgMultMultPVLowCutFunction->c_str(), 0, 4000); - cfgFuncParas.fMultGlobalPVCutLow->SetParameters(&(cfgFuncParas.multGlobalPVCutPars[0])); + cfgFuncParas.fMultGlobalPVCutLow->SetParameters(cfgFuncParas.multGlobalPVCutPars.data()); cfgFuncParas.fMultGlobalPVCutHigh = new TF1("fMultGlobalPVCutHigh", cfgFuncParas.cfgMultMultPVHighCutFunction->c_str(), 0, 4000); - cfgFuncParas.fMultGlobalPVCutHigh->SetParameters(&(cfgFuncParas.multGlobalPVCutPars[0])); + cfgFuncParas.fMultGlobalPVCutHigh->SetParameters(cfgFuncParas.multGlobalPVCutPars.data()); cfgFuncParas.fMultMultV0ACutLow = new TF1("fMultMultV0ACutLow", cfgFuncParas.cfgMultMultV0ALowCutFunction->c_str(), 0, 4000); - cfgFuncParas.fMultMultV0ACutLow->SetParameters(&(cfgFuncParas.multMultV0ACutPars[0])); + cfgFuncParas.fMultMultV0ACutLow->SetParameters(cfgFuncParas.multMultV0ACutPars.data()); cfgFuncParas.fMultMultV0ACutHigh = new TF1("fMultMultV0ACutHigh", cfgFuncParas.cfgMultMultV0AHighCutFunction->c_str(), 0, 4000); - cfgFuncParas.fMultMultV0ACutHigh->SetParameters(&(cfgFuncParas.multMultV0ACutPars[0])); + cfgFuncParas.fMultMultV0ACutHigh->SetParameters(cfgFuncParas.multMultV0ACutPars.data()); cfgFuncParas.fT0AV0AMean = new TF1("fT0AV0AMean", "[0]+[1]*x", 0, 200000); cfgFuncParas.fT0AV0AMean->SetParameters(-1601.0581, 9.417652e-01); cfgFuncParas.fT0AV0ASigma = new TF1("fT0AV0ASigma", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 200000); @@ -350,7 +351,7 @@ struct MeanptFluctuationsAnalysis { } //! end init function template - bool eventSelected(TCollision collision, const int& multTrk, const float& centrality) + bool eventSelected(TCollision const& collision, const int multTrk, const float centrality) { if (collision.alias_bit(kTVXinTRD)) { // TRD triggered @@ -362,71 +363,87 @@ struct MeanptFluctuationsAnalysis { float zRes = std::sqrt(collision.covZZ()); float zResMax = 0.25; float numContribMin = 20; - if (zRes > zResMax && collision.numContrib() < numContribMin) + if (zRes > zResMax && collision.numContrib() < numContribMin) { vtxz = -999; + } } auto multNTracksPV = collision.multNTracksPV(); - if ((vtxz > cfgCutVertex) || (vtxz < -1.0 * cfgCutVertex)) + if ((vtxz > cfgCutVertex) || (vtxz < -1.0 * cfgCutVertex)) { return 0; - if (multNTracksPV < fMultPVCutLow->Eval(centrality)) + } + if (multNTracksPV < fMultPVCutLow->Eval(centrality)) { return 0; - if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) + } + if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) { return 0; - if (multTrk < fMultCutLow->Eval(centrality)) + } + if (multTrk < fMultCutLow->Eval(centrality)) { return 0; - if (multTrk > fMultCutHigh->Eval(centrality)) + } + if (multTrk > fMultCutHigh->Eval(centrality)) { return 0; - if (multTrk > fMultMultPVCut->Eval(multNTracksPV)) + } + if (multTrk > fMultMultPVCut->Eval(multNTracksPV)) { return 0; + } return 1; } template - bool eventSelectedSmallion(TCollision collision, const int multTrk, const float centrality) + bool eventSelectedSmallion(TCollision const& collision, const int multTrk, const float centrality) { auto multNTracksPV = collision.multNTracksPV(); if (cfgEvSelMultCorrelation) { if (cfgFuncParas.cfgMultPVT0CCutEnabled) { - if (multNTracksPV < cfgFuncParas.fMultPVT0CCutLow->Eval(centrality)) + if (multNTracksPV < cfgFuncParas.fMultPVT0CCutLow->Eval(centrality)) { return 0; - if (multNTracksPV > cfgFuncParas.fMultPVT0CCutHigh->Eval(centrality)) + } + if (multNTracksPV > cfgFuncParas.fMultPVT0CCutHigh->Eval(centrality)) { return 0; + } } if (cfgFuncParas.cfgMultT0CCutEnabled) { - if (multTrk < cfgFuncParas.fMultT0CCutLow->Eval(centrality)) + if (multTrk < cfgFuncParas.fMultT0CCutLow->Eval(centrality)) { return 0; - if (multTrk > cfgFuncParas.fMultT0CCutHigh->Eval(centrality)) + } + if (multTrk > cfgFuncParas.fMultT0CCutHigh->Eval(centrality)) { return 0; + } } if (cfgFuncParas.cfgMultGlobalPVCutEnabled) { - if (multTrk < cfgFuncParas.fMultGlobalPVCutLow->Eval(multNTracksPV)) + if (multTrk < cfgFuncParas.fMultGlobalPVCutLow->Eval(multNTracksPV)) { return 0; - if (multTrk > cfgFuncParas.fMultGlobalPVCutHigh->Eval(multNTracksPV)) + } + if (multTrk > cfgFuncParas.fMultGlobalPVCutHigh->Eval(multNTracksPV)) { return 0; + } } if (cfgFuncParas.cfgMultMultV0ACutEnabled) { - if (collision.multFV0A() < cfgFuncParas.fMultMultV0ACutLow->Eval(multTrk)) + if (collision.multFV0A() < cfgFuncParas.fMultMultV0ACutLow->Eval(multTrk)) { return 0; - if (collision.multFV0A() > cfgFuncParas.fMultMultV0ACutHigh->Eval(multTrk)) + } + if (collision.multFV0A() > cfgFuncParas.fMultMultV0ACutHigh->Eval(multTrk)) { return 0; + } } } float sigma = 5.0; - if (cfgEvSelV0AT0ACut && (std::fabs(collision.multFV0A() - cfgFuncParas.fT0AV0AMean->Eval(collision.multFT0A())) > sigma * cfgFuncParas.fT0AV0ASigma->Eval(collision.multFT0A()))) + if (cfgEvSelV0AT0ACut && (std::fabs(collision.multFV0A() - cfgFuncParas.fT0AV0AMean->Eval(collision.multFT0A())) > sigma * cfgFuncParas.fT0AV0ASigma->Eval(collision.multFT0A()))) { return 0; + } return 1; } template - bool eventSelectionDefaultCuts(TCollision coll) + bool eventSelectionDefaultCuts(TCollision const& coll) { histos.fill(HIST("hEventStatData"), 0.5); if (!coll.sel8()) { @@ -490,7 +507,7 @@ struct MeanptFluctuationsAnalysis { if (std::abs(mcCollision.posZ()) < cfgCutVertex) { histos.fill(HIST("MCGenerated/hMC"), 1.5); } - auto cent = 0; + auto cent = 0.0f; int nchInel = 0; for (const auto& mcParticle : mcParticles) { @@ -501,8 +518,9 @@ struct MeanptFluctuationsAnalysis { } } } - if (nchInel > 0 && std::abs(mcCollision.posZ()) < cfgCutVertex) + if (nchInel > 0 && std::abs(mcCollision.posZ()) < cfgCutVertex) { histos.fill(HIST("MCGenerated/hMC"), 2.5); + } std::vector selectedEvents(collisions.size()); int nevts = 0; @@ -557,15 +575,19 @@ struct MeanptFluctuationsAnalysis { float nChgen = 0.0; for (const auto& mcParticle : mcParticles) { - if (!mcParticle.has_mcCollision()) + if (!mcParticle.has_mcCollision()) { continue; + } // charged check - auto pdgEntry = TDatabasePDG::Instance()->GetParticle(mcParticle.pdgCode()); - if (!pdgEntry) - continue; - if (pdgEntry->Charge() == 0) - continue; + auto pdgcode = std::abs(mcParticle.pdgCode()); + if (pdgcode != PDG_t::kPiPlus && + pdgcode != PDG_t::kKPlus && + pdgcode != PDG_t::kProton && + pdgcode != PDG_t::kElectron && + pdgcode != PDG_t::kMuonMinus) { + continue; // skip this track + } if (mcParticle.isPhysicalPrimary()) { if ((mcParticle.pt() > cfgCutPtLower) && (mcParticle.pt() < cfgCutPreSelPt) && (std::abs(mcParticle.eta()) < cfgCutPreSelEta)) { @@ -589,8 +611,9 @@ struct MeanptFluctuationsAnalysis { } //! end particle loop // Generated MeanPt distribution - if (nNgen > 0.0f) + if (nNgen > 0.0f) { histos.fill(HIST("MCGenerated/hMeanPt"), cent, pTsumgen / nNgen); + } // calculating observables if (nChgen > cfgMinNch) { @@ -627,72 +650,120 @@ struct MeanptFluctuationsAnalysis { } //------------------------------------------------------------------------------------------- } - PROCESS_SWITCH(MeanptFluctuationsAnalysis, processMCGen, "Process Generated MC data", true); + PROCESS_SWITCH(MeanptFluctuations, processMCGen, "Process Generated MC data", true); - void processMCRec(MyMCRecCollisions::iterator const& collision, MyMCTracks const& tracks, aod::McCollisions const&, aod::McParticles const& mcParticles) + void processMCRec(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles, const soa::SmallGroups& collisions, MyMCTracks const& tracks) { histos.fill(HIST("MCGenerated/hMC"), 5.5); - if (!collision.has_mcCollision()) { - return; + if (collisions.size() == 0) { + return; // this generated event was never reconstructed at all } + histos.fill(HIST("MCGenerated/hMC"), 6.5); - if (!eventSelectionDefaultCuts(collision)) { + std::vector selectedEvents(collisions.size()); + int nevts = 0; + + for (const auto& collision : collisions) { + if (!collision.sel8() || std::abs(collision.mcCollision().posZ()) > cfgCutVertex) { + continue; + } + if (cfgUseGoodITSLayerAllCut && !(collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll))) { + continue; + } + if (cfgEvSelkNoSameBunchPileup && !(collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup))) { + continue; + } + if (cfgEvSelkNoITSROFrameBorder && !(collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder))) { + continue; + } + if (cfgEvSelkNoTimeFrameBorder && !(collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder))) { + continue; + } + if (cfgEvSelUseGoodZvtxFT0vsPV && !(collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV))) { + continue; + } + + auto rectrackspart = tracks.sliceBy(perCollision, collision.globalIndex()); + auto cent = collision.centFT0C(); + + fillMultCorrPlotsBeforeSel(collision, rectrackspart); + + if (cfgUseSmallIonAdditionalEventCutInMC && !eventSelectedSmallion(collision, rectrackspart.size(), cent)) { + continue; + } + + if (cfgUseSmallIonAdditionalEventCutInMC) { + fillMultCorrPlotsAfterSel(collision, rectrackspart); + } + + selectedEvents[nevts++] = collision.mcCollision_as().globalIndex(); + } + selectedEvents.resize(nevts); + const auto evtReconstructedAndSelected = std::find(selectedEvents.begin(), selectedEvents.end(), mcCollision.globalIndex()) != selectedEvents.end(); + + if (!evtReconstructedAndSelected) { // Check that the event is reconstructed and that the reconstructed events pass the selection return; } histos.fill(HIST("MCGenerated/hMC"), 7.5); - fillMultCorrPlotsBeforeSel(collision, tracks); - - const auto centralityFT0C = collision.centFT0C(); - if (cfgUse22sEventCut && !eventSelected(collision, tracks.size(), centralityFT0C)) - return; - if (cfgUseSmallIonAdditionalEventCut && !eventSelectedSmallion(collision, tracks.size(), centralityFT0C)) + auto bestColl = collisions.begin(); + bool foundValidColl = false; + for (auto const& coll : collisions) { + if (!foundValidColl || coll.numContrib() > bestColl.numContrib()) { + bestColl = coll; + foundValidColl = true; + } + } + if (!foundValidColl) { return; - - if (cfgUseSmallIonAdditionalEventCut) { - fillMultCorrPlotsAfterSel(collision, tracks); } - histos.fill(HIST("MCGenerated/hMC"), 8.5); - histos.fill(HIST("hZvtx_after_sel"), collision.posZ()); + + if (!bestColl.has_mcCollision()) { + return; + } + histos.fill(HIST("MCGenerated/hMC"), 9.5); double cent = 0.0; int centChoiceFT0C = 1; int centChoiceFT0A = 2; int centChoiceFT0M = 3; int centChoiceFV0A = 4; - if (cfgCentralityEstimator == centChoiceFT0C) - cent = collision.centFT0C(); - else if (cfgCentralityEstimator == centChoiceFT0A) - cent = collision.centFT0A(); - else if (cfgCentralityEstimator == centChoiceFT0M) - cent = collision.centFT0M(); - else if (cfgCentralityEstimator == centChoiceFV0A) - cent = collision.centFV0A(); + if (cfgCentralityEstimator == centChoiceFT0C) { + cent = bestColl.centFT0C(); + } else if (cfgCentralityEstimator == centChoiceFT0A) { + cent = bestColl.centFT0A(); + } else if (cfgCentralityEstimator == centChoiceFT0M) { + cent = bestColl.centFT0M(); + } else if (cfgCentralityEstimator == centChoiceFV0A) { + cent = bestColl.centFV0A(); + } histos.fill(HIST("hCentrality"), cent); + histos.fill(HIST("hZvtx_after_sel"), bestColl.posZ()); - histos.fill(HIST("Hist2D_globalTracks_PVTracks"), collision.multNTracksPV(), tracks.size()); - histos.fill(HIST("Hist2D_cent_nch"), tracks.size(), centralityFT0C); + auto tracksThisCollision = tracks.sliceBy(perCollision, bestColl.globalIndex()); + histos.fill(HIST("Hist2D_globalTracks_PVTracks"), bestColl.multNTracksPV(), tracksThisCollision.size()); + histos.fill(HIST("Hist2D_cent_nch"), tracksThisCollision.size(), cent); // Calculating generated no of particles for the collision event double noGen = 0.0; - auto mcColl = collision.mcCollision(); - // Slice particles belonging only to this MC collision - auto particlesThisEvent = mcParticles.sliceBy(perMcCollision, mcColl.globalIndex()); - - for (const auto& mcParticle : particlesThisEvent) { - if (!mcParticle.has_mcCollision()) + for (const auto& mcParticle : mcParticles) { + if (!mcParticle.has_mcCollision()) { continue; + } // charged check - auto pdgEntry = TDatabasePDG::Instance()->GetParticle(mcParticle.pdgCode()); - if (!pdgEntry) - continue; - if (pdgEntry->Charge() == 0) - continue; + auto pdgcode = std::abs(mcParticle.pdgCode()); + if (pdgcode != PDG_t::kPiPlus && + pdgcode != PDG_t::kKPlus && + pdgcode != PDG_t::kProton && + pdgcode != PDG_t::kElectron && + pdgcode != PDG_t::kMuonMinus) { + continue; // skip this track + } if (mcParticle.isPhysicalPrimary()) { if ((mcParticle.pt() > cfgCutPtLower) && (mcParticle.pt() < cfgCutPreSelPt) && (std::abs(mcParticle.eta()) < cfgCutPreSelEta)) { @@ -706,14 +777,13 @@ struct MeanptFluctuationsAnalysis { // variables double pTsum = 0.0; double nN = 0.0; - float q1 = 0.0; float q2 = 0.0; float q3 = 0.0; float q4 = 0.0; float nCh = 0.0; - for (const auto& track : tracks) { // Loop over tracks + for (const auto& track : tracksThisCollision) { // Loop over tracks if (!track.has_collision()) { continue; @@ -727,6 +797,21 @@ struct MeanptFluctuationsAnalysis { continue; } + if (particle.mcCollisionId() != mcCollision.globalIndex()) { // reject tracks whose true particle belongs to a DIFFERENT generated collision (pileup contamination in bestColl) + continue; + } + + if (cfgUseParticlePDGsInProcessMcReco) { + auto pdgPart = std::abs(particle.pdgCode()); + if (pdgPart != PDG_t::kPiPlus && + pdgPart != PDG_t::kKPlus && + pdgPart != PDG_t::kProton && + pdgPart != PDG_t::kElectron && + pdgPart != PDG_t::kMuonMinus) { + continue; // skip this track + } + } + if (!track.isPVContributor()) { continue; } @@ -777,8 +862,9 @@ struct MeanptFluctuationsAnalysis { histos.fill(HIST("MCGenerated/hNgenVsNrec"), noGen, nCh); // MeanPt - if (nN > 0.0f) + if (nN > 0.0f) { histos.fill(HIST("hMeanPt"), cent, pTsum / nN); + } // calculating observables if (nCh > cfgMinNch) { @@ -799,6 +885,7 @@ struct MeanptFluctuationsAnalysis { histos.get(HIST("AnalysisProfilesV2/Prof_var_t1"))->Fill(noGen, nCh, varianceTerm1); histos.get(HIST("AnalysisProfilesV2/Prof_skew_t1"))->Fill(noGen, nCh, skewnessTerm1); histos.get(HIST("AnalysisProfilesV2/Prof_kurt_t1"))->Fill(noGen, nCh, kurtosisTerm1); + histos.fill(HIST("AnalysisProfiles/Hist2D_Ngen_centrality"), cent, noGen); // selecting subsample and filling profiles float lRandom = fRndm->Rndm(); @@ -815,7 +902,7 @@ struct MeanptFluctuationsAnalysis { } //------------------------------------------------------------------------------------------- } - PROCESS_SWITCH(MeanptFluctuationsAnalysis, processMCRec, "Process MC Reconstructed Data", true); + PROCESS_SWITCH(MeanptFluctuations, processMCRec, "Process MC Reconstructed Data", true); // void process(aod::Collision const& coll, aod::Tracks const& inputTracks) void processData(AodCollisions::iterator const& coll, aod::BCsWithTimestamps const&, AodTracks const& inputTracks) @@ -827,10 +914,12 @@ struct MeanptFluctuationsAnalysis { fillMultCorrPlotsBeforeSel(coll, inputTracks); const auto centralityFT0C = coll.centFT0C(); - if (cfgUse22sEventCut && !eventSelected(coll, inputTracks.size(), centralityFT0C)) + if (cfgUse22sEventCut && !eventSelected(coll, inputTracks.size(), centralityFT0C)) { return; - if (cfgUseSmallIonAdditionalEventCut && !eventSelectedSmallion(coll, inputTracks.size(), centralityFT0C)) + } + if (cfgUseSmallIonAdditionalEventCut && !eventSelectedSmallion(coll, inputTracks.size(), centralityFT0C)) { return; + } if (cfgUseSmallIonAdditionalEventCut) { fillMultCorrPlotsAfterSel(coll, inputTracks); @@ -845,14 +934,15 @@ struct MeanptFluctuationsAnalysis { int centChoiceFT0A = 2; int centChoiceFT0M = 3; int centChoiceFV0A = 4; - if (cfgCentralityEstimator == centChoiceFT0C) + if (cfgCentralityEstimator == centChoiceFT0C) { cent = coll.centFT0C(); - else if (cfgCentralityEstimator == centChoiceFT0A) + } else if (cfgCentralityEstimator == centChoiceFT0A) { cent = coll.centFT0A(); - else if (cfgCentralityEstimator == centChoiceFT0M) + } else if (cfgCentralityEstimator == centChoiceFT0M) { cent = coll.centFT0M(); - else if (cfgCentralityEstimator == centChoiceFV0A) + } else if (cfgCentralityEstimator == centChoiceFV0A) { cent = coll.centFV0A(); + } histos.fill(HIST("hCentrality"), cent); @@ -916,8 +1006,9 @@ struct MeanptFluctuationsAnalysis { } } // MeanPt - if (nN > 0.0f) + if (nN > 0.0f) { histos.fill(HIST("hMeanPt"), cent, pTsum / nN); + } // calculating observables if (nCh > cfgMinNch) { @@ -944,12 +1035,12 @@ struct MeanptFluctuationsAnalysis { } //------------------------------------------------------------------------------------------- } - PROCESS_SWITCH(MeanptFluctuationsAnalysis, processData, "Process Real Data", true); + PROCESS_SWITCH(MeanptFluctuations, processData, "Process Real Data", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { // Equivalent to the AddTask in AliPhysics return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGCF/EbyEFluctuations/Tasks/multAndPtFluctuations.cxx b/PWGCF/EbyEFluctuations/Tasks/multAndPtFluctuations.cxx new file mode 100644 index 00000000000..2032d0e252a --- /dev/null +++ b/PWGCF/EbyEFluctuations/Tasks/multAndPtFluctuations.cxx @@ -0,0 +1,232 @@ +// 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. + +/// \file multAndPtFluctuations.cxx +/// \brief Calculate multiplicity and transverse momentum fluctuations using strongly intensive observables +/// \author Omama Rubza +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::aod; +using namespace o2::framework::expressions; + +struct MultAndPtFluctuations { + + // ------ Histogram binning + + Configurable nBinsPt{"nBinsPt", 100, "pT bins"}; + Configurable ndcaXY{"ndcaXY", 100, "DCAxy bins"}; + Configurable ndcaZ{"ndcaZ", 100, "DCAz bins"}; + Configurable nCentBins{"nCentBins", 100, "Number of centrality bins"}; + + // ------ Event Cuts + Configurable vtxZcut{"vtxZcut", 10.0f, "vertex Z"}; + Configurable cfgNoSameBunchPileup{"cfgNoSameBunchPileup", true, "kNoSameBunchPileup"}; + Configurable cfgEvSelUseGoodZvtxFT0vsPV{"cfgEvSelUseGoodZvtxFT0vsPV", true, "Good Zvtx FT0 vs PV"}; + Configurable cfgUseGoodITSLayerAllCut{"cfgUseGoodITSLayerAllCut", true, "Good ITS Layers"}; + + // ----- Centrality estimator + Configurable cFT0M{"cFT0M", false, "FT0M centrality"}; // for pp + Configurable cFT0C{"cFT0C", true, "Use FT0C centrality"}; + + // ------ Track cuts + Configurable ptMinCut{"ptMinCut", 0.2f, "Minimum pT"}; + Configurable ptMaxCut{"ptMaxCut", 5.0f, "Maximum pT"}; + Configurable etaCut{"etaCut", 0.8f, "Maximum |eta|"}; + Configurable itsNClsCut{"itsNClsCut", 4, "Minimum ITS clusters"}; + Configurable tpcCrossCut{"tpcCrossCut", 70.0f, "TPC crossed rows"}; + Configurable crossedRowsOverFindableCut{"crossedRowsOverFindableCut", 0.8f, "TPC crossed rows over findable"}; + Configurable dcaZCut{"dcaZCut", 2.0f, "Maximum DCAz"}; + Configurable dcaXYCut{"dcaXYCut", 0.2f, "Maximum DCAxy"}; + Configurable tpcChiCut{"tpcChiCut", 4.0f, "TPC chi2/NCls"}; + Configurable itsChiCut{"itsChiCut", 36.0f, "ITS chi2/NCls"}; + Configurable requireITS{"requireITS", true, "Require ITS hit"}; + Configurable requireTPC{"requireTPC", true, "Require TPC hit"}; + Configurable requireInnerITS{"requireInnerITS", true, "At least one hit in ITS layers 0,1,2"}; + + //----- Histogram Registry + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + void init(InitContext const&) + { + const AxisSpec axisEta{30, -1.5, +1.5, "#eta"}; + const AxisSpec axisPt{nBinsPt, 0.15, 10.0, "p_{T}"}; + const AxisSpec axisVtxz{80, -20, 20, "V_{Z} (cm)"}; + const AxisSpec axisPhi{40, -1, 7, "#phi"}; + const AxisSpec axisdcaXY{ndcaXY, -0.3, 0.3, "DCAxy"}; + const AxisSpec axisdcaZ{ndcaZ, -3.0, 3.0, "DCAz"}; + const AxisSpec axisNch{500, 0, 500, "Nch"}; + const AxisSpec axisCent{nCentBins, 0.0, 100.0, "Centrality (%)"}; // ------------- centrality bins + histos.add("QA/BeforeCut/VtxZ", "Vertex Z", kTH1F, {axisVtxz}); + histos.add("QA/AfterCut/VtxZ", "Vertex Z", kTH1F, {axisVtxz}); + histos.add("QA/BeforeCut/Cent", "Centrality", kTH1F, {axisCent}); + histos.add("QA/AfterCut/Cent", "Centrality", kTH1F, {axisCent}); + histos.add("QA/BeforeCut/Eta", "Eta", kTH1F, {axisEta}); + histos.add("QA/AfterCut/Eta", "Eta", kTH1F, {axisEta}); + histos.add("QA/BeforeCut/Pt", "Pt", kTH1F, {axisPt}); + histos.add("QA/AfterCut/Pt", "Pt", kTH1F, {axisPt}); + histos.add("QA/BeforeCut/Phi", "Phi", kTH1F, {axisPhi}); + histos.add("QA/AfterCut/Phi", "Phi", kTH1F, {axisPhi}); + histos.add("QA/BeforeCut/DcaXY", "DCAxy", kTH1F, {axisdcaXY}); + histos.add("QA/AfterCut/DcaXY", "DCAxy", kTH1F, {axisdcaXY}); + histos.add("QA/BeforeCut/DcaZ", "DCAz", kTH1F, {axisdcaZ}); + histos.add("QA/AfterCut/DcaZ", "DCAz", kTH1F, {axisdcaZ}); + histos.add("hNch", "Nch", kTH1F, {axisNch}); + histos.add("h2_DcaZ", "DCA_{Z}", kTH2D, {{axisPt}, {axisdcaZ}}); + histos.add("h2_DcaXY", "DCA_{XY}", kTH2D, {{axisPt}, {axisdcaXY}}); + histos.add("hEventCounter", "Number of events vs centrality", kTH1F, {axisCent}); + histos.add("p_a", " vs centrality", kTProfile, {axisCent}); + histos.add("p_b", " vs centrality", kTProfile, {axisCent}); + histos.add("p_a2", " vs centrality", kTProfile, {axisCent}); + histos.add("p_b2", " vs centrality", kTProfile, {axisCent}); + histos.add("p_ab", " vs centrality", kTProfile, {axisCent}); + histos.add("p_asumb", " vs centrality", kTProfile, {axisCent}); + } + + //---------- Filters + Filter ptFilter = (aod::track::pt > ptMinCut) && (aod::track::pt < ptMaxCut); + Filter etaFilter = nabs(aod::track::eta) < etaCut; + Filter posZFilter = nabs(aod::collision::posZ) < vtxZcut; + + using MyColsData = soa::Join; + using MyTracksData = soa::Join; + using MyFilteredTracksData = soa::Filtered; + + void process(MyColsData::iterator const& col, MyFilteredTracksData const& tracks) + { + histos.fill(HIST("QA/BeforeCut/VtxZ"), col.posZ()); + float cent = -1.0f; + if (cFT0M) { + cent = col.centFT0M(); + } + if (cFT0C) { + cent = col.centFT0C(); + // if (!track.isGlobalTrack()) continue; + } + if (cent < 0) { + return; + } + + histos.fill(HIST("QA/BeforeCut/Cent"), cent); + if (!col.sel8()) { + return; + } + if (std::abs(col.posZ()) > vtxZcut) { + return; + } + if (cfgNoSameBunchPileup && !col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return; + } + if (cfgEvSelUseGoodZvtxFT0vsPV && !col.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return; + } + if (cfgUseGoodITSLayerAllCut && !col.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return; + } + + histos.fill(HIST("hEventCounter"), cent); + histos.fill(HIST("QA/AfterCut/VtxZ"), col.posZ()); + histos.fill(HIST("QA/AfterCut/Cent"), cent); + + double a = 0.0; + double b = 0.0; + + // if (!track.isGlobalTrack()) continue; + for (const auto& track : tracks) { + + histos.fill(HIST("QA/BeforeCut/Eta"), track.eta()); + histos.fill(HIST("QA/BeforeCut/Pt"), track.pt()); + histos.fill(HIST("QA/BeforeCut/Phi"), track.phi()); + histos.fill(HIST("QA/BeforeCut/DcaXY"), track.dcaXY()); + histos.fill(HIST("QA/BeforeCut/DcaZ"), track.dcaZ()); + + // Track quality cuts + + if (requireITS && !track.hasITS()) { + continue; + } + if (requireTPC && !track.hasTPC()) { + continue; + } + if (track.itsNCls() < itsNClsCut) { + continue; + } + if (track.tpcNClsCrossedRows() < tpcCrossCut) { + continue; + } + if (track.tpcCrossedRowsOverFindableCls() < crossedRowsOverFindableCut) { + continue; + } + if (std::abs(track.dcaZ()) > dcaZCut) { + continue; + } + if (std::abs(track.dcaXY()) > dcaXYCut) { + continue; + } + if (track.tpcChi2NCl() > tpcChiCut) { + continue; + } + if (track.itsChi2NCl() > itsChiCut) { + continue; + } + if (std::abs(track.eta()) > etaCut) { + continue; + } + if (requireInnerITS) { + auto itsMap = track.itsClusterMap(); + if (((itsMap & (1 << 0)) == 0) && + ((itsMap & (1 << 1)) == 0) && + ((itsMap & (1 << 2)) == 0)) { + continue; + } + } + + // After cuts QA + histos.fill(HIST("QA/AfterCut/Eta"), track.eta()); + histos.fill(HIST("QA/AfterCut/Pt"), track.pt()); + histos.fill(HIST("QA/AfterCut/Phi"), track.phi()); + histos.fill(HIST("QA/AfterCut/DcaXY"), track.dcaXY()); + histos.fill(HIST("QA/AfterCut/DcaZ"), track.dcaZ()); + histos.fill(HIST("h2_DcaZ"), track.pt(), track.dcaZ()); + histos.fill(HIST("h2_DcaXY"), track.pt(), track.dcaXY()); + a++; // A-nch, B =pt + b += track.pt(); + } + + // ---- Fill TProfiles (once per event) + histos.fill(HIST("p_a"), cent, a); + histos.fill(HIST("p_b"), cent, b); + histos.fill(HIST("p_a2"), cent, a * a); + histos.fill(HIST("p_b2"), cent, b * b); + histos.fill(HIST("p_ab"), cent, a * b); + histos.fill(HIST("p_asumb"), cent, a + b); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/EbyEFluctuations/Tasks/nchCumulantsId.cxx b/PWGCF/EbyEFluctuations/Tasks/nchCumulantsId.cxx index 027f38957c9..d19f975b2e3 100644 --- a/PWGCF/EbyEFluctuations/Tasks/nchCumulantsId.cxx +++ b/PWGCF/EbyEFluctuations/Tasks/nchCumulantsId.cxx @@ -68,8 +68,15 @@ constexpr int McBitPR = 2; constexpr int McBitEL = 3; constexpr int McBitDE = 4; -#define BITSET(mask, ithBit) ((mask) |= (1 << (ithBit))) // avoid name bitset as std::bitset is already there -#define BITCHECK(mask, ithBit) ((mask) & (1 << (ithBit))) // bit check will return int value, not bool, use BITCHECK != 0 in Analysi +constexpr void BITSET(int& mask, int ithBit) +{ + mask |= (1 << ithBit); +} + +constexpr bool BITCHECK(int mask, int ithBit) +{ + return (mask & (1 << ithBit)) != 0; +} enum PidEnum { kCh = 0, @@ -212,6 +219,10 @@ struct NchCumulantsId { ConfigurableAxis subSampleAxis{"subSampleAxis", {10, 0., 10.}, "Subsample"}; TRandom3* fRandom = new TRandom3(0); // Random number generator for subsampling int currentSubsample = 0; + Configurable cfgCutPtMinKa{"cfgCutPtMinKa", 0.30, "min pT for kaon eff-correction inclusion"}; + Configurable cfgCutPtMaxKa{"cfgCutPtMaxKa", 1.20, "max pT for kaon eff-correction inclusion (purity cutoff)"}; + Configurable cfgCutPtMinPr{"cfgCutPtMinPr", 0.40, "min pT for proton eff-correction inclusion"}; + Configurable cfgCutPtMaxPr{"cfgCutPtMaxPr", 1.50, "max pT for proton eff-correction inclusion (purity cutoff)"}; } cfgEventSelection; // Configurables for particle Identification @@ -297,9 +308,11 @@ struct NchCumulantsId { double q4 = 0.; }; + static constexpr float KmaxWeight = 10.0f; // secondary safeguard for pr and kaon eff fix + inline void fillEffPower(EffPowerSums& p, float weight) { - if (weight <= 0.f) { + if (weight <= 0.f || weight > KmaxWeight) { return; } @@ -1008,28 +1021,20 @@ struct NchCumulantsId { { switch (pidMode) { case kPi: - if (std::fabs(track.tpcNSigmaPi()) < nSigmaTPC && - std::fabs(track.tofNSigmaPi()) < nSigmaTOF) { - return true; - } - break; + return std::fabs(track.tpcNSigmaPi()) < nSigmaTPC && + std::fabs(track.tofNSigmaPi()) < nSigmaTOF; + case kKa: - if (std::fabs(track.tpcNSigmaKa()) < nSigmaTPC && - std::fabs(track.tofNSigmaKa()) < nSigmaTOF) { - return true; - } - break; + return std::fabs(track.tpcNSigmaKa()) < nSigmaTPC && + std::fabs(track.tofNSigmaKa()) < nSigmaTOF; + case kPr: - if (std::fabs(track.tpcNSigmaPr()) < nSigmaTPC && - std::fabs(track.tofNSigmaPr()) < nSigmaTOF) { - return true; - } - break; + return std::fabs(track.tpcNSigmaPr()) < nSigmaTPC && + std::fabs(track.tofNSigmaPr()) < nSigmaTOF; + default: return false; - break; } - return false; } template @@ -1037,25 +1042,23 @@ struct NchCumulantsId { { switch (pidMode) { case kPi: - if (std::pow(track.tpcNSigmaPi() / nSigmaTPC, 2) + std::pow(track.tofNSigmaPi() / nSigmaTOF, 2) < 1.0) { - return true; - } - break; + return std::pow(track.tpcNSigmaPi() / nSigmaTPC, 2) + + std::pow(track.tofNSigmaPi() / nSigmaTOF, 2) < + 1.0; + case kKa: - if (std::pow(track.tpcNSigmaKa() / nSigmaTPC, 2) + std::pow(track.tofNSigmaKa() / nSigmaTOF, 2) < 1.0) { - return true; - } - break; + return std::pow(track.tpcNSigmaKa() / nSigmaTPC, 2) + + std::pow(track.tofNSigmaKa() / nSigmaTOF, 2) < + 1.0; + case kPr: - if (std::pow(track.tpcNSigmaPr() / nSigmaTPC, 2) + std::pow(track.tofNSigmaPr() / nSigmaTOF, 2) < 1.0) { - return true; - } - break; + return std::pow(track.tpcNSigmaPr() / nSigmaTPC, 2) + + std::pow(track.tofNSigmaPr() / nSigmaTOF, 2) < + 1.0; + default: return false; - break; } - return false; } template @@ -1196,13 +1199,10 @@ struct NchCumulantsId { template bool selTrackForId(const T& track) { - if (cfgIdElRejLowNSigma < track.tpcNSigmaEl() && track.tpcNSigmaEl() < cfgIdElRejHighNSigma && - std::fabs(track.tpcNSigmaPi()) > cfgIdPiRejNSigma && - std::fabs(track.tpcNSigmaKa()) > cfgIdKaRejNSigma && - std::fabs(track.tpcNSigmaPr()) > cfgIdPrRejNSigma) { - return false; - } - return true; + return !(cfgIdElRejLowNSigma < track.tpcNSigmaEl() && track.tpcNSigmaEl() < cfgIdElRejHighNSigma && + std::fabs(track.tpcNSigmaPi()) > cfgIdPiRejNSigma && + std::fabs(track.tpcNSigmaKa()) > cfgIdKaRejNSigma && + std::fabs(track.tpcNSigmaPr()) > cfgIdPrRejNSigma); } // Pion @@ -1999,19 +1999,27 @@ struct NchCumulantsId { fillGenTrackQA(genAnalysis, mcTrack); } else if (pdg == kKPlus) { // fillGenTrackQA(genAnalysis, mcTrack); - nKaGen++; + if (mcTrack.pt() >= cfgEventSelection.cfgCutPtMinKa && mcTrack.pt() <= cfgEventSelection.cfgCutPtMaxKa) { + nKaGen++; + } fillGenTrackQA(genAnalysis, mcTrack); } else if (pdg == kKMinus) { // fillGenTrackQA(genAnalysis, mcTrack); - nAKaGen++; + if (mcTrack.pt() >= cfgEventSelection.cfgCutPtMinKa && mcTrack.pt() <= cfgEventSelection.cfgCutPtMaxKa) { + nAKaGen++; + } fillGenTrackQA(genAnalysis, mcTrack); } else if (pdg == kProton) { // fillGenTrackQA(genAnalysis, mcTrack); - nPrGen++; + if (mcTrack.pt() >= cfgEventSelection.cfgCutPtMinPr && mcTrack.pt() <= cfgEventSelection.cfgCutPtMaxPr) { + nPrGen++; + } fillGenTrackQA(genAnalysis, mcTrack); } else if (pdg == kProtonBar) { // fillGenTrackQA(genAnalysis, mcTrack); - nAPrGen++; + if (mcTrack.pt() >= cfgEventSelection.cfgCutPtMinPr && mcTrack.pt() <= cfgEventSelection.cfgCutPtMaxPr) { + nAPrGen++; + } fillGenTrackQA(genAnalysis, mcTrack); } @@ -2176,15 +2184,19 @@ struct NchCumulantsId { } } else if (trackIsKaon) { if (track.sign() > 0) { - nKaRec += hPtEtaForEffCorrection[kKa][kPos]->GetBinContent(ptEtaBin); fillRecoTrackQA(recoAnalysis, track); - float weight = hPtEtaForEffCorrection[kKa][kPos]->GetBinContent(ptEtaBin); - fillEffPower(kapPow, weight); + if (track.pt() >= cfgEventSelection.cfgCutPtMinKa && track.pt() <= cfgEventSelection.cfgCutPtMaxKa) { + nKaRec += hPtEtaForEffCorrection[kKa][kPos]->GetBinContent(ptEtaBin); + float weight = hPtEtaForEffCorrection[kKa][kPos]->GetBinContent(ptEtaBin); + fillEffPower(kapPow, weight); + } } else if (track.sign() < 0) { - nAKaRec += hPtEtaForEffCorrection[kKa][kNeg]->GetBinContent(ptEtaBin); fillRecoTrackQA(recoAnalysis, track); - float weight = hPtEtaForEffCorrection[kKa][kNeg]->GetBinContent(ptEtaBin); - fillEffPower(kamPow, weight); + if (track.pt() >= cfgEventSelection.cfgCutPtMinKa && track.pt() <= cfgEventSelection.cfgCutPtMaxKa) { + nAKaRec += hPtEtaForEffCorrection[kKa][kNeg]->GetBinContent(ptEtaBin); + float weight = hPtEtaForEffCorrection[kKa][kNeg]->GetBinContent(ptEtaBin); + fillEffPower(kamPow, weight); + } } // PID band QA for kaons if (idMethodKa == kTPCidentified) { @@ -2195,15 +2207,19 @@ struct NchCumulantsId { } } else if (trackIsProton) { if (track.sign() > 0) { - nPrRec += hPtEtaForEffCorrection[kPr][kPos]->GetBinContent(ptEtaBin); fillRecoTrackQA(recoAnalysis, track); - float weight = hPtEtaForEffCorrection[kPr][kPos]->GetBinContent(ptEtaBin); - fillEffPower(prPow, weight); + if (track.pt() >= cfgEventSelection.cfgCutPtMinPr && track.pt() <= cfgEventSelection.cfgCutPtMaxPr) { + nPrRec += hPtEtaForEffCorrection[kPr][kPos]->GetBinContent(ptEtaBin); + float weight = hPtEtaForEffCorrection[kPr][kPos]->GetBinContent(ptEtaBin); + fillEffPower(prPow, weight); + } } else if (track.sign() < 0) { - nAPrRec += hPtEtaForEffCorrection[kPr][kNeg]->GetBinContent(ptEtaBin); fillRecoTrackQA(recoAnalysis, track); - float weight = hPtEtaForEffCorrection[kPr][kNeg]->GetBinContent(ptEtaBin); - fillEffPower(aprPow, weight); + if (track.pt() >= cfgEventSelection.cfgCutPtMinPr && track.pt() <= cfgEventSelection.cfgCutPtMaxPr) { + nAPrRec += hPtEtaForEffCorrection[kPr][kNeg]->GetBinContent(ptEtaBin); + float weight = hPtEtaForEffCorrection[kPr][kNeg]->GetBinContent(ptEtaBin); + fillEffPower(aprPow, weight); + } } // PID band QA for protons if (idMethodPr == kTPCidentified) { diff --git a/PWGCF/EbyEFluctuations/Tasks/partNumFluc.cxx b/PWGCF/EbyEFluctuations/Tasks/partNumFluc.cxx index 2bcecf4fb12..d459822b071 100644 --- a/PWGCF/EbyEFluctuations/Tasks/partNumFluc.cxx +++ b/PWGCF/EbyEFluctuations/Tasks/partNumFluc.cxx @@ -57,11 +57,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include @@ -70,16 +70,16 @@ #include #include -#define C_CS(cs) /* NOLINT(cppcoreguidelines-macro-usage) */ \ - [](std::index_sequence) constexpr -> ConstStr<(cs)[indices]...> { \ - static_assert(std::is_array_v> && \ - std::same_as>, char>); \ - return ConstStr<(cs)[indices]...>{}; \ +#define C_CS(cs) /* NOLINT(cppcoreguidelines-macro-usage) */ \ + [](const std::index_sequence) constexpr -> ConstStr<(cs)[indices]...> { \ + static_assert(std::is_array_v> && \ + std::same_as>, char>); \ + return ConstStr<(cs)[indices]...>{}; \ }(std::make_index_sequence{}) -#define C_SV(sv) /* NOLINT(cppcoreguidelines-macro-usage) */ \ - [](std::index_sequence) constexpr -> ConstStr<(sv)[indices]...> { \ - static_assert(std::same_as, std::string_view>); \ - return ConstStr<(sv)[indices]...>{}; \ +#define C_SV(sv) /* NOLINT(cppcoreguidelines-macro-usage) */ \ + [](const std::index_sequence) constexpr -> ConstStr<(sv)[indices]...> { \ + static_assert(std::same_as, std::string_view>); \ + return ConstStr<(sv)[indices]...>{}; \ }(std::make_index_sequence<(sv).size()>{}) using namespace o2; @@ -88,49 +88,74 @@ using namespace o2::framework::expressions; namespace o2::aod { +using JoinedMcCollisions = soa::Join; using JoinedCollisions = soa::Join; -using JoinedTracks = soa::Join; using JoinedCollisionsWithMc = soa::Join; +using JoinedTracks = soa::Join; using JoinedTracksWithMc = soa::Join; -using JoinedMcCollisions = soa::Join; - -namespace mini_mc_collision -{ -DECLARE_SOA_COLUMN(NMcParticlesP, nMcParticlesP, std::uint16_t); -DECLARE_SOA_COLUMN(NMcParticlesM, nMcParticlesM, std::uint16_t); -} // namespace mini_mc_collision - -DECLARE_SOA_TABLE(MiniMcCollisions, "AOD", "MINIMCCOLLISION", soa::Index<>, mini_mc_collision::NMcParticlesP, mini_mc_collision::NMcParticlesM); -using MiniMcCollision = MiniMcCollisions::iterator; namespace mini_collision { -DECLARE_SOA_COLUMN(Vz, vz, std::int8_t); -DECLARE_SOA_COLUMN(Centrality, centrality, std::uint16_t); -DECLARE_SOA_COLUMN(NTracksP, nTracksP, std::uint16_t); -DECLARE_SOA_COLUMN(NTracksM, nTracksM, std::uint16_t); +DECLARE_SOA_COLUMN(Code, code, std::uint16_t); } // namespace mini_collision -DECLARE_SOA_TABLE(MiniCollisions, "AOD", "MINICOLLISION", soa::Index<>, mini_collision::Vz, mini_collision::Centrality, mini_collision::NTracksP, mini_collision::NTracksM); +DECLARE_SOA_TABLE(MiniCollisions, "AOD", "MINICOLLISION", soa::Index<>, mini_collision::Code); using MiniCollision = MiniCollisions::iterator; namespace mini_mc_particle { -DECLARE_SOA_INDEX_COLUMN(MiniMcCollision, miniMcCollision); -DECLARE_SOA_COLUMN(SignedEfficiency, signedEfficiency, std::int16_t); +DECLARE_SOA_INDEX_COLUMN(MiniCollision, miniCollision); +DECLARE_SOA_COLUMN(Code, code, std::uint16_t); } // namespace mini_mc_particle -DECLARE_SOA_TABLE(MiniMcParticles, "AOD", "MINIMCPARTICLE", soa::Index<>, mini_mc_particle::MiniMcCollisionId, mini_mc_particle::SignedEfficiency); +DECLARE_SOA_TABLE(MiniMcParticles, "AOD", "MINIMCPARTICLE", soa::Index<>, mini_mc_particle::MiniCollisionId, mini_mc_particle::Code); using MiniMcParticle = MiniMcParticles::iterator; namespace mini_track { DECLARE_SOA_INDEX_COLUMN(MiniCollision, miniCollision); -DECLARE_SOA_COLUMN(SignedEfficiency, signedEfficiency, std::int16_t); +DECLARE_SOA_COLUMN(Code, code, std::uint32_t); } // namespace mini_track -DECLARE_SOA_TABLE(MiniTracks, "AOD", "MINITRACK", soa::Index<>, mini_track::MiniCollisionId, mini_track::SignedEfficiency); +DECLARE_SOA_TABLE(MiniTracks, "AOD", "MINITRACK", soa::Index<>, mini_track::MiniCollisionId, mini_track::Code); using MiniTrack = MiniTracks::iterator; + +namespace tiny_mc_collision +{ +DECLARE_SOA_COLUMN(NMcParticlesP, nMcParticlesP, std::uint16_t); +DECLARE_SOA_COLUMN(NMcParticlesM, nMcParticlesM, NMcParticlesP::type); +} // namespace tiny_mc_collision + +DECLARE_SOA_TABLE(TinyMcCollisions, "AOD", "TINYMCCOLLISION", soa::Index<>, tiny_mc_collision::NMcParticlesP, tiny_mc_collision::NMcParticlesM); +using TinyMcCollision = TinyMcCollisions::iterator; + +namespace tiny_collision +{ +DECLARE_SOA_COLUMN(Code, code, mini_collision::Code::type); +DECLARE_SOA_COLUMN(NTracksP, nTracksP, std::uint16_t); +DECLARE_SOA_COLUMN(NTracksM, nTracksM, NTracksP::type); +} // namespace tiny_collision + +DECLARE_SOA_TABLE(TinyCollisions, "AOD", "TINYCOLLISION", soa::Index<>, tiny_collision::Code, tiny_collision::NTracksP, tiny_collision::NTracksM); +using TinyCollision = TinyCollisions::iterator; + +namespace tiny_mc_particle +{ +DECLARE_SOA_INDEX_COLUMN(TinyMcCollision, tinyMcCollision); +DECLARE_SOA_COLUMN(SignedEfficiency, signedEfficiency, std::int16_t); +} // namespace tiny_mc_particle + +DECLARE_SOA_TABLE(TinyMcParticles, "AOD", "TINYMCPARTICLE", soa::Index<>, tiny_mc_particle::TinyMcCollisionId, tiny_mc_particle::SignedEfficiency); +using TinyMcParticle = TinyMcParticles::iterator; + +namespace tiny_track +{ +DECLARE_SOA_INDEX_COLUMN(TinyCollision, tinyCollision); +DECLARE_SOA_COLUMN(SignedEfficiency, signedEfficiency, std::int16_t); +} // namespace tiny_track + +DECLARE_SOA_TABLE(TinyTracks, "AOD", "TINYTRACK", soa::Index<>, tiny_track::TinyCollisionId, tiny_track::SignedEfficiency); +using TinyTrack = TinyTracks::iterator; } // namespace o2::aod namespace @@ -139,7 +164,7 @@ namespace fluctuation_calculator_base { inline constexpr std::int8_t MaxOrder{8}; inline constexpr std::int32_t NExponentKeys{MaxOrder * (MaxOrder + 1) / 2}; -inline constexpr std::array, NExponentKeys> ExponentKeys{[]() constexpr -> std::array, NExponentKeys> { +inline constexpr std::array, NExponentKeys> ExponentKeys{[]() consteval noexcept -> std::array, NExponentKeys> { std::array, NExponentKeys> result{}; std::int32_t index{}; for (std::int32_t const& iExponent : std::views::iota(1, MaxOrder + 1)) { @@ -149,7 +174,7 @@ inline constexpr std::array, NExponentKeys> } return result; }()}; -inline constexpr std::int32_t NOrderKeys{[]() constexpr -> std::int32_t { +inline constexpr std::int32_t NOrderKeys{[]() consteval noexcept -> std::int32_t { std::array counts{1}; for (std::pair const& exponentKey /* o2-linter: disable=const-ref-in-for-loop */ : ExponentKeys) { const std::int32_t weight{exponentKey.first}; @@ -159,11 +184,8 @@ inline constexpr std::int32_t NOrderKeys{[]() constexpr -> std::int32_t { } return std::accumulate(counts.begin(), counts.end(), 0); }()}; -inline constexpr std::array, NOrderKeys> OrderKeys{[]() constexpr -> std::array, NOrderKeys> { - std::array, NOrderKeys> result{}; - std::array current{}; - std::int32_t index{}; - const auto fillOrderKeys{[¤t, &index, &result](const auto& self, const std::int32_t position, const std::int32_t sum, const std::int32_t target) constexpr -> void { +inline constexpr std::array, NOrderKeys> OrderKeys{[]() consteval noexcept -> std::array, NOrderKeys> { + constexpr auto FillOrderKeys{[](const auto& self, std::array& current, std::int32_t& index, std::array, NOrderKeys>& result, const std::int32_t position, const std::int32_t sum, const std::int32_t target) consteval noexcept -> void { if (position == NExponentKeys) { if (sum == target) { result[index++] = current; @@ -172,29 +194,82 @@ inline constexpr std::array, NOrderKeys> } const std::int32_t weight{ExponentKeys[position].first}; - for (std::int32_t power{}; sum + power * weight <= target; ++power) { + for (std::int32_t const& power : std::views::iota(0, (target - sum) / weight + 1)) { current[position] = static_cast(power); - self(self, position + 1, sum + power * weight, target); + self(self, current, index, result, position + 1, sum + power * weight, target); } }}; + + std::array, NOrderKeys> result{}; + std::array current{}; + std::int32_t index{}; for (std::int32_t const& target : std::views::iota(0, MaxOrder + 1)) { - fillOrderKeys(fillOrderKeys, 0, 0, target); + FillOrderKeys(FillOrderKeys, current, index, result, 0, 0, target); + } + return result; +}()}; +inline constexpr std::array>, NOrderKeys> OrderKeyProductLinks{[]() consteval noexcept -> std::array>, NOrderKeys> { + std::array>, NOrderKeys> result{}; + for (std::int32_t const& iOrderKey : std::views::iota(1, NOrderKeys)) { + result[iOrderKey].first = iOrderKey; + std::array orderKeyParent{OrderKeys[iOrderKey]}; + for (std::int32_t const& iExponentKey : std::views::iota(0, NExponentKeys) | std::views::reverse) { + const std::int8_t power{orderKeyParent[iExponentKey]}; + if (power <= 0) { + continue; + } + + orderKeyParent[iExponentKey] = {}; + for (std::int32_t const& iOrderKeyParent : std::views::iota(0, iOrderKey)) { + if (OrderKeys[iOrderKeyParent] == orderKeyParent) { + result[iOrderKey] = {iOrderKeyParent, {iExponentKey, power}}; + break; + } + } + break; + } } return result; }()}; +static_assert([]() consteval noexcept -> bool { + if (OrderKeys[0] != std::array{}) { + return false; + } + for (std::int32_t const& iOrderKey : std::views::iota(1, NOrderKeys)) { + const auto& [iOrderKeyParent, factor]{OrderKeyProductLinks[iOrderKey]}; + const auto& [iExponentKey, power]{factor}; + if (iOrderKeyParent < 0 || iOrderKeyParent >= iOrderKey || iExponentKey < 0 || iExponentKey >= NExponentKeys || power <= 0) { + return false; + } + for (std::int32_t const& iExponentKeyAfter : std::views::iota(iExponentKey + 1, NExponentKeys)) { + if (OrderKeys[iOrderKey][iExponentKeyAfter] > 0) { + return false; + } + } + std::array orderKeyReconstructed{OrderKeys[iOrderKeyParent]}; + if (orderKeyReconstructed[iExponentKey] != 0) { + return false; + } + orderKeyReconstructed[iExponentKey] = power; + if (orderKeyReconstructed != OrderKeys[iOrderKey]) { + return false; + } + } + return true; +}()); } // namespace fluctuation_calculator_base class FluctuationCalculatorTrack { public: - FluctuationCalculatorTrack() = default; - FluctuationCalculatorTrack(const FluctuationCalculatorTrack&) = default; + FluctuationCalculatorTrack() noexcept = default; + FluctuationCalculatorTrack(const FluctuationCalculatorTrack&) noexcept = default; FluctuationCalculatorTrack(FluctuationCalculatorTrack&&) noexcept = default; - FluctuationCalculatorTrack& operator=(const FluctuationCalculatorTrack&) = default; + FluctuationCalculatorTrack& operator=(const FluctuationCalculatorTrack&) noexcept = default; FluctuationCalculatorTrack& operator=(FluctuationCalculatorTrack&&) noexcept = default; - virtual ~FluctuationCalculatorTrack() = default; + virtual ~FluctuationCalculatorTrack() noexcept = default; - [[nodiscard]] std::array getProducts(const double weight = 1.) const + [[nodiscard]] std::array getProducts(const double weight = 1.) const noexcept { std::array, fluctuation_calculator_base::NExponentKeys> powersQ{}; for (std::int32_t const& iExponentKey : std::views::iota(0, fluctuation_calculator_base::NExponentKeys)) { @@ -204,22 +279,20 @@ class FluctuationCalculatorTrack } } - std::array products{}; - products.fill(weight); - for (std::int32_t const& iOrderKey : std::views::iota(0, fluctuation_calculator_base::NOrderKeys)) { - for (std::int32_t const& iExponentKey : std::views::iota(0, fluctuation_calculator_base::NExponentKeys)) { - if (const std::int32_t power{fluctuation_calculator_base::OrderKeys[iOrderKey][iExponentKey]}; power > 0) { - products[iOrderKey] *= powersQ[iExponentKey][power]; - } - } + std::array products{weight}; + for (std::int32_t const& iOrderKey : std::views::iota(1, fluctuation_calculator_base::NOrderKeys)) { + const auto& [iOrderKeyParent, factor]{fluctuation_calculator_base::OrderKeyProductLinks[iOrderKey]}; + const auto& [iExponentKey, power]{factor}; + products[iOrderKey] = products[iOrderKeyParent] * powersQ[iExponentKey][power]; } return products; } - void clear() { mQs.fill({}); } - void fill(const double charge, const double efficiency, const double weight = 1.) + void addQ(const std::int32_t exponentKeyIndex, const double q) noexcept { mQs[exponentKeyIndex] += q; } + void clear() noexcept { mQs.fill({}); } + void fill(const double charge, const double efficiency, const double weight = 1.) noexcept { const double inverseEfficiency{1. / efficiency}; - std::array powersCharge{1.}; + std::array powersCharge{weight}; std::array powersInverseEfficiency{1.}; for (std::int32_t const& exponent : std::views::iota(1, fluctuation_calculator_base::MaxOrder + 1)) { powersCharge[exponent] = powersCharge[exponent - 1] * charge; @@ -227,7 +300,7 @@ class FluctuationCalculatorTrack } for (std::int32_t const& iExponentKey : std::views::iota(0, fluctuation_calculator_base::NExponentKeys)) { const auto& [exponentCharge, exponentEfficiency]{fluctuation_calculator_base::ExponentKeys[iExponentKey]}; - mQs[iExponentKey] += weight * powersCharge[exponentCharge] * powersInverseEfficiency[exponentEfficiency]; + addQ(iExponentKey, powersCharge[exponentCharge] * powersInverseEfficiency[exponentEfficiency]); } } @@ -238,23 +311,18 @@ class FluctuationCalculatorTrack template concept IsValidEnum = ((std::is_enum_v> && requires { std::remove_cvref_t::N; }) && ...); template -concept IsValid = IsValidEnum...> && ((EValues != std::remove_cvref_t::N) && ...); +concept IsValidEnumValue = IsValidEnum...> && ((EValues != std::remove_cvref_t::N) && ...); template requires IsValidEnum -constexpr std::int32_t toI(const E e) +constexpr std::int32_t toI(const E e) noexcept { return static_cast(e); } - template requires IsValidEnum constexpr std::int32_t NEs{toI(E::N)}; -template - requires IsValidEnum -struct EnumInfo; - enum class NameKind { Default = 0, Lower, @@ -262,43 +330,44 @@ enum class NameKind { DisplayLower, N }; -template - requires IsValidEnum -constexpr std::string_view getName(const std::int32_t index) -{ - if constexpr (NameKindValue == NameKind::Lower) { - return EnumInfo>::NamesLower.at(index); - } else if constexpr (NameKindValue == NameKind::Display) { - return EnumInfo>::DisplayNames.at(index); - } else if constexpr (NameKindValue == NameKind::DisplayLower) { - return EnumInfo>::DisplayNamesLower.at(index); - } else { - return EnumInfo>::Names.at(index); - } -} -template - requires IsValidEnum -constexpr std::string_view getName(const E e) -{ - return getName(toI(e)); -} -template - requires IsValidEnum -std::vector getDisplayNames() -{ - if constexpr (requires { EnumInfo>::DisplayNames; }) { - return {EnumInfo>::DisplayNames.begin(), EnumInfo>::DisplayNames.end()}; - } else { - return {EnumInfo>::Names.begin(), EnumInfo>::Names.end()}; - } -} - enum class DataMode { McMcParticle = 0, McTrack, RawTrack, N }; +enum class Selection { + Loose = 0, + Default, + Tight, + N +}; +enum class RangeEdge { + Min = 0, + Max, + N +}; +enum class McEventSelection { + All = 0, + Good, + Inel, + Vz, + NRecoCollisions, + N +}; +enum class EventSelection { + All = 0, + Good, + Run, + Rct, + Inel, + Bits, + Centrality, + Vz, + Occupancy, + NPvContributors, + N +}; enum class CentralityDefinition { Ft0a = 0, Ft0c, @@ -345,17 +414,17 @@ enum class ParticleSpeciesAll { Proton, N }; +enum class ChargeSpecies { + Plus = 0, + Minus, + N +}; enum class ParticleNumber { Charge = 0, Kaon, Proton, N }; -enum class ChargeSpecies { - Plus = 0, - Minus, - N -}; enum class ChargeNumber { Plus = 0, Minus, @@ -364,6 +433,17 @@ enum class ChargeNumber { N }; +template + requires IsValidEnum +struct EnumInfo; +template <> +struct EnumInfo { + static constexpr std::array> Names{"Loose", "Default", "Tight"}; +}; +template <> +struct EnumInfo { + static constexpr std::array> Names{"Min", "Max"}; +}; template <> struct EnumInfo { static constexpr std::array> Names{"Mean", "Sigma"}; @@ -407,23 +487,54 @@ struct EnumInfo { static constexpr std::array> ParticleSpeciesValues{ParticleSpecies::N, ParticleSpecies::Pion, ParticleSpecies::Kaon, ParticleSpecies::Proton}; }; template <> +struct EnumInfo { + static constexpr std::array> Names{"P", "M"}; + static constexpr std::array> NamesLower{"p", "m"}; + static constexpr std::array> Titles{"+", "#minus"}; +}; +template <> struct EnumInfo { static constexpr std::array> Names{"Ch", "Ka", "Pr"}; static constexpr std::array> DisplayNames{"Charge", "Kaon", "Proton"}; static constexpr std::array> DisplayNamesLower{"charge", "kaon", "proton"}; static constexpr std::array> Titles{"h", "K", "p"}; -}; -template <> -struct EnumInfo { - static constexpr std::array> Names{"P", "M"}; - static constexpr std::array> NamesLower{"p", "m"}; - static constexpr std::array> Titles{"+", "#minus"}; + static constexpr std::array> ParticleSpeciesAllValues{ParticleSpeciesAll::All, ParticleSpeciesAll::Kaon, ParticleSpeciesAll::Proton}; }; template <> struct EnumInfo { static constexpr std::array> Names{"P", "M", "T", "N"}; }; +template + requires IsValidEnum +constexpr std::string_view getName(const std::int32_t index) +{ + if constexpr (NameKindValue == NameKind::Lower) { + return EnumInfo>::NamesLower.at(index); + } else if constexpr (NameKindValue == NameKind::Display) { + return EnumInfo>::DisplayNames.at(index); + } else if constexpr (NameKindValue == NameKind::DisplayLower) { + return EnumInfo>::DisplayNamesLower.at(index); + } else { + return EnumInfo>::Names.at(index); + } +} +template + requires IsValidEnum +constexpr std::string_view getName(const E e) +{ + return getName(toI(e)); +} +template + requires IsValidEnum +std::vector getDisplayNames() +{ + if constexpr (requires { EnumInfo>::DisplayNames; }) { + return {EnumInfo>::DisplayNames.begin(), EnumInfo>::DisplayNames.end()}; + } else { + return {EnumInfo>::Names.begin(), EnumInfo>::Names.end()}; + } +} template requires IsValidEnum constexpr std::string_view getTitle(const std::int32_t index) @@ -432,7 +543,7 @@ constexpr std::string_view getTitle(const std::int32_t index) } template requires IsValidEnum -constexpr To getValue(const E e) +constexpr To getValue(const E e) noexcept { if constexpr (std::is_same_v, Detector>) { return EnumInfo::DetectorValues[toI(e)]; @@ -446,15 +557,183 @@ constexpr To getValue(const E e) return To::N; } } -constexpr std::int32_t getPdgCode(const ParticleSpecies particleSpecies, const ChargeSpecies chargeSpecies) +constexpr std::int32_t getPdgCode(const ParticleSpecies particleSpecies, const ChargeSpecies chargeSpecies) noexcept { return EnumInfo::PdgCodes[toI(particleSpecies)][toI(chargeSpecies)]; } -constexpr double getMass(const ParticleSpecies particleSpecies) +constexpr double getMass(const ParticleSpecies particleSpecies) noexcept { return EnumInfo::Masses[toI(particleSpecies)]; } +namespace mini_collision_codec +{ +inline constexpr std::int32_t NBinsVz{40}; +inline constexpr std::array> RangeVz{-10., 10.}; +inline constexpr std::int32_t NBinsCentrality{550}; +inline constexpr std::array BinEdgesCentrality{[]() consteval noexcept -> std::array { + constexpr std::array EdgesSelection{0., 0.001, 0.01, 0.1, 1., 10., 100.}; + constexpr std::array NBinsPerSection{100, 90, 90, 90, 90, 90}; + std::array edges{}; + std::int32_t index{}; + edges[index++] = EdgesSelection.front(); + for (std::int32_t const& iSection : std::views::iota(0, static_cast(NBinsPerSection.size()))) { + const double width{(EdgesSelection[iSection + 1] - EdgesSelection[iSection]) / NBinsPerSection[iSection]}; + for (std::int32_t const& iBin : std::views::iota(1, NBinsPerSection[iSection] + 1)) { + edges[index++] = EdgesSelection[iSection] + iBin * width; + } + } + return edges; +}()}; +inline constexpr std::int32_t NStatesGoodNPvContributors{2}; +static_assert(static_cast(NBinsVz) * NBinsCentrality * NStatesGoodNPvContributors <= static_cast(std::numeric_limits::max()) + 1); + +std::optional encode(const double vz, const double centrality, const bool isGoodNPvContributors) noexcept +{ + if (!std::isfinite(vz) || !std::isfinite(centrality) || vz < RangeVz[toI(RangeEdge::Min)] || RangeVz[toI(RangeEdge::Max)] <= vz || centrality < BinEdgesCentrality.front() || BinEdgesCentrality.back() <= centrality) { + return std::nullopt; + } + + const std::int32_t vzBinIndex{static_cast(std::floor((vz - RangeVz[toI(RangeEdge::Min)]) / ((RangeVz[toI(RangeEdge::Max)] - RangeVz[toI(RangeEdge::Min)]) / NBinsVz)))}; + if (vzBinIndex < 0 || NBinsVz <= vzBinIndex) { + return std::nullopt; + } + + aod::mini_collision::Code::type code{static_cast(vzBinIndex)}; + aod::mini_collision::Code::type codeSpan{NBinsVz}; + code += (static_cast(std::ranges::upper_bound(BinEdgesCentrality, centrality) - BinEdgesCentrality.begin()) - 1) * codeSpan; + codeSpan *= NBinsCentrality; + code += static_cast(isGoodNPvContributors) * codeSpan; + return code; +} +} // namespace mini_collision_codec + +namespace mini_track_codec +{ +inline constexpr std::int32_t NStatesPvContributor{2}; +inline constexpr std::int32_t NBinsPt{18}; +inline constexpr std::int32_t NBinsEta{16}; +inline constexpr std::array> RangePt{0.2, 2.}; +inline constexpr std::array> RangeEta{-0.8, 0.8}; +static_assert(static_cast(NStatesPvContributor) * NEs * NEs * NEs * NEs * NEs * NEs * NEs * NEs * NBinsPt * NBinsEta * NEs * NEs * NEs <= static_cast(std::numeric_limits::max()) + 1); + +struct ConfigSelection { + std::array> minItsNCls{}; + std::array> maxItsChi2NCls{}; + std::array> minTpcNCls{}; + std::array> maxTpcChi2NCls{}; + std::array> minTpcNCrossedRows{}; + std::array> maxTpcNClsSharedRatio{}; + std::array>, NEs> maxAbsNSigmaDca{}; + std::array>, NEs> maxAbsNSigmaPid{}; +}; + +std::optional encode(const ConfigSelection& configSelection, const bool isPvContributor, const double itsNCls, const double itsChi2NCls, const double tpcNCls, const double tpcChi2NCls, const double tpcNCrossedRows, const double tpcNClsSharedRatio, const std::array>& absNSigmaDca, const double pt, const double eta, const std::int32_t sign, const ParticleSpeciesAll particleSpeciesAll, const double absNSigmaPid) noexcept +{ + if (!std::isfinite(pt) || !std::isfinite(eta) || pt < RangePt[toI(RangeEdge::Min)] || RangePt[toI(RangeEdge::Max)] <= pt || eta < RangeEta[toI(RangeEdge::Min)] || RangeEta[toI(RangeEdge::Max)] <= eta) { + return std::nullopt; + } + + const std::int32_t ptBinIndex{static_cast(std::floor((pt - RangePt[toI(RangeEdge::Min)]) / ((RangePt[toI(RangeEdge::Max)] - RangePt[toI(RangeEdge::Min)]) / NBinsPt)))}; + if (ptBinIndex < 0 || NBinsPt <= ptBinIndex) { + return std::nullopt; + } + + const std::int32_t etaBinIndex{static_cast(std::floor((eta - RangeEta[toI(RangeEdge::Min)]) / ((RangeEta[toI(RangeEdge::Max)] - RangeEta[toI(RangeEdge::Min)]) / NBinsEta)))}; + if (etaBinIndex < 0 || NBinsEta <= etaBinIndex) { + return std::nullopt; + } + + static constexpr auto GetState{ + [] + requires IsValidEnumValue + (const double value, const std::array>& cuts) noexcept -> std::int32_t { + for (std::int32_t const& iSelection : std::views::iota(0, NEs) | std::views::reverse) { + if constexpr (RangeEdgeValue == RangeEdge::Min) { + if (value > cuts[iSelection]) { + return iSelection; + } + } else { + if (value < cuts[iSelection]) { + return iSelection; + } + } + } + return -1; + }}; + + aod::mini_track::Code::type code{static_cast(isPvContributor)}; + aod::mini_track::Code::type codeSpan{NStatesPvContributor}; + for (std::int32_t const& state : std::to_array( + // cppcheck-suppress internalAstError + {GetState.template operator()(itsNCls, configSelection.minItsNCls), + GetState.template operator()(itsChi2NCls, configSelection.maxItsChi2NCls), + GetState.template operator()(tpcNCls, configSelection.minTpcNCls), + GetState.template operator()(tpcChi2NCls, configSelection.maxTpcChi2NCls), + GetState.template operator()(tpcNCrossedRows, configSelection.minTpcNCrossedRows), + GetState.template operator()(tpcNClsSharedRatio, configSelection.maxTpcNClsSharedRatio), + GetState.template operator()(absNSigmaDca[toI(DcaAxis::Xy)], configSelection.maxAbsNSigmaDca[toI(DcaAxis::Xy)]), + GetState.template operator()(absNSigmaDca[toI(DcaAxis::Z)], configSelection.maxAbsNSigmaDca[toI(DcaAxis::Z)])})) { + if (state < 0) { + return std::nullopt; + } + + code += state * codeSpan; + codeSpan *= NEs; + } + code += ptBinIndex * codeSpan; + codeSpan *= NBinsPt; + code += etaBinIndex * codeSpan; + codeSpan *= NBinsEta; + code += (sign > 0 ? toI(ChargeSpecies::Plus) : toI(ChargeSpecies::Minus)) * codeSpan; + codeSpan *= NEs; + code += toI(particleSpeciesAll) * codeSpan; + codeSpan *= NEs; + if (particleSpeciesAll != ParticleSpeciesAll::All) { + // clang-format v20.1.3 + // clang-format off + const std::int32_t statePid{GetState.template operator()(absNSigmaPid, configSelection.maxAbsNSigmaPid[toI(getValue(particleSpeciesAll))])}; + // clang-format on + if (statePid < 0) { + return std::nullopt; + } + code += statePid * codeSpan; + } + return code; +} +} // namespace mini_track_codec + +namespace mini_mc_particle_codec +{ +static_assert(static_cast(mini_track_codec::NBinsPt) * mini_track_codec::NBinsEta * NEs * NEs <= static_cast(std::numeric_limits::max()) + 1); + +std::optional encode(const double pt, const double eta, const std::int32_t sign, const ParticleSpecies particleSpecies) noexcept +{ + if (!std::isfinite(pt) || !std::isfinite(eta) || pt < mini_track_codec::RangePt[toI(RangeEdge::Min)] || mini_track_codec::RangePt[toI(RangeEdge::Max)] <= pt || eta < mini_track_codec::RangeEta[toI(RangeEdge::Min)] || mini_track_codec::RangeEta[toI(RangeEdge::Max)] <= eta) { + return std::nullopt; + } + + const std::int32_t ptBinIndex{static_cast(std::floor((pt - mini_track_codec::RangePt[toI(RangeEdge::Min)]) / ((mini_track_codec::RangePt[toI(RangeEdge::Max)] - mini_track_codec::RangePt[toI(RangeEdge::Min)]) / mini_track_codec::NBinsPt)))}; + if (ptBinIndex < 0 || mini_track_codec::NBinsPt <= ptBinIndex) { + return std::nullopt; + } + + const std::int32_t etaBinIndex{static_cast(std::floor((eta - mini_track_codec::RangeEta[toI(RangeEdge::Min)]) / ((mini_track_codec::RangeEta[toI(RangeEdge::Max)] - mini_track_codec::RangeEta[toI(RangeEdge::Min)]) / mini_track_codec::NBinsEta)))}; + if (etaBinIndex < 0 || mini_track_codec::NBinsEta <= etaBinIndex) { + return std::nullopt; + } + + aod::mini_mc_particle::Code::type code{static_cast(ptBinIndex)}; + aod::mini_mc_particle::Code::type codeSpan{mini_track_codec::NBinsPt}; + code += etaBinIndex * codeSpan; + codeSpan *= mini_track_codec::NBinsEta; + code += (sign > 0 ? toI(ChargeSpecies::Plus) : toI(ChargeSpecies::Minus)) * codeSpan; + codeSpan *= NEs; + code += toI(particleSpecies) * codeSpan; + return code; +} +} // namespace mini_mc_particle_codec + template requires std::is_arithmetic_v constexpr std::int32_t nEnabled(const Configurable>& cfg) @@ -475,36 +754,36 @@ double interpolate(const TH3* const h, const double x, const double y, const dou return 0.; } - static constexpr auto GetBinIndicesWeights{[](const TAxis* const axis, const double position) -> std::array, 2> { + static constexpr auto GetBinIndicesWeights{[](const TAxis* const axis, const double position) -> std::array, NEs> { if (!axis) { return {}; } - const std::int32_t n{axis->GetNbins()}; - if (n == 1 || position <= axis->GetBinCenter(1)) { + const std::int32_t nBins{axis->GetNbins()}; + if (nBins == 1 || position <= axis->GetBinCenter(1)) { return {{{1, 1.}, {1, 0.}}}; } - if (position >= axis->GetBinCenter(n)) { - return {{{n, 1.}, {n, 0.}}}; + if (position >= axis->GetBinCenter(nBins)) { + return {{{nBins, 1.}, {nBins, 0.}}}; } - const std::int32_t bin{axis->FindFixBin(position)}; - const std::int32_t lower{position < axis->GetBinCenter(bin) ? bin - 1 : bin}; - const std::int32_t upper{lower + 1}; - const double fraction{(position - axis->GetBinCenter(lower)) / (axis->GetBinCenter(upper) - axis->GetBinCenter(lower))}; + const std::int32_t binIndex{axis->FindFixBin(position)}; + const std::int32_t binIndexLower{position < axis->GetBinCenter(binIndex) ? binIndex - 1 : binIndex}; + const std::int32_t binIndexUpper{binIndexLower + 1}; + const double fraction{(position - axis->GetBinCenter(binIndexLower)) / (axis->GetBinCenter(binIndexUpper) - axis->GetBinCenter(binIndexLower))}; - return {{{lower, 1. - fraction}, {upper, fraction}}}; + return {{{binIndexLower, 1. - fraction}, {binIndexUpper, fraction}}}; }}; - const std::array, 2> xb{GetBinIndicesWeights(h->GetXaxis(), x)}; - const std::array, 2> yb{GetBinIndicesWeights(h->GetYaxis(), y)}; - const std::array, 2> zb{GetBinIndicesWeights(h->GetZaxis(), z)}; + const std::array, NEs> binIndicesWeightsX{GetBinIndicesWeights(h->GetXaxis(), x)}; + const std::array, NEs> binIndicesWeightsY{GetBinIndicesWeights(h->GetYaxis(), y)}; + const std::array, NEs> binIndicesWeightsZ{GetBinIndicesWeights(h->GetZaxis(), z)}; double result{}; - for (const auto& [ix, wx] : xb) { - for (const auto& [iy, wy] : yb) { - for (const auto& [iz, wz] : zb) { - result += wx * wy * wz * h->GetBinContent(ix, iy, iz); + for (const auto& [iBinX, weightX] : binIndicesWeightsX) { + for (const auto& [iBinY, weightY] : binIndicesWeightsY) { + for (const auto& [iBinZ, weightZ] : binIndicesWeightsZ) { + result += weightX * weightY * weightZ * h->GetBinContent(iBinX, iBinY, iBinZ); } } } @@ -514,12 +793,14 @@ double interpolate(const TH3* const h, const double x, const double y, const dou struct PartNumFluc { struct HolderCcdb { - [[maybe_unused]] static constexpr std::int32_t NDimensionsEfficiency{4}; + static constexpr std::int32_t NDimensionsEfficiency{4}; + const TList* lCcdb{}; std::map> runNumbersIndicesGroupIndices; - std::vector, NEs>, NEs>, NEs>> fPtMeasureDca; - std::vector>, NEs>, NEs>> hCentralityPtEtaShiftNSigmaPid; - std::vector>, NEs>, NEs>> hVzCentralityPtEtaEfficiency; + std::int32_t runGroupIndexCurrent{}; + std::array, NEs>, NEs>, NEs> calibrationsPtMeasureDca{}; + std::array>, NEs>, NEs> hsCentralityPtEtaShiftNSigmaPid{}; + std::array>, NEs>, NEs> hsVzCentralityPtEtaEfficiency{}; } holderCcdb{}; struct HolderMcEvent { @@ -527,12 +808,12 @@ struct PartNumFluc { std::array>, NEs> numbers{}; std::array>, NEs> numbersEff{}; - void clear() { *this = {}; } + void clear() noexcept { *this = {}; } } holderMcEvent{}; struct HolderEvent { - static constexpr std::pair RangeCentrality{0., 100.}; - static constexpr bool isValidCentrality(const double value) { return RangeCentrality.first <= value && value <= RangeCentrality.second; } + static constexpr std::array> RangeCentrality{0., 100.}; + static constexpr bool isValidCentrality(const double value) noexcept { return RangeCentrality[toI(RangeEdge::Min)] <= value && value < RangeCentrality[toI(RangeEdge::Max)]; } std::int32_t runNumber{}; std::int32_t runIndex{}; @@ -545,14 +826,14 @@ struct PartNumFluc { double centralityCalibration{}; double centrality{}; std::int32_t subgroupIndex{}; - std::array>, NEs> numbers{}; + std::array>, NEs> numbers{}; - void clear() { *this = {}; } - [[nodiscard]] std::int32_t getNGlobalTracks() const { return std::accumulate(nGlobalTracks.begin(), nGlobalTracks.end(), 0); } - [[nodiscard]] std::int32_t getNPvContributors() const { return std::accumulate(nPvContributors.begin(), nPvContributors.end(), 0); } + void clear() noexcept { *this = {}; } + [[nodiscard]] std::int32_t getNGlobalTracks() const noexcept { return std::accumulate(nGlobalTracks.begin(), nGlobalTracks.end(), 0); } + [[nodiscard]] std::int32_t getNPvContributors() const noexcept { return std::accumulate(nPvContributors.begin(), nPvContributors.end(), 0); } template - requires IsValid - [[nodiscard]] double getMeasureDca() const + requires IsValidEnumValue + [[nodiscard]] double getMeasureDca() const noexcept { const std::int32_t sumNGlobalTracks{getNGlobalTracks()}; if (sumNGlobalTracks == 0) { @@ -573,7 +854,7 @@ struct PartNumFluc { return sumDca / sumNGlobalTracks; } } - [[nodiscard]] std::int32_t getNTofBeta() const { return std::accumulate(nTofBeta.begin(), nTofBeta.end(), 0); } + [[nodiscard]] std::int32_t getNTofBeta() const noexcept { return std::accumulate(nTofBeta.begin(), nTofBeta.end(), 0); } } holderEvent{}; struct HolderMcParticle { @@ -582,18 +863,18 @@ struct PartNumFluc { double pt{}; double eta{}; - void clear() { *this = {}; } + void clear() noexcept { *this = {}; } } holderMcParticle{}; struct HolderTrack { static constexpr double TruncationAbsNSigmaPid{999.}; - static constexpr double truncateNSigmaPid(const double value, const double shift = {}) + static constexpr double truncateNSigmaPid(const double value, const double shift = {}) noexcept { const double valueShifted{value - shift}; return std::abs(value) < TruncationAbsNSigmaPid && std::abs(valueShifted) < TruncationAbsNSigmaPid ? valueShifted : -TruncationAbsNSigmaPid; } - [[nodiscard]] double getNSigmaPidCombined(const std::int32_t particleSpeciesIndex) const + [[nodiscard]] double getNSigmaPidCombined(const std::int32_t particleSpeciesIndex) const noexcept { return truncateNSigmaPid(std::copysign(std::hypot(nSigmaPid[toI(Detector::Tpc)][particleSpeciesIndex], nSigmaPid[toI(Detector::Tof)][particleSpeciesIndex]), nSigmaPid[toI(Detector::Tpc)][particleSpeciesIndex] + nSigmaPid[toI(Detector::Tof)][particleSpeciesIndex])); } @@ -612,27 +893,22 @@ struct PartNumFluc { return a; }()}; - void clear() { *this = {}; } + void clear() noexcept { *this = {}; } } holderTrack{}; struct HolderDerivedData { template - static constexpr T convertFloor(const double value) - { - return std::numeric_limits::lowest() <= value && value <= std::numeric_limits::max() ? static_cast(std::floor(value)) : (std::is_signed_v ? std::numeric_limits::lowest() : std::numeric_limits::max()); - } - template - static constexpr T convertRound(const double value) + static constexpr T convert(const double value) noexcept { - return std::numeric_limits::lowest() <= value && value <= std::numeric_limits::max() ? static_cast(std::round(value)) : (std::is_signed_v ? std::numeric_limits::lowest() : std::numeric_limits::max()); + return std::numeric_limits::lowest() <= value && value <= std::numeric_limits::max() ? static_cast(std::rint(value)) : (std::is_signed_v ? std::numeric_limits::lowest() : std::numeric_limits::max()); } - std::array> nMcParticles{}; - std::array> nTracks{}; - std::vector signedEfficienciesMcParticle{[]() constexpr -> std::vector { std::vector v{}; v.reserve(256); return v; }()}; - std::vector signedEfficienciesTrack{[]() constexpr -> std::vector { std::vector v{}; v.reserve(256); return v; }()}; + std::array> nMcParticles{}; + std::array> nTracks{}; + std::vector signedEfficienciesMcParticle{[]() constexpr -> std::vector { std::vector v{}; v.reserve(256); return v; }()}; + std::vector signedEfficienciesTrack{[]() constexpr -> std::vector { std::vector v{}; v.reserve(256); return v; }()}; - void clear() + void clear() noexcept { nMcParticles = {}; nTracks = {}; @@ -641,15 +917,15 @@ struct PartNumFluc { } } holderDerivedData{}; - std::array, NEs>, NEs> fluctuationCalculatorTrack{}; - struct : ConfigurableGroup { + std::string prefix{"cgCcdb"}; Configurable cfgCcdbUrl{"cfgCcdbUrl", "http://ccdb-test.cern.ch:8080", "Url of CCDB"}; Configurable cfgCcdbPath{"cfgCcdbPath", "Users/f/fasi/test", "Path in CCDB"}; Configurable cfgCcdbTimestampLatest{"cfgCcdbTimestampLatest", std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(), "Latest timestamp in CCDB"}; - } groupCcdb{}; + } cgCcdb{}; struct : ConfigurableGroup { + std::string prefix{"cgAnalysis"}; Configurable cfgFlagQaRun{"cfgFlagQaRun", false, "Run QA flag"}; Configurable cfgFlagQaEvent{"cfgFlagQaEvent", false, "Event QA flag"}; Configurable cfgFlagQaCentrality{"cfgFlagQaCentrality", false, "Centrality QA flag"}; @@ -663,9 +939,11 @@ struct PartNumFluc { Configurable> cfgFlagsCalculationPurity{"cfgFlagsCalculationPurity", {std::array>{}.data(), NEs, getDisplayNames()}, "Purity calculation flags"}; Configurable> cfgFlagsCalculationFractionPrimary{"cfgFlagsCalculationFractionPrimary", {std::array>{}.data(), NEs, getDisplayNames()}, "Primary fraction calculation flags"}; Configurable> cfgFlagsCalculationFluctuation{"cfgFlagsCalculationFluctuation", {std::array>{}.data(), NEs, getDisplayNames()}, "Fluctuation calculation flags"}; - } groupAnalysis{}; + Configurable> cfgFlagsStorageMiniTable{"cfgFlagsStorageMiniTable", {std::array>{}.data(), NEs, getDisplayNames()}, "Mini table storage flags"}; + } cgAnalysis{}; struct : ConfigurableGroup { + std::string prefix{"cgEvent"}; Configurable cfgFlagRejectionRunBad{"cfgFlagRejectionRunBad", false, "Bad run rejection flag"}; Configurable cfgFlagRejectionRunBadMc{"cfgFlagRejectionRunBadMc", false, "MC bad run rejection flag"}; Configurable cfgLabelFlagsRct{"cfgLabelFlagsRct", "CBT_hadronPID", "RCT flags label"}; @@ -674,84 +952,105 @@ struct PartNumFluc { Configurable cfgFlagInelEvent{"cfgFlagInelEvent", true, "Flag of requiring inelastic event"}; Configurable cfgFlagInelEventMc{"cfgFlagInelEventMc", false, "Flag of requiring inelastic MC event"}; Configurable cfgCutMaxAbsVz{"cfgCutMaxAbsVz", 8., "Maximum absolute z-vertex position (cm)"}; - Configurable cfgCutMaxAbsVzMc{"cfgCutMaxAbsVzMc", 999., "Maximum absolute MC z-vertex position (cm)"}; + Configurable cfgCutMaxAbsVzMc{"cfgCutMaxAbsVzMc", 8., "Maximum absolute MC z-vertex position (cm)"}; + Configurable cfgCutMaxOccupancy{"cfgCutMaxOccupancy", 0, "Maximum occupancy"}; Configurable cfgCutMinDeviationNPvContributors{"cfgCutMinDeviationNPvContributors", -4, "Minimum nPvContributors deviation from nGlobalTracks"}; Configurable cfgIndexDefinitionCentrality{"cfgIndexDefinitionCentrality", 2, "Centrality definition index"}; Configurable cfgFlagDefinitionCentralitySameQa{"cfgFlagDefinitionCentralitySameQa", false, "Flag of using the same centrality definition for QA"}; - ConfigurableAxis cfgAxisCentrality{"cfgAxisCentrality", {18, 0., 90.}, "Centrality axis in fluctuation calculation"}; + Configurable cfgNMultiplicityBinsAxis{"cfgNMultiplicityBinsAxis", 200, "Number of multiplicity bins for axis"}; ConfigurableAxis cfgAxisCentralityCalibration{"cfgAxisCentralityCalibration", {VARIABLE_WIDTH, 0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 100.}, "Centrality axis in calibration"}; + ConfigurableAxis cfgAxisCentrality{"cfgAxisCentrality", {20, 0., 100.}, "Centrality axis in fluctuation calculation"}; Configurable cfgNSubgroups{"cfgNSubgroups", 20, "Number of subgroups in fluctuation calculation"}; + Configurable cfgFactorStorageMiniTable{"cfgFactorStorageMiniTable", 1., "Mini table storage inverse probability factor"}; Configurable cfgFlagSingleCollisionMc{"cfgFlagSingleCollisionMc", false, "Flag of requiring exactly single collision of MC collision"}; - Configurable cfgFlagBestCollisionMc{"cfgFlagBestCollisionMc", false, "Flag of requiring best collision of MC collision"}; Configurable cfgFlagMcCollisionVz{"cfgFlagMcCollisionVz", false, "Flag of using z-vertex position of MC collision"}; - } groupEvent{}; + } cgEvent{}; struct : ConfigurableGroup { + std::string prefix{"cgTrack"}; Configurable cfgFlagPvContributor{"cfgFlagPvContributor", true, "Flag of requiring PV contributor"}; - Configurable cfgCutMinItsNCls{"cfgCutMinItsNCls", 5, "Minimum number of clusters ITS"}; - Configurable cfgCutMaxItsChi2NCls{"cfgCutMaxItsChi2NCls", 25., "Maximum chi2 per cluster ITS"}; - Configurable cfgCutMinTpcNCls{"cfgCutMinTpcNCls", 55, "Minimum number of clusters TPC"}; + Configurable> cfgCutsMinItsNCls{"cfgCutsMinItsNCls", {std::array>{4, 5, 6}.data(), NEs, getDisplayNames()}, "Minimum numbers of clusters ITS"}; + Configurable> cfgCutsMaxItsChi2NCls{"cfgCutsMaxItsChi2NCls", {std::array>{30., 25., 20.}.data(), NEs, getDisplayNames()}, "Maximum chi2 per cluster ITS"}; + Configurable> cfgCutsMinTpcNCls{"cfgCutsMinTpcNCls", {std::array>{45, 55, 65}.data(), NEs, getDisplayNames()}, "Minimum numbers of clusters TPC"}; Configurable cfgCutMinTpcChi2NCls{"cfgCutMinTpcChi2NCls", 0., "Minimum chi2 per cluster TPC"}; - Configurable cfgCutMaxTpcChi2NCls{"cfgCutMaxTpcChi2NCls", 3.5, "Maximum chi2 per cluster TPC"}; - Configurable cfgCutMaxTpcNClsSharedRatio{"cfgCutMaxTpcNClsSharedRatio", 0.4, "Maximum ratio of shared clusters over clusters TPC"}; - Configurable cfgCutMinTpcNCrossedRows{"cfgCutMinTpcNCrossedRows", 80, "Minimum number of crossed rows TPC"}; + Configurable> cfgCutsMaxTpcChi2NCls{"cfgCutsMaxTpcChi2NCls", {std::array>{4., 3.5, 3.}.data(), NEs, getDisplayNames()}, "Maximum chi2 per cluster TPC"}; + Configurable> cfgCutsMaxTpcNClsSharedRatio{"cfgCutsMaxTpcNClsSharedRatio", {std::array>{0.5, 0.4, 0.3}.data(), NEs, getDisplayNames()}, "Maximum ratios of shared clusters over clusters TPC"}; + Configurable> cfgCutsMinTpcNCrossedRows{"cfgCutsMinTpcNCrossedRows", {std::array>{70, 80, 90}.data(), NEs, getDisplayNames()}, "Minimum numbers of crossed rows TPC"}; Configurable cfgCutMinTpcNCrossedRowsRatio{"cfgCutMinTpcNCrossedRowsRatio", 0.8, "Minimum ratio of crossed rows over findable clusters TPC"}; Configurable cfgFlagRecalibrationDca{"cfgFlagRecalibrationDca", false, "DCA recalibration flag"}; - Configurable> cfgCutsMaxAbsNSigmaDca{"cfgCutsMaxAbsNSigmaDca", {std::array>{2.5, 2.5}.data(), NEs, getDisplayNames()}, "Maximum absolute nSigma values of DCA (cm)"}; - Configurable cfgCutMinPt{"cfgCutMinPt", 0.4, "Minimum pT (GeV/c)"}; - Configurable cfgCutMaxPt{"cfgCutMaxPt", 2., "Maximum pT (GeV/c)"}; + Configurable> cfgCutsMaxAbsNSigmaDca{"cfgCutsMaxAbsNSigmaDca", {std::array * NEs>{3., 2.5, 2., 3., 2.5, 2.}.data(), NEs, NEs, getDisplayNames(), getDisplayNames()}, "Maximum absolute nSigma values of DCA (cm)"}; + Configurable> cfgCutsRangePt{"cfgCutsRangePt", {std::array * NEs>{0.2, 2., 0.3, 2., 0.4, 2.}.data(), NEs, NEs, getDisplayNames(), getDisplayNames()}, "pT ranges (GeV/c)"}; Configurable cfgCutMaxAbsEta{"cfgCutMaxAbsEta", 0.8, "Maximum absolute eta"}; - Configurable> cfgThresholdsPtTofPid{"cfgThresholdsPtTofPid", {std::array>{0.5, 0.5, 0.8}.data(), NEs, getDisplayNames()}, "pT (GeV/c) thresholds for TOF PID"}; + Configurable> cfgThresholdsPtTofPid{"cfgThresholdsPtTofPid", {std::array>{0.4, 0.4, 0.8}.data(), NEs, getDisplayNames()}, "pT (GeV/c) thresholds for TOF PID"}; Configurable> cfgFlagsRecalibrationNSigmaPid{"cfgFlagsRecalibrationNSigmaPid", {std::array>{}.data(), NEs, getDisplayNames()}, "nSigma PID recalibration flags"}; Configurable cfgFlagRejectionOthers{"cfgFlagRejectionOthers", false, "Other particle species rejection flag"}; - Configurable> cfgCutsMaxAbsNSigmaPid{"cfgCutsMaxAbsNSigmaPid", {std::array>{2., 2., 2.}.data(), NEs, getDisplayNames()}, "Maximum absolute nSigma values for PID"}; + Configurable> cfgCutsMaxAbsNSigmaPid{"cfgCutsMaxAbsNSigmaPid", {std::array * NEs>{2.5, 2., 1.5, 2.5, 2., 1.5, 2.5, 2., 1.5}.data(), NEs, NEs, getDisplayNames(), getDisplayNames()}, "Maximum absolute nSigma values for PID"}; Configurable cfgFlagMcParticlePhysicalPrimary{"cfgFlagMcParticlePhysicalPrimary", true, "Flag of requiring physical primary MC particle"}; Configurable cfgFlagMcParticleMomentum{"cfgFlagMcParticleMomentum", true, "Flag of using momentum of MC particle"}; - } groupTrack{}; - - bool doQaAcceptance{}; - bool doQaPhi{}; - bool doQaPid{}; - bool doCalculationYield{}; - bool doCalculationPurity{}; - bool doCalculationFractionPrimary{}; - bool doCalculationFluctuation{}; - - HistogramRegistry hrCalculationFluctuation{"hrCalculationFluctuation", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry hrCalculationFractionPrimary{"hrCalculationFractionPrimary", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry hrCalculationPurity{"hrCalculationPurity", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry hrCalculationYield{"hrCalculationYield", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry hrQaMc{"hrQaMc", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry hrQaPid{"hrQaPid", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry hrQaPhi{"hrQaPhi", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry hrQaAcceptance{"hrQaAcceptance", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry hrQaDca{"hrQaDca", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry hrQaTrack{"hrQaTrack", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry hrQaCentrality{"hrQaCentrality", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry hrQaEvent{"hrQaEvent", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry hrQaRun{"hrQaRun", {}, OutputObjHandlingPolicy::AnalysisObject}; - HistogramRegistry hrCounter{"hrCounter", {}, OutputObjHandlingPolicy::AnalysisObject}; - - aod::rctsel::RCTFlagsChecker rctFlagsChecker; + } cgTrack{}; Service pdg{}; Service ccdb{}; + aod::rctsel::RCTFlagsChecker rctFlagsChecker; + Filter filterCollision{aod::evsel::sel8 == true}; Filter filterTrack{requireQualityTracksInFilter() && requireTrackCutInFilter(TrackSelectionFlags::kGoldenChi2)}; Filter filterMcCollision{aod::mccollisionprop::numRecoCollision > 0}; Preslice presliceTracksPerCollision{aod::track::collisionId}; + PresliceUnsorted presliceTracksPerMcParticle{aod::mctracklabel::mcParticleId}; - Produces miniMcCollision{}; Produces miniCollision{}; Produces miniMcParticle{}; Produces miniTrack{}; + Produces tinyMcCollision{}; + Produces tinyCollision{}; + Produces tinyMcParticle{}; + Produces tinyTrack{}; + + HistogramRegistry hrCalculationFluctuation{"CalculationFluctuation", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry hrCalculationFractionPrimary{"CalculationFractionPrimary", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry hrCalculationPurity{"CalculationPurity", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry hrCalculationYield{"CalculationYield", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry hrQaMc{"QaMc", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry hrQaPid{"QaPid", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry hrQaPhi{"QaPhi", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry hrQaAcceptance{"QaAcceptance", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry hrQaDca{"QaDca", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry hrQaTrack{"QaTrack", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry hrQaCentrality{"QaCentrality", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry hrQaEvent{"QaEvent", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry hrQaRun{"QaRun", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; + HistogramRegistry hrCounter{"Counter", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + bool doQaAcceptance{}; + bool doQaPhi{}; + bool doQaPid{}; + bool doCalculationYield{}; + bool doCalculationPurity{}; + bool doCalculationFractionPrimary{}; + bool doCalculationFluctuation{}; + bool doStorageMiniTable{}; + std::array> rangePtAll{std::numeric_limits::max(), std::numeric_limits::lowest()}; + std::unique_ptr configSelection; + + std::array, NEs>, NEs> fluctuationCalculatorsTrackMcParticle{}; + std::array, NEs>, NEs> fluctuationCalculatorsTrackTrack{}; void init(const InitContext&) { gRandom->SetSeed(0); + doQaAcceptance = isEnabled(cgAnalysis.cfgFlagsQaAcceptance); + doQaPhi = isEnabled(cgAnalysis.cfgFlagsQaPhi); + doQaPid = isEnabled(cgAnalysis.cfgFlagsQaPid); + doCalculationYield = isEnabled(cgAnalysis.cfgFlagsCalculationYield); + doCalculationPurity = isEnabled(cgAnalysis.cfgFlagsCalculationPurity); + doCalculationFractionPrimary = isEnabled(cgAnalysis.cfgFlagsCalculationFractionPrimary); + doCalculationFluctuation = isEnabled(cgAnalysis.cfgFlagsCalculationFluctuation); + doStorageMiniTable = isEnabled(cgAnalysis.cfgFlagsStorageMiniTable); + if (doProcessRaw.value == doProcessMc.value) { LOG(fatal) << "Identical values of doProcessRaw and doProcessMc!"; } @@ -760,59 +1059,99 @@ struct PartNumFluc { } else { LOG(info) << "Enabling raw data process."; } - - doQaAcceptance = isEnabled(groupAnalysis.cfgFlagsQaAcceptance); - doQaPhi = isEnabled(groupAnalysis.cfgFlagsQaPhi); - doQaPid = isEnabled(groupAnalysis.cfgFlagsQaPid); - doCalculationYield = isEnabled(groupAnalysis.cfgFlagsCalculationYield); - doCalculationPurity = isEnabled(groupAnalysis.cfgFlagsCalculationPurity); - doCalculationFractionPrimary = isEnabled(groupAnalysis.cfgFlagsCalculationFractionPrimary); - doCalculationFluctuation = isEnabled(groupAnalysis.cfgFlagsCalculationFluctuation); - - rctFlagsChecker.init(groupEvent.cfgLabelFlagsRct.value, static_cast(groupEvent.cfgFlagsRct.value.get("ZDC")), static_cast(groupEvent.cfgFlagsRct.value.get("Acceptance")), static_cast(groupEvent.cfgFlagsRct.value.get("Table"))); - - ccdb->setURL(groupCcdb.cfgCcdbUrl.value); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(true); - if (groupCcdb.cfgCcdbTimestampLatest.value >= 0) { - ccdb->setCreatedNotAfter(groupCcdb.cfgCcdbTimestampLatest.value); + if (nEnabled(cgAnalysis.cfgFlagsCalculationFluctuation) > 1) { + LOG(fatal) << "Invalid " << cgAnalysis.cfgFlagsCalculationFluctuation.name << "!"; + } + if (nEnabled(cgAnalysis.cfgFlagsStorageMiniTable) > 1) { + LOG(fatal) << "Invalid " << cgAnalysis.cfgFlagsStorageMiniTable.name << "!"; } - const TList* const ccdbObject{ccdb->get(groupCcdb.cfgCcdbPath.value)}; - if (!ccdbObject || ccdbObject->IsA() != TList::Class()) { - LOG(fatal) << "Invalid CCDB object!"; + if ((cgAnalysis.cfgFlagQaEvent.value || cgAnalysis.cfgFlagQaCentrality.value || doCalculationFluctuation) && cgEvent.cfgNMultiplicityBinsAxis.value <= 0) { + LOG(fatal) << "Invalid " << cgEvent.cfgNMultiplicityBinsAxis.name << "!"; + } + if (doCalculationFluctuation && cgEvent.cfgNSubgroups.value <= 0) { + LOG(fatal) << "Invalid " << cgEvent.cfgNSubgroups.name << "!"; } - std::int32_t nRunsBad{}; - std::int32_t nRunGroups{}; - { - const TGraph* const gRunNumberGroupIndex{dynamic_cast(ccdbObject->FindObject("gRunNumberGroupIndex"))}; - if (!gRunNumberGroupIndex || gRunNumberGroupIndex->IsA() != TGraph::Class()) { - LOG(fatal) << "Invalid gRunNumberGroupIndex!"; + if (doStorageMiniTable) { + configSelection = std::make_unique(); + for (std::int32_t const& iSelection : std::views::iota(0, NEs)) { + configSelection->minItsNCls[iSelection] = cgTrack.cfgCutsMinItsNCls.value.get(iSelection); + configSelection->maxItsChi2NCls[iSelection] = cgTrack.cfgCutsMaxItsChi2NCls.value.get(iSelection); + configSelection->minTpcNCls[iSelection] = cgTrack.cfgCutsMinTpcNCls.value.get(iSelection); + configSelection->maxTpcChi2NCls[iSelection] = cgTrack.cfgCutsMaxTpcChi2NCls.value.get(iSelection); + configSelection->minTpcNCrossedRows[iSelection] = cgTrack.cfgCutsMinTpcNCrossedRows.value.get(iSelection); + configSelection->maxTpcNClsSharedRatio[iSelection] = cgTrack.cfgCutsMaxTpcNClsSharedRatio.value.get(iSelection); } - for (std::int32_t const& iRun : std::views::iota(0, gRunNumberGroupIndex->GetN())) { - const std::int32_t runGroupIndex{static_cast(std::llrint(gRunNumberGroupIndex->GetY()[iRun]))}; - if (runGroupIndex == 0 || (groupEvent.cfgFlagRejectionRunBad.value && runGroupIndex < 0)) { - ++nRunsBad; + for (std::int32_t const& iDcaAxis : std::views::iota(0, NEs)) { + for (std::int32_t const& iSelection : std::views::iota(0, NEs)) { + configSelection->maxAbsNSigmaDca[iDcaAxis][iSelection] = cgTrack.cfgCutsMaxAbsNSigmaDca.value.get(getName(iDcaAxis).data(), getName(iSelection).data()); } - nRunGroups = std::max(nRunGroups, std::abs(runGroupIndex)); - holderCcdb.runNumbersIndicesGroupIndices[std::llrint(gRunNumberGroupIndex->GetX()[iRun])] = {iRun, runGroupIndex}; } - } - if (groupEvent.cfgFlagRejectionRunBadMc.value) { - const TGraph* const gRunNumberGroupIndex{dynamic_cast(ccdbObject->FindObject("gRunNumberGroupIndex_mc"))}; - if (!gRunNumberGroupIndex || gRunNumberGroupIndex->IsA() != TGraph::Class()) { - LOG(fatal) << "Invalid gRunNumberGroupIndex_mc!"; + for (std::int32_t const& iParticleSpecies : std::views::iota(0, NEs)) { + for (std::int32_t const& iSelection : std::views::iota(0, NEs)) { + configSelection->maxAbsNSigmaPid[iParticleSpecies][iSelection] = cgTrack.cfgCutsMaxAbsNSigmaPid.value.get(getName(iParticleSpecies).data(), getName(iSelection).data()); + } } - for (std::int32_t const& iRun : std::views::iota(0, gRunNumberGroupIndex->GetN())) { - if (std::llrint(gRunNumberGroupIndex->GetY()[iRun]) <= 0) { - if (const auto iter{holderCcdb.runNumbersIndicesGroupIndices.find(std::llrint(gRunNumberGroupIndex->GetX()[iRun]))}; iter != holderCcdb.runNumbersIndicesGroupIndices.end() && iter->second.second > 0) { - iter->second.second = -iter->second.second; - if (groupEvent.cfgFlagRejectionRunBad.value) { - ++nRunsBad; + + static constexpr auto ValidateCuts{ + [] + requires IsValidEnumValue + (const auto& cuts, const auto& name) constexpr -> void { + for (std::int32_t const& iSelection : std::views::iota(0, NEs)) { + if (!std::isfinite(cuts[iSelection])) { + LOG(fatal) << "Non-finite value in " << name << "!"; + } + if (iSelection == 0) { + continue; + } + if constexpr (RangeEdgeValue == RangeEdge::Min) { + if (!(cuts[iSelection - 1] < cuts[iSelection])) { + LOG(fatal) << "Values in " << name << " must satisfy " << getName(Selection::Loose) << " < " << getName(Selection::Default) << " < " << getName(Selection::Tight) << "!"; + } + } else { + if (!(cuts[iSelection - 1] > cuts[iSelection])) { + LOG(fatal) << "Values in " << name << " must satisfy " << getName(Selection::Loose) << " > " << getName(Selection::Default) << " > " << getName(Selection::Tight) << "!"; + } } } - } + }}; + ValidateCuts.template operator()(configSelection->minItsNCls, cgTrack.cfgCutsMinItsNCls.name); + ValidateCuts.template operator()(configSelection->maxItsChi2NCls, cgTrack.cfgCutsMaxItsChi2NCls.name); + ValidateCuts.template operator()(configSelection->minTpcNCls, cgTrack.cfgCutsMinTpcNCls.name); + ValidateCuts.template operator()(configSelection->maxTpcChi2NCls, cgTrack.cfgCutsMaxTpcChi2NCls.name); + ValidateCuts.template operator()(configSelection->minTpcNCrossedRows, cgTrack.cfgCutsMinTpcNCrossedRows.name); + ValidateCuts.template operator()(configSelection->maxTpcNClsSharedRatio, cgTrack.cfgCutsMaxTpcNClsSharedRatio.name); + for (std::int32_t const& iDcaAxis : std::views::iota(0, NEs)) { + ValidateCuts.template operator()(configSelection->maxAbsNSigmaDca[iDcaAxis], cgTrack.cfgCutsMaxAbsNSigmaDca.name); + } + for (std::int32_t const& iParticleSpecies : std::views::iota(0, NEs)) { + ValidateCuts.template operator()(configSelection->maxAbsNSigmaPid[iParticleSpecies], cgTrack.cfgCutsMaxAbsNSigmaPid.name); + } + } + + if (doStorageMiniTable || static_cast(cgAnalysis.cfgFlagsCalculationFluctuation.value.get(toI(ParticleNumber::Charge)))) { + for (std::int32_t const& iParticleSpecies : std::views::iota(0, NEs)) { + rangePtAll[toI(RangeEdge::Min)] = std::min(rangePtAll[toI(RangeEdge::Min)], cgTrack.cfgCutsRangePt.value.get(iParticleSpecies, toI(RangeEdge::Min))); + rangePtAll[toI(RangeEdge::Max)] = std::max(rangePtAll[toI(RangeEdge::Max)], cgTrack.cfgCutsRangePt.value.get(iParticleSpecies, toI(RangeEdge::Max))); + } + } + + rctFlagsChecker.init(cgEvent.cfgLabelFlagsRct.value, static_cast(cgEvent.cfgFlagsRct.value.get("ZDC")), static_cast(cgEvent.cfgFlagsRct.value.get("Acceptance")), static_cast(cgEvent.cfgFlagsRct.value.get("Table"))); + + ccdb->setURL(cgCcdb.cfgCcdbUrl.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(true); + if (cgCcdb.cfgCcdbTimestampLatest.value >= 0) { + ccdb->setCreatedNotAfter(cgCcdb.cfgCcdbTimestampLatest.value); + } + + readCcdb(); + std::int32_t nRunsBad{}; + for (const auto& [runNumber, runIndexGroupIndex] : holderCcdb.runNumbersIndicesGroupIndices) { + const std::int32_t runGroupIndex{runIndexGroupIndex.second}; + if (runGroupIndex == 0 || (cgEvent.cfgFlagRejectionRunBad.value && runGroupIndex < 0)) { + ++nRunsBad; } } @@ -826,7 +1165,7 @@ struct PartNumFluc { LOG(info) << "Number of bad runs: " << nRunsBad; } for (const auto& [runNumber, runIndexGroupIndex] : holderCcdb.runNumbersIndicesGroupIndices) { - if (runIndexGroupIndex.second == 0 || (groupEvent.cfgFlagRejectionRunBad.value && runIndexGroupIndex.second < 0)) { + if (runIndexGroupIndex.second == 0 || (cgEvent.cfgFlagRejectionRunBad.value && runIndexGroupIndex.second < 0)) { LOG(info) << "Enabling rejecting run: " << runNumber << " (" << runIndexGroupIndex.second << ")"; } else { LOG(info) << "Enabling processing run: " << runNumber << " (" << std::abs(runIndexGroupIndex.second) << ")"; @@ -834,32 +1173,32 @@ struct PartNumFluc { } } - if (groupEvent.cfgLabelFlagsRct.value.empty()) { + if (cgEvent.cfgLabelFlagsRct.value.empty()) { LOG(info) << "No RCT flags label enabled."; } else { - LOG(info) << "Enabling RCT flags label: " << groupEvent.cfgLabelFlagsRct.value; + LOG(info) << "Enabling RCT flags label: " << cgEvent.cfgLabelFlagsRct.value; } - if (static_cast(groupEvent.cfgFlagsRct.value.get("ZDC"))) { + if (static_cast(cgEvent.cfgFlagsRct.value.get("ZDC"))) { LOG(info) << "Enabling RCT flag: ZDC"; } - if (static_cast(groupEvent.cfgFlagsRct.value.get("Acceptance"))) { + if (static_cast(cgEvent.cfgFlagsRct.value.get("Acceptance"))) { LOG(info) << "Enabling RCT flag: acceptance"; } - if (static_cast(groupEvent.cfgFlagsRct.value.get("Table"))) { + if (static_cast(cgEvent.cfgFlagsRct.value.get("Table"))) { LOG(info) << "Enabling RCT flag: table"; } - if ((groupEvent.cfgBitsSelectionEvent.value & ((std::uint64_t{1} << aod::evsel::EventSelectionFlags::kNsel) - 1)) == 0) { + if ((cgEvent.cfgBitsSelectionEvent.value & ((std::uint64_t{1} << aod::evsel::EventSelectionFlags::kNsel) - 1)) == 0) { LOG(info) << "No event selection bit enabled."; } else { - for (std::int32_t const& iEvSel : std::views::iota(0, aod::evsel::EventSelectionFlags::kNsel)) { - if (static_cast((groupEvent.cfgBitsSelectionEvent.value >> iEvSel) & 1)) { - LOG(info) << "Enabling event selection bit: " << aod::evsel::selectionLabels[iEvSel]; + for (std::int32_t const& iBit : std::views::iota(0, aod::evsel::EventSelectionFlags::kNsel)) { + if (static_cast((cgEvent.cfgBitsSelectionEvent.value >> iBit) & 1)) { + LOG(info) << "Enabling event selection bit: " << aod::evsel::selectionLabels[iBit]; } } } - switch (groupEvent.cfgIndexDefinitionCentrality.value) { + switch (cgEvent.cfgIndexDefinitionCentrality.value) { case toI(CentralityDefinition::Ft0a): LOG(info) << "Enabling centrality definition: FT0A"; break; @@ -871,74 +1210,12 @@ struct PartNumFluc { break; } - static constexpr auto ReadListRunGroup{[](const TList* const ccdbObject, const std::int32_t runGroupIndex) -> const TList* { - const std::string name{std::format("lRunGroup_{}", runGroupIndex)}; - const TList* const lRunGroup{dynamic_cast(ccdbObject->FindObject(name.c_str()))}; - if (!lRunGroup) { - LOG(fatal) << "Invalid " << name << "!"; - } - return lRunGroup; - }}; - - if (groupTrack.cfgFlagRecalibrationDca.value) { - LOG(info) << "Enabling DCA recalibration."; - - holderCcdb.fPtMeasureDca.resize(nRunGroups); - for (std::int32_t const& iRunGroup : std::views::iota(0, nRunGroups)) { - const TList* const lRunGroup{ReadListRunGroup(ccdbObject, iRunGroup + 1)}; - for (std::int32_t const& iDcaMeasure : std::views::iota(0, NEs)) { - for (std::int32_t const& iDcaAxis : std::views::iota(0, NEs)) { - for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - std::pair& calibration{holderCcdb.fPtMeasureDca[iRunGroup][iDcaMeasure][iDcaAxis][iChargeSpecies]}; - const std::string nameFormula{std::format("fPt{}Dca{}{}{}_runGroup{}", getName(iDcaMeasure), getName(iDcaAxis), getName(iChargeSpecies), doProcessMc.value ? "_mc" : "", iRunGroup + 1)}; - calibration.first = dynamic_cast(lRunGroup->FindObject(nameFormula.c_str())); - if (!calibration.first || calibration.first->GetNdim() != 1 || calibration.first->GetNpar() <= 0) { - LOG(fatal) << "Invalid " << nameFormula << "!"; - } - LOG(info) << "Reading from CCDB: " << nameFormula << " \"" << calibration.first->GetExpFormula() << "\""; - const std::int32_t nParameters{calibration.first->GetNpar()}; - - const std::string nameHistogram{std::format("hCentralityEtaParameterPt{}Dca{}{}{}_runGroup{}", getName(iDcaMeasure), getName(iDcaAxis), getName(iChargeSpecies), doProcessMc.value ? "_mc" : "", iRunGroup + 1)}; - calibration.second = dynamic_cast(lRunGroup->FindObject(nameHistogram.c_str())); - if (calibration.second == nullptr || calibration.second->GetNbinsZ() != nParameters || std::ranges::any_of(std::views::iota(0, nParameters), [zAxis = calibration.second->GetZaxis()](const std::int32_t binIndex) -> bool { return zAxis->GetBinCenter(binIndex + 1) != binIndex; })) { - LOG(fatal) << "Invalid " << nameHistogram << "!"; - } - LOG(info) << "Reading from CCDB: " << nameHistogram; - } - } - } - } - } - - for (std::int32_t const& iParticleSpecies : std::views::iota(0, NEs)) { - if (!static_cast(groupTrack.cfgFlagsRecalibrationNSigmaPid.value.get(iParticleSpecies))) { - continue; - } - - LOG(info) << "Enabling nSigma" << getName(iParticleSpecies) << " recalibration."; - - holderCcdb.hCentralityPtEtaShiftNSigmaPid.resize(nRunGroups); - for (std::int32_t const& iRunGroup : std::views::iota(0, nRunGroups)) { - const TList* const lRunGroup{ReadListRunGroup(ccdbObject, iRunGroup + 1)}; - for (std::int32_t const& iDetector : std::views::iota(0, NEs)) { - for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - const std::string name{std::format("hCentralityPtEtaShift{}NSigma{}{}{}_runGroup{}", getName(iDetector), getName(iParticleSpecies), getName(iChargeSpecies), doProcessMc.value ? "_mc" : "", iRunGroup + 1)}; - holderCcdb.hCentralityPtEtaShiftNSigmaPid[iRunGroup][iDetector][iParticleSpecies][iChargeSpecies] = dynamic_cast(lRunGroup->FindObject(name.c_str())); - if (!holderCcdb.hCentralityPtEtaShiftNSigmaPid[iRunGroup][iDetector][iParticleSpecies][iChargeSpecies]) { - LOG(fatal) << "Invalid " << name << "!"; - } - LOG(info) << "Reading from CCDB: " << name; - } - } - } - } - - hrCounter.add("hNEvents", ";;No. of Events", {HistType::kTH1D, {{10 + aod::evsel::EventSelectionFlags::kNsel, -0.5, 9.5 + static_cast(aod::evsel::EventSelectionFlags::kNsel), "Selection"}}}); + hrCounter.add("hNEvents", ";;No. of Events", {HistType::kTH1D, {{NEs + aod::evsel::EventSelectionFlags::kNsel, -0.5, static_cast(NEs + aod::evsel::EventSelectionFlags::kNsel) - 0.5, "Selection"}}}); if (doProcessMc.value) { - hrCounter.add("hNMcEvents", ";;No. of MC Events", {HistType::kTH1D, {{10, -0.5, 9.5, "Selection"}}}); + hrCounter.add("hNMcEvents", ";;No. of MC Events", {HistType::kTH1D, {{NEs, -0.5, static_cast(NEs) - 0.5, "Selection"}}}); } - if (groupAnalysis.cfgFlagQaRun.value) { + if (cgAnalysis.cfgFlagQaRun.value) { LOG(info) << "Enabling run QA."; const HistogramConfigSpec hcsQaRun{HistType::kTProfile, {{static_cast(holderCcdb.runNumbersIndicesGroupIndices.size()), -0.5, holderCcdb.runNumbersIndicesGroupIndices.size() - 0.5, "Run Index"}}}; @@ -979,72 +1256,71 @@ struct PartNumFluc { {std::format("{}NSigma{}", getName(Detector::Tof), getName(ParticleSpecies::Kaon)), std::format("{} #LT#it{{n}}#it{{#sigma}}_{{K}}#GT", getName(Detector::Tof)), true}, {std::format("{}NSigma{}", getName(Detector::Tof), getName(ParticleSpecies::Proton)), std::format("{} #LT#it{{n}}#it{{#sigma}}_{{p}}#GT", getName(Detector::Tof)), true}})) { if (!isChargeSpeciesSeparated) { - hrQaRun.add(std::format("QaRun/pRunIndex{}", name).c_str(), std::format(";;{}", title).c_str(), hcsQaRun); + hrQaRun.add(std::format("pRunIndex{}", name).c_str(), std::format(";;{}", title).c_str(), hcsQaRun); } else { - hrQaRun.add(std::format("QaRun/pRunIndex{}_{}", name, getName(ChargeSpecies::Plus)).c_str(), std::format(";;{} (#it{{q}}>0)", title).c_str(), hcsQaRun); - hrQaRun.add(std::format("QaRun/pRunIndex{}_{}", name, getName(ChargeSpecies::Minus)).c_str(), std::format(";;{} (#it{{q}}<0)", title).c_str(), hcsQaRun); + hrQaRun.add(std::format("pRunIndex{}_{}", name, getName(ChargeSpecies::Plus)).c_str(), std::format(";;{} (#it{{q}}>0)", title).c_str(), hcsQaRun); + hrQaRun.add(std::format("pRunIndex{}_{}", name, getName(ChargeSpecies::Minus)).c_str(), std::format(";;{} (#it{{q}}<0)", title).c_str(), hcsQaRun); } } } - if (groupAnalysis.cfgFlagQaEvent.value) { + if (cgAnalysis.cfgFlagQaEvent.value) { LOG(info) << "Enabling event QA."; - const AxisSpec asNTracks{200, -0.5, 199.5}; - const HistogramConfigSpec hcsQaEvent{HistType::kTHnSparseD, {asNTracks, asNTracks}}; + const AxisSpec asMultiplicity{cgEvent.cfgNMultiplicityBinsAxis.value, -0.5, cgEvent.cfgNMultiplicityBinsAxis.value - 0.5}; + const HistogramConfigSpec hcsQaEvent{HistType::kTHnSparseD, {asMultiplicity, asMultiplicity}}; - hrQaEvent.add("QaEvent/hVxVy", "", {HistType::kTHnSparseD, {{150, -0.15, 0.15, "#it{V}_{#it{x}} (cm)"}, {150, -0.15, 0.15, "#it{V}_{#it{y}} (cm)"}}}); - hrQaEvent.add("QaEvent/hVz", "", {HistType::kTH1D, {{300, -15., 15., "#it{V}_{#it{z}} (cm)"}}}); - hrQaEvent.add("QaEvent/hNPvContributorsNGlobalTracks", ";nPvContributors;nGlobalTracks;", hcsQaEvent); - hrQaEvent.add("QaEvent/hNGlobalTracksMeanDcaXy", ";nGlobalTracks;", {HistType::kTHnSparseD, {asNTracks, {250, -0.25, 0.25, "#LTDCA_{#it{xy}}#GT_{event} (cm)"}}}); - hrQaEvent.add("QaEvent/hNGlobalTracksMeanDcaXy_nPvContributorsCut", ";nGlobalTracks;", {HistType::kTHnSparseD, {asNTracks, {250, -0.25, 0.25, "#LTDCA_{#it{xy}}#GT_{event} (cm)"}}}); - hrQaEvent.add("QaEvent/hNGlobalTracksMeanDcaZ", ";nGlobalTracks;", {HistType::kTHnSparseD, {asNTracks, {200, -2., 2., "#LTDCA_{#it{z}}#GT_{event} (cm)"}}}); - hrQaEvent.add("QaEvent/hNGlobalTracksMeanDcaZ_nPvContributorsCut", ";nGlobalTracks;", {HistType::kTHnSparseD, {asNTracks, {200, -2., 2., "#LTDCA_{#it{z}}#GT_{event} (cm)"}}}); - hrQaEvent.add("QaEvent/hNTofBetaNGlobalTracks", ";nTofBeta;nGlobalTracks;", hcsQaEvent); - hrQaEvent.add("QaEvent/hNTofBetaNGlobalTracks_nPvContributorsCut", ";nTofBeta;nGlobalTracks;", hcsQaEvent); + hrQaEvent.add("hVxVy", "", {HistType::kTHnSparseD, {{150, -0.15, 0.15, "#it{V}_{#it{x}} (cm)"}, {150, -0.15, 0.15, "#it{V}_{#it{y}} (cm)"}}}); + hrQaEvent.add("hVz", "", {HistType::kTH1D, {{300, -15., 15., "#it{V}_{#it{z}} (cm)"}}}); + hrQaEvent.add("hNPvContributorsNGlobalTracks", ";nPvContributors;nGlobalTracks;", hcsQaEvent); + hrQaEvent.add("hNGlobalTracksMeanDcaXy", ";nGlobalTracks;", {HistType::kTHnSparseD, {asMultiplicity, {250, -0.25, 0.25, "#LTDCA_{#it{xy}}#GT_{event} (cm)"}}}); + hrQaEvent.add("hNGlobalTracksMeanDcaXy_nPvContributorsCut", ";nGlobalTracks;", {HistType::kTHnSparseD, {asMultiplicity, {250, -0.25, 0.25, "#LTDCA_{#it{xy}}#GT_{event} (cm)"}}}); + hrQaEvent.add("hNGlobalTracksMeanDcaZ", ";nGlobalTracks;", {HistType::kTHnSparseD, {asMultiplicity, {200, -2., 2., "#LTDCA_{#it{z}}#GT_{event} (cm)"}}}); + hrQaEvent.add("hNGlobalTracksMeanDcaZ_nPvContributorsCut", ";nGlobalTracks;", {HistType::kTHnSparseD, {asMultiplicity, {200, -2., 2., "#LTDCA_{#it{z}}#GT_{event} (cm)"}}}); + hrQaEvent.add("hNTofBetaNGlobalTracks", ";nTofBeta;nGlobalTracks;", hcsQaEvent); + hrQaEvent.add("hNTofBetaNGlobalTracks_nPvContributorsCut", ";nTofBeta;nGlobalTracks;", hcsQaEvent); } - if (groupAnalysis.cfgFlagQaCentrality.value) { + if (cgAnalysis.cfgFlagQaCentrality.value) { LOG(info) << "Enabling centrality QA."; - hrQaCentrality.add("QaCentrality/hCentralitySelection", "", {HistType::kTHnSparseD, {{100, 0., 100., "Centrality (%)"}, {10 + aod::evsel::EventSelectionFlags::kNsel, -0.5, 9.5 + static_cast(aod::evsel::EventSelectionFlags::kNsel), "Selection"}}}); - hrQaCentrality.add("QaCentrality/hCentralityMultiplicity", "", {HistType::kTHnSparseD, {{100, 0., 100., "Centrality (%)"}, {200, -0.5, 199.5, "Multiplicity"}}}); + hrQaCentrality.add("hCentralitySelection", "", {HistType::kTHnSparseD, {{100, 0., 100., "Centrality (%)"}, {NEs + aod::evsel::EventSelectionFlags::kNsel, -0.5, static_cast(NEs + aod::evsel::EventSelectionFlags::kNsel) - 0.5, "Selection"}}}); + hrQaCentrality.add("hCentralityMultiplicity", "", {HistType::kTHnSparseD, {{100, 0., 100., "Centrality (%)"}, {cgEvent.cfgNMultiplicityBinsAxis.value, -0.5, cgEvent.cfgNMultiplicityBinsAxis.value - 0.5, "Multiplicity"}}}); } - if (groupAnalysis.cfgFlagQaTrack.value) { + if (cgAnalysis.cfgFlagQaTrack.value) { LOG(info) << "Enabling track QA."; - for (const auto& [name, configSpec] : std::to_array>( - {{"ItsNCls", {HistType::kTH1D, {{10, -0.5, 9.5, "ITS nClusters"}}}}, - {"ItsChi2NCls", {HistType::kTH1D, {{80, 0., 40., "ITS #it{#chi}^{2}/nClusters"}}}}, + for (const auto& [name, hcs] : std::to_array>( + {{"ItsNClsChi2NCls", {HistType::kTHnSparseD, {{10, -0.5, 9.5, "ITS nClusters"}, {80, 0., 40., "ITS #it{#chi}^{2}/nClusters"}}}}, + {"TpcNClsChi2NCls", {HistType::kTHnSparseD, {{180, -0.5, 179.5, "TPC nClusters"}, {100, 0., 5., "TPC #it{#chi}^{2}/nClusters"}}}}, {"TpcNClsNClsShared", {HistType::kTHnSparseD, {{180, -0.5, 179.5, "TPC nClusters"}, {180, -0.5, 179.5, "TPC nSharedClusters"}}}}, - {"TpcChi2NCls", {HistType::kTH1D, {{100, 0., 5., "TPC #it{#chi}^{2}/nClusters"}}}}, {"TpcNClsFindableNCrossedRows", {HistType::kTHnSparseD, {{180, -0.5, 179.5, "TPC nFindableClusters"}, {180, -0.5, 179.5, "TPC nCrossedRows"}}}}})) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrQaTrack.add(std::format("QaTrack/h{}_{}", name, getName(iChargeSpecies)).c_str(), "", configSpec); + hrQaTrack.add(std::format("h{}_{}", name, getName(iChargeSpecies)).c_str(), "", hcs); } } } - if (groupAnalysis.cfgFlagQaDca.value) { + if (cgAnalysis.cfgFlagQaDca.value) { LOG(info) << "Enabling DCA QA."; const AxisSpec asPt{40, 0., 2., "#it{p}_{T} (GeV/#it{c})"}; - const HistogramConfigSpec hcsQaDcaProfile{HistType::kTProfile3D, {{groupEvent.cfgAxisCentralityCalibration, "Centrality (%)"}, asPt, {24, -1.2, 1.2, "#it{#eta}"}}}; + const HistogramConfigSpec hcsQaDcaProfile{HistType::kTProfile3D, {{cgEvent.cfgAxisCentralityCalibration, "Centrality (%)"}, asPt, {24, -1.2, 1.2, "#it{#eta}"}}}; - for (const auto& [name, title, configSpec] : std::to_array>( + for (const auto& [name, title, hcs] : std::to_array>( {{"hPtDcaXy", "", {HistType::kTHnSparseD, {asPt, {250, -0.25, 0.25, "DCA_{#it{xy}} (cm)"}}}}, {"pCentralityPtEtaDcaXy", ";;#LTDCA_{#it{xy}}#GT (cm)", hcsQaDcaProfile}, {"hPtDcaZ", "", {HistType::kTHnSparseD, {asPt, {250, -0.5, 0.5, "DCA_{#it{z}} (cm)"}}}}, {"pCentralityPtEtaDcaZ", ";;#LTDCA_{#it{z}}#GT (cm)", hcsQaDcaProfile}})) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrQaDca.add(std::format("QaDca/{}_{}", name, getName(iChargeSpecies)).c_str(), title.data(), configSpec); + hrQaDca.add(std::format("{}_{}", name, getName(iChargeSpecies)).c_str(), title.data(), hcs); } } } for (std::int32_t const& iParticleSpeciesAll : std::views::iota(0, NEs)) { - if (!static_cast(groupAnalysis.cfgFlagsQaAcceptance.value.get(iParticleSpeciesAll))) { + if (!static_cast(cgAnalysis.cfgFlagsQaAcceptance.value.get(iParticleSpeciesAll))) { continue; } @@ -1052,107 +1328,107 @@ struct PartNumFluc { for (std::int32_t const& iPidStrategy : std::views::iota(0, NEs)) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrQaAcceptance.add(std::format("QaAcceptance/h{}Pt_{}Edge{}{}", iParticleSpeciesAll == toI(ParticleSpeciesAll::All) ? "Eta" : "Rapidity", getName(iPidStrategy), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), "", {HistType::kTHnSparseD, {{300, -1.5, 1.5, iParticleSpeciesAll == toI(ParticleSpeciesAll::All) ? "#it{#eta}" : "#it{y}"}, {250, 0., 2.5, "#it{p}_{T} (GeV/#it{c})"}}}); + hrQaAcceptance.add(std::format("h{}Pt_{}Edge{}{}", iParticleSpeciesAll == toI(ParticleSpeciesAll::All) ? "Eta" : "Rapidity", getName(iPidStrategy), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), "", {HistType::kTHnSparseD, {{300, -1.5, 1.5, iParticleSpeciesAll == toI(ParticleSpeciesAll::All) ? "#it{#eta}" : "#it{y}"}, {250, 0., 2.5, "#it{p}_{T} (GeV/#it{c})"}}}); } } } for (std::int32_t const& iParticleSpeciesAll : std::views::iota(0, NEs)) { - if (!static_cast(groupAnalysis.cfgFlagsQaPhi.value.get(iParticleSpeciesAll))) { + if (!static_cast(cgAnalysis.cfgFlagsQaPhi.value.get(iParticleSpeciesAll))) { continue; } LOG(info) << "Enabling " << getName(iParticleSpeciesAll) << " phi QA."; - const HistogramConfigSpec hcsQaPhi{HistType::kTHnSparseF, {{groupEvent.cfgAxisCentralityCalibration, "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {24, -1.2, 1.2, "#it{#eta}"}, {360, 0., constants::math::TwoPI, "#it{#varphi} (rad)"}}}; + const HistogramConfigSpec hcsQaPhi{HistType::kTHnSparseF, {{cgEvent.cfgAxisCentralityCalibration, "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {24, -1.2, 1.2, "#it{#eta}"}, {360, 0., constants::math::TwoPI, "#it{#varphi} (rad)"}}}; for (std::int32_t const& iPidStrategy : std::views::iota(0, NEs)) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrQaPhi.add(std::format("QaPhi/hCentralityPtEtaPhi_{}{}{}{}", doProcessMc.value ? "mc" : "", doProcessMc.value ? getName(iPidStrategy) : getName(iPidStrategy), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), "", hcsQaPhi); + hrQaPhi.add(std::format("hCentralityPtEtaPhi_{}{}{}{}", doProcessMc.value ? "mc" : "", doProcessMc.value ? getName(iPidStrategy) : getName(iPidStrategy), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), "", hcsQaPhi); } } } for (std::int32_t const& iParticleSpeciesAll : std::views::iota(0, NEs)) { - if (!static_cast(groupAnalysis.cfgFlagsQaPid.value.get(iParticleSpeciesAll))) { + if (!static_cast(cgAnalysis.cfgFlagsQaPid.value.get(iParticleSpeciesAll))) { continue; } LOG(info) << "Enabling " << getName(iParticleSpeciesAll) << " PID QA."; - const AxisSpec asCentrality{groupEvent.cfgAxisCentralityCalibration, "Centrality (%)"}; + const AxisSpec asCentrality{cgEvent.cfgAxisCentralityCalibration, "Centrality (%)"}; if (iParticleSpeciesAll == toI(ParticleSpeciesAll::All)) { const AxisSpec asPOverQ{350, -3.5, 3.5, "#it{p}/#it{q} (GeV/#it{c})"}; const AxisSpec asEta{48, -1.2, 1.2, "#it{#eta}"}; - hrQaPid.add("QaPid/hCentralityPOverQEtaTpcLnDeDx", "", {HistType::kTHnSparseF, {asCentrality, asPOverQ, asEta, {240, 3., 9., "TPC ln(d#it{E}/d#it{x} (a.u.))"}}}); - hrQaPid.add("QaPid/hCentralityPOverQEtaTofInverseBeta", "", {HistType::kTHnSparseF, {asCentrality, asPOverQ, asEta, {120, 0.5, 3.5, "TOF 1/#it{#beta}"}}}); + hrQaPid.add("hCentralityPOverQEtaTpcLnDeDx", "", {HistType::kTHnSparseF, {asCentrality, asPOverQ, asEta, {240, 3., 9., "TPC ln(d#it{E}/d#it{x} (a.u.))"}}}); + hrQaPid.add("hCentralityPOverQEtaTofInverseBeta", "", {HistType::kTHnSparseF, {asCentrality, asPOverQ, asEta, {120, 0.5, 3.5, "TOF 1/#it{#beta}"}}}); } else { const HistogramConfigSpec hcsQaPid{HistType::kTHnSparseF, {asCentrality, {40, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {32, -0.8, 0.8, "#it{#eta}"}, {300, -30., 30.}}}; if (doProcessMc.value) { for (std::int32_t const& iDetector : std::views::iota(0, NEs)) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrQaPid.add(std::format("QaPid/hCentralityPtEta{}NSigma{}_mc{}{}", getName(iDetector), getName(iParticleSpeciesAll), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), std::format(";;;;{} #it{{n}}#it{{#sigma}}_{{{}}};", getName(iDetector), getTitle(iParticleSpeciesAll)).c_str(), hcsQaPid); + hrQaPid.add(std::format("hCentralityPtEta{}NSigma{}_mc{}{}", getName(iDetector), getName(iParticleSpeciesAll), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), std::format(";;;;{} #it{{n}}#it{{#sigma}}_{{{}}};", getName(iDetector), getTitle(iParticleSpeciesAll)).c_str(), hcsQaPid); } } } else { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrQaPid.add(std::format("QaPid/hCentralityPtEta{}NSigma{}_{}", getName(Detector::Tpc), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), std::format(";;;;{} #it{{n}}#it{{#sigma}}_{{{}}};", getName(Detector::Tpc), getTitle(iParticleSpeciesAll)).c_str(), hcsQaPid); + hrQaPid.add(std::format("hCentralityPtEta{}NSigma{}_{}", getName(Detector::Tpc), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), std::format(";;;;{} #it{{n}}#it{{#sigma}}_{{{}}};", getName(Detector::Tpc), getTitle(iParticleSpeciesAll)).c_str(), hcsQaPid); } for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrQaPid.add(std::format("QaPid/hCentralityPtEta{}NSigma{}_{}{}{}", getName(Detector::Tpc), getName(iParticleSpeciesAll), getName(Detector::Tof), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), std::format(";;;;{} #it{{n}}#it{{#sigma}}_{{{}}};", getName(Detector::Tpc), getTitle(iParticleSpeciesAll)).c_str(), hcsQaPid); + hrQaPid.add(std::format("hCentralityPtEta{}NSigma{}_{}{}{}", getName(Detector::Tpc), getName(iParticleSpeciesAll), getName(Detector::Tof), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), std::format(";;;;{} #it{{n}}#it{{#sigma}}_{{{}}};", getName(Detector::Tpc), getTitle(iParticleSpeciesAll)).c_str(), hcsQaPid); } for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrQaPid.add(std::format("QaPid/hCentralityPtEta{}NSigma{}_{}{}{}", getName(Detector::Tof), getName(iParticleSpeciesAll), getName(Detector::Tpc), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), std::format(";;;;{} #it{{n}}#it{{#sigma}}_{{{}}};", getName(Detector::Tof), getTitle(iParticleSpeciesAll)).c_str(), hcsQaPid); + hrQaPid.add(std::format("hCentralityPtEta{}NSigma{}_{}{}{}", getName(Detector::Tof), getName(iParticleSpeciesAll), getName(Detector::Tpc), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), std::format(";;;;{} #it{{n}}#it{{#sigma}}_{{{}}};", getName(Detector::Tof), getTitle(iParticleSpeciesAll)).c_str(), hcsQaPid); } for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrQaPid.add(std::format("QaPid/hCentralityPtEta{}NSigma{}_{}", getName(PidStrategy::TpcTof), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), std::format(";;;;{} #it{{n}}#it{{#sigma}}_{{{}}};", getName(PidStrategy::TpcTof), getTitle(iParticleSpeciesAll)).c_str(), hcsQaPid); + hrQaPid.add(std::format("hCentralityPtEta{}NSigma{}_{}", getName(PidStrategy::TpcTof), getName(iParticleSpeciesAll), getName(iChargeSpecies)).c_str(), std::format(";;;;{} #it{{n}}#it{{#sigma}}_{{{}}};", getName(PidStrategy::TpcTof), getTitle(iParticleSpeciesAll)).c_str(), hcsQaPid); } } } } if (doProcessMc.value) { - if (groupAnalysis.cfgFlagQaMc.value) { + if (cgAnalysis.cfgFlagQaMc.value) { LOG(info) << "Enabling MC QA."; - const double maxAbsVz{std::ceil(groupEvent.cfgFlagMcCollisionVz.value ? groupEvent.cfgCutMaxAbsVzMc.value : groupEvent.cfgCutMaxAbsVz.value)}; + const double maxAbsVz{std::ceil(cgEvent.cfgFlagMcCollisionVz.value ? cgEvent.cfgCutMaxAbsVzMc.value : cgEvent.cfgCutMaxAbsVz.value)}; const AxisSpec asCentrality{20, 0., 100., "Centrality (%)"}; - hrQaMc.add("QaMc/hCentralityVzMcDeltaVz", "", {HistType::kTHnSparseF, {asCentrality, {static_cast(maxAbsVz) * 20, -maxAbsVz, maxAbsVz, "#it{V}_{#it{z}}^{Gen} (cm)"}, {200, -0.2, 0.2, "#it{V}_{#it{z}}^{Rec}#minus#it{V}_{#it{z}}^{Gen} (cm)"}}}); - hrQaMc.add("QaMc/hCentralityPtMcEtaMcDeltaPt", "", {HistType::kTHnSparseF, {asCentrality, {200, 0., 2., "#it{p}_{T}^{Gen} (GeV/#it{c})"}, {24, -1.2, 1.2, "#it{#eta}_{Gen}"}, {320, -0.8, 0.8, "#it{p}_{T}^{Rec}#minus#it{p}_{T}^{Gen} (GeV/#it{c})"}}}); - hrQaMc.add("QaMc/hCentralityPtMcEtaMcDeltaEta", "", {HistType::kTHnSparseF, {asCentrality, {20, 0., 2., "#it{p}_{T}^{Gen} (GeV/#it{c})"}, {240, -1.2, 1.2, "#it{#eta}_{Gen}"}, {160, -0.4, 0.4, "#it{#eta}_{Rec}#minus#it{#eta}_{Gen}"}}}); + hrQaMc.add("hCentralityVzMcDeltaVz", "", {HistType::kTHnSparseF, {asCentrality, {static_cast(maxAbsVz) * 20, -maxAbsVz, maxAbsVz, "#it{V}_{#it{z}}^{Gen} (cm)"}, {200, -0.2, 0.2, "#it{V}_{#it{z}}^{Rec}#minus#it{V}_{#it{z}}^{Gen} (cm)"}}}); + hrQaMc.add("hCentralityPtMcEtaMcDeltaPt", "", {HistType::kTHnSparseF, {asCentrality, {200, 0., 2., "#it{p}_{T}^{Gen} (GeV/#it{c})"}, {24, -1.2, 1.2, "#it{#eta}_{Gen}"}, {320, -0.8, 0.8, "#it{p}_{T}^{Rec}#minus#it{p}_{T}^{Gen} (GeV/#it{c})"}}}); + hrQaMc.add("hCentralityPtMcEtaMcDeltaEta", "", {HistType::kTHnSparseF, {asCentrality, {20, 0., 2., "#it{p}_{T}^{Gen} (GeV/#it{c})"}, {240, -1.2, 1.2, "#it{#eta}_{Gen}"}, {160, -0.4, 0.4, "#it{#eta}_{Rec}#minus#it{#eta}_{Gen}"}}}); } } for (std::int32_t const& iParticleSpecies : std::views::iota(0, NEs)) { - if (!static_cast(groupAnalysis.cfgFlagsCalculationYield.value.get(iParticleSpecies))) { + if (!static_cast(cgAnalysis.cfgFlagsCalculationYield.value.get(iParticleSpecies))) { continue; } LOG(info) << "Enabling " << getName(iParticleSpecies) << " yield calculation."; - const double maxAbsVz{std::ceil(doProcessMc.value && groupEvent.cfgFlagMcCollisionVz.value ? groupEvent.cfgCutMaxAbsVzMc.value : groupEvent.cfgCutMaxAbsVz.value)}; - const HistogramConfigSpec hcsCalculationYield{HistType::kTHnSparseF, {{static_cast(maxAbsVz) * 2, -maxAbsVz, maxAbsVz, "#it{V}_{#it{z}} (cm)"}, {groupEvent.cfgAxisCentralityCalibration, "Centrality (%)"}, {40, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {32, -0.8, 0.8, "#it{#eta}"}}}; + const double maxAbsVz{std::ceil(doProcessMc.value && cgEvent.cfgFlagMcCollisionVz.value ? cgEvent.cfgCutMaxAbsVzMc.value : cgEvent.cfgCutMaxAbsVz.value)}; + const HistogramConfigSpec hcsCalculationYield{HistType::kTHnSparseF, {{static_cast(maxAbsVz) * 2, -maxAbsVz, maxAbsVz, "#it{V}_{#it{z}} (cm)"}, {cgEvent.cfgAxisCentralityCalibration, "Centrality (%)"}, {40, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {32, -0.8, 0.8, "#it{#eta}"}}}; if (doProcessMc.value) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrCalculationYield.add(std::format("CalculationYield/hVzCentralityPtMcEtaMc_mc{}{}", getName(iParticleSpecies), getName(iChargeSpecies)).c_str(), "", hcsCalculationYield); + hrCalculationYield.add(std::format("hVzCentralityPtMcEtaMc_mc{}{}", getName(iParticleSpecies), getName(iChargeSpecies)).c_str(), "", hcsCalculationYield); } for (std::int32_t const& iPidStrategy : std::views::iota(0, NEs)) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - if (groupTrack.cfgFlagMcParticleMomentum.value) { - hrCalculationYield.add(std::format("CalculationYield/hVzCentralityPtMcEtaMc_mc{}{}{}", getName(iPidStrategy), getName(iParticleSpecies), getName(iChargeSpecies)).c_str(), "", hcsCalculationYield); + if (cgTrack.cfgFlagMcParticleMomentum.value) { + hrCalculationYield.add(std::format("hVzCentralityPtMcEtaMc_mc{}{}{}", getName(iPidStrategy), getName(iParticleSpecies), getName(iChargeSpecies)).c_str(), "", hcsCalculationYield); } else { - hrCalculationYield.add(std::format("CalculationYield/hVzCentralityPtEta_mc{}{}{}", getName(iPidStrategy), getName(iParticleSpecies), getName(iChargeSpecies)).c_str(), "", hcsCalculationYield); + hrCalculationYield.add(std::format("hVzCentralityPtEta_mc{}{}{}", getName(iPidStrategy), getName(iParticleSpecies), getName(iChargeSpecies)).c_str(), "", hcsCalculationYield); } } } } else { for (std::int32_t const& iPidStrategy : std::views::iota(0, NEs)) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrCalculationYield.add(std::format("CalculationYield/hVzCentralityPtEta_{}{}{}", getName(iPidStrategy), getName(iParticleSpecies), getName(iChargeSpecies)).c_str(), "", hcsCalculationYield); + hrCalculationYield.add(std::format("hVzCentralityPtEta_{}{}{}", getName(iPidStrategy), getName(iParticleSpecies), getName(iChargeSpecies)).c_str(), "", hcsCalculationYield); } } } @@ -1160,17 +1436,17 @@ struct PartNumFluc { if (doProcessMc.value) { for (std::int32_t const& iParticleSpecies : std::views::iota(0, NEs)) { - if (!static_cast(groupAnalysis.cfgFlagsCalculationPurity.value.get(iParticleSpecies))) { + if (!static_cast(cgAnalysis.cfgFlagsCalculationPurity.value.get(iParticleSpecies))) { continue; } LOG(info) << "Enabling " << getName(iParticleSpecies) << " purity calculation."; - const HistogramConfigSpec hcsCalculationPurity{HistType::kTProfile3D, {{groupEvent.cfgAxisCentralityCalibration, "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#it{#eta}"}}}; + const HistogramConfigSpec hcsCalculationPurity{HistType::kTProfile3D, {{cgEvent.cfgAxisCentralityCalibration, "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#it{#eta}"}}}; for (std::int32_t const& iPidStrategy : std::views::iota(0, NEs)) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrCalculationPurity.add(std::format("CalculationPurity/pCentralityPtEtaPurity{}{}{}", getName(iPidStrategy), getName(iParticleSpecies), getName(iChargeSpecies)).c_str(), "", hcsCalculationPurity); + hrCalculationPurity.add(std::format("pCentralityPtEtaPurity{}{}{}", getName(iPidStrategy), getName(iParticleSpecies), getName(iChargeSpecies)).c_str(), "", hcsCalculationPurity); } } } @@ -1178,69 +1454,158 @@ struct PartNumFluc { if (doProcessMc.value) { for (std::int32_t const& iParticleSpecies : std::views::iota(0, NEs)) { - if (!static_cast(groupAnalysis.cfgFlagsCalculationFractionPrimary.value.get(iParticleSpecies))) { + if (!static_cast(cgAnalysis.cfgFlagsCalculationFractionPrimary.value.get(iParticleSpecies))) { continue; } LOG(info) << "Enabling " << getName(iParticleSpecies) << " primary fraction calculation."; - const HistogramConfigSpec hcsCalculationFractionPrimary{HistType::kTProfile3D, {{groupEvent.cfgAxisCentralityCalibration, "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#it{#eta}"}}}; + const HistogramConfigSpec hcsCalculationFractionPrimary{HistType::kTProfile3D, {{cgEvent.cfgAxisCentralityCalibration, "Centrality (%)"}, {20, 0., 2., "#it{p}_{T} (GeV/#it{c})"}, {16, -0.8, 0.8, "#it{#eta}"}}}; for (std::int32_t const& iPidStrategy : std::views::iota(0, NEs)) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - hrCalculationFractionPrimary.add(std::format("CalculationFractionPrimary/pCentralityPtEtaFractionPrimary{}{}{}", getName(iPidStrategy), getName(iParticleSpecies), getName(iChargeSpecies)).c_str(), "", hcsCalculationFractionPrimary); + hrCalculationFractionPrimary.add(std::format("pCentralityPtEtaFractionPrimary{}{}{}", getName(iPidStrategy), getName(iParticleSpecies), getName(iChargeSpecies)).c_str(), "", hcsCalculationFractionPrimary); } } } } - if (nEnabled(groupAnalysis.cfgFlagsCalculationFluctuation) > 1) { - LOG(fatal) << "Invalid " << groupAnalysis.cfgFlagsCalculationFluctuation.name << "!"; - } - if (doCalculationFluctuation && groupEvent.cfgNSubgroups.value <= 0) { - LOG(fatal) << "Invalid " << groupEvent.cfgNSubgroups.name << "!"; - } for (std::int32_t const& iParticleNumber : std::views::iota(0, NEs)) { - if (!static_cast(groupAnalysis.cfgFlagsCalculationFluctuation.value.get(iParticleNumber))) { + if (!static_cast(cgAnalysis.cfgFlagsCalculationFluctuation.value.get(iParticleNumber))) { continue; } LOG(info) << "Enabling " << getName(iParticleNumber) << " number fluctuation calculation."; - const AxisSpec asCentrality{groupEvent.cfgAxisCentrality, "Centrality (%)"}; - const HistogramConfigSpec hcsDistribution{HistType::kTHnSparseD, {asCentrality, {200, -0.5, 199.5}, {200, -0.5, 199.5}}}; - const HistogramConfigSpec hcsFluctuationCalculator{HistType::kTH3D, {asCentrality, {groupEvent.cfgNSubgroups.value, -0.5, groupEvent.cfgNSubgroups.value - 0.5, "Subgroup Index"}, {fluctuation_calculator_base::NOrderKeys, -0.5, fluctuation_calculator_base::NOrderKeys - 0.5, "Order Key Index"}}}; + const AxisSpec asCentrality{cgEvent.cfgAxisCentrality, "Centrality (%)"}; + const AxisSpec asMultiplicity{cgEvent.cfgNMultiplicityBinsAxis.value, -0.5, cgEvent.cfgNMultiplicityBinsAxis.value - 0.5}; + const HistogramConfigSpec hcsDistribution{HistType::kTHnSparseD, {asCentrality, asMultiplicity, asMultiplicity}}; + const HistogramConfigSpec hcsFluctuationCalculator{HistType::kTH3D, {asCentrality, {cgEvent.cfgNSubgroups.value, -0.5, cgEvent.cfgNSubgroups.value - 0.5, "Subgroup Index"}, {fluctuation_calculator_base::NOrderKeys, -0.5, fluctuation_calculator_base::NOrderKeys - 0.5, "Order Key Index"}}}; for (std::int32_t const& iChargeNumber : std::views::iota(0, NEs)) { - fluctuationCalculatorTrack[iParticleNumber][iChargeNumber] = std::make_unique(); + if (doProcessMc.value) { + fluctuationCalculatorsTrackMcParticle[iParticleNumber][iChargeNumber] = std::make_unique(); + } + fluctuationCalculatorsTrackTrack[iParticleNumber][iChargeNumber] = std::make_unique(); } if (doProcessMc.value) { - hrCalculationFluctuation.add(std::format("CalculationFluctuation/hCentralityN{}{}N{}{}_mc", getName(iParticleNumber), getName(ChargeSpecies::Plus), getName(iParticleNumber), getName(ChargeSpecies::Minus)).c_str(), std::format(";;#it{{N}}({}^{{{}}});#it{{N}}({}^{{{}}});", getTitle(iParticleNumber), getTitle(toI(ChargeSpecies::Plus)), getTitle(iParticleNumber), getTitle(toI(ChargeSpecies::Minus))).c_str(), hcsDistribution); - hrCalculationFluctuation.add(std::format("CalculationFluctuation/hCentralityN{}{}N{}{}_mcEff", getName(iParticleNumber), getName(ChargeSpecies::Plus), getName(iParticleNumber), getName(ChargeSpecies::Minus)).c_str(), std::format(";;#it{{N}}({}^{{{}}});#it{{N}}({}^{{{}}});", getTitle(iParticleNumber), getTitle(toI(ChargeSpecies::Plus)), getTitle(iParticleNumber), getTitle(toI(ChargeSpecies::Minus))).c_str(), hcsDistribution); + hrCalculationFluctuation.add(std::format("hCentralityN{}{}N{}{}_mc", getName(iParticleNumber), getName(ChargeSpecies::Plus), getName(iParticleNumber), getName(ChargeSpecies::Minus)).c_str(), std::format(";;#it{{N}}({}^{{{}}});#it{{N}}({}^{{{}}});", getTitle(iParticleNumber), getTitle(toI(ChargeSpecies::Plus)), getTitle(iParticleNumber), getTitle(toI(ChargeSpecies::Minus))).c_str(), hcsDistribution); + hrCalculationFluctuation.add(std::format("hCentralityN{}{}N{}{}_mcEff", getName(iParticleNumber), getName(ChargeSpecies::Plus), getName(iParticleNumber), getName(ChargeSpecies::Minus)).c_str(), std::format(";;#it{{N}}({}^{{{}}});#it{{N}}({}^{{{}}});", getTitle(iParticleNumber), getTitle(toI(ChargeSpecies::Plus)), getTitle(iParticleNumber), getTitle(toI(ChargeSpecies::Minus))).c_str(), hcsDistribution); for (std::int32_t const& iChargeNumber : std::views::iota(0, NEs)) { - hrCalculationFluctuation.add(std::format("CalculationFluctuation/hFluctuationCalculator{}{}_mc", getName(iParticleNumber), getName(iChargeNumber)).c_str(), "", hcsFluctuationCalculator); + hrCalculationFluctuation.add(std::format("hFluctuationCalculator{}{}_mc", getName(iParticleNumber), getName(iChargeNumber)).c_str(), "", hcsFluctuationCalculator); } } - hrCalculationFluctuation.add(std::format("CalculationFluctuation/hCentralityN{}{}N{}{}", getName(iParticleNumber), getName(ChargeSpecies::Plus), getName(iParticleNumber), getName(ChargeSpecies::Minus)).c_str(), std::format(";;#it{{N}}({}^{{{}}});#it{{N}}({}^{{{}}});", getTitle(iParticleNumber), getTitle(toI(ChargeSpecies::Plus)), getTitle(iParticleNumber), getTitle(toI(ChargeSpecies::Minus))).c_str(), hcsDistribution); + hrCalculationFluctuation.add(std::format("hCentralityN{}{}N{}{}", getName(iParticleNumber), getName(ChargeSpecies::Plus), getName(iParticleNumber), getName(ChargeSpecies::Minus)).c_str(), std::format(";;#it{{N}}({}^{{{}}});#it{{N}}({}^{{{}}});", getTitle(iParticleNumber), getTitle(toI(ChargeSpecies::Plus)), getTitle(iParticleNumber), getTitle(toI(ChargeSpecies::Minus))).c_str(), hcsDistribution); for (std::int32_t const& iChargeNumber : std::views::iota(0, NEs)) { - hrCalculationFluctuation.add(std::format("CalculationFluctuation/hFluctuationCalculator{}{}", getName(iParticleNumber), getName(iChargeNumber)).c_str(), "", hcsFluctuationCalculator); + hrCalculationFluctuation.add(std::format("hFluctuationCalculator{}{}", getName(iParticleNumber), getName(iChargeNumber)).c_str(), "", hcsFluctuationCalculator); } } + } - for (std::int32_t const& iParticleSpecies : std::views::iota(0, NEs)) { - if (!static_cast(groupAnalysis.cfgFlagsCalculationFluctuation.value.get(toI(ParticleNumber::Charge))) && (iParticleSpecies != toI(ParticleSpecies::Kaon) || !static_cast(groupAnalysis.cfgFlagsCalculationFluctuation.value.get(toI(ParticleNumber::Kaon)))) && (iParticleSpecies != toI(ParticleSpecies::Proton) || !static_cast(groupAnalysis.cfgFlagsCalculationFluctuation.value.get(toI(ParticleNumber::Proton))))) { - continue; + template + void readCcdb() + { + if constexpr (DoInit) { + holderCcdb.lCcdb = ccdb->get(cgCcdb.cfgCcdbPath.value); + if (!holderCcdb.lCcdb || holderCcdb.lCcdb->IsA() != TList::Class()) { + LOG(fatal) << "Invalid CCDB object!"; + } + + const TGraph* const gRunNumberGroupIndex{dynamic_cast(holderCcdb.lCcdb->FindObject("gRunNumberGroupIndex"))}; + if (!gRunNumberGroupIndex || gRunNumberGroupIndex->IsA() != TGraph::Class()) { + LOG(fatal) << "Invalid gRunNumberGroupIndex!"; + } + for (std::int32_t const& iRun : std::views::iota(0, gRunNumberGroupIndex->GetN())) { + holderCcdb.runNumbersIndicesGroupIndices[static_cast(std::rint(gRunNumberGroupIndex->GetX()[iRun]))] = {iRun, static_cast(std::rint(gRunNumberGroupIndex->GetY()[iRun]))}; + } + + if (cgEvent.cfgFlagRejectionRunBadMc.value) { + const TGraph* const gRunNumberGroupIndexMc{dynamic_cast(holderCcdb.lCcdb->FindObject("gRunNumberGroupIndex_mc"))}; + if (!gRunNumberGroupIndexMc || gRunNumberGroupIndexMc->IsA() != TGraph::Class()) { + LOG(fatal) << "Invalid gRunNumberGroupIndex_mc!"; + } + for (std::int32_t const& iRun : std::views::iota(0, gRunNumberGroupIndexMc->GetN())) { + if (static_cast(std::rint(gRunNumberGroupIndexMc->GetY()[iRun])) <= 0) { + if (const auto iter{holderCcdb.runNumbersIndicesGroupIndices.find(static_cast(std::rint(gRunNumberGroupIndexMc->GetX()[iRun])))}; iter != holderCcdb.runNumbersIndicesGroupIndices.end() && iter->second.second > 0) { + iter->second.second = -iter->second.second; + } + } + } + } + } else { + const std::int32_t runGroupIndex{std::abs(holderEvent.runGroupIndex)}; + if (holderCcdb.runGroupIndexCurrent == runGroupIndex) { + return; + } + + holderCcdb.runGroupIndexCurrent = runGroupIndex; + holderCcdb.calibrationsPtMeasureDca = {}; + holderCcdb.hsCentralityPtEtaShiftNSigmaPid = {}; + holderCcdb.hsVzCentralityPtEtaEfficiency = {}; + if (!cgTrack.cfgFlagRecalibrationDca.value && !isEnabled(cgTrack.cfgFlagsRecalibrationNSigmaPid) && !doCalculationFluctuation) { + return; + } + + const std::string nameList{std::format("lRunGroup_{}", runGroupIndex)}; + const TList* const lRunGroup{dynamic_cast(holderCcdb.lCcdb->FindObject(nameList.c_str()))}; + if (!lRunGroup) { + LOG(fatal) << "Invalid " << nameList << "!"; } - holderCcdb.hVzCentralityPtEtaEfficiency.resize(nRunGroups); - for (std::int32_t const& iRunGroup : std::views::iota(0, nRunGroups)) { - const TList* const lRunGroup{ReadListRunGroup(ccdbObject, iRunGroup + 1)}; + if (cgTrack.cfgFlagRecalibrationDca.value) { + for (std::int32_t const& iDcaMeasure : std::views::iota(0, NEs)) { + for (std::int32_t const& iDcaAxis : std::views::iota(0, NEs)) { + for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { + std::pair& calibration{holderCcdb.calibrationsPtMeasureDca[iDcaMeasure][iDcaAxis][iChargeSpecies]}; + const std::string nameFormula{std::format("fPt{}Dca{}{}{}_runGroup{}", getName(iDcaMeasure), getName(iDcaAxis), getName(iChargeSpecies), doProcessMc.value ? "_mc" : "", runGroupIndex)}; + calibration.first = dynamic_cast(lRunGroup->FindObject(nameFormula.c_str())); + if (!calibration.first || calibration.first->GetNdim() != 1 || calibration.first->GetNpar() <= 0) { + LOG(fatal) << "Invalid " << nameFormula << "!"; + } + LOG(info) << "Reading from CCDB: " << nameFormula << " \"" << calibration.first->GetExpFormula() << "\""; + const std::int32_t nParameters{calibration.first->GetNpar()}; + + const std::string nameHistogram{std::format("hCentralityEtaParameterPt{}Dca{}{}{}_runGroup{}", getName(iDcaMeasure), getName(iDcaAxis), getName(iChargeSpecies), doProcessMc.value ? "_mc" : "", runGroupIndex)}; + calibration.second = dynamic_cast(lRunGroup->FindObject(nameHistogram.c_str())); + if (calibration.second == nullptr || calibration.second->GetNbinsZ() != nParameters || std::ranges::any_of(std::views::iota(0, nParameters), [zAxis = calibration.second->GetZaxis()](const std::int32_t binIndex) -> bool { return zAxis->GetBinCenter(binIndex + 1) != binIndex; })) { + LOG(fatal) << "Invalid " << nameHistogram << "!"; + } + LOG(info) << "Reading from CCDB: " << nameHistogram; + } + } + } + } + + for (std::int32_t const& iParticleSpecies : std::views::iota(0, NEs)) { + if (!static_cast(cgTrack.cfgFlagsRecalibrationNSigmaPid.value.get(iParticleSpecies))) { + continue; + } + + for (std::int32_t const& iDetector : std::views::iota(0, NEs)) { + for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { + const std::string name{std::format("hCentralityPtEtaShift{}NSigma{}{}{}_runGroup{}", getName(iDetector), getName(iParticleSpecies), getName(iChargeSpecies), doProcessMc.value ? "_mc" : "", runGroupIndex)}; + const TH3*& histogram{holderCcdb.hsCentralityPtEtaShiftNSigmaPid[iDetector][iParticleSpecies][iChargeSpecies]}; + histogram = dynamic_cast(lRunGroup->FindObject(name.c_str())); + if (!histogram) { + LOG(fatal) << "Invalid " << name << "!"; + } + LOG(info) << "Reading from CCDB: " << name; + } + } + } + + for (std::int32_t const& iParticleSpecies : std::views::iota(0, NEs)) { + if (!static_cast(cgAnalysis.cfgFlagsCalculationFluctuation.value.get(toI(ParticleNumber::Charge))) && (iParticleSpecies != toI(ParticleSpecies::Kaon) || !static_cast(cgAnalysis.cfgFlagsCalculationFluctuation.value.get(toI(ParticleNumber::Kaon)))) && (iParticleSpecies != toI(ParticleSpecies::Proton) || !static_cast(cgAnalysis.cfgFlagsCalculationFluctuation.value.get(toI(ParticleNumber::Proton))))) { + continue; + } + for (std::int32_t const& iPidStrategy : std::views::iota(0, NEs)) { for (std::int32_t const& iChargeSpecies : std::views::iota(0, NEs)) { - const std::string name{std::format("hVzCentralityPtEtaEfficiency{}{}{}_runGroup{}", getName(iPidStrategy), getName(iParticleSpecies), getName(iChargeSpecies), iRunGroup + 1)}; - holderCcdb.hVzCentralityPtEtaEfficiency[iRunGroup][iPidStrategy][iParticleSpecies][iChargeSpecies] = dynamic_cast(lRunGroup->FindObject(name.c_str())); - if (!holderCcdb.hVzCentralityPtEtaEfficiency[iRunGroup][iPidStrategy][iParticleSpecies][iChargeSpecies] || holderCcdb.hVzCentralityPtEtaEfficiency[iRunGroup][iPidStrategy][iParticleSpecies][iChargeSpecies]->GetNdimensions() != HolderCcdb::NDimensionsEfficiency) { + const std::string name{std::format("hsVzCentralityPtEtaEfficiency{}{}{}_runGroup{}", getName(iPidStrategy), getName(iParticleSpecies), getName(iChargeSpecies), runGroupIndex)}; + const THnBase*& histogram{holderCcdb.hsVzCentralityPtEtaEfficiency[iPidStrategy][iParticleSpecies][iChargeSpecies]}; + histogram = dynamic_cast(lRunGroup->FindObject(name.c_str())); + if (!histogram || histogram->GetNdimensions() != HolderCcdb::NDimensionsEfficiency) { LOG(fatal) << "Invalid " << name << "!"; } LOG(info) << "Reading from CCDB: " << name; @@ -1251,40 +1616,25 @@ struct PartNumFluc { } template - requires IsValid + requires IsValidEnumValue double getEfficiency(const bool doUseMcParticleMomentum) const { - const THnBase* const hVzCentralityPtEtaEfficiency{holderCcdb.hVzCentralityPtEtaEfficiency[std::abs(holderEvent.runGroupIndex) - 1][toI(PidStrategyValue)][toI(ParticleSpeciesValue)][toI(ChargeSpeciesValue)]}; - return hVzCentralityPtEtaEfficiency ? hVzCentralityPtEtaEfficiency->GetBinContent(hVzCentralityPtEtaEfficiency->GetBin(std::array{doProcessMc.value && groupEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz, holderEvent.centrality, doUseMcParticleMomentum ? holderMcParticle.pt : holderTrack.pt, doUseMcParticleMomentum ? holderMcParticle.eta : holderTrack.eta}.data())) : 0.; + const THnBase* const hsVzCentralityPtEtaEfficiency{holderCcdb.hsVzCentralityPtEtaEfficiency[toI(PidStrategyValue)][toI(ParticleSpeciesValue)][toI(ChargeSpeciesValue)]}; + return hsVzCentralityPtEtaEfficiency ? hsVzCentralityPtEtaEfficiency->GetBinContent(hsVzCentralityPtEtaEfficiency->GetBin(std::array{doProcessMc.value && cgEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz, holderEvent.centrality, doUseMcParticleMomentum ? holderMcParticle.pt : holderTrack.pt, doUseMcParticleMomentum ? holderMcParticle.eta : holderTrack.eta}.data())) : 0.; } - template - requires IsValid + template + requires IsValidEnumValue double getShiftNSigmaPid() const { - if constexpr (DoRecalibration) { - if (groupTrack.cfgFlagsRecalibrationNSigmaPid.value.get(toI(ParticleSpeciesValue))) { - return interpolate(holderCcdb.hCentralityPtEtaShiftNSigmaPid[std::abs(holderEvent.runGroupIndex) - 1][toI(DetectorValue)][toI(ParticleSpeciesValue)][holderTrack.sign > 0 ? toI(ChargeSpecies::Plus) : toI(ChargeSpecies::Minus)], holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta); + if constexpr (DoRecalibrate) { + if (cgTrack.cfgFlagsRecalibrationNSigmaPid.value.get(toI(ParticleSpeciesValue))) { + return interpolate(holderCcdb.hsCentralityPtEtaShiftNSigmaPid[toI(DetectorValue)][toI(ParticleSpeciesValue)][holderTrack.sign > 0 ? toI(ChargeSpecies::Plus) : toI(ChargeSpecies::Minus)], holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta); } } return 0.; } - template - void setNSigmaPid(const T& track) - { - if (holderTrack.hasPid[toI(Detector::Tpc)]) { - holderTrack.nSigmaPid[toI(Detector::Tpc)][toI(ParticleSpecies::Pion)] = HolderTrack::truncateNSigmaPid(track.tpcNSigmaPi(), getShiftNSigmaPid()); - holderTrack.nSigmaPid[toI(Detector::Tpc)][toI(ParticleSpecies::Kaon)] = HolderTrack::truncateNSigmaPid(track.tpcNSigmaKa(), getShiftNSigmaPid()); - holderTrack.nSigmaPid[toI(Detector::Tpc)][toI(ParticleSpecies::Proton)] = HolderTrack::truncateNSigmaPid(track.tpcNSigmaPr(), getShiftNSigmaPid()); - } - if (holderTrack.hasPid[toI(Detector::Tof)]) { - holderTrack.nSigmaPid[toI(Detector::Tof)][toI(ParticleSpecies::Pion)] = HolderTrack::truncateNSigmaPid(track.tofNSigmaPi(), getShiftNSigmaPid()); - holderTrack.nSigmaPid[toI(Detector::Tof)][toI(ParticleSpecies::Kaon)] = HolderTrack::truncateNSigmaPid(track.tofNSigmaKa(), getShiftNSigmaPid()); - holderTrack.nSigmaPid[toI(Detector::Tof)][toI(ParticleSpecies::Proton)] = HolderTrack::truncateNSigmaPid(track.tofNSigmaPr(), getShiftNSigmaPid()); - } - } - double getMeasureDca(const std::pair& calibration) const { static thread_local std::vector parametersPtMeasureDcaScratch{}; @@ -1292,7 +1642,7 @@ struct PartNumFluc { const TFormula* const fPtMeasureDca{calibration.first}; const TH3* const hCentralityEtaParameterPtMeasureDca{calibration.second}; const std::int32_t nParameters{fPtMeasureDca->GetNpar()}; - if (static_cast(parametersPtMeasureDcaScratch.size()) < nParameters) { + if (std::cmp_less(parametersPtMeasureDcaScratch.size(), nParameters)) { parametersPtMeasureDcaScratch.resize(nParameters); } const std::int32_t centralityBinIndex{std::clamp(hCentralityEtaParameterPtMeasureDca->GetXaxis()->FindFixBin(holderEvent.centralityCalibration), 1, hCentralityEtaParameterPtMeasureDca->GetNbinsX())}; @@ -1303,8 +1653,21 @@ struct PartNumFluc { return fPtMeasureDca->EvalPar(&holderTrack.pt, parametersPtMeasureDcaScratch.data()); } - template - requires IsValid + template + requires IsValidEnumValue + double getAbsNSigmaDca() const + { + if (!cgTrack.cfgFlagRecalibrationDca.value) { + return std::abs(holderTrack.dca[toI(DcaAxisValue)]); + } + + const std::int32_t chargeSpeciesIndex{holderTrack.sign > 0 ? toI(ChargeSpecies::Plus) : toI(ChargeSpecies::Minus)}; + const double sigma{getMeasureDca(holderCcdb.calibrationsPtMeasureDca[toI(DcaMeasure::Sigma)][toI(DcaAxisValue)][chargeSpeciesIndex])}; + return sigma > 0. ? std::abs((holderTrack.dca[toI(DcaAxisValue)] - getMeasureDca(holderCcdb.calibrationsPtMeasureDca[toI(DcaMeasure::Mean)][toI(DcaAxisValue)][chargeSpeciesIndex])) / sigma) : std::numeric_limits::infinity(); + } + + template + requires IsValidEnumValue bool isPid(const bool doRejectOthers) const { if constexpr (ParticleSpeciesAllValue == ParticleSpeciesAll::All) { @@ -1324,10 +1687,10 @@ struct PartNumFluc { } else { constexpr std::int32_t ParticleSpeciesIndex{toI(getValue(ParticleSpeciesAllValue))}; if constexpr (PidStrategyAllValue == PidStrategyAll::TpcTofSeparated) { - if (!(std::abs(holderTrack.nSigmaPid[toI(Detector::Tpc)][ParticleSpeciesIndex]) < groupTrack.cfgCutsMaxAbsNSigmaPid.value.get(ParticleSpeciesIndex))) { + if (!(std::abs(holderTrack.nSigmaPid[toI(Detector::Tpc)][ParticleSpeciesIndex]) < cgTrack.cfgCutsMaxAbsNSigmaPid.value.get(ParticleSpeciesIndex, toI(SelectionValue)))) { return false; } - if (!(std::abs(holderTrack.nSigmaPid[toI(Detector::Tof)][ParticleSpeciesIndex]) < groupTrack.cfgCutsMaxAbsNSigmaPid.value.get(ParticleSpeciesIndex))) { + if (!(std::abs(holderTrack.nSigmaPid[toI(Detector::Tof)][ParticleSpeciesIndex]) < cgTrack.cfgCutsMaxAbsNSigmaPid.value.get(ParticleSpeciesIndex, toI(SelectionValue)))) { return false; } if (doRejectOthers && !(std::abs(holderTrack.nSigmaPid[toI(Detector::Tof)][ParticleSpeciesIndex]) < std::min(std::abs(holderTrack.nSigmaPid[toI(Detector::Tof)][(ParticleSpeciesIndex + 1) % NEs]), std::abs(holderTrack.nSigmaPid[toI(Detector::Tof)][(ParticleSpeciesIndex + 2) % NEs])))) { @@ -1335,7 +1698,7 @@ struct PartNumFluc { } } else if constexpr (PidStrategyAllValue == PidStrategyAll::TpcTofCombined) { const double absNSigmaPidCombined{std::abs(holderTrack.getNSigmaPidCombined(ParticleSpeciesIndex))}; - if (!(absNSigmaPidCombined < groupTrack.cfgCutsMaxAbsNSigmaPid.value.get(ParticleSpeciesIndex))) { + if (!(absNSigmaPidCombined < cgTrack.cfgCutsMaxAbsNSigmaPid.value.get(ParticleSpeciesIndex, toI(SelectionValue)))) { return false; } if (doRejectOthers && !(absNSigmaPidCombined < std::min(std::abs(holderTrack.getNSigmaPidCombined((ParticleSpeciesIndex + 1) % NEs)), std::abs(holderTrack.getNSigmaPidCombined((ParticleSpeciesIndex + 2) % NEs))))) { @@ -1343,7 +1706,7 @@ struct PartNumFluc { } } else { constexpr std::int32_t DetectorIndex{toI(getValue(PidStrategyAllValue))}; - if (!(std::abs(holderTrack.nSigmaPid[DetectorIndex][ParticleSpeciesIndex]) < groupTrack.cfgCutsMaxAbsNSigmaPid.value.get(ParticleSpeciesIndex))) { + if (!(std::abs(holderTrack.nSigmaPid[DetectorIndex][ParticleSpeciesIndex]) < cgTrack.cfgCutsMaxAbsNSigmaPid.value.get(ParticleSpeciesIndex, toI(SelectionValue)))) { return false; } if (doRejectOthers && !(std::abs(holderTrack.nSigmaPid[DetectorIndex][ParticleSpeciesIndex]) < std::min(std::abs(holderTrack.nSigmaPid[DetectorIndex][(ParticleSpeciesIndex + 1) % NEs]), std::abs(holderTrack.nSigmaPid[DetectorIndex][(ParticleSpeciesIndex + 2) % NEs])))) { @@ -1355,7 +1718,7 @@ struct PartNumFluc { } template - requires IsValid + requires IsValidEnumValue bool isPid() const { if constexpr (ParticleSpeciesAllValue == ParticleSpeciesAll::All) { @@ -1365,92 +1728,69 @@ struct PartNumFluc { } } + template + requires IsValidEnumValue bool isGoodMomentum(const bool doUseMcParticleMomentum) const { const double pt{doUseMcParticleMomentum ? holderMcParticle.pt : holderTrack.pt}; - const double eta{doUseMcParticleMomentum ? holderMcParticle.eta : holderTrack.eta}; - if (!(groupTrack.cfgCutMinPt.value < pt) || !(pt < groupTrack.cfgCutMaxPt.value)) { - return false; - } - if (!(std::abs(eta) < groupTrack.cfgCutMaxAbsEta.value)) { - return false; + if constexpr (ParticleSpeciesAllValue == ParticleSpeciesAll::All) { + if (!(rangePtAll[toI(RangeEdge::Min)] < pt) || !(pt < rangePtAll[toI(RangeEdge::Max)])) { + return false; + } + } else { + const std::int32_t particleSpeciesIndex{toI(getValue(ParticleSpeciesAllValue))}; + if (!(cgTrack.cfgCutsRangePt.value.get(particleSpeciesIndex, toI(RangeEdge::Min)) < pt) || !(pt < cgTrack.cfgCutsRangePt.value.get(particleSpeciesIndex, toI(RangeEdge::Max)))) { + return false; + } } - return true; + return std::abs(doUseMcParticleMomentum ? holderMcParticle.eta : holderTrack.eta) < cgTrack.cfgCutMaxAbsEta.value; } bool isGoodDca() const { - if (!groupTrack.cfgFlagRecalibrationDca.value) { - for (std::int32_t const& iDcaAxis : std::views::iota(0, NEs)) { - if (!(std::abs(holderTrack.dca[iDcaAxis]) < groupTrack.cfgCutsMaxAbsNSigmaDca.value.get(iDcaAxis))) { - return false; - } - } - } else { - const std::int32_t chargeSpeciesIndex{holderTrack.sign > 0 ? toI(ChargeSpecies::Plus) : toI(ChargeSpecies::Minus)}; - const std::array, NEs>, NEs>, NEs>& fPtMeasureDcaGroup{holderCcdb.fPtMeasureDca[std::abs(holderEvent.runGroupIndex) - 1]}; - for (std::int32_t const& iDcaAxis : std::views::iota(0, NEs)) { - const double mean{getMeasureDca(fPtMeasureDcaGroup[toI(DcaMeasure::Mean)][iDcaAxis][chargeSpeciesIndex])}; - const double sigma{getMeasureDca(fPtMeasureDcaGroup[toI(DcaMeasure::Sigma)][iDcaAxis][chargeSpeciesIndex])}; - if (!(std::abs(holderTrack.dca[iDcaAxis] - mean) < groupTrack.cfgCutsMaxAbsNSigmaDca.value.get(iDcaAxis) * sigma)) { - return false; - } - } - } - return true; + return getAbsNSigmaDca() < cgTrack.cfgCutsMaxAbsNSigmaDca.value.get(toI(DcaAxis::Xy), toI(Selection::Default)) && getAbsNSigmaDca() < cgTrack.cfgCutsMaxAbsNSigmaDca.value.get(toI(DcaAxis::Z), toI(Selection::Default)); } template bool isGoodTrack(const T& track) const { - if (groupTrack.cfgFlagPvContributor.value && !track.isPVContributor()) { + if (cgTrack.cfgFlagPvContributor.value && !track.isPVContributor()) { return false; } - if (!(track.itsNCls() > groupTrack.cfgCutMinItsNCls.value)) { + if (!(track.itsNCls() > cgTrack.cfgCutsMinItsNCls.value.get(toI(Selection::Default)))) { return false; } - if (!(track.itsChi2NCl() < groupTrack.cfgCutMaxItsChi2NCls.value)) { + if (!(track.itsChi2NCl() < cgTrack.cfgCutsMaxItsChi2NCls.value.get(toI(Selection::Default)))) { return false; } - if (!(track.tpcNClsFound() > groupTrack.cfgCutMinTpcNCls.value)) { + if (!(track.tpcNClsFound() > cgTrack.cfgCutsMinTpcNCls.value.get(toI(Selection::Default)))) { return false; } - if (!(groupTrack.cfgCutMinTpcChi2NCls.value < track.tpcChi2NCl()) || !(track.tpcChi2NCl() < groupTrack.cfgCutMaxTpcChi2NCls.value)) { + if (!(cgTrack.cfgCutMinTpcChi2NCls.value < track.tpcChi2NCl()) || !(track.tpcChi2NCl() < cgTrack.cfgCutsMaxTpcChi2NCls.value.get(toI(Selection::Default)))) { return false; } - if (!(track.tpcFractionSharedCls() < groupTrack.cfgCutMaxTpcNClsSharedRatio.value)) { + if (!(track.tpcFractionSharedCls() < cgTrack.cfgCutsMaxTpcNClsSharedRatio.value.get(toI(Selection::Default)))) { return false; } - if (!(track.tpcNClsCrossedRows() > groupTrack.cfgCutMinTpcNCrossedRows.value)) { + if (!(track.tpcNClsCrossedRows() > cgTrack.cfgCutsMinTpcNCrossedRows.value.get(toI(Selection::Default)))) { return false; } - if (!(track.tpcCrossedRowsOverFindableCls() > groupTrack.cfgCutMinTpcNCrossedRowsRatio.value)) { + if (!(track.tpcCrossedRowsOverFindableCls() > cgTrack.cfgCutMinTpcNCrossedRowsRatio.value)) { return false; } return true; } - template - bool isGoodMcParticle(const MP& mcParticle) const - { - if constexpr (IsMc) { - if (!mcParticle.isPhysicalPrimary()) { - return false; - } - } - return true; - } - template - requires IsValid + requires IsValidEnumValue void fillQaRunByTrackByChargeSpecies(const T& track) { const auto fill{[this](const auto& name, const auto value) -> void { - hrQaRun.fill(C_CS("QaRun/pRunIndex") + name + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderEvent.runIndex, value); + hrQaRun.fill(C_CS("pRunIndex") + name + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderEvent.runIndex, value); }}; const auto fillNSigmaPidByDetectorParticleSpecies{ [this, &fill] - requires IsValid + requires IsValidEnumValue () -> void { const double nSigmaPid{holderTrack.nSigmaPid[toI(DetectorValue)][toI(ParticleSpeciesValue)]}; if (std::abs(nSigmaPid) < HolderTrack::TruncationAbsNSigmaPid) { @@ -1483,11 +1823,11 @@ struct PartNumFluc { } template - requires IsValid + requires IsValidEnumValue void fillQaRunByEventByChargeSpecies() { const auto fill{[this](const auto& name, const auto value) -> void { - hrQaRun.fill(C_CS("QaRun/pRunIndex") + name + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderEvent.runIndex, value); + hrQaRun.fill(C_CS("pRunIndex") + name + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderEvent.runIndex, value); }}; fill(C_CS("NGlobalTracks"), holderEvent.nGlobalTracks[toI(ChargeSpeciesValue)]); @@ -1502,30 +1842,29 @@ struct PartNumFluc { } template - requires IsValid + requires IsValidEnumValue void fillQaTrackByChargeSpecies(const T& track) { const auto fill{[this](const auto& name, const auto... positionAndWeight) -> void { - hrQaTrack.fill(C_CS("QaTrack/h") + name + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), positionAndWeight...); + hrQaTrack.fill(C_CS("h") + name + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), positionAndWeight...); }}; - fill(C_CS("ItsNCls"), track.itsNCls()); - fill(C_CS("ItsChi2NCls"), track.itsChi2NCl()); + fill(C_CS("ItsNClsChi2NCls"), track.itsNCls(), track.itsChi2NCl()); + fill(C_CS("TpcNClsChi2NCls"), track.tpcNClsFound(), track.tpcChi2NCl()); fill(C_CS("TpcNClsNClsShared"), track.tpcNClsFound(), track.tpcNClsShared()); - fill(C_CS("TpcChi2NCls"), track.tpcChi2NCl()); fill(C_CS("TpcNClsFindableNCrossedRows"), track.tpcNClsFindable(), track.tpcNClsCrossedRows()); } template - requires IsValid + requires IsValidEnumValue void fillQaDcaByChargeSpecies() { const auto fillByDcaAxis{ [this] - requires IsValid + requires IsValidEnumValue () -> void { - hrQaDca.fill(C_CS("QaDca/hPtDca") + C_SV(getName(DcaAxisValue)) + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderTrack.pt, holderTrack.dca[toI(DcaAxisValue)]); - hrQaDca.fill(C_CS("QaDca/pCentralityPtEtaDca") + C_SV(getName(DcaAxisValue)) + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.dca[toI(DcaAxisValue)]); + hrQaDca.fill(C_CS("hPtDca") + C_SV(getName(DcaAxisValue)) + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderTrack.pt, holderTrack.dca[toI(DcaAxisValue)]); + hrQaDca.fill(C_CS("pCentralityPtEtaDca") + C_SV(getName(DcaAxisValue)) + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.dca[toI(DcaAxisValue)]); }}; fillByDcaAxis.template operator()(); @@ -1533,23 +1872,23 @@ struct PartNumFluc { } template - requires IsValid - void fillQaAcceptancebyParticleSpeciesAll(const T& track) + requires IsValidEnumValue + void fillQaAcceptanceByParticleSpeciesAll(const T& track) { - if (!groupAnalysis.cfgFlagsQaAcceptance.value.get(toI(ParticleSpeciesAllValue))) { + if (!cgAnalysis.cfgFlagsQaAcceptance.value.get(toI(ParticleSpeciesAllValue))) { return; } const auto fillByChargeSpecies{ [this] - requires IsValid + requires IsValidEnumValue (const auto& name, const double value) -> void { const auto fillByPidStrategy{ [this, &name, value] - requires IsValid + requires IsValidEnumValue () -> void { if (isPid(PidStrategyValue), ParticleSpeciesAllValue>(false)) { - hrQaAcceptance.fill(C_CS("QaAcceptance/h") + name + C_CS("Pt_") + C_SV(getName(PidStrategyValue)) + C_CS("Edge") + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), value, holderTrack.pt); // NOLINT(clang-analyzer-core.NonNullParamChecker) + hrQaAcceptance.fill(C_CS("h") + name + C_CS("Pt_") + C_SV(getName(PidStrategyValue)) + C_CS("Edge") + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), value, holderTrack.pt); // NOLINT(clang-analyzer-core.NonNullParamChecker) } }}; @@ -1573,28 +1912,28 @@ struct PartNumFluc { } template - requires IsValid && (DataModeValue != DataMode::McMcParticle) + requires IsValidEnumValue && (DataModeValue != DataMode::McMcParticle) void fillQaPhiByParticleSpeciesAll() { - if (!groupAnalysis.cfgFlagsQaPhi.value.get(toI(ParticleSpeciesAllValue))) { + if (!cgAnalysis.cfgFlagsQaPhi.value.get(toI(ParticleSpeciesAllValue))) { return; } const auto fillByChargeSpecies{ [this] - requires IsValid + requires IsValidEnumValue () -> void { const auto fillByPidStrategy{ [this] - requires IsValid + requires IsValidEnumValue () -> void { if constexpr (DataModeValue == DataMode::McTrack) { if (isPid() && isPid(PidStrategyValue), ParticleSpeciesAllValue>(false)) { - hrQaPhi.fill(C_CS("QaPhi/hCentralityPtEtaPhi_mc") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.phi); + hrQaPhi.fill(C_CS("hCentralityPtEtaPhi_mc") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.phi); } } else { // DataModeValue == DataMode::RawTrack if (isPid(PidStrategyValue), ParticleSpeciesAllValue>(false)) { - hrQaPhi.fill(C_CS("QaPhi/hCentralityPtEtaPhi_") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.phi); + hrQaPhi.fill(C_CS("hCentralityPtEtaPhi_") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.phi); } } }}; @@ -1611,40 +1950,40 @@ struct PartNumFluc { } template - requires IsValid && (DataModeValue != DataMode::McMcParticle) + requires IsValidEnumValue && (DataModeValue != DataMode::McMcParticle) void fillQaPidByParticleSpeciesAll(const T& track) { - if (!groupAnalysis.cfgFlagsQaPid.value.get(toI(ParticleSpeciesAllValue))) { + if (!cgAnalysis.cfgFlagsQaPid.value.get(toI(ParticleSpeciesAllValue))) { return; } if constexpr (ParticleSpeciesAllValue == ParticleSpeciesAll::All) { if (isPid(PidStrategy::Tpc), ParticleSpeciesAll::All>(false)) { - hrQaPid.fill(C_CS("QaPid/hCentralityPOverQEtaTpcLnDeDx"), holderEvent.centralityCalibration, track.p() / holderTrack.sign, holderTrack.eta, std::log(track.tpcSignal())); + hrQaPid.fill(C_CS("hCentralityPOverQEtaTpcLnDeDx"), holderEvent.centralityCalibration, track.p() / holderTrack.sign, holderTrack.eta, std::log(track.tpcSignal())); } if (isPid(PidStrategy::TpcTof), ParticleSpeciesAll::All>(false)) { - hrQaPid.fill(C_CS("QaPid/hCentralityPOverQEtaTofInverseBeta"), holderEvent.centralityCalibration, track.p() / holderTrack.sign, holderTrack.eta, 1. / track.beta()); + hrQaPid.fill(C_CS("hCentralityPOverQEtaTofInverseBeta"), holderEvent.centralityCalibration, track.p() / holderTrack.sign, holderTrack.eta, 1. / track.beta()); } } else { constexpr std::int32_t ParticleSpeciesIndex{toI(getValue(ParticleSpeciesAllValue))}; const auto fillByChargeSpecies{ [this] - requires IsValid + requires IsValidEnumValue () -> void { if constexpr (DataModeValue == DataMode::McTrack) { if (isPid()) { - hrQaPid.fill(C_CS("QaPid/hCentralityPtEta") + C_SV(getName(Detector::Tpc)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_mc") + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(Detector::Tpc)][ParticleSpeciesIndex]); - hrQaPid.fill(C_CS("QaPid/hCentralityPtEta") + C_SV(getName(Detector::Tof)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_mc") + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(Detector::Tof)][ParticleSpeciesIndex]); + hrQaPid.fill(C_CS("hCentralityPtEta") + C_SV(getName(Detector::Tpc)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_mc") + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(Detector::Tpc)][ParticleSpeciesIndex]); + hrQaPid.fill(C_CS("hCentralityPtEta") + C_SV(getName(Detector::Tof)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_mc") + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(Detector::Tof)][ParticleSpeciesIndex]); } } else { // DataModeValue == DataMode::RawTrack - hrQaPid.fill(C_CS("QaPid/hCentralityPtEta") + C_SV(getName(Detector::Tpc)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(Detector::Tpc)][ParticleSpeciesIndex]); + hrQaPid.fill(C_CS("hCentralityPtEta") + C_SV(getName(Detector::Tpc)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(Detector::Tpc)][ParticleSpeciesIndex]); if (isPid(false)) { - hrQaPid.fill(C_CS("QaPid/hCentralityPtEta") + C_SV(getName(Detector::Tpc)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_") + C_SV(getName(Detector::Tof)) + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(Detector::Tpc)][ParticleSpeciesIndex]); + hrQaPid.fill(C_CS("hCentralityPtEta") + C_SV(getName(Detector::Tpc)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_") + C_SV(getName(Detector::Tof)) + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(Detector::Tpc)][ParticleSpeciesIndex]); } if (isPid(false)) { - hrQaPid.fill(C_CS("QaPid/hCentralityPtEta") + C_SV(getName(Detector::Tof)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_") + C_SV(getName(Detector::Tpc)) + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(Detector::Tof)][ParticleSpeciesIndex]); + hrQaPid.fill(C_CS("hCentralityPtEta") + C_SV(getName(Detector::Tof)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_") + C_SV(getName(Detector::Tpc)) + C_SV(getName(ParticleSpeciesAllValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.nSigmaPid[toI(Detector::Tof)][ParticleSpeciesIndex]); } - hrQaPid.fill(C_CS("QaPid/hCentralityPtEta") + C_SV(getName(PidStrategy::TpcTof)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.getNSigmaPidCombined(ParticleSpeciesIndex)); + hrQaPid.fill(C_CS("hCentralityPtEta") + C_SV(getName(PidStrategy::TpcTof)) + C_CS("NSigma") + C_SV(getName(ParticleSpeciesAllValue)) + C_CS("_") + C_SV(getName(ChargeSpeciesValue)), holderEvent.centralityCalibration, holderTrack.pt, holderTrack.eta, holderTrack.getNSigmaPidCombined(ParticleSpeciesIndex)); } }}; @@ -1657,10 +1996,10 @@ struct PartNumFluc { } template - requires IsValid + requires IsValidEnumValue void fillCalculationYieldByParticleSpecies() { - if (!groupAnalysis.cfgFlagsCalculationYield.value.get(toI(ParticleSpeciesValue))) { + if (!cgAnalysis.cfgFlagsCalculationYield.value.get(toI(ParticleSpeciesValue))) { return; } @@ -1679,28 +2018,28 @@ struct PartNumFluc { const auto fillByChargeSpecies{ [this] - requires IsValid + requires IsValidEnumValue () -> void { if constexpr (DataModeValue == DataMode::McMcParticle) { if (isPid(ParticleSpeciesValue), ChargeSpeciesValue>()) { - hrCalculationYield.fill(C_CS("CalculationYield/hVzCentralityPtMcEtaMc_mc") + C_SV(getName(ParticleSpeciesValue)) + C_SV(getName(ChargeSpeciesValue)), groupEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz, holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta); + hrCalculationYield.fill(C_CS("hVzCentralityPtMcEtaMc_mc") + C_SV(getName(ParticleSpeciesValue)) + C_SV(getName(ChargeSpeciesValue)), cgEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz, holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta); } } else { const auto fillByPidStrategy{ [this] - requires IsValid + requires IsValidEnumValue () -> void { if constexpr (DataModeValue == DataMode::McTrack) { - if (isPid(ParticleSpeciesValue), ChargeSpeciesValue>() && isPid(PidStrategyValue), getValue(ParticleSpeciesValue)>(groupTrack.cfgFlagRejectionOthers.value)) { - if (groupTrack.cfgFlagMcParticleMomentum.value) { - hrCalculationYield.fill(C_CS("CalculationYield/hVzCentralityPtMcEtaMc_mc") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesValue)) + C_SV(getName(ChargeSpeciesValue)), groupEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz, holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta); + if (isPid(ParticleSpeciesValue), ChargeSpeciesValue>() && isPid(PidStrategyValue), getValue(ParticleSpeciesValue)>(cgTrack.cfgFlagRejectionOthers.value)) { + if (cgTrack.cfgFlagMcParticleMomentum.value) { + hrCalculationYield.fill(C_CS("hVzCentralityPtMcEtaMc_mc") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesValue)) + C_SV(getName(ChargeSpeciesValue)), cgEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz, holderEvent.centrality, holderMcParticle.pt, holderMcParticle.eta); } else { - hrCalculationYield.fill(C_CS("CalculationYield/hVzCentralityPtEta_mc") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesValue)) + C_SV(getName(ChargeSpeciesValue)), groupEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz, holderEvent.centrality, holderTrack.pt, holderTrack.eta); + hrCalculationYield.fill(C_CS("hVzCentralityPtEta_mc") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesValue)) + C_SV(getName(ChargeSpeciesValue)), cgEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz, holderEvent.centrality, holderTrack.pt, holderTrack.eta); } } } else { // DataModeValue == DataMode::RawTrack - if (isPid(PidStrategyValue), getValue(ParticleSpeciesValue)>(groupTrack.cfgFlagRejectionOthers.value)) { - hrCalculationYield.fill(C_CS("CalculationYield/hVzCentralityPtEta_") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.vz, holderEvent.centrality, holderTrack.pt, holderTrack.eta); + if (isPid(PidStrategyValue), getValue(ParticleSpeciesValue)>(cgTrack.cfgFlagRejectionOthers.value)) { + hrCalculationYield.fill(C_CS("hVzCentralityPtEta_") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.vz, holderEvent.centrality, holderTrack.pt, holderTrack.eta); } } }}; @@ -1718,23 +2057,23 @@ struct PartNumFluc { } template - requires IsValid + requires IsValidEnumValue void fillCalculationPurityByParticleSpecies() { - if (!groupAnalysis.cfgFlagsCalculationPurity.value.get(toI(ParticleSpeciesValue))) { + if (!cgAnalysis.cfgFlagsCalculationPurity.value.get(toI(ParticleSpeciesValue))) { return; } const auto fillByChargeSpecies{ [this] - requires IsValid + requires IsValidEnumValue () -> void { const auto fillByPidStrategy{ [this] - requires IsValid + requires IsValidEnumValue () -> void { - if (isPid(PidStrategyValue), getValue(ParticleSpeciesValue)>(groupTrack.cfgFlagRejectionOthers.value)) { - hrCalculationPurity.fill(C_CS("CalculationPurity/pCentralityPtEtaPurity") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centrality, holderTrack.pt, holderTrack.eta, isPid(ParticleSpeciesValue), ChargeSpeciesValue>() ? 1. : 0.); + if (isPid(PidStrategyValue), getValue(ParticleSpeciesValue)>(cgTrack.cfgFlagRejectionOthers.value)) { + hrCalculationPurity.fill(C_CS("pCentralityPtEtaPurity") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centrality, holderTrack.pt, holderTrack.eta, isPid(ParticleSpeciesValue), ChargeSpeciesValue>() ? 1. : 0.); } }}; @@ -1750,23 +2089,23 @@ struct PartNumFluc { } template - requires IsValid + requires IsValidEnumValue void fillCalculationFractionPrimaryByParticleSpecies(const MP& mcParticle) { - if (!groupAnalysis.cfgFlagsCalculationFractionPrimary.value.get(toI(ParticleSpeciesValue))) { + if (!cgAnalysis.cfgFlagsCalculationFractionPrimary.value.get(toI(ParticleSpeciesValue))) { return; } const auto fillByChargeSpecies{ [this, &mcParticle] - requires IsValid + requires IsValidEnumValue () -> void { const auto fillByPidStrategy{ [this, &mcParticle] - requires IsValid + requires IsValidEnumValue () -> void { - if (isPid(ParticleSpeciesValue), ChargeSpeciesValue>() && isPid(PidStrategyValue), getValue(ParticleSpeciesValue)>(groupTrack.cfgFlagRejectionOthers.value)) { - hrCalculationFractionPrimary.fill(C_CS("CalculationFractionPrimary/pCentralityPtEtaFractionPrimary") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centrality, holderTrack.pt, holderTrack.eta, mcParticle.isPhysicalPrimary() ? 1. : 0.); + if (isPid(ParticleSpeciesValue), ChargeSpeciesValue>() && isPid(PidStrategyValue), getValue(ParticleSpeciesValue)>(cgTrack.cfgFlagRejectionOthers.value)) { + hrCalculationFractionPrimary.fill(C_CS("pCentralityPtEtaFractionPrimary") + C_SV(getName(PidStrategyValue)) + C_SV(getName(ParticleSpeciesValue)) + C_SV(getName(ChargeSpeciesValue)), holderEvent.centrality, holderTrack.pt, holderTrack.eta, mcParticle.isPhysicalPrimary() ? 1. : 0.); } }}; @@ -1784,19 +2123,22 @@ struct PartNumFluc { void initCalculationFluctuation() { for (std::int32_t const& iParticleNumber : std::views::iota(0, NEs)) { - if (static_cast(groupAnalysis.cfgFlagsCalculationFluctuation.value.get(iParticleNumber))) { + if (static_cast(cgAnalysis.cfgFlagsCalculationFluctuation.value.get(iParticleNumber))) { for (std::int32_t const& iChargeNumber : std::views::iota(0, NEs)) { - fluctuationCalculatorTrack[iParticleNumber][iChargeNumber]->clear(); + if (doProcessMc.value) { + fluctuationCalculatorsTrackMcParticle[iParticleNumber][iChargeNumber]->clear(); + } + fluctuationCalculatorsTrackTrack[iParticleNumber][iChargeNumber]->clear(); } } } } template - requires IsValid + requires IsValidEnumValue void calculateFluctuationByParticleNumber() { - if (!groupAnalysis.cfgFlagsCalculationFluctuation.value.get(toI(ParticleNumberValue))) { + if (!cgAnalysis.cfgFlagsCalculationFluctuation.value.get(toI(ParticleNumberValue))) { return; } @@ -1821,57 +2163,55 @@ struct PartNumFluc { } else { return false; } - }(groupTrack.cfgFlagMcParticleMomentum.value)}; - if (!isGoodMomentum(doUseMcParticleMomentum)) { - return; - } - - if constexpr (DataModeValue == DataMode::McMcParticle) { - ++holderDerivedData.nMcParticles[toI(chargeSign > 0 ? ChargeSpecies::Plus : ChargeSpecies::Minus)]; - } else { - ++holderDerivedData.nTracks[toI(chargeSign > 0 ? ChargeSpecies::Plus : ChargeSpecies::Minus)]; + }(cgTrack.cfgFlagMcParticleMomentum.value)}; + const ChargeSpecies chargeSpecies{chargeSign > 0 ? ChargeSpecies::Plus : ChargeSpecies::Minus}; + if (isGoodMomentum(ParticleNumberValue)>(doUseMcParticleMomentum)) { + if constexpr (DataModeValue == DataMode::McMcParticle) { + ++holderDerivedData.nMcParticles[toI(chargeSpecies)]; + } else { + ++holderDerivedData.nTracks[toI(chargeSpecies)]; + } } const auto calculateByParticleSpecies{ [this, chargeSign, doUseMcParticleMomentum] - requires IsValid && (ParticleNumberValue == ParticleNumber::Charge || (ParticleNumberValue == ParticleNumber::Kaon && ParticleSpeciesValue == ParticleSpecies::Kaon) || (ParticleNumberValue == ParticleNumber::Proton && ParticleSpeciesValue == ParticleSpecies::Proton)) - () -> void { - const auto calculateByChargeSpecies{ - [this, chargeSign, doUseMcParticleMomentum] - requires IsValid - () -> void { - if constexpr (DataModeValue != DataMode::RawTrack) { - if (!isPid(ParticleSpeciesValue), ChargeSpeciesValue>()) { - return; - } - } + requires IsValidEnumValue && (getValue(ParticleNumberValue) == ParticleSpeciesAll::All || getValue(ParticleNumberValue) == getValue(ParticleSpeciesValue)) + () -> bool { + if (!isGoodMomentum(ParticleSpeciesValue)>(doUseMcParticleMomentum) || (DataModeValue != DataMode::RawTrack && (chargeSign > 0 ? !isPid(ParticleSpeciesValue), ChargeSpecies::Plus>() : !isPid(ParticleSpeciesValue), ChargeSpecies::Minus>()))) { + return false; + } - const bool doUseTofPid{[](const bool doUseMcParticleMomentumValue, const double ptMcParticle, const double ptTrack, const double thresholdPtTofPid) constexpr -> bool { - if constexpr (DataModeValue == DataMode::McMcParticle) { - return ptMcParticle >= thresholdPtTofPid; - } else if constexpr (DataModeValue == DataMode::McTrack) { - return (doUseMcParticleMomentumValue ? ptMcParticle : ptTrack) >= thresholdPtTofPid; - } else { - return ptTrack >= thresholdPtTofPid; - } - }(doUseMcParticleMomentum, holderMcParticle.pt, holderTrack.pt, groupTrack.cfgThresholdsPtTofPid.value.get(toI(ParticleSpeciesValue)))}; - if constexpr (DataModeValue != DataMode::McMcParticle) { - if (!(doUseTofPid ? isPid(PidStrategy::TpcTof), getValue(ParticleSpeciesValue)>(groupTrack.cfgFlagRejectionOthers.value) : isPid(PidStrategy::Tpc), getValue(ParticleSpeciesValue)>(groupTrack.cfgFlagRejectionOthers.value))) { - return; - } - } + const bool doUseTofPid{[](const bool doUseMcParticleMomentumValue, const double ptMcParticle, const double ptTrack, const double thresholdPtTofPid) constexpr -> bool { + if constexpr (DataModeValue == DataMode::McMcParticle) { + return ptMcParticle >= thresholdPtTofPid; + } else if constexpr (DataModeValue == DataMode::McTrack) { + return (doUseMcParticleMomentumValue ? ptMcParticle : ptTrack) >= thresholdPtTofPid; + } else { + return ptTrack >= thresholdPtTofPid; + } + }(doUseMcParticleMomentum, holderMcParticle.pt, holderTrack.pt, cgTrack.cfgThresholdsPtTofPid.value.get(toI(ParticleSpeciesValue)))}; + if constexpr (DataModeValue != DataMode::McMcParticle) { + if (!(doUseTofPid ? isPid(PidStrategy::TpcTof), getValue(ParticleSpeciesValue)>(cgTrack.cfgFlagRejectionOthers.value) : isPid(PidStrategy::Tpc), getValue(ParticleSpeciesValue)>(cgTrack.cfgFlagRejectionOthers.value))) { + return false; + } + } - const double efficiency{doUseTofPid ? getEfficiency(doUseMcParticleMomentum) : getEfficiency(doUseMcParticleMomentum)}; // NOLINT(clang-analyzer-core.NullDereference) + const auto calculateByChargeSpecies{ + [this, chargeSign, doUseMcParticleMomentum, doUseTofPid] + requires IsValidEnumValue + () -> void { + const double efficiency{doUseTofPid ? getEfficiency(doUseMcParticleMomentum) : getEfficiency(doUseMcParticleMomentum)}; const auto fill{ [this, efficiency]() -> void { + std::array, NEs>, NEs>& fluctuationCalculatorsTrack{DataModeValue == DataMode::McMcParticle ? fluctuationCalculatorsTrackMcParticle : fluctuationCalculatorsTrackTrack}; if constexpr (ChargeSpeciesValue == ChargeSpecies::Plus) { - fluctuationCalculatorTrack[toI(ParticleNumberValue)][toI(ChargeNumber::Plus)]->fill(1., efficiency); - fluctuationCalculatorTrack[toI(ParticleNumberValue)][toI(ChargeNumber::Net)]->fill(1., efficiency); + fluctuationCalculatorsTrack[toI(ParticleNumberValue)][toI(ChargeNumber::Plus)]->fill(1., efficiency); + fluctuationCalculatorsTrack[toI(ParticleNumberValue)][toI(ChargeNumber::Net)]->fill(1., efficiency); } else { - fluctuationCalculatorTrack[toI(ParticleNumberValue)][toI(ChargeNumber::Minus)]->fill(1., efficiency); - fluctuationCalculatorTrack[toI(ParticleNumberValue)][toI(ChargeNumber::Net)]->fill(-1., efficiency); + fluctuationCalculatorsTrack[toI(ParticleNumberValue)][toI(ChargeNumber::Minus)]->fill(1., efficiency); + fluctuationCalculatorsTrack[toI(ParticleNumberValue)][toI(ChargeNumber::Net)]->fill(-1., efficiency); } - fluctuationCalculatorTrack[toI(ParticleNumberValue)][toI(ChargeNumber::Total)]->fill(1., efficiency); + fluctuationCalculatorsTrack[toI(ParticleNumberValue)][toI(ChargeNumber::Total)]->fill(1., efficiency); }}; if constexpr (DataModeValue == DataMode::McMcParticle) { ++holderMcEvent.numbers[toI(ParticleNumberValue)][toI(ChargeSpeciesValue)]; @@ -1879,59 +2219,60 @@ struct PartNumFluc { ++holderMcEvent.numbersEff[toI(ParticleNumberValue)][toI(ChargeSpeciesValue)]; fill(); } - holderDerivedData.signedEfficienciesMcParticle.push_back(HolderDerivedData::convertRound(std::copysign(std::numeric_limits::max(), chargeSign) * efficiency)); + holderDerivedData.signedEfficienciesMcParticle.push_back(HolderDerivedData::convert(std::copysign(std::numeric_limits::max(), chargeSign) * efficiency)); } else { ++holderEvent.numbers[toI(ParticleNumberValue)][toI(ChargeSpeciesValue)]; fill(); - holderDerivedData.signedEfficienciesTrack.push_back(HolderDerivedData::convertRound(std::copysign(std::numeric_limits::max(), chargeSign) * efficiency)); + holderDerivedData.signedEfficienciesTrack.push_back(HolderDerivedData::convert(std::copysign(std::numeric_limits::max(), chargeSign) * efficiency)); } }}; - if (chargeSign > 0) { // NOLINT(clang-analyzer-core.NullDereference) + if (chargeSign > 0) { calculateByChargeSpecies.template operator()(); } else { calculateByChargeSpecies.template operator()(); } + return true; }}; - if constexpr (ParticleNumberValue == ParticleNumber::Kaon) { - calculateByParticleSpecies.template operator()(); - } else if constexpr (ParticleNumberValue == ParticleNumber::Proton) { - calculateByParticleSpecies.template operator()(); - } else { // ParticleNumberValue == ParticleNumber::Charge - calculateByParticleSpecies.template operator()(); - calculateByParticleSpecies.template operator()(); - calculateByParticleSpecies.template operator()(); + if constexpr (getValue(ParticleNumberValue) == ParticleSpeciesAll::All) { + if (!calculateByParticleSpecies.template operator()() && !calculateByParticleSpecies.template operator()()) { + calculateByParticleSpecies.template operator()(); + } + } else { + calculateByParticleSpecies.template operator()(getValue(ParticleNumberValue))>(); } } - template - requires IsValid + template + requires IsValidEnumValue void fillCalculationFluctuationByParticleNumber() { - if (!groupAnalysis.cfgFlagsCalculationFluctuation.value.get(toI(ParticleNumberValue))) { + if (!cgAnalysis.cfgFlagsCalculationFluctuation.value.get(toI(ParticleNumberValue))) { return; } - if constexpr (DataModeValue == DataMode::McMcParticle) { - hrCalculationFluctuation.fill(C_CS("CalculationFluctuation/hCentralityN") + C_SV(getName(ParticleNumberValue)) + C_SV(getName(ChargeSpecies::Plus)) + C_CS("N") + C_SV(getName(ParticleNumberValue)) + C_SV(getName(ChargeSpecies::Minus)) + C_CS("_mc"), holderEvent.centrality, holderMcEvent.numbers[toI(ParticleNumberValue)][toI(ChargeSpecies::Plus)], holderMcEvent.numbers[toI(ParticleNumberValue)][toI(ChargeSpecies::Minus)]); - hrCalculationFluctuation.fill(C_CS("CalculationFluctuation/hCentralityN") + C_SV(getName(ParticleNumberValue)) + C_SV(getName(ChargeSpecies::Plus)) + C_CS("N") + C_SV(getName(ParticleNumberValue)) + C_SV(getName(ChargeSpecies::Minus)) + C_CS("_mcEff"), holderEvent.centrality, holderMcEvent.numbersEff[toI(ParticleNumberValue)][toI(ChargeSpecies::Plus)], holderMcEvent.numbersEff[toI(ParticleNumberValue)][toI(ChargeSpecies::Minus)]); - } else { - hrCalculationFluctuation.fill(C_CS("CalculationFluctuation/hCentralityN") + C_SV(getName(ParticleNumberValue)) + C_SV(getName(ChargeSpecies::Plus)) + C_CS("N") + C_SV(getName(ParticleNumberValue)) + C_SV(getName(ChargeSpecies::Minus)), holderEvent.centrality, holderEvent.numbers[toI(ParticleNumberValue)][toI(ChargeSpecies::Plus)], holderEvent.numbers[toI(ParticleNumberValue)][toI(ChargeSpecies::Minus)]); + if (doProcessMc.value) { + hrCalculationFluctuation.fill(C_CS("hCentralityN") + C_SV(getName(ParticleNumberValue)) + C_SV(getName(ChargeSpecies::Plus)) + C_CS("N") + C_SV(getName(ParticleNumberValue)) + C_SV(getName(ChargeSpecies::Minus)) + C_CS("_mc"), holderEvent.centrality, holderMcEvent.numbers[toI(ParticleNumberValue)][toI(ChargeSpecies::Plus)], holderMcEvent.numbers[toI(ParticleNumberValue)][toI(ChargeSpecies::Minus)]); + hrCalculationFluctuation.fill(C_CS("hCentralityN") + C_SV(getName(ParticleNumberValue)) + C_SV(getName(ChargeSpecies::Plus)) + C_CS("N") + C_SV(getName(ParticleNumberValue)) + C_SV(getName(ChargeSpecies::Minus)) + C_CS("_mcEff"), holderEvent.centrality, holderMcEvent.numbersEff[toI(ParticleNumberValue)][toI(ChargeSpecies::Plus)], holderMcEvent.numbersEff[toI(ParticleNumberValue)][toI(ChargeSpecies::Minus)]); } + hrCalculationFluctuation.fill(C_CS("hCentralityN") + C_SV(getName(ParticleNumberValue)) + C_SV(getName(ChargeSpecies::Plus)) + C_CS("N") + C_SV(getName(ParticleNumberValue)) + C_SV(getName(ChargeSpecies::Minus)), holderEvent.centrality, holderEvent.numbers[toI(ParticleNumberValue)][toI(ChargeSpecies::Plus)], holderEvent.numbers[toI(ParticleNumberValue)][toI(ChargeSpecies::Minus)]); const auto fillByChargeNumber{ [this] - requires IsValid + requires IsValidEnumValue () -> void { - const std::array products{fluctuationCalculatorTrack[toI(ParticleNumberValue)][toI(ChargeNumberValue)]->getProducts()}; - for (std::int32_t const& iOrderKey : std::views::iota(0, fluctuation_calculator_base::NOrderKeys)) { - if constexpr (DataModeValue == DataMode::McMcParticle) { - hrCalculationFluctuation.fill(C_CS("CalculationFluctuation/hFluctuationCalculator") + C_SV(getName(ParticleNumberValue)) + C_SV(getName(ChargeNumberValue)) + C_CS("_mc"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderKey, products[iOrderKey]); - } else { - hrCalculationFluctuation.fill(C_CS("CalculationFluctuation/hFluctuationCalculator") + C_SV(getName(ParticleNumberValue)) + C_SV(getName(ChargeNumberValue)), holderEvent.centrality, holderEvent.subgroupIndex, iOrderKey, products[iOrderKey]); + if (doProcessMc.value) { + const std::array products{fluctuationCalculatorsTrackMcParticle[toI(ParticleNumberValue)][toI(ChargeNumberValue)]->getProducts()}; + for (std::int32_t const& iOrderKey : std::views::iota(0, fluctuation_calculator_base::NOrderKeys)) { + hrCalculationFluctuation.fill(C_CS("hFluctuationCalculator") + C_SV(getName(ParticleNumberValue)) + C_SV(getName(ChargeNumberValue)) + C_CS("_mc"), holderEvent.centrality, holderEvent.subgroupIndex, iOrderKey, products[iOrderKey]); } } + + const std::array products{fluctuationCalculatorsTrackTrack[toI(ParticleNumberValue)][toI(ChargeNumberValue)]->getProducts()}; + for (std::int32_t const& iOrderKey : std::views::iota(0, fluctuation_calculator_base::NOrderKeys)) { + hrCalculationFluctuation.fill(C_CS("hFluctuationCalculator") + C_SV(getName(ParticleNumberValue)) + C_SV(getName(ChargeNumberValue)), holderEvent.centrality, holderEvent.subgroupIndex, iOrderKey, products[iOrderKey]); + } }}; fillByChargeNumber.template operator()(); @@ -1940,8 +2281,8 @@ struct PartNumFluc { fillByChargeNumber.template operator()(); } - template - bool initTrack(const T& track) + template + bool setTrack(const T& track) { if (std::abs(track.sign()) != 1) { return false; @@ -1956,7 +2297,197 @@ struct PartNumFluc { holderTrack.phi = track.phi(); holderTrack.hasPid[toI(Detector::Tpc)] = (track.hasTPC() && track.tpcSignal() > 0.); holderTrack.hasPid[toI(Detector::Tof)] = (track.hasTOF() && track.beta() > 0.); - setNSigmaPid(track); + if (holderTrack.hasPid[toI(Detector::Tpc)]) { + holderTrack.nSigmaPid[toI(Detector::Tpc)][toI(ParticleSpecies::Pion)] = HolderTrack::truncateNSigmaPid(track.tpcNSigmaPi(), getShiftNSigmaPid()); + holderTrack.nSigmaPid[toI(Detector::Tpc)][toI(ParticleSpecies::Kaon)] = HolderTrack::truncateNSigmaPid(track.tpcNSigmaKa(), getShiftNSigmaPid()); + holderTrack.nSigmaPid[toI(Detector::Tpc)][toI(ParticleSpecies::Proton)] = HolderTrack::truncateNSigmaPid(track.tpcNSigmaPr(), getShiftNSigmaPid()); + } + if (holderTrack.hasPid[toI(Detector::Tof)]) { + holderTrack.nSigmaPid[toI(Detector::Tof)][toI(ParticleSpecies::Pion)] = HolderTrack::truncateNSigmaPid(track.tofNSigmaPi(), getShiftNSigmaPid()); + holderTrack.nSigmaPid[toI(Detector::Tof)][toI(ParticleSpecies::Kaon)] = HolderTrack::truncateNSigmaPid(track.tofNSigmaKa(), getShiftNSigmaPid()); + holderTrack.nSigmaPid[toI(Detector::Tof)][toI(ParticleSpecies::Proton)] = HolderTrack::truncateNSigmaPid(track.tofNSigmaPr(), getShiftNSigmaPid()); + } + + return true; + } + + template + requires IsValidEnumValue + void fillMiniTableMc(const MPs& mcParticles, const Ts& tracks, const bool isGoodNPvContributors) + { + if (!static_cast(cgAnalysis.cfgFlagsStorageMiniTable.value.get(toI(ParticleNumberValue)))) { + return; + } + + const std::optional codeCollision{mini_collision_codec::encode(cgEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz, holderEvent.centrality, isGoodNPvContributors)}; + if (!codeCollision.has_value()) { + return; + } + + miniCollision(*codeCollision); + + for (const auto& mcParticle : mcParticles) { + initMcParticle(mcParticle); + + if (mcParticle.isPhysicalPrimary()) { + const auto fillByParticleSpecies{ + [this] + requires IsValidEnumValue && (getValue(ParticleNumberValue) == ParticleSpeciesAll::All || getValue(ParticleNumberValue) == getValue(ParticleSpeciesValue)) + () -> bool { + if (!isGoodMomentum(ParticleSpeciesValue)>(true) || (holderMcParticle.charge > 0 ? !isPid(ParticleSpeciesValue), ChargeSpecies::Plus>() : !isPid(ParticleSpeciesValue), ChargeSpecies::Minus>())) { + return false; + } + + const std::optional codeMcParticle{mini_mc_particle_codec::encode(holderMcParticle.pt, holderMcParticle.eta, holderMcParticle.charge, ParticleSpeciesValue)}; + if (codeMcParticle.has_value()) { + miniMcParticle(miniCollision.lastIndex(), *codeMcParticle); + } + return true; + }}; + + if constexpr (ParticleNumberValue == ParticleNumber::Charge) { + if (!fillByParticleSpecies.template operator()() && !fillByParticleSpecies.template operator()()) { + fillByParticleSpecies.template operator()(); + } + } else { + fillByParticleSpecies.template operator()(getValue(ParticleNumberValue))>(); + } + } + + if (!cgTrack.cfgFlagMcParticlePhysicalPrimary.value || mcParticle.isPhysicalPrimary()) { + const auto& tracksMatched{tracks.sliceBy(presliceTracksPerMcParticle, mcParticle.globalIndex())}; + for (const auto& track : tracksMatched) { + if (!setTrack(track) || !(cgTrack.cfgCutMinTpcChi2NCls.value < track.tpcChi2NCl()) || !(track.tpcCrossedRowsOverFindableCls() > cgTrack.cfgCutMinTpcNCrossedRowsRatio.value)) { + continue; + } + + const auto fillByParticleSpeciesAll{ + [this, &track] + requires IsValidEnumValue && (ParticleSpeciesAllValue != ParticleSpeciesAll::All) + () -> bool { + const bool doUseMcParticleMomentum{cgTrack.cfgFlagMcParticleMomentum.value}; + if (!isGoodMomentum(doUseMcParticleMomentum) || (holderTrack.sign > 0 ? !isPid() : !isPid())) { + return false; + } + + constexpr std::int32_t ParticleSpeciesIndex{toI(getValue(ParticleSpeciesAllValue))}; + const double pt{doUseMcParticleMomentum ? holderMcParticle.pt : holderTrack.pt}; + const bool doUseTofPid{pt >= cgTrack.cfgThresholdsPtTofPid.value.get(ParticleSpeciesIndex)}; + if (!(doUseTofPid ? isPid(PidStrategy::TpcTof), ParticleSpeciesAllValue, Selection::Loose>(cgTrack.cfgFlagRejectionOthers.value) : isPid(PidStrategy::Tpc), ParticleSpeciesAllValue, Selection::Loose>(cgTrack.cfgFlagRejectionOthers.value))) { + return false; + } + + const std::optional codeTrack{mini_track_codec::encode(*configSelection, track.isPVContributor(), track.itsNCls(), track.itsChi2NCl(), track.tpcNClsFound(), track.tpcChi2NCl(), track.tpcNClsCrossedRows(), track.tpcFractionSharedCls(), {getAbsNSigmaDca(), getAbsNSigmaDca()}, pt, doUseMcParticleMomentum ? holderMcParticle.eta : holderTrack.eta, holderTrack.sign, ParticleSpeciesAllValue, doUseTofPid ? std::abs(holderTrack.getNSigmaPidCombined(ParticleSpeciesIndex)) : std::abs(holderTrack.nSigmaPid[toI(Detector::Tpc)][ParticleSpeciesIndex]))}; + if (codeTrack.has_value()) { + miniTrack(miniCollision.lastIndex(), *codeTrack); + } + return true; + }}; + + if constexpr (ParticleNumberValue == ParticleNumber::Charge) { + if (!fillByParticleSpeciesAll.template operator()() && !fillByParticleSpeciesAll.template operator()()) { + fillByParticleSpeciesAll.template operator()(); + } + } else { + fillByParticleSpeciesAll.template operator()(ParticleNumberValue)>(); + } + } + } + } + } + + template + requires IsValidEnumValue + void fillMiniTableRaw(const T& tracks, const bool isGoodNPvContributors) + { + if (!static_cast(cgAnalysis.cfgFlagsStorageMiniTable.value.get(toI(ParticleNumberValue)))) { + return; + } + + const std::optional codeCollision{mini_collision_codec::encode(holderEvent.vz, holderEvent.centrality, isGoodNPvContributors)}; + if (!codeCollision.has_value()) { + return; + } + + miniCollision(*codeCollision); + + for (const auto& track : tracks) { + if (!setTrack(track) || !(cgTrack.cfgCutMinTpcChi2NCls.value < track.tpcChi2NCl()) || !(track.tpcCrossedRowsOverFindableCls() > cgTrack.cfgCutMinTpcNCrossedRowsRatio.value)) { + continue; + } + + const auto fill{ + [this, &track](const ParticleSpeciesAll particleSpeciesAll, const double absNSigmaPid) -> void { + const std::optional codeTrack{mini_track_codec::encode(*configSelection, track.isPVContributor(), track.itsNCls(), track.itsChi2NCl(), track.tpcNClsFound(), track.tpcChi2NCl(), track.tpcNClsCrossedRows(), track.tpcFractionSharedCls(), {getAbsNSigmaDca(), getAbsNSigmaDca()}, holderTrack.pt, holderTrack.eta, holderTrack.sign, particleSpeciesAll, absNSigmaPid)}; + if (codeTrack.has_value()) { + miniTrack(miniCollision.lastIndex(), *codeTrack); + } + }}; + const auto fillByParticleSpeciesAll{ + [this, &fill] + requires IsValidEnumValue + () -> bool { + if constexpr (ParticleSpeciesAllValue == ParticleSpeciesAll::All) { + if (!isGoodMomentum(ParticleNumberValue)>(false)) { + return false; + } + + fill(ParticleSpeciesAll::All, 0.); + } else { + if (!isGoodMomentum(false)) { + return false; + } + + constexpr std::int32_t ParticleSpeciesIndex{toI(getValue(ParticleSpeciesAllValue))}; + const bool doUseTofPid{holderTrack.pt >= cgTrack.cfgThresholdsPtTofPid.value.get(ParticleSpeciesIndex)}; + if (!(doUseTofPid ? isPid(PidStrategy::TpcTof), ParticleSpeciesAllValue, Selection::Loose>(cgTrack.cfgFlagRejectionOthers.value) : isPid(PidStrategy::Tpc), ParticleSpeciesAllValue, Selection::Loose>(cgTrack.cfgFlagRejectionOthers.value))) { + return false; + } + + fill(ParticleSpeciesAllValue, doUseTofPid ? std::abs(holderTrack.getNSigmaPidCombined(ParticleSpeciesIndex)) : std::abs(holderTrack.nSigmaPid[toI(Detector::Tpc)][ParticleSpeciesIndex])); + } + return true; + }}; + + if constexpr (ParticleNumberValue == ParticleNumber::Charge) { + if (!fillByParticleSpeciesAll.template operator()() && !fillByParticleSpeciesAll.template operator()() && !fillByParticleSpeciesAll.template operator()()) { + fillByParticleSpeciesAll.template operator()(); + } + } else { + if (!fillByParticleSpeciesAll.template operator()(ParticleNumberValue)>()) { + fillByParticleSpeciesAll.template operator()(); + } + } + } + } + + template + void initMcParticle(const MP& mcParticle) + { + holderMcParticle.clear(); + holderMcParticle.pdgCode = mcParticle.pdgCode(); + const TParticlePDG* const particlePdg{pdg->GetParticle(mcParticle.pdgCode())}; + if (particlePdg) { + holderMcParticle.charge = static_cast(std::rint(particlePdg->Charge())); + } else { + switch (std::abs(holderMcParticle.pdgCode) / 100000000) { + case 10: + holderMcParticle.charge = holderMcParticle.pdgCode / 10000 % 1000; + break; + default: + break; + } + } + holderMcParticle.pt = mcParticle.pt(); + holderMcParticle.eta = mcParticle.eta(); + } + + template + bool initTrack(const T& track) + { + if (!setTrack(track)) { + return false; + } if constexpr (DoInitEvent) { if (track.isPrimaryTrack()) { @@ -1974,17 +2505,15 @@ struct PartNumFluc { } } - if (groupAnalysis.cfgFlagQaRun.value && track.isPrimaryTrack()) { + if (cgAnalysis.cfgFlagQaRun.value && track.isPrimaryTrack()) { if (holderTrack.sign > 0) { fillQaRunByTrackByChargeSpecies(track); } else { fillQaRunByTrackByChargeSpecies(track); } } - - return true; } else { - if (groupAnalysis.cfgFlagQaTrack.value && track.isPrimaryTrack()) { + if (cgAnalysis.cfgFlagQaTrack.value && track.isPrimaryTrack()) { if (holderTrack.sign > 0) { fillQaTrackByChargeSpecies(track); } else { @@ -1996,7 +2525,7 @@ struct PartNumFluc { return false; } - if (groupAnalysis.cfgFlagQaDca.value) { + if (cgAnalysis.cfgFlagQaDca.value) { if (holderTrack.sign > 0) { fillQaDcaByChargeSpecies(); } else { @@ -2008,49 +2537,55 @@ struct PartNumFluc { return false; } - { - const double vz{doProcessMc.value && groupEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz}; - if (doQaAcceptance && (holderTrack.eta * vz > 0. && std::abs(vz) > (doProcessMc.value && groupEvent.cfgFlagMcCollisionVz.value ? groupEvent.cfgCutMaxAbsVzMc.value : groupEvent.cfgCutMaxAbsVz.value) - 1.)) { - fillQaAcceptancebyParticleSpeciesAll(track); - fillQaAcceptancebyParticleSpeciesAll(track); - fillQaAcceptancebyParticleSpeciesAll(track); - fillQaAcceptancebyParticleSpeciesAll(track); + if (doQaAcceptance) { + const double vz{doProcessMc.value && cgEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz}; + if (holderTrack.eta * vz > 0. && std::abs(vz) > (doProcessMc.value && cgEvent.cfgFlagMcCollisionVz.value ? cgEvent.cfgCutMaxAbsVzMc.value : cgEvent.cfgCutMaxAbsVz.value) - 1.) { + fillQaAcceptanceByParticleSpeciesAll(track); + fillQaAcceptanceByParticleSpeciesAll(track); + fillQaAcceptanceByParticleSpeciesAll(track); + fillQaAcceptanceByParticleSpeciesAll(track); } } - - return true; } + + return true; } - template - bool initMcParticle(const MP& mcParticle) + template + McEventSelection initMcEvent(const MC& mcCollision) { - holderMcParticle.clear(); - holderMcParticle.pdgCode = mcParticle.pdgCode(); - const TParticlePDG* const particlePdg{pdg->GetParticle(mcParticle.pdgCode())}; - if (particlePdg) { - holderMcParticle.charge = std::llrint(particlePdg->Charge()); - } else { - switch (std::abs(holderMcParticle.pdgCode) / 100000000) { - case 10: - holderMcParticle.charge = holderMcParticle.pdgCode / 10000 % 1000; - break; - default: - break; - } + holderMcEvent.clear(); + holderMcEvent.vz = mcCollision.posZ(); + + const auto fillMcEventSelection{ + [this](const McEventSelection selection) -> McEventSelection { + hrCounter.fill(C_CS("hNMcEvents"), toI(selection)); + return selection; + }}; + + fillMcEventSelection(McEventSelection::All); + + if (cgEvent.cfgFlagInelEventMc.value && !mcCollision.isInelGt0()) { + return fillMcEventSelection(McEventSelection::Inel); } - holderMcParticle.pt = mcParticle.pt(); - holderMcParticle.eta = mcParticle.eta(); - return isGoodMcParticle(mcParticle); + if (!(std::abs(holderMcEvent.vz) < cgEvent.cfgCutMaxAbsVzMc.value)) { + return fillMcEventSelection(McEventSelection::Vz); + } + + if (cgEvent.cfgFlagSingleCollisionMc.value && mcCollision.numRecoCollision() != 1) { + return fillMcEventSelection(McEventSelection::NRecoCollisions); + } + + return fillMcEventSelection(McEventSelection::Good); } template - bool initEvent(const C& collision, const Ts& tracks) + EventSelection initEvent(const C& collision, const Ts& tracks) { holderEvent.clear(); holderEvent.vz = collision.posZ(); - switch (groupEvent.cfgIndexDefinitionCentrality.value) { + switch (cgEvent.cfgIndexDefinitionCentrality.value) { case toI(CentralityDefinition::Ft0a): holderEvent.centrality = collision.centFT0A(); break; @@ -2061,20 +2596,25 @@ struct PartNumFluc { holderEvent.centrality = collision.centFT0M(); break; } - holderEvent.centralityCalibration = (groupEvent.cfgFlagDefinitionCentralitySameQa.value ? holderEvent.centrality : collision.centNTPV()); + holderEvent.centralityCalibration = (cgEvent.cfgFlagDefinitionCentralitySameQa.value ? holderEvent.centrality : collision.centNTPV()); - const auto fillEventSelection{[this](const auto... selections) -> void { - (hrCounter.fill(C_CS("hNEvents"), selections), ...); - if (groupAnalysis.cfgFlagQaCentrality.value) { - (hrQaCentrality.fill(C_CS("QaCentrality/hCentralitySelection"), holderEvent.centrality, selections), ...); - } - }}; + const auto fillEventSelection{ + [this](const EventSelection selection, const auto... selectionsAdditional) -> EventSelection + requires((std::is_arithmetic_v> && ...)) + { + hrCounter.fill(C_CS("hNEvents"), toI(selection)); + (hrCounter.fill(C_CS("hNEvents"), selectionsAdditional), ...); + if (cgAnalysis.cfgFlagQaCentrality.value) { + hrQaCentrality.fill(C_CS("hCentralitySelection"), holderEvent.centrality, toI(selection)); + (hrQaCentrality.fill(C_CS("hCentralitySelection"), holderEvent.centrality, selectionsAdditional), ...); + } + return selection; + }}; - fillEventSelection(0.); + fillEventSelection(EventSelection::All); if (!collision.has_foundBC()) { - fillEventSelection(2.); - return false; + return fillEventSelection(EventSelection::Run); } const auto& foundBc{collision.template foundBC_as()}; @@ -2083,66 +2623,66 @@ struct PartNumFluc { { const auto iter{holderCcdb.runNumbersIndicesGroupIndices.find(holderEvent.runNumber)}; if (iter == holderCcdb.runNumbersIndicesGroupIndices.end()) { - fillEventSelection(2.); - return false; + return fillEventSelection(EventSelection::Run); } std::tie(holderEvent.runIndex, holderEvent.runGroupIndex) = iter->second; } - if (holderEvent.runGroupIndex == 0 || (groupEvent.cfgFlagRejectionRunBad.value && holderEvent.runGroupIndex < 0)) { - fillEventSelection(2.); - return false; + if (holderEvent.runGroupIndex == 0 || (cgEvent.cfgFlagRejectionRunBad.value && holderEvent.runGroupIndex < 0)) { + return fillEventSelection(EventSelection::Run); } if (rctFlagsChecker.any() && !rctFlagsChecker.checkTable(collision)) { - fillEventSelection(3.); - return false; + return fillEventSelection(EventSelection::Rct); } - if (groupEvent.cfgFlagInelEvent.value && !collision.isInelGt0()) { - fillEventSelection(4.); - return false; + if (cgEvent.cfgFlagInelEvent.value && !collision.isInelGt0()) { + return fillEventSelection(EventSelection::Inel); } - for (std::int32_t const& iEvSel : std::views::iota(0, aod::evsel::EventSelectionFlags::kNsel)) { - if (((groupEvent.cfgBitsSelectionEvent.value >> iEvSel) & 1) && !collision.selection_bit(iEvSel)) { - fillEventSelection(5., 10. + iEvSel); - return false; + for (std::int32_t const& iBit : std::views::iota(0, aod::evsel::EventSelectionFlags::kNsel)) { + if (((cgEvent.cfgBitsSelectionEvent.value >> iBit) & 1) && !collision.selection_bit(iBit)) { + return fillEventSelection(EventSelection::Bits, NEs + iBit); } } if (!HolderEvent::isValidCentrality(holderEvent.centrality) || !HolderEvent::isValidCentrality(holderEvent.centralityCalibration)) { - fillEventSelection(6.); - return false; + return fillEventSelection(EventSelection::Centrality); } - if (groupAnalysis.cfgFlagQaEvent.value) { - hrQaEvent.fill(C_CS("QaEvent/hVxVy"), collision.posX(), collision.posY()); - hrQaEvent.fill(C_CS("QaEvent/hVz"), holderEvent.vz); + if (cgAnalysis.cfgFlagQaEvent.value) { + hrQaEvent.fill(C_CS("hVxVy"), collision.posX(), collision.posY()); + hrQaEvent.fill(C_CS("hVz"), holderEvent.vz); } - if (!(std::abs(holderEvent.vz) < groupEvent.cfgCutMaxAbsVz.value)) { - fillEventSelection(7.); - return false; + if (!(std::abs(holderEvent.vz) < cgEvent.cfgCutMaxAbsVz.value)) { + return fillEventSelection(EventSelection::Vz); + } + + if (cgEvent.cfgCutMaxOccupancy.value > 0) { + const std::int32_t occupancy{collision.trackOccupancyInTimeRange()}; + if (occupancy < 0 || occupancy >= cgEvent.cfgCutMaxOccupancy.value) { + return fillEventSelection(EventSelection::Occupancy); + } } - if (groupAnalysis.cfgFlagQaRun.value) { - hrQaRun.fill(C_CS("QaRun/pRunIndexVx"), holderEvent.runIndex, collision.posX()); - hrQaRun.fill(C_CS("QaRun/pRunIndexVy"), holderEvent.runIndex, collision.posY()); - hrQaRun.fill(C_CS("QaRun/pRunIndexVz"), holderEvent.runIndex, holderEvent.vz); - hrQaRun.fill(C_CS("QaRun/pRunIndexMultiplicityFt0a"), holderEvent.runIndex, collision.multZeqFT0A()); - hrQaRun.fill(C_CS("QaRun/pRunIndexMultiplicityFt0c"), holderEvent.runIndex, collision.multZeqFT0C()); + if (cgAnalysis.cfgFlagQaRun.value) { + hrQaRun.fill(C_CS("pRunIndexVx"), holderEvent.runIndex, collision.posX()); + hrQaRun.fill(C_CS("pRunIndexVy"), holderEvent.runIndex, collision.posY()); + hrQaRun.fill(C_CS("pRunIndexVz"), holderEvent.runIndex, holderEvent.vz); + hrQaRun.fill(C_CS("pRunIndexMultiplicityFt0a"), holderEvent.runIndex, collision.multZeqFT0A()); + hrQaRun.fill(C_CS("pRunIndexMultiplicityFt0c"), holderEvent.runIndex, collision.multZeqFT0C()); if (const double centrality{collision.centNTPV()}; HolderEvent::isValidCentrality(centrality)) { - hrQaRun.fill(C_CS("QaRun/pRunIndexCentralityNtpv"), holderEvent.runIndex, centrality); + hrQaRun.fill(C_CS("pRunIndexCentralityNtpv"), holderEvent.runIndex, centrality); } if (const double centrality{collision.centFT0A()}; HolderEvent::isValidCentrality(centrality)) { - hrQaRun.fill(C_CS("QaRun/pRunIndexCentralityFt0a"), holderEvent.runIndex, centrality); + hrQaRun.fill(C_CS("pRunIndexCentralityFt0a"), holderEvent.runIndex, centrality); } if (const double centrality{collision.centFT0C()}; HolderEvent::isValidCentrality(centrality)) { - hrQaRun.fill(C_CS("QaRun/pRunIndexCentralityFt0c"), holderEvent.runIndex, centrality); + hrQaRun.fill(C_CS("pRunIndexCentralityFt0c"), holderEvent.runIndex, centrality); } if (const double centrality{collision.centFT0M()}; HolderEvent::isValidCentrality(centrality)) { - hrQaRun.fill(C_CS("QaRun/pRunIndexCentralityFt0m"), holderEvent.runIndex, centrality); + hrQaRun.fill(C_CS("pRunIndexCentralityFt0m"), holderEvent.runIndex, centrality); } } @@ -2158,78 +2698,185 @@ struct PartNumFluc { } } - if (groupAnalysis.cfgFlagQaRun.value) { + if (cgAnalysis.cfgFlagQaRun.value) { fillQaRunByEventByChargeSpecies(); fillQaRunByEventByChargeSpecies(); } - if (groupAnalysis.cfgFlagQaEvent.value) { - hrQaEvent.fill(C_CS("QaEvent/hNPvContributorsNGlobalTracks"), holderEvent.getNPvContributors(), holderEvent.getNGlobalTracks()); + if (cgAnalysis.cfgFlagQaEvent.value) { + hrQaEvent.fill(C_CS("hNPvContributorsNGlobalTracks"), holderEvent.getNPvContributors(), holderEvent.getNGlobalTracks()); if (holderEvent.getNGlobalTracks() > 0) { - hrQaEvent.fill(C_CS("QaEvent/hNGlobalTracks") + C_SV(getName(DcaMeasure::Mean)) + C_CS("Dca") + C_SV(getName(DcaAxis::Xy)), holderEvent.getNGlobalTracks(), holderEvent.getMeasureDca()); - hrQaEvent.fill(C_CS("QaEvent/hNGlobalTracks") + C_SV(getName(DcaMeasure::Mean)) + C_CS("Dca") + C_SV(getName(DcaAxis::Z)), holderEvent.getNGlobalTracks(), holderEvent.getMeasureDca()); + hrQaEvent.fill(C_CS("hNGlobalTracks") + C_SV(getName(DcaMeasure::Mean)) + C_CS("Dca") + C_SV(getName(DcaAxis::Xy)), holderEvent.getNGlobalTracks(), holderEvent.getMeasureDca()); + hrQaEvent.fill(C_CS("hNGlobalTracks") + C_SV(getName(DcaMeasure::Mean)) + C_CS("Dca") + C_SV(getName(DcaAxis::Z)), holderEvent.getNGlobalTracks(), holderEvent.getMeasureDca()); } - hrQaEvent.fill(C_CS("QaEvent/hNTofBetaNGlobalTracks"), holderEvent.getNTofBeta(), holderEvent.getNGlobalTracks()); + hrQaEvent.fill(C_CS("hNTofBetaNGlobalTracks"), holderEvent.getNTofBeta(), holderEvent.getNGlobalTracks()); } - if (!(holderEvent.getNPvContributors() - holderEvent.getNGlobalTracks() > groupEvent.cfgCutMinDeviationNPvContributors.value)) { - fillEventSelection(8.); - return false; + if (!(holderEvent.getNPvContributors() - holderEvent.getNGlobalTracks() > cgEvent.cfgCutMinDeviationNPvContributors.value)) { + return fillEventSelection(EventSelection::NPvContributors); } - fillEventSelection(1.); + readCcdb(); - if (groupAnalysis.cfgFlagQaEvent.value) { + if (cgAnalysis.cfgFlagQaEvent.value) { if (holderEvent.getNGlobalTracks() > 0) { - hrQaEvent.fill(C_CS("QaEvent/hNGlobalTracks") + C_SV(getName(DcaMeasure::Mean)) + C_CS("Dca") + C_SV(getName(DcaAxis::Xy)) + C_CS("_nPvContributorsCut"), holderEvent.getNGlobalTracks(), holderEvent.getMeasureDca()); - hrQaEvent.fill(C_CS("QaEvent/hNGlobalTracks") + C_SV(getName(DcaMeasure::Mean)) + C_CS("Dca") + C_SV(getName(DcaAxis::Z)) + C_CS("_nPvContributorsCut"), holderEvent.getNGlobalTracks(), holderEvent.getMeasureDca()); + hrQaEvent.fill(C_CS("hNGlobalTracks") + C_SV(getName(DcaMeasure::Mean)) + C_CS("Dca") + C_SV(getName(DcaAxis::Xy)) + C_CS("_nPvContributorsCut"), holderEvent.getNGlobalTracks(), holderEvent.getMeasureDca()); + hrQaEvent.fill(C_CS("hNGlobalTracks") + C_SV(getName(DcaMeasure::Mean)) + C_CS("Dca") + C_SV(getName(DcaAxis::Z)) + C_CS("_nPvContributorsCut"), holderEvent.getNGlobalTracks(), holderEvent.getMeasureDca()); } - hrQaEvent.fill(C_CS("QaEvent/hNTofBetaNGlobalTracks_nPvContributorsCut"), holderEvent.getNTofBeta(), holderEvent.getNGlobalTracks()); + hrQaEvent.fill(C_CS("hNTofBetaNGlobalTracks_nPvContributorsCut"), holderEvent.getNTofBeta(), holderEvent.getNGlobalTracks()); } - if (groupAnalysis.cfgFlagQaCentrality.value) { - hrQaCentrality.fill(C_CS("QaCentrality/hCentralityMultiplicity"), holderEvent.centrality, collision.multNTracksPVeta1()); + if (cgAnalysis.cfgFlagQaCentrality.value) { + hrQaCentrality.fill(C_CS("hCentralityMultiplicity"), holderEvent.centrality, collision.multNTracksPVeta1()); } - return true; + return fillEventSelection(EventSelection::Good); } - template - bool initMcEvent(const MC& mcCollision) + void processMc(const soa::Filtered::iterator& mcCollision, const aod::McParticles& mcParticles, const soa::SmallGroups& collisions, const soa::Filtered& tracksUngrouped, const aod::BCsWithTimestamps&) { - holderMcEvent.clear(); - holderMcEvent.vz = mcCollision.posZ(); + const McEventSelection mcEventSelection{initMcEvent(mcCollision)}; + if (mcEventSelection != McEventSelection::Good) { + return; + } + + for (const auto& collision : collisions) { + if (collision.globalIndex() != mcCollision.bestCollisionIndex()) { + continue; + } - hrCounter.fill(C_CS("hNMcEvents"), 0.); + const auto& tracks{tracksUngrouped.sliceBy(presliceTracksPerCollision, collision.globalIndex())}; - if (groupEvent.cfgFlagInelEventMc.value && !mcCollision.isInelGt0()) { - hrCounter.fill(C_CS("hNMcEvents"), 2.); - return false; - } + const EventSelection eventSelection{initEvent(collision, tracks)}; + if ((eventSelection == EventSelection::Good || toI(eventSelection) >= toI(EventSelection::NPvContributors)) && doStorageMiniTable && gRandom->Rndm() * cgEvent.cfgFactorStorageMiniTable.value < 1.) { + const bool isGoodNPvContributors{eventSelection != EventSelection::NPvContributors}; + readCcdb(); + fillMiniTableMc(mcParticles, tracks, isGoodNPvContributors); + fillMiniTableMc(mcParticles, tracks, isGoodNPvContributors); + fillMiniTableMc(mcParticles, tracks, isGoodNPvContributors); + } + if (eventSelection != EventSelection::Good) { + continue; + } - if (!(std::abs(holderMcEvent.vz) < groupEvent.cfgCutMaxAbsVzMc.value)) { - hrCounter.fill(C_CS("hNMcEvents"), 3.); - return false; - } + if (cgAnalysis.cfgFlagQaMc.value) { + hrQaMc.fill(C_CS("hCentralityVzMcDeltaVz"), holderEvent.centralityCalibration, holderMcEvent.vz, holderEvent.vz - holderMcEvent.vz); + } - if (groupEvent.cfgFlagSingleCollisionMc.value && mcCollision.numRecoCollision() != 1) { - hrCounter.fill(C_CS("hNMcEvents"), 4.); - return false; - } + if (cgAnalysis.cfgFlagQaTrack.value || cgAnalysis.cfgFlagQaDca.value || doQaAcceptance || doQaPhi || doQaPid || cgAnalysis.cfgFlagQaMc.value || doCalculationYield || doCalculationPurity || doCalculationFractionPrimary || doCalculationFluctuation) { + if (doCalculationFluctuation) { + holderEvent.subgroupIndex = gRandom->Integer(cgEvent.cfgNSubgroups.value); + initCalculationFluctuation(); + holderDerivedData.clear(); + } - hrCounter.fill(C_CS("hNMcEvents"), 1.); + for (const auto& mcParticle : mcParticles) { + initMcParticle(mcParticle); - return true; + if (mcParticle.isPhysicalPrimary()) { + if (doCalculationYield) { + fillCalculationYieldByParticleSpecies(); + fillCalculationYieldByParticleSpecies(); + fillCalculationYieldByParticleSpecies(); + } + + if (doCalculationFluctuation) { + calculateFluctuationByParticleNumber(); + calculateFluctuationByParticleNumber(); + calculateFluctuationByParticleNumber(); + } + } + + const auto& tracksMatched{tracks.sliceBy(presliceTracksPerMcParticle, mcParticle.globalIndex())}; + for (const auto& track : tracksMatched) { + if (!initTrack(track)) { + continue; + } + + if (doQaPhi) { + fillQaPhiByParticleSpeciesAll(); + fillQaPhiByParticleSpeciesAll(); + fillQaPhiByParticleSpeciesAll(); + fillQaPhiByParticleSpeciesAll(); + } + + if (doQaPid) { + fillQaPidByParticleSpeciesAll(track); + fillQaPidByParticleSpeciesAll(track); + fillQaPidByParticleSpeciesAll(track); + fillQaPidByParticleSpeciesAll(track); + } + + if (cgAnalysis.cfgFlagQaMc.value && (!cgTrack.cfgFlagMcParticlePhysicalPrimary.value || mcParticle.isPhysicalPrimary())) { + hrQaMc.fill(C_CS("hCentralityPtMcEtaMcDeltaPt"), holderEvent.centralityCalibration, holderMcParticle.pt, holderMcParticle.eta, holderTrack.pt - holderMcParticle.pt); + hrQaMc.fill(C_CS("hCentralityPtMcEtaMcDeltaEta"), holderEvent.centralityCalibration, holderMcParticle.pt, holderMcParticle.eta, holderTrack.eta - holderMcParticle.eta); + } + + if (doCalculationYield && (!cgTrack.cfgFlagMcParticlePhysicalPrimary.value || mcParticle.isPhysicalPrimary())) { + fillCalculationYieldByParticleSpecies(); + fillCalculationYieldByParticleSpecies(); + fillCalculationYieldByParticleSpecies(); + } + + if (doCalculationPurity && (!cgTrack.cfgFlagMcParticlePhysicalPrimary.value || mcParticle.isPhysicalPrimary())) { + fillCalculationPurityByParticleSpecies(); + fillCalculationPurityByParticleSpecies(); + fillCalculationPurityByParticleSpecies(); + } + + if (doCalculationFractionPrimary) { + fillCalculationFractionPrimaryByParticleSpecies(mcParticle); + fillCalculationFractionPrimaryByParticleSpecies(mcParticle); + fillCalculationFractionPrimaryByParticleSpecies(mcParticle); + } + + if (doCalculationFluctuation && (!cgTrack.cfgFlagMcParticlePhysicalPrimary.value || mcParticle.isPhysicalPrimary())) { + calculateFluctuationByParticleNumber(); + calculateFluctuationByParticleNumber(); + calculateFluctuationByParticleNumber(); + } + } + } + + if (doCalculationFluctuation) { + fillCalculationFluctuationByParticleNumber(); + fillCalculationFluctuationByParticleNumber(); + fillCalculationFluctuationByParticleNumber(); + if (const std::optional codeCollision{mini_collision_codec::encode(cgEvent.cfgFlagMcCollisionVz.value ? holderMcEvent.vz : holderEvent.vz, holderEvent.centrality, true)}; codeCollision.has_value()) { + tinyMcCollision(holderDerivedData.nMcParticles[toI(ChargeSpecies::Plus)], holderDerivedData.nMcParticles[toI(ChargeSpecies::Minus)]); + tinyCollision(*codeCollision, holderDerivedData.nTracks[toI(ChargeSpecies::Plus)], holderDerivedData.nTracks[toI(ChargeSpecies::Minus)]); + for (aod::tiny_mc_particle::SignedEfficiency::type const& signedEfficiency : holderDerivedData.signedEfficienciesMcParticle) { + tinyMcParticle(tinyMcCollision.lastIndex(), signedEfficiency); + } + for (aod::tiny_track::SignedEfficiency::type const& signedEfficiency : holderDerivedData.signedEfficienciesTrack) { + tinyTrack(tinyCollision.lastIndex(), signedEfficiency); + } + } + } + } + } } void processRaw(const soa::Filtered::iterator& collision, const soa::Filtered& tracks, const aod::BCsWithTimestamps&) { - if (!initEvent(collision, tracks) || (!groupAnalysis.cfgFlagQaTrack.value && !groupAnalysis.cfgFlagQaDca.value && !doQaAcceptance && !doQaPhi && !doQaPid && !doCalculationYield && !doCalculationFluctuation)) { + const EventSelection eventSelection{initEvent(collision, tracks)}; + if ((eventSelection == EventSelection::Good || toI(eventSelection) >= toI(EventSelection::NPvContributors)) && doStorageMiniTable && gRandom->Rndm() * cgEvent.cfgFactorStorageMiniTable.value < 1.) { + const bool isGoodNPvContributors{eventSelection != EventSelection::NPvContributors}; + readCcdb(); + fillMiniTableRaw(tracks, isGoodNPvContributors); + fillMiniTableRaw(tracks, isGoodNPvContributors); + fillMiniTableRaw(tracks, isGoodNPvContributors); + } + if (eventSelection != EventSelection::Good) { + return; + } + + if (!cgAnalysis.cfgFlagQaTrack.value && !cgAnalysis.cfgFlagQaDca.value && !doQaAcceptance && !doQaPhi && !doQaPid && !doCalculationYield && !doCalculationFluctuation) { return; } if (doCalculationFluctuation) { - holderEvent.subgroupIndex = gRandom->Integer(groupEvent.cfgNSubgroups.value); + holderEvent.subgroupIndex = gRandom->Integer(cgEvent.cfgNSubgroups.value); initCalculationFluctuation(); holderDerivedData.clear(); } @@ -2267,153 +2914,20 @@ struct PartNumFluc { } if (doCalculationFluctuation) { - fillCalculationFluctuationByParticleNumber(); - fillCalculationFluctuationByParticleNumber(); - fillCalculationFluctuationByParticleNumber(); - miniCollision(HolderDerivedData::convertFloor(holderEvent.vz * 10.), HolderDerivedData::convertFloor(holderEvent.centrality * 500.), holderDerivedData.nTracks[toI(ChargeSpecies::Plus)], holderDerivedData.nTracks[toI(ChargeSpecies::Minus)]); - for (std::int16_t const& signedEfficiency : holderDerivedData.signedEfficienciesTrack) { - miniTrack(miniCollision.lastIndex(), signedEfficiency); - } - } - } - - void processMc(const soa::Filtered::iterator& mcCollision, const aod::McParticles& mcParticles, const soa::SmallGroups& collisions, const soa::Filtered& tracksUngrouped, const aod::BCsWithTimestamps&) - { - if (!initMcEvent(mcCollision)) { - return; - } - - for (const auto& collision : collisions) { - if (groupEvent.cfgFlagBestCollisionMc.value && collision.globalIndex() != mcCollision.bestCollisionIndex()) { - continue; - } - - const auto& tracks{tracksUngrouped.sliceBy(presliceTracksPerCollision, collision.globalIndex())}; - - if (!initEvent(collision, tracks)) { - continue; - } - - if (groupAnalysis.cfgFlagQaMc.value) { - hrQaMc.fill(C_CS("QaMc/hCentralityVzMcDeltaVz"), holderEvent.centralityCalibration, holderMcEvent.vz, holderEvent.vz - holderMcEvent.vz); - } - - if (doCalculationYield || doCalculationFluctuation) { - if (doCalculationFluctuation) { - holderEvent.subgroupIndex = gRandom->Integer(groupEvent.cfgNSubgroups.value); - initCalculationFluctuation(); - holderDerivedData.clear(); - } - - for (const auto& mcParticle : mcParticles) { - if (!initMcParticle(mcParticle)) { - continue; - } - - if (doCalculationYield) { - fillCalculationYieldByParticleSpecies(); - fillCalculationYieldByParticleSpecies(); - fillCalculationYieldByParticleSpecies(); - } - - if (doCalculationFluctuation) { - calculateFluctuationByParticleNumber(); - calculateFluctuationByParticleNumber(); - calculateFluctuationByParticleNumber(); - } - } - - if (doCalculationFluctuation) { - fillCalculationFluctuationByParticleNumber(); - fillCalculationFluctuationByParticleNumber(); - fillCalculationFluctuationByParticleNumber(); - } - } - - if (groupAnalysis.cfgFlagQaTrack.value || groupAnalysis.cfgFlagQaDca.value || doQaAcceptance || doQaPhi || doQaPid || groupAnalysis.cfgFlagQaMc.value || doCalculationYield || doCalculationPurity || doCalculationFractionPrimary || doCalculationFluctuation) { - if (doCalculationFluctuation) { - initCalculationFluctuation(); - } - - for (const auto& track : tracks) { - if (!track.has_mcParticle()) { - continue; - } - - const auto& mcParticle{track.template mcParticle_as()}; - if (!mcParticle.has_mcCollision() || mcParticle.mcCollisionId() != mcCollision.globalIndex()) { - continue; - } - - if (!initTrack(track) || !initMcParticle(mcParticle)) { - continue; - } - - if (doQaPhi) { - fillQaPhiByParticleSpeciesAll(); - fillQaPhiByParticleSpeciesAll(); - fillQaPhiByParticleSpeciesAll(); - fillQaPhiByParticleSpeciesAll(); - } - - if (doQaPid) { - fillQaPidByParticleSpeciesAll(track); - fillQaPidByParticleSpeciesAll(track); - fillQaPidByParticleSpeciesAll(track); - fillQaPidByParticleSpeciesAll(track); - } - - if (groupAnalysis.cfgFlagQaMc.value && (!groupTrack.cfgFlagMcParticlePhysicalPrimary.value || mcParticle.isPhysicalPrimary())) { - hrQaMc.fill(C_CS("QaMc/hCentralityPtMcEtaMcDeltaPt"), holderEvent.centralityCalibration, holderMcParticle.pt, holderMcParticle.eta, holderTrack.pt - holderMcParticle.pt); - hrQaMc.fill(C_CS("QaMc/hCentralityPtMcEtaMcDeltaEta"), holderEvent.centralityCalibration, holderMcParticle.pt, holderMcParticle.eta, holderTrack.eta - holderMcParticle.eta); - } - - if (doCalculationYield && (!groupTrack.cfgFlagMcParticlePhysicalPrimary.value || mcParticle.isPhysicalPrimary())) { - fillCalculationYieldByParticleSpecies(); - fillCalculationYieldByParticleSpecies(); - fillCalculationYieldByParticleSpecies(); - } - - if (doCalculationPurity && (!groupTrack.cfgFlagMcParticlePhysicalPrimary.value || mcParticle.isPhysicalPrimary())) { - fillCalculationPurityByParticleSpecies(); - fillCalculationPurityByParticleSpecies(); - fillCalculationPurityByParticleSpecies(); - } - - if (doCalculationFractionPrimary) { - fillCalculationFractionPrimaryByParticleSpecies(mcParticle); - fillCalculationFractionPrimaryByParticleSpecies(mcParticle); - fillCalculationFractionPrimaryByParticleSpecies(mcParticle); - } - - if (doCalculationFluctuation && (!groupTrack.cfgFlagMcParticlePhysicalPrimary.value || mcParticle.isPhysicalPrimary())) { - calculateFluctuationByParticleNumber(); - calculateFluctuationByParticleNumber(); - calculateFluctuationByParticleNumber(); - } - } - - if (doCalculationFluctuation) { - fillCalculationFluctuationByParticleNumber(); - fillCalculationFluctuationByParticleNumber(); - fillCalculationFluctuationByParticleNumber(); - miniMcCollision(holderDerivedData.nMcParticles[toI(ChargeSpecies::Plus)], holderDerivedData.nMcParticles[toI(ChargeSpecies::Minus)]); - miniCollision(HolderDerivedData::convertFloor(holderEvent.vz * 10.), HolderDerivedData::convertFloor(holderEvent.centrality * 500.), holderDerivedData.nTracks[toI(ChargeSpecies::Plus)], holderDerivedData.nTracks[toI(ChargeSpecies::Minus)]); - for (std::int16_t const& signedEfficiency : holderDerivedData.signedEfficienciesMcParticle) { - miniMcParticle(miniMcCollision.lastIndex(), signedEfficiency); - } - for (std::int16_t const& signedEfficiency : holderDerivedData.signedEfficienciesTrack) { - miniTrack(miniCollision.lastIndex(), signedEfficiency); - } + fillCalculationFluctuationByParticleNumber(); + fillCalculationFluctuationByParticleNumber(); + fillCalculationFluctuationByParticleNumber(); + if (const std::optional codeCollision{mini_collision_codec::encode(holderEvent.vz, holderEvent.centrality, true)}; codeCollision.has_value()) { + tinyCollision(*codeCollision, holderDerivedData.nTracks[toI(ChargeSpecies::Plus)], holderDerivedData.nTracks[toI(ChargeSpecies::Minus)]); + for (aod::tiny_track::SignedEfficiency::type const& signedEfficiency : holderDerivedData.signedEfficienciesTrack) { + tinyTrack(tinyCollision.lastIndex(), signedEfficiency); } } - - break; } } - PROCESS_SWITCH_FULL(PartNumFluc, processRaw, ProcessRaw, "Flag of processing raw data", true); PROCESS_SWITCH_FULL(PartNumFluc, processMc, ProcessMc, "Flag of processing MC data", false); + PROCESS_SWITCH_FULL(PartNumFluc, processRaw, ProcessRaw, "Flag of processing raw data", true); }; WorkflowSpec defineDataProcessing(const ConfigContext& configContext) diff --git a/PWGCF/EbyEFluctuations/Tasks/radialFlowDecorr.cxx b/PWGCF/EbyEFluctuations/Tasks/radialFlowDecorr.cxx index cded5d14896..879200ba721 100644 --- a/PWGCF/EbyEFluctuations/Tasks/radialFlowDecorr.cxx +++ b/PWGCF/EbyEFluctuations/Tasks/radialFlowDecorr.cxx @@ -18,8 +18,6 @@ #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/FT0Corrected.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponseTOF.h" -#include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" #include @@ -38,8 +36,6 @@ #include #include -#include -#include #include #include #include @@ -47,6 +43,7 @@ #include #include #include +#include #include #include @@ -55,9 +52,9 @@ #include #include #include +#include #include #include -#include #include #include @@ -68,19 +65,16 @@ using namespace constants::math; struct RadialFlowDecorr { - static constexpr int KPidPionOne = 1; - static constexpr int KPidKaonTwo = 2; - static constexpr int KPidProtonThree = 3; - static constexpr int KConstTen = 10; - + // --- fixed constants --------------------------------------------------------- static constexpr int KnFt0cCell = 96; - static constexpr int KIntM = 3; - static constexpr int KIntK = 3; - static constexpr int KNEta = 9; + static constexpr int KIntM = 4; // pT-moment order used in the sums (need m up to 3 for c3) + static constexpr int KIntK = 4; // weight-power order used in the sums (need k up to 3 for c3) + + static constexpr int KNEtaHalfBinsMax = 8; // 0.8 / 0.1: finest (DATA) bins per side + static constexpr int KNEtaMax = 2 * KNEtaHalfBinsMax + 1; // + index-0 full-range reference bin + static constexpr float KFloatEpsilon = 1e-6f; - static constexpr int KPiPlus = 211; - static constexpr int KKPlus = 321; - static constexpr int KProton = 2212; + static constexpr float KEtaEdgeTolerance = 1e-3f; // slack for cfgCutEta being an integer multiple of the bin width static constexpr float KBinOffset = 0.5f; static constexpr float KPhiMin = 0.f; static constexpr int KNbinsZvtx = 240; @@ -94,47 +88,18 @@ struct RadialFlowDecorr { static constexpr float KEtaMin = -1.2f; static constexpr float KEtaMax = 1.2f; static constexpr int KNbinsPhi = 64; - static constexpr float KEtaAxisMin = -0.8f; - static constexpr float KEtaAxisMax = 0.8f; static constexpr int KNbinsPtRes = 50; - static constexpr float KPtResMax = 1.f; static constexpr int KNbinsEtaRes = 100; - static constexpr float KEtaResMax = 0.5f; static constexpr int KNbinsVz = 80; static constexpr float KVzMin = -40.f; static constexpr float KVzMax = 40.f; - static constexpr float KVzResMax = 20.f; static constexpr int KNbinsEtaFine = 20; static constexpr float KEtaFineMax = 1.f; - static constexpr int KNbinsDca = 400; - static constexpr float KDcaMax = 0.2f; static constexpr float KCentMax = 90; - enum PIDIdx { - kInclusiveIdx = 0, - kPiMinusIdx, - kPiPlusIdx, - kPiAllIdx, - kKaMinusIdx, - kKaPlusIdx, - kKaAllIdx, - kAntiPrIdx, - kPrIdx, - kPrAllIdx, - KNsp - }; - - inline static const std::vector pidSuffix = {"", "_PiMinus", "_PiPlus", "_PiAll", "_KaMinus", "_KaPlus", "_KaAll", "_AntiPr", "_Pr", "_PrAll"}; - - struct PIDMeanSigmaMap { - static constexpr int MaxCentBins = 100; - double meanTOF[KNsp][MaxCentBins] = {{0.0}}; - double sigmaTOF[KNsp][MaxCentBins] = {{1.0}}; // Default sigma = 1 - double meanTPC[KNsp][MaxCentBins] = {{0.0}}; - double sigmaTPC[KNsp][MaxCentBins] = {{1.0}}; // Default sigma = 1 - }; - - PIDMeanSigmaMap* pidMeanSigmaMap = nullptr; + // Bootstrap: KMaxBoot is the compile-time storage cap; the number actually + // filled is nBoot = min(cfgNBootstrap, KMaxBoot). + static constexpr int KMaxBoot = 64; enum ECentralityEstimator { kCentFT0C = 1, @@ -148,21 +113,42 @@ struct RadialFlowDecorr { kOO = 3, kpp = 4 }; + + // Systematic-variation selector for DATA. Base is the main measurement; each + // variation reads its own DataMean object (systSuffix) for the correlation step. + // kSystEtaBinning additionally changes the eta bin width via cfgEtaBinWidth. + enum ESystType { + kSystBase = 0, + kSystDCA, + kSystEff, + kSystFlat, + kSystNITS, + kSystNTPC, + kSystPileup, + kSystVz, + kSystEtaBinning, + kNSystType + }; + // Suffix appended to the DataMean CCDB path per systematic (Base -> no suffix). + inline static const std::vector systSuffix = { + "", "_systDCA", "_systEff", "_systFlat", + "_systNITS", "_systNTPC", "_systPileup", "_systVz", "_systEtaBinning"}; + static constexpr float KinvalidCentrality = -1.0f; - inline static const std::vector etaLw = { - -0.8, - -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6}; - inline static const std::vector etaUp = { - 0.8, - -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8}; - - Configurable cfgVtxZCut{"cfgVtxZCut", 10.f, "z-vertex range"}; - Configurable cfgPtMin{"cfgPtMin", 0.2f, "min pT"}; - Configurable cfgPtMax{"cfgPtMax", 5.0f, "max pT"}; - Configurable cfgEtaCut{"cfgEtaCut", 0.8f, "|η| cut"}; - Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + + // Observable eta binning, filled at init(): index 0 = full-range reference bin. + std::vector etaLw; + std::vector etaUp; + int nEta = 9; // active eta-bin count (set in init()) + int nBoot = 0; // active bootstrap samples (set in init()) + bool doBoot = false; // bootstrap active for this run (base data fluc only) + + // --- configurables ----------------------------------------------------------- + Configurable cfgVtxZCut{"cfgVtxZCut", 10.f, "|z_{vtx}| acceptance (cm): collision filter + explicit event/particle vertex checks"}; + Configurable cfgPtMin{"cfgPtMin", 0.2f, "min pT for observables"}; + Configurable cfgPtMax{"cfgPtMax", 5.0f, "max pT for observables"}; Configurable cfgCutTracKDcaMaxZ{"cfgCutTracKDcaMaxZ", 2.0f, "Maximum DcaZ"}; - Configurable cfgCutTracKDcaMaxXY{"cfgCutTracKDcaMaxXY", 0.2f, "Maximum DcaZ"}; + Configurable cfgCutTracKDcaMaxXY{"cfgCutTracKDcaMaxXY", 0.2f, "Maximum DcaXY"}; Configurable cfgPtDepDCAxy{"cfgPtDepDCAxy", false, "Use pt-dependent DCAxy cut"}; Configurable cfgDcaXyP0{"cfgDcaXyP0", 0.0026f, "p0 for DCAxy"}; @@ -177,18 +163,11 @@ struct RadialFlowDecorr { Configurable cfgITScluster{"cfgITScluster", 1, "Minimum Number of ITS cluster"}; Configurable cfgTPCcluster{"cfgTPCcluster", 80, "Minimum Number of TPC cluster"}; Configurable cfgTPCnCrossedRows{"cfgTPCnCrossedRows", 70, "Minimum Number of TPC crossed-rows"}; - Configurable cfgCutPtUpperTPC{"cfgCutPtUpperTPC", 0.6f, "Upper pT cut for PID using TPC only"}; - Configurable cfgnSigmaOtherParticles{"cfgnSigmaOtherParticles", 3.0f, "PID nSigma cut to remove other particles (default:3)"}; - Configurable cfgnSigmaCutTPC{"cfgnSigmaCutTPC", 2.0f, "PID nSigma cut for TPC"}; - Configurable cfgnSigmaCutTOF{"cfgnSigmaCutTOF", 2.0f, "PID nSigma cut for TOF"}; - Configurable cfgnSigmaCutCombTPCTOF{"cfgnSigmaCutCombTPCTOF", 2.0f, "PID nSigma combined cut for TPC and TOF"}; - - Configurable cfgCutPtLower{"cfgCutPtLower", 0.2f, "Lower pT cut"}; - Configurable cfgCutPtUpper{"cfgCutPtUpper", 10.0f, "Higher pT cut for inclusive hadron analysis"}; - Configurable cfgCutPtUpperPID{"cfgCutPtUpperPID", 6.0f, "Higher pT cut for identified particle analysis"}; + + Configurable cfgCutPtLower{"cfgCutPtLower", 0.2f, "Lower pT cut (track selection)"}; + Configurable cfgCutPtUpper{"cfgCutPtUpper", 10.0f, "Higher pT cut (track selection)"}; Configurable cfgCutEta{"cfgCutEta", 0.8f, "absolute Eta cut"}; - Configurable cfgMinTracksPerEtaBin{"cfgMinTracksPerEtaBin", 0, "Min weighted-track sum required in every narrow eta bin for inclusive species (0 = disabled)"}; - Configurable cfgNsubsample{"cfgNsubsample", 10, "Number of subsamples"}; + Configurable cfgEtaBinWidth{"cfgEtaBinWidth", 0.1f, "DATA only: width of each narrow observable eta bin (eta units); cfgCutEta must be an integer multiple so eta=0 is a bin edge. MC is pinned to 0.2."}; Configurable cfgCentralityChoice{"cfgCentralityChoice", 1, "Which centrality estimator? 1-->FT0C, 2-->FT0M, 3-->FDDM, 4-->FV0A"}; Configurable cfgEvSelNoSameBunchPileup{"cfgEvSelNoSameBunchPileup", true, "Pileup removal"}; Configurable cfgUseGoodITSLayerAllCut{"cfgUseGoodITSLayerAllCut", true, "Remove time interval with dead ITS zone"}; @@ -205,7 +184,11 @@ struct RadialFlowDecorr { Configurable cfgNchPbMax{"cfgNchPbMax", 5000, "Max Nch range for PbPb collisions"}; Configurable cfgNchOMax{"cfgNchOMax", 800, "Max Nch range for OO collisions"}; - Configurable cfgSys{"cfgSys", 1, "Efficiency to be used for which system? 1-->PbPb, 2-->NeNe, 3-->OO, 4-->pp"}; + Configurable cfgSys{"cfgSys", 1, "Which collision system? 1-->PbPb, 2-->NeNe, 3-->OO, 4-->pp"}; + Configurable cfgSystType{"cfgSystType", 0, "Systematic variation: 0=Base,1=systDCA,2=systEff,3=systFlat,4=systNEta,5=systNITS,6=systNTPC,7=systPileup,8=systVz,9=systEtaBinning"}; + Configurable cfgNBootstrap{"cfgNBootstrap", 30, "Number of Poisson bootstrap samples (base data run only)"}; + Configurable cfgBootstrapSeed{"cfgBootstrapSeed", 0, "TRandom3 seed for bootstrap (0 = machine-random per job)"}; + Configurable cfgFlat{"cfgFlat", false, "Whether to use flattening weights"}; Configurable cfgEff{"cfgEff", false, "Whether to use Efficiency weights"}; Configurable cfgZDC{"cfgZDC", false, "Whether to use ZDC for pileup histograms"}; @@ -215,405 +198,207 @@ struct RadialFlowDecorr { ConfigurableAxis cfgAxisCent{"cfgAxisCent", {0.0, 1.0, 5.0, 10, 20, 40, 60, 80, 100}, "centrality axis (percentile)"}; - const AxisSpec centAxis{cfgAxisCent, "Centrality (%)"}; - const AxisSpec centAxis1Per{100, 0.0, 100.0, "Centrality (%)"}; + // --- axes -------------------------------------------------------------------- + AxisSpec centAxis{cfgAxisCent, "Centrality (%)"}; + AxisSpec centAxis1Per{100, 0.0, 100.0, "Centrality (%)"}; AxisSpec nChAxis{1, 0., 1., "Nch", "Nch"}; AxisSpec nChAxis2{1, 0., 1., "Nch", "Nch"}; - const AxisSpec vzAxis{5, -12.5, 12.5, "Vz"}; - const AxisSpec chgAxis{3, -1.5, 1.5}; - const AxisSpec pTAxis{{0.0, 0.2, 0.4, 0.6, 0.8, 1, 3, 5, 7, 10}, "pT Axis"}; - const AxisSpec etaAxis{{-0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8}, "Eta"}; - const AxisSpec phiAxis{KNbinsPhi, KPhiMin, TwoPI, "#phi"}; - const AxisSpec etaBinAxis{KNEta + 1, -0.5, KNEta + 0.5, "#eta bin Number"}; - const AxisSpec spBinAxis{KNsp + 1, -KBinOffset, static_cast(KNsp) + KBinOffset, "species index Number"}; + AxisSpec vzAxis{5, -12.5, 12.5, "Vz"}; + AxisSpec chgAxis{3, -1.5, 1.5}; + AxisSpec pTAxis{{0.0, 0.2, 0.4, 0.6, 0.8, 1, 3, 5, 7, 10}, "pT Axis"}; + AxisSpec phiAxis{KNbinsPhi, KPhiMin, TwoPI, "#phi"}; - const AxisSpec gapAxis{{-1.5, -1.3, -1.1, -0.9, -0.7, -0.5, -0.3, -0.1, - 0.1, 0.3, 0.5, 0.7, 0.9, 1.1, 1.3, 1.5}, - "Gap"}; + // etaFlatAxis is the *fixed* granularity used only for the flattening map, so + // that a flattening map is reusable across the 0.1/0.2 observable binnings. + AxisSpec etaFlatAxis{{-0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8}, "#eta"}; - const AxisSpec sumAxis{{-1.5, -1.3, -1.1, -0.9, -0.7, -0.5, -0.3, -0.1, - 0.1, 0.3, 0.5, 0.7, 0.9, 1.1, 1.3, 1.5}, - "Sum"}; + // etaAxis (physical) and etaBinAxis (integer index) follow the observable + // binning and are rebuilt in init(). Placeholders here. + AxisSpec etaAxis{9, -0.9, 0.9, "#eta"}; + AxisSpec etaBinAxis{10, -0.5, 9.5, "#eta bin Number"}; - Configurable cfgRunMCGetNSig{"cfgRunMCGetNSig", false, "Run MC pass to get mean of Nsig Plots"}; + AxisSpec gapAxis{{-1.5, -1.3, -1.1, -0.9, -0.7, -0.5, -0.3, -0.1, + 0.1, 0.3, 0.5, 0.7, 0.9, 1.1, 1.3, 1.5}, + "Gap"}; + AxisSpec sumAxis{{-1.5, -1.3, -1.1, -0.9, -0.7, -0.5, -0.3, -0.1, + 0.1, 0.3, 0.5, 0.7, 0.9, 1.1, 1.3, 1.5}, + "Sum"}; + + // --- process switches -------------------------------------------------------- Configurable cfgRunGetEff{"cfgRunGetEff", false, "Run MC pass to build efficiency/fake maps"}; - Configurable cfgRunGetMCFlat{"cfgRunGetMCFlat", false, "Run MC to Get Flattening Weights"}; - Configurable cfgRunMCMean{"cfgRunMCMean", false, "Run MC mean(pT) & mean(Et)"}; + Configurable cfgRunGetMCFlat{"cfgRunGetMCFlat", false, "Run MC to get flattening weights"}; + Configurable cfgRunMCMean{"cfgRunMCMean", false, "Run MC mean(pT)"}; Configurable cfgRunMCFluc{"cfgRunMCFluc", false, "Run MC fluctuations (C2, subevent)"}; - Configurable cfgRunDataGetNSig{"cfgRunDataGetNSig", false, "Run MC pass to get mean of Nsig Plots"}; - Configurable cfgRunGetDataFlat{"cfgRunGetDataFlat", false, "Run Data Get Flattening Weights"}; - Configurable cfgRunDataMean{"cfgRunDataMean", false, "Run DATA mean(pT) & mean(Et)"}; + Configurable cfgRunGetDataFlat{"cfgRunGetDataFlat", false, "Run data get flattening weights"}; + Configurable cfgRunDataMean{"cfgRunDataMean", false, "Run DATA mean(pT)"}; Configurable cfgRunDataFluc{"cfgRunDataFluc", false, "Run DATA fluctuations (C2, subevent)"}; - Service ccdb; - Service pdg; + Service ccdb{}; + Service pdg{}; HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + TRandom3 rng; // bootstrap Poisson weights + + // --- persistent state -------------------------------------------------------- struct InternalState { - std::array hEff{}; - std::array hFake{}; - std::array hFlatWeight{}; + TH3F* hEff = nullptr; + TH3F* hFake = nullptr; + THnSparseF* hFlatWeight = nullptr; std::vector> mLimitsNchCent; float mMinXNchCent = 0, mMaxXNchCent = 0; - TProfile3D* pmeanTruNchEtabinSpbinStep2 = nullptr; - TProfile3D* pmeanRecoNchEtabinSpbinStep2 = nullptr; - TProfile3D* pmeanRecoEffcorrNchEtabinSpbinStep2 = nullptr; + // MC mean maps (per eta bin): truth / reco / reco-eff-corrected + TProfile2D* pmeanTruNchEtabinStep2 = nullptr; + TProfile2D* pmeanRecoNchEtabinStep2 = nullptr; + TProfile2D* pmeanRecoEffcorrNchEtabinStep2 = nullptr; + TProfile2D* pmeanMultTruNchEtabinStep2 = nullptr; + TProfile2D* pmeanMultRecoNchEtabinStep2 = nullptr; + TProfile2D* pmeanMultRecoEffcorrNchEtabinStep2 = nullptr; - TProfile3D* pmeanMultTruNchEtabinSpbinStep2 = nullptr; - TProfile3D* pmeanMultRecoNchEtabinSpbinStep2 = nullptr; - TProfile3D* pmeanMultRecoEffcorrNchEtabinSpbinStep2 = nullptr; - - TProfile3D* pmeanNchEtabinSpbinStep2 = nullptr; - TProfile3D* pmeanMultNchEtabinSpbinStep2 = nullptr; + // Data mean maps (per eta bin) + TProfile2D* pmeanNchEtabinStep2 = nullptr; + TProfile2D* pmeanMultNchEtabinStep2 = nullptr; TProfile* pmeanFT0AmultpvStep2 = nullptr; TProfile* pmeanFT0CmultpvStep2 = nullptr; } state; o2::ft0::Geometry ft0Det; - template - void fillNSigmaBefCut(const T& track, float cent) - { - float pt = track.pt(); - auto sign = track.sign(); - - if (sign > 0) { - histos.fill(HIST("h3DnsigmaTpcVsPtBefCut_Cent_PiPlus"), cent, pt, track.tpcNSigmaPi()); - histos.fill(HIST("h3DnsigmaTofVsPtBefCut_Cent_PiPlus"), cent, pt, track.tofNSigmaPi()); - histos.fill(HIST("h3DnsigmaTpcVsTofBefCut_Cent_PiPlus"), cent, track.tofNSigmaPi(), track.tpcNSigmaPi()); - - histos.fill(HIST("h3DnsigmaTpcVsPtBefCut_Cent_KaPlus"), cent, pt, track.tpcNSigmaKa()); - histos.fill(HIST("h3DnsigmaTofVsPtBefCut_Cent_KaPlus"), cent, pt, track.tofNSigmaKa()); - histos.fill(HIST("h3DnsigmaTpcVsTofBefCut_Cent_KaPlus"), cent, track.tofNSigmaKa(), track.tpcNSigmaKa()); - - histos.fill(HIST("h3DnsigmaTpcVsPtBefCut_Cent_Pr"), cent, pt, track.tpcNSigmaPr()); - histos.fill(HIST("h3DnsigmaTofVsPtBefCut_Cent_Pr"), cent, pt, track.tofNSigmaPr()); - histos.fill(HIST("h3DnsigmaTpcVsTofBefCut_Cent_Pr"), cent, track.tofNSigmaPr(), track.tpcNSigmaPr()); - } else if (sign < 0) { - histos.fill(HIST("h3DnsigmaTpcVsPtBefCut_Cent_PiMinus"), cent, pt, track.tpcNSigmaPi()); - histos.fill(HIST("h3DnsigmaTofVsPtBefCut_Cent_PiMinus"), cent, pt, track.tofNSigmaPi()); - histos.fill(HIST("h3DnsigmaTpcVsTofBefCut_Cent_PiMinus"), cent, track.tofNSigmaPi(), track.tpcNSigmaPi()); - - histos.fill(HIST("h3DnsigmaTpcVsPtBefCut_Cent_KaMinus"), cent, pt, track.tpcNSigmaKa()); - histos.fill(HIST("h3DnsigmaTofVsPtBefCut_Cent_KaMinus"), cent, pt, track.tofNSigmaKa()); - histos.fill(HIST("h3DnsigmaTpcVsTofBefCut_Cent_KaMinus"), cent, track.tofNSigmaKa(), track.tpcNSigmaKa()); - - histos.fill(HIST("h3DnsigmaTpcVsPtBefCut_Cent_AntiPr"), cent, pt, track.tpcNSigmaPr()); - histos.fill(HIST("h3DnsigmaTofVsPtBefCut_Cent_AntiPr"), cent, pt, track.tofNSigmaPr()); - histos.fill(HIST("h3DnsigmaTpcVsTofBefCut_Cent_AntiPr"), cent, track.tofNSigmaPr(), track.tpcNSigmaPr()); - } - histos.fill(HIST("h3DnsigmaTpcVsPtBefCut_Cent_PiAll"), cent, pt, track.tpcNSigmaPi()); - histos.fill(HIST("h3DnsigmaTofVsPtBefCut_Cent_PiAll"), cent, pt, track.tofNSigmaPi()); - histos.fill(HIST("h3DnsigmaTpcVsTofBefCut_Cent_PiAll"), cent, track.tofNSigmaPi(), track.tpcNSigmaPi()); - - histos.fill(HIST("h3DnsigmaTpcVsPtBefCut_Cent_KaAll"), cent, pt, track.tpcNSigmaKa()); - histos.fill(HIST("h3DnsigmaTofVsPtBefCut_Cent_KaAll"), cent, pt, track.tofNSigmaKa()); - histos.fill(HIST("h3DnsigmaTpcVsTofBefCut_Cent_KaAll"), cent, track.tofNSigmaKa(), track.tpcNSigmaKa()); - - histos.fill(HIST("h3DnsigmaTpcVsPtBefCut_Cent_PrAll"), cent, pt, track.tpcNSigmaPr()); - histos.fill(HIST("h3DnsigmaTofVsPtBefCut_Cent_PrAll"), cent, pt, track.tofNSigmaPr()); - histos.fill(HIST("h3DnsigmaTpcVsTofBefCut_Cent_PrAll"), cent, track.tofNSigmaPr(), track.tpcNSigmaPr()); - } - - template - void fillNSigmaAftCut(const T& track, float cent, bool isSpecies[]) - { - float pt = track.pt(); - float tpcPi = track.tpcNSigmaPi(); - float tofPi = track.tofNSigmaPi(); - - float tpcKa = track.tpcNSigmaKa(); - float tofKa = track.tofNSigmaKa(); - - float tpcPr = track.tpcNSigmaPr(); - float tofPr = track.tofNSigmaPr(); - - if (isSpecies[kPiPlusIdx]) { - histos.fill(HIST("h3DnsigmaTpcVsPtAftCut_Cent_PiPlus"), cent, pt, tpcPi); - histos.fill(HIST("h3DnsigmaTofVsPtAftCut_Cent_PiPlus"), cent, pt, tofPi); - histos.fill(HIST("h3DnsigmaTpcVsTofAftCut_Cent_PiPlus"), cent, tofPi, tpcPi); - } - if (isSpecies[kPiMinusIdx]) { - histos.fill(HIST("h3DnsigmaTpcVsPtAftCut_Cent_PiMinus"), cent, pt, tpcPi); - histos.fill(HIST("h3DnsigmaTofVsPtAftCut_Cent_PiMinus"), cent, pt, tofPi); - histos.fill(HIST("h3DnsigmaTpcVsTofAftCut_Cent_PiMinus"), cent, tofPi, tpcPi); - } - if (isSpecies[kPiAllIdx]) { - histos.fill(HIST("h3DnsigmaTpcVsPtAftCut_Cent_PiAll"), cent, pt, tpcPi); - histos.fill(HIST("h3DnsigmaTofVsPtAftCut_Cent_PiAll"), cent, pt, tofPi); - histos.fill(HIST("h3DnsigmaTpcVsTofAftCut_Cent_PiAll"), cent, tofPi, tpcPi); - } - if (isSpecies[kKaPlusIdx]) { - histos.fill(HIST("h3DnsigmaTpcVsPtAftCut_Cent_KaPlus"), cent, pt, tpcKa); - histos.fill(HIST("h3DnsigmaTofVsPtAftCut_Cent_KaPlus"), cent, pt, tofKa); - histos.fill(HIST("h3DnsigmaTpcVsTofAftCut_Cent_KaPlus"), cent, tofKa, tpcKa); - } - if (isSpecies[kKaMinusIdx]) { - histos.fill(HIST("h3DnsigmaTpcVsPtAftCut_Cent_KaMinus"), cent, pt, tpcKa); - histos.fill(HIST("h3DnsigmaTofVsPtAftCut_Cent_KaMinus"), cent, pt, tofKa); - histos.fill(HIST("h3DnsigmaTpcVsTofAftCut_Cent_KaMinus"), cent, tofKa, tpcKa); - } - if (isSpecies[kKaAllIdx]) { - histos.fill(HIST("h3DnsigmaTpcVsPtAftCut_Cent_KaAll"), cent, pt, tpcKa); - histos.fill(HIST("h3DnsigmaTofVsPtAftCut_Cent_KaAll"), cent, pt, tofKa); - histos.fill(HIST("h3DnsigmaTpcVsTofAftCut_Cent_KaAll"), cent, tofKa, tpcKa); - } - if (isSpecies[kPrIdx]) { - histos.fill(HIST("h3DnsigmaTpcVsPtAftCut_Cent_Pr"), cent, pt, tpcPr); - histos.fill(HIST("h3DnsigmaTofVsPtAftCut_Cent_Pr"), cent, pt, tofPr); - histos.fill(HIST("h3DnsigmaTpcVsTofAftCut_Cent_Pr"), cent, tofPr, tpcPr); - } - if (isSpecies[kAntiPrIdx]) { - histos.fill(HIST("h3DnsigmaTpcVsPtAftCut_Cent_AntiPr"), cent, pt, tpcPr); - histos.fill(HIST("h3DnsigmaTofVsPtAftCut_Cent_AntiPr"), cent, pt, tofPr); - histos.fill(HIST("h3DnsigmaTpcVsTofAftCut_Cent_AntiPr"), cent, tofPr, tpcPr); - } - if (isSpecies[kPrAllIdx]) { - histos.fill(HIST("h3DnsigmaTpcVsPtAftCut_Cent_PrAll"), cent, pt, tpcPr); - histos.fill(HIST("h3DnsigmaTofVsPtAftCut_Cent_PrAll"), cent, pt, tofPr); - histos.fill(HIST("h3DnsigmaTpcVsTofAftCut_Cent_PrAll"), cent, tofPr, tpcPr); - } else { - return; - } - } - - // Returns: 0 = Unknown/Reject, 1 = Pion, 2 = Kaon, 3 = Proton - template - int identifyTrack(const T& candidate, int cent) - { - if (!candidate.hasTPC()) - return 0; - - float pt = candidate.pt(); - if (pt <= cfgCutPtLower || pt >= cfgCutPtUpperPID) - return 0; // Out of bounds - - if (!pidMeanSigmaMap) - return 0; - - int centBin = cent + 0.5; - auto charge = candidate.sign(); - int piIdx = (charge > 0) ? kPiPlusIdx : kPiMinusIdx; - int kaIdx = (charge > 0) ? kKaPlusIdx : kKaMinusIdx; - int prIdx = (charge > 0) ? kPrIdx : kAntiPrIdx; - - // TPC - float mPiTpc = pidMeanSigmaMap->meanTPC[piIdx][centBin]; - float sPiTpc = pidMeanSigmaMap->sigmaTPC[piIdx][centBin]; - - float mKaTpc = pidMeanSigmaMap->meanTPC[kaIdx][centBin]; - float sKaTpc = pidMeanSigmaMap->sigmaTPC[kaIdx][centBin]; - - float mPrTpc = pidMeanSigmaMap->meanTPC[prIdx][centBin]; - float sPrTpc = pidMeanSigmaMap->sigmaTPC[prIdx][centBin]; - - // TOF - float mPiTof = pidMeanSigmaMap->meanTOF[piIdx][centBin]; - float sPiTof = pidMeanSigmaMap->sigmaTOF[piIdx][centBin]; - - float mKaTof = pidMeanSigmaMap->meanTOF[kaIdx][centBin]; - float sKaTof = pidMeanSigmaMap->sigmaTOF[kaIdx][centBin]; - - float mPrTof = pidMeanSigmaMap->meanTOF[prIdx][centBin]; - float sPrTof = pidMeanSigmaMap->sigmaTOF[prIdx][centBin]; - - static int debugLogCounter = 0; - if (debugLogCounter < KConstTen) { - LOGF(info, "[PID DEBUG] CentBin: %d, Charge: %d", centBin, charge); - LOGF(info, " -> TPC USED | Pi (\u03bc=%.3f, \u03c3=%.3f) | Ka (\u03bc=%.3f, \u03c3=%.3f) | Pr (\u03bc=%.3f, \u03c3=%.3f)", - mPiTpc, sPiTpc, mKaTpc, sKaTpc, mPrTpc, sPrTpc); - - if (candidate.hasTOF()) { - LOGF(info, " -> TOF USED | Pi (\u03bc=%.3f, \u03c3=%.3f) | Ka (\u03bc=%.3f, \u03c3=%.3f) | Pr (\u03bc=%.3f, \u03c3=%.3f)", - mPiTof, sPiTof, mKaTof, sKaTof, mPrTof, sPrTof); - } else { - LOGF(info, " -> TOF USED | Track has no TOF signal."); - } - debugLogCounter++; - } - // Fetch Raw nSigma Values - float rawTpcPi = candidate.tpcNSigmaPi(); - float rawTpcKa = candidate.tpcNSigmaKa(); - float rawTpcPr = candidate.tpcNSigmaPr(); - - float rawTofPi = 0.f, rawTofKa = 0.f, rawTofPr = 0.f; - if (candidate.hasTOF()) { - rawTofPi = candidate.tofNSigmaPi(); - rawTofKa = candidate.tofNSigmaKa(); - rawTofPr = candidate.tofNSigmaPr(); - } - - // --- Low PT Regime --- - if (pt <= cfgCutPtUpperTPC) { - // Basic TPC passing check: |Raw - Mean| < (Cut * Sigma) - bool inTpcPi = std::abs(rawTpcPi - mPiTpc) < (cfgnSigmaCutTPC * sPiTpc); - bool inTpcKa = std::abs(rawTpcKa - mKaTpc) < (cfgnSigmaCutTPC * sKaTpc); - bool inTpcPr = std::abs(rawTpcPr - mPrTpc) < (cfgnSigmaCutTPC * sPrTpc); - - // Combined passing check (adds TOF if available) - bool passPi = inTpcPi && (!candidate.hasTOF() || std::abs(rawTofPi - mPiTof) < (cfgnSigmaCutTOF * sPiTof)); - bool passKa = inTpcKa && (!candidate.hasTOF() || std::abs(rawTofKa - mKaTof) < (cfgnSigmaCutTOF * sKaTof)); - bool passPr = inTpcPr && (!candidate.hasTOF() || std::abs(rawTofPr - mPrTof) < (cfgnSigmaCutTOF * sPrTof)); - - // Uniqueness check: Must pass target cut, and NOT fall into the TPC range of the others - if (passPi && !passKa && !passPr) - return 1; - if (passKa && !passPi && !passPr) - return 2; - if (passPr && !passPi && !passKa) - return 3; - - return 0; // Ambiguous or failed all cuts - } - - // --- High PT Regime--- - if (candidate.hasTOF() && pt > cfgCutPtUpperTPC) { - // Calculate 2D Normalized Distance (Elliptical distance normalized by sigma) - float dPi = std::hypot((rawTpcPi - mPiTpc) / sPiTpc, (rawTofPi - mPiTof) / sPiTof); - float dKa = std::hypot((rawTpcKa - mKaTpc) / sKaTpc, (rawTofKa - mKaTof) / sKaTof); - float dPr = std::hypot((rawTpcPr - mPrTpc) / sPrTpc, (rawTofPr - mPrTof) / sPrTof); - - // Count how many particles are within the ambiguity radius - int competitors = (dPi < cfgnSigmaOtherParticles) + - (dKa < cfgnSigmaOtherParticles) + - (dPr < cfgnSigmaOtherParticles); - - // If 1 or fewer are in the ambiguity region, pick the absolute best match - if (competitors <= 1) { - if (dPi <= dKa && dPi <= dPr && dPi < cfgnSigmaCutCombTPCTOF) - return 1; - if (dKa <= dPi && dKa <= dPr && dKa < cfgnSigmaCutCombTPCTOF) - return 2; - if (dPr <= dPi && dPr <= dKa && dPr < cfgnSigmaCutCombTPCTOF) - return 3; - } - } - return 0; // Unknown/Reject - } - + // --- bootstrap replica storage (base data fluc only) ------------------------- + struct BootstrapHists { + std::array, KMaxBoot> amplFT0ACent{}; + std::array, KMaxBoot> amplFT0AMult{}; + std::array, KMaxBoot> amplFT0CCent{}; + std::array, KMaxBoot> amplFT0CMult{}; + std::array, KMaxBoot> multCent{}; + std::array, KMaxBoot> multMult{}; + std::array, KMaxBoot> meanpTCent{}; + std::array, KMaxBoot> meanpTMult{}; + std::array, KMaxBoot> c2Cent{}; + std::array, KMaxBoot> c2Mult{}; + std::array, KMaxBoot> c3Cent{}; + std::array, KMaxBoot> c3Mult{}; + std::array, KMaxBoot> c2SubCent{}; + std::array, KMaxBoot> c2SubMult{}; + std::array, KMaxBoot> c3SubCent{}; + std::array, KMaxBoot> c3SubMult{}; + std::array, KMaxBoot> covCent{}; + std::array, KMaxBoot> covMult{}; + std::array, KMaxBoot> covFT0ACent{}; + std::array, KMaxBoot> covFT0AMult{}; + std::array, KMaxBoot> covFT0CCent{}; + std::array, KMaxBoot> covFT0CMult{}; + std::array, KMaxBoot> c2Sub2D{}; + std::array, KMaxBoot> c3Sub2D{}; + std::array, KMaxBoot> gapSum2D{}; + std::array, KMaxBoot> c3GapSum2D{}; + std::array, KMaxBoot> cov2D{}; + std::array, KMaxBoot> covFT0A2D{}; + std::array, KMaxBoot> covFT0C2D{}; + } bs; + + // =========================================================================== + // Selection helpers + // =========================================================================== template bool isEventSelected(const T& col) { histos.fill(HIST("hEvtCount"), 0.5); - - if (!col.sel8()) + if (!col.sel8()) { return false; + } histos.fill(HIST("hEvtCount"), 1.5); - - if (std::abs(col.posZ()) > cfgCutVertex) + if (std::abs(col.posZ()) > cfgVtxZCut) { return false; + } histos.fill(HIST("hEvtCount"), 2.5); - - if (cfgEvSelNoSameBunchPileup && !col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) + if (cfgEvSelNoSameBunchPileup && !col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { return false; + } histos.fill(HIST("hEvtCount"), 3.5); - - if (cfgUseGoodITSLayerAllCut && !col.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) + if (cfgUseGoodITSLayerAllCut && !col.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { return false; + } histos.fill(HIST("hEvtCount"), 4.5); - - if (cfgIsGoodZvtxFT0VsPV && !col.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) + if (cfgIsGoodZvtxFT0VsPV && !col.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { return false; + } histos.fill(HIST("hEvtCount"), 5.5); return true; } - bool isPassAddPileup(int multPV, int trksize, float cent) + bool isPassAddPileup(float multPV, int trksize, float cent) { auto checkLimits = [](float x, float y, const std::vector>& limits, float xM, float xMx) { - if (limits.empty()) + if (limits.empty()) { return true; + } int bin = 1 + static_cast((x - xM) / (xMx - xM) * (limits.size() - 2)); - if (bin < 1 || bin >= static_cast(limits.size() - 1)) + if (bin < 1 || bin >= static_cast(limits.size() - 1)) { return false; + } return (y >= limits[bin].first && y <= limits[bin].second); }; if (cfgApplySigPupCut) { - if (!checkLimits(cent, trksize, state.mLimitsNchCent, state.mMinXNchCent, state.mMaxXNchCent)) + if (!checkLimits(cent, trksize, state.mLimitsNchCent, state.mMinXNchCent, state.mMaxXNchCent)) { return false; + } histos.fill(HIST("hEvtCount"), 6.5); } - if (cfgApplyLinPupCut) { - if (trksize > (cfgLinPupParam0 + cfgLinPupParam1 * multPV)) + if (trksize > (cfgLinPupParam0 + cfgLinPupParam1 * multPV)) { return false; + } histos.fill(HIST("hEvtCount"), 7.5); - if (trksize < (cfgLinPupParam2 + cfgLinPupParam3 * multPV)) + if (trksize < (cfgLinPupParam2 + cfgLinPupParam3 * multPV)) { return false; + } histos.fill(HIST("hEvtCount"), 8.5); } return true; } - template - bool hasMinTracksInAllEtaBins(const double (&sw)[NspT][NetaT][NkT]) - { - const int minTracks = cfgMinTracksPerEtaBin; - if (minTracks <= 0) - return true; - for (std::size_t ieta = 1; ieta < NetaT; ++ieta) { - if (sw[kInclusiveIdx][ieta][1] < static_cast(minTracks)) - return false; - } - return true; - } - - template - bool hasMinTracksInAllEtaBins(const double (&sw)[NspT][NetaT]) - { - const int minTracks = cfgMinTracksPerEtaBin; - if (minTracks <= 0) - return true; - for (std::size_t ieta = 1; ieta < NetaT; ++ieta) { - if (sw[kInclusiveIdx][ieta] < static_cast(minTracks)) - return false; - } - return true; - } - template bool isTrackSelected(const T& trk) { histos.fill(HIST("hTrkCount"), 0.5); - - if (trk.sign() == 0) + if (trk.sign() == 0) { return false; + } histos.fill(HIST("hTrkCount"), 1.5); - - if (!trk.has_collision()) + if (!trk.has_collision()) { return false; + } histos.fill(HIST("hTrkCount"), 2.5); - - if (!trk.isPVContributor()) + if (!trk.isPVContributor()) { return false; + } histos.fill(HIST("hTrkCount"), 3.5); - - if (!(trk.itsNCls() > cfgITScluster)) + if (!(trk.itsNCls() > cfgITScluster)) { return false; + } histos.fill(HIST("hTrkCount"), 4.5); - - if (!(trk.tpcNClsFound() >= cfgTPCcluster)) + if (!(trk.tpcNClsFound() >= cfgTPCcluster)) { return false; + } histos.fill(HIST("hTrkCount"), 5.5); - - if (!(trk.tpcNClsCrossedRows() >= cfgTPCnCrossedRows)) + if (!(trk.tpcNClsCrossedRows() >= cfgTPCnCrossedRows)) { return false; + } histos.fill(HIST("hTrkCount"), 6.5); - - if (trk.pt() < cfgCutPtLower || trk.pt() > cfgCutPtUpper || std::abs(trk.eta()) > cfgCutEta) + if (trk.pt() < cfgCutPtLower || trk.pt() > cfgCutPtUpper || std::abs(trk.eta()) > cfgCutEta) { return false; + } histos.fill(HIST("hTrkCount"), 7.5); - - if (!trk.isGlobalTrack()) + if (!trk.isGlobalTrack()) { return false; + } histos.fill(HIST("hTrkCount"), 8.5); if (cfgPtDepDCAxy) { - // Evaluates: P0 + P1 / (pt^P2) float maxDcaXY = cfgDcaXyP0 + cfgDcaXyP1 / std::pow(trk.pt(), cfgDcaXyP2); if (std::abs(trk.dcaXY()) > maxDcaXY) { return false; @@ -626,10 +411,9 @@ struct RadialFlowDecorr { histos.fill(HIST("hTrkCount"), 9.5); } if (cfgPtDepDCAz) { - // Evaluates: P0 + P1 / (pt^P2) float maxDcaZ = cfgDcaZP0 + cfgDcaZP1 / std::pow(trk.pt(), cfgDcaZP2); if (std::abs(trk.dcaZ()) > maxDcaZ) { - return false; // Reject track if DCA is too large + return false; } histos.fill(HIST("hTrkCount"), 10.5); } else { @@ -645,67 +429,74 @@ struct RadialFlowDecorr { bool isParticleSelected(const T& particle) { auto* pd = pdg->GetParticle(particle.pdgCode()); - if (!pd) + if (!pd) { return false; - if (std::abs(pd->Charge()) == 0) + } + if (std::abs(pd->Charge()) == 0) { return false; - if (particle.pt() < cfgCutPtLower || particle.pt() > cfgCutPtUpper || std::abs(particle.eta()) > cfgCutEta) + } + if (particle.pt() < cfgCutPtLower || particle.pt() > cfgCutPtUpper || std::abs(particle.eta()) > cfgCutEta) { return false; - if (std::abs(particle.vz()) > cfgCutVertex) + } + if (std::abs(particle.vz()) > cfgVtxZCut) { return false; + } return true; } float getCentrality(const auto& col) const { - if (cfgCentralityChoice.value == kCentFT0C) + if (cfgCentralityChoice.value == kCentFT0C) { return col.centFT0C(); - if (cfgCentralityChoice.value == kCentFT0M) + } + if (cfgCentralityChoice.value == kCentFT0M) { return col.centFT0M(); - if (cfgCentralityChoice.value == kCentFDDM) + } + if (cfgCentralityChoice.value == kCentFDDM) { return col.centFDDM(); - if (cfgCentralityChoice.value == kCentFV0A) + } + if (cfgCentralityChoice.value == kCentFV0A) { return col.centFV0A(); + } return KinvalidCentrality; } - float getEfficiency(float mult, float pt, float eta, PIDIdx pidType, int effidx, bool cfgEff) const + // Inclusive efficiency/fake lookup (no species dependence). + float getEfficiency(float mult, float pt, float eta, int effidx, bool useEff) const { - if (!cfgEff) { + if (!useEff) { return (effidx == 0) ? 1.0f : 0.0f; } - TH3F* h = (effidx == 0) ? state.hEff[pidType] : state.hFake[pidType]; - - if (!h) + TH3F* h = (effidx == 0) ? state.hEff : state.hFake; + if (!h) { return -1; - + } int ibx = h->GetXaxis()->FindBin(mult); int iby = h->GetYaxis()->FindBin(pt); int ibz = h->GetZaxis()->FindBin(eta); float val = h->GetBinContent(ibx, iby, ibz); - - if (effidx == 0) + if (effidx == 0) { return (val > 0.f) ? val : 1.0f; + } return val; } - float getFlatteningWeight(float vz, float chg, float pt, float eta, float phi, PIDIdx pidType, bool cfgflat) const + float getFlatteningWeight(float vz, float chg, float pt, float eta, float phi, bool useFlat) const { - if (!cfgflat) + if (!useFlat) { return 1.0; - THnSparseF* h = state.hFlatWeight[pidType]; - - if (!h) + } + THnSparseF* h = state.hFlatWeight; + if (!h) { return 0.0; - int bins[5]; + } + std::array bins{}; bins[0] = h->GetAxis(0)->FindBin(vz); bins[1] = h->GetAxis(1)->FindBin(chg); bins[2] = h->GetAxis(2)->FindBin(pt); bins[3] = h->GetAxis(3)->FindBin(eta); bins[4] = h->GetAxis(4)->FindBin(phi); - float val = h->GetBinContent(bins); - - return val; + return h->GetBinContent(bins.data()); } std::vector* offsetFT0 = nullptr; @@ -719,8 +510,6 @@ struct RadialFlowDecorr { auto x = chPos.X() + (*offsetFT0)[i].getX(); auto y = chPos.Y() + (*offsetFT0)[i].getY(); auto z = chPos.Z() + (*offsetFT0)[i].getZ(); - // i == 0 is FT0A (A-side, positive Z) - // i == 1 is FT0C (C-side, negative Z) if (i == 1) { z = -std::abs(z); } else if (i == 0) { @@ -742,50 +531,57 @@ struct RadialFlowDecorr { return; } mLastTimestamp = timestamp; - LOGF(info, "Successfully loaded new alignment parameters for timestamp %llu", timestamp); - LOGF(info, "Offset for FT0A: x = %.3f y = %.3f z = %.3f\n", (*offsetFT0)[0].getX(), (*offsetFT0)[0].getY(), (*offsetFT0)[0].getZ()); - LOGF(info, "Offset for FT0C: x = %.3f y = %.3f z = %.3f\n", (*offsetFT0)[1].getX(), (*offsetFT0)[1].getY(), (*offsetFT0)[1].getZ()); + LOGF(info, "Loaded FT0 alignment for timestamp %llu", timestamp); } - template - std::pair calculateMeanAndC2FromSums(const double sumpmwk[KIntM][KIntK], const double sumwk[KIntK], float referenceMeanPt) const - { - if (sumwk[1] == 0.) { - return {0.f, 0.f}; - } - - double tau1 = sumwk[2] / (sumwk[1] * sumwk[1]); - double denom2 = 1. - tau1; - - if (std::abs(denom2) < KFloatEpsilon) { - double pmk11safe = sumpmwk[1][1] / sumwk[1]; - return {static_cast(pmk11safe), 0.f}; - } - - double pmk11 = sumpmwk[1][1] / sumwk[1]; - - double pmk12 = 0.f; - if (sumwk[2] != 0.f) { - pmk12 = sumpmwk[1][2] / sumwk[2]; - } - - double pmk22 = 0.f; - if (sumwk[2] != 0.f) { - pmk22 = sumpmwk[2][2] / sumwk[2]; - } - - float calculatedMeanPt = pmk11; - - double p1kBar1 = pmk11 - referenceMeanPt; - double p2kBar2 = pmk22 - 2.0f * pmk12 * referenceMeanPt + referenceMeanPt * referenceMeanPt; - - double p1kBar1sq = p1kBar1 * p1kBar1; - double numerator2 = p1kBar1sq - (tau1 * p2kBar2); + // Per-event two- and three-particle pT correlators (standard method) from the + // power sums, following arXiv:2112.03397, Eqs. 2-3. + struct C2C3Result { + double c2 = std::numeric_limits::quiet_NaN(); + double c3 = std::numeric_limits::quiet_NaN(); + }; - float twopcorr = numerator2 / denom2; - return {calculatedMeanPt, twopcorr}; + template + C2C3Result calculateC2C3FromSums(const std::array, M>& sumpmwk, const std::array& sumwk, float referenceMeanPt) const + { + C2C3Result r; + const double s1 = sumwk[1]; + if (s1 <= 0.) { + return r; + } + const double refpt = referenceMeanPt; + const double p11 = sumpmwk[1][1] / s1; + const double p1Bar1 = p11 - refpt; + + // --- c2: needs >=2 particles (D2 = 1 - tau1 > eps) --- + const double tau1 = sumwk[2] / (s1 * s1); + const double denom2 = 1. - tau1; + if (denom2 > KFloatEpsilon) { + const double p12 = sumpmwk[1][2] / sumwk[2]; + const double p22 = sumpmwk[2][2] / sumwk[2]; + const double p2Bar2 = p22 - 2.0 * p12 * refpt + refpt * refpt; + r.c2 = (p1Bar1 * p1Bar1 - tau1 * p2Bar2) / denom2; + } + + // --- c3: needs >=3 particles (D3 = 1 - 3 tau1 + 2 tau2 > eps) --- + const double tau2 = sumwk[3] / (s1 * s1 * s1); + const double denom3 = 1. - 3.0 * tau1 + 2.0 * tau2; + if (denom3 > KFloatEpsilon) { + const double p12 = sumpmwk[1][2] / sumwk[2]; + const double p22 = sumpmwk[2][2] / sumwk[2]; + const double p13 = sumpmwk[1][3] / sumwk[3]; + const double p23 = sumpmwk[2][3] / sumwk[3]; + const double p33 = sumpmwk[3][3] / sumwk[3]; + const double p2Bar2 = p22 - 2.0 * p12 * refpt + refpt * refpt; + const double p3Bar3 = p33 - 3.0 * p23 * refpt + 3.0 * p13 * refpt * refpt - refpt * refpt * refpt; + r.c3 = (p1Bar1 * p1Bar1 * p1Bar1 - 3.0 * tau1 * p2Bar2 * p1Bar1 + 2.0 * tau2 * p3Bar3) / denom3; + } + return r; } + // =========================================================================== + // Table joins + // =========================================================================== using GeneralCollisions = soa::Join; using UnfilteredTracks = soa::Join< - aod::Tracks, - aod::TracksExtra, - aod::TrackSelection, - aod::TracksDCA, - aod::pidTPCFullPi, aod::pidTPCFullKa, aod::pidTPCFullPr, aod::pidTPCFullEl, - aod::pidTOFFullPi, aod::pidTOFFullKa, aod::pidTOFFullPr, aod::pidTOFFullEl>; - Filter trackFilter = aod::track::pt > KPtMin&& - aod::track::pt < KPtMax&& - requireGlobalTrackInFilter(); + aod::Tracks, aod::TracksExtra, aod::TrackSelection, aod::TracksDCA>; + Filter trackFilter = aod::track::pt > KPtMin&& aod::track::pt < KPtMax&& requireGlobalTrackInFilter(); using AodTracksSel = soa::Filtered; using TCs = soa::Join; using FilteredTCs = soa::Filtered; @@ -816,6 +605,9 @@ struct RadialFlowDecorr { PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; + // =========================================================================== + // Histogram declarations + // =========================================================================== void declareCommonQA() { histos.add("hVtxZ_after_sel", ";z_{vtx} (cm)", kTH1F, {{KNbinsZvtx, KZvtxMin, KZvtxMax}}); @@ -823,7 +615,6 @@ struct RadialFlowDecorr { histos.add("hCentrality", ";centrality (%)", kTH1F, {{centAxis1Per}}); histos.add("Hist2D_globalTracks_PVTracks", ";N_{global};N_{PV}", kTH2F, {{nChAxis}, {nChAxis}}); histos.add("Hist2D_cent_nch", ";N_{PV};cent (%)", kTH2F, {{nChAxis}, {centAxis1Per}}); - histos.add("Hist2D_globalTracks_cent", "cent (%);N_{global}", kTH2F, {{centAxis1Per}, {nChAxis}}); histos.add("Hist2D_PVTracks_cent", "cent (%);N_{PV}", kTH2F, {{centAxis1Per}, {nChAxis}}); @@ -859,14 +650,11 @@ struct RadialFlowDecorr { void declareMCCommonHists() { - for (const auto& suf : pidSuffix) { - histos.add("h3_AllPrimary" + suf, ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, KPtMin, KPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - histos.add("h3_RecoMatchedToPrimary" + suf, ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, KPtMin, KPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - histos.add("h3_AllReco" + suf, ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, KPtMin, KPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - histos.add("h3_RecoUnMatchedToPrimary_Secondary" + suf, ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, KPtMin, KPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - histos.add("h3_RecoUnMatchedToPrimary_Fake" + suf, ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, KPtMin, KPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - histos.add("h3_RecoMatchedToPrimary_MisID" + suf, ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, KPtMin, KPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - } + histos.add("h3_AllPrimary", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, KPtMin, KPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + histos.add("h3_RecoMatchedToPrimary", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, KPtMin, KPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + histos.add("h3_AllReco", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, KPtMin, KPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + histos.add("h3_RecoUnMatchedToPrimary_Secondary", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, KPtMin, KPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); + histos.add("h3_RecoUnMatchedToPrimary_Fake", ";N_{PV};p_{T};#eta", kTH3F, {{nChAxis2}, {KNbinsPtRes, KPtMin, KPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); histos.add("ptResolution", ";p_{T}^{MC};(p_{T}^{reco}-p_{T}^{MC})/p_{T}^{MC}", kTH2F, {{KNbinsPtRes, KPtMin, KPtMax}, {100, -0.2, 0.2}}); histos.add("etaResolution", ";#eta^{MC};#eta^{reco}-#eta^{MC}", kTH2F, {{KNbinsEtaRes, -KEtaFineMax, KEtaFineMax}, {100, -0.02, 0.02}}); @@ -875,25 +663,11 @@ struct RadialFlowDecorr { histos.add("vzResolution", ";Vz^{MC};(Vz^{reco}-Vz^{MC})/Vz^{MC}", kTH2F, {{KNbinsVz, KVzMin, KVzMax}, {100, -0.1, 0.1}}); } - void declarenSigHists() - { - for (const auto& suf : pidSuffix) { - histos.add("h3DnsigmaTpcVsPtBefCut_Cent" + suf, "TPC nSigma vs pT Before Cut;cent [%]; p_{T} (GeV/c);n#sigma_{TPC}", kTH3F, {{centAxis1Per}, {KNbinsPtRes, KPtMin, KPtMax}, {200, -10.f, 10.f}}); - histos.add("h3DnsigmaTofVsPtBefCut_Cent" + suf, "TOF nSigma vs pT Before Cut;cent [%]; p_{T} (GeV/c);n#sigma_{TOF}", kTH3F, {{centAxis1Per}, {KNbinsPtRes, KPtMin, KPtMax}, {200, -10.f, 10.f}}); - histos.add("h3DnsigmaTpcVsTofBefCut_Cent" + suf, "TPC vs TOF nSigma Before Cut;cent [%]; n#sigma_{TOF};n#sigma_{TPC}", kTH3F, {{centAxis1Per}, {200, -10.f, 10.f}, {200, -10.f, 10.f}}); - histos.add("h3DnsigmaTpcVsPtAftCut_Cent" + suf, "TPC nSigma vs pT After Cut;cent [%],; p_{T} (GeV/c);n#sigma_{TPC}", kTH3F, {{centAxis1Per}, {KNbinsPtRes, KPtMin, KPtMax}, {200, -10.f, 10.f}}); - histos.add("h3DnsigmaTofVsPtAftCut_Cent" + suf, "TOF nSigma vs pT After Cut;cent [%],; p_{T} (GeV/c);n#sigma_{TOF}", kTH3F, {{centAxis1Per}, {KNbinsPtRes, KPtMin, KPtMax}, {200, -10.f, 10.f}}); - histos.add("h3DnsigmaTpcVsTofAftCut_Cent" + suf, "TPC vs TOF nSigma After Cut;cent [%],; n#sigma_{TOF};n#sigma_{TPC}", kTH3F, {{centAxis1Per}, {200, -10.f, 10.f}, {200, -10.f, 10.f}}); - } - } - void declareMCGetFlatHists() { - for (const auto& suf : pidSuffix) { - histos.add("MCGen/hEtaPhiReco" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); - histos.add("MCGen/hEtaPhiRecoEffWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); - histos.add("MCGen/hEtaPhiRecoWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); - } + histos.add("MCGen/hEtaPhiReco", ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaFlatAxis}, {phiAxis}}); + histos.add("MCGen/hEtaPhiRecoEffWtd", ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaFlatAxis}, {phiAxis}}); + histos.add("MCGen/hEtaPhiRecoWtd", ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaFlatAxis}, {phiAxis}}); } void declareMCMeanHists() @@ -902,12 +676,10 @@ struct RadialFlowDecorr { histos.add("Eff_Ntrk", ";N_{PV}", kTProfile, {nChAxis2}); histos.add("Eff_pT", ";p_{T}", kTProfile, {{KNbinsPtRes, KPtMin, KPtMax}}); histos.add("Eff_eta", ";#eta", kTProfile, {{KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - histos.add("Fake_cent", ";cent", kTProfile, {centAxis1Per}); histos.add("Fake_Ntrk", ";N_{PV}", kTProfile, {nChAxis2}); histos.add("Fake_pT", ";p_{T}", kTProfile, {{KNbinsPtRes, KPtMin, KPtMax}}); histos.add("Fake_eta", ";#eta", kTProfile, {{KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}}); - histos.add("wgt_cent", ";cent", kTProfile, {centAxis1Per}); histos.add("wgt_Ntrk", ";N_{PV}", kTProfile, {nChAxis2}); histos.add("wgt_pT", ";p_{T}", kTProfile, {{KNbinsPtRes, KPtMin, KPtMax}}); @@ -920,71 +692,71 @@ struct RadialFlowDecorr { histos.add("pmean_cent_id_eta_FT0", ";cent;id;#eta", kTProfile3D, {{centAxis1Per}, {200, -0.5, 199.5}, {100, -5.0, 5.0}}); histos.add("h3_cent_id_eta_FT0", ";cent;id;#eta", kTH3F, {{centAxis1Per}, {200, -0.5, 199.5}, {100, -5.0, 5.0}}); - histos.add("MCGen/Prof_Cent_Nsp_Nchrec", ";cent;isp", kTProfile2D, {{centAxis1Per}, {spBinAxis}}); - histos.add("MCGen/Prof_Mult_Nsp_Nchrec", ";mult;isp", kTProfile2D, {{nChAxis}, {spBinAxis}}); - histos.add("MCGen/Prof_Cent_Nsp_MeanpT", ";cent;isp", kTProfile2D, {{centAxis1Per}, {spBinAxis}}); - histos.add("MCGen/Prof_Mult_Nsp_MeanpT", ";mult;isp", kTProfile2D, {{nChAxis}, {spBinAxis}}); - - histos.add("pmeanTru_nch_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); - histos.add("pmeanReco_nch_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); - histos.add("pmeanRecoEffcorr_nch_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); - - histos.add("pmeanMultTru_nch_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); - histos.add("pmeanMultReco_nch_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); - histos.add("pmeanMultRecoEffcorr_nch_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); - - for (const auto& suf : pidSuffix) { - histos.add("hEtaPhiReco" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); - histos.add("hEtaPhiRecoEffWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); - histos.add("hEtaPhiRecoWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); - - histos.add("Prof2D_MeanpTSub_Tru" + suf, ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {etaBinAxis}}); - histos.add("Prof2D_MeanpTSub_Reco" + suf, ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {etaBinAxis}}); - histos.add("Prof2D_MeanpTSub_RecoEffCorr" + suf, ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {etaBinAxis}}); - } + histos.add("MCGen/Prof_Cent_Nchrec", ";cent;#LT N#GT", kTProfile, {centAxis1Per}); + histos.add("MCGen/Prof_Mult_Nchrec", ";mult;#LT N#GT", kTProfile, {nChAxis}); + histos.add("MCGen/Prof_Cent_MeanpT", ";cent;#LT p_{T}#GT", kTProfile, {centAxis1Per}); + histos.add("MCGen/Prof_Mult_MeanpT", ";mult;#LT p_{T}#GT", kTProfile, {nChAxis}); + + histos.add("pmeanTru_nch_etabin", ";mult;eta", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + histos.add("pmeanReco_nch_etabin", ";mult;eta", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + histos.add("pmeanRecoEffcorr_nch_etabin", ";mult;eta", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + histos.add("pmeanMultTru_nch_etabin", ";mult;eta", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + histos.add("pmeanMultReco_nch_etabin", ";mult;eta", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + histos.add("pmeanMultRecoEffcorr_nch_etabin", ";mult;eta", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + + histos.add("MCGen/hEtaPhiReco", ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaFlatAxis}, {phiAxis}}); + histos.add("MCGen/hEtaPhiRecoEffWtd", ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaFlatAxis}, {phiAxis}}); + histos.add("MCGen/hEtaPhiRecoWtd", ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaFlatAxis}, {phiAxis}}); + + histos.add("Prof2D_MeanpTSub_Tru", ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {etaBinAxis}}); + histos.add("Prof2D_MeanpTSub_Reco", ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {etaBinAxis}}); + histos.add("Prof2D_MeanpTSub_RecoEffCorr", ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {etaBinAxis}}); } void declareMCFlucHists() { - histos.add("MCGen/Prof_Cent_NEta_Nsp_Nchrec", ";cent;eta;isp", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {spBinAxis}}); - histos.add("MCGen/Prof_Mult_NEta_Nsp_Nchrec", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); - histos.add("MCGen/Prof_Cent_NEta_Nsp_MeanpT", ";cent;eta;isp", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {spBinAxis}}); - histos.add("MCGen/Prof_Mult_NEta_Nsp_MeanpT", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); - - histos.add("MCGen/Prof_MeanpT_Cent_etabin_spbin", ";cent;eta;isp", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {spBinAxis}}); - histos.add("MCGen/Prof_C2_Cent_etabin_spbin", ";cent;eta;isp", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {spBinAxis}}); - histos.add("MCGen/Prof_C2Sub_Cent_etabin_spbin", ";cent;eta;isp", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {spBinAxis}}); - histos.add("MCGen/Prof_Cov_Cent_etabin_spbin", ";cent;eta;isp", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {spBinAxis}}); - histos.add("MCGen/Prof_CovFT0A_Cent_etabin_spbin", ";cent;eta;isp", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {spBinAxis}}); - histos.add("MCGen/Prof_CovFT0C_Cent_etabin_spbin", ";cent;eta;isp", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {spBinAxis}}); - - histos.add("MCGen/Prof_MeanpT_Mult_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); - histos.add("MCGen/Prof_C2_Mult_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); - histos.add("MCGen/Prof_C2Sub_Mult_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); - histos.add("MCGen/Prof_Cov_Mult_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); - histos.add("MCGen/Prof_CovFT0A_Mult_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); - histos.add("MCGen/Prof_CovFT0C_Mult_etabin_spbin", ";mult;eta;isp", kTProfile3D, {{nChAxis}, {etaBinAxis}, {spBinAxis}}); - - for (const auto& suf : pidSuffix) { - histos.add("hEtaPhiReco" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); - histos.add("hEtaPhiRecoEffWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); - histos.add("hEtaPhiRecoWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); - - histos.add(Form("MCGen/Prof_C2Sub2D_Cent_etaA_etaC%s", suf.c_str()), ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); - histos.add(Form("MCGen/Prof_GapSum2D%s", suf.c_str()), ";cent;gap;sum", kTProfile3D, {{centAxis1Per}, {gapAxis}, {sumAxis}}); - histos.add(Form("MCGen/Prof_Cov2D_Cent_etaA_etaC%s", suf.c_str()), ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); - histos.add(Form("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC%s", suf.c_str()), ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); - histos.add(Form("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC%s", suf.c_str()), ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); - } + histos.add("MCGen/Prof_Cent_NEta_Nchrec", ";cent;eta", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + histos.add("MCGen/Prof_Mult_NEta_Nchrec", ";mult;eta", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + histos.add("MCGen/Prof_Cent_NEta_MeanpT", ";cent;eta", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + histos.add("MCGen/Prof_Mult_NEta_MeanpT", ";mult;eta", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + + histos.add("MCGen/Prof_MeanpT_Cent_etabin", ";cent;eta", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + histos.add("MCGen/Prof_C2_Cent_etabin", ";cent;eta", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + histos.add("MCGen/Prof_C2Sub_Cent_etabin", ";cent;eta", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + histos.add("MCGen/Prof_Cov_Cent_etabin", ";cent;eta", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + histos.add("MCGen/Prof_CovFT0A_Cent_etabin", ";cent;eta", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + histos.add("MCGen/Prof_CovFT0C_Cent_etabin", ";cent;eta", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + + histos.add("MCGen/Prof_MeanpT_Mult_etabin", ";mult;eta", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + histos.add("MCGen/Prof_C2_Mult_etabin", ";mult;eta", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + histos.add("MCGen/Prof_C2Sub_Mult_etabin", ";mult;eta", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + histos.add("MCGen/Prof_Cov_Mult_etabin", ";mult;eta", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + histos.add("MCGen/Prof_CovFT0A_Mult_etabin", ";mult;eta", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + histos.add("MCGen/Prof_CovFT0C_Mult_etabin", ";mult;eta", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + + histos.add("MCGen/Prof_C3_Cent_etabin", ";cent;eta", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + histos.add("MCGen/Prof_C3_Mult_etabin", ";mult;eta", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + histos.add("MCGen/Prof_C3Sub_Cent_etabin", ";cent;eta", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + histos.add("MCGen/Prof_C3Sub_Mult_etabin", ";mult;eta", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + + histos.add("MCGen/hEtaPhiReco", ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaFlatAxis}, {phiAxis}}); + histos.add("MCGen/hEtaPhiRecoEffWtd", ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaFlatAxis}, {phiAxis}}); + histos.add("MCGen/hEtaPhiRecoWtd", ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaFlatAxis}, {phiAxis}}); + + histos.add("MCGen/Prof_C2Sub2D_Cent_etaA_etaC", ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + histos.add("MCGen/Prof_GapSum2D", ";cent;gap;sum", kTProfile3D, {{centAxis1Per}, {gapAxis}, {sumAxis}}); + histos.add("MCGen/Prof_C3Sub2D_Cent_etaA_etaC", ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + histos.add("MCGen/Prof_C3GapSum2D", ";cent;gap;sum", kTProfile3D, {{centAxis1Per}, {gapAxis}, {sumAxis}}); + histos.add("MCGen/Prof_Cov2D_Cent_etaA_etaC", ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + histos.add("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC", ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + histos.add("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC", ";cent;etaA;etaC", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); } void declareDataGetFlatHists() { - for (const auto& suf : pidSuffix) { - histos.add("hEtaPhiReco" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); - histos.add("hEtaPhiRecoEffWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); - histos.add("hEtaPhiRecoWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); - } + histos.add("hEtaPhiReco", ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaFlatAxis}, {phiAxis}}); + histos.add("hEtaPhiRecoEffWtd", ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaFlatAxis}, {phiAxis}}); + histos.add("hEtaPhiRecoWtd", ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaFlatAxis}, {phiAxis}}); histos.add("hnTrkPVZDC", ";N_{PV};ZDC_{A+C}", kTH2F, {{nChAxis2}, {200, 0, 3000}}); histos.add("hNchZDC", ";N_{trk};ZDC_{A+C}", kTH2F, {{nChAxis2}, {200, 0, 30000}}); } @@ -993,76 +765,123 @@ struct RadialFlowDecorr { { histos.add("pmeanFT0Amultpv", "N_{PV}; AmplitudeA", kTProfile, {nChAxis}); histos.add("pmeanFT0A_cent", "cent; AmplitudeA", kTProfile, {centAxis1Per}); - histos.add("pmeanFT0Cmultpv", "N_{PV}; AmplitudeA", kTProfile, {nChAxis}); - histos.add("pmeanFT0C_cent", "cent; AmplitudeA", kTProfile, {centAxis1Per}); + histos.add("pmeanFT0Cmultpv", "N_{PV}; AmplitudeC", kTProfile, {nChAxis}); + histos.add("pmeanFT0C_cent", "cent; AmplitudeC", kTProfile, {centAxis1Per}); histos.add("pmean_cent_id_eta_FT0", ";cent;channel id; #eta;amplitude", kTProfile3D, {{centAxis1Per}, {200, -0.5, 199.5}, {100, -5.0, 5.0}}); histos.add("h3_cent_id_eta_FT0", ";cent;channel id; #eta", kTH3F, {{centAxis1Per}, {200, -0.5, 199.5}, {100, -5.0, 5.0}}); - histos.add("Prof_Cent_Nsp_Nchrec", ";cent;Species;#LT N_{PV}#GT", kTProfile2D, {{centAxis1Per}, {spBinAxis}}); - histos.add("Prof_Mult_Nsp_Nchrec", ";N_{PV};Species;#LT N_{PV}#GT", kTProfile2D, {{nChAxis}, {spBinAxis}}); - histos.add("Prof_Cent_Nsp_MeanpT", ";cent;Species;#LT p_{T}#GT", kTProfile2D, {{centAxis1Per}, {spBinAxis}}); - histos.add("Prof_Mult_Nsp_MeanpT", ";N_{PV};Species;#LT p_{T}#GT", kTProfile2D, {{nChAxis}, {spBinAxis}}); + histos.add("Prof_Cent_Nchrec", ";cent;#LT N_{PV}#GT", kTProfile, {centAxis1Per}); + histos.add("Prof_Mult_Nchrec", ";N_{PV};#LT N_{PV}#GT", kTProfile, {nChAxis}); + histos.add("Prof_Cent_MeanpT", ";cent;#LT p_{T}#GT", kTProfile, {centAxis1Per}); + histos.add("Prof_Mult_MeanpT", ";N_{PV};#LT p_{T}#GT", kTProfile, {nChAxis}); - histos.add("pmean_nch_etabin_spbin", ";N_{PV};#eta-bin;Species", kTProfile3D, {{nChAxis}, {{etaBinAxis}}, {spBinAxis}}); - histos.add("pmeanMult_nch_etabin_spbin", ";N_{PV};#eta-bin;Species", kTProfile3D, {{nChAxis}, {{etaBinAxis}}, {spBinAxis}}); - histos.add("pmean_cent_etabin_spbin", ";Centrality (%) ;#eta-bin;Species", kTProfile3D, {{centAxis1Per}, {{etaBinAxis}}, {spBinAxis}}); - histos.add("pmeanMult_cent_etabin_spbin", ";Centrality (%) ;#eta-bin;Species", kTProfile3D, {{centAxis1Per}, {{etaBinAxis}}, {spBinAxis}}); + histos.add("pmean_nch_etabin", ";N_{PV};#eta-bin", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + histos.add("pmeanMult_nch_etabin", ";N_{PV};#eta-bin", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + histos.add("pmean_cent_etabin", ";Centrality (%);#eta-bin", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + histos.add("pmeanMult_cent_etabin", ";Centrality (%);#eta-bin", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); - for (const auto& suf : pidSuffix) { - histos.add("hEtaPhiReco" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); - histos.add("hEtaPhiRecoEffWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); - histos.add("hEtaPhiRecoWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); + histos.add("hEtaPhiReco", ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaFlatAxis}, {phiAxis}}); + histos.add("hEtaPhiRecoEffWtd", ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaFlatAxis}, {phiAxis}}); + histos.add("hEtaPhiRecoWtd", ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaFlatAxis}, {phiAxis}}); - histos.add("Prof2D_MeanpTSub" + suf, ";cent;#eta_{A} bin;#eta_{C} bin", kTProfile3D, {{centAxis1Per}, {{etaBinAxis}}, {{etaBinAxis}}}); - } + histos.add("Prof2D_MeanpTSub", ";cent;#eta_{A} bin;#eta_{C} bin", kTProfile3D, {{centAxis1Per}, {etaBinAxis}, {etaBinAxis}}); + + histos.add("pEffWeight_pt_eta_cent", ";p_{T} (GeV/c);#eta;cent;#LT eff#GT", kTProfile3D, {{KNbinsPtRes, KPtMin, KPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}, {centAxis1Per}}); + histos.add("pFakeWeight_pt_eta_cent", ";p_{T} (GeV/c);#eta;cent;#LT fake#GT", kTProfile3D, {{KNbinsPtRes, KPtMin, KPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}, {centAxis1Per}}); + histos.add("pFlatWeight_pt_eta_cent", ";p_{T} (GeV/c);#eta;cent;#LT w_{#phi}#GT", kTProfile3D, {{KNbinsPtRes, KPtMin, KPtMax}, {KNbinsEtaFine, -KEtaFineMax, KEtaFineMax}, {centAxis1Per}}); } void declareDataFlucHists() { - histos.add("Prof_MeanpT_Cent_etabin_spbin", ";cent;#eta-bin;Species", kTProfile3D, {{centAxis1Per}, {{etaBinAxis}}, {spBinAxis}}); - histos.add("Prof_MeanpT_Mult_etabin_spbin", ";N_{PV};#eta-bin;Species", kTProfile3D, {{nChAxis}, {{etaBinAxis}}, {spBinAxis}}); - histos.add("Prof_C2_Cent_etabin_spbin", ";cent;#eta-bin;Species", kTProfile3D, {{centAxis1Per}, {{etaBinAxis}}, {spBinAxis}}); - histos.add("Prof_C2_Mult_etabin_spbin", ";N_{PV};#eta-bin;Species", kTProfile3D, {{nChAxis}, {{etaBinAxis}}, {spBinAxis}}); - - histos.add("Prof_C2Sub_Cent_etabin_spbin", ";Centrality;#eta-bin;Species", kTProfile3D, {{centAxis1Per}, {{etaBinAxis}}, {spBinAxis}}); - histos.add("Prof_C2Sub_Mult_etabin_spbin", ";N_{PV};#eta-bin;Species", kTProfile3D, {{nChAxis}, {{etaBinAxis}}, {spBinAxis}}); - histos.add("Prof_Cov_Cent_etabin_spbin", ";Centrality;#eta-bin;Species", kTProfile3D, {{centAxis1Per}, {{etaBinAxis}}, {spBinAxis}}); - histos.add("Prof_Cov_Mult_etabin_spbin", ";N_{PV};#eta-bin;Species", kTProfile3D, {{nChAxis}, {{etaBinAxis}}, {spBinAxis}}); - - histos.add("Prof_CovFT0A_Cent_etabin_spbin", ";Centrality;#eta-bin;Species", kTProfile3D, {{centAxis1Per}, {{etaBinAxis}}, {spBinAxis}}); - histos.add("Prof_CovFT0A_Mult_etabin_spbin", ";N_{PV};#eta-bin;Species", kTProfile3D, {{nChAxis}, {{etaBinAxis}}, {spBinAxis}}); - histos.add("Prof_CovFT0C_Cent_etabin_spbin", ";Centrality;#eta-bin;Species", kTProfile3D, {{centAxis1Per}, {{etaBinAxis}}, {spBinAxis}}); - histos.add("Prof_CovFT0C_Mult_etabin_spbin", ";N_{PV};#eta-bin;Species", kTProfile3D, {{nChAxis}, {{etaBinAxis}}, {spBinAxis}}); - - for (const auto& suf : pidSuffix) { - histos.add("hEtaPhiReco" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); - histos.add("hEtaPhiRecoEffWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); - histos.add("hEtaPhiRecoWtd" + suf, ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaAxis}, {phiAxis}}); - histos.add("Prof_C2Sub2D_Cent_etaA_etaC" + suf, ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); - histos.add("Prof_GapSum2D" + suf, ";cent;#Delta#eta (Gap);#Sigma#eta/2 (Sum)", kTProfile3D, {{centAxis1Per}, {gapAxis}, {sumAxis}}); - histos.add("Prof_Cov2D_Cent_etaA_etaC" + suf, ";cent;#eta_{A} bin;#eta_{C} bin", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); - histos.add("Prof_CovFT0A2D_Cent_etaA_etaC" + suf, ";cent;#eta_{A};#eta_{B}", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); - histos.add("Prof_CovFT0C2D_Cent_etaA_etaC" + suf, ";cent;#eta_{A};#eta_{B}", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + histos.add("Prof_MeanpT_Cent_etabin", ";cent;#eta-bin", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + histos.add("Prof_MeanpT_Mult_etabin", ";N_{PV};#eta-bin", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + histos.add("Prof_C2_Cent_etabin", ";cent;#eta-bin", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + histos.add("Prof_C2_Mult_etabin", ";N_{PV};#eta-bin", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + histos.add("Prof_C2Sub_Cent_etabin", ";Centrality;#eta-bin", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + histos.add("Prof_C2Sub_Mult_etabin", ";N_{PV};#eta-bin", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + histos.add("Prof_Cov_Cent_etabin", ";Centrality;#eta-bin", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + histos.add("Prof_Cov_Mult_etabin", ";N_{PV};#eta-bin", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + histos.add("Prof_CovFT0A_Cent_etabin", ";Centrality;#eta-bin", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + histos.add("Prof_CovFT0A_Mult_etabin", ";N_{PV};#eta-bin", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + histos.add("Prof_CovFT0C_Cent_etabin", ";Centrality;#eta-bin", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + histos.add("Prof_CovFT0C_Mult_etabin", ";N_{PV};#eta-bin", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + + histos.add("Prof_C3_Cent_etabin", ";cent;#eta-bin", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + histos.add("Prof_C3_Mult_etabin", ";N_{PV};#eta-bin", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + histos.add("Prof_C3Sub_Cent_etabin", ";Centrality;#eta-bin", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + histos.add("Prof_C3Sub_Mult_etabin", ";N_{PV};#eta-bin", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + + histos.add("hEtaPhiReco", ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaFlatAxis}, {phiAxis}}); + histos.add("hEtaPhiRecoEffWtd", ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaFlatAxis}, {phiAxis}}); + histos.add("hEtaPhiRecoWtd", ";vz;sign;pt;eta;phi", kTHnSparseF, {{vzAxis}, {chgAxis}, {pTAxis}, {etaFlatAxis}, {phiAxis}}); + + histos.add("Prof_C2Sub2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + histos.add("Prof_GapSum2D", ";cent;#Delta#eta (Gap);#Sigma#eta/2 (Sum)", kTProfile3D, {{centAxis1Per}, {gapAxis}, {sumAxis}}); + histos.add("Prof_C3Sub2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + histos.add("Prof_C3GapSum2D", ";cent;#Delta#eta (Gap);#Sigma#eta/2 (Sum)", kTProfile3D, {{centAxis1Per}, {gapAxis}, {sumAxis}}); + histos.add("Prof_Cov2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + histos.add("Prof_CovFT0A2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + histos.add("Prof_CovFT0C2D_Cent_etaA_etaC", ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + } + + // 30 Poisson-bootstrap replicas of every final fluctuation observable + // (base data run only). Filled by pointer to bypass the compile-time HIST() + // macro, which cannot take a runtime sample index. + void declareBootstrapHists() + { + for (int s = 0; s < nBoot; ++s) { + bs.multCent[s] = histos.add(Form("Bootstrap/Prof_Mult_Cent_etabin_sample%d", s), ";cent;#eta-bin", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + bs.multMult[s] = histos.add(Form("Bootstrap/Prof_Mult_Mult_etabin_sample%d", s), ";N_{PV};#eta-bin", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + bs.amplFT0ACent[s] = histos.add(Form("Bootstrap/Prof_AmplFT0A_Cent_sample%d", s), ";cent;AmplitudeA", kTProfile, {centAxis1Per}); + bs.amplFT0AMult[s] = histos.add(Form("Bootstrap/Prof_AmplFT0A_Mult_sample%d", s), ";N_{PV};AmplitudeA", kTProfile, {nChAxis}); + bs.amplFT0CCent[s] = histos.add(Form("Bootstrap/Prof_AmplFT0C_Cent_sample%d", s), ";cent;AmplitudeC", kTProfile, {centAxis1Per}); + bs.amplFT0CMult[s] = histos.add(Form("Bootstrap/Prof_AmplFT0C_Mult_sample%d", s), ";N_{PV};AmplitudeC", kTProfile, {nChAxis}); + bs.meanpTCent[s] = histos.add(Form("Bootstrap/Prof_MeanpT_Cent_etabin_sample%d", s), ";cent;#eta-bin", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + bs.meanpTMult[s] = histos.add(Form("Bootstrap/Prof_MeanpT_Mult_etabin_sample%d", s), ";N_{PV};#eta-bin", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + bs.c2Cent[s] = histos.add(Form("Bootstrap/Prof_C2_Cent_etabin_sample%d", s), ";cent;#eta-bin", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + bs.c2Mult[s] = histos.add(Form("Bootstrap/Prof_C2_Mult_etabin_sample%d", s), ";N_{PV};#eta-bin", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + bs.c2SubCent[s] = histos.add(Form("Bootstrap/Prof_C2Sub_Cent_etabin_sample%d", s), ";cent;#eta-bin", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + bs.c2SubMult[s] = histos.add(Form("Bootstrap/Prof_C2Sub_Mult_etabin_sample%d", s), ";N_{PV};#eta-bin", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + bs.c3Cent[s] = histos.add(Form("Bootstrap/Prof_C3_Cent_etabin_sample%d", s), ";cent;#eta-bin", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + bs.c3Mult[s] = histos.add(Form("Bootstrap/Prof_C3_Mult_etabin_sample%d", s), ";N_{PV};#eta-bin", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + bs.c3SubCent[s] = histos.add(Form("Bootstrap/Prof_C3Sub_Cent_etabin_sample%d", s), ";cent;#eta-bin", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + bs.c3SubMult[s] = histos.add(Form("Bootstrap/Prof_C3Sub_Mult_etabin_sample%d", s), ";N_{PV};#eta-bin", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + bs.covCent[s] = histos.add(Form("Bootstrap/Prof_Cov_Cent_etabin_sample%d", s), ";cent;#eta-bin", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + bs.covMult[s] = histos.add(Form("Bootstrap/Prof_Cov_Mult_etabin_sample%d", s), ";N_{PV};#eta-bin", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + bs.covFT0ACent[s] = histos.add(Form("Bootstrap/Prof_CovFT0A_Cent_etabin_sample%d", s), ";cent;#eta-bin", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + bs.covFT0AMult[s] = histos.add(Form("Bootstrap/Prof_CovFT0A_Mult_etabin_sample%d", s), ";N_{PV};#eta-bin", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + bs.covFT0CCent[s] = histos.add(Form("Bootstrap/Prof_CovFT0C_Cent_etabin_sample%d", s), ";cent;#eta-bin", kTProfile2D, {{centAxis1Per}, {etaBinAxis}}); + bs.covFT0CMult[s] = histos.add(Form("Bootstrap/Prof_CovFT0C_Mult_etabin_sample%d", s), ";N_{PV};#eta-bin", kTProfile2D, {{nChAxis}, {etaBinAxis}}); + bs.c2Sub2D[s] = histos.add(Form("Bootstrap/Prof_C2Sub2D_Cent_etaA_etaC_sample%d", s), ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + bs.gapSum2D[s] = histos.add(Form("Bootstrap/Prof_GapSum2D_sample%d", s), ";cent;gap;sum", kTProfile3D, {{centAxis1Per}, {gapAxis}, {sumAxis}}); + bs.c3Sub2D[s] = histos.add(Form("Bootstrap/Prof_C3Sub2D_Cent_etaA_etaC_sample%d", s), ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + bs.c3GapSum2D[s] = histos.add(Form("Bootstrap/Prof_C3GapSum2D_sample%d", s), ";cent;gap;sum", kTProfile3D, {{centAxis1Per}, {gapAxis}, {sumAxis}}); + bs.cov2D[s] = histos.add(Form("Bootstrap/Prof_Cov2D_Cent_etaA_etaC_sample%d", s), ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + bs.covFT0A2D[s] = histos.add(Form("Bootstrap/Prof_CovFT0A2D_Cent_etaA_etaC_sample%d", s), ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); + bs.covFT0C2D[s] = histos.add(Form("Bootstrap/Prof_CovFT0C2D_Cent_etaA_etaC_sample%d", s), ";cent;#eta_{A};#eta_{C}", kTProfile3D, {{centAxis1Per}, {etaAxis}, {etaAxis}}); } } + // =========================================================================== + // CCDB helpers + // =========================================================================== THnSparseF* buildWeightMapFromRaw(THnSparseF* hRaw, const char* mapName) { if (!hRaw) { LOGF(error, "Raw eta-phi map for '%s' is null; no flattening will be applied.", mapName); return nullptr; } - auto hWMap = reinterpret_cast(hRaw->Clone(mapName)); + auto hWMap = dynamic_cast(hRaw->Clone(mapName)); hWMap->SetTitle(Form("Flattening Weight Map %s (w_{#phi} = / N_{#phi})", mapName)); hWMap->Reset(); - auto axV = hRaw->GetAxis(0); // Vz - auto axChg = hRaw->GetAxis(1); // Charge - auto axPt = hRaw->GetAxis(2); // Pt - auto axE = hRaw->GetAxis(3); // Eta - auto axP = hRaw->GetAxis(4); // Phi + auto axV = hRaw->GetAxis(0); + auto axChg = hRaw->GetAxis(1); + auto axPt = hRaw->GetAxis(2); + auto axE = hRaw->GetAxis(3); + auto axP = hRaw->GetAxis(4); - int bins[5]; + std::array bins{}; for (int iv = 1; iv <= axV->GetNbins(); ++iv) { bins[0] = iv; for (int ichg = 1; ichg <= axChg->GetNbins(); ++ichg) { @@ -1075,47 +894,50 @@ struct RadialFlowDecorr { int nphi = axP->GetNbins(); for (int ip = 1; ip <= nphi; ++ip) { bins[4] = ip; - sum += hRaw->GetBinContent(bins); + sum += hRaw->GetBinContent(bins.data()); } const double avg = (nphi > 0 ? sum / nphi : 0.0); for (int ip = 1; ip <= nphi; ++ip) { bins[4] = ip; - const double raw = hRaw->GetBinContent(bins); + const double raw = hRaw->GetBinContent(bins.data()); const double w = (avg > 0.0 && raw > 0.0) ? (avg / raw) : 1.0; - hWMap->SetBinContent(bins, w); + hWMap->SetBinContent(bins.data(), w); } } } } } - LOGF(info, "Flattening weight map '%s' built.", mapName); return hWMap; } - inline void loadTProfile3D(TDirectory* dir, const char* name, TProfile3D*& target) + template + void loadProfileFromList(TList* src, const char* name, TP*& target) { - if (!dir) { - LOGF(error, "loadTProfile3D: directory is null for object %s", name); + if (!src) { return; } - auto* obj = dir->Get(name); + auto* obj = src->FindObject(name); if (!obj) { - LOGF(error, "loadTProfile3D: object '%s' not found in directory %s", name, dir->GetName()); + LOGF(error, "Profile %s missing in CCDB TList", name); return; } - auto* prof = dynamic_cast(obj); - if (!prof) { - LOGF(error, "loadTProfile3D: object '%s' is not a TProfile3D (it is %s)", name, obj->ClassName()); + auto* tp = dynamic_cast(obj); + if (!tp) { + LOGF(error, "%s is not the expected profile type (it is %s)", name, obj->ClassName()); return; } - target = reinterpret_cast(prof->Clone(Form("%s_clone", name))); + target = dynamic_cast(tp->Clone()); target->SetDirectory(nullptr); - LOGF(info, "Loaded TProfile3D '%s' with entries = %.0f", name, target->GetEntries()); + LOGF(info, "Loaded %s from list", name); } + // =========================================================================== + // init + // =========================================================================== void init(InitContext&) { + // Nch axes by system if (cfgSys == kPbPb) { nChAxis = {cfgNchPbMax / 2, KBinOffset, cfgNchPbMax + KBinOffset, "Nch", "PV-contributor track multiplicity"}; nChAxis2 = {cfgNchPbMax / 4, KBinOffset, cfgNchPbMax + KBinOffset, "Nch", "PV-contributor track multiplicity"}; @@ -1124,6 +946,69 @@ struct RadialFlowDecorr { nChAxis2 = {cfgNchOMax, KBinOffset, cfgNchOMax + KBinOffset, "Nch", "PV-contributor track multiplicity"}; } + // ---- run type: MC is pinned to the reference binning, DATA is configurable ---- + // cfgEtaBinWidth exists only to vary the DATA measurement. MC (efficiency, + // closure) always uses 0.2-wide bins so its mean and fluctuation passes stay + // mutually consistent and reproducible. + const bool isMcRun = (cfgRunGetEff || cfgRunGetMCFlat || cfgRunMCMean || cfgRunMCFluc); + const bool isDataRun = (cfgRunGetDataFlat || cfgRunDataMean || cfgRunDataFluc); + if (isMcRun && isDataRun) { + LOGF(fatal, + "MC and DATA process switches are both enabled in one job: MC binning is " + "pinned to 0.2 while DATA uses cfgEtaBinWidth. Run them as separate jobs."); + } + const float mcEtaBinWidth = 0.2f; + const float effEtaBinWidth = isMcRun ? mcEtaBinWidth : static_cast(cfgEtaBinWidth); + + // ---- observable eta binning (width = effEtaBinWidth) -------------------------- + { + const float halfEta = cfgCutEta; + const float width = effEtaBinWidth; + if (width <= 0.f) { + LOGF(fatal, "eta bin width must be > 0 (got %.3f)", width); + } + const int nHalf = static_cast(std::lround(halfEta / width)); + if (nHalf < 1 || std::abs(nHalf * width - halfEta) > KEtaEdgeTolerance) { + LOGF(fatal, + "cfgCutEta=%.3f is not an integer multiple of the eta bin width=%.3f; " + "eta=0 must be a bin edge for mirror pairing.", + halfEta, width); + } + const int nbins = 2 * nHalf; // even -> symmetric about eta = 0 + const float lo = -halfEta; + const float hi = halfEta; + + etaLw.clear(); + etaUp.clear(); + etaLw.push_back(lo); // index 0: full-range reference bin + etaUp.push_back(hi); + for (int i = 0; i < nbins; ++i) { + etaLw.push_back(lo + i * width); + etaUp.push_back(lo + (i + 1) * width); + } + nEta = nbins + 1; + if (nEta > KNEtaMax) { + LOGF(fatal, "nEta=%d exceeds KNEtaMax=%d (raise the cap or widen the eta bin width)", nEta, KNEtaMax); + } + + std::vector obsEdges; + obsEdges.reserve(nEta); + obsEdges.push_back(etaLw[1]); + for (int i = 1; i < nEta; ++i) { + obsEdges.push_back(etaUp[i]); + } + etaAxis = AxisSpec{obsEdges, "#eta"}; + etaBinAxis = AxisSpec{nEta + 1, -0.5, static_cast(nEta) + 0.5, "#eta bin Number"}; + LOGF(info, "Observable eta binning (%s): %d bins of width %.2f over |eta|<%.2f (+ reference), nEta=%d", + isMcRun ? "MC pinned" : "DATA", nbins, width, halfEta, nEta); + } + + // bootstrap active only for the base data fluctuation pass + doBoot = cfgRunDataFluc && (cfgSystType == kSystBase) && (cfgNBootstrap > 0); + nBoot = std::min(cfgNBootstrap, KMaxBoot); + rng.SetSeed(cfgBootstrapSeed); + + // ---- CCDB ---- ccdb->setURL(cfgCCDBurl.value); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); @@ -1133,7 +1018,7 @@ struct RadialFlowDecorr { loadAlignParam(now); ft0Det.calculateChannelCenter(); - std::string sysDir = ""; + std::string sysDir; switch (cfgSys) { case kPbPb: sysDir = "PbPbTest"; @@ -1150,20 +1035,14 @@ struct RadialFlowDecorr { default: LOGF(fatal, "Invalid cfgSys value: %d", cfgSys.value); } - std::string pathNsig = cfgCCDBUserPath.value + "/" + sysDir + "/Job0_nSigMaps"; std::string pathEff = cfgCCDBUserPath.value + "/" + sysDir + "/Job1_EffMaps"; std::string pathMCFlat = cfgCCDBUserPath.value + "/" + sysDir + "/Job1_MCFlatMaps"; std::string pathMCMean = cfgCCDBUserPath.value + "/" + sysDir + "/Job2_MCMean"; - - std::string pathDataNsig = cfgCCDBUserPath.value + "/" + sysDir + "/Job0_DatanSigMaps"; std::string pathDataFlat = cfgCCDBUserPath.value + "/" + sysDir + "/Job1_DataFlatMaps"; std::string pathDataMean = cfgCCDBUserPath.value + "/" + sysDir + "/Job2_DataMean"; + // ---- declarations ---- declareCommonQA(); - if (cfgRunMCGetNSig || cfgRunGetEff || cfgRunDataGetNSig || cfgRunGetDataFlat) { - declarenSigHists(); - } - if (cfgRunMCMean || cfgRunMCFluc || cfgRunGetEff) { declareMCCommonHists(); } @@ -1182,9 +1061,6 @@ struct RadialFlowDecorr { histos.addClone("MCGen/", "MCReco/"); histos.addClone("MCGen/", "MCRecoEffCorr/"); } - if (cfgRunDataGetNSig) { - declareDataGetFlatHists(); - } if (cfgRunGetDataFlat) { declareDataGetFlatHists(); } @@ -1193,269 +1069,180 @@ struct RadialFlowDecorr { } if (cfgRunDataFluc) { declareDataFlucHists(); + if (doBoot) { + declareBootstrapHists(); + } } - if (!cfgRunGetEff && !cfgRunMCGetNSig && (cfgEff)) { - TList* lst = ccdb->getForTimeStamp(pathEff, now); - + // ---- efficiency/fake maps (inclusive) ---- + if (!cfgRunGetEff && cfgEff) { + auto* lst = ccdb->getForTimeStamp(pathEff, now); if (!lst) { LOGF(fatal, "Efficiency maps required but CCDB list is null at %s!", pathEff.c_str()); + return; } - LOGF(info, "Loading Eff/Fake maps from TList for all species..."); - - auto loadEffFakeForPID = [&](PIDIdx pidType) { - std::string suffix = pidSuffix[pidType]; - std::string hEffNumName = "h3_RecoMatchedToPrimary" + suffix; - std::string hEffDenName = "h3_AllPrimary" + suffix; - std::string hFakeNumSecName = "h3_RecoUnMatchedToPrimary_Secondary" + suffix; - std::string hFakeNumFakName = "h3_RecoUnMatchedToPrimary_Fake" + suffix; - std::string hFakeNumFakName2 = "h3_RecoMatchedToPrimary_MisID" + suffix; - std::string hFakeDenName = "h3_AllReco" + suffix; + auto* hNum = dynamic_cast(lst->FindObject("h3_RecoMatchedToPrimary")); + auto* hDen = dynamic_cast(lst->FindObject("h3_AllPrimary")); + if (hNum && hDen) { + state.hEff = dynamic_cast(hNum->Clone("hEff")); + state.hEff->SetDirectory(nullptr); + state.hEff->Divide(hDen); + } else { + LOGF(error, "Missing CCDB objects for efficiency (h3_RecoMatchedToPrimary / h3_AllPrimary)."); + } - auto* hNum = reinterpret_cast(lst->FindObject(hEffNumName.c_str())); - auto* hDen = reinterpret_cast(lst->FindObject(hEffDenName.c_str())); + auto* hNumS = dynamic_cast(lst->FindObject("h3_RecoUnMatchedToPrimary_Secondary")); + auto* hNumF = dynamic_cast(lst->FindObject("h3_RecoUnMatchedToPrimary_Fake")); + auto* hDenF = dynamic_cast(lst->FindObject("h3_AllReco")); + if (hNumS && hNumF && hDenF) { + state.hFake = dynamic_cast(hNumS->Clone("hFake")); + state.hFake->Add(hNumF); + state.hFake->SetDirectory(nullptr); + state.hFake->Divide(hDenF); + } else { + LOGF(error, "Missing CCDB objects for fakes."); + } + } - if (hNum && hDen) { - state.hEff[pidType] = reinterpret_cast(hNum->Clone(Form("hEff%s", suffix.c_str()))); - state.hEff[pidType]->SetDirectory(nullptr); - state.hEff[pidType]->Divide(hDen); + // ---- flattening maps (inclusive) ---- + if (!cfgRunGetEff && cfgFlat) { + if (cfgRunDataMean || cfgRunDataFluc) { + auto* lstDataFlat = ccdb->getForTimeStamp(pathDataFlat, now); + if (lstDataFlat) { + std::string hName = cfgEff ? "hEtaPhiRecoWtd" : "hEtaPhiReco"; + auto* hRaw = dynamic_cast(lstDataFlat->FindObject(hName.c_str())); + if (hRaw) { + state.hFlatWeight = buildWeightMapFromRaw(hRaw, "hFlatWeight"); + } else { + LOGF(error, "Data flattening map '%s' not found.", hName.c_str()); + } } else { - LOGF(error, "Missing CCDB objects for efficiency. Checked: %s, %s", hEffNumName.c_str(), hEffDenName.c_str()); + LOGF(error, "Could not retrieve Data Flattening TList from: %s", pathDataFlat.c_str()); } - - auto* hNumS = reinterpret_cast(lst->FindObject(hFakeNumSecName.c_str())); - auto* hNumF = reinterpret_cast(lst->FindObject(hFakeNumFakName.c_str())); - auto* hNumF2 = reinterpret_cast(lst->FindObject(hFakeNumFakName2.c_str())); - auto* hDenF = reinterpret_cast(lst->FindObject(hFakeDenName.c_str())); - - if (hNumS && hNumF && hDenF) { - state.hFake[pidType] = reinterpret_cast(hNumS->Clone(Form("hFake%s", suffix.c_str()))); - state.hFake[pidType]->Add(hNumF); - if (pidType != kInclusiveIdx && hNumF2) { - state.hFake[pidType]->Add(hNumF2); + } + if (cfgRunMCMean || cfgRunMCFluc) { + auto* lstMCFlat = ccdb->getForTimeStamp(pathMCFlat, now); + if (lstMCFlat) { + std::string hName = cfgEff ? "MCReco/hEtaPhiRecoWtd" : "MCReco/hEtaPhiReco"; + auto* hRaw = dynamic_cast(lstMCFlat->FindObject(hName.c_str())); + if (hRaw) { + state.hFlatWeight = buildWeightMapFromRaw(hRaw, "hFlatWeight"); + } else { + LOGF(warning, "MC flattening source '%s' not found.", hName.c_str()); } - state.hFake[pidType]->SetDirectory(nullptr); - state.hFake[pidType]->Divide(hDenF); } else { - LOGF(error, "Missing CCDB object(s) for fakes for %s in list.", suffix.c_str()); + LOGF(error, "Could not retrieve MC Flattening TList from: %s", pathMCFlat.c_str()); } - }; - - for (int i = 0; i < KNsp; ++i) { - loadEffFakeForPID(static_cast(i)); } } - bool requiresMCMap = (cfgRunGetEff || cfgRunGetMCFlat || cfgRunMCMean || cfgRunMCFluc); - bool requiresDataMap = (cfgRunGetDataFlat || cfgRunDataMean || cfgRunDataFluc); - - if (requiresMCMap || requiresDataMap) { - std::string currentPath = requiresMCMap ? pathNsig : pathDataNsig; - TList* pidList = ccdb->getForTimeStamp(currentPath, now); - - if (!pidList) { - LOGF(warn, "nSigma maps required but CCDB list is null at %s! Using raw values.", currentPath.c_str()); - } else { - if (!pidMeanSigmaMap) { - pidMeanSigmaMap = new PIDMeanSigmaMap(); - } - LOGF(info, "Performing 2D Gaussian fits on PID maps from CCDB..."); - auto loadPIDMeans = [&](PIDIdx pidType) { - std::string suffix = pidSuffix[pidType]; - std::string hName = "h3DnsigmaTpcVsTofBefCut_Cent" + suffix; - auto* h3 = reinterpret_cast(pidList->FindObject(hName.c_str())); - if (!h3) { - LOGF(warn, " [!] PID Hist %s not found in CCDB list.", hName.c_str()); - return; - } - int nCentBins = std::min(h3->GetXaxis()->GetNbins(), PIDMeanSigmaMap::MaxCentBins - 1); - LOGF(info, " -> Species: %s (Bins: %d)", hName.c_str(), nCentBins); - for (int iCent = 1; iCent <= nCentBins; ++iCent) { - h3->GetXaxis()->SetRange(iCent, iCent); - // Projecting: Z(TPC) vs Y(TOF). Result: X_axis=TOF, Y_axis=TPC - std::unique_ptr h2(reinterpret_cast(h3->Project3D("zy"))); - if (h2) { - int binX, binY, binZ; - h2->GetMaximumBin(binX, binY, binZ); - double guessMeanTOF = h2->GetXaxis()->GetBinCenter(binX); - double guessMeanTPC = h2->GetYaxis()->GetBinCenter(binY); - TF2 f2("f2", "[0]*TMath::Gaus(x,[1],[2])*TMath::Gaus(y,[3],[4])", -3, 3, -3, 3); - f2.SetParameters(h2->GetMaximum(), guessMeanTOF, 1.0, guessMeanTPC, 1.0); - h2->Fit(&f2, "QRN"); // Q=Quiet, R=Range, N=NoDraw - pidMeanSigmaMap->meanTOF[pidType][iCent - 1] = f2.GetParameter(1); - pidMeanSigmaMap->meanTPC[pidType][iCent - 1] = f2.GetParameter(3); - pidMeanSigmaMap->sigmaTOF[pidType][iCent - 1] = std::abs(f2.GetParameter(2)); - pidMeanSigmaMap->sigmaTPC[pidType][iCent - 1] = std::abs(f2.GetParameter(4)); - if (iCent % KConstTen == 0) { - LOGF(info, " Derived: For Species: %s (Bins: %d), Mean TOF = %.3f, Mean TPC = %.3f, Sigma TOF = %.3f, Sigma TPC = %.3f", hName.c_str(), iCent - 1, f2.GetParameter(1), f2.GetParameter(3), f2.GetParameter(2), f2.GetParameter(4)); - } - } - } - }; - for (int i = 1; i < KNsp; ++i) { - loadPIDMeans(static_cast(i)); - } - + // ---- sigma-pileup limits ---- + // These were produced by the (now removed) nSigma pass. They are re-sourced + // from the flattening-map file, which also stores Hist2D_globalTracks_cent. + // Loaded only when the sigma-pileup cut is actually requested. + if (cfgApplySigPupCut) { + const bool mcSide = (cfgRunGetEff || cfgRunGetMCFlat || cfgRunMCMean || cfgRunMCFluc); + std::string limPath = mcSide ? pathMCFlat : pathDataFlat; + auto* limList = ccdb->getForTimeStamp(limPath, now); + if (limList) { auto loadLimits = [&](const char* name, std::vector>& limits, float& xMin, float& xMax) { - auto* h2 = reinterpret_cast(pidList->FindObject(name)); - if (!h2) + auto* h2 = dynamic_cast(limList->FindObject(name)); + if (!h2) { return; - + } std::unique_ptr prof(h2->ProfileX("ptmp", 1, -1, "S")); - int nBins = prof->GetNbinsX(); xMin = prof->GetXaxis()->GetXmin(); xMax = prof->GetXaxis()->GetXmax(); - limits.assign(nBins + 2, {-99999.f, 999999.f}); - for (int i = 1; i <= nBins; ++i) { float mean = prof->GetBinContent(i); float rms = prof->GetBinError(i); - limits[i] = {mean - cfgPupnSig * rms, mean + cfgPupnSig * rms}; } }; loadLimits("Hist2D_globalTracks_cent", state.mLimitsNchCent, state.mMinXNchCent, state.mMaxXNchCent); - } - } - if (!cfgRunGetEff && (cfgFlat)) { - if (cfgRunDataMean || cfgRunDataFluc) { - LOGF(info, "Data Run: Loading flattening maps from %s", pathDataFlat.c_str()); - TList* lstDataFlat = ccdb->getForTimeStamp(pathDataFlat, now); - - if (lstDataFlat) { - for (int i = 0; i < KNsp; ++i) { - std::string suffix = pidSuffix[i]; - std::string hName; - - if (cfgEff && cfgFlat) { - hName = "hEtaPhiRecoWtd" + suffix; - } else if (cfgEff) { - hName = "hEtaPhiRecoEffWtd" + suffix; - } else { - hName = "hEtaPhiReco" + suffix; - } - auto* hRaw = reinterpret_cast(lstDataFlat->FindObject(hName.c_str())); - - if (hRaw) { - state.hFlatWeight[i] = buildWeightMapFromRaw(hRaw, Form("hFlatWeight%s", suffix.c_str())); - } else { - LOGF(error, "Data flattening map '%s' not found.", hName.c_str()); - } - } - } else { - LOGF(error, "Could not retrieve Data Flattening TList from: %s", pathDataFlat.c_str()); - } - } - - if (cfgRunMCMean || cfgRunMCFluc) { - LOGF(info, "MC Run: Loading flattening maps from %s", pathMCFlat.c_str()); - TList* lstMCFlat = ccdb->getForTimeStamp(pathMCFlat, now); - - if (lstMCFlat) { - auto loadFlatForPID = [&](PIDIdx pidType) { - std::string suffix = pidSuffix[pidType]; - std::string hFlatSrcName; - if (cfgEff && cfgFlat) { - hFlatSrcName = "MCReco/hEtaPhiRecoWtd" + suffix; - } else if (cfgEff) { - hFlatSrcName = "MCReco/hEtaPhiRecoEffWtd" + suffix; - } else { - hFlatSrcName = "MCReco/hEtaPhiReco" + suffix; - } - - auto* hRaw = reinterpret_cast(lstMCFlat->FindObject(hFlatSrcName.c_str())); - - if (hRaw) { - state.hFlatWeight[pidType] = buildWeightMapFromRaw(hRaw, Form("hFlatWeight%s", suffix.c_str())); - } else { - LOGF(warning, "MC flattening source '%s' not found in list.", hFlatSrcName.c_str()); - } - }; - - for (int i = 0; i < KNsp; ++i) { - loadFlatForPID(static_cast(i)); - } - } else { - LOGF(error, "Could not retrieve MC Flattening TList from: %s", pathMCFlat.c_str()); - } - } - } - - auto loadTProfile3DFromList = [&](TList* sourceList, const char* objName, TProfile3D*& target) { - if (!sourceList) - return; - auto* tp = reinterpret_cast(sourceList->FindObject(objName)); - if (tp) { - target = reinterpret_cast(tp->Clone()); - target->SetDirectory(nullptr); - LOGF(info, "Loaded %s from list", objName); - } else { - LOGF(error, "Histogram %s missing in CCDB TList", objName); - } - }; - - auto loadTProfileFromList = [&](TList* sourceList, const char* objName, TProfile*& target) { - if (!sourceList) - return; - auto* tp = reinterpret_cast(sourceList->FindObject(objName)); - if (tp) { - target = reinterpret_cast(tp->Clone()); - target->SetDirectory(nullptr); - LOGF(info, "Loaded %s from list", objName); } else { - LOGF(error, "Histogram %s missing in CCDB TList", objName); + LOGF(warning, "sigma-pileup limits source list missing at %s; sigma-pileup cut effectively disabled.", limPath.c_str()); } - }; + } + // ---- MC mean profiles for MC fluc ---- if (cfgRunMCFluc) { LOGF(info, "Loading MC Mean profiles from CCDB path: %s", pathMCMean.c_str()); - TList* lstMCMean = ccdb->getForTimeStamp(pathMCMean, now); - + auto* lstMCMean = ccdb->getForTimeStamp(pathMCMean, now); if (lstMCMean) { - loadTProfileFromList(lstMCMean, "pmeanFT0Amultpv", state.pmeanFT0AmultpvStep2); - loadTProfileFromList(lstMCMean, "pmeanFT0Cmultpv", state.pmeanFT0CmultpvStep2); - - loadTProfile3DFromList(lstMCMean, "pmeanTru_nch_etabin_spbin", state.pmeanTruNchEtabinSpbinStep2); - loadTProfile3DFromList(lstMCMean, "pmeanReco_nch_etabin_spbin", state.pmeanRecoNchEtabinSpbinStep2); - loadTProfile3DFromList(lstMCMean, "pmeanRecoEffcorr_nch_etabin_spbin", state.pmeanRecoEffcorrNchEtabinSpbinStep2); - - loadTProfile3DFromList(lstMCMean, "pmeanMultTru_nch_etabin_spbin", state.pmeanMultTruNchEtabinSpbinStep2); - loadTProfile3DFromList(lstMCMean, "pmeanMultReco_nch_etabin_spbin", state.pmeanMultRecoNchEtabinSpbinStep2); - loadTProfile3DFromList(lstMCMean, "pmeanMultRecoEffcorr_nch_etabin_spbin", state.pmeanMultRecoEffcorrNchEtabinSpbinStep2); + loadProfileFromList(lstMCMean, "pmeanFT0Amultpv", state.pmeanFT0AmultpvStep2); + loadProfileFromList(lstMCMean, "pmeanFT0Cmultpv", state.pmeanFT0CmultpvStep2); + loadProfileFromList(lstMCMean, "pmeanTru_nch_etabin", state.pmeanTruNchEtabinStep2); + loadProfileFromList(lstMCMean, "pmeanReco_nch_etabin", state.pmeanRecoNchEtabinStep2); + loadProfileFromList(lstMCMean, "pmeanRecoEffcorr_nch_etabin", state.pmeanRecoEffcorrNchEtabinStep2); + loadProfileFromList(lstMCMean, "pmeanMultTru_nch_etabin", state.pmeanMultTruNchEtabinStep2); + loadProfileFromList(lstMCMean, "pmeanMultReco_nch_etabin", state.pmeanMultRecoNchEtabinStep2); + loadProfileFromList(lstMCMean, "pmeanMultRecoEffcorr_nch_etabin", state.pmeanMultRecoEffcorrNchEtabinStep2); + // MC is pinned to 0.2-wide bins; guard against a stale MC-mean object built + // at a different width (its y-axis would then not have nEta+1 bins). + if (state.pmeanTruNchEtabinStep2 && + state.pmeanTruNchEtabinStep2->GetYaxis()->GetNbins() != nEta + 1) { + LOGF(fatal, + "MC Mean eta binning mismatch: loaded profile has %d y-bins, this job " + "expects nEta+1=%d. Rebuild the MC-mean pass at the current binning.", + state.pmeanTruNchEtabinStep2->GetYaxis()->GetNbins(), nEta + 1); + } } else { LOGF(error, "Could not retrieve TList for MC Mean from: %s", pathMCMean.c_str()); } } + // ---- Data mean profiles for data fluc (one per systematic variation) ---- if (cfgRunDataFluc) { - LOGF(info, "Loading Data Mean profiles from CCDB path: %s", pathDataMean.c_str()); - TList* lstDataMean = ccdb->getForTimeStamp(pathDataMean, now); - + int st = std::clamp(cfgSystType, 0, kNSystType - 1); + std::string meanPath = pathDataMean + systSuffix[st]; + LOGF(info, "Loading Data Mean profiles for systematic '%s' from: %s", + (st == kSystBase ? "Base" : systSuffix[st].c_str()), meanPath.c_str()); + auto* lstDataMean = ccdb->getForTimeStamp(meanPath, now); if (lstDataMean) { - loadTProfileFromList(lstDataMean, "pmeanFT0Amultpv", state.pmeanFT0AmultpvStep2); - loadTProfileFromList(lstDataMean, "pmeanFT0Cmultpv", state.pmeanFT0CmultpvStep2); - - loadTProfile3DFromList(lstDataMean, "pmean_nch_etabin_spbin", state.pmeanNchEtabinSpbinStep2); - loadTProfile3DFromList(lstDataMean, "pmeanMult_nch_etabin_spbin", state.pmeanMultNchEtabinSpbinStep2); + loadProfileFromList(lstDataMean, "pmeanFT0Amultpv", state.pmeanFT0AmultpvStep2); + loadProfileFromList(lstDataMean, "pmeanFT0Cmultpv", state.pmeanFT0CmultpvStep2); + loadProfileFromList(lstDataMean, "pmean_nch_etabin", state.pmeanNchEtabinStep2); + loadProfileFromList(lstDataMean, "pmeanMult_nch_etabin", state.pmeanMultNchEtabinStep2); + // The DataMean and DataFluc passes must share cfgEtaBinWidth, else the + // (ibx, ieta+1) read in processDataFluc maps a fluc bin index onto a + // different physical eta slice, silently. The mean profile y-axis has + // nEta+1 bins by construction (etaBinAxis). + if (state.pmeanNchEtabinStep2 && + state.pmeanNchEtabinStep2->GetYaxis()->GetNbins() != nEta + 1) { + LOGF(fatal, + "Data Mean eta binning mismatch: loaded profile has %d y-bins, this job " + "expects nEta+1=%d -> DataMean and DataFluc used different cfgEtaBinWidth.", + state.pmeanNchEtabinStep2->GetYaxis()->GetNbins(), nEta + 1); + } } else { - LOGF(error, "Could not retrieve TList for Data Mean from: %s", pathDataMean.c_str()); + LOGF(error, "Could not retrieve TList for Data Mean from: %s", meanPath.c_str()); } } LOGF(info, "CCDB initialization complete for RadialFlowDecorr."); } - void processMCGetMeanNsig(MyRun3MCCollisions::iterator const& mcCollision, FilteredTCs const& mcTracks) + // =========================================================================== + // MC: build efficiency / fake maps (inclusive) + // =========================================================================== + void processGetEffHists(MyRun3MCCollisions::iterator const& mcCollision, FilteredTCs const& mcTracks, aod::McParticles const& mcParticles) { histos.fill(HIST("hVtxZ"), mcCollision.posZ()); - if (!mcCollision.has_mcCollision() || !isEventSelected(mcCollision)) + if (!mcCollision.has_mcCollision() || !isEventSelected(mcCollision)) { return; + } float cent = getCentrality(mcCollision); - if (cent > KCentMax) + if (cent > KCentMax) { return; + } float multPV = mcCollision.multNTracksPV(); + float vz = mcCollision.posZ(); + if (!isPassAddPileup(multPV, mcTracks.size(), cent)) { + return; + } histos.fill(HIST("hVtxZ_after_sel"), mcCollision.posZ()); histos.fill(HIST("hCentrality"), cent); @@ -1464,682 +1251,244 @@ struct RadialFlowDecorr { histos.fill(HIST("Hist2D_globalTracks_cent"), cent, mcTracks.size()); histos.fill(HIST("Hist2D_PVTracks_cent"), cent, multPV); - for (const auto& track : mcTracks) { - if (track.collisionId() != mcCollision.index()) + for (const auto& particle : mcParticles) { + if (particle.mcCollisionId() != mcCollision.mcCollisionId()) { continue; - - if (!isTrackSelected(track)) + } + if (!isParticleSelected(particle) || !particle.isPhysicalPrimary()) { continue; - fillNSigmaBefCut(track, cent); - } - } - PROCESS_SWITCH(RadialFlowDecorr, processMCGetMeanNsig, "process MC to calculate Mean values of nSig Plots", cfgRunMCGetNSig); - - void processGetEffHists(MyRun3MCCollisions::iterator const& mcCollision, FilteredTCs const& mcTracks, aod::McParticles const& mcParticles) - { - histos.fill(HIST("hVtxZ"), mcCollision.posZ()); - if (!mcCollision.has_mcCollision() || !isEventSelected(mcCollision)) - return; - float cent = getCentrality(mcCollision); - if (cent > KCentMax) - return; - float multPV = mcCollision.multNTracksPV(); - float vz = mcCollision.posZ(); - if (!isPassAddPileup(multPV, mcTracks.size(), cent)) - return; - histos.fill(HIST("hVtxZ_after_sel"), mcCollision.posZ()); - histos.fill(HIST("hCentrality"), cent); - - histos.fill(HIST("Hist2D_globalTracks_PVTracks"), multPV, mcTracks.size()); - histos.fill(HIST("Hist2D_cent_nch"), mcTracks.size(), cent); - histos.fill(HIST("Hist2D_globalTracks_cent"), cent, mcTracks.size()); - histos.fill(HIST("Hist2D_PVTracks_cent"), cent, multPV); - - for (const auto& particle : mcParticles) { - if (particle.mcCollisionId() != mcCollision.mcCollisionId()) - continue; - - if (!isParticleSelected(particle) || !particle.isPhysicalPrimary()) - continue; - - const int pdg = particle.pdgCode(); - const int absPdg = std::abs(pdg); - float pt = particle.pt(), eta = particle.eta(); - - bool isSpecies[KNsp] = { - true, // kInclusiveIdx - pdg == -KPiPlus, // kPiMinusIdx - pdg == KPiPlus, // kPiPlusIdx - absPdg == KPiPlus, // kPiAllIdx - pdg == -KKPlus, // kKaMinusIdx - pdg == KKPlus, // kKaPlusIdx - absPdg == KKPlus, // kKaAllIdx - pdg == -KProton, // kAntiPrIdx - pdg == KProton, // kPrIdx - absPdg == KProton // kPrAllIdx - }; - - histos.fill(HIST("h3_AllPrimary"), multPV, pt, eta); - if (isSpecies[kPiMinusIdx]) - histos.fill(HIST("h3_AllPrimary_PiMinus"), multPV, pt, eta); - else if (isSpecies[kPiPlusIdx]) - histos.fill(HIST("h3_AllPrimary_PiPlus"), multPV, pt, eta); - if (isSpecies[kPiAllIdx]) - histos.fill(HIST("h3_AllPrimary_PiAll"), multPV, pt, eta); - - if (isSpecies[kKaMinusIdx]) - histos.fill(HIST("h3_AllPrimary_KaMinus"), multPV, pt, eta); - else if (isSpecies[kKaPlusIdx]) - histos.fill(HIST("h3_AllPrimary_KaPlus"), multPV, pt, eta); - if (isSpecies[kKaAllIdx]) - histos.fill(HIST("h3_AllPrimary_KaAll"), multPV, pt, eta); - - if (isSpecies[kAntiPrIdx]) - histos.fill(HIST("h3_AllPrimary_AntiPr"), multPV, pt, eta); - else if (isSpecies[kPrIdx]) - histos.fill(HIST("h3_AllPrimary_Pr"), multPV, pt, eta); - if (isSpecies[kPrAllIdx]) - histos.fill(HIST("h3_AllPrimary_PrAll"), multPV, pt, eta); + } + histos.fill(HIST("h3_AllPrimary"), multPV, particle.pt(), particle.eta()); } for (const auto& track : mcTracks) { - if (track.collisionId() != mcCollision.index()) + if (track.collisionId() != mcCollision.index()) { continue; - - if (!isTrackSelected(track)) + } + if (!isTrackSelected(track)) { continue; + } float pt = track.pt(), eta = track.eta(); histos.fill(HIST("hPt"), pt); histos.fill(HIST("hEta"), eta); - auto sign = track.sign(); - fillNSigmaBefCut(track, cent); - - int id = identifyTrack(track, cent); - bool isPi = (id == KPidPionOne); - bool isKa = (id == KPidKaonTwo); - bool isPr = (id == KPidProtonThree); - bool isSpecies[KNsp] = { - true, - isPi && sign < 0, isPi && sign > 0, isPi, - isKa && sign < 0, isKa && sign > 0, isKa, - isPr && sign < 0, isPr && sign > 0, isPr}; - - fillNSigmaAftCut(track, cent, isSpecies); - - for (int isp = 0; isp < KNsp; ++isp) { - if (!isSpecies[isp]) - continue; - - if (isp == kInclusiveIdx) { - histos.fill(HIST("h3_AllReco"), multPV, pt, eta); - if (track.has_mcParticle()) { - auto mcP = track.mcParticle(); - if (mcP.isPhysicalPrimary()) { - histos.fill(HIST("ptResolution"), mcP.pt(), (pt - mcP.pt()) / mcP.pt()); - histos.fill(HIST("etaResolution"), mcP.eta(), eta - mcP.eta()); - histos.fill(HIST("etaTruthReco"), mcP.eta(), eta); - histos.fill(HIST("vzResolution"), mcP.vz(), (vz - mcP.vz()) / mcP.vz()); - histos.fill(HIST("TruthTracKVz"), mcP.vz(), vz); - histos.fill(HIST("h3_RecoMatchedToPrimary"), multPV, mcP.pt(), mcP.eta()); - } else { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary"), multPV, pt, eta); - } - } else { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake"), multPV, pt, eta); - } - } else if (isp == kPiMinusIdx) { - histos.fill(HIST("h3_AllReco_PiMinus"), multPV, pt, eta); - if (track.has_mcParticle()) { - auto mcP = track.mcParticle(); - if (mcP.isPhysicalPrimary()) { - if (mcP.pdgCode() == -KPiPlus) { - histos.fill(HIST("h3_RecoMatchedToPrimary_PiMinus"), multPV, mcP.pt(), mcP.eta()); - } else { // Misidentified - histos.fill(HIST("h3_RecoMatchedToPrimary_MisID_PiMinus"), multPV, pt, eta); - } - } else { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary_PiMinus"), multPV, pt, eta); - } - } else { // No MC - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake_PiMinus"), multPV, pt, eta); - } - } else if (isp == kPiPlusIdx) { - histos.fill(HIST("h3_AllReco_PiPlus"), multPV, pt, eta); - if (track.has_mcParticle()) { - auto mcP = track.mcParticle(); - if (mcP.isPhysicalPrimary()) { - if (mcP.pdgCode() == KPiPlus) { - histos.fill(HIST("h3_RecoMatchedToPrimary_PiPlus"), multPV, mcP.pt(), mcP.eta()); - } else { // Misidentified - histos.fill(HIST("h3_RecoMatchedToPrimary_MisID_PiPlus"), multPV, pt, eta); - } - } else { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary_PiPlus"), multPV, pt, eta); - } - } else { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake_PiPlus"), multPV, pt, eta); - } - } else if (isp == kPiAllIdx) { - histos.fill(HIST("h3_AllReco_PiAll"), multPV, pt, eta); - if (track.has_mcParticle()) { - auto mcP = track.mcParticle(); - if (mcP.isPhysicalPrimary()) { - if (std::abs(mcP.pdgCode()) == KPiPlus) { - histos.fill(HIST("h3_RecoMatchedToPrimary_PiAll"), multPV, mcP.pt(), mcP.eta()); - } else { // Misidentified - histos.fill(HIST("h3_RecoMatchedToPrimary_MisID_PiAll"), multPV, pt, eta); - } - } else { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary_PiAll"), multPV, pt, eta); - } - } else { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake_PiAll"), multPV, pt, eta); - } - } else if (isp == kKaMinusIdx) { - histos.fill(HIST("h3_AllReco_KaMinus"), multPV, pt, eta); - if (track.has_mcParticle()) { - auto mcP = track.mcParticle(); - if (mcP.isPhysicalPrimary()) { - if (mcP.pdgCode() == -KKPlus) { - histos.fill(HIST("h3_RecoMatchedToPrimary_KaMinus"), multPV, mcP.pt(), mcP.eta()); - } else { // Misidentified - histos.fill(HIST("h3_RecoMatchedToPrimary_MisID_KaMinus"), multPV, pt, eta); - } - } else { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary_KaMinus"), multPV, pt, eta); - } - } else { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake_KaMinus"), multPV, pt, eta); - } - } else if (isp == kKaPlusIdx) { - histos.fill(HIST("h3_AllReco_KaPlus"), multPV, pt, eta); - if (track.has_mcParticle()) { - auto mcP = track.mcParticle(); - if (mcP.isPhysicalPrimary()) { - if (mcP.pdgCode() == KKPlus) { - histos.fill(HIST("h3_RecoMatchedToPrimary_KaPlus"), multPV, mcP.pt(), mcP.eta()); - } else { // Misidentified - histos.fill(HIST("h3_RecoMatchedToPrimary_MisID_KaPlus"), multPV, pt, eta); - } - } else { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary_KaPlus"), multPV, pt, eta); - } - } else { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake_KaPlus"), multPV, pt, eta); - } - } else if (isp == kKaAllIdx) { - histos.fill(HIST("h3_AllReco_KaAll"), multPV, pt, eta); - if (track.has_mcParticle()) { - auto mcP = track.mcParticle(); - if (mcP.isPhysicalPrimary()) { - if (std::abs(mcP.pdgCode()) == KKPlus) { - histos.fill(HIST("h3_RecoMatchedToPrimary_KaAll"), multPV, mcP.pt(), mcP.eta()); - } else { // Misidentified - histos.fill(HIST("h3_RecoMatchedToPrimary_MisID_KaAll"), multPV, pt, eta); - } - } else { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary_KaAll"), multPV, pt, eta); - } - } else { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake_KaAll"), multPV, pt, eta); - } - } else if (isp == kAntiPrIdx) { - histos.fill(HIST("h3_AllReco_AntiPr"), multPV, pt, eta); - if (track.has_mcParticle()) { - auto mcP = track.mcParticle(); - if (mcP.isPhysicalPrimary()) { - if (mcP.pdgCode() == -KProton) { - histos.fill(HIST("h3_RecoMatchedToPrimary_AntiPr"), multPV, mcP.pt(), mcP.eta()); - } else { // Misidentified - histos.fill(HIST("h3_RecoMatchedToPrimary_MisID_AntiPr"), multPV, pt, eta); - } - } else { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary_AntiPr"), multPV, pt, eta); - } - } else { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake_AntiPr"), multPV, pt, eta); - } - } else if (isp == kPrIdx) { - histos.fill(HIST("h3_AllReco_Pr"), multPV, pt, eta); - if (track.has_mcParticle()) { - auto mcP = track.mcParticle(); - if (mcP.isPhysicalPrimary()) { - if (mcP.pdgCode() == KProton) { - histos.fill(HIST("h3_RecoMatchedToPrimary_Pr"), multPV, mcP.pt(), mcP.eta()); - } else { // Misidentified - histos.fill(HIST("h3_RecoMatchedToPrimary_MisID_Pr"), multPV, pt, eta); - } - } else { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary_Pr"), multPV, pt, eta); - } - } else { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake_Pr"), multPV, pt, eta); - } - } else if (isp == kPrAllIdx) { - histos.fill(HIST("h3_AllReco_PrAll"), multPV, pt, eta); - if (track.has_mcParticle()) { - auto mcP = track.mcParticle(); - if (mcP.isPhysicalPrimary()) { - if (std::abs(mcP.pdgCode()) == KProton) { - histos.fill(HIST("h3_RecoMatchedToPrimary_PrAll"), multPV, mcP.pt(), mcP.eta()); - } else { // Misidentified - histos.fill(HIST("h3_RecoMatchedToPrimary_MisID_PrAll"), multPV, pt, eta); - } - } else { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary_PrAll"), multPV, pt, eta); - } - } else { - histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake_PrAll"), multPV, pt, eta); - } + histos.fill(HIST("h3_AllReco"), multPV, pt, eta); + + if (track.has_mcParticle()) { + auto mcP = track.mcParticle(); + if (mcP.isPhysicalPrimary()) { + histos.fill(HIST("ptResolution"), mcP.pt(), (pt - mcP.pt()) / mcP.pt()); + histos.fill(HIST("etaResolution"), mcP.eta(), eta - mcP.eta()); + histos.fill(HIST("etaTruthReco"), mcP.eta(), eta); + histos.fill(HIST("vzResolution"), mcP.vz(), (vz - mcP.vz()) / mcP.vz()); + histos.fill(HIST("TruthTracKVz"), mcP.vz(), vz); + histos.fill(HIST("h3_RecoMatchedToPrimary"), multPV, mcP.pt(), mcP.eta()); + } else { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Secondary"), multPV, pt, eta); } + } else { + histos.fill(HIST("h3_RecoUnMatchedToPrimary_Fake"), multPV, pt, eta); } } } PROCESS_SWITCH(RadialFlowDecorr, processGetEffHists, "process MC to calculate EffWeights", cfgRunGetEff); + // =========================================================================== + // MC: build flattening maps (inclusive) + // =========================================================================== void processMCFlat(MyRun3MCCollisions::iterator const& mcCollision, FilteredTCs const& mcTracks) { histos.fill(HIST("hVtxZ"), mcCollision.posZ()); - if (!mcCollision.has_mcCollision() || !isEventSelected(mcCollision)) + if (!mcCollision.has_mcCollision() || !isEventSelected(mcCollision)) { return; - + } float cent = getCentrality(mcCollision); - if (cent > KCentMax) + if (cent > KCentMax) { return; - + } float multPV = mcCollision.multNTracksPV(); float vz = mcCollision.posZ(); - - if (!isPassAddPileup(multPV, mcTracks.size(), cent)) + if (!isPassAddPileup(multPV, mcTracks.size(), cent)) { return; + } + histos.fill(HIST("hVtxZ_after_sel"), mcCollision.posZ()); histos.fill(HIST("hCentrality"), cent); - - histos.fill(HIST("Hist2D_globalTracks_PVTracks"), mcCollision.multNTracksPV(), mcTracks.size()); + histos.fill(HIST("Hist2D_globalTracks_PVTracks"), multPV, mcTracks.size()); histos.fill(HIST("Hist2D_cent_nch"), mcTracks.size(), cent); histos.fill(HIST("Hist2D_globalTracks_cent"), cent, mcTracks.size()); histos.fill(HIST("Hist2D_PVTracks_cent"), cent, multPV); + for (const auto& track : mcTracks) { - if (track.collisionId() != mcCollision.index()) + if (track.collisionId() != mcCollision.index()) { continue; - - if (!isTrackSelected(track)) + } + if (!isTrackSelected(track)) { continue; + } float pt = track.pt(), eta = track.eta(), phi = track.phi(); auto sign = track.sign(); histos.fill(HIST("hPt"), pt); histos.fill(HIST("hEta"), eta); histos.fill(HIST("hPhi"), phi); - int id = identifyTrack(track, cent); - bool isPi = (id == KPidPionOne); - bool isKa = (id == KPidKaonTwo); - bool isPr = (id == KPidProtonThree); - bool isSpecies[KNsp] = { - true, - isPi && sign < 0, isPi && sign > 0, isPi, - isKa && sign < 0, isKa && sign > 0, isKa, - isPr && sign < 0, isPr && sign > 0, isPr}; - - for (int isp = 0; isp < KNsp; ++isp) { - if (!isSpecies[isp]) - continue; - float eff = getEfficiency(multPV, pt, eta, static_cast(isp), 0, cfgEff); - float fake = getEfficiency(multPV, pt, eta, static_cast(isp), 1, cfgEff); - float w = (eff > KFloatEpsilon) ? (1.0f - fake) / eff : 0.0f; - - if (std::isfinite(w) && w > 0.f) { - if (isp == kInclusiveIdx) { - histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("MCReco/hEtaPhiReco"), vz, sign, pt, eta, phi, 1.0); - histos.fill(HIST("MCReco/hEtaPhiRecoWtd"), vz, sign, pt, eta, phi, w); - } else if (isp == kPiMinusIdx) { - histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd_PiMinus"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("MCReco/hEtaPhiReco_PiMinus"), vz, sign, pt, eta, phi, 1.0); - histos.fill(HIST("MCReco/hEtaPhiRecoWtd_PiMinus"), vz, sign, pt, eta, phi, w); - } else if (isp == kPiPlusIdx) { - histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd_PiPlus"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("MCReco/hEtaPhiReco_PiPlus"), vz, sign, pt, eta, phi, 1.0); - histos.fill(HIST("MCReco/hEtaPhiRecoWtd_PiPlus"), vz, sign, pt, eta, phi, w); - } else if (isp == kPiAllIdx) { - histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd_PiAll"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("MCReco/hEtaPhiReco_PiAll"), vz, sign, pt, eta, phi, 1.0); - histos.fill(HIST("MCReco/hEtaPhiRecoWtd_PiAll"), vz, sign, pt, eta, phi, w); - } else if (isp == kKaMinusIdx) { - histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd_KaMinus"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("MCReco/hEtaPhiReco_KaMinus"), vz, sign, pt, eta, phi, 1.0); - histos.fill(HIST("MCReco/hEtaPhiRecoWtd_KaMinus"), vz, sign, pt, eta, phi, w); - } else if (isp == kKaPlusIdx) { - histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd_KaPlus"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("MCReco/hEtaPhiReco_KaPlus"), vz, sign, pt, eta, phi, 1.0); - histos.fill(HIST("MCReco/hEtaPhiRecoWtd_KaPlus"), vz, sign, pt, eta, phi, w); - } else if (isp == kKaAllIdx) { - histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd_KaAll"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("MCReco/hEtaPhiReco_KaAll"), vz, sign, pt, eta, phi, 1.0); - histos.fill(HIST("MCReco/hEtaPhiRecoWtd_KaAll"), vz, sign, pt, eta, phi, w); - } else if (isp == kAntiPrIdx) { - histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd_AntiPr"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("MCReco/hEtaPhiReco_AntiPr"), vz, sign, pt, eta, phi, 1.0); - histos.fill(HIST("MCReco/hEtaPhiRecoWtd_AntiPr"), vz, sign, pt, eta, phi, w); - } else if (isp == kPrIdx) { - histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd_Pr"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("MCReco/hEtaPhiReco_Pr"), vz, sign, pt, eta, phi, 1.0); - histos.fill(HIST("MCReco/hEtaPhiRecoWtd_Pr"), vz, sign, pt, eta, phi, w); - } else if (isp == kPrAllIdx) { - histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd_PrAll"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("MCReco/hEtaPhiReco_PrAll"), vz, sign, pt, eta, phi, 1.0); - histos.fill(HIST("MCReco/hEtaPhiRecoWtd_PrAll"), vz, sign, pt, eta, phi, w); - } - } + float eff = getEfficiency(multPV, pt, eta, 0, cfgEff); + float fake = getEfficiency(multPV, pt, eta, 1, cfgEff); + float w = (eff > KFloatEpsilon) ? (1.0f - fake) / eff : 0.0f; + if (std::isfinite(w) && w > 0.f) { + histos.fill(HIST("MCReco/hEtaPhiRecoEffWtd"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("MCReco/hEtaPhiReco"), vz, sign, pt, eta, phi, 1.0); + histos.fill(HIST("MCReco/hEtaPhiRecoWtd"), vz, sign, pt, eta, phi, w); } } } PROCESS_SWITCH(RadialFlowDecorr, processMCFlat, "process MC to calculate FlatWeights", cfgRunGetMCFlat); + // =========================================================================== + // MC: mean pT (truth / reco / reco-eff-corrected) + // =========================================================================== void processMCMean(MyRun3MCCollisions::iterator const& mcCollision, FilteredTCs const& mcTracks, aod::FT0s const&, aod::McParticles const& mcParticles) { - double sumWiTruth[KNsp][KNEta]{}, sumWiptiTruth[KNsp][KNEta]{}; - double sumWiReco[KNsp][KNEta]{}, sumWiptiReco[KNsp][KNEta]{}; - double sumWiRecoEffCorr[KNsp][KNEta]{}, sumWiptiRecoEffCorr[KNsp][KNEta]{}; + std::array sumWiTruth{}, sumWiptiTruth{}; + std::array sumWiReco{}, sumWiptiReco{}; + std::array sumWiRecoEffCorr{}, sumWiptiRecoEffCorr{}; + histos.fill(HIST("hVtxZ"), mcCollision.posZ()); - if (!mcCollision.has_mcCollision() || !isEventSelected(mcCollision)) + if (!mcCollision.has_mcCollision() || !isEventSelected(mcCollision)) { return; + } float cent = getCentrality(mcCollision); - if (cent > KCentMax) + if (cent > KCentMax) { return; + } float multPV = mcCollision.multNTracksPV(); float vz = mcCollision.posZ(); - if (!isPassAddPileup(multPV, mcTracks.size(), cent)) + if (!isPassAddPileup(multPV, mcTracks.size(), cent)) { return; + } histos.fill(HIST("hVtxZ_after_sel"), mcCollision.posZ()); histos.fill(HIST("hCentrality"), cent); - - histos.fill(HIST("Hist2D_globalTracks_PVTracks"), mcCollision.multNTracksPV(), mcTracks.size()); + histos.fill(HIST("Hist2D_globalTracks_PVTracks"), multPV, mcTracks.size()); histos.fill(HIST("Hist2D_cent_nch"), mcTracks.size(), cent); histos.fill(HIST("Hist2D_globalTracks_cent"), cent, mcTracks.size()); histos.fill(HIST("Hist2D_PVTracks_cent"), cent, multPV); - memset(sumWiTruth, 0, sizeof(sumWiTruth)); - memset(sumWiptiTruth, 0, sizeof(sumWiptiTruth)); - memset(sumWiReco, 0, sizeof(sumWiReco)); - memset(sumWiptiReco, 0, sizeof(sumWiptiReco)); - memset(sumWiRecoEffCorr, 0, sizeof(sumWiRecoEffCorr)); - memset(sumWiptiRecoEffCorr, 0, sizeof(sumWiptiRecoEffCorr)); - + // --- truth --- for (const auto& particle : mcParticles) { - if (particle.mcCollisionId() != mcCollision.mcCollisionId()) + if (particle.mcCollisionId() != mcCollision.mcCollisionId()) { continue; - - if (!isParticleSelected(particle) || !particle.isPhysicalPrimary()) + } + if (!isParticleSelected(particle) || !particle.isPhysicalPrimary()) { continue; + } float pt = particle.pt(), eta = particle.eta(); - if (pt <= cfgPtMin || pt > cfgPtMax) + if (pt <= cfgPtMin || pt > cfgPtMax) { continue; - int pdgCode = particle.pdgCode(); - int absPdg = std::abs(pdgCode); - - bool isSpecies[KNsp] = { - true, // kInclusiveIdx - pdgCode == -KPiPlus, // kPiMinusIdx - pdgCode == KPiPlus, // kPiPlusIdx - absPdg == KPiPlus, // kPiAllIdx - pdgCode == -KKPlus, // kKaMinusIdx - pdgCode == KKPlus, // kKaPlusIdx - absPdg == KKPlus, // kKaAllIdx - pdgCode == -KProton, // kAntiPrIdx - pdgCode == KProton, // kPrIdx - absPdg == KProton // kPrAllIdx - }; - - for (int ieta = 0; ieta < KNEta; ++ieta) { - if (eta <= etaLw[ieta] || eta > etaUp[ieta]) + } + for (int ieta = 0; ieta < nEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) { continue; - - for (int isp = 0; isp < KNsp; ++isp) { - if (isSpecies[isp]) { - sumWiTruth[isp][ieta]++; - sumWiptiTruth[isp][ieta] += pt; - } } + sumWiTruth[ieta]++; + sumWiptiTruth[ieta] += pt; } } - for (int isp = 0; isp < KNsp; ++isp) { - histos.fill(HIST("MCGen/Prof_Cent_Nsp_Nchrec"), cent, isp, sumWiTruth[isp][0]); - histos.fill(HIST("MCGen/Prof_Mult_Nsp_Nchrec"), multPV, isp, sumWiTruth[isp][0]); - if (sumWiTruth[isp][0] > 1.0f) { - histos.fill(HIST("MCGen/Prof_Cent_Nsp_MeanpT"), cent, isp, sumWiptiTruth[isp][0] / sumWiTruth[isp][0]); - histos.fill(HIST("MCGen/Prof_Mult_Nsp_MeanpT"), multPV, isp, sumWiptiTruth[isp][0] / sumWiTruth[isp][0]); - } + histos.fill(HIST("MCGen/Prof_Cent_Nchrec"), cent, sumWiTruth[0]); + histos.fill(HIST("MCGen/Prof_Mult_Nchrec"), multPV, sumWiTruth[0]); + if (sumWiTruth[0] > 1.0f) { + histos.fill(HIST("MCGen/Prof_Cent_MeanpT"), cent, sumWiptiTruth[0] / sumWiTruth[0]); + histos.fill(HIST("MCGen/Prof_Mult_MeanpT"), multPV, sumWiptiTruth[0] / sumWiTruth[0]); } + // --- reco --- for (const auto& track : mcTracks) { - if (track.collisionId() != mcCollision.index()) + if (track.collisionId() != mcCollision.index()) { continue; - - if (!isTrackSelected(track)) + } + if (!isTrackSelected(track)) { continue; + } float pt = track.pt(), eta = track.eta(), phi = track.phi(); - if (pt <= cfgPtMin || pt > cfgPtMax) + if (pt <= cfgPtMin || pt > cfgPtMax) { continue; + } auto sign = track.sign(); histos.fill(HIST("hPt"), pt); histos.fill(HIST("hEta"), eta); histos.fill(HIST("hPhi"), phi); - int id = identifyTrack(track, cent); - bool isPi = (id == KPidPionOne); - bool isKa = (id == KPidKaonTwo); - bool isPr = (id == KPidProtonThree); - bool isSpecies[KNsp] = { - true, - isPi && sign < 0, isPi && sign > 0, isPi, - isKa && sign < 0, isKa && sign > 0, isKa, - isPr && sign < 0, isPr && sign > 0, isPr}; - - for (int isp = 0; isp < KNsp; ++isp) { - if (!isSpecies[isp]) - continue; - float eff = getEfficiency(multPV, pt, eta, static_cast(isp), 0, cfgEff); - float fake = getEfficiency(multPV, pt, eta, static_cast(isp), 1, cfgEff); - float flatW = getFlatteningWeight(vz, sign, pt, eta, phi, static_cast(isp), cfgFlat); - float w = flatW * (1.0 - fake) / eff; - if (!std::isfinite(w) || w <= 0.f || eff <= KFloatEpsilon) - continue; - - for (int ieta = 0; ieta < KNEta; ++ieta) { - if (eta <= etaLw[ieta] || eta > etaUp[ieta]) - continue; - sumWiReco[isp][ieta]++; - sumWiptiReco[isp][ieta] += pt; - sumWiRecoEffCorr[isp][ieta] += w; - sumWiptiRecoEffCorr[isp][ieta] += w * pt; - } - if (isp == kInclusiveIdx) { - histos.fill(HIST("Eff_cent"), cent, eff); - histos.fill(HIST("Fake_cent"), cent, fake); - histos.fill(HIST("wgt_cent"), cent, w); - - histos.fill(HIST("Eff_Ntrk"), multPV, eff); - histos.fill(HIST("Fake_Ntrk"), multPV, fake); - histos.fill(HIST("wgt_Ntrk"), multPV, w); - - histos.fill(HIST("Eff_pT"), pt, eff); - histos.fill(HIST("Fake_pT"), pt, fake); - histos.fill(HIST("wgt_pT"), pt, w); - - histos.fill(HIST("Eff_eta"), eta, eff); - histos.fill(HIST("Fake_eta"), eta, fake); - histos.fill(HIST("wgt_eta"), eta, w); - } - if (isp == kInclusiveIdx) { - histos.fill(HIST("hEtaPhiReco"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoWtd"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("hEtaPhiRecoEffWtd"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); - } else if (isp == kPiMinusIdx) { - histos.fill(HIST("hEtaPhiReco_PiMinus"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoWtd_PiMinus"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("hEtaPhiRecoEffWtd_PiMinus"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); - } else if (isp == kPiPlusIdx) { - histos.fill(HIST("hEtaPhiReco_PiPlus"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoWtd_PiPlus"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("hEtaPhiRecoEffWtd_PiPlus"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); - } else if (isp == kPiAllIdx) { - histos.fill(HIST("hEtaPhiReco_PiAll"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoWtd_PiAll"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("hEtaPhiRecoEffWtd_PiAll"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); - } else if (isp == kKaMinusIdx) { - histos.fill(HIST("hEtaPhiReco_KaMinus"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoWtd_KaMinus"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("hEtaPhiRecoEffWtd_KaMinus"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); - } else if (isp == kKaPlusIdx) { - histos.fill(HIST("hEtaPhiReco_KaPlus"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoWtd_KaPlus"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("hEtaPhiRecoEffWtd_KaPlus"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); - } else if (isp == kKaAllIdx) { - histos.fill(HIST("hEtaPhiReco_KaAll"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoWtd_KaAll"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("hEtaPhiRecoEffWtd_KaAll"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); - } else if (isp == kPrIdx) { - histos.fill(HIST("hEtaPhiReco_Pr"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoWtd_Pr"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("hEtaPhiRecoEffWtd_Pr"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); - } else if (isp == kAntiPrIdx) { - histos.fill(HIST("hEtaPhiReco_AntiPr"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoWtd_AntiPr"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("hEtaPhiRecoEffWtd_AntiPr"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); - } else if (isp == kPrAllIdx) { - histos.fill(HIST("hEtaPhiReco_PrAll"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoWtd_PrAll"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("hEtaPhiRecoEffWtd_PrAll"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); - } + float eff = getEfficiency(multPV, pt, eta, 0, cfgEff); + float fake = getEfficiency(multPV, pt, eta, 1, cfgEff); + float flatW = getFlatteningWeight(vz, sign, pt, eta, phi, cfgFlat); + float w = flatW * (1.0 - fake) / eff; + if (!std::isfinite(w) || w <= 0.f || eff <= KFloatEpsilon) { + continue; } - } - if (!hasMinTracksInAllEtaBins(sumWiTruth) || !hasMinTracksInAllEtaBins(sumWiReco)) - return; - - for (int isp = 0; isp < KNsp; ++isp) { - histos.fill(HIST("MCReco/Prof_Cent_Nsp_Nchrec"), cent, isp, sumWiReco[isp][0]); - histos.fill(HIST("MCReco/Prof_Mult_Nsp_Nchrec"), multPV, isp, sumWiReco[isp][0]); - - histos.fill(HIST("MCRecoEffCorr/Prof_Cent_Nsp_Nchrec"), cent, isp, sumWiRecoEffCorr[isp][0]); - histos.fill(HIST("MCRecoEffCorr/Prof_Mult_Nsp_Nchrec"), multPV, isp, sumWiRecoEffCorr[isp][0]); - - if (sumWiReco[isp][0] > 1.0f) { - histos.fill(HIST("MCReco/Prof_Cent_Nsp_MeanpT"), cent, isp, sumWiptiReco[isp][0] / sumWiReco[isp][0]); - histos.fill(HIST("MCReco/Prof_Mult_Nsp_MeanpT"), multPV, isp, sumWiptiReco[isp][0] / sumWiReco[isp][0]); - } - if (sumWiRecoEffCorr[isp][0] > 1.0f) { - histos.fill(HIST("MCRecoEffCorr/Prof_Cent_Nsp_MeanpT"), cent, isp, sumWiptiRecoEffCorr[isp][0] / sumWiRecoEffCorr[isp][0]); - histos.fill(HIST("MCRecoEffCorr/Prof_Mult_Nsp_MeanpT"), multPV, isp, sumWiptiRecoEffCorr[isp][0] / sumWiRecoEffCorr[isp][0]); - } - } - - for (int ietaA = 0; ietaA < KNEta; ++ietaA) { - for (int ietaC = 0; ietaC < KNEta; ++ietaC) { - for (int isp = 0; isp < KNsp; ++isp) { - float nTruAB = sumWiTruth[isp][ietaA] + sumWiTruth[isp][ietaC]; - float nRecoAB = sumWiReco[isp][ietaA] + sumWiReco[isp][ietaC]; - float nCorrAB = sumWiRecoEffCorr[isp][ietaA] + sumWiRecoEffCorr[isp][ietaC]; - - float mptsubTru = (sumWiptiTruth[isp][ietaA] + sumWiptiTruth[isp][ietaC]) / nTruAB; - float mptsubReco = (sumWiptiReco[isp][ietaA] + sumWiptiReco[isp][ietaC]) / nRecoAB; - float mptsubRecoEffCorr = (sumWiptiRecoEffCorr[isp][ietaA] + sumWiptiRecoEffCorr[isp][ietaC]) / nCorrAB; - - if (nTruAB > 0) { - if (isp == kInclusiveIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Tru"), cent, ietaA, ietaC, mptsubTru); - else if (isp == kPiMinusIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Tru_PiMinus"), cent, ietaA, ietaC, mptsubTru); - else if (isp == kPiPlusIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Tru_PiPlus"), cent, ietaA, ietaC, mptsubTru); - else if (isp == kPiAllIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Tru_PiAll"), cent, ietaA, ietaC, mptsubTru); - else if (isp == kKaMinusIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Tru_KaMinus"), cent, ietaA, ietaC, mptsubTru); - else if (isp == kKaPlusIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Tru_KaPlus"), cent, ietaA, ietaC, mptsubTru); - else if (isp == kKaAllIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Tru_KaAll"), cent, ietaA, ietaC, mptsubTru); - else if (isp == kPrIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Tru_Pr"), cent, ietaA, ietaC, mptsubTru); - else if (isp == kAntiPrIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Tru_AntiPr"), cent, ietaA, ietaC, mptsubTru); - else if (isp == kPrAllIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Tru_PrAll"), cent, ietaA, ietaC, mptsubTru); - } - - if (nRecoAB > 0) { - if (isp == kInclusiveIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Reco"), cent, ietaA, ietaC, mptsubReco); - else if (isp == kPiMinusIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Reco_PiMinus"), cent, ietaA, ietaC, mptsubReco); - else if (isp == kPiPlusIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Reco_PiPlus"), cent, ietaA, ietaC, mptsubReco); - else if (isp == kPiAllIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Reco_PiAll"), cent, ietaA, ietaC, mptsubReco); - else if (isp == kKaMinusIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Reco_KaMinus"), cent, ietaA, ietaC, mptsubReco); - else if (isp == kKaPlusIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Reco_KaPlus"), cent, ietaA, ietaC, mptsubReco); - else if (isp == kKaAllIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Reco_KaAll"), cent, ietaA, ietaC, mptsubReco); - else if (isp == kPrIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Reco_Pr"), cent, ietaA, ietaC, mptsubReco); - else if (isp == kAntiPrIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Reco_AntiPr"), cent, ietaA, ietaC, mptsubReco); - else if (isp == kPrAllIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Reco_PrAll"), cent, ietaA, ietaC, mptsubReco); - } - - if (nCorrAB > 0) { - if (isp == kInclusiveIdx) - histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr"), cent, ietaA, ietaC, mptsubRecoEffCorr); - else if (isp == kPiMinusIdx) - histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr_PiMinus"), cent, ietaA, ietaC, mptsubRecoEffCorr); - else if (isp == kPiPlusIdx) - histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr_PiPlus"), cent, ietaA, ietaC, mptsubRecoEffCorr); - else if (isp == kPiAllIdx) - histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr_PiAll"), cent, ietaA, ietaC, mptsubRecoEffCorr); - else if (isp == kKaMinusIdx) - histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr_KaMinus"), cent, ietaA, ietaC, mptsubRecoEffCorr); - else if (isp == kKaPlusIdx) - histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr_KaPlus"), cent, ietaA, ietaC, mptsubRecoEffCorr); - else if (isp == kKaAllIdx) - histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr_KaAll"), cent, ietaA, ietaC, mptsubRecoEffCorr); - else if (isp == kPrIdx) - histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr_Pr"), cent, ietaA, ietaC, mptsubRecoEffCorr); - else if (isp == kAntiPrIdx) - histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr_AntiPr"), cent, ietaA, ietaC, mptsubRecoEffCorr); - else if (isp == kPrAllIdx) - histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr_PrAll"), cent, ietaA, ietaC, mptsubRecoEffCorr); - } + for (int ieta = 0; ieta < nEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) { + continue; } + sumWiReco[ieta]++; + sumWiptiReco[ieta] += pt; + sumWiRecoEffCorr[ieta] += w; + sumWiptiRecoEffCorr[ieta] += w * pt; } - for (int isp = 0; isp < KNsp; ++isp) { - if (sumWiTruth[isp][ietaA] > 0) { - float val = sumWiptiTruth[isp][ietaA] / sumWiTruth[isp][ietaA]; - histos.fill(HIST("pmeanTru_nch_etabin_spbin"), multPV, ietaA, isp, val); - histos.fill(HIST("pmeanMultTru_nch_etabin_spbin"), multPV, ietaA, isp, sumWiTruth[isp][ietaA]); + histos.fill(HIST("Eff_cent"), cent, eff); + histos.fill(HIST("Fake_cent"), cent, fake); + histos.fill(HIST("wgt_cent"), cent, w); + histos.fill(HIST("Eff_Ntrk"), multPV, eff); + histos.fill(HIST("Fake_Ntrk"), multPV, fake); + histos.fill(HIST("wgt_Ntrk"), multPV, w); + histos.fill(HIST("Eff_pT"), pt, eff); + histos.fill(HIST("Fake_pT"), pt, fake); + histos.fill(HIST("wgt_pT"), pt, w); + histos.fill(HIST("Eff_eta"), eta, eff); + histos.fill(HIST("Fake_eta"), eta, fake); + histos.fill(HIST("wgt_eta"), eta, w); + + histos.fill(HIST("hEtaPhiReco"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } + + // subevent mean-pT maps + for (int ietaA = 0; ietaA < nEta; ++ietaA) { + for (int ietaC = 0; ietaC < nEta; ++ietaC) { + float nTruAB = sumWiTruth[ietaA] + sumWiTruth[ietaC]; + float nRecoAB = sumWiReco[ietaA] + sumWiReco[ietaC]; + float nCorrAB = sumWiRecoEffCorr[ietaA] + sumWiRecoEffCorr[ietaC]; + + if (nTruAB > 0) { + histos.fill(HIST("Prof2D_MeanpTSub_Tru"), cent, ietaA, ietaC, (sumWiptiTruth[ietaA] + sumWiptiTruth[ietaC]) / nTruAB); } - if (sumWiReco[isp][ietaA] > 0) { - float val = sumWiptiReco[isp][ietaA] / sumWiReco[isp][ietaA]; - histos.fill(HIST("pmeanReco_nch_etabin_spbin"), multPV, ietaA, isp, val); - histos.fill(HIST("pmeanMultReco_nch_etabin_spbin"), multPV, ietaA, isp, sumWiReco[isp][ietaA]); + if (nRecoAB > 0) { + histos.fill(HIST("Prof2D_MeanpTSub_Reco"), cent, ietaA, ietaC, (sumWiptiReco[ietaA] + sumWiptiReco[ietaC]) / nRecoAB); } - if (sumWiRecoEffCorr[isp][ietaA] > 0) { - float val = sumWiptiRecoEffCorr[isp][ietaA] / sumWiRecoEffCorr[isp][ietaA]; - histos.fill(HIST("pmeanRecoEffcorr_nch_etabin_spbin"), multPV, ietaA, isp, val); - histos.fill(HIST("pmeanMultRecoEffcorr_nch_etabin_spbin"), multPV, ietaA, isp, sumWiRecoEffCorr[isp][ietaA]); + if (nCorrAB > 0) { + histos.fill(HIST("Prof2D_MeanpTSub_RecoEffCorr"), cent, ietaA, ietaC, (sumWiptiRecoEffCorr[ietaA] + sumWiptiRecoEffCorr[ietaC]) / nCorrAB); } } - } // end ietaA + if (sumWiTruth[ietaA] > 0) { + histos.fill(HIST("pmeanTru_nch_etabin"), multPV, ietaA, sumWiptiTruth[ietaA] / sumWiTruth[ietaA]); + histos.fill(HIST("pmeanMultTru_nch_etabin"), multPV, ietaA, sumWiTruth[ietaA]); + } + if (sumWiReco[ietaA] > 0) { + histos.fill(HIST("pmeanReco_nch_etabin"), multPV, ietaA, sumWiptiReco[ietaA] / sumWiReco[ietaA]); + histos.fill(HIST("pmeanMultReco_nch_etabin"), multPV, ietaA, sumWiReco[ietaA]); + } + if (sumWiRecoEffCorr[ietaA] > 0) { + histos.fill(HIST("pmeanRecoEffcorr_nch_etabin"), multPV, ietaA, sumWiptiRecoEffCorr[ietaA] / sumWiRecoEffCorr[ietaA]); + histos.fill(HIST("pmeanMultRecoEffcorr_nch_etabin"), multPV, ietaA, sumWiRecoEffCorr[ietaA]); + } + } + + // FT0 double amplFT0A = 0, amplFT0C = 0; if (mcCollision.has_foundFT0()) { const auto& ft0 = mcCollision.foundFT0(); @@ -2161,265 +1510,192 @@ struct RadialFlowDecorr { histos.fill(HIST("h3_cent_id_eta_FT0"), cent, globalId, eta, ampl); } } - histos.fill(HIST("pmeanFT0Amultpv"), multPV, amplFT0A); histos.fill(HIST("pmeanFT0A_cent"), cent, amplFT0A); histos.fill(HIST("pmeanFT0Cmultpv"), multPV, amplFT0C); histos.fill(HIST("pmeanFT0C_cent"), cent, amplFT0C); } - PROCESS_SWITCH(RadialFlowDecorr, processMCMean, "process MC to calculate mean pt and Eff Hists", cfgRunMCMean); + PROCESS_SWITCH(RadialFlowDecorr, processMCMean, "process MC to calculate mean pt", cfgRunMCMean); + // =========================================================================== + // MC: fluctuations (C2, subevent) at three levels + // =========================================================================== void processMCFluc(MyRun3MCCollisions::iterator const& mcCollision, FilteredTCs const& mcTracks, aod::FT0s const&, aod::McParticles const& mcParticles) { - if (!state.pmeanTruNchEtabinSpbinStep2 || !state.pmeanRecoNchEtabinSpbinStep2 || !state.pmeanRecoEffcorrNchEtabinSpbinStep2 || - !state.pmeanMultTruNchEtabinSpbinStep2 || !state.pmeanMultRecoNchEtabinSpbinStep2 || !state.pmeanMultRecoEffcorrNchEtabinSpbinStep2) { - LOGF(warning, "MC fluc: Unified Mean pT or Mult map missing"); + if (!state.pmeanTruNchEtabinStep2 || !state.pmeanRecoNchEtabinStep2 || !state.pmeanRecoEffcorrNchEtabinStep2 || + !state.pmeanMultTruNchEtabinStep2 || !state.pmeanMultRecoNchEtabinStep2 || !state.pmeanMultRecoEffcorrNchEtabinStep2) { + LOGF(warning, "MC fluc: mean pT or mult map missing"); return; } - double sumPmwkTru[KNsp][KNEta][KIntM][KIntK]{}; - double sumWkTru[KNsp][KNEta][KIntK]{}; - double sumPmwkReco[KNsp][KNEta][KIntM][KIntK]{}; - double sumWkReco[KNsp][KNEta][KIntK]{}; - double sumPmwkRecoEffCor[KNsp][KNEta][KIntM][KIntK]{}; - double sumWkRecoEffCor[KNsp][KNEta][KIntK]{}; - double meanTru[KNsp][KNEta]{}, c2Tru[KNsp][KNEta]{}; - double meanReco[KNsp][KNEta]{}, c2Reco[KNsp][KNEta]{}; - double meanRecoEffCor[KNsp][KNEta]{}, c2RecoEffCor[KNsp][KNEta]{}; + std::array, KIntM>, KNEtaMax> sumPmwkTru{}; + std::array, KNEtaMax> sumWkTru{}; + std::array, KIntM>, KNEtaMax> sumPmwkReco{}; + std::array, KNEtaMax> sumWkReco{}; + std::array, KIntM>, KNEtaMax> sumPmwkRecoEffCor{}; + std::array, KNEtaMax> sumWkRecoEffCor{}; - double meanTruMult[KNsp][KNEta]{}; - double meanRecoMult[KNsp][KNEta]{}; - double meanRecoEffCorMult[KNsp][KNEta]{}; + std::array meanTru{}, c2Tru{}, c3Tru{}; + std::array meanReco{}, c2Reco{}, c3Reco{}; + std::array meanRecoEffCor{}, c2RecoEffCor{}, c3RecoEffCor{}; - double p1kBarTru[KNsp][KNEta]{}, p1kBarReco[KNsp][KNEta]{}, p1kBarRecoEffCor[KNsp][KNEta]{}; - double p1kBarTruMult[KNsp][KNEta]{}, p1kBarRecoMult[KNsp][KNEta]{}, p1kBarRecoEffCorMult[KNsp][KNEta]{}; + std::array meanTruMult{}, meanRecoMult{}, meanRecoEffCorMult{}; + std::array p1kBarTru{}, p1kBarReco{}, p1kBarRecoEffCor{}; + std::array p1kBarTruMult{}, p1kBarRecoMult{}, p1kBarRecoEffCorMult{}; - if (!mcCollision.has_mcCollision() || !isEventSelected(mcCollision)) + if (!mcCollision.has_mcCollision() || !isEventSelected(mcCollision)) { return; + } float cent = getCentrality(mcCollision); - if (cent > KCentMax) + if (cent > KCentMax) { return; + } float multPV = mcCollision.multNTracksPV(); float vz = mcCollision.posZ(); - if (!isPassAddPileup(multPV, mcTracks.size(), cent)) + if (!isPassAddPileup(multPV, mcTracks.size(), cent)) { return; + } histos.fill(HIST("hVtxZ_after_sel"), mcCollision.posZ()); histos.fill(HIST("hCentrality"), cent); - histos.fill(HIST("Hist2D_globalTracks_PVTracks"), multPV, mcTracks.size()); histos.fill(HIST("Hist2D_cent_nch"), mcTracks.size(), cent); histos.fill(HIST("Hist2D_globalTracks_cent"), cent, mcTracks.size()); histos.fill(HIST("Hist2D_PVTracks_cent"), cent, multPV); - memset(sumPmwkTru, 0, sizeof(sumPmwkTru)); - memset(sumWkTru, 0, sizeof(sumWkTru)); - memset(sumPmwkReco, 0, sizeof(sumPmwkReco)); - memset(sumWkReco, 0, sizeof(sumWkReco)); - memset(sumPmwkRecoEffCor, 0, sizeof(sumPmwkRecoEffCor)); - memset(sumWkRecoEffCor, 0, sizeof(sumWkRecoEffCor)); - - memset(meanTru, 0, sizeof(meanTru)); - memset(c2Tru, 0, sizeof(c2Tru)); - memset(meanReco, 0, sizeof(meanReco)); - memset(c2Reco, 0, sizeof(c2Reco)); - memset(meanRecoEffCor, 0, sizeof(meanRecoEffCor)); - memset(c2RecoEffCor, 0, sizeof(c2RecoEffCor)); - - memset(meanTruMult, 0, sizeof(meanTruMult)); - memset(meanRecoMult, 0, sizeof(meanRecoMult)); - memset(meanRecoEffCorMult, 0, sizeof(meanRecoEffCorMult)); - - memset(p1kBarTru, 0, sizeof(p1kBarTru)); - memset(p1kBarReco, 0, sizeof(p1kBarReco)); - memset(p1kBarRecoEffCor, 0, sizeof(p1kBarRecoEffCor)); - - memset(p1kBarTruMult, 0, sizeof(p1kBarTruMult)); - memset(p1kBarRecoMult, 0, sizeof(p1kBarRecoMult)); - memset(p1kBarRecoEffCorMult, 0, sizeof(p1kBarRecoEffCorMult)); - double p1kBarFt0A = 0.0, p1kBarFt0C = 0.0; + // --- truth sums --- for (const auto& particle : mcParticles) { - if (particle.mcCollisionId() != mcCollision.mcCollisionId()) + if (particle.mcCollisionId() != mcCollision.mcCollisionId()) { continue; - - if (!isParticleSelected(particle) || !particle.isPhysicalPrimary()) + } + if (!isParticleSelected(particle) || !particle.isPhysicalPrimary()) { continue; - + } float pt = particle.pt(); - if (pt <= cfgPtMin || pt > cfgPtMax) + if (pt <= cfgPtMin || pt > cfgPtMax) { continue; + } float eta = particle.eta(); - int pdgCode = particle.pdgCode(); - int absPdg = std::abs(pdgCode); - - bool isSpecies[KNsp] = { - true, // kInclusiveIdx - pdgCode == -KPiPlus, // kPiMinusIdx - pdgCode == KPiPlus, // kPiPlusIdx - absPdg == KPiPlus, // kPiAllIdx - pdgCode == -KKPlus, // kKaMinusIdx - pdgCode == KKPlus, // kKaPlusIdx - absPdg == KKPlus, // kKaAllIdx - pdgCode == -KProton, // kAntiPrIdx - pdgCode == KProton, // kPrIdx - absPdg == KProton // kPrAllIdx - }; - - for (int ieta = 0; ieta < KNEta; ++ieta) { - if (eta <= etaLw[ieta] || eta > etaUp[ieta]) + for (int ieta = 0; ieta < nEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) { continue; - for (int isp = 0; isp < KNsp; ++isp) { - if (isSpecies[isp]) { - for (int k = 0; k < KIntK; ++k) { - for (int m = 0; m < KIntM; ++m) { - sumPmwkTru[isp][ieta][m][k] += std::pow(pt, m); - } - sumWkTru[isp][ieta][k]++; - } + } + for (int k = 0; k < KIntK; ++k) { + for (int m = 0; m < KIntM; ++m) { + sumPmwkTru[ieta][m][k] += std::pow(pt, m); } + sumWkTru[ieta][k]++; } } - } // end truth loop + } + // --- reco sums --- for (const auto& track : mcTracks) { - if (track.collisionId() != mcCollision.index()) + if (track.collisionId() != mcCollision.index()) { continue; - - if (!isTrackSelected(track)) + } + if (!isTrackSelected(track)) { continue; - + } float pt = track.pt(); - if (pt <= cfgPtMin || pt > cfgPtMax) + if (pt <= cfgPtMin || pt > cfgPtMax) { continue; - float eta = track.eta(); - float phi = track.phi(); + } + float eta = track.eta(), phi = track.phi(); auto sign = track.sign(); histos.fill(HIST("hPt"), pt); histos.fill(HIST("hEta"), eta); histos.fill(HIST("hPhi"), phi); - int id = identifyTrack(track, cent); - bool isPi = (id == KPidPionOne); - bool isKa = (id == KPidKaonTwo); - bool isPr = (id == KPidProtonThree); - bool isSpecies[KNsp] = { - true, - isPi && sign < 0, isPi && sign > 0, isPi, - isKa && sign < 0, isKa && sign > 0, isKa, - isPr && sign < 0, isPr && sign > 0, isPr}; - - for (int isp = 0; isp < KNsp; ++isp) { - if (!isSpecies[isp]) - continue; - float eff = getEfficiency(multPV, pt, eta, static_cast(isp), 0, cfgEff); - float fake = getEfficiency(multPV, pt, eta, static_cast(isp), 1, cfgEff); - float flatW = getFlatteningWeight(vz, sign, pt, eta, phi, static_cast(isp), cfgFlat); - float w = flatW * (1.0 - fake) / eff; + float eff = getEfficiency(multPV, pt, eta, 0, cfgEff); + float fake = getEfficiency(multPV, pt, eta, 1, cfgEff); + float flatW = getFlatteningWeight(vz, sign, pt, eta, phi, cfgFlat); + float w = flatW * (1.0 - fake) / eff; + if (!std::isfinite(w) || w <= 0.f || eff <= KFloatEpsilon) { + continue; + } - if (!std::isfinite(w) || w <= 0.f || eff <= KFloatEpsilon) + for (int ieta = 0; ieta < nEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) { continue; - - for (int ieta = 0; ieta < KNEta; ++ieta) { - if (eta <= etaLw[ieta] || eta > etaUp[ieta]) - continue; - for (int k = 0; k < KIntK; ++k) { - for (int m = 0; m < KIntM; ++m) { - sumPmwkReco[isp][ieta][m][k] += std::pow(1.0, k) * std::pow(pt, m); - sumPmwkRecoEffCor[isp][ieta][m][k] += std::pow(w, k) * std::pow(pt, m); - } - sumWkReco[isp][ieta][k] += std::pow(1.0, k); - sumWkRecoEffCor[isp][ieta][k] += std::pow(w, k); - } } - - if (isp == kInclusiveIdx) { - histos.fill(HIST("hEtaPhiReco"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoWtd"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("hEtaPhiRecoEffWtd"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); - } else if (isp == kPiMinusIdx) { - histos.fill(HIST("hEtaPhiReco_PiMinus"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoWtd_PiMinus"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("hEtaPhiRecoEffWtd_PiMinus"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); - } else if (isp == kPiPlusIdx) { - histos.fill(HIST("hEtaPhiReco_PiPlus"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoWtd_PiPlus"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("hEtaPhiRecoEffWtd_PiPlus"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); - } else if (isp == kPiAllIdx) { - histos.fill(HIST("hEtaPhiReco_PiAll"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoWtd_PiAll"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("hEtaPhiRecoEffWtd_PiAll"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); - } else if (isp == kKaMinusIdx) { - histos.fill(HIST("hEtaPhiReco_KaMinus"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoWtd_KaMinus"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("hEtaPhiRecoEffWtd_KaMinus"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); - } else if (isp == kKaPlusIdx) { - histos.fill(HIST("hEtaPhiReco_KaPlus"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoWtd_KaPlus"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("hEtaPhiRecoEffWtd_KaPlus"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); - } else if (isp == kKaAllIdx) { - histos.fill(HIST("hEtaPhiReco_KaAll"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoWtd_KaAll"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("hEtaPhiRecoEffWtd_KaAll"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); - } else if (isp == kPrIdx) { - histos.fill(HIST("hEtaPhiReco_Pr"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoWtd_Pr"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("hEtaPhiRecoEffWtd_Pr"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); - } else if (isp == kAntiPrIdx) { - histos.fill(HIST("hEtaPhiReco_AntiPr"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoWtd_AntiPr"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("hEtaPhiRecoEffWtd_AntiPr"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); - } else if (isp == kPrAllIdx) { - histos.fill(HIST("hEtaPhiReco_PrAll"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoWtd_PrAll"), vz, sign, pt, eta, phi, w); - histos.fill(HIST("hEtaPhiRecoEffWtd_PrAll"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + for (int k = 0; k < KIntK; ++k) { + for (int m = 0; m < KIntM; ++m) { + sumPmwkReco[ieta][m][k] += std::pow(1.0, k) * std::pow(pt, m); + sumPmwkRecoEffCor[ieta][m][k] += std::pow(w, k) * std::pow(pt, m); + } + sumWkReco[ieta][k] += std::pow(1.0, k); + sumWkRecoEffCor[ieta][k] += std::pow(w, k); } } - } // trkslice - if (!hasMinTracksInAllEtaBins(sumWkTru) || !hasMinTracksInAllEtaBins(sumWkReco)) - return; + histos.fill(HIST("hEtaPhiReco"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoWtd"), vz, sign, pt, eta, phi, w); + histos.fill(HIST("hEtaPhiRecoEffWtd"), vz, sign, pt, eta, phi, (1.0 - fake) / eff); + } - for (int ieta = 0; ieta < KNEta; ++ieta) { - const int ibx = state.pmeanTruNchEtabinSpbinStep2->GetXaxis()->FindBin(mcCollision.multNTracksPV()); + for (int ieta = 0; ieta < nEta; ++ieta) { + const int ibx = state.pmeanTruNchEtabinStep2->GetXaxis()->FindBin(multPV); const int iby = ieta + 1; - for (int isp = 0; isp < KNsp; ++isp) { - const int ibz = isp + 1; - - meanTruMult[isp][ieta] = sumWkTru[isp][ieta][1]; - meanRecoMult[isp][ieta] = sumWkReco[isp][ieta][1]; - meanRecoEffCorMult[isp][ieta] = sumWkRecoEffCor[isp][ieta][1]; - - float mmptTru = state.pmeanTruNchEtabinSpbinStep2->GetBinContent(ibx, iby, ibz); - float mmptReco = state.pmeanRecoNchEtabinSpbinStep2->GetBinContent(ibx, iby, ibz); - float mmptRecoEffCor = state.pmeanRecoEffcorrNchEtabinSpbinStep2->GetBinContent(ibx, iby, ibz); - - float mmMultTru = state.pmeanMultTruNchEtabinSpbinStep2->GetBinContent(ibx, iby, ibz); - float mmMultReco = state.pmeanMultRecoNchEtabinSpbinStep2->GetBinContent(ibx, iby, ibz); - float mmMultRecoEffCor = state.pmeanMultRecoEffcorrNchEtabinSpbinStep2->GetBinContent(ibx, iby, ibz); - - if (std::isfinite(mmptTru)) - std::tie(meanTru[isp][ieta], c2Tru[isp][ieta]) = calculateMeanAndC2FromSums(sumPmwkTru[isp][ieta], sumWkTru[isp][ieta], mmptTru); - if (std::isfinite(mmptReco)) - std::tie(meanReco[isp][ieta], c2Reco[isp][ieta]) = calculateMeanAndC2FromSums(sumPmwkReco[isp][ieta], sumWkReco[isp][ieta], mmptReco); - if (std::isfinite(mmptRecoEffCor)) - std::tie(meanRecoEffCor[isp][ieta], c2RecoEffCor[isp][ieta]) = calculateMeanAndC2FromSums(sumPmwkRecoEffCor[isp][ieta], sumWkRecoEffCor[isp][ieta], mmptRecoEffCor); - - if (mmptTru != 0.0f) - p1kBarTru[isp][ieta] = meanTru[isp][ieta] - mmptTru; - if (mmptReco != 0.0f) - p1kBarReco[isp][ieta] = meanReco[isp][ieta] - mmptReco; - if (mmptRecoEffCor != 0.0f) - p1kBarRecoEffCor[isp][ieta] = meanRecoEffCor[isp][ieta] - mmptRecoEffCor; - - if (mmMultTru != 0.0f) - p1kBarTruMult[isp][ieta] = meanTruMult[isp][ieta] - mmMultTru; - if (mmMultReco != 0.0f) - p1kBarRecoMult[isp][ieta] = meanRecoMult[isp][ieta] - mmMultReco; - if (mmMultRecoEffCor != 0.0f) - p1kBarRecoEffCorMult[isp][ieta] = meanRecoEffCorMult[isp][ieta] - mmMultRecoEffCor; + meanTruMult[ieta] = sumWkTru[ieta][1]; + meanRecoMult[ieta] = sumWkReco[ieta][1]; + meanRecoEffCorMult[ieta] = sumWkRecoEffCor[ieta][1]; + + float mmptTru = state.pmeanTruNchEtabinStep2->GetBinContent(ibx, iby); + float mmptReco = state.pmeanRecoNchEtabinStep2->GetBinContent(ibx, iby); + float mmptRecoEffCor = state.pmeanRecoEffcorrNchEtabinStep2->GetBinContent(ibx, iby); + + float mmMultTru = state.pmeanMultTruNchEtabinStep2->GetBinContent(ibx, iby); + float mmMultReco = state.pmeanMultRecoNchEtabinStep2->GetBinContent(ibx, iby); + float mmMultRecoEffCor = state.pmeanMultRecoEffcorrNchEtabinStep2->GetBinContent(ibx, iby); + + // covariance requires both bins populated: gate each multiplicity deviation on + // the same >=1-track condition as the mean, so cov skips unless both bins qualify + p1kBarTruMult[ieta] = (sumWkTru[ieta][1] >= 1.0) ? (meanTruMult[ieta] - mmMultTru) : std::numeric_limits::quiet_NaN(); + p1kBarRecoMult[ieta] = (sumWkReco[ieta][1] >= 1.0) ? (meanRecoMult[ieta] - mmMultReco) : std::numeric_limits::quiet_NaN(); + p1kBarRecoEffCorMult[ieta] = (sumWkRecoEffCor[ieta][1] >= 1.0) ? (meanRecoEffCorMult[ieta] - mmMultRecoEffCor) : std::numeric_limits::quiet_NaN(); + + // truth + meanTru[ieta] = (sumWkTru[ieta][1] >= 1.0) ? (sumPmwkTru[ieta][1][1] / sumWkTru[ieta][1]) : std::numeric_limits::quiet_NaN(); + c2Tru[ieta] = std::numeric_limits::quiet_NaN(); + c3Tru[ieta] = std::numeric_limits::quiet_NaN(); + p1kBarTru[ieta] = std::numeric_limits::quiet_NaN(); + if (std::isfinite(mmptTru) && mmptTru != 0) { + const auto corr = calculateC2C3FromSums(sumPmwkTru[ieta], sumWkTru[ieta], mmptTru); + c2Tru[ieta] = corr.c2; + c3Tru[ieta] = corr.c3; + if (std::isfinite(meanTru[ieta])) { + p1kBarTru[ieta] = meanTru[ieta] - mmptTru; + } + } + // reco + meanReco[ieta] = (sumWkReco[ieta][1] >= 1.0) ? (sumPmwkReco[ieta][1][1] / sumWkReco[ieta][1]) : std::numeric_limits::quiet_NaN(); + c2Reco[ieta] = std::numeric_limits::quiet_NaN(); + c3Reco[ieta] = std::numeric_limits::quiet_NaN(); + p1kBarReco[ieta] = std::numeric_limits::quiet_NaN(); + if (std::isfinite(mmptReco) && mmptReco != 0) { + const auto corr = calculateC2C3FromSums(sumPmwkReco[ieta], sumWkReco[ieta], mmptReco); + c2Reco[ieta] = corr.c2; + c3Reco[ieta] = corr.c3; + if (std::isfinite(meanReco[ieta])) { + p1kBarReco[ieta] = meanReco[ieta] - mmptReco; + } + } + // reco, efficiency-corrected + meanRecoEffCor[ieta] = (sumWkRecoEffCor[ieta][1] >= 1.0) ? (sumPmwkRecoEffCor[ieta][1][1] / sumWkRecoEffCor[ieta][1]) : std::numeric_limits::quiet_NaN(); + c2RecoEffCor[ieta] = std::numeric_limits::quiet_NaN(); + c3RecoEffCor[ieta] = std::numeric_limits::quiet_NaN(); + p1kBarRecoEffCor[ieta] = std::numeric_limits::quiet_NaN(); + if (std::isfinite(mmptRecoEffCor) && mmptRecoEffCor != 0) { + const auto corr = calculateC2C3FromSums(sumPmwkRecoEffCor[ieta], sumWkRecoEffCor[ieta], mmptRecoEffCor); + c2RecoEffCor[ieta] = corr.c2; + c3RecoEffCor[ieta] = corr.c3; + if (std::isfinite(meanRecoEffCor[ieta])) { + p1kBarRecoEffCor[ieta] = meanRecoEffCor[ieta] - mmptRecoEffCor; + } } } @@ -2427,586 +1703,289 @@ struct RadialFlowDecorr { if (mcCollision.has_foundFT0()) { const auto& ft0 = mcCollision.foundFT0(); for (std::size_t iCh = 0; iCh < ft0.channelA().size(); iCh++) { - float ampl = ft0.amplitudeA()[iCh]; - amplFT0A += ampl; + amplFT0A += ft0.amplitudeA()[iCh]; } for (std::size_t iCh = 0; iCh < ft0.channelC().size(); iCh++) { - float ampl = ft0.amplitudeC()[iCh]; - amplFT0C += ampl; + amplFT0C += ft0.amplitudeC()[iCh]; } } + p1kBarFt0A = amplFT0A - state.pmeanFT0AmultpvStep2->GetBinContent(state.pmeanFT0AmultpvStep2->GetXaxis()->FindBin(multPV)); + p1kBarFt0C = amplFT0C - state.pmeanFT0CmultpvStep2->GetBinContent(state.pmeanFT0CmultpvStep2->GetXaxis()->FindBin(multPV)); - for (int isp = 0; isp < KNsp; ++isp) { - for (int ieta = 0; ieta < KNEta; ++ieta) { - histos.fill(HIST("MCGen/Prof_Cent_NEta_Nsp_Nchrec"), cent, ieta, isp, sumWkTru[isp][ieta][1]); - histos.fill(HIST("MCGen/Prof_Mult_NEta_Nsp_Nchrec"), multPV, ieta, isp, sumWkTru[isp][ieta][1]); + // per-eta counts & means + for (int ieta = 0; ieta < nEta; ++ieta) { + histos.fill(HIST("MCGen/Prof_Cent_NEta_Nchrec"), cent, ieta, sumWkTru[ieta][1]); + histos.fill(HIST("MCGen/Prof_Mult_NEta_Nchrec"), multPV, ieta, sumWkTru[ieta][1]); + histos.fill(HIST("MCReco/Prof_Cent_NEta_Nchrec"), cent, ieta, sumWkReco[ieta][1]); + histos.fill(HIST("MCReco/Prof_Mult_NEta_Nchrec"), multPV, ieta, sumWkReco[ieta][1]); + histos.fill(HIST("MCRecoEffCorr/Prof_Cent_NEta_Nchrec"), cent, ieta, sumWkRecoEffCor[ieta][1]); + histos.fill(HIST("MCRecoEffCorr/Prof_Mult_NEta_Nchrec"), multPV, ieta, sumWkRecoEffCor[ieta][1]); + + if (sumWkTru[ieta][1] > 1.0f) { + histos.fill(HIST("MCGen/Prof_Cent_NEta_MeanpT"), cent, ieta, meanTru[ieta]); + histos.fill(HIST("MCGen/Prof_Mult_NEta_MeanpT"), multPV, ieta, meanTru[ieta]); + } + if (sumWkReco[ieta][1] > 1.0f) { + histos.fill(HIST("MCReco/Prof_Cent_NEta_MeanpT"), cent, ieta, meanReco[ieta]); + histos.fill(HIST("MCReco/Prof_Mult_NEta_MeanpT"), multPV, ieta, meanReco[ieta]); + } + if (sumWkRecoEffCor[ieta][1] > 1.0f) { + histos.fill(HIST("MCRecoEffCorr/Prof_Cent_NEta_MeanpT"), cent, ieta, meanRecoEffCor[ieta]); + histos.fill(HIST("MCRecoEffCorr/Prof_Mult_NEta_MeanpT"), multPV, ieta, meanRecoEffCor[ieta]); + } + } - histos.fill(HIST("MCReco/Prof_Cent_NEta_Nsp_Nchrec"), cent, ieta, isp, sumWkReco[isp][ieta][1]); - histos.fill(HIST("MCReco/Prof_Mult_NEta_Nsp_Nchrec"), multPV, ieta, isp, sumWkReco[isp][ieta][1]); + // meanpT & C2 vs eta bin + for (int ieta = 0; ieta < nEta; ++ieta) { + if (std::isfinite(meanTru[ieta])) { + histos.fill(HIST("MCGen/Prof_MeanpT_Cent_etabin"), cent, ieta, meanTru[ieta]); + histos.fill(HIST("MCGen/Prof_MeanpT_Mult_etabin"), multPV, ieta, meanTru[ieta]); + } + if (std::isfinite(c2Tru[ieta])) { + histos.fill(HIST("MCGen/Prof_C2_Cent_etabin"), cent, ieta, c2Tru[ieta]); + histos.fill(HIST("MCGen/Prof_C2_Mult_etabin"), multPV, ieta, c2Tru[ieta]); + } + if (std::isfinite(c3Tru[ieta])) { + histos.fill(HIST("MCGen/Prof_C3_Cent_etabin"), cent, ieta, c3Tru[ieta]); + histos.fill(HIST("MCGen/Prof_C3_Mult_etabin"), multPV, ieta, c3Tru[ieta]); + } + if (std::isfinite(meanReco[ieta])) { + histos.fill(HIST("MCReco/Prof_MeanpT_Cent_etabin"), cent, ieta, meanReco[ieta]); + histos.fill(HIST("MCReco/Prof_MeanpT_Mult_etabin"), multPV, ieta, meanReco[ieta]); + } + if (std::isfinite(c2Reco[ieta])) { + histos.fill(HIST("MCReco/Prof_C2_Cent_etabin"), cent, ieta, c2Reco[ieta]); + histos.fill(HIST("MCReco/Prof_C2_Mult_etabin"), multPV, ieta, c2Reco[ieta]); + } + if (std::isfinite(c3Reco[ieta])) { + histos.fill(HIST("MCReco/Prof_C3_Cent_etabin"), cent, ieta, c3Reco[ieta]); + histos.fill(HIST("MCReco/Prof_C3_Mult_etabin"), multPV, ieta, c3Reco[ieta]); + } + if (std::isfinite(meanRecoEffCor[ieta])) { + histos.fill(HIST("MCRecoEffCorr/Prof_MeanpT_Cent_etabin"), cent, ieta, meanRecoEffCor[ieta]); + histos.fill(HIST("MCRecoEffCorr/Prof_MeanpT_Mult_etabin"), multPV, ieta, meanRecoEffCor[ieta]); + } + if (std::isfinite(c2RecoEffCor[ieta])) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2_Cent_etabin"), cent, ieta, c2RecoEffCor[ieta]); + histos.fill(HIST("MCRecoEffCorr/Prof_C2_Mult_etabin"), multPV, ieta, c2RecoEffCor[ieta]); + } + if (std::isfinite(c3RecoEffCor[ieta])) { + histos.fill(HIST("MCRecoEffCorr/Prof_C3_Cent_etabin"), cent, ieta, c3RecoEffCor[ieta]); + histos.fill(HIST("MCRecoEffCorr/Prof_C3_Mult_etabin"), multPV, ieta, c3RecoEffCor[ieta]); + } + } - histos.fill(HIST("MCRecoEffCorr/Prof_Cent_NEta_Nsp_Nchrec"), cent, ieta, isp, sumWkRecoEffCor[isp][ieta][1]); - histos.fill(HIST("MCRecoEffCorr/Prof_Mult_NEta_Nsp_Nchrec"), multPV, ieta, isp, sumWkRecoEffCor[isp][ieta][1]); + // mirror-pair subevent (C2Sub) & covariances vs eta bin + for (int ietaA = 1; ietaA <= (nEta - 1) / 2; ++ietaA) { + int ietaC = nEta - ietaA; - if (sumWkTru[isp][ieta][1] > 1.0f) { - histos.fill(HIST("MCGen/Prof_Cent_NEta_Nsp_MeanpT"), cent, ieta, isp, meanTru[isp][ieta]); - histos.fill(HIST("MCGen/Prof_Mult_NEta_Nsp_MeanpT"), multPV, ieta, isp, meanTru[isp][ieta]); - } - if (sumWkReco[isp][ieta][1] > 1.0f) { - histos.fill(HIST("MCReco/Prof_Cent_NEta_Nsp_MeanpT"), cent, ieta, isp, meanReco[isp][ieta]); - histos.fill(HIST("MCReco/Prof_Mult_NEta_Nsp_MeanpT"), multPV, ieta, isp, meanReco[isp][ieta]); - } - if (sumWkRecoEffCor[isp][ieta][1] > 1.0f) { - histos.fill(HIST("MCRecoEffCorr/Prof_Cent_NEta_Nsp_MeanpT"), cent, ieta, isp, meanRecoEffCor[isp][ieta]); - histos.fill(HIST("MCRecoEffCorr/Prof_Mult_NEta_Nsp_MeanpT"), multPV, ieta, isp, meanRecoEffCor[isp][ieta]); - } + float c2SubTru = p1kBarTru[ietaA] * p1kBarTru[ietaC]; + float c2SubReco = p1kBarReco[ietaA] * p1kBarReco[ietaC]; + float c2SubRecoEffCor = p1kBarRecoEffCor[ietaA] * p1kBarRecoEffCor[ietaC]; + + float c3SubTruA = c2Tru[ietaA] * p1kBarTru[ietaC]; // 2 from A, 1 from C + float c3SubTruC = c2Tru[ietaC] * p1kBarTru[ietaA]; // 2 from C, 1 from A + float c3SubRecoA = c2Reco[ietaA] * p1kBarReco[ietaC]; + float c3SubRecoC = c2Reco[ietaC] * p1kBarReco[ietaA]; + float c3SubRecoEffCorA = c2RecoEffCor[ietaA] * p1kBarRecoEffCor[ietaC]; + float c3SubRecoEffCorC = c2RecoEffCor[ietaC] * p1kBarRecoEffCor[ietaA]; + + float covTru = p1kBarTruMult[ietaA] * p1kBarTru[ietaC]; + float covReco = p1kBarRecoMult[ietaA] * p1kBarReco[ietaC]; + float covRecoEffCor = p1kBarRecoEffCorMult[ietaA] * p1kBarRecoEffCor[ietaC]; + + if (std::isfinite(c2SubTru)) { + histos.fill(HIST("MCGen/Prof_C2Sub_Cent_etabin"), cent, ietaA, c2SubTru); + histos.fill(HIST("MCGen/Prof_C2Sub_Mult_etabin"), multPV, ietaA, c2SubTru); + } + if (std::isfinite(c2SubReco)) { + histos.fill(HIST("MCReco/Prof_C2Sub_Cent_etabin"), cent, ietaA, c2SubReco); + histos.fill(HIST("MCReco/Prof_C2Sub_Mult_etabin"), multPV, ietaA, c2SubReco); + } + if (std::isfinite(c2SubRecoEffCor)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub_Cent_etabin"), cent, ietaA, c2SubRecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub_Mult_etabin"), multPV, ietaA, c2SubRecoEffCor); + } + if (std::isfinite(c3SubTruA)) { + histos.fill(HIST("MCGen/Prof_C3Sub_Cent_etabin"), cent, ietaA, c3SubTruA); + histos.fill(HIST("MCGen/Prof_C3Sub_Mult_etabin"), multPV, ietaA, c3SubTruA); + } + if (std::isfinite(c3SubTruC)) { + histos.fill(HIST("MCGen/Prof_C3Sub_Cent_etabin"), cent, ietaC, c3SubTruC); + histos.fill(HIST("MCGen/Prof_C3Sub_Mult_etabin"), multPV, ietaC, c3SubTruC); + } + if (std::isfinite(c3SubRecoA)) { + histos.fill(HIST("MCReco/Prof_C3Sub_Cent_etabin"), cent, ietaA, c3SubRecoA); + histos.fill(HIST("MCReco/Prof_C3Sub_Mult_etabin"), multPV, ietaA, c3SubRecoA); + } + if (std::isfinite(c3SubRecoC)) { + histos.fill(HIST("MCReco/Prof_C3Sub_Cent_etabin"), cent, ietaC, c3SubRecoC); + histos.fill(HIST("MCReco/Prof_C3Sub_Mult_etabin"), multPV, ietaC, c3SubRecoC); + } + if (std::isfinite(c3SubRecoEffCorA)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C3Sub_Cent_etabin"), cent, ietaA, c3SubRecoEffCorA); + histos.fill(HIST("MCRecoEffCorr/Prof_C3Sub_Mult_etabin"), multPV, ietaA, c3SubRecoEffCorA); + } + if (std::isfinite(c3SubRecoEffCorC)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C3Sub_Cent_etabin"), cent, ietaC, c3SubRecoEffCorC); + histos.fill(HIST("MCRecoEffCorr/Prof_C3Sub_Mult_etabin"), multPV, ietaC, c3SubRecoEffCorC); + } + if (std::isfinite(covTru)) { + histos.fill(HIST("MCGen/Prof_Cov_Cent_etabin"), cent, ietaA, covTru); + histos.fill(HIST("MCGen/Prof_Cov_Mult_etabin"), multPV, ietaA, covTru); + } + if (std::isfinite(covReco)) { + histos.fill(HIST("MCReco/Prof_Cov_Cent_etabin"), cent, ietaA, covReco); + histos.fill(HIST("MCReco/Prof_Cov_Mult_etabin"), multPV, ietaA, covReco); + } + if (std::isfinite(covRecoEffCor)) { + histos.fill(HIST("MCRecoEffCorr/Prof_Cov_Cent_etabin"), cent, ietaA, covRecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_Cov_Mult_etabin"), multPV, ietaA, covRecoEffCor); } } - for (int ieta = 0; ieta < KNEta; ++ieta) { - for (int isp = 0; isp < KNsp; ++isp) { - if (std::isfinite(meanTru[isp][ieta])) { - histos.fill(HIST("MCGen/Prof_MeanpT_Cent_etabin_spbin"), cent, ieta, isp, meanTru[isp][ieta]); - histos.fill(HIST("MCGen/Prof_MeanpT_Mult_etabin_spbin"), multPV, ieta, isp, meanTru[isp][ieta]); - } - if (std::isfinite(c2Tru[isp][ieta])) { - histos.fill(HIST("MCGen/Prof_C2_Cent_etabin_spbin"), cent, ieta, isp, c2Tru[isp][ieta]); - histos.fill(HIST("MCGen/Prof_C2_Mult_etabin_spbin"), multPV, ieta, isp, c2Tru[isp][ieta]); - } - if (std::isfinite(meanReco[isp][ieta])) { - histos.fill(HIST("MCReco/Prof_MeanpT_Cent_etabin_spbin"), cent, ieta, isp, meanReco[isp][ieta]); - histos.fill(HIST("MCReco/Prof_MeanpT_Mult_etabin_spbin"), multPV, ieta, isp, meanReco[isp][ieta]); - } - if (std::isfinite(c2Reco[isp][ieta])) { - histos.fill(HIST("MCReco/Prof_C2_Cent_etabin_spbin"), cent, ieta, isp, c2Reco[isp][ieta]); - histos.fill(HIST("MCReco/Prof_C2_Mult_etabin_spbin"), multPV, ieta, isp, c2Reco[isp][ieta]); - } - if (std::isfinite(meanRecoEffCor[isp][ieta])) { - histos.fill(HIST("MCRecoEffCorr/Prof_MeanpT_Cent_etabin_spbin"), cent, ieta, isp, meanRecoEffCor[isp][ieta]); - histos.fill(HIST("MCRecoEffCorr/Prof_MeanpT_Mult_etabin_spbin"), multPV, ieta, isp, meanRecoEffCor[isp][ieta]); - } - if (std::isfinite(c2RecoEffCor[isp][ieta])) { - histos.fill(HIST("MCRecoEffCorr/Prof_C2_Cent_etabin_spbin"), cent, ieta, isp, c2RecoEffCor[isp][ieta]); - histos.fill(HIST("MCRecoEffCorr/Prof_C2_Mult_etabin_spbin"), multPV, ieta, isp, c2RecoEffCor[isp][ieta]); - } + // FT0 covariance vs narrow eta bin (full range, indexed by the actual pT bin) + for (int ieta = 1; ieta < nEta; ++ieta) { + float covFT0ATru = p1kBarFt0A * p1kBarTru[ieta]; + float covFT0AReco = p1kBarFt0A * p1kBarReco[ieta]; + float covFT0ARecoEffCor = p1kBarFt0A * p1kBarRecoEffCor[ieta]; + float covFT0CTru = p1kBarFt0C * p1kBarTru[ieta]; + float covFT0CReco = p1kBarFt0C * p1kBarReco[ieta]; + float covFT0CRecoEffCor = p1kBarFt0C * p1kBarRecoEffCor[ieta]; + + if (std::isfinite(covFT0ATru)) { + histos.fill(HIST("MCGen/Prof_CovFT0A_Cent_etabin"), cent, ieta, covFT0ATru); + histos.fill(HIST("MCGen/Prof_CovFT0A_Mult_etabin"), multPV, ieta, covFT0ATru); + } + if (std::isfinite(covFT0AReco)) { + histos.fill(HIST("MCReco/Prof_CovFT0A_Cent_etabin"), cent, ieta, covFT0AReco); + histos.fill(HIST("MCReco/Prof_CovFT0A_Mult_etabin"), multPV, ieta, covFT0AReco); + } + if (std::isfinite(covFT0ARecoEffCor)) { + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A_Cent_etabin"), cent, ieta, covFT0ARecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A_Mult_etabin"), multPV, ieta, covFT0ARecoEffCor); + } + if (std::isfinite(covFT0CTru)) { + histos.fill(HIST("MCGen/Prof_CovFT0C_Cent_etabin"), cent, ieta, covFT0CTru); + histos.fill(HIST("MCGen/Prof_CovFT0C_Mult_etabin"), multPV, ieta, covFT0CTru); + } + if (std::isfinite(covFT0CReco)) { + histos.fill(HIST("MCReco/Prof_CovFT0C_Cent_etabin"), cent, ieta, covFT0CReco); + histos.fill(HIST("MCReco/Prof_CovFT0C_Mult_etabin"), multPV, ieta, covFT0CReco); + } + if (std::isfinite(covFT0CRecoEffCor)) { + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C_Cent_etabin"), cent, ieta, covFT0CRecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C_Mult_etabin"), multPV, ieta, covFT0CRecoEffCor); } } - p1kBarFt0A = amplFT0A - state.pmeanFT0AmultpvStep2->GetBinContent(state.pmeanFT0AmultpvStep2->GetXaxis()->FindBin(multPV)); - p1kBarFt0C = amplFT0C - state.pmeanFT0CmultpvStep2->GetBinContent(state.pmeanFT0CmultpvStep2->GetXaxis()->FindBin(multPV)); + // full 2D subevent map + for (int ietaA = 1; ietaA < nEta; ++ietaA) { + for (int ietaC = 1; ietaC < nEta; ++ietaC) { + float etaValA = (etaLw[ietaA] + etaUp[ietaA]) / 2.0f; + float etaValB = (etaLw[ietaC] + etaUp[ietaC]) / 2.0f; + float gap = etaValA - etaValB; + float sum = (etaValA + etaValB); + + float c2SubTru = (ietaA == ietaC) ? static_cast(c2Tru[ietaA]) : p1kBarTru[ietaA] * p1kBarTru[ietaC]; + float c2SubReco = (ietaA == ietaC) ? static_cast(c2Reco[ietaA]) : p1kBarReco[ietaA] * p1kBarReco[ietaC]; + float c2SubRecoEffCor = (ietaA == ietaC) ? static_cast(c2RecoEffCor[ietaA]) : p1kBarRecoEffCor[ietaA] * p1kBarRecoEffCor[ietaC]; - for (int ietaA = 1; ietaA <= (KNEta - 1) / 2; ++ietaA) { - int ietaC = KNEta - ietaA; - for (int isp = 0; isp < KNsp; ++isp) { - float c2SubTru = p1kBarTru[isp][ietaA] * p1kBarTru[isp][ietaC]; - float c2SubReco = p1kBarReco[isp][ietaA] * p1kBarReco[isp][ietaC]; - float c2SubRecoEffCor = p1kBarRecoEffCor[isp][ietaA] * p1kBarRecoEffCor[isp][ietaC]; + float c3Sub2DTru = (ietaA == ietaC) ? static_cast(c3Tru[ietaA]) : c2Tru[ietaA] * p1kBarTru[ietaC]; // diag: within-bin c3; off-diag: 2 from A, 1 from C + float c3Sub2DReco = (ietaA == ietaC) ? static_cast(c3Reco[ietaA]) : c2Reco[ietaA] * p1kBarReco[ietaC]; + float c3Sub2DRecoEffCor = (ietaA == ietaC) ? static_cast(c3RecoEffCor[ietaA]) : c2RecoEffCor[ietaA] * p1kBarRecoEffCor[ietaC]; - float covTru = p1kBarTruMult[isp][ietaA] * p1kBarTru[isp][ietaC]; - float covReco = p1kBarRecoMult[isp][ietaA] * p1kBarReco[isp][ietaC]; - float covRecoEffCor = p1kBarRecoEffCorMult[isp][ietaA] * p1kBarRecoEffCor[isp][ietaC]; + float covTru = p1kBarTruMult[ietaA] * p1kBarTru[ietaC]; + float covReco = p1kBarRecoMult[ietaA] * p1kBarReco[ietaC]; + float covRecoEffCor = p1kBarRecoEffCorMult[ietaA] * p1kBarRecoEffCor[ietaC]; - float covFT0ATru = p1kBarFt0A * p1kBarTru[isp][ietaC]; - float covFT0AReco = p1kBarFt0A * p1kBarReco[isp][ietaC]; - float covFT0ARecoEffCor = p1kBarFt0A * p1kBarRecoEffCor[isp][ietaC]; + float covFT0ATru = p1kBarFt0A * p1kBarTru[ietaC]; + float covFT0AReco = p1kBarFt0A * p1kBarReco[ietaC]; + float covFT0ARecoEffCor = p1kBarFt0A * p1kBarRecoEffCor[ietaC]; - float covFT0CTru = p1kBarFt0C * p1kBarTru[isp][ietaA]; - float covFT0CReco = p1kBarFt0C * p1kBarReco[isp][ietaA]; - float covFT0CRecoEffCor = p1kBarFt0C * p1kBarRecoEffCor[isp][ietaA]; + float covFT0CTru = p1kBarFt0C * p1kBarTru[ietaA]; + float covFT0CReco = p1kBarFt0C * p1kBarReco[ietaA]; + float covFT0CRecoEffCor = p1kBarFt0C * p1kBarRecoEffCor[ietaA]; if (std::isfinite(c2SubTru)) { - histos.fill(HIST("MCGen/Prof_C2Sub_Cent_etabin_spbin"), cent, ietaA, isp, c2SubTru); - histos.fill(HIST("MCGen/Prof_C2Sub_Mult_etabin_spbin"), multPV, ietaA, isp, c2SubTru); + histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC"), cent, etaValA, etaValB, c2SubTru); + histos.fill(HIST("MCGen/Prof_GapSum2D"), cent, gap, sum, c2SubTru); } if (std::isfinite(c2SubReco)) { - histos.fill(HIST("MCReco/Prof_C2Sub_Cent_etabin_spbin"), cent, ietaA, isp, c2SubReco); - histos.fill(HIST("MCReco/Prof_C2Sub_Mult_etabin_spbin"), multPV, ietaA, isp, c2SubReco); + histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC"), cent, etaValA, etaValB, c2SubReco); + histos.fill(HIST("MCReco/Prof_GapSum2D"), cent, gap, sum, c2SubReco); } if (std::isfinite(c2SubRecoEffCor)) { - histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub_Cent_etabin_spbin"), cent, ietaA, isp, c2SubRecoEffCor); - histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub_Mult_etabin_spbin"), multPV, ietaA, isp, c2SubRecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC"), cent, etaValA, etaValB, c2SubRecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D"), cent, gap, sum, c2SubRecoEffCor); } + + if (std::isfinite(c3Sub2DTru)) { + histos.fill(HIST("MCGen/Prof_C3Sub2D_Cent_etaA_etaC"), cent, etaValA, etaValB, c3Sub2DTru); + histos.fill(HIST("MCGen/Prof_C3GapSum2D"), cent, gap, sum, c3Sub2DTru); + } + if (std::isfinite(c3Sub2DReco)) { + histos.fill(HIST("MCReco/Prof_C3Sub2D_Cent_etaA_etaC"), cent, etaValA, etaValB, c3Sub2DReco); + histos.fill(HIST("MCReco/Prof_C3GapSum2D"), cent, gap, sum, c3Sub2DReco); + } + if (std::isfinite(c3Sub2DRecoEffCor)) { + histos.fill(HIST("MCRecoEffCorr/Prof_C3Sub2D_Cent_etaA_etaC"), cent, etaValA, etaValB, c3Sub2DRecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_C3GapSum2D"), cent, gap, sum, c3Sub2DRecoEffCor); + } + if (std::isfinite(covTru)) { - histos.fill(HIST("MCGen/Prof_Cov_Cent_etabin_spbin"), cent, ietaA, isp, covTru); - histos.fill(HIST("MCGen/Prof_Cov_Mult_etabin_spbin"), multPV, ietaA, isp, covTru); + histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covTru); } if (std::isfinite(covReco)) { - histos.fill(HIST("MCReco/Prof_Cov_Cent_etabin_spbin"), cent, ietaA, isp, covReco); - histos.fill(HIST("MCReco/Prof_Cov_Mult_etabin_spbin"), multPV, ietaA, isp, covReco); + histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covReco); } if (std::isfinite(covRecoEffCor)) { - histos.fill(HIST("MCRecoEffCorr/Prof_Cov_Cent_etabin_spbin"), cent, ietaA, isp, covRecoEffCor); - histos.fill(HIST("MCRecoEffCorr/Prof_Cov_Mult_etabin_spbin"), multPV, ietaA, isp, covRecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covRecoEffCor); } if (std::isfinite(covFT0ATru)) { - histos.fill(HIST("MCGen/Prof_CovFT0A_Cent_etabin_spbin"), cent, ietaA, isp, covFT0ATru); - histos.fill(HIST("MCGen/Prof_CovFT0A_Mult_etabin_spbin"), multPV, ietaA, isp, covFT0ATru); + histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0ATru); } if (std::isfinite(covFT0AReco)) { - histos.fill(HIST("MCReco/Prof_CovFT0A_Cent_etabin_spbin"), cent, ietaA, isp, covFT0AReco); - histos.fill(HIST("MCReco/Prof_CovFT0A_Mult_etabin_spbin"), multPV, ietaA, isp, covFT0AReco); + histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0AReco); } if (std::isfinite(covFT0ARecoEffCor)) { - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A_Cent_etabin_spbin"), cent, ietaA, isp, covFT0ARecoEffCor); - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A_Mult_etabin_spbin"), multPV, ietaA, isp, covFT0ARecoEffCor); + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0ARecoEffCor); } if (std::isfinite(covFT0CTru)) { - histos.fill(HIST("MCGen/Prof_CovFT0C_Cent_etabin_spbin"), cent, ietaA, isp, covFT0CTru); - histos.fill(HIST("MCGen/Prof_CovFT0C_Mult_etabin_spbin"), multPV, ietaA, isp, covFT0CTru); + histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0CTru); } if (std::isfinite(covFT0CReco)) { - histos.fill(HIST("MCReco/Prof_CovFT0C_Cent_etabin_spbin"), cent, ietaA, isp, covFT0CReco); - histos.fill(HIST("MCReco/Prof_CovFT0C_Mult_etabin_spbin"), multPV, ietaA, isp, covFT0CReco); + histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0CReco); } if (std::isfinite(covFT0CRecoEffCor)) { - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C_Cent_etabin_spbin"), cent, ietaA, isp, covFT0CRecoEffCor); - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C_Mult_etabin_spbin"), multPV, ietaA, isp, covFT0CRecoEffCor); - } - } - } - - for (int ietaA = 1; ietaA < KNEta; ++ietaA) { - for (int ietaC = 1; ietaC < KNEta; ++ietaC) { - - float etaValA = (etaLw[ietaA] + etaUp[ietaA]) / 2.0f; - float etaValB = (etaLw[ietaC] + etaUp[ietaC]) / 2.0f; - float gap = etaValA - etaValB; - float sum = (etaValA + etaValB); - for (int isp = 0; isp < KNsp; ++isp) { - - float c2SubTru = (ietaA == ietaC) ? static_cast(c2Tru[isp][ietaA]) - : p1kBarTru[isp][ietaA] * p1kBarTru[isp][ietaC]; - float c2SubReco = (ietaA == ietaC) ? static_cast(c2Reco[isp][ietaA]) - : p1kBarReco[isp][ietaA] * p1kBarReco[isp][ietaC]; - float c2SubRecoEffCor = (ietaA == ietaC) ? static_cast(c2RecoEffCor[isp][ietaA]) - : p1kBarRecoEffCor[isp][ietaA] * p1kBarRecoEffCor[isp][ietaC]; - - float covTru = p1kBarTruMult[isp][ietaA] * p1kBarTru[isp][ietaC]; - float covReco = p1kBarRecoMult[isp][ietaA] * p1kBarReco[isp][ietaC]; - float covRecoEffCor = p1kBarRecoEffCorMult[isp][ietaA] * p1kBarRecoEffCor[isp][ietaC]; - - float covFT0ATru = p1kBarFt0A * p1kBarTru[isp][ietaC]; - float covFT0AReco = p1kBarFt0A * p1kBarReco[isp][ietaC]; - float covFT0ARecoEffCor = p1kBarFt0A * p1kBarRecoEffCor[isp][ietaC]; - - float covFT0CTru = p1kBarFt0C * p1kBarTru[isp][ietaA]; - float covFT0CReco = p1kBarFt0C * p1kBarReco[isp][ietaA]; - float covFT0CRecoEffCor = p1kBarFt0C * p1kBarRecoEffCor[isp][ietaA]; - - if (isp == kInclusiveIdx) { - if (std::isfinite(c2SubTru)) { - histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC"), cent, etaValA, etaValB, c2SubTru); - histos.fill(HIST("MCGen/Prof_GapSum2D"), cent, gap, sum, c2SubTru); - } - if (std::isfinite(c2SubReco)) { - histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC"), cent, etaValA, etaValB, c2SubReco); - histos.fill(HIST("MCReco/Prof_GapSum2D"), cent, gap, sum, c2SubReco); - } - if (std::isfinite(c2SubRecoEffCor)) { - histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC"), cent, etaValA, etaValB, c2SubRecoEffCor); - histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D"), cent, gap, sum, c2SubRecoEffCor); - } - - if (std::isfinite(covTru)) - histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covTru); - if (std::isfinite(covReco)) - histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covReco); - if (std::isfinite(covRecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covRecoEffCor); - - if (std::isfinite(covFT0ATru)) - histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0ATru); - if (std::isfinite(covFT0AReco)) - histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0AReco); - if (std::isfinite(covFT0ARecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0ARecoEffCor); - - if (std::isfinite(covFT0CTru)) - histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0CTru); - if (std::isfinite(covFT0CReco)) - histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0CReco); - if (std::isfinite(covFT0CRecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0CRecoEffCor); - - } else if (isp == kPiMinusIdx) { - if (std::isfinite(c2SubTru)) { - histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, c2SubTru); - histos.fill(HIST("MCGen/Prof_GapSum2D_PiMinus"), cent, gap, sum, c2SubTru); - } - if (std::isfinite(c2SubReco)) { - histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, c2SubReco); - histos.fill(HIST("MCReco/Prof_GapSum2D_PiMinus"), cent, gap, sum, c2SubReco); - } - if (std::isfinite(c2SubRecoEffCor)) { - histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, c2SubRecoEffCor); - histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D_PiMinus"), cent, gap, sum, c2SubRecoEffCor); - } - - if (std::isfinite(covTru)) - histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covTru); - if (std::isfinite(covReco)) - histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covReco); - if (std::isfinite(covRecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covRecoEffCor); - - if (std::isfinite(covFT0ATru)) - histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covFT0ATru); - if (std::isfinite(covFT0AReco)) - histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covFT0AReco); - if (std::isfinite(covFT0ARecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covFT0ARecoEffCor); - - if (std::isfinite(covFT0CTru)) - histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covFT0CTru); - if (std::isfinite(covFT0CReco)) - histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covFT0CReco); - if (std::isfinite(covFT0CRecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covFT0CRecoEffCor); - - } else if (isp == kPiPlusIdx) { - if (std::isfinite(c2SubTru)) { - histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, c2SubTru); - histos.fill(HIST("MCGen/Prof_GapSum2D_PiPlus"), cent, gap, sum, c2SubTru); - } - if (std::isfinite(c2SubReco)) { - histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, c2SubReco); - histos.fill(HIST("MCReco/Prof_GapSum2D_PiPlus"), cent, gap, sum, c2SubReco); - } - if (std::isfinite(c2SubRecoEffCor)) { - histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, c2SubRecoEffCor); - histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D_PiPlus"), cent, gap, sum, c2SubRecoEffCor); - } - - if (std::isfinite(covTru)) - histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covTru); - if (std::isfinite(covReco)) - histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covReco); - if (std::isfinite(covRecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covRecoEffCor); - - if (std::isfinite(covFT0ATru)) - histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covFT0ATru); - if (std::isfinite(covFT0AReco)) - histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covFT0AReco); - if (std::isfinite(covFT0ARecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covFT0ARecoEffCor); - - if (std::isfinite(covFT0CTru)) - histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covFT0CTru); - if (std::isfinite(covFT0CReco)) - histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covFT0CReco); - if (std::isfinite(covFT0CRecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covFT0CRecoEffCor); - - } else if (isp == kPiAllIdx) { - if (std::isfinite(c2SubTru)) { - histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, c2SubTru); - histos.fill(HIST("MCGen/Prof_GapSum2D_PiAll"), cent, gap, sum, c2SubTru); - } - if (std::isfinite(c2SubReco)) { - histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, c2SubReco); - histos.fill(HIST("MCReco/Prof_GapSum2D_PiAll"), cent, gap, sum, c2SubReco); - } - if (std::isfinite(c2SubRecoEffCor)) { - histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, c2SubRecoEffCor); - histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D_PiAll"), cent, gap, sum, c2SubRecoEffCor); - } - - if (std::isfinite(covTru)) - histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covTru); - if (std::isfinite(covReco)) - histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covReco); - if (std::isfinite(covRecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covRecoEffCor); - - if (std::isfinite(covFT0ATru)) - histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covFT0ATru); - if (std::isfinite(covFT0AReco)) - histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covFT0AReco); - if (std::isfinite(covFT0ARecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covFT0ARecoEffCor); - - if (std::isfinite(covFT0CTru)) - histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covFT0CTru); - if (std::isfinite(covFT0CReco)) - histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covFT0CReco); - if (std::isfinite(covFT0CRecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covFT0CRecoEffCor); - - } else if (isp == kKaMinusIdx) { - if (std::isfinite(c2SubTru)) { - histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, c2SubTru); - histos.fill(HIST("MCGen/Prof_GapSum2D_KaMinus"), cent, gap, sum, c2SubTru); - } - if (std::isfinite(c2SubReco)) { - histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, c2SubReco); - histos.fill(HIST("MCReco/Prof_GapSum2D_KaMinus"), cent, gap, sum, c2SubReco); - } - if (std::isfinite(c2SubRecoEffCor)) { - histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, c2SubRecoEffCor); - histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D_KaMinus"), cent, gap, sum, c2SubRecoEffCor); - } - - if (std::isfinite(covTru)) - histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covTru); - if (std::isfinite(covReco)) - histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covReco); - if (std::isfinite(covRecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covRecoEffCor); - - if (std::isfinite(covFT0ATru)) - histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covFT0ATru); - if (std::isfinite(covFT0AReco)) - histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covFT0AReco); - if (std::isfinite(covFT0ARecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covFT0ARecoEffCor); - - if (std::isfinite(covFT0CTru)) - histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covFT0CTru); - if (std::isfinite(covFT0CReco)) - histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covFT0CReco); - if (std::isfinite(covFT0CRecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covFT0CRecoEffCor); - - } else if (isp == kKaPlusIdx) { - if (std::isfinite(c2SubTru)) { - histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, c2SubTru); - histos.fill(HIST("MCGen/Prof_GapSum2D_KaPlus"), cent, gap, sum, c2SubTru); - } - if (std::isfinite(c2SubReco)) { - histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, c2SubReco); - histos.fill(HIST("MCReco/Prof_GapSum2D_KaPlus"), cent, gap, sum, c2SubReco); - } - if (std::isfinite(c2SubRecoEffCor)) { - histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, c2SubRecoEffCor); - histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D_KaPlus"), cent, gap, sum, c2SubRecoEffCor); - } - - if (std::isfinite(covTru)) - histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covTru); - if (std::isfinite(covReco)) - histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covReco); - if (std::isfinite(covRecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covRecoEffCor); - - if (std::isfinite(covFT0ATru)) - histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covFT0ATru); - if (std::isfinite(covFT0AReco)) - histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covFT0AReco); - if (std::isfinite(covFT0ARecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covFT0ARecoEffCor); - - if (std::isfinite(covFT0CTru)) - histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covFT0CTru); - if (std::isfinite(covFT0CReco)) - histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covFT0CReco); - if (std::isfinite(covFT0CRecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covFT0CRecoEffCor); - - } else if (isp == kKaAllIdx) { - if (std::isfinite(c2SubTru)) { - histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, c2SubTru); - histos.fill(HIST("MCGen/Prof_GapSum2D_KaAll"), cent, gap, sum, c2SubTru); - } - if (std::isfinite(c2SubReco)) { - histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, c2SubReco); - histos.fill(HIST("MCReco/Prof_GapSum2D_KaAll"), cent, gap, sum, c2SubReco); - } - if (std::isfinite(c2SubRecoEffCor)) { - histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, c2SubRecoEffCor); - histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D_KaAll"), cent, gap, sum, c2SubRecoEffCor); - } - - if (std::isfinite(covTru)) - histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covTru); - if (std::isfinite(covReco)) - histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covReco); - if (std::isfinite(covRecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covRecoEffCor); - - if (std::isfinite(covFT0ATru)) - histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covFT0ATru); - if (std::isfinite(covFT0AReco)) - histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covFT0AReco); - if (std::isfinite(covFT0ARecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covFT0ARecoEffCor); - - if (std::isfinite(covFT0CTru)) - histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covFT0CTru); - if (std::isfinite(covFT0CReco)) - histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covFT0CReco); - if (std::isfinite(covFT0CRecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covFT0CRecoEffCor); - - } else if (isp == kPrIdx) { - if (std::isfinite(c2SubTru)) { - histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, c2SubTru); - histos.fill(HIST("MCGen/Prof_GapSum2D_Pr"), cent, gap, sum, c2SubTru); - } - if (std::isfinite(c2SubReco)) { - histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, c2SubReco); - histos.fill(HIST("MCReco/Prof_GapSum2D_Pr"), cent, gap, sum, c2SubReco); - } - if (std::isfinite(c2SubRecoEffCor)) { - histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, c2SubRecoEffCor); - histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D_Pr"), cent, gap, sum, c2SubRecoEffCor); - } - - if (std::isfinite(covTru)) - histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covTru); - if (std::isfinite(covReco)) - histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covReco); - if (std::isfinite(covRecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covRecoEffCor); - - if (std::isfinite(covFT0ATru)) - histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covFT0ATru); - if (std::isfinite(covFT0AReco)) - histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covFT0AReco); - if (std::isfinite(covFT0ARecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covFT0ARecoEffCor); - - if (std::isfinite(covFT0CTru)) - histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covFT0CTru); - if (std::isfinite(covFT0CReco)) - histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covFT0CReco); - if (std::isfinite(covFT0CRecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covFT0CRecoEffCor); - - } else if (isp == kAntiPrIdx) { - if (std::isfinite(c2SubTru)) { - histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, c2SubTru); - histos.fill(HIST("MCGen/Prof_GapSum2D_AntiPr"), cent, gap, sum, c2SubTru); - } - if (std::isfinite(c2SubReco)) { - histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, c2SubReco); - histos.fill(HIST("MCReco/Prof_GapSum2D_AntiPr"), cent, gap, sum, c2SubReco); - } - if (std::isfinite(c2SubRecoEffCor)) { - histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, c2SubRecoEffCor); - histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D_AntiPr"), cent, gap, sum, c2SubRecoEffCor); - } - - if (std::isfinite(covTru)) - histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covTru); - if (std::isfinite(covReco)) - histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covReco); - if (std::isfinite(covRecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covRecoEffCor); - - if (std::isfinite(covFT0ATru)) - histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covFT0ATru); - if (std::isfinite(covFT0AReco)) - histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covFT0AReco); - if (std::isfinite(covFT0ARecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covFT0ARecoEffCor); - - if (std::isfinite(covFT0CTru)) - histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covFT0CTru); - if (std::isfinite(covFT0CReco)) - histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covFT0CReco); - if (std::isfinite(covFT0CRecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covFT0CRecoEffCor); - - } else if (isp == kPrAllIdx) { - if (std::isfinite(c2SubTru)) { - histos.fill(HIST("MCGen/Prof_C2Sub2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, c2SubTru); - histos.fill(HIST("MCGen/Prof_GapSum2D_PrAll"), cent, gap, sum, c2SubTru); - } - if (std::isfinite(c2SubReco)) { - histos.fill(HIST("MCReco/Prof_C2Sub2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, c2SubReco); - histos.fill(HIST("MCReco/Prof_GapSum2D_PrAll"), cent, gap, sum, c2SubReco); - } - if (std::isfinite(c2SubRecoEffCor)) { - histos.fill(HIST("MCRecoEffCorr/Prof_C2Sub2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, c2SubRecoEffCor); - histos.fill(HIST("MCRecoEffCorr/Prof_GapSum2D_PrAll"), cent, gap, sum, c2SubRecoEffCor); - } - - if (std::isfinite(covTru)) - histos.fill(HIST("MCGen/Prof_Cov2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covTru); - if (std::isfinite(covReco)) - histos.fill(HIST("MCReco/Prof_Cov2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covReco); - if (std::isfinite(covRecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_Cov2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covRecoEffCor); - - if (std::isfinite(covFT0ATru)) - histos.fill(HIST("MCGen/Prof_CovFT0A2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covFT0ATru); - if (std::isfinite(covFT0AReco)) - histos.fill(HIST("MCReco/Prof_CovFT0A2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covFT0AReco); - if (std::isfinite(covFT0ARecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0A2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covFT0ARecoEffCor); - - if (std::isfinite(covFT0CTru)) - histos.fill(HIST("MCGen/Prof_CovFT0C2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covFT0CTru); - if (std::isfinite(covFT0CReco)) - histos.fill(HIST("MCReco/Prof_CovFT0C2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covFT0CReco); - if (std::isfinite(covFT0CRecoEffCor)) - histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covFT0CRecoEffCor); - } + histos.fill(HIST("MCRecoEffCorr/Prof_CovFT0C2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0CRecoEffCor); } } } } PROCESS_SWITCH(RadialFlowDecorr, processMCFluc, "process MC to calculate pt fluc", cfgRunMCFluc); - void processDataGetNSig(AodCollisionsSel::iterator const& coll, BCsRun3 const& /*bcs*/, aod::Zdcs const& /*zdcsData*/, AodTracksSel const& tracks) - { - histos.fill(HIST("hVtxZ"), coll.posZ()); - if (!isEventSelected(coll)) - return; - float cent = getCentrality(coll); - if (cent > KCentMax) - return; - histos.fill(HIST("hVtxZ_after_sel"), coll.posZ()); - histos.fill(HIST("hCentrality"), cent); - - histos.fill(HIST("Hist2D_globalTracks_PVTracks"), coll.multNTracksPV(), tracks.size()); - histos.fill(HIST("Hist2D_cent_nch"), tracks.size(), cent); - histos.fill(HIST("Hist2D_globalTracks_cent"), cent, tracks.size()); - histos.fill(HIST("Hist2D_PVTracks_cent"), cent, coll.multNTracksPV()); - - int ntrk = 0; - for (const auto& track : tracks) { - if (!isTrackSelected(track)) - continue; - float pt = track.pt(); - if (pt <= cfgPtMin || pt > cfgPtMax) - continue; - float eta = track.eta(); - if (eta > etaLw[0] && eta < etaUp[0]) - ntrk++; - fillNSigmaBefCut(track, cent); - } - - if (cfgZDC) { - const auto& foundBC = coll.foundBC_as(); - if (!foundBC.has_zdc()) { - return; - } - auto zdc = foundBC.zdc(); - auto zdcAmp = zdc.energyCommonZNA() + zdc.energyCommonZNC(); - histos.fill(HIST("hnTrkPVZDC"), coll.multNTracksPV(), zdcAmp); - histos.fill(HIST("hNchZDC"), ntrk, zdcAmp); - } - } - PROCESS_SWITCH(RadialFlowDecorr, processDataGetNSig, "process data to Get Nsigma cuts", cfgRunDataGetNSig); - + // =========================================================================== + // DATA: build flattening maps (inclusive) + // =========================================================================== void processGetDataFlat(AodCollisionsSel::iterator const& coll, BCsRun3 const& /*bcs*/, aod::Zdcs const& /*zdcsData*/, AodTracksSel const& tracks) { histos.fill(HIST("hVtxZ"), coll.posZ()); - if (!isEventSelected(coll)) + if (!isEventSelected(coll)) { return; + } float cent = getCentrality(coll); - if (cent > KCentMax) + if (cent > KCentMax) { return; - - if (!isPassAddPileup(coll.multNTracksPV(), tracks.size(), cent)) + } + if (!isPassAddPileup(coll.multNTracksPV(), tracks.size(), cent)) { return; + } histos.fill(HIST("hVtxZ_after_sel"), coll.posZ()); histos.fill(HIST("hCentrality"), cent); - histos.fill(HIST("Hist2D_globalTracks_PVTracks"), coll.multNTracksPV(), tracks.size()); histos.fill(HIST("Hist2D_cent_nch"), tracks.size(), cent); histos.fill(HIST("Hist2D_globalTracks_cent"), cent, tracks.size()); @@ -3016,88 +1995,36 @@ struct RadialFlowDecorr { float vz = coll.posZ(); for (const auto& track : tracks) { - if (!isTrackSelected(track)) + if (!isTrackSelected(track)) { continue; + } float pt = track.pt(); - if (pt <= cfgPtMin || pt > cfgPtMax) + if (pt <= cfgPtMin || pt > cfgPtMax) { continue; - float eta = track.eta(); - float phi = track.phi(); + } + float eta = track.eta(), phi = track.phi(); auto sign = track.sign(); histos.fill(HIST("hPt"), pt); histos.fill(HIST("hEta"), eta); histos.fill(HIST("hPhi"), phi); - - if (eta > etaLw[0] && eta < etaUp[0]) + if (eta > etaLw[0] && eta < etaUp[0]) { ntrk++; - fillNSigmaBefCut(track, cent); - int id = identifyTrack(track, cent); - bool isPi = (id == KPidPionOne); - bool isKa = (id == KPidKaonTwo); - bool isPr = (id == KPidProtonThree); - bool isSpecies[KNsp] = { - true, - isPi && sign < 0, isPi && sign > 0, isPi, - isKa && sign < 0, isKa && sign > 0, isKa, - isPr && sign < 0, isPr && sign > 0, isPr}; - - fillNSigmaAftCut(track, cent, isSpecies); - for (int isp = 0; isp < KNsp; ++isp) { - if (!isSpecies[isp]) - continue; - float eff = getEfficiency(coll.multNTracksPV(), pt, eta, static_cast(isp), 0, cfgEff); - if (eff <= KFloatEpsilon) - continue; - - float fake = getEfficiency(coll.multNTracksPV(), pt, eta, static_cast(isp), 1, cfgEff); - float w = (1.0f - fake) / eff; - - if (!std::isfinite(w) || w <= 0.f) - continue; + } - if (isp == kInclusiveIdx) { - histos.fill(HIST("hEtaPhiReco"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); - histos.fill(HIST("hEtaPhiRecoWtd"), vz, sign, pt, eta, phi, w); - } else if (isp == kPiMinusIdx) { - histos.fill(HIST("hEtaPhiReco_PiMinus"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd_PiMinus"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); - histos.fill(HIST("hEtaPhiRecoWtd_PiMinus"), vz, sign, pt, eta, phi, w); - } else if (isp == kPiPlusIdx) { - histos.fill(HIST("hEtaPhiReco_PiPlus"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd_PiPlus"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); - histos.fill(HIST("hEtaPhiRecoWtd_PiPlus"), vz, sign, pt, eta, phi, w); - } else if (isp == kPiAllIdx) { - histos.fill(HIST("hEtaPhiReco_PiAll"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd_PiAll"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); - histos.fill(HIST("hEtaPhiRecoWtd_PiAll"), vz, sign, pt, eta, phi, w); - } else if (isp == kKaMinusIdx) { - histos.fill(HIST("hEtaPhiReco_KaMinus"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd_KaMinus"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); - histos.fill(HIST("hEtaPhiRecoWtd_KaMinus"), vz, sign, pt, eta, phi, w); - } else if (isp == kKaPlusIdx) { - histos.fill(HIST("hEtaPhiReco_KaPlus"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd_KaPlus"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); - histos.fill(HIST("hEtaPhiRecoWtd_KaPlus"), vz, sign, pt, eta, phi, w); - } else if (isp == kKaAllIdx) { - histos.fill(HIST("hEtaPhiReco_KaAll"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd_KaAll"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); - histos.fill(HIST("hEtaPhiRecoWtd_KaAll"), vz, sign, pt, eta, phi, w); - } else if (isp == kPrIdx) { - histos.fill(HIST("hEtaPhiReco_Pr"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd_Pr"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); - histos.fill(HIST("hEtaPhiRecoWtd_Pr"), vz, sign, pt, eta, phi, w); - } else if (isp == kAntiPrIdx) { - histos.fill(HIST("hEtaPhiReco_AntiPr"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd_AntiPr"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); - histos.fill(HIST("hEtaPhiRecoWtd_AntiPr"), vz, sign, pt, eta, phi, w); - } else if (isp == kPrAllIdx) { - histos.fill(HIST("hEtaPhiReco_PrAll"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd_PrAll"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); - histos.fill(HIST("hEtaPhiRecoWtd_PrAll"), vz, sign, pt, eta, phi, w); - } + float eff = getEfficiency(coll.multNTracksPV(), pt, eta, 0, cfgEff); + if (eff <= KFloatEpsilon) { + continue; + } + float fake = getEfficiency(coll.multNTracksPV(), pt, eta, 1, cfgEff); + float w = (1.0f - fake) / eff; + if (!std::isfinite(w) || w <= 0.f) { + continue; } + + histos.fill(HIST("hEtaPhiReco"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd"), vz, sign, pt, eta, phi, w); } if (cfgZDC) { @@ -3113,23 +2040,26 @@ struct RadialFlowDecorr { } PROCESS_SWITCH(RadialFlowDecorr, processGetDataFlat, "process data to calculate Flattening maps", cfgRunGetDataFlat); + // =========================================================================== + // DATA: mean pT + // =========================================================================== void processDataMean(AodCollisionsSel::iterator const& coll, BCsRun3 const& /*bcs*/, aod::Zdcs const& /*zdcsData*/, aod::FT0s const&, AodTracksSel const& tracks) { - double sumWi[KNsp][KNEta]{}, sumWipti[KNsp][KNEta]{}; + std::array sumWi{}, sumWipti{}; - if (!isEventSelected(coll)) + if (!isEventSelected(coll)) { return; - + } float cent = getCentrality(coll); - if (cent > KCentMax) + if (cent > KCentMax) { return; - - if (!isPassAddPileup(coll.multNTracksPV(), tracks.size(), cent)) + } + if (!isPassAddPileup(coll.multNTracksPV(), tracks.size(), cent)) { return; + } histos.fill(HIST("hVtxZ_after_sel"), coll.posZ()); histos.fill(HIST("hCentrality"), cent); - histos.fill(HIST("Hist2D_globalTracks_PVTracks"), coll.multNTracksPV(), tracks.size()); histos.fill(HIST("Hist2D_cent_nch"), tracks.size(), cent); histos.fill(HIST("Hist2D_globalTracks_cent"), cent, tracks.size()); @@ -3138,154 +2068,84 @@ struct RadialFlowDecorr { float vz = coll.posZ(); for (const auto& track : tracks) { - if (!isTrackSelected(track)) + if (!isTrackSelected(track)) { continue; - + } float p = track.p(); float pt = track.pt(); - float eta = track.eta(); - float phi = track.phi(); + float eta = track.eta(), phi = track.phi(); auto sign = track.sign(); - - if (p < KFloatEpsilon) + if (p < KFloatEpsilon) { continue; - - if (pt <= cfgPtMin || pt > cfgPtMax) + } + if (pt <= cfgPtMin || pt > cfgPtMax) { continue; + } histos.fill(HIST("hP"), p); histos.fill(HIST("hPt"), pt); histos.fill(HIST("hEta"), eta); histos.fill(HIST("hPhi"), phi); - int id = identifyTrack(track, cent); - bool isPi = (id == KPidPionOne); - bool isKa = (id == KPidKaonTwo); - bool isPr = (id == KPidProtonThree); - bool isSpecies[KNsp] = { - true, - isPi && sign < 0, isPi && sign > 0, isPi, - isKa && sign < 0, isKa && sign > 0, isKa, - isPr && sign < 0, isPr && sign > 0, isPr}; - - for (int isp = 0; isp < KNsp; ++isp) { - if (!isSpecies[isp]) - continue; - float eff = getEfficiency(coll.multNTracksPV(), pt, eta, static_cast(isp), 0, cfgEff); - if (eff <= KFloatEpsilon) - continue; - float fake = getEfficiency(coll.multNTracksPV(), pt, eta, static_cast(isp), 1, cfgEff); - float flatWeight = getFlatteningWeight(vz, sign, pt, eta, phi, static_cast(isp), cfgFlat); - float w = flatWeight * (1.0f - fake) / eff; + float eff = getEfficiency(coll.multNTracksPV(), pt, eta, 0, cfgEff); + float fake = getEfficiency(coll.multNTracksPV(), pt, eta, 1, cfgEff); + float flatWeight = getFlatteningWeight(vz, sign, pt, eta, phi, cfgFlat); - if (!std::isfinite(w) || w <= 0.f) - continue; + histos.fill(HIST("pEffWeight_pt_eta_cent"), pt, eta, cent, eff); + histos.fill(HIST("pFakeWeight_pt_eta_cent"), pt, eta, cent, fake); + histos.fill(HIST("pFlatWeight_pt_eta_cent"), pt, eta, cent, flatWeight); - if (isp == kInclusiveIdx) { - histos.fill(HIST("hEtaPhiReco"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); - histos.fill(HIST("hEtaPhiRecoWtd"), vz, sign, pt, eta, phi, w); - } else if (isp == kPiMinusIdx) { - histos.fill(HIST("hEtaPhiReco_PiMinus"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd_PiMinus"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); - histos.fill(HIST("hEtaPhiRecoWtd_PiMinus"), vz, sign, pt, eta, phi, w); - } else if (isp == kPiPlusIdx) { - histos.fill(HIST("hEtaPhiReco_PiPlus"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd_PiPlus"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); - histos.fill(HIST("hEtaPhiRecoWtd_PiPlus"), vz, sign, pt, eta, phi, w); - } else if (isp == kPiAllIdx) { - histos.fill(HIST("hEtaPhiReco_PiAll"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd_PiAll"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); - histos.fill(HIST("hEtaPhiRecoWtd_PiAll"), vz, sign, pt, eta, phi, w); - } else if (isp == kKaMinusIdx) { - histos.fill(HIST("hEtaPhiReco_KaMinus"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd_KaMinus"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); - histos.fill(HIST("hEtaPhiRecoWtd_KaMinus"), vz, sign, pt, eta, phi, w); - } else if (isp == kKaPlusIdx) { - histos.fill(HIST("hEtaPhiReco_KaPlus"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd_KaPlus"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); - histos.fill(HIST("hEtaPhiRecoWtd_KaPlus"), vz, sign, pt, eta, phi, w); - } else if (isp == kKaAllIdx) { - histos.fill(HIST("hEtaPhiReco_KaAll"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd_KaAll"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); - histos.fill(HIST("hEtaPhiRecoWtd_KaAll"), vz, sign, pt, eta, phi, w); - } else if (isp == kPrIdx) { - histos.fill(HIST("hEtaPhiReco_Pr"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd_Pr"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); - histos.fill(HIST("hEtaPhiRecoWtd_Pr"), vz, sign, pt, eta, phi, w); - } else if (isp == kAntiPrIdx) { - histos.fill(HIST("hEtaPhiReco_AntiPr"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd_AntiPr"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); - histos.fill(HIST("hEtaPhiRecoWtd_AntiPr"), vz, sign, pt, eta, phi, w); - } else if (isp == kPrAllIdx) { - histos.fill(HIST("hEtaPhiReco_PrAll"), vz, sign, pt, eta, phi); - histos.fill(HIST("hEtaPhiRecoEffWtd_PrAll"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); - histos.fill(HIST("hEtaPhiRecoWtd_PrAll"), vz, sign, pt, eta, phi, w); - } + if (eff <= KFloatEpsilon) { + continue; + } + + float w = flatWeight * (1.0f - fake) / eff; + if (!std::isfinite(w) || w <= 0.f) { + continue; + } - for (int ieta = 0; ieta < KNEta; ++ieta) { - if (eta <= etaLw[ieta] || eta > etaUp[ieta]) - continue; - sumWi[isp][ieta] += w; - sumWipti[isp][ieta] += w * pt; + histos.fill(HIST("hEtaPhiReco"), vz, sign, pt, eta, phi); + histos.fill(HIST("hEtaPhiRecoEffWtd"), vz, sign, pt, eta, phi, (1.0f - fake) / eff); + histos.fill(HIST("hEtaPhiRecoWtd"), vz, sign, pt, eta, phi, w); + + for (int ieta = 0; ieta < nEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) { + continue; } + sumWi[ieta] += w; + sumWipti[ieta] += w * pt; } } - if (!hasMinTracksInAllEtaBins(sumWi)) - return; + if (sumWi[0] >= 1.0f) { + histos.fill(HIST("Prof_Cent_Nchrec"), cent, sumWi[0]); + histos.fill(HIST("Prof_Mult_Nchrec"), coll.multNTracksPV(), sumWi[0]); + histos.fill(HIST("Prof_Cent_MeanpT"), cent, sumWipti[0] / sumWi[0]); + histos.fill(HIST("Prof_Mult_MeanpT"), coll.multNTracksPV(), sumWipti[0] / sumWi[0]); + } - for (int isp = 0; isp < KNsp; ++isp) { - if (sumWi[isp][0] < 1.0f) - continue; - histos.fill(HIST("Prof_Cent_Nsp_Nchrec"), cent, isp, sumWi[isp][0]); - histos.fill(HIST("Prof_Mult_Nsp_Nchrec"), coll.multNTracksPV(), isp, sumWi[isp][0]); - histos.fill(HIST("Prof_Cent_Nsp_MeanpT"), cent, isp, sumWipti[isp][0] / sumWi[isp][0]); - histos.fill(HIST("Prof_Mult_Nsp_MeanpT"), coll.multNTracksPV(), isp, sumWipti[isp][0] / sumWi[isp][0]); - } - - for (int ietaA = 0; ietaA < KNEta; ++ietaA) { - for (int ietaC = 0; ietaC < KNEta; ++ietaC) { - for (int isp = 0; isp < KNsp; ++isp) { - if ((sumWi[isp][ietaA] < 1.0f) || (sumWi[isp][ietaC] < 1.0f)) - continue; - - double wCorrAB = sumWi[isp][ietaA] + sumWi[isp][ietaC]; - if (wCorrAB > 0) { - float mptsub = (sumWipti[isp][ietaA] + sumWipti[isp][ietaC]) / wCorrAB; - if (isp == kInclusiveIdx) - histos.fill(HIST("Prof2D_MeanpTSub"), cent, ietaA, ietaC, mptsub); - else if (isp == kPiMinusIdx) - histos.fill(HIST("Prof2D_MeanpTSub_PiMinus"), cent, ietaA, ietaC, mptsub); - else if (isp == kPiPlusIdx) - histos.fill(HIST("Prof2D_MeanpTSub_PiPlus"), cent, ietaA, ietaC, mptsub); - else if (isp == kPiAllIdx) - histos.fill(HIST("Prof2D_MeanpTSub_PiAll"), cent, ietaA, ietaC, mptsub); - else if (isp == kKaMinusIdx) - histos.fill(HIST("Prof2D_MeanpTSub_KaMinus"), cent, ietaA, ietaC, mptsub); - else if (isp == kKaPlusIdx) - histos.fill(HIST("Prof2D_MeanpTSub_KaPlus"), cent, ietaA, ietaC, mptsub); - else if (isp == kKaAllIdx) - histos.fill(HIST("Prof2D_MeanpTSub_KaAll"), cent, ietaA, ietaC, mptsub); - else if (isp == kPrIdx) - histos.fill(HIST("Prof2D_MeanpTSub_Pr"), cent, ietaA, ietaC, mptsub); - else if (isp == kAntiPrIdx) - histos.fill(HIST("Prof2D_MeanpTSub_AntiPr"), cent, ietaA, ietaC, mptsub); - else if (isp == kPrAllIdx) - histos.fill(HIST("Prof2D_MeanpTSub_PrAll"), cent, ietaA, ietaC, mptsub); - } - if (ietaA == ietaC) { - double mpt = sumWipti[isp][ietaA] / sumWi[isp][ietaA]; - if (sumWi[isp][ietaA] >= 1.0f && std::isfinite(mpt)) { - histos.fill(HIST("pmean_nch_etabin_spbin"), coll.multNTracksPV(), ietaA, isp, mpt); - histos.fill(HIST("pmeanMult_nch_etabin_spbin"), coll.multNTracksPV(), ietaA, isp, sumWi[isp][ietaA]); - histos.fill(HIST("pmean_cent_etabin_spbin"), cent, ietaA, isp, mpt); - histos.fill(HIST("pmeanMult_cent_etabin_spbin"), cent, ietaA, isp, sumWi[isp][ietaA]); - } - } + for (int ietaA = 0; ietaA < nEta; ++ietaA) { + for (int ietaC = 0; ietaC < nEta; ++ietaC) { + if ((sumWi[ietaA] < 1.0f) || (sumWi[ietaC] < 1.0f)) { + continue; + } + double wCorrAB = sumWi[ietaA] + sumWi[ietaC]; + if (wCorrAB > 0) { + float mptsub = (sumWipti[ietaA] + sumWipti[ietaC]) / wCorrAB; + histos.fill(HIST("Prof2D_MeanpTSub"), cent, ietaA, ietaC, mptsub); + } + } + if (sumWi[ietaA] >= 1.0f) { + double mpt = sumWipti[ietaA] / sumWi[ietaA]; + if (std::isfinite(mpt)) { + histos.fill(HIST("pmean_nch_etabin"), coll.multNTracksPV(), ietaA, mpt); + histos.fill(HIST("pmeanMult_nch_etabin"), coll.multNTracksPV(), ietaA, sumWi[ietaA]); + histos.fill(HIST("pmean_cent_etabin"), cent, ietaA, mpt); + histos.fill(HIST("pmeanMult_cent_etabin"), cent, ietaA, sumWi[ietaA]); } } } + double amplFT0A = 0, amplFT0C = 0; if (coll.has_foundFT0()) { const auto& ft0 = coll.foundFT0(); @@ -3301,13 +2161,12 @@ struct RadialFlowDecorr { auto chanelid = ft0.channelC()[iCh]; auto globalId = chanelid + KnFt0cCell; float ampl = ft0.amplitudeC()[iCh]; - auto eta = getEtaFT0(globalId, 1); amplFT0C += ampl; + auto eta = getEtaFT0(globalId, 1); histos.fill(HIST("pmean_cent_id_eta_FT0"), cent, globalId, eta, ampl); histos.fill(HIST("h3_cent_id_eta_FT0"), cent, globalId, eta, ampl); } } - histos.fill(HIST("pmeanFT0Amultpv"), coll.multNTracksPV(), amplFT0A); histos.fill(HIST("pmeanFT0A_cent"), cent, amplFT0A); histos.fill(HIST("pmeanFT0Cmultpv"), coll.multNTracksPV(), amplFT0C); @@ -3315,310 +2174,286 @@ struct RadialFlowDecorr { } PROCESS_SWITCH(RadialFlowDecorr, processDataMean, "process data to calculate mean pT", cfgRunDataMean); + // =========================================================================== + // DATA: fluctuations (C2, subevent) + Poisson bootstrap for the base run + // =========================================================================== void processDataFluc(AodCollisionsSel::iterator const& coll, BCsRun3 const& /*bcs*/, aod::Zdcs const& /*zdcsData*/, aod::FT0s const&, AodTracksSel const& tracks) { - if (!isEventSelected(coll)) + if (!isEventSelected(coll)) { return; + } float cent = getCentrality(coll); - if (cent > KCentMax) + if (cent > KCentMax) { return; - - if (!isPassAddPileup(coll.multNTracksPV(), tracks.size(), cent)) + } + if (!isPassAddPileup(coll.multNTracksPV(), tracks.size(), cent)) { return; + } histos.fill(HIST("hVtxZ_after_sel"), coll.posZ()); histos.fill(HIST("hCentrality"), cent); - histos.fill(HIST("Hist2D_globalTracks_PVTracks"), coll.multNTracksPV(), tracks.size()); histos.fill(HIST("Hist2D_cent_nch"), tracks.size(), cent); histos.fill(HIST("Hist2D_globalTracks_cent"), cent, tracks.size()); histos.fill(HIST("Hist2D_PVTracks_cent"), cent, coll.multNTracksPV()); - if (!state.pmeanNchEtabinSpbinStep2 || !state.pmeanMultNchEtabinSpbinStep2) { - LOGF(warning, "Data fluc: Mean pT or Mult map missing"); + if (!state.pmeanNchEtabinStep2 || !state.pmeanMultNchEtabinStep2) { + LOGF(warning, "Data fluc: mean pT or mult map missing"); return; } - - for (int isp = 0; isp < KNsp; ++isp) { - auto pid = static_cast(isp); - if (!state.hEff[pid] || !state.hFake[pid] || !state.hFlatWeight[pid]) { - LOGF(warning, "Data fluc: Correction maps (Eff, Fake, or Flat) are null for species index %d", isp); - return; - } + if ((cfgEff || cfgFlat) && (!state.hEff || !state.hFake || !state.hFlatWeight)) { + LOGF(warning, "Data fluc: correction maps requested but not all present."); + return; } - double sumpmwk[KNsp][KNEta][KIntM][KIntK]{}; - double sumwk[KNsp][KNEta][KIntK]{}; + std::array, KIntM>, KNEtaMax> sumpmwk{}; + std::array, KNEtaMax> sumwk{}; + std::array mean{}, c2{}, c3{}, p1kBar{}; + std::array meanMult{}, p1kBarMult{}; - double mean[KNsp][KNEta]{}, c2[KNsp][KNEta]{}; - double p1kBar[KNsp][KNEta]{}; - double meanMult[KNsp][KNEta]{}, p1kBarMult[KNsp][KNEta]{}; + // --- Poisson bootstrap: one weight per sample per event --- + std::array poisW{}; + if (doBoot) { + for (int s = 0; s < nBoot; ++s) { + poisW[s] = rng.Poisson(1.0); + } + } + auto fillBS1D = [&](std::array, KMaxBoot>& arr, double x, double val) { + if (!doBoot) { + return; + } + for (int s = 0; s < nBoot; ++s) { + arr[s]->Fill(x, val, poisW[s]); + } + }; + auto fillBS2D = [&](std::array, KMaxBoot>& arr, double x, double y, double val) { + if (!doBoot) { + return; + } + for (int s = 0; s < nBoot; ++s) { + arr[s]->Fill(x, y, val, poisW[s]); + } + }; + auto fillBS3D = [&](std::array, KMaxBoot>& arr, double x, double y, double z, double val) { + if (!doBoot) { + return; + } + for (int s = 0; s < nBoot; ++s) { + arr[s]->Fill(x, y, z, val, poisW[s]); + } + }; float vz = coll.posZ(); for (const auto& track : tracks) { - if (!isTrackSelected(track)) + if (!isTrackSelected(track)) { continue; - + } float p = track.p(); float pt = track.pt(); - float eta = track.eta(); - float phi = track.phi(); + float eta = track.eta(), phi = track.phi(); auto sign = track.sign(); - - if (p < KFloatEpsilon) + if (p < KFloatEpsilon) { continue; - - if (pt <= cfgPtMin || pt > cfgPtMax) + } + if (pt <= cfgPtMin || pt > cfgPtMax) { continue; - int id = identifyTrack(track, cent); - bool isPi = (id == KPidPionOne); - bool isKa = (id == KPidKaonTwo); - bool isPr = (id == KPidProtonThree); - bool isSpecies[KNsp] = { - true, - isPi && sign < 0, isPi && sign > 0, isPi, - isKa && sign < 0, isKa && sign > 0, isKa, - isPr && sign < 0, isPr && sign > 0, isPr}; - - for (int isp = 0; isp < KNsp; ++isp) { - if (!isSpecies[isp]) - continue; - float eff = getEfficiency(coll.multNTracksPV(), pt, eta, static_cast(isp), 0, cfgEff); - if (eff <= KFloatEpsilon) - continue; + } - float fake = getEfficiency(coll.multNTracksPV(), pt, eta, static_cast(isp), 1, cfgEff); - float flatWeight = getFlatteningWeight(vz, sign, pt, eta, phi, static_cast(isp), cfgFlat); - float w = flatWeight * (1.0f - fake) / eff; + float eff = getEfficiency(coll.multNTracksPV(), pt, eta, 0, cfgEff); + if (eff <= KFloatEpsilon) { + continue; + } + float fake = getEfficiency(coll.multNTracksPV(), pt, eta, 1, cfgEff); + float flatWeight = getFlatteningWeight(vz, sign, pt, eta, phi, cfgFlat); + float w = flatWeight * (1.0f - fake) / eff; + if (!std::isfinite(w) || w <= 0.f) { + continue; + } - if (!std::isfinite(w) || w <= 0.f) + for (int ieta = 0; ieta < nEta; ++ieta) { + if (eta <= etaLw[ieta] || eta > etaUp[ieta]) { continue; - - for (int ieta = 0; ieta < KNEta; ++ieta) { - if (eta <= etaLw[ieta] || eta > etaUp[ieta]) - continue; - for (int k = 0; k < KIntK; ++k) { - for (int m = 0; m < KIntM; ++m) { - sumpmwk[isp][ieta][m][k] += std::pow(w, k) * std::pow(pt, m); - } - sumwk[isp][ieta][k] += std::pow(w, k); + } + for (int k = 0; k < KIntK; ++k) { + for (int m = 0; m < KIntM; ++m) { + sumpmwk[ieta][m][k] += std::pow(w, k) * std::pow(pt, m); } + sumwk[ieta][k] += std::pow(w, k); } } } - if (!hasMinTracksInAllEtaBins(sumwk)) - return; - double amplFT0A = 0, amplFT0C = 0; if (coll.has_foundFT0()) { const auto& ft0 = coll.foundFT0(); for (std::size_t iCh = 0; iCh < ft0.channelA().size(); iCh++) { - float ampl = ft0.amplitudeA()[iCh]; - amplFT0A += ampl; + amplFT0A += ft0.amplitudeA()[iCh]; } for (std::size_t iCh = 0; iCh < ft0.channelC().size(); iCh++) { - float ampl = ft0.amplitudeC()[iCh]; - amplFT0C += ampl; + amplFT0C += ft0.amplitudeC()[iCh]; } } + fillBS1D(bs.amplFT0ACent, cent, amplFT0A); + fillBS1D(bs.amplFT0AMult, coll.multNTracksPV(), amplFT0A); + fillBS1D(bs.amplFT0CCent, cent, amplFT0C); + fillBS1D(bs.amplFT0CMult, coll.multNTracksPV(), amplFT0C); + double p1kBarFt0A = amplFT0A - state.pmeanFT0AmultpvStep2->GetBinContent(state.pmeanFT0AmultpvStep2->GetXaxis()->FindBin(coll.multNTracksPV())); double p1kBarFt0C = amplFT0C - state.pmeanFT0CmultpvStep2->GetBinContent(state.pmeanFT0CmultpvStep2->GetXaxis()->FindBin(coll.multNTracksPV())); - for (int ieta = 0; ieta < KNEta; ++ieta) { - const int ibx = state.pmeanNchEtabinSpbinStep2->GetXaxis()->FindBin(coll.multNTracksPV()); + for (int ieta = 0; ieta < nEta; ++ieta) { + const int ibx = state.pmeanNchEtabinStep2->GetXaxis()->FindBin(coll.multNTracksPV()); const int iby = ieta + 1; - for (int isp = 0; isp < KNsp; ++isp) { - const int ibz = isp + 1; + float mmpt = state.pmeanNchEtabinStep2->GetBinContent(ibx, iby); + float mmMult = state.pmeanMultNchEtabinStep2->GetBinContent(ibx, iby); + + meanMult[ieta] = sumwk[ieta][1]; + // covariance requires both bins populated: gate the multiplicity deviation on + // the same >=1-track condition as the mean, so cov skips unless both bins qualify + p1kBarMult[ieta] = (sumwk[ieta][1] >= 1.0) ? (meanMult[ieta] - mmMult) : std::numeric_limits::quiet_NaN(); + + // mean pT of the bin: valid only with >=1 (weighted) track + mean[ieta] = (sumwk[ieta][1] >= 1.0) ? (sumpmwk[ieta][1][1] / sumwk[ieta][1]) : std::numeric_limits::quiet_NaN(); + + // c2 (>=2 tracks), c3 (>=3 tracks) and the pT deviation need a usable reference + c2[ieta] = std::numeric_limits::quiet_NaN(); + c3[ieta] = std::numeric_limits::quiet_NaN(); + p1kBar[ieta] = std::numeric_limits::quiet_NaN(); + if (std::isfinite(mmpt) && mmpt != 0) { + const auto corr = calculateC2C3FromSums(sumpmwk[ieta], sumwk[ieta], mmpt); + c2[ieta] = corr.c2; + c3[ieta] = corr.c3; + if (std::isfinite(mean[ieta])) { + p1kBar[ieta] = mean[ieta] - mmpt; + } + } + } - float mmpt = state.pmeanNchEtabinSpbinStep2->GetBinContent(ibx, iby, ibz); - float mmMult = state.pmeanMultNchEtabinSpbinStep2->GetBinContent(ibx, iby, ibz); + // meanpT & C2 vs eta bin + for (int ieta = 0; ieta < nEta; ++ieta) { + if (std::isfinite(meanMult[ieta])) { + fillBS2D(bs.multCent, cent, ieta, meanMult[ieta]); + fillBS2D(bs.multMult, coll.multNTracksPV(), ieta, meanMult[ieta]); + } - mean[isp][ieta] = sumpmwk[isp][ieta][1][1] / sumwk[isp][ieta][1]; - meanMult[isp][ieta] = sumwk[isp][ieta][1]; + if (std::isfinite(mean[ieta])) { + histos.fill(HIST("Prof_MeanpT_Cent_etabin"), cent, ieta, mean[ieta]); + histos.fill(HIST("Prof_MeanpT_Mult_etabin"), coll.multNTracksPV(), ieta, mean[ieta]); + fillBS2D(bs.meanpTCent, cent, ieta, mean[ieta]); + fillBS2D(bs.meanpTMult, coll.multNTracksPV(), ieta, mean[ieta]); + } + if (std::isfinite(c2[ieta])) { + histos.fill(HIST("Prof_C2_Cent_etabin"), cent, ieta, c2[ieta]); + histos.fill(HIST("Prof_C2_Mult_etabin"), coll.multNTracksPV(), ieta, c2[ieta]); + fillBS2D(bs.c2Cent, cent, ieta, c2[ieta]); + fillBS2D(bs.c2Mult, coll.multNTracksPV(), ieta, c2[ieta]); + } + if (std::isfinite(c3[ieta])) { + histos.fill(HIST("Prof_C3_Cent_etabin"), cent, ieta, c3[ieta]); + histos.fill(HIST("Prof_C3_Mult_etabin"), coll.multNTracksPV(), ieta, c3[ieta]); + fillBS2D(bs.c3Cent, cent, ieta, c3[ieta]); + fillBS2D(bs.c3Mult, coll.multNTracksPV(), ieta, c3[ieta]); + } + } - if (std::isfinite(mmpt)) { - std::tie(mean[isp][ieta], c2[isp][ieta]) = calculateMeanAndC2FromSums(sumpmwk[isp][ieta], sumwk[isp][ieta], mmpt); - p1kBar[isp][ieta] = mean[isp][ieta] - mmpt; - } - p1kBarMult[isp][ieta] = meanMult[isp][ieta] - mmMult; + // mirror-pair subevent (C2Sub) & covariances vs eta bin + for (int ietaA = 1; ietaA <= (nEta - 1) / 2; ++ietaA) { + int ietaC = nEta - ietaA; + float c2Sub = p1kBar[ietaA] * p1kBar[ietaC]; + float c3SubA = c2[ietaA] * p1kBar[ietaC]; // 2 particles from A, 1 from C + float c3SubC = c2[ietaC] * p1kBar[ietaA]; // 2 particles from C, 1 from A + float covAC = p1kBarMult[ietaA] * p1kBar[ietaC]; + float covCA = p1kBar[ietaA] * p1kBarMult[ietaC]; + + if (std::isfinite(c2Sub)) { + histos.fill(HIST("Prof_C2Sub_Cent_etabin"), cent, ietaA, c2Sub); + histos.fill(HIST("Prof_C2Sub_Mult_etabin"), coll.multNTracksPV(), ietaA, c2Sub); + fillBS2D(bs.c2SubCent, cent, ietaA, c2Sub); + fillBS2D(bs.c2SubMult, coll.multNTracksPV(), ietaA, c2Sub); + } + if (std::isfinite(c3SubA)) { + histos.fill(HIST("Prof_C3Sub_Cent_etabin"), cent, ietaA, c3SubA); + histos.fill(HIST("Prof_C3Sub_Mult_etabin"), coll.multNTracksPV(), ietaA, c3SubA); + fillBS2D(bs.c3SubCent, cent, ietaA, c3SubA); + fillBS2D(bs.c3SubMult, coll.multNTracksPV(), ietaA, c3SubA); + } + if (std::isfinite(c3SubC)) { + histos.fill(HIST("Prof_C3Sub_Cent_etabin"), cent, ietaC, c3SubC); + histos.fill(HIST("Prof_C3Sub_Mult_etabin"), coll.multNTracksPV(), ietaC, c3SubC); + fillBS2D(bs.c3SubCent, cent, ietaC, c3SubC); + fillBS2D(bs.c3SubMult, coll.multNTracksPV(), ietaC, c3SubC); + } + if (std::isfinite(covAC)) { + histos.fill(HIST("Prof_Cov_Cent_etabin"), cent, ietaA, covAC); + histos.fill(HIST("Prof_Cov_Mult_etabin"), coll.multNTracksPV(), ietaA, covAC); + fillBS2D(bs.covCent, cent, ietaA, covAC); + fillBS2D(bs.covMult, coll.multNTracksPV(), ietaA, covAC); + } + if (std::isfinite(covCA)) { + histos.fill(HIST("Prof_Cov_Cent_etabin"), cent, ietaC, covCA); + histos.fill(HIST("Prof_Cov_Mult_etabin"), coll.multNTracksPV(), ietaC, covCA); + fillBS2D(bs.covCent, cent, ietaC, covCA); + fillBS2D(bs.covMult, coll.multNTracksPV(), ietaC, covCA); } } - for (int ieta = 0; ieta < KNEta; ++ieta) { - for (int isp = 0; isp < KNsp; ++isp) { - if (std::isfinite(mean[isp][ieta])) { - histos.fill(HIST("Prof_MeanpT_Cent_etabin_spbin"), cent, ieta, isp, mean[isp][ieta]); - histos.fill(HIST("Prof_MeanpT_Mult_etabin_spbin"), coll.multNTracksPV(), ieta, isp, mean[isp][ieta]); - } - if (std::isfinite(c2[isp][ieta])) { - histos.fill(HIST("Prof_C2_Cent_etabin_spbin"), cent, ieta, isp, c2[isp][ieta]); - histos.fill(HIST("Prof_C2_Mult_etabin_spbin"), coll.multNTracksPV(), ieta, isp, c2[isp][ieta]); - } + + // FT0 covariance vs narrow eta bin (full range, indexed by the actual pT bin) + for (int ieta = 1; ieta < nEta; ++ieta) { + float covFT0Aeta = p1kBarFt0A * p1kBar[ieta]; + float covFT0Ceta = p1kBarFt0C * p1kBar[ieta]; + if (std::isfinite(covFT0Aeta)) { + histos.fill(HIST("Prof_CovFT0A_Cent_etabin"), cent, ieta, covFT0Aeta); + histos.fill(HIST("Prof_CovFT0A_Mult_etabin"), coll.multNTracksPV(), ieta, covFT0Aeta); + fillBS2D(bs.covFT0ACent, cent, ieta, covFT0Aeta); + fillBS2D(bs.covFT0AMult, coll.multNTracksPV(), ieta, covFT0Aeta); + } + if (std::isfinite(covFT0Ceta)) { + histos.fill(HIST("Prof_CovFT0C_Cent_etabin"), cent, ieta, covFT0Ceta); + histos.fill(HIST("Prof_CovFT0C_Mult_etabin"), coll.multNTracksPV(), ieta, covFT0Ceta); + fillBS2D(bs.covFT0CCent, cent, ieta, covFT0Ceta); + fillBS2D(bs.covFT0CMult, coll.multNTracksPV(), ieta, covFT0Ceta); } } - for (int ietaA = 1; ietaA <= (KNEta - 1) / 2; ++ietaA) { - int ietaC = KNEta - ietaA; - for (int isp = 0; isp < KNsp; ++isp) { - float c2Sub = p1kBar[isp][ietaA] * p1kBar[isp][ietaC]; - float covAC = p1kBarMult[isp][ietaA] * p1kBar[isp][ietaC]; - float covCA = p1kBar[isp][ietaA] * p1kBarMult[isp][ietaC]; + // full 2D subevent map + for (int ietaA = 1; ietaA < nEta; ++ietaA) { + for (int ietaC = 1; ietaC < nEta; ++ietaC) { + float etaValA = (etaLw[ietaA] + etaUp[ietaA]) / 2.0f; + float etaValB = (etaLw[ietaC] + etaUp[ietaC]) / 2.0f; + float gap = etaValA - etaValB; + float sum = (etaValA + etaValB); - float covFT0A = p1kBarFt0A * p1kBar[isp][ietaC]; - float covFT0C = p1kBarFt0C * p1kBar[isp][ietaA]; + float c2Sub = (ietaA == ietaC) ? static_cast(c2[ietaA]) : p1kBar[ietaA] * p1kBar[ietaC]; + float c3Sub2D = (ietaA == ietaC) ? static_cast(c3[ietaA]) : c2[ietaA] * p1kBar[ietaC]; // diag: within-bin c3; off-diag: 2 from A, 1 from C + float cov = p1kBarMult[ietaA] * p1kBar[ietaC]; + float covFT0A = p1kBarFt0A * p1kBar[ietaC]; + float covFT0C = p1kBarFt0C * p1kBar[ietaA]; if (std::isfinite(c2Sub)) { - histos.fill(HIST("Prof_C2Sub_Cent_etabin_spbin"), cent, ietaA, isp, c2Sub); - histos.fill(HIST("Prof_C2Sub_Mult_etabin_spbin"), coll.multNTracksPV(), ietaA, isp, c2Sub); + histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC"), cent, etaValA, etaValB, c2Sub); + histos.fill(HIST("Prof_GapSum2D"), cent, gap, sum, c2Sub); + fillBS3D(bs.c2Sub2D, cent, etaValA, etaValB, c2Sub); + fillBS3D(bs.gapSum2D, cent, gap, sum, c2Sub); } - if (std::isfinite(covAC)) { - histos.fill(HIST("Prof_Cov_Cent_etabin_spbin"), cent, ietaA, isp, covAC); - histos.fill(HIST("Prof_Cov_Mult_etabin_spbin"), coll.multNTracksPV(), ietaA, isp, covAC); + if (std::isfinite(c3Sub2D)) { + histos.fill(HIST("Prof_C3Sub2D_Cent_etaA_etaC"), cent, etaValA, etaValB, c3Sub2D); + histos.fill(HIST("Prof_C3GapSum2D"), cent, gap, sum, c3Sub2D); + fillBS3D(bs.c3Sub2D, cent, etaValA, etaValB, c3Sub2D); + fillBS3D(bs.c3GapSum2D, cent, gap, sum, c3Sub2D); } - if (std::isfinite(covCA)) { - histos.fill(HIST("Prof_Cov_Cent_etabin_spbin"), cent, ietaC, isp, covCA); - histos.fill(HIST("Prof_Cov_Mult_etabin_spbin"), coll.multNTracksPV(), ietaC, isp, covCA); + if (std::isfinite(cov)) { + histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC"), cent, etaValA, etaValB, cov); + fillBS3D(bs.cov2D, cent, etaValA, etaValB, cov); } if (std::isfinite(covFT0A)) { - histos.fill(HIST("Prof_CovFT0A_Cent_etabin_spbin"), cent, ietaA, isp, covFT0A); - histos.fill(HIST("Prof_CovFT0A_Mult_etabin_spbin"), coll.multNTracksPV(), ietaA, isp, covFT0A); + histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0A); + fillBS3D(bs.covFT0A2D, cent, etaValA, etaValB, covFT0A); } if (std::isfinite(covFT0C)) { - histos.fill(HIST("Prof_CovFT0C_Cent_etabin_spbin"), cent, ietaA, isp, covFT0C); - histos.fill(HIST("Prof_CovFT0C_Mult_etabin_spbin"), coll.multNTracksPV(), ietaA, isp, covFT0C); - } - } - } - - for (int ietaA = 1; ietaA < KNEta; ++ietaA) { - for (int ietaC = 1; ietaC < KNEta; ++ietaC) { - - float etaValA = (etaLw[ietaA] + etaUp[ietaA]) / 2.0f; - float etaValB = (etaLw[ietaC] + etaUp[ietaC]) / 2.0f; - float gap = etaValA - etaValB; - float sum = (etaValA + etaValB); - - for (int isp = 0; isp < KNsp; ++isp) { - - float c2Sub = (ietaA == ietaC) ? static_cast(c2[isp][ietaA]) - : p1kBar[isp][ietaA] * p1kBar[isp][ietaC]; - float cov = p1kBarMult[isp][ietaA] * p1kBar[isp][ietaC]; - float covFT0A = p1kBarFt0A * p1kBar[isp][ietaC]; - float covFT0C = p1kBarFt0C * p1kBar[isp][ietaA]; - - if (isp == kInclusiveIdx) { - if (std::isfinite(c2Sub)) { - histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC"), cent, etaValA, etaValB, c2Sub); - histos.fill(HIST("Prof_GapSum2D"), cent, gap, sum, c2Sub); - } - if (std::isfinite(cov)) - histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC"), cent, etaValA, etaValB, cov); - if (std::isfinite(covFT0A)) - histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0A); - if (std::isfinite(covFT0C)) - histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0C); - } else if (isp == kPiMinusIdx) { - if (std::isfinite(c2Sub)) { - histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, c2Sub); - histos.fill(HIST("Prof_GapSum2D_PiMinus"), cent, gap, sum, c2Sub); - } - if (std::isfinite(cov)) - histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, cov); - if (std::isfinite(covFT0A)) - histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covFT0A); - if (std::isfinite(covFT0C)) - histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC_PiMinus"), cent, etaValA, etaValB, covFT0C); - } else if (isp == kPiPlusIdx) { - if (std::isfinite(c2Sub)) { - histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, c2Sub); - histos.fill(HIST("Prof_GapSum2D_PiPlus"), cent, gap, sum, c2Sub); - } - if (std::isfinite(cov)) - histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, cov); - if (std::isfinite(covFT0A)) - histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covFT0A); - if (std::isfinite(covFT0C)) - histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC_PiPlus"), cent, etaValA, etaValB, covFT0C); - } else if (isp == kPiAllIdx) { - if (std::isfinite(c2Sub)) { - histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, c2Sub); - histos.fill(HIST("Prof_GapSum2D_PiAll"), cent, gap, sum, c2Sub); - } - if (std::isfinite(cov)) - histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, cov); - if (std::isfinite(covFT0A)) - histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covFT0A); - if (std::isfinite(covFT0C)) - histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC_PiAll"), cent, etaValA, etaValB, covFT0C); - } else if (isp == kKaMinusIdx) { - if (std::isfinite(c2Sub)) { - histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, c2Sub); - histos.fill(HIST("Prof_GapSum2D_KaMinus"), cent, gap, sum, c2Sub); - } - if (std::isfinite(cov)) - histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, cov); - if (std::isfinite(covFT0A)) - histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covFT0A); - if (std::isfinite(covFT0C)) - histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC_KaMinus"), cent, etaValA, etaValB, covFT0C); - } else if (isp == kKaPlusIdx) { - if (std::isfinite(c2Sub)) { - histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, c2Sub); - histos.fill(HIST("Prof_GapSum2D_KaPlus"), cent, gap, sum, c2Sub); - } - if (std::isfinite(cov)) - histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, cov); - if (std::isfinite(covFT0A)) - histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covFT0A); - if (std::isfinite(covFT0C)) - histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC_KaPlus"), cent, etaValA, etaValB, covFT0C); - } else if (isp == kKaAllIdx) { - if (std::isfinite(c2Sub)) { - histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, c2Sub); - histos.fill(HIST("Prof_GapSum2D_KaAll"), cent, gap, sum, c2Sub); - } - if (std::isfinite(cov)) - histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, cov); - if (std::isfinite(covFT0A)) - histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covFT0A); - if (std::isfinite(covFT0C)) - histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC_KaAll"), cent, etaValA, etaValB, covFT0C); - } else if (isp == kPrIdx) { - if (std::isfinite(c2Sub)) { - histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, c2Sub); - histos.fill(HIST("Prof_GapSum2D_Pr"), cent, gap, sum, c2Sub); - } - if (std::isfinite(cov)) - histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, cov); - if (std::isfinite(covFT0A)) - histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covFT0A); - if (std::isfinite(covFT0C)) - histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC_Pr"), cent, etaValA, etaValB, covFT0C); - } else if (isp == kAntiPrIdx) { - if (std::isfinite(c2Sub)) { - histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, c2Sub); - histos.fill(HIST("Prof_GapSum2D_AntiPr"), cent, gap, sum, c2Sub); - } - if (std::isfinite(cov)) - histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, cov); - if (std::isfinite(covFT0A)) - histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covFT0A); - if (std::isfinite(covFT0C)) - histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC_AntiPr"), cent, etaValA, etaValB, covFT0C); - } else if (isp == kPrAllIdx) { - if (std::isfinite(c2Sub)) { - histos.fill(HIST("Prof_C2Sub2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, c2Sub); - histos.fill(HIST("Prof_GapSum2D_PrAll"), cent, gap, sum, c2Sub); - } - if (std::isfinite(cov)) - histos.fill(HIST("Prof_Cov2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, cov); - if (std::isfinite(covFT0A)) - histos.fill(HIST("Prof_CovFT0A2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covFT0A); - if (std::isfinite(covFT0C)) - histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC_PrAll"), cent, etaValA, etaValB, covFT0C); - } + histos.fill(HIST("Prof_CovFT0C2D_Cent_etaA_etaC"), cent, etaValA, etaValB, covFT0C); + fillBS3D(bs.covFT0C2D, cent, etaValA, etaValB, covFT0C); } } } diff --git a/PWGCF/Femto/Core/closePairRejection.h b/PWGCF/Femto/Core/closePairRejection.h index 2dd8e07abf5..b6e42f80408 100644 --- a/PWGCF/Femto/Core/closePairRejection.h +++ b/PWGCF/Femto/Core/closePairRejection.h @@ -53,6 +53,7 @@ enum CprHist { kRadius6, kRadius7, kRadius8, + kKinematic, // kinematic variable of the pair/triplet which are blocked kPhi1VsPhi2, kEta1VsEta2, kCprHistogramLast @@ -64,15 +65,18 @@ struct ConfCpr : o2::framework::ConfigurableGroup { std::string prefix = std::string(Prefix); o2::framework::Configurable cutAverage{"cutAverage", true, "Apply CPR if the average deta-dphistar is below the configured values"}; o2::framework::Configurable cutAnyRadius{"cutAnyRadius", false, "Apply CPR if the deta-dphistar is below the configured values at any radius"}; + o2::framework::Configurable cutElipsoidal{"cutElipsoidal", true, "If true, apply CPR as episoidal cut. If false use rectangluar cut."}; o2::framework::Configurable plotAllRadii{"plotAllRadii", true, "Plot deta-dphi distribution at all radii"}; o2::framework::Configurable plotAverage{"plotAverage", true, "Plot average deta dphi distribution"}; o2::framework::Configurable plotAngularCorrelation{"plotAngularCorrelation", false, "Plot angular correlation of particles (eta1 vs eta2 & phi1 vs phi2"}; + o2::framework::Configurable plotKinematic{"plotKinematic", true, "Plot kinematic (kstar/Q3) distribution of blocked pairs/triplets"}; o2::framework::Configurable detaMax{"detaMax", 0.01f, "Maximium deta"}; o2::framework::Configurable dphistarMax{"dphistarMax", 0.01f, "Maximum dphistar"}; o2::framework::Configurable detaCenter{"detaCenter", 0.f, "Center of deta cut"}; o2::framework::Configurable dphistarCenter{"dphistarCenter", 0.f, "Center of dphistar cut"}; o2::framework::Configurable kinematicMin{"kinematicMin", -1.f, "Minimum kstar/Q3 of pair/triplet for plotting (Set to negative value to turn off the cut)"}; o2::framework::Configurable kinematicMax{"kinematicMax", -1.f, "Maximum kstar/Q3 of pair/triplet for plotting (Set to negative value to turn off the cut)"}; + o2::framework::ConfigurableAxis binningKinematic{"binningKinematic", {100, 0, 1}, "Binning of kinematic variable of pair/triplet which are cut"}; o2::framework::ConfigurableAxis binningDeta{"binningDeta", {{250, -0.5, 0.5}}, "deta"}; o2::framework::ConfigurableAxis binningDphistar{"binningDphistar", {{250, -0.5, 0.5}}, "dphi"}; o2::framework::ConfigurableAxis binningCorrelationPhi{"binningCorrelationPhi", {{720, 0, o2::constants::math::TwoPI}}, "Phi binning for correlation plot"}; @@ -165,6 +169,7 @@ constexpr std::array, kCprHistogramLast> HistTabl {kRadius6, o2::framework::HistType::kTH2F, "hRadius6", "Radius 6: #Delta #eta vs #Delta #phi*; #Delta #eta; #Delta #phi*"}, {kRadius7, o2::framework::HistType::kTH2F, "hRadius7", "Radius 7: #Delta #eta vs #Delta #phi*; #Delta #eta; #Delta #phi*"}, {kRadius8, o2::framework::HistType::kTH2F, "hRadius8", "Radius 8: #Delta #eta vs #Delta #phi*; #Delta #eta; #Delta #phi*"}, + {kKinematic, o2::framework::HistType::kTH1F, "hKinematic", "Kinematic distribution of blocked pairs; kinematic Variable (GeV/c#it{c}); Entries"}, {kPhi1VsPhi2, o2::framework::HistType::kTH2F, "hPhi1vsPhi2", "#phi_{1} vs #phi_{2}; #phi_{1}; #phi_{2}"}, {kEta1VsEta2, o2::framework::HistType::kTH2F, "hEta1VsEta2", "#eta_{1} vs #eta_{2}; #eta_{1}; #eta_{2}"}}}; @@ -182,6 +187,7 @@ auto makeCprHistSpecMap(const T& confCpr) {kRadius6, {confCpr.binningDeta, confCpr.binningDphistar}}, {kRadius7, {confCpr.binningDeta, confCpr.binningDphistar}}, {kRadius8, {confCpr.binningDeta, confCpr.binningDphistar}}, + {kKinematic, {confCpr.binningKinematic}}, {kPhi1VsPhi2, {confCpr.binningCorrelationPhi, confCpr.binningCorrelationPhi}}, {kEta1VsEta2, {confCpr.binningCorrelationEta, confCpr.binningCorrelationEta}}, }; @@ -217,6 +223,7 @@ class CloseTrackRejection mCutAverage = confCpr.cutAverage.value; mCutAnyRadius = confCpr.cutAnyRadius.value; + mUseEpisoidalCut = confCpr.cutElipsoidal.value; mKinematicMin = confCpr.kinematicMin.value; mKinematicMax = confCpr.kinematicMax.value; @@ -225,6 +232,7 @@ class CloseTrackRejection mPlotAllRadii = confCpr.plotAllRadii.value; mPlotAngularCorrelation = confCpr.plotAngularCorrelation.value; + mPlotKinematic = confCpr.plotKinematic.value; if (confCpr.seed.value >= 0) { uint64_t randomSeed = 0; @@ -237,11 +245,15 @@ class CloseTrackRejection mRng = std::mt19937(randomSeed); } - // check if we need to apply any cut a plot is requested + // check if we need to apply any cut or if a plot is requested mIsActivated = mCutAverage || mCutAnyRadius || mPlotAverage || mPlotAllRadii; mHistogramRegistry = registry; + if (mPlotKinematic) { + mHistogramRegistry->add(std::string(prefix) + getHistNameV2(kKinematic, HistTable), getHistDesc(kKinematic, HistTable), getHistType(kKinematic, HistTable), {specs.at(kKinematic)}); + } + if (mPlotAverage) { mHistogramRegistry->add(std::string(prefix) + getHistNameV2(kAverage, HistTable), getHistDesc(kAverage, HistTable), getHistType(kAverage, HistTable), {specs.at(kAverage)}); } @@ -265,12 +277,34 @@ class CloseTrackRejection void setMagField(float magField) { mMagField = magField; } - template - void compute(T1 const& track1, T2 const& track2) + // checks if the cut is activated; if so, computes deta/dphistar for the pair, + // fills the "blocked" or "passed" histograms accordingly, and returns whether + // the pair was rejected. If the cut is not activated, does nothing and returns false. + // pairHistManager must expose getKinematic() (same interface PcManager::isCleanPair expects). + template + [[nodiscard]] bool isClosePair(T1 const& track1, T2 const& track2, T3 const& pairHistManager) { if (!mIsActivated) { - return; + return false; + } + + compute(track1, track2); + + bool isClose = mUseEpisoidalCut ? isClosePairEpisoidalCut() : isClosePairRectengularCut(); + + if (isClose) { + fillBlocked(pairHistManager.getKinematic()); + } else { + fillPassed(pairHistManager.getKinematic()); } + + return isClose; + } + + private: + template + void compute(T1 const& track1, T2 const& track2) + { // reset values mAverageDphistar = 0.f; int count = 0; @@ -283,14 +317,14 @@ class CloseTrackRejection swapTracks = (mSwapDist(mRng) == 1); } - auto const& t1 = swapTracks ? track2 : track1; - auto const& t2 = swapTracks ? track1 : track2; + auto t1 = swapTracks ? track2 : track1; + auto t2 = swapTracks ? track1 : track2; mDeta = t1.eta() - t2.eta(); for (size_t i = 0; i < TpcRadii.size(); i++) { - auto phistar1 = phistar(mMagField, TpcRadii[i], mChargeAbsTrack1 * t1.signedPt(), t1.phi()); - auto phistar2 = phistar(mMagField, TpcRadii[i], mChargeAbsTrack2 * t2.signedPt(), t2.phi()); + auto phistar1 = phistar(mMagField, TpcRadii.at(i), mChargeAbsTrack1 * t1.signedPt(), t1.phi()); + auto phistar2 = phistar(mMagField, TpcRadii.at(i), mChargeAbsTrack2 * t2.signedPt(), t2.phi()); if (phistar1 && phistar2) { mDphistar.at(i) = RecoDecay::constrainAngle(phistar1.value() - phistar2.value(), -o2::constants::math::PI); // constrain angular difference between -pi and pi mDphistarMask.at(i) = true; @@ -312,12 +346,65 @@ class CloseTrackRejection } } - void fill(float kinematic) + std::optional phistar(float magfield, float radius, float signedPt, float phi) { - if (!mIsActivated) { - return; + double arg = 0.3 * (0.1 * magfield) * (0.01 * radius) / (2. * signedPt); + if (std::fabs(arg) <= 1.) { + double angle = phi - std::asin(arg); + return static_cast(RecoDecay::constrainAngle(angle)); + } + return std::nullopt; + } + + [[nodiscard]] bool isClosePairEpisoidalCut() const + { + bool isCloseAverage = false; + bool isCloseAnyRadius = false; + + if (mCutAverage) { + isCloseAverage = std::hypot((mAverageDphistar - mDphistarCenter) / mDphistarMax, (mDeta - mDetaCenter) / mDetaMax) < 1.f; } + if (mCutAnyRadius) { + for (size_t i = 0; i < TpcRadii.size(); i++) { + if (isCloseAnyRadius) { + break; + } + if (mDphistarMask.at(i)) { + isCloseAnyRadius = std::hypot((mDphistar.at(i) - mDphistarCenter) / mDphistarMax, (mDeta - mDetaCenter) / mDetaMax) < 1.f; + } + } + } + return isCloseAverage || isCloseAnyRadius; + } + + [[nodiscard]] bool isClosePairRectengularCut() const + { + bool isCloseAverage = false; + bool isCloseAnyRadius = false; + + if (mCutAverage) { + isCloseAverage = std::fabs(mAverageDphistar - mDphistarCenter) < mDphistarMax && + std::fabs(mDeta - mDetaCenter) < mDetaMax; + } + + if (mCutAnyRadius) { + for (size_t i = 0; i < TpcRadii.size(); i++) { + if (isCloseAnyRadius) { + break; + } + if (mDphistarMask.at(i)) { + isCloseAnyRadius = std::fabs(mDphistar.at(i) - mDphistarCenter) < mDphistarMax && + std::fabs(mDeta - mDetaCenter) < mDetaMax; + } + } + } + return isCloseAverage || isCloseAnyRadius; + } + + // fill the "normal" distributions (deta-dphistar, angular correlation) for pairs that passed the cut + void fillPassed(float kinematic) const + { if (mKinematicMin > 0.f && kinematic < mKinematicMin) { return; } @@ -340,82 +427,63 @@ class CloseTrackRejection if (mPlotAllRadii) { if (mDphistarMask.at(0)) { mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius0, HistTable)), mDeta, mDphistar.at(0)); - } - if (mDphistarMask.at(1)) { - mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius1, HistTable)), mDeta, mDphistar.at(1)); - } - if (mDphistarMask.at(2)) { - mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius2, HistTable)), mDeta, mDphistar.at(2)); - } - if (mDphistarMask.at(3)) { - mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius3, HistTable)), mDeta, mDphistar.at(3)); - } - if (mDphistarMask.at(4)) { - mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius4, HistTable)), mDeta, mDphistar.at(4)); - } - if (mDphistarMask.at(5)) { - mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius5, HistTable)), mDeta, mDphistar.at(5)); - } - if (mDphistarMask.at(6)) { - mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius6, HistTable)), mDeta, mDphistar.at(6)); - } - if (mDphistarMask.at(7)) { - mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius7, HistTable)), mDeta, mDphistar.at(7)); - } - if (mDphistarMask.at(8)) { - mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius8, HistTable)), mDeta, mDphistar.at(8)); + if (mDphistarMask.at(1)) { + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius1, HistTable)), mDeta, mDphistar.at(1)); + } + if (mDphistarMask.at(2)) { + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius2, HistTable)), mDeta, mDphistar.at(2)); + } + if (mDphistarMask.at(3)) { + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius3, HistTable)), mDeta, mDphistar.at(3)); + } + if (mDphistarMask.at(4)) { + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius4, HistTable)), mDeta, mDphistar.at(4)); + } + if (mDphistarMask.at(5)) { + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius5, HistTable)), mDeta, mDphistar.at(5)); + } + if (mDphistarMask.at(6)) { + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius6, HistTable)), mDeta, mDphistar.at(6)); + } + if (mDphistarMask.at(7)) { + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius7, HistTable)), mDeta, mDphistar.at(7)); + } + if (mDphistarMask.at(8)) { + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kRadius8, HistTable)), mDeta, mDphistar.at(8)); + } } } } - [[nodiscard]] bool isClosePair() const + // fill the kinematic (kstar/Q3) distribution of pairs that were blocked by the CPR cut + void fillBlocked(float kinematic) const { - if (!mIsActivated) { - return false; - } - bool isCloseAverage = false; - bool isCloseAnyRadius = false; - - if (mCutAverage) { - isCloseAverage = std::hypot((mAverageDphistar - mDphistarCenter) / mDphistarMax, (mDeta - mDetaCenter) / mDetaMax) < 1.f; + if (!mPlotKinematic) { + return; } - if (mCutAnyRadius) { - for (size_t i = 0; i < TpcRadii.size(); i++) { - if (isCloseAnyRadius) { - break; - } - if (mDphistarMask.at(i)) { - isCloseAnyRadius = std::hypot((mDphistar.at(i) - mDphistarCenter) / mDphistarMax, (mDeta - mDetaCenter) / mDetaMax) < 1.f; - } - } + if (mKinematicMin > 0.f && kinematic < mKinematicMin) { + return; } - return isCloseAverage || isCloseAnyRadius; - } - - [[nodiscard]] bool isActivated() const { return mIsActivated; } - private: - std::optional phistar(float magfield, float radius, float signedPt, float phi) - { - double arg = 0.3 * (0.1 * magfield) * (0.01 * radius) / (2. * signedPt); - if (std::fabs(arg) <= 1.) { - double angle = phi - std::asin(arg); - return static_cast(RecoDecay::constrainAngle(angle)); + if (mKinematicMax > 0.f && kinematic > mKinematicMax) { + return; } - return std::nullopt; + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kKinematic, HistTable)), kinematic); } o2::framework::HistogramRegistry* mHistogramRegistry = nullptr; bool mPlotAllRadii = false; bool mPlotAverage = false; bool mPlotAngularCorrelation = false; + bool mPlotKinematic = false; float mKinematicMin = -1.f; float mKinematicMax = -1.f; bool mCutAverage = false; bool mCutAnyRadius = false; + bool mUseEpisoidalCut = true; bool mIsActivated = false; @@ -458,13 +526,12 @@ class ClosePairRejectionTrackTrack } void setMagField(float magField) { mCtr.setMagField(magField); } - template - void setPair(T1 const& track1, T2 const& track2, T3 const& /*tracks*/) // pass track table for compatibility with other classes + + template + [[nodiscard]] bool isClosePair(T1 const& track1, T2 const& track2, T3 const& /*tracks*/, T4 const& pairHistManager) { - mCtr.compute(track1, track2); + return mCtr.isClosePair(track1, track2, pairHistManager); } - [[nodiscard]] bool isClosePair() const { return mCtr.isClosePair(); } - void fill(float kstar) { mCtr.fill(kstar); } private: CloseTrackRejection mCtr; @@ -491,24 +558,18 @@ class ClosePairRejectionV0V0 mCtrNeg.setMagField(magField); } - template - void setPair(T1 const& v01, T2 const& v02, T3 const& tracks) + template + [[nodiscard]] bool isClosePair(T1 const& v01, T2 const& v02, T3 const& tracks, T4 const& pairHistManager) { auto posDau1 = tracks.rawIteratorAt(v01.posDauId() - tracks.offset()); auto posDau2 = tracks.rawIteratorAt(v02.posDauId() - tracks.offset()); - mCtrPos.compute(posDau1, posDau2); + bool isClosePos = mCtrPos.isClosePair(posDau1, posDau2, pairHistManager); auto negDau1 = tracks.rawIteratorAt(v01.negDauId() - tracks.offset()); auto negDau2 = tracks.rawIteratorAt(v02.negDauId() - tracks.offset()); - mCtrNeg.compute(negDau1, negDau2); - } + bool isCloseNeg = mCtrNeg.isClosePair(negDau1, negDau2, pairHistManager); - [[nodiscard]] bool isClosePair() const { return mCtrPos.isClosePair() || mCtrNeg.isClosePair(); } - - void fill(float kstar) - { - mCtrPos.fill(kstar); - mCtrNeg.fill(kstar); + return isClosePos || isCloseNeg; } private: @@ -531,22 +592,17 @@ class ClosePairRejectionTrackV0 // can also be used for any particle type that h void setMagField(float magField) { mCtr.setMagField(magField); } - template - void setPair(T1 const& track, T2 const& v0, T3 const& trackTable) + template + [[nodiscard]] bool isClosePair(T1 const& track, T2 const& v0, T3 const& trackTable, T4 const& pairHistManager) { if (track.sign() > 0) { auto posDau = trackTable.rawIteratorAt(v0.posDauId() - trackTable.offset()); - mCtr.compute(track, posDau); - } else { - auto negDau = trackTable.rawIteratorAt(v0.negDauId() - trackTable.offset()); - mCtr.compute(track, negDau); + return mCtr.isClosePair(track, posDau, pairHistManager); } + auto negDau = trackTable.rawIteratorAt(v0.negDauId() - trackTable.offset()); + return mCtr.isClosePair(track, negDau, pairHistManager); } - [[nodiscard]] bool isClosePair() const { return mCtr.isClosePair(); } - - void fill(float kstar) { mCtr.fill(kstar); } - private: CloseTrackRejection mCtr; }; @@ -577,24 +633,19 @@ class ClosePairRejectionTrackLc mCtrPion.setMagField(magField); } - template - void setPair(T1 const& track, T2 const& lc, T3 const& trackTable) + template + [[nodiscard]] bool isClosePair(T1 const& track, T2 const& lc, T3 const& trackTable, T4 const& pairHistManager) { auto prong0 = trackTable.rawIteratorAt(lc.prong0DauId() - trackTable.offset()); - mCtrProton.compute(track, prong0); + bool isCloseProton = mCtrProton.isClosePair(track, prong0, pairHistManager); + auto prong1 = trackTable.rawIteratorAt(lc.prong1DauId() - trackTable.offset()); - mCtrKaon.compute(track, prong1); - auto prong2 = trackTable.rawIteratorAt(lc.prong2DauId() - trackTable.offset()); - mCtrPion.compute(track, prong2); - } + bool isCloseKaon = mCtrKaon.isClosePair(track, prong1, pairHistManager); - [[nodiscard]] bool isClosePair() const { return mCtrProton.isClosePair() || mCtrKaon.isClosePair() || mCtrPion.isClosePair(); } + auto prong2 = trackTable.rawIteratorAt(lc.prong2DauId() - trackTable.offset()); + bool isClosePion = mCtrPion.isClosePair(track, prong2, pairHistManager); - void fill(float kstar) - { - mCtrProton.fill(kstar); - mCtrKaon.fill(kstar); - mCtrPion.fill(kstar); + return isCloseProton || isCloseKaon || isClosePion; } private: @@ -625,27 +676,22 @@ class ClosePairRejectionTrackCascade mCtrV0Daughter.setMagField(magField); } - template - void setPair(T1 const& track, T2 const& cascade, T3 const& trackTable) + template + [[nodiscard]] bool isClosePair(T1 const& track, T2 const& cascade, T3 const& trackTable, T4 const& pairHistManager) { auto bachelor = trackTable.rawIteratorAt(cascade.bachelorId() - trackTable.offset()); - mCtrBachelor.compute(track, bachelor); + bool isCloseBachelor = mCtrBachelor.isClosePair(track, bachelor, pairHistManager); + bool isCloseV0Daughter = false; if (track.sign() > 0) { auto posDau = trackTable.rawIteratorAt(cascade.posDauId() - trackTable.offset()); - mCtrV0Daughter.compute(track, posDau); + isCloseV0Daughter = mCtrV0Daughter.isClosePair(track, posDau, pairHistManager); } else { auto negDau = trackTable.rawIteratorAt(cascade.negDauId() - trackTable.offset()); - mCtrV0Daughter.compute(track, negDau); + isCloseV0Daughter = mCtrV0Daughter.isClosePair(track, negDau, pairHistManager); } - } - - [[nodiscard]] bool isClosePair() const { return mCtrBachelor.isClosePair() || mCtrV0Daughter.isClosePair(); } - void fill(float kstar) - { - mCtrBachelor.fill(kstar); - mCtrV0Daughter.fill(kstar); + return isCloseBachelor || isCloseV0Daughter; } private: @@ -671,16 +717,13 @@ class ClosePairRejectionTrackKink mCtr.setMagField(magField); } - template - void setPair(T1 const& track, T2 const& kink, T3 const& trackTable) + template + [[nodiscard]] bool isClosePair(T1 const& track, T2 const& kink, T3 const& trackTable, T4 const& pairHistManager) { auto daughter = trackTable.rawIteratorAt(kink.chaDauId() - trackTable.offset()); - mCtr.compute(track, daughter); + return mCtr.isClosePair(track, daughter, pairHistManager); } - [[nodiscard]] bool isClosePair() const { return mCtr.isClosePair(); } - void fill(float kstar) { mCtr.fill(kstar); } - private: CloseTrackRejection mCtr; }; @@ -697,13 +740,12 @@ class ClosePairRejectionMcParticleMcParticle mCtr.init(registry, specs, confCpr, 1, 1); mCtr.setMagField(confCpr.magField.value); } - template - void setPair(T1 const& mcParticle1, T2 const& mcParticle2) + + template + [[nodiscard]] bool isClosePair(T1 const& mcParticle1, T2 const& mcParticle2, T3 const& pairHistManager) { - mCtr.compute(mcParticle1, mcParticle2); + return mCtr.isClosePair(mcParticle1, mcParticle2, pairHistManager); } - [[nodiscard]] bool isClosePair() const { return mCtr.isClosePair(); } - void fill(float kstar) { mCtr.fill(kstar); } private: CloseTrackRejection mCtr; diff --git a/PWGCF/Femto/Core/closeTripletRejection.h b/PWGCF/Femto/Core/closeTripletRejection.h index f9b5b788762..20a68f86cfe 100644 --- a/PWGCF/Femto/Core/closeTripletRejection.h +++ b/PWGCF/Femto/Core/closeTripletRejection.h @@ -27,7 +27,12 @@ namespace o2::analysis::femto::closetripletrejection { constexpr const char PrefixCtrTrackTrackTrack[] = "CtrTrackTrackTrack"; +constexpr const char PrefixCtrTrackTrackV0[] = "CtrTrackTrackV0"; +constexpr const char PrefixCtrTrackTrackCascade[] = "CtrTrackTrackCascade"; + using ConfCtrTrackTrackTrack = closepairrejection::ConfCpr; +using ConfCtrTrackTrackV0 = closepairrejection::ConfCpr; +using ConfCtrTrackTrackCascade = closepairrejection::ConfCpr; // directory names constexpr char PrefixTrack1Track2Se[] = "CPR_Track1Track2/SE/"; @@ -85,23 +90,17 @@ class CloseTripletRejectionTrackTrackTrack mCtrTrack23.setMagField(magField); mCtrTrack13.setMagField(magField); } - template - void setTriplet(T1 const& track1, T2 const& track2, T3 const& track3, T4 const& trackTable) - { - mCtrTrack12.setPair(track1, track2, trackTable); - mCtrTrack23.setPair(track2, track3, trackTable); - mCtrTrack13.setPair(track1, track3, trackTable); - } - [[nodiscard]] bool isCloseTriplet() const - { - return mCtrTrack12.isClosePair() || mCtrTrack23.isClosePair() || mCtrTrack13.isClosePair(); - } - void fill(float q3) + // checks all three constituent pairs of the triplet; fills the deta-dphi/kinematic + // histograms of each pair internally and returns whether the triplet is rejected. + // tripletHistManager must expose getKinematic() (same interface CloseTrackRejection expects). + template + [[nodiscard]] bool isCloseTriplet(T1 const& track1, T2 const& track2, T3 const& track3, T4 const& trackTable, T5 const& tripletHistManager) { - mCtrTrack12.fill(q3); - mCtrTrack23.fill(q3); - mCtrTrack13.fill(q3); + bool isClose12 = mCtrTrack12.isClosePair(track1, track2, trackTable, tripletHistManager); + bool isClose23 = mCtrTrack23.isClosePair(track2, track3, trackTable, tripletHistManager); + bool isClose13 = mCtrTrack13.isClosePair(track1, track3, trackTable, tripletHistManager); + return isClose12 || isClose23 || isClose13; } private: @@ -137,23 +136,16 @@ class CloseTripletRejectionTrackTrackV0 mCtrTrack1V0.setMagField(magField); mCtrTrack2V0.setMagField(magField); } - template - void setTriplet(T1 const& track1, T2 const& track2, T3 const& v0, T4 const& trackTable) - { - mCtrTrack12.setPair(track1, track2, trackTable); - mCtrTrack1V0.setPair(track1, v0, trackTable); - mCtrTrack2V0.setPair(track2, v0, trackTable); - } - [[nodiscard]] bool isCloseTriplet() const - { - return mCtrTrack12.isClosePair() || mCtrTrack1V0.isClosePair() || mCtrTrack2V0.isClosePair(); - } - void fill(float q3) + // checks track1-track2, track1-v0 and track2-v0; fills the deta-dphi/kinematic + // histograms of each pair internally and returns whether the triplet is rejected. + template + [[nodiscard]] bool isCloseTriplet(T1 const& track1, T2 const& track2, T3 const& v0, T4 const& trackTable, T5 const& tripletHistManager) { - mCtrTrack12.fill(q3); - mCtrTrack1V0.fill(q3); - mCtrTrack2V0.fill(q3); + bool isClose12 = mCtrTrack12.isClosePair(track1, track2, trackTable, tripletHistManager); + bool isClose1V0 = mCtrTrack1V0.isClosePair(track1, v0, trackTable, tripletHistManager); + bool isClose2V0 = mCtrTrack2V0.isClosePair(track2, v0, trackTable, tripletHistManager); + return isClose12 || isClose1V0 || isClose2V0; } private: @@ -195,23 +187,16 @@ class CloseTripletRejectionTrackTrackCascade mCtrTrack1Cascade.setMagField(magField); mCtrTrack2Cascade.setMagField(magField); } - template - void setTriplet(T1 const& track1, T2 const& track2, T3 const& cascade, T4 const& trackTable) - { - mCtrTrack12.setPair(track1, track2, trackTable); - mCtrTrack1Cascade.setPair(track1, cascade, trackTable); - mCtrTrack2Cascade.setPair(track2, cascade, trackTable); - } - [[nodiscard]] bool isCloseTriplet() const - { - return mCtrTrack12.isClosePair() || mCtrTrack1Cascade.isClosePair() || mCtrTrack2Cascade.isClosePair(); - } - void fill(float q3) + // checks track1-track2, track1-cascade and track2-cascade; fills the deta-dphi/kinematic + // histograms of each pair internally and returns whether the triplet is rejected. + template + [[nodiscard]] bool isCloseTriplet(T1 const& track1, T2 const& track2, T3 const& cascade, T4 const& trackTable, T5 const& tripletHistManager) { - mCtrTrack12.fill(q3); - mCtrTrack1Cascade.fill(q3); - mCtrTrack2Cascade.fill(q3); + bool isClose12 = mCtrTrack12.isClosePair(track1, track2, trackTable, tripletHistManager); + bool isClose1Cascade = mCtrTrack1Cascade.isClosePair(track1, cascade, trackTable, tripletHistManager); + bool isClose2Cascade = mCtrTrack2Cascade.isClosePair(track2, cascade, trackTable, tripletHistManager); + return isClose12 || isClose1Cascade || isClose2Cascade; } private: diff --git a/PWGCF/Femto/Core/dataTypes.h b/PWGCF/Femto/Core/dataTypes.h index e61a528dd5c..0ed2fb12ec7 100644 --- a/PWGCF/Femto/Core/dataTypes.h +++ b/PWGCF/Femto/Core/dataTypes.h @@ -67,6 +67,9 @@ using CharmHadronType = uint16_t; using QvecDetectorType = uint8_t; using QvecHarmonicType = uint8_t; +// datatype for kinematic variable +using KinematicVariableType = uint8_t; + } // namespace o2::analysis::femto::datatypes #endif // PWGCF_FEMTO_CORE_DATATYPES_H_ diff --git a/PWGCF/Femto/Core/femtoUtils.h b/PWGCF/Femto/Core/femtoUtils.h index fa4b9a23466..c623e161f2b 100644 --- a/PWGCF/Femto/Core/femtoUtils.h +++ b/PWGCF/Femto/Core/femtoUtils.h @@ -30,6 +30,7 @@ #include #include #include +#include #include namespace o2::analysis::femto @@ -83,7 +84,7 @@ inline double getPdgMass(int pdgCode) { // use this function instead of TDatabasePDG to return masses defined in the PhysicsConstants.h header // this approach saves a lot of memory and important partilces like deuteron are missing in TDatabasePDG anyway - double mass = 0.f; + double mass = 0.; // add new particles if necessary here switch (std::abs(pdgCode)) { case kPiPlus: @@ -102,10 +103,10 @@ inline double getPdgMass(int pdgCode) mass = o2::constants::physics::MassPhi; break; case kRho770_0: - mass = 775.26; // not defined in O2? + mass = 0.77526; // not defined in O2? break; case kRho770Plus: - mass = 775.11; // not defined in O2? + mass = 0.77511; // not defined in O2? break; case o2::constants::physics::Pdg::kK0Star892: mass = o2::constants::physics::MassK0Star892; @@ -138,7 +139,7 @@ inline double getPdgMass(int pdgCode) mass = o2::constants::physics::MassOmegaMinus; break; default: - LOG(warn) << "PDG code is not suppored. Return 0..."; + LOG(warn) << "PDG code " << pdgCode << " is not suppored. Return 0... "; } return mass; } @@ -154,11 +155,15 @@ concept HasQvectors = requires(T col) { }; template -concept HasEventShape = requires(T col) { - col.qvec(); - col.eventPlaneAngle(); +concept HasEventShapeRow = requires(T row) { + row.qvec(); + row.eventPlaneAngle(); }; +/// accepts either a row/iterator or a table (Filtered> etc.) +template +concept HasEventShape = HasEventShapeRow> || (requires { typename std::decay_t::iterator; } && HasEventShapeRow::iterator>); + /// Recalculate pT for Kinks (Sigmas) using kinematic constraints inline float calcPtnew(float pxMother, float pyMother, float pzMother, float pxDaughter, float pyDaughter, float pzDaughter) { diff --git a/PWGCF/Femto/Core/mcBuilder.h b/PWGCF/Femto/Core/mcBuilder.h index 187fa5dce33..ac110ae0424 100644 --- a/PWGCF/Femto/Core/mcBuilder.h +++ b/PWGCF/Femto/Core/mcBuilder.h @@ -748,6 +748,182 @@ class McBuilder std::unordered_map mMcMotherMap; std::unordered_map mMcPartonicMotherMap; }; + +struct McBuilderDerivedToDerivedProducts : o2::framework::ProducesGroup { + o2::framework::Produces producedMcCollisions; + o2::framework::Produces producedMcParticles; + o2::framework::Produces producedMothers; + o2::framework::Produces producedPartonicMothers; + o2::framework::Produces producedMcMotherLabels; + + o2::framework::Produces producedCollisionLabels; + o2::framework::Produces producedTrackLabels; +}; + +struct ConfMcTablesDerivedToDerived : o2::framework::ConfigurableGroup { + std::string prefix = std::string("McTables"); + o2::framework::Configurable requireMcLabel{"requireMcLabel", false, "Reject particles without an associated MC particle instead of writing a -1 label"}; // dummy configuration for now +}; + +/// Copies MC information from one femto derived file into another. +/// The ancestry is already resolved upstream (FMcMothers / FMcPartMoths / +/// FMcMotherLabels), so this only remaps indices: each source row is copied on +/// first use and cached for the rest of the dataframe. +class McBuilderDerivedToDerived +{ + public: + McBuilderDerivedToDerived() = default; + ~McBuilderDerivedToDerived() = default; + + template + void init(T& config) + { + LOG(info) << "Initialize derived-to-derived monte carlo builder..."; + mRequireMcLabel = config.requireMcLabel.value; + LOG(info) << "Initialization done..."; + } + + /// Write one FColLabels row. Call exactly once per produced collision, + /// directly after collisionBuilder.processCollision(). + template + void fillCollisionWithLabel(T1 const& col, T2 const& /*mcCols*/, T3& mcProducts) + { + if (!col.has_fMcCol()) { + mcProducts.producedCollisionLabels(-1); + return; + } + auto mcCol = col.template fMcCol_as(); + mcProducts.producedCollisionLabels(this->getOrCreateMcCollisionRow(mcCol, mcProducts)); + } + + /// True if this track has no MC particle and we are configured to drop such tracks. + template + bool rejectParticle(T const& particle) const + { + return mRequireMcLabel && !particle.has_fMcParticle(); + } + + /// Write one FTrackLabels row. Call exactly once per produced track row. + /// mcParticles must be joined with FMcMotherLabels so the mother indices resolve. + template + void fillTrackWithLabel(T1 const& track, T2 const& mcCols, T3 const& /*mcParticles*/, T4 const& mcMothers, T5 const& mcPartonicMothers, T6& mcProducts) + { + if (!track.has_fMcParticle()) { + mcProducts.producedTrackLabels(-1); + return; + } + auto mcParticle = track.template fMcParticle_as(); + mcProducts.producedTrackLabels( + this->getOrCreateMcParticleRow(mcParticle, mcCols, mcMothers, mcPartonicMothers, mcProducts)); + } + + template + void reset(T1 const& mcCols, T2 const& mcParticles) + { + mCollisionMap.clear(); + mCollisionMap.reserve(mcCols.size()); + mMcParticleMap.clear(); + mMcParticleMap.reserve(mcParticles.size()); + mMcMotherMap.clear(); + mMcMotherMap.reserve(mcParticles.size()); + mMcPartonicMotherMap.clear(); + mMcPartonicMotherMap.reserve(mcParticles.size()); + } + + private: + template + int64_t getOrCreateMcCollisionRow(T1 const& mcCol, T2& mcProducts) + { + const int64_t gid = mcCol.globalIndex(); + auto it = mCollisionMap.find(gid); + if (it != mCollisionMap.end()) { + return it->second; + } + mcProducts.producedMcCollisions(mcCol.posZ(), + mcCol.mult(), + mcCol.cent()); + const int64_t row = mcProducts.producedMcCollisions.lastIndex(); + mCollisionMap.emplace(gid, row); + return row; + } + + /// Find-or-create the FMcParticles row. On first creation the mother and + /// partonic mother rows are copied and the single matching FMcMotherLabels row + /// is written, so the two tables stay in lockstep exactly as in McBuilder. + template + int64_t getOrCreateMcParticleRow(T1 const& mcParticle, T2 const& /*mcCols*/, T3 const& /*mcMothers*/, T4 const& /*mcPartonicMothers*/, T5& mcProducts) + { + const int64_t gid = mcParticle.globalIndex(); + auto it = mMcParticleMap.find(gid); + if (it != mMcParticleMap.end()) { + return it->second; + } + + // NOTE: the MC collision of the particle, not of the reconstructed collision. + // These differ for wrongly associated particles, which is the point of keeping it. + int64_t mcColId = -1; + if (mcParticle.has_fMcCol()) { + auto mcCol = mcParticle.template fMcCol_as(); + mcColId = this->getOrCreateMcCollisionRow(mcCol, mcProducts); + } + + mcProducts.producedMcParticles(mcColId, + mcParticle.origin(), + mcParticle.pdgCode(), + mcParticle.signedPt(), + mcParticle.eta(), + mcParticle.phi()); + const int64_t row = mcProducts.producedMcParticles.lastIndex(); + mMcParticleMap.emplace(gid, row); + + // --- mother --- + int64_t mcMotherRow = -1; + if (mcParticle.has_fMcMother()) { + auto mother = mcParticle.template fMcMother_as(); + const int64_t motherGid = mother.globalIndex(); + auto itM = mMcMotherMap.find(motherGid); + if (itM != mMcMotherMap.end()) { + mcMotherRow = itM->second; + } else { + mcProducts.producedMothers(mother.origin(), + mother.pdgCode(), + mother.signedPt(), + mother.eta(), + mother.phi()); + mcMotherRow = mcProducts.producedMothers.lastIndex(); + mMcMotherMap.emplace(motherGid, mcMotherRow); + } + } + + // --- partonic mother --- + int64_t mcPartonicMotherRow = -1; + if (mcParticle.has_fMcPartMoth()) { + auto partonicMother = mcParticle.template fMcPartMoth_as(); + const int64_t partonicGid = partonicMother.globalIndex(); + auto itPM = mMcPartonicMotherMap.find(partonicGid); + if (itPM != mMcPartonicMotherMap.end()) { + mcPartonicMotherRow = itPM->second; + } else { + mcProducts.producedPartonicMothers(partonicMother.pdgCode()); + mcPartonicMotherRow = mcProducts.producedPartonicMothers.lastIndex(); + mMcPartonicMotherMap.emplace(partonicGid, mcPartonicMotherRow); + } + } + + // exactly one FMcMotherLabels row per FMcParticles row, written here and only here + mcProducts.producedMcMotherLabels(mcMotherRow, mcPartonicMotherRow); + + return row; + } + + bool mRequireMcLabel = false; + + std::unordered_map mCollisionMap; + std::unordered_map mMcParticleMap; + std::unordered_map mMcMotherMap; + std::unordered_map mMcPartonicMotherMap; +}; + } // namespace o2::analysis::femto::mcbuilder #endif // PWGCF_FEMTO_CORE_MCBUILDER_H_ diff --git a/PWGCF/Femto/Core/modes.h b/PWGCF/Femto/Core/modes.h index 57e53837633..bb665fe1057 100644 --- a/PWGCF/Femto/Core/modes.h +++ b/PWGCF/Femto/Core/modes.h @@ -190,5 +190,13 @@ enum class QvecHarmonic : o2::analysis::femto::datatypes::QvecHarmonicType { kQvecHarmonicLast = 4 }; +enum class KinematicVariable : o2::analysis::femto::datatypes::KinematicVariableType { + kKstar = 0, + kKt = 1, + kMt = 2, + kQ3 = 3, + kKinematicVariableLast = 4 +}; + }; // namespace o2::analysis::femto::modes #endif // PWGCF_FEMTO_CORE_MODES_H_ diff --git a/PWGCF/Femto/Core/pairBuilder.h b/PWGCF/Femto/Core/pairBuilder.h index b7e01e2fbb3..43dc4c8c82c 100644 --- a/PWGCF/Femto/Core/pairBuilder.h +++ b/PWGCF/Femto/Core/pairBuilder.h @@ -20,6 +20,7 @@ #include "PWGCF/Femto/Core/charmHadronHistManager.h" #include "PWGCF/Femto/Core/closePairRejection.h" #include "PWGCF/Femto/Core/collisionHistManager.h" +#include "PWGCF/Femto/Core/femtoUtils.h" #include "PWGCF/Femto/Core/kinkHistManager.h" #include "PWGCF/Femto/Core/mcParticleHistManager.h" #include "PWGCF/Femto/Core/modes.h" @@ -72,7 +73,8 @@ class PairTrackTrackBuilder typename T11, typename T12, typename T13, - typename T14> + typename T14, + typename T15> void init(o2::framework::HistogramRegistry* registry, T1 const& confCollisionBinning, T2 const& confTrackSelection1, @@ -87,7 +89,8 @@ class PairTrackTrackBuilder std::map> const& trackHistSpec1, std::map> const& trackHistSpec2, std::map> const& pairHistSpec, - std::map> const& cprHistSpec) + std::map> const& cprHistSpec, + std::map> const& pairCleanerHistSpec) { // check if correlate the same tracks or not @@ -96,7 +99,8 @@ class PairTrackTrackBuilder mColHistManager.template init(registry, colHistSpec, confCollisionBinning); mPairHistManagerSe.template init(registry, pairHistSpec, confPairBinning, confPairCuts, confMixing); mPairHistManagerMe.template init(registry, pairHistSpec, confPairBinning, confPairCuts, confMixing); - mPc.template init(confPairCuts); + mPcSe.template init(registry, pairCleanerHistSpec, confPairCuts); + mPcMe.template init(registry, pairCleanerHistSpec, confPairCuts); if (mSameSpecies) { mTrackCleaner1.init(confTrackCleaner1); @@ -158,7 +162,7 @@ class PairTrackTrackBuilder if (mMixIdenticalParticles) { pairOrder = static_cast(mDist(mRng)); } - pairprocesshelpers::processSameEvent(trackSlice1, trackTable, col, mTrackHistManager1, mPairHistManagerSe, mCprSe, mPc, pairOrder); + pairprocesshelpers::processSameEvent(trackSlice1, trackTable, col, mTrackHistManager1, mPairHistManagerSe, mCprSe, mPcSe, pairOrder); } else { auto trackSlice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); auto trackSlice2 = partition2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); @@ -167,7 +171,7 @@ class PairTrackTrackBuilder } mColHistManager.template fill(col); mCprSe.setMagField(col.magField()); - pairprocesshelpers::processSameEvent(trackSlice1, trackSlice2, trackTable, col, mTrackHistManager1, mTrackHistManager2, mPairHistManagerSe, mCprSe, mPc); + pairprocesshelpers::processSameEvent(trackSlice1, trackSlice2, trackTable, col, mTrackHistManager1, mTrackHistManager2, mPairHistManagerSe, mCprSe, mPcSe); } } @@ -186,7 +190,7 @@ class PairTrackTrackBuilder if (mMixIdenticalParticles) { pairOrder = static_cast(mDist(mRng)); } - pairprocesshelpers::processSameEvent(trackSlice1, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager1, mPairHistManagerSe, mTrackCleaner1, mCprSe, mPc, pairOrder); + pairprocesshelpers::processSameEvent(trackSlice1, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager1, mPairHistManagerSe, mTrackCleaner1, mCprSe, mPcSe, pairOrder); } else { auto trackSlice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); auto trackSlice2 = partition2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); @@ -195,24 +199,31 @@ class PairTrackTrackBuilder } mColHistManager.template fill(col, mcCols); mCprSe.setMagField(col.magField()); - pairprocesshelpers::processSameEvent(trackSlice1, trackSlice2, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager1, mTrackHistManager2, mPairHistManagerSe, mTrackCleaner1, mTrackCleaner2, mCprSe, mPc); + pairprocesshelpers::processSameEvent(trackSlice1, trackSlice2, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager1, mTrackHistManager2, mPairHistManagerSe, mTrackCleaner1, mTrackCleaner2, mCprSe, mPcSe); } } - template - void processMixedEvent(T1 const& cols, T2& trackTable, T3& partition1, T4& partition2, T5& cache, T6& binsVtxMult, T7& binsVtxCent, T8& binsVtxMultCent) + template + void processMixedEvent(T1 const& cols, T2& trackTable, T3& partition1, T4& partition2, T5& cache, T6& binsVtxMult, T7& binsVtxCent, T8& binsVtxMultCent, T9& binsVtxCentEventPlaneAngle) { if (mSameSpecies) { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); + break; + case static_cast(pairhistmanager::kVtxCentEventPlaneAngle): + if constexpr (utils::HasEventShape) { + pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxCentEventPlaneAngle, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); + } else { + LOG(fatal) << "Mixing policy kVtxCentEventPlaneAngle requires a collision table with event-shape columns. Breaking..."; + } break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -220,13 +231,20 @@ class PairTrackTrackBuilder } else { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); + break; + case static_cast(pairhistmanager::kVtxCentEventPlaneAngle): + if constexpr (utils::HasEventShape) { + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxCentEventPlaneAngle, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); + } else { + LOG(fatal) << "Mixing policy kVtxCentEventPlaneAngle requires a collision table with event-shape columns. Breaking..."; + } break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -234,19 +252,26 @@ class PairTrackTrackBuilder } } - template - void processMixedEvent(T1 const& cols, T2 const& mcCols, T3& trackTable, T4& partition1, T5& partition2, T6 const& mcParticles, T7 const& mcMothers, T8 const& mcPartonicMothers, T9& cache, T10& binsVtxMult, T11& binsVtxCent, T12& binsVtxMultCent) + template + void processMixedEvent(T1 const& cols, T2 const& mcCols, T3& trackTable, T4& partition1, T5& partition2, T6 const& mcParticles, T7 const& mcMothers, T8 const& mcPartonicMothers, T9& cache, T10& binsVtxMult, T11& binsVtxCent, T12& binsVtxMultCent, T13& binsVtxCentEventPlaneAngle) { if (mSameSpecies) { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mTrackCleaner1, mTrackCleaner1, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mTrackCleaner1, mTrackCleaner1, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner1, mTrackCleaner1, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner1, mTrackCleaner1, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner1, mTrackCleaner1, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner1, mTrackCleaner1, mCprMe, mPcMe); + break; + case static_cast(pairhistmanager::kVtxCentEventPlaneAngle): + if constexpr (utils::HasEventShape) { + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCentEventPlaneAngle, mMixingDepth, mPairHistManagerMe, mTrackCleaner1, mTrackCleaner1, mCprMe, mPcMe); + } else { + LOG(fatal) << "Mixing policy kVtxCentEventPlaneAngle requires a collision table with event-shape columns. Breaking..."; + } break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -254,13 +279,20 @@ class PairTrackTrackBuilder } else { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mTrackCleaner1, mTrackCleaner2, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mTrackCleaner1, mTrackCleaner2, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner1, mTrackCleaner2, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner1, mTrackCleaner2, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner1, mTrackCleaner2, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner1, mTrackCleaner2, mCprMe, mPcMe); + break; + case static_cast(pairhistmanager::kVtxCentEventPlaneAngle): + if constexpr (utils::HasEventShape) { + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCentEventPlaneAngle, mMixingDepth, mPairHistManagerMe, mTrackCleaner1, mTrackCleaner2, mCprMe, mPcMe); + } else { + LOG(fatal) << "Mixing policy kVtxCentEventPlaneAngle requires a collision table with event-shape columns. Breaking..."; + } break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -276,7 +308,8 @@ class PairTrackTrackBuilder pairhistmanager::PairHistManager mPairHistManagerMe; closepairrejection::ClosePairRejectionTrackTrack mCprSe; closepairrejection::ClosePairRejectionTrackTrack mCprMe; - paircleaner::TrackTrackPairCleaner mPc; + paircleaner::TrackTrackPairCleaner mPcSe; + paircleaner::TrackTrackPairCleaner mPcMe; particlecleaner::ParticleCleaner mTrackCleaner1; particlecleaner::ParticleCleaner mTrackCleaner2; pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; @@ -328,7 +361,8 @@ class PairV0V0Builder typename T17, typename T18, typename T19, - typename T20> + typename T20, + typename T21> void init(o2::framework::HistogramRegistry* registry, T1 const& confCollisionBinning, T2 const& confV0Selection1, @@ -349,7 +383,8 @@ class PairV0V0Builder std::map> const& NegDauHistSpec2, std::map> const& pairHistSpec, std::map> const& cprHistSpecPos, - std::map> const& cprHistSpecNeg) + std::map> const& cprHistSpecNeg, + std::map> const& pairCleanerHistSpec) { mSameSpecies = confMixing.sameSpecies.value; @@ -374,7 +409,8 @@ class PairV0V0Builder mColHistManager.template init(registry, colHistSpec, confCollisionBinning); mPairHistManagerSe.template init(registry, pairHistSpec, confPairBinning, confPairCuts, confMixing); mPairHistManagerMe.template init(registry, pairHistSpec, confPairBinning, confPairCuts, confMixing); - mPc.template init(confPairCuts); + mPcSe.template init(registry, pairCleanerHistSpec, confPairCuts); + mPcMe.template init(registry, pairCleanerHistSpec, confPairCuts); mV0Cleaner1.init(confV0Cleaner1); mV0Cleaner2.init(confV0Cleaner2); @@ -434,7 +470,7 @@ class PairV0V0Builder if (mMixIdenticalParticles) { pairOrder = static_cast(mDist(mRng)); } - pairprocesshelpers::processSameEvent(v0Slice1, trackTable, col, mV0HistManager1, mPairHistManagerSe, mCprSe, mPc, pairOrder); + pairprocesshelpers::processSameEvent(v0Slice1, trackTable, col, mV0HistManager1, mPairHistManagerSe, mCprSe, mPcSe, pairOrder); } else { auto v0Slice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); auto v0Slice2 = partition2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); @@ -443,7 +479,7 @@ class PairV0V0Builder } mColHistManager.template fill(col); mCprSe.setMagField(col.magField()); - pairprocesshelpers::processSameEvent(v0Slice1, v0Slice2, trackTable, col, mV0HistManager1, mV0HistManager2, mPairHistManagerSe, mCprSe, mPc); + pairprocesshelpers::processSameEvent(v0Slice1, v0Slice2, trackTable, col, mV0HistManager1, mV0HistManager2, mPairHistManagerSe, mCprSe, mPcSe); } } @@ -462,7 +498,7 @@ class PairV0V0Builder if (mMixIdenticalParticles) { pairOrder = static_cast(mDist(mRng)); } - pairprocesshelpers::processSameEvent(v0Slice1, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mV0HistManager1, mPairHistManagerSe, mV0Cleaner1, mCprSe, mPc, pairOrder); + pairprocesshelpers::processSameEvent(v0Slice1, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mV0HistManager1, mPairHistManagerSe, mV0Cleaner1, mCprSe, mPcSe, pairOrder); } else { auto v0Slice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); auto v0Slice2 = partition2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); @@ -471,7 +507,7 @@ class PairV0V0Builder } mColHistManager.template fill(col, mcCols); mCprSe.setMagField(col.magField()); - pairprocesshelpers::processSameEvent(v0Slice1, v0Slice2, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mV0HistManager1, mV0HistManager2, mPairHistManagerSe, mV0Cleaner1, mV0Cleaner2, mCprSe, mPc); + pairprocesshelpers::processSameEvent(v0Slice1, v0Slice2, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mV0HistManager1, mV0HistManager2, mPairHistManagerSe, mV0Cleaner1, mV0Cleaner2, mCprSe, mPcSe); } } @@ -482,13 +518,13 @@ class PairV0V0Builder if (mSameSpecies) { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -496,13 +532,13 @@ class PairV0V0Builder } else { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -516,13 +552,13 @@ class PairV0V0Builder if (mSameSpecies) { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mV0Cleaner1, mV0Cleaner1, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mV0Cleaner1, mV0Cleaner1, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mV0Cleaner1, mV0Cleaner1, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mV0Cleaner1, mV0Cleaner1, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mV0Cleaner1, mV0Cleaner1, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mV0Cleaner1, mV0Cleaner1, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -530,13 +566,13 @@ class PairV0V0Builder } else { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mV0Cleaner1, mV0Cleaner2, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mV0Cleaner1, mV0Cleaner2, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mV0Cleaner1, mV0Cleaner2, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mV0Cleaner1, mV0Cleaner2, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mV0Cleaner1, mV0Cleaner2, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mV0Cleaner1, mV0Cleaner2, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -554,7 +590,8 @@ class PairV0V0Builder pairhistmanager::PairHistManager mPairHistManagerMe; closepairrejection::ClosePairRejectionV0V0 mCprSe; closepairrejection::ClosePairRejectionV0V0 mCprMe; - paircleaner::V0V0PairCleaner mPc; + paircleaner::V0V0PairCleaner mPcSe; + paircleaner::V0V0PairCleaner mPcMe; pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; bool mSameSpecies = false; int mMixingDepth = 5; @@ -605,7 +642,8 @@ class PairD0D0Builder typename T17, typename T18, typename T19, - typename T20> + typename T20, + typename T21> void init(o2::framework::HistogramRegistry* registry, T1 const& confCollisionBinning, T2 const& confD0Selection1, @@ -626,7 +664,8 @@ class PairD0D0Builder std::map> const& NegDauHistSpec2, std::map> const& pairHistSpec, std::map> const& cprHistSpecPos, - std::map> const& cprHistSpecNeg) + std::map> const& cprHistSpecNeg, + std::map> const& pairCleanerHistSpec) { mSameSpecies = confMixing.sameSpecies.value; @@ -648,7 +687,8 @@ class PairD0D0Builder mColHistManager.template init(registry, colHistSpec, confCollisionBinning); mPairHistManagerSe.template init(registry, pairHistSpec, confPairBinning, confPairCuts, confMixing); mPairHistManagerMe.template init(registry, pairHistSpec, confPairBinning, confPairCuts, confMixing); - mPc.template init(confPairCuts); + mPcSe.template init(registry, pairCleanerHistSpec, confPairCuts); + mPcMe.template init(registry, pairCleanerHistSpec, confPairCuts); mD0Cleaner1.init(confD0Cleaner1); mD0Cleaner2.init(confD0Cleaner2); @@ -715,7 +755,7 @@ class PairD0D0Builder if (mMixIdenticalParticles) { pairOrder = static_cast(mDist(mRng)); } - pairprocesshelpers::processSameEvent(d0Slice1, trackTable, col, mD0HistManager1, mPairHistManagerSe, mCprSe, mPc, pairOrder); + pairprocesshelpers::processSameEvent(d0Slice1, trackTable, col, mD0HistManager1, mPairHistManagerSe, mCprSe, mPcSe, pairOrder); } else { auto d0Slice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); auto d0Slice2 = partition2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); @@ -724,7 +764,7 @@ class PairD0D0Builder } mColHistManager.template fill(col); mCprSe.setMagField(col.magField()); - pairprocesshelpers::processSameEvent(d0Slice1, d0Slice2, trackTable, col, mD0HistManager1, mD0HistManager2, mPairHistManagerSe, mCprSe, mPc); + pairprocesshelpers::processSameEvent(d0Slice1, d0Slice2, trackTable, col, mD0HistManager1, mD0HistManager2, mPairHistManagerSe, mCprSe, mPcSe); } } @@ -743,7 +783,7 @@ class PairD0D0Builder if (mMixIdenticalParticles) { pairOrder = static_cast(mDist(mRng)); } - pairprocesshelpers::processSameEvent(d0Slice1, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mD0HistManager1, mPairHistManagerSe, mD0Cleaner1, mCprSe, mPc, pairOrder); + pairprocesshelpers::processSameEvent(d0Slice1, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mD0HistManager1, mPairHistManagerSe, mD0Cleaner1, mCprSe, mPcSe, pairOrder); } else { auto d0Slice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); auto d0Slice2 = partition2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); @@ -752,7 +792,7 @@ class PairD0D0Builder } mColHistManager.template fill(col, mcCols); mCprSe.setMagField(col.magField()); - pairprocesshelpers::processSameEvent(d0Slice1, d0Slice2, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mD0HistManager1, mD0HistManager2, mPairHistManagerSe, mD0Cleaner1, mD0Cleaner2, mCprSe, mPc); + pairprocesshelpers::processSameEvent(d0Slice1, d0Slice2, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mD0HistManager1, mD0HistManager2, mPairHistManagerSe, mD0Cleaner1, mD0Cleaner2, mCprSe, mPcSe); } } @@ -762,13 +802,13 @@ class PairD0D0Builder if (mSameSpecies) { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition1, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -776,13 +816,13 @@ class PairD0D0Builder } else { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -796,13 +836,13 @@ class PairD0D0Builder if (mSameSpecies) { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mD0Cleaner1, mD0Cleaner1, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mD0Cleaner1, mD0Cleaner1, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mD0Cleaner1, mD0Cleaner1, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mD0Cleaner1, mD0Cleaner1, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mD0Cleaner1, mD0Cleaner1, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mD0Cleaner1, mD0Cleaner1, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -810,13 +850,13 @@ class PairD0D0Builder } else { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mD0Cleaner1, mD0Cleaner2, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mD0Cleaner1, mD0Cleaner2, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mD0Cleaner1, mD0Cleaner2, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mD0Cleaner1, mD0Cleaner2, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mD0Cleaner1, mD0Cleaner2, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mD0Cleaner1, mD0Cleaner2, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -834,7 +874,8 @@ class PairD0D0Builder pairhistmanager::PairHistManager mPairHistManagerMe; closepairrejection::ClosePairRejectionV0V0 mCprSe; closepairrejection::ClosePairRejectionV0V0 mCprMe; - paircleaner::V0V0PairCleaner mPc; + paircleaner::V0V0PairCleaner mPcSe; + paircleaner::V0V0PairCleaner mPcMe; pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; bool mSameSpecies = false; int mMixingDepth = 5; @@ -876,7 +917,8 @@ class PairTrackD0Builder typename T13, typename T14, typename T15, - typename T16> + typename T16, + typename T17> void init(o2::framework::HistogramRegistry* registry, T1 const& confCollisionBinning, T2 const& confTrackSelection, @@ -893,7 +935,8 @@ class PairTrackD0Builder std::map>& posDauHistSpec, std::map>& negDauHistSpec, std::map>& pairHistSpec, - std::map>& cprHistSpec) + std::map>& cprHistSpec, + std::map>& pairCleanerHistSpec) { mColHistManager.template init(registry, colHistSpec, confCollisionBinning); @@ -925,7 +968,8 @@ class PairTrackD0Builder mPairHistManagerMe.setMass(confTrackSelection.pdgCodeAbs.value, 0, 0, confD0Selection.pdgCodeAbs.value, posDauPdg, negDauPdg); mPairHistManagerMe.setCharge(confTrackSelection.chargeAbs.value, 1); mCprMe.init(registry, cprHistSpec, confCpr, confTrackSelection.chargeAbs.value); - mPc.template init(confPairCuts); + mPcSe.template init(registry, pairCleanerHistSpec, confPairCuts); + mPcMe.template init(registry, pairCleanerHistSpec, confPairCuts); // setup mixing mMixingPolicy = static_cast(confMixing.policy.value); @@ -942,7 +986,7 @@ class PairTrackD0Builder } mColHistManager.template fill(col); mCprSe.setMagField(col.magField()); - pairprocesshelpers::processSameEvent(trackSlice, d0Slice, trackTable, col, mTrackHistManager, mD0HistManager, mPairHistManagerSe, mCprSe, mPc); + pairprocesshelpers::processSameEvent(trackSlice, d0Slice, trackTable, col, mTrackHistManager, mD0HistManager, mPairHistManagerSe, mCprSe, mPcSe); } template @@ -950,13 +994,13 @@ class PairTrackD0Builder { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, trackPartition, d0Partition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, trackPartition, d0Partition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, trackPartition, d0Partition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, trackPartition, d0Partition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, trackPartition, d0Partition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, trackPartition, d0Partition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -973,7 +1017,7 @@ class PairTrackD0Builder } mColHistManager.template fill(col, mcCols); mCprSe.setMagField(col.magField()); - pairprocesshelpers::processSameEvent(trackSlice, d0Slice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager, mD0HistManager, mPairHistManagerSe, mTrackCleaner, mD0Cleaner, mCprSe, mPc); + pairprocesshelpers::processSameEvent(trackSlice, d0Slice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager, mD0HistManager, mPairHistManagerSe, mTrackCleaner, mD0Cleaner, mCprSe, mPcSe); } template @@ -981,13 +1025,13 @@ class PairTrackD0Builder { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, d0Partition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mD0Cleaner, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, d0Partition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mD0Cleaner, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, d0Partition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mD0Cleaner, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, d0Partition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mD0Cleaner, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, d0Partition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mD0Cleaner, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, d0Partition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mD0Cleaner, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -1004,7 +1048,8 @@ class PairTrackD0Builder pairhistmanager::PairHistManager mPairHistManagerMe; closepairrejection::ClosePairRejectionTrackV0 mCprSe; closepairrejection::ClosePairRejectionTrackV0 mCprMe; - paircleaner::TrackV0PairCleaner mPc; + paircleaner::TrackV0PairCleaner mPcSe; + paircleaner::TrackV0PairCleaner mPcMe; pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; int mMixingDepth = 5; }; @@ -1033,7 +1078,7 @@ class PairTrackLcBuilder modes::Mode modeMe, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, - typename T15, typename T16, typename T17, typename T18, typename T19> + typename T15, typename T16, typename T17, typename T18, typename T19, typename T20> void init(o2::framework::HistogramRegistry* registry, T1 const& confCollisionBinning, T2 const& confTrackSelection, @@ -1053,7 +1098,8 @@ class PairTrackLcBuilder std::map>& kaonDauHistSpec, std::map>& pionDauHistSpec, std::map>& pairHistSpec, - std::map>& cprHistSpec) + std::map>& cprHistSpec, + std::map>& pairCleanerHistSpec) { mColHistManager.template init(registry, colHistSpec, confCollisionBinning); @@ -1078,7 +1124,8 @@ class PairTrackLcBuilder mPairHistManagerMe.setMass(confTrackSelection.pdgCodeAbs.value, 0, 0, confLcSelection.pdgCodeAbs.value, protonDauPdg, kaonDauPdg); mPairHistManagerMe.setCharge(confTrackSelection.chargeAbs.value, 1); mCprMe.init(registry, cprHistSpec, cprHistSpec, cprHistSpec, confCprProton, confCprKaon, confCprPion, confTrackSelection.chargeAbs.value); - mPc.template init(confPairCuts); + mPcSe.template init(registry, pairCleanerHistSpec, confPairCuts); + mPcMe.template init(registry, pairCleanerHistSpec, confPairCuts); // setup mixing mMixingPolicy = static_cast(confMixing.policy.value); @@ -1095,7 +1142,7 @@ class PairTrackLcBuilder } mColHistManager.template fill(col); mCprSe.setMagField(col.magField()); - pairprocesshelpers::processSameEvent(trackSlice, lcSlice, trackTable, col, mTrackHistManager, mLcHistManager, mPairHistManagerSe, mCprSe, mPc); + pairprocesshelpers::processSameEvent(trackSlice, lcSlice, trackTable, col, mTrackHistManager, mLcHistManager, mPairHistManagerSe, mCprSe, mPcSe); } template @@ -1103,13 +1150,13 @@ class PairTrackLcBuilder { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, trackPartition, lcPartition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, trackPartition, lcPartition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, trackPartition, lcPartition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, trackPartition, lcPartition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, trackPartition, lcPartition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, trackPartition, lcPartition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -1126,7 +1173,7 @@ class PairTrackLcBuilder } mColHistManager.template fill(col, mcCols); mCprSe.setMagField(col.magField()); - pairprocesshelpers::processSameEvent(trackSlice, lcSlice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager, mLcHistManager, mPairHistManagerSe, mTrackCleaner, mLcCleaner, mCprSe, mPc); + pairprocesshelpers::processSameEvent(trackSlice, lcSlice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager, mLcHistManager, mPairHistManagerSe, mTrackCleaner, mLcCleaner, mCprSe, mPcSe); } template @@ -1134,13 +1181,13 @@ class PairTrackLcBuilder { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, lcPartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mLcCleaner, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, lcPartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mLcCleaner, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, lcPartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mLcCleaner, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, lcPartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mLcCleaner, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, lcPartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mLcCleaner, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, lcPartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mLcCleaner, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -1157,7 +1204,8 @@ class PairTrackLcBuilder pairhistmanager::PairHistManager mPairHistManagerMe; closepairrejection::ClosePairRejectionTrackLc mCprSe; closepairrejection::ClosePairRejectionTrackLc mCprMe; - paircleaner::TrackLcPairCleaner mPc; + paircleaner::TrackLcPairCleaner mPcSe; + paircleaner::TrackLcPairCleaner mPcMe; pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; int mMixingDepth = 5; }; @@ -1194,7 +1242,8 @@ class PairTrackV0Builder typename T13, typename T14, typename T15, - typename T16> + typename T16, + typename T17> void init(o2::framework::HistogramRegistry* registry, T1 const& confCollisionBinning, T2 const& confTrackSelection, @@ -1211,7 +1260,8 @@ class PairTrackV0Builder std::map>& posDauHistSpec, std::map>& negDauHistSpec, std::map>& pairHistSpec, - std::map>& cprHistSpec) + std::map>& cprHistSpec, + std::map>& pairCleanerHistSpec) { mColHistManager.template init(registry, colHistSpec, confCollisionBinning); @@ -1245,7 +1295,8 @@ class PairTrackV0Builder mPairHistManagerMe.setMass(confTrackSelection.pdgCodeAbs.value, 0, 0, confV0Selection.pdgCodeAbs.value, pdgCodePosDau, pdgCodeNegDau); mPairHistManagerMe.setCharge(confTrackSelection.chargeAbs.value, 1); mCprMe.init(registry, cprHistSpec, confCpr, confTrackSelection.chargeAbs.value); - mPc.template init(confPairCuts); + mPcSe.template init(registry, pairCleanerHistSpec, confPairCuts); + mPcMe.template init(registry, pairCleanerHistSpec, confPairCuts); // setup mixing mMixingPolicy = static_cast(confMixing.policy.value); @@ -1262,7 +1313,7 @@ class PairTrackV0Builder } mColHistManager.template fill(col); mCprSe.setMagField(col.magField()); - pairprocesshelpers::processSameEvent(trackSlice, v0Slice, trackTable, col, mTrackHistManager, mV0HistManager, mPairHistManagerSe, mCprSe, mPc); + pairprocesshelpers::processSameEvent(trackSlice, v0Slice, trackTable, col, mTrackHistManager, mV0HistManager, mPairHistManagerSe, mCprSe, mPcSe); } template @@ -1275,7 +1326,7 @@ class PairTrackV0Builder } mColHistManager.template fill(col, mcCols); mCprSe.setMagField(col.magField()); - pairprocesshelpers::processSameEvent(trackSlice, v0Slice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager, mV0HistManager, mPairHistManagerSe, mTrackCleaner, mV0Cleaner, mCprSe, mPc); + pairprocesshelpers::processSameEvent(trackSlice, v0Slice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager, mV0HistManager, mPairHistManagerSe, mTrackCleaner, mV0Cleaner, mCprSe, mPcSe); } template @@ -1283,13 +1334,13 @@ class PairTrackV0Builder { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, trackPartition, v0Partition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, trackPartition, v0Partition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, trackPartition, v0Partition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, trackPartition, v0Partition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, trackPartition, v0Partition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, trackPartition, v0Partition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -1301,13 +1352,13 @@ class PairTrackV0Builder { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, v0Partition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mV0Cleaner, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, v0Partition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mV0Cleaner, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, v0Partition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mV0Cleaner, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, v0Partition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mV0Cleaner, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, v0Partition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mV0Cleaner, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, v0Partition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mV0Cleaner, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -1324,7 +1375,8 @@ class PairTrackV0Builder pairhistmanager::PairHistManager mPairHistManagerMe; closepairrejection::ClosePairRejectionTrackV0 mCprSe; closepairrejection::ClosePairRejectionTrackV0 mCprMe; - paircleaner::TrackV0PairCleaner mPc; + paircleaner::TrackV0PairCleaner mPcSe; + paircleaner::TrackV0PairCleaner mPcMe; pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; int mMixingDepth = 5; }; @@ -1359,7 +1411,8 @@ class PairTrackTwoTrackResonanceBuilder typename T11, typename T12, typename T13, - typename T14> + typename T14, + typename T15> void init(o2::framework::HistogramRegistry* registry, T1 const& confCollisionBinning, T2 const& confTrackSelection, @@ -1374,7 +1427,8 @@ class PairTrackTwoTrackResonanceBuilder std::map> const& posDauHistSpec, std::map> const& negDauHistSpec, std::map> const& pairHistSpec, - std::map> const& cprHistSpec) + std::map> const& cprHistSpec, + std::map> const& pairCleanerHistSpec) { mColHistManager.template init(registry, colHistSpec, confCollisionBinning); @@ -1390,6 +1444,8 @@ class PairTrackTwoTrackResonanceBuilder mPairHistManagerMe.setMass(confTrackSelection.pdgCodeAbs.value, confResonanceSelection.pdgCodeAbs.value); mPairHistManagerMe.setCharge(confTrackSelection.chargeAbs.value, 1); mCprMe.init(registry, cprHistSpec, confCpr, confTrackSelection.chargeAbs.value); + mPcSe.template init(registry, pairCleanerHistSpec, confPairCuts); + mPcMe.template init(registry, pairCleanerHistSpec, confPairCuts); // setup mixing mMixingPolicy = static_cast(confMixing.policy.value); @@ -1406,7 +1462,7 @@ class PairTrackTwoTrackResonanceBuilder } mColHistManager.template fill(col); mCprSe.setMagField(col.magField()); - pairprocesshelpers::processSameEvent(trackSlice, resonanaceSlice, trackTable, col, mTrackHistManager, mResonanceHistManager, mPairHistManagerSe, mCprSe, mPc); + pairprocesshelpers::processSameEvent(trackSlice, resonanaceSlice, trackTable, col, mTrackHistManager, mResonanceHistManager, mPairHistManagerSe, mCprSe, mPcSe); } template @@ -1414,13 +1470,13 @@ class PairTrackTwoTrackResonanceBuilder { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, trackPartition, resonancePartition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, trackPartition, resonancePartition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, trackPartition, resonancePartition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, trackPartition, resonancePartition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, trackPartition, resonancePartition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, trackPartition, resonancePartition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -1433,9 +1489,10 @@ class PairTrackTwoTrackResonanceBuilder twotrackresonancehistmanager::TwoTrackResonanceHistManager mResonanceHistManager; pairhistmanager::PairHistManager mPairHistManagerSe; pairhistmanager::PairHistManager mPairHistManagerMe; - closepairrejection::ClosePairRejectionTrackV0 mCprSe; // cpr for twotrackresonances and v0 work the same way - closepairrejection::ClosePairRejectionTrackV0 mCprMe; // cpr for twotrackresonances and v0 work the same way - paircleaner::TrackV0PairCleaner mPc; // pc for twotrackresonances and v0 work the same way + closepairrejection::ClosePairRejectionTrackV0 mCprSe; // cpr for twotrackresonances and v0 work the same way + closepairrejection::ClosePairRejectionTrackV0 mCprMe; // cpr for twotrackresonances and v0 work the same way + paircleaner::TrackV0PairCleaner mPcSe; // pc for twotrackresonances and v0 work the same way + paircleaner::TrackV0PairCleaner mPcMe; // pc for twotrackresonances and v0 work the same way pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; int mMixingDepth = 5; }; @@ -1479,7 +1536,8 @@ class PairV0TwoTrackResonanceBuilder typename T15, typename T16, typename T17, - typename T18> + typename T18, + typename T19> void init(o2::framework::HistogramRegistry* registry, T1 const& confCollisionBinning, T2 const& confV0Selection, @@ -1498,7 +1556,8 @@ class PairV0TwoTrackResonanceBuilder std::map> const& ResonanceNegDauHistSpec, std::map> const& pairHistSpec, std::map> const& cprHistSpecPos, - std::map> const& cprHistSpecNeg) + std::map> const& cprHistSpecNeg, + std::map> const& pairCleanerHistSpec) { mColHistManager.template init(registry, colHistSpec, confCollisionBinning); @@ -1514,6 +1573,8 @@ class PairV0TwoTrackResonanceBuilder mPairHistManagerMe.setMass(confV0Selection.pdgCodeAbs.value, confResonanceSelection.pdgCodeAbs.value); mPairHistManagerMe.setCharge(1, 1); // set charge to 1 mCprMe.init(registry, cprHistSpecPos, cprHistSpecNeg, confCprPos, confCprNeg); + mPcSe.template init(registry, pairCleanerHistSpec, confPairCuts); + mPcMe.template init(registry, pairCleanerHistSpec, confPairCuts); // setup mixing mMixingPolicy = static_cast(confMixing.policy.value); @@ -1530,7 +1591,7 @@ class PairV0TwoTrackResonanceBuilder } mColHistManager.template fill(col); mCprSe.setMagField(col.magField()); - pairprocesshelpers::processSameEvent(v0Slice, resonanaceSlice, trackTable, col, mV0HistManager, mResonanceHistManager, mPairHistManagerSe, mCprSe, mPc); + pairprocesshelpers::processSameEvent(v0Slice, resonanaceSlice, trackTable, col, mV0HistManager, mResonanceHistManager, mPairHistManagerSe, mCprSe, mPcSe); } template @@ -1538,13 +1599,13 @@ class PairV0TwoTrackResonanceBuilder { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, v0Partition, resonancePartition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, v0Partition, resonancePartition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, v0Partition, resonancePartition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, v0Partition, resonancePartition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, v0Partition, resonancePartition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, v0Partition, resonancePartition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -1559,7 +1620,8 @@ class PairV0TwoTrackResonanceBuilder pairhistmanager::PairHistManager mPairHistManagerMe; closepairrejection::ClosePairRejectionV0V0 mCprSe; // cpr for twotrackresonances and v0 work the same way closepairrejection::ClosePairRejectionV0V0 mCprMe; // cpr for twotrackresonances and v0 work the same way - paircleaner::V0V0PairCleaner mPc; // pc for twotrackresonances and v0 work the same way + paircleaner::V0V0PairCleaner mPcSe; // pc for twotrackresonances and v0 work the same way + paircleaner::V0V0PairCleaner mPcMe; // pc for twotrackresonances and v0 work the same way pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; int mMixingDepth = 5; }; @@ -1594,7 +1656,8 @@ class PairTrackKinkBuilder typename T12, typename T13, typename T14, - typename T15> + typename T15, + typename T16> void init(o2::framework::HistogramRegistry* registry, T1 const& confCollisionBinning, T2 const& confTrackSelection, @@ -1610,7 +1673,8 @@ class PairTrackKinkBuilder std::map> const& kinkHistSpec, std::map> const& chaDauHistSpec, std::map> const& pairHistSpec, - std::map> const& cprHistSpec) + std::map> const& cprHistSpec, + std::map> const& pairCleanerHistSpec) { mColHistManager.template init(registry, colHistSpec, confCollisionBinning); @@ -1629,7 +1693,8 @@ class PairTrackKinkBuilder mPairHistManagerMe.setMass(confTrackSelection.pdgCodeAbs.value, confKinkSelection.pdgCodeAbs.value); mPairHistManagerMe.setCharge(confTrackSelection.chargeAbs.value, 1); // abs charge of kink daughter is always 1 mCprMe.init(registry, cprHistSpec, confCpr, confTrackSelection.chargeAbs.value); - mPc.template init(confPairCuts); + mPcSe.template init(registry, pairCleanerHistSpec, confPairCuts); + mPcMe.template init(registry, pairCleanerHistSpec, confPairCuts); // setup mixing mMixingPolicy = static_cast(confMixing.policy.value); @@ -1646,7 +1711,7 @@ class PairTrackKinkBuilder } mColHistManager.template fill(col); mCprSe.setMagField(col.magField()); - pairprocesshelpers::processSameEvent(trackSlice, kinkSlice, trackTable, col, mTrackHistManager, mKinkHistManager, mPairHistManagerSe, mCprSe, mPc); + pairprocesshelpers::processSameEvent(trackSlice, kinkSlice, trackTable, col, mTrackHistManager, mKinkHistManager, mPairHistManagerSe, mCprSe, mPcSe); } template @@ -1659,7 +1724,7 @@ class PairTrackKinkBuilder } mColHistManager.template fill(col, mcCols); mCprSe.setMagField(col.magField()); - pairprocesshelpers::processSameEvent(trackSlice, kinkSlice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager, mKinkHistManager, mPairHistManagerSe, mTrackCleaner, mKinkCleaner, mCprSe, mPc); + pairprocesshelpers::processSameEvent(trackSlice, kinkSlice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager, mKinkHistManager, mPairHistManagerSe, mTrackCleaner, mKinkCleaner, mCprSe, mPcSe); } template @@ -1667,13 +1732,13 @@ class PairTrackKinkBuilder { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, trackPartition, kinkPartition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, trackPartition, kinkPartition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, trackPartition, kinkPartition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, trackPartition, kinkPartition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, trackPartition, kinkPartition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, trackPartition, kinkPartition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -1685,13 +1750,13 @@ class PairTrackKinkBuilder { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, kinkPartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mKinkCleaner, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, kinkPartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mKinkCleaner, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, kinkPartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mKinkCleaner, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, kinkPartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mKinkCleaner, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, kinkPartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mKinkCleaner, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, kinkPartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mKinkCleaner, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -1708,7 +1773,8 @@ class PairTrackKinkBuilder pairhistmanager::PairHistManager mPairHistManagerMe; closepairrejection::ClosePairRejectionTrackKink mCprSe; closepairrejection::ClosePairRejectionTrackKink mCprMe; - paircleaner::TrackKinkPairCleaner mPc; + paircleaner::TrackKinkPairCleaner mPcSe; + paircleaner::TrackKinkPairCleaner mPcMe; pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; int mMixingDepth = 5; }; @@ -1751,7 +1817,8 @@ class PairTrackCascadeBuilder typename T16, typename T17, typename T18, - typename T19> + typename T19, + typename T20> void init(o2::framework::HistogramRegistry* registry, T1 const& confCollisionBinning, T2 const& confTrackSelection, @@ -1771,7 +1838,8 @@ class PairTrackCascadeBuilder std::map> const& negDauHistSpec, std::map> const& pairHistSpec, std::map> const& cprHistSpecBachelor, - std::map> const& cprHistSpecV0Daughter) + std::map> const& cprHistSpecV0Daughter, + std::map> const& pairCleanerHistSpec) { mColHistManager.template init(registry, colHistSpec, confCollisionBinning); @@ -1790,6 +1858,8 @@ class PairTrackCascadeBuilder mPairHistManagerMe.setMass(confTrackSelection.pdgCodeAbs.value, confCascadeSelection.pdgCodeAbs.value); mPairHistManagerMe.setCharge(confTrackSelection.chargeAbs.value, 1); mCprMe.init(registry, cprHistSpecBachelor, cprHistSpecV0Daughter, confCprBachelor, confCprV0Daughter, confTrackSelection.chargeAbs.value); + mPcSe.template init(registry, pairCleanerHistSpec, confPairCuts); + mPcMe.template init(registry, pairCleanerHistSpec, confPairCuts); // setup mixing mMixingPolicy = static_cast(confMixing.policy.value); @@ -1806,7 +1876,7 @@ class PairTrackCascadeBuilder } mColHistManager.template fill(col); mCprSe.setMagField(col.magField()); - pairprocesshelpers::processSameEvent(trackSlice, cascadeSlice, trackTable, col, mTrackHistManager, mCascadeHistManager, mPairHistManagerSe, mCprSe, mPc); + pairprocesshelpers::processSameEvent(trackSlice, cascadeSlice, trackTable, col, mTrackHistManager, mCascadeHistManager, mPairHistManagerSe, mCprSe, mPcSe); } template @@ -1819,7 +1889,7 @@ class PairTrackCascadeBuilder } mColHistManager.template fill(col, mcCols); mCprSe.setMagField(col.magField()); - pairprocesshelpers::processSameEvent(trackSlice, cascadeSlice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager, mCascadeHistManager, mPairHistManagerSe, mTrackCleaner, mCascadeCleaner, mCprSe, mPc); + pairprocesshelpers::processSameEvent(trackSlice, cascadeSlice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager, mCascadeHistManager, mPairHistManagerSe, mTrackCleaner, mCascadeCleaner, mCprSe, mPcSe); } template @@ -1827,13 +1897,13 @@ class PairTrackCascadeBuilder { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, trackPartition, v0Partition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, trackPartition, v0Partition, trackTable, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, trackPartition, v0Partition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, trackPartition, v0Partition, trackTable, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, trackPartition, v0Partition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, trackPartition, v0Partition, trackTable, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -1845,13 +1915,13 @@ class PairTrackCascadeBuilder { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, cascadePartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mCascadeCleaner, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, cascadePartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mCascadeCleaner, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, cascadePartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mCascadeCleaner, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, cascadePartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mCascadeCleaner, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, cascadePartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mCascadeCleaner, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, mcCols, trackPartition, cascadePartition, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mTrackCleaner, mCascadeCleaner, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -1868,7 +1938,8 @@ class PairTrackCascadeBuilder pairhistmanager::PairHistManager mPairHistManagerMe; closepairrejection::ClosePairRejectionTrackCascade mCprSe; closepairrejection::ClosePairRejectionTrackCascade mCprMe; - paircleaner::TrackCascadePairCleaner mPc; + paircleaner::TrackCascadePairCleaner mPcSe; + paircleaner::TrackCascadePairCleaner mPcMe; pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; int mMixingDepth = 5; }; @@ -1897,7 +1968,8 @@ class PairMcParticleMcParticleBuilder typename T13, typename T14, typename T15, - typename T16> + typename T16, + typename T17> void init(o2::framework::HistogramRegistry* registry, T1 const& confCollisionBinning, T2 const& confMcParticleSelection1, @@ -1914,7 +1986,8 @@ class PairMcParticleMcParticleBuilder std::map> const& mcParticleHistSpec1, std::map> const& mcParticleHistSpec2, std::map> const& pairHistSpec, - std::map> const& cprHistSpec) + std::map> const& cprHistSpec, + std::map> const& pairCleanerHistSpec) { // check if correlate the same tracks or not @@ -1923,7 +1996,8 @@ class PairMcParticleMcParticleBuilder mColHistManager.template init(registry, colHistSpec, confCollisionBinning); mPairHistManagerSe.template init(registry, pairHistSpec, confPairBinning, confPairCuts, confMixing); mPairHistManagerMe.template init(registry, pairHistSpec, confPairBinning, confPairCuts, confMixing); - mPc.template init(confPairCuts); + mPcSe.template init(registry, pairCleanerHistSpec, confPairCuts); + mPcMe.template init(registry, pairCleanerHistSpec, confPairCuts); if (mSameSpecies) { mMcParticleCleaner1.init(confMcParticleCleaner1); @@ -1985,7 +2059,7 @@ class PairMcParticleMcParticleBuilder if (mMixIdenticalParticles) { pairOrder = static_cast(mDist(mRng)); } - pairprocesshelpers::processSameEvent(mcParticleSlice, mcParticles, mcMothers, mcPartonicMothers, col, mMcParticleHistManager1, mPairHistManagerSe, mMcParticleCleaner1, mCprSe, mPc, pairOrder); + pairprocesshelpers::processSameEvent(mcParticleSlice, mcParticles, mcMothers, mcPartonicMothers, col, mMcParticleHistManager1, mPairHistManagerSe, mMcParticleCleaner1, mCprSe, mPcSe, pairOrder); } else { auto mcParticleSlice1 = partition1->sliceByCached(o2::aod::femtomcparticle::fMcColId, col.globalIndex(), cache); auto mcParticleSlice2 = partition2->sliceByCached(o2::aod::femtomcparticle::fMcColId, col.globalIndex(), cache); @@ -1993,7 +2067,7 @@ class PairMcParticleMcParticleBuilder return; } mColHistManager.template fill(col); - pairprocesshelpers::processSameEvent(mcParticleSlice1, mcParticleSlice2, mcParticles, mcMothers, mcPartonicMothers, col, mMcParticleHistManager1, mMcParticleHistManager2, mPairHistManagerSe, mMcParticleCleaner1, mMcParticleCleaner2, mCprSe, mPc); + pairprocesshelpers::processSameEvent(mcParticleSlice1, mcParticleSlice2, mcParticles, mcMothers, mcPartonicMothers, col, mMcParticleHistManager1, mMcParticleHistManager2, mPairHistManagerSe, mMcParticleCleaner1, mMcParticleCleaner2, mCprSe, mPcSe); } } @@ -2003,13 +2077,13 @@ class PairMcParticleMcParticleBuilder if (mSameSpecies) { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, partition1, partition1, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mMcParticleCleaner1, mMcParticleCleaner1, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition1, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mMcParticleCleaner1, mMcParticleCleaner1, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, partition1, partition1, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mMcParticleCleaner1, mMcParticleCleaner1, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition1, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mMcParticleCleaner1, mMcParticleCleaner1, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, partition1, partition1, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mMcParticleCleaner1, mMcParticleCleaner1, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition1, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mMcParticleCleaner1, mMcParticleCleaner1, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -2017,13 +2091,13 @@ class PairMcParticleMcParticleBuilder } else { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - pairprocesshelpers::processMixedEvent(cols, partition1, partition2, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mMcParticleCleaner1, mMcParticleCleaner2, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mPairHistManagerMe, mMcParticleCleaner1, mMcParticleCleaner2, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxCent): - pairprocesshelpers::processMixedEvent(cols, partition1, partition2, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mMcParticleCleaner1, mMcParticleCleaner2, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mPairHistManagerMe, mMcParticleCleaner1, mMcParticleCleaner2, mCprMe, mPcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - pairprocesshelpers::processMixedEvent(cols, partition1, partition2, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mMcParticleCleaner1, mMcParticleCleaner2, mCprMe, mPc); + pairprocesshelpers::processMixedEvent(cols, partition1, partition2, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mPairHistManagerMe, mMcParticleCleaner1, mMcParticleCleaner2, mCprMe, mPcMe); break; default: LOG(fatal) << "Invalid binning policiy specifed. Breaking..."; @@ -2039,7 +2113,8 @@ class PairMcParticleMcParticleBuilder pairhistmanager::PairHistManager mPairHistManagerMe; closepairrejection::ClosePairRejectionMcParticleMcParticle mCprSe; closepairrejection::ClosePairRejectionMcParticleMcParticle mCprMe; - paircleaner::McParticleMcParticlePairCleaner mPc; + paircleaner::McParticleMcParticlePairCleaner mPcSe; + paircleaner::McParticleMcParticlePairCleaner mPcMe; particlecleaner::ParticleCleaner mMcParticleCleaner1; particlecleaner::ParticleCleaner mMcParticleCleaner2; pairhistmanager::MixingPolicy mMixingPolicy = pairhistmanager::MixingPolicy::kVtxMult; diff --git a/PWGCF/Femto/Core/pairCleaner.h b/PWGCF/Femto/Core/pairCleaner.h index 7c5763b15ad..6bf859149b8 100644 --- a/PWGCF/Femto/Core/pairCleaner.h +++ b/PWGCF/Femto/Core/pairCleaner.h @@ -16,20 +16,94 @@ #ifndef PWGCF_FEMTO_CORE_PAIRCLEANER_H_ #define PWGCF_FEMTO_CORE_PAIRCLEANER_H_ +#include "PWGCF/Femto/Core/histManager.h" #include "PWGCF/Femto/Core/modes.h" +#include +#include +#include #include +#include + +#include +#include +#include +#include + namespace o2::analysis::femto::paircleaner { + +// enum for pair cleaner histograms +enum PairCleanerHist { + // standard 1D + kStats, + kKinematic, // kinematic variable of the pair/triplet + kPairCleanerHistLast +}; + +// bin indices (0-based fill values) for the kStats histogram +enum PairCleanerStatsBin { + kAllAnalyzed = 0, + kAllBlocked = 1, + kPairCleanerStatsBinLast = 2, +}; + +struct ConfPairCleanerBinning : o2::framework::ConfigurableGroup { + std::string prefix = std::string("PairCleanerBinning"); + o2::framework::ConfigurableAxis kinematic{"kinematic", {{100, 0.f, 1.f}}, "kinematic"}; +}; + +constexpr std::array, kPairCleanerHistLast> + HistTable = { + { + // 1D + {kStats, o2::framework::HistType::kTH1F, "hStats", "Stats; ; Entries"}, + {kKinematic, o2::framework::HistType::kTH1F, "hKinematic", "Kinematic of blocked pairs; Kinematic variable (GeV/#it{c}); Entries"}, + }}; + +template +auto makePairCleanerHistSpecMap(const T& confPairCleaner) +{ + return std::map>{ + {kKinematic, {confPairCleaner.kinematic}}, + }; +}; + +constexpr char PrefixPairCleanerTrackTrackSe[] = "TrackTrackCleaner/SE/"; +constexpr char PrefixPairCleanerTrackTrackMe[] = "TrackTrackCleaner/ME/"; +constexpr char PrefixPairCleanerV0V0Se[] = "V0V0Cleaner/SE/"; +constexpr char PrefixPairCleanerV0V0Me[] = "V0V0Cleaner/ME/"; +constexpr char PrefixPairCleanerD0D0Se[] = "D0D0Cleaner/SE/"; +constexpr char PrefixPairCleanerD0D0Me[] = "D0D0Cleaner/ME/"; +constexpr char PrefixPairCleanerTrackV0Se[] = "TrackV0Cleaner/SE/"; +constexpr char PrefixPairCleanerTrackV0Me[] = "TrackV0Cleaner/ME/"; +constexpr char PrefixPairCleanerTrackD0Se[] = "TrackD0Cleaner/SE/"; +constexpr char PrefixPairCleanerTrackD0Me[] = "TrackD0Cleaner/ME/"; +constexpr char PrefixPairCleanerTrackLcSe[] = "TrackLcCleaner/SE/"; +constexpr char PrefixPairCleanerTrackLcMe[] = "TrackLcCleaner/ME/"; +constexpr char PrefixPairCleanerTrackResonanceSe[] = "TrackResonanceCleaner/SE/"; +constexpr char PrefixPairCleanerTrackResonanceMe[] = "TrackResonanceCleaner/ME/"; +constexpr char PrefixPairCleanerV0ResonanceSe[] = "V0ResonanceCleaner/SE/"; +constexpr char PrefixPairCleanerV0ResonanceMe[] = "V0ResonanceCleaner/ME/"; +constexpr char PrefixPairCleanerTrackKinkSe[] = "TrackKinkCleaner/SE/"; +constexpr char PrefixPairCleanerTrackKinkMe[] = "TrackKinkCleaner/ME/"; +constexpr char PrefixPairCleanerTrackCascadeSe[] = "TrackCascadeCleaner/SE/"; +constexpr char PrefixPairCleanerTrackCascadeMe[] = "TrackCascadeCleaner/ME/"; +constexpr char PrefixPairCleanerMcParticleMcParticleSe[] = "McParticleMcParticleCleaner/SE/"; +constexpr char PrefixPairCleanerMcParticleMcParticleMe[] = "McParticleMcParticleCleaner/ME/"; + +template class BasePairCleaner { public: BasePairCleaner() = default; virtual ~BasePairCleaner() = default; - template - void init(T const& pairCuts) + template + void init(o2::framework::HistogramRegistry* registry, + T1 const& specs, + T2 const& pairCuts) // pair cuts configurable is defined in pairHistManager.h { if constexpr (modes::isFlagSet(mode, modes::Mode::kMc)) { mMixPairsWithCommonAncestor = pairCuts.mixOnlyCommonAncestor.value; @@ -39,6 +113,14 @@ class BasePairCleaner LOG(fatal) << "Both mixing with common and non-common ancestor is activated. Breaking..."; } } + + mHistogramRegistry = registry; + int nStatBins = static_cast(kPairCleanerStatsBinLast); + const o2::framework::AxisSpec axisStats = {nStatBins, -0.5, nStatBins - 0.5}; + mHistogramRegistry->add(std::string(prefix) + getHistNameV2(kStats, HistTable), getHistDesc(kStats, HistTable), getHistType(kStats, HistTable), {axisStats}); + mHistogramRegistry->get(HIST(prefix) + HIST(histmanager::getHistName(kStats, HistTable)))->GetXaxis()->SetBinLabel(1, "All analyzed reco pairs"); + mHistogramRegistry->get(HIST(prefix) + HIST(histmanager::getHistName(kStats, HistTable)))->GetXaxis()->SetBinLabel(2, "All blocked reco pairs"); + mHistogramRegistry->add(std::string(prefix) + getHistNameV2(kKinematic, HistTable), getHistDesc(kKinematic, HistTable), getHistType(kKinematic, HistTable), {specs.at(kKinematic)}); } protected: @@ -48,6 +130,19 @@ class BasePairCleaner return particle1.globalIndex() != particle2.globalIndex(); }; + // const: only mutates *mHistogramRegistry through the stored pointer, not the pointer itself, + // so it can be called from the const isCleanPair() overloads below. + void fillAll() const + { + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kStats, HistTable)), kAllAnalyzed); + } + + void fillBlocked(float kinematic) const + { + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kStats, HistTable)), kAllBlocked); + mHistogramRegistry->fill(HIST(prefix) + HIST(getHistName(kKinematic, HistTable)), kinematic); + } + // mc only // ancestry is checked either with the partonic mother or with the first ancestor (i.e. the direct mother), depending on mUseMotherAsAncestor template @@ -140,216 +235,264 @@ class BasePairCleaner return particle1.fMcMotherId() == particle2.fMcMotherId(); }; + o2::framework::HistogramRegistry* mHistogramRegistry = nullptr; bool mUseMotherAsAncestor = false; }; -class TrackTrackPairCleaner : public BasePairCleaner +template +class TrackTrackPairCleaner : public BasePairCleaner { public: TrackTrackPairCleaner() = default; - template - bool isCleanPair(T1 const& track1, T2 const& track2, T3 const& /*trackTable*/) const + template + bool isCleanPair(T1 const& track1, T2 const& track2, T3 const& /*trackTable*/, T4 const& pairHistManager) const { - return this->isCleanParticlePair(track1, track2); + this->fillAll(); + bool isClean = this->isCleanParticlePair(track1, track2); + if (!isClean) { + this->fillBlocked(pairHistManager.getKinematic()); + } + return isClean; } - template - bool isCleanPair(T1 const& track1, T2 const& track2, T3 const& trackTable, T4 const& mcParticles, T5 const& partonicMothers) const + template + bool isCleanPair(T1 const& track1, T2 const& track2, T3 const& trackTable, T4 const& mcParticles, T5 const& partonicMothers, T6 const& pairHistManager) const { - if (!this->isCleanPair(track1, track2, trackTable)) { + if (!this->isCleanPair(track1, track2, trackTable, pairHistManager)) { return false; } // pair is clean // no check if we require common or non-common ancestry - if (mMixPairsWithCommonAncestor) { + if (this->mMixPairsWithCommonAncestor) { return this->pairHasCommonAncestor(track1, track2, mcParticles, partonicMothers); } - if (mMixPairsWithNonCommonAncestor) { + if (this->mMixPairsWithNonCommonAncestor) { return this->pairHasNonCommonAncestor(track1, track2, mcParticles, partonicMothers); } return true; } }; -class V0V0PairCleaner : public BasePairCleaner // also works for particles decaying into a positive and negative daughter, like resonances +template +class V0V0PairCleaner : public BasePairCleaner // also works for particles decaying into a positive and negative daughter, like resonances { public: V0V0PairCleaner() = default; - template - bool isCleanPair(T1 const& v01, T2 const& v02, T3 const& trackTable) const + + template + bool isCleanPair(T1 const& v01, T2 const& v02, T3 const& trackTable, T4 const& pairHistManager) const { + this->fillAll(); auto posDaughter1 = trackTable.rawIteratorAt(v01.posDauId() - trackTable.offset()); auto negDaughter1 = trackTable.rawIteratorAt(v01.negDauId() - trackTable.offset()); auto posDaughter2 = trackTable.rawIteratorAt(v02.posDauId() - trackTable.offset()); auto negDaughter2 = trackTable.rawIteratorAt(v02.negDauId() - trackTable.offset()); - return this->isCleanParticlePair(v01, v02) && - this->isCleanParticlePair(posDaughter1, posDaughter2) && this->isCleanParticlePair(negDaughter1, negDaughter2) && - this->isCleanParticlePair(posDaughter1, negDaughter2) && this->isCleanParticlePair(negDaughter1, posDaughter2); + bool isClean = this->isCleanParticlePair(v01, v02) && + this->isCleanParticlePair(posDaughter1, posDaughter2) && this->isCleanParticlePair(negDaughter1, negDaughter2) && + this->isCleanParticlePair(posDaughter1, negDaughter2) && this->isCleanParticlePair(negDaughter1, posDaughter2); + if (!isClean) { + this->fillBlocked(pairHistManager.getKinematic()); + } + return isClean; } - template - bool isCleanPair(T1 const& v01, T2 const& v02, T3 const& trackTable, T4 const& mcParticles, T5 const& partonicMothers) const + template + bool isCleanPair(T1 const& v01, T2 const& v02, T3 const& trackTable, T4 const& mcParticles, T5 const& partonicMothers, T6 const& pairHistManager) const { - if (!this->isCleanPair(v01, v02, trackTable)) { + if (!this->isCleanPair(v01, v02, trackTable, pairHistManager)) { return false; } // pair is clean // no check if we require common or non-common ancestry - if (mMixPairsWithCommonAncestor) { + if (this->mMixPairsWithCommonAncestor) { return this->pairHasCommonAncestor(v01, v02, mcParticles, partonicMothers); } - if (mMixPairsWithNonCommonAncestor) { + if (this->mMixPairsWithNonCommonAncestor) { return this->pairHasNonCommonAncestor(v01, v02, mcParticles, partonicMothers); } return true; } }; -class TrackV0PairCleaner : public BasePairCleaner // also works for particles decaying into a positive and negative daughter, like resonances +template +class TrackV0PairCleaner : public BasePairCleaner // also works for particles decaying into a positive and negative daughter, like resonances { public: TrackV0PairCleaner() = default; - template - bool isCleanPair(T1 const& track, T2 const& v0, T3 const& trackTable) const + + template + bool isCleanPair(T1 const& track, T2 const& v0, T3 const& trackTable, T4 const& pairHistManager) const { + this->fillAll(); auto posDaughter = trackTable.rawIteratorAt(v0.posDauId() - trackTable.offset()); auto negDaughter = trackTable.rawIteratorAt(v0.negDauId() - trackTable.offset()); - return (this->isCleanParticlePair(posDaughter, track) && this->isCleanParticlePair(negDaughter, track)); + bool isClean = this->isCleanParticlePair(posDaughter, track) && this->isCleanParticlePair(negDaughter, track); + if (!isClean) { + this->fillBlocked(pairHistManager.getKinematic()); + } + return isClean; } - template - bool isCleanPair(T1 const& track1, T2 const& v0, T3 const& trackTable, T4 const& mcParticles, T5 const& partonicMothers) const + template + bool isCleanPair(T1 const& track1, T2 const& v0, T3 const& trackTable, T4 const& mcParticles, T5 const& partonicMothers, T6 const& pairHistManager) const { - if (!this->isCleanPair(track1, v0, trackTable)) { + if (!this->isCleanPair(track1, v0, trackTable, pairHistManager)) { return false; } // pair is clean // now check if we require common or non-common ancestry - if (mMixPairsWithCommonAncestor) { + if (this->mMixPairsWithCommonAncestor) { return this->pairHasCommonAncestor(track1, v0, mcParticles, partonicMothers); } - if (mMixPairsWithNonCommonAncestor) { + if (this->mMixPairsWithNonCommonAncestor) { return this->pairHasNonCommonAncestor(track1, v0, mcParticles, partonicMothers); } return true; } }; -class TrackKinkPairCleaner : public BasePairCleaner +template +class TrackKinkPairCleaner : public BasePairCleaner { public: TrackKinkPairCleaner() = default; - template - bool isCleanPair(T1 const& track, T2 const& kink, T3 const& trackTable) const + + template + bool isCleanPair(T1 const& track, T2 const& kink, T3 const& trackTable, T4 const& pairHistManager) const { + this->fillAll(); auto chaDaughter = trackTable.rawIteratorAt(kink.chaDauId() - trackTable.offset()); - return this->isCleanParticlePair(chaDaughter, track); + bool isClean = this->isCleanParticlePair(chaDaughter, track); + if (!isClean) { + this->fillBlocked(pairHistManager.getKinematic()); + } + return isClean; } - template - bool isCleanPair(T1 const& track1, T2 const& kink, T3 const& trackTable, T4 const& mcParticles, T5 const& partonicMothers) const + template + bool isCleanPair(T1 const& track1, T2 const& kink, T3 const& trackTable, T4 const& mcParticles, T5 const& partonicMothers, T6 const& pairHistManager) const { - if (!this->isCleanPair(track1, kink, trackTable)) { + if (!this->isCleanPair(track1, kink, trackTable, pairHistManager)) { return false; } // pair is clean // now check if we require common or non-common ancestry - if (mMixPairsWithCommonAncestor) { + if (this->mMixPairsWithCommonAncestor) { return this->pairHasCommonAncestor(track1, kink, mcParticles, partonicMothers); } - if (mMixPairsWithNonCommonAncestor) { + if (this->mMixPairsWithNonCommonAncestor) { return this->pairHasNonCommonAncestor(track1, kink, mcParticles, partonicMothers); } return true; } }; -class TrackCascadePairCleaner : public BasePairCleaner +template +class TrackCascadePairCleaner : public BasePairCleaner { public: TrackCascadePairCleaner() = default; - template - bool isCleanPair(T1 const& track, T2 const& cascade, T3 const& trackTable) const + + template + bool isCleanPair(T1 const& track, T2 const& cascade, T3 const& trackTable, T4 const& pairHistManager) const { + this->fillAll(); auto bachelor = trackTable.rawIteratorAt(cascade.bachelorId() - trackTable.offset()); auto posDaughter = trackTable.rawIteratorAt(cascade.posDauId() - trackTable.offset()); auto negDaughter = trackTable.rawIteratorAt(cascade.negDauId() - trackTable.offset()); - return (this->isCleanParticlePair(bachelor, track) && this->isCleanParticlePair(posDaughter, track) && this->isCleanParticlePair(negDaughter, track)); + bool isClean = this->isCleanParticlePair(bachelor, track) && this->isCleanParticlePair(posDaughter, track) && this->isCleanParticlePair(negDaughter, track); + if (!isClean) { + this->fillBlocked(pairHistManager.getKinematic()); + } + return isClean; } - template - bool isCleanPair(T1 const& track1, T2 const& cascade, T3 const& trackTable, T4 const& mcParticles, T5 const& partonicMothers) const + template + bool isCleanPair(T1 const& track1, T2 const& cascade, T3 const& trackTable, T4 const& mcParticles, T5 const& partonicMothers, T6 const& pairHistManager) const { - if (!this->isCleanPair(track1, cascade, trackTable)) { + if (!this->isCleanPair(track1, cascade, trackTable, pairHistManager)) { return false; } // pair is clean // now check if we require common or non-common ancestry - if (mMixPairsWithCommonAncestor) { + if (this->mMixPairsWithCommonAncestor) { return this->pairHasCommonAncestor(track1, cascade, mcParticles, partonicMothers); } - if (mMixPairsWithNonCommonAncestor) { + if (this->mMixPairsWithNonCommonAncestor) { return this->pairHasNonCommonAncestor(track1, cascade, mcParticles, partonicMothers); } return true; } }; -class TrackLcPairCleaner : public BasePairCleaner +template +class TrackLcPairCleaner : public BasePairCleaner { public: TrackLcPairCleaner() = default; - template - bool isCleanPair(T1 const& track, T2 const& lc, T3 const& trackTable) const + + template + bool isCleanPair(T1 const& track, T2 const& lc, T3 const& trackTable, T4 const& pairHistManager) const { + this->fillAll(); auto prong0 = trackTable.rawIteratorAt(lc.prong0DauId() - trackTable.offset()); auto prong1 = trackTable.rawIteratorAt(lc.prong1DauId() - trackTable.offset()); auto prong2 = trackTable.rawIteratorAt(lc.prong2DauId() - trackTable.offset()); - return (this->isCleanParticlePair(prong0, track) && this->isCleanParticlePair(prong1, track) && this->isCleanParticlePair(prong2, track)); + bool isClean = this->isCleanParticlePair(prong0, track) && this->isCleanParticlePair(prong1, track) && this->isCleanParticlePair(prong2, track); + if (!isClean) { + this->fillBlocked(pairHistManager.getKinematic()); + } + return isClean; } - template - bool isCleanPair(T1 const& track1, T2 const& lc, T3 const& trackTable, T4 const& mcParticles, T5 const& partonicMothers) const + template + bool isCleanPair(T1 const& track1, T2 const& lc, T3 const& trackTable, T4 const& mcParticles, T5 const& partonicMothers, T6 const& pairHistManager) const { - if (!this->isCleanPair(track1, lc, trackTable)) { + if (!this->isCleanPair(track1, lc, trackTable, pairHistManager)) { return false; } // pair is clean // now check if we require common or non-common ancestry - if (mMixPairsWithCommonAncestor) { + if (this->mMixPairsWithCommonAncestor) { return this->pairHasCommonAncestor(track1, lc, mcParticles, partonicMothers); } - if (mMixPairsWithNonCommonAncestor) { + if (this->mMixPairsWithNonCommonAncestor) { return this->pairHasNonCommonAncestor(track1, lc, mcParticles, partonicMothers); } return true; } }; -class McParticleMcParticlePairCleaner : public BasePairCleaner +template +class McParticleMcParticlePairCleaner : public BasePairCleaner { public: McParticleMcParticlePairCleaner() = default; - template - bool isCleanPair(T1 const& particle1, T2 const& particle2) const + template + bool isCleanPair(T1 const& particle1, T2 const& particle2, T3 const& pairHistManager) const { - return this->isCleanParticlePair(particle1, particle2); + this->fillAll(); + bool isClean = this->isCleanParticlePair(particle1, particle2); + if (!isClean) { + this->fillBlocked(pairHistManager.getKinematic()); + } + return isClean; } - template - bool isCleanPair(T1 const& particle1, T2 const& particle2, T3 const& partonicMothers) const + template + bool isCleanPair(T1 const& particle1, T2 const& particle2, T3 const& partonicMothers, T4 const& pairHistManager) const { - if (!this->isCleanPair(particle1, particle2)) { + if (!this->isCleanPair(particle1, particle2, pairHistManager)) { return false; } // pair is clean // no check if we require common or non-common ancestry - if (mMixPairsWithCommonAncestor) { + if (this->mMixPairsWithCommonAncestor) { return this->mcPairHasCommonAncestor(particle1, particle2, partonicMothers); } - if (mMixPairsWithNonCommonAncestor) { + if (this->mMixPairsWithNonCommonAncestor) { return this->mcPairHasNonCommonAncestor(particle1, particle2, partonicMothers); } return true; diff --git a/PWGCF/Femto/Core/pairHistManager.h b/PWGCF/Femto/Core/pairHistManager.h index 99382d6baa9..08a40744013 100644 --- a/PWGCF/Femto/Core/pairHistManager.h +++ b/PWGCF/Femto/Core/pairHistManager.h @@ -155,7 +155,11 @@ enum PairHist { kQout, kQside, kQlong, - kQoutQsideQlong, + kQoutVsQsideVsQlong, + + // event shape enginerring + kQoutVsQsideVsQlongVsMtVsCentVsEventPlaneAngleVsQvector, + kPairHistogramLast }; @@ -163,6 +167,7 @@ enum MixingPolicy { kVtxMult, kVtxCent, kVtxMultCent, + kVtxCentEventPlaneAngle, kMixingPolicyLast }; @@ -172,8 +177,9 @@ struct ConfMixing : o2::framework::ConfigurableGroup { o2::framework::ConfigurableAxis multBins{"multBins", {o2::framework::VARIABLE_WIDTH, 0.0f, 4.0f, 8.0f, 12.0f, 16.0f, 20.0f, 24.0f, 28.0f, 32.0f, 36.0f, 40.0f, 44.0f, 48.0f, 52.0f, 56.0f, 60.0f, 64.0f, 68.0f, 72.0f, 76.0f, 80.0f, 84.0f, 88.0f, 92.0f, 96.0f, 100.0f, 200.0f}, "Mixing bins - multiplicity"}; o2::framework::ConfigurableAxis centBins{"centBins", {o2::framework::VARIABLE_WIDTH, 0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f}, "Mixing bins - centrality"}; o2::framework::ConfigurableAxis vtxBins{"vtxBins", {o2::framework::VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; + o2::framework::ConfigurableAxis eventPlaneAngle{"eventPlaneAngle", {10, 0.f, 1.f * o2::constants::math::TwoPI}, "Mixing bins - event plane angle"}; o2::framework::Configurable depth{"depth", 5, "Number of events for mixing"}; - o2::framework::Configurable policy{"policy", 0, "Binning policy for mixing (alywas in combination with z-vertex) -> 0: multiplicity, -> 1: centrality, -> 2: both"}; + o2::framework::Configurable policy{"policy", 0, "Binning policy for mixing (alywas in combination with z-vertex) -> 0: multiplicity, -> 1: centrality, -> 2: multiplicity and centrality, -> 3: centrality and event plane angle"}; o2::framework::Configurable sameSpecies{"sameSpecies", false, "Enable if particle 1 and particle 2 are the same"}; o2::framework::Configurable seed{"seed", -1, "Seed to randomize particle 1 and particle 2 (if they are identical). Set to negative value to deactivate. Set to 0 to generate unique seed in time."}; o2::framework::Configurable enablePairCorrelationQa{"enablePairCorrelationQa", true, "Enable pair-level correlation QA (same-event + mixed-event)"}; @@ -221,12 +227,16 @@ struct ConfPairBinning : o2::framework::ConfigurableGroup { o2::framework::ConfigurableAxis dalitzM12{"dalitzM12", {{100, 0, 10}}, "Mass12 binning of darlitz plot"}; o2::framework::ConfigurableAxis dalitzM13{"dalitzM13", {{100, 0, 10}}, "Mass13 binning of darlitz plot"}; o2::framework::Configurable transverseMassType{"transverseMassType", static_cast(modes::TransverseMassType::kAveragePdgMass), "Type of transverse mass (0-> Average Pdg Mass, 1-> Reduced Pdg Mass, 2-> Mt from combined 4 vector)"}; + o2::framework::Configurable kinematicVariable{"kinematicVariable", static_cast(modes::KinematicVariable::kKstar), "Type of kinematic variable (0->kstar, 1->kT, 2->mT) for PC and CPR plots"}; o2::framework::ConfigurableAxis binningDeltaEta{"binningDeltaEta", {{35, -1.6, 1.6}}, "Delta eta"}; o2::framework::ConfigurableAxis binningDeltaPhi{"binningDeltaPhi", {{35, -o2::constants::math::PIHalf, 3 * o2::constants::math::PIHalf}}, "Delta phi"}; o2::framework::Configurable plotBertschPratt{"plotBertschPratt", false, "(Reco/Mc) Enable 1D projections and 3D (q_out, q_side, q_long) Bertsch-Pratt histograms in LCMS"}; o2::framework::ConfigurableAxis qout{"qout", {{300, -1.5f, 1.5f}}, "q_{out} (GeV/c) in LCMS"}; o2::framework::ConfigurableAxis qside{"qside", {{300, -1.5f, 1.5f}}, "q_{side} (GeV/c) in LCMS"}; o2::framework::ConfigurableAxis qlong{"qlong", {{300, -1.5f, 1.5f}}, "q_{long} (GeV/c) in LCMS"}; + o2::framework::Configurable plotEventShape{"plotEventShape", false, "(Reco/Mc) Enable 7D (q_out, q_side, q_long, mt, centrality event plane angle, qvector) histogram"}; + o2::framework::ConfigurableAxis eventPlaneAngle{"eventPlaneAngle", {{10, 0.f, 1.f * o2::constants::math::TwoPI}}, "event plane angle"}; + o2::framework::ConfigurableAxis qvector{"qvector", {{o2::framework::VARIABLE_WIDTH, 0.50f, 68.50f, 100.50f, 126.50f, 151.50f, 176.50f, 203.50f, 232.50f, 269.50f, 322.50f, 833.50f}}, "qvector"}; o2::framework::Configurable plotSH{"plotSH", false, "(Reco) Enable spherical-harmonics decomposition of the pair momentum-difference vector"}; o2::framework::Configurable shLMax{"shLMax", 2, "Maximum l for SH decomposition (0..5). FemtoUniverse hard-codes 1."}; o2::framework::Configurable shFrame{"shFrame", 1, "SH reference frame/variable: 0=LCMS non-identical (k*), 1=LCMS identical (qinv, FemtoUniverse default), 2=PRF (q_PRF, matches FemtoUniverse isIdenPRF=true)"}; @@ -349,10 +359,11 @@ constexpr std::array, kPairHistogramLast> {kQout, o2::framework::HistType::kTH1F, "hQout", "q_{out} in LCMS; q_{out} (GeV/#it{c}); Entries"}, {kQside, o2::framework::HistType::kTH1F, "hQside", "q_{side} in LCMS; q_{side} (GeV/#it{c}); Entries"}, {kQlong, o2::framework::HistType::kTH1F, "hQlong", "q_{long} in LCMS; q_{long} (GeV/#it{c}); Entries"}, - {kQoutQsideQlong, o2::framework::HistType::kTH3F, "hQoutQsideQlong", "Bertsch-Pratt 3D; q_{out} (GeV/#it{c}); q_{side} (GeV/#it{c}); q_{long} (GeV/#it{c})"}, + {kQoutVsQsideVsQlong, o2::framework::HistType::kTH3F, "hQoutQsideQlong", "Bertsch-Pratt 3D; q_{out} (GeV/#it{c}); q_{side} (GeV/#it{c}); q_{long} (GeV/#it{c})"}, {kTrueQoutVsQout, o2::framework::HistType::kTH2F, "hTrueQoutVsQout", "q_{out,True} vs q_{out}; q_{out,True} (GeV/#it{c}); q_{out} (GeV/#it{c})"}, {kTrueQsideVsQside, o2::framework::HistType::kTH2F, "hTrueQsideVsQside", "q_{side,True} vs q_{side}; q_{side,True} (GeV/#it{c}); q_{side} (GeV/#it{c})"}, {kTrueQlongVsQlong, o2::framework::HistType::kTH2F, "hTrueQlongVsQlong", "q_{long,True} vs q_{long}; q_{long,True} (GeV/#it{c}); q_{long} (GeV/#it{c})"}, + {kQoutVsQsideVsQlongVsMtVsCentVsEventPlaneAngleVsQvector, o2::framework::HistType::kTHnSparseF, "hQoutQsideQlongEventPlaneAngleQvector", "Event shape enginering; q_{out} (GeV/#it{c}); q_{side} (GeV/#it{c}); q_{long} (GeV/#it{c}); #varphi_{EP}; q-vector;"}, }}; // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) @@ -402,7 +413,8 @@ constexpr std::array, kPairHistogramLast> {kQout, {(confAnalysis).qout}}, \ {kQside, {(confAnalysis).qside}}, \ {kQlong, {(confAnalysis).qlong}}, \ - {kQoutQsideQlong, {(confAnalysis).qout, (confAnalysis).qside, (confAnalysis).qlong}}, + {kQoutVsQsideVsQlong, {(confAnalysis).qout, (confAnalysis).qside, (confAnalysis).qlong}}, \ + {kQoutVsQsideVsQlongVsMtVsCentVsEventPlaneAngleVsQvector, {(confAnalysis).qout, (confAnalysis).qside, (confAnalysis).qlong, (confAnalysis).mt, (confAnalysis).centrality, (confAnalysis).eventPlaneAngle, (confAnalysis).qvector}}, // mixing-qa entries are independent of reco vs mc-truth status — both the reco // analysis path and the pure mc-truth path need them whenever kSe/kMe is set @@ -577,6 +589,7 @@ class PairHistManager mPlotDalitz = ConfPairBinning.plotDalitz.value; mPlotDeltaEtaDeltaPhi = ConfPairBinning.plotDeltaEtaDeltaPhi.value; mPlotBertschPratt = ConfPairBinning.plotBertschPratt.value; + mPlotEventShape = ConfPairBinning.plotEventShape.value; mPlotSH = ConfPairBinning.plotSH.value; mShUseCent = ConfPairBinning.shUseCent.value; @@ -596,6 +609,9 @@ class PairHistManager // transverse mass type mMtType = static_cast(ConfPairBinning.transverseMassType.value); + // kinematic variable + mKinematicVariable = static_cast(ConfPairBinning.kinematicVariable.value); + // values for cuts mKstarMin = ConfPairCuts.kstarMin.value; mKstarMax = ConfPairCuts.kstarMax.value; @@ -654,81 +670,10 @@ class PairHistManager mAbsCharge2 = std::abs(chargeAbsParticle2); } - template - void setPair(T1 const& particle1, T2 const& particle2, T3 const& trackTable) - { - // if one of the particles has a mass getter (like lambda), we cache the value for the filling later - // otherwise set it to the pdg mass - if constexpr (utils::HasMass) { - mRecoMass1 = particle1.mass(); - } else { - mRecoMass1 = mPdgMass1; - } - if constexpr (utils::HasMass) { - mRecoMass2 = particle2.mass(); - } else { - mRecoMass2 = mPdgMass2; - } - - // get mass for 4-vectors - double mass1 = 0.f; - double mass2 = 0.f; - if (mUsePdgMass) { - mass1 = mPdgMass1; - mass2 = mPdgMass2; - } else { - mass1 = mRecoMass1; - mass2 = mRecoMass2; - } - - // pt in track table is calculated from 1/signedPt from the original track table - // in case of He with Z=2, we have to rescale the pt with the absolute charge - mParticle1 = ROOT::Math::PtEtaPhiMVector(mAbsCharge1 * particle1.pt(), particle1.eta(), particle1.phi(), mass1); - mParticle2 = ROOT::Math::PtEtaPhiMVector(mAbsCharge2 * particle2.pt(), particle2.eta(), particle2.phi(), mass2); - - // set kT - mKt = getKt(mParticle1, mParticle2); - - // set mT - mMt = getMt(mParticle1, mParticle2); - - // set Minv - mMassInv = getMinv(mParticle1, mParticle2); - - // set kstar - mKstar = getKstar(mParticle1, mParticle2); - - if (mPlotBertschPratt) { - std::tie(mQout, mQside, mQlong) = computeBertschPrattLCMS(mParticle1, mParticle2); - } - - if (mPlotSH) { - std::tie(mShKv, mShOut, mShSide, mShLong) = computeShKinematics(mParticle1, mParticle2); - } - - if (mPlotDeltaEtaDeltaPhi) { - mDeltaEta = particle1.eta() - particle2.eta(); - mDeltaPhi = RecoDecay::constrainAngle(particle1.phi() - particle2.phi(), -o2::constants::math::PIHalf); - } - - if (mPlotDalitz) { - if constexpr (modes::isEqual(particleType1, modes::Particle::kTrack) && (modes::isEqual(particleType2, modes::Particle::kV0) || modes::isEqual(particleType2, modes::Particle::kTwoTrackResonance) || modes::isEqual(particleType2, modes::Particle::kCharmHadron)) && - requires(T2 p) { p.posDauId(); p.negDauId(); }) { - auto posDaughter = trackTable.rawIteratorAt(particle2.posDauId() - trackTable.offset()); - auto negDaughter = trackTable.rawIteratorAt(particle2.negDauId() - trackTable.offset()); - ROOT::Math::PtEtaPhiMVector posDau4v = ROOT::Math::PtEtaPhiMVector(posDaughter.pt(), posDaughter.eta(), posDaughter.phi(), mPdgMassPosDau2); - ROOT::Math::PtEtaPhiMVector negDau4v = ROOT::Math::PtEtaPhiMVector(negDaughter.pt(), negDaughter.eta(), negDaughter.phi(), mPdgMassNegDau2); - mMassTot2 = (mParticle1 + posDau4v + negDau4v).M2(); - mMass12 = (mParticle1 + posDau4v).M2(); - mMass13 = (mParticle1 + negDau4v).M2(); - } - } - } - template void setPair(T1 const& particle1, T2 const& particle2, T3 const& trackTable, T4 const& col) { - setPair(particle1, particle2, trackTable); + setPairKinematics(particle1, particle2, trackTable, col); mMult = col.mult(); mCent = col.cent(); } @@ -736,7 +681,7 @@ class PairHistManager template void setPair(T1 const& particle1, T2 const& particle2, T3 const& trackTable, T4 const& col1, T5 const& col2) { - setPair(particle1, particle2, trackTable); + setPairKinematics(particle1, particle2, trackTable, col1); mMult = 0.5f * (col1.mult() + col2.mult()); // if mixing with multiplicity, should be in the same mixing bin mCent = 0.5f * (col1.cent() + col2.cent()); // if mixing with centrality, should be in the same mixing bin } @@ -918,7 +863,23 @@ class PairHistManager } } - float getKstar() const { return mKstar; } + float getKinematic() const + { + switch (mKinematicVariable) { + case modes::KinematicVariable::kKstar: + return mKstar; + break; + case modes::KinematicVariable::kKt: + return mKt; + break; + case modes::KinematicVariable::kMt: + return mMt; + break; + default: + LOG(fatal) << "Invalid kinematic Variable, breaking..."; + } + return mKstar; + } private: void initAnalysis(std::map> const& Specs) @@ -1025,8 +986,13 @@ class PairHistManager mHistogramRegistry->add(analysisDir + getHistNameV2(kQout, HistTable), getHistDesc(kQout, HistTable), getHistType(kQout, HistTable), {Specs.at(kQout)}); mHistogramRegistry->add(analysisDir + getHistNameV2(kQside, HistTable), getHistDesc(kQside, HistTable), getHistType(kQside, HistTable), {Specs.at(kQside)}); mHistogramRegistry->add(analysisDir + getHistNameV2(kQlong, HistTable), getHistDesc(kQlong, HistTable), getHistType(kQlong, HistTable), {Specs.at(kQlong)}); - mHistogramRegistry->add(analysisDir + getHistNameV2(kQoutQsideQlong, HistTable), getHistDesc(kQoutQsideQlong, HistTable), getHistType(kQoutQsideQlong, HistTable), {Specs.at(kQoutQsideQlong)}); + mHistogramRegistry->add(analysisDir + getHistNameV2(kQoutVsQsideVsQlong, HistTable), getHistDesc(kQoutVsQsideVsQlong, HistTable), getHistType(kQoutVsQsideVsQlong, HistTable), {Specs.at(kQoutVsQsideVsQlong)}); + } + + if (mPlotEventShape) { + mHistogramRegistry->add(analysisDir + getHistNameV2(kQoutVsQsideVsQlongVsMtVsCentVsEventPlaneAngleVsQvector, HistTable), getHistDesc(kQoutVsQsideVsQlongVsMtVsCentVsEventPlaneAngleVsQvector, HistTable), getHistType(kQoutVsQsideVsQlongVsMtVsCentVsEventPlaneAngleVsQvector, HistTable), {Specs.at(kQoutVsQsideVsQlongVsMtVsCentVsEventPlaneAngleVsQvector)}); } + if (mPlotSH) { const int nJM = (mShLMax + 1) * (mShLMax + 1); const int nCent = static_cast(mShCentEdges.size()) - 1; // n edges -> n - 1 bins @@ -1205,6 +1171,89 @@ class PairHistManager } } + template + void setPairKinematics(T1 const& particle1, T2 const& particle2, T3 const& trackTable, T4 const& col) + { + // if one of the particles has a mass getter (like lambda), we cache the value for the filling later + // otherwise set it to the pdg mass + if constexpr (utils::HasMass) { + mRecoMass1 = particle1.mass(); + } else { + mRecoMass1 = mPdgMass1; + } + if constexpr (utils::HasMass) { + mRecoMass2 = particle2.mass(); + } else { + mRecoMass2 = mPdgMass2; + } + + // get mass for 4-vectors + double mass1 = 0.f; + double mass2 = 0.f; + if (mUsePdgMass) { + mass1 = mPdgMass1; + mass2 = mPdgMass2; + } else { + mass1 = mRecoMass1; + mass2 = mRecoMass2; + } + + // pt in track table is calculated from 1/signedPt from the original track table + // in case of He with Z=2, we have to rescale the pt with the absolute charge + mParticle1 = ROOT::Math::PtEtaPhiMVector(mAbsCharge1 * particle1.pt(), particle1.eta(), particle1.phi(), mass1); + mParticle2 = ROOT::Math::PtEtaPhiMVector(mAbsCharge2 * particle2.pt(), particle2.eta(), particle2.phi(), mass2); + + // set kT + mKt = getKt(mParticle1, mParticle2); + + // set mT + mMt = getMt(mParticle1, mParticle2); + + // set Minv + mMassInv = getMinv(mParticle1, mParticle2); + + // set kstar + mKstar = getKstar(mParticle1, mParticle2); + + if (mPlotBertschPratt) { + std::tie(mQout, mQside, mQlong) = computeBertschPrattLCMS(mParticle1, mParticle2); + } + + if (mPlotEventShape) { + if (!mPlotBertschPratt) { + std::tie(mQout, mQside, mQlong) = computeBertschPrattLCMS(mParticle1, mParticle2); + } + if constexpr (utils::HasEventShape) { + mPairPhiFromEventPlaneAngle = getPairPhiFromEventPlaneAngle(mParticle1, mParticle2, col); + mQvector = col.qvec(); + } else { + LOG(fatal) << "plotEventShape is enabled but the collision table has no event-shape columns. Breaking..."; + } + } + + if (mPlotSH) { + std::tie(mShKv, mShOut, mShSide, mShLong) = computeShKinematics(mParticle1, mParticle2); + } + + if (mPlotDeltaEtaDeltaPhi) { + mDeltaEta = particle1.eta() - particle2.eta(); + mDeltaPhi = RecoDecay::constrainAngle(particle1.phi() - particle2.phi(), -o2::constants::math::PIHalf); + } + + if (mPlotDalitz) { + if constexpr (modes::isEqual(particleType1, modes::Particle::kTrack) && (modes::isEqual(particleType2, modes::Particle::kV0) || modes::isEqual(particleType2, modes::Particle::kTwoTrackResonance) || modes::isEqual(particleType2, modes::Particle::kCharmHadron)) && + requires(T2 p) { p.posDauId(); p.negDauId(); }) { + auto posDaughter = trackTable.rawIteratorAt(particle2.posDauId() - trackTable.offset()); + auto negDaughter = trackTable.rawIteratorAt(particle2.negDauId() - trackTable.offset()); + ROOT::Math::PtEtaPhiMVector posDau4v = ROOT::Math::PtEtaPhiMVector(posDaughter.pt(), posDaughter.eta(), posDaughter.phi(), mPdgMassPosDau2); + ROOT::Math::PtEtaPhiMVector negDau4v = ROOT::Math::PtEtaPhiMVector(negDaughter.pt(), negDaughter.eta(), negDaughter.phi(), mPdgMassNegDau2); + mMassTot2 = (mParticle1 + posDau4v + negDau4v).M2(); + mMass12 = (mParticle1 + posDau4v).M2(); + mMass13 = (mParticle1 + negDau4v).M2(); + } + } + } + void fillAnalysis() { if (mPlot1d) { @@ -1305,7 +1354,10 @@ class PairHistManager mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kQout, HistTable)), mQout); mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kQside, HistTable)), mQside); mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kQlong, HistTable)), mQlong); - mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kQoutQsideQlong, HistTable)), mQout, mQside, mQlong); + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kQoutVsQsideVsQlong, HistTable)), mQout, mQside, mQlong); + } + if (mPlotEventShape) { + mHistogramRegistry->fill(HIST(prefix) + HIST(AnalysisDir) + HIST(getHistName(kQoutVsQsideVsQlongVsMtVsCentVsEventPlaneAngleVsQvector, HistTable)), mQout, mQside, mQlong, mMt, mCent, mPairPhiFromEventPlaneAngle, mQvector); } if (mPlotSH) { const float shCentValue = mShUseCent ? mCent : mMult; @@ -1591,6 +1643,14 @@ class PairHistManager static_cast(fDKOut), static_cast(fDKSide), static_cast(fDKLong)}; } + template + float getPairPhiFromEventPlaneAngle(const ROOT::Math::PtEtaPhiMVector& part1, const ROOT::Math::PtEtaPhiMVector& part2, const T1& col) + { + const ROOT::Math::PtEtaPhiMVector trackSum = part1 + part2; + float phi = RecoDecay::constrainAngle(trackSum.Phi() - col.eventPlaneAngle()); + return phi; + } + o2::framework::HistogramRegistry* mHistogramRegistry = nullptr; bool mUsePdgMass = true; double mPdgMass1 = 0.; @@ -1601,6 +1661,7 @@ class PairHistManager double mPdgMassNegDau2 = 0; modes::TransverseMassType mMtType = modes::TransverseMassType::kAveragePdgMass; + modes::KinematicVariable mKinematicVariable = modes::KinematicVariable::kKstar; int mAbsCharge1 = 1; int mAbsCharge2 = 1; @@ -1681,6 +1742,8 @@ class PairHistManager bool mPlotBertschPratt = false; + bool mPlotEventShape = false; + float mQout = 0.f; float mQside = 0.f; float mQlong = 0.f; @@ -1688,6 +1751,9 @@ class PairHistManager float mDeltaEta = 0.f; float mDeltaPhi = 0.f; + float mQvector = 0.f; + float mPairPhiFromEventPlaneAngle = 0.f; + // Spherical harmonics bool mPlotSH = false; bool mShUseCent = false; diff --git a/PWGCF/Femto/Core/pairProcessHelpers.h b/PWGCF/Femto/Core/pairProcessHelpers.h index 9606051ff57..ced0f7e7e14 100644 --- a/PWGCF/Femto/Core/pairProcessHelpers.h +++ b/PWGCF/Femto/Core/pairProcessHelpers.h @@ -55,16 +55,7 @@ void processSameEvent(T1 const& SliceParticle, ParticleHistManager.template fill(part, TrackTable); } for (auto const& [p1, p2] : o2::soa::combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(SliceParticle, SliceParticle))) { - // check if pair is clean - if (!PcManager.isCleanPair(p1, p2, TrackTable)) { - continue; - } - // check if pair is close - CprManager.setPair(p1, p2, TrackTable); - if (CprManager.isClosePair()) { - continue; - } - // Randomize pair order if enabled + // Randomize pair order if enabled, then compute the kinematic (kstar) for this pair switch (pairOrder) { case kOrder12: PairHistManager.setPair(p1, p2, TrackTable, Collision); @@ -75,8 +66,14 @@ void processSameEvent(T1 const& SliceParticle, default: PairHistManager.setPair(p1, p2, TrackTable, Collision); } - // fill deta-dphi histograms with kstar cutoff - CprManager.fill(PairHistManager.getKstar()); + // check if pair is clean + if (!PcManager.isCleanPair(p1, p2, TrackTable, PairHistManager)) { + continue; + } + // check if pair is close; fills deta-dphi/kinematic histograms internally + if (CprManager.isClosePair(p1, p2, TrackTable, PairHistManager)) { + continue; + } // if pair cuts are configured check them before filling if (PairHistManager.checkPairCuts()) { PairHistManager.template fill(); @@ -127,16 +124,7 @@ void processSameEvent(T1 const& SliceParticle, !ParticleCleaner.isClean(p2, mcParticles, mcMothers, mcPartonicMothers)) { continue; } - // check if pair is clean - if (!PcManager.isCleanPair(p1, p2, TrackTable, mcParticles, mcPartonicMothers)) { - continue; - } - // check if pair is close - CprManager.setPair(p1, p2, TrackTable); - if (CprManager.isClosePair()) { - continue; - } - // Randomize pair order if enabled + // Randomize pair order if enabled, then compute the kinematic (kstar) for this pair switch (pairOrder) { case kOrder12: PairHistManager.setPairMc(p1, p2, TrackTable, mcParticles, Collision, mcCollisions); @@ -147,8 +135,14 @@ void processSameEvent(T1 const& SliceParticle, default: PairHistManager.setPairMc(p1, p2, TrackTable, mcParticles, Collision, mcCollisions); } - // fill deta-dphi histograms with kstar cutoff - CprManager.fill(PairHistManager.getKstar()); + // check if pair is clean + if (!PcManager.isCleanPair(p1, p2, TrackTable, mcParticles, mcPartonicMothers, PairHistManager)) { + continue; + } + // check if pair is close; fills deta-dphi/kinematic histograms internally + if (CprManager.isClosePair(p1, p2, TrackTable, PairHistManager)) { + continue; + } // if pair cuts are configured check them before filling if (PairHistManager.checkPairCuts()) { PairHistManager.template fill(); @@ -188,17 +182,16 @@ void processSameEvent(T1 const& SliceParticle1, ParticleHistManager2.template fill(part, TrackTable); } for (auto const& [p1, p2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(SliceParticle1, SliceParticle2))) { + // compute the kinematic (kstar) for this pair + PairHistManager.setPair(p1, p2, TrackTable, Collision); // pair cleaning - if (!PcManager.isCleanPair(p1, p2, TrackTable)) { + if (!PcManager.isCleanPair(p1, p2, TrackTable, PairHistManager)) { continue; } - // Close pair rejection - CprManager.setPair(p1, p2, TrackTable); - if (CprManager.isClosePair()) { + // Close pair rejection; fills deta-dphi/kinematic histograms internally + if (CprManager.isClosePair(p1, p2, TrackTable, PairHistManager)) { continue; } - PairHistManager.setPair(p1, p2, TrackTable, Collision); - CprManager.fill(PairHistManager.getKstar()); if (PairHistManager.checkPairCuts()) { PairHistManager.template fill(); PairHistManager.trackParticlesPerEvent(p1, p2); @@ -260,17 +253,16 @@ void processSameEvent(T1 const& SliceParticle1, !ParticleCleaner2.isClean(p2, mcParticles, mcMothers, mcPartonicMothers)) { continue; } + // compute the kinematic (kstar) for this pair + PairHistManager.setPairMc(p1, p2, TrackTable, mcParticles, Collision, mcCollisions); // pair cleaning - if (!PcManager.isCleanPair(p1, p2, TrackTable, mcParticles, mcPartonicMothers)) { + if (!PcManager.isCleanPair(p1, p2, TrackTable, mcParticles, mcPartonicMothers, PairHistManager)) { continue; } - // Close pair rejection - CprManager.setPair(p1, p2, TrackTable); - if (CprManager.isClosePair()) { + // Close pair rejection; fills deta-dphi/kinematic histograms internally + if (CprManager.isClosePair(p1, p2, TrackTable, PairHistManager)) { continue; } - PairHistManager.setPairMc(p1, p2, TrackTable, mcParticles, Collision, mcCollisions); - CprManager.fill(PairHistManager.getKstar()); if (PairHistManager.checkPairCuts()) { PairHistManager.template fill(); PairHistManager.trackParticlesPerEvent(p1, p2); @@ -314,13 +306,7 @@ void processSameEvent(T1 const& SliceParticle, !ParticleCleaner.isClean(p2, mcMothers, mcPartonicMothers)) { continue; } - if (!PcManager.isCleanPair(p1, p2, mcPartonicMothers)) { - continue; - } - CprManager.setPair(p1, p2); - if (CprManager.isClosePair()) { - continue; - } + // Randomize pair order if enabled, then compute the kinematic (kstar) for this pair switch (pairOrder) { case kOrder12: PairHistManager.setPairMcTruth(p1, p2, Collision); @@ -331,7 +317,13 @@ void processSameEvent(T1 const& SliceParticle, default: PairHistManager.setPairMcTruth(p1, p2, Collision); } - CprManager.fill(PairHistManager.getKstar()); + if (!PcManager.isCleanPair(p1, p2, mcPartonicMothers, PairHistManager)) { + continue; + } + // Close pair rejection; fills deta-dphi/kinematic histograms internally + if (CprManager.isClosePair(p1, p2, PairHistManager)) { + continue; + } if (PairHistManager.checkPairCuts()) { PairHistManager.template fill(); PairHistManager.trackParticlesPerEvent(p1, p2); @@ -387,15 +379,15 @@ void processSameEvent(T1 const& SliceParticle1, !ParticleCleaner2.isClean(p2, mcMothers, mcPartonicMothers)) { continue; } - if (!PcManager.isCleanPair(p1, p2, mcPartonicMothers)) { + // compute the kinematic (kstar) for this pair + PairHistManager.setPairMcTruth(p1, p2, Collision); + if (!PcManager.isCleanPair(p1, p2, mcPartonicMothers, PairHistManager)) { continue; } - CprManager.setPair(p1, p2); - if (CprManager.isClosePair()) { + // Close pair rejection; fills deta-dphi/kinematic histograms internally + if (CprManager.isClosePair(p1, p2, PairHistManager)) { continue; } - PairHistManager.setPairMcTruth(p1, p2, Collision); - CprManager.fill(PairHistManager.getKstar()); if (PairHistManager.checkPairCuts()) { PairHistManager.template fill(); PairHistManager.trackParticlesPerEvent(p1, p2); @@ -472,18 +464,18 @@ void processMixedEvent(T1 const& Collisions, PairHistManager.fillMixingQaMe(collision1, collision2); for (auto const& [p1, p2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(*sliceParticle1, sliceParticle2))) { - if (!PcManager.isCleanPair(p1, p2, TrackTable)) { + // compute the kinematic (kstar) for this pair + PairHistManager.setPair(p1, p2, TrackTable, collision1, collision2); + + if (!PcManager.isCleanPair(p1, p2, TrackTable, PairHistManager)) { continue; } - CprManager.setPair(p1, p2, TrackTable); - if (CprManager.isClosePair()) { + // Close pair rejection; fills deta-dphi/kinematic histograms internally + if (CprManager.isClosePair(p1, p2, TrackTable, PairHistManager)) { continue; } - PairHistManager.setPair(p1, p2, TrackTable, collision1, collision2); - CprManager.fill(PairHistManager.getKstar()); - if (PairHistManager.checkPairCuts()) { hasValidPair = true; PairHistManager.trackParticlesPerEvent(p1, p2); @@ -588,19 +580,18 @@ void processMixedEvent(T1 const& Collisions, continue; } - if (!PcManager.isCleanPair(p1, p2, TrackTable)) { + // compute the kinematic (kstar) for this pair + PairHistManager.setPairMc(p1, p2, TrackTable, mcParticles, collision1, collision2, mcCollisions); + + if (!PcManager.isCleanPair(p1, p2, TrackTable, PairHistManager)) { continue; } - CprManager.setPair(p1, p2, TrackTable); - if (CprManager.isClosePair()) { + // Close pair rejection; fills deta-dphi/kinematic histograms internally + if (CprManager.isClosePair(p1, p2, TrackTable, PairHistManager)) { continue; } - PairHistManager.setPairMc(p1, p2, TrackTable, mcParticles, collision1, collision2, mcCollisions); - - CprManager.fill(PairHistManager.getKstar()); - if (PairHistManager.checkPairCuts()) { hasValidPair = true; PairHistManager.trackParticlesPerEvent(p1, p2); @@ -689,19 +680,18 @@ void processMixedEvent(T1 const& Collisions, continue; } - if (!PcManager.isCleanPair(p1, p2, mcPartonicMothers)) { + // compute the kinematic (kstar) for this pair + PairHistManager.setPairMcTruth(p1, p2, collision1, collision2); + + if (!PcManager.isCleanPair(p1, p2, mcPartonicMothers, PairHistManager)) { continue; } - CprManager.setPair(p1, p2); - if (CprManager.isClosePair()) { + // Close pair rejection; fills deta-dphi/kinematic histograms internally + if (CprManager.isClosePair(p1, p2, PairHistManager)) { continue; } - PairHistManager.setPairMcTruth(p1, p2, collision1, collision2); - - CprManager.fill(PairHistManager.getKstar()); - if (PairHistManager.checkPairCuts()) { hasValidPair = true; PairHistManager.trackParticlesPerEvent(p1, p2); diff --git a/PWGCF/Femto/Core/partitions.h b/PWGCF/Femto/Core/partitions.h index ed849b52048..ad0af6731b8 100644 --- a/PWGCF/Femto/Core/partitions.h +++ b/PWGCF/Femto/Core/partitions.h @@ -16,6 +16,8 @@ #ifndef PWGCF_FEMTO_CORE_PARTITIONS_H_ #define PWGCF_FEMTO_CORE_PARTITIONS_H_ +#include + // collsion selection // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define MAKE_COLLISION_FILTER(selection) \ diff --git a/PWGCF/Femto/Core/trackBuilder.h b/PWGCF/Femto/Core/trackBuilder.h index ec758ba9d2c..bec064663c4 100644 --- a/PWGCF/Femto/Core/trackBuilder.h +++ b/PWGCF/Femto/Core/trackBuilder.h @@ -134,7 +134,7 @@ struct ConfTrackSelection : public o2::framework::ConfigurableGroup { std::string prefix = Prefix; // Unique prefix based on the template argument // configuration parameters o2::framework::Configurable pdgCodeAbs{"pdgCodeAbs", 2212, "Absolute value of PDG code. Set sign of charge to -1 for antiparticle."}; - o2::framework::Configurable chargeAbs{"chargeAbs", 1, "Absolute value of charge (e.g. 1 for most tracks, 2 for He3). Set sign of charge to -1 for antiparticle"}; + o2::framework::Configurable chargeAbs{"chargeAbs", 1, "Absolute value of charge (e.g. 1 for most tracks, 2 for He3)"}; o2::framework::Configurable chargeSign{"chargeSign", 1, "Track charge sign: +1 for positive, -1 for negative, 0 for both"}; // filters for kinematics o2::framework::Configurable ptMin{"ptMin", 0.0f, "Minimum pT (GeV/c)"}; @@ -920,6 +920,41 @@ class TrackBuilderDerivedToDerived return idx; } + template + void processTracksWithMc(T1& col, T2& /*trackTable*/, T3& partitionTrack1, T4& partitionTrack2, T5& cache, + T6& newTrackTable, T7& newCollisionTable, + T8& mcBuilder, T9 const& mcCols, T10 const& mcParticles, T11 const& mcMothers, T12 const& mcPartonicMothers, auto& mcProducts) + { + if (mLimitTrack1 > 0) { + auto trackSlice1 = partitionTrack1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + for (auto const& track : trackSlice1) { + this->fillTrackWithMcLabel(track, newTrackTable, newCollisionTable, mcBuilder, mcCols, mcParticles, mcMothers, mcPartonicMothers, mcProducts); + } + } + if (mLimitTrack2 > 0) { + auto trackSlice2 = partitionTrack2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); + for (auto const& track : trackSlice2) { + this->fillTrackWithMcLabel(track, newTrackTable, newCollisionTable, mcBuilder, mcCols, mcParticles, mcMothers, mcPartonicMothers, mcProducts); + } + } + } + + /// Same as fillTrack, but writes the matching FTrackLabels row. The indexMap + /// lookup happens first, so a track selected by both partitions produces + /// exactly one track row and exactly one label row. + template + int64_t fillTrackWithMcLabel(T1 const& track, T2& trackProducts, T3& collisionProducts, + T4& mcBuilder, T5 const& mcCols, T6 const& mcParticles, T7 const& mcMothers, T8 const& mcPartonicMothers, T9& mcProducts) + { + auto index = utils::getIndex(track.globalIndex(), indexMap); + if (index) { + return index.value(); + } + const int64_t idx = this->fillTrack(track, trackProducts, collisionProducts); + mcBuilder.fillTrackWithLabel(track, mcCols, mcParticles, mcMothers, mcPartonicMothers, mcProducts); + return idx; + } + template int64_t getDaughterIndex(const T1& daughter, T2& trackProducts, T3& collisionProducts) { diff --git a/PWGCF/Femto/Core/tripletBuilder.h b/PWGCF/Femto/Core/tripletBuilder.h index 7ebda0d0802..914c9bafdc3 100644 --- a/PWGCF/Femto/Core/tripletBuilder.h +++ b/PWGCF/Femto/Core/tripletBuilder.h @@ -80,7 +80,8 @@ class TripletTrackTrackTrackBuilder typename T14, typename T15, typename T16, - typename T17> + typename T17, + typename T18> void init(o2::framework::HistogramRegistry* registry, T1 const& confCollisionBinning, T2 const& confTrackSelection1, @@ -98,21 +99,23 @@ class TripletTrackTrackTrackBuilder std::map> const& trackHistSpec2, std::map> const& trackHistSpec3, std::map> const& pairHistSpec, - std::map> const& cprHistSpec) + std::map> const& cprHistSpec, + std::map> const& tripletCleanerHistSpec) { // check if correlate the same tracks or not mTrack1Track2Track3AreSameSpecies = confMixing.particle123AreSameSpecies.value; mTrack1Track2AreSameSpecies = confMixing.particle12AreSameSpecies.value; if (mTrack1Track2Track3AreSameSpecies && mTrack1Track2AreSameSpecies) { - LOG(fatal) << "Option Track 1&2 are identical and Option Track 1&2&3 are identical is activated. Breaking..."; + LOG(fatal) << "Option Track 1&2 are identical and Option Track 1&2&3 are identical are activated. Breaking..."; } mColHistManager.template init(registry, colHistSpec, confCollisionBinning); mTripletHistManagerSe.template init(registry, pairHistSpec, confTripletBinning, confTripletCuts, confMixing); mTripletHistManagerMe.template init(registry, pairHistSpec, confTripletBinning, confTripletCuts, confMixing); - mTc.template init(confTripletCuts); + mTcSe.template init(registry, tripletCleanerHistSpec, confTripletCuts); + mTcMe.template init(registry, tripletCleanerHistSpec, confTripletCuts); if (mTrack1Track2Track3AreSameSpecies) { // Track1 & Track2 & Track3 are the same particle species @@ -196,7 +199,7 @@ class TripletTrackTrackTrackBuilder if (mMixIdenticalParticles) { tripletOrder = static_cast(mDist(mRng)); } - tripletprocesshelpers::processSameEvent(trackSlice1, trackTable, col, mTrackHistManager1, mTripletHistManagerSe, mCtrSe, mTc, tripletOrder); + tripletprocesshelpers::processSameEvent(trackSlice1, trackTable, col, mTrackHistManager1, mTripletHistManagerSe, mCtrSe, mTcSe, tripletOrder); } else if (mTrack1Track2AreSameSpecies) { auto trackSlice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); auto trackSlice3 = partition3->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); @@ -208,7 +211,7 @@ class TripletTrackTrackTrackBuilder if (mMixIdenticalParticles) { tripletOrder = static_cast(mDist(mRng)); } - tripletprocesshelpers::processSameEvent(trackSlice1, trackSlice3, trackTable, col, mTrackHistManager1, mTrackHistManager3, mTripletHistManagerSe, mCtrSe, mTc, tripletOrder); + tripletprocesshelpers::processSameEvent(trackSlice1, trackSlice3, trackTable, col, mTrackHistManager1, mTrackHistManager3, mTripletHistManagerSe, mCtrSe, mTcSe, tripletOrder); } else { auto trackSlice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); auto trackSlice2 = partition2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); @@ -218,7 +221,7 @@ class TripletTrackTrackTrackBuilder } mColHistManager.template fill(col); mCtrSe.setMagField(col.magField()); - tripletprocesshelpers::processSameEvent(trackSlice1, trackSlice2, trackSlice3, trackTable, col, mTrackHistManager1, mTrackHistManager2, mTrackHistManager3, mTripletHistManagerSe, mCtrSe, mTc); + tripletprocesshelpers::processSameEvent(trackSlice1, trackSlice2, trackSlice3, trackTable, col, mTrackHistManager1, mTrackHistManager2, mTrackHistManager3, mTripletHistManagerSe, mCtrSe, mTcSe); } } @@ -237,7 +240,7 @@ class TripletTrackTrackTrackBuilder if (mMixIdenticalParticles) { tripletOrder = static_cast(mDist(mRng)); } - tripletprocesshelpers::processSameEvent(trackSlice1, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager1, mTripletHistManagerSe, mCleaner1, mCtrSe, mTc, tripletOrder); + tripletprocesshelpers::processSameEvent(trackSlice1, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager1, mTripletHistManagerSe, mCleaner1, mCtrSe, mTcSe, tripletOrder); } else if (mTrack1Track2AreSameSpecies) { auto trackSlice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); auto trackSlice3 = partition3->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); @@ -249,7 +252,7 @@ class TripletTrackTrackTrackBuilder if (mMixIdenticalParticles) { tripletOrder = static_cast(mDist(mRng)); } - tripletprocesshelpers::processSameEvent(trackSlice1, trackSlice3, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager1, mTrackHistManager3, mTripletHistManagerSe, mCleaner1, mCleaner3, mCtrSe, mTc, tripletOrder); + tripletprocesshelpers::processSameEvent(trackSlice1, trackSlice3, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager1, mTrackHistManager3, mTripletHistManagerSe, mCleaner1, mCleaner3, mCtrSe, mTcSe, tripletOrder); } else { auto trackSlice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); auto trackSlice2 = partition2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); @@ -259,7 +262,7 @@ class TripletTrackTrackTrackBuilder } mColHistManager.template fill(col, mcCols); mCtrSe.setMagField(col.magField()); - tripletprocesshelpers::processSameEvent(trackSlice1, trackSlice2, trackSlice3, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager1, mTrackHistManager2, mTrackHistManager3, mTripletHistManagerSe, mCleaner1, mCleaner2, mCleaner3, mCtrSe, mTc); + tripletprocesshelpers::processSameEvent(trackSlice1, trackSlice2, trackSlice3, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager1, mTrackHistManager2, mTrackHistManager3, mTripletHistManagerSe, mCleaner1, mCleaner2, mCleaner3, mCtrSe, mTcSe); } } @@ -270,13 +273,13 @@ class TripletTrackTrackTrackBuilder if (mTrack1Track2Track3AreSameSpecies) { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition1, trackTable, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition1, trackTable, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxCent): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition1, trackTable, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition1, trackTable, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition1, trackTable, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition1, trackTable, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; default: LOG(fatal) << "Invalid binning policy specifed. Breaking..."; @@ -284,13 +287,13 @@ class TripletTrackTrackTrackBuilder } else if (mTrack1Track2AreSameSpecies) { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition3, trackTable, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition3, trackTable, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxCent): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition3, trackTable, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition3, trackTable, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition3, trackTable, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition3, trackTable, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; default: LOG(fatal) << "Invalid binning policy specifed. Breaking..."; @@ -298,13 +301,13 @@ class TripletTrackTrackTrackBuilder } else { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition2, partition3, trackTable, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, partition1, partition2, partition3, trackTable, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxCent): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition2, partition3, trackTable, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, partition1, partition2, partition3, trackTable, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition2, partition3, trackTable, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, partition1, partition2, partition3, trackTable, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; default: LOG(fatal) << "Invalid binning policy specifed. Breaking..."; @@ -319,13 +322,13 @@ class TripletTrackTrackTrackBuilder if (mTrack1Track2Track3AreSameSpecies) { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner1, mCleaner1, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner1, mCleaner1, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxCent): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner1, mCleaner1, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner1, mCleaner1, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner1, mCleaner1, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition1, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner1, mCleaner1, mCtrMe, mTcMe); break; default: LOG(fatal) << "Invalid binning policy specifed. Breaking..."; @@ -333,13 +336,13 @@ class TripletTrackTrackTrackBuilder } else if (mTrack1Track2AreSameSpecies) { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner1, mCleaner3, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner1, mCleaner3, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxCent): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner1, mCleaner3, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner1, mCleaner3, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner1, mCleaner3, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner1, mCleaner3, mCtrMe, mTcMe); break; default: LOG(fatal) << "Invalid binning policy specifed. Breaking..."; @@ -347,13 +350,13 @@ class TripletTrackTrackTrackBuilder } else { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner2, mCleaner3, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner2, mCleaner3, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxCent): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner2, mCleaner3, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner2, mCleaner3, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner2, mCleaner3, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner2, mCleaner3, mCtrMe, mTcMe); break; default: LOG(fatal) << "Invalid binning policy specifed. Breaking..."; @@ -374,7 +377,8 @@ class TripletTrackTrackTrackBuilder closetripletrejection::CloseTripletRejectionTrackTrackTrack mCtrSe; closetripletrejection::CloseTripletRejectionTrackTrackTrack mCtrMe; - tripletcleaner::TrackTrackTrackTripletCleaner mTc; + tripletcleaner::TrackTrackTrackTripletCleaner mTcSe; + tripletcleaner::TrackTrackTrackTripletCleaner mTcMe; triplethistmanager::MixingPolicy mMixingPolicy = triplethistmanager::MixingPolicy::kVtxMult; bool mTrack1Track2Track3AreSameSpecies = false; bool mTrack1Track2AreSameSpecies = false; @@ -424,7 +428,8 @@ class TripletTrackTrackV0Builder typename T16, typename T17, typename T18, - typename T19> + typename T19, + typename T20> void init(o2::framework::HistogramRegistry* registry, T1 const& confCollisionBinning, T2 const& confTrackSelection1, @@ -444,7 +449,8 @@ class TripletTrackTrackV0Builder std::map> const& posDauhistSpec, std::map> const& negDauhistSpec, std::map> const& tripletHistSpec, - std::map> const& ctrHistSpec) + std::map> const& ctrHistSpec, + std::map> const& tripletCleanerHistSpec) { // check if correlate the same tracks or not mTrack1Track2AreSameSpecies = confMixing.particle12AreSameSpecies.value; @@ -453,7 +459,8 @@ class TripletTrackTrackV0Builder mTripletHistManagerSe.template init(registry, tripletHistSpec, confTripletBinning, confTripletCuts, confMixing); mTripletHistManagerMe.template init(registry, tripletHistSpec, confTripletBinning, confTripletCuts, confMixing); - mTc.template init(confTripletCuts); + mTcSe.template init(registry, tripletCleanerHistSpec, confTripletCuts); + mTcMe.template init(registry, tripletCleanerHistSpec, confTripletCuts); mV0Cleaner.init(confV0Cleaner); @@ -521,7 +528,7 @@ class TripletTrackTrackV0Builder if (mMixIdenticalParticles) { tripletOrder = static_cast(mDist(mRng)); } - tripletprocesshelpers::processSameEvent(trackSlice1, v0Slice, trackTable, col, mTrackHistManager1, mV0HistManager, mTripletHistManagerSe, mCtrSe, mTc, tripletOrder); + tripletprocesshelpers::processSameEvent(trackSlice1, v0Slice, trackTable, col, mTrackHistManager1, mV0HistManager, mTripletHistManagerSe, mCtrSe, mTcSe, tripletOrder); } else { auto trackSlice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); auto trackSlice2 = partition2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); @@ -531,7 +538,7 @@ class TripletTrackTrackV0Builder } mColHistManager.template fill(col); mCtrSe.setMagField(col.magField()); - tripletprocesshelpers::processSameEvent(trackSlice1, trackSlice2, v0Slice, trackTable, col, mTrackHistManager1, mTrackHistManager2, mV0HistManager, mTripletHistManagerSe, mCtrSe, mTc); + tripletprocesshelpers::processSameEvent(trackSlice1, trackSlice2, v0Slice, trackTable, col, mTrackHistManager1, mTrackHistManager2, mV0HistManager, mTripletHistManagerSe, mCtrSe, mTcSe); } } @@ -551,7 +558,7 @@ class TripletTrackTrackV0Builder if (mMixIdenticalParticles) { tripletOrder = static_cast(mDist(mRng)); } - tripletprocesshelpers::processSameEvent(trackSlice1, v0Slice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager1, mV0HistManager, mTripletHistManagerSe, mCleaner1, mV0Cleaner, mCtrSe, mTc, tripletOrder); + tripletprocesshelpers::processSameEvent(trackSlice1, v0Slice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager1, mV0HistManager, mTripletHistManagerSe, mCleaner1, mV0Cleaner, mCtrSe, mTcSe, tripletOrder); } else { auto trackSlice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); auto trackSlice2 = partition2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); @@ -561,7 +568,7 @@ class TripletTrackTrackV0Builder } mColHistManager.template fill(col, mcCols); mCtrSe.setMagField(col.magField()); - tripletprocesshelpers::processSameEvent(trackSlice1, trackSlice2, v0Slice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager1, mTrackHistManager2, mV0HistManager, mTripletHistManagerSe, mCleaner1, mCleaner2, mV0Cleaner, mCtrSe, mTc); + tripletprocesshelpers::processSameEvent(trackSlice1, trackSlice2, v0Slice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager1, mTrackHistManager2, mV0HistManager, mTripletHistManagerSe, mCleaner1, mCleaner2, mV0Cleaner, mCtrSe, mTcSe); } } @@ -572,13 +579,13 @@ class TripletTrackTrackV0Builder if (mTrack1Track2AreSameSpecies) { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition3, trackTable, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition3, trackTable, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxCent): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition3, trackTable, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition3, trackTable, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition3, trackTable, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition3, trackTable, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; default: LOG(fatal) << "Invalid binning policy specifed. Breaking..."; @@ -586,13 +593,13 @@ class TripletTrackTrackV0Builder } else { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition2, partition3, trackTable, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, partition1, partition2, partition3, trackTable, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxCent): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition2, partition3, trackTable, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, partition1, partition2, partition3, trackTable, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition2, partition3, trackTable, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, partition1, partition2, partition3, trackTable, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; default: LOG(fatal) << "Invalid binning policy specifed. Breaking..."; @@ -607,13 +614,13 @@ class TripletTrackTrackV0Builder if (mTrack1Track2AreSameSpecies) { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner1, mV0Cleaner, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner1, mV0Cleaner, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxCent): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner1, mV0Cleaner, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner1, mV0Cleaner, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner1, mV0Cleaner, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner1, mV0Cleaner, mCtrMe, mTcMe); break; default: LOG(fatal) << "Invalid binning policy specifed. Breaking..."; @@ -621,13 +628,13 @@ class TripletTrackTrackV0Builder } else { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner2, mV0Cleaner, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner2, mV0Cleaner, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxCent): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner2, mV0Cleaner, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner2, mV0Cleaner, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner2, mV0Cleaner, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCleaner1, mCleaner2, mV0Cleaner, mCtrMe, mTcMe); break; default: LOG(fatal) << "Invalid binning policy specifed. Breaking..."; @@ -648,7 +655,8 @@ class TripletTrackTrackV0Builder closetripletrejection::CloseTripletRejectionTrackTrackV0 mCtrSe; closetripletrejection::CloseTripletRejectionTrackTrackV0 mCtrMe; - tripletcleaner::TrackTrackV0TripletCleaner mTc; + tripletcleaner::TrackTrackV0TripletCleaner mTcSe; + tripletcleaner::TrackTrackV0TripletCleaner mTcMe; triplethistmanager::MixingPolicy mMixingPolicy = triplethistmanager::MixingPolicy::kVtxMult; bool mTrack1Track2AreSameSpecies = false; int mMixingDepth = 5; @@ -707,7 +715,8 @@ class TripletTrackTrackCascadeBuilder typename T21, typename T22, typename T23, - typename T24> + typename T24, + typename T25> void init(o2::framework::HistogramRegistry* registry, T1 const& confCollisionBinning, @@ -733,7 +742,8 @@ class TripletTrackTrackCascadeBuilder std::map> const& tripletHistSpec, std::map> const& cprHistSpecBachelor, std::map> const& cprHistSpecV0Daughter, - std::map> const& ctrHistSpec) + std::map> const& ctrHistSpec, + std::map> const& tripletCleanerHistSpec) { // check if correlate the same tracks or not mTrack1Track2AreSameSpecies = confMixing.particle12AreSameSpecies.value; @@ -741,7 +751,8 @@ class TripletTrackTrackCascadeBuilder mTripletHistManagerSe.template init(registry, tripletHistSpec, confTripletBinning, confTripletCuts, confMixing); mTripletHistManagerMe.template init(registry, tripletHistSpec, confTripletBinning, confTripletCuts, confMixing); - mTc.template init(confTripletCuts); + mTcSe.template init(registry, tripletCleanerHistSpec, confTripletCuts); + mTcMe.template init(registry, tripletCleanerHistSpec, confTripletCuts); mCascadeCleaner.init(confCascadeCleaner); if (mTrack1Track2AreSameSpecies) { @@ -805,7 +816,7 @@ class TripletTrackTrackCascadeBuilder if (mMixIdenticalParticles) { tripletOrder = static_cast(mDist(mRng)); } - tripletprocesshelpers::processSameEvent(trackSlice1, cascadeSlice, trackTable, col, mTrackHistManager1, mCascadeHistManager, mTripletHistManagerSe, mCtrSe, mTc, tripletOrder); + tripletprocesshelpers::processSameEvent(trackSlice1, cascadeSlice, trackTable, col, mTrackHistManager1, mCascadeHistManager, mTripletHistManagerSe, mCtrSe, mTcSe, tripletOrder); } else { auto trackSlice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); auto trackSlice2 = partition2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); @@ -815,7 +826,7 @@ class TripletTrackTrackCascadeBuilder } mColHistManager.template fill(col); mCtrSe.setMagField(col.magField()); - tripletprocesshelpers::processSameEvent(trackSlice1, trackSlice2, cascadeSlice, trackTable, col, mTrackHistManager1, mTrackHistManager2, mCascadeHistManager, mTripletHistManagerSe, mCtrSe, mTc); + tripletprocesshelpers::processSameEvent(trackSlice1, trackSlice2, cascadeSlice, trackTable, col, mTrackHistManager1, mTrackHistManager2, mCascadeHistManager, mTripletHistManagerSe, mCtrSe, mTcSe); } } @@ -835,7 +846,7 @@ class TripletTrackTrackCascadeBuilder if (mMixIdenticalParticles) { tripletOrder = static_cast(mDist(mRng)); } - tripletprocesshelpers::processSameEvent(trackSlice1, cascadeSlice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager1, mCascadeHistManager, mTripletHistManagerSe, mTrackCleaner1, mCascadeCleaner, mCtrSe, mTc, tripletOrder); + tripletprocesshelpers::processSameEvent(trackSlice1, cascadeSlice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager1, mCascadeHistManager, mTripletHistManagerSe, mTrackCleaner1, mCascadeCleaner, mCtrSe, mTcSe, tripletOrder); } else { auto trackSlice1 = partition1->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); auto trackSlice2 = partition2->sliceByCached(o2::aod::femtobase::stored::fColId, col.globalIndex(), cache); @@ -845,7 +856,7 @@ class TripletTrackTrackCascadeBuilder } mColHistManager.template fill(col, mcCols); mCtrSe.setMagField(col.magField()); - tripletprocesshelpers::processSameEvent(trackSlice1, trackSlice2, cascadeSlice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager1, mTrackHistManager2, mCascadeHistManager, mTripletHistManagerSe, mTrackCleaner1, mTrackCleaner2, mCascadeCleaner, mCtrSe, mTc); + tripletprocesshelpers::processSameEvent(trackSlice1, trackSlice2, cascadeSlice, trackTable, mcParticles, mcMothers, mcPartonicMothers, col, mcCols, mTrackHistManager1, mTrackHistManager2, mCascadeHistManager, mTripletHistManagerSe, mTrackCleaner1, mTrackCleaner2, mCascadeCleaner, mCtrSe, mTcSe); } } @@ -856,14 +867,13 @@ class TripletTrackTrackCascadeBuilder if (mTrack1Track2AreSameSpecies) { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition3, trackTable, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); - + tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition3, trackTable, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxCent): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition3, trackTable, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition3, trackTable, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition3, trackTable, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, partition1, partition1, partition3, trackTable, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; default: LOG(fatal) << "Invalid binning policy specifed. Breaking..."; @@ -871,13 +881,13 @@ class TripletTrackTrackCascadeBuilder } else { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition2, partition3, trackTable, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, partition1, partition2, partition3, trackTable, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxCent): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition2, partition3, trackTable, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, partition1, partition2, partition3, trackTable, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - tripletprocesshelpers::processMixedEvent(cols, partition1, partition2, partition3, trackTable, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, partition1, partition2, partition3, trackTable, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mCtrMe, mTcMe); break; default: LOG(fatal) << "Invalid binning policy specifed. Breaking..."; @@ -892,13 +902,13 @@ class TripletTrackTrackCascadeBuilder if (mTrack1Track2AreSameSpecies) { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mTrackCleaner1, mTrackCleaner1, mCascadeCleaner, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mTrackCleaner1, mTrackCleaner1, mCascadeCleaner, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxCent): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mTrackCleaner1, mTrackCleaner1, mCascadeCleaner, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mTrackCleaner1, mTrackCleaner1, mCascadeCleaner, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mTrackCleaner1, mTrackCleaner1, mCascadeCleaner, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition1, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mTrackCleaner1, mTrackCleaner1, mCascadeCleaner, mCtrMe, mTcMe); break; default: LOG(fatal) << "Invalid binning policy specifed. Breaking..."; @@ -906,13 +916,13 @@ class TripletTrackTrackCascadeBuilder } else { switch (mMixingPolicy) { case static_cast(pairhistmanager::kVtxMult): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mTrackCleaner1, mTrackCleaner2, mCascadeCleaner, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMult, mMixingDepth, mTripletHistManagerMe, mTrackCleaner1, mTrackCleaner2, mCascadeCleaner, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxCent): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mTrackCleaner1, mTrackCleaner2, mCascadeCleaner, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxCent, mMixingDepth, mTripletHistManagerMe, mTrackCleaner1, mTrackCleaner2, mCascadeCleaner, mCtrMe, mTcMe); break; case static_cast(pairhistmanager::kVtxMultCent): - tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mTrackCleaner1, mTrackCleaner2, mCascadeCleaner, mCtrMe, mTc); + tripletprocesshelpers::processMixedEvent(cols, mcCols, partition1, partition2, partition3, trackTable, mcParticles, mcMothers, mcPartonicMothers, cache, binsVtxMultCent, mMixingDepth, mTripletHistManagerMe, mTrackCleaner1, mTrackCleaner2, mCascadeCleaner, mCtrMe, mTcMe); break; default: LOG(fatal) << "Invalid binning policy specifed. Breaking..."; @@ -933,7 +943,8 @@ class TripletTrackTrackCascadeBuilder closetripletrejection::CloseTripletRejectionTrackTrackCascade mCtrSe; closetripletrejection::CloseTripletRejectionTrackTrackCascade mCtrMe; - tripletcleaner::TrackTrackCascadeTripletCleaner mTc; + tripletcleaner::TrackTrackCascadeTripletCleaner mTcSe; + tripletcleaner::TrackTrackCascadeTripletCleaner mTcMe; triplethistmanager::MixingPolicy mMixingPolicy = triplethistmanager::MixingPolicy::kVtxMult; bool mTrack1Track2AreSameSpecies = false; int mMixingDepth = 5; diff --git a/PWGCF/Femto/Core/tripletCleaner.h b/PWGCF/Femto/Core/tripletCleaner.h index c40a0760bbb..1a1cb689968 100644 --- a/PWGCF/Femto/Core/tripletCleaner.h +++ b/PWGCF/Femto/Core/tripletCleaner.h @@ -17,37 +17,50 @@ #define PWGCF_FEMTO_CORE_TRIPLETCLEANER_H_ #include "PWGCF/Femto/Core/pairCleaner.h" - namespace o2::analysis::femto::tripletcleaner { -class TrackTrackTrackTripletCleaner : public paircleaner::BasePairCleaner + +constexpr char PrefixTripletCleanerTrackTrackTrackSe[] = "TrackTrackTrackCleaner/SE/"; +constexpr char PrefixTripletCleanerTrackTrackTrackMe[] = "TrackTrackTrackCleaner/ME/"; +constexpr char PrefixTripletCleanerTrackTrackV0Se[] = "TrackTrackV0Cleaner/SE/"; +constexpr char PrefixTripletCleanerTrackTrackV0Me[] = "TrackTrackV0Cleaner/ME/"; +constexpr char PrefixTripletCleanerTrackTrackCascadeSe[] = "TrackTrackCascadeCleaner/SE/"; +constexpr char PrefixTripletCleanerTrackTrackCascadeMe[] = "TrackTrackCascadeCleaner/ME/"; + +template +class TrackTrackTrackTripletCleaner : public paircleaner::BasePairCleaner { public: TrackTrackTrackTripletCleaner() = default; ~TrackTrackTrackTripletCleaner() override = default; - template - bool isCleanTriplet(T1 const& track1, T2 const& track2, T3 const& track3, T4 const& /*trackTable*/) const + template + bool isCleanTriplet(T1 const& track1, T2 const& track2, T3 const& track3, T4 const& /*trackTable*/, T5 const& tripletHistManager) const { - return this->isCleanParticlePair(track1, track2) && - this->isCleanParticlePair(track2, track3) && - this->isCleanParticlePair(track1, track3); + this->fillAll(); + bool isClean = this->isCleanParticlePair(track1, track2) && + this->isCleanParticlePair(track2, track3) && + this->isCleanParticlePair(track1, track3); + if (!isClean) { + this->fillBlocked(tripletHistManager.getKinematic()); + } + return isClean; } - template - bool isCleanTriplet(T1 const& track1, T2 const& track2, T3 const& track3, T4 const& trackTable, T5 const& mcParticles, T6 const& partonicMothers) const + template + bool isCleanTriplet(T1 const& track1, T2 const& track2, T3 const& track3, T4 const& trackTable, T5 const& mcParticles, T6 const& partonicMothers, T7 const& tripletHistManager) const { - if (!this->isCleanTriplet(track1, track2, track3, trackTable)) { + if (!this->isCleanTriplet(track1, track2, track3, trackTable, tripletHistManager)) { return false; } // pair is clean // no check if we require common or non-common ancestry - if (mMixPairsWithCommonAncestor) { + if (this->mMixPairsWithCommonAncestor) { return this->pairHasCommonAncestor(track1, track2, mcParticles, partonicMothers) && this->pairHasCommonAncestor(track2, track3, mcParticles, partonicMothers) && this->pairHasCommonAncestor(track1, track3, mcParticles, partonicMothers); } - if (mMixPairsWithNonCommonAncestor) { + if (this->mMixPairsWithNonCommonAncestor) { return this->pairHasNonCommonAncestor(track1, track2, mcParticles, partonicMothers) && this->pairHasNonCommonAncestor(track2, track3, mcParticles, partonicMothers) && this->pairHasNonCommonAncestor(track1, track3, mcParticles, partonicMothers); @@ -56,38 +69,44 @@ class TrackTrackTrackTripletCleaner : public paircleaner::BasePairCleaner } }; -class TrackTrackV0TripletCleaner : public paircleaner::BasePairCleaner +template +class TrackTrackV0TripletCleaner : public paircleaner::BasePairCleaner { public: TrackTrackV0TripletCleaner() = default; ~TrackTrackV0TripletCleaner() override = default; - template - bool isCleanTriplet(T1 const& track1, T2 const& track2, T3 const& v0, T4 const& trackTable) const + template + bool isCleanTriplet(T1 const& track1, T2 const& track2, T3 const& v0, T4 const& trackTable, T5 const& tripletHistManager) const { + this->fillAll(); auto posDaughter = trackTable.rawIteratorAt(v0.posDauId() - trackTable.offset()); auto negDaughter = trackTable.rawIteratorAt(v0.negDauId() - trackTable.offset()); - return this->isCleanParticlePair(track1, track2) && - this->isCleanParticlePair(track1, posDaughter) && - this->isCleanParticlePair(track1, negDaughter) && - this->isCleanParticlePair(track2, posDaughter) && - this->isCleanParticlePair(track2, negDaughter); + bool isClean = this->isCleanParticlePair(track1, track2) && + this->isCleanParticlePair(track1, posDaughter) && + this->isCleanParticlePair(track1, negDaughter) && + this->isCleanParticlePair(track2, posDaughter) && + this->isCleanParticlePair(track2, negDaughter); + if (!isClean) { + this->fillBlocked(tripletHistManager.getKinematic()); + } + return isClean; } - template - bool isCleanTriplet(T1 const& track1, T2 const& track2, T3 const& v0, T4 const& trackTable, T5 const& mcParticles, T6 const& partonicMothers) const + template + bool isCleanTriplet(T1 const& track1, T2 const& track2, T3 const& v0, T4 const& trackTable, T5 const& mcParticles, T6 const& partonicMothers, T7 const& tripletHistManager) const { - if (!this->isCleanTriplet(track1, track2, v0, trackTable)) { + if (!this->isCleanTriplet(track1, track2, v0, trackTable, tripletHistManager)) { return false; } // pair is clean // no check if we require common or non-common ancestry - if (mMixPairsWithCommonAncestor) { + if (this->mMixPairsWithCommonAncestor) { return this->pairHasCommonAncestor(track1, track2, mcParticles, partonicMothers) && this->pairHasCommonAncestor(track1, v0, mcParticles, partonicMothers) && this->pairHasCommonAncestor(track2, v0, mcParticles, partonicMothers); } - if (mMixPairsWithNonCommonAncestor) { + if (this->mMixPairsWithNonCommonAncestor) { return this->pairHasNonCommonAncestor(track1, track2, mcParticles, partonicMothers) && this->pairHasNonCommonAncestor(track1, v0, mcParticles, partonicMothers) && this->pairHasNonCommonAncestor(track2, v0, mcParticles, partonicMothers); @@ -96,41 +115,47 @@ class TrackTrackV0TripletCleaner : public paircleaner::BasePairCleaner } }; -class TrackTrackCascadeTripletCleaner : public paircleaner::BasePairCleaner +template +class TrackTrackCascadeTripletCleaner : public paircleaner::BasePairCleaner { public: TrackTrackCascadeTripletCleaner() = default; ~TrackTrackCascadeTripletCleaner() override = default; - template - bool isCleanTriplet(T1 const& track1, T2 const& track2, T3 const& cascade, T4 const& trackTable) const + template + bool isCleanTriplet(T1 const& track1, T2 const& track2, T3 const& cascade, T4 const& trackTable, T5 const& tripletHistManager) const { + this->fillAll(); auto bachelor = trackTable.rawIteratorAt(cascade.bachelorId() - trackTable.offset()); auto posDaughter = trackTable.rawIteratorAt(cascade.posDauId() - trackTable.offset()); auto negDaughter = trackTable.rawIteratorAt(cascade.negDauId() - trackTable.offset()); - return this->isCleanParticlePair(track1, track2) && - this->isCleanParticlePair(track1, posDaughter) && - this->isCleanParticlePair(track1, negDaughter) && - this->isCleanParticlePair(track1, bachelor) && - this->isCleanParticlePair(track2, posDaughter) && - this->isCleanParticlePair(track2, negDaughter) && - this->isCleanParticlePair(track2, bachelor); + bool isClean = this->isCleanParticlePair(track1, track2) && + this->isCleanParticlePair(track1, posDaughter) && + this->isCleanParticlePair(track1, negDaughter) && + this->isCleanParticlePair(track1, bachelor) && + this->isCleanParticlePair(track2, posDaughter) && + this->isCleanParticlePair(track2, negDaughter) && + this->isCleanParticlePair(track2, bachelor); + if (!isClean) { + this->fillBlocked(tripletHistManager.getKinematic()); + } + return isClean; } - template - bool isCleanTriplet(T1 const& track1, T2 const& track2, T3 const& cascade, T4 const& trackTable, T5 const& mcParticles, T6 const& partonicMothers) const + template + bool isCleanTriplet(T1 const& track1, T2 const& track2, T3 const& cascade, T4 const& trackTable, T5 const& mcParticles, T6 const& partonicMothers, T7 const& tripletHistManager) const { - if (!this->isCleanTriplet(track1, track2, cascade, trackTable)) { + if (!this->isCleanTriplet(track1, track2, cascade, trackTable, tripletHistManager)) { return false; } // pair is clean // no check if we require common or non-common ancestry - if (mMixPairsWithCommonAncestor) { + if (this->mMixPairsWithCommonAncestor) { return this->pairHasCommonAncestor(track1, track2, mcParticles, partonicMothers) && this->pairHasCommonAncestor(track1, cascade, mcParticles, partonicMothers) && this->pairHasCommonAncestor(track2, cascade, mcParticles, partonicMothers); } - if (mMixPairsWithNonCommonAncestor) { + if (this->mMixPairsWithNonCommonAncestor) { return this->pairHasNonCommonAncestor(track1, track2, mcParticles, partonicMothers) && this->pairHasNonCommonAncestor(track1, cascade, mcParticles, partonicMothers) && this->pairHasNonCommonAncestor(track2, cascade, mcParticles, partonicMothers); @@ -138,7 +163,6 @@ class TrackTrackCascadeTripletCleaner : public paircleaner::BasePairCleaner return true; } }; - } // namespace o2::analysis::femto::tripletcleaner #endif // PWGCF_FEMTO_CORE_TRIPLETCLEANER_H_ diff --git a/PWGCF/Femto/Core/tripletHistManager.h b/PWGCF/Femto/Core/tripletHistManager.h index 601f6bf9fc4..ea15869bdd1 100644 --- a/PWGCF/Femto/Core/tripletHistManager.h +++ b/PWGCF/Femto/Core/tripletHistManager.h @@ -44,7 +44,7 @@ namespace o2::analysis::femto::triplethistmanager enum TripletHist { // standard 1D kQ3, - kMt, // averate mt of all pairs in the triplet + kMt, // average mt of all pairs in the triplet // kstar betweeen single particles kKstar12, kKstar13, @@ -130,6 +130,7 @@ struct ConfTripletBinning : o2::framework::ConfigurableGroup { o2::framework::ConfigurableAxis mass2{"mass2", {{100, 0, 2}}, "Mass binning for particle 2 (if particle has mass getter, otherwise PDG mass)"}; o2::framework::ConfigurableAxis mass3{"mass3", {{100, 0, 2}}, "Mass binning for particle 3 (if particle has mass getter, otherwise PDG mass)"}; o2::framework::Configurable transverseMassType{"transverseMassType", static_cast(modes::TransverseMassType::kAveragePdgMass), "Type of transverse mass (0-> Average Pdg Mass, 1-> Reduced Pdg Mass, 2-> Mt from combined 4 vector)"}; + o2::framework::Configurable kinematicVariable{"kinematicVariable", static_cast(modes::KinematicVariable::kQ3), "Type of kinematic variable (2->mT, 3->Q3) for PC and CPR plots"}; }; struct ConfTripletCuts : o2::framework::ConfigurableGroup { @@ -268,6 +269,7 @@ class TripletHistManager // transverse mass type mMtType = static_cast(ConfTripletBinning.transverseMassType.value); + mKinematicVariable = static_cast(ConfTripletBinning.kinematicVariable.value); // values for cuts mQ3Min = ConfTripletCuts.q3Min.value; @@ -437,7 +439,20 @@ class TripletHistManager } } - float getQ3() const { return mQ3; } + float getKinematic() const + { + switch (mKinematicVariable) { + case modes::KinematicVariable::kMt: + return mMt; + break; + case modes::KinematicVariable::kQ3: + return mQ3; + break; + default: + LOG(fatal) << "Invalid kinematic Variable, breaking..."; + } + return mQ3; + } template void trackParticlesPerEvent(T1 const& particle1, T2 const& particle2, T3 const& particle3) @@ -513,7 +528,7 @@ class TripletHistManager auto q23 = getqij(p2, p3); auto q31 = getqij(p3, p1); double q = q12.M2() + q23.M2() + q31.M2(); - return static_cast(std::sqrt(-q)); + return static_cast(std::sqrt(std::max(0.0, -q))); } float getKstar(ROOT::Math::PtEtaPhiMVector const& part1, ROOT::Math::PtEtaPhiMVector const& part2) @@ -695,6 +710,7 @@ class TripletHistManager double mPdgMass3 = 0.; modes::TransverseMassType mMtType = modes::TransverseMassType::kAveragePdgMass; + modes::KinematicVariable mKinematicVariable = modes::KinematicVariable::kQ3; int mAbsCharge1 = 1; int mAbsCharge2 = 1; diff --git a/PWGCF/Femto/Core/tripletProcessHelpers.h b/PWGCF/Femto/Core/tripletProcessHelpers.h index 932f91b37c4..c277fb80e57 100644 --- a/PWGCF/Femto/Core/tripletProcessHelpers.h +++ b/PWGCF/Femto/Core/tripletProcessHelpers.h @@ -60,18 +60,7 @@ void processSameEvent(T1 const& SliceParticle, for (auto const& [p1, p2, p3] : o2::soa::combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(SliceParticle, SliceParticle, SliceParticle))) { - // check if triplet is clean - if (!TcManager.isCleanTriplet(p1, p2, p3, TrackTable)) { - continue; - } - - // check if triplet is close - CtrManager.setTriplet(p1, p2, p3, TrackTable); - if (CtrManager.isCloseTriplet()) { - continue; - } - - // Randomize pair order if enabled + // Randomize triplet order if enabled, then compute the kinematic (Q3) for this triplet switch (tripletOrder) { case kOrder123: TripletHistManager.setTriplet(p1, p2, p3, Collision); @@ -90,8 +79,15 @@ void processSameEvent(T1 const& SliceParticle, break; } - // fill deta-dphi histograms with q3 cutoff - CtrManager.fill(TripletHistManager.getQ3()); + // check if triplet is clean + if (!TcManager.isCleanTriplet(p1, p2, p3, TrackTable, TripletHistManager)) { + continue; + } + + // check if triplet is close; fills deta-dphi/kinematic histograms internally + if (CtrManager.isCloseTriplet(p1, p2, p3, TrackTable, TripletHistManager)) { + continue; + } // if triplet cuts are configured check them before filling if (TripletHistManager.checkTripletCuts()) { @@ -130,18 +126,7 @@ void processSameEvent(T1 const& SliceParticle1, // 1&2 have same species for (auto const& p3 : SliceParticle3) { for (auto const& [p1, p2] : o2::soa::combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(SliceParticle1, SliceParticle1))) { - // check if triplet is clean - if (!TcManager.isCleanTriplet(p1, p2, p3, TrackTable)) { - continue; - } - - // check if triplet is close - CtrManager.setTriplet(p1, p2, p3, TrackTable); - if (CtrManager.isCloseTriplet()) { - continue; - } - - // Randomize triplet order if enabled + // Randomize triplet order if enabled, then compute the kinematic (Q3) for this triplet // only kOrder123 and kOrder213 are meaningful here since particle 1 & 2 are the same species switch (tripletOrder) { case kOrder213: @@ -153,8 +138,15 @@ void processSameEvent(T1 const& SliceParticle1, // 1&2 have same species break; } - // fill deta-dphi histograms with q3 cutoff - CtrManager.fill(TripletHistManager.getQ3()); + // check if triplet is clean + if (!TcManager.isCleanTriplet(p1, p2, p3, TrackTable, TripletHistManager)) { + continue; + } + + // check if triplet is close; fills deta-dphi/kinematic histograms internally + if (CtrManager.isCloseTriplet(p1, p2, p3, TrackTable, TripletHistManager)) { + continue; + } // if triplet cuts are configured check them before filling if (TripletHistManager.checkTripletCuts()) { @@ -206,22 +198,19 @@ void processSameEvent(T1 const& SliceParticle1, for (auto const& [p1, p2, p3] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(SliceParticle1, SliceParticle2, SliceParticle3))) { + // compute the kinematic (Q3) for this triplet + TripletHistManager.setTriplet(p1, p2, p3, Collision); + // check if triplet is clean - if (!TcManager.isCleanTriplet(p1, p2, p3, TrackTable)) { + if (!TcManager.isCleanTriplet(p1, p2, p3, TrackTable, TripletHistManager)) { continue; } - // check if triplet is close - CtrManager.setTriplet(p1, p2, p3, TrackTable); - if (CtrManager.isCloseTriplet()) { + // check if triplet is close; fills deta-dphi/kinematic histograms internally + if (CtrManager.isCloseTriplet(p1, p2, p3, TrackTable, TripletHistManager)) { continue; } - TripletHistManager.setTriplet(p1, p2, p3, Collision); - - // fill deta-dphi histograms with q3 cutoff - CtrManager.fill(TripletHistManager.getQ3()); - // if triplet cuts are configured check them before filling if (TripletHistManager.checkTripletCuts()) { TripletHistManager.template fill(); @@ -276,16 +265,8 @@ void processSameEvent(T1 const& SliceParticle, !Cleaner.isClean(p3, mcParticles, mcMothers, mcPartonicMothers)) { continue; } - // check if triplet is clean - if (!TcManager.isCleanTriplet(p1, p2, p3, TrackTable, mcParticles, mcPartonicMothers)) { - continue; - } - // check if triplet is close - CtrManager.setTriplet(p1, p2, p3, TrackTable); - if (CtrManager.isCloseTriplet()) { - continue; - } - // Randomize triplet order if enabled + + // Randomize triplet order if enabled, then compute the kinematic (Q3) for this triplet switch (tripletOrder) { case kOrder123: TripletHistManager.setTripletMc(p1, p2, p3, mcParticles, Collision, mcCollisions); @@ -303,8 +284,17 @@ void processSameEvent(T1 const& SliceParticle, TripletHistManager.setTripletMc(p1, p2, p3, mcParticles, Collision, mcCollisions); break; } - // fill deta-dphi histograms with q3 cutoff - CtrManager.fill(TripletHistManager.getQ3()); + + // check if triplet is clean + if (!TcManager.isCleanTriplet(p1, p2, p3, TrackTable, mcParticles, mcPartonicMothers, TripletHistManager)) { + continue; + } + + // check if triplet is close; fills deta-dphi/kinematic histograms internally + if (CtrManager.isCloseTriplet(p1, p2, p3, TrackTable, TripletHistManager)) { + continue; + } + // if triplet cuts are configured check them before filling if (TripletHistManager.checkTripletCuts()) { TripletHistManager.template fill(); @@ -359,16 +349,8 @@ void processSameEvent(T1 const& SliceParticle1, !Cleaner3.isClean(p3, mcParticles, mcMothers, mcPartonicMothers)) { continue; } - // check if triplet is clean - if (!TcManager.isCleanTriplet(p1, p2, p3, TrackTable, mcParticles, mcPartonicMothers)) { - continue; - } - // check if triplet is close - CtrManager.setTriplet(p1, p2, p3, TrackTable); - if (CtrManager.isCloseTriplet()) { - continue; - } - // Randomize triplet order if enabled + + // Randomize triplet order if enabled, then compute the kinematic (Q3) for this triplet // only kOrder123 and kOrder213 are meaningful here since particle 1 & 2 are the same species switch (tripletOrder) { case kOrder213: @@ -379,8 +361,17 @@ void processSameEvent(T1 const& SliceParticle1, TripletHistManager.setTripletMc(p1, p2, p3, mcParticles, Collision, mcCollisions); break; } - // fill deta-dphi histograms with q3 cutoff - CtrManager.fill(TripletHistManager.getQ3()); + + // check if triplet is clean + if (!TcManager.isCleanTriplet(p1, p2, p3, TrackTable, mcParticles, mcPartonicMothers, TripletHistManager)) { + continue; + } + + // check if triplet is close; fills deta-dphi/kinematic histograms internally + if (CtrManager.isCloseTriplet(p1, p2, p3, TrackTable, TripletHistManager)) { + continue; + } + // if triplet cuts are configured check them before filling if (TripletHistManager.checkTripletCuts()) { TripletHistManager.template fill(); @@ -460,18 +451,20 @@ void processSameEvent(T1 const& SliceParticle1, !Cleaner3.isClean(p3, mcParticles, mcMothers, mcPartonicMothers)) { continue; } + + // compute the kinematic (Q3) for this triplet + TripletHistManager.setTripletMc(p1, p2, p3, mcParticles, Collision, mcCollisions); + // check if triplet is clean - if (!TcManager.isCleanTriplet(p1, p2, p3, TrackTable, mcParticles, mcPartonicMothers)) { + if (!TcManager.isCleanTriplet(p1, p2, p3, TrackTable, mcParticles, mcPartonicMothers, TripletHistManager)) { continue; } - // check if triplet is close - CtrManager.setTriplet(p1, p2, p3, TrackTable); - if (CtrManager.isCloseTriplet()) { + + // check if triplet is close; fills deta-dphi/kinematic histograms internally + if (CtrManager.isCloseTriplet(p1, p2, p3, TrackTable, TripletHistManager)) { continue; } - TripletHistManager.setTripletMc(p1, p2, p3, mcParticles, Collision, mcCollisions); - // fill deta-dphi histograms with q3 cutoff - CtrManager.fill(TripletHistManager.getQ3()); + // if triplet cuts are configured check them before filling if (TripletHistManager.checkTripletCuts()) { TripletHistManager.template fill(); @@ -562,19 +555,20 @@ void processMixedEvent(T1 const& Collisions, TripletHistManager.fillMixingQaMe(collision1, collision2, collision3); for (auto const& [p1, p2, p3] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(*sliceParticle1, *sliceParticle2, sliceParticle3))) { - // pair cleaning - if (!TcManager.isCleanTriplet(p1, p2, p3, TrackTable)) { + + // compute the kinematic (Q3) for this triplet + TripletHistManager.setTriplet(p1, p2, p3, collision1, collision2, collision3); + + // triplet cleaning + if (!TcManager.isCleanTriplet(p1, p2, p3, TrackTable, TripletHistManager)) { continue; } - // Close pair rejection - CtrManager.setTriplet(p1, p2, p3, TrackTable); - if (CtrManager.isCloseTriplet()) { + + // Close triplet rejection; fills deta-dphi/kinematic histograms internally + if (CtrManager.isCloseTriplet(p1, p2, p3, TrackTable, TripletHistManager)) { continue; } - TripletHistManager.setTriplet(p1, p2, p3, collision1, collision2, collision3); - CtrManager.fill(TripletHistManager.getQ3()); - if (TripletHistManager.checkTripletCuts()) { hasValidTriplet = true; TripletHistManager.trackParticlesPerEvent(p1, p2, p3); @@ -690,25 +684,27 @@ void processMixedEvent(T1 const& Collisions, TripletHistManager.fillMixingQaMe(collision1, collision2, collision3); for (auto const& [p1, p2, p3] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(*sliceParticle1, *sliceParticle2, sliceParticle3))) { + // particle cleaning if (!Cleaner1.isClean(p1, mcParticles, mcMothers, mcPartonicMothers) || !Cleaner2.isClean(p2, mcParticles, mcMothers, mcPartonicMothers) || !Cleaner3.isClean(p3, mcParticles, mcMothers, mcPartonicMothers)) { continue; } - // pair cleaning - if (!TcManager.isCleanTriplet(p1, p2, p3, TrackTable, mcParticles, mcPartonicMothers)) { + + // compute the kinematic (Q3) for this triplet + TripletHistManager.setTripletMc(p1, p2, p3, mcParticles, collision1, collision2, collision3, mcCollisions); + + // triplet cleaning + if (!TcManager.isCleanTriplet(p1, p2, p3, TrackTable, mcParticles, mcPartonicMothers, TripletHistManager)) { continue; } - // Close pair rejection - CtrManager.setTriplet(p1, p2, p3, TrackTable); - if (CtrManager.isCloseTriplet()) { + + // Close triplet rejection; fills deta-dphi/kinematic histograms internally + if (CtrManager.isCloseTriplet(p1, p2, p3, TrackTable, TripletHistManager)) { continue; } - TripletHistManager.setTripletMc(p1, p2, p3, mcParticles, collision1, collision2, collision3, mcCollisions); - CtrManager.fill(TripletHistManager.getQ3()); - if (TripletHistManager.checkTripletCuts()) { hasValidTriplet = true; TripletHistManager.trackParticlesPerEvent(p1, p2, p3); diff --git a/PWGCF/Femto/DataModel/FemtoTables.h b/PWGCF/Femto/DataModel/FemtoTables.h index 3e2935ea551..9ac62087b1d 100644 --- a/PWGCF/Femto/DataModel/FemtoTables.h +++ b/PWGCF/Femto/DataModel/FemtoTables.h @@ -1295,11 +1295,13 @@ namespace femtomccollisions DECLARE_SOA_TABLE_STAGED_VERSIONED(FMcCols_001, "FMCCOL", 1, //! femto mc collisions o2::soa::Index<>, - femtocollisions::PosZ, //! Multiplicity of the event as given by the generator in |eta|<0.8 + femtocollisions::PosZ, femtocollisions::Mult, femtocollisions::Cent); using FMcCols = FMcCols_001; using FMcCol = FMcCols_001::iterator; +using StoredFMcCols = StoredFMcCols_001; +using StoredFMcCol = StoredFMcCols_001::iterator; namespace femtomcparticle { @@ -1326,6 +1328,8 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FMcParticles_001, "FMCPARTICLE", 1, //! femto femtobase::dynamic::Theta); using FMcParticles = FMcParticles_001; using FMcParticle = FMcParticles::iterator; +using StoredFMcParticles = StoredFMcParticles_001; +using StoredFMcParticle = StoredFMcParticles::iterator; DECLARE_SOA_TABLE_STAGED_VERSIONED(FMcMothers_001, "FMCMOTHER", 1, //! first direct mother of the monte carlo particle o2::soa::Index<>, // no collision index needed since the mother is retrieved from the daughter mc particle @@ -1344,12 +1348,16 @@ DECLARE_SOA_TABLE_STAGED_VERSIONED(FMcMothers_001, "FMCMOTHER", 1, //! first dir using FMcMothers = FMcMothers_001; using FMcMother = FMcMothers::iterator; +using StoredFMcMothers = StoredFMcMothers_001; +using StoredFMcMother = StoredFMcMothers::iterator; DECLARE_SOA_TABLE_STAGED_VERSIONED(FMcPartMoths_001, "FMCPARTMOTH", 1, //! first partonic mother of the monte carlo particle after hadronization o2::soa::Index<>, femtomcparticle::PdgCode); using FMcPartMoths = FMcPartMoths_001; using FMcPartMoth = FMcPartMoths::iterator; +using StoredFMcPartMoths = StoredFMcPartMoths_001; +using StoredFMcPartMoth = StoredFMcPartMoths::iterator; namespace femtolabels { @@ -1360,30 +1368,87 @@ DECLARE_SOA_INDEX_COLUMN(FMcMother, fMcMother); //! DECLARE_SOA_INDEX_COLUMN(FMcPartMoth, fMcPartMoth); //! } // namespace femtolabels -DECLARE_SOA_TABLE(FColLabels, "AOD", "FCOLMCLABEL", femtolabels::FMcColId); - -DECLARE_SOA_TABLE(FTrackLabels, "AOD", "FTRACKLABEL", femtolabels::FMcParticleId); - -DECLARE_SOA_TABLE(FLambdaLabels, "AOD", "FLAMBDALABEL", femtolabels::FMcParticleId); - -DECLARE_SOA_TABLE(FK0shortLabels, "AOD", "FK0SHORTLABEL", femtolabels::FMcParticleId); - -DECLARE_SOA_TABLE(FD0Labels, "AOD", "FD0LABEL", femtolabels::FMcParticleId); - -DECLARE_SOA_TABLE(FLcLabels, "AOD", "FLCLABEL", femtolabels::FMcParticleId); - -DECLARE_SOA_TABLE(FSigmaLabels, "AOD", "FSIGMALABEL", femtolabels::FMcParticleId); - -DECLARE_SOA_TABLE(FSigmaPlusLabels, "AOD", "FSIGMAPLUSLABEL", femtolabels::FMcParticleId); - -DECLARE_SOA_TABLE(FXiLabels, "AOD", "FXILABEL", femtolabels::FMcParticleId); - -DECLARE_SOA_TABLE(FOmegaLabels, "AOD", "FOMEGALABEL", femtolabels::FMcParticleId); +// Labels are staged like the tables they point into: the derived-to-derived +// producer writes the Stored* variant, so MC information survives a second +// derived-data pass. +DECLARE_SOA_TABLE_STAGED_VERSIONED(FColLabels_001, "FCOLMCLABEL", 1, //! label from femto collision to femto mc collision + femtolabels::FMcColId); +using FColLabels = FColLabels_001; +using FColLabel = FColLabels::iterator; +using StoredFColLabels = StoredFColLabels_001; +using StoredFColLabel = StoredFColLabels::iterator; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FTrackLabels_001, "FTRACKLABEL", 1, //! label from femto track to femto mc particle + femtolabels::FMcParticleId); +using FTrackLabels = FTrackLabels_001; +using FTrackLabel = FTrackLabels::iterator; +using StoredFTrackLabels = StoredFTrackLabels_001; +using StoredFTrackLabel = StoredFTrackLabels::iterator; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLambdaLabels_001, "FLAMBDALABEL", 1, //! label from femto lambda to femto mc particle + femtolabels::FMcParticleId); +using FLambdaLabels = FLambdaLabels_001; +using FLambdaLabel = FLambdaLabels::iterator; +using StoredFLambdaLabels = StoredFLambdaLabels_001; +using StoredFLambdaLabel = StoredFLambdaLabels::iterator; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FK0shortLabels_001, "FK0SHORTLABEL", 1, //! label from femto k0short to femto mc particle + femtolabels::FMcParticleId); +using FK0shortLabels = FK0shortLabels_001; +using FK0shortLabel = FK0shortLabels::iterator; +using StoredFK0shortLabels = StoredFK0shortLabels_001; +using StoredFK0shortLabel = StoredFK0shortLabels::iterator; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FD0Labels_001, "FD0LABEL", 1, //! label from femto d0 to femto mc particle + femtolabels::FMcParticleId); +using FD0Labels = FD0Labels_001; +using FD0Label = FD0Labels::iterator; +using StoredFD0Labels = StoredFD0Labels_001; +using StoredFD0Label = StoredFD0Labels::iterator; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FLcLabels_001, "FLCLABEL", 1, //! label from femto lc to femto mc particle + femtolabels::FMcParticleId); +using FLcLabels = FLcLabels_001; +using FLcLabel = FLcLabels::iterator; +using StoredFLcLabels = StoredFLcLabels_001; +using StoredFLcLabel = StoredFLcLabels::iterator; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmaLabels_001, "FSIGMALABEL", 1, //! label from femto sigma to femto mc particle + femtolabels::FMcParticleId); +using FSigmaLabels = FSigmaLabels_001; +using FSigmaLabel = FSigmaLabels::iterator; +using StoredFSigmaLabels = StoredFSigmaLabels_001; +using StoredFSigmaLabel = StoredFSigmaLabels::iterator; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FSigmaPlusLabels_001, "FSIGMAPLUSLABEL", 1, //! label from femto sigma plus to femto mc particle + femtolabels::FMcParticleId); +using FSigmaPlusLabels = FSigmaPlusLabels_001; +using FSigmaPlusLabel = FSigmaPlusLabels::iterator; +using StoredFSigmaPlusLabels = StoredFSigmaPlusLabels_001; +using StoredFSigmaPlusLabel = StoredFSigmaPlusLabels::iterator; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FXiLabels_001, "FXILABEL", 1, //! label from femto xi to femto mc particle + femtolabels::FMcParticleId); +using FXiLabels = FXiLabels_001; +using FXiLabel = FXiLabels::iterator; +using StoredFXiLabels = StoredFXiLabels_001; +using StoredFXiLabel = StoredFXiLabels::iterator; + +DECLARE_SOA_TABLE_STAGED_VERSIONED(FOmegaLabels_001, "FOMEGALABEL", 1, //! label from femto omega to femto mc particle + femtolabels::FMcParticleId); +using FOmegaLabels = FOmegaLabels_001; +using FOmegaLabel = FOmegaLabels::iterator; +using StoredFOmegaLabels = StoredFOmegaLabels_001; +using StoredFOmegaLabel = StoredFOmegaLabels::iterator; // for mc only processing, we also need Labels pointing from mc particles to mothers and partonic mothers -DECLARE_SOA_TABLE(FMcMotherLabels, "AOD", "FMCMOTHERLABEL", - femtolabels::FMcMotherId, - femtolabels::FMcPartMothId); +DECLARE_SOA_TABLE_STAGED_VERSIONED(FMcMotherLabels_001, "FMCMOTHERLABEL", 1, //! labels from femto mc particle to its mother and partonic mother + femtolabels::FMcMotherId, + femtolabels::FMcPartMothId); +using FMcMotherLabels = FMcMotherLabels_001; +using FMcMotherLabel = FMcMotherLabels::iterator; +using StoredFMcMotherLabels = StoredFMcMotherLabels_001; +using StoredFMcMotherLabel = StoredFMcMotherLabels::iterator; } // namespace o2::aod #endif // PWGCF_FEMTO_DATAMODEL_FEMTOTABLES_H_ diff --git a/PWGCF/Femto/FemtoNuclei/DataModel/HadronNucleiTables.h b/PWGCF/Femto/FemtoNuclei/DataModel/HadronNucleiTables.h index babbf2105ae..161be5544ab 100644 --- a/PWGCF/Femto/FemtoNuclei/DataModel/HadronNucleiTables.h +++ b/PWGCF/Femto/FemtoNuclei/DataModel/HadronNucleiTables.h @@ -71,8 +71,8 @@ DECLARE_SOA_COLUMN(MassTOFNu, massTOFNu, float); DECLARE_SOA_COLUMN(MassTOFHad, massTOFHad, float); DECLARE_SOA_COLUMN(PidTrkNu, pidTrkNu, uint32_t); DECLARE_SOA_COLUMN(PidTrkHad, pidTrkHad, uint32_t); -DECLARE_SOA_COLUMN(TrackIDHad, trackIDHad, int); -DECLARE_SOA_COLUMN(TrackIDNu, trackIDNu, int); +DECLARE_SOA_COLUMN(TrackIDHad, trackIDHad, int64_t); +DECLARE_SOA_COLUMN(TrackIDNu, trackIDNu, int64_t); DECLARE_SOA_COLUMN(ItsClusterSizeNu, itsClusterSizeNu, uint32_t); DECLARE_SOA_COLUMN(ItsClusterSizeHad, itsClusterSizeHad, uint32_t); @@ -82,6 +82,23 @@ DECLARE_SOA_COLUMN(SharedClustersHad, sharedClustersHad, uint8_t); DECLARE_SOA_COLUMN(DeltaEta, deltaEta, float); DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); +DECLARE_SOA_COLUMN(RunNumber, runNumber, int32_t); +DECLARE_SOA_COLUMN(MagneticField, magneticField, float); +DECLARE_SOA_COLUMN(CollisionIdNu, collisionIdNu, int64_t); +DECLARE_SOA_COLUMN(CollisionIdHad, collisionIdHad, int64_t); +DECLARE_SOA_COLUMN(NClsFindableTPCNu, nClsFindableTPCNu, uint8_t); +DECLARE_SOA_COLUMN(NClsFindableTPCHad, nClsFindableTPCHad, uint8_t); +DECLARE_SOA_COLUMN(FractionSharedTPCNu, fractionSharedTPCNu, float); +DECLARE_SOA_COLUMN(FractionSharedTPCHad, fractionSharedTPCHad, float); +DECLARE_SOA_COLUMN(NClsITSNu, nClsITSNu, uint8_t); +DECLARE_SOA_COLUMN(NClsITSHad, nClsITSHad, uint8_t); +DECLARE_SOA_COLUMN(NClsITSInnerBarrelNu, nClsITSInnerBarrelNu, uint8_t); +DECLARE_SOA_COLUMN(NClsITSInnerBarrelHad, nClsITSInnerBarrelHad, uint8_t); +DECLARE_SOA_COLUMN(Chi2ITSNu, chi2ITSNu, float); +DECLARE_SOA_COLUMN(Chi2ITSHad, chi2ITSHad, float); +DECLARE_SOA_COLUMN(NSigmaTPCNuDe, nSigmaTPCNuDe, float); +DECLARE_SOA_COLUMN(NSigmaTPCNuPr, nSigmaTPCNuPr, float); +DECLARE_SOA_COLUMN(NSigmaTPCNuPi, nSigmaTPCNuPi, float); // Reconstructed-MC pair information. The signed generated pT follows the // convention used by PtNu/PtHad: particles are positive and antiparticles @@ -154,7 +171,26 @@ DECLARE_SOA_TABLE(HadronNucleiTable, "AOD", "HADNUCLEITABLE", hadron_nuclei_tables::NSigmaTOFNu, hadron_nuclei_tables::NSigmaITSNu, hadron_nuclei_tables::NSigmaTOFHad, - hadron_nuclei_tables::NSigmaITSHad) + hadron_nuclei_tables::NSigmaITSHad, + hadron_nuclei_tables::RunNumber, + hadron_nuclei_tables::MagneticField, + hadron_nuclei_tables::TrackIDNu, + hadron_nuclei_tables::TrackIDHad, + hadron_nuclei_tables::CollisionIdNu, + hadron_nuclei_tables::CollisionIdHad, + hadron_nuclei_tables::NClsFindableTPCNu, + hadron_nuclei_tables::NClsFindableTPCHad, + hadron_nuclei_tables::FractionSharedTPCNu, + hadron_nuclei_tables::FractionSharedTPCHad, + hadron_nuclei_tables::NClsITSNu, + hadron_nuclei_tables::NClsITSHad, + hadron_nuclei_tables::NClsITSInnerBarrelNu, + hadron_nuclei_tables::NClsITSInnerBarrelHad, + hadron_nuclei_tables::Chi2ITSNu, + hadron_nuclei_tables::Chi2ITSHad, + hadron_nuclei_tables::NSigmaTPCNuDe, + hadron_nuclei_tables::NSigmaTPCNuPr, + hadron_nuclei_tables::NSigmaTPCNuPi) DECLARE_SOA_TABLE(HadronNucleiTableMC, "AOD", "HADNUCLEIMC", hadron_nuclei_tables::PtNuMC, hadron_nuclei_tables::EtaNuMC, @@ -169,32 +205,6 @@ DECLARE_SOA_TABLE(HadronNucleiTableMC, "AOD", "HADNUCLEIMC", hadron_nuclei_tables::IsPhysicalPrimaryHadMC, hadron_nuclei_tables::SameMCCollision, hadron_nuclei_tables::MatchesRecoMCCollision) -DECLARE_SOA_TABLE(HadronHyperTable, "AOD", "HADHYPERTABLE", - hadron_nuclei_tables::PtHyp, - hadron_nuclei_tables::EtaHyp, - hadron_nuclei_tables::PtHe3, - hadron_nuclei_tables::EtaHe3, - hadron_nuclei_tables::PhiHyp, - hadron_nuclei_tables::PtHad, - hadron_nuclei_tables::EtaHad, - hadron_nuclei_tables::PhiHad, - hadron_nuclei_tables::DcaxyHad, - hadron_nuclei_tables::DcazHad, - hadron_nuclei_tables::SignalTPCHad, - hadron_nuclei_tables::SignalTPCNu, - hadron_nuclei_tables::InnerParamTPCHad, - hadron_nuclei_tables::NSigmaTPCHad, - hadron_nuclei_tables::NSigmaTPCNu, - hadron_nuclei_tables::Chi2TPCHad, - hadron_nuclei_tables::Chi2TPCNu, - hadron_nuclei_tables::MassTOFHad, - hadron_nuclei_tables::PidTrkHad, - hadron_nuclei_tables::ItsClusterSizeHad, - hadron_nuclei_tables::ItsClusterSizeNu, - hadron_nuclei_tables::SharedClustersHad, - hadron_nuclei_tables::TrackIDHad, - hadron_nuclei_tables::IsBkgUS, - hadron_nuclei_tables::IsBkgEM) DECLARE_SOA_TABLE(HadronNucleiMult, "AOD", "HADNUCLEIMULT", hadron_nuclei_tables::CollisionId, hadron_nuclei_tables::ZVertex, @@ -202,6 +212,243 @@ DECLARE_SOA_TABLE(HadronNucleiMult, "AOD", "HADNUCLEIMULT", hadron_nuclei_tables::CentFT0C, hadron_nuclei_tables::MultiplicityFT0C) +// Reduced hadron-hypertriton pair output. Reconstructable quantities such as +// k*, invariant mass and pointing variables are intentionally derived offline. +namespace hadronhyperpair +{ +DECLARE_SOA_COLUMN(IsMixed, isMixed, bool); +DECLARE_SOA_COLUMN(MixingDepth, mixingDepth, int); +DECLARE_SOA_COLUMN(RunNumber, runNumber, int32_t); +DECLARE_SOA_COLUMN(PosZ, posZ, float); +DECLARE_SOA_COLUMN(CentFT0A, centFT0A, float); +DECLARE_SOA_COLUMN(CentFT0C, centFT0C, float); +DECLARE_SOA_COLUMN(CentFT0M, centFT0M, float); +DECLARE_SOA_COLUMN(TrackOccupancy, trackOccupancy, int); +DECLARE_SOA_COLUMN(Ft0cOccupancy, ft0cOccupancy, float); +DECLARE_SOA_COLUMN(NContributors, nContributors, uint16_t); +DECLARE_SOA_COLUMN(MultFT0C, multFT0C, float); +DECLARE_SOA_COLUMN(XPrimVtx, xPrimVtx, float); +DECLARE_SOA_COLUMN(YPrimVtx, yPrimVtx, float); +DECLARE_SOA_COLUMN(ZPrimVtx, zPrimVtx, float); +DECLARE_SOA_COLUMN(HypIsMatter, hypIsMatter, bool); +DECLARE_SOA_COLUMN(HypPtHe3, hypPtHe3, float); +DECLARE_SOA_COLUMN(HypEtaHe3, hypEtaHe3, float); +DECLARE_SOA_COLUMN(HypPhiHe3, hypPhiHe3, float); +DECLARE_SOA_COLUMN(HypPtPi, hypPtPi, float); +DECLARE_SOA_COLUMN(HypEtaPi, hypEtaPi, float); +DECLARE_SOA_COLUMN(HypPhiPi, hypPhiPi, float); +DECLARE_SOA_COLUMN(HypDcaV0Daug, hypDcaV0Daug, float); +DECLARE_SOA_COLUMN(HypDcaHe, hypDcaHe, float); +DECLARE_SOA_COLUMN(HypDcaPi, hypDcaPi, float); +DECLARE_SOA_COLUMN(HypNSigmaHe, hypNSigmaHe, float); +DECLARE_SOA_COLUMN(HypTofMass, hypTofMass, float); +DECLARE_SOA_COLUMN(HypNTPCCrossedRowsHe, hypNTPCCrossedRowsHe, uint8_t); +DECLARE_SOA_COLUMN(HypNTPCCrossedRowsPi, hypNTPCCrossedRowsPi, uint8_t); +DECLARE_SOA_COLUMN(HypTpcMomHe, hypTpcMomHe, float); +DECLARE_SOA_COLUMN(HypTpcMomPi, hypTpcMomPi, float); +DECLARE_SOA_COLUMN(HypTpcSignalHe, hypTpcSignalHe, uint16_t); +DECLARE_SOA_COLUMN(HypTpcSignalPi, hypTpcSignalPi, uint16_t); +DECLARE_SOA_COLUMN(HypTpcChi2He, hypTpcChi2He, float); +DECLARE_SOA_COLUMN(HypItsChi2He, hypItsChi2He, float); +DECLARE_SOA_COLUMN(HypItsChi2Pi, hypItsChi2Pi, float); +DECLARE_SOA_COLUMN(HypItsClusterSizesHe, hypItsClusterSizesHe, uint32_t); +DECLARE_SOA_COLUMN(HypItsClusterSizesPi, hypItsClusterSizesPi, uint32_t); +DECLARE_SOA_COLUMN(HypXDecVtx, hypXDecVtx, float); +DECLARE_SOA_COLUMN(HypYDecVtx, hypYDecVtx, float); +DECLARE_SOA_COLUMN(HypZDecVtx, hypZDecVtx, float); +DECLARE_SOA_COLUMN(HadPt, hadPt, float); +DECLARE_SOA_COLUMN(HadEta, hadEta, float); +DECLARE_SOA_COLUMN(HadPhi, hadPhi, float); +DECLARE_SOA_COLUMN(HadSign, hadSign, int8_t); +DECLARE_SOA_COLUMN(HadDcaXY, hadDcaXY, float); +DECLARE_SOA_COLUMN(HadTpcNClsCrossedRows, hadTpcNClsCrossedRows, uint8_t); +DECLARE_SOA_COLUMN(HadTpcNClsPID, hadTpcNClsPID, uint8_t); +DECLARE_SOA_COLUMN(HadTpcChi2NCl, hadTpcChi2NCl, float); +DECLARE_SOA_COLUMN(HadItsClusterSizes, hadItsClusterSizes, uint32_t); +DECLARE_SOA_COLUMN(HadItsChi2NCl, hadItsChi2NCl, float); +DECLARE_SOA_COLUMN(HadHasTOF, hadHasTOF, bool); +DECLARE_SOA_COLUMN(HadTpcNSigmaPi, hadTpcNSigmaPi, float); +DECLARE_SOA_COLUMN(HadTpcNSigmaKa, hadTpcNSigmaKa, float); +DECLARE_SOA_COLUMN(HadTpcNSigmaPr, hadTpcNSigmaPr, float); +DECLARE_SOA_COLUMN(HadTofNSigmaPi, hadTofNSigmaPi, float); +DECLARE_SOA_COLUMN(HadTofNSigmaKa, hadTofNSigmaKa, float); +DECLARE_SOA_COLUMN(HadTofNSigmaPr, hadTofNSigmaPr, float); +DECLARE_SOA_COLUMN(HypGenPt, hypGenPt, float); +DECLARE_SOA_COLUMN(HypGenEta, hypGenEta, float); +DECLARE_SOA_COLUMN(HypGenPhi, hypGenPhi, float); +DECLARE_SOA_COLUMN(HypGenXDecVtx, hypGenXDecVtx, float); +DECLARE_SOA_COLUMN(HypGenYDecVtx, hypGenYDecVtx, float); +DECLARE_SOA_COLUMN(HypGenZDecVtx, hypGenZDecVtx, float); +DECLARE_SOA_COLUMN(HypIsReco, hypIsReco, bool); +DECLARE_SOA_COLUMN(HypIsSignal, hypIsSignal, bool); +DECLARE_SOA_COLUMN(HypIsRecoMCCollision, hypIsRecoMCCollision, bool); +DECLARE_SOA_COLUMN(HypIsSurvEvSel, hypIsSurvEvSel, bool); +DECLARE_SOA_COLUMN(HypIsTwoBodyDecay, hypIsTwoBodyDecay, bool); +DECLARE_SOA_COLUMN(HypStatusCode, hypStatusCode, int16_t); +DECLARE_SOA_COLUMN(HeGenPt, heGenPt, float); +DECLARE_SOA_COLUMN(HeIsPhysicalPrimary, heIsPhysicalPrimary, bool); +DECLARE_SOA_COLUMN(DecayPiIsPhysicalPrimary, decayPiIsPhysicalPrimary, bool); +DECLARE_SOA_COLUMN(HadRecoPt, hadRecoPt, float); +DECLARE_SOA_COLUMN(HadRecoEta, hadRecoEta, float); +DECLARE_SOA_COLUMN(HadRecoPhi, hadRecoPhi, float); +DECLARE_SOA_COLUMN(HadGenPt, hadGenPt, float); +DECLARE_SOA_COLUMN(HadGenEta, hadGenEta, float); +DECLARE_SOA_COLUMN(HadGenPhi, hadGenPhi, float); +DECLARE_SOA_COLUMN(HadIsPhysicalPrimary, hadIsPhysicalPrimary, bool); +DECLARE_SOA_COLUMN(HadProcess, hadProcess, int16_t); +DECLARE_SOA_COLUMN(SameMCCollision, sameMCCollision, bool); +DECLARE_SOA_COLUMN(MatchesHypRecoMCCollision, matchesHypRecoMCCollision, bool); +DECLARE_SOA_COLUMN(MatchesPairRecoMCCollision, matchesPairRecoMCCollision, bool); +DECLARE_SOA_COLUMN(IsTruthSelfCorrelation, isTruthSelfCorrelation, bool); +DECLARE_SOA_COLUMN(IsTruePrimaryHadHyperPair, isTruePrimaryHadHyperPair, bool); +} // namespace hadronhyperpair + +DECLARE_SOA_TABLE(HadronHyperTable, "AOD", "HADHYPERTABLE", + hadronhyperpair::IsMixed, + hadronhyperpair::MixingDepth, + hadronhyperpair::RunNumber, + hadronhyperpair::PosZ, + hadronhyperpair::CentFT0A, + hadronhyperpair::CentFT0C, + hadronhyperpair::CentFT0M, + hadronhyperpair::TrackOccupancy, + hadronhyperpair::Ft0cOccupancy, + hadronhyperpair::NContributors, + hadronhyperpair::MultFT0C, + hadronhyperpair::XPrimVtx, + hadronhyperpair::YPrimVtx, + hadronhyperpair::ZPrimVtx, + hadronhyperpair::HypIsMatter, + hadronhyperpair::HypPtHe3, + hadronhyperpair::HypEtaHe3, + hadronhyperpair::HypPhiHe3, + hadronhyperpair::HypPtPi, + hadronhyperpair::HypEtaPi, + hadronhyperpair::HypPhiPi, + hadronhyperpair::HypDcaV0Daug, + hadronhyperpair::HypDcaHe, + hadronhyperpair::HypDcaPi, + hadronhyperpair::HypNSigmaHe, + hadronhyperpair::HypTofMass, + hadronhyperpair::HypNTPCCrossedRowsHe, + hadronhyperpair::HypNTPCCrossedRowsPi, + hadronhyperpair::HypTpcMomHe, + hadronhyperpair::HypTpcMomPi, + hadronhyperpair::HypTpcSignalHe, + hadronhyperpair::HypTpcSignalPi, + hadronhyperpair::HypTpcChi2He, + hadronhyperpair::HypItsChi2He, + hadronhyperpair::HypItsChi2Pi, + hadronhyperpair::HypItsClusterSizesHe, + hadronhyperpair::HypItsClusterSizesPi, + hadronhyperpair::HypXDecVtx, + hadronhyperpair::HypYDecVtx, + hadronhyperpair::HypZDecVtx, + hadronhyperpair::HadPt, + hadronhyperpair::HadEta, + hadronhyperpair::HadPhi, + hadronhyperpair::HadSign, + hadronhyperpair::HadDcaXY, + hadronhyperpair::HadTpcNClsCrossedRows, + hadronhyperpair::HadTpcNClsPID, + hadronhyperpair::HadTpcChi2NCl, + hadronhyperpair::HadItsClusterSizes, + hadronhyperpair::HadItsChi2NCl, + hadronhyperpair::HadHasTOF, + hadronhyperpair::HadTpcNSigmaPi, + hadronhyperpair::HadTpcNSigmaKa, + hadronhyperpair::HadTpcNSigmaPr, + hadronhyperpair::HadTofNSigmaPi, + hadronhyperpair::HadTofNSigmaKa, + hadronhyperpair::HadTofNSigmaPr); + +DECLARE_SOA_TABLE(HadronHyperTableMC, "AOD", "HADHYPERMC", + hadronhyperpair::IsMixed, + hadronhyperpair::MixingDepth, + hadronhyperpair::RunNumber, + hadronhyperpair::PosZ, + hadronhyperpair::CentFT0A, + hadronhyperpair::CentFT0C, + hadronhyperpair::CentFT0M, + hadronhyperpair::TrackOccupancy, + hadronhyperpair::Ft0cOccupancy, + hadronhyperpair::NContributors, + hadronhyperpair::MultFT0C, + hadronhyperpair::XPrimVtx, + hadronhyperpair::YPrimVtx, + hadronhyperpair::ZPrimVtx, + hadronhyperpair::HypIsMatter, + hadronhyperpair::HypPtHe3, + hadronhyperpair::HypEtaHe3, + hadronhyperpair::HypPhiHe3, + hadronhyperpair::HypPtPi, + hadronhyperpair::HypEtaPi, + hadronhyperpair::HypPhiPi, + hadronhyperpair::HypDcaV0Daug, + hadronhyperpair::HypDcaHe, + hadronhyperpair::HypDcaPi, + hadronhyperpair::HypNSigmaHe, + hadronhyperpair::HypTofMass, + hadronhyperpair::HypNTPCCrossedRowsHe, + hadronhyperpair::HypNTPCCrossedRowsPi, + hadronhyperpair::HypTpcMomHe, + hadronhyperpair::HypTpcMomPi, + hadronhyperpair::HypTpcSignalHe, + hadronhyperpair::HypTpcSignalPi, + hadronhyperpair::HypTpcChi2He, + hadronhyperpair::HypItsChi2He, + hadronhyperpair::HypItsChi2Pi, + hadronhyperpair::HypItsClusterSizesHe, + hadronhyperpair::HypItsClusterSizesPi, + hadronhyperpair::HypXDecVtx, + hadronhyperpair::HypYDecVtx, + hadronhyperpair::HypZDecVtx, + hadronhyperpair::HadPt, + hadronhyperpair::HadEta, + hadronhyperpair::HadPhi, + hadronhyperpair::HadSign, + hadronhyperpair::HadDcaXY, + hadronhyperpair::HadTpcNClsCrossedRows, + hadronhyperpair::HadTpcNClsPID, + hadronhyperpair::HadTpcChi2NCl, + hadronhyperpair::HadItsClusterSizes, + hadronhyperpair::HadItsChi2NCl, + hadronhyperpair::HadHasTOF, + hadronhyperpair::HadTpcNSigmaPi, + hadronhyperpair::HadTpcNSigmaKa, + hadronhyperpair::HadTpcNSigmaPr, + hadronhyperpair::HadTofNSigmaPi, + hadronhyperpair::HadTofNSigmaKa, + hadronhyperpair::HadTofNSigmaPr, + hadronhyperpair::HypGenPt, + hadronhyperpair::HypGenEta, + hadronhyperpair::HypGenPhi, + hadronhyperpair::HypGenXDecVtx, + hadronhyperpair::HypGenYDecVtx, + hadronhyperpair::HypGenZDecVtx, + hadronhyperpair::HypIsReco, + hadronhyperpair::HypIsSignal, + hadronhyperpair::HypIsRecoMCCollision, + hadronhyperpair::HypIsSurvEvSel, + hadronhyperpair::HypIsTwoBodyDecay, + hadronhyperpair::HypStatusCode, + hadronhyperpair::HeGenPt, + hadronhyperpair::HeIsPhysicalPrimary, + hadronhyperpair::DecayPiIsPhysicalPrimary, + hadronhyperpair::HadRecoPt, + hadronhyperpair::HadRecoEta, + hadronhyperpair::HadRecoPhi, + hadronhyperpair::HadGenPt, + hadronhyperpair::HadGenEta, + hadronhyperpair::HadGenPhi, + hadronhyperpair::HadIsPhysicalPrimary, + hadronhyperpair::HadProcess, + hadronhyperpair::SameMCCollision, + hadronhyperpair::MatchesHypRecoMCCollision, + hadronhyperpair::MatchesPairRecoMCCollision, + hadronhyperpair::IsTruthSelfCorrelation, + hadronhyperpair::IsTruePrimaryHadHyperPair); + } // namespace o2::aod #endif // PWGCF_FEMTO_FEMTONUCLEI_DATAMODEL_HADRONNUCLEITABLES_H_ diff --git a/PWGCF/Femto/FemtoNuclei/TableProducer/HadNucleiFemto.cxx b/PWGCF/Femto/FemtoNuclei/TableProducer/HadNucleiFemto.cxx index ffc11f0065e..fdc18ea18d2 100644 --- a/PWGCF/Femto/FemtoNuclei/TableProducer/HadNucleiFemto.cxx +++ b/PWGCF/Femto/FemtoNuclei/TableProducer/HadNucleiFemto.cxx @@ -10,8 +10,8 @@ // or submit itself to any jurisdiction. // -/// \file HadNucleiFemto.cxx -/// \brief Analysis task for Nuclei-Hadron femto analysis +/// \file HadNucleiFemtoDcaPurity.cxx +/// \brief Nuclei-hadron femtoscopy task with DCA-fraction and purity inputs /// \author CMY /// \date 2025-04-10 @@ -57,6 +57,9 @@ #include #include #include +#include +#include +#include #include #include @@ -78,8 +81,12 @@ using namespace o2::framework::expressions; using std::array; using CollBracket = o2::math_utils::Bracket; +using HyperCandidates = aod::DataHypCandsWColl; +using HyperCandidatesMC = aod::MCHypCands; using CollisionsFull = soa::Join; using CollisionsFullMC = soa::Join; +using HadHyperCollisionsFull = soa::Join; +using HadHyperCollisionsFullMC = soa::Join; using TrackCandidates = soa::Join; using TrackCandidatesMC = soa::Join; @@ -93,6 +100,17 @@ constexpr std::array tmpRadiiTPC{{85.f, 105.f, 125.f, 145.f, 165.f, 18 constexpr int DeuteronPDG = o2::constants::physics::Pdg::kDeuteron; constexpr int TritonPDG = o2::constants::physics::Pdg::kTriton; constexpr int He3PDG = o2::constants::physics::Pdg::kHelium3; +constexpr int HyperTritonPDG = o2::constants::physics::Pdg::kHyperTriton; +constexpr int Lithium4PDG = o2::constants::physics::Pdg::kLithium4; +// Store an exact integer PDG code in sparse histograms as +// sign * (high * kMotherPdgChunkBase + low). Splitting the code avoids the +// loss of integer precision that a single float coordinate has near 10^9. +constexpr int MotherPdgChunkBase = 10000; // o2-linter: disable=pdg/explicit-code (encoding base, not a PDG code) +constexpr int MotherPdgHighMax = 120000; // o2-linter: disable=pdg/explicit-code (encoding-axis limit, not a PDG code) +constexpr int HadronDcaFitBins = 2400; // 0.002 cm/bin in [-2.4, 2.4] cm +constexpr float HadronDcaFitAxisMax = 2.4f; +constexpr int NucleusDcaFitBins = 2000; // 0.001 cm/bin in [-1, 1] cm +constexpr float NucleusDcaFitAxisMax = 1.f; constexpr float He3TPCChi2NClMin = 0.5f; using PairLorentzVector = ROOT::Math::LorentzVector>; @@ -103,6 +121,48 @@ enum Selections { kAll }; +enum DcaOrigin { + Primary = 0, + WeakDecay, + Material, + NDcaOrigins +}; + +enum CollisionAssociation { + CorrectCollision = 0, + WrongCollision, + NCollisionAssociations +}; + +// The base DCA origin stays primary/weak/material. This independent parent +// axis permits optional feed-down splits without changing the base templates. +enum ParentCategory { + NoSpecialParent = 0, + LambdaParent, + SigmaParent, + K0ShortParent, + K0LongParent, + ChargedKaonParent, + HypertritonParent, + Lithium4Parent, + OtherDecayParent, + MissingDecayParent, + NParentCategories +}; + +enum PurityCategory { + AllSelected = 0, + CorrectSpecies, + MisidentifiedSpecies, + NoMCLabel, + CorrectCollisionSpecies, + WrongCollisionSpecies, + CorrectPrimary, + CorrectWeakDecay, + CorrectMaterial, + NPurityCategories +}; + } // namespace struct HadNucandidate { @@ -136,11 +196,20 @@ struct HadNucandidate { uint8_t nTPCClustersHad = 0u; uint8_t nTPCCrossedRowsNu = 0u; uint8_t nTPCCrossedRowsHad = 0u; + uint8_t nTPCFindableNu = 0u; + uint8_t nTPCFindableHad = 0u; uint8_t sharedClustersNu = 0u; uint8_t sharedClustersHad = 0u; + float fractionSharedTPCNu = 0.f; + float fractionSharedTPCHad = 0.f; float chi2TPCNu = -10.f; float chi2TPCHad = -10.f; + float chi2ITSNu = -10.f; + float chi2ITSHad = -10.f; float nSigmaNu = -10.f; + float nSigmaTPCNuDe = -10.f; + float nSigmaTPCNuPr = -10.f; + float nSigmaTPCNuPi = -10.f; float nSigmaHad = -10.f; float nSigmaTOFNu = -10.f; float nSigmaITSNu = -10.f; @@ -163,12 +232,16 @@ struct HadNucandidate { uint8_t nClsItsNu = 0u; uint8_t nClsItsHad = 0u; + uint8_t nClsItsInnerBarrelNu = 0u; + uint8_t nClsItsInnerBarrelHad = 0u; bool isBkgUS = false; // unlike sign bool isBkgEM = false; // event mixing - int trackIDNu = -1; - int trackIDHad = -1; + int64_t trackIDNu = -1; + int64_t trackIDHad = -1; + int64_t collisionIDNu = -1; + int64_t collisionIDHad = -1; float deltaEta = -99.f; float deltaPhi = -99.f; @@ -197,10 +270,17 @@ struct BufferedTrack { float tpcInnerParam{-99.f}; uint8_t tpcNClsFound{0u}; uint8_t tpcNClsCrossedRows{0u}; + uint8_t tpcNClsFindable{0u}; uint8_t tpcNClsShared{0u}; + float tpcFractionSharedCls{0.f}; uint8_t itsNCls{0u}; + uint8_t itsNClsInnerBarrel{0u}; float tpcChi2NCl{-10.f}; + float itsChi2NCl{-10.f}; float nSigmaTPC{-10.f}; + float nSigmaTPCDe{-10.f}; + float nSigmaTPCPr{-10.f}; + float nSigmaTPCPi{-10.f}; float nSigmaTOF{-10.f}; float nSigmaITS{-10.f}; float nSigmaTPCHadPi{-10.f}; @@ -213,6 +293,7 @@ struct BufferedTrack { uint32_t pidForTracking{0xFFFFFu}; uint32_t itsClusterSizes{0u}; int64_t trackId{-1}; + int64_t collisionId{-1}; }; struct BufferedCollision { @@ -229,7 +310,8 @@ struct HadNucleiFemto { Produces mOutputDataTable; Produces mOutputMCTable; - Produces mOutputHyperDataTable; + Produces mOutputHadHyperDataTable; + Produces mOutputHadHyperMCTable; Produces mOutputMultiplicityTable; struct : o2::framework::ConfigurableGroup { @@ -246,6 +328,7 @@ struct HadNucleiFemto { // Event selection and mixing configuration Configurable settingCutVertex{"settingCutVertex", 10.0f, "Accepted z-vertex range"}; Configurable settingNoMixedEvents{"settingNoMixedEvents", 5, "Number of mixed events per event"}; + Configurable settingRequireBothSpeciesForMixing{"settingRequireBothSpeciesForMixing", false, "Use only events containing at least one selected nucleus and one selected hadron for mixed-event pairing"}; Configurable settingEnableBkgUS{"settingEnableBkgUS", false, "Enable US background"}; Configurable settingSaveUSandLS{"settingSaveUSandLS", true, "Save All Pairs"}; } eventMixing; @@ -332,6 +415,7 @@ struct HadNucleiFemto { std::string prefix{"CPR"}; // Close pair rejection controls Configurable settingEnableClosePairRejection{"settingEnableClosePairRejection", false, "Enable close pair rejection for nucleus-hadron track pairs"}; + Configurable settingApplyClosePairRejection{"settingApplyClosePairRejection", true, "Reject close pairs; disable to calculate and store CPR variables without rejecting pairs"}; Configurable settingClosePairDeltaPhiMax{"settingClosePairDeltaPhiMax", 0.01f, "Maximum delta phi star for close pair rejection"}; Configurable settingClosePairDeltaEtaMax{"settingClosePairDeltaEtaMax", 0.01f, "Maximum delta eta for close pair rejection"}; Configurable settingClosePairRadiusMode{"settingClosePairRadiusMode", 1, "Close pair rejection mode: 0 = PV, 1 = average phi star, 2 = specific TPC radius"}; @@ -348,14 +432,145 @@ struct HadNucleiFemto { Configurable settingRequirePhysicalPrimaries{"settingRequirePhysicalPrimaries", false, "Store only pairs in which both truth particles are physical primaries"}; } mc; + struct : o2::framework::ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"fractionPurity"}; + Configurable settingHadronDcaFitAbsMax{"settingHadronDcaFitAbsMax", 2.4f, "Maximum absolute pion DCAxy and DCAz stored for the fraction fit"}; + Configurable settingNucleusDcaFitAbsMax{"settingNucleusDcaFitAbsMax", 1.0f, "Maximum absolute nucleus DCAxy and DCAz stored for the fraction fit"}; + Configurable settingRequireRecoMCCollisionMatch{"settingRequireRecoMCCollisionMatch", true, "For the base DCA templates, require the truth particle to belong to the reconstructed collision MC label; detailed templates always store both association classes"}; + } fractionPurity; + struct : o2::framework::ConfigurableGroup { // cppcheck-suppress unusedStructMember std::string prefix{"hypertriton"}; // Hypertriton-specific cuts - Configurable settingCutTPCChi2He{"settingCutTPCChi2He", 0.0f, "Minimum tpcChi2He for Hyper He3"}; - Configurable settingCutAverClsSizeHe{"settingCutAverClsSizeHe", 0.0f, "Minimum averClusSizeHe for Hyper He3"}; + Configurable settingHypMassMin{"settingHypMassMin", 2.94f, "Minimum hypertriton invariant mass"}; + Configurable settingHypMassMax{"settingHypMassMax", 3.10f, "Maximum hypertriton invariant mass"}; } hypertriton; + struct : o2::framework::ConfigurableGroup { + // cppcheck-suppress unusedStructMember + std::string prefix{"hadHyper"}; + Configurable enableMixing{"enableMixing", true, "Build mixed-event pion-hypertriton pairs"}; + Configurable maxOutputKstar{"maxOutputKstar", -1.f, "Maximum pair k* (GeV/c); negative saves all selected pairs"}; + } hadHyper; + + HistogramRegistry hadHyperRegistry{ + "hadHyperRegistry", + {{"hSE", "Raw same-event pairs;k*;Entries", {HistType::kTH1D, {{300, 0., 3.}}}}, + {"hME", "Raw mixed-event pairs;k*;Entries", {HistType::kTH1D, {{300, 0., 3.}}}}, + {"hMass", "Unique selected candidates;mass He3-pi;Entries", {HistType::kTH1D, {{160, 2.94, 3.10}}}}, + {"hSelfPairs", "Rejected daughter reuse;reason (0=He3,1=pion,2=truth);k*", {HistType::kTH2F, {{3, -0.5, 2.5}, {300, 0., 3.}}}}, + {"hSameEventSelfPairs", "Same-event rejected daughter reuse;reason (0=He3,1=pion,2=truth);k*", {HistType::kTH2F, {{3, -0.5, 2.5}, {300, 0., 3.}}}}, + {"hCandidatePairMultiplicitySE", "Accepted same-event hadron pairs per hypertriton candidate;pairs;centrality", {HistType::kTH2F, {{200, -0.5, 199.5}, {10, 0., 100.}}}}, + {"hCandidatePairMultiplicityME", "Accepted mixed-event hadron pairs per hypertriton candidate;pairs;centrality", {HistType::kTH2F, {{200, -0.5, 199.5}, {10, 0., 100.}}}}, + {"hMixEventDeltaPosZVsCent", "Mixed-event #Delta z_{vtx} vs hypertriton centrality;hypertriton CentFT0C;#Delta z_{vtx}", {HistType::kTH2F, {{100, 0., 100.}, {120, -30., 30.}}}}, + {"hMixEventDeltaCentFT0CVsCent", "Mixed-event #Delta CentFT0C vs hypertriton centrality;hypertriton CentFT0C;#Delta CentFT0C", {HistType::kTH2F, {{100, 0., 100.}, {200, -100., 100.}}}}, + {"hMixingDepth", "Available partner events;events;anchor events", {HistType::kTH1F, {{101, -0.5, 100.5}}}}, + {"hPoolFlow", "Mixing pool selection;0=selected,1=in range;events", {HistType::kTH1F, {{2, -0.5, 1.5}}}}, + {"hClosePairBeforePV", "Hadron-hypertriton PV close-pair QA before rejection;#Delta#eta;#Delta#varphi", {HistType::kTH2F, {{200, -0.1, 0.1}, {200, -0.1, 0.1}}}}, + {"hClosePairAfterPV", "Hadron-hypertriton PV close-pair QA after rejection;#Delta#eta;#Delta#varphi", {HistType::kTH2F, {{200, -0.1, 0.1}, {200, -0.1, 0.1}}}}, + {"hDaughterHeTPC", "He3 daughter QA per candidate;TPC rigidity;TPC signal", {HistType::kTH2F, {{100, 0., 10.}, {300, 0., 1500.}}}}, + {"hDaughterPiTPC", "Pion daughter QA per candidate;TPC rigidity;TPC signal", {HistType::kTH2F, {{100, 0., 10.}, {300, 0., 1500.}}}}, + {"hHadronTPC", "Pair hadron QA per selected track;TPC rigidity;TPC signal", {HistType::kTH2F, {{100, 0., 10.}, {300, 0., 1500.}}}}, + {"MC/hKstarRecVsGenHyperReco", "Hadron-hypertriton k* response for reconstructed true hypertritons;generated k* (GeV/#it{c});reconstructed k* (GeV/#it{c})", {HistType::kTH2F, {{300, 0., 3.}, {300, 0., 3.}}}}, + {"MC/hKstarResolutionHyperReco", "Hadron-hypertriton k* resolution for reconstructed true hypertritons;reconstructed k* (GeV/#it{c});k*_{reco}-k*_{gen} (GeV/#it{c})", {HistType::kTH2F, {{300, 0., 3.}, {200, -0.2, 0.2}}}}, + {"MC/hPrimaryHadronVsKstarDen", "Truth-matched selected hadron denominator;k* (GeV/#it{c});Entries", {HistType::kTH1D, {{300, 0., 3.}}}}, + {"MC/hPrimaryHadronVsKstarNum", "Physical-primary selected hadron numerator;k* (GeV/#it{c});Entries", {HistType::kTH1D, {{300, 0., 3.}}}}, + {"MC/hPrimaryHadronVsCentDen", "Truth-matched selected hadron denominator;hypertriton CentFT0C;Entries", {HistType::kTH1D, {{100, 0., 100.}}}}, + {"MC/hPrimaryHadronVsCentNum", "Physical-primary selected hadron numerator;hypertriton CentFT0C;Entries", {HistType::kTH1D, {{100, 0., 100.}}}}}}; + + // Tuple order follows the column blocks in HadronNucleiTables.h. + using HadHyperTrackInfo = std::tuple; + using HadHyperEventInfo = std::tuple; + using HadHyperCandidateInfo = std::tuple; + using HadHyperDataInfo = decltype(std::tuple_cat(std::declval>(), + std::declval(), + std::declval(), + std::declval())); + using HadHyperMCInfo = std::tuple; + + struct HadHyperParticleTruth { + int64_t particleId{-1}; + int64_t collisionId{-1}; + int32_t pdgCode{0}; + float pt{-1.f}; + float eta{-999.f}; + float phi{-999.f}; + bool isPhysicalPrimary{false}; + int16_t statusCode{0}; + int16_t process{0}; + std::array momentum{0.f, 0.f, 0.f}; + }; + + struct HadHyperCandidate { + HadHyperCandidateInfo info{}; + HadHyperParticleTruth hyperTruth{}; + HadHyperParticleTruth heTruth{}; + HadHyperParticleTruth decayPionTruth{}; + int64_t sourceCandidateId{-1}; + int64_t heTrackId{-1}; + int64_t pionTrackId{-1}; + int16_t statusCode{0}; + bool isReco{true}; + bool isSignal{false}; + bool isRecoMCCollision{false}; + bool isSurvEvSel{false}; + bool isTwoBodyDecay{false}; + uint8_t isFakeHeOnITSLayer{0u}; + float genPt{-1.f}; + float genEta{-1.f}; + float genPhi{-1.f}; + float genPtHe3{-1.f}; + std::array genDecVtx{-1.f, -1.f, -1.f}; + std::array momentum{}; + std::array genMomentum{}; + float mass{0.f}; + float etaHe{0.f}; + float phiHe{0.f}; + float etaPi{0.f}; + float phiPi{0.f}; + bool isMatter{false}; + + float pt() const { return std::hypot(momentum[0], momentum[1]); } + float eta() const + { + const float transverseMomentum = pt(); + return transverseMomentum > 0.f ? std::asinh(momentum[2] / transverseMomentum) : 999.f; + } + float phi() const { return std::atan2(momentum[1], momentum[0]); } + int8_t sign() const { return isMatter ? 1 : -1; } + }; + + struct HadHyperHadron { + HadHyperTrackInfo info{}; + HadHyperParticleTruth truth{}; + std::vector motherIds; + int64_t sourceId{-1}; + std::array momentum{}; + float tpcInnerParam{0.f}; + float tpcSignal{0.f}; + float etaValue{0.f}; + float phiValue{0.f}; + int8_t signValue{0}; + + float pt() const { return std::hypot(momentum[0], momentum[1]); } + float eta() const { return etaValue; } + float phi() const { return phiValue; } + int8_t sign() const { return signValue; } + }; + + struct HadHyperEvent { + HadHyperEventInfo info{}; + int64_t mcCollisionId{-1}; + bool hasMCCollision{false}; + float centrality{0.f}; + std::vector candidates; + std::vector hadrons; + }; + struct : o2::framework::ConfigurableGroup { // cppcheck-suppress unusedStructMember std::string prefix{"output"}; @@ -399,7 +614,8 @@ struct HadNucleiFemto { Preslice mPerCol = aod::track::collisionId; Preslice mPerColMC = aod::track::collisionId; - PresliceUnsorted hypPerCol = o2::aod::hyperrec::collisionId; + PresliceUnsorted hypPerCol = o2::aod::hyperrec::collisionId; + PresliceUnsorted hypPerColMC = o2::aod::hyperrec::collisionId; // binning for EM background ConfigurableAxis axisVertex{"axisVertex", {30, -10, 10}, "Binning for vtxz"}; @@ -410,10 +626,13 @@ struct HadNucleiFemto { float mMassHad{0.f}; std::vector mGoodCollisions; std::vector mTrackPairs; - std::vector mTrackHypPairs; std::unordered_map> mMixingPools; + std::unordered_map> mHyperMixingPools; + std::unordered_map> mHyperMCMixingPools; int64_t mNextMixedEventId{0}; int mMixingRunNumber{-1}; + int mHyperMixingRunNumber{-1}; + int mHyperMCMixingRunNumber{-1}; o2::vertexing::DCAFitterN<2> mFitter; int mRunNumber{0}; @@ -467,6 +686,40 @@ struct HadNucleiFemto { {"MC/hPtNuRecVsGen", "Reconstructed versus generated signed nucleus pT;generated pT (GeV/c);reconstructed pT (GeV/c)", {HistType::kTH2F, {{280, -7.f, 7.f}, {280, -7.f, 7.f}}}}, {"MC/hPtHadRecVsGen", "Reconstructed versus generated signed pion pT;generated pT (GeV/c);reconstructed pT (GeV/c)", {HistType::kTH2F, {{280, -7.f, 7.f}, {280, -7.f, 7.f}}}}, + // Base inputs for Giorgio-style offline DCA fits. The origin axis is: + // 0 primary, 1 weak decay, 2 material (every non-primary, non-decay process). + {"fraction/hDcaDataHad", "Pion DCA-fit input;signed reconstructed p_{T} (GeV/c);DCA_{xy} (cm);DCA_{z} (cm);centrality", {HistType::kTHnSparseF, {{280, -7.f, 7.f}, {HadronDcaFitBins, -HadronDcaFitAxisMax, HadronDcaFitAxisMax}, {HadronDcaFitBins, -HadronDcaFitAxisMax, HadronDcaFitAxisMax}, {40, 0.f, 100.f}}}}, + {"fraction/hDcaDataNu", "Nucleus DCA-fit input;signed physical reconstructed p_{T} (GeV/c);DCA_{xy} (cm);DCA_{z} (cm);centrality", {HistType::kTHnSparseF, {{280, -7.f, 7.f}, {NucleusDcaFitBins, -NucleusDcaFitAxisMax, NucleusDcaFitAxisMax}, {NucleusDcaFitBins, -NucleusDcaFitAxisMax, NucleusDcaFitAxisMax}, {40, 0.f, 100.f}}}}, + {"fraction/hDcaTemplateHad", "Truth pion DCA templates;signed reconstructed p_{T} (GeV/c);DCA_{xy} (cm);DCA_{z} (cm);centrality;origin", {HistType::kTHnSparseF, {{280, -7.f, 7.f}, {HadronDcaFitBins, -HadronDcaFitAxisMax, HadronDcaFitAxisMax}, {HadronDcaFitBins, -HadronDcaFitAxisMax, HadronDcaFitAxisMax}, {40, 0.f, 100.f}, {NDcaOrigins, -0.5f, static_cast(NDcaOrigins) - 0.5f}}}}, + {"fraction/hDcaTemplateNu", "Truth nucleus DCA templates;signed physical reconstructed p_{T} (GeV/c);DCA_{xy} (cm);DCA_{z} (cm);centrality;origin", {HistType::kTHnSparseF, {{280, -7.f, 7.f}, {NucleusDcaFitBins, -NucleusDcaFitAxisMax, NucleusDcaFitAxisMax}, {NucleusDcaFitBins, -NucleusDcaFitAxisMax, NucleusDcaFitAxisMax}, {40, 0.f, 100.f}, {NDcaOrigins, -0.5f, static_cast(NDcaOrigins) - 0.5f}}}}, + + // DCA shapes of selected candidates that are not the requested truth + // species. They are kept separate from primary/weak/material so that + // their normalisation can be fixed or constrained by the PID purity. + {"fraction/hDcaMisidentifiedHad", "Misidentified pion candidates;signed reconstructed p_{T} (GeV/c);DCA_{xy} (cm);DCA_{z} (cm);centrality;collision association", {HistType::kTHnSparseF, {{280, -7.f, 7.f}, {HadronDcaFitBins, -HadronDcaFitAxisMax, HadronDcaFitAxisMax}, {HadronDcaFitBins, -HadronDcaFitAxisMax, HadronDcaFitAxisMax}, {40, 0.f, 100.f}, {NCollisionAssociations, -0.5f, static_cast(NCollisionAssociations) - 0.5f}}}}, + {"fraction/hDcaMisidentifiedNu", "Misidentified nucleus candidates;signed physical reconstructed p_{T} (GeV/c);DCA_{xy} (cm);DCA_{z} (cm);centrality;collision association", {HistType::kTHnSparseF, {{280, -7.f, 7.f}, {NucleusDcaFitBins, -NucleusDcaFitAxisMax, NucleusDcaFitAxisMax}, {NucleusDcaFitBins, -NucleusDcaFitAxisMax, NucleusDcaFitAxisMax}, {40, 0.f, 100.f}, {NCollisionAssociations, -0.5f, static_cast(NCollisionAssociations) - 0.5f}}}}, + {"fraction/hDcaNoMCLabelHad", "Selected pion candidates without an MC label;signed reconstructed p_{T} (GeV/c);DCA_{xy} (cm);DCA_{z} (cm);centrality", {HistType::kTHnSparseF, {{280, -7.f, 7.f}, {HadronDcaFitBins, -HadronDcaFitAxisMax, HadronDcaFitAxisMax}, {HadronDcaFitBins, -HadronDcaFitAxisMax, HadronDcaFitAxisMax}, {40, 0.f, 100.f}}}}, + {"fraction/hDcaNoMCLabelNu", "Selected nucleus candidates without an MC label;signed physical reconstructed p_{T} (GeV/c);DCA_{xy} (cm);DCA_{z} (cm);centrality", {HistType::kTHnSparseF, {{280, -7.f, 7.f}, {NucleusDcaFitBins, -NucleusDcaFitAxisMax, NucleusDcaFitAxisMax}, {NucleusDcaFitBins, -NucleusDcaFitAxisMax, NucleusDcaFitAxisMax}, {40, 0.f, 100.f}}}}, + + // Superset templates for optional offline refinements. They retain the + // same base origin plus collision association, direct-parent category, + // and the particle production radius. Projecting away the extra axes + // recovers the base shapes; selecting them enables species-specific fits. + {"fraction/hDcaTemplateDetailHad", "Detailed truth pion DCA templates;signed reconstructed p_{T} (GeV/c);DCA_{xy} (cm);DCA_{z} (cm);centrality;origin;collision association;parent category;production R_{xy} (cm)", {HistType::kTHnSparseF, {{280, -7.f, 7.f}, {HadronDcaFitBins, -HadronDcaFitAxisMax, HadronDcaFitAxisMax}, {HadronDcaFitBins, -HadronDcaFitAxisMax, HadronDcaFitAxisMax}, {40, 0.f, 100.f}, {NDcaOrigins, -0.5f, static_cast(NDcaOrigins) - 0.5f}, {NCollisionAssociations, -0.5f, static_cast(NCollisionAssociations) - 0.5f}, {NParentCategories, -0.5f, static_cast(NParentCategories) - 0.5f}, {200, 0.f, 100.f}}}}, + {"fraction/hDcaTemplateDetailNu", "Detailed truth nucleus DCA templates;signed physical reconstructed p_{T} (GeV/c);DCA_{xy} (cm);DCA_{z} (cm);centrality;origin;collision association;parent category;production R_{xy} (cm)", {HistType::kTHnSparseF, {{280, -7.f, 7.f}, {NucleusDcaFitBins, -NucleusDcaFitAxisMax, NucleusDcaFitAxisMax}, {NucleusDcaFitBins, -NucleusDcaFitAxisMax, NucleusDcaFitAxisMax}, {40, 0.f, 100.f}, {NDcaOrigins, -0.5f, static_cast(NDcaOrigins) - 0.5f}, {NCollisionAssociations, -0.5f, static_cast(NCollisionAssociations) - 0.5f}, {NParentCategories, -0.5f, static_cast(NParentCategories) - 0.5f}, {200, 0.f, 100.f}}}}, + + // Mother-resolved templates. There is one entry per direct mother (or a + // single zero-code entry when no mother is stored). Reconstruct the exact + // PDG code offline as sign * (PDG high * 10000 + PDG low). + {"fraction/hDcaMotherPdgHad", "Pion DCA by exact direct-mother PDG; signed reconstructed p_{T} (GeV/c);DCA_{xy} (cm);DCA_{z} (cm);centrality;origin;collision association;mother PDG sign;mother PDG high;mother PDG low", {HistType::kTHnSparseF, {{280, -7.f, 7.f}, {HadronDcaFitBins, -HadronDcaFitAxisMax, HadronDcaFitAxisMax}, {HadronDcaFitBins, -HadronDcaFitAxisMax, HadronDcaFitAxisMax}, {40, 0.f, 100.f}, {NDcaOrigins, -0.5f, static_cast(NDcaOrigins) - 0.5f}, {NCollisionAssociations, -0.5f, static_cast(NCollisionAssociations) - 0.5f}, {3, -1.5f, 1.5f}, {MotherPdgHighMax + 1, -0.5f, static_cast(MotherPdgHighMax) + 0.5f}, {MotherPdgChunkBase, -0.5f, static_cast(MotherPdgChunkBase) - 0.5f}}}}, + {"fraction/hDcaMotherPdgNu", "Nucleus DCA by exact direct-mother PDG; signed physical reconstructed p_{T} (GeV/c);DCA_{xy} (cm);DCA_{z} (cm);centrality;origin;collision association;mother PDG sign;mother PDG high;mother PDG low", {HistType::kTHnSparseF, {{280, -7.f, 7.f}, {NucleusDcaFitBins, -NucleusDcaFitAxisMax, NucleusDcaFitAxisMax}, {NucleusDcaFitBins, -NucleusDcaFitAxisMax, NucleusDcaFitAxisMax}, {40, 0.f, 100.f}, {NDcaOrigins, -0.5f, static_cast(NDcaOrigins) - 0.5f}, {NCollisionAssociations, -0.5f, static_cast(NCollisionAssociations) - 0.5f}, {3, -1.5f, 1.5f}, {MotherPdgHighMax + 1, -0.5f, static_cast(MotherPdgHighMax) + 0.5f}, {MotherPdgChunkBase, -0.5f, static_cast(MotherPdgChunkBase) - 0.5f}}}}, + + // Hierarchical MC truth purity counters: all = correct species + mis-ID + // + no label; correct species = correct collision + wrong collision; + // correct collision = primary + weak + material. + {"purityMC/hHadron", "Selected pion truth composition;signed reconstructed p_{T} (GeV/c);category;centrality", {HistType::kTH3F, {{280, -7.f, 7.f}, {NPurityCategories, -0.5f, static_cast(NPurityCategories) - 0.5f}, {40, 0.f, 100.f}}}}, + {"purityMC/hNucleus", "Selected nucleus truth composition;signed physical reconstructed p_{T} (GeV/c);category;centrality", {HistType::kTH3F, {{280, -7.f, 7.f}, {NPurityCategories, -0.5f, static_cast(NPurityCategories) - 0.5f}, {40, 0.f, 100.f}}}}, + // dE/dx {"h2dEdxNucandidates", "dEdx distribution; #it{p} (GeV/#it{c}); dE/dx (a.u.)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {100, 0.0f, 2000.0f}}}}, {"h2dEdxHadcandidates", "dEdx distribution; #it{p} (GeV/#it{c}); dE/dx (a.u.)", {HistType::kTH2F, {{200, -5.0f, 5.0f}, {100, 0.0f, 2000.0f}}}}, @@ -535,6 +788,16 @@ struct HadNucleiFemto { void init(o2::framework::InitContext&) { + const bool processHyperPairs = doprocessHyper || doprocessMCHyper; + if (processHyperPairs && hadHyper.maxOutputKstar.value == 0.f) { + LOG(fatal) << "Hadron-hypertriton mode requires a nonzero output k* range"; + } + if (processHyperPairs && hadHyper.enableMixing.value && eventMixing.settingNoMixedEvents.value <= 0) { + LOG(fatal) << "Hadron-hypertriton mixed-event mode requires enabled mixing and positive mixing depth"; + } + if (processHyperPairs && hypertriton.settingHypMassMin.value >= hypertriton.settingHypMassMax.value) { + LOG(fatal) << "Hadron-hypertriton mode requires settingHypMassMin < settingHypMassMax"; + } constexpr int closePairRadiusModePv = 0; constexpr int closePairRadiusModeSpecificTpc = 2; if (CPR.settingEnableClosePairRejection.value) { @@ -591,6 +854,64 @@ struct HadNucleiFemto { for (size_t i = 0; i < mixedEventLabels.size(); i++) { mQaRegistry.get(HIST("hMixedEventSelections"))->GetXaxis()->SetBinLabel(i + 1, mixedEventLabels[i].c_str()); } + + const std::array originLabels = {"Primary", "WeakDecay", "Material"}; + const std::array collisionLabels = {"CorrectCollision", "WrongCollision"}; + const std::array parentLabels = {"NoSpecialParent", "Lambda", "Sigma", "K0Short", "K0Long", "ChargedKaon", "Hypertriton", "Lithium4", "OtherDecay", "MissingDecayMother"}; + const std::array purityLabels = {"AllSelected", "CorrectSpecies", "MisidentifiedSpecies", "NoMCLabel", "CorrectCollisionSpecies", "WrongCollisionSpecies", "CorrectPrimary", "CorrectWeakDecay", "CorrectMaterial"}; + + const auto baseDcaHad = mQaRegistry.get(HIST("fraction/hDcaTemplateHad")); + const auto baseDcaNu = mQaRegistry.get(HIST("fraction/hDcaTemplateNu")); + const std::array baseDcaHistograms = {baseDcaHad.get(), baseDcaNu.get()}; + for (const auto& histogram : baseDcaHistograms) { + for (int i = 0; i < NDcaOrigins; ++i) { + histogram->GetAxis(4)->SetBinLabel(i + 1, originLabels[i]); + } + } + const auto misidentifiedDcaHad = mQaRegistry.get(HIST("fraction/hDcaMisidentifiedHad")); + const auto misidentifiedDcaNu = mQaRegistry.get(HIST("fraction/hDcaMisidentifiedNu")); + const std::array misidentifiedDcaHistograms = {misidentifiedDcaHad.get(), misidentifiedDcaNu.get()}; + for (const auto& histogram : misidentifiedDcaHistograms) { + for (int i = 0; i < NCollisionAssociations; ++i) { + histogram->GetAxis(4)->SetBinLabel(i + 1, collisionLabels[i]); + } + } + const auto detailedDcaHad = mQaRegistry.get(HIST("fraction/hDcaTemplateDetailHad")); + const auto detailedDcaNu = mQaRegistry.get(HIST("fraction/hDcaTemplateDetailNu")); + const std::array detailedDcaHistograms = {detailedDcaHad.get(), detailedDcaNu.get()}; + for (const auto& histogram : detailedDcaHistograms) { + for (int i = 0; i < NDcaOrigins; ++i) { + histogram->GetAxis(4)->SetBinLabel(i + 1, originLabels[i]); + } + for (int i = 0; i < NCollisionAssociations; ++i) { + histogram->GetAxis(5)->SetBinLabel(i + 1, collisionLabels[i]); + } + for (int i = 0; i < NParentCategories; ++i) { + histogram->GetAxis(6)->SetBinLabel(i + 1, parentLabels[i]); + } + } + const auto motherPdgHad = mQaRegistry.get(HIST("fraction/hDcaMotherPdgHad")); + const auto motherPdgNu = mQaRegistry.get(HIST("fraction/hDcaMotherPdgNu")); + const std::array motherPdgHistograms = {motherPdgHad.get(), motherPdgNu.get()}; + for (const auto& histogram : motherPdgHistograms) { + for (int i = 0; i < NDcaOrigins; ++i) { + histogram->GetAxis(4)->SetBinLabel(i + 1, originLabels[i]); + } + for (int i = 0; i < NCollisionAssociations; ++i) { + histogram->GetAxis(5)->SetBinLabel(i + 1, collisionLabels[i]); + } + histogram->GetAxis(6)->SetBinLabel(1, "Negative"); + histogram->GetAxis(6)->SetBinLabel(2, "NoMother"); + histogram->GetAxis(6)->SetBinLabel(3, "Positive"); + } + const auto purityHad = mQaRegistry.get(HIST("purityMC/hHadron")); + const auto purityNu = mQaRegistry.get(HIST("purityMC/hNucleus")); + const std::array purityHistograms = {purityHad.get(), purityNu.get()}; + for (const auto& histogram : purityHistograms) { + for (int i = 0; i < NPurityCategories; ++i) { + histogram->GetYaxis()->SetBinLabel(i + 1, purityLabels[i]); + } + } } template @@ -911,6 +1232,60 @@ struct HadNucleiFemto { return false; } + // DCA-template inputs must retain the tails. These predicates reproduce the + // nominal track-quality selections while deliberately omitting only DCA. + template + bool selectPionTrackForDcaFit(const Ttrack& candidate) const + { + const float absPt = std::abs(candidate.pt()); + return std::abs(candidate.eta()) <= trackCut.settingCutEta.value && + absPt >= hadronPid.settingHadptMin.value && + absPt <= hadronPid.settingHadptMax.value && + candidate.itsNClsInnerBarrel() >= hadronPid.settingPionITSInnerBarrelMin.value && + candidate.itsNCls() >= hadronPid.settingPionITSNClsMin.value && + candidate.tpcNClsFound() >= hadronPid.settingPionTPCNClsFoundMin.value && + candidate.tpcNClsCrossedRows() >= hadronPid.settingPionTPCCrossedRowsMin.value; + } + + template + bool selectTritonTrackForDcaFit(const Ttrack& candidate) const + { + constexpr float maxAbsEta = 0.8f; + constexpr int minTPCCrossedRows = 70; + constexpr float maxTPCChi2NCl = 5.f; + constexpr float maxTPCFractionSharedCls = 0.3f; + constexpr int minITSNCls = 5; + constexpr float maxITSChi2NCl = 10.f; + return std::abs(candidate.eta()) < maxAbsEta && + candidate.tpcNClsCrossedRows() >= minTPCCrossedRows && + candidate.tpcChi2NCl() < maxTPCChi2NCl && + candidate.tpcFractionSharedCls() < maxTPCFractionSharedCls && + candidate.itsNCls() >= minITSNCls && + candidate.itsChi2NCl() < maxITSChi2NCl; + } + + template + bool selectHadronTrackForDcaFit(const Ttrack& candidate) + { + if (species.settingHadPDGCode.value == static_cast(PDG_t::kPiPlus)) { + return selectPionTrackForDcaFit(candidate); + } + // The fraction feature is intended for pion-nucleus configurations. Keep + // the nominal selection for other supported hadrons instead of silently + // changing their established cuts. + return selectTrackHadron(candidate); + } + + template + bool selectNucleusTrackForDcaFit(const Ttrack& candidate) + { + if (useTritonNucleus()) { + return selectTritonTrackForDcaFit(candidate); + } + // The deuteron and helium-3 track-quality predicates contain no DCA cut. + return selectTrackNu(candidate); + } + void fillNucleusTrackSelection(const Selections selection) { mQaRegistry.fill(HIST("hTrackSelNu"), selection); @@ -1039,6 +1414,12 @@ struct HadNucleiFemto { if (fillQA) { mQaRegistry.fill(HIST("h2CPRBefore"), deltaEta, deltaPhi); } + if (!CPR.settingApplyClosePairRejection.value) { + if (fillQA) { + mQaRegistry.fill(HIST("h2CPRAfter"), deltaEta, deltaPhi); + } + return false; + } const bool isRejected = std::pow(deltaPhi, 2.f) / std::pow(CPR.settingClosePairDeltaPhiMax.value, 2.f) + std::pow(deltaEta, 2.f) / std::pow(CPR.settingClosePairDeltaEtaMax.value, 2.f) < 1.f; @@ -1048,6 +1429,33 @@ struct HadNucleiFemto { return isRejected; } + bool isCloseHadHyperPairAtPV(const HadHyperCandidate& candidate, const HadHyperHadron& hadron, bool fillQA) + { + if (!CPR.settingEnableClosePairRejection.value) { + return false; + } + constexpr int closePairRadiusModePv = 0; + if (CPR.settingClosePairRadiusMode.value != closePairRadiusModePv) { + return false; + } + if (candidate.sign() != hadron.sign()) { + return false; + } + + const float deltaEta = candidate.eta() - hadron.eta(); + const float deltaPhi = wrapDeltaPhi(candidate.phi() - hadron.phi()); + if (fillQA) { + hadHyperRegistry.fill(HIST("hClosePairBeforePV"), deltaEta, deltaPhi); + } + const bool isRejected = std::pow(deltaPhi, 2.f) / std::pow(CPR.settingClosePairDeltaPhiMax.value, 2.f) + + std::pow(deltaEta, 2.f) / std::pow(CPR.settingClosePairDeltaEtaMax.value, 2.f) < + 1.f; + if (fillQA && !isRejected) { + hadHyperRegistry.fill(HIST("hClosePairAfterPV"), deltaEta, deltaPhi); + } + return isRejected; + } + template bool selectionPIDProton(const Ttrack& candidate) { @@ -1448,6 +1856,128 @@ struct HadNucleiFemto { return false; } + template + bool selectionPIDDeForDcaFit(const Ttrack& candidate) + { + const float absPt = std::abs(candidate.pt()); + const float absTPCInnerParam = std::abs(candidate.tpcInnerParam()); + if (absTPCInnerParam < deuteronPid.settingCutPinMinDe.value || + absPt < deuteronPid.settingCutDeptMin.value || + absPt > deuteronPid.settingCutDeptMax.value) { + return false; + } + + const float tpcNSigmaDe = output.settingUseBBcomputeDeNsigma.value ? computeNSigmaDe(candidate) : candidate.tpcNSigmaDe(); + if (absTPCInnerParam > deuteronPid.settingCutPinMinTOFITSDe.value) { + if (!candidate.hasTOF()) { + return false; + } + const float tofNSigmaDe = candidate.tofNSigmaDe(); + const float combinedNSigma = std::hypot(tpcNSigmaDe, tofNSigmaDe); + if (combinedNSigma > deuteronPid.settingCutNsigmaTOFTPCDe.value) { + return false; + } + return !deuteronPid.settingReqSingleNsig.value || + (std::abs(tpcNSigmaDe) <= deuteronPid.settingCutNsigmaTOFTPCDe.value && + std::abs(tofNSigmaDe) <= deuteronPid.settingCutNsigmaTOFTPCDe.value); + } + + if (std::abs(tpcNSigmaDe) > deuteronPid.settingCutNsigmaTPCDe.value) { + return false; + } + o2::aod::ITSResponse itsResponse; + const float itsNSigmaDe = itsResponse.nSigmaITS(candidate.itsClusterSizes(), candidate.p(), candidate.eta()); + return std::abs(itsNSigmaDe) <= deuteronPid.settingCutNsigmaITSDe.value; + } + + template + bool selectionPIDNuForDcaFit(const Ttrack& candidate) + { + if (useDeuteronNucleus()) { + return selectionPIDDeForDcaFit(candidate); + } + // The helium-3 and triton PID predicates do not contain DCA selections. + return selectionPIDNu(candidate); + } + + template + float signedPhysicalPt(const Ttrack& track, bool isNucleus) const + { + const float chargeFactor = isNucleus ? nucleusChargeFactor() : 1.f; + return track.sign() * chargeFactor * std::abs(track.pt()); + } + + template + int classifyDcaOrigin(const Tparticle& particle) const + { + if (particle.isPhysicalPrimary()) { + return Primary; + } + if (particle.getProcess() == TMCProcess::kPDecay) { + return WeakDecay; + } + // Following the DCA-template convention used by Giorgio: after excluding + // physical primaries and decay daughters, every remaining transport + // process is treated as a secondary produced in detector material. + return Material; + } + + int purityOriginCategory(int origin) const + { + switch (origin) { + case Primary: + return CorrectPrimary; + case WeakDecay: + return CorrectWeakDecay; + case Material: + return CorrectMaterial; + default: + // classifyDcaOrigin deliberately has only the three Giorgio classes. + return CorrectMaterial; + } + } + + template + int classifyParentCategory(const Tparticle& particle, int origin) const + { + if (!particle.has_mothers()) { + return origin == WeakDecay ? MissingDecayParent : NoSpecialParent; + } + + const int fallbackCategory = origin == WeakDecay ? OtherDecayParent : NoSpecialParent; + for (const auto& mother : particle.template mothers_as()) { + const int motherPdg = std::abs(mother.pdgCode()); + + // Keep the nuclear feed-down parents identifiable for all origin labels. + if (motherPdg == HyperTritonPDG) { + return HypertritonParent; + } + if (motherPdg == Lithium4PDG) { + return Lithium4Parent; + } + + if (origin != WeakDecay) { + continue; + } + if (motherPdg == PDG_t::kLambda0) { + return LambdaParent; + } + if (motherPdg == PDG_t::kSigmaMinus || motherPdg == PDG_t::kSigma0 || motherPdg == PDG_t::kSigmaPlus) { + return SigmaParent; + } + if (motherPdg == PDG_t::kK0Short) { + return K0ShortParent; + } + if (motherPdg == PDG_t::kK0Long) { + return K0LongParent; + } + if (motherPdg == PDG_t::kKPlus) { + return ChargedKaonParent; + } + } + return fallbackCategory; + } + template float getNucleusTPCNSigma(const Ttrack& candidate) { @@ -1491,37 +2021,32 @@ struct HadNucleiFemto { return -10.f; } - float averageClusterSizeCosl(uint32_t itsClusterSizes, float eta) + template + float computeHyperCandidateMass(const Tcandidate& candidate) const { - float average = 0; - int nclusters = 0; - const float cosl = 1. / std::cosh(eta); - const int nlayerITS = 7; - - for (int layer = 0; layer < nlayerITS; layer++) { - if (((itsClusterSizes >> (layer * 4)) & 0xf) != 0u) { - nclusters++; - average += (itsClusterSizes >> (layer * 4)) & 0xf; - } - } - if (nclusters == 0) { - return 0; - } - return average * cosl / nclusters; - }; + const std::array heMomentum{ + candidate.ptHe3() * std::cos(candidate.phiHe3()), + candidate.ptHe3() * std::sin(candidate.phiHe3()), + candidate.ptHe3() * std::sinh(candidate.etaHe3())}; + const std::array pionMomentum{ + candidate.ptPi() * std::cos(candidate.phiPi()), + candidate.ptPi() * std::sin(candidate.phiPi()), + candidate.ptPi() * std::sinh(candidate.etaPi())}; + return RecoDecay::m(std::array{heMomentum, pionMomentum}, + std::array{static_cast(o2::constants::physics::MassHelium3), + static_cast(o2::constants::physics::MassPiPlus)}); + } - bool selectionPIDHyper(const aod::DataHypCandsWColl::iterator& V0Hyper) + template + bool selectHyperCandidate(const Tcandidate& candidate) { - mQaRegistry.fill(HIST("hHe3P_preselected"), V0Hyper.tpcMomHe()); - float averClusSizeHe = averageClusterSizeCosl(V0Hyper.itsClusterSizesHe(), V0Hyper.etaHe3()); - if (averClusSizeHe <= hypertriton.settingCutAverClsSizeHe) { + mQaRegistry.fill(HIST("hHe3P_preselected"), candidate.tpcMomHe()); + const float mass = computeHyperCandidateMass(candidate); + if (!std::isfinite(mass) || mass < hypertriton.settingHypMassMin || mass > hypertriton.settingHypMassMax) { return false; } - if (V0Hyper.tpcChi2He() <= hypertriton.settingCutTPCChi2He) { - return false; - } - mQaRegistry.fill(HIST("hHe3P"), V0Hyper.tpcMomHe()); - mQaRegistry.fill(HIST("hHe3TPCnsigma"), V0Hyper.ptHe3(), V0Hyper.nSigmaHe()); + mQaRegistry.fill(HIST("hHe3P"), candidate.tpcMomHe()); + mQaRegistry.fill(HIST("hHe3TPCnsigma"), candidate.ptHe3(), candidate.nSigmaHe()); return true; } @@ -1635,7 +2160,12 @@ struct HadNucleiFemto { hadNucand.nTPCClustersHad = trackHad.tpcNClsFound(); hadNucand.nTPCCrossedRowsNu = trackDe.tpcNClsCrossedRows(); hadNucand.nTPCCrossedRowsHad = trackHad.tpcNClsCrossedRows(); + hadNucand.nTPCFindableNu = trackDe.tpcNClsFindable(); + hadNucand.nTPCFindableHad = trackHad.tpcNClsFindable(); hadNucand.nSigmaNu = getNucleusTPCNSigma(trackDe); + hadNucand.nSigmaTPCNuDe = trackDe.tpcNSigmaDe(); + hadNucand.nSigmaTPCNuPr = trackDe.tpcNSigmaPr(); + hadNucand.nSigmaTPCNuPi = trackDe.tpcNSigmaPi(); hadNucand.nSigmaHad = getHadronTPCNSigma(trackHad); hadNucand.nSigmaTOFNu = getNucleusTOFNSigma(trackDe); hadNucand.nSigmaITSNu = getNucleusITSNSigma(trackDe); @@ -1650,6 +2180,8 @@ struct HadNucleiFemto { hadNucand.chi2TPCNu = trackDe.tpcChi2NCl(); hadNucand.chi2TPCHad = trackHad.tpcChi2NCl(); + hadNucand.chi2ITSNu = trackDe.itsChi2NCl(); + hadNucand.chi2ITSHad = trackHad.itsChi2NCl(); hadNucand.pidTrkNu = trackDe.pidForTracking(); hadNucand.pidTrkHad = trackHad.pidForTracking(); @@ -1659,9 +2191,13 @@ struct HadNucleiFemto { hadNucand.nClsItsNu = trackDe.itsNCls(); hadNucand.nClsItsHad = trackHad.itsNCls(); + hadNucand.nClsItsInnerBarrelNu = trackDe.itsNClsInnerBarrel(); + hadNucand.nClsItsInnerBarrelHad = trackHad.itsNClsInnerBarrel(); hadNucand.sharedClustersNu = trackDe.tpcNClsShared(); hadNucand.sharedClustersHad = trackHad.tpcNClsShared(); + hadNucand.fractionSharedTPCNu = trackDe.tpcFractionSharedCls(); + hadNucand.fractionSharedTPCHad = trackHad.tpcFractionSharedCls(); hadNucand.isBkgUS = trackDe.sign() * trackHad.sign() < 0; hadNucand.isBkgEM = isMixedEvent; @@ -1670,6 +2206,8 @@ struct HadNucleiFemto { hadNucand.trackIDNu = trackDe.globalIndex(); hadNucand.trackIDHad = trackHad.globalIndex(); + hadNucand.collisionIDNu = trackDe.collisionId(); + hadNucand.collisionIDHad = trackHad.collisionId(); if (trackDe.hasTOF()) { float beta = o2::pid::tof::Beta::GetBeta(trackDe); @@ -1692,71 +2230,6 @@ struct HadNucleiFemto { return true; } - template - void fillCandidateInfoHyper(const aod::DataHypCandsWColl::iterator& V0Hyper, const Ttrack& trackHad, HadNucandidate& hadHypercand, bool isMixedEvent) - { - hadHypercand.collisionID = V0Hyper.collisionId(); - // get hypertriton information - // constexpr double mHe3 = o2::constants::physics::MassHelium3; - // constexpr double mPi = o2::constants::physics::MassPiPlus; - // --- He3 - float pxHe3 = V0Hyper.ptHe3() * std::cos(V0Hyper.phiHe3()); - float pyHe3 = V0Hyper.ptHe3() * std::sin(V0Hyper.phiHe3()); - float pzHe3 = V0Hyper.ptHe3() * std::sinh(V0Hyper.etaHe3()); - // float pHe3 = V0Hyper.ptHe3() * std::cosh(V0Hyper.etaHe3()); - // float enHe3 = std::sqrt(pHe3 * pHe3 + mHe3 * mHe3); - // --- pi - float pxPi = V0Hyper.ptPi() * std::cos(V0Hyper.phiPi()); - float pyPi = V0Hyper.ptPi() * std::sin(V0Hyper.phiPi()); - float pzPi = V0Hyper.ptPi() * std::sinh(V0Hyper.etaPi()); - // float pPi = V0Hyper.ptPi() * std::cosh(V0Hyper.etaPi()); - // float enPi = std::sqrt(pPi * pPi + mPi * mPi); - // --- hypertriton - float px = pxHe3 + pxPi; - float py = pyHe3 + pyPi; - float pz = pzHe3 + pzPi; - hadHypercand.momNu = std::array{px, py, pz}; - hadHypercand.momHad = std::array{trackHad.px(), trackHad.py(), trackHad.pz()}; - - float invMass = 0; - invMass = RecoDecay::m(std::array, 2>{hadHypercand.momNu, hadHypercand.momHad}, std::array{static_cast(o2::constants::physics::MassHelium3), mMassHad}); - - hadHypercand.signHad = trackHad.sign(); - if (V0Hyper.isMatter()) { - hadHypercand.signNu = 1; - } else { - hadHypercand.signNu = -1; - } - hadHypercand.etaHe3 = V0Hyper.etaHe3(); - hadHypercand.ptHe3 = V0Hyper.ptHe3(); - hadHypercand.dcaxyHad = trackHad.dcaXY(); - hadHypercand.dcazHad = trackHad.dcaZ(); - hadHypercand.tpcSignalHad = trackHad.tpcSignal(); - hadHypercand.tpcSignalNu = V0Hyper.tpcSignalHe(); - hadHypercand.momHadTPC = trackHad.tpcInnerParam(); - hadHypercand.nSigmaHad = getHadronTPCNSigma(trackHad); - hadHypercand.nSigmaNu = V0Hyper.nSigmaHe(); - hadHypercand.chi2TPCHad = trackHad.tpcChi2NCl(); - hadHypercand.chi2TPCNu = V0Hyper.tpcChi2He(); - hadHypercand.pidTrkHad = trackHad.pidForTracking(); - hadHypercand.itsClSizeHad = trackHad.itsClusterSizes(); - hadHypercand.itsClSizeNu = V0Hyper.itsClusterSizesHe(); - hadHypercand.nClsItsHad = trackHad.itsNCls(); - hadHypercand.sharedClustersHad = trackHad.tpcNClsShared(); - - hadHypercand.isBkgUS = hadHypercand.signNu * trackHad.sign() < 0; - hadHypercand.isBkgEM = isMixedEvent; - hadHypercand.invMass = invMass; - - hadHypercand.trackIDHad = trackHad.globalIndex(); - - if (trackHad.hasTOF()) { - float beta = o2::pid::tof::Beta::GetBeta(trackHad); - beta = std::min(1.f - 1.e-6f, std::max(1.e-4f, beta)); /// sometimes beta > 1 or < 0, to be checked - hadHypercand.massTOFHad = trackHad.tpcInnerParam() * std::sqrt(1.f / (beta * beta) - 1.f); - } - } - template void pairTracksSameEvent(const Ttrack& tracks, float /*cent*/) { @@ -1825,40 +2298,8 @@ struct HadNucleiFemto { } } - template - void pairTracksSameEventHyper(const Ttrack& hadTracks, const Thypers& V0Hypers) - { - for (const auto& V0Hyper : V0Hypers) { - if (!selectionPIDHyper(V0Hyper)) { - continue; - } - for (const auto& hadTrack : hadTracks) { - - mQaRegistry.fill(HIST("hTrackSel"), Selections::kNoCuts); - - if (!selectTrackHadron(hadTrack)) { - continue; - } - mQaRegistry.fill(HIST("hTrackSel"), Selections::kTrackCuts); - - if (!selectionPIDHadron(hadTrack)) { - continue; - } - mQaRegistry.fill(HIST("hTrackSel"), Selections::kPID); - - SVCand pair; - pair.tr0Idx = V0Hyper.globalIndex(); - pair.tr1Idx = hadTrack.globalIndex(); - const int collIdx = V0Hyper.collisionId(); - CollBracket collBracket{collIdx, collIdx}; - pair.collBracket = collBracket; - mTrackHypPairs.push_back(pair); - } - } - } - template - BufferedTrack makeBufferedTrack(const Ttrack& track, bool isNucleus) + BufferedTrack makeBufferedTrack(const Ttrack& track, bool isNucleus, int64_t collisionId) { BufferedTrack bufferedTrack; bufferedTrack.momentum = {track.px(), track.py(), track.pz()}; @@ -1872,15 +2313,23 @@ struct HadNucleiFemto { bufferedTrack.tpcInnerParam = isNucleus && useHelium3Nucleus() ? correctedTPCInnerParamHe3(track) : track.tpcInnerParam(); bufferedTrack.tpcNClsFound = track.tpcNClsFound(); bufferedTrack.tpcNClsCrossedRows = track.tpcNClsCrossedRows(); + bufferedTrack.tpcNClsFindable = track.tpcNClsFindable(); bufferedTrack.tpcNClsShared = track.tpcNClsShared(); + bufferedTrack.tpcFractionSharedCls = track.tpcFractionSharedCls(); bufferedTrack.itsNCls = track.itsNCls(); + bufferedTrack.itsNClsInnerBarrel = track.itsNClsInnerBarrel(); bufferedTrack.tpcChi2NCl = track.tpcChi2NCl(); + bufferedTrack.itsChi2NCl = track.itsChi2NCl(); bufferedTrack.pidForTracking = track.pidForTracking(); bufferedTrack.itsClusterSizes = track.itsClusterSizes(); bufferedTrack.trackId = track.globalIndex(); + bufferedTrack.collisionId = collisionId; if (isNucleus) { bufferedTrack.nSigmaTPC = getNucleusTPCNSigma(track); + bufferedTrack.nSigmaTPCDe = track.tpcNSigmaDe(); + bufferedTrack.nSigmaTPCPr = track.tpcNSigmaPr(); + bufferedTrack.nSigmaTPCPi = track.tpcNSigmaPi(); bufferedTrack.nSigmaTOF = getNucleusTOFNSigma(track); bufferedTrack.nSigmaITS = getNucleusITSNSigma(track); } else { @@ -1944,13 +2393,24 @@ struct HadNucleiFemto { hadNucand.nTPCClustersHad = hadron.tpcNClsFound; hadNucand.nTPCCrossedRowsNu = nucleus.tpcNClsCrossedRows; hadNucand.nTPCCrossedRowsHad = hadron.tpcNClsCrossedRows; + hadNucand.nTPCFindableNu = nucleus.tpcNClsFindable; + hadNucand.nTPCFindableHad = hadron.tpcNClsFindable; hadNucand.sharedClustersNu = nucleus.tpcNClsShared; hadNucand.sharedClustersHad = hadron.tpcNClsShared; + hadNucand.fractionSharedTPCNu = nucleus.tpcFractionSharedCls; + hadNucand.fractionSharedTPCHad = hadron.tpcFractionSharedCls; hadNucand.nClsItsNu = nucleus.itsNCls; hadNucand.nClsItsHad = hadron.itsNCls; + hadNucand.nClsItsInnerBarrelNu = nucleus.itsNClsInnerBarrel; + hadNucand.nClsItsInnerBarrelHad = hadron.itsNClsInnerBarrel; hadNucand.chi2TPCNu = nucleus.tpcChi2NCl; hadNucand.chi2TPCHad = hadron.tpcChi2NCl; + hadNucand.chi2ITSNu = nucleus.itsChi2NCl; + hadNucand.chi2ITSHad = hadron.itsChi2NCl; hadNucand.nSigmaNu = nucleus.nSigmaTPC; + hadNucand.nSigmaTPCNuDe = nucleus.nSigmaTPCDe; + hadNucand.nSigmaTPCNuPr = nucleus.nSigmaTPCPr; + hadNucand.nSigmaTPCNuPi = nucleus.nSigmaTPCPi; hadNucand.nSigmaHad = hadron.nSigmaTPC; hadNucand.nSigmaTOFNu = nucleus.nSigmaTOF; hadNucand.nSigmaITSNu = nucleus.nSigmaITS; @@ -1968,8 +2428,10 @@ struct HadNucleiFemto { hadNucand.pidTrkHad = hadron.pidForTracking; hadNucand.itsClSizeNu = nucleus.itsClusterSizes; hadNucand.itsClSizeHad = hadron.itsClusterSizes; - hadNucand.trackIDNu = static_cast(nucleus.trackId); - hadNucand.trackIDHad = static_cast(hadron.trackId); + hadNucand.trackIDNu = nucleus.trackId; + hadNucand.trackIDHad = hadron.trackId; + hadNucand.collisionIDNu = nucleus.collisionId; + hadNucand.collisionIDHad = hadron.collisionId; hadNucand.isBkgUS = nucleus.sign() * hadron.sign() < 0; hadNucand.isBkgEM = true; @@ -2026,7 +2488,26 @@ struct HadNucleiFemto { hadNucand.nSigmaTOFNu, hadNucand.nSigmaITSNu, hadNucand.nSigmaTOFHad, - hadNucand.nSigmaITSHad); + hadNucand.nSigmaITSHad, + mRunNumber, + mDbz, + hadNucand.trackIDNu, + hadNucand.trackIDHad, + hadNucand.collisionIDNu, + hadNucand.collisionIDHad, + hadNucand.nTPCFindableNu, + hadNucand.nTPCFindableHad, + hadNucand.fractionSharedTPCNu, + hadNucand.fractionSharedTPCHad, + hadNucand.nClsItsNu, + hadNucand.nClsItsHad, + hadNucand.nClsItsInnerBarrelNu, + hadNucand.nClsItsInnerBarrelHad, + hadNucand.chi2ITSNu, + hadNucand.chi2ITSHad, + hadNucand.nSigmaTPCNuDe, + hadNucand.nSigmaTPCNuPr, + hadNucand.nSigmaTPCNuPi); } template @@ -2085,45 +2566,6 @@ struct HadNucleiFemto { mQaRegistry.fill(HIST("MC/hPtHadRecVsGen"), signedPtHadMC, hadNucand.recoPtHad()); } - template - void fillTableHyper(const HadNucandidate& hadNucand, const Tcoll& collision) - { - mOutputHyperDataTable( - hadNucand.recoPtNu(), - hadNucand.recoEtaNu(), - hadNucand.ptHe3, - hadNucand.etaHe3, - hadNucand.recoPhiNu(), - hadNucand.recoPtHad(), - hadNucand.recoEtaHad(), - hadNucand.recoPhiHad(), - hadNucand.dcaxyHad, - hadNucand.dcazHad, - hadNucand.tpcSignalHad, - hadNucand.tpcSignalNu, - hadNucand.momHadTPC, - hadNucand.nSigmaHad, - hadNucand.nSigmaNu, - hadNucand.chi2TPCHad, - hadNucand.chi2TPCNu, - hadNucand.massTOFHad, - hadNucand.pidTrkHad, - hadNucand.itsClSizeHad, - hadNucand.itsClSizeNu, - hadNucand.sharedClustersHad, - hadNucand.trackIDHad, - hadNucand.isBkgUS, - hadNucand.isBkgEM); - if (output.settingFillMultiplicity) { - mOutputMultiplicityTable( - collision.globalIndex(), - collision.posZ(), - collision.numContrib(), - collision.centFT0C(), - collision.multFT0C()); - } - } - void fillHistograms(const HadNucandidate& hadNucand) { mQaRegistry.fill(HIST("hNuPt"), hadNucand.recoPtNu()); @@ -2217,33 +2659,449 @@ struct HadNucleiFemto { } } - template - void fillPairsHyper(const Tcollisions& collisions, const Ttracks& hadTracks, const o2::aod::DataHypCandsWColl& V0Hypers, const bool isMixedEvent) + template + HadHyperTrackInfo makeHadHyperTrackInfo(const Ttrack& track) { - for (const auto& trackPair : mTrackHypPairs) { + constexpr float InvalidPID = -999.f; + return {track.pt(), track.eta(), track.phi(), static_cast(track.sign()), + track.dcaXY(), track.tpcNClsCrossedRows(), track.tpcNClsPID(), track.tpcChi2NCl(), + track.itsClusterSizes(), track.itsChi2NCl(), track.hasTOF(), + track.tpcNSigmaPi(), track.tpcNSigmaKa(), track.tpcNSigmaPr(), + track.hasTOF() ? track.tofNSigmaPi() : InvalidPID, + track.hasTOF() ? track.tofNSigmaKa() : InvalidPID, + track.hasTOF() ? track.tofNSigmaPr() : InvalidPID}; + } - auto v0hyper = V0Hypers.rawIteratorAt(trackPair.tr0Idx); - auto hadTrack = hadTracks.rawIteratorAt(trackPair.tr1Idx); - // auto collBracket = trackPair.collBracket; + template + HadHyperEventInfo makeHadHyperEventInfo(const Tcollision& collision) + { + const auto bc = collision.template bc_as(); + return {bc.runNumber(), collision.posZ(), collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), + collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange(), + static_cast(collision.numContrib()), collision.multFT0C(), + collision.posX(), collision.posY(), collision.posZ()}; + } - HadNucandidate hadNucand; - fillCandidateInfoHyper(v0hyper, hadTrack, hadNucand, isMixedEvent); - - mQaRegistry.fill(HIST("hNuPt"), hadNucand.recoPtNu()); - mQaRegistry.fill(HIST("hHadPt"), hadNucand.recoPtHad()); - mQaRegistry.fill(HIST("hNuEta"), hadNucand.recoEtaNu()); - mQaRegistry.fill(HIST("hHadEta"), hadNucand.recoEtaHad()); - mQaRegistry.fill(HIST("hNuPhi"), hadNucand.recoPhiNu()); - mQaRegistry.fill(HIST("hHadPhi"), hadNucand.recoPhiHad()); - mQaRegistry.fill(HIST("hNuHadtInvMass"), hadNucand.invMass); - mQaRegistry.fill(HIST("hNClsHadITS"), hadNucand.nClsItsHad); - mQaRegistry.fill(HIST("hisBkgEM"), hadNucand.isBkgEM); + template + HadHyperParticleTruth makeHadHyperParticleTruth(const Tparticle& particle) + { + return {particle.globalIndex(), particle.mcCollisionId(), particle.pdgCode(), particle.pt(), particle.eta(), particle.phi(), particle.isPhysicalPrimary(), static_cast(particle.statusCode()), static_cast(particle.getProcess()), {particle.px(), particle.py(), particle.pz()}}; + } - auto collision = collisions.rawIteratorAt(hadNucand.collisionID); + template + HadHyperHadron makeHadHyperHadron(const Ttrack& track) + { + HadHyperHadron hadron{makeHadHyperTrackInfo(track), {}, {}, track.globalIndex(), {track.px(), track.py(), track.pz()}, track.tpcInnerParam(), track.tpcSignal(), track.eta(), track.phi(), static_cast(track.sign())}; + if constexpr (isMC) { + if (track.has_mcParticle()) { + const auto particle = track.template mcParticle_as(); + hadron.truth = makeHadHyperParticleTruth(particle); + if (particle.has_mothers()) { + for (const auto& mother : particle.template mothers_as()) { + hadron.motherIds.push_back(mother.globalIndex()); + } + } + } + } + return hadron; + } + + template + HadHyperCandidate makeHadHyperCandidate(const Tcandidate& candidate, const Ttracks& tracks) + { + const auto he = tracks.rawIteratorAt(candidate.heTrackId() - tracks.offset()); + const auto pion = tracks.rawIteratorAt(candidate.piTrackId() - tracks.offset()); + const std::array heMomentum{ + candidate.ptHe3() * std::cos(candidate.phiHe3()), + candidate.ptHe3() * std::sin(candidate.phiHe3()), + candidate.ptHe3() * std::sinh(candidate.etaHe3())}; + const std::array pionMomentum{ + candidate.ptPi() * std::cos(candidate.phiPi()), + candidate.ptPi() * std::sin(candidate.phiPi()), + candidate.ptPi() * std::sinh(candidate.etaPi())}; + HadHyperCandidate result; + for (size_t i = 0; i < result.momentum.size(); ++i) { + result.momentum[i] = heMomentum[i] + pionMomentum[i]; + } + result.mass = computeHyperCandidateMass(candidate); + result.heTrackId = candidate.heTrackId(); + result.pionTrackId = candidate.piTrackId(); + result.sourceCandidateId = candidate.globalIndex(); + result.etaHe = candidate.etaHe3(); + result.phiHe = candidate.phiHe3(); + result.etaPi = candidate.etaPi(); + result.phiPi = candidate.phiPi(); + result.isMatter = candidate.isMatter(); + if constexpr (isMC) { + if (he.has_mcParticle()) { + result.heTruth = makeHadHyperParticleTruth(he.template mcParticle_as()); + } + if (pion.has_mcParticle()) { + result.decayPionTruth = makeHadHyperParticleTruth(pion.template mcParticle_as()); + } + if (he.has_mcParticle() && pion.has_mcParticle()) { + const auto heParticle = he.template mcParticle_as(); + const auto pionParticle = pion.template mcParticle_as(); + if (heParticle.has_mothers() && pionParticle.has_mothers()) { + for (const auto& heMother : heParticle.template mothers_as()) { + for (const auto& pionMother : pionParticle.template mothers_as()) { + if (heMother.globalIndex() == pionMother.globalIndex() && + std::abs(heMother.pdgCode()) == HyperTritonPDG) { + result.hyperTruth = makeHadHyperParticleTruth(heMother); + } + } + } + } + } + } + result.info = {candidate.isMatter(), + candidate.ptHe3(), candidate.etaHe3(), candidate.phiHe3(), + candidate.ptPi(), candidate.etaPi(), candidate.phiPi(), + candidate.dcaV0Daug(), candidate.dcaHe(), candidate.dcaPi(), + candidate.nSigmaHe(), candidate.tofMass(), + candidate.nTPCCrossedRowsHe(), candidate.nTPCCrossedRowsPi(), + candidate.tpcMomHe(), candidate.tpcMomPi(), + candidate.tpcSignalHe(), candidate.tpcSignalPi(), + candidate.tpcChi2He(), candidate.itsChi2He(), candidate.itsChi2Pi(), + candidate.itsClusterSizesHe(), candidate.itsClusterSizesPi(), + candidate.xDecVtx(), candidate.yDecVtx(), candidate.zDecVtx()}; + if constexpr (isMC) { + result.statusCode = static_cast(candidate.statusCode()); + result.isReco = candidate.isReco(); + result.isSignal = candidate.isSignal(); + result.isRecoMCCollision = candidate.isRecoMCCollision(); + result.isSurvEvSel = candidate.isSurvEvSel(); + result.isTwoBodyDecay = candidate.isTwoBodyDecay(); + result.isFakeHeOnITSLayer = candidate.isFakeHeOnITSLayer(); + result.genPt = candidate.genPt(); + result.genEta = candidate.genEta(); + result.genPhi = candidate.genPhi(); + result.genPtHe3 = candidate.genPtHe3(); + result.genDecVtx = {candidate.genXDecVtx(), candidate.genYDecVtx(), candidate.genZDecVtx()}; + const float absGenPt = std::abs(candidate.genPt()); + result.genMomentum = {absGenPt * std::cos(candidate.genPhi()), + absGenPt * std::sin(candidate.genPhi()), + absGenPt * std::sinh(candidate.genEta())}; + } + hadHyperRegistry.fill(HIST("hMass"), result.mass); + hadHyperRegistry.fill(HIST("hDaughterHeTPC"), he.tpcInnerParam(), he.tpcSignal()); + hadHyperRegistry.fill(HIST("hDaughterPiTPC"), pion.tpcInnerParam(), pion.tpcSignal()); + return result; + } + + HadHyperDataInfo makeHadHyperDataInfo(const HadHyperCandidate& candidate, const HadHyperHadron& hadron, + const HadHyperEvent& hyperEvent, const HadHyperEvent& hadronEvent, + bool mixed, int mixingDepth) + { + (void)hadronEvent; + return std::tuple_cat(std::make_tuple(mixed, mixingDepth), + hyperEvent.info, candidate.info, + hadron.info); + } + + bool hasTruthMother(const HadHyperHadron& hadron, int64_t motherId) const + { + return motherId >= 0 && std::find(hadron.motherIds.begin(), hadron.motherIds.end(), motherId) != hadron.motherIds.end(); + } + + bool isHadHyperTruthSelfCorrelation(const HadHyperCandidate& candidate, const HadHyperHadron& hadron) const + { + return hadron.truth.particleId >= 0 && + (hadron.truth.particleId == candidate.heTruth.particleId || + hadron.truth.particleId == candidate.decayPionTruth.particleId || + hasTruthMother(hadron, candidate.hyperTruth.particleId)); + } + + HadHyperMCInfo makeHadHyperMCInfo(const HadHyperCandidate& candidate, const HadHyperHadron& hadron, + const HadHyperEvent& hyperEvent, const HadHyperEvent& hadronEvent) const + { + const bool sameMCCollision = candidate.hyperTruth.collisionId >= 0 && + hadron.truth.collisionId == candidate.hyperTruth.collisionId; + const bool matchesHypRecoMCCollision = hyperEvent.hasMCCollision && + candidate.hyperTruth.collisionId == hyperEvent.mcCollisionId; + const bool matchesPairRecoMCCollision = hadronEvent.hasMCCollision && + hadron.truth.collisionId == hadronEvent.mcCollisionId; + const bool isTruthSelfCorrelation = isHadHyperTruthSelfCorrelation(candidate, hadron); + const bool isTruePrimaryHadHyperPair = candidate.isSignal && + std::abs(candidate.hyperTruth.pdgCode) == HyperTritonPDG && + std::abs(hadron.truth.pdgCode) == std::abs(species.settingHadPDGCode.value) && + hadron.truth.isPhysicalPrimary && sameMCCollision && !isTruthSelfCorrelation; + return {candidate.genPt, candidate.genEta, candidate.genPhi, + candidate.genDecVtx[0], candidate.genDecVtx[1], candidate.genDecVtx[2], + candidate.isReco, candidate.isSignal, + candidate.isRecoMCCollision, candidate.isSurvEvSel, candidate.isTwoBodyDecay, candidate.statusCode, + candidate.heTruth.pt, candidate.heTruth.isPhysicalPrimary, + candidate.decayPionTruth.isPhysicalPrimary, + std::get<0>(hadron.info), std::get<1>(hadron.info), std::get<2>(hadron.info), + hadron.truth.pt, hadron.truth.eta, hadron.truth.phi, hadron.truth.isPhysicalPrimary, + hadron.truth.process, + sameMCCollision, matchesHypRecoMCCollision, matchesPairRecoMCCollision, + isTruthSelfCorrelation, isTruePrimaryHadHyperPair}; + } + + void fillHadHyperMCQA(const HadHyperCandidate& candidate, const HadHyperHadron& hadron, + const HadHyperEvent& hyperEvent, float kstar) + { + if (!candidate.isReco || !candidate.isSignal || + std::abs(candidate.hyperTruth.pdgCode) != HyperTritonPDG) { + return; + } + + const bool isSelectedHadronSpecies = std::abs(hadron.truth.pdgCode) == std::abs(species.settingHadPDGCode.value); + if (!isSelectedHadronSpecies) { + return; + } - if (output.settingFillTable) { - fillTableHyper(hadNucand, collision); + const float kstarMC = computePairKstar(hadron.truth.momentum, configuredHadronMass(), + candidate.genMomentum, o2::constants::physics::MassHyperTriton); + if (std::isfinite(kstarMC)) { + hadHyperRegistry.fill(HIST("MC/hKstarRecVsGenHyperReco"), kstarMC, kstar); + hadHyperRegistry.fill(HIST("MC/hKstarResolutionHyperReco"), kstar, kstar - kstarMC); + } + + hadHyperRegistry.fill(HIST("MC/hPrimaryHadronVsKstarDen"), kstar); + hadHyperRegistry.fill(HIST("MC/hPrimaryHadronVsCentDen"), hyperEvent.centrality); + if (hadron.truth.isPhysicalPrimary) { + hadHyperRegistry.fill(HIST("MC/hPrimaryHadronVsKstarNum"), kstar); + hadHyperRegistry.fill(HIST("MC/hPrimaryHadronVsCentNum"), hyperEvent.centrality); + } + } + + template + bool fillHadHyperPair(const HadHyperCandidate& candidate, const HadHyperHadron& hadron, + const HadHyperEvent& hyperEvent, const HadHyperEvent& hadronEvent, + bool mixed, int mixingDepth) + { + const float kstar = computePairKstar(hadron.momentum, configuredHadronMass(), + candidate.momentum, o2::constants::physics::MassHyperTriton); + // All source indices here belong to the same timeframe. Also clean mixed + // pairs in case LF reassigned a daughter to a different collision. + if (hadron.sourceId == candidate.heTrackId || hadron.sourceId == candidate.pionTrackId) { + const int reason = hadron.sourceId == candidate.heTrackId ? 0 : 1; + hadHyperRegistry.fill(HIST("hSelfPairs"), reason, kstar); + if (!mixed) { + hadHyperRegistry.fill(HIST("hSameEventSelfPairs"), reason, kstar); + } + return false; + } + if constexpr (isMC) { + if (isHadHyperTruthSelfCorrelation(candidate, hadron)) { + hadHyperRegistry.fill(HIST("hSelfPairs"), 2, kstar); + if (!mixed) { + hadHyperRegistry.fill(HIST("hSameEventSelfPairs"), 2, kstar); + } + return false; + } + } + const bool unlikeSign = candidate.sign() * hadron.sign() < 0; + if (!eventMixing.settingSaveUSandLS && unlikeSign != eventMixing.settingEnableBkgUS.value) { + return false; + } + if (!std::isfinite(kstar)) { + return false; + } + if (isCloseHadHyperPairAtPV(candidate, hadron, /*fillQA*/ true)) { + return false; + } + if (mixed) { + hadHyperRegistry.fill(HIST("hME"), kstar); + } else { + hadHyperRegistry.fill(HIST("hSE"), kstar); + } + + if constexpr (isMC) { + fillHadHyperMCQA(candidate, hadron, hyperEvent, kstar); + } + + if (!output.settingFillTable || (hadHyper.maxOutputKstar.value > 0.f && kstar >= hadHyper.maxOutputKstar.value)) { + return true; + } + const auto dataInfo = makeHadHyperDataInfo(candidate, hadron, hyperEvent, hadronEvent, mixed, mixingDepth); + if constexpr (isMC) { + std::apply([this](const auto&... columns) { mOutputHadHyperMCTable(columns...); }, + std::tuple_cat(dataInfo, makeHadHyperMCInfo(candidate, hadron, hyperEvent, hadronEvent))); + } else { + std::apply([this](const auto&... columns) { mOutputHadHyperDataTable(columns...); }, dataInfo); + } + return true; + } + + template + bool hasValidHyperDaughterIndices(const Ttracks& tracks, int64_t heTrackId, int64_t pionTrackId) const + { + const auto first = static_cast(tracks.offset()); + const auto last = first + static_cast(tracks.size()); + return heTrackId >= first && heTrackId < last && pionTrackId >= first && pionTrackId < last; + } + + template + void collectHyperHadronTracks(HadHyperEvent& event, const Ttracks& eventTracks) + { + for (const auto& track : eventTracks) { + if (!selectTrackHadron(track) || !selectionPIDHadron(track)) { + continue; + } + event.hadrons.push_back(makeHadHyperHadron(track)); + hadHyperRegistry.fill(HIST("hHadronTPC"), track.tpcInnerParam(), track.tpcSignal()); + } + } + + template + void collectHyperCandidates(HadHyperEvent& event, const Tcandidates& eventCandidates, const Ttracks& tracks) + { + for (const auto& candidate : eventCandidates) { + if constexpr (isMC) { + if (!candidate.isReco()) { + continue; + } + } + if (!hasValidHyperDaughterIndices(tracks, candidate.heTrackId(), candidate.piTrackId())) { + if constexpr (isMC) { + continue; + } else { + LOG(fatal) << "Hypertriton daughter indices must reference the input Tracks table"; + } + } + if (!selectHyperCandidate(candidate)) { + continue; + } + event.candidates.push_back(makeHadHyperCandidate(candidate, tracks)); + } + } + + template + HadHyperEvent buildHyperEvent(const Tcollision& collision, const Ttracks& tracks, const Tcandidates& candidates) + { + HadHyperEvent event; + event.info = makeHadHyperEventInfo(collision); + event.centrality = collision.centFT0C(); + if constexpr (isMC) { + event.hasMCCollision = collision.has_mcCollision(); + event.mcCollisionId = collision.has_mcCollision() ? collision.mcCollisionId() : -1; + } + + if constexpr (isMC) { + const auto eventTracks = tracks.sliceBy(mPerColMC, collision.globalIndex()); + collectHyperHadronTracks(event, eventTracks); + + const auto eventCandidates = candidates.sliceBy(hypPerColMC, collision.globalIndex()); + collectHyperCandidates(event, eventCandidates, tracks); + } else { + const auto eventTracks = tracks.sliceBy(mPerCol, collision.globalIndex()); + collectHyperHadronTracks(event, eventTracks); + + const auto eventCandidates = candidates.sliceBy(hypPerCol, collision.globalIndex()); + collectHyperCandidates(event, eventCandidates, tracks); + } + + return event; + } + + template + void fillSameEventHyperPairs(const HadHyperEvent& event) + { + for (const auto& candidate : event.candidates) { + int acceptedPairs = 0; + for (const auto& hadron : event.hadrons) { + if (fillHadHyperPair(candidate, hadron, event, event, false, 0)) { + ++acceptedPairs; + } } + hadHyperRegistry.fill(HIST("hCandidatePairMultiplicitySE"), acceptedPairs, event.centrality); + } + } + + template + void fillMixedEventHyperPairs(const HadHyperEvent& currentEvent, const std::deque& pool) + { + const int depth = static_cast(pool.size()); + hadHyperRegistry.fill(HIST("hMixingDepth"), depth); + std::vector currentCandidatePairCounts(currentEvent.candidates.size(), 0); + for (const auto& partner : pool) { + const float currentPosZ = std::get<1>(currentEvent.info); + const float partnerPosZ = std::get<1>(partner.info); + hadHyperRegistry.fill(HIST("hMixEventDeltaPosZVsCent"), currentEvent.centrality, currentPosZ - partnerPosZ); + hadHyperRegistry.fill(HIST("hMixEventDeltaCentFT0CVsCent"), currentEvent.centrality, currentEvent.centrality - partner.centrality); + size_t candidateIndex = 0; + for (const auto& candidate : currentEvent.candidates) { + for (const auto& hadron : partner.hadrons) { + if (fillHadHyperPair(candidate, hadron, currentEvent, partner, true, depth)) { + ++currentCandidatePairCounts[candidateIndex]; + } + } + ++candidateIndex; + } + for (const auto& candidate : partner.candidates) { + int acceptedPairs = 0; + for (const auto& hadron : currentEvent.hadrons) { + if (fillHadHyperPair(candidate, hadron, partner, currentEvent, true, depth)) { + ++acceptedPairs; + } + } + hadHyperRegistry.fill(HIST("hCandidatePairMultiplicityME"), acceptedPairs, partner.centrality); + } + } + for (const auto& acceptedPairs : currentCandidatePairCounts) { + hadHyperRegistry.fill(HIST("hCandidatePairMultiplicityME"), acceptedPairs, currentEvent.centrality); + } + } + + void storeHyperEventInPool(std::deque& pool, HadHyperEvent&& event) + { + const int requestedMixingDepth = eventMixing.settingNoMixedEvents.value; + if (requestedMixingDepth <= 0) { + return; + } + const auto mixingDepth = static_cast(requestedMixingDepth); + if (pool.size() >= mixingDepth) { + pool.pop_front(); + } + pool.push_back(std::move(event)); + } + + template + void processHyperPairs(const Tcollisions& collisions, const Ttracks& tracks, const Tcandidates& candidates, + const aod::BCsWithTimestamps& bcs, + std::unordered_map>& mixingPools, + int& mixingRunNumber) + { + const BinningType configuredBinningPolicy{{axisVertex, axisCentrality}, true}; + for (const auto& collision : collisions) { + if (!selectCollision(collision, bcs)) { + continue; + } + if constexpr (isMC) { + if (mc.settingRequireRecoMCCollisionMatch.value && !collision.has_mcCollision()) { + continue; + } + } + + hadHyperRegistry.fill(HIST("hPoolFlow"), 0); + int poolBin = -1; + if (hadHyper.enableMixing.value) { + poolBin = configuredBinningPolicy.getBin(std::make_tuple(collision.posZ(), collision.centFT0C())); + if (poolBin < 0) { + continue; + } + hadHyperRegistry.fill(HIST("hPoolFlow"), 1); + } + + auto event = buildHyperEvent(collision, tracks, candidates); + fillSameEventHyperPairs(event); + + if (!hadHyper.enableMixing.value) { + continue; + } + + const auto bc = collision.template bc_as(); + if (mixingRunNumber != bc.runNumber()) { + mixingPools.clear(); + mixingRunNumber = bc.runNumber(); + } + + auto& pool = mixingPools[poolBin]; + fillMixedEventHyperPairs(event, pool); + storeHyperEventInPool(pool, std::move(event)); } } @@ -2330,8 +3188,6 @@ struct HadNucleiFemto { } PROCESS_SWITCH(HadNucleiFemto, processMC, "Process reconstructed MC same-event pairs", false); - // ================================================================================================================== - void processSameEvent(const CollisionsFull& collisions, const TrackCandidates& tracks, const aod::BCsWithTimestamps& bcs) { mGoodCollisions.clear(); @@ -2361,38 +3217,6 @@ struct HadNucleiFemto { } PROCESS_SWITCH(HadNucleiFemto, processSameEvent, "Process Same event", false); - void processSameEventHyper(const CollisionsFull& collisions, const TrackCandidates& hadtracks, o2::aod::DataHypCandsWColl const& V0Hypers, const aod::BCsWithTimestamps& bcs) - { - mGoodCollisions.clear(); - mGoodCollisions.resize(collisions.size(), false); - // LOG(info) << "Number of hyperCandidates read = " << V0Hypers.size(); - - for (const auto& collision : collisions) { - - mTrackHypPairs.clear(); - - if (!selectCollision(collision, bcs)) { - continue; - } - - mGoodCollisions[collision.globalIndex()] = true; - const uint64_t collIdx = collision.globalIndex(); - auto trackTableThisCollision = hadtracks.sliceBy(mPerCol, collIdx); - auto hypdTableThisCollision = V0Hypers.sliceBy(hypPerCol, collIdx); - trackTableThisCollision.bindExternalIndices(&hadtracks); - hypdTableThisCollision.bindExternalIndices(&V0Hypers); - - pairTracksSameEventHyper(trackTableThisCollision, hypdTableThisCollision); - - if (mTrackHypPairs.empty()) { - continue; - } - - fillPairsHyper(collisions, hadtracks, V0Hypers, /*isMixedEvent*/ false); - } - } - PROCESS_SWITCH(HadNucleiFemto, processSameEventHyper, "Process Same event", false); - void processMixedEvent(const CollisionsFull& collisions, const TrackCandidates& tracks, const aod::BCsWithTimestamps&) { LOG(debug) << "Processing mixed event"; @@ -2427,16 +3251,21 @@ struct HadNucleiFemto { tracksThisCollision.bindExternalIndices(&tracks); for (const auto& track : tracksThisCollision) { if (selectTrackNu(track) && selectionPIDNu(track)) { - currentCollision.nuclei.push_back(makeBufferedTrack(track, /*isNucleus*/ true)); + currentCollision.nuclei.push_back(makeBufferedTrack(track, /*isNucleus*/ true, currentCollision.eventId)); } if (selectTrackHadron(track) && selectionPIDHadron(track)) { - currentCollision.hadrons.push_back(makeBufferedTrack(track, /*isNucleus*/ false)); + currentCollision.hadrons.push_back(makeBufferedTrack(track, /*isNucleus*/ false, currentCollision.eventId)); } } mQaRegistry.fill(HIST("hMixedNucleiPerEvent"), currentCollision.nuclei.size()); mQaRegistry.fill(HIST("hMixedHadronsPerEvent"), currentCollision.hadrons.size()); + if (eventMixing.settingRequireBothSpeciesForMixing.value && + (currentCollision.nuclei.empty() || currentCollision.hadrons.empty())) { + continue; + } + const int poolBin = configuredBinningPolicy.getBin(std::make_tuple(collision.posZ(), collision.centFT0C())); auto& pool = mMixingPools[poolBin]; mQaRegistry.fill(HIST("hMixingPoolOccupancy"), pool.size()); @@ -2471,6 +3300,229 @@ struct HadNucleiFemto { } PROCESS_SWITCH(HadNucleiFemto, processMixedEvent, "Process Mixed event", false); + // Produce the data distributions fitted offline with the MC templates. All + // nominal quality and PID selections are applied; only DCA is relaxed. + void processDcaFractionData(const CollisionsFull& collisions, const TrackCandidates& tracks, const aod::BCsWithTimestamps& bcs) + { + for (const auto& collision : collisions) { + if (!selectCollision(collision, bcs)) { + continue; + } + + const uint64_t collIdx = collision.globalIndex(); + auto tracksThisCollision = tracks.sliceBy(mPerCol, collIdx); + tracksThisCollision.bindExternalIndices(&tracks); + for (const auto& track : tracksThisCollision) { + if (selectHadronTrackForDcaFit(track) && selectionPIDHadron(track) && + std::abs(track.dcaXY()) <= fractionPurity.settingHadronDcaFitAbsMax.value && + std::abs(track.dcaZ()) <= fractionPurity.settingHadronDcaFitAbsMax.value) { + mQaRegistry.fill(HIST("fraction/hDcaDataHad"), signedPhysicalPt(track, false), track.dcaXY(), track.dcaZ(), collision.centFT0C()); + } + + if (selectNucleusTrackForDcaFit(track) && selectionPIDNuForDcaFit(track) && + std::abs(track.dcaXY()) <= fractionPurity.settingNucleusDcaFitAbsMax.value && + std::abs(track.dcaZ()) <= fractionPurity.settingNucleusDcaFitAbsMax.value) { + mQaRegistry.fill(HIST("fraction/hDcaDataNu"), signedPhysicalPt(track, true), track.dcaXY(), track.dcaZ(), collision.centFT0C()); + } + } + } + } + PROCESS_SWITCH(HadNucleiFemto, processDcaFractionData, "Produce data DCA-fraction fit inputs", false); + + template + bool truthBelongsToRecoCollision(const Ttrack&, const Tparticle& particle, const Tcollision& collision) const + { + return collision.has_mcCollision() && particle.mcCollisionId() == collision.mcCollisionId(); + } + + template + void fillMCDcaMisidentified(const Ttrack& track, float centrality, bool isNucleus, bool matchesRecoCollision) + { + const float signedPt = signedPhysicalPt(track, isNucleus); + const float collisionAssociation = matchesRecoCollision ? static_cast(CorrectCollision) : static_cast(WrongCollision); + if (isNucleus) { + mQaRegistry.fill(HIST("fraction/hDcaMisidentifiedNu"), signedPt, track.dcaXY(), track.dcaZ(), centrality, collisionAssociation); + } else { + mQaRegistry.fill(HIST("fraction/hDcaMisidentifiedHad"), signedPt, track.dcaXY(), track.dcaZ(), centrality, collisionAssociation); + } + } + + template + void fillMCDcaNoLabel(const Ttrack& track, float centrality, bool isNucleus) + { + const float signedPt = signedPhysicalPt(track, isNucleus); + if (isNucleus) { + mQaRegistry.fill(HIST("fraction/hDcaNoMCLabelNu"), signedPt, track.dcaXY(), track.dcaZ(), centrality); + } else { + mQaRegistry.fill(HIST("fraction/hDcaNoMCLabelHad"), signedPt, track.dcaXY(), track.dcaZ(), centrality); + } + } + + template + void fillMCDcaTemplate(const Ttrack& track, const Tparticle& particle, float centrality, bool isNucleus, bool matchesRecoCollision) + { + const int origin = classifyDcaOrigin(particle); + const int collisionAssociation = matchesRecoCollision ? CorrectCollision : WrongCollision; + const int parentCategory = classifyParentCategory(particle, origin); + const float productionRadius = std::hypot(particle.vx(), particle.vy()); + const float signedPt = signedPhysicalPt(track, isNucleus); + + // The detailed histogram is always filled for a truth-PDG-matched track, + // including wrong-collision associations, so tighter choices can be made + // offline without rerunning the table producer. + if (isNucleus) { + mQaRegistry.fill(HIST("fraction/hDcaTemplateDetailNu"), signedPt, track.dcaXY(), track.dcaZ(), centrality, static_cast(origin), static_cast(collisionAssociation), static_cast(parentCategory), productionRadius); + } else { + mQaRegistry.fill(HIST("fraction/hDcaTemplateDetailHad"), signedPt, track.dcaXY(), track.dcaZ(), centrality, static_cast(origin), static_cast(collisionAssociation), static_cast(parentCategory), productionRadius); + } + + const auto fillMotherPdg = [&](int motherPdg) { + const int motherSign = (motherPdg > 0) - (motherPdg < 0); + const int absoluteMotherPdg = std::abs(motherPdg); + const int motherPdgHigh = absoluteMotherPdg / MotherPdgChunkBase; + const int motherPdgLow = absoluteMotherPdg % MotherPdgChunkBase; + if (motherPdgHigh > MotherPdgHighMax) { + LOG(warning) << "Direct-mother PDG " << motherPdg << " exceeds the configured exact-PDG histogram range"; + return; + } + if (isNucleus) { + mQaRegistry.fill(HIST("fraction/hDcaMotherPdgNu"), signedPt, track.dcaXY(), track.dcaZ(), centrality, static_cast(origin), static_cast(collisionAssociation), static_cast(motherSign), static_cast(motherPdgHigh), static_cast(motherPdgLow)); + } else { + mQaRegistry.fill(HIST("fraction/hDcaMotherPdgHad"), signedPt, track.dcaXY(), track.dcaZ(), centrality, static_cast(origin), static_cast(collisionAssociation), static_cast(motherSign), static_cast(motherPdgHigh), static_cast(motherPdgLow)); + } + }; + + if (particle.has_mothers()) { + for (const auto& mother : particle.template mothers_as()) { + fillMotherPdg(mother.pdgCode()); + } + } else { + fillMotherPdg(0); + } + + // This is the stable three-component Giorgio template. The collision-match + // configurable preserves the previous strict/relaxed behavior. + if (fractionPurity.settingRequireRecoMCCollisionMatch.value && !matchesRecoCollision) { + return; + } + if (isNucleus) { + mQaRegistry.fill(HIST("fraction/hDcaTemplateNu"), signedPt, track.dcaXY(), track.dcaZ(), centrality, static_cast(origin)); + } else { + mQaRegistry.fill(HIST("fraction/hDcaTemplateHad"), signedPt, track.dcaXY(), track.dcaZ(), centrality, static_cast(origin)); + } + } + + template + void fillMCPurityComposition(const Ttrack& track, const Tparticle& particle, float centrality, bool isNucleus, bool correctSpecies, bool matchesRecoCollision) + { + const float signedPt = signedPhysicalPt(track, isNucleus); + const auto fillCategory = [&](int category) { + if (isNucleus) { + mQaRegistry.fill(HIST("purityMC/hNucleus"), signedPt, static_cast(category), centrality); + } else { + mQaRegistry.fill(HIST("purityMC/hHadron"), signedPt, static_cast(category), centrality); + } + }; + fillCategory(AllSelected); + if (!correctSpecies) { + fillCategory(MisidentifiedSpecies); + return; + } + fillCategory(CorrectSpecies); + if (!matchesRecoCollision) { + fillCategory(WrongCollisionSpecies); + return; + } + fillCategory(CorrectCollisionSpecies); + const int origin = classifyDcaOrigin(particle); + fillCategory(purityOriginCategory(origin)); + } + + template + void fillMCNoLabelPurity(const Ttrack& track, float centrality, bool isNucleus) + { + const float signedPt = signedPhysicalPt(track, isNucleus); + if (isNucleus) { + mQaRegistry.fill(HIST("purityMC/hNucleus"), signedPt, static_cast(AllSelected), centrality); + mQaRegistry.fill(HIST("purityMC/hNucleus"), signedPt, static_cast(NoMCLabel), centrality); + } else { + mQaRegistry.fill(HIST("purityMC/hHadron"), signedPt, static_cast(AllSelected), centrality); + mQaRegistry.fill(HIST("purityMC/hHadron"), signedPt, static_cast(NoMCLabel), centrality); + } + } + + // MC DCA templates use the relaxed-DCA selection. MC purity uses the full + // nominal candidate selection, including its DCA requirement. + void processDcaFractionPurityMC(const CollisionsFullMC& collisions, const TrackCandidatesMC& tracks, const aod::McParticles&, const aod::BCsWithTimestamps& bcs) + { + for (const auto& collision : collisions) { + if (!selectCollision(collision, bcs)) { + continue; + } + + const uint64_t collIdx = collision.globalIndex(); + auto tracksThisCollision = tracks.sliceBy(mPerColMC, collIdx); + tracksThisCollision.bindExternalIndices(&tracks); + for (const auto& track : tracksThisCollision) { + const bool selectedHadronForFraction = selectHadronTrackForDcaFit(track) && selectionPIDHadron(track) && + std::abs(track.dcaXY()) <= fractionPurity.settingHadronDcaFitAbsMax.value && + std::abs(track.dcaZ()) <= fractionPurity.settingHadronDcaFitAbsMax.value; + const bool selectedNucleusForFraction = selectNucleusTrackForDcaFit(track) && selectionPIDNuForDcaFit(track) && + std::abs(track.dcaXY()) <= fractionPurity.settingNucleusDcaFitAbsMax.value && + std::abs(track.dcaZ()) <= fractionPurity.settingNucleusDcaFitAbsMax.value; + + const bool selectedHadronForPurity = selectTrackHadron(track) && selectionPIDHadron(track); + const bool selectedNucleusForPurity = selectTrackNu(track) && selectionPIDNu(track); + + if (!track.has_mcParticle()) { + if (selectedHadronForFraction) { + fillMCDcaNoLabel(track, collision.centFT0C(), false); + } + if (selectedNucleusForFraction) { + fillMCDcaNoLabel(track, collision.centFT0C(), true); + } + if (selectedHadronForPurity) { + fillMCNoLabelPurity(track, collision.centFT0C(), false); + } + if (selectedNucleusForPurity) { + fillMCNoLabelPurity(track, collision.centFT0C(), true); + } + continue; + } + + const auto particle = track.template mcParticle_as(); + const bool matchesRecoCollision = truthBelongsToRecoCollision(track, particle, collision); + const int expectedHadronPdg = track.sign() >= 0 ? std::abs(species.settingHadPDGCode.value) : -std::abs(species.settingHadPDGCode.value); + const int expectedNucleusPdg = track.sign() >= 0 ? std::abs(species.settingNuPDGCode.value) : -std::abs(species.settingNuPDGCode.value); + const bool correctHadronSpecies = particle.pdgCode() == expectedHadronPdg; + const bool correctNucleusSpecies = particle.pdgCode() == expectedNucleusPdg; + + if (selectedHadronForPurity) { + fillMCPurityComposition(track, particle, collision.centFT0C(), false, correctHadronSpecies, matchesRecoCollision); + } + if (selectedNucleusForPurity) { + fillMCPurityComposition(track, particle, collision.centFT0C(), true, correctNucleusSpecies, matchesRecoCollision); + } + + if (selectedHadronForFraction) { + if (correctHadronSpecies) { + fillMCDcaTemplate(track, particle, collision.centFT0C(), false, matchesRecoCollision); + } else { + fillMCDcaMisidentified(track, collision.centFT0C(), false, matchesRecoCollision); + } + } + if (selectedNucleusForFraction) { + if (correctNucleusSpecies) { + fillMCDcaTemplate(track, particle, collision.centFT0C(), true, matchesRecoCollision); + } else { + fillMCDcaMisidentified(track, collision.centFT0C(), true, matchesRecoCollision); + } + } + } + } + } + PROCESS_SWITCH(HadNucleiFemto, processDcaFractionPurityMC, "Produce MC DCA templates and truth-purity counters", false); + void processPurity(const CollisionsFull& collisions, const TrackCandidates& tracks, const aod::BCsWithTimestamps& bcs) { for (const auto& collision : collisions) { @@ -2582,6 +3634,20 @@ struct HadNucleiFemto { } } PROCESS_SWITCH(HadNucleiFemto, processPurity, "Process for hadron and nucleus purity QA", false); + + void processHyper(const HadHyperCollisionsFull& collisions, const TrackCandidates& tracks, + const HyperCandidates& candidates, const aod::BCsWithTimestamps& bcs) + { + processHyperPairs(collisions, tracks, candidates, bcs, mHyperMixingPools, mHyperMixingRunNumber); + } + PROCESS_SWITCH(HadNucleiFemto, processHyper, "Process same-event and mixed-event hadron-hypertriton pairs", false); + + void processMCHyper(const HadHyperCollisionsFullMC& collisions, const TrackCandidatesMC& tracks, + const HyperCandidatesMC& candidates, const aod::McParticles&, const aod::BCsWithTimestamps& bcs) + { + processHyperPairs(collisions, tracks, candidates, bcs, mHyperMCMixingPools, mHyperMCMixingRunNumber); + } + PROCESS_SWITCH(HadNucleiFemto, processMCHyper, "Process MC same-event and mixed-event hadron-hypertriton pairs", false); }; WorkflowSpec defineDataProcessing(const ConfigContext& cfgc) diff --git a/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx b/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx index 516ab3f323e..0168d308901 100644 --- a/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx +++ b/PWGCF/Femto/TableProducer/femtoProducerDerivedToDerived.cxx @@ -16,6 +16,7 @@ #include "PWGCF/Femto/Core/cascadeBuilder.h" #include "PWGCF/Femto/Core/collisionBuilder.h" #include "PWGCF/Femto/Core/kinkBuilder.h" +#include "PWGCF/Femto/Core/mcBuilder.h" #include "PWGCF/Femto/Core/partitions.h" #include "PWGCF/Femto/Core/trackBuilder.h" #include "PWGCF/Femto/Core/v0Builder.h" @@ -39,6 +40,9 @@ struct FemtoProducerDerivedToDerived { using FilteredFemtoCollisions = o2::soa::Filtered; using FilteredFemtoCollision = FilteredFemtoCollisions::iterator; + using FemtoMcCollisions = o2::soa::Join; + using FilteredFemtoMcCollisions = o2::soa::Filtered; + using FemtoTracks = o2::soa::Join; using FemtoTracksWithMass = o2::soa::Join; using FemtoLambdas = o2::soa::Join; @@ -48,6 +52,9 @@ struct FemtoProducerDerivedToDerived { using FemtoSigma = o2::soa::Join; using FemtoSigmaPlus = o2::soa::Join; + using FemtoMcTracks = o2::soa::Join; + using FemtoMcParticles = o2::soa::Join; + o2::framework::SliceCache cache; // collision builder @@ -110,14 +117,25 @@ struct FemtoProducerDerivedToDerived { o2::framework::Partition omegaPartition = MAKE_CASCADE_PARTITION(omegaSelection); o2::framework::Preslice perColOmegas = o2::aod::femtobase::stored::fColId; + // mc builder + mcbuilder::McBuilderDerivedToDerived mcBuilder; + mcbuilder::McBuilderDerivedToDerivedProducts mcBuilderProducts; + mcbuilder::ConfMcTablesDerivedToDerived confMcBuilder; + + o2::framework::Partition mcTrackPartition1 = MAKE_TRACK_PARTITION(trackSelections1); + o2::framework::Partition mcTrackPartition2 = MAKE_TRACK_PARTITION(trackSelections2); + o2::framework::Preslice perColMcTracks = o2::aod::femtobase::stored::fColId; + void init(o2::framework::InitContext& /*context*/) { const int activeProcesses = static_cast(doprocessTracks) + static_cast(doprocessTracksWithMass) + - static_cast(doprocessTracksLambdas) + static_cast(doprocessLambdas) + + static_cast(doprocessTracksLambdas) + static_cast(doprocessTracksWithMassLambdas) + + static_cast(doprocessLambdas) + static_cast(doprocessTracksXis) + static_cast(doprocessTracksOmegas) + static_cast(doprocessTracksK0shorts) + static_cast(doprocessTracksSigma) + - static_cast(doprocessTracksSigmaPlus); + static_cast(doprocessTracksSigmaPlus) + + static_cast(doprocessTracksMc); if (activeProcesses != 1) { LOG(fatal) << "Exactly one process function must be activated (got " << activeProcesses << ")."; } @@ -126,6 +144,7 @@ struct FemtoProducerDerivedToDerived { v0Builder.init(confV0Builder); cascadeBuilder.init(confCascadeBuilder); kinkBuilder.init(confKinkBuilder); + mcBuilder.init(confMcBuilder); } // process functions @@ -163,6 +182,18 @@ struct FemtoProducerDerivedToDerived { } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksLambdas, "Process lambdas and tracks", false); + void processTracksWithMassLambdas(FilteredFemtoCollision const& col, FemtoTracksWithMass const& tracks, FemtoLambdas const& lambdas) + { + if (trackBuilder.collisionHasTooFewTracks(col, tracks, trackWithMassPartition1, trackWithMassPartition2, cache) || v0Builder.collisionHasTooFewLambdas(col, lambdas, lambdaPartition, cache)) { + return; + } + trackBuilder.reset(tracks); + collisionBuilder.processCollision(col, collisionBuilderProducts); + trackBuilder.processTracks(col, tracks, trackWithMassPartition1, trackWithMassPartition2, cache, trackBuilderProducts, collisionBuilderProducts); + v0Builder.processLambdas(col, lambdas, tracks, lambdaPartition, trackBuilder, cache, v0BuilderProducts, trackBuilderProducts, collisionBuilderProducts); + } + PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksWithMassLambdas, "Process lambdas and tracks with mass", false); + void processLambdas(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoLambdas const& lambdas) { if (v0Builder.collisionHasTooFewLambdas(col, lambdas, lambdaPartition, cache)) { @@ -233,6 +264,35 @@ struct FemtoProducerDerivedToDerived { kinkBuilder.processSigmaPlus(col, sigmaplus, tracks, sigmaPlusPartition, trackBuilder, cache, kinkBuilderProducts, trackBuilderProducts, collisionBuilderProducts); } PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksSigmaPlus, "Process sigmaPlus and tracks", false); + + // mc processing + // // NOTE: unlike the other process functions, this one subscribes to the full + // collision table and iterates manually. The MC index maps are keyed by source + // global index and must live for the whole dataframe + void processTracksMc(FilteredFemtoMcCollisions const& cols, + FemtoMcTracks const& tracks, + o2::aod::FMcCols const& mcCols, + FemtoMcParticles const& mcParticles, + o2::aod::FMcMothers const& mcMothers, + o2::aod::FMcPartMoths const& mcPartonicMothers) + { + // once per dataframe + mcBuilder.reset(mcCols, mcParticles); + + for (auto const& col : cols) { + if (trackBuilder.collisionHasTooFewTracks(col, tracks, mcTrackPartition1, mcTrackPartition2, cache)) { + continue; + } + // track indexMap is per collision by construction, so it resets here + trackBuilder.reset(tracks); + collisionBuilder.processCollision(col, collisionBuilderProducts); + mcBuilder.fillCollisionWithLabel(col, mcCols, mcBuilderProducts); + trackBuilder.processTracksWithMc(col, tracks, mcTrackPartition1, mcTrackPartition2, cache, + trackBuilderProducts, collisionBuilderProducts, + mcBuilder, mcCols, mcParticles, mcMothers, mcPartonicMothers, mcBuilderProducts); + } + } + PROCESS_SWITCH(FemtoProducerDerivedToDerived, processTracksMc, "Process tracks with MC information", false); }; o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& context) diff --git a/PWGCF/Femto/Tasks/femtoPairD0D0.cxx b/PWGCF/Femto/Tasks/femtoPairD0D0.cxx index 4053c196774..66c7decf0f4 100644 --- a/PWGCF/Femto/Tasks/femtoPairD0D0.cxx +++ b/PWGCF/Femto/Tasks/femtoPairD0D0.cxx @@ -20,6 +20,7 @@ #include "PWGCF/Femto/Core/collisionHistManager.h" #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairCleaner.h" #include "PWGCF/Femto/Core/pairHistManager.h" #include "PWGCF/Femto/Core/particleCleaner.h" #include "PWGCF/Femto/Core/partitions.h" @@ -100,6 +101,7 @@ struct FemtoPairD0D0 { // setup pairs pairhistmanager::ConfPairBinning confPairBinning; pairhistmanager::ConfPairCuts confPairCuts; + paircleaner::ConfPairCleanerBinning confPairCleaner; pairbuilder::PairD0D0Builder< charmhadronhistmanager::PrefixD01, @@ -162,6 +164,7 @@ struct FemtoPairD0D0 { std::map> pairD0D0HistSpec; std::map> cprHistSpecPos = closepairrejection::makeCprHistSpecMap(confCprPos); std::map> cprHistSpecNeg = closepairrejection::makeCprHistSpecMap(confCprNeg); + std::map> pairCleanerHistSpec = paircleaner::makePairCleanerHistSpecMap(confPairCleaner); if (processData) { colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); @@ -172,7 +175,7 @@ struct FemtoPairD0D0 { d0HistSpec1 = charmhadronhistmanager::makeCharmHadronHistSpecMap(confD0Binning1); d0HistSpec2 = charmhadronhistmanager::makeCharmHadronHistSpecMap(confD0Binning2); pairD0D0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); - pairD0D0Builder.init(&hRegistry, confCollisionBinning, confD0Selection1, confD0Selection2, confD0Cleaner1, confD0Cleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, d0HistSpec1, d0HistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairD0D0HistSpec, cprHistSpecPos, cprHistSpecNeg); + pairD0D0Builder.init(&hRegistry, confCollisionBinning, confD0Selection1, confD0Selection2, confD0Cleaner1, confD0Cleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, d0HistSpec1, d0HistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairD0D0HistSpec, cprHistSpecPos, cprHistSpecNeg, pairCleanerHistSpec); } else { colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); posDauSpec1 = trackhistmanager::makeTrackMcHistSpecMap(confD01PosDauBinning); @@ -182,8 +185,9 @@ struct FemtoPairD0D0 { d0HistSpec1 = charmhadronhistmanager::makeCharmHadronMcHistSpecMap(confD0Binning1); d0HistSpec2 = charmhadronhistmanager::makeCharmHadronMcHistSpecMap(confD0Binning2); pairD0D0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); - pairD0D0Builder.init(&hRegistry, confCollisionBinning, confD0Selection1, confD0Selection2, confD0Cleaner1, confD0Cleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, d0HistSpec1, d0HistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairD0D0HistSpec, cprHistSpecPos, cprHistSpecNeg); + pairD0D0Builder.init(&hRegistry, confCollisionBinning, confD0Selection1, confD0Selection2, confD0Cleaner1, confD0Cleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, d0HistSpec1, d0HistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairD0D0HistSpec, cprHistSpecPos, cprHistSpecNeg, pairCleanerHistSpec); } + hRegistry.print(); } void processSameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoD0s const& d0s) diff --git a/PWGCF/Femto/Tasks/femtoPairMcParticleMcParticle.cxx b/PWGCF/Femto/Tasks/femtoPairMcParticleMcParticle.cxx index 01c25a60146..d7a36b69bf3 100644 --- a/PWGCF/Femto/Tasks/femtoPairMcParticleMcParticle.cxx +++ b/PWGCF/Femto/Tasks/femtoPairMcParticleMcParticle.cxx @@ -19,6 +19,7 @@ #include "PWGCF/Femto/Core/mcParticleHistManager.h" #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairCleaner.h" #include "PWGCF/Femto/Core/pairHistManager.h" #include "PWGCF/Femto/Core/particleCleaner.h" #include "PWGCF/Femto/Core/partitions.h" @@ -73,13 +74,14 @@ struct FemtoPairMcParticleMcParticle { particlecleaner::ConfMcParticleCleaner2 confMcParticleCleaner2; particlecleaner::ParticleCleaner mcParticleCleaner2; - o2::framework::Partition mcParticlesPartition2 = MAKE_MC_PARTICLE_PARTITION(confMcParticleSelection1); + o2::framework::Partition mcParticlesPartition2 = MAKE_MC_PARTICLE_PARTITION(confMcParticleSelection2); o2::framework::Preslice perColParticles = o2::aod::femtomcparticle::fMcColId; // setup pairs pairhistmanager::ConfPairBinning confPairBinning; pairhistmanager::ConfPairCuts confPairCuts; + paircleaner::ConfPairCleanerBinning confPairCleaner; closepairrejection::ConfCprTrackTrack confCpr; @@ -117,12 +119,13 @@ struct FemtoPairMcParticleMcParticle { std::map> mcParticleHistSpec2; std::map> pairHistSpec; std::map> cprHistSpec = closepairrejection::makeCprHistSpecMap(confCpr); + std::map> pairCleanerHistSpec = paircleaner::makePairCleanerHistSpecMap(confPairCleaner); colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); mcParticleHistSpec1 = mcparticlehistmanager::makeMcParticleHistSpecMap(confMcParticleBinning1); mcParticleHistSpec2 = mcparticlehistmanager::makeMcParticleHistSpecMap(confMcParticleBinning2); pairHistSpec = pairhistmanager::makePairMcTruthHistSpecMap(confPairBinning, confMixing); - pairMcParticleMcParticleBuilder.init(&hRegistry, confCollisionBinning, confMcParticleSelection1, confMcParticleSelection2, confMcParticleBinning1, confMcParticleBinning2, confMcParticleCleaner1, confMcParticleCleaner2, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, mcParticleHistSpec1, mcParticleHistSpec2, pairHistSpec, cprHistSpec); + pairMcParticleMcParticleBuilder.init(&hRegistry, confCollisionBinning, confMcParticleSelection1, confMcParticleSelection2, confMcParticleBinning1, confMcParticleBinning2, confMcParticleCleaner1, confMcParticleCleaner2, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, mcParticleHistSpec1, mcParticleHistSpec2, pairHistSpec, cprHistSpec, pairCleanerHistSpec); hRegistry.print(); }; diff --git a/PWGCF/Femto/Tasks/femtoPairTrackCascade.cxx b/PWGCF/Femto/Tasks/femtoPairTrackCascade.cxx index 1c08e4b14a7..4e70a7ab76f 100644 --- a/PWGCF/Femto/Tasks/femtoPairTrackCascade.cxx +++ b/PWGCF/Femto/Tasks/femtoPairTrackCascade.cxx @@ -20,6 +20,7 @@ #include "PWGCF/Femto/Core/collisionHistManager.h" #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairCleaner.h" #include "PWGCF/Femto/Core/pairHistManager.h" #include "PWGCF/Femto/Core/particleCleaner.h" #include "PWGCF/Femto/Core/partitions.h" @@ -60,8 +61,8 @@ struct FemtoPairTrackCascade { using FemtoOmegas = o2::soa::Join; using FemtoTracksWithLabel = o2::soa::Join; - using FemtoXisWithLabel = o2::soa::Join; - using FemtoOmegasWithLabel = o2::soa::Join; + using FemtoXisWithLabel = o2::soa::Join; + using FemtoOmegasWithLabel = o2::soa::Join; using FemtoMcParticlesWithLabel = o2::soa::Join; @@ -113,6 +114,7 @@ struct FemtoPairTrackCascade { // setup pairs pairhistmanager::ConfPairBinning confPairBinning; pairhistmanager::ConfPairCuts confPairCuts; + paircleaner::ConfPairCleanerBinning confPairCleaner; pairbuilder::PairTrackCascadeBuilder< trackhistmanager::PrefixTrack1, @@ -192,6 +194,7 @@ struct FemtoPairTrackCascade { std::map> cprHistSpecBachelor = closepairrejection::makeCprHistSpecMap(confCprBachelor); std::map> cprHistSpecV0Daughter = closepairrejection::makeCprHistSpecMap(confCprV0Daughter); + std::map> pairCleanerHistSpec = paircleaner::makePairCleanerHistSpecMap(confPairCleaner); if (processData) { colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); @@ -202,11 +205,11 @@ struct FemtoPairTrackCascade { pairTrackCascadeHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); if (processXi) { xiHistSpec = cascadehistmanager::makeCascadeHistSpecMap(confXiBinning); - pairTrackXiBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, confXiSelection, confXiCleaner, confCprBachelor, confCprV0Daughter, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, xiHistSpec, bachelorHistSpec, posDauSpec, negDauSpec, pairTrackCascadeHistSpec, cprHistSpecBachelor, cprHistSpecV0Daughter); + pairTrackXiBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, confXiSelection, confXiCleaner, confCprBachelor, confCprV0Daughter, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, xiHistSpec, bachelorHistSpec, posDauSpec, negDauSpec, pairTrackCascadeHistSpec, cprHistSpecBachelor, cprHistSpecV0Daughter, pairCleanerHistSpec); } else { omegaHistSpec = cascadehistmanager::makeCascadeHistSpecMap(confOmegaBinning); pairTrackCascadeHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); - pairTrackOmegaBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, confOmegaSelection, confOmegaCleaner, confCprBachelor, confCprV0Daughter, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, omegaHistSpec, bachelorHistSpec, posDauSpec, negDauSpec, pairTrackCascadeHistSpec, cprHistSpecBachelor, cprHistSpecV0Daughter); + pairTrackOmegaBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, confOmegaSelection, confOmegaCleaner, confCprBachelor, confCprV0Daughter, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, omegaHistSpec, bachelorHistSpec, posDauSpec, negDauSpec, pairTrackCascadeHistSpec, cprHistSpecBachelor, cprHistSpecV0Daughter, pairCleanerHistSpec); } } else { colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); @@ -217,12 +220,13 @@ struct FemtoPairTrackCascade { pairTrackCascadeHistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); if (processXi) { xiHistSpec = cascadehistmanager::makeCascadeMcHistSpecMap(confXiBinning); - pairTrackXiBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, confXiSelection, confXiCleaner, confCprBachelor, confCprV0Daughter, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, xiHistSpec, bachelorHistSpec, posDauSpec, negDauSpec, pairTrackCascadeHistSpec, cprHistSpecBachelor, cprHistSpecV0Daughter); + pairTrackXiBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, confXiSelection, confXiCleaner, confCprBachelor, confCprV0Daughter, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, xiHistSpec, bachelorHistSpec, posDauSpec, negDauSpec, pairTrackCascadeHistSpec, cprHistSpecBachelor, cprHistSpecV0Daughter, pairCleanerHistSpec); } else { omegaHistSpec = cascadehistmanager::makeCascadeMcHistSpecMap(confOmegaBinning); - pairTrackOmegaBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, confOmegaSelection, confOmegaCleaner, confCprBachelor, confCprV0Daughter, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, omegaHistSpec, bachelorHistSpec, posDauSpec, negDauSpec, pairTrackCascadeHistSpec, cprHistSpecBachelor, cprHistSpecV0Daughter); + pairTrackOmegaBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, confOmegaSelection, confOmegaCleaner, confCprBachelor, confCprV0Daughter, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, omegaHistSpec, bachelorHistSpec, posDauSpec, negDauSpec, pairTrackCascadeHistSpec, cprHistSpecBachelor, cprHistSpecV0Daughter, pairCleanerHistSpec); } } + hRegistry.print(); }; void processXiSameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoXis const& xis) @@ -267,7 +271,7 @@ struct FemtoPairTrackCascade { } PROCESS_SWITCH(FemtoPairTrackCascade, processOmegaMixedEvent, "Enable processing mixed event processing for tracks and omegas", false); - void processOmegaMixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoXisWithLabel const& /*xis*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) + void processOmegaMixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoOmegasWithLabel const& /*omegas*/, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { pairTrackOmegaBuilder.processMixedEvent(cols, mcCols, tracks, trackWithLabelPartition, omegaWithLabelPartition, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } diff --git a/PWGCF/Femto/Tasks/femtoPairTrackCharmHadron.cxx b/PWGCF/Femto/Tasks/femtoPairTrackCharmHadron.cxx index 2780d6f4503..600c3c3c033 100644 --- a/PWGCF/Femto/Tasks/femtoPairTrackCharmHadron.cxx +++ b/PWGCF/Femto/Tasks/femtoPairTrackCharmHadron.cxx @@ -20,6 +20,7 @@ #include "PWGCF/Femto/Core/collisionHistManager.h" #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairCleaner.h" #include "PWGCF/Femto/Core/pairHistManager.h" #include "PWGCF/Femto/Core/particleCleaner.h" #include "PWGCF/Femto/Core/partitions.h" @@ -116,6 +117,7 @@ struct FemtoPairTrackCharmHadron { // setup pairs pairhistmanager::ConfPairBinning confPairBinning; pairhistmanager::ConfPairCuts confPairCuts; + paircleaner::ConfPairCleanerBinning confPairCleaner; pairbuilder::PairTrackD0Builder< trackhistmanager::PrefixTrack1, @@ -194,6 +196,8 @@ struct FemtoPairTrackCharmHadron { std::map> pairTrackD0HistSpec; std::map> pairTrackLcHistSpec; std::map> cprHistSpec = closepairrejection::makeCprHistSpecMap(confCpr); + std::map> cprHistSpecLc = closepairrejection::makeCprHistSpecMap(confCprLcProton); + std::map> pairCleanerHistSpec = paircleaner::makePairCleanerHistSpecMap(confPairCleaner); if (processData) { colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); @@ -203,7 +207,7 @@ struct FemtoPairTrackCharmHadron { negDauSpec = trackhistmanager::makeTrackHistSpecMap(confNegDauBinning); d0HistSpec = charmhadronhistmanager::makeCharmHadronHistSpecMap(confD0Binning); pairTrackD0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); - pairTrackD0Builder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, d0Selection, confD0Cleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, d0HistSpec, posDauSpec, negDauSpec, pairTrackD0HistSpec, cprHistSpec); + pairTrackD0Builder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, d0Selection, confD0Cleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, d0HistSpec, posDauSpec, negDauSpec, pairTrackD0HistSpec, cprHistSpec, pairCleanerHistSpec); } if (processLc) { protonDauSpec = trackhistmanager::makeTrackHistSpecMap(confProtonDauBinning); @@ -211,7 +215,7 @@ struct FemtoPairTrackCharmHadron { pionDauSpec = trackhistmanager::makeTrackHistSpecMap(confPionDauBinning); lcHistSpec = charmhadronhistmanager::makeCharmHadronHistSpecMap(confLcBinning); pairTrackLcHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); - pairTrackLcBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, lcSelection, confLcCleaner, confCprLcProton, confCprLcKaon, confCprLcPion, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, lcHistSpec, protonDauSpec, kaonDauSpec, pionDauSpec, pairTrackLcHistSpec, cprHistSpec); + pairTrackLcBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, lcSelection, confLcCleaner, confCprLcProton, confCprLcKaon, confCprLcPion, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, lcHistSpec, protonDauSpec, kaonDauSpec, pionDauSpec, pairTrackLcHistSpec, cprHistSpecLc, pairCleanerHistSpec); } } else { colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); @@ -221,7 +225,7 @@ struct FemtoPairTrackCharmHadron { negDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confNegDauBinning); d0HistSpec = charmhadronhistmanager::makeCharmHadronMcHistSpecMap(confD0Binning); pairTrackD0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); - pairTrackD0Builder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, d0Selection, confD0Cleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, d0HistSpec, posDauSpec, negDauSpec, pairTrackD0HistSpec, cprHistSpec); + pairTrackD0Builder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, d0Selection, confD0Cleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, d0HistSpec, posDauSpec, negDauSpec, pairTrackD0HistSpec, cprHistSpec, pairCleanerHistSpec); } if (processLcMc) { protonDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confProtonDauBinning); @@ -229,7 +233,7 @@ struct FemtoPairTrackCharmHadron { pionDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confPionDauBinning); lcHistSpec = charmhadronhistmanager::makeCharmHadronMcHistSpecMap(confLcBinning); pairTrackLcHistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); - pairTrackLcBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, lcSelection, confLcCleaner, confCprLcProton, confCprLcKaon, confCprLcPion, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, lcHistSpec, protonDauSpec, kaonDauSpec, pionDauSpec, pairTrackLcHistSpec, cprHistSpec); + pairTrackLcBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, lcSelection, confLcCleaner, confCprLcProton, confCprLcKaon, confCprLcPion, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, lcHistSpec, protonDauSpec, kaonDauSpec, pionDauSpec, pairTrackLcHistSpec, cprHistSpecLc, pairCleanerHistSpec); } } diff --git a/PWGCF/Femto/Tasks/femtoPairTrackKink.cxx b/PWGCF/Femto/Tasks/femtoPairTrackKink.cxx index 3572e577537..bbf0da77024 100644 --- a/PWGCF/Femto/Tasks/femtoPairTrackKink.cxx +++ b/PWGCF/Femto/Tasks/femtoPairTrackKink.cxx @@ -21,6 +21,7 @@ #include "PWGCF/Femto/Core/kinkHistManager.h" #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairCleaner.h" #include "PWGCF/Femto/Core/pairHistManager.h" #include "PWGCF/Femto/Core/particleCleaner.h" #include "PWGCF/Femto/Core/partitions.h" @@ -112,6 +113,7 @@ struct FemtoPairTrackKink { // setup pairs pairhistmanager::ConfPairBinning confPairBinning; pairhistmanager::ConfPairCuts confPairCuts; + paircleaner::ConfPairCleanerBinning confPairCleaner; pairbuilder::PairTrackKinkBuilder< trackhistmanager::PrefixTrack1, @@ -178,6 +180,7 @@ struct FemtoPairTrackKink { std::map> sigmaPlusHistSpec; std::map> pairTrackKinkHistSpec; std::map> cprHistSpec = closepairrejection::makeCprHistSpecMap(confCpr); + std::map> pairCleanerHistSpec = paircleaner::makePairCleanerHistSpecMap(confPairCleaner); if (processData) { colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); @@ -186,10 +189,10 @@ struct FemtoPairTrackKink { pairTrackKinkHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); if (processSigma) { sigmaHistSpec = kinkhistmanager::makeKinkHistSpecMap(confSigmaBinning); - pairTrackSigmaBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, confSigmaSelection, confSigmaCleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, sigmaHistSpec, chaDauSpec, pairTrackKinkHistSpec, cprHistSpec); + pairTrackSigmaBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, confSigmaSelection, confSigmaCleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, sigmaHistSpec, chaDauSpec, pairTrackKinkHistSpec, cprHistSpec, pairCleanerHistSpec); } else { sigmaPlusHistSpec = kinkhistmanager::makeKinkHistSpecMap(confSigmaPlusBinning); - pairTrackSigmaPlusBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, confSigmaPlusSelection, confSigmaPlusCleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, sigmaPlusHistSpec, chaDauSpec, pairTrackKinkHistSpec, cprHistSpec); + pairTrackSigmaPlusBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, confSigmaPlusSelection, confSigmaPlusCleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, sigmaPlusHistSpec, chaDauSpec, pairTrackKinkHistSpec, cprHistSpec, pairCleanerHistSpec); } } else { colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); @@ -198,10 +201,10 @@ struct FemtoPairTrackKink { pairTrackKinkHistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); if (processSigma) { sigmaHistSpec = kinkhistmanager::makeKinkMcHistSpecMap(confSigmaBinning); - pairTrackSigmaBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, confSigmaSelection, confSigmaCleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, sigmaHistSpec, chaDauSpec, pairTrackKinkHistSpec, cprHistSpec); + pairTrackSigmaBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, confSigmaSelection, confSigmaCleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, sigmaHistSpec, chaDauSpec, pairTrackKinkHistSpec, cprHistSpec, pairCleanerHistSpec); } else { sigmaPlusHistSpec = kinkhistmanager::makeKinkMcHistSpecMap(confSigmaPlusBinning); - pairTrackSigmaPlusBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, confSigmaPlusSelection, confSigmaPlusCleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, sigmaPlusHistSpec, chaDauSpec, pairTrackKinkHistSpec, cprHistSpec); + pairTrackSigmaPlusBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, confSigmaPlusSelection, confSigmaPlusCleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, sigmaPlusHistSpec, chaDauSpec, pairTrackKinkHistSpec, cprHistSpec, pairCleanerHistSpec); } } hRegistry.print(); @@ -245,7 +248,7 @@ struct FemtoPairTrackKink { void processSigmaPlusMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks, FemtoSigmaPlus const& /*sigmaplus*/) { - pairTrackSigmaPlusBuilder.processMixedEvent(cols, tracks, trackPartition, sigmaPlusPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairTrackSigmaPlusBuilder.processMixedEvent(cols, tracks, trackPartition, sigmaPlusPartition, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); } PROCESS_SWITCH(FemtoPairTrackKink, processSigmaPlusMixedEvent, "Enable processing mixed event processing for tracks and sigma plus", false); diff --git a/PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx b/PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx index cb49fed5e8d..818db97e7eb 100644 --- a/PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx +++ b/PWGCF/Femto/Tasks/femtoPairTrackTrack.cxx @@ -18,6 +18,7 @@ #include "PWGCF/Femto/Core/collisionHistManager.h" #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairCleaner.h" #include "PWGCF/Femto/Core/pairHistManager.h" #include "PWGCF/Femto/Core/particleCleaner.h" #include "PWGCF/Femto/Core/partitions.h" @@ -25,6 +26,7 @@ #include "PWGCF/Femto/Core/trackHistManager.h" #include "PWGCF/Femto/DataModel/FemtoTables.h" +#include #include #include #include @@ -53,6 +55,11 @@ struct FemtoPairTrackTrack { using FilteredFemtoCollisionsWithLabel = o2::soa::Filtered; using FilteredFemtoCollisionWithLabel = FilteredFemtoCollisionsWithLabel::iterator; + // collision table with event shape, same filter as standard collisions + using FemtoCollisionsWithEventShape = o2::soa::Join; + using FilteredFemtoCollisionsWithEventShape = o2::soa::Filtered; + using FilteredFemtoCollisionWithEventShape = FilteredFemtoCollisionsWithEventShape::iterator; + using FemtoTracks = o2::soa::Join; // for analysis which require particles at high pt, add tof mass so sidebands can be used @@ -93,6 +100,7 @@ struct FemtoPairTrackTrack { // setup pairs pairhistmanager::ConfPairBinning confPairBinning; pairhistmanager::ConfPairCuts confPairCuts; + paircleaner::ConfPairCleanerBinning confPairCleaner; closepairrejection::ConfCprTrackTrack confCpr; @@ -109,19 +117,22 @@ struct FemtoPairTrackTrack { std::vector defaultVtxBins{10, -10, 10}; std::vector defaultMultBins{50, 0, 200}; std::vector defaultCentBins{10, 0, 100}; + std::vector defaultEventPlaneAngleBins{10, 0, o2::constants::math::TwoPI}; o2::framework::ColumnBinningPolicy mixBinsVtxMult{{defaultVtxBins, defaultMultBins}, true}; o2::framework::ColumnBinningPolicy mixBinsVtxCent{{defaultVtxBins, defaultCentBins}, true}; o2::framework::ColumnBinningPolicy mixBinsVtxMultCent{{defaultVtxBins, defaultMultBins, defaultCentBins}, true}; + o2::framework::ColumnBinningPolicy mixBinsVtxCentEventPlaneAngle{{defaultVtxBins, defaultCentBins, defaultEventPlaneAngleBins}, true}; pairhistmanager::ConfMixing confMixing; o2::framework::HistogramRegistry hRegistry{"FemtoTrackTrack", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject}; void init(o2::framework::InitContext&) { - if ((static_cast(doprocessSameEvent) + static_cast(doprocessSameEventWithMass) + static_cast(doprocessSameEventMc)) > 1 || (static_cast(doprocessMixedEvent) + static_cast(doprocessMixedEventWithMass) + static_cast(doprocessMixedEventMc)) > 1) { + if ((static_cast(doprocessSameEvent) + static_cast(doprocessSameEventWithMass) + static_cast(doprocessSameEventWithEventShape) + static_cast(doprocessSameEventMc)) > 1 || + (static_cast(doprocessMixedEvent) + static_cast(doprocessMixedEventWithMass) + static_cast(doprocessMixedEventWithEventShape) + static_cast(doprocessMixedEventMc)) > 1) { LOG(fatal) << "More than 1 same or mixed event process function is activated. Breaking..."; } - bool processData = doprocessSameEvent || doprocessMixedEvent || doprocessSameEventWithMass || doprocessMixedEventWithMass; + bool processData = doprocessSameEvent || doprocessMixedEvent || doprocessSameEventWithMass || doprocessMixedEventWithMass || doprocessSameEventWithEventShape || doprocessMixedEventWithEventShape; bool processMc = doprocessSameEventMc || doprocessMixedEventMc; if (processData && processMc) { LOG(fatal) << "Both data and mc processing is activated. Breaking..."; @@ -132,6 +143,7 @@ struct FemtoPairTrackTrack { mixBinsVtxMult = {{confMixing.vtxBins.value, confMixing.multBins.value}, true}; mixBinsVtxCent = {{confMixing.vtxBins.value, confMixing.centBins.value}, true}; mixBinsVtxMultCent = {{confMixing.vtxBins.value, confMixing.multBins.value, confMixing.centBins.value}, true}; + mixBinsVtxCentEventPlaneAngle = {{confMixing.vtxBins.value, confMixing.centBins.value, confMixing.eventPlaneAngle.value}, true}; // setup histogram specs std::map> colHistSpec; @@ -139,19 +151,20 @@ struct FemtoPairTrackTrack { std::map> trackHistSpec2; std::map> pairHistSpec; std::map> cprHistSpec = closepairrejection::makeCprHistSpecMap(confCpr); + std::map> pairCleanerHistSpec = paircleaner::makePairCleanerHistSpecMap(confPairCleaner); if (processData) { colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); trackHistSpec1 = trackhistmanager::makeTrackHistSpecMap(confTrackBinning1); trackHistSpec2 = trackhistmanager::makeTrackHistSpecMap(confTrackBinning2); pairHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); - pairTrackTrackBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confTrackCleaner1, confTrackCleaner2, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec1, trackHistSpec2, pairHistSpec, cprHistSpec); + pairTrackTrackBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confTrackCleaner1, confTrackCleaner2, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec1, trackHistSpec2, pairHistSpec, cprHistSpec, pairCleanerHistSpec); } else { colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); trackHistSpec1 = trackhistmanager::makeTrackMcHistSpecMap(confTrackBinning1); trackHistSpec2 = trackhistmanager::makeTrackMcHistSpecMap(confTrackBinning2); pairHistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); - pairTrackTrackBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confTrackCleaner1, confTrackCleaner2, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec1, trackHistSpec2, pairHistSpec, cprHistSpec); + pairTrackTrackBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confTrackCleaner1, confTrackCleaner2, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec1, trackHistSpec2, pairHistSpec, cprHistSpec, pairCleanerHistSpec); } hRegistry.print(); }; @@ -168,6 +181,12 @@ struct FemtoPairTrackTrack { } PROCESS_SWITCH(FemtoPairTrackTrack, processSameEventWithMass, "Enable processing same event processing (with track masses)", false); + void processSameEventWithEventShape(FilteredFemtoCollisionWithEventShape const& col, FemtoTracks const& tracks) + { + pairTrackTrackBuilder.processSameEvent(col, tracks, trackPartition1, trackPartition2, cache); + } + PROCESS_SWITCH(FemtoPairTrackTrack, processSameEventWithEventShape, "Enable processing same event processing with event shape information", false); + void processSameEventMc(FilteredFemtoCollisionWithLabel const& col, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { pairTrackTrackBuilder.processSameEvent(col, mcCols, tracks, trackWithLabelPartition1, trackWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache); @@ -176,19 +195,25 @@ struct FemtoPairTrackTrack { void processMixedEvent(FilteredFemtoCollisions const& cols, FemtoTracks const& tracks) { - pairTrackTrackBuilder.processMixedEvent(cols, tracks, trackPartition1, trackPartition2, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairTrackTrackBuilder.processMixedEvent(cols, tracks, trackPartition1, trackPartition2, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent, mixBinsVtxCentEventPlaneAngle); } PROCESS_SWITCH(FemtoPairTrackTrack, processMixedEvent, "Enable processing mixed event processing", true); void processMixedEventWithMass(FilteredFemtoCollisions const& cols, FemtoTracksWithMass const& tracks) { - pairTrackTrackBuilder.processMixedEvent(cols, tracks, trackWithMassPartition1, trackWithMassPartition2, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairTrackTrackBuilder.processMixedEvent(cols, tracks, trackWithMassPartition1, trackWithMassPartition2, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent, mixBinsVtxCentEventPlaneAngle); } PROCESS_SWITCH(FemtoPairTrackTrack, processMixedEventWithMass, "Enable processing mixed event processing (with track masses)", false); + void processMixedEventWithEventShape(FilteredFemtoCollisionsWithEventShape const& cols, FemtoTracks const& tracks) + { + pairTrackTrackBuilder.processMixedEvent(cols, tracks, trackPartition1, trackPartition2, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent, mixBinsVtxCentEventPlaneAngle); + } + PROCESS_SWITCH(FemtoPairTrackTrack, processMixedEventWithEventShape, "Enable processing mixed event processing with event shape information", false); + void processMixedEventMc(FilteredFemtoCollisionsWithLabel const& cols, o2::aod::FMcCols const& mcCols, FemtoTracksWithLabel const& tracks, FemtoMcParticlesWithLabel const& mcParticles, o2::aod::FMcMothers const& mcMothers, o2::aod::FMcPartMoths const& mcPartonicMothers) { - pairTrackTrackBuilder.processMixedEvent(cols, mcCols, tracks, trackWithLabelPartition1, trackWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent); + pairTrackTrackBuilder.processMixedEvent(cols, mcCols, tracks, trackWithLabelPartition1, trackWithLabelPartition2, mcParticles, mcMothers, mcPartonicMothers, cache, mixBinsVtxMult, mixBinsVtxCent, mixBinsVtxMultCent, mixBinsVtxCentEventPlaneAngle); } PROCESS_SWITCH(FemtoPairTrackTrack, processMixedEventMc, "Enable processing mixed event processing", false); }; diff --git a/PWGCF/Femto/Tasks/femtoPairTrackTwoTrackResonance.cxx b/PWGCF/Femto/Tasks/femtoPairTrackTwoTrackResonance.cxx index f5fb9088aa5..5197f851bcb 100644 --- a/PWGCF/Femto/Tasks/femtoPairTrackTwoTrackResonance.cxx +++ b/PWGCF/Femto/Tasks/femtoPairTrackTwoTrackResonance.cxx @@ -18,6 +18,7 @@ #include "PWGCF/Femto/Core/collisionHistManager.h" #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairCleaner.h" #include "PWGCF/Femto/Core/pairHistManager.h" #include "PWGCF/Femto/Core/partitions.h" #include "PWGCF/Femto/Core/trackBuilder.h" @@ -94,6 +95,7 @@ struct FemtoPairTrackTwoTrackResonance { // setup pairs pairhistmanager::ConfPairBinning confPairBinning; pairhistmanager::ConfPairCuts confPairCuts; + paircleaner::ConfPairCleanerBinning confPairCleaner; // setup for track-phi pairs pairbuilder::PairTrackTwoTrackResonanceBuilder< @@ -167,27 +169,30 @@ struct FemtoPairTrackTwoTrackResonance { auto posDauSpec = trackhistmanager::makeTrackHistSpecMap(confPosDauBinning); auto negDauSpec = trackhistmanager::makeTrackHistSpecMap(confNegDauBinning); auto cprHistSpec = closepairrejection::makeCprHistSpecMap(confCpr); + auto pairCleanerHistSpec = paircleaner::makePairCleanerHistSpecMap(confPairCleaner); // setup for phi if (doprocessPhiSameEvent || doprocessPhiMixedEvent) { auto phiHistSpec = twotrackresonancehistmanager::makeTwoTrackResonanceHistSpecMap(confPhiBinning); auto pairTrackPhiHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); - pairTrackPhiBuilder.init(&hRegistry, confCollisionBinning, trackSelection, phiSelection, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, phiHistSpec, posDauSpec, negDauSpec, pairTrackPhiHistSpec, cprHistSpec); + pairTrackPhiBuilder.init(&hRegistry, confCollisionBinning, trackSelection, phiSelection, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, phiHistSpec, posDauSpec, negDauSpec, pairTrackPhiHistSpec, cprHistSpec, pairCleanerHistSpec); } // setup for kstar0 if (doprocessKstar0SameEvent || doprocessKstar0MixedEvent) { auto kstar0HistSpec = twotrackresonancehistmanager::makeTwoTrackResonanceHistSpecMap(confKstar0Binning); auto pairTrackKstar0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); - pairTrackKstar0Builder.init(&hRegistry, confCollisionBinning, trackSelection, kstar0Selection, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, kstar0HistSpec, posDauSpec, negDauSpec, pairTrackKstar0HistSpec, cprHistSpec); + pairTrackKstar0Builder.init(&hRegistry, confCollisionBinning, trackSelection, kstar0Selection, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, kstar0HistSpec, posDauSpec, negDauSpec, pairTrackKstar0HistSpec, cprHistSpec, pairCleanerHistSpec); } // setup for kstar0 if (doprocessRho0SameEvent || doprocessRho0MixedEvent) { auto rho0HistSpec = twotrackresonancehistmanager::makeTwoTrackResonanceHistSpecMap(confRho0Binning); auto pairTrackRho0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); - pairTrackRho0Builder.init(&hRegistry, confCollisionBinning, trackSelection, rho0Selection, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, rho0HistSpec, posDauSpec, negDauSpec, pairTrackRho0HistSpec, cprHistSpec); + pairTrackRho0Builder.init(&hRegistry, confCollisionBinning, trackSelection, rho0Selection, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, rho0HistSpec, posDauSpec, negDauSpec, pairTrackRho0HistSpec, cprHistSpec, pairCleanerHistSpec); } + + hRegistry.print(); }; void processPhiSameEvent(FilteredCollision const& col, FemtoTracks const& tracks, FemtoPhis const& phis) diff --git a/PWGCF/Femto/Tasks/femtoPairTrackV0.cxx b/PWGCF/Femto/Tasks/femtoPairTrackV0.cxx index 73cf010fb31..224567da38e 100644 --- a/PWGCF/Femto/Tasks/femtoPairTrackV0.cxx +++ b/PWGCF/Femto/Tasks/femtoPairTrackV0.cxx @@ -18,6 +18,7 @@ #include "PWGCF/Femto/Core/collisionHistManager.h" #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairCleaner.h" #include "PWGCF/Femto/Core/pairHistManager.h" #include "PWGCF/Femto/Core/particleCleaner.h" #include "PWGCF/Femto/Core/partitions.h" @@ -112,6 +113,7 @@ struct FemtoPairTrackV0 { // setup pairs pairhistmanager::ConfPairBinning confPairBinning; pairhistmanager::ConfPairCuts confPairCuts; + paircleaner::ConfPairCleanerBinning confPairCleaner; pairbuilder::PairTrackV0Builder< trackhistmanager::PrefixTrack1, @@ -181,6 +183,7 @@ struct FemtoPairTrackV0 { std::map> k0shortHistSpec; std::map> pairTrackV0HistSpec; std::map> cprHistSpec = closepairrejection::makeCprHistSpecMap(confCpr); + std::map> pairCleanerHistSpec = paircleaner::makePairCleanerHistSpecMap(confPairCleaner); if (processData) { colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); @@ -190,10 +193,10 @@ struct FemtoPairTrackV0 { pairTrackV0HistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); if (processLambda) { lambdaHistSpec = v0histmanager::makeV0HistSpecMap(confLambdaBinning); - pairTrackLambdaBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, lambdaSelection, confLambdaCleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, lambdaHistSpec, posDauSpec, negDauSpec, pairTrackV0HistSpec, cprHistSpec); + pairTrackLambdaBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, lambdaSelection, confLambdaCleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, lambdaHistSpec, posDauSpec, negDauSpec, pairTrackV0HistSpec, cprHistSpec, pairCleanerHistSpec); } else { k0shortHistSpec = v0histmanager::makeV0HistSpecMap(confK0shortBinning); - pairTrackK0shortBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, lambdaSelection, confTrackCleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, k0shortHistSpec, posDauSpec, negDauSpec, pairTrackV0HistSpec, cprHistSpec); + pairTrackK0shortBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, k0shortSelection, confK0shortCleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, k0shortHistSpec, posDauSpec, negDauSpec, pairTrackV0HistSpec, cprHistSpec, pairCleanerHistSpec); } } else { colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); @@ -203,10 +206,10 @@ struct FemtoPairTrackV0 { pairTrackV0HistSpec = pairhistmanager::makePairMcHistSpecMap(confPairBinning, confMixing); if (processLambda) { lambdaHistSpec = v0histmanager::makeV0McHistSpecMap(confLambdaBinning); - pairTrackLambdaBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, lambdaSelection, confLambdaCleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, lambdaHistSpec, posDauSpec, negDauSpec, pairTrackV0HistSpec, cprHistSpec); + pairTrackLambdaBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, lambdaSelection, confLambdaCleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, lambdaHistSpec, posDauSpec, negDauSpec, pairTrackV0HistSpec, cprHistSpec, pairCleanerHistSpec); } else { k0shortHistSpec = v0histmanager::makeV0McHistSpecMap(confK0shortBinning); - pairTrackK0shortBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, lambdaSelection, confLambdaCleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, k0shortHistSpec, posDauSpec, negDauSpec, pairTrackV0HistSpec, cprHistSpec); + pairTrackK0shortBuilder.init(&hRegistry, confCollisionBinning, confTrackSelection, confTrackCleaner, k0shortSelection, confK0shortCleaner, confCpr, confMixing, confPairBinning, confPairCuts, colHistSpec, trackHistSpec, k0shortHistSpec, posDauSpec, negDauSpec, pairTrackV0HistSpec, cprHistSpec, pairCleanerHistSpec); } } hRegistry.print(); diff --git a/PWGCF/Femto/Tasks/femtoPairV0TwoTrackResonance.cxx b/PWGCF/Femto/Tasks/femtoPairV0TwoTrackResonance.cxx index d742aba5be4..68ddc7d277f 100644 --- a/PWGCF/Femto/Tasks/femtoPairV0TwoTrackResonance.cxx +++ b/PWGCF/Femto/Tasks/femtoPairV0TwoTrackResonance.cxx @@ -18,6 +18,7 @@ #include "PWGCF/Femto/Core/collisionHistManager.h" #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairCleaner.h" #include "PWGCF/Femto/Core/pairHistManager.h" #include "PWGCF/Femto/Core/particleCleaner.h" #include "PWGCF/Femto/Core/partitions.h" @@ -114,6 +115,7 @@ struct FemtoPairV0TwoTrackResonance { // setup pairs pairhistmanager::ConfPairBinning confPairBinning; pairhistmanager::ConfPairCuts confPairCuts; + paircleaner::ConfPairCleanerBinning confPairCleaner; // setup for lambda-phi pairs pairbuilder::PairV0TwoTrackResonanceBuilder< @@ -273,47 +275,51 @@ struct FemtoPairV0TwoTrackResonance { auto pairV0TwoTrackResonanceHistSpec = pairhistmanager::makePairHistSpecMap(confPairBinning, confMixing); + auto pairCleanerHistSpec = paircleaner::makePairCleanerHistSpecMap(confPairCleaner); + // setup for lambda-phi if (doprocessLambdaPhiSameEvent || doprocessLambdaPhiMixedEvent) { auto lambdaHistSpec = v0histmanager::makeV0HistSpecMap(confLambdaBinning); auto phiHistSpec = twotrackresonancehistmanager::makeTwoTrackResonanceHistSpecMap(confPhiBinning); - pairLambdaPhiBuilder.init(&hRegistry, confCollisionBinning, lambdaSelection, phiSelection, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, v0PosDauSpec, v0NegDauSpec, phiHistSpec, resoPosDauSpec, resoNegDauSpec, pairV0TwoTrackResonanceHistSpec, cprHistSpecPos, cprHistSpecNeg); + pairLambdaPhiBuilder.init(&hRegistry, confCollisionBinning, lambdaSelection, phiSelection, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, v0PosDauSpec, v0NegDauSpec, phiHistSpec, resoPosDauSpec, resoNegDauSpec, pairV0TwoTrackResonanceHistSpec, cprHistSpecPos, cprHistSpecNeg, pairCleanerHistSpec); } // setup for lambda-kstar0 if (doprocessLambdaKstar0SameEvent || doprocessLambdaKstar0MixedEvent) { auto lambdaHistSpec = v0histmanager::makeV0HistSpecMap(confLambdaBinning); auto kstar0HistSpec = twotrackresonancehistmanager::makeTwoTrackResonanceHistSpecMap(confKstar0Binning); - pairLambdaKstar0Builder.init(&hRegistry, confCollisionBinning, lambdaSelection, kstar0Selection, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, v0PosDauSpec, v0NegDauSpec, kstar0HistSpec, resoPosDauSpec, resoNegDauSpec, pairV0TwoTrackResonanceHistSpec, cprHistSpecPos, cprHistSpecNeg); + pairLambdaKstar0Builder.init(&hRegistry, confCollisionBinning, lambdaSelection, kstar0Selection, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, v0PosDauSpec, v0NegDauSpec, kstar0HistSpec, resoPosDauSpec, resoNegDauSpec, pairV0TwoTrackResonanceHistSpec, cprHistSpecPos, cprHistSpecNeg, pairCleanerHistSpec); } // setup for lambda-rho0 if (doprocessLambdaRho0SameEvent || doprocessLambdaRho0MixedEvent) { auto lambdaHistSpec = v0histmanager::makeV0HistSpecMap(confLambdaBinning); auto rho0HistSpec = twotrackresonancehistmanager::makeTwoTrackResonanceHistSpecMap(confRho0Binning); - pairLambdaRho0Builder.init(&hRegistry, confCollisionBinning, lambdaSelection, rho0Selection, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, v0PosDauSpec, v0NegDauSpec, rho0HistSpec, resoPosDauSpec, resoNegDauSpec, pairV0TwoTrackResonanceHistSpec, cprHistSpecPos, cprHistSpecNeg); + pairLambdaRho0Builder.init(&hRegistry, confCollisionBinning, lambdaSelection, rho0Selection, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, v0PosDauSpec, v0NegDauSpec, rho0HistSpec, resoPosDauSpec, resoNegDauSpec, pairV0TwoTrackResonanceHistSpec, cprHistSpecPos, cprHistSpecNeg, pairCleanerHistSpec); } // setup for k0short-phi if (doprocessK0shortPhiSameEvent || doprocessK0shortPhiMixedEvent) { auto k0shortHistSpec = v0histmanager::makeV0HistSpecMap(confK0shortBinning); auto phiHistSpec = twotrackresonancehistmanager::makeTwoTrackResonanceHistSpecMap(confPhiBinning); - pairK0shortPhiBuilder.init(&hRegistry, confCollisionBinning, k0shortSelection, phiSelection, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, v0PosDauSpec, v0NegDauSpec, phiHistSpec, resoPosDauSpec, resoNegDauSpec, pairV0TwoTrackResonanceHistSpec, cprHistSpecPos, cprHistSpecNeg); + pairK0shortPhiBuilder.init(&hRegistry, confCollisionBinning, k0shortSelection, phiSelection, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, v0PosDauSpec, v0NegDauSpec, phiHistSpec, resoPosDauSpec, resoNegDauSpec, pairV0TwoTrackResonanceHistSpec, cprHistSpecPos, cprHistSpecNeg, pairCleanerHistSpec); } // setup for k0short-kstar0 if (doprocessK0shortKstar0SameEvent || doprocessK0shortKstar0MixedEvent) { auto k0shortHistSpec = v0histmanager::makeV0HistSpecMap(confK0shortBinning); auto kstar0HistSpec = twotrackresonancehistmanager::makeTwoTrackResonanceHistSpecMap(confKstar0Binning); - pairK0shortKstar0Builder.init(&hRegistry, confCollisionBinning, k0shortSelection, kstar0Selection, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, v0PosDauSpec, v0NegDauSpec, kstar0HistSpec, resoPosDauSpec, resoNegDauSpec, pairV0TwoTrackResonanceHistSpec, cprHistSpecPos, cprHistSpecNeg); + pairK0shortKstar0Builder.init(&hRegistry, confCollisionBinning, k0shortSelection, kstar0Selection, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, v0PosDauSpec, v0NegDauSpec, kstar0HistSpec, resoPosDauSpec, resoNegDauSpec, pairV0TwoTrackResonanceHistSpec, cprHistSpecPos, cprHistSpecNeg, pairCleanerHistSpec); } // setup for k0short-rho0 if (doprocessK0shortRho0SameEvent || doprocessK0shortRho0MixedEvent) { auto k0shortHistSpec = v0histmanager::makeV0HistSpecMap(confK0shortBinning); auto rho0HistSpec = twotrackresonancehistmanager::makeTwoTrackResonanceHistSpecMap(confRho0Binning); - pairK0shortRho0Builder.init(&hRegistry, confCollisionBinning, k0shortSelection, rho0Selection, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, v0PosDauSpec, v0NegDauSpec, rho0HistSpec, resoPosDauSpec, resoNegDauSpec, pairV0TwoTrackResonanceHistSpec, cprHistSpecPos, cprHistSpecNeg); + pairK0shortRho0Builder.init(&hRegistry, confCollisionBinning, k0shortSelection, rho0Selection, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, v0PosDauSpec, v0NegDauSpec, rho0HistSpec, resoPosDauSpec, resoNegDauSpec, pairV0TwoTrackResonanceHistSpec, cprHistSpecPos, cprHistSpecNeg, pairCleanerHistSpec); } + + hRegistry.print(); } // lambda-phi diff --git a/PWGCF/Femto/Tasks/femtoPairV0V0.cxx b/PWGCF/Femto/Tasks/femtoPairV0V0.cxx index 82ae5b62bb4..dd676c5e43c 100644 --- a/PWGCF/Femto/Tasks/femtoPairV0V0.cxx +++ b/PWGCF/Femto/Tasks/femtoPairV0V0.cxx @@ -18,6 +18,7 @@ #include "PWGCF/Femto/Core/collisionHistManager.h" #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairCleaner.h" #include "PWGCF/Femto/Core/pairHistManager.h" #include "PWGCF/Femto/Core/particleCleaner.h" #include "PWGCF/Femto/Core/partitions.h" @@ -121,6 +122,7 @@ struct FemtoPairV0V0 { // setup pairs pairhistmanager::ConfPairBinning confPairBinning; pairhistmanager::ConfPairCuts confPairCuts; + paircleaner::ConfPairCleanerBinning confPairCleaner; pairbuilder::PairV0V0Builder< v0histmanager::PrefixLambda1, @@ -234,6 +236,7 @@ struct FemtoPairV0V0 { std::map> pairV0V0HistSpec; std::map> cprHistSpecPos = closepairrejection::makeCprHistSpecMap(confCprPos); std::map> cprHistSpecNeg = closepairrejection::makeCprHistSpecMap(confCprNeg); + std::map> pairCleanerHistSpec = paircleaner::makePairCleanerHistSpecMap(confPairCleaner); if (processData) { colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); @@ -246,19 +249,19 @@ struct FemtoPairV0V0 { if (processLambdaLambda) { lambdaHistSpec1 = v0histmanager::makeV0HistSpecMap(confLambdaBinning1); lambdaHistSpec2 = v0histmanager::makeV0HistSpecMap(confLambdaBinning2); - pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection1, confLambdaSelection2, confLambdaCleaner1, confLambdaCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec1, lambdaHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection1, confLambdaSelection2, confLambdaCleaner1, confLambdaCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec1, lambdaHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg, pairCleanerHistSpec); } if (processK0shortK0short) { k0shortHistSpec1 = v0histmanager::makeV0HistSpecMap(confK0shortBinning1); k0shortHistSpec2 = v0histmanager::makeV0HistSpecMap(confK0shortBinning2); - pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection1, confK0shortSelection2, confK0shortCleaner1, confK0shortCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec1, k0shortHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection1, confK0shortSelection2, confK0shortCleaner1, confK0shortCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec1, k0shortHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg, pairCleanerHistSpec); } if (processLambdaK0short) { lambdaHistSpec1 = v0histmanager::makeV0HistSpecMap(confLambdaBinning1); k0shortHistSpec2 = v0histmanager::makeV0HistSpecMap(confK0shortBinning2); - pairLambdaK0shortBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection1, confK0shortSelection2, confLambdaCleaner1, confK0shortCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec1, k0shortHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + pairLambdaK0shortBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection1, confK0shortSelection2, confLambdaCleaner1, confK0shortCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec1, k0shortHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg, pairCleanerHistSpec); } } else { colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); @@ -271,21 +274,22 @@ struct FemtoPairV0V0 { if (processLambdaLambda) { lambdaHistSpec1 = v0histmanager::makeV0McHistSpecMap(confLambdaBinning1); lambdaHistSpec2 = v0histmanager::makeV0McHistSpecMap(confLambdaBinning2); - pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection1, confLambdaSelection2, confLambdaCleaner1, confLambdaCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec1, lambdaHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection1, confLambdaSelection2, confLambdaCleaner1, confLambdaCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec1, lambdaHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg, pairCleanerHistSpec); } if (processK0shortK0short) { k0shortHistSpec1 = v0histmanager::makeV0McHistSpecMap(confK0shortBinning1); k0shortHistSpec2 = v0histmanager::makeV0McHistSpecMap(confK0shortBinning2); - pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection1, confK0shortSelection2, confK0shortCleaner1, confK0shortCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec1, k0shortHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection1, confK0shortSelection2, confK0shortCleaner1, confK0shortCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec1, k0shortHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg, pairCleanerHistSpec); } if (processLambdaK0short) { lambdaHistSpec1 = v0histmanager::makeV0McHistSpecMap(confLambdaBinning1); k0shortHistSpec2 = v0histmanager::makeV0McHistSpecMap(confK0shortBinning2); - pairLambdaK0shortBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection1, confK0shortSelection2, confLambdaCleaner1, confK0shortCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec1, k0shortHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + pairLambdaK0shortBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection1, confK0shortSelection2, confLambdaCleaner1, confK0shortCleaner2, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec1, k0shortHistSpec2, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg, pairCleanerHistSpec); } } + hRegistry.print(); } void processLambdaLambdaSameEvent(FilteredFemtoCollision const& col, FemtoTracks const& tracks, FemtoLambdas const& lambdas) diff --git a/PWGCF/Femto/Tasks/femtoTripletTrackTrackCascade.cxx b/PWGCF/Femto/Tasks/femtoTripletTrackTrackCascade.cxx index fca9c8cad9f..b84c7418248 100644 --- a/PWGCF/Femto/Tasks/femtoTripletTrackTrackCascade.cxx +++ b/PWGCF/Femto/Tasks/femtoTripletTrackTrackCascade.cxx @@ -20,6 +20,7 @@ #include "PWGCF/Femto/Core/collisionBuilder.h" #include "PWGCF/Femto/Core/collisionHistManager.h" #include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/pairCleaner.h" #include "PWGCF/Femto/Core/particleCleaner.h" #include "PWGCF/Femto/Core/partitions.h" #include "PWGCF/Femto/Core/trackBuilder.h" @@ -117,6 +118,7 @@ struct FemtoTripletTrackTrackCascade { // setup triplets triplethistmanager::ConfTripletBinning confTripletBinning; triplethistmanager::ConfTripletCuts confTripletCuts; + paircleaner::ConfPairCleanerBinning confTripletCleanerBinning; closetripletrejection::ConfCtrTrackTrackTrack confCtr; @@ -217,6 +219,7 @@ struct FemtoTripletTrackTrackCascade { std::map> cprHistSpecBachelor = closepairrejection::makeCprHistSpecMap(confCprBachelor); std::map> cprHistSpecV0Daughter = closepairrejection::makeCprHistSpecMap(confCprV0Daughter); std::map> ctrHistSpec = closepairrejection::makeCprHistSpecMap(confCtr); + std::map> tripletCleanerHistSpec = paircleaner::makePairCleanerHistSpecMap(confTripletCleanerBinning); if (processData) { colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); @@ -229,10 +232,10 @@ struct FemtoTripletTrackTrackCascade { if (processXi) { xiHistSpec = cascadehistmanager::makeCascadeHistSpecMap(confXiBinning); - tripletTrackTrackXiBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confTrackCleaner1, confTrackCleaner2, confCtr, confXiSelection, confXiCleaner, confCprBachelor, confCprV0Daughter, confMixing, confTripletBinning, confTripletCuts, colHistSpec, trackHistSpec1, trackHistSpec2, xiHistSpec, bachelorHistSpec, posDauSpec, negDauSpec, tripletTrackTrackCascadeHistSpec, cprHistSpecBachelor, cprHistSpecV0Daughter, ctrHistSpec); + tripletTrackTrackXiBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confTrackCleaner1, confTrackCleaner2, confCtr, confXiSelection, confXiCleaner, confCprBachelor, confCprV0Daughter, confMixing, confTripletBinning, confTripletCuts, colHistSpec, trackHistSpec1, trackHistSpec2, xiHistSpec, bachelorHistSpec, posDauSpec, negDauSpec, tripletTrackTrackCascadeHistSpec, cprHistSpecBachelor, cprHistSpecV0Daughter, ctrHistSpec, tripletCleanerHistSpec); } else { omegaHistSpec = cascadehistmanager::makeCascadeHistSpecMap(confOmegaBinning); - tripletTrackTrackOmegaBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confTrackCleaner1, confTrackCleaner2, confCtr, confOmegaSelection, confOmegaCleaner, confCprBachelor, confCprV0Daughter, confMixing, confTripletBinning, confTripletCuts, colHistSpec, trackHistSpec1, trackHistSpec2, omegaHistSpec, bachelorHistSpec, posDauSpec, negDauSpec, tripletTrackTrackCascadeHistSpec, cprHistSpecBachelor, cprHistSpecV0Daughter, ctrHistSpec); + tripletTrackTrackOmegaBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confTrackCleaner1, confTrackCleaner2, confCtr, confOmegaSelection, confOmegaCleaner, confCprBachelor, confCprV0Daughter, confMixing, confTripletBinning, confTripletCuts, colHistSpec, trackHistSpec1, trackHistSpec2, omegaHistSpec, bachelorHistSpec, posDauSpec, negDauSpec, tripletTrackTrackCascadeHistSpec, cprHistSpecBachelor, cprHistSpecV0Daughter, ctrHistSpec, tripletCleanerHistSpec); } } else { colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); @@ -244,10 +247,10 @@ struct FemtoTripletTrackTrackCascade { tripletTrackTrackCascadeHistSpec = triplethistmanager::makeTripletMcHistSpecMap(confTripletBinning, confMixing); if (processXi) { xiHistSpec = cascadehistmanager::makeCascadeMcHistSpecMap(confXiBinning); - tripletTrackTrackXiBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confTrackCleaner1, confTrackCleaner2, confCtr, confXiSelection, confXiCleaner, confCprBachelor, confCprV0Daughter, confMixing, confTripletBinning, confTripletCuts, colHistSpec, trackHistSpec1, trackHistSpec2, xiHistSpec, bachelorHistSpec, posDauSpec, negDauSpec, tripletTrackTrackCascadeHistSpec, cprHistSpecBachelor, cprHistSpecV0Daughter, ctrHistSpec); + tripletTrackTrackXiBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confTrackCleaner1, confTrackCleaner2, confCtr, confXiSelection, confXiCleaner, confCprBachelor, confCprV0Daughter, confMixing, confTripletBinning, confTripletCuts, colHistSpec, trackHistSpec1, trackHistSpec2, xiHistSpec, bachelorHistSpec, posDauSpec, negDauSpec, tripletTrackTrackCascadeHistSpec, cprHistSpecBachelor, cprHistSpecV0Daughter, ctrHistSpec, tripletCleanerHistSpec); } else { omegaHistSpec = cascadehistmanager::makeCascadeMcHistSpecMap(confOmegaBinning); - tripletTrackTrackOmegaBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confTrackCleaner1, confTrackCleaner2, confCtr, confOmegaSelection, confOmegaCleaner, confCprBachelor, confCprV0Daughter, confMixing, confTripletBinning, confTripletCuts, colHistSpec, trackHistSpec1, trackHistSpec2, omegaHistSpec, bachelorHistSpec, posDauSpec, negDauSpec, tripletTrackTrackCascadeHistSpec, cprHistSpecBachelor, cprHistSpecV0Daughter, ctrHistSpec); + tripletTrackTrackOmegaBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confTrackCleaner1, confTrackCleaner2, confCtr, confOmegaSelection, confOmegaCleaner, confCprBachelor, confCprV0Daughter, confMixing, confTripletBinning, confTripletCuts, colHistSpec, trackHistSpec1, trackHistSpec2, omegaHistSpec, bachelorHistSpec, posDauSpec, negDauSpec, tripletTrackTrackCascadeHistSpec, cprHistSpecBachelor, cprHistSpecV0Daughter, ctrHistSpec, tripletCleanerHistSpec); } } hRegistry.print(); diff --git a/PWGCF/Femto/Tasks/femtoTripletTrackTrackTrack.cxx b/PWGCF/Femto/Tasks/femtoTripletTrackTrackTrack.cxx index cbdbc3e2345..199038f6372 100644 --- a/PWGCF/Femto/Tasks/femtoTripletTrackTrackTrack.cxx +++ b/PWGCF/Femto/Tasks/femtoTripletTrackTrackTrack.cxx @@ -18,6 +18,7 @@ #include "PWGCF/Femto/Core/collisionBuilder.h" #include "PWGCF/Femto/Core/collisionHistManager.h" #include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/pairCleaner.h" #include "PWGCF/Femto/Core/particleCleaner.h" #include "PWGCF/Femto/Core/partitions.h" #include "PWGCF/Femto/Core/trackBuilder.h" @@ -93,6 +94,7 @@ struct FemtoTripletTrackTrackTrack { // setup triplets triplethistmanager::ConfTripletBinning confTripletBinning; triplethistmanager::ConfTripletCuts confTripletCuts; + paircleaner::ConfPairCleanerBinning confTripletCleanerBinning; closetripletrejection::ConfCtrTrackTrackTrack confCtr; @@ -146,6 +148,7 @@ struct FemtoTripletTrackTrackTrack { std::map> trackHistSpec3; std::map> tripletHistSpec; std::map> ctrHistSpec = closepairrejection::makeCprHistSpecMap(confCtr); + std::map> tripletCleanerHistSpec = paircleaner::makePairCleanerHistSpecMap(confTripletCleanerBinning); if (processData) { colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); @@ -153,14 +156,14 @@ struct FemtoTripletTrackTrackTrack { trackHistSpec2 = trackhistmanager::makeTrackHistSpecMap(confTrackBinning2); trackHistSpec3 = trackhistmanager::makeTrackHistSpecMap(confTrackBinning3); tripletHistSpec = triplethistmanager::makeTripletHistSpecMap(confTripletBinning, confMixing); - tripletTrackTrackTrackBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confTrackSelections3, confTrackCleaner1, confTrackCleaner2, confTrackCleaner3, confCtr, confMixing, confTripletBinning, confTripletCuts, colHistSpec, trackHistSpec1, trackHistSpec2, trackHistSpec3, tripletHistSpec, ctrHistSpec); + tripletTrackTrackTrackBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confTrackSelections3, confTrackCleaner1, confTrackCleaner2, confTrackCleaner3, confCtr, confMixing, confTripletBinning, confTripletCuts, colHistSpec, trackHistSpec1, trackHistSpec2, trackHistSpec3, tripletHistSpec, ctrHistSpec, tripletCleanerHistSpec); } else { colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); trackHistSpec1 = trackhistmanager::makeTrackMcHistSpecMap(confTrackBinning1); trackHistSpec2 = trackhistmanager::makeTrackMcHistSpecMap(confTrackBinning2); trackHistSpec3 = trackhistmanager::makeTrackMcHistSpecMap(confTrackBinning3); tripletHistSpec = triplethistmanager::makeTripletMcHistSpecMap(confTripletBinning, confMixing); - tripletTrackTrackTrackBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confTrackSelections3, confTrackCleaner1, confTrackCleaner2, confTrackCleaner3, confCtr, confMixing, confTripletBinning, confTripletCuts, colHistSpec, trackHistSpec1, trackHistSpec2, trackHistSpec3, tripletHistSpec, ctrHistSpec); + tripletTrackTrackTrackBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confTrackSelections3, confTrackCleaner1, confTrackCleaner2, confTrackCleaner3, confCtr, confMixing, confTripletBinning, confTripletCuts, colHistSpec, trackHistSpec1, trackHistSpec2, trackHistSpec3, tripletHistSpec, ctrHistSpec, tripletCleanerHistSpec); } hRegistry.print(); }; diff --git a/PWGCF/Femto/Tasks/femtoTripletTrackTrackV0.cxx b/PWGCF/Femto/Tasks/femtoTripletTrackTrackV0.cxx index 6fe9a688384..aa1610d48e1 100644 --- a/PWGCF/Femto/Tasks/femtoTripletTrackTrackV0.cxx +++ b/PWGCF/Femto/Tasks/femtoTripletTrackTrackV0.cxx @@ -18,6 +18,7 @@ #include "PWGCF/Femto/Core/collisionBuilder.h" #include "PWGCF/Femto/Core/collisionHistManager.h" #include "PWGCF/Femto/Core/modes.h" +#include "PWGCF/Femto/Core/pairCleaner.h" #include "PWGCF/Femto/Core/particleCleaner.h" #include "PWGCF/Femto/Core/partitions.h" #include "PWGCF/Femto/Core/trackBuilder.h" @@ -110,8 +111,9 @@ struct FemtoTripletTrackTrackV0 { // setup triplets triplethistmanager::ConfTripletBinning confTripletBinning; triplethistmanager::ConfTripletCuts confTripletCuts; + paircleaner::ConfPairCleanerBinning confTripletCleanerBinning; - closetripletrejection::ConfCtrTrackTrackTrack confCtr; + closetripletrejection::ConfCtrTrackTrackV0 confCtr; tripletbuilder::TripletTrackTrackV0Builder< modes::V0::kLambda, @@ -119,7 +121,7 @@ struct FemtoTripletTrackTrackV0 { trackhistmanager::PrefixTrack2, v0histmanager::PrefixLambda1, trackhistmanager::PrefixV01PosDaughter, - trackhistmanager::PrefixV02NegDaughter, + trackhistmanager::PrefixV01NegDaughter, triplethistmanager::PrefixTrackTrackLambdaSe, triplethistmanager::PrefixTrackTrackLambdaMe, closetripletrejection::PrefixTrack1Track2Se, @@ -168,6 +170,7 @@ struct FemtoTripletTrackTrackV0 { std::map> lambdaHistSpec; std::map> tripletHistSpec; std::map> ctrHistSpec = closepairrejection::makeCprHistSpecMap(confCtr); + std::map> tripletCleanerHistSpec = paircleaner::makePairCleanerHistSpecMap(confTripletCleanerBinning); if (processData) { colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); @@ -177,7 +180,7 @@ struct FemtoTripletTrackTrackV0 { posDauSpec = trackhistmanager::makeTrackHistSpecMap(confPosDauBinning); negDauSpec = trackhistmanager::makeTrackHistSpecMap(confNegDauBinning); tripletHistSpec = triplethistmanager::makeTripletHistSpecMap(confTripletBinning, confMixing); - tripletTrackTrackLambdaBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confLambdaSelection, confTrackCleaner1, confTrackCleaner2, confLambdaCleaner, confCtr, confMixing, confTripletBinning, confTripletCuts, colHistSpec, trackHistSpec1, trackHistSpec2, lambdaHistSpec, posDauSpec, negDauSpec, tripletHistSpec, ctrHistSpec); + tripletTrackTrackLambdaBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confLambdaSelection, confTrackCleaner1, confTrackCleaner2, confLambdaCleaner, confCtr, confMixing, confTripletBinning, confTripletCuts, colHistSpec, trackHistSpec1, trackHistSpec2, lambdaHistSpec, posDauSpec, negDauSpec, tripletHistSpec, ctrHistSpec, tripletCleanerHistSpec); } else { colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); trackHistSpec1 = trackhistmanager::makeTrackMcHistSpecMap(confTrackBinning1); @@ -186,7 +189,7 @@ struct FemtoTripletTrackTrackV0 { posDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confPosDauBinning); negDauSpec = trackhistmanager::makeTrackMcHistSpecMap(confNegDauBinning); tripletHistSpec = triplethistmanager::makeTripletMcHistSpecMap(confTripletBinning, confMixing); - tripletTrackTrackLambdaBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confLambdaSelection, confTrackCleaner1, confTrackCleaner2, confLambdaCleaner, confCtr, confMixing, confTripletBinning, confTripletCuts, colHistSpec, trackHistSpec1, trackHistSpec2, lambdaHistSpec, posDauSpec, negDauSpec, tripletHistSpec, ctrHistSpec); + tripletTrackTrackLambdaBuilder.init(&hRegistry, confCollisionBinning, confTrackSelections1, confTrackSelections2, confLambdaSelection, confTrackCleaner1, confTrackCleaner2, confLambdaCleaner, confCtr, confMixing, confTripletBinning, confTripletCuts, colHistSpec, trackHistSpec1, trackHistSpec2, lambdaHistSpec, posDauSpec, negDauSpec, tripletHistSpec, ctrHistSpec, tripletCleanerHistSpec); } hRegistry.print(); }; diff --git a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackD0.cxx b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackD0.cxx index 9ee61802ed0..c0cd656cab1 100644 --- a/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackD0.cxx +++ b/PWGCF/FemtoUniverse/Tasks/femtoUniversePairTaskTrackD0.cxx @@ -184,8 +184,8 @@ struct FemtoUniversePairTaskTrackD0 { // Correlated background for D0/D0bar candidates Configurable fillCorrBkgs{"fillCorrBkgs", false, "Fill histograms with correlated background candidates"}; // Configurable to enable filling histograms with BDT scores values - Configurable fillBDTvsPt{"fillBDTvsPt", false, "Fill BDT vs pT histograms for D0/D0bar candidates"}; - Configurable fillBDTvsPtVsMass{"fillBDTvsPtVsMass", true, "Fill BDT vs pT vs mass histograms for D0/D0bar candidates"}; + Configurable fillBDTvsPt{"fillBDTvsPt", true, "Fill BDT vs pT histograms for D0/D0bar candidates"}; + Configurable fillBDTvsPtVsMass{"fillBDTvsPtVsMass", false, "Fill BDT vs pT vs mass histograms for D0/D0bar candidates"}; } ConfFill; // Efficiency Configurable doEfficiencyCorr{"doEfficiencyCorr", false, "Apply efficiency corrections"}; @@ -260,6 +260,7 @@ struct FemtoUniversePairTaskTrackD0 { struct : o2::framework::ConfigurableGroup { ConfigurableAxis thnConfigAxisNonPromptScore{"thnConfigAxisNonPromptScore", {100, 0., 1.}, "Non-prompt score bins"}; ConfigurableAxis thnConfigAxisPromptScore{"thnConfigAxisPromptScore", {100, 0., 1.}, "Prompt score bins"}; + ConfigurableAxis thnConfigAxisBkgScore{"thnConfigAxisBkgScore", {100, 0., 1.}, "Background score bins"}; ConfigurableAxis thnConfigAxisMass{"thnConfigAxisMass", {500, 0., 5.0}, "Cand. inv-mass bins"}; ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {360, 0., 36.}, "Cand. pT bins"}; } ConfThnAxes; @@ -475,9 +476,13 @@ struct FemtoUniversePairTaskTrackD0 { // Axes for THnSparse const AxisSpec thnAxisNonPromptScore{ConfThnAxes.thnConfigAxisNonPromptScore, "BDT score non-prompt"}; const AxisSpec thnAxisPromptScore{ConfThnAxes.thnConfigAxisPromptScore, "BDT score prompt"}; + const AxisSpec thnAxisBkgScore{ConfThnAxes.thnConfigAxisBkgScore, "BDT score background"}; const AxisSpec thnAxisMass{ConfThnAxes.thnConfigAxisMass, "inv. mass (#pi K) (GeV/#it{c}^{2})"}; - const AxisSpec thnAxisPt{ConfThnAxes.thnConfigAxisPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec thnAxisPt{vbins, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec thnAxisPtWiderBins{vFivePtBins, "#it{p}_{T} (GeV/#it{c})"}; std::vector axesTHn = {thnAxisPromptScore, thnAxisNonPromptScore, thnAxisMass, thnAxisPt}; + std::vector axesTHnMc = {thnAxisBkgScore, thnAxisPromptScore, thnAxisNonPromptScore, thnAxisPt}; + std::vector axesTHnFD = {thnAxisBkgScore, thnAxisPromptScore, thnAxisNonPromptScore, thnAxisPtWiderBins}; if (doEfficiencyCorr) { registry.add("D0D0bar_oneMassHypo/hMassVsPtEffCorr", "2-prong candidates;inv. mass (#pi K) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {confInvMassBins, {vbins, "#it{p}_{T} (GeV/#it{c})"}}}); @@ -499,17 +504,18 @@ struct FemtoUniversePairTaskTrackD0 { registry.add("DebugBdt/hBdtScore1", ";BDT score;Entries", {HistType::kTH1F, {axisBdtScore}}); registry.add("DebugBdt/hBdtScore2", ";BDT score;Entries", {HistType::kTH1F, {axisBdtScore}}); if (ConfFill.fillBDTvsPt) { - registry.add("DebugBdtMcReco/hBdtScore0VsPt", ";BDT score;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisBdtScore, {vbins}}}); - registry.add("DebugBdtMcReco/hBdtScore1VsPt", ";BDT score;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisBdtScore, {vbins}}}); - registry.add("DebugBdtMcReco/hBdtScore2VsPt", ";BDT score;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisBdtScore, {vbins}}}); - registry.add("DebugBdtMcReco/hBdtScore1VsPtD0Prompt", ";BDT score;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisBdtScore, {vFivePtBins}}}); - registry.add("DebugBdtMcReco/hBdtScore1VsPtD0NonPrompt", ";BDT score;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisBdtScore, {vFivePtBins}}}); - registry.add("DebugBdtMcReco/hBdtScore1VsPtD0barPrompt", ";BDT score;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisBdtScore, {vFivePtBins}}}); - registry.add("DebugBdtMcReco/hBdtScore1VsPtD0barNonPrompt", ";BDT score;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisBdtScore, {vFivePtBins}}}); - registry.add("DebugBdtMcReco/hBdtScore2VsPtD0Prompt", ";BDT score;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisBdtScore, {vFivePtBins}}}); - registry.add("DebugBdtMcReco/hBdtScore2VsPtD0NonPrompt", ";BDT score;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisBdtScore, {vFivePtBins}}}); - registry.add("DebugBdtMcReco/hBdtScore2VsPtD0barPrompt", ";BDT score;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisBdtScore, {vFivePtBins}}}); - registry.add("DebugBdtMcReco/hBdtScore2VsPtD0barNonPrompt", ";BDT score;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisBdtScore, {vFivePtBins}}}); + registry.add("DebugBdtMcReco/hBdtScoresVsPtD0", "Thn for reconstructed D0 candidates", HistType::kTHnSparseD, axesTHnMc); + registry.get(HIST("DebugBdtMcReco/hBdtScoresVsPtD0"))->Sumw2(); + registry.add("DebugBdtMcReco/hBdtScoresVsPtD0bar", "Thn for reconstructed D0bar candidates", HistType::kTHnSparseD, axesTHnMc); + registry.get(HIST("DebugBdtMcReco/hBdtScoresVsPtD0bar"))->Sumw2(); + registry.add("DebugBdtMcReco/hBdtScoresVsPtPromptD0", "Thn for reconstructed prompt D0 candidates", HistType::kTHnSparseD, axesTHnFD); + registry.get(HIST("DebugBdtMcReco/hBdtScoresVsPtPromptD0"))->Sumw2(); + registry.add("DebugBdtMcReco/hBdtScoresVsPtNonPromptD0", "Thn for reconstructed non-prompt D0 candidates", HistType::kTHnSparseD, axesTHnFD); + registry.get(HIST("DebugBdtMcReco/hBdtScoresVsPtNonPromptD0"))->Sumw2(); + registry.add("DebugBdtMcReco/hBdtScoresVsPtPromptD0bar", "Thn for reconstructed prompt D0bar candidates", HistType::kTHnSparseD, axesTHnFD); + registry.get(HIST("DebugBdtMcReco/hBdtScoresVsPtPromptD0bar"))->Sumw2(); + registry.add("DebugBdtMcReco/hBdtScoresVsPtNonPromptD0bar", "Thn for reconstructed non-prompt D0bar candidates", HistType::kTHnSparseD, axesTHnFD); + registry.get(HIST("DebugBdtMcReco/hBdtScoresVsPtNonPromptD0bar"))->Sumw2(); } if (ConfFill.fillBDTvsPtVsMass) { registry.add("DebugBdt/hBdtScoresVsMassVsPtD0", "Thn for D0 candidates", HistType::kTHnSparseD, axesTHn); @@ -1330,52 +1336,46 @@ struct FemtoUniversePairTaskTrackD0 { } } } - } else if ((part.partType() == aod::femtouniverseparticle::ParticleType::kD0) && (part.pt() > ConfDmesons.confMinPtD0D0barReco) && (part.pt() < ConfDmesons.confMaxPtD0D0barReco)) { - if (ConfFill.fillBDTvsPt && std::abs(mcpart.pdgMCTruth()) == o2::constants::physics::Pdg::kD0) { - registry.fill(HIST("DebugBdtMcReco/hBdtScore0VsPt"), part.decayVtxX(), part.pt()); - registry.fill(HIST("DebugBdtMcReco/hBdtScore1VsPt"), part.decayVtxY(), part.pt()); - registry.fill(HIST("DebugBdtMcReco/hBdtScore2VsPt"), part.decayVtxZ(), part.pt()); - } + } else if ((part.partType() == aod::femtouniverseparticle::ParticleType::kD0) && (part.pt() > ConfDmesons.confMinPtD0D0barReco) && (part.pt() < ConfDmesons.confMaxPtD0D0barReco) && (part.decayVtxZ() < ConfMlProb.confMlProbNonPromptMax)) { + if (mcpart.pdgMCTruth() == ConfDmesons.confPDGCodeD0) { mcRecoRegistry.fill(HIST("hMcRecD0"), part.pt(), part.eta()); mcRecoRegistry.fill(HIST("hMcRecD0Pt"), part.pt()); mcRecoRegistry.fill(HIST("hMcRecD0Phi"), part.phi()); + registry.fill(HIST("DebugBdtMcReco/hBdtScoresVsPtD0"), part.decayVtxX(), part.decayVtxY(), part.decayVtxZ(), part.pt()); if (part.tpcNClsFound() == 0) { // prompt candidates mcRecoRegistry.fill(HIST("hMcRecD0Prompt"), part.pt(), part.eta()); mcRecoRegistry.fill(HIST("hMcRecD0PromptPt"), part.pt()); mcRecoRegistry.fill(HIST("hMcRecD0PromptPhi"), part.phi()); if (ConfFill.fillBDTvsPt) { - registry.fill(HIST("DebugBdtMcReco/hBdtScore1VsPtD0Prompt"), part.decayVtxY(), part.pt()); - registry.fill(HIST("DebugBdtMcReco/hBdtScore2VsPtD0Prompt"), part.decayVtxZ(), part.pt()); + registry.fill(HIST("DebugBdtMcReco/hBdtScoresVsPtPromptD0"), part.decayVtxX(), part.decayVtxY(), part.decayVtxZ(), part.pt()); } } else if (part.tpcNClsFound() == 1) { // non-prompt candidates mcRecoRegistry.fill(HIST("hMcRecD0NonPrompt"), part.pt(), part.eta()); mcRecoRegistry.fill(HIST("hMcRecD0NonPromptPt"), part.pt()); mcRecoRegistry.fill(HIST("hMcRecD0NonPromptPhi"), part.phi()); if (ConfFill.fillBDTvsPt) { - registry.fill(HIST("DebugBdtMcReco/hBdtScore1VsPtD0NonPrompt"), part.decayVtxY(), part.pt()); - registry.fill(HIST("DebugBdtMcReco/hBdtScore2VsPtD0NonPrompt"), part.decayVtxZ(), part.pt()); + registry.fill(HIST("DebugBdtMcReco/hBdtScoresVsPtNonPromptD0"), part.decayVtxX(), part.decayVtxY(), part.decayVtxZ(), part.pt()); } } } else if (mcpart.pdgMCTruth() == ConfDmesons.confPDGCodeD0bar) { mcRecoRegistry.fill(HIST("hMcRecD0bar"), part.pt(), part.eta()); mcRecoRegistry.fill(HIST("hMcRecD0barPt"), part.pt()); mcRecoRegistry.fill(HIST("hMcRecD0barPhi"), part.phi()); + registry.fill(HIST("DebugBdtMcReco/hBdtScoresVsPtD0bar"), part.decayVtxX(), part.decayVtxY(), part.decayVtxZ(), part.pt()); if (part.tpcNClsFound() == 0) { // prompt candidates mcRecoRegistry.fill(HIST("hMcRecD0barPrompt"), part.pt(), part.eta()); mcRecoRegistry.fill(HIST("hMcRecD0barPromptPt"), part.pt()); if (ConfFill.fillBDTvsPt) { - registry.fill(HIST("DebugBdtMcReco/hBdtScore1VsPtD0barPrompt"), part.decayVtxY(), part.pt()); - registry.fill(HIST("DebugBdtMcReco/hBdtScore2VsPtD0barPrompt"), part.decayVtxZ(), part.pt()); + registry.fill(HIST("DebugBdtMcReco/hBdtScoresVsPtNonPromptD0bar"), part.decayVtxX(), part.decayVtxY(), part.decayVtxZ(), part.pt()); } } else if (part.tpcNClsFound() == 1) { // non-prompt candidates mcRecoRegistry.fill(HIST("hMcRecD0barNonPrompt"), part.pt(), part.eta()); mcRecoRegistry.fill(HIST("hMcRecD0barNonPromptPt"), part.pt()); if (ConfFill.fillBDTvsPt) { - registry.fill(HIST("DebugBdtMcReco/hBdtScore1VsPtD0barNonPrompt"), part.decayVtxY(), part.pt()); - registry.fill(HIST("DebugBdtMcReco/hBdtScore2VsPtD0barNonPrompt"), part.decayVtxZ(), part.pt()); + registry.fill(HIST("DebugBdtMcReco/hBdtScoresVsPtNonPromptD0bar"), part.decayVtxX(), part.decayVtxY(), part.decayVtxZ(), part.pt()); } } } diff --git a/PWGCF/FemtoWorld/Tasks/femtoPairLambdaAntilambda.cxx b/PWGCF/FemtoWorld/Tasks/femtoPairLambdaAntilambda.cxx index 3fe9e5071d1..97f8b7ec190 100644 --- a/PWGCF/FemtoWorld/Tasks/femtoPairLambdaAntilambda.cxx +++ b/PWGCF/FemtoWorld/Tasks/femtoPairLambdaAntilambda.cxx @@ -19,6 +19,7 @@ #include "PWGCF/Femto/Core/collisionHistManager.h" #include "PWGCF/Femto/Core/modes.h" #include "PWGCF/Femto/Core/pairBuilder.h" +#include "PWGCF/Femto/Core/pairCleaner.h" #include "PWGCF/Femto/Core/pairHistManager.h" #include "PWGCF/Femto/Core/particleCleaner.h" #include "PWGCF/Femto/Core/partitions.h" @@ -108,6 +109,7 @@ struct FemtoPairLambdaAntilambda { // setup pairs pairhistmanager::ConfPairBinning confPairBinning; pairhistmanager::ConfPairCuts confPairCuts; + paircleaner::ConfPairCleanerBinning confPairCleaner; pairbuilder::PairV0V0Builder< v0histmanager::PrefixLambda1, @@ -186,6 +188,7 @@ struct FemtoPairLambdaAntilambda { std::map> pairV0V0HistSpec; std::map> cprHistSpecPos = closepairrejection::makeCprHistSpecMap(confCprPos); std::map> cprHistSpecNeg = closepairrejection::makeCprHistSpecMap(confCprNeg); + std::map> pairCleanerHistSpec = paircleaner::makePairCleanerHistSpecMap(confPairCleaner); if (processData) { colHistSpec = colhistmanager::makeColHistSpecMap(confCollisionBinning); @@ -197,12 +200,12 @@ struct FemtoPairLambdaAntilambda { if (processLambdaLambda) { lambdaHistSpec = v0histmanager::makeV0HistSpecMap(confLambdaBinning); - pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confLambdaSelection2, confLambdaCleaner, confLambdaCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, lambdaHistSpec, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confLambdaSelection2, confLambdaCleaner, confLambdaCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, lambdaHistSpec, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg, pairCleanerHistSpec); } if (processK0shortK0short) { k0shortHistSpec = v0histmanager::makeV0HistSpecMap(confK0shortBinning); - pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection, confK0shortSelection, confK0shortCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, k0shortHistSpec, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection, confK0shortSelection, confK0shortCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, k0shortHistSpec, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg, pairCleanerHistSpec); } } else { colHistSpec = colhistmanager::makeColMcHistSpecMap(confCollisionBinning); @@ -214,12 +217,12 @@ struct FemtoPairLambdaAntilambda { if (processLambdaLambda) { lambdaHistSpec = v0histmanager::makeV0McHistSpecMap(confLambdaBinning); - pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confLambdaSelection2, confLambdaCleaner, confLambdaCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, lambdaHistSpec, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + pairLambdaLambdaBuilder.init(&hRegistry, confCollisionBinning, confLambdaSelection, confLambdaSelection2, confLambdaCleaner, confLambdaCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, lambdaHistSpec, lambdaHistSpec, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg, pairCleanerHistSpec); } if (processK0shortK0short) { k0shortHistSpec = v0histmanager::makeV0McHistSpecMap(confK0shortBinning); - pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection, confK0shortSelection, confK0shortCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, k0shortHistSpec, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg); + pairK0shortK0shortBuilder.init(&hRegistry, confCollisionBinning, confK0shortSelection, confK0shortSelection, confK0shortCleaner, confK0shortCleaner, confCprPos, confCprNeg, confMixing, confPairBinning, confPairCuts, colHistSpec, k0shortHistSpec, k0shortHistSpec, posDauSpec1, negDauSpec1, posDauSpec2, negDauSpec2, pairV0V0HistSpec, cprHistSpecPos, cprHistSpecNeg, pairCleanerHistSpec); } } } diff --git a/PWGCF/Flow/Tasks/flowEseTask.cxx b/PWGCF/Flow/Tasks/flowEseTask.cxx index 20553572aa7..b5cfe97f7b4 100644 --- a/PWGCF/Flow/Tasks/flowEseTask.cxx +++ b/PWGCF/Flow/Tasks/flowEseTask.cxx @@ -9,12 +9,14 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \author Junlee Kim (jikim1290@gmail.com) +/// \author Junlee Kim (jikim1290@gmail.com) & Shiqi Wang(shiqi.wang@cern.ch) /// \file flowEseTask.cxx /// \brief Task for flow and event shape engineering correlation with other observation. /// \since 2023-05-15 /// \version 1.0 +#include "PWGCF/GenericFramework/Core/GFW.h" +#include "PWGCF/GenericFramework/Core/GFWWeights.h" #include "PWGLF/DataModel/LFStrangenessTables.h" #include "PWGMM/Mult/DataModel/Index.h" // for Particles2Tracks table @@ -46,6 +48,7 @@ #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) #include #include +#include #include #include #include @@ -146,6 +149,13 @@ struct FlowEseTask { Configurable cfgAccCor{"cfgAccCor", false, "flag to apply acceptance correction"}; Configurable cfgAccCorPath{"cfgAccCorPath", "", "path for pseudo acceptance correction"}; + struct : ConfigurableGroup { + Configurable cfgGfwEffCor{"cfgGfwEffCor", false, "flag to apply charged-track efficiency correction for GFW"}; + Configurable cfgGfwEffCorPath{"cfgGfwEffCorPath", "", "CCDB path to charged-track efficiency correction for GFW"}; + Configurable cfgGfwAccCor{"cfgGfwAccCor", false, "flag to apply charged-track acceptance correction for GFW"}; + Configurable cfgGfwAccCorPath{"cfgGfwAccCorPath", "", "CCDB path to charged-track acceptance correction for GFW"}; + } cfgGfwParam; + Configurable cfgCalcCum{"cfgCalcCum", false, "flag to calculate cumulants of cossin"}; Configurable cfgCalcCum1{"cfgCalcCum1", false, "flag to calculate cumulants of coscos"}; @@ -188,6 +198,8 @@ struct FlowEseTask { static constexpr int NEseCentBins = 8; static constexpr int NEseGroups = 10; static constexpr int NEseCutsPerCentBin = NEseGroups - 1; + static constexpr int GFWRefMask = 1; + static constexpr int GFWPoiMask = 2; static constexpr float EseCentMin = 0.0f; static constexpr float EseCentMax = 80.0f; static constexpr float EseCentBinWidth = 10.0f; @@ -220,6 +232,21 @@ struct FlowEseTask { std::vector shiftprofile; TProfile2D* effMap = nullptr; TProfile2D* accMap = nullptr; + struct { + int lastGfwCorrectionRunNumber = -999; + TH1D* gfwEffMap = nullptr; + GFWWeights* gfwAccWeights = nullptr; + TProfile2D* histRefQn = nullptr; + TProfile3D* histPoiNQn = nullptr; + TProfile3D* histPoiPQn = nullptr; + GFW* fGFW = new GFW(); + GFW::CorrConfig corrRef22; + GFW::CorrConfig corrPoiN22; + GFW::CorrConfig corrPoiP22; + GFW::CorrConfig corrRef32; + GFW::CorrConfig corrPoiN32; + GFW::CorrConfig corrPoiP32; + } gfwState; std::string fullCCDBShiftCorrPath; @@ -362,6 +389,15 @@ struct FlowEseTask { } histos.add("QA/CentDist", "", {HistType::kTH1F, {centQaAxis}}); histos.add("QA/PVzDist", "", {HistType::kTH1F, {pVzQaAxis}}); + histos.add("psi2/h_Ref03Gap22", "", {HistType::kTProfile, {centAxis}}); + histos.add("psi2/h_PoiN03Gap22", "", {HistType::kTProfile2D, {ptAxis, centAxis}}); + histos.add("psi2/h_PoiP03Gap22", "", {HistType::kTProfile2D, {ptAxis, centAxis}}); + histos.add("psi3/h_Ref03Gap32", "", {HistType::kTProfile, {centAxis}}); + histos.add("psi3/h_PoiN03Gap32", "", {HistType::kTProfile2D, {ptAxis, centAxis}}); + histos.add("psi3/h_PoiP03Gap32", "", {HistType::kTProfile2D, {ptAxis, centAxis}}); + gfwState.histRefQn = histos.add(Form("psi%d/h_Ref03Gap%d2VsQ%d", cfgEseHarmonic.value, cfgEseHarmonic.value, cfgEseHarmonic.value), "", HistType::kTProfile2D, {centAxis, eseGroupAxis}).get(); + gfwState.histPoiNQn = histos.add(Form("psi%d/h_PoiN03Gap%d2VsQ%d", cfgEseHarmonic.value, cfgEseHarmonic.value, cfgEseHarmonic.value), "", HistType::kTProfile3D, {ptAxis, centAxis, eseGroupAxis}).get(); + gfwState.histPoiPQn = histos.add(Form("psi%d/h_PoiP03Gap%d2VsQ%d", cfgEseHarmonic.value, cfgEseHarmonic.value, cfgEseHarmonic.value), "", HistType::kTProfile3D, {ptAxis, centAxis, eseGroupAxis}).get(); for (auto i = 2; i < cfgnMods + 2; i++) { histos.add(Form("psi%d/h_lambda_cos", i), "", {HistType::kTHnSparseF, {massAxis, ptAxis, cosAxis, centAxis, epAxis}}); @@ -533,6 +569,21 @@ struct FlowEseTask { fMultPVCutHigh = new TF1("fMultPVCutHigh", "[0]+[1]*x+[2]*x*x+[3]*x*x*x + 2.5*([4]+[5]*x+[6]*x*x+[7]*x*x*x+[8]*x*x*x*x)", 0, 100); fMultPVCutHigh->SetParameters(2834.66, -87.0127, 0.915126, -0.00330136, 332.513, -12.3476, 0.251663, -0.00272819, 1.12242e-05); + const int nPtBins = histos.get(HIST("psi2/h_PoiN03Gap22"))->GetXaxis()->GetNbins(); + gfwState.fGFW->AddRegion("refN03", -0.8, -0.15, 1, GFWRefMask); + gfwState.fGFW->AddRegion("refP03", 0.15, 0.8, 1, GFWRefMask); + gfwState.fGFW->AddRegion("poiN03", -0.8, -0.15, nPtBins + 1, GFWPoiMask); + gfwState.fGFW->AddRegion("poiP03", 0.15, 0.8, nPtBins + 1, GFWPoiMask); + + gfwState.corrRef22 = gfwState.fGFW->GetCorrelatorConfig("refN03 {2} refP03 {-2}", "Ref03Gap22", false); + gfwState.corrPoiN22 = gfwState.fGFW->GetCorrelatorConfig("poiN03 {2} refP03 {-2}", "PoiN03Gap22", true); + gfwState.corrPoiP22 = gfwState.fGFW->GetCorrelatorConfig("poiP03 {2} refN03 {-2}", "PoiP03Gap22", true); + gfwState.corrRef32 = gfwState.fGFW->GetCorrelatorConfig("refN03 {3} refP03 {-3}", "Ref03Gap32", false); + gfwState.corrPoiN32 = gfwState.fGFW->GetCorrelatorConfig("poiN03 {3} refP03 {-3}", "PoiN03Gap32", true); + gfwState.corrPoiP32 = gfwState.fGFW->GetCorrelatorConfig("poiP03 {3} refN03 {-3}", "PoiP03Gap32", true); + + gfwState.fGFW->CreateRegions(); + ccdb->setURL(cfgCcdbParam.cfgURL); ccdbApi.init("http://alice-ccdb.cern.ch"); ccdb->setCaching(true); @@ -878,24 +929,122 @@ struct FlowEseTask { } template - void fillHistograms(TCollision const& collision, V0 const& V0s, TrackType const& track, int nmode, int eseGroupIndex = -1, bool fillRegular = true) + void fillHistograms(TCollision const& collision, V0 const& V0s, TrackType const& track, int nmode, int eseGroupIndex = -1, bool fillRegular = true, bool fillGfw = false) { qvecDetInd = detId * 4 + 3 + (nmode - 2) * cfgNQvec * 4; qvecRefAInd = refAId * 4 + 3 + (nmode - 2) * cfgNQvec * 4; qvecRefBInd = refBId * 4 + 3 + (nmode - 2) * cfgNQvec * 4; const bool fillEse = eseGroupIndex >= 0 && nmode == cfgEseHarmonic.value; + THnSparse* histEseVn = nullptr; + double esePlane = 0.0; if (fillEse) { const auto suffix = eseGroupSuffix(eseGroupIndex); - auto* histEseVn = getEseHistogram(Form("histV%d_%s", cfgEseHarmonic.value, suffix.c_str())); + histEseVn = getEseHistogram(Form("histV%d_%s", cfgEseHarmonic.value, suffix.c_str())); const int harmonicIndex = nmode - 2; - const double esePlane = helperEP.GetEventPlane(collision.qvecFT0CReVec()[harmonicIndex], collision.qvecFT0CImVec()[harmonicIndex], nmode); + esePlane = helperEP.GetEventPlane(collision.qvecFT0CReVec()[harmonicIndex], collision.qvecFT0CImVec()[harmonicIndex], nmode); + } + + TProfile2D* histPoiN22 = nullptr; + if (fillGfw) { + gfwState.fGFW->Clear(); + histPoiN22 = histos.get(HIST("psi2/h_PoiN03Gap22")).get(); + } + if (fillEse || fillGfw) { for (const auto& trk : track) { if (!selectionTrack(trk)) { continue; } - const std::array values = {centrality, trk.pt(), std::cos(static_cast(nmode) * (trk.phi() - esePlane))}; - histEseVn->Fill(values.data()); + if (fillEse) { + const std::array values = {centrality, trk.pt(), std::cos(static_cast(nmode) * (trk.phi() - esePlane))}; + histEseVn->Fill(values.data()); + } + if (!fillGfw) { + continue; + } + double weff = 1.0; + double wacc = 1.0; + if (cfgGfwParam.cfgGfwEffCor && gfwState.gfwEffMap != nullptr) { + const double efficiency = gfwState.gfwEffMap->GetBinContent(gfwState.gfwEffMap->FindBin(trk.pt())); + if (efficiency <= 0.0) { + continue; + } + weff = 1.0 / efficiency; + } + if (cfgGfwParam.cfgGfwAccCor && gfwState.gfwAccWeights != nullptr) { + wacc = gfwState.gfwAccWeights->getNUA(trk.phi(), trk.eta(), collision.posZ()); + } + const double trackWeight = weff * wacc; + const int ptBin = histPoiN22->GetXaxis()->FindBin(trk.pt()) - 1; + gfwState.fGFW->Fill(trk.eta(), ptBin, trk.phi(), trackWeight, GFWRefMask); + gfwState.fGFW->Fill(trk.eta(), ptBin, trk.phi(), trackWeight, GFWPoiMask); + } + } + + if (fillGfw) { + double denominator = gfwState.fGFW->Calculate(gfwState.corrRef22, 0, true).real(); + if (denominator > 0.0) { + const double correlation = gfwState.fGFW->Calculate(gfwState.corrRef22, 0, false).real() / denominator; + if (std::abs(correlation) < 1.0) { + histos.fill(HIST("psi2/h_Ref03Gap22"), centrality, correlation, denominator); + if (fillEse && cfgEseHarmonic.value == SecondHarmonic) { + gfwState.histRefQn->Fill(centrality, eseGroupIndex + 0.5, correlation, denominator); + } + } + } + denominator = gfwState.fGFW->Calculate(gfwState.corrRef32, 0, true).real(); + if (denominator > 0.0) { + const double correlation = gfwState.fGFW->Calculate(gfwState.corrRef32, 0, false).real() / denominator; + if (std::abs(correlation) < 1.0) { + histos.fill(HIST("psi3/h_Ref03Gap32"), centrality, correlation, denominator); + if (fillEse && cfgEseHarmonic.value == ThirdHarmonic) { + gfwState.histRefQn->Fill(centrality, eseGroupIndex + 0.5, correlation, denominator); + } + } + } + + for (int iPt = 1; iPt <= histPoiN22->GetXaxis()->GetNbins(); ++iPt) { + const double pt = histPoiN22->GetXaxis()->GetBinCenter(iPt); + denominator = gfwState.fGFW->Calculate(gfwState.corrPoiN22, iPt - 1, true).real(); + if (denominator > 0.0) { + const double correlation = gfwState.fGFW->Calculate(gfwState.corrPoiN22, iPt - 1, false).real() / denominator; + if (std::abs(correlation) < 1.0) { + histos.fill(HIST("psi2/h_PoiN03Gap22"), pt, centrality, correlation, denominator); + if (fillEse && cfgEseHarmonic.value == SecondHarmonic) { + gfwState.histPoiNQn->Fill(pt, centrality, eseGroupIndex + 0.5, correlation, denominator); + } + } + } + denominator = gfwState.fGFW->Calculate(gfwState.corrPoiP22, iPt - 1, true).real(); + if (denominator > 0.0) { + const double correlation = gfwState.fGFW->Calculate(gfwState.corrPoiP22, iPt - 1, false).real() / denominator; + if (std::abs(correlation) < 1.0) { + histos.fill(HIST("psi2/h_PoiP03Gap22"), pt, centrality, correlation, denominator); + if (fillEse && cfgEseHarmonic.value == SecondHarmonic) { + gfwState.histPoiPQn->Fill(pt, centrality, eseGroupIndex + 0.5, correlation, denominator); + } + } + } + denominator = gfwState.fGFW->Calculate(gfwState.corrPoiN32, iPt - 1, true).real(); + if (denominator > 0.0) { + const double correlation = gfwState.fGFW->Calculate(gfwState.corrPoiN32, iPt - 1, false).real() / denominator; + if (std::abs(correlation) < 1.0) { + histos.fill(HIST("psi3/h_PoiN03Gap32"), pt, centrality, correlation, denominator); + if (fillEse && cfgEseHarmonic.value == ThirdHarmonic) { + gfwState.histPoiNQn->Fill(pt, centrality, eseGroupIndex + 0.5, correlation, denominator); + } + } + } + denominator = gfwState.fGFW->Calculate(gfwState.corrPoiP32, iPt - 1, true).real(); + if (denominator > 0.0) { + const double correlation = gfwState.fGFW->Calculate(gfwState.corrPoiP32, iPt - 1, false).real() / denominator; + if (std::abs(correlation) < 1.0) { + histos.fill(HIST("psi3/h_PoiP03Gap32"), pt, centrality, correlation, denominator); + if (fillEse && cfgEseHarmonic.value == ThirdHarmonic) { + gfwState.histPoiPQn->Fill(pt, centrality, eseGroupIndex + 0.5, correlation, denominator); + } + } + } } } @@ -1261,12 +1410,28 @@ struct FlowEseTask { if (cfgAccCor) { accMap = ccdb->getForTimeStamp(cfgAccCorPath.value, bc.timestamp()); } + if (bc.runNumber() != gfwState.lastGfwCorrectionRunNumber) { + if (cfgGfwParam.cfgGfwEffCor && !cfgGfwParam.cfgGfwEffCorPath.value.empty()) { + gfwState.gfwEffMap = ccdb->getForTimeStamp(cfgGfwParam.cfgGfwEffCorPath.value, bc.timestamp()); + if (gfwState.gfwEffMap == nullptr) { + LOGF(fatal, "Could not load charged-track efficiency histogram from %s", cfgGfwParam.cfgGfwEffCorPath.value.c_str()); + } + } + if (cfgGfwParam.cfgGfwAccCor && !cfgGfwParam.cfgGfwAccCorPath.value.empty()) { + gfwState.gfwAccWeights = ccdb->getForTimeStamp(cfgGfwParam.cfgGfwAccCorPath.value, bc.timestamp()); + if (gfwState.gfwAccWeights == nullptr) { + LOGF(fatal, "Could not load charged-track acceptance weights from %s", cfgGfwParam.cfgGfwAccCorPath.value.c_str()); + } + } + gfwState.lastGfwCorrectionRunNumber = bc.runNumber(); + } + fillEseEPQA(collision, eseGroupIndex); if (cfgShiftCorrDef && cfgEseHarmonic.value >= cfgnMods.value + 2) { fillShiftCorrection(collision, cfgEseHarmonic.value); } if (eseGroupIndex >= 0 && cfgEseHarmonic.value >= cfgnMods.value + 2) { - fillHistograms(collision, V0s, tracks, cfgEseHarmonic.value, eseGroupIndex, false); + fillHistograms(collision, V0s, tracks, cfgEseHarmonic.value, eseGroupIndex, false, true); } for (int i = 2; i < cfgnMods + 2; i++) { if (cfgShiftCorrDef) { @@ -1275,7 +1440,8 @@ struct FlowEseTask { if (cfgQAv0) { fillEPQA(collision, i); } - fillHistograms(collision, V0s, tracks, i, i == cfgEseHarmonic.value ? eseGroupIndex : -1); + const bool fillGfw = eseGroupIndex >= 0 ? i == cfgEseHarmonic.value : i == SecondHarmonic; + fillHistograms(collision, V0s, tracks, i, i == cfgEseHarmonic.value ? eseGroupIndex : -1, true, fillGfw); } // FIXME: need to fill different histograms for different harmonic } PROCESS_SWITCH(FlowEseTask, processData, "Process Event for data", true); diff --git a/PWGCF/Flow/Tasks/flowTask.cxx b/PWGCF/Flow/Tasks/flowTask.cxx index bb30eddfe97..cc52045a35b 100644 --- a/PWGCF/Flow/Tasks/flowTask.cxx +++ b/PWGCF/Flow/Tasks/flowTask.cxx @@ -1478,7 +1478,7 @@ struct FlowTask { registry.fill(HIST("hMeanPt"), independent, ptSum / weffEvent, weffEvent); } if (weffEventWithinGap08) - registry.fill(HIST("hMeanPtWithinGap08"), independent, ptSum_Gap08 / weffEventWithinGap08, 1.0); + registry.fill(HIST("hMeanPtWithinGap08"), independent, ptSum_Gap08 / weffEventWithinGap08, cfgUserIO.cfgUserPtVnEvWeightEnabled ? weffEventWithinGap08 : 1.); if (weffEventWithinGap08) bootstrapArray[sampleIndex][kMeanPtWithinGap08]->Fill(independent, ptSum_Gap08 / weffEventWithinGap08, 1.0); // c22_gap8 * pt_withGap8 @@ -1583,7 +1583,7 @@ struct FlowTask { } if (count_Gap08 > 0) - registry.fill(HIST("hMeanPtWithinGap08_MC"), independent, ptSum_Gap08 / count_Gap08, 1.0); + registry.fill(HIST("hMeanPtWithinGap08_MC"), independent, ptSum_Gap08 / count_Gap08, cfgUserIO.cfgUserPtVnEvWeightEnabled ? count_Gap08 : 1.); int sampleIndex = static_cast(cfgNbootstrap * lRandom); if (count_Gap08 > 0) bootstrapArray[sampleIndex][kMeanPtWithinGap08_MC]->Fill(independent, ptSum_Gap08 / count_Gap08, 1.0); diff --git a/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx b/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx index 6f5cedf0485..fd4e1075e27 100644 --- a/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx +++ b/PWGCF/Flow/Tasks/pidFlowPtCorr.cxx @@ -3748,8 +3748,8 @@ struct PidFlowPtCorr { PROCESS_SWITCH(PidFlowPtCorr, processMCClosure, "Run truth-level MC flow closure", false); /** - * @brief this function is used to fill THn hist for NUA correction and for NUE correction - * @details hist THn: (runNumberIDX, phi, eta, Vz), note that different runNumber will be put in the same hist + * @brief Fill THnSparse histograms used to derive NUA weights + * @details Histograms use (runNumberIDX, phi, eta, Vz, pT); cfgUseNUAWithPt enables NUE weighting before filling * * @param collision * @param tracks @@ -3780,6 +3780,10 @@ struct PidFlowPtCorr { } // end collision cut + if (switchsOpts.cfgUseNUAWithPt.value) { + loadCorrections(bc.timestamp()); + } + // loop the vector, find the place to put (phi eta Vz) // if the run number is new, create one int matchedPosition = -1; @@ -3816,24 +3820,32 @@ struct PidFlowPtCorr { // fill the THn if (isWithinRefPtRange(track.pt())) { - registry.fill(HIST("correction/hRunNumberPhiEtaVertex"), matchedPosition, track.phi(), track.eta(), collision.posZ(), track.pt()); + float weightNUE = 1.f; + if (switchsOpts.cfgUseNUAWithPt.value) { + setParticleNUEWeight(weightNUE, track, cent); + } + registry.fill(HIST("correction/hRunNumberPhiEtaVertex"), matchedPosition, track.phi(), track.eta(), collision.posZ(), track.pt(), weightNUE); } int pid = this->getPidConfigurable(track); if (!isWithinPOIPtRange(pid, track.pt())) { continue; } + float weightNUEPid = 1.f; + if (switchsOpts.cfgUseNUAWithPt.value) { + setParticleNUEWeight(weightNUEPid, track, cent, pid); + } switch (pid) { case MyParticleType::kPion: - registry.fill(HIST("correction/hRunNumberPhiEtaVertexPion"), matchedPosition, track.phi(), track.eta(), collision.posZ(), track.pt()); + registry.fill(HIST("correction/hRunNumberPhiEtaVertexPion"), matchedPosition, track.phi(), track.eta(), collision.posZ(), track.pt(), weightNUEPid); break; case MyParticleType::kKaon: - registry.fill(HIST("correction/hRunNumberPhiEtaVertexKaon"), matchedPosition, track.phi(), track.eta(), collision.posZ(), track.pt()); + registry.fill(HIST("correction/hRunNumberPhiEtaVertexKaon"), matchedPosition, track.phi(), track.eta(), collision.posZ(), track.pt(), weightNUEPid); break; case MyParticleType::kProton: - registry.fill(HIST("correction/hRunNumberPhiEtaVertexProton"), matchedPosition, track.phi(), track.eta(), collision.posZ(), track.pt()); + registry.fill(HIST("correction/hRunNumberPhiEtaVertexProton"), matchedPosition, track.phi(), track.eta(), collision.posZ(), track.pt(), weightNUEPid); break; default: diff --git a/PWGCF/GenericFramework/Core/FlowContainer.cxx b/PWGCF/GenericFramework/Core/FlowContainer.cxx index daa553374f2..b038eea0e11 100644 --- a/PWGCF/GenericFramework/Core/FlowContainer.cxx +++ b/PWGCF/GenericFramework/Core/FlowContainer.cxx @@ -9,6 +9,10 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +/// \file FlowContainer.cxx +/// \brief Container class to store and calculate multi-particle azimuthal correlations and cumulants +/// \author Emil Gorm Dahlbæk Nielsen + #include "FlowContainer.h" #include "PWGCF/GenericFramework/Core/ProfileSubset.h" @@ -30,7 +34,8 @@ #include #include -#include +#include +#include #include ClassImp(FlowContainer); @@ -73,15 +78,15 @@ void FlowContainer::Initialize(TObjArray* inputList, const o2::framework::AxisSp if (nMultiBins <= 0) nMultiBins = multiBins.size() - 1; if (nMultiBins <= 0) { - printf("Multiplicity axis does not exist"); + LOGF(error, "Multiplicity axis does not exist"); return; } if (!inputList) { - printf("Input list not specified\n"); + LOGF(warning, "Input list not specified"); return; } if (inputList->GetEntries() < 1) { - printf("Input list empty!\n"); + LOGF(warning, "Input list empty!"); return; } fProf = new TProfile2D(Form("%s_CorrProfile", this->GetName()), "CorrProfile", nMultiBins, &multiBins[0], inputList->GetEntries(), 0.5, inputList->GetEntries() + 0.5); @@ -101,11 +106,11 @@ void FlowContainer::Initialize(TObjArray* inputList, const o2::framework::AxisSp void FlowContainer::Initialize(TObjArray* inputList, int nMultiBins, double MultiMin, double MultiMax, int nRandom) { if (!inputList) { - printf("Input list not specified\n"); + LOGF(warning, "Input list not specified"); return; } if (inputList->GetEntries() < 1) { - printf("Input list empty!\n"); + LOGF(warning, "Input list empty!"); return; } fProf = new TProfile2D(Form("%s_CorrProfile", this->GetName()), "CorrProfile", nMultiBins, MultiMin, MultiMax, inputList->GetEntries(), 0.5, inputList->GetEntries() + 0.5); @@ -138,7 +143,7 @@ void FlowContainer::SetXAxis(TAxis* inax) fXAxis = dynamic_cast(inax->Clone("pTAxis")); bool success = CreateBinsFromAxis(fXAxis); if (!success) - printf("Something went wrong setting the x axis!\n"); + LOGF(warning, "Something went wrong setting the x axis!"); } void FlowContainer::SetXAxis() { @@ -161,7 +166,7 @@ int FlowContainer::FillProfile(const char* hname, double multi, double corr, dou return -1; int yin = fProf->GetYaxis()->FindBin(hname); if (!yin) { - printf("Could not find bin %s\n", hname); + LOGF(info, "Could not find bin %s\n", hname); return -1; } fProf->Fill(multi, yin, corr, w); @@ -176,23 +181,23 @@ void FlowContainer::OverrideProfileErrors(TProfile2D* inpf) int nBinsX = fProf->GetNbinsX(); int nBinsY = fProf->GetNbinsY(); if ((inpf->GetNbinsX() != nBinsX) || (inpf->GetNbinsY() != nBinsY)) { - printf("Number of bins in two profiles do not match, not doing anything\n"); + LOGF(info, "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"); + LOGF(info, "Input profile has no BinSumw2()! Returning\n"); return; } if (!fProf->GetBinSumw2()->fArray) fProf->Sumw2(); double* sumw2Prof = fProf->GetSumw2()->fArray; - double* sumw2Targ = inpf->GetSumw2()->fArray; + const double* sumw2Targ = inpf->GetSumw2()->fArray; double* binsw2Prof = fProf->GetBinSumw2()->fArray; - double* binsw2Targ = inpf->GetBinSumw2()->fArray; + const double* binsw2Targ = inpf->GetBinSumw2()->fArray; double* farrProf = fProf->fArray; for (int ix = 1; ix <= nBinsX; ix++) { double xval = fProf->GetXaxis()->GetBinCenter(ix); - printf("Processing x-bin %i\n", ix); + LOGF(info, "Processing x-bin %i\n", ix); for (int iy = 1; iy <= nBinsY; iy++) { double yval = fProf->GetYaxis()->GetBinCenter(iy); int binno = fProf->FindBin(xval, yval); @@ -244,34 +249,38 @@ Long64_t FlowContainer::Merge(TCollection* collist) void FlowContainer::ReadAndMerge(const char* filelist) { - FILE* flist = fopen(filelist, "r"); - char str[150]; - int nFiles = 0; - while (fscanf(flist, "%s\n", str) == 1) - nFiles++; - rewind(flist); - if (nFiles == 0) { - printf("No files to read!\n"); + if (!filelist) { + LOGF(error, "File list path is null!"); + return; + } + std::ifstream input(filelist); + if (!input) { + LOGF(error, "Could not open file list %s!", filelist); return; } - for (int i = 0; i < nFiles; i++) { - auto retVal = fscanf(flist, "%s\n", str); - (void)retVal; - TFile* tf = new TFile(str, "READ"); - if (tf->IsZombie()) { - printf("Could not open file %s!\n", str); - tf->Close(); + + std::string filename; + bool hasFiles = false; + while (input >> filename) { + hasFiles = true; + TFile tf(filename.c_str(), "READ"); + if (tf.IsZombie()) { + LOGF(info, "Could not open file %s!", filename.c_str()); continue; } - PickAndMerge(tf); - tf->Close(); + PickAndMerge(&tf); + } + if (input.bad()) { + LOGF(error, "Error reading file list %s!", filelist); + } else if (!hasFiles) { + LOGF(info, "No files to read!"); } } void FlowContainer::PickAndMerge(TFile* tfi) { FlowContainer* lfc = dynamic_cast(tfi->Get(this->GetName())); if (!lfc) { - printf("Could not pick up the %s from %s\n", this->GetName(), tfi->GetName()); + LOGF(info, "Could not pick up the %s from %s", this->GetName(), tfi->GetName()); return; } TProfile2D* spro = lfc->GetProfile(); @@ -313,13 +322,13 @@ bool FlowContainer::OverrideBinsWithZero(int xb1, int yb1, int xb2, int yb2) bool FlowContainer::OverrideMainWithSub(int ind, bool ExcludeChosen) { if (!fProfRand) { - printf("Cannot override main profile with a randomized one. Random profile array does not exist.\n"); + LOGF(info, "Cannot override main profile with a randomized one. Random profile array does not exist."); return kFALSE; } if (!ExcludeChosen) { TProfile2D* tarprof = dynamic_cast(fProfRand->At(ind)); if (!tarprof) { - printf("Target random histogram does not exist.\n"); + LOGF(info, "Target random histogram does not exist."); return kFALSE; } TString ts(fProf->GetName()); @@ -345,7 +354,7 @@ bool FlowContainer::OverrideMainWithSub(int ind, bool ExcludeChosen) bool FlowContainer::RandomizeProfile(int nSubsets) { if (!fProfRand) { - printf("Cannot randomize profile, random array does not exist.\n"); + LOGF(info, "Cannot randomize profile, random array does not exist."); return kFALSE; } int l_Subsets = nSubsets ? nSubsets : fProfRand->GetEntries(); @@ -393,7 +402,7 @@ TProfile* FlowContainer::GetCorrXXVsMulti(const char* order, int l_pti) const char* ybinlab = Form("%s%s%s", l_name.Data(), order, ptpf); int ybinno = fProf->GetYaxis()->FindBin(ybinlab); if (ybinno < 0) { - printf("Could not find %s!\n", ybinlab); + LOGF(info, "Could not find %s!", ybinlab); return 0; } TProfile* rethist = dynamic_cast(fProf->ProfileX("temp_prof", ybinno, ybinno)); @@ -426,7 +435,6 @@ TH1D* FlowContainer::GetCorrXXVsPt(const char* order, double lminmulti, double l } if (lmaxmulti > lminmulti) maxm = fProf->GetXaxis()->FindBin(lmaxmulti - 0.001); - ProfileSubset* rhProfSub = new ProfileSubset(*fProf); TString l_name(""); Ssiz_t l_pos = 0; while (fIDName.Tokenize(l_name, l_pos)) { @@ -435,20 +443,19 @@ TH1D* FlowContainer::GetCorrXXVsPt(const char* order, double lminmulti, double l int ybn1 = fProf->GetYaxis()->FindBin(ybl1.Data()); int ybn2 = fProf->GetYaxis()->FindBin(ybl2.Data()); if (fNbinsPt != (ybn2 - ybn1 + 1)) { - printf("fNbinsPt is not matching the num of found histograms"); + LOGF(info, "fNbinsPt is not matching the num of found histograms"); return nullptr; } - TProfile* profY = rhProfSub->ProfileY("profY", minm, maxm); + const TString temporaryTag = Form("%s_%s_%.3f_%.3f", fIDName.Data(), order, lminmulti, lmaxmulti); + TProfile* profY = fProf->ProfileY(Form("profY_%s", temporaryTag.Data()), minm, maxm); TH1D* histY = ProfToHist(profY); - TH1D* hist = new TH1D("temphist", "temphist", fNbinsPt, fbinsPt); + delete profY; + TH1D* hist = new TH1D(Form("temphist_%s", temporaryTag.Data()), "temphist", fNbinsPt, fbinsPt); for (int ibin = 1; ibin <= hist->GetNbinsX(); ibin++) { - TString bLabel = rhProfSub->GetYaxis()->GetBinLabel(ibin + ybn1 - 1); - hist->GetXaxis()->SetBinLabel(ibin, bLabel.Data()); hist->SetBinContent(ibin, histY->GetBinContent(ibin + ybn1 - 1)); hist->SetBinError(ibin, histY->GetBinError(ibin + ybn1 - 1)); } delete histY; - delete rhProfSub; return hist; } return nullptr; @@ -479,7 +486,7 @@ TH1D* FlowContainer::GetHistCorrXXVsPt(const char* order, double lminmulti, doub { TH1D* rethist = GetCorrXXVsPt(order, lminmulti, lmaxmulti); if (!rethist) { - printf("GetCorrXXVsPt return nullptr!"); + LOGF(info, "GetCorrXXVsPt return nullptr!"); return nullptr; } TProfile* refflow = GetRefFlowProfile(order, lminmulti, lmaxmulti); @@ -890,23 +897,24 @@ TH1D* FlowContainer::GetVN8VsX(int n, bool onPt, double arg1, double arg2) } return rethist; } + TH1D* FlowContainer::GetCNN(int n, int c, bool onPt, double arg1, double arg2) { - if (c == 8) + if (c == kEightParticleOrder) return GetCN8VsX(n, onPt, arg1, arg2); - if (c == 6) + if (c == kSixParticleOrder) return GetCN6VsX(n, onPt, arg1, arg2); - if (c == 4) + if (c == kFourParticleOrder) return GetCN4VsX(n, onPt, arg1, arg2); return GetCN2VsX(n, onPt, arg1, arg2); }; TH1D* FlowContainer::GetVNN(int n, int c, bool onPt, double arg1, double arg2) { - if (c == 8) + if (c == kEightParticleOrder) return GetVN8VsX(n, onPt, arg1, arg2); - if (c == 6) + if (c == kSixParticleOrder) return GetVN6VsX(n, onPt, arg1, arg2); - if (c == 4) + if (c == kFourParticleOrder) return GetVN4VsX(n, onPt, arg1, arg2); return GetVN2VsX(n, onPt, arg1, arg2); }; @@ -1051,12 +1059,14 @@ double FlowContainer::CN6Error(double cor6e, double cor4, double cor4e, double c { if (!fPropagateErrors) return 0; - double inters[3]; + + constexpr int kCN6Terms = 3; + double inters[kCN6Terms]; inters[0] = cor6e; inters[1] = -9 * cor2 * cor4e; inters[2] = (-9 * cor4 + 36 * cor2 * cor2) * cor2e; double sum = 0; - for (int i = 0; i < 3; i++) + for (int i = 0; i < kCN6Terms; i++) sum += (inters[i] * inters[i]); return TMath::Sqrt(sum); }; @@ -1070,14 +1080,15 @@ double FlowContainer::DN6Error(double d6e, double d4, double d4e, double d2, { if (!fPropagateErrors) return 0; - double inters[5]; + constexpr int kDN6Terms = 5; + double inters[kDN6Terms]; 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 sum = 0; - for (int i = 0; i < 5; i++) + for (int i = 0; i < kDN6Terms; i++) sum += (inters[i] * inters[i]); return TMath::Sqrt(sum); }; @@ -1126,13 +1137,14 @@ double FlowContainer::CN8Error(double cor8e, double cor6, double cor6e, { if (!fPropagateErrors) return 0; - double parts[4]; + constexpr int kCN8Terms = 4; + double parts[kCN8Terms]; 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 retval = 0; - for (int i = 0; i < 4; i++) + for (int i = 0; i < kCN8Terms; i++) retval += TMath::Power(parts[i], 2); return TMath::Sqrt(retval); }; @@ -1147,7 +1159,8 @@ double FlowContainer::DN8Error(double d8e, double d6, double d6e, double d4, { if (!fPropagateErrors) return 0; - double parts[7]; + constexpr int kDN8Terms = 7; + double parts[kDN8Terms]; parts[0] = d8e; // d/d8' parts[1] = -12 * c2 * d6e; // d/d6' parts[2] = -4 * d2 * c6e; // d/d6 @@ -1156,7 +1169,7 @@ double FlowContainer::DN8Error(double d8e, double d6, double d6e, double 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 retval = 0; - for (int i = 0; i < 7; i++) + for (int i = 0; i < kDN8Terms; i++) retval += TMath::Power(parts[i], 2); return TMath::Sqrt(retval); }; @@ -1197,26 +1210,6 @@ void FlowContainer::SetPtRebin(int nbins, double* binedges) { fPtRebin = nbins; fPtRebinEdges = binedges; - return; - int fPtRebin = 0; - // double *lPtRebinEdges=binedges; - if (!fbinsPt) - SetXAxis(); - for (int 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[fPtRebin]; - fPtRebin = 0; - for (int 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 nbins, double* binedges) { diff --git a/PWGCF/GenericFramework/Core/FlowContainer.h b/PWGCF/GenericFramework/Core/FlowContainer.h index 941442a941e..6d3da46f2e9 100644 --- a/PWGCF/GenericFramework/Core/FlowContainer.h +++ b/PWGCF/GenericFramework/Core/FlowContainer.h @@ -165,6 +165,12 @@ class FlowContainer : public TNamed double* fbinsPt; //! Do not store; stored in fXAxis bool fPropagateErrors; //! do not store TProfile* GetRefFlowProfile(const char* order, double m1 = -1, double m2 = -1); + + private: + static constexpr int kTwoParticleOrder = 2; + static constexpr int kFourParticleOrder = 4; + static constexpr int kSixParticleOrder = 6; + static constexpr int kEightParticleOrder = 8; ClassDef(FlowContainer, 2); }; diff --git a/PWGCF/GenericFramework/Tasks/flowGenericFramework.cxx b/PWGCF/GenericFramework/Tasks/flowGenericFramework.cxx index 0d3014d1179..8bac910d2c8 100644 --- a/PWGCF/GenericFramework/Tasks/flowGenericFramework.cxx +++ b/PWGCF/GenericFramework/Tasks/flowGenericFramework.cxx @@ -160,6 +160,7 @@ struct FlowGenericFramework { O2_DEFINE_CONFIGURABLE(cfgDCAz, float, 2, "Cut on DCA in the longitudinal direction (cm)"); O2_DEFINE_CONFIGURABLE(cfgNTPCCls, float, 50, "Cut on number of TPC clusters found"); O2_DEFINE_CONFIGURABLE(cfgNTPCXrows, float, 70, "Cut on number of TPC crossed rows"); + O2_DEFINE_CONFIGURABLE(cfgNTPCXrowsDaughters, float, 70, "Cut on number of TPC crossed rows of V0 daughters"); O2_DEFINE_CONFIGURABLE(cfgMinNITSCls, float, 5, "Cut on minimum number of ITS clusters found"); O2_DEFINE_CONFIGURABLE(cfgChi2PrITSCls, float, 36, "Cut on chi^2 per ITS clusters found"); O2_DEFINE_CONFIGURABLE(cfgChi2PrTPCCls, float, 2.5, "Cut on chi^2 per TPC clusters found"); @@ -178,8 +179,7 @@ struct FlowGenericFramework { O2_DEFINE_CONFIGURABLE(cfgIsVertexITSTPC, bool, true, "IsVertexITSTPC - Selects collisions with at least one ITS-TPC track"); } cfgEventCutFlags; struct : ConfigurableGroup { - O2_DEFINE_CONFIGURABLE(cfgOccupancySelection, int, 2000, "Max occupancy selection, -999 to disable"); - O2_DEFINE_CONFIGURABLE(cfgDoOccupancySel, bool, true, "Bool for event selection on detector occupancy"); + O2_DEFINE_CONFIGURABLE(cfgOccupancySelection, int, -999, "Max occupancy selection, -999 to disable"); O2_DEFINE_CONFIGURABLE(cfgMagField, float, 99999, "Configurable magnetic field; default CCDB will be queried"); O2_DEFINE_CONFIGURABLE(cfgMultCut, bool, false, "Use additional event cut on mult correlations"); } cfgEventSelection; @@ -1393,7 +1393,7 @@ struct FlowGenericFramework { if (cfgTrackCuts.cfgDCAxyNSigma && (std::fabs(track.dcaXY()) > fPtDepDCAxy->Eval(track.pt()))) { return false; } - if (!cfgTrackCuts.cfgDCAzPtDep.value.empty() && std::fabs(track.dcaZ() > fPtDepDCAz->Eval(track.pt()))) { + if (!cfgTrackCuts.cfgDCAzPtDep.value.empty() && std::fabs(track.dcaZ()) > fPtDepDCAz->Eval(track.pt())) { return false; } return ((track.tpcNClsCrossedRows() >= cfgTrackCuts.cfgNTPCXrows) && (track.tpcNClsFound() >= cfgTrackCuts.cfgNTPCCls) && (track.itsNCls() >= cfgTrackCuts.cfgMinNITSCls)); @@ -1407,7 +1407,7 @@ struct FlowGenericFramework { if (cfgTrackCuts.cfgDCAxyNSigma && (std::fabs(track.dcaXY()) > defaultNsigma / cfgTrackCuts.cfgDCAxyNSigma * fPtDepDCAxy->Eval(track.pt()))) { return false; } - if (!cfgTrackCuts.cfgDCAzPtDep.value.empty() && std::fabs(track.dcaZ() > fPtDepDCAz->Eval(track.pt()))) { + if (!cfgTrackCuts.cfgDCAzPtDep.value.empty() && std::fabs(track.dcaZ()) > fPtDepDCAz->Eval(track.pt())) { return false; } int tpcNClsCrossedRowsDefault = 70; @@ -2165,8 +2165,8 @@ struct FlowGenericFramework { if (cfgFill.cfgFillV0QA && fractionSetup == FractionV02) { fillV0QA(lambdaSelection, v0, postrack, negtrack, centrality, weff); } - - if (v0.mLambda() > cfgPIDCuts.cfgLambdaSideBand1Min && v0.mLambda() < cfgPIDCuts.cfgLambdaSideBand1Max) { + const double lambdaMass = lambdaSelection.isL ? v0.mLambda() : v0.mAntiLambda(); + if (lambdaMass > cfgPIDCuts.cfgLambdaSideBand1Min && lambdaMass < cfgPIDCuts.cfgLambdaSideBand1Max) { histosResoNpt[fractionSetup][LambdaSideband1]->Fill(v0.pt(), (cfgUseNchCorrection) ? weff : 1.0); } if (v0.mLambda() > cfgPIDCuts.cfgLambdaSignalMin && v0.mLambda() < cfgPIDCuts.cfgLambdaSignalMax) { @@ -2241,7 +2241,7 @@ struct FlowGenericFramework { template bool selectionV0Daughter(const TTrack& track, int pid) { - if (track.tpcNClsCrossedRows() < cfgTrackCuts.cfgNTPCXrows) { + if (track.tpcNClsCrossedRows() < cfgTrackCuts.cfgNTPCXrowsDaughters) { return false; } // Only accept daughters consistent with the expected identities of K0 or Lambda decay. @@ -2758,7 +2758,7 @@ struct FlowGenericFramework { th1sList[run][EventSel]->Fill(1.5); } float centrality = getCentrality(collision); - if (cfgEventSelection.cfgDoOccupancySel) { + if (cfgEventSelection.cfgOccupancySelection >= 0) { int occupancy = collision.trackOccupancyInTimeRange(); if (cfgFill.cfgFillQA) { registryQA.fill(HIST("eventQA/before/occ_mult_cent"), occupancy, tracks.size(), centrality); @@ -2821,7 +2821,7 @@ struct FlowGenericFramework { const auto centrality = getCentrality(collision); - if (cfgEventSelection.cfgDoOccupancySel) { + if (cfgEventSelection.cfgOccupancySelection >= 0) { int occupancy = collision.trackOccupancyInTimeRange(); if (cfgFill.cfgFillQA) { registryQA.fill(HIST("eventQA/before/occ_mult_cent"), occupancy, tracks.size(), centrality); @@ -2974,7 +2974,7 @@ struct FlowGenericFramework { if (centrality < gfwMemberCache.centbinning.front() || centrality > gfwMemberCache.centbinning.back()) { return false; } - if (cfgEventSelection.cfgDoOccupancySel) { + if (cfgEventSelection.cfgOccupancySelection >= 0) { int occupancy = collision.trackOccupancyInTimeRange(); if (occupancy < 0 || occupancy > cfgEventSelection.cfgOccupancySelection) { return false; diff --git a/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx b/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx index cf8f332fb10..db3767664e9 100644 --- a/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx +++ b/PWGCF/GenericFramework/Tasks/flowGfwV02.cxx @@ -11,10 +11,9 @@ // /// \file flowGfwV02.cxx /// \brief Skeleton copy of flowGfwLightIons with empty function bodies -/// \author Emil Gorm Nielsen, NBI, emil.gorm.nielsen@cern.ch +/// \author Maxim Virta, NBI, maxim.virta@cern.ch #include "PWGCF/DataModel/CorrelationsDerived.h" -#include "PWGCF/GenericFramework/Core/FlowContainer.h" #include "PWGCF/GenericFramework/Core/GFW.h" #include "PWGCF/GenericFramework/Core/GFWConfig.h" #include "PWGCF/GenericFramework/Core/GFWWeights.h" @@ -51,13 +50,13 @@ #include #include -#include #include #include #include #include +#include #include #include #include @@ -132,6 +131,7 @@ struct FlowGfwV02 { O2_DEFINE_CONFIGURABLE(cfgNormalizeByCharged, bool, true, "Enable or disable the normalization by charged particles"); O2_DEFINE_CONFIGURABLE(cfgConsistentEventFlag, int, 15, "Flag for consistent event selection"); O2_DEFINE_CONFIGURABLE(cfgMultCut, bool, true, "Use additional event cut on mult correlations"); + O2_DEFINE_CONFIGURABLE(cfgUseV02, bool, false, "Use V02 analysis"); O2_DEFINE_CONFIGURABLE(cfgUseV0, bool, false, "Use V0 analysis"); // Event selection cuts @@ -221,7 +221,6 @@ struct FlowGfwV02 { } cfg{}; // Define output - OutputObj fFC{FlowContainer("FlowContainer")}; HistogramRegistry registry{"registry"}; enum CentEstimators { @@ -413,28 +412,41 @@ struct FlowGfwV02 { AxisSpec dcaXYAxis = {200, -0.5, 0.5, "DCA_{xy} (cm)"}; AxisSpec bsAxis = {gfwMemberCache.nBootstrap, -0.5, gfwMemberCache.nBootstrap - 0.5, "Bootstrap Index"}; - registry.add("v02pt", "", {HistType::kTProfile3D, {ptAxis, centAxis, nchAxis}}); - registry.add("nchMid", "", {HistType::kTProfile3D, {ptAxis, centAxis, nchAxis}}); - registry.add("v02centmult", "", {HistType::kTProfile2D, {centAxis, nchAxis}}); - + // V0 spectra registry.add("analysis/charged/v0AB", "", {HistType::kTProfile3D, {bsAxis, ptAxis, centAxis}}); registry.add("analysis/charged/v0BA", "", {HistType::kTProfile3D, {bsAxis, ptAxis, centAxis}}); registry.add("analysis/charged/nchA", "", {HistType::kTProfile3D, {bsAxis, ptAxis, centAxis}}); registry.add("analysis/charged/nchB", "", {HistType::kTProfile3D, {bsAxis, ptAxis, centAxis}}); - registry.add("analysis/charged/ptA", "", {HistType::kTProfile3D, {bsAxis, centAxis, nchAxis}}); - registry.add("analysis/charged/ptB", "", {HistType::kTProfile3D, {bsAxis, centAxis, nchAxis}}); - registry.add("analysis/charged/ptAB", "", {HistType::kTProfile3D, {bsAxis, centAxis, nchAxis}}); + + // V02 spectra + registry.add("analysis/charged/v22npt", "", {HistType::kTProfile3D, {bsAxis, ptAxis, centAxis}}); + registry.add("analysis/charged/nchC", "", {HistType::kTProfile3D, {bsAxis, ptAxis, centAxis}}); + if (cfgUseMultiplicityFracWeights) { registry.add("analysis/charged/nchA2pc", "", {HistType::kTProfile3D, {bsAxis, ptAxis, centAxis}}); registry.add("analysis/charged/nchB2pc", "", {HistType::kTProfile3D, {bsAxis, ptAxis, centAxis}}); - registry.add("analysis/charged/ptA2pc", "", {HistType::kTProfile3D, {bsAxis, centAxis, nchAxis}}); - registry.add("analysis/charged/ptB2pc", "", {HistType::kTProfile3D, {bsAxis, centAxis, nchAxis}}); + registry.add("analysis/charged/nchC3pc", "", {HistType::kTProfile3D, {bsAxis, ptAxis, centAxis}}); } registry.addClone("analysis/charged/", "analysis/pion/"); registry.addClone("analysis/charged/", "analysis/kaon/"); registry.addClone("analysis/charged/", "analysis/proton/"); + // Only charged particles + registry.add("analysis/charged/v22pt", "", {HistType::kTProfile2D, {bsAxis, centAxis}}); + registry.add("analysis/charged/ptA", "", {HistType::kTProfile2D, {bsAxis, centAxis}}); + registry.add("analysis/charged/ptB", "", {HistType::kTProfile2D, {bsAxis, centAxis}}); + registry.add("analysis/charged/ptAB", "", {HistType::kTProfile2D, {bsAxis, centAxis}}); + registry.add("analysis/charged/ptC", "", {HistType::kTProfile2D, {bsAxis, centAxis}}); + registry.add("analysis/charged/v22", "", {HistType::kTProfile2D, {bsAxis, centAxis}}); + + if (cfgUseMultiplicityFracWeights) { + registry.add("analysis/charged/ptA2pc", "", {HistType::kTProfile2D, {bsAxis, centAxis}}); + registry.add("analysis/charged/ptB2pc", "", {HistType::kTProfile2D, {bsAxis, centAxis}}); + registry.add("analysis/charged/ptC3pc", "", {HistType::kTProfile2D, {bsAxis, centAxis}}); + registry.add("analysis/charged/v223pc", "", {HistType::kTProfile2D, {bsAxis, centAxis}}); + } + ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); @@ -495,24 +507,23 @@ struct FlowGfwV02 { registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kMultCuts, "after Mult cuts"); registry.get(HIST("eventQA/eventSel"))->GetXaxis()->SetBinLabel(kTrackCent, "has track + within cent"); - if (gfwMemberCache.regions.GetSize() < 0) + if (gfwMemberCache.regions.GetSize() < 0) { LOGF(error, "Configuration contains vectors of different size - check the GFWRegions configurable"); + } for (auto i(0); i < gfwMemberCache.regions.GetSize(); ++i) { fGFW->AddRegion(gfwMemberCache.regions.GetNames()[i], gfwMemberCache.regions.GetEtaMin()[i], gfwMemberCache.regions.GetEtaMax()[i], (gfwMemberCache.regions.GetpTDifs()[i] != 0) ? ptbins + 1 : 1, gfwMemberCache.regions.GetBitmasks()[i]); } for (auto i = 0; i < gfwMemberCache.configs.GetSize(); ++i) { corrconfigs.push_back(fGFW->GetCorrelatorConfig(gfwMemberCache.configs.GetCorrs()[i], gfwMemberCache.configs.GetHeads()[i], gfwMemberCache.configs.GetpTDifs()[i] != 0)); } - if (corrconfigs.empty()) + if (corrconfigs.empty()) { LOGF(error, "Configuration contains vectors of different size - check the GFWCorrConfig configurable"); + } fGFW->CreateRegions(); auto* oba = new TObjArray(); oba->SetOwner(kTRUE); addConfigObjectsToObjArray(oba, corrconfigs); LOGF(info, "Number of correlators: %d", oba->GetEntries()); - fFC->SetName("FlowContainer"); - fFC->SetXAxis(fSecondAxis.get()); - fFC->Initialize(oba, centAxis, cfgNbootstrap); delete oba; if (cfgConsistentEventFlag != 0) { @@ -634,8 +645,9 @@ struct FlowGfwV02 { void loadCorrections(aod::BCsWithTimestamps::iterator const& bc) { uint64_t timestamp = bc.timestamp(); - if (cfg.correctionsLoaded) + if (cfg.correctionsLoaded) { return; + } if (!cfgAcceptance.value.empty()) { cfg.mAcceptance = ccdb->getForTimeStamp(cfgAcceptance.value, timestamp); } @@ -662,8 +674,9 @@ struct FlowGfwV02 { void loadCorrections(int runnumber) { - if (cfg.correctionsLoaded) + if (cfg.correctionsLoaded) { return; + } if (!cfgAcceptance.value.empty()) { cfg.mAcceptance = ccdb->getForRun(cfgAcceptance.value, runnumber); } @@ -677,8 +690,9 @@ struct FlowGfwV02 { double getJTrackAcceptance(TTrack const& track) { double wacc = 1; - if constexpr (requires { track.weightNUA(); }) + if constexpr (requires { track.weightNUA(); }) { wacc = 1. / track.weightNUA(); + } return wacc; } @@ -686,8 +700,9 @@ struct FlowGfwV02 { double getJTrackEfficiency(TTrack const& track) { double eff = 1.; - if constexpr (requires { track.weightEff(); }) + if constexpr (requires { track.weightEff(); }) { eff = track.weightEff(); + } return eff; } @@ -695,8 +710,9 @@ struct FlowGfwV02 { double getAcceptance(TTrack const& track, const double& vtxz) { double wacc = 1; - if (cfg.mAcceptance) + if (cfg.mAcceptance) { wacc = cfg.mAcceptance->getNUA(track.phi(), track.eta(), vtxz); + } return wacc; } @@ -704,10 +720,12 @@ struct FlowGfwV02 { double getEfficiency(TTrack const& track, const int& pid = PidCharged) { double eff = 1.; - if (cfg.mEfficiency[pid]) + if (cfg.mEfficiency[pid]) { eff = cfg.mEfficiency[pid]->GetBinContent(cfg.mEfficiency[pid]->FindBin(track.pt())); - if (eff == 0) + } + if (eff == 0) { return -1.; + } return 1. / eff; } @@ -797,25 +815,32 @@ struct FlowGfwV02 { float zRes = std::sqrt(collision.covZZ()); float minZRes = 0.25; int minNContrib = 20; - if (zRes > minZRes && collision.numContrib() < minNContrib) + if (zRes > minZRes && collision.numContrib() < minNContrib) { vtxz = -999; + } } auto multNTracksPV = collision.multNTracksPV(); - if (vtxz > gfwMemberCache.vtxZup || vtxz < gfwMemberCache.vtxZlow) + if (vtxz > gfwMemberCache.vtxZup || vtxz < gfwMemberCache.vtxZlow) { return 0; + } if (cfgMultCut) { - if (multNTracksPV < fMultPVCutLow->Eval(centrality)) + if (multNTracksPV < fMultPVCutLow->Eval(centrality)) { return 0; - if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) + } + if (multNTracksPV > fMultPVCutHigh->Eval(centrality)) { return 0; - if (multTrk < fMultCutLow->Eval(centrality)) + } + if (multTrk < fMultCutLow->Eval(centrality)) { return 0; - if (multTrk > fMultCutHigh->Eval(centrality)) + } + if (multTrk > fMultCutHigh->Eval(centrality)) { return 0; - if (multTrk > fMultPVGlobalCutHigh->Eval(collision.multNTracksPV())) + } + if (multTrk > fMultPVGlobalCutHigh->Eval(collision.multNTracksPV())) { return 0; + } registry.fill(HIST("eventQA/eventSel"), kMultCuts); } return 1; @@ -829,58 +854,101 @@ struct FlowGfwV02 { int getPIDIndex(const std::string& corrconfig) { - if (!boost::ifind_first(corrconfig, "pi").empty()) + if (!boost::ifind_first(corrconfig, "pi").empty()) { return PidPions; - if (!boost::ifind_first(corrconfig, "ka").empty()) + } + if (!boost::ifind_first(corrconfig, "ka").empty()) { return PidKaons; - if (!boost::ifind_first(corrconfig, "pr").empty()) + } + if (!boost::ifind_first(corrconfig, "pr").empty()) { return PidProtons; + } return PidCharged; } template - void fillOutputContainers(const float& centmult, const int& multiplicity, const double& rndm, const int& /*run*/ = 0) + void fillOutputContainers(const float& centmult) { - double threshold = 1.01; - for (uint l_ind = 0; l_ind < corrconfigs.size(); ++l_ind) { - if (!corrconfigs.at(l_ind).pTDif) { - auto dnx = fGFW->Calculate(corrconfigs.at(l_ind), 0, kTRUE).real(); - if (dnx == 0) - continue; - auto val = fGFW->Calculate(corrconfigs.at(l_ind), 0, kFALSE).real() / dnx; - - if (std::abs(val) < threshold) { - fFC->FillProfile(corrconfigs.at(l_ind).Head.c_str(), centmult, val, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0, rndm); - } - continue; + constexpr double threshold = 1.01; + constexpr double minDnxAB = 1e-8; // skip events with vanishing V22 weight + + int bootstrap = fRndm->Integer(gfwMemberCache.nBootstrap); + // Calculate V02 + if (cfgUseV02) { + double v22npt = 0; + double ptMeanMid = pidStates.hPtMid[PidCharged]->GetMean(); + double ptFractionMid = 0.; + double dnxAB = fGFW->Calculate(corrconfigs.at(0), 0, kTRUE).real(); // V22 weight for AB + auto valAB = fGFW->Calculate(corrconfigs.at(0), 0, kFALSE).real() / dnxAB; + if (std::abs(valAB) > threshold || std::isnan(valAB) || std::isinf(valAB) || dnxAB < minDnxAB) { + return; } - - // Fill pt profiles for different particles - int pidInd = getPIDIndex(corrconfigs.at(l_ind).Head); - - auto dnx = fGFW->Calculate(corrconfigs.at(0), 0, kTRUE).real(); - if (dnx == 0) - continue; - auto val = fGFW->Calculate(corrconfigs.at(0), 0, kFALSE).real() / dnx; - double ebyeWeight = (cfgUseMultiplicityFlowWeights) ? dnx : 1.0; - for (int i = 1; i <= fSecondAxis->GetNbins(); i++) { - if (corrconfigs.at(l_ind).Head.find("nch") != std::string::npos) { - ebyeWeight = 1.0; - val = 1.0; + double v22pt = valAB * ptMeanMid; + double WeightAB = (cfgUseMultiplicityFlowWeights) ? dnxAB : 1.0; + double WeightC = 1.0; + // Calculate V02 for each particle type + for (int pid = 0; pid < PidTotal; pid++) { + int normIndex = (cfgNormalizeByCharged) ? PidCharged : pid; + if (!(pidStates.hPtMid[normIndex]->Integral() > 0)) { + continue; // Mid pT distribution is not defined } - if (cfgUseMultiplicityFracWeights && pidStates.hPtMid[PidCharged]->Integral() > 0) { - ebyeWeight *= pidStates.hPtMid[PidCharged]->Integral(); + if (cfgUseMultiplicityFracWeights) { + WeightC = pidStates.hPtMid[PidCharged]->Integral(); // Mean pt/npt C weight } - double ptFraction = 0; - int normIndex = (cfgNormalizeByCharged) ? PidCharged : pidInd; // Configured to normalize by charged particles or the selected particle - if (pidStates.hPtMid[normIndex]->Integral() > 0) { - ptFraction = pidStates.hPtMid[pidInd]->GetBinContent(i) / pidStates.hPtMid[normIndex]->Integral(); - if (std::abs(val) < threshold) - fFC->FillProfile(Form("%s_pt_%i", corrconfigs.at(l_ind).Head.c_str(), i), centmult, val * ptFraction, ebyeWeight, rndm); + for (int i = 1; i <= fSecondAxis->GetNbins(); i++) { + ptFractionMid = pidStates.hPtMid[pid]->GetBinContent(i) / pidStates.hPtMid[normIndex]->Integral(); + v22npt = valAB * ptFractionMid; + + switch (pid) { + case PidCharged: + registry.fill(HIST("analysis/charged/v22npt"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, v22npt, WeightC * WeightAB); + registry.fill(HIST("analysis/charged/nchC"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionMid, WeightC); + if (cfgUseMultiplicityFracWeights) { + registry.fill(HIST("analysis/charged/nchC3pc"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionMid, WeightC * WeightAB); + } + break; + case PidPions: + registry.fill(HIST("analysis/pion/v22npt"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, v22npt, WeightC * WeightAB); + registry.fill(HIST("analysis/pion/nchC"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionMid, WeightC); + if (cfgUseMultiplicityFracWeights) { + registry.fill(HIST("analysis/pion/nchC3pc"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionMid, WeightC * WeightAB); + } + break; + case PidKaons: + registry.fill(HIST("analysis/kaon/v22npt"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, v22npt, WeightC * WeightAB); + registry.fill(HIST("analysis/kaon/nchC"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionMid, WeightC); + if (cfgUseMultiplicityFracWeights) { + registry.fill(HIST("analysis/kaon/nchC3pc"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionMid, WeightC * WeightAB); + } + break; + case PidProtons: + registry.fill(HIST("analysis/proton/v22npt"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, v22npt, WeightC * WeightAB); + registry.fill(HIST("analysis/proton/nchC"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionMid, WeightC); + if (cfgUseMultiplicityFracWeights) { + registry.fill(HIST("analysis/proton/nchC3pc"), bootstrap, fSecondAxis->GetBinCenter(i), centmult, ptFractionMid, WeightC * WeightAB); + } + break; + default: + break; + } } } - } + // Calculate NCv22pt + if (cfgUseMultiplicityFracWeights) { + WeightC = pidStates.hPtMid[PidCharged]->Integral(); + } + + registry.fill(HIST("analysis/charged/v22pt"), bootstrap, centmult, v22pt, WeightC * WeightAB); + registry.fill(HIST("analysis/charged/v22"), bootstrap, centmult, valAB, WeightAB); + registry.fill(HIST("analysis/charged/ptC"), bootstrap, centmult, ptMeanMid, WeightC); + if (cfgUseMultiplicityFracWeights) { + registry.fill(HIST("analysis/charged/v223pc"), bootstrap, centmult, valAB, WeightC * WeightAB); + registry.fill(HIST("analysis/charged/ptC3pc"), bootstrap, centmult, ptMeanMid, WeightC * WeightAB); + } + } // End of V02 + + // Calculate V0 if (cfgUseV0) { double v0corrAB = 0; double v0corrBA = 0; @@ -888,14 +956,13 @@ struct FlowGfwV02 { double ptMeanBackward = pidStates.hPtBackward[PidCharged]->GetMean(); double ptFractionForward = 0.; double ptFractionBackward = 0.; - int bootstrap = fRndm->Integer(gfwMemberCache.nBootstrap); + double WeightA = 1.0; + double WeightB = 1.0; for (int pid = 0; pid < PidTotal; pid++) { int normIndex = (cfgNormalizeByCharged) ? PidCharged : pid; if (!(pidStates.hPtForward[normIndex]->Integral() > 0) || !(pidStates.hPtBackward[normIndex]->Integral() > 0)) { continue; // Forward or backward pT distribution is not defined } - double WeightA = 1.0; - double WeightB = 1.0; if (cfgUseMultiplicityFracWeights) { WeightA = pidStates.hPtForward[PidCharged]->Integral(); WeightB = pidStates.hPtBackward[PidCharged]->Integral(); @@ -950,65 +1017,23 @@ struct FlowGfwV02 { break; } } - switch (pid) { - case PidCharged: - registry.fill(HIST("analysis/charged/ptA"), bootstrap, centmult, multiplicity, ptMeanForward, WeightA); - registry.fill(HIST("analysis/charged/ptB"), bootstrap, centmult, multiplicity, ptMeanBackward, WeightB); - if (cfgUseMultiplicityFracWeights) { - registry.fill(HIST("analysis/charged/ptA2pc"), bootstrap, centmult, multiplicity, ptMeanForward, WeightA * WeightB); - registry.fill(HIST("analysis/charged/ptB2pc"), bootstrap, centmult, multiplicity, ptMeanBackward, WeightA * WeightB); - } - registry.fill(HIST("analysis/charged/ptAB"), bootstrap, centmult, multiplicity, ptMeanForward * ptMeanBackward, WeightA * WeightB); - break; - case PidPions: - registry.fill(HIST("analysis/pion/ptA"), bootstrap, centmult, multiplicity, ptMeanForward, WeightA); - registry.fill(HIST("analysis/pion/ptB"), bootstrap, centmult, multiplicity, ptMeanBackward, WeightB); - if (cfgUseMultiplicityFracWeights) { - registry.fill(HIST("analysis/pion/ptA2pc"), bootstrap, centmult, multiplicity, ptMeanForward, WeightA * WeightB); - registry.fill(HIST("analysis/pion/ptB2pc"), bootstrap, centmult, multiplicity, ptMeanBackward, WeightA * WeightB); - } - registry.fill(HIST("analysis/pion/ptAB"), bootstrap, centmult, multiplicity, ptMeanForward * ptMeanBackward, WeightA * WeightB); - break; - case PidKaons: - registry.fill(HIST("analysis/kaon/ptA"), bootstrap, centmult, multiplicity, ptMeanForward, WeightA); - registry.fill(HIST("analysis/kaon/ptB"), bootstrap, centmult, multiplicity, ptMeanBackward, WeightB); - if (cfgUseMultiplicityFracWeights) { - registry.fill(HIST("analysis/kaon/ptA2pc"), bootstrap, centmult, multiplicity, ptMeanForward, WeightA * WeightB); - registry.fill(HIST("analysis/kaon/ptB2pc"), bootstrap, centmult, multiplicity, ptMeanBackward, WeightA * WeightB); - } - registry.fill(HIST("analysis/kaon/ptAB"), bootstrap, centmult, multiplicity, ptMeanForward * ptMeanBackward, WeightA * WeightB); - break; - case PidProtons: - registry.fill(HIST("analysis/proton/ptA"), bootstrap, centmult, multiplicity, ptMeanForward, WeightA); - registry.fill(HIST("analysis/proton/ptB"), bootstrap, centmult, multiplicity, ptMeanBackward, WeightB); - if (cfgUseMultiplicityFracWeights) { - registry.fill(HIST("analysis/proton/ptA2pc"), bootstrap, centmult, multiplicity, ptMeanForward, WeightA * WeightB); - registry.fill(HIST("analysis/proton/ptB2pc"), bootstrap, centmult, multiplicity, ptMeanBackward, WeightA * WeightB); - } - registry.fill(HIST("analysis/proton/ptAB"), bootstrap, centmult, multiplicity, ptMeanForward * ptMeanBackward, WeightA * WeightB); - break; - default: - break; - } - } - } + } // End of PID dependent parts of V0 - // Fill the profiles for each pT bin - auto dnx = fGFW->Calculate(corrconfigs.at(0), 0, kTRUE).real(); - if (dnx == 0) - return; - auto val = fGFW->Calculate(corrconfigs.at(0), 0, kFALSE).real() / dnx; - for (int i = 1; i <= fSecondAxis->GetNbins(); i++) { - double ptFraction = 0; - if (pidStates.hPtMid[PidCharged]->Integral() > 0) { - ptFraction = pidStates.hPtMid[PidCharged]->GetBinContent(i) / pidStates.hPtMid[PidCharged]->Integral(); - if (std::abs(val) < threshold) - registry.fill(HIST("v02pt"), fSecondAxis->GetBinCenter(i), centmult, multiplicity, val * ptFraction, (cfgUseMultiplicityFlowWeights) ? dnx : 1.0); - registry.fill(HIST("nchMid"), fSecondAxis->GetBinCenter(i), centmult, multiplicity, ptFraction); + // Calculate PID independent parts of V0 + if (cfgUseMultiplicityFracWeights) { + WeightA = pidStates.hPtForward[PidCharged]->Integral(); + WeightB = pidStates.hPtBackward[PidCharged]->Integral(); } - } - registry.fill(HIST("v02centmult"), centmult, multiplicity, val); - } + registry.fill(HIST("analysis/charged/ptA"), bootstrap, centmult, ptMeanForward, WeightA); + registry.fill(HIST("analysis/charged/ptB"), bootstrap, centmult, ptMeanBackward, WeightB); + if (cfgUseMultiplicityFracWeights) { + registry.fill(HIST("analysis/charged/ptA2pc"), bootstrap, centmult, ptMeanForward, WeightA * WeightB); + registry.fill(HIST("analysis/charged/ptB2pc"), bootstrap, centmult, ptMeanBackward, WeightA * WeightB); + } + registry.fill(HIST("analysis/charged/ptAB"), bootstrap, centmult, ptMeanForward * ptMeanBackward, WeightA * WeightB); + + } // End of V0 + } // End of Filling struct XAxis { float centrality; @@ -1023,15 +1048,18 @@ struct FlowGfwV02 { }; template - void processCollision(TCollision const& collision, TTracks const& tracks, const XAxis& xaxis, const int& run) + void processCollision(TCollision const& collision, TTracks const& tracks, const XAxis& xaxis) { float vtxz = collision.posZ(); - if (tracks.size() < 1) + if (tracks.size() < 1) { return; - if (xaxis.centrality >= 0 && (xaxis.centrality < gfwMemberCache.centbinning.front() || xaxis.centrality > gfwMemberCache.centbinning.back())) + } + if (xaxis.centrality >= 0 && (xaxis.centrality < gfwMemberCache.centbinning.front() || xaxis.centrality > gfwMemberCache.centbinning.back())) { return; - if (xaxis.multiplicity < cfgFixedMultMin || xaxis.multiplicity > cfgFixedMultMax) + } + if (xaxis.multiplicity < cfgFixedMultMin || xaxis.multiplicity > cfgFixedMultMax) { return; + } fGFW->Clear(); pidStates.hPtMid[PidCharged]->Reset(); pidStates.hPtMid[PidPions]->Reset(); @@ -1046,73 +1074,90 @@ struct FlowGfwV02 { pidStates.hPtForward[PidKaons]->Reset(); pidStates.hPtForward[PidProtons]->Reset(); - float lRandom = fRndm->Rndm(); - // Loop over tracks and check if they are accepted AcceptedTracks acceptedTracks{.nPos = 0, .nNeg = 0, .nFull = 0, .nMid = 0}; for (const auto& track : tracks) { - processTrack(track, vtxz, xaxis.multiplicity, run, acceptedTracks); - if (track.eta() > cfgSubeventCuts.cfgEtaSubCMin && track.eta() < cfgSubeventCuts.cfgEtaSubCMax) + processTrack(track, vtxz, xaxis.multiplicity, acceptedTracks); + if (track.eta() > cfgSubeventCuts.cfgEtaSubCMin && track.eta() < cfgSubeventCuts.cfgEtaSubCMax) { pidStates.hPtMid[PidCharged]->Fill(track.pt(), getEfficiency(track, PidCharged)); - if (track.eta() > cfgSubeventCuts.cfgEtaSubAMin && track.eta() < cfgSubeventCuts.cfgEtaSubAMax) // add mean pT + } + if (track.eta() > cfgSubeventCuts.cfgEtaSubAMin && track.eta() < cfgSubeventCuts.cfgEtaSubAMax) { // add mean pT pidStates.hPtBackward[PidCharged]->Fill(track.pt(), getEfficiency(track, PidCharged)); - if (track.eta() > cfgSubeventCuts.cfgEtaSubBMin && track.eta() < cfgSubeventCuts.cfgEtaSubBMax) // add mean pT + } + if (track.eta() > cfgSubeventCuts.cfgEtaSubBMin && track.eta() < cfgSubeventCuts.cfgEtaSubBMax) { // add mean pT pidStates.hPtForward[PidCharged]->Fill(track.pt(), getEfficiency(track, PidCharged)); + } // If PID is identified, fill pt spectrum for the corresponding particle int pidInd = getNsigmaPID(track); if (pidInd != -1 && track.eta() > cfgSubeventCuts.cfgEtaSubCMin && track.eta() < cfgSubeventCuts.cfgEtaSubCMax) { - if (cfgPIDEfficiency) + if (cfgPIDEfficiency) { pidStates.hPtMid[pidInd]->Fill(track.pt(), getEfficiency(track, pidInd)); - else + } else { pidStates.hPtMid[pidInd]->Fill(track.pt(), getEfficiency(track, PidCharged)); // Default to charged particles if PID efficiency is not used + } } if (pidInd != -1 && track.eta() > cfgSubeventCuts.cfgEtaSubAMin && track.eta() < cfgSubeventCuts.cfgEtaSubAMax) { - if (cfgPIDEfficiency) + if (cfgPIDEfficiency) { pidStates.hPtBackward[pidInd]->Fill(track.pt(), getEfficiency(track, pidInd)); - else + } else { pidStates.hPtBackward[pidInd]->Fill(track.pt(), getEfficiency(track, PidCharged)); // Default to charged particles if PID efficiency is not used + } } if (pidInd != -1 && track.eta() > cfgSubeventCuts.cfgEtaSubBMin && track.eta() < cfgSubeventCuts.cfgEtaSubBMax) { - if (cfgPIDEfficiency) + if (cfgPIDEfficiency) { pidStates.hPtForward[pidInd]->Fill(track.pt(), getEfficiency(track, pidInd)); - else + } else { pidStates.hPtForward[pidInd]->Fill(track.pt(), getEfficiency(track, PidCharged)); // Default to charged particles if PID efficiency is not used + } } } - if (cfgConsistentEventFlag & 1) - if (!acceptedTracks.nPos || !acceptedTracks.nNeg) + if (cfgConsistentEventFlag & 1) { + if (!acceptedTracks.nPos || !acceptedTracks.nNeg) { return; - if (cfgConsistentEventFlag & 2) - if (acceptedTracks.nFull < 4) // o2-linter: disable=magic-number (at least four tracks in full acceptance) + } + } + if (cfgConsistentEventFlag & 2) { + if (acceptedTracks.nFull < 4) { // o2-linter: disable=magic-number (at least four tracks in full acceptance) return; - if (cfgConsistentEventFlag & 4) - if (acceptedTracks.nPos < 2 || acceptedTracks.nNeg < 2) // o2-linter: disable=magic-number (at least two tracks in each subevent) + } + } + if (cfgConsistentEventFlag & 4) { + if (acceptedTracks.nPos < 2 || acceptedTracks.nNeg < 2) { // o2-linter: disable=magic-number (at least two tracks in each subevent) return; - if (cfgConsistentEventFlag & 8) - if (acceptedTracks.nPos < 2 || acceptedTracks.nMid < 2 || acceptedTracks.nNeg < 2) // o2-linter: disable=magic-number (at least two tracks in all three subevents) + } + } + if (cfgConsistentEventFlag & 8) { + if (acceptedTracks.nPos < 2 || acceptedTracks.nMid < 2 || acceptedTracks.nNeg < 2) { // o2-linter: disable=magic-number (at least two tracks in all three subevents) return; + } + } // Fill output containers - fillOutputContainers
(xaxis.centrality, xaxis.multiplicity, lRandom, run); + fillOutputContainers
(xaxis.centrality); } template void fillAcceptedTracks(TTrack const& track, AcceptedTracks& acceptedTracks) { - if (posRegionIndex >= 0 && track.eta() > gfwMemberCache.regions.GetEtaMin()[posRegionIndex] && track.eta() < gfwMemberCache.regions.GetEtaMax()[posRegionIndex]) + if (posRegionIndex >= 0 && track.eta() > gfwMemberCache.regions.GetEtaMin()[posRegionIndex] && track.eta() < gfwMemberCache.regions.GetEtaMax()[posRegionIndex]) { ++acceptedTracks.nPos; - if (negRegionIndex >= 0 && track.eta() > gfwMemberCache.regions.GetEtaMin()[negRegionIndex] && track.eta() < gfwMemberCache.regions.GetEtaMax()[negRegionIndex]) + } + if (negRegionIndex >= 0 && track.eta() > gfwMemberCache.regions.GetEtaMin()[negRegionIndex] && track.eta() < gfwMemberCache.regions.GetEtaMax()[negRegionIndex]) { ++acceptedTracks.nNeg; - if (fullRegionIndex >= 0 && track.eta() > gfwMemberCache.regions.GetEtaMin()[fullRegionIndex] && track.eta() < gfwMemberCache.regions.GetEtaMax()[fullRegionIndex]) + } + if (fullRegionIndex >= 0 && track.eta() > gfwMemberCache.regions.GetEtaMin()[fullRegionIndex] && track.eta() < gfwMemberCache.regions.GetEtaMax()[fullRegionIndex]) { ++acceptedTracks.nFull; - if (midRegionIndex >= 0 && track.eta() > gfwMemberCache.regions.GetEtaMin()[midRegionIndex] && track.eta() < gfwMemberCache.regions.GetEtaMax()[midRegionIndex]) + } + if (midRegionIndex >= 0 && track.eta() > gfwMemberCache.regions.GetEtaMin()[midRegionIndex] && track.eta() < gfwMemberCache.regions.GetEtaMax()[midRegionIndex]) { ++acceptedTracks.nMid; + } } template bool trackSelected(TTrack const& track) { - if (cfgTrackCuts.cfgDCAxyNSigma && (std::fabs(track.dcaXY()) > fPtDepDCAxy->Eval(track.pt()))) + if (cfgTrackCuts.cfgDCAxyNSigma && (std::fabs(track.dcaXY()) > fPtDepDCAxy->Eval(track.pt()))) { return false; + } return ((track.tpcNClsCrossedRows() >= cfgTrackCuts.cfgNTPCXrows) && (track.tpcNClsFound() >= cfgTrackCuts.cfgNTPCCls) && (track.itsNCls() >= cfgTrackCuts.cfgMinNITSCls)); } @@ -1140,7 +1185,7 @@ struct FlowGfwV02 { } template - inline void processTrack(TTrack const& track, const float& vtxz, const int& multiplicity, const int& /*run*/, AcceptedTracks& acceptedTracks) + inline void processTrack(TTrack const& track, const float& vtxz, const int& multiplicity, AcceptedTracks& acceptedTracks) { if (cfgFillQA) { @@ -1148,11 +1193,13 @@ struct FlowGfwV02 { registry.fill(HIST("trackQA/before/nch_pt"), multiplicity, track.pt()); } - if (cfgGetNsigmaQA) + if (cfgGetNsigmaQA) { fillPidQA(track, getNsigmaPID(track)); + } - if (!trackSelected(track)) + if (!trackSelected(track)) { return; + } fillGFW(track, vtxz); // Fill GFW fillAcceptedTracks(track, acceptedTracks); // Fill accepted tracks @@ -1161,8 +1208,9 @@ struct FlowGfwV02 { registry.fill(HIST("trackQA/after/nch_pt"), multiplicity, track.pt()); } - if (cfgGetNsigmaQA) + if (cfgGetNsigmaQA) { fillPidQA(track, getNsigmaPID(track)); + } } template @@ -1173,24 +1221,30 @@ struct FlowGfwV02 { bool withinPtRef = (track.pt() > gfwMemberCache.ptreflow && track.pt() < gfwMemberCache.ptrefup); bool withinPtPOI = (track.pt() > gfwMemberCache.ptpoilow && track.pt() < gfwMemberCache.ptpoiup); - if (!withinPtPOI && !withinPtRef) + if (!withinPtPOI && !withinPtRef) { return; + } double weff = getEfficiency(track, PidCharged); - if (weff < 0) + if (weff < 0) { return; + } double wacc = getAcceptance(track, vtxz); // Fill cumulants for different particles // ***Need to add proper weights for each particle!*** - if (withinPtRef) + if (withinPtRef) { fGFW->Fill(track.eta(), fSecondAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, 1); - if (withinPtPOI && pidInd == PidPions) + } + if (withinPtPOI && pidInd == PidPions) { fGFW->Fill(track.eta(), fSecondAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, PidPions + 1); - if (withinPtPOI && pidInd == PidKaons) + } + if (withinPtPOI && pidInd == PidKaons) { fGFW->Fill(track.eta(), fSecondAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, PidKaons + 1); - if (withinPtPOI && pidInd == PidProtons) + } + if (withinPtPOI && pidInd == PidProtons) { fGFW->Fill(track.eta(), fSecondAxis->FindBin(track.pt()) - 1, track.phi(), weff * wacc, PidProtons + 1); + } } template @@ -1308,8 +1362,9 @@ struct FlowGfwV02 { loadCorrections(bc); registry.fill(HIST("eventQA/eventSel"), kFilteredEvent); - if (!collision.sel8()) + if (!collision.sel8()) { return; + } registry.fill(HIST("eventQA/eventSel"), kSel8); registry.fill(HIST("eventQA/eventSel"), kOccupancy); // Add occupancy selection later @@ -1319,14 +1374,16 @@ struct FlowGfwV02 { registry.fill(HIST("eventQA/before/centrality"), xaxis.centrality); registry.fill(HIST("eventQA/before/multiplicity"), xaxis.multiplicity); } - if (cfgUseAdditionalEventCut && !eventSelected(collision, xaxis.multiplicity, xaxis.centrality)) + if (cfgUseAdditionalEventCut && !eventSelected(collision, xaxis.multiplicity, xaxis.centrality)) { return; - if (cfgFillQA) + } + if (cfgFillQA) { fillEventQA(collision, xaxis); + } registry.fill(HIST("eventQA/after/centrality"), xaxis.centrality); registry.fill(HIST("eventQA/after/multiplicity"), xaxis.multiplicity); - processCollision(collision, tracks, xaxis, run); + processCollision(collision, tracks, xaxis); } PROCESS_SWITCH(FlowGfwV02, processData, "Process analysis for non-derived data", true); @@ -1343,7 +1400,7 @@ struct FlowGfwV02 { registry.fill(HIST("eventQA/after/centrality"), xaxis.centrality); registry.fill(HIST("eventQA/after/multiplicity"), xaxis.multiplicity); - // processCollision(collision, tracks, xaxis, run); + // processCollision(collision, tracks, xaxis); } PROCESS_SWITCH(FlowGfwV02, processCFDerived, "Process analysis for CF derived data", false); void processCFDerivedCorrected(aod::CFCollision const& collision, soa::Filtered> const& tracks) @@ -1356,7 +1413,7 @@ struct FlowGfwV02 { const XAxis xaxis{.centrality = collision.multiplicity(), .multiplicity = tracks.size()}; registry.fill(HIST("eventQA/after/centrality"), xaxis.centrality); registry.fill(HIST("eventQA/after/multiplicity"), xaxis.multiplicity); - // processCollision(collision, tracks, xaxis, run); + // processCollision(collision, tracks, xaxis); } PROCESS_SWITCH(FlowGfwV02, processCFDerivedCorrected, "Process analysis for CF derived data with corrections", false); }; diff --git a/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt b/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt index aa98d11a997..a20000206b2 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt +++ b/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt @@ -33,3 +33,8 @@ o2physics_add_dpl_workflow(multiparticle-cumulants SOURCES multiparticleCumulants.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(multiparticle-correlations-mei + SOURCES multiparticleCorrelationsMei.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) diff --git a/PWGCF/MultiparticleCorrelations/Tasks/multiparticleCorrelationsMei.cxx b/PWGCF/MultiparticleCorrelations/Tasks/multiparticleCorrelationsMei.cxx new file mode 100644 index 00000000000..41b9c0b42be --- /dev/null +++ b/PWGCF/MultiparticleCorrelations/Tasks/multiparticleCorrelationsMei.cxx @@ -0,0 +1,981 @@ +// 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. + +/// \file multiparticleCorrelationsMei.cxx +/// \brief Multiparticle correlation in O2 Framework +/// \author yuanjun.mei@cern.ch + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" // needed for aod::TracksDCA table + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::constants; +using namespace std; + +// Definitions of join tables for Run 3 analysis: +using EventSelection = soa::Join; +using CollisionRec = soa::Join::iterator; // use in json "isMC": "true" for "event-selection-task" +using CollisionRecSim = soa::Join::iterator; +using CollisionSim = aod::McCollision; +using TracksRec = soa::Join; +using TrackRec = soa::Join::iterator; +using TracksRecSim = soa::Join; // + use in json "isMC" : "true" +using TrackRecSim = soa::Join::iterator; +using TracksSim = aod::McParticles; +using TrackSim = aod::McParticles::iterator; + +// *) Define enums: +enum ECentralityEstimator { + EFT0C = 0, + EFT0M, + EFV0A, + ENTPV +}; + +enum EMultiplicityTables { + EMultTPC = 0, + EMultFV0M, + EMultFT0C, + EMultFT0M, + EMultNTracksPV +}; + +enum ERecSim { + ERec = 0, + ESim, + ERecAndSim +}; + +enum ECuts { + ENoCuts = 0, + EWithCuts +}; + +enum EProcess { + EProcessRec = 0, // Run 3, only reconstructed + EProcessRecSim, // Run 3, both reconstructed and simulated + EProcessSim, // Run 3, only simulated + EProcess_N +}; + +enum EParticleHistograms { + EParticleHistogramsList = 0, + EHistPt, + EHistPhi, + EHistEta, + EParticleHistograms_N +}; + +enum EEventHistograms { + EHistCentrality = 0, + EHistMultiplicity, + EHistVertexX, + EHistVertexY, + EHistVertexZ, + EHistImpactParameter, + EHistReferenceMultiplicity, + EEventHistograms_N +}; + +enum EExternalHistograms { + EHistWeights = 0, + EExternalHistograms_N +}; + +// *) Main task: +struct MultiparticleCorrelationsMei // this name is used in lower-case format to name the TDirectoryFile in AnalysisResults.root +{ + // *) Base TList to hold all output objects: + TString sBaseListName = "Default list name"; // yes, I declare it separately, because I need it also later in BailOut() function + OutputObj fBaseList{sBaseListName.Data(), + OutputObjHandlingPolicy::AnalysisObject, + OutputObjSourceType::OutputObjSource}; + + // *) CCDB: + Service ccdb{}; // support for offline callibration data base, not needed for the time being... + + // *) Define configurables: + Configurable centralityEstimator{"centralityEstimator", 0, "centrality estimator: 0=FT0C, 1=FT0M, 2=FV0A, 3=NTPV"}; + Configurable multiplicityTables{"multiplicityTables", 0, "multiplicity tables: 0=multTPC, 1=multFV0M, 2=multFT0C, 3=multFT0M, 4=multNTracksPV"}; + Configurable cfDryRun{"cfDryRun", false, "book all histos and run without filling and calculating anything"}; + + // external root files + Configurable cfExternalFileSwitch{"cfExternalFileSwitch", false, "choose to include external root files or not"}; + Configurable cfFileWithWeights{"cfFileWithWeights", "/alice-ccdb.cern.ch/Users/m/mei/O2challenge-", "path to external ROOT file which holds all particle weights"}; + + // binnings + Configurable> cfPtBins{"cfPtBins", {2000, 0., 5.}, "nPtBins, ptMin, ptMax"}; // example for an array + Configurable> cfPhiBins{"cfPhiBins", {180, 0., math::TwoPI}, "nPhiBins, phiMin, phiMax"}; // example for an array + Configurable> cfEtaBins{"cfEtaBins", {800, -3., 3.}, "nEtaBins, etaMin, etaMax"}; // example for an array + + Configurable> cfMultBinsRec{"cfMultBinsRec", {100, 0., 40000.}, "nMultBins, multMin, multMax"}; + Configurable> cfMultBinsRef{"cfMultBinsRef", {80, 0., 40000.}, "nMultBins, multMin, multMax"}; + Configurable> cfMultBinsSim{"cfMultBinsSim", {80, 0., 40000.}, "nMultBins, multMin, multMax"}; + Configurable> cfVxBins{"cfVxBins", {80, -0.04, 0.04}, "Vertex X hist: nVxBins, vxMin, vxMax"}; + Configurable> cfVyBins{"cfVyBins", {80, -0.01, 0.01}, "Vertex Y hist: nVyBins, vyMin, vyMax"}; + Configurable> cfVzBins{"cfVzBins", {80, -20., 20.}, "Vertex Z hist: nVzBins, vzMin, vzMax"}; + Configurable> cfCentBins{"cfCentBins", {100, 0., 100.}, "nCentBins, centMin, centMax"}; + Configurable> cfIpBins{"cfIpBins", {100, 0., 20.}, "Impact parameters hist: nIPBins, ipMin, ipMax"}; + + // Cuts + // event level cuts + Configurable cfEventCutSwitch{"cfEventCutSwitch", false, "switch to apply vertex z position cut"}; + Configurable> cfVertexZCutRange{"cfVertexZCutRange", {-10, 10.}, "vertex z position range: {min, max}[cm], with convention: min <= Vz < max"}; + + // particle level cuts + Configurable cfPtCutSwitch{"cfPtCutSwitch", false, "switch to apply pt cut"}; + Configurable> cfPtCutRange{"cfPtCutRange", {0.2, 5.}, "pt cut range: {min, max}, with convention: min <= Vz < max"}; + + // misc + Configurable sigmaInel{"sigmaInel", 7.71, "inelastic cross section in mb"}; + Configurable qualityAssuranceSwitch{"qualityAssuranceSwitch", false, "quality assurance switch"}; + + // *) Define and initialize all data members to be called in the main process* functions: + // **) Task configuration: + struct TaskConfiguration { + bool fProcess[EProcess_N] = {false}; // Set what to process. See enum EProcess for full description. Set via implicit variables within a PROCESS_SWITCH clause. + bool fDryRun = false; // book all histos and run without filling and calculating anything + } tc; // you have to prepend "tc." for all objects name in this group later in the code + + // **) Particle histograms: + struct ParticleHistograms { + TList* fParticleHistogramsList = NULL; //!Get("hist-name"). + + // Usage: TH1D *hist = (TH1D*) getObjectFromList("some-valid-TList-pointer","some-object-name"); + + // Insanity checks: + if (!list) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + if (!objectName) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + if (0 == list->GetEntries()) { + return nullptr; + } + + // The object is in the current base list: + TObject* objectFinal = list->FindObject(objectName); // the final object I am after + if (objectFinal) { + return objectFinal; + } + + // Otherwise, search for the object recursively in the nested lists: + TObject* objectIter = nullptr; // iterator object in the loop below + TIter next(list); + while ((objectIter = next())) // double round braces are to silence the warnings + { + if (auto* subList = dynamic_cast(objectIter)) { + objectFinal = getObjectFromList(subList, objectName); + if (objectFinal) { + return objectFinal; + } + } + } // while(objectIter = next()) + + return nullptr; + } // TObject* getObjectFromList(TList *list, char *objectName) + + TH1D* getHistogramWithWeights(const char* filePath, const char* runNumber) + { + // *) Return value: + TH1D* hist = nullptr; + TList* baseList = nullptr; // base top-level list in the TFile, e.g. named "ccdb_object" + TList* listWithRuns = nullptr; // nested list with run-wise TList's holding run-specific weights + + // *) Determine from filePath if the file is on a local machine, or in home dir AliEn, or in CCDB: + // Algorithm: If filePath begins with "/alice/cern.ch/" then it's in the home dir AliEn; + // If filePath begins with "/alice-ccdb.cern.ch/" then it's in CCDB. Therefore, files in AliEn and CCDB must be specified with abs path; + // for local files both abs and relative paths are just fine. + bool bFileIsInAliEn = false; + bool bFileIsInCCDB = false; + + std::string path(filePath); + + if (path.starts_with("/alice/cern.ch/")) { + bFileIsInAliEn = true; + } else if (path.starts_with("/alice-ccdb.cern.ch/")) { + bFileIsInCCDB = true; + } + + if (bFileIsInAliEn) { + // File you want to access is in your home dir in AliEn: + const TGrid* alien = TGrid::Connect("alien", gSystem->Getenv("USER"), "", ""); // do not forget to add #include to the preamble of your analysis task + if (!alien) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + TFile* weightsFile = TFile::Open(Form("alien://%s", filePath), "READ"); // yes, ROOT can open a file transparently, even if it's sitting in AliEn, with this specific syntax + if (!weightsFile) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + weightsFile->GetObject("ccdb_object", baseList); + if (!baseList) { + // weightsFile->ls(); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + // Finally, from the top-level TList, get the desired nested TList => the technical problem here is that it can be nested at any level, + // for that there is a helper utility function getObjectFromList(...) , see its implementation further below + listWithRuns = dynamic_cast(getObjectFromList(baseList, runNumber)); + if (!listWithRuns) { + TString runNumberWithLeadingZeroes = "000"; + runNumberWithLeadingZeroes += runNumber; // another try, with "000" prepended to run number + listWithRuns = dynamic_cast(getObjectFromList(baseList, runNumberWithLeadingZeroes.Data())); + if (!listWithRuns) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + } + + // OK, we got the desired TList with efficiency corrections, after that we can use the common code for all 3 cases (local, AliEn, CCDB, that common code is below) + + } else if (bFileIsInCCDB) { + // File you want to access is in your home dir in CCDB: + // Remember that here I do not access the file; instead, I directly access the object in that file. + // My home dir in CCDB: https://alice-ccdb.cern.ch/browse/Users/a/abilandz/ => adapt for your case + ccdb->setURL("https://alice-ccdb.cern.ch"); // to be able to use "ccdb" this object in your analysis task, see 4b/ below + baseList = dynamic_cast(ccdb->get(TString(filePath).ReplaceAll("/alice-ccdb.cern.ch/", "").Data())); + if (!baseList) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + listWithRuns = dynamic_cast(getObjectFromList(baseList, runNumber)); + if (!listWithRuns) { + TString runNumberWithLeadingZeroes = "000"; + runNumberWithLeadingZeroes += runNumber; // another try, with "000" prepended to run number + listWithRuns = dynamic_cast(getObjectFromList(baseList, runNumberWithLeadingZeroes.Data())); + if (!listWithRuns) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + } + + // OK, we got the desired TList with efficiency corrections, after that we + // can use the common code for all 3 cases (local, AliEn, CCDB, that + // common code is below) + } else { + // this is the local case: + // Check if the external ROOT file exists at the specified path: + if (gSystem->AccessPathName(filePath, kFileExists)) { + LOGF(info, "\033[1;33m if(gSystem->AccessPathName(filePath,kFileExists)), filePath = %s \033[0m", filePath); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + TFile* weightsFile = TFile::Open(filePath, "READ"); + if (!weightsFile) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + weightsFile->GetObject("ccdb_object", baseList); + + if (!baseList) { + // weightsFile->ls(); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + listWithRuns = dynamic_cast(getObjectFromList(baseList, runNumber)); + if (!listWithRuns) { + TString runNumberWithLeadingZeroes = "000"; + runNumberWithLeadingZeroes += runNumber; // another try, with "000" prepended to run number + listWithRuns = dynamic_cast(getObjectFromList(baseList, runNumberWithLeadingZeroes.Data())); + if (!listWithRuns) { + // baseList->ls(); + // LOGF(fatal, "\033[1;31m%s at line %d : this crash can happen if in the output file there is no list with weights for the current run number = %s\033[0m", __FUNCTION__, __LINE__, tc.fRunNumber.Data()); + } + } + } + + // Here comes the common code for all three cases, where from "listWithRuns" you fetch the desired histogram with efficiency corrections: + // listWithRuns->ls(); + + if (!listWithRuns) { + LOGF(fatal, + "\033[1;31m%s: listWithRuns is null for run %s\033[0m", + __FUNCTION__, runNumber); + } + + hist = dynamic_cast(listWithRuns->FindObject("h_invert")); + if (!hist) { + LOGF(fatal, "%s: histogram 'hist1' not found in run list", __FUNCTION__); + } + hist->SetDirectory(nullptr); + auto histClone = dynamic_cast(hist->Clone()); + histClone->SetDirectory(nullptr); + + delete baseList; // release back the memory + + return histClone; + } + + // templates + template + bool eventCuts(T1 const& collision) + { + if constexpr (rs == ERec || rs == ERecAndSim) { + if (cfEventCutSwitch) // event level cuts for Rec + { + if (collision.posZ() > cfVertexZCutRange.value[1] || collision.posZ() < cfVertexZCutRange.value[0]) { + return false; + } // vertex z cut + if constexpr (rs == ERecAndSim) // event level cuts for Sim + { + if (!collision.has_mcCollision()) { + return false; + } + auto mcCollision = collision.mcCollision(); // corresponding MC truth simulated particle + if (mcCollision.posZ() > cfVertexZCutRange.value[1] || mcCollision.posZ() < cfVertexZCutRange.value[0]) { + return false; + } // vertex z cut + } + } + } + + return true; + } + + template + void eventHistFill(T1 const& collision, T2 const& tracks) + { + auto thisCent = collision.centFT0C(); // use auto to determine the type + switch (centralityEstimator) { + case EFT0C: + thisCent = collision.centFT0C(); + break; + case EFT0M: + thisCent = collision.centFT0M(); + break; + case EFV0A: + thisCent = collision.centFV0A(); + break; + case ENTPV: + thisCent = collision.centNTPV(); + break; + default: + LOG(warning) << "Unknown centrality estimator. Using FT0C as default."; + break; // thisCent is already FT0C + } + + auto thisRefMult = collision.multTPC(); // use auto to determine the type + switch (multiplicityTables) { + case EMultTPC: + thisRefMult = collision.multTPC(); + break; + case EMultFV0M: + thisRefMult = collision.multFV0M(); + break; + case EMultFT0C: + thisRefMult = collision.multFT0C(); + break; + case EMultFT0M: + thisRefMult = collision.multFT0M(); + break; + case EMultNTracksPV: + thisRefMult = collision.multNTracksPV(); + break; + default: + LOG(warning) << "Unknown multiplicity. Using multTPC as default."; + break; // thisRefMult is already multTPC + } + + if constexpr (rs == ERec || rs == ERecAndSim) { + // Fill reconstructed-level event histograms + int multiplicityRec = static_cast(tracks.size()); + if constexpr (cuts == ENoCuts) { + ec.fEventHistograms[EHistMultiplicity][ERec][ENoCuts]->Fill(multiplicityRec); + ec.fEventHistograms[EHistCentrality][ERec][ENoCuts]->Fill(thisCent); + ec.fEventHistograms[EHistReferenceMultiplicity][ERec][ENoCuts]->Fill(thisRefMult); + ec.fEventHistograms[EHistVertexX][ERec][ENoCuts]->Fill(collision.posX()); + ec.fEventHistograms[EHistVertexY][ERec][ENoCuts]->Fill(collision.posY()); + ec.fEventHistograms[EHistVertexZ][ERec][ENoCuts]->Fill(collision.posZ()); + } + if constexpr (cuts == EWithCuts) { + ec.fEventHistograms[EHistMultiplicity][ERec][EWithCuts]->Fill(multiplicityRec); + ec.fEventHistograms[EHistCentrality][ERec][EWithCuts]->Fill(thisCent); + ec.fEventHistograms[EHistReferenceMultiplicity][ERec][EWithCuts]->Fill(thisRefMult); + ec.fEventHistograms[EHistVertexX][ERec][EWithCuts]->Fill(collision.posX()); + ec.fEventHistograms[EHistVertexY][ERec][EWithCuts]->Fill(collision.posY()); + ec.fEventHistograms[EHistVertexZ][ERec][EWithCuts]->Fill(collision.posZ()); + } + + // Fill MC simulated-level event histograms if both reconstructed and simulated data are processed + if constexpr (rs == ERecAndSim) { + if (!collision.has_mcCollision()) { + return; + } + auto mcCollision = collision.mcCollision(); // corresponding MC truth simulated particle + int multiplicitySim = static_cast(tracks.size()); + float impactParameter = mcCollision.impactParameter(); + float centralitySim = math::PI * impactParameter * impactParameter / sigmaInel; // centrality for sim derived from impact parameter + if constexpr (cuts == ENoCuts) { + ec.fEventHistograms[EHistMultiplicity][ESim][ENoCuts]->Fill(multiplicitySim); + ec.fEventHistograms[EHistCentrality][ESim][ENoCuts]->Fill(centralitySim); + ec.fEventHistograms[EHistImpactParameter][ESim][ENoCuts]->Fill(mcCollision.impactParameter()); + ec.fEventHistograms[EHistVertexX][ESim][ENoCuts]->Fill(mcCollision.posX()); + ec.fEventHistograms[EHistVertexY][ESim][ENoCuts]->Fill(mcCollision.posY()); + ec.fEventHistograms[EHistVertexZ][ESim][ENoCuts]->Fill(mcCollision.posZ()); + } + + if constexpr (cuts == EWithCuts) { + ec.fEventHistograms[EHistMultiplicity][ESim][EWithCuts]->Fill(multiplicitySim); + ec.fEventHistograms[EHistCentrality][ESim][EWithCuts]->Fill(centralitySim); + ec.fEventHistograms[EHistImpactParameter][ESim][EWithCuts]->Fill(mcCollision.impactParameter()); + ec.fEventHistograms[EHistVertexX][ESim][EWithCuts]->Fill(mcCollision.posX()); + ec.fEventHistograms[EHistVertexY][ESim][EWithCuts]->Fill(mcCollision.posY()); + ec.fEventHistograms[EHistVertexZ][ESim][EWithCuts]->Fill(mcCollision.posZ()); + } + } + } + } + + template + bool particleCuts(T const& track) + { + if constexpr (rs == ERec || rs == ERecAndSim) { + if (cfPtCutSwitch) // Vertex Z cuts for Rec + { + if (track.pt() < cfPtCutRange.value[0] || track.pt() > cfPtCutRange.value[1]) { + return false; + } + if constexpr (rs == ERecAndSim) // Vertex Z cuts for Sim + { + if (!track.has_mcParticle()) { + return false; + } + auto mcParticle = track.mcParticle(); // corresponding MC truth simulated particle + if (mcParticle.pt() < cfPtCutRange.value[0] || mcParticle.pt() > cfPtCutRange.value[1]) { + return false; + } + } + } + } + + return true; + } + + template + void particleHistFill(T1 const& track) + { + if constexpr (rs == ERec || rs == ERecAndSim) { + if constexpr (cuts == ENoCuts) { + pc.fParticleHistograms[EHistPt][ERec][ENoCuts]->Fill(track.pt()); + pc.fParticleHistograms[EHistPhi][ERec][ENoCuts]->Fill(track.phi()); + pc.fParticleHistograms[EHistEta][ERec][ENoCuts]->Fill(track.eta()); + } + + if constexpr (cuts == EWithCuts) { + pc.fParticleHistograms[EHistPt][ERec][EWithCuts]->Fill(track.pt()); + pc.fParticleHistograms[EHistPhi][ERec][EWithCuts]->Fill(track.phi()); + pc.fParticleHistograms[EHistEta][ERec][EWithCuts]->Fill(track.eta()); + } + + // ... and corresponding MC truth simulated: + // See https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx + // See https://aliceo2group.github.io/analysis-framework/docs/datamodel/ao2dTables.html#montecarlo + if constexpr (rs == ERecAndSim) { + if (!track.has_mcParticle()) { + LOGF(warning, " No MC particle for this track, skip..."); + return; + } + auto mcParticle = track.mcParticle(); // corresponding MC truth simulated particle + if constexpr (cuts == ENoCuts) { + pc.fParticleHistograms[EHistPt][ESim][ENoCuts]->Fill(mcParticle.pt()); + pc.fParticleHistograms[EHistPhi][ESim][ENoCuts]->Fill(mcParticle.phi()); + pc.fParticleHistograms[EHistEta][ESim][ENoCuts]->Fill(mcParticle.eta()); + } + + if constexpr (cuts == EWithCuts) { + pc.fParticleHistograms[EHistPt][ESim][EWithCuts]->Fill(mcParticle.pt()); + pc.fParticleHistograms[EHistPhi][ESim][EWithCuts]->Fill(mcParticle.phi()); + pc.fParticleHistograms[EHistEta][ESim][EWithCuts]->Fill(mcParticle.eta()); + } + } + } + } + + template + void qaFill(T1 const& collision) + { + auto thisCent = collision.centFT0C(); // use auto to determine the type + switch (centralityEstimator) { + case EFT0C: + thisCent = collision.centFT0C(); + break; + case EFT0M: + thisCent = collision.centFT0M(); + break; + case EFV0A: + thisCent = collision.centFV0A(); + break; + case ENTPV: + thisCent = collision.centNTPV(); + break; + default: + LOG(warning) << "Unknown centrality estimator. Using FT0C as default."; + break; // thisCent is already FT0C + } + if constexpr (rs == ERecAndSim || rs == ESim) { + if (!collision.has_mcCollision()) { + return; + } + auto mcCollision = collision.mcCollision(); + float impactParameter = mcCollision.impactParameter(); + float centralitySim = math::PI * impactParameter * impactParameter / sigmaInel; // centrality for sim derived from impact parameter + qa.fHistCentralityRecSim->Fill(thisCent, centralitySim); + } + } + + // *) Define all member functions to be called in the main process* functions: + template + void steer(T1 const& collision, T2 const& tracks) + { + // Dry run: + if (tc.fDryRun) { + return; + } + + // Fill Quality Assurance + if (qualityAssuranceSwitch) { + qaFill(collision); + } + + // Fill Event Hist + eventHistFill(collision, tracks); + if (cfEventCutSwitch && eventCuts(collision)) { + eventHistFill(collision, tracks); + } + + // Print current run number: + LOGF(info, "Run number: %d", collision.bc().runNumber()); + + // Print centrality estimated with the selected estimator: + // LOGF(info, "Centrality: %f", thisCent); + + // Print vertex X position: + LOGF(info, "Vertex X position: %f", collision.posX()); + + // Main loop over particles: + auto track = tracks.iteratorAt(0); // set the type and scope from one instance + for (int64_t i = 0; i < tracks.size(); i++) { + // Print track azimuthal angle: + // LOGF(info, "Track azimuthal angle: %f", track.phi()); + + track = tracks.iteratorAt(i); + // Fill reconstructed ...: + particleHistFill(track); + if (cfPtCutSwitch && cfEventCutSwitch && eventCuts(collision) && particleCuts(track)) { + particleHistFill(track); + } + } // end of for (int64_t i = 0; i < tracks.size(); i++) { + } // end of template void steer(T1 const& collision, T2 const& tracks) { + + // *) Initialize and book all objects: + void init(InitContext&) + { + // ... code to book and initialize all analysis objects ... + + // *) Set automatically what to process, from an implicit variable "doprocessSomEProcessName" within a PROCESS_SWITCH clause: + tc.fProcess[EProcessRec] = doprocessRec; + tc.fProcess[EProcessRecSim] = doprocessRecSim; + tc.fProcess[EProcessSim] = doprocessSim; + + // *) Configure your task using configurables in the json file: + tc.fDryRun = cfDryRun; + + // *) Book base list: + auto* temp = new TList(); + temp->SetOwner(true); + fBaseList.setObject(temp); + + if (cfExternalFileSwitch) { + // *) Book External Hist List + ex.fExternalHistogramsList = new TList(); + ex.fExternalHistogramsList->SetName("ExternalHistograms"); + ex.fExternalHistogramsList->SetOwner(true); + fBaseList->Add(ex.fExternalHistogramsList); + + // *) Book and Fill external hist + ex.fhistWeights = getHistogramWithWeights(cfFileWithWeights.value.c_str(), "000123456"); + ex.fhistWeights->SetTitle(cfFileWithWeights.value.c_str()); + ex.fExternalHistogramsList->Add(ex.fhistWeights); + } + + // *) Book and nest all other TLists: + pc.fParticleHistogramsList = new TList(); + pc.fParticleHistogramsList->SetName("ParticleHistograms"); + pc.fParticleHistogramsList->SetOwner(true); + fBaseList->Add(pc.fParticleHistogramsList); // any nested TList in the base TList appears as a subdir in the output ROOT file + + // *) Book pt and phi distribution with binning defined through configurables in the json file: + vector lPtBins = cfPtBins.value; // define local array and initialize it from an array set in the configurables + int nBinsPt = static_cast(lPtBins[0]); + float minPt = lPtBins[1]; + float maxPt = lPtBins[2]; + + vector lPhiBins = cfPhiBins.value; // define local array and initialize it from an array set in the configurables + int nBinsPhi = static_cast(lPhiBins[0]); + float minPhi = lPhiBins[1]; + float maxPhi = lPhiBins[2]; + + vector lEtaBins = cfEtaBins.value; // define local array and initialize it from an array set in the configurables + int nBinsEta = static_cast(lEtaBins[0]); + float minEta = lEtaBins[1]; + float maxEta = lEtaBins[2]; + + if (doprocessRec || doprocessRecSim) { + pc.fParticleHistograms[EHistPt][ERec][ENoCuts] = new TH1F("[EHistPt][ERec][ENoCuts]", "pt distribution for reconstructed particles before cuts", nBinsPt, minPt, maxPt); + pc.fParticleHistograms[EHistPt][ERec][ENoCuts]->GetXaxis()->SetTitle("p_{T}"); + pc.fParticleHistograms[EHistPt][ERec][ENoCuts]->SetColors(kRed, -1, kRed); + pc.fParticleHistogramsList->Add(pc.fParticleHistograms[EHistPt][ERec][ENoCuts]); + + pc.fParticleHistograms[EHistPhi][ERec][ENoCuts] = new TH1F("[EHistPhi][ERec][ENoCuts]", "phi distribution for reconstructed particles before cuts", nBinsPhi, minPhi, maxPhi); + pc.fParticleHistograms[EHistPhi][ERec][ENoCuts]->GetXaxis()->SetTitle("p_{phi}"); + pc.fParticleHistograms[EHistPhi][ERec][ENoCuts]->SetColors(kRed, -1, kRed); + pc.fParticleHistogramsList->Add(pc.fParticleHistograms[EHistPhi][ERec][ENoCuts]); + + pc.fParticleHistograms[EHistEta][ERec][ENoCuts] = new TH1F("[EHistEta][ERec][ENoCuts]", "eta distribution for reconstructed particles before cuts", nBinsEta, minEta, maxEta); + pc.fParticleHistograms[EHistEta][ERec][ENoCuts]->GetXaxis()->SetTitle("#eta"); + pc.fParticleHistograms[EHistEta][ERec][ENoCuts]->SetColors(kRed, -1, kRed); + pc.fParticleHistogramsList->Add(pc.fParticleHistograms[EHistEta][ERec][ENoCuts]); + + if (cfPtCutSwitch) { + pc.fParticleHistograms[EHistPt][ERec][EWithCuts] = new TH1F("[EHistPt][ERec][EWithCuts]", "pt distribution for reconstructed particles after cuts", nBinsPt, minPt, maxPt); + pc.fParticleHistograms[EHistPt][ERec][EWithCuts]->GetXaxis()->SetTitle("p_{T}"); + pc.fParticleHistograms[EHistPt][ERec][EWithCuts]->SetColors(kGreen, -1, kGreen); + pc.fParticleHistogramsList->Add(pc.fParticleHistograms[EHistPt][ERec][EWithCuts]); + + pc.fParticleHistograms[EHistPhi][ERec][EWithCuts] = new TH1F("[EHistPhi][ERec][EWithCuts]", "phi distribution for reconstructed particles after cuts", nBinsPhi, minPhi, maxPhi); + pc.fParticleHistograms[EHistPhi][ERec][EWithCuts]->GetXaxis()->SetTitle("p_{phi}"); + pc.fParticleHistograms[EHistPhi][ERec][EWithCuts]->SetColors(kGreen, -1, kGreen); + pc.fParticleHistogramsList->Add(pc.fParticleHistograms[EHistPhi][ERec][EWithCuts]); + + pc.fParticleHistograms[EHistEta][ERec][EWithCuts] = new TH1F("[EHistEta][ERec][EWithCuts]", "eta distribution for reconstructed particles after cuts", nBinsEta, minEta, maxEta); + pc.fParticleHistograms[EHistEta][ERec][EWithCuts]->GetXaxis()->SetTitle("#eta"); + pc.fParticleHistograms[EHistEta][ERec][EWithCuts]->SetColors(kGreen, -1, kGreen); + pc.fParticleHistogramsList->Add(pc.fParticleHistograms[EHistEta][ERec][EWithCuts]); + } + } + + if (doprocessSim || doprocessRecSim) { + pc.fParticleHistograms[EHistPt][ESim][ENoCuts] = new TH1F("[EHistPt][ESim][ENoCuts]", "pt distribution for simulated particles before cuts", nBinsPt, minPt, maxPt); + pc.fParticleHistograms[EHistPt][ESim][ENoCuts]->GetXaxis()->SetTitle("p_{T}"); + pc.fParticleHistograms[EHistPt][ESim][ENoCuts]->SetColors(kRed, -1, kRed); + pc.fParticleHistogramsList->Add(pc.fParticleHistograms[EHistPt][ESim][ENoCuts]); + + pc.fParticleHistograms[EHistPhi][ESim][ENoCuts] = new TH1F("[EHistPhi][ESim][ENoCuts]", "phi distribution for simulated particles before cuts", nBinsPhi, minPhi, maxPhi); + pc.fParticleHistograms[EHistPhi][ESim][ENoCuts]->GetXaxis()->SetTitle("p_{phi}"); + pc.fParticleHistograms[EHistPhi][ESim][ENoCuts]->SetColors(kRed, -1, kRed); + pc.fParticleHistogramsList->Add(pc.fParticleHistograms[EHistPhi][ESim][ENoCuts]); + + pc.fParticleHistograms[EHistEta][ESim][ENoCuts] = new TH1F("[EHistEta][ESim][ENoCuts]", "eta distribution for simulated particles before cuts", nBinsEta, minEta, maxEta); + pc.fParticleHistograms[EHistEta][ESim][ENoCuts]->GetXaxis()->SetTitle("#eta"); + pc.fParticleHistograms[EHistEta][ESim][ENoCuts]->SetColors(kRed, -1, kRed); + pc.fParticleHistogramsList->Add(pc.fParticleHistograms[EHistEta][ESim][ENoCuts]); + + if (cfPtCutSwitch) { + pc.fParticleHistograms[EHistPt][ESim][EWithCuts] = new TH1F("[EHistPt][ESim][EWithCuts]", "pt distribution for simulated particles after cuts", nBinsPt, minPt, maxPt); + pc.fParticleHistograms[EHistPt][ESim][EWithCuts]->GetXaxis()->SetTitle("p_{T}"); + pc.fParticleHistograms[EHistPt][ESim][EWithCuts]->SetColors(kGreen, -1, kGreen); + pc.fParticleHistogramsList->Add(pc.fParticleHistograms[EHistPt][ESim][EWithCuts]); + + pc.fParticleHistograms[EHistPhi][ESim][EWithCuts] = new TH1F("[EHistPhi][ESim][EWithCuts]", "phi distribution for simulated particles after cuts", nBinsPhi, minPhi, maxPhi); + pc.fParticleHistograms[EHistPhi][ESim][EWithCuts]->GetXaxis()->SetTitle("p_{phi}"); + pc.fParticleHistograms[EHistPhi][ESim][EWithCuts]->SetColors(kGreen, -1, kGreen); + pc.fParticleHistogramsList->Add(pc.fParticleHistograms[EHistPhi][ESim][EWithCuts]); + + pc.fParticleHistograms[EHistEta][ESim][EWithCuts] = new TH1F("[EHistEta][ESim][EWithCuts]", "eta distribution for simulated particles after cuts", nBinsEta, minEta, maxEta); + pc.fParticleHistograms[EHistEta][ESim][EWithCuts]->GetXaxis()->SetTitle("#eta"); + pc.fParticleHistograms[EHistEta][ESim][EWithCuts]->SetColors(kGreen, -1, kGreen); + pc.fParticleHistogramsList->Add(pc.fParticleHistograms[EHistEta][ESim][EWithCuts]); + } + } + + // Book event-level histograms + ec.fEventHistogramsList = new TList(); + ec.fEventHistogramsList->SetName("EventHistograms"); + ec.fEventHistogramsList->SetOwner(true); + fBaseList->Add(ec.fEventHistogramsList); + + vector lCent = cfCentBins.value; + int nBinsCent = static_cast(lCent[0]); + float minCent = lCent[1]; + float maxCent = lCent[2]; + + vector lMultRec = cfMultBinsRec.value; + int nBinsMultRec = static_cast(lMultRec[0]); + float minMultRec = lMultRec[1]; + float maxMultRec = lMultRec[2]; + + vector lMultRef = cfMultBinsRef.value; + int nBinsMultRef = static_cast(lMultRef[0]); + float minMultRef = lMultRef[1]; + float maxMultRef = lMultRef[2]; + + vector lMultSim = cfMultBinsSim.value; + int nBinsMultSim = static_cast(lMultSim[0]); + float minMultSim = lMultSim[1]; + float maxMultSim = lMultSim[2]; + + vector lVx = cfVxBins.value; + int nBinsVx = static_cast(lVx[0]); + float minVx = lVx[1]; + float maxVx = lVx[2]; + + vector lVy = cfVyBins.value; + int nBinsVy = static_cast(lVy[0]); + float minVy = lVy[1]; + float maxVy = lVy[2]; + + vector lVz = cfVzBins.value; + int nBinsVz = static_cast(lVz[0]); + float minVz = lVz[1]; + float maxVz = lVz[2]; + + vector lIp = cfIpBins.value; + int nBinsIp = static_cast(lIp[0]); + float minIp = lIp[1]; + float maxIp = lIp[2]; + + if (doprocessRec || doprocessRecSim) { + ec.fEventHistograms[EHistCentrality][ERec][ENoCuts] = new TH1F("[EHistCentrality][ERec][ENoCuts]", "Centrality (reconstructed) before cuts", nBinsCent, minCent, maxCent); + ec.fEventHistograms[EHistCentrality][ERec][ENoCuts]->GetXaxis()->SetTitle("Centrality"); + ec.fEventHistograms[EHistCentrality][ERec][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistCentrality][ERec][ENoCuts]); + + ec.fEventHistograms[EHistMultiplicity][ERec][ENoCuts] = new TH1F("[EHistMultiplicity][ERec][ENoCuts]", "Multiplicity (reconstructed) before cuts", nBinsMultRec, minMultRec, maxMultRec); + ec.fEventHistograms[EHistMultiplicity][ERec][ENoCuts]->GetXaxis()->SetTitle("Multiplicity"); + ec.fEventHistograms[EHistMultiplicity][ERec][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistMultiplicity][ERec][ENoCuts]); + + ec.fEventHistograms[EHistReferenceMultiplicity][ERec][ENoCuts] = new TH1F("[EHistReferenceMultiplicity][ERec][ENoCuts]", "Reference Multiplicity before cuts", nBinsMultRef, minMultRef, maxMultRef); + ec.fEventHistograms[EHistReferenceMultiplicity][ERec][ENoCuts]->GetXaxis()->SetTitle("Reference Multiplicity"); + ec.fEventHistograms[EHistReferenceMultiplicity][ERec][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistReferenceMultiplicity][ERec][ENoCuts]); + + ec.fEventHistograms[EHistVertexX][ERec][ENoCuts] = new TH1F("[EHistVertexX][ERec][ENoCuts]", "Vertex X (reconstructed) before cuts", nBinsVx, minVx, maxVx); + ec.fEventHistograms[EHistVertexX][ERec][ENoCuts]->GetXaxis()->SetTitle("Vertex X"); + ec.fEventHistograms[EHistVertexX][ERec][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexX][ERec][ENoCuts]); + + ec.fEventHistograms[EHistVertexY][ERec][ENoCuts] = new TH1F("[EHistVertexY][ERec][ENoCuts]", "Vertex Y (reconstructed) before cuts", nBinsVy, minVy, maxVy); + ec.fEventHistograms[EHistVertexY][ERec][ENoCuts]->GetXaxis()->SetTitle("Vertex Y"); + ec.fEventHistograms[EHistVertexY][ERec][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexY][ERec][ENoCuts]); + + ec.fEventHistograms[EHistVertexZ][ERec][ENoCuts] = new TH1F("[EHistVertexZ][ERec][ENoCuts]", "Vertex Z (reconstructed) before cuts", nBinsVz, minVz, maxVz); + ec.fEventHistograms[EHistVertexZ][ERec][ENoCuts]->GetXaxis()->SetTitle("Vertex Z"); + ec.fEventHistograms[EHistVertexZ][ERec][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexZ][ERec][ENoCuts]); + + if (cfEventCutSwitch) { + ec.fEventHistograms[EHistCentrality][ERec][EWithCuts] = new TH1F("[EHistCentrality][ERec][EWithCuts]", "Centrality (reconstructed) after cuts", nBinsCent, minCent, maxCent); + ec.fEventHistograms[EHistCentrality][ERec][EWithCuts]->GetXaxis()->SetTitle("Centrality"); + ec.fEventHistograms[EHistCentrality][ERec][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistCentrality][ERec][EWithCuts]); + + ec.fEventHistograms[EHistMultiplicity][ERec][EWithCuts] = new TH1F("[EHistMultiplicity][ERec][EWithCuts]", "Multiplicity (reconstructed) after cuts", nBinsMultRec, minMultRec, maxMultRec); + ec.fEventHistograms[EHistMultiplicity][ERec][EWithCuts]->GetXaxis()->SetTitle("Multiplicity"); + ec.fEventHistograms[EHistMultiplicity][ERec][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistMultiplicity][ERec][EWithCuts]); + + ec.fEventHistograms[EHistReferenceMultiplicity][ERec][EWithCuts] = new TH1F("[EHistReferenceMultiplicity][ERec][EWithCuts]", "Reference Multiplicity after cuts", nBinsMultRef, minMultRef, maxMultRef); + ec.fEventHistograms[EHistReferenceMultiplicity][ERec][EWithCuts]->GetXaxis()->SetTitle("Reference Multiplicity"); + ec.fEventHistograms[EHistReferenceMultiplicity][ERec][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistReferenceMultiplicity][ERec][EWithCuts]); + + ec.fEventHistograms[EHistVertexX][ERec][EWithCuts] = new TH1F("[EHistVertexX][ERec][EWithCuts]", "Vertex X (reconstructed) after cuts", nBinsVx, minVx, maxVx); + ec.fEventHistograms[EHistVertexX][ERec][EWithCuts]->GetXaxis()->SetTitle("Vertex X"); + ec.fEventHistograms[EHistVertexX][ERec][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexX][ERec][EWithCuts]); + + ec.fEventHistograms[EHistVertexY][ERec][EWithCuts] = new TH1F("[EHistVertexY][ERec][EWithCuts]", "Vertex Y (reconstructed) after cuts", nBinsVy, minVy, maxVy); + ec.fEventHistograms[EHistVertexY][ERec][EWithCuts]->GetXaxis()->SetTitle("Vertex Y"); + ec.fEventHistograms[EHistVertexY][ERec][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexY][ERec][EWithCuts]); + + ec.fEventHistograms[EHistVertexZ][ERec][EWithCuts] = new TH1F("[EHistVertexZ][ERec][EWithCuts]", "Vertex Z (reconstructed) after cuts", nBinsVz, minVz, maxVz); + ec.fEventHistograms[EHistVertexZ][ERec][EWithCuts]->GetXaxis()->SetTitle("Vertex Z"); + ec.fEventHistograms[EHistVertexZ][ERec][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexZ][ERec][EWithCuts]); + } + } + + if (doprocessSim || doprocessRecSim) { + ec.fEventHistograms[EHistCentrality][ESim][ENoCuts] = new TH1F("[EHistCentrality][ESim][ENoCuts]", "Centrality (simulated) before cuts", nBinsCent, minCent, maxCent); + ec.fEventHistograms[EHistCentrality][ESim][ENoCuts]->GetXaxis()->SetTitle("Centrality"); + ec.fEventHistograms[EHistCentrality][ESim][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistCentrality][ESim][ENoCuts]); + + ec.fEventHistograms[EHistMultiplicity][ESim][ENoCuts] = new TH1F("[EHistMultiplicity][ESim][ENoCuts]", "Multiplicity (simulated) before cuts", nBinsMultSim, minMultSim, maxMultSim); + ec.fEventHistograms[EHistMultiplicity][ESim][ENoCuts]->GetXaxis()->SetTitle("Multiplicity"); + ec.fEventHistograms[EHistMultiplicity][ESim][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistMultiplicity][ESim][ENoCuts]); + + ec.fEventHistograms[EHistVertexX][ESim][ENoCuts] = new TH1F("[EHistVertexX][ESim][ENoCuts]", "Vertex X (simulated) before cuts", nBinsVx, minVx, maxVx); + ec.fEventHistograms[EHistVertexX][ESim][ENoCuts]->GetXaxis()->SetTitle("Vertex X"); + ec.fEventHistograms[EHistVertexX][ESim][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexX][ESim][ENoCuts]); + + ec.fEventHistograms[EHistVertexY][ESim][ENoCuts] = new TH1F("[EHistVertexY][ESim][ENoCuts]", "Vertex Y (simulated) before cuts", nBinsVy, minVy, maxVy); + ec.fEventHistograms[EHistVertexY][ESim][ENoCuts]->GetXaxis()->SetTitle("Vertex Y"); + ec.fEventHistograms[EHistVertexY][ESim][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexY][ESim][ENoCuts]); + + ec.fEventHistograms[EHistVertexZ][ESim][ENoCuts] = new TH1F("[EHistVertexZ][ESim][ENoCuts]", "Vertex Z (simulated) before cuts", nBinsVz, minVz, maxVz); + ec.fEventHistograms[EHistVertexZ][ESim][ENoCuts]->GetXaxis()->SetTitle("Vertex Z"); + ec.fEventHistograms[EHistVertexZ][ESim][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexZ][ESim][ENoCuts]); + + ec.fEventHistograms[EHistImpactParameter][ESim][ENoCuts] = new TH1F("[EHistImpactParameter][ESim][ENoCuts]", "Impact Parameter (simulated) before cuts", nBinsIp, minIp, maxIp); + ec.fEventHistograms[EHistImpactParameter][ESim][ENoCuts]->GetXaxis()->SetTitle("Impact Parameter"); + ec.fEventHistograms[EHistImpactParameter][ESim][ENoCuts]->SetColors(kRed, -1, kRed); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistImpactParameter][ESim][ENoCuts]); + + if (cfEventCutSwitch) { + ec.fEventHistograms[EHistCentrality][ESim][EWithCuts] = new TH1F("[EHistCentrality][ESim][EWithCuts]", "Centrality (simulated) after cuts", nBinsCent, minCent, maxCent); + ec.fEventHistograms[EHistCentrality][ESim][EWithCuts]->GetXaxis()->SetTitle("Centrality"); + ec.fEventHistograms[EHistCentrality][ESim][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistCentrality][ESim][EWithCuts]); + + ec.fEventHistograms[EHistMultiplicity][ESim][EWithCuts] = new TH1F("[EHistMultiplicity][ESim][EWithCuts]", "Multiplicity (simulated) after cuts", nBinsMultSim, minMultSim, maxMultSim); + ec.fEventHistograms[EHistMultiplicity][ESim][EWithCuts]->GetXaxis()->SetTitle("Multiplicity"); + ec.fEventHistograms[EHistMultiplicity][ESim][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistMultiplicity][ESim][EWithCuts]); + + ec.fEventHistograms[EHistVertexX][ESim][EWithCuts] = new TH1F("[EHistVertexX][ESim][EWithCuts]", "Vertex X (simulated) after cuts", nBinsVx, minVx, maxVx); + ec.fEventHistograms[EHistVertexX][ESim][EWithCuts]->GetXaxis()->SetTitle("Vertex X"); + ec.fEventHistograms[EHistVertexX][ESim][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexX][ESim][EWithCuts]); + + ec.fEventHistograms[EHistVertexY][ESim][EWithCuts] = new TH1F("[EHistVertexY][ESim][EWithCuts]", "Vertex Y (simulated) after cuts", nBinsVy, minVy, maxVy); + ec.fEventHistograms[EHistVertexY][ESim][EWithCuts]->GetXaxis()->SetTitle("Vertex Y"); + ec.fEventHistograms[EHistVertexY][ESim][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexY][ESim][EWithCuts]); + + ec.fEventHistograms[EHistVertexZ][ESim][EWithCuts] = new TH1F("[EHistVertexZ][ESim][EWithCuts]", "Vertex Z (simulated) after cuts", nBinsVz, minVz, maxVz); + ec.fEventHistograms[EHistVertexZ][ESim][EWithCuts]->GetXaxis()->SetTitle("Vertex Z"); + ec.fEventHistograms[EHistVertexZ][ESim][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistVertexZ][ESim][EWithCuts]); + + ec.fEventHistograms[EHistImpactParameter][ESim][EWithCuts] = new TH1F("[EHistImpactParameter][ESim][EWithCuts]", "Impact Parameter (simulated) after cuts", nBinsIp, minIp, maxIp); + ec.fEventHistograms[EHistImpactParameter][ESim][EWithCuts]->GetXaxis()->SetTitle("Impact Parameter"); + ec.fEventHistograms[EHistImpactParameter][ESim][EWithCuts]->SetColors(kGreen, -1, kGreen); + ec.fEventHistogramsList->Add(ec.fEventHistograms[EHistImpactParameter][ESim][EWithCuts]); + } + } + + if (qualityAssuranceSwitch && doprocessRecSim) { + qa.fQualityAssuranceList = new TList(); + qa.fQualityAssuranceList->SetName("QualityAssurance"); + qa.fQualityAssuranceList->SetOwner(true); + fBaseList->Add(qa.fQualityAssuranceList); + + qa.fHistCentralityRecSim = new TH2F("fHistCentralityRecSim", "Centrality Rec vs Sim", nBinsCent, minCent, maxCent, nBinsCent, minCent, maxCent); + qa.fHistCentralityRecSim->GetXaxis()->SetTitle("Centrality (reconstructed)"); + qa.fHistCentralityRecSim->GetYaxis()->SetTitle("Centrality (simulated)"); + qa.fQualityAssuranceList->Add(qa.fHistCentralityRecSim); + } + } // end of void init(InitContext&) { + + // A) Process only reconstructed data: + void processRec(CollisionRec const& collision, aod::BCs const&, TracksRec const& tracks) + { + // *) steer all analysis steps: + steer(collision, tracks); + } + PROCESS_SWITCH(MultiparticleCorrelationsMei, processRec, "process only reconstructed data", true); // yes, keep always one process switch "true", so that there is default running version + + // ------------------------------------------- + + // B) Process both reconstructed and corresponding MC truth simulated data: + void processRecSim(CollisionRecSim const& collision, aod::BCs const&, TracksRecSim const& tracks, aod::McParticles const&, aod::McCollisions const&) + { + steer(collision, tracks); + } + PROCESS_SWITCH(MultiparticleCorrelationsMei, processRecSim, "process both reconstructed and corresponding MC truth simulated data", false); + + // ------------------------------------------- + + // C) Process only simulated data: + void processSim(CollisionSim const& /*collision*/, aod::BCs const&, TracksSim const& /*tracks*/) + { + // steer(collision, tracks); // TBI 20241105 not ready yet, but I do not really need this one urgently, since RecSim is working, and I need that one for efficiencies... + } + PROCESS_SWITCH(MultiparticleCorrelationsMei, processSim, "process only simulated data", false); + +}; // struct MultiparticleCorrelationsMei { + +// *) The final touch: +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} // WorkflowSpec... diff --git a/PWGCF/MultiparticleCorrelations/Tasks/multiparticleCumulants.cxx b/PWGCF/MultiparticleCorrelations/Tasks/multiparticleCumulants.cxx index eeceadca07e..c880ec3d9a0 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/multiparticleCumulants.cxx +++ b/PWGCF/MultiparticleCorrelations/Tasks/multiparticleCumulants.cxx @@ -126,12 +126,25 @@ enum EnQAHistograms { enum EnCorrHistograms { eCorrCent, eCorrMult, + eCorrNumContribMult, eCorrHistograms_N }; static constexpr std::array CorrHistNames = { "Centrality", - "Multiplicity"}; + "Multiplicity", + "NContributionMultiplicity"}; + +enum EnCorrBound { + eCentABBound, + eCentACBound, + eCentBCBound, + eMultABBound, + eMultACBound, + eMultBCBound, + eNumContribMultBound, + eCorrBound_N +}; enum EnCentEstm { eCentFT0C, @@ -181,7 +194,12 @@ static constexpr std::array BeforeAfterNames = "Before", "After"}; -static constexpr int NumHarmonics = 3; +static constexpr int NumHarmonics = 3; // n = 2, 3, 4 +static constexpr int NumTwoPCorrBins = NumHarmonics; // , , , in this case 3 +static constexpr int NumFourPCorrBins = (NumHarmonics * (NumHarmonics + 1)) / 2; // , , , , , , with , in this case 6 +static constexpr int NumSixPCorrBins = (NumHarmonics * (NumHarmonics - 1) * (NumHarmonics - 2)) / 6; // , without , in this case 1 +static constexpr std::array, NumFourPCorrBins> FourPHarmonicIndex{{{2, 2}, {2, 3}, {2, 4}, {3, 3}, {3, 4}, {4, 4}}}; +static constexpr int NumEtaGap = 3; // *) Main task: struct MultiparticleCumulants { // this name is used in lower-case format to name the TDirectoryFile in AnalysisResults.root @@ -209,8 +227,9 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam Configurable cfSel8CutSwitch{"cfSel8CutSwitch", true, "Sel8 cut switch"}; Configurable cfCentCutSwitch{"cfCentCutSwitch", true, "centrality cut switch"}; Configurable cfNumContribCutSwitch{"cfNumContribCutSwitch", true, "NContribution cut switch"}; - Configurable cfCentCorrCutSwitch{"cfCentCorrCutSwitch", true, "centrality correlation cut switch"}; - Configurable cfMultCorrCutSwitch{"cfMultCorrCutSwitch", true, "multiplicity correlation cut switch"}; + Configurable cfCentCorrCutSwitch{"cfCentCorrCutSwitch", true, "centrality correlation outlier cut switch"}; + Configurable cfMultCorrCutSwitch{"cfMultCorrCutSwitch", true, "multiplicity correlation outlier cut switch"}; + Configurable cfNumContribMultCorrCutSwitch{"cfNumContribMultCorrCutSwitch", true, "NContribution vs. multiplicity correlation outlier cut switch"}; // *) Particle cut switches Configurable cfPtCutSwitch{"cfPtCutSwitch", true, "Pt cut switch"}; @@ -219,25 +238,30 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam Configurable cfTpcNClsFoundCutSwitch{"cfTpcNClsFoundCutSwitch", true, ""}; Configurable cfDCAXYCutSwitch{"cfDCAXYCutSwitch", true, ""}; Configurable cfDCAZCutSwitch{"cfDCAZCutSwitch", true, ""}; - Configurable cfEtaGapSwitch{"cfEtaGapSwitch", true, "Eta gap switch"}; + Configurable cfHasTpcItsCutSwitch{"cfHasTpcItsCutSwitch", false, ""}; // *) Event cut Configurable> cfVertexZCut{"cfVertexZCut", {-10., 10.}, "vertex z position range: {min, max}[cm]"}; Configurable> cfCentCut{"cfCentCut", {10., 20.}, "centrality range: {min, max}[%]"}; Configurable> cfNumContribCut{"cfNumContribCut", {0, 3000.}, "NContribution range: {min, max}"}; - Configurable> cfCentCorrCut{"cfCentCorrCut", {1., 10.}, "parameters of limits in centralities 2D histograms, (x-t)/m < y < mx+t: {m, t}"}; - Configurable> cfMultABCorrCut{"cfMultABCorrCut", {1.4, 300., 1.4, 300.}, "parameters of limits in FT0C vs. FT0M multiplicities 2D histograms, ax+b < y < cx+d: {a,b,c,d}"}; - Configurable> cfMultACCorrCut{"cfMultACCorrCut", {1.4, 300., 1.4, 300.}, "parameters of limits in FT0C vs. FV0A multiplicities 2D histograms, ax+b < y < cx+d: {a,b,c,d}"}; - Configurable> cfMultBCCorrCut{"cfMultBCCorrCut", {1.4, 300., 1.4, 300.}, "parameters of limits in FT0M vs. FV0A multiplicities 2D histograms, ax+b < y < cx+d: {a,b,c,d}"}; + // Configurable> cfCentCorrCut{"cfCentCorrCut", {1., 10.}, "parameters of limits in centralities 2D histograms, (x-t)/m < y < mx+t: {m, t}"}; + Configurable> cfCentABCorrCut{"cfCentABCorrCut", {1.4, 300., 1.4, 300.}, "parameters of limits in FT0C vs. FT0M centrality 2D histograms, cx+d < y < ax+b: {a,b,c,d}"}; + Configurable> cfCentACCorrCut{"cfCentACCorrCut", {1.4, 300., 1.4, 300.}, "parameters of limits in FT0C vs. FT0M centrality 2D histograms, cx+d < y < ax+b: {a,b,c,d}"}; + Configurable> cfCentBCCorrCut{"cfCentBCCorrCut", {1.4, 300., 1.4, 300.}, "parameters of limits in FT0C vs. FT0M centrality 2D histograms, cx+d < y < ax+b: {a,b,c,d}"}; + Configurable> cfMultABCorrCut{"cfMultABCorrCut", {1.4, 300., 1.4, 300.}, "parameters of limits in FT0C vs. FT0M multiplicities 2D histograms, cx+d < y < ax+b: {a,b,c,d}"}; + Configurable> cfMultACCorrCut{"cfMultACCorrCut", {1.4, 300., 1.4, 300.}, "parameters of limits in FT0C vs. FV0A multiplicities 2D histograms, cx+d < y < ax+b: {a,b,c,d}"}; + Configurable> cfMultBCCorrCut{"cfMultBCCorrCut", {1.4, 300., 1.4, 300.}, "parameters of limits in FT0M vs. FV0A multiplicities 2D histograms, cx+d < y < ax+b: {a,b,c,d}"}; + Configurable> cfNumContribMultCorrCut{"cfNumContribMultCorrCut", {0.035, 100., 0.024, -600.}, "parameters of limits in NContribution vs. multiplicity 2D histograms, cx+d < y < ax+b: {a,b,c,d}"}; // *) Particle cut - Configurable> cfPtCut{"cfPtCut", {0.2, 5.0}, "Pt range: {min, max}[GeV], with convention: min <= Pt < max"}; - Configurable> cfEtaCut{"cfEtaCut", {-0.8, 0.8}, "Eta range: {min, max}, with convention: min <= Eta < max"}; + Configurable> cfPtCut{"cfPtCut", {0.2, 5.0}, "Pt range: {min, max}[GeV], with convention: min < Pt < max"}; + Configurable> cfEtaCut{"cfEtaCut", {-0.8, 0.8}, "Eta range: {min, max}, with convention: min < Eta < max"}; Configurable> cfSignCut{"cfSignCut", {1, 0, 1}, "sign of charge, 1 to keep and 0 to discard, {negative, neutral, positive}"}; Configurable> cfTpcNClsFoundCut{"cfTpcNClsFoundCut", {70., 160.}, "range of found TPC clusters for this track geometry: {min, max}"}; Configurable> cfDCAXYCut{"cfDCAXYCut", {-3.2, 3.2}, "range of distance-of-closest-approach (DCA) of the extrapolated track to the primary position in XY-direction: {min, max}[cm]"}; Configurable> cfDCAZCut{"cfDCAZCut", {-2.4, 2.4}, "range of distance-of-closest-approach (DCA) of the extrapolated track to the primary position in Z-direction: {min, max}[cm]"}; - Configurable cfEtaGap{"cfEtaGap", 1., "|dEta| > gap"}; + Configurable> cfHasTpcItsCut{"cfHasTpcItsCut", {1, 1}, "1 to keep tracks that have {TPC, ITS} information"}; + Configurable> cfEtaGap{"cfEtaGap", {0.4, 0.8, 1.0}, "|dEta| > gap"}; // *) Others Configurable cfFileWithWeights{"cfFileWithWeights", "/scratch3/go52dab/O2tutorial/tutorial3-6/weights.root", "path to external ROOT file which holds all particle weights in O2 format"}; @@ -255,6 +279,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam Configurable> cfNumContribBins{"cfNumContribBins", {100, 0., 5000.}, "nNumContribBins, NumContribMin, NumContribMax"}; Configurable> cfTwoParticleCorrBins{"cfTwoParticleCorrBins", {100, 0., 2e-3}, "nTwoParticleCorrBins, TwoParticleCorrMin, TwoParticleCorrMax"}; Configurable> cfFourParticleCorrBins{"cfFourParticleCorrBins", {100, 0., 1e-7}, "nFourParticleCorrBins, FourParticleCorrMin, FourParticleCorrMax"}; + Configurable> cfSixParticleCorrBins{"cfSixParticleCorrBins", {100, 0., 1e-11}, "nSixParticleCorrBins, SixParticleCorrMin, SixParticleCorrMax"}; // *) Define and initialize all data members to be called in the main process* functions: // **) Task configuration: @@ -274,6 +299,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam bool fNumContribCutSwitch = true; bool fCentCorrCutSwitch = true; bool fMultCorrCutSwitch = true; + bool fNumContribMultCorrCutSwitch = true; bool fPtCutSwitch = true; bool fEtaCutSwitch = true; @@ -281,20 +307,22 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam bool fTpcNClsFoundCutSwitch = true; bool fDCAXYCutSwitch = true; bool fDCAZCutSwitch = true; - bool fEtaGapSwitch = true; + bool fHasTpcItsCutSwitch = true; std::vector fVertexZCut = {-10., 10.}; std::vector fCentCut = {10., 20.}; std::vector fNumContribCut = {0, 3000.}; - std::vector fCentCorrCut = {1., 10.}; + std::vector>> fCentAllCorrCut = {{{0., 0., 0., 0.}, {0., 0., 0., 0.}, {0., 0., 0., 0.}}, {{0., 0., 0., 0.}, {0., 0., 0., 0.}, {0., 0., 0., 0.}}, {{0., 0., 0., 0.}, {0., 0., 0., 0.}, {0., 0., 0., 0.}}}; std::vector>> fMultAllCorrCut = {{{0., 0., 0., 0.}, {0., 0., 0., 0.}, {0., 0., 0., 0.}}, {{0., 0., 0., 0.}, {0., 0., 0., 0.}, {0., 0., 0., 0.}}, {{0., 0., 0., 0.}, {0., 0., 0., 0.}, {0., 0., 0., 0.}}}; + std::vector fNumContribMultCorrCut = {0.024, -600., 0.035, 100.}; std::vector fPtCut = {0.2, 5.0}; std::vector fEtaCut = {-0.8, 0.8}; std::vector fSignCut = {1, 0, 1}; std::vector fTpcNClsFoundCut = {70., 160.}; std::vector fDCAXYCut = {-3.2, 3.2}; std::vector fDCAZCut = {-2.4, 2.4}; - float fEtaGap = 1.; + std::vector fHasTpcItsCut = {1, 1}; + std::vector fEtaGap = {0.4, 0.8, 1.0}; std::vector fPtBins = {1000, 0., 100.}; std::vector fPhiBins = {1000, 0., o2::constants::math::TwoPI}; @@ -311,6 +339,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam std::vector fNumContribBins = {100, 0, 5000}; std::vector fTwoParticleCorrBins = {100, 0, 2e-3}; std::vector fFourParticleCorrBins = {100, 0, 1e-7}; + std::vector fSixParticleCorrBins = {100, 0, 1e-11}; std::string fFileWithWeights = "/scratch3/go52dab/O2tutorial/analysis_code/weights.root"; @@ -334,8 +363,8 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam struct CorrHistograms { TList* fCorrHistogramsList = nullptr; - std::array, eMultEstm_N>, eMultEstm_N>, eCorrHistograms_N> fCorrHistograms{}; // [mult/cent][type][type][before/after cut] - std::array, eCorrHistograms_N + 2> fCorrBounds{}; //[cent/multAB/multAC/multBC][upper/lower] + std::array, eMultEstm_N>, eMultEstm_N>, eCorrHistograms_N - 1> fCorrHistograms{}; // [mult/cent][type][type][before/after cut] + std::array, eCorrBound_N> fCorrBounds{}; // [centAB/centAC/centBC/multAB/multAC/multBC/NumContrib vs. mult][upper/lower] } cr; struct WeightHistograms { @@ -364,13 +393,16 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam int h7 = 0; int h8 = 0; // Book Q-vector components: - static constexpr int MaxCorrelator = 4; // <> - static constexpr int MaxHarmonic = 17; // need 4 + 2 + 2 + 4 + 1 at least for SC(4,2) + static constexpr int MaxCorrelator = 6; // <>, in this case 6 + static constexpr int MaxHarmonic = ((MaxCorrelator * (MaxCorrelator + 1)) / 2 - 1) * 2 + 1; // (2 + 3 + ... + n) * 2 + 1, in this case need (2 + 3 + 4) * 2 + 1 = 19 at least for SC(2,3,4) static constexpr int MaxPower = MaxCorrelator + 1; + std::array, MaxHarmonic> fQvectorBefore; std::array, MaxHarmonic> fQvectorAfter; - std::array, MaxHarmonic> fQvectorAfterA; // Q-vector with eta gap - std::array, MaxHarmonic> fQvectorAfterB; // Q-vector with eta gap + std::array, MaxHarmonic>, NumEtaGap> fQvectorBeforeA; + std::array, MaxHarmonic>, NumEtaGap> fQvectorBeforeB; + std::array, MaxHarmonic>, NumEtaGap> fQvectorAfterA; + std::array, MaxHarmonic>, NumEtaGap> fQvectorAfterB; } mcc; struct MultiparticleCorrelationProfile { @@ -379,9 +411,12 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam std::map fMultiparticleCorrelationByRunMap; std::array fTwoParticleCorrelationProfiles{}; // [cut] std::array fFourParticleCorrelationProfiles{}; - std::array, eBeforeAfter_N>, eBeforeAfter_N> fTwoParticleCorrelationHistograms{}; // [cut][event weight][n] - std::array, eBeforeAfter_N>, eBeforeAfter_N> fFourParticleCorrelationHistograms{}; - std::array fTwoParticleCorrelationGapHistograms{}; + std::array fSixParticleCorrelationProfiles{}; + std::array, NumEtaGap> fTwoParticleCorrelationGapProfiles{}; + std::array, eBeforeAfter_N>, eBeforeAfter_N> fTwoParticleCorrelationHistograms{}; // [cut][event weight][n] + std::array, eBeforeAfter_N>, eBeforeAfter_N> fFourParticleCorrelationHistograms{}; + std::array, eBeforeAfter_N>, eBeforeAfter_N> fSixParticleCorrelationHistograms{}; + std::array, NumEtaGap> fTwoParticleCorrelationGapHistograms{}; } mc; struct EventByEventQuantities { @@ -392,16 +427,19 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam float fCentralitySim = 0.; float fImpactParameter = 0.; float fNumContrib = 0.; - std::array, eBeforeAfter_N> fTwoParticleCorrelationEbye{}; //<2> [before, after][v2^2, v3^2, v4^2] - std::array, eBeforeAfter_N> fTwoParticleCorrelationMinEbye{}; - std::array, eBeforeAfter_N> fTwoParticleCorrelationMaxEbye{}; - std::array, eBeforeAfter_N> fFourParticleCorrelationEbye{}; //<4> [before, after][v2^4, v3^2 v2^2, v4^2 v2^2] - std::array, eBeforeAfter_N> fFourParticleCorrelationMinEbye{}; - std::array, eBeforeAfter_N> fFourParticleCorrelationMaxEbye{}; + std::array, eBeforeAfter_N> fTwoParticleCorrelationEbye{}; // <<2>> [before, after][, , ] + std::array, eBeforeAfter_N> fTwoParticleCorrelationMinEbye{}; + std::array, eBeforeAfter_N> fTwoParticleCorrelationMaxEbye{}; + std::array, eBeforeAfter_N> fFourParticleCorrelationEbye{}; // <<4>> [before, after][, , , , , ] + std::array, eBeforeAfter_N> fFourParticleCorrelationMinEbye{}; + std::array, eBeforeAfter_N> fFourParticleCorrelationMaxEbye{}; + std::array, eBeforeAfter_N> fSixParticleCorrelationEbye{}; // <<6>> [before, after][] + std::array, eBeforeAfter_N> fSixParticleCorrelationMinEbye{}; + std::array, eBeforeAfter_N> fSixParticleCorrelationMaxEbye{}; } ebye; - template // rm should be rec and sim - bool ctEventCuts(T1 const& collision, T2 const& rlCollisionCentAll, T3 const& rlCollisionMultAll) + template + bool ctEventCuts(T1 const& collision, T2 const& rlCollisionCentAll, T3 const& rlCollisionMultAll, T4 const& rlCollisionNumContrib) { bool pass = true; @@ -412,6 +450,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam bool bNumContribCut = true; bool bCentCorrCut = true; bool bMultCorrCut = true; + bool bNumContribMultCorrCut = true; // *) For rec event and sim event bVertexZCut = collision.posZ() < tc.fVertexZCut[1] && @@ -438,29 +477,35 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam // *) CentCorrCut float iCent = 0.; float jCent = 0.; + int nCentComb = 0; for (int i = 0; i < eCentEstm_N; i++) { iCent = rlCollisionCentAll[i]; for (int j = i + 1; j < eCentEstm_N; j++) { jCent = rlCollisionCentAll[j]; - float upper = cr.fCorrBounds[eCorrCent][0]->Eval(iCent); - float lower = cr.fCorrBounds[eCorrCent][1]->Eval(iCent); + float upper = cr.fCorrBounds[eCentABBound + nCentComb][0]->Eval(iCent); + float lower = cr.fCorrBounds[eCentABBound + nCentComb][1]->Eval(iCent); bCentCorrCut &= jCent >= lower && jCent <= upper; + nCentComb += 1; } } // *) MultCorrCut float iMult = 0.; float jMult = 0.; - int nComb = 0; + int nMultComb = 0; for (int i = 0; i < eMultEstm_N; i++) { iMult = rlCollisionMultAll[i]; for (int j = i + 1; j < eMultEstm_N; j++) { jMult = rlCollisionMultAll[j]; - float upper = cr.fCorrBounds[eCorrMult + nComb][0]->Eval(iMult); - float lower = cr.fCorrBounds[eCorrMult + nComb][1]->Eval(iMult); + float upper = cr.fCorrBounds[eMultABBound + nMultComb][0]->Eval(iMult); + float lower = cr.fCorrBounds[eMultABBound + nMultComb][1]->Eval(iMult); bMultCorrCut &= jMult >= lower && jMult <= upper; - nComb += 1; + nMultComb += 1; } } + // *) NumContribMultCorrCut + float upper = cr.fCorrBounds[eNumContribMultBound][0]->Eval(ebye.fReferenceMultiplicity); + float lower = cr.fCorrBounds[eNumContribMultBound][1]->Eval(ebye.fReferenceMultiplicity); + bNumContribMultCorrCut = rlCollisionNumContrib >= lower && rlCollisionNumContrib <= upper; } // *) For sim event only @@ -492,6 +537,9 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam if (tc.fMultCorrCutSwitch) { pass &= bMultCorrCut; } + if (tc.fNumContribMultCorrCutSwitch) { + pass &= bNumContribMultCorrCut; + } return pass; } @@ -507,6 +555,8 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam bool bTpcNClsFoundCut = true; bool bDCAXYCut = true; bool bDCAZCut = true; + bool bHasTpcCut = true; + bool bHasItsCut = true; // *) For rec event and sim event bPtCut = track.pt() < tc.fPtCut[1] && track.pt() > tc.fPtCut[0]; @@ -523,6 +573,8 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam track.dcaXY() > tc.fDCAXYCut[0]; bDCAZCut = track.dcaZ() < tc.fDCAZCut[1] && track.dcaZ() > tc.fDCAZCut[0]; + bHasTpcCut = track.hasTPC() && tc.fHasTpcItsCut[0]; + bHasItsCut = track.hasITS() && tc.fHasTpcItsCut[1]; } // *) For sim event only @@ -558,11 +610,15 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam if (tc.fDCAZCutSwitch) { pass &= bDCAZCut; } + if (tc.fHasTpcItsCutSwitch) { + pass &= bHasTpcCut; + pass &= bHasItsCut; + } return pass; } - TComplex mccQ(int n, int p, EnBeforeAfter eba, int egap) + TComplex mccQ(int n, int p, EnBeforeAfter eba) { // Using the fact that Q{-n,p} = Q{n,p}^*. if (eba == eBefore) { @@ -572,43 +628,28 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam } return TComplex::Conjugate(mcc.fQvectorBefore[-n][p]); } - if (egap == 0) { - // Q-vector after cut: - if (n >= 0) { - return mcc.fQvectorAfter[n][p]; - } - return TComplex::Conjugate(mcc.fQvectorAfter[-n][p]); - } - if (egap == 1) { - // Q-vector after cut, eta < gap: - if (n >= 0) { - return mcc.fQvectorAfterA[n][p]; - } - return TComplex::Conjugate(mcc.fQvectorAfterA[-n][p]); - } - // Q-vector after cut, eta > gap: if (n >= 0) { - return mcc.fQvectorAfterB[n][p]; + return mcc.fQvectorAfter[n][p]; } - return TComplex::Conjugate(mcc.fQvectorAfterB[-n][p]); + return TComplex::Conjugate(mcc.fQvectorAfter[-n][p]); } - TComplex mccTwo(int n1, int n2, EnBeforeAfter eba, int egap) - { - return mccQ(n1, 1, eba, egap) * mccQ(n2, 1, eba, egap) - mccQ(n1 + n2, 2, eba, egap); - } + // TComplex mccTwo(int n1, int n2, EnBeforeAfter eba) + // { + // return mccQ(n1, 1, eba) * mccQ(n2, 1, eba) - mccQ(n1 + n2, 2, eba); + // } template - TComplex mccRecursion(int n, std::array harmonic, EnBeforeAfter eba, int egap, int mult = 1, int skip = 0) + TComplex mccRecursion(int n, std::array harmonic, EnBeforeAfter eba, int mult = 1, int skip = 0) { // Calculate multi-particle correlators by using recursion (an improved faster version) originally developed by Kristjan Gulbrandsen (gulbrand@nbi.dk). int nm1 = n - 1; - TComplex c(mccQ(harmonic[nm1], mult, eba, egap)); + TComplex c(mccQ(harmonic[nm1], mult, eba)); if (nm1 == 0) { return c; } - c *= mccRecursion(nm1, harmonic, eba, egap); + c *= mccRecursion(nm1, harmonic, eba); if (nm1 == skip) { return c; } @@ -619,7 +660,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam int hhold = harmonic[counter1]; harmonic[counter1] = harmonic[nm2]; harmonic[nm2] = hhold + harmonic[nm1]; - TComplex c2(mccRecursion(nm1, harmonic, eba, egap, multp1, nm2)); + TComplex c2(mccRecursion(nm1, harmonic, eba, multp1, nm2)); int counter2 = n - 3; while (counter2 >= skip) { harmonic[nm2] = harmonic[counter1]; @@ -628,7 +669,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam hhold = harmonic[counter1]; harmonic[counter1] = harmonic[nm2]; harmonic[nm2] = hhold + harmonic[nm1]; - c2 += mccRecursion(nm1, harmonic, eba, egap, multp1, counter2); + c2 += mccRecursion(nm1, harmonic, eba, multp1, counter2); --counter2; } harmonic[nm2] = harmonic[counter1]; @@ -835,8 +876,13 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam for (int p = 0; p < mcc.MaxPower; p++) { mcc.fQvectorBefore[h][p] = TComplex(0., 0.); mcc.fQvectorAfter[h][p] = TComplex(0., 0.); - mcc.fQvectorAfterA[h][p] = TComplex(0., 0.); - mcc.fQvectorAfterB[h][p] = TComplex(0., 0.); + + for (int n = 0; n < NumEtaGap; n++) { + mcc.fQvectorBeforeA[n][h][p] = TComplex(0., 0.); + mcc.fQvectorBeforeB[n][h][p] = TComplex(0., 0.); + mcc.fQvectorAfterA[n][h][p] = TComplex(0., 0.); + mcc.fQvectorAfterB[n][h][p] = TComplex(0., 0.); + } } } @@ -926,24 +972,36 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam for (int i = 0; i < eBeforeAfter_N; i++) { // before/after cut mc.fTwoParticleCorrelationProfiles[i] = nullptr; mc.fFourParticleCorrelationProfiles[i] = nullptr; + mc.fSixParticleCorrelationProfiles[i] = nullptr; + mc.fTwoParticleCorrelationGapProfiles[i].fill(nullptr); for (int j = 0; j < eBeforeAfter_N; j++) { // before/after weight mc.fTwoParticleCorrelationHistograms[i][j].fill(nullptr); mc.fFourParticleCorrelationHistograms[i][j].fill(nullptr); + mc.fSixParticleCorrelationHistograms[i][j].fill(nullptr); } } + // Define 2p profiles and histograms: for (int i = 0; i < eBeforeAfter_N; i++) { // before/after cut - mc.fTwoParticleCorrelationProfiles[i] = new TProfile(Form("prof2%sCut", BeforeAfterNames[i + 2]), Form("2-p correlation %s cut", BeforeAfterNames[i]), 3, 2., 5.); + mc.fTwoParticleCorrelationProfiles[i] = new TProfile(Form("prof2%sCut", BeforeAfterNames[i + 2]), Form("2-p correlation %s cut", BeforeAfterNames[i]), NumTwoPCorrBins, 0., 1.); mc.fTwoParticleCorrelationProfiles[i]->Sumw2(); + for (int n = 0; n < NumEtaGap; n++) { + mc.fTwoParticleCorrelationGapProfiles[n][i] = new TProfile(Form("prof2%sCutGapped%.1f", BeforeAfterNames[i + 2], tc.fEtaGap[n]), Form("2-p correlation %s cut, %.1f gapped", BeforeAfterNames[i], tc.fEtaGap[n]), NumTwoPCorrBins, 0., 1.); + mc.fTwoParticleCorrelationGapProfiles[n][i]->Sumw2(); + } - for (int k = 0; k < NumHarmonics; k++) { // v2, v3, v4 - mc.fTwoParticleCorrelationProfiles[i]->GetXaxis()->SetBinLabel(k + 1, Form("v%d^2", k + 2)); - if (static_cast(i)) { - mc.fTwoParticleCorrelationGapHistograms[k] = new TH1D(Form("hist2v%dAfterCutWithGap", k + 2), Form("2-p correlation v%d^2 after cut with gap", k + 2), static_cast(tc.fTwoParticleCorrBins[0]), tc.fTwoParticleCorrBins[1], tc.fTwoParticleCorrBins[2]); - mc.fTwoParticleCorrelationGapHistograms[k]->Sumw2(); - mc.fTwoParticleCorrelationGapHistograms[k]->SetOption("HIST"); + for (int k = 0; k < NumTwoPCorrBins; k++) { // v2, v3, v4 + mc.fTwoParticleCorrelationProfiles[i]->GetXaxis()->SetBinLabel(k + 1, Form("", k + 2)); + for (int n = 0; n < NumEtaGap; n++) { + mc.fTwoParticleCorrelationGapProfiles[n][i]->GetXaxis()->SetBinLabel(k + 1, Form("", k + 2)); + if (static_cast(i)) { + mc.fTwoParticleCorrelationGapHistograms[n][k] = new TH1D(Form("hist2v%dAfterCutWithGap%.1f", k + 2, tc.fEtaGap[n]), Form("2-p correlation v%d^2 after cut with gap %.1f", k + 2, tc.fEtaGap[n]), static_cast(tc.fTwoParticleCorrBins[0]), tc.fTwoParticleCorrBins[1], tc.fTwoParticleCorrBins[2]); + mc.fTwoParticleCorrelationGapHistograms[n][k]->Sumw2(); + mc.fTwoParticleCorrelationGapHistograms[n][k]->SetOption("HIST"); + } } + for (int j = 0; j < eBeforeAfter_N; j++) { // before/after weight mc.fTwoParticleCorrelationHistograms[i][j][k] = new TH1D(Form("hist2v%d%sCut%sWeight", k + 2, BeforeAfterNames[i + 2], BeforeAfterNames[j + 2]), Form("2-p correlation v%d^2 %s cut %s weight", k + 2, BeforeAfterNames[i], BeforeAfterNames[j]), static_cast(tc.fTwoParticleCorrBins[0]), tc.fTwoParticleCorrBins[1], tc.fTwoParticleCorrBins[2]); if (static_cast(j)) { @@ -953,21 +1011,27 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam mc.fMultiparticleCorrelationBackupList->Add(mc.fTwoParticleCorrelationHistograms[i][j][k]); } if (static_cast(i)) { - mc.fMultiparticleCorrelationBackupList->Add(mc.fTwoParticleCorrelationGapHistograms[k]); + for (int n = 0; n < NumEtaGap; n++) { + mc.fMultiparticleCorrelationBackupList->Add(mc.fTwoParticleCorrelationGapHistograms[n][k]); + } } } mc.fMultiparticleCorrelationByRunMap[ebye.fRunNumber]->Add(mc.fTwoParticleCorrelationProfiles[i]); + for (int n = 0; n < NumEtaGap; n++) { + mc.fMultiparticleCorrelationByRunMap[ebye.fRunNumber]->Add(mc.fTwoParticleCorrelationGapProfiles[n][i]); + } } + // Define 4p profiles and histograms: for (int i = 0; i < eBeforeAfter_N; i++) { // before/after cut - mc.fFourParticleCorrelationProfiles[i] = new TProfile(Form("prof4%sCut", BeforeAfterNames[i + 2]), Form("4-p correlation %s cut", BeforeAfterNames[i]), NumHarmonics, 2., 5.); + mc.fFourParticleCorrelationProfiles[i] = new TProfile(Form("prof4%sCut", BeforeAfterNames[i + 2]), Form("4-p correlation %s cut", BeforeAfterNames[i]), NumFourPCorrBins, 0., 1.); mc.fFourParticleCorrelationProfiles[i]->Sumw2(); - for (int k = 0; k < NumHarmonics; k++) { // v2v2, v2v3, v2v4 - mc.fFourParticleCorrelationProfiles[i]->GetXaxis()->SetBinLabel(k + 1, Form("v2^2v%d^2", k + 2)); + for (int k = 0; k < NumFourPCorrBins; k++) { // v2v2, v2v3, v2v4, v3v3, v3v4, v4v4 + mc.fFourParticleCorrelationProfiles[i]->GetXaxis()->SetBinLabel(k + 1, Form("", FourPHarmonicIndex[k][0], FourPHarmonicIndex[k][1])); for (int j = 0; j < eBeforeAfter_N; j++) { // before/after weight - mc.fFourParticleCorrelationHistograms[i][j][k] = new TH1D(Form("hist4v2v%d%sCut%sWeight", k + 2, BeforeAfterNames[i + 2], BeforeAfterNames[j + 2]), Form("4-p correlation v2^2v%d^2 %s cut %s weight", k + 2, BeforeAfterNames[i], BeforeAfterNames[j]), static_cast(tc.fFourParticleCorrBins[0]), tc.fFourParticleCorrBins[1], tc.fFourParticleCorrBins[2]); + mc.fFourParticleCorrelationHistograms[i][j][k] = new TH1D(Form("hist4v%dv%d%sCut%sWeight", FourPHarmonicIndex[k][0], FourPHarmonicIndex[k][1], BeforeAfterNames[i + 2], BeforeAfterNames[j + 2]), Form("4-p correlation v%d^2v%d^2 %s cut %s weight", FourPHarmonicIndex[k][0], FourPHarmonicIndex[k][1], BeforeAfterNames[i], BeforeAfterNames[j]), static_cast(tc.fFourParticleCorrBins[0]), tc.fFourParticleCorrBins[1], tc.fFourParticleCorrBins[2]); if (static_cast(j)) { mc.fFourParticleCorrelationHistograms[i][j][k]->Sumw2(); mc.fFourParticleCorrelationHistograms[i][j][k]->SetOption("HIST"); @@ -977,6 +1041,26 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam } mc.fMultiparticleCorrelationByRunMap[ebye.fRunNumber]->Add(mc.fFourParticleCorrelationProfiles[i]); } + + // Define 6p profiles and histograms: + for (int i = 0; i < eBeforeAfter_N; i++) { // before/after cut + mc.fSixParticleCorrelationProfiles[i] = new TProfile(Form("prof6%sCut", BeforeAfterNames[i + 2]), Form("6-p correlation %s cut", BeforeAfterNames[i]), NumSixPCorrBins, 0., 1.); + mc.fSixParticleCorrelationProfiles[i]->Sumw2(); + + for (int k = 0; k < NumSixPCorrBins; k++) { // v2v3v4 + mc.fSixParticleCorrelationProfiles[i]->GetXaxis()->SetBinLabel(k + 1, ""); + + for (int j = 0; j < eBeforeAfter_N; j++) { // before/after weight + mc.fSixParticleCorrelationHistograms[i][j][k] = new TH1D(Form("hist6v2v3v4%sCut%sWeight", BeforeAfterNames[i + 2], BeforeAfterNames[j + 2]), Form("6-p correlation v2^2v3^2v4^2 %s cut %s weight", BeforeAfterNames[i], BeforeAfterNames[j]), static_cast(tc.fSixParticleCorrBins[0]), tc.fSixParticleCorrBins[1], tc.fSixParticleCorrBins[2]); + if (static_cast(j)) { + mc.fSixParticleCorrelationHistograms[i][j][k]->Sumw2(); + mc.fSixParticleCorrelationHistograms[i][j][k]->SetOption("HIST"); + } + mc.fMultiparticleCorrelationBackupList->Add(mc.fSixParticleCorrelationHistograms[i][j][k]); + } + } + mc.fMultiparticleCorrelationByRunMap[ebye.fRunNumber]->Add(mc.fSixParticleCorrelationProfiles[i]); + } } // Real data centrality: @@ -1055,31 +1139,27 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam ev.fEventHistograms[eNumContrib][eRec][eBefore]->Fill(rlCollisionNumContrib); // Fill centrality correlation histograms before cut: - if (tc.fCentCorrCutSwitch) { - for (int i = 0; i < eCentEstm_N; i++) { - for (int j = i + 1; j < eCentEstm_N; j++) { - auto* h = cr.fCorrHistograms[eCorrCent][i][j][eBefore]; - if (!h) { - LOGF(fatal, "Missing histogram cr.fCorrHistograms[eCorrCent][%d][%d][eBefore]", i, j); - } - if (rlCollisionCentAll[i] >= 0. && rlCollisionCentAll[j] >= 0.) { - h->Fill(rlCollisionCentAll[i], rlCollisionCentAll[j]); - } + for (int i = 0; i < eCentEstm_N; i++) { + for (int j = i + 1; j < eCentEstm_N; j++) { + auto* h = cr.fCorrHistograms[eCorrCent][i][j][eBefore]; + if (!h) { + LOGF(fatal, "Missing histogram cr.fCorrHistograms[eCorrCent][%d][%d][eBefore]", i, j); + } + if (rlCollisionCentAll[i] >= 0. && rlCollisionCentAll[j] >= 0.) { + h->Fill(rlCollisionCentAll[i], rlCollisionCentAll[j]); } } } // Fill multiplicity correlation histograms before cut: - if (tc.fMultCorrCutSwitch) { - for (int i = 0; i < eMultEstm_N; i++) { - for (int j = i + 1; j < eMultEstm_N; j++) { - auto* h = cr.fCorrHistograms[eCorrMult][i][j][eBefore]; - if (!h) { - LOGF(fatal, "Missing histogram cr.fCorrHistograms[eCorrMult][%d][%d][eBefore]", i, j); - } - if (rlCollisionMultAll[i] >= 0. && rlCollisionMultAll[j] >= 0.) { - h->Fill(rlCollisionMultAll[i], rlCollisionMultAll[j]); - } + for (int i = 0; i < eMultEstm_N; i++) { + for (int j = i + 1; j < eMultEstm_N; j++) { + auto* h = cr.fCorrHistograms[eCorrMult][i][j][eBefore]; + if (!h) { + LOGF(fatal, "Missing histogram cr.fCorrHistograms[eCorrMult][%d][%d][eBefore]", i, j); + } + if (rlCollisionMultAll[i] >= 0. && rlCollisionMultAll[j] >= 0.) { + h->Fill(rlCollisionMultAll[i], rlCollisionMultAll[j]); } } } @@ -1124,7 +1204,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam ev.fEventHistograms[eVertexZ][eSim][eBefore]->Fill(mccollision.posZ()); // Fill MC event histograms after cut: - if (ctEventCuts(mccollision, rlCollisionCentAll, rlCollisionMultAll)) { + if (ctEventCuts(mccollision, rlCollisionCentAll, rlCollisionMultAll, rlCollisionNumContrib)) { ev.fEventHistograms[eCent][eSim][eAfter]->Fill(mcCollisionCent); ev.fEventHistograms[eVertexX][eSim][eAfter]->Fill(mccollision.posX()); ev.fEventHistograms[eVertexY][eSim][eAfter]->Fill(mccollision.posY()); @@ -1134,8 +1214,8 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam // Fill centrality QA histogram before/after cut: if (qa.fQASwitch) { qa.fQAHistograms[eQACent][eBefore]->Fill(rlCollisionCent, mcCollisionCent); - if (ctEventCuts(collision, rlCollisionCentAll, rlCollisionMultAll) && - ctEventCuts(mccollision, rlCollisionCentAll, rlCollisionMultAll)) { + if (ctEventCuts(collision, rlCollisionCentAll, rlCollisionMultAll, rlCollisionNumContrib) && + ctEventCuts(mccollision, rlCollisionCentAll, rlCollisionMultAll, rlCollisionNumContrib)) { qa.fQAHistograms[eQACent][eAfter]->Fill(rlCollisionCent, mcCollisionCent); } } @@ -1143,7 +1223,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam } // Fill real event histograms after cut - if (ctEventCuts(collision, rlCollisionCentAll, rlCollisionMultAll)) { + if (ctEventCuts(collision, rlCollisionCentAll, rlCollisionMultAll, rlCollisionNumContrib)) { ev.fEventHistograms[eCent][eRec][eAfter]->Fill(rlCollisionCent); ev.fEventHistograms[eMult][eRec][eAfter]->Fill(rlCollisionMult); ev.fEventHistograms[eVertexX][eRec][eAfter]->Fill(collision.posX()); @@ -1152,28 +1232,24 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam ev.fEventHistograms[eNumContrib][eRec][eAfter]->Fill(rlCollisionNumContrib); // Fill centrality correlation histograms after cut: - if (tc.fCentCorrCutSwitch) { - for (int i = 0; i < eCentEstm_N; i++) { - for (int j = i + 1; j < eCentEstm_N; j++) { - auto* h = cr.fCorrHistograms[eCorrCent][i][j][eAfter]; - if (!h) { - LOGF(fatal, "Missing histogram cr.fCorrHistograms[eCorrCent][%d][%d][eAfter]", i, j); - } - h->Fill(rlCollisionCentAll[i], rlCollisionCentAll[j]); + for (int i = 0; i < eCentEstm_N; i++) { + for (int j = i + 1; j < eCentEstm_N; j++) { + auto* h = cr.fCorrHistograms[eCorrCent][i][j][eAfter]; + if (!h) { + LOGF(fatal, "Missing histogram cr.fCorrHistograms[eCorrCent][%d][%d][eAfter]", i, j); } + h->Fill(rlCollisionCentAll[i], rlCollisionCentAll[j]); } } // Fill multiplicity correlation histograms after cut: - if (tc.fMultCorrCutSwitch) { - for (int i = 0; i < eMultEstm_N; i++) { - for (int j = i + 1; j < eMultEstm_N; j++) { - auto* h = cr.fCorrHistograms[eCorrMult][i][j][eAfter]; - if (!h) { - LOGF(fatal, "Missing histogram cr.fCorrHistograms[eCorrMult][%d][%d][eAfter]", i, j); - } - h->Fill(rlCollisionMultAll[i], rlCollisionMultAll[j]); + for (int i = 0; i < eMultEstm_N; i++) { + for (int j = i + 1; j < eMultEstm_N; j++) { + auto* h = cr.fCorrHistograms[eCorrMult][i][j][eAfter]; + if (!h) { + LOGF(fatal, "Missing histogram cr.fCorrHistograms[eCorrMult][%d][%d][eAfter]", i, j); } + h->Fill(rlCollisionMultAll[i], rlCollisionMultAll[j]); } } @@ -1190,8 +1266,10 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam int nTracksBefore = tracks.size(); int nTracksAfter = 0; - int nTracksAfterA = 0; - int nTracksAfterB = 0; + std::vector nTracksBeforeA = {0, 0, 0}; + std::vector nTracksBeforeB = {0, 0, 0}; + std::vector nTracksAfterA = {0, 0, 0}; + std::vector nTracksAfterB = {0, 0, 0}; // Calculate Q-vectors for available angles and weights: double dEta = 0.; @@ -1208,10 +1286,6 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam if constexpr (rs == eRec || rs == eRecAndSim) { - // Fill phi/pt real histogram with this run number: - wt.fPhiByRunMap.at(ebye.fRunNumber)->Fill(track.phi()); - wt.fPtRealByRunMap.at(ebye.fRunNumber)->Fill(track.pt()); - // Fill track histograms before cut: pc.fParticleHistograms[ePt][eRec][eBefore]->Fill(track.pt()); pc.fParticleHistograms[ePhi][eRec][eBefore]->Fill(track.phi()); @@ -1242,11 +1316,30 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam wPhiToPowerP = std::pow(wPhi, p); } mcc.fQvectorBefore[h][p] += TComplex(wPhiToPowerP * std::cos(h * dPhi), wPhiToPowerP * std::sin(h * dPhi)); + for (int n = 0; n < NumEtaGap; n++) { + if (dEta < -tc.fEtaGap[n] / 2.) { + mcc.fQvectorBeforeA[n][h][p] += TComplex(wPhiToPowerP * std::cos(h * dPhi), wPhiToPowerP * std::sin(h * dPhi)); + } else if (dEta > tc.fEtaGap[n] / 2.) { + mcc.fQvectorBeforeB[n][h][p] += TComplex(wPhiToPowerP * std::cos(h * dPhi), wPhiToPowerP * std::sin(h * dPhi)); + } + } + } + } + + for (int n = 0; n < NumEtaGap; n++) { + if (dEta < -tc.fEtaGap[n] / 2.) { + nTracksBeforeA[n] += 1; + } else if (dEta > tc.fEtaGap[n] / 2.) { + nTracksBeforeB[n] += 1; } } if (ctParticleCuts(track)) { + // Fill phi/pt real histogram with this run number: + wt.fPhiByRunMap.at(ebye.fRunNumber)->Fill(track.phi()); + wt.fPtRealByRunMap.at(ebye.fRunNumber)->Fill(track.pt()); + // Fill particle histograms after cut: pc.fParticleHistograms[ePt][eRec][eAfter]->Fill(track.pt()); pc.fParticleHistograms[ePhi][eRec][eAfter]->Fill(track.phi()); @@ -1258,21 +1351,25 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam wPhiToPowerP = std::pow(wPhi, p); } mcc.fQvectorAfter[h][p] += TComplex(wPhiToPowerP * std::cos(h * dPhi), wPhiToPowerP * std::sin(h * dPhi)); - if (tc.fEtaGapSwitch) { - if (dEta < -tc.fEtaGap / 2.) { - mcc.fQvectorAfterA[h][p] += TComplex(wPhiToPowerP * std::cos(h * dPhi), wPhiToPowerP * std::sin(h * dPhi)); - } else if (dEta > tc.fEtaGap / 2.) { - mcc.fQvectorAfterB[h][p] += TComplex(wPhiToPowerP * std::cos(h * dPhi), wPhiToPowerP * std::sin(h * dPhi)); + + for (int n = 0; n < NumEtaGap; n++) { + if (dEta < -tc.fEtaGap[n] / 2.) { + mcc.fQvectorAfterA[n][h][p] += TComplex(wPhiToPowerP * std::cos(h * dPhi), wPhiToPowerP * std::sin(h * dPhi)); + } else if (dEta > tc.fEtaGap[n] / 2.) { + mcc.fQvectorAfterB[n][h][p] += TComplex(wPhiToPowerP * std::cos(h * dPhi), wPhiToPowerP * std::sin(h * dPhi)); } } } } nTracksAfter += 1; - if (dEta < -tc.fEtaGap / 2) { - nTracksAfterA += 1; - } else if (dEta > tc.fEtaGap / 2) { - nTracksAfterB += 1; + + for (int n = 0; n < NumEtaGap; n++) { + if (dEta < -tc.fEtaGap[n] / 2.) { + nTracksAfterA[n] += 1; + } else if (dEta > tc.fEtaGap[n] / 2.) { + nTracksAfterB[n] += 1; + } } } // ... @@ -1291,14 +1388,19 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam // Corresponding MC truth simulated particle auto mcparticle = track.mcParticle(); - // Fill pt MC sim histogram with this run number: - wt.fPtMCByRunMap.at(ebye.fRunNumber)->Fill(mcparticle.pt()); - // Fill MC particle histograms before cut: pc.fParticleHistograms[ePt][eSim][eBefore]->Fill(mcparticle.pt()); pc.fParticleHistograms[ePhi][eSim][eBefore]->Fill(mcparticle.phi()); if (ctParticleCuts(mcparticle)) { + // Fill pt MC sim histogram with this run number: + double diffPt = std::abs(track.pt() - mcparticle.pt()); + double diffPtMax = (tc.fPtBins[2] - tc.fPtBins[1]) / tc.fPtBins[0]; + if (diffPt < diffPtMax) { + wt.fPtMCByRunMap.at(ebye.fRunNumber)->Fill(mcparticle.pt()); + } else { + LOGF(info, "|RecPt - SimPt| = %e > %e", diffPt, diffPtMax); + } // Fill MC particle histograms after cut: pc.fParticleHistograms[ePt][eSim][eAfter]->Fill(mcparticle.pt()); pc.fParticleHistograms[ePhi][eSim][eAfter]->Fill(mcparticle.phi()); @@ -1308,21 +1410,22 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam } // if constexpr (rs == eRec || rs == eRecAndSim) { } // end of for (int64_t i = 0; i < tracks.size(); i++) { - for (int i = 0; i < NumHarmonics; i++) { - // 2-p correlations: + // 2-p correlations: + for (int i = 0; i < NumTwoPCorrBins; i++) { + int k = 2; mcc.h1 = -(i + 2); mcc.h2 = i + 2; std::array harmonicsTwoNum = {mcc.h1, mcc.h2}; std::array harmonicsTwoDen = {0, 0}; // Before cut: - TComplex twoRecursionBefore = mccRecursion(2, harmonicsTwoNum, eBefore, 0) / mccRecursion(2, harmonicsTwoDen, eBefore, 0).Re(); - double wTwoRecursionBefore = mccRecursion(2, harmonicsTwoDen, eBefore, 0).Re(); + TComplex twoRecursionBefore = mccRecursion(2, harmonicsTwoNum, eBefore) / mccRecursion(2, harmonicsTwoDen, eBefore).Re(); + double wTwoRecursionBefore = mccRecursion(2, harmonicsTwoDen, eBefore).Re(); ebye.fTwoParticleCorrelationEbye[eBefore][i] = twoRecursionBefore.Re(); - if (nTracksBefore > 1 && wTwoRecursionBefore > 0.) { + if (nTracksBefore > k - 1 && wTwoRecursionBefore > 0.) { // Fill vn^2 profile and histogram: - mc.fTwoParticleCorrelationProfiles[eBefore]->Fill(i + 2.5, ebye.fTwoParticleCorrelationEbye[eBefore][i], wTwoRecursionBefore); + mc.fTwoParticleCorrelationProfiles[eBefore]->Fill(mc.fTwoParticleCorrelationProfiles[eBefore]->GetXaxis()->GetBinCenter(i + 1), ebye.fTwoParticleCorrelationEbye[eBefore][i], wTwoRecursionBefore); mc.fTwoParticleCorrelationHistograms[eBefore][eBefore][i]->Fill(ebye.fTwoParticleCorrelationEbye[eBefore][i]); mc.fTwoParticleCorrelationHistograms[eBefore][eAfter][i]->Fill(ebye.fTwoParticleCorrelationEbye[eBefore][i], wTwoRecursionBefore); @@ -1340,13 +1443,13 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam } // After cut: - TComplex twoRecursionAfter = mccRecursion(2, harmonicsTwoNum, eAfter, 0) / mccRecursion(2, harmonicsTwoDen, eAfter, 0).Re(); - double wTwoRecursionAfter = mccRecursion(2, harmonicsTwoDen, eAfter, 0).Re(); + TComplex twoRecursionAfter = mccRecursion(2, harmonicsTwoNum, eAfter) / mccRecursion(2, harmonicsTwoDen, eAfter).Re(); + double wTwoRecursionAfter = mccRecursion(2, harmonicsTwoDen, eAfter).Re(); ebye.fTwoParticleCorrelationEbye[eAfter][i] = twoRecursionAfter.Re(); - if (nTracksAfter > 1 && wTwoRecursionAfter > 0.) { + if (nTracksAfter > k - 1 && wTwoRecursionAfter > 0.) { // Fill vn^2 profile and histogram: - mc.fTwoParticleCorrelationProfiles[eAfter]->Fill(i + 2.5, ebye.fTwoParticleCorrelationEbye[eAfter][i], wTwoRecursionAfter); + mc.fTwoParticleCorrelationProfiles[eAfter]->Fill(mc.fTwoParticleCorrelationProfiles[eAfter]->GetXaxis()->GetBinCenter(i + 1), ebye.fTwoParticleCorrelationEbye[eAfter][i], wTwoRecursionAfter); mc.fTwoParticleCorrelationHistograms[eAfter][eBefore][i]->Fill(ebye.fTwoParticleCorrelationEbye[eAfter][i]); mc.fTwoParticleCorrelationHistograms[eAfter][eAfter][i]->Fill(ebye.fTwoParticleCorrelationEbye[eAfter][i], wTwoRecursionAfter); @@ -1363,84 +1466,156 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam LOGF(warning, "cent=%f, nTracksAfter = %d, wTwoRecursionAfter = %e", rlCollisionCent, nTracksAfter, wTwoRecursionAfter); } - // After cut, with gap: - TComplex qva = mcc.fQvectorAfterA[mcc.h2][0]; - TComplex qvb = mcc.fQvectorAfterB[mcc.h2][0]; - double gap = 0.; - if (nTracksAfterA * nTracksAfterB > 0) { - gap = (qva * TComplex::Conjugate(qvb)).Re() / (nTracksAfterA * nTracksAfterB); - mc.fTwoParticleCorrelationGapHistograms[i]->Fill(gap, nTracksAfterA * nTracksAfterB); - } else { - LOGF(warning, "cent=%f, nTracksAfterA = %d, nTracksAfterB = %d", rlCollisionCent, nTracksAfterA, nTracksAfterB); - } - - // // Check if results are consistent: - // double direct = (mccTwo(mcc.h1, mcc.h2, eBefore, 0) / mccTwo(0, 0, eBefore, 0).Re()).Re(); - // double recur = twoRecursionBefore.Re(); - // double diff = std::abs((direct - recur) / recur); + for (int n = 0; n < NumEtaGap; n++) { + + // Before cut, with gap: + TComplex qvba = mcc.fQvectorBeforeA[n][mcc.h2][1]; + TComplex qvbb = mcc.fQvectorBeforeB[n][mcc.h2][1]; + double wba = mcc.fQvectorBeforeA[n][0][1].Re(); + double wbb = mcc.fQvectorBeforeB[n][0][1].Re(); + double gapb = 0.; + if (wba * wbb > 0) { // nTracksBeforeA[n] * nTracksBeforeB[n] > 0 + gapb = (qvba * TComplex::Conjugate(qvbb)).Re() / (wba * wbb); + mc.fTwoParticleCorrelationGapProfiles[n][eBefore]->Fill(mc.fTwoParticleCorrelationGapProfiles[n][eBefore]->GetXaxis()->GetBinCenter(i + 1), gapb, wba * wbb); + } else { + LOGF(warning, "etagap=%f, cent=%f, nTracksBeforeA = %d, nTracksBeforeB = %d", tc.fEtaGap[n], rlCollisionCent, nTracksBeforeA[n], nTracksBeforeB[n]); + } - // if(mccTwo(0, 0, eBefore, 0).Re() < 0. || wTwoRecursionBefore < 0. || diff > 0.01) { - // LOGF(warning, "Compare <2>: cent=%f, n=%d, direct=%e, recursion=%e, diff=%e, denDirect=%e, denRec=%e", rlCollisionCent, mcc.h2, direct, recur, diff, mccTwo(0, 0, eBefore, 0).Re(), wTwoRecursionBefore); - // } + // After cut, with gap: + TComplex qvaa = mcc.fQvectorAfterA[n][mcc.h2][1]; + TComplex qvab = mcc.fQvectorAfterB[n][mcc.h2][1]; + double waa = mcc.fQvectorAfterA[n][0][1].Re(); + double wab = mcc.fQvectorAfterB[n][0][1].Re(); + double gapa = 0.; + if (waa * wab > 0) { + gapa = (qvaa * TComplex::Conjugate(qvab)).Re() / (waa * wab); + mc.fTwoParticleCorrelationGapProfiles[n][eAfter]->Fill(mc.fTwoParticleCorrelationGapProfiles[n][eAfter]->GetXaxis()->GetBinCenter(i + 1), gapa, waa * wab); + mc.fTwoParticleCorrelationGapHistograms[n][i]->Fill(gapa, waa * wab); + } else { + LOGF(warning, "etagap=%f, cent=%f, nTracksAfterA = %d, nTracksAfterB = %d", tc.fEtaGap[n], rlCollisionCent, nTracksAfterA[n], nTracksAfterB[n]); + } + } } - for (int i = 0; i < NumHarmonics; i++) { - // 4-p correlations: - mcc.h1 = -(i + 2); - mcc.h2 = -2; - mcc.h3 = 2; - mcc.h4 = i + 2; + // 4-p correlations: + for (int i = 0; i < NumFourPCorrBins; i++) { + int k = 4; + mcc.h1 = -FourPHarmonicIndex[i][0]; + mcc.h2 = -FourPHarmonicIndex[i][1]; + mcc.h3 = FourPHarmonicIndex[i][0]; + mcc.h4 = FourPHarmonicIndex[i][1]; std::array harmonicsFourNum = {mcc.h1, mcc.h2, mcc.h3, mcc.h4}; std::array harmonicsFourDen = {0, 0, 0, 0}; // Before cut: - TComplex fourRecursionBefore = mccRecursion(4, harmonicsFourNum, eBefore, 0) / mccRecursion(4, harmonicsFourDen, eBefore, 0).Re(); - double wFourRecursionBefore = mccRecursion(4, harmonicsFourDen, eBefore, 0).Re(); + TComplex fourRecursionBefore = mccRecursion(4, harmonicsFourNum, eBefore) / mccRecursion(4, harmonicsFourDen, eBefore).Re(); + double wFourRecursionBefore = mccRecursion(4, harmonicsFourDen, eBefore).Re(); ebye.fFourParticleCorrelationEbye[eBefore][i] = fourRecursionBefore.Re(); - if (nTracksBefore > mcc.MaxCorrelator && wFourRecursionBefore > 0.) { - // Fill v2^2vn^2 profile and histogram: - mc.fFourParticleCorrelationProfiles[eBefore]->Fill(i + 2.5, ebye.fFourParticleCorrelationEbye[eBefore][i], wFourRecursionBefore); + if (nTracksBefore > k - 1 && wFourRecursionBefore > 0.) { + // Fill vn^2vm^2 profile and histogram: + mc.fFourParticleCorrelationProfiles[eBefore]->Fill(mc.fFourParticleCorrelationProfiles[eBefore]->GetXaxis()->GetBinCenter(i + 1), ebye.fFourParticleCorrelationEbye[eBefore][i], wFourRecursionBefore); mc.fFourParticleCorrelationHistograms[eBefore][eBefore][i]->Fill(ebye.fFourParticleCorrelationEbye[eBefore][i]); mc.fFourParticleCorrelationHistograms[eBefore][eAfter][i]->Fill(ebye.fFourParticleCorrelationEbye[eBefore][i], wFourRecursionBefore); // Find max and min: if (ebye.fFourParticleCorrelationEbye[eBefore][i] > ebye.fFourParticleCorrelationMaxEbye[eBefore][i]) { ebye.fFourParticleCorrelationMaxEbye[eBefore][i] = ebye.fFourParticleCorrelationEbye[eBefore][i]; - LOGF(info, "max v2^2v%d^2 so far = %e", i + 2, ebye.fFourParticleCorrelationEbye[eBefore][i]); + LOGF(info, "max v%d^2v%d^2 so far = %e", mcc.h3, mcc.h4, ebye.fFourParticleCorrelationEbye[eBefore][i]); } if (ebye.fFourParticleCorrelationEbye[eBefore][i] < ebye.fFourParticleCorrelationMinEbye[eBefore][i]) { ebye.fFourParticleCorrelationMinEbye[eBefore][i] = ebye.fFourParticleCorrelationEbye[eBefore][i]; - LOGF(info, "min v2^2v%d^2 so far = %e", i + 2, ebye.fFourParticleCorrelationEbye[eBefore][i]); + LOGF(info, "min v%d^2v%d^2 so far = %e", mcc.h3, mcc.h4, ebye.fFourParticleCorrelationEbye[eBefore][i]); } } else { LOGF(warning, "cent=%f, nTracksBefore = %d, wFourRecursionBefore = %e", rlCollisionCent, nTracksBefore, wFourRecursionBefore); } // After cut: - TComplex fourRecursionAfter = mccRecursion(4, harmonicsFourNum, eAfter, 0) / mccRecursion(4, harmonicsFourDen, eAfter, 0).Re(); - double wFourRecursionAfter = mccRecursion(4, harmonicsFourDen, eAfter, 0).Re(); + TComplex fourRecursionAfter = mccRecursion(4, harmonicsFourNum, eAfter) / mccRecursion(4, harmonicsFourDen, eAfter).Re(); + double wFourRecursionAfter = mccRecursion(4, harmonicsFourDen, eAfter).Re(); ebye.fFourParticleCorrelationEbye[eAfter][i] = fourRecursionAfter.Re(); - if (nTracksAfter > mcc.MaxCorrelator && wFourRecursionAfter > 0.) { - // Fill v2^2vn^2 profile and histogram: - mc.fFourParticleCorrelationProfiles[eAfter]->Fill(i + 2.5, ebye.fFourParticleCorrelationEbye[eAfter][i], wFourRecursionAfter); + if (nTracksAfter > k - 1 && wFourRecursionAfter > 0.) { + // Fill vn^2vm^2 profile and histogram: + mc.fFourParticleCorrelationProfiles[eAfter]->Fill(mc.fFourParticleCorrelationProfiles[eAfter]->GetXaxis()->GetBinCenter(i + 1), ebye.fFourParticleCorrelationEbye[eAfter][i], wFourRecursionAfter); mc.fFourParticleCorrelationHistograms[eAfter][eBefore][i]->Fill(ebye.fFourParticleCorrelationEbye[eAfter][i]); mc.fFourParticleCorrelationHistograms[eAfter][eAfter][i]->Fill(ebye.fFourParticleCorrelationEbye[eAfter][i], wFourRecursionAfter); // Find max and min: if (ebye.fFourParticleCorrelationEbye[eAfter][i] > ebye.fFourParticleCorrelationMaxEbye[eAfter][i]) { ebye.fFourParticleCorrelationMaxEbye[eAfter][i] = ebye.fFourParticleCorrelationEbye[eAfter][i]; - LOGF(info, "max v2^2v%d^2 so far = %e", i + 2, ebye.fFourParticleCorrelationEbye[eAfter][i]); + LOGF(info, "max v%d^2v%d^2 so far = %e", mcc.h3, mcc.h4, ebye.fFourParticleCorrelationEbye[eAfter][i]); } if (ebye.fFourParticleCorrelationEbye[eAfter][i] < ebye.fFourParticleCorrelationMinEbye[eAfter][i]) { ebye.fFourParticleCorrelationMinEbye[eAfter][i] = ebye.fFourParticleCorrelationEbye[eAfter][i]; - LOGF(info, "min v2^2v%d^2 so far = %e", i + 2, ebye.fFourParticleCorrelationEbye[eAfter][i]); + LOGF(info, "min v%d^2v%d^2 so far = %e", mcc.h3, mcc.h4, ebye.fFourParticleCorrelationEbye[eAfter][i]); } } else { LOGF(warning, "cent=%f, nTracksAfter = %d, wFourRecursionAfter = %e", rlCollisionCent, nTracksAfter, wFourRecursionAfter); } } + + // 6-p correlations: + for (int i = 0; i < NumSixPCorrBins; i++) { + int k = 6; + mcc.h1 = -2; + mcc.h2 = -3; + mcc.h3 = -4; + mcc.h4 = 2; + mcc.h5 = 3; + mcc.h6 = 4; + std::array harmonicsSixNum = {mcc.h1, mcc.h2, mcc.h3, mcc.h4, mcc.h5, mcc.h6}; + std::array harmonicsSixDen = {0, 0, 0, 0, 0, 0}; + + // Before cut: + TComplex sixRecursionBefore = mccRecursion(6, harmonicsSixNum, eBefore) / mccRecursion(6, harmonicsSixDen, eBefore).Re(); + double wSixRecursionBefore = mccRecursion(6, harmonicsSixDen, eBefore).Re(); + ebye.fSixParticleCorrelationEbye[eBefore][i] = sixRecursionBefore.Re(); + + if (nTracksBefore > k - 1 && wSixRecursionBefore > 0.) { + // Fill v2^2v3^2v4^2 profile and histogram: + mc.fSixParticleCorrelationProfiles[eBefore]->Fill(mc.fSixParticleCorrelationProfiles[eBefore]->GetXaxis()->GetBinCenter(i + 1), ebye.fSixParticleCorrelationEbye[eBefore][i], wSixRecursionBefore); + mc.fSixParticleCorrelationHistograms[eBefore][eBefore][i]->Fill(ebye.fSixParticleCorrelationEbye[eBefore][i]); + mc.fSixParticleCorrelationHistograms[eBefore][eAfter][i]->Fill(ebye.fSixParticleCorrelationEbye[eBefore][i], wSixRecursionBefore); + + // Find max and min: + if (ebye.fSixParticleCorrelationEbye[eBefore][i] > ebye.fSixParticleCorrelationMaxEbye[eBefore][i]) { + ebye.fSixParticleCorrelationMaxEbye[eBefore][i] = ebye.fSixParticleCorrelationEbye[eBefore][i]; + LOGF(info, "max v%d^2v%d^2v%d^2 so far = %e", mcc.h4, mcc.h5, mcc.h6, ebye.fSixParticleCorrelationEbye[eBefore][i]); + } + if (ebye.fSixParticleCorrelationEbye[eBefore][i] < ebye.fSixParticleCorrelationMinEbye[eBefore][i]) { + ebye.fSixParticleCorrelationMinEbye[eBefore][i] = ebye.fSixParticleCorrelationEbye[eBefore][i]; + LOGF(info, "min v%d^2v%d^2v%d^2 so far = %e", mcc.h4, mcc.h5, mcc.h6, ebye.fSixParticleCorrelationEbye[eBefore][i]); + } + } else { + LOGF(warning, "cent=%f, nTracksBefore = %d, wSixRecursionBefore = %e", rlCollisionCent, nTracksBefore, wSixRecursionBefore); + } + + // After cut: + TComplex sixRecursionAfter = mccRecursion(6, harmonicsSixNum, eAfter) / mccRecursion(6, harmonicsSixDen, eAfter).Re(); + double wSixRecursionAfter = mccRecursion(6, harmonicsSixDen, eAfter).Re(); + ebye.fSixParticleCorrelationEbye[eAfter][i] = sixRecursionAfter.Re(); + + if (nTracksAfter > k - 1 && wSixRecursionAfter > 0.) { + // Fill v2^2v3^2v4^2 profile and histogram: + mc.fSixParticleCorrelationProfiles[eAfter]->Fill(mc.fSixParticleCorrelationProfiles[eAfter]->GetXaxis()->GetBinCenter(i + 1), ebye.fSixParticleCorrelationEbye[eAfter][i], wSixRecursionAfter); + mc.fSixParticleCorrelationHistograms[eAfter][eBefore][i]->Fill(ebye.fSixParticleCorrelationEbye[eAfter][i]); + mc.fSixParticleCorrelationHistograms[eAfter][eAfter][i]->Fill(ebye.fSixParticleCorrelationEbye[eAfter][i], wSixRecursionAfter); + + // Find max and min: + if (ebye.fSixParticleCorrelationEbye[eAfter][i] > ebye.fSixParticleCorrelationMaxEbye[eAfter][i]) { + ebye.fSixParticleCorrelationMaxEbye[eAfter][i] = ebye.fSixParticleCorrelationEbye[eAfter][i]; + LOGF(info, "max v%d^2v%d^2v%d^2 so far = %e", mcc.h4, mcc.h5, mcc.h6, ebye.fSixParticleCorrelationEbye[eAfter][i]); + } + if (ebye.fSixParticleCorrelationEbye[eAfter][i] < ebye.fSixParticleCorrelationMinEbye[eAfter][i]) { + ebye.fSixParticleCorrelationMinEbye[eAfter][i] = ebye.fSixParticleCorrelationEbye[eAfter][i]; + LOGF(info, "min v%d^2v%d^2v%d^2 so far = %e", mcc.h4, mcc.h5, mcc.h6, ebye.fSixParticleCorrelationEbye[eAfter][i]); + } + } else { + LOGF(warning, "cent=%f, nTracksAfter = %d, wSixRecursionAfter = %e", rlCollisionCent, nTracksAfter, wSixRecursionAfter); + } + } } template @@ -1571,125 +1746,172 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam template void bookCorrHistograms(T1 const& lCrBins) { + // (mult)(cent)(NContribMult) offset + constexpr int BoundOffset = histType == eCorrCent ? eCentABBound : histType == eCorrMult ? eMultABBound + : eNumContribMultBound; - // book limit functions: - if constexpr (histType == eCorrCent) { - cr.fCorrBounds[histType][0] = new TF1(Form("fCorrUpperBound%s", CorrHistNames[histType]), "[0] * x + [1]"); - cr.fCorrBounds[histType][1] = new TF1(Form("fCorrLowerBound%s", CorrHistNames[histType]), "(x - [1]) / [0]"); - cr.fCorrBounds[histType][0]->SetTitle(Form("%s upper bound", CorrHistNames[histType])); - cr.fCorrBounds[histType][1]->SetTitle(Form("%s lower bound", CorrHistNames[histType])); - } else if constexpr (histType == eCorrMult) { + // (mult)(cent)(NContribMult) book functions: + if constexpr (histType == eCorrCent || histType == eCorrMult) { for (int i = 0; i < eEstmCorr_N; i++) { - cr.fCorrBounds[histType + i][0] = new TF1(Form("fCorrUpperBound%s%s", EstmCorrName[i], CorrHistNames[histType]), "[0] * x + [1]"); - cr.fCorrBounds[histType + i][1] = new TF1(Form("fCorrLowerBound%s%s", EstmCorrName[i], CorrHistNames[histType]), "[0] * x + [1]"); - cr.fCorrBounds[histType + i][0]->SetTitle(Form("%s %s upper bound", EstmCorrName[i], CorrHistNames[histType])); - cr.fCorrBounds[histType + i][1]->SetTitle(Form("%s %s lower bound", EstmCorrName[i], CorrHistNames[histType])); + int indexBound = BoundOffset + i; + cr.fCorrBounds[indexBound][0] = new TF1(Form("fCorrUpperBound%s%s", EstmCorrName[i], CorrHistNames[histType]), "[0] * x + [1]"); + cr.fCorrBounds[indexBound][1] = new TF1(Form("fCorrLowerBound%s%s", EstmCorrName[i], CorrHistNames[histType]), "[0] * x + [1]"); + cr.fCorrBounds[indexBound][0]->SetTitle(Form("%s %s upper bound", EstmCorrName[i], CorrHistNames[histType])); + cr.fCorrBounds[indexBound][1]->SetTitle(Form("%s %s lower bound", EstmCorrName[i], CorrHistNames[histType])); } + } else if constexpr (histType == eCorrNumContribMult) { + int indexBound = BoundOffset; + cr.fCorrBounds[indexBound][0] = new TF1(Form("fCorrUpperBound%s", CorrHistNames[histType]), "[0] * x + [1]"); + cr.fCorrBounds[indexBound][1] = new TF1(Form("fCorrLowerBound%s", CorrHistNames[histType]), "[0] * x + [1]"); + cr.fCorrBounds[indexBound][0]->SetTitle(Form("%s upper bound", CorrHistNames[histType])); + cr.fCorrBounds[indexBound][1]->SetTitle(Form("%s lower bound", CorrHistNames[histType])); } - int nBinsCent = 0; - float minCent = 0.; - float maxCent = 0.; + int nBinsXCent = 0; + float minXCent = 0.; + float maxXCent = 0.; + int nBinsYCent = 0; + float minYCent = 0.; + float maxYCent = 0.; int nBinsXMult = 0; float minXMult = 0.; float maxXMult = 0.; int nBinsYMult = 0; float minYMult = 0.; float maxYMult = 0.; + // int nBinsNumContrib = 0; + // float minNumContrib = 0.; + float maxNumContrib = 0.; + + // (NContribMult) set functions and add to list: + if constexpr (histType == eCorrNumContribMult) { + + int indexBins = static_cast(histType) + static_cast(eMultEstm_N); + + // (NContribMult) get bins: + const auto& lMultXBins = lCrBins[indexBins]; + nBinsXMult = static_cast(lMultXBins[0]); + minXMult = lMultXBins[1]; + maxXMult = lMultXBins[2]; + const auto& lNumContribBins = lCrBins[indexBins - 1]; + // nBinsNumContrib = static_cast(lNumContribBins[0]); + // minNumContrib = lNumContribBins[1]; + maxNumContrib = lNumContribBins[2]; + + // (NContribMult) set functions and add to list: + int indexBound = BoundOffset; + cr.fCorrBounds[indexBound][0]->SetRange(minXMult, maxXMult); + cr.fCorrBounds[indexBound][1]->SetRange(minXMult, maxXMult); + cr.fCorrBounds[indexBound][0]->SetMinimum(0); + cr.fCorrBounds[indexBound][1]->SetMinimum(0); + cr.fCorrBounds[indexBound][0]->SetMaximum(maxNumContrib); + cr.fCorrBounds[indexBound][1]->SetMaximum(maxNumContrib); + cr.fCorrBounds[indexBound][0]->SetParameters(tc.fNumContribMultCorrCut[0], tc.fNumContribMultCorrCut[1]); + cr.fCorrBounds[indexBound][1]->SetParameters(tc.fNumContribMultCorrCut[2], tc.fNumContribMultCorrCut[3]); + cr.fCorrHistogramsList->Add(cr.fCorrBounds[indexBound][0]); + cr.fCorrHistogramsList->Add(cr.fCorrBounds[indexBound][1]); + } - if constexpr (histType == eCorrCent) { - - // (cent) get bins: - const auto& lCentBins = lCrBins[histType]; - nBinsCent = static_cast(lCentBins[0]); - minCent = lCentBins[1]; - maxCent = lCentBins[2]; - - // (cent) set functions and add to list: - cr.fCorrBounds[histType][0]->SetRange(minCent, maxCent); - cr.fCorrBounds[histType][1]->SetRange(minCent, maxCent); - cr.fCorrBounds[histType][0]->SetMinimum(0); - cr.fCorrBounds[histType][1]->SetMinimum(0); - cr.fCorrBounds[histType][0]->SetMaximum(100); - cr.fCorrBounds[histType][1]->SetMaximum(100); - cr.fCorrBounds[histType][0]->SetParameters(tc.fCentCorrCut[0], tc.fCentCorrCut[1]); - cr.fCorrBounds[histType][1]->SetParameters(tc.fCentCorrCut[0], tc.fCentCorrCut[1]); - cr.fCorrHistogramsList->Add(cr.fCorrBounds[histType][0]); - cr.fCorrHistogramsList->Add(cr.fCorrBounds[histType][1]); - - } // else if constexpr (histType == eCorrMult) {} - - for (int ba = 0; ba < eBeforeAfter_N; ba++) { - std::string name; - std::string namefull = Form("%s correlation %s cut", CorrHistNames[histType], BeforeAfterNames[ba]); - - int nEstm = 0; - if constexpr (histType == eCorrCent) { - nEstm = eCentEstm_N; - } else if constexpr (histType == eCorrMult) { - nEstm = eMultEstm_N; - } - - int nComb = 0; // count combination AB, AC, BC - - for (int i = 0; i < nEstm; i++) { + // (mult)(cent) Book histograms, set functions and add to list: + if constexpr (histType != eCorrNumContribMult) { + for (int ba = 0; ba < eBeforeAfter_N; ba++) { + std::string name; + std::string namefull = Form("%s correlation %s cut", CorrHistNames[histType], BeforeAfterNames[ba]); - std::string titleX; + int nEstm = 0; if constexpr (histType == eCorrCent) { - titleX = Form("%s %s", CentEstmNames[i], CorrHistNames[histType]); - + nEstm = eCentEstm_N; } else if constexpr (histType == eCorrMult) { - titleX = Form("%s %s", MultEstmNames[i], CorrHistNames[histType]); + nEstm = eMultEstm_N; } - for (int j = i + 1; j < nEstm; j++) { + int nComb = 0; // count combination AB, AC, BC - std::string titleY; - if constexpr (histType == eCorrCent) { - name = Form("fHist%s[%s vs. %s][%s cut]", CorrHistNames[histType], CentEstmNames[i], CentEstmNames[j], BeforeAfterNames[ba]); - titleY = Form("%s %s", CentEstmNames[j], CorrHistNames[histType]); + for (int i = 0; i < nEstm; i++) { - // (cent) book corr 2D histogram: - cr.fCorrHistograms[histType][i][j][ba] = new TH2F(name.c_str(), namefull.c_str(), nBinsCent, minCent, maxCent, nBinsCent, minCent, maxCent); + std::string titleX; + if constexpr (histType == eCorrCent) { + titleX = Form("%s %s", CentEstmNames[i], CorrHistNames[histType]); } else if constexpr (histType == eCorrMult) { - name = Form("fHist%s[%s vs. %s][%s cut]", CorrHistNames[histType], MultEstmNames[i], MultEstmNames[j], BeforeAfterNames[ba]); - titleY = Form("%s %s", MultEstmNames[j], CorrHistNames[histType]); - - // (mult) get bins: - const auto& lMultXBins = lCrBins[i + 1]; - nBinsXMult = static_cast(lMultXBins[0]); - minXMult = lMultXBins[1]; - maxXMult = lMultXBins[2]; - const auto& lMultYBins = lCrBins[j + 1]; - nBinsYMult = static_cast(lMultYBins[0]); - minYMult = lMultYBins[1]; - maxYMult = lMultYBins[2]; - - // (mult) set functions and add to list: - if (static_cast(ba)) { - cr.fCorrBounds[histType + nComb][0]->SetRange(minXMult, maxXMult); - cr.fCorrBounds[histType + nComb][1]->SetRange(minXMult, maxXMult); - cr.fCorrBounds[histType + nComb][0]->SetParameters(tc.fMultAllCorrCut[i][j][0], tc.fMultAllCorrCut[i][j][1]); - cr.fCorrBounds[histType + nComb][1]->SetParameters(tc.fMultAllCorrCut[i][j][2], tc.fMultAllCorrCut[i][j][3]); - cr.fCorrBounds[histType + nComb][0]->SetMinimum(0); - cr.fCorrBounds[histType + nComb][1]->SetMinimum(0); - cr.fCorrBounds[histType + nComb][0]->SetMaximum(maxYMult); - cr.fCorrBounds[histType + nComb][1]->SetMaximum(maxYMult); - cr.fCorrHistogramsList->Add(cr.fCorrBounds[histType + nComb][0]); - cr.fCorrHistogramsList->Add(cr.fCorrBounds[histType + nComb][1]); - } - - // (mult) book corr 2D histogram: - cr.fCorrHistograms[histType][i][j][ba] = new TH2F(name.c_str(), namefull.c_str(), nBinsXMult, minXMult, maxXMult, nBinsYMult, minYMult, maxYMult); + titleX = Form("%s %s", MultEstmNames[i], CorrHistNames[histType]); } - // (cent/mult) set corr histogram - cr.fCorrHistograms[histType][i][j][ba]->GetYaxis()->SetTitle(titleY.c_str()); - cr.fCorrHistograms[histType][i][j][ba]->GetXaxis()->SetTitle(titleX.c_str()); - cr.fCorrHistogramsList->Add(cr.fCorrHistograms[histType][i][j][ba]); + for (int j = i + 1; j < nEstm; j++) { + + std::string titleY; + if constexpr (histType == eCorrCent) { + name = Form("fHist%s[%s vs. %s][%s cut]", CorrHistNames[histType], CentEstmNames[i], CentEstmNames[j], BeforeAfterNames[ba]); + titleY = Form("%s %s", CentEstmNames[j], CorrHistNames[histType]); + + // (cent) get bins: + const auto& lCentXBins = lCrBins[0]; + nBinsXCent = static_cast(lCentXBins[0]); + minXCent = lCentXBins[1]; + maxXCent = lCentXBins[2]; + const auto& lCentYBins = lCrBins[0]; + nBinsYCent = static_cast(lCentYBins[0]); + minYCent = lCentYBins[1]; + maxYCent = lCentYBins[2]; + + // (cent) set functions and add to list: + if (static_cast(ba)) { + int indexBound = BoundOffset + nComb; + cr.fCorrBounds[indexBound][0]->SetRange(minXCent, maxXCent); + cr.fCorrBounds[indexBound][1]->SetRange(minXCent, maxXCent); + cr.fCorrBounds[indexBound][0]->SetParameters(tc.fCentAllCorrCut[i][j][0], tc.fCentAllCorrCut[i][j][1]); + cr.fCorrBounds[indexBound][1]->SetParameters(tc.fCentAllCorrCut[i][j][2], tc.fCentAllCorrCut[i][j][3]); + cr.fCorrBounds[indexBound][0]->SetMinimum(0); + cr.fCorrBounds[indexBound][1]->SetMinimum(0); + cr.fCorrBounds[indexBound][0]->SetMaximum(maxYCent); + cr.fCorrBounds[indexBound][1]->SetMaximum(maxYCent); + cr.fCorrHistogramsList->Add(cr.fCorrBounds[indexBound][0]); + cr.fCorrHistogramsList->Add(cr.fCorrBounds[indexBound][1]); + } + + // (cent) book corr 2D histogram: + cr.fCorrHistograms[histType][i][j][ba] = new TH2F(name.c_str(), namefull.c_str(), nBinsXCent, minXCent, maxXCent, nBinsYCent, minYCent, maxYCent); + + } else if constexpr (histType == eCorrMult) { + name = Form("fHist%s[%s vs. %s][%s cut]", CorrHistNames[histType], MultEstmNames[i], MultEstmNames[j], BeforeAfterNames[ba]); + titleY = Form("%s %s", MultEstmNames[j], CorrHistNames[histType]); + + // (mult) get bins: + const auto& lMultXBins = lCrBins[i + 1]; + nBinsXMult = static_cast(lMultXBins[0]); + minXMult = lMultXBins[1]; + maxXMult = lMultXBins[2]; + const auto& lMultYBins = lCrBins[j + 1]; + nBinsYMult = static_cast(lMultYBins[0]); + minYMult = lMultYBins[1]; + maxYMult = lMultYBins[2]; + + // (mult) set functions and add to list: + if (static_cast(ba)) { + int indexBound = BoundOffset + nComb; + cr.fCorrBounds[indexBound][0]->SetRange(minXMult, maxXMult); + cr.fCorrBounds[indexBound][1]->SetRange(minXMult, maxXMult); + cr.fCorrBounds[indexBound][0]->SetParameters(tc.fMultAllCorrCut[i][j][0], tc.fMultAllCorrCut[i][j][1]); + cr.fCorrBounds[indexBound][1]->SetParameters(tc.fMultAllCorrCut[i][j][2], tc.fMultAllCorrCut[i][j][3]); + cr.fCorrBounds[indexBound][0]->SetMinimum(0); + cr.fCorrBounds[indexBound][1]->SetMinimum(0); + cr.fCorrBounds[indexBound][0]->SetMaximum(maxYMult); + cr.fCorrBounds[indexBound][1]->SetMaximum(maxYMult); + cr.fCorrHistogramsList->Add(cr.fCorrBounds[indexBound][0]); + cr.fCorrHistogramsList->Add(cr.fCorrBounds[indexBound][1]); + } - nComb += 1; + // (mult) book corr 2D histogram: + cr.fCorrHistograms[histType][i][j][ba] = new TH2F(name.c_str(), namefull.c_str(), nBinsXMult, minXMult, maxXMult, nBinsYMult, minYMult, maxYMult); + } + + // (cent)(mult) set corr histogram + cr.fCorrHistograms[histType][i][j][ba]->GetYaxis()->SetTitle(titleY.c_str()); + cr.fCorrHistograms[histType][i][j][ba]->GetXaxis()->SetTitle(titleX.c_str()); + cr.fCorrHistogramsList->Add(cr.fCorrHistograms[histType][i][j][ba]); + + nComb += 1; + } } } } @@ -1719,6 +1941,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam tc.fNumContribCutSwitch = cfNumContribCutSwitch; tc.fCentCorrCutSwitch = cfCentCorrCutSwitch; tc.fMultCorrCutSwitch = cfMultCorrCutSwitch; + tc.fNumContribMultCorrCutSwitch = cfNumContribMultCorrCutSwitch; tc.fPtCutSwitch = cfPtCutSwitch; tc.fEtaCutSwitch = cfEtaCutSwitch; @@ -1726,15 +1949,18 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam tc.fTpcNClsFoundCutSwitch = cfTpcNClsFoundCutSwitch; tc.fDCAXYCutSwitch = cfDCAXYCutSwitch; tc.fDCAZCutSwitch = cfDCAZCutSwitch; - tc.fEtaGapSwitch = cfEtaGapSwitch; + tc.fHasTpcItsCutSwitch = cfHasTpcItsCutSwitch; tc.fVertexZCut = cfVertexZCut; tc.fCentCut = cfCentCut; tc.fNumContribCut = cfNumContribCut; - tc.fCentCorrCut = cfCentCorrCut; + tc.fCentAllCorrCut[0][1] = cfCentABCorrCut; + tc.fCentAllCorrCut[0][2] = cfCentACCorrCut; + tc.fCentAllCorrCut[1][2] = cfCentBCCorrCut; tc.fMultAllCorrCut[0][1] = cfMultABCorrCut; tc.fMultAllCorrCut[0][2] = cfMultACCorrCut; tc.fMultAllCorrCut[1][2] = cfMultBCCorrCut; + tc.fNumContribMultCorrCut = cfNumContribMultCorrCut; tc.fPtCut = cfPtCut; tc.fEtaCut = cfEtaCut; @@ -1742,6 +1968,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam tc.fTpcNClsFoundCut = cfTpcNClsFoundCut; tc.fDCAXYCut = cfDCAXYCut; tc.fDCAZCut = cfDCAZCut; + tc.fHasTpcItsCut = cfHasTpcItsCut; tc.fEtaGap = cfEtaGap; tc.fPtBins = cfPtBins; @@ -1758,6 +1985,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam tc.fNumContribBins = cfNumContribBins; tc.fTwoParticleCorrBins = cfTwoParticleCorrBins; tc.fFourParticleCorrBins = cfFourParticleCorrBins; + tc.fSixParticleCorrBins = cfSixParticleCorrBins; tc.fPrintSwitch = cfPrintSwitch; tc.fFileWithWeights = cfFileWithWeights; @@ -1814,7 +2042,7 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam std::vector> lPcBins = {tc.fPtBins, tc.fPhiBins}; std::vector> lEvBins = {tc.fCentBins, tc.fMultBins, tc.fVerXBins, tc.fVerYBins, tc.fVerZBins, tc.fNumContribBins}; std::vector> lQABins = {tc.fCentBins, tc.fMultBins, tc.fNumContribBins}; - std::vector> lCrBins = {tc.fCentBins, tc.fFT0CMultBins, tc.fFT0MMultBins, tc.fFV0AMultBins}; + std::vector> lCrBins = {tc.fCentBins, tc.fFT0CMultBins, tc.fFT0MMultBins, tc.fFV0AMultBins, tc.fNumContribBins, tc.fMultBins}; bookParticleHistograms(lPcBins); bookParticleHistograms(lPcBins); @@ -1826,8 +2054,9 @@ struct MultiparticleCumulants { // this name is used in lower-case format to nam bookEventHistograms(lEvBins); bookQAHistograms(lQABins); bookQAHistograms(lQABins); - bookCorrHistograms(lCrBins); // if switch on ... + bookCorrHistograms(lCrBins); bookCorrHistograms(lCrBins); + bookCorrHistograms(lCrBins); wt.fDummyPhiWeightHistogram = new TH1F("fDummyPhiWeightHistogram", "Dummy phi weight histogram", static_cast(tc.fPhiBins[0]), tc.fPhiBins[1], tc.fPhiBins[2]); for (int i = 1; i <= wt.fDummyPhiWeightHistogram->GetNbinsX(); i++) { diff --git a/PWGCF/TableProducer/filterCorrelations.cxx b/PWGCF/TableProducer/filterCorrelations.cxx index 3063ff72605..8f246c14653 100644 --- a/PWGCF/TableProducer/filterCorrelations.cxx +++ b/PWGCF/TableProducer/filterCorrelations.cxx @@ -9,10 +9,12 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +// o2-linter: disable=name/workflow-file (file contains several table-producer tasks) #include "PWGCF/DataModel/CorrelationsDerived.h" #include "Common/CCDB/EventSelectionParams.h" #include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/TableHelper.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" @@ -21,6 +23,8 @@ #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" +#include +#include #include #include #include @@ -35,29 +39,38 @@ #include #include +#include #include +#include #include #include #include +#include +#include +#include #include #include // required for is_detected +#include +#include +#include #include #include -#include - using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::math_utils::detail; -#define FLOAT_PRECISION 0xFFFFFFF0 -#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; +constexpr std::uint32_t kFloatPrecision = 0xFFFFFFF0u; +// clang-format off +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME { #NAME, (DEFAULT), (HELP) } // NOLINT(bugprone-macro-parentheses) +// clang-format on struct FilterCF { - Service pdg; + Service pdg{}; + Service ccdb{}; enum TrackSelectionCuts1 : uint8_t { kTrackSelected = BIT(0), @@ -73,36 +86,40 @@ struct FilterCF { }; // Configuration - O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 7.0f, "Accepted z-vertex range") - O2_DEFINE_CONFIGURABLE(cfgCutPt, float, 0.5f, "Minimal pT for tracks") - O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") - O2_DEFINE_CONFIGURABLE(cfgCutMCPt, float, 0.5f, "Minimal pT for particles") - O2_DEFINE_CONFIGURABLE(cfgCutMCEta, float, 0.8f, "Eta range for particles") - O2_DEFINE_CONFIGURABLE(cfgVerbosity, int, 1, "Verbosity level (0 = major, 1 = per collision)") - O2_DEFINE_CONFIGURABLE(cfgTrigger, int, 7, "Trigger choice: (0 = none, 7 = sel7, 8 = sel8, 9 = sel8 + kNoSameBunchPileup + kIsGoodZvtxFT0vsPV, 10 = sel8 before April, 2024, 11 = sel8 for MC, 12 = sel8 with low occupancy cut, 13 = sel8 + kNoSameBunchPileup + kIsGoodITSLayersAll -- for OO/NeNe) ") - O2_DEFINE_CONFIGURABLE(cfgMinOcc, int, 0, "minimum occupancy selection") - O2_DEFINE_CONFIGURABLE(cfgMaxOcc, int, 3000, "maximum occupancy selection") - O2_DEFINE_CONFIGURABLE(cfgCollisionFlags, uint16_t, aod::collision::CollisionFlagsRun2::Run2VertexerTracks, "Request collision flags if non-zero (0 = off, 1 = Run2VertexerTracks)") - O2_DEFINE_CONFIGURABLE(cfgTransientTables, bool, false, "Output transient tables for collision and track IDs to enable successive filtering tasks") - O2_DEFINE_CONFIGURABLE(cfgTrackSelection, int, 0, "Type of track selection (0 = Run 2/3 without systematics | 1 = Run 3 with systematics | 2 = Run 3 with proton pid selection)") - O2_DEFINE_CONFIGURABLE(cfgMinMultiplicity, float, -1, "Minimum multiplicity considered for filtering (if value positive)") - O2_DEFINE_CONFIGURABLE(cfgMcSpecialPDGs, std::vector, {}, "Special MC PDG codes to include in the MC primary particle output (additional to charged particles). Empty = charged particles only.") // needed for some neutral particles - O2_DEFINE_CONFIGURABLE(nsigmaCutTPCProton, float, 3, "proton nsigma TPC") - O2_DEFINE_CONFIGURABLE(nsigmaCutTOFProton, float, 3, "proton nsigma TOF") - O2_DEFINE_CONFIGURABLE(ITSProtonselection, bool, false, "flag for ITS proton nsigma selection") - O2_DEFINE_CONFIGURABLE(nsigmaCutITSProton, float, 3, "proton nsigma ITS") - O2_DEFINE_CONFIGURABLE(dcaxymax, float, 999.f, "maximum dcaxy of tracks") - O2_DEFINE_CONFIGURABLE(dcazmax, float, 999.f, "maximum dcaz of tracks") - O2_DEFINE_CONFIGURABLE(enablePtDepDCAxy, bool, false, "Enable pT-dependent DCAxy cut: |DCAxy| < a + b/pT") - O2_DEFINE_CONFIGURABLE(dcaXyConst, float, 0.004f, "Constant term 'a' for pT-dependent DCAxy cut: |DCAxy| < a + b/pT (cm)") - O2_DEFINE_CONFIGURABLE(dcaXySlope, float, 0.013f, "Slope term 'b' for pT-dependent DCAxy cut: |DCAxy| < a + b/pT (cm x GeV/c)") - O2_DEFINE_CONFIGURABLE(itsnclusters, int, 5, "minimum number of ITS clusters for tracks") - O2_DEFINE_CONFIGURABLE(tpcncrossedrows, int, 80, "minimum number of TPC crossed rows for tracks") - O2_DEFINE_CONFIGURABLE(tpcnclusters, int, 50, "minimum number of TPC clusters found") - O2_DEFINE_CONFIGURABLE(chi2pertpccluster, float, 2.5, "maximum Chi2 / cluster for the TPC track segment") - O2_DEFINE_CONFIGURABLE(chi2peritscluster, float, 36, "maximum Chi2 / cluster for the ITS track segment") + O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 7.0f, "Accepted z-vertex range"); + O2_DEFINE_CONFIGURABLE(cfgCutPt, float, 0.5f, "Minimal pT for tracks"); + O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks"); + O2_DEFINE_CONFIGURABLE(cfgCutMCPt, float, 0.5f, "Minimal pT for particles"); + O2_DEFINE_CONFIGURABLE(cfgCutMCEta, float, 0.8f, "Eta range for particles"); + O2_DEFINE_CONFIGURABLE(cfgVerbosity, int, 1, "Verbosity level (0 = major, 1 = per collision)"); + O2_DEFINE_CONFIGURABLE(cfgTrigger, int, 7, "Trigger choice: (0 = none, 7 = sel7, 8 = sel8, 9 = sel8 + kNoSameBunchPileup + kIsGoodZvtxFT0vsPV, 10 = sel8 before April, 2024, 11 = sel8 for MC, 12 = sel8 with low occupancy cut, 13 = sel8 + kNoSameBunchPileup + kIsGoodITSLayersAll -- for OO/NeNe) "); + O2_DEFINE_CONFIGURABLE(cfgMinOcc, int, 0, "minimum occupancy selection"); + O2_DEFINE_CONFIGURABLE(cfgMaxOcc, int, 3000, "maximum occupancy selection"); + O2_DEFINE_CONFIGURABLE(cfgCollisionFlags, uint16_t, aod::collision::CollisionFlagsRun2::Run2VertexerTracks, "Request collision flags if non-zero (0 = off, 1 = Run2VertexerTracks)"); + O2_DEFINE_CONFIGURABLE(cfgTransientTables, bool, false, "Output transient tables for collision and track IDs to enable successive filtering tasks"); + O2_DEFINE_CONFIGURABLE(cfgTrackSelection, int, 0, "Type of track selection (0 = Run 2/3 without systematics | 1 = Run 3 with systematics | 2 = Run 3 with proton pid selection)"); + O2_DEFINE_CONFIGURABLE(cfgMinMultiplicity, float, -1, "Minimum multiplicity considered for filtering (if value positive)"); + O2_DEFINE_CONFIGURABLE(cfgMcSpecialPDGs, std::vector, std::vector{}, "Special MC PDG codes to include in the MC primary particle output (additional to charged particles). Empty = charged particles only."); // needed for some neutral particles + O2_DEFINE_CONFIGURABLE(nsigmaCutTPCProton, float, 3, "proton nsigma TPC"); + O2_DEFINE_CONFIGURABLE(nsigmaCutTOFProton, float, 3, "proton nsigma TOF"); + O2_DEFINE_CONFIGURABLE(ITSProtonselection, bool, false, "flag for ITS proton nsigma selection"); + O2_DEFINE_CONFIGURABLE(nsigmaCutITSProton, float, 3, "proton nsigma ITS"); + O2_DEFINE_CONFIGURABLE(dcaxymax, float, 999.f, "maximum dcaxy of tracks"); + O2_DEFINE_CONFIGURABLE(dcazmax, float, 999.f, "maximum dcaz of tracks"); + O2_DEFINE_CONFIGURABLE(enablePtDepDCAxy, bool, false, "Enable pT-dependent DCAxy cut: |DCAxy| < a + b/pT"); + O2_DEFINE_CONFIGURABLE(dcaXyConst, float, 0.004f, "Constant term 'a' for pT-dependent DCAxy cut: |DCAxy| < a + b/pT (cm)"); + O2_DEFINE_CONFIGURABLE(dcaXySlope, float, 0.013f, "Slope term 'b' for pT-dependent DCAxy cut: |DCAxy| < a + b/pT (cm x GeV/c)"); + O2_DEFINE_CONFIGURABLE(itsnclusters, int, 5, "minimum number of ITS clusters for tracks"); + O2_DEFINE_CONFIGURABLE(tpcncrossedrows, int, 80, "minimum number of TPC crossed rows for tracks"); + O2_DEFINE_CONFIGURABLE(tpcnclusters, int, 50, "minimum number of TPC clusters found"); + O2_DEFINE_CONFIGURABLE(chi2pertpccluster, float, 2.5, "maximum Chi2 / cluster for the TPC track segment"); + O2_DEFINE_CONFIGURABLE(chi2peritscluster, float, 36, "maximum Chi2 / cluster for the ITS track segment"); O2_DEFINE_CONFIGURABLE(cfgEstimatorBitMask, uint16_t, 0, "BitMask for multiplicity estimators to be included in the CFMultSet tables."); + O2_DEFINE_CONFIGURABLE(cfgEfficiencyMultiplicity, std::string, "", "Multiplicity efficiency (RecoAll / MC): CCDB path or local ROOT file with a 4D ccdb_object (eta, pT, multiplicity, z-vtx); empty disables CFCollisionsExtra output"); + O2_DEFINE_CONFIGURABLE(cfgLocalEfficiency, int, 0, "0 = CCDB efficiency, 1 = local ROOT efficiency"); + O2_DEFINE_CONFIGURABLE(cfgMultiplicityTrackBitMask, uint16_t, 0, "Required track-type bits for corrected multiplicity; match cfgTrackBitMask used to produce the efficiency (0 = all stored tracks)"); + // Filters and input definitions Filter collisionZVtxFilter = nabs(aod::collision::posZ) < cfgCutVertex; Filter collisionVertexTypeFilter = (cfgCollisionFlags == 0) || ((aod::collision::flags & cfgCollisionFlags) == cfgCollisionFlags); @@ -114,11 +131,12 @@ struct FilterCF { Filter mcCollisionFilter = nabs(aod::mccollision::posZ) < cfgCutVertex; OutputObj yields{TH3F("yields", "centrality vs pT vs eta", 100, 0, 100, 40, 0, 20, 100, -2, 2)}; - OutputObj etaphi{TH3F("etaphi", "centrality vs eta vs phi", 100, 0, 100, 100, -2, 2, 200, 0, 2 * M_PI)}; + OutputObj etaphi{TH3F("etaphi", "centrality vs eta vs phi", 100, 0, 100, 100, -2, 2, 200, 0, o2::constants::math::TwoPI)}; HistogramRegistry registrytrackQA{"TrackQA", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; Produces outputCollisions; + Produces outputCollisionsExtra; Produces outputTracks; Produces outputMcCollisionLabels; @@ -133,14 +151,55 @@ struct FilterCF { Produces outputMcParticleRefs; Produces outputMultSets; - std::vector multiplicities{}; + std::vector multiplicities; + + // Own local histograms independently of their input file. CCDB owns its objects. + std::unique_ptr localMultiplicityEfficiency; + THn* mEfficiency = nullptr; + static constexpr int MultiplicityEfficiencyDimensions = 4; // persistent caches std::vector mcReconstructedCache; std::vector mcParticleLabelsCache; - void init(InitContext&) + void init(InitContext& initContext) { + if (!cfgEfficiencyMultiplicity.value.empty()) { + bool processTracksEnabled = false; + if (!o2::common::core::getTaskOptionValue(initContext, "multiplicity-selector", "processTracks", processTracksEnabled, false)) { + LOGF(fatal, "Could not determine whether MultiplicitySelector::processTracks is enabled"); + } + if (!processTracksEnabled) { + LOGF(fatal, "Efficiency-corrected multiplicity requires MultiplicitySelector::processTracks"); + } + if (cfgLocalEfficiency != 0 && cfgLocalEfficiency != 1) { + LOGF(fatal, "cfgLocalEfficiency must be 0 (CCDB) or 1 (local ROOT file)"); + } + if (cfgMultiplicityTrackBitMask > std::numeric_limits::max()) { + LOGF(fatal, "cfgMultiplicityTrackBitMask must fit the 8-bit track type"); + } + if (cfgLocalEfficiency == 1) { + std::unique_ptr file(TFile::Open(cfgEfficiencyMultiplicity.value.c_str(), "READ")); + if (!file) { + LOGF(fatal, "Could not open multiplicity efficiency file %s", cfgEfficiencyMultiplicity.value.c_str()); + return; + } + if (file->IsZombie()) { + LOGF(fatal, "Multiplicity efficiency file %s is invalid", cfgEfficiencyMultiplicity.value.c_str()); + return; + } + auto* efficiency = dynamic_cast(file->Get("ccdb_object")); + if (!efficiency || efficiency->GetNdimensions() != MultiplicityEfficiencyDimensions) { + LOGF(fatal, "Multiplicity efficiency from %s must be a 4D THn with axes (eta, pT, multiplicity, z-vtx)", cfgEfficiencyMultiplicity.value.c_str()); + return; + } + localMultiplicityEfficiency.reset(dynamic_cast(efficiency->Clone())); + } else { + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + } + } if (doprocessTrackQA) { registrytrackQA.add("zvtx", "Z Vertex position; posz (cm); Events", HistType::kTH1F, {{100, -12, 12}}); registrytrackQA.add("eta", "eta distribution; eta; arb. units", HistType::kTH1F, {{100, -2, 2}}); @@ -156,31 +215,38 @@ struct FilterCF { } template - bool keepCollision(TCollision& collision) + bool keepCollision(const TCollision& collision) { bool isMultSelected = false; - if (collision.multiplicity() >= cfgMinMultiplicity) + if (collision.multiplicity() >= cfgMinMultiplicity) { isMultSelected = true; - + } if (cfgTrigger == 0) { return true; - } else if (cfgTrigger == 7) { + } + if (cfgTrigger == 7) { // o2-linter: disable=magic-number (documented legacy trigger-selection code) return isMultSelected && collision.alias_bit(kINT7) && collision.sel7(); - } else if (cfgTrigger == 8) { + } + if (cfgTrigger == 8) { // o2-linter: disable=magic-number (documented legacy trigger-selection code) return isMultSelected && collision.sel8(); - } else if (cfgTrigger == 9) { // relevant only for Pb-Pb + } + if (cfgTrigger == 9) { // relevant only for Pb-Pb; o2-linter: disable=magic-number (documented legacy trigger-selection code) return isMultSelected && collision.sel8() && collision.selection_bit(aod::evsel::kNoSameBunchPileup) && collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) && collision.selection_bit(aod::evsel::kIsGoodITSLayersAll); - } else if (cfgTrigger == 10) { // TVX trigger only (sel8 selection before April, 2024) + } + if (cfgTrigger == 10) { // TVX trigger only (sel8 selection before April, 2024); o2-linter: disable=magic-number (documented legacy trigger-selection code) return isMultSelected && collision.selection_bit(aod::evsel::kIsTriggerTVX); - } else if (cfgTrigger == 11) { // sel8 selection for MC + } + if (cfgTrigger == 11) { // sel8 selection for MC; o2-linter: disable=magic-number (documented legacy trigger-selection code) return isMultSelected && collision.selection_bit(aod::evsel::kIsTriggerTVX) && collision.selection_bit(aod::evsel::kNoTimeFrameBorder); - } else if (cfgTrigger == 12) { // relevant only for Pb-Pb with occupancy cuts and rejection of the collisions which have other events nearby + } + if (cfgTrigger == 12) { // relevant only for Pb-Pb with occupancy cuts and rejection of nearby collisions; o2-linter: disable=magic-number (documented legacy trigger-selection code) int occupancy = collision.trackOccupancyInTimeRange(); - if (occupancy >= cfgMinOcc && occupancy < cfgMaxOcc) + if (occupancy >= cfgMinOcc && occupancy < cfgMaxOcc) { return isMultSelected && collision.sel8() && collision.selection_bit(aod::evsel::kNoSameBunchPileup) && collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) && collision.selection_bit(aod::evsel::kNoCollInTimeRangeStandard) && collision.selection_bit(aod::evsel::kIsGoodITSLayersAll); - else - return false; - } else if (cfgTrigger == 13) { // relevant for pO/OO/NeNe --recommended by Physics Board on 27.01.2026 + } + return false; + } + if (cfgTrigger == 13) { // relevant for pO/OO/NeNe, recommended by Physics Board on 27.01.2026; o2-linter: disable=magic-number (documented legacy trigger-selection code) return isMultSelected && collision.sel8() && collision.selection_bit(aod::evsel::kNoSameBunchPileup) && collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV); } return false; @@ -193,18 +259,18 @@ struct FilterCF { { o2::aod::ITSResponse itsResponse; - if (ITSProtonselection && candidate.pt() <= 0.6 && !(itsResponse.nSigmaITS(candidate) > nsigmaCutITSProton)) { + if (ITSProtonselection && candidate.pt() <= 0.6 && !(itsResponse.nSigmaITS(candidate) > nsigmaCutITSProton)) { // o2-linter: disable=magic-number (established proton PID momentum boundary) return false; } - if (ITSProtonselection && candidate.pt() > 0.6 && candidate.pt() <= 0.8 && !(itsResponse.nSigmaITS(candidate) > nsigmaCutITSProton)) { + if (ITSProtonselection && candidate.pt() > 0.6 && candidate.pt() <= 0.8 && !(itsResponse.nSigmaITS(candidate) > nsigmaCutITSProton)) { // o2-linter: disable=magic-number (established proton PID momentum boundaries) return false; } if (candidate.hasTOF()) { - if (candidate.pt() < 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPCProton) { + if (candidate.pt() < 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPCProton) { // o2-linter: disable=magic-number (established proton PID momentum boundary) return true; } - if (candidate.p() >= 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPCProton && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOFProton) { + if (candidate.p() >= 0.7 && std::abs(candidate.tpcNSigmaPr()) < nsigmaCutTPCProton && std::abs(candidate.tofNSigmaPr()) < nsigmaCutTOFProton) { // o2-linter: disable=magic-number (established proton PID momentum boundary) return true; } } else { @@ -233,11 +299,13 @@ struct FilterCF { if (cfgTrackSelection == 0) { if (track.isGlobalTrack()) { return 1; - } else if (track.isGlobalTrackSDD()) { + } + if (track.isGlobalTrackSDD()) { return 2; } return 0; - } else if (cfgTrackSelection == 1) { + } + if (cfgTrackSelection == 1) { uint8_t trackType = 0; if (track.isGlobalTrack()) { trackType |= kTrackSelected; @@ -258,7 +326,8 @@ struct FilterCF { } } return trackType; - } else if (cfgTrackSelection == 2) { + } + if (cfgTrackSelection == 2) { // o2-linter: disable=magic-number (documented track-selection mode) uint8_t trackType = 0; if constexpr (HasProtonPID::value) { if (track.isGlobalTrack() && (track.itsNCls() >= itsnclusters) && (track.tpcNClsCrossedRows() >= tpcncrossedrows) && selectionPIDProton(track)) { @@ -280,6 +349,66 @@ struct FilterCF { return dcaXyConst + dcaXySlope / pt; // a + b/pT } + THn* loadMultiplicityEfficiency(uint64_t timestamp) + { + if (cfgLocalEfficiency == 1) { + return localMultiplicityEfficiency.get(); + } + if (!mEfficiency || !ccdb->isCachedObjectValid(cfgEfficiencyMultiplicity.value, timestamp)) { + mEfficiency = ccdb->getForTimeStamp>(cfgEfficiencyMultiplicity.value, timestamp); + } + if (!mEfficiency || mEfficiency->GetNdimensions() != MultiplicityEfficiencyDimensions) { + LOGF(fatal, "Multiplicity efficiency from %s must be a 4D THn with axes (eta, pT, multiplicity, z-vtx)", cfgEfficiencyMultiplicity.value.c_str()); + } + return mEfficiency; + } + + template + float getCorrectedMultiplicity(const TCollision& collision, const TTracks& tracks, uint64_t timestamp) + { + auto* efficiency = loadMultiplicityEfficiency(timestamp); + double correctedMultiplicity = 0.; + size_t skippedTracks = 0; + for (const auto& track : tracks) { + // Match the tracks written by the corresponding data/MC producer path. + if (!isTrackSelected(track, true)) { + continue; + } + // The map contains RecoAll / MC, not inverse-efficiency weights. + // Keep the original estimator as the map coordinate, including for centrality. + const std::array values{track.eta(), track.pt(), collision.multiplicity(), collision.posZ()}; + const double eff = efficiency->GetBinContent(efficiency->GetBin(values.data())); + if (!std::isfinite(eff) || eff <= 0.) { + ++skippedTracks; + continue; + } + correctedMultiplicity += 1. / eff; + } + if (cfgVerbosity > 0 && skippedTracks > 0) { + LOGF(warning, "Skipped %zu tracks with invalid efficiency while correcting collision %lld", skippedTracks, static_cast(collision.globalIndex())); + } + if (!std::isfinite(correctedMultiplicity) || correctedMultiplicity > std::numeric_limits::max()) { + LOGF(fatal, "Corrected multiplicity cannot be represented as a float: %g", correctedMultiplicity); + } + return static_cast(correctedMultiplicity); + } + + template + bool isTrackSelected(const TTrack& track, bool checkTrackBitMask = false) + { + const float maxDCAxy = getMaxDCAxy(track.pt()); + if (std::abs(track.dcaXY()) > maxDCAxy || std::abs(track.dcaZ()) > dcazmax) { + return false; + } + if (checkTrackBitMask) { + const auto mask = static_cast(cfgMultiplicityTrackBitMask.value); + if (mask != 0 && (getTrackType(track) & mask) != mask) { + return false; + } + } + return true; + } + template using HasMultTables = decltype(std::declval().multNTracksPV()); @@ -299,33 +428,42 @@ struct FilterCF { auto bc = collision.template bc_as(); outputCollisions(bc.runNumber(), collision.posZ(), collision.multiplicity(), bc.timestamp()); + if (!cfgEfficiencyMultiplicity.value.empty()) { + outputCollisionsExtra(getCorrectedMultiplicity(collision, tracks, bc.timestamp())); + } if constexpr (std::experimental::is_detected::value) { multiplicities.clear(); - if (cfgEstimatorBitMask & aod::cfmultset::CentFT0C) + if (cfgEstimatorBitMask & aod::cfmultset::CentFT0C) { multiplicities.push_back(collision.centFT0C()); - if (cfgEstimatorBitMask & aod::cfmultset::MultFV0A) + } + if (cfgEstimatorBitMask & aod::cfmultset::MultFV0A) { multiplicities.push_back(collision.multFV0A()); - if (cfgEstimatorBitMask & aod::cfmultset::MultNTracksPV) + } + if (cfgEstimatorBitMask & aod::cfmultset::MultNTracksPV) { multiplicities.push_back(collision.multNTracksPV()); - if (cfgEstimatorBitMask & aod::cfmultset::MultNTracksGlobal) + } + if (cfgEstimatorBitMask & aod::cfmultset::MultNTracksGlobal) { multiplicities.push_back(collision.multNTracksGlobal()); - if (cfgEstimatorBitMask & aod::cfmultset::CentFT0M) + } + if (cfgEstimatorBitMask & aod::cfmultset::CentFT0M) { multiplicities.push_back(collision.centFT0M()); + } outputMultSets(multiplicities); } - if (cfgTransientTables) + if (cfgTransientTables) { outputCollRefs(collision.globalIndex()); - for (auto& track : tracks) { - float maxDCAxy = getMaxDCAxy(track.pt()); - if ((std::abs(track.dcaXY()) > maxDCAxy) || (std::abs(track.dcaZ()) > dcazmax)) { + } + for (const auto& track : tracks) { + if (!isTrackSelected(track)) { continue; } outputTracks(outputCollisions.lastIndex(), track.pt(), track.eta(), track.phi(), track.sign(), getTrackType(track)); - if (cfgTransientTables) + if (cfgTransientTables) { outputTrackRefs(collision.globalIndex(), track.globalIndex()); + } yields->Fill(collision.multiplicity(), track.pt(), track.eta()); etaphi->Fill(collision.multiplicity(), track.eta(), track.phi()); @@ -360,8 +498,7 @@ struct FilterCF { if (!track.isGlobalTrack()) { continue; // trackQA for global tracks only } - float maxDCAxy = getMaxDCAxy(track.pt()); - if ((std::abs(track.dcaXY()) > maxDCAxy) || (std::abs(track.dcaZ()) > dcazmax)) { + if (!isTrackSelected(track)) { continue; } registrytrackQA.fill(HIST("eta"), track.eta()); @@ -371,10 +508,12 @@ struct FilterCF { registrytrackQA.fill(HIST("tpcxrows"), track.tpcNClsCrossedRows()); registrytrackQA.fill(HIST("tpcnclst"), track.tpcNClsFound()); registrytrackQA.fill(HIST("itsnclst"), track.itsNCls()); - if (track.tpcNClsFound() > 0) + if (track.tpcNClsFound() > 0) { registrytrackQA.fill(HIST("chi2tpc"), track.tpcChi2NCl()); - if (track.itsNCls() > 0) + } + if (track.itsNCls() > 0) { registrytrackQA.fill(HIST("chi2its"), track.itsChi2NCl()); + } } } PROCESS_SWITCH(FilterCF, processTrackQA, "Process track QA", false); @@ -401,8 +540,11 @@ struct FilterCF { mcParticleLabelsCache.push_back(-1); } + std::vector bestRecoCollisionIndices(mcCollisions.size(), -1); + std::vector bestRecoCollisionNContrib(mcCollisions.size(), -1); + // PASS 1 on collisions: check which particles are kept - for (auto& collision : allCollisions) { + for (const auto& collision : allCollisions) { auto groupedTracks = tracks.sliceBy(perCollision, collision.globalIndex()); if (cfgVerbosity > 0) { LOGF(info, "processMC: Tracks for collision %d: %d | Vertex: %.1f (%d) | INT7: %d", collision.globalIndex(), groupedTracks.size(), collision.posZ(), collision.flags(), collision.sel7()); @@ -412,14 +554,20 @@ struct FilterCF { continue; } - for (auto& track : groupedTracks) { + const auto mcCollisionId = collision.mcCollisionId(); + if (mcCollisionId >= 0 && mcCollisionId < static_cast(bestRecoCollisionIndices.size()) && collision.numContrib() > bestRecoCollisionNContrib[mcCollisionId]) { + bestRecoCollisionNContrib[mcCollisionId] = collision.numContrib(); + bestRecoCollisionIndices[mcCollisionId] = collision.globalIndex(); + } + + for (const auto& track : groupedTracks) { if (track.has_mcParticle()) { mcReconstructedCache[track.mcParticleId()] = true; } } } - for (auto& mcCollision : mcCollisions) { + for (const auto& mcCollision : mcCollisions) { auto particles = allParticles.sliceBy(perMcCollision, mcCollision.globalIndex()); if (cfgVerbosity > 0) { @@ -428,11 +576,11 @@ struct FilterCF { // Store selected MC particles and MC collisions int multiplicity = 0; - for (auto& particle : particles) { + for (const auto& particle : particles) { int8_t sign = 0; TParticlePDG* pdgparticle = pdg->GetParticle(particle.pdgCode()); if (pdgparticle != nullptr) { - sign = (pdgparticle->Charge() > 0) ? 1.0 : ((pdgparticle->Charge() < 0) ? -1.0 : 0.0); + sign = (pdgparticle->Charge() > 0) ? 1 : ((pdgparticle->Charge() < 0) ? -1 : 0); } bool special = !cfgMcSpecialPDGs->empty() && std::find(cfgMcSpecialPDGs->begin(), cfgMcSpecialPDGs->end(), particle.pdgCode()) != cfgMcSpecialPDGs->end(); @@ -450,10 +598,11 @@ struct FilterCF { } // NOTE using "outputMcCollisions.lastIndex()+1" here to allow filling of outputMcCollisions *after* the loop - outputMcParticles(outputMcCollisions.lastIndex() + 1, truncateFloatFraction(particle.pt(), FLOAT_PRECISION), truncateFloatFraction(particle.eta(), FLOAT_PRECISION), - truncateFloatFraction(particle.phi(), FLOAT_PRECISION), sign, particle.pdgCode(), flags); - if (cfgTransientTables) + outputMcParticles(outputMcCollisions.lastIndex() + 1, truncateFloatFraction(particle.pt(), kFloatPrecision), truncateFloatFraction(particle.eta(), kFloatPrecision), + truncateFloatFraction(particle.phi(), kFloatPrecision), sign, particle.pdgCode(), flags); + if (cfgTransientTables) { outputMcParticleRefs(outputMcCollisions.lastIndex() + 1, particle.globalIndex()); + } // relabeling array mcParticleLabelsCache[particle.globalIndex()] = outputMcParticles.lastIndex(); @@ -464,7 +613,7 @@ struct FilterCF { } // PASS 2 on collisions: store collisions and tracks - for (auto& collision : allCollisions) { + for (const auto& collision : allCollisions) { auto groupedTracks = tracks.sliceBy(perCollision, collision.globalIndex()); if (cfgVerbosity > 0) { LOGF(info, "processMC: Tracks for collision %d: %d | Vertex: %.1f (%d) | INT7: %d", collision.globalIndex(), groupedTracks.size(), collision.posZ(), collision.flags(), collision.sel7()); @@ -477,27 +626,39 @@ struct FilterCF { auto bc = collision.template bc_as(); // NOTE works only when we store all MC collisions (as we do here) outputCollisions(bc.runNumber(), collision.posZ(), collision.multiplicity(), bc.timestamp()); - outputMcCollisionLabels(collision.mcCollisionId()); + if (!cfgEfficiencyMultiplicity.value.empty()) { + outputCollisionsExtra(getCorrectedMultiplicity(collision, groupedTracks, bc.timestamp())); + } + + const auto mcCollisionId = collision.mcCollisionId(); + const bool bestRecoCollision = mcCollisionId >= 0 && mcCollisionId < static_cast(bestRecoCollisionIndices.size()) && bestRecoCollisionIndices[mcCollisionId] == collision.globalIndex(); + outputMcCollisionLabels(mcCollisionId, bestRecoCollision); if constexpr (std::experimental::is_detected::value) { multiplicities.clear(); - if (cfgEstimatorBitMask & aod::cfmultset::CentFT0C) + if (cfgEstimatorBitMask & aod::cfmultset::CentFT0C) { multiplicities.push_back(collision.centFT0C()); - if (cfgEstimatorBitMask & aod::cfmultset::MultFV0A) + } + if (cfgEstimatorBitMask & aod::cfmultset::MultFV0A) { multiplicities.push_back(collision.multFV0A()); - if (cfgEstimatorBitMask & aod::cfmultset::MultNTracksPV) + } + if (cfgEstimatorBitMask & aod::cfmultset::MultNTracksPV) { multiplicities.push_back(collision.multNTracksPV()); - if (cfgEstimatorBitMask & aod::cfmultset::MultNTracksGlobal) + } + if (cfgEstimatorBitMask & aod::cfmultset::MultNTracksGlobal) { multiplicities.push_back(collision.multNTracksGlobal()); - if (cfgEstimatorBitMask & aod::cfmultset::CentFT0M) + } + if (cfgEstimatorBitMask & aod::cfmultset::CentFT0M) { multiplicities.push_back(collision.centFT0M()); + } outputMultSets(multiplicities); } - if (cfgTransientTables) + if (cfgTransientTables) { outputCollRefs(collision.globalIndex()); + } - for (auto& track : groupedTracks) { + for (const auto& track : groupedTracks) { int mcParticleId = track.mcParticleId(); if (mcParticleId >= 0) { mcParticleId = mcParticleLabelsCache[track.mcParticleId()]; @@ -507,8 +668,9 @@ struct FilterCF { } outputTracks(outputCollisions.lastIndex(), truncateFloatFraction(track.pt()), truncateFloatFraction(track.eta()), truncateFloatFraction(track.phi()), track.sign(), getTrackType(track)); outputTrackLabels(mcParticleId); - if (cfgTransientTables) + if (cfgTransientTables) { outputTrackRefs(collision.globalIndex(), track.globalIndex()); + } yields->Fill(collision.multiplicity(), track.pt(), track.eta()); etaphi->Fill(collision.multiplicity(), track.eta(), track.phi()); @@ -522,7 +684,7 @@ struct FilterCF { using McCollisionsWithHepMC = soa::Join; void processMC(McCollisionsWithHepMC const& mcCollisions, aod::McParticles const& allParticles, soa::Join const& allCollisions, - soa::Filtered> const& tracks, + soa::Filtered> const& tracks, aod::BCsWithTimestamps const& bcs) { processMCT(mcCollisions, allParticles, allCollisions, tracks, bcs); @@ -541,7 +703,7 @@ struct FilterCF { void processMCMults(McCollisionsWithHepMC const& mcCollisions, aod::McParticles const& allParticles, soa::Join const& allCollisions, - soa::Filtered> const& tracks, + soa::Filtered> const& tracks, aod::BCsWithTimestamps const& bcs) { processMCT(mcCollisions, allParticles, allCollisions, tracks, bcs); @@ -552,16 +714,20 @@ struct FilterCF { void processMCGen(McCollisionsWithHepMC::iterator const& mcCollision, aod::McParticles const& particles) { float multiplicity = 0.0f; - for (auto& particle : particles) { - if (!particle.isPhysicalPrimary() || std::abs(particle.eta()) > cfgCutMCEta || particle.pt() < cfgCutMCPt) + for (const auto& particle : particles) { + if (!particle.isPhysicalPrimary() || std::abs(particle.eta()) > cfgCutMCEta || particle.pt() < cfgCutMCPt) { continue; + } int8_t sign = 0; - if (TParticlePDG* pdgparticle = pdg->GetParticle(particle.pdgCode())) - if ((sign = pdgparticle->Charge()) != 0) + if (TParticlePDG* pdgparticle = pdg->GetParticle(particle.pdgCode())) { + sign = static_cast(pdgparticle->Charge()); + if (sign != 0) { multiplicity += 1.0f; - outputMcParticles(outputMcCollisions.lastIndex() + 1, truncateFloatFraction(particle.pt(), FLOAT_PRECISION), - truncateFloatFraction(particle.eta(), FLOAT_PRECISION), - truncateFloatFraction(particle.phi(), FLOAT_PRECISION), + } + } + outputMcParticles(outputMcCollisions.lastIndex() + 1, truncateFloatFraction(particle.pt(), kFloatPrecision), + truncateFloatFraction(particle.eta(), kFloatPrecision), + truncateFloatFraction(particle.phi(), kFloatPrecision), sign, particle.pdgCode(), particle.flags()); } outputMcCollisions(mcCollision.posZ(), multiplicity); @@ -573,8 +739,8 @@ struct FilterCF { struct MultiplicitySelector { Produces output; - O2_DEFINE_CONFIGURABLE(cfgCutPt, float, 0.5f, "Minimal pT for tracks") - O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPt, float, 0.5f, "Minimal pT for tracks"); + O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks"); Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPt); Filter trackSelection = (requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t)true); @@ -623,7 +789,7 @@ struct MultiplicitySelector { void processFT0M(aod::CentFT0Ms const& centralities) { - for (auto& c : centralities) { + for (const auto& c : centralities) { output(c.centFT0M()); } } @@ -631,7 +797,7 @@ struct MultiplicitySelector { void processFT0C(aod::CentFT0Cs const& centralities) { - for (auto& c : centralities) { + for (const auto& c : centralities) { output(c.centFT0C()); } } @@ -639,7 +805,7 @@ struct MultiplicitySelector { void processFT0CVariant1(aod::CentFT0CVariant1s const& centralities) { - for (auto& c : centralities) { + for (const auto& c : centralities) { output(c.centFT0CVariant1()); } } @@ -647,7 +813,7 @@ struct MultiplicitySelector { void processFT0CVariant2(aod::CentFT0CVariant2s const& centralities) { - for (auto& c : centralities) { + for (const auto& c : centralities) { output(c.centFT0CVariant2()); } } @@ -655,7 +821,7 @@ struct MultiplicitySelector { void processFT0A(aod::CentFT0As const& centralities) { - for (auto& c : centralities) { + for (const auto& c : centralities) { output(c.centFT0A()); } } @@ -663,7 +829,7 @@ struct MultiplicitySelector { void processCentNGlobal(aod::CentNGlobals const& centralities) { - for (auto& c : centralities) { + for (const auto& c : centralities) { output(c.centNGlobal()); } } @@ -671,7 +837,7 @@ struct MultiplicitySelector { void processRun2V0M(aod::CentRun2V0Ms const& centralities) { - for (auto& c : centralities) { + for (const auto& c : centralities) { output(c.centRun2V0M()); } } diff --git a/PWGCF/Tasks/correlations.cxx b/PWGCF/Tasks/correlations.cxx index f8dce2e6257..46d372b88ae 100644 --- a/PWGCF/Tasks/correlations.cxx +++ b/PWGCF/Tasks/correlations.cxx @@ -13,6 +13,8 @@ /// \brief task for the correlation calculations with CF-filtered tracks for O2 analysis /// \author Jan Fiete Grosse-Oetringhaus , Jasper Parkkila +// o2-linter: disable=name/workflow-file (preserve the established workflow filename and executable name) + #include "PWGCF/Core/CorrelationContainer.h" #include "PWGCF/Core/PairCuts.h" #include "PWGCF/DataModel/CorrelationsDerived.h" @@ -26,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -45,7 +48,6 @@ #include #include #include -#include #include #include @@ -71,7 +73,7 @@ using namespace o2::framework; using namespace o2::framework::expressions; using namespace constants::math; -#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; // NOLINT(bugprone-macro-parentheses) // NOTE This is a nice idea but will again make it impossible to use subwagon configurations... // namespace o2::aod @@ -84,7 +86,7 @@ using namespace constants::math; // cfcorreff::Correction); // } // namespace o2::aod -static constexpr float kCfgPairCutDefaults[1][5] = {{-1, -1, -1, -1, -1}}; +static constexpr std::array, 1> kCfgPairCutDefaults = {{{-1, -1, -1, -1, -1}}}; // o2-linter: disable=name/constexpr-constant (preserve the established identifier) struct CorrelationTask { SliceCache cache; @@ -105,15 +107,17 @@ struct CorrelationTask { O2_DEFINE_CONFIGURABLE(cfgLocalEfficiency, int, 0, "0 = OFF and 1 = ON for local efficiency"); O2_DEFINE_CONFIGURABLE(cfgDropStepRECO, bool, false, "choice to drop step RECO if efficiency correction is used") O2_DEFINE_CONFIGURABLE(cfgCentBinsForMC, int, 0, "0 = OFF and 1 = ON for data like multiplicity/centrality bins for MC steps"); + O2_DEFINE_CONFIGURABLE(cfgRequireRecoCollision, int, 1, "0 = all generated collisions; 1 = only generated collisions with exactly 1 reconstructed collision; 2 = select reconstructed collision with largest number of contributors per generated collision") O2_DEFINE_CONFIGURABLE(cfgTrackBitMask, uint16_t, 0, "BitMask for track selection systematics; refer to the enum TrackSelectionCuts in filtering task"); O2_DEFINE_CONFIGURABLE(cfgMultCorrelationsMask, uint16_t, 0, "Selection bitmask for the multiplicity correlations. This should match the filter selection cfgEstimatorBitMask.") O2_DEFINE_CONFIGURABLE(cfgMultCutFormula, std::string, "", "Multiplicity correlations cut formula. A result greater than zero results in accepted event. Parameters: [cFT0C] FT0C centrality, [mFV0A] V0A multiplicity, [mGlob] global track multiplicity, [mPV] PV track multiplicity, [cFT0M] FT0M centrality") // Suggested values: Photon: 0.004; K0 and Lambda: 0.005 - Configurable> cfgPairCut{"cfgPairCut", {kCfgPairCutDefaults[0], 5, {"Photon", "K0", "Lambda", "Phi", "Rho"}}, "Pair cuts on various particles"}; + Configurable> cfgPairCut{"cfgPairCut", {kCfgPairCutDefaults.front().data(), 5, {"Photon", "K0", "Lambda", "Phi", "Rho"}}, "Pair cuts on various particles"}; O2_DEFINE_CONFIGURABLE(cfgEfficiencyTrigger, std::string, "", "CCDB path to efficiency object for trigger particles") O2_DEFINE_CONFIGURABLE(cfgEfficiencyAssociated, std::string, "", "CCDB path to efficiency object for associated particles") + O2_DEFINE_CONFIGURABLE(cfgUseRun3MagField, bool, false, "false: Run 2 GRPObject; true: Run 3 GRPMagField") O2_DEFINE_CONFIGURABLE(cfgNoMixedEvents, int, 5, "Number of mixed events per event") O2_DEFINE_CONFIGURABLE(cfgRejectMixedPhiProngEvents, bool, true, "Reject associated hadrons from either mixed-phi prong event") @@ -173,7 +177,7 @@ struct CorrelationTask { std::vector p2indexCache; std::unique_ptr multCutFormula; - std::array multCutFormulaParamIndex; + std::array multCutFormulaParamIndex{}; struct Config { bool mPairCuts = false; @@ -185,7 +189,9 @@ struct CorrelationTask { HistogramRegistry registry{"registry"}; PairCuts mPairCuts; - Service ccdb; + Service ccdb{}; + int mCachedRunNumber{-1}; // cached run number for magnetic field -- to avoid re-fetching the magnetic field for the same run, assuming that the magnetic field remains the same for the same run + int mCachedMagField{0}; // cached magnetic field --reduces number of calls to the CCDB using AodCollisions = soa::Filtered>; using AodTracks = soa::Filtered>; @@ -193,15 +199,27 @@ struct CorrelationTask { using DerivedCollisions = soa::Filtered; using DerivedTracks = soa::Filtered; + enum RecoCollisionSelection { + AllGeneratedCollisions = 0, + RequireOneRecoCollision, + RequireBestRecoCollision + }; + void init(o2::framework::InitContext&) { + if (cfgRequireRecoCollision < 0 || cfgRequireRecoCollision > RecoCollisionSelection::RequireBestRecoCollision) { + LOGF(fatal, "Unsupported cfgRequireRecoCollision=%d; use 0 (no reco. collision required), 1 (exactly one reco. collision required), 2 (at least one. reco, and best reco. collision selected)", cfgRequireRecoCollision.value); + } if (doprocessSame2ProngDerivedML || doprocessSame2Prong2ProngML || doprocessMixed2ProngDerivedML || doprocessMixed2Prong2ProngML || doprocessMCEfficiency2ProngML || doprocessMCReflection2ProngML) { - if (cfgPtDepMLbkg->empty() || cfgPtCentDepMLbkgSel->empty()) + if (cfgPtDepMLbkg->empty() || cfgPtCentDepMLbkgSel->empty()) { LOGF(fatal, "cfgPtDepMLbkg or cfgPtCentDepMLbkgSel can not be empty when ML 2-prong selections are used."); - if (cfgPtDepMLbkg->size() != cfgPtCentDepMLbkgSel->size()) + } + if (cfgPtDepMLbkg->size() != cfgPtCentDepMLbkgSel->size()) { LOGF(fatal, "cfgPtDepMLbkg and cfgPtCentDepMLbkgSel must be same size."); - if (!cfgPtCentDepMLpromptSel->empty() && cfgPtCentDepMLpromptSel->size() != cfgPtDepMLbkg->size()) + } + if (!cfgPtCentDepMLpromptSel->empty() && cfgPtCentDepMLpromptSel->size() != cfgPtDepMLbkg->size()) { LOGF(fatal, "cfgPtDepMLbkg and cfgPtCentDepMLpromptSel must be same size."); + } } registry.add("yields", "multiplicity/centrality vs pT vs eta", {HistType::kTH3F, {{100, 0, 100, "/multiplicity/centrality"}, {40, 0, 20, "p_{T}"}, {100, -2, 2, "#eta"}}}); registry.add("etaphi", "multiplicity/centrality vs eta vs phi", {HistType::kTH3F, {{100, 0, 100, "multiplicity/centrality"}, {100, -2, 2, "#eta"}, {200, 0, o2::constants::math::TwoPI, "#varphi"}}}); @@ -224,19 +242,25 @@ struct CorrelationTask { registry.add("invMassReflected", "2-prong invariant mass (GeV/c^2)", {HistType::kTH3F, {axisSpecMass, axisPtTrigger, axisMultiplicity}}); } if (doprocessSameDerivedMultSet) { - if (cfgMultCorrelationsMask == 0) + if (cfgMultCorrelationsMask == 0) { LOGF(fatal, "cfgMultCorrelationsMask can not be 0 when MultSet process functions are in use."); + } std::vector multAxes; - if (cfgMultCorrelationsMask & aod::cfmultset::CentFT0C) + if (cfgMultCorrelationsMask & aod::cfmultset::CentFT0C) { multAxes.emplace_back(axisMultCorrCent, "FT0C centrality"); - if (cfgMultCorrelationsMask & aod::cfmultset::MultFV0A) + } + if (cfgMultCorrelationsMask & aod::cfmultset::MultFV0A) { multAxes.emplace_back(axisMultCorrV0, "V0A multiplicity"); - if (cfgMultCorrelationsMask & aod::cfmultset::MultNTracksPV) + } + if (cfgMultCorrelationsMask & aod::cfmultset::MultNTracksPV) { multAxes.emplace_back(axisMultCorrMult, "Nch PV"); - if (cfgMultCorrelationsMask & aod::cfmultset::MultNTracksGlobal) + } + if (cfgMultCorrelationsMask & aod::cfmultset::MultNTracksGlobal) { multAxes.emplace_back(axisMultCorrMult, "Nch Global"); - if (cfgMultCorrelationsMask & aod::cfmultset::CentFT0M) + } + if (cfgMultCorrelationsMask & aod::cfmultset::CentFT0M) { multAxes.emplace_back(axisMultCorrCent, "FT0M centrality"); + } registry.add("multCorrelations", "Multiplicity correlations", {HistType::kTHnSparseF, multAxes}); } registry.add("multiplicity", "event multiplicity", {HistType::kTH1F, {{1000, 0, 100, "/multiplicity/centrality"}}}); @@ -302,10 +326,12 @@ struct CorrelationTask { userAxis.emplace_back(axisInvMass, "m (GeV/c^2)"); userMixingAxis.emplace_back(axisInvMass, "m (GeV/c^2)"); } - if (doprocessSame2Prong2Prong || doprocessSame2Prong2ProngML) + if (doprocessSame2Prong2Prong || doprocessSame2Prong2ProngML) { userAxis.emplace_back(axisInvMass, "m (GeV/c^2)"); - if (doprocessMixed2Prong2Prong || doprocessMixed2Prong2ProngML) + } + if (doprocessMixed2Prong2Prong || doprocessMixed2Prong2ProngML) { userMixingAxis.emplace_back(axisInvMass, "m (GeV/c^2)"); + } same.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, userAxis)); mixed.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, userMixingAxis)); @@ -313,12 +339,14 @@ struct CorrelationTask { same->setTrackEtaCut(cfgCutEta); mixed->setTrackEtaCut(cfgCutEta); - if (!cfgEfficiencyAssociated.value.empty()) + if (!cfgEfficiencyAssociated.value.empty()) { efficiencyAssociatedCache.reserve(512); + } if (doprocessMCEfficiency2Prong || doprocessMCEfficiency2ProngML || doprocessMCReflection2ProngML) { p2indexCache.reserve(16); - if (cfgMcTriggerPDGs->empty()) + if (cfgMcTriggerPDGs->empty()) { LOGF(fatal, "At least one PDG code in {} is to be selected to process 2-prong efficiency.", cfgMcTriggerPDGs.name); + } } // o2-ccdb-upload -p Users/jgrosseo/correlations/LHC15o -f /tmp/correction_2011_global.root -k correction @@ -331,21 +359,32 @@ struct CorrelationTask { ccdb->setCreatedNotAfter(now); // TODO must become global parameter from the train creation time } - int getMagneticField(uint64_t timestamp) + int getMagneticField(int runNumber, uint64_t timestamp) { - // TODO done only once (and not per run). Will be replaced by CCDBConfigurable - static o2::parameters::GRPObject* grpo = nullptr; - // static o2::parameters::GRPMagField* grpo = nullptr; - if (grpo == nullptr) { - grpo = ccdb->getForTimeStamp("GLO/GRP/GRP", timestamp); - // grpo = ccdb->getForTimeStamp("GLO/Config/GRPMagField", timestamp); + static constexpr const char* kGRPPathRun2 = "GLO/GRP/GRP"; // fixed path for now, can be made into a config + static constexpr const char* kGRPPathRun3 = "GLO/Config/GRPMagField"; // fixed path for now, can be made into a config + + if (runNumber == mCachedRunNumber) { + return mCachedMagField; + } + + if (cfgUseRun3MagField) { + auto* grpmag = ccdb->getForTimeStamp(kGRPPathRun3, timestamp); + if (grpmag == nullptr) { + LOGF(fatal, "Run 3 GRPMagField not found at %s for run %d timestamp %llu", kGRPPathRun3, runNumber, timestamp); + } + mCachedMagField = grpmag->getNominalL3Field(); + } else { + auto* grpo = ccdb->getForTimeStamp(kGRPPathRun2, timestamp); if (grpo == nullptr) { - LOGF(fatal, "GRP object not found for timestamp %llu", timestamp); - return 0; + LOGF(fatal, "Run 2 GRPObject not found at %s for run %d timestamp %llu", kGRPPathRun2, runNumber, timestamp); } - LOGF(info, "Retrieved GRP for timestamp %llu with magnetic field of %d kG", timestamp, grpo->getNominalL3Field()); + mCachedMagField = grpo->getNominalL3Field(); } - return grpo->getNominalL3Field(); + + mCachedRunNumber = runNumber; + LOGF(info, "Run %d: magnetic field %d kG", runNumber, mCachedMagField); + return mCachedMagField; } template @@ -372,8 +411,9 @@ struct CorrelationTask { { registry.fill(HIST("multiplicity"), multiplicity); if constexpr (std::experimental::is_detected::value) { - if (std::popcount(cfgMultCorrelationsMask.value) != static_cast(collision.multiplicities().size())) + if (std::popcount(cfgMultCorrelationsMask.value) != static_cast(collision.multiplicities().size())) { LOGF(fatal, "Multiplicity selections (cfgMultCorrelationsMask = 0x%x) do not match the size of the table column (%ld). The histogram filling relies on the preservation of order.", cfgMultCorrelationsMask.value, collision.multiplicities().size()); + } // need to convert to vec of doubles since THnSparse has no way to fill vec of floats directly std::vector v(collision.multiplicities().begin(), collision.multiplicities().end()); registry.get(HIST("multCorrelations")).get()->Fill(v.data()); @@ -394,21 +434,25 @@ struct CorrelationTask { { for (const auto& track1 : tracks1) { if constexpr (std::experimental::is_detected::value && std::experimental::is_detected::value) { - if (cfgDecayParticleMask != 0 && (cfgDecayParticleMask & (1u << static_cast(track1.decay()))) == 0u) + if (cfgDecayParticleMask != 0 && (cfgDecayParticleMask & (1u << static_cast(track1.decay()))) == 0u) { continue; + } if constexpr (std::experimental::is_detected::value) { - if (!passMLScore(track1)) + if (!passMLScore(track1)) { continue; + } } registry.fill(HIST("invMass"), track1.invMass(), track1.pt(), multiplicity, posZ); for (const auto& track2 : tracks2) { if constexpr (std::experimental::is_detected::value && std::experimental::is_detected::value) { if (doprocessSame2Prong2Prong || doprocessMixed2Prong2Prong || doprocessSame2Prong2ProngML || doprocessMixed2Prong2ProngML) { - if (cfgDecayParticleMask != 0 && (cfgDecayParticleMask & (1u << static_cast(track1.decay()))) == 0u) + if (cfgDecayParticleMask != 0 && (cfgDecayParticleMask & (1u << static_cast(track1.decay()))) == 0u) { continue; + } if constexpr (std::experimental::is_detected::value) { - if (!passMLScore(track2)) + if (!passMLScore(track2)) { continue; + } } if constexpr (std::experimental::is_detected::value) { @@ -437,12 +481,14 @@ struct CorrelationTask { } } // no shared prong for two mothers - if (cfgCorrelationMethod == 1 && track1.decay() != track2.decay()) + if (cfgCorrelationMethod == 1 && track1.decay() != track2.decay()) { continue; - if (cfgCorrelationMethod == 2 && track1.decay() == track2.decay()) + } + if (cfgCorrelationMethod == 2 && track1.decay() == track2.decay()) { // o2-linter: disable=magic-number (value is the established ddbar correlation-method mode) continue; + } registry.fill(HIST("invMassTwoPart"), track1.invMass(), track2.invMass(), track1.pt(), track2.pt(), multiplicity); - registry.fill(HIST("invMassTwoPartDPhi"), track1.invMass(), track2.invMass(), track1.pt(), track2.pt(), TVector2::Phi_0_2pi(track1.phi() - track2.phi() + TMath::Pi() / 2.0) - TMath::Pi() / 2.0); + registry.fill(HIST("invMassTwoPartDPhi"), track1.invMass(), track2.invMass(), track1.pt(), track2.pt(), TVector2::Phi_0_2pi(track1.phi() - track2.phi() + PIHalf) - PIHalf); if (std::abs(track1.phi() - track2.phi()) < constants::math::PI * 0.5) { registry.fill(HIST("invMassTwoPartDEta"), track1.invMass(), track2.invMass(), track1.pt(), track2.pt(), track1.eta() - track2.eta()); } @@ -451,8 +497,9 @@ struct CorrelationTask { } } if constexpr (std::experimental::is_detected::value) { - if (!cfgMcTriggerPDGs->empty() && std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), track1.pdgCode()) == cfgMcTriggerPDGs->end()) + if (!cfgMcTriggerPDGs->empty() && std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), track1.pdgCode()) == cfgMcTriggerPDGs->end()) { continue; + } } registry.fill(HIST("yieldsTrigger"), multiplicity, track1.pt(), track1.eta()); registry.fill(HIST("etaphiTrigger"), multiplicity, track1.eta(), track1.phi()); @@ -461,7 +508,7 @@ struct CorrelationTask { } template - bool fillCollisionAOD(TTarget target, TCollision collision, float multiplicity) + bool fillCollisionAOD(TTarget target, const TCollision& collision, float multiplicity) { target->fillEvent(multiplicity, CorrelationContainer::kCFStepAll); @@ -521,11 +568,13 @@ struct CorrelationTask { template bool passOutlier(CollType const& collision) { - if (cfgMultCutFormula.value.empty()) + if (cfgMultCutFormula.value.empty()) { return true; + } for (uint i = 0; i < aod::cfmultset::NMultiplicityEstimators; ++i) { - if ((cfgMultCorrelationsMask.value & (1u << i)) == 0 || multCutFormulaParamIndex[i] == ~0u) + if ((cfgMultCorrelationsMask.value & (1u << i)) == 0 || multCutFormulaParamIndex[i] == ~0u) { continue; + } auto estIndex = std::popcount(cfgMultCorrelationsMask.value & ((1u << i) - 1)); multCutFormula->SetParameter(multCutFormulaParamIndex[i], collision.multiplicities()[estIndex]); } @@ -535,8 +584,9 @@ struct CorrelationTask { template std::tuple getV0Rapidity(const T& track) { - if constexpr (!std::experimental::is_detected::value) + if constexpr (!std::experimental::is_detected::value) { return {false, 0.0f}; // no decay type, return dummy rapidity + } const auto decayType = track.decay(); float mass = 0.f; @@ -560,7 +610,7 @@ struct CorrelationTask { const float p2 = px * px + py * py + pz * pz; - const float E = std::sqrt(p2 + mass * mass); + const float E = std::sqrt(p2 + mass * mass); // o2-linter: disable=name/function-variable (E is the conventional symbol for particle energy) return {true, 0.5f * std::log((E + pz) / (E - pz))}; } @@ -591,45 +641,52 @@ struct CorrelationTask { if constexpr (std::experimental::is_detected::value) { // If the MC trigger particle is on the trigger PDG code list, we will accept them regardless of their charge. if (!cfgMcTriggerPDGs->empty()) { - if (std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), track1.pdgCode()) == cfgMcTriggerPDGs->end()) + if (std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), track1.pdgCode()) == cfgMcTriggerPDGs->end()) { continue; + } } else { // otherwise check the sign against the configuration if (cfgTriggerCharge != 0) { - if (cfgTriggerCharge * track1.sign() < 0) + if (cfgTriggerCharge * track1.sign() < 0) { continue; + } } else if (track1.sign() == 0) { continue; // reject neutral MC particles } } } else if constexpr (std::experimental::is_detected::value) { // Check reco objects that have the sign attribute. There are no neutrals to deal with. - if (cfgTriggerCharge != 0 && cfgTriggerCharge * track1.sign() < 0) + if (cfgTriggerCharge != 0 && cfgTriggerCharge * track1.sign() < 0) { continue; + } } if constexpr (std::experimental::is_detected::value) { - if (((track1.mcDecay() != aod::cf2prongtrack::D0ToPiK) && (track1.mcDecay() != aod::cf2prongtrack::D0barToKPiExclusive)) || (!cfgPtCentDepMLpromptSel->empty() && (track1.decay() & aod::cf2prongmcpart::Prompt) == 0)) + if (((track1.mcDecay() != aod::cf2prongtrack::D0ToPiK) && (track1.mcDecay() != aod::cf2prongtrack::D0barToKPiExclusive)) || (!cfgPtCentDepMLpromptSel->empty() && (track1.decay() & aod::cf2prongmcpart::Prompt) == 0)) { continue; + } } else if constexpr (std::experimental::is_detected::value) { if (cfgDecayParticleMask != 0 && (cfgDecayParticleMask & (1u << static_cast(track1.decay()))) == 0u) { continue; // skip particles that do not match the decay mask } if (cfgV0RapidityMax > 0) { auto [t, y] = getV0Rapidity(track1); - if (t && std::abs(y) > cfgV0RapidityMax) + if (t && std::abs(y) > cfgV0RapidityMax) { continue; // V0s are not allowed to be outside the rapidity range + } registry.fill(HIST("yvspt"), y, track1.pt()); } } if constexpr (std::experimental::is_detected::value) { - if (track1.cfParticleDaugh0Id() < 0 && track1.cfParticleDaugh1Id() < 0) + if (track1.cfParticleDaugh0Id() < 0 && track1.cfParticleDaugh1Id() < 0) { continue; // these we could not match + } } if constexpr (std::experimental::is_detected::value) { - if (!passMLScore(track1)) + if (!passMLScore(track1)) { continue; + } } // ML selection float triggerWeight = eventWeight; @@ -640,9 +697,9 @@ struct CorrelationTask { } if (cfgMassAxis) { - if constexpr (std::experimental::is_detected::value) + if constexpr (std::experimental::is_detected::value) { target->getTriggerHist()->Fill(step, track1.pt(), multiplicity, posZ, track1.invMass(), triggerWeight); - else if constexpr (std::experimental::is_detected::value) { + } else if constexpr (std::experimental::is_detected::value) { // TParticlePDG *p = pdg->GetParticle(track1.pdgCode()); // target->getTriggerHist()->Fill(step, track1.pt(), multiplicity, posZ, p->Mass(), triggerWeight); target->getTriggerHist()->Fill(step, track1.pt(), multiplicity, posZ, 1.8, triggerWeight); @@ -684,26 +741,31 @@ struct CorrelationTask { } if constexpr (std::experimental::is_detected::value) { // skip those that are specifically chosen to be triggers - if (!cfgMcTriggerPDGs->empty() && std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), track2.pdgCode()) != cfgMcTriggerPDGs->end()) + if (!cfgMcTriggerPDGs->empty() && std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), track2.pdgCode()) != cfgMcTriggerPDGs->end()) { continue; // TODO: fix cases like MC D0-D0 + } } // Daughter track and particle checks if constexpr (std::experimental::is_detected::value) { - if (track2.globalIndex() == track1.cfTrackProng0Id()) // do not correlate daughter tracks of the same event + if (track2.globalIndex() == track1.cfTrackProng0Id()) { // do not correlate daughter tracks of the same event continue; + } } if constexpr (std::experimental::is_detected::value) { - if (track2.globalIndex() == track1.cfTrackProng1Id()) // do not correlate daughter tracks of the same event + if (track2.globalIndex() == track1.cfTrackProng1Id()) { // do not correlate daughter tracks of the same event continue; + } } if constexpr (std::experimental::is_detected::value) { - if (track2.globalIndex() == track1.cfParticleDaugh0Id()) // do not correlate daughter particles of the same event + if (track2.globalIndex() == track1.cfParticleDaugh0Id()) { // do not correlate daughter particles of the same event continue; + } } if constexpr (std::experimental::is_detected::value) { - if (track2.globalIndex() == track1.cfParticleDaugh1Id()) // do not correlate daughter particles of the same event + if (track2.globalIndex() == track1.cfParticleDaugh1Id()) { // do not correlate daughter particles of the same event continue; + } } if constexpr (step <= CorrelationContainer::kCFStepTracked && !std::experimental::is_detected::value) { @@ -714,8 +776,9 @@ struct CorrelationTask { // If decay attributes are found for the second track/particle, we assume 2p-2p correlation if constexpr (std::experimental::is_detected::value) { - if ((((track2.mcDecay()) != aod::cf2prongtrack::D0ToPiK) && ((track2.mcDecay()) != aod::cf2prongtrack::D0barToKPiExclusive)) || (!cfgPtCentDepMLpromptSel->empty() && (track2.decay() & aod::cf2prongmcpart::Prompt) == 0)) + if ((((track2.mcDecay()) != aod::cf2prongtrack::D0ToPiK) && ((track2.mcDecay()) != aod::cf2prongtrack::D0barToKPiExclusive)) || (!cfgPtCentDepMLpromptSel->empty() && (track2.decay() & aod::cf2prongmcpart::Prompt) == 0)) { continue; + } } else if constexpr (std::experimental::is_detected::value) { if (cfgDecayParticleMask != 0 && (cfgDecayParticleMask & (1u << static_cast(track2.decay()))) == 0u) { continue; // skip particles that do not match the decay mask @@ -731,10 +794,12 @@ struct CorrelationTask { } if constexpr (std::experimental::is_detected::value && std::experimental::is_detected::value) { - if (cfgCorrelationMethod == 1 && track1.decay() != track2.decay()) + if (cfgCorrelationMethod == 1 && track1.decay() != track2.decay()) { continue; - if (cfgCorrelationMethod == 2 && track1.decay() == track2.decay()) + } + if (cfgCorrelationMethod == 2 && track1.decay() == track2.decay()) { // o2-linter: disable=magic-number (value is the established ddbar correlation-method mode) continue; + } } if constexpr (std::experimental::is_detected::value) { @@ -771,8 +836,9 @@ struct CorrelationTask { if constexpr (std::experimental::is_detected::value) { // TODO: support for MC D0-D0 case if (cfgAssociatedCharge != 0) { - if (cfgAssociatedCharge * track2.sign() < 0) + if (cfgAssociatedCharge * track2.sign() < 0) { continue; + } } else if (track2.sign() == 0) { // mc particles come in neutrals, need to check explicitly continue; } @@ -807,16 +873,18 @@ struct CorrelationTask { float deltaPhi = RecoDecay::constrainAngle(track1.phi() - track2.phi(), -o2::constants::math::PIHalf); if constexpr (std::experimental::is_detected::value) { - if (!passMLScore(track2)) + if (!passMLScore(track2)) { continue; + } } // ML selection // last param is the weight if (cfgMassAxis && (doprocessSame2Prong2Prong || doprocessMixed2Prong2Prong || doprocessSame2Prong2ProngML || doprocessMixed2Prong2ProngML) && !(doprocessSame2ProngDerived || doprocessSame2ProngDerivedML || doprocessMixed2ProngDerived || doprocessMixed2ProngDerivedML || doprocessMixed2ProngDerivedMixedPhi)) { - if constexpr (std::experimental::is_detected::value && std::experimental::is_detected::value) + if constexpr (std::experimental::is_detected::value && std::experimental::is_detected::value) { target->getPairHist()->Fill(step, track1.eta() - track2.eta(), track2.pt(), track1.pt(), multiplicity, deltaPhi, posZ, track2.invMass(), track1.invMass(), associatedWeight); - else + } else { LOGF(fatal, "Can not fill mass axis without invMass column. \n no mass for two particles"); + } } else if (cfgMassAxis) { if constexpr (std::experimental::is_detected::value) { target->getPairHist()->Fill(step, track1.eta() - track2.eta(), track2.pt(), track1.pt(), multiplicity, deltaPhi, posZ, track1.invMass(), associatedWeight); @@ -847,7 +915,7 @@ struct CorrelationTask { if (cfg.mEfficiencyTrigger == nullptr) { LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgEfficiencyTrigger.value.c_str()); } - LOGF(info, "Loaded efficiency histogram for trigger particles from %s (%p)", cfgEfficiencyTrigger.value.c_str(), (void*)cfg.mEfficiencyTrigger); + LOGF(info, "Loaded efficiency histogram for trigger particles from %s (%p)", cfgEfficiencyTrigger.value.c_str(), static_cast(cfg.mEfficiencyTrigger)); } if (cfgEfficiencyAssociated.value.empty() == false) { if (cfgLocalEfficiency > 0) { @@ -859,7 +927,7 @@ struct CorrelationTask { if (cfg.mEfficiencyAssociated == nullptr) { LOGF(fatal, "Could not load efficiency histogram for associated particles from %s", cfgEfficiencyAssociated.value.c_str()); } - LOGF(info, "Loaded efficiency histogram for associated particles from %s (%p)", cfgEfficiencyAssociated.value.c_str(), (void*)cfg.mEfficiencyAssociated); + LOGF(info, "Loaded efficiency histogram for associated particles from %s (%p)", cfgEfficiencyAssociated.value.c_str(), static_cast(cfg.mEfficiencyAssociated)); } cfg.efficiencyLoaded = true; } @@ -894,7 +962,7 @@ struct CorrelationTask { } registry.fill(HIST("eventcount_same"), -2); fillQA(collision, multiplicity, tracks); - fillCorrelations(same, tracks, tracks, multiplicity, collision.posZ(), getMagneticField(bc.timestamp()), 1.0f); + fillCorrelations(same, tracks, tracks, multiplicity, collision.posZ(), getMagneticField(bc.runNumber(), bc.timestamp()), 1.0f); } PROCESS_SWITCH(CorrelationTask, processSameAOD, "Process same event on AOD", true); @@ -911,16 +979,17 @@ struct CorrelationTask { const auto multiplicity = collision.multiplicity(); int field = 0; if (cfgTwoTrackCut > 0) { - field = getMagneticField(collision.timestamp()); + field = getMagneticField(collision.runNumber(), collision.timestamp()); } int bin = configurableBinningDerived.getBin({collision.posZ(), collision.multiplicity()}); registry.fill(HIST("eventcount_same"), bin); registry.fill(HIST("trackcount_same"), bin, tracks1.size()); - if constexpr (std::experimental::is_detected::value) + if constexpr (std::experimental::is_detected::value) { fillQA(collision, multiplicity, collision.posZ(), tracks1, tracks2); - else + } else { fillQA(collision, multiplicity, tracks1); + } const bool hasEfficiency = (cfg.mEfficiencyAssociated != nullptr || cfg.mEfficiencyTrigger != nullptr); const bool fillReco = !(cfgDropStepRECO && hasEfficiency); @@ -943,8 +1012,9 @@ struct CorrelationTask { void processSameDerivedMultSet(soa::Filtered>::iterator const& collision, soa::Filtered const& tracks) { - if (!passOutlier(collision)) + if (!passOutlier(collision)) { return; + } processSameDerivedT(collision, tracks, tracks); } PROCESS_SWITCH(CorrelationTask, processSameDerivedMultSet, "Process same event on derived data with multiplicity sets", false); @@ -1011,7 +1081,7 @@ struct CorrelationTask { // LOGF(info, "Tracks: %d and %d entries", tracks1.size(), tracks2.size()); - fillCorrelations(mixed, tracks1, tracks2, collision1.centRun2V0M(), collision1.posZ(), getMagneticField(bc.timestamp()), 1.0f / it.currentWindowNeighbours()); + fillCorrelations(mixed, tracks1, tracks2, collision1.centRun2V0M(), collision1.posZ(), getMagneticField(bc.runNumber(), bc.timestamp()), 1.0f / it.currentWindowNeighbours()); } } PROCESS_SWITCH(CorrelationTask, processMixedAOD, "Process mixed events on AOD", false); @@ -1022,8 +1092,9 @@ struct CorrelationTask { auto getMultiplicity = [this](auto& col) { if constexpr (std::experimental::is_detected::value) { - if (!passOutlier(col)) + if (!passOutlier(col)) { return -1.0f; + } } else { (void)this; // fix compile error on unused 'this' capture } @@ -1045,7 +1116,7 @@ struct CorrelationTask { float eventWeight = 1.0f / it.currentWindowNeighbours(); int field = 0; if (cfgTwoTrackCut > 0) { - field = getMagneticField(collision1.timestamp()); + field = getMagneticField(collision1.runNumber(), collision1.timestamp()); } if (cfgVerbosity > 0) { @@ -1197,10 +1268,11 @@ struct CorrelationTask { case -2212: return 2; } - if (std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), pdgCode) != cfgMcTriggerPDGs->end()) + if (std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), pdgCode) != cfgMcTriggerPDGs->end()) { return 4; // NOTE - if changed, the number in processMCEfficiency2Prong needs to be changed too since we skip the getSpecies call - else // The efficiency histogram is hardcoded to contain 5 species. Anything special will have the 4th slot. + } else { // The efficiency histogram is hardcoded to contain 5 species. Anything special will have the 4th slot. return 3; + } } // NOTE SmallGroups includes soa::Filtered always @@ -1211,13 +1283,30 @@ struct CorrelationTask { LOGF(info, "MC collision at vtx-z = %f with %d mc particles and %d reconstructed collisions", mcCollision.posZ(), mcParticles.size(), collisions.size()); } + // Select reconstructed collisions as specified by cfgRequireRecoCollision auto multiplicity = mcCollision.multiplicity(); - if (cfgCentBinsForMC > 0) { + if (cfgRequireRecoCollision > 0) { if (collisions.size() == 0) { return; } - for (const auto& collision : collisions) { - multiplicity = collision.multiplicity(); + if (cfgRequireRecoCollision == RecoCollisionSelection::RequireOneRecoCollision) { // cfgRequireRecoCollision == 1 + if (collisions.size() != 1) { + return; + } + multiplicity = collisions.begin().multiplicity(); + } + if (cfgRequireRecoCollision == RecoCollisionSelection::RequireBestRecoCollision) { // cfgRequireRecoCollision == 2 + bool foundBestCollision = false; + for (const auto& collision : collisions) { + if (collision.bestRecoCollision()) { + multiplicity = collision.multiplicity(); + foundBestCollision = true; + break; + } + } + if (!foundBestCollision) { + return; + } } } // Primaries @@ -1226,7 +1315,11 @@ struct CorrelationTask { same->getTrackHistEfficiency()->Fill(CorrelationContainer::MC, mcParticle.eta(), mcParticle.pt(), getSpecies(mcParticle.pdgCode()), multiplicity, mcCollision.posZ()); } } + const bool useBestCollision = cfgRequireRecoCollision == RecoCollisionSelection::AllGeneratedCollisions || cfgRequireRecoCollision == RecoCollisionSelection::RequireBestRecoCollision; // For cfgRequireRecoCollision == 0 still need to reject split vertices for (const auto& collision : collisions) { + if (useBestCollision && !collision.bestRecoCollision()) { + continue; + } auto groupedTracks = tracks.sliceBy(perCollision, collision.globalIndex()); if (cfgVerbosity > 0) { LOGF(info, " Reconstructed collision at vtx-z = %f", collision.posZ()); @@ -1234,12 +1327,14 @@ struct CorrelationTask { } for (const auto& track : groupedTracks) { - if (cfgTrackBitMask > 0 && (track.trackType() & (uint8_t)cfgTrackBitMask) != (uint8_t)cfgTrackBitMask) + if (cfgTrackBitMask > 0 && (track.trackType() & (uint8_t)cfgTrackBitMask) != (uint8_t)cfgTrackBitMask) { continue; + } if (track.has_cfMCParticle()) { const auto& mcParticle = track.cfMCParticle(); - if ((doprocessMCEfficiency2Prong || doprocessMCEfficiency2ProngML) && std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), mcParticle.pdgCode()) != cfgMcTriggerPDGs->end()) + if ((doprocessMCEfficiency2Prong || doprocessMCEfficiency2ProngML) && std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), mcParticle.pdgCode()) != cfgMcTriggerPDGs->end()) { continue; // properly booked by the 2Prong efficiency function, ignore here + } if (mcParticle.isPhysicalPrimary()) { same->getTrackHistEfficiency()->Fill(CorrelationContainer::RecoPrimaries, mcParticle.eta(), mcParticle.pt(), getSpecies(mcParticle.pdgCode()), multiplicity, mcCollision.posZ()); } @@ -1255,7 +1350,7 @@ struct CorrelationTask { PROCESS_SWITCH(CorrelationTask, processMCEfficiency, "MC: Extract efficiencies", false); template - void processMCEfficiency2ProngT(soa::Filtered::iterator const& mcCollision, soa::Join const& mcParticles, soa::SmallGroups const& collisions, aod::CFTracksWithLabel const&, p2type const& p2tracks, Preslice& perCollision2Prong) + void processMCEfficiency2ProngT(soa::Filtered::iterator const& mcCollision, soa::Join const& mcParticles, soa::SmallGroups const& collisions, aod::CFTracksWithLabel const&, p2type const& p2tracks, Preslice& collision2ProngPreslice) { auto multiplicity = mcCollision.multiplicity(); if (cfgCentBinsForMC > 0) { @@ -1270,68 +1365,81 @@ struct CorrelationTask { p2indexCache.clear(); for (const auto& mcParticle : mcParticles) { if (std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), mcParticle.pdgCode()) != cfgMcTriggerPDGs->end()) { - if ((mcParticle.mcDecay() != aod::cf2prongtrack::D0ToPiK) && (mcParticle.mcDecay() != aod::cf2prongtrack::D0barToKPiExclusive)) + if ((mcParticle.mcDecay() != aod::cf2prongtrack::D0ToPiK) && (mcParticle.mcDecay() != aod::cf2prongtrack::D0barToKPiExclusive)) { continue; // wrong decay channel - if (mcParticle.cfParticleDaugh0Id() < 0 && mcParticle.cfParticleDaugh1Id() < 0) + } + if (mcParticle.cfParticleDaugh0Id() < 0 && mcParticle.cfParticleDaugh1Id() < 0) { continue; // daughters not found + } if constexpr (!reflectionSpec) { - if (cfgPtCentDepMLpromptSel->empty() || (mcParticle.decay() & aod::cf2prongmcpart::Prompt) != 0) + if (cfgPtCentDepMLpromptSel->empty() || (mcParticle.decay() & aod::cf2prongmcpart::Prompt) != 0) { same->getTrackHistEfficiency()->Fill(CorrelationContainer::MC, mcParticle.eta(), mcParticle.pt(), 4, multiplicity, mcCollision.posZ()); + } } p2indexCache.push_back(mcParticle.globalIndex()); } } for (const auto& collision : collisions) { - auto grouped2ProngTracks = p2tracks.sliceBy(perCollision2Prong, collision.globalIndex()); + auto grouped2ProngTracks = p2tracks.sliceBy(collision2ProngPreslice, collision.globalIndex()); for (const auto& p2track : grouped2ProngTracks) { if constexpr (!reflectionSpec) { - if (cfgDecayParticleMask != 0 && (cfgDecayParticleMask & (1u << static_cast(p2track.decay()))) == 0u) + if (cfgDecayParticleMask != 0 && (cfgDecayParticleMask & (1u << static_cast(p2track.decay()))) == 0u) { continue; + } } // Check if the mc particles of the prongs are found. if constexpr (std::experimental::is_detected::value) { - if (!passMLScore(p2track)) + if (!passMLScore(p2track)) { continue; + } } - if constexpr (!reflectionSpec) + if constexpr (!reflectionSpec) { same->getTrackHistEfficiency()->Fill(CorrelationContainer::RecoAll, p2track.eta(), p2track.pt(), 4, multiplicity, mcCollision.posZ()); + } auto fillMC2p = [&](const aod::CFTracksWithLabel::iterator& p) -> bool { - if (!p.has_cfMCParticle()) + if (!p.has_cfMCParticle()) { return false; + } auto m = std::find_if(p2indexCache.begin(), p2indexCache.end(), [&](const auto& t) -> bool { const auto& mcParticle = mcParticles.iteratorAt(t - mcParticles.begin().globalIndex()); return (p.cfMCParticleId() == mcParticle.cfParticleDaugh0Id() || p.cfMCParticleId() == mcParticle.cfParticleDaugh1Id()); }); - if (m == p2indexCache.end()) + if (m == p2indexCache.end()) { return false; + } const auto& mcParticle = mcParticles.iteratorAt(*m - mcParticles.begin().globalIndex()); if constexpr (!reflectionSpec) { - if (!cfgPtCentDepMLpromptSel->empty() && (mcParticle.decay() & aod::cf2prongmcpart::Prompt) == 0) + if (!cfgPtCentDepMLpromptSel->empty() && (mcParticle.decay() & aod::cf2prongmcpart::Prompt) == 0) { return true; // a valid candidate but not a prompt + } same->getTrackHistEfficiency()->Fill(CorrelationContainer::RecoPrimaries, mcParticle.eta(), mcParticle.pt(), 4, multiplicity, mcCollision.posZ()); } else { if ((mcParticle.mcDecay() == aod::cf2prongtrack::D0barToKPiExclusive && (p2track.decay() == aod::cf2prongtrack::D0barToKPiExclusive || p2track.decay() == aod::cf2prongtrack::D0barToKPi)) || - (mcParticle.mcDecay() == aod::cf2prongtrack::D0ToPiK && p2track.decay() == aod::cf2prongtrack::D0ToPiK)) + (mcParticle.mcDecay() == aod::cf2prongtrack::D0ToPiK && p2track.decay() == aod::cf2prongtrack::D0ToPiK)) { registry.fill(HIST("invMassSignal"), p2track.invMass(), p2track.pt(), multiplicity); - else // one particle may be filled into both histograms through duplicates + } else { // one particle may be filled into both histograms through duplicates registry.fill(HIST("invMassReflected"), p2track.invMass(), p2track.pt(), multiplicity); + } } return true; }; if (p2track.has_cfTrackProng0()) { // - if (const auto& p0 = p2track.template cfTrackProng0_as(); fillMC2p(p0)) + if (const auto& p0 = p2track.template cfTrackProng0_as(); fillMC2p(p0)) { continue; + } } if (p2track.has_cfTrackProng1()) { - if (const auto& p1 = p2track.template cfTrackProng1_as(); fillMC2p(p1)) + if (const auto& p1 = p2track.template cfTrackProng1_as(); fillMC2p(p1)) { continue; + } } // fake track - if constexpr (!reflectionSpec) + if constexpr (!reflectionSpec) { same->getTrackHistEfficiency()->Fill(CorrelationContainer::Fake, p2track.eta(), p2track.pt(), 4, multiplicity, mcCollision.posZ()); + } } } } @@ -1374,10 +1482,11 @@ struct CorrelationTask { } if (!(doprocessSameDerived || doprocessSameDerivedMultSet || doprocessSame2ProngDerived || doprocessSame2ProngDerivedML || doprocessSame2Prong2Prong || doprocessSame2Prong2ProngML)) { - if constexpr (std::experimental::is_detected::value) + if constexpr (std::experimental::is_detected::value) { fillQA(mcCollision, multiplicity, mcCollision.posZ(), mcParticles1, mcParticles2); - else + } else { fillQA(mcCollision, multiplicity, mcParticles1); + } } same->fillEvent(multiplicity, CorrelationContainer::kCFStepAll); @@ -1424,11 +1533,13 @@ struct CorrelationTask { bool useMCMultiplicity = (cfgCentBinsForMC == 0); auto getMultiplicity = [&collisions, &useMCMultiplicity, this](auto& col) { - if (useMCMultiplicity) + if (useMCMultiplicity) { return col.multiplicity(); + } auto groupedCollisions = collisions.sliceBy(collisionPerMCCollision, col.globalIndex()); - if (groupedCollisions.size() == 0) + if (groupedCollisions.size() == 0) { return -1.0f; + } return groupedCollisions.begin().multiplicity(); }; diff --git a/PWGCF/TwoParticleCorrelations/TableProducer/longrangeMaker.cxx b/PWGCF/TwoParticleCorrelations/TableProducer/longrangeMaker.cxx index 5a11c2ae50d..e6bbb5e8d7f 100644 --- a/PWGCF/TwoParticleCorrelations/TableProducer/longrangeMaker.cxx +++ b/PWGCF/TwoParticleCorrelations/TableProducer/longrangeMaker.cxx @@ -207,6 +207,9 @@ struct LongrangeMaker { Configurable minV0DcaPiLambda{"minV0DcaPiLambda", 0.2f, "Min V0 pion DCA for Lambda"}; Configurable minV0DcaPr{"minV0DcaPr", 0.07f, "Min V0 proton DCA for Lambda"}; Configurable maxLambdaLifeTime{"maxLambdaLifeTime", 30.0f, "Maximum Lambda lifetime (in cm)"}; + + Configurable rejK0sMassWindow{"rejK0sMassWindow", 0.012f, "K0s mass rejection window for Lambda (12 MeV/c^2)"}; + Configurable cfgQAV0Mask{"cfgQAV0Mask", 7, "Bitmask for V0 QA: 1=K0s, 2=Lambda, 4=ALambda, 7=All"}; } cfgv0trksel; struct : ConfigurableGroup { @@ -216,6 +219,23 @@ struct LongrangeMaker { ConfigurableAxis axisMFTAmbDegree{"axisMFTAmbDegree", {50, -0.5, 49.5}, "Track Ambiguity axis"}; ConfigurableAxis axisEta = {"axisEta", {100, -5, 5}, "eta axis"}; ConfigurableAxis axisPhi{"axisPhi", {72, 0, TwoPI}, "#phi axis"}; + + ConfigurableAxis axisV0Species{"axisV0Species", {3, -0.5, 2.5}, "V0 Species (0=K0s, 1=#Lambda, 2=#bar{#Lambda})"}; + ConfigurableAxis axisAlpha{"axisAlpha", {100, -1.0, 1.0}, "Armenteros #alpha"}; + ConfigurableAxis axisQt{"axisQt", {100, 0.0, 0.42}, "Armenteros q_{T} (GeV/c)"}; + ConfigurableAxis axisV0Pt{"axisV0Pt", {100, 0.0, 10.0}, "V0 p_{T} (GeV/c)"}; + ConfigurableAxis axisMass{"axisMass", {150, 0.4, 1.2}, "Invariant Mass (GeV/c^{2})"}; + ConfigurableAxis axisDcaV0Dau{"axisDcaV0Dau", {100, 0.0, 1.5}, "DCA between V0 Daughters (cm)"}; + ConfigurableAxis axisDcaPosToPv{"axisDcaPosToPv", {100, 0.0, 10.0}, "DCA Pos-Prong to PV (cm)"}; + ConfigurableAxis axisDcaNegToPv{"axisDcaNegToPv", {100, 0.0, 10.0}, "DCA Neg-Prong to PV (cm)"}; + ConfigurableAxis axisDcaV0ToPv{"axisDcaV0ToPv", {100, 0.0, 5.0}, "DCA V0 to PV (cm)"}; + ConfigurableAxis axisCosPA{"axisCosPA", {100, 0.97, 1.0}, "Cosine of Pointing Angle (cos#theta_{PA})"}; + ConfigurableAxis axisRadius{"axisRadius", {100, 0.0, 100.0}, "V0 2D Decay Radius (cm)"}; + ConfigurableAxis axisCtau{"axisCtau", {100, 0.0, 50.0}, "Proper Lifetime c#tau (cm)"}; + + ConfigurableAxis axisPQA{"axisPQA", {100, 0.0, 10.0}, "p (GeV/c)"}; + ConfigurableAxis axisTpcSignal{"axisTpcSignal", {250, 0, 250}, "TPC dE/dx (a.u.)"}; + ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 15, 25, 30, 40, 50, 60, 80, 100, 150, 200}, "Multiplicity / Centrality"}; } cfgAxis; Configurable> itsNsigmaPidCut{"itsNsigmaPidCut", std::vector{3, 2.5, 2, -3, -2.5, -2}, "ITS n-sigma cut for pions_posNsigma, kaons_posNsigma, protons_posNsigma, pions_negNsigma, kaons_negNsigma, protons_negNsigma"}; @@ -228,7 +248,7 @@ struct LongrangeMaker { Service pdg; o2::ccdb::CcdbApi ccdbApi; o2::ft0::Geometry ft0Det; - std::vector* offsetFT0; + std::vector* offsetFT0{nullptr}; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; TrackSelection myTrackFilter; @@ -315,6 +335,17 @@ struct LongrangeMaker { histos.add("FT0C_Channel_vs_phi", "FT0C_Channel_vs_phi", kTH2D, {cfgAxis.axisPhi, cfgAxis.axisChannel}); histos.add("h3DVtxZetaPhi", "", kTH3D, {{20, -10, 10}, {16, -0.8, +0.8}, {100, 0., TwoPI}}); + histos.add("hArmenteros_before", "Armenteros-Podolanski (Before Cuts);#alpha;q_{T} (GeV/c)", kTH2D, {cfgAxis.axisAlpha, cfgAxis.axisQt}); + histos.add("hArmenteros_after", "Armenteros-Podolanski (After Cuts);V0 Species;#alpha;q_{T} (GeV/c)", kTH3D, {cfgAxis.axisV0Species, cfgAxis.axisAlpha, cfgAxis.axisQt}); + histos.add("hTopoQA", "V0 Topological and Kinematic QA;V0 Species;DCA between V0 Daughters (cm);DCA Pos-Prong to PV (cm);DCA Neg-Prong to PV (cm);DCA V0 to PV (cm);Cosine of Pointing Angle (cos#theta_{PA});V0 2D Decay Radius (cm);Proper Lifetime c#tau (cm);V0 p_{T} (GeV/c);Invariant Mass (GeV/c^{2})", kTHnSparseF, {cfgAxis.axisV0Species, cfgAxis.axisDcaV0Dau, cfgAxis.axisDcaPosToPv, cfgAxis.axisDcaNegToPv, cfgAxis.axisDcaV0ToPv, cfgAxis.axisCosPA, cfgAxis.axisRadius, cfgAxis.axisCtau, cfgAxis.axisV0Pt, cfgAxis.axisMass}); + + // V0 Daughter dE/dx Histograms + histos.add("hTpcdEdx_pos_before", "Pos-prong dE/dx Before PID;V0 Species;Multiplicity;p (GeV/c);TPC dE/dx", kTHnSparseF, {cfgAxis.axisV0Species, cfgAxis.axisMultiplicity, cfgAxis.axisPQA, cfgAxis.axisTpcSignal}); + histos.add("hTpcdEdx_neg_before", "Neg-prong dE/dx Before PID;V0 Species;Multiplicity;p (GeV/c);TPC dE/dx", kTHnSparseF, {cfgAxis.axisV0Species, cfgAxis.axisMultiplicity, cfgAxis.axisPQA, cfgAxis.axisTpcSignal}); + + histos.add("hTpcdEdx_pos_after", "Pos-prong dE/dx After PID;V0 Species;Multiplicity;p (GeV/c);TPC dE/dx", kTHnSparseF, {cfgAxis.axisV0Species, cfgAxis.axisMultiplicity, cfgAxis.axisPQA, cfgAxis.axisTpcSignal}); + histos.add("hTpcdEdx_neg_after", "Neg-prong dE/dx After PID;V0 Species;Multiplicity;p (GeV/c);TPC dE/dx", kTHnSparseF, {cfgAxis.axisV0Species, cfgAxis.axisMultiplicity, cfgAxis.axisPQA, cfgAxis.axisTpcSignal}); + myTrackFilter = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, TrackSelection::GlobalTrackRun3DCAxyCut::Default); myTrackFilter.SetPtRange(cfgtrksel.cfgPtCutMin, cfgtrksel.cfgPtCutMax); @@ -816,9 +847,9 @@ struct LongrangeMaker { } } auto recTracksPart = RecTracks.sliceBy(perColMidtrack, RecCol.globalIndex()); - float multiplicity = countNTracks(recTracksPart, RecCol.posZ()); + float recMultiplicity = countNTracks(recTracksPart, RecCol.posZ()); float centrality = selColCent(RecCol); - lrcollision(bc.runNumber(), RecCol.posZ(), multiplicity, centrality, bc.timestamp()); + lrcollision(bc.runNumber(), RecCol.posZ(), recMultiplicity, centrality, bc.timestamp()); lrcollisionMcLabel(RecCol.mcCollisionId()); // track loop @@ -1004,6 +1035,86 @@ struct LongrangeMaker { } } + void processV0QA(CollTable::iterator const& col, aod::V0Datas const& V0s, TrksTable const& tracks) + { + if (!isEventSelected(col)) { + return; + } + + float multiplicity = selColCent(col); + if (multiplicity == -1) { + multiplicity = countNTracks(tracks, col.posZ()); + } + + bool checkK0s = (cfgv0trksel.cfgQAV0Mask & 1); + bool checkLam = (cfgv0trksel.cfgQAV0Mask & 2); + bool checkALam = (cfgv0trksel.cfgQAV0Mask & 4); + + for (const auto& v0 : V0s) { + if (!isSelectV0Track(v0)) { + continue; + } + + auto posTrack = v0.template posTrack_as(); + auto negTrack = v0.template negTrack_as(); + float posP = posTrack.p(); + float negP = negTrack.p(); + float posSignal = posTrack.tpcSignal(); + float negSignal = negTrack.tpcSignal(); + + histos.fill(HIST("hArmenteros_before"), v0.alpha(), v0.qtarm()); + + // Evaluate topology ONLY (PID disabled) + bool isK0sTopoOnly = checkK0s && isSelectK0s(col, v0, false); + bool isLamTopoOnly = checkLam && isSelectLambda(col, v0, false); + bool isAlamTopoOnly = checkALam && isSelectLambda(col, v0, false); + + // Evaluate full selection (PID enabled) + bool isK0sTag = checkK0s && isSelectK0s(col, v0, true); + bool lambdaTag = checkLam && isSelectLambda(col, v0, true); + bool antilambdaTag = checkALam && isSelectLambda(col, v0, true); + + // ---------------- K0s ---------------- + if (isK0sTopoOnly) { + histos.fill(HIST("hTpcdEdx_pos_before"), 0.0f, multiplicity, posP, posSignal); + histos.fill(HIST("hTpcdEdx_neg_before"), 0.0f, multiplicity, negP, negSignal); + } + if (isK0sTag) { + histos.fill(HIST("hTpcdEdx_pos_after"), 0.0f, multiplicity, posP, posSignal); + histos.fill(HIST("hTpcdEdx_neg_after"), 0.0f, multiplicity, negP, negSignal); + histos.fill(HIST("hArmenteros_after"), 0.0f, v0.alpha(), v0.qtarm()); + float ctau = v0.distovertotmom(col.posX(), col.posY(), col.posZ()) * o2::constants::physics::MassK0; + histos.fill(HIST("hTopoQA"), 0.0f, v0.dcaV0daughters(), std::abs(v0.dcapostopv()), std::abs(v0.dcanegtopv()), std::abs(v0.dcav0topv()), v0.v0cosPA(), v0.v0radius(), ctau, v0.pt(), v0.mK0Short()); + } + + // -------------- Lambda --------------- + if (isLamTopoOnly) { + histos.fill(HIST("hTpcdEdx_pos_before"), 1.0f, multiplicity, posP, posSignal); + histos.fill(HIST("hTpcdEdx_neg_before"), 1.0f, multiplicity, negP, negSignal); + } + if (lambdaTag) { + histos.fill(HIST("hTpcdEdx_pos_after"), 1.0f, multiplicity, posP, posSignal); + histos.fill(HIST("hTpcdEdx_neg_after"), 1.0f, multiplicity, negP, negSignal); + histos.fill(HIST("hArmenteros_after"), 1.0f, v0.alpha(), v0.qtarm()); + float ctau = v0.distovertotmom(col.posX(), col.posY(), col.posZ()) * o2::constants::physics::MassLambda; + histos.fill(HIST("hTopoQA"), 1.0f, v0.dcaV0daughters(), std::abs(v0.dcapostopv()), std::abs(v0.dcanegtopv()), std::abs(v0.dcav0topv()), v0.v0cosPA(), v0.v0radius(), ctau, v0.pt(), v0.mLambda()); + } + + // ----------- Anti-Lambda ------------- + if (isAlamTopoOnly) { + histos.fill(HIST("hTpcdEdx_pos_before"), 2.0f, multiplicity, posP, posSignal); + histos.fill(HIST("hTpcdEdx_neg_before"), 2.0f, multiplicity, negP, negSignal); + } + if (antilambdaTag) { + histos.fill(HIST("hTpcdEdx_pos_after"), 2.0f, multiplicity, posP, posSignal); + histos.fill(HIST("hTpcdEdx_neg_after"), 2.0f, multiplicity, negP, negSignal); + histos.fill(HIST("hArmenteros_after"), 2.0f, v0.alpha(), v0.qtarm()); + float ctau = v0.distovertotmom(col.posX(), col.posY(), col.posZ()) * o2::constants::physics::MassLambda; + histos.fill(HIST("hTopoQA"), 2.0f, v0.dcaV0daughters(), std::abs(v0.dcapostopv()), std::abs(v0.dcanegtopv()), std::abs(v0.dcav0topv()), v0.v0cosPA(), v0.v0radius(), ctau, v0.pt(), v0.mAntiLambda()); + } + } + } + template bool isGenPartSelected(CheckGenPart const& particle) { @@ -1306,7 +1417,7 @@ struct LongrangeMaker { } template - bool isSelectK0s(Collision const& col, const V0candidate& v0) + bool isSelectK0s(Collision const& col, const V0candidate& v0, bool applyPidCut = true) { const auto& posTrack = v0.template posTrack_as(); const auto& negTrack = v0.template negTrack_as(); @@ -1316,7 +1427,7 @@ struct LongrangeMaker { if (v0.mK0Short() < cfgv0trksel.minK0sMass || v0.mK0Short() > cfgv0trksel.maxK0sMass) { return false; } - if ((v0.qtarm() / std::abs(v0.alpha())) < cfgv0trksel.minqtArmenterosForK0s) { + if (v0.qtarm() < (cfgv0trksel.minqtArmenterosForK0s * std::abs(v0.alpha()))) { return false; } if (v0.v0radius() > cfgv0trksel.maxK0sRadius || v0.v0radius() < cfgv0trksel.minK0sRadius) { @@ -1331,25 +1442,40 @@ struct LongrangeMaker { if (std::abs(ctauK0s) > cfgv0trksel.maxK0sLifeTime) { return false; } - if (((std::abs(posTrack.tpcNSigmaPi()) > cfgv0trksel.daughPIDCuts) || (std::abs(negTrack.tpcNSigmaPi()) > cfgv0trksel.daughPIDCuts))) { - return false; + if (applyPidCut) { + if (std::abs(posTrack.tpcNSigmaPi()) > cfgv0trksel.daughPIDCuts || + std::abs(negTrack.tpcNSigmaPi()) > cfgv0trksel.daughPIDCuts) { + return false; + } } - if ((std::abs(v0.dcapostopv()) < cfgv0trksel.minV0DcaPiK0s || std::abs(v0.dcanegtopv()) < cfgv0trksel.minV0DcaPiK0s)) { + if (std::abs(v0.dcapostopv()) < cfgv0trksel.minV0DcaPiK0s || + std::abs(v0.dcanegtopv()) < cfgv0trksel.minV0DcaPiK0s) { return false; } return true; } template - bool isSelectLambda(Collision const& col, const V0candidate& v0) + bool isSelectLambda(Collision const& col, const V0candidate& v0, bool applyPidCut = true) { const auto& posTrack = v0.template posTrack_as(); const auto& negTrack = v0.template negTrack_as(); float ctauLambda = v0.distovertotmom(col.posX(), col.posY(), col.posZ()) * o2::constants::physics::MassLambda; - if ((v0.mLambda() < cfgv0trksel.minLambdaMass || v0.mLambda() > cfgv0trksel.maxLambdaMass) && - (v0.mAntiLambda() < cfgv0trksel.minLambdaMass || v0.mAntiLambda() > cfgv0trksel.maxLambdaMass)) { + + if constexpr (pid == KindOfV0::kLambda) { + if (v0.mLambda() < cfgv0trksel.minLambdaMass || v0.mLambda() > cfgv0trksel.maxLambdaMass) { + return false; + } + } else if constexpr (pid == KindOfV0::kAntiLambda) { + if (v0.mAntiLambda() < cfgv0trksel.minLambdaMass || v0.mAntiLambda() > cfgv0trksel.maxLambdaMass) { + return false; + } + } + + if (std::abs(v0.mK0Short() - o2::constants::physics::MassK0) < cfgv0trksel.rejK0sMassWindow) { return false; } + if (v0.v0radius() > cfgv0trksel.maxLambdaRadius || v0.v0radius() < cfgv0trksel.minLambdaRadius) { return false; } @@ -1359,17 +1485,29 @@ struct LongrangeMaker { if (v0.dcaV0daughters() > cfgv0trksel.maxDcaV0DauLambda) { return false; } - if (pid == KindOfV0::kLambda && (std::abs(v0.dcapostopv()) < cfgv0trksel.minV0DcaPr || std::abs(v0.dcanegtopv()) < cfgv0trksel.minV0DcaPiLambda)) { - return false; - } - if (pid == KindOfV0::kAntiLambda && (std::abs(v0.dcapostopv()) < cfgv0trksel.minV0DcaPiLambda || std::abs(v0.dcanegtopv()) < cfgv0trksel.minV0DcaPr)) { - return false; - } - if (pid == KindOfV0::kLambda && ((std::abs(posTrack.tpcNSigmaPr()) > cfgv0trksel.daughPIDCuts) || (std::abs(negTrack.tpcNSigmaPi()) > cfgv0trksel.daughPIDCuts))) { - return false; + if constexpr (pid == KindOfV0::kLambda) { + if (std::abs(v0.dcapostopv()) < cfgv0trksel.minV0DcaPr || + std::abs(v0.dcanegtopv()) < cfgv0trksel.minV0DcaPiLambda) { + return false; + } + } else if constexpr (pid == KindOfV0::kAntiLambda) { + if (std::abs(v0.dcapostopv()) < cfgv0trksel.minV0DcaPiLambda || + std::abs(v0.dcanegtopv()) < cfgv0trksel.minV0DcaPr) { + return false; + } } - if (pid == KindOfV0::kAntiLambda && ((std::abs(posTrack.tpcNSigmaPi()) > cfgv0trksel.daughPIDCuts) || (std::abs(negTrack.tpcNSigmaPr()) > cfgv0trksel.daughPIDCuts))) { - return false; + if (applyPidCut) { + if constexpr (pid == KindOfV0::kLambda) { + if (std::abs(posTrack.tpcNSigmaPr()) > cfgv0trksel.daughPIDCuts || + std::abs(negTrack.tpcNSigmaPi()) > cfgv0trksel.daughPIDCuts) { + return false; + } + } else if constexpr (pid == KindOfV0::kAntiLambda) { + if (std::abs(posTrack.tpcNSigmaPi()) > cfgv0trksel.daughPIDCuts || + std::abs(negTrack.tpcNSigmaPr()) > cfgv0trksel.daughPIDCuts) { + return false; + } + } } if (std::abs(ctauLambda) > cfgv0trksel.maxLambdaLifeTime) { return false; @@ -1387,7 +1525,7 @@ struct LongrangeMaker { if (hTrkEff == nullptr) { LOGF(fatal, "Could not load efficiency histogram for trigger particles from %s", cfgtrksel.cfgEffccdbPath.value.c_str()); } - LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgtrksel.cfgEffccdbPath.value.c_str(), (void*)hTrkEff); + LOGF(info, "Loaded efficiency histogram from %s (%p)", cfgtrksel.cfgEffccdbPath.value.c_str(), static_cast(hTrkEff)); } fLoadTrkEffCorr = true; } @@ -1411,6 +1549,7 @@ struct LongrangeMaker { PROCESS_SWITCH(LongrangeMaker, processUpc, "process UPC collisions", false); PROCESS_SWITCH(LongrangeMaker, processMCGen, "process MC generated collisions", false); PROCESS_SWITCH(LongrangeMaker, processMCRec, "process MC both gen and rec collisions", false); + PROCESS_SWITCH(LongrangeMaker, processV0QA, "process V0 QA histograms", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGCF/TwoParticleCorrelations/Tasks/CMakeLists.txt b/PWGCF/TwoParticleCorrelations/Tasks/CMakeLists.txt index ea65ecf1162..8b4b5dad8fc 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/CMakeLists.txt +++ b/PWGCF/TwoParticleCorrelations/Tasks/CMakeLists.txt @@ -120,10 +120,15 @@ o2physics_add_dpl_workflow(casc-di-hadron-corr o2physics_add_dpl_workflow(two-particle-correlations-mpi SOURCES twoParticleCorrelationsMpi.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore O2Physics::GFWCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(charge-balance-function SOURCES chargeBalanceFunction.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(lambda-or-anti-lambda-producer-with-spin + SOURCES lambdaOrAntiLambdaProducerWithSpin.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGCF/TwoParticleCorrelations/Tasks/chargeBalanceFunction.cxx b/PWGCF/TwoParticleCorrelations/Tasks/chargeBalanceFunction.cxx index bfd3ccbd7fa..98cd608aa39 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/chargeBalanceFunction.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/chargeBalanceFunction.cxx @@ -120,6 +120,7 @@ struct ChargeBalanceFunction { // Efficiency Correction Configurable cGetCorrectionFlag{"cGetCorrectionFlag", false, "Apply correction flag"}; Configurable cGetNuaCorrectionFlag{"cGetNuaCorrectionFlag", false, "Apply NUA correction flag"}; + Configurable cDoEffNuaCorrection{"cDoEffNuaCorrection", false, "Do NUE x NUA correction"}; // CCDB Configurable cUrlCCDB{"cUrlCCDB", "http://alice-ccdb.cern.ch", "ALICE CCDB URL"}; @@ -248,6 +249,10 @@ struct ChargeBalanceFunction { histos.add("Reco/h3f_n1_rapphi_P", "#rho_{1}^{#plus}", kTH3F, {axisCent, axisTrackEta, axisTrackPhi}); histos.add("Reco/h3f_n1_rapphi_M", "#rho_{1}^{#minus}", kTH3F, {axisCent, axisTrackEta, axisTrackPhi}); + // Rho1 for P2 pT + histos.add("Reco/h2f_n1_pt_P", "#rho_{1}^{#plus}", kTH2F, {axisCent, axisTrackPt}); + histos.add("Reco/h2f_n1_pt_M", "#rho_{1}^{#minus}", kTH2F, {axisCent, axisTrackPt}); + // Rho1 for P2 RapPhi histos.add("Reco/h3f_pt_rapphi_P", "#rho_{1}^{#plus}", kTH3F, {axisCent, axisTrackEta, axisTrackPhi}); histos.add("Reco/h3f_pt_rapphi_M", "#rho_{1}^{#minus}", kTH3F, {axisCent, axisTrackEta, axisTrackPhi}); @@ -394,7 +399,7 @@ struct ChargeBalanceFunction { } template - float getCorrectionFactor(T const& track, S const& sign) + float getEffCorrectionFactor(T const& track, S const& sign) { if (!cGetCorrectionFlag) { return 1.; @@ -530,7 +535,13 @@ struct ChargeBalanceFunction { const auto phibin1 = static_cast(trk_1.phi() / phibinwidth); const auto phibin2 = static_cast(trk_2.phi() / phibinwidth); - float corfac = getCorrectionFactor(trk_1, sign_1) * getCorrectionFactor(trk_2, sign_2); + float effcorr = getEffCorrectionFactor(trk_1, sign_1) * getEffCorrectionFactor(trk_2, sign_2); + float nuacorr = getNuaCorrectionFactor(trk_1, sign_1) * getNuaCorrectionFactor(trk_2, sign_2); + float corrfact = effcorr; + + if (cDoEffNuaCorrection) { + corrfact *= nuacorr; + } if (rapbin1 >= 0 && rapbin2 >= 0 && phibin1 >= 0 && phibin2 >= 0 && rapbin1 < nrapbins && rapbin2 < nrapbins && phibin1 < nphibins && phibin2 < nphibins) { @@ -538,21 +549,21 @@ struct ChargeBalanceFunction { int rapphiy = rapbin2 * nphibins + phibin2; if ((sign_1 > 0 && sign_2 < 0) || (sign_1 < 0 && sign_2 > 0)) { - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n2_rapphi_PM"), cent, rapphix + 0.5, rapphiy + 0.5, corfac); - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptpt_rapphi_PM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * trk_2.pt() * corfac); - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_npt_rapphi_PM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * corfac); - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptn_rapphi_PM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_2.pt() * corfac); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n2_rapphi_PM"), cent, rapphix + 0.5, rapphiy + 0.5, corrfact); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptpt_rapphi_PM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * trk_2.pt() * corrfact); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_npt_rapphi_PM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * corrfact); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptn_rapphi_PM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_2.pt() * corrfact); } else { if (sign_1 > 0 && sign_2 > 0) { - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n2_rapphi_PP"), cent, rapphix + 0.5, rapphiy + 0.5, corfac); - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptpt_rapphi_PP"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * trk_2.pt() * corfac); - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_npt_rapphi_PP"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * corfac); - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptn_rapphi_PP"), cent, rapphix + 0.5, rapphiy + 0.5, trk_2.pt() * corfac); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n2_rapphi_PP"), cent, rapphix + 0.5, rapphiy + 0.5, corrfact); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptpt_rapphi_PP"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * trk_2.pt() * corrfact); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_npt_rapphi_PP"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * corrfact); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptn_rapphi_PP"), cent, rapphix + 0.5, rapphiy + 0.5, trk_2.pt() * corrfact); } else if (sign_1 < 0 && sign_2 < 0) { - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n2_rapphi_MM"), cent, rapphix + 0.5, rapphiy + 0.5, corfac); - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptpt_rapphi_MM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * trk_2.pt() * corfac); - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_npt_rapphi_MM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * corfac); - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptn_rapphi_MM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_2.pt() * corfac); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n2_rapphi_MM"), cent, rapphix + 0.5, rapphiy + 0.5, corrfact); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptpt_rapphi_MM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * trk_2.pt() * corrfact); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_npt_rapphi_MM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_1.pt() * corrfact); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_ptn_rapphi_MM"), cent, rapphix + 0.5, rapphiy + 0.5, trk_2.pt() * corrfact); } } } @@ -573,8 +584,13 @@ struct ChargeBalanceFunction { static constexpr auto SubDirRecGen = std::array{"Reco/", "McGen/"}; // Correction factor - float corrFact = getCorrectionFactor(track, sign); + float effCorr = getEffCorrectionFactor(track, sign); float nuaCorr = getNuaCorrectionFactor(track, sign); + float corrFact = effCorr; + + if (cDoEffNuaCorrection) { + corrFact *= nuaCorr; + } // Histograms if (sign > 0) { @@ -584,14 +600,15 @@ struct ChargeBalanceFunction { histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("NUA/h3f_n1_vzrapphi_P"), posz, track.eta(), track.phi()); // Checks - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h1f_n1_pt_P"), track.pt(), corrFact); - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h1f_n1_rap_P"), track.eta(), corrFact); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h1f_n1_pt_P"), track.pt(), effCorr); + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h1f_n1_rap_P"), track.eta(), effCorr); histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h1f_n1_phi_P"), track.phi(), nuaCorr); // R2 Rho1 (Eta,Phi) histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n1_rapphi_P"), cent, track.eta(), track.phi(), corrFact); // P2 Rho1 (Eta,Phi) + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h2f_n1_pt_P"), cent, track.pt(), corrFact); histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_pt_rapphi_P"), cent, track.eta(), track.phi(), track.pt() * corrFact); } else if (sign < 0) { // Corrections @@ -608,6 +625,7 @@ struct ChargeBalanceFunction { histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n1_rapphi_M"), cent, track.eta(), track.phi(), corrFact); // P2 Rho1 (Eta,Phi) + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h2f_n1_pt_M"), cent, track.pt(), corrFact); histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_pt_rapphi_M"), cent, track.eta(), track.phi(), track.pt() * corrFact); } } diff --git a/PWGCF/TwoParticleCorrelations/Tasks/corrReso.cxx b/PWGCF/TwoParticleCorrelations/Tasks/corrReso.cxx index d11bf03b021..338aa2406bf 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/corrReso.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/corrReso.cxx @@ -68,6 +68,18 @@ using namespace constants::math; #define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, (DEFAULT), (HELP)}; // NOLINT(bugprone-macro-parentheses) +template +auto readMatrix(Array2D const& mat, P& array) +{ + for (auto i = 0; i < static_cast(mat.rows); ++i) { + for (auto j = 0; j < static_cast(mat.cols); ++j) { + array[i][j] = mat(i, j); + } + } + + return; +} + static constexpr std::array, 20> LongArrayFloat = {{{{1.1, 2.1, 3.1}}, {{1.2, 2.2, 3.2}}, {{1.3, 2.3, 3.3}}, {{-1.1, -2.1, -3.1}}, {{-1.2, -2.2, -3.2}}, {{-1.3, -2.3, -3.3}}, {{1.1, 1.1, 1.1}}, {{1.2, 1.2, 1.2}}, {{1.3, 1.3, 1.3}}, {{-1.1, -1.1, -1.1}}, {{-1.2, -1.2, -1.2}}, {{-1.3, -1.3, -1.3}}, {{1.1, 1.1, 1.1}}, {{1.2, 1.2, 1.2}}, {{1.3, 1.3, 1.3}}, {{-1.1, -1.1, -1.1}}, {{-1.2, -1.2, -1.2}}, {{-1.3, -1.3, -1.3}}, {{1.1, 1.1, 1.1}}, {{1.2, 1.2, 1.2}}}}; static constexpr std::array, 20> LongArrayInt = {{{{1, 2, 3}}, {{1, 2, 3}}, {{1, 2, 3}}, {{0, 0, 0}}, {{0, 0, 0}}, {{0, 0, 0}}, {{1, 1, 1}}, {{1, 1, 1}}, {{1, 1, 1}}, {{0, 0, 0}}, {{0, 0, 0}}, {{0, 0, 0}}, {{1, 1, 1}}, {{1, 1, 1}}, {{1, 1, 1}}, {{0, 0, 0}}, {{0, 0, 0}}, {{0, 0, 0}}, {{1, 1, 1}}, {{1, 1, 1}}}}; @@ -77,14 +89,10 @@ struct CorrReso { O2_DEFINE_CONFIGURABLE(cfgUseAdditionalEventCut, bool, true, "Use additional event cut on mult correlations") O2_DEFINE_CONFIGURABLE(cfgZVtxCut, float, 10.0f, "Accepted z-vertex range") - O2_DEFINE_CONFIGURABLE(cfgUseTransverseMomentum, bool, false, "Use transverse momentum for correlation container") O2_DEFINE_CONFIGURABLE(cfgQaCheck, bool, true, "Enable QA histograms for event selection") O2_DEFINE_CONFIGURABLE(cfgStrictTrackCounter, bool, false, "Strict track counter for multiplicity correlation cut, counts only tracks that pass all cuts and are used in the correlation") - O2_DEFINE_CONFIGURABLE(cfgRefpTt, bool, false, "Apply upper pT cut on reference tracks") - O2_DEFINE_CONFIGURABLE(cfgRefpTMax, float, 3.0f, "maximum pT for reference tracks if cfgRefpTt is true") O2_DEFINE_CONFIGURABLE(cfgMinMultForCorrelations, int, 0, "minimum multiplicity for correlations") O2_DEFINE_CONFIGURABLE(cfgMaxMultForCorrelations, int, 20, "maximum multiplicity for correlations") - O2_DEFINE_CONFIGURABLE(cfgRefMultiplicity, bool, false, "Use multiplicity of reference tracks for multiplicity correlation cut instead of Nch") Configurable> cfgRunRemoveList{"cfgRunRemoveList", std::vector{-1}, "excluded run numbers"}; O2_DEFINE_CONFIGURABLE(cfgEvSelRCTflags, std::string, "", "keep empty to disable, usage: 'CentralBarrelTracking (CBT)', 'CBT_hadronPID' ") @@ -111,7 +119,6 @@ struct CorrReso { O2_DEFINE_CONFIGURABLE(cfgCentralityWeight, std::string, "", "CCDB path to centrality weight object") O2_DEFINE_CONFIGURABLE(cfgLocalEfficiency, bool, false, "Use local efficiency object") O2_DEFINE_CONFIGURABLE(cfgLocalEfficiencyNch, bool, false, "Use local multiplicity dependent efficiency object"); - O2_DEFINE_CONFIGURABLE(cfgUseEventWeights, bool, false, "Use event weights for mixed event") O2_DEFINE_CONFIGURABLE(cfgCentEstimator, int, 0, "0:FT0C; 1:FT0CVariant1; 2:FT0M; 3:FT0A") struct : ConfigurableGroup { @@ -148,15 +155,14 @@ struct CorrReso { struct : ConfigurableGroup { O2_DEFINE_CONFIGURABLE(cfgUseOnlyTPC, bool, true, "Use only TPC PID for daughter selection") - O2_DEFINE_CONFIGURABLE(cfgUseAntiLambda, bool, true, "Use AntiLambda candidates for analysis") O2_DEFINE_CONFIGURABLE(cfgPIDUseRejection, bool, true, "True: use exclusion exclusion criteria for PID determination, false: don't use exclusion") O2_DEFINE_CONFIGURABLE(cfgTpcCut, float, 3.0f, "TPC N-sigma cut for pions, kaons, protons") O2_DEFINE_CONFIGURABLE(cfgPIDParticle, int, 0, "4 = kshort, 5 = lambda, 6 = phi, 0 for no PID") O2_DEFINE_CONFIGURABLE(cfgUseItsPID, bool, true, "Use ITS PID for particle identification") O2_DEFINE_CONFIGURABLE(cfgTofPtCut, float, 0.4f, "Minimum pt to use TOF N-sigma") Configurable> nSigmas{"nSigmas", {LongArrayFloat.front().data(), 6, 3, {"UpCut_pi", "UpCut_ka", "UpCut_pr", "LowCut_pi", "LowCut_ka", "LowCut_pr"}, {"TPC", "TOF", "ITS"}}, "Labeled array for n-sigma values for TPC, TOF, ITS for pions, kaons, protons (positive and negative)"}; - Configurable> cfgResoCuts{"cfgResoCuts", {LongArrayFloat.front().data(), 12, 3, {"cos_PAs", "massMin", "massMax", "PosTrackPt", "NegTrackPt", "DCAPosToPVMin", "DCANegToPVMin", "Lifetime", "RadiusMin", "RadiusMax", "Rapidity", "ArmPodMinVal"}, {"K0", "Lambda", "Phi"}}, "Labeled array (float) for various cuts on resonances"}; - Configurable> cfgResoSwitches{"cfgResoSwitches", {LongArrayInt.front().data(), 6, 3, {"UseCosPA", "NMassBins", "DCABetDaug", "UseProperLifetime", "UseV0Radius", "UseArmPodCut"}, {"K0", "Lambda", "Phi"}}, "Labeled array (int) for various cuts on resonances"}; + Configurable> cfgResoCuts{"cfgResoCuts", {LongArrayFloat.front().data(), 13, 3, {"cos_PAs", "massMin", "massMax", "PosTrackPt", "NegTrackPt", "DCAPosToPVMin", "DCANegToPVMin", "Lifetime", "RadiusMin", "RadiusMax", "Rapidity", "ArmPodMinVal", "DCABetDaug"}, {"K0", "Lambda", "Phi"}}, "Labeled array (float) for various cuts on resonances"}; + Configurable> cfgResoSwitches{"cfgResoSwitches", {LongArrayInt.front().data(), 6, 3, {"UseCosPA", "NMassBins", "UseDCABetDaug", "UseProperLifetime", "UseV0Radius", "UseArmPodCut"}, {"K0", "Lambda", "Phi"}}, "Labeled array (int) for various cuts on resonances"}; } cfgPIDConfigs; Configurable cfgCutFV0{"cfgCutFV0", 50., "FV0A threshold"}; @@ -178,7 +184,6 @@ struct CorrReso { ConfigurableAxis axisVtxMix{"axisVtxMix", {VARIABLE_WIDTH, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "vertex axis for mixed event histograms"}; ConfigurableAxis axisMultMix{"axisMultMix", {VARIABLE_WIDTH, 0, 10, 20, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 260}, "multiplicity / centrality axis for mixed event histograms"}; ConfigurableAxis axisSample{"axisSample", {cfgSampleSize, 0, cfgSampleSize}, "sample axis for histograms"}; - ConfigurableAxis axisNch{"axisNch", {VARIABLE_WIDTH, 0, 10, 50, 70, 100}, "multiplicity axis for correlation container"}; ConfigurableAxis axisNsigmaTPC{"axisNsigmaTPC", {80, -5, 5}, "nsigmaTPC axis"}; ConfigurableAxis axisNsigmaTOF{"axisNsigmaTOF", {80, -5, 5}, "nsigmaTOF axis"}; @@ -222,6 +227,12 @@ struct CorrReso { HistogramRegistry registry{"registry"}; + // For Labelled array value containers + std::array, 13> resoCutVals{}; + std::array, 6> resoSwitchVals{}; + std::array, 14> eventCuts{}; + std::array, 6> nSigmaVals{}; + // define global variables TRandom3* gRandom = new TRandom3(); @@ -272,12 +283,13 @@ struct CorrReso { kRadiusMax, kRapidity, kArmPodMinVal, + kDCABetDaug, kNParticleCuts }; enum ResoParticleSwitches { kUseCosPA = 0, kMassBins, - kDCABetDaug, + kUseDCABetDaug, kUseProperLifetime, kUseV0Radius, kUseArmPodCut, @@ -337,26 +349,31 @@ struct CorrReso { return; } + readMatrix(cfgPIDConfigs.cfgResoCuts->getData(), resoCutVals); + readMatrix(cfgPIDConfigs.cfgResoSwitches->getData(), resoSwitchVals); + readMatrix(cfgUseEventCuts->getData(), eventCuts); + readMatrix(cfgPIDConfigs.nSigmas->getData(), nSigmaVals); + // Creating mass axis depending on particle - 4 = kshort, 5 = lambda, 6 = phi AxisSpec axisInvMass = {10, 0, 1, "mass"}; if (cfgPIDConfigs.cfgPIDParticle == kK0) { - const auto bins = cfgPIDConfigs.cfgResoSwitches->getData()[kMassBins][iK0]; - const auto min = cfgPIDConfigs.cfgResoCuts->getData()[kMassMin][iK0]; - const auto max = cfgPIDConfigs.cfgResoCuts->getData()[kMassMax][iK0]; + const auto bins = resoSwitchVals[kMassBins][iK0]; + const auto min = resoCutVals[kMassMin][iK0]; + const auto max = resoCutVals[kMassMax][iK0]; axisInvMass = {bins, min, max, "M_{#pi^{+}#pi^{-}} (GeV/c^{2})"}; } if (cfgPIDConfigs.cfgPIDParticle == kLambda) { - const auto bins = cfgPIDConfigs.cfgResoSwitches->getData()[kMassBins][iLambda]; - const auto min = cfgPIDConfigs.cfgResoCuts->getData()[kMassMin][iLambda]; - const auto max = cfgPIDConfigs.cfgResoCuts->getData()[kMassMax][iLambda]; + const auto bins = resoSwitchVals[kMassBins][iLambda]; + const auto min = resoCutVals[kMassMin][iLambda]; + const auto max = resoCutVals[kMassMax][iLambda]; axisInvMass = {bins, min, max, "M_{p#pi} (GeV/c^{2})"}; } if (cfgPIDConfigs.cfgPIDParticle == kPhi) { - const auto bins = cfgPIDConfigs.cfgResoSwitches->getData()[kMassBins][iPhi]; - const auto min = cfgPIDConfigs.cfgResoCuts->getData()[kMassMin][iPhi]; - const auto max = cfgPIDConfigs.cfgResoCuts->getData()[kMassMax][iPhi]; + const auto bins = resoSwitchVals[kMassBins][iPhi]; + const auto min = resoCutVals[kMassMin][iPhi]; + const auto max = resoCutVals[kMassMax][iPhi]; axisInvMass = {bins, min, max, "M_{K^{+}K^{-}} (GeV/c^{2})"}; } @@ -389,12 +406,10 @@ struct CorrReso { registry.add("PrPlusTOF_La", "", {HistType::kTH2D, {{axisPtFiner, axisNsigmaTOF}}}); registry.add("PiMinusTOF_La", "", {HistType::kTH2D, {{axisPtFiner, axisNsigmaTOF}}}); - if (cfgPIDConfigs.cfgUseAntiLambda) { - registry.add("PrMinusTPC_Al", "", {HistType::kTH2D, {{axisPtFiner, axisNsigmaTPC}}}); - registry.add("PiPlusTPC_Al", "", {HistType::kTH2D, {{axisPtFiner, axisNsigmaTPC}}}); - registry.add("PrMinusTOF_Al", "", {HistType::kTH2D, {{axisPtFiner, axisNsigmaTOF}}}); - registry.add("PiPlusTOF_Al", "", {HistType::kTH2D, {{axisPtFiner, axisNsigmaTOF}}}); - } + registry.add("PrMinusTPC_Al", "", {HistType::kTH2D, {{axisPtFiner, axisNsigmaTPC}}}); + registry.add("PiPlusTPC_Al", "", {HistType::kTH2D, {{axisPtFiner, axisNsigmaTPC}}}); + registry.add("PrMinusTOF_Al", "", {HistType::kTH2D, {{axisPtFiner, axisNsigmaTOF}}}); + registry.add("PiPlusTOF_Al", "", {HistType::kTH2D, {{axisPtFiner, axisNsigmaTOF}}}); registry.add("hLambdaPhi", "", {HistType::kTH1D, {axisPhi}}); registry.add("hLambdaEta", "", {HistType::kTH1D, {axisEta}}); @@ -450,7 +465,7 @@ struct CorrReso { } // Multiplicity correlation cuts - if (cfgUseEventCuts->getData()[kUseMultCorrCut][kEvCut1] != 0) { + if (eventCuts[kUseMultCorrCut][kEvCut1] != 0) { cfgFuncParas.multT0CCutPars = cfgFuncParas.cfgMultT0CCutPars; cfgFuncParas.multPVT0CCutPars = cfgFuncParas.cfgMultPVT0CCutPars; cfgFuncParas.multGlobalPVCutPars = cfgFuncParas.cfgMultGlobalPVCutPars; @@ -475,7 +490,7 @@ struct CorrReso { cfgFuncParas.fMultMultV0ACutHigh = new TF1("fMultMultV0ACutHigh", cfgFuncParas.cfgMultMultV0AHighCutFunction->c_str(), 0, 4000); cfgFuncParas.fMultMultV0ACutHigh->SetParameters(cfgFuncParas.multMultV0ACutPars.data()); } - if (cfgUseEventCuts->getData()[kUseT0AV0ACut][kEvCut1] != 0) { + if (eventCuts[kUseT0AV0ACut][kEvCut1] != 0) { cfgFuncParas.fT0AV0AMean = new TF1("fT0AV0AMean", "[0]+[1]*x", 0, 200000); cfgFuncParas.fT0AV0AMean->SetParameters(-1601.0581, 9.417652e-01); cfgFuncParas.fT0AV0ASigma = new TF1("fT0AV0ASigma", "[0]+[1]*x+[2]*x*x+[3]*x*x*x+[4]*x*x*x*x", 0, 200000); @@ -584,13 +599,15 @@ struct CorrReso { bool eventRct(TCollision const& collision, const bool fillCounter) { if (!rctChecker(collision)) { - if (fillCounter) + if (fillCounter) { registry.fill(HIST("hEventCountRct"), 0.5); + } return 0; } - if (fillCounter) + if (fillCounter) { registry.fill(HIST("hEventCountRct"), 1.5); + } return 1; } @@ -598,118 +615,127 @@ struct CorrReso { template bool eventSelected(TCollision const& collision, const int mult, const bool fillCounter) { - if (cfgUseEventCuts->getData()[kUseNoTimeFrameBorder][kEvCut1] && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + if (eventCuts[kUseNoTimeFrameBorder][kEvCut1] && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { return 0; } - if (fillCounter && cfgUseEventCuts->getData()[kUseNoTimeFrameBorder][kEvCut1]) + if (fillCounter && eventCuts[kUseNoTimeFrameBorder][kEvCut1]) { registry.fill(HIST("hEventCount"), kUseNoTimeFrameBorder); - - if (cfgUseEventCuts->getData()[kUseNoITSROFrameBorder][kEvCut1] && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + } + if (eventCuts[kUseNoITSROFrameBorder][kEvCut1] && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { return 0; } - if (fillCounter && cfgUseEventCuts->getData()[kUseNoITSROFrameBorder][kEvCut1]) + if (fillCounter && eventCuts[kUseNoITSROFrameBorder][kEvCut1]) { registry.fill(HIST("hEventCount"), kUseNoITSROFrameBorder); - - if (cfgUseEventCuts->getData()[kUseNoSameBunchPileup][kEvCut1] && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + } + if (eventCuts[kUseNoSameBunchPileup][kEvCut1] && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { // rejects collisions which are associated with the same "found-by-T0" bunch crossing // https://indico.cern.ch/event/1396220/#1-event-selection-with-its-rof return 0; } - if (fillCounter && cfgUseEventCuts->getData()[kUseNoSameBunchPileup][kEvCut1]) + if (fillCounter && eventCuts[kUseNoSameBunchPileup][kEvCut1]) { registry.fill(HIST("hEventCount"), kUseNoSameBunchPileup); - - if (cfgUseEventCuts->getData()[kUseGoodZvtxFT0vsPV][kEvCut1] && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + } + if (eventCuts[kUseGoodZvtxFT0vsPV][kEvCut1] && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference // use this cut at low multiplicities with caution return 0; } - if (fillCounter && cfgUseEventCuts->getData()[kUseGoodZvtxFT0vsPV][kEvCut1]) + if (fillCounter && eventCuts[kUseGoodZvtxFT0vsPV][kEvCut1]) { registry.fill(HIST("hEventCount"), kUseGoodZvtxFT0vsPV); - - if (cfgUseEventCuts->getData()[kUseNoCollInTimeRangeStandard][kEvCut1] && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + } + if (eventCuts[kUseNoCollInTimeRangeStandard][kEvCut1] && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { // no collisions in specified time range return 0; } - if (fillCounter && cfgUseEventCuts->getData()[kUseNoCollInTimeRangeStandard][kEvCut1]) + if (fillCounter && eventCuts[kUseNoCollInTimeRangeStandard][kEvCut1]) { registry.fill(HIST("hEventCount"), kUseNoCollInTimeRangeStandard); - - if (cfgUseEventCuts->getData()[kUseGoodITSLayersAll][kEvCut1] && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + } + if (eventCuts[kUseGoodITSLayersAll][kEvCut1] && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { // from Jan 9 2025 AOT meeting // cut time intervals with dead ITS staves return 0; } - if (fillCounter && cfgUseEventCuts->getData()[kUseGoodITSLayersAll][kEvCut1]) + if (fillCounter && eventCuts[kUseGoodITSLayersAll][kEvCut1]) { registry.fill(HIST("hEventCount"), kUseGoodITSLayersAll); - - if (cfgUseEventCuts->getData()[kUseGoodITSLayer0123][kEvCut1] && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)) { + } + if (eventCuts[kUseGoodITSLayer0123][kEvCut1] && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayer0123)) { return 0; } - if (fillCounter && cfgUseEventCuts->getData()[kUseGoodITSLayer0123][kEvCut1]) + if (fillCounter && eventCuts[kUseGoodITSLayer0123][kEvCut1]) { registry.fill(HIST("hEventCount"), kUseGoodITSLayer0123); - - if (cfgUseEventCuts->getData()[kUseNoCollInRofStandard][kEvCut1] && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + } + if (eventCuts[kUseNoCollInRofStandard][kEvCut1] && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { // no other collisions in this Readout Frame with per-collision multiplicity above threshold return 0; } - if (fillCounter && cfgUseEventCuts->getData()[kUseNoCollInRofStandard][kEvCut1]) + if (fillCounter && eventCuts[kUseNoCollInRofStandard][kEvCut1]) { registry.fill(HIST("hEventCount"), kUseNoCollInRofStandard); - - if (cfgUseEventCuts->getData()[kUseNoHighMultCollInPrevRof][kEvCut1] && !collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + } + if (eventCuts[kUseNoHighMultCollInPrevRof][kEvCut1] && !collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { // veto an event if FT0C amplitude in previous ITS ROF is above threshold return 0; } - if (fillCounter && cfgUseEventCuts->getData()[kUseNoHighMultCollInPrevRof][kEvCut1]) + if (fillCounter && eventCuts[kUseNoHighMultCollInPrevRof][kEvCut1]) { registry.fill(HIST("hEventCount"), kUseNoHighMultCollInPrevRof); - + } auto multNTracksPV = collision.multNTracksPV(); auto occupancy = collision.trackOccupancyInTimeRange(); - if (cfgUseEventCuts->getData()[kUseOccupancy][kEvCut1] && (occupancy < cfgEventSelection.cfgCutOccupancyLow || occupancy > cfgEventSelection.cfgCutOccupancyHigh)) { + if (eventCuts[kUseOccupancy][kEvCut1] && (occupancy < cfgEventSelection.cfgCutOccupancyLow || occupancy > cfgEventSelection.cfgCutOccupancyHigh)) { return 0; } - if (fillCounter && cfgUseEventCuts->getData()[kUseOccupancy][kEvCut1]) + if (fillCounter && eventCuts[kUseOccupancy][kEvCut1]) { registry.fill(HIST("hEventCount"), kUseOccupancy); - - if (cfgUseEventCuts->getData()[kUseMultCorrCut][kEvCut1]) { + } + if (eventCuts[kUseMultCorrCut][kEvCut1]) { float cent = getCentrality(collision); if (cfgFuncParas.cfgMultPVT0CCutEnabled) { - if (multNTracksPV < cfgFuncParas.fMultPVT0CCutLow->Eval(cent)) + if (multNTracksPV < cfgFuncParas.fMultPVT0CCutLow->Eval(cent)) { return 0; - if (multNTracksPV > cfgFuncParas.fMultPVT0CCutHigh->Eval(cent)) + } + if (multNTracksPV > cfgFuncParas.fMultPVT0CCutHigh->Eval(cent)) { return 0; + } } if (cfgFuncParas.cfgMultT0CCutEnabled) { - if (mult < cfgFuncParas.fMultT0CCutLow->Eval(cent)) + if (mult < cfgFuncParas.fMultT0CCutLow->Eval(cent)) { return 0; - if (mult > cfgFuncParas.fMultT0CCutHigh->Eval(cent)) + } + if (mult > cfgFuncParas.fMultT0CCutHigh->Eval(cent)) { return 0; + } } if (cfgFuncParas.cfgMultGlobalPVCutEnabled) { - if (mult < cfgFuncParas.fMultGlobalPVCutLow->Eval(multNTracksPV)) + if (mult < cfgFuncParas.fMultGlobalPVCutLow->Eval(multNTracksPV)) { return 0; - if (mult > cfgFuncParas.fMultGlobalPVCutHigh->Eval(multNTracksPV)) + } + if (mult > cfgFuncParas.fMultGlobalPVCutHigh->Eval(multNTracksPV)) { return 0; + } } if (cfgFuncParas.cfgMultMultV0ACutEnabled) { - if (collision.multFV0A() < cfgFuncParas.fMultMultV0ACutLow->Eval(mult)) + if (collision.multFV0A() < cfgFuncParas.fMultMultV0ACutLow->Eval(mult)) { return 0; - if (collision.multFV0A() > cfgFuncParas.fMultMultV0ACutHigh->Eval(mult)) + } + if (collision.multFV0A() > cfgFuncParas.fMultMultV0ACutHigh->Eval(mult)) { return 0; + } } } - if (fillCounter && cfgUseEventCuts->getData()[kUseMultCorrCut][kEvCut1]) + if (fillCounter && eventCuts[kUseMultCorrCut][kEvCut1]) { registry.fill(HIST("hEventCount"), kUseMultCorrCut); - + } // V0A T0A 5 sigma cut - if (cfgUseEventCuts->getData()[kUseT0AV0ACut][kEvCut1] && (std::fabs(collision.multFV0A() - cfgFuncParas.fT0AV0AMean->Eval(collision.multFT0A())) > cfgFuncParas.cfgV0AT0Acut * cfgFuncParas.fT0AV0ASigma->Eval(collision.multFT0A()))) + if (eventCuts[kUseT0AV0ACut][kEvCut1] && (std::fabs(collision.multFV0A() - cfgFuncParas.fT0AV0AMean->Eval(collision.multFT0A())) > cfgFuncParas.cfgV0AT0Acut * cfgFuncParas.fT0AV0ASigma->Eval(collision.multFT0A()))) { return 0; - if (fillCounter && cfgUseEventCuts->getData()[kUseT0AV0ACut][kEvCut1]) + } + if (fillCounter && eventCuts[kUseT0AV0ACut][kEvCut1]) { registry.fill(HIST("hEventCount"), kUseT0AV0ACut); - + } return 1; } @@ -759,7 +785,7 @@ struct CorrReso { } auto occupancy = collision.trackOccupancyInTimeRange(); - if (cfgUseEventCuts->getData()[kUseOccupancy][kEvCut1] && (occupancy < cfgEventSelection.cfgCutOccupancyLow || occupancy > cfgEventSelection.cfgCutOccupancyHigh)) { + if (eventCuts[kUseOccupancy][kEvCut1] && (occupancy > cfgEventSelection.cfgCutOccupancyLow && occupancy < cfgEventSelection.cfgCutOccupancyHigh)) { registry.fill(HIST("hPassedEventSelection"), kUseOccupancy); } } @@ -806,7 +832,7 @@ struct CorrReso { template bool trackSelected(TTrack const& track) { - return ((track.tpcNClsFound() >= cfgTrackCuts.cfgCutTPCclu) && (track.tpcNClsCrossedRows() >= cfgTrackCuts.cfgCutTPCCrossedRows) && (track.itsNCls() >= cfgTrackCuts.cfgCutITSclu) && (track.tpcChi2NCl() < cfgTrackCuts.cfgCutChi2prTPCcls) && (track.dcaZ() < cfgTrackCuts.cfgCutDCAz)); + return ((track.tpcNClsFound() >= cfgTrackCuts.cfgCutTPCclu) && (track.tpcNClsCrossedRows() >= cfgTrackCuts.cfgCutTPCCrossedRows) && (track.itsNCls() >= cfgTrackCuts.cfgCutITSclu) && (track.tpcChi2NCl() < cfgTrackCuts.cfgCutChi2prTPCcls) && (std::abs(track.dcaZ()) < cfgTrackCuts.cfgCutDCAz)); } void loadGain(aod::BCsWithTimestamps::iterator const& bc) @@ -841,8 +867,9 @@ struct CorrReso { id = ft0.channelC()[iCh]; id = id + Ft0IndexA; ampl = ft0.amplitudeC()[iCh]; - if (system == SameEvent) + if (system == SameEvent) { registry.fill(HIST("FT0Amp"), id, ampl); + } ampl = ampl / cstFT0RelGain[id]; if (system == SameEvent) { registry.fill(HIST("FT0AmpCorrect"), id, ampl); @@ -850,8 +877,9 @@ struct CorrReso { } else if (fitType == kFT0A) { id = ft0.channelA()[iCh]; ampl = ft0.amplitudeA()[iCh]; - if (system == SameEvent) + if (system == SameEvent) { registry.fill(HIST("FT0Amp"), id, ampl); + } ampl = ampl / cstFT0RelGain[id]; if (system == SameEvent) { registry.fill(HIST("FT0AmpCorrect"), id, ampl); @@ -876,13 +904,13 @@ struct CorrReso { bool isPion = false; bool isKaon = false; bool isProton = false; - bool isDetectedPion = nSigmaToUse[iPionUp] < cfgPIDConfigs.nSigmas->getData()[iPionUp][kIndexDetector] && nSigmaToUse[iPionUp] > cfgPIDConfigs.nSigmas->getData()[iPionLow][kIndexDetector]; - bool isDetectedKaon = nSigmaToUse[iKaonUp] < cfgPIDConfigs.nSigmas->getData()[iKaonUp][kIndexDetector] && nSigmaToUse[iKaonUp] > cfgPIDConfigs.nSigmas->getData()[iKaonLow][kIndexDetector]; - bool isDetectedProton = nSigmaToUse[iProtonUp] < cfgPIDConfigs.nSigmas->getData()[iProtonUp][kIndexDetector] && nSigmaToUse[iProtonUp] > cfgPIDConfigs.nSigmas->getData()[iProtonLow][kIndexDetector]; + bool isDetectedPion = nSigmaToUse[iPionUp] < nSigmaVals[iPionUp][kIndexDetector] && nSigmaToUse[iPionUp] > nSigmaVals[iPionLow][kIndexDetector]; + bool isDetectedKaon = nSigmaToUse[iKaonUp] < nSigmaVals[iKaonUp][kIndexDetector] && nSigmaToUse[iKaonUp] > nSigmaVals[iKaonLow][kIndexDetector]; + bool isDetectedProton = nSigmaToUse[iProtonUp] < nSigmaVals[iProtonUp][kIndexDetector] && nSigmaToUse[iProtonUp] > nSigmaVals[iProtonLow][kIndexDetector]; - bool isTofPion = nSigmaTOF[iPionUp] < cfgPIDConfigs.nSigmas->getData()[iPionUp][kTOF] && nSigmaTOF[iPionUp] > cfgPIDConfigs.nSigmas->getData()[iPionLow][kTOF]; - bool isTofKaon = nSigmaTOF[iKaonUp] < cfgPIDConfigs.nSigmas->getData()[iKaonUp][kTOF] && nSigmaTOF[iKaonUp] > cfgPIDConfigs.nSigmas->getData()[iKaonLow][kTOF]; - bool isTofProton = nSigmaTOF[iProtonUp] < cfgPIDConfigs.nSigmas->getData()[iProtonUp][kTOF] && nSigmaTOF[iProtonUp] > cfgPIDConfigs.nSigmas->getData()[iProtonLow][kTOF]; + bool isTofPion = nSigmaTOF[iPionUp] < nSigmaVals[iPionUp][kTOF] && nSigmaTOF[iPionUp] > nSigmaVals[iPionLow][kTOF]; + bool isTofKaon = nSigmaTOF[iKaonUp] < nSigmaVals[iKaonUp][kTOF] && nSigmaTOF[iKaonUp] > nSigmaVals[iKaonLow][kTOF]; + bool isTofProton = nSigmaTOF[iProtonUp] < nSigmaVals[iProtonUp][kTOF] && nSigmaTOF[iProtonUp] > nSigmaVals[iProtonLow][kTOF]; if (track.pt() > cfgPIDConfigs.cfgTofPtCut && !track.hasTOF()) { return -1; @@ -917,29 +945,38 @@ struct CorrReso { template bool selectionV0Daughter(TTrack const& track, int pid) { - if (!(track.itsNCls() > cfgTrackCuts.cfgCutITSclu)) + if (!(track.itsNCls() >= cfgTrackCuts.cfgCutITSclu)) { return false; - if (!track.hasTPC()) + } + if (!track.hasTPC()) { return false; - if (!(track.tpcNClsFound() >= cfgTrackCuts.cfgCutTPCclu)) + } + if (!(track.tpcNClsFound() >= cfgTrackCuts.cfgCutTPCclu)) { return false; - if (!(track.tpcNClsCrossedRows() >= cfgTrackCuts.cfgCutTPCCrossedRows)) + } + if (!(track.tpcNClsCrossedRows() >= cfgTrackCuts.cfgCutTPCCrossedRows)) { return false; - if (!(track.dcaZ() < cfgTrackCuts.cfgCutDCAz)) + } + if (!(std::abs(track.dcaZ()) < cfgTrackCuts.cfgCutDCAz)) { return false; + } if (cfgPIDConfigs.cfgUseOnlyTPC) { - if (pid == kPions && std::abs(track.tpcNSigmaPi()) > cfgPIDConfigs.cfgTpcCut) + if (pid == kPions && std::abs(track.tpcNSigmaPi()) > cfgPIDConfigs.cfgTpcCut) { return false; - if (pid == kKaons && std::abs(track.tpcNSigmaKa()) > cfgPIDConfigs.cfgTpcCut) + } + if (pid == kKaons && std::abs(track.tpcNSigmaKa()) > cfgPIDConfigs.cfgTpcCut) { return false; - if (pid == kProtons && std::abs(track.tpcNSigmaPr()) > cfgPIDConfigs.cfgTpcCut) + } + if (pid == kProtons && std::abs(track.tpcNSigmaPr()) > cfgPIDConfigs.cfgTpcCut) { return false; + } } else { int partIndex = getNsigmaPID(track); int pidIndex = partIndex; // 1 = pion, 2 = kaon, 3 = proton - if (pidIndex != pid) + if (pidIndex != pid) { return false; + } } return true; @@ -997,8 +1034,9 @@ struct CorrReso { } else { effNch = 1.0; } - if (effNch == 0) + if (effNch == 0) { return false; + } weightNch = 1. / effNch; return true; } @@ -1016,8 +1054,9 @@ struct CorrReso { } else { eff = 1.0; } - if (eff == 0) + if (eff == 0) { return false; + } weight = 1. / eff; return true; } @@ -1029,11 +1068,6 @@ struct CorrReso { float weightNch = 1.0f; for (auto const& track : tracks) { - if (cfgRefMultiplicity) { - if (track.pt() > cfgRefpTMax) - continue; - } - if (!getEfficiencyCorrectionNch(weightNch, track.pt())) { continue; } @@ -1056,7 +1090,7 @@ struct CorrReso { continue; } - if (!getEfficiencyCorrection(weff1, track1.eta(), track1.pt(), zvtx)) { + if (!getEfficiencyCorrection(weff1, track1.pt(), track1.eta(), zvtx)) { continue; } @@ -1078,43 +1112,53 @@ struct CorrReso { auto negtrack = candidate.template negTrack_as(); registry.fill(HIST("hK0Count"), 0.5); - if (postrack.pt() < cfgPIDConfigs.cfgResoCuts->getData()[kPosTrackPt][iK0] || negtrack.pt() < cfgPIDConfigs.cfgResoCuts->getData()[kNegTrackPt][iK0]) + if (postrack.pt() < resoCutVals[kPosTrackPt][iK0] || negtrack.pt() < resoCutVals[kNegTrackPt][iK0]) { return false; + } registry.fill(HIST("hK0Count"), 1.5); - if (mk0 < cfgPIDConfigs.cfgResoCuts->getData()[kMassMin][iK0] && mk0 > cfgPIDConfigs.cfgResoCuts->getData()[kMassMax][iK0]) + if (mk0 < resoCutVals[kMassMin][iK0] || mk0 > resoCutVals[kMassMax][iK0]) { return false; + } registry.fill(HIST("hK0Count"), 2.5); // Rapidity correction - if (candidate.yK0Short() > cfgPIDConfigs.cfgResoCuts->getData()[kRapidity][iK0]) + if (std::abs(candidate.yK0Short()) > resoCutVals[kRapidity][iK0]) { return false; + } registry.fill(HIST("hK0Count"), 3.5); // DCA cuts for K0short - if (std::abs(candidate.dcapostopv()) < cfgPIDConfigs.cfgResoCuts->getData()[kDCAPosToPVMin][iK0] || std::abs(candidate.dcanegtopv()) < cfgPIDConfigs.cfgResoCuts->getData()[kDCANegToPVMin][iK0]) + if (std::abs(candidate.dcapostopv()) < resoCutVals[kDCAPosToPVMin][iK0] || std::abs(candidate.dcanegtopv()) < resoCutVals[kDCANegToPVMin][iK0]) { return false; + } registry.fill(HIST("hK0Count"), 4.5); - if (std::abs(candidate.dcaV0daughters()) > cfgPIDConfigs.cfgResoSwitches->getData()[kDCABetDaug][iK0]) + if (resoSwitchVals[kUseDCABetDaug][iK0] && std::abs(candidate.dcaV0daughters()) > resoCutVals[kDCABetDaug][iK0]) { return false; + } registry.fill(HIST("hK0Count"), 5.5); // v0 radius cuts - if (cfgPIDConfigs.cfgResoSwitches->getData()[kUseV0Radius][iK0] && (candidate.v0radius() < cfgPIDConfigs.cfgResoCuts->getData()[kRadiusMin][iK0] || candidate.v0radius() > cfgPIDConfigs.cfgResoCuts->getData()[kRadiusMax][iK0])) + if (resoSwitchVals[kUseV0Radius][iK0] && (candidate.v0radius() < resoCutVals[kRadiusMin][iK0] || candidate.v0radius() > resoCutVals[kRadiusMax][iK0])) { return false; + } registry.fill(HIST("hK0Count"), 6.5); // cosine pointing angle cuts - if (candidate.v0cosPA() < cfgPIDConfigs.cfgResoCuts->getData()[kCosPA][iK0]) + if (resoSwitchVals[kUseCosPA][iK0] && candidate.v0cosPA() < resoCutVals[kCosPA][iK0]) { return false; + } registry.fill(HIST("hK0Count"), 7.5); // Proper lifetime float cTauK0 = candidate.distovertotmom(posX, posY, posZ) * massK0Short; - if (cfgPIDConfigs.cfgResoSwitches->getData()[kUseProperLifetime][iK0] && std::abs(cTauK0) > cfgPIDConfigs.cfgResoCuts->getData()[kLifeTime][iK0]) + if (resoSwitchVals[kUseProperLifetime][iK0] && cTauK0 > resoCutVals[kLifeTime][iK0]) { return false; + } registry.fill(HIST("hK0Count"), 8.5); // ArmenterosPodolanskiCut - if (cfgPIDConfigs.cfgResoSwitches->getData()[kUseArmPodCut][iK0] && (candidate.qtarm() / std::abs(candidate.alpha())) < cfgPIDConfigs.cfgResoCuts->getData()[kArmPodMinVal][iK0]) + if (resoSwitchVals[kUseArmPodCut][iK0] && (candidate.qtarm() / std::abs(candidate.alpha())) < resoCutVals[kArmPodMinVal][iK0]) { return false; + } registry.fill(HIST("hK0Count"), 9.5); // Selection on V0 daughters - if (!selectionV0Daughter(postrack, kPions) || !selectionV0Daughter(negtrack, kPions)) + if (!selectionV0Daughter(postrack, kPions) || !selectionV0Daughter(negtrack, kPions)) { return false; + } registry.fill(HIST("hK0Count"), 10.5); registry.fill(HIST("hK0Phi"), candidate.phi()); @@ -1141,14 +1185,16 @@ struct CorrReso { auto negtrack = candidate.template negTrack_as(); registry.fill(HIST("hLambdaCount"), 0.5); - if (postrack.pt() < cfgPIDConfigs.cfgResoCuts->getData()[kPosTrackPt][iLambda] || negtrack.pt() < cfgPIDConfigs.cfgResoCuts->getData()[kNegTrackPt][iLambda]) + if (postrack.pt() < resoCutVals[kPosTrackPt][iLambda] || negtrack.pt() < resoCutVals[kNegTrackPt][iLambda]) { return false; - + } registry.fill(HIST("hLambdaCount"), 1.5); - if (mlambda > cfgPIDConfigs.cfgResoCuts->getData()[kMassMin][iLambda] && mlambda < cfgPIDConfigs.cfgResoCuts->getData()[kMassMax][iLambda]) + if (mlambda > resoCutVals[kMassMin][iLambda] && mlambda < resoCutVals[kMassMax][iLambda]) { isL = true; - if (mantilambda > cfgPIDConfigs.cfgResoCuts->getData()[kMassMin][iLambda] && mantilambda < cfgPIDConfigs.cfgResoCuts->getData()[kMassMax][iLambda]) + } + if (mantilambda > resoCutVals[kMassMin][iLambda] && mantilambda < resoCutVals[kMassMax][iLambda]) { isAL = true; + } if (!isL && !isAL) { return false; @@ -1156,48 +1202,57 @@ struct CorrReso { registry.fill(HIST("hLambdaCount"), 2.5); // Rapidity correction - if (candidate.yLambda() > cfgPIDConfigs.cfgResoCuts->getData()[kRapidity][iLambda]) + if (std::abs(candidate.yLambda()) > resoCutVals[kRapidity][iLambda]) { return false; + } registry.fill(HIST("hLambdaCount"), 3.5); + // DCA cuts for lambda and antilambda - if (isL) { - if (std::abs(candidate.dcapostopv()) < cfgPIDConfigs.cfgResoCuts->getData()[kDCAPosToPVMin][iLambda] || std::abs(candidate.dcanegtopv()) < cfgPIDConfigs.cfgResoCuts->getData()[kDCANegToPVMin][iLambda]) - return false; + if (isL && (std::abs(candidate.dcapostopv()) < resoCutVals[kDCAPosToPVMin][iLambda] || std::abs(candidate.dcanegtopv()) < resoCutVals[kDCANegToPVMin][iLambda])) { + isL = false; } - if (isAL) { - if (std::abs(candidate.dcapostopv()) < cfgPIDConfigs.cfgResoCuts->getData()[kDCANegToPVMin][iLambda] || std::abs(candidate.dcanegtopv()) < cfgPIDConfigs.cfgResoCuts->getData()[kDCAPosToPVMin][iLambda]) - return false; + if (isAL && (std::abs(candidate.dcapostopv()) < resoCutVals[kDCANegToPVMin][iLambda] || std::abs(candidate.dcanegtopv()) < resoCutVals[kDCAPosToPVMin][iLambda])) { + isAL = false; + } + if (!isL && !isAL) { + return false; } registry.fill(HIST("hLambdaCount"), 4.5); - if (std::abs(candidate.dcaV0daughters()) > cfgPIDConfigs.cfgResoSwitches->getData()[kDCABetDaug][iLambda]) + if (resoSwitchVals[kUseDCABetDaug][iLambda] && std::abs(candidate.dcaV0daughters()) > resoCutVals[kDCABetDaug][iLambda]) { return false; + } registry.fill(HIST("hLambdaCount"), 5.5); // v0 radius cuts - if (cfgPIDConfigs.cfgResoSwitches->getData()[kUseV0Radius][iLambda] && (candidate.v0radius() < cfgPIDConfigs.cfgResoCuts->getData()[kRadiusMin][iLambda] || candidate.v0radius() > cfgPIDConfigs.cfgResoCuts->getData()[kRadiusMax][iLambda])) + if (resoSwitchVals[kUseV0Radius][iLambda] && (candidate.v0radius() < resoCutVals[kRadiusMin][iLambda] || candidate.v0radius() > resoCutVals[kRadiusMax][iLambda])) { return false; + } registry.fill(HIST("hLambdaCount"), 6.5); // cosine pointing angle cuts - if (candidate.v0cosPA() < cfgPIDConfigs.cfgResoCuts->getData()[kCosPA][iLambda]) + if (resoSwitchVals[kUseCosPA][iLambda] && candidate.v0cosPA() < resoCutVals[kCosPA][iLambda]) { return false; + } registry.fill(HIST("hLambdaCount"), 7.5); // Proper lifetime float cTauLambda = candidate.distovertotmom(posX, posY, posZ) * massLambda; - if (cfgPIDConfigs.cfgResoSwitches->getData()[kUseProperLifetime][iLambda] && cTauLambda > cfgPIDConfigs.cfgResoCuts->getData()[kLifeTime][iLambda]) + if (resoSwitchVals[kUseProperLifetime][iLambda] && cTauLambda > resoCutVals[kLifeTime][iLambda]) { return false; + } registry.fill(HIST("hLambdaCount"), 8.5); + if (isL) { - if (!selectionV0Daughter(postrack, kProtons) || !selectionV0Daughter(negtrack, kPions)) - return false; + if (!selectionV0Daughter(postrack, kProtons) || !selectionV0Daughter(negtrack, kPions)) { + isL = false; + } } if (isAL) { - if (!selectionV0Daughter(postrack, kPions) || !selectionV0Daughter(negtrack, kProtons)) - return false; + if (!selectionV0Daughter(postrack, kPions) || !selectionV0Daughter(negtrack, kProtons)) { + isAL = false; + } } - registry.fill(HIST("hLambdaCount"), 9.5); - - if (!cfgPIDConfigs.cfgUseAntiLambda && isAL) { // Reject the track if it is antilambda + if (!isL && !isAL) { return false; } + registry.fill(HIST("hLambdaCount"), 9.5); registry.fill(HIST("hLambdaPhi"), candidate.phi()); registry.fill(HIST("hLambdaEta"), candidate.eta()); @@ -1207,7 +1262,7 @@ struct CorrReso { registry.fill(HIST("PiMinusTPC_La"), negtrack.pt(), negtrack.tpcNSigmaPi()); registry.fill(HIST("PiMinusTOF_La"), negtrack.pt(), negtrack.tofNSigmaPi()); } - if (cfgPIDConfigs.cfgUseAntiLambda && isAL) { + if (isAL) { registry.fill(HIST("PrMinusTPC_Al"), negtrack.pt(), negtrack.tpcNSigmaPr()); registry.fill(HIST("PrMinusTOF_Al"), negtrack.pt(), negtrack.tofNSigmaPr()); registry.fill(HIST("PiPlusTPC_Al"), postrack.pt(), postrack.tpcNSigmaPi()); @@ -1229,15 +1284,17 @@ struct CorrReso { // 4 = kshort, 5 = lambda, 6 = phi if (cfgPIDConfigs.cfgPIDParticle == kK0) { - if (!isSelectedK0(track1, posZ, posY, posX)) + if (!isSelectedK0(track1, posZ, posY, posX)) { continue; // Reject if called for K0 but V0 is not K0 + } resoMass = track1.mK0Short(); } if (cfgPIDConfigs.cfgPIDParticle == kLambda) { - if (!isSelectedLambda(track1, posZ, posY, posX)) + if (!isSelectedLambda(track1, posZ, posY, posX)) { continue; // Reject if called for Lambda but V0 is not lambda + } resoMass = track1.mLambda(); } @@ -1325,13 +1382,15 @@ struct CorrReso { eventSelectedIndividually(collision); } - if (!collision.sel8()) + if (!collision.sel8()) { return; + } registry.fill(HIST("hEventCount"), kAfterSel8); - if (!eventRct(collision, true)) + if (!eventRct(collision, true)) { return; + } auto bc = collision.bc_as(); @@ -1341,11 +1400,13 @@ struct CorrReso { return; } - if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), true)) + if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), true)) { return; + } - if (!collision.has_foundFT0()) + if (!collision.has_foundFT0()) { return; + } loadAlignParam(bc.timestamp()); loadGain(bc); @@ -1360,8 +1421,9 @@ struct CorrReso { double multiplicity = static_cast(tracks.size()); - if (cfgQaCheck) + if (cfgQaCheck) { registry.fill(HIST("Nch"), multiplicity); + } if (cfgStrictTrackCounter) { trackCounter(tracks, multiplicity); @@ -1382,7 +1444,6 @@ struct CorrReso { void processMixedTpcFt0a(FilteredCollisions const& collisions, FilteredTracks const& tracks, aod::FT0s const&, aod::BCsWithTimestamps const&, aod::V0Datas const& V0s) { - auto getTracksSize = [&tracks, this](FilteredCollisions::iterator const& collision) { auto associatedTracks = tracks.sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), this->cache); auto mult = associatedTracks.size(); @@ -1398,36 +1459,42 @@ struct CorrReso { for (auto it = pairs.begin(); it != pairs.end(); it++) { auto& [collision1, v0s1, collision2, tracks2] = *it; - if (!collision1.sel8() || !collision2.sel8()) + if (!collision1.sel8() || !collision2.sel8()) { continue; + } - if (!eventRct(collision1, false) || !eventRct(collision2, false)) + if (!eventRct(collision1, false) || !eventRct(collision2, false)) { continue; + } auto tracks1 = tracks.sliceByCached(o2::aod::track::collisionId, collision1.globalIndex(), this->cache); - if (cfgUseAdditionalEventCut && !eventSelected(collision1, tracks1.size(), false)) + if (cfgUseAdditionalEventCut && !eventSelected(collision1, tracks1.size(), false)) { continue; - if (cfgUseAdditionalEventCut && !eventSelected(collision2, tracks2.size(), false)) + } + if (cfgUseAdditionalEventCut && !eventSelected(collision2, tracks2.size(), false)) { continue; + } - if (!(collision1.has_foundFT0() && collision2.has_foundFT0())) + if (!(collision1.has_foundFT0() && collision2.has_foundFT0())) { continue; + } registry.fill(HIST("eventcount"), MixedEvent); // fill the mixed event in the 3 bin auto bc = collision1.bc_as(); int currentRunNumber = bc.runNumber(); if (!cfgRunRemoveList.value.empty()) { - if (!isGoodRun(currentRunNumber)) // Rejects runs if bad run number + if (!isGoodRun(currentRunNumber)) { // Rejects runs if bad run number continue; + } } loadAlignParam(bc.timestamp()); loadCorrection(bc.timestamp()); float eventWeight = 1.0f; - double multiplicity = static_cast(tracks.size()); + double multiplicity = static_cast(tracks1.size()); if (cfgStrictTrackCounter) { trackCounter(tracks1, multiplicity); @@ -1451,25 +1518,30 @@ struct CorrReso { eventSelectedIndividually(collision); } - if (!collision.sel8()) + if (!collision.sel8()) { return; + } registry.fill(HIST("hEventCount"), kAfterSel8); - if (!eventRct(collision, true)) + if (!eventRct(collision, true)) { return; + } auto bc = collision.bc_as(); int currentRunNumber = bc.runNumber(); if (!cfgRunRemoveList.value.empty()) { - if (!isGoodRun(currentRunNumber)) // Rejects runs if bad run number + if (!isGoodRun(currentRunNumber)) { // Rejects runs if bad run number return; + } } - if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), true)) + if (cfgUseAdditionalEventCut && !eventSelected(collision, tracks.size(), true)) { return; - if (!collision.has_foundFT0()) + } + if (!collision.has_foundFT0()) { return; + } loadAlignParam(bc.timestamp()); loadGain(bc); loadCorrection(bc.timestamp()); @@ -1482,8 +1554,9 @@ struct CorrReso { double multiplicity = static_cast(tracks.size()); - if (cfgQaCheck) + if (cfgQaCheck) { registry.fill(HIST("Nch"), multiplicity); + } if (cfgStrictTrackCounter) { trackCounter(tracks, multiplicity); @@ -1518,29 +1591,35 @@ struct CorrReso { Pair pairs{binningOnVtxAndMult, cfgMinMixEventNum, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip for (auto it = pairs.begin(); it != pairs.end(); it++) { auto& [collision1, v0s1, collision2, tracks2] = *it; - if (!collision1.sel8() || !collision2.sel8()) + if (!collision1.sel8() || !collision2.sel8()) { continue; + } - if (!eventRct(collision1, false) || !eventRct(collision2, false)) + if (!eventRct(collision1, false) || !eventRct(collision2, false)) { continue; + } auto tracks1 = tracks.sliceByCached(o2::aod::track::collisionId, collision1.globalIndex(), this->cache); - if (cfgUseAdditionalEventCut && !eventSelected(collision1, tracks1.size(), false)) + if (cfgUseAdditionalEventCut && !eventSelected(collision1, tracks1.size(), false)) { continue; + } - if (cfgUseAdditionalEventCut && !eventSelected(collision2, tracks2.size(), false)) + if (cfgUseAdditionalEventCut && !eventSelected(collision2, tracks2.size(), false)) { continue; + } - if (!(collision1.has_foundFT0() && collision2.has_foundFT0())) + if (!(collision1.has_foundFT0() && collision2.has_foundFT0())) { continue; + } registry.fill(HIST("eventcount"), MixedEvent); // fill the mixed event in the 3 bin auto bc = collision1.bc_as(); int currentRunNumber = bc.runNumber(); if (!cfgRunRemoveList.value.empty()) { - if (!isGoodRun(currentRunNumber)) // Rejects runs if bad run number + if (!isGoodRun(currentRunNumber)) { // Rejects runs if bad run number continue; + } } loadAlignParam(bc.timestamp()); loadCorrection(bc.timestamp()); diff --git a/PWGCF/TwoParticleCorrelations/Tasks/lambdaOrAntiLambdaProducerWithSpin.cxx b/PWGCF/TwoParticleCorrelations/Tasks/lambdaOrAntiLambdaProducerWithSpin.cxx new file mode 100644 index 00000000000..a228a55a528 --- /dev/null +++ b/PWGCF/TwoParticleCorrelations/Tasks/lambdaOrAntiLambdaProducerWithSpin.cxx @@ -0,0 +1,2179 @@ +// 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. + +/// \file lambdaOrAntiLambdaProducerWithSpin.cxx +/// \brief Produces Lambda and anti-Lambda candidates and analyzes their spin correlations +/// \author Akash Raj (akash.raj.john.babu@cern.ch) + +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; + +/*void customize(std::vector& workflowOptions) +{ + workflowOptions.push_back( + {"isMC", VariantType::Bool, false, {"Run the Monte Carlo analysis workflow"}}); +}*/ + +#include + +// Defining Lambda & Anti-Lambda Table + +namespace o2::aod +{ +namespace lambdaorantilambda +{ +// Event information +DECLARE_SOA_INDEX_COLUMN(Collision, collision); +DECLARE_SOA_COLUMN(Centrality, centrality, float); +DECLARE_SOA_COLUMN(Multiplicity, multiplicity, float); +DECLARE_SOA_COLUMN(Sel8, sel8, bool); +DECLARE_SOA_COLUMN(VertexZ, vertexZ, float); + +// false = Lambda hypothesis +// true = anti-Lambda hypothesis +DECLARE_SOA_COLUMN(IsAntiLambdaHypothesis, isAntiLambdaHypothesis, bool); + +// V0 kinematics +DECLARE_SOA_COLUMN(Px, px, float); +DECLARE_SOA_COLUMN(Py, py, float); +DECLARE_SOA_COLUMN(Pz, pz, float); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Rapidity, rapidity, float); + +// Hypothesis-dependent invariant mass +DECLARE_SOA_COLUMN(Mass, mass, float); + +// V0 topology +DECLARE_SOA_COLUMN(CosPA, cosPA, float); +DECLARE_SOA_COLUMN(CTau, cTau, float); +DECLARE_SOA_COLUMN(V0Radius, v0Radius, float); +DECLARE_SOA_COLUMN(DcaDau, dcaDau, float); +DECLARE_SOA_COLUMN(DcaV0ToPV, dcaV0ToPV, float); + +// Proton for Lambda; antiproton for anti-Lambda +DECLARE_SOA_COLUMN(ProtonPx, protonPx, float); +DECLARE_SOA_COLUMN(ProtonPy, protonPy, float); +DECLARE_SOA_COLUMN(ProtonPz, protonPz, float); +DECLARE_SOA_COLUMN(ProtonPt, protonPt, float); +DECLARE_SOA_COLUMN(ProtonEta, protonEta, float); +DECLARE_SOA_COLUMN(ProtonPhi, protonPhi, float); +DECLARE_SOA_COLUMN(ProtonDcaToPV, protonDcaToPV, float); +DECLARE_SOA_COLUMN(ProtonTrackId, protonTrackId, int64_t); + +// Pion information +DECLARE_SOA_COLUMN(PionPx, pionPx, float); +DECLARE_SOA_COLUMN(PionPy, pionPy, float); +DECLARE_SOA_COLUMN(PionPz, pionPz, float); +DECLARE_SOA_COLUMN(PionPt, pionPt, float); +DECLARE_SOA_COLUMN(PionEta, pionEta, float); +DECLARE_SOA_COLUMN(PionPhi, pionPhi, float); +DECLARE_SOA_COLUMN(PionDcaToPV, pionDcaToPV, float); +DECLARE_SOA_COLUMN(PionTrackId, pionTrackId, int64_t); + +// Original positive/negative daughter indices +DECLARE_SOA_COLUMN(PosTrackId, posTrackId, int64_t); +DECLARE_SOA_COLUMN(NegTrackId, negTrackId, int64_t); + +// Armenteros–Podolanski variables +DECLARE_SOA_COLUMN(Alpha, alpha, float); +DECLARE_SOA_COLUMN(QtArm, qtArm, float); + +} // namespace lambdaorantilambda + +DECLARE_SOA_TABLE(LambdaOrAntiLambdas, + "AOD", + "LAMORANTILAM", + o2::soa::Index<>, + + lambdaorantilambda::CollisionId, + lambdaorantilambda::Centrality, + lambdaorantilambda::Multiplicity, + lambdaorantilambda::Sel8, + lambdaorantilambda::VertexZ, + + lambdaorantilambda::IsAntiLambdaHypothesis, + + lambdaorantilambda::Px, + lambdaorantilambda::Py, + lambdaorantilambda::Pz, + lambdaorantilambda::Pt, + lambdaorantilambda::Eta, + lambdaorantilambda::Phi, + lambdaorantilambda::Rapidity, + + lambdaorantilambda::Mass, + + lambdaorantilambda::CosPA, + lambdaorantilambda::CTau, + lambdaorantilambda::V0Radius, + lambdaorantilambda::DcaDau, + lambdaorantilambda::DcaV0ToPV, + + lambdaorantilambda::ProtonPx, + lambdaorantilambda::ProtonPy, + lambdaorantilambda::ProtonPz, + lambdaorantilambda::ProtonPt, + lambdaorantilambda::ProtonEta, + lambdaorantilambda::ProtonPhi, + lambdaorantilambda::ProtonDcaToPV, + lambdaorantilambda::ProtonTrackId, + + lambdaorantilambda::PionPx, + lambdaorantilambda::PionPy, + lambdaorantilambda::PionPz, + lambdaorantilambda::PionPt, + lambdaorantilambda::PionEta, + lambdaorantilambda::PionPhi, + lambdaorantilambda::PionDcaToPV, + lambdaorantilambda::PionTrackId, + + lambdaorantilambda::PosTrackId, + lambdaorantilambda::NegTrackId, + + lambdaorantilambda::Alpha, + lambdaorantilambda::QtArm); + +namespace lambdahyperon +{ +DECLARE_SOA_INDEX_COLUMN(Collision, collision); + +DECLARE_SOA_COLUMN(Centrality, centrality, float); +DECLARE_SOA_COLUMN(Multiplicity, multiplicity, float); + +DECLARE_SOA_COLUMN(Px, px, float); +DECLARE_SOA_COLUMN(Py, py, float); +DECLARE_SOA_COLUMN(Pz, pz, float); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Rapidity, rapidity, float); +DECLARE_SOA_COLUMN(Mass, mass, float); + +// Proton for Lambda; antiproton for anti-Lambda. +DECLARE_SOA_COLUMN(ProtonPx, protonPx, float); +DECLARE_SOA_COLUMN(ProtonPy, protonPy, float); +DECLARE_SOA_COLUMN(ProtonPz, protonPz, float); + +DECLARE_SOA_COLUMN(PosTrackId, posTrackId, int64_t); +DECLARE_SOA_COLUMN(NegTrackId, negTrackId, int64_t); + +DECLARE_SOA_COLUMN(CosPA, cosPA, float); +DECLARE_SOA_COLUMN(DcaDau, dcaDau, float); +DECLARE_SOA_COLUMN(DcaV0ToPV, dcaV0ToPV, float); +DECLARE_SOA_COLUMN(ProtonDcaToPV, protonDcaToPV, float); +DECLARE_SOA_COLUMN(PionDcaToPV, pionDcaToPV, float); +DECLARE_SOA_COLUMN(V0Radius, v0Radius, float); +DECLARE_SOA_COLUMN(Alpha, alpha, float); +DECLARE_SOA_COLUMN(QtArm, qtArm, float); +} // namespace lambdahyperon + +DECLARE_SOA_TABLE(Lambdas, "AOD", "LAMBDAS", o2::soa::Index<>, + lambdahyperon::CollisionId, + lambdahyperon::Centrality, lambdahyperon::Multiplicity, + lambdahyperon::Px, lambdahyperon::Py, lambdahyperon::Pz, + lambdahyperon::Pt, lambdahyperon::Eta, lambdahyperon::Phi, + lambdahyperon::Rapidity, lambdahyperon::Mass, + lambdahyperon::ProtonPx, lambdahyperon::ProtonPy, lambdahyperon::ProtonPz, + lambdahyperon::PosTrackId, lambdahyperon::NegTrackId, + lambdahyperon::CosPA, lambdahyperon::DcaDau, lambdahyperon::DcaV0ToPV, + lambdahyperon::ProtonDcaToPV, lambdahyperon::PionDcaToPV, + lambdahyperon::V0Radius, lambdahyperon::Alpha, lambdahyperon::QtArm); + +DECLARE_SOA_TABLE(AntiLambdas, "AOD", "ANTILAMBDAS", o2::soa::Index<>, + lambdahyperon::CollisionId, + lambdahyperon::Centrality, lambdahyperon::Multiplicity, + lambdahyperon::Px, lambdahyperon::Py, lambdahyperon::Pz, + lambdahyperon::Pt, lambdahyperon::Eta, lambdahyperon::Phi, + lambdahyperon::Rapidity, lambdahyperon::Mass, + lambdahyperon::ProtonPx, lambdahyperon::ProtonPy, lambdahyperon::ProtonPz, + lambdahyperon::PosTrackId, lambdahyperon::NegTrackId, + lambdahyperon::CosPA, lambdahyperon::DcaDau, lambdahyperon::DcaV0ToPV, + lambdahyperon::ProtonDcaToPV, lambdahyperon::PionDcaToPV, + lambdahyperon::V0Radius, lambdahyperon::Alpha, lambdahyperon::QtArm); + +// ===================================================================== +// MC-reconstructed Lambda/anti-Lambda candidates +// One row per reconstructed V0 candidate +// ===================================================================== + +namespace mcrecolambda +{ +// Reconstructed-event information +DECLARE_SOA_INDEX_COLUMN(Collision, collision); +DECLARE_SOA_COLUMN(Sel8, sel8, bool); +DECLARE_SOA_COLUMN(VertexZ, vertexZ, float); + +// MC truth matching +DECLARE_SOA_COLUMN(HasMcMatch, hasMcMatch, bool); +DECLARE_SOA_COLUMN(IsAntiLambda, isAntiLambda, bool); +DECLARE_SOA_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, bool); + +// Generated kinematics of the matched Lambda/anti-Lambda +DECLARE_SOA_COLUMN(GenPx, genPx, float); +DECLARE_SOA_COLUMN(GenPy, genPy, float); +DECLARE_SOA_COLUMN(GenPz, genPz, float); +DECLARE_SOA_COLUMN(GenPt, genPt, float); +DECLARE_SOA_COLUMN(GenEta, genEta, float); +DECLARE_SOA_COLUMN(GenPhi, genPhi, float); +DECLARE_SOA_COLUMN(GenRapidity, genRapidity, float); + +// Reconstructed V0 kinematics +DECLARE_SOA_COLUMN(RecoPx, recoPx, float); +DECLARE_SOA_COLUMN(RecoPy, recoPy, float); +DECLARE_SOA_COLUMN(RecoPz, recoPz, float); +DECLARE_SOA_COLUMN(RecoPt, recoPt, float); +DECLARE_SOA_COLUMN(RecoEta, recoEta, float); +DECLARE_SOA_COLUMN(RecoPhi, recoPhi, float); +DECLARE_SOA_COLUMN(RecoRapidity, recoRapidity, float); + +//|pTReco-pTGen| +DECLARE_SOA_COLUMN(PtResolution, ptResolution, float); +// Reconstructed invariant-mass hypotheses +DECLARE_SOA_COLUMN(MassLambda, massLambda, float); + +// Reconstructed V0 topology +DECLARE_SOA_COLUMN(DcaDaughters, dcaDaughters, float); +DECLARE_SOA_COLUMN(DcaV0ToPV, dcaV0ToPV, float); +DECLARE_SOA_COLUMN(CosPA, cosPA, float); +DECLARE_SOA_COLUMN(V0Radius, v0Radius, float); +DECLARE_SOA_COLUMN(CTau, cTau, float); + +// Proton-Or-AntiProton reconstructed daughter +DECLARE_SOA_COLUMN(ProPx, proPx, float); +DECLARE_SOA_COLUMN(ProPy, proPy, float); +DECLARE_SOA_COLUMN(ProPz, proPz, float); +DECLARE_SOA_COLUMN(ProPt, proPt, float); +DECLARE_SOA_COLUMN(ProEta, proEta, float); +DECLARE_SOA_COLUMN(ProPhi, proPhi, float); +DECLARE_SOA_COLUMN(ProDcaToPV, proDcaToPV, float); +DECLARE_SOA_COLUMN(ProTPCCrossedRows, proTPCCrossedRows, int); +DECLARE_SOA_COLUMN(ProTPCNSigma, proTPCNSigma, float); + +// PiePlus-OrPieMinus- reconstructed daughter +DECLARE_SOA_COLUMN(PiePx, piePx, float); +DECLARE_SOA_COLUMN(PiePy, piePy, float); +DECLARE_SOA_COLUMN(PiePz, piePz, float); +DECLARE_SOA_COLUMN(PiePt, piePt, float); +DECLARE_SOA_COLUMN(PieEta, pieEta, float); +DECLARE_SOA_COLUMN(PiePhi, piePhi, float); +DECLARE_SOA_COLUMN(PieDcaToPV, pieDcaToPV, float); +DECLARE_SOA_COLUMN(PieTPCCrossedRows, pieTPCCrossedRows, int); +DECLARE_SOA_COLUMN(PieTPCNSigma, pieTPCNSigma, float); + +} // namespace mcrecolambda + +DECLARE_SOA_TABLE(McRecoLambdaCandidates, + "AOD", + "MCRECOLAMBDA", + + o2::soa::Index<>, + + mcrecolambda::CollisionId, + mcrecolambda::Sel8, + mcrecolambda::VertexZ, + + mcrecolambda::HasMcMatch, + mcrecolambda::IsAntiLambda, + mcrecolambda::IsPhysicalPrimary, + + mcrecolambda::GenPx, + mcrecolambda::GenPy, + mcrecolambda::GenPz, + mcrecolambda::GenPt, + mcrecolambda::GenEta, + mcrecolambda::GenPhi, + mcrecolambda::GenRapidity, + + mcrecolambda::RecoPx, + mcrecolambda::RecoPy, + mcrecolambda::RecoPz, + mcrecolambda::RecoPt, + mcrecolambda::RecoEta, + mcrecolambda::RecoPhi, + mcrecolambda::RecoRapidity, + + mcrecolambda::PtResolution, + + mcrecolambda::MassLambda, + + mcrecolambda::DcaDaughters, + mcrecolambda::DcaV0ToPV, + mcrecolambda::CosPA, + mcrecolambda::V0Radius, + mcrecolambda::CTau, + + mcrecolambda::ProPx, + mcrecolambda::ProPy, + mcrecolambda::ProPz, + mcrecolambda::ProPt, + mcrecolambda::ProEta, + mcrecolambda::ProPhi, + mcrecolambda::ProDcaToPV, + mcrecolambda::ProTPCCrossedRows, + mcrecolambda::ProTPCNSigma, + + mcrecolambda::PiePx, + mcrecolambda::PiePy, + mcrecolambda::PiePz, + mcrecolambda::PiePt, + mcrecolambda::PieEta, + mcrecolambda::PiePhi, + mcrecolambda::PieDcaToPV, + mcrecolambda::PieTPCCrossedRows, + mcrecolambda::PieTPCNSigma); + +// ===================================================================== +// MC-generated Lambda/anti-Lambda candidates +// One row per generated particle +// ===================================================================== + +namespace eveselpassmcgenevent +{ +DECLARE_SOA_INDEX_COLUMN(McCollision, mcCollision); +DECLARE_SOA_COLUMN(NRecoCollisions, nRecoCollisions, int); // Total Number of RecoCollions which is am image of McCollions +DECLARE_SOA_COLUMN(NSel8Collisions, nSel8Collisions, int); // Number of RecoCollions which passed Sel8() +} // namespace eveselpassmcgenevent + +DECLARE_SOA_TABLE(EveSelPassMcGenLambdaCandidates, + "AOD", + "MCGENLAMBDA", + + o2::soa::Index<>, + + eveselpassmcgenevent::McCollisionId, + eveselpassmcgenevent::NRecoCollisions, + eveselpassmcgenevent::NSel8Collisions); + +} // namespace o2::aod + +//*********************************************************************************************************** +// UnFilterred Lambda-LambdaBar Structure (Only TPCnsigma and TPC min CorssRows fillters are applied ) +//*********************************************************************************************************** + +struct LambdaOrAntiLambdaProducerWithSpin { + + Produces + lambdaOrAntiLambdaTable; + + // Produces lambdaTable; + // Produces antilambdaTable; + + HistogramRegistry rLambdaOrAntiLambda{"LambdaORAntiLambda", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + // HistogramRegistry rLambda{"Lambdas", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + // HistogramRegistry rAntiLambda{"AntiLambdas", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + Configurable minTPCCrossedRows{"minTPCCrossedRows", 70, "Minimum number of TPC crossed rows"}; + Configurable maxTPCNSigma{"maxTPCNSigma", 3.0f, "Maximum absolute TPC PID n-sigma"}; + + ConfigurableAxis axisInvariantMass{"axisInvariantMass", {100, 1.08f, 1.2f}, "Invariant-mass axis"}; + ConfigurableAxis axisLambdaAntiLambdaPt{"axisLambdaAntiLambdaPt", {200, 0.f, 10.f}, "LambdaAntiLambda transverse-momentum axis"}; + + void init(InitContext const&) + { + + // Event information + rLambdaOrAntiLambda.add("Event/hCentrality", "Centrality;FT0M centrality (%);entries", HistType::kTH1F, {{100, 0.f, 100.f}}); + rLambdaOrAntiLambda.add("Event/hMultiplicity", "Primary-vertex multiplicity;N_{tracks}^{PV};entries", HistType::kTH1F, {{500, 0.f, 500.f}}); + rLambdaOrAntiLambda.add("Candidate/hHypothesis", "Candidate hypothesis;hypothesis;entries", HistType::kTH1F, {{2, -0.5f, 1.5f}}); + + // V0 kinematics + rLambdaOrAntiLambda.add("Candidate/hPx", "V0 p_{x};p_{x} (GeV/c);entries", HistType::kTH1F, {{200, -10.f, 10.f}}); + rLambdaOrAntiLambda.add("Candidate/hPy", "V0 p_{y};p_{y} (GeV/c);entries", HistType::kTH1F, {{200, -10.f, 10.f}}); + rLambdaOrAntiLambda.add("Candidate/hPz", "V0 p_{z};p_{z} (GeV/c);entries", HistType::kTH1F, {{200, -10.f, 10.f}}); + // rLambdaOrAntiLambda.add("Candidate/hPt", "V0 p_{T};p_{T} (GeV/c);entries", HistType::kTH1F, {{200, 0.f, 10.f}}); + rLambdaOrAntiLambda.add("Candidate/hPt", "V0 p_{T};p_{T} (GeV/c);entries", HistType::kTH1F, {axisLambdaAntiLambdaPt}); + rLambdaOrAntiLambda.add("Candidate/hEta", "V0 pseudorapidity;#eta;entries", HistType::kTH1F, {{100, -2.f, 2.f}}); + rLambdaOrAntiLambda.add("Candidate/hPhi", "V0 azimuth;#varphi;entries", HistType::kTH1F, {{72, 0.f, o2::constants::math::TwoPI}}); + rLambdaOrAntiLambda.add("Candidate/hRapidity", "V0 rapidity;y;entries", HistType::kTH1F, {{100, -2.f, 2.f}}); + rLambdaOrAntiLambda.add("Candidate/hMass", "Reconstructed invariant mass;m_{p#pi} (GeV/c^{2});entries", HistType::kTH1F, {axisInvariantMass}); + rLambdaOrAntiLambda.add("Candidate/hMassVsPt", + "#Lambda invariant mass versus p_{T};" + "p_{T} (GeV/c);" + "m_{#Lambda} (GeV/c^{2})", + HistType::kTH2F, {axisLambdaAntiLambdaPt, axisInvariantMass}); + + // Topology + rLambdaOrAntiLambda.add("Topology/hCosPA", "V0 pointing angle;cos(PA);entries", HistType::kTH1F, {{300, 0.97f, 1.f}}); + rLambdaOrAntiLambda.add("Topology/hCTau", "Lambda proper decay length;c#tau (cm);entries", HistType::kTH1F, {{200, 0.f, 100.f}}); + rLambdaOrAntiLambda.add("Topology/hRadius", "V0 transverse decay radius;r_{xy} (cm);entries", HistType::kTH1F, {{200, 0.f, 200.f}}); + rLambdaOrAntiLambda.add("Topology/hDcaDaughters", "DCA between V0 daughters;DCA (cm);entries", HistType::kTH1F, {{200, 0.f, 5.f}}); + rLambdaOrAntiLambda.add("Topology/hDcaV0ToPV", "V0 DCA to PV;DCA (cm);entries", HistType::kTH1F, {{200, 0.f, 5.f}}); + + // Proton or antiproton + rLambdaOrAntiLambda.add("Proton/hTPCdEdxVsP", "V0 proton/antiproton TPC signal;p_{TPC} (GeV/c);TPC dE/dx (arb. units)", HistType::kTH2F, {{200, 0.f, 10.f}, {500, 0.f, 1000.f}}); + + rLambdaOrAntiLambda.add("Proton/hPx", "Proton/antiproton p_{x};p_{x} (GeV/c);entries", HistType::kTH1F, {{200, -5.f, 5.f}}); + rLambdaOrAntiLambda.add("Proton/hPy", "Proton/antiproton p_{y};p_{y} (GeV/c);entries", HistType::kTH1F, {{200, -5.f, 5.f}}); + rLambdaOrAntiLambda.add("Proton/hPz", "Proton/antiproton p_{z};p_{z} (GeV/c);entries", HistType::kTH1F, {{200, -10.f, 10.f}}); + rLambdaOrAntiLambda.add("Proton/hPt", "Proton/antiproton p_{T};p_{T} (GeV/c);entries", HistType::kTH1F, {{200, 0.f, 5.f}}); + rLambdaOrAntiLambda.add("Proton/hEta", "Proton/antiproton pseudorapidity;#eta;entries", HistType::kTH1F, {{100, -2.f, 2.f}}); + rLambdaOrAntiLambda.add("Proton/hPhi", "Proton/antiproton azimuth;#varphi;entries", HistType::kTH1F, {{72, 0.f, o2::constants::math::TwoPI}}); + rLambdaOrAntiLambda.add("Proton/hDcaToPV", "Proton/antiproton DCA to PV;DCA (cm);entries", HistType::kTH1F, {{200, 0.f, 10.f}}); + + // Pion + rLambdaOrAntiLambda.add("Pion/hTPCdEdxVsP", "V0 pion TPC signal;p_{TPC} (GeV/c);TPC dE/dx (arb. units)", HistType::kTH2F, {{200, 0.f, 10.f}, {500, 0.f, 1000.f}}); + + rLambdaOrAntiLambda.add("Pion/hPx", "Pion p_{x};p_{x} (GeV/c);entries", HistType::kTH1F, {{200, -5.f, 5.f}}); + rLambdaOrAntiLambda.add("Pion/hPy", "Pion p_{y};p_{y} (GeV/c);entries", HistType::kTH1F, {{200, -5.f, 5.f}}); + rLambdaOrAntiLambda.add("Pion/hPz", "Pion p_{z};p_{z} (GeV/c);entries", HistType::kTH1F, {{200, -10.f, 10.f}}); + rLambdaOrAntiLambda.add("Pion/hPt", "Pion p_{T};p_{T} (GeV/c);entries", HistType::kTH1F, {{200, 0.f, 5.f}}); + rLambdaOrAntiLambda.add("Pion/hEta", "Pion pseudorapidity;#eta;entries", HistType::kTH1F, {{100, -2.f, 2.f}}); + rLambdaOrAntiLambda.add("Pion/hPhi", "Pion azimuth;#varphi;entries", HistType::kTH1F, {{72, 0.f, o2::constants::math::TwoPI}}); + rLambdaOrAntiLambda.add("Pion/hDcaToPV", "Pion DCA to PV;DCA (cm);entries", HistType::kTH1F, {{200, 0.f, 10.f}}); + + // Armenteros-Podolanski + rLambdaOrAntiLambda.add("Armenteros/hAlpha", "Armenteros #alpha;#alpha;entries", HistType::kTH1F, {{200, -1.f, 1.f}}); + rLambdaOrAntiLambda.add("Armenteros/hQtArm", "Armenteros q_{T};q_{T} (GeV/c);entries", HistType::kTH1F, {{200, 0.f, 0.4f}}); + rLambdaOrAntiLambda.add("Armenteros/hAlphaVsQt", "Armenteros-Podolanski;#alpha;q_{T} (GeV/c)", HistType::kTH2F, {{200, -1.f, 1.f}, {200, 0.f, 0.4f}}); + + auto* hypothesisAxis = rLambdaOrAntiLambda.get(HIST("Candidate/hHypothesis"))->GetXaxis(); + + hypothesisAxis->SetBinLabel(1, "Lambda"); + hypothesisAxis->SetBinLabel(2, "Anti-Lambda"); + } + + using TracksWithPID = soa::Join; + using CollisionsWithActivity = soa::Join; + + void process(aod::V0Datas const& v0s, + TracksWithPID const&, + CollisionsWithActivity const&) + { + + for (auto const& v0 : v0s) { + auto collision = v0.collision_as(); + auto posTrack = v0.posTrack_as(); + auto negTrack = v0.negTrack_as(); + + if (posTrack.tpcNClsCrossedRows() < minTPCCrossedRows || negTrack.tpcNClsCrossedRows() < minTPCCrossedRows) { + continue; + } + + const bool isLambda = + std::abs(posTrack.tpcNSigmaPr()) < maxTPCNSigma && + std::abs(negTrack.tpcNSigmaPi()) < maxTPCNSigma; + + const bool isAntiLambda = + std::abs(negTrack.tpcNSigmaPr()) < maxTPCNSigma && + std::abs(posTrack.tpcNSigmaPi()) < maxTPCNSigma; + + // Reject candidates compatible with neither or with both hypotheses. + if (isLambda == isAntiLambda) { + continue; + } + + const auto& protonORantiprotonTrack = isLambda ? posTrack : negTrack; + + const auto& pionTrack = isLambda ? negTrack : posTrack; + + const float mass = isLambda ? v0.mLambda() : v0.mAntiLambda(); + + const float protonDcaToPV = isLambda ? std::abs(v0.dcapostopv()) : std::abs(v0.dcanegtopv()); + + const float pionDcaToPV = isLambda ? std::abs(v0.dcanegtopv()) : std::abs(v0.dcapostopv()); + + const float cTau = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0; + + lambdaOrAntiLambdaTable( + // Event information + v0.collisionId(), + collision.centFT0M(), + collision.multNTracksPV(), + collision.sel8(), + collision.posZ(), + + // false = Lambda; true = anti-Lambda + isAntiLambda, + + // V0 kinematics + v0.px(), + v0.py(), + v0.pz(), + v0.pt(), + v0.eta(), + v0.phi(), + v0.yLambda(), // Lambda/anti-Lambda rapidity; v0.y() is the decay position. + + // Reconstructed hypothesis-dependent mass + mass, + + // V0 topology + v0.v0cosPA(), + cTau, + v0.v0radius(), + v0.dcaV0daughters(), + v0.dcav0topv(), + + // Proton for Lambda; antiproton for anti-Lambda + protonORantiprotonTrack.px(), + protonORantiprotonTrack.py(), + protonORantiprotonTrack.pz(), + protonORantiprotonTrack.pt(), + protonORantiprotonTrack.eta(), + protonORantiprotonTrack.phi(), + protonDcaToPV, + protonORantiprotonTrack.globalIndex(), + + // Pion + pionTrack.px(), + pionTrack.py(), + pionTrack.pz(), + pionTrack.pt(), + pionTrack.eta(), + pionTrack.phi(), + pionDcaToPV, + pionTrack.globalIndex(), + + // Original positive and negative track IDs + posTrack.globalIndex(), + negTrack.globalIndex(), + + // Armenteros-Podolanski + v0.alpha(), + v0.qtarm()); + + rLambdaOrAntiLambda.fill(HIST("Event/hCentrality"), collision.centFT0M()); + + rLambdaOrAntiLambda.fill(HIST("Event/hMultiplicity"), collision.multNTracksPV()); + + rLambdaOrAntiLambda.fill(HIST("Candidate/hHypothesis"), isAntiLambda ? 1.f : 0.f); + rLambdaOrAntiLambda.fill(HIST("Candidate/hPx"), v0.px()); + rLambdaOrAntiLambda.fill(HIST("Candidate/hPy"), v0.py()); + rLambdaOrAntiLambda.fill(HIST("Candidate/hPz"), v0.pz()); + rLambdaOrAntiLambda.fill(HIST("Candidate/hPt"), v0.pt()); + rLambdaOrAntiLambda.fill(HIST("Candidate/hEta"), v0.eta()); + rLambdaOrAntiLambda.fill(HIST("Candidate/hPhi"), v0.phi()); + rLambdaOrAntiLambda.fill(HIST("Candidate/hRapidity"), v0.yLambda()); + rLambdaOrAntiLambda.fill(HIST("Candidate/hMass"), mass); + rLambdaOrAntiLambda.fill(HIST("Candidate/hMassVsPt"), v0.pt(), mass); + + rLambdaOrAntiLambda.fill(HIST("Topology/hCosPA"), v0.v0cosPA()); + rLambdaOrAntiLambda.fill(HIST("Topology/hCTau"), cTau); + rLambdaOrAntiLambda.fill(HIST("Topology/hRadius"), v0.v0radius()); + rLambdaOrAntiLambda.fill(HIST("Topology/hDcaDaughters"), v0.dcaV0daughters()); + rLambdaOrAntiLambda.fill(HIST("Topology/hDcaV0ToPV"), v0.dcav0topv()); + + rLambdaOrAntiLambda.fill(HIST("Proton/hTPCdEdxVsP"), protonORantiprotonTrack.tpcInnerParam(), protonORantiprotonTrack.tpcSignal()); + rLambdaOrAntiLambda.fill(HIST("Proton/hPx"), protonORantiprotonTrack.px()); + rLambdaOrAntiLambda.fill(HIST("Proton/hPy"), protonORantiprotonTrack.py()); + rLambdaOrAntiLambda.fill(HIST("Proton/hPz"), protonORantiprotonTrack.pz()); + rLambdaOrAntiLambda.fill(HIST("Proton/hPt"), protonORantiprotonTrack.pt()); + rLambdaOrAntiLambda.fill(HIST("Proton/hEta"), protonORantiprotonTrack.eta()); + rLambdaOrAntiLambda.fill(HIST("Proton/hPhi"), protonORantiprotonTrack.phi()); + rLambdaOrAntiLambda.fill(HIST("Proton/hDcaToPV"), protonDcaToPV); + + rLambdaOrAntiLambda.fill(HIST("Pion/hTPCdEdxVsP"), pionTrack.tpcInnerParam(), pionTrack.tpcSignal()); + rLambdaOrAntiLambda.fill(HIST("Pion/hPx"), pionTrack.px()); + rLambdaOrAntiLambda.fill(HIST("Pion/hPy"), pionTrack.py()); + rLambdaOrAntiLambda.fill(HIST("Pion/hPz"), pionTrack.pz()); + rLambdaOrAntiLambda.fill(HIST("Pion/hPt"), pionTrack.pt()); + rLambdaOrAntiLambda.fill(HIST("Pion/hEta"), pionTrack.eta()); + rLambdaOrAntiLambda.fill(HIST("Pion/hPhi"), pionTrack.phi()); + rLambdaOrAntiLambda.fill(HIST("Pion/hDcaToPV"), pionDcaToPV); + + rLambdaOrAntiLambda.fill(HIST("Armenteros/hAlpha"), v0.alpha()); + rLambdaOrAntiLambda.fill(HIST("Armenteros/hQtArm"), v0.qtarm()); + rLambdaOrAntiLambda.fill(HIST("Armenteros/hAlphaVsQt"), v0.alpha(), v0.qtarm()); + } + } +}; + +//*********************************************************************************************************** +// Filltered Lambda-LambdaBar Structure +//*********************************************************************************************************** +struct LambdaAntiLambdaSelector { + Produces lambdaTable; + Produces antiLambdaTable; + + HistogramRegistry rSelected{"Selected", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + ConfigurableAxis axisInvariantMass{"axisInvariantMass", {100, 1.08f, 1.2f}, "Invariant-mass axis"}; + ConfigurableAxis axisPt{"axisPt", {200, 0.f, 10.f}, "transverse-momentum axis"}; + + // HistogramRegistry rSelectedLambda{"SelectedLambdas", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + // HistogramRegistry rSelectedAntiLambda{"SelectedAntiLambdas", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + + void addSelectedHistograms(std::string const& prefix) + { + // Event information + rSelected.add((prefix + "/Event/hCentrality").c_str(), "Centrality;FT0M centrality (%);entries", HistType::kTH1F, {{100, 0.f, 100.f}}); + rSelected.add((prefix + "/Event/hMultiplicity").c_str(), "Primary-vertex multiplicity;N_{tracks}^{PV};entries", HistType::kTH1F, {{500, 0.f, 500.f}}); + + // Candidate kinematics + rSelected.add((prefix + "/Candidate/hPx").c_str(), "Candidate p_{x};p_{x} (GeV/c);entries", HistType::kTH1F, {{200, -10.f, 10.f}}); + rSelected.add((prefix + "/Candidate/hPy").c_str(), "Candidate p_{y};p_{y} (GeV/c);entries", HistType::kTH1F, {{200, -10.f, 10.f}}); + rSelected.add((prefix + "/Candidate/hPz").c_str(), "Candidate p_{z};p_{z} (GeV/c);entries", HistType::kTH1F, {{200, -10.f, 10.f}}); + rSelected.add((prefix + "/Candidate/hPt").c_str(), "Candidate p_{T};p_{T} (GeV/c);entries", HistType::kTH1F, {axisPt}); + rSelected.add((prefix + "/Candidate/hEta").c_str(), "Candidate pseudorapidity;#eta;entries", HistType::kTH1F, {{100, -2.f, 2.f}}); + rSelected.add((prefix + "/Candidate/hPhi").c_str(), "Candidate azimuth;#varphi;entries", HistType::kTH1F, {{72, 0.f, 6.283185307f}}); + rSelected.add((prefix + "/Candidate/hRapidity").c_str(), "Candidate rapidity;y;entries", HistType::kTH1F, {{100, -1.f, 1.f}}); + rSelected.add((prefix + "/Candidate/hMass").c_str(), "Candidate invariant mass;m_{p#pi} (GeV/c^{2});entries", HistType::kTH1F, {axisInvariantMass}); + rSelected.add((prefix + "/Candidate/hMassVsPt").c_str(), + "#Candidate invariant mass versus p_{T};" + "p_{T} (GeV/c);" + "m_{#Lambda} (GeV/c^{2})", + HistType::kTH2F, {axisPt, axisInvariantMass}); + + // Proton or antiproton momentum + rSelected.add((prefix + "/Proton/hPx").c_str(), "Proton/antiproton p_{x};p_{x} (GeV/c);entries", HistType::kTH1F, {{200, -5.f, 5.f}}); + rSelected.add((prefix + "/Proton/hPy").c_str(), "Proton/antiproton p_{y};p_{y} (GeV/c);entries", HistType::kTH1F, {{200, -5.f, 5.f}}); + rSelected.add((prefix + "/Proton/hPz").c_str(), "Proton/antiproton p_{z};p_{z} (GeV/c);entries", HistType::kTH1F, {{200, -10.f, 10.f}}); + + // Topology + rSelected.add((prefix + "/Topology/hCosPA").c_str(), "V0 pointing angle;cos(PA);entries", HistType::kTH1F, {{300, 0.97f, 1.f}}); + rSelected.add((prefix + "/Topology/hDcaDaughters").c_str(), "DCA between V0 daughters;DCA (cm);entries", HistType::kTH1F, {{200, 0.f, 5.f}}); + rSelected.add((prefix + "/Topology/hDcaV0ToPV").c_str(), "V0 DCA to primary vertex;DCA (cm);entries", HistType::kTH1F, {{200, 0.f, 5.f}}); + rSelected.add((prefix + "/Topology/hProtonDcaToPV").c_str(), "Proton/antiproton DCA to PV;DCA (cm);entries", HistType::kTH1F, {{200, 0.f, 10.f}}); + rSelected.add((prefix + "/Topology/hPionDcaToPV").c_str(), "Pion DCA to PV;DCA (cm);entries", HistType::kTH1F, {{200, 0.f, 10.f}}); + rSelected.add((prefix + "/Topology/hRadius").c_str(), "V0 transverse decay radius;r_{xy} (cm);entries", HistType::kTH1F, {{200, 0.f, 200.f}}); + + // Armenteros-Podolanski + rSelected.add((prefix + "/Armenteros/hAlpha").c_str(), "Armenteros #alpha;#alpha;entries", HistType::kTH1F, {{200, -1.f, 1.f}}); + rSelected.add((prefix + "/Armenteros/hQtArm").c_str(), "Armenteros q_{T};q_{T} (GeV/c);entries", HistType::kTH1F, {{200, 0.f, 0.4f}}); + rSelected.add((prefix + "/Armenteros/hAlphaVsQt").c_str(), "Armenteros-Podolanski;#alpha;q_{T} (GeV/c)", HistType::kTH2F, {{200, -1.f, 1.f}, {200, 0.f, 0.4f}}); + } + + void init(InitContext const&) + { + addSelectedHistograms("Lambda"); + addSelectedHistograms("AntiLambda"); + } + + template + void fillSelectedHistograms(bool isAntiLambda, + Candidate const& candidate) + { + if (!isAntiLambda) { + rSelected.fill(HIST("Lambda/Event/hCentrality"), candidate.centrality()); + rSelected.fill(HIST("Lambda/Event/hMultiplicity"), candidate.multiplicity()); + + rSelected.fill(HIST("Lambda/Candidate/hPx"), candidate.px()); + rSelected.fill(HIST("Lambda/Candidate/hPy"), candidate.py()); + rSelected.fill(HIST("Lambda/Candidate/hPz"), candidate.pz()); + rSelected.fill(HIST("Lambda/Candidate/hPt"), candidate.pt()); + rSelected.fill(HIST("Lambda/Candidate/hEta"), candidate.eta()); + rSelected.fill(HIST("Lambda/Candidate/hPhi"), candidate.phi()); + rSelected.fill(HIST("Lambda/Candidate/hRapidity"), candidate.rapidity()); + rSelected.fill(HIST("Lambda/Candidate/hMass"), candidate.mass()); + rSelected.fill(HIST("Lambda/Candidate/hMassVsPt"), candidate.pt(), candidate.mass()); + + rSelected.fill(HIST("Lambda/Proton/hPx"), candidate.protonPx()); + rSelected.fill(HIST("Lambda/Proton/hPy"), candidate.protonPy()); + rSelected.fill(HIST("Lambda/Proton/hPz"), candidate.protonPz()); + + rSelected.fill(HIST("Lambda/Topology/hCosPA"), candidate.cosPA()); + rSelected.fill(HIST("Lambda/Topology/hDcaDaughters"), candidate.dcaDau()); + rSelected.fill(HIST("Lambda/Topology/hDcaV0ToPV"), candidate.dcaV0ToPV()); + rSelected.fill(HIST("Lambda/Topology/hProtonDcaToPV"), candidate.protonDcaToPV()); + rSelected.fill(HIST("Lambda/Topology/hPionDcaToPV"), candidate.pionDcaToPV()); + rSelected.fill(HIST("Lambda/Topology/hRadius"), candidate.v0Radius()); + + rSelected.fill(HIST("Lambda/Armenteros/hAlpha"), candidate.alpha()); + rSelected.fill(HIST("Lambda/Armenteros/hQtArm"), candidate.qtArm()); + rSelected.fill(HIST("Lambda/Armenteros/hAlphaVsQt"), candidate.alpha(), candidate.qtArm()); + } else { + rSelected.fill(HIST("AntiLambda/Event/hCentrality"), candidate.centrality()); + rSelected.fill(HIST("AntiLambda/Event/hMultiplicity"), candidate.multiplicity()); + + rSelected.fill(HIST("AntiLambda/Candidate/hPx"), candidate.px()); + rSelected.fill(HIST("AntiLambda/Candidate/hPy"), candidate.py()); + rSelected.fill(HIST("AntiLambda/Candidate/hPz"), candidate.pz()); + rSelected.fill(HIST("AntiLambda/Candidate/hPt"), candidate.pt()); + rSelected.fill(HIST("AntiLambda/Candidate/hEta"), candidate.eta()); + rSelected.fill(HIST("AntiLambda/Candidate/hPhi"), candidate.phi()); + rSelected.fill(HIST("AntiLambda/Candidate/hRapidity"), candidate.rapidity()); + rSelected.fill(HIST("AntiLambda/Candidate/hMass"), candidate.mass()); + rSelected.fill(HIST("AntiLambda/Candidate/hMassVsPt"), candidate.pt(), candidate.mass()); + + rSelected.fill(HIST("AntiLambda/Proton/hPx"), candidate.protonPx()); + rSelected.fill(HIST("AntiLambda/Proton/hPy"), candidate.protonPy()); + rSelected.fill(HIST("AntiLambda/Proton/hPz"), candidate.protonPz()); + + rSelected.fill(HIST("AntiLambda/Topology/hCosPA"), candidate.cosPA()); + rSelected.fill(HIST("AntiLambda/Topology/hDcaDaughters"), candidate.dcaDau()); + rSelected.fill(HIST("AntiLambda/Topology/hDcaV0ToPV"), candidate.dcaV0ToPV()); + rSelected.fill(HIST("AntiLambda/Topology/hProtonDcaToPV"), candidate.protonDcaToPV()); + rSelected.fill(HIST("AntiLambda/Topology/hPionDcaToPV"), candidate.pionDcaToPV()); + rSelected.fill(HIST("AntiLambda/Topology/hRadius"), candidate.v0Radius()); + + rSelected.fill(HIST("AntiLambda/Armenteros/hAlpha"), candidate.alpha()); + rSelected.fill(HIST("AntiLambda/Armenteros/hQtArm"), candidate.qtArm()); + rSelected.fill(HIST("AntiLambda/Armenteros/hAlphaVsQt"), candidate.alpha(), candidate.qtArm()); + } + } + // ================================================================ + // Event selection + // ================================================================ + + Configurable cutZVertex{"cutZVertex", 10.f, "Maximum absolute reconstructed vertex z"}; + + // ================================================================ + // Event selection Filter + // ================================================================ + + Filter selectedLambdaFilter = aod::lambdaorantilambda::sel8 == true && + nabs(aod::lambdaorantilambda::vertexZ) < cutZVertex; + + // ================================================================ + // Daughter-track selection + // ================================================================ + + Configurable minDaughterPt{"minDaughterPt", 0.15f, "Minimum daughter-track pT (GeV/c)"}; + + Configurable maxDaughterEta{"maxDaughterEta", 0.8f, "Maximum absolute daughter-track eta"}; + + // ===================================================================== + // Applying Daughter Filteres + // ===================================================================== + + Filter daughterKinematicFilter = + aod::lambdaorantilambda::protonPt > minDaughterPt&& + + aod::lambdaorantilambda::pionPt > minDaughterPt&& + + nabs(aod::lambdaorantilambda::protonEta) < maxDaughterEta&& + + nabs(aod::lambdaorantilambda::pionEta) < maxDaughterEta; + + // ================================================================ + // V0 topology selection + // ================================================================ + + Configurable maxDcaV0Daughters{"maxDcaV0Daughters", 1.0f, "Maximum DCA between V0 daughters (cm)"}; + + Configurable maxDcaV0ToPV{"maxDcaV0ToPV", 0.1f, "Maximum DCA of V0 to primary vertex (cm)"}; + + Configurable minDcaProtonToPV{"minDcaProtonToPV", 0.02f, "Minimum proton DCA to primary vertex (cm)"}; + + Configurable minDcaPionToPV{"minDcaPionToPV", 0.06f, "Minimum pion DCA to primary vertex (cm)"}; + + Configurable minV0Radius{"minV0Radius", 0.5f, "Minimum transverse V0 decay radius (cm)"}; + + Configurable maxV0CTau{"maxV0CTau", 30.0f, "Maximum Lambda proper decay length c-tau (cm)"}; + + Configurable minV0CosPA{"minV0CosPA", 0.995f, "Minimum cosine of V0 pointing angle"}; + + // ===================================================================== + // Applying V0 topology Filteres + // ===================================================================== + + Filter topologyFilter = + aod::lambdaorantilambda::dcaDau < maxDcaV0Daughters && + + aod::lambdaorantilambda::dcaV0ToPV < maxDcaV0ToPV && + + aod::lambdaorantilambda::protonDcaToPV > minDcaProtonToPV&& + + aod::lambdaorantilambda::pionDcaToPV > minDcaPionToPV&& + + aod::lambdaorantilambda::v0Radius > minV0Radius&& + + aod::lambdaorantilambda::cTau + minV0CosPA; + + // ================================================================ + // Lambda/anti-Lambda invariant-mass selection + // ================================================================ + + // Configurable minLambdaMass{"minLambdaMass", 1.1081f, "Minimum Lambda invariant mass (GeV/c2)"}; + + // Configurable maxLambdaMass{"maxLambdaMass", 1.1231f, "Maximum Lambda invariant mass (GeV/c2)"}; + + // ===================================================================== + // Applying invariant-mass Filteres + // ===================================================================== + + // Filter lambdaInvariantMassFilter = + // aod::lambdaorantilambda::mass > minLambdaMass && + // + // aod::lambdaorantilambda::mass < maxLambdaMass; + + // ================================================================ + // Lambda/anti-Lambda kinematic selection + // ================================================================ + + Configurable minLambdaPt{"minLambdaPt", 0.5f, "Minimum Lambda pT (GeV/c)"}; + + Configurable maxLambdaPt{"maxLambdaPt", 4.5f, "Maximum Lambda pT (GeV/c)"}; + + Configurable maxLambdaRapidity{"maxLambdaRapidity", 0.5f, "Maximum absolute Lambda rapidity"}; + + // ===================================================================== + // Applying Lambda/anti-Lambda kinematic Filteres + // ===================================================================== + + Filter lambdakinematicFilter = + + aod::lambdaorantilambda::pt > minLambdaPt&& + + aod::lambdaorantilambda::pt < maxLambdaPt&& + + nabs(aod::lambdaorantilambda::rapidity) < maxLambdaRapidity; + + // All compatible filters above are combined with logical AND. + using SelectedLambdaOrAntiLambdas = soa::Filtered; + + // ============================================================== + // Lambda and anti-Lambda partitions + // ============================================================== + + Partition + selectedLambdas = aod::lambdaorantilambda::isAntiLambdaHypothesis == false; + + Partition + selectedAntiLambdas = aod::lambdaorantilambda::isAntiLambdaHypothesis == true; + + void process(SelectedLambdaOrAntiLambdas const&) + { + // ============================================================ + // Fill the final Lambda table + // ============================================================ + + for (auto const& candidate : selectedLambdas) { + + fillSelectedHistograms(false, candidate); // Lambda + + lambdaTable( + candidate.collisionId(), + candidate.centrality(), + candidate.multiplicity(), + + candidate.px(), + candidate.py(), + candidate.pz(), + + candidate.pt(), + candidate.eta(), + candidate.phi(), + + candidate.rapidity(), + candidate.mass(), + + candidate.protonPx(), + candidate.protonPy(), + candidate.protonPz(), + + candidate.posTrackId(), + candidate.negTrackId(), + + candidate.cosPA(), + candidate.dcaDau(), + candidate.dcaV0ToPV(), + + candidate.protonDcaToPV(), + candidate.pionDcaToPV(), + + candidate.v0Radius(), + candidate.alpha(), + candidate.qtArm()); + } + + // ============================================================ + // Fill the final anti-Lambda table + // ============================================================ + + for (auto const& candidate : selectedAntiLambdas) { + + fillSelectedHistograms(true, candidate); // anti-Lambda + + antiLambdaTable( + candidate.collisionId(), + candidate.centrality(), + candidate.multiplicity(), + + candidate.px(), + candidate.py(), + candidate.pz(), + + candidate.pt(), + candidate.eta(), + candidate.phi(), + + candidate.rapidity(), + candidate.mass(), + + candidate.protonPx(), + candidate.protonPy(), + candidate.protonPz(), + + candidate.posTrackId(), + candidate.negTrackId(), + + candidate.cosPA(), + candidate.dcaDau(), + candidate.dcaV0ToPV(), + + candidate.protonDcaToPV(), + candidate.pionDcaToPV(), + + candidate.v0Radius(), + candidate.alpha(), + candidate.qtArm()); + } + } +}; + +//*********************************************************************************************************** +// MC Reconstructed and MC Generated Lambda-LambdaBar Table Producer Structure +//*********************************************************************************************************** +struct LambdaAntiLambdaMcRecoTableProducer { + Produces mcRecoTable; + + // ================================================================ + // Daughter-track selection + // ================================================================ + + Configurable maxTPCNSigma{"maxTPCNSigma", 3.f, "Maximum TPC PID n-sigma"}; + + // ================================================================ + // Lambda/anti-Lambda invariant-mass selection + // ================================================================ + + // Configurable minLambdaMass{"minLambdaMass", 1.1081f, "Minimum Lambda invariant mass (GeV/c2)"}; + // Configurable maxLambdaMass{"maxLambdaMass", 1.1231f, "Maximum Lambda invariant mass (GeV/c2)"}; + + // ===================================================================== + // Applying invariant-mass Filteres + // ===================================================================== + + // Filter lambdaInvariantMassFilter = + // aod::v0data::mass > minLambdaMass && + // aod::v0data::mass < maxLambdaMass; + + using DaughterTracks = soa::Join; + using V0CandidatesMC = soa::Join; + // using SelectedV0CandidatesMC = soa::Filtered; + + void processMcReco( + soa::Join::iterator const& collision, + V0CandidatesMC const& V0s, DaughterTracks const&, aod::McParticles const&) + { + + for (const auto& v0 : V0s) { + + auto posTrack = v0.posTrack_as(); + auto negTrack = v0.negTrack_as(); + + const bool isLambda = + std::abs(posTrack.tpcNSigmaPr()) < maxTPCNSigma && + std::abs(negTrack.tpcNSigmaPi()) < maxTPCNSigma; + + const bool isAntiLambda = + std::abs(negTrack.tpcNSigmaPr()) < maxTPCNSigma && + std::abs(posTrack.tpcNSigmaPi()) < maxTPCNSigma; + + if (isLambda == isAntiLambda) { + continue; + } + + // Hypothesis-dependent daughter assignments + const auto& protonTrack = isLambda ? posTrack : negTrack; + const auto& pionTrack = isLambda ? negTrack : posTrack; + + const float protonDcaToPV = isLambda ? std::abs(v0.dcapostopv()) : std::abs(v0.dcanegtopv()); + const float pionDcaToPV = isLambda ? std::abs(v0.dcanegtopv()) : std::abs(v0.dcapostopv()); + + // Hypothesis-dependent reconstructed invariant mass + const float reconstructedMass = + isLambda ? v0.mLambda() : v0.mAntiLambda(); + + // --------------------------------------------------------------- + // Default MC values for an unmatched reconstructed V0 + // --------------------------------------------------------------- + + const bool hasMcMatch = v0.has_mcParticle(); + + // --------------------------------------------------------------- + // Generated quantities for a truth-matched reconstructed V0 + // --------------------------------------------------------------- + + if (!hasMcMatch) { + continue; + } + const auto mcGenParticle = v0.mcParticle(); + + const int pdgCode = mcGenParticle.pdgCode(); + + // Require reconstructed PID hypothesis to agree with MC truth. + const bool correctSpecies = + (isLambda && pdgCode == PDG_t::kLambda0) || + (isAntiLambda && pdgCode == PDG_t::kLambda0Bar); + + if (!correctSpecies) { + continue; + } + + const bool isTrueAntiLambda = (pdgCode == PDG_t::kLambda0Bar); + const bool isPhysicalPrimary = mcGenParticle.isPhysicalPrimary(); + + const float genPx = mcGenParticle.px(); + const float genPy = mcGenParticle.py(); + const float genPz = mcGenParticle.pz(); + const float genPt = mcGenParticle.pt(); + const float genEta = mcGenParticle.eta(); + const float genPhi = mcGenParticle.phi(); + const float genRapidity = mcGenParticle.y(); + + // --------------------------------------------------------------- + // Quantities calculated from the reconstructed candidate + // --------------------------------------------------------------- + + const float cTau = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassLambda0; + const float ptResolution = std::abs(v0.pt() - genPt); + // --------------------------------------------------------------- + // Fill exactly one row for every reconstructed V0 + // --------------------------------------------------------------- + + mcRecoTable( + // Event + collision.globalIndex(), + collision.sel8(), + collision.posZ(), + + // MC truth matching + hasMcMatch, + isTrueAntiLambda, + isPhysicalPrimary, + + // Generated V0 kinematics + genPx, + genPy, + genPz, + genPt, + genEta, + genPhi, + genRapidity, + + // Reconstructed V0 kinematics + v0.px(), + v0.py(), + v0.pz(), + v0.pt(), + v0.eta(), + v0.phi(), + v0.yLambda(), + + //|pTReco-pTGen| + ptResolution, + // Reconstructed mass hypotheses + reconstructedMass, + + // Reconstructed topology + v0.dcaV0daughters(), + v0.dcav0topv(), + v0.v0cosPA(), + v0.v0radius(), + cTau, + + // Positive daughter + protonTrack.px(), + protonTrack.py(), + protonTrack.pz(), + protonTrack.pt(), + protonTrack.eta(), + protonTrack.phi(), + protonDcaToPV, + static_cast(protonTrack.tpcNClsCrossedRows()), + protonTrack.tpcNSigmaPr(), + + // Negative daughter + pionTrack.px(), + pionTrack.py(), + pionTrack.pz(), + pionTrack.pt(), + pionTrack.eta(), + pionTrack.phi(), + pionDcaToPV, + static_cast(pionTrack.tpcNClsCrossedRows()), + pionTrack.tpcNSigmaPi()); + } + } + + Configurable cutZVertexMcGen{"cutZVertexMcGen", 10.f, "Maximum reconstructed vertex z for MCGen event selection"}; + + using RecoCollisionsMC = soa::Join; + + Produces mcGenEventSelectedTable; + + void processEveSelPassedMcGenTable(aod::McCollisions::iterator const& mcCollision, + soa::SmallGroups const& recoCollisions) + { + int nRecoCollisions = 0; + int nSel8Collisions = 0; + + for (const auto& recoCollision : recoCollisions) { + ++nRecoCollisions; + + if (recoCollision.sel8() && std::abs(recoCollision.posZ()) < cutZVertexMcGen) { + ++nSel8Collisions; + } + } + + mcGenEventSelectedTable( + mcCollision.globalIndex(), + nRecoCollisions, + nSel8Collisions); + } + + PROCESS_SWITCH(LambdaAntiLambdaMcRecoTableProducer, processMcReco, "Produce MC reconstructed table", false); + PROCESS_SWITCH(LambdaAntiLambdaMcRecoTableProducer, processEveSelPassedMcGenTable, "Produce MC generated table", false); +}; +//*********************************************************************************************************** +// Using Produced Lambda-LambdaBar MC Reconstructed and MC Generated Lambda-LambdaBar For Efficiency Plots +//*********************************************************************************************************** +struct LambdaAntiLambdaEfficiencyPlots { + HistogramRegistry rEfficiencyPlots{"EfficiencyPlotsy", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Defining Plot axis for later purpose + ConfigurableAxis axisInvariantMass{"axisInvariantMass", {100, 1.08f, 1.2f}, "Invariant-mass axis"}; + ConfigurableAxis axisMcRecoPt{"axisMcRecoPt", {200, 0.f, 10.f}, "McReco transverse-momentum axis"}; + ConfigurableAxis axisGenPt{"axisGenPt", {200, 0.f, 10.f}, "McGen transverse-momentum axis"}; + ConfigurableAxis axisDeltaPt{"axisDeltaPt", {200, 0.f, 2.f}, "|pt_{Reco} - pT_{Gen}|"}; + ConfigurableAxis axisMcRecoEta{"axisMcRecoEta", {100, -2.f, 2.f}, "McReco eta axis"}; + ConfigurableAxis axisMcGenEta{"axisMcGenEta", {100, -2.f, 2.f}, "McGen eta axis"}; + + // ========================Filters====================================== + //~~~~~~~~~~~~~~~~~~~~~~~McRecoFillters~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + // ================================================================ + // Event selection Filters + // ================================================================ + + Configurable cutZVertex{"cutZVertex", 10.f, "Maximum absolute reconstructed vertex z"}; + + Filter mcRecoEventFilter = aod::mcrecolambda::sel8 == true && + nabs(aod::mcrecolambda::vertexZ) < cutZVertex && + aod::mcrecolambda::isPhysicalPrimary == true; + // ================================================================ + // Topological Selection Filters + // ================================================================ + + Configurable maxDcaV0Daughters{"maxDcaV0Daughters", 1.0f, "Maximum DCA between V0 daughters"}; + Configurable maxDcaV0ToPV{"maxDcaV0ToPV", 0.1f, "Maximum V0 DCA to primary vertex"}; + Configurable minDcaProtonToPV{"minDcaProtonToPV", 0.02f, "Minimum proton DCA to primary vertex"}; + Configurable minDcaPionToPV{"minDcaPionToPV", 0.06f, "Minimum pion DCA to primary vertex"}; + Configurable minV0Radius{"minV0Radius", 0.5f, "Minimum V0 decay radius"}; + Configurable maxV0CTau{"maxV0CTau", 30.0f, "Maximum Lambda c-tau"}; + Configurable minV0CosPA{"minV0CosPA", 0.995f, "Minimum V0 cosine of pointing angle"}; + + Filter mcRecoTopologyFilter = aod::mcrecolambda::dcaDaughters < maxDcaV0Daughters && + nabs(aod::mcrecolambda::dcaV0ToPV) < maxDcaV0ToPV && + aod::mcrecolambda::proDcaToPV > minDcaProtonToPV&& + aod::mcrecolambda::pieDcaToPV > minDcaPionToPV&& + aod::mcrecolambda::v0Radius > minV0Radius&& + aod::mcrecolambda::cTau + minV0CosPA; + + // ================================================================ + // kinematics Filter + // ================================================================ + + Configurable minLambdaPt{"minLambdaPt", 0.5f, "Minimum Lambda pT"}; + Configurable maxLambdaPt{"maxLambdaPt", 4.5f, "Maximum Lambda pT"}; + Configurable maxLambdaRapidity{"maxLambdaRapidity", 0.5f, "Maximum absolute Lambda rapidity"}; + + Filter mcRecoKinematicFilter = aod::mcrecolambda::recoPt > minLambdaPt&& + aod::mcrecolambda::recoPt < maxLambdaPt&& + nabs(aod::mcrecolambda::recoRapidity) < maxLambdaRapidity; + + // ================================================================ + // Daughter-track selection + // ================================================================ + + Configurable minDaughterPt{"minDaughterPt", 0.15f, "Minimum daughter-track pT"}; + Configurable maxDaughterEta{"maxDaughterEta", 0.8f, "Maximum absolute daughter-track eta"}; + Configurable minTPCCrossedRows{"minTPCCrossedRows", 70, "Minimum TPC crossed rows"}; + + Filter mcRecoDaughterFilter = aod::mcrecolambda::proPt > minDaughterPt&& aod::mcrecolambda::piePt > minDaughterPt&& + nabs(aod::mcrecolambda::proEta) < maxDaughterEta&& nabs(aod::mcrecolambda::pieEta) < maxDaughterEta&& aod::mcrecolambda::proTPCCrossedRows + >= minTPCCrossedRows&& aod::mcrecolambda::pieTPCCrossedRows >= minTPCCrossedRows; + + void addEfficiencyPlotsHistograms(std::string const& particle) + { + const std::string recoDirectory = particle + "/Reco/"; + const std::string genDirectory = particle + "/Gen/"; + + rEfficiencyPlots.add((recoDirectory + "hMcRecoPt").c_str(), "Reconstructed p_{T};p_{T} (GeV/c);Entries", HistType::kTH1F, {axisMcRecoPt}); + rEfficiencyPlots.add((recoDirectory + "hAssoMcGenPt").c_str(), "Reco Accociated Gen p_{T};p_{T} (GeV/c);Entries", HistType::kTH1F, {axisGenPt}); + rEfficiencyPlots.add((recoDirectory + "hMcRecoEta").c_str(), "Reconstructed #eta;#eta;Entries", HistType::kTH1F, {axisMcRecoEta}); + rEfficiencyPlots.add((recoDirectory + "hAssoMcGenEta").c_str(), "Reco Accociated Gen #eta;#eta;Entries", HistType::kTH1F, {axisMcGenEta}); + rEfficiencyPlots.add((recoDirectory + "hPtResolution").c_str(), "|pT_{Reco} - pT_{Gen}|", HistType::kTH1F, {axisDeltaPt}); + rEfficiencyPlots.add((recoDirectory + "hInvariantMass").c_str(), "Reconstructed invariant mass;m_{p#pi} (GeV/c^{2});entries", HistType::kTH1F, {axisInvariantMass}); + + rEfficiencyPlots.add((genDirectory + "hPt").c_str(), "Generated p_{T};p_{T} (GeV/c);Entries", HistType::kTH1F, {axisGenPt}); + rEfficiencyPlots.add((genDirectory + "hEta").c_str(), "Generated #eta;#eta;Entries", HistType::kTH1F, {axisMcGenEta}); + rEfficiencyPlots.add((genDirectory + "PrimarAndNonPrimary").c_str(), "Generated Primary And Non-Primary Genp_{T};Genp_{T} (GeV/c);Entries", HistType::kTH1F, {axisGenPt}); + } + + void init(InitContext const&) + { + addEfficiencyPlotsHistograms("Lambda"); + addEfficiencyPlotsHistograms("AntiLambda"); + } + + using SelectedMcRecoLambdas = soa::Filtered; + + Partition selectedMcRecoLambdas = aod::mcrecolambda::isAntiLambda == false; + Partition selectedMcRecoAntiLambdas = aod::mcrecolambda::isAntiLambda == true; + + void processEfficiencyMcReco(SelectedMcRecoLambdas const&) + { + for (const auto& lambda : selectedMcRecoLambdas) { + rEfficiencyPlots.fill(HIST("Lambda/Reco/hMcRecoPt"), lambda.recoPt()); + rEfficiencyPlots.fill(HIST("Lambda/Reco/hAssoMcGenPt"), lambda.genPt()); + rEfficiencyPlots.fill(HIST("Lambda/Reco/hMcRecoEta"), lambda.recoEta()); + rEfficiencyPlots.fill(HIST("Lambda/Reco/hAssoMcGenEta"), lambda.genEta()); + rEfficiencyPlots.fill(HIST("Lambda/Reco/hPtResolution"), lambda.ptResolution()); + rEfficiencyPlots.fill(HIST("Lambda/Reco/hInvariantMass"), lambda.massLambda()); + } + + for (const auto& antiLambda : selectedMcRecoAntiLambdas) { + rEfficiencyPlots.fill(HIST("AntiLambda/Reco/hMcRecoPt"), antiLambda.recoPt()); + rEfficiencyPlots.fill(HIST("AntiLambda/Reco/hAssoMcGenPt"), antiLambda.genPt()); + rEfficiencyPlots.fill(HIST("AntiLambda/Reco/hMcRecoEta"), antiLambda.recoEta()); + rEfficiencyPlots.fill(HIST("AntiLambda/Reco/hAssoMcGenEta"), antiLambda.genEta()); + rEfficiencyPlots.fill(HIST("AntiLambda/Reco/hPtResolution"), antiLambda.ptResolution()); + rEfficiencyPlots.fill(HIST("AntiLambda/Reco/hInvariantMass"), antiLambda.massLambda()); + } + } + PROCESS_SWITCH(LambdaAntiLambdaEfficiencyPlots, processEfficiencyMcReco, "Fill MC reconstructed efficiency histograms", false); + + // McGen Filters + Filter mcGenEventFilter = aod::eveselpassmcgenevent::nSel8Collisions > 0; + + using SelectedMcGenEvents = soa::Filtered; + Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; + + void processEfficiencyMcGen(SelectedMcGenEvents::iterator const& selectedMcEvent, aod::McParticles const& allMcParticles) + { + // We will slice the particles here later. + const auto particlesFromThisMcCollision = allMcParticles.sliceBy(mcParticlesPerMcCollision, selectedMcEvent.mcCollisionId()); + + // Reconstructed-collision-opportunity weight + const auto weight = static_cast(selectedMcEvent.nSel8Collisions()); + + for (const auto& particle : particlesFromThisMcCollision) { + + // Generated kinematic acceptance + if (particle.pt() <= minLambdaPt || particle.pt() >= maxLambdaPt) { + continue; + } + if (std::abs(particle.y()) >= maxLambdaRapidity) { + continue; + } + // Lambda or anti-Lambda + + if (particle.pdgCode() == PDG_t::kLambda0) { + // Inclusive: primary + non-primary Lambda + rEfficiencyPlots.fill(HIST("Lambda/Gen/PrimarAndNonPrimary"), particle.pt(), weight); + + if (!particle.isPhysicalPrimary()) { + continue; + } + + rEfficiencyPlots.fill(HIST("Lambda/Gen/hPt"), particle.pt(), weight); + rEfficiencyPlots.fill(HIST("Lambda/Gen/hEta"), particle.eta(), weight); + + } else if (particle.pdgCode() == PDG_t::kLambda0Bar) { + // Inclusive: primary + non-primary anti-Lambda + rEfficiencyPlots.fill(HIST("AntiLambda/Gen/PrimarAndNonPrimary"), particle.pt(), weight); + + if (!particle.isPhysicalPrimary()) { + continue; + } + + rEfficiencyPlots.fill(HIST("AntiLambda/Gen/hPt"), particle.pt(), weight); + rEfficiencyPlots.fill(HIST("AntiLambda/Gen/hEta"), particle.eta(), weight); + } + } + } + PROCESS_SWITCH(LambdaAntiLambdaEfficiencyPlots, processEfficiencyMcGen, "Fill MC-generated efficiency histograms", false); +}; + +struct LambdaAntiLambdaSelectionCutFlow { + HistogramRegistry cutFlowRegistry{"cutFlowRegistry", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // Event selection + Configurable cutZVertex{"cutZVertex", 10.f, "Maximum absolute reconstructed vertex z"}; + + // Daughter selection + Configurable minDaughterPt{"minDaughterPt", 0.15f, "Minimum daughter pT"}; + Configurable maxDaughterEta{"maxDaughterEta", 0.8f, "Maximum daughter absolute eta"}; + Configurable minTPCCrossedRows{"minTPCCrossedRows", 70, "Minimum TPC crossed rows"}; + + // Topology + Configurable maxDcaV0Daughters{"maxDcaV0Daughters", 1.f, "Maximum daughter DCA"}; + Configurable maxDcaV0ToPV{"maxDcaV0ToPV", 0.1f, "Maximum V0 DCA to PV"}; + Configurable minDcaProtonToPV{"minDcaProtonToPV", 0.02f, "Minimum proton DCA to PV"}; + Configurable minDcaPionToPV{"minDcaPionToPV", 0.06f, "Minimum pion DCA to PV"}; + Configurable minV0Radius{"minV0Radius", 0.5f, "Minimum V0 radius"}; + Configurable maxV0CTau{"maxV0CTau", 30.f, "Maximum Lambda c-tau"}; + Configurable minV0CosPA{"minV0CosPA", 0.995f, "Minimum cosine of pointing angle"}; + + // Lambda kinematics + Configurable minLambdaPt{"minLambdaPt", 0.5f, "Minimum Lambda pT"}; + Configurable maxLambdaPt{"maxLambdaPt", 4.5f, "Maximum Lambda pT"}; + Configurable maxLambdaRapidity{"maxLambdaRapidity", 0.5f, "Maximum absolute Lambda rapidity"}; + + void init(InitContext const&) + { + AxisSpec eventCutAxis{3, -0.5, 2.5, "Event-selection stage"}; + + AxisSpec lambdaCutAxis{8, -0.5, 7.5, "Candidate-selection stage"}; + + cutFlowRegistry.add("Event/hCutFlow", "Event cut flow;Selection;Collisions", HistType::kTH1D, {eventCutAxis}); + cutFlowRegistry.add("Lambda/hCutFlow", "Lambda cut flow;Selection;Candidates", HistType::kTH1D, {lambdaCutAxis}); + cutFlowRegistry.add("AntiLambda/hCutFlow", "Anti-Lambda cut flow;Selection;Candidates", HistType::kTH1D, {lambdaCutAxis}); + + auto eventHistogram = cutFlowRegistry.get(HIST("Event/hCutFlow")); + + eventHistogram->GetXaxis()->SetBinLabel(1, "All collisions"); + eventHistogram->GetXaxis()->SetBinLabel(2, "sel8"); + eventHistogram->GetXaxis()->SetBinLabel(3, "Vertex z"); + + auto lambdaHistogram = cutFlowRegistry.get(HIST("Lambda/hCutFlow")); + + auto antiLambdaHistogram = cutFlowRegistry.get(HIST("AntiLambda/hCutFlow")); + + for (const auto& histogram : {lambdaHistogram, antiLambdaHistogram}) { + histogram->GetXaxis()->SetBinLabel(1, "Truth matched + PID selected"); + histogram->GetXaxis()->SetBinLabel(2, "sel8"); + histogram->GetXaxis()->SetBinLabel(3, "Vertex z"); + histogram->GetXaxis()->SetBinLabel(4, "Physical primary"); + histogram->GetXaxis()->SetBinLabel(5, "Daughter acceptance"); + histogram->GetXaxis()->SetBinLabel(6, "TPC crossed rows"); + histogram->GetXaxis()->SetBinLabel(7, "V0 topology"); + histogram->GetXaxis()->SetBinLabel(8, "Lambda kinematics"); + } + } + + using ReconstructedEvents = soa::Join; + + void processEventCutFlow(ReconstructedEvents::iterator const& collision) + { + cutFlowRegistry.fill(HIST("Event/hCutFlow"), 0.f); + + if (!collision.sel8()) { + return; + } + + cutFlowRegistry.fill(HIST("Event/hCutFlow"), 1.f); + + if (std::abs(collision.posZ()) >= cutZVertex) { + return; + } + + cutFlowRegistry.fill(HIST("Event/hCutFlow"), 2.f); + } + + void processLambdaCutFlow(aod::McRecoLambdaCandidates const& candidates) + { + for (const auto& candidate : candidates) { + const bool isAntiLambda = candidate.isAntiLambda(); + + auto fillStage = [&](float stage) { + if (isAntiLambda) { + cutFlowRegistry.fill(HIST("AntiLambda/hCutFlow"), stage); + } else { + cutFlowRegistry.fill(HIST("Lambda/hCutFlow"), stage); + } + }; + + // PID, truth match and correct species were already + // required by LambdaAntiLambdaMcRecoTableProducer. + fillStage(0.f); + + if (!candidate.sel8()) { + continue; + } + fillStage(1.f); + + if (std::abs(candidate.vertexZ()) >= cutZVertex) { + continue; + } + fillStage(2.f); + + if (!candidate.isPhysicalPrimary()) { + continue; + } + fillStage(3.f); + + if (candidate.proPt() <= minDaughterPt || candidate.piePt() <= minDaughterPt || + std::abs(candidate.proEta()) >= maxDaughterEta || + std::abs(candidate.pieEta()) >= maxDaughterEta) { + continue; + } + fillStage(4.f); + + if (candidate.proTPCCrossedRows() < minTPCCrossedRows || + candidate.pieTPCCrossedRows() < minTPCCrossedRows) { + continue; + } + fillStage(5.f); + + if (candidate.dcaDaughters() >= maxDcaV0Daughters || std::abs(candidate.dcaV0ToPV()) >= maxDcaV0ToPV || + candidate.proDcaToPV() <= minDcaProtonToPV || candidate.pieDcaToPV() <= minDcaPionToPV || + candidate.v0Radius() <= minV0Radius || candidate.cTau() >= maxV0CTau || + candidate.cosPA() <= minV0CosPA) { + continue; + } + fillStage(6.f); + + if (candidate.recoPt() <= minLambdaPt || candidate.recoPt() >= maxLambdaPt || + std::abs(candidate.recoRapidity()) >= maxLambdaRapidity) { + continue; + } + fillStage(7.f); + } + } + + PROCESS_SWITCH(LambdaAntiLambdaSelectionCutFlow, processEventCutFlow, "Fill reconstructed-event cut flow", false); + PROCESS_SWITCH(LambdaAntiLambdaSelectionCutFlow, processLambdaCutFlow, "Fill MCReco Lambda cut flow", false); +}; + +struct LambdaAntiLambdaPairAnalysis { + // Defining Histogram registry + HistogramRegistry rSpinAnalysis{"SpinPairAnalysis", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; + // defining Axis for histograms + ConfigurableAxis axisDeltaEta{"axisDeltaEta", {100, -2.f, 2.f}, "#Delta#eta axis"}; + ConfigurableAxis axisDeltaPhi{"axisDeltaPhi", {72, -o2::constants::math::PI, o2::constants::math::PI}, "#Delta#phi axis"}; + ConfigurableAxis axisDeltaPt{"axisDeltaPt", {400, -10.f, 10.f}, "#Delta#p_{T} axis"}; + + ConfigurableAxis axisPt{"axisPt", {200, 0.f, 10.f}, "transverse-momentum axis"}; + ConfigurableAxis axisEta{"axisEta", {100, -2.f, 2.f}, "#eta axis"}; + ConfigurableAxis axisPhi{"axisPhi", {72, 0, o2::constants::math::TwoPI}, "#phi axis"}; + + ConfigurableAxis axisInvariantMass{"axisInvariantMass", {100, 1.08f, 1.2f}, "Invariant-mass axis"}; + ConfigurableAxis axisDeltaMass{"axisDeltaMass", {100, -0.12f, 0.12f}, "Invariant-mass axis"}; + // ConfigurableAxis axisNumberOfPairs{"axisNumberOfPairs", {1001, -0.5f, 1000.5f}, "NumberOfPairs axis"}; + + ConfigurableAxis axisCos{"axisCos", {200, -1.f, 1.f}, "#Cos#theta axis"}; + ConfigurableAxis axisMult{"axisMult", {200, 0.f, 200.f}, "Multiplicity axis"}; + ConfigurableAxis axisDeltaMult{"axisDeltaMult", {400, -200.f, 200.f}, "Delta Multiplicity axis"}; + ConfigurableAxis axisCent{"axisCent", {100, 0.f, 100.f}, "Centrality axis"}; + ConfigurableAxis axisDeltaCent{"axisDeltaCent", {200, -100.f, 100.f}, "Delta Centrality axis"}; + + // Mixed-Event Compatablity variables + Configurable compatibilityDeltaPt{"compatibilityDeltaPt", 0.1f, "compatibility pT difference for mixed-candidate matching"}; + Configurable compatibilityDeltaPhi{"compatibilityDeltaPhi", 0.1f, "compatibility phi difference for mixed-candidate matching"}; + Configurable compatibilityDeltaRapidity{"compatibilityDeltaRapidity", 0.1f, "compatibility rapidity difference for mixed-candidate matching"}; + Configurable mixedEventMaxDeltaMultiplicity{"mixedEventMaxDeltaMultiplicity", 10.f, "Maximum multiplicity difference between mixed events"}; + + // Short-range pairs + Configurable sameEventShortRangePairMaxDeltaRapidity{"sameEventShortRangePairMaxDeltaRapidity", 0.5f, "ShortRangePai Maximum absolute rapidity difference for same-event pairs"}; + Configurable sameEventShortRangePairMaxDeltaPhi{"sameEventShortRangePairMaxDeltaPhi", 1.047f, "ShortRangePai Maximum absolute wrapped phi difference for same-event pairs"}; // Pi/3 =1.047 + + void addHistograms(TString const& candidate1, TString const& candidate2) + { + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Same-Event~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // EventConter histogram + rSpinAnalysis.add(candidate1 + candidate2 + "/hSameEvent/EventCount", "Same-event" + candidate1 + candidate2 + + "pairs;" + "SameEvent", + HistType::kTH1F, {{1, -0.5, 0.5}}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hSameEvent/NumberOfPairs", "Same-event pair count;Counter;Accepted pairs", HistType::kTH1F, {{1, -0.5, 0.5}}); + // Delta Kinaematics histos + rSpinAnalysis.add(candidate1 + candidate2 + "/hSameEvent/DeltaEtaDelatPhi", "Same-event" + candidate1 + candidate2 + + "pairs;" + "#Delta#eta;" + "#Delta#phi", + HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hSameEvent/DeltaPtDelatEta", "Same-event" + candidate1 + candidate2 + + "pairs;" + "#Delta#p_{T};" + "#Delta#eta", + HistType::kTH2F, {axisDeltaPt, axisDeltaEta}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hSameEvent/DeltaPtDelatPhi", "Same-event" + candidate1 + candidate2 + + "pairs;" + "#Delta#p_{T};" + "#Delta#phi", + HistType::kTH2F, {axisDeltaPt, axisDeltaPhi}); + // Invarient mass and Cent histos + rSpinAnalysis.add(candidate1 + candidate2 + "/hSameEvent/DeltaMassDeltaCent", "Same-event" + candidate1 + candidate2 + + "pairs;" + "#Delta m_{#pi#p} ;" + "DeltaCent", + HistType::kTH2F, {axisDeltaMass, axisDeltaCent}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hSameEvent/DeltaMassDeltaPt", "Same-event" + candidate1 + candidate2 + + "pairs;" + "#Delta m_{#pi#p} ;" + "Deltap_{T}", + HistType::kTH2F, {axisDeltaMass, axisDeltaPt}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hSameEvent/DeltaCentDeltaMult", "Same-event" + candidate1 + candidate2 + + "pairs;" + "DeltaCent ;" + "DeltaMult", + HistType::kTH2F, {axisDeltaCent, axisDeltaMult}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hSameEvent/Mass", "Same-event" + candidate1 + candidate2 + + "pairs;" + "Mass-Lambda ;" + "Mass-AntiLambda", + HistType::kTH2F, {axisInvariantMass, axisInvariantMass}); + + // ================================================================ + // Same-event short-range spin histograms + // |Delta y| < 0.5 and |Delta phi| < pi/3 + // ================================================================ + + rSpinAnalysis.add(candidate1 + candidate2 + "/hSameEvent/ShortRange/CosMult", "Same-event short-range " + candidate1 + candidate2 + " pairs;cos#theta;Mult", HistType::kTH2F, {axisCos, axisMult}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hSameEvent/ShortRange/CosCent", "Same-event short-range " + candidate1 + candidate2 + " pairs;cos#theta;Cent", HistType::kTH2F, {axisCos, axisCent}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hSameEvent/ShortRange/Cos", "Same-event short-range " + candidate1 + candidate2 + " pairs;cos#theta", HistType::kTH1F, {axisCos}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hSameEvent/ShortRange/NumberOfPairs", "Same-event short-range pair count;Counter;Accepted pairs", HistType::kTH1F, {{1, -0.5, 0.5}}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hSameEvent/ShortRange/EventCount", "Events containing at least one short-range pair;Counter;Events", HistType::kTH1F, {{1, -0.5, 0.5}}); + + // ================================================================ + // Same-event long-range spin histograms + // Complement of the short-range selection + // ================================================================ + + rSpinAnalysis.add(candidate1 + candidate2 + "/hSameEvent/LongRange/CosMult", "Same-event long-range " + candidate1 + candidate2 + " pairs;cos#theta;Mult", HistType::kTH2F, {axisCos, axisMult}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hSameEvent/LongRange/CosCent", "Same-event long-range " + candidate1 + candidate2 + " pairs;cos#theta;Cent", HistType::kTH2F, {axisCos, axisCent}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hSameEvent/LongRange/Cos", "Same-event long-range " + candidate1 + candidate2 + " pairs;cos#theta", HistType::kTH1F, {axisCos}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hSameEvent/LongRange/NumberOfPairs", "Same-event long-range pair count;Counter;Accepted pairs", HistType::kTH1F, {{1, -0.5, 0.5}}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hSameEvent/LongRange/EventCount", "Events containing at least one long-range pair;Counter;Events", HistType::kTH1F, {{1, -0.5, 0.5}}); + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Mixed-Event~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // EventConter histogram + rSpinAnalysis.add(candidate1 + candidate2 + "/hMixedEvent/EventCount", "Mixed-event" + candidate1 + candidate2 + + "pairs;" + "MixedEvent", + HistType::kTH1F, {{1, -0.5, 0.5}}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hMixedEvent/NumberOfPairs", "Mixed-event pair count;Counter;Accepted pairs", HistType::kTH1F, {{1, -0.5, 0.5}}); + + // Delta Kinaematics histos + rSpinAnalysis.add(candidate1 + candidate2 + "/hMixedEvent/DeltaEtaDelatPhi", "Mixed-event" + candidate1 + candidate2 + + "pairs;" + "#Delta#eta;" + "#Delta#phi", + HistType::kTH2F, {axisDeltaEta, axisDeltaPhi}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hMixedEvent/DeltaPtDelatEta", "Mixed-event" + candidate1 + candidate2 + + "pairs;" + "#Delta#p_{T};" + "#Delta#eta", + HistType::kTH2F, {axisDeltaPt, axisDeltaEta}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hMixedEvent/DeltaPtDelatPhi", "Mixed-event" + candidate1 + candidate2 + + "pairs;" + "#Delta#p_{T};" + "#Delta#phi", + HistType::kTH2F, {axisDeltaPt, axisDeltaPhi}); + // Invarient mass and Cent histos + rSpinAnalysis.add(candidate1 + candidate2 + "/hMixedEvent/DeltaMassDeltaCent", "Mixed-event" + candidate1 + candidate2 + + "pairs;" + "#Delta m_{#pi#p} ;" + "DeltaCent", + HistType::kTH2F, {axisDeltaMass, axisDeltaCent}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hMixedEvent/DeltaMassDeltaPt", "Mixed-event" + candidate1 + candidate2 + + "pairs;" + "#Delta m_{#pi#p} ;" + "Deltap_{T}", + HistType::kTH2F, {axisDeltaMass, axisDeltaPt}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hMixedEvent/DeltaCentDeltaMult", "Mixed-event" + candidate1 + candidate2 + + "pairs;" + "DeltaCent ;" + "DeltaMult", + HistType::kTH2F, {axisDeltaCent, axisDeltaMult}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hMixedEvent/Mass", "Mixed-event" + candidate1 + candidate2 + + "pairs;" + "Mass-Lambda ;" + "Mass-AntiLambda", + HistType::kTH2F, {axisInvariantMass, axisInvariantMass}); + + // Spin histos + // 2d + rSpinAnalysis.add(candidate1 + candidate2 + "/hMixedEvent/CosMult", "Mixed-event" + candidate1 + candidate2 + + "pairs;" + "cos#theta;" + "Mult" + + candidate1 + + ";" + "Mult" + + candidate2, + HistType::kTH3F, {axisCos, axisMult, axisMult}); + rSpinAnalysis.add(candidate1 + candidate2 + "/hMixedEvent/CosCent", "Mixed-event" + candidate1 + candidate2 + + "pairs;" + "cos#theta;" + "Cent" + + candidate1 + + ";" + "Cent" + + candidate2, + HistType::kTH3F, {axisCos, axisCent, axisCent}); + // 1d + rSpinAnalysis.add(candidate1 + candidate2 + "/hMixedEvent/Cos", "Mixed-event" + candidate1 + candidate2 + + "pairs;" + "cos#theta", + HistType::kTH1F, {axisCos}); + } + + void init(InitContext const&) + { + addHistograms("Lambda", "AntiLambda"); + addHistograms("Lambda", "Lambda"); + addHistograms("AntiLambda", "AntiLambda"); + } + + ROOT::Math::PxPyPzMVector daughterInParentRestFrame(float parentLambdaPx, float parentLambdaPy, float parentLambdaPz, float parentLambdaMass, float daughterProtonPx, float daughterProtonPy, float daughterProtonPz, float daughterProtonMass) + { + + ROOT::Math::PxPyPzMVector parentFourVector{parentLambdaPx, parentLambdaPy, parentLambdaPz, parentLambdaMass}; + ROOT::Math::PxPyPzMVector daughterFourVector{daughterProtonPx, daughterProtonPy, daughterProtonPz, daughterProtonMass}; + + ROOT::Math::Boost boostToParentRest{parentFourVector.BoostToCM()}; // returns inverse boost requiret make lambda momentum zero i.e rest fram of lambda + const auto protonStar = boostToParentRest(daughterFourVector); // Applies the store inverse boost of the lambda rest fram to the proton + + return protonStar; + } + + float cosTheta(ROOT::Math::PxPyPzMVector const& proton1, + ROOT::Math::PxPyPzMVector const& proton2) + { + const float numerator = proton1.Px() * proton2.Px() + proton1.Py() * proton2.Py() + proton1.Pz() * proton2.Pz(); + const float denominator = proton1.P() * proton2.P(); + + if (denominator == 0.f) { + return -2.f; + } + return numerator / denominator; + } + + template + bool isKinematicallyCompatible(Candidate1 const& candidate1, Candidate2 const& candidate2) + { + const float deltaPt = std::abs(candidate1.pt() - candidate2.pt()); + const float deltaPhi = std::abs(std::remainder(candidate1.phi() - candidate2.phi(), o2::constants::math::TwoPI)); + const float deltaRapidity = std::abs(candidate1.rapidity() - candidate2.rapidity()); + + return deltaPt < compatibilityDeltaPt && + deltaPhi < compatibilityDeltaPhi && + deltaRapidity < compatibilityDeltaRapidity; + } + + template + bool isSameEventShortRange(Candidate1 const& candidate1, Candidate2 const& candidate2) + { + const float deltaRapidity = std::abs(candidate1.rapidity() - candidate2.rapidity()); + + const float deltaPhi = std::abs(std::remainder(candidate1.phi() - candidate2.phi(), o2::constants::math::TwoPI)); + + return deltaRapidity < sameEventShortRangePairMaxDeltaRapidity && + deltaPhi < sameEventShortRangePairMaxDeltaPhi; + } + + template + void fillLambdaAntiLambdaSameEvent(LambdaSlice const& lambdas, AntiLambdaSlice const& antiLambdas) + { + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hSameEvent/EventCount"), 0); + + bool hasShortRangePair = false; + bool hasLongRangePair = false; + + // Lambda-AntiLambda pairs + for (auto const& [lambda, antiLambda] : combinations(CombinationsFullIndexPolicy(lambdas, antiLambdas))) { + + // Boost the proton into the Lambda rest frame. + const auto protonStar = daughterInParentRestFrame(lambda.px(), lambda.py(), lambda.pz(), lambda.mass(), lambda.protonPx(), lambda.protonPy(), lambda.protonPz(), o2::constants::physics::MassProton); + // Boost the antiproton into the anti-Lambda rest frame. + const auto antiProtonStar = daughterInParentRestFrame(antiLambda.px(), antiLambda.py(), antiLambda.pz(), antiLambda.mass(), antiLambda.protonPx(), antiLambda.protonPy(), antiLambda.protonPz(), o2::constants::physics::MassProton); + + const float cosDeltaThetaStar = cosTheta(protonStar, antiProtonStar); + const float deltaPhi = std::remainder(lambda.phi() - antiLambda.phi(), o2::constants::math::TwoPI); + // Invalid result returned by cosTheta(). + if (cosDeltaThetaStar < -1.f) { + continue; + } + + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hSameEvent/NumberOfPairs"), 0); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hSameEvent/DeltaEtaDelatPhi"), lambda.eta() - antiLambda.eta(), deltaPhi); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hSameEvent/DeltaPtDelatEta"), lambda.pt() - antiLambda.pt(), lambda.eta() - antiLambda.eta()); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hSameEvent/DeltaPtDelatPhi"), lambda.pt() - antiLambda.pt(), deltaPhi); + + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hSameEvent/DeltaMassDeltaCent"), lambda.mass() - antiLambda.mass(), lambda.centrality() - antiLambda.centrality()); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hSameEvent/DeltaMassDeltaPt"), lambda.mass() - antiLambda.mass(), lambda.pt() - antiLambda.pt()); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hSameEvent/DeltaCentDeltaMult"), lambda.centrality() - antiLambda.centrality(), lambda.multiplicity() - antiLambda.multiplicity()); + + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hSameEvent/Mass"), lambda.mass(), antiLambda.mass()); + + const bool isShortRange = isSameEventShortRange(lambda, antiLambda); + + if (isShortRange) { + hasShortRangePair = true; + + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hSameEvent/ShortRange/NumberOfPairs"), 0); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hSameEvent/ShortRange/Cos"), cosDeltaThetaStar); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hSameEvent/ShortRange/CosMult"), cosDeltaThetaStar, lambda.multiplicity()); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hSameEvent/ShortRange/CosCent"), cosDeltaThetaStar, lambda.centrality()); + } else { + hasLongRangePair = true; + + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hSameEvent/LongRange/NumberOfPairs"), 0); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hSameEvent/LongRange/Cos"), cosDeltaThetaStar); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hSameEvent/LongRange/CosMult"), cosDeltaThetaStar, lambda.multiplicity()); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hSameEvent/LongRange/CosCent"), cosDeltaThetaStar, lambda.centrality()); + } + } + if (hasShortRangePair) { + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hSameEvent/ShortRange/EventCount"), 0); + } + if (hasLongRangePair) { + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hSameEvent/LongRange/EventCount"), 0); + } + } + + template + void fillLambdaLambdaSameEvent(LambdaSlice const& lambdas) + { + + bool hasShortRangePair = false; + bool hasLongRangePair = false; + + rSpinAnalysis.fill(HIST("LambdaLambda/hSameEvent/EventCount"), 0); + + // Lambda-Lamda pairs + for (auto const& [lambda1, lambda2] : combinations(CombinationsStrictlyUpperIndexPolicy(lambdas, lambdas))) { + + // Boost the proton into the Lambda rest frame. + const auto protonStar1 = daughterInParentRestFrame(lambda1.px(), lambda1.py(), lambda1.pz(), lambda1.mass(), lambda1.protonPx(), lambda1.protonPy(), lambda1.protonPz(), o2::constants::physics::MassProton); + // Boost the antiproton into the anti-Lambda rest frame. + const auto protonStar2 = daughterInParentRestFrame(lambda2.px(), lambda2.py(), lambda2.pz(), lambda2.mass(), lambda2.protonPx(), lambda2.protonPy(), lambda2.protonPz(), o2::constants::physics::MassProton); + + const float cosDeltaThetaStar = cosTheta(protonStar1, protonStar2); + const float deltaPhi = std::remainder(lambda1.phi() - lambda2.phi(), o2::constants::math::TwoPI); + // Invalid result returned by cosTheta(). + if (cosDeltaThetaStar < -1.f) { + continue; + } + + rSpinAnalysis.fill(HIST("LambdaLambda/hSameEvent/NumberOfPairs"), 0); + + rSpinAnalysis.fill(HIST("LambdaLambda/hSameEvent/DeltaEtaDelatPhi"), lambda1.eta() - lambda2.eta(), deltaPhi); + rSpinAnalysis.fill(HIST("LambdaLambda/hSameEvent/DeltaPtDelatEta"), lambda1.pt() - lambda2.pt(), lambda1.eta() - lambda2.eta()); + rSpinAnalysis.fill(HIST("LambdaLambda/hSameEvent/DeltaPtDelatPhi"), lambda1.pt() - lambda2.pt(), deltaPhi); + + rSpinAnalysis.fill(HIST("LambdaLambda/hSameEvent/DeltaMassDeltaCent"), lambda1.mass() - lambda2.mass(), lambda1.centrality() - lambda2.centrality()); + rSpinAnalysis.fill(HIST("LambdaLambda/hSameEvent/DeltaMassDeltaPt"), lambda1.mass() - lambda2.mass(), lambda1.pt() - lambda2.pt()); + rSpinAnalysis.fill(HIST("LambdaLambda/hSameEvent/DeltaCentDeltaMult"), lambda1.centrality() - lambda2.centrality(), lambda1.multiplicity() - lambda2.multiplicity()); + + rSpinAnalysis.fill(HIST("LambdaLambda/hSameEvent/Mass"), lambda1.mass(), lambda2.mass()); + + const bool isShortRange = isSameEventShortRange(lambda1, lambda2); + + if (isShortRange) { + hasShortRangePair = true; + + rSpinAnalysis.fill(HIST("LambdaLambda/hSameEvent/ShortRange/NumberOfPairs"), 0); + rSpinAnalysis.fill(HIST("LambdaLambda/hSameEvent/ShortRange/Cos"), cosDeltaThetaStar); + rSpinAnalysis.fill(HIST("LambdaLambda/hSameEvent/ShortRange/CosMult"), cosDeltaThetaStar, lambda1.multiplicity()); + rSpinAnalysis.fill(HIST("LambdaLambda/hSameEvent/ShortRange/CosCent"), cosDeltaThetaStar, lambda1.centrality()); + } else { + hasLongRangePair = true; + + rSpinAnalysis.fill(HIST("LambdaLambda/hSameEvent/LongRange/NumberOfPairs"), 0); + rSpinAnalysis.fill(HIST("LambdaLambda/hSameEvent/LongRange/Cos"), cosDeltaThetaStar); + rSpinAnalysis.fill(HIST("LambdaLambda/hSameEvent/LongRange/CosMult"), cosDeltaThetaStar, lambda1.multiplicity()); + rSpinAnalysis.fill(HIST("LambdaLambda/hSameEvent/LongRange/CosCent"), cosDeltaThetaStar, lambda1.centrality()); + } + } + if (hasShortRangePair) { + rSpinAnalysis.fill(HIST("LambdaLambda/hSameEvent/ShortRange/EventCount"), 0); + } + if (hasLongRangePair) { + rSpinAnalysis.fill(HIST("LambdaLambda/hSameEvent/LongRange/EventCount"), 0); + } + } + + template + void fillAntiLambdaAntiLambdaSameEvent(AntiLambdaSlice const& antiLambdas) + { + bool hasShortRangePair = false; + bool hasLongRangePair = false; + + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hSameEvent/EventCount"), 0); + + // AntiLambda-AntiLambda pairs + for (auto const& [antilambda1, antilambda2] : combinations(CombinationsStrictlyUpperIndexPolicy(antiLambdas, antiLambdas))) { + + // Boost the proton into the Lambda rest frame. + const auto antiProtonStar1 = daughterInParentRestFrame(antilambda1.px(), antilambda1.py(), antilambda1.pz(), antilambda1.mass(), antilambda1.protonPx(), antilambda1.protonPy(), antilambda1.protonPz(), o2::constants::physics::MassProton); + // Boost the antiproton into the anti-Lambda rest frame. + const auto antiProtonStar2 = daughterInParentRestFrame(antilambda2.px(), antilambda2.py(), antilambda2.pz(), antilambda2.mass(), antilambda2.protonPx(), antilambda2.protonPy(), antilambda2.protonPz(), o2::constants::physics::MassProton); + + const float cosDeltaThetaStar = cosTheta(antiProtonStar1, antiProtonStar2); + const float deltaPhi = std::remainder(antilambda1.phi() - antilambda2.phi(), o2::constants::math::TwoPI); + // Invalid result returned by cosTheta(). + if (cosDeltaThetaStar < -1.f) { + continue; + } + + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hSameEvent/NumberOfPairs"), 0); + + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hSameEvent/DeltaEtaDelatPhi"), antilambda1.eta() - antilambda2.eta(), deltaPhi); + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hSameEvent/DeltaPtDelatEta"), antilambda1.pt() - antilambda2.pt(), antilambda1.eta() - antilambda2.eta()); + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hSameEvent/DeltaPtDelatPhi"), antilambda1.pt() - antilambda2.pt(), deltaPhi); + + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hSameEvent/DeltaMassDeltaCent"), antilambda1.mass() - antilambda2.mass(), antilambda1.centrality() - antilambda2.centrality()); + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hSameEvent/DeltaMassDeltaPt"), antilambda1.mass() - antilambda2.mass(), antilambda1.pt() - antilambda2.pt()); + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hSameEvent/DeltaCentDeltaMult"), antilambda1.centrality() - antilambda2.centrality(), antilambda1.multiplicity() - antilambda2.multiplicity()); + + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hSameEvent/Mass"), antilambda1.mass(), antilambda2.mass()); + + const bool isShortRange = isSameEventShortRange(antilambda1, antilambda2); + + if (isShortRange) { + hasShortRangePair = true; + + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hSameEvent/ShortRange/NumberOfPairs"), 0); + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hSameEvent/ShortRange/Cos"), cosDeltaThetaStar); + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hSameEvent/ShortRange/CosMult"), cosDeltaThetaStar, antilambda1.multiplicity()); + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hSameEvent/ShortRange/CosCent"), cosDeltaThetaStar, antilambda1.centrality()); + } else { + hasLongRangePair = true; + + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hSameEvent/LongRange/NumberOfPairs"), 0); + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hSameEvent/LongRange/Cos"), cosDeltaThetaStar); + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hSameEvent/LongRange/CosMult"), cosDeltaThetaStar, antilambda1.multiplicity()); + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hSameEvent/LongRange/CosCent"), cosDeltaThetaStar, antilambda1.centrality()); + } + } + if (hasShortRangePair) { + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hSameEvent/ShortRange/EventCount"), 0); + } + if (hasLongRangePair) { + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hSameEvent/LongRange/EventCount"), 0); + } + } + + template + void fillLambdaAntiLambdaMixedEvent(LambdaSlice1 const& lambdas, AntiLambdaSlice2 const& antiLambdas) + { + bool hasAcceptedPair = false; + // Lambda-AntiLambda pairs + for (auto const& [lambda, antiLambda] : combinations(CombinationsFullIndexPolicy(lambdas, antiLambdas))) { + + if (!isKinematicallyCompatible(lambda, antiLambda)) { + continue; + } + // Boost the proton into the Lambda rest frame. + const auto protonStar = daughterInParentRestFrame(lambda.px(), lambda.py(), lambda.pz(), lambda.mass(), lambda.protonPx(), lambda.protonPy(), lambda.protonPz(), o2::constants::physics::MassProton); + // Boost the antiproton into the anti-Lambda rest frame. + const auto antiProtonStar = daughterInParentRestFrame(antiLambda.px(), antiLambda.py(), antiLambda.pz(), antiLambda.mass(), antiLambda.protonPx(), antiLambda.protonPy(), antiLambda.protonPz(), o2::constants::physics::MassProton); + + const float cosDeltaThetaStar = cosTheta(protonStar, antiProtonStar); + const float deltaPhi = std::remainder(lambda.phi() - antiLambda.phi(), o2::constants::math::TwoPI); + // Invalid result returned by cosTheta(). + if (cosDeltaThetaStar < -1.f) { + continue; + } + hasAcceptedPair = true; + + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/NumberOfPairs"), 0); + + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/DeltaEtaDelatPhi"), lambda.eta() - antiLambda.eta(), deltaPhi); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/DeltaPtDelatEta"), lambda.pt() - antiLambda.pt(), lambda.eta() - antiLambda.eta()); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/DeltaPtDelatPhi"), lambda.pt() - antiLambda.pt(), deltaPhi); + + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/DeltaMassDeltaCent"), lambda.mass() - antiLambda.mass(), lambda.centrality() - antiLambda.centrality()); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/DeltaMassDeltaPt"), lambda.mass() - antiLambda.mass(), lambda.pt() - antiLambda.pt()); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/DeltaCentDeltaMult"), lambda.centrality() - antiLambda.centrality(), lambda.multiplicity() - antiLambda.multiplicity()); + + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/Mass"), lambda.mass(), antiLambda.mass()); + + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/CosMult"), cosDeltaThetaStar, lambda.multiplicity(), antiLambda.multiplicity()); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/CosCent"), cosDeltaThetaStar, lambda.centrality(), antiLambda.centrality()); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/Cos"), cosDeltaThetaStar); + } + + if (hasAcceptedPair) { + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/EventCount"), 0); + } + } + + template + void fillAntiLambdaLambdaMixedEvent(AntiLambdaSlice1 const& antiLambdas, LambdaSlice2 const& lambdas) + { + bool hasAcceptedPair = false; + // Lambda-AntiLambda pairs + for (auto const& [lambda, antiLambda] : combinations(CombinationsFullIndexPolicy(lambdas, antiLambdas))) { + + if (!isKinematicallyCompatible(lambda, antiLambda)) { + continue; + } + // Boost the proton into the Lambda rest frame. + const auto protonStar = daughterInParentRestFrame(lambda.px(), lambda.py(), lambda.pz(), lambda.mass(), lambda.protonPx(), lambda.protonPy(), lambda.protonPz(), o2::constants::physics::MassProton); + // Boost the antiproton into the anti-Lambda rest frame. + const auto antiProtonStar = daughterInParentRestFrame(antiLambda.px(), antiLambda.py(), antiLambda.pz(), antiLambda.mass(), antiLambda.protonPx(), antiLambda.protonPy(), antiLambda.protonPz(), o2::constants::physics::MassProton); + + const float cosDeltaThetaStar = cosTheta(protonStar, antiProtonStar); + const float deltaPhi = std::remainder(lambda.phi() - antiLambda.phi(), o2::constants::math::TwoPI); + // Invalid result returned by cosTheta(). + if (cosDeltaThetaStar < -1.f) { + continue; + } + hasAcceptedPair = true; + + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/NumberOfPairs"), 0); + + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/DeltaEtaDelatPhi"), lambda.eta() - antiLambda.eta(), deltaPhi); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/DeltaPtDelatEta"), lambda.pt() - antiLambda.pt(), lambda.eta() - antiLambda.eta()); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/DeltaPtDelatPhi"), lambda.pt() - antiLambda.pt(), deltaPhi); + + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/DeltaMassDeltaCent"), lambda.mass() - antiLambda.mass(), lambda.centrality() - antiLambda.centrality()); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/DeltaMassDeltaPt"), lambda.mass() - antiLambda.mass(), lambda.pt() - antiLambda.pt()); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/DeltaCentDeltaMult"), lambda.centrality() - antiLambda.centrality(), lambda.multiplicity() - antiLambda.multiplicity()); + + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/Mass"), lambda.mass(), antiLambda.mass()); + + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/CosMult"), cosDeltaThetaStar, lambda.multiplicity(), antiLambda.multiplicity()); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/CosCent"), cosDeltaThetaStar, lambda.centrality(), antiLambda.centrality()); + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/Cos"), cosDeltaThetaStar); + } + + if (hasAcceptedPair) { + rSpinAnalysis.fill(HIST("LambdaAntiLambda/hMixedEvent/EventCount"), 0); + } + } + + template + void fillLambdaLambdaMixedEvent(LambdaSlice1 const& lambdas1, LambdaSlice2 const& lambdas2) + { + bool hasAcceptedPair = false; + // Lambda-AntiLambda pairs + for (auto const& [lambda1, lambda2] : combinations(CombinationsFullIndexPolicy(lambdas1, lambdas2))) { + + if (!isKinematicallyCompatible(lambda1, lambda2)) { + continue; + } + // Boost the proton into the Lambda rest frame. + const auto protonStar = daughterInParentRestFrame(lambda1.px(), lambda1.py(), lambda1.pz(), lambda1.mass(), lambda1.protonPx(), lambda1.protonPy(), lambda1.protonPz(), o2::constants::physics::MassProton); + // Boost the antiproton into the anti-Lambda rest frame. + const auto antiProtonStar = daughterInParentRestFrame(lambda2.px(), lambda2.py(), lambda2.pz(), lambda2.mass(), lambda2.protonPx(), lambda2.protonPy(), lambda2.protonPz(), o2::constants::physics::MassProton); + + const float cosDeltaThetaStar = cosTheta(protonStar, antiProtonStar); + const float deltaPhi = std::remainder(lambda1.phi() - lambda2.phi(), o2::constants::math::TwoPI); + // Invalid result returned by cosTheta(). + if (cosDeltaThetaStar < -1.f) { + continue; + } + hasAcceptedPair = true; + + rSpinAnalysis.fill(HIST("LambdaLambda/hMixedEvent/NumberOfPairs"), 0); + + rSpinAnalysis.fill(HIST("LambdaLambda/hMixedEvent/DeltaEtaDelatPhi"), lambda1.eta() - lambda2.eta(), deltaPhi); + rSpinAnalysis.fill(HIST("LambdaLambda/hMixedEvent/DeltaPtDelatEta"), lambda1.pt() - lambda2.pt(), lambda1.eta() - lambda2.eta()); + rSpinAnalysis.fill(HIST("LambdaLambda/hMixedEvent/DeltaPtDelatPhi"), lambda1.pt() - lambda2.pt(), deltaPhi); + + rSpinAnalysis.fill(HIST("LambdaLambda/hMixedEvent/DeltaMassDeltaCent"), lambda1.mass() - lambda2.mass(), lambda1.centrality() - lambda2.centrality()); + rSpinAnalysis.fill(HIST("LambdaLambda/hMixedEvent/DeltaMassDeltaPt"), lambda1.mass() - lambda2.mass(), lambda1.pt() - lambda2.pt()); + rSpinAnalysis.fill(HIST("LambdaLambda/hMixedEvent/DeltaCentDeltaMult"), lambda1.centrality() - lambda2.centrality(), lambda1.multiplicity() - lambda2.multiplicity()); + + rSpinAnalysis.fill(HIST("LambdaLambda/hMixedEvent/Mass"), lambda1.mass(), lambda2.mass()); + + rSpinAnalysis.fill(HIST("LambdaLambda/hMixedEvent/CosMult"), cosDeltaThetaStar, lambda1.multiplicity(), lambda2.multiplicity()); + rSpinAnalysis.fill(HIST("LambdaLambda/hMixedEvent/CosCent"), cosDeltaThetaStar, lambda1.centrality(), lambda2.centrality()); + rSpinAnalysis.fill(HIST("LambdaLambda/hMixedEvent/Cos"), cosDeltaThetaStar); + } + + if (hasAcceptedPair) { + rSpinAnalysis.fill(HIST("LambdaLambda/hMixedEvent/EventCount"), 0); + } + } + + template + void fillAntiLambdaAntiLambdaMixedEvent(AntiLambdaSlice1 const& antiLambdas1, AntiLambdaSlice2 const& antiLambdas2) + { + bool hasAcceptedPair = false; + // Lambda-AntiLambda pairs + for (auto const& [antiLambda1, antiLambda2] : combinations(CombinationsFullIndexPolicy(antiLambdas1, antiLambdas2))) { + + if (!isKinematicallyCompatible(antiLambda1, antiLambda2)) { + continue; + } + // Boost the proton into the Lambda rest frame. + const auto protonStar = daughterInParentRestFrame(antiLambda1.px(), antiLambda1.py(), antiLambda1.pz(), antiLambda1.mass(), antiLambda1.protonPx(), antiLambda1.protonPy(), antiLambda1.protonPz(), o2::constants::physics::MassProton); + // Boost the antiproton into the anti-Lambda rest frame. + const auto antiProtonStar = daughterInParentRestFrame(antiLambda2.px(), antiLambda2.py(), antiLambda2.pz(), antiLambda2.mass(), antiLambda2.protonPx(), antiLambda2.protonPy(), antiLambda2.protonPz(), o2::constants::physics::MassProton); + + const float cosDeltaThetaStar = cosTheta(protonStar, antiProtonStar); + const float deltaPhi = std::remainder(antiLambda1.phi() - antiLambda2.phi(), o2::constants::math::TwoPI); + // Invalid result returned by cosTheta(). + if (cosDeltaThetaStar < -1.f) { + continue; + } + hasAcceptedPair = true; + + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hMixedEvent/NumberOfPairs"), 0); + + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hMixedEvent/DeltaEtaDelatPhi"), antiLambda1.eta() - antiLambda2.eta(), deltaPhi); + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hMixedEvent/DeltaPtDelatEta"), antiLambda1.pt() - antiLambda2.pt(), antiLambda1.eta() - antiLambda2.eta()); + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hMixedEvent/DeltaPtDelatPhi"), antiLambda1.pt() - antiLambda2.pt(), deltaPhi); + + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hMixedEvent/DeltaMassDeltaCent"), antiLambda1.mass() - antiLambda2.mass(), antiLambda1.centrality() - antiLambda2.centrality()); + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hMixedEvent/DeltaMassDeltaPt"), antiLambda1.mass() - antiLambda2.mass(), antiLambda1.pt() - antiLambda2.pt()); + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hMixedEvent/DeltaCentDeltaMult"), antiLambda1.centrality() - antiLambda2.centrality(), antiLambda1.multiplicity() - antiLambda2.multiplicity()); + + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hMixedEvent/Mass"), antiLambda1.mass(), antiLambda2.mass()); + + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hMixedEvent/CosMult"), cosDeltaThetaStar, antiLambda1.multiplicity(), antiLambda2.multiplicity()); + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hMixedEvent/CosCent"), cosDeltaThetaStar, antiLambda1.centrality(), antiLambda2.centrality()); + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hMixedEvent/Cos"), cosDeltaThetaStar); + } + + if (hasAcceptedPair) { + rSpinAnalysis.fill(HIST("AntiLambdaAntiLambda/hMixedEvent/EventCount"), 0); + } + } + // ================================================================ + // Mass Filter + // ================================================================ + + Configurable minLambdaMass{"minLambdaMass", 1.11f, "Minimum Lambda mass"}; + Configurable maxLambdaMass{"maxLambdaMass", 1.12f, "Maximum Lambda mass"}; + + Filter lambdaMassFilter = aod::lambdahyperon::mass >= minLambdaMass && + aod::lambdahyperon::mass <= maxLambdaMass; + + using FilteredLambdas = soa::Filtered; + using FilteredAntiLambdas = soa::Filtered; + using CollisionsWithMultiplicity = soa::Join; + + Preslice lambdasPerCollision = aod::lambdahyperon::collisionId; + Preslice antiLambdasPerCollision = aod::lambdahyperon::collisionId; + + void process(CollisionsWithMultiplicity const& collisions, FilteredLambdas const& lambdas, FilteredAntiLambdas const& antiLambdas) + { + static constexpr int MinimumSameSpeciesCandidates = 2; + + for (auto const& collision : collisions) { + + const auto lambdasThisCollision = lambdas.sliceBy(lambdasPerCollision, collision.globalIndex()); + const auto antiLambdasThisCollision = antiLambdas.sliceBy(antiLambdasPerCollision, collision.globalIndex()); + + // Lambda–anti-Lambda requires at least one of each. + if (lambdasThisCollision.size() > 0 && antiLambdasThisCollision.size() > 0) { + fillLambdaAntiLambdaSameEvent(lambdasThisCollision, antiLambdasThisCollision); + } + + // Lambda–Lambda requires at least two Lambdas. + if (lambdasThisCollision.size() >= MinimumSameSpeciesCandidates) { + fillLambdaLambdaSameEvent(lambdasThisCollision); + } + + // Anti-Lambda–anti-Lambda requires at least two anti-Lambdas. + if (antiLambdasThisCollision.size() >= MinimumSameSpeciesCandidates) { + fillAntiLambdaAntiLambdaSameEvent(antiLambdasThisCollision); + } + } + + // ============================================================ + // Mixed events + // ============================================================ + + for (auto const& [collision1, collision2] : combinations(CombinationsStrictlyUpperIndexPolicy(collisions, collisions))) { + + const float deltaMultiplicity = std::abs(static_cast(collision1.multNTracksPV()) - static_cast(collision2.multNTracksPV())); + + if (deltaMultiplicity > mixedEventMaxDeltaMultiplicity) { + continue; + } + + const auto lambdas1 = lambdas.sliceBy(lambdasPerCollision, collision1.globalIndex()); + const auto lambdas2 = lambdas.sliceBy(lambdasPerCollision, collision2.globalIndex()); + + const auto antiLambdas1 = antiLambdas.sliceBy(antiLambdasPerCollision, collision1.globalIndex()); + const auto antiLambdas2 = antiLambdas.sliceBy(antiLambdasPerCollision, collision2.globalIndex()); + + // Lambda–anti-Lambda requires at least one of each. + if (lambdas1.size() > 0 && antiLambdas2.size() > 0) { + fillLambdaAntiLambdaMixedEvent(lambdas1, antiLambdas2); + } + if (lambdas2.size() > 0 && antiLambdas1.size() > 0) { + fillAntiLambdaLambdaMixedEvent(antiLambdas1, lambdas2); + } + // Lambda–Lambda requires at least two Lambdas. + if (lambdas1.size() > 0 && lambdas2.size() > 0) { + fillLambdaLambdaMixedEvent(lambdas1, lambdas2); + } + // Anti-Lambda–anti-Lambda requires at least two anti-Lambdas. + if (antiLambdas1.size() > 0 && antiLambdas2.size() > 0) { + fillAntiLambdaAntiLambdaMixedEvent(antiLambdas1, antiLambdas2); + } + } + } +}; + +/*WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + const bool isMC = cfgc.options().get("isMC"); + + WorkflowSpec workflow; + + if (isMC) { + workflow.push_back(adaptAnalysisTask(cfgc)); + workflow.push_back(adaptAnalysisTask(cfgc)); + workflow.push_back(adaptAnalysisTask(cfgc)); + } else { + workflow.push_back(adaptAnalysisTask(cfgc)); + workflow.push_back(adaptAnalysisTask(cfgc)); + workflow.push_back(adaptAnalysisTask(cfgc)); + } + + return workflow; +}*/ + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGCF/TwoParticleCorrelations/Tasks/lambdaR2Correlation.cxx b/PWGCF/TwoParticleCorrelations/Tasks/lambdaR2Correlation.cxx index 7d4222a57cf..bcf8852121d 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/lambdaR2Correlation.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/lambdaR2Correlation.cxx @@ -123,36 +123,6 @@ DECLARE_SOA_TABLE(LambdaTracks, "AOD", "LAMBDATRACKS", o2::soa::Index<>, lambdatrack::CorrFact); using LambdaTrack = LambdaTracks::iterator; -namespace kaontrack -{ -DECLARE_SOA_INDEX_COLUMN(LambdaCollision, lambdaCollision); -DECLARE_SOA_COLUMN(Pt, pt, float); -DECLARE_SOA_COLUMN(Eta, eta, float); -DECLARE_SOA_COLUMN(Phi, phi, float); -DECLARE_SOA_COLUMN(Rap, rap, float); -DECLARE_SOA_COLUMN(Px, px, float); -DECLARE_SOA_COLUMN(Py, py, float); -DECLARE_SOA_COLUMN(Pz, pz, float); -DECLARE_SOA_COLUMN(Mass, mass, float); -DECLARE_SOA_COLUMN(KaonTrackId, kaonTrackId, int64_t); -DECLARE_SOA_COLUMN(PartType, partType, int8_t); -DECLARE_SOA_COLUMN(CorrFact, corrFact, float); -} // namespace kaontrack -DECLARE_SOA_TABLE(KaonTracks, "AOD", "KAONTRACKS", o2::soa::Index<>, - kaontrack::LambdaCollisionId, - kaontrack::Pt, - kaontrack::Eta, - kaontrack::Phi, - kaontrack::Rap, - kaontrack::Px, - kaontrack::Py, - kaontrack::Pz, - kaontrack::Mass, - kaontrack::KaonTrackId, - kaontrack::PartType, - kaontrack::CorrFact); -using KaonTrack = KaonTracks::iterator; - namespace lambdatrackext { DECLARE_SOA_COLUMN(LambdaSharingDaughter, lambdaSharingDaughter, bool); @@ -166,18 +136,6 @@ DECLARE_SOA_TABLE(LambdaTracksExt, "AOD", "LAMBDATRACKSEXT", using LambdaTrackExt = LambdaTracksExt::iterator; -namespace kaontrackext -{ -DECLARE_SOA_COLUMN(KaonSharingLambdaDau, kaonSharingLambdaDau, bool); -DECLARE_SOA_COLUMN(KaonSharingLambdaDauIds, kaonSharingLambdaDauIds, std::vector); -DECLARE_SOA_COLUMN(TrueKaonFlag, trueKaonFlag, bool); -} // namespace kaontrackext -DECLARE_SOA_TABLE(KaonTracksExt, "AOD", "KAONTRACKSEXT", - kaontrackext::KaonSharingLambdaDau, - kaontrackext::KaonSharingLambdaDauIds, - kaontrackext::TrueKaonFlag); -using KaonTrackExt = KaonTracksExt::iterator; - namespace lambdamcgentrack { DECLARE_SOA_INDEX_COLUMN(LambdaMcGenCollision, lambdaMcGenCollision); @@ -197,25 +155,6 @@ DECLARE_SOA_TABLE(LambdaMcGenTracks, "AOD", "LMCGENTRACKS", o2::soa::Index<>, lambdatrack::PartType, lambdatrack::CorrFact); using LambdaMcGenTrack = LambdaMcGenTracks::iterator; - -namespace kaonmcgentrack -{ -DECLARE_SOA_INDEX_COLUMN(LambdaMcGenCollision, lambdaMcGenCollision); -} -DECLARE_SOA_TABLE(KaonMcGenTracks, "AOD", "KMCGENTRACKS", o2::soa::Index<>, - kaonmcgentrack::LambdaMcGenCollisionId, - kaontrack::Pt, - kaontrack::Eta, - kaontrack::Phi, - kaontrack::Rap, - kaontrack::Px, - kaontrack::Py, - kaontrack::Pz, - kaontrack::Mass, - kaontrack::KaonTrackId, - kaontrack::PartType, - kaontrack::CorrFact); -using KaonMcGenTrack = KaonMcGenTracks::iterator; } // namespace o2::aod enum CollisionLabels { @@ -236,15 +175,6 @@ enum LambdaLabels { kGenLambdaNoDau, }; -enum KaonLabels { - kKaonAllChargedTracks = 1, - kKaonPassKinSel, - kKaonPassGlobalSel, - kKaonPassDcaSel, - kKaonPassElRejSel, - kKaonPassAllSel -}; - enum EffCorrType { kEffCorrPtCent = 0, kEffCorrPtRapCent @@ -257,19 +187,13 @@ enum CentEstType { enum ParticleType { kLambda = 0, - kAntiLambda, - kKaonPlus, - kKaonMinus + kAntiLambda }; enum ParticlePairType { kLambdaAntiLambda = 0, kLambdaLambda, kAntiLambdaAntiLambda, - kLambdaKaonPlus, - kLambdaKaonMinus, - kAntiLambdaKaonPlus, - kAntiLambdaKaonMinus }; enum ShareDauLambda { @@ -291,10 +215,8 @@ struct LambdaTableProducer { // Table Producers Produces lambdaCollisionTable; Produces lambdaTrackTable; - Produces kaonTrackTable; Produces lambdaMCGenCollisionTable; Produces lambdaMCGenTrackTable; - Produces kaonMCGenTrackTable; // Centrality Axis ConfigurableAxis cCentBins{"cCentBins", {VARIABLE_WIDTH, 0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.f, 60.0f, 70.0f, 80.0f, 90.0f, 100.f}, "Variable Centrality Bins"}; @@ -314,21 +236,6 @@ struct LambdaTableProducer { Configurable cTpcNsigmaCut{"cTpcNsigmaCut", 3.0, "TPC NSigma Selection Cut"}; Configurable cRemoveAmbiguousTracks{"cRemoveAmbiguousTracks", false, "Remove Ambiguous Tracks"}; - // Kaon Tracks - Configurable cKaonMinPt{"cKaonMinPt", 0.3, "Kaon Min pT"}; - Configurable cKaonMaxPt{"cKaonMaxPt", 2.4, "Kaon Max pT"}; - Configurable cKaonRapCut{"cKaonRapCut", 0.5, "Kaon |y| cut"}; - Configurable cKaonGlobalSel{"cKaonGlobalSel", true, "Global Track"}; - Configurable cKaonDcaXYCut{"cKaonDcaXYCut", 0.1, "DcaXY Cut"}; - Configurable cKaonDcaZCut{"cKaonDcaZCut", 1., "DcaZ Cut"}; - Configurable cTpcElRejCutMin{"cTpcElRejCutMin", -3., "Electron Rejection Cut Minimum"}; - Configurable cTpcElRejCutMax{"cTpcElRejCutMax", 5., "Electron Rejection Cut Maximum"}; - Configurable cKaonTpcNSigmaCut{"cKaonTpcNSigmaCut", 2, "TPC Kaon NSigma Cut"}; - Configurable cTpcRejCut{"cTpcRejCut", 3, "TPC Rej Cut"}; - Configurable cKaonTofNSigmaCut{"cKaonTofNSigmaCut", 2, "TOF Kaon NSigma Cut"}; - Configurable cTofRejCut{"cTofRejCut", 3, "TOF Rej Cut"}; - Configurable cKaonTpcPtSel{"cKaonTpcPtSel", 0.7, "Kaon TPC pT cutoff"}; - // V0s Configurable cMinDcaProtonToPV{"cMinDcaProtonToPV", 0.02, "Minimum Proton DCAr to PV"}; Configurable cMinDcaPionToPV{"cMinDcaPionToPV", 0.06, "Minimum Pion DCAr to PV"}; @@ -372,19 +279,19 @@ struct LambdaTableProducer { HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; // Initialize corr_factor objects - std::vector> vCorrFactStrings = {{"hEffVsPtCentLambda", "hEffVsPtCentAntiLambda", "hEffVsPtCentKaonPlus", "hEffVsPtCentKaonMinus"}, {"hEffVsPtYCentLambda", "hEffVsPtYCentAntiLambda", "hEffVsPtYCentKaonPlus", "hEffVsPtYCentKaonMinus"}}; + std::vector> vCorrFactStrings = {{"hEffVsPtCentLambda", "hEffVsPtCentAntiLambda"}, {"hEffVsPtYCentLambda", "hEffVsPtYCentAntiLambda"}}; // Store correction histograms struct CorrHist { - std::array vPtCentCorrHists{}; - std::array vPtRapCentCorrHists{}; + std::array vPtCentCorrHists{}; + std::array vPtRapCentCorrHists{}; } corrHist; // Initialize Global Variables float cent = 0.; TList* ccdbObjRecoEff = nullptr; TList* ccdbObjMatchEff = nullptr; - static constexpr auto SubDir = std::array{"QA/Lambda/", "QA/AntiLambda/", "QA/KaonPlus/", "QA/KaonMinus/"}; + static constexpr auto SubDir = std::array{"QA/Lambda/", "QA/AntiLambda/"}; void init(InitContext const&) { @@ -404,7 +311,7 @@ struct LambdaTableProducer { const AxisSpec axisV0Eta(48, -1.2, 1.2, "#eta"); const AxisSpec axisV0Phi(36, 0., TwoPI, "#phi (rad)"); - const AxisSpec axisRadius(200, 0, 200, "r(cm)"); + const AxisSpec axisRadius(5000, 0, 5, "r(cm)"); const AxisSpec axisCosPA(100, 0.99, 1.0, "cos(#theta_{PA})"); const AxisSpec axisDcaV0PV(100, 0., 0.1, "dca (cm)"); const AxisSpec axisDcaProngPV(5000, -50., 50., "dca (cm)"); @@ -414,15 +321,12 @@ struct LambdaTableProducer { const AxisSpec axisQtarm(40, 0, 0.4, "q_{T}"); const AxisSpec axisDcaLambda(100, 0., cMaxDcaV0ToPV, "Dca_{V^{0}}"); - const AxisSpec axisDcaKaon(100, -cKaonDcaXYCut, cKaonDcaXYCut, "Dca_{K}"); - const AxisSpec axisITSTPCTrackPt(100, 0, 10, "p_{T} (GeV/#it{c})"); const AxisSpec axisTrackPt(40, 0, 4, "p_{T} (GeV/#it{c})"); const AxisSpec axisTrackDCA(200, -1, 1, "dca_{XY} (cm)"); const AxisSpec axisMomPID(80, 0, 4, "p_{T} (GeV/#it{c})"); const AxisSpec axisTrackNsigma(401, -10.025, 10.025, {"n#sigma"}); const AxisSpec axisTrackdEdx(360, 20, 200, "#frac{dE}{dx}"); - const AxisSpec axisTrackTofSignal(240, 0, 1.2, "#beta"); // Create Histograms. // Event histograms @@ -432,7 +336,6 @@ struct LambdaTableProducer { // QA histos.add("Tracks/h1f_lambda_info", "Lambda selection info", kTH1F, {axisTrks}); - histos.add("Tracks/h1f_kaon_info", "Kaon selection info", kTH1F, {axisTrks}); histos.add("Tracks/h1f_effcorr_info", "Efficiency correction info", kTH1F, {axisEffChecks}); histos.add("Tracks/h2f_armpod_before_sel", "Armentros-Podolanski Plot", kTH2F, {axisAlpha, axisQtarm}); histos.add("Tracks/h2f_armpod_after_sel", "Armentros-Podolanski Plot", kTH2F, {axisAlpha, axisQtarm}); @@ -458,13 +361,6 @@ struct LambdaTableProducer { // Dca analysis histogram histos.add("QA/Lambda/DCA/h3f_Dca_vs_pT_cent", "DCA", kTH3F, {axisCent, axisV0Pt, axisDcaLambda}); - histos.add("QA/KaonPlus/DCA/h3f_Dca_vs_pT_cent", "DCA", kTH3F, {axisCent, axisV0Pt, axisDcaKaon}); - - // QA Kaons - histos.add("QA/KaonPlus/hdEdX", "dE/dx vs pT", kTH2F, {axisMomPID, axisTrackdEdx}); - histos.add("QA/KaonPlus/hTOFSignal", "#beta_{TOF} vs p_{T}", kTH2F, {axisMomPID, axisTrackTofSignal}); - histos.add("QA/KaonPlus/hTPCNSigma", "n#sigma_{TPC} vs p_{T}", kTH2F, {axisMomPID, axisTrackNsigma}); - histos.add("QA/KaonPlus/hTOFNSigma", "n#sigma_{TOF} vs p_{T}", kTH2F, {axisMomPID, axisTrackNsigma}); // MC Generated Histograms if (doprocessMCRecoGen || doprocessMCReco) { @@ -472,9 +368,6 @@ struct LambdaTableProducer { histos.add("QA/Lambda/DCA/h3f_Prm_Dca_vs_pT_cent", "Primary DCA", kTH3F, {axisCent, axisV0Pt, axisDcaLambda}); histos.add("QA/Lambda/DCA/h3f_Scd_Dca_vs_pT_cent", "Weak Decay DCA", kTH3F, {axisCent, axisV0Pt, axisDcaLambda}); histos.add("QA/Lambda/DCA/h3f_Mat_Dca_vs_pT_cent", "Material DCA", kTH3F, {axisCent, axisV0Pt, axisDcaLambda}); - histos.add("QA/KaonPlus/DCA/h3f_Prm_Dca_vs_pT_cent", "Primary DCA", kTH3F, {axisCent, axisV0Pt, axisDcaKaon}); - histos.add("QA/KaonPlus/DCA/h3f_Scd_Dca_vs_pT_cent", "Weak Decay DCA", kTH3F, {axisCent, axisV0Pt, axisDcaKaon}); - histos.add("QA/KaonPlus/DCA/h3f_Mat_Dca_vs_pT_cent", "Material DCA", kTH3F, {axisCent, axisV0Pt, axisDcaKaon}); // McGen Histos histos.add("McGen/h1f_collision_recgen", "# of Reco Collision Associated to One Mc Generator Collision", kTH1F, {axisMult}); @@ -497,9 +390,6 @@ struct LambdaTableProducer { // QA Anti-Lambda histos.addClone("QA/Lambda/", "QA/AntiLambda/"); - // QA KaonMinus - histos.addClone("QA/KaonPlus/", "QA/KaonMinus/"); - // Set bin labels histos.get(HIST("Events/h1f_collisions_info"))->GetXaxis()->SetBinLabel(CollisionLabels::kTotCol, "kTotCol"); histos.get(HIST("Events/h1f_collisions_info"))->GetXaxis()->SetBinLabel(CollisionLabels::kPassSelCol, "kPassSelCol"); @@ -509,12 +399,6 @@ struct LambdaTableProducer { histos.get(HIST("Tracks/h1f_lambda_info"))->GetXaxis()->SetBinLabel(LambdaLabels::kPassV0KinCuts, "kPassV0KinCuts"); histos.get(HIST("Tracks/h1f_lambda_info"))->GetXaxis()->SetBinLabel(LambdaLabels::kPassV0TopoSel, "kPassV0TopoSel"); histos.get(HIST("Tracks/h1f_lambda_info"))->GetXaxis()->SetBinLabel(LambdaLabels::kAllSelPassed, "kAllSelPassed"); - histos.get(HIST("Tracks/h1f_kaon_info"))->GetXaxis()->SetBinLabel(KaonLabels::kKaonAllChargedTracks, "kKaonAllChargedTracks"); - histos.get(HIST("Tracks/h1f_kaon_info"))->GetXaxis()->SetBinLabel(KaonLabels::kKaonPassKinSel, "kKaonPassKinSel"); - histos.get(HIST("Tracks/h1f_kaon_info"))->GetXaxis()->SetBinLabel(KaonLabels::kKaonPassGlobalSel, "kKaonPassGlobalSel"); - histos.get(HIST("Tracks/h1f_kaon_info"))->GetXaxis()->SetBinLabel(KaonLabels::kKaonPassDcaSel, "kKaonPassDcaSel"); - histos.get(HIST("Tracks/h1f_kaon_info"))->GetXaxis()->SetBinLabel(KaonLabels::kKaonPassElRejSel, "kKaonPassElRejSel"); - histos.get(HIST("Tracks/h1f_kaon_info"))->GetXaxis()->SetBinLabel(KaonLabels::kKaonPassAllSel, "kKaonPassAllSel"); // Load correction factor if (cGetCorrectionFlag) { @@ -751,53 +635,6 @@ struct LambdaTableProducer { return true; } - template - bool selKaonTrack(T const& track, float const& rap) - { - // Kinematic selection - if (track.pt() <= cKaonMinPt || track.pt() >= cKaonMaxPt || std::abs(rap) >= cKaonRapCut) { - return false; - } - - histos.fill(HIST("Tracks/h1f_kaon_info"), kKaonPassKinSel); - - // Global track selection - if (cKaonGlobalSel && !track.isGlobalTrackWoDCA()) { - return false; - } - - histos.fill(HIST("Tracks/h1f_kaon_info"), kKaonPassGlobalSel); - - // Dca selection - if (std::abs(track.dcaXY()) >= cKaonDcaXYCut || std::abs(track.dcaZ()) >= cKaonDcaZCut) { - return false; - } - - histos.fill(HIST("Tracks/h1f_kaon_info"), kKaonPassDcaSel); - - // Electron rejection - if (std::abs(track.tpcNSigmaPi()) > cTpcRejCut && std::abs(track.tpcNSigmaKa()) > cTpcRejCut && std::abs(track.tpcNSigmaPr()) > cTpcRejCut && track.tpcNSigmaEl() > cTpcElRejCutMin && track.tpcNSigmaEl() < cTpcElRejCutMax) { - return false; - } - - histos.fill(HIST("Tracks/h1f_kaon_info"), kKaonPassElRejSel); - - // Kaon PID TPC + TOF - if (track.hasTOF()) { - if (std::abs(track.tofNSigmaKa()) >= cKaonTofNSigmaCut || std::abs(track.tofNSigmaPi()) < cTofRejCut || std::abs(track.tofNSigmaPr()) < cTofRejCut || std::abs(track.tpcNSigmaKa()) >= cKaonTpcNSigmaCut) { - return false; - } - } else { - if (track.pt() >= cKaonTpcPtSel || std::abs(track.tpcNSigmaKa()) >= cKaonTpcNSigmaCut || std::abs(track.tpcNSigmaPi()) < cTpcRejCut || std::abs(track.tpcNSigmaPr()) < cTpcRejCut) { - return false; - } - } - - histos.fill(HIST("Tracks/h1f_kaon_info"), kKaonPassAllSel); - - return true; - } - // Correction factors template float getCorrectionFactors(V const& v, float const& rap) @@ -851,18 +688,6 @@ struct LambdaTableProducer { histos.fill(HIST(SubDir[part]) + HIST("h2f_neg_prong_tpc_nsigma_pi_vs_p"), negtrack.tpcInnerParam(), negtrack.tpcNSigmaPi()); } - // Kaon QA - template - void fillKaonQA(T const& track) - { - histos.fill(HIST(SubDir[part]) + HIST("hdEdX"), track.pt(), track.tpcSignal()); - histos.fill(HIST(SubDir[part]) + HIST("hTPCNSigma"), track.pt(), track.tpcNSigmaKa()); - if (track.hasTOF()) { - histos.fill(HIST(SubDir[part]) + HIST("hTOFSignal"), track.pt(), track.beta()); - histos.fill(HIST(SubDir[part]) + HIST("hTOFNSigma"), track.pt(), track.tofNSigmaKa()); - } - } - // Dca analysis template void getDcaHist(T const& track, float const& dca) @@ -973,61 +798,6 @@ struct LambdaTableProducer { v0.template posTrack_as().index(), v0.template negTrack_as().index(), posTrackKin, negTrackKin, (int8_t)partType, lambdaCorrFact); } - - // Loop over tracks to select Kaon - float kaonCorrFact = 1.; - for (auto const& track : tracks) { - // Check corresponding MC particle - if constexpr (dmc == kMC) { - if (!track.has_mcParticle()) { - continue; - } - } - - // All charged tracks - histos.fill(HIST("Tracks/h1f_kaon_info"), kKaonAllChargedTracks); - - // Kaon rapidity - std::array mom = {track.px(), track.py(), track.pz()}; - float rap = RecoDecay::y(mom, MassKPlus); - if (!selKaonTrack(track, rap)) { // Kaon selection - continue; - } - - // MC matching - if constexpr (dmc == kMC) { - auto mcpart = track.mcParticle(); - if (cSelPrimaryParticle && !mcpart.isPhysicalPrimary()) { // Primary kaon selection - continue; - } - - if (cSelTrueParticle && std::abs(mcpart.pdgCode()) != kKPlus) { // True kaon selection - continue; - } - } - - // K+ / K- - if (track.sign() >= 0) { - getDcaHist(track, track.dcaXY()); - fillKaonQA(track); - partType = kKaonPlus; - } else if (track.sign() <= 0) { - getDcaHist(track, track.dcaXY()); - fillKaonQA(track); - partType = kKaonMinus; - } else { - continue; - } - - // Get Kaon correction factor - if (cGetCorrectionFlag) { - kaonCorrFact = (partType == kKaonPlus) ? getCorrectionFactors(track, rap) : getCorrectionFactors(track, rap); - } - - // Fill table - kaonTrackTable(lambdaCollisionTable.lastIndex(), track.pt(), track.eta(), track.phi(), rap, track.px(), track.py(), track.pz(), MassKaonCharged, - track.globalIndex(), (int8_t)partType, kaonCorrFact); - } } // MC Generater Level Tables @@ -1042,65 +812,46 @@ struct LambdaTableProducer { // Loop over MC particles for (auto const& mcpart : mcParticles) { - // Check for Primary Lambda/Anti-Lambda/K+/K- + // Check for Primary Lambda/Anti-Lambda if (mcpart.isPhysicalPrimary() && mcpart.pdgCode() == kLambda0) { partType = kLambda; } else if (mcpart.isPhysicalPrimary() && mcpart.pdgCode() == kLambda0Bar) { partType = kAntiLambda; - } else if (mcpart.isPhysicalPrimary() && mcpart.pdgCode() == kKPlus) { - partType = kKaonPlus; - } else if (mcpart.isPhysicalPrimary() && mcpart.pdgCode() == kKMinus) { - partType = kKaonMinus; } else { continue; } - // Fill Lambda Table - if (partType == kLambda || partType == kAntiLambda) { - // Kinematic selection - if (mcpart.pt() <= cLambdaMinPt || mcpart.pt() >= cLambdaMaxPt || std::abs(mcpart.y()) >= cLambdaRapCut) { - continue; - } + // Kinematic selection + if (mcpart.pt() <= cLambdaMinPt || mcpart.pt() >= cLambdaMaxPt || std::abs(mcpart.y()) >= cLambdaRapCut) { + continue; + } - histos.fill(HIST("Tracks/h1f_lambda_info"), kGenTotAccLambda); + histos.fill(HIST("Tracks/h1f_lambda_info"), kGenTotAccLambda); - // get daughter track info and check for decay channel flag - if (!mcpart.has_daughters()) { - histos.fill(HIST("Tracks/h1f_lambda_info"), kGenLambdaNoDau); - continue; - } - auto dautracks = mcpart.template daughters_as(); - std::vector daughterPDGs, daughterIDs; - for (auto const& dautrack : dautracks) { - daughterPDGs.push_back(dautrack.pdgCode()); - daughterIDs.push_back(dautrack.globalIndex()); - } - - if (partType == kLambda) { - histos.fill(HIST("McGen/h1f_lambda_daughter_PDG"), daughterPDGs[0]); - histos.fill(HIST("McGen/h1f_lambda_daughter_PDG"), daughterPDGs[1]); - histos.fill(HIST("McGen/h1f_lambda_daughter_PDG"), mcpart.pdgCode()); - } else { - histos.fill(HIST("McGen/h1f_antilambda_daughter_PDG"), daughterPDGs[0]); - histos.fill(HIST("McGen/h1f_antilambda_daughter_PDG"), daughterPDGs[1]); - histos.fill(HIST("McGen/h1f_antilambda_daughter_PDG"), mcpart.pdgCode()); - } - // Fill table - lambdaMCGenTrackTable(lambdaMCGenCollisionTable.lastIndex(), mcpart.pt(), mcpart.eta(), mcpart.phi(), mcpart.y(), mcpart.px(), mcpart.py(), mcpart.pz(), RecoDecay::m(mcpart.p(), mcpart.e()), - daughterIDs[0], daughterIDs[1], (int8_t)partType, 1.); + // get daughter track info and check for decay channel flag + if (!mcpart.has_daughters()) { + histos.fill(HIST("Tracks/h1f_lambda_info"), kGenLambdaNoDau); + continue; + } + auto dautracks = mcpart.template daughters_as(); + std::vector daughterPDGs, daughterIDs; + for (auto const& dautrack : dautracks) { + daughterPDGs.push_back(dautrack.pdgCode()); + daughterIDs.push_back(dautrack.globalIndex()); } - // Fill Kaon Table - if (partType == kKaonPlus || partType == kKaonMinus) { - // Kinematic selection - if (mcpart.pt() <= cKaonMinPt || mcpart.pt() >= cKaonMaxPt || std::abs(mcpart.y()) >= cKaonRapCut) { - continue; - } - - // Fill table - kaonMCGenTrackTable(lambdaMCGenCollisionTable.lastIndex(), mcpart.pt(), mcpart.eta(), mcpart.phi(), mcpart.y(), mcpart.px(), mcpart.py(), mcpart.pz(), RecoDecay::m(mcpart.p(), mcpart.e()), - mcpart.globalIndex(), (int8_t)partType, 1.); + if (partType == kLambda) { + histos.fill(HIST("McGen/h1f_lambda_daughter_PDG"), daughterPDGs[0]); + histos.fill(HIST("McGen/h1f_lambda_daughter_PDG"), daughterPDGs[1]); + histos.fill(HIST("McGen/h1f_lambda_daughter_PDG"), mcpart.pdgCode()); + } else { + histos.fill(HIST("McGen/h1f_antilambda_daughter_PDG"), daughterPDGs[0]); + histos.fill(HIST("McGen/h1f_antilambda_daughter_PDG"), daughterPDGs[1]); + histos.fill(HIST("McGen/h1f_antilambda_daughter_PDG"), mcpart.pdgCode()); } + // Fill table + lambdaMCGenTrackTable(lambdaMCGenCollisionTable.lastIndex(), mcpart.pt(), mcpart.eta(), mcpart.phi(), mcpart.y(), mcpart.px(), mcpart.py(), mcpart.pz(), RecoDecay::m(mcpart.p(), mcpart.e()), + daughterIDs[0], daughterIDs[1], (int8_t)partType, 1.); } } @@ -1177,13 +928,10 @@ struct LambdaTableProducer { struct LambdaTracksExtProducer { // Tables Produces lambdaTrackExtTable; - Produces kaonTrackExtTable; // Configurables Configurable cAcceptAllLambda{"cAcceptAllLambda", false, "Accept all Lambda"}; Configurable cRejAllLambdaShaDau{"cRejAllLambdaShaDau", true, "Reject all Lambda sharing daughters"}; - Configurable cAcceptAllKaon{"cAcceptAllKaon", false, "Accept all Kaons"}; - Configurable cRejAllKaonShaLaDau{"cRejAllKaonShaLaDau", true, "Reject all Kaons sharing Lambda daughters"}; // Histogram Registry. HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -1200,20 +948,9 @@ struct LambdaTracksExtProducer { histos.add("h1i_totantilambda_mult", "Multiplicity", kTH1I, {axisMult}); histos.add("h1i_lambda_mult", "Multiplicity", kTH1I, {axisMult}); histos.add("h1i_antilambda_mult", "Multiplicity", kTH1I, {axisMult}); - - histos.add("h1i_totkaplus_mult", "Multiplicity", kTH1I, {axisMult}); - histos.add("h1i_totkaminus_mult", "Multiplicity", kTH1I, {axisMult}); - histos.add("h1i_kaplus_mult", "Multiplicity", kTH1I, {axisMult}); - histos.add("h1i_kaminus_mult", "Multiplicity", kTH1I, {axisMult}); - histos.add("h2d_n2_etaphi_LaP_LaM", "#rho_{2}^{SharePair}", kTH2D, {axisDEta, axisDPhi}); histos.add("h2d_n2_etaphi_LaP_LaP", "#rho_{2}^{SharePair}", kTH2D, {axisDEta, axisDPhi}); histos.add("h2d_n2_etaphi_LaM_LaM", "#rho_{2}^{SharePair}", kTH2D, {axisDEta, axisDPhi}); - - histos.add("h2d_n2_etaphi_KaPLaP", "#rho_{2}", kTH2D, {axisDEta, axisDPhi}); - histos.add("h2d_n2_etaphi_KaPLaM", "#rho_{2}", kTH2D, {axisDEta, axisDPhi}); - histos.add("h2d_n2_etaphi_KaMLaP", "#rho_{2}", kTH2D, {axisDEta, axisDPhi}); - histos.add("h2d_n2_etaphi_KaMLaM", "#rho_{2}", kTH2D, {axisDEta, axisDPhi}); } void processDummy(aod::LambdaCollisions::iterator const&) {} @@ -1291,75 +1028,6 @@ struct LambdaTracksExtProducer { } PROCESS_SWITCH(LambdaTracksExtProducer, processLambdaTrackExt, "Process for lambda track extension", false); - - void processKaonTrackExt(aod::LambdaCollisions::iterator const&, aod::LambdaTracks const& lambdaTracks, aod::KaonTracks const& kaonTracks) - { - int nTotKaonPlus = 0, nTotKaonMinus = 0, nSelKaonPlus = 0, nSelKaonMinus = 0; - - for (auto const& kaonTrack : kaonTracks) { - bool kaonSharingLambdaDauFlag = false, trueKaonFlag = false; - std::vector vKaonShareDauLambdaIndex; - - if (kaonTrack.partType() == kKaonPlus) { - ++nTotKaonPlus; - } else if (kaonTrack.partType() == kKaonMinus) { - ++nTotKaonMinus; - } - - for (auto const& lambdaTrack : lambdaTracks) { - // Removal based on shared track index - if (kaonTrack.kaonTrackId() == lambdaTrack.posTrackId() || kaonTrack.kaonTrackId() == lambdaTrack.negTrackId()) { - vKaonShareDauLambdaIndex.push_back(kaonTrack.kaonTrackId()); - kaonSharingLambdaDauFlag = true; - - // Fill Deta-Dphi Histogram - if (kaonTrack.partType() == kKaonPlus && lambdaTrack.partType() == kLambda) { - histos.fill(HIST("h2d_n2_etaphi_KaPLaP"), kaonTrack.eta() - lambdaTrack.eta(), RecoDecay::constrainAngle(kaonTrack.phi() - lambdaTrack.phi(), -PIHalf)); - } else if (kaonTrack.partType() == kKaonPlus && lambdaTrack.partType() == kAntiLambda) { - histos.fill(HIST("h2d_n2_etaphi_KaPLaM"), kaonTrack.eta() - lambdaTrack.eta(), RecoDecay::constrainAngle(kaonTrack.phi() - lambdaTrack.phi(), -PIHalf)); - } else if (kaonTrack.partType() == kKaonMinus && lambdaTrack.partType() == kLambda) { - histos.fill(HIST("h2d_n2_etaphi_KaMLaP"), kaonTrack.eta() - lambdaTrack.eta(), RecoDecay::constrainAngle(kaonTrack.phi() - lambdaTrack.phi(), -PIHalf)); - } else if (kaonTrack.partType() == kKaonMinus && lambdaTrack.partType() == kAntiLambda) { - histos.fill(HIST("h2d_n2_etaphi_KaMLaM"), kaonTrack.eta() - lambdaTrack.eta(), RecoDecay::constrainAngle(kaonTrack.phi() - lambdaTrack.phi(), -PIHalf)); - } - } - } - - // Accept / Reject - trueKaonFlag = cAcceptAllKaon || (cRejAllKaonShaLaDau && !kaonSharingLambdaDauFlag); - - // Multiplicity of selected kaons - if (trueKaonFlag) { - if (kaonTrack.partType() == kKaonPlus) { - ++nSelKaonPlus; - } else if (kaonTrack.partType() == kKaonMinus) { - ++nSelKaonMinus; - } - } - - // Fill LambdaTrackExt table - kaonTrackExtTable(kaonSharingLambdaDauFlag, vKaonShareDauLambdaIndex, trueKaonFlag); - } - - // Fill multiplicity histograms - if (nTotKaonPlus != 0) { - histos.fill(HIST("h1i_totkaplus_mult"), nTotKaonPlus); - } - - if (nTotKaonMinus != 0) { - histos.fill(HIST("h1i_totkaminus_mult"), nTotKaonMinus); - } - - if (nSelKaonPlus != 0) { - histos.fill(HIST("h1i_kaplus_mult"), nSelKaonPlus); - } - - if (nSelKaonMinus != 0) { - histos.fill(HIST("h1i_kaminus_mult"), nSelKaonMinus); - } - } - - PROCESS_SWITCH(LambdaTracksExtProducer, processKaonTrackExt, "Process for kaon track extension", false); }; struct LambdaR2Correlation { @@ -1367,9 +1035,6 @@ struct LambdaR2Correlation { Configurable cLambdaNPtBins{"cLambdaNPtBins", 34, "N pT Bins"}; Configurable cLambdaPtMin{"cLambdaPtMin", 0.7, "Lambda pT Min"}; Configurable cLambdaPtMax{"cLambdaPtMax", 3.4, "Lambda pT Max"}; - Configurable cKaonNPtBins{"cKaonNPtBins", 20, "N pT Bins"}; - Configurable cKaonPtMin{"cKaonPtMin", 0.3, "Kaon pT Min"}; - Configurable cKaonPtMax{"cKaonPtMax", 2.2, "Kaon pT Max"}; Configurable cNRapBins{"cNRapBins", 10, "N Rapidity Bins"}; Configurable cMinRap{"cMinRap", -0.5, "Minimum Rapidity"}; @@ -1382,7 +1047,7 @@ struct LambdaR2Correlation { // Lambda Kaon femtoscopic correction Configurable cApplyFemtoSel{"cApplyFemtoSel", false, "Femto qinv selection"}; - Configurable cFemtoCut{"cFemtoCut", 0.1, "Kaon--Lambda Femto qinv cut"}; + Configurable cFemtoCut{"cFemtoCut", 0.1, "Femto qinv cut"}; // Lambda Kaon two-track cuts Configurable cApplyTwoTrackCut{"cApplyTwoTrackCut", false, "Flag for two track cut"}; @@ -1434,8 +1099,6 @@ struct LambdaR2Correlation { const AxisSpec axisDPhi(640, -PIHalf, 3. * PIHalf, "#Delta#varphi"); const AxisSpec axisMass(100, 1.06, 1.16, "M_{#Lambda} (GeV/#it{c}^{2})"); const AxisSpec axisPtLambda(cLambdaNPtBins, cLambdaPtMin, cLambdaPtMax, "p_{T} (GeV/#it{c})"); - const AxisSpec axisPtKaon(cKaonNPtBins, cKaonPtMin, cKaonPtMax, "p_{T} (GeV/#it{c})"); - const AxisSpec axisEta(cNRapBins, cMinRap, cMaxRap, "#eta"); const AxisSpec axisRap(cNRapBins, cMinRap, cMaxRap, "y"); const AxisSpec axisPhi(cNPhiBins, 0., TwoPI, "#varphi (rad)"); const AxisSpec axisRapPhi(knrapphibins, kminrapphi, kmaxrapphi, "y #varphi"); @@ -1444,7 +1107,6 @@ struct LambdaR2Correlation { // Event histos.add("Event/Reco/h1f_collision_posz", "V_{Z} Distribution", kTH1F, {axisPosZ}); histos.add("Event/Reco/h1f_ft0m_mult_percentile", "FT0M (%)", kTH1F, {axisCent}); - histos.add("Event/Reco/h2f_Mult_vs_Centrality", "N_{ch} vs FT0M(%)", kTProfile, {axisCent}); // Two track cut histos.add("QA/TwoTrackCut/Before/h2d_n2_detadphi", "#rho_{2}", kTH2D, {axisDEta, axisDPhi}); @@ -1457,16 +1119,10 @@ struct LambdaR2Correlation { if (cAnaEff) { histos.add("Reco/Efficiency/h2f_n1_centpt_LaP", "#rho_{1}^{#Lambda}", kTH2F, {axisCent, axisPtLambda}); histos.add("Reco/Efficiency/h2f_n1_centpt_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH2F, {axisCent, axisPtLambda}); - histos.add("Reco/Efficiency/h2f_n1_centpt_KaP", "#rho_{1}^{K^{#plus}}", kTH2F, {axisCent, axisPtKaon}); - histos.add("Reco/Efficiency/h2f_n1_centpt_KaM", "#rho_{1}^{K^{#minus}}", kTH2F, {axisCent, axisPtKaon}); histos.add("Reco/Efficiency/h3f_n1_centptrap_LaP", "#rho_{1}^{#Lambda}", kTH3F, {axisCent, axisPtLambda, axisRap}); histos.add("Reco/Efficiency/h3f_n1_centptrap_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH3F, {axisCent, axisPtLambda, axisRap}); - histos.add("Reco/Efficiency/h3f_n1_centptrap_KaP", "#rho_{1}^{K^{#plus}}", kTH3F, {axisCent, axisPtKaon, axisRap}); - histos.add("Reco/Efficiency/h3f_n1_centptrap_KaM", "#rho_{1}^{K^{#minus}}", kTH3F, {axisCent, axisPtKaon, axisRap}); histos.add("Reco/Efficiency/h4f_n1_centvzptrap_LaP", "#rho_{1}^{#Lambda}", kTHnSparseF, {axisCent, axisVz, axisPtLambda, axisRap}); histos.add("Reco/Efficiency/h4f_n1_centvzptrap_LaM", "#rho_{1}^{#bar{#Lambda}}", kTHnSparseF, {axisCent, axisVz, axisPtLambda, axisRap}); - histos.add("Reco/Efficiency/h4f_n1_centvzptrap_KaP", "#rho_{1}^{K^{#plus}}", kTHnSparseF, {axisCent, axisVz, axisPtKaon, axisRap}); - histos.add("Reco/Efficiency/h4f_n1_centvzptrap_KaM", "#rho_{1}^{K^{#minus}}", kTHnSparseF, {axisCent, axisVz, axisPtKaon, axisRap}); } // Single and Two Particle Densities @@ -1475,24 +1131,16 @@ struct LambdaR2Correlation { histos.add("Reco/h3f_n1_centptmass_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH3F, {axisCent, axisPtLambda, axisMass}); histos.add("Reco/h3f_n1_centptrap_LaP", "#rho_{1}^{#Lambda}", kTH3F, {axisCent, axisPtLambda, axisRap}); histos.add("Reco/h3f_n1_centptrap_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH3F, {axisCent, axisPtLambda, axisRap}); - histos.add("Reco/h3f_n1_centptrap_KaP", "#rho_{1}^{K^{#plus}}", kTH3F, {axisCent, axisPtKaon, axisRap}); - histos.add("Reco/h3f_n1_centptrap_KaM", "#rho_{1}^{K^{#minus}}", kTH3F, {axisCent, axisPtKaon, axisRap}); // rho1 for R2 RapPhi histos.add("Reco/h3f_n1_rapphi_LaP", "#rho_{1}^{#Lambda}", kTH3F, {axisCent, axisRap, axisPhi}); histos.add("Reco/h3f_n1_rapphi_LaM", "#rho_{1}^{#bar{#Lambda}}", kTH3F, {axisCent, axisRap, axisPhi}); - histos.add("Reco/h3f_n1_rapphi_KaP", "#rho_{1}^{K^{#plus}}", kTH3F, {axisCent, axisRap, axisPhi}); - histos.add("Reco/h3f_n1_rapphi_KaM", "#rho_{1}^{K^{#minus}}", kTH3F, {axisCent, axisRap, axisPhi}); if (cAnaPairs) { // rho2 for R2 Rap1Phi1Rap2Phi2 histos.add("Reco/h3f_n2_rapphi_LaP_LaM", "#rho_{2}^{#Lambda#bar{#Lambda}}", kTH3F, {axisCent, axisRapPhi, axisRapPhi}); histos.add("Reco/h3f_n2_rapphi_LaP_LaP", "#rho_{2}^{#Lambda#Lambda}", kTH3F, {axisCent, axisRapPhi, axisRapPhi}); histos.add("Reco/h3f_n2_rapphi_LaM_LaM", "#rho_{2}^{#bar{#Lambda}#bar{#Lambda}}", kTH3F, {axisCent, axisRapPhi, axisRapPhi}); - histos.add("Reco/h3f_n2_rapphi_LaP_KaM", "#rho_{2}^{#LambdaK^{#minus}}", kTH3F, {axisCent, axisRapPhi, axisRapPhi}); - histos.add("Reco/h3f_n2_rapphi_LaP_KaP", "#rho_{2}^{#LambdaK^{#plus}}", kTH3F, {axisCent, axisRapPhi, axisRapPhi}); - histos.add("Reco/h3f_n2_rapphi_LaM_KaM", "#rho_{2}^{#bar{#Lambda}K^{#plus}}", kTH3F, {axisCent, axisRapPhi, axisRapPhi}); - histos.add("Reco/h3f_n2_rapphi_LaM_KaP", "#rho_{2}^{#bar{#Lambda}K^{#minus}}", kTH3F, {axisCent, axisRapPhi, axisRapPhi}); } // MCGen @@ -1531,29 +1179,24 @@ struct LambdaR2Correlation { return (std::abs(deta) < cDEtaCut && std::abs(dphistar) < cDPhiStarCut); } - template - bool isClosePair(V const& lambda, T const& track) + template + bool isClosePair(V const& l1, V const& l2) { // Before - histos.fill(HIST("QA/TwoTrackCut/Before/h2d_n2_detadphi"), track.eta() - lambda.eta(), RecoDecay::constrainAngle(track.phi() - lambda.phi(), -PIHalf)); - - // Close pair flag - bool retFlag = false; + histos.fill(HIST("QA/TwoTrackCut/Before/h2d_n2_detadphi"), l1.eta() - l2.eta(), RecoDecay::constrainAngle(l1.phi() - l2.phi(), -PIHalf)); // Assign kinematics - std::array trackKin = {track.pt(), track.eta(), track.phi()}; - std::array lambdaPosTrackKin = {lambda.posTrackKin()[0], lambda.posTrackKin()[1], lambda.posTrackKin()[2]}; - std::array lambdaNegTrackKin = {lambda.negTrackKin()[0], lambda.negTrackKin()[1], lambda.negTrackKin()[2]}; - - if (track.partType() == kKaonPlus) { - retFlag = checkClosePair(trackKin, lambdaPosTrackKin, 1, 1) || checkClosePair(trackKin, lambdaNegTrackKin, 1, -1); - } else if (track.partType() == kKaonMinus) { - retFlag = checkClosePair(trackKin, lambdaPosTrackKin, -1, 1) || checkClosePair(trackKin, lambdaNegTrackKin, -1, -1); - } + std::array posTrackKinLambda1 = {l1.posTrackKin()[0], l1.posTrackKin()[1], l1.posTrackKin()[2]}; + std::array negTrackKinLambda1 = {l1.negTrackKin()[0], l1.negTrackKin()[1], l1.negTrackKin()[2]}; + std::array posTrackKinLambda2 = {l2.posTrackKin()[0], l2.posTrackKin()[1], l2.posTrackKin()[2]}; + std::array negTrackKinLambda2 = {l2.negTrackKin()[0], l2.negTrackKin()[1], l2.negTrackKin()[2]}; + + // Check close pair + bool retFlag = checkClosePair(posTrackKinLambda1, posTrackKinLambda2, 1, 1) && checkClosePair(negTrackKinLambda1, negTrackKinLambda2, -1, -1); // Fill QA if (!retFlag) { // Pair accept - histos.fill(HIST("QA/TwoTrackCut/After/h2d_n2_detadphi"), track.eta() - lambda.eta(), RecoDecay::constrainAngle(track.phi() - lambda.phi(), -PIHalf)); + histos.fill(HIST("QA/TwoTrackCut/After/h2d_n2_detadphi"), l1.eta() - l2.eta(), RecoDecay::constrainAngle(l1.phi() - l2.phi(), -PIHalf)); } // Pair reject @@ -1585,7 +1228,7 @@ struct LambdaR2Correlation { void fillPairHistos(T1& p1, T2& p2) { static constexpr auto SubDirRecGen = std::array{"Reco/", "McGen/"}; - static constexpr auto SubDirHist = std::array{"LaP_LaM", "LaP_LaP", "LaM_LaM", "LaP_KaP", "LaP_KaM", "LaM_KaP", "LaM_KaM", "KaP_KaM", "KaP_KaP", "KaM_KaM"}; + static constexpr auto SubDirHist = std::array{"LaP_LaM", "LaP_LaP", "LaM_LaM"}; const auto rapbin1 = static_cast((p1.rap() - kminrap) / rapbinwidth); const auto rapbin2 = static_cast((p2.rap() - kminrap) / rapbinwidth); @@ -1608,7 +1251,7 @@ struct LambdaR2Correlation { void analyzeSingles(T const& tracks) { static constexpr auto SubDirRecGen = std::array{"Reco/", "McGen/"}; - static constexpr auto SubDirHist = std::array{"LaP", "LaM", "KaP", "KaM"}; + static constexpr auto SubDirHist = std::array{"LaP", "LaM"}; for (auto const& track : tracks) { // Efficiency Plots @@ -1619,9 +1262,7 @@ struct LambdaR2Correlation { } // QA Plots - if (part == kLambda || part == kAntiLambda) { - histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n1_centptmass_") + HIST(SubDirHist[part]), cent, track.pt(), track.mass()); - } + histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n1_centptmass_") + HIST(SubDirHist[part]), cent, track.pt(), track.mass()); histos.fill(HIST(SubDirRecGen[rec_gen]) + HIST("h3f_n1_centptrap_") + HIST(SubDirHist[part]), cent, track.pt(), track.rap(), track.corrFact()); // Rho1 for N1RapPhi @@ -1639,17 +1280,15 @@ struct LambdaR2Correlation { continue; } - // Lambda-Kaon close pair rejection + // Lambda close pair rejection if constexpr (rec_gen == kRec) { - if constexpr (partpair == kLambdaKaonPlus || partpair == kLambdaKaonMinus || partpair == kAntiLambdaKaonPlus || partpair == kAntiLambdaKaonMinus) { - // Close pair - if (cApplyTwoTrackCut && isClosePair(trk_1, trk_2)) { - continue; - } - // Femto selection - if (cApplyFemtoSel && isCloseQinv(trk_1, trk_2)) { - continue; - } + // Close pair + if (cApplyTwoTrackCut && isClosePair(trk_1, trk_2)) { + continue; + } + // Femto selection + if (cApplyFemtoSel && isCloseQinv(trk_1, trk_2)) { + continue; } } @@ -1661,19 +1300,16 @@ struct LambdaR2Correlation { using LambdaCollisions = aod::LambdaCollisions; using LambdaTracks = soa::Join; - using KaonTracks = soa::Join; SliceCache cache; Partition partLambdaTracks = (aod::lambdatrack::partType == (int8_t)kLambda) && (aod::lambdatrackext::trueLambdaFlag == true); Partition partAntiLambdaTracks = (aod::lambdatrack::partType == (int8_t)kAntiLambda) && (aod::lambdatrackext::trueLambdaFlag == true); - Partition partKaonPlusTracks = (aod::kaontrack::partType == (int8_t)kKaonPlus) && (aod::kaontrackext::trueKaonFlag == true); - Partition partKaonMinusTracks = (aod::kaontrack::partType == (int8_t)kKaonMinus) && (aod::kaontrackext::trueKaonFlag == true); void processDummy(aod::LambdaCollisions::iterator const&) {} PROCESS_SWITCH(LambdaR2Correlation, processDummy, "Dummy Process", true); - void processDataReco(LambdaCollisions::iterator const& collision, LambdaTracks const&, KaonTracks const&) + void processDataReco(LambdaCollisions::iterator const& collision, LambdaTracks const&) { histos.fill(HIST("Event/Reco/h1f_collision_posz"), collision.posZ()); histos.fill(HIST("Event/Reco/h1f_ft0m_mult_percentile"), collision.cent()); @@ -1684,23 +1320,15 @@ struct LambdaR2Correlation { auto lambdaTracks = partLambdaTracks->sliceByCached(aod::lambdatrack::lambdaCollisionId, collision.globalIndex(), cache); auto antiLambdaTracks = partAntiLambdaTracks->sliceByCached(aod::lambdatrack::lambdaCollisionId, collision.globalIndex(), cache); - auto kaonPlusTracks = partKaonPlusTracks->sliceByCached(aod::kaontrack::lambdaCollisionId, collision.globalIndex(), cache); - auto kaonMinusTracks = partKaonMinusTracks->sliceByCached(aod::kaontrack::lambdaCollisionId, collision.globalIndex(), cache); analyzeSingles(lambdaTracks); analyzeSingles(antiLambdaTracks); - analyzeSingles(kaonPlusTracks); - analyzeSingles(kaonMinusTracks); if (cAnaPairs) { // Pairs Only analyzePairs(lambdaTracks, antiLambdaTracks); analyzePairs(lambdaTracks, lambdaTracks); analyzePairs(antiLambdaTracks, antiLambdaTracks); - analyzePairs(lambdaTracks, kaonPlusTracks); - analyzePairs(lambdaTracks, kaonMinusTracks); - analyzePairs(antiLambdaTracks, kaonPlusTracks); - analyzePairs(antiLambdaTracks, kaonMinusTracks); } } @@ -1708,15 +1336,12 @@ struct LambdaR2Correlation { using LambdaMcGenCollisions = aod::LambdaMcGenCollisions; using LambdaMcGenTracks = aod::LambdaMcGenTracks; - using KaonMcGenTracks = aod::KaonMcGenTracks; SliceCache cachemc; Partition partMcLambdaTracks = (aod::lambdatrack::partType == (int8_t)kLambda); Partition partMcAntiLambdaTracks = (aod::lambdatrack::partType == (int8_t)kAntiLambda); - Partition partMcKaonPlusTracks = (aod::kaontrack::partType == (int8_t)kKaonPlus); - Partition partMcKaonMinusTracks = (aod::kaontrack::partType == (int8_t)kKaonMinus); - void processMCGen(LambdaMcGenCollisions::iterator const& mcgencol, LambdaMcGenTracks const&, KaonMcGenTracks const&) + void processMCGen(LambdaMcGenCollisions::iterator const& mcgencol, LambdaMcGenTracks const&) { histos.fill(HIST("Event/McGen/h1f_collision_posz"), mcgencol.posZ()); histos.fill(HIST("Event/McGen/h1f_ft0m_mult_percentile"), mcgencol.cent()); @@ -1726,22 +1351,14 @@ struct LambdaR2Correlation { auto lambdaTracks = partMcLambdaTracks->sliceByCached(aod::lambdamcgentrack::lambdaMcGenCollisionId, mcgencol.globalIndex(), cache); auto antiLambdaTracks = partMcAntiLambdaTracks->sliceByCached(aod::lambdamcgentrack::lambdaMcGenCollisionId, mcgencol.globalIndex(), cache); - auto kaonPlusTracks = partMcKaonPlusTracks->sliceByCached(aod::kaonmcgentrack::lambdaMcGenCollisionId, mcgencol.globalIndex(), cache); - auto kaonMinusTracks = partMcKaonMinusTracks->sliceByCached(aod::kaonmcgentrack::lambdaMcGenCollisionId, mcgencol.globalIndex(), cache); analyzeSingles(lambdaTracks); analyzeSingles(antiLambdaTracks); - analyzeSingles(kaonPlusTracks); - analyzeSingles(kaonMinusTracks); if (cAnaPairs) { analyzePairs(lambdaTracks, antiLambdaTracks); analyzePairs(lambdaTracks, lambdaTracks); analyzePairs(antiLambdaTracks, antiLambdaTracks); - analyzePairs(lambdaTracks, kaonPlusTracks); - analyzePairs(lambdaTracks, kaonMinusTracks); - analyzePairs(antiLambdaTracks, kaonPlusTracks); - analyzePairs(antiLambdaTracks, kaonMinusTracks); } } diff --git a/PWGCF/TwoParticleCorrelations/Tasks/lambdaSpinPolarization.cxx b/PWGCF/TwoParticleCorrelations/Tasks/lambdaSpinPolarization.cxx index 91fc6b6ec3a..f5d26c6fbaa 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/lambdaSpinPolarization.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/lambdaSpinPolarization.cxx @@ -1180,17 +1180,17 @@ struct LambdaTableProducer { : getCorrectionFactors(v0); if (v0Type == kLambda) { - prPx = v0.template posTrack_as().px(); - prPy = v0.template posTrack_as().py(); - prPz = v0.template posTrack_as().pz(); + prPx = v0.pxpos(); + prPy = v0.pypos(); + prPz = v0.pzpos(); histos.fill(HIST("Tracks/h1f_lambda_pt_vs_invm"), mass, v0.pt()); fillLambdaQAHistos(collision, v0, tracks); fillKinematicHists(v0.pt(), v0.eta(), v0.yLambda(), v0.phi()); } else { - prPx = v0.template negTrack_as().px(); - prPy = v0.template negTrack_as().py(); - prPz = v0.template negTrack_as().pz(); + prPx = v0.pxneg(); + prPy = v0.pyneg(); + prPz = v0.pzneg(); histos.fill(HIST("Tracks/h1f_antilambda_pt_vs_invm"), mass, v0.pt()); fillLambdaQAHistos(collision, v0, tracks); fillKinematicHists(v0.pt(), v0.eta(), v0.yLambda(), diff --git a/PWGCF/TwoParticleCorrelations/Tasks/longrangecorrDerived.cxx b/PWGCF/TwoParticleCorrelations/Tasks/longrangecorrDerived.cxx index 7471acec39b..54014f8f0e7 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/longrangecorrDerived.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/longrangecorrDerived.cxx @@ -45,6 +45,7 @@ #include #include +#include #include #include @@ -74,8 +75,8 @@ struct LongrangecorrDerived { SGSelector sgSelector; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; TrackSelection myTrackFilter; - Service pdg; - Service ccdb; + Service pdg{}; + Service ccdb{}; struct : ConfigurableGroup { Configurable cfgNmixedevent{"cfgNmixedevent", 5, "how many events are mixed"}; @@ -114,6 +115,10 @@ struct LongrangecorrDerived { Configurable cfgTofPidPtCut{"cfgTofPidPtCut", 0.4f, "Minimum pt to use TOF N-sigma"}; Configurable cfgPidNsigmaMax{"cfgPidNsigmaMax", 1.5f, "Maximum n-sigma for PID"}; Configurable cfgPidNsigmaMin{"cfgPidNsigmaMin", -1.5f, "Minimum n-sigma for PID"}; + Configurable cfgCleanNsigmaTpcMax{"cfgCleanNsigmaTpcMax", 1.5f, "Max TPC n-sigma for clean templates"}; + Configurable cfgCleanNsigmaTpcMin{"cfgCleanNsigmaTpcMin", -1.5f, "Min TPC n-sigma for clean templates"}; + Configurable cfgCleanNsigmaTofMax{"cfgCleanNsigmaTofMax", 1.5f, "Max TOF n-sigma for clean templates"}; + Configurable cfgCleanNsigmaTofMin{"cfgCleanNsigmaTofMin", -1.5f, "Min TOF n-sigma for clean templates"}; Configurable cfgGetNsigmaQA{"cfgGetNsigmaQA", true, "Get QA histograms for PID selection"}; Configurable cfgGetdEdx{"cfgGetdEdx", true, "Get dEdx histograms for TPC signal"}; @@ -159,6 +164,9 @@ struct LongrangecorrDerived { ConfigurableAxis axisNsigmaTOF{"axisNsigmaTOF", {80, -5, 5}, "nsigmaTOF axis"}; ConfigurableAxis axisTpcSignal{"axisTpcSignal", {250, 0, 250}, "dEdx axis for TPC"}; + ConfigurableAxis axisMcPt{"axisMcPt", {100, 0.2, 10.0}, "p_{T} (GeV/c)"}; + ConfigurableAxis axisMcEta{"axisMcEta", {100, -0.8, 0.8}, "#eta"}; + ConfigurableAxis axisMcPhi{"axisMcPhi", {100, 0., TwoPI}, "#phi"}; } cfgAxis; Configurable cfgFv0Cut{"cfgFv0Cut", 50.0f, "FV0A threshold"}; @@ -246,7 +254,7 @@ struct LongrangecorrDerived { histos.add("Trig_pt", "Trig_pt", kTH1D, {cfgAxis.axisPtTrigger}); histos.add("Trig_pt_corrected", "Trig_pt_corrected", kTH1D, {cfgAxis.axisPtTrigger}); histos.add("Trig_invMass", "Trig_invMass", kTH1D, {cfgAxis.axisInvMassQA}); - histos.add("Trig_hist", "Trig_hist", kTHnSparseF, {cfgAxis.axisSample, cfgAxis.axisVtxZ, cfgAxis.axisMultiplicity, cfgAxis.axisPtTrigger, cfgAxis.axisInvMass}); + histos.add("Trig_hist", "Trigger Track Properties;Sample;Vertex Z (cm);Multiplicity;p_{T} (GeV/c);Invariant Mass (GeV/c^{2})", kTHnSparseF, {cfgAxis.axisSample, cfgAxis.axisVtxZ, cfgAxis.axisMultiplicity, cfgAxis.axisPtTrigger, cfgAxis.axisInvMass}); histos.add("Trig_amp", "Trig_amp", kTH1D, {cfgAxis.axisAmplitude}); histos.add("Channel_vs_Trig_amp", "Channel_vs_Trig_amp", kTH2D, {cfgAxis.axisChannel, cfgAxis.axisAmplitude}); @@ -275,14 +283,23 @@ struct LongrangecorrDerived { if (doprocessTPCtrackEff) { histos.add("hGenMCdndpt", "hGenMCdndpt", kTH3D, {cfgAxis.axisVtxZ, cfgAxis.axisEtaEfficiency, cfgAxis.axisPtEfficiency}); histos.add("hRecMCdndpt", "hRecMCdndpt", kTH3D, {cfgAxis.axisVtxZ, cfgAxis.axisEtaEfficiency, cfgAxis.axisPtEfficiency}); + + if (cfgSel.cfgPidMask == KPidMaskPion || cfgSel.cfgPidMask == KPidMaskKaon || cfgSel.cfgPidMask == KPidMaskProton) { + histos.add("hMCGen_PidPtEtaPhi", "MC Gen Target", kTH3D, {cfgAxis.axisMcPt, cfgAxis.axisMcEta, cfgAxis.axisMcPhi}); + histos.add("hMCRec_PidPtEtaPhi", "MC Rec Target", kTH3D, {cfgAxis.axisMcPt, cfgAxis.axisMcEta, cfgAxis.axisMcPhi}); + } + + if (cfgSel.cfgGetdEdx) { + histos.add("MC_TpcdEdx_ptwise", "MC True TPC dE/dx;Particle Species;p_{T} (GeV/c);TPC dE/dx", kTHnSparseD, {{3, 0.5, 3.5}, cfgAxis.axisPtQA, cfgAxis.axisTpcSignal}); + } } myTrackFilter = getGlobalTrackSelectionRun3ITSMatch(TrackSelection::GlobalTrackRun3ITSMatching::Run3ITSibAny, TrackSelection::GlobalTrackRun3DCAxyCut::Default); myTrackFilter.SetPtRange(cfgSel.cfgPtCutMin, cfgSel.cfgPtCutMax); myTrackFilter.SetEtaRange(-cfgSel.cfgEtaCut, cfgSel.cfgEtaCut); - myTrackFilter.SetMinNCrossedRowsTPC(cfgSel.cfgTpcMinNCrossedRows); - myTrackFilter.SetMinNClustersTPC(cfgSel.cfgTpcMinNclsFound); + myTrackFilter.SetMinNCrossedRowsTPC(static_cast(cfgSel.cfgTpcMinNCrossedRows)); + myTrackFilter.SetMinNClustersTPC(static_cast(cfgSel.cfgTpcMinNclsFound)); myTrackFilter.SetMaxChi2PerClusterTPC(cfgSel.cfgTpcMaxChi2PerCluster); myTrackFilter.SetMaxDcaZ(cfgSel.cfgTpcMaxDcaZ); myTrackFilter.print(); @@ -498,7 +515,7 @@ struct LongrangecorrDerived { template void fillCorrHist(TTarget target, TTriggers const& triggers, TAssocs const& assocs, bool mixing, float vz, float multiplicity, float eventWeight) { - int fSampleIndex = gRandom->Uniform(0, cfgSel.cfgSampleSize); + int fSampleIndex = static_cast(gRandom->Uniform(0, cfgSel.cfgSampleSize)); for (auto const& triggerTrack : triggers) { auto trigAmpl = 1.0f; auto trkeff = 1.0f; @@ -770,6 +787,16 @@ struct LongrangecorrDerived { processSame(col, tracks, ft0as); } + void processV0ft0cSE(CollsTable::iterator const& col, V0TrksTable const& tracks, Ft0cTrksTable const& ft0cs) + { + processSame(col, tracks, ft0cs); + } + + void processV0tpcSE(CollsTable::iterator const& col, V0TrksTable const& v0s, TrksTable const& tracks) + { + processSame(col, v0s, tracks); + } + void processV0mftSE(CollsTable::iterator const& col, V0TrksTable const& tracks, MftTrksTable const& mfts) { processSame(col, tracks, mfts); @@ -805,6 +832,16 @@ struct LongrangecorrDerived { processMixed(cols, tracks, ft0as); } + void processV0ft0cME(CollsTable const& cols, V0TrksTable const& tracks, Ft0cTrksTable const& ft0cs) + { + processMixed(cols, tracks, ft0cs); + } + + void processV0tpcME(CollsTable const& cols, V0TrksTable const& v0s, TrksTable const& tracks) + { + processMixed(cols, v0s, tracks); + } + void processV0mftME(CollsTable const& cols, V0TrksTable const& tracks, MftTrksTable const& mfts) { processMixed(cols, tracks, mfts); @@ -855,6 +892,11 @@ struct LongrangecorrDerived { processSame(col, tracks, ft0as); } + void processUpcV0ft0cSE(UpcCollsTable::iterator const& col, V0TrksUpcTable const& tracks, Ft0cTrksUpcTable const& ft0cs) + { + processSame(col, tracks, ft0cs); + } + void processUpcV0mftSE(UpcCollsTable::iterator const& col, V0TrksUpcTable const& tracks, MftTrksUpcTable const& mfts) { if (!isUpcEventSelected(col)) { @@ -888,6 +930,11 @@ struct LongrangecorrDerived { processMixed(cols, tracks, ft0as); } + void processUpcV0ft0cME(UpcCollsTable const& cols, V0TrksUpcTable const& tracks, Ft0cTrksUpcTable const& ft0cs) + { + processMixed(cols, tracks, ft0cs); + } + void processUpcV0mftME(UpcCollsTable const& cols, V0TrksUpcTable const& tracks, MftTrksUpcTable const& mfts) { processMixed(cols, tracks, mfts); @@ -963,6 +1010,16 @@ struct LongrangecorrDerived { processMcGenSame(mccollision, mfts, ft0as); } + void processMcGenV0ft0aSE(McCollsTable::iterator const& mccollision, McTrksTable const& tracks, McFt0aTrksTable const& ft0as) + { + processMcGenSame(mccollision, tracks, ft0as); + } + + void processMcGenV0ft0cSE(McCollsTable::iterator const& mccollision, McTrksTable const& tracks, McFt0cTrksTable const& ft0cs) + { + processMcGenSame(mccollision, tracks, ft0cs); + } + void processMcGenFt0aft0cSE(McCollsTable::iterator const& mccollision, McFt0aTrksTable const& ft0as, McFt0cTrksTable const& ft0cs) { processMcGenSame(mccollision, ft0as, ft0cs); @@ -988,6 +1045,16 @@ struct LongrangecorrDerived { processMcGenMixed(mccollisions, mfts, ft0as); } + void processMcGenV0ft0aME(McCollsTable const& mccollisions, McTrksTable const& tracks, McFt0aTrksTable const& ft0as) + { + processMcGenMixed(mccollisions, tracks, ft0as); + } + + void processMcGenV0ft0cME(McCollsTable const& mccollisions, McTrksTable const& tracks, McFt0cTrksTable const& ft0cs) + { + processMcGenMixed(mccollisions, tracks, ft0cs); + } + void processMcGenFt0aft0cME(McCollsTable const& mccollisions, McFt0aTrksTable const& ft0as, McFt0cTrksTable const& ft0cs) { processMcGenMixed(mccollisions, ft0as, ft0cs); @@ -995,7 +1062,7 @@ struct LongrangecorrDerived { using ColMCTrueTable = soa::Join; using ColMCRecTable = soa::SmallGroups>; - using TrksMCRecTable = soa::Join; + using TrksMCRecTable = soa::Join; Preslice perColMidtrack = aod::track::collisionId; template @@ -1039,7 +1106,6 @@ struct LongrangecorrDerived { continue; if (RecCol.globalIndex() != mcCollision.bestCollisionIndex()) continue; - auto recTracksPart = RecTracks.sliceBy(perColMidtrack, RecCol.globalIndex()); atLeastOne = true; } for (const auto& particle : mcparticles) { @@ -1048,9 +1114,23 @@ struct LongrangecorrDerived { particle.pt() < cfgSel.cfgPtCutMin || particle.pt() > cfgSel.cfgPtCutMax) continue; - if (atLeastOne) + if (atLeastOne) { histos.fill(HIST("hGenMCdndpt"), mcCollision.posZ(), particle.eta(), particle.pt()); + + if (cfgSel.cfgPidMask == KPidMaskPion || cfgSel.cfgPidMask == KPidMaskKaon || cfgSel.cfgPidMask == KPidMaskProton) { + auto pdgcode = std::abs(particle.pdgCode()); + + bool isTargetGen = (cfgSel.cfgPidMask == KPidMaskPion && pdgcode == PDG_t::kPiPlus) || + (cfgSel.cfgPidMask == KPidMaskKaon && pdgcode == PDG_t::kKPlus) || + (cfgSel.cfgPidMask == KPidMaskProton && pdgcode == PDG_t::kProton); + + if (isTargetGen) { + histos.fill(HIST("hMCGen_PidPtEtaPhi"), particle.pt(), particle.eta(), particle.phi()); + } + } + } } + for (const auto& RecCol : RecCols) { if (!isEventSelected(RecCol)) continue; @@ -1069,6 +1149,58 @@ struct LongrangecorrDerived { continue; if (particle.isPhysicalPrimary()) { histos.fill(HIST("hRecMCdndpt"), mcCollision.posZ(), particle.eta(), particle.pt()); + + if (cfgSel.cfgGetdEdx) { + int pdgIdx = 0; + auto absPdg = std::abs(particle.pdgCode()); + + if (absPdg == PDG_t::kPiPlus) + pdgIdx = 1; // o2-linter: disable=pdg/explicit-code (histogram species index) + else if (absPdg == PDG_t::kKPlus) + pdgIdx = 2; // o2-linter: disable=pdg/explicit-code (histogram species index) + else if (absPdg == PDG_t::kProton) + pdgIdx = 3; // o2-linter: disable=pdg/explicit-code (histogram species index) + + if (pdgIdx > 0) { + histos.fill(HIST("MC_TpcdEdx_ptwise"), static_cast(pdgIdx), track.pt(), track.tpcSignal()); + } + } + + bool isTpcPion = (track.tpcNSigmaPi() > cfgSel.cfgPidNsigmaMin && track.tpcNSigmaPi() < cfgSel.cfgPidNsigmaMax); + bool isTpcKaon = (track.tpcNSigmaKa() > cfgSel.cfgPidNsigmaMin && track.tpcNSigmaKa() < cfgSel.cfgPidNsigmaMax); + bool isTpcProton = (track.tpcNSigmaPr() > cfgSel.cfgPidNsigmaMin && track.tpcNSigmaPr() < cfgSel.cfgPidNsigmaMax); + + bool isTofPion = (track.tofNSigmaPi() > cfgSel.cfgPidNsigmaMin && track.tofNSigmaPi() < cfgSel.cfgPidNsigmaMax); + bool isTofKaon = (track.tofNSigmaKa() > cfgSel.cfgPidNsigmaMin && track.tofNSigmaKa() < cfgSel.cfgPidNsigmaMax); + bool isTofProton = (track.tofNSigmaPr() > cfgSel.cfgPidNsigmaMin && track.tofNSigmaPr() < cfgSel.cfgPidNsigmaMax); + + bool isPion = false, isKaon = false, isProton = false; + + if (track.pt() > cfgSel.cfgTofPidPtCut && track.hasTOF()) { + isPion = isTofPion && isTpcPion; + isKaon = isTofKaon && isTpcKaon; + isProton = isTofProton && isTpcProton; + } else if (!(track.pt() > cfgSel.cfgTofPidPtCut && !track.hasTOF())) { + isPion = isTpcPion; + isKaon = isTpcKaon; + isProton = isTpcProton; + } + + if ((isPion && isKaon) || (isPion && isProton) || (isKaon && isProton)) { + isPion = isKaon = isProton = false; + } + + if (cfgSel.cfgPidMask == KPidMaskPion || cfgSel.cfgPidMask == KPidMaskKaon || cfgSel.cfgPidMask == KPidMaskProton) { + + auto pdgcodeRec = std::abs(particle.pdgCode()); + bool isTargetRec = (cfgSel.cfgPidMask == KPidMaskPion && isPion && pdgcodeRec == PDG_t::kPiPlus) || + (cfgSel.cfgPidMask == KPidMaskKaon && isKaon && pdgcodeRec == PDG_t::kKPlus) || + (cfgSel.cfgPidMask == KPidMaskProton && isProton && pdgcodeRec == PDG_t::kProton); + + if (isTargetRec) { + histos.fill(HIST("hMCRec_PidPtEtaPhi"), particle.pt(), particle.eta(), particle.phi()); + } + } } } } @@ -1104,6 +1236,9 @@ struct LongrangecorrDerived { if (!myTrackFilter.IsSelected(track)) continue; + if (!track.hasTOF()) + continue; + float tpcNsig = 0.0f, tofNsig = 0.0f; if (cfgSel.cfgPidMask & KPidMaskPion) { tpcNsig = track.tpcNSigmaPi(); @@ -1124,30 +1259,25 @@ struct LongrangecorrDerived { } } - bool isTpcPion = (track.tpcNSigmaPi() > cfgSel.cfgPidNsigmaMin && track.tpcNSigmaPi() < cfgSel.cfgPidNsigmaMax); - bool isTpcKaon = (track.tpcNSigmaKa() > cfgSel.cfgPidNsigmaMin && track.tpcNSigmaKa() < cfgSel.cfgPidNsigmaMax); - bool isTpcProton = (track.tpcNSigmaPr() > cfgSel.cfgPidNsigmaMin && track.tpcNSigmaPr() < cfgSel.cfgPidNsigmaMax); - - bool isTofPion = (track.tofNSigmaPi() > cfgSel.cfgPidNsigmaMin && track.tofNSigmaPi() < cfgSel.cfgPidNsigmaMax); - bool isTofKaon = (track.tofNSigmaKa() > cfgSel.cfgPidNsigmaMin && track.tofNSigmaKa() < cfgSel.cfgPidNsigmaMax); - bool isTofProton = (track.tofNSigmaPr() > cfgSel.cfgPidNsigmaMin && track.tofNSigmaPr() < cfgSel.cfgPidNsigmaMax); - - bool isPion = false, isKaon = false, isProton = false; - if (track.pt() > cfgSel.cfgTofPidPtCut && track.hasTOF()) { - isPion = isTofPion && isTpcPion; - isKaon = isTofKaon && isTpcKaon; - isProton = isTofProton && isTpcProton; - } else if (!(track.pt() > cfgSel.cfgTofPidPtCut && !track.hasTOF())) { - isPion = isTpcPion; - isKaon = isTpcKaon; - isProton = isTpcProton; - } + bool isTpcPion = (track.tpcNSigmaPi() > cfgSel.cfgCleanNsigmaTpcMin && track.tpcNSigmaPi() < cfgSel.cfgCleanNsigmaTpcMax); + bool isTpcKaon = (track.tpcNSigmaKa() > cfgSel.cfgCleanNsigmaTpcMin && track.tpcNSigmaKa() < cfgSel.cfgCleanNsigmaTpcMax); + bool isTpcProton = (track.tpcNSigmaPr() > cfgSel.cfgCleanNsigmaTpcMin && track.tpcNSigmaPr() < cfgSel.cfgCleanNsigmaTpcMax); + + bool isTofPion = (track.tofNSigmaPi() > cfgSel.cfgCleanNsigmaTofMin && track.tofNSigmaPi() < cfgSel.cfgCleanNsigmaTofMax); + bool isTofKaon = (track.tofNSigmaKa() > cfgSel.cfgCleanNsigmaTofMin && track.tofNSigmaKa() < cfgSel.cfgCleanNsigmaTofMax); + bool isTofProton = (track.tofNSigmaPr() > cfgSel.cfgCleanNsigmaTofMin && track.tofNSigmaPr() < cfgSel.cfgCleanNsigmaTofMax); + + bool isPion = isTofPion && isTpcPion; + bool isKaon = isTofKaon && isTpcKaon; + bool isProton = isTofProton && isTpcProton; if ((isPion && isKaon) || (isPion && isProton) || (isKaon && isProton)) { isPion = isKaon = isProton = false; } - bool isTargetParticle = ((cfgSel.cfgPidMask & KPidMaskPion) && isPion) || ((cfgSel.cfgPidMask & KPidMaskKaon) && isKaon) || ((cfgSel.cfgPidMask & KPidMaskProton) && isProton); + bool isTargetParticle = ((cfgSel.cfgPidMask & KPidMaskPion) && isPion) || + ((cfgSel.cfgPidMask & KPidMaskKaon) && isKaon) || + ((cfgSel.cfgPidMask & KPidMaskProton) && isProton); // FILL AFTER CUTS if (cfgSel.cfgGetNsigmaQA && isTargetParticle) { @@ -1170,6 +1300,10 @@ struct LongrangecorrDerived { PROCESS_SWITCH(LongrangecorrDerived, processMftft0aME, "mixed event MFT vs FT0A", false); PROCESS_SWITCH(LongrangecorrDerived, processV0ft0aSE, "same event V0 vs FT0A", false); PROCESS_SWITCH(LongrangecorrDerived, processV0ft0aME, "mixed event V0 vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processV0ft0cSE, "same event V0 vs FT0C", false); + PROCESS_SWITCH(LongrangecorrDerived, processV0ft0cME, "mixed event V0 vs FT0C", false); + PROCESS_SWITCH(LongrangecorrDerived, processV0tpcSE, "same event V0 vs TPC", false); + PROCESS_SWITCH(LongrangecorrDerived, processV0tpcME, "mixed event V0 vs TPC", false); PROCESS_SWITCH(LongrangecorrDerived, processV0mftSE, "same event V0 vs MFT", false); PROCESS_SWITCH(LongrangecorrDerived, processV0mftME, "mixed event V0 vs MFT", false); PROCESS_SWITCH(LongrangecorrDerived, processFt0aft0cSE, "same event FT0A vs FT0C", false); @@ -1184,6 +1318,8 @@ struct LongrangecorrDerived { PROCESS_SWITCH(LongrangecorrDerived, processUpcMftft0aME, "mixed UPC event MFT vs FT0A", false); PROCESS_SWITCH(LongrangecorrDerived, processUpcV0ft0aSE, "same UPC event V0 vs FT0A", false); PROCESS_SWITCH(LongrangecorrDerived, processUpcV0ft0aME, "mixed UPC event V0 vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processUpcV0ft0cSE, "same UPC event V0 vs FT0C", false); + PROCESS_SWITCH(LongrangecorrDerived, processUpcV0ft0cME, "mixed UPC event V0 vs FT0C", false); PROCESS_SWITCH(LongrangecorrDerived, processUpcV0mftSE, "same UPC event V0 vs MFT", false); PROCESS_SWITCH(LongrangecorrDerived, processUpcV0mftME, "mixed UPC event V0 vs MFT", false); PROCESS_SWITCH(LongrangecorrDerived, processMcTpcft0aSE, "same MC event TPC vs FT0A", false); @@ -1204,6 +1340,10 @@ struct LongrangecorrDerived { PROCESS_SWITCH(LongrangecorrDerived, processMcGenTpcmftME, "mixed MC gen event TPC vs MFT", false); PROCESS_SWITCH(LongrangecorrDerived, processMcGenMftft0aSE, "same MC gen event MFT vs FT0A", false); PROCESS_SWITCH(LongrangecorrDerived, processMcGenMftft0aME, "mixed MC gen event MFT vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processMcGenV0ft0aSE, "same MC gen event V0 vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processMcGenV0ft0aME, "mixed MC gen event V0 vs FT0A", false); + PROCESS_SWITCH(LongrangecorrDerived, processMcGenV0ft0cSE, "same MC gen event V0 vs FT0C", false); + PROCESS_SWITCH(LongrangecorrDerived, processMcGenV0ft0cME, "mixed MC gen event V0 vs FT0C", false); PROCESS_SWITCH(LongrangecorrDerived, processMcGenFt0aft0cSE, "same MC gen event FT0A vs FT0C", false); PROCESS_SWITCH(LongrangecorrDerived, processMcGenFt0aft0cME, "mixed MC gen event FT0A vs FT0C", false); PROCESS_SWITCH(LongrangecorrDerived, processTPCtrackEff, "process TPC track efficiency", false); diff --git a/PWGCF/TwoParticleCorrelations/Tasks/nucleibalance.cxx b/PWGCF/TwoParticleCorrelations/Tasks/nucleibalance.cxx index 380b6f04594..d39ca486469 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/nucleibalance.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/nucleibalance.cxx @@ -71,7 +71,8 @@ using namespace o2::framework; using namespace o2::framework::expressions; using namespace constants::math; -#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, (DEFAULT), (HELP)}; +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) \ + Configurable NAME{#NAME, (DEFAULT), (HELP)}; // NOLINT(bugprone-macro-parentheses) static constexpr float PairCutOff = -1.f; static constexpr std::array, 1> CfgPairCutDefaults{{{PairCutOff, PairCutOff, PairCutOff, PairCutOff, PairCutOff}}}; @@ -1796,6 +1797,8 @@ struct Lambdastarproxy { }; struct ProxyCand { float px, py, pz; + float pxFull, pyFull, pzFull; + bool protonLike; int charge; int tid; }; @@ -2088,6 +2091,56 @@ struct Lambdastarproxy { // THnSparse for invariant-mass analysis (mass, pT, multiplicity/centrality) if (lstarEnableSparse.value != 0) { + + histos.add( + "hLambdaStarProxyVsFullPKMixedSparse", + "d-selected mixed-event pairs: full-p proton hypothesis vs (d/2)K proxy;" + "M_{(d/2)K} (GeV/c^{2});" + "M_{pK}^{full} (GeV/c^{2});" + "p_{T}^{(d/2)K} (GeV/c);" + "multiplicity/centrality", + HistType::kTHnSparseF, + {AxisSpec{400, 1.4, 1.8, + "M_{(d/2)K} (GeV/c^{2})"}, + + AxisSpec{400, 1.4, 1.8, + "M_{pK}^{full} (GeV/c^{2})"}, + + AxisSpec{100, 0., 10., + "p_{T}^{(d/2)K} (GeV/c)"}, + + centAxis}); + + histos.add( + "hLambdaStarProxyProtonLikeUnlikeSparse", + "d-selected and proton-like OS proxy candidates;" + "M_{(d/2)K} (GeV/c^{2});" + "p_{T}^{(d/2)K} (GeV/c);" + "multiplicity/centrality", + HistType::kTHnSparseF, + {AxisSpec{400, 1.4, 1.8, + "M_{(d/2)K} (GeV/c^{2})"}, + + AxisSpec{100, 0., 10., + "p_{T}^{(d/2)K} (GeV/c)"}, + + centAxis}); + + histos.add( + "hLambdaStarProxyProtonLikeLikeSparse", + "d-selected and proton-like LS proxy candidates;" + "M_{(d/2)K} (GeV/c^{2});" + "p_{T}^{(d/2)K} (GeV/c);" + "multiplicity/centrality", + HistType::kTHnSparseF, + {AxisSpec{400, 1.4, 1.8, + "M_{(d/2)K} (GeV/c^{2})"}, + + AxisSpec{100, 0., 10., + "p_{T}^{(d/2)K} (GeV/c)"}, + + centAxis}); + histos.add("hLambdaStarPKUnlikeSparse", "#Lambda^{*}(1520) pK unlike-sign candidates;M_{pK} (GeV/c^{2});p_{T}^{pK} (GeV/c);multiplicity/centrality", HistType::kTHnSparseF, @@ -2124,6 +2177,44 @@ struct Lambdastarproxy { HistType::kTHnSparseF, {AxisSpec{400, 1.4, 1.8, "M_{p_{proxy}K} (GeV/c^{2})"}, AxisSpec{100, 0., 10., "p_{T}^{p_{proxy}K} (GeV/c)"}, centAxis}); + + histos.add( + "hLambdaStarProxyVsFullPKUnlikeSparse", + "d-selected OS pairs: full-p proton hypothesis vs (d/2)K proxy;" + "M_{(d/2)K} (GeV/c^{2});" + "M_{pK}^{full} (GeV/c^{2});" + "p_{T}^{(d/2)K} (GeV/c);" + "multiplicity/centrality", + HistType::kTHnSparseF, + {AxisSpec{400, 1.4, 1.8, + "M_{(d/2)K} (GeV/c^{2})"}, + + AxisSpec{400, 1.4, 1.8, + "M_{pK}^{full} (GeV/c^{2})"}, + + AxisSpec{100, 0., 10., + "p_{T}^{(d/2)K} (GeV/c)"}, + + centAxis}); + + histos.add( + "hLambdaStarProxyVsFullPKLikeSparse", + "d-selected LS pairs: full-p proton hypothesis vs (d/2)K proxy;" + "M_{(d/2)K} (GeV/c^{2});" + "M_{pK}^{full} (GeV/c^{2});" + "p_{T}^{(d/2)K} (GeV/c);" + "multiplicity/centrality", + HistType::kTHnSparseF, + {AxisSpec{400, 1.4, 1.8, + "M_{(d/2)K} (GeV/c^{2})"}, + + AxisSpec{400, 1.4, 1.8, + "M_{pK}^{full} (GeV/c^{2})"}, + + AxisSpec{100, 0., 10., + "p_{T}^{(d/2)K} (GeV/c)"}, + + centAxis}); } // Deuteron-proxy invariant mass (p_{proxy} from d/2 combined with K) @@ -2309,6 +2400,37 @@ struct Lambdastarproxy { histos.add("hNsigmaTOFDeuteronVsPt", "TOF n#sigma_{d} vs p_{T};p_{T} (GeV/c);n#sigma^{TOF}_{d};Counts", HistType::kTH2F, {ptAxis, nsAxis}); + histos.add( + "hNsigmaTPCProtonForSelectedDeuteronVsPt", + "TPC n#sigma_{p} for selected d candidates vs p_{T};" + "p_{T} (GeV/c);" + "n#sigma^{TPC}_{p};Counts", + HistType::kTH2F, + {ptAxis, nsAxis}); + + histos.add( + "hNsigmaTOFProtonForSelectedDeuteronVsPt", + "TOF n#sigma_{p} for selected d candidates vs p_{T};" + "p_{T} (GeV/c);" + "n#sigma^{TOF}_{p};Counts", + HistType::kTH2F, + {ptAxis, nsAxis}); + + histos.add( + "hTPCNsigmaDeVsPrForSelectedDeuteron", + "TPC PID overlap for selected d candidates;" + "n#sigma^{TPC}_{d};" + "n#sigma^{TPC}_{p};Counts", + HistType::kTH2F, + {nsAxis, nsAxis}); + + histos.add( + "hTOFNsigmaDeVsPrForSelectedDeuteron", + "TOF PID overlap for selected d candidates;" + "n#sigma^{TOF}_{d};" + "n#sigma^{TOF}_{p};Counts", + HistType::kTH2F, + {nsAxis, nsAxis}); histos.add("hTPCvsTOFNsigma_K", "TPC vs TOF n#sigma for selected K;n#sigma^{TPC}_{K};n#sigma^{TOF}_{K};Counts", @@ -2793,16 +2915,27 @@ struct Lambdastarproxy { continue; } - if (useProtonAsProxy) { - const float nsTPCPrAsProxy = trkD.tpcNSigmaPr(); - const float nsTOFPrAsProxy = trkD.tofNSigmaPr(); - const bool passesProtonSelection = passFinalCandidatePID(ptD, nsTPCPrAsProxy, nsTOFPrAsProxy, hasTofDe, - lstarCutNsigmaTPCPr.value, lstarCutNsigmaTOFPr.value, - lstarPidCircularCutPr.value, lstarPidPtRefPr.value, - false); - if (!passesProtonSelection) { - continue; - } + const float nsTPCPrAsProxy = + trkD.tpcNSigmaPr(); + + const float nsTOFPrAsProxy = + trkD.tofNSigmaPr(); + + const bool passesProtonSelection = + passFinalCandidatePID( + ptD, + nsTPCPrAsProxy, + nsTOFPrAsProxy, + hasTofDe, + lstarCutNsigmaTPCPr.value, + lstarCutNsigmaTOFPr.value, + lstarPidCircularCutPr.value, + lstarPidPtRefPr.value, + false); + + if (useProtonAsProxy && + !passesProtonSelection) { + continue; } const double pD = static_cast(ptD) * std::cosh(static_cast(etaD)); @@ -2818,7 +2951,30 @@ struct Lambdastarproxy { histos.fill(HIST("hNsigmaTOFDeuteronVsP"), pD, nsTOFDe); histos.fill(HIST("hNsigmaTPCDeuteronVsPt"), ptD, nsTPCDe); histos.fill(HIST("hNsigmaTOFDeuteronVsPt"), ptD, nsTOFDe); + histos.fill( + HIST( + "hNsigmaTPCProtonForSelectedDeuteronVsPt"), + ptD, + nsTPCPrAsProxy); + + histos.fill( + HIST( + "hNsigmaTOFProtonForSelectedDeuteronVsPt"), + ptD, + nsTOFPrAsProxy); + + histos.fill( + HIST( + "hTPCNsigmaDeVsPrForSelectedDeuteron"), + nsTPCDe, + nsTPCPrAsProxy); + if (hasTofDe) { + histos.fill( + HIST( + "hTOFNsigmaDeVsPrForSelectedDeuteron"), + nsTOFDe, + nsTOFPrAsProxy); histos.fill(HIST("hTPCvsTOFNsigma_D"), nsTPCDe, nsTOFDe); } if constexpr (requires { trkD.beta(); }) { @@ -2838,7 +2994,37 @@ struct Lambdastarproxy { const float pyProxy = ProxyMomentumScale * ptD * std::sin(phiD); const float pzProxy = ProxyMomentumScale * ptD * std::sinh(etaD); - proxyCands.push_back(ProxyCand{.px = pxProxy, .py = pyProxy, .pz = pzProxy, .charge = static_cast(trkD.sign()), .tid = static_cast(trkD.globalIndex())}); + // Full measured momentum of the same d-selected track. + // This will later be interpreted under the proton mass hypothesis. + const float pxFull = + ptD * std::cos(phiD); + + const float pyFull = + ptD * std::sin(phiD); + + const float pzFull = + ptD * std::sinh(etaD); + + proxyCands.push_back( + ProxyCand{ + .px = pxProxy, + .py = pyProxy, + .pz = pzProxy, + + .pxFull = pxFull, + .pyFull = pyFull, + .pzFull = pzFull, + + .protonLike = + passesProtonSelection, + + .charge = + static_cast( + trkD.sign()), + + .tid = + static_cast( + trkD.globalIndex())}); } // Proton candidates (for genuine pK #Lambda^{*} reconstruction) @@ -3034,20 +3220,121 @@ struct Lambdastarproxy { continue; // sanity check: should never match, but just in case of bug in candidate-building logic } const double mass = invariantMass(pr.px, pr.py, pr.pz, MassProton, k.px, k.py, k.pz, MassKaonCharged); + // Same d-selected track, but now use its FULL measured + // momentum and assign the proton mass. + // + // No proton PID requirement is involved. + const double massFullPK = + invariantMass( + pr.pxFull, + pr.pyFull, + pr.pzFull, + MassProton, + k.px, + k.py, + k.pz, + MassKaonCharged); + + const float pxTotFullPK = + pr.pxFull + k.px; + + const float pyTotFullPK = + pr.pyFull + k.py; + + const float pzTotFullPK = + pr.pzFull + k.pz; + + const float yFullPK = + rapidityFromMomentumAndMass( + pxTotFullPK, + pyTotFullPK, + pzTotFullPK, + massFullPK); const float pxTot = pr.px + k.px; const float pyTot = pr.py + k.py; + const float pzTot = pr.pz + k.pz; const float ptPair = ptFromPxPy(pxTot, pyTot); + const float yProxy = + rapidityFromMomentumAndMass( + pxTot, + pyTot, + pzTot, + mass); + + if (std::abs(yProxy) > + lstarLambdaAbsYMax.value) { + continue; + } + + const bool unlikeSignProxy = + (pr.charge * k.charge) < 0; + // Inclusive invariant-mass spectrum for the #Lambda^{*} proxy (d/2 + K) histos.fill(HIST("hDeuteronProxyMass"), mass); if (lstarEnableSparse.value != 0) { - histos.fill(HIST("hLambdaStarProxySparse"), mass, ptPair, eventMult); - // Like-sign proxy background: proxy and kaon have the same charge sign. - // Here the proxy charge follows the original deuteron-candidate charge. - if ((pr.charge * k.charge) > 0) { - histos.fill(HIST("hLambdaStarProxyLikeSparse"), mass, ptPair, eventMult); + if (unlikeSignProxy) { + + histos.fill( + HIST( + "hLambdaStarProxySparse"), + mass, + ptPair, + eventMult); + + } else { + + histos.fill( + HIST( + "hLambdaStarProxyLikeSparse"), + mass, + ptPair, + eventMult); + } + if (std::abs(yFullPK) <= + lstarLambdaAbsYMax.value) { + + if (unlikeSignProxy) { + + histos.fill( + HIST( + "hLambdaStarProxyVsFullPKUnlikeSparse"), + mass, + massFullPK, + ptPair, + eventMult); + + } else { + + histos.fill( + HIST( + "hLambdaStarProxyVsFullPKLikeSparse"), + mass, + massFullPK, + ptPair, + eventMult); + } + } + if (pr.protonLike) { + + if (unlikeSignProxy) { + + histos.fill( + HIST("hLambdaStarProxyProtonLikeUnlikeSparse"), + mass, + ptPair, + eventMult); + + } else { + + histos.fill( + HIST("hLambdaStarProxyProtonLikeLikeSparse"), + mass, + ptPair, + eventMult); + } } } } @@ -3057,37 +3344,75 @@ struct Lambdastarproxy { // --- MIXED-EVENT: current kaons + previous-event real protons --- // This fills the standard pK mixed-event background. for (auto const& prev : mLStarMixEvents) { - if (std::abs(prev.zvtx - collision.posZ()) > lstarMixZvtxMax.value) { + + if (std::abs(prev.zvtx - collision.posZ()) > + lstarMixZvtxMax.value) { continue; } - if (std::abs(prev.mult - eventMult) > lstarMixMultMax.value) { + + if (std::abs(prev.mult - eventMult) > + lstarMixMultMax.value) { continue; } + if (prev.protons.empty()) { continue; } for (auto const& pr : prev.protons) { + for (auto const& k : kaonCands) { + // Unlike-sign pK mixed-event background. if ((pr.charge * k.charge) >= 0) { continue; } - const double mass = invariantMass(pr.px, pr.py, pr.pz, MassProton, - k.px, k.py, k.pz, MassKaonCharged); - const float pxTot = pr.px + k.px; - const float pyTot = pr.py + k.py; - const float pzTot = pr.pz + k.pz; - const float ptPair = ptFromPxPy(pxTot, pyTot); - - const float yPair = rapidityFromMomentumAndMass(pxTot, pyTot, pzTot, mass); - if (std::abs(yPair) > lstarLambdaAbsYMax.value) { + const double mass = + invariantMass( + pr.px, + pr.py, + pr.pz, + MassProton, + k.px, + k.py, + k.pz, + MassKaonCharged); + + const float pxTot = + pr.px + k.px; + + const float pyTot = + pr.py + k.py; + + const float pzTot = + pr.pz + k.pz; + + const float ptPair = + ptFromPxPy( + pxTot, + pyTot); + + const float yPair = + rapidityFromMomentumAndMass( + pxTot, + pyTot, + pzTot, + mass); + + if (std::abs(yPair) > + lstarLambdaAbsYMax.value) { continue; } if (lstarEnableSparse.value != 0) { - histos.fill(HIST("hLambdaStarPKMixedSparse"), mass, ptPair, eventMult); + + histos.fill( + HIST( + "hLambdaStarPKMixedSparse"), + mass, + ptPair, + eventMult); } } } @@ -3095,39 +3420,149 @@ struct Lambdastarproxy { // --- MIXED-EVENT: current proxies + previous-event kaons --- // This fills the deuteron-proxy mixed-event background. + // + // For every d-selected proxy candidate we calculate: + // + // 1) M_{(d/2)K} + // using p_proxy = p_track / 2 + // + // 2) M_{pK}^{full} + // using the FULL measured momentum of the same d-selected track, + // but assigning the proton mass. + // + // The standard proxy mixed spectrum requires only the proxy rapidity + // acceptance. The 2D proxy-vs-full-pK map additionally requires the + // full-pK hypothesis to satisfy the same rapidity acceptance. if (hasProxyCandidates) { + for (auto const& prev : mLStarMixEvents) { - if (std::abs(prev.zvtx - collision.posZ()) > lstarMixZvtxMax.value) { + + if (std::abs(prev.zvtx - collision.posZ()) > + lstarMixZvtxMax.value) { continue; } - if (std::abs(prev.mult - eventMult) > lstarMixMultMax.value) { + + if (std::abs(prev.mult - eventMult) > + lstarMixMultMax.value) { continue; } + if (prev.kaons.empty()) { continue; } for (auto const& pr : proxyCands) { + for (auto const& k : prev.kaons) { + // Unlike-sign proxy-K mixed-event background. if ((pr.charge * k.charge) >= 0) { continue; } - const double mass = invariantMass(pr.px, pr.py, pr.pz, MassProton, - k.px, k.py, k.pz, MassKaonCharged); - const float pxTot = pr.px + k.px; - const float pyTot = pr.py + k.py; - const float pzTot = pr.pz + k.pz; - const float ptPair = ptFromPxPy(pxTot, pyTot); - - const float yPair = rapidityFromMomentumAndMass(pxTot, pyTot, pzTot, mass); - if (std::abs(yPair) > lstarLambdaAbsYMax.value) { + // ---------------------------------------------------------- + // Proxy hypothesis: p_proxy = p_d / 2 + // ---------------------------------------------------------- + + const double mass = + invariantMass( + pr.px, + pr.py, + pr.pz, + MassProton, + k.px, + k.py, + k.pz, + MassKaonCharged); + + const float pxTot = + pr.px + k.px; + + const float pyTot = + pr.py + k.py; + + const float pzTot = + pr.pz + k.pz; + + const float ptPair = + ptFromPxPy( + pxTot, + pyTot); + + const float yProxy = + rapidityFromMomentumAndMass( + pxTot, + pyTot, + pzTot, + mass); + + // Standard proxy rapidity acceptance. + if (std::abs(yProxy) > + lstarLambdaAbsYMax.value) { continue; } + // ---------------------------------------------------------- + // Full-momentum proton hypothesis for the SAME d-selected + // track. + // ---------------------------------------------------------- + + const double massFullPK = + invariantMass( + pr.pxFull, + pr.pyFull, + pr.pzFull, + MassProton, + k.px, + k.py, + k.pz, + MassKaonCharged); + + const float pxTotFullPK = + pr.pxFull + k.px; + + const float pyTotFullPK = + pr.pyFull + k.py; + + const float pzTotFullPK = + pr.pzFull + k.pz; + + const float yFullPK = + rapidityFromMomentumAndMass( + pxTotFullPK, + pyTotFullPK, + pzTotFullPK, + massFullPK); + if (lstarEnableSparse.value != 0) { - histos.fill(HIST("hLambdaStarProxyMixedSparse"), mass, ptPair, eventMult); + + // Standard mixed-event proxy spectrum. + // + // This requires only the proxy hypothesis to satisfy + // |y| < lstarLambdaAbsYMax. + histos.fill( + HIST( + "hLambdaStarProxyMixedSparse"), + mass, + ptPair, + eventMult); + + // Mixed-event 2D map. + // + // Since this histogram explicitly represents both + // hypotheses, require the full-pK hypothesis to satisfy + // the same configurable rapidity acceptance as well. + if (std::abs(yFullPK) <= + lstarLambdaAbsYMax.value) { + + histos.fill( + HIST( + "hLambdaStarProxyVsFullPKMixedSparse"), + mass, + massFullPK, + ptPair, + eventMult); + } } } } diff --git a/PWGCF/TwoParticleCorrelations/Tasks/twoParticleCorrelationsMpi.cxx b/PWGCF/TwoParticleCorrelations/Tasks/twoParticleCorrelationsMpi.cxx index 6c8ca4262a4..39988d92474 100644 --- a/PWGCF/TwoParticleCorrelations/Tasks/twoParticleCorrelationsMpi.cxx +++ b/PWGCF/TwoParticleCorrelations/Tasks/twoParticleCorrelationsMpi.cxx @@ -16,6 +16,11 @@ #include "PWGCF/Core/CorrelationContainer.h" #include "PWGCF/Core/PairCuts.h" #include "PWGCF/DataModel/CorrelationsDerived.h" +#include "PWGCF/GenericFramework/Core/FlowContainer.h" +#include "PWGCF/GenericFramework/Core/FlowPtContainer.h" +#include "PWGCF/GenericFramework/Core/GFW.h" +#include "PWGCF/GenericFramework/Core/GFWConfig.h" +#include "PWGCF/GenericFramework/Core/GFWWeights.h" #include "Common/CCDB/TriggerAliases.h" #include "Common/Core/RecoDecay.h" @@ -39,9 +44,9 @@ #include #include #include -#include #include +#include #include #include #include @@ -50,7 +55,9 @@ #include #include #include +#include #include +#include #include #include @@ -66,6 +73,7 @@ #include #include #include +#include #include #include #include @@ -77,29 +85,37 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using namespace constants::math; +using namespace o2::analysis::genericframework; static constexpr std::array, 1> CfgPairCutDefaults = {{{-1, -1, -1, -1, -1}}}; +static constexpr std::array, 4> LongArrayDouble = {{{{-0.8, -0.5}}, {{0.5, 0.8}}, {{-2, -2}}, {{-2, -2}}}}; +static constexpr int DefaultAcceptancePhiBins = 72; +static constexpr int DefaultAcceptanceEtaBins = 32; +static constexpr int InvalidRunNumber = -1; +static constexpr int FlowNBootstrap = 10; +static constexpr int MaxPtCorrelationOrder = 4; struct TwoParticleCorrelationsMpi { SliceCache cache; // Configuration - Configurable cfgCutVertex{"cfgCutVertex", 7.0f, "Accepted z-vertex range"}; - Configurable cfgCutPt{"cfgCutPt", 0.5f, "Minimal pT for tracks"}; - Configurable cfgCutEta{"cfgCutEta", 0.8f, "Eta range for tracks"}; - - Configurable cfgPtOrder{"cfgPtOrder", 1, "Only consider pairs for which pT,1 < pT,2 (0 = OFF, 1 = ON)"}; - Configurable cfgTriggerCharge{"cfgTriggerCharge", 0, "Select on charge of trigger particle: 0 = all; 1 = positive; -1 = negative"}; - Configurable cfgAssociatedCharge{"cfgAssociatedCharge", 0, "Select on charge of associated particle: 0 = all charged; 1 = positive; -1 = negative"}; - Configurable cfgPairCharge{"cfgPairCharge", 0, "Select on charge of particle pair: 0 = all; 1 = like sign; -1 = unlike sign"}; - Configurable cfgCorrelationMethod{"cfgCorrelationMethod", 0, "Correlation method, 0 = all, 1 = dd, 2 = ddbar"}; - - Configurable cfgTwoTrackCut{"cfgTwoTrackCut", -1, "Two track cut: -1 = off; >0 otherwise distance value (suggested: 0.02)"}; - Configurable cfgTwoTrackCutMinRadius{"cfgTwoTrackCutMinRadius", 0.8f, "Two track cut: radius in m from which two track cuts are applied"}; - ; - Configurable cfgLocalEfficiency{"cfgLocalEfficiency", 0, "0 = OFF and 1 = ON for local efficiency"}; - Configurable cfgDropStepRECO{"cfgDropStepRECO", false, "choice to drop step RECO if efficiency correction is used"}; - Configurable cfgCentBinsForMC{"cfgCentBinsForMC", 0, "0 = OFF and 1 = ON for data like multiplicity/centrality bins for MC steps"}; + struct : ConfigurableGroup { + Configurable cfgCutVertex{"cfgCutVertex", 7.0f, "Accepted z-vertex range"}; + Configurable cfgCutPt{"cfgCutPt", 0.5f, "Minimal pT for tracks"}; + Configurable cfgCutEta{"cfgCutEta", 0.8f, "Eta range for tracks"}; + Configurable> cfgFlowPtRef{"cfgFlowPtRef", {0.5f, 3.0f}, "Minimum and maximum pT for reference flow particles"}; + Configurable> cfgFlowPtPOI{"cfgFlowPtPOI", {0.5f, 10.0f}, "Minimum and maximum pT for particles of interest in flow correlations"}; + Configurable cfgPtOrder{"cfgPtOrder", 1, "Only consider pairs for which pT,1 < pT,2 (0 = OFF, 1 = ON)"}; + Configurable cfgTriggerCharge{"cfgTriggerCharge", 0, "Select on charge of trigger particle: 0 = all; 1 = positive; -1 = negative"}; + Configurable cfgAssociatedCharge{"cfgAssociatedCharge", 0, "Select on charge of associated particle: 0 = all charged; 1 = positive; -1 = negative"}; + Configurable cfgPairCharge{"cfgPairCharge", 0, "Select on charge of particle pair: 0 = all; 1 = like sign; -1 = unlike sign"}; + Configurable cfgCorrelationMethod{"cfgCorrelationMethod", 0, "Correlation method, 0 = all, 1 = dd, 2 = ddbar"}; + Configurable cfgTwoTrackCut{"cfgTwoTrackCut", -1, "Two track cut: -1 = off; >0 otherwise distance value (suggested: 0.02)"}; + Configurable cfgTwoTrackCutMinRadius{"cfgTwoTrackCutMinRadius", 0.8f, "Two track cut: radius in m from which two track cuts are applied"}; + Configurable cfgLocalEfficiency{"cfgLocalEfficiency", 0, "0 = OFF and 1 = ON for local efficiency"}; + Configurable cfgDropStepRECO{"cfgDropStepRECO", false, "choice to drop step RECO if efficiency correction is used"}; + Configurable cfgCentBinsForMC{"cfgCentBinsForMC", 0, "0 = generated multiplicity; 1 = reconstructed multiplicity and all associated collisions"}; + } cfgGeneral; Configurable cfgTrackBitMask{"cfgTrackBitMask", 0, "BitMask for track selection systematics; refer to the enum TrackSelectionCuts in filtering task"}; Configurable cfgMultCorrelationsMask{"cfgMultCorrelationsMask", 0, "Selection bitmask for the multiplicity correlations. This should match the filter selection cfgEstimatorBitMask."}; Configurable cfgMultCutFormula{"cfgMultCutFormula", "", "Multiplicity correlations cut formula. A result greater than zero results in accepted event. Parameters: [cFT0C] FT0C centrality, [mFV0A] V0A multiplicity, [mGlob] global track multiplicity, [mPV] PV track multiplicity, [cFT0M] FT0M centrality"}; @@ -109,6 +125,11 @@ struct TwoParticleCorrelationsMpi { Configurable cfgEfficiencyTrigger{"cfgEfficiencyTrigger", "", "CCDB path to efficiency object for trigger particles"}; Configurable cfgEfficiencyAssociated{"cfgEfficiencyAssociated", "", "CCDB path to efficiency object for associated particles"}; + Configurable cfgAcceptance{"cfgAcceptance", "", "CCDB path to the GFW acceptance object"}; + Configurable cfgFillAcceptanceWeights{"cfgFillAcceptanceWeights", false, "Fill acceptance maps instead of physics outputs"}; + Configurable cfgAcceptanceRunByRun{"cfgAcceptanceRunByRun", false, "Fill or load run-by-run acceptance weights"}; + Configurable cfgAcceptancePhiBins{"cfgAcceptancePhiBins", int{DefaultAcceptancePhiBins}, "Number of phi bins in acceptance maps"}; + Configurable cfgAcceptanceEtaBins{"cfgAcceptanceEtaBins", int{DefaultAcceptanceEtaBins}, "Number of eta bins in acceptance maps"}; Configurable cfgNuncSeedsTemplateFile{"cfgNuncSeedsTemplateFile", "", "Local ROOT file containing ensembleYieldTemplates"}; Configurable cfgNuncSeedsTemplate{"cfgNuncSeedsTemplate", "", "CCDB path to the ensemble-yield template ccdb_object"}; Configurable cfgMinPairAcceptance{"cfgMinPairAcceptance", 0.05f, "Minimum pair acceptance used by the event seed estimator"}; @@ -117,6 +138,8 @@ struct TwoParticleCorrelationsMpi { Configurable cfgEventSeedPriorExposure{"cfgEventSeedPriorExposure", 1.f, "Gamma-prior strength in equivalent event exposures for MAP-EM"}; Configurable cfgEventSeedEMMaxIterations{"cfgEventSeedEMMaxIterations", 10, "Maximum number of weighted MAP-EM iterations per event"}; Configurable cfgEventSeedEMTolerance{"cfgEventSeedEMTolerance", 1.e-5f, "Relative component-yield convergence tolerance for MAP-EM"}; + Configurable> cfgEventClassifierPercentileLower{"cfgEventClassifierPercentileLower", {}, "Lower event-classifier percentile boundary in each axisMultiplicity bin; empty keeps the raw classifier user axis"}; + Configurable> cfgEventClassifierPercentileUpper{"cfgEventClassifierPercentileUpper", {}, "Upper event-classifier percentile boundary in each axisMultiplicity bin; empty keeps the raw classifier user axis"}; Configurable cfgNumMixedEvents{"cfgNumMixedEvents", 5, "Number of mixed events per event"}; @@ -124,7 +147,7 @@ struct TwoParticleCorrelationsMpi { Configurable cfgDecayParticleMask{"cfgDecayParticleMask", 0, "Selection bitmask for the decay particles: 0 = no selection"}; Configurable cfgV0RapidityMax{"cfgV0RapidityMax", 0.8, "Maximum rapidity for the decay particles (0 = no selection)"}; - Configurable cfgMassAxis{"cfgMassAxis", 0, "Use invariant mass axis (0 = OFF, 1 = ON)"}; + Configurable cfgUserAxis{"cfgUserAxis", 0, "Additional user axis: 0 = OFF, 1 = invariant mass, 2 = event seed, 3 = nMPI (MCGen only)"}; Configurable> cfgMcTriggerPDGs{"cfgMcTriggerPDGs", {}, "MC PDG codes to use exclusively as trigger particles and exclude from associated particles. Empty = no selection."}; ConfigurableAxis axisVertex{"axisVertex", {7, -7, 7}, "vertex axis for histograms"}; @@ -138,25 +161,34 @@ struct TwoParticleCorrelationsMpi { ConfigurableAxis axisEtaEfficiency{"axisEtaEfficiency", {20, -1.0, 1.0}, "eta axis for efficiency histograms"}; ConfigurableAxis axisPtEfficiency{"axisPtEfficiency", {VARIABLE_WIDTH, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 3.25, 3.5, 3.75, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0}, "pt axis for efficiency histograms"}; - ConfigurableAxis axisInvMass{"axisInvMass", {VARIABLE_WIDTH, 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2.0, 5.0}, "invariant mass axis for histograms"}; + ConfigurableAxis axisUser{"axisUser", {VARIABLE_WIDTH, 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2.0, 5.0}, "additional user axis for histograms"}; ConfigurableAxis axisMultCorrCent{"axisMultCorrCent", {100, 0, 100}, "multiplicity correlation axis for centralities"}; ConfigurableAxis axisMultCorrV0{"axisMultCorrV0", {1000, 0, 100000}, "multiplicity correlation axis for V0 multiplicities"}; ConfigurableAxis axisMultCorrMult{"axisMultCorrMult", {1000, 0, 1000}, "multiplicity correlation axis for track multiplicities"}; + Configurable cfgRegions{"cfgRegions", {{"refN", "refP", "refFull"}, {-0.8, 0.4, -0.8}, {-0.4, 0.8, 0.8}, {0, 0, 0}, {1, 1, 1}}, "Configurations for GFW regions"}; + Configurable cfgCorrConfig{"cfgCorrConfig", {{"refP {2} refN {-2}", "refP {3} refN {-3}", "refP {4} refN {-4}", "refFull {2 -2}", "refFull {2 2 -2 -2}"}, {"ChGap22", "ChGap32", "ChGap42", "ChFull22", "ChFull24"}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}}, "Configurations for each correlation to calculate"}; + Configurable> cfgPtPtGaps{"cfgPtPtGaps", {LongArrayDouble.front().data(), 4, 2, {"subevent 1", "subevent 2", "subevent 3", "subevent 4"}, {"etamin", "etamax"}}, "{etamin,etamax} for all ptpt-subevents"}; + struct : ConfigurableGroup { + Configurable cfgUsePtCorrWeights{"cfgUsePtCorrWeights", true, "Use multiplicity-based event weighting for pt-pt correlations"}; + Configurable cfgUseMultiplicityFlowWeights{"cfgUseMultiplicityFlowWeights", true, "Use multiplicity-based event weighting for azimuthal correlations"}; + Configurable cfgUseMultiplicityFractionWeights{"cfgUseMultiplicityFractionWeights", false, "Use multiplicity-based event weighting for the spectral fraction"}; + } cfgEventWeight; + // This filter is applied to AOD and derived data (column names are identical) - Filter collisionZVtxFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter collisionZVtxFilter = nabs(aod::collision::posZ) < cfgGeneral.cfgCutVertex; // This filter is only applied to AOD Filter collisionVertexTypeFilter = (aod::collision::flags & static_cast(aod::collision::CollisionFlagsRun2::Run2VertexerTracks)) == static_cast(aod::collision::CollisionFlagsRun2::Run2VertexerTracks); // Track filters - Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPt) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t)true)); - Filter cfTrackFilter = (nabs(aod::cftrack::eta) < cfgCutEta) && (aod::cftrack::pt > cfgCutPt) && ncheckbit(aod::track::trackType, as(cfgTrackBitMask)); + Filter trackFilter = (nabs(aod::track::eta) < cfgGeneral.cfgCutEta) && (aod::track::pt > cfgGeneral.cfgCutPt) && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t)true)); + Filter cfTrackFilter = (nabs(aod::cftrack::eta) < cfgGeneral.cfgCutEta) && (aod::cftrack::pt > cfgGeneral.cfgCutPt) && ncheckbit(aod::track::trackType, as(cfgTrackBitMask)); // MC filters - Filter cfMCCollisionFilter = nabs(aod::mccollision::posZ) < cfgCutVertex; - Filter cfMCParticleFilter = (nabs(aod::cfmcparticle::eta) < cfgCutEta) && (aod::cfmcparticle::pt > cfgCutPt); // && (aod::cfmcparticle::sign != 0); //check the sign manually, some specials may be neutral - Filter mcParticleFilter = (nabs(aod::mcparticle::eta) < cfgCutEta) && (aod::mcparticle::pt > cfgCutPt); + Filter cfMCCollisionFilter = nabs(aod::mccollision::posZ) < cfgGeneral.cfgCutVertex; + Filter cfMCParticleFilter = (nabs(aod::cfmcparticle::eta) < cfgGeneral.cfgCutEta) && (aod::cfmcparticle::pt > cfgGeneral.cfgCutPt); // && (aod::cfmcparticle::sign != 0); //check the sign manually, some specials may be neutral + Filter mcParticleFilter = (nabs(aod::mcparticle::eta) < cfgGeneral.cfgCutEta) && (aod::mcparticle::pt > cfgGeneral.cfgCutPt); // Output definitions OutputObj same{"sameEvent"}; @@ -172,7 +204,10 @@ struct TwoParticleCorrelationsMpi { bool mPairCuts = false; THn* mEfficiencyTrigger = nullptr; THn* mEfficiencyAssociated = nullptr; + GFWWeights* mAcceptance = nullptr; bool efficiencyLoaded = false; + bool acceptanceLoaded = false; + int acceptanceRunNumber = InvalidRunNumber; } cfg; struct YieldTemplate { @@ -237,21 +272,57 @@ struct TwoParticleCorrelationsMpi { } }; + struct PendingSeedTriggerFill { + float pt; + float multiplicity; + float posZ; + float weight; + }; + + struct PendingSeedPairFill { + float deltaEta; + float assocPt; + float triggerPt; + float multiplicity; + float deltaPhi; + float posZ; + float weight; + }; + std::vector yieldTemplates; std::vector> pairAcceptanceMaps; std::vector> pairAcceptanceEtaVertexMaps; int pairAcceptanceSchemaVersion = 0; const TList* loadedCcdbYieldTemplateObject = nullptr; bool eventSeedEstimatorEnabled = false; + bool eventClassifierPercentileAxisEnabled = false; enum CorrelationMethod { All = 0, Dd, Ddbar }; + enum UserAxisMode { + NoUserAxis = 0, + InvariantMassAxis, + EventSeedAxis, + NMPIAxis + }; HistogramRegistry registry{"registry"}; PairCuts mPairCuts; + // Generic Framework outputs + OutputObj fFC{"FlowContainer"}; + OutputObj fFCpt{"FlowPtContainer"}; + OutputObj fFCGen{"FlowContainer_gen"}; + OutputObj fFCptGen{"FlowPtContainer_gen"}; + std::unique_ptr fGFW{std::make_unique()}; + std::unique_ptr fPtAxis; + std::unique_ptr fRndm{std::make_unique()}; + std::vector mCorrConfigs; + std::shared_ptr mAcceptanceWeights; + std::map> mAcceptanceWeightsByRun; + Service ccdb{}; Service pdg{}; @@ -259,16 +330,49 @@ struct TwoParticleCorrelationsMpi { using AodTracks = soa::Filtered>; using DerivedCollisions = soa::Filtered; + using DerivedCollisionsCorrected = soa::Filtered; + using DerivedCollisionsMultSet = soa::Filtered>; + using DerivedCollisionsMultSetCorrected = soa::Filtered>; using DerivedTracks = soa::Filtered; void init(o2::framework::InitContext&) { - if (doprocessMCSameDerived && (doprocessSameDerived || doprocessSameDerivedMultSet)) { + if (cfgUserAxis < NoUserAxis || cfgUserAxis > NMPIAxis) { + LOGF(fatal, "Unsupported cfgUserAxis=%d; use 0 (off), 1 (invariant mass), 2 (event seed), or 3 (nMPI)", cfgUserAxis.value); + } + if (cfgGeneral.cfgCentBinsForMC < 0 || cfgGeneral.cfgCentBinsForMC > 1) { + LOGF(fatal, "Unsupported cfgCentBinsForMC=%d; use 0 (generated multiplicity), 1 (reconstructed multiplicity and all associated collisions)", cfgGeneral.cfgCentBinsForMC.value); + } + const int enabledDerivedSameProcesses = static_cast(doprocessSameDerived) + static_cast(doprocessSameDerivedCorrected) + static_cast(doprocessSameDerivedMultSet) + static_cast(doprocessSameDerivedMultSetCorrected); + if (enabledDerivedSameProcesses > 1) { + LOGF(fatal, "Only one reconstructed derived same-event process can be enabled"); + } + const int enabledDerivedMixedProcesses = static_cast(doprocessMixedDerived) + static_cast(doprocessMixedDerivedCorrected) + static_cast(doprocessMixedDerivedMultSet) + static_cast(doprocessMixedDerivedMultSetCorrected); + if (enabledDerivedMixedProcesses > 1) { + LOGF(fatal, "Only one reconstructed derived mixed-event process can be enabled"); + } + if (doprocessMCSameDerived && enabledDerivedSameProcesses > 0) { LOGF(fatal, "processMCSameDerived is mutually exclusive with the reconstructed derived same-event processes because it also fills those outputs"); } if (doprocessSameGenMC && doprocessMCSameDerived) { LOGF(fatal, "processSameGenMC and processMCSameDerived are mutually exclusive because both fill the generated same-event outputs"); } + if (cfgUserAxis == NMPIAxis && + (!(doprocessSameGenMC || doprocessMCSameDerived) || + doprocessSameAOD || enabledDerivedSameProcesses > 0 || + doprocessMixedAOD || enabledDerivedMixedProcesses > 0 || doprocessMCMixedDerived || + cfgGeneral.cfgCentBinsForMC != 0 || cfgFillAcceptanceWeights)) { + LOGF(fatal, "cfgUserAxis=3 supports generated MC same events only: enable processSameGenMC or processMCSameDerived and disable all other same/mixed processes"); + } + if (cfgFillAcceptanceWeights && !cfgAcceptance.value.empty()) { + LOGF(fatal, "cfgFillAcceptanceWeights and cfgAcceptance are mutually exclusive: produce and apply acceptance weights in separate jobs"); + } + if (cfgFillAcceptanceWeights && !(doprocessSameDerived || doprocessSameDerivedMultSet || doprocessMCSameDerived)) { + LOGF(fatal, "cfgFillAcceptanceWeights requires a reconstructed derived same-event process"); + } + if (cfgAcceptancePhiBins < 1 || cfgAcceptanceEtaBins < 1) { + LOGF(fatal, "Acceptance-map bin counts must be positive"); + } if (!cfgNuncSeedsTemplateFile.value.empty() && !cfgNuncSeedsTemplate.value.empty()) { LOGF(fatal, "Configure only one template source: cfgNuncSeedsTemplateFile or cfgNuncSeedsTemplate"); } @@ -279,13 +383,47 @@ struct TwoParticleCorrelationsMpi { LOGF(fatal, "MAP-EM configuration requires non-negative prior exposure, at least one iteration, and positive tolerance"); } eventSeedEstimatorEnabled = !cfgNuncSeedsTemplateFile.value.empty() || !cfgNuncSeedsTemplate.value.empty(); + if (cfgUserAxis == EventSeedAxis && !eventSeedEstimatorEnabled) { + LOGF(fatal, "cfgUserAxis=2 requires an event-seed template configured through cfgNuncSeedsTemplateFile or cfgNuncSeedsTemplate"); + } + const bool hasLowerPercentileBoundaries = !cfgEventClassifierPercentileLower->empty(); + const bool hasUpperPercentileBoundaries = !cfgEventClassifierPercentileUpper->empty(); + if (hasLowerPercentileBoundaries != hasUpperPercentileBoundaries) { + LOGF(fatal, "Configure both cfgEventClassifierPercentileLower and cfgEventClassifierPercentileUpper, or leave both empty"); + } + eventClassifierPercentileAxisEnabled = hasLowerPercentileBoundaries; + if (eventClassifierPercentileAxisEnabled) { + const int nMultiplicityBins = AxisSpec(axisMultiplicity).getNbins(); + if (static_cast(cfgEventClassifierPercentileLower->size()) != nMultiplicityBins || + static_cast(cfgEventClassifierPercentileUpper->size()) != nMultiplicityBins) { + LOGF(fatal, "Event-classifier percentile boundary vectors must each contain exactly %d values, one per axisMultiplicity bin", nMultiplicityBins); + } + for (int multBin = 0; multBin < nMultiplicityBins; ++multBin) { + if (!std::isfinite(cfgEventClassifierPercentileLower->at(multBin)) || + !std::isfinite(cfgEventClassifierPercentileUpper->at(multBin)) || + cfgEventClassifierPercentileLower->at(multBin) >= cfgEventClassifierPercentileUpper->at(multBin)) { + LOGF(fatal, "Invalid event-classifier percentile boundaries in multiplicity bin %d: lower=%g upper=%g", + multBin, cfgEventClassifierPercentileLower->at(multBin), cfgEventClassifierPercentileUpper->at(multBin)); + } + } + if (cfgUserAxis == EventSeedAxis || cfgUserAxis == NMPIAxis) { + const std::vector expectedEdges{-1.5, -0.5, 0.5, 1.5, 2.5}; + const auto& configuredEdges = AxisSpec(axisUser).binEdges; + const float threshold = 1.e-6; + if (configuredEdges.size() != expectedEdges.size() || + !std::equal(configuredEdges.begin(), configuredEdges.end(), expectedEdges.begin(), + [&threshold](double lhs, double rhs) { return std::abs(lhs - rhs) < threshold; })) { + LOGF(fatal, "Percentile-class event classifier axis requires axisUser edges {-1.5,-0.5,0.5,1.5,2.5}"); + } + } + } LOGF(info, "Event seed estimator histogram booking: %s (local template='%s', CCDB template='%s')", eventSeedEstimatorEnabled ? "enabled" : "disabled", cfgNuncSeedsTemplateFile.value.c_str(), cfgNuncSeedsTemplate.value.c_str()); registry.add("yields", "multiplicity/centrality vs pT vs eta", {HistType::kTH3F, {{100, 0, 100, "/multiplicity/centrality"}, {40, 0, 20, "p_{T}"}, {100, -2, 2, "#eta"}}}); registry.add("etaphi", "multiplicity/centrality vs eta vs phi", {HistType::kTH3F, {{100, 0, 100, "multiplicity/centrality"}, {100, -2, 2, "#eta"}, {200, 0, o2::constants::math::TwoPI, "#varphi"}}}); - if (doprocessSameDerivedMultSet) { + if (doprocessSameDerivedMultSet || doprocessSameDerivedMultSetCorrected) { if (cfgMultCorrelationsMask == 0) { LOGF(fatal, "cfgMultCorrelationsMask can not be 0 when MultSet process functions are in use."); } @@ -307,13 +445,14 @@ struct TwoParticleCorrelationsMpi { } registry.add("multCorrelations", "Multiplicity correlations", {HistType::kTHnSparseF, multAxes}); } - registry.add("multiplicity", "event multiplicity", {HistType::kTH1F, {{1000, 0, 100, "/multiplicity/centrality"}}}); + registry.add("multiplicity", "event multiplicity", {HistType::kTH1F, {{100, 0, 100, "/multiplicity/centrality"}}}); if (eventSeedEstimatorEnabled) { registry.add("eventSeedEstimator", "event-level template estimator", {HistType::kTHnSparseF, {{100, 0, 100, "multiplicity"}, {100, -0.5, 99.5, "N_{trig}"}, {200, 0, 20, "Y_{near}"}, {200, 0, 20, "Y_{away}"}, {200, 0, 100, "N_{uncorrelated seeds}"}}}); registry.add("eventSeedPairProbabilities", "summed pair probabilities", {HistType::kTH3F, {{200, 0, 200, "#Sigma P_{baseline}"}, {200, 0, 200, "#Sigma P_{near}"}, {200, 0, 200, "#Sigma P_{away}"}}}); registry.add("eventSeedEstimatorStatus", "event-estimator status", {HistType::kTH1F, {{5, -0.5, 4.5, "status"}}}); registry.add("eventSeedTemplateCoverage", "template coverage vs multiplicity", {HistType::kTH2F, {{100, 0, 100, "multiplicity"}, {102, -0.01, 1.01, "matched/candidate pairs"}}}); registry.add("eventSeedEstimateVsMultiplicity", "event-level seed estimate vs multiplicity", {HistType::kTH2F, {{100, 0, 100, "multiplicity"}, {200, 0, 100, "N_{uncorrelated seeds}"}}}); + registry.add("eventSeedFixedProbabilityVsMultiplicity", "fixed-probability event Seed versus multiplicity;multiplicity;N_{seed}^{probability sum}", {HistType::kTH2F, {axisMultiplicity, {1000, 0, 100}}}); registry.add("eventNearYieldVsMultiplicity", "event-level near yield vs multiplicity", {HistType::kTH2F, {{100, 0, 100, "multiplicity"}, {200, 0, 20, "Y_{near}"}}}); registry.add("eventAwayYieldVsMultiplicity", "event-level away yield vs multiplicity", {HistType::kTH2F, {{100, 0, 100, "multiplicity"}, {200, 0, 20, "Y_{away}"}}}); registry.add("profileEventNTriggers", "mean event trigger count", {HistType::kTProfile, {axisMultiplicity}}); @@ -337,6 +476,7 @@ struct TwoParticleCorrelationsMpi { registry.add("profileEventEMAwayPrior", "mean MAP-EM away-component prior mode", {HistType::kTProfile, {axisMultiplicity}}); registry.add("profileEventEMBaselinePrior", "mean MAP-EM baseline-component prior mode", {HistType::kTProfile, {axisMultiplicity}}); registry.add("eventSeedMAPVsProbability", "MAP-EM versus fixed-probability seed estimate;N_{seed}^{probability sum};N_{seed}^{MAP-EM}", {HistType::kTH2F, {{200, 0, 100}, {200, 0, 100}}}); + registry.add("eventSeedMAPEMVsMultiplicity", "MAP-EM event Seed versus multiplicity;multiplicity;N_{seed}^{MAP-EM}", {HistType::kTH2F, {axisMultiplicity, {1000, 0, 100}}}); registry.add("profileEventProbabilityNuncSeeds", "mean fixed-probability seed estimate", {HistType::kTProfile, {axisMultiplicity}}); } auto* estimatorStatus = registry.get(HIST("eventSeedEstimatorStatus")).get(); @@ -346,6 +486,7 @@ struct TwoParticleCorrelationsMpi { estimatorStatus->GetXaxis()->SetBinLabel(4, "no acceptance-corrected pairs"); estimatorStatus->GetXaxis()->SetBinLabel(5, "valid estimate"); registry.add("mcValidation/estimatedSeedsVsTrueNMPI", "template estimator response;N_{MPI}^{true};N_{seed}^{estimated}", {HistType::kTH2F, {{101, -0.5, 100.5}, {202, -0.5, 100.5}}}); + registry.add("mcValidation/estimatedSeedsVsTrueNMPIVsMultiplicity", "event-level template estimator response;multiplicity;N_{MPI}^{true};N_{seed}^{estimated}", {HistType::kTH3F, {axisMultiplicity, {101, -0.5, 100.5}, {202, -0.5, 100.5}}}); if (cfgEventSeedEstimatorMethod == 1) { registry.add("mcValidation/probabilityEstimatedSeedsVsTrueNMPI", "fixed-probability estimator response;N_{MPI}^{true};N_{seed}^{probability sum}", {HistType::kTH2F, {{101, -0.5, 100.5}, {202, -0.5, 100.5}}}); } @@ -364,6 +505,7 @@ struct TwoParticleCorrelationsMpi { mcValidationStatus->GetXaxis()->SetBinLabel(6, "no acceptance-corrected pairs"); mcValidationStatus->GetXaxis()->SetBinLabel(7, "valid response"); registry.add("mcValidation/generated/estimatedSeedsVsTrueNMPI", "generated-level template estimator response;N_{MPI}^{true};N_{seed,gen}^{estimated}", {HistType::kTH2F, {{101, -0.5, 100.5}, {202, -0.5, 100.5}}}); + registry.add("mcValidation/generated/estimatedSeedsVsTrueNMPIVsMultiplicity", "generated event-level template estimator response;N_{ch}^{gen};N_{MPI}^{true};N_{seed,gen}^{estimated}", {HistType::kTH3F, {axisMultiplicity, {101, -0.5, 100.5}, {202, -0.5, 100.5}}}); if (cfgEventSeedEstimatorMethod == 1) { registry.add("mcValidation/generated/probabilityEstimatedSeedsVsTrueNMPI", "generated-level fixed-probability estimator response;N_{MPI}^{true};N_{seed,gen}^{probability sum}", {HistType::kTH2F, {{101, -0.5, 100.5}, {202, -0.5, 100.5}}}); } @@ -389,6 +531,11 @@ struct TwoParticleCorrelationsMpi { registry.add("eventcount_mixed", "bin", {HistType::kTH1F, {{maxMixBin + 2, -2.5, -0.5 + maxMixBin, "bin"}}}); registry.add("trackcount_same", "bin", {HistType::kTH2F, {{maxMixBin + 2, -2.5, -0.5 + maxMixBin, "bin"}, {10, -0.5, 9.5}}}); registry.add("trackcount_mixed", "bin", {HistType::kTH3F, {{maxMixBin + 2, -2.5, -0.5 + maxMixBin, "bin"}, {10, -0.5, 9.5}, {10, -0.5, 9.5}}}); + if (cfgFillAcceptanceWeights && !cfgAcceptanceRunByRun) { + AxisSpec phiAxis{cfgAcceptancePhiBins, 0., o2::constants::math::TwoPI, "#varphi"}; + AxisSpec etaAxis{cfgAcceptanceEtaBins, -cfgGeneral.cfgCutEta.value, cfgGeneral.cfgCutEta.value, "#eta"}; + mAcceptanceWeights = registry.add("phi_eta_vtxz_ref", "Reference-track acceptance;#varphi;#eta;z_{vtx} (cm)", {HistType::kTH3D, {phiAxis, etaAxis, axisVertex}}); + } mPairCuts.SetHistogramRegistry(®istry); @@ -401,8 +548,8 @@ struct TwoParticleCorrelationsMpi { cfg.mPairCuts = true; } - if (cfgTwoTrackCut > 0) { - mPairCuts.SetTwoTrackCuts(cfgTwoTrackCut, cfgTwoTrackCutMinRadius); + if (cfgGeneral.cfgTwoTrackCut > 0) { + mPairCuts.SetTwoTrackCuts(cfgGeneral.cfgTwoTrackCut, cfgGeneral.cfgTwoTrackCutMinRadius); } // --- OBJECT INIT --- @@ -441,15 +588,23 @@ struct TwoParticleCorrelationsMpi { std::vector userAxis; std::vector userMixingAxis; - if (cfgMassAxis != 0) { - userAxis.emplace_back(axisInvMass, "m (GeV/c^2)"); - userMixingAxis.emplace_back(axisInvMass, "m (GeV/c^2)"); + if (cfgUserAxis == InvariantMassAxis) { + userAxis.emplace_back(axisUser, "m (GeV/c^2)"); + userMixingAxis.emplace_back(axisUser, "m (GeV/c^2)"); + } else if (cfgUserAxis == EventSeedAxis) { + const char* title = eventClassifierPercentileAxisEnabled ? "N_{seed} percentile class" : "N_{seed}"; + userAxis.emplace_back(axisUser, title); + userMixingAxis.emplace_back(axisUser, title); + } else if (cfgUserAxis == NMPIAxis) { + const char* title = eventClassifierPercentileAxisEnabled ? "N_{MPI}^{true} percentile class" : "N_{MPI}^{true}"; + userAxis.emplace_back(axisUser, title); + userMixingAxis.emplace_back(axisUser, title); } same.setObject(new CorrelationContainer("sameEvent", "sameEvent", corrAxis, effAxis, userAxis)); mixed.setObject(new CorrelationContainer("mixedEvent", "mixedEvent", corrAxis, effAxis, userMixingAxis)); - same->setTrackEtaCut(cfgCutEta); - mixed->setTrackEtaCut(cfgCutEta); + same->setTrackEtaCut(cfgGeneral.cfgCutEta); + mixed->setTrackEtaCut(cfgGeneral.cfgCutEta); if (!cfgEfficiencyAssociated.value.empty()) { efficiencyAssociatedCache.reserve(512); @@ -463,6 +618,298 @@ struct TwoParticleCorrelationsMpi { ccdb->setCreatedNotAfter(now); // TODO must become global parameter from the train creation time loadLocalYieldTemplates(); + + // Generic Framework init + AxisSpec ptAxisSpec = axisPtTrigger; + const auto validateFlowPtRange = [&ptAxisSpec](const std::pair& range, const char* name) { + if (!std::isfinite(range.first) || !std::isfinite(range.second) || range.first >= range.second) { + LOGF(fatal, "%s must define a finite, increasing pT range; received {%g, %g}", name, range.first, range.second); + } + if (range.first < ptAxisSpec.binEdges.front() || range.second > ptAxisSpec.binEdges.back()) { + LOGF(fatal, "%s={%g, %g} must be contained in axisPtTrigger={%g, %g}", + name, range.first, range.second, ptAxisSpec.binEdges.front(), ptAxisSpec.binEdges.back()); + } + }; + validateFlowPtRange(cfgGeneral.cfgFlowPtRef.value, "cfgFlowPtRef"); + validateFlowPtRange(cfgGeneral.cfgFlowPtPOI.value, "cfgFlowPtPOI"); + const int nPtBins = static_cast(ptAxisSpec.binEdges.size()) - 1; + fPtAxis = std::make_unique(nPtBins, ptAxisSpec.binEdges.data()); + if (cfgRegions->GetSize() < 0) { + LOGF(error, "Configuration contains vectors of different size - check the GFWRegions configurable"); + } + for (auto i(0); i < cfgRegions->GetSize(); ++i) { + fGFW->AddRegion(cfgRegions->GetNames()[i], cfgRegions->GetEtaMin()[i], cfgRegions->GetEtaMax()[i], (cfgRegions->GetpTDifs()[i] != 0) ? nPtBins + 1 : 1, cfgRegions->GetBitmasks()[i]); + } + for (auto i = 0; i < cfgCorrConfig->GetSize(); ++i) { + mCorrConfigs.push_back(fGFW->GetCorrelatorConfig(cfgCorrConfig->GetCorrs()[i], cfgCorrConfig->GetHeads()[i], cfgCorrConfig->GetpTDifs()[i] != 0)); + } + if (mCorrConfigs.empty()) { + LOGF(error, "Configuration contains vectors of different size - check the GFWCorrConfig configurable"); + } + fGFW->CreateRegions(); + int nPtPtSubevents = 0; + for (uint32_t i = 0; i < cfgPtPtGaps->rows(); ++i) { + if (cfgPtPtGaps->get(i, uint32_t{0}) < -1. || cfgPtPtGaps->get(i, uint32_t{1}) < -1.) { + continue; + } + ++nPtPtSubevents; + } + + if (!cfgFillAcceptanceWeights && (doprocessMCSameDerived || doprocessSameDerived || doprocessSameDerivedMultSet)) { + auto recoProfiles = std::make_unique(); + addConfigObjectsToObjArray(recoProfiles.get(), mCorrConfigs, cfgUserAxis == EventSeedAxis && eventClassifierPercentileAxisEnabled); + fFC.setObject(new FlowContainer("FlowContainer")); + fFC->SetXAxis(fPtAxis.get()); + fFC->Initialize(recoProfiles.get(), axisMultiplicity, FlowNBootstrap); + + fFCpt.setObject(new FlowPtContainer("FlowPtContainer")); + fFCpt->setEventWeight(cfgEventWeight.cfgUsePtCorrWeights ? eventweight::TupleWeight : eventweight::UnityWeight); + fFCpt->setUseCentralMoments(true); + fFCpt->setUseGapMethod(true); + fFCpt->initialise(axisMultiplicity, MaxPtCorrelationOrder, cfgCorrConfig.value, FlowNBootstrap); + fFCpt->initialiseSubevent(axisMultiplicity, MaxPtCorrelationOrder, nPtPtSubevents, FlowNBootstrap); + } + if (!cfgFillAcceptanceWeights && (doprocessMCSameDerived || doprocessSameGenMC)) { + auto generatedProfiles = std::make_unique(); + addConfigObjectsToObjArray(generatedProfiles.get(), mCorrConfigs, cfgUserAxis == NMPIAxis && eventClassifierPercentileAxisEnabled); + fFCGen.setObject(new FlowContainer("FlowContainer_gen")); + fFCGen->SetXAxis(fPtAxis.get()); + fFCGen->Initialize(generatedProfiles.get(), axisMultiplicity, FlowNBootstrap); + + fFCptGen.setObject(new FlowPtContainer("FlowPtContainer_gen")); + fFCptGen->setEventWeight(cfgEventWeight.cfgUsePtCorrWeights ? eventweight::TupleWeight : eventweight::UnityWeight); + fFCptGen->setUseCentralMoments(true); + fFCptGen->setUseGapMethod(true); + fFCptGen->initialise(axisMultiplicity, MaxPtCorrelationOrder, cfgCorrConfig.value, FlowNBootstrap); + fFCptGen->initialiseSubevent(axisMultiplicity, MaxPtCorrelationOrder, nPtPtSubevents, FlowNBootstrap); + } + } + + enum DataType { + Reco, + Gen + }; + enum GFWRegionMask { + ReferenceMask = 1, + PoiMask = 2, + OverlapMask = 4 + }; + enum SeedClass { + InvalidSeedClass = -1, + LowSeedClass, + MiddleSeedClass, + HighSeedClass, + SeedClassCount + }; + + const char* getSeedClassSuffix(const SeedClass seedClass) const + { + if (cfgUserAxis.value == NMPIAxis) { + switch (seedClass) { + case LowSeedClass: + return "__nMPILow"; + case MiddleSeedClass: + return "__nMPIMiddle"; + case HighSeedClass: + return "__nMPIHigh"; + default: + return ""; + } + } + switch (seedClass) { + case LowSeedClass: + return "__seedLow"; + case MiddleSeedClass: + return "__seedMiddle"; + case HighSeedClass: + return "__seedHigh"; + default: + return ""; + } + } + + std::string getSeedClassProfileName(const std::string& baseName, const SeedClass seedClass) const + { + return baseName + getSeedClassSuffix(seedClass); + } + + void addFlowProfileDefinition(TObjArray* profiles, const std::string& name, const std::string& title, const bool addSeedClasses) + { + profiles->Add(new TNamed(name.c_str(), title.c_str())); + if (!addSeedClasses) { + return; + } + for (int seedClassIndex = LowSeedClass; seedClassIndex < SeedClassCount; ++seedClassIndex) { + const auto seedClass = static_cast(seedClassIndex); + const auto classifiedName = getSeedClassProfileName(name, seedClass); + const auto classifiedTitle = getSeedClassProfileName(title, seedClass); + profiles->Add(new TNamed(classifiedName.c_str(), classifiedTitle.c_str())); + } + } + + void addConfigObjectsToObjArray(TObjArray* profiles, const std::vector& configs, const bool addSeedClasses) + { + profiles->SetOwner(true); + for (const auto& config : configs) { + if (config.pTDif) { + const std::string suffix = "_ptDiff"; + for (auto i = 0; i < fPtAxis->GetNbins(); ++i) { + const std::string index = Form("_pt_%i", i + 1); + const std::string name = config.Head + index; + const std::string title = config.Head + suffix; + addFlowProfileDefinition(profiles, name, title, addSeedClasses); + } + } else { + addFlowProfileDefinition(profiles, config.Head, config.Head, addSeedClasses); + } + } + } + + template + void fillOutputContainers(const float& centMult, const double& randomNumber, const SeedClass seedClass = InvalidSeedClass) + { + auto& flowContainer = (dt == Gen) ? fFCGen : fFC; + auto& flowPtContainer = (dt == Gen) ? fFCptGen : fFCpt; + const auto fillFlowProfile = [&](const std::string& profileName, const double value, const double weight) { + flowContainer->FillProfile(profileName.c_str(), centMult, value, weight, randomNumber); + if (seedClass != InvalidSeedClass) { + const auto classifiedName = getSeedClassProfileName(profileName, seedClass); + flowContainer->FillProfile(classifiedName.c_str(), centMult, value, weight, randomNumber); + } + }; + + flowPtContainer->calculateCorrelations(); + flowPtContainer->calculateSubeventCorrelations(); + flowPtContainer->fillPtProfiles(centMult, randomNumber); + flowPtContainer->fillSubeventPtProfiles(centMult, randomNumber); + flowPtContainer->fillCMProfiles(centMult, randomNumber); + flowPtContainer->fillCMSubeventProfiles(centMult, randomNumber); + + for (std::size_t configIndex = 0; configIndex < mCorrConfigs.size(); ++configIndex) { + if (!mCorrConfigs.at(configIndex).pTDif) { + const auto dnx = fGFW->Calculate(mCorrConfigs.at(configIndex), 0, true).real(); + if (dnx == 0) { + continue; + } + const auto val = fGFW->Calculate(mCorrConfigs.at(configIndex), 0, false).real() / dnx; + if (std::abs(val) < 1) { + fillFlowProfile(mCorrConfigs.at(configIndex).Head, val, cfgEventWeight.cfgUseMultiplicityFlowWeights ? dnx : 1.0); + flowPtContainer->fillVnPtProfiles(centMult, val, dnx, randomNumber, cfgCorrConfig->GetpTCorrMasks()[configIndex]); + } + continue; + } + for (int i = 1; i <= fPtAxis->GetNbins(); i++) { + const auto dnx = fGFW->Calculate(mCorrConfigs.at(configIndex), i - 1, true).real(); + if (dnx == 0) { + continue; + } + const auto val = fGFW->Calculate(mCorrConfigs.at(configIndex), i - 1, false).real() / dnx; + if (std::abs(val) < 1) { + const std::string profileName = Form("%s_pt_%i", mCorrConfigs.at(configIndex).Head.c_str(), i); + fillFlowProfile(profileName, val, cfgEventWeight.cfgUseMultiplicityFlowWeights ? dnx : 1.0); + } + } + } + } + + template + inline void fillPtSums(const TTrack& track, const float& centMult, const double& posZ) + { + auto& flowPtContainer = (dt == Gen) ? fFCptGen : fFCpt; + double weff = 1.; + if constexpr (dt == Reco) { + if (cfg.mEfficiencyTrigger) { + weff = getEfficiencyCorrection(cfg.mEfficiencyTrigger, track.eta(), track.pt(), centMult, posZ); + } + } + if (weff < 0) { + return; + } + + // Fill the nominal sums + if (std::abs(track.eta()) < cfgGeneral.cfgCutEta) { + flowPtContainer->fill(weff, track.pt()); + } + + // Fill the subevent sums + std::size_t index = 0; + for (uint32_t i = 0; i < cfgPtPtGaps->rows(); ++i) { + const auto etamin = cfgPtPtGaps->get(i, uint32_t{0}); + const auto etamax = cfgPtPtGaps->get(i, uint32_t{1}); + if (etamin < -1. || etamax < -1.) { + continue; + } + if (etamin < track.eta() && track.eta() < etamax) { + flowPtContainer->fillSub(weff, track.pt(), index); + } + ++index; + } + } + + template + double getAcceptance(const TTrack& track, const double& posZ) + { + if (!cfg.mAcceptance) { + return 1.; + } + return cfg.mAcceptance->getNUA(track.phi(), track.eta(), posZ); + } + + std::shared_ptr getAcceptanceWeightsForRun(const int runNumber) + { + const auto existing = mAcceptanceWeightsByRun.find(runNumber); + if (existing != mAcceptanceWeightsByRun.end()) { + return existing->second; + } + + AxisSpec phiAxis{cfgAcceptancePhiBins, 0., o2::constants::math::TwoPI, "#varphi"}; + AxisSpec etaAxis{cfgAcceptanceEtaBins, -cfgGeneral.cfgCutEta.value, cfgGeneral.cfgCutEta.value, "#eta"}; + const std::string histogramName = Form("%d/phi_eta_vtxz_ref", runNumber); + const auto histogram = registry.add(histogramName.c_str(), "Reference-track acceptance;#varphi;#eta;z_{vtx} (cm)", {HistType::kTH3D, {phiAxis, etaAxis, axisVertex}}); + mAcceptanceWeightsByRun.emplace(runNumber, histogram); + return histogram; + } + + template + void fillAcceptanceWeights(const TTrack& track, const double& posZ, const int runNumber) + { + if (track.pt() <= fPtAxis->GetXmin() || track.pt() >= fPtAxis->GetXmax()) { + return; + } + const auto histogram = cfgAcceptanceRunByRun ? getAcceptanceWeightsForRun(runNumber) : mAcceptanceWeights; + histogram->Fill(track.phi(), track.eta(), posZ); + } + + template + inline void fillGFW(const TTrack& track, const float& centMult, const double& posZ) + { + const bool withinPtRef = track.pt() > cfgGeneral.cfgFlowPtRef->first && track.pt() < cfgGeneral.cfgFlowPtRef->second; + const bool withinPtPOI = track.pt() > cfgGeneral.cfgFlowPtPOI->first && track.pt() < cfgGeneral.cfgFlowPtPOI->second; + if (!withinPtRef && !withinPtPOI) { + return; + } + double wacc = 1.; + double weff = 1.; + if constexpr (dt == Reco) { + wacc = getAcceptance(track, posZ); + if (cfg.mEfficiencyAssociated) { + weff = getEfficiencyCorrection(cfg.mEfficiencyAssociated, track.eta(), track.pt(), centMult, posZ); + } + } + if (weff < 0 || !std::isfinite(wacc) || wacc <= 0.) { + return; + } + const double weight = weff * wacc; + const int ptBin = fPtAxis->FindBin(track.pt()) - 1; + if (withinPtRef) { + fGFW->Fill(track.eta(), ptBin, track.phi(), weight, ReferenceMask); + } + if (withinPtPOI) { + fGFW->Fill(track.eta(), ptBin, track.phi(), weight, PoiMask); + } + if (withinPtRef && withinPtPOI) { + fGFW->Fill(track.eta(), ptBin, track.phi(), weight, OverlapMask); + } } int getMagneticField(uint64_t timestamp) @@ -485,6 +932,18 @@ struct TwoParticleCorrelationsMpi { template using HasMultSet = decltype(std::declval().multiplicities()); + template + using HasCorrectedMultiplicity = decltype(std::declval().multiplicityCorrected()); + + template + static float getAnalysisMultiplicity(const TCollision& collision) + { + if constexpr (std::experimental::is_detected::value) { + return collision.multiplicityCorrected(); + } + return collision.multiplicity(); + } + template void fillQA(const TCollision& collision, float multiplicity, const TTracks& tracks) { @@ -532,11 +991,10 @@ struct TwoParticleCorrelationsMpi { template bool fillContainerEvent(TTarget target, float multiplicity, CorrelationContainer::CFStep step) { - const float containerMultiplicity = getCorrelationContainerMultiplicity(multiplicity); - if (containerMultiplicity < 0.f) { + if (multiplicity < 0.f) { return false; } - target->fillEvent(containerMultiplicity, step); + target->fillEvent(multiplicity, step); return true; } @@ -896,6 +1354,70 @@ struct TwoParticleCorrelationsMpi { return static_cast(std::distance(edges.begin(), upper)) - 1; } + double getEventSeedUserAxisValue(double multiplicity, double eventSeed) const + { + if (!eventClassifierPercentileAxisEnabled || eventSeed < 0.0) { + return eventSeed; + } + const int multBin = findPairAcceptanceMultiplicityBin(multiplicity); + if (multBin < 0 || multBin >= static_cast(cfgEventClassifierPercentileLower->size())) { + return -1.0; + } + if (eventSeed < cfgEventClassifierPercentileLower->at(multBin)) { + return 0.0; + } + if (eventSeed >= cfgEventClassifierPercentileUpper->at(multBin)) { + return 2.0; + } + return 1.0; + } + + double getTrueNMPIUserAxisValue(double multiplicity, double nMPI) const + { + if (!eventClassifierPercentileAxisEnabled || nMPI < 0.0) { + return nMPI; + } + const int multBin = findPairAcceptanceMultiplicityBin(multiplicity); + if (multBin < 0 || multBin >= static_cast(cfgEventClassifierPercentileLower->size())) { + return -1.0; + } + if (nMPI < cfgEventClassifierPercentileLower->at(multBin)) { + return 0.0; + } + if (nMPI >= cfgEventClassifierPercentileUpper->at(multBin)) { + return 2.0; + } + return 1.0; + } + + SeedClass getEventSeedClass(const double multiplicity, const double eventSeed) const + { + if (!eventClassifierPercentileAxisEnabled) { + return InvalidSeedClass; + } + const double userAxisValue = getEventSeedUserAxisValue(multiplicity, eventSeed); + if (!std::isfinite(userAxisValue) || + userAxisValue < static_cast(LowSeedClass) || + userAxisValue >= static_cast(SeedClassCount)) { + return InvalidSeedClass; + } + return static_cast(userAxisValue); + } + + SeedClass getTrueNMPIClass(const double multiplicity, const double nMPI) const + { + if (!eventClassifierPercentileAxisEnabled) { + return InvalidSeedClass; + } + const double userAxisValue = getTrueNMPIUserAxisValue(multiplicity, nMPI); + if (!std::isfinite(userAxisValue) || + userAxisValue < static_cast(LowSeedClass) || + userAxisValue >= static_cast(SeedClassCount)) { + return InvalidSeedClass; + } + return static_cast(userAxisValue); + } + double getPairAcceptance(double multiplicity, double deltaPhi, double deltaEta, double posZ) const { const int multBin = findPairAcceptanceMultiplicityBin(multiplicity); @@ -927,7 +1449,7 @@ struct TwoParticleCorrelationsMpi { } void addPairProbabilities(EventSeedEstimate& estimate, const YieldTemplate& yieldTemplate, - double multiplicity, double deltaPhi, double deltaEta, double posZ) + double multiplicity, double deltaPhi, double deltaEta, double posZ, bool fillAcceptanceQA = true) { const auto& parameters = yieldTemplate.parameters; const double near = std::max(0.0, evaluateGaussian(deltaPhi, parameters.data()) + evaluateGaussian(deltaPhi, parameters.data() + 3)); @@ -977,7 +1499,9 @@ struct TwoParticleCorrelationsMpi { } estimate.sumAcceptanceWeights += acceptanceWeight; ++estimate.nAcceptanceCorrectedPairs; - registry.fill(HIST("eventSeedAcceptanceWeight"), acceptanceWeight); + if (fillAcceptanceQA) { + registry.fill(HIST("eventSeedAcceptanceWeight"), acceptanceWeight); + } } void finalizeEventSeedEstimate(EventSeedEstimate& estimate) @@ -1090,6 +1614,7 @@ struct TwoParticleCorrelationsMpi { registry.fill(HIST("eventSeedEstimator"), multiplicity, estimate.nTriggers, estimate.nearYield(), estimate.awayYield(), estimate.nuncSeeds()); registry.fill(HIST("eventSeedPairProbabilities"), estimate.probabilityBaselinePairs, estimate.probabilityNearPairs, estimate.probabilityAwayPairs); registry.fill(HIST("eventSeedEstimateVsMultiplicity"), multiplicity, estimate.nuncSeeds()); + registry.fill(HIST("eventSeedFixedProbabilityVsMultiplicity"), multiplicity, estimate.probabilityNuncSeeds()); registry.fill(HIST("eventNearYieldVsMultiplicity"), multiplicity, estimate.nearYield()); registry.fill(HIST("eventAwayYieldVsMultiplicity"), multiplicity, estimate.awayYield()); registry.fill(HIST("profileEventNearYield"), multiplicity, estimate.nearYield()); @@ -1103,6 +1628,7 @@ struct TwoParticleCorrelationsMpi { registry.fill(HIST("profileEventEMAwayPrior"), multiplicity, estimate.priorComponentCounts[1]); registry.fill(HIST("profileEventEMBaselinePrior"), multiplicity, estimate.priorComponentCounts[2]); registry.fill(HIST("eventSeedMAPVsProbability"), estimate.probabilityNuncSeeds(), estimate.nuncSeeds()); + registry.fill(HIST("eventSeedMAPEMVsMultiplicity"), multiplicity, estimate.nuncSeeds()); } } @@ -1139,6 +1665,7 @@ struct TwoParticleCorrelationsMpi { const double bias = estimatedSeeds - trueNMPI; registry.fill(HIST("mcValidation/status"), 6.0); registry.fill(HIST("mcValidation/estimatedSeedsVsTrueNMPI"), trueNMPI, estimatedSeeds); + registry.fill(HIST("mcValidation/estimatedSeedsVsTrueNMPIVsMultiplicity"), multiplicity, trueNMPI, estimatedSeeds); if (estimate.usedMapEM) { registry.fill(HIST("mcValidation/probabilityEstimatedSeedsVsTrueNMPI"), trueNMPI, estimate.probabilityNuncSeeds()); } @@ -1182,6 +1709,7 @@ struct TwoParticleCorrelationsMpi { const double bias = estimatedSeeds - trueNMPI; registry.fill(HIST("mcValidation/generated/status"), 5.0); registry.fill(HIST("mcValidation/generated/estimatedSeedsVsTrueNMPI"), trueNMPI, estimatedSeeds); + registry.fill(HIST("mcValidation/generated/estimatedSeedsVsTrueNMPIVsMultiplicity"), multiplicity, trueNMPI, estimatedSeeds); if (estimate.usedMapEM) { registry.fill(HIST("mcValidation/generated/probabilityEstimatedSeedsVsTrueNMPI"), trueNMPI, estimate.probabilityNuncSeeds()); } @@ -1192,11 +1720,34 @@ struct TwoParticleCorrelationsMpi { } } + template + void flushSeedAxisFills(TTarget target, const std::vector& triggerFills, const std::vector& pairFills, double eventSeed) + { + for (const auto& fill : triggerFills) { + target->getTriggerHist()->Fill(step, fill.pt, fill.multiplicity, fill.posZ, getEventSeedUserAxisValue(fill.multiplicity, eventSeed), fill.weight); + } + for (const auto& fill : pairFills) { + target->getPairHist()->Fill(step, fill.deltaEta, fill.assocPt, fill.triggerPt, fill.multiplicity, fill.deltaPhi, fill.posZ, getEventSeedUserAxisValue(fill.multiplicity, eventSeed), fill.weight); + } + } + + template + double estimateEventSeedWithoutFilling(TTarget target, TTracks& tracks, float multiplicity, float posZ, int magField) + { + EventSeedEstimate estimate; + std::vector discardedTriggerFills; + std::vector discardedPairFills; + discardedTriggerFills.reserve(tracks.size()); + discardedPairFills.reserve(tracks.size() * tracks.size()); + fillCorrelations(std::move(target), tracks, tracks, multiplicity, posZ, magField, 1.0f, &estimate, &discardedTriggerFills, &discardedPairFills, -1.f, false, false); + finalizeEventSeedEstimate(estimate); + return estimate.nuncSeeds(); + } + template - void fillCorrelations(TTarget target, TTracks1& tracks1, TTracks2& tracks2, float multiplicity, float posZ, int magField, float eventWeight, EventSeedEstimate* seedEstimate = nullptr) + void fillCorrelations(TTarget target, TTracks1& tracks1, TTracks2& tracks2, float multiplicity, float posZ, int magField, float eventWeight, EventSeedEstimate* seedEstimate = nullptr, std::vector* pendingTriggerFills = nullptr, std::vector* pendingPairFills = nullptr, double userAxisValue = -1.0, bool fillEstimatorAcceptanceQA = true, bool fillLoopQA = true) { - const float containerMultiplicity = getCorrelationContainerMultiplicity(multiplicity); - if (containerMultiplicity < 0.f) { + if (multiplicity < 0.f) { return; } @@ -1229,8 +1780,8 @@ struct TwoParticleCorrelationsMpi { } } else { // otherwise check the sign against the configuration const int sign = getParticleSign(track1); - if (cfgTriggerCharge != 0) { - if (cfgTriggerCharge * sign < 0) { + if (cfgGeneral.cfgTriggerCharge != 0) { + if (cfgGeneral.cfgTriggerCharge * sign < 0) { continue; } } else if (sign == 0) { @@ -1239,7 +1790,7 @@ struct TwoParticleCorrelationsMpi { } } else if constexpr (std::experimental::is_detected::value) { // Check reco objects that have the sign attribute. There are no neutrals to deal with. - if (cfgTriggerCharge != 0 && cfgTriggerCharge * track1.sign() < 0) { + if (cfgGeneral.cfgTriggerCharge != 0 && cfgGeneral.cfgTriggerCharge * track1.sign() < 0) { continue; } } @@ -1253,7 +1804,9 @@ struct TwoParticleCorrelationsMpi { if (t && std::abs(y) > cfgV0RapidityMax) { continue; // V0s are not allowed to be outside the rapidity range } - registry.fill(HIST("yvspt"), y, track1.pt()); + if (fillLoopQA) { + registry.fill(HIST("yvspt"), y, track1.pt()); + } } } @@ -1270,18 +1823,26 @@ struct TwoParticleCorrelationsMpi { } } - if (cfgMassAxis) { + if (cfgUserAxis == EventSeedAxis) { + if (pendingTriggerFills) { + pendingTriggerFills->push_back({track1.pt(), multiplicity, posZ, triggerWeight}); + } else { + target->getTriggerHist()->Fill(step, track1.pt(), multiplicity, posZ, userAxisValue, triggerWeight); + } + } else if (cfgUserAxis == NMPIAxis) { + target->getTriggerHist()->Fill(step, track1.pt(), multiplicity, posZ, userAxisValue, triggerWeight); + } else if (cfgUserAxis == InvariantMassAxis) { if constexpr (std::experimental::is_detected::value) { - target->getTriggerHist()->Fill(step, track1.pt(), containerMultiplicity, posZ, track1.invMass(), triggerWeight); + target->getTriggerHist()->Fill(step, track1.pt(), multiplicity, posZ, track1.invMass(), triggerWeight); } else if constexpr (std::experimental::is_detected::value) { // TParticlePDG *p = pdg->GetParticle(track1.pdgCode()); // target->getTriggerHist()->Fill(step, track1.pt(), multiplicity, posZ, p->Mass(), triggerWeight); - target->getTriggerHist()->Fill(step, track1.pt(), containerMultiplicity, posZ, 1.8, triggerWeight); + target->getTriggerHist()->Fill(step, track1.pt(), multiplicity, posZ, 1.8, triggerWeight); } else { - LOGF(fatal, "Can not fill mass axis without invMass column. Disable cfgMassAxis."); + LOGF(fatal, "Can not fill invariant-mass user axis without invMass column. Disable cfgUserAxis or select another mode."); } } else { - target->getTriggerHist()->Fill(step, track1.pt(), containerMultiplicity, posZ, triggerWeight); + target->getTriggerHist()->Fill(step, track1.pt(), multiplicity, posZ, triggerWeight); } const bool triggerHasTemplate = seedEstimate && hasTriggerTemplate(multiplicity, track1.pt()); @@ -1331,22 +1892,22 @@ struct TwoParticleCorrelationsMpi { } if constexpr (std::experimental::is_detected::value && std::experimental::is_detected::value) { - if (cfgCorrelationMethod == CorrelationMethod::Dd && track1.decay() != track2.decay()) { + if (cfgGeneral.cfgCorrelationMethod == CorrelationMethod::Dd && track1.decay() != track2.decay()) { continue; } - if (cfgCorrelationMethod == CorrelationMethod::Ddbar && track1.decay() == track2.decay()) { + if (cfgGeneral.cfgCorrelationMethod == CorrelationMethod::Ddbar && track1.decay() == track2.decay()) { continue; } } - if (cfgPtOrder != 0 && track2.pt() >= track1.pt()) { + if (cfgGeneral.cfgPtOrder != 0 && track2.pt() >= track1.pt()) { continue; } if constexpr (std::experimental::is_detected::value || std::experimental::is_detected::value) { const int associatedSign = getParticleSign(track2); - if (cfgAssociatedCharge != 0) { - if (cfgAssociatedCharge * associatedSign < 0) { + if (cfgGeneral.cfgAssociatedCharge != 0) { + if (cfgGeneral.cfgAssociatedCharge * associatedSign < 0) { continue; } } else if (associatedSign == 0) { // mc particles come in neutrals, need to check explicitly @@ -1356,7 +1917,7 @@ struct TwoParticleCorrelationsMpi { if constexpr ((std::experimental::is_detected::value || std::experimental::is_detected::value) && (std::experimental::is_detected::value || std::experimental::is_detected::value)) { - if (cfgPairCharge != 0 && cfgPairCharge * getParticleSign(track1) * getParticleSign(track2) < 0) { + if (cfgGeneral.cfgPairCharge != 0 && cfgGeneral.cfgPairCharge * getParticleSign(track1) * getParticleSign(track2) < 0) { continue; } } @@ -1367,7 +1928,7 @@ struct TwoParticleCorrelationsMpi { if (cfg.mPairCuts && mPairCuts.conversionCuts(track1, track2)) { continue; } - if (cfgTwoTrackCut > 0 && mPairCuts.twoTrackCut(track1, track2, magField)) { + if (cfgGeneral.cfgTwoTrackCut > 0 && mPairCuts.twoTrackCut(track1, track2, magField)) { continue; } } @@ -1387,23 +1948,31 @@ struct TwoParticleCorrelationsMpi { if (triggerHasTemplate) { ++seedEstimate->nCandidatePairs; if (const auto* yieldTemplate = findYieldTemplate(multiplicity, track1.pt(), track2.pt())) { - addPairProbabilities(*seedEstimate, *yieldTemplate, multiplicity, deltaPhi, deltaEta, posZ); + addPairProbabilities(*seedEstimate, *yieldTemplate, multiplicity, deltaPhi, deltaEta, posZ, fillEstimatorAcceptanceQA); } else { ++seedEstimate->nPairsWithoutTemplate; } } // last param is the weight - if (cfgMassAxis) { + if (cfgUserAxis == EventSeedAxis) { + if (pendingPairFills) { + pendingPairFills->push_back({deltaEta, track2.pt(), track1.pt(), multiplicity, deltaPhi, posZ, associatedWeight}); + } else { + target->getPairHist()->Fill(step, deltaEta, track2.pt(), track1.pt(), multiplicity, deltaPhi, posZ, userAxisValue, associatedWeight); + } + } else if (cfgUserAxis == NMPIAxis) { + target->getPairHist()->Fill(step, deltaEta, track2.pt(), track1.pt(), multiplicity, deltaPhi, posZ, userAxisValue, associatedWeight); + } else if (cfgUserAxis == InvariantMassAxis) { if constexpr (std::experimental::is_detected::value) { - target->getPairHist()->Fill(step, deltaEta, track2.pt(), track1.pt(), containerMultiplicity, deltaPhi, posZ, track1.invMass(), associatedWeight); + target->getPairHist()->Fill(step, deltaEta, track2.pt(), track1.pt(), multiplicity, deltaPhi, posZ, track1.invMass(), associatedWeight); } else if constexpr (std::experimental::is_detected::value) { - target->getPairHist()->Fill(step, deltaEta, track2.pt(), track1.pt(), containerMultiplicity, deltaPhi, posZ, 1.8, associatedWeight); // p->Mass() + target->getPairHist()->Fill(step, deltaEta, track2.pt(), track1.pt(), multiplicity, deltaPhi, posZ, 1.8, associatedWeight); // p->Mass() } else { - LOGF(fatal, "Can not fill mass axis without invMass column. Disable cfgMassAxis."); + LOGF(fatal, "Can not fill invariant-mass user axis without invMass column. Disable cfgUserAxis or select another mode."); } } else { - target->getPairHist()->Fill(step, deltaEta, track2.pt(), track1.pt(), containerMultiplicity, deltaPhi, posZ, associatedWeight); + target->getPairHist()->Fill(step, deltaEta, track2.pt(), track1.pt(), multiplicity, deltaPhi, posZ, associatedWeight); } } } @@ -1415,7 +1984,7 @@ struct TwoParticleCorrelationsMpi { return; } if (!cfgEfficiencyTrigger.value.empty()) { - if (cfgLocalEfficiency > 0) { + if (cfgGeneral.cfgLocalEfficiency > 0) { TFile* fEfficiencyTrigger = TFile::Open(cfgEfficiencyTrigger.value.c_str(), "READ"); cfg.mEfficiencyTrigger = dynamic_cast(fEfficiencyTrigger->Get("ccdb_object")); } else { @@ -1427,7 +1996,7 @@ struct TwoParticleCorrelationsMpi { LOGF(info, "Loaded efficiency histogram for trigger particles from %s", cfgEfficiencyTrigger.value.c_str()); } if (!cfgEfficiencyAssociated.value.empty()) { - if (cfgLocalEfficiency > 0) { + if (cfgGeneral.cfgLocalEfficiency > 0) { TFile* fEfficiencyAssociated = TFile::Open(cfgEfficiencyAssociated.value.c_str(), "READ"); cfg.mEfficiencyAssociated = dynamic_cast(fEfficiencyAssociated->Get("ccdb_object")); } else { @@ -1441,6 +2010,33 @@ struct TwoParticleCorrelationsMpi { cfg.efficiencyLoaded = true; } + void loadAcceptance(const uint64_t timestamp, const int runNumber) + { + if (cfgFillAcceptanceWeights || cfgAcceptance.value.empty()) { + cfg.mAcceptance = nullptr; + cfg.acceptanceLoaded = true; + return; + } + if (cfg.acceptanceLoaded && (!cfgAcceptanceRunByRun || cfg.acceptanceRunNumber == runNumber)) { + return; + } + + std::string path = cfgAcceptance.value; + if (cfgAcceptanceRunByRun) { + if (path.back() != '/') { + path += '/'; + } + path += "RunByRun/"; + } + cfg.mAcceptance = ccdb->getForTimeStamp(path, timestamp); + if (!cfg.mAcceptance || !cfg.mAcceptance->isDataFilled()) { + LOGF(fatal, "Could not load a populated GFW acceptance object from %s for run %d at timestamp %llu", path.c_str(), runNumber, timestamp); + } + cfg.acceptanceLoaded = true; + cfg.acceptanceRunNumber = runNumber; + LOGF(info, "Loaded GFW acceptance object from %s for run %d", path.c_str(), runNumber); + } + double getEfficiencyCorrection(THn* eff, float eta, float pt, float multiplicity, float posZ) { std::array effVars{}; @@ -1451,11 +2047,6 @@ struct TwoParticleCorrelationsMpi { return eff->GetBinContent(effVars.data()); } - float getCorrelationContainerMultiplicity(float multiplicity) const - { - return multiplicity; - } - template void processSameAODT(TCollision const& collision, TTracks const& tracks, const int* trueNMPI = nullptr) { @@ -1478,8 +2069,19 @@ struct TwoParticleCorrelationsMpi { registry.fill(HIST("eventcount_same"), -2); fillQA(collision, multiplicity, tracks); EventSeedEstimate seedEstimate; - fillCorrelations(same, tracks, tracks, multiplicity, collision.posZ(), getMagneticField(bc.timestamp()), 1.0f, &seedEstimate); + std::vector pendingTriggerFills; + std::vector pendingPairFills; + if (cfgUserAxis == EventSeedAxis) { + pendingTriggerFills.reserve(tracks.size()); + pendingPairFills.reserve(tracks.size() * tracks.size()); + } + fillCorrelations(same, tracks, tracks, multiplicity, collision.posZ(), getMagneticField(bc.timestamp()), 1.0f, &seedEstimate, + cfgUserAxis == EventSeedAxis ? &pendingTriggerFills : nullptr, + cfgUserAxis == EventSeedAxis ? &pendingPairFills : nullptr); finalizeEventSeedEstimate(seedEstimate); + if (cfgUserAxis == EventSeedAxis) { + flushSeedAxisFills(same, pendingTriggerFills, pendingPairFills, seedEstimate.nuncSeeds()); + } fillEventSeedEstimatorQA(multiplicity, seedEstimate); if (trueNMPI) { fillMCValidation(multiplicity, seedEstimate, *trueNMPI); @@ -1497,6 +2099,12 @@ struct TwoParticleCorrelationsMpi { soa::Filtered const& mcParticles, soa::SmallGroups const& collisions) { + if (cfgFillAcceptanceWeights) { + return; + } + if (cfgUserAxis == NMPIAxis && mcCollision.nMPI() < 0) { + return; + } if (!cfgNuncSeedsTemplate.value.empty()) { for (const auto& collision : collisions) { loadCcdbYieldTemplates(collision.timestamp()); @@ -1505,10 +2113,45 @@ struct TwoParticleCorrelationsMpi { } const auto generatedMultiplicity = mcCollision.multiplicity(); + const double trueNMPIUserAxisValue = cfgUserAxis == NMPIAxis + ? getTrueNMPIUserAxisValue(generatedMultiplicity, mcCollision.nMPI()) + : -1.0; + if (cfgUserAxis == NMPIAxis) { + fGFW->Clear(); + fFCptGen->clearVector(); + for (const auto& mcParticle : mcParticles) { + if (!mcParticle.isPhysicalPrimary()) { + continue; + } + const int sign = getParticleSign(mcParticle); + if (sign == 0 || (cfgGeneral.cfgAssociatedCharge != 0 && cfgGeneral.cfgAssociatedCharge * sign < 0)) { + continue; + } + if (!cfgMcTriggerPDGs->empty() && + std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), mcParticle.pdgCode()) != cfgMcTriggerPDGs->end()) { + continue; + } + fillPtSums(mcParticle, generatedMultiplicity, mcCollision.posZ()); + fillGFW(mcParticle, generatedMultiplicity, mcCollision.posZ()); + } + fillOutputContainers(generatedMultiplicity, fRndm->Rndm(), getTrueNMPIClass(generatedMultiplicity, mcCollision.nMPI())); + } fillContainerEvent(same, generatedMultiplicity, CorrelationContainer::kCFStepAll); EventSeedEstimate seedEstimate; - fillCorrelations(same, mcParticles, mcParticles, generatedMultiplicity, mcCollision.posZ(), 0, 1.0f, &seedEstimate); + std::vector pendingTriggerFills; + std::vector pendingPairFills; + if (cfgUserAxis == EventSeedAxis) { + pendingTriggerFills.reserve(mcParticles.size()); + pendingPairFills.reserve(mcParticles.size() * mcParticles.size()); + } + fillCorrelations(same, mcParticles, mcParticles, generatedMultiplicity, mcCollision.posZ(), 0, 1.0f, &seedEstimate, + cfgUserAxis == EventSeedAxis ? &pendingTriggerFills : nullptr, + cfgUserAxis == EventSeedAxis ? &pendingPairFills : nullptr, + trueNMPIUserAxisValue); finalizeEventSeedEstimate(seedEstimate); + if (cfgUserAxis == EventSeedAxis) { + flushSeedAxisFills(same, pendingTriggerFills, pendingPairFills, seedEstimate.nuncSeeds()); + } fillGeneratedMCValidation(generatedMultiplicity, seedEstimate, mcCollision.nMPI()); } PROCESS_SWITCH(TwoParticleCorrelationsMpi, processSameGenMC, "Process generated MC events from derived data and validate against the stored HepMC N MPI", false); @@ -1516,22 +2159,38 @@ struct TwoParticleCorrelationsMpi { template void processSameDerivedT(CollType const& collision, TTracks1 const& tracks1, TTracks2 const& tracks2, const int* trueNMPI = nullptr) { - using BinningTypeDerived = ColumnBinningPolicy; - BinningTypeDerived configurableBinningDerived{{axisVertex, axisMultiplicity}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1. + auto getMultiplicity = [](const auto& col) { + return getAnalysisMultiplicity(col); + }; + using BinningTypeDerived = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getMultiplicity)>; + BinningTypeDerived configurableBinningDerived{{getMultiplicity}, {axisVertex, axisMultiplicity}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1. + const auto multiplicity = getMultiplicity(collision); if (cfgVerbosity > 0) { - LOGF(info, "processSameDerivedT: Tracks for collision: %d/%d | Vertex: %.1f | Multiplicity/Centrality: %.1f", tracks1.size(), tracks2.size(), collision.posZ(), collision.multiplicity()); + LOGF(info, "processSameDerivedT: Tracks for collision: %d/%d | Vertex: %.1f | Multiplicity/Centrality: %.1f", tracks1.size(), tracks2.size(), collision.posZ(), multiplicity); + } + if (cfgFillAcceptanceWeights) { + for (const auto& track : tracks2) { + fillAcceptanceWeights(track, collision.posZ(), collision.runNumber()); + } + return; } loadEfficiency(collision.timestamp()); + loadAcceptance(collision.timestamp(), collision.runNumber()); loadCcdbYieldTemplates(collision.timestamp()); - const auto multiplicity = collision.multiplicity(); - int field = 0; - if (cfgTwoTrackCut > 0) { + if (cfgGeneral.cfgTwoTrackCut > 0) { field = getMagneticField(collision.timestamp()); } - int bin = configurableBinningDerived.getBin({collision.posZ(), collision.multiplicity()}); + fGFW->Clear(); + fFCpt->clearVector(); + for (const auto& track : tracks2) { + fillPtSums(track, multiplicity, collision.posZ()); + fillGFW(track, multiplicity, collision.posZ()); + } + + int bin = configurableBinningDerived.getBin(std::tuple(collision.posZ(), multiplicity)); registry.fill(HIST("eventcount_same"), bin); registry.fill(HIST("trackcount_same"), bin, tracks1.size()); if constexpr (std::experimental::is_detected::value) { @@ -1541,9 +2200,40 @@ struct TwoParticleCorrelationsMpi { } const bool hasEfficiency = (cfg.mEfficiencyAssociated != nullptr || cfg.mEfficiencyTrigger != nullptr); - const bool fillReco = !(cfgDropStepRECO && hasEfficiency); + const bool fillReco = !(cfgGeneral.cfgDropStepRECO && hasEfficiency); EventSeedEstimate seedEstimate; + if (cfgUserAxis == EventSeedAxis) { + std::vector pendingTriggerFills; + std::vector pendingPairFills; + pendingTriggerFills.reserve(tracks1.size()); + pendingPairFills.reserve(tracks1.size() * tracks2.size()); + + if (fillReco) { + fillContainerEvent(same, multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelations(same, tracks1, tracks2, multiplicity, collision.posZ(), field, 1.0f, &seedEstimate, &pendingTriggerFills, &pendingPairFills); + finalizeEventSeedEstimate(seedEstimate); + flushSeedAxisFills(same, pendingTriggerFills, pendingPairFills, seedEstimate.nuncSeeds()); + } else if (hasEfficiency) { + fillContainerEvent(same, multiplicity, CorrelationContainer::kCFStepCorrected); + fillCorrelations(same, tracks1, tracks2, multiplicity, collision.posZ(), field, 1.0f, &seedEstimate, &pendingTriggerFills, &pendingPairFills); + finalizeEventSeedEstimate(seedEstimate); + flushSeedAxisFills(same, pendingTriggerFills, pendingPairFills, seedEstimate.nuncSeeds()); + } + + if (fillReco && hasEfficiency) { + fillContainerEvent(same, multiplicity, CorrelationContainer::kCFStepCorrected); + fillCorrelations(same, tracks1, tracks2, multiplicity, collision.posZ(), field, 1.0f, nullptr, nullptr, nullptr, getEventSeedUserAxisValue(multiplicity, seedEstimate.nuncSeeds())); + } + const auto seedClass = getEventSeedClass(multiplicity, seedEstimate.nuncSeeds()); + fillOutputContainers(multiplicity, fRndm->Rndm(), seedClass); + fillEventSeedEstimatorQA(multiplicity, seedEstimate); + if (trueNMPI) { + fillMCValidation(multiplicity, seedEstimate, *trueNMPI); + } + return; + } + if (fillReco) { fillContainerEvent(same, multiplicity, CorrelationContainer::kCFStepReconstructed); fillCorrelations(same, tracks1, tracks2, multiplicity, collision.posZ(), field, 1.0f, &seedEstimate); @@ -1553,19 +2243,26 @@ struct TwoParticleCorrelationsMpi { fillCorrelations(same, tracks1, tracks2, multiplicity, collision.posZ(), field, 1.0f, fillReco ? nullptr : &seedEstimate); } finalizeEventSeedEstimate(seedEstimate); + fillOutputContainers(multiplicity, fRndm->Rndm()); fillEventSeedEstimatorQA(multiplicity, seedEstimate); if (trueNMPI) { fillMCValidation(multiplicity, seedEstimate, *trueNMPI); } } - void processSameDerived(DerivedCollisions::iterator const& collision, soa::Filtered const& tracks) + void processSameDerived(DerivedCollisions::iterator const& collision, DerivedTracks const& tracks) { processSameDerivedT(collision, tracks, tracks); } PROCESS_SWITCH(TwoParticleCorrelationsMpi, processSameDerived, "Process same event on derived data", false); - void processSameDerivedMultSet(soa::Filtered>::iterator const& collision, soa::Filtered const& tracks) + void processSameDerivedCorrected(DerivedCollisionsCorrected::iterator const& collision, DerivedTracks const& tracks) + { + processSameDerivedT(collision, tracks, tracks); + } + PROCESS_SWITCH(TwoParticleCorrelationsMpi, processSameDerivedCorrected, "Process same event on derived data with corrected multiplicity", false); + + void processSameDerivedMultSet(DerivedCollisionsMultSet::iterator const& collision, DerivedTracks const& tracks) { if (!passOutlier(collision)) { return; @@ -1574,6 +2271,15 @@ struct TwoParticleCorrelationsMpi { } PROCESS_SWITCH(TwoParticleCorrelationsMpi, processSameDerivedMultSet, "Process same event on derived data with multiplicity sets", false); + void processSameDerivedMultSetCorrected(DerivedCollisionsMultSetCorrected::iterator const& collision, DerivedTracks const& tracks) + { + if (!passOutlier(collision)) { + return; + } + processSameDerivedT(collision, tracks, tracks); + } + PROCESS_SWITCH(TwoParticleCorrelationsMpi, processSameDerivedMultSetCorrected, "Process same event on derived data with corrected multiplicity and multiplicity sets", false); + using BinningTypeAOD = ColumnBinningPolicy; void processMixedAOD(AodCollisions const& collisions, AodTracks const& tracks, aod::BCsWithTimestamps const&) { @@ -1585,6 +2291,7 @@ struct TwoParticleCorrelationsMpi { SameKindPair pairs{configurableBinning, cfgNumMixedEvents, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip int skipID = -1; + double triggerEventSeed = -1.0; for (auto it = pairs.begin(); it != pairs.end(); it++) { auto& [collision1, tracks1, collision2, tracks2] = *it; int bin = configurableBinning.getBin({collision1.posZ(), collision1.centRun2V0M()}); @@ -1601,6 +2308,11 @@ struct TwoParticleCorrelationsMpi { skipID = collision1.globalIndex(); continue; } + if (cfgUserAxis == EventSeedAxis) { + auto bc = collision1.bc_as(); + loadCcdbYieldTemplates(bc.timestamp()); + triggerEventSeed = getEventSeedUserAxisValue(collision1.centRun2V0M(), estimateEventSeedWithoutFilling(mixed, tracks1, collision1.centRun2V0M(), collision1.posZ(), getMagneticField(bc.timestamp()))); + } } if (!collision2.alias_bit(kINT7) || !collision2.sel7()) { continue; @@ -1612,7 +2324,7 @@ struct TwoParticleCorrelationsMpi { // LOGF(info, "Tracks: %d and %d entries", tracks1.size(), tracks2.size()); - fillCorrelations(mixed, tracks1, tracks2, collision1.centRun2V0M(), collision1.posZ(), getMagneticField(bc.timestamp()), 1.0f / it.currentWindowNeighbours()); + fillCorrelations(mixed, tracks1, tracks2, collision1.centRun2V0M(), collision1.posZ(), getMagneticField(bc.timestamp()), 1.0f / it.currentWindowNeighbours(), nullptr, nullptr, nullptr, triggerEventSeed); } } PROCESS_SWITCH(TwoParticleCorrelationsMpi, processMixedAOD, "Process mixed events on AOD", false); @@ -1621,7 +2333,7 @@ struct TwoParticleCorrelationsMpi { void processMixedDerivedT(CollType const& collisions, TrackTypes&&... tracks) { auto getMultiplicity = - [this](auto& col) { + [this](const auto& col) { if constexpr (std::experimental::is_detected::value) { if (!passOutlier(col)) { return -1.0f; @@ -1629,7 +2341,7 @@ struct TwoParticleCorrelationsMpi { } else { (void)this; // fix compile error on unused 'this' capture } - return col.multiplicity(); + return getAnalysisMultiplicity(col); }; using BinningTypeDerived = FlexibleBinningPolicy, aod::collision::PosZ, decltype(getMultiplicity)>; @@ -1640,30 +2352,40 @@ struct TwoParticleCorrelationsMpi { using TB = std::tuple_element - 1, decltype(tracksTuple)>::type; Pair pairs{configurableBinningDerived, cfgNumMixedEvents, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip + double triggerEventSeed = -1.0; for (auto it = pairs.begin(); it != pairs.end(); it++) { auto& [collision1, tracks1, collision2, tracks2] = *it; float multiplicity = getMultiplicity(collision1); int bin = configurableBinningDerived.getBin(std::tuple(collision1.posZ(), multiplicity)); float eventWeight = 1.0f / it.currentWindowNeighbours(); int field = 0; - if (cfgTwoTrackCut > 0) { + if (cfgGeneral.cfgTwoTrackCut > 0) { field = getMagneticField(collision1.timestamp()); } if (cfgVerbosity > 0) { - LOGF(info, "processMixedDerived: Mixed collisions bin: %d pair: [%d, %d] %d (%.3f, %.3f), %d (%.3f, %.3f)", bin, it.isNewWindow(), it.currentWindowNeighbours(), collision1.globalIndex(), collision1.posZ(), collision1.multiplicity(), collision2.globalIndex(), collision2.posZ(), collision2.multiplicity()); + LOGF(info, "processMixedDerived: Mixed collisions bin: %d pair: [%d, %d] %d (%.3f, %.3f), %d (%.3f, %.3f)", bin, it.isNewWindow(), it.currentWindowNeighbours(), collision1.globalIndex(), collision1.posZ(), multiplicity, collision2.globalIndex(), collision2.posZ(), getAnalysisMultiplicity(collision2)); } bool hasEfficiencyMixed = (cfg.mEfficiencyAssociated != nullptr || cfg.mEfficiencyTrigger != nullptr); - bool fillRecoMixed = !(cfgDropStepRECO && hasEfficiencyMixed); + bool fillRecoMixed = !(cfgGeneral.cfgDropStepRECO && hasEfficiencyMixed); if (it.isNewWindow()) { loadEfficiency(collision1.timestamp()); hasEfficiencyMixed = (cfg.mEfficiencyAssociated != nullptr || cfg.mEfficiencyTrigger != nullptr); - fillRecoMixed = !(cfgDropStepRECO && hasEfficiencyMixed); + fillRecoMixed = !(cfgGeneral.cfgDropStepRECO && hasEfficiencyMixed); + + if (cfgUserAxis == EventSeedAxis) { + loadCcdbYieldTemplates(collision1.timestamp()); + if constexpr (std::is_same_v, std::remove_cvref_t>) { + triggerEventSeed = getEventSeedUserAxisValue(multiplicity, estimateEventSeedWithoutFilling(mixed, tracks1, multiplicity, collision1.posZ(), field)); + } else { + LOGF(fatal, "Event-seed user axis for mixed events requires the same trigger and associated track table so the trigger event can be estimated independently"); + } + } if (fillRecoMixed) { - fillContainerEvent(mixed, collision1.multiplicity(), CorrelationContainer::kCFStepReconstructed); + fillContainerEvent(mixed, multiplicity, CorrelationContainer::kCFStepReconstructed); } } @@ -1672,14 +2394,14 @@ struct TwoParticleCorrelationsMpi { registry.fill(HIST("eventcount_mixed"), bin); registry.fill(HIST("trackcount_mixed"), bin, tracks1.size(), tracks2.size()); if (fillRecoMixed) { - fillCorrelations(mixed, tracks1, tracks2, collision1.multiplicity(), collision1.posZ(), field, eventWeight); + fillCorrelations(mixed, tracks1, tracks2, multiplicity, collision1.posZ(), field, eventWeight, nullptr, nullptr, nullptr, triggerEventSeed); } if (hasEfficiencyMixed) { if (it.isNewWindow()) { - fillContainerEvent(mixed, collision1.multiplicity(), CorrelationContainer::kCFStepCorrected); + fillContainerEvent(mixed, multiplicity, CorrelationContainer::kCFStepCorrected); } - fillCorrelations(mixed, tracks1, tracks2, collision1.multiplicity(), collision1.posZ(), field, eventWeight); + fillCorrelations(mixed, tracks1, tracks2, multiplicity, collision1.posZ(), field, eventWeight, nullptr, nullptr, nullptr, triggerEventSeed); } } } @@ -1690,93 +2412,39 @@ struct TwoParticleCorrelationsMpi { } PROCESS_SWITCH(TwoParticleCorrelationsMpi, processMixedDerived, "Process mixed events on derived data", false); - void processMixedDerivedMultSet(soa::Filtered> const& collisions, DerivedTracks const& tracks) + void processMixedDerivedCorrected(DerivedCollisionsCorrected const& collisions, DerivedTracks const& tracks) { processMixedDerivedT(collisions, tracks); } - PROCESS_SWITCH(TwoParticleCorrelationsMpi, processMixedDerivedMultSet, "Process mixed events on derived data with multiplicity sets", false); + PROCESS_SWITCH(TwoParticleCorrelationsMpi, processMixedDerivedCorrected, "Process mixed events on derived data with corrected multiplicity", false); - int getSpecies(int pdgCode) + void processMixedDerivedMultSet(DerivedCollisionsMultSet const& collisions, DerivedTracks const& tracks) { - switch (pdgCode) { - case 211: // pion - case -211: - return 0; - case 321: // Kaon - case -321: - return 1; - case 2212: // proton - case -2212: - return 2; - default: - break; - } - if (std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), pdgCode) != cfgMcTriggerPDGs->end()) { - return 4; - } - // The efficiency histogram is hardcoded to contain 5 species. Anything special will have the 4th slot. - return 3; + processMixedDerivedT(collisions, tracks); } + PROCESS_SWITCH(TwoParticleCorrelationsMpi, processMixedDerivedMultSet, "Process mixed events on derived data with multiplicity sets", false); - // NOTE SmallGroups includes soa::Filtered always - Preslice perCollision = aod::cftrack::cfCollisionId; - void processMCEfficiency(soa::Filtered::iterator const& mcCollision, aod::CFMcParticles const& mcParticles, soa::SmallGroups const& collisions, aod::CFTracksWithLabel const& tracks) + void processMixedDerivedMultSetCorrected(DerivedCollisionsMultSetCorrected const& collisions, DerivedTracks const& tracks) { - if (cfgVerbosity > 0) { - LOGF(info, "MC collision at vtx-z = %f with %d mc particles and %d reconstructed collisions", mcCollision.posZ(), mcParticles.size(), collisions.size()); - } - - auto multiplicity = mcCollision.multiplicity(); - if (cfgCentBinsForMC > 0) { - if (collisions.size() == 0) { - return; - } - for (const auto& collision : collisions) { - multiplicity = collision.multiplicity(); - } - } - // Primaries - for (const auto& mcParticle : mcParticles) { - if (mcParticle.isPhysicalPrimary() && mcParticle.sign() != 0 && !(std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), mcParticle.pdgCode()) != cfgMcTriggerPDGs->end())) { - same->getTrackHistEfficiency()->Fill(CorrelationContainer::MC, mcParticle.eta(), mcParticle.pt(), getSpecies(mcParticle.pdgCode()), multiplicity, mcCollision.posZ()); - } - } - for (const auto& collision : collisions) { - auto groupedTracks = tracks.sliceBy(perCollision, collision.globalIndex()); - if (cfgVerbosity > 0) { - LOGF(info, " Reconstructed collision at vtx-z = %f", collision.posZ()); - LOGF(info, " which has %d tracks", groupedTracks.size()); - } - - for (const auto& track : groupedTracks) { - if (cfgTrackBitMask > 0 && (track.trackType() & (uint8_t)cfgTrackBitMask) != (uint8_t)cfgTrackBitMask) { - continue; - } - if (track.has_cfMCParticle()) { - const auto& mcParticle = track.cfMCParticle(); - if (mcParticle.isPhysicalPrimary()) { - same->getTrackHistEfficiency()->Fill(CorrelationContainer::RecoPrimaries, mcParticle.eta(), mcParticle.pt(), getSpecies(mcParticle.pdgCode()), multiplicity, mcCollision.posZ()); - } - same->getTrackHistEfficiency()->Fill(CorrelationContainer::RecoAll, mcParticle.eta(), mcParticle.pt(), getSpecies(mcParticle.pdgCode()), multiplicity, mcCollision.posZ()); - // LOGF(info, "Filled track %d", track.globalIndex()); - } else { - // fake track - same->getTrackHistEfficiency()->Fill(CorrelationContainer::Fake, track.eta(), track.pt(), 0, multiplicity, mcCollision.posZ()); - } - } - } + processMixedDerivedT(collisions, tracks); } - PROCESS_SWITCH(TwoParticleCorrelationsMpi, processMCEfficiency, "MC: Extract efficiencies", false); + PROCESS_SWITCH(TwoParticleCorrelationsMpi, processMixedDerivedMultSetCorrected, "Process mixed events on derived data with corrected multiplicity and multiplicity sets", false); template void processMCSameDerivedT(McCollision const& mcCollision, Particles1 const& mcParticles1, Particles2 const& mcParticles2, soa::SmallGroups const& collisions) { + if (cfgFillAcceptanceWeights) { + return; + } + if (cfgUserAxis == NMPIAxis && mcCollision.nMPI() < 0) { + return; + } if (cfgVerbosity > 0) { LOGF(info, "processMCSameDerivedT. MC collision: %d, particles1: %d, particles2: %d, collisions: %d", mcCollision.globalIndex(), mcParticles1.size(), mcParticles2.size(), collisions.size()); } auto multiplicity = mcCollision.multiplicity(); - if (cfgCentBinsForMC > 0) { + if (cfgGeneral.cfgCentBinsForMC > 0) { if (collisions.size() == 0) { return; } @@ -1784,8 +2452,11 @@ struct TwoParticleCorrelationsMpi { multiplicity = collision.multiplicity(); } } + const double trueNMPIUserAxisValue = cfgUserAxis == NMPIAxis + ? getTrueNMPIUserAxisValue(multiplicity, mcCollision.nMPI()) + : -1.0; - if (!(doprocessMCSameDerived || doprocessSameDerived || doprocessSameDerivedMultSet)) { + if (!(doprocessMCSameDerived || doprocessSameDerived || doprocessSameDerivedCorrected || doprocessSameDerivedMultSet || doprocessSameDerivedMultSetCorrected)) { if constexpr (std::experimental::is_detected::value) { fillQA(mcCollision, multiplicity, mcCollision.posZ(), mcParticles1, mcParticles2); } else { @@ -1793,21 +2464,44 @@ struct TwoParticleCorrelationsMpi { } } + fGFW->Clear(); + fFCptGen->clearVector(); + for (const auto& mcParticle : mcParticles2) { + if (!mcParticle.isPhysicalPrimary()) { + continue; + } + const int sign = getParticleSign(mcParticle); + if (sign == 0 || (cfgGeneral.cfgAssociatedCharge != 0 && cfgGeneral.cfgAssociatedCharge * sign < 0)) { + continue; + } + if (!cfgMcTriggerPDGs->empty() && std::find(cfgMcTriggerPDGs->begin(), cfgMcTriggerPDGs->end(), mcParticle.pdgCode()) != cfgMcTriggerPDGs->end()) { + continue; + } + fillPtSums(mcParticle, multiplicity, mcCollision.posZ()); + fillGFW(mcParticle, multiplicity, mcCollision.posZ()); + } + const SeedClass nMPIClass = cfgUserAxis == NMPIAxis ? getTrueNMPIClass(multiplicity, mcCollision.nMPI()) : InvalidSeedClass; + fillOutputContainers(multiplicity, fRndm->Rndm(), nMPIClass); + fillContainerEvent(same, multiplicity, CorrelationContainer::kCFStepAll); - fillCorrelations(same, mcParticles1, mcParticles2, multiplicity, mcCollision.posZ(), 0, 1.0f); + fillCorrelations(same, mcParticles1, mcParticles2, multiplicity, mcCollision.posZ(), 0, 1.0f, + nullptr, nullptr, nullptr, trueNMPIUserAxisValue); if (collisions.size() == 0) { return; } fillContainerEvent(same, multiplicity, CorrelationContainer::kCFStepVertex); - fillCorrelations(same, mcParticles1, mcParticles2, multiplicity, mcCollision.posZ(), 0, 1.0f); + fillCorrelations(same, mcParticles1, mcParticles2, multiplicity, mcCollision.posZ(), 0, 1.0f, + nullptr, nullptr, nullptr, trueNMPIUserAxisValue); fillContainerEvent(same, multiplicity, CorrelationContainer::kCFStepTrackedOnlyPrim); - fillCorrelations(same, mcParticles1, mcParticles2, multiplicity, mcCollision.posZ(), 0, 1.0f); + fillCorrelations(same, mcParticles1, mcParticles2, multiplicity, mcCollision.posZ(), 0, 1.0f, + nullptr, nullptr, nullptr, trueNMPIUserAxisValue); fillContainerEvent(same, multiplicity, CorrelationContainer::kCFStepTracked); - fillCorrelations(same, mcParticles1, mcParticles2, multiplicity, mcCollision.posZ(), 0, 1.0f); + fillCorrelations(same, mcParticles1, mcParticles2, multiplicity, mcCollision.posZ(), 0, 1.0f, + nullptr, nullptr, nullptr, trueNMPIUserAxisValue); // kCFStepReconstructed and kCFStepCorrected are filled below for every // reconstructed collision associated with this MC collision. @@ -1818,6 +2512,9 @@ struct TwoParticleCorrelationsMpi { void processMCSameDerived(soa::Filtered::iterator const& mcCollision, soa::Filtered const& mcParticles, soa::SmallGroups const& collisions, soa::Filtered const& tracks) // TODO. For mixed no need to check the daughters since the events are different { processMCSameDerivedT(mcCollision, mcParticles, mcParticles, collisions); + if (cfgUserAxis == NMPIAxis) { + return; + } if (eventSeedEstimatorEnabled && collisions.size() == 0) { registry.fill(HIST("mcValidation/status"), 0.0); } @@ -1833,7 +2530,7 @@ struct TwoParticleCorrelationsMpi { template void processMCMixedDerivedT(soa::Filtered const& mcCollisions, soa::Filtered const& collisions, ParticleTypes&&... particles) { - bool useMCMultiplicity = (cfgCentBinsForMC == 0); + bool useMCMultiplicity = (cfgGeneral.cfgCentBinsForMC == 0); auto getMultiplicity = [&collisions, &useMCMultiplicity, this](auto& col) { if (useMCMultiplicity) { diff --git a/PWGDQ/Core/CutsLibrary.cxx b/PWGDQ/Core/CutsLibrary.cxx index 187a1ec1700..56b283503f8 100644 --- a/PWGDQ/Core/CutsLibrary.cxx +++ b/PWGDQ/Core/CutsLibrary.cxx @@ -541,13 +541,6 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } - if (nameStr == "JpsiPWGSkimmedCuts1") { // please do not remove or modify, this is used for the common Skimmed tree production, (Xiaozhi Bai) - cut->AddCut(GetAnalysisCut("jpsiKineSkimmed")); - cut->AddCut(GetAnalysisCut("electronTrackQualitySkimmed")); - cut->AddCut(GetAnalysisCut("electronPIDLooseSkimmed")); - return cut; - } - if (nameStr == "JpsiPWGSkimmedCuts2") { cut->AddCut(GetAnalysisCut("jpsiKineSkimmed")); cut->AddCut(GetAnalysisCut("electronTrackQualitySkimmed")); @@ -3110,6 +3103,24 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (nameStr == "muonLowPt1p5_MchMidmatching") { + cut->AddCut(GetAnalysisCut("muonLowPt1p5")); + cut->AddCut(GetAnalysisCut("matchedMchMid")); + return cut; + } + + if (nameStr == "muonLowPt1p7_MchMidmatching") { + cut->AddCut(GetAnalysisCut("muonLowPt1p7")); + cut->AddCut(GetAnalysisCut("matchedMchMid")); + return cut; + } + + if (nameStr == "muonLowPt6_MchMidmatching") { + cut->AddCut(GetAnalysisCut("muonLowPt6")); + cut->AddCut(GetAnalysisCut("matchedMchMid")); + return cut; + } + if (nameStr == "muonLowPt10SigmaPDCA") { cut->AddCut(GetAnalysisCut("muonLowPt")); cut->AddCut(GetAnalysisCut("muonQualityCuts10SigmaPDCA")); @@ -3174,6 +3185,18 @@ AnalysisCompositeCut* o2::aod::dqcuts::GetCompositeCut(const char* cutName) return cut; } + if (nameStr == "muonLowPt1p5") { + cut->AddCut(GetAnalysisCut("muonLowPt1p5")); + cut->AddCut(GetAnalysisCut("muonQualityCuts")); + return cut; + } + + if (nameStr == "muonLowPt1p7") { + cut->AddCut(GetAnalysisCut("muonLowPt1p7")); + cut->AddCut(GetAnalysisCut("muonQualityCuts")); + return cut; + } + if (nameStr == "muonLowPtMatchingOnly") { cut->AddCut(GetAnalysisCut("muonLowPt")); cut->AddCut(GetAnalysisCut("muonQualityCutsMatchingOnly")); @@ -4278,7 +4301,7 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } - if (nameStr == "eventStandardSel8PbPbQualityTightTrackOccupancyCollInTime") { + if (nameStr == "eventStandardSel8PbPbQualityTightTrackOccupancyCollInTime2") { cut->AddCut(VarManager::kVtxZ, -10.0, 10.0); cut->AddCut(VarManager::kIsSel8, 0.5, 1.5); cut->AddCut(VarManager::kIsNoTFBorder, 0.5, 1.5); @@ -4672,12 +4695,6 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } - if (nameStr == "jpsiKineSkimmed") { - cut->AddCut(VarManager::kPt, 0.7, 1000.0); - cut->AddCut(VarManager::kEta, -0.9, 0.9); - return cut; - } - if (nameStr == "lmeePrefilterKine") { cut->AddCut(VarManager::kPt, 0., 20.0); cut->AddCut(VarManager::kEta, -1.2, 1.2); @@ -5471,7 +5488,7 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) for (int i = 1; i <= 8; i++) { // o2-linter: disable=magic-number (number of cuts) if (nameStr == Form("dalitzLeg%d", i)) { - cut->AddCut(VarManager::kIsDalitzLeg + i - 1, 0.5, 1.5); + cut->AddCut(VarManager::kIsDalitzLeg + i - 1, -0.5, 0.5, true); return cut; } @@ -5482,17 +5499,17 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) } if (nameStr == "pidcalib_ele") { - cut->AddCut(VarManager::kIsLegFromGamma, 0.5, 1.5, false); + cut->AddCut(VarManager::kIsLegFromGamma, -0.5, 0.5, true); return cut; } if (nameStr == "pidcalib_pion") { - cut->AddCut(VarManager::kIsLegFromK0S, 0.5, 1.5, false); + cut->AddCut(VarManager::kIsLegFromK0S, -0.5, 0.5, true); return cut; } if (nameStr == "pidcalib_proton") { - cut->AddCut(VarManager::kIsProtonFromLambdaAndAntiLambda, 0.5, 1.5, false); + cut->AddCut(VarManager::kIsProtonFromLambdaAndAntiLambda, -0.5, 0.5, true); return cut; } @@ -6663,6 +6680,16 @@ AnalysisCut* o2::aod::dqcuts::GetAnalysisCut(const char* cutName) return cut; } + if (nameStr == "muonLowPt1p5") { + cut->AddCut(VarManager::kPt, 1.5, 1000.0); + return cut; + } + + if (nameStr == "muonLowPt1p7") { + cut->AddCut(VarManager::kPt, 1.7, 1000.0); + return cut; + } + if (nameStr == "muonHighPt") { cut->AddCut(VarManager::kPt, 3.0, 1000.0); return cut; @@ -7937,9 +7964,7 @@ o2::aod::dqmlcuts::BdtScoreConfig o2::aod::dqmlcuts::GetBdtScoreCutsAndConfigFro } } - if (!cutDirsFilled) { - cutDirsFilled = true; - } + cutDirsFilled = true; centBins.emplace_back(centMin, centMax); ptBins.emplace_back(ptMin, ptMax); @@ -7988,9 +8013,10 @@ o2::aod::dqmlcuts::BdtScoreConfig o2::aod::dqmlcuts::GetBdtScoreCutsAndConfigFro binaryCfg.cutsMl = makeLabeledCutsMl(cutsMl, labelsFlatBin, labelsClass); return binaryCfg; + } - // MultiClass - } else if (typeStr == "MultiClass") { + // MultiClass + if (typeStr == "MultiClass") { dqmlcuts::MultiClassBdtScoreConfig multiCfg; multiCfg.inputFeatures = namesInputFeatures; multiCfg.onnxFiles = onnxFileNames; diff --git a/PWGDQ/Core/HistogramsLibrary.cxx b/PWGDQ/Core/HistogramsLibrary.cxx index 923df279ea3..662a89f514e 100644 --- a/PWGDQ/Core/HistogramsLibrary.cxx +++ b/PWGDQ/Core/HistogramsLibrary.cxx @@ -110,6 +110,14 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h hm->AddHistogram(histClass, "CentFT0C_MultTPC", "CentFT0C vs MultTPC", false, 100, 0., 100., VarManager::kCentFT0C, 100, 0., 50000., VarManager::kMultTPC); hm->AddHistogram(histClass, "CentFT0C_Run", "Cent FT0C", true, 1, -0.5, 0.5, VarManager::kRunNo, 100, 0., 100., VarManager::kCentFT0C, 1, 0, 1, VarManager::kNothing, "", "", "", VarManager::kNothing, VarManager::kNothing, false, true); } + if (subGroupStr.Contains("alice3multcent")) { + hm->AddHistogram(histClass, "Cent", "Cent", false, 100, 0.0, 100.0, VarManager::kCent); + hm->AddHistogram(histClass, "MultPV", "MultPV", false, 100, 0.0, 10000.0, VarManager::kMultPV); + hm->AddHistogram(histClass, "MultPVeta1", "MultPVeta1", false, 100, 0.0, 10000.0, VarManager::kMultPVeta1); + hm->AddHistogram(histClass, "MultPVetaHalf", "MultPVetaHalf", false, 100, 0.0, 10000.0, VarManager::kMultPVetaHalf); + hm->AddHistogram(histClass, "MultGlobal", "MultGlobal", false, 100, 0.0, 10000.0, VarManager::kMultGlobalTracks); + hm->AddHistogram(histClass, "MultGlobalPV", "MultGlobalPV", false, 100, 0.0, 10000.0, VarManager::kMultGlobalTracksPV); + } if (subGroupStr.Contains("randomplane")) { hm->AddHistogram(histClass, "random plane angle", "random Psi", false, 100, -TMath::Pi() / 2, TMath::Pi() / 2, VarManager::kRandomPsi2); } @@ -1395,6 +1403,17 @@ void o2::aod::dqhistograms::DefineHistograms(HistogramManager* hm, const char* h } hm->AddHistogram(histClass, "Mass_PtLong", "", false, 500, alice3MassBins.data(), VarManager::kMass, 20, pTBins.data(), VarManager::kPt); } + if (subGroupStr.Contains("alice3pbpb")) { + hm->AddHistogram(histClass, "Mass_Cent", "", false, 125, 0.0, 5.0, VarManager::kMass, 20, 0.0, 100.0, VarManager::kCent); + hm->AddHistogram(histClass, "Pt_CentFT0C", "", false, 100, 0.0, 10.0, VarManager::kPt, 20, 0.0, 100.0, VarManager::kCent); + hm->AddHistogram(histClass, "Mass_Pt_CentFT0C", "", false, 75, 1.5, 4.5, VarManager::kMass, 20, 0.0, 10.0, VarManager::kPt, 10, 0.0, 100.0, VarManager::kCent); + } + if (subGroupStr.Contains("alice3mult")) { + hm->AddHistogram(histClass, "Mass_Pt_MultGlobal", "Mass vs pT vs multGlobal", false, 200, 0.0, 5.0, VarManager::kMass, 40, 0.0, 40.0, VarManager::kPt, 100, 0.0, 10000.0, VarManager::kMultGlobalTracks); + hm->AddHistogram(histClass, "Mass_MultGlobal", "Mass vs Global Tracks", false, 200, 0.0, 5.0, VarManager::kMass, 100, 0, 10000.0, VarManager::kMultGlobalTracks); + hm->AddHistogram(histClass, "Mass_MultGlobal_VtxZ", "Mass vs Global Tracks vs VtxZ", false, 200, 2.0, 5.0, VarManager::kMass, 100, 0, 10000.0, VarManager::kMultGlobalTracks, 20, -10.0, 10.0, VarManager::kVtxZ); + hm->AddHistogram(histClass, "VtxZ_MultGlobal", "VtxZ vs VtxNcontribReal", false, 240, -12.0, 12.0, VarManager::kVtxZ, 100, 0, 10000.0, VarManager::kMultGlobalTracks); + } if (subGroupStr.Contains("dielectron-polarization-he-pbpb")) { std::array varsHEpbpb = {VarManager::kMass, VarManager::kPt, VarManager::kCentFT0C, VarManager::kCosThetaHE, VarManager::kPhiHE}; std::array binspT = {100, 30, 10, 10, 10}; diff --git a/PWGDQ/Core/MCProng.cxx b/PWGDQ/Core/MCProng.cxx index ee95463839d..611db4bcd5c 100644 --- a/PWGDQ/Core/MCProng.cxx +++ b/PWGDQ/Core/MCProng.cxx @@ -92,19 +92,19 @@ MCProng::MCProng(int n, int m) : fNGenerations(n), } //________________________________________________________________________________________________________________ -MCProng::MCProng(int n, const std::vector pdgs, const std::vector checkBothCharges, const std::vector excludePDG, - const std::vector sourceBits, const std::vector excludeSource, - const std::vector useANDonSourceBitMap, bool checkGenerationsInTime, - const std::vector checkIfPDGInHistory, const std::vector excludePDGInHistory) : fNGenerations(n), - fPDGcodes(pdgs), - fCheckBothCharges(checkBothCharges), - fExcludePDG(excludePDG), - fSourceBits(sourceBits), - fExcludeSource(excludeSource), - fUseANDonSourceBitMap(useANDonSourceBitMap), - fCheckGenerationsInTime(checkGenerationsInTime), - fPDGInHistory(checkIfPDGInHistory), - fExcludePDGInHistory(excludePDGInHistory) {} +MCProng::MCProng(int n, const std::vector& pdgs, const std::vector& checkBothCharges, const std::vector& excludePDG, + const std::vector& sourceBits, const std::vector& excludeSource, + const std::vector& useANDonSourceBitMap, bool checkGenerationsInTime, + const std::vector& checkIfPDGInHistory, const std::vector& excludePDGInHistory) : fNGenerations(n), + fPDGcodes(pdgs), + fCheckBothCharges(checkBothCharges), + fExcludePDG(excludePDG), + fSourceBits(sourceBits), + fExcludeSource(excludeSource), + fUseANDonSourceBitMap(useANDonSourceBitMap), + fCheckGenerationsInTime(checkGenerationsInTime), + fPDGInHistory(checkIfPDGInHistory), + fExcludePDGInHistory(excludePDGInHistory) {} //________________________________________________________________________________________________________________ void MCProng::SetPDGcode(int generation, int code, bool checkBothCharges /*= false*/, bool exclude /*= false*/) diff --git a/PWGDQ/Core/MCProng.h b/PWGDQ/Core/MCProng.h index 7d795834855..5db3b8feb1a 100644 --- a/PWGDQ/Core/MCProng.h +++ b/PWGDQ/Core/MCProng.h @@ -89,9 +89,9 @@ class MCProng MCProng(); explicit MCProng(int n); MCProng(int n, int m); - MCProng(int n, std::vector pdgs, std::vector checkBothCharges, std::vector excludePDG, - std::vector sourceBits, std::vector excludeSource, std::vector useANDonSourceBitMap, - bool checkGenerationsInTime = false, std::vector checkIfPDGInHistory = {}, std::vector excludePDGInHistory = {}); + MCProng(int n, const std::vector& pdgs, const std::vector& checkBothCharges, const std::vector& excludePDG, + const std::vector& sourceBits, const std::vector& excludeSource, const std::vector& useANDonSourceBitMap, + bool checkGenerationsInTime = false, const std::vector& checkIfPDGInHistory = {}, const std::vector& excludePDGInHistory = {}); MCProng(const MCProng& c) = default; virtual ~MCProng() = default; diff --git a/PWGDQ/Core/MCSignal.cxx b/PWGDQ/Core/MCSignal.cxx index 20e510b0662..2068d426a70 100644 --- a/PWGDQ/Core/MCSignal.cxx +++ b/PWGDQ/Core/MCSignal.cxx @@ -19,6 +19,7 @@ #include #include +#include #include using std::cout; @@ -52,28 +53,28 @@ MCSignal::MCSignal(int nProngs, const char* name /*= ""*/, const char* title /*= } //________________________________________________________________________________________________ -MCSignal::MCSignal(const char* name, const char* title, std::vector prongs, std::vector commonAncestors, bool excludeCommonAncestor) : TNamed(name, title), - fProngs(prongs), - fNProngs(prongs.size()), - fCommonAncestorIdxs(commonAncestors), - fExcludeCommonAncestor(excludeCommonAncestor), - fDecayChannelIsExclusive(false), - fDecayChannelIsNotExclusive(false), - fNAncestorDirectProngs(0), - fTempAncestorLabel(-1) +MCSignal::MCSignal(const char* name, const char* title, const std::vector& prongs, std::vector commonAncestors, bool excludeCommonAncestor) : TNamed(name, title), + fProngs(prongs), + fNProngs(prongs.size()), + fCommonAncestorIdxs(std::move(commonAncestors)), + fExcludeCommonAncestor(excludeCommonAncestor), + fDecayChannelIsExclusive(false), + fDecayChannelIsNotExclusive(false), + fNAncestorDirectProngs(0), + fTempAncestorLabel(-1) { } //________________________________________________________________________________________________ void MCSignal::SetProngs(std::vector prongs, std::vector commonAncestors) { - fProngs = prongs; + fProngs = std::move(prongs); fNProngs = fProngs.size(); - fCommonAncestorIdxs = commonAncestors; + fCommonAncestorIdxs = std::move(commonAncestors); } //________________________________________________________________________________________________ -void MCSignal::AddProng(MCProng prong, int8_t commonAncestor) +void MCSignal::AddProng(const MCProng& prong, int8_t commonAncestor) { if (fProngs.size() < fNProngs) { fProngs.push_back(prong); diff --git a/PWGDQ/Core/MCSignal.h b/PWGDQ/Core/MCSignal.h index f13f9657fbd..476fb4b8751 100644 --- a/PWGDQ/Core/MCSignal.h +++ b/PWGDQ/Core/MCSignal.h @@ -68,12 +68,12 @@ class MCSignal : public TNamed public: MCSignal(); MCSignal(int nProngs, const char* name = "", const char* title = ""); // NOLINT - MCSignal(const char* name, const char* title, std::vector prongs, std::vector commonAncestors, bool excludeCommonAncestor = false); + MCSignal(const char* name, const char* title, const std::vector& prongs, std::vector commonAncestors, bool excludeCommonAncestor = false); MCSignal(const MCSignal& c) = default; ~MCSignal() override = default; void SetProngs(std::vector prongs, std::vector commonAncestors); - void AddProng(MCProng prong, int8_t commonAncestor = -1); + void AddProng(const MCProng& prong, int8_t commonAncestor = -1); void SetDecayChannelIsExclusive(int nProngs, bool option = true) { fDecayChannelIsExclusive = option; diff --git a/PWGDQ/Core/MCSignalLibrary.cxx b/PWGDQ/Core/MCSignalLibrary.cxx index bdd86156c7d..af5677d07d7 100644 --- a/PWGDQ/Core/MCSignalLibrary.cxx +++ b/PWGDQ/Core/MCSignalLibrary.cxx @@ -522,6 +522,18 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "Electrons from pi0 decays", {prong}, {-1}); return signal; } + if (nameStr == "ePrimaryFromPi0") { + MCProng prong(2, {11, 111}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "Electrons from primary pi0 decays", {prong}, {-1}); + return signal; + } + if (nameStr == "eSecondaryFromPi0") { + MCProng prong(2, {11, 111}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary, true); + signal = new MCSignal(name, "Electrons from secondary pi0 decays", {prong}, {-1}); + return signal; + } if (nameStr == "ePrimaryFromPromptPi0") { MCProng prong(2, {11, 111}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502, 402}, {true, true}); prong.SetSourceBit(0, MCProng::kPhysicalPrimary); @@ -533,6 +545,18 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "Electrons from eta decays", {prong}, {-1}); return signal; } + if (nameStr == "ePrimaryFromEta") { + MCProng prong(2, {11, 221}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "Electrons from primary eta decays", {prong}, {-1}); + return signal; + } + if (nameStr == "eSecondaryFromEta") { + MCProng prong(2, {11, 221}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary, true); + signal = new MCSignal(name, "Electrons from secondary eta decays", {prong}, {-1}); + return signal; + } if (nameStr == "eFromEtaPrime") { MCProng prong(2, {11, 331}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); signal = new MCSignal(name, "Electrons from eta' decays", {prong}, {-1}); @@ -885,6 +909,12 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) //_________________________________________________________________________________________________________________________ // LMEE pair signals for LF, same mother + if (nameStr == "eeDuplicated") { // check whether we have two tracks pointing to the same MC particle + MCProng prong(1, {11}, {true}, {false}, {0}, {0}, {false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary); + signal = new MCSignal(name, "duplicated electron", {prong, prong}, {0, 0}); // signal at pair level + return signal; + } if (nameStr == "eeFromAnything") { MCProng prong(2, {11, MCProng::kPDGCodeNotAssigned}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); prong.SetSourceBit(0, MCProng::kPhysicalPrimary); @@ -897,6 +927,12 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "ee pairs from pi0 decays", {prong, prong}, {1, 1}); // signal at pair level return signal; } + if (nameStr == "eeSecondaryFromPi0") { + MCProng prong(2, {11, 111}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary, true); + signal = new MCSignal(name, "ee secondary pairs from pi0 decays", {prong, prong}, {1, 1}); // signal at pair level + return signal; + } if (nameStr == "eePrimaryFromPromptPi0") { MCProng prong(2, {11, 111}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}, false, {502, 402}, {true, true}); prong.SetSourceBit(0, MCProng::kPhysicalPrimary); @@ -909,6 +945,12 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "ee pairs from eta decays", {prong, prong}, {1, 1}); // signal at pair level return signal; } + if (nameStr == "eeSecondaryFromEta") { + MCProng prong(2, {11, 221}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); + prong.SetSourceBit(0, MCProng::kPhysicalPrimary, true); + signal = new MCSignal(name, "ee pairs from eta decays", {prong, prong}, {1, 1}); // signal at pair level + return signal; + } if (nameStr == "eeFromEtaprime") { MCProng prong(2, {11, 331}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); prong.SetSourceBit(0, MCProng::kPhysicalPrimary); @@ -1769,7 +1811,7 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "Jpsi from Chic2 decays", {prong}, {1}); return signal; } - if (nameStr == "JpsiFromChic2") { + if (nameStr == "JpsiFromChic") { MCProng prong(2, {443, 904}, {true, true}, {false, false}, {0, 0}, {0, 0}, {false, false}); prong.SetSourceBit(0, MCProng::kPhysicalPrimary); signal = new MCSignal(name, "Jpsi from Chic0, Chic1 or Chic2 decays", {prong}, {1}); @@ -2038,6 +2080,8 @@ MCSignal* o2::aod::dqmcsignals::GetMCSignal(const char* name) signal = new MCSignal(name, "anyprimary and electron pair from non-prompt jpsi", {pronge, pronge, prongPrimary}, {1, 1, -1}); return signal; } + + LOGF(warn, "Did not find MC signal %s", nameStr); return nullptr; } @@ -2080,10 +2124,10 @@ std::vector o2::aod::dqmcsignals::GetMCSignalsFromJSON(const char* js if (!ValidateJSONMCSignal(&signal, sigName)) { LOG(fatal) << "MCSignal JSON not properly defined for " << sigName << ". Skipping"; continue; - } else { - LOG(debug) << "MCSignal validated"; } + LOG(debug) << "MCSignal validated"; + // Get the signal title const char* title = (signal.HasMember("title") ? signal.FindMember("title")->value.GetString() : ""); LOG(info) << "Title is: " << title; @@ -2121,7 +2165,7 @@ std::vector o2::aod::dqmcsignals::GetMCSignalsFromJSON(const char* js // Get the common ancestors array std::vector commonAncestors; if (signal.HasMember("commonAncestors")) { - for (auto& v : signal.FindMember("commonAncestors")->value.GetArray()) { + for (const auto& v : signal.FindMember("commonAncestors")->value.GetArray()) { commonAncestors.push_back(v.GetInt()); LOG(debug) << "common ancestor " << v.GetInt(); } @@ -2131,7 +2175,7 @@ std::vector o2::aod::dqmcsignals::GetMCSignalsFromJSON(const char* js } } - if (prongs.size() == 0) { + if (prongs.empty()) { LOG(fatal) << "No prongs were defined for this MCSignal!"; return signals; } @@ -2196,13 +2240,13 @@ bool o2::aod::dqmcsignals::ValidateJSONMCProng(T prongJSON, const char* prongNam return false; } std::vector nSourceBits; - for (auto& ii : prongJSON->FindMember("sourceBits")->value.GetArray()) { + for (const auto& ii : prongJSON->FindMember("sourceBits")->value.GetArray()) { if (!ii.IsArray()) { LOG(fatal) << "The sourceBits field should be an array of arrays of MCProng::Source"; return false; } nSourceBits.push_back(ii.GetArray().Size()); - for (auto& iii : ii.GetArray()) { + for (const auto& iii : ii.GetArray()) { if (MCProng::fgSourceNames.find(iii.GetString()) == MCProng::fgSourceNames.end()) { LOG(fatal) << "Source " << iii.GetString() << " not implemented in MCProng"; return false; @@ -2215,7 +2259,7 @@ bool o2::aod::dqmcsignals::ValidateJSONMCProng(T prongJSON, const char* prongNam return false; } int iElem = 0; - for (auto& ii : prongJSON->FindMember("excludeSource")->value.GetArray()) { + for (const auto& ii : prongJSON->FindMember("excludeSource")->value.GetArray()) { if (!ii.IsArray()) { LOG(fatal) << "The excludeSource field should be an array of arrays of bool"; return false; @@ -2293,13 +2337,13 @@ MCProng* o2::aod::dqmcsignals::ParseJSONMCProng(T prongJSON, const char* prongNa LOG(debug) << "n: " << n; // Get the array of PDG codes std::vector pdgs; - for (auto& pdg : prongJSON->FindMember("pdgs")->value.GetArray()) { + for (const auto& pdg : prongJSON->FindMember("pdgs")->value.GetArray()) { pdgs.push_back(pdg.GetInt()); LOG(debug) << "pdgs: " << pdg.GetInt(); } // get the array of booleans for check both charges option std::vector checkBothCharges; - for (auto& ii : prongJSON->FindMember("checkBothCharges")->value.GetArray()) { + for (const auto& ii : prongJSON->FindMember("checkBothCharges")->value.GetArray()) { checkBothCharges.push_back(ii.GetBool()); LOG(debug) << "check both charges " << ii.GetBool(); } @@ -2307,7 +2351,7 @@ MCProng* o2::aod::dqmcsignals::ParseJSONMCProng(T prongJSON, const char* prongNa // get the array of booleans for the excludePDG option, defaults to false std::vector excludePDG; if (prongJSON->HasMember("excludePDG")) { - for (auto& ii : prongJSON->FindMember("excludePDG")->value.GetArray()) { + for (const auto& ii : prongJSON->FindMember("excludePDG")->value.GetArray()) { excludePDG.push_back(ii.GetBool()); LOG(debug) << "exclude pdg " << ii.GetBool(); } @@ -2320,9 +2364,9 @@ MCProng* o2::aod::dqmcsignals::ParseJSONMCProng(T prongJSON, const char* prongNa // get the source bits, and transform from string to int std::vector> sourceBitsVec; if (prongJSON->HasMember("sourceBits")) { - for (auto& ii : prongJSON->FindMember("sourceBits")->value.GetArray()) { + for (const auto& ii : prongJSON->FindMember("sourceBits")->value.GetArray()) { std::vector sourceBits; - for (auto& iii : ii.GetArray()) { + for (const auto& iii : ii.GetArray()) { sourceBits.push_back(MCProng::fgSourceNames[iii.GetString()]); LOG(debug) << "source bit " << iii.GetString(); } @@ -2332,9 +2376,9 @@ MCProng* o2::aod::dqmcsignals::ParseJSONMCProng(T prongJSON, const char* prongNa // prepare the exclusion source options if specified std::vector> excludeSourceVec; if (prongJSON->HasMember("excludeSource")) { - for (auto& ii : prongJSON->FindMember("excludeSource")->value.GetArray()) { + for (const auto& ii : prongJSON->FindMember("excludeSource")->value.GetArray()) { std::vector excludeSource; - for (auto& iii : ii.GetArray()) { + for (const auto& iii : ii.GetArray()) { excludeSource.push_back(iii.GetBool()); LOG(debug) << "exclude source bit " << iii.GetBool(); } @@ -2345,7 +2389,7 @@ MCProng* o2::aod::dqmcsignals::ParseJSONMCProng(T prongJSON, const char* prongNa // prepare the useANDonSourceBitMap vector, defaults to true for each generation std::vector useANDonSourceBitMap; if (prongJSON->HasMember("useANDonSourceBitMap")) { - for (auto& ii : prongJSON->FindMember("useANDonSourceBitMap")->value.GetArray()) { + for (const auto& ii : prongJSON->FindMember("useANDonSourceBitMap")->value.GetArray()) { useANDonSourceBitMap.push_back(ii.GetBool()); LOG(debug) << "use AND on source map " << ii.GetBool(); } @@ -2360,12 +2404,12 @@ MCProng* o2::aod::dqmcsignals::ParseJSONMCProng(T prongJSON, const char* prongNa int igen = 0; std::vector sBitsVec; std::vector sBitsExcludeVec; - for (auto& itgen : sourceBitsVec) { + for (const auto& itgen : sourceBitsVec) { int is = 0; uint64_t sBits = 0; uint64_t sBitsExclude = 0; auto excludeVec = (hasExclude ? excludeSourceVec[igen] : std::vector{}); - for (auto& s : itgen) { + for (const auto& s : itgen) { bool exclude = (hasExclude ? excludeVec[is] : false); if (s != MCProng::kNothing) { sBits |= (static_cast(1) << s); @@ -2414,7 +2458,7 @@ MCProng* o2::aod::dqmcsignals::ParseJSONMCProng(T prongJSON, const char* prongNa std::vector checkIfPDGInHistory = {}; if (prongJSON->HasMember("checkIfPDGInHistory")) { - for (auto& ii : prongJSON->FindMember("checkIfPDGInHistory")->value.GetArray()) { + for (const auto& ii : prongJSON->FindMember("checkIfPDGInHistory")->value.GetArray()) { checkIfPDGInHistory.push_back(ii.GetInt()); LOG(debug) << "checkIfPDGInHistory: " << ii.GetInt(); } @@ -2422,7 +2466,7 @@ MCProng* o2::aod::dqmcsignals::ParseJSONMCProng(T prongJSON, const char* prongNa std::vector excludePDGInHistory = {}; if (prongJSON->HasMember("excludePDGInHistory")) { - for (auto& ii : prongJSON->FindMember("excludePDGInHistory")->value.GetArray()) { + for (const auto& ii : prongJSON->FindMember("excludePDGInHistory")->value.GetArray()) { excludePDGInHistory.push_back(ii.GetBool()); LOG(debug) << "excludePDGInHistory: " << ii.GetBool(); } diff --git a/PWGDQ/Core/MixingHandler.cxx b/PWGDQ/Core/MixingHandler.cxx index 962032ca864..7d3a8e49f62 100644 --- a/PWGDQ/Core/MixingHandler.cxx +++ b/PWGDQ/Core/MixingHandler.cxx @@ -58,7 +58,7 @@ MixingHandler::~MixingHandler() } //_________________________________________________________________________ -void MixingHandler::AddMixingVariable(int var, std::vector binLims) +void MixingHandler::AddMixingVariable(int var, const std::vector& binLims) { fVariables[var] = fVariableLimits.size(); fVariableLimits.push_back(binLims); diff --git a/PWGDQ/Core/MixingHandler.h b/PWGDQ/Core/MixingHandler.h index 8a6f8597db8..931db50f8a2 100644 --- a/PWGDQ/Core/MixingHandler.h +++ b/PWGDQ/Core/MixingHandler.h @@ -174,7 +174,7 @@ class MixingHandler : public TNamed virtual ~MixingHandler(); // setters - void AddMixingVariable(int var, std::vector binLims); + void AddMixingVariable(int var, const std::vector& binLims); void SetPoolDepth(int16_t depth) { fPoolDepth = depth; } // getters diff --git a/PWGDQ/Core/MixingLibrary.cxx b/PWGDQ/Core/MixingLibrary.cxx index 8bc00b6a53d..810f09cb62c 100644 --- a/PWGDQ/Core/MixingLibrary.cxx +++ b/PWGDQ/Core/MixingLibrary.cxx @@ -77,6 +77,14 @@ void o2::aod::dqmixing::SetUpMixing(MixingHandler* mh, const char* mixingVarible std::vector fCentFT0CLimsHashing = {0.0f, 2.5f, 5.0f, 7.5f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f}; mh->AddMixingVariable(VarManager::kCentFT0C, fCentFT0CLimsHashing); } + if (nameStr == "CentralityFT0C7") { + std::vector fCentFT0CLimsHashing = {0.0f, 5.0f, 10.0f, 15.0f, 20.0f, 25.0f, 30.0f, 35.0f, 40.0f, 60.0f, 90.0f}; + mh->AddMixingVariable(VarManager::kCentFT0C, fCentFT0CLimsHashing); + } + if (nameStr == "CentralityFT0C8") { + std::vector fCentFT0CLimsHashing = {0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 60.0f, 90.0f}; + mh->AddMixingVariable(VarManager::kCentFT0C, fCentFT0CLimsHashing); + } if (nameStr == "Mult1") { std::vector fMultLimsHashing = {0.0f, 10.0f, 20.0f, 40.0f, 60.0f, 80.0f, 100.0f, 120.0f, 160.0f, 350.0f}; mh->AddMixingVariable(VarManager::kVtxNcontrib, fMultLimsHashing); @@ -240,7 +248,7 @@ void o2::aod::dqmixing::SetUpMixingFromJSON(MixingHandler* mh, const char* json) const auto& lims = obj["LimsHashing"]; std::vector limits; limits.reserve(lims.Size()); - for (auto& v : lims.GetArray()) { + for (const auto& v : lims.GetArray()) { limits.push_back(v.GetFloat()); } diff --git a/PWGDQ/Core/VarManager.cxx b/PWGDQ/Core/VarManager.cxx index df1eaa466bd..84e6d055ce9 100644 --- a/PWGDQ/Core/VarManager.cxx +++ b/PWGDQ/Core/VarManager.cxx @@ -59,6 +59,10 @@ float VarManager::fgzMatching = -77.5; float VarManager::fgxShiftFwd = 0.0; float VarManager::fgyShiftFwd = 0.0; float VarManager::fgzShiftFwd = 0.0; +bool VarManager::fgUseTopBottomShift = false; +float VarManager::fgxShiftFwdBottom = 0.0; +float VarManager::fgyShiftFwdBottom = 0.0; +float VarManager::fgzShiftFwdBottom = 0.0; float VarManager::fgValues[VarManager::kNVars] = {0.0f}; float VarManager::fgTPCInterSectorBoundary = 1.0; // cm int VarManager::fgITSROFbias = 0; @@ -147,7 +151,7 @@ void VarManager::ResetValues(int startValue, int endValue, float* values) } //__________________________________________________________________ -void VarManager::SetCollisionSystem(TString system, float energy) +void VarManager::SetCollisionSystem(const TString& system, float energy) { // // Set the collision system and the center of mass energy @@ -200,8 +204,8 @@ void VarManager::SetCollisionSystem(TString system, float energy) // TO Do: add more systems // set the beam 4-momentum vectors - float beamAEnergy = energy / 2.0 * sqrt(NumberOfProtonsA * NumberOfProtonsC / NumberOfProtonsC / NumberOfProtonsA); // GeV - float beamCEnergy = energy / 2.0 * sqrt(NumberOfProtonsC * NumberOfProtonsA / NumberOfProtonsA / NumberOfProtonsC); // GeV + float beamAEnergy = energy / 2.0f * std::sqrt(static_cast(NumberOfProtonsA) * NumberOfProtonsC / NumberOfProtonsC / NumberOfProtonsA); // GeV + float beamCEnergy = energy / 2.0f * std::sqrt(static_cast(NumberOfProtonsC) * NumberOfProtonsA / NumberOfProtonsA / NumberOfProtonsC); // GeV float beamAMomentum = std::sqrt(beamAEnergy * beamAEnergy - NumberOfNucleonsA * NumberOfNucleonsA * MassProton * MassProton); float beamCMomentum = std::sqrt(beamCEnergy * beamCEnergy - NumberOfNucleonsC * NumberOfNucleonsC * MassProton * MassProton); fgBeamA.SetPxPyPzE(0, 0, beamAMomentum, beamAEnergy); @@ -243,7 +247,7 @@ void VarManager::FillTrackDerived(float* values) } //__________________________________________________________________ -float VarManager::calculateCosPA(KFParticle kfp, KFParticle PV) +float VarManager::calculateCosPA(const KFParticle& kfp, const KFParticle& PV) { return cpaFromKF(kfp, PV); } @@ -256,7 +260,8 @@ double VarManager::ComputePIDcalibration(int species, double nSigmaValue) if (fgCalibrationType == 1) { // get the calibration histograms - CalibObjects calibMean, calibSigma; + CalibObjects calibMean = kTPCElectronMean; + CalibObjects calibSigma = kTPCElectronSigma; switch (species) { case 0: calibMean = kTPCElectronMean; @@ -279,8 +284,8 @@ double VarManager::ComputePIDcalibration(int species, double nSigmaValue) return -999.0; // Return zero if species is invalid } - TH3F* calibMeanHist = reinterpret_cast(fgCalibs[calibMean]); - TH3F* calibSigmaHist = reinterpret_cast(fgCalibs[calibSigma]); + TH3F* calibMeanHist = dynamic_cast(fgCalibs[calibMean]); + TH3F* calibSigmaHist = dynamic_cast(fgCalibs[calibSigma]); if (!calibMeanHist || !calibSigmaHist) { LOG(fatal) << "Calibration histograms not found for species: " << species; return -999.0; // Return zero if histograms are not found @@ -302,7 +307,9 @@ double VarManager::ComputePIDcalibration(int species, double nSigmaValue) return (nSigmaValue - mean) / sigma; // Return the calibrated nSigma value } else if (fgCalibrationType == 2) { // get the calibration histograms - CalibObjects calibMean, calibSigma, calibStatus; + CalibObjects calibMean = kTPCElectronMean; + CalibObjects calibSigma = kTPCElectronSigma; + CalibObjects calibStatus = kTPCElectronStatus; switch (species) { case 0: calibMean = kTPCElectronMean; @@ -329,9 +336,9 @@ double VarManager::ComputePIDcalibration(int species, double nSigmaValue) return -999.0; // Return zero if species is invalid } - THnF* calibMeanHist = reinterpret_cast(fgCalibs[calibMean]); - THnF* calibSigmaHist = reinterpret_cast(fgCalibs[calibSigma]); - THnF* calibStatusHist = reinterpret_cast(fgCalibs[calibStatus]); + THnF* calibMeanHist = dynamic_cast(fgCalibs[calibMean]); + THnF* calibSigmaHist = dynamic_cast(fgCalibs[calibSigma]); + THnF* calibStatusHist = dynamic_cast(fgCalibs[calibStatus]); if (!calibMeanHist || !calibSigmaHist || !calibStatusHist) { LOG(fatal) << "Calibration histograms not found for species: " << species; return -999.0; // Return zero if histograms are not found @@ -351,17 +358,18 @@ double VarManager::ComputePIDcalibration(int species, double nSigmaValue) binTlong = (binTlong == 0 ? 1 : binTlong); binTlong = (binTlong > calibMeanHist->GetAxis(3)->GetNbins() ? calibMeanHist->GetAxis(3)->GetNbins() : binTlong); - int bin[4] = {binEta, binNpv, binNlong, binTlong}; - int status = static_cast(calibStatusHist->GetBinContent(bin)); - double mean = calibMeanHist->GetBinContent(bin); - double sigma = calibSigmaHist->GetBinContent(bin); + std::array bin{binEta, binNpv, binNlong, binTlong}; + int status = static_cast(calibStatusHist->GetBinContent(bin.data())); + double mean = calibMeanHist->GetBinContent(bin.data()); + double sigma = calibSigmaHist->GetBinContent(bin.data()); switch (status) { case 0: // good calibration, return the calibrated nSigma value return (nSigmaValue - mean) / sigma; break; case 1: - // calibration not valid, return the original nSigma value + case 4: + // calibration not valid or interpolation failed, return the original nSigma value return nSigmaValue; break; case 2: // calibration constant has poor stat uncertainty, consider the user option for what to do @@ -374,10 +382,6 @@ double VarManager::ComputePIDcalibration(int species, double nSigmaValue) return nSigmaValue; } break; - case 4: - // calibration constants interpolation failed, return the original nSigma value - return nSigmaValue; - break; default: return nSigmaValue; // unknown status, return the original nSigma value break; @@ -419,7 +423,7 @@ void VarManager::FillEfficiency(float* values) LOG(fatal) << "efficiency histogram not set"; return; } - TH3F* efficiencyHist = reinterpret_cast(fgEfficiencyHist); + TH3F* efficiencyHist = dynamic_cast(fgEfficiencyHist); // Get the bin indices for the efficiency histogram int binPt = efficiencyHist->GetXaxis()->FindBin(values[kPt]); binPt = (binPt == 0 ? 1 : binPt); @@ -439,7 +443,7 @@ void VarManager::FillEfficiency(float* values) LOG(fatal) << "efficiency histogram not set"; return; } - TH3F* efficiencyHist = reinterpret_cast(fgEfficiencyHist); + TH3F* efficiencyHist = dynamic_cast(fgEfficiencyHist); // Get the bin indices for the efficiency histogram int binPt = efficiencyHist->GetXaxis()->FindBin(values[kPt]); binPt = (binPt == 0 ? 1 : binPt); @@ -541,10 +545,9 @@ std::tuple VarManager::BimodalityCoefficientU float mean = std::accumulate(data.begin(), data.end(), 0.0) / n; float m2 = 0.0, m3 = 0.0, m4 = 0.0; - float diff, diff2; - for (float x : data) { - diff = x - mean; - diff2 = diff * diff; + for (const float& x : data) { + const float diff = x - mean; + const float diff2 = diff * diff; m2 += diff2; m3 += diff2 * diff; m4 += diff2 * diff2; @@ -581,7 +584,7 @@ std::tuple VarManager::BimodalityCoeffic int nBins = static_cast((max - min) / binWidth); std::vector counts(nBins, 0.0); - for (float x : data) { + for (const float& x : data) { if (x < min || x >= max) { continue; // skip out-of-range values } @@ -688,14 +691,13 @@ std::tuple VarManager::BimodalityCoeffic // then compute the second, third, and fourth central moments float m2 = 0.0, m3 = 0.0, m4 = 0.0; - float diff, diff2, binCenter; for (int i = 0; i < nBins; ++i) { if (counts[i] == 0) { continue; // skip empty bins } - binCenter = min + (i + 0.5) * binWidth; - diff = binCenter - mean; - diff2 = diff * diff; + const float binCenter = min + (i + 0.5f) * binWidth; + const float diff = binCenter - mean; + const float diff2 = diff * diff; m2 += counts[i] * diff2; m3 += counts[i] * diff2 * diff; m4 += counts[i] * diff2 * diff2; @@ -1900,10 +1902,26 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kBGFDDCpf] = ""; fgVariableNames[kMultDensity] = "dNdeta ALICE3"; fgVariableUnits[kMultDensity] = ""; - fgVariableNames[kMultMCNParticlesEta40] = "Multiplicity_eta40"; - fgVariableUnits[kMultMCNParticlesEta40] = ""; - fgVariableNames[kMultMCNParticlesEta20] = "Multiplicity_eta20"; - fgVariableUnits[kMultMCNParticlesEta20] = ""; + fgVariableNames[kCent] = "Centrality ALICE3"; + fgVariableUnits[kCent] = ""; + fgVariableNames[kMultPV] = "Mult PV ALICE3"; + fgVariableUnits[kMultPV] = ""; + fgVariableNames[kMultPVeta1] = "Mult PV ALICE3 in |eta| < 1"; + fgVariableUnits[kMultPVeta1] = ""; + fgVariableNames[kMultPVetaHalf] = "Mult PV ALICE3 in |eta| < 0.5"; + fgVariableUnits[kMultPVetaHalf] = ""; + fgVariableNames[kMultGlobalTracks] = "Mult global tracks ALICE3"; + fgVariableUnits[kMultGlobalTracks] = ""; + fgVariableNames[kMultGlobalTracksPV] = "Mult global tracks that are PV ALICE3"; + fgVariableUnits[kMultGlobalTracksPV] = ""; + fgVariableNames[kMultMCNParticlesAll] = "Multiplicity MC all"; + fgVariableUnits[kMultMCNParticlesAll] = ""; + fgVariableNames[kMultMCNParticlesEta25] = "Multiplicity MC |eta| < 2.5"; + fgVariableUnits[kMultMCNParticlesEta25] = ""; + fgVariableNames[kMultMCNParticlesEta125] = "Multiplicity MC |eta| < 1.25"; + fgVariableUnits[kMultMCNParticlesEta125] = ""; + fgVariableNames[kMultMCNParticlesEta09] = "Multiplicity MC |eta| < 0.9"; + fgVariableUnits[kMultMCNParticlesEta09] = ""; fgVariableNames[kIsReconstructed] = "is track reconstructed"; fgVariableUnits[kIsReconstructed] = ""; fgVariableNames[kNSiliconHits] = "Number of hits in silicon layers"; @@ -2703,9 +2721,13 @@ void VarManager::SetDefaultVarNames() fgVarNamesMap["kDeltaPhi_TPC"] = kDeltaPhi_TPC; fgVarNamesMap["kDeltaPhi_FT0A"] = kDeltaPhi_FT0A; fgVarNamesMap["kDeltaPhi_FT0C"] = kDeltaPhi_FT0C; + fgVarNamesMap["kDeltaPhi_Random"] = kDeltaPhi_Random; + fgVarNamesMap["kDeltaPhi_MC"] = kDeltaPhi_MC; fgVarNamesMap["kCos2DeltaPhi_TPC"] = kCos2DeltaPhi_TPC; fgVarNamesMap["kCos2DeltaPhi_FT0A"] = kCos2DeltaPhi_FT0A; fgVarNamesMap["kCos2DeltaPhi_FT0C"] = kCos2DeltaPhi_FT0C; + fgVarNamesMap["kCos2DeltaPhi_Random"] = kCos2DeltaPhi_Random; + fgVarNamesMap["kCos2DeltaPhi_MC"] = kCos2DeltaPhi_MC; fgVarNamesMap["kDeltaPhiME_TPC"] = kDeltaPhiME_TPC; fgVarNamesMap["kDeltaPhiME_FT0A"] = kDeltaPhiME_FT0A; fgVarNamesMap["kDeltaPhiME_FT0C"] = kDeltaPhiME_FT0C; @@ -2834,8 +2856,16 @@ void VarManager::SetDefaultVarNames() fgVarNamesMap["kBBFDDCpf"] = kBBFDDCpf; fgVarNamesMap["kBGFDDCpf"] = kBGFDDCpf; fgVarNamesMap["kMultDensity"] = kMultDensity; - fgVarNamesMap["kMultMCNParticlesEta40"] = kMultMCNParticlesEta40; - fgVarNamesMap["kMultMCNParticlesEta20"] = kMultMCNParticlesEta20; + fgVarNamesMap["kCent"] = kCent; + fgVarNamesMap["kMultPV"] = kMultPV; + fgVarNamesMap["kMultPVeta1"] = kMultPVeta1; + fgVarNamesMap["kMultPVetaHalf"] = kMultPVetaHalf; + fgVarNamesMap["kMultGlobalTracks"] = kMultGlobalTracks; + fgVarNamesMap["kMultGlobalTracksPV"] = kMultGlobalTracksPV; + fgVarNamesMap["kMultMCNParticlesAll"] = kMultMCNParticlesAll; + fgVarNamesMap["kMultMCNParticlesEta25"] = kMultMCNParticlesEta25; + fgVarNamesMap["kMultMCNParticlesEta125"] = kMultMCNParticlesEta125; + fgVarNamesMap["kMultMCNParticlesEta09"] = kMultMCNParticlesEta09; fgVarNamesMap["kIsReconstructed"] = kIsReconstructed; fgVarNamesMap["kNSiliconHits"] = kNSiliconHits; fgVarNamesMap["kNTPCHits"] = kNTPCHits; diff --git a/PWGDQ/Core/VarManager.h b/PWGDQ/Core/VarManager.h index 665d5f6bef9..4521c911eb0 100644 --- a/PWGDQ/Core/VarManager.h +++ b/PWGDQ/Core/VarManager.h @@ -79,7 +79,6 @@ #include #include #include -#include #include #include #include @@ -1117,8 +1116,16 @@ class VarManager : public TObject // ALICE 3 Variables kMultDensity, - kMultMCNParticlesEta40, - kMultMCNParticlesEta20, + kCent, + kMultPV, + kMultPVeta1, + kMultPVetaHalf, + kMultGlobalTracks, + kMultGlobalTracksPV, + kMultMCNParticlesAll, + kMultMCNParticlesEta25, + kMultMCNParticlesEta125, + kMultMCNParticlesEta09, kIsReconstructed, kNSiliconHits, kNTPCHits, @@ -1206,7 +1213,8 @@ class VarManager : public TObject enum DileptonCharmHadronTypes { kJPsi = 0, kD0ToPiK, - kD0barToKPi + kD0barToKPi, + kDplusToPiKPi }; enum EventFilters { @@ -1266,7 +1274,7 @@ class VarManager : public TObject } // Setup the collision system - static void SetCollisionSystem(TString system, float energy); + static void SetCollisionSystem(const TString& system, float energy); static void SetCollisionSystem(o2::parameters::GRPLHCIFData* grplhcif); static void SetMagneticField(float magField) @@ -1289,6 +1297,7 @@ class VarManager : public TObject static void SetZShift(float z) { fgzShiftFwd = z; + fgUseTopBottomShift = false; } // Set x, y and z shifts for forward tracks @@ -1297,6 +1306,33 @@ class VarManager : public TObject fgxShiftFwd = x; fgyShiftFwd = y; fgzShiftFwd = z; + fgUseTopBottomShift = false; + } + + // Set separate x, y, z shifts for top (y >= 0) and bottom (y < 0) forward tracks + // Top shifts are stored in fgx/y/zShiftFwd; bottom shifts in fgx/y/zShiftFwdBottom + static void SetTopBottom3DShift(float xTop, float yTop, float zTop, float xBottom, float yBottom, float zBottom) + { + fgxShiftFwd = xTop; + fgyShiftFwd = yTop; + fgzShiftFwd = zTop; + fgxShiftFwdBottom = xBottom; + fgyShiftFwdBottom = yBottom; + fgzShiftFwdBottom = zBottom; + fgUseTopBottomShift = true; + } + + static void GetFwdShiftForY(float y, float& xShift, float& yShift, float& zShift) + { + if (fgUseTopBottomShift && y < 0.f) { + xShift = fgxShiftFwdBottom; + yShift = fgyShiftFwdBottom; + zShift = fgzShiftFwdBottom; + } else { + xShift = fgxShiftFwd; + yShift = fgyShiftFwd; + zShift = fgzShiftFwd; + } } // Setup the 2 prong KFParticle @@ -1412,8 +1448,6 @@ class VarManager : public TObject template static o2::track::TrackParCovFwd PropagateFwd(const T& track, const C& cov, float z); template - static void FillMuonPDca(const T& muon, const C& collision, float* values = nullptr); - template static void FillPropagateMuon(const T& muon, const C& collision, float* values = nullptr); template static void FillBC(T const& bc, float* values = nullptr); @@ -1460,7 +1494,7 @@ class VarManager : public TObject template static void FillPair(T1 const& t1, T2 const& t2, float* values = nullptr); template - static void FillPairRotation(T1 const& t1, T2 const& t2, float* values = nullptr); + static void FillPairRotation(T1 const& t1, T2 const& t2, int rotation, float* values = nullptr); template static void FillPairCollision(C const& collision, T1 const& t1, T2 const& t2, float* values = nullptr); template @@ -1487,8 +1521,8 @@ class VarManager : public TObject static void FillDileptonTrackVertexing(C const& collision, T1 const& lepton1, T1 const& lepton2, T1 const& track, float* values); template static void FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* values = nullptr, float hadronMass = 0.0f); - template - static void FillEnergyCorrelatorTriple(T1 const& lepton1, T2 const& lepton2, T3 const& hadron, float* values = nullptr, float Translow = 1. / 3, float Transhigh = 2. / 3, bool applyFitMass = false, float sidebandMass = 0.0f, float weight = 1.0f); + template + static void FillEnergyCorrelatorTriple(C const& collision, T1 const& lepton1, T2 const& lepton2, T3 const& hadron, float* values = nullptr, float Translow = 1. / 3, float Transhigh = 2. / 3, bool applyFitMass = false, float sidebandMass = 0.0f, float weight = 1.0f); template static void FillEnergyCorrelatorsUnfoldingTriple(T1 const& lepton1, T2 const& lepton2, T3 const& hadron, T4 const& track, T5 const& t1, float* values = nullptr, bool applyFitMass = false, float Effweight_rec = 1.f, float Accweight_gen = 1.f, float Translow = 1. / 3, float Transhigh = 2. / 3); template @@ -1611,6 +1645,10 @@ class VarManager : public TObject static float fgxShiftFwd; static float fgyShiftFwd; static float fgzShiftFwd; + static bool fgUseTopBottomShift; + static float fgxShiftFwdBottom; + static float fgyShiftFwdBottom; + static float fgzShiftFwdBottom; static float fgCenterOfMassEnergy; // collision energy static float fgMassofCollidingParticle; // mass of the colliding particle static float fgTPCInterSectorBoundary; // TPC inter-sector border size at the TPC outer radius, in cm @@ -1633,7 +1671,7 @@ class VarManager : public TObject static KFPTrack createKFPFwdTrackFromFwdTrack(const T& muon); template static KFPVertex createKFPVertexFromCollision(const T& collision); - static float calculateCosPA(KFParticle kfp, KFParticle PV); + static float calculateCosPA(const KFParticle& kfp, const KFParticle& PV); template static float calculatePhiV(const T1& t1, const T2& t2); template @@ -1789,14 +1827,14 @@ o2::dataformats::VertexBase VarManager::RecalculatePrimaryVertex(T const& track0 template o2::dataformats::GlobalFwdTrack VarManager::PropagateMuon(const T& muon, const C& collision, const int endPoint) { - o2::track::TrackParCovFwd fwdtrack = o2::aod::fwdtrackutils::getTrackParCovFwd3DShift(muon, fgxShiftFwd, fgyShiftFwd, fgzShiftFwd, muon); + float xShift = 0.f; + float yShift = 0.f; + float zShift = 0.f; + GetFwdShiftForY(muon.y(), xShift, yShift, zShift); + o2::track::TrackParCovFwd fwdtrack = o2::aod::fwdtrackutils::getTrackParCovFwd3DShift(muon, xShift, yShift, zShift, muon); o2::dataformats::GlobalFwdTrack propmuon; if (static_cast(muon.trackType()) > 2) { - o2::dataformats::GlobalFwdTrack track; - track.setParameters(fwdtrack.getParameters()); - track.setZ(fwdtrack.getZ()); - track.setCovariances(fwdtrack.getCovariances()); - auto mchTrack = mMatching.FwdtoMCH(track); + auto mchTrack = mMatching.FwdtoMCH(fwdtrack); if (endPoint == kToVertex) { o2::mch::TrackExtrap::extrapToVertex(mchTrack, collision.posX(), collision.posY(), collision.posZ(), collision.covXX(), collision.covYY()); @@ -1811,17 +1849,12 @@ o2::dataformats::GlobalFwdTrack VarManager::PropagateMuon(const T& muon, const C o2::mch::TrackExtrap::extrapToVertexWithoutBranson(mchTrack, fgzMatching); } - auto proptrack = mMatching.MCHtoFwd(mchTrack); - propmuon.setParameters(proptrack.getParameters()); - propmuon.setZ(proptrack.getZ()); - propmuon.setCovariances(proptrack.getCovariances()); + propmuon = mMatching.MCHtoFwd(mchTrack); } else if (static_cast(muon.trackType()) < 2) { std::array dcaInfOrig{999.f, 999.f, 999.f}; fwdtrack.propagateToDCAhelix(fgMagField, {collision.posX(), collision.posY(), collision.posZ()}, dcaInfOrig); - propmuon.setParameters(fwdtrack.getParameters()); - propmuon.setZ(fwdtrack.getZ()); - propmuon.setCovariances(fwdtrack.getCovariances()); + propmuon = fwdtrack; } return propmuon; } @@ -1834,25 +1867,6 @@ o2::track::TrackParCovFwd VarManager::PropagateFwd(const T& track, const C& cov, return fwdtrack; } -template -void VarManager::FillMuonPDca(const T& muon, const C& collision, float* values) -{ - if (!values) { - values = fgValues; - } - - if constexpr ((fillMap & MuonCov) > 0 || (fillMap & ReducedMuonCov) > 0) { - - o2::dataformats::GlobalFwdTrack propmuon = PropagateMuon(muon, collision); - o2::dataformats::GlobalFwdTrack propmuonAtDCA = PropagateMuon(muon, collision, kToDCA); - - float dcaX = (propmuonAtDCA.getX() - collision.posX()); - float dcaY = (propmuonAtDCA.getY() - collision.posY()); - float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); - values[kMuonPDca] = muon.p() * dcaXY; - } -} - template void VarManager::FillPropagateMuon(const T& muon, const C& collision, float* values) { @@ -1876,20 +1890,6 @@ void VarManager::FillPropagateMuon(const T& muon, const C& collision, float* val values[kTgl] = propmuon.getTgl(); values[kPhi] = propmuon.getPhi(); - // Redo propagation only for muon tracks - // propagation of MFT tracks alredy done in fwdtrack-extention task - if (static_cast(muon.trackType()) > 2) { - o2::dataformats::GlobalFwdTrack propmuonAtDCA = PropagateMuon(muon, collision, kToDCA); - o2::dataformats::GlobalFwdTrack propmuonAtRabs = PropagateMuon(muon, collision, kToRabs); - float dcaX = (propmuonAtDCA.getX() - collision.posX()); - float dcaY = (propmuonAtDCA.getY() - collision.posY()); - values[kMuonDCAx] = dcaX; - values[kMuonDCAy] = dcaY; - double xAbs = propmuonAtRabs.getX(); - double yAbs = propmuonAtRabs.getY(); - values[kMuonRAtAbsorberEnd] = std::sqrt(xAbs * xAbs + yAbs * yAbs); - } - const SMatrix55& cov = propmuon.getCovariances(); values[kMuonCXX] = cov(0, 0); values[kMuonCXY] = cov(1, 0); @@ -1916,12 +1916,17 @@ void VarManager::FillGlobalMuonRefit(T1 const& muontrack, T2 const& mfttrack, co values = fgValues; } if constexpr ((fillMap & MuonCov) > 0 || (fillMap & ReducedMuonCov) > 0) { - o2::dataformats::GlobalFwdTrack propmuon = PropagateMuon(muontrack, collision); + float xShift = 0.f; + float yShift = 0.f; + float zShift = 0.f; + GetFwdShiftForY(mfttrack.y(), xShift, yShift, zShift); + o2::dataformats::GlobalFwdTrack propmuon = PropagateMuon(muontrack, collision, kToVertex); double px = propmuon.getP() * std::sin(o2::constants::math::PIHalf - std::atan(mfttrack.tgl())) * std::cos(mfttrack.phi()); double py = propmuon.getP() * std::sin(o2::constants::math::PIHalf - std::atan(mfttrack.tgl())) * std::sin(mfttrack.phi()); double pz = propmuon.getP() * std::cos(o2::constants::math::PIHalf - std::atan(mfttrack.tgl())); double pt = std::sqrt(std::pow(px, 2) + std::pow(py, 2)); - auto mftprop = o2::aod::fwdtrackutils::getTrackParCovFwd3DShift(mfttrack, fgxShiftFwd, fgyShiftFwd, fgzShiftFwd); + auto mftprop = o2::aod::fwdtrackutils::getTrackParCovFwd3DShift(mfttrack, xShift, yShift, zShift); + mftprop.setInvQPt(static_cast(muontrack.sign()) / pt); values[kX] = mftprop.getX(); values[kY] = mftprop.getY(); values[kZ] = mftprop.getZ(); @@ -1930,6 +1935,12 @@ void VarManager::FillGlobalMuonRefit(T1 const& muontrack, T2 const& mfttrack, co values[kPz] = pz; values[kEta] = mftprop.getEta(); values[kPhi] = mftprop.getPhi(); + + // Helix DCA of the refitted global track w.r.t. the associated collision + std::array dca{999., 999., 999.}; + mftprop.propagateToDCAhelix(fgMagField, {collision.posX(), collision.posY(), collision.posZ()}, dca); + values[kMuonDCAx] = static_cast(dca[0]); + values[kMuonDCAy] = static_cast(dca[1]); } } @@ -1941,8 +1952,12 @@ void VarManager::FillGlobalMuonRefitCov(T1 const& muontrack, T2 const& mfttrack, } if constexpr ((MuonfillMap & MuonCov) > 0) { if constexpr ((MFTfillMap & MFTCov) > 0) { - o2::dataformats::GlobalFwdTrack propmuon = PropagateMuon(muontrack, collision); - auto mft = o2::aod::fwdtrackutils::getTrackParCovFwd3DShift(mfttrack, fgxShiftFwd, fgyShiftFwd, fgzShiftFwd, mftcov); + float xShift = 0.f; + float yShift = 0.f; + float zShift = 0.f; + GetFwdShiftForY(mfttrack.y(), xShift, yShift, zShift); + o2::dataformats::GlobalFwdTrack propmuon = PropagateMuon(muontrack, collision, kToVertex); + auto mft = o2::aod::fwdtrackutils::getTrackParCovFwd3DShift(mfttrack, xShift, yShift, zShift, mftcov); o2::dataformats::GlobalFwdTrack globalRefit = o2::aod::fwdtrackutils::refitGlobalMuonCov(propmuon, mft); values[kX] = globalRefit.getX(); @@ -1953,6 +1968,12 @@ void VarManager::FillGlobalMuonRefitCov(T1 const& muontrack, T2 const& mfttrack, values[kPz] = globalRefit.getPz(); values[kEta] = globalRefit.getEta(); values[kPhi] = globalRefit.getPhi(); + + // Helix DCA of the covariance-refitted global track w.r.t. the associated collision + std::array dca{999., 999., 999.}; + globalRefit.propagateToDCAhelix(fgMagField, {collision.posX(), collision.posY(), collision.posZ()}, dca); + values[kMuonDCAx] = static_cast(dca[0]); + values[kMuonDCAy] = static_cast(dca[1]); } } } @@ -3329,9 +3350,7 @@ void VarManager::FillTrack(T const& track, float* values) values[kMuonChi2MatchMCHMFT] = track.chi2MatchMCHMFT(); values[kMuonMatchScoreMCHMFT] = track.matchScoreMCHMFT(); values[kMuonTrackType] = track.trackType(); - values[kMuonDCAx] = track.sign() * (track.pDca() / std::numbers::sqrt2 / track.p()); - values[kMuonDCAy] = values[kMuonDCAx]; - if constexpr ((fillMap & MuonDca) > 0) { + if constexpr ((fillMap & ReducedMuonExtra) > 0) { values[kMuonDCAx] = track.fwdDcaX(); values[kMuonDCAy] = track.fwdDcaY(); } @@ -3361,7 +3380,11 @@ void VarManager::FillTrack(T const& track, float* values) values[kMuonC1Pt21Pt2] = track.c1Pt21Pt2(); } if constexpr ((fillMap & MuonCov) > 0 || (fillMap & MuonCovRealign) > 0) { - auto muonTrack = o2::aod::fwdtrackutils::getTrackParCovFwd3DShift(track, fgxShiftFwd, fgyShiftFwd, fgzShiftFwd, track); + float xShift = 0.f; + float yShift = 0.f; + float zShift = 0.f; + GetFwdShiftForY(track.y(), xShift, yShift, zShift); + auto muonTrack = o2::aod::fwdtrackutils::getTrackParCovFwd3DShift(track, xShift, yShift, zShift, track); auto muonCov = muonTrack.getCovariances(); values[kX] = muonTrack.getX(); values[kY] = muonTrack.getY(); @@ -3420,13 +3443,30 @@ void VarManager::FillTrackCollision(T const& track, C const& collision, float* v } } if constexpr ((fillMap & MuonCov) > 0 || (fillMap & MuonCovRealign) > 0 || (fillMap & ReducedMuonCov) > 0) { + float dcaX = 999.f; + float dcaY = 999.f; + if (static_cast(track.trackType()) <= 2) { + // Global / MCH-MID: helix DCA only (for globals, kMuonPDca is filled from the matched MCH in skimMuons) + float xShift = 0.f; + float yShift = 0.f; + float zShift = 0.f; + GetFwdShiftForY(track.y(), xShift, yShift, zShift); + o2::track::TrackParCovFwd fwdtrack = o2::aod::fwdtrackutils::getTrackParCovFwd3DShift(track, xShift, yShift, zShift, track); + std::array dca{999., 999., 999.}; + fwdtrack.propagateToDCAhelix(fgMagField, {collision.posX(), collision.posY(), collision.posZ()}, dca); + dcaX = static_cast(dca[0]); + dcaY = static_cast(dca[1]); + } else { + // MCH standalone: DCA and pDCA from MCH extrapolation + o2::dataformats::GlobalFwdTrack propmuonAtDCA = PropagateMuon(track, collision, kToDCA); + dcaX = propmuonAtDCA.getX() - collision.posX(); + dcaY = propmuonAtDCA.getY() - collision.posY(); + float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); + values[kMuonPDca] = track.p() * dcaXY; + } - o2::dataformats::GlobalFwdTrack propmuonAtDCA = PropagateMuon(track, collision, kToDCA); - - float dcaX = (propmuonAtDCA.getX() - collision.posX()); - float dcaY = (propmuonAtDCA.getY() - collision.posY()); - float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); - values[kMuonPDca] = track.p() * dcaXY; + values[kMuonDCAx] = dcaX; + values[kMuonDCAy] = dcaY; } } @@ -3981,7 +4021,7 @@ void VarManager::FillPair(T1 const& t1, T2 const& t2, float* values) } } } - if constexpr ((pairType == kDecayToMuMu) && ((fillMap & Muon) > 0 || (fillMap & ReducedMuon) > 0)) { + if constexpr ((pairType == kDecayToMuMu) && ((fillMap & ReducedMuonExtra) > 0)) { if (fgUsedVars[kQuadDCAabsXY]) { double dca1X = t1.fwdDcaX(); double dca1Y = t1.fwdDcaY(); @@ -4004,7 +4044,7 @@ void VarManager::FillPair(T1 const& t1, T2 const& t2, float* values) // change_start: rotation pair template -void VarManager::FillPairRotation(T1 const& t1, T2 const& t2, float* values) +void VarManager::FillPairRotation(T1 const& t1, T2 const& t2, int rotation, float* values) { if (!values) { values = fgValues; @@ -4034,7 +4074,17 @@ void VarManager::FillPairRotation(T1 const& t1, T2 const& t2, float* values) m2 = o2::constants::physics::MassMuon; } - double rotationphi2 = SampleRotationPhi(t2.pt(), t2.eta(), t2.sign()); + double rotationphi2 = t2.phi(); + + if (rotation == 1) { + rotationphi2 = t2.phi() + o2::constants::math::PI; + } else if (rotation == 2) { + rotationphi2 = 2 * values[kPsi2A] - t2.phi(); + } else if (rotation == 3) { + rotationphi2 = 2 * values[kPsi2A] - t2.phi() + o2::constants::math::PI; + } + + rotationphi2 = RecoDecay::constrainAngle(rotationphi2); values[kCharge] = t1.sign() + t2.sign(); values[kCharge1] = t1.sign(); @@ -6393,9 +6443,15 @@ void VarManager::FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* } } -template -void VarManager::FillEnergyCorrelatorTriple(T1 const& lepton1, T2 const& lepton2, T3 const& hadron, float* values, float Translow, float Transhigh, bool applyFitMass, float sidebandMass, float weight) +template +void VarManager::FillEnergyCorrelatorTriple(C const& collision, T1 const& lepton1, T2 const& lepton2, T3 const& hadron, float* values, float Translow, float Transhigh, bool applyFitMass, float sidebandMass, float weight) { + if (!values) { + values = fgValues; + } + if (fgUsedVars[kVertexingTauxyProjectedPoleJPsiMass] || fgUsedVars[kVertexingLxyProjected]) { + FillPairVertexing(collision, lepton1, lepton2, false, values); + } float m1 = o2::constants::physics::MassElectron; float m2 = o2::constants::physics::MassElectron; @@ -6411,7 +6467,8 @@ void VarManager::FillEnergyCorrelatorTriple(T1 const& lepton1, T2 const& lepton2 dileptonmass = sidebandMass; } - if (fgUsedVars[kCosChi] || fgUsedVars[kECWeight] || fgUsedVars[kCosTheta] || fgUsedVars[kEWeight_before] || fgUsedVars[kPtDau] || fgUsedVars[kEtaDau] || fgUsedVars[kPhiDau] || fgUsedVars[kCosChi_randomPhi_trans] || fgUsedVars[kCosChi_randomPhi_toward] || fgUsedVars[kCosChi_randomPhi_away]) { + if (fgUsedVars[kPairMassDau] || fgUsedVars[kCosChi] || fgUsedVars[kECWeight] || fgUsedVars[kCosTheta] || fgUsedVars[kEWeight_before] || fgUsedVars[kPtDau] || fgUsedVars[kEtaDau] || fgUsedVars[kPhiDau] || fgUsedVars[kCosChi_randomPhi_trans] || fgUsedVars[kCosChi_randomPhi_toward] || fgUsedVars[kCosChi_randomPhi_away]) { + values[kPairMassDau] = dilepton.mass(); values[kdileptonmass] = dileptonmass; ROOT::Math::PtEtaPhiMVector v1(dilepton.pt(), dilepton.eta(), dilepton.phi(), dileptonmass); ROOT::Math::PtEtaPhiMVector v2(hadron.pt(), hadron.eta(), hadron.phi(), o2::constants::physics::MassPionCharged); @@ -6586,6 +6643,13 @@ void VarManager::FillSingleDileptonCharmHadron(Cand const& candidate, H hfHelper values[kRapCharmHadron] = hfHelper.yD0(candidate); values[kBdtCharmHadron] = static_cast(bdtScoreCharmHad); } + if constexpr (partType == kDplusToPiKPi) { + values[kMassCharmHadron] = hfHelper.invMassDplusToPiKPi(candidate); + values[kPtCharmHadron] = candidate.pt(); + values[kPhiCharmHadron] = candidate.phi(); + values[kRapCharmHadron] = hfHelper.yDplus(candidate); + values[kBdtCharmHadron] = static_cast(bdtScoreCharmHad); + } } template @@ -7183,6 +7247,12 @@ void VarManager::FillEventAlice3(T const& event, float* values) values[kVtxChi2] = event.chi2(); values[kCollisionTime] = event.collisionTime(); values[kCollisionTimeRes] = event.collisionTimeRes(); + values[kCent] = event.centRun2V0M(); + values[kMultPV] = event.multNTracksPV(); + values[kMultPVeta1] = event.multNTracksPVeta1(); + values[kMultPVetaHalf] = event.multNTracksPVetaHalf(); + values[kMultGlobalTracks] = event.multNTracksGlobal(); + values[kMultGlobalTracksPV] = event.multNGlobalTracksPV(); } if constexpr ((fillMap & ReducedEvent) > 0) { @@ -7193,6 +7263,12 @@ void VarManager::FillEventAlice3(T const& event, float* values) values[kVtxNcontrib] = event.numContrib(); values[kCollisionTime] = event.collisionTime(); values[kCollisionTimeRes] = event.collisionTimeRes(); + values[kCent] = event.centRun2V0M(); + values[kMultPV] = event.multNTracksPV(); + values[kMultPVeta1] = event.multNTracksPVeta1(); + values[kMultPVetaHalf] = event.multNTracksPVetaHalf(); + values[kMultGlobalTracks] = event.multNTracksGlobal(); + values[kMultGlobalTracksPV] = event.multNGlobalTracksPV(); } if constexpr ((fillMap & ReducedEventVtxCov) > 0) { values[kVtxCovXX] = event.covXX(); @@ -7213,6 +7289,10 @@ void VarManager::FillEventAlice3(T const& event, float* values) values[kMCEventTime] = event.t(); values[kMCEventWeight] = event.weight(); values[kMCEventImpParam] = event.impactParameter(); + values[kMultMCNParticlesAll] = event.multMC(); + values[kMultMCNParticlesEta25] = event.multMC25(); + values[kMultMCNParticlesEta125] = event.multMC125(); + values[kMultMCNParticlesEta09] = event.multMC09(); } if constexpr ((fillMap & ReducedEventMC) > 0) { @@ -7224,6 +7304,10 @@ void VarManager::FillEventAlice3(T const& event, float* values) values[kMCEventTime] = event.t(); values[kMCEventWeight] = event.weight(); values[kMCEventImpParam] = event.impactParameter(); + values[kMultMCNParticlesAll] = event.multMC(); + values[kMultMCNParticlesEta25] = event.multMC25(); + values[kMultMCNParticlesEta125] = event.multMC125(); + values[kMultMCNParticlesEta09] = event.multMC09(); } } diff --git a/PWGDQ/DataModel/ReducedInfoTables.h b/PWGDQ/DataModel/ReducedInfoTables.h index e9efc3ddd89..ffd96c9b267 100644 --- a/PWGDQ/DataModel/ReducedInfoTables.h +++ b/PWGDQ/DataModel/ReducedInfoTables.h @@ -1338,32 +1338,44 @@ DECLARE_SOA_COLUMN(DeltaY, deltaY, float); DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); //! DECLARE_SOA_COLUMN(NumItsClsDmesProng0, numItsClsDmesProng0, int); //! DECLARE_SOA_COLUMN(NumItsClsDmesProng1, numItsClsDmesProng1, int); //! +DECLARE_SOA_COLUMN(NumItsClsDmesProng2, numItsClsDmesProng2, int); //! DECLARE_SOA_COLUMN(NumTpcCrossedRowsDmesProng0, numTpcCrossedRowsDmesProng0, int); //! DECLARE_SOA_COLUMN(NumTpcCrossedRowsDmesProng1, numTpcCrossedRowsDmesProng1, int); //! +DECLARE_SOA_COLUMN(NumTpcCrossedRowsDmesProng2, numTpcCrossedRowsDmesProng2, int); //! DECLARE_SOA_COLUMN(EtaDmesProng0, etaDmesProng0, float); //! DECLARE_SOA_COLUMN(EtaDmesProng1, etaDmesProng1, float); //! +DECLARE_SOA_COLUMN(EtaDmesProng2, etaDmesProng2, float); //! DECLARE_SOA_COLUMN(PtDmesProng0, ptDmesProng0, float); //! DECLARE_SOA_COLUMN(PtDmesProng1, ptDmesProng1, float); //! +DECLARE_SOA_COLUMN(PtDmesProng2, ptDmesProng2, float); //! DECLARE_SOA_COLUMN(MinNumItsClsDmesProng, minNumItsClsDmesProng, int); //! DECLARE_SOA_COLUMN(MinNumTpcCrossedRowsDmesProng, minNumTpcCrossedRowsDmesProng, int); //! DECLARE_SOA_COLUMN(MinAbsEtaDmesProng, minAbsEtaDmesProng, float); //! DECLARE_SOA_COLUMN(MinPtDmesProng, minPtDmesProng, float); //! DECLARE_SOA_COLUMN(NumSigmaTpcPiProng0, numSigmaTpcPiProng0, float); //! DECLARE_SOA_COLUMN(NumSigmaTpcPiProng1, numSigmaTpcPiProng1, float); //! +DECLARE_SOA_COLUMN(NumSigmaTpcPiProng2, numSigmaTpcPiProng2, float); //! DECLARE_SOA_COLUMN(NumSigmaTofPiProng0, numSigmaTofPiProng0, float); //! DECLARE_SOA_COLUMN(NumSigmaTofPiProng1, numSigmaTofPiProng1, float); //! +DECLARE_SOA_COLUMN(NumSigmaTofPiProng2, numSigmaTofPiProng2, float); //! DECLARE_SOA_COLUMN(NumSigmaTpcKaProng0, numSigmaTpcKaProng0, float); //! DECLARE_SOA_COLUMN(NumSigmaTpcKaProng1, numSigmaTpcKaProng1, float); //! +DECLARE_SOA_COLUMN(NumSigmaTpcKaProng2, numSigmaTpcKaProng2, float); //! DECLARE_SOA_COLUMN(NumSigmaTofKaProng0, numSigmaTofKaProng0, float); //! DECLARE_SOA_COLUMN(NumSigmaTofKaProng1, numSigmaTofKaProng1, float); //! +DECLARE_SOA_COLUMN(NumSigmaTofKaProng2, numSigmaTofKaProng2, float); //! DECLARE_SOA_DYNAMIC_COLUMN(NumSigmaTpcTofPiProng0, numSigmaTpcTofPiProng0, //! [](float tpcNSigmaPi0, float tofNSigmaPi0) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPi0, tofNSigmaPi0); }); DECLARE_SOA_DYNAMIC_COLUMN(NumSigmaTpcTofPiProng1, numSigmaTpcTofPiProng1, //! [](float tpcNSigmaPi1, float tofNSigmaPi1) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPi1, tofNSigmaPi1); }); +DECLARE_SOA_DYNAMIC_COLUMN(NumSigmaTpcTofPiProng2, numSigmaTpcTofPiProng2, //! + [](float tpcNSigmaPi2, float tofNSigmaPi2) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaPi2, tofNSigmaPi2); }); DECLARE_SOA_DYNAMIC_COLUMN(NumSigmaTpcTofKaProng0, numSigmaTpcTofKaProng0, //! [](float tpcNSigmaKa0, float tofNSigmaKa0) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaKa0, tofNSigmaKa0); }); DECLARE_SOA_DYNAMIC_COLUMN(NumSigmaTpcTofKaProng1, numSigmaTpcTofKaProng1, //! [](float tpcNSigmaKa1, float tofNSigmaKa1) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaKa1, tofNSigmaKa1); }); +DECLARE_SOA_DYNAMIC_COLUMN(NumSigmaTpcTofKaProng2, numSigmaTpcTofKaProng2, //! + [](float tpcNSigmaKa2, float tofNSigmaKa2) -> float { return pid_tpc_tof_utils::combineNSigma(tpcNSigmaKa2, tofNSigmaKa2); }); } // namespace jpsidmescorr DECLARE_SOA_TABLE(RedJpDmDileptons, "AOD", "REDJPDMDILEPTON", //! @@ -1418,6 +1430,23 @@ DECLARE_SOA_TABLE(RedJpDmDmDau1s, "AOD", "REDJPDMDMDAU1", //! jpsidmescorr::NumSigmaTpcTofPiProng1, jpsidmescorr::NumSigmaTpcTofKaProng1); +DECLARE_SOA_TABLE(RedJpDmDmDau2s, "AOD", "REDJPDMDMDAU2", //! + jpsidmescorr::PtDmesProng2, + jpsidmescorr::EtaDmesProng2, + jpsidmescorr::NumItsClsDmesProng2, + jpsidmescorr::NumTpcCrossedRowsDmesProng2, + jpsidmescorr::NumSigmaTpcPiProng2, + jpsidmescorr::NumSigmaTofPiProng2, + jpsidmescorr::NumSigmaTpcKaProng2, + jpsidmescorr::NumSigmaTofKaProng2, + jpsidmescorr::NumSigmaTpcTofPiProng2, + jpsidmescorr::NumSigmaTpcTofKaProng2); + +// General table for Dmeson mass +DECLARE_SOA_TABLE(RedJpDmDmesMasss, "AOD", "REDJPDMDMESMASS", //??? + jpsidmescorr::MassDmes); + +// Special table for D0 mass: particle and antiparticle separated DECLARE_SOA_TABLE(RedJpDmD0Masss, "AOD", "REDJPDMD0MASS", //! jpsidmescorr::MassD0, jpsidmescorr::MassD0bar); @@ -1430,6 +1459,11 @@ DECLARE_SOA_TABLE(RedJpDmDmesBdts, "AOD", "REDJPDMDMESBDT", //! jpsidmescorr::BdtPromptMassHypo1, jpsidmescorr::BdtNonpromptMassHypo1); +DECLARE_SOA_TABLE(RedJpDmDplusBdts, "AOD", "REDJPDMDPLUSBDT", + jpsidmescorr::BdtBkgMassHypo0, + jpsidmescorr::BdtPromptMassHypo0, + jpsidmescorr::BdtNonpromptMassHypo0); + DECLARE_SOA_TABLE(RedDleptDmesAll, "AOD", "RTDILPTDMESALL", //! reducedpair::Mass, jpsidmescorr::MassDmes, diff --git a/PWGDQ/Macros/dqFlowAccWeights.C b/PWGDQ/Macros/dqFlowAccWeights.C index d4786089810..8df81ff38e1 100644 --- a/PWGDQ/Macros/dqFlowAccWeights.C +++ b/PWGDQ/Macros/dqFlowAccWeights.C @@ -32,7 +32,7 @@ using namespace o2; using namespace std; -void dqFlowAccWeights(int64_t tmin = 1546300800000, int64_t tmax = 1577833200000, std::string Period = "LHC23zzh_pass2", std::string SubDir = "d-q-event-qvector", std::string FileName = "AnalysisResults.root") +void dqFlowAccWeights(int64_t tmin = 1546300800000, int64_t tmax = 1577833200000, const std::string& Period = "LHC23zzh_pass2", const std::string& SubDir = "d-q-event-qvector", const std::string& FileName = "AnalysisResults.root") { if (tmax < tmin) { LOG(fatal) << "Wrong validity syntax!"; @@ -64,7 +64,7 @@ void dqFlowAccWeights(int64_t tmin = 1546300800000, int64_t tmax = 1577833200000 if (!ccdbHost.empty()) { LOGP(info, "Storing alignment object on {}/{}", ccdbHost, objectPath); o2::ccdb::CcdbApi api; - map metadata; // can be empty + std::map metadata; // can be empty metadata.insert(std::pair{"comment", Form("Acceptance weights for %s", Period.c_str())}); api.init(ccdbHost.c_str()); try { diff --git a/PWGDQ/TableProducer/tableMaker.cxx b/PWGDQ/TableProducer/tableMaker.cxx index f2938705e87..15edcac01ec 100644 --- a/PWGDQ/TableProducer/tableMaker.cxx +++ b/PWGDQ/TableProducer/tableMaker.cxx @@ -1246,7 +1246,7 @@ struct TableMaker { } // end if constexpr (TMuonFillMap) } // end fullSkimming() - void DefineHistograms(TString histClasses) + void DefineHistograms(const TString& histClasses) { std::unique_ptr objArray(histClasses.Tokenize(";")); for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { diff --git a/PWGDQ/TableProducer/tableMakerJpsiHf.cxx b/PWGDQ/TableProducer/tableMakerJpsiHf.cxx index c5569ae7e14..59b06e3ef64 100644 --- a/PWGDQ/TableProducer/tableMakerJpsiHf.cxx +++ b/PWGDQ/TableProducer/tableMakerJpsiHf.cxx @@ -55,6 +55,7 @@ using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::aod; using namespace o2::aod::hf_cand_2prong; +using namespace o2::aod::hf_cand_3prong; // bit maps used for the Fill functions of the VarManager constexpr static uint32_t gkTrackFillMapWithColl = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelPID | VarManager::ObjTypes::ReducedTrackCollInfo; @@ -94,6 +95,8 @@ struct CandidateDilepton { using MyEvents = soa::Join; using MyD0CandidatesSelected = soa::Join; using MyD0CandidatesSelectedWithBdt = soa::Join; +using MyDplusCandidatesSelected = soa::Join; +using MyDplusCandidatesSelectedWithBdt = soa::Join; using TracksWithExtra = soa::Join; using MyBarrelTracksSelectedWithColl = soa::Join; @@ -111,8 +114,11 @@ struct tableMakerJpsiHf { Produces redDmesons; Produces redDmesDau0; Produces redDmesDau1; + Produces redDmesDau2; Produces redDmesBdts; + Produces redDplusBdts; Produces redD0Masses; + Produces redDmesMasses; Produces redDileptons; Produces redCollCounter; @@ -125,17 +131,26 @@ struct tableMakerJpsiHf { Configurable fConfigMuonCuts{"cfgMuonCuts", "muonQualityCuts", "Comma separated list of muon cuts"}; Configurable massDileptonCandMin{"massDileptonCandMin", 1, "minimum dilepton mass"}; Configurable massDileptonCandMax{"massDileptonCandMax", 5, "maximum dilepton mass"}; + // General configurables - Configurable configDebug{"configDebug", true, "If true, fill D0 - J/psi histograms separately"}; + Configurable configDebug{"configDebug", true, "If true, fill D - J/psi histograms separately"}; Configurable storeTableForNorm{"storeTableForNorm", true, "If true, store a table with number of processed collisions for normalisation"}; - Preslice perCollisionDmeson = aod::hf_cand::collisionId; - Preslice perCollisionDmesonWithBdt = aod::hf_cand::collisionId; + enum class DmesonType { + D0, + Dplus + }; + + Preslice perCollisionD0 = aod::hf_cand::collisionId; + Preslice perCollisionD0WithBdt = aod::hf_cand::collisionId; + Preslice perCollisionDplus = aod::hf_cand::collisionId; + Preslice perCollisionDplusWithBdt = aod::hf_cand::collisionId; PresliceUnsorted perCollisionMuons = aod::reducedmuon::collisionId; PresliceUnsorted perCollisionElectrons = aod::reducedtrack::collisionId; SliceCache cache; Filter filterD0Candidates = aod::hf_sel_candidate_d0::isSelD0 >= 1 || aod::hf_sel_candidate_d0::isSelD0bar >= 1; + Filter filterDplusCandidates = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= 1; // Define histograms manager float* fValuesDileptonCharmHadron{}; @@ -147,7 +162,7 @@ struct tableMakerJpsiHf { void init(o2::framework::InitContext&) { - std::array doprocess{doprocessJspiToMuMuD0, doprocessJspiToMuMuD0WithBdt, doprocessJspiToEED0, doprocessJspiToEED0WithBdt}; + std::array doprocess{doprocessJspiToMuMuD0, doprocessJspiToMuMuD0WithBdt, doprocessJspiToEED0, doprocessJspiToEED0WithBdt, doprocessJspiToMuMuDplus, doprocessJspiToMuMuDplusWithBdt, doprocessJspiToEEDplus, doprocessJspiToEEDplusWithBdt}; if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) != 1) { LOGP(fatal, "Only one process function should be enabled! Please check your configuration!"); } @@ -161,11 +176,11 @@ struct tableMakerJpsiHf { fHistMan->AddHistClass("JPsi"); fHistMan->AddHistClass("JPsiDmeson"); dqhistograms::DefineHistograms(fHistMan, "Dmeson", "dilepton-charmhadron", "dmeson"); - if (doprocessJspiToMuMuD0 || doprocessJspiToMuMuD0WithBdt) { + if (doprocessJspiToMuMuD0 || doprocessJspiToMuMuD0WithBdt || doprocessJspiToMuMuDplus || doprocessJspiToMuMuDplusWithBdt) { dqhistograms::DefineHistograms(fHistMan, "JPsi", "dilepton-charmhadron", "jpsitomumu"); dqhistograms::DefineHistograms(fHistMan, "JPsiDmeson", "dilepton-charmhadron", "jpsitomumudmeson"); } - if (doprocessJspiToEED0 || doprocessJspiToEED0WithBdt) { + if (doprocessJspiToEED0 || doprocessJspiToEED0WithBdt || doprocessJspiToEEDplus || doprocessJspiToEEDplusWithBdt) { dqhistograms::DefineHistograms(fHistMan, "JPsi", "dilepton-charmhadron", "jpsitoee"); dqhistograms::DefineHistograms(fHistMan, "JPsiDmeson", "dilepton-charmhadron", "jpsitoeedmeson"); } @@ -173,7 +188,7 @@ struct tableMakerJpsiHf { fOutputList.setObject(fHistMan->GetMainHistogramList()); // cut strings - if (doprocessJspiToMuMuD0 || doprocessJspiToMuMuD0WithBdt) { + if (doprocessJspiToMuMuD0 || doprocessJspiToMuMuD0WithBdt || doprocessJspiToMuMuDplus || doprocessJspiToMuMuDplusWithBdt) { TString cutNamesMuon = fConfigMuonCuts.value; if (!cutNamesMuon.IsNull()) { std::unique_ptr objArray(cutNamesMuon.Tokenize(",")); @@ -182,7 +197,7 @@ struct tableMakerJpsiHf { } } } - if (doprocessJspiToEED0 || doprocessJspiToEED0WithBdt) { + if (doprocessJspiToEED0 || doprocessJspiToEED0WithBdt || doprocessJspiToEEDplus || doprocessJspiToEEDplusWithBdt) { TString cutNamesElectron = fConfigTrackCuts.value; if (!cutNamesElectron.IsNull()) { // if track cuts std::unique_ptr objArray(cutNamesElectron.Tokenize(",")); @@ -262,8 +277,8 @@ struct tableMakerJpsiHf { } // Template function to run pair - hadron combinations - // TODO: generalise to all charm-hadron species - template + // Charm-hadrons: D0, Dplus; can be extended to other species + template void runDileptonDmeson(TDqTrack const& leptons, THfTrack const& dmesons, MyEvents::iterator const& collision, TracksWithExtra const&) { VarManager::ResetValues(0, VarManager::kNVars, fValuesDileptonCharmHadron); @@ -271,12 +286,18 @@ struct tableMakerJpsiHf { bool isCollSel{false}; if (configDebug) { for (auto const& dmeson : dmesons) { - if (!TESTBIT(dmeson.hfflag(), DecayType::D0ToPiK)) { - continue; + if constexpr (TDmeson == DmesonType::D0) { + if (!TESTBIT(dmeson.hfflag(), hf_cand_2prong::DecayType::D0ToPiK)) { + continue; + } + } else if constexpr (TDmeson == DmesonType::Dplus) { + if (!TESTBIT(dmeson.hfflag(), hf_cand_3prong::DecayType::DplusToPiKPi)) { + continue; + } } std::array scores = {999., -999., -999., 999., -999., -999.}; // D0 + D0bar - if constexpr (withBdt) { + if constexpr (withBdt && TDmeson == DmesonType::D0) { if (dmeson.mlProbD0().size() == 3) { for (auto iScore{0u}; iScore < dmeson.mlProbD0().size(); ++iScore) { scores[iScore] = dmeson.mlProbD0()[iScore]; @@ -289,21 +310,43 @@ struct tableMakerJpsiHf { } } - auto rapD0 = hfHelper.yD0(dmeson); + std::array scores_dplus = {999., -999., -999.}; // Dplus + if constexpr (withBdt && TDmeson == DmesonType::Dplus) { + if (dmeson.mlProbDplusToPiKPi().size() == 3) { + for (auto iScore{0u}; iScore < dmeson.mlProbDplusToPiKPi().size(); ++iScore) { + scores_dplus[iScore] = dmeson.mlProbDplusToPiKPi()[iScore]; + } + } + } - if (yCandDmesonMax >= 0. && std::abs(rapD0) > yCandDmesonMax) { - continue; + double rapDmeson = -999.; + if constexpr (TDmeson == DmesonType::D0) { + rapDmeson = hfHelper.yD0(dmeson); + } else if constexpr (TDmeson == DmesonType::Dplus) { + rapDmeson = hfHelper.yDplus(dmeson); } - if (dmeson.isSelD0() >= 1) { - VarManager::FillSingleDileptonCharmHadron(dmeson, hfHelper, scores[0], fValuesDileptonCharmHadron); - fHistMan->FillHistClass("Dmeson", fValuesDileptonCharmHadron); - VarManager::ResetValues(0, VarManager::kNVars, fValuesDileptonCharmHadron); + if (yCandDmesonMax >= 0. && std::abs(rapDmeson) > yCandDmesonMax) { + continue; } - if (dmeson.isSelD0bar() >= 1) { - VarManager::FillSingleDileptonCharmHadron(dmeson, hfHelper, scores[3], fValuesDileptonCharmHadron); - fHistMan->FillHistClass("Dmeson", fValuesDileptonCharmHadron); - VarManager::ResetValues(0, VarManager::kNVars, fValuesDileptonCharmHadron); + + if constexpr (TDmeson == DmesonType::D0) { + if (dmeson.isSelD0() >= 1) { + VarManager::FillSingleDileptonCharmHadron(dmeson, hfHelper, scores[0], fValuesDileptonCharmHadron); + fHistMan->FillHistClass("Dmeson", fValuesDileptonCharmHadron); + VarManager::ResetValues(0, VarManager::kNVars, fValuesDileptonCharmHadron); + } + if (dmeson.isSelD0bar() >= 1) { + VarManager::FillSingleDileptonCharmHadron(dmeson, hfHelper, scores[3], fValuesDileptonCharmHadron); + fHistMan->FillHistClass("Dmeson", fValuesDileptonCharmHadron); + VarManager::ResetValues(0, VarManager::kNVars, fValuesDileptonCharmHadron); + } + } else if constexpr (TDmeson == DmesonType::Dplus) { + if (dmeson.isSelDplusToPiKPi() >= 1) { + VarManager::FillSingleDileptonCharmHadron(dmeson, hfHelper, scores_dplus[0], fValuesDileptonCharmHadron); + fHistMan->FillHistClass("Dmeson", fValuesDileptonCharmHadron); + VarManager::ResetValues(0, VarManager::kNVars, fValuesDileptonCharmHadron); + } } } } @@ -330,8 +373,14 @@ struct tableMakerJpsiHf { // loop over D mesons for (auto const& dmeson : dmesons) { - if (!TESTBIT(dmeson.hfflag(), DecayType::D0ToPiK)) { - continue; + if constexpr (TDmeson == DmesonType::D0) { + if (!TESTBIT(dmeson.hfflag(), hf_cand_2prong::DecayType::D0ToPiK)) { + continue; + } + } else if constexpr (TDmeson == DmesonType::Dplus) { + if (!TESTBIT(dmeson.hfflag(), hf_cand_3prong::DecayType::DplusToPiKPi)) { + continue; + } } int dmesonIdx = dmeson.globalIndex(); @@ -340,16 +389,29 @@ struct tableMakerJpsiHf { isDmesonFilled = true; } - auto rapD0 = hfHelper.yD0(dmeson); + double rapDmeson = -999.; + if constexpr (TDmeson == DmesonType::D0) { + rapDmeson = hfHelper.yD0(dmeson); + } else if constexpr (TDmeson == DmesonType::Dplus) { + rapDmeson = hfHelper.yDplus(dmeson); + } - if (yCandDmesonMax >= 0. && std::abs(rapD0) > yCandDmesonMax) { + if (yCandDmesonMax >= 0. && std::abs(rapDmeson) > yCandDmesonMax) { continue; } auto massD0 = -1.; auto massD0bar = -1.; + auto massDplus = -1.; + + bool isSelectedDmeson{false}; + if constexpr (TDmeson == DmesonType::D0) { + isSelectedDmeson = dmeson.isSelD0() >= 1 || dmeson.isSelD0bar() >= 1; + } else if constexpr (TDmeson == DmesonType::Dplus) { + isSelectedDmeson = dmeson.isSelDplusToPiKPi() >= 1; + } - if (dmeson.isSelD0() >= 1 || dmeson.isSelD0bar() >= 1) { + if (isSelectedDmeson) { if (!isCollSel) { redCollisions(collision.posX(), collision.posY(), collision.posZ(), collision.numContrib()); isCollSel = true; @@ -370,10 +432,16 @@ struct tableMakerJpsiHf { // one table for each daughter with single track variables redDmesDau0(trackProng0.pt(), trackProng0.eta(), trackProng0.itsNCls(), trackProng0.tpcNClsCrossedRows(), dmeson.nSigTpcPi0(), dmeson.nSigTofPi0(), dmeson.nSigTpcKa0(), dmeson.nSigTofKa0()); redDmesDau1(trackProng1.pt(), trackProng1.eta(), trackProng1.itsNCls(), trackProng1.tpcNClsCrossedRows(), dmeson.nSigTpcPi1(), dmeson.nSigTofPi1(), dmeson.nSigTpcKa1(), dmeson.nSigTofKa1()); + + if constexpr (TDmeson == DmesonType::Dplus) { + auto trackProng2 = dmeson.template prong2_as(); + redDmesDau2(trackProng2.pt(), trackProng2.eta(), trackProng2.itsNCls(), trackProng2.tpcNClsCrossedRows(), dmeson.nSigTpcPi2(), dmeson.nSigTofPi2(), dmeson.nSigTpcKa2(), dmeson.nSigTofKa2()); + } filledDmesonIds.push_back(dmesonIdx); } + std::array scores = {999., -999., -999., 999., -999., -999.}; // D0 + D0bar - if constexpr (withBdt) { + if constexpr (withBdt && TDmeson == DmesonType::D0) { if (!isDmesonFilled) { if (dmeson.mlProbD0().size() == 3) { for (auto iScore{0u}; iScore < dmeson.mlProbD0().size(); ++iScore) { @@ -389,20 +457,44 @@ struct tableMakerJpsiHf { } } - if (dmeson.isSelD0() >= 1) { - massD0 = hfHelper.invMassD0ToPiK(dmeson); - VarManager::FillDileptonCharmHadron(dilepton, dmeson, hfHelper, scores[0], fValuesDileptonCharmHadron); - fHistMan->FillHistClass("JPsiDmeson", fValuesDileptonCharmHadron); - VarManager::ResetValues(0, VarManager::kNVars, fValuesDileptonCharmHadron); - } - if (dmeson.isSelD0bar() >= 1) { - massD0bar = hfHelper.invMassD0barToKPi(dmeson); - VarManager::FillDileptonCharmHadron(dilepton, dmeson, hfHelper, scores[3], fValuesDileptonCharmHadron); - fHistMan->FillHistClass("JPsiDmeson", fValuesDileptonCharmHadron); - VarManager::ResetValues(0, VarManager::kNVars, fValuesDileptonCharmHadron); + std::array scores_dplus = {999., -999., -999.}; + if constexpr (withBdt && TDmeson == DmesonType::Dplus) { + if (!isDmesonFilled) { + if (dmeson.mlProbDplusToPiKPi().size() == 3) { + for (auto iScore{0u}; iScore < dmeson.mlProbDplusToPiKPi().size(); ++iScore) { + scores_dplus[iScore] = dmeson.mlProbDplusToPiKPi()[iScore]; + } + } + redDplusBdts(scores_dplus[0], scores_dplus[1], scores_dplus[2]); + } } - if (!isDmesonFilled) { - redD0Masses(massD0, massD0bar); + + if constexpr (TDmeson == DmesonType::D0) { + if (dmeson.isSelD0() >= 1) { + massD0 = hfHelper.invMassD0ToPiK(dmeson); + VarManager::FillDileptonCharmHadron(dilepton, dmeson, hfHelper, scores[0], fValuesDileptonCharmHadron); + fHistMan->FillHistClass("JPsiDmeson", fValuesDileptonCharmHadron); + VarManager::ResetValues(0, VarManager::kNVars, fValuesDileptonCharmHadron); + } + if (dmeson.isSelD0bar() >= 1) { + massD0bar = hfHelper.invMassD0barToKPi(dmeson); + VarManager::FillDileptonCharmHadron(dilepton, dmeson, hfHelper, scores[3], fValuesDileptonCharmHadron); + fHistMan->FillHistClass("JPsiDmeson", fValuesDileptonCharmHadron); + VarManager::ResetValues(0, VarManager::kNVars, fValuesDileptonCharmHadron); + } + if (!isDmesonFilled) { + redD0Masses(massD0, massD0bar); + } + } else if constexpr (TDmeson == DmesonType::Dplus) { + if (dmeson.isSelDplusToPiKPi() >= 1) { + massDplus = hfHelper.invMassDplusToPiKPi(dmeson); + VarManager::FillDileptonCharmHadron(dilepton, dmeson, hfHelper, scores_dplus[0], fValuesDileptonCharmHadron); + fHistMan->FillHistClass("JPsiDmeson", fValuesDileptonCharmHadron); + VarManager::ResetValues(0, VarManager::kNVars, fValuesDileptonCharmHadron); + } + if (!isDmesonFilled) { + redDmesMasses(massDplus); + } } } } @@ -416,9 +508,48 @@ struct tableMakerJpsiHf { redCollCounter(collisions.size()); } for (auto const& collision : collisions) { - auto groupedDmesonCandidates = selectedD0Candidates.sliceBy(perCollisionDmeson, collision.globalIndex()); + auto groupedDmesonCandidates = selectedD0Candidates.sliceBy(perCollisionD0, collision.globalIndex()); + auto groupedLeptonCandidates = muonCandidates.sliceBy(perCollisionMuons, collision.globalIndex()); + runDileptonDmeson(groupedLeptonCandidates, groupedDmesonCandidates, collision, barrelTracks); + } + } + + // process J/psi(->mumu) - D0 adding the BDT output scores to the D0 table + void processJspiToMuMuD0WithBdt(MyEvents const& collisions, MyMuonTracksSelectedWithColl const& muonCandidates, soa::Filtered const& selectedD0Candidates, TracksWithExtra const& barrelTracks) + { + if (storeTableForNorm) { + redCollCounter(collisions.size()); + } + for (auto const& collision : collisions) { + auto groupedDmesonCandidates = selectedD0Candidates.sliceBy(perCollisionD0WithBdt, collision.globalIndex()); + auto groupedLeptonCandidates = muonCandidates.sliceBy(perCollisionMuons, collision.globalIndex()); + runDileptonDmeson(groupedLeptonCandidates, groupedDmesonCandidates, collision, barrelTracks); + } + } + + // process J/psi(->mumu) - Dplus + void processJspiToMuMuDplus(MyEvents const& collisions, MyMuonTracksSelectedWithColl const& muonCandidates, soa::Filtered const& selectedDplusCandidates, TracksWithExtra const& barrelTracks) + { + if (storeTableForNorm) { + redCollCounter(collisions.size()); + } + for (auto const& collision : collisions) { + auto groupedDmesonCandidates = selectedDplusCandidates.sliceBy(perCollisionDplus, collision.globalIndex()); + auto groupedLeptonCandidates = muonCandidates.sliceBy(perCollisionMuons, collision.globalIndex()); + runDileptonDmeson(groupedLeptonCandidates, groupedDmesonCandidates, collision, barrelTracks); + } + } + + // process J/psi(->mumu) - Dplus adding the BDT output scores to the D0 table + void processJspiToMuMuDplusWithBdt(MyEvents const& collisions, MyMuonTracksSelectedWithColl const& muonCandidates, soa::Filtered const& selectedDplusCandidates, TracksWithExtra const& barrelTracks) + { + if (storeTableForNorm) { + redCollCounter(collisions.size()); + } + for (auto const& collision : collisions) { + auto groupedDmesonCandidates = selectedDplusCandidates.sliceBy(perCollisionDplusWithBdt, collision.globalIndex()); auto groupedLeptonCandidates = muonCandidates.sliceBy(perCollisionMuons, collision.globalIndex()); - runDileptonDmeson(groupedLeptonCandidates, groupedDmesonCandidates, collision, barrelTracks); + runDileptonDmeson(groupedLeptonCandidates, groupedDmesonCandidates, collision, barrelTracks); } } @@ -429,42 +560,59 @@ struct tableMakerJpsiHf { redCollCounter(collisions.size()); } for (auto const& collision : collisions) { - auto groupedDmesonCandidates = selectedD0Candidates.sliceBy(perCollisionDmeson, collision.globalIndex()); + auto groupedDmesonCandidates = selectedD0Candidates.sliceBy(perCollisionD0, collision.globalIndex()); auto groupedLeptonCandidates = electronCandidates.sliceBy(perCollisionElectrons, collision.globalIndex()); - runDileptonDmeson(groupedLeptonCandidates, groupedDmesonCandidates, collision, barrelTracks); + runDileptonDmeson(groupedLeptonCandidates, groupedDmesonCandidates, collision, barrelTracks); } } - // process J/psi(->mumu) - D0 adding the BDT output scores to the D0 table - void processJspiToMuMuD0WithBdt(MyEvents const& collisions, MyMuonTracksSelectedWithColl const& muonCandidates, soa::Filtered const& selectedD0CandidatesWithBdt, TracksWithExtra const& barrelTracks) + // process J/psi(->ee) - D0 adding the BDT output scores to the D0 table + void processJspiToEED0WithBdt(MyEvents const& collisions, MyBarrelTracksSelectedWithColl const& electronCandidates, soa::Filtered const& selectedD0Candidates, TracksWithExtra const& barrelTracks) { if (storeTableForNorm) { redCollCounter(collisions.size()); } for (auto const& collision : collisions) { - auto groupedDmesonCandidates = selectedD0CandidatesWithBdt.sliceBy(perCollisionDmesonWithBdt, collision.globalIndex()); - auto groupedLeptonCandidates = muonCandidates.sliceBy(perCollisionMuons, collision.globalIndex()); - runDileptonDmeson(groupedLeptonCandidates, groupedDmesonCandidates, collision, barrelTracks); + auto groupedDmesonCandidates = selectedD0Candidates.sliceBy(perCollisionD0WithBdt, collision.globalIndex()); + auto groupedLeptonCandidates = electronCandidates.sliceBy(perCollisionElectrons, collision.globalIndex()); + runDileptonDmeson(groupedLeptonCandidates, groupedDmesonCandidates, collision, barrelTracks); } } - // process J/psi(->ee) - D0 adding the BDT output scores to the D0 table - void processJspiToEED0WithBdt(MyEvents const& collisions, MyBarrelTracksSelectedWithColl const& electronCandidates, soa::Filtered const& selectedD0CandidatesWithBdt, TracksWithExtra const& barrelTracks) + // process J/psi(->ee) - Dplus adding the BDT output scores to the D0 table + void processJspiToEEDplus(MyEvents const& collisions, MyBarrelTracksSelectedWithColl const& electronCandidates, soa::Filtered const& selectedDplusCandidates, TracksWithExtra const& barrelTracks) + { + if (storeTableForNorm) { + redCollCounter(collisions.size()); + } + for (auto const& collision : collisions) { + auto groupedDmesonCandidates = selectedDplusCandidates.sliceBy(perCollisionDplus, collision.globalIndex()); + auto groupedLeptonCandidates = electronCandidates.sliceBy(perCollisionElectrons, collision.globalIndex()); + runDileptonDmeson(groupedLeptonCandidates, groupedDmesonCandidates, collision, barrelTracks); + } + } + + // process J/psi(->ee) - Dplus with BDT + void processJspiToEEDplusWithBdt(MyEvents const& collisions, MyBarrelTracksSelectedWithColl const& electronCandidates, soa::Filtered const& selectedDplusCandidates, TracksWithExtra const& barrelTracks) { if (storeTableForNorm) { redCollCounter(collisions.size()); } for (auto const& collision : collisions) { - auto groupedDmesonCandidates = selectedD0CandidatesWithBdt.sliceBy(perCollisionDmesonWithBdt, collision.globalIndex()); auto groupedLeptonCandidates = electronCandidates.sliceBy(perCollisionElectrons, collision.globalIndex()); - runDileptonDmeson(groupedLeptonCandidates, groupedDmesonCandidates, collision, barrelTracks); + auto groupedDmesonCandidates = selectedDplusCandidates.sliceBy(perCollisionDplusWithBdt, collision.globalIndex()); + runDileptonDmeson(groupedLeptonCandidates, groupedDmesonCandidates, collision, barrelTracks); } } PROCESS_SWITCH(tableMakerJpsiHf, processJspiToMuMuD0, "Process J/psi(->mumu) - D0", false); PROCESS_SWITCH(tableMakerJpsiHf, processJspiToEED0, "Process J/psi(->ee) - D0", false); PROCESS_SWITCH(tableMakerJpsiHf, processJspiToMuMuD0WithBdt, "Process J/psi(->mumu) - D0 with BDT", false); + PROCESS_SWITCH(tableMakerJpsiHf, processJspiToMuMuDplus, "Process J/psi(->mumu) - Dplus", false); + PROCESS_SWITCH(tableMakerJpsiHf, processJspiToMuMuDplusWithBdt, "Process J/psi(->mumu) - Dplus with BDT", false); PROCESS_SWITCH(tableMakerJpsiHf, processJspiToEED0WithBdt, "Process J/psi(->ee) - D0 with BDT", false); + PROCESS_SWITCH(tableMakerJpsiHf, processJspiToEEDplus, "Process J/psi(->ee) - Dplus", false); + PROCESS_SWITCH(tableMakerJpsiHf, processJspiToEEDplusWithBdt, "Process J/psi(->ee) - Dplus with BDT", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGDQ/TableProducer/tableMakerMC.cxx b/PWGDQ/TableProducer/tableMakerMC.cxx index 8a2d93f9f89..41e26e1a374 100644 --- a/PWGDQ/TableProducer/tableMakerMC.cxx +++ b/PWGDQ/TableProducer/tableMakerMC.cxx @@ -1534,7 +1534,7 @@ struct TableMakerMC { fEventLabels.clear(); } - void DefineHistograms(TString histClasses) + void DefineHistograms(const TString& histClasses) { std::unique_ptr objArray(histClasses.Tokenize(";")); for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { diff --git a/PWGDQ/TableProducer/tableMakerMC_withAssoc.cxx b/PWGDQ/TableProducer/tableMakerMC_withAssoc.cxx index 620de63de2f..ad9fdc91f8d 100644 --- a/PWGDQ/TableProducer/tableMakerMC_withAssoc.cxx +++ b/PWGDQ/TableProducer/tableMakerMC_withAssoc.cxx @@ -100,9 +100,9 @@ using MyBarrelTracksWithCov = soa::Join; -using MyMuons = soa::Join; -using MyMuonsWithCov = soa::Join; -using MyMuonsRealignWithCov = soa::Join; +using MyMuons = soa::Join; +using MyMuonsWithCov = soa::Join; +using MyMuonsRealignWithCov = soa::Join; using MyEvents = soa::Join; using MyEventsWithMults = soa::Join; @@ -144,7 +144,7 @@ template void PrintBitMap(TMap map, int nbits) { for (int i = 0; i < nbits; i++) { - cout << ((map & (TMap(1) << i)) > 0 ? "1" : "0"); + LOG(info) << ((map & (TMap(1) << i)) > 0 ? "1" : "0"); } } */ @@ -234,9 +234,6 @@ struct TableMakerMC { Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable fGeoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; Configurable fGrpMagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable fZShiftPath{"zShiftPath", "Users/m/mcoquet/ZShift", "CCDB path for z shift to apply to forward tracks"}; - Configurable fUseRemoteZShift{"cfgUseRemoteZShift", false, "Enable getting Zshift from ccdb"}; - Configurable fManualZShift{"cfgManualZShift", 0.f, "Manual value for the Zshift for muons."}; Configurable fGrpMagPathRun2{"grpmagPathRun2", "GLO/GRP/GRP", "CCDB path of the GRPObject (Usage for Run 2)"}; Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; } fConfigCCDB; @@ -580,17 +577,16 @@ struct TableMakerMC { /*if ((std::abs(mctrack.pdgCode())>400 && std::abs(mctrack.pdgCode())<599) || (std::abs(mctrack.pdgCode())>4000 && std::abs(mctrack.pdgCode())<5999) || (mcflags > 0)) { - cout << ">>>>>>>>>>>>>>>>>>>>>>> track idx / pdg / process / status code / HEPMC status / primary : " - << mctrack.globalIndex() << " / " << mctrack.pdgCode() << " / " - << mctrack.getProcess() << " / " << mctrack.getGenStatusCode() << " / " << mctrack.getHepMCStatusCode() << " / " << mctrack.isPhysicalPrimary() << endl; - cout << ">>>>>>>>>>>>>>>>>>>>>>> track bitmap: "; + LOG(info) << ">>>>>>>>>>>>>>>>>>>>>> track idx / pdg / process / status code / HEPMC status / primary : " + << mctrack.globalIndex() << " / " << mctrack.pdgCode() << " / " + << mctrack.getProcess() << " / " << mctrack.getGenStatusCode() << " / " << mctrack.getHepMCStatusCode() << " / " << mctrack.isPhysicalPrimary(); + LOG(info) << ">>>>>>>>>>>>>>>>>>>>>> track bitmap: "; PrintBitMap(mcflags, 16); - cout << endl; if (mctrack.has_mothers()) { for (const auto& m : mctrack.mothersIds()) { if (m < mcTracks.size()) { // protect against bad mother indices auto aMother = mcTracks.rawIteratorAt(m); - cout << "<<<<<< mother idx / pdg: " << m << " / " << aMother.pdgCode() << endl; + LOG(info) << "<<<<<< mother idx / pdg: " << m << " / " << aMother.pdgCode(); } } } @@ -600,7 +596,7 @@ struct TableMakerMC { if (d < mcTracks.size()) { // protect against bad daughter indices auto aDaughter = mcTracks.rawIteratorAt(d); - cout << "<<<<<< daughter idx / pdg: " << d << " / " << aDaughter.pdgCode() << endl; + LOG(info) << "<<<<<< daughter idx / pdg: " << d << " / " << aDaughter.pdgCode(); } } } @@ -1133,22 +1129,29 @@ struct TableMakerMC { VarManager::FillTrack(muon); // NOTE: If a muon is associated to multiple collisions, depending on the selections, // it may be accepted for some associations and rejected for other - if (fConfigVariousOptions.fPropMuon) { + if (static_cast(muon.trackType()) > 2 && fConfigVariousOptions.fPropMuon) { VarManager::FillPropagateMuon(muon, collision); } - // recalculte pDca and global muon kinematics - if (static_cast(muon.trackType()) < 2 && fConfigVariousOptions.fRefitGlobalMuon) { + // recalculate pDca / DCA and global muon kinematics + // kMuonPDca is always taken from MCH (standalone or the MCH matched to a global) + if (static_cast(muon.trackType()) <= 2) { auto muontrack = muon.template matchMCHTrack_as(); - if (muontrack.eta() < fConfigVariousOptions.fMuonMatchEtaMin || muontrack.eta() > fConfigVariousOptions.fMuonMatchEtaMax) { - continue; - } - auto mfttrack = muon.template matchMFTTrack_as(); VarManager::FillTrackCollision(muontrack, collision); - if constexpr (static_cast(TMFTFillMap & VarManager::ObjTypes::MFTCov)) { - auto const& mfttrackcov = mfCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); - VarManager::FillGlobalMuonRefitCov(muontrack, mfttrack, collision, mfttrackcov); + if (fConfigVariousOptions.fRefitGlobalMuon) { + if (muontrack.eta() < fConfigVariousOptions.fMuonMatchEtaMin || muontrack.eta() > fConfigVariousOptions.fMuonMatchEtaMax) { + continue; + } + auto mfttrack = muon.template matchMFTTrack_as(); + // Helix DCA (kMuonDCAx/y) is filled from the refitted parameters inside FillGlobalMuonRefit(Cov) + if constexpr (static_cast(TMFTFillMap & VarManager::ObjTypes::MFTCov)) { + auto const& mfttrackcov = mfCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); + VarManager::FillGlobalMuonRefitCov(muontrack, mfttrack, collision, mfttrackcov); + } else { + VarManager::FillGlobalMuonRefit(muontrack, mfttrack, collision); + } } else { - VarManager::FillGlobalMuonRefit(muontrack, mfttrack, collision); + // Helix DCA of the global track; leaves kMuonPDca from the matched MCH above + VarManager::FillTrackCollision(muon, collision); } } else { VarManager::FillTrackCollision(muon, collision); @@ -1262,21 +1265,28 @@ struct TableMakerMC { } VarManager::FillTrack(muon); - if (fConfigVariousOptions.fPropMuon) { + if (static_cast(muon.trackType()) > 2 && fConfigVariousOptions.fPropMuon) { VarManager::FillPropagateMuon(muon, collision); } - // recalculte pDca and global muon kinematics + // recalculate pDca / DCA and global muon kinematics + // kMuonPDca is always taken from MCH (standalone or the MCH matched to a global) int globalClusters = muon.nClusters(); - if (static_cast(muon.trackType()) < 2 && fConfigVariousOptions.fRefitGlobalMuon) { + if (static_cast(muon.trackType()) <= 2) { auto muontrack = muon.template matchMCHTrack_as(); - auto mfttrack = muon.template matchMFTTrack_as(); - globalClusters += mfttrack.nClusters(); VarManager::FillTrackCollision(muontrack, collision); - if constexpr (static_cast(TMFTFillMap & VarManager::ObjTypes::MFTCov)) { - auto const& mfttrackcov = mfCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); - VarManager::FillGlobalMuonRefitCov(muontrack, mfttrack, collision, mfttrackcov); + if (fConfigVariousOptions.fRefitGlobalMuon) { + auto mfttrack = muon.template matchMFTTrack_as(); + globalClusters += mfttrack.nClusters(); + // Helix DCA (kMuonDCAx/y) is filled from the refitted parameters inside FillGlobalMuonRefit(Cov) + if constexpr (static_cast(TMFTFillMap & VarManager::ObjTypes::MFTCov)) { + auto const& mfttrackcov = mfCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); + VarManager::FillGlobalMuonRefitCov(muontrack, mfttrack, collision, mfttrackcov); + } else { + VarManager::FillGlobalMuonRefit(muontrack, mfttrack, collision); + } } else { - VarManager::FillGlobalMuonRefit(muontrack, mfttrack, collision); + // Helix DCA of the global track; leaves kMuonPDca from the matched MCH above + VarManager::FillTrackCollision(muon, collision); } } else { VarManager::FillTrackCollision(muon, collision); @@ -1323,16 +1333,6 @@ struct TableMakerMC { o2::base::Propagator::initFieldFromGRP(fGrpMag); VarManager::SetMagneticField(fGrpMag->getNominalL3Field()); } - if (fConfigCCDB.fUseRemoteZShift) { - auto* fZShift = fCCDB->getForTimeStamp>(fConfigCCDB.fZShiftPath, bcs.begin().timestamp()); - if (fZShift != nullptr && !fZShift->empty()) { - VarManager::SetZShift((*fZShift)[0]); - } else { - LOG(fatal) << "Could not retrieve Z-shift value from CCDB"; - } - } else { - VarManager::SetZShift(fConfigCCDB.fManualZShift.value); - } if (fConfigVariousOptions.fPropMuon) { VarManager::SetupMuonMagField(); } diff --git a/PWGDQ/TableProducer/tableMakerMuonMchTrkEfficiency.cxx b/PWGDQ/TableProducer/tableMakerMuonMchTrkEfficiency.cxx index 84d9a42bbbc..a499141f60d 100644 --- a/PWGDQ/TableProducer/tableMakerMuonMchTrkEfficiency.cxx +++ b/PWGDQ/TableProducer/tableMakerMuonMchTrkEfficiency.cxx @@ -246,7 +246,7 @@ struct tableMakerMuonMchTrkEfficiency { /// extrapolate tracks to a given r value (spherical coordinates) /// to mimic the (x,y) position in a given chamber - void extrapolate(TLorentzVector vec, int ich, double& x, double& y) + void extrapolate(const TLorentzVector& vec, int ich, double& x, double& y) { // i = 0..9 double zposCh[10] = {5, 5, 7, 7, 10, 10, 12.5, 12.5, 14.5, 14.5}; double theta = vec.Theta(); @@ -396,7 +396,7 @@ struct tableMakerMuonMchTrkEfficiency { /// Event selection template - void runEventSelection(TEvent event) + void runEventSelection(const TEvent& event) { VarManager::ResetValues(0, VarManager::kNEventWiseVariables); VarManager::FillEvent(event); // extract event information and place it in the fValues array diff --git a/PWGDQ/TableProducer/tableMaker_withAssoc.cxx b/PWGDQ/TableProducer/tableMaker_withAssoc.cxx index 4797235a21d..4bf71f23791 100644 --- a/PWGDQ/TableProducer/tableMaker_withAssoc.cxx +++ b/PWGDQ/TableProducer/tableMaker_withAssoc.cxx @@ -130,12 +130,12 @@ using MyEventsWithCent = soa::Join; using MyEventsWithMultsExtra = soa::Join; using MyEventsWithCentAndMultsQvect = soa::Join; -using MyMuons = soa::Join; +using MyMuons = aod::FwdTracks; using MyMuonsNoDca = soa::Join; -using MyMuonsWithCov = soa::Join; -using MyMuonsRealignWithCov = soa::Join; -using MyMuonsColl = soa::Join; -using MyMuonsCollWithCov = soa::Join; +using MyMuonsWithCov = soa::Join; +using MyMuonsRealignWithCov = soa::Join; +using MyMuonsColl = soa::Join; +using MyMuonsCollWithCov = soa::Join; using MyBCs = soa::Join; using ExtBCs = soa::Join; @@ -162,8 +162,8 @@ constexpr static uint32_t gkTrackFillMapWithV0BitsNoTOF = VarManager::ObjTypes:: constexpr static uint32_t gkTrackFillMapNoTOF = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackTPCPID; // constexpr static uint32_t gkTrackFillMapWithDalitzBits = gkTrackFillMap | VarManager::ObjTypes::DalitzBits; constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::Muon | VarManager::ObjTypes::MuonCov; -constexpr static uint32_t gkMuonFillMapWithCov = VarManager::ObjTypes::Muon | VarManager::ObjTypes::MuonCov | VarManager::ObjTypes::MuonDca; -constexpr static uint32_t gkMuonRealignFillMapWithCov = VarManager::ObjTypes::MuonRealign | VarManager::ObjTypes::MuonCovRealign | VarManager::ObjTypes::MuonDca; +constexpr static uint32_t gkMuonFillMapWithCov = VarManager::ObjTypes::Muon | VarManager::ObjTypes::MuonCov; +constexpr static uint32_t gkMuonRealignFillMapWithCov = VarManager::ObjTypes::MuonRealign | VarManager::ObjTypes::MuonCovRealign; // constexpr static uint32_t gkMuonFillMapWithAmbi = VarManager::ObjTypes::Muon | VarManager::ObjTypes::AmbiMuon; // constexpr static uint32_t gkMuonFillMapWithCovAmbi = VarManager::ObjTypes::Muon | VarManager::ObjTypes::MuonCov | VarManager::ObjTypes::AmbiMuon; // constexpr static uint32_t gkTrackFillMapWithAmbi = VarManager::ObjTypes::Track | VarManager::ObjTypes::AmbiTrack; @@ -288,9 +288,8 @@ struct TableMaker { Configurable fConfigNoLaterThan{"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 fConfigGeoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; Configurable fConfigGrpMagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable fFwdShiftPath{"fwdShiftPath", "Users/m/mcoquet/ZShift", "CCDB path for the shift to apply to forward tracks, either 1 value (z) or 3 values (x, y, z)"}; + Configurable fFwdShiftPath{"fwdShiftPath", "Users/m/mcoquet/ZShift", "CCDB path for the shift to apply to forward tracks: 1 (z), 3 (x,y,z), or 10 (x,y,z,slopeX,slopeY for top then bottom; slopes unused)"}; Configurable fUseRemoteFwdShift{"cfgUseRemoteFwdShift", false, "Enable getting the forward track shift from ccdb"}; - Configurable fManualZShift{"cfgManualZShift", 0.f, "Manual value for the Zshift for muons."}; Configurable fConfigGrpMagPathRun2{"grpmagPathRun2", "GLO/GRP/GRP", "CCDB path of the GRPObject (Usage for Run 2)"}; } fConfigCCDB; @@ -508,7 +507,7 @@ struct TableMaker { bool enableEMCalHistos = (context.mOptions.get("processPPBarrelOnlyWithEMCal") || context.mOptions.get("processPPWithEMCal")); - bool enableMuonHistos = (context.mOptions.get("processPP") || context.mOptions.get("processPPWithEMCal") || context.mOptions.get("processPPWithFilter") || context.mOptions.get("processPPWithFilterMuonOnly") || context.mOptions.get("processPPWithFilterMuonMFT") || context.mOptions.get("processPPMuonOnly") || context.mOptions.get("processPPRealignedMuonOnly") || context.mOptions.get("processPPMuonMFT") || context.mOptions.get("processPPMuonMFTWithMultsExtra") || + bool enableMuonHistos = (context.mOptions.get("processPP") || context.mOptions.get("processPPWithEMCal") || context.mOptions.get("processPPWithFilter") || context.mOptions.get("processPPWithFilterMuonOnly") || context.mOptions.get("processPPWithFilterMuonMFT") || context.mOptions.get("processPPMuonOnly") || context.mOptions.get("processPPRealignedMuonOnly") || context.mOptions.get("processPPMuonMFT") || context.mOptions.get("processPPMuonMFTWithMultsExtra") || context.mOptions.get("processPPMuonRefit") || context.mOptions.get("processPbPb") || context.mOptions.get("processPbPbMuonOnly") || context.mOptions.get("processPbPbWithFilterMuonOnly") || context.mOptions.get("processPbPbStreamMuonOnly") || context.mOptions.get("processPbPbRealignedMuonOnly") || context.mOptions.get("processPbPbMuonMFT")); if (enableBarrelHistos) { @@ -1558,7 +1557,7 @@ struct TableMaker { float deltaR2 = deltaEta * deltaEta + deltaPhi * deltaPhi; auto existing = fTrackEMCalMatchMap.find(match.trackId()); if (existing == fTrackEMCalMatchMap.end() || deltaR2 < existing->second.deltaR2) { - fTrackEMCalMatchMap[match.trackId()] = EMCalMatch{static_cast(outTables.emcal.lastIndex()), deltaEta, deltaPhi, deltaR2}; + fTrackEMCalMatchMap[match.trackId()] = EMCalMatch{.clusterIdx = static_cast(outTables.emcal.lastIndex()), .deltaEta = deltaEta, .deltaPhi = deltaPhi, .deltaR2 = deltaR2}; } } } // end loop over clusters @@ -1687,24 +1686,29 @@ struct TableMaker { // NOTE: Muons are propagated to the current associated collisions. // So if a muon is associated to multiple collisions, depending on the selections, // it may be accepted for some associations and rejected for other - if (fConfigVariousOptions.fPropMuon) { + if (static_cast(muon.trackType()) > 2 && fConfigVariousOptions.fPropMuon) { VarManager::FillPropagateMuon(muon, collision); } - // recalculate pDca and global muon kinematics - if (static_cast(muon.trackType()) < 2 && fConfigVariousOptions.fRefitGlobalMuon) { + // recalculate pDca / DCA and global muon kinematics + // kMuonPDca is always taken from MCH (standalone or the MCH matched to a global) + if (static_cast(muon.trackType()) <= 2) { auto muontrack = muon.template matchMCHTrack_as(); - if (muontrack.eta() < fConfigVariousOptions.fMuonMatchEtaMin || muontrack.eta() > fConfigVariousOptions.fMuonMatchEtaMax) { - continue; - } - auto mfttrack = muon.template matchMFTTrack_as(); VarManager::FillTrackCollision(muontrack, collision); - // NOTE: the MFT track originally associated to the MUON track is currently used in the global muon refit - // Should MUON - MFT time ambiguities be taken into account ? - if constexpr (static_cast(TMFTFillMap & VarManager::ObjTypes::MFTCov)) { - auto const& mfttrackcov = mfCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); - VarManager::FillGlobalMuonRefitCov(muontrack, mfttrack, collision, mfttrackcov); + if (fConfigVariousOptions.fRefitGlobalMuon) { + if (muontrack.eta() < fConfigVariousOptions.fMuonMatchEtaMin || muontrack.eta() > fConfigVariousOptions.fMuonMatchEtaMax) { + continue; + } + auto mfttrack = muon.template matchMFTTrack_as(); + // Helix DCA (kMuonDCAx/y) is filled from the refitted parameters inside FillGlobalMuonRefit(Cov) + if constexpr (static_cast(TMFTFillMap & VarManager::ObjTypes::MFTCov)) { + auto const& mfttrackcov = mfCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); + VarManager::FillGlobalMuonRefitCov(muontrack, mfttrack, collision, mfttrackcov); + } else { + VarManager::FillGlobalMuonRefit(muontrack, mfttrack, collision); + } } else { - VarManager::FillGlobalMuonRefit(muontrack, mfttrack, collision); + // Helix DCA of the global track; leaves kMuonPDca from the matched MCH above + VarManager::FillTrackCollision(muon, collision); } } else { VarManager::FillTrackCollision(muon, collision); @@ -1782,21 +1786,28 @@ struct TableMaker { } VarManager::FillTrack(muon); - if (fConfigVariousOptions.fPropMuon) { + if (static_cast(muon.trackType()) > 2 && fConfigVariousOptions.fPropMuon) { VarManager::FillPropagateMuon(muon, collision); } - // recalculte pDca and global muon kinematics + // recalculate pDca / DCA and global muon kinematics + // kMuonPDca is always taken from MCH (standalone or the MCH matched to a global) int globalClusters = muon.nClusters(); - if (static_cast(muon.trackType()) < 2 && fConfigVariousOptions.fRefitGlobalMuon) { + if (static_cast(muon.trackType()) <= 2) { auto muontrack = muon.template matchMCHTrack_as(); - auto mfttrack = muon.template matchMFTTrack_as(); - globalClusters += mfttrack.nClusters(); VarManager::FillTrackCollision(muontrack, collision); - if constexpr (static_cast(TMFTFillMap & VarManager::ObjTypes::MFTCov)) { - auto const& mfttrackcov = mfCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); - VarManager::FillGlobalMuonRefitCov(muontrack, mfttrack, collision, mfttrackcov); + if (fConfigVariousOptions.fRefitGlobalMuon) { + auto mfttrack = muon.template matchMFTTrack_as(); + globalClusters += mfttrack.nClusters(); + // Helix DCA (kMuonDCAx/y) is filled from the refitted parameters inside FillGlobalMuonRefit(Cov) + if constexpr (static_cast(TMFTFillMap & VarManager::ObjTypes::MFTCov)) { + auto const& mfttrackcov = mfCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); + VarManager::FillGlobalMuonRefitCov(muontrack, mfttrack, collision, mfttrackcov); + } else { + VarManager::FillGlobalMuonRefit(muontrack, mfttrack, collision); + } } else { - VarManager::FillGlobalMuonRefit(muontrack, mfttrack, collision); + // Helix DCA of the global track; leaves kMuonPDca from the matched MCH above + VarManager::FillTrackCollision(muon, collision); } } else { VarManager::FillTrackCollision(muon, collision); @@ -1870,11 +1881,16 @@ struct TableMaker { VarManager::SetZShift((*fFwdShift)[0]); } else if (fFwdShift->size() == 3) { VarManager::Set3DShift((*fFwdShift)[0], (*fFwdShift)[1], (*fFwdShift)[2]); + } else if (fFwdShift->size() == 10) { + // x_top, y_top, z_top, slopeX_top, slopeY_top, x_bottom, y_bottom, z_bottom, slopeX_bottom, slopeY_bottom + // Slopes are unused for now; shift is selected from track y (top: y >= 0, bottom: y < 0) + VarManager::SetTopBottom3DShift((*fFwdShift)[0], (*fFwdShift)[1], (*fFwdShift)[2], + (*fFwdShift)[5], (*fFwdShift)[6], (*fFwdShift)[7]); + LOG(info) << "Loaded top/bottom forward track shifts from CCDB: top=(" << (*fFwdShift)[0] << ", " << (*fFwdShift)[1] << ", " << (*fFwdShift)[2] + << "), bottom=(" << (*fFwdShift)[5] << ", " << (*fFwdShift)[6] << ", " << (*fFwdShift)[7] << ")"; } else { - LOG(fatal) << "Unexpected number of shift values from CCDB: " << fFwdShift->size() << ", expected 1 (z) or 3 (x, y, z)"; + LOG(fatal) << "Unexpected number of shift values from CCDB: " << fFwdShift->size() << ", expected 1 (z), 3 (x, y, z) or 10 (top/bottom x,y,z + slopes)"; } - } else { - VarManager::SetZShift(fConfigCCDB.fManualZShift.value); } if (fConfigHistOutput.fConfigFillBcStat) { mLHCIFdata = fCCDB->getSpecific("GLO/Config/GRPLHCIF", bcs.begin().timestamp()); @@ -1968,6 +1984,8 @@ struct TableMaker { if constexpr (static_cast(TMFTFillMap & VarManager::ObjTypes::MFTCov)) { if (fConfigVariousOptions.fUseML.value) { skimBestMuonMatchesML(muons, mftTracks, mftCovs, collision); + } else { + skimBestMuonMatches(muons); } } else { skimBestMuonMatches(muons); @@ -2101,13 +2119,13 @@ struct TableMaker { } // produce the full DQ skimmed data model typically for Pb-Pb (with centrality), no subscribtion to the DQ event filter - void processPbPb(MyEventsWithCentAndMultsQvect const& collisions, MyBCs const& bcs, + void processPbPb(MyEventsWithCentAndMultsQvect const& collisions, MyBCs const& bcs, aod::Zdcs const& zdcs, MyBarrelTracksWithCov const& tracksBarrel, MyMuonsWithCov const& muons, MFTTracks const& mftTracks, TrackAssoc const& trackAssocs, FwdTrackAssoc const& fwdTrackAssocs, MFTTrackAssoc const& mftAssocs, aod::FT0s const& ft0s, aod::FV0As const& fv0as, aod::FDDs const& fdds) { - fullSkimming(collisions, bcs, nullptr, tracksBarrel, muons, mftTracks, trackAssocs, fwdTrackAssocs, mftAssocs, nullptr, ft0s, fv0as, fdds); + fullSkimming(collisions, bcs, zdcs, tracksBarrel, muons, mftTracks, trackAssocs, fwdTrackAssocs, mftAssocs, nullptr, ft0s, fv0as, fdds); } // produce the barrel only DQ skimmed data model typically for Pb-Pb (with centrality), no subscribtion to the DQ event filter @@ -2230,6 +2248,7 @@ struct TableMaker { PROCESS_SWITCH(TableMaker, processPPRealignedMuonOnly, "Build realigned muon only DQ skimmed data model typically for pp/p-Pb and UPC Pb-Pb", false); PROCESS_SWITCH(TableMaker, processPPMuonMFT, "Build muon + mft DQ skimmed data model typically for pp/p-Pb and UPC Pb-Pb", false); PROCESS_SWITCH(TableMaker, processPPMuonMFTWithMultsExtra, "Build muon + mft DQ skimmed data model typically for pp/p-Pb and UPC Pb-Pb", false); + PROCESS_SWITCH(TableMaker, processPPMuonRefit, "Build muon + mft DQ skimmed data model with MFT covariances for global muon refit, typically for pp/p-Pb", false); PROCESS_SWITCH(TableMaker, processPbPb, "Build full DQ skimmed data model typically for Pb-Pb, w/o event filtering", false); PROCESS_SWITCH(TableMaker, processPbPbBarrelOnly, "Build barrel only DQ skimmed data model typically for Pb-Pb, w/o event filtering", false); PROCESS_SWITCH(TableMaker, processPbPbBarrelOnlyNoTOF, "Build barrel only DQ skimmed data model typically for Pb-Pb, w/o event filtering, no TOF", false); diff --git a/PWGDQ/Tasks/CMakeLists.txt b/PWGDQ/Tasks/CMakeLists.txt index 90fda23675d..6e5ce44fb90 100644 --- a/PWGDQ/Tasks/CMakeLists.txt +++ b/PWGDQ/Tasks/CMakeLists.txt @@ -9,7 +9,7 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. -# tableReader_withAssoc.cxx is 5000 lines of task definitions, and seven +# tableReader_withAssoc.h is 5000 lines of task definitions, and seven # workflow variants below #include it verbatim -- differing only in which # adaptAnalysisTask<> entries they list, with identical preprocessor state and # identical link libraries. Without this it is parsed and instantiated seven @@ -21,7 +21,7 @@ add_library(TableReaderWithAssocPCH OBJECT tableReaderWithAssocPCH.cxx) target_link_libraries(TableReaderWithAssocPCH PUBLIC O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::AnalysisCCDB O2Physics::PWGDQCore O2Physics::MLCore) if(NOT DEFINED ENV{USE_RECC}) target_precompile_headers(TableReaderWithAssocPCH PRIVATE - [["PWGDQ/Tasks/tableReader_withAssoc.cxx"]]) + [["PWGDQ/Tasks/tableReader_withAssoc.h"]]) endif() o2physics_add_dpl_workflow(table-reader diff --git a/PWGDQ/Tasks/DalitzSelection.cxx b/PWGDQ/Tasks/DalitzSelection.cxx index 4c3a6a7e581..e0452279ab2 100644 --- a/PWGDQ/Tasks/DalitzSelection.cxx +++ b/PWGDQ/Tasks/DalitzSelection.cxx @@ -129,6 +129,7 @@ struct DalitzSelection { Configurable fUseRemoteField{"cfgUseRemoteField", true, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable fConfigBitsToPropagate{"cfgBitsToPropagate", 0, "bits to propagate for further analysis (e.g. MC true analysis): 0 = only probe bits (checking selected signals), 1 = tag and probe bits (checking pairs), 2 = tag and probe bits selected from like-sign (checking LS pairs)"}; } fConfigOptions; Service fCCDB{}; @@ -142,6 +143,7 @@ struct DalitzSelection { std::map fTrackmapProbe; // whether it is selected with probe cut std::map fDalitzmap; // whether it is selected as dalitz decay daughter with symmetric or tag cut std::map fDalitzmapProbe; // whether it is selected as dalitz decay daughter with probe cut + std::map fDalitzmapLS; // whether it is selected as decay daughter of a LS pair // maps to remove ambiguities std::map fDalitzmapAmbiguity; @@ -578,6 +580,10 @@ struct DalitzSelection { } else { if (fConfigOptions.fQA && !isPairAlreadySelected) { fHistMan->FillHistClass(fIsTagAndProbe ? Form("PairLS_%s_%s_%s", (*trackCut).GetName(), fTrackCutsProbe.at(icut).GetName(), (*pairCut).GetName()) : Form("PairLS_%s_%s", (*trackCut).GetName(), (*pairCut).GetName()), static_cast(VarManager::fgValues)); + if (fConfigOptions.fConfigBitsToPropagate == 2) { + fDalitzmapLS[trackIdx1] |= (uint8_t(1) << icut); + fDalitzmapLS[trackIdx2] |= (uint8_t(1) << icut); + } } } // end if like-sign } // end if isSelected @@ -673,7 +679,7 @@ struct DalitzSelection { uint32_t bitMask = (static_cast(1) << 8); fMixingEvent->ClearFilteringMask(bitMask); - for (auto& poolEvent : pool.events) { + for (auto& poolEvent : pool.events) { // o2-linter: disable=const-ref-in-for-loop (false positive, it cannot be made const since it is modified within the loop) if ((poolEvent.filteringMask & static_cast(255)) == 0) { // all other bits have been erased, so we can also mark bit 8 for deletion poolEvent.filteringMask |= bitMask; @@ -730,6 +736,8 @@ struct DalitzSelection { VarManager::fgValues[VarManager::kPt2] = t2.pt; VarManager::fgValues[VarManager::kEta2] = t2.eta; VarManager::fgValues[VarManager::kPhi2] = t2.phi; + VarManager::fgValues[VarManager::kDeltaEtaPair2] = t1.eta - t2.eta; + VarManager::fgValues[VarManager::kDeltaPhiPair] = t1.phi - t2.phi; } bool isLS = (t1.filteringFlags & (static_cast(1) << 8)) == (t2.filteringFlags & (static_cast(1) << 8)); for (uint32_t icut = 0; icut < fPairCuts.size(); icut++) { @@ -801,6 +809,7 @@ struct DalitzSelection { const int pairType = VarManager::kDecayToEE; fDalitzmap.clear(); fDalitzmapProbe.clear(); + fDalitzmapLS.clear(); bool initDFDone = false; // some quantities might need to be updated for each dataframe @@ -847,8 +856,20 @@ struct DalitzSelection { } if (fIsOutputRequested) { - for (const auto& track : tracks) { // Fill dalitz bits - dalitzbits(fIsTagAndProbe ? fDalitzmapProbe[track.globalIndex()] : fDalitzmap[track.globalIndex()]); + if (fConfigOptions.fConfigBitsToPropagate == 0) { + for (const auto& track : tracks) { // Fill dalitz bits + dalitzbits(fIsTagAndProbe ? fDalitzmapProbe[track.globalIndex()] : fDalitzmap[track.globalIndex()]); + } + } + if (fConfigOptions.fConfigBitsToPropagate == 1) { + for (const auto& track : tracks) { // Fill dalitz bits + dalitzbits(fDalitzmapProbe[track.globalIndex()] | fDalitzmap[track.globalIndex()]); + } + } + if (fConfigOptions.fConfigBitsToPropagate == 2) { + for (const auto& track : tracks) { // Fill dalitz bits + dalitzbits(fDalitzmapLS[track.globalIndex()]); + } } } } @@ -859,6 +880,7 @@ struct DalitzSelection { const int pairType = VarManager::kDecayToEE; fDalitzmap.clear(); fDalitzmapProbe.clear(); + fDalitzmapLS.clear(); fDalitzmapAmbiguity.clear(); fDalitzmapProbeAmbiguity.clear(); fAmbiguousPairs.clear(); @@ -909,8 +931,20 @@ struct DalitzSelection { } if (fIsOutputRequested) { - for (const auto& track : tracks) { // Fill dalitz bits - dalitzbits(fIsTagAndProbe ? fDalitzmapProbe[track.globalIndex()] : fDalitzmap[track.globalIndex()]); + if (fConfigOptions.fConfigBitsToPropagate == 0) { + for (const auto& track : tracks) { // Fill dalitz bits + dalitzbits(fIsTagAndProbe ? fDalitzmapProbe[track.globalIndex()] : fDalitzmap[track.globalIndex()]); + } + } + if (fConfigOptions.fConfigBitsToPropagate == 1) { + for (const auto& track : tracks) { // Fill dalitz bits + dalitzbits(fDalitzmapProbe[track.globalIndex()] | fDalitzmap[track.globalIndex()]); + } + } + if (fConfigOptions.fConfigBitsToPropagate == 2) { + for (const auto& track : tracks) { // Fill dalitz bits + dalitzbits(fDalitzmapLS[track.globalIndex()]); + } } } } @@ -921,6 +955,7 @@ struct DalitzSelection { const int pairType = VarManager::kDecayToEE; fDalitzmap.clear(); fDalitzmapProbe.clear(); + fDalitzmapLS.clear(); fDalitzmapAmbiguity.clear(); fDalitzmapProbeAmbiguity.clear(); fAmbiguousPairs.clear(); @@ -971,8 +1006,20 @@ struct DalitzSelection { } if (fIsOutputRequested) { - for (const auto& track : tracks) { // Fill dalitz bits - dalitzbits(fIsTagAndProbe ? fDalitzmapProbe[track.globalIndex()] : fDalitzmap[track.globalIndex()]); + if (fConfigOptions.fConfigBitsToPropagate == 0) { + for (const auto& track : tracks) { // Fill dalitz bits + dalitzbits(fIsTagAndProbe ? fDalitzmapProbe[track.globalIndex()] : fDalitzmap[track.globalIndex()]); + } + } + if (fConfigOptions.fConfigBitsToPropagate == 1) { + for (const auto& track : tracks) { // Fill dalitz bits + dalitzbits(fDalitzmapProbe[track.globalIndex()] | fDalitzmap[track.globalIndex()]); + } + } + if (fConfigOptions.fConfigBitsToPropagate == 2) { + for (const auto& track : tracks) { // Fill dalitz bits + dalitzbits(fDalitzmapLS[track.globalIndex()]); + } } } } diff --git a/PWGDQ/Tasks/TagAndProbe.cxx b/PWGDQ/Tasks/TagAndProbe.cxx index b637ec64aad..8ee82257af1 100644 --- a/PWGDQ/Tasks/TagAndProbe.cxx +++ b/PWGDQ/Tasks/TagAndProbe.cxx @@ -79,7 +79,7 @@ constexpr static uint32_t gkEventFillMapWithCov = VarManager::ObjTypes::ReducedE constexpr static uint32_t gkMuonFillMapWithCov = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra | VarManager::ObjTypes::ReducedMuonCov; // Global function used to define needed histogram classes -void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups); // defines histograms for all tasks +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const char* histGroups); // defines histograms for all tasks template void PrintBitMap(TMap map, int nbits) @@ -348,7 +348,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc)}; } -void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups) +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const char* histGroups) { // // Define here the histograms for all the classes required in analysis. diff --git a/PWGDQ/Tasks/dqCorrelation.cxx b/PWGDQ/Tasks/dqCorrelation.cxx index 890bdefe46b..30c0bc1a38b 100644 --- a/PWGDQ/Tasks/dqCorrelation.cxx +++ b/PWGDQ/Tasks/dqCorrelation.cxx @@ -286,7 +286,7 @@ struct DqCumulantFlow { float weff = 1.0, wacc = 1.0; if (dileptons.size() > 0) { - for (auto track : tracks) { + for (const auto& track : tracks) { trackGlobalIndexes.push_back(track.globalIndex()); } @@ -316,7 +316,7 @@ struct DqCumulantFlow { } } - for (auto dilepton : dileptons) { + for (const auto& dilepton : dileptons) { registry.fill(HIST("dimuon_mass"), dilepton.mass()); VarManager::FillTrack(dilepton, fValuesDilepton); diff --git a/PWGDQ/Tasks/dqEfficiency.cxx b/PWGDQ/Tasks/dqEfficiency.cxx index 45e84b4c3e4..32548b335d5 100644 --- a/PWGDQ/Tasks/dqEfficiency.cxx +++ b/PWGDQ/Tasks/dqEfficiency.cxx @@ -95,7 +95,7 @@ constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::ReducedMuon | Va constexpr static uint32_t gkMuonFillMapWithCov = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra | VarManager::ObjTypes::ReducedMuonCov; constexpr static uint32_t gkParticleMCFillMap = VarManager::ObjTypes::ParticleMC; -void DefineHistograms(HistogramManager* histMan, TString histClasses); +void DefineHistograms(HistogramManager* histMan, const TString& histClasses); struct AnalysisEventSelection { Produces eventSel; @@ -1197,12 +1197,12 @@ struct AnalysisDileptonTrack { std::vector trackGlobalIndexes; if (dileptons.size() > 0) { - for (auto track : tracks) { + for (const auto& track : tracks) { trackGlobalIndexes.push_back(track.globalIndex()); // std::cout << track.index() << " " << track.globalIndex() << std::endl; } } - for (auto dilepton : dileptons) { + for (const auto& dilepton : dileptons) { int indexLepton1 = dilepton.index0Id(); int indexLepton2 = dilepton.index1Id(); @@ -1504,14 +1504,14 @@ struct AnalysisDileptonTrackTrack { std::vector trackGlobalIndexes; if (dileptons.size() > 0) { - for (auto track : tracks) { + for (const auto& track : tracks) { trackGlobalIndexes.push_back(track.globalIndex()); // std::cout << track.index() << " " << track.globalIndex() << std::endl; } } // loop over dileptons - for (auto dilepton : dileptons) { + for (const auto& dilepton : dileptons) { VarManager::FillTrack(dilepton, fValuesQuadruplet); // apply the dilepton cut @@ -1665,7 +1665,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc)}; } -void DefineHistograms(HistogramManager* histMan, TString histClasses) +void DefineHistograms(HistogramManager* histMan, const TString& histClasses) { // // Define here the histograms for all the classes required in analysis. diff --git a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx index f2391b0debb..57b142eda98 100644 --- a/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx +++ b/PWGDQ/Tasks/dqEfficiency_withAssoc.cxx @@ -2482,9 +2482,9 @@ struct AnalysisSameEventPairing { if (twoTrackFilter & (static_cast(1) << icut)) { isAmbiInBunch = (twoTrackFilter & (static_cast(1) << 28)) || (twoTrackFilter & (static_cast(1) << 29)); isAmbiOutOfBunch = (twoTrackFilter & (static_cast(1) << 30)) || (twoTrackFilter & (static_cast(1) << 31)); - if (sign1 * sign2 < 0) { // +- pairs + if (sign1 * sign2 < 0) { // +- pairs fHistMan->FillHistClass(histNames[icut][0].Data(), dqefficiency_helpers::varValues()); // reconstructed, unmatched - for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals + for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals if (mcDecision & (static_cast(1) << isig)) { PromptNonPromptSepTable(VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kRap], VarManager::fgValues[VarManager::kPhi], VarManager::fgValues[VarManager::kVertexingTauxyProjected], VarManager::fgValues[VarManager::kVertexingTauxyProjectedPoleJPsiMass], VarManager::fgValues[VarManager::kVertexingTauzProjected], VarManager::fgValues[VarManager::kVertexingTauxyProjectedPoleJPsiMassRecalculatePV], @@ -2737,7 +2737,7 @@ struct AnalysisSameEventPairing { // cout << "AnalysisSameEventPairing::runMCGen() completed" << endl; } - // Run same-event e-mu pairing on reconstructed tracks. Logic mirrors runEmuSameEventPairing in tableReader_withAssoc.cxx + // Run same-event e-mu pairing on reconstructed tracks. Logic mirrors runEmuSameEventPairing in tableReader_withAssoc.h // with MC matching added: for each pair we evaluate the user-supplied fEmuRecMCSignals (2-prong, leg1=e, leg2=µ) // and fill an MC-matched histogram per (track cut, muon cut, signal) when CheckSignal returns true on the linked // ReducedMCTracks. Mixed events are handled in runEmuMixedPairing / runEmuSameSideMixing and do not perform MC matching. @@ -3934,7 +3934,7 @@ struct AnalysisAsymmetricPairing { for (int icut = 0; icut < fNLegCuts; icut++) { if (twoTrackFilter & (static_cast(1) << icut)) { isAmbi = (twoTrackFilter & (static_cast(1) << 30)) || (twoTrackFilter & (static_cast(1) << 31)); - if (sign1 * sign2 < 0) { // +- pairs + if (sign1 * sign2 < 0) { // +- pairs fHistMan->FillHistClass(Form("PairsBarrelSEPM_%s", fLegCutNames[icut].Data()), dqefficiency_helpers::varValues()); // reconstructed, unmatched if (isAmbi && fConfigQA) { fHistMan->FillHistClass(Form("PairsBarrelSEPM_ambiguous_%s", fLegCutNames[icut].Data()), dqefficiency_helpers::varValues()); diff --git a/PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx b/PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx index d61bf37ea71..d3a968e28a8 100644 --- a/PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx +++ b/PWGDQ/Tasks/dqEfficiency_withAssoc_direct.cxx @@ -54,7 +54,6 @@ #include #include -#include #include #include @@ -62,11 +61,11 @@ #include #include +#include #include #include #include #include -#include #include #include #include @@ -74,8 +73,6 @@ #include #include -using std::cout; -using std::endl; using std::string; using namespace o2; @@ -279,6 +276,10 @@ using MyBarrelTracksWithCovNoTOF = soa::Join; +using MyBarrelTracksWithDalitzBits = soa::Join; using MyBarrelTracksWithCovWithAmbiguities = soa::Join void PrintBitMap(TMap map, int nbits) { + std::string msg = ""; for (int i = 0; i < nbits; i++) { - cout << ((map & (TMap(1) << i)) > 0 ? "1" : "0"); + msg += ((map & (TMap(1) << i)) > 0 ? "1" : "0"); } + LOG(info) << msg; } // Analysis task that produces event decisions and the Hash table used in event mixing @@ -333,7 +337,7 @@ struct AnalysisEventSelection { AnalysisCompositeCut* fEventCut = nullptr; - Service fCCDB; + Service fCCDB{}; o2::ccdb::CcdbApi fCCDBApi; std::map fSelMap; // key: reduced event global index, value: event selection decision @@ -342,7 +346,7 @@ struct AnalysisEventSelection { void init(o2::framework::InitContext& context) { - cout << "AnalysisEventSelection::init() called" << endl; + LOG(info) << "AnalysisEventSelection::init() called"; if (context.mOptions.get("processDummy")) { return; } @@ -360,7 +364,7 @@ struct AnalysisEventSelection { TString eventCutJSONStr = fConfigEventCutsJSON.value; if (eventCutJSONStr != "") { std::vector jsonCuts = dqcuts::GetCutsFromJSON(eventCutJSONStr.Data()); - for (auto& cutIt : jsonCuts) { + for (const auto& cutIt : jsonCuts) { fEventCut->AddCut(cutIt); } } @@ -370,7 +374,7 @@ struct AnalysisEventSelection { if (fConfigQA) { fHistMan = new HistogramManager("analysisHistos", "", VarManager::kNVars); fHistMan->SetUseDefaultVariableNames(true); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + fHistMan->SetDefaultVarNames(static_cast(VarManager::fgVariableNames), static_cast(VarManager::fgVariableUnits)); DefineHistograms(fHistMan, "TimeFrameStats;Event_BeforeCuts;Event_AfterCuts;", fConfigAddEventHistogram.value.data()); if (fConfigCheckSplitCollisions) { DefineHistograms(fHistMan, "OutOfBunchCorrelations;SameBunchCorrelations;", ""); @@ -387,13 +391,13 @@ struct AnalysisEventSelection { fCCDB->setLocalObjectValidityChecking(); fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); fCCDBApi.init(fConfigCcdbUrl.value); - cout << "AnalysisEventSelection::init() completed" << endl; + LOG(info) << "AnalysisEventSelection::init() completed"; } template void runEventSelection(TEvents const& events, BCsWithTimestamps const& bcs, TEventsMC const& mcEvents) { - cout << "AnalysisEventSelection::runEventSelection() called with " << events.size() << " events and " << bcs.size() << " BCs" << endl; + LOG(info) << "AnalysisEventSelection::runEventSelection() called with " << events.size() << " events and " << bcs.size() << " BCs"; if (bcs.size() > 0 && bcs.begin().runNumber() != fCurrentRun) { std::map metadataRCT, header; header = fCCDBApi.retrieveHeaders(Form("RCT/Info/RunInformation/%i", bcs.begin().runNumber()), metadataRCT, -1); @@ -402,21 +406,21 @@ struct AnalysisEventSelection { VarManager::SetSORandEOR(sor, eor); } - cout << "Filling TimeFrame statistics histograms" << endl; + // cout << "Filling TimeFrame statistics histograms" << endl; VarManager::ResetValues(0, VarManager::kNEventWiseVariables); VarManager::FillTimeFrame(bcs); VarManager::FillTimeFrame(events); VarManager::FillTimeFrame(mcEvents); if (fConfigQA) { - fHistMan->FillHistClass("TimeFrameStats", VarManager::fgValues); + fHistMan->FillHistClass("TimeFrameStats", static_cast(VarManager::fgValues)); } fSelMap.clear(); fBCCollMap.clear(); // int iEvent = 0; - cout << "Starting event loop for event selection" << endl; - for (auto& event : events) { + // cout << "Starting event loop for event selection" << endl; + for (const auto& event : events) { auto bc = event.template bc_as(); // check if there is a mismatch between the collision associated BC and the recomputed one in event selection @@ -436,11 +440,11 @@ struct AnalysisEventSelection { bool decision = false; // if QA is requested fill histograms before event selections if (fConfigQA) { - fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); // automatically fill all the histograms in the class Event + fHistMan->FillHistClass("Event_BeforeCuts", static_cast(VarManager::fgValues)); // automatically fill all the histograms in the class Event } - if (fEventCut->IsSelected(VarManager::fgValues)) { + if (fEventCut->IsSelected(static_cast(VarManager::fgValues))) { if (fConfigQA) { - fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); + fHistMan->FillHistClass("Event_AfterCuts", static_cast(VarManager::fgValues)); } decision = true; } @@ -454,22 +458,22 @@ struct AnalysisEventSelection { } } - for (auto& event : mcEvents) { + for (const auto& event : mcEvents) { // Reset the fValues array and fill event observables VarManager::ResetValues(0, VarManager::kNEventWiseVariables); VarManager::FillEvent(event); if (fConfigQA) { - fHistMan->FillHistClass("EventsMC", VarManager::fgValues); + fHistMan->FillHistClass("EventsMC", static_cast(VarManager::fgValues)); } } - cout << "AnalysisEventSelection::runEventSelection() completed" << endl; + // cout << "AnalysisEventSelection::runEventSelection() completed" << endl; } template void publishSelections(TEvents const& events) { - cout << "AnalysisEventSelection::publishSelections() called" << endl; + // cout << "AnalysisEventSelection::publishSelections() called" << endl; std::map collisionSplittingMap; // key: event global index, value: whether pileup event is a possible splitting // Reset the fValues array and fill event observables @@ -487,12 +491,12 @@ struct AnalysisEventSelection { auto ev2 = events.rawIteratorAt(*ev2It); // compute 2-event quantities and mark the candidate split collisions VarManager::FillTwoEvents(ev1, ev2); - if (TMath::Abs(VarManager::fgValues[VarManager::kTwoEvDeltaZ]) < fConfigSplitCollisionsDeltaZ) { // this is a possible collision split + if (std::fabs(VarManager::fgValues[VarManager::kTwoEvDeltaZ]) < fConfigSplitCollisionsDeltaZ) { // this is a possible collision split collisionSplittingMap[*ev1It] = true; collisionSplittingMap[*ev2It] = true; } if (fConfigQA) { - fHistMan->FillHistClass("SameBunchCorrelations", VarManager::fgValues); + fHistMan->FillHistClass("SameBunchCorrelations", static_cast(VarManager::fgValues)); } } // end second event loop } // end first event loop @@ -507,19 +511,19 @@ struct AnalysisEventSelection { auto const& bc2Events = bc2It->second; // loop over events in the first BC - for (auto ev1It : bc1Events) { + for (const auto ev1It : bc1Events) { auto ev1 = events.rawIteratorAt(ev1It); // loop over events in the second BC - for (auto ev2It : bc2Events) { + for (const auto ev2It : bc2Events) { auto ev2 = events.rawIteratorAt(ev2It); // compute 2-event quantities and mark the candidate split collisions VarManager::FillTwoEvents(ev1, ev2); - if (TMath::Abs(VarManager::fgValues[VarManager::kTwoEvDeltaZ]) < fConfigSplitCollisionsDeltaZ) { // this is a possible collision split + if (std::fabs(VarManager::fgValues[VarManager::kTwoEvDeltaZ]) < fConfigSplitCollisionsDeltaZ) { // this is a possible collision split collisionSplittingMap[ev1It] = true; collisionSplittingMap[ev2It] = true; } if (fConfigQA) { - fHistMan->FillHistClass("OutOfBunchCorrelations", VarManager::fgValues); + fHistMan->FillHistClass("OutOfBunchCorrelations", static_cast(VarManager::fgValues)); } } } @@ -527,8 +531,8 @@ struct AnalysisEventSelection { } // publish the table - uint32_t evSel = static_cast(0); - for (auto& event : events) { + auto evSel = static_cast(0); + for (const auto& event : events) { evSel = 0; if (fSelMap[event.globalIndex()]) { // event passed the user cuts evSel |= (static_cast(1) << 0); @@ -543,26 +547,26 @@ struct AnalysisEventSelection { } eventSel(evSel); } - cout << "AnalysisEventSelection::publishSelections() completed" << endl; + // cout << "AnalysisEventSelection::publishSelections() completed" << endl; } void processDirect(MyEvents const& events, BCsWithTimestamps const& bcs, soa::Join const& mcEvents) { - cout << "AnalysisEventSelection::processDirect() called" << endl; + // cout << "AnalysisEventSelection::processDirect() called" << endl; runEventSelection(events, bcs, mcEvents); publishSelections(events); - cout << "AnalysisEventSelection::processDirect() completed" << endl; + // cout << "AnalysisEventSelection::processDirect() completed" << endl; } void processPbPbDirect(MyEventsWithCentAndMults const& events, BCsWithTimestamps const& bcs, soa::Join const& mcEvents) { - cout << "AnalysisEventSelection::processPbPbDirect() called" << endl; + // cout << "AnalysisEventSelection::processPbPbDirect() called" << endl; runEventSelection(events, bcs, mcEvents); publishSelections(events); - cout << "AnalysisEventSelection::processPbPbDirect() completed" << endl; + // cout << "AnalysisEventSelection::processPbPbDirect() completed" << endl; } - void processDummy(aod::Collisions&) + void processDummy(const aod::Collisions&) { // do nothing } @@ -592,8 +596,8 @@ struct AnalysisTrackSelection { Configurable fConfigMCSignals{"cfgTrackMCSignals", "", "Comma separated list of MC signals"}; Configurable fConfigMCSignalsJSON{"cfgTrackMCsignalsJSON", "", "Additional list of MC signals via JSON"}; - Service fCCDB; - Service fTofResponse; + Service fCCDB{}; + Service fTofResponse{}; HistogramManager* fHistMan = nullptr; std::vector fTrackCuts; @@ -608,7 +612,7 @@ struct AnalysisTrackSelection { void init(o2::framework::InitContext& context) { - cout << "AnalysisTrackSelection::init() called" << endl; + LOG(info) << "AnalysisTrackSelection::init() called"; if (context.mOptions.get("processDummy")) { return; } @@ -626,7 +630,7 @@ struct AnalysisTrackSelection { TString addTrackCutsStr = fConfigCutsJSON.value; if (addTrackCutsStr != "") { std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); - for (auto& t : addTrackCuts) { + for (const auto& t : addTrackCuts) { fTrackCuts.push_back(reinterpret_cast(t)); } } @@ -648,7 +652,7 @@ struct AnalysisTrackSelection { TString addMCSignalsStr = fConfigMCSignalsJSON.value; if (addMCSignalsStr != "") { std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); - for (auto& mcIt : addMCSignals) { + for (const auto& mcIt : addMCSignals) { if (mcIt->GetNProngs() != 1) { // NOTE: only 1 prong signals continue; } @@ -659,16 +663,16 @@ struct AnalysisTrackSelection { if (fConfigQA) { fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + fHistMan->SetDefaultVarNames(static_cast(VarManager::fgVariableNames), static_cast(VarManager::fgVariableUnits)); // Configure histogram classes for each track cut; // Add histogram classes for each track cut and for each requested MC signal (reconstructed tracks with MC truth) TString histClasses = "TimeFrameStats;AssocsBarrel_BeforeCuts;"; - for (auto& cut : fTrackCuts) { + for (const auto& cut : fTrackCuts) { TString nameStr = Form("AssocsBarrel_%s", cut->GetName()); fHistNamesReco.push_back(nameStr); histClasses += Form("%s;", nameStr.Data()); - for (auto& sig : fMCSignals) { + for (const auto& sig : fMCSignals) { TString nameStr2 = Form("AssocsCorrectBarrel_%s_%s", cut->GetName(), sig->GetName()); fHistNamesMCMatched.push_back(nameStr2); histClasses += Form("%s;", nameStr2.Data()); @@ -692,14 +696,17 @@ struct AnalysisTrackSelection { fCCDB->setLocalObjectValidityChecking(); fCCDB->setCreatedNotAfter(fConfigNoLaterThan.value); - fTofResponse->initSetup(fCCDB, context); - cout << "AnalysisTrackSelection::init() completed" << endl; + if (!context.mOptions.get("processWithDalitzBits")) { + fTofResponse->initSetup(fCCDB, context); + } + + LOG(info) << "AnalysisTrackSelection::init() completed"; } template void runTrackSelection(TrackAssoc const& assocs, BCsWithTimestamps const& bcs, TEvents const& events, TTracks const& tracks, McCollisions const& /*eventsMC*/, McParticles const& tracksMC) { - cout << "AnalysisTrackSelection::runTrackSelection() called with " << events.size() << " events, " << tracks.size() << " tracks and " << assocs.size() << " associations" << endl; + LOG(info) << "AnalysisTrackSelection::runTrackSelection() called with " << events.size() << " events, " << tracks.size() << " tracks and " << assocs.size() << " associations"; // determine if TEvents table contains aod::Collisions // bool hasCollisions = std::is_same::value; @@ -710,11 +717,11 @@ struct AnalysisTrackSelection { VarManager::FillTimeFrame(events); VarManager::FillTimeFrame(tracks); if (fConfigQA) { - fHistMan->FillHistClass("TimeFrameStats", VarManager::fgValues); + fHistMan->FillHistClass("TimeFrameStats", static_cast(VarManager::fgValues)); } - cout << "After filling TimeFrame statistics" << endl; - // TODO: Check if postcalibration needed for MC + // cout << "After filling TimeFrame statistics" << endl; + // TODO: Check if postcalibration needed for MC if (bcs.size() > 0 && fCurrentRun != bcs.begin().runNumber()) { if (fConfigComputeTPCpostCalib) { auto calibList = fCCDB->getForTimeStamp(fConfigCcdbPathTPC.value, bcs.begin().timestamp()); @@ -726,7 +733,7 @@ struct AnalysisTrackSelection { VarManager::SetCalibrationObject(VarManager::kTPCProtonSigma, calibList->FindObject("sigma_map_proton")); } - o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(grpmagPath, bcs.begin().timestamp()); + auto grpmag = fCCDB->getForTimeStamp(grpmagPath, bcs.begin().timestamp()); if (grpmag != nullptr) { VarManager::SetMagneticField(grpmag->getNominalL3Field()); } else { @@ -736,13 +743,13 @@ struct AnalysisTrackSelection { fCurrentRun = bcs.begin().runNumber(); } - cout << "Starting loop over track associations" << endl; + // cout << "Starting loop over track associations" << endl; trackSel.reserve(assocs.size()); trackAmbiguities.reserve(tracks.size()); // Loop over associations - for (auto& assoc : assocs) { + for (const auto& assoc : assocs) { auto event = assoc.template collision_as(); if (!event.isEventSelected_bit(0)) { trackSel(0); @@ -767,9 +774,10 @@ struct AnalysisTrackSelection { VarManager::FillTrack(track); // compute quantities which depend on the associated collision, such as DCA - if (track.collisionId() != event.globalIndex()) + if (track.collisionId() != event.globalIndex()) { VarManager::FillTrackCollision(track, event); // cout << "Filled track observables for association" << endl; + } bool isCorrectAssoc = false; if (track.has_mcParticle()) { @@ -783,17 +791,17 @@ struct AnalysisTrackSelection { // cout << "Filled MC observables for association" << endl; if (fConfigQA) { - fHistMan->FillHistClass("AssocsBarrel_BeforeCuts", VarManager::fgValues); + fHistMan->FillHistClass("AssocsBarrel_BeforeCuts", static_cast(VarManager::fgValues)); } // cout << "Filled AssocsBarrel_BeforeCuts histograms" << endl; int iCut = 0; - uint32_t filterMap = static_cast(0); + auto filterMap = static_cast(0); for (auto cut = fTrackCuts.begin(); cut != fTrackCuts.end(); cut++, iCut++) { - if ((*cut)->IsSelected(VarManager::fgValues)) { + if ((*cut)->IsSelected(static_cast(VarManager::fgValues))) { filterMap |= (static_cast(1) << iCut); if (fConfigQA) { - fHistMan->FillHistClass(fHistNamesReco[iCut], VarManager::fgValues); + fHistMan->FillHistClass(fHistNamesReco[iCut], static_cast(VarManager::fgValues)); } } } // end loop over cuts @@ -862,7 +870,7 @@ struct AnalysisTrackSelection { // So one could QA these tracks separately if (fConfigPublishAmbiguity) { if (fConfigQA) { - for (auto& [trackIdx, evIndices] : fNAssocsInBunch) { + for (const auto& [trackIdx, evIndices] : fNAssocsInBunch) { if (evIndices.size() == 1) { continue; } @@ -870,10 +878,10 @@ struct AnalysisTrackSelection { VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); VarManager::FillTrack(track); VarManager::fgValues[VarManager::kBarrelNAssocsInBunch] = static_cast(evIndices.size()); - fHistMan->FillHistClass("TrackBarrel_AmbiguityInBunch", VarManager::fgValues); + fHistMan->FillHistClass("TrackBarrel_AmbiguityInBunch", static_cast(VarManager::fgValues)); } // end loop over in-bunch ambiguous tracks - for (auto& [trackIdx, evIndices] : fNAssocsOutOfBunch) { + for (const auto& [trackIdx, evIndices] : fNAssocsOutOfBunch) { if (evIndices.size() == 1) { continue; } @@ -881,12 +889,12 @@ struct AnalysisTrackSelection { VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables); VarManager::FillTrack(track); VarManager::fgValues[VarManager::kBarrelNAssocsOutOfBunch] = static_cast(evIndices.size()); - fHistMan->FillHistClass("TrackBarrel_AmbiguityOutOfBunch", VarManager::fgValues); + fHistMan->FillHistClass("TrackBarrel_AmbiguityOutOfBunch", static_cast(VarManager::fgValues)); } // end loop over out-of-bunch ambiguous tracks } // publish the ambiguity table - for (auto& track : tracks) { + for (const auto& track : tracks) { int8_t nInBunch = 0; if (fNAssocsInBunch.find(track.globalIndex()) != fNAssocsInBunch.end()) { nInBunch = fNAssocsInBunch[track.globalIndex()].size(); @@ -898,32 +906,38 @@ struct AnalysisTrackSelection { trackAmbiguities(nInBunch, nOutOfBunch); } } - cout << "AnalysisTrackSelection::runTrackSelection() completed" << endl; + // cout << "AnalysisTrackSelection::runTrackSelection() completed" << endl; } // end runTrackSelection() void processWithCov(TrackAssoc const& assocs, BCsWithTimestamps const& bcs, MyEventsSelected const& events, MyBarrelTracksWithCov const& tracks, McCollisions const& eventsMC, McParticles const& tracksMC) { - cout << "AnalysisTrackSelection::processWithCov() called" << endl; + // cout << "AnalysisTrackSelection::processWithCov() called" << endl; runTrackSelection(assocs, bcs, events, tracks, eventsMC, tracksMC); - cout << "AnalysisTrackSelection::processWithCov() completed" << endl; + // cout << "AnalysisTrackSelection::processWithCov() completed" << endl; } void processWithCovTOFService(TrackAssoc const& assocs, BCsWithTimestamps const& bcs, MyEventsSelected const& events, MyBarrelTracksWithCovNoTOF const& tracks, McCollisions const& eventsMC, McParticles const& tracksMC) { - cout << "AnalysisTrackSelection::processWithCov() called" << endl; + // cout << "AnalysisTrackSelection::processWithCov() called" << endl; fTofResponse->processSetup(bcs.iteratorAt(0)); auto tracksWithTOFservice = soa::Attach(tracks); runTrackSelection(assocs, bcs, events, tracksWithTOFservice, eventsMC, tracksMC); - cout << "AnalysisTrackSelection::processWithCov() completed" << endl; + // cout << "AnalysisTrackSelection::processWithCov() completed" << endl; + } + void processWithDalitzBits(TrackAssoc const& assocs, BCsWithTimestamps const& bcs, MyEventsSelected const& events, MyBarrelTracksWithDalitzBits const& tracks, + McCollisions const& eventsMC, McParticles const& tracksMC) + { + runTrackSelection(assocs, bcs, events, tracks, eventsMC, tracksMC); } - void processDummy(MyEvents&) + void processDummy(const MyEvents&) { // do nothing } PROCESS_SWITCH(AnalysisTrackSelection, processWithCov, "Run barrel track selection on DQ skimmed tracks w/ cov matrix associations", false); PROCESS_SWITCH(AnalysisTrackSelection, processWithCovTOFService, "Run barrel track selection on DQ skimmed tracks w/ cov matrix associations, with TOF service", false); + PROCESS_SWITCH(AnalysisTrackSelection, processWithDalitzBits, "Run barrel track selection on DQ skimmed tracks w/ dalitz bits obtained from DalitzSelection task", false); PROCESS_SWITCH(AnalysisTrackSelection, processDummy, "Dummy function", true); }; @@ -946,7 +960,7 @@ struct AnalysisPrefilterSelection { void init(o2::framework::InitContext& context) { - cout << "AnalysisPrefilterSelection::init() called" << endl; + LOG(info) << "AnalysisPrefilterSelection::init() called"; if (context.mOptions.get("processDummy")) { return; } @@ -984,7 +998,7 @@ struct AnalysisPrefilterSelection { TString addTrackCutsStr = trackCuts; if (addTrackCutsStr != "") { std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); - for (auto& t : addTrackCuts) { + for (const auto& t : addTrackCuts) { allTrackCutsStr += Form(",%s", t->GetName()); } } @@ -1021,7 +1035,7 @@ struct AnalysisPrefilterSelection { VarManager::SetupTwoProngDCAFitter(5.0f, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, true); // TODO: get these parameters from Configurables VarManager::SetupTwoProngFwdDCAFitter(5.0f, true, 200.0f, 1.0e-3f, 0.9f, true); - cout << "AnalysisPrefilterSelection::init() completed" << endl; + LOG(info) << "AnalysisPrefilterSelection::init() completed"; } template @@ -1032,7 +1046,7 @@ struct AnalysisPrefilterSelection { return; } - for (auto& [assoc1, assoc2] : o2::soa::combinations(assocs, assocs)) { + for (const auto& [assoc1, assoc2] : o2::soa::combinations(assocs, assocs)) { auto track1 = assoc1.template track_as(); auto track2 = assoc2.template track_as(); @@ -1058,7 +1072,7 @@ struct AnalysisPrefilterSelection { VarManager::FillPairCollision(event, track1, track2); } // if the pair fullfils the criteria, add an entry into the prefilter map for the two tracks - if (fPairCut->IsSelected(VarManager::fgValues)) { + if (fPairCut->IsSelected(static_cast(VarManager::fgValues))) { if (fPrefilterMap.find(track1.globalIndex()) == fPrefilterMap.end() && track1Candidate > 0) { fPrefilterMap[track1.globalIndex()] = track1Candidate; } @@ -1070,12 +1084,12 @@ struct AnalysisPrefilterSelection { // cout << "AnalysisPrefilterSelection::runPrefilter() completed for event " << event.globalIndex() << endl; } - void processBarrel(MyEvents const& events, soa::Join const& assocs, MyBarrelTracksWithCov const& tracks) + void processBarrel(MyEvents const& events, soa::Join const& assocs, MyBarrelTracksWithCovNoTOF const& tracks) { - cout << "AnalysisPrefilterSelection::processBarrel() called" << endl; + // cout << "AnalysisPrefilterSelection::processBarrel() called" << endl; fPrefilterMap.clear(); - for (auto& event : events) { + for (const auto& event : events) { auto groupedAssocs = assocs.sliceBy(trackAssocsPerCollision, event.globalIndex()); groupedAssocs.bindInternalIndicesTo(&assocs); @@ -1091,7 +1105,7 @@ struct AnalysisPrefilterSelection { prefilter(mymap); } } else { - for (auto& assoc : assocs) { + for (const auto& assoc : assocs) { // TODO: just use the index from the assoc (no need to cast the whole track) // auto track = assoc.template track_as(); mymap = -1; @@ -1106,10 +1120,10 @@ struct AnalysisPrefilterSelection { } } } - cout << "AnalysisPrefilterSelection::processBarrel() completed" << endl; + // cout << "AnalysisPrefilterSelection::processBarrel() completed" << endl; } - void processDummy(MyEvents&) + void processDummy(const MyEvents&) { // do nothing } @@ -1131,7 +1145,7 @@ struct AnalysisSameEventPairing { Produces MCTruthTableEffi; o2::base::MatLayerCylSet* fLUT = nullptr; - int fCurrentRun; // needed to detect if the run changed and trigger update of calibrations etc. + int fCurrentRun = 0; // needed to detect if the run changed and trigger update of calibrations etc. OutputObj fOutputList{"output"}; @@ -1182,11 +1196,11 @@ struct AnalysisSameEventPairing { Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; } fConfigCCDB; - Service fCCDB; + Service fCCDB{}; // PDG database - Service pdgDB; + Service pdgDB{}; - HistogramManager* fHistMan; + HistogramManager* fHistMan = nullptr; // vectors needed for PV recomputation std::vector pvContribGlobIDs; @@ -1196,8 +1210,8 @@ struct AnalysisSameEventPairing { // keep histogram class names in maps, so we don't have to buld their names in the pair loops std::map> fTrackHistNames; std::map> fBarrelHistNamesMCmatched; - std::map> fMuonHistNames; - std::map> fMuonHistNamesMCmatched; + // std::map> fMuonHistNames; + // std::map> fMuonHistNamesMCmatched; std::vector fRecMCSignals; std::vector fGenMCSignals; MCSignal* fEFromJpsiSignal = nullptr; @@ -1221,7 +1235,7 @@ struct AnalysisSameEventPairing { void init(o2::framework::InitContext& context) { - cout << "AnalysisSameEventPairing::init() called" << endl; + LOG(info) << "AnalysisSameEventPairing::init() called"; if (context.mOptions.get("processDummy")) { return; } @@ -1270,7 +1284,7 @@ struct AnalysisSameEventPairing { TString addMCSignalsStr = fConfigMC.recSignalsJSON.value; if (addMCSignalsStr != "") { std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); - for (auto& mcIt : addMCSignals) { + for (const auto& mcIt : addMCSignals) { if (mcIt->GetNProngs() != 2) { // NOTE: only 2 prong signals continue; } @@ -1289,7 +1303,7 @@ struct AnalysisSameEventPairing { TString addTrackCutsStr = tempCuts; if (addTrackCutsStr != "") { std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); - for (auto& t : addTrackCuts) { + for (const auto& t : addTrackCuts) { tempCutsStr += Form(",%s", t->GetName()); } } @@ -1334,7 +1348,7 @@ struct AnalysisSameEventPairing { names.push_back(Form("PairsBarrelSEPP_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); names.push_back(Form("PairsBarrelSEMM_ambiguousOutOfBunch_%s", objArray->At(icut)->GetName())); } - for (auto& n : names) { + for (const auto& n : names) { histNames += Form("%s;", n.Data()); } fTrackHistNames[icut] = names; @@ -1342,7 +1356,7 @@ struct AnalysisSameEventPairing { // if there are pair cuts specified, assign hist directories for each barrel cut - pair cut combination // NOTE: This could possibly lead to large histogram outputs. It is strongly advised to use pair cuts only // if you know what you are doing. - TString cutNamesStr = fConfigOptions.pair.value; + // TString cutNamesStr = fConfigOptions.pair.value; if (!cutNamesStr.IsNull()) { // if pair cuts std::unique_ptr objArrayPair(cutNamesStr.Tokenize(",")); fNPairCuts = objArrayPair->GetEntries(); @@ -1375,7 +1389,7 @@ struct AnalysisSameEventPairing { names.push_back(Form("PairsBarrelSEPM_ambiguousOutOfBunchCorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); names.push_back(Form("PairsBarrelSEPM_ambiguousOutOfBunchIncorrectAssoc_%s_%s", objArray->At(icut)->GetName(), sig->GetName())); } - for (auto& n : names) { + for (const auto& n : names) { histNames += Form("%s;", n.Data()); } fBarrelHistNamesMCmatched.try_emplace(icut * fRecMCSignals.size() + isig, names); @@ -1492,7 +1506,7 @@ struct AnalysisSameEventPairing { TString addMCSignalsGenStr = fConfigMC.genSignalsJSON.value; if (addMCSignalsGenStr != "") { std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsGenStr.Data()); - for (auto& mcIt : addMCSignals) { + for (const auto& mcIt : addMCSignals) { if (mcIt->GetNProngs() > 2) { // NOTE: only 2 prong signals continue; } @@ -1500,7 +1514,7 @@ struct AnalysisSameEventPairing { } } - for (auto& sig : fGenMCSignals) { + for (const auto& sig : fGenMCSignals) { if (sig->GetNProngs() == 1) { histNames += Form("MCTruthGen_%s;", sig->GetName()); // TODO: Add these names to a std::vector to avoid using Form in the process function histNames += Form("MCTruthGenSel_%s;", sig->GetName()); @@ -1527,7 +1541,7 @@ struct AnalysisSameEventPairing { } // for these pair level signals, also add histograms for each MCgenAcc cut if specified if (fUseMCGenAccCut) { - for (auto& cut : fMCGenAccCuts) { + for (const auto& cut : fMCGenAccCuts) { if (fConfigOptions.fConfigMCtruthQA.value) { histNames += Form("MCTruthGenPairSel_%s_%s;", sig->GetName(), cut->GetName()); // after event selection and MCgenAcc cut } @@ -1569,7 +1583,7 @@ struct AnalysisSameEventPairing { fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); fHistMan->SetUseDefaultVariableNames(kTRUE); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + fHistMan->SetDefaultVarNames(static_cast(VarManager::fgVariableNames), static_cast(VarManager::fgVariableUnits)); VarManager::SetCollisionSystem((TString)fConfigOptions.collisionSystem, fConfigOptions.centerMassEnergy); // set collision system and center of mass energy @@ -1578,14 +1592,14 @@ struct AnalysisSameEventPairing { VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill fOutputList.setObject(fHistMan->GetMainHistogramList()); - cout << "AnalysisSameEventPairing::init() completed" << endl; + LOG(info) << "AnalysisSameEventPairing::init() completed"; } void initParamsFromCCDB(uint64_t timestamp, bool withTwoProngFitter = true) { - cout << "AnalysisSameEventPairing::initParamsFromCCDB() called for timestamp " << timestamp << endl; + LOG(info) << "AnalysisSameEventPairing::initParamsFromCCDB() called for timestamp " << timestamp; if (fConfigOptions.useRemoteField.value) { - o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(fConfigCCDB.grpMagPath, timestamp); + auto grpmag = fCCDB->getForTimeStamp(fConfigCCDB.grpMagPath, timestamp); o2::base::MatLayerCylSet* lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(fCCDB->get(fConfigCCDB.lutPath)); float magField = 0.0; if (grpmag != nullptr) { @@ -1617,7 +1631,7 @@ struct AnalysisSameEventPairing { VarManager::SetupTwoProngDCAFitter(fConfigOptions.magField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, fConfigOptions.useAbsDCA.value); // needed because take in varmanager Bz from fgFitterTwoProngBarrel for PhiV calculations } } - cout << "AnalysisSameEventPairing::initParamsFromCCDB() completed" << endl; + LOG(info) << "AnalysisSameEventPairing::initParamsFromCCDB() completed"; } template @@ -1629,15 +1643,18 @@ struct AnalysisSameEventPairing { // int nMyPVContrib = 0; int nMyPVContribOrig = 0; for (auto const& trk : tracks) { // check if it is PV contributor - if (!trk.isPVContributor()) + if (!trk.isPVContributor()) { continue; + } // check if it contributes to the vtx of this collision - if (trk.collisionId() != collision.globalIndex()) + if (trk.collisionId() != collision.globalIndex()) { continue; + } // nMyPVContribOrig++; // --- remove t1 and t2 if they are PV contributors --- - if (trk.globalIndex() == t1.globalIndex() || trk.globalIndex() == t2.globalIndex()) + if (trk.globalIndex() == t1.globalIndex() || trk.globalIndex() == t2.globalIndex()) { continue; + } // add tracks and parameters to the list pvContribGlobIDs.push_back(trk.globalIndex()); pvContribTrackPars.push_back(getTrackParCov(trk)); @@ -1662,8 +1679,9 @@ struct AnalysisSameEventPairing { vertexer.init(); bool PVrefit_doable = vertexer.prepareVertexRefit(pvContribTrackPars, Pvtx); - if (!PVrefit_doable) + if (!PVrefit_doable) { return false; + } // --- do the refit --- pvRefitted = vertexer.refitVertex(vec_useTrk_PVrefit, Pvtx); @@ -1675,7 +1693,7 @@ struct AnalysisSameEventPairing { template void runSameEventPairing(TEvents const& events, BCsWithTimestamps const& bcs, Preslice>& preslice, soa::Join const& assocs, TTracks const& tracks, TEventsMC const& mcEvents, McParticles const& mcTracks) { - cout << "AnalysisSameEventPairing::runSameEventPairing() called" << endl; + // cout << "AnalysisSameEventPairing::runSameEventPairing() called" << endl; if (events.size() == 0) { LOG(warning) << "No events in this TF, going to the next one ..."; return; @@ -1696,17 +1714,17 @@ struct AnalysisSameEventPairing { ncuts = fNCutsMuon; }*/ - uint32_t twoTrackFilter = static_cast(0); + auto twoTrackFilter = static_cast(0); int sign1 = 0; int sign2 = 0; - uint32_t mcDecision = static_cast(0); + auto mcDecision = static_cast(0); bool isCorrectAssoc_leg1 = false; bool isCorrectAssoc_leg2 = false; // estimate reserved size int64_t reserveSize = 0; int64_t reserveSizeGen = mcTracks.size(); - for (auto& event : events) { + for (const auto& event : events) { if (event.isEventSelected_bit(0)) { auto groupedAssocs = assocs.sliceBy(preslice, event.globalIndex()); size_t nGood = 0; @@ -1741,20 +1759,20 @@ struct AnalysisSameEventPairing { constexpr bool eventHasQvector = ((TEventFillMap & VarManager::ObjTypes::CollisionQvect) > 0); constexpr bool trackHasCov = ((TTrackFillMap & VarManager::ObjTypes::TrackCov) > 0); - for (auto& event : events) { + for (const auto& event : events) { if (!event.isEventSelected_bit(0)) { continue; } // uint8_t evSel = event.isEventSelected_raw(); // Reset the fValues array VarManager::ResetValues(0, VarManager::kNVars); - VarManager::FillEvent(event, VarManager::fgValues); + VarManager::FillEvent(event, static_cast(VarManager::fgValues)); // if (event.has_mcCollision()) { - // VarManager::FillEvent(event.mcCollision(), VarManager::fgValues); + // VarManager::FillEvent(event.mcCollision(), static_cast(VarManager::fgValues)); // } if (event.has_mcCollision()) { auto mcEvent = mcEvents.rawIteratorAt(event.mcCollisionId()); - VarManager::FillEvent(mcEvent, VarManager::fgValues); + VarManager::FillEvent(mcEvent, static_cast(VarManager::fgValues)); } auto groupedAssocs = assocs.sliceBy(preslice, event.globalIndex()); @@ -1762,7 +1780,7 @@ struct AnalysisSameEventPairing { continue; } - for (auto& [a1, a2] : o2::soa::combinations(groupedAssocs, groupedAssocs)) { + for (const auto& [a1, a2] : o2::soa::combinations(groupedAssocs, groupedAssocs)) { if constexpr (TPairType == VarManager::kDecayToEE) { twoTrackFilter = a1.isBarrelSelected_raw() & a2.isBarrelSelected_raw() & a1.isBarrelSelectedPrefilter_raw() & a2.isBarrelSelectedPrefilter_raw() & fTrackFilterMask; @@ -1818,15 +1836,16 @@ struct AnalysisSameEventPairing { // cout << "primary vertex (before): x -> " << event.posX() << " y -> " << event.posY() << " z -> " << event.posZ() << endl; o2::dataformats::VertexBase pvRefit; bool ok = refitPVWithPVertexer(event, tracks, t1, t2, pvRefit); - if (ok) + if (ok) { VarManager::FillPairVertexingRecomputePV(event, t1, t2, pvRefit); + } // cout << "primary vertex (after): ok -> " << ok << " x -> " << pvRefit.getX() << " y -> " << pvRefit.getY() << " z -> " << pvRefit.getZ() << endl; } } if constexpr (eventHasQvector) { VarManager::FillPairVn(t1, t2); } - if (!fConfigMC.skimSignalOnly || (fConfigMC.skimSignalOnly && mcDecision > 0)) { + if (!fConfigMC.skimSignalOnly || (mcDecision > 0)) { dielectronList(event.globalIndex(), VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], t1.sign() + t2.sign(), twoTrackFilter, mcDecision); @@ -1949,15 +1968,16 @@ struct AnalysisSameEventPairing { bool isAmbiInBunch = false; bool isAmbiOutOfBunch = false; bool isCorrect_pair = false; - if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) + if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) { isCorrect_pair = true; + } for (int icut = 0; icut < ncuts; icut++) { if (twoTrackFilter & (static_cast(1) << icut)) { isAmbiInBunch = (twoTrackFilter & (static_cast(1) << 28)) || (twoTrackFilter & (static_cast(1) << 29)); isAmbiOutOfBunch = (twoTrackFilter & (static_cast(1) << 30)) || (twoTrackFilter & (static_cast(1) << 31)); if (sign1 * sign2 < 0) { // +- pairs - fHistMan->FillHistClass(histNames[icut][0].Data(), VarManager::fgValues); // reconstructed, unmatched + fHistMan->FillHistClass(histNames[icut][0].Data(), static_cast(VarManager::fgValues)); // reconstructed, unmatched for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals if (mcDecision & (static_cast(1) << isig)) { PromptNonPromptSepTable(VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kRap], VarManager::fgValues[VarManager::kPhi], @@ -1999,81 +2019,82 @@ struct AnalysisSameEventPairing { }*/ if (fConfigOptions.fConfigQA) { if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) { // correct track-collision association - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][3].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][3].Data(), static_cast(VarManager::fgValues)); } else { // incorrect track-collision association - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][4].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][4].Data(), static_cast(VarManager::fgValues)); } if (isAmbiInBunch) { // ambiguous in bunch - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][5].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][5].Data(), static_cast(VarManager::fgValues)); if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) { - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][6].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][6].Data(), static_cast(VarManager::fgValues)); } else { - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][7].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][7].Data(), static_cast(VarManager::fgValues)); } } if (isAmbiOutOfBunch) { // ambiguous out of bunch - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][8].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][8].Data(), static_cast(VarManager::fgValues)); if (isCorrectAssoc_leg1 && isCorrectAssoc_leg2) { - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][9].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][9].Data(), static_cast(VarManager::fgValues)); } else { - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][10].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][10].Data(), static_cast(VarManager::fgValues)); } } } } if (fConfigOptions.fConfigQA) { if (isAmbiInBunch) { - fHistMan->FillHistClass(histNames[icut][3].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[icut][3].Data(), static_cast(VarManager::fgValues)); } if (isAmbiOutOfBunch) { - fHistMan->FillHistClass(histNames[icut][3 + 3].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[icut][3 + 3].Data(), static_cast(VarManager::fgValues)); } } } } else { if (sign1 > 0) { // ++ pairs - fHistMan->FillHistClass(histNames[icut][1].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[icut][1].Data(), static_cast(VarManager::fgValues)); for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][1].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][1].Data(), static_cast(VarManager::fgValues)); } } if (fConfigOptions.fConfigQA) { if (isAmbiInBunch) { - fHistMan->FillHistClass(histNames[icut][4].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[icut][4].Data(), static_cast(VarManager::fgValues)); } if (isAmbiOutOfBunch) { - fHistMan->FillHistClass(histNames[icut][4 + 3].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[icut][4 + 3].Data(), static_cast(VarManager::fgValues)); } } } else { // -- pairs - fHistMan->FillHistClass(histNames[icut][2].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[icut][2].Data(), static_cast(VarManager::fgValues)); for (unsigned int isig = 0; isig < fRecMCSignals.size(); isig++) { // loop over MC signals if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][2].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNamesMC[icut * fRecMCSignals.size() + isig][2].Data(), static_cast(VarManager::fgValues)); } } if (fConfigOptions.fConfigQA) { if (isAmbiInBunch) { - fHistMan->FillHistClass(histNames[icut][5].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[icut][5].Data(), static_cast(VarManager::fgValues)); } if (isAmbiOutOfBunch) { - fHistMan->FillHistClass(histNames[icut][5 + 3].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[icut][5 + 3].Data(), static_cast(VarManager::fgValues)); } } } } for (unsigned int iPairCut = 0; iPairCut < fPairCuts.size(); iPairCut++) { AnalysisCompositeCut cut = fPairCuts.at(iPairCut); - if (!(cut.IsSelected(VarManager::fgValues))) // apply pair cuts + if (!(cut.IsSelected(static_cast(VarManager::fgValues)))) { // apply pair cuts continue; + } if (sign1 * sign2 < 0) { - fHistMan->FillHistClass(histNames[ncuts + icut * fPairCuts.size() + iPairCut][0].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[ncuts + icut * fPairCuts.size() + iPairCut][0].Data(), static_cast(VarManager::fgValues)); } else { if (sign1 > 0) { - fHistMan->FillHistClass(histNames[ncuts + icut * fPairCuts.size() + iPairCut][1].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[ncuts + icut * fPairCuts.size() + iPairCut][1].Data(), static_cast(VarManager::fgValues)); } else { - fHistMan->FillHistClass(histNames[ncuts + icut * fPairCuts.size() + iPairCut][2].Data(), VarManager::fgValues); + fHistMan->FillHistClass(histNames[ncuts + icut * fPairCuts.size() + iPairCut][2].Data(), static_cast(VarManager::fgValues)); } } } // end loop (pair cuts) @@ -2082,7 +2103,7 @@ struct AnalysisSameEventPairing { } // end loop over pairs of track associations } // end loop over events - cout << "AnalysisSameEventPairing::runSameEventPairing() completed" << endl; + // cout << "AnalysisSameEventPairing::runSameEventPairing() completed" << endl; } PresliceUnsorted perReducedMcEvent = aod::mcparticle::mcCollisionId; @@ -2091,19 +2112,19 @@ struct AnalysisSameEventPairing { template void runMCGen(TEvents const& events, TEventsMC const& mcEvents, McParticles const& mcTracks) { - cout << "AnalysisSameEventPairing::runMCGen() called" << endl; + // cout << "AnalysisSameEventPairing::runMCGen() called" << endl; uint32_t mcDecision = 0; int isig = 0; // Loop over all MC single particles to fill generator level histograms, disregarding of whether they belong to selected reconstructed events or not - for (auto& mctrack : mcTracks) { - for (auto& sig : fGenMCSignals) { + for (const auto& mctrack : mcTracks) { + for (const auto& sig : fGenMCSignals) { if (sig->CheckSignal(true, mctrack)) { VarManager::FillTrackMC(mcTracks, mctrack); - // if (fUseMCGenAccCut && !fMCGenAccCut.IsSelected(VarManager::fgValues)) { + // if (fUseMCGenAccCut && !fMCGenAccCut.IsSelected(static_cast(VarManager::fgValues))) { // continue; // } - fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), static_cast(VarManager::fgValues)); } } } @@ -2113,7 +2134,7 @@ struct AnalysisSameEventPairing { std::vector eFromJpsiMcParticleIndices; // Now loop over reconstructed events to select only MC particles belonging to the same MC collision as the reconstructed event - for (auto& event : events) { + for (const auto& event : events) { if (!event.isEventSelected_bit(0)) { continue; } @@ -2133,29 +2154,29 @@ struct AnalysisSameEventPairing { auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, mcCollisionGlobalIndex); groupedMCTracks.bindInternalIndicesTo(&mcTracks); - for (auto& track : groupedMCTracks) { + for (const auto& track : groupedMCTracks) { auto track_raw = mcTracks.rawIteratorAt(track.globalIndex()); mcDecision = 0; isig = 0; - for (auto& sig : fGenMCSignals) { + for (const auto& sig : fGenMCSignals) { if (sig->CheckSignal(true, track_raw)) { // check that the mc track belongs to the same mc collision as the reconstructed event if (track.mcCollisionId() != mcCollisionGlobalIndex) { continue; } VarManager::FillTrackMC(mcTracks, track); - // if (fUseMCGenAccCut && !fMCGenAccCut.IsSelected(VarManager::fgValues)) { + // if (fUseMCGenAccCut && !fMCGenAccCut.IsSelected(static_cast(VarManager::fgValues))) { // // cout << "Applying MC gen acceptance cut." << endl; // continue; // } mcDecision |= (static_cast(1) << isig); - fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), static_cast(VarManager::fgValues)); MCTruthTableEffi(VarManager::fgValues[VarManager::kMCPt], VarManager::fgValues[VarManager::kMCEta], VarManager::fgValues[VarManager::kMCY], VarManager::fgValues[VarManager::kMCPhi], VarManager::fgValues[VarManager::kMCVz], VarManager::fgValues[VarManager::kMCVtxZ], VarManager::fgValues[VarManager::kMultFT0A], VarManager::fgValues[VarManager::kMultFT0C], VarManager::fgValues[VarManager::kCentFT0M], VarManager::fgValues[VarManager::kVtxNcontribReal]); if (fConfigOptions.fConfigMiniTree) { - auto mcEvent = mcEvents.rawIteratorAt(track_raw.mcCollisionId()); - dileptonMiniTreeGen(mcDecision, mcEvent.impactParameter(), track_raw.pt(), track_raw.eta(), track_raw.phi(), -999, -999, -999); + auto mcEventFromTrack = mcEvents.rawIteratorAt(track_raw.mcCollisionId()); + dileptonMiniTreeGen(mcDecision, mcEventFromTrack.impactParameter(), track_raw.pt(), track_raw.eta(), track_raw.phi(), -999, -999, -999); } } isig++; @@ -2168,9 +2189,9 @@ struct AnalysisSameEventPairing { if (fHasTwoProngGenMCsignals) { // loop over combinations of the selected mc particles to fill generator level pair histograms - for (auto& t1 : eFromJpsiMcParticleIndices) { + for (const auto& t1 : eFromJpsiMcParticleIndices) { auto t1_raw = mcTracks.rawIteratorAt(t1); - for (auto& t2 : eFromJpsiMcParticleIndices) { + for (const auto& t2 : eFromJpsiMcParticleIndices) { if (t2 <= t1) { continue; // avoid double counting and self-pairing } @@ -2180,7 +2201,7 @@ struct AnalysisSameEventPairing { mcDecision = 0; isig = 0; - for (auto& sig : fGenMCSignals) { + for (const auto& sig : fGenMCSignals) { if (sig->GetNProngs() != 2) { // NOTE: 2-prong signals required here continue; } @@ -2195,51 +2216,51 @@ struct AnalysisSameEventPairing { auto motherMCParticle_t1 = t1_raw.template mothers_first_as(); auto motherMCParticle_t2 = t2_raw.template mothers_first_as(); if (motherMCParticle_t1 == motherMCParticle_t2) { - auto mcEvent = mcEvents.rawIteratorAt(motherMCParticle_t1.mcCollisionId()); - std::array collVtxPos = {mcEvent.posX(), mcEvent.posY(), mcEvent.posZ()}; + auto mcEventFromTrack = mcEvents.rawIteratorAt(motherMCParticle_t1.mcCollisionId()); + std::array collVtxPos = {mcEventFromTrack.posX(), mcEventFromTrack.posY(), mcEventFromTrack.posZ()}; VarManager::FillTrackCollisionMC(motherMCParticle_t1, collVtxPos, pdgDB->Mass(motherMCParticle_t1.pdgCode())); } } if (fConfigOptions.fConfigMCtruthQA.value) { - fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s", sig->GetName()), static_cast(VarManager::fgValues)); } if (fConfigOptions.fConfigPseudoHEQA.value) { - fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairHESel_%s", sig->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairHESel_%s", sig->GetName()), static_cast(VarManager::fgValues)); } if (fConfigOptions.fConfigPseudoCSQA.value) { - fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairCSSel_%s", sig->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairCSSel_%s", sig->GetName()), static_cast(VarManager::fgValues)); } if (fConfigOptions.fConfigPseudoRMQA.value) { - fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairRMSel_%s", sig->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairRMSel_%s", sig->GetName()), static_cast(VarManager::fgValues)); } if (fConfigOptions.fConfigTruthPbPbMIDYHE.value) { - fHistMan->FillHistClass(Form("MCTruthGenPoldielectronPbPbPairHESel_%s", sig->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGenPoldielectronPbPbPairHESel_%s", sig->GetName()), static_cast(VarManager::fgValues)); } if (fConfigOptions.fConfigTruthPbPbMIDYCS.value) { - fHistMan->FillHistClass(Form("MCTruthGenPoldielectronPbPbPairCSSel_%s", sig->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGenPoldielectronPbPbPairCSSel_%s", sig->GetName()), static_cast(VarManager::fgValues)); } if (fUseMCGenAccCut) { - for (auto& cut : fMCGenAccCuts) { - if (cut->IsSelected(VarManager::fgValues)) { + for (const auto& cut : fMCGenAccCuts) { + if (cut->IsSelected(static_cast(VarManager::fgValues))) { if (fConfigOptions.fConfigMCtruthQA.value) { - fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s_%s", sig->GetName(), cut->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGenPairSel_%s_%s", sig->GetName(), cut->GetName()), static_cast(VarManager::fgValues)); } if (fConfigOptions.fConfigPseudoHEQA.value) { - fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairHESel_%s_%s", sig->GetName(), cut->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairHESel_%s_%s", sig->GetName(), cut->GetName()), static_cast(VarManager::fgValues)); } if (fConfigOptions.fConfigPseudoCSQA.value) { - fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairCSSel_%s_%s", sig->GetName(), cut->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairCSSel_%s_%s", sig->GetName(), cut->GetName()), static_cast(VarManager::fgValues)); } if (fConfigOptions.fConfigPseudoRMQA.value) { - fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairRMSel_%s_%s", sig->GetName(), cut->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGenPseudoPolPairRMSel_%s_%s", sig->GetName(), cut->GetName()), static_cast(VarManager::fgValues)); } if (fConfigOptions.fConfigTruthPbPbMIDYHE.value) { - fHistMan->FillHistClass(Form("MCTruthGenPoldielectronPbPbPairHESel_%s_%s", sig->GetName(), cut->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGenPoldielectronPbPbPairHESel_%s_%s", sig->GetName(), cut->GetName()), static_cast(VarManager::fgValues)); } if (fConfigOptions.fConfigTruthPbPbMIDYCS.value) { - fHistMan->FillHistClass(Form("MCTruthGenPoldielectronPbPbPairCSSel_%s_%s", sig->GetName(), cut->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGenPoldielectronPbPbPairCSSel_%s_%s", sig->GetName(), cut->GetName()), static_cast(VarManager::fgValues)); } } } @@ -2257,30 +2278,30 @@ struct AnalysisSameEventPairing { } // end loop over reconstructed events - cout << "AnalysisSameEventPairing::runMCGen() completed" << endl; + // cout << "AnalysisSameEventPairing::runMCGen() completed" << endl; } void processBarrelOnly(MyEventsSelected const& events, BCsWithTimestamps const& bcs, soa::Join const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, McCollisions const& mcEvents, McParticles const& mcTracks) { - cout << "AnalysisSameEventPairing::processBarrelOnly() called" << endl; + // cout << "AnalysisSameEventPairing::processBarrelOnly() called" << endl; runSameEventPairing(events, bcs, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); runMCGen(events, mcEvents, mcTracks); - cout << "AnalysisSameEventPairing::processBarrelOnly() completed" << endl; + // cout << "AnalysisSameEventPairing::processBarrelOnly() completed" << endl; } void processBarrelPbPbOnly(MyEventsSelectedWithCentAndMults const& events, BCsWithTimestamps const& bcs, soa::Join const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, soa::Join const& mcEvents, McParticles const& mcTracks) { - cout << "AnalysisSameEventPairing::processBarrelPbPbOnly() called" << endl; + // cout << "AnalysisSameEventPairing::processBarrelPbPbOnly() called" << endl; runSameEventPairing(events, bcs, trackAssocsPerCollision, barrelAssocs, barrelTracks, mcEvents, mcTracks); runMCGen(events, mcEvents, mcTracks); - cout << "AnalysisSameEventPairing::processBarrelPbPbOnly() completed" << endl; + // cout << "AnalysisSameEventPairing::processBarrelPbPbOnly() completed" << endl; } - void processDummy(MyEvents&) + void processDummy(const MyEvents&) { // do nothing } @@ -2371,7 +2392,7 @@ struct AnalysisDileptonTrack { void init(o2::framework::InitContext& context) { - cout << "AnalysisDileptonTrack::init() called" << endl; + LOG(info) << "AnalysisDileptonTrack::init() called"; bool isBarrel = context.mOptions.get("processBarrel"); // bool isBarrelAsymmetric = context.mOptions.get("processDstarToD0Pi"); // bool isMuon = context.mOptions.get("processMuonSkimmed"); @@ -2380,9 +2401,9 @@ struct AnalysisDileptonTrack { if (isDummy) { if (isBarrel || isMCGen) { - LOG(fatal) << "Dummy function is enabled even if there are normal process functions running! Fix your config!" << endl; + LOG(fatal) << "Dummy function is enabled even if there are normal process functions running! Fix your config!"; } else { - LOG(info) << "Dummy function is enabled. Skipping the rest of the init function" << endl; + LOG(info) << "Dummy function is enabled. Skipping the rest of the init function"; return; } } @@ -2403,7 +2424,7 @@ struct AnalysisDileptonTrack { VarManager::SetDefaultVarNames(); fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars); fHistMan->SetUseDefaultVariableNames(true); - fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + fHistMan->SetDefaultVarNames(static_cast(VarManager::fgVariableNames), static_cast(VarManager::fgVariableUnits)); TString sigNamesStr = fConfigMCOptions.fConfigMCRecSignals.value; std::unique_ptr objRecSigArray(sigNamesStr.Tokenize(",")); @@ -2425,7 +2446,7 @@ struct AnalysisDileptonTrack { TString addMCSignalsStr = fConfigMCOptions.fConfigMCRecSignalsJSON.value; if (addMCSignalsStr != "") { std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); - for (auto& mcIt : addMCSignals) { + for (const auto& mcIt : addMCSignals) { if (mcIt->GetNProngs() != 3) { LOG(fatal) << "Signal at reconstructed level requested (" << mcIt->GetName() << ") " << "does not have 3 prongs! Fix it"; } @@ -2465,7 +2486,7 @@ struct AnalysisDileptonTrack { addMCSignalsStr = fConfigMCOptions.fConfigMCGenSignalsJSON.value; if (addMCSignalsStr != "") { std::vector addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data()); - for (auto& mcIt : addMCSignals) { + for (const auto& mcIt : addMCSignals) { if (mcIt->GetNProngs() == 1) { fGenMCSignals.push_back(mcIt); } @@ -2499,8 +2520,8 @@ struct AnalysisDileptonTrack { cfgTrackSelection_objArrayTrackCuts = new TObjArray(); } std::vector addTrackCuts = dqcuts::GetCutsFromJSON(cfgTrackSelection_TrackCuts.data()); - for (auto& t : addTrackCuts) { - TObjString* tempObjStr = new TObjString(t->GetName()); + for (const auto& t : addTrackCuts) { + auto tempObjStr = new TObjString(t->GetName()); cfgTrackSelection_objArrayTrackCuts->Add(tempObjStr); } } @@ -2540,7 +2561,7 @@ struct AnalysisDileptonTrack { // but this is only used for histograms, not for the produced dilepton tables string cfgPairing_TrackCuts; string cfgPairing_PairCuts; - string cfgPairing_PairCutsJSON; + // string cfgPairing_PairCutsJSON; string cfgPairing_CommonTrackCuts; if (isBarrel) { getTaskOptionValue(context, "analysis-same-event-pairing", "cfgTrackCuts", cfgPairing_TrackCuts, false); @@ -2608,15 +2629,15 @@ struct AnalysisDileptonTrack { TString pairLegCutName; // here we check that this cut is one of those used for building the dileptons - if (isBarrel) { - if (!cfgPairing_objArrayTrackCuts->FindObject(fTrackCutNames[icut].Data())) { - continue; - } - pairLegCutName = fTrackCutNames[icut].Data(); - } else { - // For asymmetric pairs we access the leg cuts instead - pairLegCutName = static_cast(cfgPairing_objArrayTrackCuts->At(icut))->GetString(); + // if (isBarrel) { + if (!cfgPairing_objArrayTrackCuts->FindObject(fTrackCutNames[icut].Data())) { + continue; } + pairLegCutName = fTrackCutNames[icut].Data(); + // } else { + // // For asymmetric pairs we access the leg cuts instead + // pairLegCutName = static_cast(cfgPairing_objArrayTrackCuts->At(icut))->GetString(); + // } fLegCutNames.push_back(pairLegCutName); @@ -2632,7 +2653,7 @@ struct AnalysisDileptonTrack { } DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s", pairLegCutName.Data(), fTrackCutNames[iCutTrack].Data()), fConfigOptions.fConfigHistogramSubgroups.value.data()); - for (auto& sig : fRecMCSignals) { + for (const auto& sig : fRecMCSignals) { DefineHistograms(fHistMan, Form("DileptonTrackMCMatched_%s_%s_%s", pairLegCutName.Data(), fTrackCutNames[iCutTrack].Data(), sig->GetName()), fConfigOptions.fConfigHistogramSubgroups.value.data()); } @@ -2641,7 +2662,7 @@ struct AnalysisDileptonTrack { for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { DefineHistograms(fHistMan, Form("DileptonsSelected_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data()), "barrel,vertexing"); DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iCutTrack].Data()), fConfigOptions.fConfigHistogramSubgroups.value.data()); - for (auto& sig : fRecMCSignals) { + for (const auto& sig : fRecMCSignals) { DefineHistograms(fHistMan, Form("DileptonTrackMCMatched_%s_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iCutTrack].Data(), sig->GetName()), fConfigOptions.fConfigHistogramSubgroups.value.data()); } } @@ -2652,7 +2673,7 @@ struct AnalysisDileptonTrack { for (int iPairCut = 0; iPairCut < fNPairCuts; ++iPairCut) { DefineHistograms(fHistMan, Form("DileptonsSelected_%s_%s", pairLegCutName.Data(), fPairCutNames[iPairCut].Data()), "barrel,vertexing"); DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s", pairLegCutName.Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iCutTrack].Data()), fConfigOptions.fConfigHistogramSubgroups.value.data()); - for (auto& sig : fRecMCSignals) { + for (const auto& sig : fRecMCSignals) { DefineHistograms(fHistMan, Form("DileptonTrackMCMatched_%s_%s_%s_%s", pairLegCutName.Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iCutTrack].Data(), sig->GetName()), fConfigOptions.fConfigHistogramSubgroups.value.data()); } @@ -2661,7 +2682,7 @@ struct AnalysisDileptonTrack { for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; ++iCommonCut) { DefineHistograms(fHistMan, Form("DileptonsSelected_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data()), "barrel,vertexing"); DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iCutTrack].Data()), fConfigOptions.fConfigHistogramSubgroups.value.data()); - for (auto& sig : fRecMCSignals) { + for (const auto& sig : fRecMCSignals) { DefineHistograms(fHistMan, Form("DileptonTrack_%s_%s_%s_%s_%s", pairLegCutName.Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iCutTrack].Data(), sig->GetName()), fConfigOptions.fConfigHistogramSubgroups.value.data()); } } @@ -2673,11 +2694,11 @@ struct AnalysisDileptonTrack { } // end if (isBarrel || isBarrelAsymmetric || isMuon) if (isMCGen) { - for (auto& sig : fGenMCSignals) { + for (const auto& sig : fGenMCSignals) { DefineHistograms(fHistMan, Form("MCTruthGen_%s", sig->GetName()), ""); DefineHistograms(fHistMan, Form("MCTruthGenSel_%s", sig->GetName()), ""); } - for (auto& sig : fRecMCSignals) { + for (const auto& sig : fRecMCSignals) { DefineHistograms(fHistMan, Form("MCTruthGenSelBR_%s", sig->GetName()), ""); DefineHistograms(fHistMan, Form("MCTruthGenSelBRAccepted_%s", sig->GetName()), ""); } @@ -2689,15 +2710,15 @@ struct AnalysisDileptonTrack { } VarManager::SetUseVars(fHistMan->GetUsedVars()); fOutputList.setObject(fHistMan->GetMainHistogramList()); - cout << "AnalysisDileptonTrack::init() completed" << endl; + LOG(info) << "AnalysisDileptonTrack::init() completed"; } // init parameters from CCDB void initParamsFromCCDB(uint64_t timestamp) { - cout << "AnalysisDileptonTrack::initParamsFromCCDB() called for timestamp=" << timestamp << endl; + LOG(info) << "AnalysisDileptonTrack::initParamsFromCCDB() called for timestamp=" << timestamp; if (fConfigCCDBOptions.fConfigUseRemoteField.value) { - o2::parameters::GRPMagField* grpmag = fCCDB->getForTimeStamp(fConfigCCDBOptions.fConfigGRPmagPath.value, timestamp); + auto grpmag = fCCDB->getForTimeStamp(fConfigCCDBOptions.fConfigGRPmagPath.value, timestamp); float magField = 0.0; if (grpmag != nullptr) { magField = grpmag->getNominalL3Field(); @@ -2716,7 +2737,7 @@ struct AnalysisDileptonTrack { VarManager::SetupThreeProngDCAFitter(fConfigCCDBOptions.fConfigMagField.value, true, 200.0f, 4.0f, 1.0e-3f, 0.9f, false); // TODO: get these parameters from Configurables } } - cout << "AnalysisDileptonTrack::initParamsFromCCDB() completed" << endl; + LOG(info) << "AnalysisDileptonTrack::initParamsFromCCDB() completed"; } // Template function to run pair - hadron combinations @@ -2732,12 +2753,12 @@ struct AnalysisDileptonTrack { VarManager::FillEvent(event.mcCollision(), fValuesDilepton); } - uint32_t mcDecision = static_cast(0); + auto mcDecision = static_cast(0); size_t isig = 0; auto bc = event.template bc_as(); - for (auto dilepton : dileptons) { + for (const auto& dilepton : dileptons) { // get full track info of tracks based on the index auto lepton1 = tracks.rawIteratorAt(dilepton.index0Id()); auto lepton2 = tracks.rawIteratorAt(dilepton.index1Id()); @@ -2783,7 +2804,7 @@ struct AnalysisDileptonTrack { } // loop over track associations - for (auto& assoc : assocs) { + for (const auto& assoc : assocs) { VarManager::ResetValues(0, VarManager::kNVars, fValuesHadron); // VarManager::ResetValues(0, VarManager::kNVars, fValuesDilepton); @@ -2943,9 +2964,9 @@ struct AnalysisDileptonTrack { } fHistMan->FillHistClass(Form("DileptonTrack_%s_%s", fLegCutNames[icut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); - for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { - if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s", fLegCutNames[icut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isig]->GetName()), fValuesHadron); + for (uint32_t isignal = 0; isignal < fRecMCSignals.size(); isignal++) { + if (mcDecision & (static_cast(1) << isignal)) { + fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s", fLegCutNames[icut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isignal]->GetName()), fValuesHadron); } } @@ -2953,9 +2974,9 @@ struct AnalysisDileptonTrack { for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { if (dilepton.commonFilterMap_bit(fCommonTrackCutMap[iCommonCut])) { fHistMan->FillHistClass(Form("DileptonTrack_%s_%s_%s", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); - for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { - if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isig]->GetName()), fValuesHadron); + for (uint32_t isignal = 0; isignal < fRecMCSignals.size(); isignal++) { + if (mcDecision & (static_cast(1) << isignal)) { + fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isignal]->GetName()), fValuesHadron); } } } @@ -2963,17 +2984,17 @@ struct AnalysisDileptonTrack { for (int iPairCut = 0; iPairCut < fNPairCuts; iPairCut++) { if (dilepton.pairFilterMap_bit(iPairCut)) { fHistMan->FillHistClass(Form("DileptonTrack_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); - for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { - if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isig]->GetName()), fValuesHadron); + for (uint32_t isignal = 0; isignal < fRecMCSignals.size(); isignal++) { + if (mcDecision & (static_cast(1) << isignal)) { + fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s_%s", fLegCutNames[icut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isignal]->GetName()), fValuesHadron); } } for (int iCommonCut = 0; iCommonCut < fNCommonTrackCuts; iCommonCut++) { if (dilepton.commonFilterMap_bit(fCommonTrackCutMap[iCommonCut])) { fHistMan->FillHistClass(Form("DileptonTrack_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data()), fValuesHadron); - for (uint32_t isig = 0; isig < fRecMCSignals.size(); isig++) { - if (mcDecision & (static_cast(1) << isig)) { - fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isig]->GetName()), fValuesHadron); + for (uint32_t isignal = 0; isignal < fRecMCSignals.size(); isignal++) { + if (mcDecision & (static_cast(1) << isignal)) { + fHistMan->FillHistClass(Form("DileptonTrackMCMatched_%s_%s_%s_%s_%s", fLegCutNames[icut].Data(), fCommonPairCutNames[iCommonCut].Data(), fPairCutNames[iPairCut].Data(), fTrackCutNames[iTrackCut].Data(), fRecMCSignals[isignal]->GetName()), fValuesHadron); } } } @@ -2996,8 +3017,8 @@ struct AnalysisDileptonTrack { MyBarrelTracksWithCov const& tracks, soa::Filtered const& dileptons, McCollisions const& mcEvents, McParticles const& mcTracks) { - cout << "AnalysisDileptonTrack::processBarrel() called" << endl; - // set up KF or DCAfitter + // cout << "AnalysisDileptonTrack::processBarrel() called" << endl; + // set up KF or DCAfitter if (events.size() == 0) { return; } @@ -3005,7 +3026,7 @@ struct AnalysisDileptonTrack { initParamsFromCCDB(bcs.begin().timestamp()); fCurrentRun = bcs.begin().runNumber(); } // end: runNumber - for (auto& event : events) { + for (const auto& event : events) { if (!event.isEventSelected_bit(0)) { continue; } @@ -3015,7 +3036,7 @@ struct AnalysisDileptonTrack { // groupedDielectrons.bindInternalIndicesTo(&dileptons); runDileptonHadron(event, bcs, groupedBarrelAssocs, tracks, groupedDielectrons, mcEvents, mcTracks); } - cout << "AnalysisDileptonTrack::processBarrel() completed" << endl; + // cout << "AnalysisDileptonTrack::processBarrel() completed" << endl; } /* void processDstarToD0Pi(soa::Filtered const& events, BCsWithTimestamps const& bcs, @@ -3070,13 +3091,13 @@ struct AnalysisDileptonTrack { void processMCGen(soa::Filtered const& events, McCollisions const& /*mcEvents*/, McParticles const& mcTracks) { - cout << "AnalysisDileptonTrack::processMCGen() called" << endl; - // first loop over MC particles to fill generator level histograms for one prong MC signals (e.g. the B meson) - for (auto& mctrack : mcTracks) { - for (auto& sig : fGenMCSignals) { + // cout << "AnalysisDileptonTrack::processMCGen() called" << endl; + // first loop over MC particles to fill generator level histograms for one prong MC signals (e.g. the B meson) + for (const auto& mctrack : mcTracks) { + for (const auto& sig : fGenMCSignals) { if (sig->CheckSignal(true, mctrack)) { VarManager::FillTrackMC(mcTracks, mctrack); - fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGen_%s", sig->GetName()), static_cast(VarManager::fgValues)); } } } @@ -3086,7 +3107,7 @@ struct AnalysisDileptonTrack { std::vector mcParticleListDileptonLegs; std::vector mcParticleListHadron; - for (auto& event : events) { + for (const auto& event : events) { if (!event.isEventSelected_bit(0)) { continue; } @@ -3098,12 +3119,12 @@ struct AnalysisDileptonTrack { auto groupedMCTracks = mcTracks.sliceBy(perReducedMcEvent, event.mcCollisionId()); groupedMCTracks.bindInternalIndicesTo(&mcTracks); - for (auto& track : groupedMCTracks) { + for (const auto& track : groupedMCTracks) { auto track_raw = mcTracks.rawIteratorAt(track.globalIndex()); - for (auto& sig : fGenMCSignals) { + for (const auto& sig : fGenMCSignals) { if (sig->CheckSignal(true, track_raw)) { VarManager::FillTrackMC(mcTracks, track); - fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGenSel_%s", sig->GetName()), static_cast(VarManager::fgValues)); } } if (fDileptonLegSignal->CheckSignal(true, track_raw)) { @@ -3116,25 +3137,25 @@ struct AnalysisDileptonTrack { // construct all possible triplets of MC tracks in this MC collision to fill generator level histograms // for three prong MC signals (e.g. B -> J/psi + K) - for (auto& t1 : mcParticleListDileptonLegs) { + for (const auto& t1 : mcParticleListDileptonLegs) { auto t1_raw = mcTracks.rawIteratorAt(t1); - for (auto& t2 : mcParticleListDileptonLegs) { + for (const auto& t2 : mcParticleListDileptonLegs) { if (t2 <= t1) { continue; // avoid double counting and self-pairing } auto t2_raw = mcTracks.rawIteratorAt(t2); - for (auto& t3 : mcParticleListHadron) { + for (const auto& t3 : mcParticleListHadron) { if (t3 == t1 || t3 == t2) { continue; // avoid self-pairing } auto t3_raw = mcTracks.rawIteratorAt(t3); - for (auto& sig : fRecMCSignals) { + for (const auto& sig : fRecMCSignals) { if (sig->CheckSignal(true, t1_raw, t2_raw, t3_raw)) { - VarManager::FillTripleMC(t1_raw, t2_raw, t3_raw, VarManager::fgValues); // nb! hardcoded for jpsiK - fHistMan->FillHistClass(Form("MCTruthGenSelBR_%s", sig->GetName()), VarManager::fgValues); + VarManager::FillTripleMC(t1_raw, t2_raw, t3_raw, static_cast(VarManager::fgValues)); // nb! hardcoded for jpsiK + fHistMan->FillHistClass(Form("MCTruthGenSelBR_%s", sig->GetName()), static_cast(VarManager::fgValues)); // apply kinematic cuts if (t1_raw.pt() < fConfigMCOptions.fConfigMCGenDileptonLegPtMin.value || std::abs(t1_raw.eta()) > fConfigMCOptions.fConfigMCGenDileptonLegEtaAbs.value) { @@ -3146,17 +3167,17 @@ struct AnalysisDileptonTrack { if (t3_raw.pt() < fConfigMCOptions.fConfigMCGenHadronPtMin.value || std::abs(t3_raw.eta()) > fConfigMCOptions.fConfigMCGenHadronEtaAbs.value) { continue; } - fHistMan->FillHistClass(Form("MCTruthGenSelBRAccepted_%s", sig->GetName()), VarManager::fgValues); + fHistMan->FillHistClass(Form("MCTruthGenSelBRAccepted_%s", sig->GetName()), static_cast(VarManager::fgValues)); } } } } } } // end loop over reconstructed events - cout << "AnalysisDileptonTrack::processMCGen() completed" << endl; + // cout << "AnalysisDileptonTrack::processMCGen() completed" << endl; } - void processDummy(MyEvents&) + void processDummy(const MyEvents&) { // do nothing } @@ -3180,7 +3201,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc)}; } -void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups) +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const char* histGroups) { // // Define here the histograms for all the classes required in analysis. diff --git a/PWGDQ/Tasks/dqEnergyCorrelator_direct.cxx b/PWGDQ/Tasks/dqEnergyCorrelator_direct.cxx index 06c997df1fd..3fc4da628f5 100644 --- a/PWGDQ/Tasks/dqEnergyCorrelator_direct.cxx +++ b/PWGDQ/Tasks/dqEnergyCorrelator_direct.cxx @@ -84,7 +84,7 @@ constexpr static uint32_t gkEventFillMapWithMults = VarManager::ObjTypes::BC | V constexpr static uint32_t gkTrackFillMapWithCov = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackCov | VarManager::ObjTypes::TrackPID; // Forward declarations -void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups); // defines histograms for all tasks +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const char* histGroups); // defines histograms for all tasks struct AnalysisEnergyCorrelator { OutputObj fOutputList{"output"}; @@ -530,7 +530,7 @@ struct AnalysisEnergyCorrelator { template void runDileptonHadron(TTrack1 const& track1, TTrack2 const& track2, int iEleCut, - THadron const& hadron, TEvent const& event, aod::McParticles const& /*mcParticles*/) + THadron const& hadron, TEvent const& dileptonEvent, TEvent const& event, aod::McParticles const& /*mcParticles*/) { // Check that hadron is not one of the dilepton legs @@ -556,6 +556,7 @@ struct AnalysisEnergyCorrelator { float Effweight_rec = 1.0f; float Accweight_gen = 1.0f; if (fConfigDileptonHadronOptions.fConfigApplyEfficiency) { + VarManager::FillPair(track1, track2, VarManager::fgValues); float dilepton_pt = VarManager::fgValues[VarManager::kPt]; float dilepton_eta = VarManager::fgValues[VarManager::kEta]; float dilepton_phi = VarManager::fgValues[VarManager::kPhi]; @@ -594,7 +595,7 @@ struct AnalysisEnergyCorrelator { // Fill dilepton-hadron variables std::vector fTransRange = fConfigDileptonHadronOptions.fConfigTransRange; - VarManager::FillEnergyCorrelatorTriple(track1, track2, hadron, VarManager::fgValues, fTransRange[0], fTransRange[1], fConfigDileptonHadronOptions.fConfigApplyMassEC.value, -1, 1. / Effweight_rec); + VarManager::FillEnergyCorrelatorTriple(dileptonEvent, track1, track2, hadron, VarManager::fgValues, fTransRange[0], fTransRange[1], fConfigDileptonHadronOptions.fConfigApplyMassEC.value, -1, 1. / Effweight_rec); if (fConfigDileptonHadronOptions.fConfigUsePionMass.value) { VarManager::FillEnergyCorrelatorsUnfoldingTriple(track1, track2, hadron, motherParticle, hadronMC, VarManager::fgValues, fConfigDileptonHadronOptions.fConfigApplyMassEC.value, 1. / Effweight_rec, 1. / Accweight_gen, fTransRange[0], fTransRange[1]); } else { @@ -826,7 +827,7 @@ struct AnalysisEnergyCorrelator { // Process dilepton-hadron correlation for each common cut for (size_t iCut = 0; iCut < fTrackCuts.size(); iCut++) { if (twoTrackFilter & (static_cast(1) << iCut)) { - runDileptonHadron(t1, t2, iCut, hadron, event, mcParticles); + runDileptonHadron(t1, t2, iCut, hadron, event, event, mcParticles); } } } // end hadron loop @@ -945,7 +946,7 @@ struct AnalysisEnergyCorrelator { // Process dilepton-hadron correlation for each common cut for (size_t iCut = 0; iCut < fTrackCuts.size(); iCut++) { if (twoTrackFilter & (static_cast(1) << iCut)) { - runDileptonHadron(t1, t2, iCut, hadron, event2, mcParticles); + runDileptonHadron(t1, t2, iCut, hadron, event1, event2, mcParticles); } } } // end hadron loop @@ -1182,7 +1183,7 @@ struct AnalysisEnergyCorrelator { }; // Histogram definitions -void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups) +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const char* histGroups) { std::unique_ptr objArray(histClasses.Tokenize(";")); for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { diff --git a/PWGDQ/Tasks/dqFlow.cxx b/PWGDQ/Tasks/dqFlow.cxx index fe16c52daee..323ec4ade4a 100644 --- a/PWGDQ/Tasks/dqFlow.cxx +++ b/PWGDQ/Tasks/dqFlow.cxx @@ -100,7 +100,7 @@ constexpr static uint32_t gkEventFillMapRun3 = VarManager::ObjTypes::BC | VarMan constexpr static uint32_t gkEventFillMapRun3Qvect = VarManager::ObjTypes::BC | VarManager::ObjTypes::Collision | VarManager::ObjTypes::CollisionCent | VarManager::ObjTypes::CollisionQvectCentr; constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackPID; -void DefineHistograms(HistogramManager* histMan, TString histClasses); +void DefineHistograms(HistogramManager* histMan, const TString& histClasses); struct DQEventQvector { @@ -142,7 +142,7 @@ struct DQEventQvector { ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100.1}, "multiplicity / centrality axis for histograms"}; // Define the filter for barrel tracks and forward tracks - Filter trackFilter = (requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true); + Filter trackFilter = (requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t)true); Filter fwdFilter = (aod::fwdtrack::eta < -2.45f) && (aod::fwdtrack::eta > -3.6f); // Histograms used for optionnal efficiency and non-uniform acceptance corrections @@ -656,7 +656,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc)}; } -void DefineHistograms(HistogramManager* histMan, TString histClasses) +void DefineHistograms(HistogramManager* histMan, const TString& histClasses) { // // Define here the histograms for all the classes required in analysis. diff --git a/PWGDQ/Tasks/filterPP.cxx b/PWGDQ/Tasks/filterPP.cxx index 1bfa487594e..71e59bd6f32 100644 --- a/PWGDQ/Tasks/filterPP.cxx +++ b/PWGDQ/Tasks/filterPP.cxx @@ -106,7 +106,7 @@ constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::BC | VarManager constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackSelection | VarManager::ObjTypes::TrackPID; constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::Muon; -void DefineHistograms(HistogramManager* histMan, TString histClasses); +void DefineHistograms(HistogramManager* histMan, const TString& histClasses); struct DQEventSelectionTask { Produces eventSel; @@ -521,7 +521,7 @@ struct DQFilterPPTask { std::vector objCountersBarrel(fNBarrelCuts, 0); // init all counters to zero // count the number of barrel tracks fulfilling each cut - for (auto track : tracksBarrel) { + for (const auto& track : tracksBarrel) { for (int i = 0; i < fNBarrelCuts; ++i) { if (track.isDQBarrelSelected() & (static_cast(1) << i)) { objCountersBarrel[i] += 1; @@ -585,7 +585,7 @@ struct DQFilterPPTask { std::vector objCountersMuon(fNMuonCuts, 0); // init all counters to zero // count the number of muon tracks fulfilling each selection - for (auto muon : muons) { + for (const auto& muon : muons) { for (int i = 0; i < fNMuonCuts; ++i) { if (muon.isDQMuonSelected() & (static_cast(1) << i)) { objCountersMuon[i] += 1; @@ -701,7 +701,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc)}; } -void DefineHistograms(HistogramManager* histMan, TString histClasses) +void DefineHistograms(HistogramManager* histMan, const TString& histClasses) { // // Define here the histograms for all the classes required in analysis. diff --git a/PWGDQ/Tasks/filterPPwithAssociation.cxx b/PWGDQ/Tasks/filterPPwithAssociation.cxx index cf7c18ce8f6..a338691417b 100644 --- a/PWGDQ/Tasks/filterPPwithAssociation.cxx +++ b/PWGDQ/Tasks/filterPPwithAssociation.cxx @@ -123,7 +123,7 @@ constexpr static uint32_t gkTrackFillMap = VarManager::ObjTypes::Track | VarMana constexpr static uint32_t gkTrackFillMapTPCPID = VarManager::ObjTypes::Track | VarManager::ObjTypes::TrackExtra | VarManager::ObjTypes::TrackDCA | VarManager::ObjTypes::TrackTPCPID; constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::Muon | VarManager::ObjTypes::MuonCov; -void DefineHistograms(HistogramManager* histMan, TString histClasses, TString subgroups = ""); +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const TString& subgroups = ""); template void PrintBitMap(TMap map, int nbits) @@ -720,7 +720,7 @@ struct DQFilterPPTask { uint32_t pairFilter = 0; // count the number of barrel tracks fulfilling each cut if constexpr (static_cast(TTrackFillMap)) { - for (auto trackAssoc : barrelAssocs) { + for (const auto& trackAssoc : barrelAssocs) { for (int i = 0; i < fNBarrelCuts; ++i) { if (trackAssoc.isDQBarrelSelected() & (static_cast(1) << i)) { objCountersBarrel[i] += 1; @@ -1227,7 +1227,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc)}; } -void DefineHistograms(HistogramManager* histMan, TString histClasses, TString subgroups) +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const TString& subgroups) { // // Define here the histograms for all the classes required in analysis. diff --git a/PWGDQ/Tasks/global-muon-matcher.cxx b/PWGDQ/Tasks/global-muon-matcher.cxx index ab91c5cae70..98863864b8e 100644 --- a/PWGDQ/Tasks/global-muon-matcher.cxx +++ b/PWGDQ/Tasks/global-muon-matcher.cxx @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/PWGDQ/Tasks/mftMchMatcher.cxx b/PWGDQ/Tasks/mftMchMatcher.cxx index 024bb1b36c4..6149433f586 100644 --- a/PWGDQ/Tasks/mftMchMatcher.cxx +++ b/PWGDQ/Tasks/mftMchMatcher.cxx @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -46,7 +47,6 @@ #include #include #include -#include #include #include diff --git a/PWGDQ/Tasks/muonGlobalAlignment.cxx b/PWGDQ/Tasks/muonGlobalAlignment.cxx index 1d328384718..66f3b57240d 100644 --- a/PWGDQ/Tasks/muonGlobalAlignment.cxx +++ b/PWGDQ/Tasks/muonGlobalAlignment.cxx @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -56,8 +57,10 @@ #include #include #include -#include -#include +#include // IWYU pragma: keep (do not replace with Math/Vector3Dfwd.h) +#include +#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) +#include #include #include #include @@ -74,14 +77,18 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include +#include #include +#include #include #include #include @@ -93,15 +100,10 @@ using namespace o2::aod; using namespace o2::aod::rctsel; -// using MyReducedMuons = soa::Join; -// using MyReducedEvents = soa::Join; -// using MyReducedEventsVtxCov = soa::Join; - using MyCollisions = aod::Collisions; using MyBCs = soa::Join; using MyEvents = soa::Join; using MyMuonsWithCov = soa::Join; -// using MyMuonsWithCov = aod::FwdTracks; using MyMFTs = aod::MFTTracks; using MyMFTCovariances = aod::MFTTracksCov; @@ -117,18 +119,142 @@ using SMatrix5 = ROOT::Math::SVector; using o2::dataformats::GlobalFwdTrack; using o2::track::TrackParCovFwd; +namespace muonaligncoll +{ +DECLARE_SOA_COLUMN(RunNumber, runNumber, int); +DECLARE_SOA_COLUMN(Timestamp, timestamp, uint64_t); //! Timestamp of a BC in ms (epoch style) +} // namespace muonaligncoll + +namespace o2::aod +{ +// Reduced collisions table +DECLARE_SOA_TABLE(MACollisions, "AOD", "MACOLL", //! Time and vertex information of collision + o2::soa::Index<>, muonaligncoll::RunNumber, muonaligncoll::Timestamp, + collision::PosX, collision::PosY, collision::PosZ, + collision::CovXX, collision::CovYY, collision::CovZZ); +using MACollision = MACollisions::iterator; +} // namespace o2::aod + +namespace muonalignmfttrk +{ +DECLARE_SOA_INDEX_COLUMN_FULL_CUSTOM(Collision, collision, int32_t, MACollisions, "MACOLLs", ""); +} // namespace muonalignmfttrk + namespace o2::aod { +// Reduced MFT tracks table +DECLARE_SOA_TABLE(StoredMAMFTTracks, "AOD", "MAMFTTRK", //! On disk version of MFTTracks + o2::soa::Index<>, muonalignmfttrk::CollisionId, + fwdtrack::X, fwdtrack::Y, fwdtrack::Z, fwdtrack::Phi, fwdtrack::Tgl, fwdtrack::Signed1Pt, + fwdtrack::v001::NClusters, fwdtrack::MFTClusterSizesAndTrackFlags, fwdtrack::IsCA, + fwdtrack::Px, + fwdtrack::Py, + fwdtrack::Pz, + fwdtrack::Sign, fwdtrack::Chi2); + +DECLARE_SOA_EXTENDED_TABLE_USER(MAMFTTracks, StoredMAMFTTracks, "MAMFTTRK", //! Additional MFTTracks information (Pt, Eta, P), version 0 + aod::fwdtrack::Pt, + aod::fwdtrack::Eta, + aod::fwdtrack::P); +using MAMFTTrack = MAMFTTracks::iterator; +} // namespace o2::aod + +namespace muonalignfwdtrk +{ +DECLARE_SOA_INDEX_COLUMN_FULL_CUSTOM(Collision, collision, int32_t, MACollisions, "MACOLLs", ""); +// Index of matching MCH track for GlobalMuonTracks and GlobalForwardTracks +DECLARE_SOA_SELF_INDEX_COLUMN_FULL(MAMCHTrack, matchMCHTrack, int, "MAFWDTRACKs_MatchMCHTrack"); // o2-linter: disable=name/o2-column (to match naming in official tables) +// ID of matching MFT track for GlobalMuonTracks and GlobalForwardTracks +DECLARE_SOA_INDEX_COLUMN_FULL_CUSTOM(MAMFTTrack, matchMFTTrack, int32_t, MAMFTTracks, "MAMFTTRKs", ""); // o2-linter: disable=name/o2-column (to match naming in official tables) +} // namespace muonalignfwdtrk + +namespace o2::aod +{ +// Reduced forward tracks table +DECLARE_SOA_TABLE(StoredMAFwdTracks, "AOD", "MAFWDTRACK", + o2::soa::Index<>, muonalignfwdtrk::CollisionId, fwdtrack::TrackType, + fwdtrack::X, fwdtrack::Y, fwdtrack::Z, fwdtrack::Phi, fwdtrack::Tgl, + fwdtrack::Signed1Pt, fwdtrack::NClusters, fwdtrack::PDca, fwdtrack::RAtAbsorberEnd, + fwdtrack::Px, + fwdtrack::Py, + fwdtrack::Pz, + fwdtrack::Sign, + fwdtrack::Chi2, fwdtrack::Chi2MatchMCHMFT, + muonalignfwdtrk::MAMFTTrackId, muonalignfwdtrk::MAMCHTrackId); + +DECLARE_SOA_EXTENDED_TABLE_USER(MAFwdTracks, StoredMAFwdTracks, "MAFWDTRACK", //! + aod::fwdtrack::Pt, + aod::fwdtrack::Eta, + aod::fwdtrack::P); + +// Reduced forward track covariances table + +DECLARE_SOA_TABLE(StoredMAFwdTracksCov, "AOD", "MAFWDTRACKSCOV", //! + fwdtrack::SigmaX, fwdtrack::SigmaY, fwdtrack::SigmaPhi, fwdtrack::SigmaTgl, fwdtrack::Sigma1Pt, + fwdtrack::RhoXY, fwdtrack::RhoPhiY, fwdtrack::RhoPhiX, fwdtrack::RhoTglX, fwdtrack::RhoTglY, + fwdtrack::RhoTglPhi, fwdtrack::Rho1PtX, fwdtrack::Rho1PtY, fwdtrack::Rho1PtPhi, fwdtrack::Rho1PtTgl); + +DECLARE_SOA_EXTENDED_TABLE_USER(MAFwdTracksCov, StoredMAFwdTracksCov, "MAFWDTRACKSCOV", //! + aod::fwdtrack::CXX, + aod::fwdtrack::CXY, + aod::fwdtrack::CYY, + aod::fwdtrack::CPhiX, + aod::fwdtrack::CPhiY, + aod::fwdtrack::CPhiPhi, + aod::fwdtrack::CTglX, + aod::fwdtrack::CTglY, + aod::fwdtrack::CTglPhi, + aod::fwdtrack::CTglTgl, + aod::fwdtrack::C1PtX, + aod::fwdtrack::C1PtY, + aod::fwdtrack::C1PtPhi, + aod::fwdtrack::C1PtTgl, + aod::fwdtrack::C1Pt21Pt2); + +using MAFwdTrack = MAFwdTracks::iterator; +using MAFwdTrackCov = MAFwdTracksCov::iterator; +} // namespace o2::aod + +namespace muonaligncl +{ +DECLARE_SOA_INDEX_COLUMN_FULL_CUSTOM(FwdTrack, fwdTrack, int32_t, MAFwdTracks, "MAFwdTracks", ""); +} // namespace muonaligncl + +namespace o2::aod +{ +// Reduced MCH clusters table +DECLARE_SOA_TABLE(MAFwdTrkCls, "AOD", "MAFWDTRKCL", //! Forward Track Cluster information + o2::soa::Index<>, + muonaligncl::FwdTrackId, + fwdtrkcl::X, + fwdtrkcl::Y, + fwdtrkcl::Z, + fwdtrkcl::ClInfo, + fwdtrkcl::DEId, + fwdtrkcl::IsGoodX, + fwdtrkcl::IsGoodY); + +using MAFwdTrkCl = MAFwdTrkCls::iterator; +} // namespace o2::aod + +namespace o2::aod +{ +// Compact collision + MFT tracks table for DCA analysis DECLARE_SOA_TABLE(CompactMFTTracks, "AOD", "COMPACTMFT", //! standalone table for studying alignment collision::PosX, collision::PosY, collision::PosZ, fwdtrack::Signed1Pt, fwdtrack::Tgl, fwdtrack::Phi, fwdtrack::FwdDcaX, fwdtrack::FwdDcaY, o2::aod::fwdtrack::CXX, o2::aod::fwdtrack::CYY, o2::aod::fwdtrack::CXY, fwdtrack::NClusters, fwdtrack::Chi2, fwdtrack::X, fwdtrack::Y, fwdtrack::Z); -using CompactMFTTrack = CompactMFTTracks; +using CompactMFTTrack = CompactMFTTracks::iterator; } // namespace o2::aod -struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struct (exception) +// Switch to enable/disable the processing of the derived tables +// 0: process standard AO2Ds and produce the derived tables +// 1: process derived AO2Ds and disable the derived tables creation +#define PROCESS_DERIVED_TABLES 0 + +struct MuonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struct (exception) static constexpr int GlobalTrackTypeMax = 2; static constexpr int NMchChambers = 10; @@ -138,8 +264,17 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc static constexpr double AbsorberBackZ = -505.f; static constexpr double BransonPlaneZ = -466.f; - Produces mftTable; - Configurable cfgProduceMFTTable{"cfgProduceMFTTable", false, "flag to produce MFTsa table"}; +#if (PROCESS_DERIVED_TABLES == 0) + Produces collTable; + Produces fwdTable; + Produces fwdCovTable; + Produces mftTable; + Produces clusTable; + Produces compactMftTable; + Configurable cfgProduceMuonAlignmentTables{"cfgProduceMuonAlignmentTables", false, "flag to produce derived tables for muon alignment"}; + Configurable cfgProduceMuonAlignmentTablesWithCovariances{"cfgProduceMuonAlignmentTablesWithCovariances", true, "flag to include muon track covariances in derived tables for muon alignment"}; + Configurable cfgProduceMFTTable{"cfgProduceMFTTable", false, "flag to produce MFTs table"}; +#endif //// Variables for selecting MCH and MFT tracks Configurable cfgTrackChi2MchUp{"cfgTrackChi2MchUp", 5.f, ""}; @@ -194,6 +329,15 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc Configurable cfgMCHRealignCorrections{"cfgMCHRealignCorrections", "", "MCH DE positions/angles corrections in JSON format"}; } configRealign; + //// Variables for forward two-prong fitter + struct : ConfigurableGroup { + Configurable cfgFitterTwoProngFwdPropagateToPCA{"cfgFitterTwoProngFwdPropagateToPCA", true, ""}; + Configurable cfgFitterTwoProngFwdMaxR{"cfgFitterTwoProngFwdMaxR", 200.f, ""}; + Configurable cfgFitterTwoProngFwdMinParamChange{"cfgFitterTwoProngFwdMinParamChange", 1.0e-3f, ""}; + Configurable cfgFitterTwoProngFwdMinRelChi2Change{"cfgFitterTwoProngFwdMinRelChi2Change", 0.9f, ""}; + Configurable cfgFitterTwoProngFwdUseAbsDCA{"cfgFitterTwoProngFwdUseAbsDCA", false, ""}; + } configFitterTwoProngFwd; + //// Variables for ccdb struct : ConfigurableGroup { Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; @@ -206,6 +350,19 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc Configurable cfgCcdbNoLaterThanNew{"cfgCcdbNoLaterThanNew", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object of new basis"}; } configCCDB; + //// Variables for histograms configuration + struct : ConfigurableGroup { + Configurable cfgHistMftDcaVzAxis{"cfgHistMftDcaVzAxis", "", "Vertex z axis configuration for MFT DCA histograms"}; + Configurable cfgHistMftDcaTxAxis{"cfgHistMftDcaTxAxis", "", "Track x axis configuration for MFT DCA histograms"}; + Configurable cfgHistMftDcaTyAxis{"cfgHistMftDcaTyAxis", "", "Track y axis configuration for MFT DCA histograms"}; + Configurable cfgHistMftDcaNclusAxis{"cfgHistMftDcaNclusAxis", "", "Clusters axis configuration for MFT DCA histograms"}; + Configurable cfgHistMftDcaEnableDetailedVzAnalysis{"cfgHistMftDcaEnableDetailedVzAnalysis", false, ""}; + Configurable cfgHistDimuonLxyAxis{"cfgHistDimuonLxyAxis", "", "Di-muon Lxy axis configuration"}; + Configurable cfgHistDimuonLzAxis{"cfgHistDimuonLzAxis", "", "Di-muon Lz axis configuration"}; + Configurable cfgHistDimuonTauxyAxis{"cfgHistDimuonTauxyAxis", "", "Di-muon tauxy axis configuration"}; + Configurable cfgHistDimuonTauzAxis{"cfgHistDimuonTauzAxis", "", "Di-muon tauz axis configuration"}; + } configHistograms; + Configurable cfgRequireGoodRCT{"cfgRequireGoodRCT", true, "Require good detector flags in Run Condition Table"}; Configurable cfgEnableVertexShiftAnalysis{"cfgEnableVertexShiftAnalysis", false, "Enable the analysis of vertex shift"}; @@ -296,6 +453,8 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc TrackFitter trackFitter; // Track fitter from MCH tracking library double mImproveCutChi2{0}; // Chi2 cut for track improvement. + o2::vertexing::FwdDCAFitterN<2> fgFitterTwoProngFwd; + struct AlignmentCorrections { double x{0}; double y{0}; @@ -303,7 +462,11 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc }; std::map mMchAlignmentCorrections; +#if (PROCESS_DERIVED_TABLES == 0) Preslice perMuon = aod::fwdtrkcl::fwdtrackId; +#else + Preslice perMuon = muonaligncl::fwdTrackId; +#endif o2::aod::rctsel::RCTFlagsChecker rctChecker{"CBT_muon_glo", false, false, true}; @@ -319,7 +482,8 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc using MatchingCandidates = std::map>; struct CollisionInfo { - uint64_t bc{0}; + int runNumber{0}; + uint64_t timestamp{0}; // z position of the collision double zVertex{0}; // number of MFT tracks associated to the collision @@ -332,6 +496,28 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc std::map> globalMuonTracks; }; + std::tuple getAxisConfiguration(std::string cfgStr, int nBinsDef, double xMinDef, double xMaxDef) + { + // replace commas and semi-colons by spaces + for (size_t i = 0; i < cfgStr.size(); i++) { + if (cfgStr[i] == ',' || cfgStr[i] == ';') { + cfgStr[i] = ' '; + } + } + + std::tuple result{nBinsDef, xMinDef, xMaxDef}; + std::stringstream cfg(cfgStr); + try { + cfg >> std::get<0>(result); + cfg >> std::get<1>(result); + cfg >> std::get<2>(result); + } catch (const std::exception& e) { + return result; + } + + return result; + } + template void initCCDB(BC const& bc) { @@ -350,6 +536,8 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc fieldB = dynamic_cast(TGeoGlobalMagField::Instance()->GetField()); // for MFT std::array centerMFT{0, 0, -61.4}; // or use middle point between Vtx and MFT? mBzAtMftCenter = fieldB->getBz(centerMFT.data()); + + fgFitterTwoProngFwd.setBz(grpmag->getNominalL3Field()); } else { LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", bc.timestamp()); } @@ -430,14 +618,26 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc LOG(error) << "JSON parse error: " << rapidjson::GetParseErrorFunc(jsonOk.Code()) << " (" << jsonOk.Offset() << ")"; } + // two-prong track fitter setup + fgFitterTwoProngFwd.setPropagateToPCA(configFitterTwoProngFwd.cfgFitterTwoProngFwdPropagateToPCA.value); + fgFitterTwoProngFwd.setMaxR(configFitterTwoProngFwd.cfgFitterTwoProngFwdMaxR.value); + fgFitterTwoProngFwd.setMinParamChange(configFitterTwoProngFwd.cfgFitterTwoProngFwdMinParamChange.value); + fgFitterTwoProngFwd.setMinRelChi2Change(configFitterTwoProngFwd.cfgFitterTwoProngFwdMinRelChi2Change.value); + fgFitterTwoProngFwd.setUseAbsDCA(configFitterTwoProngFwd.cfgFitterTwoProngFwdUseAbsDCA.value); + float mftLadderWidth = 1.7; AxisSpec dcaxMFTAxis = {400, -0.5, 0.5, "DCA_{x} (cm)"}; AxisSpec dcayMFTAxis = {400, -0.5, 0.5, "DCA_{y} (cm)"}; AxisSpec dcaxMCHAxis = {400, -10.0, 10.0, "DCA_{x} (cm)"}; AxisSpec dcayMCHAxis = {400, -10.0, 10.0, "DCA_{y} (cm)"}; - AxisSpec dcazAxis = {20, -10.0, 10.0, "v_{z} (cm)"}; - AxisSpec txAxis = {30 * 4, -mftLadderWidth * 15.f / 2.f, mftLadderWidth * 15.f / 2.f, "track_{x} (cm)"}; - AxisSpec tyAxis = {24 * 4, -12.f, 12.f, "track_{y} (cm)"}; + auto dcaVzAxisConfig = getAxisConfiguration(configHistograms.cfgHistMftDcaVzAxis, 20, -10., 10.); + AxisSpec dcaVzAxis = {std::get<0>(dcaVzAxisConfig), std::get<1>(dcaVzAxisConfig), std::get<2>(dcaVzAxisConfig), "v_{z} (cm)"}; + auto txAxisConfig = getAxisConfiguration(configHistograms.cfgHistMftDcaTxAxis, 30 * 4, -mftLadderWidth * 15.f / 2.f, mftLadderWidth * 15.f / 2.f); + AxisSpec txAxis = {std::get<0>(txAxisConfig), std::get<1>(txAxisConfig), std::get<2>(txAxisConfig), "track_{x} (cm)"}; + auto tyAxisConfig = getAxisConfiguration(configHistograms.cfgHistMftDcaTyAxis, 24 * 4, -12.f, 12.f); + AxisSpec tyAxis = {std::get<0>(tyAxisConfig), std::get<1>(tyAxisConfig), std::get<2>(tyAxisConfig), "track_{y} (cm)"}; + AxisSpec txCoarseAxis = {2, -mftLadderWidth * 15.f / 2.f, mftLadderWidth * 15.f / 2.f, "track_{x} (cm)"}; + AxisSpec tyCoarseAxis = {2, -12.f, 12.f, "track_{y} (cm)"}; AxisSpec txFineAxis = {1500, -15.f, 15.f, "track_{x} (cm)"}; AxisSpec tyFineAxis = {1500, -15.f, 15.f, "track_{y} (cm)"}; AxisSpec vxAxis = {400, -0.5, 0.5, "vtx_{x} (cm)"}; @@ -474,10 +674,21 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc } if (cfgEnableMftDcaAnalysis) { - registry.add("DCA/MFT/DCA_x", "DCA(x) vs. vz, tx, ty, nclus", - HistType::kTHnSparseF, {dcaxMFTAxis, dcazAxis, txAxis, tyAxis, nMftClustersAxis}); - registry.add("DCA/MFT/DCA_y", "DCA(y) vs. vz, tx, ty, nclus", - HistType::kTHnSparseF, {dcayMFTAxis, dcazAxis, txAxis, tyAxis, nMftClustersAxis}); + if (configHistograms.cfgHistMftDcaEnableDetailedVzAnalysis) { + registry.add("DCA/MFT/DCA_x", "DCA(x) vs. vz, tx, ty, nclus", + HistType::kTHnSparseF, {dcaxMFTAxis, dcaVzAxis, txAxis, tyAxis, nMftClustersAxis}); + registry.add("DCA/MFT/DCA_y", "DCA(y) vs. vz, tx, ty, nclus", + HistType::kTHnSparseF, {dcayMFTAxis, dcaVzAxis, txAxis, tyAxis, nMftClustersAxis}); + } else { + registry.add("DCA/MFT/DCA_x", "DCA(x) vs. vz, tx, ty, nclus", + HistType::kTHnSparseF, {dcaxMFTAxis, {1, -10., 10., "v_{z} (cm)"}, txAxis, tyAxis, nMftClustersAxis}); + registry.add("DCA/MFT/DCA_y", "DCA(y) vs. vz, tx, ty, nclus", + HistType::kTHnSparseF, {dcayMFTAxis, {1, -10., 10., "v_{z} (cm)"}, txAxis, tyAxis, nMftClustersAxis}); + registry.add("DCA/MFT/DCAxVsVz", "DCA(x) vs. vz", + HistType::kTHnSparseF, {dcaxMFTAxis, dcaVzAxis, txCoarseAxis, tyCoarseAxis, nMftClustersAxis}); + registry.add("DCA/MFT/DCAyVsVz", "DCA(y) vs. vz", + HistType::kTHnSparseF, {dcayMFTAxis, dcaVzAxis, txCoarseAxis, tyCoarseAxis, nMftClustersAxis}); + } if (cfgEnableMftDcaExtraPlots) { registry.add("DCA/MFT/layers", "Layers vs. tx, ty, nclus", @@ -501,9 +712,9 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc if (cfgEnableGlobalFwdDcaAnalysis) { registry.add("DCA/GlobalFwd/DCA_x", "DCA(x) vs. vz, tx, ty, nclus", - HistType::kTHnSparseF, {dcaxMFTAxis, dcazAxis, txAxis, tyAxis, nMftClustersAxis}); + HistType::kTHnSparseF, {dcaxMFTAxis, dcaVzAxis, txAxis, tyAxis, nMftClustersAxis}); registry.add("DCA/GlobalFwd/DCA_y", "DCA(y) vs. vz, tx, ty, nclus", - HistType::kTHnSparseF, {dcayMFTAxis, dcazAxis, txAxis, tyAxis, nMftClustersAxis}); + HistType::kTHnSparseF, {dcayMFTAxis, dcaVzAxis, txAxis, tyAxis, nMftClustersAxis}); } if (cfgEnableMftMchResidualsAnalysis) { @@ -551,8 +762,8 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc } if (cfgEnableMftMchResidualsExtraPlots) { - registry.add("DCA/MCH/DCA_x_vs_sign_vs_quadrant_vs_vz", std::format("DCA(x) vs. vz, quadrant, chargeSign").c_str(), {HistType::kTHnSparseF, {dcazAxis, {4, 0, 4, "quadrant"}, {2, 0, 2, "sign"}, dcaxMCHAxis}}); - registry.add("DCA/MCH/DCA_y_vs_sign_vs_quadrant_vs_vz", std::format("DCA(y) vs. vz, quadrant, chargeSign").c_str(), {HistType::kTHnSparseF, {dcazAxis, {4, 0, 4, "quadrant"}, {2, 0, 2, "sign"}, dcayMCHAxis}}); + registry.add("DCA/MCH/DCA_x_vs_sign_vs_quadrant_vs_vz", std::format("DCA(x) vs. vz, quadrant, chargeSign").c_str(), {HistType::kTHnSparseF, {dcaVzAxis, {4, 0, 4, "quadrant"}, {2, 0, 2, "sign"}, dcaxMCHAxis}}); + registry.add("DCA/MCH/DCA_y_vs_sign_vs_quadrant_vs_vz", std::format("DCA(y) vs. vz, quadrant, chargeSign").c_str(), {HistType::kTHnSparseF, {dcaVzAxis, {4, 0, 4, "quadrant"}, {2, 0, 2, "sign"}, dcayMCHAxis}}); registry.add("residuals/dphi_at_mft", "Track #Delta#phi at MFT", {HistType::kTHnSparseF, {{200, -0.2f, 0.2f, "#Delta#phi"}, {80, -10.f, 10.f, "track_x (cm)"}, {80, -10.f, 10.f, "track_y (cm)"}, {2, 0, 2, "sign"}, {20, 0, 100.0, "p (GeV/c)"}}}); @@ -593,12 +804,21 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc if (cfgEnableDimuonAnalysis) { AxisSpec invMassAxis = {1500, 0, 15, "M_{#mu^{+}#mu^{-}} (GeV/c^{2})"}; + AxisSpec invMassAxisCoarse = {60, 2, 5, "M_{#mu^{+}#mu^{-}} (GeV/c^{2})"}; AxisSpec pTAxis = {30, 0, 30, "#mu^{+}#mu^{-} p_{T} (GeV/c)"}; AxisSpec pAxis = {50, 0, 200, "#mu^{+}#mu^{-} p (GeV/c)"}; AxisSpec muPosQuadrantAxis = {4, 0, 4, "#mu^{+} quadrant"}; AxisSpec muNegQuadrantAxis = {4, 0, 4, "#mu^{-} quadrant"}; AxisSpec angleAxis = {100, 0, 0.5, "#mu^{+}#mu^{-} angle (rad)"}; AxisSpec angleDiffAxis = {500, -0.05, 0.05, "#mu^{+}#mu^{-} angle difference (rad)"}; + auto lzAxisConfig = getAxisConfiguration(configHistograms.cfgHistDimuonLzAxis, 100, -0.5, 1.5); + AxisSpec lzAxis = {std::get<0>(lzAxisConfig), std::get<1>(lzAxisConfig), std::get<2>(lzAxisConfig), "L_{z}^{#mu#mu} (cm)"}; + auto tauzAxisConfig = getAxisConfiguration(configHistograms.cfgHistDimuonTauzAxis, 200, -10., 10.); + AxisSpec tauzAxis = {std::get<0>(tauzAxisConfig), std::get<1>(tauzAxisConfig), std::get<2>(tauzAxisConfig), "#tau_{z}^{#mu#mu} (cm)"}; + auto lxyAxisConfig = getAxisConfiguration(configHistograms.cfgHistDimuonLxyAxis, 100, 0, 0.2); + AxisSpec lxyAxis = {std::get<0>(lxyAxisConfig), std::get<1>(lxyAxisConfig), std::get<2>(lxyAxisConfig), "L_{xy}^{#mu#mu} (cm)"}; + auto tauxyAxisConfig = getAxisConfiguration(configHistograms.cfgHistDimuonTauxyAxis, 200, 0, 20); + AxisSpec tauxyAxis = {std::get<0>(tauxyAxisConfig), std::get<1>(tauxyAxisConfig), std::get<2>(tauxyAxisConfig), "L_{xy}^{#mu#mu} (cm)"}; AxisSpec dcaxAxis = {400, -10.0, 10.0, "#mu^{+}#mu^{-} DCA_{x} (cm)"}; AxisSpec dcayAxis = {400, -10.0, 10.0, "#mu^{+}#mu^{-} DCA_{y} (cm)"}; AxisSpec dcaMftxAxis = {400, -0.5, 0.5, "#mu^{+}#mu^{-} DCA_{x} (cm)"}; @@ -609,7 +829,7 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc registry.add("dimuon/invariantMass_MuonKine_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} invariant mass (global muon cuts, good matches)", {HistType::kTHnSparseF, {invMassAxis, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); registry.add("dimuon/invariantMass_ScaledMftKine_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} invariant mass (global muon cuts, rescaled MFT, good matches)", {HistType::kTHnSparseF, {invMassAxis, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); // difference in mu+mu- opening angle between MCH and global muon tracks - registry.add("dimuon/angle_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} opening angle difference (global muon cuts, good matches)", {HistType::kTHnSparseF, {angleDiffAxis, angleAxis, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); + registry.add("dimuon/angle_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} opening angle difference (global muon cuts, good matches)", {HistType::kTHnSparseF, {angleDiffAxis, invMassAxisCoarse, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); // mu+mu- DCA registry.add("dimuon/dcax_MuonKine_MuonCuts", "#mu^{+}#mu^{-} DCA_{x} (muon cuts)", {HistType::kTHnSparseF, {dcaxAxis, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); registry.add("dimuon/dcay_MuonKine_MuonCuts", "#mu^{+}#mu^{-} DCA_{y} (muon cuts)", {HistType::kTHnSparseF, {dcayAxis, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); @@ -617,13 +837,19 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc registry.add("dimuon/dcay_MuonKine_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} DCA_{y} (global muon cuts, good matches)", {HistType::kTHnSparseF, {dcayAxis, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); registry.add("dimuon/dcax_ScaledMftKine_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} DCA_{x} (global muon cuts, rescaled MFT, good matches)", {HistType::kTHnSparseF, {dcaMftxAxis, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); registry.add("dimuon/dcay_ScaledMftKine_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} DCA_{y} (global muon cuts, rescaled MFT, good matches)", {HistType::kTHnSparseF, {dcaMftyAxis, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); + // mu+mu- decay length z + registry.add("dimuon/Lz_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} L_{z} (global muon cuts, good matches)", {HistType::kTHnSparseF, {lzAxis, invMassAxisCoarse, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); + registry.add("dimuon/tauz_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} L_{z} (global muon cuts, good matches)", {HistType::kTHnSparseF, {tauzAxis, invMassAxisCoarse, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); + // mu+mu- decay length xy + registry.add("dimuon/Lxy_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} L_{xy} (global muon cuts, good matches)", {HistType::kTHnSparseF, {lxyAxis, invMassAxisCoarse, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); + registry.add("dimuon/tauxy_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} L_{xy} (global muon cuts, good matches)", {HistType::kTHnSparseF, {tauxyAxis, invMassAxisCoarse, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); // di-muon invariant mass distributions (realigned/refitted tracks) registry.add("dimuon/realign/invariantMass_MuonKine_MuonCuts", "#mu^{+}#mu^{-} invariant mass (muon cuts)", {HistType::kTHnSparseF, {invMassAxis, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); registry.add("dimuon/realign/invariantMass_MuonKine_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} invariant mass (global muon cuts, good matches)", {HistType::kTHnSparseF, {invMassAxis, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); registry.add("dimuon/realign/invariantMass_ScaledMftKine_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} invariant mass (global muon cuts, rescaled MFT, good matches)", {HistType::kTHnSparseF, {invMassAxis, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); // difference in mu+mu- opening angle between MCH and global muon tracks (realigned/refitted tracks) - registry.add("dimuon/realign/angle_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} opening angle difference (global muon cuts, good matches)", {HistType::kTHnSparseF, {angleDiffAxis, angleAxis, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); + registry.add("dimuon/realign/angle_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} opening angle difference (global muon cuts, good matches)", {HistType::kTHnSparseF, {angleDiffAxis, invMassAxisCoarse, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); // mu+mu- DCA registry.add("dimuon/realign/dcax_MuonKine_MuonCuts", "#mu^{+}#mu^{-} DCA_{x} (muon cuts)", {HistType::kTHnSparseF, {dcaxAxis, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); registry.add("dimuon/realign/dcay_MuonKine_MuonCuts", "#mu^{+}#mu^{-} DCA_{y} (muon cuts)", {HistType::kTHnSparseF, {dcayAxis, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); @@ -631,6 +857,12 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc registry.add("dimuon/realign/dcay_MuonKine_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} DCA_{y} (global muon cuts, good matches)", {HistType::kTHnSparseF, {dcayAxis, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); registry.add("dimuon/realign/dcax_ScaledMftKine_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} DCA_{x} (global muon cuts, rescaled MFT, good matches)", {HistType::kTHnSparseF, {dcaMftxAxis, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); registry.add("dimuon/realign/dcay_ScaledMftKine_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} DCA_{y} (global muon cuts, rescaled MFT, good matches)", {HistType::kTHnSparseF, {dcaMftyAxis, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); + // mu+mu- decay length z + registry.add("dimuon/realign/Lz_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} L_{z} (global muon cuts, good matches)", {HistType::kTHnSparseF, {lzAxis, invMassAxisCoarse, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); + registry.add("dimuon/realign/tauz_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} L_{z} (global muon cuts, good matches)", {HistType::kTHnSparseF, {tauzAxis, invMassAxisCoarse, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); + // mu+mu- decay length xy + registry.add("dimuon/realign/Lxy_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} L_{xy} (global muon cuts, good matches)", {HistType::kTHnSparseF, {lxyAxis, invMassAxisCoarse, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); + registry.add("dimuon/realign/tauxy_GlobalMuonCuts_GoodMatches", "#mu^{+}#mu^{-} L_{xy} (global muon cuts, good matches)", {HistType::kTHnSparseF, {tauxyAxis, invMassAxisCoarse, pAxis, pTAxis, muPosQuadrantAxis, muNegQuadrantAxis}}); } } @@ -1034,37 +1266,39 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc std::array rAbsCut, double nSigmaPdcaCut) { - auto const& mchTrack = (static_cast(muonTrack.trackType()) <= GlobalTrackTypeMax) ? muonTrack.template matchMCHTrack_as() : muonTrack; + if (static_cast(muonTrack.trackType()) <= GlobalTrackTypeMax) { + LOGF(warning, "IsGoodMuon() called with global forward track"); + } // chi2 cut - if (mchTrack.chi2() > chi2Cut) { + if (muonTrack.chi2() > chi2Cut) { return false; } // momentum cut - if (mchTrack.p() < pCut) { + if (muonTrack.p() < pCut) { return false; // skip low-momentum tracks } // transverse momentum cut - if (mchTrack.pt() < pTCut) { + if (muonTrack.pt() < pTCut) { return false; // skip low-momentum tracks } // Eta cut - double eta = mchTrack.eta(); + double eta = muonTrack.eta(); if ((eta < etaCut[0] || eta > etaCut[1])) { return false; } // RAbs cut - double rAbs = mchTrack.rAtAbsorberEnd(); + double rAbs = muonTrack.rAtAbsorberEnd(); if ((rAbs < rAbsCut[0] || rAbs > rAbsCut[1])) { return false; } // pDCA cut - if (!pDCACut(mchTrack, collision, nSigmaPdcaCut)) { + if (!pDCACut(muonTrack, collision, nSigmaPdcaCut)) { return false; } @@ -1096,8 +1330,55 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; SMatrix55 tcovs(v1.begin(), v1.end()); - o2::track::TrackParCovFwd trackparCov{track.z(), tpars, tcovs, chi2}; - return trackparCov; + return {track.z(), tpars, tcovs, chi2}; + } + + template + o2::track::TrackParCovFwd TrackToParCovFwd(const T& track, const C& cov) + { + double chi2 = track.chi2(); + SMatrix5 tpars(track.x(), track.y(), track.phi(), track.tgl(), track.signed1Pt()); + std::vector v1{cov.cXX(), cov.cXY(), cov.cYY(), cov.cPhiX(), cov.cPhiY(), + cov.cPhiPhi(), cov.cTglX(), cov.cTglY(), cov.cTglPhi(), cov.cTglTgl(), + cov.c1PtX(), cov.c1PtY(), cov.c1PtPhi(), cov.c1PtTgl(), cov.c1Pt21Pt2()}; + SMatrix55 tcovs(v1.begin(), v1.end()); + return {track.z(), tpars, tcovs, chi2}; + } + + o2::track::TrackParCovFwd MatchedTrackToParCovFwd(const o2::track::TrackParCovFwd& mchTrackPar, + const o2::track::TrackParCovFwd& mftTrackPar) + { + // extrapolation of MCH track to first MFT track point + auto mchTrackAtMFT = FwdtoMCH(mchTrackPar); + o2::mch::TrackExtrap::extrapToVertex(mchTrackAtMFT, + mftTrackPar.getX(), + mftTrackPar.getY(), + mftTrackPar.getZ(), + std::sqrt(mftTrackPar.getSigma2X()), + std::sqrt(mftTrackPar.getSigma2Y())); + + auto fwdTrackRefit = fwdtrackutils::refitGlobalMuonCov(MCHtoFwd(mchTrackAtMFT), mftTrackPar); + + return {fwdTrackRefit.getZ(), fwdTrackRefit.getParameters(), fwdTrackRefit.getCovariances(), fwdTrackRefit.getTrackChi2()}; + } + + template + o2::track::TrackParCovFwd MatchedTrackToParCovFwd(const T& mchTrack, const T& mftTrack, const C& mftCov) + { + auto mftTrackPar = TrackToParCovFwd(mftTrack, mftCov); + + // extrapolation of MCH track to first MFT track point + auto mchTrackAtMFT = FwdtoMCH(TrackToParCovFwd(mchTrack, mchTrack)); + o2::mch::TrackExtrap::extrapToVertex(mchTrackAtMFT, + mftTrackPar.getX(), + mftTrackPar.getY(), + mftTrackPar.getZ(), + std::sqrt(mftTrackPar.getSigma2X()), + std::sqrt(mftTrackPar.getSigma2Y())); + + auto fwdTrackRefit = fwdtrackutils::refitGlobalMuonCov(MCHtoFwd(mchTrackAtMFT), mftTrackPar); + + return {fwdTrackRefit.getZ(), fwdTrackRefit.getParameters(), fwdTrackRefit.getCovariances(), fwdTrackRefit.getTrackChi2()}; } template @@ -1117,6 +1398,23 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc return fwdtrack; } + template + o2::dataformats::GlobalFwdTrack TrackToGlobalFwd(const T& track, const C& cov) + { + double chi2 = track.chi2(); + SMatrix5 tpars(track.x(), track.y(), track.phi(), track.tgl(), track.signed1Pt()); + std::vector v1{cov.cXX(), cov.cXY(), cov.cYY(), cov.cPhiX(), cov.cPhiY(), + cov.cPhiPhi(), cov.cTglX(), cov.cTglY(), cov.cTglPhi(), cov.cTglTgl(), + cov.c1PtX(), cov.c1PtY(), cov.c1PtPhi(), cov.c1PtTgl(), cov.c1Pt21Pt2()}; + SMatrix55 tcovs(v1.begin(), v1.end()); + o2::track::TrackParCovFwd trackparCov{track.z(), tpars, tcovs, chi2}; + o2::dataformats::GlobalFwdTrack fwdtrack; + fwdtrack.setParameters(trackparCov.getParameters()); + fwdtrack.setZ(trackparCov.getZ()); + fwdtrack.setCovariances(trackparCov.getCovariances()); + return fwdtrack; + } + void TransformMFTPar(o2::mch::TrackParam& track) { // double zCH10 = -1437.6; @@ -1465,11 +1763,17 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc std::sqrt(mftTrackPar.getSigma2X()), std::sqrt(mftTrackPar.getSigma2Y())); - auto fwdTrackProp = fwdtrackutils::refitGlobalMuonCov(MCHtoFwd(mchTrackAtMFT), mftTrackPar); + auto fwdTrackRefit = fwdtrackutils::refitGlobalMuonCov(MCHtoFwd(mchTrackAtMFT), mftTrackPar); + + // apply vertex shift correction + fwdTrackRefit.setZ(fwdTrackRefit.getZ() + cfgVertexZshift.value); - auto geoMan = o2::base::GeometryManager::meanMaterialBudget(fwdTrackProp.getX(), fwdTrackProp.getY(), fwdTrackProp.getZ(), collision.posX(), collision.posY(), collision.posZ()); - auto x2x0 = static_cast(geoMan.meanX2X0); - fwdTrackProp.propagateToVtxhelixWithMCS(collision.posZ(), {collision.posX(), collision.posY()}, {collision.covXX(), collision.covYY()}, mBzAtMftCenter, x2x0); + auto fwdTrackProp = fwdtrackutils::propagateTrackParCovFwd(fwdTrackRefit, + 0, + collision, + fwdtrackutils::propagationPoint::kToVertex, + cfgRefPlaneZMFT, + mBzAtMftCenter); return fwdTrackProp; } @@ -1528,8 +1832,31 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc return getMuMu4Momentum(track1, track2).M(); } + template + std::optional> getMuMuDecayLength(const o2::track::TrackParCovFwd& track1, + const o2::track::TrackParCovFwd& track2, + const C& collision) + { + auto progCode = fgFitterTwoProngFwd.process(track1, track2); + + if (progCode == 0) { + return {}; + } + + // Get pca candidate from forward DCA fitter + auto secondaryVertex = fgFitterTwoProngFwd.getPCACandidate(); + + double Lxy = (collision.posX() - secondaryVertex[0]) * (collision.posX() - secondaryVertex[0]) + + (collision.posY() - secondaryVertex[1]) * (collision.posY() - secondaryVertex[1]); + Lxy = std::sqrt(Lxy); + + double Lz = collision.posZ() - secondaryVertex[2]; + + return {{Lxy, Lz}}; + } + template - bool MchRealignTrack(const TMUON& mchTrack, const TCLUS& clusters, TrackRealigned& convertedTrack, bool applyCorrections) + bool MchRefitTrack(const TMUON& mchTrack, const TCLUS& clusters, TrackRealigned& convertedTrack, bool applyCorrections) { auto mchTrackPar = FwdtoMCH(TrackToGlobalFwd(mchTrack)); @@ -1603,12 +1930,13 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc return !removable; } - template + template void InitCollisions(COLL const& collisions, BC const& bcs, TMUON const& muonTracks, - aod::FwdTrkCls const& clusters, - std::map& collisionInfos) + TCLS const& clusters, + TMFT const& mftTracks, + std::unordered_map& collisionInfos) { mMchTrackPars.clear(); mMchTrackParsNew.clear(); @@ -1620,6 +1948,13 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc } auto collision = collisions.rawIteratorAt(muonTrack.collisionId()); + const auto& bc = bcs.rawIteratorAt(collision.bcId()); + + // remove TF/ROF borders and ambiguous collisions + if (!bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || + !bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + continue; + } if (cfgRequireGoodRCT && !rctChecker(collision)) { continue; @@ -1627,10 +1962,9 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc uint64_t collisionIndex = collision.globalIndex(); - auto bc = bcs.rawIteratorAt(collision.bcId()); - auto& collisionInfo = collisionInfos[collisionIndex]; - collisionInfo.bc = bc.globalBC(); + collisionInfo.runNumber = bc.runNumber(); + collisionInfo.timestamp = bc.timestamp(); collisionInfo.zVertex = collision.posZ(); if (static_cast(muonTrack.trackType()) > GlobalTrackTypeMax) { @@ -1644,7 +1978,7 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc // refit MCH track if requested if (configRealign.cfgEnableMCHRefit || configRealign.cfgEnableMCHRealign) { TrackRealigned convertedTrack; - bool convertedTrackOk = MchRealignTrack(muonTrack, clusters, convertedTrack, !mMchAlignmentCorrections.empty()); + bool convertedTrackOk = MchRefitTrack(muonTrack, clusters, convertedTrack, !mMchAlignmentCorrections.empty()); // Get the re-aligned track parameters: track param at the first cluster mch::TrackParam trackParam = mch::TrackParam(convertedTrack.first()); @@ -1693,16 +2027,141 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc std::sort(globalTracksVector.begin(), globalTracksVector.end(), compareChi2); } } + + mMftTrackPars.clear(); + mMftTrackParsNew.clear(); + + // fill collision information for MFT standalone tracks + for (const auto& mftTrack : mftTracks) { + if (!mftTrack.has_collision()) { + continue; + } + + auto collision = collisions.rawIteratorAt(mftTrack.collisionId()); + uint64_t collisionIndex = collision.globalIndex(); + + auto bc = bcs.rawIteratorAt(collision.bcId()); + + // remove TF/ROF borders and ambiguous collisions + if (!bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || + !bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + continue; + } + + if (cfgRequireGoodRCT && !rctChecker(collision)) { + continue; + } + + uint64_t mftTrackIndex = mftTrack.globalIndex(); + + auto& collisionInfo = collisionInfos[collisionIndex]; + collisionInfo.runNumber = bc.runNumber(); + collisionInfo.timestamp = bc.timestamp(); + collisionInfo.zVertex = collision.posZ(); + + collisionInfo.mftTracks.push_back(mftTrackIndex); + + // initialize the original MFT track parameters + auto mftTrackFwd = TrackToParCovFwd(mftTrack); + mMftTrackPars.try_emplace(mftTrackIndex, TrackParExt(mftTrackFwd, mftTrack.nClusters())); + + // initialize the corrected MFT track parameters, if requested + if (configMFTAlignmentCorrections.cfgEnableMFTAlignmentCorrections) { + TransformMFT(mftTrackFwd); + mMftTrackParsNew.try_emplace(mftTrackIndex, TrackParExt(mftTrackFwd, mftTrack.nClusters())); + } else { + // initialize the new MFT track parameters with the original ones, without corrections + mMftTrackParsNew.try_emplace(mftTrackIndex, TrackParExt(mftTrackFwd, mftTrack.nClusters())); + } + } } - void InitCollisions(MyEvents const& collisions, - MyBCs const& bcs, - MyMuonsWithCov const& muonTracks, - aod::FwdTrkCls const& clusters, - MyMFTs const& mftTracks, - std::map& collisionInfos) + template + void InitCollisionsDerivedTables(COLL const& collisions, + TMUON const& muonTracks, + TCLS const& clusters, + TMFT const& mftTracks, + std::unordered_map& collisionInfos) { - InitCollisions(collisions, bcs, muonTracks, clusters, collisionInfos); + // InitCollisions(collisions, bcs, muonTracks, clusters, collisionInfos); + + mMchTrackPars.clear(); + mMchTrackParsNew.clear(); + + // fill collision information for global muon tracks (MFT-MCH-MID matches) + for (const auto& muonTrack : muonTracks) { + if (!muonTrack.has_collision()) { + continue; + } + + auto collision = collisions.rawIteratorAt(muonTrack.collisionId()); + uint64_t collisionIndex = collision.globalIndex(); + + auto& collisionInfo = collisionInfos[collisionIndex]; + collisionInfo.runNumber = collision.runNumber(); + collisionInfo.timestamp = collision.timestamp(); + collisionInfo.zVertex = collision.posZ(); + + if (static_cast(muonTrack.trackType()) > GlobalTrackTypeMax) { + // standalone MCH or MCH-MID tracks + uint64_t mchTrackIndex = muonTrack.globalIndex(); + collisionInfo.mchTracks.push_back(mchTrackIndex); + + // initialize the original MCH track parameters + mMchTrackPars.try_emplace(mchTrackIndex, TrackParExt(fwdtrackutils::getTrackParCovFwd(muonTrack, muonTrack), muonTrack.nClusters())); + + // refit MCH track if requested + if (configRealign.cfgEnableMCHRefit || configRealign.cfgEnableMCHRealign) { + TrackRealigned convertedTrack; + bool convertedTrackOk = MchRefitTrack(muonTrack, clusters, convertedTrack, !mMchAlignmentCorrections.empty()); + + // Get the re-aligned track parameters: track param at the first cluster + mch::TrackParam trackParam = mch::TrackParam(convertedTrack.first()); + + auto mchTrackParIt = mMchTrackParsNew.try_emplace(mchTrackIndex, TrackParExt(MCHtoFwd(trackParam), convertedTrack.getNClusters())); + if (mchTrackParIt.second) { + // the insertion succeeded + mchTrackParIt.first->second.setTrackChi2(trackParam.getTrackChi2() / convertedTrack.getNDF()); + if (!convertedTrackOk) { + mchTrackParIt.first->second.setRemovable(); + } + } + } else { + // initialize the new MCH track parameters with the original ones, without refitting + mMchTrackParsNew.try_emplace(mchTrackIndex, TrackParExt(fwdtrackutils::getTrackParCovFwd(muonTrack, muonTrack), muonTrack.nClusters())); + } + } else { + // global muon tracks (MFT-MCH or MFT-MCH-MID) + uint64_t muonTrackIndex = muonTrack.globalIndex(); + auto const& mchTrack = muonTrack.template matchMCHTrack_as(); + uint64_t mchTrackIndex = mchTrack.globalIndex(); + + // check if a vector of global muon candidates is already available for the current MCH index + // if not, initialize a new one and add the current global muon track + // bool globalMuonTrackFound = false; + auto matchingCandidateIterator = collisionInfo.globalMuonTracks.find(mchTrackIndex); + if (matchingCandidateIterator != collisionInfo.globalMuonTracks.end()) { + matchingCandidateIterator->second.push_back(muonTrackIndex); + // globalMuonTrackFound = true; + } else { + collisionInfo.globalMuonTracks[mchTrackIndex].push_back(muonTrackIndex); + } + } + } + + // sort the vectors of matching candidates in ascending order based on the matching chi2 value + auto compareChi2 = [&muonTracks](uint64_t trackIndex1, uint64_t trackIndex2) -> bool { + auto const& track1 = muonTracks.rawIteratorAt(trackIndex1); + auto const& track2 = muonTracks.rawIteratorAt(trackIndex2); + + return (track1.chi2MatchMCHMFT() < track2.chi2MatchMCHMFT()); + }; + + for (auto& [collisionIndex, collisionInfo] : collisionInfos) { // o2-linter: disable=const-ref-in-for-loop (object is modified in loop) + for (auto& [mchIndex, globalTracksVector] : collisionInfo.globalMuonTracks) { // o2-linter: disable=const-ref-in-for-loop (object is modified in loop) + std::sort(globalTracksVector.begin(), globalTracksVector.end(), compareChi2); + } + } mMftTrackPars.clear(); mMftTrackParsNew.clear(); @@ -1716,12 +2175,11 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc auto collision = collisions.rawIteratorAt(mftTrack.collisionId()); uint64_t collisionIndex = collision.globalIndex(); - auto bc = bcs.rawIteratorAt(collision.bcId()); - uint64_t mftTrackIndex = mftTrack.globalIndex(); auto& collisionInfo = collisionInfos[collisionIndex]; - collisionInfo.bc = bc.globalBC(); + collisionInfo.runNumber = collision.runNumber(); + collisionInfo.timestamp = collision.timestamp(); collisionInfo.zVertex = collision.posZ(); collisionInfo.mftTracks.push_back(mftTrackIndex); @@ -1741,23 +2199,113 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc } } - void FillMftPlots(MyEvents const& collisions, - MyBCs const& bcs, - MyMuonsWithCov const& muonTracks, - MyMFTs const& mftTracks, - const std::map& collisionInfos) +#if (PROCESS_DERIVED_TABLES == 0) + template + void StoreCollisions(const std::unordered_map& collisionInfos, + COLL const& collisions, + TMUON const& muonTracks, + TCLS const& clusters, + TMFT const& /*mftTracks*/) { - // outer loop over collisions + int32_t collId = 0; + int32_t fwdTrkId = 0; + int32_t mftTrkId = 0; + + std::unordered_map mchTrackIdRemapping; for (const auto& [collisionIndex, collisionInfo] : collisionInfos) { - auto const& collision = collisions.rawIteratorAt(collisionIndex); - const auto& bc = bcs.rawIteratorAt(collision.bcId()); + auto const& c = collisions.rawIteratorAt(collisionIndex); - // remove TF/ROF borders and ambiguous collisions - if (!bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || - !bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + if (collisionInfo.mchTracks.empty()) { continue; } + collTable(collisionInfo.runNumber, collisionInfo.timestamp, + c.posX(), c.posY(), c.posZ(), + c.covXX(), c.covYY(), c.covZZ()); + + // loop over MCH tracks + for (const auto& mchIndex : collisionInfo.mchTracks) { + auto const& mchTrack = muonTracks.rawIteratorAt(mchIndex); + + // only store good MCH tracks + if (!IsGoodMuon(mchTrack, c, cfgTrackChi2MchUp, 0.f, cfgPtMchLow, {cfgEtaMftLow, cfgEtaMftUp}, {cfgRabsLow, cfgRabsUp}, fSigmaPdcaUp)) { + continue; + } + + fwdTable(collId, + mchTrack.trackType(), + mchTrack.x(), mchTrack.y(), mchTrack.z(), + mchTrack.phi(), mchTrack.tgl(), mchTrack.signed1Pt(), + mchTrack.nClusters(), mchTrack.pDca(), mchTrack.rAtAbsorberEnd(), + mchTrack.chi2(), mchTrack.chi2MatchMCHMFT(), + mchTrack.matchMFTTrackId(), mchTrack.matchMCHTrackId()); + + if (cfgProduceMuonAlignmentTablesWithCovariances.value) { + fwdCovTable(mchTrack.sigmaX(), mchTrack.sigmaY(), mchTrack.sigmaPhi(), mchTrack.sigmaTgl(), mchTrack.sigma1Pt(), + mchTrack.rhoXY(), mchTrack.rhoPhiY(), mchTrack.rhoPhiX(), mchTrack.rhoTglX(), mchTrack.rhoTglY(), + mchTrack.rhoTglPhi(), mchTrack.rho1PtX(), mchTrack.rho1PtY(), mchTrack.rho1PtPhi(), mchTrack.rho1PtTgl()); + } + + // loop over attached clusters + auto clustersSliced = clusters.sliceBy(perMuon, mchTrack.globalIndex()); // Slice clusters by muon id + for (auto const& cluster : clustersSliced) { + clusTable(fwdTrkId, cluster.x(), cluster.y(), cluster.z(), cluster.clInfo()); + } + + mchTrackIdRemapping[mchTrack.globalIndex()] = fwdTrkId; + fwdTrkId += 1; + } + + // loop over global muon tracks + for (const auto& [muonIndex, globalTracksVector] : collisionInfo.globalMuonTracks) { + auto const& muonTrack = muonTracks.rawIteratorAt(globalTracksVector[0]); + const auto& mchTrack = muonTrack.template matchMCHTrack_as(); + const auto& mftTrack = muonTrack.template matchMFTTrack_as(); + + try { + auto remappedMchId = mchTrackIdRemapping.at(mchTrack.globalIndex()); + + mftTable(collId, + mftTrack.x(), mftTrack.y(), mftTrack.z(), + mftTrack.phi(), mftTrack.tgl(), mftTrack.signed1Pt(), + mftTrack.mftClusterSizesAndTrackFlags(), mftTrack.chi2()); + + fwdTable(collId, + muonTrack.trackType(), + muonTrack.x(), muonTrack.y(), muonTrack.z(), + muonTrack.phi(), muonTrack.tgl(), muonTrack.signed1Pt(), + muonTrack.nClusters(), muonTrack.pDca(), muonTrack.rAtAbsorberEnd(), + muonTrack.chi2(), muonTrack.chi2MatchMCHMFT(), + mftTrkId, remappedMchId); + + if (cfgProduceMuonAlignmentTablesWithCovariances.value) { + fwdCovTable(muonTrack.sigmaX(), muonTrack.sigmaY(), muonTrack.sigmaPhi(), muonTrack.sigmaTgl(), muonTrack.sigma1Pt(), + muonTrack.rhoXY(), muonTrack.rhoPhiY(), muonTrack.rhoPhiX(), muonTrack.rhoTglX(), muonTrack.rhoTglY(), + muonTrack.rhoTglPhi(), muonTrack.rho1PtX(), muonTrack.rho1PtY(), muonTrack.rho1PtPhi(), muonTrack.rho1PtTgl()); + } + + fwdTrkId += 1; + mftTrkId += 1; + } catch (const std::exception& e) { + continue; + } + } + + collId += 1; + } + } +#endif + + template + void FillMftPlots(C const& collisions, + TMUON const& muonTracks, + TMFT const& mftTracks, + const std::unordered_map& collisionInfos) + { + // outer loop over collisions + for (const auto& [collisionIndex, collisionInfo] : collisionInfos) { + auto const& collision = collisions.rawIteratorAt(collisionIndex); + registry.get(HIST("vertex_y_vs_x"))->Fill(collision.posX(), collision.posY()); registry.get(HIST("vertex_z"))->Fill(collision.posZ()); @@ -1825,13 +2373,20 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc registry.get(HIST("DCA/MFT/DCA_x"))->Fill(dcax, collision.posZ(), mftTrack.x(), mftTrack.y(), mftNclusters); registry.get(HIST("DCA/MFT/DCA_y"))->Fill(dcay, collision.posZ(), mftTrack.x(), mftTrack.y(), mftNclusters); + if (!configHistograms.cfgHistMftDcaEnableDetailedVzAnalysis) { + registry.get(HIST("DCA/MFT/DCAxVsVz"))->Fill(dcax, collision.posZ(), mftTrack.x(), mftTrack.y(), mftNclusters); + registry.get(HIST("DCA/MFT/DCAyVsVz"))->Fill(dcay, collision.posZ(), mftTrack.x(), mftTrack.y(), mftNclusters); + } + +#if (PROCESS_DERIVED_TABLES == 0) if (cfgProduceMFTTable) { - mftTable(collision.posX(), collision.posY(), collision.posZ(), - mftTrack.signed1Pt(), mftTrack.tgl(), mftTrack.phi(), - dcax, dcay, mftTrackAtDCA.getSigma2X(), mftTrackAtDCA.getSigma2Y(), mftTrackAtDCA.getSigmaXY(), - mftNclusters, mftTrack.chi2(), - mftTrack.x(), mftTrack.y(), mftTrack.z()); + compactMftTable(collision.posX(), collision.posY(), collision.posZ(), + mftTrack.signed1Pt(), mftTrack.tgl(), mftTrack.phi(), + dcax, dcay, mftTrackAtDCA.getSigma2X(), mftTrackAtDCA.getSigma2Y(), mftTrackAtDCA.getSigmaXY(), + mftNclusters, mftTrack.chi2(), + mftTrack.x(), mftTrack.y(), mftTrack.z()); } +#endif if (cfgEnableMftDcaExtraPlots) { static constexpr int nMftClustersMin = 6; @@ -1885,8 +2440,8 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc // loop over global muon tracks for (const auto& [muonIndex, globalTracksVector] : collisionInfo.globalMuonTracks) { auto const& muonTrack = muonTracks.rawIteratorAt(globalTracksVector[0]); - const auto& mchTrack = muonTrack.template matchMCHTrack_as(); - const auto& mftTrack = muonTrack.template matchMFTTrack_as(); + const auto& mchTrack = muonTrack.template matchMCHTrack_as(); + const auto& mftTrack = muonTrack.template matchMFTTrack_as(); auto mchIndex = mchTrack.globalIndex(); auto mftIndex = mftTrack.globalIndex(); @@ -1947,11 +2502,12 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc } } - void FillMchPlots(MyEvents const& collisions, - MyBCs const& bcs, - MyMuonsWithCov const& muonTracks, - aod::FwdTrkCls const& clusters, - const std::map& collisionInfos) + template + void FillMchPlots(C const& collisions, + TMUON const& muonTracks, + TCLS const& clusters, + TMFT const& /*mftTracks*/, + const std::unordered_map& collisionInfos) { if (!cfgEnableMftMchResidualsAnalysis && !cfgEnableMftMchMatchingAnalysis) { return; @@ -1960,19 +2516,12 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc // loop over collisions for (const auto& [collisionIndex, collisionInfo] : collisionInfos) { auto const& collision = collisions.rawIteratorAt(collisionIndex); - const auto& bc = bcs.rawIteratorAt(collision.bcId()); - - // remove TF/ROF borders and ambiguous collisions - if (!bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || - !bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { - continue; - } // loop over global muon tracks for (const auto& [muonIndex, globalTracksVector] : collisionInfo.globalMuonTracks) { auto const& muonTrack = muonTracks.rawIteratorAt(globalTracksVector[0]); - const auto& mchTrack = muonTrack.template matchMCHTrack_as(); - const auto& mftTrack = muonTrack.template matchMFTTrack_as(); + const auto& mchTrack = muonTrack.template matchMCHTrack_as(); + const auto& mftTrack = muonTrack.template matchMFTTrack_as(); // int quadrant = GetQuadrant(mchTrack); int quadrant = GetQuadrant(mftTrack); int posNeg = (mchTrack.sign() >= 0) ? 0 : 1; @@ -2205,15 +2754,50 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc double p = mumu4mom.P(); double pT = mumu4mom.Pt(); double dAngle = mchAngle - fwdAngle; + double invMass = mumu4mom.M(); int quadrant1 = GetQuadrant(static_cast(std::atan2(trackPar1.getY(), trackPar1.getX()))); int quadrant2 = GetQuadrant(static_cast(std::atan2(trackPar2.getY(), trackPar2.getX()))); - registry.get(histConfig)->Fill(dAngle, fwdAngle, p, pT, quadrant1, quadrant2); + registry.get(histConfig)->Fill(dAngle, invMass, p, pT, quadrant1, quadrant2); } - void FillDimuonPlots(MyEvents const& collisions, - MyMuonsWithCov const& muonTracks, - const std::map& collisionInfos) + template + inline void fillDimuonDecayLengthPlots(const T1& trackPar1, + const T2& trackPar2, + const T3& trackPar1AtVertex, + const T4& trackPar2AtVertex, + const C& collision, + HistConfigType1 histConfigLxy, + HistConfigType2 histConfigLz, + HistConfigType3 histConfigTauxy, + HistConfigType4 histConfigTauz) + { + auto decayLength = getMuMuDecayLength(trackPar1, trackPar2, collision); + if (!decayLength) { + return; + } + + auto v12 = getMuMu4Momentum(trackPar1AtVertex, trackPar2AtVertex); + double p = v12.P(); + double pT = v12.Pt(); + double invMass = v12.M(); + int quadrant1 = GetQuadrant(static_cast(std::atan2(trackPar1.getY(), trackPar1.getX()))); + int quadrant2 = GetQuadrant(static_cast(std::atan2(trackPar2.getY(), trackPar2.getX()))); + + registry.get(histConfigLxy)->Fill(decayLength->first, invMass, p, pT, quadrant1, quadrant2); + registry.get(histConfigLz)->Fill(decayLength->second, invMass, p, pT, quadrant1, quadrant2); + + double tauxy = 299792458.e-7 * 10. * decayLength->first * v12.M() / (v12.Pt() * o2::constants::physics::LightSpeedCm2NS); + double tauz = 299792458.e-7 * 10. * decayLength->second * invMass / (TMath::Abs(v12.Pz()) * o2::constants::physics::LightSpeedCm2NS); + + registry.get(histConfigTauxy)->Fill(tauxy, invMass, p, pT, quadrant1, quadrant2); + registry.get(histConfigTauz)->Fill(tauz, invMass, p, pT, quadrant1, quadrant2); + } + + template + void FillDimuonPlots(C const& collisions, + TMUON const& muonTracks, + const std::unordered_map& collisionInfos) { if (!cfgEnableDimuonAnalysis) { return; @@ -2359,6 +2943,25 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc fillDimuonAnglePlot(mchTrackPar1, mchTrackPar2, fwdTrackPar1AtVertex, fwdTrackPar2AtVertex, mchAngle, fwdAngle, HIST("dimuon/angle_GlobalMuonCuts_GoodMatches")); fillDimuonAnglePlot(mchTrackParNew1, mchTrackParNew2, fwdTrackParNew1AtVertex, fwdTrackParNew2AtVertex, mchAngleNew, fwdAngleNew, HIST("dimuon/realign/angle_GlobalMuonCuts_GoodMatches")); + + fillDimuonDecayLengthPlots(MatchedTrackToParCovFwd(mchTrackPar1, mftTrackPar1), + MatchedTrackToParCovFwd(mchTrackPar2, mftTrackPar2), + fwdTrackPar1AtVertex, + fwdTrackPar2AtVertex, + collision, + HIST("dimuon/Lxy_GlobalMuonCuts_GoodMatches"), + HIST("dimuon/Lz_GlobalMuonCuts_GoodMatches"), + HIST("dimuon/tauxy_GlobalMuonCuts_GoodMatches"), + HIST("dimuon/tauz_GlobalMuonCuts_GoodMatches")); + fillDimuonDecayLengthPlots(MatchedTrackToParCovFwd(mchTrackParNew1, mftTrackParNew1), + MatchedTrackToParCovFwd(mchTrackParNew2, mftTrackParNew2), + fwdTrackParNew1AtVertex, + fwdTrackParNew2AtVertex, + collision, + HIST("dimuon/realign/Lxy_GlobalMuonCuts_GoodMatches"), + HIST("dimuon/realign/Lz_GlobalMuonCuts_GoodMatches"), + HIST("dimuon/realign/tauxy_GlobalMuonCuts_GoodMatches"), + HIST("dimuon/realign/tauz_GlobalMuonCuts_GoodMatches")); } catch (const std::exception&) { continue; } @@ -2366,11 +2969,11 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc } } +#if (PROCESS_DERIVED_TABLES == 0) void processQA(MyEvents const& collisions, MyBCs const& bcs, MyMuonsWithCov const& muonTracks, MyMFTs const& mftTracks, - // MyMFTCovariances const& mftCovariances, aod::FwdTrkCls const& clusters) { auto bc = bcs.begin(); @@ -2381,21 +2984,95 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc mRunNumber = bc.runNumber(); } - std::map collisionInfos; + std::unordered_map collisionInfos; InitCollisions(collisions, bcs, muonTracks, clusters, mftTracks, collisionInfos); - FillMftPlots(collisions, bcs, muonTracks, mftTracks, collisionInfos); + if (cfgProduceMuonAlignmentTables) { + StoreCollisions(collisionInfos, collisions, muonTracks, clusters, mftTracks); + } + + FillMftPlots(collisions, muonTracks, mftTracks, collisionInfos); - FillMchPlots(collisions, bcs, muonTracks, clusters, collisionInfos); + FillMchPlots(collisions, muonTracks, clusters, mftTracks, collisionInfos); FillDimuonPlots(collisions, muonTracks, collisionInfos); } - PROCESS_SWITCH(muonGlobalAlignment, processQA, "processQA", true); + PROCESS_SWITCH(MuonGlobalAlignment, processQA, "processQA", true); + +#else + + void processDerivedTables(o2::aod::MACollisions const& collisions, + soa::Join const& muonTracks, + o2::aod::MAFwdTrkCls const& clusters, + o2::aod::MAMFTTracks const& mftTracks) + { + if (collisions.size() < 1) { + return; + } + const auto& c = collisions.begin(); + if (mRunNumber != c.runNumber()) { + initCCDB(c); + LOGF(info, "Set field for muons"); + VarManager::SetupMuonMagField(); + mRunNumber = c.runNumber(); + } + + std::unordered_map collisionInfos; + InitCollisionsDerivedTables(collisions, muonTracks, clusters, mftTracks, collisionInfos); + + FillMftPlots(collisions, muonTracks, mftTracks, collisionInfos); + + FillMchPlots(collisions, muonTracks, clusters, mftTracks, collisionInfos); + + FillDimuonPlots(collisions, muonTracks, collisionInfos); + } + + PROCESS_SWITCH(MuonGlobalAlignment, processDerivedTables, "processDerivedTables", true); +#endif }; +#if (PROCESS_DERIVED_TABLES == 1) +// Extends the derived tables with expression columns +struct MuonGlobalAlignmentSpawner { + Spawns realignFwdTrks; + Spawns realignFwdTrksCov; + Spawns realignMftTrks; + void init(InitContext const&) {} + + /*auto process(o2::aod::StoredMAFwdTracks const& storedFwd, + o2::aod::StoredMAFwdTracksCov const& storedFwdCov, + o2::aod::StoredMAMFTTracks const& storedMft) + { + // Evaluate the dynamic kinematic expressions on the fly + auto fwdExtended = o2::soa::Extend(storedFwd); + + auto fwdExtended = o2::soa::Extend(storedFwd); + + auto mftExtended = o2::soa::Extend(storedMft); + + return std::make_tuple(fwdExtended, mftExtended); + }*/ +}; +#endif + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { +#if (PROCESS_DERIVED_TABLES == 0) + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +#else return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; +#endif }; diff --git a/PWGDQ/Tasks/qaMatching.cxx b/PWGDQ/Tasks/qaMatching.cxx index 4036e4c1af0..768cacc25da 100644 --- a/PWGDQ/Tasks/qaMatching.cxx +++ b/PWGDQ/Tasks/qaMatching.cxx @@ -1661,31 +1661,18 @@ struct QaMatching { std::sqrt(collision.covYY())); } - o2::dataformats::GlobalFwdTrack propagateToVertexMft(o2::dataformats::GlobalFwdTrack muon, - const float vx, const float vy, const float vz, - const float covVx, const float covVy) - { - o2::dataformats::GlobalFwdTrack propmuon; - auto geoMan = o2::base::GeometryManager::meanMaterialBudget(muon.getX(), muon.getY(), muon.getZ(), vx, vy, vz); - auto x2x0 = static_cast(geoMan.meanX2X0); - muon.propagateToVtxhelixWithMCS(vz, {vx, vy}, {covVx, covVy}, mBzAtMftCenter, x2x0); - propmuon.setParameters(muon.getParameters()); - propmuon.setZ(muon.getZ()); - propmuon.setCovariances(muon.getCovariances()); - - return propmuon; - } - template o2::dataformats::GlobalFwdTrack propagateToVertexMft(const TMFT& muon, const C& collision) { - return propagateToVertexMft(fwdToTrackPar(muon), - collision.posX(), - collision.posY(), - collision.posZ(), - std::sqrt(collision.covXX()), - std::sqrt(collision.covYY())); + auto fwdTrackProp = fwdtrackutils::propagateTrackParCovFwd(fwdToTrackPar(muon), + 0, + collision, + fwdtrackutils::propagationPoint::kToVertex, + 0, + mBzAtMftCenter); + + return fwdTrackProp; } template @@ -1701,11 +1688,14 @@ struct QaMatching { mftTrack.z(), 0, 0); - auto fwdTrackProp = fwdtrackutils::refitGlobalMuonCov(mExtrap.MCHtoFwd(mchTrackAtMFT), fwdToTrackPar(mftTrack)); + auto fwdTrackRefit = fwdtrackutils::refitGlobalMuonCov(mExtrap.MCHtoFwd(mchTrackAtMFT), fwdToTrackPar(mftTrack)); - auto geoMan = o2::base::GeometryManager::meanMaterialBudget(fwdTrackProp.getX(), fwdTrackProp.getY(), fwdTrackProp.getZ(), collision.posX(), collision.posY(), collision.posZ()); - auto x2x0 = static_cast(geoMan.meanX2X0); - fwdTrackProp.propagateToVtxhelixWithMCS(collision.posZ(), {collision.posX(), collision.posY()}, {collision.covXX(), collision.covYY()}, mBzAtMftCenter, x2x0); + auto fwdTrackProp = fwdtrackutils::propagateTrackParCovFwd(fwdTrackRefit, + 0, + collision, + fwdtrackutils::propagationPoint::kToVertex, + 0, + mBzAtMftCenter); return fwdTrackProp; } diff --git a/PWGDQ/Tasks/quarkoniaToHyperons.cxx b/PWGDQ/Tasks/quarkoniaToHyperons.cxx index 102936f70af..9c1fcb459f8 100644 --- a/PWGDQ/Tasks/quarkoniaToHyperons.cxx +++ b/PWGDQ/Tasks/quarkoniaToHyperons.cxx @@ -1203,7 +1203,7 @@ struct QuarkoniaToHyperons { } template - bool isEventAccepted(TCollision collision, bool fillHists) + bool isEventAccepted(const TCollision& collision, bool fillHists) // check whether the collision passes our collision selections { if (fillHists) @@ -1295,7 +1295,7 @@ struct QuarkoniaToHyperons { } template - void fillEventHistograms(TCollision collision, float& centrality, int& selGapSide) + void fillEventHistograms(const TCollision& collision, float& centrality, int& selGapSide) { if (isPP) { // centrality = collision.centFT0M(); @@ -1337,7 +1337,7 @@ struct QuarkoniaToHyperons { } template - uint64_t computeReconstructionBitmap(TV0 v0, TCollision collision, float rapidityLambda, float rapidityK0Short, float /*pT*/) + uint64_t computeReconstructionBitmap(const TV0& v0, const TCollision& collision, float rapidityLambda, float rapidityK0Short, float /*pT*/) // precalculate this information so that a check is one mask operation, not many { uint64_t bitMap = 0; @@ -1492,7 +1492,7 @@ struct QuarkoniaToHyperons { } template - bool isCascadeSelected(TCascade casc, TCollision collision, float rapidity, bool isXi) + bool isCascadeSelected(const TCascade& casc, const TCollision& collision, float rapidity, bool isXi) // precalculate this information so that a check is one mask operation, not many { // @@ -1728,7 +1728,7 @@ struct QuarkoniaToHyperons { } template - uint64_t computeMCAssociation(TV0 v0) + uint64_t computeMCAssociation(const TV0& v0) // precalculate this information so that a check is one mask operation, not many { uint64_t bitMap = 0; @@ -1758,7 +1758,7 @@ struct QuarkoniaToHyperons { } template - void analyseV0Candidate(TV0 v0, float pt, uint64_t selMap, std::vector& selK0ShortIndices, std::vector& selLambdaIndices, std::vector& selAntiLambdaIndices /*, int v0TableOffset*/) + void analyseV0Candidate(const TV0& v0, float pt, uint64_t selMap, std::vector& selK0ShortIndices, std::vector& selLambdaIndices, std::vector& selAntiLambdaIndices /*, int v0TableOffset*/) // precalculate this information so that a check is one mask operation, not many { bool passK0ShortSelections = false; @@ -1825,7 +1825,7 @@ struct QuarkoniaToHyperons { } template - void fillQAplot(TCollision collision, PairTopoInfo pair, THyperon hyperon, THyperon antiHyperon, float pt, float invmass, int type) + void fillQAplot(const TCollision& collision, PairTopoInfo pair, const THyperon& hyperon, const THyperon& antiHyperon, float pt, float invmass, int type) { // fill QA information about hyperon - antihyperon pair if (type == 0) { if constexpr (requires { hyperon.mK0Short(); antiHyperon.mK0Short(); }) { // check if v0 information is available @@ -2152,7 +2152,7 @@ struct QuarkoniaToHyperons { } template - void analyseHyperonPairCandidate(TCollision collision, THyperon hyperon, THyperon antiHyperon, float centrality, uint8_t gapSide, int type) + void analyseHyperonPairCandidate(const TCollision& collision, const THyperon& hyperon, const THyperon& antiHyperon, float centrality, uint8_t gapSide, int type) // fill information related to the quarkonium mother // type = 0 (Lambda), 1 (Xi), 2 (Omega) { @@ -2408,7 +2408,7 @@ struct QuarkoniaToHyperons { // function to check that the hyperon and antihyperon have different daughter tracks template - bool checkTrackIndices(THyperon hyperon, THyperon antiHyperon) + bool checkTrackIndices(const THyperon& hyperon, const THyperon& antiHyperon) { if constexpr (requires { hyperon.template bachTrackExtra_as(); }) { // cascade case: check if bachelor information is available // check that bachelor track from hyperon is different from daughter tracks of antiHyperon diff --git a/PWGDQ/Tasks/tableReader.cxx b/PWGDQ/Tasks/tableReader.cxx index f8e00266743..8501e0792e5 100644 --- a/PWGDQ/Tasks/tableReader.cxx +++ b/PWGDQ/Tasks/tableReader.cxx @@ -158,7 +158,7 @@ constexpr static int pairTypeMuMu = VarManager::kDecayToMuMu; constexpr static int pairTypeEMu = VarManager::kElectronMuon; // Global function used to define needed histogram classes -void DefineHistograms(HistogramManager* histMan, TString histClasses, Configurable configVar); // defines histograms for all tasks +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const Configurable& configVar); // defines histograms for all tasks struct AnalysisEventSelection { Produces eventSel; @@ -1984,13 +1984,13 @@ struct AnalysisDileptonHadron { std::vector trackGlobalIndexes; if (dileptons.size() > 0) { - for (auto track : tracks) { + for (const auto& track : tracks) { trackGlobalIndexes.push_back(track.globalIndex()); // std::cout << track.index() << " " << track.globalIndex() << std::endl; } } // loop once over dileptons for QA purposes - for (auto dilepton : dileptons) { + for (const auto& dilepton : dileptons) { VarManager::FillTrack(dilepton, fValuesDilepton); fHistMan->FillHistClass("DileptonsSelected", fValuesDilepton); @@ -2062,7 +2062,7 @@ struct AnalysisDileptonHadron { auto evTracks = tracks.sliceBy(perEventTracks, event2.globalIndex()); evTracks.bindExternalIndices(&events); - for (auto dilepton : evDileptons) { + for (const auto& dilepton : evDileptons) { for (auto& track : evTracks) { if (!(static_cast(track.isBarrelSelected()) & (static_cast(1) << fNHadronCutBit))) { @@ -2189,14 +2189,14 @@ struct AnalysisDileptonTrackTrack { std::vector trackGlobalIndexes; if (dileptons.size() > 0) { - for (auto track : tracks) { + for (const auto& track : tracks) { trackGlobalIndexes.push_back(track.globalIndex()); // std::cout << track.index() << " " << track.globalIndex() << std::endl; } } // loop over dileptons - for (auto dilepton : dileptons) { + for (const auto& dilepton : dileptons) { VarManager::FillTrack(dilepton, fValuesQuadruplet); // apply the dilepton cut @@ -2315,7 +2315,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc)}; } -void DefineHistograms(HistogramManager* histMan, TString histClasses, Configurable configVar) +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const Configurable& configVar) { // // Define here the histograms for all the classes required in analysis. diff --git a/PWGDQ/Tasks/tableReader_withAssoc.cxx b/PWGDQ/Tasks/tableReader_withAssoc.h similarity index 80% rename from PWGDQ/Tasks/tableReader_withAssoc.cxx rename to PWGDQ/Tasks/tableReader_withAssoc.h index d88307fcf06..541a8f039cb 100644 --- a/PWGDQ/Tasks/tableReader_withAssoc.cxx +++ b/PWGDQ/Tasks/tableReader_withAssoc.h @@ -9,12 +9,14 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. // -// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no -// Configurable workflow for running several DQ or other PWG analyses -// Included verbatim by the *_workflowSpec.cxx variants and precompiled into -// TableReaderWithAssocPCH; without the guard the two collide. -#pragma once +/// \file tableReader_withAssoc.h +/// \author iarsene@cern.ch, i.c.arsene@fys.uio.no +/// \brief Configurable workflow for running several DQ or other PWG analyses +/// \note Precompiled into TableReaderWithAssocPCH + +#ifndef PWGDQ_TASKS_TABLEREADER_WITHASSOC_H_ +#define PWGDQ_TASKS_TABLEREADER_WITHASSOC_H_ #include "PWGDQ/Core/AnalysisCompositeCut.h" #include "PWGDQ/Core/AnalysisCut.h" @@ -79,14 +81,6 @@ #include #include -using std::string; - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::aod; -using namespace o2::common::core; - // Some definitions namespace o2::aod { @@ -97,10 +91,10 @@ DECLARE_SOA_BITMAP_COLUMN(IsEventSelected, isEventSelected, 8); DECLARE_SOA_BITMAP_COLUMN(IsBarrelSelected, isBarrelSelected, 32); //! Barrel track decisions DECLARE_SOA_COLUMN(BarrelAmbiguityInBunch, barrelAmbiguityInBunch, int8_t); //! Barrel track in-bunch ambiguity DECLARE_SOA_COLUMN(BarrelAmbiguityOutOfBunch, barrelAmbiguityOutOfBunch, int8_t); //! Barrel track out of bunch ambiguity -DECLARE_SOA_BITMAP_COLUMN(IsMuonSelected, isMuonSelected, 32); //! Muon track decisions (joinable to ReducedMuonsAssoc) +DECLARE_SOA_BITMAP_COLUMN(IsMuonSelected, isMuonSelected, 32); //! Muon track decisions (joinable to o2::aod::ReducedMuonsAssoc) DECLARE_SOA_COLUMN(MuonAmbiguityInBunch, muonAmbiguityInBunch, int8_t); //! Muon track in-bunch ambiguity DECLARE_SOA_COLUMN(MuonAmbiguityOutOfBunch, muonAmbiguityOutOfBunch, int8_t); //! Muon track out of bunch ambiguity -DECLARE_SOA_BITMAP_COLUMN(IsBarrelSelectedPrefilter, isBarrelSelectedPrefilter, 32); //! Barrel prefilter decisions (joinable to ReducedTracksAssoc) +DECLARE_SOA_BITMAP_COLUMN(IsBarrelSelectedPrefilter, isBarrelSelectedPrefilter, 32); //! Barrel prefilter decisions (joinable to o2::aod::ReducedTracksAssoc) // Bcandidate columns for ML analysis of B->Jpsi+K DECLARE_SOA_COLUMN(RunNumber, runNumber, uint64_t); DECLARE_SOA_COLUMN(EventIdx, eventIdx, uint64_t); @@ -190,11 +184,11 @@ DECLARE_SOA_COLUMN(DeltaPhi, deltaPhi, float); DECLARE_SOA_TABLE(EventCuts, "AOD", "DQANAEVCUTSA", dqanalysisflags::IsEventSelected); //! joinable to ReducedEvents DECLARE_SOA_TABLE(MixingHashes, "AOD", "DQANAMIXHASHA", dqanalysisflags::MixingHash); //! joinable to ReducedEvents -DECLARE_SOA_TABLE(BarrelTrackCuts, "AOD", "DQANATRKCUTSA", dqanalysisflags::IsBarrelSelected); //! joinable to ReducedTracksAssoc +DECLARE_SOA_TABLE(BarrelTrackCuts, "AOD", "DQANATRKCUTSA", dqanalysisflags::IsBarrelSelected); //! joinable to o2::aod::ReducedTracksAssoc DECLARE_SOA_TABLE(BarrelAmbiguities, "AOD", "DQBARRELAMBA", dqanalysisflags::BarrelAmbiguityInBunch, dqanalysisflags::BarrelAmbiguityOutOfBunch); //! joinable to ReducedBarrelTracks -DECLARE_SOA_TABLE(MuonTrackCuts, "AOD", "DQANAMUONCUTSA", dqanalysisflags::IsMuonSelected); //! joinable to ReducedMuonsAssoc +DECLARE_SOA_TABLE(MuonTrackCuts, "AOD", "DQANAMUONCUTSA", dqanalysisflags::IsMuonSelected); //! joinable to o2::aod::ReducedMuonsAssoc DECLARE_SOA_TABLE(MuonAmbiguities, "AOD", "DQMUONAMBA", dqanalysisflags::MuonAmbiguityInBunch, dqanalysisflags::MuonAmbiguityOutOfBunch); //! joinable to ReducedMuonTracks -DECLARE_SOA_TABLE(Prefilter, "AOD", "DQPREFILTERA", dqanalysisflags::IsBarrelSelectedPrefilter); //! joinable to ReducedTracksAssoc +DECLARE_SOA_TABLE(Prefilter, "AOD", "DQPREFILTERA", dqanalysisflags::IsBarrelSelectedPrefilter); //! joinable to o2::aod::ReducedTracksAssoc DECLARE_SOA_TABLE(BmesonCandidates, "AOD", "DQBMESONSA", dqanalysisflags::RunNumber, dqanalysisflags::EventIdx, dqanalysisflags::EventTimestamp, dqanalysisflags::massBcandidate, dqanalysisflags::MassDileptonCandidate, dqanalysisflags::deltamassBcandidate, dqanalysisflags::pTBcandidate, dqanalysisflags::EtaBcandidate, dqanalysisflags::PhiBcandidate, dqanalysisflags::RapBcandidate, @@ -223,46 +217,46 @@ DECLARE_SOA_TABLE(JPsieeCandidates, "AOD", "DQPSEUDOPROPER", } // namespace o2::aod // Declarations of various short names -using MyEvents = soa::Join; -using MyEventsBasic = soa::Join; -using MyEventsMultExtraNoQvector = soa::Join; -using MyEventsMultExtra = soa::Join; -using MyEventsMultExtraQVector = soa::Join; -using MyEventsZdc = soa::Join; -using MyEventsMultExtraZdc = soa::Join; -using MyEventsMultExtraZdcFit = soa::Join; -using MyEventsSelected = soa::Join; -using MyEventsMultExtraSelected = soa::Join; -using MyEventsVtxCovSelectedMultExtra = soa::Join; -using MyEventsHashSelected = soa::Join; -using MyEventsVtxCov = soa::Join; -using MyEventsVtxCovSelected = soa::Join; -using MyEventsVtxCovSelectedInfo = soa::Join; -using MyEventsVtxCovSelectedQvector = soa::Join; -using MyEventsVtxCovSelectedQvectorWithHash = soa::Join; -using MyEventsVtxCovZdcFitSelected = soa::Join; -using MyEventsVtxCovZdcFitSelectedMultExtra = soa::Join; -using MyEventsQvector = soa::Join; -using MyEventsHashSelectedQvector = soa::Join; -using MyEventsQvectorCentr = soa::Join; -using MyEventsQvectorCentrMerge = soa::Join; -using MyEventsQvectorCentrSelected = soa::Join; -using MyEventsHashSelectedQvectorCentr = soa::Join; - -using MyBarrelTracks = soa::Join; -using MyBarrelTracksWithAmbiguities = soa::Join; -using MyBarrelTracksWithCov = soa::Join; -using MyBarrelTracksWithCovWithAmbiguities = soa::Join; -using MyBarrelTracksWithCovWithAmbiguitiesWithColl = soa::Join; -using MyBarrelTracksWithEMCal = soa::Join; -using MyBarrelTracksWithCovWithEMCal = soa::Join; -using MyDielectronCandidates = soa::Join; -using MyDitrackCandidates = soa::Join; -using MyDimuonCandidates = soa::Join; -using MyMuonTracks = soa::Join; -using MyMuonTracksWithCov = soa::Join; -using MyMuonTracksWithCovWithAmbiguities = soa::Join; -using MyMuonTracksSelectedWithColl = soa::Join; +using MyEvents = o2::soa::Join; +using MyEventsBasic = o2::soa::Join; +using MyEventsMultExtraNoQvector = o2::soa::Join; +using MyEventsMultExtra = o2::soa::Join; +using MyEventsMultExtraQVector = o2::soa::Join; +using MyEventsZdc = o2::soa::Join; +using MyEventsMultExtraZdc = o2::soa::Join; +using MyEventsMultExtraZdcFit = o2::soa::Join; +using MyEventsSelected = o2::soa::Join; +using MyEventsMultExtraSelected = o2::soa::Join; +using MyEventsVtxCovSelectedMultExtra = o2::soa::Join; +using MyEventsHashSelected = o2::soa::Join; +using MyEventsVtxCov = o2::soa::Join; +using MyEventsVtxCovSelected = o2::soa::Join; +using MyEventsVtxCovSelectedInfo = o2::soa::Join; +using MyEventsVtxCovSelectedQvector = o2::soa::Join; +using MyEventsVtxCovSelectedQvectorWithHash = o2::soa::Join; +using MyEventsVtxCovZdcFitSelected = o2::soa::Join; +using MyEventsVtxCovZdcFitSelectedMultExtra = o2::soa::Join; +using MyEventsQvector = o2::soa::Join; +using MyEventsHashSelectedQvector = o2::soa::Join; +using MyEventsQvectorCentr = o2::soa::Join; +using MyEventsQvectorCentrMerge = o2::soa::Join; +using MyEventsQvectorCentrSelected = o2::soa::Join; +using MyEventsHashSelectedQvectorCentr = o2::soa::Join; + +using MyBarrelTracks = o2::soa::Join; +using MyBarrelTracksWithAmbiguities = o2::soa::Join; +using MyBarrelTracksWithCov = o2::soa::Join; +using MyBarrelTracksWithCovWithAmbiguities = o2::soa::Join; +using MyBarrelTracksWithCovWithAmbiguitiesWithColl = o2::soa::Join; +using MyBarrelTracksWithEMCal = o2::soa::Join; +using MyBarrelTracksWithCovWithEMCal = o2::soa::Join; +using MyDielectronCandidates = o2::soa::Join; +using MyDitrackCandidates = o2::soa::Join; +using MyDimuonCandidates = o2::soa::Join; +using MyMuonTracks = o2::soa::Join; +using MyMuonTracksWithCov = o2::soa::Join; +using MyMuonTracksWithCovWithAmbiguities = o2::soa::Join; +using MyMuonTracksSelectedWithColl = o2::soa::Join; // bit maps used for the Fill functions of the VarManager constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended; @@ -318,40 +312,40 @@ void PrintBitMap(TMap map, int nbits) // Analysis task that produces event decisions (analysis cut, in bunch pileup and split collision check) and the Hash table used in event mixing struct AnalysisEventSelection { - Produces eventSel; - Produces hash; - Produces JetEvents; - OutputObj fOutputList{"output"}; + o2::framework::Produces eventSel; + o2::framework::Produces hash; + o2::framework::Produces JetEvents; + o2::framework::OutputObj fOutputList{"output"}; // TODO: Provide the mixing variables and binning directly via configurables (e.g. vectors of float) - Configurable fConfigMixingVariables{"cfgMixingVars", "", "Mixing configs separated by a comma, default no mixing"}; - Configurable fConfigMixingVariablesJson{"cfgMixingVarsJSON", "", "Mixing configs in JSON format"}; - Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; - Configurable fConfigEventCutsJSON{"cfgEventCutsJSON", "", "Additional event cuts specified in JSON format"}; - Configurable fConfigAddEventHistogram{"cfgAddEventHistogram", "", "Comma separated list of histograms"}; - Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Add event histograms defined via JSON formatting (see HistogramsLibrary)"}; - Configurable fConfigQA{"cfgQA", true, "If true, QA histograms will be created and filled"}; - - Configurable fConfigITSROFrameStartBorderMargin{"cfgITSROFrameStartBorderMargin", -1, "Number of bcs at the start of ITS RO Frame border. Take from CCDB if -1"}; - Configurable fConfigITSROFrameEndBorderMargin{"cfgITSROFrameEndBorderMargin", -1, "Number of bcs at the end of ITS RO Frame border. Take from CCDB if -1"}; - - Configurable fConfigSplitCollisionsDeltaZ{"cfgSplitCollisionsDeltaZ", 1.0, "maximum delta-z (cm) between two collisions to consider them as split candidates"}; - Configurable fConfigSplitCollisionsDeltaBC{"cfgSplitCollisionsDeltaBC", 100, "maximum delta-BC between two collisions to consider them as split candidates; do not apply if value is negative"}; - Configurable fConfigCheckSplitCollisions{"cfgCheckSplitCollisions", false, "If true, run the split collision check and fill histograms"}; - - Configurable fConfigRunZorro{"cfgRunZorro", false, "Enable event selection with zorro [WARNING: under debug, do not enable!]"}; - Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable fConfigNoLaterThan{"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 fConfigFetchInteractionRate{"cfgFetchInteractionRate", false, "Fetch event-wise interaction rate from the CCDB"}; - Configurable fConfigIRSource{"cfgIRSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; + o2::framework::Configurable fConfigMixingVariables{"cfgMixingVars", "", "Mixing configs separated by a comma, default no mixing"}; + o2::framework::Configurable fConfigMixingVariablesJson{"cfgMixingVarsJSON", "", "Mixing configs in JSON format"}; + o2::framework::Configurable fConfigEventCuts{"cfgEventCuts", "eventStandard", "Event selection"}; + o2::framework::Configurable fConfigEventCutsJSON{"cfgEventCutsJSON", "", "Additional event cuts specified in JSON format"}; + o2::framework::Configurable fConfigAddEventHistogram{"cfgAddEventHistogram", "", "Comma separated list of histograms"}; + o2::framework::Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Add event histograms defined via JSON formatting (see HistogramsLibrary)"}; + o2::framework::Configurable fConfigQA{"cfgQA", true, "If true, QA histograms will be created and filled"}; + + o2::framework::Configurable fConfigITSROFrameStartBorderMargin{"cfgITSROFrameStartBorderMargin", -1, "Number of bcs at the start of ITS RO Frame border. Take from CCDB if -1"}; + o2::framework::Configurable fConfigITSROFrameEndBorderMargin{"cfgITSROFrameEndBorderMargin", -1, "Number of bcs at the end of ITS RO Frame border. Take from CCDB if -1"}; + + o2::framework::Configurable fConfigSplitCollisionsDeltaZ{"cfgSplitCollisionsDeltaZ", 1.0, "maximum delta-z (cm) between two collisions to consider them as split candidates"}; + o2::framework::Configurable fConfigSplitCollisionsDeltaBC{"cfgSplitCollisionsDeltaBC", 100, "maximum delta-BC between two collisions to consider them as split candidates; do not apply if value is negative"}; + o2::framework::Configurable fConfigCheckSplitCollisions{"cfgCheckSplitCollisions", false, "If true, run the split collision check and fill histograms"}; + + o2::framework::Configurable fConfigRunZorro{"cfgRunZorro", false, "Enable event selection with zorro [WARNING: under debug, do not enable!]"}; + o2::framework::Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + o2::framework::Configurable fConfigNoLaterThan{"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"}; + o2::framework::Configurable fConfigFetchInteractionRate{"cfgFetchInteractionRate", false, "Fetch event-wise interaction rate from the CCDB"}; + o2::framework::Configurable fConfigIRSource{"cfgIRSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; HistogramManager* fHistMan = nullptr; MixingHandler* fMixHandler = nullptr; AnalysisCompositeCut* fEventCut = nullptr; - Service fCCDB{}; + o2::framework::Service fCCDB{}; o2::ccdb::CcdbApi fCCDBApi; - ctpRateFetcher rateFetcher; + o2::ctpRateFetcher rateFetcher; std::map fSelMap; // key: reduced event global index, value: event selection decision std::map> fBCCollMap; // key: global BC, value: vector of reduced event global indices @@ -378,7 +372,7 @@ struct AnalysisEventSelection { fEventCut = new AnalysisCompositeCut(true); TString eventCutStr = fConfigEventCuts.value; if (eventCutStr != "") { - AnalysisCut* cut = dqcuts::GetAnalysisCut(eventCutStr.Data()); + AnalysisCut* cut = o2::aod::dqcuts::GetAnalysisCut(eventCutStr.Data()); if (cut != nullptr) { fEventCut->AddCut(cut); } @@ -386,7 +380,7 @@ struct AnalysisEventSelection { // Additional cuts via JSON TString eventCutJSONStr = fConfigEventCutsJSON.value; if (eventCutJSONStr != "") { - std::vector jsonCuts = dqcuts::GetCutsFromJSON(eventCutJSONStr.Data()); + std::vector jsonCuts = o2::aod::dqcuts::GetCutsFromJSON(eventCutJSONStr.Data()); for (auto const& cutIt : jsonCuts) { fEventCut->AddCut(cutIt); } @@ -403,7 +397,7 @@ struct AnalysisEventSelection { DefineHistograms(fHistMan, "SameBunchCorrelations;OutOfBunchCorrelations;", ""); } // Additional histograms via JSON - dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); + o2::aod::dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); VarManager::SetUseVars(fHistMan->GetUsedVars()); fOutputList.setObject(fHistMan->GetMainHistogramList()); } @@ -416,11 +410,11 @@ struct AnalysisEventSelection { fMixHandler->Init(); if (objArray->GetEntries() > 0) { for (int iVar = 0; iVar < objArray->GetEntries(); ++iVar) { - dqmixing::SetUpMixing(fMixHandler, objArray->At(iVar)->GetName()); + o2::aod::dqmixing::SetUpMixing(fMixHandler, objArray->At(iVar)->GetName()); } } if (mixVarsJsonString != "") { - dqmixing::SetUpMixingFromJSON(fMixHandler, mixVarsJsonString.Data()); + o2::aod::dqmixing::SetUpMixingFromJSON(fMixHandler, mixVarsJsonString.Data()); } } @@ -662,32 +656,32 @@ struct AnalysisEventSelection { PROCESS_SWITCH(AnalysisEventSelection, processDummy, "Dummy function", true); }; -// Produces a table with barrel track decisions (joinable to the ReducedTracksAssociations) +// o2::framework::Produces a table with barrel track decisions (joinable to the ReducedTracksAssociations) // Here one should add all the track cuts needed through the workflow (e.g. cuts for same-even pairing, electron prefiltering, track for dilepton-track correlations) struct AnalysisTrackSelection { - Produces trackSel; - Produces trackAmbiguities; - OutputObj fOutputList{"output"}; - - Configurable fConfigCuts{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; - Configurable fConfigCutsJSON{"cfgBarrelTrackCutsJSON", "", "Additional list of barrel track cuts in JSON format"}; - Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; - Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; - Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; - Configurable fConfigPublishAmbiguity{"cfgPublishAmbiguity", true, "If true, publish ambiguity table and fill QA histograms"}; - - Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable fConfigCcdbPathTPC{"ccdb-path-tpc", "Users/z/zhxiong/TPCPID/PostCalib", "base path to the ccdb object"}; - Configurable fConfigNoLaterThan{"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 fConfigComputeTPCpostCalib{"cfgTPCpostCalib", false, "If true, compute TPC post-calibrated n-sigmas"}; - Configurable fConfigTPCpostCalibType{"cfgTPCpostCalibType", 1, "1: (TPCncls,pIN,eta) calibration typically for pp, 2: (eta,nPV,nLong,tLong) calibration typically for PbPb"}; - Configurable fConfigTPCuseInterpolatedCalib{"cfgTPCpostCalibUseInterpolation", true, "If true, use interpolated calibration values (default: true)"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + o2::framework::Produces trackSel; + o2::framework::Produces trackAmbiguities; + o2::framework::OutputObj fOutputList{"output"}; + + o2::framework::Configurable fConfigCuts{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; + o2::framework::Configurable fConfigCutsJSON{"cfgBarrelTrackCutsJSON", "", "Additional list of barrel track cuts in JSON format"}; + o2::framework::Configurable fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"}; + o2::framework::Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + o2::framework::Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + o2::framework::Configurable fConfigPublishAmbiguity{"cfgPublishAmbiguity", true, "If true, publish ambiguity table and fill QA histograms"}; + + o2::framework::Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + o2::framework::Configurable fConfigCcdbPathTPC{"ccdb-path-tpc", "Users/z/zhxiong/TPCPID/PostCalib", "base path to the ccdb object"}; + o2::framework::Configurable fConfigNoLaterThan{"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"}; + + o2::framework::Configurable fConfigComputeTPCpostCalib{"cfgTPCpostCalib", false, "If true, compute TPC post-calibrated n-sigmas"}; + o2::framework::Configurable fConfigTPCpostCalibType{"cfgTPCpostCalibType", 1, "1: (TPCncls,pIN,eta) calibration typically for pp, 2: (eta,nPV,nLong,tLong) calibration typically for PbPb"}; + o2::framework::Configurable fConfigTPCuseInterpolatedCalib{"cfgTPCpostCalibUseInterpolation", true, "If true, use interpolated calibration values (default: true)"}; + o2::framework::Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; // Track related options - Configurable fPropTrack{"cfgPropTrack", true, "Propgate tracks to associated collision to recalculate DCA and momentum vector"}; + o2::framework::Configurable fPropTrack{"cfgPropTrack", true, "Propgate tracks to associated collision to recalculate DCA and momentum vector"}; - Service fCCDB{}; + o2::framework::Service fCCDB{}; o2::ccdb::CcdbApi fCCDBApi; HistogramManager* fHistMan = nullptr; @@ -710,13 +704,13 @@ struct AnalysisTrackSelection { if (!cutNamesStr.IsNull()) { std::unique_ptr objArray(cutNamesStr.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - fTrackCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + fTrackCuts.push_back(o2::aod::dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); } } // Extra cuts via JSON TString addTrackCutsStr = fConfigCutsJSON.value; if (addTrackCutsStr != "") { - std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); + std::vector addTrackCuts = o2::aod::dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); for (auto const& t : addTrackCuts) { fTrackCuts.push_back(static_cast(t)); } @@ -738,9 +732,9 @@ struct AnalysisTrackSelection { histDirNames += "TrackBarrel_AmbiguityInBunch;TrackBarrel_AmbiguityOutOfBunch;"; } - DefineHistograms(fHistMan, histDirNames.Data(), fConfigAddTrackHistogram.value.data()); // define all histograms - dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + DefineHistograms(fHistMan, histDirNames.Data(), fConfigAddTrackHistogram.value.data()); // define all histograms + o2::aod::dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill fOutputList.setObject(fHistMan->GetMainHistogramList()); } @@ -752,7 +746,7 @@ struct AnalysisTrackSelection { } template - void runTrackSelection(ReducedTracksAssoc const& assocs, TEvents const& events, TTracks const& tracks) + void runTrackSelection(o2::aod::ReducedTracksAssoc const& assocs, TEvents const& events, TTracks const& tracks) { fNAssocsInBunch.clear(); fNAssocsOutOfBunch.clear(); @@ -818,7 +812,7 @@ struct AnalysisTrackSelection { // tracks without a matched cluster keep the sentinel values set by ResetValues if constexpr (static_cast(TTrackFillMap & VarManager::ObjTypes::TrackEMCal)) { if (track.has_matchedEMCalCluster()) { - auto cluster = track.template matchedEMCalCluster_as(); + auto cluster = track.template matchedEMCalCluster_as(); VarManager::FillTrackEMCal(cluster, track.p(), track.emcalMatchDeltaEta(), track.emcalMatchDeltaPhi()); } } @@ -905,23 +899,23 @@ struct AnalysisTrackSelection { } // end runTrackSelection() - void processSkimmed(ReducedTracksAssoc const& assocs, MyEventsSelected const& events, MyBarrelTracks const& tracks) + void processSkimmed(o2::aod::ReducedTracksAssoc const& assocs, MyEventsSelected const& events, MyBarrelTracks const& tracks) { runTrackSelection(assocs, events, tracks); } - void processSkimmedWithMultExtra(ReducedTracksAssoc const& assocs, MyEventsMultExtraSelected const& events, MyBarrelTracks const& tracks) + void processSkimmedWithMultExtra(o2::aod::ReducedTracksAssoc const& assocs, MyEventsMultExtraSelected const& events, MyBarrelTracks const& tracks) { runTrackSelection(assocs, events, tracks); } - void processSkimmedWithCov(ReducedTracksAssoc const& assocs, MyEventsVtxCovSelected const& events, MyBarrelTracksWithCov const& tracks) + void processSkimmedWithCov(o2::aod::ReducedTracksAssoc const& assocs, MyEventsVtxCovSelected const& events, MyBarrelTracksWithCov const& tracks) { runTrackSelection(assocs, events, tracks); } - void processSkimmedWithEMCal(ReducedTracksAssoc const& assocs, MyEventsSelected const& events, MyBarrelTracksWithEMCal const& tracks, aod::ReducedEMCals const& /*emcals*/) + void processSkimmedWithEMCal(o2::aod::ReducedTracksAssoc const& assocs, MyEventsSelected const& events, MyBarrelTracksWithEMCal const& tracks, o2::aod::ReducedEMCals const& /*emcals*/) { runTrackSelection(assocs, events, tracks); } - void processSkimmedWithCovWithEMCal(ReducedTracksAssoc const& assocs, MyEventsVtxCovSelected const& events, MyBarrelTracksWithCovWithEMCal const& tracks, aod::ReducedEMCals const& /*emcals*/) + void processSkimmedWithCovWithEMCal(o2::aod::ReducedTracksAssoc const& assocs, MyEventsVtxCovSelected const& events, MyBarrelTracksWithCovWithEMCal const& tracks, o2::aod::ReducedEMCals const& /*emcals*/) { runTrackSelection(assocs, events, tracks); } @@ -938,26 +932,26 @@ struct AnalysisTrackSelection { PROCESS_SWITCH(AnalysisTrackSelection, processDummy, "Dummy function", true); }; -// Produces a table with muon decisions (joinable to the ReducedMuonsAssociations) +// o2::framework::Produces a table with muon decisions (joinable to the ReducedMuonsAssociations) // Here one should add all the track cuts needed through the workflow (e.g. cuts for same-event pairing, track for dilepton-track correlations) struct AnalysisMuonSelection { - Produces muonSel; - Produces muonAmbiguities; - OutputObj fOutputList{"output"}; + o2::framework::Produces muonSel; + o2::framework::Produces muonAmbiguities; + o2::framework::OutputObj fOutputList{"output"}; - Configurable fConfigCuts{"cfgMuonCuts", "muonQualityCuts", "Comma separated list of muon cuts"}; - Configurable fConfigCutsJSON{"cfgMuonCutsJSON", "", "Additional list of muon cuts in JSON format"}; - Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; - Configurable fConfigAddMuonHistogram{"cfgAddMuonHistogram", "", "Comma separated list of histograms"}; - Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; - Configurable fConfigPublishAmbiguity{"cfgPublishAmbiguity", true, "If true, publish ambiguity table and fill QA histograms"}; + o2::framework::Configurable fConfigCuts{"cfgMuonCuts", "muonQualityCuts", "Comma separated list of muon cuts"}; + o2::framework::Configurable fConfigCutsJSON{"cfgMuonCutsJSON", "", "Additional list of muon cuts in JSON format"}; + o2::framework::Configurable fConfigQA{"cfgQA", false, "If true, fill QA histograms"}; + o2::framework::Configurable fConfigAddMuonHistogram{"cfgAddMuonHistogram", "", "Comma separated list of histograms"}; + o2::framework::Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + o2::framework::Configurable fConfigPublishAmbiguity{"cfgPublishAmbiguity", true, "If true, publish ambiguity table and fill QA histograms"}; - Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable fConfigNoLaterThan{"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 fConfigGeoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + o2::framework::Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + o2::framework::Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + o2::framework::Configurable fConfigNoLaterThan{"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"}; + o2::framework::Configurable fConfigGeoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - Service fCCDB{}; + o2::framework::Service fCCDB{}; HistogramManager* fHistMan = nullptr; std::vector fMuonCuts; @@ -979,13 +973,13 @@ struct AnalysisMuonSelection { if (!cutNamesStr.IsNull()) { std::unique_ptr objArray(cutNamesStr.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - fMuonCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + fMuonCuts.push_back(o2::aod::dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); } } // extra cuts from JSON TString addCutsStr = fConfigCutsJSON.value; if (addCutsStr != "") { - std::vector addCuts = dqcuts::GetCutsFromJSON(addCutsStr.Data()); + std::vector addCuts = o2::aod::dqcuts::GetCutsFromJSON(addCutsStr.Data()); for (auto const& t : addCuts) { fMuonCuts.push_back(static_cast(t)); } @@ -1007,9 +1001,9 @@ struct AnalysisMuonSelection { histDirNames += "TrackMuon_AmbiguityInBunch;TrackMuon_AmbiguityOutOfBunch;"; } - DefineHistograms(fHistMan, histDirNames.Data(), fConfigAddMuonHistogram.value.data()); // define all histograms - dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + DefineHistograms(fHistMan, histDirNames.Data(), fConfigAddMuonHistogram.value.data()); // define all histograms + o2::aod::dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill fOutputList.setObject(fHistMan->GetMainHistogramList()); } @@ -1023,7 +1017,7 @@ struct AnalysisMuonSelection { } template - void runMuonSelection(ReducedMuonsAssoc const& assocs, TEvents const& events, TMuons const& muons) + void runMuonSelection(o2::aod::ReducedMuonsAssoc const& assocs, TEvents const& events, TMuons const& muons) { fNAssocsInBunch.clear(); fNAssocsOutOfBunch.clear(); @@ -1134,7 +1128,7 @@ struct AnalysisMuonSelection { } } - void processSkimmed(ReducedMuonsAssoc const& assocs, MyEventsVtxCovSelected const& events, MyMuonTracksWithCov const& muons) + void processSkimmed(o2::aod::ReducedMuonsAssoc const& assocs, MyEventsVtxCovSelected const& events, MyMuonTracksWithCov const& muons) { runMuonSelection(assocs, events, muons); } @@ -1152,12 +1146,12 @@ struct AnalysisMuonSelection { // with the sample of tracks to be used in downstream analysis (fConfigTrackCuts). If a pair is found to pass // the pair prefilter cut (cfgPrefilterPairCut), the analysis track is tagged to be removed from analysis. struct AnalysisPrefilterSelection { - Produces prefilter; // joinable with ReducedTracksAssoc + o2::framework::Produces prefilter; // joinable with o2::aod::ReducedTracksAssoc // Configurables - Configurable fConfigPrefilterTrackCut{"cfgPrefilterTrackCut", "", "Prefilter track cut"}; - Configurable fConfigPrefilterPairCut{"cfgPrefilterPairCut", "", "Prefilter pair cut"}; - Configurable fConfigTrackCuts{"cfgTrackCuts", "", "Track cuts for which to run the prefilter"}; + o2::framework::Configurable fConfigPrefilterTrackCut{"cfgPrefilterTrackCut", "", "Prefilter track cut"}; + o2::framework::Configurable fConfigPrefilterPairCut{"cfgPrefilterPairCut", "", "Prefilter pair cut"}; + o2::framework::Configurable fConfigTrackCuts{"cfgTrackCuts", "", "Track cuts for which to run the prefilter"}; // TODO: Add prefilter pair cut via JSON @@ -1166,7 +1160,7 @@ struct AnalysisPrefilterSelection { uint32_t fPrefilterMask = 0; int fPrefilterCutBit = -1; - Preslice trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; + o2::framework::Preslice trackAssocsPerCollision = o2::aod::reducedtrack_association::reducedeventId; void init(o2::framework::InitContext& context) { @@ -1200,14 +1194,14 @@ struct AnalysisPrefilterSelection { if (runPrefilter) { // get the list of cuts that were computed in the barrel track-selection task and create a bit mask // to mark just the ones we want to apply a prefilter on - string trackCuts; - getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", trackCuts, false); + std::string trackCuts; + o2::common::core::getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", trackCuts, false); TString allTrackCutsStr = trackCuts; // check also the cuts added via JSON and add them to the string of cuts - getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", trackCuts, false); + o2::common::core::getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", trackCuts, false); TString addTrackCutsStr = trackCuts; if (addTrackCutsStr != "") { - std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); + std::vector addTrackCuts = o2::aod::dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); for (auto const& t : addTrackCuts) { allTrackCutsStr += Form(",%s", t->GetName()); } @@ -1233,7 +1227,7 @@ struct AnalysisPrefilterSelection { fPairCut = new AnalysisCompositeCut(true); TString pairCutStr = fConfigPrefilterPairCut.value; if (!pairCutStr.IsNull()) { - fPairCut = dqcuts::GetCompositeCut(pairCutStr.Data()); + fPairCut = o2::aod::dqcuts::GetCompositeCut(pairCutStr.Data()); } } if (fPrefilterMask == static_cast(0) || fPrefilterCutBit < 0) { @@ -1246,7 +1240,7 @@ struct AnalysisPrefilterSelection { } template - void runPrefilter(soa::Join const& assocs, TTracks const& /*tracks*/) + void runPrefilter(o2::soa::Join const& assocs, TTracks const& /*tracks*/) { if (fPrefilterCutBit < 0 || fPrefilterMask == 0) { return; @@ -1287,7 +1281,7 @@ struct AnalysisPrefilterSelection { } // end loop over combinations } - void processBarrelSkimmed(MyEventsBasic const& events, soa::Join const& assocs, MyBarrelTracks const& tracks) + void processBarrelSkimmed(MyEventsBasic const& events, o2::soa::Join const& assocs, MyBarrelTracks const& tracks) { fPrefilterMap.clear(); @@ -1336,100 +1330,100 @@ struct AnalysisPrefilterSelection { // The task implements also process functions for running event mixing struct AnalysisSameEventPairing { - Produces dielectronList; - Produces dimuonList; - Produces electronmuonList; - Produces dielectronsExtraList; - Produces dielectronInfoList; - Produces dimuonsExtraList; - Produces dielectronAllList; - Produces dielectronMlList; - Produces dimuonAllList; - Produces dileptonFlowList; - Produces dileptonInfoList; - Produces PromptNonPromptSepTable; - Produces dileptonPolarList; - Produces dileptonEventInfoList; - Produces dileptonMiniTree; + o2::framework::Produces dielectronList; + o2::framework::Produces dimuonList; + o2::framework::Produces electronmuonList; + o2::framework::Produces dielectronsExtraList; + o2::framework::Produces dielectronInfoList; + o2::framework::Produces dimuonsExtraList; + o2::framework::Produces dielectronAllList; + o2::framework::Produces dielectronMlList; + o2::framework::Produces dimuonAllList; + o2::framework::Produces dileptonFlowList; + o2::framework::Produces dileptonInfoList; + o2::framework::Produces PromptNonPromptSepTable; + o2::framework::Produces dileptonPolarList; + o2::framework::Produces dileptonEventInfoList; + o2::framework::Produces dileptonMiniTree; o2::base::MatLayerCylSet* fLUT = nullptr; TH1D* ResoFlowSP = nullptr; TH1D* ResoFlowEP = nullptr; int fCurrentRun = -1; // needed to detect if the run changed and trigger update of calibrations etc. - OutputObj fOutputList{"output"}; + o2::framework::OutputObj fOutputList{"output"}; - struct : ConfigurableGroup { - Configurable track{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; - Configurable muon{"cfgMuonCuts", "", "Comma separated list of muon cuts"}; - Configurable pair{"cfgPairCuts", "", "Comma separated list of pair cuts"}; - Configurable qVector{"cfgQvectorTrackCut", "", "Track cut of Q-vector, enable this if you want to remove the auto-correlation in TPC"}; - Configurable event{"cfgRemoveCollSplittingCandidates", false, "If true, remove collision splitting candidates as determined by the event selection task upstream"}; + struct : o2::framework::ConfigurableGroup { + o2::framework::Configurable track{"cfgTrackCuts", "jpsiO2MCdebugCuts2", "Comma separated list of barrel track cuts"}; + o2::framework::Configurable muon{"cfgMuonCuts", "", "Comma separated list of muon cuts"}; + o2::framework::Configurable pair{"cfgPairCuts", "", "Comma separated list of pair cuts"}; + o2::framework::Configurable qVector{"cfgQvectorTrackCut", "", "Track cut of Q-vector, enable this if you want to remove the auto-correlation in TPC"}; + o2::framework::Configurable event{"cfgRemoveCollSplittingCandidates", false, "If true, remove collision splitting candidates as determined by the event selection task upstream"}; // TODO: Add pair cuts via JSON } fConfigCuts; - Configurable fConfigMixingDepth{"cfgMixingDepth", 100, "Number of Events stored for event mixing"}; - Configurable fConfigMixingVariables{"cfgMixingVars", "", "Mixing configs separated by a comma, default no mixing"}; - Configurable fConfigMixingVariablesJson{"cfgMixingVarsJSON", "", "Mixing configs in JSON format"}; - Configurable fConfigRunMixingAcrossTFs{"cfgRunMixingAcrossTFs", false, "If true, run event mixing using the MixingHandler which accumulates events across multiple TFs"}; - // Configurable fConfigAddEventMixingHistogram{"cfgAddEventMixingHistogram", "", "Comma separated list of histograms"}; - Configurable fConfigAddSEPHistogram{"cfgAddSEPHistogram", "", "Comma separated list of histograms"}; - Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; - Configurable fConfigQA{"cfgQA", true, "If true, fill output histograms"}; - Configurable fConfigAmbiguousMuonHistograms{"cfgAmbiguousMuonHistograms", true, "If true, fill ambiguous histograms"}; + o2::framework::Configurable fConfigMixingDepth{"cfgMixingDepth", 100, "Number of Events stored for event mixing"}; + o2::framework::Configurable fConfigMixingVariables{"cfgMixingVars", "", "Mixing configs separated by a comma, default no mixing"}; + o2::framework::Configurable fConfigMixingVariablesJson{"cfgMixingVarsJSON", "", "Mixing configs in JSON format"}; + o2::framework::Configurable fConfigRunMixingAcrossTFs{"cfgRunMixingAcrossTFs", false, "If true, run event mixing using the MixingHandler which accumulates events across multiple TFs"}; + // o2::framework::Configurable fConfigAddEventMixingHistogram{"cfgAddEventMixingHistogram", "", "Comma separated list of histograms"}; + o2::framework::Configurable fConfigAddSEPHistogram{"cfgAddSEPHistogram", "", "Comma separated list of histograms"}; + o2::framework::Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + o2::framework::Configurable fConfigQA{"cfgQA", true, "If true, fill output histograms"}; + o2::framework::Configurable fConfigAmbiguousMuonHistograms{"cfgAmbiguousMuonHistograms", true, "If true, fill ambiguous histograms"}; // option for TR pair fill - Configurable fConfigTRPairs{"cfgFillTRPairs", false, "If true, fill Track rotation pairs"}; - Configurable fConfigNRotations{"cfgNRotations", 20, "Number of rotations for track rotation method"}; - - struct : ConfigurableGroup { - Configurable url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable grpMagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; - Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - Configurable GrpLhcIfPath{"grplhcif", "GLO/Config/GRPLHCIF", "Path on the CCDB for the GRPLHCIF object"}; - Configurable efficiencyPath{"effHistPath", "Users/z/zhxiong/efficiency", "Path on the CCDB for the efficiency histograms"}; - Configurable flowPath{"flowPath", "Users/y/yiping/FlowResolution", "Path to the flow resolution object"}; - Configurable phiPath{"phiPath", "Users/h/hxiaoyu/TrackPhi/LHC23", "Path to load phi distribution for track rotation"}; + o2::framework::Configurable fConfigTRPairs{"cfgFillTRPairs", false, "If true, fill Track rotation pairs"}; + o2::framework::Configurable fConfigNRotations{"cfgNRotations", 3, "Number of rotations for event plane preserving track rotation method, only 1 or 3 are supported"}; + + struct : o2::framework::ConfigurableGroup { + o2::framework::Configurable url{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + o2::framework::Configurable grpMagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + o2::framework::Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + o2::framework::Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + o2::framework::Configurable GrpLhcIfPath{"grplhcif", "GLO/Config/GRPLHCIF", "Path on the CCDB for the GRPLHCIF object"}; + o2::framework::Configurable efficiencyPath{"effHistPath", "Users/z/zhxiong/efficiency", "Path on the CCDB for the efficiency histograms"}; + o2::framework::Configurable flowPath{"flowPath", "Users/y/yiping/FlowResolution", "Path to the flow resolution object"}; + o2::framework::Configurable phiPath{"phiPath", "Users/h/hxiaoyu/TrackPhi/LHC23", "Path to load phi distribution for track rotation"}; } fConfigCCDB; - struct : ConfigurableGroup { - Configurable useRemoteField{"cfgUseRemoteField", false, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; - Configurable magField{"cfgMagField", 5.0f, "Manually set magnetic field"}; - Configurable flatTables{"cfgFlatTables", false, "Produce a single flat tables with all relevant information of the pairs and single tracks"}; - Configurable polarTables{"cfgPolarTables", false, "Produce tables with dilepton polarization information"}; - Configurable useKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; - Configurable useAbsDCA{"cfgUseAbsDCA", false, "Use absolute DCA minimization instead of chi^2 minimization in secondary vertexing"}; - Configurable propToPCA{"cfgPropToPCA", false, "Propagate tracks to secondary vertex"}; - Configurable corrFullGeo{"cfgCorrFullGeo", false, "Use full geometry to correct for MCS effects in track propagation"}; - Configurable noCorr{"cfgNoCorrFwdProp", false, "Do not correct for MCS effects in track propagation"}; - Configurable collisionSystem{"syst", "pp", "Collision system, pp or PbPb"}; - Configurable centerMassEnergy{"energy", 13600, "Center of mass energy in GeV"}; - Configurable propTrack{"cfgPropTrack", true, "Propgate tracks to associated collision to recalculate DCA and momentum vector"}; - Configurable useRemoteCollisionInfo{"cfgUseRemoteCollisionInfo", false, "Use remote collision information from CCDB"}; - Configurable useEfficiencyWeighting{"cfgUseEfficiencyWeighting", false, "Apply efficiency weighting to the pairs from CCDB"}; - Configurable efficiencyType{"cfgEfficiencyType", 0, "Type of efficiency to apply from CCDB: 0 no efficiency, 1 pt-cent-costhetastar"}; - Configurable useFlowReso{"cfgUseFlowReso", false, "Use remote flow information from CCDB"}; - Configurable usePhiDistribution{"cfgUsePhiDistribution", false, "Use phi distribution to correct track rotation"}; + struct : o2::framework::ConfigurableGroup { + o2::framework::Configurable useRemoteField{"cfgUseRemoteField", false, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; + o2::framework::Configurable magField{"cfgMagField", 5.0f, "Manually set magnetic field"}; + o2::framework::Configurable flatTables{"cfgFlatTables", false, "Produce a single flat tables with all relevant information of the pairs and single tracks"}; + o2::framework::Configurable polarTables{"cfgPolarTables", false, "Produce tables with dilepton polarization information"}; + o2::framework::Configurable useKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; + o2::framework::Configurable useAbsDCA{"cfgUseAbsDCA", false, "Use absolute DCA minimization instead of chi^2 minimization in secondary vertexing"}; + o2::framework::Configurable propToPCA{"cfgPropToPCA", false, "Propagate tracks to secondary vertex"}; + o2::framework::Configurable corrFullGeo{"cfgCorrFullGeo", false, "Use full geometry to correct for MCS effects in track propagation"}; + o2::framework::Configurable noCorr{"cfgNoCorrFwdProp", false, "Do not correct for MCS effects in track propagation"}; + o2::framework::Configurable collisionSystem{"syst", "pp", "Collision system, pp or PbPb"}; + o2::framework::Configurable centerMassEnergy{"energy", 13600, "Center of mass energy in GeV"}; + o2::framework::Configurable propTrack{"cfgPropTrack", true, "Propgate tracks to associated collision to recalculate DCA and momentum vector"}; + o2::framework::Configurable useRemoteCollisionInfo{"cfgUseRemoteCollisionInfo", false, "Use remote collision information from CCDB"}; + o2::framework::Configurable useEfficiencyWeighting{"cfgUseEfficiencyWeighting", false, "Apply efficiency weighting to the pairs from CCDB"}; + o2::framework::Configurable efficiencyType{"cfgEfficiencyType", 0, "Type of efficiency to apply from CCDB: 0 no efficiency, 1 pt-cent-costhetastar"}; + o2::framework::Configurable useFlowReso{"cfgUseFlowReso", false, "Use remote flow information from CCDB"}; + o2::framework::Configurable usePhiDistribution{"cfgUsePhiDistribution", false, "Use phi distribution to correct track rotation"}; } fConfigOptions; - struct : ConfigurableGroup { - Configurable applyBDT{"applyBDT", false, "Flag to apply ML selections"}; - Configurable fConfigBdtCutsJSON{"fConfigBdtCutsJSON", "", "Additional list of BDT cuts in JSON format"}; + struct : o2::framework::ConfigurableGroup { + o2::framework::Configurable applyBDT{"applyBDT", false, "Flag to apply ML selections"}; + o2::framework::Configurable fConfigBdtCutsJSON{"fConfigBdtCutsJSON", "", "Additional list of BDT cuts in JSON format"}; - Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{"Users/j/jseo/ML/PbPbPsi/default/"}, "Paths of models on CCDB"}; - Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; - Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + o2::framework::Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{"Users/j/jseo/ML/PbPbPsi/default/"}, "Paths of models on CCDB"}; + o2::framework::Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; + o2::framework::Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; } fConfigML; - struct : ConfigurableGroup { - Configurable fConfigMiniTree{"useMiniTree.cfgMiniTree", false, "Produce a single flat table with minimal information for analysis"}; - Configurable fConfigMiniTreeMinMass{"useMiniTree.cfgMiniTreeMinMass", 2, "Min. mass cut for minitree"}; - Configurable fConfigMiniTreeMaxMass{"useMiniTree.cfgMiniTreeMaxMass", 5, "Max. mass cut for minitree"}; + struct : o2::framework::ConfigurableGroup { + o2::framework::Configurable fConfigMiniTree{"useMiniTree.cfgMiniTree", false, "Produce a single flat table with minimal information for analysis"}; + o2::framework::Configurable fConfigMiniTreeMinMass{"useMiniTree.cfgMiniTreeMinMass", 2, "Min. mass cut for minitree"}; + o2::framework::Configurable fConfigMiniTreeMaxMass{"useMiniTree.cfgMiniTreeMaxMass", 5, "Max. mass cut for minitree"}; } useMiniTree; - Service fCCDB{}; + o2::framework::Service fCCDB{}; o2::ccdb::CcdbApi fCCDBApi; - Filter filterEventSelected = aod::dqanalysisflags::isEventSelected > static_cast(0); + o2::framework::expressions::Filter filterEventSelected = o2::aod::dqanalysisflags::isEventSelected > static_cast(0); HistogramManager* fHistMan = nullptr; MixingHandler fMixingHandler; @@ -1461,10 +1455,10 @@ struct AnalysisSameEventPairing { bool fEnableBarrelMuonHistos = false; bool fEnableBarrelMuonMixingHistos = false; - NoBinningPolicy hashBin; + o2::framework::NoBinningPolicy hashBin; - Preslice> trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; - Preslice> muonAssocsPerCollision = aod::reducedtrack_association::reducedeventId; + o2::framework::Preslice> trackAssocsPerCollision = o2::aod::reducedtrack_association::reducedeventId; + o2::framework::Preslice> muonAssocsPerCollision = o2::aod::reducedtrack_association::reducedeventId; void init(o2::framework::InitContext& context) { @@ -1505,7 +1499,7 @@ struct AnalysisSameEventPairing { if (!cutNamesStr.IsNull()) { std::unique_ptr objArray(cutNamesStr.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - fPairCuts.push_back(*dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + fPairCuts.push_back(*o2::aod::dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); } } @@ -1534,8 +1528,8 @@ struct AnalysisSameEventPairing { auto config = o2::aod::dqmlcuts::GetBdtScoreCutsAndConfigFromJSON(fConfigML.fConfigBdtCutsJSON.value.c_str()); - if (std::holds_alternative(config)) { - auto& cfg = std::get(config); + if (std::holds_alternative(config)) { + auto& cfg = std::get(config); binsMl = cfg.binsMl; nClassesMl = 1; cutsMl = cfg.cutsMl; @@ -1547,7 +1541,7 @@ struct AnalysisSameEventPairing { fDQMlResponse.setCentType(cfg.centType); LOG(info) << "Using BDT cuts for binary classification"; } else { - auto& cfg = std::get(config); + auto& cfg = std::get(config); binsMl = cfg.binsMl; nClassesMl = 3; cutsMl = cfg.cutsMl; @@ -1572,14 +1566,14 @@ struct AnalysisSameEventPairing { } // get the barrel track selection cuts - string tempCuts; - getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", tempCuts, false); + std::string tempCuts; + o2::common::core::getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", tempCuts, false); TString tempCutsStr = tempCuts; // check also the cuts added via JSON and add them to the string of cuts - getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", tempCuts, false); + o2::common::core::getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", tempCuts, false); TString addTrackCutsStr = tempCuts; if (addTrackCutsStr != "") { - std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); + std::vector addTrackCuts = o2::aod::dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); for (auto const& t : addTrackCuts) { tempCutsStr += Form(",%s", t->GetName()); } @@ -1638,13 +1632,13 @@ struct AnalysisSameEventPairing { } // get the muon track selection cuts - getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCuts", tempCuts, false); + o2::common::core::getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCuts", tempCuts, false); tempCutsStr = tempCuts; // check also the cuts added via JSON and add them to the string of cuts - getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCutsJSON", tempCuts, false); + o2::common::core::getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCutsJSON", tempCuts, false); TString addMuonCutsStr = tempCuts; if (addMuonCutsStr != "") { - std::vector addMuonCuts = dqcuts::GetCutsFromJSON(addMuonCutsStr.Data()); + std::vector addMuonCuts = o2::aod::dqcuts::GetCutsFromJSON(addMuonCutsStr.Data()); for (auto const& t : addMuonCuts) { tempCutsStr += Form(",%s", t->GetName()); } @@ -1727,12 +1721,12 @@ struct AnalysisSameEventPairing { // fMixingHandler = new MixingHandler("mixingHandler", "mixing handler"); if (objArray->GetEntries() > 0) { for (int iVar = 0; iVar < objArray->GetEntries(); ++iVar) { - dqmixing::SetUpMixing(&fMixingHandler, objArray->At(iVar)->GetName()); + o2::aod::dqmixing::SetUpMixing(&fMixingHandler, objArray->At(iVar)->GetName()); } } } if (mixVarsJsonString != "") { - dqmixing::SetUpMixingFromJSON(&fMixingHandler, mixVarsJsonString.Data()); + o2::aod::dqmixing::SetUpMixingFromJSON(&fMixingHandler, mixVarsJsonString.Data()); } fMixingHandler.SetPoolDepth(fConfigMixingDepth); fMixingHandler.Init(); @@ -1819,8 +1813,8 @@ struct AnalysisSameEventPairing { if (fEnableBarrelMixingHistos) { DefineHistograms(fHistMan, "PairingMEQA", "mixedevent-pairing"); // histograms for QA of the pairing } - dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + o2::aod::dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill fOutputList.setObject(fHistMan->GetMainHistogramList()); } } @@ -1859,7 +1853,7 @@ struct AnalysisSameEventPairing { } } - std::map metadataRCT, header; + std::map metadataRCT, header; header = fCCDBApi.retrieveHeaders(Form("RCT/Info/RunInformation/%i", runNumber), metadataRCT, -1); uint64_t sor = std::atol(header["SOR"].c_str()); uint64_t eor = std::atol(header["EOR"].c_str()); @@ -1901,7 +1895,7 @@ struct AnalysisSameEventPairing { // Template function to run same event pairing (barrel-barrel, muon-muon, barrel-muon) template - void runSameEventPairing(TEvents const& events, Preslice& preslice, TTrackAssocs const& assocs, TTracks const& /*tracks*/) + void runSameEventPairing(TEvents const& events, o2::framework::Preslice& preslice, TTrackAssocs const& assocs, TTracks const& /*tracks*/) { if (events.size() > 0) { // Additional protection to avoid crashing of events.begin().runNumber() if (fCurrentRun != events.begin().runNumber()) { @@ -2449,14 +2443,26 @@ struct AnalysisSameEventPairing { } } if (sign1 * sign2 < 0) { - for (int i = 0; i < fConfigNRotations.value; i++) { - VarManager::FillPairRotation(t1, t2); + if (fConfigNRotations.value == 1) { + VarManager::FillPairRotation(t1, t2, fConfigNRotations.value); if constexpr (TPairType == VarManager::kDecayToEE) { fHistMan->FillHistClass(Form("PairsBarrelTRPM_%s", fTrackCuts[icut].Data()), dqtablereader_helpers::varValues()); if (isAmbiExtra) { fHistMan->FillHistClass(Form("PairsBarrelTRPM_ambiguousextra_%s", fTrackCuts[icut].Data()), dqtablereader_helpers::varValues()); } } + } else if (fConfigNRotations.value == 3) { + for (int irot = 1; irot <= fConfigNRotations.value; irot++) { + VarManager::FillPairRotation(t1, t2, irot); + if constexpr (TPairType == VarManager::kDecayToEE) { + fHistMan->FillHistClass(Form("PairsBarrelTRPM_%s", fTrackCuts[icut].Data()), dqtablereader_helpers::varValues()); + if (isAmbiExtra) { + fHistMan->FillHistClass(Form("PairsBarrelTRPM_ambiguousextra_%s", fTrackCuts[icut].Data()), dqtablereader_helpers::varValues()); + } + } + } + } else { + LOGF(fatal, "Unsupported number of rotations: %d, only 1 and 3 are supported", fConfigNRotations.value); } } } @@ -2733,7 +2739,7 @@ struct AnalysisSameEventPairing { // barrel-barrel and muon-muon event mixing template - void runSameSideMixing(TEvents& events, TAssocs const& assocs, TTracks const& tracks, Preslice& preSlice) + void runSameSideMixing(TEvents& events, TAssocs const& assocs, TTracks const& tracks, o2::framework::Preslice& preSlice) { if (ResoFlowSP == nullptr || ResoFlowEP == nullptr) { LOG(info) << "Flow resolution objects not set, flow will not be filled for mixed events"; @@ -2768,7 +2774,7 @@ struct AnalysisSameEventPairing { } template - void runEmuSameEventPairing(TEvents const& events, Preslice& preslice1, TTrackAssocs const& assocs1, TTracks const& /*tracks1*/, Preslice& preslice2, TMuonAssocs const& assocs2, TMuons const& /*tracks2*/) + void runEmuSameEventPairing(TEvents const& events, o2::framework::Preslice& preslice1, TTrackAssocs const& assocs1, TTracks const& /*tracks1*/, o2::framework::Preslice& preslice2, TMuonAssocs const& assocs2, TMuons const& /*tracks2*/) { if (events.size() > 0) { if (fCurrentRun != events.begin().runNumber()) { @@ -2810,7 +2816,7 @@ struct AnalysisSameEventPairing { } // Custom combination policy - for (auto const& [a1, a2] : o2::soa::combinations(soa::CombinationsFullIndexPolicy(groupedAssocs1, groupedAssocs2))) { + for (auto const& [a1, a2] : o2::soa::combinations(o2::soa::CombinationsFullIndexPolicy(groupedAssocs1, groupedAssocs2))) { if (!(a1.isBarrelSelected_raw() & a1.isBarrelSelectedPrefilter_raw() & fTrackFilterMask)) { continue; } @@ -2966,8 +2972,8 @@ struct AnalysisSameEventPairing { } template - void runEmuSameSideMixing(TEvents& events, Preslice& preslice1, TTrackAssocs const& assocs1, TTracks const& tracks1, - Preslice& preslice2, TMuonAssocs const& assocs2, TMuons const& tracks2) + void runEmuSameSideMixing(TEvents& events, o2::framework::Preslice& preslice1, TTrackAssocs const& assocs1, TTracks const& tracks1, + o2::framework::Preslice& preslice2, TMuonAssocs const& assocs2, TMuons const& tracks2) { events.bindExternalIndices(&assocs1); events.bindExternalIndices(&assocs2); @@ -2993,8 +2999,8 @@ struct AnalysisSameEventPairing { } void processAllSkimmed(MyEventsVtxCovSelected const& events, - soa::Join const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, - soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) + o2::soa::Join const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, + o2::soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) { runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks); runSameEventPairing(events, muonAssocsPerCollision, muonAssocs, muons); @@ -3002,120 +3008,120 @@ struct AnalysisSameEventPairing { } void processBarrelOnlySkimmed(MyEventsVtxCovSelected const& events, - soa::Join const& barrelAssocs, + o2::soa::Join const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks) { runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks); } void processBarrelOnlySkimmedFlow(MyEventsVtxCovSelectedQvector const& events, - soa::Join const& barrelAssocs, + o2::soa::Join const& barrelAssocs, MyBarrelTracksWithAmbiguities const& barrelTracks) { runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks); } void processBarrelOnlySkimmedNoCov(MyEventsSelected const& events, - soa::Join const& barrelAssocs, + o2::soa::Join const& barrelAssocs, MyBarrelTracksWithAmbiguities const& barrelTracks) { runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks); } void processBarrelOnlySkimmedNoCovWithMultExtra(MyEventsMultExtraSelected const& events, - soa::Join const& barrelAssocs, + o2::soa::Join const& barrelAssocs, MyBarrelTracksWithAmbiguities const& barrelTracks) { runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks); } void processBarrelOnlyWithCollSkimmed(MyEventsVtxCovSelectedInfo const& events, - soa::Join const& barrelAssocs, + o2::soa::Join const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguitiesWithColl const& barrelTracks) { runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks); } void processBarrelOnlyWithQvectorCentrSkimmedNoCov(MyEventsQvectorCentrSelected const& events, - soa::Join const& barrelAssocs, + o2::soa::Join const& barrelAssocs, MyBarrelTracksWithAmbiguities const& barrelTracks) { runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks); } void processBarrelOnlyWithQvectorCentrSkimmed(MyEventsQvectorCentrSelected const& events, - soa::Join const& barrelAssocs, + o2::soa::Join const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks) { runSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks); } void processMuonOnlySkimmed(MyEventsVtxCovSelected const& events, - soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) + o2::soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) { runSameEventPairing(events, muonAssocsPerCollision, muonAssocs, muons); } void processMuonOnlySkimmedMultExtra(MyEventsVtxCovSelectedMultExtra const& events, - soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) + o2::soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) { runSameEventPairing(events, muonAssocsPerCollision, muonAssocs, muons); } void processMuonOnlySkimmedFlow(MyEventsQvectorCentrSelected const& events, - soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) + o2::soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) { runSameEventPairing(events, muonAssocsPerCollision, muonAssocs, muons); } void processElectronMuonSkimmed(MyEventsVtxCovSelected const& events, - soa::Join const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, - soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) + o2::soa::Join const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks, + o2::soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) { runEmuSameEventPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, muonAssocsPerCollision, muonAssocs, muons); } - void processMixingAllSkimmed(soa::Filtered& events, // o2-linter: disable=const-ref-in-process - soa::Join const& trackAssocs, MyBarrelTracksWithCov const& tracks, - soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) + void processMixingAllSkimmed(o2::soa::Filtered& events, // o2-linter: disable=const-ref-in-process + o2::soa::Join const& trackAssocs, MyBarrelTracksWithCov const& tracks, + o2::soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) { runSameSideMixing(events, trackAssocs, tracks, trackAssocsPerCollision); runSameSideMixing(events, muonAssocs, muons, muonAssocsPerCollision); } - void processMixingBarrelSkimmed(soa::Filtered& events, // o2-linter: disable=const-ref-in-process - soa::Join const& trackAssocs, aod::ReducedTracks const& tracks) + void processMixingBarrelSkimmed(o2::soa::Filtered& events, // o2-linter: disable=const-ref-in-process + o2::soa::Join const& trackAssocs, o2::aod::ReducedTracks const& tracks) { runSameSideMixing(events, trackAssocs, tracks, trackAssocsPerCollision); } - void processMixingBarrelSkimmedFlow(soa::Filtered& events, // o2-linter: disable=const-ref-in-process - soa::Join const& trackAssocs, aod::ReducedTracks const& tracks) + void processMixingBarrelSkimmedFlow(o2::soa::Filtered& events, // o2-linter: disable=const-ref-in-process + o2::soa::Join const& trackAssocs, o2::aod::ReducedTracks const& tracks) { runSameSideMixing(events, trackAssocs, tracks, trackAssocsPerCollision); } - void processMixingBarrelWithQvectorCentrSkimmedNoCov(soa::Filtered& events, // o2-linter: disable=const-ref-in-process - soa::Join const& trackAssocs, MyBarrelTracksWithAmbiguities const& tracks) + void processMixingBarrelWithQvectorCentrSkimmedNoCov(o2::soa::Filtered& events, // o2-linter: disable=const-ref-in-process + o2::soa::Join const& trackAssocs, MyBarrelTracksWithAmbiguities const& tracks) { runSameSideMixing(events, trackAssocs, tracks, trackAssocsPerCollision); } - void processMixingMuonSkimmed(soa::Filtered& events, // o2-linter: disable=const-ref-in-process - soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) + void processMixingMuonSkimmed(o2::soa::Filtered& events, // o2-linter: disable=const-ref-in-process + o2::soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) { runSameSideMixing(events, muonAssocs, muons, muonAssocsPerCollision); } - void processMixingMuonSkimmedFlow(soa::Filtered& events, // o2-linter: disable=const-ref-in-process - soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) + void processMixingMuonSkimmedFlow(o2::soa::Filtered& events, // o2-linter: disable=const-ref-in-process + o2::soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) { runSameSideMixing(events, muonAssocs, muons, muonAssocsPerCollision); } - void processMixingElectronMuonSkimmed(soa::Filtered& events, // o2-linter: disable=const-ref-in-process - soa::Join const& barrelAssocs, aod::ReducedTracks const& barrelTracks, - soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) + void processMixingElectronMuonSkimmed(o2::soa::Filtered& events, // o2-linter: disable=const-ref-in-process + o2::soa::Join const& barrelAssocs, o2::aod::ReducedTracks const& barrelTracks, + o2::soa::Join const& muonAssocs, MyMuonTracksWithCovWithAmbiguities const& muons) { runEmuSameSideMixing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, muonAssocsPerCollision, muonAssocs, muons); } @@ -3150,53 +3156,53 @@ struct AnalysisSameEventPairing { // Run pairing for resonance with legs fulfilling separate cuts (asymmetric decay channel) struct AnalysisAsymmetricPairing { - Produces ditrackList; - Produces ditrackExtraList; + o2::framework::Produces ditrackList; + o2::framework::Produces ditrackExtraList; o2::base::MatLayerCylSet* fLUT = nullptr; int fCurrentRun = -1; // needed to detect if the run changed and trigger update of calibrations etc. // Output objects - OutputObj fOutputList{"output"}; + o2::framework::OutputObj fOutputList{"output"}; // Configurables - Configurable fConfigLegCuts{"cfgLegCuts", "", ":[:],[:[:],...]"}; - Configurable fConfigLegAFilterMask{"cfgLegAFilterMask", 0, "Filter mask corresponding to cuts in track-selection"}; - Configurable fConfigLegBFilterMask{"cfgLegBFilterMask", 0, "Filter mask corresponding to cuts in track-selection"}; - Configurable fConfigLegCFilterMask{"cfgLegCFilterMask", 0, "Filter mask corresponding to cuts in track-selection"}; - Configurable fConfigCommonTrackCuts{"cfgCommonTrackCuts", "", "Comma separated list of cuts to be applied to all legs"}; - Configurable fConfigPairCuts{"cfgPairCuts", "", "Comma separated list of pair cuts"}; - Configurable fConfigPairCutsJSON{"cfgPairCutsJSON", "", "Additional list of pair cuts in JSON format"}; - Configurable fConfigRemoveCollSplittingCandidates{"cfgRemoveCollSplittingCandidates", false, "If true, remove collision splitting candidates as determined by the event selection task upstream"}; - Configurable fConfigSkipAmbiguousIdCombinations{"cfgSkipAmbiguousIdCombinations", true, "Choose whether to skip pairs/triples which pass a stricter combination of cuts, e.g. KKPi triplets for D+ -> KPiPi"}; - - Configurable fConfigHistogramSubgroups{"cfgAsymmetricPairingHistogramsSubgroups", "barrel,vertexing", "Comma separated list of asymmetric-pairing histogram subgroups"}; - Configurable fConfigSameSignHistograms{"cfgSameSignHistograms", false, "Include same sign pair histograms for 2-prong decays"}; - Configurable fConfigAmbiguousHistograms{"cfgAmbiguousHistograms", false, "Include separate histograms for pairs/triplets with ambiguous tracks"}; - Configurable fConfigReflectedHistograms{"cfgReflectedHistograms", false, "Include separate histograms for pairs which are reflections of previously counted pairs"}; - Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; - - Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable fConfigGRPMagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable fConfigUseRemoteField{"cfgUseRemoteField", false, "Choose whether to fetch the magnetic field from ccdb or set it manually"}; - Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; - - Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; - Configurable fConfigUseAbsDCA{"cfgUseAbsDCA", false, "Use absolute DCA minimization instead of chi^2 minimization in secondary vertexing"}; - Configurable fConfigPropToPCA{"cfgPropToPCA", false, "Propagate tracks to secondary vertex"}; - Configurable fConfigLutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; - Configurable fConfigFetchInteractionRate{"cfgFetchInteractionRate", false, "Fetch event-wise interaction rate from the CCDB"}; - Configurable fConfigIRSource{"cfgIRSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; - - Service fCCDB{}; - ctpRateFetcher rateFetcher; + o2::framework::Configurable fConfigLegCuts{"cfgLegCuts", "", ":[:],[:[:],...]"}; + o2::framework::Configurable fConfigLegAFilterMask{"cfgLegAFilterMask", 0, "o2::framework::expressions::Filter mask corresponding to cuts in track-selection"}; + o2::framework::Configurable fConfigLegBFilterMask{"cfgLegBFilterMask", 0, "o2::framework::expressions::Filter mask corresponding to cuts in track-selection"}; + o2::framework::Configurable fConfigLegCFilterMask{"cfgLegCFilterMask", 0, "o2::framework::expressions::Filter mask corresponding to cuts in track-selection"}; + o2::framework::Configurable fConfigCommonTrackCuts{"cfgCommonTrackCuts", "", "Comma separated list of cuts to be applied to all legs"}; + o2::framework::Configurable fConfigPairCuts{"cfgPairCuts", "", "Comma separated list of pair cuts"}; + o2::framework::Configurable fConfigPairCutsJSON{"cfgPairCutsJSON", "", "Additional list of pair cuts in JSON format"}; + o2::framework::Configurable fConfigRemoveCollSplittingCandidates{"cfgRemoveCollSplittingCandidates", false, "If true, remove collision splitting candidates as determined by the event selection task upstream"}; + o2::framework::Configurable fConfigSkipAmbiguousIdCombinations{"cfgSkipAmbiguousIdCombinations", true, "Choose whether to skip pairs/triples which pass a stricter combination of cuts, e.g. KKPi triplets for D+ -> KPiPi"}; + + o2::framework::Configurable fConfigHistogramSubgroups{"cfgAsymmetricPairingHistogramsSubgroups", "barrel,vertexing", "Comma separated list of asymmetric-pairing histogram subgroups"}; + o2::framework::Configurable fConfigSameSignHistograms{"cfgSameSignHistograms", false, "Include same sign pair histograms for 2-prong decays"}; + o2::framework::Configurable fConfigAmbiguousHistograms{"cfgAmbiguousHistograms", false, "Include separate histograms for pairs/triplets with ambiguous tracks"}; + o2::framework::Configurable fConfigReflectedHistograms{"cfgReflectedHistograms", false, "Include separate histograms for pairs which are reflections of previously counted pairs"}; + o2::framework::Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + + o2::framework::Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + o2::framework::Configurable fConfigGRPMagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + o2::framework::Configurable fConfigUseRemoteField{"cfgUseRemoteField", false, "Choose whether to fetch the magnetic field from ccdb or set it manually"}; + o2::framework::Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; + + o2::framework::Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; + o2::framework::Configurable fConfigUseAbsDCA{"cfgUseAbsDCA", false, "Use absolute DCA minimization instead of chi^2 minimization in secondary vertexing"}; + o2::framework::Configurable fConfigPropToPCA{"cfgPropToPCA", false, "Propagate tracks to secondary vertex"}; + o2::framework::Configurable fConfigLutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + o2::framework::Configurable fConfigFetchInteractionRate{"cfgFetchInteractionRate", false, "Fetch event-wise interaction rate from the CCDB"}; + o2::framework::Configurable fConfigIRSource{"cfgIRSource", "ZNC hadronic", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; + + o2::framework::Service fCCDB{}; + o2::ctpRateFetcher rateFetcher; HistogramManager* fHistMan = nullptr; std::vector fPairCuts; int fNPairHistPrefixes = 0; - // Filter masks to find legs in BarrelTrackCuts table + // o2::framework::expressions::Filter masks to find legs in BarrelTrackCuts table uint32_t fLegAFilterMask = 0; uint32_t fLegBFilterMask = 0; uint32_t fLegCFilterMask = 0; @@ -3204,7 +3210,7 @@ struct AnalysisAsymmetricPairing { std::map fConstructedLegAFilterMasksMap; std::map fConstructedLegBFilterMasksMap; std::map fConstructedLegCFilterMasksMap; - // Filter map for common track cuts + // o2::framework::expressions::Filter map for common track cuts uint32_t fCommonTrackCutMask = 0; // Map tracking which common track cut the track cuts correspond to std::map fCommonTrackCutFilterMasks; @@ -3217,12 +3223,12 @@ struct AnalysisAsymmetricPairing { std::vector fPairCutNames; std::vector fCommonCutNames; - Preslice> trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; + o2::framework::Preslice> trackAssocsPerCollision = o2::aod::reducedtrack_association::reducedeventId; // Partitions for triplets and asymmetric pairs - Partition> legACandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegAFilterMask) > static_cast(0); - Partition> legBCandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegBFilterMask) > static_cast(0); - Partition> legCCandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegCFilterMask) > static_cast(0); + o2::framework::Partition> legACandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegAFilterMask) > static_cast(0); + o2::framework::Partition> legBCandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegBFilterMask) > static_cast(0); + o2::framework::Partition> legCCandidateAssocs = (o2::aod::dqanalysisflags::isBarrelSelected & fConfigLegCFilterMask) > static_cast(0); // Map to track how many times a pair of tracks has been encountered std::map, int8_t> fPairCount; @@ -3247,13 +3253,13 @@ struct AnalysisAsymmetricPairing { if (!cutNamesStr.IsNull()) { std::unique_ptr objArray(cutNamesStr.Tokenize(",")); for (int icut = 0; icut < objArray->GetEntries(); ++icut) { - fPairCuts.push_back(dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); + fPairCuts.push_back(o2::aod::dqcuts::GetCompositeCut(objArray->At(icut)->GetName())); } } // Extra pair cuts via JSON TString addPairCutsStr = fConfigPairCutsJSON.value; if (addPairCutsStr != "") { - std::vector addPairCuts = dqcuts::GetCutsFromJSON(addPairCutsStr.Data()); + std::vector addPairCuts = o2::aod::dqcuts::GetCutsFromJSON(addPairCutsStr.Data()); for (auto const& t : addPairCuts) { fPairCuts.push_back(static_cast(t)); cutNamesStr += Form(",%s", t->GetName()); @@ -3265,14 +3271,14 @@ struct AnalysisAsymmetricPairing { fPairCutNames.push_back(objArrayPairCuts->At(j)->GetName()); } // Get the barrel track selection cuts - string tempCuts; - getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", tempCuts, false); + std::string tempCuts; + o2::common::core::getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", tempCuts, false); TString tempCutsStr = tempCuts; // check also the cuts added via JSON and add them to the string of cuts - getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", tempCuts, false); + o2::common::core::getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", tempCuts, false); TString addTrackCutsStr = tempCuts; if (addTrackCutsStr != "") { - std::vector addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); + std::vector addTrackCuts = o2::aod::dqcuts::GetCutsFromJSON(addTrackCutsStr.Data()); for (auto const& t : addTrackCuts) { tempCutsStr += Form(",%s", t->GetName()); } @@ -3454,8 +3460,8 @@ struct AnalysisAsymmetricPairing { fLUT = o2::base::MatLayerCylSet::rectifyPtrFromFile(fCCDB->get(fConfigLutPath)); VarManager::SetupMatLUTFwdDCAFitter(fLUT); - dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON - VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + o2::aod::dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill fOutputList.setObject(fHistMan->GetMainHistogramList()); } @@ -3501,7 +3507,7 @@ struct AnalysisAsymmetricPairing { // Template function to run same event pairing with asymmetric pairs (e.g. kaon-pion) template - void runAsymmetricPairing(TEvents const& events, Preslice& preslice, TTrackAssocs const& /*assocs*/, TTracks const& /*tracks*/) + void runAsymmetricPairing(TEvents const& events, o2::framework::Preslice& preslice, TTrackAssocs const& /*assocs*/, TTracks const& /*tracks*/) { fPairCount.clear(); @@ -3558,7 +3564,7 @@ struct AnalysisAsymmetricPairing { continue; } - for (auto const& [a1, a2] : combinations(soa::CombinationsFullIndexPolicy(groupedLegAAssocs, groupedLegBAssocs))) { + for (auto const& [a1, a2] : combinations(o2::soa::CombinationsFullIndexPolicy(groupedLegAAssocs, groupedLegBAssocs))) { auto twoTrackFilter = static_cast(0); uint32_t twoTrackCommonFilter = static_cast(0); @@ -3707,7 +3713,7 @@ struct AnalysisAsymmetricPairing { // Template function to run same event triplets (e.g. D+->K-pi+pi+) template - void runThreeProng(TEvents const& events, Preslice& preslice, TTrackAssocs const& /*assocs*/, TTracks const& tracks, VarManager::PairCandidateType tripletType) + void runThreeProng(TEvents const& events, o2::framework::Preslice& preslice, TTrackAssocs const& /*assocs*/, TTracks const& tracks, VarManager::PairCandidateType tripletType) { if (events.size() > 0) { // Additional protection to avoid crashing of events.begin().runNumber() if (fCurrentRun != events.begin().runNumber()) { @@ -3742,7 +3748,7 @@ struct AnalysisAsymmetricPairing { // Based on triplet type, make suitable combinations of the partitions if (tripletType == VarManager::kTripleCandidateToPKPi) { - for (auto const& [a1, a2, a3] : combinations(soa::CombinationsFullIndexPolicy(groupedLegAAssocs, groupedLegBAssocs, groupedLegCAssocs))) { + for (auto const& [a1, a2, a3] : combinations(o2::soa::CombinationsFullIndexPolicy(groupedLegAAssocs, groupedLegBAssocs, groupedLegCAssocs))) { readTriplet(a1, a2, a3, tracks, event, tripletType); } } else if (tripletType == VarManager::kTripleCandidateToKPiPi) { @@ -3859,35 +3865,35 @@ struct AnalysisAsymmetricPairing { } void processKaonPionSkimmed(MyEventsVtxCovZdcFitSelected const& events, - soa::Join const& barrelAssocs, + o2::soa::Join const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks) { runAsymmetricPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks); } void processKaonPionSkimmedMultExtra(MyEventsVtxCovZdcFitSelectedMultExtra const& events, - soa::Join const& barrelAssocs, + o2::soa::Join const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks) { runAsymmetricPairing(events, trackAssocsPerCollision, barrelAssocs, barrelTracks); } void processKaonPionPionSkimmed(MyEventsVtxCovZdcFitSelected const& events, - soa::Join const& barrelAssocs, + o2::soa::Join const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks) { runThreeProng(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, VarManager::kTripleCandidateToKPiPi); } void processKaonPionPionSkimmedMultExtra(MyEventsVtxCovZdcFitSelectedMultExtra const& events, - soa::Join const& barrelAssocs, + o2::soa::Join const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks) { runThreeProng(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, VarManager::kTripleCandidateToKPiPi); } void processProtonKaonPionSkimmed(MyEventsVtxCovZdcFitSelected const& events, - soa::Join const& barrelAssocs, + o2::soa::Join const& barrelAssocs, MyBarrelTracksWithCovWithAmbiguities const& barrelTracks) { runThreeProng(events, trackAssocsPerCollision, barrelAssocs, barrelTracks, VarManager::kTripleCandidateToPKPi); @@ -3910,40 +3916,40 @@ struct AnalysisAsymmetricPairing { // Dileptons produced with all the selection cuts specified in the same-event pairing task are combined with the // tracks passing the fConfigTrackCut cut. The dileptons cuts from the same-event pairing task are auto-detected struct AnalysisDileptonTrack { - Produces BmesonsTable; - Produces DileptonTrackTable; - OutputObj fOutputList{"output"}; - - Configurable fConfigTrackCuts{"cfgTrackCuts", "kaonPID", "Comma separated list of cuts for the track to be correlated with the dileptons"}; - Configurable fConfigDileptonLowMass{"cfgDileptonLowMass", 2.8, "Low mass cut for the dileptons used in analysis"}; - Configurable fConfigDileptonHighMass{"cfgDileptonHighMass", 3.2, "High mass cut for the dileptons used in analysis"}; - Configurable fConfigDileptonLowpTCut{"cfgDileptonLowpTCut", 0.0, "Low pT cut for dileptons used in the triplet vertexing"}; - Configurable fConfigDileptonHighpTCut{"cfgDileptonHighpTCut", 1E5, "High pT cut for dileptons used in the triplet vertexing"}; - Configurable fConfigDileptonRapCutAbs{"cfgDileptonRapCutAbs", 1.0, "Rap cut for dileptons used in the triplet vertexing"}; - Configurable fConfigDileptonLxyCut{"cfgDileptonLxyCut", 0.0, "Lxy cut for dileptons used in the triplet vertexing"}; - Configurable fConfigDileptonTauxyCut{"cfgDileptonTauxyCut", -10000, "Tauxy cut for dileptons used to select the non-prompt Jpsi"}; - Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; - - Configurable fConfigHistogramSubgroups{"cfgDileptonTrackHistogramsSubgroups", "invmass,vertexing", "Comma separated list of dilepton-track histogram subgroups"}; - Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; - Configurable fConfigMixingDepth{"cfgMixingDepth", 5, "Event mixing pool depth"}; - - Configurable fConfigUseRemoteField{"cfgUseRemoteField", false, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; - Configurable fConfigGRPmagPath{"cfgGrpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; - - Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable fConfigNoLaterThan{"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 fConfigGeoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - Configurable fConfigUseRapcut{"cfgUseMCRapcut", false, "Use Rap cut for dileptons used in the triplet vertexing"}; - Configurable fConfigEnergycorrelator{"cfgEnergycorrelator", false, "Add some hist for energy correlator study"}; - Configurable fConfigApplyMassEC{"cfgApplyMassEC", false, "Apply fit mass for sideband for the energy correlator study"}; - Configurable> fConfigFitmassEC{"cfgTFitmassEC", std::vector{-0.541438, 2.8, 3.2}, "parameter from the fit fuction and fit range"}; - Configurable> fConfigTransRange{"cfgTransRange", std::vector{0.333333, 0.666667}, "Transverse region for the energy correlstor analysis"}; - - Configurable fConfigApplyEfficiency{"cfgApplyEfficiency", false, "If true, apply efficiency correction for the energy correlator study"}; - Configurable fConfigApplyEfficiencyME{"cfgApplyEfficiencyME", false, "If true, apply efficiency correction for the energy correlator study"}; - Configurable fConfigAccCCDBPath{"AccCCDBPath", "Users/y/yalin/pptest/test2", "Path of the efficiency corrections"}; + o2::framework::Produces BmesonsTable; + o2::framework::Produces DileptonTrackTable; + o2::framework::OutputObj fOutputList{"output"}; + + o2::framework::Configurable fConfigTrackCuts{"cfgTrackCuts", "kaonPID", "Comma separated list of cuts for the track to be correlated with the dileptons"}; + o2::framework::Configurable fConfigDileptonLowMass{"cfgDileptonLowMass", 2.8, "Low mass cut for the dileptons used in analysis"}; + o2::framework::Configurable fConfigDileptonHighMass{"cfgDileptonHighMass", 3.2, "High mass cut for the dileptons used in analysis"}; + o2::framework::Configurable fConfigDileptonLowpTCut{"cfgDileptonLowpTCut", 0.0, "Low pT cut for dileptons used in the triplet vertexing"}; + o2::framework::Configurable fConfigDileptonHighpTCut{"cfgDileptonHighpTCut", 1E5, "High pT cut for dileptons used in the triplet vertexing"}; + o2::framework::Configurable fConfigDileptonRapCutAbs{"cfgDileptonRapCutAbs", 1.0, "Rap cut for dileptons used in the triplet vertexing"}; + o2::framework::Configurable fConfigDileptonLxyCut{"cfgDileptonLxyCut", 0.0, "Lxy cut for dileptons used in the triplet vertexing"}; + o2::framework::Configurable fConfigDileptonTauxyCut{"cfgDileptonTauxyCut", -10000, "Tauxy cut for dileptons used to select the non-prompt Jpsi"}; + o2::framework::Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; + + o2::framework::Configurable fConfigHistogramSubgroups{"cfgDileptonTrackHistogramsSubgroups", "invmass,vertexing", "Comma separated list of dilepton-track histogram subgroups"}; + o2::framework::Configurable fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"}; + o2::framework::Configurable fConfigMixingDepth{"cfgMixingDepth", 5, "Event mixing pool depth"}; + + o2::framework::Configurable fConfigUseRemoteField{"cfgUseRemoteField", false, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; + o2::framework::Configurable fConfigGRPmagPath{"cfgGrpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + o2::framework::Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; + + o2::framework::Configurable fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + o2::framework::Configurable fConfigNoLaterThan{"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"}; + o2::framework::Configurable fConfigGeoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + o2::framework::Configurable fConfigUseRapcut{"cfgUseMCRapcut", false, "Use Rap cut for dileptons used in the triplet vertexing"}; + o2::framework::Configurable fConfigEnergycorrelator{"cfgEnergycorrelator", false, "Add some hist for energy correlator study"}; + o2::framework::Configurable fConfigApplyMassEC{"cfgApplyMassEC", false, "Apply fit mass for sideband for the energy correlator study"}; + o2::framework::Configurable> fConfigFitmassEC{"cfgTFitmassEC", std::vector{-0.541438, 2.8, 3.2}, "parameter from the fit fuction and fit range"}; + o2::framework::Configurable> fConfigTransRange{"cfgTransRange", std::vector{0.333333, 0.666667}, "Transverse region for the energy correlstor analysis"}; + + o2::framework::Configurable fConfigApplyEfficiency{"cfgApplyEfficiency", false, "If true, apply efficiency correction for the energy correlator study"}; + o2::framework::Configurable fConfigApplyEfficiencyME{"cfgApplyEfficiencyME", false, "If true, apply efficiency correction for the energy correlator study"}; + o2::framework::Configurable fConfigAccCCDBPath{"AccCCDBPath", "Users/y/yalin/pptest/test2", "Path of the efficiency corrections"}; int fCurrentRun = -1; // needed to detect if the run changed and trigger update of calibrations etc. int fNCuts = 0; // number of dilepton leg cuts @@ -3959,13 +3965,13 @@ struct AnalysisDileptonTrack { std::vector fPairCutNames; std::vector fCommonPairCutNames; - Service fCCDB{}; + o2::framework::Service fCCDB{}; // TODO: The filter expressions seem to always use the default value of configurables, not the values from the actual configuration file - Filter eventFilter = aod::dqanalysisflags::isEventSelected > static_cast(0); - Filter dileptonFilter = aod::reducedpair::pt > fConfigDileptonLowpTCut&& aod::reducedpair::pt fConfigDileptonLowMass&& aod::reducedpair::mass fConfigDileptonLxyCut&& aod::reducedpair::tauxy > fConfigDileptonTauxyCut; - Filter filterBarrel = aod::dqanalysisflags::isBarrelSelected > static_cast(0); - Filter filterMuon = aod::dqanalysisflags::isMuonSelected > static_cast(0); + o2::framework::expressions::Filter eventFilter = o2::aod::dqanalysisflags::isEventSelected > static_cast(0); + o2::framework::expressions::Filter dileptonFilter = o2::aod::reducedpair::pt > fConfigDileptonLowpTCut&& o2::aod::reducedpair::pt fConfigDileptonLowMass&& o2::aod::reducedpair::mass fConfigDileptonLxyCut&& o2::aod::reducedpair::tauxy > fConfigDileptonTauxyCut; + o2::framework::expressions::Filter filterBarrel = o2::aod::dqanalysisflags::isBarrelSelected > static_cast(0); + o2::framework::expressions::Filter filterMuon = o2::aod::dqanalysisflags::isMuonSelected > static_cast(0); constexpr static uint32_t fgDileptonFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::Pair; // fill map @@ -3974,7 +3980,7 @@ struct AnalysisDileptonTrack { float* fValuesHadron = nullptr; HistogramManager* fHistMan = nullptr; - NoBinningPolicy fHashBin; + o2::framework::NoBinningPolicy fHashBin; TF1* fMassBkg = nullptr; @@ -4015,11 +4021,11 @@ struct AnalysisDileptonTrack { // Get the list of single track and muon cuts computed in the dedicated tasks upstream // We need this to know the order in which they were computed, and also to make sure that in this task we do not ask // for cuts which were not computed (in which case this will trigger a fatal) - string cfgTrackSelection_TrackCuts; + std::string cfgTrackSelection_TrackCuts; if (isBarrel || isBarrelAsymmetric) { - getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", cfgTrackSelection_TrackCuts, false); + o2::common::core::getTaskOptionValue(context, "analysis-track-selection", "cfgTrackCuts", cfgTrackSelection_TrackCuts, false); } else { - getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCuts", cfgTrackSelection_TrackCuts, false); + o2::common::core::getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCuts", cfgTrackSelection_TrackCuts, false); } TObjArray* cfgTrackSelection_objArrayTrackCuts = nullptr; @@ -4028,15 +4034,15 @@ struct AnalysisDileptonTrack { } // get also the list of cuts specified via the JSON parameters if (isBarrel || isBarrelAsymmetric) { - getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", cfgTrackSelection_TrackCuts, false); + o2::common::core::getTaskOptionValue(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", cfgTrackSelection_TrackCuts, false); } else { - getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCutsJSON", cfgTrackSelection_TrackCuts, false); + o2::common::core::getTaskOptionValue(context, "analysis-muon-selection", "cfgMuonCutsJSON", cfgTrackSelection_TrackCuts, false); } if (!cfgTrackSelection_TrackCuts.empty()) { if (cfgTrackSelection_objArrayTrackCuts == nullptr) { cfgTrackSelection_objArrayTrackCuts = new TObjArray(); } - std::vector addTrackCuts = dqcuts::GetCutsFromJSON(cfgTrackSelection_TrackCuts.data()); + std::vector addTrackCuts = o2::aod::dqcuts::GetCutsFromJSON(cfgTrackSelection_TrackCuts.data()); for (auto const& t : addTrackCuts) { auto tempObjStr = new TObjString(t->GetName()); cfgTrackSelection_objArrayTrackCuts->Add(tempObjStr); @@ -4073,20 +4079,20 @@ struct AnalysisDileptonTrack { // NOTE: The track/muon cuts in analysis-same-event-pairing are used to select electrons/muons to build dielectrons/dimuons // NOTE: The cfgPairCuts in analysis-same-event-pairing are used to apply an additional selection on top of the already produced dileptons // but this is only used for histograms, not for the produced dilepton tables - string cfgPairing_TrackCuts; - string cfgPairing_PairCuts; - string cfgPairing_PairCutsJSON; - string cfgPairing_CommonTrackCuts; + std::string cfgPairing_TrackCuts; + std::string cfgPairing_PairCuts; + std::string cfgPairing_PairCutsJSON; + std::string cfgPairing_CommonTrackCuts; if (isBarrel) { - getTaskOptionValue(context, "analysis-same-event-pairing", "cfgTrackCuts", cfgPairing_TrackCuts, false); - getTaskOptionValue(context, "analysis-same-event-pairing", "cfgPairCuts", cfgPairing_PairCuts, false); + o2::common::core::getTaskOptionValue(context, "analysis-same-event-pairing", "cfgTrackCuts", cfgPairing_TrackCuts, false); + o2::common::core::getTaskOptionValue(context, "analysis-same-event-pairing", "cfgPairCuts", cfgPairing_PairCuts, false); } else if (isMuon) { - getTaskOptionValue(context, "analysis-same-event-pairing", "cfgMuonCuts", cfgPairing_TrackCuts, false); - getTaskOptionValue(context, "analysis-same-event-pairing", "cfgPairCuts", cfgPairing_PairCuts, false); + o2::common::core::getTaskOptionValue(context, "analysis-same-event-pairing", "cfgMuonCuts", cfgPairing_TrackCuts, false); + o2::common::core::getTaskOptionValue(context, "analysis-same-event-pairing", "cfgPairCuts", cfgPairing_PairCuts, false); } else if (isBarrelAsymmetric) { - getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgLegCuts", cfgPairing_TrackCuts, false); - getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgPairCuts", cfgPairing_PairCuts, false); - getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgCommonTrackCuts", cfgPairing_CommonTrackCuts, false); + o2::common::core::getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgLegCuts", cfgPairing_TrackCuts, false); + o2::common::core::getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgPairCuts", cfgPairing_PairCuts, false); + o2::common::core::getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgCommonTrackCuts", cfgPairing_CommonTrackCuts, false); } if (cfgPairing_TrackCuts.empty()) { LOG(fatal) << "There are no dilepton cuts specified in the upstream in the same-event-pairing or asymmetric-pairing"; @@ -4108,10 +4114,10 @@ struct AnalysisDileptonTrack { } // end if (common cuts) // Get also the pair cuts specified via the JSON parameters if (isBarrelAsymmetric) { - getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgPairCutsJSON", cfgPairing_PairCutsJSON, false); + o2::common::core::getTaskOptionValue(context, "analysis-asymmetric-pairing", "cfgPairCutsJSON", cfgPairing_PairCutsJSON, false); TString addPairCutsStr = cfgPairing_PairCutsJSON; if (addPairCutsStr != "") { - std::vector addPairCuts = dqcuts::GetCutsFromJSON(addPairCutsStr.Data()); + std::vector addPairCuts = o2::aod::dqcuts::GetCutsFromJSON(addPairCutsStr.Data()); for (auto const& t : addPairCuts) { cfgPairing_PairCuts += Form(",%s", t->GetName()); } @@ -4195,7 +4201,7 @@ struct AnalysisDileptonTrack { } // end loop over pair leg track cuts } - dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON + o2::aod::dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON VarManager::SetUseVars(fHistMan->GetUsedVars()); fOutputList.setObject(fHistMan->GetMainHistogramList()); @@ -4365,7 +4371,7 @@ struct AnalysisDileptonTrack { Effweight_rec = Effweight_rec * Effdilepton * Effhadron * Masswindow; } std::vector fTransRange = fConfigTransRange; - VarManager::FillEnergyCorrelatorTriple(lepton1, lepton2, track, fValuesHadron, fTransRange[0], fTransRange[1], fConfigApplyMassEC, fMassBkg->GetRandom(), 1. / Effweight_rec); + VarManager::FillEnergyCorrelatorTriple(event, lepton1, lepton2, track, fValuesHadron, fTransRange[0], fTransRange[1], fConfigApplyMassEC, fMassBkg->GetRandom(), 1. / Effweight_rec); // table to be written out for ML analysis BmesonsTable(event.runNumber(), event.globalIndex(), event.timestamp(), fValuesHadron[VarManager::kPairMass], dilepton.mass(), fValuesHadron[VarManager::kDeltaMass], fValuesHadron[VarManager::kPairPt], fValuesHadron[VarManager::kPairEta], fValuesHadron[VarManager::kPairPhi], fValuesHadron[VarManager::kPairRap], @@ -4456,13 +4462,13 @@ struct AnalysisDileptonTrack { } } - Preslice trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; - Preslice dielectronsPerCollision = aod::reducedpair::reducedeventId; - Preslice ditracksPerCollision = aod::reducedpair::reducedeventId; + o2::framework::Preslice trackAssocsPerCollision = o2::aod::reducedtrack_association::reducedeventId; + o2::framework::Preslice dielectronsPerCollision = o2::aod::reducedpair::reducedeventId; + o2::framework::Preslice ditracksPerCollision = o2::aod::reducedpair::reducedeventId; - void processBarrelSkimmed(soa::Filtered const& events, - soa::Filtered> const& assocs, - MyBarrelTracksWithCov const& tracks, soa::Filtered const& dileptons) + void processBarrelSkimmed(o2::soa::Filtered const& events, + o2::soa::Filtered> const& assocs, + MyBarrelTracksWithCov const& tracks, o2::soa::Filtered const& dileptons) { // set up KF or DCAfitter if (events.size() == 0) { @@ -4482,9 +4488,9 @@ struct AnalysisDileptonTrack { } } - void processDstarToD0Pi(soa::Filtered const& events, - soa::Filtered> const& assocs, - MyBarrelTracksWithCov const& tracks, soa::Filtered const& ditracks) + void processDstarToD0Pi(o2::soa::Filtered const& events, + o2::soa::Filtered> const& assocs, + MyBarrelTracksWithCov const& tracks, o2::soa::Filtered const& ditracks) { // set up KF or DCAfitter if (events.size() == 0) { @@ -4501,12 +4507,12 @@ struct AnalysisDileptonTrack { } } - Preslice muonAssocsPerCollision = aod::reducedtrack_association::reducedeventId; - Preslice dimuonsPerCollision = aod::reducedpair::reducedeventId; + o2::framework::Preslice muonAssocsPerCollision = o2::aod::reducedtrack_association::reducedeventId; + o2::framework::Preslice dimuonsPerCollision = o2::aod::reducedpair::reducedeventId; - void processMuonSkimmed(soa::Filtered const& events, - soa::Filtered> const& assocs, - MyMuonTracksWithCov const& tracks, soa::Filtered const& dileptons) + void processMuonSkimmed(o2::soa::Filtered const& events, + o2::soa::Filtered> const& assocs, + MyMuonTracksWithCov const& tracks, o2::soa::Filtered const& dileptons) { // set up KF or DCAfitter if (events.size() == 0) { @@ -4523,9 +4529,9 @@ struct AnalysisDileptonTrack { } } - void processBarrelMixedEvent(soa::Filtered& events, // o2-linter: disable=const-ref-in-process - soa::Filtered> const& assocs, - MyBarrelTracksWithCov const& tracks, soa::Filtered const& dileptons) + void processBarrelMixedEvent(o2::soa::Filtered& events, // o2-linter: disable=const-ref-in-process + o2::soa::Filtered> const& assocs, + MyBarrelTracksWithCov const& tracks, o2::soa::Filtered const& dileptons) { if (events.size() == 0) { return; @@ -4604,7 +4610,7 @@ struct AnalysisDileptonTrack { } } std::vector fTransRange = fConfigTransRange; - VarManager::FillEnergyCorrelatorTriple(lepton1, lepton2, track, dqtablereader_helpers::varValues(), fTransRange[0], fTransRange[1], fConfigApplyMassEC, fMassBkg->GetRandom(), 1. / Effweight_rec); + VarManager::FillEnergyCorrelatorTriple(event1, lepton1, lepton2, track, dqtablereader_helpers::varValues(), fTransRange[0], fTransRange[1], fConfigApplyMassEC, fMassBkg->GetRandom(), 1. / Effweight_rec); // loop over dilepton leg cuts and track cuts and fill histograms separately for each combination for (int icut = 0; icut < fNCuts; icut++) { @@ -4625,9 +4631,9 @@ struct AnalysisDileptonTrack { } // end event loop } - void processMuonMixedEvent(soa::Filtered& events, // o2-linter: disable=const-ref-in-process - soa::Filtered> const& assocs, - MyMuonTracksWithCov const&, soa::Filtered const& dileptons) + void processMuonMixedEvent(o2::soa::Filtered& events, // o2-linter: disable=const-ref-in-process + o2::soa::Filtered> const& assocs, + MyMuonTracksWithCov const&, o2::soa::Filtered const& dileptons) { if (events.size() == 0) { return; @@ -4684,22 +4690,22 @@ struct AnalysisDileptonTrack { }; struct AnalysisDileptonTrackTrack { - OutputObj fOutputList{"output"}; + o2::framework::OutputObj fOutputList{"output"}; - Configurable fConfigTrackCut1{"cfgTrackCut1", "pionPIDCut1", "track1 cut"}; // used for select the tracks from SelectedTracks - Configurable fConfigTrackCut2{"cfgTrackCut2", "pionPIDCut2", "track2 cut"}; // used for select the tracks from SelectedTracks - Configurable fConfigDileptonCut{"cfgDiLeptonCut", "pairJpsi2", "Dilepton cut"}; - Configurable fConfigQuadrupletCuts{"cfgQuadrupletCuts", "pairX3872Cut1", "Comma separated list of Dilepton-Track-Track cut"}; - Configurable fConfigAddDileptonHistogram{"cfgAddDileptonHistogram", "barrel", "Comma separated list of histograms"}; - Configurable fConfigAddQuadrupletHistogram{"cfgAddQuadrupletHistogram", "xtojpsipipi", "Comma separated list of histograms"}; + o2::framework::Configurable fConfigTrackCut1{"cfgTrackCut1", "pionPIDCut1", "track1 cut"}; // used for select the tracks from SelectedTracks + o2::framework::Configurable fConfigTrackCut2{"cfgTrackCut2", "pionPIDCut2", "track2 cut"}; // used for select the tracks from SelectedTracks + o2::framework::Configurable fConfigDileptonCut{"cfgDiLeptonCut", "pairJpsi2", "Dilepton cut"}; + o2::framework::Configurable fConfigQuadrupletCuts{"cfgQuadrupletCuts", "pairX3872Cut1", "Comma separated list of Dilepton-Track-Track cut"}; + o2::framework::Configurable fConfigAddDileptonHistogram{"cfgAddDileptonHistogram", "barrel", "Comma separated list of histograms"}; + o2::framework::Configurable fConfigAddQuadrupletHistogram{"cfgAddQuadrupletHistogram", "xtojpsipipi", "Comma separated list of histograms"}; - Configurable fConfigSetupFourProngFitter{"cfgSetupFourProngFitter", false, "Use DCA for secondary vertex reconstruction (DCAFitter is used by default)"}; - Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; - Configurable fConfigUseRemoteField{"cfgUseRemoteField", false, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; - Configurable fConfigGRPmagPath{"cfgGrpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; + o2::framework::Configurable fConfigSetupFourProngFitter{"cfgSetupFourProngFitter", false, "Use DCA for secondary vertex reconstruction (DCAFitter is used by default)"}; + o2::framework::Configurable fConfigUseKFVertexing{"cfgUseKFVertexing", false, "Use KF Particle for secondary vertex reconstruction (DCAFitter is used by default)"}; + o2::framework::Configurable fConfigUseRemoteField{"cfgUseRemoteField", false, "Chose whether to fetch the magnetic field from ccdb or set it manually"}; + o2::framework::Configurable fConfigGRPmagPath{"cfgGrpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + o2::framework::Configurable fConfigMagField{"cfgMagField", 5.0f, "Manually set magnetic field"}; - Produces DileptonTrackTrackTable; + o2::framework::Produces DileptonTrackTrackTable; int fCurrentRun = -1; // needed to detect if the run changed and trigger update of calibrations etc. // uint32_t fTrackCutBitMap; // track cut bit mask to be used in the selection of tracks associated with dileptons @@ -4711,11 +4717,11 @@ struct AnalysisDileptonTrackTrack { std::vector fQuadrupletCutNames; std::vector fQuadrupletCuts; - Service fCCDB{}; + o2::framework::Service fCCDB{}; - Filter eventFilter = aod::dqanalysisflags::isEventSelected > static_cast(0); - Filter dileptonFilter = aod::reducedpair::sign == 0; - Filter filterBarrelTrackSelected = aod::dqanalysisflags::isBarrelSelected > static_cast(0); + o2::framework::expressions::Filter eventFilter = o2::aod::dqanalysisflags::isEventSelected > static_cast(0); + o2::framework::expressions::Filter dileptonFilter = o2::aod::reducedpair::sign == 0; + o2::framework::expressions::Filter filterBarrelTrackSelected = o2::aod::dqanalysisflags::isBarrelSelected > static_cast(0); constexpr static uint32_t fgDileptonFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::Pair; // fill map @@ -4746,13 +4752,13 @@ struct AnalysisDileptonTrackTrack { fIsSameTrackCut = true; } TString configDileptonCutNamesStr = fConfigDileptonCut.value; - fDileptonCut = *dqcuts::GetCompositeCut(configDileptonCutNamesStr.Data()); + fDileptonCut = *o2::aod::dqcuts::GetCompositeCut(configDileptonCutNamesStr.Data()); TString configQuadruletCutNamesStr = fConfigQuadrupletCuts.value; std::unique_ptr objArray(configQuadruletCutNamesStr.Tokenize(",")); for (Int_t icut = 0; icut < objArray->GetEntries(); ++icut) { TString cutName = objArray->At(icut)->GetName(); fQuadrupletCutNames.push_back(cutName); - fQuadrupletCuts.push_back(*dqcuts::GetCompositeCut(cutName.Data())); + fQuadrupletCuts.push_back(*o2::aod::dqcuts::GetCompositeCut(cutName.Data())); } if (!context.mOptions.get("processDummy")) { @@ -4905,13 +4911,13 @@ struct AnalysisDileptonTrackTrack { } } - Preslice trackAssocsPerCollision = aod::reducedtrack_association::reducedeventId; - Preslice dielectronsPerCollision = aod::reducedpair::reducedeventId; - Preslice ditracksPerCollision = aod::reducedpair::reducedeventId; + o2::framework::Preslice trackAssocsPerCollision = o2::aod::reducedtrack_association::reducedeventId; + o2::framework::Preslice dielectronsPerCollision = o2::aod::reducedpair::reducedeventId; + o2::framework::Preslice ditracksPerCollision = o2::aod::reducedpair::reducedeventId; - void processJpsiPiPi(soa::Filtered const& events, - soa::Filtered> const& assocs, - MyBarrelTracksWithCov const& tracks, soa::Filtered const& dileptons) + void processJpsiPiPi(o2::soa::Filtered const& events, + o2::soa::Filtered> const& assocs, + MyBarrelTracksWithCov const& tracks, o2::soa::Filtered const& dileptons) { if (events.size() == 0) { return; @@ -4951,76 +4957,78 @@ void DefineHistograms(HistogramManager* histMan, const TString& histClasses, con TString histName = histGroups; // NOTE: The level of detail for histogramming can be controlled via configurables if (classStr.Contains("Event")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "event", histName); + o2::aod::dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "event", histName); } if (classStr.Contains("SameBunchCorrelations") || classStr.Contains("OutOfBunchCorrelations")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "two-collisions", histName); + o2::aod::dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "two-collisions", histName); } if (classStr.Contains("Track") && !classStr.Contains("Pairs")) { if (classStr.Contains("Barrel")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); + o2::aod::dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); if (classStr.Contains("PIDCalibElectron")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "postcalib_electron"); + o2::aod::dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "postcalib_electron"); } if (classStr.Contains("PIDCalibPion")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "postcalib_pion"); + o2::aod::dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "postcalib_pion"); } if (classStr.Contains("PIDCalibProton")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "postcalib_proton"); + o2::aod::dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "postcalib_proton"); } if (classStr.Contains("Ambiguity")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "ambiguity"); + o2::aod::dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", "ambiguity"); } } if (classStr.Contains("Muon")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); + o2::aod::dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); } } if (classStr.Contains("Pairs")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", histName); + o2::aod::dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", histName); } if (classStr.Contains("Pairing")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "event", histName); + o2::aod::dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "event", histName); } if (classStr.Contains("Triplets")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", histName); + o2::aod::dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", histName); } if (classStr.Contains("DileptonsSelected")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", "barrel,vertexing"); + o2::aod::dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "pair", "barrel,vertexing"); } if (classStr.Contains("DileptonTrack") && !classStr.Contains("ME")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-track", histName); + o2::aod::dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-track", histName); } if (classStr.Contains("DileptonTrackME")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-track", "dilepton-hadron-array-correlation"); + o2::aod::dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-track", "dilepton-hadron-array-correlation"); } if (classStr.Contains("DileptonTrackECME")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-track", "energy-correlator"); + o2::aod::dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-track", "energy-correlator"); } if (classStr.Contains("HadronsSelected")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); + o2::aod::dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "track", histName); } if (classStr.Contains("DileptonHadronInvMass")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-hadron-mass"); + o2::aod::dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-hadron-mass"); } if (classStr.Contains("DileptonHadronCorrelation")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-hadron-correlation"); + o2::aod::dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-hadron-correlation"); } if (classStr.Contains("Quadruplet")) { - dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-dihadron", histName); + o2::aod::dqhistograms::DefineHistograms(histMan, objArray->At(iclass)->GetName(), "dilepton-dihadron", histName); } } // end loop over histogram classes } + +#endif // PWGDQ_TASKS_TABLEREADER_WITHASSOC_H_ diff --git a/PWGDQ/Tasks/tableReader_withAssoc_AsymmetricPairing_workflowSpec.cxx b/PWGDQ/Tasks/tableReader_withAssoc_AsymmetricPairing_workflowSpec.cxx index 4104a9882ec..62fd0a134a3 100644 --- a/PWGDQ/Tasks/tableReader_withAssoc_AsymmetricPairing_workflowSpec.cxx +++ b/PWGDQ/Tasks/tableReader_withAssoc_AsymmetricPairing_workflowSpec.cxx @@ -12,11 +12,13 @@ // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // Configurable workflow for running several DQ or other PWG analyses -#include "PWGDQ/Tasks/tableReader_withAssoc.cxx" +#include "PWGDQ/Tasks/tableReader_withAssoc.h" #include #include +using namespace o2::framework; + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ diff --git a/PWGDQ/Tasks/tableReader_withAssoc_DileptonTrackPairing_workflowSpec.cxx b/PWGDQ/Tasks/tableReader_withAssoc_DileptonTrackPairing_workflowSpec.cxx index 5ebc720a889..c76889c25a4 100644 --- a/PWGDQ/Tasks/tableReader_withAssoc_DileptonTrackPairing_workflowSpec.cxx +++ b/PWGDQ/Tasks/tableReader_withAssoc_DileptonTrackPairing_workflowSpec.cxx @@ -12,11 +12,13 @@ // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // Configurable workflow for running several DQ or other PWG analyses -#include "PWGDQ/Tasks/tableReader_withAssoc.cxx" +#include "PWGDQ/Tasks/tableReader_withAssoc.h" #include #include +using namespace o2::framework; + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ diff --git a/PWGDQ/Tasks/tableReader_withAssoc_DileptonTrackTrackPairing_workflowSpec.cxx b/PWGDQ/Tasks/tableReader_withAssoc_DileptonTrackTrackPairing_workflowSpec.cxx index 33cc56c530a..14954aff005 100644 --- a/PWGDQ/Tasks/tableReader_withAssoc_DileptonTrackTrackPairing_workflowSpec.cxx +++ b/PWGDQ/Tasks/tableReader_withAssoc_DileptonTrackTrackPairing_workflowSpec.cxx @@ -12,11 +12,13 @@ // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // Configurable workflow for running several DQ or other PWG analyses -#include "PWGDQ/Tasks/tableReader_withAssoc.cxx" +#include "PWGDQ/Tasks/tableReader_withAssoc.h" #include #include +using namespace o2::framework; + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ diff --git a/PWGDQ/Tasks/tableReader_withAssoc_SameEventPairingBarrelOnly_workflowSpec.cxx b/PWGDQ/Tasks/tableReader_withAssoc_SameEventPairingBarrelOnly_workflowSpec.cxx index e66a829fc80..e70f0bfbc56 100644 --- a/PWGDQ/Tasks/tableReader_withAssoc_SameEventPairingBarrelOnly_workflowSpec.cxx +++ b/PWGDQ/Tasks/tableReader_withAssoc_SameEventPairingBarrelOnly_workflowSpec.cxx @@ -12,11 +12,13 @@ // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // Configurable workflow for running several DQ or other PWG analyses -#include "PWGDQ/Tasks/tableReader_withAssoc.cxx" +#include "PWGDQ/Tasks/tableReader_withAssoc.h" #include #include +using namespace o2::framework; + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ diff --git a/PWGDQ/Tasks/tableReader_withAssoc_SameEventPairingMuonOnly_workflowSpec.cxx b/PWGDQ/Tasks/tableReader_withAssoc_SameEventPairingMuonOnly_workflowSpec.cxx index aa3dbeb5700..e18dd6fa7ba 100644 --- a/PWGDQ/Tasks/tableReader_withAssoc_SameEventPairingMuonOnly_workflowSpec.cxx +++ b/PWGDQ/Tasks/tableReader_withAssoc_SameEventPairingMuonOnly_workflowSpec.cxx @@ -12,11 +12,13 @@ // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // Configurable workflow for running several DQ or other PWG analyses -#include "PWGDQ/Tasks/tableReader_withAssoc.cxx" +#include "PWGDQ/Tasks/tableReader_withAssoc.h" #include #include +using namespace o2::framework; + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ diff --git a/PWGDQ/Tasks/tableReader_withAssoc_SameEventPairing_workflowSpec.cxx b/PWGDQ/Tasks/tableReader_withAssoc_SameEventPairing_workflowSpec.cxx index 02795bdc03b..6f72e0cf357 100644 --- a/PWGDQ/Tasks/tableReader_withAssoc_SameEventPairing_workflowSpec.cxx +++ b/PWGDQ/Tasks/tableReader_withAssoc_SameEventPairing_workflowSpec.cxx @@ -12,11 +12,13 @@ // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // Configurable workflow for running several DQ or other PWG analyses -#include "PWGDQ/Tasks/tableReader_withAssoc.cxx" +#include "PWGDQ/Tasks/tableReader_withAssoc.h" #include #include +using namespace o2::framework; + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ diff --git a/PWGDQ/Tasks/tableReader_withAssoc_direct.cxx b/PWGDQ/Tasks/tableReader_withAssoc_direct.cxx index 883513615ed..781930985c7 100644 --- a/PWGDQ/Tasks/tableReader_withAssoc_direct.cxx +++ b/PWGDQ/Tasks/tableReader_withAssoc_direct.cxx @@ -258,7 +258,7 @@ constexpr static uint32_t gkTrackFillMapWithCovNoTOF = VarManager::ObjTypes::Tra constexpr static uint32_t gkMuonFillMapWithCov = VarManager::ObjTypes::Muon | VarManager::ObjTypes::MuonCov; // Global function used to define needed histogram classes -void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups); // defines histograms for all tasks +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const char* histGroups); // defines histograms for all tasks // Enum containing the ordering of statistics histograms to be written in the QA file enum ZorroStatHist { @@ -2013,7 +2013,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) // adaptAnalysisTask(cfgc)}; } -void DefineHistograms(HistogramManager* histMan, TString histClasses, const char* histGroups) +void DefineHistograms(HistogramManager* histMan, const TString& histClasses, const char* histGroups) { // // Define here the histograms for all the classes required in analysis. diff --git a/PWGDQ/Tasks/tableReader_withAssoc_workflowSpec.cxx b/PWGDQ/Tasks/tableReader_withAssoc_workflowSpec.cxx index e458aff4e49..0097ffe5692 100644 --- a/PWGDQ/Tasks/tableReader_withAssoc_workflowSpec.cxx +++ b/PWGDQ/Tasks/tableReader_withAssoc_workflowSpec.cxx @@ -12,11 +12,13 @@ // Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no // Configurable workflow for running several DQ or other PWG analyses -#include "PWGDQ/Tasks/tableReader_withAssoc.cxx" +#include "PWGDQ/Tasks/tableReader_withAssoc.h" #include #include +using namespace o2::framework; + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ diff --git a/PWGDQ/Tasks/taskFwdTrackPid.cxx b/PWGDQ/Tasks/taskFwdTrackPid.cxx index 8f7febbbf28..4947a37a942 100644 --- a/PWGDQ/Tasks/taskFwdTrackPid.cxx +++ b/PWGDQ/Tasks/taskFwdTrackPid.cxx @@ -56,7 +56,7 @@ constexpr static uint32_t gkEventFillMap = VarManager::ObjTypes::ReducedEvent | constexpr static uint32_t gkMCEventFillMap = VarManager::ObjTypes::ReducedEventMC; constexpr static uint32_t gkMuonFillMap = VarManager::ObjTypes::ReducedMuon | VarManager::ObjTypes::ReducedMuonExtra; -void DefineHistograms(HistogramManager* histMan, TString histClasses); +void DefineHistograms(HistogramManager* histMan, const TString& histClasses); struct taskFwdTrackPid { Produces fwdPidAllList; @@ -243,7 +243,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) adaptAnalysisTask(cfgc)}; } -void DefineHistograms(HistogramManager* histMan, TString histClasses) +void DefineHistograms(HistogramManager* histMan, const TString& histClasses) { std::unique_ptr objArray(histClasses.Tokenize(";")); for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { diff --git a/PWGDQ/Tasks/v0selector.cxx b/PWGDQ/Tasks/v0selector.cxx index f464459adf0..bc27b0eb06e 100644 --- a/PWGDQ/Tasks/v0selector.cxx +++ b/PWGDQ/Tasks/v0selector.cxx @@ -762,7 +762,7 @@ struct trackPIDQA { } // end of track loop } // end of process - void DefineHistograms(TString histClasses) + void DefineHistograms(const TString& histClasses) { std::unique_ptr objArray(histClasses.Tokenize(";")); for (Int_t iclass = 0; iclass < objArray->GetEntries(); ++iclass) { diff --git a/PWGEM/Dilepton/Core/Dilepton.h b/PWGEM/Dilepton/Core/Dilepton.h index 148ed2d99c6..5cd306812cb 100644 --- a/PWGEM/Dilepton/Core/Dilepton.h +++ b/PWGEM/Dilepton/Core/Dilepton.h @@ -64,6 +64,7 @@ #include #include #include +#include #include #include #include @@ -323,6 +324,15 @@ struct Dilepton { o2::framework::Configurable bcMarginForSoftwareTrigger{"bcMarginForSoftwareTrigger", 100, "Number of BCs of margin for software triggers"}; } zorroGroup; + struct : o2::framework::ConfigurableGroup { + std::string prefix = "flowcorrection_group"; + o2::framework::Configurable cfgApplyWeightNUA{"cfgApplyWeightNUA", false, "flag to apply q-vector Non-uniform acceptance weighting"}; + o2::framework::Configurable nuaPath{"nuaPath", "Users/o/omassen/Dielectron/NUAWeights/LHC23_PbPb_pass5", "Path to NUA-weights file"}; + o2::framework::ConfigurableAxis ConfNUAPhiBins{"ConfNUAPhiBins", {60, -M_PI, M_PI}, "NUA histogram bins - phi-angle"}; + o2::framework::ConfigurableAxis ConfNUAEtaBins{"ConfNUAEtaBins", {40, -1., +1.}, "NUA histogram bins - eta"}; + o2::framework::ConfigurableAxis ConfNUAZVtxBins{"ConfNUAZVtxBins", {40, -10., 10.}, "NUA histogram bins - z-vtx"}; + } flowcorrectionGroup; + Zorro zorro; int mToIidx = 0; int mTOICounter = 0; @@ -355,6 +365,7 @@ struct Dilepton { float beamP1 = 0.f; // beam momentum float beamP2 = 0.f; // beam momentum TH2D* h2sp_resolution = nullptr; + std::vector h3nua_weights; void init(o2::framework::InitContext& /*context*/) { @@ -558,6 +569,16 @@ struct Dilepton { h2sp_resolution = reinterpret_cast(list->FindObject(spresoHistName.value.data())); LOGF(info, "h2sp_resolution.GetBinContent(40, 1) = %f", h2sp_resolution->GetBinContent(40, 1)); } + + if (flowcorrectionGroup.cfgApplyWeightNUA) { + auto list_nua = ccdb->getForTimeStamp(flowcorrectionGroup.nuaPath, collision.timestamp()); + h3nua_weights.push_back(reinterpret_cast(list_nua->FindObject("weights_uls_NUA"))); + LOGF(info, "h3nua_weights.at(0)->GetBinContent(5, 5, 5) = %f", h3nua_weights.at(0)->GetBinContent(5, 5, 5)); + h3nua_weights.push_back(reinterpret_cast(list_nua->FindObject("weights_lspp_NUA"))); + LOGF(info, "h3nua_weights.at(1)->GetBinContent(5, 5, 5) = %f", h3nua_weights.at(1)->GetBinContent(5, 5, 5)); + h3nua_weights.push_back(reinterpret_cast(list_nua->FindObject("weights_lsmm_NUA"))); + LOGF(info, "h3nua_weights.at(2)->GetBinContent(5, 5, 5) = %f", h3nua_weights.at(2)->GetBinContent(5, 5, 5)); + } } ~Dilepton() @@ -648,6 +669,7 @@ struct Dilepton { const o2::framework::AxisSpec axis_sp{ConfSPBins, Form("#vec{u}_{%d,ll} #upoint #vec{Q}_{%d}^{%s}", nmod, nmod, qvec_det_names[cfgQvecEstimator].data())}; fRegistry.add("Pair/same/uls/hs", "dilepton", o2::framework::HistType::kTHnSparseD, {axis_mass, axis_pt, axis_dca, axis_y, axis_sp}, true); + fRegistry.add("Pair/same/uls/hNUA", "NUA Histogram;#phi (rad.);#eta;VtxZ;", o2::framework::HistType::kTH3D, {flowcorrectionGroup.ConfNUAPhiBins, flowcorrectionGroup.ConfNUAEtaBins, flowcorrectionGroup.ConfNUAZVtxBins}, true); fRegistry.addClone("Pair/same/uls/", "Pair/same/lspp/"); fRegistry.addClone("Pair/same/uls/", "Pair/same/lsmm/"); @@ -880,8 +902,24 @@ struct Dilepton { } } + float getNUAweight(const int type_int, const float phi, const float eta, const float zVtx) + { + if (h3nua_weights.at(type_int) == nullptr) { + return 1.f; + } + int binId_phi = h3nua_weights.at(type_int)->GetXaxis()->FindBin(phi); + int binId_eta = h3nua_weights.at(type_int)->GetYaxis()->FindBin(eta); + int binId_zVtx = h3nua_weights.at(type_int)->GetZaxis()->FindBin(zVtx); + float nuaWeight = h3nua_weights.at(type_int)->GetBinContent(binId_phi, binId_eta, binId_zVtx); + + if (nuaWeight == 0 || std::isnan(nuaWeight) || std::isinf(nuaWeight)) { + nuaWeight = 1.f; + } + return nuaWeight; + } + template - bool fillPairInfo(TCollision const& collision, TTrack1 const& t1, TTrack2 const& t2, TCut const& cut, TAllTracks const&, const std::vector weightvector) + bool fillPairInfo(TCollision const& collision, TTrack1 const& t1, TTrack2 const& t2, TCut const& cut, TAllTracks const&, const std::vector& weightvector) { if constexpr (ev_id == 0) { if constexpr (pairtype == o2::aod::pwgem::dilepton::utils::pairutil::DileptonPairType::kDielectron) { @@ -1054,14 +1092,20 @@ struct Dilepton { if constexpr (ev_id == 0) { // LOGF(info, "collision.centFT0C() = %f, collision.trackOccupancyInTimeRange() = %d, getSPresolution = %f", collision.centFT0C(), collision.trackOccupancyInTimeRange(), getSPresolution(collision.centFT0C(), collision.trackOccupancyInTimeRange())); + if (flowcorrectionGroup.cfgApplyWeightNUA) { + weight *= 1. / getNUAweight(t1.sign() * t2.sign() < 0 ? 0 : (t1.sign() > 0 && t2.sign() > 0 ? 1 : 2), v12.Phi(), v12.Eta(), collision.posZ()); + } float sp = RecoDecay::dotProd(std::array{static_cast(std::cos(nmod * v12.Phi())), static_cast(std::sin(nmod * v12.Phi()))}, qvectors[nmod][cfgQvecEstimator]) / getSPresolution(collision.centFT0C(), collision.trackOccupancyInTimeRange()); if (t1.sign() * t2.sign() < 0) { // ULS fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), sp, weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("uls/hNUA"), v12.Phi(), v12.Eta(), collision.posZ(), weight); } else if (t1.sign() > 0 && t2.sign() > 0) { // LS++ fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), sp, weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lspp/hNUA"), v12.Phi(), v12.Eta(), collision.posZ(), weight); } else if (t1.sign() < 0 && t2.sign() < 0) { // LS-- fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hs"), v12.M(), v12.Pt(), pair_dca, v12.Rapidity(), sp, weight); + fRegistry.fill(HIST("Pair/") + HIST(event_pair_types[ev_id]) + HIST("lsmm/hNUA"), v12.Phi(), v12.Eta(), collision.posZ(), weight); } } else if constexpr (ev_id == 1) { if (t1.sign() * t2.sign() < 0) { // ULS diff --git a/PWGEM/Dilepton/Core/SingleTrackQC.h b/PWGEM/Dilepton/Core/SingleTrackQC.h index 15289d398f2..0530a64e6e2 100644 --- a/PWGEM/Dilepton/Core/SingleTrackQC.h +++ b/PWGEM/Dilepton/Core/SingleTrackQC.h @@ -70,7 +70,7 @@ using MyCollisions = o2::soa::Join; using MyCollision = MyCollisions::iterator; -using MyCollisionsSWT = o2::soa::Join; +using MyCollisionsSWT = o2::soa::Join; using MyCollisionSWT = MyCollisionsSWT::iterator; using MyElectrons = o2::soa::Join; @@ -331,8 +331,10 @@ struct SingleTrackQC { fRegistry.add("Track/positive/hsDelta", "diff. between GL and associated SA;p_{T}^{gl} (GeV/c);(p_{T}^{sa} - p_{T}^{gl})/p_{T}^{gl};#Delta#eta;#Delta#varphi (rad.);", o2::framework::HistType::kTHnSparseF, {axis_pt, {100, -0.5, +0.5}, {100, -0.5, +0.5}, {90, -M_PI / 4, M_PI / 4}}, false); fRegistry.add("Track/positive/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", o2::framework::HistType::kTH1F, {{1000, -5, 5}}, false); fRegistry.add("Track/positive/hTrackType", "track type", o2::framework::HistType::kTH1F, {{6, -0.5f, 5.5}}, false); - fRegistry.add("Track/positive/hDCAxy", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", o2::framework::HistType::kTH2F, {{200, -0.5f, 0.5f}, {200, -0.5f, 0.5f}}, false); - fRegistry.add("Track/positive/hDCAxySigma", "DCA x vs. y;DCA_{x} (#sigma);DCA_{y} (#sigma)", o2::framework::HistType::kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); + fRegistry.add("Track/positive/hDCAxy2D", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", o2::framework::HistType::kTH2F, {{200, -0.5f, 0.5f}, {200, -0.5f, 0.5f}}, false); + fRegistry.add("Track/positive/hDCAxy2DinSigma", "DCA x vs. y;DCA_{x} (#sigma);DCA_{y} (#sigma)", o2::framework::HistType::kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); + fRegistry.add("Track/positive/hDCAxy", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", o2::framework::HistType::kTH1F, {{1000, 0.f, 1.0f}}, false); // dummy comment + fRegistry.add("Track/positive/hDCAxyinSigma", "DCA x vs. y;DCA_{x} (#sigma);DCA_{y} (#sigma)", o2::framework::HistType::kTH1F, {{100, 0.0f, 10.0f}}, false); fRegistry.add("Track/positive/hDCAxRes_Pt", "DCA_{x} resolution vs. pT;p_{T} (GeV/c);DCA_{x} resolution (#mum)", o2::framework::HistType::kTH2F, {{200, 0, 10}, {500, 0, 500}}, false); fRegistry.add("Track/positive/hDCAyRes_Pt", "DCA_{y} resolution vs. pT;p_{T} (GeV/c);DCA_{y} resolution (#mum)", o2::framework::HistType::kTH2F, {{200, 0, 10}, {500, 0, 500}}, false); fRegistry.add("Track/positive/hDCAxyRes_Pt", "DCA_{xy} resolution vs. pT;p_{T} (GeV/c);DCA_{xy} resolution (#mum)", o2::framework::HistType::kTH2F, {{200, 0, 10}, {500, 0, 500}}, false); @@ -664,8 +666,10 @@ struct SingleTrackQC { fRegistry.fill(HIST("Track/positive/hsDelta"), track.pt(), reldpt, deta, dphi, weight); fRegistry.fill(HIST("Track/positive/hQoverPt"), track.sign() / track.pt()); fRegistry.fill(HIST("Track/positive/hTrackType"), track.trackType()); - fRegistry.fill(HIST("Track/positive/hDCAxy"), track.fwdDcaX(), track.fwdDcaY()); - fRegistry.fill(HIST("Track/positive/hDCAxySigma"), track.fwdDcaX() / std::sqrt(track.cXXatDCA()), track.fwdDcaY() / std::sqrt(track.cYYatDCA())); + fRegistry.fill(HIST("Track/positive/hDCAxy"), std::hypot(track.fwdDcaX(), track.fwdDcaY())); + fRegistry.fill(HIST("Track/positive/hDCAxyinSigma"), dca_xy); + fRegistry.fill(HIST("Track/positive/hDCAxy2D"), track.fwdDcaX(), track.fwdDcaY()); + fRegistry.fill(HIST("Track/positive/hDCAxy2DinSigma"), track.fwdDcaX() / std::sqrt(track.cXXatDCA()), track.fwdDcaY() / std::sqrt(track.cYYatDCA())); fRegistry.fill(HIST("Track/positive/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXXatDCA()) * 1e+4); fRegistry.fill(HIST("Track/positive/hDCAyRes_Pt"), track.pt(), std::sqrt(track.cYYatDCA()) * 1e+4); fRegistry.fill(HIST("Track/positive/hDCAxyRes_Pt"), track.pt(), o2::aod::pwgem::dilepton::utils::emtrackutil::sigmaFwdDcaXY(track) * 1e+4); @@ -689,8 +693,10 @@ struct SingleTrackQC { fRegistry.fill(HIST("Track/negative/hsDelta"), track.pt(), reldpt, deta, dphi, weight); fRegistry.fill(HIST("Track/negative/hQoverPt"), track.sign() / track.pt()); fRegistry.fill(HIST("Track/negative/hTrackType"), track.trackType()); - fRegistry.fill(HIST("Track/negative/hDCAxy"), track.fwdDcaX(), track.fwdDcaY()); - fRegistry.fill(HIST("Track/negative/hDCAxySigma"), track.fwdDcaX() / std::sqrt(track.cXXatDCA()), track.fwdDcaY() / std::sqrt(track.cYYatDCA())); + fRegistry.fill(HIST("Track/negative/hDCAxy"), std::hypot(track.fwdDcaX(), track.fwdDcaY())); + fRegistry.fill(HIST("Track/negative/hDCAxyinSigma"), dca_xy); + fRegistry.fill(HIST("Track/negative/hDCAxy2D"), track.fwdDcaX(), track.fwdDcaY()); + fRegistry.fill(HIST("Track/negative/hDCAxy2DinSigma"), track.fwdDcaX() / std::sqrt(track.cXXatDCA()), track.fwdDcaY() / std::sqrt(track.cYYatDCA())); fRegistry.fill(HIST("Track/negative/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXXatDCA()) * 1e+4); fRegistry.fill(HIST("Track/negative/hDCAyRes_Pt"), track.pt(), std::sqrt(track.cYYatDCA()) * 1e+4); fRegistry.fill(HIST("Track/negative/hDCAxyRes_Pt"), track.pt(), o2::aod::pwgem::dilepton::utils::emtrackutil::sigmaFwdDcaXY(track) * 1e+4); diff --git a/PWGEM/Dilepton/Core/SingleTrackQCMC.h b/PWGEM/Dilepton/Core/SingleTrackQCMC.h index 222f863e71f..314265b4e6b 100644 --- a/PWGEM/Dilepton/Core/SingleTrackQCMC.h +++ b/PWGEM/Dilepton/Core/SingleTrackQCMC.h @@ -375,7 +375,8 @@ struct SingleTrackQCMC { fRegistry.add("Track/PromptLF/positive/hsDelta", "diff. between GL and associated SA;p_{T}^{gl} (GeV/c);(p_{T}^{sa} - p_{T}^{gl})/p_{T}^{gl};#Delta#eta;#Delta#varphi (rad.);", o2::framework::HistType::kTHnSparseF, {axis_pt, {100, -0.5, +0.5}, {100, -0.5, +0.5}, {90, -M_PI / 4, M_PI / 4}}, false); fRegistry.add("Track/PromptLF/positive/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", o2::framework::HistType::kTH1F, {{1000, -5, 5}}, false); fRegistry.add("Track/PromptLF/positive/hTrackType", "track type", o2::framework::HistType::kTH1F, {{6, -0.5f, 5.5}}, false); - fRegistry.add("Track/PromptLF/positive/hDCAxy", "DCAxy;DCA_{xy} (cm)", o2::framework::HistType::kTH1F, {{100, 0.f, 1.0f}}, false); + fRegistry.add("Track/PromptLF/positive/hDCAxy", "DCAxy;DCA_{xy} (cm)", o2::framework::HistType::kTH1F, {{1000, 0.f, 1.0f}}, false); + fRegistry.add("Track/PromptLF/positive/hDCAxyinSigma", "DCAxy;DCA_{xy} (#sigma)", o2::framework::HistType::kTH1F, {{100, 0.f, 10.0f}}, false); fRegistry.add("Track/PromptLF/positive/hDCAxy2D", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", o2::framework::HistType::kTH2F, {{200, -0.5f, 0.5f}, {200, -0.5f, 0.5f}}, false); fRegistry.add("Track/PromptLF/positive/hDCAxy2DinSigma", "DCA x vs. y;DCA_{x} (#sigma);DCA_{y} (#sigma)", o2::framework::HistType::kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); fRegistry.add("Track/PromptLF/positive/hDCAxRes_Pt", "DCA_{x} resolution vs. pT;p_{T} (GeV/c);DCA_{x} resolution (#mum)", o2::framework::HistType::kTH2F, {{200, 0, 10}, {500, 0, 500}}, false); @@ -396,7 +397,6 @@ struct SingleTrackQCMC { fRegistry.add("Track/PromptLF/positive/hPtGen_DeltaPtOverPtGen", "muon p_{T} resolution;p_{T}^{gen} (GeV/c);(p_{T}^{rec} - p_{T}^{gen})/p_{T}^{gen}", o2::framework::HistType::kTH2F, {{200, 0, 10}, {200, -1.0f, 1.0f}}, true); fRegistry.add("Track/PromptLF/positive/hPtGen_DeltaEta", "muon #eta resolution;p_{T}^{gen} (GeV/c);#eta^{rec} - #eta^{gen}", o2::framework::HistType::kTH2F, {{200, 0, 10}, {100, -0.05f, 0.05f}}, true); fRegistry.add("Track/PromptLF/positive/hPtGen_DeltaPhi", "muon #varphi resolution;p_{T}^{gen} (GeV/c);#varphi^{rec} - #varphi^{gen} (rad.)", o2::framework::HistType::kTH2F, {{200, 0, 10}, {100, -0.05f, 0.05f}}, true); - fRegistry.add("Track/PromptLF/positive/hdR_Chi2MatchMCHMFT", "dr vs. matching chi2 MCH-MFT;chi2 match MCH-MFT;#DeltaR;", o2::framework::HistType::kTH2F, {{200, 0.0f, 100}, {200, 0, 0.5}}, false); fRegistry.add("Track/PromptLF/positive/hLog10Chi2IP", "chi2IP;log_{10}(#chi^{2}_{IP})", o2::framework::HistType::kTH1F, {{100, -5, 5}}, false); } fRegistry.addClone("Track/PromptLF/positive/", "Track/PromptLF/negative/"); @@ -776,6 +776,7 @@ struct SingleTrackQCMC { fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hQoverPt"), track.sign() / track.pt()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hTrackType"), track.trackType()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxy"), std::sqrt(std::pow(track.fwdDcaX(), 2) + std::pow(track.fwdDcaY(), 2))); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxyinSigma"), dca_xy); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxy2D"), track.fwdDcaX(), track.fwdDcaY()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxy2DinSigma"), track.fwdDcaX() / std::sqrt(track.cXXatDCA()), track.fwdDcaY() / std::sqrt(track.cYYatDCA())); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXXatDCA()) * 1e+4); @@ -793,7 +794,6 @@ struct SingleTrackQCMC { fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hChi2MatchMCHMID_Pt"), track.pt(), track.chi2MatchMCHMID()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hChi2MatchMCHMFT_Pt"), track.pt(), track.chi2MatchMCHMFT()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hMFTClusterMap"), track.mftClusterMap()); - fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hdR_Chi2MatchMCHMFT"), track.chi2MatchMCHMFT(), std::sqrt(deta * deta + dphi * dphi)); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hLog10Chi2IP"), std::log10(track.chi2IP())); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hPtGen_DeltaPtOverPtGen"), mctrack.pt(), (track.pt() - mctrack.pt()) / mctrack.pt()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("positive/hPtGen_DeltaEta"), mctrack.pt(), track.eta() - mctrack.eta()); @@ -810,6 +810,7 @@ struct SingleTrackQCMC { fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hQoverPt"), track.sign() / track.pt()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hTrackType"), track.trackType()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxy"), std::sqrt(std::pow(track.fwdDcaX(), 2) + std::pow(track.fwdDcaY(), 2))); + fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxyinSigma"), dca_xy); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxy2D"), track.fwdDcaX(), track.fwdDcaY()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxy2DinSigma"), track.fwdDcaX() / std::sqrt(track.cXXatDCA()), track.fwdDcaY() / std::sqrt(track.cYYatDCA())); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hDCAxRes_Pt"), track.pt(), std::sqrt(track.cXXatDCA()) * 1e+4); @@ -827,7 +828,6 @@ struct SingleTrackQCMC { fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hChi2MatchMCHMID_Pt"), track.pt(), track.chi2MatchMCHMID()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hChi2MatchMCHMFT_Pt"), track.pt(), track.chi2MatchMCHMFT()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hMFTClusterMap"), track.mftClusterMap()); - fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hdR_Chi2MatchMCHMFT"), track.chi2MatchMCHMFT(), std::sqrt(deta * deta + dphi * dphi)); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hLog10Chi2IP"), std::log10(track.chi2IP())); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hPtGen_DeltaPtOverPtGen"), mctrack.pt(), (track.pt() - mctrack.pt()) / mctrack.pt()); fRegistry.fill(HIST("Track/") + HIST(lepton_source_types[lepton_source_id]) + HIST("negative/hPtGen_DeltaEta"), mctrack.pt(), track.eta() - mctrack.eta()); diff --git a/PWGEM/Dilepton/TableProducer/CMakeLists.txt b/PWGEM/Dilepton/TableProducer/CMakeLists.txt index 5d2889041ae..8a00046766a 100644 --- a/PWGEM/Dilepton/TableProducer/CMakeLists.txt +++ b/PWGEM/Dilepton/TableProducer/CMakeLists.txt @@ -46,11 +46,6 @@ o2physics_add_dpl_workflow(skimmer-primary-muon PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::GlobalTracking COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(skimmer-primary-muon-qc - SOURCES skimmerPrimaryMuonQC.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::GlobalTracking - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(skimmer-primary-track SOURCES skimmerPrimaryTrack.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore diff --git a/PWGEM/Dilepton/TableProducer/createEMEventDilepton.cxx b/PWGEM/Dilepton/TableProducer/createEMEventDilepton.cxx index 7d6f5018521..23b90b26725 100644 --- a/PWGEM/Dilepton/TableProducer/createEMEventDilepton.cxx +++ b/PWGEM/Dilepton/TableProducer/createEMEventDilepton.cxx @@ -138,6 +138,12 @@ struct CreateEMEventDilepton { continue; } + if constexpr (eventtype == EMEventType::kEvent_Cent_ZDC) { + if (!collision.triggereventsp()) { + continue; // dummy comment + } + } + if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { int8_t posZint8 = static_cast(collision.posZ() * 2.f); if (posZint8 == 0) { diff --git a/PWGEM/Dilepton/TableProducer/filterEoI.cxx b/PWGEM/Dilepton/TableProducer/filterEoI.cxx index 8e45681943f..217706c4d97 100644 --- a/PWGEM/Dilepton/TableProducer/filterEoI.cxx +++ b/PWGEM/Dilepton/TableProducer/filterEoI.cxx @@ -19,7 +19,6 @@ #include "Common/Core/TableHelper.h" -#include #include #include #include @@ -29,7 +28,6 @@ #include #include -#include #include #include @@ -52,10 +50,9 @@ struct filterEoI { Configurable inheritFromOtherTask{"inheritFromOtherTask", true, "Flag to iherit all common configurables from skimmerPrimaryElectron or skimmerPrimaryMuon"}; Configurable minNelectron{"minNelectron", -1, "min number of electron candidates per collision"}; Configurable minNmuon{"minNmuon", -1, "min number of muon candidates per collision"}; - Configurable minNphotons{"minNphotons", 1, "min number of photon candidates per collision"}; + Configurable minNgamma{"minNgamma", 1, "min number of V0-photon candidates per collision"}; Configurable taskNameForNelectron{"taskNameForNelectron", "skimmer-primary-electron", "task name where minNelectron is defined."}; Configurable varNameForNelectron{"varNameForNelectron", "minNelectron", "variable name for minNelectron"}; - Configurable maxMinvPair{"maxMinvPair", -1.f, "keep events only if at least one photon pair has q_inv below this (GeV/c); negative = disabled"}; HistogramRegistry fRegistry{"output"}; void init(o2::framework::InitContext& initContext) @@ -67,10 +64,8 @@ struct filterEoI { LOGF(info, "minNelectron = %d", minNelectron.value); LOGF(info, "minNmuon = %d", minNmuon.value); - LOGF(info, "minNphotons = %d", minNphotons.value); - LOGF(info, "maxMinvPair = %f", static_cast(maxMinvPair.value)); - auto hEventCounter = fRegistry.add("hEventCounter", "hEventCounter", kTH1D, {{10, 0.5f, 10.5f}}); + auto hEventCounter = fRegistry.add("hEventCounter", "hEventCounter", kTH1D, {{8, 0.5f, 8.5f}}); hEventCounter->GetXaxis()->SetBinLabel(1, "all"); hEventCounter->GetXaxis()->SetBinLabel(2, "event with electron"); hEventCounter->GetXaxis()->SetBinLabel(3, "event with forward muon"); @@ -79,8 +74,6 @@ struct filterEoI { hEventCounter->GetXaxis()->SetBinLabel(6, "event with electron and forward muon"); hEventCounter->GetXaxis()->SetBinLabel(7, "event with electron or forward muon or v0"); hEventCounter->GetXaxis()->SetBinLabel(8, "event with v0 or electrons from dalitz"); - hEventCounter->GetXaxis()->SetBinLabel(9, "event with minNphotons v0s selection"); - hEventCounter->GetXaxis()->SetBinLabel(10, "event with minNphotons v0s and low-M pair selection"); } SliceCache cache; @@ -115,27 +108,10 @@ struct filterEoI { } if constexpr (static_cast(system & kPCM)) { auto v0s_coll = v0s.sliceBy(perCollision_v0, collision.globalIndex()); - if (v0s_coll.size() >= 1) { + if (v0s_coll.size() >= minNgamma) { + does_pcm_exist = true; fRegistry.fill(HIST("hEventCounter"), 4); } - if (v0s_coll.size() >= minNphotons) { - fRegistry.fill(HIST("hEventCounter"), 9); - bool hasLowMPair = (maxMinvPair < 0.f); - if (!hasLowMPair) { - for (const auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(v0s_coll, v0s_coll))) { - ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.f); - ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.f); - if ((v1 + v2).M() < maxMinvPair) { - hasLowMPair = true; - break; - } - } - } - if (hasLowMPair) { - does_pcm_exist = true; - fRegistry.fill(HIST("hEventCounter"), 10); - } - } } if constexpr (static_cast(system & kElectronFromDalitz)) { auto electronsda_coll = electronsda.sliceBy(perCollision_elda, collision.globalIndex()); @@ -157,7 +133,11 @@ struct filterEoI { fRegistry.fill(HIST("hEventCounter"), 8); } - emeoi(does_electron_exist || does_fwdmuon_exist || does_pcm_exist || does_electronda_exist); + if constexpr (static_cast(system & kPCM) && static_cast(system & kElectronFromDalitz)) { + emeoi(does_pcm_exist && does_electronda_exist); + } else { + emeoi(does_electron_exist || does_fwdmuon_exist || does_pcm_exist || does_electronda_exist); + } } // end of collision loop @@ -193,6 +173,12 @@ struct filterEoI { selectEoI(collisions, electrons, muons, v0s, nullptr); } + void process_ElectronFromDalitz(aod::Collisions const& collisions, aod::EMPrimaryElectronsFromDalitz const& electronsda) + { + const uint8_t sysflag = kElectronFromDalitz; + selectEoI(collisions, nullptr, nullptr, nullptr, electronsda); + } + void process_PCM_ElectronFromDalitz(aod::Collisions const& collisions, aod::V0PhotonsKF const& v0s, aod::EMPrimaryElectronsFromDalitz const& electronsda) { const uint8_t sysflag = kPCM | kElectronFromDalitz; @@ -211,6 +197,7 @@ struct filterEoI { PROCESS_SWITCH(filterEoI, process_PCM, "create filter bit for PCM", false); PROCESS_SWITCH(filterEoI, process_Electron_FwdMuon, "create filter bit for Electron, FwdMuon", false); PROCESS_SWITCH(filterEoI, process_Electron_FwdMuon_PCM, "create filter bit for Electron, FwdMuon, PCM", false); + PROCESS_SWITCH(filterEoI, process_ElectronFromDalitz, "create filter bit for ElectronFromDalitz", false); PROCESS_SWITCH(filterEoI, process_PCM_ElectronFromDalitz, "create filter bit for PCM, ElectronFromDalitz", false); PROCESS_SWITCH(filterEoI, processDummy, "processDummy", true); }; diff --git a/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx b/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx index 8706432f69d..75c52e0aaef 100644 --- a/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx +++ b/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuon.cxx @@ -48,7 +48,6 @@ #include #include #include -#include #include #include #include @@ -112,16 +111,26 @@ struct skimmerPrimaryMuon { // for z shift for propagation Configurable cfgApplyZShiftFromCCDB{"cfgApplyZShiftFromCCDB", false, "flag to apply z shift"}; Configurable cfgZShiftPath{"cfgZShiftPath", "Users/m/mcoquet/ZShift", "CCDB path for z shift to apply to forward tracks"}; - Configurable cfgManualZShift{"cfgManualZShift", 0, "manual z-shift for propagation of global muon to PV"}; + Configurable cfgManualXShiftMFTtop{"cfgManualXShiftMFTtop", 0, "manual x shift on MFT top when propagating global muon to PV"}; + Configurable cfgManualYShiftMFTtop{"cfgManualYShiftMFTtop", 0, "manual y shift on MFT top when propagating global muon to PV"}; + Configurable cfgManualZShiftMFTtop{"cfgManualZShiftMFTtop", 0, "manual z shift on MFT top when propagating global muon to PV"}; + Configurable cfgManualXShiftMFTbottom{"cfgManualXShiftMFTbottom", 0, "manual x shift on MFT bottom when propagating global muon to PV"}; + Configurable cfgManualYShiftMFTbottom{"cfgManualYShiftMFTbottom", 0, "manual y shift on MFT bottom when propagating global muon to PV"}; + Configurable cfgManualZShiftMFTbottom{"cfgManualZShiftMFTbottom", 0, "manual z shift on MFT bottom when propagating global muon to PV"}; o2::ccdb::CcdbApi ccdbApi; Service ccdb; int mRunNumber = 0; float mBz = 0; - float mZShift = 0; + float mXShiftMFTtop = 0; + float mYShiftMFTtop = 0; + float mZShiftMFTtop = 0; + float mXShiftMFTbottom = 0; + float mYShiftMFTbottom = 0; + float mZShiftMFTbottom = 0; HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; - static constexpr std::string_view muon_types[5] = {"MFTMCHMID/", "MFTMCHMIDOtherMatch/", "MFTMCH/", "MCHMID/", "MCH/"}; + // static constexpr std::string_view muon_types[5] = {"MFTMCHMID/", "MFTMCHMIDOtherMatch/", "MFTMCH/", "MCHMID/", "MCH/"}; void init(InitContext&) { @@ -140,7 +149,12 @@ struct skimmerPrimaryMuon { } mRunNumber = 0; mBz = 0; - mZShift = 0; + mXShiftMFTtop = 0; + mYShiftMFTtop = 0; + mZShiftMFTtop = 0; + mXShiftMFTbottom = 0; + mYShiftMFTbottom = 0; + mZShiftMFTbottom = 0; } void initCCDB(aod::BCsWithTimestamps::iterator const& bc) @@ -168,14 +182,22 @@ struct skimmerPrimaryMuon { auto* zShift = ccdb->getForTimeStamp>(cfgZShiftPath, bc.timestamp()); if (zShift != nullptr && !zShift->empty()) { LOGF(info, "reading z shift %f from %s", (*zShift)[0], cfgZShiftPath.value); - mZShift = (*zShift)[0]; + mZShiftMFTtop = (*zShift)[0]; + mZShiftMFTbottom = (*zShift)[0]; } else { LOGF(info, "z shift is not found in ccdb path %s. set to 0 cm", cfgZShiftPath.value); - mZShift = 0; + mZShiftMFTtop = 0; + mZShiftMFTbottom = 0; } } else { - LOGF(info, "z shift is manually set to %f cm", cfgManualZShift.value); - mZShift = cfgManualZShift; + LOGF(info, "z shift on MFT top is manually set to %f cm", cfgManualZShiftMFTtop.value); + LOGF(info, "z shift on MFT bottom is manually set to %f cm", cfgManualZShiftMFTbottom.value); + mXShiftMFTtop = cfgManualXShiftMFTtop; + mYShiftMFTtop = cfgManualYShiftMFTtop; + mZShiftMFTtop = cfgManualZShiftMFTtop; + mXShiftMFTbottom = cfgManualXShiftMFTbottom; + mYShiftMFTbottom = cfgManualYShiftMFTbottom; + mZShiftMFTbottom = cfgManualZShiftMFTbottom; } } @@ -209,8 +231,10 @@ struct skimmerPrimaryMuon { fRegistry.add("MFTMCHMID/hDCAxyinSigma", "DCAxy in sigma;DCA_{xy} (#sigma);", kTH1F, {{100, 0, 10}}, false); fRegistry.add("MFTMCHMID/hLog10Chi2IP", "chi2IP;log_{10}(#chi^{2}_{IP})", kTH1F, {{100, -5, 5}}, false); fRegistry.add("MFTMCHMID/hSqrtChi2IP", "chi2IP;#sqrt{#chi^{2}_{IP}}", kTH1F, {{100, 0, 10}}, false); - fRegistry.add("MFTMCHMID/hDCAx_PosZ", "DCAx vs. posZ;Z_{vtx} (cm);DCA_{x} (cm)", kTH2F, {{200, -10, +10}, {400, -0.2, +0.2}}, false); - fRegistry.add("MFTMCHMID/hDCAy_PosZ", "DCAy vs. posZ;Z_{vtx} (cm);DCA_{y} (cm)", kTH2F, {{200, -10, +10}, {400, -0.2, +0.2}}, false); + fRegistry.add("MFTMCHMID/hDCAx_PosZ_MFTtop", "DCAx vs. posZ;Z_{vtx} (cm);DCA_{x} (cm)", kTH2F, {{200, -10, +10}, {400, -0.2, +0.2}}, false); + fRegistry.add("MFTMCHMID/hDCAy_PosZ_MFTtop", "DCAy vs. posZ;Z_{vtx} (cm);DCA_{y} (cm)", kTH2F, {{200, -10, +10}, {400, -0.2, +0.2}}, false); + fRegistry.add("MFTMCHMID/hDCAx_PosZ_MFTbottom", "DCAx vs. posZ;Z_{vtx} (cm);DCA_{x} (cm)", kTH2F, {{200, -10, +10}, {400, -0.2, +0.2}}, false); + fRegistry.add("MFTMCHMID/hDCAy_PosZ_MFTbottom", "DCAy vs. posZ;Z_{vtx} (cm);DCA_{y} (cm)", kTH2F, {{200, -10, +10}, {400, -0.2, +0.2}}, false); fRegistry.add("MFTMCHMID/hDCAx_Phi", "DCAx vs. #varphi;#varphi (rad.);DCA_{x} (cm)", kTH2F, {{180, -M_PI, M_PI}, {400, -0.2, +0.2}}, false); fRegistry.add("MFTMCHMID/hDCAy_Phi", "DCAy vs. #varphi;#varphi (rad.);DCA_{y} (cm)", kTH2F, {{180, -M_PI, M_PI}, {400, -0.2, +0.2}}, false); fRegistry.add("MFTMCHMID/hMeanDCAx", ";X_{IU} (cm);Y_{IU} (cm); (cm)", kTProfile2D, {{240, -12, +12}, {240, -12, +12}}, false); @@ -279,51 +303,24 @@ struct skimmerPrimaryMuon { return false; } - o2::dataformats::GlobalFwdTrack propmuonAtPV = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToVertex, matchingZ, mBz, mZShift); - float pt = propmuonAtPV.getPt(); - float eta = propmuonAtPV.getEta(); - float phi = propmuonAtPV.getPhi(); - o2::math_utils::bringTo02Pi(phi); + o2::dataformats::GlobalFwdTrack propmuonAtPV; + float pt = 0.f, eta = 0.f, phi = 0.f; - o2::dataformats::GlobalFwdTrack propmuonAtDCA = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, mZShift); - - float dcaX = propmuonAtDCA.getX() - collision.posX(); - float dcaY = propmuonAtDCA.getY() - collision.posY(); - float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); - float rAtAbsorberEnd = fwdtrack.rAtAbsorberEnd(); // this works only for GlobalMuonTrack - float cXXatDCA = propmuonAtDCA.getSigma2X(); - float cYYatDCA = propmuonAtDCA.getSigma2Y(); - float cXYatDCA = propmuonAtDCA.getSigmaXY(); - - float det = cXXatDCA * cYYatDCA - cXYatDCA * cXYatDCA; // determinanat + o2::dataformats::GlobalFwdTrack propmuonAtDCA; + float dcaX = 999.f, dcaY = 999.f, dcaXY = 999.f; + float rAtAbsorberEnd = 1e+10; + float cXXatDCA = 1e+10, cYYatDCA = 1e+10, cXYatDCA = 1e+10; float dcaXYinSigma = 999.f; - if (det < 0) { - dcaXYinSigma = 999.f; - } else { - dcaXYinSigma = std::sqrt(std::fabs((dcaX * dcaX * cYYatDCA + dcaY * dcaY * cXXatDCA - 2.f * dcaX * dcaY * cXYatDCA) / det / 2.f)); // dca xy in sigma - } - float sigma_dcaXY = dcaXY / dcaXYinSigma; + float sigma_dcaXY = 1e+10; - float pDCA = propmuonAtPV.getP() * dcaXY; + float pDCA = 1e+10; int nClustersMFT = 0; - float ptMatchedMCHMID = propmuonAtPV.getPt(); - float etaMatchedMCHMID = propmuonAtPV.getEta(); - float phiMatchedMCHMID = propmuonAtPV.getPhi(); - o2::math_utils::bringTo02Pi(phiMatchedMCHMID); - // float x = fwdtrack.x(); - // float y = fwdtrack.y(); - // float z = fwdtrack.z(); - // float tgl = fwdtrack.tgl(); + float ptMatchedMCHMID = 1e+10, etaMatchedMCHMID = 1e+10, phiMatchedMCHMID = 1e+10; float chi2mft = 0.f; uint64_t mftClusterSizesAndTrackFlags = 0; int ndf_mchmft = 1; int ndf_mft = 1; - // float etaMatchedMCHMIDatMP = 999.f; - float phiMatchedMCHMIDatMP = 999.f; - // float etaMatchedMFTatMP = 999.f; - float phiMatchedMFTatMP = 999.f; - float deta = 999.f; float dphi = 999.f; @@ -341,17 +338,40 @@ struct skimmerPrimaryMuon { return false; } - // apply dca cut here to minimize the number of calling propagateMuon. - if (maxDCAxy < dcaXY) { - return false; - } - auto mchtrack = fwdtrack.template matchMCHTrack_as(); // MCH-MID auto mfttrack = fwdtrack.template matchMFTTrack_as(); // MFTsa if (mfttrack.chi2() < 0.f) { return false; } + propmuonAtPV = std::atan2(mfttrack.y(), mfttrack.x()) > 0.f ? propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToVertex, matchingZ, mBz, mXShiftMFTtop, mYShiftMFTtop, mZShiftMFTtop) : propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToVertex, matchingZ, mBz, mXShiftMFTbottom, mYShiftMFTbottom, mZShiftMFTbottom); + pt = propmuonAtPV.getPt(); + eta = propmuonAtPV.getEta(); + phi = propmuonAtPV.getPhi(); + o2::math_utils::bringTo02Pi(phi); + + propmuonAtDCA = std::atan2(mfttrack.y(), mfttrack.x()) > 0.f ? propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, mXShiftMFTtop, mYShiftMFTtop, mZShiftMFTtop) : propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, mXShiftMFTbottom, mYShiftMFTbottom, mZShiftMFTbottom); + dcaX = propmuonAtDCA.getX() - collision.posX(); + dcaY = propmuonAtDCA.getY() - collision.posY(); + dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); + cXXatDCA = propmuonAtDCA.getSigma2X(); + cYYatDCA = propmuonAtDCA.getSigma2Y(); + cXYatDCA = propmuonAtDCA.getSigmaXY(); + rAtAbsorberEnd = fwdtrack.rAtAbsorberEnd(); // this works only for GlobalMuonTrack + + float det = cXXatDCA * cYYatDCA - cXYatDCA * cXYatDCA; // determinant + if (det < 0) { + dcaXYinSigma = 999.f; + } else { + dcaXYinSigma = std::sqrt(std::fabs((dcaX * dcaX * cYYatDCA + dcaY * dcaY * cXXatDCA - 2.f * dcaX * dcaY * cXYatDCA) / det / 2.f)); // dca xy in sigma + } + sigma_dcaXY = dcaXY / dcaXYinSigma / std::sqrt(2); + + // apply dca cut here to minimize the number of calling propagateMuon. + if (maxDCAxy < dcaXY) { + return false; + } + xMFT = mfttrack.x(); yMFT = mfttrack.y(); @@ -369,39 +389,30 @@ struct skimmerPrimaryMuon { ndf_mchmft = 2.f * (mchtrack.nClusters() + nClustersMFT) - 5.f; ndf_mft = 2.f * nClustersMFT - 5.f; chi2mft = mfttrack.chi2(); - // chi2mft = mfttrack.chi2() / (2.f * nClustersMFT - 5.f); // apply chi2/ndf cut here to minimize the number of calling propagateMuon. if (maxChi2GL < fwdtrack.chi2() / ndf_mchmft) { return false; } - o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToVertex, matchingZ, mBz, mZShift); + o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToVertex, matchingZ, mBz, 0.f, 0.f, 0.f); ptMatchedMCHMID = propmuonAtPV_Matched.getPt(); etaMatchedMCHMID = propmuonAtPV_Matched.getEta(); phiMatchedMCHMID = propmuonAtPV_Matched.getPhi(); o2::math_utils::bringTo02Pi(phiMatchedMCHMID); - o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, mZShift); - float dcaX_Matched = propmuonAtDCA_Matched.getX() - collision.posX(); - float dcaY_Matched = propmuonAtDCA_Matched.getY() - collision.posY(); - float dcaXY_Matched = std::sqrt(dcaX_Matched * dcaX_Matched + dcaY_Matched * dcaY_Matched); - pDCA = mchtrack.p() * dcaXY_Matched; + o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, 0.f, 0.f, 0.f); + // float dcaXY_Matched = std::hypot(propmuonAtDCA_Matched.getX() - collision.posX(), propmuonAtDCA_Matched.getY() - collision.posY()); + pDCA = mchtrack.p() * std::hypot(propmuonAtDCA_Matched.getX() - collision.posX(), propmuonAtDCA_Matched.getY() - collision.posY()); if constexpr (withMFTCov) { auto mfttrackcov = mftCovs.rawIteratorAt(map_mfttrackcovs[mfttrack.globalIndex()]); - auto muonAtMP = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToMatchingPlane, matchingZ, mBz, mZShift); // propagated to matching plane - o2::track::TrackParCovFwd mftsaAtMP = getTrackParCovFwdShift(mfttrack, mZShift, mfttrackcov); // values at innermost update - mftsaAtMP.propagateToZhelix(matchingZ, mBz); // propagated to matching plane - // etaMatchedMFTatMP = mftsaAtMP.getEta(); - phiMatchedMFTatMP = mftsaAtMP.getPhi(); - // etaMatchedMCHMIDatMP = muonAtMP.getEta(); - phiMatchedMCHMIDatMP = muonAtMP.getPhi(); - o2::math_utils::bringTo02Pi(phiMatchedMCHMIDatMP); - o2::math_utils::bringTo02Pi(phiMatchedMFTatMP); - - o2::track::TrackParCovFwd mftsa = getTrackParCovFwdShift(mfttrack, mZShift, mfttrackcov); // values at innermost update - o2::dataformats::GlobalFwdTrack globalMuonRefit = o2::aod::fwdtrackutils::refitGlobalMuonCov(propmuonAtPV_Matched, mftsa); // this is track at IU. + // auto muonAtMP = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToMatchingPlane, matchingZ, mBz, 0.f, 0.f, 0.f); // propagated to matching plane + // o2::track::TrackParCovFwd mftsaAtMP = std::atan2(mfttrack.y(), mfttrack.x()) > 0.f ? getTrackParCovFwd3DShift(mfttrack, mXShiftMFTtop, mYShiftMFTtop, mZShiftMFTtop, mfttrackcov) : getTrackParCovFwd3DShift(mfttrack, mXShiftMFTbottom, mYShiftMFTbottom, mZShiftMFTbottom, mfttrackcov); // values at innermost update + // mftsaAtMP.propagateToZhelix(matchingZ, mBz); // propagated to matching plane + + o2::track::TrackParCovFwd mftsa = std::atan2(mfttrack.y(), mfttrack.x()) > 0.f ? getTrackParCovFwd3DShift(mfttrack, mXShiftMFTtop, mYShiftMFTtop, mZShiftMFTtop, mfttrackcov) : getTrackParCovFwd3DShift(mfttrack, mXShiftMFTbottom, mYShiftMFTbottom, mZShiftMFTbottom, mfttrackcov); // values at innermost update + o2::dataformats::GlobalFwdTrack globalMuonRefit = o2::aod::fwdtrackutils::refitGlobalMuonCov(propmuonAtPV_Matched, mftsa); // this is track at IU. auto globalMuon = o2::aod::fwdtrackutils::propagateTrackParCovFwd(globalMuonRefit, fwdtrack.trackType(), collision, propagationPoint::kToVertex, matchingZ, mBz); pt = globalMuon.getPt(); eta = globalMuon.getEta(); @@ -414,8 +425,7 @@ struct skimmerPrimaryMuon { dcaX = globalMuon.getX() - collision.posX(); dcaY = globalMuon.getY() - collision.posY(); dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); - det = cXXatDCA * cYYatDCA - cXYatDCA * cXYatDCA; // determinanat - dcaXYinSigma = 999.f; + det = cXXatDCA * cYYatDCA - cXYatDCA * cXYatDCA; // determinant if (det < 0) { dcaXYinSigma = 999.f; } else { @@ -428,7 +438,7 @@ struct skimmerPrimaryMuon { dphi = phiMatchedMCHMID - phi; o2::math_utils::bringToPMPi(dphi); - chi2IP = getFwdChi2IP(fwdtrack, collision, mBz, mZShift); + chi2IP = std::atan2(mfttrack.y(), mfttrack.x()) > 0.f ? getFwdChi2IP(fwdtrack, collision, mBz, mXShiftMFTtop, mYShiftMFTtop, mZShiftMFTtop) : getFwdChi2IP(fwdtrack, collision, mBz, mXShiftMFTbottom, mYShiftMFTbottom, mZShiftMFTbottom); if (std::sqrt(std::pow(deta / maxDEta, 2) + std::pow(dphi / maxDPhi, 2)) > 1.f) { return false; @@ -440,14 +450,14 @@ struct skimmerPrimaryMuon { const auto& fwdcov = propmuonAtPV.getCovariances(); // covatiance matrix at PV - auto globalMuonManual = getTrackParCovFwdShiftManual( + auto globalMuonManual = getTrackParCovFwd3DShiftManual( propmuonAtPV.getX(), propmuonAtPV.getY(), propmuonAtPV.getPhi(), propmuonAtPV.getTgl(), propmuonAtPV.getInvQPt() / sfPt, fwdcov(0, 0), fwdcov(1, 0), fwdcov(1, 1), fwdcov(2, 0), fwdcov(2, 1), fwdcov(2, 2), fwdcov(3, 0), fwdcov(3, 1), fwdcov(3, 2), fwdcov(3, 3), fwdcov(4, 0) / sfPt, fwdcov(4, 1) / sfPt, fwdcov(4, 2) / sfPt, fwdcov(4, 3) / sfPt, fwdcov(4, 4) / sfPt / sfPt, - propmuonAtPV.getZ(), 0.0, fwdtrack.chi2()); + propmuonAtPV.getZ(), 0.0, 0.0, 0.0, fwdtrack.chi2()); auto globalMuonManualAtZPV = o2::aod::fwdtrackutils::propagateTrackParCovFwd(globalMuonManual, fwdtrack.trackType(), collision, propagationPoint::kToDCA, matchingZ, mBz); @@ -471,24 +481,29 @@ struct skimmerPrimaryMuon { cXYatDCA = cXYatDCA + resPVXY; cYYatDCA = cYYatDCA + resPVYY; - det = cXXatDCA * cYYatDCA - cXYatDCA * cXYatDCA; // determinanat - dcaXYinSigma = 999.f; + det = cXXatDCA * cYYatDCA - cXYatDCA * cXYatDCA; // determinant if (det < 0) { dcaXYinSigma = 999.f; } else { dcaXYinSigma = std::sqrt(std::fabs((dcaX * dcaX * cYYatDCA + dcaY * dcaY * cXXatDCA - 2.f * dcaX * dcaY * cXYatDCA) / det / 2.f)); // dca xy in sigma } - sigma_dcaXY = dcaXY / dcaXYinSigma; + sigma_dcaXY = dcaXY / dcaXYinSigma / std::sqrt(2); chi2IP = getFwdChi2IP(globalMuonManual, collision, mBz); } } else if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { - o2::dataformats::GlobalFwdTrack propmuonAtRabs = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToRabs, matchingZ, mBz, mZShift); // this is necessary only for MuonStandaloneTrack + propmuonAtPV = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToVertex, matchingZ, mBz, 0.f, 0.f, 0.f); + pt = propmuonAtPV.getPt(); + eta = propmuonAtPV.getEta(); + phi = propmuonAtPV.getPhi(); + o2::math_utils::bringTo02Pi(phi); + + o2::dataformats::GlobalFwdTrack propmuonAtRabs = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToRabs, matchingZ, mBz, 0.f, 0.f, 0.f); // this is necessary only for MuonStandaloneTrack float xAbs = propmuonAtRabs.getX(); float yAbs = propmuonAtRabs.getY(); rAtAbsorberEnd = std::sqrt(xAbs * xAbs + yAbs * yAbs); // Redo propagation only for muon tracks // propagation of MFT tracks alredy done in reconstruction - o2::dataformats::GlobalFwdTrack propmuonAtDCA = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, mZShift); + propmuonAtDCA = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, 0.f, 0.f, 0.f); cXXatDCA = propmuonAtDCA.getSigma2X(); cYYatDCA = propmuonAtDCA.getSigma2Y(); cXYatDCA = propmuonAtDCA.getSigmaXY(); @@ -497,14 +512,13 @@ struct skimmerPrimaryMuon { dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); pDCA = fwdtrack.p() * dcaXY; - det = cXXatDCA * cYYatDCA - cXYatDCA * cXYatDCA; // determinanat - dcaXYinSigma = 999.f; + float det = cXXatDCA * cYYatDCA - cXYatDCA * cXYatDCA; // determinant if (det < 0) { dcaXYinSigma = 999.f; } else { dcaXYinSigma = std::sqrt(std::fabs((dcaX * dcaX * cYYatDCA + dcaY * dcaY * cXXatDCA - 2.f * dcaX * dcaY * cXYatDCA) / det / 2.f)); // dca xy in sigma } - sigma_dcaXY = dcaXY / dcaXYinSigma; + sigma_dcaXY = dcaXY / dcaXYinSigma / std::sqrt(2); } else { return false; } @@ -516,10 +530,6 @@ struct skimmerPrimaryMuon { if constexpr (fillTable) { float dpt = (ptMatchedMCHMID - pt) / pt; - // float detaMP = etaMatchedMCHMIDatMP - etaMatchedMFTatMP; - // float dphiMP = phiMatchedMCHMIDatMP - phiMatchedMFTatMP; - // o2::math_utils::bringToPMPi(dphiMP); - bool isAssociatedToMPC = fwdtrack.collisionId() == collision.globalIndex(); // LOGF(info, "isAmbiguous = %d, isAssociatedToMPC = %d, fwdtrack.globalIndex() = %d, fwdtrack.collisionId() = %d, collision.globalIndex() = %d", isAmbiguous, isAssociatedToMPC, fwdtrack.globalIndex(), fwdtrack.collisionId(), collision.globalIndex()); @@ -572,8 +582,13 @@ struct skimmerPrimaryMuon { fRegistry.fill(HIST("MFTMCHMID/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 1e+4); // convert cm to um fRegistry.fill(HIST("MFTMCHMID/hLog10Chi2IP"), std::log10(chi2IP)); fRegistry.fill(HIST("MFTMCHMID/hSqrtChi2IP"), std::sqrt(chi2IP)); - fRegistry.fill(HIST("MFTMCHMID/hDCAx_PosZ"), collision.posZ(), dcaX); - fRegistry.fill(HIST("MFTMCHMID/hDCAy_PosZ"), collision.posZ(), dcaY); + if (std::atan2(yMFT, xMFT) > 0.f) { + fRegistry.fill(HIST("MFTMCHMID/hDCAx_PosZ_MFTtop"), collision.posZ(), dcaX); + fRegistry.fill(HIST("MFTMCHMID/hDCAy_PosZ_MFTtop"), collision.posZ(), dcaY); + } else { + fRegistry.fill(HIST("MFTMCHMID/hDCAx_PosZ_MFTbottom"), collision.posZ(), dcaX); + fRegistry.fill(HIST("MFTMCHMID/hDCAy_PosZ_MFTbottom"), collision.posZ(), dcaY); + } fRegistry.fill(HIST("MFTMCHMID/hDCAx_Phi"), std::atan2(yMFT, xMFT), dcaX); fRegistry.fill(HIST("MFTMCHMID/hDCAy_Phi"), std::atan2(yMFT, xMFT), dcaY); fRegistry.fill(HIST("MFTMCHMID/hMeanDCAx"), fwdtrack.x(), fwdtrack.y(), dcaX); @@ -627,17 +642,6 @@ struct skimmerPrimaryMuon { // LOGF(info, "stanadalone: muon.globalIndex() = %d, muon.chi2MatchMCHMFT() = %f", muon.globalIndex(), muon.chi2MatchMCHMFT()); // LOGF(info, "muons_per_MCHMID.size() = %d", muons_per_MCHMID.size()); - // o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToVertex, matchingZ, mBz, mZShift); - // float etaMatchedMCHMID = propmuonAtPV_Matched.getEta(); - // float phiMatchedMCHMID = propmuonAtPV_Matched.getPhi(); - // o2::math_utils::bringTo02Pi(phiMatchedMCHMID); - - // o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, mZShift); - // float dcaX_Matched = propmuonAtDCA_Matched.getX() - collision.posX(); - // float dcaY_Matched = propmuonAtDCA_Matched.getY() - collision.posY(); - // float dcaXY_Matched = std::sqrt(dcaX_Matched * dcaX_Matched + dcaY_Matched * dcaY_Matched); - // float pDCA = fwdtrack.p() * dcaXY_Matched; - float min_chi2MatchMCHMFT = 1e+10; std::tuple tupleId_at_min_chi2mftmch; std::vector vec_chi2tmp; @@ -653,41 +657,6 @@ struct skimmerPrimaryMuon { continue; } - // if (muon_tmp.chi2() < 0.f || muon_tmp.chi2MatchMCHMFT() < 0.f || muon_tmp.chi2MatchMCHMID() < 0.f || mfttrack.chi2() < 0.f) { // reject negative chi2, i.e. wrong. - // continue; - // } - - // o2::dataformats::GlobalFwdTrack propmuonAtPV = propagateMuon(muon_tmp, muon_tmp, collision, propagationPoint::kToVertex, matchingZ, mBz, mZShift); - // float pt = propmuonAtPV.getPt(); - // float eta = propmuonAtPV.getEta(); - // float phi = propmuonAtPV.getPhi(); - // o2::math_utils::bringTo02Pi(phi); - - // if (refitGlobalMuon) { - // pt = propmuonAtPV_Matched.getP() * std::sin(2.f * std::atan(std::exp(-eta))); - // } - - // float deta = etaMatchedMCHMID - eta; - // float dphi = phiMatchedMCHMID - phi; - // o2::math_utils::bringToPMPi(dphi); - // int ndf = 2 * (mchtrack.nClusters() + mfttrack.nClusters()) - 5; - - // float dcaX = propmuonAtPV.getX() - collision.posX(); - // float dcaY = propmuonAtPV.getY() - collision.posY(); - // float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); - - // if (cfgApplyPreselectionInBestMatch) { - // if (!isSelected(pt, eta, muon_tmp.rAtAbsorberEnd(), pDCA, muon_tmp.chi2() / ndf, muon_tmp.trackType(), dcaXY)) { - // continue; - // } - // if (std::sqrt(std::pow(deta / maxDEta, 2) + std::pow(dphi / maxDPhi, 2)) > 1.f) { - // continue; - // } - // if (muon_tmp.chi2MatchMCHMFT() > maxMatchingChi2MCHMFT) { - // continue; - // } - // } - vec_chi2tmp.emplace_back(muon_tmp.chi2MatchMCHMFT()); if (0.f < muon_tmp.chi2MatchMCHMFT() && muon_tmp.chi2MatchMCHMFT() < min_chi2MatchMCHMFT) { min_chi2MatchMCHMFT = muon_tmp.chi2MatchMCHMFT(); diff --git a/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuonQC.cxx b/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuonQC.cxx deleted file mode 100644 index 246634a975d..00000000000 --- a/PWGEM/Dilepton/TableProducer/skimmerPrimaryMuonQC.cxx +++ /dev/null @@ -1,797 +0,0 @@ -// 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. - -/// \brief write relevant information for muons. -/// \author daiki.sekihata@cern.ch - -#include "PWGEM/Dilepton/DataModel/dileptonTables.h" - -#include "Common/Core/fwdtrackUtilities.h" -#include "Common/DataModel/CollisionAssociationTables.h" -#include "Common/DataModel/EventSelection.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) -#include -#include - -#include -#include -#include -#include -#include -#include - -using namespace o2; -using namespace o2::soa; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::constants::physics; -using namespace o2::aod::fwdtrackutils; - -struct skimmerPrimaryMuonQC { - using MyCollisions = soa::Join; - using MyCollisionsWithSWT = soa::Join; - - using MyFwdTracks = soa::Join; // muon tracks are repeated. i.e. not exclusive. - using MyFwdTrack = MyFwdTracks::iterator; - - using MyFwdTracksMC = soa::Join; - using MyFwdTrackMC = MyFwdTracksMC::iterator; - - using MFTTracksMC = soa::Join; - using MFTTrackMC = MFTTracksMC::iterator; - - Produces emprimarymuons; - Produces emprimarymuonscov; - - // Configurables - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - Configurable fillQAHistograms{"fillQAHistograms", false, "flag to fill QA histograms"}; - - // for z shift for propagation - Configurable cfgApplyZShiftFromCCDB{"cfgApplyZShiftFromCCDB", false, "flag to apply z shift"}; - Configurable cfgZShiftPath{"cfgZShiftPath", "Users/m/mcoquet/ZShift", "CCDB path for z shift to apply to forward tracks"}; - Configurable cfgManualZShift{"cfgManualZShift", 0, "manual z-shift for propagation of global muon to PV"}; - Configurable matchingZ{"matchingZ", -77.5, "z position where matching is performed"}; - Configurable refitGlobalMuon{"refitGlobalMuon", true, "flag to refit global muon"}; - - struct : ConfigurableGroup { // tight cut - std::string prefix = "tagMuonCut"; - Configurable minPt{"minPt", 0.8, "min pt for muon"}; - Configurable maxPt{"maxPt", 1e+10, "max pt for muon"}; - Configurable minEta{"minEta", -3.6, "min. eta acceptance for MFT-MCH-MID"}; - Configurable maxEta{"maxEta", -2.5, "max. eta acceptance for MFT-MCH-MID"}; - Configurable minRabs{"minRabs", 27.6, "min. R at absorber end for global muon (min. eta = -3.6)"}; // std::tan(2.f * std::atan(std::exp(- -3.6)) ) * -505. = 27.6 - Configurable maxRabs{"maxRabs", 89.5, "max. R at absorber end"}; - Configurable maxDCAxy{"maxDCAxy", 0.06, "max. DCAxy for global muons"}; - Configurable maxMatchingChi2MCHMFT{"maxMatchingChi2MCHMFT", 40.f, "max. chi2 for MCH-MFT matching"}; - Configurable maxChi2{"maxChi2", 4.f, "max. chi2/ndf for global muon"}; - // Configurable minNclsMFT{"minNclsMFT", 5, "min ncluster of MFT"}; - // Configurable minNclsMCH{"minNclsMCH", 5, "min ncluster of MCH"}; - Configurable maxDEta{"maxDEta", 0.08, "max. deta between MFT-MCH-MID and MCH-MID"}; - Configurable maxDPhi{"maxDPhi", 0.08, "max. dphi between MFT-MCH-MID and MCH-MID"}; - } tagMuonCut; - - struct : ConfigurableGroup { // loose cut - std::string prefix = "probeMuonCut"; - Configurable minPt{"minPt", 0.01, "min pt for muon"}; - Configurable maxPt{"maxPt", 1e+10, "max pt for muon"}; - Configurable minEtaSA{"minEtaSA", -4.0, "min. eta acceptance for MFT-MCH"}; - Configurable maxEtaSA{"maxEtaSA", -2.5, "max. eta acceptance for MFT-MCH"}; - Configurable minEtaGL{"minEtaGL", -3.6, "min. eta acceptance for MFT-MCH-MID"}; - Configurable maxEtaGL{"maxEtaGL", -2.5, "max. eta acceptance for MFT-MCH-MID"}; - Configurable minRabs{"minRabs", 17.6, "min. R at absorber end for global muon (min. eta = -3.6)"}; // std::tan(2.f * std::atan(std::exp(- -3.6)) ) * -505. = 27.6 - Configurable midRabs{"midRabs", 26.5, "middle R at absorber end for pDCA cut"}; - Configurable maxRabs{"maxRabs", 89.5, "max. R at absorber end"}; - Configurable maxDCAxy{"maxDCAxy", 1.f, "max. DCAxy for global muons"}; - Configurable maxPDCAforLargeR{"maxPDCAforLargeR", 324.f, "max. pDCA for large R at absorber end"}; - Configurable maxPDCAforSmallR{"maxPDCAforSmallR", 594.f, "max. pDCA for small R at absorber end"}; - Configurable maxMatchingChi2MCHMFT{"maxMatchingChi2MCHMFT", 100, "max. chi2 for MCH-MFT matching"}; - Configurable maxChi2{"maxChi2", 1e+10, "max. chi2/ndf for global muon"}; - // Configurable minNclsMFT{"minNclsMFT", 5, "min ncluster of MFT"}; - // Configurable minNclsMCH{"minNclsMCH", 5, "min ncluster of MCH"}; - Configurable maxDEta{"maxDEta", 1e+10, "max. deta between MFT-MCH-MID and MCH-MID"}; - Configurable maxDPhi{"maxDPhi", 1e+10, "max. dphi between MFT-MCH-MID and MCH-MID"}; - } probeMuonCut; - - struct : ConfigurableGroup { - std::string prefix = "pairCuts"; - Configurable minMass{"minMass", 0.21, "min mass"}; - Configurable maxMass{"maxMass", 0.30, "max mass"}; - } pairCuts; - - o2::ccdb::CcdbApi ccdbApi; - Service ccdb; - int mRunNumber = 0; - float mBz = 0; - float mZShift = 0; - - HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; - // static constexpr std::string_view muon_types[5] = {"MFTMCHMID/", "MFTMCHMIDOtherMatch/", "MFTMCH/", "MCHMID/", "MCH/"}; - - void init(InitContext&) - { - ccdb->setURL(ccdburl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(false); - ccdbApi.init(ccdburl); - - if (fillQAHistograms) { - addHistograms(); - } - mRunNumber = 0; - mBz = 0; - mZShift = 0; - } - - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) - { - if (mRunNumber == bc.runNumber()) { - return; - } - mRunNumber = bc.runNumber(); - - std::map metadata; - auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, mRunNumber); - auto ts = soreor.first; - auto grpmag = ccdbApi.retrieveFromTFileAny(grpmagPath, metadata, ts); - o2::base::Propagator::initFieldFromGRP(grpmag); - if (!o2::base::GeometryManager::isGeometryLoaded()) { - ccdb->get(geoPath); - } - o2::mch::TrackExtrap::setField(); - const double centerMFT[3] = {0, 0, -61.4}; - o2::field::MagneticField* field = static_cast(TGeoGlobalMagField::Instance()->GetField()); - mBz = field->getBz(centerMFT); // Get field at centre of MFT - LOGF(info, "Bz at center of MFT = %f kZG", mBz); - - if (cfgApplyZShiftFromCCDB) { - auto* zShift = ccdb->getForTimeStamp>(cfgZShiftPath, bc.timestamp()); - if (zShift != nullptr && !zShift->empty()) { - LOGF(info, "reading z shift %f from %s", (*zShift)[0], cfgZShiftPath.value); - mZShift = (*zShift)[0]; - } else { - LOGF(info, "z shift is not found in ccdb path %s. set to 0 cm", cfgZShiftPath.value); - mZShift = 0; - } - } else { - LOGF(info, "z shift is manually set to %f cm", cfgManualZShift.value); - mZShift = cfgManualZShift; - } - } - - void addHistograms() - { - // auto hMuonType = fRegistry.add("hMuonType", "muon type", kTH1F, {{5, -0.5f, 4.5f}}, false); - // hMuonType->GetXaxis()->SetBinLabel(1, "MFT-MCH-MID (global muon)"); - // hMuonType->GetXaxis()->SetBinLabel(2, "MFT-MCH-MID (global muon other match)"); - // hMuonType->GetXaxis()->SetBinLabel(3, "MFT-MCH"); - // hMuonType->GetXaxis()->SetBinLabel(4, "MCH-MID"); - // hMuonType->GetXaxis()->SetBinLabel(5, "MCH standalone"); - - // fRegistry.add("MFTMCHMID/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{200, 0.0f, 10}}, false); - // fRegistry.add("MFTMCHMID/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {80, -4.f, -2.f}}, false); - // fRegistry.add("MFTMCHMID/hEtaPhi_MatchedMCHMID", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {80, -4.f, -2.f}}, false); - // fRegistry.add("MFTMCHMID/hDeltaPt_Pt", "#Deltap_{T}/p_{T} vs. p_{T};p_{T}^{gl} (GeV/c);(p_{T}^{sa} - p_{T}^{gl})/p_{T}^{gl}", kTH2F, {{100, 0, 10}, {200, -0.5, +0.5}}, false); - // fRegistry.add("MFTMCHMID/hDeltaEta_Pt", "#Delta#eta vs. p_{T};p_{T}^{gl} (GeV/c);#Delta#eta", kTH2F, {{100, 0, 10}, {200, -0.5, +0.5}}, false); - // fRegistry.add("MFTMCHMID/hDeltaPhi_Pt", "#Delta#varphi vs. p_{T};p_{T}^{gl} (GeV/c);#Delta#varphi (rad.)", kTH2F, {{100, 0, 10}, {200, -0.5, +0.5}}, false); - // fRegistry.add("MFTMCHMID/hSign", "sign;sign", kTH1F, {{3, -1.5, +1.5}}, false); - // fRegistry.add("MFTMCHMID/hNclusters", "Nclusters;Nclusters", kTH1F, {{21, -0.5f, 20.5}}, false); - // fRegistry.add("MFTMCHMID/hNclustersMFT", "NclustersMFT;Nclusters MFT", kTH1F, {{11, -0.5f, 10.5}}, false); - // fRegistry.add("MFTMCHMID/hRatAbsorberEnd", "R at absorber end;R at absorber end (cm)", kTH1F, {{100, 0.0f, 100}}, false); - // fRegistry.add("MFTMCHMID/hPDCA_Rabs", "pDCA vs. Rabs;R at absorber end (cm);p #times DCA (GeV/c #upoint cm)", kTH2F, {{100, 0, 100}, {100, 0.0f, 1000}}, false); - // fRegistry.add("MFTMCHMID/hChi2", "chi2;chi2/ndf", kTH1F, {{200, 0.0f, 20}}, false); - // fRegistry.add("MFTMCHMID/hChi2MFT", "chi2 MFT;chi2 MFT/ndf", kTH1F, {{200, 0.0f, 20}}, false); - // fRegistry.add("MFTMCHMID/hChi2MatchMCHMID", "chi2 match MCH-MID;chi2", kTH1F, {{200, 0.0f, 20}}, false); - // fRegistry.add("MFTMCHMID/hChi2MatchMCHMFT", "chi2 match MCH-MFT;chi2", kTH1F, {{200, 0.0f, 100}}, false); - // fRegistry.add("MFTMCHMID/hDCAxy2D", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", kTH2F, {{200, -1, 1}, {200, -1, +1}}, false); - // fRegistry.add("MFTMCHMID/hDCAxy2DinSigma", "DCA x vs. y in sigma;DCA_{x} (#sigma);DCA_{y} (#sigma)", kTH2F, {{200, -10, 10}, {200, -10, +10}}, false); - // fRegistry.add("MFTMCHMID/hDCAxy", "DCAxy;DCA_{xy} (cm);", kTH1F, {{100, 0, 1}}, false); - // fRegistry.add("MFTMCHMID/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{100, 0, 1}, {200, -0.1, 0.1}}, false); - // fRegistry.add("MFTMCHMID/hDCAxyinSigma", "DCAxy in sigma;DCA_{xy} (#sigma);", kTH1F, {{100, 0, 10}}, false); - // fRegistry.add("MFTMCHMID/hDCAx_PosZ", "DCAx vs. posZ;Z_{vtx} (cm);DCA_{x} (cm)", kTH2F, {{200, -10, +10}, {400, -0.2, +0.2}}, false); - // fRegistry.add("MFTMCHMID/hDCAy_PosZ", "DCAy vs. posZ;Z_{vtx} (cm);DCA_{y} (cm)", kTH2F, {{200, -10, +10}, {400, -0.2, +0.2}}, false); - // fRegistry.add("MFTMCHMID/hDCAx_Phi", "DCAx vs. #varphi;#varphi (rad.);DCA_{x} (cm)", kTH2F, {{90, 0, 2 * M_PI}, {400, -0.2, +0.2}}, false); - // fRegistry.add("MFTMCHMID/hDCAy_Phi", "DCAy vs. #varphi;#varphi (rad.);DCA_{y} (cm)", kTH2F, {{90, 0, 2 * M_PI}, {400, -0.2, +0.2}}, false); - // fRegistry.add("MFTMCHMID/hNmu", "#mu multiplicity;N_{#mu} per collision", kTH1F, {{21, -0.5, 20.5}}, false); - - // fRegistry.addClone("MFTMCHMID/", "MCHMID/"); - // fRegistry.add("MFTMCHMID/hDCAxResolutionvsPt", "DCA_{x} vs. p_{T};p_{T} (GeV/c);DCA_{x} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 500}}, false); - // fRegistry.add("MFTMCHMID/hDCAyResolutionvsPt", "DCA_{y} vs. p_{T};p_{T} (GeV/c);DCA_{y} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 500}}, false); - // fRegistry.add("MFTMCHMID/hDCAxyResolutionvsPt", "DCA_{xy} vs. p_{T};p_{T} (GeV/c);DCA_{y} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 500}}, false); - // fRegistry.add("MCHMID/hDCAxResolutionvsPt", "DCA_{x} vs. p_{T};p_{T} (GeV/c);DCA_{x} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 5e+5}}, false); - // fRegistry.add("MCHMID/hDCAyResolutionvsPt", "DCA_{y} vs. p_{T};p_{T} (GeV/c);DCA_{y} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 5e+5}}, false); - // fRegistry.add("MCHMID/hDCAxyResolutionvsPt", "DCA_{xy} vs. p_{T};p_{T} (GeV/c);DCA_{y} resolution (#mum);", kTH2F, {{100, 0, 10.f}, {500, 0, 5e+5}}, false); - - fRegistry.add("Pair/uls/gl_gl/hMvsPt", "dimuon;m_{#mu#mu} (GeV/c^{2});p_{T,#mu} (GeV/c);", kTH2F, {{380, 0.2, 4.f}, {100, 0, 10}}, false); - fRegistry.add("Pair/uls/gl_sa/hMvsPt", "dimuon;m_{#mu#mu} (GeV/c^{2});p_{T,#mu} (GeV/c);", kTH2F, {{380, 0.2, 4.f}, {100, 0, 10}}, false); - } - - struct Muon { - int globalIndex = -1; - int collisionId = -1; - int matchMCHTrackId = -1; - int matchMFTTrackId = -1; - uint8_t trackType = 99; - int8_t sign = 0; - float pt = 0; - float eta = 0; - float phi = 0; - float dcaX = 0; // in cm - float dcaY = 0; // in cm - float dcaXY = 0; // in cm - float cXX = 0; - float cYY = 0; - float cXY = 0; - float rAtAbsorberEnd = 0; - float pDCA = 0; - float chi2ndf = 0; - float chi2MatchMCHMID = 0; - - // only for global muons - float ptMatchedMCHMID = 0; - float etaMatchedMCHMID = 0; - float phiMatchedMCHMID = 0; - float chi2MatchMCHMFT = 0; - float chi2mft = -999.f; - uint64_t mftClusterSizesAndTrackFlags = 0; - }; - - bool isSelected(Muon const& muon) - { - if (muon.pt < probeMuonCut.minPt || probeMuonCut.maxPt < muon.pt) { - return false; - } - - if (muon.rAtAbsorberEnd < probeMuonCut.minRabs || probeMuonCut.maxRabs < muon.rAtAbsorberEnd) { - return false; - } - - if (muon.trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { - if (muon.eta < probeMuonCut.minEtaGL || probeMuonCut.maxEtaGL < muon.eta) { - return false; - } - if (probeMuonCut.maxDCAxy < muon.dcaXY) { - return false; - } - if (probeMuonCut.maxMatchingChi2MCHMFT < muon.chi2MatchMCHMFT) { - return false; - } - } else if (muon.trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { - if (muon.eta < probeMuonCut.minEtaSA || probeMuonCut.maxEtaSA < muon.eta) { - return false; - } - if (muon.rAtAbsorberEnd < probeMuonCut.midRabs ? muon.pDCA > probeMuonCut.maxPDCAforSmallR : muon.pDCA > probeMuonCut.maxPDCAforLargeR) { - return false; - } - } else { - return false; - } - - return true; - } - - bool isSelectedTight(Muon const& muon) - { - if (muon.trackType != static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { // tag muon should be tight. - return false; - } - - if (muon.pt < tagMuonCut.minPt || tagMuonCut.maxPt < muon.pt) { - return false; - } - - if (muon.rAtAbsorberEnd < tagMuonCut.minRabs || tagMuonCut.maxRabs < muon.rAtAbsorberEnd) { - return false; - } - - if (muon.chi2ndf < 0.f || tagMuonCut.maxChi2 < muon.chi2ndf) { - return false; - } - - if (muon.eta < tagMuonCut.minEta || tagMuonCut.maxEta < muon.eta) { - return false; - } - - if (tagMuonCut.maxDCAxy < muon.dcaXY) { - return false; - } - - if (tagMuonCut.maxMatchingChi2MCHMFT < muon.chi2MatchMCHMFT) { - return false; - } - - float deta = muon.etaMatchedMCHMID - muon.eta; - float dphi = muon.phiMatchedMCHMID - muon.phi; - // LOGF(info, "muon.trackType = %d, deta = %f, dphi = %f", muon.trackType, deta, dphi); - if (std::sqrt(std::pow(deta / tagMuonCut.maxDEta, 2) + std::pow(dphi / tagMuonCut.maxDPhi, 2)) > 1.f) { - return false; - } - - return true; - } - - template - bool fillMuonInfo(TCollision const& collision, TFwdTrack fwdtrack) - { - if (fwdtrack.trackType() != static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) && fwdtrack.trackType() != static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { - return false; - } - - if (fwdtrack.chi2MatchMCHMID() < 0.f) { // this should never happen. only for protection. - return false; - } - - if (fwdtrack.chi2() < 0.f) { // this should never happen. only for protection. - return false; - } - - o2::dataformats::GlobalFwdTrack propmuonAtPV = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToVertex, matchingZ, mBz, mZShift); - float pt = propmuonAtPV.getPt(); - float eta = propmuonAtPV.getEta(); - float phi = propmuonAtPV.getPhi(); - o2::math_utils::bringTo02Pi(phi); - - float dcaX = propmuonAtPV.getX() - collision.posX(); - float dcaY = propmuonAtPV.getY() - collision.posY(); - float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); - float rAtAbsorberEnd = fwdtrack.rAtAbsorberEnd(); // this works only for GlobalMuonTrack - float cXX = propmuonAtPV.getSigma2X(); - float cYY = propmuonAtPV.getSigma2Y(); - float cXY = propmuonAtPV.getSigmaXY(); - - float pDCA = propmuonAtPV.getP() * dcaXY; - int nClustersMFT = 0; - float ptMatchedMCHMID = propmuonAtPV.getPt(); - float etaMatchedMCHMID = propmuonAtPV.getEta(); - float phiMatchedMCHMID = propmuonAtPV.getPhi(); - o2::math_utils::bringTo02Pi(phiMatchedMCHMID); - float chi2mft = -999.f; - uint64_t mftClusterSizesAndTrackFlags = 0; - int ndf_mchmft = 1; - - if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { - if (fwdtrack.chi2MatchMCHMFT() < 0.f) { - return false; - } // Users have to decide the best match between MFT and MCH-MID at analysis level. The same global muon is repeatedly stored. - - auto mchtrack = fwdtrack.template matchMCHTrack_as(); // MCH-MID - auto mfttrack = fwdtrack.template matchMFTTrack_as(); // MFTsa - if (mfttrack.chi2() < 0.f) { - return false; - } - - if constexpr (isMC) { - if (!mfttrack.has_mcParticle() || !mchtrack.has_mcParticle() || !fwdtrack.has_mcParticle()) { - return false; - } - // auto mcParticle_MFTMCHMID = fwdtrack.template mcParticle_as(); // this is identical to mcParticle_MCHMID - auto mcParticle_MCHMID = mchtrack.template mcParticle_as(); // this is identical to mcParticle_MFTMCHMID - auto mcParticle_MFT = mfttrack.template mcParticle_as(); - } - - nClustersMFT = mfttrack.nClusters(); - mftClusterSizesAndTrackFlags = mfttrack.mftClusterSizesAndTrackFlags(); - ndf_mchmft = 2.f * (mchtrack.nClusters() + nClustersMFT) - 5.f; - chi2mft = mfttrack.chi2(); - - o2::dataformats::GlobalFwdTrack propmuonAtPV_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToVertex, matchingZ, mBz, mZShift); - ptMatchedMCHMID = propmuonAtPV_Matched.getPt(); - etaMatchedMCHMID = propmuonAtPV_Matched.getEta(); - phiMatchedMCHMID = propmuonAtPV_Matched.getPhi(); - o2::math_utils::bringTo02Pi(phiMatchedMCHMID); - - o2::dataformats::GlobalFwdTrack propmuonAtDCA_Matched = propagateMuon(mchtrack, mchtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, mZShift); - float dcaX_Matched = propmuonAtDCA_Matched.getX() - collision.posX(); - float dcaY_Matched = propmuonAtDCA_Matched.getY() - collision.posY(); - float dcaXY_Matched = std::sqrt(dcaX_Matched * dcaX_Matched + dcaY_Matched * dcaY_Matched); - pDCA = mchtrack.p() * dcaXY_Matched; - - if (refitGlobalMuon) { - pt = propmuonAtPV_Matched.getP() * std::sin(2.f * std::atan(std::exp(-eta))); - } - } else if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { - o2::dataformats::GlobalFwdTrack propmuonAtRabs = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToRabs, matchingZ, mBz, mZShift); // this is necessary only for MuonStandaloneTrack - float xAbs = propmuonAtRabs.getX(); - float yAbs = propmuonAtRabs.getY(); - rAtAbsorberEnd = std::sqrt(xAbs * xAbs + yAbs * yAbs); // Redo propagation only for muon tracks // propagation of MFT tracks alredy done in reconstruction - ndf_mchmft = 1; // chi2 is already normalized by ndf for MCH-MID tracks. - - o2::dataformats::GlobalFwdTrack propmuonAtDCA = propagateMuon(fwdtrack, fwdtrack, collision, propagationPoint::kToDCA, matchingZ, mBz, mZShift); - cXX = propmuonAtDCA.getSigma2X(); - cYY = propmuonAtDCA.getSigma2Y(); - cXY = propmuonAtDCA.getSigmaXY(); - dcaX = propmuonAtDCA.getX() - collision.posX(); - dcaY = propmuonAtDCA.getY() - collision.posY(); - dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); - pDCA = fwdtrack.p() * dcaXY; - } else { - return false; - } - - Muon muon; - muon.globalIndex = fwdtrack.globalIndex(); - muon.collisionId = collision.globalIndex(); - muon.trackType = fwdtrack.trackType(); - muon.sign = fwdtrack.sign(); - muon.pt = pt; - muon.eta = eta; - muon.phi = phi; - muon.dcaX = dcaX; - muon.dcaY = dcaY; - muon.dcaXY = dcaXY; - muon.cXX = cXX; - muon.cYY = cYY; - muon.cXY = cXY; - muon.rAtAbsorberEnd = rAtAbsorberEnd; - muon.pDCA = pDCA; - muon.chi2ndf = fwdtrack.chi2() / ndf_mchmft; - muon.ptMatchedMCHMID = ptMatchedMCHMID; - muon.etaMatchedMCHMID = etaMatchedMCHMID; - muon.phiMatchedMCHMID = phiMatchedMCHMID; - muon.chi2mft = chi2mft; - muon.matchMCHTrackId = fwdtrack.matchMCHTrackId(); - muon.matchMFTTrackId = fwdtrack.matchMFTTrackId(); - muon.mftClusterSizesAndTrackFlags = mftClusterSizesAndTrackFlags; - - vecMuons.emplace_back(muon); - return true; - } - - template - bool fillFwdTrackTable(TCollision const& collision, TMuon const& muon, TFwdTrack const& fwdtrack) - { - emprimarymuons(collision.globalIndex(), fwdtrack.globalIndex(), fwdtrack.matchMFTTrackId(), fwdtrack.matchMCHTrackId(), fwdtrack.trackType(), - muon.pt, muon.eta, muon.phi, fwdtrack.sign(), muon.dcaX, muon.dcaY, muon.cXX, muon.cYY, muon.cXY, muon.ptMatchedMCHMID, muon.etaMatchedMCHMID, muon.phiMatchedMCHMID, - fwdtrack.nClusters(), muon.pDCA, muon.rAtAbsorberEnd, fwdtrack.chi2(), fwdtrack.chi2MatchMCHMID(), fwdtrack.chi2MatchMCHMFT(), 9999.f, - fwdtrack.mchBitMap(), fwdtrack.midBitMap(), fwdtrack.midBoards(), muon.mftClusterSizesAndTrackFlags, muon.chi2mft, true, false); - - // if (fillQAHistograms) { - // fRegistry.fill(HIST("hMuonType"), fwdtrack.trackType()); - // if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { - // fRegistry.fill(HIST("MFTMCHMID/hPt"), pt); - // fRegistry.fill(HIST("MFTMCHMID/hEtaPhi"), phi, eta); - // fRegistry.fill(HIST("MFTMCHMID/hEtaPhi_MatchedMCHMID"), phiMatchedMCHMID, etaMatchedMCHMID); - // fRegistry.fill(HIST("MFTMCHMID/hDeltaPt_Pt"), pt, dpt); - // fRegistry.fill(HIST("MFTMCHMID/hDeltaEta_Pt"), pt, deta); - // fRegistry.fill(HIST("MFTMCHMID/hDeltaPhi_Pt"), pt, dphi); - // fRegistry.fill(HIST("MFTMCHMID/hSign"), fwdtrack.sign()); - // fRegistry.fill(HIST("MFTMCHMID/hNclusters"), fwdtrack.nClusters()); - // fRegistry.fill(HIST("MFTMCHMID/hNclustersMFT"), nClustersMFT); - // fRegistry.fill(HIST("MFTMCHMID/hPDCA_Rabs"), rAtAbsorberEnd, pDCA); - // fRegistry.fill(HIST("MFTMCHMID/hRatAbsorberEnd"), rAtAbsorberEnd); - // fRegistry.fill(HIST("MFTMCHMID/hChi2"), fwdtrack.chi2() / ndf_mchmft); - // fRegistry.fill(HIST("MFTMCHMID/hChi2MFT"), chi2mft / ndf_mft); - // fRegistry.fill(HIST("MFTMCHMID/hChi2MatchMCHMID"), fwdtrack.chi2MatchMCHMID()); - // fRegistry.fill(HIST("MFTMCHMID/hChi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT()); - // fRegistry.fill(HIST("MFTMCHMID/hDCAxy2D"), dcaX, dcaY); - // fRegistry.fill(HIST("MFTMCHMID/hDCAxy2DinSigma"), dcaX / std::sqrt(cXX), dcaY / std::sqrt(cYY)); - // fRegistry.fill(HIST("MFTMCHMID/hDCAxy"), dcaXY); - // fRegistry.fill(HIST("MFTMCHMID/hDCAxyz"), dcaXY, dcaZ); - // fRegistry.fill(HIST("MFTMCHMID/hDCAxyinSigma"), dcaXYinSigma); - // fRegistry.fill(HIST("MFTMCHMID/hDCAxResolutionvsPt"), pt, std::sqrt(cXX) * 1e+4); // convert cm to um - // fRegistry.fill(HIST("MFTMCHMID/hDCAyResolutionvsPt"), pt, std::sqrt(cYY) * 1e+4); // convert cm to um - // fRegistry.fill(HIST("MFTMCHMID/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 1e+4); // convert cm to um - // fRegistry.fill(HIST("MFTMCHMID/hDCAx_PosZ"), collision.posZ(), dcaX); - // fRegistry.fill(HIST("MFTMCHMID/hDCAy_PosZ"), collision.posZ(), dcaY); - // fRegistry.fill(HIST("MFTMCHMID/hDCAx_Phi"), phi, dcaX); - // fRegistry.fill(HIST("MFTMCHMID/hDCAy_Phi"), phi, dcaY); - // } else if (fwdtrack.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { - // fRegistry.fill(HIST("MCHMID/hPt"), pt); - // fRegistry.fill(HIST("MCHMID/hEtaPhi"), phi, eta); - // fRegistry.fill(HIST("MCHMID/hEtaPhi_MatchedMCHMID"), phiMatchedMCHMID, etaMatchedMCHMID); - // fRegistry.fill(HIST("MCHMID/hDeltaPt_Pt"), pt, dpt); - // fRegistry.fill(HIST("MCHMID/hDeltaEta_Pt"), pt, deta); - // fRegistry.fill(HIST("MCHMID/hDeltaPhi_Pt"), pt, dphi); - // fRegistry.fill(HIST("MCHMID/hSign"), fwdtrack.sign()); - // fRegistry.fill(HIST("MCHMID/hNclusters"), fwdtrack.nClusters()); - // fRegistry.fill(HIST("MCHMID/hNclustersMFT"), nClustersMFT); - // fRegistry.fill(HIST("MCHMID/hPDCA_Rabs"), rAtAbsorberEnd, pDCA); - // fRegistry.fill(HIST("MCHMID/hRatAbsorberEnd"), rAtAbsorberEnd); - // fRegistry.fill(HIST("MCHMID/hChi2"), fwdtrack.chi2()); - // fRegistry.fill(HIST("MCHMID/hChi2MFT"), chi2mft / ndf_mft); - // fRegistry.fill(HIST("MCHMID/hChi2MatchMCHMID"), fwdtrack.chi2MatchMCHMID()); - // fRegistry.fill(HIST("MCHMID/hChi2MatchMCHMFT"), fwdtrack.chi2MatchMCHMFT()); - // fRegistry.fill(HIST("MCHMID/hDCAxy2D"), dcaX, dcaY); - // fRegistry.fill(HIST("MCHMID/hDCAxy2DinSigma"), dcaX / std::sqrt(cXX), dcaY / std::sqrt(cYY)); - // fRegistry.fill(HIST("MCHMID/hDCAxy"), dcaXY); - // fRegistry.fill(HIST("MCHMID/hDCAxyz"), dcaXY, dcaZ); - // fRegistry.fill(HIST("MCHMID/hDCAxyinSigma"), dcaXYinSigma); - // fRegistry.fill(HIST("MCHMID/hDCAxResolutionvsPt"), pt, std::sqrt(cXX) * 1e+4); // convert cm to um - // fRegistry.fill(HIST("MCHMID/hDCAyResolutionvsPt"), pt, std::sqrt(cYY) * 1e+4); // convert cm to um - // fRegistry.fill(HIST("MCHMID/hDCAxyResolutionvsPt"), pt, sigma_dcaXY * 1e+4); // convert cm to um - // } - // } - return true; - } - - SliceCache cache; - Preslice perCollision = o2::aod::fwdtrack::collisionId; - Preslice fwdtrackIndicesPerCollision = aod::track_association::collisionId; - PresliceUnsorted fwdtrackIndicesPerFwdTrack = aod::track_association::fwdtrackId; - PresliceUnsorted fwdtracksPerMCHTrack = aod::fwdtrack::matchMCHTrackId; - - // Filter trackFilter = o2::aod::fwdtrack::trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) || o2::aod::fwdtrack::trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack); - // using filteredMyFwdTracks = soa::Filtered; - // Partition posTracks = o2::aod::fwdtrack::signed1Pt > 0.f; - // Partition negTracks = o2::aod::fwdtrack::signed1Pt < 0.f; - - std::vector vecMuons; - - void processRec(MyCollisions const& collisions, MyFwdTracks const& fwdtracks, aod::MFTTracks const&, aod::BCsWithTimestamps const&) - { - vecMuons.reserve(fwdtracks.size()); - - for (const auto& collision : collisions) { - auto bc = collision.template bc_as(); - initCCDB(bc); - - if (!collision.isSelected()) { - continue; - } - - auto fwdtracks_per_coll = fwdtracks.sliceBy(perCollision, collision.globalIndex()); - for (const auto& fwdtrack : fwdtracks_per_coll) { - fillMuonInfo(collision, fwdtrack); - } - - auto pos_muons_per_col = std::views::filter(vecMuons, [](Muon muon) { return muon.sign > 0; }); - auto neg_muons_per_col = std::views::filter(vecMuons, [](Muon muon) { return muon.sign < 0; }); - - // ULS - for (const auto& pos : pos_muons_per_col) { - if (!isSelectedTight(pos)) { // pos is tag, neg is probe - continue; - } - for (const auto& neg : neg_muons_per_col) { - if (!isSelected(neg)) { - continue; - } - ROOT::Math::PtEtaPhiMVector v1(pos.pt, pos.eta, pos.phi, o2::constants::physics::MassMuon); // tag - ROOT::Math::PtEtaPhiMVector v2(neg.pt, neg.eta, neg.phi, o2::constants::physics::MassMuon); // probe - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - if (neg.trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { - if (pos.matchMCHTrackId == neg.matchMCHTrackId || pos.matchMFTTrackId == neg.matchMFTTrackId) { // this should not happen in ULS. only for protection. - continue; - } - fRegistry.fill(HIST("Pair/uls/gl_gl/hMvsPt"), v12.M(), v2.Pt()); - } else if (neg.trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { - if (pos.matchMCHTrackId == neg.globalIndex) { // this should not happen in ULS. only for protection. - continue; - } - fRegistry.fill(HIST("Pair/uls/gl_sa/hMvsPt"), v12.M(), v2.Pt()); - } - if (pairCuts.minMass < v12.M() && v12.M() < pairCuts.maxMass) { - fillFwdTrackTable(collision, neg, fwdtracks.rawIteratorAt(neg.globalIndex)); - } - } // end of neg - } // end of pos - - // ULS - for (const auto& neg : neg_muons_per_col) { - if (!isSelectedTight(neg)) { // neg is tag, pos is probe - continue; - } - for (const auto& pos : pos_muons_per_col) { - if (!isSelected(pos)) { - continue; - } - ROOT::Math::PtEtaPhiMVector v1(neg.pt, neg.eta, neg.phi, o2::constants::physics::MassMuon); // tag - ROOT::Math::PtEtaPhiMVector v2(pos.pt, pos.eta, pos.phi, o2::constants::physics::MassMuon); // probe - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - if (pos.trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack)) { - if (pos.matchMCHTrackId == neg.matchMCHTrackId || pos.matchMFTTrackId == neg.matchMFTTrackId) { // this should not happen in ULS. only for protection. - continue; - } - fRegistry.fill(HIST("Pair/uls/gl_gl/hMvsPt"), v12.M(), v2.Pt()); - } else if (pos.trackType == static_cast(o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack)) { - if (neg.matchMCHTrackId == pos.globalIndex) { // this should not happen in ULS. only for protection. - continue; - } - fRegistry.fill(HIST("Pair/uls/gl_sa/hMvsPt"), v12.M(), v2.Pt()); - } - if (pairCuts.minMass < v12.M() && v12.M() < pairCuts.maxMass) { - fillFwdTrackTable(collision, pos, fwdtracks.rawIteratorAt(pos.globalIndex)); - } - } // end of pos - } // end of neg - - } // end of collision loop - - vecMuons.clear(); - vecMuons.shrink_to_fit(); - } - PROCESS_SWITCH(skimmerPrimaryMuonQC, processRec, "process reconstructed info", false); - - void processRec_SWT(MyCollisionsWithSWT const& collisions, MyFwdTracks const& fwdtracks, aod::MFTTracks const&, aod::BCsWithTimestamps const&) - { - vecMuons.reserve(fwdtracks.size()); - - for (const auto& collision : collisions) { - const auto& bc = collision.template bc_as(); - initCCDB(bc); - - if (!collision.isSelected()) { - continue; - } - - if (collision.triggerMask_raw() == 0) { - continue; - } - - // const auto& fwdtracks_per_coll = fwdtracks.sliceBy(perCollision, collision.globalIndex()); - // for (const auto& fwdtrack : fwdtracks_per_coll) { - // if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { - // continue; - // } - - // if (!fillFwdTrackTable(collision, fwdtrack, false)) { - // continue; - // } - - // } // end of fwdtrack loop - } // end of collision loop - - vecMuons.clear(); - vecMuons.shrink_to_fit(); - } - PROCESS_SWITCH(skimmerPrimaryMuonQC, processRec_SWT, "process reconstructed info only with standalone", false); - - using filteredMyFwdTracksMC = soa::Filtered; - void processMC(soa::Join const& collisions, MyFwdTracksMC const& fwdtracks, MFTTracksMC const&, aod::BCsWithTimestamps const&, aod::McParticles const&) - { - vecMuons.reserve(fwdtracks.size()); - - for (const auto& collision : collisions) { - auto bc = collision.template bc_as(); - initCCDB(bc); - if (!collision.isSelected()) { - continue; - } - if (!collision.has_mcCollision()) { - continue; - } - - // auto fwdtracks_per_coll = fwdtracks.sliceBy(perCollision, collision.globalIndex()); - // for (const auto& fwdtrack : fwdtracks_per_coll) { - // if (!fwdtrack.has_mcParticle()) { - // continue; - // } - // if (fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack && fwdtrack.trackType() != o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack) { - // continue; - // } - - // if (!fillFwdTrackTable(collision, fwdtrack, false)) { - // continue; - // } - - // } // end of fwdtrack loop - } // end of collision loop - - vecMuons.clear(); - vecMuons.shrink_to_fit(); - } - PROCESS_SWITCH(skimmerPrimaryMuonQC, processMC, "process reconstructed and MC info", false); - - void processDummy(aod::Collisions const&) {} - PROCESS_SWITCH(skimmerPrimaryMuonQC, processDummy, "process dummy", true); -}; -struct associateAmbiguousMuon { - Produces em_amb_muon_ids; - - SliceCache cache; - PresliceUnsorted perTrack = o2::aod::emprimarymuon::fwdtrackId; - std::vector ambmuon_self_Ids; - - void process(aod::EMPrimaryMuons const& muons) - { - for (const auto& muon : muons) { - auto muons_with_same_trackId = muons.sliceBy(perTrack, muon.fwdtrackId()); - ambmuon_self_Ids.reserve(muons_with_same_trackId.size()); - for (const auto& amb_muon : muons_with_same_trackId) { - if (amb_muon.globalIndex() == muon.globalIndex()) { // don't store myself. - continue; - } - ambmuon_self_Ids.emplace_back(amb_muon.globalIndex()); - } - em_amb_muon_ids(ambmuon_self_Ids); - ambmuon_self_Ids.clear(); - ambmuon_self_Ids.shrink_to_fit(); - } - } -}; - -struct associateSameMuonElement { - Produces glmuon_same_ids; - - SliceCache cache; - PresliceUnsorted perMFTTrack = o2::aod::emprimarymuon::mfttrackId; - PresliceUnsorted perMCHTrack = o2::aod::emprimarymuon::mchtrackId; - std::vector selfIds_per_MFT; - std::vector selfIds_per_MCHMID; - - // Multiple MCH-MID tracks can match with the same MFTsa. This function is to reject such global muons. - void process(aod::EMPrimaryMuons const& muons) - { - for (const auto& muon : muons) { - if (muon.trackType() == o2::aod::fwdtrack::ForwardTrackTypeEnum::GlobalMuonTrack) { - auto muons_with_same_mfttrackId = muons.sliceBy(perMFTTrack, muon.mfttrackId()); - auto muons_with_same_mchtrackId = muons.sliceBy(perMCHTrack, muon.mchtrackId()); - selfIds_per_MFT.reserve(muons_with_same_mfttrackId.size()); - selfIds_per_MCHMID.reserve(muons_with_same_mchtrackId.size()); - // LOGF(info, "muons_with_same_mchtrackId.size() = %d, muons_with_same_mfttrackId.size() = %d", muons_with_same_mchtrackId.size(), muons_with_same_mfttrackId.size()); - - for (const auto& global_muon : muons_with_same_mfttrackId) { - // LOGF(info, "same MFT: global_muon.globalIndex() = %d, global_muon.mchtrackId() = %d, global_muon.mfttrackId() = %d, global_muon.collisionId() = %d", global_muon.globalIndex(), global_muon.mchtrackId(), global_muon.mfttrackId(), global_muon.collisionId()); - if (global_muon.globalIndex() == muon.globalIndex()) { // don't store myself. - continue; - } - if (global_muon.collisionId() == muon.collisionId()) { // the same global muon is repeatedly stored and associated to different collisions if FTTCA is used. - selfIds_per_MFT.emplace_back(global_muon.globalIndex()); - } - } - - for (const auto& global_muon : muons_with_same_mchtrackId) { - // LOGF(info, "same MCH: global_muon.globalIndex() = %d, global_muon.mchtrackId() = %d, global_muon.mfttrackId() = %d, global_muon.collisionId() = %d", global_muon.globalIndex(), global_muon.mchtrackId(), global_muon.mfttrackId(), global_muon.collisionId()); - if (global_muon.globalIndex() == muon.globalIndex()) { // don't store myself. - continue; - } - if (global_muon.collisionId() == muon.collisionId()) { // the same global muon is repeatedly stored and associated to different collisions if FTTCA is used. - selfIds_per_MCHMID.emplace_back(global_muon.globalIndex()); - } - } - - glmuon_same_ids(selfIds_per_MCHMID, selfIds_per_MFT); - selfIds_per_MFT.clear(); - selfIds_per_MFT.shrink_to_fit(); - selfIds_per_MCHMID.clear(); - selfIds_per_MCHMID.shrink_to_fit(); - } else { - glmuon_same_ids(std::vector{}, std::vector{}); // empty for standalone muons - selfIds_per_MFT.clear(); - selfIds_per_MFT.shrink_to_fit(); - selfIds_per_MCHMID.clear(); - selfIds_per_MCHMID.shrink_to_fit(); - } - } // end of muon loop - } -}; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc, TaskName{"skimmer-primary-muon-qc"}), - adaptAnalysisTask(cfgc, TaskName{"associate-ambiguous-muon"}), - adaptAnalysisTask(cfgc, TaskName{"associate-same-muon-element"})}; -} diff --git a/PWGEM/Dilepton/Tasks/testPV.cxx b/PWGEM/Dilepton/Tasks/testPV.cxx index 5684d2cc0f7..7c7057c3681 100644 --- a/PWGEM/Dilepton/Tasks/testPV.cxx +++ b/PWGEM/Dilepton/Tasks/testPV.cxx @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -28,31 +29,27 @@ #include +#include #include -using namespace o2; -using namespace o2::soa; -using namespace o2::framework; -using namespace o2::framework::expressions; - struct testPV { // Configurables - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + o2::framework::Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - struct : ConfigurableGroup { + struct : o2::framework::ConfigurableGroup { std::string prefix = "eventCut"; - Configurable cfgEventGeneratorId{"cfgEventGeneratorId", -1, "event generator index. e.g. select gap/signal events"}; - Configurable cfgChi2PerNcontribMax{"cfgChi2PerNcontribMax", 1e+10, "max. chi2/Ncontrib of PV"}; - Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; - Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; - Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND"}; - Configurable cfgRequireNoTFB{"cfgRequireNoTFB", true, "require No time frame border"}; - Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border"}; - Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; - Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; - Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. - Configurable cfgRequireVertexTOFmatched{"cfgRequireVertexTOFmatched", false, "require Vertex TOFmatched in event cut"}; // ITS-TPC-TOF matched track contributes PV. + o2::framework::Configurable cfgEventGeneratorId{"cfgEventGeneratorId", -1, "event generator index. e.g. select gap/signal events"}; + o2::framework::Configurable cfgChi2PerNcontribMax{"cfgChi2PerNcontribMax", 1e+10, "max. chi2/Ncontrib of PV"}; + o2::framework::Configurable cfgZvtxMin{"cfgZvtxMin", -10.f, "min. Zvtx"}; + o2::framework::Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + o2::framework::Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND"}; + o2::framework::Configurable cfgRequireNoTFB{"cfgRequireNoTFB", true, "require No time frame border"}; + o2::framework::Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border"}; + o2::framework::Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + o2::framework::Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + o2::framework::Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + o2::framework::Configurable cfgRequireVertexTOFmatched{"cfgRequireVertexTOFmatched", false, "require Vertex TOFmatched in event cut"}; // ITS-TPC-TOF matched track contributes PV. // for RCT o2::framework::Configurable cfgRequireGoodRCT{"cfgRequireGoodRCT", true, "require good detector flag in run condtion table"}; @@ -62,14 +59,14 @@ struct testPV { } eventCut; // for zorro - struct : ConfigurableGroup { + struct : o2::framework::ConfigurableGroup { std::string prefix = "zorroGroup"; - Configurable cfgTriggerName{"cfgTriggerName", "fGlobalDimuon", "desired software trigger name"}; - Configurable ccdbPathSoftwareTrigger{"ccdbPathSoftwareTrigger", "EventFiltering/Zorro/", "ccdb path for ZORRO objects"}; - Configurable bcMarginForSoftwareTrigger{"bcMarginForSoftwareTrigger", 100, "Number of BCs of margin for software triggers"}; + o2::framework::Configurable cfgTriggerName{"cfgTriggerName", "fGlobalDimuon", "desired software trigger name"}; + o2::framework::Configurable ccdbPathSoftwareTrigger{"ccdbPathSoftwareTrigger", "EventFiltering/Zorro/", "ccdb path for ZORRO objects"}; + o2::framework::Configurable bcMarginForSoftwareTrigger{"bcMarginForSoftwareTrigger", 100, "Number of BCs of margin for software triggers"}; } zorroGroup; - HistogramRegistry fRegistry{"fRegistry"}; + o2::framework::HistogramRegistry fRegistry{"fRegistry"}; Zorro zorro; void init(o2::framework::InitContext&) @@ -85,7 +82,7 @@ struct testPV { } int mRunNumber{0}; - Service ccdb; + o2::framework::Service ccdb; template void initCCDB(TBC const& bc) @@ -105,26 +102,26 @@ struct testPV { void addHistograms() { - auto hCollisionCounter = fRegistry.add("hCollisionCounter", "collision counter", kTH1D, {{2, 0.5f, 2.5f}}, false); + auto hCollisionCounter = fRegistry.add("hCollisionCounter", "collision counter", o2::framework::HistType::kTH1D, {{2, 0.5f, 2.5f}}, false); hCollisionCounter->GetXaxis()->SetBinLabel(1, "all"); hCollisionCounter->GetXaxis()->SetBinLabel(2, "accepted"); - fRegistry.add("Vertex/hZvtx", "vertex z; Z_{vtx} (cm)", kTH1F, {{100, -50, +50}}, false); - fRegistry.add("Vertex/hNContrib", "Number of PV contributors;N_{contrib}", kTH1F, {{101, -0.5, 100.5}}, false); - fRegistry.add("Vertex/hChi2", "vertex chi2;#chi^{2}/N_{contrib}", kTH1F, {{100, 0, 10}}, false); - fRegistry.add("Vertex/hChi2vsNContrib", "vertex #chi^{2}/N_{contrib} vs. N_{contrib};N_{contrib};#chi^{2}/N_{contrib}", kTH2F, {{101, -0.5, 100.5}, {100, 0, 10}}, false); + fRegistry.add("Vertex/hZvtx", "vertex z; Z_{vtx} (cm)", o2::framework::HistType::kTH1F, {{100, -50, +50}}, false); + fRegistry.add("Vertex/hNContrib", "Number of PV contributors;N_{contrib}", o2::framework::HistType::kTH1F, {{101, -0.5, 100.5}}, false); + fRegistry.add("Vertex/hChi2", "vertex chi2;#chi^{2}/N_{contrib}", o2::framework::HistType::kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Vertex/hChi2vsNContrib", "vertex #chi^{2}/N_{contrib} vs. N_{contrib};N_{contrib};#chi^{2}/N_{contrib}", o2::framework::HistType::kTH2F, {{101, -0.5, 100.5}, {100, 0, 10}}, false); - fRegistry.add("Vertex/hSigmaX", "vertex #sigma_{X} vs. N_{contrib};N_{contrib};#sigma_{X} (#mum)", kTH2F, {{101, -0.5, 100.5}, {1000, 0, 100}}, false); - fRegistry.add("Vertex/hSigmaY", "vertex #sigma_{Y} vs. N_{contrib};N_{contrib};#sigma_{Y} (#mum)", kTH2F, {{101, -0.5, 100.5}, {1000, 0, 100}}, false); - fRegistry.add("Vertex/hSigmaZ", "vertex #sigma_{Z} vs. N_{contrib};N_{contrib};#sigma_{Z} (#mum)", kTH2F, {{101, -0.5, 100.5}, {1000, 0, 100}}, false); + fRegistry.add("Vertex/hSigmaX", "vertex #sigma_{X} vs. N_{contrib};N_{contrib};#sigma_{X} (#mum)", o2::framework::HistType::kTH2F, {{101, -0.5, 100.5}, {1000, 0, 100}}, false); + fRegistry.add("Vertex/hSigmaY", "vertex #sigma_{Y} vs. N_{contrib};N_{contrib};#sigma_{Y} (#mum)", o2::framework::HistType::kTH2F, {{101, -0.5, 100.5}, {1000, 0, 100}}, false); + fRegistry.add("Vertex/hSigmaZ", "vertex #sigma_{Z} vs. N_{contrib};N_{contrib};#sigma_{Z} (#mum)", o2::framework::HistType::kTH2F, {{101, -0.5, 100.5}, {1000, 0, 100}}, false); - fRegistry.add("Vertex/hCollisionTime", "vertex time;N_{contrib};collision time (ns)", kTH2F, {{101, -0.5, 100.5}, {500, -25, 25}}, false); - fRegistry.add("Vertex/hCollisionTimeRes", "vertex time resolution;N_{contrib};collision time resolution (ns)", kTH2F, {{101, -0.5, 100.5}, {250, 0, 25}}, false); + fRegistry.add("Vertex/hCollisionTime", "vertex time;N_{contrib};collision time (ns)", o2::framework::HistType::kTH2F, {{101, -0.5, 100.5}, {500, -25, 25}}, false); + fRegistry.add("Vertex/hCollisionTimeRes", "vertex time resolution;N_{contrib};collision time resolution (ns)", o2::framework::HistType::kTH2F, {{101, -0.5, 100.5}, {250, 0, 25}}, false); if (doprocessMC) { - fRegistry.add("Vertex/hDeltaX", "vertex #DeltaX vs. N_{contrib};N_{contrib};#DeltaX = (X_{rec} #minus X_{gen})/#sigma_{X}", kTH2F, {{101, -0.5, 100.5}, {200, -10, 10}}, false); - fRegistry.add("Vertex/hDeltaY", "vertex #DeltaY vs. N_{contrib};N_{contrib};#DeltaY = (Y_{rec} #minus Y_{gen})/#sigma_{Y}", kTH2F, {{101, -0.5, 100.5}, {200, -10, 10}}, false); - fRegistry.add("Vertex/hDeltaZ", "vertex #DeltaZ vs. N_{contrib};N_{contrib};#DeltaZ = (Z_{rec} #minus Z_{gen})/#sigma_{Z}", kTH2F, {{101, -0.5, 100.5}, {200, -10, 10}}, false); + fRegistry.add("Vertex/hDeltaX", "vertex #DeltaX vs. N_{contrib};N_{contrib};#DeltaX = (X_{rec} #minus X_{gen})/#sigma_{X}", o2::framework::HistType::kTH2F, {{101, -0.5, 100.5}, {200, -10, 10}}, false); + fRegistry.add("Vertex/hDeltaY", "vertex #DeltaY vs. N_{contrib};N_{contrib};#DeltaY = (Y_{rec} #minus Y_{gen})/#sigma_{Y}", o2::framework::HistType::kTH2F, {{101, -0.5, 100.5}, {200, -10, 10}}, false); + fRegistry.add("Vertex/hDeltaZ", "vertex #DeltaZ vs. N_{contrib};N_{contrib};#DeltaZ = (Z_{rec} #minus Z_{gen})/#sigma_{Z}", o2::framework::HistType::kTH2F, {{101, -0.5, 100.5}, {200, -10, 10}}, false); } } @@ -218,13 +215,13 @@ struct testPV { } // end of collision loop } - using MyCollisions = soa::Join; - using MyCollisionsMC = soa::Join; - using MyBCs = soa::Join; + using MyCollisions = o2::soa::Join; + using MyCollisionsMC = o2::soa::Join; + using MyBCs = o2::soa::Join; - Filter collisionFilter_evsel = eventCut.cfgZvtxMin < o2::aod::collision::posZ && o2::aod::collision::posZ < eventCut.cfgZvtxMax; - using FilteredMyCollisions = soa::Filtered; - using FilteredMyCollisionsMC = soa::Filtered; + o2::framework::expressions::Filter collisionFilter_evsel = eventCut.cfgZvtxMin < o2::aod::collision::posZ && o2::aod::collision::posZ < eventCut.cfgZvtxMax; + using FilteredMyCollisions = o2::soa::Filtered; + using FilteredMyCollisionsMC = o2::soa::Filtered; void processData(FilteredMyCollisions const& collisions, MyBCs const& bcs) { @@ -236,9 +233,9 @@ struct testPV { { run(bcs, collisions, nullptr, nullptr); } - PROCESS_SWITCH(testPV, processTriggeredData, "processTriggeredData", true); + PROCESS_SWITCH(testPV, processTriggeredData, "processTriggeredData", false); - void processMC(FilteredMyCollisionsMC const& collisions, MyBCs const& bcs, aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles) + void processMC(FilteredMyCollisionsMC const& collisions, MyBCs const& bcs, o2::aod::McCollisions const& mcCollisions, o2::aod::McParticles const& mcParticles) { run(bcs, collisions, mcCollisions, mcParticles); } @@ -247,7 +244,7 @@ struct testPV { void processDummy(MyCollisions const&) {} PROCESS_SWITCH(testPV, processDummy, "processDummy", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"test-pv"})}; + return o2::framework::WorkflowSpec{adaptAnalysisTask(cfgc, o2::framework::TaskName{"test-pv"})}; } diff --git a/PWGEM/PhotonMeson/Core/EMBitFlags.h b/PWGEM/PhotonMeson/Core/EMBitFlags.h index efe782546b6..99aac0dfd6a 100644 --- a/PWGEM/PhotonMeson/Core/EMBitFlags.h +++ b/PWGEM/PhotonMeson/Core/EMBitFlags.h @@ -37,17 +37,18 @@ class EMBitFlags /// \brief check bit i /// \param i index of bit that should be checked + /// \return false if the bit was set before [[nodiscard]] bool test(std::size_t i) const; - /// \brief set bit i + /// \brief set bit i to false /// \param i index of bit which value should be set void set(std::size_t i); - /// \brief reset bit i + /// \brief reset bit i to true /// \param i index of bit which value should be reset void reset(std::size_t i); - /// \brief resetting all flags to false + /// \brief resetting all flags to true void clear(); /// \brief reserve space in the underlying storage for nBits bits diff --git a/PWGEM/PhotonMeson/Core/EMCConversionCandidate.h b/PWGEM/PhotonMeson/Core/EMCConversionCandidate.h new file mode 100644 index 00000000000..bc8a6f79d2e --- /dev/null +++ b/PWGEM/PhotonMeson/Core/EMCConversionCandidate.h @@ -0,0 +1,85 @@ +// 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. + +/// \file EMCConversionCandidate.h +/// \brief Header file that defines EMCConversionCandidate, a struct to be used with the EMCConversion ML model +/// \author Marvin Hemmer + +#ifndef PWGEM_PHOTONMESON_CORE_EMCCONVERSIONCANDIDATE_H_ +#define PWGEM_PHOTONMESON_CORE_EMCCONVERSIONCANDIDATE_H_ + +#include +#include + +namespace o2::analysis::em +{ + +// Requires T to expose the specific named getters getInputFeatures() needs, +// each returning something convertible to float. +template +concept IsEmcConversionCandidate = requires(T const& c) { + { c.minv() } -> std::convertible_to; + { c.deltaEta() } -> std::convertible_to; + { c.deltaR() } -> std::convertible_to; + { c.phiv() } -> std::convertible_to; + { c.rConv() } -> std::convertible_to; + { c.totE() } -> std::convertible_to; + { c.e2() } -> std::convertible_to; + { c.e1() } -> std::convertible_to; + { c.deltaPhi() } -> std::convertible_to; + { c.harmonicEt() } -> std::convertible_to; + { c.m021() } -> std::convertible_to; + { c.m022() } -> std::convertible_to; + { c.time1() } -> std::convertible_to; + { c.time2() } -> std::convertible_to; + { c.ncell1() } -> std::convertible_to; + { c.ncell2() } -> std::convertible_to; +}; + +struct EMCConversionCandidate { + float mMinv; + float mDeltaEta; + float mDeltaR; + float mPhiv; + float mRConv; + float mTotE; + float mE2; + float mE1; + float mDeltaPhi; + float mHarmonicEt; + float mM021; + float mM022; + float mTime1; + float mTime2; + uint8_t mNcell1; + uint8_t mNcell2; + + [[nodiscard]] float minv() const { return mMinv; } + [[nodiscard]] float deltaEta() const { return mDeltaEta; } + [[nodiscard]] float deltaR() const { return mDeltaR; } + [[nodiscard]] float phiv() const { return mPhiv; } + [[nodiscard]] float rConv() const { return mRConv; } + [[nodiscard]] float totE() const { return mTotE; } + [[nodiscard]] float e2() const { return mE2; } + [[nodiscard]] float e1() const { return mE1; } + [[nodiscard]] float deltaPhi() const { return mDeltaPhi; } + [[nodiscard]] float harmonicEt() const { return mHarmonicEt; } + [[nodiscard]] float m021() const { return mM021; } + [[nodiscard]] float m022() const { return mM022; } + [[nodiscard]] float time1() const { return mTime1; } + [[nodiscard]] float time2() const { return mTime2; } + [[nodiscard]] uint8_t ncell1() const { return mNcell1; } + [[nodiscard]] uint8_t ncell2() const { return mNcell2; } +}; + +} // namespace o2::analysis::em + +#endif // PWGEM_PHOTONMESON_CORE_EMCCONVERSIONCANDIDATE_H_ diff --git a/PWGEM/PhotonMeson/Core/EMCPhotonCut.h b/PWGEM/PhotonMeson/Core/EMCPhotonCut.h index 5567ca37c5f..1e93046b573 100644 --- a/PWGEM/PhotonMeson/Core/EMCPhotonCut.h +++ b/PWGEM/PhotonMeson/Core/EMCPhotonCut.h @@ -443,6 +443,10 @@ class EMCPhotonCut /// \return true if cluster survives cut else false bool IsSelectedEMCalRunning(const EMCPhotonCuts& cut, o2::soa::is_iterator auto const& cluster, IsFullTrackIterator auto& matchedTrackIter, int64_t const nMatchedTracks, o2::framework::HistogramRegistry* fRegistry = nullptr) const { + if (nMatchedTracks == 0) { + // there are not tracks to match with, so its true + return true; + } switch (cut) { case EMCPhotonCuts::kTM: return checkTrackMatching(cluster, matchedTrackIter, nMatchedTracks, true, [this](float pt) { return GetTrackMatchingEta(pt); }, [this](float pt) { return GetTrackMatchingPhi(pt); }, fRegistry, TrackType::kPrimary); diff --git a/PWGEM/PhotonMeson/Core/EMPhotonEventCut.h b/PWGEM/PhotonMeson/Core/EMPhotonEventCut.h index 1056de45a76..26b1f2c9490 100644 --- a/PWGEM/PhotonMeson/Core/EMPhotonEventCut.h +++ b/PWGEM/PhotonMeson/Core/EMPhotonEventCut.h @@ -50,8 +50,8 @@ class EMPhotonEventCut kNCuts }; - const std::string getName() const { return name; } - const std::string getTitle() const { return title; } + [[nodiscard]] const std::string& getName() const { return name; } + [[nodiscard]] const std::string& getTitle() const { return title; } template bool IsSelected(T const& collision) const diff --git a/PWGEM/PhotonMeson/Core/EmMlResponseEMCConversion.h b/PWGEM/PhotonMeson/Core/EmMlResponseEMCConversion.h new file mode 100644 index 00000000000..3565a6b82bd --- /dev/null +++ b/PWGEM/PhotonMeson/Core/EmMlResponseEMCConversion.h @@ -0,0 +1,118 @@ +// 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. + +/// \file EmMlResponseEMCConversion.h +/// \brief Class to compute the ML response for EMC conversion selections +/// \author Marvin Hemmer + +#ifndef PWGEM_PHOTONMESON_CORE_EMMLRESPONSEEMCCONVERSION_H_ +#define PWGEM_PHOTONMESON_CORE_EMMLRESPONSEEMCCONVERSION_H_ + +#include "PWGEM/PhotonMeson/Core/EMCConversionCandidate.h" + +#include "Tools/ML/MlResponse.h" + +#include +#include + +// Fill the map of available input features +// the key is the feature's name (std::string) +// the value is the corresponding value in EnumInputFeatures +#define FILL_MAP_EMC_CONV(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesEMCConversion::FEATURE)} + +// Check if the index of mCachedIndices (index associated to a FEATURE) +// matches the entry in EnumInputFeatures associated to this FEATURE +// if so, the inputFeatures vector is filled with the FEATURE's value +// by calling the corresponding GETTER from OBJECT +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define CHECK_AND_FILL_VEC_EMC_CONV(GETTER) \ + case static_cast(InputFeaturesEMCConversion::GETTER): { \ + inputFeatures.emplace_back(candidate.GETTER()); \ + break; \ + } + +namespace o2::analysis::em::emcconv +{ + +// input feature used in the ml model +enum class InputFeaturesEMCConversion : uint8_t { + minv, + deltaEta, + deltaR, + phiv, + rConv, + totE, + e2, + e1, + deltaPhi, + harmonicEt, + m021, + m022, + time1, + time2, + ncell1, + ncell2 +}; + +template +class EmMlResponseEMCConversion : public MlResponse +{ + public: + EmMlResponseEMCConversion() = default; + virtual ~EmMlResponseEMCConversion() = default; + + template + void getInputFeatures(TCandidate const& candidate, std::vector& inputFeatures) + { + inputFeatures.clear(); + for (const auto& idx : MlResponse::mCachedIndices) { + switch (idx) { + CHECK_AND_FILL_VEC_EMC_CONV(minv) + CHECK_AND_FILL_VEC_EMC_CONV(deltaEta) + CHECK_AND_FILL_VEC_EMC_CONV(deltaR) + CHECK_AND_FILL_VEC_EMC_CONV(phiv) + CHECK_AND_FILL_VEC_EMC_CONV(rConv) + CHECK_AND_FILL_VEC_EMC_CONV(totE) + CHECK_AND_FILL_VEC_EMC_CONV(e2) + CHECK_AND_FILL_VEC_EMC_CONV(e1) + CHECK_AND_FILL_VEC_EMC_CONV(deltaPhi) + CHECK_AND_FILL_VEC_EMC_CONV(harmonicEt) + CHECK_AND_FILL_VEC_EMC_CONV(m021) + CHECK_AND_FILL_VEC_EMC_CONV(m022) + CHECK_AND_FILL_VEC_EMC_CONV(time1) + CHECK_AND_FILL_VEC_EMC_CONV(time2) + CHECK_AND_FILL_VEC_EMC_CONV(ncell1) + CHECK_AND_FILL_VEC_EMC_CONV(ncell2) + } + } + } + + protected: + void setAvailableInputFeatures() + { + MlResponse::mAvailableInputFeatures = { + FILL_MAP_EMC_CONV(minv), FILL_MAP_EMC_CONV(deltaEta), FILL_MAP_EMC_CONV(deltaR), + FILL_MAP_EMC_CONV(phiv), FILL_MAP_EMC_CONV(rConv), FILL_MAP_EMC_CONV(totE), + FILL_MAP_EMC_CONV(e2), FILL_MAP_EMC_CONV(e1), FILL_MAP_EMC_CONV(deltaPhi), + FILL_MAP_EMC_CONV(harmonicEt), FILL_MAP_EMC_CONV(m021), FILL_MAP_EMC_CONV(m022), + FILL_MAP_EMC_CONV(time1), FILL_MAP_EMC_CONV(time2), FILL_MAP_EMC_CONV(ncell1), + FILL_MAP_EMC_CONV(ncell2)}; + } +}; + +} // namespace o2::analysis::em::emcconv + +#undef FILL_MAP_EMC_CONV +#undef CHECK_AND_FILL_VEC_EMC_CONV + +#endif // PWGEM_PHOTONMESON_CORE_EMMLRESPONSEEMCCONVERSION_H_ diff --git a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h index e1db2a28d7b..45e4f7c26d7 100644 --- a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h +++ b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGamma.h @@ -458,10 +458,8 @@ struct Pi0EtaToGammaGamma { if (mRunNumber == collision.runNumber()) { return; } + mRunNumber = collision.runNumber(); - if (mRunNumber == collision.runNumber()) { - return; - } // In case override, don't proceed, please - no CCDB access required if (d_bz_input > -990) { // o2-linter: disable=magic-number (override value) d_bz = d_bz_input; @@ -470,7 +468,6 @@ struct Pi0EtaToGammaGamma { grpmag.setL3Current(30000.f / (d_bz / 5.0f)); // o2-linter: disable=magic-number (override value) } o2::base::Propagator::initFieldFromGRP(&grpmag); - mRunNumber = collision.runNumber(); return; } diff --git a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h index ea43bd54900..79c7b4308ae 100644 --- a/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h +++ b/PWGEM/PhotonMeson/Core/Pi0EtaToGammaGammaMC.h @@ -313,10 +313,8 @@ struct Pi0EtaToGammaGammaMC { if (mRunNumber == collision.runNumber()) { return; } + mRunNumber = collision.runNumber(); - if (mRunNumber == collision.runNumber()) { - return; - } // In case override, don't proceed, please - no CCDB access required if (d_bz_input > -990) { // o2-linter: disable=magic-number (override value) d_bz = d_bz_input; @@ -325,7 +323,6 @@ struct Pi0EtaToGammaGammaMC { grpmag.setL3Current(30000.f / (d_bz / 5.0f)); // o2-linter: disable=magic-number (override value) } o2::base::Propagator::initFieldFromGRP(&grpmag); - mRunNumber = collision.runNumber(); return; } diff --git a/PWGEM/PhotonMeson/Core/TaggingPi0MC.h b/PWGEM/PhotonMeson/Core/TaggingPi0MC.h index e6248abe388..4588f70182d 100644 --- a/PWGEM/PhotonMeson/Core/TaggingPi0MC.h +++ b/PWGEM/PhotonMeson/Core/TaggingPi0MC.h @@ -77,7 +77,7 @@ using MyMCCollision = MyMCCollisions::iterator; using MyV0Photons = o2::soa::Join; using MyV0Photon = MyV0Photons::iterator; -using MyEMCClusters = o2::soa::Join; +using MyEMCClusters = o2::soa::Join; using MyEMCCluster = MyEMCClusters::iterator; // using MyPHOSClusters = o2::soa::Join; diff --git a/PWGEM/PhotonMeson/Core/V0PhotonCandidate.h b/PWGEM/PhotonMeson/Core/V0PhotonCandidate.h index 37aeb4b5425..d653194ca4d 100644 --- a/PWGEM/PhotonMeson/Core/V0PhotonCandidate.h +++ b/PWGEM/PhotonMeson/Core/V0PhotonCandidate.h @@ -89,8 +89,8 @@ struct V0PhotonCandidate { dcaXYV0ToPV = RecoDecay::sqrtSumOfSquares(dcaXV0ToPV, dcaYV0ToPV) * tmpSign; dcaZV0ToPV = (v0DecayVtx.GetZ() - v0DecayVtx.GetPz() * cospa_ * length / v0mom) - collision.posZ(); - alpha = v0_alpha(posPx, posPy, posPz, elePx, elePy, elePz); - qt = v0_qt(posPx, posPy, posPz, elePx, elePy, elePz); + alpha = v0Alpha(posPx, posPy, posPz, elePx, elePy, elePz); + qt = v0Qt(posPx, posPy, posPz, elePx, elePy, elePz); cospa = cospa_; cospaRZ = cospaRZ_; diff --git a/PWGEM/PhotonMeson/DataModel/EventTables.h b/PWGEM/PhotonMeson/DataModel/EventTables.h index 7bbd2a761dc..93630002fc5 100644 --- a/PWGEM/PhotonMeson/DataModel/EventTables.h +++ b/PWGEM/PhotonMeson/DataModel/EventTables.h @@ -29,36 +29,37 @@ #include // for BIT #include +#include namespace o2::aod { namespace pmevsel { -// Event selection criteria. See O2Physics/Common/CCDB/EventSelectionParams.h -enum EventSelectionFlags { - kIsTriggerTVX = 0, // FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level - kNoITSROFrameBorder, // bunch crossing is far from ITS RO Frame border - kNoTimeFrameBorder, // bunch crossing is far from Time Frame borders - kNoSameBunchPileup, // reject collisions in case of pileup with another collision in the same foundBC - kIsGoodZvtxFT0vsPV, // small difference between z-vertex from PV and from FT0 - kIsVertexITSTPC, // at least one ITS-TPC track (reject vertices built from ITS-only tracks) - kIsVertexTOFmatched, // at least one of vertex contributors is matched to TOF - kIsVertexTRDmatched, // at least one of vertex contributors is matched to TRD - kNoCollInTimeRangeNarrow, // no other collisions in specified time range (narrower than Strict) - kNoCollInTimeRangeStrict, // no other collisions in specified time range - kNoCollInTimeRangeStandard, // no other collisions in specified time range with per-collision multiplicity above threshold - kNoCollInRofStrict, // no other collisions in this Readout Frame - kNoCollInRofStandard, // no other collisions in this Readout Frame with per-collision multiplicity above threshold - kNoHighMultCollInPrevRof, // veto an event if FT0C amplitude in previous ITS ROF is above threshold - kIsGoodITSLayer3, // number of inactive chips on ITS layer 3 is below maximum allowed value - kIsGoodITSLayer0123, // numbers of inactive chips on ITS layers 0-3 are below maximum allowed values - kIsGoodITSLayersAll, // numbers of inactive chips on all ITS layers are below maximum allowed values - kNsel // counter -}; -DECLARE_SOA_BITMAP_COLUMN(Selection, selection, 32); //! Bitmask of selection flags -DECLARE_SOA_DYNAMIC_COLUMN(Sel8, sel8, [](uint32_t selection_bit) -> bool { return (selection_bit & BIT(o2::aod::pmevsel::kIsTriggerTVX)) && (selection_bit & BIT(o2::aod::pmevsel::kNoTimeFrameBorder)) && (selection_bit & BIT(o2::aod::pmevsel::kNoITSROFrameBorder)); }); +DECLARE_SOA_DYNAMIC_COLUMN(Sel8, sel8, [](uint64_t selection_bit, int runNumber) -> bool { + return (selection_bit & BIT(o2::aod::evsel::kIsTriggerTVX)) && (selection_bit & BIT(o2::aod::evsel::kNoTimeFrameBorder)) && (runNumber < 568873 ? (selection_bit & BIT(o2::aod::evsel::kNoITSROFrameBorder)) : true); // o2-linter: disable=magic-number (hard-coded run range to indicate 2026 datataking) +}); + +// Enum used for filling table for event-norm purposes +enum EventAcceptanceBits { + kAll = 0, // o2-linter: disable=magic-number (enum) + kHasMCColl, + kGoodZVtx, + kIsFT0AND, + kNoTFB, + kITSROFB, + kNoSameBunchPileUp, + kGoodZVtxFTOPV, + kNoCollInTimeRange, + kGoodTrackOccupancy, + kGoodFT0Occupancy, + kTVXInEMC, + kGoodCent, + kGoodRCT, + kGoodSel8, + kSize +}; } // namespace pmevsel @@ -66,16 +67,27 @@ namespace pmevent { DECLARE_SOA_COLUMN(CollisionId, collisionId, int); -DECLARE_SOA_DYNAMIC_COLUMN(Sel8, sel8, [](uint64_t selection_bit) -> bool { return (selection_bit & BIT(o2::aod::evsel::kIsTriggerTVX)) && (selection_bit & BIT(o2::aod::evsel::kNoTimeFrameBorder)) && (selection_bit & BIT(o2::aod::evsel::kNoITSROFrameBorder)); }); } // namespace pmevent DECLARE_SOA_TABLE(PMEvents, "AOD", "PMEVENT", //! Main event information table o2::soa::Index<>, pmevent::CollisionId, bc::RunNumber, bc::GlobalBC, evsel::Selection, evsel::Rct, timestamp::Timestamp, collision::PosZ, - collision::NumContrib, evsel::NumTracksInTimeRange, evsel::SumAmpFT0CInTimeRange, pmevent::Sel8); + collision::NumContrib, evsel::NumTracksInTimeRange, evsel::SumAmpFT0CInTimeRange, pmevsel::Sel8); using PMEvent = PMEvents::iterator; +// Tables for event selection and event bookkeeping + +DECLARE_SOA_COLUMN(IsSelected, isSelected, bool); //! MB event selection info +DECLARE_SOA_TABLE(PMEvSels, "AOD", "PMEVSEL", //! joinable to o2::aod::Collisions + IsSelected); +using PMEvSel = PMEvSels::iterator; + +DECLARE_SOA_COLUMN(EventSelectionBit, eventSelectionBit, std::vector); //! Event selection info stored in binned data for each DF +DECLARE_SOA_TABLE(PMEvSelBits, "AOD", "PMEVSELBITS", //! produces binned data that can be loaded in analysis task for event counting + EventSelectionBit); +using PMEvSelBit = PMEvSelBits::iterator; + namespace ccdbPcm { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) diff --git a/PWGEM/PhotonMeson/DataModel/gammaTables.h b/PWGEM/PhotonMeson/DataModel/gammaTables.h index 33dca54b611..f0e0bdf8d85 100644 --- a/PWGEM/PhotonMeson/DataModel/gammaTables.h +++ b/PWGEM/PhotonMeson/DataModel/gammaTables.h @@ -242,16 +242,56 @@ using V0Legs = V0Legs_001; // iterators using V0Leg = V0Legs::iterator; +// copy of V0Legs table +DECLARE_SOA_TABLE(V0LegsTmp, "AOD", "V0LEGTMP", //! + o2::soa::Index<>, v0leg::CollisionId, v0leg::TrackId, v0leg::Sign, + v0leg::Px, v0leg::Py, v0leg::Pz, + track::DcaXY, track::DcaZ, + track::TPCNClsFindable, track::TPCNClsFindableMinusFound, track::TPCNClsFindableMinusCrossedRows, track::TPCNClsShared, + track::TPCChi2NCl, track::TPCInnerParam, + track::TPCSignal, pidtpc::TPCNSigmaEl, pidtpc::TPCNSigmaPi, + track::ITSClusterSizes, track::ITSChi2NCl, track::DetectorMap, + + // dynamic column + v0leg::P, + v0leg::Pt, + v0leg::Eta, + v0leg::Phi, + v0leg::Tgl, + + track::TPCNClsFound, + track::TPCNClsCrossedRows, + track::TPCCrossedRowsOverFindableCls, + track::TPCFoundOverFindableCls, + track::TPCFractionSharedCls, + track::v001::ITSClusterMap, track::v001::ITSNCls, track::v001::ITSNClsInnerBarrel, + track::HasITS, track::HasTPC, track::HasTRD, track::HasTOF, + v0leg::MeanClusterSizeITS, + v0leg::MeanClusterSizeITSib, + v0leg::MeanClusterSizeITSob); +// iterators +using V0LegTmp = V0LegsTmp::iterator; + DECLARE_SOA_TABLE_VERSIONED(V0LegsXYZ_000, "AOD", "V0LEGXYZ", 0, track::X, track::Y, track::Z); using V0LegsXYZ = V0LegsXYZ_000; // iterators using V0LegXYZ = V0LegsXYZ::iterator; +// copy of V0Legs table +DECLARE_SOA_TABLE(V0LegsXYZTmp, "AOD", "V0LEGXYZTMP", track::X, track::Y, track::Z); +// iterators +using V0LegXYZTmp = V0LegsXYZTmp::iterator; + DECLARE_SOA_TABLE_VERSIONED(V0LegsDeDxMC_000, "AOD", "V0LEGDEDXMC", 0, mcpidtpc::DeDxTunedMc, o2::soa::Marker<2>); using V0LegsDeDxMC = V0LegsDeDxMC_000; // iterators using V0LegDeDxMC = V0LegsDeDxMC::iterator; +// copy of V0Legs table +DECLARE_SOA_TABLE_VERSIONED(V0LegsDeDxMCTmp, "AOD", "V0LEGDEDXMCTMP", 0, mcpidtpc::DeDxTunedMc, o2::soa::Marker<2>); +// iterators +using V0LegDeDxMCTmp = V0LegsDeDxMCTmp::iterator; + namespace emevent { DECLARE_SOA_COLUMN(NgPCM, ngpcm, int); @@ -347,6 +387,27 @@ using V0PhotonsKF = V0PhotonsKF_001; // iterators using V0PhotonKF = V0PhotonsKF::iterator; +// Clone of V0PhotonKF table for intermediate processing needed for dalitz +DECLARE_SOA_TABLE(V0PhotonsKFTmp, "AOD", "V0PHOTONKFTMP", //! + o2::soa::Index<>, v0photonkf::CollisionId, v0photonkf::V0Id, v0photonkf::PosTrackId, v0photonkf::NegTrackId, + v0photonkf::Vx, v0photonkf::Vy, v0photonkf::Vz, + v0photonkf::Px, v0photonkf::Py, v0photonkf::Pz, + v0photonkf::MGamma, + v0photonkf::DCAxyToPV, v0photonkf::DCAzToPV, + v0photonkf::CosPA, v0photonkf::CosPAXY, v0photonkf::CosPARZ, v0photonkf::PCA, + v0photonkf::Alpha, v0photonkf::QtArm, + v0photonkf::ChiSquareNDF, + + // dynamic column + v0photonkf::E, + v0photonkf::Pt, + v0photonkf::Eta, + v0photonkf::Phi, + v0photonkf::P, + v0photonkf::V0Radius); +// iterators +using V0PhotonKFTmp = V0PhotonsKFTmp::iterator; + DECLARE_SOA_TABLE(V0KFEMEventIds_000, "AOD", "V0KFEMEVENTID", v0photonkf::EMEventId); // To be joined with V0PhotonsKF table at analysis level. DECLARE_SOA_TABLE_VERSIONED(V0KFEMEventIds_001, "AOD", "V0KFEMEVENTID", 1, v0photonkf::PMEventId); // To be joined with V0PhotonsKF table at analysis level. using V0KFEMEventIds = V0KFEMEventIds_001; @@ -423,6 +484,45 @@ using EMPrimaryElectronsFromDalitz = EMPrimaryElectronsFromDalitz_001; // iterators using EMPrimaryElectronFromDalitz = EMPrimaryElectronsFromDalitz::iterator; +// Table that is a clone of EMPrimaryELectronsFromDalitz but needed for event selection purposes +DECLARE_SOA_TABLE(EMPrimaryElectronsFromDalitzTmp, "AOD", "EMPRIMARYELDATMP", //! + o2::soa::Index<>, emprimaryelectron::CollisionId, + emprimaryelectron::TrackId, emprimaryelectron::Sign, + track::Pt, track::Eta, track::Phi, track::DcaXY, track::DcaZ, track::CYY, track::CZY, track::CZZ, + track::TPCNClsFindable, track::TPCNClsFindableMinusFound, track::TPCNClsFindableMinusCrossedRows, track::TPCNClsShared, + track::TPCChi2NCl, track::TPCInnerParam, + track::TPCSignal, pidtpc::TPCNSigmaEl, pidtpc::TPCNSigmaPi, + pidtofbeta::Beta, pidtof::TOFNSigmaEl, + track::ITSClusterSizes, track::ITSChi2NCl, track::TOFChi2, track::DetectorMap, + + // dynamic column + track::TPCNClsFound, + track::TPCNClsCrossedRows, + track::TPCCrossedRowsOverFindableCls, + track::TPCFoundOverFindableCls, + track::v001::ITSClusterMap, track::v001::ITSNCls, track::v001::ITSNClsInnerBarrel, + track::TPCFractionSharedCls, + track::HasITS, track::HasTPC, track::HasTRD, track::HasTOF, + + emprimaryelectron::Signed1Pt, + emprimaryelectron::P, + emprimaryelectron::Px, + emprimaryelectron::Py, + emprimaryelectron::Pz, + emprimaryelectron::Tgl, + emprimaryelectron::MeanClusterSizeITS, + emprimaryelectron::MeanClusterSizeITSib, + emprimaryelectron::MeanClusterSizeITSob); + +// iterators +using EMPrimaryElectronFromDalitzTmp = EMPrimaryElectronsFromDalitzTmp::iterator; + +// copy of EMPrimaryElectronDeDxMC to use as intermediate step for Dalitz analysis +DECLARE_SOA_TABLE(EMPrimaryElectronsDeDxMCTmp, "AOD", "EMELDEDXMCTMP", mcpidtpc::DeDxTunedMc, o2::soa::Marker<1>); +using EMPrimaryElectronsDeDxMCTmp = EMPrimaryElectronsDeDxMCTmp; +// iterators +using EMPrimaryElectronDeDxMCTmp = EMPrimaryElectronsDeDxMCTmp::iterator; + namespace emprimaryelectronda { DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! @@ -445,6 +545,12 @@ DECLARE_SOA_TABLE(V0PhotonsPhiVPsi, "AOD", "V0PHOTONPHIVPSI", //! // iterators using V0PhotonsPhiVPsi = V0PhotonsPhiVPsi; +// clone for temporary table +DECLARE_SOA_TABLE(V0PhotonsPhiVPsiTmp, "AOD", "V0PHOTONPHIVTMP", //! + o2::soa::Index<>, v0photonsphivpsi::PhiV, v0photonsphivpsi::PsiPair); +// iterators +using V0PhotonsPhiVPsiTmp = V0PhotonsPhiVPsiTmp; + namespace dalitzee { DECLARE_SOA_INDEX_COLUMN(EMEvent, emevent); //! @@ -647,10 +753,10 @@ DECLARE_SOA_INDEX_COLUMN(EmEmcCluster, emEmcCluster); //! } // namespace trackmatching DECLARE_SOA_TABLE(EmEmcMTracks, "AOD", "EMEMCMTRACK", //! - trackmatching::EmEmcClusterId, emctm::DeltaPhi, emctm::DeltaEta, emctm::TrackP, emctm::TrackPt); + o2::soa::Index<>, trackmatching::EmEmcClusterId, emctm::DeltaPhi, emctm::DeltaEta, emctm::TrackP, emctm::TrackPt); DECLARE_SOA_TABLE(EmEmcMSTracks, "AOD", "EMEMCMSTRACK", //! - trackmatching::EmEmcClusterId, emctm::DeltaPhi, emctm::DeltaEta, emctm::TrackP, emctm::TrackPt); + o2::soa::Index<>, trackmatching::EmEmcClusterId, emctm::DeltaPhi, emctm::DeltaEta, emctm::TrackP, emctm::TrackPt); DECLARE_SOA_TABLE(EMCEMEventIds_000, "AOD", "EMCEMEVENTID", emccluster::EMEventId); // To be joined with SkimEMCClusters table at analysis level. DECLARE_SOA_TABLE_VERSIONED(EMCEMEventIds_001, "AOD", "EMCEMEVENTID", 1, emccluster::PMEventId); // To be joined with SkimEMCClusters table at analysis level. @@ -731,6 +837,7 @@ DECLARE_SOA_COLUMN(OmegaMBWeight, omegaMBWeight, float); DECLARE_SOA_TABLE(V0PhotonOmegaMBWeights, "AOD", "V0PHOTONMBW", v0photonMBweights::OmegaMBWeight); // store MB weights. To be joined with V0PhotonsKF table at analysis level. using V0PhotonOmegaMBWeight = V0PhotonOmegaMBWeights::iterator; + } // namespace o2::aod #endif // PWGEM_PHOTONMESON_DATAMODEL_GAMMATABLES_H_ diff --git a/PWGEM/PhotonMeson/Legacy/CMakeLists.txt b/PWGEM/PhotonMeson/Legacy/CMakeLists.txt index eb838a12cd8..0fae049d13a 100644 --- a/PWGEM/PhotonMeson/Legacy/CMakeLists.txt +++ b/PWGEM/PhotonMeson/Legacy/CMakeLists.txt @@ -38,3 +38,18 @@ o2physics_add_dpl_workflow(gammaconversionstruthonlymc SOURCES gammaConversionsTruthOnlyMc.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(material-budget + SOURCES MaterialBudget.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(material-budget-mc + SOURCES MaterialBudgetMC.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(pcm-qc-mc + SOURCES pcmQCMC.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) diff --git a/PWGEM/PhotonMeson/Tasks/MaterialBudget.cxx b/PWGEM/PhotonMeson/Legacy/MaterialBudget.cxx similarity index 100% rename from PWGEM/PhotonMeson/Tasks/MaterialBudget.cxx rename to PWGEM/PhotonMeson/Legacy/MaterialBudget.cxx diff --git a/PWGEM/PhotonMeson/Tasks/MaterialBudgetMC.cxx b/PWGEM/PhotonMeson/Legacy/MaterialBudgetMC.cxx similarity index 99% rename from PWGEM/PhotonMeson/Tasks/MaterialBudgetMC.cxx rename to PWGEM/PhotonMeson/Legacy/MaterialBudgetMC.cxx index 30bf1e1d469..4db16a9e817 100644 --- a/PWGEM/PhotonMeson/Tasks/MaterialBudgetMC.cxx +++ b/PWGEM/PhotonMeson/Legacy/MaterialBudgetMC.cxx @@ -131,7 +131,7 @@ struct MaterialBudgetMC { auto* list_pair_subsys_photoncut = dynamic_cast(list_pair_subsys->FindObject(photon_cut_name.data())); for (const auto& cut3 : cuts3) { - std::string pair_cut_name = cut3.getName(); + std::string const& pair_cut_name = cut3.getName(); o2::aod::pwgem::photon::histogram::AddHistClass(list_pair_subsys_photoncut, pair_cut_name.data()); auto* list_pair_subsys_paircut = dynamic_cast(list_pair_subsys_photoncut->FindObject(pair_cut_name.data())); o2::aod::pwgem::photon::histogram::DefineHistograms(list_pair_subsys_paircut, "material_budget_study", "Pair"); diff --git a/PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx b/PWGEM/PhotonMeson/Legacy/pcmQCMC.cxx similarity index 100% rename from PWGEM/PhotonMeson/Tasks/pcmQCMC.cxx rename to PWGEM/PhotonMeson/Legacy/pcmQCMC.cxx diff --git a/PWGEM/PhotonMeson/TableProducer/CMakeLists.txt b/PWGEM/PhotonMeson/TableProducer/CMakeLists.txt index 4cc5fb529b5..b7eaafafcaf 100644 --- a/PWGEM/PhotonMeson/TableProducer/CMakeLists.txt +++ b/PWGEM/PhotonMeson/TableProducer/CMakeLists.txt @@ -16,6 +16,11 @@ o2physics_add_dpl_workflow(photon-conversion-builder PUBLIC_LINK_LIBRARIES O2::Framework O2::DCAFitter O2Physics::AnalysisCore O2Physics::MLCore KFParticle::KFParticle O2Physics::TPCDriftManager COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(photon-conversion-builder-tmptable + SOURCES photonconversionbuilderTmpTable.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DCAFitter O2Physics::AnalysisCore O2Physics::MLCore KFParticle::KFParticle O2Physics::TPCDriftManager + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(create-emevent-photon SOURCES createEMEventPhoton.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGJECore @@ -46,6 +51,16 @@ o2physics_add_dpl_workflow(skimmer-primary-electron-from-dalitzee PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(skimmer-primary-electron-from-dalitzee-tmptable + SOURCES skimmerPrimaryElectronFromDalitzEETmpTable.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(skimmer-dalitz-events + SOURCES skimmerDalitzEvents.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(non-lin-producer SOURCES nonLinProducer.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore @@ -60,3 +75,8 @@ o2physics_add_dpl_workflow(material-budget-weights SOURCES materialBudgetWeights.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::CCDB ROOT::Hist ROOT::Core COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(event-selection-photon + SOURCES eventSelection.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx b/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx index 786e373470c..e89f5c765e6 100644 --- a/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx +++ b/PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx @@ -13,6 +13,7 @@ /// \brief This code produces EmMc tables were the McParticleIds get reshuffled due to not storing all McParticles /// \author Daiki Sekihata (daiki.sekihata@cern.ch), Marvin Hemmer (marvin.hemmer@cern.ch), Nicolas Strangmann (nicolas.strangmann@cern.ch) +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/MCUtilities.h" @@ -56,7 +57,7 @@ using namespace o2::soa; using namespace o2::aod::pwgem::photonmeson::utils::mcutil; using namespace o2::constants::physics; -using MyCollisionsMC = soa::Join; +using MyCollisionsMC = soa::Join; using TracksMC = soa::Join; using FwdTracksMC = soa::Join; using MyEMCClusters = soa::Join; diff --git a/PWGEM/PhotonMeson/TableProducer/createEMEventPhoton.cxx b/PWGEM/PhotonMeson/TableProducer/createEMEventPhoton.cxx index 4a3ab9a1a91..03aba7421de 100644 --- a/PWGEM/PhotonMeson/TableProducer/createEMEventPhoton.cxx +++ b/PWGEM/PhotonMeson/TableProducer/createEMEventPhoton.cxx @@ -50,7 +50,7 @@ using namespace o2::soa; using MyBCs = soa::Join; using MyQvectors = soa::Join; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollisionsCent = soa::Join; // centrality table has dependency on multiplicity table. using MyCollisionsCentQvec = soa::Join; @@ -95,6 +95,7 @@ struct CreateEMEventPhoton { template void skimEvent(TCollisions const& collisions, TBCs const&) { + for (const auto& collision : collisions) { if constexpr (isMC) { if (!collision.has_mcCollision()) { diff --git a/PWGEM/PhotonMeson/TableProducer/eventSelection.cxx b/PWGEM/PhotonMeson/TableProducer/eventSelection.cxx new file mode 100644 index 00000000000..64c46cda5b3 --- /dev/null +++ b/PWGEM/PhotonMeson/TableProducer/eventSelection.cxx @@ -0,0 +1,196 @@ +// 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. +// +// ======================== +// +// This code produces event selection table for PWG-EM Photon/Meson. + +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" +// +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/CCDB/TriggerAliases.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using EventAccBits = o2::aod::pmevsel::EventAcceptanceBits; + +using MyCollisions = soa::Join; +using MyCollisions_Cent = soa::Join; + +using MyCollisionsMC = soa::Join; +using MyCollisionsMC_Cent = soa::Join; + +struct PMEventSelection { + Produces pmevsel; + Produces pmevselbits; + + // Configurables + Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; + Configurable cfgCentMin{"cfgCentMin", -1.f, "min. centrality"}; + Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; + + // for RCT + Configurable cfgRequireGoodRCT{"cfgRequireGoodRCT", false, "require good detector flag in run condtion table"}; + Configurable cfgRCTLabel{"cfgRCTLabel", "CBT_hadronPID", "select 1 [CBT, CBT_hadronPID, CBT_muon_glo] see O2Physics/Common/CCDB/RCTSelectionFlags.h"}; + Configurable cfgCheckZDC{"cfgCheckZDC", false, "set ZDC flag for PbPb"}; + Configurable cfgTreatLimitedAcceptanceAsBad{"cfgTreatLimitedAcceptanceAsBad", false, "reject all events where the detectors relevant for the specified Runlist are flagged as LimitedAcceptance"}; + + Configurable cfgZvtxMin{"cfgZvtxMin", -1e+10, "min. Zvtx"}; + Configurable cfgZvtxMax{"cfgZvtxMax", 1e+10, "max. Zvtx"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", false, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgTrackOccupancyMin{"cfgTrackOccupancyMin", -2, "min. track occupancy"}; + Configurable cfgTrackOccupancyMax{"cfgTrackOccupancyMax", 1000000000, "max. track occupancy"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -2, "min. occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. occupancy"}; + Configurable cfgRequireNoCollInTimeRangeStandard{"cfgRequireNoCollInTimeRangeStandard", false, "require no collision in time range standard"}; + + Configurable cfgRequireTVXinEMC{"cfgRequireTVXinEMC", false, "require kTVXinEMC (only for EMC analyses)"}; + + Configurable cfgRequireSel8{"cfgRequireSel8", false, "require sel8 condition"}; + + o2::aod::rctsel::RCTFlagsChecker rctChecker; + + std::vector vecEvSelBits; + + void init(InitContext&) + { + rctChecker.init(cfgRCTLabel.value, cfgCheckZDC.value, cfgTreatLimitedAcceptanceAsBad.value); + vecEvSelBits.assign(EventAccBits::kSize, 0); + } + + template + bool isSelectedEvent(TCollision const& collision) + { + vecEvSelBits[EventAccBits::kAll]++; + if constexpr (std::is_same_v, MyCollisionsMC::iterator> || std::is_same_v, MyCollisionsMC_Cent::iterator>) { + if (!collision.has_mcCollision()) { + return false; + } + } + vecEvSelBits[EventAccBits::kHasMCColl]++; + + if (collision.posZ() < cfgZvtxMin || cfgZvtxMax < collision.posZ()) { + return false; + } + vecEvSelBits[EventAccBits::kGoodZVtx]++; + + if (cfgRequireFT0AND && !collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + return false; + } + vecEvSelBits[EventAccBits::kIsFT0AND]++; + + if (cfgRequireNoTFB && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + vecEvSelBits[EventAccBits::kNoTFB]++; + + if (cfgRequireNoITSROFB && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + vecEvSelBits[EventAccBits::kITSROFB]++; + + if (cfgRequireNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + vecEvSelBits[EventAccBits::kNoSameBunchPileUp]++; + + if (cfgRequireGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + vecEvSelBits[EventAccBits::kGoodZVtxFTOPV]++; + + if (cfgRequireNoCollInTimeRangeStandard && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + vecEvSelBits[EventAccBits::kNoCollInTimeRange]++; + + if (!(cfgTrackOccupancyMin <= collision.trackOccupancyInTimeRange() && collision.trackOccupancyInTimeRange() < cfgTrackOccupancyMax)) { + return false; + } + vecEvSelBits[EventAccBits::kGoodTrackOccupancy]++; + + if (!(cfgFT0COccupancyMin <= collision.ft0cOccupancyInTimeRange() && collision.ft0cOccupancyInTimeRange() < cfgFT0COccupancyMax)) { + return false; + } + vecEvSelBits[EventAccBits::kGoodFT0Occupancy]++; + + if (cfgRequireTVXinEMC && !collision.alias_bit(triggerAliases::kTVXinEMC)) { + return false; + } + vecEvSelBits[EventAccBits::kTVXInEMC]++; + + if constexpr (std::is_same_v, MyCollisions_Cent::iterator>) { + std::array centralities = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + return false; + } + } + vecEvSelBits[EventAccBits::kGoodCent]++; + + if (cfgRequireGoodRCT && !rctChecker.checkTable(collision)) { + // LOGF(info, "rejected by RCT flag"); + return false; + } + vecEvSelBits[EventAccBits::kGoodRCT]++; + + if (cfgRequireSel8 && !collision.sel8()) { + return false; + } + vecEvSelBits[EventAccBits::kGoodSel8]++; + + return true; + } + + template + void processEventSelection(TCollisions const& collisions) + { + // reset the event counter to zero for all elements + vecEvSelBits.assign(EventAccBits::kSize, 0); + + for (const auto& collision : collisions) { + pmevsel(isSelectedEvent(collision)); + } // end of collision loop + // Write event selection info at the end of DF + pmevselbits(vecEvSelBits); + } // end of process + + PROCESS_SWITCH_FULL(PMEventSelection, processEventSelection, processEventSelection, "event selection", true); + PROCESS_SWITCH_FULL(PMEventSelection, processEventSelection, processEventSelection_Cent, "event selection with cent", false); + PROCESS_SWITCH_FULL(PMEventSelection, processEventSelection, processEventSelectionMC, "event selection MC", false); + PROCESS_SWITCH_FULL(PMEventSelection, processEventSelection, processEventSelectionMC_Cent, "event selection MC with cent", false); +}; +WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& context) +{ + return WorkflowSpec{adaptAnalysisTask(context, TaskName{"em-event-selection"})}; +} diff --git a/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx index fbaf3238eeb..714a3ca3f72 100644 --- a/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx +++ b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx @@ -10,1750 +10,14 @@ // or submit itself to any jurisdiction. // -/// \file photonconversionbuilder.cxx +/// \file photonconversionbuilder.ch /// \brief this task produces photon data table with KFParticle. /// \author Daiki Sekihata , Tokyo -#ifndef HomogeneousField -#define HomogeneousField // o2-linter: disable=name/macro (name coming from KFParticle, not us, needed for KFParticle::SetField) -#endif +#include "PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.h" -#include "PWGEM/Dilepton/Utils/PairUtilities.h" -#include "PWGEM/PhotonMeson/Core/EmMlResponsePCM.h" -#include "PWGEM/PhotonMeson/Core/V0PhotonCandidate.h" -#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" -#include "PWGEM/PhotonMeson/DataModel/EventTables.h" -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" -#include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" -#include "PWGEM/PhotonMeson/Utils/TrackSelection.h" - -#include "Common/Core/RecoDecay.h" -#include "Common/Core/TPCVDriftManager.h" -#include "Common/Core/trackUtilities.h" -#include "Common/DataModel/Centrality.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponseTPC.h" -#include "Tools/KFparticle/KFUtilities.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) -#include -#include - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace o2; -using namespace o2::soa; -using namespace o2::framework; -using namespace o2::framework::expressions; -using namespace o2::constants::physics; -using namespace o2::pwgem::photonmeson; -using std::array; - -using MyCollisions = soa::Join; -// using MyCollisionsWithSWT = soa::Join; -using MyCollisionsMC = soa::Join; -using MyBCs = soa::Join; - -using MyTracksIU = soa::Join; -using MyTracksIUMC = soa::Join; - -enum MatCorrType { - None = 0, - TGeo = 1, - LUT = 2 -}; - -enum TrackPropMode { - kProper = 0, - kFast = 1, - kBoth = 2 -}; - -enum V0DeduplicationMode { - Pairwise = 0, // old algorithm, V0 with best PCA + cosPA at the same time in a group wins - GreedyMatching = 1, // new algorithm, best score wins (score combines PCA and cosPA -- see detailed implementation in PCMUtilities.cxx) - GroupMatching = 2, // new algorithm, best combination of leg-disjoint V0s wins, not the single best V0 - KeepAll = 3 // no deduplication, keep all V0s -}; - -// Struct needed for deduplication mode 1. Used to keep track of v0 properties and a score based on pca and cosPA -struct V0CandidateHelper { - int v0ID = -1; - int colID = -1; - int posID = -1; - int eleID = -1; - float cosPA = -1.f; - float pca = -1.f; - float score = -1.f; - float mee = 0.f; // e+e- mass at the secondary vertex (GeV/c^2) - - V0CandidateHelper() = default; - - V0CandidateHelper(int v0, int col, int pos, int ele, float cpa, float p, float s, float m = 0.f) - : v0ID(v0), colID(col), posID(pos), eleID(ele), cosPA(cpa), pca(p), score(s), mee(m) - { - } - - bool operator==(const V0CandidateHelper& other) const { return score == other.score; } - bool operator<(const V0CandidateHelper& other) const { return score < other.score; } - bool operator>(const V0CandidateHelper& other) const { return score > other.score; } -}; - -// (v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) -using CandKey = std::tuple; - -// Everything the truth diagnosis need, -struct DedupDiag { - std::map> blockersByKey; // rejected candidate -> ALL candidates that took one of its legs - std::vector snapshot; // ALL candidates, before deduplication - std::vector stored; // the survivors - // group matching only: rejected candidate -> (how many candidates the best solution CONTAINING - // it would have cost, by how much its best solution was worse in total score). - // deficit == 0 means an equally large alternative existed and the score alone decided. - std::map> lossMargin; -}; - -struct PhotonConversionBuilder { - Produces v0photonskf; - Produces v0legs; - Produces v0legsXYZ; - Produces v0legsDeDxMC; - Produces v0photonsphivpsi; - // Produces v0photonskfcov; - // Produces events_ngpcm; - - // CCDB options - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; - Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; - - // Operation and minimisation criteria - Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; - Configurable useMatCorrType{"useMatCorrType", 0, "0: none, 1: TGeo, 2: LUT"}; - Configurable modeTrackPropagation{"modeTrackPropagation", 0, "0: use real track propagation, including material, 1: use fast approximation using only geometry, 2: Use real track propagation and make comparison to fast propagation (only for debugging and testing)"}; - Configurable deduplicationMode{"deduplicationMode", 0, "0: Pairwise deduplication, 1: Based on Greedy matching (best score wins), 2: Based on Group matching (crossed pairs are both kept), 3: Keep all V0s, our default in the config is mode 0, however if a wrong configuration is used, the default will be mode 1 (Greedy matching) to avoid crashes"}; - Configurable deduplicationScoreWeight{"deduplicationScoreWeight", 0.5f, "0.:only pca goes into the score, 1: only cosPA goes itno score, any number in between is a mix of pca and cosPA"}; - Configurable cfgDedupTruthMaps{"cfgDedupTruthMaps", true, "fill the fine (dEta, dPhi, q) truth maps in MC"}; - Configurable dedupMaxGroupSize{"dedupMaxGroupSize", 12, "group matching (mode 2): conflict groups up to this size are solved exactly, larger ones greedily (capped at 16)"}; - - // single track cuts - Configurable min_ncluster_tpc{"min_ncluster_tpc", 0, "min ncluster tpc"}; - Configurable mincrossedrows{"mincrossedrows", 40, "min crossed rows"}; - Configurable moveTPCTracks{"moveTPCTracks", true, "Move TPC-only tracks under the collision assumption"}; - Configurable disableITSonlyTracks{"disableITSonlyTracks", false, "disable ITSonly tracks in V0 legs"}; - Configurable disableTPConlyTracks{"disableTPConlyTracks", false, "disable TPConly tracks in V0 legs"}; - Configurable requireITShit{"requireITShit", false, "require ITS hit to V0 legs"}; - - Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max chi2/NclsTPC"}; // default 4.0 + 1.0 - Configurable maxchi2its{"maxchi2its", 6.0, "max chi2/NclsITS"}; // default 5.0 + 1.0 - Configurable maxpt_itsonly{"maxpt_itsonly", 0.15, "max pT for ITSonly tracks at SV"}; - Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", 4.0, "max. TPC n sigma for electron"}; - Configurable minTPCNsigmaEl{"minTPCNsigmaEl", -4.0, "min. TPC n sigma for electron"}; - Configurable max_frac_shared_clusters_tpc{"max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; - Configurable dcanegtopv{"dcanegtopv", 0.1, "DCA Neg To PV"}; - Configurable dcapostopv{"dcapostopv", 0.1, "DCA Pos To PV"}; - Configurable maxX{"maxX", 83.1, "max X for track IU"}; - Configurable min_pt_trackiu{"min_pt_trackiu", 0.05, "min pT for trackiu"}; // this comes from online processing. pT of track seed is above 50 MeV/c in B = 0.5 T, 20 MeV/c in B = 0.2 T. - - // v0 cuts - Configurable min_v0cospa_tpconly{"min_v0cospa_tpconly", 0.99, "min V0 CosPA to V0s with TPConly tracks"}; // double -> N.B. dcos(x)/dx = 0 at x=0) - Configurable min_v0cospa_its{"min_v0cospa_its", 0.99, "min V0 CosPA to V0s with ITs hits"}; // double -> N.B. dcos(x)/dx = 0 at x=0) - Configurable max_dcav0dau_tpconly{"max_dcav0dau_tpconly", 3.0, "max distance btween 2 legs to V0s with TPConly tracks"}; - Configurable max_dcav0dau_its{"max_dcav0dau_its", 0.5, "max distance btween 2 legs to V0s with ITS hits"}; - Configurable max_dcav0dau_itsibss{"max_dcav0dau_itsibss", 1.0, "max distance btween 2 legs to V0s with ITS hits on ITSib SS"}; - Configurable max_dcav0dau_tpc_inner_fc{"max_dcav0dau_tpc_inner_fc", 1.5, "max distance btween 2 legs to V0s with ITS hits on TPC inner FC"}; - Configurable min_v0radius{"min_v0radius", 1.0, "min v0 radius"}; - Configurable max_v0radius{"max_v0radius", 90.0, "max v0 radius"}; - Configurable margin_r_its{"margin_r_its", 3.0, "margin for r cut in cm"}; - Configurable margin_r_tpc{"margin_r_tpc", 7.0, "margin for r cut in cm"}; - Configurable margin_r_itstpc_tpc{"margin_r_itstpc_tpc", 7.0, "margin for r cut in cm"}; - Configurable margin_z{"margin_z", 7.0, "margin for z cut in cm"}; - Configurable max_alpha_ap{"max_alpha_ap", 0.95, "max alpha for AP cut"}; - Configurable max_qt_ap{"max_qt_ap", 0.01, "max qT for AP cut"}; - Configurable min_pt_v0{"min_pt_v0", 0.1, "min pT for v0 photons at PV"}; - Configurable max_pt_v0_itsonly{"max_pt_v0_itsonly", 0.3, "max pT for v0 photons wth 2 ITSonly tracks at PV"}; - Configurable max_eta_v0{"max_eta_v0", 0.9, "max eta for v0 photons at PV"}; - Configurable kfMassConstrain{"kfMassConstrain", -1.f, "mass constrain for the KFParticle mother particle"}; - Configurable max_r_req_its{"max_r_req_its", 16.0, "max Rxy for V0 with ITS hits"}; - Configurable min_r_tpconly{"min_r_tpconly", 32.0, "min Rxy for V0 with TPConly tracks"}; - Configurable max_r_itsmft_ss{"max_r_itsmft_ss", 66.0, "max Rxy for ITS/MFT SS"}; - Configurable max_dcatopv_xy_v0{"max_dcatopv_xy_v0", +1e+10, "max. DCAxy to PV for V0"}; - Configurable max_dcatopv_z_v0{"max_dcatopv_z_v0", +1e+10, "max. DCAz to PV for V0"}; - Configurable reject_v0_on_itsib{"reject_v0_on_itsib", true, "flag to reject v0s on ITSib"}; - - // PCM ML inference - Configurable applyPCMMl{"applyPCMMl", false, "Flag to apply ML selections"}; - Configurable use2DBinning{"use2DBinning", false, "Flag to enable/disable 2D binning for ML application"}; - Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; - Configurable nClassesPCMMl{"nClassesPCMMl", static_cast(o2::analysis::em_cuts_ml::NCutScores), "Number of classes in ML model"}; - Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; - Configurable centTypePCMMl{"centTypePCMMl", 2, "Centrality type for 2D ML application: FT0M:0, FT0A:1, FT0C:2"}; - Configurable> cutDirPCMMl{"cutDirPCMMl", std::vector{o2::analysis::em_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; - Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; - Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{"path_ccdb/BDT_PCM/"}, "Paths of models on CCDB"}; - Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_onnx_PCM.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; - Configurable> labelsBinsPCMMl{"labelsBinsPCMMl", std::vector{"bin 0", "bin 1"}, "Labels for bins"}; - Configurable> labelsCutScoresPCMMl{"labelsCutScoresPCMMl", std::vector{o2::analysis::em_cuts_ml::labelsCutScore}, "Labels for cut scores"}; - Configurable> binsPtPCMMl{"binsPtPCMMl", std::vector{0.0, +1e+10}, "pT bin limits for ML application"}; - Configurable> binsCentPCMMl{"binsCentPCMMl", std::vector{0.0, 100.0}, "Centrality bin limits for ML application"}; - Configurable> cutsPCMMlFlat{"cutsPCMMlFlat", {0.5}, "Flattened ML cuts: [bin0_score0, bin0_score1, ..., binN_scoreM]"}; - - Configurable propV0LegsRadius{"propV0LegsRadius", 60.f, "Radius to which the V0 legs are propagated to calculate psipair and phiV"}; - - o2::analysis::EmMlResponsePCM emMlResponse; - std::vector outputML; - V0PhotonCandidate v0photoncandidate; - o2::ccdb::CcdbApi ccdbApi; - - int mRunNumber{}; - float d_bz{}; - float maxSnp{}; // max sine phi for propagation - float maxStep{}; // max step size (cm) for propagation - Service ccdb{}; - o2::base::MatLayerCylSet* lut = nullptr; - o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - o2::aod::common::TPCVDriftManager mVDriftMgr; - - HistogramRegistry registry{ - "registry", - { - {"hCollisionCounter", "hCollisionCounter", {HistType::kTH1F, {{1, 0.5f, 1.5f}}}}, - {"V0/hAP", "Armenteros Podolanski;#alpha;q_{T} (GeV/c)", {HistType::kTH2F, {{200, -1.0f, 1.0f}, {250, 0, 0.25}}}}, - {"V0/hConversionPointXY", "conversion point in XY;X (cm);Y (cm)", {HistType::kTH2F, {{400, -100.0f, 100.0f}, {400, -100.f, 100.f}}}}, - {"V0/hConversionPointRZ", "conversion point in RZ;Z (cm);R_{xy} (cm)", {HistType::kTH2F, {{200, -100.0f, 100.0f}, {200, 0.f, 100.f}}}}, - {"V0/hPt", "pT of V0 at PV;p_{T,#gamma} (GeV/c)", {HistType::kTH1F, {{1000, 0.0f, 10.0f}}}}, - {"V0/hEtaPhi", "#eta vs. #varphi of V0 at PV;#varphi (rad.);#eta", {HistType::kTH2F, {{72, 0.0f, o2::constants::math::TwoPI}, {200, -1, +1}}}}, - {"V0/hCosPA", "cosine of pointing angle;cosine of pointing angle", {HistType::kTH1F, {{100, 0.99f, 1.f}}}}, - {"V0/hCosPA_Rxy", "cosine of pointing angle;r_{xy} (cm);cosine of pointing angle", {HistType::kTH2F, {{200, 0, 100}, {100, 0.99f, 1.f}}}}, - {"V0/hCosPAXY_Rxy", "cosine of pointing angle;r_{xy} (cm);cosine of pointing angle", {HistType::kTH2F, {{200, 0, 100}, {100, 0.99f, 1.f}}}}, - {"V0/hCosPARZ_Rxy", "cosine of pointing angle;r_{xy} (cm);cosine of pointing angle", {HistType::kTH2F, {{200, 0, 100}, {100, 0.99f, 1.f}}}}, - {"V0/hPCA", "distance between 2 legs at SV;PCA (cm)", {HistType::kTH1F, {{500, 0.0f, 5.f}}}}, - {"V0/hPCA_Rxy", "distance between 2 legs at SV;R_{xy} (cm);PCA (cm)", {HistType::kTH2F, {{200, 0, 100}, {500, 0.0f, 5.f}}}}, - {"V0/hPCA_CosPA", "distance between 2 legs at SV vs. cosPA;cosine of pointing angle;PCA (cm)", {HistType::kTH2F, {{100, 0.99, 1}, {500, 0.0f, 5.f}}}}, - {"V0/hDCAxyz", "DCA to PV;DCA_{xy} (cm);DCA_{z} (cm)", {HistType::kTH2F, {{200, -5.f, +5.f}, {200, -5.f, +5.f}}}}, - {"V0/hMeeSV_Rxy", "mee at SV vs. R_{xy};R_{xy} (cm);m_{ee} at SV (GeV/c^{2})", {HistType::kTH2F, {{200, 0.0f, 100.f}, {100, 0, 0.1f}}}}, - {"V0/hRxy_minX_ITSonly_ITSonly", "min trackiu X vs. R_{xy};trackiu X (cm);min trackiu X - R_{xy} (cm)", {HistType::kTH2F, {{100, 0.0f, 100.f}, {100, -50.0, 50.0f}}}}, - {"V0/hRxy_minX_ITSTPC_ITSTPC", "min trackiu X vs. R_{xy};trackiu X (cm);min trackiu X - R_{xy} (cm)", {HistType::kTH2F, {{100, 0.0f, 100.f}, {100, -50.0, 50.0f}}}}, - {"V0/hRxy_minX_ITSTPC_ITSonly", "min trackiu X vs. R_{xy};trackiu X (cm);min trackiu X - R_{xy} (cm)", {HistType::kTH2F, {{100, 0.0f, 100.f}, {100, -50.0, 50.0f}}}}, - {"V0/hRxy_minX_ITSTPC_TPC", "min trackiu X vs. R_{xy};trackiu X (cm);min trackiu X - R_{xy} (cm)", {HistType::kTH2F, {{100, 0.0f, 100.f}, {100, -50.0, 50.0f}}}}, - {"V0/hRxy_minX_TPC_TPC", "min trackiu X vs. R_{xy};trackiu X (cm);min trackiu X - R_{xy} (cm)", {HistType::kTH2F, {{100, 0.0f, 100.f}, {100, -50.0, 50.0f}}}}, - {"V0/hPCA_diffX", "PCA vs. trackiu X - R_{xy};distance btween 2 legs (cm);min trackiu X - R_{xy} (cm)", {HistType::kTH2F, {{500, 0.0f, 5.f}, {100, -50.0, 50.0f}}}}, - {"V0/hPhiVPsiPair", "phiV vs. psi pair;#psi_{pair} (rad.);#phi_{V} (rad.)", {HistType::kTH2F, {{500, -o2::constants::math::PI, o2::constants::math::PI}, {500, 0.0f, o2::constants::math::TwoPI}}}}, - {"V0Leg/hPt", "pT of leg at SV;p_{T,e} (GeV/c)", {HistType::kTH1F, {{1000, 0.0f, 10.0f}}}}, - {"V0Leg/hEtaPhi", "#eta vs. #varphi of leg at SV;#varphi (rad.);#eta", {HistType::kTH2F, {{72, 0.0f, o2::constants::math::TwoPI}, {200, -1, +1}}}}, - {"V0Leg/hRelDeltaPt", "pT resolution;p_{T} (GeV/c);#Deltap_{T}/p_{T}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, 0, 1}}}}, - {"V0Leg/hDCAxyz", "DCA xy vs. z to PV;DCA_{xy} (cm);DCA_{z} (cm)", {HistType::kTH2F, {{200, -50.f, 50.f}, {200, -50.f, +50.f}}}}, - {"V0Leg/hdEdx_Pin", "TPC dE/dx vs. p_{in};p_{in} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{1000, 0.f, 10.f}, {200, 0.f, 200.f}}}}, - {"V0Leg/hTPCNsigmaEl", "TPC dE/dx vs. p_{in};p_{in} (GeV/c);n #sigma_{e}^{TPC}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5.f, +5.f}}}}, - {"V0Leg/hXZ", "track iu x vs. z;z (cm);x (cm)", {HistType::kTH2F, {{200, -100.f, 100.f}, {200, 0.f, 100.f}}}}, - }}; - - void init(InitContext&) - { - mRunNumber = 0; - d_bz = 0; - maxSnp = 0.85f; // could be changed later - maxStep = 2.00f; // could be changed later - - static constexpr std::array DedupNames = {"pairwise", "greedy matching", "group matching", "keep all"}; - if (deduplicationMode < 0 || deduplicationMode >= static_cast(DedupNames.size())) { - LOG(fatal) << "unknown deduplicationMode " << deduplicationMode.value; - } - LOGF(info, "photon-conversion-builder: deduplicationMode = %d (%s), score weight = %.2f", - deduplicationMode.value, DedupNames[deduplicationMode.value], deduplicationScoreWeight.value); - - ccdb->setURL(ccdburl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(false); - switch (useMatCorrType) { - case MatCorrType::TGeo: - LOGF(info, "TGeo correction requested, loading geometry"); - if (!o2::base::GeometryManager::isGeometryLoaded()) { - ccdb->get(geoPath); - } - matCorr = o2::base::Propagator::MatCorrType::USEMatCorrTGeo; - break; - case MatCorrType::LUT: - LOGF(info, "LUT correction requested, loading LUT"); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); - matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; - break; - default: - LOGF(info, "no correction requested, loading LUT by default!"); - lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); - matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; - break; - } - - if (applyPCMMl) { - if (use2DBinning) { - int binsNPt = static_cast(binsPtPCMMl->size()) - 1; - int binsNCent = static_cast(binsCentPCMMl->size()) - 1; - int binsN = binsNPt * binsNCent; - if (binsN * static_cast(cutDirPCMMl->size()) != static_cast(cutsPCMMlFlat->size())) { - LOG(fatal) << "Mismatch in number of bins and cuts provided for 2D ML application: binsN * cutDirPCMMl: " << binsN * static_cast(cutDirPCMMl->size()) << " bins vs. cutsPCMMlFlat: " << cutsPCMMlFlat->size() << " cuts"; - } - if (binsN != static_cast(onnxFileNames->size())) { - LOG(fatal) << "Mismatch in number of bins and ONNX files provided for 2D ML application: binsN " << binsN << " bins vs. onnxFileNames: " << onnxFileNames->size() << " ONNX files"; - } - if (binsN != static_cast(labelsBinsPCMMl->size())) { - LOG(fatal) << "Mismatch in number of bins and labels provided for 2D ML application: binsN:" << binsN << " bins vs. labelsBinsPCMMl: " << labelsBinsPCMMl->size() << " labels"; - } - if (static_cast(cutDirPCMMl->size()) != nClassesPCMMl) { - LOG(fatal) << "Mismatch in number of classes and cut directions provided for 2D ML application: nClassesPCMMl: " << nClassesPCMMl << " classes vs. cutDirPCMMl: " << cutDirPCMMl->size() << " cut directions"; - } - if (static_cast(labelsCutScoresPCMMl->size()) != nClassesPCMMl) { - LOG(fatal) << "Mismatch in number of labels for cut scores and number of classes provided for 2D ML application: nClassesPCMMl: " << nClassesPCMMl << " classes vs. labelsCutScoresPCMMl: " << labelsCutScoresPCMMl->size() << " labels"; - } - LabeledArray cutsPCMMl(cutsPCMMlFlat->data(), binsN, nClassesPCMMl, labelsBinsPCMMl, labelsCutScoresPCMMl); - emMlResponse.configure2D(binsPtPCMMl, binsCentPCMMl, cutsPCMMl, cutDirPCMMl, nClassesPCMMl); - } else { - int binsNPt = static_cast(binsPtPCMMl->size()) - 1; - if (binsNPt * static_cast(cutDirPCMMl->size()) != static_cast(cutsPCMMlFlat->size())) { - LOG(fatal) << "Mismatch in number of pT bins and cuts provided for ML application: binsNPt * cutDirPCMMl:" << binsNPt * cutDirPCMMl->size() << " bins vs. cutsPCMMlFlat: " << cutsPCMMlFlat->size() << " cuts"; - } - if (binsNPt != static_cast(onnxFileNames->size())) { - LOG(fatal) << "Mismatch in number of pT bins and ONNX files provided for ML application: binsNPt " << binsNPt << " bins vs. onnxFileNames: " << onnxFileNames->size() << " ONNX files"; - } - if (binsNPt != static_cast(labelsBinsPCMMl->size())) { - LOG(fatal) << "Mismatch in number of pT bins and labels provided for ML application: binsNPt:" << binsNPt << " bins vs. labelsBinsPCMMl: " << labelsBinsPCMMl->size() << " labels"; - } - if (nClassesPCMMl != static_cast(cutDirPCMMl->size())) { - LOG(fatal) << "Mismatch in number of classes and cut directions provided for ML application: nClassesPCMMl: " << nClassesPCMMl << " classes vs. cutDirPCMMl: " << cutDirPCMMl->size() << " cut directions"; - } - if (static_cast(labelsCutScoresPCMMl->size()) != nClassesPCMMl) { - LOG(fatal) << "Mismatch in number of labels for cut scores and number of classes provided for ML application: nClassesPCMMl:" << nClassesPCMMl << " classes vs. labelsCutScoresPCMMl: " << labelsCutScoresPCMMl->size() << " labels"; - } - LabeledArray cutsPCMMl(cutsPCMMlFlat->data(), binsNPt, nClassesPCMMl, labelsBinsPCMMl, labelsCutScoresPCMMl); - emMlResponse.configure(binsPtPCMMl, cutsPCMMl, cutDirPCMMl, nClassesPCMMl); - } - if (loadModelsFromCCDB) { - ccdbApi.init(ccdburl); - emMlResponse.setModelPathsCCDB(onnxFileNames, ccdbApi, modelPathsCCDB, timestampCCDB); - } else { - emMlResponse.setModelPathsLocal(onnxFileNames); - } - emMlResponse.cacheInputFeaturesIndices(namesInputFeatures); - emMlResponse.init(); - if (nClassesPCMMl == o2::analysis::NClassesML::kTwo) { - registry.add("V0/hBDTBackgroundScoreBeforeCutVsPt", "BDT background score before cut vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); - registry.add("V0/hBDTBackgroundScoreAfterCutVsPt", "BDT background score after cut vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); - registry.add("V0/hBDTSignalScoreBeforeCutVsPt", "BDT signal score before cut vs pT; pT (GeV/c); BDT signal score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); - registry.add("V0/hBDTSignalScoreAfterCutVsPt", "BDT signal score after cut vs pT; pT (GeV/c); BDT signal score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); - } else if (nClassesPCMMl == o2::analysis::NClassesML::kThree) { - registry.add("V0/hBDTBackgroundScoreBeforeCutVsPt", "BDT background score before cut vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); - registry.add("V0/hBDTBackgroundScoreAfterCutVsPt", "BDT background score after cut vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); - registry.add("V0/hBDTPrimaryPhotonScoreBeforeCutVsPt", "BDT primary photon score before cut vs pT; pT (GeV/c); BDT primary photon score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); - registry.add("V0/hBDTPrimaryPhotonScoreAfterCutVsPt", "BDT primary photon score after cut vs pT; pT (GeV/c); BDT primary photon score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); - registry.add("V0/hBDTSecondaryPhotonScoreBeforeCutVsPt", "BDT secondary photon score before cut vs pT; pT (GeV/c); BDT secondary photon score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); - registry.add("V0/hBDTSecondaryPhotonScoreAfterCutVsPt", "BDT secondary photon score after cut vs pT; pT (GeV/c); BDT secondary photon score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); - } else { - registry.add("V0/hBDTScoreBeforeCutVsPt", "BDT score before cut vs pT; pT (GeV/c); BDT score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); - registry.add("V0/hBDTScoreAfterCutVsPt", "BDT score after cut vs pT; pT (GeV/c); BDT score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); - } - } - - // Compare proper propagation and fast geometrical propagation - if (modeTrackPropagation == TrackPropMode::kBoth) { - registry.add("V0Leg/hDCAxyPropagationCompare", "Comparison of DCA_{xy} propagation;DCA_{xy} (cm) proper propagation; DCA_{xy} (cm) geom. propagation", {HistType::kTH2F, {{200, -10., 10.}, {200, -10., 10.}}}); - registry.add("V0Leg/hDCAzPropagationCompare", "Comparison of DCA_{z} propagation;DCA_{z} (cm) proper propagation; DCA_{z} (cm) geom. propagation", {HistType::kTH2F, {{200, -10., 10.}, {200, -10., 10.}}}); - registry.add("V0/hPhivPropagationCompare", "Comparison of #phi_{v};#phi_{v} proper propagation; #phi_{v} geom. propagation", {HistType::kTH2F, {{100, 0., 1.6}, {100, 0., 1.6}}}); - registry.add("V0/hPsiPairPropagationCompare", "Comparison of #Psi_{pair};#Psi_{pair} proper propagation; #Psi_{pair} geom. propagation", {HistType::kTH2F, {{100, 0., 1.6}, {100, 0., 1.6}}}); - } - - // Make sure the deduplicationScoreWeight is between 0 and 1 - if (deduplicationScoreWeight > 1.f) { // o2-linter: disable=magic-number (score has to be below unity) - LOG(warning) << "deduplicationScoreWeight is larger than unity which is not allowed"; - } - if (deduplicationScoreWeight < 0.f) { // o2-linter: disable=magic-number (score has to be above zero) - LOG(warning) << "deduplicationScoreWeight is smaller than zero which is not allowed"; - } - - if (doprocessMC) { - const AxisSpec axQ{60, 0.f, 0.3f, "q_{inv}^{true} (GeV/c)"}; - const AxisSpec axDEta{80, -1.6f, 1.6f, "#Delta#eta_{#gamma#gamma}^{true}"}; - const AxisSpec axClass{3, -0.5f, 2.5f, "0 = true, 1 = cross-leg fake, 2 = other fake"}; - // One folder per pair fate, with the SAME histogram names inside. The post-processing then - // only varies the folder, and everything belonging to one fate sits together. - // NB: the "lost..." folders are diagnostic selections, NOT an exclusive decomposition - - // lostByPartnerFake is a subset of lostByCrossFake, and a pair can appear in several of them. - for (const auto& nm : {"before", "bothSurvive", "bothSurviveSameColl", "oneLost", "bothLost", - "lostByCrossFake", "lostByPartnerFake", "lostByOtherFake", "lostByTrue"}) { - const std::string dir = std::string("MCDedup/Pairs/") + nm + "/"; - registry.add((dir + "hQ").c_str(), "truth photon pairs with >=1 true V0 candidate before deduplication;q_{inv}^{true} (GeV/c);pairs", kTH1F, {axQ}, true); - registry.add((dir + "hDEta").c_str(), "truth photon pairs with >=1 true V0 candidate before deduplication;#Delta#eta^{true};pairs", kTH1F, {axDEta}, true); - } - registry.add("MCDedup/Candidates/hClassStage", "candidate composition;class;0 = before, 1 = stored", kTH2F, {axClass, {2, -0.5f, 1.5f}}, true); - - const AxisSpec axBlocker{4, -0.5f, 3.5f, "0 = true, 1 = cross-leg fake, 2 = other fake, 3 = no blocker (cut, not dedup)"}; - - registry.add("MCDedup/Photons/hFate", "fate of the true photons;0 = alive, 1 = lost (blocked), 2 = lost (no blocker);photons", kTH1F, {{3, -0.5f, 2.5f}}, true); - registry.add("MCDedup/Photons/hBlockerClass", "blockers of a killed true photon (ENTRIES = blockers, not photons);class of the blocker;blocker entries", kTH1F, {axBlocker}, true); - // only meaningful for mode 0/1, where the smaller score always wins. Mode 2 compares SETS and - // may deliberately keep the worse-scoring candidates, so it is not filled there. - registry.add("MCDedup/Photons/hKillMargin", "mode 0/1 only;S_{victim} - S_{winner};kills", kTH1F, {{200, 0.f, 1.f}}, true); - registry.add("MCDedup/Photons/hVictimVsWinnerPCA", "PCA of the two;PCA_{victim} (cm);PCA_{winner} (cm)", kTH2F, {{60, 0.f, 3.f}, {60, 0.f, 3.f}}, true); - // mode 2 only: why exactly was this true photon not part of the winning set? - // x = 0 -> an equally large solution containing it existed, only the total score decided. - // That is a pure ranking problem and the part that a better discriminant can win back. - // x > 0 -> keeping it would have cost x candidates. Structural, no arbitration can repair it. - registry.add("MCDedup/Photons/hLostMargin", "why the true photon lost (mode 2);cardinality deficit;#Sigma S(best set with it) - #Sigma S(winner)", - kTH2F, {{5, -0.5f, 4.5f}, {100, 0.f, 2.f}}, true); - if (cfgDedupTruthMaps) { - const AxisSpec axDEtaFine{640, -1.6f, 1.6f, "#Delta#eta^{true}"}; - const AxisSpec axDPhi{144, -o2::constants::math::PI, o2::constants::math::PI, "#Delta#varphi^{true} (rad)"}; - for (const auto& nm : {"before", "bothSurvive", "bothLost", "lostByPartnerFake"}) { - // the fine map lands in the same folder as hQ and hDEta of that fate - registry.add((std::string("MCDedup/Pairs/") + nm + "/hMap").c_str(), "truth photon pairs", kTHnSparseF, {axDEtaFine, axDPhi, axQ}, true); - } - } - } - } - - void initCCDB(MyBCs::iterator const& bc) - { - if (mRunNumber == bc.runNumber()) { - return; - } - // In case override, don't proceed, please - no CCDB access required - if (d_bz_input > -990) { // o2-linter: disable=magic-number (override value) - d_bz = d_bz_input; - o2::parameters::GRPMagField grpmag; - if (std::fabs(d_bz) > 1e-5) { // o2-linter: disable=magic-number (override value) - grpmag.setL3Current(30000.f / (d_bz / 5.0f)); // o2-linter: disable=magic-number (override value) - } - o2::base::Propagator::initFieldFromGRP(&grpmag); - mRunNumber = bc.runNumber(); - return; - } - - auto run3grp_timestamp = bc.timestamp(); - o2::base::Propagator::initFieldFromGRP(&bc.grpMagField()); - // Fetch magnetic field from ccdb for current collision - d_bz = bc.grpMagField().getNominalL3Field(); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; - mRunNumber = bc.runNumber(); - - if (useMatCorrType == 2) { // o2-linter: disable=magic-number (material budget correction) - // setMatLUT only after magfield has been initalized (setMatLUT has implicit and problematic init field call if not) - o2::base::Propagator::Instance()->setMatLUT(lut); - } - /// Set magnetic field for KF vertexing - const float magneticField = o2::base::Propagator::Instance()->getNominalBz(); - KFParticle::SetField(magneticField); - - mVDriftMgr.init(&ccdb->instance()); - } - - void updateCCDB(MyBCs::iterator const& bc) - { - auto timestamp = bc.timestamp(); - - mVDriftMgr.update(timestamp); - } - - std::pair> its_ib_Requirement = {0, {0, 1, 2}}; // no hit on 3 ITS ib layers. - template - bool checkV0leg(TTrack const& track) - { - if constexpr (isMC) { - if (!track.has_mcParticle()) { - return false; - } - } - - if (disableITSonlyTracks && isITSonlyTrack(track)) { - return false; - } - - if (disableTPConlyTracks && isTPConlyTrack(track)) { - return false; - } - - if (requireITShit && !track.hasITS()) { - return false; - } - - if (track.x() > maxX) { - return false; - } - - if (!track.hasITS() && !track.hasTPC()) { - return false; - } - - if (track.hasITS() && !track.hasTPC() && (track.hasTRD() || track.hasTOF())) { // remove unrealistic track. this should not happen. - return false; - } - - if (track.hasTPC()) { - if (track.tpcNClsFound() < min_ncluster_tpc) { - return false; - } - if (track.tpcNClsCrossedRows() < mincrossedrows || track.tpcChi2NCl() > maxchi2tpc) { - return false; - } - if (track.tpcFractionSharedCls() > max_frac_shared_clusters_tpc) { - return false; - } - if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { - return false; - } - } - - if (track.hasITS()) { - if (track.itsChi2NCl() > maxchi2its) { - return false; - } - - if (reject_v0_on_itsib) { - auto hits_ib = std::count_if(its_ib_Requirement.second.begin(), its_ib_Requirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); - bool its_ob_only = hits_ib <= its_ib_Requirement.first; - if (!its_ob_only) { - return false; - } - } - } - - return true; - } - - float cospaXY_KF(const KFParticle& kfp, const KFParticle& PV) - { - float lx = kfp.GetX() - PV.GetX(); // flight length X - float ly = kfp.GetY() - PV.GetY(); // flight length Y - - float px = kfp.GetPx(); - float py = kfp.GetPy(); - float cospaXY = RecoDecay::dotProd(std::array{lx, ly}, std::array{px, py}) / (RecoDecay::sqrtSumOfSquares(lx, ly) * RecoDecay::sqrtSumOfSquares(px, py)); - if (cospaXY < -1.f) { - return -1.f; - } - if (cospaXY > 1.f) { - return 1.f; - } - return cospaXY; - } - - float cospaRZ_KF(const KFParticle& kfp, const KFParticle& PV) - { - float lx = kfp.GetX() - PV.GetX(); // flight length X - float ly = kfp.GetY() - PV.GetY(); // flight length Y - float lz = kfp.GetZ() - PV.GetZ(); // flight length Z - float lt = RecoDecay::sqrtSumOfSquares(lx, ly); // flight length R, i.e. transverse plane. - - float pt = RecoDecay::sqrtSumOfSquares(kfp.GetPx(), kfp.GetPy()); - float pz = kfp.GetPz(); - - float cospaRZ = RecoDecay::dotProd(std::array{lt, lz}, std::array{pt, pz}) / (RecoDecay::sqrtSumOfSquares(lt, lz) * RecoDecay::sqrtSumOfSquares(pt, pz)); - if (cospaRZ < -1.f) { - return -1.f; - } - if (cospaRZ > 1.f) { - return 1.f; - } - return cospaRZ; - } - - template - void fillTrackTable(TTrack const& track, TShiftedTrack const& shiftedtrack, const float dcaXY, const float dcaZ) - { - v0legs(track.collisionId(), track.globalIndex(), track.sign(), - shiftedtrack.GetPx(), shiftedtrack.GetPy(), shiftedtrack.GetPz(), dcaXY, dcaZ, - track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), track.tpcNClsShared(), - track.tpcChi2NCl(), track.tpcInnerParam(), track.tpcSignal(), - track.tpcNSigmaEl(), track.tpcNSigmaPi(), - track.itsClusterSizes(), track.itsChi2NCl(), track.detectorMap()); - - v0legsXYZ(shiftedtrack.GetX(), shiftedtrack.GetY(), shiftedtrack.GetZ()); - - if constexpr (isMC) { - v0legsDeDxMC(track.mcTunedTPCSignal()); - } - } - - template - void fillV0Table(TV0 const& v0, const bool filltable) - { - // Get tracks - const auto& pos = v0.template posTrack_as(); - const auto& ele = v0.template negTrack_as(); - const auto& collision = v0.template collision_as(); // collision where this v0 belongs to. - // LOGF(info, "v0.collisionId() = %d, pos.collisionId() = %d, ele.collisionId() = %d", v0.collisionId(), pos.collisionId(), ele.collisionId()); - - if (pos.sign() * ele.sign() > 0) { // reject same sign pair - return; - } - - if (pos.pt() < min_pt_trackiu || ele.pt() < min_pt_trackiu) { - return; - } - - if (pos.globalIndex() == ele.globalIndex()) { - return; - } - - if (isITSonlyTrack(pos) && !ele.hasITS()) { - return; - } - - if (isITSonlyTrack(ele) && !pos.hasITS()) { - return; - } - - if (!checkV0leg(pos) || !checkV0leg(ele)) { - return; - } - - // LOGF(info, "v0.collisionId() = %d , v0.posTrackId() = %d , v0.negTrackId() = %d", v0.collisionId(), v0.posTrackId(), v0.negTrackId()); - - // if(isTPConlyTrack(ele)){ - // // LOGF(info, "TPConly: ele.globalIndex() = %d, ele.x() = %f, ele.y() = %f, ele.z() = %f, ele.tgl() = %f, ele.alpha() = %f, ele.snp() = %f, ele.signed1Pt() = %f", ele.globalIndex(), ele.x(), ele.y(), ele.z(), ele.tgl(), ele.alpha(), ele.snp(), ele.signed1Pt()); - // // LOGF(info, "TPConly: ele.globalIndex() = %d, ele.cYY() = %f, ele.cZY() = %f, ele.cZZ() = %f, ele.cSnpY() = %f, ele.cSnpZ() = %f, ele.cSnpSnp() = %f, ele.cTglY() = %f, ele.cTglZ() = %f, ele.cTglSnp() = %f, ele.cTglTgl() = %f, ele.c1PtY() = %f, ele.c1PtZ() = %f, ele.c1PtSnp() = %f, ele.c1PtTgl() = %f, ele.c1Pt21Pt2() = %f", ele.globalIndex(), ele.cYY(), ele.cZY(), ele.cZZ(), ele.cSnpY(), ele.cSnpZ(), ele.cSnpSnp(), ele.cTglY(), ele.cTglZ(), ele.cTglSnp(), ele.cTglTgl(), ele.c1PtY(), ele.c1PtZ(), ele.c1PtSnp(), ele.c1PtTgl(), ele.c1Pt21Pt2()); - // } - - // Calculate DCA with respect to the collision associated to the v0, not individual tracks - std::array dcaInfo{}; - - auto pTrack = getTrackParCov(pos); - if (moveTPCTracks && isTPConlyTrack(pos) && !mVDriftMgr.moveTPCTrack(collision, pos, pTrack)) { - LOGP(error, "failed correction for positive tpc track"); - return; - } - auto pTrackC = pTrack; - o2::math_utils::Point3D vtxPrim{ - collision.posX(), - collision.posY(), - collision.posZ()}; - if (modeTrackPropagation != TrackPropMode::kProper) { - dcaInfo = CalculateDCAFast(pTrackC, vtxPrim, d_bz); - } - pTrackC.setPID(o2::track::PID::Electron); - - std::array dcaInfoFast = dcaInfo; - if (modeTrackPropagation != TrackPropMode::kFast) { - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrackC, 2.f, matCorr, &dcaInfo); - if (filltable && modeTrackPropagation == TrackPropMode::kBoth) { - registry.fill(HIST("V0Leg/hDCAxyPropagationCompare"), dcaInfo[0], dcaInfoFast[0]); - registry.fill(HIST("V0Leg/hDCAzPropagationCompare"), dcaInfo[1], dcaInfoFast[1]); - } - } - auto posdcaXY = dcaInfo[0]; - auto posdcaZ = dcaInfo[1]; - - auto nTrack = getTrackParCov(ele); - if (moveTPCTracks && isTPConlyTrack(ele) && !mVDriftMgr.moveTPCTrack(collision, ele, nTrack)) { - LOGP(error, "failed correction for negative tpc track"); - return; - } - auto nTrackC = nTrack; - if (modeTrackPropagation != TrackPropMode::kProper) { - dcaInfo = CalculateDCAFast(nTrackC, vtxPrim, d_bz); - } - nTrackC.setPID(o2::track::PID::Electron); - - dcaInfoFast = dcaInfo; - if (modeTrackPropagation != TrackPropMode::kFast) { - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrackC, 2.f, matCorr, &dcaInfo); - if (filltable && modeTrackPropagation == TrackPropMode::kBoth) { - registry.fill(HIST("V0Leg/hDCAxyPropagationCompare"), dcaInfo[0], dcaInfoFast[0]); - registry.fill(HIST("V0Leg/hDCAzPropagationCompare"), dcaInfo[1], dcaInfoFast[1]); - } - } - auto eledcaXY = dcaInfo[0]; - auto eledcaZ = dcaInfo[1]; - - if (std::fabs(posdcaXY) < dcapostopv || std::fabs(eledcaXY) < dcanegtopv) { - return; - } - - std::array xyz = {0.f, 0.f, 0.f}; - Vtx_recalculationParCov(o2::base::Propagator::Instance(), pTrack, nTrack, xyz, matCorr); - float rxy_tmp = RecoDecay::sqrtSumOfSquares(xyz[0], xyz[1]); - if (rxy_tmp > maxX + margin_r_tpc) { - return; - } - if (rxy_tmp < std::fabs(xyz[2]) * std::tan(2 * std::atan(std::exp(-max_eta_v0))) - margin_z) { - return; // RZ line cut - } - - float phiv = 999.f; - float psipair = 999.f; - float phivFast = 999.f; - float psipairFast = 999.f; - float baseR = std::hypot(xyz[0], xyz[1]); - // This method uses the track Helix instead of the full propagation. - // Hence, it is only an approximation but much faster - if (modeTrackPropagation != TrackPropMode::kProper) { - - o2::track::TrackAuxPar helixPosEle(nTrack, d_bz); - o2::track::TrackAuxPar helixPosPos(pTrack, d_bz); - - float diffX = helixPosEle.xC - helixPosPos.xC; - float diffY = helixPosEle.yC - helixPosPos.yC; - auto phiHelix = RecoDecay::constrainAngle(std::atan2(diffY, diffX) - o2::constants::math::PI / 2.); - - // Electron - float arcLenghtEle = helixPosEle.rC * 0.9 > propV0LegsRadius ? std::asin(propV0LegsRadius / helixPosEle.rC) * helixPosEle.rC : o2::constants::math::PI / 2.2 * helixPosEle.rC; // This assumes that the photon momentum vector is a tangent of the circle // o2-linter: disable=magic-number (geometrical assumption for propagation) - auto propTrackEle = getPropMomentumFromTrackHelix(arcLenghtEle, ele, helixPosEle, d_bz / 10., phiHelix - ele.phi()); - // Positron - float arcLenghtPos = helixPosPos.rC * 0.9 > propV0LegsRadius ? std::asin(propV0LegsRadius / helixPosPos.rC) * helixPosPos.rC : o2::constants::math::PI / 2.2 * helixPosPos.rC; // This assumes that the photon momentum vector is a tangent of the circle // o2-linter: disable=magic-number (geometrical assumption for propagation) - auto propTrackPos = getPropMomentumFromTrackHelix(arcLenghtPos, pos, helixPosPos, d_bz / 10., phiHelix - pos.phi()); - - phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(propTrackPos[0], propTrackPos[1], propTrackPos[2], propTrackEle[0], propTrackEle[1], propTrackEle[2], pos.sign(), ele.sign(), d_bz); - psipair = o2::aod::pwgem::dilepton::utils::pairutil::getPsiPair(propTrackPos[0], propTrackPos[1], propTrackPos[2], propTrackEle[0], propTrackEle[1], propTrackEle[2]); - - // Store values for later comparison - phivFast = phiv; - psipairFast = psipair; - } - // This uses the full propagation including material effects - if (modeTrackPropagation != TrackPropMode::kFast) { - std::array offsetsR = {propV0LegsRadius, 30.f, 10.f}; - bool pPropagatedSuccess = false; - bool nPropagatedSuccess = false; - auto pTrackProp = pTrack; - auto nTrackProp = nTrack; - for (const auto& offsetR : offsetsR) { - pTrackProp = pTrack; - pTrackProp.setPID(o2::track::PID::Electron); - nTrackProp = nTrack; - nTrackProp.setPID(o2::track::PID::Electron); - - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrackProp, 2.f, matCorr, &dcaInfo); - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrackProp, 2.f, matCorr, &dcaInfo); - - pPropagatedSuccess = o2::base::Propagator::Instance()->propagateToR(pTrackProp, baseR + offsetR); - nPropagatedSuccess = o2::base::Propagator::Instance()->propagateToR(nTrackProp, baseR + offsetR); - - if (pPropagatedSuccess && nPropagatedSuccess) { - KFPTrack kfp_track_posProp = createKFPTrackFromTrackParCov(pTrackProp, pos.sign(), pos.tpcNClsFound(), pos.tpcChi2NCl()); - KFPTrack kfp_track_eleProp = createKFPTrackFromTrackParCov(nTrackProp, ele.sign(), ele.tpcNClsFound(), ele.tpcChi2NCl()); - phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(kfp_track_posProp.GetPx(), kfp_track_posProp.GetPy(), kfp_track_posProp.GetPz(), kfp_track_eleProp.GetPx(), kfp_track_eleProp.GetPy(), kfp_track_eleProp.GetPz(), pos.sign(), ele.sign(), d_bz); - psipair = o2::aod::pwgem::dilepton::utils::pairutil::getPsiPair(kfp_track_posProp.GetPx(), kfp_track_posProp.GetPy(), kfp_track_posProp.GetPz(), kfp_track_eleProp.GetPx(), kfp_track_eleProp.GetPy(), kfp_track_eleProp.GetPz()); - break; - } - LOG(debug) << "Propagation to offset" << offsetR << " cm failed for " << (pPropagatedSuccess ? "negative" : "positive") << " track. Trying smaller offset."; - } - if (filltable && modeTrackPropagation == TrackPropMode::kBoth) { - registry.fill(HIST("V0/hPhivPropagationCompare"), phiv, phivFast); - registry.fill(HIST("V0/hPsiPairPropagationCompare"), psipair, psipairFast); - } - } - - if (phiv == 999.f || psipair == 999.f) { // o2-linter: disable=magic-number (nonsensical default value) - LOG(debug) << "Propagation failed for all radii (" << propV0LegsRadius << ", 30, 10 cm). Using default values for phiv and psipair (999.f)."; - } - - KFPTrack kfp_track_pos = createKFPTrackFromTrackParCov(pTrack, pos.sign(), pos.tpcNClsFound(), pos.tpcChi2NCl()); - KFPTrack kfp_track_ele = createKFPTrackFromTrackParCov(nTrack, ele.sign(), ele.tpcNClsFound(), ele.tpcChi2NCl()); - KFParticle kfp_pos(kfp_track_pos, kPositron); - KFParticle kfp_ele(kfp_track_ele, kElectron); - std::array GammaDaughters{&kfp_pos, &kfp_ele}; - - KFParticle gammaKF; - gammaKF.SetConstructMethod(2); - gammaKF.Construct(GammaDaughters.data(), 2); - if (kfMassConstrain > -0.1) { // o2-linter: disable=magic-number (nonsensical default value) - gammaKF.SetNonlinearMassConstraint(kfMassConstrain); - } - KFPVertex kfpVertex = createKFPVertexFromCollision(collision); - KFParticle KFPV(kfpVertex); - - // Transport the gamma to the recalculated decay vertex - KFParticle gammaKF_DecayVtx = gammaKF; // with respect to (0,0,0) - gammaKF_DecayVtx.TransportToPoint(xyz.data()); - - float cospa_kf = cpaFromKF(gammaKF_DecayVtx, KFPV); - if (!ele.hasITS() && !pos.hasITS()) { - if (cospa_kf < min_v0cospa_tpconly) { - return; - } - } else { - if (cospa_kf < min_v0cospa_its) { - return; - } - } - - float rxy = RecoDecay::sqrtSumOfSquares(gammaKF_DecayVtx.GetX(), gammaKF_DecayVtx.GetY()); - if (rxy > maxX + margin_r_tpc) { - return; - } - if (rxy < std::fabs(gammaKF_DecayVtx.GetZ()) * std::tan(2 * std::atan(std::exp(-max_eta_v0))) - margin_z) { - return; // RZ line cut - } - if (rxy < min_v0radius || max_v0radius < rxy) { - return; - } - - if (!filltable) { - if (isITSTPCTrack(pos) && isITSTPCTrack(ele)) { - registry.fill(HIST("V0/hRxy_minX_ITSTPC_ITSTPC"), std::min(pTrack.getX(), nTrack.getX()), std::min(pTrack.getX(), nTrack.getX()) - rxy); // trackiu.x() - rxy should be positive - } else if (isITSonlyTrack(pos) && isITSonlyTrack(ele)) { - registry.fill(HIST("V0/hRxy_minX_ITSonly_ITSonly"), std::min(pTrack.getX(), nTrack.getX()), std::min(pTrack.getX(), nTrack.getX()) - rxy); // trackiu.x() - rxy should be positive - } else if ((isITSTPCTrack(pos) && isITSonlyTrack(ele)) || (isITSTPCTrack(ele) && isITSonlyTrack(pos))) { - registry.fill(HIST("V0/hRxy_minX_ITSTPC_ITSonly"), std::min(pTrack.getX(), nTrack.getX()), std::min(pTrack.getX(), nTrack.getX()) - rxy); // trackiu.x() - rxy should be positive - } else if (isITSTPCTrack(pos) && !ele.hasITS()) { - registry.fill(HIST("V0/hRxy_minX_ITSTPC_TPC"), std::min(pTrack.getX(), 83.f), std::min(pTrack.getX(), 83.f) - rxy); // trackiu.x() - rxy should be positive - } else if (isITSTPCTrack(ele) && !pos.hasITS()) { - registry.fill(HIST("V0/hRxy_minX_ITSTPC_TPC"), std::min(nTrack.getX(), 83.f), std::min(nTrack.getX(), 83.f) - rxy); // trackiu.x() - rxy should be positive - } else { - registry.fill(HIST("V0/hRxy_minX_TPC_TPC"), std::min(83.f, 83.f), std::min(83.f, 83.f) - rxy); // trackiu.x() - rxy should be positive - } - } - - if (pos.hasITS() && ele.hasITS()) { // ITSonly-ITSonly, ITSTPC-ITSTPC, ITSTPC-ITSonly - if (rxy > std::min(pTrack.getX(), nTrack.getX()) + margin_r_its) { - return; - } - } else if (!pos.hasITS() && ele.hasITS()) { // ITSTPC-TPC - if (rxy > std::min(83.f, nTrack.getX()) + margin_r_itstpc_tpc) { - return; - } - } else if (pos.hasITS() && !ele.hasITS()) { // ITSTPC-TPC - if (rxy > std::min(pTrack.getX(), 83.f) + margin_r_itstpc_tpc) { - return; - } - } else if (!pos.hasITS() && !ele.hasITS()) { // TPC-TPC - if (rxy > std::min(83.f, 83.f) + margin_r_tpc) { - return; - } - } - - if ((!pos.hasITS() || !ele.hasITS()) && rxy < max_r_req_its) { // conversion points smaller than max_r_req_its have to be detected with ITS hits. - return; - } - - if ((!pos.hasITS() && !ele.hasITS()) && rxy < min_r_tpconly) { // TPConly tracks can detect conversion points larger than min_r_tpconly. - return; - } - - // Apply a topological constraint of the gamma to the PV. Parameters will be given at the primary vertex. - KFParticle gammaKF_PV = gammaKF; - gammaKF_PV.SetProductionVertex(KFPV); - float v0pt = RecoDecay::sqrtSumOfSquares(gammaKF_PV.GetPx(), gammaKF_PV.GetPy()); - float v0eta = RecoDecay::eta(std::array{gammaKF_PV.GetPx(), gammaKF_PV.GetPy(), gammaKF_PV.GetPz()}); - float v0phi = RecoDecay::constrainAngle(RecoDecay::phi(gammaKF_PV.GetPx(), gammaKF_PV.GetPy())); - - // KFParticle gammaKF_DecayVtx2 = gammaKF; - // gammaKF_DecayVtx2.SetProductionVertex(KFPV); - // gammaKF_DecayVtx2.TransportToPoint(xyz); - // LOGF(info, "gammaKF_PV.GetPx() = %f, gammaKF_DecayVtx.GetPx() = %f, gammaKF_DecayVtx2.GetPx() = %f", gammaKF_PV.GetPx(), gammaKF_DecayVtx.GetPx(), gammaKF_DecayVtx2.GetPx()); - // LOGF(info, "gammaKF_PV.GetPy() = %f, gammaKF_DecayVtx.GetPy() = %f, gammaKF_DecayVtx2.GetPy() = %f", gammaKF_PV.GetPy(), gammaKF_DecayVtx.GetPy(), gammaKF_DecayVtx2.GetPy()); - // LOGF(info, "gammaKF_PV.GetPz() = %f, gammaKF_DecayVtx.GetPz() = %f, gammaKF_DecayVtx2.GetPz() = %f", gammaKF_PV.GetPz(), gammaKF_DecayVtx.GetPz(), gammaKF_DecayVtx2.GetPz()); - - if (std::fabs(v0eta) > max_eta_v0 || v0pt < min_pt_v0) { - return; - } - - if (isITSonlyTrack(ele) && isITSonlyTrack(pos) && v0pt > max_pt_v0_itsonly) { - return; - } - - KFParticle kfp_pos_DecayVtx = kfp_pos; // Don't set Primary Vertex - KFParticle kfp_ele_DecayVtx = kfp_ele; // Don't set Primary Vertex - kfp_pos_DecayVtx.TransportToPoint(xyz.data()); // Don't set Primary Vertex - kfp_ele_DecayVtx.TransportToPoint(xyz.data()); // Don't set Primary Vertex - - float cospaXYKF = cospaXY_KF(gammaKF_DecayVtx, KFPV); - float cospaRZKF = cospaRZ_KF(gammaKF_DecayVtx, KFPV); - auto centType = static_cast(centTypePCMMl.value); - v0photoncandidate.setPhotonCandidate(gammaKF_DecayVtx, gammaKF_PV, pos, kfp_pos_DecayVtx, ele, kfp_ele_DecayVtx, collision, cospaXYKF, cospaRZKF, cospaXYKF, psipair, phiv, centType, posdcaXY, eledcaXY, posdcaZ, eledcaZ); - - if (!ele.hasITS() && !pos.hasITS()) { // V0s with TPConly-TPConly - if (max_r_itsmft_ss < rxy && rxy < maxX + margin_r_tpc) { - if (v0photoncandidate.getPCA() > max_dcav0dau_tpc_inner_fc) { - return; - } - } else { - if (v0photoncandidate.getPCA() > max_dcav0dau_tpconly) { - return; - } - } - } else { // V0s with ITS hits - if (rxy < max_r_req_its) { - if (v0photoncandidate.getPCA() > max_dcav0dau_itsibss) { - return; - } - } else { - if (v0photoncandidate.getPCA() > max_dcav0dau_its) { - return; - } - } - } - - if (isITSonlyTrack(pos) && v0photoncandidate.getPosPt() > maxpt_itsonly) { - return; - } - - if (isITSonlyTrack(ele) && v0photoncandidate.getElePt() > maxpt_itsonly) { - return; - } - - if (v0photoncandidate.getChi2NDF() > 6e+3) { // protection for uint16. // o2-linter: disable=magic-number (protection for uint16) - return; - } - - if (std::fabs(v0photoncandidate.getDcaXYToPV()) > max_dcatopv_xy_v0 || std::fabs(v0photoncandidate.getDcaZToPV()) > max_dcatopv_z_v0) { - return; - } - - if (!checkAP(v0photoncandidate.getAlpha(), v0photoncandidate.getQt(), max_alpha_ap, max_qt_ap)) { // store only photon conversions - return; - } - pca_map[std::make_tuple(v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex())] = v0photoncandidate.getPCA(); - cospa_map[std::make_tuple(v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex())] = v0photoncandidate.getCosPA(); - - ROOT::Math::PxPyPzMVector vposDedup(kfp_pos_DecayVtx.GetPx(), kfp_pos_DecayVtx.GetPy(), kfp_pos_DecayVtx.GetPz(), o2::constants::physics::MassElectron); - ROOT::Math::PxPyPzMVector veleDedup(kfp_ele_DecayVtx.GetPx(), kfp_ele_DecayVtx.GetPy(), kfp_ele_DecayVtx.GetPz(), o2::constants::physics::MassElectron); - const auto meeSV = static_cast((vposDedup + veleDedup).M()); - - const auto score = getScoreV0(v0photoncandidate.getCosPA(), v0photoncandidate.getPCA(), deduplicationScoreWeight); - V0CandidateHelper v0Helper(v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex(), - v0photoncandidate.getCosPA(), v0photoncandidate.getPCA(), score, meeSV); - vecV0Dedup.emplace_back(v0Helper); - - if (applyPCMMl) { - bool isSelectedML = false; - std::vector mlInputFeatures = emMlResponse.getInputFeatures(v0photoncandidate, pos, ele); - if (use2DBinning) { - isSelectedML = emMlResponse.isSelectedMl(mlInputFeatures, v0photoncandidate.getPt(), v0photoncandidate.getCent(), outputML); - } else { - isSelectedML = emMlResponse.isSelectedMl(mlInputFeatures, v0photoncandidate.getPt(), outputML); - } - if (filltable) { - if (nClassesPCMMl == o2::analysis::NClassesML::kTwo) { - registry.fill(HIST("V0/hBDTBackgroundScoreBeforeCutVsPt"), v0photoncandidate.getPt(), outputML[0]); - registry.fill(HIST("V0/hBDTSignalScoreBeforeCutVsPt"), v0photoncandidate.getPt(), outputML[1]); - } else if (nClassesPCMMl == o2::analysis::NClassesML::kThree) { - registry.fill(HIST("V0/hBDTPrimaryPhotonScoreBeforeCutVsPt"), v0photoncandidate.getPt(), outputML[0]); - registry.fill(HIST("V0/hBDTSecondaryPhotonScoreBeforeCutVsPt"), v0photoncandidate.getPt(), outputML[1]); - registry.fill(HIST("V0/hBDTBackgroundScoreBeforeCutVsPt"), v0photoncandidate.getPt(), outputML[2]); - } else { - registry.fill(HIST("V0/hBDTScoreBeforeCutVsPt"), v0photoncandidate.getPt(), outputML[0]); - } - } - if (!isSelectedML) { - return; - } - if (filltable) { - if (nClassesPCMMl == o2::analysis::NClassesML::kTwo) { - registry.fill(HIST("V0/hBDTBackgroundScoreAfterCutVsPt"), v0photoncandidate.getPt(), outputML[0]); - registry.fill(HIST("V0/hBDTSignalScoreAfterCutVsPt"), v0photoncandidate.getPt(), outputML[1]); - } else if (nClassesPCMMl == o2::analysis::NClassesML::kThree) { - registry.fill(HIST("V0/hBDTPrimaryPhotonScoreAfterCutVsPt"), v0photoncandidate.getPt(), outputML[0]); - registry.fill(HIST("V0/hBDTSecondaryPhotonScoreAfterCutVsPt"), v0photoncandidate.getPt(), outputML[1]); - registry.fill(HIST("V0/hBDTBackgroundScoreAfterCutVsPt"), v0photoncandidate.getPt(), outputML[2]); - } else { - registry.fill(HIST("V0/hBDTScoreAfterCutVsPt"), v0photoncandidate.getPt(), outputML[0]); - } - } - } - - if (filltable) { - registry.fill(HIST("V0/hAP"), v0photoncandidate.getAlpha(), v0photoncandidate.getQt()); - registry.fill(HIST("V0/hConversionPointXY"), gammaKF_DecayVtx.GetX(), gammaKF_DecayVtx.GetY()); - registry.fill(HIST("V0/hConversionPointRZ"), gammaKF_DecayVtx.GetZ(), rxy); - registry.fill(HIST("V0/hPt"), v0photoncandidate.getPt()); - registry.fill(HIST("V0/hEtaPhi"), v0phi, v0eta); - registry.fill(HIST("V0/hCosPA"), v0photoncandidate.getCosPA()); - registry.fill(HIST("V0/hCosPA_Rxy"), rxy, v0photoncandidate.getCosPA()); - registry.fill(HIST("V0/hPCA"), v0photoncandidate.getPCA()); - registry.fill(HIST("V0/hPCA_CosPA"), v0photoncandidate.getCosPA(), v0photoncandidate.getPCA()); - registry.fill(HIST("V0/hPCA_Rxy"), rxy, v0photoncandidate.getPCA()); - registry.fill(HIST("V0/hDCAxyz"), v0photoncandidate.getDcaXYToPV(), v0photoncandidate.getDcaZToPV()); - registry.fill(HIST("V0/hPCA_diffX"), v0photoncandidate.getPCA(), std::min(pTrack.getX(), nTrack.getX()) - rxy); // trackiu.x() - rxy should be positive - registry.fill(HIST("V0/hPhiVPsiPair"), v0photoncandidate.getPsiPair(), v0photoncandidate.getPhiV()); - - // LOGF(info, "cospa_kf = %f, cospaXY_kf = %f, cospaRZ_kf = %f", cospa_kf, cospaXY_kf, cospaRZ_kf); - registry.fill(HIST("V0/hCosPAXY_Rxy"), rxy, cospaXYKF); - registry.fill(HIST("V0/hCosPARZ_Rxy"), rxy, cospaRZKF); - - for (const auto& leg : {kfp_pos_DecayVtx, kfp_ele_DecayVtx}) { - float legpt = RecoDecay::sqrtSumOfSquares(leg.GetPx(), leg.GetPy()); - float legeta = RecoDecay::eta(std::array{leg.GetPx(), leg.GetPy(), leg.GetPz()}); - float legphi = RecoDecay::constrainAngle(RecoDecay::phi(leg.GetPx(), leg.GetPy())); - registry.fill(HIST("V0Leg/hPt"), legpt); - registry.fill(HIST("V0Leg/hEtaPhi"), legphi, legeta); - } // end of leg loop - for (const auto& leg : {pos, ele}) { - registry.fill(HIST("V0Leg/hdEdx_Pin"), leg.tpcInnerParam(), leg.tpcSignal()); - registry.fill(HIST("V0Leg/hTPCNsigmaEl"), leg.tpcInnerParam(), leg.tpcNSigmaEl()); - } // end of leg loop - for (const auto& leg : {pTrack, nTrack}) { - registry.fill(HIST("V0Leg/hXZ"), leg.getZ(), leg.getX()); - registry.fill(HIST("V0Leg/hRelDeltaPt"), leg.getPt(), leg.getPt() * std::sqrt(leg.getSigma1Pt2())); - } // end of leg loop - registry.fill(HIST("V0Leg/hDCAxyz"), posdcaXY, posdcaZ); - registry.fill(HIST("V0Leg/hDCAxyz"), eledcaXY, eledcaZ); - - ROOT::Math::PxPyPzMVector vpos_sv(kfp_pos_DecayVtx.GetPx(), kfp_pos_DecayVtx.GetPy(), kfp_pos_DecayVtx.GetPz(), o2::constants::physics::MassElectron); - ROOT::Math::PxPyPzMVector vele_sv(kfp_ele_DecayVtx.GetPx(), kfp_ele_DecayVtx.GetPy(), kfp_ele_DecayVtx.GetPz(), o2::constants::physics::MassElectron); - ROOT::Math::PxPyPzMVector v0_sv = vpos_sv + vele_sv; - registry.fill(HIST("V0/hMeeSV_Rxy"), rxy, v0_sv.M()); - - v0photonskf(collision.globalIndex(), v0.globalIndex(), v0legs.lastIndex() + 1, v0legs.lastIndex() + 2, - gammaKF_DecayVtx.GetX(), gammaKF_DecayVtx.GetY(), gammaKF_DecayVtx.GetZ(), - gammaKF_PV.GetPx(), gammaKF_PV.GetPy(), gammaKF_PV.GetPz(), - v0_sv.M(), v0photoncandidate.getDcaXYToPV(), v0photoncandidate.getDcaZToPV(), - cospa_kf, cospaXYKF, cospaRZKF, - v0photoncandidate.getPCA(), v0photoncandidate.getAlpha(), v0photoncandidate.getQt(), v0photoncandidate.getChi2NDF()); - v0photonsphivpsi(v0photoncandidate.getPhiV(), v0photoncandidate.getPsiPair()); - - // v0photonskfcov(gammaKF_PV.GetCovariance(9), gammaKF_PV.GetCovariance(14), gammaKF_PV.GetCovariance(20), gammaKF_PV.GetCovariance(13), gammaKF_PV.GetCovariance(19), gammaKF_PV.GetCovariance(18)); - - fillTrackTable(pos, kfp_pos_DecayVtx, posdcaXY, posdcaZ); // positive leg first - fillTrackTable(ele, kfp_ele_DecayVtx, eledcaXY, eledcaZ); // negative leg second - } // end of fill table - } - - Preslice perCollision = o2::aod::v0::collisionId; - std::map, float> pca_map; // (v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) -> pca - std::map, float> cospa_map; // (v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) -> cospa - std::vector vecV0Dedup; // vector with all V0Candidates that is used to sort them by score (see struct V0CandidateHelper for more details of content) - std::vector> stored_v0Ids; // (pos.globalIndex(), ele.globalIndex()) - std::vector> stored_fullv0Ids; // (v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) - std::unordered_map nv0_map; // map collisionId -> nv0 - - template - void build(TCollisions const& collisions, TV0s const& v0s, TTracks const& tracks, TBCs const&, DedupDiag* diag = nullptr) - { - for (const auto& collision : collisions) { - if constexpr (isMC) { - if (!collision.has_mcCollision()) { - continue; - } - } - - if (!collision.isSelected()) { - continue; - } - - // if constexpr (isTriggerAnalysis) { - // if (collision.triggerMask_raw() == 0) { - // continue; - // } - // } - - nv0_map[collision.globalIndex()] = 0; - - const auto& bc = collision.template foundBC_as(); - initCCDB(bc); - registry.fill(HIST("hCollisionCounter"), 1); - - updateCCDB(bc); // delay update until is needed - - vecV0Dedup.reserve(30000); // rough estimate for number of V0s per DF - const auto& v0s_per_coll = v0s.sliceBy(perCollision, collision.globalIndex()); - // LOGF(info, "n v0 = %d", v0s_per_coll.size()); - for (const auto& v0 : v0s_per_coll) { - // LOGF(info, "collision.globalIndex() = %d, v0.globalIndex() = %d, v0.posTrackId() = %d, v0.negTrackId() = %d", collision.globalIndex(), v0.globalIndex(), v0.posTrackId() , v0.negTrackId()); - fillV0Table(v0, false); - } // end of v0 loop - } // end of collision loop - - stored_v0Ids.reserve(pca_map.size()); // number of photon candidates per DF - stored_fullv0Ids.reserve(pca_map.size()); // number of photon candidates per DF - - // find minimal pca - if (deduplicationMode == V0DeduplicationMode::Pairwise) { - for (const auto& [key, value] : pca_map) { - auto v0Id = std::get<0>(key); - auto collisionId = std::get<1>(key); - auto posId = std::get<2>(key); - auto eleId = std::get<3>(key); - float v0pca = value; - float cospa = cospa_map[key]; - bool is_closest_v0 = true; - bool is_most_aligned_v0 = true; - - for (const auto& [key_tmp, value_tmp] : pca_map) { - auto v0Id_tmp = std::get<0>(key_tmp); - auto collisionId_tmp = std::get<1>(key_tmp); - auto posId_tmp = std::get<2>(key_tmp); - auto eleId_tmp = std::get<3>(key_tmp); - float v0pca_tmp = value_tmp; - float cospa_tmp = cospa_map[key_tmp]; - - if (v0Id == v0Id_tmp) { // skip exactly the same v0 - continue; - } - - if (collisionId != collisionId_tmp && eleId == eleId_tmp && posId == posId_tmp && cospa < cospa_tmp) { - if (diag != nullptr) { - diag->blockersByKey[key].push_back(key_tmp); - } - is_most_aligned_v0 = false; - break; - } - if ((eleId == eleId_tmp || posId == posId_tmp) && v0pca > v0pca_tmp) { - if (diag != nullptr) { - diag->blockersByKey[key].push_back(key_tmp); - } - is_closest_v0 = false; - break; - } - } // end of pca_map tmp loop - - bool is_stored = std::find(stored_v0Ids.begin(), stored_v0Ids.end(), std::make_pair(posId, eleId)) != stored_v0Ids.end(); - if (is_closest_v0 && is_most_aligned_v0 && !is_stored) { - // auto v0 = v0s.rawIteratorAt(v0Id); - // auto collision = collisions.rawIteratorAt(collisionId); - // auto pos = tracks.rawIteratorAt(posId); - // auto ele = tracks.rawIteratorAt(eleId); - // LOGF(info, "!accept! | collision id = %d | v0id1 = %d , posid1 = %d , eleid1 = %d , pca1 = %f , cospa = %f", collisionId, v0Id, posId, eleId, v0pca, cospa); - - // fillV0Table(v0, true); - stored_v0Ids.emplace_back(std::make_pair(posId, eleId)); - stored_fullv0Ids.emplace_back(std::make_tuple(v0Id, collisionId, posId, eleId)); - nv0_map[collisionId]++; - } - } // end of pca_map loop - // LOGF(info, "pca_map.size() = %d", pca_map.size()); - - } else if (deduplicationMode == V0DeduplicationMode::KeepAll) { - // Keep-all: Every candidate that survived the quality cuts is stored, INCLUDING the - // collision duplicates. - stored_v0Ids.clear(); - stored_fullv0Ids.clear(); - nv0_map.clear(); - for (const auto& v0Cand : vecV0Dedup) { - stored_v0Ids.emplace_back(v0Cand.posID, v0Cand.eleID); - stored_fullv0Ids.emplace_back(v0Cand.v0ID, v0Cand.colID, v0Cand.posID, v0Cand.eleID); - nv0_map[v0Cand.colID]++; - } - std::sort(stored_fullv0Ids.begin(), stored_fullv0Ids.end(), - [](const auto& a, const auto& b) { - return std::get<1>(a) < std::get<1>(b); - }); - } else if (deduplicationMode == V0DeduplicationMode::GroupMatching) { - const int maxEnum = std::min(dedupMaxGroupSize.value, 16); // o2-linter: disable=magic-number (subset check of photons) - const int nCand = static_cast(vecV0Dedup.size()); - stored_v0Ids.clear(); - stored_fullv0Ids.clear(); - nv0_map.clear(); - int nGreedyFallback = 0; - - // ---- conflict groups: candidates connected through a shared leg ----- - std::vector parent(nCand); - for (int i = 0; i < nCand; ++i) { - parent[i] = i; - } - auto findRoot = [&parent](int x) { - while (parent[x] != x) { - parent[x] = parent[parent[x]]; // path halving - x = parent[x]; - } - return x; - }; - std::unordered_map firstCandOfTrack; - for (int i = 0; i < nCand; ++i) { - for (const int& trackId : {vecV0Dedup[i].posID, vecV0Dedup[i].eleID}) { - auto [it, inserted] = firstCandOfTrack.try_emplace(trackId, i); - if (!inserted) { - parent[findRoot(i)] = findRoot(it->second); - } - } - } - std::map> groups; - for (int i = 0; i < nCand; ++i) { - groups[findRoot(i)].push_back(i); - } - - // ---- decide each group on its own ---------------------------------- - for (auto& [root, members] : groups) { // o2-linter: disable=const-ref-in-for-loop (members is sorted in place below) - const int nMembers = static_cast(members.size()); - std::vector selected(nMembers, 0); - - // Fix the order inside the group: best score first, ties by v0ID. This makes the - // result independent of the order in which the candidates ended up in vecV0Dedup. - std::sort(members.begin(), members.end(), [this](int a, int b) { - if (vecV0Dedup[a].score != vecV0Dedup[b].score) { - return vecV0Dedup[a].score < vecV0Dedup[b].score; - } - return vecV0Dedup[a].v0ID < vecV0Dedup[b].v0ID; - }); - - if (nMembers == 1) { - selected[0] = 1; // no conflict -> always kept - } else if (nMembers <= maxEnum) { - // Exact. Instead of comparing track IDs for every subset, each leg of the group gets - // a local bit number; "share a leg" is then a single bitwise AND. - std::unordered_map legBit; - std::vector legMask(nMembers, 0); - for (int k = 0; k < nMembers; ++k) { - for (const int& trackId : {vecV0Dedup[members[k]].posID, vecV0Dedup[members[k]].eleID}) { - const int bit = legBit.try_emplace(trackId, static_cast(legBit.size())).first->second; - legMask[k] |= (1ull << bit); // at most 2 * 16 = 32 legs, fits into 64 bit - } - } - uint32_t bestMask = 0; - int bestCount = 0; - float bestScore = 0.f; - // per candidate: the best solution that CONTAINS it. Comparing that against the overall - // best tells afterwards whether a rejected candidate lost on cardinality (structural, - // no algorithm can help) or on total score in a tie (a ranking problem, i.e. fixable). - std::vector bestWithCount(nMembers, -1); - std::vector bestWithScore(nMembers, 0.f); - for (uint32_t mask = 1; mask < (1u << nMembers); ++mask) { - uint64_t usedLegsLocal = 0; - float scoreSum = 0.f; - int count = 0; - bool disjoint = true; - for (int k = 0; k < nMembers; ++k) { - if ((mask & (1u << k)) == 0) { - continue; - } - if ((usedLegsLocal & legMask[k]) != 0) { - disjoint = false; - break; - } - usedLegsLocal |= legMask[k]; - scoreSum += vecV0Dedup[members[k]].score; - ++count; - } - if (!disjoint) { - continue; - } - // lexicographic: cardinality first, then total score. Strict comparisons mean the - // lowest mask wins a true tie, and since members is sorted by score those are the - // better candidates. - if (count > bestCount || (count == bestCount && scoreSum < bestScore)) { - bestCount = count; - bestScore = scoreSum; - bestMask = mask; - } - if (diag != nullptr) { - for (int k = 0; k < nMembers; ++k) { - if ((mask & (1u << k)) == 0) { - continue; - } - if (count > bestWithCount[k] || (count == bestWithCount[k] && scoreSum < bestWithScore[k])) { - bestWithCount[k] = count; - bestWithScore[k] = scoreSum; - } - } - } - } - for (int k = 0; k < nMembers; ++k) { - selected[k] = ((bestMask & (1u << k)) != 0) ? 1 : 0; - if (diag != nullptr && selected[k] == 0 && bestWithCount[k] >= 0) { - const auto& cand = vecV0Dedup[members[k]]; - diag->lossMargin[std::make_tuple(static_cast(cand.v0ID), static_cast(cand.colID), - static_cast(cand.posID), static_cast(cand.eleID))] = - std::make_pair(bestCount - bestWithCount[k], bestWithScore[k] - bestScore); - } - } - } else { - // Too large to enumerate: greedy by score (members is already sorted that way). This - // gives a maximal, not necessarily a maximum matching, so it is counted below. - ++nGreedyFallback; - std::vector usedTracks; - usedTracks.reserve(2 * nMembers); - for (int k = 0; k < nMembers; ++k) { - const auto& cand = vecV0Dedup[members[k]]; - if (std::find(usedTracks.begin(), usedTracks.end(), cand.posID) != usedTracks.end() || - std::find(usedTracks.begin(), usedTracks.end(), cand.eleID) != usedTracks.end()) { - continue; - } - usedTracks.push_back(cand.posID); - usedTracks.push_back(cand.eleID); - selected[k] = 1; - } - } - - // ---- store the winners, book the blockers of the losers ---------- - for (int k = 0; k < nMembers; ++k) { - const auto& cand = vecV0Dedup[members[k]]; - if (selected[k] != 0) { - stored_v0Ids.emplace_back(cand.posID, cand.eleID); - stored_fullv0Ids.emplace_back(cand.v0ID, cand.colID, cand.posID, cand.eleID); - nv0_map[cand.colID]++; - continue; - } - if (diag == nullptr) { - continue; - } - // Record ALL winners that took a leg of this candidate. A cross-leg fake is typically - // blocked by TWO different true photons (one per leg); storing only the first would - // make the later MC cause-of-loss attribution depend on the loop order. - const CandKey victimKey = std::make_tuple(static_cast(cand.v0ID), static_cast(cand.colID), - static_cast(cand.posID), static_cast(cand.eleID)); - for (int j = 0; j < nMembers; ++j) { - if (selected[j] == 0) { - continue; - } - const auto& winner = vecV0Dedup[members[j]]; - if (winner.posID == cand.posID || winner.eleID == cand.eleID) { - diag->blockersByKey[victimKey].emplace_back(static_cast(winner.v0ID), static_cast(winner.colID), - static_cast(winner.posID), static_cast(winner.eleID)); - } - } - } - } - - if (nGreedyFallback > 0) { - LOGF(warning, "group matching: %d conflict group(s) larger than dedupMaxGroupSize = %d were solved greedily", nGreedyFallback, maxEnum); - } - - // the table expects candidates ordered by collision - std::sort(stored_fullv0Ids.begin(), stored_fullv0Ids.end(), - [](const auto& a, const auto& b) { - return std::get<1>(a) < std::get<1>(b); - }); - - } else { - // Sort best candidates first, depending on score - std::sort(vecV0Dedup.begin(), vecV0Dedup.end()); - // container to keep track of which electron and positron tracks have already been used - std::vector usedLegs(tracks.size(), false); - std::unordered_map ownerOfLeg; // diagnostics only - stored_v0Ids.clear(); - stored_fullv0Ids.clear(); - nv0_map.clear(); - for (const auto& v0Cand : vecV0Dedup) { - const CandKey candKey = std::make_tuple(static_cast(v0Cand.v0ID), static_cast(v0Cand.colID), - static_cast(v0Cand.posID), static_cast(v0Cand.eleID)); - if (usedLegs[v0Cand.posID] || usedLegs[v0Cand.eleID]) { - if (diag != nullptr) { - // both legs, not just the first one found: a cross-leg fake is usually blocked by - // two different winners, and that is exactly the case being measured here - auto& blockers = diag->blockersByKey[candKey]; - for (const int& legId : {v0Cand.posID, v0Cand.eleID}) { - const auto itOwner = ownerOfLeg.find(legId); - if (itOwner == ownerOfLeg.end()) { - continue; - } - if (std::find(blockers.begin(), blockers.end(), itOwner->second) == blockers.end()) { - blockers.push_back(itOwner->second); // the same winner may hold both legs - } - } - } - continue; - } - usedLegs[v0Cand.posID] = true; - usedLegs[v0Cand.eleID] = true; - if (diag != nullptr) { - ownerOfLeg[v0Cand.posID] = candKey; - ownerOfLeg[v0Cand.eleID] = candKey; - } - stored_v0Ids.emplace_back(v0Cand.posID, v0Cand.eleID); - stored_fullv0Ids.emplace_back(v0Cand.v0ID, v0Cand.colID, v0Cand.posID, v0Cand.eleID); - nv0_map[v0Cand.colID]++; - } - - // sort accepted candidates by collision ID to be compatible with table - std::sort(stored_fullv0Ids.begin(), stored_fullv0Ids.end(), - [](const auto& a, const auto& b) { - return std::get<1>(a) < std::get<1>(b); - }); - - // End of deduplication - } - - if (diag != nullptr) { - diag->snapshot = vecV0Dedup; - diag->stored = stored_fullv0Ids; - } - - for (const auto& fullv0Id : stored_fullv0Ids) { - auto v0Id = std::get<0>(fullv0Id); - // auto collisionId = std::get<1>(fullv0Id); - // auto posId = std::get<2>(fullv0Id); - // auto eleId = std::get<3>(fullv0Id); - // LOGF(info, "!accept! | collision id = %d | v0id = %d , posid = %d , eleid = %d", collisionId, v0Id, posId, eleId); - - auto v0 = v0s.rawIteratorAt(v0Id); - if constexpr (enableFilter) { - auto collision_tmp = v0.template collision_as(); // collision where this v0 belongs. - if (!(collision_tmp.neeuls() >= 1 || collision_tmp.neeuls() + nv0_map[collision_tmp.globalIndex()] >= 2)) { // o2-linter: disable=magic-number (nonsensical default value) - continue; - } - // LOGF(info, "collision_tmp.globalIndex() = %d, collision_tmp.neeuls() = %d, nv0_map = %d", collision_tmp.globalIndex(), collision_tmp.neeuls(), nv0_map[collision_tmp.globalIndex()]); - } - - fillV0Table(v0, true); - } // end of fullv0Id loop - - // for (const auto& collision : collisions) { - // if constexpr (isMC) { - // if (!collision.has_mcCollision()) { - // continue; - // } - // } - // // events_ngpcm(nv0_map[collision.globalIndex()]); - // } // end of collision loop - - pca_map.clear(); - cospa_map.clear(); - nv0_map.clear(); - stored_v0Ids.clear(); - stored_v0Ids.shrink_to_fit(); - stored_fullv0Ids.clear(); - stored_fullv0Ids.shrink_to_fit(); - vecV0Dedup.clear(); - } // end of build - - Filter v0Filter = o2::aod::v0::v0Type > (uint8_t)0; - using FilteredV0s = soa::Filtered; - - enum PairFate { - kBefore = 0, - kBothSurvive, - kOneLost, - kBothLost, - // NB: the four "lostBy..." entries are diagnostic selections, NOT an exclusive decomposition. - // kLostByPartnerFake is a SUBSET of kLostByCrossFake, and cross + other + true do not add up - // to oneLost + bothLost (a pair can lose two photons to two different blockers). - kLostByCrossFake, - kLostByPartnerFake, - kLostByOtherFake, - kLostByTrue - }; - - void fillTruthPair(int fate, float q, float dEta) - { - switch (fate) { - case kBefore: - registry.fill(HIST("MCDedup/Pairs/before/hQ"), q); - registry.fill(HIST("MCDedup/Pairs/before/hDEta"), dEta); - break; - case kBothSurvive: - registry.fill(HIST("MCDedup/Pairs/bothSurvive/hQ"), q); - registry.fill(HIST("MCDedup/Pairs/bothSurvive/hDEta"), dEta); - break; - case kOneLost: - registry.fill(HIST("MCDedup/Pairs/oneLost/hQ"), q); - registry.fill(HIST("MCDedup/Pairs/oneLost/hDEta"), dEta); - break; - case kBothLost: - registry.fill(HIST("MCDedup/Pairs/bothLost/hQ"), q); - registry.fill(HIST("MCDedup/Pairs/bothLost/hDEta"), dEta); - break; - case kLostByCrossFake: - registry.fill(HIST("MCDedup/Pairs/lostByCrossFake/hQ"), q); - registry.fill(HIST("MCDedup/Pairs/lostByCrossFake/hDEta"), dEta); - break; - case kLostByPartnerFake: - registry.fill(HIST("MCDedup/Pairs/lostByPartnerFake/hQ"), q); - registry.fill(HIST("MCDedup/Pairs/lostByPartnerFake/hDEta"), dEta); - break; - case kLostByOtherFake: - registry.fill(HIST("MCDedup/Pairs/lostByOtherFake/hQ"), q); - registry.fill(HIST("MCDedup/Pairs/lostByOtherFake/hDEta"), dEta); - break; - case kLostByTrue: - registry.fill(HIST("MCDedup/Pairs/lostByTrue/hQ"), q); - registry.fill(HIST("MCDedup/Pairs/lostByTrue/hDEta"), dEta); - break; - default: - break; - } - } - - void fillTruthPairMap(int fate, float dEta, float dPhi, float q) - { - if (!cfgDedupTruthMaps) { - return; - } - switch (fate) { - case kBefore: - registry.fill(HIST("MCDedup/Pairs/before/hMap"), dEta, dPhi, q); - break; - case kBothSurvive: - registry.fill(HIST("MCDedup/Pairs/bothSurvive/hMap"), dEta, dPhi, q); - break; - case kBothLost: - registry.fill(HIST("MCDedup/Pairs/bothLost/hMap"), dEta, dPhi, q); - break; - case kLostByPartnerFake: - registry.fill(HIST("MCDedup/Pairs/lostByPartnerFake/hMap"), dEta, dPhi, q); - break; - default: - break; - } - } - - template - void fillDedupTruthDiagnostics(TTracks const& tracks, TMCParticles const& mcparticles, DedupDiag const& diag) - { - const int nCand = static_cast(diag.snapshot.size()); - if (nCand == 0) { - return; - } - const std::set storedSet(diag.stored.begin(), diag.stored.end()); - - std::vector key(nCand); - std::vector cls(nCand, static_cast(kV0OtherFake)); - std::vector motherPos(nCand, -1), motherEle(nCand, -1); - std::map indexOfKey; - for (int i = 0; i < nCand; ++i) { - const auto& c = diag.snapshot[i]; - key[i] = std::make_tuple(static_cast(c.v0ID), static_cast(c.colID), - static_cast(c.posID), static_cast(c.eleID)); - indexOfKey[key[i]] = i; - cls[i] = static_cast(classifyV0Truth(tracks.rawIteratorAt(c.posID), tracks.rawIteratorAt(c.eleID), - mcparticles, motherPos[i], motherEle[i])); - registry.fill(HIST("MCDedup/Candidates/hClassStage"), static_cast(cls[i]), 0.f); - if (storedSet.contains(key[i]) > 0) { - registry.fill(HIST("MCDedup/Candidates/hClassStage"), static_cast(cls[i]), 1.f); - } - } - - // ---- per true photon: which photon passed and which one was removed - // IMPORTANT: a photon is lost only when ALL of its candidates died, so all of them are asked - // for blockers, not just the best one - different candidates have different opponents. - struct PhotonFate { - bool alive = false; - int best = -1; // best-score candidate, only used for the margin plots - std::vector cands; // all true candidates of this photon - std::set aliveColls; // collisions with a surviving candidate - }; - std::map fate; - for (int i = 0; i < nCand; ++i) { - if (cls[i] != kV0True) { - continue; - } - auto& f = fate[motherPos[i]]; - f.cands.push_back(i); - if (storedSet.contains(key[i]) > 0) { - f.alive = true; - f.aliveColls.insert(std::get<1>(key[i])); - } - if (f.best < 0 || diag.snapshot[i].score < diag.snapshot[f.best].score) { - f.best = i; - } - } - - // motherId -> indices of ALL candidates that took a leg from this photon. Empty means the - // photon disappeared without anybody claiming a leg: then the mode cut, it did not dedup. - std::map> blockersOfPhoton; - for (const auto& [mid, f] : fate) { - if (f.alive) { - registry.fill(HIST("MCDedup/Photons/hFate"), 0.f); - continue; - } - auto& blockers = blockersOfPhoton[mid]; - for (const int& ci : f.cands) { - const auto itBlocker = diag.blockersByKey.find(key[ci]); - if (itBlocker == diag.blockersByKey.end()) { - continue; - } - for (const auto& bKey : itBlocker->second) { - const auto itIndex = indexOfKey.find(bKey); - if (itIndex == indexOfKey.end()) { - continue; - } - if (std::find(blockers.begin(), blockers.end(), itIndex->second) == blockers.end()) { - blockers.push_back(itIndex->second); - } - } - } - // Why was it not in the winning set? Take the most favourable of its candidates: the one - // that could have been kept at the smallest cost in cardinality. - int bestDeficit = -1; - float bestExcess = 0.f; - for (const int& ci : f.cands) { - const auto itMargin = diag.lossMargin.find(key[ci]); - if (itMargin == diag.lossMargin.end()) { - continue; - } - if (bestDeficit < 0 || itMargin->second.first < bestDeficit || - (itMargin->second.first == bestDeficit && itMargin->second.second < bestExcess)) { - bestDeficit = itMargin->second.first; - bestExcess = itMargin->second.second; - } - } - if (bestDeficit >= 0) { - registry.fill(HIST("MCDedup/Photons/hLostMargin"), static_cast(bestDeficit), bestExcess); - } - - // ONE entry per photon, so the photon-level survival rate is comparable between modes. - // hVictimBlockerClass below counts one entry per BLOCKER and a victim can have two. - registry.fill(HIST("MCDedup/Photons/hFate"), blockers.empty() ? 2.f : 1.f); - - if (blockers.empty()) { - registry.fill(HIST("MCDedup/Photons/hBlockerClass"), 3.f); // o2-linter: disable=magic-number (bin 3 = no blocker) - continue; - } - for (const int& w : blockers) { - registry.fill(HIST("MCDedup/Photons/hBlockerClass"), static_cast(cls[w])); - } - // margin and PCA comparison relate the best candidate to its blocker - that is only the - // quantity that decided in mode 0/1. Mode 2 compares sets, so it is skipped there. - if (f.best >= 0 && deduplicationMode.value < static_cast(V0DeduplicationMode::GroupMatching)) { - const int w = blockers.front(); - registry.fill(HIST("MCDedup/Photons/hKillMargin"), diag.snapshot[f.best].score - diag.snapshot[w].score); - registry.fill(HIST("MCDedup/Photons/hVictimVsWinnerPCA"), diag.snapshot[f.best].pca, diag.snapshot[w].pca); - } - } - - // ---- truth pairs, grouped by MC collision ---------------------------- - std::map> mothersByMcColl; - for (const auto& [mid, f] : fate) { - mothersByMcColl[mcparticles.iteratorAt(mid).mcCollisionId()].push_back(mid); - } - constexpr float MaxQTruth = 0.3f; - for (const auto& [mcCol, mids] : mothersByMcColl) { - for (size_t a = 0; a < mids.size(); ++a) { - for (size_t b = a + 1; b < mids.size(); ++b) { - const auto g1 = mcparticles.iteratorAt(mids[a]); - const auto g2 = mcparticles.iteratorAt(mids[b]); - const float e1 = std::hypot(g1.px(), g1.py(), g1.pz()); - const float e2 = std::hypot(g2.px(), g2.py(), g2.pz()); - const float qTrue = std::sqrt(std::max(0.f, 2.f * (e1 * e2 - g1.px() * g2.px() - g1.py() * g2.py() - g1.pz() * g2.pz()))); - if (qTrue > MaxQTruth) { - continue; - } - const float dEta = g1.eta() - g2.eta(); - const float dPhi = RecoDecay::constrainAngle(static_cast(g1.phi() - g2.phi()), -o2::constants::math::PI); - fillTruthPair(kBefore, qTrue, dEta); - fillTruthPairMap(kBefore, dEta, dPhi, qTrue); - - const auto& f1 = fate.at(mids[a]); - const auto& f2 = fate.at(mids[b]); - const int nLost = (f1.alive ? 0 : 1) + (f2.alive ? 0 : 1); - if (nLost == 0) { - fillTruthPair(kBothSurvive, qTrue, dEta); - fillTruthPairMap(kBothSurvive, dEta, dPhi, qTrue); - bool sameColl = false; - for (const auto& c1 : f1.aliveColls) { - sameColl = sameColl || (f2.aliveColls.count(c1) > 0); - } - if (sameColl) { - registry.fill(HIST("MCDedup/Pairs/bothSurviveSameColl/hQ"), qTrue); - } - continue; - } - if (nLost == 1) { - fillTruthPair(kOneLost, qTrue, dEta); - } else { - fillTruthPair(kBothLost, qTrue, dEta); - fillTruthPairMap(kBothLost, dEta, dPhi, qTrue); - } - - // Who killed them? These four flags are DIAGNOSES, not a decomposition: partnerFake is - // a subset of crossFake, and one pair can end up in several categories at once. - bool byCross = false, byPartner = false, byOther = false, byTrue = false; - auto attribute = [&](int64_t victim, int64_t partner) { - if (fate.at(victim).alive) { - return; - } - const auto itB = blockersOfPhoton.find(victim); - if (itB == blockersOfPhoton.end()) { - return; - } - for (const int& w : itB->second) { - if (cls[w] == kV0CrossLegFake) { - byCross = true; - // partner fake = a cross-leg fake using a leg of the OTHER photon of this very - // pair -> the double-kill mechanism - if (motherPos[w] == partner || motherEle[w] == partner) { - byPartner = true; - } - } else if (cls[w] == kV0OtherFake) { - byOther = true; - } else if (cls[w] == kV0True) { - byTrue = true; // real photon against real photon: not repairable by any algorithm - } - } - }; - attribute(mids[a], mids[b]); - attribute(mids[b], mids[a]); - if (byCross) { - fillTruthPair(kLostByCrossFake, qTrue, dEta); - } - if (byPartner) { - fillTruthPair(kLostByPartnerFake, qTrue, dEta); - fillTruthPairMap(kLostByPartnerFake, dEta, dPhi, qTrue); - } - if (byOther) { - fillTruthPair(kLostByOtherFake, qTrue, dEta); - } - if (byTrue) { - fillTruthPair(kLostByTrue, qTrue, dEta); - } - } - } - } - } - - void processRec(MyCollisions const& collisions, FilteredV0s const& v0s, MyTracksIU const& tracks, MyBCs const& bcs) - { - build(collisions, v0s, tracks, bcs); - } - PROCESS_SWITCH(PhotonConversionBuilder, processRec, "process reconstructed info for data", true); - - // void processRec_SWT(MyCollisionsWithSWT const& collisions, FilteredV0s const& v0s, MyTracksIU const& tracks, MyBCs const& bcs) - // { - // build(collisions, v0s, tracks, bcs); - // } - // PROCESS_SWITCH(PhotonConversionBuilder, processRec_SWT, "process reconstructed info for data", false); - - void processMC(MyCollisionsMC const& collisions, FilteredV0s const& v0s, MyTracksIUMC const& tracks, - MyBCs const& bcs, aod::McParticles const& mcparticles) - { - DedupDiag diag; - build(collisions, v0s, tracks, bcs, &diag); - fillDedupTruthDiagnostics(tracks, mcparticles, diag); - } - PROCESS_SWITCH(PhotonConversionBuilder, processMC, "process reconstructed info for MC", false); - - void processRec_OnlyIfDielectron(soa::Join const& collisions, FilteredV0s const& v0s, MyTracksIU const& tracks, MyBCs const& bcs) - { - build(collisions, v0s, tracks, bcs); - } - PROCESS_SWITCH(PhotonConversionBuilder, processRec_OnlyIfDielectron, "process reconstructed info for data", false); - - // void processRec_SWT_OnlyIfDielectron(soa::Join const& collisions, FilteredV0s const& v0s, MyTracksIU const& tracks, MyBCs const& bcs) - // { - // build(collisions, v0s, tracks, bcs); - // } - // PROCESS_SWITCH(PhotonConversionBuilder, processRec_SWT_OnlyIfDielectron, "process reconstructed info for data", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& context) +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& context) { - return WorkflowSpec{ - adaptAnalysisTask(context, TaskName{"photon-conversion-builder"})}; + return o2::framework::WorkflowSpec{ + adaptAnalysisTask>(context, o2::framework::TaskName{"photon-conversion-builder"})}; } diff --git a/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.h b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.h new file mode 100644 index 00000000000..8040ac57d3d --- /dev/null +++ b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.h @@ -0,0 +1,1803 @@ +// Copyright 2019-2025 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. +// + +/// \file photonconversionbuilder.ch +/// \brief this task produces photon data table with KFParticle. +/// \author Daiki Sekihata , Tokyo +#ifndef PWGEM_PHOTONMESON_TABLEPRODUCER_PHOTONCONVERSIONBUILDER_H_ +#define PWGEM_PHOTONMESON_TABLEPRODUCER_PHOTONCONVERSIONBUILDER_H_ + +#ifndef HomogeneousField +#define HomogeneousField // o2-linter: disable=name/macro (name coming from KFParticle, not us, needed for KFParticle::SetField) +#endif + +#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/Core/EmMlResponsePCM.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCandidate.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/PCMUtilities.h" +#include "PWGEM/PhotonMeson/Utils/TrackSelection.h" + +#include "Common/Core/RecoDecay.h" +#include "Common/Core/TPCVDriftManager.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Tools/KFparticle/KFUtilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using o2::framework::AxisSpec; +using o2::framework::Configurable; +using o2::framework::ConfigurableGroup; +using o2::framework::HistType; +using o2::framework::kTH1D; +using o2::framework::kTH1F; +using o2::framework::kTH2F; +using o2::framework::kTHnSparseF; +using o2::framework::Preslice; +using o2::framework::Produces; + +using MyCollisions = o2::soa::Join; +// using MyCollisionsWithSWT = soa::Join; +using MyCollisionsMC = o2::soa::Join; +using MyBCs = o2::soa::Join; + +using MyTracksIU = o2::soa::Join; +using MyTracksIUMC = o2::soa::Join; + +enum MatCorrTypeEM { + None = 0, + TGeo = 1, + LUT = 2 +}; + +enum TrackPropMode { + kProper = 0, + kFast = 1, + kBoth = 2 +}; + +enum V0DeduplicationMode { + Pairwise = 0, // old algorithm, V0 with best PCA + cosPA at the same time in a group wins + GreedyMatching = 1, // new algorithm, best score wins (score combines PCA and cosPA -- see detailed implementation in PCMUtilities.cxx) + GroupMatching = 2, // new algorithm, best combination of leg-disjoint V0s wins, not the single best V0 + KeepAll = 3 // no deduplication, keep all V0s +}; + +// Struct needed for deduplication mode 1. Used to keep track of v0 properties and a score based on pca and cosPA +struct V0CandidateHelper { + int v0ID = -1; + int colID = -1; + int posID = -1; + int eleID = -1; + float cosPA = -1.f; + float pca = -1.f; + float score = -1.f; + float mee = 0.f; // e+e- mass at the secondary vertex (GeV/c^2) + float pxAtPV = 0.f; + float pyAtPV = 0.f; + float pzAtPV = 0.f; + + V0CandidateHelper() = default; + + V0CandidateHelper(int v0, int col, int pos, int ele, float cpa, float p, float s, float m = 0.f) + : v0ID(v0), colID(col), posID(pos), eleID(ele), cosPA(cpa), pca(p), score(s), mee(m) + { + } + + bool operator==(const V0CandidateHelper& other) const { return score == other.score; } + bool operator<(const V0CandidateHelper& other) const { return score < other.score; } + bool operator>(const V0CandidateHelper& other) const { return score > other.score; } +}; + +// (v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) +using CandKey = std::tuple; + +// Everything the truth diagnosis need, +struct DedupDiag { + std::map> blockersByKey; // rejected candidate -> ALL candidates that took one of its legs + std::vector snapshot; // ALL candidates, before deduplication + std::vector stored; // the survivors + std::map> lossMargin; +}; + +template +struct PhotonConversionBuilder { + + // using namespace o2; + // using namespace o2::soa; + // using namespace o2::framework; + // using namespace o2::framework::expressions; + // using namespace o2::constants::physics; + // using namespace o2::pwgem::photonmeson; + + Produces v0photonskf; + Produces v0legs; + Produces v0legsXYZ; + Produces v0legsDeDxMC; + Produces v0photonsphivpsi; + + // Produces v0photonskfcov; + // Produces events_ngpcm; + + // CCDB options + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; + Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; + + // Operation and minimisation criteria + Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; + Configurable useMatCorrType{"useMatCorrType", 0, "0: none, 1: TGeo, 2: LUT"}; + Configurable modeTrackPropagation{"modeTrackPropagation", 0, "0: use real track propagation, including material, 1: use fast approximation using only geometry, 2: Use real track propagation and make comparison to fast propagation (only for debugging and testing)"}; + Configurable propV0LegsRadius{"propV0LegsRadius", 60.f, "Radius to which the V0 legs are propagated to calculate psipair and phiV"}; + + // deduplication settings + struct : ConfigurableGroup { + std::string prefix = "dedup_group"; + Configurable deduplicationMode{"deduplicationMode", 0, "0: Pairwise deduplication, 1: Based on Greedy matching (best score wins), 2: Based on Group matching (crossed pairs are both kept), 3: Keep all V0s, our default in the config is mode 0, however if a wrong configuration is used, the default will be mode 1 (Greedy matching) to avoid crashes"}; + Configurable deduplicationScoreWeight{"deduplicationScoreWeight", 0.5f, "0.:only pca goes into the score, 1: only cosPA goes itno score, any number in between is a mix of pca and cosPA"}; + Configurable cfgDedupTruthMaps{"cfgDedupTruthMaps", true, "fill the fine (dEta, dPhi, q) truth maps in MC"}; + Configurable dedupMaxGroupSize{"dedupMaxGroupSize", 12, "group matching (mode 2): conflict groups up to this size are solved exactly, larger ones greedily (capped at 16)"}; + } dedup; + + // event-level skim for derived data + struct : ConfigurableGroup { + std::string prefix = "skim_group"; + Configurable minNv0PerCollision{"minNv0PerCollision", -1, "store V0 photons only for collisions with at least this many surviving candidates (event-level skim for derived data). negative = store all"}; + Configurable maxMinvPairPerCollision{"maxMinvPairPerCollision", -1.f, "store a collision's photons only if at least one photon pair has qinv below this (GeV/c^2). negative = disabled"}; + } skim; + + // single track cuts + struct : ConfigurableGroup { + std::string prefix = "trackcut_group"; + Configurable min_ncluster_tpc{"min_ncluster_tpc", 0, "min ncluster tpc"}; + Configurable mincrossedrows{"mincrossedrows", 40, "min crossed rows"}; + Configurable moveTPCTracks{"moveTPCTracks", true, "Move TPC-only tracks under the collision assumption"}; + Configurable disableITSonlyTracks{"disableITSonlyTracks", false, "disable ITSonly tracks in V0 legs"}; + Configurable disableTPConlyTracks{"disableTPConlyTracks", false, "disable TPConly tracks in V0 legs"}; + Configurable requireITShit{"requireITShit", false, "require ITS hit to V0 legs"}; + Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max chi2/NclsTPC"}; // default 4.0 + 1.0 + Configurable maxchi2its{"maxchi2its", 6.0, "max chi2/NclsITS"}; // default 5.0 + 1.0 + Configurable maxpt_itsonly{"maxpt_itsonly", 0.15, "max pT for ITSonly tracks at SV"}; + Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", 4.0, "max. TPC n sigma for electron"}; + Configurable minTPCNsigmaEl{"minTPCNsigmaEl", -4.0, "min. TPC n sigma for electron"}; + Configurable max_frac_shared_clusters_tpc{"max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable dcanegtopv{"dcanegtopv", 0.1, "DCA Neg To PV"}; + Configurable dcapostopv{"dcapostopv", 0.1, "DCA Pos To PV"}; + Configurable maxX{"maxX", 83.1, "max X for track IU"}; + Configurable min_pt_trackiu{"min_pt_trackiu", 0.05, "min pT for trackiu"}; // this comes from online processing. pT of track seed is above 50 MeV/c in B = 0.5 T, 20 MeV/c in B = 0.2 T. + } trackcuts; + + // v0 photon cuts + struct : ConfigurableGroup { + std::string prefix = "v0cut_group"; + Configurable min_v0cospa_tpconly{"min_v0cospa_tpconly", 0.99, "min V0 CosPA to V0s with TPConly tracks"}; // double -> N.B. dcos(x)/dx = 0 at x=0) + Configurable min_v0cospa_its{"min_v0cospa_its", 0.99, "min V0 CosPA to V0s with ITs hits"}; // double -> N.B. dcos(x)/dx = 0 at x=0) + Configurable max_dcav0dau_tpconly{"max_dcav0dau_tpconly", 3.0, "max distance btween 2 legs to V0s with TPConly tracks"}; + Configurable max_dcav0dau_its{"max_dcav0dau_its", 0.5, "max distance btween 2 legs to V0s with ITS hits"}; + Configurable max_dcav0dau_itsibss{"max_dcav0dau_itsibss", 1.0, "max distance btween 2 legs to V0s with ITS hits on ITSib SS"}; + Configurable max_dcav0dau_tpc_inner_fc{"max_dcav0dau_tpc_inner_fc", 1.5, "max distance btween 2 legs to V0s with ITS hits on TPC inner FC"}; + Configurable min_v0radius{"min_v0radius", 1.0, "min v0 radius"}; + Configurable max_v0radius{"max_v0radius", 90.0, "max v0 radius"}; + Configurable margin_r_its{"margin_r_its", 3.0, "margin for r cut in cm"}; + Configurable margin_r_tpc{"margin_r_tpc", 7.0, "margin for r cut in cm"}; + Configurable margin_r_itstpc_tpc{"margin_r_itstpc_tpc", 7.0, "margin for r cut in cm"}; + Configurable margin_z{"margin_z", 7.0, "margin for z cut in cm"}; + Configurable max_alpha_ap{"max_alpha_ap", 0.95, "max alpha for AP cut"}; + Configurable max_qt_ap{"max_qt_ap", 0.01, "max qT for AP cut"}; + Configurable min_pt_v0{"min_pt_v0", 0.1, "min pT for v0 photons at PV"}; + Configurable max_pt_v0_itsonly{"max_pt_v0_itsonly", 0.3, "max pT for v0 photons wth 2 ITSonly tracks at PV"}; + Configurable max_eta_v0{"max_eta_v0", 0.9, "max eta for v0 photons at PV"}; + Configurable kfMassConstrain{"kfMassConstrain", -1.f, "mass constrain for the KFParticle mother particle"}; + Configurable max_r_req_its{"max_r_req_its", 16.0, "max Rxy for V0 with ITS hits"}; + Configurable min_r_tpconly{"min_r_tpconly", 32.0, "min Rxy for V0 with TPConly tracks"}; + Configurable max_r_itsmft_ss{"max_r_itsmft_ss", 66.0, "max Rxy for ITS/MFT SS"}; + Configurable max_dcatopv_xy_v0{"max_dcatopv_xy_v0", +1e+10, "max. DCAxy to PV for V0"}; + Configurable max_dcatopv_z_v0{"max_dcatopv_z_v0", +1e+10, "max. DCAz to PV for V0"}; + Configurable reject_v0_on_itsib{"reject_v0_on_itsib", true, "flag to reject v0s on ITSib"}; + } v0cuts; + + // PCM ML inference + struct : ConfigurableGroup { + std::string prefix = "mlcut_group"; + Configurable applyPCMMl{"applyPCMMl", false, "Flag to apply ML selections"}; + Configurable use2DBinning{"use2DBinning", false, "Flag to enable/disable 2D binning for ML application"}; + Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + Configurable nClassesPCMMl{"nClassesPCMMl", static_cast(o2::analysis::em_cuts_ml::NCutScores), "Number of classes in ML model"}; + Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; + Configurable centTypePCMMl{"centTypePCMMl", 2, "Centrality type for 2D ML application: FT0M:0, FT0A:1, FT0C:2"}; + Configurable> cutDirPCMMl{"cutDirPCMMl", std::vector{o2::analysis::em_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; + Configurable> namesInputFeatures{"namesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; + Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{"path_ccdb/BDT_PCM/"}, "Paths of models on CCDB"}; + Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_onnx_PCM.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; + Configurable> labelsBinsPCMMl{"labelsBinsPCMMl", std::vector{"bin 0", "bin 1"}, "Labels for bins"}; + Configurable> labelsCutScoresPCMMl{"labelsCutScoresPCMMl", std::vector{o2::analysis::em_cuts_ml::labelsCutScore}, "Labels for cut scores"}; + Configurable> binsPtPCMMl{"binsPtPCMMl", std::vector{0.0, +1e+10}, "pT bin limits for ML application"}; + Configurable> binsCentPCMMl{"binsCentPCMMl", std::vector{0.0, 100.0}, "Centrality bin limits for ML application"}; + Configurable> cutsPCMMlFlat{"cutsPCMMlFlat", {0.5}, "Flattened ML cuts: [bin0_score0, bin0_score1, ..., binN_scoreM]"}; + } mlcuts; + + o2::analysis::EmMlResponsePCM emMlResponse; + std::vector outputML; + V0PhotonCandidate v0photoncandidate; + o2::ccdb::CcdbApi ccdbApi; + + int mRunNumber{}; + float d_bz{}; + float maxSnp{}; // max sine phi for propagation + float maxStep{}; // max step size (cm) for propagation + o2::framework::Service ccdb{}; + o2::base::MatLayerCylSet* lut = nullptr; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + o2::aod::common::TPCVDriftManager mVDriftMgr; + + o2::framework::HistogramRegistry registry{ + "registry", + { + {"hCollisionCounter", "hCollisionCounter", {HistType::kTH1F, {{1, 0.5f, 1.5f}}}}, + {"V0/hAP", "Armenteros Podolanski;#alpha;q_{T} (GeV/c)", {HistType::kTH2F, {{200, -1.0f, 1.0f}, {250, 0, 0.25}}}}, + {"V0/hConversionPointXY", "conversion point in XY;X (cm);Y (cm)", {HistType::kTH2F, {{400, -100.0f, 100.0f}, {400, -100.f, 100.f}}}}, + {"V0/hConversionPointRZ", "conversion point in RZ;Z (cm);R_{xy} (cm)", {HistType::kTH2F, {{200, -100.0f, 100.0f}, {200, 0.f, 100.f}}}}, + {"V0/hPt", "pT of V0 at PV;p_{T,#gamma} (GeV/c)", {HistType::kTH1F, {{1000, 0.0f, 10.0f}}}}, + {"V0/hEtaPhi", "#eta vs. #varphi of V0 at PV;#varphi (rad.);#eta", {HistType::kTH2F, {{72, 0.0f, o2::constants::math::TwoPI}, {200, -1, +1}}}}, + {"V0/hCosPA", "cosine of pointing angle;cosine of pointing angle", {HistType::kTH1F, {{100, 0.99f, 1.f}}}}, + {"V0/hCosPA_Rxy", "cosine of pointing angle;r_{xy} (cm);cosine of pointing angle", {HistType::kTH2F, {{200, 0, 100}, {100, 0.99f, 1.f}}}}, + {"V0/hCosPAXY_Rxy", "cosine of pointing angle;r_{xy} (cm);cosine of pointing angle", {HistType::kTH2F, {{200, 0, 100}, {100, 0.99f, 1.f}}}}, + {"V0/hCosPARZ_Rxy", "cosine of pointing angle;r_{xy} (cm);cosine of pointing angle", {HistType::kTH2F, {{200, 0, 100}, {100, 0.99f, 1.f}}}}, + {"V0/hPCA", "distance between 2 legs at SV;PCA (cm)", {HistType::kTH1F, {{500, 0.0f, 5.f}}}}, + {"V0/hPCA_Rxy", "distance between 2 legs at SV;R_{xy} (cm);PCA (cm)", {HistType::kTH2F, {{200, 0, 100}, {500, 0.0f, 5.f}}}}, + {"V0/hPCA_CosPA", "distance between 2 legs at SV vs. cosPA;cosine of pointing angle;PCA (cm)", {HistType::kTH2F, {{100, 0.99, 1}, {500, 0.0f, 5.f}}}}, + {"V0/hDCAxyz", "DCA to PV;DCA_{xy} (cm);DCA_{z} (cm)", {HistType::kTH2F, {{200, -5.f, +5.f}, {200, -5.f, +5.f}}}}, + {"V0/hMeeSV_Rxy", "mee at SV vs. R_{xy};R_{xy} (cm);m_{ee} at SV (GeV/c^{2})", {HistType::kTH2F, {{200, 0.0f, 100.f}, {100, 0, 0.1f}}}}, + {"V0/hRxy_minX_ITSonly_ITSonly", "min trackiu X vs. R_{xy};trackiu X (cm);min trackiu X - R_{xy} (cm)", {HistType::kTH2F, {{100, 0.0f, 100.f}, {100, -50.0, 50.0f}}}}, + {"V0/hRxy_minX_ITSTPC_ITSTPC", "min trackiu X vs. R_{xy};trackiu X (cm);min trackiu X - R_{xy} (cm)", {HistType::kTH2F, {{100, 0.0f, 100.f}, {100, -50.0, 50.0f}}}}, + {"V0/hRxy_minX_ITSTPC_ITSonly", "min trackiu X vs. R_{xy};trackiu X (cm);min trackiu X - R_{xy} (cm)", {HistType::kTH2F, {{100, 0.0f, 100.f}, {100, -50.0, 50.0f}}}}, + {"V0/hRxy_minX_ITSTPC_TPC", "min trackiu X vs. R_{xy};trackiu X (cm);min trackiu X - R_{xy} (cm)", {HistType::kTH2F, {{100, 0.0f, 100.f}, {100, -50.0, 50.0f}}}}, + {"V0/hRxy_minX_TPC_TPC", "min trackiu X vs. R_{xy};trackiu X (cm);min trackiu X - R_{xy} (cm)", {HistType::kTH2F, {{100, 0.0f, 100.f}, {100, -50.0, 50.0f}}}}, + {"V0/hPCA_diffX", "PCA vs. trackiu X - R_{xy};distance btween 2 legs (cm);min trackiu X - R_{xy} (cm)", {HistType::kTH2F, {{500, 0.0f, 5.f}, {100, -50.0, 50.0f}}}}, + {"V0/hPhiVPsiPair", "phiV vs. psi pair;#psi_{pair} (rad.);#phi_{V} (rad.)", {HistType::kTH2F, {{500, -o2::constants::math::PI, o2::constants::math::PI}, {500, 0.0f, o2::constants::math::TwoPI}}}}, + {"V0Leg/hPt", "pT of leg at SV;p_{T,e} (GeV/c)", {HistType::kTH1F, {{1000, 0.0f, 10.0f}}}}, + {"V0Leg/hEtaPhi", "#eta vs. #varphi of leg at SV;#varphi (rad.);#eta", {HistType::kTH2F, {{72, 0.0f, o2::constants::math::TwoPI}, {200, -1, +1}}}}, + {"V0Leg/hRelDeltaPt", "pT resolution;p_{T} (GeV/c);#Deltap_{T}/p_{T}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, 0, 1}}}}, + {"V0Leg/hDCAxyz", "DCA xy vs. z to PV;DCA_{xy} (cm);DCA_{z} (cm)", {HistType::kTH2F, {{200, -50.f, 50.f}, {200, -50.f, +50.f}}}}, + {"V0Leg/hdEdx_Pin", "TPC dE/dx vs. p_{in};p_{in} (GeV/c);TPC dE/dx", {HistType::kTH2F, {{1000, 0.f, 10.f}, {200, 0.f, 200.f}}}}, + {"V0Leg/hTPCNsigmaEl", "TPC dE/dx vs. p_{in};p_{in} (GeV/c);n #sigma_{e}^{TPC}", {HistType::kTH2F, {{1000, 0.f, 10.f}, {100, -5.f, +5.f}}}}, + {"V0Leg/hXZ", "track iu x vs. z;z (cm);x (cm)", {HistType::kTH2F, {{200, -100.f, 100.f}, {200, 0.f, 100.f}}}}, + }}; + + void init(o2::framework::InitContext&) + { + mRunNumber = 0; + d_bz = 0; + maxSnp = 0.85f; // could be changed later + maxStep = 2.00f; // could be changed later + + static constexpr std::array DedupNames = {"pairwise", "greedy matching", "group matching", "keep all"}; + if (dedup.deduplicationMode < 0 || dedup.deduplicationMode >= static_cast(DedupNames.size())) { + LOG(fatal) << "unknown deduplicationMode " << dedup.deduplicationMode.value; + } + LOGF(info, "photon-conversion-builder: deduplicationMode = %d (%s), score weight = %.2f", + dedup.deduplicationMode.value, DedupNames[dedup.deduplicationMode.value], dedup.deduplicationScoreWeight.value); + LOGF(info, "photon-conversion-builder: minNv0PerCollision = %d, maxMinvPairPerCollision = %f", + skim.minNv0PerCollision.value, skim.maxMinvPairPerCollision.value); + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + switch (static_cast(useMatCorrType.value)) { + case MatCorrTypeEM::TGeo: + LOGF(info, "TGeo correction requested, loading geometry"); + if (!o2::base::GeometryManager::isGeometryLoaded()) { + ccdb->get(geoPath); + } + matCorr = o2::base::Propagator::MatCorrType::USEMatCorrTGeo; + break; + case MatCorrTypeEM::LUT: + LOGF(info, "LUT correction requested, loading LUT"); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); + matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + break; + default: + LOGF(info, "no correction requested, loading LUT by default!"); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(lutPath)); + matCorr = o2::base::Propagator::MatCorrType::USEMatCorrLUT; + break; + } + + if (mlcuts.applyPCMMl) { + if (mlcuts.use2DBinning) { + int binsNPt = static_cast(mlcuts.binsPtPCMMl->size()) - 1; + int binsNCent = static_cast(mlcuts.binsCentPCMMl->size()) - 1; + int binsN = binsNPt * binsNCent; + if (binsN * static_cast(mlcuts.cutDirPCMMl->size()) != static_cast(mlcuts.cutsPCMMlFlat->size())) { + LOG(fatal) << "Mismatch in number of bins and cuts provided for 2D ML application: binsN * cutDirPCMMl: " << binsN * static_cast(mlcuts.cutDirPCMMl->size()) << " bins vs. cutsPCMMlFlat: " << mlcuts.cutsPCMMlFlat->size() << " cuts"; + } + if (binsN != static_cast(mlcuts.onnxFileNames->size())) { + LOG(fatal) << "Mismatch in number of bins and ONNX files provided for 2D ML application: binsN " << binsN << " bins vs. onnxFileNames: " << mlcuts.onnxFileNames->size() << " ONNX files"; + } + if (binsN != static_cast(mlcuts.labelsBinsPCMMl->size())) { + LOG(fatal) << "Mismatch in number of bins and labels provided for 2D ML application: binsN:" << binsN << " bins vs. labelsBinsPCMMl: " << mlcuts.labelsBinsPCMMl->size() << " labels"; + } + if (static_cast(mlcuts.cutDirPCMMl->size()) != mlcuts.nClassesPCMMl) { + LOG(fatal) << "Mismatch in number of classes and cut directions provided for 2D ML application: nClassesPCMMl: " << mlcuts.nClassesPCMMl << " classes vs. cutDirPCMMl: " << mlcuts.cutDirPCMMl->size() << " cut directions"; + } + if (static_cast(mlcuts.labelsCutScoresPCMMl->size()) != mlcuts.nClassesPCMMl) { + LOG(fatal) << "Mismatch in number of labels for cut scores and number of classes provided for 2D ML application: nClassesPCMMl: " << mlcuts.nClassesPCMMl << " classes vs. labelsCutScoresPCMMl: " << mlcuts.labelsCutScoresPCMMl->size() << " labels"; + } + o2::framework::LabeledArray cutsPCMMl(mlcuts.cutsPCMMlFlat->data(), binsN, mlcuts.nClassesPCMMl, mlcuts.labelsBinsPCMMl, mlcuts.labelsCutScoresPCMMl); + emMlResponse.configure2D(mlcuts.binsPtPCMMl, mlcuts.binsCentPCMMl, cutsPCMMl, mlcuts.cutDirPCMMl, mlcuts.nClassesPCMMl); + } else { + int binsNPt = static_cast(mlcuts.binsPtPCMMl->size()) - 1; + if (binsNPt * static_cast(mlcuts.cutDirPCMMl->size()) != static_cast(mlcuts.cutsPCMMlFlat->size())) { + LOG(fatal) << "Mismatch in number of pT bins and cuts provided for ML application: binsNPt * cutDirPCMMl:" << binsNPt * mlcuts.cutDirPCMMl->size() << " bins vs. cutsPCMMlFlat: " << mlcuts.cutsPCMMlFlat->size() << " cuts"; + } + if (binsNPt != static_cast(mlcuts.onnxFileNames->size())) { + LOG(fatal) << "Mismatch in number of pT bins and ONNX files provided for ML application: binsNPt " << binsNPt << " bins vs. onnxFileNames: " << mlcuts.onnxFileNames->size() << " ONNX files"; + } + if (binsNPt != static_cast(mlcuts.labelsBinsPCMMl->size())) { + LOG(fatal) << "Mismatch in number of pT bins and labels provided for ML application: binsNPt:" << binsNPt << " bins vs. labelsBinsPCMMl: " << mlcuts.labelsBinsPCMMl->size() << " labels"; + } + if (mlcuts.nClassesPCMMl != static_cast(mlcuts.cutDirPCMMl->size())) { + LOG(fatal) << "Mismatch in number of classes and cut directions provided for ML application: nClassesPCMMl: " << mlcuts.nClassesPCMMl << " classes vs. cutDirPCMMl: " << mlcuts.cutDirPCMMl->size() << " cut directions"; + } + if (static_cast(mlcuts.labelsCutScoresPCMMl->size()) != mlcuts.nClassesPCMMl) { + LOG(fatal) << "Mismatch in number of labels for cut scores and number of classes provided for ML application: nClassesPCMMl:" << mlcuts.nClassesPCMMl << " classes vs. labelsCutScoresPCMMl: " << mlcuts.labelsCutScoresPCMMl->size() << " labels"; + } + o2::framework::LabeledArray cutsPCMMl(mlcuts.cutsPCMMlFlat->data(), binsNPt, mlcuts.nClassesPCMMl, mlcuts.labelsBinsPCMMl, mlcuts.labelsCutScoresPCMMl); + emMlResponse.configure(mlcuts.binsPtPCMMl, cutsPCMMl, mlcuts.cutDirPCMMl, mlcuts.nClassesPCMMl); + } + if (mlcuts.loadModelsFromCCDB) { + ccdbApi.init(ccdburl); + emMlResponse.setModelPathsCCDB(mlcuts.onnxFileNames, ccdbApi, mlcuts.modelPathsCCDB, mlcuts.timestampCCDB); + } else { + emMlResponse.setModelPathsLocal(mlcuts.onnxFileNames); + } + emMlResponse.cacheInputFeaturesIndices(mlcuts.namesInputFeatures); + emMlResponse.init(); + if (mlcuts.nClassesPCMMl == o2::analysis::NClassesML::kTwo) { + registry.add("V0/hBDTBackgroundScoreBeforeCutVsPt", "BDT background score before cut vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + registry.add("V0/hBDTBackgroundScoreAfterCutVsPt", "BDT background score after cut vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + registry.add("V0/hBDTSignalScoreBeforeCutVsPt", "BDT signal score before cut vs pT; pT (GeV/c); BDT signal score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + registry.add("V0/hBDTSignalScoreAfterCutVsPt", "BDT signal score after cut vs pT; pT (GeV/c); BDT signal score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + } else if (mlcuts.nClassesPCMMl == o2::analysis::NClassesML::kThree) { + registry.add("V0/hBDTBackgroundScoreBeforeCutVsPt", "BDT background score before cut vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + registry.add("V0/hBDTBackgroundScoreAfterCutVsPt", "BDT background score after cut vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + registry.add("V0/hBDTPrimaryPhotonScoreBeforeCutVsPt", "BDT primary photon score before cut vs pT; pT (GeV/c); BDT primary photon score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + registry.add("V0/hBDTPrimaryPhotonScoreAfterCutVsPt", "BDT primary photon score after cut vs pT; pT (GeV/c); BDT primary photon score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + registry.add("V0/hBDTSecondaryPhotonScoreBeforeCutVsPt", "BDT secondary photon score before cut vs pT; pT (GeV/c); BDT secondary photon score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + registry.add("V0/hBDTSecondaryPhotonScoreAfterCutVsPt", "BDT secondary photon score after cut vs pT; pT (GeV/c); BDT secondary photon score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + } else { + registry.add("V0/hBDTScoreBeforeCutVsPt", "BDT score before cut vs pT; pT (GeV/c); BDT score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + registry.add("V0/hBDTScoreAfterCutVsPt", "BDT score after cut vs pT; pT (GeV/c); BDT score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); + } + } + + // Compare proper propagation and fast geometrical propagation + if (modeTrackPropagation == TrackPropMode::kBoth) { + registry.add("V0Leg/hDCAxyPropagationCompare", "Comparison of DCA_{xy} propagation;DCA_{xy} (cm) proper propagation; DCA_{xy} (cm) geom. propagation", {HistType::kTH2F, {{200, -10., 10.}, {200, -10., 10.}}}); + registry.add("V0Leg/hDCAzPropagationCompare", "Comparison of DCA_{z} propagation;DCA_{z} (cm) proper propagation; DCA_{z} (cm) geom. propagation", {HistType::kTH2F, {{200, -10., 10.}, {200, -10., 10.}}}); + registry.add("V0/hPhivPropagationCompare", "Comparison of #phi_{v};#phi_{v} proper propagation; #phi_{v} geom. propagation", {HistType::kTH2F, {{100, 0., 1.6}, {100, 0., 1.6}}}); + registry.add("V0/hPsiPairPropagationCompare", "Comparison of #Psi_{pair};#Psi_{pair} proper propagation; #Psi_{pair} geom. propagation", {HistType::kTH2F, {{100, 0., 1.6}, {100, 0., 1.6}}}); + } + + // Make sure the dedup.deduplicationScoreWeight is between 0 and 1 + if (dedup.deduplicationScoreWeight > 1.f) { // o2-linter: disable=magic-number (score has to be below unity) + LOG(warning) << "deduplicationScoreWeight is larger than unity which is not allowed"; + } + if (dedup.deduplicationScoreWeight < 0.f) { // o2-linter: disable=magic-number (score has to be above zero) + LOG(warning) << "deduplicationScoreWeight is smaller than zero which is not allowed"; + } + + if (doprocessMC) { + const AxisSpec axQ{60, 0.f, 0.3f, "q_{inv}^{true} (GeV/c)"}; + const AxisSpec axDEta{80, -1.6f, 1.6f, "#Delta#eta_{#gamma#gamma}^{true}"}; + const AxisSpec axClass{3, -0.5f, 2.5f, "0 = true, 1 = cross-leg fake, 2 = other fake"}; + // lostByPartnerFake is a subset of lostByCrossFake, and a pair can appear in several of them. + for (const auto& nm : {"before", "bothSurvive", "bothSurviveSameColl", "oneLost", "bothLost", + "lostByCrossFake", "lostByPartnerFake", "lostByOtherFake", "lostByTrue"}) { + const std::string dir = std::string("MCDedup/Pairs/") + nm + "/"; + registry.add((dir + "hQ").c_str(), "truth photon pairs with >=1 true V0 candidate before deduplication;q_{inv}^{true} (GeV/c);pairs", kTH1F, {axQ}, true); + registry.add((dir + "hDEta").c_str(), "truth photon pairs with >=1 true V0 candidate before deduplication;#Delta#eta^{true};pairs", kTH1F, {axDEta}, true); + } + registry.add("MCDedup/Candidates/hClassStage", "candidate composition;class;0 = before, 1 = stored", kTH2F, {axClass, {2, -0.5f, 1.5f}}, true); + + const AxisSpec axBlocker{4, -0.5f, 3.5f, "0 = true, 1 = cross-leg fake, 2 = other fake, 3 = no blocker (cut, not dedup)"}; + + registry.add("MCDedup/Photons/hFate", "fate of the true photons;0 = alive, 1 = lost (blocked), 2 = lost (no blocker);photons", kTH1F, {{3, -0.5f, 2.5f}}, true); + registry.add("MCDedup/Photons/hBlockerClass", "blockers of a killed true photon (ENTRIES = blockers, not photons);class of the blocker;blocker entries", kTH1F, {axBlocker}, true); + registry.add("MCDedup/Photons/hKillMargin", "mode 0/1 only;S_{victim} - S_{winner};kills", kTH1F, {{200, 0.f, 1.f}}, true); + registry.add("MCDedup/Photons/hVictimVsWinnerPCA", "PCA of the two;PCA_{victim} (cm);PCA_{winner} (cm)", kTH2F, {{60, 0.f, 3.f}, {60, 0.f, 3.f}}, true); + // Reason for photon building failure + // x = 0 -> an equally large solution containing it existed + // x > 0 -> keeping it would have cost x candidates + registry.add("MCDedup/Photons/hLostMargin", "why the true photon lost (mode 2);cardinality deficit;#Sigma S(best set with it) - #Sigma S(winner)", kTH2F, {{5, -0.5f, 4.5f}, {100, 0.f, 2.f}}, true); + if (dedup.cfgDedupTruthMaps) { + const AxisSpec axDEtaFine{640, -1.6f, 1.6f, "#Delta#eta^{true}"}; + const AxisSpec axDPhi{144, -o2::constants::math::PI, o2::constants::math::PI, "#Delta#varphi^{true} (rad)"}; + for (const auto& nm : {"before", "bothSurvive", "bothLost", "lostByPartnerFake"}) { + registry.add((std::string("MCDedup/Pairs/") + nm + "/hMap").c_str(), "truth photon pairs", kTHnSparseF, {axDEtaFine, axDPhi, axQ}, true); + } + } + } + } + + void initCCDB(MyBCs::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + // In case override, don't proceed, please - no CCDB access required + if (d_bz_input > -990) { // o2-linter: disable=magic-number (override value) + d_bz = d_bz_input; + o2::parameters::GRPMagField grpmag; + if (std::fabs(d_bz) > 1e-5) { // o2-linter: disable=magic-number (override value) + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); // o2-linter: disable=magic-number (override value) + } + o2::base::Propagator::initFieldFromGRP(&grpmag); + + return; + } + + auto run3grp_timestamp = bc.timestamp(); + o2::base::Propagator::initFieldFromGRP(&bc.grpMagField()); + // Fetch magnetic field from ccdb for current collision + d_bz = bc.grpMagField().getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + + if (useMatCorrType == 2) { // o2-linter: disable=magic-number (material budget correction) + // setMatLUT only after magfield has been initalized (setMatLUT has implicit and problematic init field call if not) + o2::base::Propagator::Instance()->setMatLUT(lut); + } + /// Set magnetic field for KF vertexing + const float magneticField = o2::base::Propagator::Instance()->getNominalBz(); + KFParticle::SetField(magneticField); + + mVDriftMgr.init(&ccdb->instance()); + } + + void updateCCDB(MyBCs::iterator const& bc) + { + auto timestamp = bc.timestamp(); + + mVDriftMgr.update(timestamp); + } + + std::pair> its_ib_Requirement = {0, {0, 1, 2}}; // no hit on 3 ITS ib layers. + template + bool checkV0leg(TTrack const& track) + { + using namespace o2::pwgem::photonmeson; + if constexpr (isMC) { + if (!track.has_mcParticle()) { + return false; + } + } + + if (trackcuts.disableITSonlyTracks && isITSonlyTrack(track)) { + return false; + } + + if (trackcuts.disableTPConlyTracks && isTPConlyTrack(track)) { + return false; + } + + if (trackcuts.requireITShit && !track.hasITS()) { + return false; + } + + if (track.x() > trackcuts.maxX) { + return false; + } + + if (!track.hasITS() && !track.hasTPC()) { + return false; + } + + if (track.hasITS() && !track.hasTPC() && (track.hasTRD() || track.hasTOF())) { // remove unrealistic track. this should not happen. + return false; + } + + if (track.hasTPC()) { + if (track.tpcNClsFound() < trackcuts.min_ncluster_tpc) { + return false; + } + if (track.tpcNClsCrossedRows() < trackcuts.mincrossedrows || track.tpcChi2NCl() > trackcuts.maxchi2tpc) { + return false; + } + if (track.tpcFractionSharedCls() > trackcuts.max_frac_shared_clusters_tpc) { + return false; + } + if (track.tpcNSigmaEl() < trackcuts.minTPCNsigmaEl || trackcuts.maxTPCNsigmaEl < track.tpcNSigmaEl()) { + return false; + } + } + + if (track.hasITS()) { + if (track.itsChi2NCl() > trackcuts.maxchi2its) { + return false; + } + + if (v0cuts.reject_v0_on_itsib) { + auto hits_ib = std::count_if(its_ib_Requirement.second.begin(), its_ib_Requirement.second.end(), [&](auto&& requiredLayer) { return track.itsClusterMap() & (1 << requiredLayer); }); + bool its_ob_only = hits_ib <= its_ib_Requirement.first; + if (!its_ob_only) { + return false; + } + } + } + + return true; + } + + float cospaXY_KF(const KFParticle& kfp, const KFParticle& PV) + { + float lx = kfp.GetX() - PV.GetX(); // flight length X + float ly = kfp.GetY() - PV.GetY(); // flight length Y + + float px = kfp.GetPx(); + float py = kfp.GetPy(); + float cospaXY = RecoDecay::dotProd(std::array{lx, ly}, std::array{px, py}) / (RecoDecay::sqrtSumOfSquares(lx, ly) * RecoDecay::sqrtSumOfSquares(px, py)); + if (cospaXY < -1.f) { + return -1.f; + } + if (cospaXY > 1.f) { + return 1.f; + } + return cospaXY; + } + + float cospaRZ_KF(const KFParticle& kfp, const KFParticle& PV) + { + float lx = kfp.GetX() - PV.GetX(); // flight length X + float ly = kfp.GetY() - PV.GetY(); // flight length Y + float lz = kfp.GetZ() - PV.GetZ(); // flight length Z + float lt = RecoDecay::sqrtSumOfSquares(lx, ly); // flight length R, i.e. transverse plane. + + float pt = RecoDecay::sqrtSumOfSquares(kfp.GetPx(), kfp.GetPy()); + float pz = kfp.GetPz(); + + float cospaRZ = RecoDecay::dotProd(std::array{lt, lz}, std::array{pt, pz}) / (RecoDecay::sqrtSumOfSquares(lt, lz) * RecoDecay::sqrtSumOfSquares(pt, pz)); + if (cospaRZ < -1.f) { + return -1.f; + } + if (cospaRZ > 1.f) { + return 1.f; + } + return cospaRZ; + } + + template + void fillTrackTable(TTrack const& track, TShiftedTrack const& shiftedtrack, const float dcaXY, const float dcaZ) + { + v0legs(track.collisionId(), track.globalIndex(), track.sign(), + shiftedtrack.GetPx(), shiftedtrack.GetPy(), shiftedtrack.GetPz(), dcaXY, dcaZ, + track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), track.tpcNClsShared(), + track.tpcChi2NCl(), track.tpcInnerParam(), track.tpcSignal(), + track.tpcNSigmaEl(), track.tpcNSigmaPi(), + track.itsClusterSizes(), track.itsChi2NCl(), track.detectorMap()); + + v0legsXYZ(shiftedtrack.GetX(), shiftedtrack.GetY(), shiftedtrack.GetZ()); + + if constexpr (isMC) { + v0legsDeDxMC(track.mcTunedTPCSignal()); + } + } + + template + void fillV0Table(TV0 const& v0, const bool filltable) + { + using namespace o2::pwgem::photonmeson; + // Get tracks + const auto& pos = v0.template posTrack_as(); + const auto& ele = v0.template negTrack_as(); + const auto& collision = v0.template collision_as(); // collision where this v0 belongs to. + // LOGF(info, "v0.collisionId() = %d, pos.collisionId() = %d, ele.collisionId() = %d", v0.collisionId(), pos.collisionId(), ele.collisionId()); + + if (pos.sign() * ele.sign() > 0) { // reject same sign pair + return; + } + + if (pos.pt() < trackcuts.min_pt_trackiu || ele.pt() < trackcuts.min_pt_trackiu) { + return; + } + + if (pos.globalIndex() == ele.globalIndex()) { + return; + } + + if (isITSonlyTrack(pos) && !ele.hasITS()) { + return; + } + + if (isITSonlyTrack(ele) && !pos.hasITS()) { + return; + } + + if (!checkV0leg(pos) || !checkV0leg(ele)) { + return; + } + + // LOGF(info, "v0.collisionId() = %d , v0.posTrackId() = %d , v0.negTrackId() = %d", v0.collisionId(), v0.posTrackId(), v0.negTrackId()); + + // if(isTPConlyTrack(ele)){ + // // LOGF(info, "TPConly: ele.globalIndex() = %d, ele.x() = %f, ele.y() = %f, ele.z() = %f, ele.tgl() = %f, ele.alpha() = %f, ele.snp() = %f, ele.signed1Pt() = %f", ele.globalIndex(), ele.x(), ele.y(), ele.z(), ele.tgl(), ele.alpha(), ele.snp(), ele.signed1Pt()); + // // LOGF(info, "TPConly: ele.globalIndex() = %d, ele.cYY() = %f, ele.cZY() = %f, ele.cZZ() = %f, ele.cSnpY() = %f, ele.cSnpZ() = %f, ele.cSnpSnp() = %f, ele.cTglY() = %f, ele.cTglZ() = %f, ele.cTglSnp() = %f, ele.cTglTgl() = %f, ele.c1PtY() = %f, ele.c1PtZ() = %f, ele.c1PtSnp() = %f, ele.c1PtTgl() = %f, ele.c1Pt21Pt2() = %f", ele.globalIndex(), ele.cYY(), ele.cZY(), ele.cZZ(), ele.cSnpY(), ele.cSnpZ(), ele.cSnpSnp(), ele.cTglY(), ele.cTglZ(), ele.cTglSnp(), ele.cTglTgl(), ele.c1PtY(), ele.c1PtZ(), ele.c1PtSnp(), ele.c1PtTgl(), ele.c1Pt21Pt2()); + // } + + // Calculate DCA with respect to the collision associated to the v0, not individual tracks + std::array dcaInfo{}; + + auto pTrack = getTrackParCov(pos); + if (trackcuts.moveTPCTracks && isTPConlyTrack(pos) && !mVDriftMgr.moveTPCTrack(collision, pos, pTrack)) { + LOGP(error, "failed correction for positive tpc track"); + return; + } + auto pTrackC = pTrack; + o2::math_utils::Point3D vtxPrim{ + collision.posX(), + collision.posY(), + collision.posZ()}; + if (modeTrackPropagation != TrackPropMode::kProper) { + dcaInfo = CalculateDCAFast(pTrackC, vtxPrim, d_bz); + } + pTrackC.setPID(o2::track::PID::Electron); + + std::array dcaInfoFast = dcaInfo; + if (modeTrackPropagation != TrackPropMode::kFast) { + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrackC, 2.f, matCorr, &dcaInfo); + if (filltable && modeTrackPropagation == TrackPropMode::kBoth) { + registry.fill(HIST("V0Leg/hDCAxyPropagationCompare"), dcaInfo[0], dcaInfoFast[0]); + registry.fill(HIST("V0Leg/hDCAzPropagationCompare"), dcaInfo[1], dcaInfoFast[1]); + } + } + auto posdcaXY = dcaInfo[0]; + auto posdcaZ = dcaInfo[1]; + + auto nTrack = getTrackParCov(ele); + if (trackcuts.moveTPCTracks && isTPConlyTrack(ele) && !mVDriftMgr.moveTPCTrack(collision, ele, nTrack)) { + LOGP(error, "failed correction for negative tpc track"); + return; + } + auto nTrackC = nTrack; + if (modeTrackPropagation != TrackPropMode::kProper) { + dcaInfo = CalculateDCAFast(nTrackC, vtxPrim, d_bz); + } + nTrackC.setPID(o2::track::PID::Electron); + + dcaInfoFast = dcaInfo; + if (modeTrackPropagation != TrackPropMode::kFast) { + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrackC, 2.f, matCorr, &dcaInfo); + if (filltable && modeTrackPropagation == TrackPropMode::kBoth) { + registry.fill(HIST("V0Leg/hDCAxyPropagationCompare"), dcaInfo[0], dcaInfoFast[0]); + registry.fill(HIST("V0Leg/hDCAzPropagationCompare"), dcaInfo[1], dcaInfoFast[1]); + } + } + auto eledcaXY = dcaInfo[0]; + auto eledcaZ = dcaInfo[1]; + + if (std::fabs(posdcaXY) < trackcuts.dcapostopv || std::fabs(eledcaXY) < trackcuts.dcanegtopv) { + return; + } + + std::array xyz = {0.f, 0.f, 0.f}; + Vtx_recalculationParCov(o2::base::Propagator::Instance(), pTrack, nTrack, xyz, matCorr); + float rxy_tmp = RecoDecay::sqrtSumOfSquares(xyz[0], xyz[1]); + if (rxy_tmp > trackcuts.maxX + v0cuts.margin_r_tpc) { + return; + } + if (rxy_tmp < std::fabs(xyz[2]) * std::tan(2 * std::atan(std::exp(-v0cuts.max_eta_v0))) - v0cuts.margin_z) { + return; // RZ line cut + } + + float phiv = 999.f; + float psipair = 999.f; + float phivFast = 999.f; + float psipairFast = 999.f; + float baseR = std::hypot(xyz[0], xyz[1]); + // This method uses the track Helix instead of the full propagation. + // Hence, it is only an approximation but much faster + if (modeTrackPropagation != TrackPropMode::kProper) { + + o2::track::TrackAuxPar helixPosEle(nTrack, d_bz); + o2::track::TrackAuxPar helixPosPos(pTrack, d_bz); + + float diffX = helixPosEle.xC - helixPosPos.xC; + float diffY = helixPosEle.yC - helixPosPos.yC; + auto phiHelix = RecoDecay::constrainAngle(std::atan2(diffY, diffX) - o2::constants::math::PI / 2.); + + // Electron + float arcLenghtEle = helixPosEle.rC * 0.9 > propV0LegsRadius ? std::asin(propV0LegsRadius / helixPosEle.rC) * helixPosEle.rC : o2::constants::math::PI / 2.2 * helixPosEle.rC; // This assumes that the photon momentum vector is a tangent of the circle // o2-linter: disable=magic-number (geometrical assumption for propagation) + auto propTrackEle = getPropMomentumFromTrackHelix(arcLenghtEle, ele, helixPosEle, d_bz / 10., phiHelix - ele.phi()); + // Positron + float arcLenghtPos = helixPosPos.rC * 0.9 > propV0LegsRadius ? std::asin(propV0LegsRadius / helixPosPos.rC) * helixPosPos.rC : o2::constants::math::PI / 2.2 * helixPosPos.rC; // This assumes that the photon momentum vector is a tangent of the circle // o2-linter: disable=magic-number (geometrical assumption for propagation) + auto propTrackPos = getPropMomentumFromTrackHelix(arcLenghtPos, pos, helixPosPos, d_bz / 10., phiHelix - pos.phi()); + + phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(propTrackPos[0], propTrackPos[1], propTrackPos[2], propTrackEle[0], propTrackEle[1], propTrackEle[2], pos.sign(), ele.sign(), d_bz); + psipair = o2::aod::pwgem::dilepton::utils::pairutil::getPsiPair(propTrackPos[0], propTrackPos[1], propTrackPos[2], propTrackEle[0], propTrackEle[1], propTrackEle[2]); + + // Store values for later comparison + phivFast = phiv; + psipairFast = psipair; + } + // This uses the full propagation including material effects + if (modeTrackPropagation != TrackPropMode::kFast) { + std::array offsetsR = {propV0LegsRadius, 30.f, 10.f}; + bool pPropagatedSuccess = false; + bool nPropagatedSuccess = false; + auto pTrackProp = pTrack; + auto nTrackProp = nTrack; + for (const auto& offsetR : offsetsR) { + pTrackProp = pTrack; + pTrackProp.setPID(o2::track::PID::Electron); + nTrackProp = nTrack; + nTrackProp.setPID(o2::track::PID::Electron); + + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrackProp, 2.f, matCorr, &dcaInfo); + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrackProp, 2.f, matCorr, &dcaInfo); + + pPropagatedSuccess = o2::base::Propagator::Instance()->propagateToR(pTrackProp, baseR + offsetR); + nPropagatedSuccess = o2::base::Propagator::Instance()->propagateToR(nTrackProp, baseR + offsetR); + + if (pPropagatedSuccess && nPropagatedSuccess) { + KFPTrack kfp_track_posProp = createKFPTrackFromTrackParCov(pTrackProp, pos.sign(), pos.tpcNClsFound(), pos.tpcChi2NCl()); + KFPTrack kfp_track_eleProp = createKFPTrackFromTrackParCov(nTrackProp, ele.sign(), ele.tpcNClsFound(), ele.tpcChi2NCl()); + phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(kfp_track_posProp.GetPx(), kfp_track_posProp.GetPy(), kfp_track_posProp.GetPz(), kfp_track_eleProp.GetPx(), kfp_track_eleProp.GetPy(), kfp_track_eleProp.GetPz(), pos.sign(), ele.sign(), d_bz); + psipair = o2::aod::pwgem::dilepton::utils::pairutil::getPsiPair(kfp_track_posProp.GetPx(), kfp_track_posProp.GetPy(), kfp_track_posProp.GetPz(), kfp_track_eleProp.GetPx(), kfp_track_eleProp.GetPy(), kfp_track_eleProp.GetPz()); + break; + } + LOG(debug) << "Propagation to offset" << offsetR << " cm failed for " << (pPropagatedSuccess ? "negative" : "positive") << " track. Trying smaller offset."; + } + if (filltable && modeTrackPropagation == TrackPropMode::kBoth) { + registry.fill(HIST("V0/hPhivPropagationCompare"), phiv, phivFast); + registry.fill(HIST("V0/hPsiPairPropagationCompare"), psipair, psipairFast); + } + } + + if (phiv == 999.f || psipair == 999.f) { // o2-linter: disable=magic-number (nonsensical default value) + LOG(debug) << "Propagation failed for all radii (" << propV0LegsRadius << ", 30, 10 cm). Using default values for phiv and psipair (999.f)."; + } + + KFPTrack kfp_track_pos = createKFPTrackFromTrackParCov(pTrack, pos.sign(), pos.tpcNClsFound(), pos.tpcChi2NCl()); + KFPTrack kfp_track_ele = createKFPTrackFromTrackParCov(nTrack, ele.sign(), ele.tpcNClsFound(), ele.tpcChi2NCl()); + KFParticle kfp_pos(kfp_track_pos, kPositron); + KFParticle kfp_ele(kfp_track_ele, kElectron); + std::array GammaDaughters{&kfp_pos, &kfp_ele}; + + KFParticle gammaKF; + gammaKF.SetConstructMethod(2); + gammaKF.Construct(GammaDaughters.data(), 2); + if (v0cuts.kfMassConstrain > -0.1) { // o2-linter: disable=magic-number (nonsensical default value) + gammaKF.SetNonlinearMassConstraint(v0cuts.kfMassConstrain); + } + KFPVertex kfpVertex = createKFPVertexFromCollision(collision); + KFParticle KFPV(kfpVertex); + + // Transport the gamma to the recalculated decay vertex + KFParticle gammaKF_DecayVtx = gammaKF; // with respect to (0,0,0) + gammaKF_DecayVtx.TransportToPoint(xyz.data()); + + float cospa_kf = cpaFromKF(gammaKF_DecayVtx, KFPV); + if (!ele.hasITS() && !pos.hasITS()) { + if (cospa_kf < v0cuts.min_v0cospa_tpconly) { + return; + } + } else { + if (cospa_kf < v0cuts.min_v0cospa_its) { + return; + } + } + + float rxy = RecoDecay::sqrtSumOfSquares(gammaKF_DecayVtx.GetX(), gammaKF_DecayVtx.GetY()); + if (rxy > trackcuts.maxX + v0cuts.margin_r_tpc) { + return; + } + if (rxy < std::fabs(gammaKF_DecayVtx.GetZ()) * std::tan(2 * std::atan(std::exp(-v0cuts.max_eta_v0))) - v0cuts.margin_z) { + return; // RZ line cut + } + if (rxy < v0cuts.min_v0radius || v0cuts.max_v0radius < rxy) { + return; + } + + if (!filltable) { + if (isITSTPCTrack(pos) && isITSTPCTrack(ele)) { + registry.fill(HIST("V0/hRxy_minX_ITSTPC_ITSTPC"), std::min(pTrack.getX(), nTrack.getX()), std::min(pTrack.getX(), nTrack.getX()) - rxy); // trackiu.x() - rxy should be positive + } else if (isITSonlyTrack(pos) && isITSonlyTrack(ele)) { + registry.fill(HIST("V0/hRxy_minX_ITSonly_ITSonly"), std::min(pTrack.getX(), nTrack.getX()), std::min(pTrack.getX(), nTrack.getX()) - rxy); // trackiu.x() - rxy should be positive + } else if ((isITSTPCTrack(pos) && isITSonlyTrack(ele)) || (isITSTPCTrack(ele) && isITSonlyTrack(pos))) { + registry.fill(HIST("V0/hRxy_minX_ITSTPC_ITSonly"), std::min(pTrack.getX(), nTrack.getX()), std::min(pTrack.getX(), nTrack.getX()) - rxy); // trackiu.x() - rxy should be positive + } else if (isITSTPCTrack(pos) && !ele.hasITS()) { + registry.fill(HIST("V0/hRxy_minX_ITSTPC_TPC"), std::min(pTrack.getX(), 83.f), std::min(pTrack.getX(), 83.f) - rxy); // trackiu.x() - rxy should be positive + } else if (isITSTPCTrack(ele) && !pos.hasITS()) { + registry.fill(HIST("V0/hRxy_minX_ITSTPC_TPC"), std::min(nTrack.getX(), 83.f), std::min(nTrack.getX(), 83.f) - rxy); // trackiu.x() - rxy should be positive + } else { + registry.fill(HIST("V0/hRxy_minX_TPC_TPC"), std::min(83.f, 83.f), std::min(83.f, 83.f) - rxy); // trackiu.x() - rxy should be positive + } + } + + if (pos.hasITS() && ele.hasITS()) { // ITSonly-ITSonly, ITSTPC-ITSTPC, ITSTPC-ITSonly + if (rxy > std::min(pTrack.getX(), nTrack.getX()) + v0cuts.margin_r_its) { + return; + } + } else if (!pos.hasITS() && ele.hasITS()) { // ITSTPC-TPC + if (rxy > std::min(83.f, nTrack.getX()) + v0cuts.margin_r_itstpc_tpc) { + return; + } + } else if (pos.hasITS() && !ele.hasITS()) { // ITSTPC-TPC + if (rxy > std::min(pTrack.getX(), 83.f) + v0cuts.margin_r_itstpc_tpc) { + return; + } + } else if (!pos.hasITS() && !ele.hasITS()) { // TPC-TPC + if (rxy > std::min(83.f, 83.f) + v0cuts.margin_r_tpc) { + return; + } + } + + if ((!pos.hasITS() || !ele.hasITS()) && rxy < v0cuts.max_r_req_its) { // conversion points smaller than v0cuts.max_r_req_its have to be detected with ITS hits. + return; + } + + if ((!pos.hasITS() && !ele.hasITS()) && rxy < v0cuts.min_r_tpconly) { // TPConly tracks can detect conversion points larger than v0cuts.min_r_tpconly. + return; + } + + // Apply a topological constraint of the gamma to the PV. Parameters will be given at the primary vertex. + KFParticle gammaKF_PV = gammaKF; + gammaKF_PV.SetProductionVertex(KFPV); + float v0pt = RecoDecay::sqrtSumOfSquares(gammaKF_PV.GetPx(), gammaKF_PV.GetPy()); + float v0eta = RecoDecay::eta(std::array{gammaKF_PV.GetPx(), gammaKF_PV.GetPy(), gammaKF_PV.GetPz()}); + float v0phi = RecoDecay::constrainAngle(RecoDecay::phi(gammaKF_PV.GetPx(), gammaKF_PV.GetPy())); + + // KFParticle gammaKF_DecayVtx2 = gammaKF; + // gammaKF_DecayVtx2.SetProductionVertex(KFPV); + // gammaKF_DecayVtx2.TransportToPoint(xyz); + // LOGF(info, "gammaKF_PV.GetPx() = %f, gammaKF_DecayVtx.GetPx() = %f, gammaKF_DecayVtx2.GetPx() = %f", gammaKF_PV.GetPx(), gammaKF_DecayVtx.GetPx(), gammaKF_DecayVtx2.GetPx()); + // LOGF(info, "gammaKF_PV.GetPy() = %f, gammaKF_DecayVtx.GetPy() = %f, gammaKF_DecayVtx2.GetPy() = %f", gammaKF_PV.GetPy(), gammaKF_DecayVtx.GetPy(), gammaKF_DecayVtx2.GetPy()); + // LOGF(info, "gammaKF_PV.GetPz() = %f, gammaKF_DecayVtx.GetPz() = %f, gammaKF_DecayVtx2.GetPz() = %f", gammaKF_PV.GetPz(), gammaKF_DecayVtx.GetPz(), gammaKF_DecayVtx2.GetPz()); + + if (std::fabs(v0eta) > v0cuts.max_eta_v0 || v0pt < v0cuts.min_pt_v0) { + return; + } + + if (isITSonlyTrack(ele) && isITSonlyTrack(pos) && v0pt > v0cuts.max_pt_v0_itsonly) { + return; + } + + KFParticle kfp_pos_DecayVtx = kfp_pos; // Don't set Primary Vertex + KFParticle kfp_ele_DecayVtx = kfp_ele; // Don't set Primary Vertex + kfp_pos_DecayVtx.TransportToPoint(xyz.data()); // Don't set Primary Vertex + kfp_ele_DecayVtx.TransportToPoint(xyz.data()); // Don't set Primary Vertex + + float cospaXYKF = cospaXY_KF(gammaKF_DecayVtx, KFPV); + float cospaRZKF = cospaRZ_KF(gammaKF_DecayVtx, KFPV); + auto centType = static_cast(mlcuts.centTypePCMMl.value); + v0photoncandidate.setPhotonCandidate(gammaKF_DecayVtx, gammaKF_PV, pos, kfp_pos_DecayVtx, ele, kfp_ele_DecayVtx, collision, cospaXYKF, cospaRZKF, cospaXYKF, psipair, phiv, centType, posdcaXY, eledcaXY, posdcaZ, eledcaZ); + + if (!ele.hasITS() && !pos.hasITS()) { // V0s with TPConly-TPConly + if (v0cuts.max_r_itsmft_ss < rxy && rxy < trackcuts.maxX + v0cuts.margin_r_tpc) { + if (v0photoncandidate.getPCA() > v0cuts.max_dcav0dau_tpc_inner_fc) { + return; + } + } else { + if (v0photoncandidate.getPCA() > v0cuts.max_dcav0dau_tpconly) { + return; + } + } + } else { // V0s with ITS hits + if (rxy < v0cuts.max_r_req_its) { + if (v0photoncandidate.getPCA() > v0cuts.max_dcav0dau_itsibss) { + return; + } + } else { + if (v0photoncandidate.getPCA() > v0cuts.max_dcav0dau_its) { + return; + } + } + } + + if (isITSonlyTrack(pos) && v0photoncandidate.getPosPt() > trackcuts.maxpt_itsonly) { + return; + } + + if (isITSonlyTrack(ele) && v0photoncandidate.getElePt() > trackcuts.maxpt_itsonly) { + return; + } + + if (v0photoncandidate.getChi2NDF() > 6e+3) { // protection for uint16. // o2-linter: disable=magic-number (protection for uint16) + return; + } + + if (std::fabs(v0photoncandidate.getDcaXYToPV()) > v0cuts.max_dcatopv_xy_v0 || std::fabs(v0photoncandidate.getDcaZToPV()) > v0cuts.max_dcatopv_z_v0) { + return; + } + + if (!checkAP(v0photoncandidate.getAlpha(), v0photoncandidate.getQt(), v0cuts.max_alpha_ap, v0cuts.max_qt_ap)) { // store only photon conversions + return; + } + pca_map[std::make_tuple(v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex())] = v0photoncandidate.getPCA(); + cospa_map[std::make_tuple(v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex())] = v0photoncandidate.getCosPA(); + + ROOT::Math::PxPyPzMVector vposDedup(kfp_pos_DecayVtx.GetPx(), kfp_pos_DecayVtx.GetPy(), kfp_pos_DecayVtx.GetPz(), o2::constants::physics::MassElectron); + ROOT::Math::PxPyPzMVector veleDedup(kfp_ele_DecayVtx.GetPx(), kfp_ele_DecayVtx.GetPy(), kfp_ele_DecayVtx.GetPz(), o2::constants::physics::MassElectron); + const auto meeSV = static_cast((vposDedup + veleDedup).M()); + + const auto score = getScoreV0(v0photoncandidate.getCosPA(), v0photoncandidate.getPCA(), dedup.deduplicationScoreWeight); + V0CandidateHelper v0Helper(v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex(), + v0photoncandidate.getCosPA(), v0photoncandidate.getPCA(), score, meeSV); + v0Helper.pxAtPV = gammaKF_PV.GetPx(); + v0Helper.pyAtPV = gammaKF_PV.GetPy(); + v0Helper.pzAtPV = gammaKF_PV.GetPz(); + vecV0Dedup.emplace_back(v0Helper); + + if (mlcuts.applyPCMMl) { + bool isSelectedML = false; + std::vector mlInputFeatures = emMlResponse.getInputFeatures(v0photoncandidate, pos, ele); + if (mlcuts.use2DBinning) { + isSelectedML = emMlResponse.isSelectedMl(mlInputFeatures, v0photoncandidate.getPt(), v0photoncandidate.getCent(), outputML); + } else { + isSelectedML = emMlResponse.isSelectedMl(mlInputFeatures, v0photoncandidate.getPt(), outputML); + } + if (filltable) { + if (mlcuts.nClassesPCMMl == o2::analysis::NClassesML::kTwo) { + registry.fill(HIST("V0/hBDTBackgroundScoreBeforeCutVsPt"), v0photoncandidate.getPt(), outputML[0]); + registry.fill(HIST("V0/hBDTSignalScoreBeforeCutVsPt"), v0photoncandidate.getPt(), outputML[1]); + } else if (mlcuts.nClassesPCMMl == o2::analysis::NClassesML::kThree) { + registry.fill(HIST("V0/hBDTPrimaryPhotonScoreBeforeCutVsPt"), v0photoncandidate.getPt(), outputML[0]); + registry.fill(HIST("V0/hBDTSecondaryPhotonScoreBeforeCutVsPt"), v0photoncandidate.getPt(), outputML[1]); + registry.fill(HIST("V0/hBDTBackgroundScoreBeforeCutVsPt"), v0photoncandidate.getPt(), outputML[2]); + } else { + registry.fill(HIST("V0/hBDTScoreBeforeCutVsPt"), v0photoncandidate.getPt(), outputML[0]); + } + } + if (!isSelectedML) { + return; + } + if (filltable) { + if (mlcuts.nClassesPCMMl == o2::analysis::NClassesML::kTwo) { + registry.fill(HIST("V0/hBDTBackgroundScoreAfterCutVsPt"), v0photoncandidate.getPt(), outputML[0]); + registry.fill(HIST("V0/hBDTSignalScoreAfterCutVsPt"), v0photoncandidate.getPt(), outputML[1]); + } else if (mlcuts.nClassesPCMMl == o2::analysis::NClassesML::kThree) { + registry.fill(HIST("V0/hBDTPrimaryPhotonScoreAfterCutVsPt"), v0photoncandidate.getPt(), outputML[0]); + registry.fill(HIST("V0/hBDTSecondaryPhotonScoreAfterCutVsPt"), v0photoncandidate.getPt(), outputML[1]); + registry.fill(HIST("V0/hBDTBackgroundScoreAfterCutVsPt"), v0photoncandidate.getPt(), outputML[2]); + } else { + registry.fill(HIST("V0/hBDTScoreAfterCutVsPt"), v0photoncandidate.getPt(), outputML[0]); + } + } + } + + if (filltable) { + registry.fill(HIST("V0/hAP"), v0photoncandidate.getAlpha(), v0photoncandidate.getQt()); + registry.fill(HIST("V0/hConversionPointXY"), gammaKF_DecayVtx.GetX(), gammaKF_DecayVtx.GetY()); + registry.fill(HIST("V0/hConversionPointRZ"), gammaKF_DecayVtx.GetZ(), rxy); + registry.fill(HIST("V0/hPt"), v0photoncandidate.getPt()); + registry.fill(HIST("V0/hEtaPhi"), v0phi, v0eta); + registry.fill(HIST("V0/hCosPA"), v0photoncandidate.getCosPA()); + registry.fill(HIST("V0/hCosPA_Rxy"), rxy, v0photoncandidate.getCosPA()); + registry.fill(HIST("V0/hPCA"), v0photoncandidate.getPCA()); + registry.fill(HIST("V0/hPCA_CosPA"), v0photoncandidate.getCosPA(), v0photoncandidate.getPCA()); + registry.fill(HIST("V0/hPCA_Rxy"), rxy, v0photoncandidate.getPCA()); + registry.fill(HIST("V0/hDCAxyz"), v0photoncandidate.getDcaXYToPV(), v0photoncandidate.getDcaZToPV()); + registry.fill(HIST("V0/hPCA_diffX"), v0photoncandidate.getPCA(), std::min(pTrack.getX(), nTrack.getX()) - rxy); // trackiu.x() - rxy should be positive + registry.fill(HIST("V0/hPhiVPsiPair"), v0photoncandidate.getPsiPair(), v0photoncandidate.getPhiV()); + + // LOGF(info, "cospa_kf = %f, cospaXY_kf = %f, cospaRZ_kf = %f", cospa_kf, cospaXY_kf, cospaRZ_kf); + registry.fill(HIST("V0/hCosPAXY_Rxy"), rxy, cospaXYKF); + registry.fill(HIST("V0/hCosPARZ_Rxy"), rxy, cospaRZKF); + + for (const auto& leg : {kfp_pos_DecayVtx, kfp_ele_DecayVtx}) { + float legpt = RecoDecay::sqrtSumOfSquares(leg.GetPx(), leg.GetPy()); + float legeta = RecoDecay::eta(std::array{leg.GetPx(), leg.GetPy(), leg.GetPz()}); + float legphi = RecoDecay::constrainAngle(RecoDecay::phi(leg.GetPx(), leg.GetPy())); + registry.fill(HIST("V0Leg/hPt"), legpt); + registry.fill(HIST("V0Leg/hEtaPhi"), legphi, legeta); + } // end of leg loop + for (const auto& leg : {pos, ele}) { + registry.fill(HIST("V0Leg/hdEdx_Pin"), leg.tpcInnerParam(), leg.tpcSignal()); + registry.fill(HIST("V0Leg/hTPCNsigmaEl"), leg.tpcInnerParam(), leg.tpcNSigmaEl()); + } // end of leg loop + for (const auto& leg : {pTrack, nTrack}) { + registry.fill(HIST("V0Leg/hXZ"), leg.getZ(), leg.getX()); + registry.fill(HIST("V0Leg/hRelDeltaPt"), leg.getPt(), leg.getPt() * std::sqrt(leg.getSigma1Pt2())); + } // end of leg loop + registry.fill(HIST("V0Leg/hDCAxyz"), posdcaXY, posdcaZ); + registry.fill(HIST("V0Leg/hDCAxyz"), eledcaXY, eledcaZ); + + ROOT::Math::PxPyPzMVector vpos_sv(kfp_pos_DecayVtx.GetPx(), kfp_pos_DecayVtx.GetPy(), kfp_pos_DecayVtx.GetPz(), o2::constants::physics::MassElectron); + ROOT::Math::PxPyPzMVector vele_sv(kfp_ele_DecayVtx.GetPx(), kfp_ele_DecayVtx.GetPy(), kfp_ele_DecayVtx.GetPz(), o2::constants::physics::MassElectron); + ROOT::Math::PxPyPzMVector v0_sv = vpos_sv + vele_sv; + registry.fill(HIST("V0/hMeeSV_Rxy"), rxy, v0_sv.M()); + + v0photonskf(collision.globalIndex(), v0.globalIndex(), v0legs.lastIndex() + 1, v0legs.lastIndex() + 2, + gammaKF_DecayVtx.GetX(), gammaKF_DecayVtx.GetY(), gammaKF_DecayVtx.GetZ(), + gammaKF_PV.GetPx(), gammaKF_PV.GetPy(), gammaKF_PV.GetPz(), + v0_sv.M(), v0photoncandidate.getDcaXYToPV(), v0photoncandidate.getDcaZToPV(), + cospa_kf, cospaXYKF, cospaRZKF, + v0photoncandidate.getPCA(), v0photoncandidate.getAlpha(), v0photoncandidate.getQt(), v0photoncandidate.getChi2NDF()); + v0photonsphivpsi(v0photoncandidate.getPhiV(), v0photoncandidate.getPsiPair()); + + // v0photonskfcov(gammaKF_PV.GetCovariance(9), gammaKF_PV.GetCovariance(14), gammaKF_PV.GetCovariance(20), gammaKF_PV.GetCovariance(13), gammaKF_PV.GetCovariance(19), gammaKF_PV.GetCovariance(18)); + + fillTrackTable(pos, kfp_pos_DecayVtx, posdcaXY, posdcaZ); // positive leg first + fillTrackTable(ele, kfp_ele_DecayVtx, eledcaXY, eledcaZ); // negative leg second + } // end of fill table + } + + Preslice perCollision = o2::aod::v0::collisionId; + std::map, float> pca_map; // (v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) -> pca + std::map, float> cospa_map; // (v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) -> cospa + std::vector vecV0Dedup; // vector with all V0Candidates that is used to sort them by score (see struct V0CandidateHelper for more details of content) + std::vector> stored_v0Ids; // (pos.globalIndex(), ele.globalIndex()) + std::vector> stored_fullv0Ids; // (v0.globalIndex(), collision.globalIndex(), pos.globalIndex(), ele.globalIndex()) + std::unordered_map nv0_map; // map collisionId -> nv0 + + template + void build(TCollisions const& collisions, TV0s const& v0s, TTracks const& tracks, TBCs const&, DedupDiag* diag = nullptr) + { + for (const auto& collision : collisions) { + if constexpr (isMC) { + if (!collision.has_mcCollision()) { + continue; + } + } + + if (!collision.isSelected()) { + continue; + } + + // if constexpr (isTriggerAnalysis) { + // if (collision.triggerMask_raw() == 0) { + // continue; + // } + // } + + nv0_map[collision.globalIndex()] = 0; + + const auto& bc = collision.template foundBC_as(); + initCCDB(bc); + registry.fill(HIST("hCollisionCounter"), 1); + + updateCCDB(bc); // delay update until is needed + + vecV0Dedup.reserve(30000); // rough estimate for number of V0s per DF + const auto& v0s_per_coll = v0s.sliceBy(perCollision, collision.globalIndex()); + // LOGF(info, "n v0 = %d", v0s_per_coll.size()); + for (const auto& v0 : v0s_per_coll) { + // LOGF(info, "collision.globalIndex() = %d, v0.globalIndex() = %d, v0.posTrackId() = %d, v0.negTrackId() = %d", collision.globalIndex(), v0.globalIndex(), v0.posTrackId() , v0.negTrackId()); + fillV0Table(v0, false); + } // end of v0 loop + } // end of collision loop + + stored_v0Ids.reserve(pca_map.size()); // number of photon candidates per DF + stored_fullv0Ids.reserve(pca_map.size()); // number of photon candidates per DF + + // find minimal pca + if (dedup.deduplicationMode == V0DeduplicationMode::Pairwise) { + for (const auto& [key, value] : pca_map) { + auto v0Id = std::get<0>(key); + auto collisionId = std::get<1>(key); + auto posId = std::get<2>(key); + auto eleId = std::get<3>(key); + float v0pca = value; + float cospa = cospa_map[key]; + bool is_closest_v0 = true; + bool is_most_aligned_v0 = true; + + for (const auto& [key_tmp, value_tmp] : pca_map) { + auto v0Id_tmp = std::get<0>(key_tmp); + auto collisionId_tmp = std::get<1>(key_tmp); + auto posId_tmp = std::get<2>(key_tmp); + auto eleId_tmp = std::get<3>(key_tmp); + float v0pca_tmp = value_tmp; + float cospa_tmp = cospa_map[key_tmp]; + + if (v0Id == v0Id_tmp) { // skip exactly the same v0 + continue; + } + + if (collisionId != collisionId_tmp && eleId == eleId_tmp && posId == posId_tmp && cospa < cospa_tmp) { + if (diag != nullptr) { + diag->blockersByKey[key].push_back(key_tmp); + } + is_most_aligned_v0 = false; + break; + } + if ((eleId == eleId_tmp || posId == posId_tmp) && v0pca > v0pca_tmp) { + if (diag != nullptr) { + diag->blockersByKey[key].push_back(key_tmp); + } + is_closest_v0 = false; + break; + } + } // end of pca_map tmp loop + + bool is_stored = std::find(stored_v0Ids.begin(), stored_v0Ids.end(), std::make_pair(posId, eleId)) != stored_v0Ids.end(); + if (is_closest_v0 && is_most_aligned_v0 && !is_stored) { + // auto v0 = v0s.rawIteratorAt(v0Id); + // auto collision = collisions.rawIteratorAt(collisionId); + // auto pos = tracks.rawIteratorAt(posId); + // auto ele = tracks.rawIteratorAt(eleId); + // LOGF(info, "!accept! | collision id = %d | v0id1 = %d , posid1 = %d , eleid1 = %d , pca1 = %f , cospa = %f", collisionId, v0Id, posId, eleId, v0pca, cospa); + + // fillV0Table(v0, true); + stored_v0Ids.emplace_back(std::make_pair(posId, eleId)); + stored_fullv0Ids.emplace_back(std::make_tuple(v0Id, collisionId, posId, eleId)); + nv0_map[collisionId]++; + } + } // end of pca_map loop + // LOGF(info, "pca_map.size() = %d", pca_map.size()); + + } else if (dedup.deduplicationMode == V0DeduplicationMode::KeepAll) { + // Keep-all: Every candidate that survived the quality cuts is stored, including all duplicates + stored_v0Ids.clear(); + stored_fullv0Ids.clear(); + nv0_map.clear(); + for (const auto& v0Cand : vecV0Dedup) { + stored_v0Ids.emplace_back(v0Cand.posID, v0Cand.eleID); + stored_fullv0Ids.emplace_back(v0Cand.v0ID, v0Cand.colID, v0Cand.posID, v0Cand.eleID); + nv0_map[v0Cand.colID]++; + } + std::sort(stored_fullv0Ids.begin(), stored_fullv0Ids.end(), + [](const auto& a, const auto& b) { + return std::get<1>(a) < std::get<1>(b); + }); + } else if (dedup.deduplicationMode == V0DeduplicationMode::GroupMatching) { + const int maxEnum = std::min(dedup.dedupMaxGroupSize.value, 16); // o2-linter: disable=magic-number (subset check of photons) + const int nCand = static_cast(vecV0Dedup.size()); + stored_v0Ids.clear(); + stored_fullv0Ids.clear(); + nv0_map.clear(); + int nGreedyFallback = 0; + + // ---- conflict groups: candidates connected through a shared leg ----- + std::vector parent(nCand); + for (int i = 0; i < nCand; ++i) { + parent[i] = i; + } + auto findRoot = [&parent](int x) { + while (parent[x] != x) { + parent[x] = parent[parent[x]]; // path halving + x = parent[x]; + } + return x; + }; + std::unordered_map firstCandOfTrack; + for (int i = 0; i < nCand; ++i) { + for (const int& trackId : {vecV0Dedup[i].posID, vecV0Dedup[i].eleID}) { + auto [it, inserted] = firstCandOfTrack.try_emplace(trackId, i); + if (!inserted) { + parent[findRoot(i)] = findRoot(it->second); + } + } + } + std::map> groups; + for (int i = 0; i < nCand; ++i) { + groups[findRoot(i)].push_back(i); + } + + // ---- decide each group on its own ---------------------------------- + for (auto& [root, members] : groups) { // o2-linter: disable=const-ref-in-for-loop (members is sorted in place below) + const int nMembers = static_cast(members.size()); + std::vector selected(nMembers, 0); + + // Fix the order inside the group: best score first + std::sort(members.begin(), members.end(), [this](int a, int b) { + if (vecV0Dedup[a].score != vecV0Dedup[b].score) { + return vecV0Dedup[a].score < vecV0Dedup[b].score; + } + return vecV0Dedup[a].v0ID < vecV0Dedup[b].v0ID; + }); + + if (nMembers == 1) { + selected[0] = 1; + } else if (nMembers <= maxEnum) { + + std::unordered_map legBit; + std::vector legMask(nMembers, 0); + for (int k = 0; k < nMembers; ++k) { + for (const int& trackId : {vecV0Dedup[members[k]].posID, vecV0Dedup[members[k]].eleID}) { + const int bit = legBit.try_emplace(trackId, static_cast(legBit.size())).first->second; + legMask[k] |= (1ull << bit); // at most 2 * 16 = 32 legs, fits into 64 bit + } + } + uint32_t bestMask = 0; + int bestCount = 0; + float bestScore = 0.f; + + std::vector bestWithCount(nMembers, -1); + std::vector bestWithScore(nMembers, 0.f); + for (uint32_t mask = 1; mask < (1u << nMembers); ++mask) { + uint64_t usedLegsLocal = 0; + float scoreSum = 0.f; + int count = 0; + bool disjoint = true; + for (int k = 0; k < nMembers; ++k) { + if ((mask & (1u << k)) == 0) { + continue; + } + if ((usedLegsLocal & legMask[k]) != 0) { + disjoint = false; + break; + } + usedLegsLocal |= legMask[k]; + scoreSum += vecV0Dedup[members[k]].score; + ++count; + } + if (!disjoint) { + continue; + } + + if (count > bestCount || (count == bestCount && scoreSum < bestScore)) { + bestCount = count; + bestScore = scoreSum; + bestMask = mask; + } + if (diag != nullptr) { + for (int k = 0; k < nMembers; ++k) { + if ((mask & (1u << k)) == 0) { + continue; + } + if (count > bestWithCount[k] || (count == bestWithCount[k] && scoreSum < bestWithScore[k])) { + bestWithCount[k] = count; + bestWithScore[k] = scoreSum; + } + } + } + } + for (int k = 0; k < nMembers; ++k) { + selected[k] = ((bestMask & (1u << k)) != 0) ? 1 : 0; + if (diag != nullptr && selected[k] == 0 && bestWithCount[k] >= 0) { + const auto& cand = vecV0Dedup[members[k]]; + diag->lossMargin[std::make_tuple(static_cast(cand.v0ID), static_cast(cand.colID), + static_cast(cand.posID), static_cast(cand.eleID))] = + std::make_pair(bestCount - bestWithCount[k], bestWithScore[k] - bestScore); + } + } + } else { + // Too large to enumerate: greedy by score (members is already sorted that way) + ++nGreedyFallback; + std::vector usedTracks; + usedTracks.reserve(2 * nMembers); + for (int k = 0; k < nMembers; ++k) { + const auto& cand = vecV0Dedup[members[k]]; + if (std::find(usedTracks.begin(), usedTracks.end(), cand.posID) != usedTracks.end() || + std::find(usedTracks.begin(), usedTracks.end(), cand.eleID) != usedTracks.end()) { + continue; + } + usedTracks.push_back(cand.posID); + usedTracks.push_back(cand.eleID); + selected[k] = 1; + } + } + + // ---- store the winners, book the blockers of the losers ---------- + for (int k = 0; k < nMembers; ++k) { + const auto& cand = vecV0Dedup[members[k]]; + if (selected[k] != 0) { + stored_v0Ids.emplace_back(cand.posID, cand.eleID); + stored_fullv0Ids.emplace_back(cand.v0ID, cand.colID, cand.posID, cand.eleID); + nv0_map[cand.colID]++; + continue; + } + if (diag == nullptr) { + continue; + } + // all winners that took one leg + const CandKey victimKey = std::make_tuple(static_cast(cand.v0ID), static_cast(cand.colID), + static_cast(cand.posID), static_cast(cand.eleID)); + for (int j = 0; j < nMembers; ++j) { + if (selected[j] == 0) { + continue; + } + const auto& winner = vecV0Dedup[members[j]]; + if (winner.posID == cand.posID || winner.eleID == cand.eleID) { + diag->blockersByKey[victimKey].emplace_back(static_cast(winner.v0ID), static_cast(winner.colID), + static_cast(winner.posID), static_cast(winner.eleID)); + } + } + } + } + + if (nGreedyFallback > 0) { + LOGF(warning, "group matching: %d conflict group(s) larger than dedupMaxGroupSize = %d were solved greedily", nGreedyFallback, maxEnum); + } + + // the table expects candidates ordered by collision + std::sort(stored_fullv0Ids.begin(), stored_fullv0Ids.end(), + [](const auto& a, const auto& b) { + return std::get<1>(a) < std::get<1>(b); + }); + + } else { + // Sort best candidates first, depending on score + std::sort(vecV0Dedup.begin(), vecV0Dedup.end()); + // container to keep track of which electron and positron tracks have already been used + std::vector usedLegs(tracks.size(), false); + std::unordered_map ownerOfLeg; // diagnostics only + stored_v0Ids.clear(); + stored_fullv0Ids.clear(); + nv0_map.clear(); + for (const auto& v0Cand : vecV0Dedup) { + const CandKey candKey = std::make_tuple(static_cast(v0Cand.v0ID), static_cast(v0Cand.colID), + static_cast(v0Cand.posID), static_cast(v0Cand.eleID)); + if (usedLegs[v0Cand.posID] || usedLegs[v0Cand.eleID]) { + if (diag != nullptr) { + // both legs, not just the first one found: a cross-leg fake is usually blocked by + // two different winners, and that is exactly the case being measured here + auto& blockers = diag->blockersByKey[candKey]; + for (const int& legId : {v0Cand.posID, v0Cand.eleID}) { + const auto itOwner = ownerOfLeg.find(legId); + if (itOwner == ownerOfLeg.end()) { + continue; + } + if (std::find(blockers.begin(), blockers.end(), itOwner->second) == blockers.end()) { + blockers.push_back(itOwner->second); // the same winner may hold both legs + } + } + } + continue; + } + usedLegs[v0Cand.posID] = true; + usedLegs[v0Cand.eleID] = true; + if (diag != nullptr) { + ownerOfLeg[v0Cand.posID] = candKey; + ownerOfLeg[v0Cand.eleID] = candKey; + } + stored_v0Ids.emplace_back(v0Cand.posID, v0Cand.eleID); + stored_fullv0Ids.emplace_back(v0Cand.v0ID, v0Cand.colID, v0Cand.posID, v0Cand.eleID); + nv0_map[v0Cand.colID]++; + } + + // sort accepted candidates by collision ID to be compatible with table + std::sort(stored_fullv0Ids.begin(), stored_fullv0Ids.end(), + [](const auto& a, const auto& b) { + return std::get<1>(a) < std::get<1>(b); + }); + + // End of deduplication + } + + if (diag != nullptr) { + diag->snapshot = vecV0Dedup; + diag->stored = stored_fullv0Ids; + } + + std::set skimRejected; + if (skim.minNv0PerCollision > 0 || skim.maxMinvPairPerCollision > 0.f) { + const std::set storedSetSkim(stored_fullv0Ids.begin(), stored_fullv0Ids.end()); + std::unordered_map> candsPerColl; + for (const auto& c : vecV0Dedup) { + if (storedSetSkim.contains(std::make_tuple(static_cast(c.v0ID), static_cast(c.colID), + static_cast(c.posID), static_cast(c.eleID)))) { + candsPerColl[c.colID].push_back(&c); + } + } + for (const auto& [colId, cands] : candsPerColl) { + if (skim.minNv0PerCollision > 0 && static_cast(cands.size()) < skim.minNv0PerCollision) { + skimRejected.insert(colId); + continue; + } + if (skim.maxMinvPairPerCollision > 0.f) { + bool hasLowMPair = false; + for (size_t i = 0; i < cands.size() && !hasLowMPair; ++i) { + for (size_t j = i + 1; j < cands.size(); ++j) { + ROOT::Math::PxPyPzMVector v1(cands[i]->pxAtPV, cands[i]->pyAtPV, cands[i]->pzAtPV, 0.f); + ROOT::Math::PxPyPzMVector v2(cands[j]->pxAtPV, cands[j]->pyAtPV, cands[j]->pzAtPV, 0.f); + if ((v1 + v2).M() < skim.maxMinvPairPerCollision) { + hasLowMPair = true; + break; + } + } + } + if (!hasLowMPair) { + skimRejected.insert(colId); + } + } + } + } + + for (const auto& fullv0Id : stored_fullv0Ids) { + auto v0Id = std::get<0>(fullv0Id); + const auto collisionId = std::get<1>(fullv0Id); + if (skimRejected.contains(collisionId)) { + continue; // collision failed the skim - do not store its photons/legs + } + // auto posId = std::get<2>(fullv0Id); + // auto eleId = std::get<3>(fullv0Id); + // LOGF(info, "!accept! | collision id = %d | v0id = %d , posid = %d , eleid = %d", collisionId, v0Id, posId, eleId); + + auto v0 = v0s.rawIteratorAt(v0Id); + if constexpr (enableFilter) { + auto collision_tmp = v0.template collision_as(); // collision where this v0 belongs. + if (!(collision_tmp.neeuls() >= 1 || collision_tmp.neeuls() + nv0_map[collision_tmp.globalIndex()] >= 2)) { // o2-linter: disable=magic-number (nonsensical default value) + continue; + } + // LOGF(info, "collision_tmp.globalIndex() = %d, collision_tmp.neeuls() = %d, nv0_map = %d", collision_tmp.globalIndex(), collision_tmp.neeuls(), nv0_map[collision_tmp.globalIndex()]); + } + + fillV0Table(v0, true); + } // end of fullv0Id loop + + // for (const auto& collision : collisions) { + // if constexpr (isMC) { + // if (!collision.has_mcCollision()) { + // continue; + // } + // } + // // events_ngpcm(nv0_map[collision.globalIndex()]); + // } // end of collision loop + + pca_map.clear(); + cospa_map.clear(); + nv0_map.clear(); + stored_v0Ids.clear(); + stored_v0Ids.shrink_to_fit(); + stored_fullv0Ids.clear(); + stored_fullv0Ids.shrink_to_fit(); + vecV0Dedup.clear(); + } // end of build + + o2::framework::expressions::Filter v0Filter = o2::aod::v0::v0Type > (uint8_t)0; + using FilteredV0s = o2::soa::Filtered; + + enum PairFate { + kBefore = 0, + kBothSurvive, + kOneLost, + kBothLost, + kLostByCrossFake, + kLostByPartnerFake, + kLostByOtherFake, + kLostByTrue + }; + + void fillTruthPair(int fate, float q, float dEta) + { + switch (fate) { + case kBefore: + registry.fill(HIST("MCDedup/Pairs/before/hQ"), q); + registry.fill(HIST("MCDedup/Pairs/before/hDEta"), dEta); + break; + case kBothSurvive: + registry.fill(HIST("MCDedup/Pairs/bothSurvive/hQ"), q); + registry.fill(HIST("MCDedup/Pairs/bothSurvive/hDEta"), dEta); + break; + case kOneLost: + registry.fill(HIST("MCDedup/Pairs/oneLost/hQ"), q); + registry.fill(HIST("MCDedup/Pairs/oneLost/hDEta"), dEta); + break; + case kBothLost: + registry.fill(HIST("MCDedup/Pairs/bothLost/hQ"), q); + registry.fill(HIST("MCDedup/Pairs/bothLost/hDEta"), dEta); + break; + case kLostByCrossFake: + registry.fill(HIST("MCDedup/Pairs/lostByCrossFake/hQ"), q); + registry.fill(HIST("MCDedup/Pairs/lostByCrossFake/hDEta"), dEta); + break; + case kLostByPartnerFake: + registry.fill(HIST("MCDedup/Pairs/lostByPartnerFake/hQ"), q); + registry.fill(HIST("MCDedup/Pairs/lostByPartnerFake/hDEta"), dEta); + break; + case kLostByOtherFake: + registry.fill(HIST("MCDedup/Pairs/lostByOtherFake/hQ"), q); + registry.fill(HIST("MCDedup/Pairs/lostByOtherFake/hDEta"), dEta); + break; + case kLostByTrue: + registry.fill(HIST("MCDedup/Pairs/lostByTrue/hQ"), q); + registry.fill(HIST("MCDedup/Pairs/lostByTrue/hDEta"), dEta); + break; + default: + break; + } + } + + void fillTruthPairMap(int fate, float dEta, float dPhi, float q) + { + if (!dedup.cfgDedupTruthMaps) { + return; + } + switch (fate) { + case kBefore: + registry.fill(HIST("MCDedup/Pairs/before/hMap"), dEta, dPhi, q); + break; + case kBothSurvive: + registry.fill(HIST("MCDedup/Pairs/bothSurvive/hMap"), dEta, dPhi, q); + break; + case kBothLost: + registry.fill(HIST("MCDedup/Pairs/bothLost/hMap"), dEta, dPhi, q); + break; + case kLostByPartnerFake: + registry.fill(HIST("MCDedup/Pairs/lostByPartnerFake/hMap"), dEta, dPhi, q); + break; + default: + break; + } + } + + template + void fillDedupTruthDiagnostics(TTracks const& tracks, TMCParticles const& mcparticles, DedupDiag const& diag) + { + const int nCand = static_cast(diag.snapshot.size()); + if (nCand == 0) { + return; + } + const std::set storedSet(diag.stored.begin(), diag.stored.end()); + + std::vector key(nCand); + std::vector cls(nCand, static_cast(kV0OtherFake)); + std::vector motherPos(nCand, -1), motherEle(nCand, -1); + std::map indexOfKey; + for (int i = 0; i < nCand; ++i) { + const auto& c = diag.snapshot[i]; + key[i] = std::make_tuple(static_cast(c.v0ID), static_cast(c.colID), + static_cast(c.posID), static_cast(c.eleID)); + indexOfKey[key[i]] = i; + cls[i] = static_cast(classifyV0Truth(tracks.rawIteratorAt(c.posID), tracks.rawIteratorAt(c.eleID), + mcparticles, motherPos[i], motherEle[i])); + registry.fill(HIST("MCDedup/Candidates/hClassStage"), static_cast(cls[i]), 0.f); + if (storedSet.contains(key[i]) > 0) { + registry.fill(HIST("MCDedup/Candidates/hClassStage"), static_cast(cls[i]), 1.f); + } + } + + struct PhotonFate { + bool alive = false; + int best = -1; // best-score candidate, only used for the margin plots + std::vector cands; // all true candidates of this photon + std::set aliveColls; // collisions with a surviving candidate + }; + std::map fate; + for (int i = 0; i < nCand; ++i) { + if (cls[i] != kV0True) { + continue; + } + auto& f = fate[motherPos[i]]; + f.cands.push_back(i); + if (storedSet.contains(key[i]) > 0) { + f.alive = true; + f.aliveColls.insert(std::get<1>(key[i])); + } + if (f.best < 0 || diag.snapshot[i].score < diag.snapshot[f.best].score) { + f.best = i; + } + } + + std::map> blockersOfPhoton; + for (const auto& [mid, f] : fate) { + if (f.alive) { + registry.fill(HIST("MCDedup/Photons/hFate"), 0.f); + continue; + } + auto& blockers = blockersOfPhoton[mid]; + for (const int& ci : f.cands) { + const auto itBlocker = diag.blockersByKey.find(key[ci]); + if (itBlocker == diag.blockersByKey.end()) { + continue; + } + for (const auto& bKey : itBlocker->second) { + const auto itIndex = indexOfKey.find(bKey); + if (itIndex == indexOfKey.end()) { + continue; + } + if (std::find(blockers.begin(), blockers.end(), itIndex->second) == blockers.end()) { + blockers.push_back(itIndex->second); + } + } + } + // Why was it not in the winning set? Take the most favourable of its candidates: the one + // that could have been kept at the smallest cost in cardinality. + int bestDeficit = -1; + float bestExcess = 0.f; + for (const int& ci : f.cands) { + const auto itMargin = diag.lossMargin.find(key[ci]); + if (itMargin == diag.lossMargin.end()) { + continue; + } + if (bestDeficit < 0 || itMargin->second.first < bestDeficit || + (itMargin->second.first == bestDeficit && itMargin->second.second < bestExcess)) { + bestDeficit = itMargin->second.first; + bestExcess = itMargin->second.second; + } + } + if (bestDeficit >= 0) { + registry.fill(HIST("MCDedup/Photons/hLostMargin"), static_cast(bestDeficit), bestExcess); + } + // hVictimBlockerClass below counts one entry per blocker and a victim can have two. + registry.fill(HIST("MCDedup/Photons/hFate"), blockers.empty() ? 2.f : 1.f); + + if (blockers.empty()) { + registry.fill(HIST("MCDedup/Photons/hBlockerClass"), 3.f); // o2-linter: disable=magic-number (bin 3 = no blocker) + continue; + } + for (const int& w : blockers) { + registry.fill(HIST("MCDedup/Photons/hBlockerClass"), static_cast(cls[w])); + } + // margin and PCA comparison relation the best candidate to its blocker + + if (f.best >= 0 && dedup.deduplicationMode.value < static_cast(V0DeduplicationMode::GroupMatching)) { + const int w = blockers.front(); + registry.fill(HIST("MCDedup/Photons/hKillMargin"), diag.snapshot[f.best].score - diag.snapshot[w].score); + registry.fill(HIST("MCDedup/Photons/hVictimVsWinnerPCA"), diag.snapshot[f.best].pca, diag.snapshot[w].pca); + } + } + + // ---- truth pairs, grouped by MC collision ---------------------------- + std::map> mothersByMcColl; + for (const auto& [mid, f] : fate) { + mothersByMcColl[mcparticles.iteratorAt(mid).mcCollisionId()].push_back(mid); + } + constexpr float MaxQTruth = 0.3f; + for (const auto& [mcCol, mids] : mothersByMcColl) { + for (size_t a = 0; a < mids.size(); ++a) { + for (size_t b = a + 1; b < mids.size(); ++b) { + const auto g1 = mcparticles.iteratorAt(mids[a]); + const auto g2 = mcparticles.iteratorAt(mids[b]); + const float e1 = std::hypot(g1.px(), g1.py(), g1.pz()); + const float e2 = std::hypot(g2.px(), g2.py(), g2.pz()); + const float qTrue = std::sqrt(std::max(0.f, 2.f * (e1 * e2 - g1.px() * g2.px() - g1.py() * g2.py() - g1.pz() * g2.pz()))); + if (qTrue > MaxQTruth) { + continue; + } + const float dEta = g1.eta() - g2.eta(); + const float dPhi = RecoDecay::constrainAngle(static_cast(g1.phi() - g2.phi()), -o2::constants::math::PI); + fillTruthPair(kBefore, qTrue, dEta); + fillTruthPairMap(kBefore, dEta, dPhi, qTrue); + + const auto& f1 = fate.at(mids[a]); + const auto& f2 = fate.at(mids[b]); + const int nLost = (f1.alive ? 0 : 1) + (f2.alive ? 0 : 1); + if (nLost == 0) { + fillTruthPair(kBothSurvive, qTrue, dEta); + fillTruthPairMap(kBothSurvive, dEta, dPhi, qTrue); + bool sameColl = false; + for (const auto& c1 : f1.aliveColls) { + sameColl = sameColl || (f2.aliveColls.count(c1) > 0); + } + if (sameColl) { + registry.fill(HIST("MCDedup/Pairs/bothSurviveSameColl/hQ"), qTrue); + } + continue; + } + if (nLost == 1) { + fillTruthPair(kOneLost, qTrue, dEta); + } else { + fillTruthPair(kBothLost, qTrue, dEta); + fillTruthPairMap(kBothLost, dEta, dPhi, qTrue); + } + + // Reason for photon building failure + bool byCross = false, byPartner = false, byOther = false, byTrue = false; + auto attribute = [&](int64_t victim, int64_t partner) { + if (fate.at(victim).alive) { + return; + } + const auto itB = blockersOfPhoton.find(victim); + if (itB == blockersOfPhoton.end()) { + return; + } + for (const int& w : itB->second) { + if (cls[w] == kV0CrossLegFake) { + byCross = true; + // partner fake = a cross-leg fake using a leg of the other photon + if (motherPos[w] == partner || motherEle[w] == partner) { + byPartner = true; + } + } else if (cls[w] == kV0OtherFake) { + byOther = true; + } else if (cls[w] == kV0True) { + byTrue = true; // real photon against real photon + } + } + }; + attribute(mids[a], mids[b]); + attribute(mids[b], mids[a]); + if (byCross) { + fillTruthPair(kLostByCrossFake, qTrue, dEta); + } + if (byPartner) { + fillTruthPair(kLostByPartnerFake, qTrue, dEta); + fillTruthPairMap(kLostByPartnerFake, dEta, dPhi, qTrue); + } + if (byOther) { + fillTruthPair(kLostByOtherFake, qTrue, dEta); + } + if (byTrue) { + fillTruthPair(kLostByTrue, qTrue, dEta); + } + } + } + } + } + + void processRec(MyCollisions const& collisions, FilteredV0s const& v0s, MyTracksIU const& tracks, MyBCs const& bcs) + { + build(collisions, v0s, tracks, bcs); + } + PROCESS_SWITCH(PhotonConversionBuilder, processRec, "process reconstructed info for data", true); + + // void processRec_SWT(MyCollisionsWithSWT const& collisions, FilteredV0s const& v0s, MyTracksIU const& tracks, MyBCs const& bcs) + // { + // build(collisions, v0s, tracks, bcs); + // } + // PROCESS_SWITCH(PhotonConversionBuilder, processRec_SWT, "process reconstructed info for data", false); + + void processMC(MyCollisionsMC const& collisions, FilteredV0s const& v0s, MyTracksIUMC const& tracks, + MyBCs const& bcs, o2::aod::McParticles const& mcparticles) + { + DedupDiag diag; + build(collisions, v0s, tracks, bcs, &diag); + fillDedupTruthDiagnostics(tracks, mcparticles, diag); + } + PROCESS_SWITCH(PhotonConversionBuilder, processMC, "process reconstructed info for MC", false); + + void processRec_OnlyIfDielectron(o2::soa::Join const& collisions, FilteredV0s const& v0s, MyTracksIU const& tracks, MyBCs const& bcs) + { + build(collisions, v0s, tracks, bcs); + } + PROCESS_SWITCH(PhotonConversionBuilder, processRec_OnlyIfDielectron, "process reconstructed info for data", false); + + // void processRec_SWT_OnlyIfDielectron(soa::Join const& collisions, FilteredV0s const& v0s, MyTracksIU const& tracks, MyBCs const& bcs) + // { + // build(collisions, v0s, tracks, bcs); + // } + // PROCESS_SWITCH(PhotonConversionBuilder, processRec_SWT_OnlyIfDielectron, "process reconstructed info for data", false); +}; + +#endif // PWGEM_PHOTONMESON_TABLEPRODUCER_PHOTONCONVERSIONBUILDER_H_ diff --git a/PWGEM/PhotonMeson/TableProducer/photonconversionbuilderTmpTable.cxx b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilderTmpTable.cxx new file mode 100644 index 00000000000..6b7927b6340 --- /dev/null +++ b/PWGEM/PhotonMeson/TableProducer/photonconversionbuilderTmpTable.cxx @@ -0,0 +1,23 @@ +// Copyright 2019-2025 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. +// + +/// \file photonconversionbuilder.ch +/// \brief this task produces photon data table with KFParticle. +/// \author Daiki Sekihata , Tokyo + +#include "PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.h" + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& context) +{ + return o2::framework::WorkflowSpec{ + adaptAnalysisTask>(context, o2::framework::TaskName{"photon-conversion-builder-tmptable"})}; +} diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerDalitzEvents.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerDalitzEvents.cxx new file mode 100644 index 00000000000..e038b916848 --- /dev/null +++ b/PWGEM/PhotonMeson/TableProducer/skimmerDalitzEvents.cxx @@ -0,0 +1,161 @@ +// 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. + +/// \file skimmerDalitzEvents.cxx +/// \brief write tables for photons and electrons for dalitz decay +/// \author josuha.konig@cern.ch + +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" + +#include "Common/DataModel/EventSelection.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::common::core; + +using MyCollisions = soa::Join; +using MyElectrons = o2::aod::EMPrimaryElectronsFromDalitzTmp; +using MyV0Photons = o2::soa::Join; +using MyV0PhotonsLegs = o2::soa::Join; + +using MyElectronsMC = o2::soa::Join; +using MyV0PhotonsLegsMC = o2::soa::Join; + +struct skimmerDalitzEvents { + + SliceCache cache; + PresliceUnsorted perCollisionEl = aod::emprimaryelectron::collisionId; + PresliceUnsorted perCol_pcm = o2::aod::v0photonkf::collisionId; + PresliceUnsorted perCol_legs = o2::aod::v0leg::collisionId; + PresliceUnsorted perId_legs = o2::aod::v0leg::trackId; + + Produces v0photonskf; + Produces v0legs; + Produces v0legsXYZ; + Produces v0legsDeDxMC; + Produces v0photonsphivpsi; + + Produces emprimaryelectrons; + Produces emprimaryelectronsDeDxMC; + + Configurable minNElecCand{"minNElecCand", 2, "minimum number of electrons/positron candidates in one event"}; + Configurable minNGammaCand{"minNGammaCand", 1, "minimum number of V0 photon candidates in one event"}; + + // ---------- for data ---------- + template + void coreProcess(MyCollisions const& collisions, TElectrons const& emPrimaryElecTmp, TV0Photons const& v0photonskfTmp, TV0Legs const& v0LegsTmp) + { + + auto leg = v0LegsTmp.begin(); + for (const auto& collision : collisions) { + // get electrons for current collision + auto tracks = emPrimaryElecTmp.sliceBy(perCollisionEl, collision.globalIndex()); + + // check that there are at least minNElecCand in the collision + if (tracks.size() < minNElecCand) { + continue; + } + + // get photons for current collision + auto photonskf = v0photonskfTmp.sliceBy(perCol_pcm, collision.globalIndex()); + + // check that there are at least minNGammaCand in the collision + if (photonskf.size() < minNGammaCand) { + continue; + } + + // Write electron tracks + for (const auto& track : tracks) { + emprimaryelectrons(track.collisionId(), track.trackId(), track.sign(), + track.pt(), track.eta(), track.phi(), + track.dcaXY(), track.dcaZ(), track.cYY(), track.cZY(), track.cZZ(), + track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), track.tpcNClsShared(), + track.tpcChi2NCl(), track.tpcInnerParam(), + track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaPi(), + track.beta(), track.tofNSigmaEl(), + track.itsClusterSizes(), track.itsChi2NCl(), track.tofChi2(), track.detectorMap()); + + if constexpr (isMC) { + emprimaryelectronsDeDxMC( + track.mcTunedTPCSignal()); + } + } + + for (const auto& v0 : photonskf) { + v0photonskf(v0.collisionId(), v0.v0Id(), v0legs.lastIndex() + 1, v0legs.lastIndex() + 2, // o2-linter: disable=magic-number (indexing for v0 leg table) + v0.vx(), v0.vy(), v0.vz(), + v0.px(), v0.py(), v0.pz(), + v0.mGamma(), + v0.dcaXYtopv(), v0.dcaZtopv(), + v0.cospa(), v0.cospaXY(), v0.cospaRZ(), v0.pca(), + v0.alpha(), v0.qtarm(), + v0.chiSquareNDF()); + + v0photonsphivpsi( + v0.phiv(), v0.psipair()); + + for (const auto& legId : {v0.posTrackId(), v0.negTrackId()}) { + if (legId < 0 || legId >= static_cast(v0LegsTmp.size())) { + LOG(warning) << "legID " << legId << " is outside of range of v0legs table with size " << static_cast(v0LegsTmp.size()); + continue; + } + leg.setCursor(legId); + v0legs( + leg.collisionId(), leg.trackId(), leg.sign(), + leg.px(), leg.py(), leg.pz(), + leg.dcaXY(), leg.dcaZ(), + leg.tpcNClsFindable(), leg.tpcNClsFindableMinusFound(), leg.tpcNClsFindableMinusCrossedRows(), leg.tpcNClsShared(), + leg.tpcChi2NCl(), leg.tpcInnerParam(), + leg.tpcSignal(), leg.tpcNSigmaEl(), leg.tpcNSigmaPi(), + leg.itsClusterSizes(), leg.itsChi2NCl(), leg.detectorMap()); + + v0legsXYZ( + leg.x(), leg.y(), leg.z()); + + if constexpr (isMC) { + v0legsDeDxMC( + leg.mcTunedTPCSignal()); + } + } + } + } + } + + void processRec(MyCollisions const& collisions, MyElectrons const& emPrimaryElecTmp, MyV0Photons const& v0photonskfTmp, MyV0PhotonsLegs const& v0LegsTmp) + { + coreProcess(collisions, emPrimaryElecTmp, v0photonskfTmp, v0LegsTmp); + } + + void processMC(MyCollisions const& collisions, MyElectronsMC const& emPrimaryElecTmp, MyV0Photons const& v0photonskfTmp, MyV0PhotonsLegsMC const& v0LegsTmp) + { + coreProcess(collisions, emPrimaryElecTmp, v0photonskfTmp, v0LegsTmp); + } + + PROCESS_SWITCH(skimmerDalitzEvents, processRec, "process reconstructed info only", false); // data + PROCESS_SWITCH(skimmerDalitzEvents, processMC, "process reconstructed and MC info", false); // MC +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& context) +{ + return WorkflowSpec{ + adaptAnalysisTask(context, TaskName{"skimmer-dalitz-events"})}; +} diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx index e82c3284c4c..32d3d7c3407 100644 --- a/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx +++ b/PWGEM/PhotonMeson/TableProducer/skimmerGammaCalo.cxx @@ -14,6 +14,7 @@ /// \author marvin.hemmer@cern.ch /// dependencies: emcal-correction-task +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/emcalHistoDefinitions.h" @@ -74,7 +75,7 @@ struct SkimmerGammaCalo { Configurable minE{"minE", 0.5, "Minimum energy for energy cut"}; Configurable maxE{"maxE", std::numeric_limits::max(), "Maximum energy for energy cut"}; Configurable removeExotic{"removeExotic", false, "Flag to enable the removal of exotic clusters."}; - Configurable> clusterDefinitions{"clusterDefinitions", {0, 1, 2, 10, 11, 12, 13, 20, 21, 22, 30, 40, 41, 42, 43, 44, 45}, "Cluster definitions to be accepted (e.g. 13 for kV3MostSplitLowSeed)"}; + Configurable> clusterDefinitions{"clusterDefinitions", {0, 1, 2, 10, 11, 12, 13, 20, 21, 22, 30, 40, 41, 42, 43, 44, 45}, "Cluster definitions storageID to be accepted (see O2Physics/PWGJE/DataModel/EMCALClusters.h for the storageID)"}; Configurable maxdEta{"maxdEta", 0.1, "Set a maximum difference in eta for tracks and cluster to still count as matched"}; Configurable maxdPhi{"maxdPhi", 0.1, "Set a maximum difference in phi for tracks and cluster to still count as matched"}; Configurable maxEoverP{"maxEoverP", 1.5, "Set a maximum for cluster E / track p for track matching."}; @@ -92,8 +93,8 @@ struct SkimmerGammaCalo { << "cluster table and must not be enabled together — this doubles MinClusters rows " << "relative to EMCClusterMCLabels_001."; } - historeg.add("DefinitionIn", "Cluster definitions before cuts;#bf{Cluster definition};#bf{#it{N}_{clusters}}", HistType::kTH1F, {{51, -0.5, 50.5}}); - historeg.add("DefinitionOut", "Cluster definitions after cuts;#bf{Cluster definition};#bf{#it{N}_{clusters}}", HistType::kTH1F, {{51, -0.5, 50.5}}); + historeg.add("DefinitionIn", "Cluster definitions before cuts;#bf{Cluster definition};#bf{#it{N}_{clusters}}", HistType::kTH1F, {{53, -0.5, 52.5}}); + historeg.add("DefinitionOut", "Cluster definitions after cuts;#bf{Cluster definition};#bf{#it{N}_{clusters}}", HistType::kTH1F, {{53, -0.5, 52.5}}); historeg.add("EIn", "Energy of clusters before cuts", gHistoSpecClusterE); historeg.add("EOut", "Energy of clusters after cuts", gHistoSpecClusterE); historeg.add("MTEtaPhiBeforeTM", "Eta phi of matched tracks before TM cuts", gHistoSpecClusterTMdEtadPhi); @@ -311,19 +312,19 @@ struct SkimmerGammaCalo { } } - void processRec(soa::Join::iterator const& collision, aod::EMCALClusters const& emcclusters, aod::EMCALClusterCells const& emcclustercells, aod::EMCALMatchedTracks const& emcmatchedtracks, aod::FullTracks const& tracks) + void processRec(soa::Join::iterator const& collision, aod::EMCALClusters const& emcclusters, aod::EMCALClusterCells const& emcclustercells, aod::EMCALMatchedTracks const& emcmatchedtracks, aod::FullTracks const& tracks) { runAnalysis(collision, emcclusters, emcclustercells, emcmatchedtracks, tracks); } PROCESS_SWITCH(SkimmerGammaCalo, processRec, "process only reconstructed info", true); - void processRecWithSecondaries(soa::Join::iterator const& collision, aod::EMCALClusters const& emcclusters, aod::EMCALClusterCells const& emcclustercells, aod::EMCALMatchedTracks const& emcmatchedtracks, aod::FullTracks const& tracks, aod::EMCMatchSecs const& emcmatchedsecondaries) + void processRecWithSecondaries(soa::Join::iterator const& collision, aod::EMCALClusters const& emcclusters, aod::EMCALClusterCells const& emcclustercells, aod::EMCALMatchedTracks const& emcmatchedtracks, aod::FullTracks const& tracks, aod::EMCMatchSecs const& emcmatchedsecondaries) { runAnalysis(collision, emcclusters, emcclustercells, emcmatchedtracks, tracks, emcmatchedsecondaries); } PROCESS_SWITCH(SkimmerGammaCalo, processRecWithSecondaries, "process reconstructed info with secondary track matching.", false); - void processRecMC(soa::Join::iterator const& collision, + void processRecMC(soa::Join::iterator const& collision, soa::Join const& emcclusters, aod::EMCALClusterCells const& emcclustercells, aod::EMCALMatchedTracks const& emcmatchedtracks, aod::FullTracks const& tracks) @@ -332,7 +333,7 @@ struct SkimmerGammaCalo { } PROCESS_SWITCH(SkimmerGammaCalo, processRecMC, "process reconstructed info + MC labels at once", false); - void processRecMCWithSecondaries(soa::Join::iterator const& collision, + void processRecMCWithSecondaries(soa::Join::iterator const& collision, soa::Join const& emcclusters, aod::EMCALClusterCells const& emcclustercells, aod::EMCALMatchedTracks const& emcmatchedtracks, aod::FullTracks const& tracks, aod::EMCMatchSecs const& emcmatchedsecondaries) diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.cxx index 215f4a29f49..97fe86ece34 100644 --- a/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.cxx +++ b/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.cxx @@ -10,882 +10,19 @@ // or submit itself to any jurisdiction. /// \file skimmerPrimaryElectronFromDalitzEE.cxx -/// \brief write relevant information about primary electrons. -/// \author daiki.sekihata@cern.ch +/// \brief write electrons for Dalitz into new table +/// \author lgansbartl@stud.uni-frankfurt.de -#include "PWGEM/Dilepton/Utils/PairUtilities.h" -#include "PWGEM/PhotonMeson/DataModel/EventTables.h" -#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.h" -#include "Common/Core/PID/PIDTOFParamService.h" -#include "Common/DataModel/CollisionAssociationTables.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/PIDResponseTOF.h" -#include "Common/DataModel/PIDResponseTPC.h" -#include "Common/DataModel/TrackSelectionTables.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace o2; -using namespace o2::soa; using namespace o2::framework; +using namespace o2::aod; using namespace o2::framework::expressions; -using namespace o2::constants::physics; - -using MyCollisions = soa::Join; -using MyCollisionsWithSWT = soa::Join; -using MyBCs = soa::Join; - -using MyCollisionsMC = soa::Join; -using MyTracks = soa::Join; -using MyTrack = MyTracks::iterator; -using MyTracksMC = soa::Join; -using MyTrackMC = MyTracksMC::iterator; - -namespace o2::aod -{ -namespace pwgem::pm::recalculatedtofpid -{ -DECLARE_SOA_COLUMN(BetaRecalculated, betaRecalculated, float); -DECLARE_SOA_COLUMN(TOFNSigmaElRecalculated, tofNSigmaElRecalculated, float); -} // namespace pwgem::pm::recalculatedtofpid - -DECLARE_SOA_TABLE(EMTOFNSigmas, "AOD", "EMTOFNSIGMA", // make std::map in your tasks later. // Don't store this table in the derived data. - o2::aod::emprimaryelectron::CollisionId, o2::aod::emprimaryelectron::TrackId, - o2::aod::pwgem::pm::recalculatedtofpid::BetaRecalculated, o2::aod::pwgem::pm::recalculatedtofpid::TOFNSigmaElRecalculated); - -using EMTOFNSigma = EMTOFNSigmas::iterator; -} // namespace o2::aod - -struct skimmerPrimaryElectronFromDalitzEE { - SliceCache cache; - Preslice perCol = o2::aod::track::collisionId; - PresliceOptional perTracksCollision = aod::track::collisionId; - Preslice perCol_pcm = o2::aod::v0photonkf::collisionId; - Preslice trackIndicesPerCollision = aod::track_association::collisionId; - Produces emprimaryelectrons; - Produces emprimaryelectronsDeDxMC; - Service mTOFResponse{}; - - Produces emtofs; - - // Configurables - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; - - // Operation and minimisation criteria - Configurable dBzInput{"dBzInput", -999, "bz field in kG, -999 is automatic"}; - Configurable min_ncluster_tpc{"min_ncluster_tpc", 0, "min ncluster tpc"}; // o2-linter: disable=name/function-variable (renaming configs would mess up hyperloop) - Configurable mincrossedrows{"mincrossedrows", 70, "min. crossed rows"}; - Configurable min_tpc_cr_findable_ratio{"min_tpc_cr_findable_ratio", 0.8, "min. TPC Ncr/Nf ratio"}; - Configurable max_frac_shared_clusters_tpc{"max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; - Configurable min_ncluster_its{"min_ncluster_its", 4, "min ncluster its"}; - Configurable min_ncluster_itsib{"min_ncluster_itsib", 1, "min ncluster itsib"}; - Configurable minchi2tpc{"minchi2tpc", 0.0, "min. chi2/NclsTPC"}; - Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max. chi2/NclsTPC"}; - Configurable minchi2its{"minchi2its", 0.0, "min. chi2/NclsITS"}; - Configurable maxchi2its{"maxchi2its", 36.0, "max. chi2/NclsITS"}; - Configurable minpt{"minpt", 0.05, "min pt for ITS-TPC track"}; - Configurable maxeta{"maxeta", 2.0, "max eta acceptance"}; - Configurable dca_xy_max{"dca_xy_max", 1, "max DCAxy in cm"}; // o2-linter: disable=name/function-variable (renaming configs would mess up hyperloop) - Configurable dca_z_max{"dca_z_max", 1, "max DCAz in cm"}; // o2-linter: disable=name/function-variable (renaming configs would mess up hyperloop) - Configurable dca_3d_sigma_max{"dca_3d_sigma_max", 2, "max DCA 3D in sigma"}; // o2-linter: disable=name/function-variable (renaming configs would mess up hyperloop) - Configurable minTPCNsigmaEl{"minTPCNsigmaEl", -2.5, "min. TPC n sigma for electron inclusion"}; - Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", +3.5, "max. TPC n sigma for electron inclusion"}; - Configurable maxTPCNsigmaPi{"maxTPCNsigmaPi", 0.0, "max. TPC n sigma for pion exclusion"}; - Configurable minTPCNsigmaPi{"minTPCNsigmaPi", 0.0, "min. TPC n sigma for pion exclusion"}; - Configurable minTOFNsigmaEl{"minTOFNsigmaEl", -3.5, "min. TOF n sigma for electron inclusion"}; - Configurable maxTOFNsigmaEl{"maxTOFNsigmaEl", +3.5, "max. TOF n sigma for electron inclusion"}; - Configurable minTPCNsigmaKa{"minTPCNsigmaKa", -2.5, "min. TPC n sigma for kaon exclusion"}; - Configurable maxTPCNsigmaKa{"maxTPCNsigmaKa", 2.5, "max. TPC n sigma for kaon exclusion"}; - Configurable minTPCNsigmaPr{"minTPCNsigmaPr", -2.5, "min. TPC n sigma for proton exclusion"}; - Configurable maxTPCNsigmaPr{"maxTPCNsigmaPr", 2.5, "max. TPC n sigma for proton exclusion"}; - Configurable requireTOF{"requireTOF", false, "require TOF hit"}; - Configurable min_pin_for_pion_rejection{"min_pin_for_pion_rejection", 0.0, "pion rejection is applied above this pin"}; // this is used only in TOFreq - Configurable max_pin_for_pion_rejection{"max_pin_for_pion_rejection", 0.5, "pion rejection is applied below this pin"}; - Configurable maxMee{"maxMee", 0.04, "max. mee to store dalitz ee pairs"}; - Configurable fillLS{"fillLS", true, "flag to fill LS histograms for QA"}; - Configurable fillWithPairs{"fillWithPairs", false, "flag to fill table based on pair information"}; - Configurable includeITSsa{"includeITSsa", false, "Flag to include ITSsa tracks"}; - Configurable maxpt_itssa{"maxpt_itssa", 0.15, "max pt for ITSsa track"}; // o2-linter: disable=name/function-variable (renaming configs would mess up hyperloop) - Configurable maxMeanITSClusterSize{"maxMeanITSClusterSize", 16, "max x cos(lambda)"}; - Configurable slope{"slope", 0.0185, "slope for m vs. phiv"}; - Configurable intercept{"intercept", -0.0380, "intercept for m vs. phiv"}; - Configurable useTOFNSigmaDeltaBC{"useTOFNSigmaDeltaBC", false, "Flag to shift delta BC for TOF n sigma (only with TTCA)"}; - Configurable storeOnlyTrueElectronMC{"storeOnlyTrueElectronMC", false, "Flag to store only true electron in MC"}; - - HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; - static constexpr std::array DileptonSigns = {"uls/", "lspp/", "lsmm/"}; - - int mRunNumber = 0; - float dBz = 0.; - Service ccdb{}; - o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; - o2::dataformats::VertexBase mVtx; - - void init(InitContext& initContext) - { - // if (doprocessRec && doprocessRec_SWT) { - // LOGF(fatal, "Cannot enable doprocessRec and doprocessRec_SWT at the same time. Please choose one."); - // } - - mRunNumber = 0; - dBz = 0; - - ccdb->setURL(ccdburl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(false); - - LOGF(info, "before TOF initSetup"); - mTOFResponse->initSetup(ccdb, initContext); - LOGF(info, "after TOF initSetup"); - - fRegistry.add("Track/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); - fRegistry.add("Track/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, o2::constants::math::TwoPI}, {400, -2.0f, 2.0f}}, false); - fRegistry.add("Track/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{400, -20, 20}}, false); - fRegistry.add("Track/hRelDeltaPt", "pT resolution;p_{T} (GeV/c);#Deltap_{T}/p_{T}", kTH2F, {{1000, 0, 10}, {100, 0, 0.1}}, false); - fRegistry.add("Track/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -1.0f, 1.0f}, {200, -1.0f, 1.0f}}, false); - fRegistry.add("Track/hDCAxy_Pt", "DCA_{xy} vs. pT;p_{T} (GeV/c);DCA_{xy} (cm)", kTH2F, {{200, 0, 10}, {200, -1, 1}}, false); - fRegistry.add("Track/hDCAz_Pt", "DCA_{z} vs. pT;p_{T} (GeV/c);DCA_{z} (cm)", kTH2F, {{200, 0, 10}, {200, -1, 1}}, false); - fRegistry.add("Track/hDCAxyzSigma", "DCA xy vs. z;DCA_{xy} (#sigma);DCA_{z} (#sigma)", kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); - fRegistry.add("Track/hDCAxyRes_Pt", "DCA_{xy} resolution vs. pT;p_{T} (GeV/c);DCA_{xy} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 500}}, false); - fRegistry.add("Track/hDCAzRes_Pt", "DCA_{z} resolution vs. pT;p_{T} (GeV/c);DCA_{z} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 500}}, false); - - // TPC - fRegistry.add("Track/hNclsTPC", "number of TPC clusters", kTH1F, {{161, -0.5, 160.5}}, false); - fRegistry.add("Track/hNcrTPC", "number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, false); - fRegistry.add("Track/hChi2TPC", "chi2/number of TPC clusters", kTH1F, {{100, 0, 10}}, false); - fRegistry.add("Track/hTPCNcr2Nf", "TPC Ncr/Nfindable", kTH1F, {{200, 0, 2}}, false); - fRegistry.add("Track/hTPCNcls2Nf", "TPC Ncls/Nfindable", kTH1F, {{200, 0, 2}}, false); - fRegistry.add("Track/hTPCNclsShared", "TPC Ncls shared/Ncls;p_{T} (GeV/c);N_{cls}^{shared}/N_{cls} in TPC", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); - fRegistry.add("Track/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); - fRegistry.add("Track/hTPCdEdxMC", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); - fRegistry.add("Track/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); - fRegistry.add("Track/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); - - // ITS - fRegistry.add("Track/hNclsITS", "number of ITS clusters", kTH1F, {{8, -0.5, 7.5}}, false); - fRegistry.add("Track/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{400, 0, 40}}, false); - fRegistry.add("Track/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); - fRegistry.add("Track/hMeanClusterSizeITS", "mean cluster size ITS;p_{pv} (GeV/c); #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); - fRegistry.add("Track/hMeanClusterSizeITSib", "mean cluster size ITSib;p_{pv} (GeV/c); #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); - fRegistry.add("Track/hMeanClusterSizeITSob", "mean cluster size ITSob;p_{pv} (GeV/c); #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); - - // TOF - fRegistry.add("Track/hChi2TOF", "chi2 of TOF", kTH1F, {{100, 0, 10}}, false); - fRegistry.add("Track/hTOFbeta", "TOF beta;p_{pv} (GeV/c);#beta", kTH2F, {{1000, 0, 10}, {240, 0, 1.2}}, false); - fRegistry.add("Track/hTOFNsigmaEl", "TOF n sigma el;p_{pv} (GeV/c);n #sigma_{e}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); - fRegistry.add("Track/hTOFNsigmaPi", "TOF n sigma pi;p_{pv} (GeV/c);n #sigma_{#pi}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); - - // pair - fRegistry.add("Pair/uls/hTrackMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{100, 0, 0.1}, {200, 0, 2}}, false); - fRegistry.add("Pair/uls/hCheckEMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{100, 0, 0.1}, {200, 0, 2}}, false); - fRegistry.add("Pair/uls/hMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{100, 0, 0.1}, {200, 0, 2}}, false); - fRegistry.add("Pair/uls/hMCutMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{100, 0, 0.1}, {200, 0, 2}}, false); - fRegistry.add("Pair/uls/hMPhiCutMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{100, 0, 0.1}, {200, 0, 2}}, false); - - fRegistry.add("Pair/uls/hTrackMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{180, 0, o2::constants::math::PI}, {100, 0, 0.1}}, false); - fRegistry.add("Pair/uls/hCheckEMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{180, 0, o2::constants::math::PI}, {100, 0, 0.1}}, false); - fRegistry.add("Pair/uls/hMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{180, 0, o2::constants::math::PI}, {100, 0, 0.1}}, false); - fRegistry.add("Pair/uls/hMCutMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{180, 0, o2::constants::math::PI}, {100, 0, 0.1}}, false); - fRegistry.add("Pair/uls/hMPhiCutMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{180, 0, o2::constants::math::PI}, {100, 0, 0.1}}, false); - - fRegistry.addClone("Pair/uls/", "Pair/lspp/"); - fRegistry.addClone("Pair/uls/", "Pair/lsmm/"); - } - - void initCCDB(MyBCs::iterator const& bc) - { - if (mRunNumber == bc.runNumber()) { - return; - } - mRunNumber = bc.runNumber(); - // In case override, don't proceed, please - no CCDB access required - if (dBzInput > -990) { // o2-linter: disable=magic-number (check against some default number) - dBz = dBzInput; - o2::parameters::GRPMagField grpmag; - if (std::fabs(dBz) > 1e-5) { // o2-linter: disable=magic-number (check against some default number) - grpmag.setL3Current(30000.f / (dBz / 5.0f)); // o2-linter: disable=magic-number (override value) - } - o2::base::Propagator::initFieldFromGRP(&grpmag); - return; - } - - auto run3grpTimestamp = bc.timestamp(); - - dBz = bc.grpMagField().getNominalL3Field(); - LOG(info) << "Retrieved GRP for timestamp " << run3grpTimestamp << " with magnetic field of " << dBz << " kZG"; - } - - template - void calculateTOFNSigmaWithReassociation(TCollisions const& collisions, TBCs const&, TTracks const& tracks, TTrackAssoc const& trackIndices) - { - if (useTOFNSigmaDeltaBC) { - if constexpr (withTTCA) { - for (const auto& collision : collisions) { - if (mapCollisionTime.find(collision.globalIndex()) == mapCollisionTime.end()) { - continue; - } - auto bcCollision = collision.template bc_as(); - auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); - for (const auto& trackId : trackIdsThisCollision) { - auto track = trackId.template track_as(); - if (!track.hasITS() || !track.hasTPC()) { // apply only minimal cut - continue; - } - - if (track.hasTOF() && track.has_collision()) { // TTCA may use orphan tracks. - auto bcTrack = track.template collision_as().template bc_as(); - float tofNSigmaEl = mTOFResponse->nSigma(track.tofSignalInAnotherBC(bcTrack.globalBC(), bcCollision.globalBC()), track.tofExpMom(), track.length(), track.p(), track.eta(), mapCollisionTime[collision.globalIndex()], mapCollisionTimeError[collision.globalIndex()]); - float beta = track.length() / (track.tofSignalInAnotherBC(bcTrack.globalBC(), bcCollision.globalBC()) - mapCollisionTime[collision.globalIndex()]) / (o2::constants::physics::LightSpeedCm2S * 1e-12); - mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = tofNSigmaEl; - mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = beta; - emtofs(collision.globalIndex(), track.globalIndex(), mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); - } else { - mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.tofNSigmaEl(); - mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.beta(); - emtofs(collision.globalIndex(), track.globalIndex(), mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); - } - } // end of track loop - } // end of collision loop - } else { - for (const auto& collision : collisions) { - auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); - for (const auto& track : tracks_per_coll) { - if (!track.hasITS() || !track.hasTPC()) { // apply only minimal cut - continue; - } - mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.tofNSigmaEl(); - mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.beta(); - emtofs(collision.globalIndex(), track.globalIndex(), mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); - } - } // end of track loop - } // end of collision loop - } else { - if constexpr (withTTCA) { - for (const auto& collision : collisions) { - auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); - for (const auto& trackId : trackIdsThisCollision) { - auto track = trackId.template track_as(); - if (!track.hasITS() || !track.hasTPC()) { // apply only minimal cut - continue; - } - mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.tofNSigmaEl(); - mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.beta(); - emtofs(collision.globalIndex(), track.globalIndex(), mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); - } // end of track loop - } // end of collision loop - } else { - for (const auto& collision : collisions) { - auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); - for (const auto& track : tracks_per_coll) { - if (!track.hasITS() || !track.hasTPC()) { // apply only minimal cut - continue; - } - mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.tofNSigmaEl(); - mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.beta(); - emtofs(collision.globalIndex(), track.globalIndex(), mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); - } - } // end of track loop - } // end of collision loop - } - } - - template - bool checkTrack(TCollision const& collision, TTrack const& track) - { - if constexpr (isMC) { - if (!track.has_mcParticle()) { - return false; - } - if (storeOnlyTrueElectronMC) { - const auto& mcParticle = track.template mcParticle_as(); - if (std::abs(mcParticle.pdgCode()) != 11) { - return false; - } - } - } - - float tofNSigmaEl = mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]; - if (requireTOF && !(track.hasTOF() && std::fabs(tofNSigmaEl) < maxTOFNsigmaEl)) { - return false; - } - - if (!track.hasITS()) { - return false; - } - - if (track.itsChi2NCl() < minchi2its || maxchi2its < track.itsChi2NCl()) { - return false; - } - - if (track.itsNCls() < min_ncluster_its) { - return false; - } - if (track.itsNClsInnerBarrel() < min_ncluster_itsib) { - return false; - } - - if (!includeITSsa && !track.hasTPC()) { - return false; - } - - if (track.hasTPC()) { - if (track.tpcChi2NCl() < minchi2tpc || maxchi2tpc < track.tpcChi2NCl()) { - return false; - } - - if (track.tpcNClsFound() < min_ncluster_tpc) { - return false; - } - - if (track.tpcNClsCrossedRows() < mincrossedrows) { - return false; - } - - if (track.tpcCrossedRowsOverFindableCls() < min_tpc_cr_findable_ratio) { - return false; - } - - if (track.tpcFractionSharedCls() > max_frac_shared_clusters_tpc) { - return false; - } - } - - o2::dataformats::DCA mDcaInfoCov; // for Track association - mDcaInfoCov.set(999, 999, 999, 999, 999); - auto trackParCov = getTrackParCov(track); - trackParCov.setPID(o2::track::PID::Electron); - mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); - mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); - bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); - if (!isPropOK) { - return false; - } - float dcaXY = mDcaInfoCov.getY(); - float dcaZ = mDcaInfoCov.getZ(); - - if (std::fabs(dcaXY) > dca_xy_max || std::fabs(dcaZ) > dca_z_max) { - return false; - } - - float dca3D = 999.f; - float det = trackParCov.getSigmaY2() * trackParCov.getSigmaZ2() - trackParCov.getSigmaZY() * trackParCov.getSigmaZY(); - if (det < 0) { - dca3D = 999.f; - } else { - float chi2 = (dcaXY * dcaXY * trackParCov.getSigmaZ2() + dcaZ * dcaZ * trackParCov.getSigmaY2() - 2. * dcaXY * dcaZ * trackParCov.getSigmaZY()) / det; - dca3D = std::sqrt(std::fabs(chi2) / 2.); - } - if (dca3D > dca_3d_sigma_max) { - return false; - } - - if (trackParCov.getPt() < minpt || std::fabs(trackParCov.getEta()) > maxeta) { - return false; - } - - int total_cluster_size = 0, nl = 0; - for (unsigned int layer = 0; layer < 7; layer++) { - int cluster_size_per_layer = track.itsClsSizeInLayer(layer); - if (cluster_size_per_layer > 0) { - nl++; - } - total_cluster_size += cluster_size_per_layer; - } - - if (maxMeanITSClusterSize < static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(trackParCov.getTgl()))) { - return false; - } - - if ((track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF()) && maxpt_itssa < track.pt()) { - return false; - } - - // if ((track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF()) && maxpt_itssa < track.pt()) { - // return false; - // } - - return true; - } - - template - bool isElectron(TCollision const& collision, TTrack const& track) - { - if (includeITSsa && (track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF())) [[unlikely]] { - int total_cluster_size = 0, nl = 0; - for (unsigned int layer = 0; layer < 7; layer++) { - int cluster_size_per_layer = track.itsClsSizeInLayer(layer); - if (cluster_size_per_layer > 0) { - nl++; - } - total_cluster_size += cluster_size_per_layer; - } - - return (maxMeanITSClusterSize > static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(track.tgl()))); - } - return isElectron_TPChadrej(collision, track) || isElectron_TOFreq(collision, track); - } - - template - bool isElectron_TPChadrej(TCollision const& collision, TTrack const& track) - { - float tofNSigmaEl = mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]; - - if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { - return false; - } - if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi && track.tpcInnerParam() < max_pin_for_pion_rejection) { - return false; - } - if (minTPCNsigmaKa < track.tpcNSigmaKa() && track.tpcNSigmaKa() < maxTPCNsigmaKa) { - return false; - } - if (minTPCNsigmaPr < track.tpcNSigmaPr() && track.tpcNSigmaPr() < maxTPCNsigmaPr) { - return false; - } - if (track.hasTOF() && (maxTOFNsigmaEl < std::fabs(tofNSigmaEl))) { - return false; - } - return true; - } - - template - bool isElectron_TOFreq(TCollision const& collision, TTrack const& track) - { - float tofNSigmaEl = mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]; - - if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi && (min_pin_for_pion_rejection < track.tpcInnerParam() && track.tpcInnerParam() < max_pin_for_pion_rejection)) { - return false; - } - return minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < maxTPCNsigmaEl && std::fabs(tofNSigmaEl) < maxTOFNsigmaEl; - } - - template - void fillTrackInfo(TCollision const& collision, TTracks const& tracks) - { - - for (const auto& track : tracks) { - if (!checkTrack(collision, track)) { - continue; - } - - if (!isElectron(collision, track)) { - continue; - } - - fillTrackHistograms(track); - fillTrackTable(collision, track); - } - } - - template - void fillPairInfo(TCollision const& collision, TTracks1 const& tracks1, TTracks2 const& tracks2) - { - if constexpr (pairtype == 0) { // ULS - for (const auto& [t1, t2] : combinations(CombinationsFullIndexPolicy(tracks1, tracks2))) { - - if (!checkTrack(collision, t1) || !checkTrack(collision, t2)) { - continue; - } - - if (!isElectron(collision, t1) || !isElectron(collision, t2)) { - continue; - } - - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), dBz); - - fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); - fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMvsPhiV"), phiv, v12.M()); - - if (v12.M() > maxMee) { // don't store - continue; - } - - fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMCutMvsPt"), v12.M(), v12.Pt()); - fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMCutMvsPhiV"), phiv, v12.M()); - - if (v12.M() < slope * phiv + intercept) { - continue; - } - - fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMPhiCutMvsPt"), v12.M(), v12.Pt()); - fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMPhiCutMvsPhiV"), phiv, v12.M()); - - if (t1.sign() > 0) { // for positron - if (std::find(acceptedPosTrackIds_per_collision.begin(), acceptedPosTrackIds_per_collision.end(), t1.globalIndex()) == acceptedPosTrackIds_per_collision.end()) { - fillTrackHistograms(t1); - acceptedPosTrackIds_per_collision.emplace_back(t1.globalIndex()); - } - } else { // for electron - if (std::find(acceptedNegTrackIds_per_collision.begin(), acceptedNegTrackIds_per_collision.end(), t1.globalIndex()) == acceptedNegTrackIds_per_collision.end()) { - fillTrackHistograms(t1); - acceptedNegTrackIds_per_collision.emplace_back(t1.globalIndex()); - } - } - - if (t2.sign() > 0) { // for positron - if (std::find(acceptedPosTrackIds_per_collision.begin(), acceptedPosTrackIds_per_collision.end(), t2.globalIndex()) == acceptedPosTrackIds_per_collision.end()) { - fillTrackHistograms(t2); - acceptedPosTrackIds_per_collision.emplace_back(t2.globalIndex()); - } - } else { // for electron - if (std::find(acceptedNegTrackIds_per_collision.begin(), acceptedNegTrackIds_per_collision.end(), t2.globalIndex()) == acceptedNegTrackIds_per_collision.end()) { - fillTrackHistograms(t2); - acceptedNegTrackIds_per_collision.emplace_back(t2.globalIndex()); - } - } - } // end of ULS pairing - } else { // LS - for (auto& [t1, t2] : combinations(CombinationsStrictlyUpperIndexPolicy(tracks1, tracks2))) { - if (!checkTrack(collision, t1) || !checkTrack(collision, t2)) { - continue; - } - if (!isElectron(collision, t1) || !isElectron(collision, t2)) { - continue; - } - - ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); - ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; - float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), dBz); - fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); - fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMvsPhiV"), phiv, v12.M()); - } // end of LS pairing - } - } - - template - void fillTrackHistograms(TTrack const& track) - { - float mcTunedTPCSignal = 0.f; - if constexpr (isMC) { - mcTunedTPCSignal = track.mcTunedTPCSignal(); - } - - fRegistry.fill(HIST("Track/hPt"), track.pt()); - fRegistry.fill(HIST("Track/hEtaPhi"), track.phi(), track.eta()); - fRegistry.fill(HIST("Track/hQoverPt"), track.sign() / track.pt()); - fRegistry.fill(HIST("Track/hRelDeltaPt"), track.pt(), track.sigma1Pt() * track.pt()); - fRegistry.fill(HIST("Track/hDCAxyz"), track.dcaXY(), track.dcaZ()); - fRegistry.fill(HIST("Track/hDCAxy_Pt"), track.pt(), track.dcaXY()); - fRegistry.fill(HIST("Track/hDCAz_Pt"), track.pt(), track.dcaZ()); - fRegistry.fill(HIST("Track/hDCAxyzSigma"), track.dcaXY() / std::sqrt(track.cYY()), track.dcaZ() / std::sqrt(track.cZZ())); - fRegistry.fill(HIST("Track/hDCAxyRes_Pt"), track.pt(), std::sqrt(track.cYY()) * 1e+4); // convert cm to um - fRegistry.fill(HIST("Track/hDCAzRes_Pt"), track.pt(), std::sqrt(track.cZZ()) * 1e+4); // convert cm to um - - fRegistry.fill(HIST("Track/hNclsTPC"), track.tpcNClsFound()); - fRegistry.fill(HIST("Track/hNcrTPC"), track.tpcNClsCrossedRows()); - fRegistry.fill(HIST("Track/hChi2TPC"), track.tpcChi2NCl()); - fRegistry.fill(HIST("Track/hTPCNcr2Nf"), track.tpcCrossedRowsOverFindableCls()); - fRegistry.fill(HIST("Track/hTPCNcls2Nf"), track.tpcFoundOverFindableCls()); - fRegistry.fill(HIST("Track/hTPCNclsShared"), track.pt(), track.tpcFractionSharedCls()); - fRegistry.fill(HIST("Track/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); - fRegistry.fill(HIST("Track/hTPCdEdxMC"), track.tpcInnerParam(), mcTunedTPCSignal); - fRegistry.fill(HIST("Track/hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); - fRegistry.fill(HIST("Track/hTPCNsigmaPi"), track.tpcInnerParam(), track.tpcNSigmaPi()); - - fRegistry.fill(HIST("Track/hChi2TOF"), track.tofChi2()); - fRegistry.fill(HIST("Track/hTOFbeta"), track.p(), track.beta()); - fRegistry.fill(HIST("Track/hTOFNsigmaEl"), track.p(), track.tofNSigmaEl()); - fRegistry.fill(HIST("Track/hTOFNsigmaPi"), track.p(), track.tofNSigmaPi()); - - fRegistry.fill(HIST("Track/hNclsITS"), track.itsNCls()); - fRegistry.fill(HIST("Track/hChi2ITS"), track.itsChi2NCl()); - fRegistry.fill(HIST("Track/hITSClusterMap"), track.itsClusterMap()); - - int totalClusterSize = 0, nl = 0; - for (unsigned int layer = 0; layer < 7; layer++) { // o2-linter: disable=magic-number (number of ITS layers) - int clusterSizePerLayer = track.itsClsSizeInLayer(layer); - if (clusterSizePerLayer > 0) { - nl++; - } - totalClusterSize += clusterSizePerLayer; - } - - int totalClusterSizeIb = 0, nl_ib = 0; - for (unsigned int layer = 0; layer < 3; layer++) { // o2-linter: disable=magic-number (number of inner barrel layers) - int clusterSizePerLayer = track.itsClsSizeInLayer(layer); - if (clusterSizePerLayer > 0) { - nl_ib++; - } - totalClusterSizeIb += clusterSizePerLayer; - } - - int totalClusterSizeOb = 0, nlOb = 0; - for (unsigned int layer = 3; layer < 7; layer++) { // o2-linter: disable=magic-number (number of outer barrel layers) - int clusterSizePerLayer = track.itsClsSizeInLayer(layer); - if (clusterSizePerLayer > 0) { - nlOb++; - } - totalClusterSizeOb += clusterSizePerLayer; - } - fRegistry.fill(HIST("Track/hMeanClusterSizeITS"), track.p(), static_cast(totalClusterSize) / static_cast(nl) * std::cos(std::atan(track.tgl()))); - fRegistry.fill(HIST("Track/hMeanClusterSizeITSib"), track.p(), static_cast(totalClusterSizeIb) / static_cast(nl_ib) * std::cos(std::atan(track.tgl()))); - fRegistry.fill(HIST("Track/hMeanClusterSizeITSob"), track.p(), static_cast(totalClusterSizeOb) / static_cast(nlOb) * std::cos(std::atan(track.tgl()))); - } - - template - void fillTrackTable(TCollision const& collision, TTrack const& track) - { - emprimaryelectrons(collision.globalIndex(), track.globalIndex(), track.sign(), - track.pt(), track.eta(), track.phi(), track.dcaXY(), track.dcaZ(), track.cYY(), track.cZY(), track.cZZ(), - track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), track.tpcNClsShared(), - track.tpcChi2NCl(), track.tpcInnerParam(), - track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaPi(), - track.beta(), track.tofNSigmaEl(), - track.itsClusterSizes(), track.itsChi2NCl(), track.tofChi2(), track.detectorMap()); - - if constexpr (isMC) { - emprimaryelectronsDeDxMC(track.mcTunedTPCSignal()); - } - } - - std::vector acceptedPosTrackIds_per_collision; - std::vector acceptedNegTrackIds_per_collision; - std::vector acceptedTrackIds_per_collision; - // Filter trackFilter = minpt < o2::aod::track::pt && nabs(o2::aod::track::eta) < maxeta && o2::aod::track::itsChi2NCl < maxchi2its && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && nabs(o2::aod::track::dcaXY) < dca_xy_max && nabs(o2::aod::track::dcaZ) < dca_z_max; - // Filter trackFilter - // using MyFilteredTracks = soa::Filtered; - Partition posTracks = o2::aod::track::signed1Pt > 0.f; - Partition negTracks = o2::aod::track::signed1Pt < 0.f; - - std::unordered_map mapCollisionTime; - std::unordered_map mapCollisionTimeError; - - std::map, float> mapTOFNsigmaReassociated; // map pair(collisionId, trackId) -> tof n sigma - std::map, float> mapTOFBetaReassociated; // map pair(collisionId, trackId) -> tof beta - - // ---------- for data ---------- - void processRec(MyCollisions const& collisions, MyBCs const& bcs, MyTracks const& tracks, aod::V0PhotonsKF const& v0photons, aod::TrackAssoc const& trackIndices) - { - initCCDB(bcs.iteratorAt(0)); - mTOFResponse->processSetup(bcs.iteratorAt(0)); - - for (const auto& track : tracks) { - mapCollisionTime.try_emplace(track.collisionId(), track.tofEvTime()); - mapCollisionTimeError.try_emplace(track.collisionId(), track.tofEvTimeErr()); - } - calculateTOFNSigmaWithReassociation(collisions, bcs, tracks, trackIndices); - - for (const auto& collision : collisions) { - if (!collision.isSelected()) { - continue; - } - - const auto& v0photons_per_coll = v0photons.sliceBy(perCol_pcm, collision.globalIndex()); - const auto& posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - const auto& negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - const auto& slicedTracks = tracks.sliceBy(perTracksCollision, collision.globalIndex()); - acceptedPosTrackIds_per_collision.reserve(posTracks_per_coll.size()); - acceptedNegTrackIds_per_collision.reserve(negTracks_per_coll.size()); - - if (!fillWithPairs) { - fillTrackInfo(collision, slicedTracks); - } else { - fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS - if (fillLS) { - fillPairInfo(collision, posTracks_per_coll, posTracks_per_coll); // LS++ - fillPairInfo(collision, negTracks_per_coll, negTracks_per_coll); // LS-- - } - - if ((v0photons_per_coll.size() >= 1 && !acceptedPosTrackIds_per_collision.empty() && !acceptedNegTrackIds_per_collision.empty()) || (acceptedPosTrackIds_per_collision.size() >= 2 && acceptedNegTrackIds_per_collision.size() >= 2)) { - for (const auto& posId : acceptedPosTrackIds_per_collision) { - const auto& pos = tracks.rawIteratorAt(posId); - fillTrackTable(collision, pos); - } - for (const auto& eleId : acceptedNegTrackIds_per_collision) { - const auto& ele = tracks.rawIteratorAt(eleId); - fillTrackTable(collision, ele); - } - } - } - - acceptedPosTrackIds_per_collision.clear(); - acceptedNegTrackIds_per_collision.clear(); - - } // end of collision loop - } - PROCESS_SWITCH(skimmerPrimaryElectronFromDalitzEE, processRec, "process reconstructed info only", false); // standalone - - // void processRec_SWT(MyCollisionsWithSWT const& collisions, MyBCs const& bcs, MyTracks const& tracks, aod::V0PhotonsKF const& v0photons, aod::TrackAssoc const& trackIndices) - // { - // initCCDB(bcs.iteratorAt(0)); - - // mTOFResponse->processSetup(bcs.iteratorAt(0)); - // for (const auto& track : tracks) { - // mapCollisionTime.try_emplace(track.collisionId(), track.tofEvTime()); - // mapCollisionTimeError.try_emplace(track.collisionId(), track.tofEvTimeErr()); - // } - // calculateTOFNSigmaWithReassociation(collisions, bcs, tracks, trackIndices); - - // for (const auto& collision : collisions) { - // if (!collision.isSelected()) { - // continue; - // } - - // if (collision.swtaliastmp_raw() == 0) { - // continue; - // } - - // const auto& v0photons_per_coll = v0photons.sliceBy(perCol_pcm, collision.globalIndex()); - // const auto& posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - // const auto& negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - // const auto& slicedTracks = tracks.sliceBy(perTracksCollision, collision.globalIndex()); - // acceptedPosTrackIds_per_collision.reserve(posTracks_per_coll.size()); - // acceptedNegTrackIds_per_collision.reserve(negTracks_per_coll.size()); - - // if(!fillWithPairs){ - // fillTrackInfo(collision, slicedTracks); - // }else{ - // fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS - // if (fillLS) { - // fillPairInfo(collision, posTracks_per_coll, posTracks_per_coll); // LS++ - // fillPairInfo(collision, negTracks_per_coll, negTracks_per_coll); // LS-- - // } - - // if ((v0photons_per_coll.size() >= 1 && !acceptedPosTrackIds_per_collision.empty() && !acceptedNegTrackIds_per_collision.empty()) || (acceptedPosTrackIds_per_collision.size() >= 2 && acceptedNegTrackIds_per_collision.size() >= 2)) { - // // LOGF(info, "v0photons_per_coll.size() = %d, acceptedPosTrackIds_per_collision.size() = %d, acceptedNegTrackIds_per_collision.size() = %d", v0photons_per_coll.size(), acceptedPosTrackIds_per_collision.size(), acceptedNegTrackIds_per_collision.size()); - // for (const auto& posId : acceptedPosTrackIds_per_collision) { - // const auto& pos = tracks.rawIteratorAt(posId); - // fillTrackTable(collision, pos); - // } - // for (const auto& eleId : acceptedNegTrackIds_per_collision) { - // const auto& ele = tracks.rawIteratorAt(eleId); - // fillTrackTable(collision, ele); - // } - // } - // } - - // acceptedPosTrackIds_per_collision.clear(); - // acceptedNegTrackIds_per_collision.clear(); - - // } // end of collision loop - // } - // PROCESS_SWITCH(skimmerPrimaryElectronFromDalitzEE, processRec_SWT, "process reconstructed info with CEFP", false); // with cefp - - // using MyFilteredTracksMC = soa::Filtered; - Partition posTracksMC = o2::aod::track::signed1Pt > 0.f; - Partition negTracksMC = o2::aod::track::signed1Pt < 0.f; - // ---------- for MC ---------- - void processMC(MyCollisionsMC const& collisions, aod::McCollisions const&, MyBCs const& bcs, MyTracksMC const& tracks, aod::V0PhotonsKF const& v0photons, aod::TrackAssoc const& trackIndices) - { - uint64_t nCollisSel = 0; - uint64_t nNoMcColl = 0; - uint64_t nProcessedCollisions = 0; - uint64_t nCheckTrack = 0; - - initCCDB(bcs.iteratorAt(0)); - - mTOFResponse->processSetup(bcs.iteratorAt(0)); - for (const auto& track : tracks) { - mapCollisionTime.try_emplace(track.collisionId(), track.tofEvTime()); - mapCollisionTimeError.try_emplace(track.collisionId(), track.tofEvTimeErr()); - } - calculateTOFNSigmaWithReassociation(collisions, bcs, tracks, trackIndices); - - for (const auto& collision : collisions) { - if (!collision.has_mcCollision()) { - nNoMcColl++; - continue; - } - - if (!collision.isSelected()) { - nCollisSel++; - continue; - } - nProcessedCollisions++; - - const auto& v0photons_per_coll = v0photons.sliceBy(perCol_pcm, collision.globalIndex()); - const auto& posTracks_per_coll = posTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - const auto& negTracks_per_coll = negTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); - const auto& slicedTracks = tracks.sliceBy(perTracksCollision, collision.globalIndex()); - acceptedPosTrackIds_per_collision.reserve(posTracks_per_coll.size()); - acceptedNegTrackIds_per_collision.reserve(negTracks_per_coll.size()); - acceptedTrackIds_per_collision.reserve(2 * (negTracks_per_coll.size())); - - if (!fillWithPairs) { - fillTrackInfo(collision, slicedTracks); - } else { - fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS - if (fillLS) { - fillPairInfo(collision, posTracks_per_coll, posTracks_per_coll); // LS++ - fillPairInfo(collision, negTracks_per_coll, negTracks_per_coll); // LS-- - } - if ((acceptedPosTrackIds_per_collision.empty() && acceptedNegTrackIds_per_collision.empty()) || (acceptedPosTrackIds_per_collision.size() >= 2 && acceptedNegTrackIds_per_collision.size() >= 2)) { // v0photons_per_coll.size() >= 1 && - for (const auto& posId : acceptedPosTrackIds_per_collision) { - const auto& pos = tracks.rawIteratorAt(posId); - fillTrackTable(collision, pos); - } - for (const auto& eleId : acceptedNegTrackIds_per_collision) { - const auto& ele = tracks.rawIteratorAt(eleId); - fillTrackTable(collision, ele); - } - } - } // end of fill loop - - acceptedPosTrackIds_per_collision.clear(); - acceptedNegTrackIds_per_collision.clear(); - - } // end of collision loop - - LOG(info) << "Total collisions: " << collisions.size(); - LOG(info) << "No MC collision: " << nNoMcColl; - LOG(info) << "Rejected by selection: " << nCollisSel; - LOG(info) << "Processed collisions: " << nProcessedCollisions; - LOG(info) << "Invalid track: " << nCheckTrack; - } - PROCESS_SWITCH(skimmerPrimaryElectronFromDalitzEE, processMC, "process reconstructed and MC info ", true); -}; -// WorkflowSpec defineDataProcessing(ConfigContext const& context) -// { -// return WorkflowSpec{adaptAnalysisTask(context, TaskName{"skimmer-primary-electron-from-dalitzee"})}; -// } WorkflowSpec defineDataProcessing(ConfigContext const& context) { o2::pid::tof::TOFResponseImpl::metadataInfo.initMetadata(context); return WorkflowSpec{ - adaptAnalysisTask(context, TaskName{"skimmer-primary-electron-from-dalitzee"})}; + adaptAnalysisTask>(context, TaskName{"skimmer-primary-electron-from-dalitzee"})}; } diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.h b/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.h new file mode 100644 index 00000000000..c1102e8f112 --- /dev/null +++ b/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.h @@ -0,0 +1,1028 @@ +// 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. + +/// \file skimmerPrimaryElectronFromDalitzEE.h +/// \brief write relevant information about primary electrons. +/// \author daiki.sekihata@cern.ch + +#ifndef PWGEM_PHOTONMESON_TABLEPRODUCER_SKIMMERPRIMARYELECTRONFROMDALITZEE_H_ +#define PWGEM_PHOTONMESON_TABLEPRODUCER_SKIMMERPRIMARYELECTRONFROMDALITZEE_H_ + +#include "PWGEM/Dilepton/Utils/PairUtilities.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" + +#include "Common/Core/PID/PIDTOFParamService.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// using namespace o2; +// using namespace o2::soa; +// using namespace o2::framework; +// using namespace o2::framework::expressions; +// using namespace o2::constants::physics; + +using o2::framework::AxisSpec; +using o2::framework::Configurable; +using o2::framework::ConfigurableGroup; +using o2::framework::HistType; +using o2::framework::kTH1D; +using o2::framework::kTH1F; +using o2::framework::kTH2F; +using o2::framework::kTHnSparseF; +using o2::framework::Preslice; +using o2::framework::Produces; + +using MyCollisions = o2::soa::Join; +using MyCollisionsWithSWT = o2::soa::Join; +using MyBCs = o2::soa::Join; + +using MyCollisionsMC = o2::soa::Join; +using MyTracks = o2::soa::Join; +using MyTrack = MyTracks::iterator; +using MyTracksMC = o2::soa::Join; +using MyTrackMC = MyTracksMC::iterator; + +namespace o2::aod +{ +namespace pwgem::pm::recalculatedtofpid +{ +DECLARE_SOA_COLUMN(BetaRecalculated, betaRecalculated, float); +DECLARE_SOA_COLUMN(TOFNSigmaElRecalculated, tofNSigmaElRecalculated, float); +} // namespace pwgem::pm::recalculatedtofpid + +DECLARE_SOA_TABLE(EMTOFNSigmas, "AOD", "EMTOFNSIGMA", // make std::map in your tasks later. // Don't store this table in the derived data. + o2::aod::emprimaryelectron::CollisionId, o2::aod::emprimaryelectron::TrackId, + o2::aod::pwgem::pm::recalculatedtofpid::BetaRecalculated, o2::aod::pwgem::pm::recalculatedtofpid::TOFNSigmaElRecalculated); + +using EMTOFNSigma = EMTOFNSigmas::iterator; +} // namespace o2::aod + +template +struct skimmerPrimaryElectronFromDalitzEE { + + o2::framework::SliceCache cache; + Preslice perCol = o2::aod::track::collisionId; + o2::framework::PresliceOptional perTracksCollision = o2::aod::track::collisionId; + Preslice perCol_pcm = o2::aod::v0photonkf::collisionId; // o2::aod::V0PhotonsKF + Preslice trackIndicesPerCollision = o2::aod::track_association::collisionId; + Produces emprimaryelectrons; + Produces emprimaryelectronsDeDxMC; + o2::framework::Service mTOFResponse{}; + + Produces emtofs; + + enum class enumFillingMode { + SingleTrack = 1, + EpEmPairs = 2, + EpEmPairsAndPhoton = 3 + }; + + // Configurables + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; + Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; + Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; + + // Operation and minimisation criteria + Configurable dBzInput{"dBzInput", -999, "bz field in kG, -999 is automatic"}; + Configurable min_ncluster_tpc{"min_ncluster_tpc", 0, "min ncluster tpc"}; // o2-linter: disable=name/function-variable (renaming configs would mess up hyperloop) + Configurable mincrossedrows{"mincrossedrows", 70, "min. crossed rows"}; + Configurable min_tpc_cr_findable_ratio{"min_tpc_cr_findable_ratio", 0.8, "min. TPC Ncr/Nf ratio"}; + Configurable max_frac_shared_clusters_tpc{"max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; + Configurable min_ncluster_its{"min_ncluster_its", 4, "min ncluster its"}; + Configurable min_ncluster_itsib{"min_ncluster_itsib", 1, "min ncluster itsib"}; + Configurable minchi2tpc{"minchi2tpc", 0.0, "min. chi2/NclsTPC"}; + Configurable maxchi2tpc{"maxchi2tpc", 5.0, "max. chi2/NclsTPC"}; + Configurable minchi2its{"minchi2its", 0.0, "min. chi2/NclsITS"}; + Configurable maxchi2its{"maxchi2its", 36.0, "max. chi2/NclsITS"}; + Configurable minpt{"minpt", 0.05, "min pt for ITS-TPC track"}; + Configurable maxeta{"maxeta", 2.0, "max eta acceptance"}; + Configurable dca_xy_max{"dca_xy_max", 1, "max DCAxy in cm"}; // o2-linter: disable=name/function-variable (renaming configs would mess up hyperloop) + Configurable dca_z_max{"dca_z_max", 1, "max DCAz in cm"}; // o2-linter: disable=name/function-variable (renaming configs would mess up hyperloop) + Configurable dca_3d_sigma_max{"dca_3d_sigma_max", 2, "max DCA 3D in sigma"}; // o2-linter: disable=name/function-variable (renaming configs would mess up hyperloop) + Configurable minTPCNsigmaEl{"minTPCNsigmaEl", -2.5, "min. TPC n sigma for electron inclusion"}; + Configurable maxTPCNsigmaEl{"maxTPCNsigmaEl", +3.5, "max. TPC n sigma for electron inclusion"}; + Configurable maxTPCNsigmaPi{"maxTPCNsigmaPi", 0.0, "max. TPC n sigma for pion exclusion"}; + Configurable minTPCNsigmaPi{"minTPCNsigmaPi", 0.0, "min. TPC n sigma for pion exclusion"}; + Configurable minTOFNsigmaEl{"minTOFNsigmaEl", -3.5, "min. TOF n sigma for electron inclusion"}; + Configurable maxTOFNsigmaEl{"maxTOFNsigmaEl", +3.5, "max. TOF n sigma for electron inclusion"}; + Configurable minTPCNsigmaKa{"minTPCNsigmaKa", -2.5, "min. TPC n sigma for kaon exclusion"}; + Configurable maxTPCNsigmaKa{"maxTPCNsigmaKa", 2.5, "max. TPC n sigma for kaon exclusion"}; + Configurable minTPCNsigmaPr{"minTPCNsigmaPr", -2.5, "min. TPC n sigma for proton exclusion"}; + Configurable maxTPCNsigmaPr{"maxTPCNsigmaPr", 2.5, "max. TPC n sigma for proton exclusion"}; + Configurable requireTOF{"requireTOF", false, "require TOF hit"}; + Configurable min_pin_for_pion_rejection{"min_pin_for_pion_rejection", 0.0, "pion rejection is applied above this pin"}; // this is used only in TOFreq + Configurable max_pin_for_pion_rejection{"max_pin_for_pion_rejection", 0.5, "pion rejection is applied below this pin"}; + Configurable minMee{"minMee", 0., "min. mee to store dalitz ee pairs"}; + Configurable maxMee{"maxMee", 0.5, "max. mee to store dalitz ee pairs"}; + Configurable minMeegamma{"minMeegamma", 0.3, "min. mee to store eegamma candidates"}; + Configurable maxMeegamma{"maxMeegamma", 0.8, "max. mee to store eegamma candidates"}; + Configurable fillLS{"fillLS", true, "flag to fill LS histograms for QA"}; + Configurable fillingMode{"fillingMode", 1, "Filling mode| 1: fill tracks without pair selection, 2: fill tracks from selected pairs, 3: fill tracks from selected pairs that can be combined with a photon"}; + Configurable fillWithEtaMassCut{"fillWithEtaMassCut", true, "only valid for fillingmode 3; true: filling tabled based on eta candidate selection with minMeegamma < M < maxMeegamma, false: fill identical to fillingmode 2"}; + Configurable includeITSsa{"includeITSsa", false, "Flag to include ITSsa tracks"}; + Configurable maxpt_itssa{"maxpt_itssa", 0.15, "max pt for ITSsa track"}; // o2-linter: disable=name/function-variable (renaming configs would mess up hyperloop) + Configurable maxMeanITSClusterSize{"maxMeanITSClusterSize", 16, "max x cos(lambda)"}; + Configurable slope{"slope", 0.0185, "slope for m vs. phiv"}; + Configurable intercept{"intercept", -0.0380, "intercept for m vs. phiv"}; + Configurable useTOFNSigmaDeltaBC{"useTOFNSigmaDeltaBC", false, "Flag to shift delta BC for TOF n sigma (only with TTCA)"}; + Configurable storeOnlyTrueElectronMC{"storeOnlyTrueElectronMC", false, "Flag to store only true electron in MC"}; + + o2::framework::HistogramRegistry fRegistry{"output", {}, o2::framework::OutputObjHandlingPolicy::AnalysisObject, false, false}; + static constexpr std::array DileptonSigns = {"uls/", "lspp/", "lsmm/"}; + + int mRunNumber = 0; + float dBz = 0.; + o2::framework::Service ccdb{}; + o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + o2::dataformats::VertexBase mVtx; + + void init(o2::framework::InitContext& initContext) + { + // if (doprocessRec && doprocessRec_SWT) { + // LOGF(fatal, "Cannot enable doprocessRec and doprocessRec_SWT at the same time. Please choose one."); + // } + + mRunNumber = 0; + dBz = 0; + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + LOGF(info, "before TOF initSetup"); + mTOFResponse->initSetup(ccdb, initContext); + LOGF(info, "after TOF initSetup"); + + fRegistry.add("Track/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); + fRegistry.add("Track/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, o2::constants::math::TwoPI}, {400, -2.0f, 2.0f}}, false); + fRegistry.add("Track/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{400, -20, 20}}, false); + fRegistry.add("Track/hRelDeltaPt", "pT resolution;p_{T} (GeV/c);#Deltap_{T}/p_{T}", kTH2F, {{1000, 0, 10}, {100, 0, 0.1}}, false); + fRegistry.add("Track/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -1.0f, 1.0f}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("Track/hDCAxy_Pt", "DCA_{xy} vs. pT;p_{T} (GeV/c);DCA_{xy} (cm)", kTH2F, {{200, 0, 10}, {200, -1, 1}}, false); + fRegistry.add("Track/hDCAz_Pt", "DCA_{z} vs. pT;p_{T} (GeV/c);DCA_{z} (cm)", kTH2F, {{200, 0, 10}, {200, -1, 1}}, false); + fRegistry.add("Track/hDCAxyzSigma", "DCA xy vs. z;DCA_{xy} (#sigma);DCA_{z} (#sigma)", kTH2F, {{200, -10.0f, 10.0f}, {200, -10.0f, 10.0f}}, false); + fRegistry.add("Track/hDCAxyRes_Pt", "DCA_{xy} resolution vs. pT;p_{T} (GeV/c);DCA_{xy} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 500}}, false); + fRegistry.add("Track/hDCAzRes_Pt", "DCA_{z} resolution vs. pT;p_{T} (GeV/c);DCA_{z} resolution (#mum)", kTH2F, {{200, 0, 10}, {500, 0., 500}}, false); + + // TPC + fRegistry.add("Track/hNclsTPC", "number of TPC clusters", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/hNcrTPC", "number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("Track/hChi2TPC", "chi2/number of TPC clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hTPCNcr2Nf", "TPC Ncr/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/hTPCNcls2Nf", "TPC Ncls/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("Track/hTPCNclsShared", "TPC Ncls shared/Ncls;p_{T} (GeV/c);N_{cls}^{shared}/N_{cls} in TPC", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); + fRegistry.add("Track/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); + fRegistry.add("Track/hTPCdEdxMC", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); + fRegistry.add("Track/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + + // ITS + fRegistry.add("Track/hNclsITS", "number of ITS clusters", kTH1F, {{8, -0.5, 7.5}}, false); + fRegistry.add("Track/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{400, 0, 40}}, false); + fRegistry.add("Track/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); + fRegistry.add("Track/hMeanClusterSizeITS", "mean cluster size ITS;p_{pv} (GeV/c); #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); + fRegistry.add("Track/hMeanClusterSizeITSib", "mean cluster size ITSib;p_{pv} (GeV/c); #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); + fRegistry.add("Track/hMeanClusterSizeITSob", "mean cluster size ITSob;p_{pv} (GeV/c); #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {150, 0, 15}}, false); + + // TOF + fRegistry.add("Track/hChi2TOF", "chi2 of TOF", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("Track/hTOFbeta", "TOF beta;p_{pv} (GeV/c);#beta", kTH2F, {{1000, 0, 10}, {240, 0, 1.2}}, false); + fRegistry.add("Track/hTOFNsigmaEl", "TOF n sigma el;p_{pv} (GeV/c);n #sigma_{e}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("Track/hTOFNsigmaPi", "TOF n sigma pi;p_{pv} (GeV/c);n #sigma_{#pi}^{TOF}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + + // pair + fRegistry.add("Pair/uls/hTrackMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{100, 0, 0.1}, {200, 0, 2}}, false); + fRegistry.add("Pair/uls/hCheckEMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{100, 0, 0.1}, {200, 0, 2}}, false); + fRegistry.add("Pair/uls/hMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{100, 0, 0.1}, {200, 0, 2}}, false); + fRegistry.add("Pair/uls/hMCutMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{100, 0, 0.1}, {200, 0, 2}}, false); + fRegistry.add("Pair/uls/hMPhiCutMvsPt", "m_{ee} vs. p_{T,ee};m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)", kTH2F, {{100, 0, 0.1}, {200, 0, 2}}, false); + + fRegistry.add("Pair/uls/hTrackMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{180, 0, o2::constants::math::PI}, {100, 0, 0.1}}, false); + fRegistry.add("Pair/uls/hCheckEMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{180, 0, o2::constants::math::PI}, {100, 0, 0.1}}, false); + fRegistry.add("Pair/uls/hMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{180, 0, o2::constants::math::PI}, {100, 0, 0.1}}, false); + fRegistry.add("Pair/uls/hMCutMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{180, 0, o2::constants::math::PI}, {100, 0, 0.1}}, false); + fRegistry.add("Pair/uls/hMPhiCutMvsPhiV", "m_{ee} vs. #varphi_{V};#varphi_{V} (rad.);m_{ee} (GeV/c^{2})", kTH2F, {{180, 0, o2::constants::math::PI}, {100, 0, 0.1}}, false); + + fRegistry.addClone("Pair/uls/", "Pair/lspp/"); + fRegistry.addClone("Pair/uls/", "Pair/lsmm/"); + } + + void initCCDB(MyBCs::iterator const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + mRunNumber = bc.runNumber(); + // In case override, don't proceed, please - no CCDB access required + if (dBzInput > -990) { // o2-linter: disable=magic-number (check against some default number) + dBz = dBzInput; + o2::parameters::GRPMagField grpmag; + if (std::fabs(dBz) > 1e-5) { // o2-linter: disable=magic-number (check against some default number) + grpmag.setL3Current(30000.f / (dBz / 5.0f)); // o2-linter: disable=magic-number (override value) + } + o2::base::Propagator::initFieldFromGRP(&grpmag); + return; + } + + o2::base::Propagator::initFieldFromGRP(&bc.grpMagField()); + + auto run3grpTimestamp = bc.timestamp(); + + dBz = bc.grpMagField().getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grpTimestamp << " with magnetic field of " << dBz << " kZG"; + } + + template + void calculateTOFNSigmaWithReassociation(TCollisions const& collisions, TBCs const&, TTracks const& tracks, TTrackAssoc const& trackIndices) + { + if (useTOFNSigmaDeltaBC) { + if constexpr (withTTCA) { + for (const auto& collision : collisions) { + if (mapCollisionTime.find(collision.globalIndex()) == mapCollisionTime.end()) { + continue; + } + auto bcCollision = collision.template bc_as(); + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + for (const auto& trackId : trackIdsThisCollision) { + auto track = trackId.template track_as(); + if (!track.hasITS() || !track.hasTPC()) { // apply only minimal cut + continue; + } + + if (track.hasTOF() && track.has_collision()) { // TTCA may use orphan tracks. + auto bcTrack = track.template collision_as().template bc_as(); + float tofNSigmaEl = mTOFResponse->nSigma(track.tofSignalInAnotherBC(bcTrack.globalBC(), bcCollision.globalBC()), track.tofExpMom(), track.length(), track.p(), track.eta(), mapCollisionTime[collision.globalIndex()], mapCollisionTimeError[collision.globalIndex()]); + float beta = track.length() / (track.tofSignalInAnotherBC(bcTrack.globalBC(), bcCollision.globalBC()) - mapCollisionTime[collision.globalIndex()]) / (o2::constants::physics::LightSpeedCm2S * 1e-12); + mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = tofNSigmaEl; + mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = beta; + emtofs(collision.globalIndex(), track.globalIndex(), mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); + } else { + mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.tofNSigmaEl(); + mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.beta(); + emtofs(collision.globalIndex(), track.globalIndex(), mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); + } + } // end of track loop + } // end of collision loop + } else { + for (const auto& collision : collisions) { + auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); + for (const auto& track : tracks_per_coll) { + if (!track.hasITS() || !track.hasTPC()) { // apply only minimal cut + continue; + } + mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.tofNSigmaEl(); + mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.beta(); + emtofs(collision.globalIndex(), track.globalIndex(), mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); + } + } // end of track loop + } // end of collision loop + } else { + if constexpr (withTTCA) { + for (const auto& collision : collisions) { + auto trackIdsThisCollision = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + for (const auto& trackId : trackIdsThisCollision) { + auto track = trackId.template track_as(); + if (!track.hasITS() || !track.hasTPC()) { // apply only minimal cut + continue; + } + mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.tofNSigmaEl(); + mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.beta(); + emtofs(collision.globalIndex(), track.globalIndex(), mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); + } // end of track loop + } // end of collision loop + } else { + for (const auto& collision : collisions) { + auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); + for (const auto& track : tracks_per_coll) { + if (!track.hasITS() || !track.hasTPC()) { // apply only minimal cut + continue; + } + mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.tofNSigmaEl(); + mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())] = track.beta(); + emtofs(collision.globalIndex(), track.globalIndex(), mapTOFBetaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())], mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]); + } + } // end of track loop + } // end of collision loop + } + } + + template + bool checkTrack(TCollision const& collision, TTrack const& track) + { + if constexpr (isMC) { + if (!track.has_mcParticle()) { + return false; + } + if (storeOnlyTrueElectronMC) { + const auto& mcParticle = track.template mcParticle_as(); + if (std::abs(mcParticle.pdgCode()) != 11) { + return false; + } + } + } + + float tofNSigmaEl = mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]; + if (requireTOF && !(track.hasTOF() && std::fabs(tofNSigmaEl) < maxTOFNsigmaEl)) { + return false; + } + + if (!track.hasITS()) { + return false; + } + + if (track.itsChi2NCl() < minchi2its || maxchi2its < track.itsChi2NCl()) { + return false; + } + + if (track.itsNCls() < min_ncluster_its) { + return false; + } + if (track.itsNClsInnerBarrel() < min_ncluster_itsib) { + return false; + } + + if (!includeITSsa && !track.hasTPC()) { + return false; + } + + if (track.hasTPC()) { + if (track.tpcChi2NCl() < minchi2tpc || maxchi2tpc < track.tpcChi2NCl()) { + return false; + } + + if (track.tpcNClsFound() < min_ncluster_tpc) { + return false; + } + + if (track.tpcNClsCrossedRows() < mincrossedrows) { + return false; + } + + if (track.tpcCrossedRowsOverFindableCls() < min_tpc_cr_findable_ratio) { + return false; + } + + if (track.tpcFractionSharedCls() > max_frac_shared_clusters_tpc) { + return false; + } + } + + o2::dataformats::DCA mDcaInfoCov; // for Track association + mDcaInfoCov.set(999, 999, 999, 999, 999); + auto trackParCov = getTrackParCov(track); + trackParCov.setPID(o2::track::PID::Electron); + mVtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + mVtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + bool isPropOK = o2::base::Propagator::Instance()->propagateToDCABxByBz(mVtx, trackParCov, 2.f, matCorr, &mDcaInfoCov); + if (!isPropOK) { + return false; + } + float dcaXY = mDcaInfoCov.getY(); + float dcaZ = mDcaInfoCov.getZ(); + + if (std::fabs(dcaXY) > dca_xy_max || std::fabs(dcaZ) > dca_z_max) { + return false; + } + + float dca3D = 999.f; + float det = trackParCov.getSigmaY2() * trackParCov.getSigmaZ2() - trackParCov.getSigmaZY() * trackParCov.getSigmaZY(); + if (det < 0) { + dca3D = 999.f; + } else { + float chi2 = (dcaXY * dcaXY * trackParCov.getSigmaZ2() + dcaZ * dcaZ * trackParCov.getSigmaY2() - 2. * dcaXY * dcaZ * trackParCov.getSigmaZY()) / det; + dca3D = std::sqrt(std::fabs(chi2) / 2.); + } + if (dca3D > dca_3d_sigma_max) { + return false; + } + + if (trackParCov.getPt() < minpt || std::fabs(trackParCov.getEta()) > maxeta) { + return false; + } + + int total_cluster_size = 0, nl = 0; + for (unsigned int layer = 0; layer < 7; layer++) { + int cluster_size_per_layer = track.itsClsSizeInLayer(layer); + if (cluster_size_per_layer > 0) { + nl++; + } + total_cluster_size += cluster_size_per_layer; + } + + if (maxMeanITSClusterSize < static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(trackParCov.getTgl()))) { + return false; + } + + if ((track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF()) && maxpt_itssa < track.pt()) { + return false; + } + + // if ((track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF()) && maxpt_itssa < track.pt()) { + // return false; + // } + + return true; + } + + template + bool isElectron(TCollision const& collision, TTrack const& track) + { + if (includeITSsa && (track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF())) [[unlikely]] { + int total_cluster_size = 0, nl = 0; + for (unsigned int layer = 0; layer < 7; layer++) { + int cluster_size_per_layer = track.itsClsSizeInLayer(layer); + if (cluster_size_per_layer > 0) { + nl++; + } + total_cluster_size += cluster_size_per_layer; + } + + return (maxMeanITSClusterSize > static_cast(total_cluster_size) / static_cast(nl) * std::cos(std::atan(track.tgl()))); + } + return isElectron_TPChadrej(collision, track) || isElectron_TOFreq(collision, track); + } + + template + bool isElectron_TPChadrej(TCollision const& collision, TTrack const& track) + { + float tofNSigmaEl = mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]; + + if (track.tpcNSigmaEl() < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl()) { + return false; + } + if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi && track.tpcInnerParam() < max_pin_for_pion_rejection) { + return false; + } + if (minTPCNsigmaKa < track.tpcNSigmaKa() && track.tpcNSigmaKa() < maxTPCNsigmaKa) { + return false; + } + if (minTPCNsigmaPr < track.tpcNSigmaPr() && track.tpcNSigmaPr() < maxTPCNsigmaPr) { + return false; + } + if (track.hasTOF() && (maxTOFNsigmaEl < std::fabs(tofNSigmaEl))) { + return false; + } + return true; + } + + template + bool isElectron_TOFreq(TCollision const& collision, TTrack const& track) + { + float tofNSigmaEl = mapTOFNsigmaReassociated[std::make_pair(collision.globalIndex(), track.globalIndex())]; + + if (minTPCNsigmaPi < track.tpcNSigmaPi() && track.tpcNSigmaPi() < maxTPCNsigmaPi && (min_pin_for_pion_rejection < track.tpcInnerParam() && track.tpcInnerParam() < max_pin_for_pion_rejection)) { + return false; + } + return minTPCNsigmaEl < track.tpcNSigmaEl() && track.tpcNSigmaEl() < maxTPCNsigmaEl && std::fabs(tofNSigmaEl) < maxTOFNsigmaEl; + } + + template + void fillTrackInfo(TCollision const& collision, TTracks const& tracks) + { + + for (const auto& track : tracks) { + if (!checkTrack(collision, track)) { + continue; + } + + if (!isElectron(collision, track)) { + continue; + } + + fillTrackHistograms(track); + fillTrackTable(collision, track); + } + } + + template + void fillPairInfo(TCollision const& collision, TTracks1 const& tracks1, TTracks2 const& tracks2) + { + if constexpr (pairtype == 0) { // ULS + for (const auto& [t1, t2] : combinations(o2::soa::CombinationsFullIndexPolicy(tracks1, tracks2))) { + + if (!checkTrack(collision, t1) || !checkTrack(collision, t2)) { + continue; + } + + if (!isElectron(collision, t1) || !isElectron(collision, t2)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), dBz); + + fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMvsPhiV"), phiv, v12.M()); + + // to do: test if minMee > Mpion show effect on S/B + if (v12.M() < minMee || v12.M() > maxMee) { // don't store //|| v12.M() > maxMee + continue; + } + + fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMCutMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMCutMvsPhiV"), phiv, v12.M()); + + if (v12.M() < slope * phiv + intercept) { + continue; + } + + fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMPhiCutMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMPhiCutMvsPhiV"), phiv, v12.M()); + + if (t1.sign() > 0) { // for positron + if (std::find(acceptedPosTrackIds_per_collision.begin(), acceptedPosTrackIds_per_collision.end(), t1.globalIndex()) == acceptedPosTrackIds_per_collision.end()) { + fillTrackHistograms(t1); + acceptedPosTrackIds_per_collision.emplace_back(t1.globalIndex()); + } + } else { // for electron + if (std::find(acceptedNegTrackIds_per_collision.begin(), acceptedNegTrackIds_per_collision.end(), t1.globalIndex()) == acceptedNegTrackIds_per_collision.end()) { + fillTrackHistograms(t1); + acceptedNegTrackIds_per_collision.emplace_back(t1.globalIndex()); + } + } + + if (t2.sign() > 0) { // for positron + if (std::find(acceptedPosTrackIds_per_collision.begin(), acceptedPosTrackIds_per_collision.end(), t2.globalIndex()) == acceptedPosTrackIds_per_collision.end()) { + fillTrackHistograms(t2); + acceptedPosTrackIds_per_collision.emplace_back(t2.globalIndex()); + } + } else { // for electron + if (std::find(acceptedNegTrackIds_per_collision.begin(), acceptedNegTrackIds_per_collision.end(), t2.globalIndex()) == acceptedNegTrackIds_per_collision.end()) { + fillTrackHistograms(t2); + acceptedNegTrackIds_per_collision.emplace_back(t2.globalIndex()); + } + } + } // end of ULS pairing + } else { // LS + for (auto& [t1, t2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(tracks1, tracks2))) { + if (!checkTrack(collision, t1) || !checkTrack(collision, t2)) { + continue; + } + if (!isElectron(collision, t1) || !isElectron(collision, t2)) { + continue; + } + + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), o2::constants::physics::MassElectron); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(t1.px(), t1.py(), t1.pz(), t2.px(), t2.py(), t2.pz(), t1.sign(), t2.sign(), dBz); + fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMvsPt"), v12.M(), v12.Pt()); + fRegistry.fill(HIST("Pair/") + HIST(DileptonSigns[pairtype]) + HIST("hMvsPhiV"), phiv, v12.M()); + } // end of LS pairing + } + } + + template + void fillTrackHistograms(TTrack const& track) + { + float mcTunedTPCSignal = 0.f; + if constexpr (isMC) { + mcTunedTPCSignal = track.mcTunedTPCSignal(); + } + + fRegistry.fill(HIST("Track/hPt"), track.pt()); + fRegistry.fill(HIST("Track/hEtaPhi"), track.phi(), track.eta()); + fRegistry.fill(HIST("Track/hQoverPt"), track.sign() / track.pt()); + fRegistry.fill(HIST("Track/hRelDeltaPt"), track.pt(), track.sigma1Pt() * track.pt()); + fRegistry.fill(HIST("Track/hDCAxyz"), track.dcaXY(), track.dcaZ()); + fRegistry.fill(HIST("Track/hDCAxy_Pt"), track.pt(), track.dcaXY()); + fRegistry.fill(HIST("Track/hDCAz_Pt"), track.pt(), track.dcaZ()); + fRegistry.fill(HIST("Track/hDCAxyzSigma"), track.dcaXY() / std::sqrt(track.cYY()), track.dcaZ() / std::sqrt(track.cZZ())); + fRegistry.fill(HIST("Track/hDCAxyRes_Pt"), track.pt(), std::sqrt(track.cYY()) * 1e+4); // convert cm to um + fRegistry.fill(HIST("Track/hDCAzRes_Pt"), track.pt(), std::sqrt(track.cZZ()) * 1e+4); // convert cm to um + + fRegistry.fill(HIST("Track/hNclsTPC"), track.tpcNClsFound()); + fRegistry.fill(HIST("Track/hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("Track/hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("Track/hTPCNcr2Nf"), track.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("Track/hTPCNcls2Nf"), track.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("Track/hTPCNclsShared"), track.pt(), track.tpcFractionSharedCls()); + fRegistry.fill(HIST("Track/hTPCdEdx"), track.tpcInnerParam(), track.tpcSignal()); + fRegistry.fill(HIST("Track/hTPCdEdxMC"), track.tpcInnerParam(), mcTunedTPCSignal); + fRegistry.fill(HIST("Track/hTPCNsigmaEl"), track.tpcInnerParam(), track.tpcNSigmaEl()); + fRegistry.fill(HIST("Track/hTPCNsigmaPi"), track.tpcInnerParam(), track.tpcNSigmaPi()); + + fRegistry.fill(HIST("Track/hChi2TOF"), track.tofChi2()); + fRegistry.fill(HIST("Track/hTOFbeta"), track.p(), track.beta()); + fRegistry.fill(HIST("Track/hTOFNsigmaEl"), track.p(), track.tofNSigmaEl()); + fRegistry.fill(HIST("Track/hTOFNsigmaPi"), track.p(), track.tofNSigmaPi()); + + fRegistry.fill(HIST("Track/hNclsITS"), track.itsNCls()); + fRegistry.fill(HIST("Track/hChi2ITS"), track.itsChi2NCl()); + fRegistry.fill(HIST("Track/hITSClusterMap"), track.itsClusterMap()); + + int totalClusterSize = 0, nl = 0; + for (unsigned int layer = 0; layer < 7; layer++) { // o2-linter: disable=magic-number (number of ITS layers) + int clusterSizePerLayer = track.itsClsSizeInLayer(layer); + if (clusterSizePerLayer > 0) { + nl++; + } + totalClusterSize += clusterSizePerLayer; + } + + int totalClusterSizeIb = 0, nl_ib = 0; + for (unsigned int layer = 0; layer < 3; layer++) { // o2-linter: disable=magic-number (number of inner barrel layers) + int clusterSizePerLayer = track.itsClsSizeInLayer(layer); + if (clusterSizePerLayer > 0) { + nl_ib++; + } + totalClusterSizeIb += clusterSizePerLayer; + } + + int totalClusterSizeOb = 0, nlOb = 0; + for (unsigned int layer = 3; layer < 7; layer++) { // o2-linter: disable=magic-number (number of outer barrel layers) + int clusterSizePerLayer = track.itsClsSizeInLayer(layer); + if (clusterSizePerLayer > 0) { + nlOb++; + } + totalClusterSizeOb += clusterSizePerLayer; + } + fRegistry.fill(HIST("Track/hMeanClusterSizeITS"), track.p(), static_cast(totalClusterSize) / static_cast(nl) * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/hMeanClusterSizeITSib"), track.p(), static_cast(totalClusterSizeIb) / static_cast(nl_ib) * std::cos(std::atan(track.tgl()))); + fRegistry.fill(HIST("Track/hMeanClusterSizeITSob"), track.p(), static_cast(totalClusterSizeOb) / static_cast(nlOb) * std::cos(std::atan(track.tgl()))); + } + + template + void fillTrackTable(TCollision const& collision, TTrack const& track) + { + emprimaryelectrons(collision.globalIndex(), track.globalIndex(), track.sign(), + track.pt(), track.eta(), track.phi(), track.dcaXY(), track.dcaZ(), track.cYY(), track.cZY(), track.cZZ(), + track.tpcNClsFindable(), track.tpcNClsFindableMinusFound(), track.tpcNClsFindableMinusCrossedRows(), track.tpcNClsShared(), + track.tpcChi2NCl(), track.tpcInnerParam(), + track.tpcSignal(), track.tpcNSigmaEl(), track.tpcNSigmaPi(), + track.beta(), track.tofNSigmaEl(), + track.itsClusterSizes(), track.itsChi2NCl(), track.tofChi2(), track.detectorMap()); + + if constexpr (isMC) { + emprimaryelectronsDeDxMC(track.mcTunedTPCSignal()); + } + } + + std::vector acceptedPosTrackIds_per_collision; + std::vector acceptedNegTrackIds_per_collision; + // Filter trackFilter = minpt < o2::aod::track::pt && nabs(o2::aod::track::eta) < maxeta && o2::aod::track::itsChi2NCl < maxchi2its && ncheckbit(aod::track::v001::detectorMap, (uint8_t)o2::aod::track::ITS) == true && nabs(o2::aod::track::dcaXY) < dca_xy_max && nabs(o2::aod::track::dcaZ) < dca_z_max; + // Filter trackFilter + // using MyFilteredTracks = soa::Filtered; + o2::framework::Partition posTracks = o2::aod::track::signed1Pt > 0.f; + o2::framework::Partition negTracks = o2::aod::track::signed1Pt < 0.f; + + std::unordered_map mapCollisionTime; + std::unordered_map mapCollisionTimeError; + + std::map, float> mapTOFNsigmaReassociated; // map pair(collisionId, trackId) -> tof n sigma + std::map, float> mapTOFBetaReassociated; // map pair(collisionId, trackId) -> tof beta + + // ---------- for data ---------- + void processRec(MyCollisions const& collisions, MyBCs const& bcs, MyTracks const& tracks, TV0PhotonsKF const& v0photons, o2::aod::TrackAssoc const& trackIndices) + { + initCCDB(bcs.iteratorAt(0)); + mTOFResponse->processSetup(bcs.iteratorAt(0)); + + for (const auto& track : tracks) { + mapCollisionTime.try_emplace(track.collisionId(), track.tofEvTime()); + mapCollisionTimeError.try_emplace(track.collisionId(), track.tofEvTimeErr()); + } + calculateTOFNSigmaWithReassociation(collisions, bcs, tracks, trackIndices); + + for (const auto& collision : collisions) { + if (!collision.isSelected()) { + continue; + } + + auto varFillingMode = static_cast(fillingMode.value); + + const auto& v0photons_per_coll = v0photons.sliceBy(perCol_pcm, collision.globalIndex()); + const auto& posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + const auto& negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + const auto& slicedTracks = tracks.sliceBy(perTracksCollision, collision.globalIndex()); + acceptedPosTrackIds_per_collision.reserve(posTracks_per_coll.size()); + acceptedNegTrackIds_per_collision.reserve(negTracks_per_coll.size()); + + auto iterEp = tracks.begin(); + auto iterEm = tracks.begin(); + auto iterTrack = tracks.begin(); + auto iterPhoton = v0photons.begin(); + + switch (varFillingMode) { + case enumFillingMode::SingleTrack: + fillTrackInfo(collision, slicedTracks); + break; + case enumFillingMode::EpEmPairs: + fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS + if (fillLS) { + fillPairInfo(collision, posTracks_per_coll, posTracks_per_coll); // LS++ + fillPairInfo(collision, negTracks_per_coll, negTracks_per_coll); // LS-- + } + if ((!acceptedPosTrackIds_per_collision.empty() && !acceptedNegTrackIds_per_collision.empty())) { + for (const auto& posId : acceptedPosTrackIds_per_collision) { + iterEp.setCursor(posId); + fillTrackTable(collision, iterEp); + } + for (const auto& eleId : acceptedNegTrackIds_per_collision) { + iterEm.setCursor(eleId); + fillTrackTable(collision, iterEm); + } + } + break; + case enumFillingMode::EpEmPairsAndPhoton: + std::set tracksToFill; + + fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS + if (fillLS) { + fillPairInfo(collision, posTracks_per_coll, posTracks_per_coll); // LS++ + fillPairInfo(collision, negTracks_per_coll, negTracks_per_coll); // LS-- + } + if (v0photons_per_coll.size() >= 1 && ((!acceptedPosTrackIds_per_collision.empty() && !acceptedNegTrackIds_per_collision.empty()))) { + if (!fillWithEtaMassCut) { + for (const auto& posId : acceptedPosTrackIds_per_collision) { + iterEp.setCursor(posId); + fillTrackTable(collision, iterEp); + } + for (const auto& eleId : acceptedNegTrackIds_per_collision) { + iterEm.setCursor(eleId); + fillTrackTable(collision, iterEm); + } + } else { + for (const auto& posId : acceptedPosTrackIds_per_collision) { + iterEp.setCursor(posId); + ROOT::Math::PtEtaPhiMVector vEp(iterEp.pt(), iterEp.eta(), iterEp.phi(), o2::constants::physics::MassElectron); + for (const auto& eleId : acceptedNegTrackIds_per_collision) { + iterEm.setCursor(eleId); + ROOT::Math::PtEtaPhiMVector vEm(iterEm.pt(), iterEm.eta(), iterEm.phi(), o2::constants::physics::MassElectron); + for (const auto& photonId : v0photons_per_coll) { + iterPhoton.setCursor(photonId.globalIndex()); + ROOT::Math::PtEtaPhiMVector vPhoton(iterPhoton.pt(), iterPhoton.eta(), iterPhoton.phi(), o2::constants::physics::MassPhoton); + ROOT::Math::PtEtaPhiMVector vTotal = vEp + vEm + vPhoton; + + if (vTotal.M() < minMeegamma || vTotal.M() > maxMeegamma) { // don't store + continue; + } + tracksToFill.insert(posId); // store independently + tracksToFill.insert(eleId); + } + } + } + } + } + if (fillWithEtaMassCut) { + for (const auto& trackId : tracksToFill) { + iterTrack.setCursor(trackId); + fillTrackTable(collision, iterTrack); + } + } + break; + } + + acceptedPosTrackIds_per_collision.clear(); + acceptedNegTrackIds_per_collision.clear(); + } // end of collision loop + mapCollisionTime.clear(); + mapCollisionTimeError.clear(); + mapTOFNsigmaReassociated.clear(); + mapTOFBetaReassociated.clear(); + } + PROCESS_SWITCH(skimmerPrimaryElectronFromDalitzEE, processRec, "process reconstructed info only", false); // standalone + + // void processRec_SWT(MyCollisionsWithSWT const& collisions, MyBCs const& bcs, MyTracks const& tracks, aod::V0PhotonsKF const& v0photons, aod::TrackAssoc const& trackIndices) + // { + // initCCDB(bcs.iteratorAt(0)); + + // mTOFResponse->processSetup(bcs.iteratorAt(0)); + // for (const auto& track : tracks) { + // mapCollisionTime.try_emplace(track.collisionId(), track.tofEvTime()); + // mapCollisionTimeError.try_emplace(track.collisionId(), track.tofEvTimeErr()); + // } + // calculateTOFNSigmaWithReassociation(collisions, bcs, tracks, trackIndices); + + // for (const auto& collision : collisions) { + // if (!collision.isSelected()) { + // continue; + // } + + // if (collision.swtaliastmp_raw() == 0) { + // continue; + // } + + // const auto& v0photons_per_coll = v0photons.sliceBy(perCol_pcm, collision.globalIndex()); + // const auto& posTracks_per_coll = posTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + // const auto& negTracks_per_coll = negTracks->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + // const auto& slicedTracks = tracks.sliceBy(perTracksCollision, collision.globalIndex()); + // acceptedPosTrackIds_per_collision.reserve(posTracks_per_coll.size()); + // acceptedNegTrackIds_per_collision.reserve(negTracks_per_coll.size()); + + // if(!fillWithPairs){ + // fillTrackInfo(collision, slicedTracks); + // }else{ + // fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS + // if (fillLS) { + // fillPairInfo(collision, posTracks_per_coll, posTracks_per_coll); // LS++ + // fillPairInfo(collision, negTracks_per_coll, negTracks_per_coll); // LS-- + // } + + // if ((v0photons_per_coll.size() >= 1 && !acceptedPosTrackIds_per_collision.empty() && !acceptedNegTrackIds_per_collision.empty()) || (acceptedPosTrackIds_per_collision.size() >= 2 && acceptedNegTrackIds_per_collision.size() >= 2)) { + // // LOGF(info, "v0photons_per_coll.size() = %d, acceptedPosTrackIds_per_collision.size() = %d, acceptedNegTrackIds_per_collision.size() = %d", v0photons_per_coll.size(), acceptedPosTrackIds_per_collision.size(), acceptedNegTrackIds_per_collision.size()); + // for (const auto& posId : acceptedPosTrackIds_per_collision) { + // const auto& pos = tracks.rawIteratorAt(posId); + // fillTrackTable(collision, pos); + // } + // for (const auto& eleId : acceptedNegTrackIds_per_collision) { + // const auto& ele = tracks.rawIteratorAt(eleId); + // fillTrackTable(collision, ele); + // } + // } + // } + + // acceptedPosTrackIds_per_collision.clear(); + // acceptedNegTrackIds_per_collision.clear(); + + // } // end of collision loop + // } + // PROCESS_SWITCH(skimmerPrimaryElectronFromDalitzEE, processRec_SWT, "process reconstructed info with CEFP", false); // with cefp + + // using MyFilteredTracksMC = soa::Filtered; + o2::framework::Partition posTracksMC = o2::aod::track::signed1Pt > 0.f; + o2::framework::Partition negTracksMC = o2::aod::track::signed1Pt < 0.f; + // ---------- for MC ---------- + void processMC(MyCollisionsMC const& collisions, o2::aod::McCollisions const&, MyBCs const& bcs, MyTracksMC const& tracks, TV0PhotonsKF const& v0photons, o2::aod::TrackAssoc const& trackIndices, o2::aod::McParticles const&) + { + uint64_t nCollisSel = 0; + uint64_t nNoMcColl = 0; + uint64_t nProcessedCollisions = 0; + uint64_t nCheckTrack = 0; + + initCCDB(bcs.iteratorAt(0)); + + mTOFResponse->processSetup(bcs.iteratorAt(0)); + for (const auto& track : tracks) { + mapCollisionTime.try_emplace(track.collisionId(), track.tofEvTime()); + mapCollisionTimeError.try_emplace(track.collisionId(), track.tofEvTimeErr()); + } + calculateTOFNSigmaWithReassociation(collisions, bcs, tracks, trackIndices); + + for (const auto& collision : collisions) { + if (!collision.has_mcCollision()) { + nNoMcColl++; + continue; + } + + if (!collision.isSelected()) { + nCollisSel++; + continue; + } + nProcessedCollisions++; + + auto varFillingMode = static_cast(fillingMode.value); + + const auto& v0photons_per_coll = v0photons.sliceBy(perCol_pcm, collision.globalIndex()); + const auto& posTracks_per_coll = posTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + const auto& negTracks_per_coll = negTracksMC->sliceByCached(o2::aod::track::collisionId, collision.globalIndex(), cache); + const auto& slicedTracks = tracks.sliceBy(perTracksCollision, collision.globalIndex()); + acceptedPosTrackIds_per_collision.reserve(posTracks_per_coll.size()); + acceptedNegTrackIds_per_collision.reserve(negTracks_per_coll.size()); + + auto iterEp = tracks.begin(); + auto iterEm = tracks.begin(); + auto iterTrack = tracks.begin(); + auto iterPhoton = v0photons.begin(); + + switch (varFillingMode) { + case enumFillingMode::SingleTrack: + fillTrackInfo(collision, slicedTracks); + break; + case enumFillingMode::EpEmPairs: + fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS + if (fillLS) { + fillPairInfo(collision, posTracks_per_coll, posTracks_per_coll); // LS++ + fillPairInfo(collision, negTracks_per_coll, negTracks_per_coll); // LS-- + } + if ((!acceptedPosTrackIds_per_collision.empty() && !acceptedNegTrackIds_per_collision.empty())) { + for (const auto& posId : acceptedPosTrackIds_per_collision) { + iterEp.setCursor(posId); + fillTrackTable(collision, iterEp); + } + for (const auto& eleId : acceptedNegTrackIds_per_collision) { + iterEm.setCursor(eleId); + fillTrackTable(collision, iterEm); + } + } + break; + case enumFillingMode::EpEmPairsAndPhoton: + std::set tracksToFill; + + fillPairInfo(collision, posTracks_per_coll, negTracks_per_coll); // ULS + if (fillLS) { + fillPairInfo(collision, posTracks_per_coll, posTracks_per_coll); // LS++ + fillPairInfo(collision, negTracks_per_coll, negTracks_per_coll); // LS-- + } + if (v0photons_per_coll.size() >= 1 && ((!acceptedPosTrackIds_per_collision.empty() && !acceptedNegTrackIds_per_collision.empty()))) { + if (!fillWithEtaMassCut) { + for (const auto& posId : acceptedPosTrackIds_per_collision) { + iterEp.setCursor(posId); + fillTrackTable(collision, iterEp); + } + for (const auto& eleId : acceptedNegTrackIds_per_collision) { + iterEm.setCursor(eleId); + fillTrackTable(collision, iterEm); + } + } else { + for (const auto& posId : acceptedPosTrackIds_per_collision) { + iterEp.setCursor(posId); + ROOT::Math::PtEtaPhiMVector vEp(iterEp.pt(), iterEp.eta(), iterEp.phi(), o2::constants::physics::MassElectron); + for (const auto& eleId : acceptedNegTrackIds_per_collision) { + iterEm.setCursor(eleId); + ROOT::Math::PtEtaPhiMVector vEm(iterEm.pt(), iterEm.eta(), iterEm.phi(), o2::constants::physics::MassElectron); + for (const auto& photonId : v0photons_per_coll) { + iterPhoton.setCursor(photonId.globalIndex()); + ROOT::Math::PtEtaPhiMVector vPhoton(iterPhoton.pt(), iterPhoton.eta(), iterPhoton.phi(), o2::constants::physics::MassPhoton); + ROOT::Math::PtEtaPhiMVector vTotal = vEp + vEm + vPhoton; + + if (vTotal.M() < minMeegamma || vTotal.M() > maxMeegamma) { // don't store + continue; + } + tracksToFill.insert(posId); // store independently + tracksToFill.insert(eleId); + } + } + } + } + } + if (fillWithEtaMassCut) { + for (const auto& trackId : tracksToFill) { + iterTrack.setCursor(trackId); + fillTrackTable(collision, iterTrack); + } + } + break; + } + + acceptedPosTrackIds_per_collision.clear(); + acceptedNegTrackIds_per_collision.clear(); + } // end of collision loop + mapCollisionTime.clear(); + mapCollisionTimeError.clear(); + mapTOFNsigmaReassociated.clear(); + mapTOFBetaReassociated.clear(); + + LOG(info) << "Total collisions: " << collisions.size(); + LOG(info) << "No MC collision: " << nNoMcColl; + LOG(info) << "Rejected by selection: " << nCollisSel; + LOG(info) << "Processed collisions: " << nProcessedCollisions; + LOG(info) << "Invalid track: " << nCheckTrack; + } + PROCESS_SWITCH(skimmerPrimaryElectronFromDalitzEE, processMC, "process reconstructed and MC info ", true); +}; + +#endif // PWGEM_PHOTONMESON_TABLEPRODUCER_SKIMMERPRIMARYELECTRONFROMDALITZEE_H_ diff --git a/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEETmpTable.cxx b/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEETmpTable.cxx new file mode 100644 index 00000000000..4587e8d6975 --- /dev/null +++ b/PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEETmpTable.cxx @@ -0,0 +1,28 @@ +// 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. + +/// \file skimmerPrimaryElectronFromDalitzEETmpTable.cxx +/// \brief write electrons for Dalitz into a temporary table that is then used for event skimming +/// \author joshua.konig@cern.ch + +#include "PWGEM/PhotonMeson/TableProducer/skimmerPrimaryElectronFromDalitzEE.h" + +using namespace o2::framework; +using namespace o2::aod; +using namespace o2::framework::expressions; + +WorkflowSpec defineDataProcessing(ConfigContext const& context) +{ + o2::pid::tof::TOFResponseImpl::metadataInfo.initMetadata(context); + + return WorkflowSpec{ + adaptAnalysisTask>(context, TaskName{"skimmer-primary-electron-from-dalitzee-tmptable"})}; +} diff --git a/PWGEM/PhotonMeson/Tasks/CMakeLists.txt b/PWGEM/PhotonMeson/Tasks/CMakeLists.txt index 328f039590f..dde484f2daf 100644 --- a/PWGEM/PhotonMeson/Tasks/CMakeLists.txt +++ b/PWGEM/PhotonMeson/Tasks/CMakeLists.txt @@ -31,11 +31,6 @@ o2physics_add_dpl_workflow(pcm-qc PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(pcm-qc-mc - SOURCES pcmQCMC.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(dalitz-ee-qc SOURCES dalitzEEQC.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore O2Physics::PWGEMDileptonCore @@ -126,21 +121,16 @@ o2physics_add_dpl_workflow(tag-and-probe PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore O2Physics::MLCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(material-budget - SOURCES MaterialBudget.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore - COMPONENT_NAME Analysis) - -o2physics_add_dpl_workflow(material-budget-mc - SOURCES MaterialBudgetMC.cxx - PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore - COMPONENT_NAME Analysis) - o2physics_add_dpl_workflow(check-mc-v0 SOURCES CheckMCV0.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DCAFitter O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(task-photon-flow + SOURCES taskPhotonFlow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(pi0-flow-emc SOURCES taskPi0FlowEMC.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore @@ -200,3 +190,8 @@ o2physics_add_dpl_workflow(emcal-mc-sanity-check SOURCES emcalMcSanityCheck.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(emcal-mc-task + SOURCES emcalMcTask.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGEMPhotonMesonCore + COMPONENT_NAME Analysis) diff --git a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCEMCEMC.cxx b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCEMCEMC.cxx index 0857f27f1a5..9c4398e75a3 100644 --- a/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCEMCEMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/Pi0EtaToGammaGammaMCEMCEMC.cxx @@ -27,7 +27,7 @@ using namespace o2::aod; using namespace o2::framework; using namespace o2::aod::pwgem::photonmeson::photonpair; -using MyEMCClusters = soa::Join; +using MyEMCClusters = soa::Join; WorkflowSpec defineDataProcessing(ConfigContext const& context) { diff --git a/PWGEM/PhotonMeson/Tasks/SinglePhotonMC.cxx b/PWGEM/PhotonMeson/Tasks/SinglePhotonMC.cxx index 40918d54757..d5619fd4edb 100644 --- a/PWGEM/PhotonMeson/Tasks/SinglePhotonMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/SinglePhotonMC.cxx @@ -17,9 +17,7 @@ #include "PWGEM/Dilepton/Utils/MCUtilities.h" #include "PWGEM/PhotonMeson/Core/CutsLibrary.h" -#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" #include "PWGEM/PhotonMeson/Core/HistogramsLibrary.h" -#include "PWGEM/PhotonMeson/Core/PHOSPhotonCut.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" #include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" diff --git a/PWGEM/PhotonMeson/Tasks/TagAndProbe.cxx b/PWGEM/PhotonMeson/Tasks/TagAndProbe.cxx index 8de6e48e99e..6bb206de9dc 100644 --- a/PWGEM/PhotonMeson/Tasks/TagAndProbe.cxx +++ b/PWGEM/PhotonMeson/Tasks/TagAndProbe.cxx @@ -140,7 +140,7 @@ struct TagAndProbe { THashList* list_pair_subsys_photoncut = o2::aod::pwgem::photon::histogram::AddHistClass(list_pair, photon_cut_name.data()); for (auto& cut3 : paircuts) { - std::string pair_cut_name = cut3.getName(); + std::string const& pair_cut_name = cut3.getName(); o2::aod::pwgem::photon::histogram::AddHistClass(list_pair_subsys_photoncut, pair_cut_name.data()); auto* list_pair_subsys_paircut = dynamic_cast(list_pair_subsys_photoncut->FindObject(pair_cut_name.data())); o2::aod::pwgem::photon::histogram::DefineHistograms(list_pair_subsys_paircut, "tag_and_probe", pairname.data()); diff --git a/PWGEM/PhotonMeson/Tasks/emcalMcTask.cxx b/PWGEM/PhotonMeson/Tasks/emcalMcTask.cxx new file mode 100644 index 00000000000..073479c2c9e --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/emcalMcTask.cxx @@ -0,0 +1,371 @@ +// 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. + +/// \file emcalMcTask.cxx +/// \brief Analysis task for to obtain cluster properties from MC identified particles like photons and electrons +/// \author M. Hemmer, marvin.hemmer@cern.ch + +#include "PWGEM/PhotonMeson/Core/EMBitFlags.h" +#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" +#include "PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::photon; + +namespace o2::em::emcal::mc +{ + +enum ParticleType : int { + kPhoton = 0, + kElectron, + kPositron, + kPi0, + kEta, + kOmega, + kPion, + kKaon, + kOther, + kNParticleTypes +}; +} // namespace o2::em::emcal::mc + +enum CentralityEstimator { + None = 0, + CFT0A = 1, + CFT0C = 2, + CFT0M = 3, + NCentralityEstimators = 4 +}; + +enum class MapLevel { + kGood = 1, + kNoBad = 2, + kInEMC = 3, + kAll = 4 +}; + +struct EmcalMcTask { + // configurable axis + ConfigurableAxis thnConfigAxisE{"thnConfigAxisE", {400, 0., 20.}, "energy axis"}; + ConfigurableAxis thnConfigAxisEtaDiff{"thnConfigAxisEtaDiff", {300, -1., 2.}, "(eta rec - eta true)"}; + ConfigurableAxis thnConfigAxisPhiDiff{"thnConfigAxisPhiDiff", {300, -1., 2.}, "(phi rec - phi true"}; + ConfigurableAxis thnConfigAxisM02{"thnConfigAxisM02", {100, 0.0, 1.0}, "m02 mass axis"}; + ConfigurableAxis thnConfigAxisCent{"thnConfigAxisCent", {20, 0., 100.}, "centrality axis for the current event"}; + ConfigurableAxis thnConfigAxisMult{"thnConfigAxisMult", {60, 0., 60000.}, "multiplicity axis for the current event"}; + Configurable useCent{"useCent", false, "flag to enable usage of centrality instead of multiplicity as axis."}; + + EMPhotonEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcuts"; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgRequireEMCReadoutInMB{"cfgRequireEMCReadoutInMB", true, "require the EMC to be read out in an MB collision (kTVXinEMC)"}; + Configurable cfgRequireEMCHardwareTriggered{"cfgRequireEMCHardwareTriggered", false, "require the EMC to be hardware triggered (kEMC7 or kDMC7)"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -1, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + Configurable cfgMinCent{"cfgMinCent", 0, "min. centrality (%)"}; + Configurable cfgMaxCent{"cfgMaxCent", 90, "max. centrality (%)"}; + Configurable centEstimator{"centEstimator", 2, "Centrality estimation (FT0A: 1, FT0C: 2, FT0M: 3)"}; + } eventcuts; + + EMCPhotonCut fEMCCut; + struct : ConfigurableGroup { + std::string prefix = "emccuts"; + Configurable clusterDefinition{"clusterDefinition", "kV3MostSplitSmallestTimeDiff", "Clusterizer to be selected, e.g. V3Default"}; + Configurable cfgEMCminTime{"cfgEMCminTime", -25., "Minimum cluster time for EMCal time cut"}; + Configurable cfgEMCmaxTime{"cfgEMCmaxTime", +30., "Maximum cluster time for EMCal time cut"}; + Configurable cfgEMCminM02{"cfgEMCminM02", 0.1, "Minimum M02 for EMCal M02 cut"}; + Configurable cfgEMCmaxM02{"cfgEMCmaxM02", 0.7, "Maximum M02 for EMCal M02 cut"}; + Configurable cfgEMCminE{"cfgEMCminE", 0.7, "Minimum cluster energy for EMCal energy cut"}; + Configurable cfgEMCminNCell{"cfgEMCminNCell", 1, "Minimum number of cells per cluster for EMCal NCell cut"}; + Configurable> cfgEMCTMEta{"cfgEMCTMEta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable> cfgEMCTMPhi{"cfgEMCTMPhi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable> emcSecTMEta{"emcSecTMEta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable> emcSecTMPhi{"emcSecTMPhi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable cfgEMCEoverp{"cfgEMCEoverp", 1.75, "Minimum cluster energy over track momentum for EMCal track matching"}; + Configurable cfgEMCUseExoticCut{"cfgEMCUseExoticCut", true, "FLag to use the EMCal exotic cluster cut"}; + Configurable cfgEMCUseTM{"cfgEMCUseTM", false, "flag to use EMCal track matching cut or not"}; + Configurable emcUseSecondaryTM{"emcUseSecondaryTM", false, "flag to use EMCal secondary track matching cut or not"}; + Configurable cfgEnableQA{"cfgEnableQA", false, "flag to turn QA plots on/off"}; + } emccuts; + + SliceCache cache; + + using EMCalPhotons = soa::Join; + + using Colls = soa::Join; + + using McColls = o2::soa::Join; + using McParticles = EMMCParticles; + + PresliceOptional perCollisionEMC = o2::aod::emccluster::pmeventId; + PresliceOptional perEMCClusterMT = o2::aod::mintm::minClusterId; + PresliceOptional perEMCClusterMS = o2::aod::mintm::minClusterId; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + int mRunNumber{-1}; + float dBz{0.f}; + + static constexpr std::array(o2::em::emcal::mc::ParticleType::kNParticleTypes)> kSubDirs = { + "photon/", "electron/", "positron/", "pi0/", + "eta/", "omega/", "pion/", "kaon/", "other/"}; + + void defineEMEventCut() + { + fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + fEMEventCut.SetRequireEMCReadoutInMB(eventcuts.cfgRequireEMCReadoutInMB); + fEMEventCut.SetRequireEMCHardwareTriggered(eventcuts.cfgRequireEMCHardwareTriggered); + } + + void defineEMCCut() + { + fEMCCut = EMCPhotonCut("fEMCCut", "fEMCCut"); + + fEMCCut.SetTrackMatchingEtaParams(emccuts.cfgEMCTMEta->at(0), emccuts.cfgEMCTMEta->at(1), emccuts.cfgEMCTMEta->at(2)); + fEMCCut.SetTrackMatchingPhiParams(emccuts.cfgEMCTMPhi->at(0), emccuts.cfgEMCTMPhi->at(1), emccuts.cfgEMCTMPhi->at(2)); + + fEMCCut.SetSecTrackMatchingEtaParams(emccuts.emcSecTMEta->at(0), emccuts.emcSecTMEta->at(1), emccuts.emcSecTMEta->at(2)); + fEMCCut.SetSecTrackMatchingPhiParams(emccuts.emcSecTMPhi->at(0), emccuts.emcSecTMPhi->at(1), emccuts.emcSecTMPhi->at(2)); + fEMCCut.SetMinEoverP(emccuts.cfgEMCEoverp); + + fEMCCut.SetMinE(emccuts.cfgEMCminE); + fEMCCut.SetMinNCell(emccuts.cfgEMCminNCell); + fEMCCut.SetM02Range(emccuts.cfgEMCminM02, emccuts.cfgEMCmaxM02); + fEMCCut.SetTimeRange(emccuts.cfgEMCminTime, emccuts.cfgEMCmaxTime); + fEMCCut.SetUseExoticCut(emccuts.cfgEMCUseExoticCut); + fEMCCut.SetClusterizer(emccuts.clusterDefinition); + fEMCCut.SetUseTM(emccuts.cfgEMCUseTM.value); // disables or enables TM + fEMCCut.SetUseSecondaryTM(emccuts.emcUseSecondaryTM.value); // disables or enables secondary TM + fEMCCut.SetDoQA(emccuts.cfgEnableQA.value); + } + + void init(InitContext&) + { + mRunNumber = 0; + dBz = 0; + + defineEMEventCut(); + defineEMCCut(); + fEMCCut.addQAHistograms(®istry); + o2::aod::pwgem::photonmeson::utils::eventhistogram::addEventHistograms(®istry); + + const AxisSpec thnAxisERec{thnConfigAxisE, "#it{E}_{Rec} (GeV)"}; + + const AxisSpec thnAxisM02{thnConfigAxisM02, "#it{M}_{02}"}; + + const AxisSpec thnAxisEtaDiff{thnConfigAxisEtaDiff, "#it{#eta}_{Rec} - #it{#eta}_{Gen}"}; + const AxisSpec thnAxisPhiDiff{thnConfigAxisPhiDiff, "#it{#varphi}_{Rec} - #it{#varphi}_{Gen}"}; + + AxisSpec thnAxisCentOrMult{1, 0., 1., "Centrality/Multiplicity"}; // placeholder, overwritten in init + if (useCent.value) { + // PbPb: use centrality + thnAxisCentOrMult = {thnConfigAxisCent, "Centrality (%)"}; + } else { + // pp: use multiplicity + thnAxisCentOrMult = {thnConfigAxisMult, "FT0C Multiplicity"}; + } + + registry.add("photon/hM02", "cluster m02 vs energy vs cent/mult", HistType::kTH3F, {thnAxisM02, thnAxisERec, thnAxisCentOrMult}); + registry.add("photon/hEtaRel", "relative #eta vs energy vs cent/mult", HistType::kTH3F, {thnAxisEtaDiff, thnAxisERec, thnAxisCentOrMult}); + registry.add("photon/hPhiRel", "relative #varphi vs energy vs cent/mult", HistType::kTH3F, {thnAxisPhiDiff, thnAxisERec, thnAxisCentOrMult}); + + registry.addClone("photon/", "electron/"); + registry.addClone("photon/", "positron/"); + registry.addClone("photon/", "pi0/"); + registry.addClone("photon/", "eta/"); + registry.addClone("photon/", "omega/"); + registry.addClone("photon/", "pion/"); + registry.addClone("photon/", "kaon/"); + registry.addClone("photon/", "other/"); + + }; // end init + + template + float getCentralityOrMultiplicity(TCollision const& collision) + { + if (useCent.value) { + return getCentrality(collision); + } + // pp: use raw FT0C multiplicity + return collision.multFT0C(); + } + + /// Get the centrality + /// \param collision is the collision with the centrality information + template + float getCentrality(TCollision const& collision) + { + float cent = -999.; + switch (eventcuts.centEstimator) { + case CentralityEstimator::CFT0M: + cent = collision.centFT0M(); + break; + case CentralityEstimator::CFT0A: + cent = collision.centFT0A(); + break; + case CentralityEstimator::CFT0C: + cent = collision.centFT0C(); + break; + default: + LOG(warning) << "Centrality estimator not valid. Possible values are T0M, T0A, T0C. Fallback to T0C"; + cent = collision.centFT0C(); + break; + } + return cent; + } + + /// \brief check if standard event cuts + FT0 occupancy + centrality + QVec good is + /// \param collision collision that will be checked + /// \return true if collision survives all checks, otherwise false + template + bool isFullEventSelected(TCollision const& collision, bool fillHisto = false) + { + if (fillHisto) { + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(®istry, collision); + } + if (!(fEMEventCut.IsSelected(collision))) { + // general event selection + return false; + } + if (!(eventcuts.cfgFT0COccupancyMin <= collision.ft0cOccupancyInTimeRange() && collision.ft0cOccupancyInTimeRange() < eventcuts.cfgFT0COccupancyMax)) { + // occupancy selection + return false; + } + float centOrMult = getCentralityOrMultiplicity(collision); + if (useCent && (centOrMult < eventcuts.cfgMinCent || centOrMult > eventcuts.cfgMaxCent)) { + // event selection + return false; + } + if (fillHisto) { + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(®istry, collision); + registry.fill(HIST("Event/before/hCollisionCounter"), 12.0); // accepted + registry.fill(HIST("Event/after/hCollisionCounter"), 12.0); // accepted + } + return true; + } + + // One templated fill function instead of 9 copy-pasted blocks + template + void fillClusterHistos(TCluster const& cluster, TMC const& mcPart, float centOrMult) + { + static constexpr std::string_view SubDir = kSubDirs[type]; + + registry.fill(HIST(SubDir) + HIST("hM02"), cluster.m02(), cluster.e(), centOrMult); + registry.fill(HIST(SubDir) + HIST("hEtaRel"), cluster.eta() - mcPart.eta(), cluster.e(), centOrMult); + registry.fill(HIST(SubDir) + HIST("hPhiRel"), cluster.phi() - mcPart.phi(), cluster.e(), centOrMult); + } + + // PCM-EMCal same event + void processEmcal(Colls const& collisions, EMCalPhotons const& clusters, MinMTracks const& matchedPrims, MinMSTracks const& matchedSeconds, EMMCParticles const& mcParticles) + { + if (clusters.size() <= 0) { + LOG(info) << "Skipping DF because there are not photons!"; + return; + } + EMBitFlags emcFlags(clusters.size()); + if (clusters.size() > 0) { + fEMCCut.AreSelectedRunning(emcFlags, clusters, matchedPrims, matchedSeconds, ®istry); + } + + // create iterators for photon mc particles + auto mcPhoton1 = mcParticles.begin(); + + for (const auto& collision : collisions) { + isFullEventSelected(collision, true); + + float centOrMult = getCentralityOrMultiplicity(collision); + + auto photonsEMCPerCollision = clusters.sliceBy(perCollisionEMC, collision.globalIndex()); + + for (const auto& photonEMC : photonsEMCPerCollision) { + if (!(emcFlags.test(photonEMC.globalIndex()))) { + continue; + } + if (photonEMC.emmcparticleIds().empty()) { + // this is a cluster with just noise, skip + continue; + } + // we only want to look at the largest contribution + mcPhoton1.setCursor(photonEMC.emmcparticleIds()[0]); + + if (std::abs(mcPhoton1.pdgCode()) == PDG_t::kGamma) { + fillClusterHistos(photonEMC, mcPhoton1, centOrMult); + } else if (mcPhoton1.pdgCode() == PDG_t::kElectron) { + fillClusterHistos(photonEMC, mcPhoton1, centOrMult); + } else if (mcPhoton1.pdgCode() == PDG_t::kPositron) { + fillClusterHistos(photonEMC, mcPhoton1, centOrMult); + } else if (std::abs(mcPhoton1.pdgCode()) == PDG_t::kPi0) { + fillClusterHistos(photonEMC, mcPhoton1, centOrMult); + } else if (std::abs(mcPhoton1.pdgCode()) == o2::constants::physics::Pdg::kEta) { + fillClusterHistos(photonEMC, mcPhoton1, centOrMult); + } else if (std::abs(mcPhoton1.pdgCode()) == o2::constants::physics::Pdg::kOmega) { + fillClusterHistos(photonEMC, mcPhoton1, centOrMult); + } else if (std::abs(mcPhoton1.pdgCode()) == PDG_t::kPiPlus) { + fillClusterHistos(photonEMC, mcPhoton1, centOrMult); + } else if (std::abs(mcPhoton1.pdgCode()) == PDG_t::kKPlus) { + fillClusterHistos(photonEMC, mcPhoton1, centOrMult); + } else { + fillClusterHistos(photonEMC, mcPhoton1, centOrMult); + } + } // for (const auto& photonEMC : photonsEMCPerCollision) { + } + } + PROCESS_SWITCH(EmcalMcTask, processEmcal, "Process for emcal", true); + +}; // End struct EmcalMcTask + +WorkflowSpec defineDataProcessing(ConfigContext const& context) +{ + return WorkflowSpec{adaptAnalysisTask(context)}; +} diff --git a/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx b/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx index 27f17c4d352..9d233f75ca0 100644 --- a/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx +++ b/PWGEM/PhotonMeson/Tasks/emcalPhotonMcTask.cxx @@ -14,18 +14,22 @@ /// \author M. Hemmer, marvin.hemmer@cern.ch #include "PWGEM/PhotonMeson/Core/EMBitFlags.h" +#include "PWGEM/PhotonMeson/Core/EMCConversionCandidate.h" #include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/Core/EmMlResponseEMCConversion.h" #include "PWGEM/PhotonMeson/DataModel/ConversionMl.h" #include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" #include "PWGEM/PhotonMeson/Utils/EventHistograms.h" #include "PWGEM/PhotonMeson/Utils/MCUtilities.h" +#include "PWGEM/PhotonMeson/Utils/ParticleOrigin.h" #include "Common/Core/RecoDecay.h" +#include "Tools/ML/MlResponse.h" -#include +#include #include #include #include @@ -33,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +54,7 @@ #include #include #include +#include #include #include @@ -72,10 +78,10 @@ using namespace o2::soa; using namespace o2::aod::pwgem::photon; using namespace o2::constants::physics; using namespace o2::aod::pwgem::photonmeson::utils::mcutil; +using namespace o2::analysis::em; constexpr float MinAmpThreshold = 0.2f; // Minimum cluster amplitude threshold to count as significant -constexpr float MaxAmpDiff = 0.1f; // Maximum cluster amplitude difference to leading cluster contribution to count as significant - +constexpr float MinAmpFraction = 0.6f; // Minimum fraction of particle energy that it needs to deposit in cluster to count as significant enum CentralityEstimator { None = 0, CFT0A, @@ -85,29 +91,19 @@ enum CentralityEstimator { }; enum class TruthClass { - Conversion = 0, // 0: true e+/e- pair from the same conversion - - PhotonPairSamePi0, // 1: two photon clusters, same Pi0 - PhotonPairDiffPi0, // 2: two photon clusters, different Pi0s - PhotonPairOnePi0, // 3: two photon clusters, only one from a Pi0 - - PhotonElectronSamePi0, // 4: photon + electron cluster, same Pi0 - PhotonElectronDiffPi0, // 5: photon + electron cluster, different Pi0s - PhotonElectronOnePi0, // 6: photon + electron cluster, only one from a Pi0 - BSPhotonElectron, // 7: photon + electron cluster, from Bremsstrahlung - - ElectronPairSamePi0, // 8: e+e cluster pair, same Pi0 (conversion and/or Dalitz) - ElectronPairDiffPi0, // 9: e+e cluster pair, different Pi0s - ElectronPairOnePi0, // 10: e+e cluster pair, only one from a Pi0 - - SplitPhotonCluster, // 11: one photon producing two clusters - SplitLeptonCluster, // 12: one lepton producing two clusters - PhotonBSPhotonPair, // 13: photon + photon from Bremsstrahlung - ElectronBSPhotonPair, // 14: one cluster from Bremsstrahlung and one electron cluster except case BSPhotonElectron - BSPhotonPair, // 15: both photons from Bremsstrahlung - - Background, // 16: else / uncorrelated - + Conversion, // two electron legs, same conversion vertex + GammaGammaSamePi0, // both clusters are DIRECT daughter photons of the same generator-level meson + GammaGammaAnnihilation, // two photons from the same e+e- annihilation vertex + BSPhotonElectron, // a bremsstrahlung photon paired with the specific lepton that radiated it + PhotonComptonElectronPair, // a Compton-scattered photon paired with its own recoil electron + ElectronPairSamePi0, // two lepton clusters, directly from same meson + CrossConvertedSiblings, // two lepton clusters, same meson cross-converted siblings + DalitzDecaySiblings, // two lepton clusters, same meson from Dalitz + SplitPhotonCluster, // one physical photon shower reconstructed as two clusters + SplitLeptonCluster, // one physical lepton shower reconstructed as two clusters + IndirGammaGammaSamePi0, // both clusters are indirect daughter photons of the same generator-level meson + SameMesonIndirect, // both clusters trace to the SAME generator-level meson, but at least one path passes through extra generations (e.g. a further conversion/BS/scatter) before reaching the cluster -- NOT a clean two-body relationship + Background, // no common meson ancestor at all -- genuinely uncorrelated combinatorics NClasses }; @@ -126,53 +122,79 @@ enum class TagDecision { NTags }; +struct PendingConvPair { + int64_t idx1 = 0; + int64_t idx2 = 0; +}; + struct ClusterMcInfo { - bool isLepton = false; - bool isPhoton = false; - bool isFromConv = false; - bool isMergedConv = false; - bool isFromPi0 = false; - bool isFromBremsstrahlung = false; - int convMotherId = -1; - int photonId = -1; - float purity = 0; + bool isLepton = false; // is cluster from a lepton + bool isPhoton = false; // is cluster from a photon + bool isMergedConv = false; // is cluster from a merged conversion + LeptonOrigin leptonOrigin = LeptonOrigin::Other; // origin of lepton in case isLepton == true + PhotonOrigin photonOrigin = PhotonOrigin::Other; // origin of photon in case isPhoton == true + int photonMotherId = -1; // for leptons: the photon this lepton traces to + int mesonId = -1; // for Decay photons: the pi0/eta/omega/etaprime id | for leptons from decay photons: the pi0/eta/omega/etaprime id + int hardPartonId = -1; // for Direct photons: the quark/gluon id + int decayPhotonId = -1; // unified: the photon (self, if isPhoton; or photonMotherId, if isLepton) whose immediate mother is a meson. -1 if not applicable. + float purity = 0.f; // fraction of energy the main particle contributed to the cluster + float radius = 0.f; // radius in xy from where the main contributor to the cluster originated }; -template -ClusterMcInfo classifyCluster(const TGroup& g, TIter& mcCluster, TIter& mcClusterLooper, TIter& mcClusterLooper2, McParticles const& mcParticles) +template +ClusterMcInfo classifyCluster(const TCluster& g, TIter& mcCluster, TIter& mcClusterLooper, TIter& mcClusterLooper2, McParticles const& mcParticles) { + static const std::array kMesonPdgs{PDG_t::kPi0, Pdg::kEta, Pdg::kOmega, Pdg::kEtaPrime}; ClusterMcInfo info; mcCluster.setCursor(g.emmcparticleIds()[0]); - info.isFromBremsstrahlung = isFromBremsstrahlung(mcCluster, mcClusterLooper); // particle has to be a photon and it has to have a e+ or e- as mother! + info.radius = std::hypot(mcCluster.vx(), mcCluster.vy()); float leadingAmplitude = g.amplitude()[0]; info.purity = leadingAmplitude; + info.mesonId = o2::aod::pwgem::photonmeson::utils::mcutil::GetMesonInChain(mcCluster, mcParticles, kMesonPdgs); if (std::abs(mcCluster.pdgCode()) == PDG_t::kElectron) { info.isLepton = true; - info.convMotherId = getMotherIndexFromChain(mcCluster, mcClusterLooper, PDG_t::kGamma); - info.isFromConv = info.convMotherId >= 0; - - if (mcCluster.mothersIds().size() > 0 && info.isFromConv) { - for (size_t i = 1; i < g.emmcparticleIds().size(); ++i) { - mcClusterLooper.setCursor(g.emmcparticleIds()[i]); - if (std::abs(mcClusterLooper.pdgCode()) == PDG_t::kElectron && mcClusterLooper.pdgCode() == -1 * mcCluster.pdgCode()) { - int32_t otherConvMotherId = getMotherIndexFromChain(mcClusterLooper, mcClusterLooper2, PDG_t::kGamma); - if (otherConvMotherId == info.convMotherId) { - if (g.amplitude()[i] >= leadingAmplitude - MaxAmpDiff && g.amplitude()[i] > MinAmpThreshold) { - info.isMergedConv = true; - } - break; - } - } + info.leptonOrigin = getLeptonOriginType(mcCluster, mcClusterLooper2, kMesonPdgs); + mcClusterLooper.setCursor(g.emmcparticleIds()[0]); + if (info.leptonOrigin == LeptonOrigin::Conversion) { + if (!mcCluster.has_mothers()) [[unlikely]] { + // conersion with no mother does not make any sense + info.leptonOrigin = LeptonOrigin::Other; + } else { + info.photonMotherId = mcCluster.mothersIds()[0]; + // since this is a real conversion where both daughters exist, check if the other conversion leg entered this cluster as well + for (size_t i = 1; i < g.emmcparticleIds().size(); ++i) { + mcClusterLooper.setCursor(g.emmcparticleIds()[i]); + if (std::abs(mcClusterLooper.pdgCode()) == PDG_t::kElectron && mcClusterLooper.pdgCode() == -1 * mcCluster.pdgCode()) { + mcClusterLooper2.setCursor(mcClusterLooper.globalIndex()); + int32_t otherConvMotherId = getMotherIndexFromChain(mcClusterLooper2, PDG_t::kGamma); + if (otherConvMotherId == info.photonMotherId) { + float energyFraction = (g.amplitude()[i] * g.e()) / mcClusterLooper.e(); + if (energyFraction >= MinAmpFraction && g.amplitude()[i] > MinAmpThreshold) { + info.isMergedConv = true; + } + // we found the sibling leg no need to search further + break; + } // if (otherConvMotherId == info.photonMotherId) + } // if (std::abs(mcClusterLooper.pdgCode()) == PDG_t::kElectron && mcClusterLooper.pdgCode() == -1 * mcCluster.pdgCode()) + } // end of loop over other cluster contributions + } // particle has mothers + } // if(info.leptonOrigin == LeptonOrigin::Conversion) + if (info.photonMotherId >= 0) { + mcClusterLooper.setCursor(info.photonMotherId); + info.photonOrigin = getPhotonOriginType(mcClusterLooper, mcClusterLooper2, kMesonPdgs, info.hardPartonId); + if (info.photonOrigin == PhotonOrigin::Decay) { + info.decayPhotonId = info.photonMotherId; + info.mesonId = o2::aod::pwgem::photonmeson::utils::mcutil::GetMesonInChain(mcClusterLooper, mcParticles, kMesonPdgs); } } } if (std::abs(mcCluster.pdgCode()) == PDG_t::kGamma) { info.isPhoton = true; + info.photonOrigin = getPhotonOriginType(mcCluster, mcClusterLooper, kMesonPdgs, info.hardPartonId); + if (info.photonOrigin == PhotonOrigin::Decay) { + info.mesonId = o2::aod::pwgem::photonmeson::utils::mcutil::GetMesonInChain(mcCluster, mcParticles, kMesonPdgs); + } } - - info.photonId = o2::aod::pwgem::photonmeson::utils::mcutil::FindMotherInChain(mcCluster, mcParticles, std::vector{PDG_t::kPi0, Pdg::kEta, Pdg::kOmega, Pdg::kEtaPrime}); - info.isFromPi0 = info.photonId >= 0; - return info; } @@ -181,17 +203,39 @@ struct EmcalPhotonMcTask { static constexpr float PhiVUndefined = -999.f; static constexpr float Epsilon = 1.e-6f; + static constexpr uint32_t MlModelRow = 0; + static constexpr uint32_t MlPositiveClassCol = 1; + + static constexpr std::array, 1> DefaultCutsMl{{{0.0, 0.25}}}; + static constexpr std::array(TruthClass::NClasses)> kTruthClassNames = { - "Conversion", "PhotonPairSamePi0", "PhotonPairDiffPi0", "PhotonPairOnePi0", - "PhotonElectronSamePi0", "PhotonElectronDiffPi0", "PhotonElectronOnePi0", "BSPhotonElectron", - "ElectronPairSamePi0", "ElectronPairDiffPi0", "ElectronPairOnePi0", - "SplitPhotonCluster", "SplitLeptonCluster", "Background"}; + "Conversion", "GammaGammaSamePi0", "GammaGammaAnnihilation", "BSPhotonElectron", + "PhotonComptonElectronPair", "ElectronPairSamePi0", "CrossConvertedSiblings", "DalitzDecaySiblings", + "SplitPhotonCluster", "SplitLeptonCluster", "IndirGammaGammaSamePi0", "SameMesonIndirect", + "Background"}; Produces convTagCandidates; Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable writeTable{"writeTable", true, "write table for ML."}; - Configurable> classPrescale{"classPrescale", {1, 1, 700, 25, 1, 350, 15, 1, 1, 35, 2, 1, 1, 1, 1, 1, 1000}, "prescale factor per TruthClass, indexed 0..10 matching the enum order"}; + Configurable> classPrescale{"classPrescale", + { + 1, // Conversion + 1, // GammaGammaSamePi0 + 1, // GammaGammaAnnihilation + 1, // BSPhotonElectron + 1, // PhotonComptonElectronPair + 1, // ElectronPairSamePi0 + 1, // CrossConvertedSiblings + 1, // DalitzDecaySiblings + 1, // SplitPhotonCluster + 1, // SplitLeptonCluster + 1, // IndirGammaGammaSamePi0 + 1, // SameMesonIndirect + 5000, // Background + }, + "prescale factor per TruthClass, indexed 0..12 matching the enum order"}; + Configurable bkgPrescaleSeed{"bkgPrescaleSeed", 42, "seed for the background-prescale RNG"}; // configurable axis @@ -259,6 +303,25 @@ struct EmcalPhotonMcTask { Configurable cfgEnableQA{"cfgEnableQA", false, "flag to turn QA plots on/off"}; } mesonConfig; + struct : ConfigurableGroup { + std::string prefix = "mlConfig"; + Configurable useMlTagging{"useMlTagging", false, "use ML score instead of box cut for conversion tagging"}; + Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "load ML model from CCDB"}; + Configurable enableOptimization{"enableOptimization", false, "enable the MlResponse optimizations."}; + Configurable nThreads{"nThreads", 1, "number of threads for the ML model"}; + Configurable mlBatchFlushSize{"mlBatchFlushSize", 20000, "Flush ML batch after this many pending pairs."}; + Configurable> mlInputFeatures{"mlInputFeatures", {"minv", "deltaEta", "deltaR", "phiv", "rConv", "totE", "e2", "e1", "deltaPhi", "harmonicEt", "m021", "m022", "time1", "time2", "ncell1", "ncell2"}, "input feature names -- content and order must match the Python training FEATURES list"}; + Configurable mlModelPathLocal{"mlModelPathLocal", "/data/mhemmer/O2ML/code/conversion_tagging_bdt_conversion_splits_brems.onnx", "local ONNX model path"}; + Configurable> modelPathsCCDB{"modelPathsCCDB", std::vector{"Users/m/mhemmer/EM/ML/"}, "Paths of models on CCDB"}; + Configurable> onnxFileNames{"onnxFileNames", std::vector{"conversion_tagging_bdt_conversion_splits_brems.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; + Configurable mlThreshold{"mlThreshold", 0.5f, "positive-class score threshold for tagging"}; + Configurable> cutsMl{"cutsMl", {DefaultCutsMl[0].data(), 1, 2, {"pT bin 0"}, { + "score photon pairs", + "score conversion pairs", + }}, + "ML selections per pT bin"}; + } mlConfig; + SliceCache cache; using EMCalPhotons = soa::Join; @@ -276,13 +339,15 @@ struct EmcalPhotonMcTask { int8_t bTruthLabel{}; - Service ccdb{}; + o2::ccdb::CcdbApi ccdbApi; int mRunNumber{0}; float dBz{0.f}; std::mt19937 mRandGen; std::uniform_int_distribution mPrescaleDist; + o2::analysis::em::emcconv::EmMlResponseEMCConversion mMlResponse; + void defineEMEventCut() { fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut"); @@ -325,11 +390,6 @@ struct EmcalPhotonMcTask { mRunNumber = 0; dBz = 0; - ccdb->setURL(ccdbUrl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(false); - defineEMEventCut(); defineEMCCut(); fEMCCut.addQAHistograms(®istry); @@ -339,8 +399,8 @@ struct EmcalPhotonMcTask { const AxisSpec thnAxisPtRec{thnConfigAxisPt, "#it{p}_{T} (GeV/#it{c})"}; const AxisSpec thnAxisInvMass{thnConfigAxisInvMass, "#it{M}_{#gamma#gamma} (GeV/#it{c}^{2})"}; - const AxisSpec thnAxisrConvRec{100, 0, 500, "#it{R}_{rec}"}; - const AxisSpec thnAxisrConvGen{100, 0, 500, "#it{R}_{gen}"}; + const AxisSpec thnAxisrConvRec{1000, 0, 500, "#it{R}_{rec}"}; + const AxisSpec thnAxisrConvGen{1000, 0, 500, "#it{R}_{gen}"}; const AxisSpec thnAxisDeltaEta{thnConfigAxisDeltaEta, "#Delta#it{eta}"}; const AxisSpec thnAxisDeltaPhi{thnConfigAxisDeltaPhi, "#Delta#it{#varphi} (rad)"}; @@ -348,6 +408,8 @@ struct EmcalPhotonMcTask { const AxisSpec thnAxisTagging{static_cast(TagDecision::NTags), -0.5, static_cast(TagDecision::NTags) - 0.5, ""}; const AxisSpec thnAxisClasses{static_cast(TruthClass::NClasses), -0.5, static_cast(TruthClass::NClasses) - 0.5, ""}; + const AxisSpec thnAxisM02{100, 0., 1.0, "#it{M}_{02}"}; + AxisSpec thnAxisCentOrMult{1, 0., 1., "Centrality/Multiplicity"}; // placeholder, overwritten in init if (useCent.value) { // PbPb: use centrality @@ -361,36 +423,56 @@ struct EmcalPhotonMcTask { // set bin labels once at init, so histogram is human-readable without decoding the enum hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::Conversion) + 1, "Conversion"); - hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonPairSamePi0) + 1, "PhotonPairSamePi0"); - hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonPairDiffPi0) + 1, "PhotonPairDiffPi0"); - hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonPairOnePi0) + 1, "PhotonPairOnePi0"); - hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonElectronSamePi0) + 1, "PhotonElectronSamePi0"); - hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonElectronDiffPi0) + 1, "PhotonElectronDiffPi0"); - hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonElectronOnePi0) + 1, "PhotonElectronOnePi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::GammaGammaSamePi0) + 1, "GammaGammaSamePi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::GammaGammaAnnihilation) + 1, "GammaGammaAnnihilation"); hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::BSPhotonElectron) + 1, "BSPhotonElectron"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonComptonElectronPair) + 1, "PhotonComptonElectronPair"); hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::ElectronPairSamePi0) + 1, "ElectronPairSamePi0"); - hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::ElectronPairDiffPi0) + 1, "ElectronPairDiffPi0"); - hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::ElectronPairOnePi0) + 1, "ElectronPairOnePi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::CrossConvertedSiblings) + 1, "CrossConvertedSiblings"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::DalitzDecaySiblings) + 1, "DalitzDecaySiblings"); hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::SplitPhotonCluster) + 1, "SplitPhotonCluster"); hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::SplitLeptonCluster) + 1, "SplitLeptonCluster"); - hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::PhotonBSPhotonPair) + 1, "PhotonBSPhotonPair"); - hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::ElectronBSPhotonPair) + 1, "ElectronBSPhotonPair"); - hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::BSPhotonPair) + 1, "BSPhotonPair"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::IndirGammaGammaSamePi0) + 1, "IndirGammaGammaSamePi0"); + hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::SameMesonIndirect) + 1, "SameMesonIndirect"); hTruthLabel->GetXaxis()->SetBinLabel(static_cast(TruthClass::Background) + 1, "Background"); - auto hPi0BothResolvedLost = registry.add("EMCal/hPi0BothResolvedLost", "Confusion matrix for conversion tagging", HistType::kTH1D, {{2, -0.5, 1.5}}); - hPi0BothResolvedLost->GetXaxis()->SetBinLabel(1, "both resolved (denominator)"); - hPi0BothResolvedLost->GetXaxis()->SetBinLabel(2, "lost to tagging"); + // auto hConfusionMatrixConversionTagging = registry.add("EMCal/ConfusionMatrixConversionTagging", "Confusion matrix for conversion tagging", HistType::kTH2D, {thnAxisTagging, thnAxisClasses}); + // hConfusionMatrixConversionTagging->GetXaxis()->SetBinLabel(1, "not tagged"); + // hConfusionMatrixConversionTagging->GetXaxis()->SetBinLabel(2, "tagged"); + // hConfusionMatrixConversionTagging->GetYaxis()->SetBinLabel(1, "true conv."); + // hConfusionMatrixConversionTagging->GetYaxis()->SetBinLabel(2, "true #pi^{0}"); + // hConfusionMatrixConversionTagging->GetYaxis()->SetBinLabel(3, "true #pi^{0} conv."); + // hConfusionMatrixConversionTagging->GetYaxis()->SetBinLabel(4, "background"); + // hConfusionMatrixConversionTagging->GetYaxis()->SetBinLabel(5, "#gamma"); + + auto hPhotonProcess = registry.add("Photon/hProcess", "Production process type", HistType::kTH1D, {{kMaxMCProcess, -0.5, kMaxMCProcess - 0.5}}); + for (int i = 0; i < kMaxMCProcess; ++i) { + hPhotonProcess->GetXaxis()->SetBinLabel(i + 1, TMCProcessName[i]); + } + registry.addClone("Photon/", "Electron/"); + registry.addClone("Photon/", "Positron/"); + + registry.add("Photon/Direct/M02", "M02 distribution;;counts", HistType::kTH2D, {thnAxisM02, thnAxisPtRec}); + + auto hDirectPhotonTags = registry.add("Photon/Direct/Tagging", "Tagging distribution;;counts", HistType::kTH1D, {{3, -0.5, 2.5}}); + hDirectPhotonTags->GetXaxis()->SetBinLabel(1, "Not tagged"); + hDirectPhotonTags->GetXaxis()->SetBinLabel(2, "tagged simple"); + hDirectPhotonTags->GetXaxis()->SetBinLabel(3, "tagged double"); + + registry.addClone("Photon/Direct/", "Photon/Decay/"); + registry.addClone("Photon/Direct/", "Photon/Bremsstrahlung/"); + registry.addClone("Photon/Direct/", "Photon/Annihilation/"); + registry.addClone("Photon/Direct/", "Photon/Hadronic/"); - auto hConfusionMatrixConversionTagging = registry.add("EMCal/ConfusionMatrixConversionTagging", "Confusion matrix for conversion tagging", HistType::kTH2D, {thnAxisTagging, thnAxisClasses}); - hConfusionMatrixConversionTagging->GetXaxis()->SetBinLabel(1, "not tagged"); - hConfusionMatrixConversionTagging->GetXaxis()->SetBinLabel(2, "tagged"); + registry.addClone("Photon/Direct/", "Lepton/Conversion/"); + registry.addClone("Photon/Direct/", "Lepton/Compton/"); + registry.addClone("Photon/Direct/", "Lepton/PhotoElectric/"); + registry.addClone("Photon/Direct/", "Lepton/DeltaRay/"); + registry.addClone("Photon/Direct/", "Lepton/DirectMesonDecay/"); - hConfusionMatrixConversionTagging->GetYaxis()->SetBinLabel(1, "true conv."); - hConfusionMatrixConversionTagging->GetYaxis()->SetBinLabel(2, "true #pi^{0}"); - hConfusionMatrixConversionTagging->GetYaxis()->SetBinLabel(3, "true #pi^{0} conv."); - hConfusionMatrixConversionTagging->GetYaxis()->SetBinLabel(4, "background"); - hConfusionMatrixConversionTagging->GetYaxis()->SetBinLabel(5, "#gamma"); + if (mlConfig.useMlTagging.value) { + registry.add("hMlScore", "BDT score;;Counts", HistType::kTH1D, {{100, 0, 1}}); + } mRandGen.seed(bkgPrescaleSeed.value); @@ -403,6 +485,7 @@ struct EmcalPhotonMcTask { for (size_t i = 0; i < kTruthClassNames.size(); ++i) { LOG(info) << " [" << i << "] " << kTruthClassNames[i] << " -> prescale = " << classPrescale.value[i]; } + }; // end init template @@ -413,10 +496,34 @@ struct EmcalPhotonMcTask { } mRunNumber = collision.runNumber(); - auto run3grp_timestamp = collision.timestamp(); + auto timestamp = collision.timestamp(); // Fetch magnetic field from ccdb for current collision dBz = collision.grpMagField().getNominalL3Field(); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << dBz << " kZG"; + LOG(info) << "Retrieved GRP for timestamp " << timestamp << " with magnetic field of " << dBz << " kZG"; + + if (mlConfig.useMlTagging.value) { + // single bin, full range -- see earlier discussion: pT/energy-binned + // thresholds are a straightforward future extension of this same + // machinery if ever needed, not used right now + std::vector binsLimits = {0., 1000.}; + std::vector cutDir = { + static_cast(o2::cuts_ml::CutDirection::CutNot), // class 0 (negative-class prob) -- no cut + static_cast(o2::cuts_ml::CutDirection::CutSmaller), // class 1 (positive-class prob) -- reject if score < threshold + }; + + mMlResponse.configure(binsLimits, mlConfig.cutsMl, cutDir, /*nClasses=*/2); + mMlResponse.cacheInputFeaturesIndices(mlConfig.mlInputFeatures.value); + if (mlConfig.loadModelsFromCCDB) { + ccdbApi.init(ccdbUrl); + mMlResponse.setModelPathsCCDB(mlConfig.onnxFileNames, ccdbApi, mlConfig.modelPathsCCDB.value, timestamp); + } else { + mMlResponse.setModelPathsLocal({mlConfig.mlModelPathLocal.value}); + } + mMlResponse.init(mlConfig.enableOptimization, mlConfig.nThreads); + + LOG(info) << "ML conversion tagging enabled -- model: " << mlConfig.mlModelPathLocal.value + << ", threshold: " << mlConfig.mlThreshold.value; + } } template @@ -494,12 +601,60 @@ struct EmcalPhotonMcTask { if (collisions.size() <= 0) { return; } + + auto cluster1 = clusters.begin(); + auto cluster2 = clusters.begin(); + std::vector wasMeassured(mcParticles.size(), false); EMBitFlags emcFlagsFromTrueMeson(clusters.size()); EMBitFlags emcFlagsFromTrueMesonSameGamma(clusters.size()); EMBitFlags emcFlagsFromTrueConversion(clusters.size()); EMBitFlags emcFlagsTagging(clusters.size()); + EMBitFlags emcFlagsMlTagging(clusters.size()); + EMBitFlags emcFlagsMlTaggingDoublePass(clusters.size()); EMBitFlags emcFlags(clusters.size()); + + std::vector bestPositiveScore(clusters.size(), 0); + std::vector bestNegativeScore(clusters.size(), 0); + + std::vector mMlInputBuffer; + + std::vector pending; + std::vector mlBatchBuffer; + + auto flushMlBatch = [&]() { + if (pending.empty()) { + return; + } + auto scores = mMlResponse.getModelOutputBatched(mlBatchBuffer, /*nModel=*/0, pending.size()); + for (std::size_t i = 0; i < pending.size(); ++i) { + const auto& pp = pending[i]; + cluster1.setCursor(pp.idx1); + cluster2.setCursor(pp.idx2); + const float negScore = scores[i * 2 + 0]; + const float posScore = scores[i * 2 + 1]; + + for (const auto& idx : {pp.idx1, pp.idx2}) { + if (posScore > bestPositiveScore[idx]) { + bestPositiveScore[idx] = posScore; + } + if (negScore > bestNegativeScore[idx]) { + bestNegativeScore[idx] = negScore; + } + } + const bool isTagged = posScore >= mlConfig.cutsMl->get(MlModelRow, MlPositiveClassCol); // mirrors the CutSmaller-on-class-1 logic + if (isTagged) { + emcFlagsMlTagging.set(pp.idx1); + emcFlagsMlTagging.set(pp.idx2); + } + registry.fill(HIST("hMlScore"), posScore); + + // --- classification/table-fill exactly as before (lines 706-806), using pp.vMeson, pp.deltaEta, pp.deltaPhi, pp.phiV, pp.harmonicET, g1, g2 --- + } + mlBatchBuffer.clear(); + pending.clear(); + }; + if (clusters.size() > 0) { fEMCCut.AreSelectedRunning(emcFlags, clusters, matchedPrims, matchedSeconds, ®istry); } @@ -513,12 +668,19 @@ struct EmcalPhotonMcTask { for (const auto& collision : collisions) { initCCDB(collision); - isFullEventSelected(collision, true); + if (!isFullEventSelected(collision, true)) { + continue; + } float centOrMult = getCentralityOrMultiplicity(collision); auto photonsEMCPerCollision = clusters.sliceBy(perCollisionEMC, collision.globalIndex()); + if (mlConfig.useMlTagging.value) { + pending.reserve(photonsEMCPerCollision.size()); // rough upper bound + mlBatchBuffer.reserve(photonsEMCPerCollision.size() * mlConfig.mlInputFeatures.value.size()); + } + for (const auto& [g1, g2] : combinations(CombinationsStrictlyUpperIndexPolicy(photonsEMCPerCollision, photonsEMCPerCollision))) { if (!(emcFlags.test(g1.globalIndex())) || !(emcFlags.test(g2.globalIndex()))) { continue; @@ -565,18 +727,28 @@ struct EmcalPhotonMcTask { emcFlagsTagging.set(g2.globalIndex()); } + if (mlConfig.useMlTagging.value) { + o2::analysis::em::EMCConversionCandidate candidate{ + .mMinv = static_cast(vMeson.M()), .mDeltaEta = deltaEta, .mDeltaR = std::hypot(deltaEta, deltaPhi), .mPhiv = phiV, .mRConv = rConv, .mTotE = (g2.e() + g1.e()), .mE2 = g2.e(), .mE1 = g1.e(), .mDeltaPhi = deltaPhi, .mHarmonicEt = harmonicET, .mM021 = g1.m02(), .mM022 = g2.m02(), .mTime1 = g1.time(), .mTime2 = g2.time(), .mNcell1 = g1.nCells(), .mNcell2 = g2.nCells()}; + mMlResponse.getInputFeatures(candidate, mMlInputBuffer); + mlBatchBuffer.insert(mlBatchBuffer.end(), mMlInputBuffer.begin(), mMlInputBuffer.end()); + pending.push_back({g1.globalIndex(), g2.globalIndex()}); + if (pending.size() >= mlConfig.mlBatchFlushSize.value) { + flushMlBatch(); + } + } + // set MC particle cursors to the largest cluster contributor mcCluster1.setCursor(g1.emmcparticleIds()[0]); mcCluster2.setCursor(g2.emmcparticleIds()[0]); - bool areFromSamePi0 = false; + auto c1 = classifyCluster(g1, mcCluster1, mcClusterLooper, mcClusterLooper2, mcParticles); + auto c2 = classifyCluster(g2, mcCluster2, mcClusterLooper, mcClusterLooper2, mcParticles); + + const bool areFromSamePi0 = c1.mesonId >= 0 && c1.mesonId == c2.mesonId; bool areConversionLegs = false; bool areSplitPhotonCluster = false; bool areSplitLeptonCluster = false; - bool areBSPhotonElectron = false; - - auto c1 = classifyCluster(g1, mcCluster1, mcClusterLooper, mcClusterLooper2, mcParticles); - auto c2 = classifyCluster(g2, mcCluster2, mcClusterLooper, mcClusterLooper2, mcParticles); // split-cluster check MUST run first and take priority over everything else -- // if both clusters share the same dominant MC particle, this is one physical @@ -590,34 +762,29 @@ struct EmcalPhotonMcTask { } } - const bool isAnyBSPhoton = c1.isFromBremsstrahlung || c2.isFromBremsstrahlung; - const bool areBSPhotons = c1.isFromBremsstrahlung && c2.isFromBremsstrahlung; - // if they are not a split cluster check for proper conversion pair - if (!isSameDominantParticle && c1.isFromConv && c2.isFromConv && c1.convMotherId == c2.convMotherId) { + if (!isSameDominantParticle && c1.leptonOrigin == LeptonOrigin::Conversion && c2.leptonOrigin == LeptonOrigin::Conversion && c1.photonMotherId == c2.photonMotherId) { emcFlagsFromTrueConversion.set(g1.globalIndex()); emcFlagsFromTrueConversion.set(g2.globalIndex()); areConversionLegs = true; } // if they are not a split cluster check for neutral meson connection - if (!isSameDominantParticle && c1.isFromPi0 && c2.isFromPi0) { - mcPhoton1.setCursor(c1.photonId); - mcPhoton2.setCursor(c2.photonId); + if (!isSameDominantParticle && c1.decayPhotonId >= 0 && c2.decayPhotonId >= 0) { + mcPhoton1.setCursor(c1.decayPhotonId); + mcPhoton2.setCursor(c2.decayPhotonId); mcMother.setCursor(mcPhoton1.mothersIds()[0]); if (mcMother.producedByGenerator()) { - if (c1.photonId == c2.photonId) { + if (c1.mesonId == c2.mesonId) { // bremsstrahlung: one side is a photon born from the other side's lepton lineage - const bool photonIsBS = (c1.isPhoton && c1.isFromBremsstrahlung) || (c2.isPhoton && c2.isFromBremsstrahlung); + const bool photonIsBS = (c1.isPhoton && c1.photonOrigin == PhotonOrigin::Bremsstrahlung) || (c2.isPhoton && c2.photonOrigin == PhotonOrigin::Bremsstrahlung); if (photonIsBS && ((c1.isLepton && c2.isPhoton) || (c2.isLepton && c1.isPhoton))) { - areBSPhotonElectron = true; + // nothing } else { - areFromSamePi0 = true; emcFlagsFromTrueMesonSameGamma.set(g1.globalIndex()); emcFlagsFromTrueMesonSameGamma.set(g2.globalIndex()); } } else if (mcPhoton1.mothersIds()[0] == mcPhoton2.mothersIds()[0]) { - areFromSamePi0 = true; emcFlagsFromTrueMeson.set(g1.globalIndex()); emcFlagsFromTrueMeson.set(g2.globalIndex()); } @@ -625,46 +792,45 @@ struct EmcalPhotonMcTask { } bTruthLabel = static_cast(TruthClass::Background); + if (!mcCluster1.has_mothers() || !mcCluster2.has_mothers()) { + registry.fill(HIST("hTruthLabel"), bTruthLabel, vMeson.Pt()); + + // final tree values plus filling + const int prescale = classPrescale.value[static_cast(bTruthLabel)]; + const bool keepThisRow = (prescale <= 1) || (std::uniform_int_distribution(0, prescale - 1)(mRandGen) == 0); + if (writeTable.value && keepThisRow) { + convTagCandidates(collision.globalIndex(), vMeson.M(), harmonicET, deltaEta, deltaPhi, phiV, g1.e(), g2.e(), g1.m02(), g2.m02(), g1.time(), g2.time(), g1.nCells(), g2.nCells(), c1.purity, c2.purity, bTruthLabel, centOrMult); + } + continue; + } if (areSplitPhotonCluster) { bTruthLabel = static_cast(TruthClass::SplitPhotonCluster); } else if (areSplitLeptonCluster) { bTruthLabel = static_cast(TruthClass::SplitLeptonCluster); } else if (areConversionLegs) { bTruthLabel = static_cast(TruthClass::Conversion); - } else if (areBSPhotonElectron) { + } else if (c1.photonOrigin == PhotonOrigin::Annihilation && c2.photonOrigin == PhotonOrigin::Annihilation && mcCluster1.mothersIds()[0] == mcCluster2.mothersIds()[0]) { + bTruthLabel = static_cast(TruthClass::GammaGammaAnnihilation); + } else if ((c1.photonOrigin == PhotonOrigin::Bremsstrahlung && mcCluster1.mothersIds()[0] == mcCluster2.globalIndex()) || (c2.photonOrigin == PhotonOrigin::Bremsstrahlung && mcCluster2.mothersIds()[0] == mcCluster1.globalIndex())) { bTruthLabel = static_cast(TruthClass::BSPhotonElectron); - } else if (areBSPhotons && (c1.isFromPi0 || c2.isFromPi0)) { - bTruthLabel = static_cast(TruthClass::BSPhotonPair); - } else if (isAnyBSPhoton && (c1.isFromPi0 || c2.isFromPi0) && ((c1.isPhoton && c2.isLepton) || (c2.isPhoton && c1.isLepton))) { - bTruthLabel = static_cast(TruthClass::ElectronBSPhotonPair); - } else if (isAnyBSPhoton && (c1.isFromPi0 || c2.isFromPi0) && (c1.isPhoton && c2.isPhoton)) { - bTruthLabel = static_cast(TruthClass::PhotonBSPhotonPair); - } else if (areFromSamePi0) { - if ((c1.isLepton && c2.isPhoton) || (c2.isLepton && c1.isPhoton)) { - bTruthLabel = static_cast(TruthClass::PhotonElectronSamePi0); - } else if (c1.isPhoton && c2.isPhoton) { - bTruthLabel = static_cast(TruthClass::PhotonPairSamePi0); - } else if (c1.isLepton && c2.isLepton) { + } else if ((c1.leptonOrigin == LeptonOrigin::Compton && mcCluster1.mothersIds()[0] == mcCluster2.globalIndex()) || (c2.leptonOrigin == LeptonOrigin::Compton && mcCluster2.mothersIds()[0] == mcCluster1.globalIndex())) { + bTruthLabel = static_cast(TruthClass::PhotonComptonElectronPair); + } else if (c1.leptonOrigin == LeptonOrigin::DirectMesonDecay && c2.leptonOrigin == LeptonOrigin::DirectMesonDecay && mcCluster1.mothersIds()[0] == mcCluster2.mothersIds()[0]) { // both cluster are leptons that come from the same meson decay + mcMother.setCursor(mcCluster1.mothersIds()[0]); + if (mcMother.daughtersIds().size() == 2) { // o2-linter: disable=magic-number (number of daughters) bTruthLabel = static_cast(TruthClass::ElectronPairSamePi0); + } else if (mcMother.daughtersIds().size() == 3) { // o2-linter: disable=magic-number (number of daughters) + bTruthLabel = static_cast(TruthClass::DalitzDecaySiblings); } - } else if (c1.isFromPi0 && c2.isFromPi0) { - if ((c1.isLepton && c2.isPhoton) || (c2.isLepton && c1.isPhoton)) { - bTruthLabel = static_cast(TruthClass::PhotonElectronDiffPi0); - } else if (c1.isPhoton && c2.isPhoton) { - bTruthLabel = static_cast(TruthClass::PhotonPairDiffPi0); - } else if (c1.isLepton && c2.isLepton) { - bTruthLabel = static_cast(TruthClass::ElectronPairDiffPi0); - } - } else if ((c1.isFromPi0 && !c2.isFromPi0) || (!c1.isFromPi0 && c2.isFromPi0)) { - if ((c1.isLepton && c2.isPhoton) || (c2.isLepton && c1.isPhoton)) { - bTruthLabel = static_cast(TruthClass::PhotonElectronOnePi0); - } else if (c1.isPhoton && c2.isPhoton) { - bTruthLabel = static_cast(TruthClass::PhotonPairOnePi0); - } else if (c1.isLepton && c2.isLepton) { - bTruthLabel = static_cast(TruthClass::ElectronPairOnePi0); - } + } else if (c1.leptonOrigin == LeptonOrigin::Conversion && c2.leptonOrigin == LeptonOrigin::Conversion && mcCluster1.mothersIds()[0] != mcCluster2.mothersIds()[0] && areFromSamePi0) { // both cluster are leptons that come from different conversions that come from the same meson + bTruthLabel = static_cast(TruthClass::CrossConvertedSiblings); + } else if (c1.photonOrigin == PhotonOrigin::Decay && c2.photonOrigin == PhotonOrigin::Decay && areFromSamePi0) { // both clusters are photons from decay from the same meson + bTruthLabel = static_cast(TruthClass::GammaGammaSamePi0); + } else if (c1.isPhoton && c2.isPhoton && areFromSamePi0) { + bTruthLabel = static_cast(TruthClass::IndirGammaGammaSamePi0); + } else if (areFromSamePi0) { // both cluster do not fit into one of the categories above, but they share a common meson ancestry + bTruthLabel = static_cast(TruthClass::SameMesonIndirect); } - registry.fill(HIST("hTruthLabel"), bTruthLabel, vMeson.Pt()); // final tree values plus filling @@ -674,11 +840,24 @@ struct EmcalPhotonMcTask { convTagCandidates(collision.globalIndex(), vMeson.M(), harmonicET, deltaEta, deltaPhi, phiV, g1.e(), g2.e(), g1.m02(), g2.m02(), g1.time(), g2.time(), g1.nCells(), g2.nCells(), c1.purity, c2.purity, bTruthLabel, centOrMult); } } // pair loop + + // Tagging part for the double pass using ML + for (const auto& cluster : photonsEMCPerCollision) { + if (!emcFlags.test(cluster.globalIndex())) { + continue; + } + const float bestPos = bestPositiveScore[cluster.globalIndex()]; + const float bestNeg = bestNegativeScore[cluster.globalIndex()]; + + // compare best positive vs best negative case. Only when the best positive is higher than the best negative actually mark this cluster as conversion + if (bestPos >= mlConfig.mlThreshold.value && bestPos > bestNeg) { + emcFlagsMlTaggingDoublePass.set(cluster.globalIndex()); + } + } // end of loop over cluster } // collision loop - std::vector photonSeen(mcParticles.size(), false); // this decay photon has >=1 resolved cluster - std::vector photonTagged(mcParticles.size(), false); // >=1 of those clusters got conversion-tagged auto collision = collisions.begin(); + for (const auto& cluster : clusters) { if (!(emcFlags.test(cluster.globalIndex()))) { continue; @@ -690,73 +869,157 @@ struct EmcalPhotonMcTask { if (cluster.pmeventId() > collision.globalIndex()) { collision.setCursor(cluster.pmeventId()); } - - mcCluster1.setCursor(cluster.emmcparticleIds()[0]); - int photonid1 = o2::aod::pwgem::photonmeson::utils::mcutil::FindMotherInChain(mcCluster1, mcParticles, std::vector{PDG_t::kPi0, Pdg::kEta, Pdg::kOmega, Pdg::kEtaPrime}); - int motherId = -1; - if (photonid1 >= 0) { - mcPhoton1.setCursor(photonid1); - motherId = mcPhoton1.mothersIds()[0]; - - photonSeen[static_cast(photonid1)] = true; - const bool isTagged = !emcFlagsTagging.test(cluster.globalIndex()); - if (isTagged) { - photonTagged[static_cast(photonid1)] = true; - } - } - - const bool alreadyCountedForMeson = (motherId > -1 && wasMeassured[static_cast(motherId)]); - - if (mcCluster1.pdgCode() == PDG_t::kGamma) { - registry.fill(HIST("EMCal/ConfusionMatrixConversionTagging"), emcFlagsTagging.test(cluster.globalIndex()) ? 0 : 1, static_cast(ClusterTruthClass::Photon)); - } - if (!emcFlagsFromTrueConversion.test(cluster.globalIndex())) { - registry.fill(HIST("EMCal/ConfusionMatrixConversionTagging"), emcFlagsTagging.test(cluster.globalIndex()) ? 0 : 1, static_cast(ClusterTruthClass::Conversion)); - if (!emcFlagsFromTrueMesonSameGamma.test(cluster.globalIndex()) && !alreadyCountedForMeson) { - registry.fill(HIST("EMCal/ConfusionMatrixConversionTagging"), emcFlagsTagging.test(cluster.globalIndex()) ? 0 : 1, static_cast(ClusterTruthClass::Pi0Conversion)); - } - } - if (!emcFlagsFromTrueMeson.test(cluster.globalIndex()) && !alreadyCountedForMeson) { - registry.fill(HIST("EMCal/ConfusionMatrixConversionTagging"), emcFlagsTagging.test(cluster.globalIndex()) ? 0 : 1, static_cast(ClusterTruthClass::Pi0)); - } - if (emcFlagsFromTrueMeson.test(cluster.globalIndex()) && emcFlagsFromTrueConversion.test(cluster.globalIndex())) { - registry.fill(HIST("EMCal/ConfusionMatrixConversionTagging"), emcFlagsTagging.test(cluster.globalIndex()) ? 0 : 1, static_cast(ClusterTruthClass::Background)); - } - if (motherId > -1 && !wasMeassured[static_cast(motherId)]) { - wasMeassured[static_cast(motherId)] = true; - } - } // end of loop over cluster - - for (const auto& mcPart : mcParticles) { - if (mcPart.pdgCode() != PDG_t::kPi0 && mcPart.pdgCode() != Pdg::kEta) { - continue; - } - if (!mcPart.producedByGenerator()) { - continue; - } - if (mcPart.daughtersIds().size() != 2) { // o2-linter: disable=magic-number (self explanatory and does not need extra named variable) + if (!isFullEventSelected(collision, false)) { continue; } - const int d0 = mcPart.daughtersIds()[0]; - const int d1 = mcPart.daughtersIds()[1]; - mcPhoton1.setCursor(d0); - mcPhoton2.setCursor(d1); - if (mcPhoton1.pdgCode() != PDG_t::kGamma || mcPhoton2.pdgCode() != PDG_t::kGamma) { - continue; // skip anything that is not pi0/eta -> γγ. - } - - const bool bothResolved = photonSeen[static_cast(d0)] && photonSeen[static_cast(d1)]; - if (!bothResolved) { - continue; // not in the denominator -- ceiling case, not attributable to the cut + ClusterMcInfo clusterMcInfo = classifyCluster(cluster, mcCluster1, mcClusterLooper, mcClusterLooper2, mcParticles); + const PhotonOrigin photonOrigin = clusterMcInfo.photonOrigin; + const LeptonOrigin leptonOrigin = clusterMcInfo.leptonOrigin; + const bool simpleTagged = !emcFlagsMlTagging.test(cluster.globalIndex()); + const bool doubleTagged = !emcFlagsMlTaggingDoublePass.test(cluster.globalIndex()); + const bool notTagged = !simpleTagged; + switch (photonOrigin) { + case PhotonOrigin::Direct: + registry.fill(HIST("Photon/Direct/M02"), cluster.m02(), cluster.pt()); + if (notTagged) { + registry.fill(HIST("Photon/Direct/Tagging"), 0); + } else { + if (simpleTagged) { + registry.fill(HIST("Photon/Direct/Tagging"), 1); + } + if (doubleTagged) { + registry.fill(HIST("Photon/Direct/Tagging"), 2); + } + } + break; + case PhotonOrigin::Decay: + registry.fill(HIST("Photon/Decay/M02"), cluster.m02(), cluster.pt()); + if (notTagged) { + registry.fill(HIST("Photon/Decay/Tagging"), 0); + } else { + if (simpleTagged) { + registry.fill(HIST("Photon/Decay/Tagging"), 1); + } + if (doubleTagged) { + registry.fill(HIST("Photon/Decay/Tagging"), 2); + } + } + break; + case PhotonOrigin::Bremsstrahlung: + registry.fill(HIST("Photon/Bremsstrahlung/M02"), cluster.m02(), cluster.pt()); + if (notTagged) { + registry.fill(HIST("Photon/Bremsstrahlung/Tagging"), 0); + } else { + if (simpleTagged) { + registry.fill(HIST("Photon/Bremsstrahlung/Tagging"), 1); + } + if (doubleTagged) { + registry.fill(HIST("Photon/Bremsstrahlung/Tagging"), 2); + } + } + break; + case PhotonOrigin::Annihilation: + registry.fill(HIST("Photon/Annihilation/M02"), cluster.m02(), cluster.pt()); + if (notTagged) { + registry.fill(HIST("Photon/Annihilation/Tagging"), 0); + } else { + if (simpleTagged) { + registry.fill(HIST("Photon/Annihilation/Tagging"), 1); + } + if (doubleTagged) { + registry.fill(HIST("Photon/Annihilation/Tagging"), 2); + } + } + break; + case PhotonOrigin::Hadronic: + registry.fill(HIST("Photon/Hadronic/M02"), cluster.m02(), cluster.pt()); + if (notTagged) { + registry.fill(HIST("Photon/Hadronic/Tagging"), 0); + } else { + if (simpleTagged) { + registry.fill(HIST("Photon/Hadronic/Tagging"), 1); + } + if (doubleTagged) { + registry.fill(HIST("Photon/Hadronic/Tagging"), 2); + } + } + break; + case PhotonOrigin::Other: + default: + break; } - - const bool lost = photonTagged[static_cast(d0)] || photonTagged[static_cast(d1)]; - registry.fill(HIST("EMCal/hPi0BothResolvedLost"), 0.0); // "denominator" bin, once per bothResolved pi0 - if (lost) { - registry.fill(HIST("EMCal/hPi0BothResolvedLost"), 1.0); // "lost" bin + switch (leptonOrigin) { + case LeptonOrigin::Conversion: + registry.fill(HIST("Lepton/Conversion/M02"), cluster.m02(), cluster.pt()); + if (notTagged) { + registry.fill(HIST("Lepton/Conversion/Tagging"), 0); + } else { + if (simpleTagged) { + registry.fill(HIST("Lepton/Conversion/Tagging"), 1); + } + if (doubleTagged) { + registry.fill(HIST("Lepton/Conversion/Tagging"), 2); + } + } + break; + case LeptonOrigin::Compton: + registry.fill(HIST("Lepton/Compton/M02"), cluster.m02(), cluster.pt()); + if (notTagged) { + registry.fill(HIST("Lepton/Compton/Tagging"), 0); + } else { + if (simpleTagged) { + registry.fill(HIST("Lepton/Compton/Tagging"), 1); + } + if (doubleTagged) { + registry.fill(HIST("Lepton/Compton/Tagging"), 2); + } + } + break; + case LeptonOrigin::PhotoElectric: + registry.fill(HIST("Lepton/PhotoElectric/M02"), cluster.m02(), cluster.pt()); + if (notTagged) { + registry.fill(HIST("Lepton/PhotoElectric/Tagging"), 0); + } else { + if (simpleTagged) { + registry.fill(HIST("Lepton/PhotoElectric/Tagging"), 1); + } + if (doubleTagged) { + registry.fill(HIST("Lepton/PhotoElectric/Tagging"), 2); + } + } + break; + case LeptonOrigin::DeltaRay: + registry.fill(HIST("Lepton/DeltaRay/M02"), cluster.m02(), cluster.pt()); + if (notTagged) { + registry.fill(HIST("Lepton/DeltaRay/Tagging"), 0); + } else { + if (simpleTagged) { + registry.fill(HIST("Lepton/DeltaRay/Tagging"), 1); + } + if (doubleTagged) { + registry.fill(HIST("Lepton/DeltaRay/Tagging"), 2); + } + } + break; + case LeptonOrigin::DirectMesonDecay: + registry.fill(HIST("Lepton/DirectMesonDecay/M02"), cluster.m02(), cluster.pt()); + if (notTagged) { + registry.fill(HIST("Lepton/DirectMesonDecay/Tagging"), 0); + } else { + if (simpleTagged) { + registry.fill(HIST("Lepton/DirectMesonDecay/Tagging"), 1); + } + if (doubleTagged) { + registry.fill(HIST("Lepton/DirectMesonDecay/Tagging"), 2); + } + } + break; + case LeptonOrigin::Other: + default: + break; } - } + } // end of loop over cluster } PROCESS_SWITCH(EmcalPhotonMcTask, processEmcal, "Process for pcm and emcal photons", true); diff --git a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx index 1b161a8976a..496cf7a8067 100644 --- a/PWGEM/PhotonMeson/Tasks/pcmQC.cxx +++ b/PWGEM/PhotonMeson/Tasks/pcmQC.cxx @@ -9,17 +9,41 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file MaterialBudget.cxx -/// \brief This code runs loop over v0 photons for PCM QC. -/// \author Daiki Sekihata, daiki.sekihata@cern.ch +/// \file pcmQC.cxx +/// \brief Quality, purity, material and reconstruction monitoring of the selected V0 photon candidates +/// +/// - processQC: kinematics, conversion-point and leg-track QA of the +/// reconstructed photons. Material-budget configurables +/// add conversion-point maps, restricted to selectable +/// detector regions for material studies. +/// - processQCML: the same QC with the ML-based photon selection (BDT +/// models from CCDB) instead of the classical V0 cuts +/// - processPCMQCMC: MC-truth of the QC observables for the purity +/// assessment, plus resolution assessment. +/// Configurables activate collision-association studies +/// and the same regional material-budget mode as in +/// processQC, there with per-region resolution on top. +/// - processPCMQCMCML: the same MC QC with the ML-based photon selection +/// - processGen: generator-level distributions as the denominator +/// reference (requires the binned generated-pT derived +/// data as input). +/// - processRecoQA: runs on AO2Ds, before any skimming: track-level QA +/// plus a truth-based check of the SVertexer candidate +/// building and deduplication, separating genuine +/// reconstruction quality from reconstruction artifacts. +/// +/// \author Daiki Sekihata and author Stefanie Mrozinski +#include "PWGEM/Dilepton/Utils/MCUtilities.h" #include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCandidate.h" #include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" #include "PWGEM/PhotonMeson/DataModel/EventTables.h" #include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/MCUtilities.h" #include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" @@ -27,26 +51,29 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include #include #include #include -#include #include +#include +#include #include #include +#include // for the concept std::ranges::contiguous_range #include #include #include +#include #include using namespace o2; @@ -55,8 +82,10 @@ using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; using namespace o2::aod::pwgem::photon; +using namespace o2::aod::pwgem::photonmeson::utils::mcutil; +using namespace o2::aod::pwgem::dilepton::utils::mcutil; -using MyCollisions = soa::Join; +using MyCollisions = soa::Join; using MyCollision = MyCollisions::iterator; using MyV0Photons = soa::Join; @@ -65,14 +94,24 @@ using MyV0Photon = MyV0Photons::iterator; using MyV0PhotonsML = soa::Join; using MyV0PhotonML = MyV0PhotonsML::iterator; +// MC Joins +using MyCollisionsMC = soa::Join; +using MyCollisionMC = MyCollisionsMC::iterator; + +using MyMCCollisions = soa::Join; +using MyMCCollision = MyMCCollisions::iterator; + +using MyMCV0Legs = soa::Join; +using MyMCV0Leg = MyMCV0Legs::iterator; + +// AO2D level (processRecoQA): tracks before any skimming, with their MC labels +using MyTracksMC = soa::Join; + struct PCMQC { Configurable cfgCentEstimator{"cfgCentEstimator", 2, "FT0M:0, FT0A:1, FT0C:2"}; Configurable cfgCentMin{"cfgCentMin", 0, "min. centrality"}; Configurable cfgCentMax{"cfgCentMax", 999.f, "max. centrality"}; Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; - Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; - Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; Configurable d_bz_input{"d_bz_input", -999, "bz field in kG, -999 is automatic"}; EMPhotonEventCut fEMEventCut; @@ -98,61 +137,113 @@ struct PCMQC { } eventcuts; V0PhotonCut fV0PhotonCut; + // v0 photon cuts + struct : ConfigurableGroup { + std::string prefix = "v0cut_group"; + Configurable cfgRequireV0WithITSTPC{"cfgRequireV0WithITSTPC", false, "flag to select V0s with ITS-TPC matched tracks"}; + Configurable cfgRequireV0WithITSonly{"cfgRequireV0WithITSonly", false, "flag to select V0s with ITSonly tracks"}; + Configurable cfgRequireV0WithTPConly{"cfgRequireV0WithTPConly", false, "flag to select V0s with TPConly tracks"}; + Configurable cfgMinPtV0{"cfgMinPtV0", 0.1, "min pT for v0 photons at PV"}; + Configurable cfgMaxPtV0{"cfgMaxPtV0", 1e+10, "max pT for v0 photons at PV"}; + Configurable cfgMinEtaV0{"cfgMinEtaV0", -0.8, "min eta for v0 photons at PV"}; + Configurable cfgMaxEtaV0{"cfgMaxEtaV0", +0.8, "max eta for v0 photons at PV"}; + Configurable cfgMinV0Radius{"cfgMinV0Radius", 4.0, "min v0 radius"}; + Configurable cfgMaxV0Radius{"cfgMaxV0Radius", 90.0, "max v0 radius"}; + Configurable cfgMidLV0Radius{"cfgMidLV0Radius", -1.0, "middle low v0 radius for rejection if >0"}; + Configurable cfgMidHV0Radius{"cfgMidHV0Radius", -1.0, "middle high v0 radius for rejection if >0"}; + Configurable cfgMaxAlphaAP{"cfgMaxAlphaAP", 0.95, "max alpha for AP cut"}; + Configurable cfgMaxQtAP{"cfgMaxQtAP", 0.01, "max qT for AP cut"}; + Configurable cfgMinV0CosPA{"cfgMinV0CosPA", 0.999, "min V0 CosPA"}; + Configurable cfgMaxPCA{"cfgMaxPCA", 1.5, "max distance btween 2 legs"}; + Configurable cfgMaxChi2KF{"cfgMaxChi2KF", 1e+10, "max chi2/ndf with KF"}; + Configurable cfgRejectV0OnITSib{"cfgRejectV0OnITSib", true, "flag to reject V0s on ITSib"}; + } v0cuts; + + // single track cuts + struct : ConfigurableGroup { + std::string prefix = "trackcut_group"; + Configurable cfgMinNClustersTPC{"cfgMinNClustersTPC", 0, "min ncluster tpc"}; + Configurable cfgMinNCrossedRows{"cfgMinNCrossedRows", 40, "min crossed rows"}; + Configurable cfgMaxFracSharedClustersTPC{"cfgMaxFracSharedClustersTPC", 999.f, "max fraction of shared clusters in TPC"}; + Configurable cfgMaxChi2TPC{"cfgMaxChi2TPC", 4.0, "max chi2/NclsTPC"}; + Configurable cfgMaxChi2ITS{"cfgMaxChi2ITS", 36.0, "max chi2/NclsITS"}; + Configurable cfgMinTPCNsigmaEl{"cfgMinTPCNsigmaEl", -3.0, "min. TPC n sigma for electron"}; + Configurable cfgMaxTPCNsigmaEl{"cfgMaxTPCNsigmaEl", +3.0, "max. TPC n sigma for electron"}; + Configurable cfgDisableITSonlyTracks{"cfgDisableITSonlyTracks", false, "disable ITSonly tracks in V0 legs"}; + Configurable cfgDisableTPConlyTracks{"cfgDisableTPConlyTracks", false, "disable TPConly tracks in V0 legs"}; + Configurable cfgDoDEdxPostCalibration{"cfgDoDEdxPostCalibration", false, "flag to enable dEdx post calibration"}; + } trackcuts; + + // pT-dependent loss QA + struct : ConfigurableGroup { + std::string prefix = "qaSettings_group"; + Configurable cfgDoPtDependentLossQA{"cfgDoPtDependentLossQA", false, "fill the cut variables vs. pT before AND after the V0 selection - the after/before ratio shows which candidates the cuts remove"}; + Configurable cfgDoKappaAnalysis{"cfgDoKappaAnalysis", false, "fill histograms with kappa vs pT vs cent."}; + } qaSettingsGroup; + + // PCM ML inference + struct : ConfigurableGroup { + std::string prefix = "mlcut_group"; + Configurable cfgApplyPCMMl{"cfgApplyPCMMl", false, "Flag to apply ML selections"}; + Configurable cfgUse2DBinning{"cfgUse2DBinning", false, "Flag to enable/disable 2D binning for ML application"}; + Configurable cfgLoadModelsFromCCDB{"cfgLoadModelsFromCCDB", true, "Flag to enable or disable the loading of models from CCDB"}; + Configurable cfgTimestampCCDB{"cfgTimestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; + Configurable cfgNClassesPCMMl{"cfgNClassesPCMMl", static_cast(o2::analysis::em_cuts_ml::NCutScores), "Number of classes in ML model"}; + Configurable> cfgCutDirPCMMl{"cfgCutDirPCMMl", std::vector{o2::analysis::em_cuts_ml::vecCutDir}, "Whether to reject score values greater or smaller than the threshold"}; + Configurable> cfgNamesInputFeatures{"cfgNamesInputFeatures", std::vector{"feature1", "feature2"}, "Names of ML model input features"}; + Configurable> cfgModelPathsCCDB{"cfgModelPathsCCDB", std::vector{"path_ccdb/BDT_PCM/"}, "Paths of models on CCDB"}; + Configurable> cfgOnnxFileNames{"cfgOnnxFileNames", std::vector{"ModelHandler_onnx_PCM.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; + Configurable> cfgLabelsBinsPCMMl{"cfgLabelsBinsPCMMl", std::vector{"bin 0", "bin 1"}, "Labels for bins"}; + Configurable> cfgLabelsCutScoresPCMMl{"cfgLabelsCutScoresPCMMl", std::vector{o2::analysis::em_cuts_ml::labelsCutScore}, "Labels for cut scores"}; + Configurable> cfgBinsPtPCMMl{"cfgBinsPtPCMMl", std::vector{0.0, +1e+10}, "pT bin limits for ML application"}; + Configurable> cfgBinsCentPCMMl{"cfgBinsCentPCMMl", std::vector{o2::analysis::em_cuts_ml::vecBinsCent}, "Centrality bin limits for ML application"}; + Configurable> cfgCutsPCMMlFlat{"cfgCutsPCMMlFlat", {0.5}, "Flattened ML cuts: [bin0_score0, bin0_score1, ..., binN_scoreM]"}; + } mlcuts; + + struct : ConfigurableGroup { + std::string prefix = "mcAnalysisModeSettings_group"; + Configurable cfgDoDetailedResolution{"cfgDoDetailedResolution", false, "purpose of the configurable is to choose if we have more THnSparses included in order to see if some regions have better or worse resolution"}; + Configurable cfgDoCollisionAssociationQA{"cfgDoCollisionAssociationQA", false, "include the QA Plots which give an idea how photon distribution changes with different subclasses or what the effect of wrong collision association is"}; + Configurable cfgRequireTrueAssociation{"cfgRequireTrueAssociation", false, "flag to require true mc collision association for the truth-classified QC observables"}; + } mcAnalysisModeSettings; + + struct : ConfigurableGroup { + std::string prefix = "materialBudgetSettings_group"; + Configurable cfgDoMaterialDistribution{"cfgDoMaterialDistribution", false, "add THnSparses of the conversion-point distribution for the material budget study"}; + Configurable cfgDoWiresDetail{"cfgDoWiresDetail", false, "add detailed conversion-point histograms around the wire region"}; + Configurable cfgDoMFTDetail{"cfgDoMFTDetail", false, "add detailed conversion-point histograms around the MFT region"}; + Configurable cfgDoITSDetail{"cfgDoITSDetail", false, "add detailed conversion-point histograms around the ITS layers"}; + Configurable cfgDoTPCInnerBarrelDetail{"cfgDoTPCInnerBarrelDetail", false, "add detailed conversion-point histograms around the TPC inner barrel"}; + } materialBudgetSettingsGroup; + + struct : ConfigurableGroup { + std::string prefix = "genSettings_group"; + Configurable cfgMaxRGen{"cfgMaxRGen", 90.f, "maximum conversion radius for generated photons (fiducial cut, matches the reco acceptance)"}; + Configurable cfgMarginZMC{"cfgMarginZMC", 7.0, "margin for z cut in cm for MC"}; + } genSettingsGroup; + struct : ConfigurableGroup { - std::string prefix = "pcmcut_group"; - Configurable cfg_require_v0_with_itstpc{"cfg_require_v0_with_itstpc", false, "flag to select V0s with ITS-TPC matched tracks"}; - Configurable cfg_require_v0_with_itsonly{"cfg_require_v0_with_itsonly", false, "flag to select V0s with ITSonly tracks"}; - Configurable cfg_require_v0_with_tpconly{"cfg_require_v0_with_tpconly", false, "flag to select V0s with TPConly tracks"}; - Configurable cfg_min_pt_v0{"cfg_min_pt_v0", 0.1, "min pT for v0 photons at PV"}; - Configurable cfg_max_pt_v0{"cfg_max_pt_v0", 1e+10, "max pT for v0 photons at PV"}; - Configurable cfg_min_eta_v0{"cfg_min_eta_v0", -0.8, "min eta for v0 photons at PV"}; - Configurable cfg_max_eta_v0{"cfg_max_eta_v0", +0.8, "max eta for v0 photons at PV"}; - Configurable cfg_min_v0radius{"cfg_min_v0radius", 4.0, "min v0 radius"}; - Configurable cfg_max_v0radius{"cfg_max_v0radius", 90.0, "max v0 radius"}; - Configurable cfg_midL_v0radius{"cfg_midL_v0radius", -1.0, "middle low v0 radius for rejection if >0"}; - Configurable cfg_midH_v0radius{"cfg_midH_v0radius", -1.0, "middle high v0 radius for rejection if >0"}; - Configurable cfg_max_alpha_ap{"cfg_max_alpha_ap", 0.95, "max alpha for AP cut"}; - Configurable cfg_max_qt_ap{"cfg_max_qt_ap", 0.01, "max qT for AP cut"}; - Configurable cfg_min_cospa{"cfg_min_cospa", 0.999, "min V0 CosPA"}; - Configurable cfg_max_pca{"cfg_max_pca", 1.5, "max distance btween 2 legs"}; - Configurable cfg_max_chi2kf{"cfg_max_chi2kf", 1e+10, "max chi2/ndf with KF"}; - Configurable cfg_reject_v0_on_itsib{"cfg_reject_v0_on_itsib", true, "flag to reject V0s on ITSib"}; - Configurable cfg_min_ncluster_tpc{"cfg_min_ncluster_tpc", 0, "min ncluster tpc"}; - Configurable cfg_min_ncrossedrows{"cfg_min_ncrossedrows", 40, "min ncrossed rows"}; - Configurable cfg_max_frac_shared_clusters_tpc{"cfg_max_frac_shared_clusters_tpc", 999.f, "max fraction of shared clusters in TPC"}; - Configurable cfg_max_chi2tpc{"cfg_max_chi2tpc", 4.0, "max chi2/NclsTPC"}; - Configurable cfg_max_chi2its{"cfg_max_chi2its", 36.0, "max chi2/NclsITS"}; - Configurable cfg_min_TPCNsigmaEl{"cfg_min_TPCNsigmaEl", -3.0, "min. TPC n sigma for electron"}; - Configurable cfg_max_TPCNsigmaEl{"cfg_max_TPCNsigmaEl", +3.0, "max. TPC n sigma for electron"}; - Configurable cfg_disable_itsonly_track{"cfg_disable_itsonly_track", false, "flag to disable ITSonly tracks"}; - Configurable cfg_disable_tpconly_track{"cfg_disable_tpconly_track", false, "flag to disable TPConly tracks"}; - Configurable cfg_dEdx_postcalibration{"cfg_dEdx_postcalibration", false, "flag to enable dEdx post calibration"}; - // for ML cuts - Configurable cfg_apply_ml_cuts{"cfg_apply_ml", false, "flag to apply ML cut"}; - Configurable cfg_use_2d_binning{"cfg_use_2d_binning", false, "flag to use 2D binning (pT, cent)"}; - Configurable cfg_load_ml_models_from_ccdb{"cfg_load_ml_models_from_ccdb", true, "flag to load ML models from CCDB"}; - Configurable cfg_timestamp_ccdb{"cfg_timestamp_ccdb", -1, "timestamp for CCDB"}; - Configurable cfg_nclasses_ml{"cfg_nclasses_ml", static_cast(o2::analysis::em_cuts_ml::NCutScores), "number of classes for ML"}; - Configurable> cfg_cut_dir_ml{"cfg_cut_dir_ml", std::vector{o2::analysis::em_cuts_ml::vecCutDir}, "cut direction for ML"}; - Configurable> cfg_input_feature_names{"cfg_input_feature_names", std::vector{"feature1", "feature2"}, "input feature names for ML models"}; - Configurable> cfg_model_paths_ccdb{"cfg_model_paths_ccdb", std::vector{"path_ccdb/BDT_PCM/"}, "CCDB paths for ML models"}; - Configurable> cfg_onnx_file_names{"cfg_onnx_file_names", std::vector{"ModelHandler_onnx_PCM.onnx"}, "ONNX file names for ML models"}; - Configurable> cfg_labels_bins_ml{"cfg_labels_bins_ml", std::vector{"bin 0", "bin 1"}, "Labels for bins"}; - Configurable> cfg_labels_cut_scores_ml{"cfg_labels_cut_scores_ml", std::vector{o2::analysis::em_cuts_ml::labelsCutScore}, "Labels for cut scores"}; - Configurable> cfg_bins_pt_ml{"cfg_bins_pt_ml", std::vector{0.0, +1e+10}, "pT bin limits for ML application"}; - Configurable> cfg_bins_cent_ml{"cfg_bins_cent_ml", std::vector{o2::analysis::em_cuts_ml::vecBinsCent}, "centrality bins for ML"}; - Configurable> cfg_cuts_ml_flat{"cfg_cuts_ml_flat", {0.5}, "Flattened ML cuts: [bin0_score0, bin0_score1, ..., binN_scoreM]"}; - } pcmcuts; + std::string prefix = "recoQASettings_group"; + Configurable cfgDoDetailedTrackQA{"cfgDoDetailedTrackQA", false, "add track-quality histograms of surviving vs. lost conversion legs"}; + Configurable cfgRMinGen{"cfgRMinGen", 1.f, "min true conversion radius (cm)"}; + Configurable cfgRMaxGen{"cfgRMaxGen", 90.f, "max true conversion radius (cm)"}; + Configurable cfgLegEtaMax{"cfgLegEtaMax", 0.9f, "max |eta| of true MC legs"}; + Configurable cfgPhotonEtaMax{"cfgPhotonEtaMax", 0.9f, "max |eta| of true MC photon"}; + Configurable cfgPhotonPtMin{"cfgPhotonPtMin", 0.1f, "min pT of true MC photon"}; + } recoQASettingsGroup; o2::ccdb::CcdbApi ccdbApi; o2::framework::Service ccdb{}; int mRunNumber = 0; float d_bz = 0; static constexpr std::array event_types = {"before/", "after/"}; + static constexpr std::array mcphoton_types = {"primary/", "fromWD/", "fromHS/", "fromPi0Dalitz/", "fromEtaDalitz/"}; HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; - void init(InitContext&) + void init(InitContext& context) { + + (void)context; addhistograms(); DefineEMEventCut(); DefinePCMCut(); @@ -166,45 +257,28 @@ struct PCMQC { ccdb->setFatalWhenNull(false); } - template + template void initCCDB(TCollision const& collision) { if (mRunNumber == collision.runNumber()) { return; } + mRunNumber = collision.runNumber(); // In case override, don't proceed, please - no CCDB access required - if (d_bz_input > -990) { + if (d_bz_input > -990) { // o2-linter: disable=magic-number (override value) d_bz = d_bz_input; o2::parameters::GRPMagField grpmag; - if (std::fabs(d_bz) > 1e-5) { - grpmag.setL3Current(30000.f / (d_bz / 5.0f)); + if (std::fabs(d_bz) > 1e-5) { // o2-linter: disable=magic-number (override value) + grpmag.setL3Current(30000.f / (d_bz / 5.0f)); // o2-linter: disable=magic-number (override value) } - mRunNumber = collision.runNumber(); return; } - auto run3grp_timestamp = collision.timestamp(); - o2::parameters::GRPObject* grpo = nullptr; - o2::parameters::GRPMagField* grpmag = nullptr; - if (!skipGRPOquery) { - grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); - } - if (grpo) { - // Fetch magnetic field from ccdb for current collision - d_bz = grpo->getNominalL3Field(); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; - } else { - grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); - if (!grpmag) { - LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; - } - // Fetch magnetic field from ccdb for current collision - d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; - } + // Fetch magnetic field from ccdb for current collision + d_bz = collision.grpMagField().getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << collision.timestamp() << " with magnetic field of " << d_bz << " kZG"; fV0PhotonCut.SetD_Bz(d_bz); - mRunNumber = collision.runNumber(); } void addhistograms() @@ -245,6 +319,11 @@ struct PCMQC { fRegistry.add("V0/hDCAxyz", "DCA to PV;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -5.f, +5.f}, {200, -5.f, +5.f}}, false); fRegistry.add("V0/hDCAz_Pt", "DCA_{z} to PV vs. p_{T};DCA_{z} (cm);p_{T} (GeV/c)", kTH2F, {{200, -5.f, +5.f}, {2000, 0.0f, 20}}, false); fRegistry.add("V0/hAPplot", "AP plot;#alpha;q_{T} (GeV/c)", kTH2F, {{200, -1.0f, +1.0f}, {250, 0.0f, 0.25f}}, false); + fRegistry.add("V0/hRxyVsPt", "conversion radius vs. pT;p_{T,#gamma} (GeV/c);R_{xy} (cm)", kTH2F, {{100, 0, 10}, {200, 0, 100}}, false); + fRegistry.add("V0/hEtaVsPt", "#eta vs. pT;p_{T,#gamma} (GeV/c);#eta", kTH2F, {{100, 0, 10}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("V0/hPhiVsPt", "#varphi vs. pT;p_{T,#gamma} (GeV/c);#varphi (rad.)", kTH2F, {{100, 0, 10}, {90, 0, o2::constants::math::TwoPI}}, false); + fRegistry.add("V0/hsAlphaQtPt", "Armenteros vs. pT;#alpha;q_{T} (GeV/c);p_{T,#gamma} (GeV/c)", kTHnSparseF, {{100, -1.0f, +1.0f}, {125, 0.0f, 0.25f}, {100, 0, 10}}, false); + fRegistry.add("V0/hPsiPairVsPt", "#psi_{pair} vs. pT;p_{T,#gamma} (GeV/c);#psi_{pair} (rad.)", kTH2F, {{100, 0, 10}, {200, -0.5f, +0.5f}}, false); fRegistry.add("V0/hMassGamma", "hMassGamma;R_{xy} (cm);m_{ee} (GeV/c^{2})", kTH2F, {{200, 0.0f, 100.0f}, {100, 0.0f, 0.1f}}, false); fRegistry.add("V0/hKFChi2vsM", "KF chi2 vs. m_{ee};m_{ee} (GeV/c^{2});KF chi2/NDF", kTH2F, {{100, 0.0f, 0.1f}, {100, 0.f, 100.0f}}, false); fRegistry.add("V0/hKFChi2vsR", "KF chi2 vs. conversion point in XY;R_{xy} (cm);KF chi2/NDF", kTH2F, {{200, 0.0f, 100.0f}, {100, 0.f, 100.0f}}, false); @@ -254,12 +333,12 @@ struct PCMQC { fRegistry.add("V0/hsConvPoint", "photon conversion point;r_{xy} (cm);#varphi (rad.);#eta;", kTHnSparseF, {{100, 0.0f, 100}, {90, 0, o2::constants::math::TwoPI}, {80, -2, +2}}, false); fRegistry.add("V0/hNgamma", "Number of #gamma candidates per collision", kTH1F, {{101, -0.5f, 100.5f}}); - if (pcmcuts.cfg_apply_ml_cuts) { - if (pcmcuts.cfg_nclasses_ml == 2) { + if (mlcuts.cfgApplyPCMMl) { + if (mlcuts.cfgNClassesPCMMl == 2) { // o2-linter: disable=magic-number (BDT class) fRegistry.add("V0/hBDTBackgroundScoreVsPt", "BDT background score vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); fRegistry.add("V0/hBDTSignalScoreVsPt", "BDT signal score vs pT; pT (GeV/c); BDT signal score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); fRegistry.add("V0/hPhiVPsi", "#varphi vs. #psi angle;#psi (rad.); #varphi (rad.)", kTH2F, {{200, -o2::constants::math::PI, o2::constants::math::PI}, {200, 0, o2::constants::math::TwoPI}}, false); - } else if (pcmcuts.cfg_nclasses_ml == 3) { + } else if (mlcuts.cfgNClassesPCMMl == 3) { // o2-linter: disable=magic-number (BDT class) fRegistry.add("V0/hBDTBackgroundScoreVsPt", "BDT background score vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); fRegistry.add("V0/hBDTPrimaryPhotonScoreVsPt", "BDT primary photon score vs pT; pT (GeV/c); BDT primary photon score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); fRegistry.add("V0/hBDTSecondaryPhotonScoreVsPt", "BDT secondary photon score vs pT; pT (GeV/c); BDT secondary photon score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}}); @@ -281,6 +360,7 @@ struct PCMQC { fRegistry.add("V0Leg/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); fRegistry.add("V0Leg/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); fRegistry.add("V0Leg/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("V0Leg/hTPCNsigmaElVsEta", "TPC n sigma el vs. eta;#eta;n #sigma_{e}^{TPC}", kTH2F, {{40, -1.0f, 1.0f}, {100, -5, +5}}, false); // eta-dependence = dE/dx calibration check (TOF/ITS n#sigma not stored in the V0Leg skim) fRegistry.add("V0Leg/hTPCNcr2Nf", "TPC Ncr/Nfindable", kTH1F, {{200, 0, 2}}, false); fRegistry.add("V0Leg/hTPCNcls2Nf", "TPC Ncls/Nfindable", kTH1F, {{200, 0, 2}}, false); fRegistry.add("V0Leg/hTPCNclsShared", "TPC Ncls shared/Ncls;p_{T} (GeV/c);N_{cls}^{shared}/N_{cls} in TPC", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); @@ -288,13 +368,206 @@ struct PCMQC { fRegistry.add("V0Leg/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{100, 0, 10}}, false); fRegistry.add("V0Leg/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); fRegistry.add("V0Leg/hMeanClusterSizeITS", "mean cluster size ITS; on ITS #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {160, 0, 16}}, false); - if (pcmcuts.cfg_dEdx_postcalibration) { + if (trackcuts.cfgDoDEdxPostCalibration) { fRegistry.add("V0Leg/hPvsConvPointvsTPCNsigmaElvsEta_Pos", "momentum of pos leg vs. conversion point of V0 vs. TPC n sigma pos vs. eta of pos leg; p (GeV/c); r_{xy} (cm); n #sigma_{e}^{TPC}; #eta", kTHnSparseF, {{200, 0, 20}, {100, 0, 100}, {500, -5, 5}, {200, -1, +1}}, false); fRegistry.add("V0Leg/hPvsConvPointvsTPCNsigmaElvsEta_Ele", "momentum of neg leg vs. conversion point of V0 vs. TPC n sigma el vs. eta of neg leg; p (GeV/c); r_{xy} (cm); n #sigma_{e}^{TPC}; #eta", kTHnSparseF, {{200, 0, 20}, {100, 0, 100}, {500, -5, 5}, {200, -1, +1}}, false); } - // fRegistry.add("V0Leg/hXY", "X vs. Y;X (cm);Y (cm)", kTH2F, {{100, 0, 100}, {80, -20, 20}}, false); - // fRegistry.add("V0Leg/hZX", "Z vs. X;Z (cm);X (cm)", kTH2F, {{200, -100, 100}, {100, 0, 100}}, false); - // fRegistry.add("V0Leg/hZY", "Z vs. Y;Z (cm);Y (cm)", kTH2F, {{200, -100, 100}, {80, -20, 20}}, false); + + if (materialBudgetSettingsGroup.cfgDoMaterialDistribution) { + fRegistry.add("MaterialBudget/hs", "conversion point;z (cm);r_{xy} (cm);#eta;#varphi (rad.);p_{T,#gamma} (GeV/c)", kTHnSparseF, {{200, -100, 100}, {100, 0, 100}, {80, -2, +2}, {90, 0, o2::constants::math::TwoPI}, {100, 0, 10}}, false); + } + if (materialBudgetSettingsGroup.cfgDoWiresDetail) { + fRegistry.add("MaterialBudget/Wires/hsLeft", "conversion point near left wire;x (cm);y (cm);z (cm);#varphi (rad.);r_{xy} (cm);p_{T,#gamma} (GeV/c)", kTHnSparseF, {{200, -20, 20}, {200, -20, 20}, {80, -20, 20}, {40, 3.15, 3.4}, {80, 0, 20}, {100, 0, 10}}, false); + fRegistry.add("MaterialBudget/Wires/hsRight", "conversion point near right wire;x (cm);y (cm);z (cm);#varphi (rad.);r_{xy} (cm);p_{T,#gamma} (GeV/c)", kTHnSparseF, {{200, -20, 20}, {200, -20, 20}, {80, -20, 20}, {40, 6.00, 6.15}, {80, 0, 20}, {100, 0, 10}}, false); + } + if (materialBudgetSettingsGroup.cfgDoITSDetail) { + fRegistry.add("MaterialBudget/ITS/hs", "conversion point around the ITS layers;x (cm);y (cm);z (cm);#varphi (rad.);r_{xy} (cm);p_{T,#gamma} (GeV/c)", kTHnSparseF, {{160, -40, 40}, {160, -40, 40}, {80, -40, 40}, {90, 0, o2::constants::math::TwoPI}, {150, 0, 60}, {100, 0, 10}}, false); + } + if (materialBudgetSettingsGroup.cfgDoMFTDetail) { + fRegistry.add("MaterialBudget/MFT/hs", "conversion point around the MFT region;x (cm);y (cm);z (cm);#varphi (rad.);r_{xy} (cm);p_{T,#gamma} (GeV/c)", kTHnSparseF, {{160, -80, 80}, {160, -80, 80}, {40, -40, 40}, {90, 0, o2::constants::math::TwoPI}, {40, 40, 60}, {100, 0, 10}}, false); + } + if (materialBudgetSettingsGroup.cfgDoTPCInnerBarrelDetail) { + fRegistry.add("MaterialBudget/TPC/hs", "conversion point around the TPC inner barrel;x (cm);y (cm);z (cm);#varphi (rad.);r_{xy} (cm);p_{T,#gamma} (GeV/c)", kTHnSparseF, {{160, -90, 90}, {160, -90, 90}, {80, -40, 40}, {90, 0, o2::constants::math::TwoPI}, {80, 60, 80}, {100, 0, 10}}, false); + } + + if (doprocessGen) { + std::vector ptbins; + ptbins.reserve(72); + for (int i = 0; i < 2; i++) { // o2-linter: disable=magic-number (binning) + ptbins.emplace_back(0.05 * (i - 0) + 0.0); // from 0 to 0.05 GeV/c, every 0.05 GeV/c + } + for (int i = 2; i < 51; i++) { // o2-linter: disable=magic-number (binning) + ptbins.emplace_back(0.1 * (i - 2) + 0.1); // from 0.1 to 4.9 GeV/c, every 0.1 GeV/c + } + for (int i = 51; i < 61; i++) { // o2-linter: disable=magic-number (binning) + ptbins.emplace_back(0.5 * (i - 51) + 5.0); // from 5 to 9.5 GeV/c, every 0.5 GeV/c + } + for (int i = 61; i < 72; i++) { // o2-linter: disable=magic-number (binning) + ptbins.emplace_back(1.0 * (i - 61) + 10.0); // from 10 to 20 GeV/c, every 1 GeV/c + } + const AxisSpec axisPtGen{ptbins, "p_{T,#gamma} (GeV/c)"}; + const AxisSpec axisRapidityGen{{0.0, +0.8, +0.9}, "rapidity |y_{#gamma}|"}; + + fRegistry.add("Generated/hPt", "pT;p_{T} (GeV/c)", kTH1D, {axisPtGen}, true); + fRegistry.add("Generated/hPtY", "Generated info", kTH2D, {axisPtGen, axisRapidityGen}, true); + fRegistry.add("Generated/hPt_ConversionPhoton", "converted photon pT;p_{T} (GeV/c)", kTH1D, {axisPtGen}, true); + fRegistry.add("Generated/hY_ConversionPhoton", "converted photon y;rapidity y", kTH1F, {{40, -2.0f, 2.0f}}, true); + fRegistry.add("Generated/hPhi_ConversionPhoton", "converted photon #varphi;#varphi (rad.)", kTH1F, {{180, 0, o2::constants::math::TwoPI}}, true); + fRegistry.add("Generated/hXY", "conversion point in XY MC;V_{x} (cm);V_{y} (cm)", kTH2F, {{800, -100.0f, 100.0f}, {800, -100.0f, 100.0f}}, true); + fRegistry.add("Generated/hRZ", "conversion point in RZ MC;V_{z} (cm);R_{xy} (cm)", kTH2F, {{400, -100.0f, 100.0f}, {400, 0.f, 100.0f}}, true); + fRegistry.add("Generated/hRPhi", "conversion point of #varphi vs. R_{xy} MC;#varphi (rad.);R_{xy} (cm);N_{e}", kTH2F, {{360, 0.0f, o2::constants::math::TwoPI}, {400, 0, 100}}, true); + fRegistry.add("Generated/hsConvPoint", "photon conversion point;r_{xy} (cm);#varphi (rad.);#eta;", kTHnSparseF, {{100, 0.0f, 100}, {90, 0, o2::constants::math::TwoPI}, {80, -2, +2}}, true); + fRegistry.add("Generated/hR_ConversionPhoton_wideR", "converted photon R_{xy} up to the EMCal, before fiducial cuts;R_{xy} (cm);N_{#gamma}", kTH1F, {{250, 0.0f, 500.0f}}, true); + fRegistry.add("Generated/hRZ_wideR", "conversion point in RZ up to the EMCal, before fiducial cuts;V_{z} (cm);R_{xy} (cm)", kTH2F, {{200, -400.0f, 400.0f}, {250, 0.0f, 500.0f}}, true); + fRegistry.add("Generated/hsRZPhi_wideR", "conversion point up to the EMCal, before fiducial cuts;V_{z} (cm);#varphi (rad.);R_{xy} (cm)", kTHnSparseF, {{200, -400.0f, 400.0f}, {360, 0.0f, o2::constants::math::TwoPI}, {250, 0.0f, 500.0f}}, true); + if (mcAnalysisModeSettings.cfgDoDetailedResolution) { + fRegistry.add("Generated/hPtEtaPhi", "Photon pt vs eta, and phi;p_{T, gen} (GeV/c);#eta;#phi", kTHnSparseF, {{200, 0., 20.}, {18, -0.9, 0.9}, {36, 0, o2::constants::math::TwoPI}}, false); + } + } + + if (doprocessPCMQCMC || doprocessPCMQCMCML) { + fRegistry.add("V0/primary/hPt", "pT;p_{T,#gamma} (GeV/c)", kTH1F, {{2000, 0.0f, 20}}, false); + fRegistry.add("V0/primary/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{90, 0, o2::constants::math::TwoPI}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("V0/primary/hXY", "conversion point in XY;V_{x} (cm);V_{y} (cm)", kTH2F, {{400, -100.0f, 100.0f}, {400, -100.0f, 100.0f}}, false); + fRegistry.add("V0/primary/hRZ", "conversion point in RZ;Z (cm);R_{xy} (cm)", kTH2F, {{200, -100, 100}, {200, 0.0f, 100.0f}}, false); + fRegistry.add("V0/primary/hCosPA", "V0CosPA;cosine pointing angle in 3D", kTH1F, {{100, 0.99f, 1.0f}}, false); + fRegistry.add("V0/primary/hCosPAXY", "V0CosPA;cosine pointing angle in XY", kTH1F, {{100, 0.99f, 1.0f}}, false); + fRegistry.add("V0/primary/hCosPARZ", "V0CosPA;cosine pointing angle in RZ", kTH1F, {{100, 0.99f, 1.0f}}, false); + fRegistry.add("V0/primary/hPCA", "distance between 2 legs;PCA (cm)", kTH1F, {{500, 0.0f, 5.0f}}, false); + fRegistry.add("V0/primary/hDCAxyz", "DCA to PV;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -5.f, +5.f}, {200, -5.f, +5.f}}, false); + fRegistry.add("V0/primary/hDCAz_Pt", "DCA_{z} to PV vs. p_{T};DCA_{z} (cm);p_{T} (GeV/c)", kTH2F, {{200, -5.f, +5.f}, {2000, 0.0f, 20}}, false); + fRegistry.add("V0/primary/hAPplot", "AP plot;#alpha;q_{T} (GeV/c)", kTH2F, {{200, -1.0f, +1.0f}, {250, 0.0f, 0.25f}}, false); + fRegistry.add("V0/primary/hRxyVsPt", "conversion radius vs. pT;p_{T,#gamma} (GeV/c);R_{xy} (cm)", kTH2F, {{100, 0, 10}, {200, 0, 100}}, false); + fRegistry.add("V0/primary/hEtaVsPt", "#eta vs. pT;p_{T,#gamma} (GeV/c);#eta", kTH2F, {{100, 0, 10}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("V0/primary/hPhiVsPt", "#varphi vs. pT;p_{T,#gamma} (GeV/c);#varphi (rad.)", kTH2F, {{100, 0, 10}, {90, 0, o2::constants::math::TwoPI}}, false); + fRegistry.add("V0/primary/hsAlphaQtPt", "Armenteros vs. pT;#alpha;q_{T} (GeV/c);p_{T,#gamma} (GeV/c)", kTHnSparseF, {{100, -1.0f, +1.0f}, {125, 0.0f, 0.25f}, {100, 0, 10}}, false); + fRegistry.add("V0/primary/hPsiPairVsPt", "#psi_{pair} vs. pT;p_{T,#gamma} (GeV/c);#psi_{pair} (rad.)", kTH2F, {{100, 0, 10}, {200, -0.5f, +0.5f}}, false); + fRegistry.add("V0/primary/hMassGamma", "hMassGamma;R_{xy} (cm);m_{ee} (GeV/c^{2})", kTH2F, {{200, 0.0f, 100.0f}, {100, 0.0f, 0.1f}}, false); + fRegistry.add("V0/primary/hKFChi2vsM", "KF chi2 vs. m_{ee};m_{ee} (GeV/c^{2});KF chi2/NDF", kTH2F, {{100, 0.0f, 0.1f}, {100, 0.f, 100.0f}}, false); + fRegistry.add("V0/primary/hKFChi2vsR", "KF chi2 vs. conversion point in XY;R_{xy} (cm);KF chi2/NDF", kTH2F, {{200, 0.0f, 100.0f}, {100, 0.f, 100.0f}}, false); + fRegistry.add("V0/primary/hKFChi2vsX", "KF chi2 vs. conversion point in X;X (cm);KF chi2/NDF", kTH2F, {{200, -100.0f, 100.0f}, {100, 0.f, 100.0f}}, false); + fRegistry.add("V0/primary/hKFChi2vsY", "KF chi2 vs. conversion point in Y;Y (cm);KF chi2/NDF", kTH2F, {{200, -100.0f, 100.0f}, {100, 0.f, 100.0f}}, false); + fRegistry.add("V0/primary/hKFChi2vsZ", "KF chi2 vs. conversion point in Z;Z (cm);KF chi2/NDF", kTH2F, {{200, -100.0f, 100.0f}, {100, 0.f, 100.0f}}, false); + fRegistry.add("V0/primary/hNgamma", "Number of true #gamma per collision;N_{#gamma} per event;Number of events", kTH1F, {{101, -0.5f, 100.5f}}); + fRegistry.add("V0/primary/hConvPoint_diffX", "conversion point diff X MC;X_{MC} (cm);X_{rec} - X_{MC} (cm)", kTH2F, {{200, -100, +100}, {100, -50.0f, 50.0f}}, true); + fRegistry.add("V0/primary/hConvPoint_diffY", "conversion point diff Y MC;Y_{MC} (cm);Y_{rec} - Y_{MC} (cm)", kTH2F, {{200, -100, +100}, {100, -50.0f, 50.0f}}, true); + fRegistry.add("V0/primary/hConvPoint_diffZ", "conversion point diff Z MC;Z_{MC} (cm);Z_{rec} - Z_{MC} (cm)", kTH2F, {{200, -100, +100}, {100, -50.0f, 50.0f}}, true); + fRegistry.add("V0/primary/hPtGen_DeltaPtOverPtGen", "photon p_{T} resolution;p_{T}^{gen} (GeV/c);(p_{T}^{rec} - p_{T}^{gen})/p_{T}^{gen}", kTH2F, {{1000, 0, 10}, {200, -1.0f, 1.0f}}, true); + fRegistry.add("V0/primary/hPtGen_DeltaEta", "photon #eta resolution;p_{T}^{gen} (GeV/c);#eta^{rec} - #eta^{gen}", kTH2F, {{200, 0, 20}, {199, -0.099, 0.099}}, true); + fRegistry.add("V0/primary/hPtGen_DeltaPhi", "photon #varphi resolution;p_{T}^{gen} (GeV/c);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{200, 0, 20}, {199, -0.099, 0.099}}, true); + fRegistry.add("V0/primary/hRxyGen_DeltaPtOverPtGen", "photon p_{T} resolution; R_{xy}^{gen} (cm);(p_{T}^{rec} - p_{T}^{gen})/p_{T}^{gen}", kTH2F, {{100, 0, 100}, {200, -1.0f, 1.0f}}, true); + fRegistry.add("V0/primary/hRxyGen_DeltaEta", "photon #eta resolution;R_{xy}^{gen} (cm);#eta^{rec} - #eta^{gen}", kTH2F, {{100, 0, 100}, {100, -0.5f, 0.5f}}, true); + fRegistry.add("V0/primary/hRxyGen_DeltaPhi", "photon #varphi resolution;R_{xy}^{gen} (cm);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{100, 0, 100}, {100, -0.5f, 0.5f}}, true); + fRegistry.add("V0/primary/hRxyGen_DeltaR", "photon R_{xy} resolution;R_{xy}^{gen} (cm);R_{xy}^{rec} - R_{xy}^{gen} (cm)", kTH2F, {{100, 0, 100}, {100, 0, 100}}, true); + fRegistry.add("V0/primary/hXY_MC", "X vs. Y of true photon conversion point.;X (cm);Y (cm)", kTH2F, {{400, -100.0f, +100}, {400, -100, +100}}, true); + fRegistry.add("V0/primary/hRZ_MC", "R vs. Z of true photon conversion point;Z (cm);R_{xy} (cm)", kTH2F, {{200, -100.0f, +100}, {200, 0, 100}}, true); + fRegistry.add("V0/primary/hsConvPoint", "photon conversion point;r_{xy} (cm);#varphi (rad.);#eta;", kTHnSparseF, {{100, 0.0f, 100}, {90, 0, o2::constants::math::TwoPI}, {80, -2, +2}}, false); + if (mcAnalysisModeSettings.cfgDoDetailedResolution) { + fRegistry.add("V0/primary/hEtaPhiResol", "Photon eta-phi resolution;p_{T} (GeV/c);#eta-diff;#phi-diff", kTH3F, {{200, 0., 20.}, {99, -0.049, 0.049}, {99, -0.049, 0.049}}, false); + fRegistry.add("V0/primary/hPtResolPtEtaPhi", "Photon resolution vs. pt, eta, and phi;p_{T_rec} - p_{T true} / p_{T true};p_{T} (GeV/c);#eta;#phi", kTHnSparseF, {{199, -0.995, 0.995}, {200, 0., 20.}, {18, -0.9, 0.9}, {36, 0, o2::constants::math::TwoPI}}, false); + fRegistry.add("V0/primary/hMomResolPtEtaPhi", "Photon momentum resolution vs. p, eta, and phi;p_{rec} - p_{true} / p_{true};p_{T} (GeV/c);#eta;#phi", kTHnSparseF, {{199, -0.995, 0.995}, {200, 0., 20.}, {18, -0.9, 0.9}, {36, 0, o2::constants::math::TwoPI}}, false); + fRegistry.add("V0/primary/hPtEtaPhi", "pt, eta, and phi;p_{T} (GeV/c);#eta;#phi", kTHnSparseF, {{200, 0., 20.}, {18, -0.9, 0.9}, {36, 0, o2::constants::math::TwoPI}}, false); + } + if (mlcuts.cfgApplyPCMMl) { + if (mlcuts.cfgNClassesPCMMl == 2) { // o2-linter: disable=magic-number (BDT group) + fRegistry.add("V0/primary/hBDTBackgroundScoreVsPt", "BDT background score vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 1.0f}}}); + fRegistry.add("V0/primary/hBDTSignalScoreVsPt", "BDT signal score vs pT; pT (GeV/c); BDT signal score", {HistType::kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 1.0f}}}); + } else if (mlcuts.cfgNClassesPCMMl == 3) { // o2-linter: disable=magic-number (BDT group) + fRegistry.add("V0/primary/hBDTBackgroundScoreVsPt", "BDT background score vs pT; pT (GeV/c); BDT background score", {HistType::kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 1.0f}}}); + fRegistry.add("V0/primary/hBDTPrimaryPhotonScoreVsPt", "BDT primary photon score vs pT; pT (GeV/c); BDT primary photon score", {HistType::kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 1.0f}}}); + fRegistry.add("V0/primary/hBDTSecondaryPhotonScoreVsPt", "BDT secondary photon score vs pT; pT (GeV/c); BDT secondary photon score", {HistType::kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 1.0f}}}); + } else { + fRegistry.add("V0/primary/hBDTScoreVsPt", "BDT score vs pT; pT (GeV/c); BDT score", {HistType::kTH2F, {{200, 0.0f, 20.0f}, {100, 0.0f, 1.0f}}}); + } + fRegistry.add("V0/primary/hPhiVPsi", "#varphi vs. #psi angle;#psi (rad.); #varphi (rad.)", kTH2F, {{200, -o2::constants::math::PI, o2::constants::math::PI}, {200, 0, o2::constants::math::TwoPI}}, false); + } + fRegistry.addClone("V0/primary/", "V0/fromWD/"); // from weak decay + fRegistry.addClone("V0/primary/", "V0/fromHS/"); // from hadronic shower in detector materials + fRegistry.addClone("V0/primary/", "V0/fromPi0Dalitz/"); // misidentified dielectron from pi0 dalitz decay + fRegistry.addClone("V0/primary/", "V0/fromEtaDalitz/"); // misidentified dielectron from eta dalitz decay + fRegistry.addClone("V0/primary/hPt", "V0/candidate/hPt"); // only for purity + fRegistry.addClone("V0/primary/hEtaPhi", "V0/candidate/hEtaPhi"); // only for purity + + fRegistry.add("V0Leg/primary/hPt", "pT;p_{T,e} (GeV/c)", kTH1F, {{1000, 0.0f, 10}}, false); + fRegistry.add("V0Leg/primary/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{1000, -50, 50}}, false); + fRegistry.add("V0Leg/primary/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{90, 0, o2::constants::math::TwoPI}, {200, -1.0f, 1.0f}}, false); + fRegistry.add("V0Leg/primary/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{200, -50.0f, 50.0f}, {200, -50.0f, 50.0f}}, false); + fRegistry.add("V0Leg/primary/hNclsTPC", "number of TPC clusters", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("V0Leg/primary/hNcrTPC", "number of TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, false); + fRegistry.add("V0Leg/primary/hChi2TPC", "chi2/number of TPC clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("V0Leg/primary/hTPCdEdx", "TPC dE/dx;p_{in} (GeV/c);TPC dE/dx (a.u.)", kTH2F, {{1000, 0, 10}, {200, 0, 200}}, false); + fRegistry.add("V0Leg/primary/hTPCNsigmaEl", "TPC n sigma el;p_{in} (GeV/c);n #sigma_{e}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("V0Leg/primary/hTPCNsigmaPi", "TPC n sigma pi;p_{in} (GeV/c);n #sigma_{#pi}^{TPC}", kTH2F, {{1000, 0, 10}, {100, -5, +5}}, false); + fRegistry.add("V0Leg/primary/hTPCNsigmaElVsEta", "TPC n sigma el vs. eta;#eta;n #sigma_{e}^{TPC}", kTH2F, {{40, -1.0f, 1.0f}, {100, -5, +5}}, false); + fRegistry.add("V0Leg/primary/hTPCNcr2Nf", "TPC Ncr/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("V0Leg/primary/hTPCNcls2Nf", "TPC Ncls/Nfindable", kTH1F, {{200, 0, 2}}, false); + fRegistry.add("V0Leg/primary/hTPCNclsShared", "TPC Ncls shared/Ncls;p_{T} (GeV/c);N_{cls}^{shared}/N_{cls} in TPC", kTH2F, {{1000, 0, 10}, {100, 0, 1}}, false); + fRegistry.add("V0Leg/primary/hNclsITS", "number of ITS clusters", kTH1F, {{8, -0.5, 7.5}}, false); + fRegistry.add("V0Leg/primary/hChi2ITS", "chi2/number of ITS clusters", kTH1F, {{100, 0, 10}}, false); + fRegistry.add("V0Leg/primary/hITSClusterMap", "ITS cluster map", kTH1F, {{128, -0.5, 127.5}}, false); + fRegistry.add("V0Leg/primary/hMeanClusterSizeITS", "mean cluster size ITS; on ITS #times cos(#lambda)", kTH2F, {{1000, 0, 10}, {160, 0, 16}}, false); + fRegistry.add("V0Leg/primary/hPtGen_DeltaPtOverPtGen", "electron p_{T} resolution;p_{T}^{gen} (GeV/c);(p_{T}^{rec} - p_{T}^{gen})/p_{T}^{gen}", kTH2F, {{1000, 0, 10}, {200, -1.0f, 1.0f}}, true); + fRegistry.add("V0Leg/primary/hPtGen_DeltaEta", "electron #eta resolution;p_{T}^{gen} (GeV/c);#eta^{rec} - #eta^{gen}", kTH2F, {{1000, 0, 10}, {100, -0.5f, 0.5f}}, true); + fRegistry.add("V0Leg/primary/hPtGen_DeltaPhi", "electron #varphi resolution;p_{T}^{gen} (GeV/c);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{1000, 0, 10}, {100, -0.5f, 0.5f}}, true); + fRegistry.add("V0Leg/primary/hRxyGen_DeltaPtOverPtGen", "electron p_{T} resolution; R_{xy}^{gen} (cm);(p_{T}^{rec} - p_{T}^{gen})/p_{T}^{gen}", kTH2F, {{100, 0, 100}, {200, -1.0f, 1.0f}}, true); + fRegistry.add("V0Leg/primary/hRxyGen_DeltaEta", "electron #eta resolution;R_{xy}^{gen} (cm);#eta^{rec} - #eta^{gen}", kTH2F, {{100, 0, 100}, {100, -0.5f, 0.5f}}, true); + fRegistry.add("V0Leg/primary/hRxyGen_DeltaPhi", "electron #varphi resolution;R_{xy}^{gen} (cm);#varphi^{rec} - #varphi^{gen} (rad.)", kTH2F, {{100, 0, 100}, {100, -0.5f, 0.5f}}, true); + fRegistry.addClone("V0Leg/primary/", "V0Leg/fromWD/"); + fRegistry.addClone("V0Leg/primary/", "V0Leg/fromHS/"); + fRegistry.addClone("V0Leg/primary/", "V0Leg/fromPi0Dalitz/"); + fRegistry.addClone("V0Leg/primary/", "V0Leg/fromEtaDalitz/"); + fRegistry.addClone("V0Leg/primary/hPt", "V0Leg/candidate/hPt"); // only for purity + fRegistry.addClone("V0Leg/primary/hEtaPhi", "V0Leg/candidate/hEtaPhi"); // only for purity + + // collision-association QA: + if (mcAnalysisModeSettings.cfgDoCollisionAssociationQA) { + fRegistry.add("CollisionAssociation/hDeltaCollId", "MC-event index difference;#Delta coll ID (rec - true);N_{#gamma}", kTH1F, {{21, -10.5, 10.5}}, true); + fRegistry.add("CollisionAssociation/RightCollisions/hs", "correctly associated;R_{rec} (cm);p_{T} (GeV/c);#Delta p_{T}/p_{T,gen};#Delta z (cm);#Delta R (cm);#Delta coll ID", kTHnSparseF, {{100, 0, 100}, {200, 0, 10}, {200, -1, 1}, {200, -20, 20}, {200, -8, 8}, {21, -10.5, 10.5}}, true); + fRegistry.add("CollisionAssociation/WrongCollisions/hs", "wrongly associated;R_{rec} (cm);p_{T} (GeV/c);#Delta p_{T}/p_{T,gen};#Delta z (cm);#Delta R (cm);#Delta coll ID", kTHnSparseF, {{100, 0, 100}, {200, 0, 10}, {200, -1, 1}, {200, -20, 20}, {200, -8, 8}, {21, -10.5, 10.5}}, true); + } + } + + // pT-dependent loss QA: + if (qaSettingsGroup.cfgDoPtDependentLossQA) { + fRegistry.add("V0/LossQA/before/hCosPAvsPt", "cosPA vs. pT;p_{T,#gamma} (GeV/c);cosine pointing angle", kTH2F, {{100, 0, 10}, {100, 0.99, 1.0}}, false); + fRegistry.add("V0/LossQA/before/hPCAvsPt", "PCA vs. pT;p_{T,#gamma} (GeV/c);PCA (cm)", kTH2F, {{100, 0, 10}, {500, 0, 5}}, false); + fRegistry.add("V0/LossQA/before/hQtAPvsPt", "AP q_{T} vs. pT;p_{T,#gamma} (GeV/c);q_{T} (GeV/c)", kTH2F, {{100, 0, 10}, {250, 0, 0.25}}, false); + fRegistry.add("V0/LossQA/before/hRxyVsPt", "conversion radius vs. pT;p_{T,#gamma} (GeV/c);R_{xy} (cm)", kTH2F, {{100, 0, 10}, {200, 0, 100}}, false); + fRegistry.add("V0/LossQA/before/hMeeVsPt", "m_{ee} vs. pT;p_{T,#gamma} (GeV/c);m_{ee} (GeV/c^{2})", kTH2F, {{100, 0, 10}, {100, 0, 0.1}}, false); + fRegistry.addClone("V0/LossQA/before/", "V0/LossQA/after/"); + } + + if (doprocessRecoQA) { + fRegistry.add("RecoQA/0_converted/hs", "true converted photons;p_{T,#gamma} (GeV/c);#eta;#varphi (rad.);R_{conv}^{true} (cm)", kTHnSparseF, {{100, 0, 10}, {36, -0.9, 0.9}, {36, 0, o2::constants::math::TwoPI}, {100, 0, 100}}, true); + fRegistry.addClone("RecoQA/0_converted/hs", "RecoQA/1_bothLegsTracked/hs"); + fRegistry.addClone("RecoQA/0_converted/hs", "RecoQA/2_bothLegsInV0Legs/hs"); + fRegistry.addClone("RecoQA/0_converted/hs", "RecoQA/3_photonInV0PhotonsKF/hs"); + fRegistry.add("RecoQA/hStageVsPt", "reconstruction stage vs. pT;p_{T,#gamma} (GeV/c);stage (0=converted,1=tracked,2=V0Legs,3=V0PhotonsKF)", kTH2F, {{100, 0, 10}, {4, -0.5, 3.5}}, true); + fRegistry.add("RecoQA/hMissingLeg_PtRconv", "legs tracked but lost before V0Legs;p_{T,leg}^{true} (GeV/c);R_{conv}^{true} (cm)", kTH2F, {{100, 0, 1}, {100, 0, 100}}, true); + fRegistry.add("RecoQA/Duplicates/hNTracksPerTrueLeg", "reconstructed tracks per true conversion leg;N_{tracks} per true leg;N_{legs}", kTH1F, {{6, -0.5, 5.5}}, true); + fRegistry.add("RecoQA/Duplicates/hNV0LegsPerTrueLeg", "V0Leg entries per true conversion leg;N_{V0Legs} per true leg;N_{legs}", kTH1F, {{6, -0.5, 5.5}}, true); + fRegistry.add("RecoQA/Duplicates/hNV0CandsPerPhoton_Rconv", "correctly built V0 candidates per true photon;N_{cand} per true #gamma;R_{conv}^{true} (cm)", kTH2F, {{6, -0.5, 5.5}, {100, 0, 100}}, true); + if (recoQASettingsGroup.cfgDoDetailedTrackQA) { + fRegistry.add("RecoQA/LegQuality/survived/hNcrTPC", "TPC crossed rows;TPC crossed rows", kTH1F, {{161, -0.5, 160.5}}, true); + fRegistry.add("RecoQA/LegQuality/survived/hChi2TPC", "chi2 per TPC cluster;#chi^{2}/N_{cls}^{TPC}", kTH1F, {{100, 0, 10}}, true); + fRegistry.add("RecoQA/LegQuality/survived/hSharedFracTPC", "TPC shared-cluster fraction;N_{cls}^{shared}/N_{cls}", kTH1F, {{110, 0, 1.1}}, true); + fRegistry.add("RecoQA/LegQuality/survived/hNclsTPC", "number of TPC clusters;N_{cls}^{TPC}", kTH1F, {{161, -0.5, 160.5}}, true); + fRegistry.addClone("RecoQA/LegQuality/survived/", "RecoQA/LegQuality/lost/"); + } + } + + if (qaSettingsGroup.cfgDoKappaAnalysis.value) { + if (doprocessQC || doprocessQCML) { + fRegistry.add("Kappa/Rec", ";#Kappa;#it{p}_{T} (GeV/#it{c});cent (%)", kTH3D, {{200, -10.f, 10.f}, {100, 0., 10.}, {20, 0., 100.}}, true); + } + if (doprocessPCMQCMC || doprocessPCMQCMCML) { + fRegistry.add("Kappa/MC/v0", "v0 ee pairs;#Kappa;#it{p}_{T} (GeV/#it{c});cent (%)", kTH3D, {{200, -10.f, 10.f}, {100, 0., 10.}, {20, 0., 100.}}, true); + fRegistry.add("Kappa/MC/ee", "ee pairs not from v0;#Kappa;#it{p}_{T} (GeV/#it{c});cent (%)", kTH3D, {{200, -10.f, 10.f}, {100, 0., 10.}, {20, 0., 100.}}, true); + fRegistry.add("Kappa/MC/pie", "pion + e pairs;#Kappa;#it{p}_{T} (GeV/#it{c});cent (%)", kTH3D, {{200, -10.f, 10.f}, {100, 0., 10.}, {20, 0., 100.}}, true); + fRegistry.add("Kappa/MC/pipi", "pion pion pairs;#Kappa;#it{p}_{T} (GeV/#it{c});cent (%)", kTH3D, {{200, -10.f, 10.f}, {100, 0., 10.}, {20, 0., 100.}}, true); + fRegistry.add("Kappa/MC/other", "other pairs;#Kappa;#it{p}_{T} (GeV/#it{c});cent (%)", kTH3D, {{200, -10.f, 10.f}, {100, 0., 10.}, {20, 0., 100.}}, true); + } + } } void DefineEMEventCut() @@ -320,57 +593,57 @@ struct PCMQC { fV0PhotonCut = V0PhotonCut("fV0PhotonCut", "fV0PhotonCut"); // for v0 - fV0PhotonCut.SetV0PtRange(pcmcuts.cfg_min_pt_v0, pcmcuts.cfg_max_pt_v0); - fV0PhotonCut.SetV0EtaRange(pcmcuts.cfg_min_eta_v0, pcmcuts.cfg_max_eta_v0); - fV0PhotonCut.SetMinCosPA(pcmcuts.cfg_min_cospa); - fV0PhotonCut.SetMaxPCA(pcmcuts.cfg_max_pca); - fV0PhotonCut.SetMaxChi2KF(pcmcuts.cfg_max_chi2kf); - fV0PhotonCut.SetRxyRange(pcmcuts.cfg_min_v0radius, pcmcuts.cfg_max_v0radius, pcmcuts.cfg_midL_v0radius, pcmcuts.cfg_midH_v0radius); - fV0PhotonCut.SetAPRange(pcmcuts.cfg_max_alpha_ap, pcmcuts.cfg_max_qt_ap); - fV0PhotonCut.RejectITSib(pcmcuts.cfg_reject_v0_on_itsib); + fV0PhotonCut.SetV0PtRange(v0cuts.cfgMinPtV0, v0cuts.cfgMaxPtV0); + fV0PhotonCut.SetV0EtaRange(v0cuts.cfgMinEtaV0, v0cuts.cfgMaxEtaV0); + fV0PhotonCut.SetMinCosPA(v0cuts.cfgMinV0CosPA); + fV0PhotonCut.SetMaxPCA(v0cuts.cfgMaxPCA); + fV0PhotonCut.SetMaxChi2KF(v0cuts.cfgMaxChi2KF); + fV0PhotonCut.SetRxyRange(v0cuts.cfgMinV0Radius, v0cuts.cfgMaxV0Radius, v0cuts.cfgMidLV0Radius, v0cuts.cfgMidHV0Radius); + fV0PhotonCut.SetAPRange(v0cuts.cfgMaxAlphaAP, v0cuts.cfgMaxQtAP); + fV0PhotonCut.RejectITSib(v0cuts.cfgRejectV0OnITSib); // for track - fV0PhotonCut.SetMinNClustersTPC(pcmcuts.cfg_min_ncluster_tpc); - fV0PhotonCut.SetMinNCrossedRowsTPC(pcmcuts.cfg_min_ncrossedrows); + fV0PhotonCut.SetMinNClustersTPC(trackcuts.cfgMinNClustersTPC); + fV0PhotonCut.SetMinNCrossedRowsTPC(trackcuts.cfgMinNCrossedRows); fV0PhotonCut.SetMinNCrossedRowsOverFindableClustersTPC(0.8); - fV0PhotonCut.SetMaxFracSharedClustersTPC(pcmcuts.cfg_max_frac_shared_clusters_tpc); - fV0PhotonCut.SetChi2PerClusterTPC(0.0, pcmcuts.cfg_max_chi2tpc); - fV0PhotonCut.SetTPCNsigmaElRange(pcmcuts.cfg_min_TPCNsigmaEl, pcmcuts.cfg_max_TPCNsigmaEl); - fV0PhotonCut.SetChi2PerClusterITS(-1e+10, pcmcuts.cfg_max_chi2its); + fV0PhotonCut.SetMaxFracSharedClustersTPC(trackcuts.cfgMaxFracSharedClustersTPC); + fV0PhotonCut.SetChi2PerClusterTPC(0.0, trackcuts.cfgMaxChi2TPC); + fV0PhotonCut.SetTPCNsigmaElRange(trackcuts.cfgMinTPCNsigmaEl, trackcuts.cfgMaxTPCNsigmaEl); + fV0PhotonCut.SetChi2PerClusterITS(-1e+10, trackcuts.cfgMaxChi2ITS); fV0PhotonCut.SetNClustersITS(0, 7); fV0PhotonCut.SetMeanClusterSizeITSob(0.0, 16.0); - fV0PhotonCut.SetDisableITSonly(pcmcuts.cfg_disable_itsonly_track); - fV0PhotonCut.SetDisableTPConly(pcmcuts.cfg_disable_tpconly_track); - fV0PhotonCut.SetRequireITSTPC(pcmcuts.cfg_require_v0_with_itstpc); - fV0PhotonCut.SetRequireITSonly(pcmcuts.cfg_require_v0_with_itsonly); - fV0PhotonCut.SetRequireTPConly(pcmcuts.cfg_require_v0_with_tpconly); + fV0PhotonCut.SetDisableITSonly(trackcuts.cfgDisableITSonlyTracks); + fV0PhotonCut.SetDisableTPConly(trackcuts.cfgDisableTPConlyTracks); + fV0PhotonCut.SetRequireITSTPC(v0cuts.cfgRequireV0WithITSTPC); + fV0PhotonCut.SetRequireITSonly(v0cuts.cfgRequireV0WithITSonly); + fV0PhotonCut.SetRequireTPConly(v0cuts.cfgRequireV0WithTPConly); // for ML - fV0PhotonCut.SetApplyMlCuts(pcmcuts.cfg_apply_ml_cuts); - fV0PhotonCut.SetUse2DBinning(pcmcuts.cfg_use_2d_binning); - fV0PhotonCut.SetLoadMlModelsFromCCDB(pcmcuts.cfg_load_ml_models_from_ccdb); - fV0PhotonCut.SetNClassesMl(pcmcuts.cfg_nclasses_ml); - fV0PhotonCut.SetMlTimestampCCDB(pcmcuts.cfg_timestamp_ccdb); + fV0PhotonCut.SetApplyMlCuts(mlcuts.cfgApplyPCMMl); + fV0PhotonCut.SetUse2DBinning(mlcuts.cfgUse2DBinning); + fV0PhotonCut.SetLoadMlModelsFromCCDB(mlcuts.cfgLoadModelsFromCCDB); + fV0PhotonCut.SetNClassesMl(mlcuts.cfgNClassesPCMMl); + fV0PhotonCut.SetMlTimestampCCDB(mlcuts.cfgTimestampCCDB); fV0PhotonCut.SetCcdbUrl(ccdburl); auto mCentralityTypeMlEnum = static_cast(cfgCentEstimator.value); fV0PhotonCut.SetCentralityTypeMl(mCentralityTypeMlEnum); - fV0PhotonCut.SetCutDirMl(pcmcuts.cfg_cut_dir_ml); - fV0PhotonCut.SetMlModelPathsCCDB(pcmcuts.cfg_model_paths_ccdb); - fV0PhotonCut.SetMlOnnxFileNames(pcmcuts.cfg_onnx_file_names); - fV0PhotonCut.SetBinsPtMl(pcmcuts.cfg_bins_pt_ml); - fV0PhotonCut.SetBinsCentMl(pcmcuts.cfg_bins_cent_ml); - fV0PhotonCut.SetCutsMl(pcmcuts.cfg_cuts_ml_flat); - fV0PhotonCut.SetNamesInputFeatures(pcmcuts.cfg_input_feature_names); - fV0PhotonCut.SetLabelsBinsMl(pcmcuts.cfg_labels_bins_ml); - fV0PhotonCut.SetLabelsCutScoresMl(pcmcuts.cfg_labels_cut_scores_ml); - fV0PhotonCut.SetD_Bz(0.0f); // dummy value -> only for psi_pair calculation - - if (pcmcuts.cfg_apply_ml_cuts) { + fV0PhotonCut.SetCutDirMl(mlcuts.cfgCutDirPCMMl); + fV0PhotonCut.SetMlModelPathsCCDB(mlcuts.cfgModelPathsCCDB); + fV0PhotonCut.SetMlOnnxFileNames(mlcuts.cfgOnnxFileNames); + fV0PhotonCut.SetBinsPtMl(mlcuts.cfgBinsPtPCMMl); + fV0PhotonCut.SetBinsCentMl(mlcuts.cfgBinsCentPCMMl); + fV0PhotonCut.SetCutsMl(mlcuts.cfgCutsPCMMlFlat); + fV0PhotonCut.SetNamesInputFeatures(mlcuts.cfgNamesInputFeatures); + fV0PhotonCut.SetLabelsBinsMl(mlcuts.cfgLabelsBinsPCMMl); + fV0PhotonCut.SetLabelsCutScoresMl(mlcuts.cfgLabelsCutScoresPCMMl); + fV0PhotonCut.SetD_Bz(0.0f); + + if (mlcuts.cfgApplyPCMMl) { fV0PhotonCut.initV0MlModels(ccdbApi); } } - template + template void fillEventInfo(TCollision const& collision, const float /*weight*/ = 1.f) { fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 1.0); @@ -395,7 +668,7 @@ struct PCMQC { if (collision.sel8()) { fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 8.0); } - if (std::fabs(collision.posZ()) < 10.0) { + if (std::fabs(collision.posZ()) < 10.0) { // o2-linter: disable=magic-number (vertex cut) fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hCollisionCounter"), 9.0); } fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hZvtx"), collision.posZ()); @@ -410,7 +683,7 @@ struct PCMQC { fRegistry.fill(HIST("Event/") + HIST(event_types[ev_id]) + HIST("hMultFT0MvsMultNTracksPV"), collision.multFT0A() + collision.multFT0C(), collision.multNTracksPV()); } - template + template void fillV0Info(TV0 const& v0) { fRegistry.fill(HIST("V0/hPt"), v0.pt()); @@ -424,6 +697,13 @@ struct PCMQC { fRegistry.fill(HIST("V0/hDCAxyz"), v0.dcaXYtopv(), v0.dcaZtopv()); fRegistry.fill(HIST("V0/hDCAz_Pt"), v0.dcaZtopv(), v0.pt()); fRegistry.fill(HIST("V0/hAPplot"), v0.alpha(), v0.qtarm()); + fRegistry.fill(HIST("V0/hRxyVsPt"), v0.pt(), v0.v0radius()); + fRegistry.fill(HIST("V0/hEtaVsPt"), v0.pt(), v0.eta()); + fRegistry.fill(HIST("V0/hPhiVsPt"), v0.pt(), v0.phi()); + fRegistry.fill(HIST("V0/hsAlphaQtPt"), v0.alpha(), v0.qtarm(), v0.pt()); + if constexpr (requires { v0.psipair(); }) { + fRegistry.fill(HIST("V0/hPsiPairVsPt"), v0.pt(), v0.psipair()); + } fRegistry.fill(HIST("V0/hMassGamma"), v0.v0radius(), v0.mGamma()); fRegistry.fill(HIST("V0/hKFChi2vsM"), v0.mGamma(), v0.chiSquareNDF()); fRegistry.fill(HIST("V0/hKFChi2vsR"), v0.v0radius(), v0.chiSquareNDF()); @@ -432,12 +712,12 @@ struct PCMQC { fRegistry.fill(HIST("V0/hKFChi2vsZ"), v0.vz(), v0.chiSquareNDF()); float phi_cp = std::atan2(v0.vy(), v0.vx()); - o2::math_utils::bringTo02Pi(phi_cp); + RecoDecay::constrainAngle(phi_cp); float eta_cp = std::atanh(v0.vz() / std::sqrt(std::pow(v0.vx(), 2) + std::pow(v0.vy(), 2) + std::pow(v0.vz(), 2))); fRegistry.fill(HIST("V0/hsConvPoint"), v0.v0radius(), phi_cp, eta_cp); // BDT response histogram can be filled here when apply BDT is true - if (pcmcuts.cfg_apply_ml_cuts) { + if (mlcuts.cfgApplyPCMMl) { const std::span& bdtValue = fV0PhotonCut.getBDTValue(); float psipair = 999.f; float phiv = 999.f; @@ -446,20 +726,20 @@ struct PCMQC { phiv = v0.phiv(); } fRegistry.fill(HIST("V0/hPhiVPsi"), psipair, phiv); - if (pcmcuts.cfg_nclasses_ml == 2 && bdtValue.size() == 2) { + if (mlcuts.cfgNClassesPCMMl == 2 && bdtValue.size() == 2) { // o2-linter: disable=magic-number (BDT) fRegistry.fill(HIST("V0/hBDTBackgroundScoreVsPt"), v0.pt(), bdtValue[0]); fRegistry.fill(HIST("V0/hBDTSignalScoreVsPt"), v0.pt(), bdtValue[1]); - } else if (pcmcuts.cfg_nclasses_ml == 3 && bdtValue.size() == 3) { + } else if (mlcuts.cfgNClassesPCMMl == 3 && bdtValue.size() == 3) { // o2-linter: disable=magic-number (BDT) fRegistry.fill(HIST("V0/hBDTBackgroundScoreVsPt"), v0.pt(), bdtValue[0]); fRegistry.fill(HIST("V0/hBDTPrimaryPhotonScoreVsPt"), v0.pt(), bdtValue[1]); fRegistry.fill(HIST("V0/hBDTSecondaryPhotonScoreVsPt"), v0.pt(), bdtValue[2]); } else if (bdtValue.size() == 1) { - fRegistry.fill(HIST("V0/hBDTCutVsPt"), v0.pt(), bdtValue[0]); + fRegistry.fill(HIST("V0/hBDTScoreVsPt"), v0.pt(), bdtValue[0]); } } } - template + template void fillV0LegInfo(TLeg const& leg) { fRegistry.fill(HIST("V0Leg/hPt"), leg.pt()); @@ -481,20 +761,97 @@ struct PCMQC { fRegistry.fill(HIST("V0Leg/hTPCdEdx"), leg.tpcInnerParam(), leg.tpcSignal()); fRegistry.fill(HIST("V0Leg/hTPCNsigmaEl"), leg.tpcInnerParam(), leg.tpcNSigmaEl()); fRegistry.fill(HIST("V0Leg/hTPCNsigmaPi"), leg.tpcInnerParam(), leg.tpcNSigmaPi()); - // fRegistry.fill(HIST("V0Leg/hXY"), leg.x(), leg.y()); - // fRegistry.fill(HIST("V0Leg/hZX"), leg.z(), leg.x()); - // fRegistry.fill(HIST("V0Leg/hZY"), leg.z(), leg.y()); + fRegistry.fill(HIST("V0Leg/hTPCNsigmaElVsEta"), leg.eta(), leg.tpcNSigmaEl()); + } + + template + void fillLossQAInfo(TV0 const& v0) + { + if (!qaSettingsGroup.cfgDoPtDependentLossQA) { + return; + } + fRegistry.fill(HIST("V0/LossQA/") + HIST(event_types[ev_id]) + HIST("hCosPAvsPt"), v0.pt(), v0.cospa()); + fRegistry.fill(HIST("V0/LossQA/") + HIST(event_types[ev_id]) + HIST("hPCAvsPt"), v0.pt(), v0.pca()); + fRegistry.fill(HIST("V0/LossQA/") + HIST(event_types[ev_id]) + HIST("hQtAPvsPt"), v0.pt(), v0.qtarm()); + fRegistry.fill(HIST("V0/LossQA/") + HIST(event_types[ev_id]) + HIST("hRxyVsPt"), v0.pt(), v0.v0radius()); + fRegistry.fill(HIST("V0/LossQA/") + HIST(event_types[ev_id]) + HIST("hMeeVsPt"), v0.pt(), v0.mGamma()); + } + + template + void fillMaterialBudgetInfo(TV0 const& v0) + { + if (materialBudgetSettingsGroup.cfgDoMaterialDistribution) { + fRegistry.fill(HIST("MaterialBudget/hs"), v0.vz(), v0.v0radius(), v0.eta(), v0.phi(), v0.pt()); + } + if (materialBudgetSettingsGroup.cfgDoWiresDetail && v0.v0radius() < 20.f && std::fabs(v0.vz()) < 20.f) { // o2-linter: disable=magic-number (region window = booking range) + if (3.15f < v0.phi() && v0.phi() < 3.4f) { // o2-linter: disable=magic-number (region window = booking range) + fRegistry.fill(HIST("MaterialBudget/Wires/hsLeft"), v0.vx(), v0.vy(), v0.vz(), v0.phi(), v0.v0radius(), v0.pt()); + } else if (6.00f < v0.phi() && v0.phi() < 6.15f) { // o2-linter: disable=magic-number (region window = booking range) + fRegistry.fill(HIST("MaterialBudget/Wires/hsRight"), v0.vx(), v0.vy(), v0.vz(), v0.phi(), v0.v0radius(), v0.pt()); + } + } + if (materialBudgetSettingsGroup.cfgDoITSDetail && v0.v0radius() < 60.f && std::fabs(v0.vz()) < 40.f) { // o2-linter: disable=magic-number (region window = booking range) + fRegistry.fill(HIST("MaterialBudget/ITS/hs"), v0.vx(), v0.vy(), v0.vz(), v0.phi(), v0.v0radius(), v0.pt()); + } + if (materialBudgetSettingsGroup.cfgDoMFTDetail && 40.f < v0.v0radius() && v0.v0radius() < 60.f && std::fabs(v0.vz()) < 40.f) { // o2-linter: disable=magic-number (region window = booking range) + fRegistry.fill(HIST("MaterialBudget/MFT/hs"), v0.vx(), v0.vy(), v0.vz(), v0.phi(), v0.v0radius(), v0.pt()); + } + if (materialBudgetSettingsGroup.cfgDoTPCInnerBarrelDetail && 60.f < v0.v0radius() && v0.v0radius() < 80.f && std::fabs(v0.vz()) < 40.f) { // o2-linter: disable=magic-number (region window = booking range) + fRegistry.fill(HIST("MaterialBudget/TPC/hs"), v0.vx(), v0.vy(), v0.vz(), v0.phi(), v0.v0radius(), v0.pt()); + } + } + + //_______________________________________________________________________ + template + void fillKappaRec(TLeg const& pos, TLeg const& ele, const float pt, const float cent) + { + if (!qaSettingsGroup.cfgDoKappaAnalysis.value) { + return; + } + const float kappa = getV0Kappa(pos, ele); + fRegistry.fill(HIST("Kappa/Rec"), kappa, pt, cent); } - Preslice perCollisionV0 = aod::v0photonkf::pmeventId; - Preslice perCollisionV0ML = aod::v0photonkf::pmeventId; + //_______________________________________________________________________ + template + void fillKappaMC(TLeg const& pos, TLeg const& ele, TMCParticle const& posmc, TMCParticle const& elemc, const int photonid, const float pt, const float cent) + { + if (!qaSettingsGroup.cfgDoKappaAnalysis.value) { + return; + } + + const float kappa = getV0Kappa(pos, ele); + + const int pdgPos = std::abs(posmc.pdgCode()); + const int pdgEle = std::abs(elemc.pdgCode()); + + const bool posIsElectron = (pdgPos == PDG_t::kElectron); + const bool eleIsElectron = (pdgEle == PDG_t::kElectron); + const bool posIsPion = (pdgPos == PDG_t::kPiPlus); + const bool eleIsPion = (pdgEle == PDG_t::kPiPlus); + + if (photonid > 0) { + fRegistry.fill(HIST("Kappa/MC/v0"), kappa, pt, cent); + } else if (posIsElectron && eleIsElectron) { + fRegistry.fill(HIST("Kappa/MC/ee"), kappa, pt, cent); + } else if ((posIsPion && eleIsElectron) || (posIsElectron && eleIsPion)) { + fRegistry.fill(HIST("Kappa/MC/pie"), kappa, pt, cent); + } else if (posIsPion && eleIsPion) { + fRegistry.fill(HIST("Kappa/MC/pipi"), kappa, pt, cent); + } else { + fRegistry.fill(HIST("Kappa/MC/other"), kappa, pt, cent); + } + } + + Preslice perCollisionV0 = aod::v0photonkf::pmeventId; Filter collisionFilter_centrality = (cfgCentMin < o2::aod::cent::centFT0M && o2::aod::cent::centFT0M < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0A && o2::aod::cent::centFT0A < cfgCentMax) || (cfgCentMin < o2::aod::cent::centFT0C && o2::aod::cent::centFT0C < cfgCentMax); Filter collisionFilter_occupancy_track = eventcuts.cfgTrackOccupancyMin <= o2::aod::evsel::trackOccupancyInTimeRange && o2::aod::evsel::trackOccupancyInTimeRange < eventcuts.cfgTrackOccupancyMax; Filter collisionFilter_occupancy_ft0c = eventcuts.cfgFT0COccupancyMin <= o2::aod::evsel::ft0cOccupancyInTimeRange && o2::aod::evsel::ft0cOccupancyInTimeRange < eventcuts.cfgFT0COccupancyMax; using FilteredMyCollisions = soa::Filtered; + using FilteredMyCollisionsMC = soa::Filtered; // same filters, they act column-wise - template - void process(FilteredMyCollisions const& collisions, TV0Photon const& v0photons, aod::V0Legs const&, TPerCollision const& perCollision) + template + void processRec(FilteredMyCollisions const& collisions, TV0Photon const& v0photons, aod::V0Legs const&) { for (const auto& collision : collisions) { initCCDB(collision); @@ -513,18 +870,22 @@ struct PCMQC { fV0PhotonCut.SetCentrality(centralities[cfgCentEstimator]); int nv0 = 0; - auto v0photons_coll = v0photons.sliceBy(perCollision, collision.globalIndex()); + auto v0photons_coll = v0photons.sliceBy(perCollisionV0, collision.globalIndex()); for (const auto& v0 : v0photons_coll) { auto pos = v0.template posTrack_as(); auto ele = v0.template negTrack_as(); + fillLossQAInfo<0>(v0); // all candidates offered to the selection if (!fV0PhotonCut.IsSelected(v0)) { continue; } + fillLossQAInfo<1>(v0); fillV0Info(v0); + fillKappaRec(pos, ele, v0.pt(), centralities[cfgCentEstimator]); + fillMaterialBudgetInfo(v0); for (const auto& leg : {pos, ele}) { fillV0LegInfo(leg); } - if (pcmcuts.cfg_dEdx_postcalibration) { + if (trackcuts.cfgDoDEdxPostCalibration) { fRegistry.fill(HIST("V0Leg/hPvsConvPointvsTPCNsigmaElvsEta_Pos"), pos.p(), v0.v0radius(), pos.tpcNSigmaEl(), pos.eta()); fRegistry.fill(HIST("V0Leg/hPvsConvPointvsTPCNsigmaElvsEta_Ele"), ele.p(), v0.v0radius(), ele.tpcNSigmaEl(), ele.eta()); } @@ -535,19 +896,522 @@ struct PCMQC { } void processQC(FilteredMyCollisions const& collisions, MyV0Photons const& v0photons, aod::V0Legs const& v0legs) { - process(collisions, v0photons, v0legs, perCollisionV0); + processRec(collisions, v0photons, v0legs); } // end of process void processQCML(FilteredMyCollisions const& collisions, MyV0PhotonsML const& v0photonsML, aod::V0Legs const& v0legs) { - process(collisions, v0photonsML, v0legs, perCollisionV0ML); + processRec(collisions, v0photonsML, v0legs); } // end of ML process - void processDummy(MyCollisions const&) {} + template + void fillV0InfoMC(TV0 const& v0, TMCV0 const& mcphoton, TMCLeg const& mcleg) + { + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPt"), v0.pt()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hEtaPhi"), v0.phi(), v0.eta()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hXY"), v0.vx(), v0.vy()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRZ"), v0.vz(), v0.v0radius()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hCosPA"), v0.cospa()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hCosPAXY"), v0.cospaXY()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hCosPARZ"), v0.cospaRZ()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPCA"), v0.pca()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hDCAxyz"), v0.dcaXYtopv(), v0.dcaZtopv()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hDCAz_Pt"), v0.dcaZtopv(), v0.pt()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hAPplot"), v0.alpha(), v0.qtarm()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRxyVsPt"), v0.pt(), v0.v0radius()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hEtaVsPt"), v0.pt(), v0.eta()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPhiVsPt"), v0.pt(), v0.phi()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hsAlphaQtPt"), v0.alpha(), v0.qtarm(), v0.pt()); + if constexpr (requires { v0.psipair(); }) { // only the ML join carries psi_pair + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPsiPairVsPt"), v0.pt(), v0.psipair()); + } + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hMassGamma"), v0.v0radius(), v0.mGamma()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hKFChi2vsM"), v0.mGamma(), v0.chiSquareNDF()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hKFChi2vsR"), v0.v0radius(), v0.chiSquareNDF()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hKFChi2vsX"), v0.vx(), v0.chiSquareNDF()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hKFChi2vsY"), v0.vy(), v0.chiSquareNDF()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hKFChi2vsZ"), v0.vz(), v0.chiSquareNDF()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPtGen_DeltaPtOverPtGen"), mcphoton.pt(), (v0.pt() - mcphoton.pt()) / mcphoton.pt()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPtGen_DeltaEta"), mcphoton.pt(), v0.eta() - mcphoton.eta()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPtGen_DeltaPhi"), mcphoton.pt(), v0.phi() - mcphoton.phi()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaPtOverPtGen"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), (v0.pt() - mcphoton.pt()) / mcphoton.pt()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaEta"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), v0.eta() - mcphoton.eta()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaPhi"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), v0.phi() - mcphoton.phi()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaR"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), v0.v0radius() - std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2))); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hConvPoint_diffX"), mcleg.vx(), v0.vx() - mcleg.vx()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hConvPoint_diffY"), mcleg.vy(), v0.vy() - mcleg.vy()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hConvPoint_diffZ"), mcleg.vz(), v0.vz() - mcleg.vz()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hXY_MC"), mcleg.vx(), mcleg.vy()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hRZ_MC"), mcleg.vz(), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2))); + + if (mcAnalysisModeSettings.cfgDoDetailedResolution) { + float resolPt = (v0.pt() - mcphoton.pt()) / mcphoton.pt(); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPtResolPtEtaPhi"), resolPt, mcphoton.pt(), mcphoton.eta(), mcphoton.phi()); + float resolMom = (v0.p() - mcphoton.p()) / mcphoton.p(); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hMomResolPtEtaPhi"), resolMom, mcphoton.pt(), mcphoton.eta(), mcphoton.phi()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPtEtaPhi"), mcphoton.pt(), mcphoton.eta(), mcphoton.phi()); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hEtaPhiResol"), mcphoton.pt(), v0.eta() - mcphoton.eta(), v0.phi() - mcphoton.phi()); + } + + float phi_cp = std::atan2(v0.vy(), v0.vx()); + RecoDecay::constrainAngle(phi_cp); + float eta_cp = std::atanh(v0.vz() / std::sqrt(std::pow(v0.vx(), 2) + std::pow(v0.vy(), 2) + std::pow(v0.vz(), 2))); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hsConvPoint"), v0.v0radius(), phi_cp, eta_cp); + + if (mlcuts.cfgApplyPCMMl) { + const std::span& bdtValue = fV0PhotonCut.getBDTValue(); + float psipair = 999.f; + float phiv = 999.f; + if constexpr (requires { v0.psipair(); v0.phiv(); }) { + psipair = v0.psipair(); + phiv = v0.phiv(); + } + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hPhiVPsi"), psipair, phiv); + if (mlcuts.cfgNClassesPCMMl == 2 && bdtValue.size() == 2) { // o2-linter: disable=magic-number (BDT) + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hBDTBackgroundScoreVsPt"), v0.pt(), bdtValue[0]); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hBDTSignalScoreVsPt"), v0.pt(), bdtValue[1]); + } else if (mlcuts.cfgNClassesPCMMl == 3 && bdtValue.size() == 3) { // o2-linter: disable=magic-number (BDT) + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hBDTBackgroundScoreVsPt"), v0.pt(), bdtValue[0]); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hBDTPrimaryPhotonScoreVsPt"), v0.pt(), bdtValue[1]); + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hBDTSecondaryPhotonScoreVsPt"), v0.pt(), bdtValue[2]); + } else if (bdtValue.size() == 1) { // o2-linter: disable=magic-number (BDT) + fRegistry.fill(HIST("V0/") + HIST(mcphoton_types[mctype]) + HIST("hBDTScoreVsPt"), v0.pt(), bdtValue[0]); + } + } + } + + template + void fillV0LegInfoMC(TLeg const& leg) + { + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hPt"), leg.pt()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hQoverPt"), leg.sign() / leg.pt()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hEtaPhi"), leg.phi(), leg.eta()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hDCAxyz"), leg.dcaXY(), leg.dcaZ()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hNclsITS"), leg.itsNCls()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hNclsTPC"), leg.tpcNClsFound()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hNcrTPC"), leg.tpcNClsCrossedRows()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hTPCNcr2Nf"), leg.tpcCrossedRowsOverFindableCls()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hTPCNcls2Nf"), leg.tpcFoundOverFindableCls()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hTPCNclsShared"), leg.pt(), leg.tpcFractionSharedCls()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hChi2TPC"), leg.tpcChi2NCl()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hChi2ITS"), leg.itsChi2NCl()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hITSClusterMap"), leg.itsClusterMap()); + if (leg.hasITS()) { + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hMeanClusterSizeITS"), leg.p(), leg.meanClusterSizeITS() * std::cos(std::atan(leg.tgl()))); + } + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hTPCdEdx"), leg.tpcInnerParam(), leg.tpcSignal()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hTPCNsigmaEl"), leg.tpcInnerParam(), leg.tpcNSigmaEl()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hTPCNsigmaPi"), leg.tpcInnerParam(), leg.tpcNSigmaPi()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hTPCNsigmaElVsEta"), leg.eta(), leg.tpcNSigmaEl()); + auto mcleg = leg.template emmcparticle_as(); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hPtGen_DeltaPtOverPtGen"), mcleg.pt(), (leg.pt() - mcleg.pt()) / mcleg.pt()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hPtGen_DeltaEta"), mcleg.pt(), leg.eta() - mcleg.eta()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hPtGen_DeltaPhi"), mcleg.pt(), leg.phi() - mcleg.phi()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaPtOverPtGen"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), (leg.pt() - mcleg.pt()) / mcleg.pt()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaEta"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), leg.eta() - mcleg.eta()); + fRegistry.fill(HIST("V0Leg/") + HIST(mcphoton_types[mctype]) + HIST("hRxyGen_DeltaPhi"), std::sqrt(std::pow(mcleg.vx(), 2) + std::pow(mcleg.vy(), 2)), leg.phi() - mcleg.phi()); + } + + template + void processMC(FilteredMyCollisionsMC const& collisions, TV0Photons const& v0photons, aod::EMMCParticles const& mcparticles, MyMCV0Legs const&, aod::EMMCEvents const&) + { + for (const auto& collision : collisions) { + initCCDB(collision); + const std::array centralities = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + + fillEventInfo<0>(collision); + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + fillEventInfo<1>(collision); + fRegistry.fill(HIST("Event/before/hCollisionCounter"), 10.0); // accepted + fRegistry.fill(HIST("Event/after/hCollisionCounter"), 10.0); // accepted + + fV0PhotonCut.SetCentrality(centralities[cfgCentEstimator]); // set centrality for BDT response + auto v0photons_coll = v0photons.sliceBy(perCollisionV0, collision.globalIndex()); + int ng_primary = 0, ng_wd = 0, ng_hs = 0, nee_pi0 = 0, nee_eta = 0; + for (const auto& v0 : v0photons_coll) { + auto pos = v0.template posTrack_as(); + auto ele = v0.template negTrack_as(); + auto posmc = pos.template emmcparticle_as(); + auto elemc = ele.template emmcparticle_as(); + + fillLossQAInfo<0>(v0); // all candidates offered to the selection + if (!fV0PhotonCut.IsSelected(v0)) { + continue; + } + fillLossQAInfo<1>(v0); + + fillMaterialBudgetInfo(v0); + + fRegistry.fill(HIST("V0/candidate/hPt"), v0.pt()); + fRegistry.fill(HIST("V0/candidate/hEtaPhi"), v0.phi(), v0.eta()); + for (const auto& leg : {pos, ele}) { + fRegistry.fill(HIST("V0Leg/candidate/hPt"), leg.pt()); + fRegistry.fill(HIST("V0Leg/candidate/hEtaPhi"), leg.phi(), leg.eta()); + } + + int photonid = FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 22, mcparticles); + int pi0id = FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 111, mcparticles); // pi0 dalitz decay + int etaid = FindCommonMotherFrom2Prongs(posmc, elemc, -11, 11, 221, mcparticles); // eta dalitz decay + + fillKappaMC(pos, ele, posmc, elemc, photonid, v0.pt(), centralities[cfgCentEstimator]); + + if (photonid < 0 && pi0id < 0 && etaid < 0) { + continue; + } + + if (photonid > 0) { + auto mcphoton = mcparticles.iteratorAt(photonid); + + if (mcAnalysisModeSettings.cfgDoCollisionAssociationQA) { + const int deltaCol = static_cast(collision.emmceventId()) - static_cast(mcphoton.emmceventId()); + const float rGen = std::sqrt(std::pow(elemc.vx(), 2) + std::pow(elemc.vy(), 2)); + const float deltaR = v0.v0radius() - rGen; + const float deltaZ = v0.vz() - elemc.vz(); + const float relPtRes = mcphoton.pt() > 0.f ? (v0.pt() - mcphoton.pt()) / mcphoton.pt() : 0.f; + fRegistry.fill(HIST("CollisionAssociation/hDeltaCollId"), deltaCol); + if (deltaCol == 0) { + fRegistry.fill(HIST("CollisionAssociation/RightCollisions/hs"), v0.v0radius(), v0.pt(), relPtRes, deltaZ, deltaR, deltaCol); + } else { + fRegistry.fill(HIST("CollisionAssociation/WrongCollisions/hs"), v0.v0radius(), v0.pt(), relPtRes, deltaZ, deltaR, deltaCol); + } + } + + if (mcAnalysisModeSettings.cfgRequireTrueAssociation && (mcphoton.emmceventId() != collision.emmceventId())) { + continue; + } + + if (mcphoton.isPhysicalPrimary() || mcphoton.producedByGenerator()) { + fillV0InfoMC<0>(v0, mcphoton, elemc); + for (const auto& leg : {pos, ele}) { + fillV0LegInfoMC<0>(leg); + } + ng_primary++; + } else if (IsFromWD(mcphoton.template emmcevent_as(), mcphoton, mcparticles) > 0) { + fillV0InfoMC<1>(v0, mcphoton, elemc); + for (const auto& leg : {pos, ele}) { + fillV0LegInfoMC<1>(leg); + } + ng_wd++; + } else { + fillV0InfoMC<2>(v0, mcphoton, elemc); + for (const auto& leg : {pos, ele}) { + fillV0LegInfoMC<2>(leg); + } + ng_hs++; + } + } else if (pi0id > 0) { + auto mcpi0 = mcparticles.iteratorAt(pi0id); + if (mcAnalysisModeSettings.cfgRequireTrueAssociation && (mcpi0.emmceventId() != collision.emmceventId())) { + continue; + } + if (mcpi0.isPhysicalPrimary() || mcpi0.producedByGenerator()) { + fillV0InfoMC<3>(v0, mcpi0, elemc); + for (const auto& leg : {pos, ele}) { + fillV0LegInfoMC<3>(leg); + } + nee_pi0++; + } + } else if (etaid > 0) { + auto mceta = mcparticles.iteratorAt(etaid); + if (mcAnalysisModeSettings.cfgRequireTrueAssociation && (mceta.emmceventId() != collision.emmceventId())) { + continue; + } + if (mceta.isPhysicalPrimary() || mceta.producedByGenerator()) { + fillV0InfoMC<4>(v0, mceta, elemc); + for (const auto& leg : {pos, ele}) { + fillV0LegInfoMC<4>(leg); + } + nee_eta++; + } + } + } // end of v0 loop + fRegistry.fill(HIST("V0/primary/hNgamma"), ng_primary); + fRegistry.fill(HIST("V0/fromWD/hNgamma"), ng_wd); + fRegistry.fill(HIST("V0/fromHS/hNgamma"), ng_hs); + fRegistry.fill(HIST("V0/fromPi0Dalitz/hNgamma"), nee_pi0); + fRegistry.fill(HIST("V0/fromEtaDalitz/hNgamma"), nee_eta); + } // end of collision loop + } // end of MC process + + void processPCMQCMC(FilteredMyCollisionsMC const& collisions, MyV0Photons const& v0photons, aod::EMMCParticles const& mcparticles, MyMCV0Legs const& mcv0legs, aod::EMMCEvents const& mcevents) + { + processMC(collisions, v0photons, mcparticles, mcv0legs, mcevents); + } // end of MC QC process + + void processPCMQCMCML(FilteredMyCollisionsMC const& collisions, MyV0PhotonsML const& v0photonsML, aod::EMMCParticles const& mcparticles, MyMCV0Legs const& mcv0legs, aod::EMMCEvents const& mcevents) + { + processMC(collisions, v0photonsML, mcparticles, mcv0legs, mcevents); + } // end of MC QC process with ML cuts + + template + void fillBinnedData(TBinnedData const& binned_data, const float weight = 1.f) + { + int xbin = 0, ybin = 0, zbin = 0; + auto hPtY = fRegistry.get(HIST("Generated/hPtY")); // 2D + auto hPt = fRegistry.get(HIST("Generated/hPt")); // 1D + + for (int ibin = 0; ibin < hPtY->GetNcells(); ibin++) { + int nentry = binned_data[ibin]; + hPtY->GetBinXYZ(ibin, xbin, ybin, zbin); + float pt = hPtY->GetXaxis()->GetBinCenter(xbin); + float y = hPtY->GetYaxis()->GetBinCenter(ybin); + if (y > v0cuts.cfgMaxEtaV0) { + continue; + } + + for (int j = 0; j < nentry; j++) { + hPtY->Fill(pt, y, weight); + hPt->Fill(pt, weight); + } + } + } + + PresliceUnsorted perMcCollision = aod::emmcparticle::emmceventId; + void processGen(FilteredMyCollisionsMC const& collisions, MyMCCollisions const&, aod::EMMCParticles const& mcparticles) + { + + for (const auto& collision : collisions) { + const std::array centralities = {collision.centFT0M(), collision.centFT0A(), collision.centFT0C()}; + if (centralities[cfgCentEstimator] < cfgCentMin || cfgCentMax < centralities[cfgCentEstimator]) { + continue; + } + if (!fEMEventCut.IsSelected(collision)) { + continue; + } + + auto mccollision = collision.template emmcevent_as(); + auto binned_data_gamma_gen = mccollision.generatedGamma(); + fillBinnedData(binned_data_gamma_gen, 1.f); + + auto mctracks_coll = mcparticles.sliceBy(perMcCollision, mccollision.globalIndex()); + for (const auto& mctrack : mctracks_coll) { + if (std::fabs(mctrack.y()) > v0cuts.cfgMaxEtaV0) { + continue; + } + if (std::abs(mctrack.pdgCode()) != PDG_t::kGamma || !(mctrack.isPhysicalPrimary() || mctrack.producedByGenerator())) { + continue; + } + + if (mcAnalysisModeSettings.cfgDoDetailedResolution) { + fRegistry.fill(HIST("Generated/hPtEtaPhi"), mctrack.pt(), mctrack.eta(), mctrack.phi()); // for all generated photons before any kinematic cut + } + if (mctrack.daughtersIds().empty()) { + continue; + } + auto daughter = mcparticles.iteratorAt(mctrack.daughtersIds()[0]); // choose ele or pos. + float rxy_gen_e = std::sqrt(std::pow(daughter.vx(), 2) + std::pow(daughter.vy(), 2)); + float phi_cp = std::atan2(daughter.vy(), daughter.vx()); + RecoDecay::constrainAngle(phi_cp); + float eta_cp = std::atanh(daughter.vz() / std::sqrt(std::pow(daughter.vx(), 2) + std::pow(daughter.vy(), 2) + std::pow(daughter.vz(), 2))); + + fRegistry.fill(HIST("Generated/hR_ConversionPhoton_wideR"), rxy_gen_e); + fRegistry.fill(HIST("Generated/hRZ_wideR"), daughter.vz(), rxy_gen_e); + fRegistry.fill(HIST("Generated/hsRZPhi_wideR"), daughter.vz(), phi_cp, rxy_gen_e); + if (rxy_gen_e < std::fabs(daughter.vz()) * std::tan(2 * std::atan(std::exp(-v0cuts.cfgMaxEtaV0))) - genSettingsGroup.cfgMarginZMC) { + continue; + } + if (rxy_gen_e > genSettingsGroup.cfgMaxRGen) { + continue; + } + + fRegistry.fill(HIST("Generated/hPt_ConversionPhoton"), mctrack.pt()); + fRegistry.fill(HIST("Generated/hY_ConversionPhoton"), mctrack.y()); + fRegistry.fill(HIST("Generated/hPhi_ConversionPhoton"), mctrack.phi()); + fRegistry.fill(HIST("Generated/hsConvPoint"), rxy_gen_e, phi_cp, eta_cp); + fRegistry.fill(HIST("Generated/hXY"), daughter.vx(), daughter.vy()); + fRegistry.fill(HIST("Generated/hRZ"), daughter.vz(), rxy_gen_e); + fRegistry.fill(HIST("Generated/hRPhi"), phi_cp, rxy_gen_e); + } // end of mctrack loop per collision + } // end of collision loop + } + + template + void fillLegQualityRecoQA(TTrack const& track) + { + if constexpr (survived) { + fRegistry.fill(HIST("RecoQA/LegQuality/survived/hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("RecoQA/LegQuality/survived/hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("RecoQA/LegQuality/survived/hSharedFracTPC"), track.tpcFractionSharedCls()); + fRegistry.fill(HIST("RecoQA/LegQuality/survived/hNclsTPC"), track.tpcNClsFound()); + } else { + fRegistry.fill(HIST("RecoQA/LegQuality/lost/hNcrTPC"), track.tpcNClsCrossedRows()); + fRegistry.fill(HIST("RecoQA/LegQuality/lost/hChi2TPC"), track.tpcChi2NCl()); + fRegistry.fill(HIST("RecoQA/LegQuality/lost/hSharedFracTPC"), track.tpcFractionSharedCls()); + fRegistry.fill(HIST("RecoQA/LegQuality/lost/hNclsTPC"), track.tpcNClsFound()); + } + } + + Preslice perMcCollisionTruth = aod::mcparticle::mcCollisionId; + void processRecoQA(aod::McCollisions const& mcCollisions, aod::McParticles const& mcparticles, MyTracksMC const& tracks, aod::V0Legs const& v0legs, aod::V0PhotonsKF const& v0photonsKF) + { + std::unordered_map nTracksOfMcId; + std::unordered_map mcIdToBestTrack; + std::unordered_map mcIdBestCrossedRows; + nTracksOfMcId.reserve(tracks.size()); + for (const auto& track : tracks) { + if (!track.has_mcParticle()) { + continue; + } + const int mcId = track.mcParticleId(); + nTracksOfMcId[mcId]++; + const float ncr = track.tpcNClsCrossedRows(); + auto it = mcIdBestCrossedRows.find(mcId); + if (it == mcIdBestCrossedRows.end() || ncr > it->second) { + mcIdBestCrossedRows[mcId] = ncr; + mcIdToBestTrack[mcId] = track.globalIndex(); + } + } + + std::unordered_map nV0LegsOfMcId; + nV0LegsOfMcId.reserve(v0legs.size()); + for (const auto& leg : v0legs) { + const int trackId = leg.trackId(); + if (trackId < 0 || trackId >= static_cast(tracks.size())) { + continue; + } + const auto track = tracks.iteratorAt(trackId); + if (track.has_mcParticle()) { + nV0LegsOfMcId[track.mcParticleId()]++; + } + } + auto legMcMotherId = [&](auto const& leg) -> int { + const int trackId = leg.trackId(); + if (trackId < 0 || trackId >= static_cast(tracks.size())) { + return -1; + } + const auto track = tracks.iteratorAt(trackId); + if (!track.has_mcParticle()) { + return -1; + } + const auto mc = track.mcParticle(); + if (!mc.has_mothers()) { + return -1; + } + return mc.mothersIds()[0]; + }; + std::unordered_map nV0CandsOfMcPhoton; + for (const auto& v0 : v0photonsKF) { + const int legPosIdx = v0.posTrackId(); + const int legNegIdx = v0.negTrackId(); + if (legPosIdx < 0 || legPosIdx >= static_cast(v0legs.size()) || legNegIdx < 0 || legNegIdx >= static_cast(v0legs.size())) { + continue; + } + const int motherPos = legMcMotherId(v0legs.iteratorAt(legPosIdx)); + const int motherNeg = legMcMotherId(v0legs.iteratorAt(legNegIdx)); + if (motherPos >= 0 && motherPos == motherNeg) { + nV0CandsOfMcPhoton[motherPos]++; + } + } + for (const auto& mcCollision : mcCollisions) { + const auto mcparticles_coll = mcparticles.sliceBy(perMcCollisionTruth, mcCollision.globalIndex()); + for (const auto& mctrack : mcparticles_coll) { + if (mctrack.pdgCode() != PDG_t::kGamma || !mctrack.isPhysicalPrimary()) { + continue; + } + if (std::fabs(mctrack.eta()) > recoQASettingsGroup.cfgPhotonEtaMax || mctrack.pt() < recoQASettingsGroup.cfgPhotonPtMin) { + continue; + } + if (!mctrack.has_daughters()) { + continue; + } + int idPos = -1, idNeg = -1; + for (const auto& daughterId : mctrack.daughtersIds()) { + if (daughterId < 0 || daughterId >= static_cast(mcparticles.size())) { + continue; + } + const auto daughter = mcparticles.iteratorAt(daughterId); + if (daughter.pdgCode() == -PDG_t::kElectron) { + idPos = daughterId; + } else if (daughter.pdgCode() == PDG_t::kElectron) { + idNeg = daughterId; + } + } + if (idPos < 0 || idNeg < 0) { + continue; // not an e+e- conversion + } + const auto daughterPos = mcparticles.iteratorAt(idPos); + const auto daughterNeg = mcparticles.iteratorAt(idNeg); + const float rConv = std::sqrt(std::pow(daughterPos.vx(), 2) + std::pow(daughterPos.vy(), 2)); + if (rConv < recoQASettingsGroup.cfgRMinGen || rConv > recoQASettingsGroup.cfgRMaxGen) { + continue; + } + if (std::fabs(daughterPos.eta()) > recoQASettingsGroup.cfgLegEtaMax || std::fabs(daughterNeg.eta()) > recoQASettingsGroup.cfgLegEtaMax) { + continue; + } + + fRegistry.fill(HIST("RecoQA/0_converted/hs"), mctrack.pt(), mctrack.eta(), mctrack.phi(), rConv); + fRegistry.fill(HIST("RecoQA/hStageVsPt"), mctrack.pt(), 0.f); + + auto countIn = [](std::unordered_map const& m, int key) -> int { + const auto it = m.find(key); + return (it == m.end()) ? 0 : it->second; + }; + const int nTrkPos = countIn(nTracksOfMcId, idPos); + const int nTrkNeg = countIn(nTracksOfMcId, idNeg); + const int nLegPos = countIn(nV0LegsOfMcId, idPos); + const int nLegNeg = countIn(nV0LegsOfMcId, idNeg); + const bool posTracked = nTrkPos > 0; + const bool negTracked = nTrkNeg > 0; + const bool posInV0Legs = nLegPos > 0; + const bool negInV0Legs = nLegNeg > 0; + + fRegistry.fill(HIST("RecoQA/Duplicates/hNTracksPerTrueLeg"), nTrkPos); + fRegistry.fill(HIST("RecoQA/Duplicates/hNTracksPerTrueLeg"), nTrkNeg); + fRegistry.fill(HIST("RecoQA/Duplicates/hNV0LegsPerTrueLeg"), nLegPos); + fRegistry.fill(HIST("RecoQA/Duplicates/hNV0LegsPerTrueLeg"), nLegNeg); + fRegistry.fill(HIST("RecoQA/Duplicates/hNV0CandsPerPhoton_Rconv"), countIn(nV0CandsOfMcPhoton, static_cast(mctrack.globalIndex())), rConv); + + if (posTracked && negTracked) { + fRegistry.fill(HIST("RecoQA/1_bothLegsTracked/hs"), mctrack.pt(), mctrack.eta(), mctrack.phi(), rConv); + fRegistry.fill(HIST("RecoQA/hStageVsPt"), mctrack.pt(), 1.f); + } + if (posInV0Legs && negInV0Legs) { + fRegistry.fill(HIST("RecoQA/2_bothLegsInV0Legs/hs"), mctrack.pt(), mctrack.eta(), mctrack.phi(), rConv); + fRegistry.fill(HIST("RecoQA/hStageVsPt"), mctrack.pt(), 2.f); + } + if (countIn(nV0CandsOfMcPhoton, static_cast(mctrack.globalIndex())) > 0) { + fRegistry.fill(HIST("RecoQA/3_photonInV0PhotonsKF/hs"), mctrack.pt(), mctrack.eta(), mctrack.phi(), rConv); + fRegistry.fill(HIST("RecoQA/hStageVsPt"), mctrack.pt(), 3.f); + } + if (posTracked && !posInV0Legs) { + fRegistry.fill(HIST("RecoQA/hMissingLeg_PtRconv"), daughterPos.pt(), rConv); + } + if (negTracked && !negInV0Legs) { + fRegistry.fill(HIST("RecoQA/hMissingLeg_PtRconv"), daughterNeg.pt(), rConv); + } + + if (recoQASettingsGroup.cfgDoDetailedTrackQA) { + for (const auto& legMcId : {idPos, idNeg}) { + if (countIn(nTracksOfMcId, legMcId) == 0) { + continue; + } + const auto itTrack = mcIdToBestTrack.find(legMcId); + if (itTrack == mcIdToBestTrack.end() || itTrack->second < 0 || itTrack->second >= static_cast(tracks.size())) { + continue; + } + const auto track = tracks.iteratorAt(itTrack->second); + if (countIn(nV0LegsOfMcId, legMcId) > 0) { + fillLegQualityRecoQA(track); + } else { + fillLegQualityRecoQA(track); + } + } + } + } // end of mc particle loop per true event + } // end of true event loop + } // end of reco QA process PROCESS_SWITCH(PCMQC, processQC, "run PCM QC", true); PROCESS_SWITCH(PCMQC, processQCML, "run PCM QC with ML", false); - PROCESS_SWITCH(PCMQC, processDummy, "Dummy function", false); + PROCESS_SWITCH(PCMQC, processPCMQCMC, "run PCM QC in MC", false); + PROCESS_SWITCH(PCMQC, processPCMQCMCML, "run PCM QC in MC with ML cuts", false); + PROCESS_SWITCH(PCMQC, processGen, "run generated information", false); + PROCESS_SWITCH(PCMQC, processRecoQA, "run single-photon reconstruction QA on AO2Ds", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& context) diff --git a/PWGEM/PhotonMeson/Tasks/photonResoTask.cxx b/PWGEM/PhotonMeson/Tasks/photonResoTask.cxx index 0df8f54af2a..a51c8533f95 100644 --- a/PWGEM/PhotonMeson/Tasks/photonResoTask.cxx +++ b/PWGEM/PhotonMeson/Tasks/photonResoTask.cxx @@ -28,8 +28,6 @@ #include #include -#include -#include #include #include #include @@ -80,8 +78,6 @@ enum class MapLevel { struct PhotonResoTask { o2::framework::Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - o2::framework::Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; - o2::framework::Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; o2::framework::Configurable skipGRPOquery{"skipGRPOquery", true, "skip grpo query"}; // configurable axis @@ -181,12 +177,12 @@ struct PhotonResoTask { SliceCache cache; - using EMCalPhotons = soa::Join; + using EMCalPhotons = soa::Join; using PcmPhotons = soa::Join; using PcmMcLegs = soa::Join; - using Colls = soa::Join; + using Colls = soa::Join; using McColls = o2::soa::Join; using McParticles = EMMCParticles; @@ -361,28 +357,11 @@ struct PhotonResoTask { if (mRunNumber == collision.runNumber()) { return; } + mRunNumber = collision.runNumber(); - auto run3GrpTimestamp = collision.timestamp(); - o2::parameters::GRPObject* grpo = nullptr; - o2::parameters::GRPMagField* grpmag = nullptr; - if (!skipGRPOquery) { - grpo = ccdb->getForTimeStamp(grpPath, run3GrpTimestamp); - } - if (grpo) { - // Fetch magnetic field from ccdb for current collision - dBz = grpo->getNominalL3Field(); - LOG(info) << "Retrieved GRP for timestamp " << run3GrpTimestamp << " with magnetic field of " << dBz << " kZG"; - } else { - grpmag = ccdb->getForTimeStamp(grpmagPath, run3GrpTimestamp); - if (!grpmag) { - LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3GrpTimestamp; - } - // Fetch magnetic field from ccdb for current collision - dBz = std::lround(5.f * grpmag->getL3Current() / 30000.f); - LOG(info) << "Retrieved GRP for timestamp " << run3GrpTimestamp << " with magnetic field of " << dBz << " kZG"; - } + dBz = collision.grpMagField().getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << collision.timestamp() << " with magnetic field of " << dBz << " kZG"; fV0PhotonCut.SetD_Bz(dBz); - mRunNumber = collision.runNumber(); } template diff --git a/PWGEM/PhotonMeson/Tasks/photonhbt.cxx b/PWGEM/PhotonMeson/Tasks/photonhbt.cxx index 3b42ca4d27b..1bbaab29506 100644 --- a/PWGEM/PhotonMeson/Tasks/photonhbt.cxx +++ b/PWGEM/PhotonMeson/Tasks/photonhbt.cxx @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -301,9 +302,12 @@ struct Photonhbt { [[nodiscard]] float legEta(int i) const { return fLegEta[i]; } [[nodiscard]] float legPhi(int i) const { return fLegPhi[i]; } [[nodiscard]] float legPt(int i) const { return fLegPt[i]; } + std::array fLegNsigEl{}; // TPC electron nsigma per leg, for the mixed-event leg similarity + [[nodiscard]] float legNsigEl(int i) const { return fLegNsigEl[i]; } int fNITSTPC{0}; pairutil::V0PhotonLegCounts fLegCounts{}; [[nodiscard]] pairutil::V0PhotonLegCounts const& legCounts() const { return fLegCounts; } + int fIsTruePhoton{-1}; }; struct PhotonMCInfo { @@ -315,6 +319,10 @@ struct Photonhbt { int motherId = -1; int motherPdg = 0; bool isPhysicalPrimary = false; + int posMotherId = -1; + int negMotherId = -1; + bool posMotherIsPhoton = false; + bool negMotherIsPhoton = false; }; enum class PairTruthType : uint8_t { @@ -350,6 +358,8 @@ struct Photonhbt { Configurable cfgFillDRDZSparse{"cfgFillDRDZSparse", true, "book/fill the FullRange |R1-R2|-Deltaz-qinv sparse (large; needs cfgQaLevel>=2)"}; Configurable cfgMaxQinvForProcessing{"cfgMaxQinvForProcessing", 0.5, "skip mixed pairs with q_inv above this before building observables"}; Configurable cfgFillLegPairSparses{"cfgFillLegPairSparses", false, "book/fill the 4D leg-pair QA sparses (very large)"}; + Configurable cfgFillLegSimilaritySparse{"cfgFillLegSimilaritySparse", true, "book/fill the like-sign leg similarity sparse (duplicate diagnostic: DeltaEta, DeltaPhi, pT ratio, dNsigma_e vs qinv)"}; + Configurable cfgFillLegSimilarityMixSparse{"cfgFillLegSimilarityMixSparse", false, "book/fill the MIXED-EVENT leg similarity sparse (kinematic baseline for the SE-ME duplicate excess; needs cfgFillLegSimilaritySparse)"}; Configurable cfgFillR1R2Sparse{"cfgFillR1R2Sparse", true, "book/fill the FullRange (R1, R2, q_inv) sparse: fix one conversion radius, see where the partner sits, per q_inv"}; } qaflags; @@ -358,7 +368,11 @@ struct Photonhbt { std::string prefix = "hbtanalysis_group"; Configurable cfgDo3D{"cfgDo3D", false, "enable 3D (qout,qside,qlong) analysis"}; Configurable cfgDo2D{"cfgDo2D", false, "enable 2D (qout,qinv) projection (requires cfgDo3D)"}; + Configurable cfgDo2DSideLong{"cfgDo2DSideLong", false, "additionally book/fill CF_2D_Side and CF_2D_Long (qside/qlong vs qinv; two extra 5D sparses -> costs fill time and merge size; requires cfgDo2D)"}; Configurable cfgUseLCMS{"cfgUseLCMS", false, "measure 1D relative momentum in LCMS"}; + Configurable cfgDoQinvGate3D{"cfgDoQinvGate3D", false, "book/fill CF_3D_Qinv: 3D LCMS CF with a COARSE qinv axis (edges = candidate gate values)"}; + ConfigurableAxis confMultNTracksBins{"confMultNTracksBins", {VARIABLE_WIDTH, 0., 100., 200., 300., 400., 500., 600, 700, 800, 900, 1000., 1100., 1200., 1300., 1400., 1500., 1600., 1700., 1800., 1900., 2000., 2100., 2200., 2300., 2400., 2500., 2600., 2700., 2800., 2900., 3000., 4000., 5000.}, "N_{tracks}^{PV} |#eta|<1 bins for CF sparses"}; + ConfigurableAxis confMultFT0MBins{"confMultFT0MBins", {VARIABLE_WIDTH, 0., 25., 50., 100., 200., 400., 800., 2000., 2500., 3000., 3500., 4000., 5000., 6000., 7000., 8000., 9000., 10000., 15000., 40000., 100000., 250000.}, "FT0M amplitude bins for CF sparses"}; } hbtanalysis; // ----- Photon Leg Classification @@ -587,6 +601,8 @@ struct Photonhbt { AxisSpec axisDeltaZ{confDeltaZBins, "#Delta z (cm)"}; AxisSpec axisOccupancy{confOccupancyQA, "occupancy"}; AxisSpec axisCentQA{confCentQABins, "centrality (%)"}; + [[nodiscard]] AxisSpec makeAxisMultNTracks() const { return AxisSpec{hbtanalysis.confMultNTracksBins, "N_{tracks}^{PV}, |#eta| < 1"}; } + [[nodiscard]] AxisSpec makeAxisMultFT0M() const { return AxisSpec{hbtanalysis.confMultFT0MBins, "mult. FT0M (amplitude)"}; } AxisSpec axisLegPt{confLegPtBins, "p_{T,leg} (GeV/c)"}; AxisSpec axisLegDR{confLegDRBins, "#DeltaR_{legs}"}; @@ -914,6 +930,7 @@ struct Photonhbt { void addMCAODHistograms() { fRegistryTruthMC.add("MCAOD/hPhotonStage", "conversion photons;0=converted, 1=both legs tracked, 2=both legs in same collision, 3=V0 matched;counts", kTH1F, {{4, -0.5f, 3.5f}}, true); + fRegistryTruthMC.add("MCAOD/hPhotonStageVsPt", "conversion photon stage vs p_{T};0=converted, 1=both legs tracked, 2=both legs in same collision, 3=V0 matched;p_{T,#gamma} (GeV/c)", kTH2F, {{4, -0.5f, 3.5f}, {100, 0.f, 10.f}}, true); fRegistryTruthMC.add("MCAOD/hV0Type", "matched V0, raw v0Type bitmap;v0Type;counts", kTH1F, {{8, -0.5f, 7.5f}}, true); fRegistryTruthMC.add("MCAOD/hV0MatchMultiplicity", "SVertexer V0 candidates per matched truth photon;N V0;counts", kTH1F, {{10, 0.5f, 10.5f}}, true); fRegistryTruthMC.add("MCAOD/hNTrackedColls", "collisions in which BOTH legs of a photon are tracked;N collisions;counts", kTH1F, {{5, 0.5f, 5.5f}}, true); @@ -924,6 +941,7 @@ struct Photonhbt { const AxisSpec axType{8, -0.5f, 7.5f, "v0Type (raw)"}; fRegistryTruthMC.add("MCAOD/hPairStage", "pair step histogram;pair stage;counts", kTH1F, {{4, -0.5f, 3.5f}}, true); + fRegistryTruthMC.add("MCAOD/hPairStageVsKt", "pair stage vs k_{T};pair stage;k_{T} (GeV/c)", kTH2F, {{4, -0.5f, 3.5f}, {75, 0.f, 0.75f}}, true); fRegistryTruthMC.add("MCAOD/hSparsePairStage", "pair step histogram", kTHnSparseF, {axStage, axisDeltaEta, axisDeltaPhi, axisQinv}, true); fRegistryTruthMC.add("MCAOD/hSparseDRStage", "pair step histogram", kTHnSparseF, {axStage, axisDeltaR, axisQinv}, true); @@ -945,6 +963,9 @@ struct Photonhbt { fRegistryTruthMC.add(("MCAOD/hAnaPCA" + reg).c_str(), "analytic PCA;class;PCA (cm)", kTH2F, {axClass, {150, 0.f, 30.f}}, true); fRegistryTruthMC.add(("MCAOD/hAnaCosPA" + reg).c_str(), "analytic cosPA;class;cosPA", kTH2F, {axClass, {200, 0.9f, 1.f}}, true); } + + fRegistryTruthMC.add("MCAOD/hDeltaS2x2_vs_Qinv", "2x2 score ambiguity;#DeltaS;q_{inv}^{true} (GeV/c)", kTH2F, {{100, 0.f, 10.f}, {60, 0.f, 0.3f}}, true); + fRegistryTruthMC.add("MCAOD/hDeltaS2x2_CrossWins", "2x2 groups where CROSS scores better;#DeltaS;q_{inv}^{true} (GeV/c)", kTH2F, {{100, 0.f, 10.f}, {60, 0.f, 0.3f}}, true); } // ─── Event histograms (fRegistry) ───────────────────────────────────────── @@ -964,10 +985,21 @@ struct Photonhbt { // ─── CF: final correlation-function output (fRegistryCF) ────────────────── void addPairCFHistograms() { + const AxisSpec axisMultNTracks = makeAxisMultNTracks(); + const AxisSpec axisMultFT0M = makeAxisMultFT0M(); if (hbtanalysis.cfgDo3D) { fRegistryCF.add("Pair/same/CF_3D", "diphoton correlation 3D LCMS", kTHnSparseD, {axisQout, axisQside, axisQlong, axisKt}, true); if (hbtanalysis.cfgDo2D) { - fRegistryCF.add("Pair/same/CF_2D", "diphoton correlation 2D (qout,qinv)", kTHnSparseD, {axisQout, axisQinv, axisKt}, true); + fRegistryCF.add("Pair/same/CF_2D", "diphoton correlation 2D (qout,qinv)", kTHnSparseD, {axisQout, axisQinv, axisMultNTracks, axisMultFT0M, axisKt}, true); + if (hbtanalysis.cfgDo2DSideLong) { + fRegistryCF.add("Pair/same/CF_2D_Side", "diphoton correlation 2D (qside,qinv)", kTHnSparseD, {axisQside, axisQinv, axisMultNTracks, axisMultFT0M, axisKt}, true); + fRegistryCF.add("Pair/same/CF_2D_Long", "diphoton correlation 2D (qlong,qinv)", kTHnSparseD, {axisQlong, axisQinv, axisMultNTracks, axisMultFT0M, axisKt}, true); + } + } + if (hbtanalysis.cfgDoQinvGate3D) { + const AxisSpec axisQinvGate{{0.0, 0.01, 0.02, 0.03, 0.05, 0.30}, "q_{inv} (GeV/c)"}; + fRegistryCF.add("Pair/same/CF_3D_Qinv", "diphoton correlation 3D LCMS + qinv gate axis", + kTHnSparseD, {axisQout, axisQside, axisQlong, axisKt, axisQinvGate}, true); } } else { fRegistryCF.add("Pair/same/CF_1D", hbtanalysis.cfgUseLCMS ? "diphoton correlation 1D LCMS" : "diphoton correlation 1D (qinv)", kTH2D, {hbtanalysis.cfgUseLCMS ? axisQabsLcms : axisQinv, axisKt}, true); @@ -979,6 +1011,8 @@ struct Photonhbt { fRegistryCF.add("Pair/same/hPhi_lowerPtV0", "azimuthal angle of lower-p_{T} V0 in pair;#phi (rad);counts", kTH1D, {axisPhi}, true); addFullRangeHistograms("Pair/same/FullRange/"); + fRegistryCF.add("Pair/same/CF_QLcms_Qinv", "diphoton CF |q|_{LCMS} vs. q_{inv}", kTHnSparseD, {axisQabsLcms, axisQinv, axisKt}, true); + fRegistryCF.addClone("Pair/same/", "Pair/mix/"); fRegistryCF.add("Pair/mix/hDiffBC", "diff. global BC in mixed event;|BC_{current}-BC_{mixed}|", kTH1D, {{10001, -0.5, 10000.5}}, true); @@ -1108,6 +1142,16 @@ struct Photonhbt { addQAHistogramsForStep(std::string("Pair/same/QA/") + step); } + if (qaflags.cfgFillLegSimilaritySparse.value) { + const AxisSpec axisLSDEta{100, -0.1f, 0.1f, "#Delta#eta(LS legs)"}; + const AxisSpec axisLSDPhi{100, -0.1f, 0.1f, "#Delta#varphi(LS legs) (rad)"}; + const AxisSpec axisLSPtRatio{50, 0.f, 1.f, "|p_{T,1}-p_{T,2}|/(p_{T,1}+p_{T,2})"}; + const AxisSpec axisLSDNsig{40, 0.f, 8.f, "|#Delta n#sigma_{e}^{TPC}|"}; + fRegistryPairQA.add("Pair/same/LegSimilarity/hSparse_dEta_dPhi_ptRatio_dNsig_Qinv", "like-sign leg similarity;#Delta#eta(LS legs);#Delta#varphi(LS legs) (rad);|p_{T,1}-p_{T,2}|/(p_{T,1}+p_{T,2});|#Delta n#sigma_{e}^{TPC}|;q_{inv} (GeV/c)", kTHnSparseF, {axisLSDEta, axisLSDPhi, axisLSPtRatio, axisLSDNsig, axisQinv}, true); + if (qaflags.cfgFillLegSimilarityMixSparse.value) { + fRegistryPairQA.addClone("Pair/same/LegSimilarity/", "Pair/mix/LegSimilarity/"); + } + } fRegistryPairQA.addClone("Pair/same/QA/", "Pair/mix/QA/"); if (mQa.legPairQa) { addLegPairQAForStep("Pair/same/QA/Before/"); @@ -1117,6 +1161,8 @@ struct Photonhbt { void addPairMCHistograms() { + const AxisSpec axisMultNTracks = makeAxisMultNTracks(); + const AxisSpec axisMultFT0M = makeAxisMultFT0M(); const AxisSpec axisTruthType{{0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5}, "truth type (1=TrueTrueDistinct,2=TrueTrueSamePhoton,3=SharedMcLeg," "4=TrueFake,5=FakeFake,6=Pi0Daughters)"}; @@ -1135,11 +1181,12 @@ struct Photonhbt { if (hbtanalysis.cfgDo3D) { fRegistryPairMC.add((base + "CF_3D").c_str(), "MC CF 3D LCMS", kTHnSparseD, {axisQout, axisQside, axisQlong, axisKt}, true); if (hbtanalysis.cfgDo2D) { - fRegistryPairMC.add((base + "CF_2D").c_str(), "MC CF 2D", kTHnSparseD, {axisQout, axisQinv, axisKt}, true); + fRegistryPairMC.add((base + "CF_2D").c_str(), "MC CF 2D", kTHnSparseD, {axisQout, axisQinv, axisMultNTracks, axisMultFT0M, axisKt}, true); } } else { fRegistryPairMC.add((base + "CF_1D").c_str(), hbtanalysis.cfgUseLCMS ? "MC CF 1D LCMS" : "MC CF 1D (qinv)", kTH2D, {hbtanalysis.cfgUseLCMS ? axisQabsLcms : axisQinv, axisKt}, true); } + fRegistryPairMC.add((base + "CF_QLcms_Qinv").c_str(), "MC CF |q|_{LCMS} vs. q_{inv}", kTHnSparseD, {axisQabsLcms, axisQinv, axisKt}, true); // 1D observables fRegistryPairMC.add((base + "hQinv").c_str(), "q_{inv};q_{inv} (GeV/c);counts", kTH1D, {axisQinv}, true); @@ -1186,9 +1233,53 @@ struct Photonhbt { } } + const AxisSpec axisPsiPair{90, 0.f, o2::constants::math::PIHalf, "|#psi_{pair}| (rad)"}; + const AxisSpec axisPhiV{90, 0.f, o2::constants::math::PI, "#varphi_{V} (rad)"}; + const AxisSpec axisIsTruePhoton{2, -0.5f, 1.5f, "photon is true (0/1)"}; + + fRegistryPairMC.add("Pair/same/MC/hSparse_PsiPair_PhiV_Qinv_Type", + "per-photon conversion topology;|#psi_{pair}| (rad);#varphi_{V} (rad);" + "q_{inv} (GeV/c);truth type;is true photon", + kTHnSparseF, {axisPsiPair, axisPhiV, axisQinv, axisTruthType, axisIsTruePhoton}, true); + + const AxisSpec axisMeeRatio{100, 0.f, 2.f, "min(m_{ee}^{cross})/q_{inv}"}; + fRegistryPairMC.add("Pair/same/MC/hSparse_MeeRatio_Qinv_Type", + "crossed-pair hypothesis per truth type;" + "min(m_{ee}^{cross})/q_{inv};q_{inv} (GeV/c);truth type", + kTHnSparseF, {axisMeeRatio, axisQinv, axisTruthType}, true); + // ─── Cross-type summary ────────────────────────────────────────────── fRegistryPairMC.add("Pair/same/MC/hTruthTypeVsQinv", "truth type vs q_{inv};q_{inv} (GeV/c);truth type", kTH2D, {axisQinv, axisTruthType}, true); fRegistryPairMC.add("Pair/same/MC/hTruthTypeVsKt", "truth type vs k_{T};k_{T} (GeV/c);truth type", kTH2D, {axisKt, axisTruthType}, true); + + fRegistryPairMC.add("Pair/mix/MC/hQinv_TrueTrue", "mixed pairs, both true;q_{inv} (GeV/c);counts", kTH1D, {axisQinv}, true); + fRegistryPairMC.add("Pair/mix/MC/hQinv_TrueFake", "mixed pairs, one fake;q_{inv} (GeV/c);counts", kTH1D, {axisQinv}, true); + fRegistryPairMC.add("Pair/mix/MC/hQinv_FakeFake", "mixed pairs, both fake;q_{inv} (GeV/c);counts", kTH1D, {axisQinv}, true); + + for (const auto& label : {std::string("TrueTrueDistinct/"), std::string("TrueFake/"), std::string("FakeFake/")}) { + const std::string mixBase = "Pair/mix/MC/" + label; + if (hbtanalysis.cfgDo3D) { + fRegistryPairMC.add((mixBase + "CF_3D").c_str(), "MC mixed CF 3D LCMS", kTHnSparseD, {axisQout, axisQside, axisQlong, axisKt}, true); + if (hbtanalysis.cfgDo2D) { + fRegistryPairMC.add((mixBase + "CF_2D").c_str(), "MC mixed CF 2D", kTHnSparseD, {axisQout, axisQinv, axisMultNTracks, axisMultFT0M, axisKt}, true); + } + } else { + fRegistryPairMC.add((mixBase + "CF_1D").c_str(), hbtanalysis.cfgUseLCMS ? "MC mixed CF 1D LCMS" : "MC mixed CF 1D (qinv)", kTH2D, {hbtanalysis.cfgUseLCMS ? axisQabsLcms : axisQinv, axisKt}, true); + } + fRegistryPairMC.add((mixBase + "CF_QLcms_Qinv").c_str(), "MC mixed CF |q|_{LCMS} vs. q_{inv}", kTHnSparseD, {axisQabsLcms, axisQinv, axisKt}, true); + } + + const AxisSpec axisLegOrigin{6, -0.5f, 5.5f, "0=conv e, 1=#pi^{0} Dalitz e, 2=#eta Dalitz e, 3=primary e, 4=other e, 5=NOT an electron"}; + for (const auto& cls : {std::string("truePhotons/"), std::string("fakePhotons/")}) { + const std::string spBase = "SinglePhotonMC/" + cls; + fRegistryPairMC.add((spBase + "hEtaPhi").c_str(), "#eta vs #varphi;#eta;#varphi (rad)", kTH2F, {axisEta, axisPhi}, true); + fRegistryPairMC.add((spBase + "hRZ").c_str(), "conversion point;z_{conv} (cm);R_{conv} (cm)", kTH2F, {axisZConv, axisR}, true); + fRegistryPairMC.add((spBase + "hEtaPt").c_str(), "#eta vs p_{T};#eta;p_{T} (GeV/c)", kTH2F, {axisEta, axisPt}, true); + fRegistryPairMC.add((spBase + "hLegOriginMatrix").c_str(), "pos-leg origin vs neg-leg origin;pos leg;neg leg", kTH2F, {axisLegOrigin, axisLegOrigin}, true); + } + + const AxisSpec axisFakeSubtype{3, -0.5f, 2.5f, "0=ordinary, 1=swap doublet, 2=partial swap"}; + fRegistryPairMC.add("Pair/same/MC/hFakeSubtypeVsQinv", "fake pair subtype vs q_{inv};q_{inv} (GeV/c);subtype", kTH2D, {axisQinv, axisFakeSubtype}, true); fRegistryPairMC.add("Pair/same/MC/hDEtaDPhi_truePairs", "true reco pairs (TrueTrueDistinct+SamePhoton+Pi0);" "#Delta#eta_{#gamma#gamma};#Delta#phi_{#gamma#gamma} (rad)", @@ -1217,7 +1308,7 @@ struct Photonhbt { if (hbtanalysis.cfgDo3D) { fRegistryPairMC.add("Pair/same/MC/NoLabel/CF_3D", "missing MC label - CF 3D LCMS", kTHnSparseD, {axisQout, axisQside, axisQlong, axisKt}, true); if (hbtanalysis.cfgDo2D) { - fRegistryPairMC.add("Pair/same/MC/NoLabel/CF_2D", "missing MC label - CF 2D", kTHnSparseD, {axisQout, axisQinv, axisKt}, true); + fRegistryPairMC.add("Pair/same/MC/NoLabel/CF_2D", "missing MC label - CF 2D", kTHnSparseD, {axisQout, axisQinv, axisMultNTracks, axisMultFT0M, axisKt}, true); } } else { fRegistryPairMC.add("Pair/same/MC/NoLabel/CF_1D", hbtanalysis.cfgUseLCMS ? "missing MC label - CF 1D LCMS" : "missing MC label - CF 1D (qinv)", kTH2D, {hbtanalysis.cfgUseLCMS ? axisQabsLcms : axisQinv, axisKt}, true); @@ -1580,6 +1671,7 @@ struct Photonhbt { p.fLegPt = {static_cast(pos.pt()), static_cast(ele.pt())}; p.fLegEta = {static_cast(pos.eta()), static_cast(ele.eta())}; p.fLegPhi = {static_cast(pos.phi()), static_cast(ele.phi())}; + p.fLegNsigEl = {static_cast(pos.tpcNSigmaEl()), static_cast(ele.tpcNSigmaEl())}; p.fLegCounts = pairutil::getV0PhotonLegCounts(pos, ele); p.fNITSTPC = p.fLegCounts.nITSTPC; // legHelixAt itself rejects radii below the conversion point @@ -1831,6 +1923,49 @@ struct Photonhbt { /*************************************************/ // FILL HELPERS /*************************************************/ + template + void fillLegSimilarityValues(float etaA, float phiA, float ptA, float nsigA, + float etaB, float phiB, float ptB, float nsigB, float qinv) + { + if (!qaflags.cfgFillLegSimilaritySparse.value || qinv > 0.3f) { // o2-linter: disable=magic-number (sparse axis range) + return; + } + if constexpr (ev_id == 1) { + if (!qaflags.cfgFillLegSimilarityMixSparse.value) { + return; // mixed-event sparse not booked + } + } + const float deta = etaA - etaB; + const float dphi = RecoDecay::constrainAngle(phiA - phiB, -o2::constants::math::PI); + if (std::fabs(deta) > 0.1f || std::fabs(dphi) > 0.1f) { // o2-linter: disable=magic-number (sparse axis range) + return; + } + const float ptSum = ptA + ptB; + const float ptRatio = (ptSum > 0.f) ? std::fabs(ptA - ptB) / ptSum : 0.f; + const float dNsigma = std::fabs(nsigA - nsigB); + if constexpr (ev_id == 0) { + fRegistryPairQA.fill(HIST("Pair/same/LegSimilarity/hSparse_dEta_dPhi_ptRatio_dNsig_Qinv"), + deta, dphi, ptRatio, std::min(dNsigma, 7.99f), qinv); // o2-linter: disable=magic-number (clamp to axis) + } else { + fRegistryPairQA.fill(HIST("Pair/mix/LegSimilarity/hSparse_dEta_dPhi_ptRatio_dNsig_Qinv"), + deta, dphi, ptRatio, std::min(dNsigma, 7.99f), qinv); // o2-linter: disable=magic-number (clamp to axis) + } + } + + template + void fillLegSimilarity(TLegA const& legA, TLegB const& legB, float qinv) + { + fillLegSimilarityValues<0>(legA.eta(), legA.phi(), legA.pt(), legA.tpcNSigmaEl(), + legB.eta(), legB.phi(), legB.pt(), legB.tpcNSigmaEl(), qinv); + } + + void fillLegSimilarityMix(PhotonWithLegs const& a, PhotonWithLegs const& b, float qinv) + { + fillLegSimilarityValues<1>(a.legEta(0), a.legPhi(0), a.legPt(0), a.legNsigEl(0), + b.legEta(0), b.legPhi(0), b.legPt(0), b.legNsigEl(0), qinv); + fillLegSimilarityValues<1>(a.legEta(1), a.legPhi(1), a.legPt(1), a.legNsigEl(1), + b.legEta(1), b.legPhi(1), b.legPt(1), b.legNsigEl(1), qinv); + } template inline void fillFullRangeQA(PairQAObservables const& obs, float cent, float occupancy) @@ -1945,11 +2080,14 @@ struct Photonhbt { } template - void fillPairHistogram(TCollision const& /*collision*/, + void fillPairHistogram(TCollision const& collision, ROOT::Math::PtEtaPhiMVector const& v1, ROOT::Math::PtEtaPhiMVector const& v2, float weight = 1.f) { + + const float multNTracks = collision.multNTracksPVeta1(); + const float multFT0M = collision.multFT0M(); float rndm = std::pow(-1, dist01(engine) % 2); auto k12 = 0.5 * (v1 + v2); float kt = k12.Pt(); @@ -1970,12 +2108,28 @@ struct Photonhbt { if constexpr (ev_id == 0) { fRegistryCF.fill(HIST("Pair/same/CF_3D"), std::fabs(qout_lcms), std::fabs(qside_lcms), std::fabs(qlong_lcms), kt, weight); if (hbtanalysis.cfgDo2D) { - fRegistryCF.fill(HIST("Pair/same/CF_2D"), std::fabs(qout_lcms), std::fabs(qinv), kt, weight); + fRegistryCF.fill(HIST("Pair/same/CF_2D"), std::fabs(qout_lcms), std::fabs(qinv), multNTracks, multFT0M, kt, weight); + if (hbtanalysis.cfgDo2DSideLong) { + fRegistryCF.fill(HIST("Pair/same/CF_2D_Side"), std::fabs(qside_lcms), std::fabs(qinv), multNTracks, multFT0M, kt, weight); + fRegistryCF.fill(HIST("Pair/same/CF_2D_Long"), std::fabs(qlong_lcms), std::fabs(qinv), multNTracks, multFT0M, kt, weight); + } + } + if (hbtanalysis.cfgDoQinvGate3D) { + fRegistryCF.fill(HIST("Pair/same/CF_3D_Qinv"), std::fabs(qout_lcms), std::fabs(qside_lcms), + std::fabs(qlong_lcms), kt, std::fabs(qinv), weight); } } else { fRegistryCF.fill(HIST("Pair/mix/CF_3D"), std::fabs(qout_lcms), std::fabs(qside_lcms), std::fabs(qlong_lcms), kt, weight); if (hbtanalysis.cfgDo2D) { - fRegistryCF.fill(HIST("Pair/mix/CF_2D"), std::fabs(qout_lcms), std::fabs(qinv), kt, weight); + fRegistryCF.fill(HIST("Pair/mix/CF_2D"), std::fabs(qout_lcms), std::fabs(qinv), multNTracks, multFT0M, kt, weight); + if (hbtanalysis.cfgDo2DSideLong) { + fRegistryCF.fill(HIST("Pair/mix/CF_2D_Side"), std::fabs(qside_lcms), std::fabs(qinv), multNTracks, multFT0M, kt, weight); + fRegistryCF.fill(HIST("Pair/mix/CF_2D_Long"), std::fabs(qlong_lcms), std::fabs(qinv), multNTracks, multFT0M, kt, weight); + } + } + if (hbtanalysis.cfgDoQinvGate3D) { + fRegistryCF.fill(HIST("Pair/mix/CF_3D_Qinv"), std::fabs(qout_lcms), std::fabs(qside_lcms), + std::fabs(qlong_lcms), kt, std::fabs(qinv), weight); } } } else { @@ -1985,6 +2139,11 @@ struct Photonhbt { fRegistryCF.fill(HIST("Pair/mix/CF_1D"), hbtanalysis.cfgUseLCMS ? qabs_lcms : qinv, kt, weight); } } + if constexpr (ev_id == 0) { + fRegistryCF.fill(HIST("Pair/same/CF_QLcms_Qinv"), qabs_lcms, std::fabs(qinv), kt, weight); + } else { + fRegistryCF.fill(HIST("Pair/mix/CF_QLcms_Qinv"), qabs_lcms, std::fabs(qinv), kt, weight); + } float deta_pair = v1.Eta() - v2.Eta(); float dphi_pair = v1.Phi() - v2.Phi(); dphi_pair = RecoDecay::constrainAngle(dphi_pair, -o2::constants::math::PI); @@ -1996,11 +2155,13 @@ struct Photonhbt { } template - void fillPairHistogramMC(TCollision const& /*collision*/, + void fillPairHistogramMC(TCollision const& collision, ROOT::Math::PtEtaPhiMVector const& v1, ROOT::Math::PtEtaPhiMVector const& v2, float weight = 1.f) { + const float multNTracks = collision.multNTracksPVeta1(); + const float multFT0M = collision.multFT0M(); float rndm = std::pow(-1, dist01(engine) % 2); auto k12 = 0.5 * (v1 + v2); float kt = k12.Pt(); @@ -2022,11 +2183,12 @@ struct Photonhbt { fRegistryPairMC.fill(HIST(mcDir) + HIST("CF_3D"), std::fabs(qout_lcms), std::fabs(qside_lcms), std::fabs(qlong_lcms), kt, weight); if (hbtanalysis.cfgDo2D) { - fRegistryPairMC.fill(HIST(mcDir) + HIST("CF_2D"), std::fabs(qout_lcms), std::fabs(qinv), kt, weight); + fRegistryPairMC.fill(HIST(mcDir) + HIST("CF_2D"), std::fabs(qout_lcms), std::fabs(qinv), multNTracks, multFT0M, kt, weight); } } else { fRegistryPairMC.fill(HIST(mcDir) + HIST("CF_1D"), hbtanalysis.cfgUseLCMS ? qabs_lcms : qinv, kt, weight); } + fRegistryPairMC.fill(HIST(mcDir) + HIST("CF_QLcms_Qinv"), qabs_lcms, std::fabs(qinv), kt, weight); } template @@ -2253,10 +2415,12 @@ struct Photonhbt { } template - void fillPairHistogramNoLabel(TCollision const& /*collision*/, + void fillPairHistogramNoLabel(TCollision const& collision, ROOT::Math::PtEtaPhiMVector const& v1, ROOT::Math::PtEtaPhiMVector const& v2) { + const float multNTracks = collision.multNTracksPVeta1(); + const float multFT0M = collision.multFT0M(); float rndm = std::pow(-1, dist01(engine) % 2); auto k12 = 0.5 * (v1 + v2); float kt = k12.Pt(); @@ -2275,9 +2439,9 @@ struct Photonhbt { float qlong_lcms = q3_lcms.Dot(uv_long); if (hbtanalysis.cfgDo3D) { fRegistryPairMC.fill(HIST("Pair/same/MC/NoLabel/CF_3D"), std::fabs(qout_lcms), std::fabs(qside_lcms), std::fabs(qlong_lcms), kt); - } - if (hbtanalysis.cfgDo2D) { - fRegistryPairMC.fill(HIST("Pair/same/MC/NoLabel/CF_2D"), std::fabs(qout_lcms), std::fabs(qinv), kt); + if (hbtanalysis.cfgDo2D) { + fRegistryPairMC.fill(HIST("Pair/same/MC/NoLabel/CF_2D"), std::fabs(qout_lcms), std::fabs(qinv), multNTracks, multFT0M, kt); + } } else { fRegistryPairMC.fill(HIST("Pair/same/MC/NoLabel/CF_1D"), hbtanalysis.cfgUseLCMS ? qabs_lcms : qinv, kt); } @@ -2353,6 +2517,10 @@ struct Photonhbt { return info; } const int mothIdPos = mcPos.mothersIds()[0], mothIdNeg = mcNeg.mothersIds()[0]; + info.posMotherId = mothIdPos; + info.negMotherId = mothIdNeg; + info.posMotherIsPhoton = (mcParticles.iteratorAt(mothIdPos).pdgCode() == kGamma); + info.negMotherIsPhoton = (mcParticles.iteratorAt(mothIdNeg).pdgCode() == kGamma); if (mothIdPos != mothIdNeg) { return info; } @@ -2387,6 +2555,44 @@ struct Photonhbt { return PairTruthType::TrueTrueDistinct; } + // 0 = electron from a photon conversion, 1 = pi0 Dalitz electron, 2 = eta Dalitz electron, 3 = primary electron, 4 = other electron, 5 = not an electron at all (-> PID contamination) + template + static int classifyLegOrigin(TMCParticles const& mcParticles, int legMcId) + { + constexpr int kNotElectron = 5; + if (legMcId < 0) { + return kNotElectron; + } + const auto particle = mcParticles.iteratorAt(legMcId); + if (std::abs(particle.pdgCode()) != PDG_t::kElectron) { + return kNotElectron; + } + if (!particle.has_mothers()) { + return 3; // primary electron + } + const int motherPdg = mcParticles.iteratorAt(particle.mothersIds()[0]).pdgCode(); + if (motherPdg == kGamma) { + return 0; + } + if (motherPdg == kPi0) { + return 1; + } + if (motherPdg == o2::constants::physics::Pdg::kEta) { + return 2; + } + return 4; + } + + static int classifyFakeSubtype(PhotonMCInfo const& m1, PhotonMCInfo const& m2) + { + const bool cross12 = m1.posMotherId >= 0 && m1.posMotherId == m2.negMotherId && m1.posMotherIsPhoton; + const bool cross21 = m2.posMotherId >= 0 && m2.posMotherId == m1.negMotherId && m2.posMotherIsPhoton; + if (cross12 && cross21) { + return 1; + } + return (cross12 || cross21) ? 2 : 0; + } + template static bool isPi0DaughterPair(PhotonMCInfo const& m1, PhotonMCInfo const& m2, TMCParticles const& mcParticles) @@ -2511,6 +2717,9 @@ struct Photonhbt { fillFullRangeDeltaRCosOA<0>(obs.qinv, obs.drOverCosOA); } + fillLegSimilarity(pos1, pos2, obs.qinv); + fillLegSimilarity(ele1, ele2, obs.qinv); + // ─── Pair cuts ──────────────────────────────────────────────────── if (!passPhotonClassPairCut(pwl1.legCounts(), pwl2.legCounts())) { continue; @@ -2610,6 +2819,8 @@ struct Photonhbt { fillFullRangeDeltaRCosOA<1>(obs.qinv, obs.drOverCosOA); } + fillLegSimilarityMix(g1, g2, obs.qinv); + // ─── Pair cuts ──────────────────────────────────────────────── if (!passPhotonClassPairCut(g1.legCounts(), g2.legCounts())) { continue; @@ -2698,6 +2909,23 @@ struct Photonhbt { for (const auto& g : photonsColl) { if (cut.template IsSelected(g)) { fillSinglePhotonQAStep<0>(g); + const auto mcg = buildPhotonMCInfo(g, mcParticles); + if (mcg.hasMC) { + const float rConvQA = std::hypot(g.vx(), g.vy()); + const auto originPos = static_cast(classifyLegOrigin(mcParticles, mcg.mcPosId)); + const auto originNeg = static_cast(classifyLegOrigin(mcParticles, mcg.mcNegId)); + if (mcg.sameMother && mcg.isTruePhoton) { + fRegistryPairMC.fill(HIST("SinglePhotonMC/truePhotons/hEtaPhi"), g.eta(), g.phi()); + fRegistryPairMC.fill(HIST("SinglePhotonMC/truePhotons/hRZ"), g.vz(), rConvQA); + fRegistryPairMC.fill(HIST("SinglePhotonMC/truePhotons/hEtaPt"), g.eta(), g.pt()); + fRegistryPairMC.fill(HIST("SinglePhotonMC/truePhotons/hLegOriginMatrix"), originPos, originNeg); + } else { + fRegistryPairMC.fill(HIST("SinglePhotonMC/fakePhotons/hEtaPhi"), g.eta(), g.phi()); + fRegistryPairMC.fill(HIST("SinglePhotonMC/fakePhotons/hRZ"), g.vz(), rConvQA); + fRegistryPairMC.fill(HIST("SinglePhotonMC/fakePhotons/hEtaPt"), g.eta(), g.pt()); + fRegistryPairMC.fill(HIST("SinglePhotonMC/fakePhotons/hLegOriginMatrix"), originPos, originNeg); + } + } } } } @@ -2727,8 +2955,10 @@ struct Photonhbt { } const bool doQA = passQinvQAGate(obs.qinv), doFR = passQinvFullRangeGate(obs.qinv); const auto legObs = buildLegPairObservables(g1, g2, pos1, ele1, pos2, ele2); - const auto pwl1 = makePhotonWithLegs(g1, pos1, ele1, collision.posZ()); - const auto pwl2 = makePhotonWithLegs(g2, pos2, ele2, collision.posZ()); + auto pwl1 = makePhotonWithLegs(g1, pos1, ele1, collision.posZ()); + auto pwl2 = makePhotonWithLegs(g2, pos2, ele2, collision.posZ()); + pwl1.fIsTruePhoton = (mc1.sameMother && mc1.isTruePhoton) ? 1 : 0; + pwl2.fIsTruePhoton = (mc2.sameMother && mc2.isTruePhoton) ? 1 : 0; const auto sep = computePairSep(pwl1, pwl2); // ──before pair cuts ───────────────────────────────────── @@ -2741,6 +2971,9 @@ struct Photonhbt { fillFullRangeDeltaRCosOA<0>(obs.qinv, obs.drOverCosOA); } + fillLegSimilarity(pos1, pos2, obs.qinv); + fillLegSimilarity(ele1, ele2, obs.qinv); + // ─── Pair cuts ──────────────────────────────────────────────────── if (obs.drOverCosOA < ggpaircuts.cfgMinDRCosOA) { continue; @@ -2812,6 +3045,18 @@ struct Photonhbt { } } + fRegistryPairMC.fill(HIST("Pair/same/MC/hSparse_PsiPair_PhiV_Qinv_Type"), std::fabs(g1.psipair()), g1.phiv(), obs.qinv, static_cast(static_cast(truthType)), (mc1.sameMother && mc1.isTruePhoton) ? 1.f : 0.f); + fRegistryPairMC.fill(HIST("Pair/same/MC/hSparse_PsiPair_PhiV_Qinv_Type"), std::fabs(g2.psipair()), g2.phiv(), obs.qinv, static_cast(static_cast(truthType)), (mc2.sameMother && mc2.isTruePhoton) ? 1.f : 0.f); + if (truthType == PairTruthType::FakeFake || truthType == PairTruthType::TrueFake) { + fRegistryPairMC.fill(HIST("Pair/same/MC/hFakeSubtypeVsQinv"), obs.qinv, + static_cast(classifyFakeSubtype(mc1, mc2))); + } + + const auto crossMC = computeCrossObs(pwl1, pwl2, obs.qinv); + if (crossMC.meeOverQ < 900.f) { // o2-linter: disable=magic-number (qinv was zero, skip) + fRegistryPairMC.fill(HIST("Pair/same/MC/hSparse_MeeRatio_Qinv_Type"), crossMC.meeOverQ, obs.qinv, static_cast(static_cast(truthType))); + } + switch (truthType) { case PairTruthType::TrueTrueDistinct: fillPairHistogramMC<0, PairTruthType::TrueTrueDistinct>(collision, obs.v1, obs.v2); @@ -2894,6 +3139,8 @@ struct Photonhbt { fillFullRangeDeltaRCosOA<1>(obs.qinv, obs.drOverCosOA); } + fillLegSimilarityMix(g1, g2, obs.qinv); + // ─── Pair cuts ──────────────────────────────────────────────── if (obs.drOverCosOA < ggpaircuts.cfgMinDRCosOA) { continue; @@ -2925,6 +3172,19 @@ struct Photonhbt { fillFullRangeQA<1>(obs, centForQA, occupancy); } fillPairHistogram<1>(collision, obs.v1, obs.v2, 1.f); + if (g1.fIsTruePhoton >= 0 && g2.fIsTruePhoton >= 0) { + const int nTrue = g1.fIsTruePhoton + g2.fIsTruePhoton; + if (nTrue == 2) { // o2-linter: disable=magic-number (both pairs are true) + fRegistryPairMC.fill(HIST("Pair/mix/MC/hQinv_TrueTrue"), obs.qinv); + fillPairHistogramMC<1, PairTruthType::TrueTrueDistinct>(collision, obs.v1, obs.v2); + } else if (nTrue == 1) { + fRegistryPairMC.fill(HIST("Pair/mix/MC/hQinv_TrueFake"), obs.qinv); + fillPairHistogramMC<1, PairTruthType::TrueFake>(collision, obs.v1, obs.v2); + } else { + fRegistryPairMC.fill(HIST("Pair/mix/MC/hQinv_FakeFake"), obs.qinv); + fillPairHistogramMC<1, PairTruthType::FakeFake>(collision, obs.v1, obs.v2); + } + } fRegistryCF.fill(HIST("Pair/mix/hPhi_lowerPtV0"), (g1.pt() < g2.pt()) ? g1.phi() : g2.phi()); } } @@ -3397,8 +3657,8 @@ struct Photonhbt { aod::McParticles const& mcparticles) { - constexpr float kRMinConv = 1.f; - constexpr float kRMaxConv = 90.f; + const float kRMinConv = pcmcuts.cfgMinV0Radius.value; + const float kRMaxConv = pcmcuts.cfgMaxV0Radius.value; std::unordered_map>> tracksOfMc; for (const auto& t : tracks) { @@ -3525,7 +3785,11 @@ struct Photonhbt { if (mc.pdgCode() != PDG_t::kGamma || !mc.isPhysicalPrimary() || !mc.has_daughters()) { continue; } - if (std::fabs(mc.eta()) > pcmcuts.cfgMaxEtaV0.value || mc.pt() < pcmcuts.cfgMinPtV0.value) { + + const float mcV0PtMin = (mctruth.cfgMCMinV0Pt.value > 0.f) + ? mctruth.cfgMCMinV0Pt.value + : pcmcuts.cfgMinPtV0.value; + if (std::fabs(mc.eta()) > pcmcuts.cfgMaxEtaV0.value || mc.pt() < mcV0PtMin) { continue; } int posId = -1, negId = -1; @@ -3544,12 +3808,23 @@ struct Photonhbt { continue; // not a conversion } const auto dPos = mcparticles.iteratorAt(posId); + const auto dNeg = mcparticles.iteratorAt(negId); const float rConv = std::hypot(dPos.vx(), dPos.vy()); if (rConv < kRMinConv || rConv > kRMaxConv) { continue; } + if (std::fabs(dPos.eta()) > pcmcuts.cfgMaxEtaV0.value || + std::fabs(dNeg.eta()) > pcmcuts.cfgMaxEtaV0.value) { + continue; + } + if (mctruth.cfgMCMinLegPt.value > 0.f && + (dPos.pt() < mctruth.cfgMCMinLegPt.value || dNeg.pt() < mctruth.cfgMCMinLegPt.value)) { + continue; + } + fRegistryTruthMC.fill(HIST("MCAOD/hPhotonStage"), 0.f); + fRegistryTruthMC.fill(HIST("MCAOD/hPhotonStageVsPt"), 0.f, mc.pt()); GammaLite g; g.mcId = mc.globalIndex(); g.eta = mc.eta(); @@ -3564,6 +3839,7 @@ struct Photonhbt { if (itPos != tracksOfMc.end() && itNeg != tracksOfMc.end()) { g.tracked = true; fRegistryTruthMC.fill(HIST("MCAOD/hPhotonStage"), 1.f); + fRegistryTruthMC.fill(HIST("MCAOD/hPhotonStageVsPt"), 1.f, mc.pt()); std::set commonColls; for (const auto& [posGi, posCol] : itPos->second) { @@ -3575,6 +3851,7 @@ struct Photonhbt { } if (!commonColls.empty()) { fRegistryTruthMC.fill(HIST("MCAOD/hPhotonStage"), 2.f); + fRegistryTruthMC.fill(HIST("MCAOD/hPhotonStageVsPt"), 2.f, mc.pt()); fRegistryTruthMC.fill(HIST("MCAOD/hNTrackedColls"), static_cast(commonColls.size())); g.trackedColls.assign(commonColls.begin(), commonColls.end()); @@ -3622,6 +3899,7 @@ struct Photonhbt { } if (!g.matches.empty()) { fRegistryTruthMC.fill(HIST("MCAOD/hPhotonStage"), 3.f); + fRegistryTruthMC.fill(HIST("MCAOD/hPhotonStageVsPt"), 3.f, mc.pt()); } } } @@ -3669,6 +3947,59 @@ struct Photonhbt { } } } + + { + auto findCand = [&](int pos, int neg, int coll) -> int { + const auto it = v0sByPosTrack.find(pos); + if (it == v0sByPosTrack.end()) { + return -1; + } + for (const int& idx : it->second) { + if (allCands[idx].negTrackId == neg && allCands[idx].collisionId == coll) { + return idx; + } + } + return -1; + }; + auto qinvTrue = [&](int64_t ma, int64_t mb) -> float { + const auto pa = mcparticles.iteratorAt(ma); + const auto pb = mcparticles.iteratorAt(mb); + // photons: E = |p| + const float e1 = std::hypot(pa.px(), pa.py(), pa.pz()); + const float e2 = std::hypot(pb.px(), pb.py(), pb.pz()); + return std::sqrt(std::max(0.f, 2.f * (e1 * e2 - pa.px() * pb.px() - + pa.py() * pb.py() - pa.pz() * pb.pz()))); + }; + std::unordered_map> trueByColl; + for (int i = 0; i < nC; ++i) { + if (candClass[i] == 0) { + trueByColl[allCands[i].collisionId].push_back(i); + } + } + for (const auto& [coll, trues] : trueByColl) { + for (size_t a = 0; a < trues.size(); ++a) { + for (size_t b = a + 1; b < trues.size(); ++b) { + const int i = trues[a], j = trues[b]; + if (candMother[i] == candMother[j]) { + continue; // same photon twice + } + const int x1 = findCand(allCands[i].posTrackId, allCands[j].negTrackId, coll); + const int x2 = findCand(allCands[j].posTrackId, allCands[i].negTrackId, coll); + if (x1 < 0 || x2 < 0) { + continue; // no complete alternative matching + } + const float sTrue = allCands[i].score + allCands[j].score; + const float sCross = allCands[x1].score + allCands[x2].score; + const float deltaS = std::fabs(sTrue - sCross); + const float q = qinvTrue(candMother[i], candMother[j]); + fRegistryTruthMC.fill(HIST("MCAOD/hDeltaS2x2_vs_Qinv"), std::min(deltaS, 9.99f), q); + if (sCross < sTrue) { // smaller score = better in this builder + fRegistryTruthMC.fill(HIST("MCAOD/hDeltaS2x2_CrossWins"), std::min(deltaS, 9.99f), q); + } + } + } + } + } std::array, kNDedup> dedupAlive; for (auto& a : dedupAlive) { // o2-linter: disable=const-ref-in-for-loop (assign modifies the elements) a.assign(nC, 0); @@ -3788,8 +4119,10 @@ struct Photonhbt { const float dEta = a.eta - b.eta; const float dPhi = RecoDecay::constrainAngle(a.phi - b.phi, -o2::constants::math::PI); const float dR = std::fabs(a.rConv - b.rConv); + const float kt = 0.5f * std::hypot(a.px + b.px, a.py + b.py); auto fillStage = [&](float s) { fRegistryTruthMC.fill(HIST("MCAOD/hPairStage"), s); + fRegistryTruthMC.fill(HIST("MCAOD/hPairStageVsKt"), s, kt); fRegistryTruthMC.fill(HIST("MCAOD/hSparsePairStage"), s, dEta, dPhi, qinv); fRegistryTruthMC.fill(HIST("MCAOD/hSparseDRStage"), s, dR, qinv); }; diff --git a/PWGEM/PhotonMeson/Tasks/taskPhotonFlow.cxx b/PWGEM/PhotonMeson/Tasks/taskPhotonFlow.cxx new file mode 100644 index 00000000000..41f47171448 --- /dev/null +++ b/PWGEM/PhotonMeson/Tasks/taskPhotonFlow.cxx @@ -0,0 +1,783 @@ +// 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. + +/// \file taskPhotonFlow.cxx +/// \brief Analysis task for photon flow with PCM or EMCal +/// \author M. Hemmer, marvin.hemmer@cern.ch + +#include "PWGEM/PhotonMeson/Core/EMBitFlags.h" +#include "PWGEM/PhotonMeson/Core/EMCPhotonCut.h" +#include "PWGEM/PhotonMeson/Core/EMPhotonEventCut.h" +#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h" +#include "PWGEM/PhotonMeson/DataModel/EventTables.h" +#include "PWGEM/PhotonMeson/DataModel/GammaTablesRedux.h" +#include "PWGEM/PhotonMeson/DataModel/gammaTables.h" +#include "PWGEM/PhotonMeson/Utils/EventHistograms.h" + +#include "Common/Core/EventPlaneHelper.h" +#include "Common/Core/RecoDecay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::soa; +using namespace o2::aod::pwgem::photon; + +enum QvecEstimator { + FT0M = 0, + FT0A = 1, + FT0C = 2, + TPCPos = 3, + TPCNeg = 4, + TPCTot = 5, + FV0A = 6 +}; + +enum CentralityEstimator { + None = 0, + CFT0A = 1, + CFT0C = 2, + CFT0M = 3, + NCentralityEstimators = 4 +}; + +enum Harmonics { + kNone = 0, + kDirect = 1, + kElliptic = 2, + kTriangluar = 3, + kQuadrangular = 4, + kPentagonal = 5, + kHexagonal = 6, + kHeptagonal = 7, + kOctagonal = 8 +}; + +enum class MapLevel { + kGood = 1, + kNoBad = 2, + kInEMC = 3, + kAll = 4 +}; + +struct TaskPhotonFlow { + // 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, FV0A: 6)"}; + Configurable qvecSubADetector{"qvecSubADetector", 3, "Sub A Detector for Q vector estimation for resolution (FT0M: 0, FT0A: 1, FT0C: 2, TPC Pos: 3, TPC Neg: 4, TPC Tot: 5, FV0A: 6)"}; + Configurable qvecSubBDetector{"qvecSubBDetector", 4, "Sub B Detector for Q vector estimation for resolution (FT0M: 0, FT0A: 1, FT0C: 2, TPC Pos: 3, TPC Neg: 4, TPC Tot: 5, FV0A: 6)"}; + Configurable centEstimator{"centEstimator", 2, "Centrality estimation (FT0A: 1, FT0C: 2, FT0M: 3)"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable cfgEMCalMapLevelSameEvent{"cfgEMCalMapLevelSameEvent", 4, "Different levels of correction for the same event, the smaller number includes the level of the higher number (4: none, 3: only inside EMCal, 2: remove edges, 1: exclude bad channels)"}; + Configurable cfgDistanceToEdge{"cfgDistanceToEdge", 1, "Distance to edge in cells required for rotated cluster to be accepted"}; + Configurable cfgMaxQVector{"cfgMaxQVector", 20.f, "Maximum allowed absolute QVector value."}; + + // configurable axis + ConfigurableAxis thnConfigAxisPt{"thnConfigAxisPt", {100, 0., 20.}, "pT axis for the neutral meson"}; + ConfigurableAxis thnConfigAxisCent{"thnConfigAxisCent", {20, 0., 100.}, "centrality axis for the current event"}; + ConfigurableAxis thnConfigAxisCosDeltaPhi{"thnConfigAxisCosDeltaPhi", {8, -1., 1.}, "cos(delta phi) axis for the current event"}; + ConfigurableAxis thnConfigAxisM02{"thnConfigAxisM02", {200, 0., 5.}, "M02 axis for the EMCal cluster"}; + ConfigurableAxis thnConfigAxisKappa{"thnConfigAxisKappa", {200, -10., 10.}, "Kappa axis for the EMCal cluster"}; + ConfigurableAxis thnConfigAxisEnergyCalib{"thnConfigAxisEnergyCalib", {200, 0., 20.}, "energy axis for the emcal clusters for the calibration process"}; + + EMPhotonEventCut fEMEventCut; + struct : ConfigurableGroup { + std::string prefix = "eventcuts"; + Configurable cfgZvtxMax{"cfgZvtxMax", 10.f, "max. Zvtx"}; + Configurable cfgRequireSel8{"cfgRequireSel8", true, "require sel8 in event cut"}; + Configurable cfgRequireFT0AND{"cfgRequireFT0AND", true, "require FT0AND in event cut"}; + Configurable cfgRequireNoTFB{"cfgRequireNoTFB", false, "require No time frame border in event cut"}; + Configurable cfgRequireNoITSROFB{"cfgRequireNoITSROFB", false, "require no ITS readout frame border in event cut"}; + Configurable cfgRequireNoSameBunchPileup{"cfgRequireNoSameBunchPileup", false, "require no same bunch pileup in event cut"}; + Configurable cfgRequireVertexITSTPC{"cfgRequireVertexITSTPC", false, "require Vertex ITSTPC in event cut"}; // ITS-TPC matched track contributes PV. + Configurable cfgRequireGoodZvtxFT0vsPV{"cfgRequireGoodZvtxFT0vsPV", false, "require good Zvtx between FT0 vs. PV in event cut"}; + Configurable cfgRequireEMCReadoutInMB{"cfgRequireEMCReadoutInMB", true, "require the EMC to be read out in an MB collision (kTVXinEMC)"}; + Configurable cfgRequireEMCHardwareTriggered{"cfgRequireEMCHardwareTriggered", false, "require the EMC to be hardware triggered (kEMC7 or kDMC7)"}; + Configurable cfgFT0COccupancyMin{"cfgFT0COccupancyMin", -1, "min. FT0C occupancy"}; + Configurable cfgFT0COccupancyMax{"cfgFT0COccupancyMax", 1000000000, "max. FT0C occupancy"}; + Configurable cfgMinCent{"cfgMinCent", 0, "min. centrality (%)"}; + Configurable cfgMaxCent{"cfgMaxCent", 90, "max. centrality (%)"}; + Configurable onlyKeepWeightedEvents{"onlyKeepWeightedEvents", false, "flag to keep only weighted events (for JJ MCs) and remove all MB events (with weight = 1)"}; + } eventcuts; + + EMCPhotonCut fEMCCut; + struct : ConfigurableGroup { + std::string prefix = "emccuts"; + Configurable clusterDefinition{"clusterDefinition", "kV3MostSplitSmallestTimeDiff", "Clusterizer to be selected, e.g. V3Default"}; + Configurable cfgEMCminTime{"cfgEMCminTime", -25., "Minimum cluster time for EMCal time cut"}; + Configurable cfgEMCmaxTime{"cfgEMCmaxTime", +30., "Maximum cluster time for EMCal time cut"}; + Configurable cfgEMCminM02{"cfgEMCminM02", 0.1, "Minimum M02 for EMCal M02 cut"}; + Configurable cfgEMCmaxM02{"cfgEMCmaxM02", 0.7, "Maximum M02 for EMCal M02 cut"}; + Configurable cfgEMCminE{"cfgEMCminE", 0.7, "Minimum cluster energy for EMCal energy cut"}; + Configurable cfgEMCminNCell{"cfgEMCminNCell", 1, "Minimum number of cells per cluster for EMCal NCell cut"}; + Configurable> cfgEMCTMEta{"cfgEMCTMEta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable> cfgEMCTMPhi{"cfgEMCTMPhi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable> emcSecTMEta{"emcSecTMEta", {0.01f, 4.07f, -2.5f}, "|eta| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable> emcSecTMPhi{"emcSecTMPhi", {0.015f, 3.65f, -2.f}, "|phi| <= [0]+(pT+[1])^[2] for EMCal track matching"}; + Configurable cfgEMCEoverp{"cfgEMCEoverp", 1.75, "Minimum cluster energy over track momentum for EMCal track matching"}; + Configurable cfgEMCUseExoticCut{"cfgEMCUseExoticCut", true, "FLag to use the EMCal exotic cluster cut"}; + Configurable cfgEMCUseTM{"cfgEMCUseTM", false, "flag to use EMCal track matching cut or not"}; + Configurable emcUseSecondaryTM{"emcUseSecondaryTM", false, "flag to use EMCal secondary track matching cut or not"}; + Configurable cfgEnableQA{"cfgEnableQA", false, "flag to turn QA plots on/off"}; + Configurable useEMCal{"useEMCal", false, "flag to use EMCal clusters"}; + Configurable useDCal{"useDCal", false, "flag to use DCal clusters"}; + } emccuts; + + V0PhotonCut fV0PhotonCut; + struct : o2::framework::ConfigurableGroup { + std::string prefix = "PCMcuts"; + o2::framework::Configurable requireV0WithITSTPC{"requireV0WithITSTPC", false, "flag to enforce V0s have ITS and TPC"}; + o2::framework::Configurable requireV0WithITSOnly{"requireV0WithITSOnly", false, "flag to select V0s with ITSonly tracks"}; + o2::framework::Configurable requireV0WithTPCOnly{"requireV0WithTPCOnly", false, "flag to select V0s with TPConly tracks"}; + o2::framework::Configurable minPtV0{"minPtV0", 0.1, "min pT for v0 photons at PV"}; + o2::framework::Configurable maxPtV0{"maxPtV0", 1e+10, "max pT for v0 photons at PV"}; + o2::framework::Configurable minEtaV0{"minEtaV0", -0.8, "min eta for v0 photons at PV"}; + o2::framework::Configurable maxEtaV0{"maxEtaV0", 0.8, "max eta for v0 photons at PV"}; + o2::framework::Configurable minRV0{"minRV0", 4.0, "min v0 radius"}; + o2::framework::Configurable maxRV0{"maxRV0", 90.0, "max v0 radius"}; + o2::framework::Configurable maxAlphaAP{"maxAlphaAP", 0.95, "max alpha for AP cut"}; + o2::framework::Configurable maxQtAP{"maxQtAP", 0.01, "max qT for AP cut"}; + o2::framework::Configurable minCosPA{"minCosPA", 0.999, "min V0 CosPA"}; + o2::framework::Configurable maxPCA{"maxPCA", 1.5, "max distance btween 2 legs"}; + o2::framework::Configurable maxChi2KF{"maxChi2KF", 1.e+10f, "max chi2/ndf with KF"}; + o2::framework::Configurable rejectV0onITSib{"rejectV0onITSib", true, "flag to reject V0s on ITSib"}; + o2::framework::Configurable applyPrefilter{"applyPrefilter", false, "flag to apply prefilter to V0"}; + + o2::framework::Configurable minNClusterTPC{"minNClusterTPC", 0, "min NCluster TPC"}; + o2::framework::Configurable minNCrossedRowsTPC{"minNCrossedRowsTPC", 40, "min ncrossed rows in TPC"}; + o2::framework::Configurable minNCrossedRowsOverFindableClustersTPC{"minNCrossedRowsOverFindableClustersTPC", 0.8f, "min fraction of crossed rows over findable clusters in TPC"}; + o2::framework::Configurable maxFracSharedClustersTPC{"maxFracSharedClustersTPC", 999.f, "max fraction of shared clusters in TPC"}; + o2::framework::Configurable minNClusterITS{"minNClusterITS", 0, "min NCluster ITS"}; + o2::framework::Configurable minMeanClusterSizeITSob{"minMeanClusterSizeITSob", 0.f, "min ITSob"}; + o2::framework::Configurable maxMeanClusterSizeITSob{"maxMeanClusterSizeITSob", 16.f, "max ITSob"}; + o2::framework::Configurable macChi2TPC{"macChi2TPC", 4.f, "max chi2/NclsTPC"}; + o2::framework::Configurable macChi2ITS{"macChi2ITS", 36.f, "max chi2/NclsITS"}; + o2::framework::Configurable minTPCNSigmaEl{"minTPCNSigmaEl", -3.0f, "min. TPC n sigma for electron"}; + o2::framework::Configurable maxTPCNSigmaEl{"maxTPCNSigmaEl", +3.0f, "max. TPC n sigma for electron"}; + o2::framework::Configurable disableITSOnly{"disableITSOnly", false, "flag to disable ITSonly tracks"}; + o2::framework::Configurable disableTPCOnly{"disableTPCOnly", false, "flag to disable TPConly tracks"}; + o2::framework::Configurable doQA{"doQA", false, "flag to set QA flag."}; + } pcmcuts; + + struct : ConfigurableGroup { + std::string prefix = "correctionConfig"; + Configurable cfgSpresoPath{"cfgSpresoPath", "Users/m/mhemmer/EM/Flow/Resolution", "Path to SP resolution file"}; + Configurable cfgApplySPresolution{"cfgApplySPresolution", false, "Apply resolution correction"}; + } correctionConfig; + + SliceCache cache; + EventPlaneHelper epHelper; + o2::framework::Service ccdb{}; + int runNow = 0; + int runBefore = -1; + + static constexpr float MaxPhiEMCal = 3.9f; // exatly the middle between EMCal and DCal + static constexpr uint16_t MaxPhiEMCalUint = static_cast(39000u); // exatly the middle between EMCal and DCal but as uint16_t that is used for storing phi values in derived data + + using EMCalPhotons = soa::Join; + using PCMPhotons = soa::Join; + using Colls = soa::Join; + + Partition emcalPhotons = aod::mincluster::storedPhi < MaxPhiEMCalUint; + Partition dcalPhotons = aod::mincluster::storedPhi >= MaxPhiEMCalUint; + + static constexpr std::size_t NQVecEntries = 6; + + PresliceOptional perCollisionEMC = o2::aod::emccluster::pmeventId; + PresliceOptional perCollisionPCM = aod::v0photonkf::pmeventId; + PresliceOptional perEMCClusterMT = o2::aod::mintm::minClusterId; + PresliceOptional perEMCClusterMS = o2::aod::mintm::minClusterId; + + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; + + o2::emcal::Geometry* emcalGeom = nullptr; + TH1D* h1SPResolution = nullptr; + // Constants for eta and phi ranges for the look up table + static constexpr double EtaMin = -0.75, etaMax = 0.75; + static constexpr int NBinsEta = 150; // 150 bins for eta + + static constexpr double PhiMin = 1.35, phiMax = 5.75; + static constexpr int NBinsPhi = 440; // (440 bins = 0.01 step size covering most regions) + + std::array lookupTable1D{}; + float epsilon = 1.e-8; + + // To access the 1D array + static inline int getIndex(int iEta, int iPhi) + { + return iEta * NBinsPhi + iPhi; + } + + // Function to access the lookup table + inline int8_t checkEtaPhi1D(double eta, double phi) + { + if (eta < EtaMin || eta > etaMax || phi < PhiMin || phi > phiMax) { + return 3; // Out of bounds + } + + // Compute indices directly + int iEta = static_cast((eta - EtaMin) / ((etaMax - EtaMin) / NBinsEta)); + int iPhi = static_cast((phi - PhiMin) / ((phiMax - PhiMin) / NBinsPhi)); + + return lookupTable1D[getIndex(iEta, iPhi)]; + } + + void defineEMEventCut() + { + fEMEventCut = EMPhotonEventCut("fEMEventCut", "fEMEventCut"); + fEMEventCut.SetRequireSel8(eventcuts.cfgRequireSel8); + fEMEventCut.SetRequireFT0AND(eventcuts.cfgRequireFT0AND); + fEMEventCut.SetZvtxRange(-eventcuts.cfgZvtxMax, +eventcuts.cfgZvtxMax); + fEMEventCut.SetRequireNoTFB(eventcuts.cfgRequireNoTFB); + fEMEventCut.SetRequireNoITSROFB(eventcuts.cfgRequireNoITSROFB); + fEMEventCut.SetRequireNoSameBunchPileup(eventcuts.cfgRequireNoSameBunchPileup); + fEMEventCut.SetRequireVertexITSTPC(eventcuts.cfgRequireVertexITSTPC); + fEMEventCut.SetRequireGoodZvtxFT0vsPV(eventcuts.cfgRequireGoodZvtxFT0vsPV); + fEMEventCut.SetRequireEMCReadoutInMB(eventcuts.cfgRequireEMCReadoutInMB); + fEMEventCut.SetRequireEMCHardwareTriggered(eventcuts.cfgRequireEMCHardwareTriggered); + } + + void defineEMCCut() + { + fEMCCut = EMCPhotonCut("fEMCCut", "fEMCCut"); + + fEMCCut.SetTrackMatchingEtaParams(emccuts.cfgEMCTMEta->at(0), emccuts.cfgEMCTMEta->at(1), emccuts.cfgEMCTMEta->at(2)); + fEMCCut.SetTrackMatchingPhiParams(emccuts.cfgEMCTMPhi->at(0), emccuts.cfgEMCTMPhi->at(1), emccuts.cfgEMCTMPhi->at(2)); + + fEMCCut.SetSecTrackMatchingEtaParams(emccuts.emcSecTMEta->at(0), emccuts.emcSecTMEta->at(1), emccuts.emcSecTMEta->at(2)); + fEMCCut.SetSecTrackMatchingPhiParams(emccuts.emcSecTMPhi->at(0), emccuts.emcSecTMPhi->at(1), emccuts.emcSecTMPhi->at(2)); + fEMCCut.SetMinEoverP(emccuts.cfgEMCEoverp); + + fEMCCut.SetMinE(emccuts.cfgEMCminE); + fEMCCut.SetMinNCell(emccuts.cfgEMCminNCell); + fEMCCut.SetM02Range(emccuts.cfgEMCminM02, emccuts.cfgEMCmaxM02); + fEMCCut.SetTimeRange(emccuts.cfgEMCminTime, emccuts.cfgEMCmaxTime); + fEMCCut.SetUseExoticCut(emccuts.cfgEMCUseExoticCut); + fEMCCut.SetClusterizer(emccuts.clusterDefinition); + fEMCCut.SetUseTM(emccuts.cfgEMCUseTM.value); // disables or enables TM + fEMCCut.SetUseSecondaryTM(emccuts.emcUseSecondaryTM.value); // disables or enables secondary TM + fEMCCut.SetDoQA(emccuts.cfgEnableQA.value); + } + + void definePCMCut() + { + fV0PhotonCut = V0PhotonCut("fV0PhotonCut", "fV0PhotonCut"); + + // for v0 + fV0PhotonCut.SetV0PtRange(pcmcuts.minPtV0, pcmcuts.maxPtV0); + fV0PhotonCut.SetV0EtaRange(pcmcuts.minEtaV0, pcmcuts.maxEtaV0); + fV0PhotonCut.SetMinCosPA(pcmcuts.minCosPA); + fV0PhotonCut.SetMaxPCA(pcmcuts.maxPCA); + fV0PhotonCut.SetMaxChi2KF(pcmcuts.maxChi2KF); + fV0PhotonCut.SetRxyRange(pcmcuts.minRV0, pcmcuts.maxRV0); + fV0PhotonCut.SetAPRange(pcmcuts.maxAlphaAP, pcmcuts.maxQtAP); + fV0PhotonCut.RejectITSib(pcmcuts.rejectV0onITSib); + + // for track + fV0PhotonCut.SetMinNClustersTPC(pcmcuts.minNClusterTPC); + fV0PhotonCut.SetMinNCrossedRowsTPC(pcmcuts.minNCrossedRowsTPC); + fV0PhotonCut.SetMinNCrossedRowsOverFindableClustersTPC(pcmcuts.minNCrossedRowsOverFindableClustersTPC); + fV0PhotonCut.SetMaxFracSharedClustersTPC(pcmcuts.maxFracSharedClustersTPC); + fV0PhotonCut.SetChi2PerClusterTPC(0.f, pcmcuts.macChi2TPC); + fV0PhotonCut.SetTPCNsigmaElRange(pcmcuts.minTPCNSigmaEl, pcmcuts.maxTPCNSigmaEl); + fV0PhotonCut.SetChi2PerClusterITS(0.f, pcmcuts.macChi2ITS); + fV0PhotonCut.SetNClustersITS(pcmcuts.minNClusterITS, 7); + fV0PhotonCut.SetMeanClusterSizeITSob(pcmcuts.minMeanClusterSizeITSob, pcmcuts.maxMeanClusterSizeITSob); + fV0PhotonCut.SetDisableITSonly(pcmcuts.disableITSOnly); + fV0PhotonCut.SetDisableTPConly(pcmcuts.disableTPCOnly); + fV0PhotonCut.SetRequireITSTPC(pcmcuts.requireV0WithITSTPC); + fV0PhotonCut.SetRequireITSonly(pcmcuts.requireV0WithITSOnly); + fV0PhotonCut.SetRequireTPConly(pcmcuts.requireV0WithTPCOnly); + + fV0PhotonCut.setDoQA(pcmcuts.doQA.value); + } + + void init(InitContext&) + { + if (harmonic != kElliptic && harmonic != kTriangluar) { + LOG(info) << "Harmonic was set to " << harmonic << " but can only be 2 or 3!"; + } + + defineEMEventCut(); + defineEMCCut(); + fEMCCut.addQAHistograms(®istry); + definePCMCut(); + fV0PhotonCut.addQAHistograms(®istry); + o2::aod::pwgem::photonmeson::utils::eventhistogram::addEventHistograms(®istry); + + const AxisSpec thnAxisPt{thnConfigAxisPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec thnAxisCent{thnConfigAxisCent, "Centrality (%)"}; + const AxisSpec thnAxisCosDeltaPhi{thnConfigAxisCosDeltaPhi, std::format("cos({}(#varphi - #Psi_{{sub}}))", harmonic.value)}; + const AxisSpec thnAxisM02{thnConfigAxisM02, "M_{02}"}; + const AxisSpec thnAxisKappa{thnConfigAxisKappa, "#Kappa"}; + const AxisSpec thAxisClusterEnergy{thnConfigAxisPt, "#it{E} (GeV)"}; + const AxisSpec thAxisEnergyCalib{thnConfigAxisEnergyCalib, "#it{E}_{clus} (GeV)"}; + const AxisSpec thAxisEnergy{1000, 0., 100., "#it{E}_{clus} (GeV)"}; + const AxisSpec thAxisEta{320, -0.8, 0.8, "#eta"}; + const AxisSpec thAxisPhi{500, 0, 2 * 3.14159, "phi"}; + + if (emccuts.cfgEnableQA.value) { + registry.add("clusterQA/hEClusterBefore", "Histo for cluster energy before cuts", HistType::kTH1D, {thAxisClusterEnergy}); + registry.add("clusterQA/hEClusterAfter", "Histo for cluster energy after cuts", HistType::kTH1D, {thAxisClusterEnergy}); + registry.add("clusterQA/hClusterEtaPhiBefore", "hClusterEtaPhiBefore", HistType::kTH2D, {thAxisPhi, thAxisEta}); + registry.add("clusterQA/hClusterEtaPhiAfter", "hClusterEtaPhiAfter", HistType::kTH2D, {thAxisPhi, thAxisEta}); + } + + if (doprocessEMC) { + registry.add("EMCal/hSparsePhotonFlow", " vs M_{02} vs p_T vs cent", HistType::kTProfile3D, {thnAxisM02, thnAxisPt, thnAxisCent}); + registry.add("EMCal/hSparsePhoton", "M_{02} vs p_T vs cent", HistType::kTH3D, {thnAxisM02, thnAxisPt, thnAxisCent}); + } + if (doprocessPCM) { + registry.add("PCM/hSparsePhotonFlow", " vs M_{02} vs p_T vs cent", HistType::kTProfile3D, {thnAxisM02, thnAxisPt, thnAxisCent}); + registry.add("PCM/hSparsePhoton", "M_{02} vs p_T vs cent", HistType::kTH3D, {thnAxisM02, thnAxisPt, thnAxisCent}); + } + + ccdb->setURL(ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + LOG(info) << "thnConfigAxisPt.value[1] = " << thnConfigAxisPt.value[1] << " thnConfigAxisPt.value.back() = " << thnConfigAxisPt.value.back(); + + }; // end init + + /// \brief Check whether a photon (by its phi) falls in the EMCal or DCal acceptance + /// \param phi azimuthal angle of the photon + static bool isEMCalRegion(float phi) + { + return phi < MaxPhiEMCal; + } + + /// Change radians to degree + /// \param angle in radians + /// \return angle in degree + static constexpr float getAngleDegree(float angle) + { + return angle * o2::constants::math::Rad2Deg; + } + + /// Compute the delta psi in the range [0, pi/harmonic] + /// \param psi1 is the first angle + /// \param psi2 is the second angle + float getDeltaPsiInRange(float psi1, float psi2) + { + float deltaPsi = psi1 - psi2; + return RecoDecay::constrainAngle(deltaPsi, 0.f, harmonic); + } + + /// Get the centrality + /// \param collision is the collision with the centrality information + template + float getCentrality(TCollision const& collision) + { + float cent = -999.; + switch (centEstimator) { + case CentralityEstimator::CFT0M: + cent = collision.centFT0M(); + break; + case CentralityEstimator::CFT0A: + cent = collision.centFT0A(); + break; + case CentralityEstimator::CFT0C: + cent = collision.centFT0C(); + break; + default: + LOG(warning) << "Centrality estimator not valid. Possible values are T0M, T0A, T0C. Fallback to T0C"; + cent = collision.centFT0C(); + break; + } + return cent; + } + + /// Get all used Q vector + /// \param collision is the collision with the Q vector information + template + std::array getAllQvec(TCollision const& collision) + { + // Retrieve the Q vectors using the helper function for each detector + auto [xQVecMain, yQVecMain] = getQvec(collision, qvecDetector); + auto [xQVecSubA, yQVecSubA] = getQvec(collision, qvecSubADetector); + auto [xQVecSubB, yQVecSubB] = getQvec(collision, qvecSubBDetector); + + return {xQVecMain, yQVecMain, xQVecSubA, yQVecSubA, xQVecSubB, yQVecSubB}; + } + + /// Get the Q vector + /// \param collision is the collision with the Q vector information + template + std::pair getQvec(TCollision const& collision, int detector) + { + float xQVec = -999.f; + float yQVec = -999.f; + + switch (detector) { + case QvecEstimator::FT0M: + if (harmonic == kElliptic) { + xQVec = collision.q2xft0m(); + yQVec = collision.q2yft0m(); + } else if (harmonic == kTriangluar) { + xQVec = collision.q3xft0m(); + yQVec = collision.q3yft0m(); + } + break; + case QvecEstimator::FT0A: + if (harmonic == kElliptic) { + xQVec = collision.q2xft0a(); + yQVec = collision.q2yft0a(); + } else if (harmonic == kTriangluar) { + xQVec = collision.q3xft0a(); + yQVec = collision.q3yft0a(); + } + break; + case QvecEstimator::FT0C: + if (harmonic == kElliptic) { + xQVec = collision.q2xft0c(); + yQVec = collision.q2yft0c(); + } else if (harmonic == kTriangluar) { + xQVec = collision.q3xft0c(); + yQVec = collision.q3yft0c(); + } + break; + case QvecEstimator::TPCPos: + if (harmonic == kElliptic) { + xQVec = collision.q2xbpos(); + yQVec = collision.q2ybpos(); + } else if (harmonic == kTriangluar) { + xQVec = collision.q3xbpos(); + yQVec = collision.q3ybpos(); + } + break; + case QvecEstimator::TPCNeg: + if (harmonic == kElliptic) { + xQVec = collision.q2xbneg(); + yQVec = collision.q2ybneg(); + } else if (harmonic == kTriangluar) { + xQVec = collision.q3xbneg(); + yQVec = collision.q3ybneg(); + } + break; + case QvecEstimator::TPCTot: + if (harmonic == kElliptic) { + xQVec = collision.q2xbtot(); + yQVec = collision.q2ybtot(); + } else if (harmonic == kTriangluar) { + xQVec = collision.q3xbtot(); + yQVec = collision.q3ybtot(); + } + break; + case QvecEstimator::FV0A: + if (harmonic == kElliptic) { + xQVec = collision.q2xfv0a(); + yQVec = collision.q2yfv0a(); + } else if (harmonic == kTriangluar) { + xQVec = collision.q3xfv0a(); + yQVec = collision.q3yfv0a(); + } + break; + default: + LOG(warning) << "Q vector estimator not valid. Falling back to FT0M"; + if (harmonic == kElliptic) { + xQVec = collision.q2xft0m(); + yQVec = collision.q2yft0m(); + } else if (harmonic == kTriangluar) { + xQVec = collision.q3xft0m(); + yQVec = collision.q3yft0m(); + } + break; + } + return {xQVec, yQVec}; + } + + /// Check if the QVector values are within reasonable range + /// \param collision is the collision with the Q vector information + bool isQvecGood(std::array const& QVecs) + { + bool isgood = true; + for (const auto& QVec : QVecs) { + if (std::fabs(QVec) > cfgMaxQVector) { + isgood = false; + break; + } + } + return isgood; + } + + bool isTooCloseToEdge(const int cellID, const int DistanceToBorder = 1) + { + if (DistanceToBorder <= 0) { + return false; + } + if (cellID < 0) { + return true; + } + + int iBadCell = -1; + + // check distance to border in case the cell is okay + auto [iSupMod, iMod, iPhi, iEta] = emcalGeom->GetCellIndex(cellID); + auto [irow, icol] = emcalGeom->GetCellPhiEtaIndexInSModule(iSupMod, iMod, iPhi, iEta); + + // Check rows/phi + int iRowLast = 24; + if (emcalGeom->GetSMType(iSupMod) == o2::emcal::EMCALSMType::EMCAL_HALF) { + iRowLast /= 2; // 2/3 sm case + } else if ((emcalGeom->GetSMType(iSupMod) == o2::emcal::EMCALSMType::EMCAL_THIRD) || + (emcalGeom->GetSMType(iSupMod) == o2::emcal::EMCALSMType::DCAL_EXT)) { + iRowLast /= 3; // 1/3 sm case + } + + if (irow < DistanceToBorder || (iRowLast - irow) <= DistanceToBorder) { + iBadCell = 1; + } + + if (iBadCell > 0) { + return true; + } + return false; + } + + template + bool isCellMasked(int cellID, TCollision const& collision) + { + bool masked = false; + auto maskStatus = collision.badChannelMap().getChannelStatus(cellID); + masked = (maskStatus != o2::emcal::BadChannelMap::MaskType_t::GOOD_CELL); + return masked; + } + + template + float getV0Kappa(TLeg const& pos, TLeg const& ele) + { + float kappa = (std::fabs(pos.tpcNSigmaEl()) + std::fabs(ele.tpcNSigmaEl())) / 2.f + (2.f * pos.tpcNSigmaEl() + ele.tpcNSigmaEl()); + return kappa; + } + + template + void initCCDB(TCollision const& collision) + { + // Load EMCal geometry + emcalGeom = o2::emcal::Geometry::GetInstanceFromRunNumber(collision.runNumber()); + lookupTable1D.fill(-1); + double binWidthEta = (etaMax - EtaMin) / NBinsEta; + double binWidthPhi = (phiMax - PhiMin) / NBinsPhi; + + if (cfgEMCalMapLevelSameEvent >= static_cast(MapLevel::kAll)) { + // in this case we do not want to check the clusters, so just say thery are all good. + lookupTable1D.fill(0); // good + } else { + for (int iEta = 0; iEta < NBinsEta; ++iEta) { + double etaCenter = EtaMin + (iEta + 0.5) * binWidthEta; + for (int iPhi = 0; iPhi < NBinsPhi; ++iPhi) { + double phiCenter = PhiMin + (iPhi + 0.5) * binWidthPhi; + try { + // Get the cell ID + int cellID = emcalGeom->GetAbsCellIdFromEtaPhi(etaCenter, phiCenter); + + // Check conditions for the cell + if (isTooCloseToEdge(cellID, 1)) { + lookupTable1D[getIndex(iEta, iPhi)] = 2; // Edge + } else if (isCellMasked(cellID, collision)) { + lookupTable1D[getIndex(iEta, iPhi)] = 1; // Bad + } else { + lookupTable1D[getIndex(iEta, iPhi)] = 0; // Good + } + } catch (o2::emcal::InvalidPositionException& e) { + lookupTable1D[getIndex(iEta, iPhi)] = 3; // Outside geometry + } + } + } + } + if (correctionConfig.cfgApplySPresolution.value) { + h1SPResolution = ccdb->getForTimeStamp(correctionConfig.cfgSpresoPath.value, collision.timestamp()); + } + } + + /// \brief check if standard event cuts + FT0 occupancy + centrality + QVec good is + /// \param collision collision that will be checked + /// \return true if collision survives all checks, otherwise false + template + bool isFullEventSelected(TCollision const& collision, bool fillHisto = false) + { + if (fillHisto) { + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<0>(®istry, collision); + } + if (!(fEMEventCut.IsSelected(collision))) { + // general event selection + return false; + } + if (!(eventcuts.cfgFT0COccupancyMin <= collision.ft0cOccupancyInTimeRange() && collision.ft0cOccupancyInTimeRange() < eventcuts.cfgFT0COccupancyMax)) { + // occupancy selection + return false; + } + float cent = getCentrality(collision); + if (cent < eventcuts.cfgMinCent || cent > eventcuts.cfgMaxCent) { + // event selection + return false; + } + if (!isQvecGood(getAllQvec(collision))) { + // selection based on QVector + return false; + } + if (fillHisto) { + o2::aod::pwgem::photonmeson::utils::eventhistogram::fillEventInfo<1>(®istry, collision); + registry.fill(HIST("Event/before/hCollisionCounter"), 12.0); // accepted + registry.fill(HIST("Event/after/hCollisionCounter"), 12.0); // accepted + } + return true; + } + + void processEMC(Colls const& collisions, EMCalPhotons const& clusters, MinMTracks const& matchedPrims, MinMSTracks const& matchedSeconds) + { + if (clusters.size() <= 0) { + LOG(info) << "Skipping DF because there are not photons!"; + return; + } + EMBitFlags emcFlags(clusters.size()); + fEMCCut.AreSelectedRunning(emcFlags, clusters, matchedPrims, matchedSeconds); + + for (const auto& collision : collisions) { + float cent = getCentrality(collision); + if (!isFullEventSelected(collision, true)) { + continue; + } + runNow = collision.runNumber(); + if (runNow != runBefore) { + initCCDB(collision); + runBefore = runNow; + } + auto photonsPerCollision = clusters.sliceBy(perCollisionEMC, collision.globalIndex()); + + for (const auto& photon : photonsPerCollision) { + if (emccuts.cfgEnableQA.value) { + registry.fill(HIST("clusterQA/hEClusterBefore"), photon.corrE()); // before cuts + registry.fill(HIST("clusterQA/hClusterEtaPhiBefore"), photon.phi(), photon.eta()); // before cuts + } + if (!(emcFlags.test(photon.globalIndex()))) { + continue; + } + if ((emccuts.useEMCal.value && !emccuts.useDCal.value && (!isEMCalRegion(photon.phi()))) || (!emccuts.useEMCal.value && emccuts.useDCal.value && (isEMCalRegion(photon.phi())))) { + continue; + } + if (cfgDistanceToEdge.value > 0 && (checkEtaPhi1D(photon.eta(), RecoDecay::constrainAngle(photon.phi())) >= cfgEMCalMapLevelSameEvent.value)) { + continue; + } + if (emccuts.cfgEnableQA.value) { + registry.fill(HIST("clusterQA/hEClusterAfter"), photon.corrE()); // accepted after cuts + registry.fill(HIST("clusterQA/hClusterEtaPhiAfter"), photon.phi(), photon.eta()); // after cuts + } + + auto [xQVec, yQVec] = getQvec(collision, qvecDetector); + + float phiCand = photon.phi(); + + float cosNPhi = std::cos(harmonic * phiCand); + float sinNPhi = std::sin(harmonic * phiCand); + float scalprodCand = cosNPhi * xQVec + sinNPhi * yQVec; + + if (correctionConfig.cfgApplySPresolution.value) { + scalprodCand = scalprodCand / h1SPResolution->GetBinContent(h1SPResolution->FindBin(cent + epsilon)); + } + registry.fill(HIST("EMCal/hSparsePhotonFlow"), photon.m02(), photon.corrPt(), cent, scalprodCand); + registry.fill(HIST("EMCal/hSparsePhoton"), photon.m02(), photon.corrPt(), cent); + } // end of loop over single cluster + } // end of loop over collisions + } // processEMC + PROCESS_SWITCH(TaskPhotonFlow, processEMC, "Process single EMCal clusters as function of M02", false); + + void processPCM(Colls const& collisions, PCMPhotons const& photons, aod::V0Legs const& legs) + { + if (photons.size() <= 0 || legs.size() <= 0) { + LOG(info) << "Skipping DF because there are not photons!"; + return; + } + auto ele = legs.begin(); + auto pos = legs.begin(); + EMBitFlags v0flags(photons.size()); + fV0PhotonCut.AreSelectedRunning(v0flags, photons, ®istry); + for (const auto& collision : collisions) { + + if (!isFullEventSelected(collision, true)) { + continue; + } + + float cent = getCentrality(collision); + + runNow = collision.runNumber(); + if (runNow != runBefore) { + initCCDB(collision); + runBefore = runNow; + } + + auto photonsPerCollision = photons.sliceBy(perCollisionPCM, collision.globalIndex()); + for (const auto& photon : photonsPerCollision) { + if (!(v0flags.test(photon.globalIndex()))) { + continue; + } + ele.setCursor(photon.negTrackId()); + pos.setCursor(photon.posTrackId()); + + auto [xQVec, yQVec] = getQvec(collision, qvecDetector); + + float phiCand = photon.phi(); + + float cosNPhi = std::cos(harmonic * phiCand); + float sinNPhi = std::sin(harmonic * phiCand); + float scalprodCand = cosNPhi * xQVec + sinNPhi * yQVec; + + if (correctionConfig.cfgApplySPresolution.value) { + scalprodCand = scalprodCand / h1SPResolution->GetBinContent(h1SPResolution->FindBin(cent + epsilon)); + } + + float kappa = getV0Kappa(pos, ele); + registry.fill(HIST("PCM/hSparsePhotonFlow"), kappa, photon.corrPt(), cent, scalprodCand); + registry.fill(HIST("PCM/hSparsePhoton"), kappa, photon.corrPt(), cent); + } + } // end of loop over collisions + } + PROCESS_SWITCH(TaskPhotonFlow, processPCM, "Process PCM Pi0 candidates", true); + +}; // End struct TaskPhotonFlow + +WorkflowSpec defineDataProcessing(ConfigContext const& context) +{ + return WorkflowSpec{adaptAnalysisTask(context)}; +} diff --git a/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx b/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx index db7281218ba..df0c4ac6456 100644 --- a/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx @@ -133,6 +133,7 @@ struct TaskPi0FlowEMC { ConfigurableAxis thnConfigAxisCosDeltaPhi{"thnConfigAxisCosDeltaPhi", {8, -1., 1.}, "cos(delta phi) axis for the current event"}; ConfigurableAxis thnConfigAxisM02{"thnConfigAxisM02", {200, 0., 5.}, "M02 axis for the EMCal cluster"}; ConfigurableAxis thnConfigAxisEnergyCalib{"thnConfigAxisEnergyCalib", {200, 0., 20.}, "energy axis for the emcal clusters for the calibration process"}; + ConfigurableAxis thConfigAxisEtaPhiAngle{"thConfigAxisEtaPhiAngle", {180, -o2::constants::math::PI, o2::constants::math::PI}, "atan2(#Delta#eta,#Delta#varphi) axis (deg)"}; EMPhotonEventCut fEMEventCut; struct : ConfigurableGroup { @@ -173,7 +174,9 @@ struct TaskPi0FlowEMC { Configurable cfgEMCUseTM{"cfgEMCUseTM", false, "flag to use EMCal track matching cut or not"}; Configurable emcUseSecondaryTM{"emcUseSecondaryTM", false, "flag to use EMCal secondary track matching cut or not"}; Configurable cfgEnableQA{"cfgEnableQA", false, "flag to turn QA plots on/off"}; - Configurable separateEMCalDCal{"separateEMCalDCal", false, "flag to only pair EMCal with EMCal and DCal with DCal clusters"}; + Configurable useEMCal{"useEMCal", false, "flag to use EMCal clusters"}; + Configurable useDCal{"useDCal", false, "flag to use DCal clusters"}; + Configurable useCrosspairs{"useCrosspairs", true, "flag to allow pairing of EMCal with DCal clusters. If this is set, useEMCal and useDCal are ignored!"}; } emccuts; V0PhotonCut fV0PhotonCut; @@ -245,6 +248,8 @@ struct TaskPi0FlowEMC { Configurable cfgApplySPresolution{"cfgApplySPresolution", false, "Apply resolution correction"}; Configurable doEMCalCalib{"doEMCalCalib", false, "Produce output for EMCal calibration"}; Configurable cfgEnableNonLin{"cfgEnableNonLin", false, "flag to turn extra non linear energy calibration on/off"}; + Configurable cfgEmcalEffRadius{"cfgEmcalEffRadius", 430.f, "effective EMCal radius (cm) used for mixed-event vertex-swap correction"}; + Configurable cfgCorrectMixedVtxEta{"cfgCorrectMixedVtxEta", true, "re-project cluster2 eta onto collision1's vertex in mixed event"}; } correctionConfig; SliceCache cache; @@ -253,8 +258,8 @@ struct TaskPi0FlowEMC { int runNow = 0; int runBefore = -1; - static constexpr float MaxPhiEMCal = 3.5f; - static constexpr uint16_t MaxPhiEMCalUint = static_cast(INT16_MAX); // Maximum value currently useable for partitions for some weird reason, but luckily enough + static constexpr float MaxPhiEMCal = 3.9f; // exatly the middle between EMCal and DCal + static constexpr uint16_t MaxPhiEMCalUint = static_cast(39000u); // exatly the middle between EMCal and DCal but as uint16_t that is used for storing phi values in derived data // Filter clusterFilter = aod::skimmedcluster::time >= emccuts.cfgEMCminTime && aod::skimmedcluster::time <= emccuts.cfgEMCmaxTime && aod::skimmedcluster::m02 >= emccuts.cfgEMCminM02 && aod::skimmedcluster::m02 <= emccuts.cfgEMCmaxM02 && aod::skimmedcluster::e >= emccuts.cfgEMCminE; Filter collisionFilter = (nabs(aod::collision::posZ) <= eventcuts.cfgZvtxMax) && (aod::evsel::ft0cOccupancyInTimeRange <= eventcuts.cfgFT0COccupancyMax) && (aod::evsel::ft0cOccupancyInTimeRange >= eventcuts.cfgFT0COccupancyMin); @@ -413,6 +418,7 @@ struct TaskPi0FlowEMC { const AxisSpec thnAxisMixingVtx{mixingConfig.cfgVtxBins, "#it{z} (cm)"}; const AxisSpec thnAxisMixingCent{mixingConfig.cfgCentBins, "Centrality (%)"}; const AxisSpec thnAxisMixingEP{mixingConfig.cfgEPBins, Form("cos(%d#varphi)", harmonic.value)}; + const AxisSpec thAxisEtaPhiAngle{thConfigAxisEtaPhiAngle, "atan2(#Delta#eta,#Delta#varphi) (rad)"}; if (!doprocessM02) { registry.add("hSparsePi0Flow", " vs m_{inv} vs p_T vs cent for same event", HistType::kTProfile3D, {thnAxisInvMass, thnAxisPt, thnAxisCent}); @@ -466,6 +472,8 @@ struct TaskPi0FlowEMC { registry.add("mesonQA/hInvMassPtMixed", "Histo for inv pair mass vs pt for mixed event", HistType::kTH2D, {thnAxisInvMass, thnAxisPt}); registry.add("mesonQA/hTanThetaPhiMixed", "Histo for identification of conversion cluster for mixed event", HistType::kTH2D, {thnAxisInvMass, thAxisTanThetaPhi}); registry.add("mesonQA/hAlphaPtMixed", "Histo of meson asymmetry vs pT for mixed event", HistType::kTH2D, {thAxisAlpha, thnAxisPt}); + registry.add("mesonQA/hEtaPhiAngleMassCent", "atan2(#Delta#eta,#Delta#varphi) vs m_{inv} vs cent, same event", HistType::kTH3D, {thAxisEtaPhiAngle, thnAxisInvMass, thnAxisCent}); + registry.add("mesonQA/hEtaPhiAngleMassCentMixed", "atan2(#Delta#eta,#Delta#varphi) vs m_{inv} vs cent, mixed event", HistType::kTH3D, {thAxisEtaPhiAngle, thnAxisInvMass, thnAxisCent}); } if (correctionConfig.doEMCalCalib.value) { @@ -526,6 +534,18 @@ struct TaskPi0FlowEMC { registry.fill(HIST(HistTypes[histType]), mass, pt, cent); } + /// \brief eta a cluster would have if its own vertex vzOld is swapped for vzNew, + /// assuming a nominal cylindrical EMCal surface at transverse radius emcalR (cm). + /// phi is untouched: transverse vertex spread is negligible next to emcalR. + /// \param etaOld old eta value + /// \param vzOld old primary vertex z position + /// \param vzNew new primary vertex z position + /// \param emcalR radius of the EMCal + static float correctEtaForVertexShift(float etaOld, float vzOld, float vzNew, float emcalR) + { + return std::asinh(std::sinh(etaOld) + (vzOld - vzNew) / emcalR); + } + /// Get the centrality /// \param collision is the collision with the centrality information template @@ -1050,6 +1070,7 @@ struct TaskPi0FlowEMC { float dTheta = v1.Theta() - v2.Theta(); float dPhi = v1.Phi() - v2.Phi(); + float dEta = v1.Eta() - v2.Eta(); float openingAngle = std::acos(v1.Vect().Dot(v2.Vect()) / (v1.P() * v2.P())); registry.fill(HIST("hMesonCuts"), 1); @@ -1072,6 +1093,7 @@ struct TaskPi0FlowEMC { registry.fill(HIST("mesonQA/hInvMassPt"), vMeson.M(), vMeson.Pt()); registry.fill(HIST("mesonQA/hTanThetaPhi"), vMeson.M(), getAngleDegree(std::atan(dTheta / dPhi))); registry.fill(HIST("mesonQA/hAlphaPt"), (v1.E() - v2.E()) / (v1.E() + v2.E()), vMeson.Pt()); + registry.fill(HIST("mesonQA/hEtaPhiAngleMassCent"), RecoDecay::constrainAngle(std::atan2(dEta, dPhi), -o2::constants::math::PI), vMeson.M(), getCentrality(collision)); } if (mesonConfig.enableTanThetadPhi.value && mesonConfig.minTanThetadPhi > std::fabs(getAngleDegree(std::atan(dTheta / dPhi)))) { registry.fill(HIST("hMesonCuts"), 5); @@ -1093,7 +1115,6 @@ struct TaskPi0FlowEMC { fEMCCut.AreSelectedRunning(flags, clusters, matchedPrims, matchedSeconds, ®istry); for (const auto& collision : collisions) { - if (!isFullEventSelected(collision, true)) { continue; } @@ -1121,10 +1142,13 @@ struct TaskPi0FlowEMC { registry.fill(HIST("clusterQA/hClusterEtaPhiAfter"), photon.phi(), photon.eta()); // after cuts } } - if (emccuts.separateEMCalDCal.value) { + if (emccuts.useEMCal.value && !emccuts.useCrosspairs.value) { runPairingLoop(collision, emcalPhotonsPerCollision, emcalPhotonsPerCollision, flags, flags); + } + if (emccuts.useDCal.value && !emccuts.useCrosspairs.value) { runPairingLoop(collision, dcalPhotonsPerCollision, dcalPhotonsPerCollision, flags, flags); - } else { + } + if (emccuts.useCrosspairs.value) { runPairingLoop(collision, photonsPerCollision, photonsPerCollision, flags, flags); } if (rotationConfig.cfgDoRotation.value) { @@ -1181,8 +1205,11 @@ struct TaskPi0FlowEMC { if (!(flags.test(g1.globalIndex())) || !(flags.test(g2.globalIndex()))) { continue; } - if (emccuts.separateEMCalDCal.value && isEMCalRegion(g1.phi()) != isEMCalRegion(g2.phi())) { - continue; // only pair EMCal-EMCal or DCal-DCal + if (emccuts.useEMCal.value && !emccuts.useCrosspairs.value && (!isEMCalRegion(g1.phi()) || !isEMCalRegion(g2.phi()))) { + continue; + } + if (emccuts.useDCal.value && !emccuts.useCrosspairs.value && (isEMCalRegion(g1.phi()) || isEMCalRegion(g2.phi()))) { + continue; } // Cut edge clusters away, similar to rotation method to ensure same acceptance is used @@ -1195,11 +1222,18 @@ struct TaskPi0FlowEMC { } } ROOT::Math::PtEtaPhiMVector v1(g1.corrPt(), g1.eta(), g1.phi(), 0.); - ROOT::Math::PtEtaPhiMVector v2(g2.corrPt(), g2.eta(), g2.phi(), 0.); + + // changing the eta position of cluster 2 from collision 2 to match the z-vertex position of collision 1 + float eta2 = g2.eta(); + if (correctionConfig.cfgCorrectMixedVtxEta.value) { + eta2 = correctEtaForVertexShift(g2.eta(), c2.posZ(), c1.posZ(), correctionConfig.cfgEmcalEffRadius.value); + } + ROOT::Math::PtEtaPhiMVector v2(g2.corrPt(), eta2, g2.phi(), 0.); ROOT::Math::PtEtaPhiMVector vMeson = v1 + v2; float dTheta = v1.Theta() - v2.Theta(); float dPhi = v1.Phi() - v2.Phi(); + float dEta = v1.Eta() - eta2; float openingAngle = std::acos(v1.Vect().Dot(v2.Vect()) / (v1.P() * v2.P())); registry.fill(HIST("hMesonCutsMixed"), 1); @@ -1219,6 +1253,7 @@ struct TaskPi0FlowEMC { registry.fill(HIST("mesonQA/hInvMassPtMixed"), vMeson.M(), vMeson.Pt()); registry.fill(HIST("mesonQA/hTanThetaPhiMixed"), vMeson.M(), getAngleDegree(std::atan(dTheta / dPhi))); registry.fill(HIST("mesonQA/hAlphaPtMixed"), (v1.E() - v2.E()) / (v1.E() + v2.E()), vMeson.Pt()); + registry.fill(HIST("mesonQA/hEtaPhiAngleMassCentMixed"), RecoDecay::constrainAngle(std::atan2(dEta, dPhi), -o2::constants::math::PI), vMeson.M(), getCentrality(c1)); } if (mesonConfig.enableTanThetadPhi.value && mesonConfig.minTanThetadPhi > std::fabs(getAngleDegree(std::atan(dTheta / dPhi)))) { registry.fill(HIST("hMesonCutsMixed"), 5); diff --git a/PWGEM/PhotonMeson/Utils/EventHistograms.h b/PWGEM/PhotonMeson/Utils/EventHistograms.h index e63216a4821..f9f9fcdec0b 100644 --- a/PWGEM/PhotonMeson/Utils/EventHistograms.h +++ b/PWGEM/PhotonMeson/Utils/EventHistograms.h @@ -47,34 +47,13 @@ inline void addEventHistograms(o2::framework::HistogramRegistry* fRegistry, bool hCollisionCounter->GetXaxis()->SetBinLabel(11, "EMC L0 Triggered"); hCollisionCounter->GetXaxis()->SetBinLabel(12, "accepted"); - const o2::framework::AxisSpec axis_cent_ft0m{{0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110}, - "centrality FT0M (%)"}; - - const o2::framework::AxisSpec axis_cent_ft0a{{0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110}, - "centrality FT0A (%)"}; - - const o2::framework::AxisSpec axis_cent_ft0c{{0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110}, - "centrality FT0C (%)"}; - fRegistry->add("Event/before/hZvtx", "vertex z; Z_{vtx} (cm)", o2::framework::HistType::kTH1D, {{220, -11, +11}}, useWeight); fRegistry->add("Event/before/hMultNTracksPV", "hMultNTracksPV; N_{track} to PV", o2::framework::HistType::kTH1F, {{6001, -0.5, 6000.5}}, useWeight); fRegistry->add("Event/before/hMultNTracksPVeta1", "hMultNTracksPVeta1; N_{track} to PV", o2::framework::HistType::kTH1F, {{6001, -0.5, 6000.5}}, useWeight); fRegistry->add("Event/before/hMultFT0", "hMultFT0;mult. FT0A;mult. FT0C", o2::framework::HistType::kTH2F, {{200, 0, 200000}, {60, 0, 60000}}, useWeight); - fRegistry->add("Event/before/hCentFT0A", "hCentFT0A;centrality FT0A (%)", o2::framework::HistType::kTH1F, {{axis_cent_ft0a}}, useWeight); - fRegistry->add("Event/before/hCentFT0C", "hCentFT0C;centrality FT0C (%)", o2::framework::HistType::kTH1F, {{axis_cent_ft0c}}, useWeight); - fRegistry->add("Event/before/hCentFT0M", "hCentFT0M;centrality FT0M (%)", o2::framework::HistType::kTH1F, {{axis_cent_ft0m}}, useWeight); + fRegistry->add("Event/before/hCentFT0A", "hCentFT0A;centrality FT0A (%)", o2::framework::HistType::kTH1F, {{100, 0., 100.}}, useWeight); + fRegistry->add("Event/before/hCentFT0C", "hCentFT0C;centrality FT0C (%)", o2::framework::HistType::kTH1F, {{100, 0., 100.}}, useWeight); + fRegistry->add("Event/before/hCentFT0M", "hCentFT0M;centrality FT0M (%)", o2::framework::HistType::kTH1F, {{100, 0., 100.}}, useWeight); fRegistry->add("Event/before/hCentFT0CvsMultNTracksPV", "hCentFT0CvsMultNTracksPV;centrality FT0C (%);N_{track} to PV", o2::framework::HistType::kTH2F, {{110, 0, 110}, {500, 0, 5000}}, useWeight); fRegistry->add("Event/before/hMultFT0CvsMultNTracksPV", "hMultFT0CvsMultNTracksPV;mult. FT0C;N_{track} to PV", o2::framework::HistType::kTH2F, {{60, 0, 60000}, {500, 0, 5000}}, useWeight); fRegistry->add("Event/before/hMultFT0CvsOccupancy", "hMultFT0CvsOccupancy;mult. FT0C;N_{track} in time range", o2::framework::HistType::kTH2F, {{60, 0, 60000}, {500, 0, 10000}}, useWeight); diff --git a/PWGEM/PhotonMeson/Utils/MCUtilities.h b/PWGEM/PhotonMeson/Utils/MCUtilities.h index 5dd76b4ec8b..4a31a33e51b 100644 --- a/PWGEM/PhotonMeson/Utils/MCUtilities.h +++ b/PWGEM/PhotonMeson/Utils/MCUtilities.h @@ -16,9 +16,12 @@ #ifndef PWGEM_PHOTONMESON_UTILS_MCUTILITIES_H_ #define PWGEM_PHOTONMESON_UTILS_MCUTILITIES_H_ +#include "PWGEM/PhotonMeson/Utils/ParticleOrigin.h" + #include #include +#include #include #include @@ -31,6 +34,9 @@ //_______________________________________________________________________ namespace o2::aod::pwgem::photonmeson::utils::mcutil { + +constexpr float kVertexEps = 1e-4f; // cm + template bool IsPhysicalPrimary(TTrack const& mctrack) { @@ -89,6 +95,7 @@ int IsXFromY(T const& mctrack, TMCs const& mcTracks, const int pdgX, const int p } return -1; } + //_______________________________________________________________________ // Go up the decay chain of a mcparticle looking for a mother with the given pdg codes, if found return this mothers daughter // E.g. Find the gamma that was created in a pi0 or eta decay @@ -106,6 +113,51 @@ int FindMotherInChain(T const& mcparticle, TMCs const& mcparticles, TTargetPDGs } return FindMotherInChain(mother, mcparticles, motherpdgs, Depth - 1); } + +//_______________________________________________________________________ +/// \brief Go up the decay chain of a mcparticle looking for a mother with the given pdg codes, +/// and return that MOTHER's own index (unlike FindMotherInChain, which returns its daughter). +/// Two different particles that share the same meson ancestor will resolve to the same value here. +/// \param mcparticle iterator of McParticles +/// \param mcparticles table of McParticles +/// \param motherpdgs ranges of mother PDG values to compare against +/// \param Depth how many links should this go up +template +int GetMesonInChain(T const& mcparticle, TMCs const& mcparticles, TTargetPDGs const& motherpdgs, const int Depth = 15) +{ + int decayChildIdx = FindMotherInChain(mcparticle, mcparticles, motherpdgs, Depth); + if (decayChildIdx < 0) { + return -1; + } + auto decayChild = mcparticles.iteratorAt(decayChildIdx); + return decayChild.mothersIds()[0]; // the meson itself, not its daughter +} + +//_______________________________________________________________________ +/// \brief Go up the decay chain of a mcparticle looking for a mother with the given pdg codes, if found return this mothers daughter +/// E.g. Find the gamma that was created in a pi0 or eta decay +/// \param mcIter iterator of mcparticle -- WILL BE MODIFIED/CONSUMED by this function +/// \param motherPdgs target mother PDG values +/// \param depth how many steps in the chain this check should go maximum before failing +template +int findMotherInChain(T& mcIter, TTargetPDGs const& motherPdgs, const int depth = 50) +{ + int currentIndex = mcIter.globalIndex(); // the node whose immediate mother we're about to test + + for (int d = 0; d < depth; ++d) { + if (!mcIter.has_mothers()) { + return -1; + } + const int motherId = mcIter.mothersIds()[0]; + mcIter.setCursor(motherId); + if (std::find(motherPdgs.begin(), motherPdgs.end(), mcIter.pdgCode()) != motherPdgs.end()) { + return currentIndex; // mother matches -- return the node directly below it + } + currentIndex = motherId; // no match -- this mother becomes "current" for the next step up + } + return -1; +} + //_______________________________________________________________________ template int IsEleFromPC(T const& mctrack, TMCs const& mcTracks) @@ -321,7 +373,7 @@ bool isMotherPDG(const T& mcparticle, T& mcparticleWorking, const int motherPDG, /// \param mcCursor iterator of mcparticle /// \param iter shared iterator used to walk to the mother template -bool isFromBremsstrahlung(TIter const& mcCursor, TIter& iter) +bool isFromBremsstrahlung(TIter const& mcCursor, TIter& iter, int& motherId) { if (!mcCursor.has_mothers()) { return false; @@ -329,7 +381,10 @@ bool isFromBremsstrahlung(TIter const& mcCursor, TIter& iter) if (mcCursor.pdgCode() != PDG_t::kGamma) { return false; // only a photon can itself be a bremsstrahlung emission } - const int motherId = mcCursor.mothersIds()[0]; + if (mcCursor.mothersIds().size() != 1) { + return false; // mother can be only a single lepton, otherwise it might be e+e- annihilation or something else + } + motherId = mcCursor.mothersIds()[0]; iter.setCursor(motherId); return std::abs(iter.pdgCode()) == PDG_t::kElectron; } @@ -337,48 +392,93 @@ bool isFromBremsstrahlung(TIter const& mcCursor, TIter& iter) //_______________________________________________________________________ /// \brief Go up the decay chain of a mcparticle looking for a mother with the given pdg codes, if found return id else -1 /// E.g. if electron cluster is coming from a photon return true, if primary electron return false -/// \param mcparticle iterator of mxparticle, WILL BE CHANGED by this function! +/// \param mcParticle iterator of mxparticle, WILL BE CHANGED by this function! /// \param motherPDG target mother PDG value /// \param depth how many steps in the chain this check should go maximum before failing template -int32_t getMotherIndexFromChain(T& mcparticle, const int motherPDG, const int depth = 10) // o2-linter: disable=pdg/explicit-code (false positive) +int32_t getMotherIndexFromChain(T& mcParticle, const int motherPDG, const int depth = 10) { - if (!mcparticle.has_mothers() || depth < 1) { - return -1; - } - - int32_t motherid = mcparticle.mothersIds()[0]; - mcparticle.setCursor(motherid); - if (mcparticle.pdgCode() == motherPDG) { - return motherid; // The mother has the required pdg code, so return its daughters global mc particle code. + for (int d = 0; d < depth; ++d) { + if (!mcParticle.has_mothers()) { + return -1; + } + const int32_t motherid = mcParticle.mothersIds()[0]; + mcParticle.setCursor(motherid); + if (mcParticle.pdgCode() == motherPDG) { + return motherid; + } } - return getMotherIndexFromChain(mcparticle, motherPDG, depth - 1); + return -1; } //_______________________________________________________________________ -/// \brief Go up the decay chain of a mcparticle looking for a mother with the given pdg codes, if found return id else -1 -/// E.g. if electron cluster is coming from a photon return the photon's id, if primary electron return -1 -/// \param mcparticle iterator of mcparticle, NOT modified by this function -/// \param mcparticleWorking a second iterator of the SAME table, used as scratch space to walk up the chain -- caller must supply this so the function doesn't construct its own -/// \param motherPDG target mother PDG value -/// \param depth how many steps in the chain this check should go maximum before failing -template -int32_t getMotherIndexFromChain(const T& mcparticle, T& mcparticleWorking, const int motherPDG, const int depth = 10) // o2-linter: disable=pdg/explicit-code (false positive) +/// \brief Obtains given photon mcpartlices origin type +/// \param mcPhoton mcparticle iterator of photon +/// \param iter mcparticle iterator used to walk to the mother +/// \param motherDPGs list of pdg values of mothers that would be excepted for PhotonOrigin::Decay +/// \return given photon mcpartlices origin type +template +o2::analysis::em::PhotonOrigin getPhotonOriginType(TIter const& mcPhoton, TIter& mcIter, TTargetPDGs const& motherPdgs, int& motherId) { - if (!mcparticle.has_mothers() || depth < 1) { - return -1; + switch (mcPhoton.getProcess()) { + case TMCProcess::kPBrem: + return o2::analysis::em::PhotonOrigin::Bremsstrahlung; + case TMCProcess::kPAnnihilation: + return o2::analysis::em::PhotonOrigin::Annihilation; + case TMCProcess::kPHadronic: + return o2::analysis::em::PhotonOrigin::Hadronic; + default: + break; } - - int32_t motherid = mcparticle.mothersIds()[0]; - mcparticleWorking.setCursor(motherid); - if (mcparticleWorking.pdgCode() == motherPDG) { - return motherid; + if (!mcPhoton.has_mothers()) { + return o2::analysis::em::PhotonOrigin::Other; + } + mcIter.setCursor(mcPhoton.globalIndex()); + motherId = findMotherInChain(mcIter, motherPdgs); + if (motherId >= 0) { + return o2::analysis::em::PhotonOrigin::Decay; + } + motherId = mcPhoton.mothersIds()[0]; + mcIter.setCursor(motherId); + if ((std::abs(mcIter.pdgCode()) >= PDG_t::kDown && std::abs(mcIter.pdgCode()) <= PDG_t::kTop) || std::abs(mcIter.pdgCode()) == PDG_t::kGluon) { + return o2::analysis::em::PhotonOrigin::Direct; } - return getMotherIndexFromChain(mcparticleWorking, mcparticleWorking, motherPDG, depth - 1); + return o2::analysis::em::PhotonOrigin::Other; } //_______________________________________________________________________ +/// \brief Obtains given lepton mcpartlices origin type +/// \param mcLepton mcparticle iterator of lepton +/// \param iter mcparticle iterator used to walk to the mother +/// \param motherDPGs list of pdg values of mothers that would be excepted for PhotonOrigin::Decay +/// \return given lepton mcpartlices origin type +template +o2::analysis::em::LeptonOrigin getLeptonOriginType(TIter const& mcLepton, TIter& mcIter, TTargetPDGs const& motherPdgs) +{ + switch (mcLepton.getProcess()) { + case TMCProcess::kPPair: + return o2::analysis::em::LeptonOrigin::Conversion; + case TMCProcess::kPCompton: + return o2::analysis::em::LeptonOrigin::Compton; + case TMCProcess::kPPhotoelectric: + return o2::analysis::em::LeptonOrigin::PhotoElectric; + case TMCProcess::kPDeltaRay: + return o2::analysis::em::LeptonOrigin::DeltaRay; + case TMCProcess::kPDecay: { + if (!mcLepton.has_mothers()) { + return o2::analysis::em::LeptonOrigin::Other; + } + mcIter.setCursor(mcLepton.mothersIds()[0]); + if (std::find(motherPdgs.begin(), motherPdgs.end(), mcIter.pdgCode()) != motherPdgs.end()) { + return o2::analysis::em::LeptonOrigin::DirectMesonDecay; + } + return o2::analysis::em::LeptonOrigin::Other; // decay, but not from your target meson list + } + default: + return o2::analysis::em::LeptonOrigin::Other; + } +} + } // namespace o2::aod::pwgem::photonmeson::utils::mcutil -//_______________________________________________________________________ -//_______________________________________________________________________ + #endif // PWGEM_PHOTONMESON_UTILS_MCUTILITIES_H_ diff --git a/PWGEM/PhotonMeson/Utils/PCMUtilities.h b/PWGEM/PhotonMeson/Utils/PCMUtilities.h index 8c88d20ccad..e69703a3ec5 100644 --- a/PWGEM/PhotonMeson/Utils/PCMUtilities.h +++ b/PWGEM/PhotonMeson/Utils/PCMUtilities.h @@ -43,7 +43,7 @@ inline bool checkAP(const float alpha, const float qt, const float alpha_max = 0 return (ellipse < 1.0); } //_______________________________________________________________________ -inline float v0_alpha(float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) +inline float v0Alpha(float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) { float momTot = RecoDecay::p(pxpos + pxneg, pypos + pyneg, pzpos + pzneg); float lQlNeg = RecoDecay::dotProd(std::array{pxneg, pyneg, pzneg}, std::array{pxpos + pxneg, pypos + pyneg, pzpos + pzneg}) / momTot; @@ -51,7 +51,7 @@ inline float v0_alpha(float pxpos, float pypos, float pzpos, float pxneg, float return (lQlPos - lQlNeg) / (lQlPos + lQlNeg); // longitudinal momentum asymmetry of v0 } //_______________________________________________________________________ -inline float v0_qt(float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) +inline float v0Qt(float pxpos, float pypos, float pzpos, float pxneg, float pyneg, float pzneg) { float momTot = RecoDecay::p2(pxpos + pxneg, pypos + pyneg, pzpos + pzneg); float dp = RecoDecay::dotProd(std::array{pxneg, pyneg, pzneg}, std::array{pxpos + pxneg, pypos + pyneg, pzpos + pzneg}); @@ -262,4 +262,11 @@ inline V0TruthClass classifyV0Truth(TTrack const& pos, TTrack const& ele, TMCPar return kV0OtherFake; } +template +float getV0Kappa(TLeg const& pos, TLeg const& ele) +{ + float kappa = (std::fabs(pos.tpcNSigmaEl()) + std::fabs(ele.tpcNSigmaEl())) / 2.f + (2.f * (pos.tpcNSigmaEl() + ele.tpcNSigmaEl())); + return kappa; +} + #endif // PWGEM_PHOTONMESON_UTILS_PCMUTILITIES_H_ diff --git a/PWGEM/PhotonMeson/Utils/ParticleOrigin.h b/PWGEM/PhotonMeson/Utils/ParticleOrigin.h new file mode 100644 index 00000000000..86e0c3b1470 --- /dev/null +++ b/PWGEM/PhotonMeson/Utils/ParticleOrigin.h @@ -0,0 +1,46 @@ +// 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. + +/// \file ParticleOrigin.h +/// \brief commonly used enums for particle origins. +/// \author marvin.hemmer@cern.ch + +#ifndef PWGEM_PHOTONMESON_UTILS_PARTICLEORIGIN_H_ +#define PWGEM_PHOTONMESON_UTILS_PARTICLEORIGIN_H_ + +#include + +namespace o2::analysis::em +{ + +// Classifies the production history of a lepton +enum class LeptonOrigin : uint8_t { + Conversion = 0, + Compton = 1, + PhotoElectric = 2, + DeltaRay = 3, + DirectMesonDecay = 4, + Other = 5 +}; + +// Classifies the production history of a photon +enum class PhotonOrigin : uint8_t { + Direct = 0, // direct photons from quarks or gluons from inital scattering + Decay = 1, // decay photons from + Bremsstrahlung = 2, // photon from bremsstrahlung + Annihilation = 3, // e+e- -> gammagamma + Hadronic = 4, // hadronic interactions like charged pions with material + Other = 5 // anything else +}; + +} // namespace o2::analysis::em + +#endif // PWGEM_PHOTONMESON_UTILS_PARTICLEORIGIN_H_ diff --git a/PWGHF/Core/HfMlResponseHfTracks.h b/PWGHF/Core/HfMlResponseHfTracks.h new file mode 100644 index 00000000000..60fb744a197 --- /dev/null +++ b/PWGHF/Core/HfMlResponseHfTracks.h @@ -0,0 +1,221 @@ +// Copyright 2019-2026 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. + +/// \file HfMlResponseHfTracks.h +/// \brief Class to compute the ML response for single-track selection of HF daughters +/// \author Fabrizio Chinu , Universita and INFN Torino + +#ifndef PWGHF_CORE_HFMLRESPONSEHFTRACKS_H_ +#define PWGHF_CORE_HFMLRESPONSEHFTRACKS_H_ + +#include "PWGHF/Core/HfMlResponse.h" + +#include "Tools/ML/MlResponse.h" + +#include +#include +#include +#include + +// Fill the map of available input features +// the key is the feature's name (std::string) +// the value is the corresponding value in EnumInputFeatures +#define FILL_MAP_HF_TRACK(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesTracks::FEATURE)} + +// Check if the index of mCachedIndices (index associated to a FEATURE) +// matches the entry in EnumInputFeatures associated to this FEATURE +// if so, the inputFeatures vector is filled with the FEATURE's value +#define CHECK_AND_FILL_VEC_HF_TRACK(FEATURE) \ + case static_cast(InputFeaturesTracks::FEATURE): \ + inputFeatures.emplace_back(track.FEATURE); \ + break; + +namespace o2::analysis +{ + +/// Output classes of the track-level HF model. +/// The ordering must match the one used at training time. +enum class HfTrackMlClass : uint8_t { + Background = 0, ///< track is not a daughter of a D+ → πKπ / Ds → φπ → KKπ decay + Pion, ///< track is the π± of a D+ → πKπ / Ds → φπ → KKπ decay + Kaon, ///< track is the K∓ of a D+ → πKπ / Ds → φπ → KKπ decay + NClasses +}; + +enum class InputFeaturesTracks : uint8_t { + // kinematics + pt = 0, + eta, + // impact parameter and its resolution + dcaXY, + dcaZ, + sigmaDcaXY, + sigmaDcaZ, + normDcaXY, + normDcaZ, + // track parameters + signed1Pt, + tgl, + sign, + isPvContributor, + // ITS quality + itsNCls, + itsNClsInnerBarrel, + itsChi2NCl, + // TPC quality + tpcNClsFound, + tpcCrossedRowsOverFindableCls, + tpcChi2NCl, + tpcFractionSharedCls, + // TPC PID + tpcNSigmaPi, + tpcNSigmaKa, + // event + centrality +}; + +/// Plain container with every quantity the model can be fed. +/// It is filled once per (track, collision) association by the task and then reduced to the +/// configured subset of features by getInputFeatures(). +/// Everything is a float so that the training tree and the inference input are bit-identical. +struct HfTrackMlFeatures { + // kinematics + float pt{0.f}; + float eta{0.f}; + // impact parameter and its resolution + float dcaXY{0.f}; + float dcaZ{0.f}; + float sigmaDcaXY{0.f}; + float sigmaDcaZ{0.f}; + float normDcaXY{0.f}; + float normDcaZ{0.f}; + // track parameters + float signed1Pt{0.f}; + float tgl{0.f}; + float sign{0.f}; + float isPvContributor{0.f}; + // ITS quality + float itsNCls{0.f}; + float itsNClsInnerBarrel{0.f}; + float itsChi2NCl{0.f}; + // TPC quality + float tpcNClsFound{0.f}; + float tpcCrossedRowsOverFindableCls{0.f}; + float tpcChi2NCl{0.f}; + float tpcFractionSharedCls{0.f}; + // TPC PID + float tpcNSigmaPi{0.f}; + float tpcNSigmaKa{0.f}; + // event + float centrality{0.f}; +}; + +template +class HfMlResponseHfTracks : public HfMlResponse +{ + public: + /// Default constructor + HfMlResponseHfTracks() = default; + /// Default destructor + virtual ~HfMlResponseHfTracks() = default; + + /// Index of the model to be used for a given value of the binning variable (the track pT). + /// Needed because the task applies its own per-class thresholds instead of the single-decision + /// logic of MlResponse::isSelectedMl, whose private findBin is not reachable from here. + /// Follows the same convention as the base class: mBinsLimits stores the bin edges. + /// \param value is the value of the binning variable + /// \return index of the model to be used, -1 if the value is outside the configured range + int getModelBin(float value) const + { + const auto& binsLimits = MlResponse::mBinsLimits; + const auto valueDouble = static_cast(value); + if (binsLimits.empty() || valueDouble < binsLimits.front() || valueDouble >= binsLimits.back()) { + return -1; + } + return std::distance(binsLimits.begin(), std::upper_bound(binsLimits.begin(), binsLimits.end(), valueDouble)) - 1; + } + + /// Method to get the input features vector needed for ML inference + /// \param track is the container with all the candidate track quantities + /// \return inputFeatures vector, in the order configured via cacheInputFeaturesIndices + std::vector getInputFeatures(HfTrackMlFeatures const& track) + { + std::vector inputFeatures; + inputFeatures.reserve(MlResponse::mCachedIndices.size()); + + for (const auto& idx : MlResponse::mCachedIndices) { + switch (idx) { + CHECK_AND_FILL_VEC_HF_TRACK(pt); + CHECK_AND_FILL_VEC_HF_TRACK(eta); + CHECK_AND_FILL_VEC_HF_TRACK(dcaXY); + CHECK_AND_FILL_VEC_HF_TRACK(dcaZ); + CHECK_AND_FILL_VEC_HF_TRACK(sigmaDcaXY); + CHECK_AND_FILL_VEC_HF_TRACK(sigmaDcaZ); + CHECK_AND_FILL_VEC_HF_TRACK(normDcaXY); + CHECK_AND_FILL_VEC_HF_TRACK(normDcaZ); + CHECK_AND_FILL_VEC_HF_TRACK(signed1Pt); + CHECK_AND_FILL_VEC_HF_TRACK(tgl); + CHECK_AND_FILL_VEC_HF_TRACK(sign); + CHECK_AND_FILL_VEC_HF_TRACK(isPvContributor); + CHECK_AND_FILL_VEC_HF_TRACK(itsNCls); + CHECK_AND_FILL_VEC_HF_TRACK(itsNClsInnerBarrel); + CHECK_AND_FILL_VEC_HF_TRACK(itsChi2NCl); + CHECK_AND_FILL_VEC_HF_TRACK(tpcNClsFound); + CHECK_AND_FILL_VEC_HF_TRACK(tpcCrossedRowsOverFindableCls); + CHECK_AND_FILL_VEC_HF_TRACK(tpcChi2NCl); + CHECK_AND_FILL_VEC_HF_TRACK(tpcFractionSharedCls); + CHECK_AND_FILL_VEC_HF_TRACK(tpcNSigmaPi); + CHECK_AND_FILL_VEC_HF_TRACK(tpcNSigmaKa); + CHECK_AND_FILL_VEC_HF_TRACK(centrality); + } + } + + return inputFeatures; + } + + protected: + /// Method to fill the map of available input features + void setAvailableInputFeatures() + { + MlResponse::mAvailableInputFeatures = { + FILL_MAP_HF_TRACK(pt), + FILL_MAP_HF_TRACK(eta), + FILL_MAP_HF_TRACK(dcaXY), + FILL_MAP_HF_TRACK(dcaZ), + FILL_MAP_HF_TRACK(sigmaDcaXY), + FILL_MAP_HF_TRACK(sigmaDcaZ), + FILL_MAP_HF_TRACK(normDcaXY), + FILL_MAP_HF_TRACK(normDcaZ), + FILL_MAP_HF_TRACK(signed1Pt), + FILL_MAP_HF_TRACK(tgl), + FILL_MAP_HF_TRACK(sign), + FILL_MAP_HF_TRACK(isPvContributor), + FILL_MAP_HF_TRACK(itsNCls), + FILL_MAP_HF_TRACK(itsNClsInnerBarrel), + FILL_MAP_HF_TRACK(itsChi2NCl), + FILL_MAP_HF_TRACK(tpcNClsFound), + FILL_MAP_HF_TRACK(tpcCrossedRowsOverFindableCls), + FILL_MAP_HF_TRACK(tpcChi2NCl), + FILL_MAP_HF_TRACK(tpcFractionSharedCls), + FILL_MAP_HF_TRACK(tpcNSigmaPi), + FILL_MAP_HF_TRACK(tpcNSigmaKa), + FILL_MAP_HF_TRACK(centrality)}; + } +}; + +} // namespace o2::analysis + +#undef FILL_MAP_HF_TRACK +#undef CHECK_AND_FILL_VEC_HF_TRACK + +#endif // PWGHF_CORE_HFMLRESPONSEHFTRACKS_H_ diff --git a/PWGHF/D2H/Macros/compute_fraction_cutvar.py b/PWGHF/D2H/Macros/compute_fraction_cutvar.py index 0e5ced6f8a5..74432688725 100644 --- a/PWGHF/D2H/Macros/compute_fraction_cutvar.py +++ b/PWGHF/D2H/Macros/compute_fraction_cutvar.py @@ -11,13 +11,13 @@ import json import os import sys +from enum import IntEnum, auto import numpy as np # pylint: disable=import-error import ROOT # pylint: disable=import-error -from enum import IntEnum, auto + sys.path.insert(0, '..') -from cut_variation import CutVarMinimiser -from cut_variation import MinimisationStatus +from cut_variation import CutVarMinimiser, MinimisationStatus from style_formatter import set_object_style # pylint: disable=no-member,too-many-locals,too-many-statements @@ -28,6 +28,7 @@ class PlotType(IntEnum): Frac = auto() Cov = auto() Unc = auto() + RelUnc = auto() N = auto() class ObjectToSave(IntEnum): @@ -54,6 +55,10 @@ def main(config): with open(config, encoding="utf8") as fil: cfg = json.load(fil) + zero_eff_unc = cfg.get("zero_eff_unc", False) + effp_shift_nsigma = cfg.get("effp_shift_nsigma", 0.0) + effnp_shift_nsigma = cfg.get("effnp_shift_nsigma", 0.0) + hist_rawy, hist_effp, hist_effnp = ([] for _ in range(3)) for filename_rawy, filename_eff in zip(cfg["rawyields"]["inputfiles"], cfg["efficiencies"]["inputfiles"]): infile_rawy = ROOT.TFile.Open(os.path.join(cfg["rawyields"]["inputdir"], filename_rawy)) @@ -75,6 +80,12 @@ def main(config): sys.exit(f"\33[31mFatal error: Histogram with efficiency for nonprompt \"{hist_effnp}\" is absent. Exit.\33[0m") hist_effp[-1].SetDirectory(0) hist_effnp[-1].SetDirectory(0) + for i_bin in range(1, hist_effp[-1].GetNbinsX() + 1): + hist_effp[-1].SetBinContent(i_bin, hist_effp[-1].GetBinContent(i_bin) + effp_shift_nsigma*hist_effp[-1].GetBinError(i_bin)) + hist_effnp[-1].SetBinContent(i_bin, hist_effnp[-1].GetBinContent(i_bin) + effnp_shift_nsigma*hist_effnp[-1].GetBinError(i_bin)) + if zero_eff_unc: + hist_effp[-1].SetBinError(i_bin, 0.0) + hist_effnp[-1].SetBinError(i_bin, 0.0) infile_eff.Close() pt_bin_to_process = cfg.get("pt_bin_to_process", -1) @@ -89,6 +100,7 @@ def main(config): is_draw_title[PlotType.Frac] = cfg.get("is_draw_title", {}).get("frac", False) is_draw_title[PlotType.Cov] = cfg.get("is_draw_title", {}).get("cov", False) is_draw_title[PlotType.Unc] = cfg.get("is_draw_title", {}).get("unc", True) + is_draw_title[PlotType.RelUnc] = cfg.get("is_draw_title", {}).get("relunc", True) is_save_canvas_as_macro = [False] * PlotType.N is_save_canvas_as_macro[PlotType.Rawy] = cfg.get("is_save_canvas_as_macro", {}).get("rawy", False) @@ -96,6 +108,7 @@ def main(config): is_save_canvas_as_macro[PlotType.Frac] = cfg.get("is_save_canvas_as_macro", {}).get("frac", False) is_save_canvas_as_macro[PlotType.Cov] = cfg.get("is_save_canvas_as_macro", {}).get("cov", False) is_save_canvas_as_macro[PlotType.Unc] = cfg.get("is_save_canvas_as_macro", {}).get("unc", False) + is_save_canvas_as_macro[PlotType.RelUnc] = cfg.get("is_save_canvas_as_macro", {}).get("relunc", False) is_save_to_root_file = [False] * ObjectToSave.N is_save_to_root_file[ObjectToSave.Canvas] = cfg.get("is_save_to_root_file", {}).get("canvas", True) @@ -205,14 +218,16 @@ def main(config): ) pt_bin_to_process_name_suffix = "" - if pt_bin_to_process != -1: pt_bin_to_process_name_suffix = "_bin_" + str(pt_bin_to_process) + if pt_bin_to_process != -1: + pt_bin_to_process_name_suffix = "_bin_" + str(pt_bin_to_process) output_name_template = cfg['output']['file'].replace(".root", "") + pt_bin_to_process_name_suffix + ".root" output = ROOT.TFile(os.path.join(cfg["output"]["directory"], output_name_template), "recreate") n_sets = len(hist_rawy) pt_axis_title = hist_rawy[0].GetXaxis().GetTitle() for ipt in range(hist_rawy[0].GetNbinsX()): - if pt_bin_to_process !=-1 and ipt+1 != pt_bin_to_process: continue + if pt_bin_to_process !=-1 and ipt+1 != pt_bin_to_process: + continue all_vectors_monotonous = MinimisationStatus.Success pt_min = hist_rawy[0].GetXaxis().GetBinLowEdge(ipt + 1) pt_max = hist_rawy[0].GetXaxis().GetBinUpEdge(ipt + 1) @@ -237,9 +252,9 @@ def main(config): print("\0\33[33mWARNING! main(): the raw yield uncertainties vector is not monotonous. Check the input for stability.\0\33[0m") print(f"raw yield uncertainties vector elements = {unc_rawy}\n") if not (np.all(effp[1:] > effp[:-1]) or np.all(effp[1:] < effp[:-1])): - sys.exit(f"\33[31mFatal error: the prompt efficiency vector is not monotonous. Check the input. Exit.\33[0m") + sys.exit("\33[31mFatal error: the prompt efficiency vector is not monotonous. Check the input. Exit.\33[0m") if not (np.all(effnp[1:] > effnp[:-1]) or np.all(effnp[1:] < effnp[:-1])): - sys.exit(f"\33[31mFatal error: the nonprompt efficiency vector is not monotonous. Check the input. Exit.\33[0m") + sys.exit("\33[31mFatal error: the nonprompt efficiency vector is not monotonous. Check the input. Exit.\33[0m") minimiser = CutVarMinimiser(rawy, effp, effnp, unc_rawy, unc_effp, unc_effnp) status = minimiser.minimise_system(cfg["minimisation"]["correlated"]) @@ -278,47 +293,69 @@ def main(config): hist_bin_title = f"bin # {ipt+1}; {pt_axis_title}#in ({pt_min}; {pt_max})" hist_bin_title_rawy = hist_bin_title if is_draw_title[PlotType.Rawy] else "" - canv_rawy, histos_rawy, leg_r = minimiser.plot_result(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_rawy) + canv_rawy, histos_rawy, _leg_r = minimiser.plot_result(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_rawy) output.cd() - if is_save_to_root_file[ObjectToSave.Canvas]: canv_rawy.Write() + if is_save_to_root_file[ObjectToSave.Canvas]: + canv_rawy.Write() if is_save_to_root_file[ObjectToSave.RawYield]: - for _, hist in histos_rawy.items(): + for _, hist in histos_rawy.values(): hist.Write() - if is_save_canvas_as_macro[PlotType.Rawy]: canv_rawy.SaveAs(f"canv_rawy_{ipt+1}.C") + if is_save_canvas_as_macro[PlotType.Rawy]: + canv_rawy.SaveAs(f"canv_rawy_{ipt+1}.C") hist_bin_title_unc = hist_bin_title if is_draw_title[PlotType.Unc] else "" - canv_unc, histos_unc, leg_unc = minimiser.plot_uncertainties(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_unc) + canv_unc, histos_unc, _leg_unc = minimiser.plot_uncertainties(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_unc) + output.cd() + if is_save_to_root_file[ObjectToSave.Canvas]: + canv_unc.Write() + if is_save_to_root_file[ObjectToSave.Uncertainty]: + for _, hist in histos_unc.values(): + hist.Write() + if is_save_canvas_as_macro[PlotType.Unc]: + canv_unc.SaveAs(f"canv_unc_{ipt+1}.C") + + hist_bin_title_rel_unc = hist_bin_title if is_draw_title[PlotType.RelUnc] else "" + canv_rel_unc, histos_rel_unc, _leg_rel_unc = minimiser.plot_relative_uncertainties(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_rel_unc) output.cd() - if is_save_to_root_file[ObjectToSave.Canvas]: canv_unc.Write() + if is_save_to_root_file[ObjectToSave.Canvas]: + canv_rel_unc.Write() if is_save_to_root_file[ObjectToSave.Uncertainty]: - for _, hist in histos_unc.items(): + for _, hist in histos_rel_unc.values(): hist.Write() - if is_save_canvas_as_macro[PlotType.Unc]: canv_unc.SaveAs(f"canv_unc_{ipt+1}.C") + if is_save_canvas_as_macro[PlotType.RelUnc]: + canv_rel_unc.SaveAs(f"canv_rel_unc_{ipt+1}.C") hist_bin_title_eff = hist_bin_title if is_draw_title[PlotType.Eff] else "" - canv_eff, histos_eff, leg_e = minimiser.plot_efficiencies(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_eff) + canv_eff, histos_eff, _leg_e = minimiser.plot_efficiencies(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_eff) output.cd() - if is_save_to_root_file[ObjectToSave.Canvas]: canv_eff.Write() + if is_save_to_root_file[ObjectToSave.Canvas]: + canv_eff.Write() if is_save_to_root_file[ObjectToSave.Efficiency]: - for _, hist in histos_eff.items(): + for _, hist in histos_eff.values(): hist.Write() - if is_save_canvas_as_macro[PlotType.Eff]: canv_eff.SaveAs(f"canv_eff_{ipt+1}.C") + if is_save_canvas_as_macro[PlotType.Eff]: + canv_eff.SaveAs(f"canv_eff_{ipt+1}.C") hist_bin_title_frac = hist_bin_title if is_draw_title[PlotType.Frac] else "" - canv_frac, histos_frac, leg_f = minimiser.plot_fractions(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_frac) + canv_frac, histos_frac, _leg_f = minimiser.plot_fractions(f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_frac) output.cd() - if is_save_to_root_file[ObjectToSave.Canvas]: canv_frac.Write() + if is_save_to_root_file[ObjectToSave.Canvas]: + canv_frac.Write() if is_save_to_root_file[ObjectToSave.Fraction]: - for _, hist in histos_frac.items(): + for _, hist in histos_frac.values(): hist.Write() - if is_save_canvas_as_macro[PlotType.Frac]: canv_frac.SaveAs(f"canv_frac_{ipt+1}.C") + if is_save_canvas_as_macro[PlotType.Frac]: + canv_frac.SaveAs(f"canv_frac_{ipt+1}.C") hist_bin_title_cov = hist_bin_title if is_draw_title[PlotType.Cov] else "" canv_cov, histo_cov = minimiser.plot_cov_matrix(True, f"_pt_{pt_min}_to_{pt_max}", hist_bin_title_cov) output.cd() - if is_save_to_root_file[ObjectToSave.Canvas]: canv_cov.Write() - if is_save_to_root_file[ObjectToSave.CorrelationMatrix]: histo_cov.Write() - if is_save_canvas_as_macro[PlotType.Cov]: canv_cov.SaveAs(f"canv_cov_{ipt+1}.C") + if is_save_to_root_file[ObjectToSave.Canvas]: + canv_cov.Write() + if is_save_to_root_file[ObjectToSave.CorrelationMatrix]: + histo_cov.Write() + if is_save_canvas_as_macro[PlotType.Cov]: + canv_cov.SaveAs(f"canv_cov_{ipt+1}.C") else: print(f"Minimization for pT {pt_min}, {pt_max} not successful") hist_minimisation_status.SetBinContent(ipt + 1, MinimisationStatus.Fail) @@ -327,6 +364,7 @@ def main(config): canv_frac = ROOT.TCanvas("c_frac_minimization_error", "Minimization error", 500, 500) canv_cov = ROOT.TCanvas("c_conv_minimization_error", "Minimization error", 500, 500) canv_unc = ROOT.TCanvas("c_unc_minimization_error", "Minimization error", 500, 500) + canv_rel_unc = ROOT.TCanvas("c_rel_unc_minimization_error", "Minimization error", 500, 500) canv_combined = ROOT.TCanvas(f"canv_combined_{ipt}", "", 1000, 1000) canv_combined.Divide(2, 2) @@ -346,6 +384,7 @@ def main(config): output_name_frac_pdf = f"Frac_{output_name_template}" output_name_covmat_pdf = f"CovMatrix_{output_name_template}" output_name_unc_pdf = f"Unc_{output_name_template}" + output_name_rel_unc_pdf = f"RelUnc_{output_name_template}" output_name_pdf = f"{output_name_template}" if hist_rawy[0].GetNbinsX() == 1 or pt_bin_to_process != -1: @@ -362,6 +401,7 @@ def main(config): canv_cov.Print(f"{os.path.join(cfg['output']['directory'], output_name_covmat_pdf)}{print_bracket}") canv_combined.Print(f"{os.path.join(cfg['output']['directory'], output_name_pdf)}{print_bracket}") canv_unc.Print(f"{os.path.join(cfg['output']['directory'], output_name_unc_pdf)}{print_bracket}") + canv_rel_unc.Print(f"{os.path.join(cfg['output']['directory'], output_name_rel_unc_pdf)}{print_bracket}") output.cd() if is_save_to_root_file[ObjectToSave.CorrectedYield]: diff --git a/PWGHF/D2H/Macros/config_cutvar_example.json b/PWGHF/D2H/Macros/config_cutvar_example.json index f13a2d53d7f..d645db1a6d6 100644 --- a/PWGHF/D2H/Macros/config_cutvar_example.json +++ b/PWGHF/D2H/Macros/config_cutvar_example.json @@ -62,14 +62,16 @@ "frac": false, "eff": false, "cov": false, - "unc": true + "unc": true, + "relunc": true }, "is_save_canvas_as_macro": { "rawy": false, "frac": false, "eff": false, "cov": false, - "unc": false + "unc": false, + "relunc": false }, "is_save_to_root_file": { "canvas": true, @@ -95,5 +97,8 @@ "output": { "directory": ".", "file": "CutVarDplus_pp13TeV_MB.root" - } + }, + "zero_eff_unc": false, + "effp_shift_nsigma": 0, + "effnp_shift_nsigma": 0 } diff --git a/PWGHF/D2H/Macros/cut_variation.py b/PWGHF/D2H/Macros/cut_variation.py index 6d45ac25607..8a6c31a96b4 100644 --- a/PWGHF/D2H/Macros/cut_variation.py +++ b/PWGHF/D2H/Macros/cut_variation.py @@ -8,13 +8,15 @@ """ import sys +from enum import IntEnum, auto import numpy as np # pylint: disable=import-error import ROOT # pylint: disable=import-error -from enum import IntEnum, auto + sys.path.insert(0, '..') from style_formatter import set_global_style, set_object_style + class MinimisationStatus(IntEnum): Undefined = 0 Success = auto() @@ -46,13 +48,26 @@ class CutVarMinimiser: def __init__( # pylint: disable=too-many-arguments self, - raw_yields=np.zeros(0), - eff_prompt=np.zeros(0), - eff_nonprompt=np.zeros(0), - unc_raw_yields=np.zeros(0), - unc_eff_prompt=np.zeros(0), - unc_eff_nonprompt=np.zeros(0), + raw_yields=None, + eff_prompt=None, + eff_nonprompt=None, + unc_raw_yields=None, + unc_eff_prompt=None, + unc_eff_nonprompt=None, ): + if raw_yields is None: + raw_yields = np.zeros(0) + if eff_prompt is None: + eff_prompt = np.zeros(0) + if eff_nonprompt is None: + eff_nonprompt = np.zeros(0) + if unc_raw_yields is None: + unc_raw_yields = np.zeros(0) + if unc_eff_prompt is None: + unc_eff_prompt = np.zeros(0) + if unc_eff_nonprompt is None: + unc_eff_nonprompt = np.zeros(0) + self.raw_yields = raw_yields self.eff_prompt = eff_prompt self.eff_nonprompt = eff_nonprompt @@ -161,17 +176,10 @@ def minimise_system(self, correlated=True, precision=1.0e-8, max_iterations=100) ) if correlated and unc_row > 0 and unc_col > 0: - if unc_row < unc_col: - rho = unc_row / unc_col - else: - rho = unc_col / unc_row + self.m_cov_sets[i_row, i_col] = min(unc_row **2, unc_col ** 2) else: - if i_row == i_col: - rho = 1.0 - else: - rho = 0.0 - cov_row_col = rho * unc_row * unc_col - self.m_cov_sets[i_row, i_col] = cov_row_col + self.m_cov_sets[i_row, i_col] = unc_row ** 2 if i_row == i_col else 0.0 + self.m_cov_sets = np.matrix(self.m_cov_sets) try: @@ -580,7 +588,8 @@ def plot_result(self, suffix="", title=""): hist_raw_yield_sum.Draw("histsame") tex = ROOT.TLatex() tex.SetTextSize(0.04) - tex.DrawLatexNDC(0.05, 0.95, title) + tex.SetTextAlign(31) + tex.DrawLatexNDC(0.95, 0.95, title) canvas.Modified() canvas.Update() @@ -636,22 +645,17 @@ def plot_cov_matrix(self, correlated=True, suffix="", title=""): for i_row, unc_row in enumerate(self.unc_raw_yields): for i_col, unc_col in enumerate(self.unc_raw_yields): if correlated and unc_row > 0 and unc_col > 0: - if unc_row < unc_col: - rho = unc_row / unc_col - else: - rho = unc_col / unc_row + rho = min(unc_row / unc_col, unc_col / unc_row) else: - if i_row == i_col: - rho = 1.0 - else: - rho = 0.0 + rho = 1.0 if i_row == i_col else 0.0 hist_corr_matrix.SetBinContent(i_row + 1, i_col + 1, rho) canvas = ROOT.TCanvas(f"cCorrMatrixCutSets{suffix}", "", 500, 500) hist_corr_matrix.Draw("colz") tex = ROOT.TLatex() tex.SetTextSize(0.04) - tex.DrawLatexNDC(0.05, 0.95, title) + tex.SetTextAlign(31) + tex.DrawLatexNDC(0.95, 0.95, title) canvas.Modified() canvas.Update() @@ -743,7 +747,8 @@ def plot_efficiencies(self, suffix="", title=""): leg.Draw() tex = ROOT.TLatex() tex.SetTextSize(0.04) - tex.DrawLatexNDC(0.05, 0.95, title) + tex.SetTextAlign(31) + tex.DrawLatexNDC(0.95, 0.95, title) canvas.Modified() canvas.Update() @@ -828,7 +833,8 @@ def plot_fractions(self, suffix="", title=""): leg.Draw() tex = ROOT.TLatex() tex.SetTextSize(0.04) - tex.DrawLatexNDC(0.05, 0.95, title) + tex.SetTextAlign(31) + tex.DrawLatexNDC(0.95, 0.95, title) canvas.Modified() canvas.Update() @@ -905,7 +911,8 @@ def plot_uncertainties(self, suffix="", title=""): hist_residual_unc.Draw("histsame") tex = ROOT.TLatex() tex.SetTextSize(0.04) - tex.DrawLatexNDC(0.05, 0.95, title) + tex.SetTextAlign(31) + tex.DrawLatexNDC(0.95, 0.95, title) canvas.Modified() canvas.Update() @@ -915,3 +922,97 @@ def plot_uncertainties(self, suffix="", title=""): } return canvas, histos, leg + + + # pylint: disable=no-member + def plot_relative_uncertainties(self, suffix="", title=""): + """ + Helper function to plot uncertainties as a function of cut set + + Parameters + ----------------------------------------------------- + - suffix: str + suffix to be added in the name of the output objects + - title: str + title to be written at the top margin of the output objects + + Returns + ----------------------------------------------------- + - canvas: ROOT.TCanvas + canvas with plot + - histos: dict + dictionary of ROOT.TH1F with relative uncertainties distributions + for raw yield and efficiencies + - leg: ROOT.TLegend + needed otherwise it is destroyed + """ + suffix = suffix.replace(".", "_") + + set_global_style(padleftmargin=0.16, padbottommargin=0.12, padtopmargin=0.075, titleoffsety=1.6) + + hist_raw_yield_rel_unc = ROOT.TH1F( + f"hRawYieldRelUncVsCut{suffix}", + ";cut set;relative unc.", + self.n_sets, + -0.5, + self.n_sets - 0.5, + ) + + hist_eff_prompt_rel_unc = ROOT.TH1F( + f"hEffPromptRelUncVsCut{suffix}", + ";cut set;relative unc.", + self.n_sets, + -0.5, + self.n_sets - 0.5, + ) + + hist_eff_nonprompt_rel_unc = ROOT.TH1F( + f"hEffNonPromptRelUncVsCut{suffix}", + ";cut set;relative unc.", + self.n_sets, + -0.5, + self.n_sets - 0.5, + ) + + for i_bin, (unc_rawy, rawy, unc_eff_prompt, eff_prompt, unc_eff_nonprompt, eff_nonprompt) in enumerate(zip(self.unc_raw_yields, self.raw_yields, self.unc_eff_prompt, self.eff_prompt, self.unc_eff_nonprompt, self.eff_nonprompt)): + hist_raw_yield_rel_unc.SetBinContent(i_bin + 1, unc_rawy / rawy) + hist_eff_prompt_rel_unc.SetBinContent(i_bin+1, unc_eff_prompt / eff_prompt) + hist_eff_nonprompt_rel_unc.SetBinContent(i_bin+1, unc_eff_nonprompt / eff_nonprompt) + + set_object_style(hist_raw_yield_rel_unc, color=ROOT.kBlack, fillstyle=0) + set_object_style(hist_eff_prompt_rel_unc, color=ROOT.kRed + 1, fillstyle=0) + set_object_style(hist_eff_nonprompt_rel_unc, color=ROOT.kAzure + 4, fillstyle=0) + + canvas = ROOT.TCanvas(f"cRelUncVsCut{suffix}", "", 500, 500) + canvas.DrawFrame( + -0.5, + 0.0, + self.n_sets - 0.5, + max(hist_raw_yield_rel_unc.GetMaximum(), hist_eff_prompt_rel_unc.GetMaximum(), hist_eff_nonprompt_rel_unc.GetMaximum()) * 1.2, + ";cut set;relative unc.", + ) + leg = ROOT.TLegend(0.2, 0.75, 0.4, 0.85) + leg.SetBorderSize(0) + leg.SetFillStyle(0) + leg.SetTextSize(0.04) + leg.AddEntry(hist_raw_yield_rel_unc, "raw yield", "l") + leg.AddEntry(hist_eff_prompt_rel_unc, "efficiency prompt", "l") + leg.AddEntry(hist_eff_nonprompt_rel_unc, "efficiency nonprompt", "l") + leg.Draw() + hist_raw_yield_rel_unc.Draw("histsame") + hist_eff_prompt_rel_unc.Draw("histsame") + hist_eff_nonprompt_rel_unc.Draw("histsame") + tex = ROOT.TLatex() + tex.SetTextSize(0.04) + tex.SetTextAlign(31) + tex.DrawLatexNDC(0.95, 0.95, title) + canvas.Modified() + canvas.Update() + + histos = { + "rawy": hist_raw_yield_rel_unc, + "prompt": hist_eff_prompt_rel_unc, + "nonprompt": hist_eff_nonprompt_rel_unc + } + + return canvas, histos, leg diff --git a/PWGHF/D2H/TableProducer/CMakeLists.txt b/PWGHF/D2H/TableProducer/CMakeLists.txt index 5a725c4623b..3492a98acff 100644 --- a/PWGHF/D2H/TableProducer/CMakeLists.txt +++ b/PWGHF/D2H/TableProducer/CMakeLists.txt @@ -63,6 +63,13 @@ o2physics_add_dpl_workflow(candidate-selector-lb-to-lc-pi-reduced PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore COMPONENT_NAME Analysis) +# Track selectors + +o2physics_add_dpl_workflow(ml-based-track-selector + SOURCES mlBasedTrackSelector.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsVertexing O2::DCAFitter O2Physics::AnalysisCCDB O2Physics::MLCore O2Physics::SGCutParHolder O2Physics::EventFilteringUtils + COMPONENT_NAME Analysis) + # Data creators o2physics_add_dpl_workflow(data-creator-charm-had-pi-reduced diff --git a/PWGHF/D2H/TableProducer/candidateCreatorBToJpsiReduced.cxx b/PWGHF/D2H/TableProducer/candidateCreatorBToJpsiReduced.cxx index e1db941ad9b..7d2b84ddf8a 100644 --- a/PWGHF/D2H/TableProducer/candidateCreatorBToJpsiReduced.cxx +++ b/PWGHF/D2H/TableProducer/candidateCreatorBToJpsiReduced.cxx @@ -36,7 +36,6 @@ #include #include #include -#include #include #include diff --git a/PWGHF/D2H/TableProducer/candidateSelectorB0ToDPiReduced.cxx b/PWGHF/D2H/TableProducer/candidateSelectorB0ToDPiReduced.cxx index 3913e7f0fca..89299a0136c 100644 --- a/PWGHF/D2H/TableProducer/candidateSelectorB0ToDPiReduced.cxx +++ b/PWGHF/D2H/TableProducer/candidateSelectorB0ToDPiReduced.cxx @@ -20,11 +20,13 @@ #include "PWGHF/Core/SelectorCuts.h" #include "PWGHF/D2H/DataModel/ReducedDataModel.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" #include "PWGHF/Utils/utilsPid.h" #include "Common/Core/TrackSelectorPID.h" #include +#include #include #include #include @@ -92,6 +94,7 @@ struct HfCandidateSelectorB0ToDPiReduced { Configurable> onnxFileNames{"onnxFileNames", std::vector{"ModelHandler_onnx_B0ToDPi.onnx"}, "ONNX file names for each pT bin (if not from CCDB full path)"}; Configurable timestampCCDB{"timestampCCDB", -1, "timestamp of the ONNX file for ML model used to query in CCDB"}; Configurable loadModelsFromCCDB{"loadModelsFromCCDB", false, "Flag to enable or disable the loading of models from CCDB"}; + Configurable useDplusTriggerMassCut{"useDplusTriggerMassCut", false, "Flag to enable parametrize pT differential mass cut for triggered data"}; // variable that will store the value of selectionFlagD (defined in dataCreatorDplusPiReduced.cxx) int mySelectionFlagD = -1; @@ -101,6 +104,7 @@ struct HfCandidateSelectorB0ToDPiReduced { o2::ccdb::CcdbApi ccdbApi; TrackSelectorPi selectorPion; + HfTrigger3ProngCuts hfTriggerCuts; using TracksBachPion = soa::Join; using TracksSoftPions = soa::Join; @@ -118,6 +122,10 @@ struct HfCandidateSelectorB0ToDPiReduced { LOGP(fatal, "Invalid PID option in configurable, please set 0 (no PID), 1 (TPC or TOF), or 2 (TPC and TOF)"); } + if (useDplusTriggerMassCut && (doprocessSelectionDstarPi || doprocessSelectionDstarPiWithDmesMl)) { + LOGP(fatal, "useDplusTriggerMassCut has no effect in the D*-pi channel. Please set it to false."); + } + if (pionPidMethod != PidMethod::NoPid) { selectorPion.setRangePtTpc(ptPidTpcMin, ptPidTpcMax); selectorPion.setRangeNSigmaTpc(-nSigmaTpcMax, nSigmaTpcMax); @@ -190,6 +198,28 @@ struct HfCandidateSelectorB0ToDPiReduced { return candidate.template prong1_as(); } + /// Utility function to apply the pT-differential mass cut for triggered data + /// on the D meson daughter of the B0 candidate + /// \param candidate is the B0 candidate + /// \return true if the D daughter passes the mass selection + /// \note the cut is parametrised for the D+ meson, hence it is not applied in the D*-pi channel + template + bool isDmesInMassRange(const T1& /*candidate*/) + { + return true; + } + + /// Utility function to apply the pT-differential mass cut for triggered data + /// on the D- daughter of the B0 candidate in the D-pi decay channel + /// \param candidate is the B0 candidate + /// \return true if the D- daughter passes the mass selection + template + bool isDmesInMassRange(const T1& candidate) + { + const auto candD = candidate.template prong0_as(); + return isCandidateInMassRange(candD.invMassHypo0(), o2::constants::physics::MassDPlus, candidate.ptProng0(), hfTriggerCuts); + } + /// Method to get the input features vector needed for ML inference /// \param candB0 is the B0 candidate /// \param prongBachPi is the candidate's bachelor pion prong @@ -238,6 +268,16 @@ struct HfCandidateSelectorB0ToDPiReduced { continue; } + // pT-differential mass cut on the D daughter for triggered data + if (useDplusTriggerMassCut && !isDmesInMassRange(hfCandB0)) { + hfSelB0ToDPiCandidate(statusB0ToDPi); + if (applyB0Ml) { + hfMlB0ToDPiCandidate(outputMlNotPreselected); + } + // LOGF(info, "B0 candidate selection failed at D-meson mass selection"); + continue; + } + if constexpr (WithDmesMl) { // we include it in the topological selections if (!HfHelper::selectionDmesMlScoresForBReduced(hfCandB0, cutsDmesMl, binsPtDmesMl)) { hfSelB0ToDPiCandidate(statusB0ToDPi); @@ -298,7 +338,8 @@ struct HfCandidateSelectorB0ToDPiReduced { void processSelectionDplusPi(HfRedCandB0 const& hfCandsB0, TracksBachPion const& pionTracks, - HfCandB0Configs const& configs) + HfCandB0Configs const& configs, + HfRed3Prongs const& /*candsD*/) { runSelection(hfCandsB0, pionTracks, configs); } // processSelectionDplusPi @@ -307,7 +348,8 @@ struct HfCandidateSelectorB0ToDPiReduced { void processSelectionDplusPiWithDmesMl(soa::Join const& hfCandsB0, TracksBachPion const& pionTracks, - HfCandB0Configs const& configs) + HfCandB0Configs const& configs, + HfRed3Prongs const& /*candsD*/) { runSelection(hfCandsB0, pionTracks, configs); } // processSelectionDplusPiWithDmesMl diff --git a/PWGHF/D2H/TableProducer/dataCreatorCharmHadPiReduced.cxx b/PWGHF/D2H/TableProducer/dataCreatorCharmHadPiReduced.cxx index 880fd3f62e5..6f429084a95 100644 --- a/PWGHF/D2H/TableProducer/dataCreatorCharmHadPiReduced.cxx +++ b/PWGHF/D2H/TableProducer/dataCreatorCharmHadPiReduced.cxx @@ -37,6 +37,7 @@ #include "Common/DataModel/Centrality.h" #include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/Qvectors.h" @@ -244,7 +245,7 @@ struct HfDataCreatorCharmHadPiReduced { using CandsDstarFiltered = soa::Filtered>; using CandsDstarFilteredWithMl = soa::Filtered>; - using CollisionsWCent = soa::Join; + using CollisionsWCent = soa::Join; using CollisionsWCentAndMcLabels = soa::Join; using CollisionsWCentAndQvectors = soa::Join; using BCsInfo = soa::Join; @@ -488,7 +489,7 @@ struct HfDataCreatorCharmHadPiReduced { const PParticles& particlesMc, const std::vector& vecDaughtersB, int& indexHfCandCharm, - std::map selectedTracksPion, + const std::map& selectedTracksPion, const int64_t indexCollisionMaxNumContrib) { @@ -619,7 +620,7 @@ struct HfDataCreatorCharmHadPiReduced { } tables.rowHfDPiMcCheckReduced(pdgCodeBeautyMother, pdgCodeCharmMother, pdgCodeProng0, pdgCodeProng1, pdgCodeProng2, pdgCodeProng3); } - tables.rowHfDPiMcRecReduced(indexHfCandCharm, selectedTracksPion[vecDaughtersB.back().globalIndex()], flag, flagWrongCollision, debug, motherPt); + tables.rowHfDPiMcRecReduced(indexHfCandCharm, selectedTracksPion.at(vecDaughtersB.back().globalIndex()), flag, flagWrongCollision, debug, motherPt); } else if constexpr (DecChannel == DecayChannel::BsToDsminusPi) { // Bs → Ds- π+ → (K- K+ π-) π+ auto indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2], vecDaughtersB[3]}, Pdg::kBS, std::array{-kKPlus, +kKPlus, -kPiPlus, +kPiPlus}, true, &sign, 3); @@ -774,7 +775,7 @@ struct HfDataCreatorCharmHadPiReduced { } tables.rowHfDsPiMcCheckReduced(pdgCodeBeautyMother, pdgCodeCharmMother, pdgCodeProng0, pdgCodeProng1, pdgCodeProng2, pdgCodeProng3); } - tables.rowHfDsPiMcRecReduced(indexHfCandCharm, selectedTracksPion[vecDaughtersB.back().globalIndex()], flag, flagWrongCollision, debug, motherPt); + tables.rowHfDsPiMcRecReduced(indexHfCandCharm, selectedTracksPion.at(vecDaughtersB.back().globalIndex()), flag, flagWrongCollision, debug, motherPt); } else if constexpr (DecChannel == DecayChannel::BplusToD0barPi) { // B+ → D0(bar) π+ → (K+ π-) π+ auto indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2]}, Pdg::kBPlus, std::array{+kPiPlus, +kKPlus, -kPiPlus}, true, &sign, 2); @@ -871,7 +872,7 @@ struct HfDataCreatorCharmHadPiReduced { } tables.rowHfD0PiMcCheckReduced(pdgCodeBeautyMother, pdgCodeCharmMother, pdgCodeProng0, pdgCodeProng1, pdgCodeProng2); } - tables.rowHfD0PiMcRecReduced(indexHfCandCharm, selectedTracksPion[vecDaughtersB.back().globalIndex()], flag, flagWrongCollision, debug, motherPt); + tables.rowHfD0PiMcRecReduced(indexHfCandCharm, selectedTracksPion.at(vecDaughtersB.back().globalIndex()), flag, flagWrongCollision, debug, motherPt); } else if constexpr (DecChannel == DecayChannel::LbToLcplusPi) { // Lb → Lc+ π- → (p K- π+) π- auto indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2], vecDaughtersB[3]}, Pdg::kLambdaB0, std::array{+kProton, -kKPlus, +kPiPlus, -kPiPlus}, true, &sign, 3); @@ -975,7 +976,7 @@ struct HfDataCreatorCharmHadPiReduced { } tables.rowHfLcPiMcCheckReduced(pdgCodeBeautyMother, pdgCodeCharmMother, pdgCodeProng0, pdgCodeProng1, pdgCodeProng2, pdgCodeProng3); } - tables.rowHfLcPiMcRecReduced(indexHfCandCharm, selectedTracksPion[vecDaughtersB.back().globalIndex()], flag, flagWrongCollision, debug, motherPt); + tables.rowHfLcPiMcRecReduced(indexHfCandCharm, selectedTracksPion.at(vecDaughtersB.back().globalIndex()), flag, flagWrongCollision, debug, motherPt); } else if constexpr (DecChannel == DecayChannel::B0ToDstarPi) { // B0 → D*+ π- → (D0 π+) π- → (K- π+ π+) π- auto indexRec = RecoDecay::getMatchedMCRec(particlesMc, std::array{vecDaughtersB[0], vecDaughtersB[1], vecDaughtersB[2], vecDaughtersB[3]}, Pdg::kB0, std::array{+kKPlus, -kPiPlus, -kPiPlus, +kPiPlus}, true, &sign, 4); @@ -1012,7 +1013,7 @@ struct HfDataCreatorCharmHadPiReduced { checkWrongCollision(particleMother, collision, indexCollisionMaxNumContrib, flagWrongCollision); } } - tables.rowHfDStarPiMcRecReduced(indexHfCandCharm, selectedTracksPion[vecDaughtersB.back().globalIndex()], flag, flagWrongCollision, debug, motherPt); + tables.rowHfDStarPiMcRecReduced(indexHfCandCharm, selectedTracksPion.at(vecDaughtersB.back().globalIndex()), flag, flagWrongCollision, debug, motherPt); } } @@ -1379,7 +1380,10 @@ struct HfDataCreatorCharmHadPiReduced { if constexpr (WithMl) { std::array mlScores = {-1.f, -1.f, -1.f, -1.f, -1.f, -1.f}; if constexpr (DecChannel == DecayChannel::B0ToDminusPi) { - tables.hfCand3ProngMl(candC.mlProbDplusToPiKPi()[0], candC.mlProbDplusToPiKPi()[1], candC.mlProbDplusToPiKPi()[2], -1., -1., -1.); + if (candC.mlProbDplusToPiKPi().size() == NSizeMLScore) { + std::copy(candC.mlProbDplusToPiKPi().begin(), candC.mlProbDplusToPiKPi().end(), mlScores.begin()); + } + tables.hfCand3ProngMl(mlScores[0], mlScores[1], mlScores[2], -1., -1., -1.); } else if constexpr (DecChannel == DecayChannel::BsToDsminusPi) { if (candC.mlProbDsToKKPi().size() == NSizeMLScore) { std::copy(candC.mlProbDsToKKPi().begin(), candC.mlProbDsToKKPi().end(), mlScores.begin()); @@ -1444,7 +1448,7 @@ struct HfDataCreatorCharmHadPiReduced { tables.hfCandPidProng1(candC.nSigTpcPi1(), candC.nSigTofPi1(), candC.nSigTpcKa1(), candC.nSigTofKa1(), nSigmaTpcPr1, nSigmaTofPr1, charmHadDauTracks[1].hasTOF(), charmHadDauTracks[1].hasTPC()); // Soft pion tables - auto trackSoftPion = charmHadDauTracks.back(); + const auto& trackSoftPion = charmHadDauTracks.back(); auto trackParCovSoftPion = getTrackParCov(trackSoftPion); std::array dcaSoftPion{trackSoftPion.dcaXY(), trackSoftPion.dcaZ()}; std::array pVecSoftPion = trackSoftPion.pVector(); diff --git a/PWGHF/D2H/TableProducer/dataCreatorCharmResoToD0Reduced.cxx b/PWGHF/D2H/TableProducer/dataCreatorCharmResoToD0Reduced.cxx index 6526044e6d2..c993fbda899 100644 --- a/PWGHF/D2H/TableProducer/dataCreatorCharmResoToD0Reduced.cxx +++ b/PWGHF/D2H/TableProducer/dataCreatorCharmResoToD0Reduced.cxx @@ -28,6 +28,7 @@ #include "Common/Core/ZorroSummary.h" #include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -133,7 +134,7 @@ struct HfDataCreatorCharmResoToD0Reduced { using TracksIUWithPIDAndMC = soa::Join; // Collisions MC using BCsInfo = soa::Join; - using McCollisionsNoCents = soa::Join; + using McCollisionsNoCents = soa::Join; Filter filterSelectD0Candidates = (aod::hf_sel_candidate_d0::isSelD0 >= cfgDmesCuts.selectionFlagD0 || aod::hf_sel_candidate_d0::isSelD0bar >= cfgDmesCuts.selectionFlagD0Bar); @@ -193,7 +194,7 @@ struct HfDataCreatorCharmResoToD0Reduced { // Process functions // No ML // Data - void processD0V0(soa::Join const& collisions, + void processD0V0(soa::Join const& collisions, CandsD0Filtered const& candsD0, aod::V0s const& v0s, TracksIUWithPID const& tracksIU, @@ -221,14 +222,14 @@ struct HfDataCreatorCharmResoToD0Reduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsD0.sliceBy(candsD0PerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, dummyTable, dummyTable, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, dummyTable, dummyTable, dummyTable, dummyTable); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } PROCESS_SWITCH(HfDataCreatorCharmResoToD0Reduced, processD0V0, "Process D0 candidates paired with V0s", false); - void processD0Track(soa::Join const& collisions, + void processD0Track(soa::Join const& collisions, CandsD0Filtered const& candsD0, aod::TrackAssoc const& trackIndices, TracksWithPID const& tracks, @@ -256,14 +257,14 @@ struct HfDataCreatorCharmResoToD0Reduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsD0.sliceBy(candsD0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, dummyTable, hfTrackNoParam, dummyTable, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, dummyTable, hfTrackNoParam, dummyTable, dummyTable, dummyTable); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } PROCESS_SWITCH(HfDataCreatorCharmResoToD0Reduced, processD0Track, "Process D0 candidates paired with Tracks", false); - void processD0V0AndTrack(soa::Join const& collisions, + void processD0V0AndTrack(soa::Join const& collisions, CandsD0Filtered const& candsD0, aod::V0s const& v0s, aod::TrackAssoc const& trackIndices, @@ -294,7 +295,7 @@ struct HfDataCreatorCharmResoToD0Reduced { auto candsDThisColl = candsD0.sliceBy(candsD0PerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, dummyTable); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -303,7 +304,7 @@ struct HfDataCreatorCharmResoToD0Reduced { // ML // Data - void processD0V0WithMl(soa::Join const& collisions, + void processD0V0WithMl(soa::Join const& collisions, CandsD0FilteredWithMl const& candsD0, aod::V0s const& v0s, TracksIUWithPID const& tracksIU, @@ -331,14 +332,14 @@ struct HfDataCreatorCharmResoToD0Reduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsD0.sliceBy(candsD0PerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, dummyTable, dummyTable, dummyTable, hfCandD2PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, dummyTable, dummyTable, dummyTable, hfCandD2PrMl); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } PROCESS_SWITCH(HfDataCreatorCharmResoToD0Reduced, processD0V0WithMl, "Process D0 candidates paired with V0s with ML info", false); - void processD0GammaWithMl(soa::Join const& collisions, + void processD0GammaWithMl(soa::Join const& collisions, CandsD0FilteredWithMl const& candsD0, aod::V0s const& v0s, TracksIUWithElPID const& tracksIU, @@ -366,14 +367,14 @@ struct HfDataCreatorCharmResoToD0Reduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsD0.sliceBy(candsD0PerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, dummyTable, dummyTable, dummyTable, hfCandD2PrMl, &vDriftMgr); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, dummyTable, dummyTable, dummyTable, hfCandD2PrMl, &vDriftMgr); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } PROCESS_SWITCH(HfDataCreatorCharmResoToD0Reduced, processD0GammaWithMl, "Process D0 candidates paired with gammas with ML info", false); - void processD0TrackWithMl(soa::Join const& collisions, + void processD0TrackWithMl(soa::Join const& collisions, CandsD0FilteredWithMl const& candsD0, aod::TrackAssoc const& trackIndices, TracksWithPID const& tracks, @@ -401,14 +402,14 @@ struct HfDataCreatorCharmResoToD0Reduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsD0.sliceBy(candsD0PerCollisionWithMl, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, dummyTable, hfTrackNoParam, dummyTable, dummyTable, hfCandD2PrMl); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, dummyTable, hfTrackNoParam, dummyTable, dummyTable, hfCandD2PrMl); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } PROCESS_SWITCH(HfDataCreatorCharmResoToD0Reduced, processD0TrackWithMl, "Process D0 candidates paired with Tracks with ML info", false); - void processD0V0AndTrackWithMl(soa::Join const& collisions, + void processD0V0AndTrackWithMl(soa::Join const& collisions, CandsD0FilteredWithMl const& candsD0, aod::V0s const& v0s, aod::TrackAssoc const& trackIndices, @@ -439,7 +440,7 @@ struct HfDataCreatorCharmResoToD0Reduced { auto candsDThisColl = candsD0.sliceBy(candsD0PerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, hfCandD2PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, hfCandD2PrMl); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -448,7 +449,7 @@ struct HfDataCreatorCharmResoToD0Reduced { // MC // No ML - void processD0V0MC(soa::Join const& collisions, + void processD0V0MC(soa::Join const& collisions, CandsD0FilteredWithMc const& candsD0, aod::V0s const& v0s, TracksIUWithPIDAndMC const& tracksIU, @@ -479,7 +480,7 @@ struct HfDataCreatorCharmResoToD0Reduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsD0.sliceBy(candsD0PerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, dummyTable, rowHf2PrV0McRecReduced, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, dummyTable, rowHf2PrV0McRecReduced, dummyTable, dummyTable); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -487,7 +488,7 @@ struct HfDataCreatorCharmResoToD0Reduced { } PROCESS_SWITCH(HfDataCreatorCharmResoToD0Reduced, processD0V0MC, "Process D0 candidates paired with V0s with MC matching", false); - void processD0TrackMC(soa::Join const& collisions, + void processD0TrackMC(soa::Join const& collisions, CandsD0FilteredWithMc const& candsD0, TracksWithPIDAndMC const& tracks, aod::TrackAssoc const& trackIndices, @@ -518,7 +519,7 @@ struct HfDataCreatorCharmResoToD0Reduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsD0.sliceBy(candsD0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, dummyTable, hfTrackNoParam, dummyTable, rowHf2PrTrkMcRecReduced, dummyTable); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, dummyTable, hfTrackNoParam, dummyTable, rowHf2PrTrkMcRecReduced, dummyTable); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -526,7 +527,7 @@ struct HfDataCreatorCharmResoToD0Reduced { } PROCESS_SWITCH(HfDataCreatorCharmResoToD0Reduced, processD0TrackMC, "Process D0 candidates paired with tracks with MC matching", false); - void processD0V0AndTrackMC(soa::Join const& collisions, + void processD0V0AndTrackMC(soa::Join const& collisions, CandsD0FilteredWithMc const& candsD0, aod::V0s const& v0s, aod::TrackAssoc const& trackIndices, @@ -560,7 +561,7 @@ struct HfDataCreatorCharmResoToD0Reduced { auto candsDThisColl = candsD0.sliceBy(candsD0PerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, hfTrackNoParam, rowHf2PrV0McRecReduced, rowHf2PrTrkMcRecReduced, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, hfTrackNoParam, rowHf2PrV0McRecReduced, rowHf2PrTrkMcRecReduced, dummyTable); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -569,7 +570,7 @@ struct HfDataCreatorCharmResoToD0Reduced { PROCESS_SWITCH(HfDataCreatorCharmResoToD0Reduced, processD0V0AndTrackMC, "Process D0 candidates paired with V0s and tracks with MC matching", false); // ML - void processD0V0MCWithMl(soa::Join const& collisions, + void processD0V0MCWithMl(soa::Join const& collisions, CandsD0FilteredWithMlAndMc const& candsD0, aod::V0s const& v0s, TracksIUWithPIDAndMC const& tracksIU, @@ -600,7 +601,7 @@ struct HfDataCreatorCharmResoToD0Reduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsD0.sliceBy(candsD0PerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, dummyTable, rowHf2PrV0McRecReduced, dummyTable, hfCandD2PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, dummyTable, rowHf2PrV0McRecReduced, dummyTable, hfCandD2PrMl); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -608,7 +609,7 @@ struct HfDataCreatorCharmResoToD0Reduced { } PROCESS_SWITCH(HfDataCreatorCharmResoToD0Reduced, processD0V0MCWithMl, "Process D0 candidates paired with V0s with MC matching and with ML info", false); - void processD0TrackMCWithMl(soa::Join const& collisions, + void processD0TrackMCWithMl(soa::Join const& collisions, CandsD0FilteredWithMlAndMc const& candsD0, TracksWithPIDAndMC const& tracks, aod::TrackAssoc const& trackIndices, @@ -639,7 +640,7 @@ struct HfDataCreatorCharmResoToD0Reduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsD0.sliceBy(candsD0PerCollisionWithMl, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, dummyTable, hfTrackNoParam, dummyTable, rowHf2PrTrkMcRecReduced, hfCandD2PrMl); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, dummyTable, hfTrackNoParam, dummyTable, rowHf2PrTrkMcRecReduced, hfCandD2PrMl); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -647,7 +648,7 @@ struct HfDataCreatorCharmResoToD0Reduced { } PROCESS_SWITCH(HfDataCreatorCharmResoToD0Reduced, processD0TrackMCWithMl, "Process D0 candidates paired with tracks with MC matching and with ML info", false); - void processD0V0AndTrackMCWithMl(soa::Join const& collisions, + void processD0V0AndTrackMCWithMl(soa::Join const& collisions, CandsD0FilteredWithMlAndMc const& candsD0, aod::V0s const& v0s, aod::TrackAssoc const& trackIndices, @@ -680,7 +681,7 @@ struct HfDataCreatorCharmResoToD0Reduced { auto candsDThisColl = candsD0.sliceBy(candsD0PerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, hfTrackNoParam, rowHf2PrV0McRecReduced, rowHf2PrTrkMcRecReduced, hfCandD2PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgGammaCuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD2Pr, hfCandV0, hfTrackNoParam, rowHf2PrV0McRecReduced, rowHf2PrTrkMcRecReduced, hfCandD2PrMl); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions diff --git a/PWGHF/D2H/TableProducer/dataCreatorCharmResoToDplusReduced.cxx b/PWGHF/D2H/TableProducer/dataCreatorCharmResoToDplusReduced.cxx index 71c1f6b49cc..79505392ace 100644 --- a/PWGHF/D2H/TableProducer/dataCreatorCharmResoToDplusReduced.cxx +++ b/PWGHF/D2H/TableProducer/dataCreatorCharmResoToDplusReduced.cxx @@ -27,6 +27,7 @@ #include "Common/Core/ZorroSummary.h" #include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -128,7 +129,7 @@ struct HfDataCreatorCharmResoToDplusReduced { using TracksIUWithPIDAndMC = soa::Join; // Collisions MC using BCsInfo = soa::Join; - using McCollisionsNoCents = soa::Join; + using McCollisionsNoCents = soa::Join; Filter filterSelectDplus = (aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= cfgDmesCuts.selectionFlagDplus); @@ -187,7 +188,7 @@ struct HfDataCreatorCharmResoToDplusReduced { // Process functions // No ML // Data - void processDplusV0(soa::Join const& collisions, + void processDplusV0(soa::Join const& collisions, CandsDplusFiltered const& candsDplus, aod::V0s const& v0s, TracksIUWithPID const& tracksIU, @@ -215,14 +216,14 @@ struct HfDataCreatorCharmResoToDplusReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, dummyTable, dummyTable, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, dummyTable, dummyTable, dummyTable, dummyTable); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } PROCESS_SWITCH(HfDataCreatorCharmResoToDplusReduced, processDplusV0, "Process Dplus candidates paired with V0s", false); - void processDplusTrack(soa::Join const& collisions, + void processDplusTrack(soa::Join const& collisions, CandsDplusFiltered const& candsDplus, aod::TrackAssoc const& trackIndices, TracksWithPID const& tracks, @@ -250,14 +251,14 @@ struct HfDataCreatorCharmResoToDplusReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, dummyTable, hfTrackNoParam, dummyTable, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, dummyTable, hfTrackNoParam, dummyTable, dummyTable, dummyTable); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } PROCESS_SWITCH(HfDataCreatorCharmResoToDplusReduced, processDplusTrack, "Process Dplus candidates paired with Tracks", false); - void processDplusV0AndTrack(soa::Join const& collisions, + void processDplusV0AndTrack(soa::Join const& collisions, CandsDplusFiltered const& candsDplus, aod::V0s const& v0s, aod::TrackAssoc const& trackIndices, @@ -288,7 +289,7 @@ struct HfDataCreatorCharmResoToDplusReduced { auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, dummyTable); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -297,7 +298,7 @@ struct HfDataCreatorCharmResoToDplusReduced { // ML // Data - void processDplusV0WithMl(soa::Join const& collisions, + void processDplusV0WithMl(soa::Join const& collisions, CandsDplusFilteredWithMl const& candsDplus, aod::V0s const& v0s, TracksIUWithPID const& tracksIU, @@ -325,14 +326,14 @@ struct HfDataCreatorCharmResoToDplusReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, dummyTable, dummyTable, dummyTable, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, dummyTable, dummyTable, dummyTable, hfCandD3PrMl); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } PROCESS_SWITCH(HfDataCreatorCharmResoToDplusReduced, processDplusV0WithMl, "Process Dplus candidates paired with V0s with ML info", false); - void processDplusTrackWithMl(soa::Join const& collisions, + void processDplusTrackWithMl(soa::Join const& collisions, CandsDplusFilteredWithMl const& candsDplus, aod::TrackAssoc const& trackIndices, TracksWithPID const& tracks, @@ -360,14 +361,14 @@ struct HfDataCreatorCharmResoToDplusReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollisionWithMl, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, dummyTable, hfTrackNoParam, dummyTable, dummyTable, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, dummyTable, hfTrackNoParam, dummyTable, dummyTable, hfCandD3PrMl); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } PROCESS_SWITCH(HfDataCreatorCharmResoToDplusReduced, processDplusTrackWithMl, "Process Dplus candidates paired with Tracks with ML info", false); - void processDplusV0AndTrackWithMl(soa::Join const& collisions, + void processDplusV0AndTrackWithMl(soa::Join const& collisions, CandsDplusFilteredWithMl const& candsDplus, aod::V0s const& v0s, aod::TrackAssoc const& trackIndices, @@ -398,7 +399,7 @@ struct HfDataCreatorCharmResoToDplusReduced { auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, hfCandD3PrMl); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -406,7 +407,7 @@ struct HfDataCreatorCharmResoToDplusReduced { PROCESS_SWITCH(HfDataCreatorCharmResoToDplusReduced, processDplusV0AndTrackWithMl, "Process Dplus candidates paired with V0s and Tracks with ML info", false); // Dplus - void processDplusV0MC(soa::Join const& collisions, + void processDplusV0MC(soa::Join const& collisions, CandsDplusFilteredWithMc const& candsDplus, aod::V0s const& v0s, TracksIUWithPIDAndMC const& tracksIU, @@ -437,7 +438,7 @@ struct HfDataCreatorCharmResoToDplusReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, dummyTable, rowHf3PrV0McRecReduced, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, dummyTable, rowHf3PrV0McRecReduced, dummyTable, dummyTable); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -445,7 +446,7 @@ struct HfDataCreatorCharmResoToDplusReduced { } PROCESS_SWITCH(HfDataCreatorCharmResoToDplusReduced, processDplusV0MC, "Process Dplus candidates paired with V0s with MC matching", false); - void processDplusTrackMC(soa::Join const& collisions, + void processDplusTrackMC(soa::Join const& collisions, CandsDplusFilteredWithMc const& candsDplus, TracksWithPIDAndMC const& tracks, aod::TrackAssoc const& trackIndices, @@ -476,7 +477,7 @@ struct HfDataCreatorCharmResoToDplusReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, dummyTable, hfTrackNoParam, dummyTable, rowHf3PrTrkMcRecReduced, dummyTable); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, dummyTable, hfTrackNoParam, dummyTable, rowHf3PrTrkMcRecReduced, dummyTable); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -484,7 +485,7 @@ struct HfDataCreatorCharmResoToDplusReduced { } PROCESS_SWITCH(HfDataCreatorCharmResoToDplusReduced, processDplusTrackMC, "Process Dplus candidates paired with tracks with MC matching", false); - void processDplusV0AndTrackMC(soa::Join const& collisions, + void processDplusV0AndTrackMC(soa::Join const& collisions, CandsDplusFilteredWithMc const& candsDplus, aod::V0s const& v0s, aod::TrackAssoc const& trackIndices, @@ -518,7 +519,7 @@ struct HfDataCreatorCharmResoToDplusReduced { auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, hfTrackNoParam, rowHf3PrV0McRecReduced, rowHf3PrTrkMcRecReduced, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, hfTrackNoParam, rowHf3PrV0McRecReduced, rowHf3PrTrkMcRecReduced, dummyTable); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -527,7 +528,7 @@ struct HfDataCreatorCharmResoToDplusReduced { PROCESS_SWITCH(HfDataCreatorCharmResoToDplusReduced, processDplusV0AndTrackMC, "Process Dplus candidates paired with V0s and tracks with MC matching", false); // ML - void processDplusV0MCWithMl(soa::Join const& collisions, + void processDplusV0MCWithMl(soa::Join const& collisions, CandsDplusFilteredWithMlAndMc const& candsDplus, aod::V0s const& v0s, TracksIUWithPIDAndMC const& tracksIU, @@ -558,7 +559,7 @@ struct HfDataCreatorCharmResoToDplusReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, dummyTable, rowHf3PrV0McRecReduced, dummyTable, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, dummyTable, rowHf3PrV0McRecReduced, dummyTable, hfCandD3PrMl); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -566,7 +567,7 @@ struct HfDataCreatorCharmResoToDplusReduced { } PROCESS_SWITCH(HfDataCreatorCharmResoToDplusReduced, processDplusV0MCWithMl, "Process Dplus candidates paired with V0s with MC matching and with ML info", false); - void processDplusTrackMCWithMl(soa::Join const& collisions, + void processDplusTrackMCWithMl(soa::Join const& collisions, CandsDplusFilteredWithMlAndMc const& candsDplus, TracksWithPIDAndMC const& tracks, aod::TrackAssoc const& trackIndices, @@ -597,7 +598,7 @@ struct HfDataCreatorCharmResoToDplusReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollisionWithMl, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, dummyTable, hfTrackNoParam, dummyTable, rowHf3PrTrkMcRecReduced, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, dummyTable, hfTrackNoParam, dummyTable, rowHf3PrTrkMcRecReduced, hfCandD3PrMl); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -605,7 +606,7 @@ struct HfDataCreatorCharmResoToDplusReduced { } PROCESS_SWITCH(HfDataCreatorCharmResoToDplusReduced, processDplusTrackMCWithMl, "Process Dplus candidates paired with tracks with MC matching and with ML info", false); - void processDplusV0AndTrackMCWithMl(soa::Join const& collisions, + void processDplusV0AndTrackMCWithMl(soa::Join const& collisions, CandsDplusFilteredWithMlAndMc const& candsDplus, aod::V0s const& v0s, aod::TrackAssoc const& trackIndices, @@ -638,7 +639,7 @@ struct HfDataCreatorCharmResoToDplusReduced { auto candsDThisColl = candsDplus.sliceBy(candsDplusPerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, hfTrackNoParam, rowHf3PrV0McRecReduced, rowHf3PrTrkMcRecReduced, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandD3Pr, hfCandV0, hfTrackNoParam, rowHf3PrV0McRecReduced, rowHf3PrTrkMcRecReduced, hfCandD3PrMl); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions diff --git a/PWGHF/D2H/TableProducer/dataCreatorCharmResoToDstarReduced.cxx b/PWGHF/D2H/TableProducer/dataCreatorCharmResoToDstarReduced.cxx index d8939b6a765..d3777632e78 100644 --- a/PWGHF/D2H/TableProducer/dataCreatorCharmResoToDstarReduced.cxx +++ b/PWGHF/D2H/TableProducer/dataCreatorCharmResoToDstarReduced.cxx @@ -27,6 +27,7 @@ #include "Common/Core/ZorroSummary.h" #include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -127,7 +128,7 @@ struct HfDataCreatorCharmResoToDstarReduced { using TracksIUWithPIDAndMC = soa::Join; // Collisions MC using BCsInfo = soa::Join; - using McCollisionsNoCents = soa::Join; + using McCollisionsNoCents = soa::Join; Filter filterSelectedCandDstar = (aod::hf_sel_candidate_dstar::isSelDstarToD0Pi == cfgDmesCuts.selectionFlagDstarToD0Pi); @@ -186,7 +187,7 @@ struct HfDataCreatorCharmResoToDstarReduced { // Process functions // No ML // Data - void processDstarV0(soa::Join const& collisions, + void processDstarV0(soa::Join const& collisions, CandsDstarFiltered const& candsDstar, aod::V0s const& v0s, TracksIUWithPID const& tracksIU, @@ -215,14 +216,14 @@ struct HfDataCreatorCharmResoToDstarReduced { auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, dummyTable, dummyTable, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, dummyTable, dummyTable, dummyTable, dummyTable); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } PROCESS_SWITCH(HfDataCreatorCharmResoToDstarReduced, processDstarV0, "Process Dstar candidates paired with V0s", true); - void processDstarTrack(soa::Join const& collisions, + void processDstarTrack(soa::Join const& collisions, CandsDstarFiltered const& candsDstar, aod::TrackAssoc const& trackIndices, TracksWithPID const& tracks, @@ -251,14 +252,14 @@ struct HfDataCreatorCharmResoToDstarReduced { auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, dummyTable, hfTrackNoParam, dummyTable, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, dummyTable, hfTrackNoParam, dummyTable, dummyTable, dummyTable); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } PROCESS_SWITCH(HfDataCreatorCharmResoToDstarReduced, processDstarTrack, "Process Dstar candidates paired with Tracks", false); - void processDstarV0AndTrack(soa::Join const& collisions, + void processDstarV0AndTrack(soa::Join const& collisions, CandsDstarFiltered const& candsDstar, aod::V0s const& v0s, aod::TrackAssoc const& trackIndices, @@ -289,7 +290,7 @@ struct HfDataCreatorCharmResoToDstarReduced { auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, dummyTable); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -298,7 +299,7 @@ struct HfDataCreatorCharmResoToDstarReduced { // ML // Data - void processDstarV0WithMl(soa::Join const& collisions, + void processDstarV0WithMl(soa::Join const& collisions, CandsDstarFilteredWithMl const& candsDstar, aod::V0s const& v0s, TracksIUWithPID const& tracksIU, @@ -326,14 +327,14 @@ struct HfDataCreatorCharmResoToDstarReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, dummyTable, dummyTable, dummyTable, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, dummyTable, dummyTable, dummyTable, hfCandD3PrMl); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } PROCESS_SWITCH(HfDataCreatorCharmResoToDstarReduced, processDstarV0WithMl, "Process Dstar candidates paired with V0s with ML info", false); - void processDstarTrackWithMl(soa::Join const& collisions, + void processDstarTrackWithMl(soa::Join const& collisions, CandsDstarFilteredWithMl const& candsDstar, aod::TrackAssoc const& trackIndices, TracksWithPID const& tracks, @@ -361,14 +362,14 @@ struct HfDataCreatorCharmResoToDstarReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollisionWithMl, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, dummyTable, hfTrackNoParam, dummyTable, dummyTable, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, dummyTable, hfTrackNoParam, dummyTable, dummyTable, hfCandD3PrMl); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); } PROCESS_SWITCH(HfDataCreatorCharmResoToDstarReduced, processDstarTrackWithMl, "Process Dstar candidates paired with Tracks with ML info", false); - void processDstarV0AndTrackWithMl(soa::Join const& collisions, + void processDstarV0AndTrackWithMl(soa::Join const& collisions, CandsDstarFilteredWithMl const& candsDstar, aod::V0s const& v0s, aod::TrackAssoc const& trackIndices, @@ -399,7 +400,7 @@ struct HfDataCreatorCharmResoToDstarReduced { auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, nullptr, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, hfTrackNoParam, dummyTable, dummyTable, hfCandD3PrMl); } // handle normalization by the right number of collisions hfCollisionCounter(collisions.tableSize(), zvtxColl, sel8Coll, zvtxAndSel8Coll, zvtxAndSel8CollAndSoftTrig, allSelColl); @@ -408,7 +409,7 @@ struct HfDataCreatorCharmResoToDstarReduced { // MC // No ML - void processDstarV0MC(soa::Join const& collisions, + void processDstarV0MC(soa::Join const& collisions, CandsDstarFilteredWithMc const& candsDstar, aod::V0s const& v0s, TracksIUWithPIDAndMC const& tracksIU, @@ -439,7 +440,7 @@ struct HfDataCreatorCharmResoToDstarReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, dummyTable, rowHfDstarV0McRecReduced, dummyTable, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, dummyTable, rowHfDstarV0McRecReduced, dummyTable, dummyTable); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -447,7 +448,7 @@ struct HfDataCreatorCharmResoToDstarReduced { } PROCESS_SWITCH(HfDataCreatorCharmResoToDstarReduced, processDstarV0MC, "Process Dstar candidates paired with V0s with MC matching", false); - void processDstarTrackMC(soa::Join const& collisions, + void processDstarTrackMC(soa::Join const& collisions, CandsDstarFilteredWithMc const& candsDstar, TracksWithPIDAndMC const& tracks, aod::TrackAssoc const& trackIndices, @@ -478,7 +479,7 @@ struct HfDataCreatorCharmResoToDstarReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, dummyTable, hfTrackNoParam, dummyTable, rowHfDstarTrkMcRecReduced, dummyTable); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, dummyTable, hfTrackNoParam, dummyTable, rowHfDstarTrkMcRecReduced, dummyTable); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -486,7 +487,7 @@ struct HfDataCreatorCharmResoToDstarReduced { } PROCESS_SWITCH(HfDataCreatorCharmResoToDstarReduced, processDstarTrackMC, "Process Dstar candidates paired with tracks with MC matching", false); - void processDstarV0AndTrackMC(soa::Join const& collisions, + void processDstarV0AndTrackMC(soa::Join const& collisions, CandsDstarFilteredWithMc const& candsDstar, aod::V0s const& v0s, aod::TrackAssoc const& trackIndices, @@ -520,7 +521,7 @@ struct HfDataCreatorCharmResoToDstarReduced { auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollision, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, hfTrackNoParam, rowHfDstarV0McRecReduced, rowHfDstarTrkMcRecReduced, dummyTable); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, hfTrackNoParam, rowHfDstarV0McRecReduced, rowHfDstarTrkMcRecReduced, dummyTable); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -529,7 +530,7 @@ struct HfDataCreatorCharmResoToDstarReduced { PROCESS_SWITCH(HfDataCreatorCharmResoToDstarReduced, processDstarV0AndTrackMC, "Process Dstar candidates paired with V0s and tracks with MC matching", false); // ML - void processDstarV0MCWithMl(soa::Join const& collisions, + void processDstarV0MCWithMl(soa::Join const& collisions, CandsDstarFilteredWithMlAndMc const& candsDstar, aod::V0s const& v0s, TracksIUWithPIDAndMC const& tracksIU, @@ -560,7 +561,7 @@ struct HfDataCreatorCharmResoToDstarReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, dummyTable, rowHfDstarV0McRecReduced, dummyTable, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, nullptr, tracksIU, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, dummyTable, rowHfDstarV0McRecReduced, dummyTable, hfCandD3PrMl); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -568,7 +569,7 @@ struct HfDataCreatorCharmResoToDstarReduced { } PROCESS_SWITCH(HfDataCreatorCharmResoToDstarReduced, processDstarV0MCWithMl, "Process Dstar candidates paired with V0s with MC matching and with ML info", false); - void processDstarTrackMCWithMl(soa::Join const& collisions, + void processDstarTrackMCWithMl(soa::Join const& collisions, CandsDstarFilteredWithMlAndMc const& candsDstar, TracksWithPIDAndMC const& tracks, aod::TrackAssoc const& trackIndices, @@ -599,7 +600,7 @@ struct HfDataCreatorCharmResoToDstarReduced { auto thisCollId = collision.globalIndex(); auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollisionWithMl, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, dummyTable, hfTrackNoParam, dummyTable, rowHfDstarTrkMcRecReduced, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, nullptr, trackIdsThisColl, tracks, tracks, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, dummyTable, hfTrackNoParam, dummyTable, rowHfDstarTrkMcRecReduced, hfCandD3PrMl); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions @@ -607,7 +608,7 @@ struct HfDataCreatorCharmResoToDstarReduced { } PROCESS_SWITCH(HfDataCreatorCharmResoToDstarReduced, processDstarTrackMCWithMl, "Process Dstar candidates paired with tracks with MC matching and with ML info", false); - void processDstarV0AndTrackMCWithMl(soa::Join const& collisions, + void processDstarV0AndTrackMCWithMl(soa::Join const& collisions, CandsDstarFilteredWithMlAndMc const& candsDstar, aod::V0s const& v0s, aod::TrackAssoc const& trackIndices, @@ -640,7 +641,7 @@ struct HfDataCreatorCharmResoToDstarReduced { auto candsDThisColl = candsDstar.sliceBy(candsDstarPerCollisionWithMl, thisCollId); auto v0sThisColl = v0s.sliceBy(candsV0PerCollision, thisCollId); auto trackIdsThisColl = trackIndices.sliceBy(trackIndicesPerCollision, thisCollId); - runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, hfTrackNoParam, rowHfDstarV0McRecReduced, rowHfDstarTrkMcRecReduced, hfCandD3PrMl); + runDataCreation>(collision, candsDThisColl, v0sThisColl, trackIdsThisColl, tracks, tracksIU, particlesMc, hfRejMap, bz, pdg, registry, matCorr, fitter, cfgDmesCuts, cfgSingleTrackCuts, cfgV0Cuts, cfgV0Cuts, cfgQaPlots, rejectPairsWithCommonDaughter, hfReducedCollision, hfCandDstar, hfCandV0, hfTrackNoParam, rowHfDstarV0McRecReduced, rowHfDstarTrkMcRecReduced, hfCandD3PrMl); } runMcGen(particlesMc, mcParticlesPerMcCollision, collInfos, colPerMcCollision, mcCollisions, hfEvSelMc, rejectCollisionsWithBadEvSel, registry, pdg, rowHfResoMcGenReduced, bcs); // handle normalization by the right number of collisions diff --git a/PWGHF/D2H/TableProducer/dataCreatorHiddenCharmReduced.cxx b/PWGHF/D2H/TableProducer/dataCreatorHiddenCharmReduced.cxx index f4284717c95..dc71ed37260 100644 --- a/PWGHF/D2H/TableProducer/dataCreatorHiddenCharmReduced.cxx +++ b/PWGHF/D2H/TableProducer/dataCreatorHiddenCharmReduced.cxx @@ -27,6 +27,7 @@ #include "Common/Core/ZorroSummary.h" #include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -289,7 +290,7 @@ struct HfDataCreatorHiddenCharmReduced { return isSelectedPid(track); } - void processEtaCTrack(soa::Join const& collisions, + void processEtaCTrack(soa::Join const& collisions, aod::TrackAssoc const& trackIndices, TracksWithPID const& tracks, aod::BCsWithTimestamps const&) diff --git a/PWGHF/D2H/TableProducer/dataCreatorJpsiHadReduced.cxx b/PWGHF/D2H/TableProducer/dataCreatorJpsiHadReduced.cxx index 5b2976a38a8..11e4515893c 100644 --- a/PWGHF/D2H/TableProducer/dataCreatorJpsiHadReduced.cxx +++ b/PWGHF/D2H/TableProducer/dataCreatorJpsiHadReduced.cxx @@ -34,6 +34,7 @@ #include "Common/Core/trackUtilities.h" #include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -65,6 +66,8 @@ #include #include +#include + #include #include #include @@ -191,7 +194,7 @@ struct HfDataCreatorJpsiHadReduced { using TracksPid = soa::Join; using TracksPidWithSel = soa::Join; using TracksPidWithSelAndMc = soa::Join; - using CollisionsWCMcLabels = soa::Join; + using CollisionsWCMcLabels = soa::Join; using BCsInfo = soa::Join; Preslice candsJpsiPerCollision = aod::track_association::collisionId; @@ -1479,7 +1482,7 @@ struct HfDataCreatorJpsiHadReduced { // } } - void processJpsiKData(soa::Join const& collisions, + void processJpsiKData(soa::Join const& collisions, aod::HfCand2ProngWPid const& candsJpsi, aod::TrackAssoc const& trackIndices, TracksPidWithSel const& tracks, @@ -1507,7 +1510,7 @@ struct HfDataCreatorJpsiHadReduced { } PROCESS_SWITCH(HfDataCreatorJpsiHadReduced, processJpsiKData, "Process J/Psi K without MC info", true); - void processJpsiPhiData(soa::Join const& collisions, + void processJpsiPhiData(soa::Join const& collisions, aod::HfCand2ProngWPid const& candsJpsi, aod::TrackAssoc const& trackIndices, TracksPidWithSel const& tracks, @@ -1535,7 +1538,7 @@ struct HfDataCreatorJpsiHadReduced { } PROCESS_SWITCH(HfDataCreatorJpsiHadReduced, processJpsiPhiData, "Process J/Psi phi without MC info", false); - void processJpsiK0StarData(soa::Join const& collisions, + void processJpsiK0StarData(soa::Join const& collisions, aod::HfCand2ProngWPid const& candsJpsi, aod::TrackAssoc const& trackIndices, TracksPidWithSel const& tracks, diff --git a/PWGHF/D2H/TableProducer/mlBasedTrackSelector.cxx b/PWGHF/D2H/TableProducer/mlBasedTrackSelector.cxx new file mode 100644 index 00000000000..55a854ae9ca --- /dev/null +++ b/PWGHF/D2H/TableProducer/mlBasedTrackSelector.cxx @@ -0,0 +1,1359 @@ +// Copyright 2019-2026 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. + +/// \file mlBasedTrackSelector.cxx +/// \brief D± → π± K∓ π± and D_s± → K± K∓ π± skimming with track-level ML +/// TEST ONLY, PLEASE DO NOT USE FOR ANALYSIS +/// \author Fabrizio Chinu , Universita and INFN Torino + +#include "PWGHF/Core/CentralityEstimation.h" +#include "PWGHF/Core/HfMlResponseHfTracks.h" +#include "PWGHF/Core/SelectorCuts.h" +#include "PWGHF/DataModel/AliasTables.h" +#include "PWGHF/DataModel/TrackIndexSkimmingTables.h" +#include "PWGHF/Utils/utilsAnalysis.h" +#include "PWGHF/Utils/utilsBfieldCCDB.h" +#include "PWGHF/Utils/utilsEvSelHf.h" + +#include "Common/CCDB/TriggerAliases.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Tools/ML/MlResponse.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::analysis; +using namespace o2::hf_evsel; +using namespace o2::aod; +using namespace o2::hf_centrality; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::constants::physics; + +/// Bit positions of aod::HfSelTrack::isSelProng (only Cand3Prong is ever set here). +enum CandidateType { + Cand2Prong = 0, + Cand3Prong, + CandV0bachelor, + CandDstar, + CandCascadeBachelor, + NCandidateTypes +}; + +/// The two 3-prong channels handled by this task. +enum Channel3Prong { + ChannelDplusToPiKPi = 0, + ChannelDsToKKPi, + NChannels3Prong +}; + +constexpr std::array DecayTypeOfChannel{ + hf_cand_3prong::DecayType::DplusToPiKPi, + hf_cand_3prong::DecayType::DsToKKPi}; + +/// Bit positions of aod::HfSelTrack::isIdentifiedPid filled by this task: the decision of the +/// track-level model, one bit per (channel, role). A track can be pion-like for one channel and +/// kaon-like for the other, so the four bits are independent. +enum TrackMlRole { + RolePionDplus = 0, + RoleKaonDplus, + RolePionDs, + RoleKaonDs, + NTrackMlRoles +}; + +constexpr std::array RolePionOfChannel{RolePionDplus, RolePionDs}; +constexpr std::array RoleKaonOfChannel{RoleKaonDplus, RoleKaonDs}; + +constexpr int NProngs = 3; // prongs of the candidates built here +constexpr int NMassHypos = 2; // mass hypotheses per channel, i.e. the two orderings of the same-sign pair + +/// Whether each prong is a kaon, per channel and mass hypothesis. +constexpr std::array, NMassHypos>, NChannels3Prong> IsKaonProng{{ + {{{{false, true, false}}, {{false, true, false}}}}, + {{{{true, true, false}}, {{false, true, true}}}}, +}}; + +constexpr double PtMaxModel = 1.e10; + +constexpr uint32_t MaskSameSignAny = (1u << RolePionDplus) | (1u << RolePionDs) | (1u << RoleKaonDs); +constexpr uint32_t MaskOppSignAny = (1u << RoleKaonDplus) | (1u << RoleKaonDs); + +/// Where the combinatorics spends its time, accumulated in seconds into hTiming. +enum TimingStep { + TimeLoopTotal = 0, ///< everything inside the triple loop + TimeFit2Prong, ///< the 2-track vertex used to skip pairs early + TimeFit3Prong, ///< the 3-track vertex of the surviving triplets + TimeCacheFill, ///< building the per-collision prong cache, propagation included + TimeCachePropagate, ///< only the re-propagation inside that build + NTimingSteps +}; + +/// How often each stage of the triple loop runs, accumulated into hLoopCounters. +enum LoopCounter { + CountPairsSeen = 0, ///< (same-sign, opposite-sign) pairs reached + CountPairsCandidateOk, ///< ... of those, surviving the ML pair test + CountFit2Prong, ///< ... of those, handed to the 2-prong fitter + CountPairsRejected2P, ///< ... of those, dropped by the 2-track vertex + CountTripletsEnumerated, ///< triplets built from the surviving pairs + CountTripletsWritten, ///< ... of those, written to the skim + CountTracksCached, ///< associations put into the prong cache + CountTracksPropagated, ///< ... of those, needing a re-propagation to this collision + NLoopCounters +}; + +/// Where the ML track selection spends its time, accumulated in seconds into its own hTiming. +enum TrackTimingStep { + TrackTimeTotal = 0, ///< the whole per-collision loop: slicing, features, models, table filling + TrackTimeFeatures, ///< building the input features, re-propagation included + TrackTimeModelDplus, ///< evaluating the D+ model: input vector, ONNX call, thresholds + TrackTimeModelDs, ///< evaluating the Ds model + NTrackTimingSteps +}; + +inline std::chrono::steady_clock::time_point tickIf(const bool enabled) +{ + return enabled ? std::chrono::steady_clock::now() : std::chrono::steady_clock::time_point{}; +} +inline double elapsedSeconds(std::chrono::steady_clock::time_point const& start) +{ + return std::chrono::duration(std::chrono::steady_clock::now() - start).count(); +} + +/// Event selection +struct HfTrackSelectorTagSelCollisions { + Produces rowSelectedCollision; + + Configurable fillHistograms{"fillHistograms", true, "fill histograms"}; + Configurable triggerClassName{"triggerClassName", "kINT7", "Run 2 trigger class, only for Run 2 converted data"}; + HfEventSelection hfEvSel; // event selection and monitoring + Service ccdb{}; // needed for evSelection + + // QA histos + HistogramRegistry registry{"registry"}; + OutputObj zorroSummary{"zorroSummary"}; + + void init(InitContext const&) + { + const std::array doProcess = {doprocessTrigAndCentFT0ASel, doprocessTrigAndCentFT0CSel, doprocessTrigAndCentFT0MSel, doprocessTrigAndCentFV0ASel, doprocessTrigSel, doprocessNoTrigSel, doprocessUpcSel}; + if (std::count(doProcess.begin(), doProcess.end(), true) != 1) { + LOGP(fatal, "One and only one process function for collision selection can be enabled at a time!"); + } + + // set numerical value of the Run 2 trigger class + auto* const triggerAlias = std::find(aliasLabels, aliasLabels + kNaliases, triggerClassName.value.data()); + if (triggerAlias != aliasLabels + kNaliases) { + hfEvSel.triggerClass.value = std::distance(aliasLabels, triggerAlias); + } + + hfEvSel.init(registry, &zorroSummary); // collision monitoring + if (fillHistograms) { + if (doprocessTrigAndCentFT0ASel || doprocessTrigAndCentFT0CSel || doprocessTrigAndCentFT0MSel || doprocessTrigAndCentFV0ASel) { + const AxisSpec axisCentrality{200, 0., 100., "centrality percentile"}; + registry.add("hCentralitySelected", "Centrality percentile of selected events in the centrality interval; centrality percentile;entries", {HistType::kTH1D, {axisCentrality}}); + registry.add("hCentralityRejected", "Centrality percentile of selected events outside the centrality interval; centrality percentile;entries", {HistType::kTH1D, {axisCentrality}}); + } + } + } + + /// Collision selection + /// \param collision collision table with + template + void selectCollision(const Col& collision, + const BCsType& bcs) + { + float centrality{-1.f}; + o2::hf_evsel::HfCollisionRejectionMask rejectionMask{}; + + if constexpr (ApplyUpcSel) { + rejectionMask = hfEvSel.getHfCollisionRejectionMaskWithUpc( + collision, centrality, ccdb, registry, bcs); + } else { + rejectionMask = hfEvSel.getHfCollisionRejectionMask( + collision, centrality, ccdb, registry); + } + + if (fillHistograms) { + hfEvSel.fillHistograms(collision, rejectionMask, centrality); + // additional centrality histos + if constexpr (CentEstimator != o2::hf_centrality::None) { + if (rejectionMask == 0) { + registry.fill(HIST("hCentralitySelected"), centrality); + } else if (rejectionMask == BIT(EventRejection::Centrality)) { // rejected by centrality only + registry.fill(HIST("hCentralityRejected"), centrality); + } + } + } + + // fill table row + rowSelectedCollision(rejectionMask); + } + + /// Event selection with trigger and FT0A centrality selection + void processTrigAndCentFT0ASel(soa::Join::iterator const& collision, + aod::BcFullInfos const& bcs) + { + selectCollision(collision, bcs); + } + PROCESS_SWITCH(HfTrackSelectorTagSelCollisions, processTrigAndCentFT0ASel, "Use trigger and centrality selection with FT0A", false); + + /// Event selection with trigger and FT0C centrality selection + void processTrigAndCentFT0CSel(soa::Join::iterator const& collision, + aod::BcFullInfos const& bcs) + { + selectCollision(collision, bcs); + } + PROCESS_SWITCH(HfTrackSelectorTagSelCollisions, processTrigAndCentFT0CSel, "Use trigger and centrality selection with FT0C", false); + + /// Event selection with trigger and FT0M centrality selection + void processTrigAndCentFT0MSel(soa::Join::iterator const& collision, + aod::BcFullInfos const& bcs) + { + selectCollision(collision, bcs); + } + PROCESS_SWITCH(HfTrackSelectorTagSelCollisions, processTrigAndCentFT0MSel, "Use trigger and centrality selection with FT0M", false); + + /// Event selection with trigger and FV0A centrality selection + void processTrigAndCentFV0ASel(soa::Join::iterator const& collision, + aod::BcFullInfos const& bcs) + { + selectCollision(collision, bcs); + } + PROCESS_SWITCH(HfTrackSelectorTagSelCollisions, processTrigAndCentFV0ASel, "Use trigger and centrality selection with FV0A", false); + + /// Event selection with trigger selection + void processTrigSel(soa::Join::iterator const& collision, + aod::BcFullInfos const& bcs) + { + selectCollision(collision, bcs); + } + PROCESS_SWITCH(HfTrackSelectorTagSelCollisions, processTrigSel, "Use trigger selection", false); + + /// Event selection without trigger selection + void processNoTrigSel(soa::Join::iterator const& collision, + aod::BcFullInfos const& bcs) + { + selectCollision(collision, bcs); + } + PROCESS_SWITCH(HfTrackSelectorTagSelCollisions, processNoTrigSel, "Do not use trigger selection", true); + + /// Event selection with UPC + void processUpcSel(soa::Join::iterator const& collision, + aod::BcFullInfos const& bcs, + aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0as*/, + aod::FDDs const& /*fdds*/, + aod::Zdcs const& /*zdcs*/) + { + selectCollision(collision, bcs); + } + PROCESS_SWITCH(HfTrackSelectorTagSelCollisions, processUpcSel, "Use UPC event selection", false); +}; + +/// Track selection, ML based +struct HfTrackSelectorTagSelTracks { + Produces rowSelectedTrack; + + struct : ConfigurableGroup { + Configurable testAcknowledgement{"testAcknowledgement", false, "test acknowledgement"}; + Configurable fillHistograms{"fillHistograms", true, "fill histograms"}; + Configurable ptMinTrack{"ptMinTrack", 0.3f, "min. track pT entering the charm combinatorics"}; + Configurable enableTiming{"enableTiming", false, "fill hTiming with the CPU of the feature building and of each model evaluation (adds two clock reads per call)"}; + // D+ model + Configurable applyMlDplus{"applyMlDplus", true, "evaluate the D+ track model"}; + Configurable onnxFileNameDplus{"onnxFileNameDplus", "ModelHandler_DplusTracks.onnx", "ONNX file name of the D+ track model"}; + Configurable> inputFeaturesDplus{"inputFeaturesDplus", std::vector{"pt", "eta", "dcaXY", "dcaZ", "sigmaDcaXY", "sigmaDcaZ", "normDcaXY", "normDcaZ", "signed1Pt", "tgl", "sign", "isPvContributor", "itsNCls", "itsNClsInnerBarrel", "itsChi2NCl", "tpcNClsFound", "tpcCrossedRowsOverFindableCls", "tpcChi2NCl", "tpcFractionSharedCls", "tpcNSigmaPi", "tpcNSigmaKa"}, "input features of the D+ model, in the order it expects"}; + Configurable thresholdScorePionDplus{"thresholdScorePionDplus", 0., "min. D+ pion-class score"}; + Configurable thresholdScoreKaonDplus{"thresholdScoreKaonDplus", 0., "min. D+ kaon-class score"}; + // Ds model + Configurable applyMlDs{"applyMlDs", true, "evaluate the Ds track model"}; + Configurable onnxFileNameDs{"onnxFileNameDs", "ModelHandler_DsTracks.onnx", "ONNX file name of the Ds track model"}; + Configurable> inputFeaturesDs{"inputFeaturesDs", std::vector{"pt", "eta", "dcaXY", "dcaZ", "sigmaDcaXY", "sigmaDcaZ", "normDcaXY", "normDcaZ", "signed1Pt", "tgl", "sign", "isPvContributor", "itsNCls", "itsNClsInnerBarrel", "itsChi2NCl", "tpcNClsFound", "tpcCrossedRowsOverFindableCls", "tpcChi2NCl", "tpcFractionSharedCls", "tpcNSigmaPi", "tpcNSigmaKa"}, "input features of the Ds model, in the order it expects"}; + Configurable thresholdScorePionDs{"thresholdScorePionDs", 0., "min. Ds pion-class score"}; + Configurable thresholdScoreKaonDs{"thresholdScoreKaonDs", 0., "min. Ds kaon-class score"}; + // ONNX runtime + Configurable loadModelsFromCcdb{"loadModelsFromCcdb", false, "load the ONNX models from CCDB instead of a local path"}; + Configurable mlModelPathCcdbDplus{"mlModelPathCcdbDplus", "path/to/ml/models/Dplus", "CCDB path of the D+ track model"}; + Configurable mlModelPathCcdbDs{"mlModelPathCcdbDs", "path/to/ml/models/Ds", "CCDB path of the Ds track model"}; + Configurable timestampCcdbForMlModels{"timestampCcdbForMlModels", -1, "timestamp of the ONNX files to be queried in CCDB"}; + Configurable enableOnnxOptimizations{"enableOnnxOptimizations", true, "enable the ONNX graph optimisations"}; + Configurable onnxThreads{"onnxThreads", 1, "number of threads used by the ONNX runtime (0 = let onnxruntime decide)"}; + // CCDB + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; + Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; + Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + } config; + + /// One track-level model: the response, its score thresholds and whether it runs. + struct HfTrackModel { + HfMlResponseHfTracks response{}; + double thresholdPion{0.}; + double thresholdKaon{0.}; + bool enabled{false}; + }; + std::array models; + + Service ccdb{}; + o2::ccdb::CcdbApi ccdbApi; + o2::base::MatLayerCylSet* lut{}; + o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + int runNumber{}; + + // running variables for the re-propagation of tracks to a non-default collision + o2::dataformats::DCA dcaInfoCov; + o2::dataformats::VertexBase vtx; + + using TracksWithSelAndPid = soa::Join; + using CollisionsWithSel = soa::Join; + using CollisionsWithCentFT0CAndSel = soa::Join; + + Preslice trackIndicesPerCollision = aod::track_association::collisionId; + + // per-data-frame accumulators for hTiming, filled into it at the end of each process call + std::array timing{}; + bool doTiming{false}; ///< cached config.enableTiming: read once, used on the hot path + + HistogramRegistry registry{"registry"}; + + /// Add this data frame's accumulated seconds to hTiming and reset the accumulators. + void flushTiming() + { + if (doTiming) { + // Fill(bin, weight) so the bins accumulate seconds over the whole run + for (int iStep = 0; iStep < NTrackTimingSteps; iStep++) { + registry.fill(HIST("hTiming"), iStep, timing[iStep]); + } + } + timing.fill(0.); + } + + /// Configure one model from its configurables. + /// \param model is the model to configure + /// \param onnxFile is the ONNX file name + /// \param ccdbPath is the CCDB path of the model, used if the models are loaded from CCDB + /// \param features are the input feature names, in the order the model expects + /// \param thrPion, thrKaon are the score thresholds + /// \param name is used in the log message + void configureModel(HfTrackModel& model, + std::string const& onnxFile, + std::string const& ccdbPath, + std::vector const& features, + const double thrPion, + const double thrKaon, + const char* name) + { + model.thresholdPion = thrPion; + model.thresholdKaon = thrKaon; + + const std::vector binsPtSingle{0., PtMaxModel}; + const std::vector onnxFiles{onnxFile}; + const auto nOut = static_cast(HfTrackMlClass::NClasses); + const std::vector cutDir(nOut, o2::cuts_ml::CutDirection::CutNot); + const std::vector dummyCutValues(nOut, 0.); + const o2::framework::LabeledArray dummyCuts{dummyCutValues.data(), 1u, static_cast(nOut), {}, {}}; + + model.response.configure(binsPtSingle, dummyCuts, cutDir, static_cast(nOut)); + if (config.loadModelsFromCcdb) { + ccdbApi.init(config.ccdbUrl); + model.response.setModelPathsCCDB(onnxFiles, ccdbApi, std::vector{ccdbPath}, config.timestampCcdbForMlModels); + } else { + model.response.setModelPathsLocal(onnxFiles); + } + model.response.cacheInputFeaturesIndices(features); + model.response.init(config.enableOnnxOptimizations, config.onnxThreads); + model.enabled = true; + LOGP(info, "{}: configured from {} with {} input features and {} output classes (pion score > {}, kaon score > {})", + name, config.loadModelsFromCcdb ? "CCDB " + ccdbPath : onnxFile, features.size(), nOut, thrPion, thrKaon); + } + + void init(InitContext const&) + { + if (!config.testAcknowledgement) { + LOGF(fatal, "ml-based-track-selector is for test only, please do not use for analysis. If you are aware of what you are doing, set testAcknowledgement to true in the configuration."); + } + + const std::array doProcess = {doprocessTracks, doprocessTracksWithCentFT0C}; + if (std::count(doProcess.begin(), doProcess.end(), true) != 1) { + LOGP(fatal, "One and only one process function of HfTrackSelectorTagSelTracks can be enabled at a time!"); + } + + if (config.applyMlDplus) { + configureModel(models[ChannelDplusToPiKPi], config.onnxFileNameDplus, config.mlModelPathCcdbDplus, config.inputFeaturesDplus, + config.thresholdScorePionDplus, config.thresholdScoreKaonDplus, "D+ track model"); + } + if (config.applyMlDs) { + configureModel(models[ChannelDsToKKPi], config.onnxFileNameDs, config.mlModelPathCcdbDs, config.inputFeaturesDs, + config.thresholdScorePionDs, config.thresholdScoreKaonDs, "Ds track model"); + } + if (!models[ChannelDplusToPiKPi].enabled && !models[ChannelDsToKKPi].enabled) { + LOGP(fatal, "At least one of the D+ and Ds track models must be enabled!"); + } + + ccdb->setURL(config.ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(config.ccdbPathLut)); + runNumber = 0; + + if (config.fillHistograms) { + const AxisSpec axisPtProng{360, 0., 36., "#it{p}_{T}^{track} (GeV/#it{c})"}; + const AxisSpec axisScore{100, 0., 1., "ML score"}; + const AxisSpec axisEta{100, -1., 1., "#it{#eta}"}; + + registry.add("hPtNoCuts", "all track associations;#it{p}_{T}^{track} (GeV/#it{c});entries", {HistType::kTH1D, {axisPtProng}}); + registry.add("hPtQuality", "track associations passing the pT floor and the quality cut, scored;#it{p}_{T}^{track} (GeV/#it{c});entries", {HistType::kTH1D, {axisPtProng}}); + registry.add("hPtQualityRejColl", "track associations passing the pT floor and the quality cut, not scored: collision fails the HF event selection;#it{p}_{T}^{track} (GeV/#it{c});entries", {HistType::kTH1D, {axisPtProng}}); + registry.add("hPtSelected", "track associations selected by at least one model;#it{p}_{T}^{track} (GeV/#it{c});entries", {HistType::kTH1D, {axisPtProng}}); + registry.add("hEtaSelected", "track associations selected by at least one model;#it{#eta};entries", {HistType::kTH1D, {axisEta}}); + registry.add("hScorePionDplus", "D^{#plus} pion-class score;#it{p}_{T}^{track} (GeV/#it{c});score;entries", {HistType::kTH2D, {axisPtProng, axisScore}}); + registry.add("hScoreKaonDplus", "D^{#plus} kaon-class score;#it{p}_{T}^{track} (GeV/#it{c});score;entries", {HistType::kTH2D, {axisPtProng, axisScore}}); + registry.add("hScorePionDs", "D_{s}^{#plus} pion-class score;#it{p}_{T}^{track} (GeV/#it{c});score;entries", {HistType::kTH2D, {axisPtProng, axisScore}}); + registry.add("hScoreKaonDs", "D_{s}^{#plus} kaon-class score;#it{p}_{T}^{track} (GeV/#it{c});score;entries", {HistType::kTH2D, {axisPtProng, axisScore}}); + // seconds, accumulated over the run via Fill(bin, weight); per-call cost = bin / hPtQuality entries + auto hTiming = registry.add("hTiming", "CPU of the ML track selection;;seconds", {HistType::kTH1D, {{NTrackTimingSteps, -0.5f, static_cast(NTrackTimingSteps) - 0.5f}}}); + hTiming->GetXaxis()->SetBinLabel(TrackTimeTotal + 1, "track loop total"); + hTiming->GetXaxis()->SetBinLabel(TrackTimeFeatures + 1, "features"); + hTiming->GetXaxis()->SetBinLabel(TrackTimeModelDplus + 1, "D+ model"); + hTiming->GetXaxis()->SetBinLabel(TrackTimeModelDs + 1, "Ds model"); + } + doTiming = config.enableTiming && config.fillHistograms; + } + + /// Fill the container of ML input features for one (track, collision) association. + /// The DCA and its resolution are recomputed by propagating to the collision under study + /// whenever that is not the track's own collision. + /// \param collision is the collision the track is associated to + /// \param track is the track + /// \param centrality is the centrality percentile of the collision + /// \param features is the container to be filled + template + void fillFeatures(TCollision const& collision, TTrack const& track, float centrality, HfTrackMlFeatures& features) + { + float trackPt = track.pt(); + float trackEta = track.eta(); + float dcaXY = track.dcaXY(); + float dcaZ = track.dcaZ(); + float sigmaDcaXY = std::sqrt(std::abs(track.sigmaDcaXY2())); + float sigmaDcaZ = std::sqrt(std::abs(track.sigmaDcaZ2())); + + if (track.collisionId() != collision.globalIndex()) { + // not the default collision of this track: re-propagate to get DCA and its covariance + auto trackParCov = getTrackParCov(track); + dcaInfoCov.set(999.f, 999.f, 999.f, 999.f, 999.f); + vtx.setPos({collision.posX(), collision.posY(), collision.posZ()}); + vtx.setCov(collision.covXX(), collision.covXY(), collision.covYY(), collision.covXZ(), collision.covYZ(), collision.covZZ()); + if (o2::base::Propagator::Instance()->propagateToDCABxByBz(vtx, trackParCov, 2.f, noMatCorr, &dcaInfoCov)) { + trackPt = trackParCov.getPt(); + trackEta = trackParCov.getEta(); + dcaXY = dcaInfoCov.getY(); + dcaZ = dcaInfoCov.getZ(); + sigmaDcaXY = std::sqrt(std::abs(dcaInfoCov.getSigmaY2())); + sigmaDcaZ = std::sqrt(std::abs(dcaInfoCov.getSigmaZ2())); + } + } + + constexpr float MinSigmaDca = 1.e-6f; // guard against a null resolution before dividing + + features.pt = trackPt; + features.eta = trackEta; + features.dcaXY = dcaXY; + features.dcaZ = dcaZ; + features.sigmaDcaXY = sigmaDcaXY; + features.sigmaDcaZ = sigmaDcaZ; + features.normDcaXY = dcaXY / std::max(sigmaDcaXY, MinSigmaDca); + features.normDcaZ = dcaZ / std::max(sigmaDcaZ, MinSigmaDca); + features.signed1Pt = track.signed1Pt(); + features.tgl = track.tgl(); + features.sign = static_cast(track.sign()); + features.isPvContributor = static_cast(track.isPVContributor()); + features.itsNCls = static_cast(track.itsNCls()); + features.itsNClsInnerBarrel = static_cast(track.itsNClsInnerBarrel()); + features.itsChi2NCl = track.itsChi2NCl(); + features.tpcNClsFound = static_cast(track.tpcNClsFound()); + features.tpcCrossedRowsOverFindableCls = track.tpcCrossedRowsOverFindableCls(); + features.tpcChi2NCl = track.tpcChi2NCl(); + features.tpcFractionSharedCls = track.tpcFractionSharedCls(); + features.tpcNSigmaPi = track.tpcNSigmaPi(); + features.tpcNSigmaKa = track.tpcNSigmaKa(); + features.centrality = centrality; + } + + /// Evaluate one model and turn its output into the two role decisions. + /// \param model is the model to evaluate + /// \param features are the track features + /// \param scores is filled with (background, pion-role, kaon-role); -1 if not evaluated + /// \param isSelPion, isSelKaon are filled with the threshold decisions + /// \return true if the model was actually evaluated + bool evaluateModel(HfTrackModel& model, HfTrackMlFeatures const& features, + std::array& scores, bool& isSelPion, bool& isSelKaon) + { + scores = {-1.f, -1.f, -1.f}; + isSelPion = false; + isSelKaon = false; + if (!model.enabled) { + return false; + } + auto inputFeatures = model.response.getInputFeatures(features); + // one model for the whole pT range, so the bin index is always 0 + const auto output = model.response.getModelOutput(inputFeatures, 0); + if (output.size() != scores.size()) { + LOGP(fatal, "the model emitted {} scores, expected {}: only 3-class (bkg/pi/K) models are supported", output.size(), scores.size()); + } + std::copy(output.begin(), output.end(), scores.begin()); + + isSelPion = scores[1] > model.thresholdPion; + isSelKaon = scores[2] > model.thresholdKaon; + return true; + } + + /// Selection tag for tracks + /// \param collision is the collision iterator + /// \param trackIndicesCollision are the track indices associated to this collision + /// \param centrality is the centrality percentile of the collision + /// \param isCollisionSelected is whether the collision passes the HF event selection + template + void runTagSelTracks(TCollision const& collision, + TTracks const& /*tracks*/, + GroupedTrackIndices const& trackIndicesCollision, + float centrality, + const bool isCollisionSelected) + { + const bool scoreCollision = isCollisionSelected; + + for (const auto& trackId : trackIndicesCollision) { + const auto track = trackId.template track_as(); + + // One row per track association, always: aod::HfSelTrack is joined with aod::TrackAssoc + // downstream, so the two tables have to stay index-aligned. Rejected associations are + // written with an empty selection mask, not skipped. + uint32_t statusProng{0}; + uint32_t isIdentifiedPid{0}; + + if (config.fillHistograms) { + registry.fill(HIST("hPtNoCuts"), track.pt()); + } + + const bool passesQuality = track.pt() >= config.ptMinTrack && track.isGlobalTrackWoDCA(); + if (passesQuality && !scoreCollision && config.fillHistograms) { + registry.fill(HIST("hPtQualityRejColl"), track.pt()); + } + + if (passesQuality && scoreCollision) { + if (config.fillHistograms) { + registry.fill(HIST("hPtQuality"), track.pt()); + } + + HfTrackMlFeatures features{}; + auto tStart = tickIf(doTiming); + fillFeatures(collision, track, centrality, features); + if (doTiming) { + timing[TrackTimeFeatures] += elapsedSeconds(tStart); + } + + std::array scores{}; + bool isSelPion{false}; + bool isSelKaon{false}; + + tStart = tickIf(doTiming); + const bool evaluatedDplus = evaluateModel(models[ChannelDplusToPiKPi], features, scores, isSelPion, isSelKaon); + if (doTiming) { + timing[TrackTimeModelDplus] += elapsedSeconds(tStart); + } + if (evaluatedDplus) { + if (isSelPion) { + SETBIT(isIdentifiedPid, RolePionDplus); + } + if (isSelKaon) { + SETBIT(isIdentifiedPid, RoleKaonDplus); + } + if (config.fillHistograms) { + registry.fill(HIST("hScorePionDplus"), features.pt, scores[1]); + registry.fill(HIST("hScoreKaonDplus"), features.pt, scores[2]); + } + } + + tStart = tickIf(doTiming); + const bool evaluatedDs = evaluateModel(models[ChannelDsToKKPi], features, scores, isSelPion, isSelKaon); + if (doTiming) { + timing[TrackTimeModelDs] += elapsedSeconds(tStart); + } + if (evaluatedDs) { + if (isSelPion) { + SETBIT(isIdentifiedPid, RolePionDs); + } + if (isSelKaon) { + SETBIT(isIdentifiedPid, RoleKaonDs); + } + if (config.fillHistograms) { + registry.fill(HIST("hScorePionDs"), features.pt, scores[1]); + registry.fill(HIST("hScoreKaonDs"), features.pt, scores[2]); + } + } + + // the track enters the combinatorics if it can play any role in any of the two channels + if (isIdentifiedPid != 0u) { + SETBIT(statusProng, CandidateType::Cand3Prong); + if (config.fillHistograms) { + registry.fill(HIST("hPtSelected"), features.pt); + registry.fill(HIST("hEtaSelected"), features.eta); + } + } + } + + const bool isPositive = track.sign() > 0; + rowSelectedTrack(statusProng, isIdentifiedPid, isPositive); + } + } + + /// Set the magnetic field and the material LUT for the current collision, needed by the + /// re-propagation of tracks associated to a collision that is not their own. + template + void initMagneticField(TCollision const& collision) + { + const auto bc = collision.template bc_as(); + initCCDB(bc, runNumber, ccdb, config.ccdbPathGrpMag, lut, false); + } + + void processTracks(CollisionsWithSel const& collisions, + aod::TrackAssoc const& trackIndices, + TracksWithSelAndPid const& tracks, + aod::BCsWithTimestamps const&) + { + rowSelectedTrack.reserve(trackIndices.size()); + const auto tStart = tickIf(doTiming); + for (const auto& collision : collisions) { + initMagneticField(collision); + const auto groupedTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + runTagSelTracks(collision, tracks, groupedTrackIndices, -1.f, collision.whyRejectColl() == 0); + } + if (doTiming) { + timing[TrackTimeTotal] += elapsedSeconds(tStart); + } + flushTiming(); + } + PROCESS_SWITCH(HfTrackSelectorTagSelTracks, processTracks, "Process tracks without centrality", true); + + void processTracksWithCentFT0C(CollisionsWithCentFT0CAndSel const& collisions, + aod::TrackAssoc const& trackIndices, + TracksWithSelAndPid const& tracks, + aod::BCsWithTimestamps const&) + { + rowSelectedTrack.reserve(trackIndices.size()); + const auto tStart = tickIf(doTiming); + for (const auto& collision : collisions) { + initMagneticField(collision); + const auto groupedTrackIndices = trackIndices.sliceBy(trackIndicesPerCollision, collision.globalIndex()); + runTagSelTracks(collision, tracks, groupedTrackIndices, collision.centFT0C(), collision.whyRejectColl() == 0); + } + if (doTiming) { + timing[TrackTimeTotal] += elapsedSeconds(tStart); + } + flushTiming(); + } + PROCESS_SWITCH(HfTrackSelectorTagSelTracks, processTracksWithCentFT0C, "Process tracks with FT0C centrality as ML input feature", false); +}; + +/// Pre-selection of 3-prong secondary vertices +struct HfMlBasedTrackSelector { + Produces rowTrackIndexProng3; + + struct : ConfigurableGroup { + Configurable fillHistograms{"fillHistograms", true, "fill histograms"}; + // preselection + Configurable ptTolerance{"ptTolerance", 0.1, "pT tolerance in GeV/c for applying preselections before vertex reconstruction"}; + // preselection of 3-prongs using the decay length computed only with the first two tracks + Configurable minTwoTrackDecayLengthFor3Prongs{"minTwoTrackDecayLengthFor3Prongs", 0., "Minimum decay length computed with 2 tracks for 3-prongs to speedup combinatorial"}; + Configurable maxTwoTrackChi2PcaFor3Prongs{"maxTwoTrackChi2PcaFor3Prongs", 1.e10, "Maximum chi2 pca computed with 2 tracks for 3-prongs to speedup combinatorial"}; + Configurable enableTiming{"enableTiming", false, "fill hTiming/hLoopCounters with the CPU and rates of the triple loop (adds two clock reads per fit)"}; + // vertexing + Configurable propagateToPCA{"propagateToPCA", true, "create tracks version propagated to PCA"}; + Configurable useAbsDCA{"useAbsDCA", false, "Minimise abs. distance rather than chi2"}; + Configurable useWeightedFinalPCA{"useWeightedFinalPCA", false, "Recalculate vertex position using track covariances, effective only if useAbsDCA is true"}; + Configurable maxR{"maxR", 200., "reject PCA's above this radius"}; + Configurable maxDZIni{"maxDZIni", 4., "reject (if>0) PCA candidate if tracks DZ exceeds threshold"}; + Configurable minParamChange{"minParamChange", 1.e-3, "stop iterations if largest change of any X is smaller than this"}; + Configurable minRelChi2Change{"minRelChi2Change", 0.9, "stop iterations if chi2/chi2old > this"}; + // CCDB + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable ccdbPathLut{"ccdbPathLut", "GLO/Param/MatLUT", "Path for LUT parametrization"}; + Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; + Configurable ccdbPathGrpMag{"ccdbPathGrpMag", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object (Run 3)"}; + + // D+ cuts + Configurable> binsPtDplusToPiKPi{"binsPtDplusToPiKPi", std::vector{hf_cuts_presel_3prong::vecBinsPt}, "pT bin limits for D+->piKpi pT-dependent cuts"}; + Configurable> cutsDplusToPiKPi{"cutsDplusToPiKPi", {hf_cuts_presel_3prong::Cuts[0], hf_cuts_presel_3prong::NBinsPt, hf_cuts_presel_3prong::NCutVars, hf_cuts_presel_3prong::labelsPt, hf_cuts_presel_3prong::labelsCutVar}, "D+->piKpi selections per pT bin"}; + // Ds+ cuts + Configurable> binsPtDsToKKPi{"binsPtDsToKKPi", std::vector{hf_cuts_presel_ds::vecBinsPt}, "pT bin limits for Ds+->KKPi pT-dependent cuts"}; + Configurable> cutsDsToKKPi{"cutsDsToKKPi", {hf_cuts_presel_ds::Cuts[0], hf_cuts_presel_ds::NBinsPt, hf_cuts_presel_ds::NCutVars, hf_cuts_presel_ds::labelsPt, hf_cuts_presel_ds::labelsCutVar}, "Ds+->KKPi selections per pT bin"}; + } config; + + SliceCache cache; + o2::vertexing::DCAFitterN<2> df2; // 2-prong vertex fitter, only used for the 3-prong speed-up + o2::vertexing::DCAFitterN<3> df3; // 3-prong vertex fitter + Service ccdb{}; + o2::base::MatLayerCylSet* lut{}; + o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; + int runNumber{}; + + // masses of the two mass hypotheses of each channel, in the (same-sign, opposite-sign, + // same-sign) prong ordering used by the combinatorics + std::array, NMassHypos>, NChannels3Prong> arrMass3Prong{}; + // cuts and pT binning, one entry per channel + std::array, NChannels3Prong> cut3Prong{}; + std::array, NChannels3Prong> binsPt3Prong{}; + + /// One track of the collision under study, already propagated to that collision's PV. + struct HfProngCandidate { + o2::track::TrackParCov parCov; + std::array pVec{}; + uint32_t mask{}; ///< aod::HfSelTrack::isIdentifiedPid + int64_t globalIndex{}; ///< index in the track table, written to the skim + }; + + /// Cache of propagated tracks for one collision, split by charge. + struct HfProngCache { + std::vector prongs; + std::vector sameSign; ///< can sit in a same-sign slot: pi(D+), pi(Ds) or K(Ds) + std::vector oppSign; ///< can sit in the opposite-sign slot: K(D+) or K(Ds) + + void clear() + { + prongs.clear(); + sameSign.clear(); + oppSign.clear(); + } + }; + HfProngCache cachePos; + HfProngCache cacheNeg; + + // per-collision accumulators for hTiming / hLoopCounters, reset at each collision + std::array timing{}; + std::array counters{}; + bool doTiming{false}; ///< cached config.enableTiming: read once, used on the hot path + + using SelectedCollisions = soa::Filtered>; + using FilteredTrackAssocSel = soa::Filtered>; + + // filter collisions + Filter filterSelectCollisions = (aod::hf_sel_collision::whyRejectColl == static_cast(0)); + // filter track indices + Filter filterSelectTrackIds = ((aod::hf_sel_track::isSelProng & static_cast(BIT(CandidateType::Cand3Prong))) != 0u); + + Preslice trackIndicesPerCollision = aod::track_association::collisionId; + + Partition positiveFor3Prongs = aod::hf_sel_track::isPositive == true && ((aod::hf_sel_track::isSelProng & static_cast(BIT(CandidateType::Cand3Prong))) != 0u); + Partition negativeFor3Prongs = aod::hf_sel_track::isPositive == false && ((aod::hf_sel_track::isSelProng & static_cast(BIT(CandidateType::Cand3Prong))) != 0u); + + HistogramRegistry registry{"registry"}; + + void init(InitContext const&) + { + if (!doprocess3Prongs) { + return; + } + doTiming = config.enableTiming && config.fillHistograms; + + arrMass3Prong[ChannelDplusToPiKPi] = std::array{std::array{MassPiPlus, MassKPlus, MassPiPlus}, + std::array{MassPiPlus, MassKPlus, MassPiPlus}}; + + arrMass3Prong[ChannelDsToKKPi] = std::array{std::array{MassKPlus, MassKPlus, MassPiPlus}, + std::array{MassPiPlus, MassKPlus, MassKPlus}}; + + // cuts retrieved by json, in the order of Channel3Prong + cut3Prong = {config.cutsDplusToPiKPi, config.cutsDsToKKPi}; + binsPt3Prong = {config.binsPtDplusToPiKPi, config.binsPtDsToKKPi}; + + df2.setPropagateToPCA(config.propagateToPCA); + df2.setMaxR(config.maxR); + df2.setMaxDZIni(config.maxDZIni); + df2.setMinParamChange(config.minParamChange); + df2.setMinRelChi2Change(config.minRelChi2Change); + df2.setUseAbsDCA(config.useAbsDCA); + df2.setWeightedFinalPCA(config.useWeightedFinalPCA); + + df3.setPropagateToPCA(config.propagateToPCA); + df3.setMaxR(config.maxR); + df3.setMaxDZIni(config.maxDZIni); + df3.setMinParamChange(config.minParamChange); + df3.setMinRelChi2Change(config.minRelChi2Change); + df3.setUseAbsDCA(config.useAbsDCA); + df3.setWeightedFinalPCA(config.useWeightedFinalPCA); + + ccdb->setURL(config.ccdbUrl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->get(config.ccdbPathLut)); + runNumber = 0; + + if (config.fillHistograms) { + const AxisSpec axisNumTracks{500, -0.5f, 499.5f, "Number of tracks"}; + const AxisSpec axisNumCands{1000, -0.5f, 999.5f, "Number of candidates"}; + registry.add("hNTracks", "Number of selected tracks;# of selected tracks;entries", {HistType::kTH1D, {axisNumTracks}}); + // seconds and raw counts, accumulated over the run via Fill(bin, weight) + auto hTiming = registry.add("hTiming", "CPU inside the triple loop;;seconds", {HistType::kTH1D, {{NTimingSteps, -0.5f, static_cast(NTimingSteps) - 0.5f}}}); + hTiming->GetXaxis()->SetBinLabel(TimeLoopTotal + 1, "triple loop total"); + hTiming->GetXaxis()->SetBinLabel(TimeFit2Prong + 1, "2-prong vertex fit"); + hTiming->GetXaxis()->SetBinLabel(TimeFit3Prong + 1, "3-prong vertex fit"); + hTiming->GetXaxis()->SetBinLabel(TimeCacheFill + 1, "prong cache fill"); + hTiming->GetXaxis()->SetBinLabel(TimeCachePropagate + 1, "cache re-propagation"); + auto hLoopCounters = registry.add("hLoopCounters", "Triple loop stages;;entries", {HistType::kTH1D, {{NLoopCounters, -0.5f, static_cast(NLoopCounters) - 0.5f}}}); + hLoopCounters->GetXaxis()->SetBinLabel(CountPairsSeen + 1, "pairs seen"); + hLoopCounters->GetXaxis()->SetBinLabel(CountPairsCandidateOk + 1, "pairs passing ML roles"); + hLoopCounters->GetXaxis()->SetBinLabel(CountFit2Prong + 1, "2-prong fits"); + hLoopCounters->GetXaxis()->SetBinLabel(CountPairsRejected2P + 1, "pairs rejected by 2-prong"); + hLoopCounters->GetXaxis()->SetBinLabel(CountTripletsEnumerated + 1, "triplets enumerated"); + hLoopCounters->GetXaxis()->SetBinLabel(CountTripletsWritten + 1, "triplets written"); + hLoopCounters->GetXaxis()->SetBinLabel(CountTracksCached + 1, "tracks cached"); + hLoopCounters->GetXaxis()->SetBinLabel(CountTracksPropagated + 1, "tracks re-propagated"); + registry.add("hVtx3ProngX", "3-prong candidates;#it{x}_{sec. vtx.} (cm);entries", {HistType::kTH1D, {{1000, -2., 2.}}}); + registry.add("hVtx3ProngY", "3-prong candidates;#it{y}_{sec. vtx.} (cm);entries", {HistType::kTH1D, {{1000, -2., 2.}}}); + registry.add("hVtx3ProngZ", "3-prong candidates;#it{z}_{sec. vtx.} (cm);entries", {HistType::kTH1D, {{1000, -20., 20.}}}); + registry.add("hNCand3Prong", "3-prong candidates preselected;# of candidates;entries", {HistType::kTH1D, {axisNumCands}}); + registry.add("hNCand3ProngVsNTracks", "3-prong candidates preselected;# of selected tracks;# of candidates;entries", {HistType::kTH2D, {axisNumTracks, axisNumCands}}); + registry.add("hMassDPlusToPiKPi", "D^{#plus} candidates;inv. mass (#pi K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + registry.add("hMassDsToKKPi", "D_{s}^{#plus} candidates;inv. mass (K K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH1D, {{500, 0., 5.}}}); + } + } + + /// Check whether the two prongs can satisfy any mass hypothesis of either channel, based on their ML role masks. + /// \param maskOpp is the isIdentifiedPid mask of the opposite-sign prong + /// \param maskSame is the isIdentifiedPid mask of the first same-sign prong + static bool isCandidateAllowed(const uint32_t maskOpp, const uint32_t maskSame) + { + const bool okDplus = TESTBIT(maskOpp, RoleKaonDplus) && TESTBIT(maskSame, RolePionDplus); + const bool okDs = TESTBIT(maskOpp, RoleKaonDs) && (TESTBIT(maskSame, RoleKaonDs) || TESTBIT(maskSame, RolePionDs)); + return okDplus || okDs; + } + + /// Check whether the three ML masks can satisfy any mass hypothesis of either channel + /// \param maskOpp is the mask of the opposite-sign prong (prong 1) + /// \param mask1, mask2 are the masks of the same-sign prongs (prongs 0 and 2) + static bool tripletRoleOk(const uint32_t maskOpp, const uint32_t mask1, const uint32_t mask2) + { + const std::array masks{mask1, maskOpp, mask2}; + for (int iChannel = 0; iChannel < NChannels3Prong; iChannel++) { + for (int iHypo = 0; iHypo < NMassHypos; iHypo++) { + bool isHypoAlive = true; + for (int iProng = 0; iProng < NProngs; iProng++) { + const int role = IsKaonProng[iChannel][iHypo][iProng] ? RoleKaonOfChannel[iChannel] : RolePionOfChannel[iChannel]; + if (!TESTBIT(masks[iProng], role)) { + isHypoAlive = false; + break; + } + } + if (isHypoAlive) { + return true; + } + } + } + return false; + } + + /// Require the ML role of each prong to match the mass hypothesis under test. + /// The opposite-sign prong is the kaon in both channels; the same-sign pair is (pi, pi) for the + /// D+ and (K, pi) or (pi, K) for the Ds, which is exactly what the two mass hypotheses encode. + /// \param isIdentifiedPid0,1,2 are the aod::HfSelTrack::isIdentifiedPid masks of the prongs, in + /// the (same-sign, opposite-sign, same-sign) ordering + /// \param whichHypo information of the mass hypotheses that are still alive + /// \param isSelected is a bitmap with selection outcome + void applyMlRoleSelection(const uint32_t isIdentifiedPid0, const uint32_t isIdentifiedPid1, const uint32_t isIdentifiedPid2, + std::array& whichHypo, auto& isSelected) + { + const std::array isIdentifiedPid{isIdentifiedPid0, isIdentifiedPid1, isIdentifiedPid2}; + + for (int iChannel = 0; iChannel < NChannels3Prong; iChannel++) { + for (int iHypo = 0; iHypo < NMassHypos; iHypo++) { + for (int iProng = 0; iProng < NProngs; iProng++) { + const int role = IsKaonProng[iChannel][iHypo][iProng] ? RoleKaonOfChannel[iChannel] : RolePionOfChannel[iChannel]; + if (!TESTBIT(isIdentifiedPid[iProng], role)) { + CLRBIT(whichHypo[iChannel], iHypo); + break; + } + } + } + if (whichHypo[iChannel] == 0) { + CLRBIT(isSelected, iChannel); + } + } + } + + /// Method to perform selections on difference from nominal mass for phi decay + /// \param binPt pt bin for the cuts + /// \param pVecTrack0 is the momentum array of the first daughter track + /// \param pVecTrack1 is the momentum array of the second daughter track + /// \param pVecTrack2 is the momentum array of the third daughter track + /// \param whichHypo information of the mass hypoteses that were selected + /// \param isSelected is a bitmap with selection outcome + template + void applyPreselectionPhiDecay(const int binPt, T1 const& pVecTrack0, T1 const& pVecTrack1, T1 const& pVecTrack2, + std::array& whichHypo, auto& isSelected) + { + const double deltaMassMax = cut3Prong[ChannelDsToKKPi].get(binPt, 5u); // 5u == "deltaMassKK" + if (TESTBIT(whichHypo[ChannelDsToKKPi], 0)) { + const double mass2PhiKKPi = RecoDecay::m2(std::array{pVecTrack0, pVecTrack1}, std::array{arrMass3Prong[ChannelDsToKKPi][0][0], arrMass3Prong[ChannelDsToKKPi][0][1]}); + if (mass2PhiKKPi > (MassPhi + deltaMassMax) * (MassPhi + deltaMassMax) || (deltaMassMax < MassPhi && mass2PhiKKPi < (MassPhi - deltaMassMax) * (MassPhi - deltaMassMax))) { + CLRBIT(whichHypo[ChannelDsToKKPi], 0); + } + } + if (TESTBIT(whichHypo[ChannelDsToKKPi], 1)) { + const double mass2PhiPiKK = RecoDecay::m2(std::array{pVecTrack1, pVecTrack2}, std::array{arrMass3Prong[ChannelDsToKKPi][1][1], arrMass3Prong[ChannelDsToKKPi][1][2]}); + if (mass2PhiPiKK > (MassPhi + deltaMassMax) * (MassPhi + deltaMassMax) || (deltaMassMax < MassPhi && mass2PhiPiKK < (MassPhi - deltaMassMax) * (MassPhi - deltaMassMax))) { + CLRBIT(whichHypo[ChannelDsToKKPi], 1); + } + } + if (whichHypo[ChannelDsToKKPi] == 0) { + CLRBIT(isSelected, ChannelDsToKKPi); + } + } + + /// Method to perform selections for 3-prong candidates before vertex reconstruction + /// \param pVecTrack0 is the momentum array of the first daughter track + /// \param pVecTrack1 is the momentum array of the second daughter track + /// \param pVecTrack2 is the momentum array of the third daughter track + /// \param whichHypo information of the mass hypotheses that were selected + /// \param isSelected is a bitmap with selection outcome + template + void applyPreselection3Prong(T2 const& pVecTrack0, T2 const& pVecTrack1, T2 const& pVecTrack2, + std::array& whichHypo, auto& isSelected) + { + const auto pt = RecoDecay::pt(pVecTrack0, pVecTrack1, pVecTrack2) + config.ptTolerance; // add tolerance because of no reco decay vertex + + for (int iChannel = 0; iChannel < NChannels3Prong; iChannel++) { + if (!TESTBIT(isSelected, iChannel)) { + whichHypo[iChannel] = 0; + continue; + } + + // pT + const auto binPt = findBin(&binsPt3Prong[iChannel], pt); + // return immediately if it is outside the defined pT bins + if (binPt == -1) { + CLRBIT(isSelected, iChannel); + whichHypo[iChannel] = 0; + continue; + } + + // invariant mass + const double minMass = cut3Prong[iChannel].get(binPt, 0u); + const double maxMass = cut3Prong[iChannel].get(binPt, 1u); + if (minMass >= 0. && maxMass > 0.) { + std::array massHypos = {0., 0.}; + const std::array arrMom{pVecTrack0, pVecTrack1, pVecTrack2}; + const double min2 = minMass * minMass; + const double max2 = maxMass * maxMass; + massHypos[0] = RecoDecay::m2(arrMom, arrMass3Prong[iChannel][0]); + massHypos[1] = (iChannel != ChannelDplusToPiKPi) ? RecoDecay::m2(arrMom, arrMass3Prong[iChannel][1]) : massHypos[0]; + if (massHypos[0] < min2 || massHypos[0] >= max2) { + CLRBIT(whichHypo[iChannel], 0); + } + if (massHypos[1] < min2 || massHypos[1] >= max2) { + CLRBIT(whichHypo[iChannel], 1); + } + if (whichHypo[iChannel] == 0) { + CLRBIT(isSelected, iChannel); + continue; + } + } + + // prong pT + const auto ptProngMin = cut3Prong[iChannel].get(binPt, 4u); // 4u == "ptProngMin" + const auto pt2ProngMin = ptProngMin * ptProngMin; + if (RecoDecay::pt2(pVecTrack0) < pt2ProngMin || RecoDecay::pt2(pVecTrack1) < pt2ProngMin || RecoDecay::pt2(pVecTrack2) < pt2ProngMin) { + CLRBIT(isSelected, iChannel); + continue; + } + + if (iChannel == ChannelDsToKKPi) { + applyPreselectionPhiDecay(binPt, pVecTrack0, pVecTrack1, pVecTrack2, whichHypo, isSelected); + } + } + } + + /// Method to perform selections for a 2-track vertex used to speed up the 3-prong combinatorics + /// \param secVtx is the secondary vertex + /// \param primVtx is the primary vertex + /// \param dcaFitter is the DCAFitter used for the 2-track vertex + /// \returns true if the candidate is selected + template + bool isTwoTrackVertexSelectedFor3Prongs(const T1& secVtx, const T2& primVtx, const T3& dcaFitter) + { + if (dcaFitter.getChi2AtPCACandidate() > config.maxTwoTrackChi2PcaFor3Prongs) { + return false; + } + const auto decLen = RecoDecay::distance(primVtx, secVtx); + return static_cast(decLen >= config.minTwoTrackDecayLengthFor3Prongs); + } + + /// Method to perform selections for 3-prong candidates after vertex reconstruction + /// \param pVecCand is the array for the candidate momentum after reconstruction of secondary vertex + /// \param secVtx is the secondary vertex + /// \param primVtx is the primary vertex + /// \param isSelected is a bitmap with selection outcome + template + void applySelection3Prong(const T1& pVecCand, const T2& secVtx, const T3& primVtx, auto& isSelected) + { + if (isSelected == 0) { + return; + } + + const auto pt = RecoDecay::pt(pVecCand); + for (int iChannel = 0; iChannel < NChannels3Prong; iChannel++) { + if (!TESTBIT(isSelected, iChannel)) { + continue; + } + + // pT + const auto binPt = findBin(&binsPt3Prong[iChannel], pt); + if (binPt == -1) { // cut if it is outside the defined pT bins + CLRBIT(isSelected, iChannel); + continue; + } + + // cos of pointing angle + const auto cpa = RecoDecay::cpa(primVtx, secVtx, pVecCand); + if (cpa < cut3Prong[iChannel].get(binPt, 2u)) { // 2u == "cosp" + CLRBIT(isSelected, iChannel); + continue; + } + + // decay length + const auto decayLength = RecoDecay::distance(primVtx, secVtx); + if (decayLength < cut3Prong[iChannel].get(binPt, 3u)) { // 3u == "decL" + CLRBIT(isSelected, iChannel); + } + } + } + + /// Translate the compact per-channel selection bitmap into the hfflag written to aod::Hf3Prongs, + /// which uses the hf_cand_3prong::DecayType bit positions. + uint8_t hfFlagOfSelection(const uint32_t isSelected) const + { + uint8_t hfFlag{0}; + for (int iChannel = 0; iChannel < NChannels3Prong; iChannel++) { + if (TESTBIT(isSelected, iChannel)) { + SETBIT(hfFlag, DecayTypeOfChannel[iChannel]); + } + } + return hfFlag; + } + + /// Reconstruct and preselect one 3-prong candidate, and fill its table row if it survives. + /// \param collision is the collision the candidate belongs to + /// \param trackParVar0,1,2 are the track parametrisations, in the (same-sign, opposite-sign, + /// same-sign) prong ordering + /// \param pVecTrack0,1,2 are the corresponding momenta at the primary vertex + /// \param isIdentifiedPid0,1,2 are the corresponding ML role masks + /// \param globalIndex0,1,2 are the corresponding track global indices + template + void processTriplet(SelectedCollisions::iterator const& collision, + TTrackParVar const& trackParVar0, TTrackParVar const& trackParVar1, TTrackParVar const& trackParVar2, + std::array const& pVecTrack0, std::array const& pVecTrack1, std::array const& pVecTrack2, + const uint32_t isIdentifiedPid0, const uint32_t isIdentifiedPid1, const uint32_t isIdentifiedPid2, + const int64_t globalIndex0, const int64_t globalIndex1, const int64_t globalIndex2) + { + uint32_t isSelected3ProngCand = BIT(NChannels3Prong) - 1; + std::array whichHypo3Prong{}; + whichHypo3Prong.fill(BIT(NMassHypos) - 1); // all mass hypotheses alive + + applyMlRoleSelection(isIdentifiedPid0, isIdentifiedPid1, isIdentifiedPid2, whichHypo3Prong, isSelected3ProngCand); + if (isSelected3ProngCand == 0) { + return; + } + + applyPreselection3Prong(pVecTrack0, pVecTrack1, pVecTrack2, whichHypo3Prong, isSelected3ProngCand); + if (isSelected3ProngCand == 0) { + return; + } + + // reconstruct the 3-prong secondary vertex + const auto tStart3Prong = tickIf(doTiming); + int nVtxFrom3ProngFitter = 0; + try { + nVtxFrom3ProngFitter = df3.process(trackParVar0, trackParVar1, trackParVar2); + } catch (...) { + nVtxFrom3ProngFitter = 0; + } + if (doTiming) { + timing[TimeFit3Prong] += elapsedSeconds(tStart3Prong); + } + if (nVtxFrom3ProngFitter == 0) { + return; + } + + // get secondary vertex + const auto& secondaryVertex3 = df3.getPCACandidate(); + // get track momenta + std::array pvec0{}; + std::array pvec1{}; + std::array pvec2{}; + df3.getTrack(0).getPxPyPzGlo(pvec0); + df3.getTrack(1).getPxPyPzGlo(pvec1); + df3.getTrack(2).getPxPyPzGlo(pvec2); + const auto pVecCandProng3 = RecoDecay::pVec(pvec0, pvec1, pvec2); + + // 3-prong selections after secondary vertex + const std::array pvCoord{collision.posX(), collision.posY(), collision.posZ()}; + applySelection3Prong(pVecCandProng3, secondaryVertex3, pvCoord, isSelected3ProngCand); + if (isSelected3ProngCand == 0) { + return; + } + + // fill table row + rowTrackIndexProng3(collision.globalIndex(), globalIndex0, globalIndex1, globalIndex2, hfFlagOfSelection(isSelected3ProngCand)); + + // fill histograms + if (config.fillHistograms) { + registry.fill(HIST("hVtx3ProngX"), secondaryVertex3[0]); + registry.fill(HIST("hVtx3ProngY"), secondaryVertex3[1]); + registry.fill(HIST("hVtx3ProngZ"), secondaryVertex3[2]); + const std::array arr3Mom{pvec0, pvec1, pvec2}; + for (int iChannel = 0; iChannel < NChannels3Prong; iChannel++) { + if (!TESTBIT(isSelected3ProngCand, iChannel)) { + continue; + } + if (TESTBIT(whichHypo3Prong[iChannel], 0)) { + const auto mass3Prong = RecoDecay::m(arr3Mom, arrMass3Prong[iChannel][0]); + if (iChannel == ChannelDplusToPiKPi) { + registry.fill(HIST("hMassDPlusToPiKPi"), mass3Prong); + } else { + registry.fill(HIST("hMassDsToKKPi"), mass3Prong); + } + } + // the two D+ hypotheses are identical, only the Ds has a second one worth filling + if (iChannel == ChannelDsToKKPi && TESTBIT(whichHypo3Prong[iChannel], 1)) { + registry.fill(HIST("hMassDsToKKPi"), RecoDecay::m(arr3Mom, arrMass3Prong[iChannel][1])); + } + } + } + } + + /// Build the per-collision cache of prongs propagated to the collision's primary vertex. + /// \param collision is the collision under study + /// \param trackIndices are the track associations of this collision + /// \param cacheThis is the prong cache to be filled + template + void fillProngCache(SelectedCollisions::iterator const& collision, + TTrackIndices const& trackIndices, HfProngCache& cacheThis) + { + const auto tStartCache = tickIf(doTiming); + const auto thisCollId = collision.globalIndex(); + for (const auto& trackIndex : trackIndices) { + const auto track = trackIndex.template track_as(); + HfProngCandidate prong{getTrackParCov(track), track.pVector(), trackIndex.isIdentifiedPid(), track.globalIndex()}; + ++counters[CountTracksCached]; + if (thisCollId != track.collisionId()) { // this is not the "default" collision for this track, we have to re-propagate it + const auto tStartPropagate = tickIf(doTiming); + ++counters[CountTracksPropagated]; + std::array dcaInfo{track.dcaXY(), track.dcaZ()}; + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, prong.parCov, 2.f, noMatCorr, &dcaInfo); + getPxPyPz(prong.parCov, prong.pVec); + if (doTiming) { + timing[TimeCachePropagate] += elapsedSeconds(tStartPropagate); + } + } + const int index = static_cast(cacheThis.prongs.size()); + cacheThis.prongs.push_back(prong); + if ((prong.mask & MaskSameSignAny) != 0u) { + cacheThis.sameSign.push_back(index); + } + if ((prong.mask & MaskOppSignAny) != 0u) { + cacheThis.oppSign.push_back(index); + } + } + if (doTiming) { + timing[TimeCacheFill] += elapsedSeconds(tStartCache); + } + } + + /// Run the combinatorial loop over the two same-sign prongs and the opposite-sign prong. + /// \param collision is the collision under study + /// \param sameSignCache holds the prongs of the charge the candidate carries; its sameSign + /// list supplies the two same-sign slots + /// \param oppSignCache holds the opposite charge; its oppSign list supplies the kaon slot + void runCombinatorics(SelectedCollisions::iterator const& collision, + HfProngCache const& sameSignCache, HfProngCache const& oppSignCache) + { + const std::vector& sameSignList = sameSignCache.sameSign; + const std::vector& oppSignList = oppSignCache.oppSign; + constexpr std::size_t NSameSignProngs = NProngs - 1; // two of the three prongs carry the candidate charge + if (sameSignList.size() < NSameSignProngs || oppSignList.empty()) { + return; + } + const auto tStartLoop = tickIf(doTiming); + const std::array pvCoord2Prong{collision.posX(), collision.posY(), collision.posZ()}; + const bool useTwoTrackVertex = config.minTwoTrackDecayLengthFor3Prongs > 0.f || config.maxTwoTrackChi2PcaFor3Prongs < 1.e9f; // o2-linter: disable="magic-number" (default maxTwoTrackChi2PcaFor3Prongs is 1.e10) + + for (const int iOpp : oppSignList) { // o2-linter: disable=const-ref-in-for-loop (int elements) + const auto& prongOpp = oppSignCache.prongs[iOpp]; + + for (std::size_t i1 = 0; i1 + 1 < sameSignList.size(); ++i1) { + const auto& prong1 = sameSignCache.prongs[sameSignList[i1]]; + ++counters[CountPairsSeen]; + if (!isCandidateAllowed(prongOpp.mask, prong1.mask)) { + continue; + } + ++counters[CountPairsCandidateOk]; + + // optional 2-track vertex to skip the pair early + if (useTwoTrackVertex) { + const auto tStart2Prong = tickIf(doTiming); + ++counters[CountFit2Prong]; + int nVtxFrom2ProngFitter = 0; + try { + nVtxFrom2ProngFitter = df2.process(prong1.parCov, prongOpp.parCov); + } catch (...) { + } + const bool pairOk = (nVtxFrom2ProngFitter != 0) && + isTwoTrackVertexSelectedFor3Prongs(df2.getPCACandidate(), pvCoord2Prong, df2); + if (doTiming) { + timing[TimeFit2Prong] += elapsedSeconds(tStart2Prong); + } + if (!pairOk) { + ++counters[CountPairsRejected2P]; + continue; + } + } + + for (std::size_t i2 = i1 + 1; i2 < sameSignList.size(); ++i2) { + const auto& prong2 = sameSignCache.prongs[sameSignList[i2]]; + if (!tripletRoleOk(prongOpp.mask, prong1.mask, prong2.mask)) { + continue; + } + ++counters[CountTripletsEnumerated]; + + processTriplet(collision, prong1.parCov, prongOpp.parCov, prong2.parCov, + prong1.pVec, prongOpp.pVec, prong2.pVec, + prong1.mask, prongOpp.mask, prong2.mask, + prong1.globalIndex, prongOpp.globalIndex, prong2.globalIndex); + } + } + } + if (doTiming) { + timing[TimeLoopTotal] += elapsedSeconds(tStartLoop); + } + } + + void process3Prongs(SelectedCollisions const& collisions, + aod::BCsWithTimestamps const&, + FilteredTrackAssocSel const&, + aod::TracksWCovDca const& /*tracks*/) + { + for (const auto& collision : collisions) { + // set the magnetic field from CCDB + const auto bc = collision.bc_as(); + initCCDB(bc, runNumber, ccdb, config.ccdbPathGrpMag, lut, false); + df2.setBz(o2::base::Propagator::Instance()->getNominalBz()); + df3.setBz(o2::base::Propagator::Instance()->getNominalBz()); + + // used to calculate number of candidates per event + auto nCand3 = rowTrackIndexProng3.lastIndex(); + + timing.fill(0.); + counters.fill(0); + + const auto thisCollId = collision.globalIndex(); + + const auto allPos = positiveFor3Prongs->sliceByCached(aod::track::collisionId, thisCollId, cache); + const auto allNeg = negativeFor3Prongs->sliceByCached(aod::track::collisionId, thisCollId, cache); + const int nTracks = allPos.size() + allNeg.size(); + + // We fill the prong cache for each collision, so that the prongs are propagated to the PV only once. + cachePos.clear(); + cacheNeg.clear(); + fillProngCache(collision, allPos, cachePos); + fillProngCache(collision, allNeg, cacheNeg); + + // D+ -> pi+ K- pi+ / Ds -> K+ K- pi+ and their charge conjugates: the same-sign pair carries + // the charge of the candidate, the opposite-sign prong is the kaon in both channels + runCombinatorics(collision, cachePos, cacheNeg); + runCombinatorics(collision, cacheNeg, cachePos); + + nCand3 = rowTrackIndexProng3.lastIndex() - nCand3; // number of 3-prong candidates in this collision + counters[CountTripletsWritten] = nCand3; + + if (config.fillHistograms) { + // Fill(bin, weight) so the bins accumulate seconds and counts over the whole run + for (int iStep = 0; iStep < NTimingSteps; iStep++) { + registry.fill(HIST("hTiming"), iStep, timing[iStep]); + } + for (int iStep = 0; iStep < NLoopCounters; iStep++) { + registry.fill(HIST("hLoopCounters"), iStep, static_cast(counters[iStep])); + } + registry.fill(HIST("hNTracks"), nTracks); + registry.fill(HIST("hNCand3Prong"), nCand3); + registry.fill(HIST("hNCand3ProngVsNTracks"), nTracks, nCand3); + } + } + } + PROCESS_SWITCH(HfMlBasedTrackSelector, process3Prongs, "Process 3-prong skim", true); + + void processNo3Prongs(SelectedCollisions const&) + { + // dummy + } + PROCESS_SWITCH(HfMlBasedTrackSelector, processNo3Prongs, "Do not process 3-prongs", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec workflow{}; + workflow.push_back(adaptAnalysisTask(cfgc)); + workflow.push_back(adaptAnalysisTask(cfgc)); + workflow.push_back(adaptAnalysisTask(cfgc)); + return workflow; +} diff --git a/PWGHF/D2H/Tasks/taskB0Reduced.cxx b/PWGHF/D2H/Tasks/taskB0Reduced.cxx index dd508c8f7ba..9ea6b4696bc 100644 --- a/PWGHF/D2H/Tasks/taskB0Reduced.cxx +++ b/PWGHF/D2H/Tasks/taskB0Reduced.cxx @@ -10,13 +10,16 @@ // or submit itself to any jurisdiction. /// \file taskB0Reduced.cxx -/// \brief B0 → D- π+ → (π- K+ π-) π+ analysis task +/// \brief B0 → D-/D*- π+ → (π- K+ π-) π+ analysis task /// /// \author Alexandre Bigot , IPHC Strasbourg /// \author Fabrizio Grosa , CERN +/// \author Fabrizio Chinu , Universita and INFN Torino +/// \author Marcello Di Costanzo , Polytechnic University of Turin and INFN #include "PWGHF/Core/HfHelper.h" #include "PWGHF/D2H/DataModel/ReducedDataModel.h" +#include "PWGHF/D2H/Utils/utilsFlow.h" #include "PWGHF/DataModel/CandidateReconstructionTables.h" #include "PWGHF/DataModel/CandidateSelectionTables.h" @@ -38,6 +41,7 @@ #include #include +#include #include #include #include @@ -47,6 +51,7 @@ using namespace o2::aod; using namespace o2::analysis; using namespace o2::framework; using namespace o2::framework::expressions; +using namespace o2::analysis::hf_flow_utils; namespace o2::aod { @@ -101,6 +106,8 @@ DECLARE_SOA_COLUMN(CpaD, cpaD, float); DECLARE_SOA_COLUMN(CpaDXY, cpaDXY, float); //! Cosine pointing angle of D candidate to PV in transverse plane DECLARE_SOA_COLUMN(CpaDToB, cpaDToB, float); //! Cosine pointing angle of D candidate to B decay vertex DECLARE_SOA_COLUMN(CpaDToBXY, cpaDToBXY, float); //! Cosine pointing angle of D candidate to B decay vertex in transverse plane +DECLARE_SOA_COLUMN(ScalarProd, scalarProd, float); //! Scalar product of B candidate +DECLARE_SOA_COLUMN(Centrality, centrality, float); //! Centrality of the collision DECLARE_SOA_COLUMN(MaxNormalisedDeltaIP, maxNormalisedDeltaIP, float); //! Maximum normalized difference between measured and expected impact parameter of candidate prongs DECLARE_SOA_COLUMN(MlScoreSig, mlScoreSig, float); //! ML score for signal class DECLARE_SOA_COLUMN(FlagWrongCollision, flagWrongCollision, int8_t); //! Flag for association with wrong collision @@ -124,6 +131,8 @@ DECLARE_SOA_TABLE(HfRedCandB0Lites, "AOD", "HFREDCANDB0LITE", //! Table with som hf_cand_b0_lite::MaxNormalisedDeltaIP, hf_cand_b0_lite::MlScoreSig, hf_sel_candidate_b0::IsSelB0ToDPi, + hf_cand_b0_lite::ScalarProd, + hf_cand_b0_lite::Centrality, // D meson features hf_cand_b0_lite::MD, hf_cand_b0_lite::PtD, @@ -201,7 +210,12 @@ struct HfTaskB0Reduced { Configurable fillBackground{"fillBackground", false, "Flag to enable filling of background histograms/sparses/tree (only MC)"}; Configurable downSampleBkgFactor{"downSampleBkgFactor", 1., "Fraction of background candidates to keep for ML trainings"}; Configurable ptMaxForDownSample{"ptMaxForDownSample", 10., "Maximum pt for the application of the downsampling factor"}; + Configurable centralityEstimator{"centralityEstimator", 1, "Centrality estimator (FT0M: 0, FT0C: 1)"}; + Configurable harmonic{"harmonic", 2, "harmonic number"}; + Configurable qVecDetector{"qVecDetector", 3, "Detector for Q vector estimation (FT0M: 1, FT0A: 2, FT0C: 3, TPC Pos: 4, TPC Neg: 5, TPC Tot: 6)"}; + using CollisionsWithCents = soa::Join; + using CollisionsWithCentsQvecs = soa::Join; using TracksBachPions = soa::Join; using CandsDplus = soa::Join; using CandsDstar = soa::Join; @@ -213,8 +227,8 @@ struct HfTaskB0Reduced { void init(InitContext&) { - std::array processFuncData{doprocessDataDplusPi, doprocessDataDplusPiWithDmesMl, doprocessDataDplusPiWithB0Ml, - doprocessDataDstarPi, doprocessDataDstarPiWithDmesMl}; + std::array processFuncData{doprocessDataDplusPi, doprocessDataDplusPiWithDmesMl, doprocessDataDplusPiWithDmesMlScalarProd, doprocessDataDplusPiWithB0Ml, doprocessDataDplusPiWithB0MlScalarProd, + doprocessDataDstarPi, doprocessDataDstarPiWithDmesMl, doprocessDataDstarPiWithDmesMlScalarProd}; if ((std::accumulate(processFuncData.begin(), processFuncData.end(), 0)) > 1) { LOGP(fatal, "Only one process function for data can be enabled at a time."); } @@ -241,10 +255,9 @@ struct HfTaskB0Reduced { const AxisSpec axisPtPi{100, 0.f, 10.f}; const AxisSpec axisPtSoftPi{100, 0.f, 1.f}; - std::array processFuncDplusPi = {doprocessDataDplusPi, doprocessDataDplusPiWithDmesMl, doprocessDataDplusPiWithB0Ml, - doprocessMcDplusPi, doprocessMcDplusPiWithDecayTypeCheck, doprocessMcDplusPiWithDmesMl, - doprocessMcDplusPiWithDmesMlAndDecayTypeCheck, doprocessMcDplusPiWithB0Ml, - doprocessMcDplusPiWithB0MlAndDecayTypeCheck}; + std::array processFuncDplusPi = {doprocessDataDplusPi, doprocessDataDplusPiWithDmesMl, doprocessDataDplusPiWithDmesMlScalarProd, doprocessDataDplusPiWithB0Ml, doprocessDataDplusPiWithB0MlScalarProd, + doprocessMcDplusPi, doprocessMcDplusPiWithDecayTypeCheck, doprocessMcDplusPiWithDmesMl, doprocessMcDplusPiWithDmesMlAndDecayTypeCheck, + doprocessMcDplusPiWithB0Ml, doprocessMcDplusPiWithB0MlAndDecayTypeCheck}; const AxisSpec axisMass = ((std::accumulate(processFuncDplusPi.begin(), processFuncDplusPi.end(), 0)) > 0) ? axisMassDminus : axisMassDeltaMassDStar; std::string dMesSpecie; if ((std::accumulate(processFuncDplusPi.begin(), processFuncDplusPi.end(), 0)) > 0) { @@ -253,7 +266,8 @@ struct HfTaskB0Reduced { dMesSpecie += "D^{0}#pi^{#minus}"; } - if (doprocessDataDplusPi || doprocessDataDplusPiWithDmesMl || doprocessDataDplusPiWithB0Ml || doprocessDataDstarPi || doprocessDataDstarPiWithDmesMl) { + if (doprocessDataDplusPi || doprocessDataDplusPiWithDmesMl || doprocessDataDplusPiWithB0Ml || doprocessDataDstarPi || doprocessDataDstarPiWithDmesMl || + doprocessDataDplusPiWithDmesMlScalarProd || doprocessDataDplusPiWithB0MlScalarProd || doprocessDataDstarPiWithDmesMlScalarProd) { if (fillHistograms) { registry.add("hMass", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});#it{M} (D#pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {axisPtB0, axisMassB0}}); registry.add("hDecLength", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate decay length (cm);entries", {HistType::kTH2F, {axisPtB0, axisDecayLength}}); @@ -283,19 +297,19 @@ struct HfTaskB0Reduced { registry.add("hDcaProng2", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});prong 2 (#pi^{#plus}) DCAxy to prim. vertex (cm);entries", {HistType::kTH2F, {axisPtB0, axisDca}}); } // ML scores of D- daughter - if (doprocessDataDplusPiWithDmesMl || doprocessDataDstarPiWithDmesMl) { + if (doprocessDataDplusPiWithDmesMl || doprocessDataDplusPiWithDmesMlScalarProd || doprocessDataDstarPiWithDmesMl || doprocessDataDstarPiWithDmesMlScalarProd) { registry.add("hMlScoreBkgD", Form("B^{0} candidates;#it{p}_{T}(%s) (GeV/#it{c});prong0, %s ML background score;entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisMlScore}}); registry.add("hMlScorePromptD", Form("B^{0} candidates;#it{p}_{T}(%s) (GeV/#it{c});prong0, %s ML prompt score;entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisMlScore}}); registry.add("hMlScoreNonPromptD", Form("B^{0} candidates;#it{p}_{T}(%s) (GeV/#it{c});prong0, %s ML nonprompt score;entries", dMesSpecie.c_str(), dMesSpecie.c_str()), {HistType::kTH2F, {axisPtDminus, axisMlScore}}); } // ML scores of B0 candidate - if (doprocessDataDplusPiWithB0Ml) { + if (doprocessDataDplusPiWithB0Ml || doprocessDataDplusPiWithB0MlScalarProd) { registry.add("hMlScoreSigB0", "B^{0} candidates;#it{p}_{T}(B^{0}) (GeV/#it{c});prong0, B^{0} ML signal score;entries", {HistType::kTH2F, {axisPtB0, axisMlScore}}); } } if (fillSparses) { - if (!(doprocessDataDplusPiWithDmesMl || doprocessDataDplusPiWithB0Ml || doprocessDataDstarPiWithDmesMl)) { + if (!(doprocessDataDplusPiWithDmesMl || doprocessDataDplusPiWithDmesMlScalarProd || doprocessDataDplusPiWithB0Ml || doprocessDataDplusPiWithB0MlScalarProd || doprocessDataDstarPiWithDmesMl || doprocessDataDstarPiWithDmesMlScalarProd)) { if ((std::accumulate(processFuncDplusPi.begin(), processFuncDplusPi.end(), 0)) > 0) { registry.add("hMassPtCutVars", "B^{0} candidates;#it{M} (D#pi) (GeV/#it{c}^{2});#it{p}_{T}(B^{0}) (GeV/#it{c});B^{0} candidate decay length (cm);B^{0} candidate norm. decay length XY (cm);B^{0} candidate impact parameter product (cm);B^{0} candidate cos(#vartheta_{P});#it{M} (K#pi) (GeV/#it{c}^{2});#it{p}_{T}(%s) (GeV/#it{c});%s candidate decay length (cm);%s candidate cos(#vartheta_{P})", {HistType::kTHnSparseF, {axisMassB0, axisPtB0, axisDecayLength, axisNormDecayLength, axisImpParProd, axisCosp, axisMass, axisPtDminus, axisDecayLength, axisCosp}}); } else { @@ -456,10 +470,13 @@ struct HfTaskB0Reduced { /// \param withDecayTypeCheck is the flag to enable MC with decay type check /// \param withDmesMl is the flag to enable the filling with ML scores for the D- daughter /// \param withB0Ml is the flag to enable the filling with ML scores for the B0 candidate + /// \param withScalarProd is the flag to enable the filling with scalar product + /// \param collision is the collision /// \param candidate is the B0 candidate /// \param candidatesD is the table with D- candidates - template - void fillCandDStarPi(Cand const& candidate, + template + void fillCandDStarPi(Collision const& collision, + Cand const& candidate, SoftPions const& softPions, CandsDmes const&) { @@ -600,11 +617,18 @@ struct HfTaskB0Reduced { float prong0MlScorePrompt = -1.; float prong0MlScoreNonprompt = -1.; float const candidateMlScoreSig = -1; + float scalarProd = -1; if constexpr (WithDmesMl) { prong0MlScoreBkg = candidate.prong0MlScoreBkg(); prong0MlScorePrompt = candidate.prong0MlScorePrompt(); prong0MlScoreNonprompt = candidate.prong0MlScoreNonprompt(); } + if constexpr (WithScalarProd) { + auto qVecs = getQvec(collision, qVecDetector.value); + float xQVec = qVecs[0]; + float yQVec = qVecs[1]; + scalarProd = std::cos(harmonic * candidate.phi()) * xQVec + std::sin(harmonic * candidate.phi()) * yQVec; + } auto prongBachPi = candidate.template prongBachPi_as(); float ptMother = -1.; @@ -630,6 +654,8 @@ struct HfTaskB0Reduced { candidate.maxNormalisedDeltaIP(), candidateMlScoreSig, candidate.isSelB0ToDPi(), + scalarProd, + centralityEstimator == 0 ? collision.centFT0M() : collision.centFT0C(), // D-meson features invMassD, ptD, @@ -700,10 +726,13 @@ struct HfTaskB0Reduced { /// \param withDecayTypeCheck is the flag to enable MC with decay type check /// \param withDmesMl is the flag to enable the filling with ML scores for the D- daughter /// \param withB0Ml is the flag to enable the filling with ML scores for the B0 candidate + /// \param withScalarProd is the flag to enable the filling with scalar product + /// \param collision is the collision /// \param candidate is the B0 candidate /// \param candidatesD is the table with D- candidates - template - void fillCand(Cand const& candidate, + template + void fillCand(Collision const& collision, + Cand const& candidate, CandsDmes const&) { auto ptCandB0 = candidate.pt(); @@ -860,6 +889,7 @@ struct HfTaskB0Reduced { float prong0MlScorePrompt = -1.; float prong0MlScoreNonprompt = -1.; float candidateMlScoreSig = -1; + float scalarProd = -1; if constexpr (WithDmesMl) { prong0MlScoreBkg = candidate.prong0MlScoreBkg(); prong0MlScorePrompt = candidate.prong0MlScorePrompt(); @@ -868,6 +898,12 @@ struct HfTaskB0Reduced { if constexpr (WithB0Ml) { candidateMlScoreSig = candidate.mlProbB0ToDPi(); } + if constexpr (WithScalarProd) { + auto qVecs = getQvec(collision, qVecDetector.value); + float xQVec = qVecs[0]; + float yQVec = qVecs[1]; + scalarProd = std::cos(harmonic * candidate.phi()) * xQVec + std::sin(harmonic * candidate.phi()) * yQVec; + } auto prong1 = candidate.template prong1_as(); float ptMother = -1.; @@ -893,6 +929,8 @@ struct HfTaskB0Reduced { candidate.maxNormalisedDeltaIP(), candidateMlScoreSig, candidate.isSelB0ToDPi(), + scalarProd, + centralityEstimator == 0 ? collision.centFT0M() : collision.centFT0C(), // D-meson features invMassD, ptD, @@ -997,7 +1035,8 @@ struct HfTaskB0Reduced { } // Process functions - void processDataDplusPi(soa::Filtered> const& candidates, + void processDataDplusPi(CollisionsWithCents const& collisions, + soa::Filtered> const& candidates, CandsDplus const& candidatesD, TracksBachPions const&) { @@ -1005,12 +1044,13 @@ struct HfTaskB0Reduced { if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } - fillCand(candidate, candidatesD); + fillCand(collisions.rawIteratorAt(candidate.collisionId()), candidate, candidatesD); } // candidate loop } // processDataDplusPi PROCESS_SWITCH(HfTaskB0Reduced, processDataDplusPi, "Process data without ML scores for B0 and Dplus daughter", true); - void processDataDplusPiWithDmesMl(soa::Filtered> const& candidates, + void processDataDplusPiWithDmesMl(CollisionsWithCents const& collisions, + soa::Filtered> const& candidates, CandsDplus const& candidatesD, TracksBachPions const&) { @@ -1018,12 +1058,27 @@ struct HfTaskB0Reduced { if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } - fillCand(candidate, candidatesD); + fillCand(collisions.rawIteratorAt(candidate.collisionId()), candidate, candidatesD); } // candidate loop } // processDataDplusPiWithDmesMl PROCESS_SWITCH(HfTaskB0Reduced, processDataDplusPiWithDmesMl, "Process data with(out) ML scores for Dplus daughter (B0)", false); - void processDataDplusPiWithB0Ml(soa::Filtered> const& candidates, + void processDataDplusPiWithDmesMlScalarProd(CollisionsWithCentsQvecs const& collisions, + soa::Filtered> const& candidates, + CandsDplus const& candidatesD, + TracksBachPions const&) + { + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { + continue; + } + fillCand(collisions.rawIteratorAt(candidate.collisionId()), candidate, candidatesD); + } // candidate loop + } // processDataDplusPiWithDmesMlScalarProd + PROCESS_SWITCH(HfTaskB0Reduced, processDataDplusPiWithDmesMlScalarProd, "Process data with(out) ML scores for Dplus daughter (B0) and scalar products", false); + + void processDataDplusPiWithB0Ml(CollisionsWithCents const& collisions, + soa::Filtered> const& candidates, CandsDplus const& candidatesD, TracksBachPions const&) { @@ -1031,13 +1086,27 @@ struct HfTaskB0Reduced { if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } - fillCand(candidate, candidatesD); + fillCand(collisions.rawIteratorAt(candidate.collisionId()), candidate, candidatesD); } // candidate loop } // processDataDplusPiWithB0Ml PROCESS_SWITCH(HfTaskB0Reduced, processDataDplusPiWithB0Ml, "Process data with(out) ML scores for B0 (Dplus daughter)", false); - // Process functions - void processDataDstarPi(soa::Filtered> const& candidates, + void processDataDplusPiWithB0MlScalarProd(CollisionsWithCentsQvecs const& collisions, + soa::Filtered> const& candidates, + CandsDplus const& candidatesD, + TracksBachPions const&) + { + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { + continue; + } + fillCand(collisions.rawIteratorAt(candidate.collisionId()), candidate, candidatesD); + } // candidate loop + } // processDataDplusPiWithB0MlScalarProd + PROCESS_SWITCH(HfTaskB0Reduced, processDataDplusPiWithB0MlScalarProd, "Process data with(out) ML scores for B0 (Dplus daughter) and scalar products", false); + + void processDataDstarPi(CollisionsWithCents const& collisions, + soa::Filtered> const& candidates, CandsDstar const& candidatesD, TracksSoftPions const& softPions, TracksBachPions const&) @@ -1046,12 +1115,13 @@ struct HfTaskB0Reduced { if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } - fillCandDStarPi(candidate, softPions, candidatesD); + fillCandDStarPi(collisions.rawIteratorAt(candidate.collisionId()), candidate, softPions, candidatesD); } // candidate loop } // processDataDstarPi PROCESS_SWITCH(HfTaskB0Reduced, processDataDstarPi, "Process data without ML scores for B0 and Dstar daughter", false); - void processDataDstarPiWithDmesMl(soa::Filtered> const& candidates, + void processDataDstarPiWithDmesMl(CollisionsWithCents const& collisions, + soa::Filtered> const& candidates, CandsDstar const& candidatesD, TracksSoftPions const& softPions, TracksBachPions const&) @@ -1060,12 +1130,28 @@ struct HfTaskB0Reduced { if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } - fillCandDStarPi(candidate, softPions, candidatesD); + fillCandDStarPi(collisions.rawIteratorAt(candidate.collisionId()), candidate, softPions, candidatesD); } // candidate loop } // processDataDstarPiWithDmesMl PROCESS_SWITCH(HfTaskB0Reduced, processDataDstarPiWithDmesMl, "Process data with(out) ML scores for Dstar daughter (B0)", false); - void processMcDplusPi(soa::Filtered> const& candidates, + void processDataDstarPiWithDmesMlScalarProd(CollisionsWithCentsQvecs const& collisions, + soa::Filtered> const& candidates, + CandsDstar const& candidatesD, + TracksSoftPions const& softPions, + TracksBachPions const&) + { + for (const auto& candidate : candidates) { + if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { + continue; + } + fillCandDStarPi(collisions.rawIteratorAt(candidate.collisionId()), candidate, softPions, candidatesD); + } // candidate loop + } // processDataDstarPiWithDmesMlScalarProd + PROCESS_SWITCH(HfTaskB0Reduced, processDataDstarPiWithDmesMlScalarProd, "Process data with(out) ML scores for Dstar daughter (B0) and scalar products", false); + + void processMcDplusPi(CollisionsWithCents const& collisions, + soa::Filtered> const& candidates, aod::HfMcGenRedB0s const& mcParticles, CandsDplus const& candidatesD, TracksBachPions const&) @@ -1075,7 +1161,7 @@ struct HfTaskB0Reduced { if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } - fillCand(candidate, candidatesD); + fillCand(collisions.rawIteratorAt(candidate.collisionId()), candidate, candidatesD); } // rec // MC gen. level @@ -1085,7 +1171,8 @@ struct HfTaskB0Reduced { } // processMcDplusPi PROCESS_SWITCH(HfTaskB0Reduced, processMcDplusPi, "Process MC without ML scores for B0 and Dplus daughter", false); - void processMcDplusPiWithDecayTypeCheck(soa::Filtered> const& candidates, + void processMcDplusPiWithDecayTypeCheck(CollisionsWithCents const& collisions, + soa::Filtered> const& candidates, aod::HfMcGenRedB0s const& mcParticles, CandsDplus const& candidatesD, TracksBachPions const&) @@ -1095,7 +1182,7 @@ struct HfTaskB0Reduced { if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } - fillCand(candidate, candidatesD); + fillCand(collisions.rawIteratorAt(candidate.collisionId()), candidate, candidatesD); } // rec // MC gen. level @@ -1105,7 +1192,8 @@ struct HfTaskB0Reduced { } // processMcDplusPi PROCESS_SWITCH(HfTaskB0Reduced, processMcDplusPiWithDecayTypeCheck, "Process MC with decay type check and without ML scores for B0 and Dplus daughter", false); - void processMcDplusPiWithDmesMl(soa::Filtered> const& candidates, + void processMcDplusPiWithDmesMl(CollisionsWithCents const& collisions, + soa::Filtered> const& candidates, aod::HfMcGenRedB0s const& mcParticles, CandsDplus const& candidatesD, TracksBachPions const&) @@ -1115,7 +1203,7 @@ struct HfTaskB0Reduced { if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } - fillCand(candidate, candidatesD); + fillCand(collisions.rawIteratorAt(candidate.collisionId()), candidate, candidatesD); } // rec // MC gen. level @@ -1125,7 +1213,8 @@ struct HfTaskB0Reduced { } // processMcDplusPiWithDmesMl PROCESS_SWITCH(HfTaskB0Reduced, processMcDplusPiWithDmesMl, "Process MC with(out) ML scores for Dplus daughter (B0)", false); - void processMcDplusPiWithDmesMlAndDecayTypeCheck(soa::Filtered> const& candidates, + void processMcDplusPiWithDmesMlAndDecayTypeCheck(CollisionsWithCents const& collisions, + soa::Filtered> const& candidates, aod::HfMcGenRedB0s const& mcParticles, CandsDplus const& candidatesD, TracksBachPions const&) @@ -1135,7 +1224,7 @@ struct HfTaskB0Reduced { if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } - fillCand(candidate, candidatesD); + fillCand(collisions.rawIteratorAt(candidate.collisionId()), candidate, candidatesD); } // rec // MC gen. level @@ -1145,7 +1234,8 @@ struct HfTaskB0Reduced { } // processMcDplusPi PROCESS_SWITCH(HfTaskB0Reduced, processMcDplusPiWithDmesMlAndDecayTypeCheck, "Process MC with decay type check and with(out) ML scores for B0 (Dplus daughter)", false); - void processMcDplusPiWithB0Ml(soa::Filtered> const& candidates, + void processMcDplusPiWithB0Ml(CollisionsWithCents const& collisions, + soa::Filtered> const& candidates, aod::HfMcGenRedB0s const& mcParticles, CandsDplus const& candidatesD, TracksBachPions const&) @@ -1155,7 +1245,7 @@ struct HfTaskB0Reduced { if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } - fillCand(candidate, candidatesD); + fillCand(collisions.rawIteratorAt(candidate.collisionId()), candidate, candidatesD); } // rec // MC gen. level @@ -1165,7 +1255,8 @@ struct HfTaskB0Reduced { } // processMcDplusPiWithB0Ml PROCESS_SWITCH(HfTaskB0Reduced, processMcDplusPiWithB0Ml, "Process MC with(out) ML scores for B0 (Dplus daughter)", false); - void processMcDplusPiWithB0MlAndDecayTypeCheck(soa::Filtered> const& candidates, + void processMcDplusPiWithB0MlAndDecayTypeCheck(CollisionsWithCents const& collisions, + soa::Filtered> const& candidates, aod::HfMcGenRedB0s const& mcParticles, CandsDplus const& candidatesD, TracksBachPions const&) @@ -1175,7 +1266,7 @@ struct HfTaskB0Reduced { if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } - fillCand(candidate, candidatesD); + fillCand(collisions.rawIteratorAt(candidate.collisionId()), candidate, candidatesD); } // rec // MC gen. level @@ -1185,7 +1276,8 @@ struct HfTaskB0Reduced { } // processMcDplusPi PROCESS_SWITCH(HfTaskB0Reduced, processMcDplusPiWithB0MlAndDecayTypeCheck, "Process MC with decay type check and with(out) ML scores for B0 (Dplus daughter)", false); - void processMcDstarPi(soa::Filtered> const& candidates, + void processMcDstarPi(CollisionsWithCents const& collisions, + soa::Filtered> const& candidates, aod::HfMcGenRedB0s const& mcParticles, CandsDstar const& candidatesD, TracksSoftPions const& softPions, @@ -1196,7 +1288,7 @@ struct HfTaskB0Reduced { if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } - fillCandDStarPi(candidate, softPions, candidatesD); + fillCandDStarPi(collisions.rawIteratorAt(candidate.collisionId()), candidate, softPions, candidatesD); } // rec // MC gen. level @@ -1206,7 +1298,8 @@ struct HfTaskB0Reduced { } // processMcDstarPi PROCESS_SWITCH(HfTaskB0Reduced, processMcDstarPi, "Process MC without ML scores for B0 and Dstar daughter", false); - void processMcDstarPiWithDmesMl(soa::Filtered> const& candidates, + void processMcDstarPiWithDmesMl(CollisionsWithCents const& collisions, + soa::Filtered> const& candidates, aod::HfMcGenRedB0s const& mcParticles, CandsDstar const& candidatesD, TracksSoftPions const& softPions, @@ -1217,7 +1310,7 @@ struct HfTaskB0Reduced { if (yCandRecoMax >= 0. && std::abs(HfHelper::yB0(candidate)) > yCandRecoMax) { continue; } - fillCandDStarPi(candidate, softPions, candidatesD); + fillCandDStarPi(collisions.rawIteratorAt(candidate.collisionId()), candidate, softPions, candidatesD); } // rec // MC gen. level diff --git a/PWGHF/D2H/Tasks/taskCd.cxx b/PWGHF/D2H/Tasks/taskCd.cxx index cea20fb44ae..8282a7eecf5 100644 --- a/PWGHF/D2H/Tasks/taskCd.cxx +++ b/PWGHF/D2H/Tasks/taskCd.cxx @@ -24,6 +24,7 @@ #include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponseITS.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" @@ -69,7 +70,7 @@ namespace full { // Candidate kinematics DECLARE_SOA_COLUMN(MassCd, massCd, float); //! Invariant mass of cd candidate (GeV/c^2) -DECLARE_SOA_COLUMN(MassLc, massLc, float); //! Invariant mass of lc candidate (GeV/c^2) +DECLARE_SOA_COLUMN(MassLc, massLc, float); //! Invariant mass under the p K pi hypothesis (GeV/c^2) DECLARE_SOA_COLUMN(Pt, pt, float); //! Transverse momentum of candidate (GeV/c) DECLARE_SOA_COLUMN(Eta, eta, float); //! eta of candidate (GeV/c) DECLARE_SOA_COLUMN(Phi, phi, float); //! phi of candidate (GeV/c) @@ -114,13 +115,17 @@ DECLARE_SOA_COLUMN(NTpcSignalsKa, nTpcSignalsKa, float); //! Number o DECLARE_SOA_COLUMN(NItsSignalsDe, nItsSignalsDe, float); //! Number of ITS signas DECLARE_SOA_COLUMN(CandidateSelFlag, candidateSelFlag, int8_t); //! Candidates falg DECLARE_SOA_COLUMN(CandidateSign, candidateSign, int8_t); //! Candidates sign -DECLARE_SOA_COLUMN(FlagMc, flagMc, int8_t); //! MC matching flag +DECLARE_SOA_COLUMN(FlagMc, flagMc, int8_t); //! Main MC decay-channel flag; 0 for unmatched candidates +DECLARE_SOA_COLUMN(IsCandidateSwapped, isCandidateSwapped, int8_t); //! MC-matched prong permutation; -1 for data +DECLARE_SOA_COLUMN(HypothesisMask, hypothesisMask, uint8_t); //! Bit 0: DeKPi selected; bit 1: PiKDe selected +DECLARE_SOA_COLUMN(CandidateGlobalIndex, candidateGlobalIndex, int64_t); //! Input candidate index, shared by rows from the same candidate DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); //! MC origin for reconstructed candidates DECLARE_SOA_COLUMN(FlagMcDecayChanRec, flagMcDecayChanRec, int8_t); //! Resonant MC decay channel for reconstructed candidates DECLARE_SOA_COLUMN(OriginMcGen, originMcGen, int8_t); //! MC origin for generated particles DECLARE_SOA_COLUMN(FlagMcDecayChanGen, flagMcDecayChanGen, int8_t); //! Resonant MC decay channel for generated candidates DECLARE_SOA_COLUMN(CtGen, ctGen, float); //! Generated ct computed wrt to c-deuteron production vertex, which can be either PV (prompt) or B-hadron decay vertex (non-prompt) DECLARE_SOA_COLUMN(CtRec, ctRec, float); //! Reconstructed ct computed wrt to PV +DECLARE_SOA_COLUMN(NumPvContributors, numPvContributors, uint16_t); //! Number of contributors to the primary vertex DECLARE_SOA_COLUMN(Cent, cent, float); //! Centrality DECLARE_SOA_COLUMN(VtxZ, vtxZ, float); //! Vertex Z DECLARE_SOA_COLUMN(GIndexCol, gIndexCol, int); //! Global index for the collision @@ -155,6 +160,9 @@ DECLARE_SOA_TABLE(HfCandCdLite, "AOD", "HFCANDCDLITE", full::CandidateSelFlag, full::CandidateSign, full::FlagMc, + full::IsCandidateSwapped, + full::HypothesisMask, + full::CandidateGlobalIndex, full::OriginMcRec, full::FlagMcDecayChanRec, full::CtGen, @@ -192,9 +200,13 @@ DECLARE_SOA_TABLE(HfCandCdFull, "AOD", "HFCANDCDFULL", full::CandidateSelFlag, full::CandidateSign, full::FlagMc, + full::IsCandidateSwapped, + full::HypothesisMask, + full::CandidateGlobalIndex, full::OriginMcRec, full::FlagMcDecayChanRec, full::CtGen, + full::NumPvContributors, full::Cent, full::VtxZ, full::GIndexCol, @@ -209,6 +221,7 @@ DECLARE_SOA_TABLE(HfCandCdGen, "AOD", "HFCANDCDGEN", full::OriginMcGen, full::FlagMcDecayChanGen, full::CtGen, + full::NumPvContributors, full::Cent, full::VtxZ, full::McCollisionId); @@ -231,15 +244,18 @@ struct HfTaskCd { Configurable cfgCutOnDeuteronDcaOrdering{"cfgCutOnDeuteronDcaOrdering", false, "Require deuteron DCA to be smaller than kaon and pion DCAs"}; Configurable cfgMinDeuteronDcaPreselection{"cfgMinDeuteronDcaPreselection", 0.004, "Minimum deuteron DCA for preselection (cm)"}; Configurable cfgMaxDeuteronTofPidPreselection{"cfgMaxDeuteronTofPidPreselection", 5, "Maximum |nSigma TOF| for deuteron preselection"}; + Configurable fillMcCorrelatedBackgrounds{"fillMcCorrelatedBackgrounds", false, "Store selected MC candidates matched to a supported decay channel other than c-deuteron"}; + Configurable fillMcCombinatorialBackground{"fillMcCombinatorialBackground", false, "Store selected MC candidates with flagMcMatchRec equal to zero"}; + Configurable acceptCandidatesWithoutCdFlag{"acceptCandidatesWithoutCdFlag", false, "Accept selected candidates without the Cd skim bit; intended for MC reflection studies"}; SliceCache cache; - using CollisionsWEvSel = soa::Join; - using CollisionsMc = soa::Join; - using CollisionsWithEvSelFT0C = soa::Join; - using CollisionsMcWithEvSelFT0C = soa::Join; - using CollisionsWithEvSelFT0M = soa::Join; - using CollisionsMcWithEvSelFT0M = soa::Join; + using CollisionsWEvSel = soa::Join; + using CollisionsMc = soa::Join; + using CollisionsWithEvSelFT0C = soa::Join; + using CollisionsMcWithEvSelFT0C = soa::Join; + using CollisionsWithEvSelFT0M = soa::Join; + using CollisionsMcWithEvSelFT0M = soa::Join; using CdCandidates = soa::Filtered>; using CdCandidatesMc = soa::Filtered>; @@ -263,9 +279,9 @@ struct HfTaskCd { ConfigurableAxis thnConfigAxisNumPvContr{"thnConfigAxisNumPvContr", {200, -0.5, 199.5}, "Number of PV contributors"}; ConfigurableAxis thnConfigAxisCt{"thnConfigAxisCt", {500, 0., 5000.}, ""}; - constexpr static std::string_view SignalFolders[] = {"signal", "prompt", "nonprompt"}; - constexpr static std::string_view SignalSuffixes[] = {"", "Prompt", "NonPrompt"}; - const float cmToMum = 1.e4; + static constexpr std::array SignalFolders = {"signal", "prompt", "nonprompt"}; + static constexpr std::array SignalSuffixes = {"", "Prompt", "NonPrompt"}; + static constexpr float CmToMum = 1.e4f; enum SignalClasses : int { Signal = 0, @@ -332,6 +348,9 @@ struct HfTaskCd { addHistogramsGen("hPt", "#it{p}_{T}^{gen.} (GeV/#it{c})", "entries", {HistType::kTH1D, {{360, 0., 36.}}}); if (!isData) { registry.add("MC/generated/signal/hPtGenSig", "3-prong candidates (matched);#it{p}_{T}^{gen.} (GeV/#it{c});entries", {HistType::kTH1D, {{360, 0., 36.}}}); + registry.add("MC/reconstructed/allCandidates/hFlagMcMatchRec", "Selected 3-prong candidates;MC decay-channel flag;entries", {HistType::kTH1D, {{49, -24.5, 24.5}}}); + registry.add("MC/reconstructed/allCandidates/hMassCdVsFlagMcMatchRec", "Selected 3-prong candidates;inv. mass (d K #pi) (GeV/#it{c}^{2});MC decay-channel flag", {HistType::kTH2F, {{400, 2.4, 4.4}, {49, -24.5, 24.5}}}); + registry.add("MC/reconstructed/allCandidates/hMassPKPiVsFlagMcMatchRec", "Selected 3-prong candidates;inv. mass (p K #pi) (GeV/#it{c}^{2});MC decay-channel flag", {HistType::kTH2F, {{400, 1.6, 3.2}, {49, -24.5, 24.5}}}); } addHistogramsRec("hPtProng0", "prong 0 #it{p}_{T} (GeV/#it{c})", "entries", {HistType::kTH1D, {{360, 0., 36.}}}); addHistogramsRec("hPtProng1", "prong 1 #it{p}_{T} (GeV/#it{c})", "entries", {HistType::kTH1D, {{360, 0., 36.}}}); @@ -496,10 +515,14 @@ struct HfTaskCd { const int64_t timeStamp = bc.timestamp(); for (const auto& candidate : groupedCdCandidates) { - if (candidate.flagMcMatchRec() == 0) { // we skip combinatorial background + const int absFlagMc = std::abs(candidate.flagMcMatchRec()); + const bool isTrueCd = absFlagMc == hf_decay::hf_cand_3prong::DecayChannelMain::CDeuteronToDeKPi; + const bool keepCorrelatedBackground = fillMcCorrelatedBackgrounds && absFlagMc != 0 && !isTrueCd; + const bool keepCombinatorialBackground = fillMcCombinatorialBackground && absFlagMc == 0; + if (!isTrueCd && !keepCorrelatedBackground && !keepCombinatorialBackground) { continue; } - if (!TESTBIT(candidate.hfflag(), aod::hf_cand_3prong::DecayType::CdToDeKPi)) { + if (!acceptCandidatesWithoutCdFlag && !TESTBIT(candidate.hfflag(), aod::hf_cand_3prong::DecayType::CdToDeKPi)) { continue; } const auto yCd = RecoDecay::y(candidate.pVector(), o2::constants::physics::MassCDeuteron); @@ -507,166 +530,125 @@ struct HfTaskCd { continue; } + registry.fill(HIST("MC/reconstructed/allCandidates/hFlagMcMatchRec"), candidate.flagMcMatchRec()); + if (candidate.isSelCdToDeKPi() >= selectionFlagCd) { + registry.fill(HIST("MC/reconstructed/allCandidates/hMassCdVsFlagMcMatchRec"), HfHelper::invMassCdToDeKPi(candidate), candidate.flagMcMatchRec()); + registry.fill(HIST("MC/reconstructed/allCandidates/hMassPKPiVsFlagMcMatchRec"), HfHelper::invMassLcToPKPi(candidate), candidate.flagMcMatchRec()); + } + if (candidate.isSelCdToPiKDe() >= selectionFlagCd) { + registry.fill(HIST("MC/reconstructed/allCandidates/hMassCdVsFlagMcMatchRec"), HfHelper::invMassCdToPiKDe(candidate), candidate.flagMcMatchRec()); + registry.fill(HIST("MC/reconstructed/allCandidates/hMassPKPiVsFlagMcMatchRec"), HfHelper::invMassLcToPiKP(candidate), candidate.flagMcMatchRec()); + } + float ctGen{-1.f}, ptGen{-1.f}; int pdgCodeProng0{0}; - if (std::abs(candidate.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::CDeuteronToDeKPi) { + int8_t isCandidateSwapped{-1}; + if (isTrueCd) { const auto& mcParticleProng0 = candidate.template prong0_as().template mcParticle_as(); pdgCodeProng0 = std::abs(mcParticleProng0.pdgCode()); + isCandidateSwapped = static_cast(pdgCodeProng0 == kPiPlus); const auto indexMother = RecoDecay::getMother(mcParticles, mcParticleProng0, o2::constants::physics::Pdg::kCDeuteron, true); const auto particleMother = mcParticles.rawIteratorAt(indexMother); - ctGen = RecoDecay::ct(std::array{particleMother.px(), particleMother.py(), particleMother.pz()}, RecoDecay::distance(std::array{particleMother.vx(), particleMother.vy(), particleMother.vz()}, std::array{mcParticleProng0.vx(), mcParticleProng0.vy(), mcParticleProng0.vz()}), o2::constants::physics::MassCDeuteron) * cmToMum; + ctGen = RecoDecay::ct(std::array{particleMother.px(), particleMother.py(), particleMother.pz()}, RecoDecay::distance(std::array{particleMother.vx(), particleMother.vy(), particleMother.vz()}, std::array{mcParticleProng0.vx(), mcParticleProng0.vy(), mcParticleProng0.vz()}), o2::constants::physics::MassCDeuteron) * CmToMum; ptGen = particleMother.pt(); + } else if (absFlagMc != 0) { + isCandidateSwapped = candidate.isCandidateSwapped(); } if (fillCandLiteTree || fillCandFullTree) { - float invMassCd = 0.f; - float invMassLc = 0.f; - int candFlag = -999; - int candSign = -999; - - float nSigmaTpcDe = 0.f, nSigmaTpcKa = 0.f, nSigmaTpcPi = 0.f, nSigmaTpcPr = 0.f; - float nSigmaItsDe = 0.f; - float nSigmaTofDe = 0.f, nSigmaTofKa = 0.f, nSigmaTofPi = 0.f; - float tofBetaDe = -999.f; - float tpcInnerParamDe = -999.f; - float tofExpMomDe = -999.f; - - float dcaDeuteron = 0.f, dcaKaon = 0.f, dcaPion = 0.f; - const bool selDeKPi = (candidate.isSelCdToDeKPi() >= selectionFlagCd); const bool selPiKDe = (candidate.isSelCdToPiKDe() >= selectionFlagCd); - + const uint8_t hypothesisMask = static_cast((selDeKPi ? 0x1 : 0x0) | + (selPiKDe ? 0x2 : 0x0)); + const int64_t candidateGlobalIndex = candidate.globalIndex(); auto prong0 = candidate.template prong0_as(); auto prong1 = candidate.template prong1_as(); auto prong2 = candidate.template prong2_as(); - auto prong0Its = tracksWithItsPid.iteratorAt(candidate.prong0Id() - tracksWithItsPid.offset()); auto prong2Its = tracksWithItsPid.iteratorAt(candidate.prong2Id() - tracksWithItsPid.offset()); - candSign = static_cast(-prong1.sign()); - nSigmaTpcKa = candidate.nSigTpcKa1(); - nSigmaTofKa = candidate.nSigTofKa1(); - - if (selDeKPi) { - invMassCd = HfHelper::invMassCdToDeKPi(candidate); - invMassLc = HfHelper::invMassLcToPKPi(candidate); - candFlag = 1; - nSigmaTpcDe = candidate.nSigTpcDe0(); - nSigmaTpcPr = candidate.nSigTpcPr0(); - nSigmaTofDe = candidate.nSigTofDe0(); - tofBetaDe = (prong0.hasTOF() && prong0.beta() > 0.f) ? prong0.beta() : -999.f; - tpcInnerParamDe = prong0.tpcInnerParam(); - tofExpMomDe = prong0.hasTOF() ? prong0.tofExpMom() : -999.f; - nSigmaTpcPi = candidate.nSigTpcPi2(); - nSigmaTofPi = candidate.nSigTofPi2(); - nSigmaItsDe = prong0Its.itsNSigmaDe(); - dcaDeuteron = candidate.impactParameter0(); - dcaKaon = candidate.impactParameter1(); - dcaPion = candidate.impactParameter2(); - } else if (selPiKDe) { - invMassCd = HfHelper::invMassCdToPiKDe(candidate); - invMassLc = HfHelper::invMassLcToPiKP(candidate); - candFlag = -1; - nSigmaTpcDe = candidate.nSigTpcDe2(); - nSigmaTpcPr = candidate.nSigTpcPr2(); - nSigmaTofDe = candidate.nSigTofDe2(); - tofBetaDe = (prong2.hasTOF() && prong2.beta() > 0.f) ? prong2.beta() : -999.f; - tpcInnerParamDe = prong2.tpcInnerParam(); - tofExpMomDe = prong2.hasTOF() ? prong2.tofExpMom() : -999.f; - nSigmaTpcPi = candidate.nSigTpcPi0(); - nSigmaTofPi = candidate.nSigTofPi0(); - nSigmaItsDe = prong2Its.itsNSigmaDe(); - dcaDeuteron = candidate.impactParameter2(); - dcaKaon = candidate.impactParameter1(); - dcaPion = candidate.impactParameter0(); - } - - if (cfgUseTofPidForDeuteron && std::abs(nSigmaTofDe) > cfgMaxDeuteronTofPidPreselection) { - continue; - } - if (std::abs(dcaDeuteron) < cfgMinDeuteronDcaPreselection) { - continue; - } - if (cfgCutOnDeuteronDcaOrdering && (std::abs(dcaDeuteron) > std::abs(dcaKaon) || std::abs(dcaDeuteron) > std::abs(dcaPion))) { - continue; - } - - if (fillCandLiteTree) { - rowCandCdLite( - invMassCd, - invMassLc, - candidate.pt(), - candidate.eta(), - candidate.phi(), - candidate.ptProng0(), - candidate.ptProng1(), - candidate.ptProng2(), - candidate.impactParameter0(), - candidate.impactParameter1(), - candidate.impactParameter2(), - candidate.decayLength(), - candidate.cpa(), - candidate.chi2PCA(), - nSigmaTpcDe, - nSigmaTpcPr, - nSigmaItsDe, - nSigmaTofDe, - tofBetaDe, - tpcInnerParamDe, - tofExpMomDe, - candidate.ct(o2::constants::physics::MassCDeuteron) * cmToMum, - candFlag, - candSign, - candidate.flagMcMatchRec(), - candidate.originMcRec(), - candidate.flagMcDecayChanRec(), - ctGen, - o2::hf_centrality::getCentralityColl(collision)); - } + auto writeMcHypothesis = [&](bool isDeKPi) { + const float invMassCd = isDeKPi ? HfHelper::invMassCdToDeKPi(candidate) : HfHelper::invMassCdToPiKDe(candidate); + const float invMassLc = isDeKPi ? HfHelper::invMassLcToPKPi(candidate) : HfHelper::invMassLcToPiKP(candidate); + const int candFlag = isDeKPi ? 1 : -1; + const int candSign = static_cast(-prong1.sign()); + const float nSigmaTpcDe = isDeKPi ? candidate.nSigTpcDe0() : candidate.nSigTpcDe2(); + const float nSigmaTpcPr = isDeKPi ? candidate.nSigTpcPr0() : candidate.nSigTpcPr2(); + const float nSigmaTofDe = isDeKPi ? candidate.nSigTofDe0() : candidate.nSigTofDe2(); + const float nSigmaTpcPi = isDeKPi ? candidate.nSigTpcPi2() : candidate.nSigTpcPi0(); + const float nSigmaTofPi = isDeKPi ? candidate.nSigTofPi2() : candidate.nSigTofPi0(); + const float nSigmaItsDe = isDeKPi ? prong0Its.itsNSigmaDe() : prong2Its.itsNSigmaDe(); + const float nSigmaTpcKa = candidate.nSigTpcKa1(); + const float nSigmaTofKa = candidate.nSigTofKa1(); + const auto& deuteronProng = isDeKPi ? prong0 : prong2; + const float tofBetaDe = (deuteronProng.hasTOF() && deuteronProng.beta() > 0.f) ? deuteronProng.beta() : -999.f; + const float tpcInnerParamDe = deuteronProng.tpcInnerParam(); + const float tofExpMomDe = deuteronProng.hasTOF() ? deuteronProng.tofExpMom() : -999.f; + const float dcaDeuteron = isDeKPi ? candidate.impactParameter0() : candidate.impactParameter2(); + const float dcaKaon = candidate.impactParameter1(); + const float dcaPion = isDeKPi ? candidate.impactParameter2() : candidate.impactParameter0(); + + if (cfgUseTofPidForDeuteron && std::abs(nSigmaTofDe) > cfgMaxDeuteronTofPidPreselection) { + return; + } + if (std::abs(dcaDeuteron) < cfgMinDeuteronDcaPreselection) { + return; + } + if (cfgCutOnDeuteronDcaOrdering && (std::abs(dcaDeuteron) > std::abs(dcaKaon) || std::abs(dcaDeuteron) > std::abs(dcaPion))) { + return; + } + + if (fillCandLiteTree) { + rowCandCdLite( + invMassCd, invMassLc, candidate.pt(), candidate.eta(), candidate.phi(), + candidate.ptProng0(), candidate.ptProng1(), candidate.ptProng2(), + candidate.impactParameter0(), candidate.impactParameter1(), candidate.impactParameter2(), + candidate.decayLength(), candidate.cpa(), candidate.chi2PCA(), + nSigmaTpcDe, nSigmaTpcPr, nSigmaItsDe, nSigmaTofDe, + tofBetaDe, tpcInnerParamDe, tofExpMomDe, + candidate.ct(o2::constants::physics::MassCDeuteron) * CmToMum, + candFlag, candSign, candidate.flagMcMatchRec(), isCandidateSwapped, hypothesisMask, candidateGlobalIndex, candidate.originMcRec(), + candidate.flagMcDecayChanRec(), ctGen, o2::hf_centrality::getCentralityColl(collision)); + } + + if (fillCandFullTree) { + rowCandCdFull( + candidate.pxProng0(), candidate.pyProng0(), candidate.pzProng0(), + candidate.pxProng1(), candidate.pyProng1(), candidate.pzProng1(), + candidate.pxProng2(), candidate.pyProng2(), candidate.pzProng2(), + candidate.impactParameter0(), candidate.impactParameter1(), candidate.impactParameter2(), + candidate.decayLength(), candidate.cpa(), candidate.chi2PCA(), + nSigmaTpcDe, nSigmaTpcPr, nSigmaItsDe, nSigmaTofDe, + tofBetaDe, tpcInnerParamDe, tofExpMomDe, + nSigmaTpcPi, nSigmaTofPi, nSigmaTpcKa, nSigmaTofKa, + candidate.ct(o2::constants::physics::MassCDeuteron) * CmToMum, + candFlag, candSign, candidate.flagMcMatchRec(), isCandidateSwapped, hypothesisMask, candidateGlobalIndex, candidate.originMcRec(), + candidate.flagMcDecayChanRec(), ctGen, collision.numContrib(), o2::hf_centrality::getCentralityColl(collision), + collision.posZ(), collision.globalIndex(), timeStamp); + } + }; - if (fillCandFullTree) { - rowCandCdFull( - candidate.pxProng0(), - candidate.pyProng0(), - candidate.pzProng0(), - candidate.pxProng1(), - candidate.pyProng1(), - candidate.pzProng1(), - candidate.pxProng2(), - candidate.pyProng2(), - candidate.pzProng2(), - candidate.impactParameter0(), - candidate.impactParameter1(), - candidate.impactParameter2(), - candidate.decayLength(), - candidate.cpa(), - candidate.chi2PCA(), - nSigmaTpcDe, - nSigmaTpcPr, - nSigmaItsDe, - nSigmaTofDe, - tofBetaDe, - tpcInnerParamDe, - tofExpMomDe, - nSigmaTpcPi, - nSigmaTofPi, - nSigmaTpcKa, - nSigmaTofKa, - candidate.ct(o2::constants::physics::MassCDeuteron) * cmToMum, - candFlag, - candSign, - candidate.flagMcMatchRec(), - candidate.originMcRec(), - candidate.flagMcDecayChanRec(), - ctGen, - o2::hf_centrality::getCentralityColl(collision), - collision.posZ(), - collision.globalIndex(), - timeStamp); + if (isTrueCd) { + // For signal MC, retain only the hypothesis that matches the true deuteron prong. + if (selDeKPi && pdgCodeProng0 == o2::constants::physics::Pdg::kDeuteron) { + writeMcHypothesis(true); + } + if (selPiKDe && pdgCodeProng0 == kPiPlus) { + writeMcHypothesis(false); + } + } else { + // Reflection and combinatorial candidates have no true deuteron prong. + // Retain every Cd hypothesis accepted by the selector and distinguish them with CandidateSelFlag. + if (selDeKPi) { + writeMcHypothesis(true); + } + if (selPiKDe) { + writeMcHypothesis(false); + } } } - if (std::abs(candidate.flagMcMatchRec()) != hf_decay::hf_cand_3prong::DecayChannelMain::CDeuteronToDeKPi) { + if (!isTrueCd) { continue; } @@ -727,12 +709,13 @@ struct HfTaskCd { vtxZ = recCol.posZ(); } const float cent = o2::hf_centrality::getCentralityGenColl(recoCollsPerMcColl); - const float ptGenB = particle.originMcGen() == RecoDecay::OriginType::Prompt ? -1.f : mcParticles.rawIteratorAt(particle.idxBhadMotherPart()).pt(); + const bool isPrompt = particle.originMcGen() == 0; + const float ptGenB = isPrompt ? -1.f : mcParticles.rawIteratorAt(particle.idxBhadMotherPart()).pt(); const auto firstDau = particle.template daughters_as().begin(); - const float ctGen = RecoDecay::ct(std::array{particle.px(), particle.py(), particle.pz()}, RecoDecay::distance(std::array{particle.vx(), particle.vy(), particle.vz()}, std::array{firstDau.vx(), firstDau.vy(), firstDau.vz()}), o2::constants::physics::MassCDeuteron) * cmToMum; + const float ctGen = RecoDecay::ct(std::array{particle.px(), particle.py(), particle.pz()}, RecoDecay::distance(std::array{particle.vx(), particle.vy(), particle.vz()}, std::array{firstDau.vx(), firstDau.vy(), firstDau.vz()}), o2::constants::physics::MassCDeuteron) * CmToMum; fillHistogramsGen(particle, yGen); - if (particle.originMcGen() == RecoDecay::OriginType::Prompt) { + if (isPrompt) { fillHistogramsGen(particle, yGen); } else if (particle.originMcGen() == RecoDecay::OriginType::NonPrompt) { fillHistogramsGen(particle, yGen); @@ -752,6 +735,7 @@ struct HfTaskCd { particle.originMcGen(), particle.flagMcDecayChanGen(), ctGen, + numPvContributors, cent, vtxZ, particle.mcCollision().globalIndex()); @@ -784,17 +768,6 @@ struct HfTaskCd { const auto chi2PCA = candidate.chi2PCA(); const auto cpa = candidate.cpa(); const auto cpaXY = candidate.cpaXY(); - float invMassCd = 0.f; - float invMassLc = 0.f; - if (candidate.isSelCdToDeKPi() >= selectionFlagCd) { - invMassCd = HfHelper::invMassCdToDeKPi(candidate); - invMassLc = HfHelper::invMassLcToPKPi(candidate); - } - if (candidate.isSelCdToPiKDe() >= selectionFlagCd) { - invMassCd = HfHelper::invMassCdToPiKDe(candidate); - invMassLc = HfHelper::invMassLcToPiKP(candidate); - } - if (candidate.isSelCdToDeKPi() >= selectionFlagCd) { registry.fill(HIST("Data/hMass"), HfHelper::invMassCdToDeKPi(candidate)); registry.fill(HIST("Data/hMassVsPtVsNPvContributors"), HfHelper::invMassCdToDeKPi(candidate), pt, numPvContributors); @@ -852,187 +825,96 @@ struct HfTaskCd { } if (fillCandLiteTree || fillCandFullTree) { - - int candFlag = -999; - int candSign = -999; - - float nSigmaTpcDe = 0.f, nSigmaTpcKa = 0.f, nSigmaTpcPi = 0.f, nSigmaTpcPr = 0.f; - float nSigmaItsDe = 0.f; - float nSigmaTofDe = 0.f, nSigmaTofKa = 0.f, nSigmaTofPi = 0.f; - float tofBetaDe = -999.f; - float tpcInnerParamDe = -999.f; - float tofExpMomDe = -999.f; - - float dcaDeuteron = 0.f, dcaKaon = 0.f, dcaPion = 0.f; - // int itsNClusterSizeDe = 0; - - float tpcSignalsDe = 0.f; - float tpcSignalsPi = 0.f; - float tpcSignalsKa = 0.f; - - float itsSignalsDe = 0.f; - - float pSignedDe = -999.f; - float pSignedPi = -999.f; - - nSigmaTpcKa = candidate.nSigTpcKa1(); - nSigmaTofKa = candidate.nSigTofKa1(); - const bool selDeKPi = (candidate.isSelCdToDeKPi() >= selectionFlagCd); const bool selPiKDe = (candidate.isSelCdToPiKDe() >= selectionFlagCd); - + const uint8_t hypothesisMask = static_cast((selDeKPi ? 0x1 : 0x0) | + (selPiKDe ? 0x2 : 0x0)); + const int64_t candidateGlobalIndex = candidate.globalIndex(); auto prong0 = candidate.template prong0_as(); auto prong1 = candidate.template prong1_as(); auto prong2 = candidate.template prong2_as(); - auto prong0Its = tracksWithItsPid.iteratorAt(candidate.prong0Id() - tracksWithItsPid.offset()); auto prong2Its = tracksWithItsPid.iteratorAt(candidate.prong2Id() - tracksWithItsPid.offset()); - candSign = static_cast(-prong1.sign()); - - tpcSignalsKa = prong1.tpcSignal(); + auto writeDataHypothesis = [&](bool isDeKPi) { + const float invMassCd = isDeKPi ? HfHelper::invMassCdToDeKPi(candidate) : HfHelper::invMassCdToPiKDe(candidate); + const float invMassLc = isDeKPi ? HfHelper::invMassLcToPKPi(candidate) : HfHelper::invMassLcToPiKP(candidate); + const int candFlag = isDeKPi ? 1 : -1; + const int candSign = static_cast(-prong1.sign()); + const float nSigmaTpcDe = isDeKPi ? candidate.nSigTpcDe0() : candidate.nSigTpcDe2(); + const float nSigmaTpcPr = isDeKPi ? candidate.nSigTpcPr0() : candidate.nSigTpcPr2(); + const float nSigmaTofDe = isDeKPi ? candidate.nSigTofDe0() : candidate.nSigTofDe2(); + const float nSigmaTpcPi = isDeKPi ? candidate.nSigTpcPi2() : candidate.nSigTpcPi0(); + const float nSigmaTofPi = isDeKPi ? candidate.nSigTofPi2() : candidate.nSigTofPi0(); + const float nSigmaItsDe = isDeKPi ? prong0Its.itsNSigmaDe() : prong2Its.itsNSigmaDe(); + const float nSigmaTpcKa = candidate.nSigTpcKa1(); + const float nSigmaTofKa = candidate.nSigTofKa1(); + const auto& deuteronProng = isDeKPi ? prong0 : prong2; + const auto& pionProng = isDeKPi ? prong2 : prong0; + const float tofBetaDe = (deuteronProng.hasTOF() && deuteronProng.beta() > 0.f) ? deuteronProng.beta() : -999.f; + const float tpcInnerParamDe = deuteronProng.tpcInnerParam(); + const float tofExpMomDe = deuteronProng.hasTOF() ? deuteronProng.tofExpMom() : -999.f; + const float dcaDeuteron = isDeKPi ? candidate.impactParameter0() : candidate.impactParameter2(); + const float dcaKaon = candidate.impactParameter1(); + const float dcaPion = isDeKPi ? candidate.impactParameter2() : candidate.impactParameter0(); + const float pSignedDe = deuteronProng.tpcInnerParam() * deuteronProng.sign(); + const float pSignedPi = pionProng.tpcInnerParam() * pionProng.sign(); + + // Fill PID QA per retained mass hypothesis. + registry.fill(HIST("Data/hNsigmaTPCDeVsP"), pSignedDe, nSigmaTpcDe); + registry.fill(HIST("Data/hNsigmaTPCPrVsP"), pSignedDe, nSigmaTpcPr); + registry.fill(HIST("Data/hNsigmaTOFDeVsP"), pSignedDe, nSigmaTofDe); + registry.fill(HIST("Data/hNsigmaITSDeVsP"), pSignedDe, nSigmaItsDe); + registry.fill(HIST("Data/hTPCSignalDeVsP"), pSignedDe, deuteronProng.tpcSignal()); + registry.fill(HIST("Data/hTPCSignalPiVsP"), pSignedPi, pionProng.tpcSignal()); + registry.fill(HIST("Data/hTPCSignalKaVsP"), prong1.tpcInnerParam() * prong1.sign(), prong1.tpcSignal()); + registry.fill(HIST("Data/hITSSignalDeVsP"), pSignedDe, itsSignal(deuteronProng)); + registry.fill(HIST("Data/hNsigmaTPCPiVsP"), pSignedPi, nSigmaTpcPi); + registry.fill(HIST("Data/hNsigmaTOFPiVsP"), pSignedPi, nSigmaTofPi); + registry.fill(HIST("Data/hNsigmaTPCKaVsP"), prong1.tpcInnerParam() * prong1.sign(), nSigmaTpcKa); + registry.fill(HIST("Data/hNsigmaTOFKaVsP"), prong1.tpcInnerParam() * prong1.sign(), nSigmaTofKa); + + if (cfgUseTofPidForDeuteron && std::abs(nSigmaTofDe) > cfgMaxDeuteronTofPidPreselection) { + return; + } + if (std::abs(dcaDeuteron) < cfgMinDeuteronDcaPreselection) { + return; + } + if (cfgCutOnDeuteronDcaOrdering && (std::abs(dcaDeuteron) > std::abs(dcaKaon) || std::abs(dcaDeuteron) > std::abs(dcaPion))) { + return; + } + + if (fillCandLiteTree) { + rowCandCdLite( + invMassCd, invMassLc, pt, eta, phi, ptProng0, ptProng1, ptProng2, + candidate.impactParameter0(), candidate.impactParameter1(), candidate.impactParameter2(), + decayLength, cpa, chi2PCA, nSigmaTpcDe, nSigmaTpcPr, nSigmaItsDe, nSigmaTofDe, + tofBetaDe, tpcInnerParamDe, tofExpMomDe, + candidate.ct(o2::constants::physics::MassCDeuteron), + candFlag, candSign, 0, -1, hypothesisMask, candidateGlobalIndex, 0, -1, -1.f, cent); + } + + if (fillCandFullTree) { + rowCandCdFull( + candidate.pxProng0(), candidate.pyProng0(), candidate.pzProng0(), + candidate.pxProng1(), candidate.pyProng1(), candidate.pzProng1(), + candidate.pxProng2(), candidate.pyProng2(), candidate.pzProng2(), + candidate.impactParameter0(), candidate.impactParameter1(), candidate.impactParameter2(), + decayLength, cpa, chi2PCA, nSigmaTpcDe, nSigmaTpcPr, nSigmaItsDe, nSigmaTofDe, + tofBetaDe, tpcInnerParamDe, tofExpMomDe, + nSigmaTpcPi, nSigmaTofPi, nSigmaTpcKa, nSigmaTofKa, + candidate.ct(o2::constants::physics::MassCDeuteron), + candFlag, candSign, 0, -1, hypothesisMask, candidateGlobalIndex, 0, 0, -1.f, collision.numContrib(), cent, + collision.posZ(), collision.globalIndex(), timeStamp); + } + }; + // Data have no truth information: retain every selected hypothesis. if (selDeKPi) { - candFlag = 1; - pSignedDe = prong0.tpcInnerParam() * prong0.sign(); - pSignedPi = prong2.tpcInnerParam() * prong2.sign(); - nSigmaTpcDe = candidate.nSigTpcDe0(); - nSigmaTpcPr = candidate.nSigTpcPr0(); - nSigmaTofDe = candidate.nSigTofDe0(); - tofBetaDe = (prong0.hasTOF() && prong0.beta() > 0.f) ? prong0.beta() : -999.f; - tpcInnerParamDe = prong0.tpcInnerParam(); - tofExpMomDe = prong0.hasTOF() ? prong0.tofExpMom() : -999.f; - nSigmaTpcPi = candidate.nSigTpcPi2(); - nSigmaTofPi = candidate.nSigTofPi2(); - nSigmaItsDe = prong0Its.itsNSigmaDe(); - // itsNClusterSizeDe = prong0.itsClusterSizes(); - tpcSignalsDe = prong0.tpcSignal(); - tpcSignalsPi = prong2.tpcSignal(); - itsSignalsDe = itsSignal(prong0); - - dcaDeuteron = candidate.impactParameter0(); - dcaKaon = candidate.impactParameter1(); - dcaPion = candidate.impactParameter2(); - } else if (selPiKDe) { - candFlag = -1; - pSignedDe = prong2.tpcInnerParam() * prong2.sign(); - pSignedPi = prong0.tpcInnerParam() * prong0.sign(); - nSigmaTpcDe = candidate.nSigTpcDe2(); - nSigmaTpcPr = candidate.nSigTpcPr2(); - nSigmaTofDe = candidate.nSigTofDe2(); - tofBetaDe = (prong2.hasTOF() && prong2.beta() > 0.f) ? prong2.beta() : -999.f; - tpcInnerParamDe = prong2.tpcInnerParam(); - tofExpMomDe = prong2.hasTOF() ? prong2.tofExpMom() : -999.f; - nSigmaTpcPi = candidate.nSigTpcPi0(); - nSigmaTofPi = candidate.nSigTofPi0(); - nSigmaItsDe = prong2Its.itsNSigmaDe(); - // itsNClusterSizeDe = prong2.itsClusterSizes(); - tpcSignalsDe = prong2.tpcSignal(); - tpcSignalsPi = prong0.tpcSignal(); - itsSignalsDe = itsSignal(prong2); - - dcaDeuteron = candidate.impactParameter2(); - dcaKaon = candidate.impactParameter1(); - dcaPion = candidate.impactParameter0(); + writeDataHypothesis(true); } - - // PID QA - registry.fill(HIST("Data/hNsigmaTPCDeVsP"), pSignedDe, nSigmaTpcDe); - registry.fill(HIST("Data/hNsigmaTPCPrVsP"), pSignedDe, nSigmaTpcPr); - registry.fill(HIST("Data/hNsigmaTOFDeVsP"), pSignedDe, nSigmaTofDe); - registry.fill(HIST("Data/hNsigmaITSDeVsP"), pSignedDe, nSigmaItsDe); - registry.fill(HIST("Data/hTPCSignalDeVsP"), pSignedDe, tpcSignalsDe); - registry.fill(HIST("Data/hTPCSignalPiVsP"), pSignedPi, tpcSignalsPi); - registry.fill(HIST("Data/hTPCSignalKaVsP"), prong1.tpcInnerParam() * prong1.sign(), tpcSignalsKa); - registry.fill(HIST("Data/hITSSignalDeVsP"), pSignedDe, itsSignalsDe); - registry.fill(HIST("Data/hNsigmaTPCPiVsP"), pSignedPi, nSigmaTpcPi); - registry.fill(HIST("Data/hNsigmaTOFPiVsP"), pSignedPi, nSigmaTofPi); - registry.fill(HIST("Data/hNsigmaTPCKaVsP"), prong1.tpcInnerParam() * prong1.sign(), nSigmaTpcKa); - registry.fill(HIST("Data/hNsigmaTOFKaVsP"), prong1.tpcInnerParam() * prong1.sign(), nSigmaTofKa); - - if (cfgUseTofPidForDeuteron && std::abs(nSigmaTofDe) > cfgMaxDeuteronTofPidPreselection) { - continue; - } - if (std::abs(dcaDeuteron) < cfgMinDeuteronDcaPreselection) { - continue; - } - if (cfgCutOnDeuteronDcaOrdering && (std::abs(dcaDeuteron) > std::abs(dcaKaon) || std::abs(dcaDeuteron) > std::abs(dcaPion))) { - continue; - } - if (fillCandLiteTree) { - - rowCandCdLite( - invMassCd, - invMassLc, - pt, - eta, - phi, - ptProng0, - ptProng1, - ptProng2, - candidate.impactParameter0(), - candidate.impactParameter1(), - candidate.impactParameter2(), - decayLength, - cpa, - chi2PCA, - nSigmaTpcDe, - nSigmaTpcPr, - nSigmaItsDe, - nSigmaTofDe, - tofBetaDe, - tpcInnerParamDe, - tofExpMomDe, - candidate.ct(o2::constants::physics::MassCDeuteron), - candFlag, - candSign, - 0, - 0, - -1, - -1.f, - cent); - } - - if (fillCandFullTree) { - - rowCandCdFull( - candidate.pxProng0(), - candidate.pyProng0(), - candidate.pzProng0(), - candidate.pxProng1(), - candidate.pyProng1(), - candidate.pzProng1(), - candidate.pxProng2(), - candidate.pyProng2(), - candidate.pzProng2(), - candidate.impactParameter0(), - candidate.impactParameter1(), - candidate.impactParameter2(), - decayLength, - cpa, - chi2PCA, - nSigmaTpcDe, - nSigmaTpcPr, - nSigmaItsDe, - nSigmaTofDe, - tofBetaDe, - tpcInnerParamDe, - tofExpMomDe, - nSigmaTpcPi, - nSigmaTofPi, - nSigmaTpcKa, - nSigmaTofKa, - candidate.ct(o2::constants::physics::MassCDeuteron), - candFlag, - candSign, - 0, - 0, - -1, - -1.f, - cent, - collision.posZ(), - collision.globalIndex(), - timeStamp); + if (selPiKDe) { + writeDataHypothesis(false); } } } diff --git a/PWGHF/D2H/Tasks/taskCharmPolarisation.cxx b/PWGHF/D2H/Tasks/taskCharmPolarisation.cxx index 5bd5b1b4bb4..0691e76b104 100644 --- a/PWGHF/D2H/Tasks/taskCharmPolarisation.cxx +++ b/PWGHF/D2H/Tasks/taskCharmPolarisation.cxx @@ -29,6 +29,7 @@ #include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Qvectors.h" #include @@ -226,9 +227,9 @@ struct HfTaskCharmPolarisation { HfEventSelection hfEvSel; // event selection and monitoring o2::framework::Service ccdb{}; - using CollisionsWithMcLabels = soa::SmallGroups>; - using CollisionsWithMcLabelsAndCent = soa::SmallGroups>; - using CollsWithQVecs = soa::Join; + using CollisionsWithMcLabels = soa::SmallGroups>; + using CollisionsWithMcLabelsAndCent = soa::SmallGroups>; + using CollsWithQVecs = soa::Join; using TracksWithMcLabels = soa::Join; using TracksWithExtra = soa::Join; diff --git a/PWGHF/D2H/Tasks/taskD0.cxx b/PWGHF/D2H/Tasks/taskD0.cxx index e40d15a7c57..66d9c90d620 100644 --- a/PWGHF/D2H/Tasks/taskD0.cxx +++ b/PWGHF/D2H/Tasks/taskD0.cxx @@ -26,12 +26,14 @@ #include "PWGHF/DataModel/TrackIndexSkimmingTables.h" #include "PWGHF/Utils/utilsEvSelHf.h" #include "PWGHF/Utils/utilsUpcHf.h" +#include "PWGLF/DataModel/mcCentrality.h" #include "PWGUD/Core/UPCHelpers.h" #include "Common/CCDB/ctpRateFetcher.h" #include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/TrackSelectionTables.h" #include @@ -57,6 +59,7 @@ #include #include #include +#include #include using namespace o2; @@ -81,6 +84,12 @@ enum CandTypeSel { }; } // namespace struct HfTaskD0 { + enum RecoEventStatus { + NoRecoCollision = 0, + NoSelectedRecoCollision, + SelectedRecoCollision + }; + Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection Flag for D0"}; Configurable selectionFlagD0bar{"selectionFlagD0bar", 1, "Selection Flag for D0bar"}; Configurable yCandGenMax{"yCandGenMax", 0.5, "max. gen particle rapidity"}; @@ -91,6 +100,7 @@ struct HfTaskD0 { Configurable selectionPid{"selectionPid", 1, "Selection Flag for reco PID candidates"}; Configurable> binsPt{"binsPt", std::vector{hf_cuts_d0_to_pi_k::vecBinsPt}, "pT bin limits"}; Configurable centEstimator{"centEstimator", 0, "Centrality estimation (None: 0, FT0C: 2, FT0M: 3)"}; + Configurable fillEventStatus{"fillEventStatus", false, "Use generated centrality in hSparseAcc and append reco-event status (requires storeCentrality)"}; Configurable occEstimator{"occEstimator", 0, "Occupancy estimation (None: 0, ITS: 1, FT0C: 2)"}; Configurable storeCentrality{"storeCentrality", false, "Flag to store centrality information"}; Configurable storeOccupancyAndIR{"storeOccupancyAndIR", false, "Flag to store occupancy information and interaction rate"}; @@ -120,10 +130,11 @@ struct HfTaskD0 { using D0CandidatesMlKF = soa::Filtered>; using D0CandidatesMlMcKF = soa::Filtered>; - using Collisions = soa::Join; - using CollisionsCent = soa::Join; - using CollisionsWithMcLabels = soa::Join; - using CollisionsWithMcLabelsCent = soa::Join; + using Collisions = soa::Join; + using CollisionsCent = soa::Join; + using CollisionsWithMcLabels = soa::Join; + using CollisionsWithMcLabelsCent = soa::Join; + using McCollisionsWithCentrality = soa::Join; using TracksSelQuality = soa::Join; using TracksWPid = soa::Join; // using TracksWithExtra = o2::soa::Join; @@ -330,13 +341,22 @@ struct HfTaskD0 { std::vector axesAcc = {thnAxisGenPtD, thnAxisGenPtB, thnAxisY, thnAxisOrigin, thnAxisNumPvContr}; if (storeCentrality) { - axesAcc.push_back(thnAxisCent); + axesAcc.emplace_back(thnConfigAxisCent, fillEventStatus ? "Generated centrality (%)" : "Centrality"); } // interaction rate only store in Data and MC Reco. Level if (storeOccupancyAndIR) { axesAcc.push_back(thnAxisOccupancy); } + if (fillEventStatus) { + if (!storeCentrality) { + LOGP(fatal, "fillEventStatus requires storeCentrality=true."); + } + if (centEstimator != CentralityEstimator::FT0C && centEstimator != CentralityEstimator::FT0M) { + LOGP(fatal, "centEstimator must be FT0C (2) or FT0M (3)."); + } + axesAcc.emplace_back(3, -0.5, 2.5, "Reco event status (0: no reco, 1: none selected, 2: selected)"); + } registry.add("hSparseAcc", "Thn for generated D0 from charm and beauty", HistType::kTHnSparseD, axesAcc); registry.get(HIST("hSparseAcc"))->Sumw2(); } @@ -483,7 +503,11 @@ struct HfTaskD0 { registry.add("QAtracks/hDCAxy_GapC", "Gap C; DCA xy", {HistType::kTH1F, {{400, -2, 2.}}}); registry.add("QAtracks/hDCAz_GapC", "Gap C; DCA z", {HistType::kTH1F, {{400, -4, 4.}}}); - hfEvSel.addHistograms(registry); + if (fillEventStatus && (doprocessMcWithDCAFitterN || doprocessMcWithDCAFitterNCent || doprocessMcWithKFParticle || doprocessMcWithDCAFitterNMl || doprocessMcWithDCAFitterNMlCent || doprocessMcWithKFParticleMl)) { + hfEvSel.init(registry); + } else { + hfEvSel.addHistograms(registry); + } ccdb->setURL(ccdbUrl); ccdb->setCaching(true); @@ -969,7 +993,7 @@ struct HfTaskD0 { soa::Join const& mcParticles, TracksSelQuality const&, CollType const& collisions, - aod::McCollisions const&, + McCollisionsWithCentrality const&, BCsType const&) { // MC rec. @@ -1254,7 +1278,31 @@ struct HfTaskD0 { } } } - // MC gen. + // Classify reco associations once per collision, not once per generated particle. + // The task's hfEvSel.* configuration must match the candidate creator's cuts. + std::unordered_map recoEventStatus; + if (fillEventStatus) { + for (const auto& collision : collisions) { + if (!collision.has_mcCollision()) { + continue; + } + float unusedCentrality{-1.f}; + const auto rejectionMask = hfEvSel.getHfCollisionRejectionMask(collision, unusedCentrality, ccdb, registry); + bool selected = rejectionMask == 0; + if constexpr (std::is_same_v) { + if (centEstimator != CentralityEstimator::None) { + const auto recoCentrality = getCentralityColl(collision, centEstimator); + selected = selected && recoCentrality >= hfEvSel.centralityMin && recoCentrality <= hfEvSel.centralityMax; + } + } + auto& status = recoEventStatus[collision.mcCollisionId()]; + const int currentStatus = selected ? SelectedRecoCollision : NoSelectedRecoCollision; + status = std::max(status, currentStatus); + } + } + + // MC gen. Each particle is filled once, even for split or unreconstructed events. + // Upstream event rejection can clear flagMcMatchGen: this is not an unfiltered truth sample. for (const auto& particle : mcParticles) { if (std::abs(particle.flagMcMatchGen()) == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { if (yCandGenMax >= 0. && std::abs(RecoDecay::y(particle.pVector(), o2::constants::physics::MassD0)) > yCandGenMax) { @@ -1266,11 +1314,13 @@ struct HfTaskD0 { registry.fill(HIST("hPtGen"), ptGen); registry.fill(HIST("hPtVsYGen"), ptGen, yGen); + int eventStatus = NoRecoCollision; + unsigned maxNumContrib = 0; float cent{-1.f}; float occ{-1.f}; if constexpr (std::is_same_v) { - const auto& recoCollsPerMcCollCent = collisions.sliceBy(colPerMcCollisionCent, particle.mcCollision().globalIndex()); + const auto& recoCollsPerMcCollCent = collisions.sliceBy(colPerMcCollisionCent, particle.mcCollisionId()); for (const auto& recCol : recoCollsPerMcCollCent) { maxNumContrib = recCol.numContrib() > maxNumContrib ? recCol.numContrib() : maxNumContrib; } @@ -1281,24 +1331,39 @@ struct HfTaskD0 { occ = o2::hf_occupancy::getOccupancyGenColl(recoCollsPerMcCollCent, occEstimator); } } else { - const auto& recoCollsPerMcColl = collisions.sliceBy(colPerMcCollision, particle.mcCollision().globalIndex()); + const auto& recoCollsPerMcColl = collisions.sliceBy(colPerMcCollision, particle.mcCollisionId()); for (const auto& recCol : recoCollsPerMcColl) { maxNumContrib = recCol.numContrib() > maxNumContrib ? recCol.numContrib() : maxNumContrib; } } + if (fillEventStatus) { + const auto mcCollision = particle.template mcCollision_as(); + const auto eventEntry = recoEventStatus.find(mcCollision.globalIndex()); + eventStatus = eventEntry == recoEventStatus.end() ? NoRecoCollision : eventEntry->second; + // Replace the existing centrality coordinate, including zero-reco events. + cent = centEstimator == CentralityEstimator::FT0C ? mcCollision.centFT0C() : mcCollision.centFT0M(); + } + const auto fillGeneratedSparse = [&](auto... coordinates) { + if (fillEventStatus) { + registry.fill(HIST("hSparseAcc"), coordinates..., eventStatus); + } else { + registry.fill(HIST("hSparseAcc"), coordinates...); + } + }; + if (particle.originMcGen() == RecoDecay::OriginType::Prompt) { registry.fill(HIST("hPtGenPrompt"), ptGen); registry.fill(HIST("hYGenPrompt"), yGen); registry.fill(HIST("hPtVsYGenPrompt"), ptGen, yGen); if (storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 1, maxNumContrib, cent, occ); + fillGeneratedSparse(ptGen, ptGenB, yGen, 1, maxNumContrib, cent, occ); } else if (storeCentrality && !storeOccupancyAndIR) { - registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 1, maxNumContrib, cent); + fillGeneratedSparse(ptGen, ptGenB, yGen, 1, maxNumContrib, cent); } else if (!storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 1, maxNumContrib, occ); + fillGeneratedSparse(ptGen, ptGenB, yGen, 1, maxNumContrib, occ); } else { - registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 1, maxNumContrib); + fillGeneratedSparse(ptGen, ptGenB, yGen, 1, maxNumContrib); } } else { ptGenB = mcParticles.rawIteratorAt(particle.idxBhadMotherPart()).pt(); @@ -1306,13 +1371,13 @@ struct HfTaskD0 { registry.fill(HIST("hYGenNonPrompt"), yGen); registry.fill(HIST("hPtVsYGenNonPrompt"), ptGen, yGen); if (storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 2, maxNumContrib, cent, occ); + fillGeneratedSparse(ptGen, ptGenB, yGen, 2, maxNumContrib, cent, occ); } else if (storeCentrality && !storeOccupancyAndIR) { - registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 2, maxNumContrib, cent); + fillGeneratedSparse(ptGen, ptGenB, yGen, 2, maxNumContrib, cent); } else if (!storeCentrality && storeOccupancyAndIR) { - registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 2, maxNumContrib, occ); + fillGeneratedSparse(ptGen, ptGenB, yGen, 2, maxNumContrib, occ); } else { - registry.fill(HIST("hSparseAcc"), ptGen, ptGenB, yGen, 2, maxNumContrib); + fillGeneratedSparse(ptGen, ptGenB, yGen, 2, maxNumContrib); } } registry.fill(HIST("hEtaGen"), particle.eta()); @@ -1324,7 +1389,7 @@ struct HfTaskD0 { soa::Join const& mcParticles, TracksSelQuality const& tracks, CollisionsWithMcLabels const& collisions, - aod::McCollisions const& mcCollisions, + McCollisionsWithCentrality const& mcCollisions, aod::BcFullInfos const& bcs) { processMc(selectedD0CandidatesMc, mcParticles, tracks, collisions, mcCollisions, bcs); @@ -1335,7 +1400,7 @@ struct HfTaskD0 { soa::Join const& mcParticles, TracksSelQuality const& tracks, CollisionsWithMcLabelsCent const& collisions, - aod::McCollisions const& mcCollisions, + McCollisionsWithCentrality const& mcCollisions, aod::BcFullInfos const& bcs) { processMc(selectedD0CandidatesMc, mcParticles, tracks, collisions, mcCollisions, bcs); @@ -1346,7 +1411,7 @@ struct HfTaskD0 { soa::Join const& mcParticles, TracksSelQuality const& tracks, CollisionsWithMcLabels const& collisions, - aod::McCollisions const& mcCollisions, + McCollisionsWithCentrality const& mcCollisions, aod::BcFullInfos const& bcs) { processMc(selectedD0CandidatesMcKF, mcParticles, tracks, collisions, mcCollisions, bcs); @@ -1358,7 +1423,7 @@ struct HfTaskD0 { soa::Join const& mcParticles, TracksSelQuality const& tracks, CollisionsWithMcLabels const& collisions, - aod::McCollisions const& mcCollisions, + McCollisionsWithCentrality const& mcCollisions, aod::BcFullInfos const& bcs) { processMc(selectedD0CandidatesMlMc, mcParticles, tracks, collisions, mcCollisions, bcs); @@ -1369,7 +1434,7 @@ struct HfTaskD0 { soa::Join const& mcParticles, TracksSelQuality const& tracks, CollisionsWithMcLabelsCent const& collisions, - aod::McCollisions const& mcCollisions, + McCollisionsWithCentrality const& mcCollisions, aod::BcFullInfos const& bcs) { processMc(selectedD0CandidatesMlMc, mcParticles, tracks, collisions, mcCollisions, bcs); @@ -1380,7 +1445,7 @@ struct HfTaskD0 { soa::Join const& mcParticles, TracksSelQuality const& tracks, CollisionsWithMcLabels const& collisions, - aod::McCollisions const& mcCollisions, + McCollisionsWithCentrality const& mcCollisions, aod::BcFullInfos const& bcs) { processMc(selectedD0CandidatesMlMcKF, mcParticles, tracks, collisions, mcCollisions, bcs); @@ -1388,7 +1453,7 @@ struct HfTaskD0 { PROCESS_SWITCH(HfTaskD0, processMcWithKFParticleMl, "Process MC with KFParticle and ML selections", false); // TODO: add the processMcWithKFParticleMlCent - void processDataWithDCAFitterNWithUpc(soa::Join const& collisions, + void processDataWithDCAFitterNWithUpc(soa::Join const& collisions, aod::BcFullInfos const& bcs, D0Candidates const&, aod::TracksWExtra const&, @@ -1403,7 +1468,7 @@ struct HfTaskD0 { } PROCESS_SWITCH(HfTaskD0, processDataWithDCAFitterNWithUpc, "Process real data with DCAFitterN w/o ML with UPC", false); - void processDataWithDCAFitterNMlWithUpc(soa::Join const& collisions, + void processDataWithDCAFitterNMlWithUpc(soa::Join const& collisions, aod::BcFullInfos const& bcs, D0CandidatesMl const&, aod::TracksWExtra const&, diff --git a/PWGHF/D2H/Tasks/taskDeuteronFromLb.cxx b/PWGHF/D2H/Tasks/taskDeuteronFromLb.cxx index 3910c3447ef..6b04ccd3501 100644 --- a/PWGHF/D2H/Tasks/taskDeuteronFromLb.cxx +++ b/PWGHF/D2H/Tasks/taskDeuteronFromLb.cxx @@ -71,6 +71,7 @@ struct HfTaskDeuteronFromLb { Configurable cfgDCAmin{"cfgDCAmin", 0.05f, "Minimum DCA for deuteron PID"}; Configurable cfgDCAmax{"cfgDCAmax", 1000.0f, "Maximum DCA for deuteron PID"}; Configurable rapidityCut{"rapidityCut", 0.5f, "Rapidity cut"}; + Configurable ptThresholdforPID{"ptThresholdforPID", 1.0f, "pT threshold for PID, above this value TPC+TOF PID is used, below only TPC PID is used"}; // PDG codes Configurable pdgCodeBeautyMeson{"pdgCodeBeautyMeson", -521, "PDG code of the beauty meson mother particle (default: B-)"}; Configurable pdgCodeBeautyBaryon{"pdgCodeBeautyBaryon", -5122, "PDG code of the beauty baryon mother particle (default: anti-Lambda_b)"}; @@ -135,6 +136,8 @@ struct HfTaskDeuteronFromLb { qaHistos.add("Data/ptAntiDeuteron", "ptAntiDeuteron", {HistType::kTH1F, {ptAxis}}); qaHistos.add("Data/etaAntideuteron", "etaAntideuteron", {HistType::kTH1F, {{100, -1.0f, 1.0f, "eta #bar{d}"}}}); qaHistos.add("Data/hVtxZ", "Z-Vertex distribution after selection;Z (cm)", HistType::kTH1F, {{100, -50, 50}}); + qaHistos.add("Data/hnSigmaTOFVsPtPurity", "n#sigma TOF vs p_{T} for #bar{d} hypothesis for Data-driven purity check; p_{T} (GeV/c); n#sigma TOF", {HistType::kTH2D, {ptAxis, nSigmaAxis}}); + qaHistos.add("Data/hnSigmaTPCVsPtPurity", "n#sigma TPC vs p_{T} for #bar{d} hypothesis for Data-driven purity check; p_{T} (GeV/c); n#sigma TPC", {HistType::kTH2D, {ptAxis, nSigmaAxis}}); // MC generated-level histograms qaHistos.add("MCGen/ptGeneratedBminus", "p_{T} generated B^{-};p_{T} (GeV/c);Counts", HistType::kTH1F, {ptAxis}); qaHistos.add("MCGen/ptGeneratedAntiLambdaB", "p_{T} generated #bar{#Lambda}_{b};p_{T} (GeV/c);Counts", HistType::kTH1F, {ptAxis}); @@ -145,6 +148,7 @@ struct HfTaskDeuteronFromLb { qaHistos.add("MCGen/hMotherPdgCode", "PDG code of mother, gen level;PDG code;Counts", HistType::kTH1I, {{12000, -6000, 6000}}); qaHistos.add("MCGen/ctauBminus", "ctau of B^{-}, gen level;ctau (#mu m);Counts", HistType::kTH1F, {{25, 0., 2000.f}}); qaHistos.add("MCGen/ctauAntiLambdaB", "ctau of #bar{#Lambda}_{b}, gen level;ctau (#mu m);Counts", HistType::kTH1F, {{25, 0., 2000.f}}); + // MC reco/MC-anchored histograms qaHistos.add("MCReco/ptAntiDeuteronFromBminus", "p_{T} #bar{d} from B^{-} reco/MC anchored;p_{T} (GeV/c);Counts", @@ -160,6 +164,7 @@ struct HfTaskDeuteronFromLb { {ptAxis}); qaHistos.add("MCGen/ptAntiDeuteronFromBminus", "p_{T} #bar{d} from B^{-} gen;p_{T} (GeV/c);Counts", HistType::kTH1F, {ptAxis}); qaHistos.add("MCGen/ptAntiDeuteronFromAntiLambdaB", "p_{T} #bar{d} from #bar{#Lambda}_{b} gen;p_{T} (GeV/c);Counts", HistType::kTH1F, {ptAxis}); + qaHistos.add("MCGen/ptAntiDeuteronAll", "p_{T} #bar{d} all gen;p_{T} (GeV/c);Counts", HistType::kTH1F, {ptAxis}); qaHistos.add("MCReco/hDCAxy-Primary", "DCAxy primary reco/MC anchored;DCA xy (cm);Counts", {HistType::kTH1D, {{400, -0.2f, 0.2f, "DCA xy (cm)"}}}); qaHistos.add("MCReco/hDCAxy-FromBeautyHadron", "DCAxy from beauty reco/MC anchored;DCA xy (cm);Counts", {HistType::kTH1D, {{400, -0.2f, 0.2f, "DCA xy (cm)"}}}); qaHistos.add("MCReco/hMotherPdgCode", "PDG code of mother, reco/MC anchored;PDG code;Counts", HistType::kTH1I, {{12000, -6000, 6000}}); @@ -169,8 +174,6 @@ struct HfTaskDeuteronFromLb { qaHistos.add("MCReco/ptAntiDeuteronPIDSelectedTrue", "p_{T} #bar{d} reco/MC anchored PID and PDG;p_{T} (GeV/c);Counts", HistType::kTH1F, {ptAxis}); qaHistos.add("MCReco/hnSigmaTPCVsPt", "n#sigma TPC vs p_{T} for #bar{d} hypothesis for MC; p_{T} (GeV/c); n#sigma TPC", {HistType::kTH2D, {ptAxis, nSigmaAxis}}); qaHistos.add("MCReco/hnSigmaTOFVsPt", "n#sigma TOF vs p_{T} for #bar{d} hypothesis for MC; p_{T} (GeV/c); n#sigma TOF", {HistType::kTH2D, {ptAxis, nSigmaAxis}}); - qaHistos.add("Data/hnSigmaTOFVsPtPurity", "n#sigma TOF vs p_{T} for #bar{d} hypothesis for Data-driven purity check; p_{T} (GeV/c); n#sigma TOF", {HistType::kTH2D, {ptAxis, nSigmaAxis}}); - qaHistos.add("Data/hnSigmaTPCVsPtPurity", "n#sigma TPC vs p_{T} for #bar{d} hypothesis for Data-driven purity check; p_{T} (GeV/c); n#sigma TPC", {HistType::kTH2D, {ptAxis, nSigmaAxis}}); qaHistos.add("MCReco/ptAntiDeuteronTPCOnlyPIDSelected", "p_{T} #bar{d} reco/MC anchored TPC only PID selection;p_{T} (GeV/c);Counts", HistType::kTH1F, {ptAxis}); qaHistos.add("MCReco/ptAntiDeuteronTPCOnlyPIDSelectedTrue", "p_{T} #bar{d} reco/MC anchored TPC only PID and PDG;p_{T} (GeV/c);Counts", HistType::kTH1F, {ptAxis}); qaHistos.add("MCReco/ptAntiDeuteronTPCorTPCTOFPIDSelected", "p_{T} #bar{d} reco/MC anchored TPC or TPC+TOF PID selection;p_{T} (GeV/c);Counts", HistType::kTH1F, {ptAxis}); @@ -285,14 +288,23 @@ struct HfTaskDeuteronFromLb { const bool isTPCDe = std::abs(track.tpcNSigmaDe()) < cfgTPCNsigma; const bool isTOFDe = std::abs(track.tofNSigmaDe()) < cfgTofNsigma; - if (isTPCDe && track.hasTOF()) { - qaHistos.fill(HIST("Data/hnSigmaTOFVsPtPurity"), track.pt(), track.tofNSigmaDe()); - } - if (isTOFDe && track.hasTOF()) { + if (track.pt() < ptThresholdforPID) { qaHistos.fill(HIST("Data/hnSigmaTPCVsPtPurity"), track.pt(), track.tpcNSigmaDe()); + } else { + if (isTPCDe && track.hasTOF()) { + qaHistos.fill(HIST("Data/hnSigmaTOFVsPtPurity"), track.pt(), track.tofNSigmaDe()); + } } - if (isTPCDe && isTOFDe && track.hasTOF()) { + if (track.pt() < ptThresholdforPID && isTPCDe) { + qaHistos.fill(HIST("Data/ptAntiDeuteron"), track.pt()); + qaHistos.fill(HIST("Data/etaAntideuteron"), track.eta()); + qaHistos.fill(HIST("Data/hDCAxyVsPt"), track.pt(), dca[0]); + qaHistos.fill(HIST("Data/hDCAzVsPt"), track.pt(), dca[1]); + qaHistos.fill(HIST("Data/hnSigmaTPCVsPt"), track.pt(), track.tpcNSigmaDe()); + qaHistos.fill(HIST("Data/hnSigmaTOFVsPt"), track.pt(), track.tofNSigmaDe()); + } + if (track.pt() >= ptThresholdforPID && isTPCDe && isTOFDe && track.hasTOF()) { qaHistos.fill(HIST("Data/ptAntiDeuteron"), track.pt()); qaHistos.fill(HIST("Data/etaAntideuteron"), track.eta()); qaHistos.fill(HIST("Data/hDCAxyVsPt"), track.pt(), dca[0]); @@ -443,6 +455,9 @@ struct HfTaskDeuteronFromLb { } if (mcParticle.pdgCode() == pdgCodeDaughter) { + if (std::abs(mcParticle.eta()) < cfgEta) { + qaHistos.fill(HIST("MCGen/ptAntiDeuteronAll"), mcParticle.pt()); + } if (std::abs(mcParticle.y()) > rapidityCut) { continue; diff --git a/PWGHF/D2H/Tasks/taskDplus.cxx b/PWGHF/D2H/Tasks/taskDplus.cxx index d2d0f0279dd..b252a246155 100644 --- a/PWGHF/D2H/Tasks/taskDplus.cxx +++ b/PWGHF/D2H/Tasks/taskDplus.cxx @@ -35,6 +35,7 @@ #include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include #include @@ -100,8 +101,8 @@ struct HfTaskDplus { using CandDplusMcRecoWithMl = soa::Filtered>; using CandDplusMcGen = soa::Join; - using CollisionsCent = soa::Join; - using McRecoCollisionsCent = soa::Join; + using CollisionsCent = soa::Join; + using McRecoCollisionsCent = soa::Join; Filter filterDplusFlag = (o2::aod::hf_track_index::hfflag & static_cast(BIT(aod::hf_cand_3prong::DecayType::DplusToPiKPi))) != static_cast(0); @@ -864,7 +865,7 @@ struct HfTaskDplus { } PROCESS_SWITCH(HfTaskDplus, processMcWithMl, "Process MC with ML", false); - void processDataWithUpc(soa::Join const& collisions, + void processDataWithUpc(soa::Join const& collisions, aod::BcFullInfos const& bcs, CandDplusData const& selectedDplusCandidates, aod::Tracks const&, @@ -877,7 +878,7 @@ struct HfTaskDplus { } PROCESS_SWITCH(HfTaskDplus, processDataWithUpc, "Process real data w/o ML with UPC", false); - void processDataWithMlWithUpc(soa::Join const& collisions, + void processDataWithMlWithUpc(soa::Join const& collisions, aod::BcFullInfos const& bcs, CandDplusDataWithMl const& selectedDplusCandidatesMl, aod::Tracks const&, diff --git a/PWGHF/D2H/Tasks/taskDs.cxx b/PWGHF/D2H/Tasks/taskDs.cxx index d8d1362a5d3..7e79fe0f3ad 100644 --- a/PWGHF/D2H/Tasks/taskDs.cxx +++ b/PWGHF/D2H/Tasks/taskDs.cxx @@ -192,13 +192,13 @@ struct HfTaskDs { template using MemberFunctionPointer = bool (HfTaskDs::*)(const CandDs&); - using CollisionsWithFT0C = soa::Join; - using CollisionsWithFT0M = soa::Join; + using CollisionsWithFT0C = soa::Join; + using CollisionsWithFT0M = soa::Join; using CollisionsWithNTracksPV = soa::Join; - using CollisionsMc = soa::Join; - using CollisionsMcWithFT0C = soa::Join; - using CollisionsMcWithFT0M = soa::Join; + using CollisionsMc = soa::Join; + using CollisionsMcWithFT0C = soa::Join; + using CollisionsMcWithFT0M = soa::Join; using CollisionsMcWithNTracksPV = soa::Join; using CandDsData = soa::Filtered>; @@ -1122,7 +1122,7 @@ struct HfTaskDs { } PROCESS_SWITCH(HfTaskDs, processDataWithCentNTracksPV, "Process data w/o ML information on Ds, with information on centrality from NTracksPV", false); - void processData(soa::Join const& collisions, + void processData(soa::Join const& collisions, CandDsData const& candsDs, aod::BCs const&, aod::Tracks const&) @@ -1158,7 +1158,7 @@ struct HfTaskDs { } PROCESS_SWITCH(HfTaskDs, processDataWithMlAndCentNTracksPV, "Process data with ML information on Ds, with information on centrality", false); - void processDataWithMl(soa::Join const& collisions, + void processDataWithMl(soa::Join const& collisions, CandDsDataWithMl const& candsDs, aod::BCs const&, aod::Tracks const&) diff --git a/PWGHF/D2H/Tasks/taskDstarToD0Pi.cxx b/PWGHF/D2H/Tasks/taskDstarToD0Pi.cxx index bc4c27adbc7..cc0bcff73fb 100644 --- a/PWGHF/D2H/Tasks/taskDstarToD0Pi.cxx +++ b/PWGHF/D2H/Tasks/taskDstarToD0Pi.cxx @@ -418,7 +418,7 @@ struct HfTaskDstarToD0Pi { /// @param selectedCands selected candidates with selection flag /// @param preslice preslice to slice template - void runTaskDstar(CollisionsWCent const& cols, T1 selectedCands, T2 preslice) + void runTaskDstar(CollisionsWCent const& cols, const T1& selectedCands, const T2& preslice) { for (const auto& col : cols) { auto nPVContributors = col.numContrib(); diff --git a/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx b/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx index e6b87bd46f9..84842dcd578 100644 --- a/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx +++ b/PWGHF/D2H/Tasks/taskFlowCharmHadrons.cxx @@ -28,6 +28,7 @@ #include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/Qvectors.h" #include @@ -168,9 +169,9 @@ struct HfTaskFlowCharmHadrons { using CandXic0DataWMl = soa::Filtered>; using CandD0DataWMl = soa::Filtered>; using CandD0Data = soa::Filtered>; - using CollsWithSPQvecs = soa::Join; - using CollsWithEsEQvecs = soa::Join; - using CollsWithSPEsEQvecs = soa::Join; + using CollsWithSPQvecs = soa::Join; + using CollsWithEsEQvecs = soa::Join; + using CollsWithSPEsEQvecs = soa::Join; using TracksWithExtra = soa::Join; Filter filterSelectDsCandidates = aod::hf_sel_candidate_ds::isSelDsToKKPi >= selectionFlag || aod::hf_sel_candidate_ds::isSelDsToPiKK >= selectionFlag; diff --git a/PWGHF/D2H/Tasks/taskLc.cxx b/PWGHF/D2H/Tasks/taskLc.cxx index 0334f01ada9..c74ef2485ba 100644 --- a/PWGHF/D2H/Tasks/taskLc.cxx +++ b/PWGHF/D2H/Tasks/taskLc.cxx @@ -32,6 +32,7 @@ #include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include #include @@ -63,6 +64,7 @@ using namespace o2::framework::expressions; using namespace o2::hf_centrality; using namespace o2::hf_occupancy; using namespace o2::hf_evsel; +using namespace o2::constants::physics; /// Λc± → p± K∓ π± analysis task struct HfTaskLc { @@ -74,7 +76,7 @@ struct HfTaskLc { Configurable fillTHn{"fillTHn", false, "fill THn"}; Configurable storeOccupancy{"storeOccupancy", true, "Flag to store occupancy information"}; Configurable occEstimator{"occEstimator", 2, "Occupancy estimation (None: 0, ITS: 1, FT0C: 2)"}; - Configurable storeProperLifetime{"storeProperLifetime", false, "Flag to store proper lifetime"}; + Configurable storeProperDecayTime{"storeProperDecayTime", false, "Flag to store proper decay time"}; // CCDB configuration Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable ccdbPathGrp{"ccdbPathGrp", "GLO/GRP/GRP", "Path of the grp file (Run 2)"}; @@ -84,12 +86,12 @@ struct HfTaskLc { SliceCache cache; Service ccdb{}; - using Collisions = soa::Join; - using CollisionsMc = soa::Join; - using CollisionsWithFT0C = soa::Join; - using CollisionsMcWithFT0C = soa::Join; - using CollisionsWithFT0M = soa::Join; - using CollisionsMcWithFT0M = soa::Join; + using Collisions = soa::Join; + using CollisionsMc = soa::Join; + using CollisionsWithFT0C = soa::Join; + using CollisionsMcWithFT0C = soa::Join; + using CollisionsWithFT0M = soa::Join; + using CollisionsMcWithFT0M = soa::Join; using LcCandidates = soa::Filtered>; using LcCandidatesMl = soa::Filtered>; @@ -117,16 +119,9 @@ struct HfTaskLc { ConfigurableAxis thnConfigAxisGenPtB{"thnConfigAxisGenPtB", {1000, 0, 100}, "Gen Pt B"}; ConfigurableAxis thnConfigAxisNumPvContr{"thnConfigAxisNumPvContr", {200, -0.5, 199.5}, "Number of PV contributors"}; ConfigurableAxis thnConfigAxisOccupancy{"thnConfigAxisOccupancy", {14, 0, 14000}, "axis for centrality"}; - ConfigurableAxis thnConfigAxisProperLifetime{"thnConfigAxisProperLifetime", {200, 0, 2}, "Proper lifetime, ps"}; + ConfigurableAxis thnConfigAxisProperDecayTime{"thnConfigAxisProperDecayTime", {200, 0, 2}, "Proper decay time, ps"}; HistogramRegistry registry{"registry", {}}; - // Factors for conversion between units - constexpr static float CtToProperLifetimePs = 1.f / o2::constants::physics::LightSpeedCm2PS; - constexpr static float NanoToPico = 1000.f; - // Names of folders and suffixes for MC signal histograms - constexpr static std::string_view SignalFolders[] = {"signal", "prompt", "nonprompt"}; - constexpr static std::string_view SignalSuffixes[] = {"", "Prompt", "NonPrompt"}; - enum MlClasses : int { MlClassBackground = 0, MlClassPrompt, @@ -137,9 +132,16 @@ struct HfTaskLc { enum SignalClasses : int { Signal = 0, Prompt, - NonPrompt + NonPrompt, + NumberOfSignalClasses }; + // Factor for conversion between units + constexpr static float CtToProperDecayTimePs = 1.f / o2::constants::physics::LightSpeedCm2PS; + // Names of folders and suffixes for MC signal histograms + constexpr static std::array SignalFolders = {"signal", "prompt", "nonprompt"}; + constexpr static std::array SignalSuffixes = {"", "Prompt", "NonPrompt"}; + void init(InitContext&) { const std::array doprocess{doprocessDataStd, doprocessDataStdWithFT0C, doprocessDataStdWithFT0M, doprocessDataWithMl, doprocessDataWithMlWithFT0C, doprocessDataWithMlWithFT0M, doprocessMcStd, doprocessMcStdWithFT0C, doprocessMcStdWithFT0M, doprocessMcWithMl, doprocessMcWithMlWithFT0C, doprocessMcWithMlWithFT0M}; @@ -186,8 +188,8 @@ struct HfTaskLc { addHistogramsRec("hDecLength", "decay length (cm)", "entries", {HistType::kTH1F, {{400, 0., 1.}}}); /// decay length xy candidate addHistogramsRec("hDecLengthxy", "decay length xy (cm)", "entries", {HistType::kTH1F, {{400, 0., 1.}}}); - /// proper lifetime - addHistogramsRec("hCt", "proper lifetime (#Lambda_{c}) * #it{c} (cm)", "entries", {HistType::kTH1F, {{100, 0., 0.2}}}); + /// proper decay time + addHistogramsRec("hCt", "proper decay time (#Lambda_{c}) * #it{c} (cm)", "entries", {HistType::kTH1F, {{100, 0., 0.2}}}); /// cosine of pointing angle addHistogramsRec("hCPA", "cosine of pointing angle", "entries", {HistType::kTH1F, {{110, -1.1, 1.1}}}); /// cosine of pointing angle xy @@ -219,8 +221,8 @@ struct HfTaskLc { /// decay length xy candidate addHistogramsRec("hDecLengthxyVsPt", "decay length xy (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{400, 0., 1.}, {vbins}}}); - /// proper lifetime - addHistogramsRec("hCtVsPt", "proper lifetime (#Lambda_{c}) * #it{c} (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, 0., 0.2}, {vbins}}}); + /// proper decay time + addHistogramsRec("hCtVsPt", "proper decay time (#Lambda_{c}) * #it{c} (cm)", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{100, 0., 0.2}, {vbins}}}); /// cosine of pointing angle addHistogramsRec("hCPAVsPt", "cosine of pointing angle", "#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {{110, -1.1, 1.1}, {vbins}}}); @@ -268,7 +270,8 @@ struct HfTaskLc { const AxisSpec thnAxisPtB{thnConfigAxisGenPtB, "#it{p}_{T}^{B} (GeV/#it{c})"}; const AxisSpec thnAxisTracklets{thnConfigAxisNumPvContr, "Number of PV contributors"}; const AxisSpec thnAxisOccupancy{thnConfigAxisOccupancy, "Occupancy"}; - const AxisSpec thnAxisProperLifetime{thnConfigAxisProperLifetime, "T_{proper} (ps)"}; + const AxisSpec thnAxisProperDecayTime{thnConfigAxisProperDecayTime, "#it{t}_{proper} (ps)"}; + const AxisSpec thnAxisProperDecayTimeGen{thnConfigAxisProperDecayTime, "#it{t}_{proper, gen} (ps)"}; bool const isDataWithMl = doprocessDataWithMl || doprocessDataWithMlWithFT0C || doprocessDataWithMlWithFT0M; bool const isMcWithMl = doprocessMcWithMl || doprocessMcWithMlWithFT0C || doprocessMcWithMlWithFT0M; @@ -300,10 +303,13 @@ struct HfTaskLc { } } } - if (storeProperLifetime) { + if (storeProperDecayTime) { for (const auto& axes : std::array*, 3>{&axesWithBdt, &axesStd, &axesGen}) { if (!axes->empty()) { - axes->push_back(thnAxisProperLifetime); + axes->push_back(thnAxisProperDecayTime); + if (!isData && axes != &axesGen) { + axes->push_back(thnAxisProperDecayTimeGen); + } } } } @@ -334,13 +340,34 @@ struct HfTaskLc { return o2::hf_centrality::getCentralityColl(collision); } + /// Evaluate decay time of generated particle + /// \param mcParticleProng0 one of generated particle's daughters + /// \param motherParticle generated particle + /// \return decay time in picoseconds. For nonprompt particles it is evaluated as if it was prompt (as it is calculated for data) + float evaluateMcGenDecayTime(const McParticles3ProngMatched::iterator& mcParticleProng0, const McParticles3ProngMatched::iterator& motherParticle) + { + const auto mcCollision = motherParticle.template mcCollision_as(); + const float pMother = motherParticle.p(); + const float pvX = mcCollision.posX(); + const float pvY = mcCollision.posY(); + const float pvZ = mcCollision.posZ(); + const float svX = mcParticleProng0.vx(); + const float svY = mcParticleProng0.vy(); + const float svZ = mcParticleProng0.vz(); + + const float decayLength = static_cast(RecoDecay::distance(std::array{svX, svY, svZ}, std::array{pvX, pvY, pvZ})); + const float properDecayTime = decayLength * static_cast(MassLambdaCPlus) / LightSpeedCm2PS / pMother; + + return properDecayTime; + } + /// Helper function for filling MC reconstructed histograms for prompt, nonpromt and common (signal) /// \param candidate is a reconstructed candidate /// \tparam SignalType is an enum defining which histogram in which folder (signal, prompt or nonpromt) to fill template void fillHistogramsRecSig(CandidateType const& candidate) { - const auto& mcParticleProng0 = candidate.template prong0_as().template mcParticle_as>(); + const auto& mcParticleProng0 = candidate.template prong0_as().template mcParticle_as(); const auto pdgCodeProng0 = std::abs(mcParticleProng0.pdgCode()); if ((candidate.isSelLcToPKPi() >= selectionFlagLc) && pdgCodeProng0 == kProton) { registry.fill(HIST("MC/reconstructed/") + HIST(SignalFolders[SignalType]) + HIST("/hMassRecSig") + HIST(SignalSuffixes[SignalType]), HfHelper::invMassLcToPKPi(candidate)); @@ -385,8 +412,8 @@ struct HfTaskLc { /// Fill MC histograms at reconstruction level /// \tparam FillMl switch to fill ML histograms - template - void fillHistosMcRec(CollType const& collision, CandLcMcRec const& candidates, CandLcMcGen const& mcParticles) + template + void fillHistosMcRec(CollType const& collision, CandLcMcRec const& candidates, McParticles3ProngMatched const& mcParticles) { const auto thisCollId = collision.globalIndex(); const auto& groupedLcCandidates = candidates.sliceBy(candLcPerCollision, thisCollId); @@ -403,7 +430,7 @@ struct HfTaskLc { if (std::abs(candidate.flagMcMatchRec()) == hf_decay::hf_cand_3prong::DecayChannelMain::LcToPKPi) { // Get the corresponding MC particle. - const auto& mcParticleProng0 = candidate.template prong0_as().template mcParticle_as>(); + const auto& mcParticleProng0 = candidate.template prong0_as().template mcParticle_as(); const auto pdgCodeProng0 = std::abs(mcParticleProng0.pdgCode()); const auto indexMother = RecoDecay::getMother(mcParticles, mcParticleProng0, o2::constants::physics::Pdg::kLambdaCPlus, true); const auto particleMother = mcParticles.rawIteratorAt(indexMother); @@ -420,6 +447,8 @@ struct HfTaskLc { const auto numPvContributors = collision.numContrib(); const auto ptRecB = candidate.ptBhadMotherPart(); + const float properDecayTimeGen = evaluateMcGenDecayTime(mcParticleProng0, particleMother); + /// MC reconstructed signal fillHistogramsRecSig(candidate); @@ -438,7 +467,7 @@ struct HfTaskLc { occ = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); } double outputBkg(-1), outputPrompt(-1), outputFD(-1); - const float properLifetime = HfHelper::ctLc(candidate) * CtToProperLifetimePs; + const float properDecayTime = HfHelper::ctLc(candidate) * CtToProperDecayTimePs; auto fillTHnRecSig = [&](bool isPKPi) { const auto massLc = isPKPi ? HfHelper::invMassLcToPKPi(candidate) : HfHelper::invMassLcToPiKP(candidate); @@ -461,8 +490,9 @@ struct HfTaskLc { if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { valuesToFill.push_back(occ); } - if (storeProperLifetime) { - valuesToFill.push_back(properLifetime); + if (storeProperDecayTime) { + valuesToFill.push_back(properDecayTime); + valuesToFill.push_back(properDecayTimeGen); } if constexpr (FillMl) { registry.get(HIST("hnLcVarsWithBdt"))->Fill(valuesToFill.data()); @@ -485,8 +515,8 @@ struct HfTaskLc { /// Helper function for filling MC generated histograms for prompt, nonpromt and common (signal) /// \param particle is a generated particle /// \tparam SignalType is an enum defining which histogram in which folder (signal, prompt or nonpromt) to fill - template - void fillHistogramsGen(ParticleType const& particle) + template + void fillHistogramsGen(McParticles3ProngMatched::iterator const& particle) { registry.fill(HIST("MC/generated/") + HIST(SignalFolders[SignalType]) + HIST("/hPtGen") + HIST(SignalSuffixes[SignalType]), particle.pt()); registry.fill(HIST("MC/generated/") + HIST(SignalFolders[SignalType]) + HIST("/hEtaGen") + HIST(SignalSuffixes[SignalType]), particle.eta()); @@ -498,8 +528,8 @@ struct HfTaskLc { } /// Fill MC histograms at generated level - template - void fillHistosMcGen(CandLcMcGen const& mcParticles, Coll const& recoCollisions) + template + void fillHistosMcGen(McParticles3ProngMatched const& mcParticles, Coll const& recoCollisions) { // MC gen. for (const auto& particle : mcParticles) { @@ -522,10 +552,9 @@ struct HfTaskLc { occ = o2::hf_occupancy::getOccupancyGenColl(recoCollsPerMcColl, occEstimator); } - const auto& mcDaughter0 = particle.template daughters_as>().begin(); - const float p2m = particle.p() / o2::constants::physics::MassLambdaCPlus; - const float gamma = std::sqrt(1 + p2m * p2m); // mother's particle Lorentz factor - const float properLifetime = mcDaughter0.vt() * NanoToPico / gamma; // from ns to ps * from lab time to proper time + const auto mcDaughter0 = particle.template daughters_as().begin(); + + const float properDecayTime = evaluateMcGenDecayTime(mcDaughter0, particle); fillHistogramsGen(particle); @@ -537,8 +566,8 @@ struct HfTaskLc { if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { valuesToFill.push_back(occ); } - if (storeProperLifetime) { - valuesToFill.push_back(properLifetime); + if (storeProperDecayTime) { + valuesToFill.push_back(properDecayTime); } registry.get(HIST("hnLcVarsGen"))->Fill(valuesToFill.data()); } @@ -631,7 +660,7 @@ struct HfTaskLc { occ = o2::hf_occupancy::getOccupancyColl(collision, occEstimator); } double outputBkg(-1), outputPrompt(-1), outputFD(-1); - const float properLifetime = HfHelper::ctLc(candidate) * CtToProperLifetimePs; + const float properDecayTime = HfHelper::ctLc(candidate) * CtToProperDecayTimePs; auto fillTHnData = [&](bool isPKPi) { const auto massLc = isPKPi ? HfHelper::invMassLcToPKPi(candidate) : HfHelper::invMassLcToPiKP(candidate); @@ -654,8 +683,8 @@ struct HfTaskLc { if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) { valuesToFill.push_back(occ); } - if (storeProperLifetime) { - valuesToFill.push_back(properLifetime); + if (storeProperDecayTime) { + valuesToFill.push_back(properDecayTime); } if constexpr (FillMl) { registry.get(HIST("hnLcVarsWithBdt"))->Fill(valuesToFill.data()); @@ -687,10 +716,10 @@ struct HfTaskLc { /// Run the analysis on MC data /// \tparam FillMl switch to fill ML histograms - template + template void runAnalysisPerCollisionMc(CollType const& collisions, CandType const& candidates, - CandLcMcGen const& mcParticles) + McParticles3ProngMatched const& mcParticles) { for (const auto& collision : collisions) { // MC Rec. diff --git a/PWGHF/D2H/Tasks/taskLcToK0sP.cxx b/PWGHF/D2H/Tasks/taskLcToK0sP.cxx index d3eb5f5bf68..349d5c80009 100644 --- a/PWGHF/D2H/Tasks/taskLcToK0sP.cxx +++ b/PWGHF/D2H/Tasks/taskLcToK0sP.cxx @@ -28,6 +28,7 @@ #include "Common/Core/RecoDecay.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include #include @@ -73,12 +74,12 @@ struct HfTaskLcToK0sP { using TracksWPid = soa::Join; - using Collisions = soa::Join; - using CollisionsMc = soa::Join; - using CollisionsWithFT0C = soa::Join; - using CollisionsMcWithFT0C = soa::Join; - using CollisionsWithFT0M = soa::Join; - using CollisionsMcWithFT0M = soa::Join; + using Collisions = soa::Join; + using CollisionsMc = soa::Join; + using CollisionsWithFT0C = soa::Join; + using CollisionsMcWithFT0C = soa::Join; + using CollisionsWithFT0M = soa::Join; + using CollisionsMcWithFT0M = soa::Join; Filter filterSelectCandidates = aod::hf_sel_candidate_lc_to_k0s_p::isSelLcToK0sP >= selectionFlagLcToK0sP; diff --git a/PWGHF/D2H/Tasks/taskNetCharmFluctuations.cxx b/PWGHF/D2H/Tasks/taskNetCharmFluctuations.cxx index 972dc2b6e5c..37542fdc8f1 100644 --- a/PWGHF/D2H/Tasks/taskNetCharmFluctuations.cxx +++ b/PWGHF/D2H/Tasks/taskNetCharmFluctuations.cxx @@ -22,6 +22,7 @@ #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include #include @@ -130,7 +131,7 @@ using CandD0Data = soa::Filtered>; using CandDplusData = soa::Filtered>; using CandDplusMcRec = soa::Filtered>; -using CollData = soa::Join; +using CollData = soa::Join; struct HfTaskNetCharmFluctuations { Produces outD0Cand; diff --git a/PWGHF/D2H/Tasks/taskPtFlucCharmHadrons.cxx b/PWGHF/D2H/Tasks/taskPtFlucCharmHadrons.cxx index 0f53b2ab63e..e94dcab7a87 100644 --- a/PWGHF/D2H/Tasks/taskPtFlucCharmHadrons.cxx +++ b/PWGHF/D2H/Tasks/taskPtFlucCharmHadrons.cxx @@ -24,6 +24,7 @@ #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/TrackSelectionTables.h" #include @@ -113,7 +114,7 @@ struct HfTaskPtFlucCharmHadrons { using CandDplusDataWMl = soa::Filtered>; using CandD0DataWMl = soa::Filtered>; - using Colls = soa::Join; + using Colls = soa::Join; using TracksWithExtra = soa::Join; Filter filterSelectDplusCandidates = aod::hf_sel_candidate_dplus::isSelDplusToPiKPi >= selectionFlag; diff --git a/PWGHF/D2H/Tasks/taskSigmac.cxx b/PWGHF/D2H/Tasks/taskSigmac.cxx index 69e370f3fd1..3f73c812615 100644 --- a/PWGHF/D2H/Tasks/taskSigmac.cxx +++ b/PWGHF/D2H/Tasks/taskSigmac.cxx @@ -69,6 +69,7 @@ struct HfTaskSigmac { Configurable addMassDiffAbsLambdaCToSigmacSparse{"addMassDiffAbsLambdaCToSigmacSparse", false, "enable the filling of |M(pkpi, piKp) - M(LambdaC)| in the Σc0,++ THnSparse"}; Configurable deltaMassSigmacRecoMax{"deltaMassSigmacRecoMax", 1000, "Maximum allowed value for Sigmac deltaMass. Conceived to reduce the output size (i.e. reject background above a certain threshold)"}; Configurable ptMinSc{"ptMinSc", -1.f, "Minimum accepted value for SigmaC-hadron pt (GeV/c)"}; + Configurable trackingInfo4SoftPiOnly{"trackingInfo4SoftPiOnly", false, "Flag to enable the storage of tracking info about the soft pion only"}; bool isMc{}; bool storeTrackProp{}; @@ -578,7 +579,13 @@ struct HfTaskSigmac { const auto& trackLcProng0 = candidateLc.template prong0_as(); const auto& trackLcProng1 = candidateLc.template prong1_as(); const auto& trackLcProng2 = candidateLc.template prong2_as(); - getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + if (trackingInfo4SoftPiOnly) { + /// soft pion info only + getTrackingInfo(std::vector{trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } else { + /// info from soft pion and also Lc daughters + getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } } if (addSoftPiDcaToSigmacSparse) { /// dcaXY,Z of soft pion track stored @@ -745,7 +752,13 @@ struct HfTaskSigmac { const auto& trackLcProng0 = candidateLc.template prong0_as(); const auto& trackLcProng1 = candidateLc.template prong1_as(); const auto& trackLcProng2 = candidateLc.template prong2_as(); - getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + if (trackingInfo4SoftPiOnly) { + /// soft pion info only + getTrackingInfo(std::vector{trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } else { + /// info from soft pion and also Lc daughters + getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } } if (addSoftPiDcaToSigmacSparse) { /// dcaXY,Z of soft pion track stored @@ -1301,7 +1314,13 @@ struct HfTaskSigmac { const auto& trackLcProng1 = candidateLc.template prong1_as(); const auto& trackLcProng2 = candidateLc.template prong2_as(); const auto& trackSoftPi = candSc.template prong1_as(); - getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + if (trackingInfo4SoftPiOnly) { + /// soft pion info only + getTrackingInfo(std::vector{trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } else { + /// info from soft pion and also Lc daughters + getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } } if (addSoftPiDcaToSigmacSparse) { /// dcaXY,Z of soft pion track stored @@ -1470,7 +1489,13 @@ struct HfTaskSigmac { const auto& trackLcProng1 = candidateLc.template prong1_as(); const auto& trackLcProng2 = candidateLc.template prong2_as(); const auto& trackSoftPi = candSc.template prong1_as(); - getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + if (trackingInfo4SoftPiOnly) { + /// soft pion info only + getTrackingInfo(std::vector{trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } else { + /// info from soft pion and also Lc daughters + getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } } if (addSoftPiDcaToSigmacSparse) { /// dcaXY,Z of soft pion track stored @@ -1676,7 +1701,13 @@ struct HfTaskSigmac { const auto& trackLcProng1 = candidateLc.template prong1_as(); const auto& trackLcProng2 = candidateLc.template prong2_as(); const auto& trackSoftPi = candSc.template prong1_as(); - getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + if (trackingInfo4SoftPiOnly) { + /// soft pion info only + getTrackingInfo(std::vector{trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } else { + /// info from soft pion and also Lc daughters + getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } } if (addSoftPiDcaToSigmacSparse) { /// dcaXY,Z of soft pion track stored @@ -1843,7 +1874,13 @@ struct HfTaskSigmac { const auto& trackLcProng1 = candidateLc.template prong1_as(); const auto& trackLcProng2 = candidateLc.template prong2_as(); const auto& trackSoftPi = candSc.template prong1_as(); - getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + if (trackingInfo4SoftPiOnly) { + /// soft pion info only + getTrackingInfo(std::vector{trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } else { + /// info from soft pion and also Lc daughters + getTrackingInfo(std::vector{trackLcProng0, trackLcProng1, trackLcProng2, trackSoftPi}, absEtaTrackMin, numItsClsMin, numTpcClsMin); + } } if (addSoftPiDcaToSigmacSparse) { /// dcaXY,Z of soft pion track stored diff --git a/PWGHF/D2H/Tasks/taskUpcLc.cxx b/PWGHF/D2H/Tasks/taskUpcLc.cxx index f8a4ffe91c1..bb4785cf4e3 100644 --- a/PWGHF/D2H/Tasks/taskUpcLc.cxx +++ b/PWGHF/D2H/Tasks/taskUpcLc.cxx @@ -47,6 +47,7 @@ #include #include +#include #include #include #include // std::vector @@ -79,6 +80,9 @@ DECLARE_SOA_COLUMN(AmpFT0A, ampFT0A, float); DECLARE_SOA_COLUMN(AmpFT0C, ampFT0C, float); DECLARE_SOA_COLUMN(ZdcTimeZNA, zdcTimeZNA, float); DECLARE_SOA_COLUMN(ZdcTimeZNC, zdcTimeZNC, float); +DECLARE_SOA_COLUMN(FlagMcMatchRec, flagMcMatchRec, int8_t); +DECLARE_SOA_COLUMN(OriginMcRec, originMcRec, int8_t); +DECLARE_SOA_COLUMN(PtBhadMotherPart, ptBhadMotherPart, float); } // namespace full DECLARE_SOA_TABLE(HfUpcQa, "AOD", "HFUPCQA", full::PvContributors, @@ -103,12 +107,33 @@ DECLARE_SOA_TABLE(HfUpcLcInfos, "AOD", "HFUPCLCINFOS", full::Chi2PCA, full::DecayLength, full::Cpa); +DECLARE_SOA_TABLE(HfUpcLcMcBdtInfos, "AOD", "HFUPCLCMCBDT", + full::M, + full::Pt, + full::BkgScore, + full::FlagMcMatchRec, + full::OriginMcRec, + full::PtBhadMotherPart); +DECLARE_SOA_TABLE(HfUpcLcMcInfos, "AOD", "HFUPCLCMCINFO", + full::M, + full::Pt, + full::PtProng0, + full::PtProng1, + full::PtProng2, + full::Chi2PCA, + full::DecayLength, + full::Cpa, + full::FlagMcMatchRec, + full::OriginMcRec, + full::PtBhadMotherPart); } // namespace o2::aod /// Λc± → p± K∓ π± analysis task struct HfTaskUpcLc { Produces rowCandUpcBdt; Produces rowCandUpc; + Produces rowCandUpcMcBdt; + Produces rowCandUpcMc; Produces rowUpcQa; Configurable selectionFlagLc{"selectionFlagLc", 1, "Selection Flag for Lc"}; @@ -133,6 +158,8 @@ struct HfTaskUpcLc { using LcCandidates = soa::Filtered>; using LcCandidatesMl = soa::Filtered>; + using LcCandidatesMc = soa::Filtered>; + using LcCandidatesMlMc = soa::Filtered>; Filter filterSelectCandidates = aod::hf_sel_candidate_lc::isSelLcToPKPi >= selectionFlagLc || aod::hf_sel_candidate_lc::isSelLcToPiKP >= selectionFlagLc; Preslice candLcPerCollision = aod::hf_cand::collisionId; @@ -149,7 +176,7 @@ struct HfTaskUpcLc { void init(InitContext&) { - const std::array doprocess{doprocessDataWithMlWithUpc, doprocessDataStdWithUpc}; + const std::array doprocess{doprocessDataWithMlWithUpc, doprocessDataStdWithUpc, doprocessMcWithMlWithUpc, doprocessMcStdWithUpc}; if ((std::accumulate(doprocess.begin(), doprocess.end(), 0)) != 1) { LOGP(fatal, "no or more than one process function enabled! Please check your configuration!"); } @@ -178,13 +205,13 @@ struct HfTaskUpcLc { return o2::hf_centrality::getCentralityColl(collision); } - template - void runAnalysisPerCollisionDataWithUpc(CollType const& collisions, - CandType const& candidates, - BCsType const& bcs, - aod::FT0s const& ft0s, - aod::FV0As const& fv0as, - aod::FDDs const& fdds + template + void runAnalysisPerCollisionWithUpc(CollType const& collisions, + CandType const& candidates, + BCsType const& bcs, + aod::FT0s const& ft0s, + aod::FV0As const& fv0as, + aod::FDDs const& fdds ) { @@ -244,7 +271,23 @@ struct HfTaskUpcLc { } registry.fill(HIST("Data/hUpcGapAfterSelection"), static_cast(gap)); } - const bool ignoreZdcTime = (zdcTimeThreshold < 0.f); + if constexpr (!IsMc) { + if (!hasZdc) { + continue; + } + } + if constexpr (IsMc) { + if (!hasZdc && fillHistQa) { + registry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C); + } + if (!hasZdc) { + registry.fill(HIST("Data/hUpcGapAfterSelection"), static_cast(gap)); + } + } + bool ignoreZdcTime = (zdcTimeThreshold < 0.f); + if constexpr (IsMc) { + ignoreZdcTime = ignoreZdcTime || !hasZdc; + } const auto multNTracksPV = collision.multNTracksPV(); const auto posZ = collision.posZ(); if (gap == o2::aod::sgselector::TrueGap::SingleGapA && (ignoreZdcTime || (std::abs(zdcTimeZNA) > zdcTimeThreshold && std::abs(zdcTimeZNC) < zdcTimeThreshold))) { @@ -289,6 +332,18 @@ struct HfTaskUpcLc { auto fillTHnData = [&](bool isPKPi) { const auto massLc = isPKPi ? HfHelper::invMassLcToPKPi(candidate) : HfHelper::invMassLcToPiKP(candidate); + if constexpr (IsMc) { + if constexpr (FillMl) { + const auto& mlProb = isPKPi ? candidate.mlProbLcToPKPi() : candidate.mlProbLcToPiKP(); + if (mlProb.size() == NumberOfMlClasses) { + outputBkg = mlProb[MlClassBackground]; /// bkg score + } + rowCandUpcMcBdt(massLc, pt, outputBkg, candidate.flagMcMatchRec(), candidate.originMcRec(), candidate.ptBhadMotherPart()); + } else { + rowCandUpcMc(massLc, pt, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, candidate.flagMcMatchRec(), candidate.originMcRec(), candidate.ptBhadMotherPart()); + } + return; + } if constexpr (FillMl) { const auto& mlProb = isPKPi ? candidate.mlProbLcToPKPi() : candidate.mlProbLcToPiKP(); if (mlProb.size() == NumberOfMlClasses) { @@ -321,7 +376,7 @@ struct HfTaskUpcLc { aod::FDDs const& fdds, aod::Zdcs const& /*zdcs*/) { - runAnalysisPerCollisionDataWithUpc(collisions, selectedLcCandidatesMl, bcs, ft0s, fv0as, fdds); + runAnalysisPerCollisionWithUpc(collisions, selectedLcCandidatesMl, bcs, ft0s, fv0as, fdds); } PROCESS_SWITCH(HfTaskUpcLc, processDataWithMlWithUpc, "Process real data with the ML method with UPC", false); @@ -334,9 +389,37 @@ struct HfTaskUpcLc { aod::FDDs const& fdds, aod::Zdcs const& /*zdcs*/) { - runAnalysisPerCollisionDataWithUpc(collisions, selectedLcCandidates, bcs, ft0s, fv0as, fdds); + runAnalysisPerCollisionWithUpc(collisions, selectedLcCandidates, bcs, ft0s, fv0as, fdds); } PROCESS_SWITCH(HfTaskUpcLc, processDataStdWithUpc, "Process real data with the standard method with UPC", false); + + void processMcWithMlWithUpc(soa::Join const& collisions, + aod::BcFullInfos const& bcs, + LcCandidatesMlMc const& selectedLcCandidatesMlMc, + aod::McCollisions const&, + aod::TracksWMc const&, + aod::FT0s const& ft0s, + aod::FV0As const& fv0as, + aod::FDDs const& fdds, + aod::Zdcs const& /*zdcs*/) + { + runAnalysisPerCollisionWithUpc(collisions, selectedLcCandidatesMlMc, bcs, ft0s, fv0as, fdds); + } + PROCESS_SWITCH(HfTaskUpcLc, processMcWithMlWithUpc, "Process MC with the ML method with UPC", false); + + void processMcStdWithUpc(soa::Join const& collisions, + aod::BcFullInfos const& bcs, + LcCandidatesMc const& selectedLcCandidatesMc, + aod::McCollisions const&, + aod::TracksWMc const&, + aod::FT0s const& ft0s, + aod::FV0As const& fv0as, + aod::FDDs const& fdds, + aod::Zdcs const& /*zdcs*/) + { + runAnalysisPerCollisionWithUpc(collisions, selectedLcCandidatesMc, bcs, ft0s, fv0as, fdds); + } + PROCESS_SWITCH(HfTaskUpcLc, processMcStdWithUpc, "Process MC with the standard method with UPC", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGHF/HFC/DataModel/DMesonPairsTables.h b/PWGHF/HFC/DataModel/DMesonPairsTables.h index 67a352a46ae..65f76dc586e 100644 --- a/PWGHF/HFC/DataModel/DMesonPairsTables.h +++ b/PWGHF/HFC/DataModel/DMesonPairsTables.h @@ -108,6 +108,7 @@ DECLARE_SOA_COLUMN(YD, yD, float); //! Rapidity of the D meson DECLARE_SOA_COLUMN(EtaD, etaD, float); //! Pseudorapidity of the D meson DECLARE_SOA_COLUMN(PhiD, phiD, float); //! Azimuthal angle of the D meson DECLARE_SOA_COLUMN(MD, mD, float); //! Invariant mass of the D meson +DECLARE_SOA_COLUMN(DType, dType, uint8_t); //! D meson type (D0 or D0bar) DECLARE_SOA_COLUMN(PoolBinD, poolBinD, int); //! Pool bin of the D meson DECLARE_SOA_COLUMN(GIndexColD, gIndexColD, int); //! G-index column of the D meson DECLARE_SOA_COLUMN(TimestampD, timestampD, int64_t); //! Timestamp of the D meson @@ -124,14 +125,19 @@ DECLARE_SOA_COLUMN(TimestampHad, timestampHad, int64_t); //! Timestamp of the as } // namespace hf_correlation_d_meson_had // Definition of the D meson table for D-had correlations. Contains the info needed at Data level. -DECLARE_SOA_TABLE(DMesonCandInfo, "AOD", "DMESONCANDINFO", - hf_correlation_d_meson_had::PtD, - hf_correlation_d_meson_had::EtaD, - hf_correlation_d_meson_had::PhiD, - hf_correlation_d_meson_had::MD, - hf_correlation_d_meson_had::PoolBinD, - hf_correlation_d_meson_had::GIndexColD, - hf_correlation_d_meson_had::TimestampD); +#define DECLARE_DMESON_ME_TABLE(_cand_number_, _marker_value_, _description_) \ + DECLARE_SOA_TABLE(_cand_number_, "AOD", _description_, o2::soa::Marker<_marker_value_>, \ + hf_correlation_d_meson_had::PtD, \ + hf_correlation_d_meson_had::EtaD, \ + hf_correlation_d_meson_had::PhiD, \ + hf_correlation_d_meson_had::MD, \ + hf_correlation_d_meson_had::DType, \ + hf_correlation_d_meson_had::PoolBinD, \ + hf_correlation_d_meson_had::GIndexColD, \ + hf_correlation_d_meson_had::TimestampD); + +DECLARE_DMESON_ME_TABLE(DMesonInfoCand1, 1, "DMESCAND1"); //! D0 cand 1 info for event mixing +DECLARE_DMESON_ME_TABLE(DMesonInfoCand2, 2, "DMESCAND2"); //! D0 cand 2 info for event mixing DECLARE_SOA_TABLE(AssocHadInfo, "AOD", "ASSOCHADINFO", hf_correlation_d_meson_had::PtHad, diff --git a/PWGHF/HFC/Macros/DhCorrelationExtraction.cxx b/PWGHF/HFC/Macros/DhCorrelationExtraction.cxx index f2566f4f9a6..328c05f9bbd 100644 --- a/PWGHF/HFC/Macros/DhCorrelationExtraction.cxx +++ b/PWGHF/HFC/Macros/DhCorrelationExtraction.cxx @@ -201,7 +201,7 @@ Bool_t DhCorrelationExtraction::setDmesonSpecie(DmesonSpecie k) return kTRUE; } -Bool_t DhCorrelationExtraction::extractCorrelations(Double_t ptCandMin, Double_t ptCandMax, Double_t ptHadMin, Double_t ptHadMax, TString codeName) +Bool_t DhCorrelationExtraction::extractCorrelations(Double_t ptCandMin, Double_t ptCandMax, Double_t ptHadMin, Double_t ptHadMax, const TString& codeName) { if (fSubtractSoftPiME) { @@ -1513,7 +1513,7 @@ Double_t DhCorrelationExtraction::calculateBaselineError(TH1D*& histo, Bool_t to return errBaseline; } -void DhCorrelationExtraction::setTH1HistoStyle(TH1D*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, +void DhCorrelationExtraction::setTH1HistoStyle(TH1D*& histo, const TString& hTitle, const TString& hXaxisTitle, const TString& hYaxisTitle, Style_t markerStyle, Color_t markerColor, Double_t markerSize, Color_t lineColor, Int_t lineWidth, Float_t hTitleXaxisOffset, Float_t hTitleYaxisOffset, Float_t hTitleXaxisSize, Float_t hTitleYaxisSize, Float_t hLabelXaxisSize, Float_t hLabelYaxisSize, @@ -1538,7 +1538,7 @@ void DhCorrelationExtraction::setTH1HistoStyle(TH1D*& histo, TString hTitle, TSt histo->GetYaxis()->CenterTitle(centerYaxisTitle); } -void DhCorrelationExtraction::setTH2HistoStyle(TH2D*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, TString hZaxisTitle, +void DhCorrelationExtraction::setTH2HistoStyle(TH2D*& histo, const TString& hTitle, const TString& hXaxisTitle, const TString& hYaxisTitle, const TString& hZaxisTitle, Float_t hTitleXaxisOffset, Float_t hTitleYaxisOffset, Float_t hTitleZaxisOffset, Float_t hTitleXaxisSize, Float_t hTitleYaxisSize, Float_t hTitleZaxisSize, Float_t hLabelXaxisSize, Float_t hLabelYaxisSize, Float_t hLabelZaxisSize, diff --git a/PWGHF/HFC/Macros/DhCorrelationExtraction.h b/PWGHF/HFC/Macros/DhCorrelationExtraction.h index aa3f2a52874..76372dfd81b 100644 --- a/PWGHF/HFC/Macros/DhCorrelationExtraction.h +++ b/PWGHF/HFC/Macros/DhCorrelationExtraction.h @@ -29,6 +29,8 @@ #include #include +#include + class DhCorrelationExtraction : public TObject { @@ -53,39 +55,39 @@ class DhCorrelationExtraction : public TObject /// Methods to set the input configuration // Input files, directories and histograms Bool_t setDmesonSpecie(DmesonSpecie k); - void setInputFilenameMass(TString filenameMass) { fFileNameMass = filenameMass; } - void setInputFilenameSe(TString filenameSE) { fFileNameSE = filenameSE; } - void setInputFilenameMe(TString filenameME) { fFileNameME = filenameME; } - void setInputFilenameSecPart(TString filenameSecPart) { fFileSecPartName = filenameSecPart; } + void setInputFilenameMass(TString filenameMass) { fFileNameMass = std::move(filenameMass); } + void setInputFilenameSe(TString filenameSE) { fFileNameSE = std::move(filenameSE); } + void setInputFilenameMe(TString filenameME) { fFileNameME = std::move(filenameME); } + void setInputFilenameSecPart(TString filenameSecPart) { fFileSecPartName = std::move(filenameSecPart); } void setInputFilenameBiasBtoD(TString filenamePromptMcRec, TString filenameNonPromptMcRec) { - fFilePromptMcRecName = filenamePromptMcRec; - fFileNonPromptMcRecName = filenameNonPromptMcRec; + fFilePromptMcRecName = std::move(filenamePromptMcRec); + fFileNonPromptMcRecName = std::move(filenameNonPromptMcRec); } - void setDirNameSe(TString dirNameSE) { fDirNameSE = dirNameSE; } - void setDirNameMe(TString dirNameME) { fDirNameME = dirNameME; } - void setDirNameSecPart(TString dirNameSecPart) { fDirSecPartName = dirNameSecPart; } - void setMassHistoNameSgn(TString massHistoNameSgn) { fMassHistoNameSgn = massHistoNameSgn; } - void setMassHistoNameBkg(TString massHistoNameBkg) { fMassHistoNameBkg = massHistoNameBkg; } - void setMassHistoNameSBs(TString massHistoNameSBs) { fMassHistoNameSBs = massHistoNameSBs; } - void setSeCorrelHistoSignalName(TString correlNameSigSE) { fSECorrelSignalRegionName = correlNameSigSE; } - void setSeCorrelHistoSidebandName(TString correlNameSbSE) { fSECorrelSidebandsName = correlNameSbSE; } - void setSeCorrelHistoSidebandLeftName(TString correlNameSbSE) { fSECorrelSidebandLeftName = correlNameSbSE; } - void setSeCorrelHistoSidebandRightName(TString correlNameSbSE) { fSECorrelSidebandRightName = correlNameSbSE; } - void setMeCorrelHistoSignalName(TString correlNameSigME) { fMECorrelSignalRegionName = correlNameSigME; } - void setMeCorrelHistoSidebandName(TString correlNameSbME) { fMECorrelSidebandsName = correlNameSbME; } - void setMeCorrelHistoSidebandLeftName(TString correlNameSbME) { fMECorrelSidebandLeftName = correlNameSbME; } - void setMeCorrelHistoSidebandRightName(TString correlNameSbME) { fMECorrelSidebandRightName = correlNameSbME; } + void setDirNameSe(TString dirNameSE) { fDirNameSE = std::move(dirNameSE); } + void setDirNameMe(TString dirNameME) { fDirNameME = std::move(dirNameME); } + void setDirNameSecPart(TString dirNameSecPart) { fDirSecPartName = std::move(dirNameSecPart); } + void setMassHistoNameSgn(TString massHistoNameSgn) { fMassHistoNameSgn = std::move(massHistoNameSgn); } + void setMassHistoNameBkg(TString massHistoNameBkg) { fMassHistoNameBkg = std::move(massHistoNameBkg); } + void setMassHistoNameSBs(TString massHistoNameSBs) { fMassHistoNameSBs = std::move(massHistoNameSBs); } + void setSeCorrelHistoSignalName(TString correlNameSigSE) { fSECorrelSignalRegionName = std::move(correlNameSigSE); } + void setSeCorrelHistoSidebandName(TString correlNameSbSE) { fSECorrelSidebandsName = std::move(correlNameSbSE); } + void setSeCorrelHistoSidebandLeftName(TString correlNameSbSE) { fSECorrelSidebandLeftName = std::move(correlNameSbSE); } + void setSeCorrelHistoSidebandRightName(TString correlNameSbSE) { fSECorrelSidebandRightName = std::move(correlNameSbSE); } + void setMeCorrelHistoSignalName(TString correlNameSigME) { fMECorrelSignalRegionName = std::move(correlNameSigME); } + void setMeCorrelHistoSidebandName(TString correlNameSbME) { fMECorrelSidebandsName = std::move(correlNameSbME); } + void setMeCorrelHistoSidebandLeftName(TString correlNameSbME) { fMECorrelSidebandLeftName = std::move(correlNameSbME); } + void setMeCorrelHistoSidebandRightName(TString correlNameSbME) { fMECorrelSidebandRightName = std::move(correlNameSbME); } void setHistoSecPartName(TString histoPrimaryPartName, TString histoAllPartName) { - fHistoPrimaryPartName = histoPrimaryPartName; - fHistoAllPartName = histoAllPartName; + fHistoPrimaryPartName = std::move(histoPrimaryPartName); + fHistoAllPartName = std::move(histoAllPartName); } - void setInputFilenameFdTemplate(TString filenameFDTemplate) { fFileFDTemplateName = filenameFDTemplate; } - void setInputFilenameFdPromptFrac(TString filenameFDPromptFrac) { fFileFDPromptFracName = filenameFDPromptFrac; } - void setInputHistoNameFdTemplatePrompt(TString hNameFDTemplatePrompt) { fHistoFDTemplatePromptName = hNameFDTemplatePrompt; } - void setInputHistoNameFdTemplateNonPrompt(TString hNameFDTemplateNonPrompt) { fHistoFDTemplateNonPromptName = hNameFDTemplateNonPrompt; } - void setInputHistoNameFdPromptFrac(TString hNameFDPromptFrac) { fHistoFDPromptFracName = hNameFDPromptFrac; } + void setInputFilenameFdTemplate(TString filenameFDTemplate) { fFileFDTemplateName = std::move(filenameFDTemplate); } + void setInputFilenameFdPromptFrac(TString filenameFDPromptFrac) { fFileFDPromptFracName = std::move(filenameFDPromptFrac); } + void setInputHistoNameFdTemplatePrompt(TString hNameFDTemplatePrompt) { fHistoFDTemplatePromptName = std::move(hNameFDTemplatePrompt); } + void setInputHistoNameFdTemplateNonPrompt(TString hNameFDTemplateNonPrompt) { fHistoFDTemplateNonPromptName = std::move(hNameFDTemplateNonPrompt); } + void setInputHistoNameFdPromptFrac(TString hNameFDPromptFrac) { fHistoFDPromptFracName = std::move(hNameFDPromptFrac); } // Input conditions: PtCand, PtHad, PoolBins void setNpools(Int_t npools) { fNpools = npools; } @@ -143,15 +145,15 @@ class DhCorrelationExtraction : public TObject Bool_t readInputInvMass(); Bool_t readInputFdSubtr(); Bool_t readInputSecondaryPartContamination(); - Bool_t extractCorrelations(Double_t ptCandMin, Double_t ptCandMax, Double_t ptHadMin, Double_t ptHadMax, TString codeName); + Bool_t extractCorrelations(Double_t ptCandMin, Double_t ptCandMax, Double_t ptHadMin, Double_t ptHadMax, const TString& codeName); TH1D* getCorrectedCorrHisto() { return fCorrectedCorrHisto; } TH1D* getCorrectedCorrHistoBaselineSubtr() { return fCorrectedCorrHistoBaselineSubtr; } TH1D* getCorrectedCorrHistoReflected() { return fCorrectedCorrHistoReflected; } TH1D* getCorrectedCorrHistoReflectedBaselineSubtr() { return fCorrectedCorrHistoReflectedBaselineSubtr; } /// Histogram style - void setTH1HistoStyle(TH1D*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, Style_t markerStyle = kFullCircle, Color_t markerColor = kRed + 1, Double_t markerSize = 1.4, Color_t lineColor = kRed + 1, Int_t lineWidth = 3, Float_t hTitleXaxisOffset = 1.0, Float_t hTitleYaxisOffset = 1.0, Float_t hTitleXaxisSize = 0.060, Float_t hTitleYaxisSize = 0.060, Float_t hLabelXaxisSize = 0.060, Float_t hLabelYaxisSize = 0.060, Bool_t centerXaxisTitle = false, Bool_t centerYaxisTitle = false); - void setTH2HistoStyle(TH2D*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, TString hZaxisTitle, Float_t hTitleXaxisOffset = 1.8, Float_t hTitleYaxisOffset = 1.8, Float_t hTitleZaxisOffset = 1.2, Float_t hTitleXaxisSize = 0.060, Float_t hTitleYaxisSize = 0.060, Float_t hTitleZaxisSize = 0.060, Float_t hLabelXaxisSize = 0.060, Float_t hLabelYaxisSize = 0.060, Float_t hLabelZaxisSize = 0.060, Bool_t centerXaxisTitle = true, Bool_t centerYaxisTitle = true); + void setTH1HistoStyle(TH1D*& histo, const TString& hTitle, const TString& hXaxisTitle, const TString& hYaxisTitle, Style_t markerStyle = kFullCircle, Color_t markerColor = kRed + 1, Double_t markerSize = 1.4, Color_t lineColor = kRed + 1, Int_t lineWidth = 3, Float_t hTitleXaxisOffset = 1.0, Float_t hTitleYaxisOffset = 1.0, Float_t hTitleXaxisSize = 0.060, Float_t hTitleYaxisSize = 0.060, Float_t hLabelXaxisSize = 0.060, Float_t hLabelYaxisSize = 0.060, Bool_t centerXaxisTitle = false, Bool_t centerYaxisTitle = false); + void setTH2HistoStyle(TH2D*& histo, const TString& hTitle, const TString& hXaxisTitle, const TString& hYaxisTitle, const TString& hZaxisTitle, Float_t hTitleXaxisOffset = 1.8, Float_t hTitleYaxisOffset = 1.8, Float_t hTitleZaxisOffset = 1.2, Float_t hTitleXaxisSize = 0.060, Float_t hTitleYaxisSize = 0.060, Float_t hTitleZaxisSize = 0.060, Float_t hLabelXaxisSize = 0.060, Float_t hLabelYaxisSize = 0.060, Float_t hLabelZaxisSize = 0.060, Bool_t centerXaxisTitle = true, Bool_t centerYaxisTitle = true); private: TFile* fFileMass; // File containing the mass histograms diff --git a/PWGHF/HFC/Macros/ExtractOutputCorrel.C b/PWGHF/HFC/Macros/ExtractOutputCorrel.C index db8dc9158d5..1a80656d58c 100644 --- a/PWGHF/HFC/Macros/ExtractOutputCorrel.C +++ b/PWGHF/HFC/Macros/ExtractOutputCorrel.C @@ -55,13 +55,13 @@ void parseStringArray(const Value& jsonArray, std::vector& output) } } -void setInputCorrelNames(DhCorrelationExtraction* plotter, TString pathFileSE, TString pathFileME, TString dirSE, TString dirME, TString histoNameCorrSignal, TString histoNameCorrSideba, TString histoNameCorrSidebaLeft, TString histoNameCorrSidebaRight); -void setInputHistoInvMassNames(DhCorrelationExtraction* plotter, TString pathFileMass, std::vector inputMassNames); -void setInputHistoFdSubtraction(DhCorrelationExtraction* plotter, TString pathFileFDTemplate, TString pathFileFDPromptFrac, TString histoNameFDTemplatePrompt, TString histoNameFDTemplateNonPrompt, TString histoNameRawFracPrompt); -void setInputHistoSecPart(DhCorrelationExtraction* plotter, TString pathFileSecPart, TString dirSecPartName, TString histoNamePrimaryPart, TString histoNameAllPart); -void setInputHistoBiasBtoD(DhCorrelationExtraction* plotter, TString pathfFilePromptMcRec, TString pathfFileNonPromptMcRec); +void setInputCorrelNames(DhCorrelationExtraction* plotter, const TString& pathFileSE, const TString& pathFileME, const TString& dirSE, const TString& dirME, const TString& histoNameCorrSignal, const TString& histoNameCorrSideba, const TString& histoNameCorrSidebaLeft, const TString& histoNameCorrSidebaRight); +void setInputHistoInvMassNames(DhCorrelationExtraction* plotter, const TString& pathFileMass, std::vector inputMassNames); +void setInputHistoFdSubtraction(DhCorrelationExtraction* plotter, const TString& pathFileFDTemplate, const TString& pathFileFDPromptFrac, const TString& histoNameFDTemplatePrompt, const TString& histoNameFDTemplateNonPrompt, const TString& histoNameRawFracPrompt); +void setInputHistoSecPart(DhCorrelationExtraction* plotter, const TString& pathFileSecPart, const TString& dirSecPartName, const TString& histoNamePrimaryPart, const TString& histoNameAllPart); +void setInputHistoBiasBtoD(DhCorrelationExtraction* plotter, const TString& pathfFilePromptMcRec, const TString& pathfFileNonPromptMcRec); -void extractOutputCorrelDs(const TString cfgFileName = "config_CorrAnalysis.json") +void extractOutputCorrelDs(const TString& cfgFileName = "config_CorrAnalysis.json") { // gStyle -> SetOptStat(0); gStyle->SetPadLeftMargin(0.15); @@ -274,7 +274,7 @@ void extractOutputCorrelDs(const TString cfgFileName = "config_CorrAnalysis.json outFileReflectedBaselineSubtr->Close(); } -void setInputCorrelNames(DhCorrelationExtraction* plotter, TString pathFileSE, TString pathFileME, TString dirSE, TString dirME, TString histoNameCorrSignal, TString histoNameCorrSideba, TString histoNameCorrSidebaLeft, TString histoNameCorrSidebaRight) +void setInputCorrelNames(DhCorrelationExtraction* plotter, const TString& pathFileSE, const TString& pathFileME, const TString& dirSE, const TString& dirME, const TString& histoNameCorrSignal, const TString& histoNameCorrSideba, const TString& histoNameCorrSidebaLeft, const TString& histoNameCorrSidebaRight) { // Ds paths @@ -292,7 +292,7 @@ void setInputCorrelNames(DhCorrelationExtraction* plotter, TString pathFileSE, T plotter->setMeCorrelHistoSidebandRightName(histoNameCorrSidebaRight.Data()); } -void setInputHistoInvMassNames(DhCorrelationExtraction* plotter, TString pathFileMass, std::vector inputMassNames) +void setInputHistoInvMassNames(DhCorrelationExtraction* plotter, const TString& pathFileMass, std::vector inputMassNames) { // to use if sgn and bkg extraction is done apart plotter->setInputFilenameMass(pathFileMass.Data()); @@ -301,7 +301,7 @@ void setInputHistoInvMassNames(DhCorrelationExtraction* plotter, TString pathFil plotter->setMassHistoNameSBs(inputMassNames[2].data()); } -void setInputHistoFdSubtraction(DhCorrelationExtraction* plotter, TString pathFileFDTemplate, TString pathFileFDPromptFrac, TString histoNameFDTemplatePrompt, TString histoNameFDTemplateNonPrompt, TString histoNameRawFracPrompt) +void setInputHistoFdSubtraction(DhCorrelationExtraction* plotter, const TString& pathFileFDTemplate, const TString& pathFileFDPromptFrac, const TString& histoNameFDTemplatePrompt, const TString& histoNameFDTemplateNonPrompt, const TString& histoNameRawFracPrompt) { plotter->setInputFilenameFdTemplate(pathFileFDTemplate.Data()); @@ -311,7 +311,7 @@ void setInputHistoFdSubtraction(DhCorrelationExtraction* plotter, TString pathFi plotter->setInputHistoNameFdPromptFrac(histoNameRawFracPrompt.Data()); } -void setInputHistoSecPart(DhCorrelationExtraction* plotter, TString pathFileSecPart, TString dirSecPartName, TString histoNamePrimaryPart, TString histoNameAllPart) +void setInputHistoSecPart(DhCorrelationExtraction* plotter, const TString& pathFileSecPart, const TString& dirSecPartName, const TString& histoNamePrimaryPart, const TString& histoNameAllPart) { plotter->setInputFilenameSecPart(pathFileSecPart.Data()); @@ -319,7 +319,7 @@ void setInputHistoSecPart(DhCorrelationExtraction* plotter, TString pathFileSecP plotter->setHistoSecPartName(histoNamePrimaryPart.Data(), histoNameAllPart.Data()); } -void setInputHistoBiasBtoD(DhCorrelationExtraction* plotter, TString pathfFilePromptMcRec, TString pathfFileNonPromptMcRec) +void setInputHistoBiasBtoD(DhCorrelationExtraction* plotter, const TString& pathfFilePromptMcRec, const TString& pathfFileNonPromptMcRec) { plotter->setInputFilenameBiasBtoD(pathfFilePromptMcRec.Data(), pathfFileNonPromptMcRec.Data()); diff --git a/PWGHF/HFC/Macros/FitCorrel.C b/PWGHF/HFC/Macros/FitCorrel.C index 72461f06dc3..a90d502e58f 100644 --- a/PWGHF/HFC/Macros/FitCorrel.C +++ b/PWGHF/HFC/Macros/FitCorrel.C @@ -54,18 +54,18 @@ void readArray(const Value& jsonArray, vector& output) } } -void setTH1HistoStyle(TH1D*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, +void setTH1HistoStyle(TH1D*& histo, const TString& hTitle, const TString& hXaxisTitle, const TString& hYaxisTitle, Style_t markerStyle, Color_t markerColor, Double_t markerSize, Color_t lineColor, Int_t lineWidth, Float_t hTitleXaxisOffset = 1.3, Float_t hTitleYaxisOffset = 1.3, Float_t hTitleXaxisSize = 0.045, Float_t hTitleYaxisSize = 0.045, Float_t hLabelXaxisSize = 0.045, Float_t hLabelYaxisSize = 0.045, Bool_t centerXaxisTitle = false, Bool_t centerYaxisTitle = false); -void setTH1HistoStyle(TH1F*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, +void setTH1HistoStyle(TH1F*& histo, const TString& hTitle, const TString& hXaxisTitle, const TString& hYaxisTitle, Style_t markerStyle, Color_t markerColor, Double_t markerSize, Color_t lineColor, Int_t lineWidth, Float_t hTitleXaxisOffset = 1.3, Float_t hTitleYaxisOffset = 1.3, Float_t hTitleXaxisSize = 0.045, Float_t hTitleYaxisSize = 0.045, Float_t hLabelXaxisSize = 0.045, Float_t hLabelYaxisSize = 0.045, Bool_t centerXaxisTitle = false, Bool_t centerYaxisTitle = false); -void fitCorrelDs(const TString cfgFileName = "config_CorrAnalysis.json") +void fitCorrelDs(const TString& cfgFileName = "config_CorrAnalysis.json") { gStyle->SetOptStat(0); gStyle->SetPadLeftMargin(0.2); @@ -456,7 +456,7 @@ void fitCorrelDs(const TString cfgFileName = "config_CorrAnalysis.json") } } -void setTH1HistoStyle(TH1D*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, +void setTH1HistoStyle(TH1D*& histo, const TString& hTitle, const TString& hXaxisTitle, const TString& hYaxisTitle, Style_t markerStyle, Color_t markerColor, Double_t markerSize, Color_t lineColor, Int_t lineWidth, Float_t hTitleXaxisOffset, Float_t hTitleYaxisOffset, Float_t hTitleXaxisSize, Float_t hTitleYaxisSize, Float_t hLabelXaxisSize, Float_t hLabelYaxisSize, @@ -481,7 +481,7 @@ void setTH1HistoStyle(TH1D*& histo, TString hTitle, TString hXaxisTitle, TString histo->GetYaxis()->CenterTitle(centerYaxisTitle); } -void setTH1HistoStyle(TH1F*& histo, TString hTitle, TString hXaxisTitle, TString hYaxisTitle, +void setTH1HistoStyle(TH1F*& histo, const TString& hTitle, const TString& hXaxisTitle, const TString& hYaxisTitle, Style_t markerStyle, Color_t markerColor, Double_t markerSize, Color_t lineColor, Int_t lineWidth, Float_t hTitleXaxisOffset, Float_t hTitleYaxisOffset, Float_t hTitleXaxisSize, Float_t hTitleYaxisSize, Float_t hLabelXaxisSize, Float_t hLabelYaxisSize, diff --git a/PWGHF/HFC/TableProducer/correlatorD0Hadrons.cxx b/PWGHF/HFC/TableProducer/correlatorD0Hadrons.cxx index dc18a8a7f5c..496df5d5b51 100644 --- a/PWGHF/HFC/TableProducer/correlatorD0Hadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorD0Hadrons.cxx @@ -293,6 +293,8 @@ struct HfCorrelatorD0Hadrons { AxisSpec axisBdtScoreNonPrompt = {binsBdtScoreNonPrompt, "Bdt score Nonprompt"}; AxisSpec axisOrigin = {10, 0., 10., "Candidate origin"}; AxisSpec axisCent = {binsCentFt0m, "Centrality"}; + AxisSpec const axisCandidateStatusMcRec = {64, -0.5, 63.5, "MC candidate status"}; + AxisSpec const axisRecoHypothesis = {4, -0.5, 3.5, "Reconstructed hypothesis"}; // Histograms for Data registry.add("hPtCand", "D0, D0bar candidates", {HistType::kTH1F, {axisPtD}}); @@ -339,6 +341,11 @@ struct HfCorrelatorD0Hadrons { registry.add("hPtVsMultiplicityRecNonPrompt", "Multiplicity FT0M - MC Rec Non Prompt", {HistType::kTH2F, {{axisPtD}, {axisMultFT0M}}}); registry.add("hPtParticleAssocVsCandRec", "Associated Particle - MC reco", {HistType::kTH2F, {{axisPtHadron}, {axisPtD}}}); registry.add("hPtPrimaryParticleAssocVsCandRec", "Associated Particle - MC reco", {HistType::kTH2F, {{axisPtHadron}, {axisPtD}}}); + if (useCentrality) { + registry.add("hMLScoresVsMassVsPtVsEtaVsOriginVsCandidateStatusVsHypothesisVsCent", "MCRec template information with centrality", {HistType::kTHnSparseD, {{axisBdtScoreBkg}, {axisBdtScorePrompt}, {axisBdtScoreNonPrompt}, {axisMassD}, {axisPtD}, {axisEta}, {axisOrigin}, {axisCandidateStatusMcRec}, {axisRecoHypothesis}, {axisCent}}}); + } else { + registry.add("hMLScoresVsMassVsPtVsEtaVsOriginVsCandidateStatusVsHypothesis", "MCRec template information", {HistType::kTHnSparseD, {{axisBdtScoreBkg}, {axisBdtScorePrompt}, {axisBdtScoreNonPrompt}, {axisMassD}, {axisPtD}, {axisEta}, {axisOrigin}, {axisCandidateStatusMcRec}, {axisRecoHypothesis}}}); + } // Histograms for MC Gen registry.add("hEvtCountGen", "Event counter - MC gen", {HistType::kTH1F, {axisEvtCount}}); registry.add("hPtCandGen", "D0, D0bar candidates - MC gen", {HistType::kTH1F, {axisPtD}}); @@ -681,7 +688,13 @@ struct HfCorrelatorD0Hadrons { const auto invMassD0 = HfHelper::invMassD0ToPiK(candidate); const auto invMassD0bar = HfHelper::invMassD0barToKPi(candidate); - if (candidate.isSelD0() >= selectionFlagD0 || candidate.isSelD0bar() >= selectionFlagD0bar) { + const bool selectedD0 = candidate.isSelD0() >= selectionFlagD0; + const bool selectedD0bar = candidate.isSelD0bar() >= selectionFlagD0bar; + const int recoHypothesis = selectedD0 && selectedD0bar ? aod::hf_correlation_d0_hadron::ParticleTypeData::D0D0barBoth : selectedD0 ? aod::hf_correlation_d0_hadron::ParticleTypeData::D0Only + : selectedD0bar ? aod::hf_correlation_d0_hadron::ParticleTypeData::D0barOnly + : 0; + + if (selectedD0 || selectedD0bar) { hasAcceptedD0ForOfflineMixing = true; } @@ -696,9 +709,13 @@ struct HfCorrelatorD0Hadrons { registry.fill(HIST("hSelectionStatusRec"), candidate.isSelD0bar() + (candidate.isSelD0() * 2)); } // fill invariant mass plots from D0/D0bar signal and background candidates - if (candidate.isSelD0() >= selectionFlagD0) { // only reco as D0 - if (candidate.flagMcMatchRec() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { // also matched as D0 + if (selectedD0) { // reconstructed under the D0 hypothesis + int candidateStatus = 0; + + if (candidate.flagMcMatchRec() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + SETBIT(candidateStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0Sig); registry.fill(HIST("hMassD0RecSig"), invMassD0, candidate.pt(), efficiencyWeight); + if (isD0Prompt) { registry.fill(HIST("hPtCandRecSigPrompt"), candidate.pt()); registry.fill(HIST("hPtVsMultiplicityRecPrompt"), candidate.pt(), collision.multFT0M()); @@ -709,22 +726,41 @@ struct HfCorrelatorD0Hadrons { registry.fill(HIST("hPtVsMLScoresVsEtaRecSigNonPrompt"), outputMlD0[0], outputMlD0[1], outputMlD0[2], candidate.pt(), candidate.eta()); } } else if (candidate.flagMcMatchRec() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + SETBIT(candidateStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0Ref); registry.fill(HIST("hMassD0RecRef"), invMassD0, candidate.pt(), efficiencyWeight); - if (candidate.isSelD0bar() < selectionFlagD0bar) { + + if (!selectedD0bar) { registry.fill(HIST("hMassD0RecRefAfterRejectBoth"), invMassD0, candidate.pt(), efficiencyWeight); } } else { + SETBIT(candidateStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0Bg); registry.fill(HIST("hMassD0RecBg"), invMassD0, candidate.pt(), efficiencyWeight); } + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMlD0[iclass] = candidate.mlProbD0()[classMl->at(iclass)]; } + registry.fill(HIST("hMLScoresVsMassVsPtVsEtaVsOriginVsCent"), outputMlD0[0], outputMlD0[1], outputMlD0[2], invMassD0, candidate.pt(), candidate.eta(), isD0Prompt, cent, efficiencyWeight); - entryD0(candidate.phi(), candidate.eta(), candidate.pt(), invMassD0, poolBin, gCollisionId, timeStamp, (candidate.isSelD0bar() != 0) ? o2::aod::hf_correlation_d0_hadron::D0D0barBoth : o2::aod::hf_correlation_d0_hadron::D0Only); + + if (useCentrality) { + registry.fill(HIST("hMLScoresVsMassVsPtVsEtaVsOriginVsCandidateStatusVsHypothesisVsCent"), outputMlD0[0], outputMlD0[1], outputMlD0[2], invMassD0, candidate.pt(), candidate.eta(), isD0Prompt, + candidateStatus, recoHypothesis, cent, efficiencyWeight); + } else { + registry.fill(HIST("hMLScoresVsMassVsPtVsEtaVsOriginVsCandidateStatusVsHypothesis"), outputMlD0[0], outputMlD0[1], outputMlD0[2], invMassD0, candidate.pt(), candidate.eta(), isD0Prompt, + candidateStatus, recoHypothesis, efficiencyWeight); + } + + entryD0(candidate.phi(), candidate.eta(), candidate.pt(), invMassD0, poolBin, gCollisionId, timeStamp, selectedD0bar ? o2::aod::hf_correlation_d0_hadron::D0D0barBoth : o2::aod::hf_correlation_d0_hadron::D0Only); } - if (candidate.isSelD0bar() >= selectionFlagD0bar) { // only reco as D0bar - if (candidate.flagMcMatchRec() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { // also matched as D0bar + + if (selectedD0bar) { // reconstructed under the D0bar hypothesis + int candidateStatus = 0; + + if (candidate.flagMcMatchRec() == -o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + SETBIT(candidateStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0barSig); registry.fill(HIST("hMassD0barRecSig"), invMassD0bar, candidate.pt(), efficiencyWeight); + if (isD0Prompt) { registry.fill(HIST("hPtCandRecSigPrompt"), candidate.pt()); registry.fill(HIST("hPtVsMultiplicityRecPrompt"), candidate.pt(), collision.multFT0M()); @@ -735,18 +771,32 @@ struct HfCorrelatorD0Hadrons { registry.fill(HIST("hPtVsMLScoresVsEtaRecSigNonPrompt"), outputMlD0bar[0], outputMlD0bar[1], outputMlD0bar[2], candidate.pt(), candidate.eta()); } } else if (candidate.flagMcMatchRec() == o2::hf_decay::hf_cand_2prong::DecayChannelMain::D0ToPiK) { + SETBIT(candidateStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0barRef); registry.fill(HIST("hMassD0barRecRef"), invMassD0bar, candidate.pt(), efficiencyWeight); - if (candidate.isSelD0() < selectionFlagD0) { + + if (!selectedD0) { registry.fill(HIST("hMassD0barRecRefAfterRejectBoth"), invMassD0bar, candidate.pt(), efficiencyWeight); } } else { + SETBIT(candidateStatus, aod::hf_correlation_d0_hadron::ParticleTypeMcRec::D0barBg); registry.fill(HIST("hMassD0barRecBg"), invMassD0bar, candidate.pt(), efficiencyWeight); } + for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) { outputMlD0bar[iclass] = candidate.mlProbD0bar()[classMl->at(iclass)]; } + registry.fill(HIST("hMLScoresVsMassVsPtVsEtaVsOriginVsCent"), outputMlD0bar[0], outputMlD0bar[1], outputMlD0bar[2], invMassD0bar, candidate.pt(), candidate.eta(), isD0Prompt, cent, efficiencyWeight); - entryD0(candidate.phi(), candidate.eta(), candidate.pt(), invMassD0bar, poolBin, gCollisionId, timeStamp, (candidate.isSelD0() != 0) ? o2::aod::hf_correlation_d0_hadron::D0D0barBoth : o2::aod::hf_correlation_d0_hadron::D0barOnly); + + if (useCentrality) { + registry.fill(HIST("hMLScoresVsMassVsPtVsEtaVsOriginVsCandidateStatusVsHypothesisVsCent"), outputMlD0bar[0], outputMlD0bar[1], outputMlD0bar[2], invMassD0bar, candidate.pt(), candidate.eta(), + isD0Prompt, candidateStatus, recoHypothesis, cent, efficiencyWeight); + } else { + registry.fill(HIST("hMLScoresVsMassVsPtVsEtaVsOriginVsCandidateStatusVsHypothesis"), outputMlD0bar[0], outputMlD0bar[1], outputMlD0bar[2], invMassD0bar, candidate.pt(), candidate.eta(), isD0Prompt, + candidateStatus, recoHypothesis, efficiencyWeight); + } + + entryD0(candidate.phi(), candidate.eta(), candidate.pt(), invMassD0bar, poolBin, gCollisionId, timeStamp, selectedD0 ? o2::aod::hf_correlation_d0_hadron::D0D0barBoth : o2::aod::hf_correlation_d0_hadron::D0barOnly); } entryD0CandRecoInfo(invMassD0, invMassD0bar, candidate.pt(), outputMlD0[0], outputMlD0[1], outputMlD0[2], outputMlD0bar[0], outputMlD0bar[1], outputMlD0bar[2]); entryD0CandGenInfo(isD0Prompt); diff --git a/PWGHF/HFC/TableProducer/correlatorDMesonPairs.cxx b/PWGHF/HFC/TableProducer/correlatorDMesonPairs.cxx index 9cb291e3d95..19130525213 100644 --- a/PWGHF/HFC/TableProducer/correlatorDMesonPairs.cxx +++ b/PWGHF/HFC/TableProducer/correlatorDMesonPairs.cxx @@ -143,7 +143,8 @@ struct HfCorrelatorDMesonPairs { Produces entryD0PairMcGenInfo; // Tables for event mixing - Produces entryDMesonCand; + Produces entryDMesonInfoCand1; + Produces entryDMesonInfoCand2; Produces entryAssocHad; Configurable selectionFlagD0{"selectionFlagD0", 1, "Selection Flag for D0"}; @@ -422,6 +423,7 @@ struct HfCorrelatorDMesonPairs { registry.add("hMultFT0M", "multiplicity;multiplicity;entries", {HistType::kTH1F, {{10000, 0., 10000.}}}); registry.add("hZvtx", "z vertex;z vertex;entries", {HistType::kTH1F, {{200, -20., 20.}}}); registry.add("hD0Bin", "D0 selected in pool Bin;pool Bin;entries", {HistType::kTH1F, {{axisPoolBin}}}); + registry.add("hD0Cand2Bin", "D0 selected in pool Bin;pool Bin;entries", {HistType::kTH1F, {{axisPoolBin}}}); registry.add("hTracksBin", "Tracks selected in pool Bin;pool Bin;entries", {HistType::kTH1F, {{axisPoolBin}}}); registry.add("hDcaXYVsPt", "DCA xy vs pt", {HistType::kTH2F, {{axisDcaXY}, {axisPtHadron}}}); } @@ -795,7 +797,7 @@ struct HfCorrelatorDMesonPairs { } // Fill D0 table for offline event mixing if (applyMixedEvent) { - entryDMesonCand(candidate1.pt(), candidate1.eta(), candidate1.phi(), HfHelper::invMassD0ToPiK(candidate1), poolBin, gCollisionId, timeStamp); + entryDMesonInfoCand1(candidate1.pt(), candidate1.eta(), candidate1.phi(), HfHelper::invMassD0ToPiK(candidate1), candidateType1, poolBin, gCollisionId, timeStamp); } } if (isDbarCand1) { @@ -807,7 +809,7 @@ struct HfCorrelatorDMesonPairs { } // Fill D0 table for offline event mixing if (applyMixedEvent) { - entryDMesonCand(candidate1.pt(), candidate1.eta(), candidate1.phi(), HfHelper::invMassD0barToKPi(candidate1), poolBin, gCollisionId, timeStamp); + entryDMesonInfoCand1(candidate1.pt(), candidate1.eta(), candidate1.phi(), HfHelper::invMassD0ToPiK(candidate1), candidateType1, poolBin, gCollisionId, timeStamp); } } @@ -898,6 +900,16 @@ struct HfCorrelatorDMesonPairs { continue; } + if (applyMixedEvent) { + if (isDCand2) { + entryDMesonInfoCand2(candidate2.pt(), candidate2.eta(), candidate2.phi(), HfHelper::invMassD0barToKPi(candidate2), candidateType2, poolBin, gCollisionId, timeStamp); + } + if (isDbarCand2) { + entryDMesonInfoCand2(candidate2.pt(), candidate2.eta(), candidate2.phi(), HfHelper::invMassD0barToKPi(candidate2), candidateType2, poolBin, gCollisionId, timeStamp); + } + registry.fill(HIST("hD0Cand2Bin"), poolBin); + } + fillEntry(isDCand1, isDbarCand1, isDCand2, isDbarCand2, candidateType1, candidateType2, HfHelper::yD0(candidate1), HfHelper::yD0(candidate2), candidate1.eta(), candidate2.eta(), candidate1.phi(), candidate2.phi(), candidate1.pt(), candidate2.pt(), HfHelper::invMassD0ToPiK(candidate1), HfHelper::invMassD0barToKPi(candidate1), @@ -940,8 +952,8 @@ struct HfCorrelatorDMesonPairs { auto etaCandidate1 = candidate1.eta(); float const massD0Cand1 = HfHelper::invMassD0ToPiK(candidate1); float const massD0barCand1 = HfHelper::invMassD0barToKPi(candidate1); - auto prong0Cand1 = candidate1.template prong0_as(); - auto prong1Cand1 = candidate1.template prong1_as(); + auto prong0Cand1 = candidate1.template prong0_as(); + auto prong1Cand1 = candidate1.template prong1_as(); if (std::abs(HfHelper::yD0(candidate1)) > yCandMax) { continue; diff --git a/PWGHF/HFC/TableProducer/correlatorFlowCharmHadronsReduced.cxx b/PWGHF/HFC/TableProducer/correlatorFlowCharmHadronsReduced.cxx index 2249a165d6c..eb62101c165 100644 --- a/PWGHF/HFC/TableProducer/correlatorFlowCharmHadronsReduced.cxx +++ b/PWGHF/HFC/TableProducer/correlatorFlowCharmHadronsReduced.cxx @@ -262,7 +262,7 @@ struct HfCorrelatorFlowCharmHadronsReduced { template void fillSameEvent(TPair const& pair, TTrigCand const& trigCand, - TBinningType binPolicy) + const TBinningType& binPolicy) { auto collision = pair.template hfcRedCorrColl_as(); if (collision.centrality() < centralityMin || collision.centrality() > centralityMax) { @@ -311,7 +311,7 @@ struct HfCorrelatorFlowCharmHadronsReduced { /// \param binPolicy is the binning policy for the correlation template void fillMixedEvent(TPairs const& pairs, - TBinningType binPolicy) + const TBinningType& binPolicy) { for (const auto& [trigColl, trigCands, assocColl, assocTracks] : pairs) { if (trigCands.size() == 0 || assocTracks.size() == 0) { @@ -423,7 +423,7 @@ struct HfCorrelatorFlowCharmHadronsReduced { void doCorrelationsMixedEvent(const TCollision& collisions, const TTrigCand& trigCands, const TTrackAssoc& assocTracks, - TBinningType binPolicy) + const TBinningType& binPolicy) { auto tracksTuple = std::make_tuple(trigCands, assocTracks); diff --git a/PWGHF/HFC/TableProducer/correlatorHfeHadrons.cxx b/PWGHF/HFC/TableProducer/correlatorHfeHadrons.cxx index e83da75ed36..43468843ebf 100644 --- a/PWGHF/HFC/TableProducer/correlatorHfeHadrons.cxx +++ b/PWGHF/HFC/TableProducer/correlatorHfeHadrons.cxx @@ -16,6 +16,7 @@ #include "PWGHF/HFC/DataModel/CorrelationTables.h" #include "PWGHF/HFL/DataModel/ElectronSelectionTable.h" +#include "PWGJE/DataModel/EMCALClusters.h" #include "Common/CCDB/TriggerAliases.h" #include "Common/Core/RecoDecay.h" @@ -62,7 +63,7 @@ struct HfCorrelatorHfeHadrons { // Event Selection Configurable zPvPosMax{"zPvPosMax", 10., "Maximum z of the primary vertex (cm)"}; Configurable isRun3{"isRun3", true, "Data is from Run3 or Run2"}; - + Configurable skipNoEmcClusters{"skipNoEmcClusters", false, "Skip events with no EMCal clusters"}; Configurable numberEventsMixed{"numberEventsMixed", 5, "number of events mixed in ME process"}; Configurable invMassEEMax{"invMassEEMax", 0.14f, "max Invariant Mass for Photonic electron"}; // Associated Hadron selection @@ -211,12 +212,17 @@ struct HfCorrelatorHfeHadrons { } // Electron-hadron Correlation - template - void fillCorrelation(CollisionType const& collision, ElectronType const& electrons, TracksType const& tracks, BcType const&, McParticlesType const&) + template + void fillCorrelation(CollisionType const& collision, ElectronType const& electrons, TracksType const& tracks, EmcClusterType const& emcClusters, BcType const&, McParticlesType const&) { if (!(isRun3 ? collision.sel8() : (collision.sel7() && collision.alias_bit(kINT7)))) { return; } + // skip events with no clusters + if (emcClusters.size() == 0 && skipNoEmcClusters) { + return; + } + int poolBin = corrBinning.getBin(std::make_tuple(collision.posZ(), collision.multFT0M())); auto bc = collision.template bc_as(); int gCollisionId = collision.globalIndex(); @@ -240,7 +246,11 @@ struct HfCorrelatorHfeHadrons { if (!selAssoHadron(hTrack)) { continue; } + if (!skipEventTableFilling) { + registry.fill(HIST("hptHadron"), hTrack.pt()); + entryHadron(hTrack.phi(), hTrack.eta(), hTrack.pt(), poolBin, gCollisionId, timeStamp); + } // Mc rec hadron efficiency if constexpr (IsMc) { if (hTrack.has_mcParticle()) { @@ -275,7 +285,6 @@ struct HfCorrelatorHfeHadrons { double ptElectron = -999; double phiElectron = -999; double etaElectron = -999; - int cntEle = 0; for (const auto& eTrack : electrons) { ptElectron = eTrack.ptTrack(); phiElectron = eTrack.phiTrack(); @@ -289,9 +298,7 @@ struct HfCorrelatorHfeHadrons { double etaHadron = -999; double phiHadron = -999; // EMCal electron - if (eTrack.isEmcal() && requireEmcal) { - acceptElectron = true; - } else if (!eTrack.isEmcal() && !requireEmcal) { + if (eTrack.isEmcal() == requireEmcal) { acceptElectron = true; } @@ -375,15 +382,9 @@ struct HfCorrelatorHfeHadrons { } entryElectronHadronPair(deltaPhi, deltaEta, ptElectron, ptHadron, eTrack.eopEl(), eTrack.m02El(), eTrack.tpcNSigmaElTrack(), eTrack.tofNSigmaElTrack(), eTrack.tpcNClsCrRowsTrack(), eTrack.tpcCrRowsRatioTrack(), eTrack.itsChi2NClTrack(), eTrack.tpcChi2NClTrack(), eTrack.dcaXYTrack(), eTrack.dcaZTrack(), hTrack.tpcNClsCrossedRows(), hTrack.tpcCrossedRowsOverFindableCls(), hTrack.itsChi2NCl(), hTrack.tpcChi2NCl(), hTrack.dcaXY(), hTrack.dcaZ(), poolBin, nElHadLSCorr, nElHadUSCorr); - if (!skipEventTableFilling) { - if (cntEle == 0) { - registry.fill(HIST("hptHadron"), hTrack.pt()); - entryHadron(hTrack.phi(), hTrack.eta(), hTrack.pt(), poolBin, gCollisionId, timeStamp); - } - } } // end Hadron Track loop - cntEle++; + } // end Electron loop } @@ -451,10 +452,10 @@ struct HfCorrelatorHfeHadrons { void processData(TableCollision const& collision, aod::HfCorrSelEl const& electrons, - TableTracks const& tracks, + TableTracks const& tracks, aod::EMCALClusters const& emcClusters, aod::BCsWithTimestamps const& bcs) { - fillCorrelation(collision, electrons, tracks, bcs, 0); + fillCorrelation(collision, electrons, tracks, emcClusters, bcs, 0); } PROCESS_SWITCH(HfCorrelatorHfeHadrons, processData, "Process for Data", false); @@ -463,10 +464,10 @@ struct HfCorrelatorHfeHadrons { void processMcRec(McTableCollision const& mcCollision, aod::HfCorrSelEl const& mcElectrons, - McTableTracks const& mcTracks, + McTableTracks const& mcTracks, aod::EMCALClusters const& emcClusters, aod::BCsWithTimestamps const& bcs, aod::McParticles const& mcParticle) { - fillCorrelation(mcCollision, mcElectrons, mcTracks, bcs, mcParticle); + fillCorrelation(mcCollision, mcElectrons, mcTracks, emcClusters, bcs, mcParticle); } PROCESS_SWITCH(HfCorrelatorHfeHadrons, processMcRec, "Process MC Reco mode", true); diff --git a/PWGHF/HFC/TableProducer/derivedDataCreatorCorrelationsReduced.cxx b/PWGHF/HFC/TableProducer/derivedDataCreatorCorrelationsReduced.cxx index 5636a0b8fa6..55bc064a960 100644 --- a/PWGHF/HFC/TableProducer/derivedDataCreatorCorrelationsReduced.cxx +++ b/PWGHF/HFC/TableProducer/derivedDataCreatorCorrelationsReduced.cxx @@ -111,7 +111,7 @@ struct HfDerivedDataCreatorCorrelationsReduced { double massCharm{0.}; TF1* funcDcaXYPtCutPrimTrk = nullptr; - using CollsWithCentMult = soa::Join; + using CollsWithCentMult = soa::Join; using CandDsData = soa::Filtered>; using CandDplusData = soa::Filtered>; using CandD0Data = soa::Filtered>; diff --git a/PWGHF/HFC/TableProducer/producerCharmHadronsTrackFemtoDream.cxx b/PWGHF/HFC/TableProducer/producerCharmHadronsTrackFemtoDream.cxx index d128f50fafb..dbf1d9deb2d 100644 --- a/PWGHF/HFC/TableProducer/producerCharmHadronsTrackFemtoDream.cxx +++ b/PWGHF/HFC/TableProducer/producerCharmHadronsTrackFemtoDream.cxx @@ -493,7 +493,7 @@ struct HfProducerCharmHadronsTrackFemtoDream { // list of mothers is not empty } else if (particleMc.getProcess() == TMCProcess::kPDecay && particleMc.getGenStatusCode() == GenFromTransport && !motherparticlesMc.empty()) { // get direct mother - auto motherparticleMc = motherparticlesMc.front(); + const auto& motherparticleMc = motherparticlesMc.front(); pdgCodeMother = motherparticleMc.pdgCode(); particleOrigin = checkDaughterType(fdparttype, motherparticleMc.pdgCode(), pdgCode); // check if particle is material @@ -1068,7 +1068,7 @@ struct HfProducerCharmHadronsTrackFemtoDream { } template - void fillCharmHadMcGen(ParticleType particles) + void fillCharmHadMcGen(const ParticleType& particles) { // Filling particle properties tables.rowCandCharmHadGen.reserve(particles.size() + 1); diff --git a/PWGHF/HFC/TableProducer/producerCharmHadronsV0FemtoDream.cxx b/PWGHF/HFC/TableProducer/producerCharmHadronsV0FemtoDream.cxx index 06aed471a3b..fa5c70e33d0 100644 --- a/PWGHF/HFC/TableProducer/producerCharmHadronsV0FemtoDream.cxx +++ b/PWGHF/HFC/TableProducer/producerCharmHadronsV0FemtoDream.cxx @@ -526,7 +526,7 @@ struct HfProducerCharmHadronsV0FemtoDream { // list of mothers is not empty } else if (particleMc.getProcess() == TMCProcess::kPDecay && particleMc.getGenStatusCode() == GenFromTransport && !motherparticlesMc.empty()) { // get direct mother - auto motherparticleMc = motherparticlesMc.front(); + const auto& motherparticleMc = motherparticlesMc.front(); pdgCodeMother = motherparticleMc.pdgCode(); particleOrigin = checkDaughterType(fdparttype, motherparticleMc.pdgCode(), pdgCode); // check if particle is material @@ -1175,7 +1175,7 @@ struct HfProducerCharmHadronsV0FemtoDream { } template - void fillCharmHadMcGen(ParticleType particles) + void fillCharmHadMcGen(const ParticleType& particles) { // Filling particle properties rowCandCharmHadGen.reserve(particles.size() + 1); diff --git a/PWGHF/HFC/Tasks/taskCharmHadronsTrackFemtoDream.cxx b/PWGHF/HFC/Tasks/taskCharmHadronsTrackFemtoDream.cxx index 92915f093a8..aeb4e57e88d 100644 --- a/PWGHF/HFC/Tasks/taskCharmHadronsTrackFemtoDream.cxx +++ b/PWGHF/HFC/Tasks/taskCharmHadronsTrackFemtoDream.cxx @@ -192,7 +192,7 @@ struct HfTaskCharmHadronsTrackFemtoDream { using FilteredMcColisions = soa::Filtered>; using FilteredMcColision = FilteredMcColisions::iterator; - using FilteredFDMcParts = soa::Filtered>; + using FilteredFDMcParts = soa::Filtered>; using FilteredFDMcPart = FilteredFDMcParts::iterator; using FilteredFDParticles = soa::Filtered>; @@ -1145,6 +1145,10 @@ struct HfTaskCharmHadronsTrackFemtoDream { if ((col.bitmaskTrackOne() & bitMask) != bitMask || (col.bitmaskTrackTwo() & bitMask) != bitMask) { continue; } + if (fillTableWithCharm.value && sliceMcCharmHad.size() == 0) { + continue; + } + fillTables(col, sliceMcTrk1, sliceMcCharmHad); doSameEvent(sliceMcCharmHad, sliceMcTrk1, parts, col); } if (mixSetting.doMixEvent) { @@ -1186,6 +1190,10 @@ struct HfTaskCharmHadronsTrackFemtoDream { if ((col.bitmaskTrackOne() & bitMask) != bitMask || (col.bitmaskTrackTwo() & bitMask) != bitMask) { continue; } + if (fillTableWithCharm.value && sliceMcCharmHad.size() == 0) { + continue; + } + fillTables(col, sliceMcTrk1, sliceMcCharmHad); doSameEvent(sliceMcCharmHad, sliceMcTrk1, parts, col); } if (mixSetting.doMixEvent) { @@ -1227,6 +1235,10 @@ struct HfTaskCharmHadronsTrackFemtoDream { if ((col.bitmaskTrackOne() & bitMask) != bitMask || (col.bitmaskTrackTwo() & bitMask) != bitMask) { continue; } + if (fillTableWithCharm.value && sliceMcCharmHad.size() == 0) { + continue; + } + fillTables(col, sliceMcTrk1, sliceMcCharmHad); doSameEvent(sliceMcCharmHad, sliceMcTrk1, parts, col); } if (mixSetting.doMixEvent) { @@ -1268,6 +1280,10 @@ struct HfTaskCharmHadronsTrackFemtoDream { if ((col.bitmaskTrackOne() & bitMask) != bitMask || (col.bitmaskTrackTwo() & bitMask) != bitMask) { continue; } + if (fillTableWithCharm.value && sliceMcCharmHad.size() == 0) { + continue; + } + fillTables(col, sliceMcTrk1, sliceMcCharmHad); doSameEvent(sliceMcCharmHad, sliceMcTrk1, parts, col); } if (mixSetting.doMixEvent) { @@ -1309,6 +1325,10 @@ struct HfTaskCharmHadronsTrackFemtoDream { if ((col.bitmaskTrackOne() & bitMask) != bitMask || (col.bitmaskTrackTwo() & bitMask) != bitMask) { continue; } + if (fillTableWithCharm.value && sliceMcCharmHad.size() == 0) { + continue; + } + fillTables(col, sliceMcTrk1, sliceMcCharmHad); doSameEvent(sliceMcCharmHad, sliceMcTrk1, parts, col); } if (mixSetting.doMixEvent) { diff --git a/PWGHF/HFC/Tasks/taskFlow.cxx b/PWGHF/HFC/Tasks/taskFlow.cxx index b68e6a79f18..1337864b67b 100644 --- a/PWGHF/HFC/Tasks/taskFlow.cxx +++ b/PWGHF/HFC/Tasks/taskFlow.cxx @@ -1000,7 +1000,7 @@ struct HfTaskFlow { // } template - int64_t getMultiplicityEstimator(TCollision collision, bool isSameEvent) + int64_t getMultiplicityEstimator(const TCollision& collision, bool isSameEvent) { switch (configCollision.multiplicityEstimator) { case MultiplicityEstimators::MultNTracksPV: @@ -1228,7 +1228,7 @@ struct HfTaskFlow { LOGF(info, "Loaded efficiency histogram from %s (%p)", configTask.loadEfficienciesForTpc.value.c_str(), static_cast(mEfficiencyTpc)); } if (configTask.loadEfficienciesForMft.value.empty() == false) { - mEfficiencyMft = ccdb->getForTimeStamp(configTask.loadEfficienciesForTpc, timestamp); + mEfficiencyMft = ccdb->getForTimeStamp(configTask.loadEfficienciesForMft, timestamp); if (mEfficiencyMft == nullptr) { LOGF(fatal, "Could not load efficiency histogram for MFT tracks from %s", configTask.loadEfficienciesForMft.value.c_str()); } @@ -1292,7 +1292,7 @@ struct HfTaskFlow { } template - double getCorrectedMultiplicity(TTracks tracks) // function to count the number of tracks in the event and fill the histogram + double getCorrectedMultiplicity(const TTracks& tracks) // function to count the number of tracks in the event and fill the histogram { auto trackCounter = 0; auto weightMultiplicity = 1.0f; diff --git a/PWGHF/HFL/Tasks/taskElectronWeakBoson.cxx b/PWGHF/HFL/Tasks/taskElectronWeakBoson.cxx index d579eb76d8a..ac168cf5d3e 100644 --- a/PWGHF/HFL/Tasks/taskElectronWeakBoson.cxx +++ b/PWGHF/HFL/Tasks/taskElectronWeakBoson.cxx @@ -76,6 +76,7 @@ struct HfTaskElectronWeakBoson { Configurable vtxZ{"vtxZ", 10.f, ""}; + Configurable applyTrackSys{"applyTrackSys", false, "apply additional track cuts for systematic study"}; Configurable etaTrMin{"etaTrMin", -1.0f, "minimun track eta"}; Configurable etaTrMax{"etaTrMax", 1.0f, "maximum track eta"}; Configurable etaEmcMax{"etaEmcMax", 0.6f, "maximum track eta"}; @@ -173,7 +174,7 @@ struct HfTaskElectronWeakBoson { using SelectedClusters = o2::aod::EMCALClusters; // PbPb // using TrackEle = o2::soa::Join; - using TrackEle = o2::soa::Join; + using TrackEle = o2::soa::Join; // pp // using TrackEle = o2::soa::Filtered>; @@ -201,6 +202,7 @@ struct HfTaskElectronWeakBoson { ConfigurableAxis confaxisIsoEnergy{"confaxisIsoEnergy", {255, 0, 2.0}, "E_{iso}"}; ConfigurableAxis confaxisIsoMomentum{"confaxisIsoMomentum", {255, 0, 2.0}, "p_{iso}"}; ConfigurableAxis confaxisIsoTrack{"confaxisIsoTrack", {25, -0.5, 24.5}, "Isolation Track"}; + ConfigurableAxis confaxisDedxTrack{"confaxisDedxTrack", {200, -10, 10}, "dEdx"}; ConfigurableAxis confaxisInvMassZgamma{"confaxisInvMassZgamma", {150, 0, 150}, "M_{ee} (GeV/c^{2})"}; ConfigurableAxis confaxisInvMassZ{"confaxisInvMassZ", {130, 20, 150}, "M_{ee} (GeV/c^{2})"}; ConfigurableAxis confaxisZfrag{"confaxisZfrag", {200, 0, 2.0}, "p_{T,h}/p_{T,Z}"}; @@ -259,7 +261,7 @@ struct HfTaskElectronWeakBoson { const AxisSpec axisNsigma{100, -5, 5, "N#sigma"}; const AxisSpec axisNsigmaZneg{100, -5, 5, "N#sigma_{pos}"}; const AxisSpec axisNsigmaZpos{100, -5, 5, "N#sigma_{neg}"}; - const AxisSpec axisDedx{150, 0, 150, "dEdx"}; + const AxisSpec axisDedx{confaxisDedxTrack, "dEdx"}; const AxisSpec axisE{nBinsE, 0, binEmax, "Energy"}; const AxisSpec axisM02{100, 0, 1, "M02"}; const AxisSpec axisM02neg{100, 0, 1, "M02(neg)"}; @@ -343,7 +345,7 @@ struct HfTaskElectronWeakBoson { registry.add("hTHnTrMatch", "Track EMC Match", HistType::kTHnSparseF, {axisPt, axisdPhi, axisdEta}); // Z-hadron correlation histograms - registry.add("hZHadronDphi", "Z-hadron #Delta#phi correlation", HistType::kTHnSparseF, {axisCentrality, axisSign, axisPtZ, axisDPhiZh, axisDEtaZh, axisZfrag, axisPtHadron}); + registry.add("hZHadronDphi", "Z-hadron #Delta#phi correlation", HistType::kTHnSparseF, {axisCentrality, axisSign, axisPtZ, axisDPhiZh, axisDEtaZh, axisZfrag, axisPtHadron, axisDedx}); registry.add("hZptSpectrum", "Z boson p_{T} spectrum", kTH2F, {{axisSign}, {axisPtZ}}); // hisotgram for EMCal trigger @@ -646,28 +648,32 @@ struct HfTaskElectronWeakBoson { // track loop for (const auto& track : tracks) { - if (std::abs(track.eta()) > etaTrMax) { - continue; - } - if (track.tpcNClsCrossedRows() < nclcrossTpcMin) { - continue; - } - if (std::abs(track.dcaXY()) > dcaxyMax) { - continue; - } - if (track.itsChi2NCl() > chi2ItsMax) { - continue; - } - if (track.tpcChi2NCl() > chi2TpcMax) { + if (!track.isGlobalTrackWoPtEta()) { continue; } - if (track.tpcNClsFound() < nclTpcMin) { + if (std::abs(track.eta()) > etaTrMax) { continue; } - if (track.itsNCls() < nclItsMin) { - continue; + if (applyTrackSys) { + if (track.tpcNClsCrossedRows() < nclcrossTpcMin) { + continue; + } + if (std::abs(track.dcaXY()) > dcaxyMax) { + continue; + } + if (track.itsChi2NCl() > chi2ItsMax) { + continue; + } + if (track.tpcChi2NCl() > chi2TpcMax) { + continue; + } + if (track.tpcNClsFound() < nclTpcMin) { + continue; + } + if (track.itsNCls() < nclItsMin) { + continue; + } } - registry.fill(HIST("hEta"), track.eta()); registry.fill(HIST("hITSchi2"), track.itsChi2NCl()); registry.fill(HIST("hTPCchi2"), track.tpcChi2NCl()); @@ -694,7 +700,7 @@ struct HfTaskElectronWeakBoson { eop, isoEnergy, isoMomentum, - track.tpcNSigmaEl(), + track.tpcNSigmaPi() * track.sign(), m02, trackCount, track.tpcNClsCrossedRows(), @@ -873,7 +879,7 @@ struct HfTaskElectronWeakBoson { double const deltaPhi = RecoDecay::constrainAngle(trackAss.phi - zBoson.phi, -o2::constants::math::PIHalf); double const ptRatio = trackAss.pt / zBoson.pt; double const deltaEta = zBoson.eta - trackAss.eta; - registry.fill(HIST("hZHadronDphi"), centrality, zBoson.charge, zBoson.pt, deltaPhi, deltaEta, ptRatio, trackAss.pt); + registry.fill(HIST("hZHadronDphi"), centrality, zBoson.charge, zBoson.pt, deltaPhi, deltaEta, ptRatio, trackAss.pt, trackAss.dedxTrk); } } } // end of Z-hadron correlation diff --git a/PWGHF/HFL/Tasks/taskSingleElectron.cxx b/PWGHF/HFL/Tasks/taskSingleElectron.cxx index cfe6e8434d5..3a66413094f 100644 --- a/PWGHF/HFL/Tasks/taskSingleElectron.cxx +++ b/PWGHF/HFL/Tasks/taskSingleElectron.cxx @@ -171,6 +171,18 @@ struct HfTaskSingleElectron { histos.add("hTpcNSigPtAfterTofCut", "", kTH2D, {{axisPtEl}, {axisNsig}}); histos.add("hTpcNSigPtQA", "", kTH2D, {{axisPtEl}, {axisNsig}}); + // TPC nSigma(e) vs pT per MC truth species (electron, pion, kaon, proton, other), after the track selection and after the TOF electron selection + histos.add("hTpcNSigPtRecElectron", "MC truth e^{#pm} after track selection;#it{p}_{T} (GeV/#it{c});n#sigma_{e}^{TPC}", kTH2D, {{axisPtEl}, {axisNsig}}); + histos.add("hTpcNSigPtRecPion", "MC truth #pi^{#pm} after track selection;#it{p}_{T} (GeV/#it{c});n#sigma_{e}^{TPC}", kTH2D, {{axisPtEl}, {axisNsig}}); + histos.add("hTpcNSigPtRecKaon", "MC truth K^{#pm} after track selection;#it{p}_{T} (GeV/#it{c});n#sigma_{e}^{TPC}", kTH2D, {{axisPtEl}, {axisNsig}}); + histos.add("hTpcNSigPtRecProton", "MC truth p after track selection;#it{p}_{T} (GeV/#it{c});n#sigma_{e}^{TPC}", kTH2D, {{axisPtEl}, {axisNsig}}); + histos.add("hTpcNSigPtRecOther", "MC truth other after track selection;#it{p}_{T} (GeV/#it{c});n#sigma_{e}^{TPC}", kTH2D, {{axisPtEl}, {axisNsig}}); + histos.add("hTpcNSigPtAfterTofCutRecElectron", "MC truth e^{#pm} after TOF selection;#it{p}_{T} (GeV/#it{c});n#sigma_{e}^{TPC}", kTH2D, {{axisPtEl}, {axisNsig}}); + histos.add("hTpcNSigPtAfterTofCutRecPion", "MC truth #pi^{#pm} after TOF selection;#it{p}_{T} (GeV/#it{c});n#sigma_{e}^{TPC}", kTH2D, {{axisPtEl}, {axisNsig}}); + histos.add("hTpcNSigPtAfterTofCutRecKaon", "MC truth K^{#pm} after TOF selection;#it{p}_{T} (GeV/#it{c});n#sigma_{e}^{TPC}", kTH2D, {{axisPtEl}, {axisNsig}}); + histos.add("hTpcNSigPtAfterTofCutRecProton", "MC truth p after TOF selection;#it{p}_{T} (GeV/#it{c});n#sigma_{e}^{TPC}", kTH2D, {{axisPtEl}, {axisNsig}}); + histos.add("hTpcNSigPtAfterTofCutRecOther", "MC truth other after TOF selection;#it{p}_{T} (GeV/#it{c});n#sigma_{e}^{TPC}", kTH2D, {{axisPtEl}, {axisNsig}}); + // track impact parameter histos.add("hDcaTrack", "", kTH2D, {{axisPtEl}, {axisTrackIp}}); histos.add("hDcaBeauty", "", kTH2D, {{axisPtEl}, {axisTrackIp}}); @@ -205,6 +217,42 @@ struct HfTaskSingleElectron { histos.fill(HIST("hPtDcaZPreCut"), pt, track.dcaZ()); } + template + void fillTpcNSigPtRec(const TrackType& track, bool afterTofCut) + { + if (!track.has_mcParticle()) { + return; + } + double const pt = track.pt(); + double const nSigmaEl = track.tpcNSigmaEl(); + int const absPdg = std::abs(track.mcParticle().pdgCode()); + if (!afterTofCut) { + if (absPdg == kElectron) { + histos.fill(HIST("hTpcNSigPtRecElectron"), pt, nSigmaEl); + } else if (absPdg == kPiPlus) { + histos.fill(HIST("hTpcNSigPtRecPion"), pt, nSigmaEl); + } else if (absPdg == kKPlus) { + histos.fill(HIST("hTpcNSigPtRecKaon"), pt, nSigmaEl); + } else if (absPdg == kProton) { + histos.fill(HIST("hTpcNSigPtRecProton"), pt, nSigmaEl); + } else { + histos.fill(HIST("hTpcNSigPtRecOther"), pt, nSigmaEl); + } + return; + } + if (absPdg == kElectron) { + histos.fill(HIST("hTpcNSigPtAfterTofCutRecElectron"), pt, nSigmaEl); + } else if (absPdg == kPiPlus) { + histos.fill(HIST("hTpcNSigPtAfterTofCutRecPion"), pt, nSigmaEl); + } else if (absPdg == kKPlus) { + histos.fill(HIST("hTpcNSigPtAfterTofCutRecKaon"), pt, nSigmaEl); + } else if (absPdg == kProton) { + histos.fill(HIST("hTpcNSigPtAfterTofCutRecProton"), pt, nSigmaEl); + } else { + histos.fill(HIST("hTpcNSigPtAfterTofCutRecOther"), pt, nSigmaEl); + } + } + template bool trackSel(const TrackType& track) { @@ -566,6 +614,7 @@ struct HfTaskSingleElectron { histos.fill(HIST("hTofNSigPt"), track.pt(), track.tofNSigmaEl()); histos.fill(HIST("hTpcNSigPt"), track.pt(), track.tpcNSigmaEl()); + fillTpcNSigPtRec(track, false); int mpdg{}; // electron source pdg code double mpt{}; // electron source pt @@ -599,6 +648,7 @@ struct HfTaskSingleElectron { } histos.fill(HIST("hTofNSigPtQA"), track.pt(), track.tofNSigmaEl()); histos.fill(HIST("hTpcNSigPtAfterTofCut"), track.pt(), track.tpcNSigmaEl()); + fillTpcNSigPtRec(track, true); if (track.tpcNSigmaEl() < nSigmaTpcMin || track.tpcNSigmaEl() > nSigmaTpcMax) { continue; diff --git a/PWGHF/TableProducer/candidateCreator2Prong.cxx b/PWGHF/TableProducer/candidateCreator2Prong.cxx index 821936284fb..ab7f982c398 100644 --- a/PWGHF/TableProducer/candidateCreator2Prong.cxx +++ b/PWGHF/TableProducer/candidateCreator2Prong.cxx @@ -38,6 +38,7 @@ #include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Tools/KFparticle/KFUtilities.h" #include @@ -535,7 +536,7 @@ struct HfCandidateCreator2Prong { /////////////////////////////////// /// @brief process function using DCA fitter w/ PV refit and w/o centrality selections - void processPvRefitWithDCAFitterN(soa::Join const& collisions, + void processPvRefitWithDCAFitterN(soa::Join const& collisions, soa::Join const& rowsTrackIndexProng2, TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -545,7 +546,7 @@ struct HfCandidateCreator2Prong { PROCESS_SWITCH(HfCandidateCreator2Prong, processPvRefitWithDCAFitterN, "Run candidate creator using DCA fitter w/ PV refit and w/o centrality selections", false); /// @brief process function using DCA fitter w/o PV refit and w/o centrality selections - void processNoPvRefitWithDCAFitterN(soa::Join const& collisions, + void processNoPvRefitWithDCAFitterN(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexProng2, TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -555,7 +556,7 @@ struct HfCandidateCreator2Prong { PROCESS_SWITCH(HfCandidateCreator2Prong, processNoPvRefitWithDCAFitterN, "Run candidate creator using DCA fitter w/o PV refit and w/o centrality selections", true); /// @brief process function using KFParticle package w/ PV refit and w/o centrality selections - void processPvRefitWithKFParticle(soa::Join const& collisions, + void processPvRefitWithKFParticle(soa::Join const& collisions, soa::Join const& rowsTrackIndexProng2, TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -565,7 +566,7 @@ struct HfCandidateCreator2Prong { PROCESS_SWITCH(HfCandidateCreator2Prong, processPvRefitWithKFParticle, "Run candidate creator using KFParticle package w/ PV refit and w/o centrality selections", false); /// @brief process function using KFParticle package w/o PV refit and w/o centrality selections - void processNoPvRefitWithKFParticle(soa::Join const& collisions, + void processNoPvRefitWithKFParticle(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexProng2, TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -581,7 +582,7 @@ struct HfCandidateCreator2Prong { ///////////////////////////////////////////// /// @brief process function using DCA fitter w/ PV refit and w/ centrality selection on FT0C - void processPvRefitWithDCAFitterNCentFT0C(soa::Join const& collisions, + void processPvRefitWithDCAFitterNCentFT0C(soa::Join const& collisions, soa::Join const& rowsTrackIndexProng2, TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -591,7 +592,7 @@ struct HfCandidateCreator2Prong { PROCESS_SWITCH(HfCandidateCreator2Prong, processPvRefitWithDCAFitterNCentFT0C, "Run candidate creator using DCA fitter w/ PV refit and w/ centrality selection on FT0C", false); /// @brief process function using DCA fitter w/o PV refit and w/ centrality selection FT0C - void processNoPvRefitWithDCAFitterNCentFT0C(soa::Join const& collisions, + void processNoPvRefitWithDCAFitterNCentFT0C(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexProng2, TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -601,7 +602,7 @@ struct HfCandidateCreator2Prong { PROCESS_SWITCH(HfCandidateCreator2Prong, processNoPvRefitWithDCAFitterNCentFT0C, "Run candidate creator using DCA fitter w/o PV refit and w/ centrality selection FT0C", false); /// @brief process function using KFParticle package w/ PV refit and w/ centrality selection on FT0C - void processPvRefitWithKFParticleCentFT0C(soa::Join const& collisions, + void processPvRefitWithKFParticleCentFT0C(soa::Join const& collisions, soa::Join const& rowsTrackIndexProng2, TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -611,7 +612,7 @@ struct HfCandidateCreator2Prong { PROCESS_SWITCH(HfCandidateCreator2Prong, processPvRefitWithKFParticleCentFT0C, "Run candidate creator using KFParticle package w/ PV refit and w/ centrality selection on FT0C", false); /// @brief process function using KFParticle package w/o PV refit and w/o centrality selections - void processNoPvRefitWithKFParticleCentFT0C(soa::Join const& collisions, + void processNoPvRefitWithKFParticleCentFT0C(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexProng2, TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -627,7 +628,7 @@ struct HfCandidateCreator2Prong { ///////////////////////////////////////////// /// @brief process function using DCA fitter w/ PV refit and w/ centrality selection on FT0M - void processPvRefitWithDCAFitterNCentFT0M(soa::Join const& collisions, + void processPvRefitWithDCAFitterNCentFT0M(soa::Join const& collisions, soa::Join const& rowsTrackIndexProng2, TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -637,7 +638,7 @@ struct HfCandidateCreator2Prong { PROCESS_SWITCH(HfCandidateCreator2Prong, processPvRefitWithDCAFitterNCentFT0M, "Run candidate creator using DCA fitter w/ PV refit and w/ centrality selection on FT0M", false); /// @brief process function using DCA fitter w/o PV refit and w/ centrality selection FT0M - void processNoPvRefitWithDCAFitterNCentFT0M(soa::Join const& collisions, + void processNoPvRefitWithDCAFitterNCentFT0M(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexProng2, TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -647,7 +648,7 @@ struct HfCandidateCreator2Prong { PROCESS_SWITCH(HfCandidateCreator2Prong, processNoPvRefitWithDCAFitterNCentFT0M, "Run candidate creator using DCA fitter w/o PV refit and w/ centrality selection FT0M", false); /// @brief process function using KFParticle package w/ PV refit and w/ centrality selection on FT0M - void processPvRefitWithKFParticleCentFT0M(soa::Join const& collisions, + void processPvRefitWithKFParticleCentFT0M(soa::Join const& collisions, soa::Join const& rowsTrackIndexProng2, TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -657,7 +658,7 @@ struct HfCandidateCreator2Prong { PROCESS_SWITCH(HfCandidateCreator2Prong, processPvRefitWithKFParticleCentFT0M, "Run candidate creator using KFParticle package w/ PV refit and w/ centrality selection on FT0M", false); /// @brief process function using KFParticle package w/o PV refit and w/o centrality selections - void processNoPvRefitWithKFParticleCentFT0M(soa::Join const& collisions, + void processNoPvRefitWithKFParticleCentFT0M(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexProng2, TracksWCovExtraPidPiKa const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -673,7 +674,7 @@ struct HfCandidateCreator2Prong { ///////////////////////////////////////////// /// @brief process function using DCA fitter w/ PV refit and w/ centrality selection on UPC - void processPvRefitWithDCAFitterNUpc(soa::Join const& collisions, + void processPvRefitWithDCAFitterNUpc(soa::Join const& collisions, soa::Join const& rowsTrackIndexProng2, TracksWCovExtraPidPiKa const& tracks, aod::BcFullInfos const& bcWithTimeStamps, @@ -687,7 +688,7 @@ struct HfCandidateCreator2Prong { PROCESS_SWITCH(HfCandidateCreator2Prong, processPvRefitWithDCAFitterNUpc, "Run candidate creator using DCA fitter w/ PV refit and w/ centrality selection on UltraPeripheral Collision", false); /// @brief process function using DCA fitter w/o PV refit and w/ centrality selection UPC - void processNoPvRefitWithDCAFitterNUpc(soa::Join const& collisions, + void processNoPvRefitWithDCAFitterNUpc(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexProng2, TracksWCovExtraPidPiKa const& tracks, aod::BcFullInfos const& bcWithTimeStamps, @@ -701,7 +702,7 @@ struct HfCandidateCreator2Prong { PROCESS_SWITCH(HfCandidateCreator2Prong, processNoPvRefitWithDCAFitterNUpc, "Run candidate creator using DCA fitter w/o PV refit and w/ centrality selection UltraPeripheral Collision", false); /// @brief process function using KFParticle package w/ PV refit and w/ centrality selection on UPC - void processPvRefitWithKFParticleUpc(soa::Join const& collisions, + void processPvRefitWithKFParticleUpc(soa::Join const& collisions, soa::Join const& rowsTrackIndexProng2, TracksWCovExtraPidPiKa const& tracks, aod::BcFullInfos const& bcWithTimeStamps, @@ -715,7 +716,7 @@ struct HfCandidateCreator2Prong { PROCESS_SWITCH(HfCandidateCreator2Prong, processPvRefitWithKFParticleUpc, "Run candidate creator using KFParticle package w/ PV refit and w/ centrality selection on UltraPeripheral Collision", false); /// @brief process function using KFParticle package w/o PV refit and w/o centrality selections on UPC - void processNoPvRefitWithKFParticleUpc(soa::Join const& collisions, + void processNoPvRefitWithKFParticleUpc(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexProng2, TracksWCovExtraPidPiKa const& tracks, aod::BcFullInfos const& bcWithTimeStamps, @@ -735,7 +736,7 @@ struct HfCandidateCreator2Prong { /////////////////////////////////////////////////////////// /// @brief process function to monitor collisions - no centrality - void processCollisions(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + void processCollisions(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { @@ -754,7 +755,7 @@ struct HfCandidateCreator2Prong { PROCESS_SWITCH(HfCandidateCreator2Prong, processCollisions, "Collision monitoring - no centrality", true); /// @brief process function to monitor collisions - FT0C centrality - void processCollisionsCentFT0C(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + void processCollisionsCentFT0C(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { @@ -773,7 +774,7 @@ struct HfCandidateCreator2Prong { PROCESS_SWITCH(HfCandidateCreator2Prong, processCollisionsCentFT0C, "Collision monitoring - FT0C centrality", false); /// @brief process function to monitor collisions - FT0M centrality - void processCollisionsCentFT0M(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + void processCollisionsCentFT0M(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { @@ -792,7 +793,7 @@ struct HfCandidateCreator2Prong { PROCESS_SWITCH(HfCandidateCreator2Prong, processCollisionsCentFT0M, "Collision monitoring - FT0M centrality", false); /// @brief process function to monitor collisions - UPC collision - void processCollisionsUpc(soa::Join const& collisions, + void processCollisionsUpc(soa::Join const& collisions, aod::BcFullInfos const& bcs, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0as*/, @@ -830,9 +831,9 @@ struct HfCandidateCreator2ProngExpressions { HfEventSelectionMc hfEvSelMc; // mc event selection and monitoring - using McCollisionsNoCents = soa::Join; - using McCollisionsFT0Cs = soa::Join; - using McCollisionsFT0Ms = soa::Join; + using McCollisionsNoCents = soa::Join; + using McCollisionsFT0Cs = soa::Join; + using McCollisionsFT0Ms = soa::Join; using McCollisionsCentFT0Ms = soa::Join; using BCsInfo = soa::Join; diff --git a/PWGHF/TableProducer/candidateCreator3Prong.cxx b/PWGHF/TableProducer/candidateCreator3Prong.cxx index e83396da8ab..1091c00a0a2 100644 --- a/PWGHF/TableProducer/candidateCreator3Prong.cxx +++ b/PWGHF/TableProducer/candidateCreator3Prong.cxx @@ -38,6 +38,7 @@ #include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Tools/KFparticle/KFUtilities.h" #include @@ -715,7 +716,7 @@ struct HfCandidateCreator3Prong { /////////////////////////////////// /// @brief process function using DCA fitter w/ PV refit and w/o centrality selections - void processPvRefitWithDCAFitterN(soa::Join const& collisions, + void processPvRefitWithDCAFitterN(soa::Join const& collisions, FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, TracksWCovExtraPidPiKaPrLightNuclei const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -725,7 +726,7 @@ struct HfCandidateCreator3Prong { PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitWithDCAFitterN, "Run candidate creator using DCA fitter with PV refit and w/o centrality selections", false); /// @brief process function using DCA fitter w/o PV refit and w/o centrality selections - void processNoPvRefitWithDCAFitterN(soa::Join const& collisions, + void processNoPvRefitWithDCAFitterN(soa::Join const& collisions, FilteredHf3Prongs const& rowsTrackIndexProng3, TracksWCovExtraPidPiKaPrLightNuclei const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -735,7 +736,7 @@ struct HfCandidateCreator3Prong { PROCESS_SWITCH(HfCandidateCreator3Prong, processNoPvRefitWithDCAFitterN, "Run candidate creator using DCA fitter without PV refit and w/o centrality selections", true); /// @brief process function using KFParticle package w/ PV refit and w/o centrality selections - void processPvRefitWithKFParticle(soa::Join const& collisions, + void processPvRefitWithKFParticle(soa::Join const& collisions, FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, TracksWCovExtraPidPiKaPrLightNuclei const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -745,7 +746,7 @@ struct HfCandidateCreator3Prong { PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitWithKFParticle, "Run candidate creator using KFParticle package with PV refit and w/o centrality selections", false); /// @brief process function using KFParticle package w/o PV refit and w/o centrality selections - void processNoPvRefitWithKFParticle(soa::Join const& collisions, + void processNoPvRefitWithKFParticle(soa::Join const& collisions, FilteredHf3Prongs const& rowsTrackIndexProng3, TracksWCovExtraPidPiKaPrLightNuclei const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -761,7 +762,7 @@ struct HfCandidateCreator3Prong { ///////////////////////////////////////////// /// @brief process function using DCA fitter w/ PV refit and w/ centrality selection on FT0C - void processPvRefitWithDCAFitterNCentFT0C(soa::Join const& collisions, + void processPvRefitWithDCAFitterNCentFT0C(soa::Join const& collisions, FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, TracksWCovExtraPidPiKaPrLightNuclei const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -771,7 +772,7 @@ struct HfCandidateCreator3Prong { PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitWithDCAFitterNCentFT0C, "Run candidate creator using DCA fitter with PV refit and w/ centrality selection on FT0C", false); /// @brief process function using DCA fitter w/o PV refit and w/ centrality selection on FT0C - void processNoPvRefitWithDCAFitterNCentFT0C(soa::Join const& collisions, + void processNoPvRefitWithDCAFitterNCentFT0C(soa::Join const& collisions, FilteredHf3Prongs const& rowsTrackIndexProng3, TracksWCovExtraPidPiKaPrLightNuclei const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -781,7 +782,7 @@ struct HfCandidateCreator3Prong { PROCESS_SWITCH(HfCandidateCreator3Prong, processNoPvRefitWithDCAFitterNCentFT0C, "Run candidate creator using DCA fitter without PV refit and w/ centrality selection on FT0C", false); /// @brief process function using KFParticle package w/ PV refit and w/ centrality selection on FT0C - void processPvRefitWithKFParticleCentFT0C(soa::Join const& collisions, + void processPvRefitWithKFParticleCentFT0C(soa::Join const& collisions, FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, TracksWCovExtraPidPiKaPrLightNuclei const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -791,7 +792,7 @@ struct HfCandidateCreator3Prong { PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitWithKFParticleCentFT0C, "Run candidate creator using KFParticle package with PV refit and w/ centrality selection on FT0C", false); /// @brief process function using KFParticle package w/o PV refit and w/ centrality selection on FT0C - void processNoPvRefitWithKFParticleCentFT0C(soa::Join const& collisions, + void processNoPvRefitWithKFParticleCentFT0C(soa::Join const& collisions, FilteredHf3Prongs const& rowsTrackIndexProng3, TracksWCovExtraPidPiKaPrLightNuclei const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -807,7 +808,7 @@ struct HfCandidateCreator3Prong { ///////////////////////////////////////////// /// @brief process function using DCA fitter w/ PV refit and w/ centrality selection on FT0M - void processPvRefitWithDCAFitterNCentFT0M(soa::Join const& collisions, + void processPvRefitWithDCAFitterNCentFT0M(soa::Join const& collisions, FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, TracksWCovExtraPidPiKaPrLightNuclei const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -817,7 +818,7 @@ struct HfCandidateCreator3Prong { PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitWithDCAFitterNCentFT0M, "Run candidate creator using DCA fitter with PV refit and w/ centrality selection on FT0M", false); /// @brief process function using DCA fitter w/o PV refit and w/ centrality selection on FT0M - void processNoPvRefitWithDCAFitterNCentFT0M(soa::Join const& collisions, + void processNoPvRefitWithDCAFitterNCentFT0M(soa::Join const& collisions, FilteredHf3Prongs const& rowsTrackIndexProng3, TracksWCovExtraPidPiKaPrLightNuclei const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -827,7 +828,7 @@ struct HfCandidateCreator3Prong { PROCESS_SWITCH(HfCandidateCreator3Prong, processNoPvRefitWithDCAFitterNCentFT0M, "Run candidate creator using DCA fitter without PV refit and w/ centrality selection on FT0M", false); /// @brief process function using KFParticle package w/ PV refit and w/ centrality selection on FT0M - void processPvRefitWithKFParticleCentFT0M(soa::Join const& collisions, + void processPvRefitWithKFParticleCentFT0M(soa::Join const& collisions, FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, TracksWCovExtraPidPiKaPrLightNuclei const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -837,7 +838,7 @@ struct HfCandidateCreator3Prong { PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitWithKFParticleCentFT0M, "Run candidate creator using KFParticle package with PV refit and w/ centrality selection on FT0M", false); /// @brief process function using KFParticle package w/o PV refit and w/ centrality selection on FT0M - void processNoPvRefitWithKFParticleCentFT0M(soa::Join const& collisions, + void processNoPvRefitWithKFParticleCentFT0M(soa::Join const& collisions, FilteredHf3Prongs const& rowsTrackIndexProng3, TracksWCovExtraPidPiKaPrLightNuclei const& tracks, aod::BCsWithTimestamps const& bcWithTimeStamps) @@ -853,7 +854,7 @@ struct HfCandidateCreator3Prong { ///////////////////////////////////////////// /// @brief process function using DCA fitter w/ PV refit and w/ centrality selection on UPC - void processPvRefitWithDCAFitterNUpc(soa::Join const& collisions, + void processPvRefitWithDCAFitterNUpc(soa::Join const& collisions, FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, TracksWCovExtraPidPiKaPrLightNuclei const& tracks, aod::BcFullInfos const& bcWithTimeStamps, @@ -867,7 +868,7 @@ struct HfCandidateCreator3Prong { PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitWithDCAFitterNUpc, "Run candidate creator using DCA fitter with PV refit and w/ centrality selection on UPC", false); /// @brief process function using DCA fitter w/o PV refit and w/ centrality selection on UPC - void processNoPvRefitWithDCAFitterNUpc(soa::Join const& collisions, + void processNoPvRefitWithDCAFitterNUpc(soa::Join const& collisions, FilteredHf3Prongs const& rowsTrackIndexProng3, TracksWCovExtraPidPiKaPrLightNuclei const& tracks, aod::BcFullInfos const& bcWithTimeStamps, @@ -881,7 +882,7 @@ struct HfCandidateCreator3Prong { PROCESS_SWITCH(HfCandidateCreator3Prong, processNoPvRefitWithDCAFitterNUpc, "Run candidate creator using DCA fitter without PV refit and w/ centrality selection on UPC", false); /// @brief process function using KFParticle package w/ PV refit and w/ centrality selection on UPC - void processPvRefitWithKFParticleUpc(soa::Join const& collisions, + void processPvRefitWithKFParticleUpc(soa::Join const& collisions, FilteredPvRefitHf3Prongs const& rowsTrackIndexProng3, TracksWCovExtraPidPiKaPrLightNuclei const& tracks, aod::BcFullInfos const& bcWithTimeStamps, @@ -895,7 +896,7 @@ struct HfCandidateCreator3Prong { PROCESS_SWITCH(HfCandidateCreator3Prong, processPvRefitWithKFParticleUpc, "Run candidate creator using KFParticle package with PV refit and w/ centrality selection on UPC", false); /// @brief process function using KFParticle package w/o PV refit and w/ centrality selection on UPC - void processNoPvRefitWithKFParticleUpc(soa::Join const& collisions, + void processNoPvRefitWithKFParticleUpc(soa::Join const& collisions, FilteredHf3Prongs const& rowsTrackIndexProng3, TracksWCovExtraPidPiKaPrLightNuclei const& tracks, aod::BcFullInfos const& bcWithTimeStamps, @@ -915,7 +916,7 @@ struct HfCandidateCreator3Prong { /////////////////////////////////////////////////////////// /// @brief process function to monitor collisions - no centrality - void processCollisions(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + void processCollisions(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { @@ -934,7 +935,7 @@ struct HfCandidateCreator3Prong { PROCESS_SWITCH(HfCandidateCreator3Prong, processCollisions, "Collision monitoring - no centrality", true); /// @brief process function to monitor collisions - FT0C centrality - void processCollisionsCentFT0C(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + void processCollisionsCentFT0C(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { @@ -953,7 +954,7 @@ struct HfCandidateCreator3Prong { PROCESS_SWITCH(HfCandidateCreator3Prong, processCollisionsCentFT0C, "Collision monitoring - FT0C centrality", false); /// @brief process function to monitor collisions - FT0M centrality - void processCollisionsCentFT0M(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + void processCollisionsCentFT0M(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { @@ -972,7 +973,7 @@ struct HfCandidateCreator3Prong { PROCESS_SWITCH(HfCandidateCreator3Prong, processCollisionsCentFT0M, "Collision monitoring - FT0M centrality", false); /// @brief process function to monitor collisions - UPC - void processCollisionsUpc(soa::Join const& collisions, + void processCollisionsUpc(soa::Join const& collisions, aod::BcFullInfos const& bcs, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0as*/, @@ -1014,9 +1015,9 @@ struct HfCandidateCreator3ProngExpressions { HfEventSelectionMc hfEvSelMc; // mc event selection and monitoring using BCsInfo = soa::Join; - using McCollisionsNoCents = soa::Join; - using McCollisionsFT0Cs = soa::Join; - using McCollisionsFT0Ms = soa::Join; + using McCollisionsNoCents = soa::Join; + using McCollisionsFT0Cs = soa::Join; + using McCollisionsFT0Ms = soa::Join; using McCollisionsCentFT0Ms = soa::Join; Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; diff --git a/PWGHF/TableProducer/candidateCreatorCascade.cxx b/PWGHF/TableProducer/candidateCreatorCascade.cxx index fe9c2c3a57c..d5450ffa27e 100644 --- a/PWGHF/TableProducer/candidateCreatorCascade.cxx +++ b/PWGHF/TableProducer/candidateCreatorCascade.cxx @@ -30,6 +30,7 @@ #include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include #include @@ -323,7 +324,7 @@ struct HfCandidateCreatorCascade { } /// @brief process function w/o centrality selections - void processNoCent(soa::Join const& collisions, + void processNoCent(soa::Join const& collisions, aod::HfCascades const& rowsTrackIndexCasc, aod::V0sLinked const& v0sLinked, V0full const& v0Full, @@ -335,7 +336,7 @@ struct HfCandidateCreatorCascade { PROCESS_SWITCH(HfCandidateCreatorCascade, processNoCent, " Run candidate creator w/o centrality selections", true); /// @brief process function w/ centrality selection on FT0C - void processCentFT0C(soa::Join const& collisions, + void processCentFT0C(soa::Join const& collisions, aod::HfCascades const& rowsTrackIndexCasc, aod::V0sLinked const& v0sLinked, V0full const& v0Full, @@ -347,7 +348,7 @@ struct HfCandidateCreatorCascade { PROCESS_SWITCH(HfCandidateCreatorCascade, processCentFT0C, " Run candidate creator w/ centrality selection on FT0C", false); /// @brief process function w/ centrality selection on FT0M - void processCentFT0M(soa::Join const& collisions, + void processCentFT0M(soa::Join const& collisions, aod::HfCascades const& rowsTrackIndexCasc, aod::V0sLinked const& v0sLinked, V0full const& v0Full, @@ -365,7 +366,7 @@ struct HfCandidateCreatorCascade { /////////////////////////////////////////////////////////// /// @brief process function to monitor collisions - no centrality - void processCollisions(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + void processCollisions(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { @@ -384,7 +385,7 @@ struct HfCandidateCreatorCascade { PROCESS_SWITCH(HfCandidateCreatorCascade, processCollisions, "Collision monitoring - no centrality", true); /// @brief process function to monitor collisions - FT0C centrality - void processCollisionsCentFT0C(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + void processCollisionsCentFT0C(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { @@ -403,7 +404,7 @@ struct HfCandidateCreatorCascade { PROCESS_SWITCH(HfCandidateCreatorCascade, processCollisionsCentFT0C, "Collision monitoring - FT0C centrality", false); /// @brief process function to monitor collisions - FT0M centrality - void processCollisionsCentFT0M(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + void processCollisionsCentFT0M(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { @@ -435,9 +436,9 @@ struct HfCandidateCreatorCascadeMc { using MyTracksWMc = soa::Join; using BCsInfo = soa::Join; - using McCollisionsNoCents = soa::Join; - using McCollisionsFT0Cs = soa::Join; - using McCollisionsFT0Ms = soa::Join; + using McCollisionsNoCents = soa::Join; + using McCollisionsFT0Cs = soa::Join; + using McCollisionsFT0Ms = soa::Join; using McCollisionsCentFT0Ms = soa::Join; Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; diff --git a/PWGHF/TableProducer/candidateCreatorDstar.cxx b/PWGHF/TableProducer/candidateCreatorDstar.cxx index 6e4701bc63b..b6cfbd8da88 100644 --- a/PWGHF/TableProducer/candidateCreatorDstar.cxx +++ b/PWGHF/TableProducer/candidateCreatorDstar.cxx @@ -31,6 +31,7 @@ #include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include #include @@ -403,7 +404,7 @@ struct HfCandidateCreatorDstar { /////////////////////////////////// /// @brief process function w/ PV refit and w/o centrality selections - void processPvRefit(soa::Join const& collisions, + void processPvRefit(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexD0, aod::HfDstarsWithPvRefitInfo const& rowsTrackIndexDstar, TracksWCovExtraPidPiKa const& tracks, @@ -414,7 +415,7 @@ struct HfCandidateCreatorDstar { PROCESS_SWITCH(HfCandidateCreatorDstar, processPvRefit, " Run candidate creator with PV refit and w/o centrality selections", false); /// @brief process function w/o PV refit and w/o centrality selections - void processNoPvRefit(soa::Join const& collisions, + void processNoPvRefit(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexD0, aod::HfDstars const& rowsTrackIndexDstar, TracksWCovExtraPidPiKa const& tracks, @@ -431,7 +432,7 @@ struct HfCandidateCreatorDstar { ///////////////////////////////////////////// /// @brief process function w/ PV refit and w/ centrality selection on FT0C - void processPvRefitCentFT0C(soa::Join const& collisions, + void processPvRefitCentFT0C(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexD0, aod::HfDstarsWithPvRefitInfo const& rowsTrackIndexDstar, TracksWCovExtraPidPiKa const& tracks, @@ -442,7 +443,7 @@ struct HfCandidateCreatorDstar { PROCESS_SWITCH(HfCandidateCreatorDstar, processPvRefitCentFT0C, " Run candidate creator with PV refit nad w/ centrality selection on FT0C", false); /// @brief process function w/o PV refit and w/ centrality selection on FT0C - void processNoPvRefitCentFT0C(soa::Join const& collisions, + void processNoPvRefitCentFT0C(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexD0, aod::HfDstars const& rowsTrackIndexDstar, TracksWCovExtraPidPiKa const& tracks, @@ -459,7 +460,7 @@ struct HfCandidateCreatorDstar { ///////////////////////////////////////////// /// @brief process function w/ PV refit and w/ centrality selection on FT0M - void processPvRefitCentFT0M(soa::Join const& collisions, + void processPvRefitCentFT0M(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexD0, aod::HfDstarsWithPvRefitInfo const& rowsTrackIndexDstar, TracksWCovExtraPidPiKa const& tracks, @@ -470,7 +471,7 @@ struct HfCandidateCreatorDstar { PROCESS_SWITCH(HfCandidateCreatorDstar, processPvRefitCentFT0M, " Run candidate creator with PV refit nad w/ centrality selection on FT0M", false); /// @brief process function w/o PV refit and w/ centrality selection on FT0M - void processNoPvRefitCentFT0M(soa::Join const& collisions, + void processNoPvRefitCentFT0M(soa::Join const& collisions, aod::Hf2Prongs const& rowsTrackIndexD0, aod::HfDstars const& rowsTrackIndexDstar, TracksWCovExtraPidPiKa const& tracks, @@ -487,7 +488,7 @@ struct HfCandidateCreatorDstar { /////////////////////////////////////////////////////////// /// @brief process function to monitor collisions - no centrality - void processCollisions(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + void processCollisions(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { @@ -506,7 +507,7 @@ struct HfCandidateCreatorDstar { PROCESS_SWITCH(HfCandidateCreatorDstar, processCollisions, "Collision monitoring - no centrality", true); /// @brief process function to monitor collisions - FT0C centrality - void processCollisionsCentFT0C(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + void processCollisionsCentFT0C(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { @@ -525,7 +526,7 @@ struct HfCandidateCreatorDstar { PROCESS_SWITCH(HfCandidateCreatorDstar, processCollisionsCentFT0C, "Collision monitoring - FT0C centrality", false); /// @brief process function to monitor collisions - FT0M centrality - void processCollisionsCentFT0M(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + void processCollisionsCentFT0M(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { @@ -555,9 +556,9 @@ struct HfCandidateCreatorDstarExpressions { Configurable matchKinkedDecayTopology{"matchKinkedDecayTopology", false, "Match also candidates with tracks that decay with kinked topology"}; Configurable matchInteractionsWithMaterial{"matchInteractionsWithMaterial", false, "Match also candidates with tracks that interact with material"}; - using McCollisionsNoCents = soa::Join; - using McCollisionsFT0Cs = soa::Join; - using McCollisionsFT0Ms = soa::Join; + using McCollisionsNoCents = soa::Join; + using McCollisionsFT0Cs = soa::Join; + using McCollisionsFT0Ms = soa::Join; using McCollisionsCentFT0Ms = soa::Join; using BCsInfo = soa::Join; diff --git a/PWGHF/TableProducer/candidateCreatorSigmac0plusplus.cxx b/PWGHF/TableProducer/candidateCreatorSigmac0plusplus.cxx index 072d7dcf530..4d02957459b 100644 --- a/PWGHF/TableProducer/candidateCreatorSigmac0plusplus.cxx +++ b/PWGHF/TableProducer/candidateCreatorSigmac0plusplus.cxx @@ -33,6 +33,7 @@ #include "Common/Core/trackUtilities.h" #include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include // for dca recalculation #include @@ -424,7 +425,7 @@ struct HfCandidateSigmac0plusplusMc { using BCsInfo = soa::Join; using LambdacMc = soa::Join; using McParticlesLcGenMatch = soa::Join; // including response of particle matching to MC from candidate-creator-3-prong - using McCollisionsNoCents = soa::Join; + using McCollisionsNoCents = soa::Join; PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; diff --git a/PWGHF/TableProducer/candidateCreatorXic0Omegac0.cxx b/PWGHF/TableProducer/candidateCreatorXic0Omegac0.cxx index 394d9628e4c..89185af0de5 100644 --- a/PWGHF/TableProducer/candidateCreatorXic0Omegac0.cxx +++ b/PWGHF/TableProducer/candidateCreatorXic0Omegac0.cxx @@ -37,6 +37,7 @@ #include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Tools/KFparticle/KFUtilities.h" #include @@ -2024,7 +2025,7 @@ struct HfCandidateCreatorXic0Omegac0 { } /// @brief process function w/o centrality selections - void processNoCentToXiPi(soa::Join const& collisions, + void processNoCentToXiPi(soa::Join const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, TracksWCovDca const& tracks, MyLFTracksWCov const& lfTracks, @@ -2036,7 +2037,7 @@ struct HfCandidateCreatorXic0Omegac0 { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processNoCentToXiPi, "Run candidate creator w/o centrality selections for xi pi decay channel", true); - void processNoCentToXiPiTraCasc(soa::Join const& collisions, + void processNoCentToXiPiTraCasc(soa::Join const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, TracksWCovDca const& tracks, MyLFTracksWCov const& lfTracks, @@ -2048,7 +2049,7 @@ struct HfCandidateCreatorXic0Omegac0 { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processNoCentToXiPiTraCasc, "Run candidate creator w/o centrality selections for xi pi decay channel with tracked cascades", false); - void processNoCentToOmegaPi(soa::Join const& collisions, + void processNoCentToOmegaPi(soa::Join const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, TracksWCovDca const& tracks, MyLFTracksWCov const& lfTracks, @@ -2060,7 +2061,7 @@ struct HfCandidateCreatorXic0Omegac0 { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processNoCentToOmegaPi, "Run candidate creator w/o centrality selections for omega pi decay channel", false); - void processNoCentOmegacToOmegaPiWithKFParticle(soa::Join const& collisions, + void processNoCentOmegacToOmegaPiWithKFParticle(soa::Join const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, MyKfTracksIU const& tracksIU, MyKfTracks const& tracks, @@ -2072,7 +2073,7 @@ struct HfCandidateCreatorXic0Omegac0 { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processNoCentOmegacToOmegaPiWithKFParticle, "Run candidate creator w/o centrality selections for Omegac0 To omega pi decay channel using KFParticle", false); - void processNoCentOmegac0Xic0ToOmegaKaCreatorWithKFParticle(soa::Join const& collisions, + void processNoCentOmegac0Xic0ToOmegaKaCreatorWithKFParticle(soa::Join const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, MyKfTracksIU const& tracksIU, MyKfTracks const& tracks, @@ -2084,7 +2085,7 @@ struct HfCandidateCreatorXic0Omegac0 { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processNoCentOmegac0Xic0ToOmegaKaCreatorWithKFParticle, "Run candidate creator w/o centrality selections for Omegac0 To omega ka decay channel using KFParticle", false); - void processNoCentXicToXiPiWithKFParticle(soa::Join const& collisions, + void processNoCentXicToXiPiWithKFParticle(soa::Join const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, MyKfTracksIU const& tracksIU, MyKfTracks const& tracks, @@ -2096,7 +2097,7 @@ struct HfCandidateCreatorXic0Omegac0 { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processNoCentXicToXiPiWithKFParticle, "Run candidate creator w/o centrality selections for Xic0 To Xi pi decay channel using KFParticle", false); - void processNoCentToOmegaK(soa::Join const& collisions, + void processNoCentToOmegaK(soa::Join const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, TracksWCovDca const& tracks, MyLFTracksWCov const& lfTracks, @@ -2109,7 +2110,7 @@ struct HfCandidateCreatorXic0Omegac0 { PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processNoCentToOmegaK, "Run candidate creator w/o centrality selections for omega K decay channel", false); /// @brief process function w/ FT0C centrality selections - void processCentFT0CToXiPi(soa::Join const& collisions, + void processCentFT0CToXiPi(soa::Join const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, TracksWCovDca const& tracks, MyLFTracksWCov const& lfTracks, @@ -2121,7 +2122,7 @@ struct HfCandidateCreatorXic0Omegac0 { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0CToXiPi, "Run candidate creator w/ centrality selection on FT0C for xi pi channel", false); - void processCentFT0CToOmegaPi(soa::Join const& collisions, + void processCentFT0CToOmegaPi(soa::Join const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, TracksWCovDca const& tracks, MyLFTracksWCov const& lfTracks, @@ -2133,7 +2134,7 @@ struct HfCandidateCreatorXic0Omegac0 { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0CToOmegaPi, "Run candidate creator w/ centrality selection on FT0C for omega pi channel", false); - void processCentFT0COmegacToOmegaPiWithKFParticle(soa::Join const& collisions, + void processCentFT0COmegacToOmegaPiWithKFParticle(soa::Join const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, MyKfTracksIU const& tracksIU, MyKfTracks const& tracks, @@ -2145,7 +2146,7 @@ struct HfCandidateCreatorXic0Omegac0 { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0COmegacToOmegaPiWithKFParticle, "Run candidate creator w/o centrality selections for Omegac0 To omega pi decay channel using KFParticle", false); - void processCentFT0COmegac0Xic0ToOmegaKaCreatorWithKFParticle(soa::Join const& collisions, + void processCentFT0COmegac0Xic0ToOmegaKaCreatorWithKFParticle(soa::Join const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, MyKfTracksIU const& tracksIU, MyKfTracks const& tracks, @@ -2157,7 +2158,7 @@ struct HfCandidateCreatorXic0Omegac0 { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0COmegac0Xic0ToOmegaKaCreatorWithKFParticle, "Run candidate creator w/o centrality selections for Omegac0 To omega ka decay channel using KFParticle", false); - void processCentFT0CXicToXiPiWithKFParticle(soa::Join const& collisions, + void processCentFT0CXicToXiPiWithKFParticle(soa::Join const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, MyKfTracksIU const& tracksIU, MyKfTracks const& tracks, @@ -2169,7 +2170,7 @@ struct HfCandidateCreatorXic0Omegac0 { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0CXicToXiPiWithKFParticle, "Run candidate creator w FT0C centrality selections for Xic0 To Xi pi decay channel using KFParticle", false); - void processCentFT0CToOmegaK(soa::Join const& collisions, + void processCentFT0CToOmegaK(soa::Join const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, TracksWCovDca const& tracks, MyLFTracksWCov const& lfTracks, @@ -2182,7 +2183,7 @@ struct HfCandidateCreatorXic0Omegac0 { PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0CToOmegaK, "Run candidate creator w/ centrality selection on FT0C for omega K channel", false); /// @brief process function w/ FT0M centrality selections - void processCentFT0MToXiPi(soa::Join const& collisions, + void processCentFT0MToXiPi(soa::Join const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, TracksWCovDca const& tracks, MyLFTracksWCov const& lfTracks, @@ -2194,7 +2195,7 @@ struct HfCandidateCreatorXic0Omegac0 { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0MToXiPi, "Run candidate creator w/ centrality selection on FT0M for xi pi channel", false); - void processCentFT0MToOmegaPi(soa::Join const& collisions, + void processCentFT0MToOmegaPi(soa::Join const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, TracksWCovDca const& tracks, MyLFTracksWCov const& lfTracks, @@ -2206,7 +2207,7 @@ struct HfCandidateCreatorXic0Omegac0 { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0MToOmegaPi, "Run candidate creator w/ centrality selection on FT0M for omega pi channel", false); - void processCentFT0MOmegacToOmegaPiWithKFParticle(soa::Join const& collisions, + void processCentFT0MOmegacToOmegaPiWithKFParticle(soa::Join const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, MyKfTracksIU const& tracksIU, MyKfTracks const& tracks, @@ -2218,7 +2219,7 @@ struct HfCandidateCreatorXic0Omegac0 { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0MOmegacToOmegaPiWithKFParticle, "Run candidate creator w/o centrality selections for Omegac0 To omega pi decay channel using KFParticle", false); - void processCentFT0MOmegac0Xic0ToOmegaKaCreatorWithKFParticle(soa::Join const& collisions, + void processCentFT0MOmegac0Xic0ToOmegaKaCreatorWithKFParticle(soa::Join const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, MyKfTracksIU const& tracksIU, MyKfTracks const& tracks, @@ -2230,7 +2231,7 @@ struct HfCandidateCreatorXic0Omegac0 { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0MOmegac0Xic0ToOmegaKaCreatorWithKFParticle, "Run candidate creator w/o centrality selections for Omegac0 To omega ka decay channel using KFParticle", false); - void processCentFT0MXicToXiPiWithKFParticle(soa::Join const& collisions, + void processCentFT0MXicToXiPiWithKFParticle(soa::Join const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, MyKfTracksIU const& tracksIU, MyKfTracks const& tracks, @@ -2242,7 +2243,7 @@ struct HfCandidateCreatorXic0Omegac0 { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCentFT0MXicToXiPiWithKFParticle, "Run candidate creator w FT0M centrality selections for Xic0 To Xi pi decay channel using KFParticle", false); - void processCentFT0MToOmegaK(soa::Join const& collisions, + void processCentFT0MToOmegaK(soa::Join const& collisions, aod::BCsWithTimestamps const& bcWithTimeStamps, TracksWCovDca const& tracks, MyLFTracksWCov const& lfTracks, @@ -2261,7 +2262,7 @@ struct HfCandidateCreatorXic0Omegac0 { /////////////////////////////////////////////////////////// /// @brief process function to monitor collisions - no centrality - void processCollisions(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + void processCollisions(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { @@ -2280,7 +2281,7 @@ struct HfCandidateCreatorXic0Omegac0 { PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCollisions, "Collision monitoring - no centrality", true); /// @brief process function to monitor collisions - FT0C centrality - void processCollisionsCentFT0C(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + void processCollisionsCentFT0C(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { @@ -2299,7 +2300,7 @@ struct HfCandidateCreatorXic0Omegac0 { PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0, processCollisionsCentFT0C, "Collision monitoring - FT0C centrality", false); /// @brief process function to monitor collisions - FT0M centrality - void processCollisionsCentFT0M(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) + void processCollisionsCentFT0M(soa::Join const& collisions, aod::BCsWithTimestamps const& /*bcWithTimeStamps*/) { /// loop over collisions for (const auto& collision : collisions) { @@ -2335,9 +2336,9 @@ struct HfCandidateCreatorXic0Omegac0Mc { Configurable acceptTrackIntWithMaterial{"acceptTrackIntWithMaterial", false, " switch to accept candidates with final (i.e. p, K, pi) daughter tracks interacting with material"}; using MyTracksWMc = soa::Join; - using McCollisionsNoCents = soa::Join; - using McCollisionsFT0Cs = soa::Join; - using McCollisionsFT0Ms = soa::Join; + using McCollisionsNoCents = soa::Join; + using McCollisionsFT0Cs = soa::Join; + using McCollisionsFT0Ms = soa::Join; using McCollisionsCentFT0Ms = soa::Join; using BCsInfo = soa::Join; diff --git a/PWGHF/TableProducer/candidateCreatorXic0Omegac0Qa.cxx b/PWGHF/TableProducer/candidateCreatorXic0Omegac0Qa.cxx index fff93b7f5fe..6f37217b7f6 100644 --- a/PWGHF/TableProducer/candidateCreatorXic0Omegac0Qa.cxx +++ b/PWGHF/TableProducer/candidateCreatorXic0Omegac0Qa.cxx @@ -34,6 +34,7 @@ #include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Tools/KFparticle/KFUtilities.h" #include @@ -248,7 +249,7 @@ struct HfCandidateCreatorXic0Omegac0Qa { VertexFit }; // Table aliases - using SelectedCollisions = soa::Join; + using SelectedCollisions = soa::Join; using TracksWCovIU = soa::Join; using TracksWCovDcaExtraPidPrPiKa = soa::Join; using TracksWCovExtraPidIU = soa::Join; @@ -1391,7 +1392,7 @@ struct HfCandidateCreatorXic0Omegac0Qa { PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Qa, processToXiPiWithDCAFitterNoCentWithTrackedCasc, "Charm candidte reconstruction with Xi Pi via DcaFitter method with tracked cascade, no centrality", false); #endif - void processToXiPiWithDCAFitterCentFT0C(soa::Join const& collisions, + void processToXiPiWithDCAFitterCentFT0C(soa::Join const& collisions, aod::HfCascLf2Prongs const& candidates, aod::Cascades const& cascades, aod::V0s const& v0s, @@ -1403,7 +1404,7 @@ struct HfCandidateCreatorXic0Omegac0Qa { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Qa, processToXiPiWithDCAFitterCentFT0C, "Charm candidate reconstruction with Xi Pi via DcaFitter method, centrality selection on FT0C", false); - void processToXiPiWithDCAFitterCentFT0M(soa::Join const& collisions, + void processToXiPiWithDCAFitterCentFT0M(soa::Join const& collisions, aod::HfCascLf2Prongs const& candidates, aod::Cascades const& cascades, aod::V0s const& v0s, @@ -1430,7 +1431,7 @@ struct HfCandidateCreatorXic0Omegac0Qa { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Qa, processToOmegaPiWithDCAFitterNoCent, "Charm candidte reconstruction with Omega Pi via DcaFitter method, no centrality", false); - void processToOmegaPiWithDCAFitterCentFT0C(soa::Join const& collisions, + void processToOmegaPiWithDCAFitterCentFT0C(soa::Join const& collisions, aod::HfCascLf2Prongs const& candidates, aod::Cascades const& cascades, aod::V0s const& v0s, @@ -1442,7 +1443,7 @@ struct HfCandidateCreatorXic0Omegac0Qa { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Qa, processToOmegaPiWithDCAFitterCentFT0C, "Charm candidate reconstruction with Omega Pi via DcaFitter method, centrality selection on FT0C", false); - void processToOmegaPiWithDCAFitterCentFT0M(soa::Join const& collisions, + void processToOmegaPiWithDCAFitterCentFT0M(soa::Join const& collisions, aod::HfCascLf2Prongs const& candidates, aod::Cascades const& cascades, aod::V0s const& v0s, @@ -1469,7 +1470,7 @@ struct HfCandidateCreatorXic0Omegac0Qa { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Qa, processToOmegaKaWithDCAFitterNoCent, "Charm candidte reconstruction with Omega Ka via DcaFitter method, no centrality", false); - void processToOmegaKaWithDCAFitterCentFT0C(soa::Join const& collisions, + void processToOmegaKaWithDCAFitterCentFT0C(soa::Join const& collisions, aod::HfCascLf2Prongs const& candidates, aod::Cascades const& cascades, aod::V0s const& v0s, @@ -1481,7 +1482,7 @@ struct HfCandidateCreatorXic0Omegac0Qa { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Qa, processToOmegaKaWithDCAFitterCentFT0C, "Charm candidate reconstruction with Omega Ka via DcaFitter method, centrality selection on FT0C", false); - void processToOmegaKaWithDCAFitterCentFT0M(soa::Join const& collisions, + void processToOmegaKaWithDCAFitterCentFT0M(soa::Join const& collisions, aod::HfCascLf2Prongs const& candidates, aod::Cascades const& cascades, aod::V0s const& v0s, @@ -1514,7 +1515,7 @@ struct HfCandidateCreatorXic0Omegac0Qa { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Qa, processToXiPiWithKFParticleNoCent, "Charm Baryon decaying to Xi Pi reconstruction via KFParticle method, no centrality", false); - void processToXiPiWithKFParticleCentFT0C(soa::Join const& collisions, + void processToXiPiWithKFParticleCentFT0C(soa::Join const& collisions, aod::HfCascLf2Prongs const& candidates, aod::Cascades const& cascades, aod::V0s const& v0s, @@ -1526,7 +1527,7 @@ struct HfCandidateCreatorXic0Omegac0Qa { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Qa, processToXiPiWithKFParticleCentFT0C, "Charm Baryon decaying to Xi Pi reconstruction via KFParticle method, centrality on FT0C", false); - void processToXiPiWithKFParticleCentFT0M(soa::Join const& collisions, + void processToXiPiWithKFParticleCentFT0M(soa::Join const& collisions, aod::HfCascLf2Prongs const& candidates, aod::Cascades const& cascades, aod::V0s const& v0s, @@ -1553,7 +1554,7 @@ struct HfCandidateCreatorXic0Omegac0Qa { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Qa, processToOmegaPiWithKFParticleNoCent, "Charm Baryon decaying to Omega Pi reconstruction via KFParticle method, no centrality", false); - void processToOmegaPiWithKFParticleCentFT0C(soa::Join const& collisions, + void processToOmegaPiWithKFParticleCentFT0C(soa::Join const& collisions, aod::HfCascLf2Prongs const& candidates, aod::Cascades const& cascades, aod::V0s const& v0s, @@ -1565,7 +1566,7 @@ struct HfCandidateCreatorXic0Omegac0Qa { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Qa, processToOmegaPiWithKFParticleCentFT0C, "Charm Baryon decaying to Omega Pi reconstruction via KFParticle method, centrality on FT0C", false); - void processToOmegaPiWithKFParticleCentFT0M(soa::Join const& collisions, + void processToOmegaPiWithKFParticleCentFT0M(soa::Join const& collisions, aod::HfCascLf2Prongs const& candidates, aod::Cascades const& cascades, aod::V0s const& v0s, @@ -1592,7 +1593,7 @@ struct HfCandidateCreatorXic0Omegac0Qa { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Qa, processToOmegaKaWithKFParticleNoCent, "Charm Baryon decaying to Omega Ka reconstruction via KFParticle method, no centrality", false); - void processToOmegaKaWithKFParticleCentFT0C(soa::Join const& collisions, + void processToOmegaKaWithKFParticleCentFT0C(soa::Join const& collisions, aod::HfCascLf2Prongs const& candidates, aod::Cascades const& cascades, aod::V0s const& v0s, @@ -1604,7 +1605,7 @@ struct HfCandidateCreatorXic0Omegac0Qa { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Qa, processToOmegaKaWithKFParticleCentFT0C, "Charm Baryon decaying to Omega Ka reconstruction via KFParticle method, centrality on FT0C", false); - void processToOmegaKaWithKFParticleCentFT0M(soa::Join const& collisions, + void processToOmegaKaWithKFParticleCentFT0M(soa::Join const& collisions, aod::HfCascLf2Prongs const& candidates, aod::Cascades const& cascades, aod::V0s const& v0s, @@ -1622,7 +1623,7 @@ struct HfCandidateCreatorXic0Omegac0Qa { /// /// /////////////////////////////////////////////////////////////// - void processCollisionsNoCent(soa::Join const& collisions, + void processCollisionsNoCent(soa::Join const& collisions, aod::BCsWithTimestamps const&) { for (const auto& collision : collisions) { @@ -1638,7 +1639,7 @@ struct HfCandidateCreatorXic0Omegac0Qa { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Qa, processCollisionsNoCent, "Collision monitoring - No Centrality", true); - void processCollisionsCentFT0C(soa::Join const& collisions, + void processCollisionsCentFT0C(soa::Join const& collisions, aod::BCsWithTimestamps const&) { for (const auto& collision : collisions) { @@ -1654,7 +1655,7 @@ struct HfCandidateCreatorXic0Omegac0Qa { } PROCESS_SWITCH(HfCandidateCreatorXic0Omegac0Qa, processCollisionsCentFT0C, "Collision monitoring - Centrality selection with FT0C", false); - void processCollisionsCentFT0M(soa::Join const& collisions, + void processCollisionsCentFT0M(soa::Join const& collisions, aod::BCsWithTimestamps const&) { for (const auto& collision : collisions) { @@ -1713,9 +1714,9 @@ struct HfCandidateCreatorXic0Omegac0QaMc { // Table aliases using TracksWMcIU = soa::Join; - using McCollisionsNoCents = soa::Join; - using McCollisionsFT0Cs = soa::Join; - using McCollisionsFT0Ms = soa::Join; + using McCollisionsNoCents = soa::Join; + using McCollisionsFT0Cs = soa::Join; + using McCollisionsFT0Ms = soa::Join; using McCollisionsCentFT0Ms = soa::Join; // -> Used for subscription for process functions of centrality with FT0Ms using BCsInfo = soa::Join; diff --git a/PWGHF/TableProducer/candidateCreatorXicToXiPiPi.cxx b/PWGHF/TableProducer/candidateCreatorXicToXiPiPi.cxx index b9f23076f24..3780b21c1f9 100644 --- a/PWGHF/TableProducer/candidateCreatorXicToXiPiPi.cxx +++ b/PWGHF/TableProducer/candidateCreatorXicToXiPiPi.cxx @@ -36,6 +36,7 @@ #include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Tools/KFparticle/KFUtilities.h" #include @@ -119,6 +120,7 @@ struct HfCandidateCreatorXicToXiPiPi { Configurable minDecayLength{"minDecayLength", 0.015, "Minimum decay length (computed with DCAFitter)"}; Configurable minCosPA{"minCosPA", 0.9, "Minimum coine of pointing angle (computed with DCAFitter)"}; Configurable maxChi2Pca{"maxChi2Pca", 3., "Maximum chi2 PCA (computed with DCAFitter)"}; + Configurable maxNsigmaXiDaus{"maxNsigmaXiDaus", 3., "Maximum PID Nsigma values for Xi daughters (both TPC and TOF)"}; } softTrigCuts; Service ccdb{}; @@ -144,7 +146,6 @@ struct HfCandidateCreatorXicToXiPiPi { using CascFull = soa::Join; using KFCascadesLinked = soa::Join; using KFCascFull = soa::Join; - using TracksWCovDcaPidPrPi = soa::Join; using TracksWCovExtraPidPrPi = soa::Join; HistogramRegistry registry{"registry"}; @@ -230,9 +231,42 @@ struct HfCandidateCreatorXicToXiPiPi { /// \param pVecCascade is the cascade momentum vector /// \param trackParBachelor is the array with two bachelor track parametrisations /// \param collision is the collision containing the candidate + /// \param nSigTpcBachelorPi is the TPC n-sigma for the Xi bachelor track with pion hypothesis + /// \param nSigTofBachelorPi is the TOF n-sigma for the Xi bachelor track with pion hypothesis + /// \param nSigTpcPiFromLambda is the TPC n-sigma for the pion track from the Lambda decay with pion hypothesis + /// \param nSigTofPiFromLambda is the TOF n-sigma for the pion track from the Lambda decay with pion hypothesis + /// \param nSigTpcPrFromLambda is the TPC n-sigma for the proton track from the Lambda decay with proton hypothesis + /// \param nSigTofPrFromLambda is the TOF n-sigma for the proton track from the Lambda decay with proton hypothesis + /// \param hasTofBachelorPi is true if the Xi bachelor track has TOF information, otherwise false + /// \param hasTofPiFromLambda is true if the pion track from the Lambda decay has TOF information, otherwise false + /// \param hasTofPrFromLambda is true if the proton track from the Lambda decay has TOF information, otherwise false + /// \param nClsTpc is the array with the number of TPC clusters for each track + /// \param nCrossedRowsTpc is the array with the number of crossed rows in the TPC for each track + /// \param crossedRowsOverFindableClsTpc is the array with the ratio of crossed rows over findable clusters in the TPC for each track + /// \return true if the candidate passes the software trigger selections, otherwise false template - bool isSelectedXicSoftwareTriggers(std::array const& pVecCascade, std::array const& trackParBachelor, Coll const& collision) + bool isSelectedXicSoftwareTriggers(std::array const& pVecCascade, std::array const& trackParBachelor, Coll const& collision, float nSigTpcBachelorPi, float nSigTofBachelorPi, float nSigTpcPiFromLambda, float nSigTofPiFromLambda, float nSigTpcPrFromLambda, float nSigTofPrFromLambda, bool hasTofBachelorPi, bool hasTofPiFromLambda, bool hasTofPrFromLambda, const std::array& nClsTpc, const std::array& nCrossedRowsTpc, const std::array& crossedRowsOverFindableClsTpc) { + constexpr int16_t NumClsTpcMin = 70; + constexpr int16_t NumCrossedRowsTpcMin = 70; + constexpr float CrossedRowsOverFindableClsTpcMin = 0.8f; + constexpr int NumTracks = 3; + for (int iTrack{0}; iTrack < NumTracks; ++iTrack) { + if (nClsTpc[iTrack] < NumClsTpcMin || nCrossedRowsTpc[iTrack] < NumCrossedRowsTpcMin || crossedRowsOverFindableClsTpc[iTrack] < CrossedRowsOverFindableClsTpcMin) { + return false; + } + } + + if (std::abs(nSigTpcBachelorPi) > softTrigCuts.maxNsigmaXiDaus || (hasTofBachelorPi && std::abs(nSigTofBachelorPi) > softTrigCuts.maxNsigmaXiDaus)) { + return false; + } + if (std::abs(nSigTpcPiFromLambda) > softTrigCuts.maxNsigmaXiDaus || (hasTofPiFromLambda && std::abs(nSigTofPiFromLambda) > softTrigCuts.maxNsigmaXiDaus)) { + return false; + } + if (std::abs(nSigTpcPrFromLambda) > softTrigCuts.maxNsigmaXiDaus || (hasTofPrFromLambda && std::abs(nSigTofPrFromLambda) > softTrigCuts.maxNsigmaXiDaus)) { + return false; + } + int nCand{0}; try { nCand = df2Prong.process(trackParBachelor[0], trackParBachelor[1]); @@ -273,7 +307,7 @@ struct HfCandidateCreatorXicToXiPiPi { aod::HfCascLf3Prongs const& rowsTrackIndexXicPlus, CascadesLinked const&, CascFull const&, - TracksWCovDcaPidPrPi const&, + TracksWCovExtraPidPrPi const&, aod::BCsWithTimestamps const&) { // loop over triplets of track indices @@ -296,8 +330,8 @@ struct HfCandidateCreatorXicToXiPiPi { continue; } auto casc = cascAodElement.cascData_as(); - auto trackCharmBachelor0 = rowTrackIndexXicPlus.prong0_as(); - auto trackCharmBachelor1 = rowTrackIndexXicPlus.prong1_as(); + auto trackCharmBachelor0 = rowTrackIndexXicPlus.prong0_as(); + auto trackCharmBachelor1 = rowTrackIndexXicPlus.prong1_as(); // preselect cascade candidates if (doCascadePreselection) { @@ -348,13 +382,47 @@ struct HfCandidateCreatorXicToXiPiPi { trackCasc.setAbsCharge(1); trackCasc.setPID(o2::track::PID::XiMinus); + //----------------------------calculate physical properties----------------------- + // Charge of charm baryon + int8_t const signXic = casc.sign() < 0 ? +1 : -1; + //----------------------------fit SV and create XicPlus track------------------ auto trackParCovCharmBachelor0 = getTrackParCov(trackCharmBachelor0); auto trackParCovCharmBachelor1 = getTrackParCov(trackCharmBachelor1); // if enabled, apply selections of software trigger + float pPiFromLambda{}, pPrFromLambda{}, pPionFromXi{}, ptPionFromXi{}, nSigTpcBachelorPi{}, nSigTofBachelorPi{}, nSigTpcPiFromLambda{}, nSigTofPiFromLambda{}, nSigTpcPrFromLambda{}, nSigTofPrFromLambda{}; if (softTrigCuts.applySoftwareTrigSelections) { - if (!isSelectedXicSoftwareTriggers(pVecCasc, std::array{trackParCovCharmBachelor0, trackParCovCharmBachelor1}, collision)) { + // get PID information already here + auto const& trackPionFromXi = casc.bachelor_as(); + auto const& trackPosLambdaDaughter = casc.posTrack_as(); + auto const& trackNegLambdaDaughter = casc.negTrack_as(); + nSigTpcBachelorPi = trackPionFromXi.tpcNSigmaPi(); + nSigTofBachelorPi = trackPionFromXi.tofNSigmaPi(); + pPionFromXi = trackPionFromXi.p(); + ptPionFromXi = trackPionFromXi.pt(); + bool hasTofBachelorPi = trackPionFromXi.hasTOF(); + bool hasTofPiFromLambda = false; + bool hasTofPrFromLambda = false; + if (signXic == +1) { + pPiFromLambda = trackNegLambdaDaughter.p(); + nSigTpcPiFromLambda = trackNegLambdaDaughter.tpcNSigmaPi(); + nSigTofPiFromLambda = trackNegLambdaDaughter.tofNSigmaPi(); + pPrFromLambda = trackPosLambdaDaughter.p(); + nSigTpcPrFromLambda = trackPosLambdaDaughter.tpcNSigmaPr(); + nSigTofPrFromLambda = trackPosLambdaDaughter.tofNSigmaPr(); + } else { + pPiFromLambda = trackPosLambdaDaughter.p(); + nSigTpcPiFromLambda = trackPosLambdaDaughter.tpcNSigmaPi(); + nSigTofPiFromLambda = trackPosLambdaDaughter.tofNSigmaPi(); + pPrFromLambda = trackNegLambdaDaughter.p(); + nSigTpcPrFromLambda = trackNegLambdaDaughter.tpcNSigmaPr(); + nSigTofPrFromLambda = trackNegLambdaDaughter.tofNSigmaPr(); + } + std::array const nClsTpc = {trackPionFromXi.tpcNClsFound(), trackPosLambdaDaughter.tpcNClsFound(), trackNegLambdaDaughter.tpcNClsFound()}; + std::array const nCrossedRowsTpc = {trackPionFromXi.tpcNClsCrossedRows(), trackPosLambdaDaughter.tpcNClsCrossedRows(), trackNegLambdaDaughter.tpcNClsCrossedRows()}; + std::array const crossedRowsOverFindableClsTpc = {trackPionFromXi.tpcCrossedRowsOverFindableCls(), trackPosLambdaDaughter.tpcCrossedRowsOverFindableCls(), trackNegLambdaDaughter.tpcCrossedRowsOverFindableCls()}; + if (!isSelectedXicSoftwareTriggers(pVecCasc, std::array{trackParCovCharmBachelor0, trackParCovCharmBachelor1}, collision, nSigTpcBachelorPi, nSigTofBachelorPi, nSigTpcPiFromLambda, nSigTofPiFromLambda, nSigTpcPrFromLambda, nSigTofPrFromLambda, hasTofBachelorPi, hasTofPiFromLambda, hasTofPrFromLambda, nClsTpc, nCrossedRowsTpc, crossedRowsOverFindableClsTpc)) { continue; } } @@ -370,10 +438,6 @@ struct HfCandidateCreatorXicToXiPiPi { } registry.fill(HIST("hCandCounter"), VertexFit); - //----------------------------calculate physical properties----------------------- - // Charge of charm baryon - int8_t const signXic = casc.sign() < 0 ? +1 : -1; - // get SV properties const auto& secondaryVertex = df.getPCACandidate(); auto chi2SV = df.getChi2AtPCACandidate(); @@ -435,28 +499,31 @@ struct HfCandidateCreatorXicToXiPiPi { float const nSigTofPiFromXicPlus0 = trackCharmBachelor0.tofNSigmaPi(); float const nSigTpcPiFromXicPlus1 = trackCharmBachelor1.tpcNSigmaPi(); float const nSigTofPiFromXicPlus1 = trackCharmBachelor1.tofNSigmaPi(); - // Bachelor pion - auto trackPionFromXi = casc.bachelor_as(); - float const nSigTpcBachelorPi = trackPionFromXi.tpcNSigmaPi(); - float const nSigTofBachelorPi = trackPionFromXi.tofNSigmaPi(); - // Lambda daughters - auto trackPosLambdaDaughter = casc.posTrack_as(); - auto trackNegLambdaDaughter = casc.negTrack_as(); - float pPiFromLambda{}, pPrFromLambda{}, nSigTpcPiFromLambda{}, nSigTofPiFromLambda{}, nSigTpcPrFromLambda{}, nSigTofPrFromLambda{}; - if (signXic == +1) { - pPiFromLambda = trackNegLambdaDaughter.p(); - nSigTpcPiFromLambda = trackNegLambdaDaughter.tpcNSigmaPi(); - nSigTofPiFromLambda = trackNegLambdaDaughter.tofNSigmaPi(); - pPrFromLambda = trackPosLambdaDaughter.p(); - nSigTpcPrFromLambda = trackPosLambdaDaughter.tpcNSigmaPr(); - nSigTofPrFromLambda = trackPosLambdaDaughter.tofNSigmaPr(); - } else { - pPiFromLambda = trackPosLambdaDaughter.p(); - nSigTpcPiFromLambda = trackPosLambdaDaughter.tpcNSigmaPi(); - nSigTofPiFromLambda = trackPosLambdaDaughter.tofNSigmaPi(); - pPrFromLambda = trackNegLambdaDaughter.p(); - nSigTpcPrFromLambda = trackNegLambdaDaughter.tpcNSigmaPr(); - nSigTofPrFromLambda = trackNegLambdaDaughter.tofNSigmaPr(); + if (!softTrigCuts.applySoftwareTrigSelections) { + // Bachelor pion + auto trackPionFromXi = casc.bachelor_as(); + nSigTpcBachelorPi = trackPionFromXi.tpcNSigmaPi(); + nSigTofBachelorPi = trackPionFromXi.tofNSigmaPi(); + pPionFromXi = trackPionFromXi.p(); + ptPionFromXi = trackPionFromXi.pt(); + // Lambda daughters + auto trackPosLambdaDaughter = casc.posTrack_as(); + auto trackNegLambdaDaughter = casc.negTrack_as(); + if (signXic == +1) { + pPiFromLambda = trackNegLambdaDaughter.p(); + nSigTpcPiFromLambda = trackNegLambdaDaughter.tpcNSigmaPi(); + nSigTofPiFromLambda = trackNegLambdaDaughter.tofNSigmaPi(); + pPrFromLambda = trackPosLambdaDaughter.p(); + nSigTpcPrFromLambda = trackPosLambdaDaughter.tpcNSigmaPr(); + nSigTofPrFromLambda = trackPosLambdaDaughter.tofNSigmaPr(); + } else { + pPiFromLambda = trackPosLambdaDaughter.p(); + nSigTpcPiFromLambda = trackPosLambdaDaughter.tpcNSigmaPi(); + nSigTofPiFromLambda = trackPosLambdaDaughter.tofNSigmaPi(); + pPrFromLambda = trackNegLambdaDaughter.p(); + nSigTpcPrFromLambda = trackNegLambdaDaughter.tpcNSigmaPr(); + nSigTofPrFromLambda = trackNegLambdaDaughter.tofNSigmaPr(); + } } //--------------------------------------------fill histograms---------------------------------------------------------------- @@ -499,7 +566,7 @@ struct HfCandidateCreatorXicToXiPiPi { impactParameterCasc.getY(), impactParameter0.getY(), impactParameter1.getY(), std::sqrt(impactParameterCasc.getSigmaY2()), std::sqrt(impactParameter0.getSigmaY2()), std::sqrt(impactParameter1.getSigmaY2()), /*cascade specific columns*/ - trackPionFromXi.p(), pPiFromLambda, pPrFromLambda, trackPionFromXi.pt(), + pPionFromXi, pPiFromLambda, pPrFromLambda, ptPionFromXi, cpaXi, cpaXYXi, cpaLambda, cpaXYLambda, cpaLambdaToXi, cpaXYLambdaToXi, casc.mXi(), casc.mLambda(), massXiPi0, massXiPi1, radiusLambda, @@ -541,15 +608,52 @@ struct HfCandidateCreatorXicToXiPiPi { } auto casc = cascAodElement.kfCascData_as(); - auto trackCharmBachelor0 = rowTrackIndexXicPlus.prong0_as(); - auto trackCharmBachelor1 = rowTrackIndexXicPlus.prong1_as(); + auto const& trackCharmBachelor0 = rowTrackIndexXicPlus.prong0_as(); + auto const& trackCharmBachelor1 = rowTrackIndexXicPlus.prong1_as(); + + // sign of charm baryon + int8_t const signXic = casc.sign() < 0 ? +1 : -1; // if enabled, apply selections of software trigger + float pPiFromLambda{}, pPrFromLambda{}, pPionFromXi{}, ptPionFromXi{}, nSigTpcBachelorPi{}, nSigTofBachelorPi{}, nSigTpcPiFromLambda{}, nSigTofPiFromLambda{}, nSigTpcPrFromLambda{}, nSigTofPrFromLambda{}; if (softTrigCuts.applySoftwareTrigSelections) { + // get PID information already here + auto const& trackPionFromXi = casc.bachelor_as(); + auto const& trackPosLambdaDaughter = casc.posTrack_as(); + auto const& trackNegLambdaDaughter = casc.negTrack_as(); + nSigTpcBachelorPi = trackPionFromXi.tpcNSigmaPi(); + nSigTofBachelorPi = trackPionFromXi.tofNSigmaPi(); + pPionFromXi = trackPionFromXi.p(); + ptPionFromXi = trackPionFromXi.pt(); + bool hasTofBachelorPi = trackPionFromXi.hasTOF(); + bool hasTofPiFromLambda = false; + bool hasTofPrFromLambda = false; + if (signXic == +1) { + pPiFromLambda = trackNegLambdaDaughter.p(); + nSigTpcPiFromLambda = trackNegLambdaDaughter.tpcNSigmaPi(); + nSigTofPiFromLambda = trackNegLambdaDaughter.tofNSigmaPi(); + hasTofPiFromLambda = trackNegLambdaDaughter.hasTOF(); + pPrFromLambda = trackPosLambdaDaughter.p(); + nSigTpcPrFromLambda = trackPosLambdaDaughter.tpcNSigmaPr(); + nSigTofPrFromLambda = trackPosLambdaDaughter.tofNSigmaPr(); + hasTofPrFromLambda = trackPosLambdaDaughter.hasTOF(); + } else { + pPiFromLambda = trackPosLambdaDaughter.p(); + nSigTpcPiFromLambda = trackPosLambdaDaughter.tpcNSigmaPi(); + nSigTofPiFromLambda = trackPosLambdaDaughter.tofNSigmaPi(); + hasTofPiFromLambda = trackPosLambdaDaughter.hasTOF(); + pPrFromLambda = trackNegLambdaDaughter.p(); + nSigTpcPrFromLambda = trackNegLambdaDaughter.tpcNSigmaPr(); + nSigTofPrFromLambda = trackNegLambdaDaughter.tofNSigmaPr(); + hasTofPrFromLambda = trackNegLambdaDaughter.hasTOF(); + } auto trackParCovCharmBachelor0 = getTrackParCov(trackCharmBachelor0); auto trackParCovCharmBachelor1 = getTrackParCov(trackCharmBachelor1); std::array const pVecCasc = {casc.px(), casc.py(), casc.pz()}; - if (!isSelectedXicSoftwareTriggers(pVecCasc, std::array{trackParCovCharmBachelor0, trackParCovCharmBachelor1}, collision)) { + std::array const nClsTpc = {trackPionFromXi.tpcNClsFound(), trackPosLambdaDaughter.tpcNClsFound(), trackNegLambdaDaughter.tpcNClsFound()}; + std::array const nCrossedRowsTpc = {trackPionFromXi.tpcNClsCrossedRows(), trackPosLambdaDaughter.tpcNClsCrossedRows(), trackNegLambdaDaughter.tpcNClsCrossedRows()}; + std::array const crossedRowsOverFindableClsTpc = {trackPionFromXi.tpcCrossedRowsOverFindableCls(), trackPosLambdaDaughter.tpcCrossedRowsOverFindableCls(), trackNegLambdaDaughter.tpcCrossedRowsOverFindableCls()}; + if (!isSelectedXicSoftwareTriggers(pVecCasc, std::array{trackParCovCharmBachelor0, trackParCovCharmBachelor1}, collision, nSigTpcBachelorPi, nSigTofBachelorPi, nSigTpcPiFromLambda, nSigTofPiFromLambda, nSigTpcPrFromLambda, nSigTofPrFromLambda, hasTofBachelorPi, hasTofPiFromLambda, hasTofPrFromLambda, nClsTpc, nCrossedRowsTpc, crossedRowsOverFindableClsTpc)) { continue; } } @@ -643,9 +747,6 @@ struct HfCandidateCreatorXicToXiPiPi { } //---------------------calculate physical parameters of XicPlus candidate---------------------- - // sign of charm baryon - int8_t const signXic = casc.sign() < 0 ? +1 : -1; - // transport XicPlus daughters to XicPlus decay vertex (secondary vertex) float secondaryVertex[3] = {0.}; secondaryVertex[0] = kfXicPlus.GetX(); @@ -729,28 +830,31 @@ struct HfCandidateCreatorXicToXiPiPi { float const nSigTofPiFromXicPlus0 = trackCharmBachelor0.tofNSigmaPi(); float const nSigTpcPiFromXicPlus1 = trackCharmBachelor1.tpcNSigmaPi(); float const nSigTofPiFromXicPlus1 = trackCharmBachelor1.tofNSigmaPi(); - // Bachelor pion - auto trackPionFromXi = casc.bachelor_as(); - float const nSigTpcBachelorPi = trackPionFromXi.tpcNSigmaPi(); - float const nSigTofBachelorPi = trackPionFromXi.tofNSigmaPi(); - // Lambda daughters - auto trackPosLambdaDaughter = casc.posTrack_as(); - auto trackNegLambdaDaughter = casc.negTrack_as(); - float pPiFromLambda{}, pPrFromLambda{}, nSigTpcPiFromLambda{}, nSigTofPiFromLambda{}, nSigTpcPrFromLambda{}, nSigTofPrFromLambda{}; - if (signXic == +1) { - pPiFromLambda = trackNegLambdaDaughter.p(); - nSigTpcPiFromLambda = trackNegLambdaDaughter.tpcNSigmaPi(); - nSigTofPiFromLambda = trackNegLambdaDaughter.tofNSigmaPi(); - pPrFromLambda = trackPosLambdaDaughter.p(); - nSigTpcPrFromLambda = trackPosLambdaDaughter.tpcNSigmaPr(); - nSigTofPrFromLambda = trackPosLambdaDaughter.tofNSigmaPr(); - } else { - pPiFromLambda = trackPosLambdaDaughter.p(); - nSigTpcPiFromLambda = trackPosLambdaDaughter.tpcNSigmaPi(); - nSigTofPiFromLambda = trackPosLambdaDaughter.tofNSigmaPi(); - pPrFromLambda = trackNegLambdaDaughter.p(); - nSigTpcPrFromLambda = trackNegLambdaDaughter.tpcNSigmaPr(); - nSigTofPrFromLambda = trackNegLambdaDaughter.tofNSigmaPr(); + if (!softTrigCuts.applySoftwareTrigSelections) { + // Bachelor pion + auto trackPionFromXi = casc.bachelor_as(); + nSigTpcBachelorPi = trackPionFromXi.tpcNSigmaPi(); + nSigTofBachelorPi = trackPionFromXi.tofNSigmaPi(); + pPionFromXi = trackPionFromXi.p(); + ptPionFromXi = trackPionFromXi.pt(); + // Lambda daughters + auto trackPosLambdaDaughter = casc.posTrack_as(); + auto trackNegLambdaDaughter = casc.negTrack_as(); + if (signXic == +1) { + pPiFromLambda = trackNegLambdaDaughter.p(); + nSigTpcPiFromLambda = trackNegLambdaDaughter.tpcNSigmaPi(); + nSigTofPiFromLambda = trackNegLambdaDaughter.tofNSigmaPi(); + pPrFromLambda = trackPosLambdaDaughter.p(); + nSigTpcPrFromLambda = trackPosLambdaDaughter.tpcNSigmaPr(); + nSigTofPrFromLambda = trackPosLambdaDaughter.tofNSigmaPr(); + } else { + pPiFromLambda = trackPosLambdaDaughter.p(); + nSigTpcPiFromLambda = trackPosLambdaDaughter.tpcNSigmaPi(); + nSigTofPiFromLambda = trackPosLambdaDaughter.tofNSigmaPi(); + pPrFromLambda = trackNegLambdaDaughter.p(); + nSigTpcPrFromLambda = trackNegLambdaDaughter.tpcNSigmaPr(); + nSigTofPrFromLambda = trackNegLambdaDaughter.tofNSigmaPr(); + } } //-------------------------------fill histograms-------------------------------------------- @@ -791,7 +895,7 @@ struct HfCandidateCreatorXicToXiPiPi { impactParameterXiXY, impactParameterPi0XY, impactParameterPi1XY, errImpactParameterXiXY, errImpactParameterPi0XY, errImpactParameterPi1XY, /*cascade specific columns*/ - trackPionFromXi.p(), pPiFromLambda, pPrFromLambda, trackPionFromXi.pt(), + pPionFromXi, pPiFromLambda, pPrFromLambda, ptPionFromXi, cpaXi, cpaXYXi, cpaLambda, cpaXYLambda, cpaLambdaToXi, cpaXYLambdaToXi, massXi, casc.mLambda(), massXiPi0, massXiPi1, radiusLambda, @@ -817,33 +921,33 @@ struct HfCandidateCreatorXicToXiPiPi { /// /// /////////////////////////////////////////////////////////// - void processNoCentXicplusWithDcaFitter(soa::Join const& collisions, + void processNoCentXicplusWithDcaFitter(soa::Join const& collisions, aod::HfCascLf3Prongs const& rowsTrackIndexXicPlus, CascadesLinked const& cascadesLinked, CascFull const& cascadesFull, - TracksWCovDcaPidPrPi const& tracks, + TracksWCovExtraPidPrPi const& tracks, aod::BCsWithTimestamps const& bcs) { runXicplusCreatorWithDcaFitter(collisions, rowsTrackIndexXicPlus, cascadesLinked, cascadesFull, tracks, bcs); } PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPi, processNoCentXicplusWithDcaFitter, "Run candidate creator with DCAFitter without centrality selection.", true); - void processCentFT0CXicplusWithDcaFitter(soa::Join const& collisions, + void processCentFT0CXicplusWithDcaFitter(soa::Join const& collisions, aod::HfCascLf3Prongs const& rowsTrackIndexXicPlus, CascadesLinked const& cascadesLinked, CascFull const& cascadesFull, - TracksWCovDcaPidPrPi const& tracks, + TracksWCovExtraPidPrPi const& tracks, aod::BCsWithTimestamps const& bcs) { runXicplusCreatorWithDcaFitter(collisions, rowsTrackIndexXicPlus, cascadesLinked, cascadesFull, tracks, bcs); } PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPi, processCentFT0CXicplusWithDcaFitter, "Run candidate creator with DCAFitter with centrality selection on FT0C.", false); - void processCentFT0MXicplusWithDcaFitter(soa::Join const& collisions, + void processCentFT0MXicplusWithDcaFitter(soa::Join const& collisions, aod::HfCascLf3Prongs const& rowsTrackIndexXicPlus, CascadesLinked const& cascadesLinked, CascFull const& cascadesFull, - TracksWCovDcaPidPrPi const& tracks, + TracksWCovExtraPidPrPi const& tracks, aod::BCsWithTimestamps const& bcs) { runXicplusCreatorWithDcaFitter(collisions, rowsTrackIndexXicPlus, cascadesLinked, cascadesFull, tracks, bcs); @@ -856,7 +960,7 @@ struct HfCandidateCreatorXicToXiPiPi { /// /// /////////////////////////////////////////////////////////// - void processNoCentXicplusWithKFParticle(soa::Join const& collisions, + void processNoCentXicplusWithKFParticle(soa::Join const& collisions, aod::HfCascLf3Prongs const& rowsTrackIndexXicPlus, KFCascadesLinked const& kfCascadesLinked, KFCascFull const& kfCascadesFull, @@ -867,7 +971,7 @@ struct HfCandidateCreatorXicToXiPiPi { } PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPi, processNoCentXicplusWithKFParticle, "Run candidate creator with KFParticle without centrality selection.", false); - void processCentFT0CXicplusWithKFParticle(soa::Join const& collisions, + void processCentFT0CXicplusWithKFParticle(soa::Join const& collisions, aod::HfCascLf3Prongs const& rowsTrackIndexXicPlus, KFCascadesLinked const& kfCascadesLinked, KFCascFull const& kfCascadesFull, @@ -878,7 +982,7 @@ struct HfCandidateCreatorXicToXiPiPi { } PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPi, processCentFT0CXicplusWithKFParticle, "Run candidate creator with KFParticle with centrality selection on FT0C.", false); - void processCentFT0MXicplusWithKFParticle(soa::Join const& collisions, + void processCentFT0MXicplusWithKFParticle(soa::Join const& collisions, aod::HfCascLf3Prongs const& rowsTrackIndexXicPlus, KFCascadesLinked const& kfCascadesLinked, KFCascFull const& kfCascadesFull, @@ -895,7 +999,7 @@ struct HfCandidateCreatorXicToXiPiPi { /// /// /////////////////////////////////////////////////////////// - void processCollisions(soa::Join const& collisions, aod::BCsWithTimestamps const&) + void processCollisions(soa::Join const& collisions, aod::BCsWithTimestamps const&) { /// loop over collisions for (const auto& collision : collisions) { @@ -913,7 +1017,7 @@ struct HfCandidateCreatorXicToXiPiPi { } PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPi, processCollisions, "Collision monitoring - no centrality", false); - void processCollisionsCentFT0C(soa::Join const& collisions, aod::BCsWithTimestamps const&) + void processCollisionsCentFT0C(soa::Join const& collisions, aod::BCsWithTimestamps const&) { /// loop over collisions for (const auto& collision : collisions) { @@ -931,7 +1035,7 @@ struct HfCandidateCreatorXicToXiPiPi { } PROCESS_SWITCH(HfCandidateCreatorXicToXiPiPi, processCollisionsCentFT0C, "Collision monitoring - FT0C centrality", false); - void processCollisionsCentFT0M(soa::Join const& collisions, aod::BCsWithTimestamps const&) + void processCollisionsCentFT0M(soa::Join const& collisions, aod::BCsWithTimestamps const&) { /// loop over collisions for (const auto& collision : collisions) { @@ -969,9 +1073,9 @@ struct HfCandidateCreatorXicToXiPiPiExpressions { XiToPiPPi, LambdaToPPi }; - using McCollisionsNoCents = soa::Join; - using McCollisionsFT0Cs = soa::Join; - using McCollisionsFT0Ms = soa::Join; + using McCollisionsNoCents = soa::Join; + using McCollisionsFT0Cs = soa::Join; + using McCollisionsFT0Ms = soa::Join; using McCollisionsCentFT0Ms = soa::Join; using BCsInfo = soa::Join; diff --git a/PWGHF/TableProducer/candidateSelectorCd.cxx b/PWGHF/TableProducer/candidateSelectorCd.cxx index 61c662ada3e..7658c95cf11 100644 --- a/PWGHF/TableProducer/candidateSelectorCd.cxx +++ b/PWGHF/TableProducer/candidateSelectorCd.cxx @@ -71,10 +71,11 @@ struct HfCandidateSelectorCd { Configurable itsChi2PerClusterMax{"itsChi2PerClusterMax", 1e10f, "max its fit chi2 per ITS cluster"}; // DCA track cuts Configurable> binsPtTrack{"binsPtTrack", std::vector{hf_cuts_single_track::vecBinsPtTrack}, "track pT bin limits for DCA XY/Z pT-dependent cut"}; - Configurable> cutsSingleTrack{"cutsSingleTrack", {hf_cuts_single_track::CutsTrack[0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections"}; + Configurable> cutsSingleTrack{"cutsSingleTrack", {&hf_cuts_single_track::CutsTrack[0][0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections"}; // topological cuts Configurable> binsPt{"binsPt", std::vector{hf_cuts_cd_to_de_k_pi::vecBinsPt}, "pT bin limits"}; - Configurable> cuts{"cuts", {hf_cuts_cd_to_de_k_pi::Cuts[0], hf_cuts_cd_to_de_k_pi::NBinsPt, hf_cuts_cd_to_de_k_pi::NCutVars, hf_cuts_cd_to_de_k_pi::labelsPt, hf_cuts_cd_to_de_k_pi::labelsCutVar}, "Cd candidate selection per pT bin"}; + Configurable> cuts{"cuts", {&hf_cuts_cd_to_de_k_pi::Cuts[0][0], hf_cuts_cd_to_de_k_pi::NBinsPt, hf_cuts_cd_to_de_k_pi::NCutVars, hf_cuts_cd_to_de_k_pi::labelsPt, hf_cuts_cd_to_de_k_pi::labelsCutVar}, "Cd candidate selection per pT bin"}; + Configurable acceptCandidatesWithoutCdFlag{"acceptCandidatesWithoutCdFlag", false, "Apply the Cd mass hypotheses also to 3-prong candidates without the Cd skim bit; intended for MC reflection studies"}; // QA switch Configurable activateQA{"activateQA", false, "Flag to enable QA histogram"}; @@ -102,15 +103,15 @@ struct HfCandidateSelectorCd { selectorDeuteron = selectorPion; if (activateQA) { - constexpr int kNBinsSelections = aod::SelectionStep::NSelectionSteps; - std::string labels[kNBinsSelections]; + constexpr int NBinsSelections = aod::SelectionStep::NSelectionSteps; + std::string labels[NBinsSelections]; labels[0] = "No selection"; labels[1 + aod::SelectionStep::RecoSkims] = "Skims selection"; labels[1 + aod::SelectionStep::RecoTopol] = "Skims & Topological selections"; labels[1 + aod::SelectionStep::RecoPID] = "Skims & Topological & PID selections"; - static const AxisSpec axisSelections = {kNBinsSelections, 0.5, kNBinsSelections + 0.5, ""}; + static const AxisSpec axisSelections = {NBinsSelections, 0.5, NBinsSelections + 0.5, ""}; registry.add("hSelections", "Selections;;#it{p}_{T} (GeV/#it{c})", {HistType::kTH2F, {axisSelections, {(std::vector)binsPt, "#it{p}_{T} (GeV/#it{c})"}}}); - for (int iBin = 0; iBin < kNBinsSelections; ++iBin) { + for (int iBin = 0; iBin < NBinsSelections; ++iBin) { registry.get(HIST("hSelections"))->GetXaxis()->SetBinLabel(iBin + 1, labels[iBin].data()); } } @@ -264,7 +265,7 @@ struct HfCandidateSelectorCd { auto ptCand = candidate.pt(); - if (!(candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::CdToDeKPi)) { + if (!acceptCandidatesWithoutCdFlag && !(candidate.hfflag() & 1 << aod::hf_cand_3prong::DecayType::CdToDeKPi)) { hfSelCdCandidate(statusCdToDeKPi, statusCdToPiKDe); if (activateQA) { registry.fill(HIST("hSelections"), 1, ptCand); @@ -314,24 +315,11 @@ struct HfCandidateSelectorCd { if (usePid) { // track-level PID selection - TrackSelectorPID::Status pidTrackPos1Deuteron; - TrackSelectorPID::Status pidTrackPos2Deuteron; - TrackSelectorPID::Status pidTrackPos1Pion; - TrackSelectorPID::Status pidTrackPos2Pion; - TrackSelectorPID::Status pidTrackNegKaon; - if (usePidTpcAndTof) { - pidTrackPos1Deuteron = selectorDeuteron.statusTpcAndTof(trackPos1, candidate.nSigTpcDe0(), candidate.nSigTofDe0()); - pidTrackPos2Deuteron = selectorDeuteron.statusTpcAndTof(trackPos2, candidate.nSigTpcDe2(), candidate.nSigTofDe2()); - pidTrackPos1Pion = selectorPion.statusTpcAndTof(trackPos1, candidate.nSigTpcPi0(), candidate.nSigTofPi0()); - pidTrackPos2Pion = selectorPion.statusTpcAndTof(trackPos2, candidate.nSigTpcPi2(), candidate.nSigTofPi2()); - pidTrackNegKaon = selectorKaon.statusTpcAndTof(trackNeg, candidate.nSigTpcKa1(), candidate.nSigTofKa1()); - } else { - pidTrackPos1Deuteron = selectorDeuteron.statusTpcOrTof(trackPos1, candidate.nSigTpcDe0(), candidate.nSigTofDe0()); - pidTrackPos2Deuteron = selectorDeuteron.statusTpcOrTof(trackPos2, candidate.nSigTpcDe2(), candidate.nSigTofDe2()); - pidTrackPos1Pion = selectorPion.statusTpcOrTof(trackPos1, candidate.nSigTpcPi0(), candidate.nSigTofPi0()); - pidTrackPos2Pion = selectorPion.statusTpcOrTof(trackPos2, candidate.nSigTpcPi2(), candidate.nSigTofPi2()); - pidTrackNegKaon = selectorKaon.statusTpcOrTof(trackNeg, candidate.nSigTpcKa1(), candidate.nSigTofKa1()); - } + const auto pidTrackPos1Deuteron = usePidTpcAndTof ? selectorDeuteron.statusTpcAndTof(trackPos1, candidate.nSigTpcDe0(), candidate.nSigTofDe0()) : selectorDeuteron.statusTpcOrTof(trackPos1, candidate.nSigTpcDe0(), candidate.nSigTofDe0()); + const auto pidTrackPos2Deuteron = usePidTpcAndTof ? selectorDeuteron.statusTpcAndTof(trackPos2, candidate.nSigTpcDe2(), candidate.nSigTofDe2()) : selectorDeuteron.statusTpcOrTof(trackPos2, candidate.nSigTpcDe2(), candidate.nSigTofDe2()); + const auto pidTrackPos1Pion = usePidTpcAndTof ? selectorPion.statusTpcAndTof(trackPos1, candidate.nSigTpcPi0(), candidate.nSigTofPi0()) : selectorPion.statusTpcOrTof(trackPos1, candidate.nSigTpcPi0(), candidate.nSigTofPi0()); + const auto pidTrackPos2Pion = usePidTpcAndTof ? selectorPion.statusTpcAndTof(trackPos2, candidate.nSigTpcPi2(), candidate.nSigTofPi2()) : selectorPion.statusTpcOrTof(trackPos2, candidate.nSigTpcPi2(), candidate.nSigTofPi2()); + const auto pidTrackNegKaon = usePidTpcAndTof ? selectorKaon.statusTpcAndTof(trackNeg, candidate.nSigTpcKa1(), candidate.nSigTofKa1()) : selectorKaon.statusTpcOrTof(trackNeg, candidate.nSigTpcKa1(), candidate.nSigTofKa1()); if (!isSelectedPID(pidTrackPos1Deuteron, pidTrackNegKaon, pidTrackPos2Pion)) { pidCdToDeKPi = 0; // reject CdToDeKPi diff --git a/PWGHF/TableProducer/candidateSelectorDstarToD0Pi.cxx b/PWGHF/TableProducer/candidateSelectorDstarToD0Pi.cxx index 3e2ac92ec82..0d24a58d91b 100644 --- a/PWGHF/TableProducer/candidateSelectorDstarToD0Pi.cxx +++ b/PWGHF/TableProducer/candidateSelectorDstarToD0Pi.cxx @@ -69,6 +69,10 @@ struct HfCandidateSelectorDstarToD0Pi { Configurable> binsPtDstar{"binsPtDstar", std::vector{hf_cuts_dstar_to_d0_pi::vecBinsPt}, "pT bin limits for Dstar"}; Configurable> cutsDstar{"cutsDstar", {hf_cuts_dstar_to_d0_pi::Cuts[0], hf_cuts_dstar_to_d0_pi::NBinsPt, hf_cuts_dstar_to_d0_pi::NCutVars, hf_cuts_dstar_to_d0_pi::labelsPt, hf_cuts_dstar_to_d0_pi::labelsCutVar}, "Dstar candidate selection per pT bin"}; + // Single-track DCA selections + Configurable> cutsSingleTrack{"cutsSingleTrack", {hf_cuts_single_track::CutsTrack[0], hf_cuts_single_track::NBinsPtTrack, hf_cuts_single_track::NCutVarsTrack, hf_cuts_single_track::labelsPtTrack, hf_cuts_single_track::labelsCutVarTrack}, "Single-track selections"}; + Configurable> binsPtTrack{"binsPtTrack", std::vector{hf_cuts_single_track::vecBinsPtTrack}, "track pT bin limits for DCA pT-dependent cut"}; + // common Configurable // TPC PID Configurable ptPidTpcMin{"ptPidTpcMin", 0.15, "Minimum track pT for TPC PID"}; @@ -168,6 +172,17 @@ struct HfCandidateSelectorDstarToD0Pi { } } + /// Single-track cuts + /// \param candidate is the Dstar candidate + /// \return true if all the prongs pass the selections + template + bool isSelectedCandidateProngDca(const T1& candidate) + { + // Applied only on D0 tracks, to mimic the skimming selections + return (isSelectedTrackDca(binsPtTrack, cutsSingleTrack, candidate.ptProng0(), candidate.impactParameter0(), candidate.impactParameterZ0()) && + isSelectedTrackDca(binsPtTrack, cutsSingleTrack, candidate.ptProng1(), candidate.impactParameter1(), candidate.impactParameterZ1())); + } + /// Conjugate-independent topological cuts on D0 /// @brief Topological selection on D0 candidate from Dstar /// @tparam T table iterator type of the candidate @@ -182,6 +197,10 @@ struct HfCandidateSelectorDstarToD0Pi { return false; } + if (!isSelectedCandidateProngDca(candidate)) { + return false; + } + // check that the candidate pT is within the analysis range if (candpT < ptD0CandMin || candpT >= ptD0CandMax) { return false; @@ -357,7 +376,6 @@ struct HfCandidateSelectorDstarToD0Pi { void process(TracksSel const&, HfFullDstarCandidate const& rowsDstarCand) { - // LOG(info) << "selector called"; for (const auto& candDstar : rowsDstarCand) { // final selection flag: false - rejected, true - accepted bool statusDstar = false, statusD0Flag = false, statusTopol = false, statusCand = false, statusPID = false; diff --git a/PWGHF/TableProducer/candidateSelectorXicToXiPiPi.cxx b/PWGHF/TableProducer/candidateSelectorXicToXiPiPi.cxx index 6355024ec2b..070e92a43e2 100644 --- a/PWGHF/TableProducer/candidateSelectorXicToXiPiPi.cxx +++ b/PWGHF/TableProducer/candidateSelectorXicToXiPiPi.cxx @@ -274,9 +274,9 @@ struct HfCandidateSelectorXicToXiPiPi { TrackSelectorPID::Status const statusPidPiXi, TrackSelectorPID::Status const statusPidPrLam, TrackSelectorPID::Status const statusPidPiLam, - bool const useTpcPidOnly) + bool const useOnlyTpcPid) { - if (useTpcPidOnly) { + if (useOnlyTpcPid) { return (statusPidPi0 == TrackSelectorPID::Accepted || statusPidPi0 == TrackSelectorPID::NotApplicable) && (statusPidPi1 == TrackSelectorPID::Accepted || statusPidPi1 == TrackSelectorPID::NotApplicable) && (statusPidPiXi == TrackSelectorPID::Accepted || statusPidPiXi == TrackSelectorPID::NotApplicable) && (statusPidPrLam == TrackSelectorPID::Accepted || statusPidPrLam == TrackSelectorPID::NotApplicable) && (statusPidPiLam == TrackSelectorPID::Accepted || statusPidPiLam == TrackSelectorPID::NotApplicable); } if (statusPidPi0 == TrackSelectorPID::Rejected || statusPidPi1 == TrackSelectorPID::Rejected || statusPidPiXi == TrackSelectorPID::Rejected || statusPidPrLam == TrackSelectorPID::Rejected || statusPidPiLam == TrackSelectorPID::Rejected) { @@ -567,7 +567,7 @@ struct HfCandidateSelectorXicToXiPiPi { // ITS track quality selection on pions from charm baryon if ((!isSelectedTrackItsQuality(trackPi0, nClustersItsMin, itsChi2PerClusterMax) || trackPi0.itsNClsInnerBarrel() < nClustersItsInnBarrMin) || - (!isSelectedTrackItsQuality(trackPi0, nClustersItsMin, itsChi2PerClusterMax) || trackPi1.itsNClsInnerBarrel() < nClustersItsInnBarrMin)) { + (!isSelectedTrackItsQuality(trackPi1, nClustersItsMin, itsChi2PerClusterMax) || trackPi1.itsNClsInnerBarrel() < nClustersItsInnBarrMin)) { return false; } if constexpr (IsMc) { diff --git a/PWGHF/TableProducer/derivedDataCreatorDstarToD0Pi.cxx b/PWGHF/TableProducer/derivedDataCreatorDstarToD0Pi.cxx index d2812782bde..a69bdea3f2c 100644 --- a/PWGHF/TableProducer/derivedDataCreatorDstarToD0Pi.cxx +++ b/PWGHF/TableProducer/derivedDataCreatorDstarToD0Pi.cxx @@ -255,7 +255,7 @@ struct HfDerivedDataCreatorDstarToD0Pi { int pdgBhadMotherPart = 0; for (const auto& candidate : candidatesThisColl) { if constexpr (IsMl) { - if (!TESTBIT(candidate.isSelDstarToD0Pi(), aod::SelectionStep::RecoMl)) { + if (!candidate.isSelDstarToD0Pi()) { continue; } } diff --git a/PWGHF/TableProducer/trackIndexSkimCreator.cxx b/PWGHF/TableProducer/trackIndexSkimCreator.cxx index 59f944cf4a4..c8456183f31 100644 --- a/PWGHF/TableProducer/trackIndexSkimCreator.cxx +++ b/PWGHF/TableProducer/trackIndexSkimCreator.cxx @@ -39,6 +39,7 @@ #include "Common/DataModel/Centrality.h" #include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponseITS.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" @@ -223,7 +224,7 @@ struct HfTrackIndexSkimCreatorTagSelCollisions { /// Event selection with trigger and FT0A centrality selection void processTrigAndCentFT0ASel(soa::Join::iterator const& collision, + aod::EvSels, aod::PVMults, aod::CentFT0As>::iterator const& collision, aod::BcFullInfos const& bcs) { selectCollision(collision, bcs); @@ -232,7 +233,7 @@ struct HfTrackIndexSkimCreatorTagSelCollisions { /// Event selection with trigger and FT0C centrality selection void processTrigAndCentFT0CSel(soa::Join::iterator const& collision, + aod::EvSels, aod::PVMults, aod::CentFT0Cs>::iterator const& collision, aod::BcFullInfos const& bcs) { selectCollision(collision, bcs); @@ -241,7 +242,7 @@ struct HfTrackIndexSkimCreatorTagSelCollisions { /// Event selection with trigger and FT0M centrality selection void processTrigAndCentFT0MSel(soa::Join::iterator const& collision, + aod::EvSels, aod::PVMults, aod::CentFT0Ms>::iterator const& collision, aod::BcFullInfos const& bcs) { selectCollision(collision, bcs); @@ -250,7 +251,7 @@ struct HfTrackIndexSkimCreatorTagSelCollisions { /// Event selection with trigger and FV0A centrality selection void processTrigAndCentFV0ASel(soa::Join::iterator const& collision, + aod::EvSels, aod::PVMults, aod::CentFV0As>::iterator const& collision, aod::BcFullInfos const& bcs) { selectCollision(collision, bcs); @@ -259,7 +260,7 @@ struct HfTrackIndexSkimCreatorTagSelCollisions { /// Event selection with trigger selection void processTrigSel(soa::Join::iterator const& collision, + aod::EvSels, aod::PVMults>::iterator const& collision, aod::BcFullInfos const& bcs) { selectCollision(collision, bcs); @@ -267,7 +268,7 @@ struct HfTrackIndexSkimCreatorTagSelCollisions { PROCESS_SWITCH(HfTrackIndexSkimCreatorTagSelCollisions, processTrigSel, "Use trigger selection", false); /// Event selection without trigger selection - void processNoTrigSel(aod::Collision const& collision, + void processNoTrigSel(soa::Join::iterator const& collision, aod::BcFullInfos const& bcs) { selectCollision(collision, bcs); @@ -275,7 +276,7 @@ struct HfTrackIndexSkimCreatorTagSelCollisions { PROCESS_SWITCH(HfTrackIndexSkimCreatorTagSelCollisions, processNoTrigSel, "Do not use trigger selection", true); /// Event selection with UPC - void processUpcSel(soa::Join::iterator const& collision, + void processUpcSel(soa::Join::iterator const& collision, aod::BcFullInfos const& bcs, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0as*/, @@ -1694,9 +1695,6 @@ struct HfTrackIndexSkimCreator { const std::vector ptBinsMl{0., 1.e10}; const std::vector cutDirMl{o2::cuts_ml::CutDirection::CutGreater, o2::cuts_ml::CutDirection::CutSmaller, o2::cuts_ml::CutDirection::CutSmaller}; const std::array, kN3ProngDecaysUsedMlForHfFilters> thresholdMlScore3Prongs{config.thresholdMlScoreDplusToPiKPi, config.thresholdMlScoreLcToPiKP, config.thresholdMlScoreDsToPiKK, config.thresholdMlScoreXicToPiKP}; - const std::vector inputFeatures2Prongs = {"ptProng0", "dcaXyProng0", "dcaZProng0", "ptProng1", "dcaXyProng1", "dcaZProng1"}; - const std::vector inputFeatures3Prongs = {"ptProng0", "dcaXyProng0", "dcaZProng0", "ptProng1", "dcaXyProng1", "dcaZProng1", "ptProng2", "dcaXyProng2", "dcaZProng2"}; - const std::vector inputFeatures3ProngsWithPid = {"ptProng0", "dcaXyProng0", "dcaZProng0", "ptProng1", "dcaXyProng1", "dcaZProng1", "ptProng2", "dcaXyProng2", "dcaZProng2", "tpcNSigmaPrProng0", "tpcNSigmaPrProng2", "tpcNSigmaPiProng0", "tpcNSigmaPiProng2", "tpcNSigmaKaProng1"}; // initialise 2-prong ML response hfMlResponse2Prongs.configure(ptBinsMl, config.thresholdMlScoreD0ToKPi, cutDirMl, 3); @@ -1706,7 +1704,6 @@ struct HfTrackIndexSkimCreator { } else { hfMlResponse2Prongs.setModelPathsLocal(onnxFileNames2Prongs); } - hfMlResponse2Prongs.cacheInputFeaturesIndices(inputFeatures2Prongs); hfMlResponse2Prongs.init(); // initialise 3-prong ML responses @@ -1722,16 +1719,43 @@ struct HfTrackIndexSkimCreator { } else { hfMlResponse3Prongs[iDecay3P].setModelPathsLocal(onnxFileNames3Prongs[iDecay3P]); } - if ((doprocess2And3ProngsWithPvRefitWithPidForHfFiltersBdt || doprocess2And3ProngsNoPvRefitWithPidForHfFiltersBdt) && iDecay3P == aod::hf_cand_3prong::DecayType::LcToPKPi) { - hfMlResponse3Prongs[iDecay3P].cacheInputFeaturesIndices(inputFeatures3ProngsWithPid); - } else { - hfMlResponse3Prongs[iDecay3P].cacheInputFeaturesIndices(inputFeatures3Prongs); - } hfMlResponse3Prongs[iDecay3P].init(); } } } + /// One track of the collision under study, propagated to that collision's primary vertex. + /// \tparam TTrackIndex is the iterator type of the track-collision associations + /// \tparam TTrack is the iterator type of the track table + template + struct HfPropagatedProng { + TTrackIndex trackIndex; ///< track-collision association, carries isSelProng and isIdentifiedPid + TTrack track; ///< track row + o2::track::TrackParCov trackParVar; ///< track parameters at the PCA to the primary vertex + std::array pVec{}; ///< momentum at the PCA to the primary vertex + std::array dcaInfo{}; ///< DCA (xy, z) to the primary vertex + }; + + /// Fill the per-collision cache of tracks propagated to the collision's primary vertex, so that + /// each track is propagated once per collision instead of once per pair or triplet. + /// \param collision is the collision under study + /// \param trackIndices are the track associations of this collision + /// \param prongs is the cache to be filled, in the order of trackIndices + template + void fillPropagatedProngCache(TCollision const& collision, TTrackIndices const& trackIndices, std::vector& prongs) + { + prongs.clear(); + const auto thisCollId = collision.globalIndex(); + for (auto trackIndex = trackIndices.begin(); trackIndex != trackIndices.end(); ++trackIndex) { + const auto track = trackIndex.template track_as(); + auto& prong = prongs.emplace_back(TProng{trackIndex, track, getTrackParCov(track), track.pVector(), {track.dcaXY(), track.dcaZ()}}); + if (thisCollId != track.collisionId()) { // this is not the "default" collision for this track, we have to re-propagate it + o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, prong.trackParVar, 2.f, noMatCorr, &prong.dcaInfo); + getPxPyPz(prong.trackParVar, prong.pVec); + } + } + } + /// Method to perform selections for 2-prong candidates before vertex reconstruction /// \param pVecTrack0 is the momentum array of the first daughter track /// \param pVecTrack1 is the momentum array of the second daughter track @@ -2071,7 +2095,7 @@ struct HfTrackIndexSkimCreator { /// \param outputScores is the array of vectors with the output scores to be filled /// \param isSelected ia s bitmap with selection outcome template - void applyMlSelectionForHfFilters3Prong(std::vector featuresCand, std::vector featuresCandPid, std::array, kN3ProngDecaysUsedMlForHfFilters>& outputScores, auto& isSelected) + void applyMlSelectionForHfFilters3Prong(std::vector featuresCand, const std::vector& featuresCandPid, std::array, kN3ProngDecaysUsedMlForHfFilters>& outputScores, auto& isSelected) { if (isSelected == 0) { return; @@ -2327,6 +2351,12 @@ struct HfTrackIndexSkimCreator { } */ + // per-collision caches of the tracks propagated to the primary vertex, declared here so that their capacity is reused + using TrackIndexIterator = decltype(positiveFor2And3Prongs->sliceByCached(aod::track::collisionId, 0, cache).begin()); + using PropagatedProng = HfPropagatedProng; + std::vector prongsPos{}; + std::vector prongsNeg{}; + for (const auto& collision : collisions) { /// retrieve PV contributors for the current collision @@ -2406,39 +2436,36 @@ struct HfTrackIndexSkimCreator { std::optionalsliceByCached(aod::track::collisionId, 0, cache))> groupedTrackIndicesSoftPionsPos; std::optionalsliceByCached(aod::track::collisionId, 0, cache))> groupedTrackIndicesSoftPionsNeg; int lastFilledD0 = -1; // index to be filled in table for D* mesons - for (auto trackIndexPos1 = groupedTrackIndicesPos1.begin(); trackIndexPos1 != groupedTrackIndicesPos1.end(); ++trackIndexPos1) { - const auto trackPos1 = trackIndexPos1.template track_as(); + + // propagate each track to this collision's PV once, instead of once per pair or triplet + fillPropagatedProngCache(collision, groupedTrackIndicesPos1, prongsPos); + fillPropagatedProngCache(collision, groupedTrackIndicesNeg1, prongsNeg); + + for (std::size_t iPos1 = 0; iPos1 < prongsPos.size(); ++iPos1) { + const auto& trackIndexPos1 = prongsPos[iPos1].trackIndex; + const auto& trackPos1 = prongsPos[iPos1].track; + const auto& trackParVarPos1 = prongsPos[iPos1].trackParVar; + const auto& pVecTrackPos1 = prongsPos[iPos1].pVec; + const auto& dcaInfoPos1 = prongsPos[iPos1].dcaInfo; // retrieve the selection flag that corresponds to this collision const auto isSelProngPos1 = trackIndexPos1.isSelProng(); const bool sel2ProngStatusPos = TESTBIT(isSelProngPos1, CandidateType::Cand2Prong); const bool sel3ProngStatusPos1 = TESTBIT(isSelProngPos1, CandidateType::Cand3Prong); - auto trackParVarPos1 = getTrackParCov(trackPos1); - std::array pVecTrackPos1{trackPos1.pVector()}; - std::array dcaInfoPos1{trackPos1.dcaXY(), trackPos1.dcaZ()}; - if (thisCollId != trackPos1.collisionId()) { // this is not the "default" collision for this track, we have to re-propagate it - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParVarPos1, 2.f, noMatCorr, &dcaInfoPos1); - getPxPyPz(trackParVarPos1, pVecTrackPos1); - } - // first loop over negative tracks - for (auto trackIndexNeg1 = groupedTrackIndicesNeg1.begin(); trackIndexNeg1 != groupedTrackIndicesNeg1.end(); ++trackIndexNeg1) { - const auto trackNeg1 = trackIndexNeg1.template track_as(); + for (std::size_t iNeg1 = 0; iNeg1 < prongsNeg.size(); ++iNeg1) { + const auto& trackIndexNeg1 = prongsNeg[iNeg1].trackIndex; + const auto& trackNeg1 = prongsNeg[iNeg1].track; + const auto& trackParVarNeg1 = prongsNeg[iNeg1].trackParVar; + const auto& pVecTrackNeg1 = prongsNeg[iNeg1].pVec; + const auto& dcaInfoNeg1 = prongsNeg[iNeg1].dcaInfo; // retrieve the selection flag that corresponds to this collision const auto isSelProngNeg1 = trackIndexNeg1.isSelProng(); const bool sel2ProngStatusNeg = TESTBIT(isSelProngNeg1, CandidateType::Cand2Prong); const bool sel3ProngStatusNeg1 = TESTBIT(isSelProngNeg1, CandidateType::Cand3Prong); - auto trackParVarNeg1 = getTrackParCov(trackNeg1); - std::array pVecTrackNeg1{trackNeg1.pVector()}; - std::array dcaInfoNeg1{trackNeg1.dcaXY(), trackNeg1.dcaZ()}; - if (thisCollId != trackNeg1.collisionId()) { // this is not the "default" collision for this track, we have to re-propagate it - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParVarNeg1, 2.f, noMatCorr, &dcaInfoNeg1); - getPxPyPz(trackParVarNeg1, pVecTrackNeg1); - } - uint isSelected2ProngCand = n2ProngBit; // bitmap for checking status of two-prong candidates (1 is true, 0 is rejected) if (config.debug) { @@ -2646,7 +2673,8 @@ struct HfTrackIndexSkimCreator { if (config.do3Prong && is2ProngCandidateGoodFor3Prong) { // if 3 prongs are enabled and the first 2 tracks are selected for the 3-prong channels // second loop over positive tracks - for (auto trackIndexPos2 = trackIndexPos1 + 1; trackIndexPos2 != groupedTrackIndicesPos1.end(); ++trackIndexPos2) { + for (std::size_t iPos2 = iPos1 + 1; iPos2 < prongsPos.size(); ++iPos2) { + const auto& trackIndexPos2 = prongsPos[iPos2].trackIndex; uint isSelected3ProngCand = n3ProngBit; if (!TESTBIT(trackIndexPos2.isSelProng(), CandidateType::Cand3Prong)) { // continue immediately @@ -2663,18 +2691,13 @@ struct HfTrackIndexSkimCreator { isSelected3ProngCand = 0; } - const auto trackPos2 = trackIndexPos2.template track_as(); - - auto trackParVarPos2 = getTrackParCov(trackPos2); - std::array dcaInfoPos2{trackPos2.dcaXY(), trackPos2.dcaZ()}; + const auto& trackPos2 = prongsPos[iPos2].track; + const auto& trackParVarPos2 = prongsPos[iPos2].trackParVar; + const auto& dcaInfoPos2 = prongsPos[iPos2].dcaInfo; // preselection of 3-prong candidates if (isSelected3ProngCand) { - std::array pVecTrackPos2{trackPos2.pVector()}; - if (thisCollId != trackPos2.collisionId()) { // this is not the "default" collision for this track and we still did not re-propagate it, we have to re-propagate it - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParVarPos2, 2.f, noMatCorr, &dcaInfoPos2); - getPxPyPz(trackParVarPos2, pVecTrackPos2); - } + const auto& pVecTrackPos2 = prongsPos[iPos2].pVec; if (config.debug) { for (int iDecay3P = 0; iDecay3P < kN3ProngDecays; iDecay3P++) { @@ -2921,7 +2944,8 @@ struct HfTrackIndexSkimCreator { } // second loop over negative tracks - for (auto trackIndexNeg2 = trackIndexNeg1 + 1; trackIndexNeg2 != groupedTrackIndicesNeg1.end(); ++trackIndexNeg2) { + for (std::size_t iNeg2 = iNeg1 + 1; iNeg2 < prongsNeg.size(); ++iNeg2) { + const auto& trackIndexNeg2 = prongsNeg[iNeg2].trackIndex; int isSelected3ProngCand = n3ProngBit; if (!TESTBIT(trackIndexNeg2.isSelProng(), CandidateType::Cand3Prong)) { // continue immediately @@ -2938,17 +2962,13 @@ struct HfTrackIndexSkimCreator { isSelected3ProngCand = 0; } - auto trackNeg2 = trackIndexNeg2.template track_as(); - auto trackParVarNeg2 = getTrackParCov(trackNeg2); - std::array dcaInfoNeg2{trackNeg2.dcaXY(), trackNeg2.dcaZ()}; + const auto& trackNeg2 = prongsNeg[iNeg2].track; + const auto& trackParVarNeg2 = prongsNeg[iNeg2].trackParVar; + const auto& dcaInfoNeg2 = prongsNeg[iNeg2].dcaInfo; // preselection of 3-prong candidates if (isSelected3ProngCand) { - std::array pVecTrackNeg2{trackNeg2.pVector()}; - if (thisCollId != trackNeg2.collisionId()) { // this is not the "default" collision for this track and we still did not re-propagate it, we have to re-propagate it - o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, trackParVarNeg2, 2.f, noMatCorr, &dcaInfoNeg2); - getPxPyPz(trackParVarNeg2, pVecTrackNeg2); - } + const auto& pVecTrackNeg2 = prongsNeg[iNeg2].pVec; if (config.debug) { for (int iDecay3P = 0; iDecay3P < kN3ProngDecays; iDecay3P++) { diff --git a/PWGHF/TableProducer/treeCreatorD0ToKPi.cxx b/PWGHF/TableProducer/treeCreatorD0ToKPi.cxx index dbf0b009913..4200d499db8 100644 --- a/PWGHF/TableProducer/treeCreatorD0ToKPi.cxx +++ b/PWGHF/TableProducer/treeCreatorD0ToKPi.cxx @@ -115,6 +115,8 @@ DECLARE_SOA_TABLE(HfCandD0Lites, "AOD", "HFCANDD0LITE", hf_cand::ImpactParameter1, full::ImpactParameterNormalised0, full::ImpactParameterNormalised1, + hf_cand::ImpactParameterZ0, + hf_cand::ImpactParameterZ1, full::NSigTpcPi0, full::NSigTpcKa0, full::NSigTofPi0, @@ -174,6 +176,8 @@ DECLARE_SOA_TABLE(HfCandD0Fulls, "AOD", "HFCANDD0FULL", hf_cand::ImpactParameter1, hf_cand::ErrorImpactParameter0, hf_cand::ErrorImpactParameter1, + hf_cand::ImpactParameterZ0, + hf_cand::ImpactParameterZ1, full::NSigTpcPi0, full::NSigTpcKa0, full::NSigTofPi0, @@ -303,6 +307,8 @@ struct HfTreeCreatorD0ToKPi { candidate.impactParameter1(), candidate.impactParameterNormalised0(), candidate.impactParameterNormalised1(), + candidate.impactParameterZ0(), + candidate.impactParameterZ1(), candidate.nSigTpcPi0(), candidate.nSigTpcKa0(), candidate.nSigTofPi0(), @@ -363,6 +369,8 @@ struct HfTreeCreatorD0ToKPi { candidate.impactParameter1(), candidate.errorImpactParameter0(), candidate.errorImpactParameter1(), + candidate.impactParameterZ0(), + candidate.impactParameterZ1(), candidate.nSigTpcPi0(), candidate.nSigTpcKa0(), candidate.nSigTofPi0(), diff --git a/PWGHF/TableProducer/treeCreatorLcToPKPi.cxx b/PWGHF/TableProducer/treeCreatorLcToPKPi.cxx index 6bf2d001097..7b0eb1f6a24 100644 --- a/PWGHF/TableProducer/treeCreatorLcToPKPi.cxx +++ b/PWGHF/TableProducer/treeCreatorLcToPKPi.cxx @@ -144,8 +144,8 @@ DECLARE_SOA_COLUMN(Chi2Topo, chi2Topo, float); //! chi DECLARE_SOA_COLUMN(DecayLength, decayLength, float); //! decay length, cm DECLARE_SOA_COLUMN(DecayLengthError, decayLengthError, float); //! decay length error DECLARE_SOA_COLUMN(DecayLengthNormalised, decayLengthNormalised, float); //! decay length over its error -DECLARE_SOA_COLUMN(T, t, float); //! proper lifetime, ps -DECLARE_SOA_COLUMN(ErrT, errT, float); //! lifetime error +DECLARE_SOA_COLUMN(T, t, float); //! proper decay time, ps +DECLARE_SOA_COLUMN(ErrT, errT, float); //! decay time error DECLARE_SOA_COLUMN(MassInv, massInv, float); //! invariant mass DECLARE_SOA_COLUMN(P, p, float); //! momentum DECLARE_SOA_COLUMN(Pt, pt, float); //! transverse momentum @@ -183,7 +183,7 @@ DECLARE_SOA_COLUMN(XDecay, xDecay, float); //! Secondary (decay) vertex X coordi DECLARE_SOA_COLUMN(YDecay, yDecay, float); //! Secondary (decay) vertex Y coordinate, cm DECLARE_SOA_COLUMN(ZDecay, zDecay, float); //! Secondary (decay) vertex Z coordinate, cm DECLARE_SOA_COLUMN(LDecay, lDecay, float); //! Decay length, cm (distance between PV and SV, curvature is neglected) -DECLARE_SOA_COLUMN(TDecay, tDecay, float); //! Proper lifetime, ps +DECLARE_SOA_COLUMN(TDecay, tDecay, float); //! Proper decay time, ps DECLARE_SOA_COLUMN(XEvent, xEvent, float); //! Primary (event) vertex X coordinate, cm DECLARE_SOA_COLUMN(YEvent, yEvent, float); //! Primary (event) vertex Y coordinate, cm DECLARE_SOA_COLUMN(ZEvent, zEvent, float); //! Primary (event) vertex Z coordinate, cm @@ -412,7 +412,6 @@ struct HfTreeCreatorLcToPKPi { constexpr static float UndefValueFloat = -999.f; constexpr static int UndefValueInt = -999; - constexpr static float NanoToPico = 1000.f; using TracksWPid = soa::Join; using Cents = soa::Join; @@ -420,9 +419,9 @@ struct HfTreeCreatorLcToPKPi { // number showing MC status of the candidate (signal or background, prompt or non-prompt etc.) enum SigBgStatus : int { Background = 0, // combinatorial background, at least one of the prongs do not originate from the Lc decay - Prompt, // signal with Lc produced directly in the event - NonPrompt, // signal with Lc produced aftewards the event, e.g. during decay of beauty particle - WrongOrder, // all the prongs are from Lc decay, but proton and pion hypothesis are swapped + Prompt = 1, // signal with Lc produced directly in the event + NonPrompt = 2, // signal with Lc produced aftewards the event, e.g. during decay of beauty particle + WrongOrder = 3, // all the prongs are from Lc decay, but proton and pion hypothesis are swapped Default = -1 // impossible, should not be the case, to catch logical error if any }; @@ -911,7 +910,7 @@ struct HfTreeCreatorLcToPKPi { const float deltaP = std::sqrt(pt * pt * deltaPt * deltaPt + candidate.kfPz() * candidate.kfPz() * candidate.kfErrorPz() * candidate.kfErrorPz()) / p; - const float lifetime = decayLength * static_cast(MassLambdaCPlus) / LightSpeedCm2PS / p; + const float decayTime = decayLength * static_cast(MassLambdaCPlus) / LightSpeedCm2PS / p; const float deltaT = dl * static_cast(MassLambdaCPlus) / LightSpeedCm2PS / p; rowCandidateKF( svX, svY, svZ, svErrX, svErrY, svErrZ, @@ -919,7 +918,7 @@ struct HfTreeCreatorLcToPKPi { chi2primProton, chi2primKaon, chi2primPion, dcaProtonKaon, dcaProtonPion, dcaPionKaon, chi2GeoProtonKaon, chi2GeoProtonPion, chi2GeoPionKaon, - chi2Geo, chi2Topo, decayLength, dl, decayLength / dl, lifetime, deltaT, + chi2Geo, chi2Topo, decayLength, dl, decayLength / dl, decayTime, deltaT, mass, p, pt, deltaP, deltaPt, functionSelection, sigbgstatus, collision.multNTracksPV(), @@ -953,7 +952,7 @@ struct HfTreeCreatorLcToPKPi { fillEventProperties(collisions); - const int64_t candidatesSize = static_cast(candidates.size()); + const auto candidatesSize = static_cast(candidates.size()); reserveTables(candidatesSize, IsMc); int iCand{0}; @@ -983,7 +982,7 @@ struct HfTreeCreatorLcToPKPi { fillKFTable(candidate, collision, candFlag, functionSelection, sigbgstatus); } if (fillCandidateMcTable) { - float p{}, pt{}, svX{}, svY{}, svZ{}, pvX{}, pvY{}, pvZ{}, decayLength{}, lifetime{}; + float p{}, pt{}, svX{}, svY{}, svZ{}, pvX{}, pvY{}, pvZ{}, decayLength{}, decayTime{}; if (!isMcCandidateSignal) { p = UndefValueFloat; pt = UndefValueFloat; @@ -994,7 +993,7 @@ struct HfTreeCreatorLcToPKPi { pvY = UndefValueFloat; pvZ = UndefValueFloat; decayLength = UndefValueFloat; - lifetime = UndefValueFloat; + decayTime = UndefValueFloat; } else { const auto mcParticleProng0 = candidate.template prong0_as>().template mcParticle_as>(); const auto indexMother = RecoDecay::getMother(particles, mcParticleProng0, o2::constants::physics::Pdg::kLambdaCPlus, true); @@ -1002,8 +1001,6 @@ struct HfTreeCreatorLcToPKPi { const auto mcCollision = particleMother.template mcCollision_as(); p = particleMother.p(); pt = particleMother.pt(); - const float p2m = p / static_cast(MassLambdaCPlus); - const float gamma = std::sqrt(1 + p2m * p2m); // mother's particle Lorentz factor pvX = mcCollision.posX(); pvY = mcCollision.posY(); pvZ = mcCollision.posZ(); @@ -1011,11 +1008,11 @@ struct HfTreeCreatorLcToPKPi { svY = mcParticleProng0.vy(); svZ = mcParticleProng0.vz(); decayLength = static_cast(RecoDecay::distance(std::array{svX, svY, svZ}, std::array{pvX, pvY, pvZ})); - lifetime = mcParticleProng0.vt() * NanoToPico / gamma; // from ns to ps * from lab time to proper time + decayTime = decayLength * static_cast(MassLambdaCPlus) / LightSpeedCm2PS / p; } rowCandidateMC( p, pt, - svX, svY, svZ, decayLength, lifetime, + svX, svY, svZ, decayLength, decayTime, pvX, pvY, pvZ); } } @@ -1032,16 +1029,14 @@ struct HfTreeCreatorLcToPKPi { const auto mcDaughter0 = particle.template daughters_as>().begin(); const auto mcCollision = particle.template mcCollision_as(); const auto p = particle.p(); - const float p2m = p / static_cast(MassLambdaCPlus); - const float gamma = std::sqrt(1 + p2m * p2m); // mother's particle Lorentz factor const float pvX = mcCollision.posX(); const float pvY = mcCollision.posY(); const float pvZ = mcCollision.posZ(); const float svX = mcDaughter0.vx(); const float svY = mcDaughter0.vy(); const float svZ = mcDaughter0.vz(); - const float l = static_cast(RecoDecay::distance(std::array{svX, svY, svZ}, std::array{pvX, pvY, pvZ})); - const float t = mcDaughter0.vt() * NanoToPico / gamma; // from ns to ps * from lab time to proper time + const float decayLength = static_cast(RecoDecay::distance(std::array{svX, svY, svZ}, std::array{pvX, pvY, pvZ})); + const float decayTime = decayLength * static_cast(MassLambdaCPlus) / LightSpeedCm2PS / p; rowCandidateFullParticles( particle.pt(), particle.eta(), @@ -1050,7 +1045,7 @@ struct HfTreeCreatorLcToPKPi { particle.flagMcMatchGen(), particle.originMcGen(), p, - svX, svY, svZ, l, t, + svX, svY, svZ, decayLength, decayTime, pvX, pvY, pvZ); } } diff --git a/PWGHF/TableProducer/treeCreatorXicToXiPiPi.cxx b/PWGHF/TableProducer/treeCreatorXicToXiPiPi.cxx index a80f2df5af5..b407f3b51be 100644 --- a/PWGHF/TableProducer/treeCreatorXicToXiPiPi.cxx +++ b/PWGHF/TableProducer/treeCreatorXicToXiPiPi.cxx @@ -197,27 +197,20 @@ DECLARE_SOA_TABLE(HfCandXicToXiPiPiLiteMLs, "AOD", "HFXICXI2PIMLITE", full::CandidateSelFlag, full::Y, full::Eta, - full::Phi, full::P, full::Pt, full::M, - hf_cand_xic_to_xi_pi_pi::InvMassXi, - hf_cand_xic_to_xi_pi_pi::InvMassLambda, full::DecayLength, - full::DecayLengthXY, full::Cpa, - full::CpaXY, - hf_cand_xic_to_xi_pi_pi::CpaXi, - hf_cand_xic_to_xi_pi_pi::CpaXYXi, - hf_cand_xic_to_xi_pi_pi::CpaLambda, - hf_cand_xic_to_xi_pi_pi::CpaXYLambda, - full::ImpactParameterXi, - full::ImpactParameterNormalisedXi, full::ImpactParameterPi0, full::ImpactParameterNormalisedPi0, full::ImpactParameterPi1, full::ImpactParameterNormalisedPi1, - full::MaxNormalisedDeltaIP, + hf_cand_xic_to_xi_pi_pi::NSigTpcPiFromXicPlus0, + hf_cand_xic_to_xi_pi_pi::NSigTpcPiFromXicPlus1, + hf_cand_xic_to_xi_pi_pi::NSigTpcBachelorPi, + hf_cand_xic_to_xi_pi_pi::NSigTpcPiFromLambda, + hf_cand_xic_to_xi_pi_pi::NSigTpcPrFromLambda, full::MlScoreBkg, full::MlScorePrompt, full::MlScoreNonPrompt); @@ -702,27 +695,20 @@ struct HfTreeCreatorXicToXiPiPi { candidate.isSelXicToXiPiPi(), candidate.y(o2::constants::physics::MassXiCPlus), candidate.eta(), - candidate.phi(), candidate.p(), candidate.pt(), candidate.invMassXicPlus(), - candidate.invMassXi(), - candidate.invMassLambda(), candidate.decayLength(), - candidate.decayLengthXY(), candidate.cpa(), - candidate.cpaXY(), - candidate.cpaXi(), - candidate.cpaXYXi(), - candidate.cpaLambda(), - candidate.cpaXYLambda(), - candidate.impactParameter0(), - candidate.impactParameterNormalised0(), candidate.impactParameter1(), candidate.impactParameterNormalised1(), candidate.impactParameter2(), candidate.impactParameterNormalised2(), - candidate.maxNormalisedDeltaIP(), + candidate.nSigTpcPiFromXicPlus0(), + candidate.nSigTpcPiFromXicPlus1(), + candidate.nSigTpcBachelorPi(), + candidate.nSigTpcPiFromLambda(), + candidate.nSigTpcPrFromLambda(), mlScoreBkg, mlScorePrompt, mlScoreNonPrompt); diff --git a/PWGHF/Tasks/taskMcEfficiency.cxx b/PWGHF/Tasks/taskMcEfficiency.cxx index dc9b708dfeb..246732243d2 100644 --- a/PWGHF/Tasks/taskMcEfficiency.cxx +++ b/PWGHF/Tasks/taskMcEfficiency.cxx @@ -118,7 +118,7 @@ struct HfTaskMcEfficiency { } template - bool checkTrack(T track) + bool checkTrack(const T& track) { // TODO configurable? return track.isGlobalTrackWoDCA(); @@ -424,7 +424,7 @@ struct HfTaskMcEfficiency { } template - void candidate2ProngMcLoop(C const& candidates, TracksWithSelectionMC const& tracks, aod::McParticles const& mcParticles, aod::McCollisionLabels const&, std::vector pdgCodes) + void candidate2ProngMcLoop(C const& candidates, TracksWithSelectionMC const& tracks, aod::McParticles const& mcParticles, aod::McCollisionLabels const&, const std::vector& pdgCodes) { candidate2ProngLoop(candidates, tracks, mcParticles, pdgCodes); @@ -537,7 +537,7 @@ struct HfTaskMcEfficiency { /// 3-prong analyses template - void candidate3ProngMcLoop(C const& candidates, TracksWithSelectionMC const& tracks, aod::McParticles const& mcParticles, aod::McCollisionLabels const&, std::vector pdgCodes) + void candidate3ProngMcLoop(C const& candidates, TracksWithSelectionMC const& tracks, aod::McParticles const& mcParticles, aod::McCollisionLabels const&, const std::vector& pdgCodes) { candidate3ProngLoop(candidates, tracks, mcParticles, pdgCodes); diff --git a/PWGHF/Tasks/taskMcValidation.cxx b/PWGHF/Tasks/taskMcValidation.cxx index 242565b20b4..3167bcd8f69 100644 --- a/PWGHF/Tasks/taskMcValidation.cxx +++ b/PWGHF/Tasks/taskMcValidation.cxx @@ -30,6 +30,7 @@ #include "Common/DataModel/Centrality.h" #include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/TrackSelectionTables.h" #include @@ -220,9 +221,9 @@ constexpr std::string_view OriginNames[NOriginTypes] = {"Prompt", "NonPrompt"}; struct HfTaskMcValidationGen { using BCsInfo = soa::Join; - using CollisionsNoCents = soa::Join; - using CollisionsFT0Cs = soa::Join; - using CollisionsFT0Ms = soa::Join; + using CollisionsNoCents = soa::Join; + using CollisionsFT0Cs = soa::Join; + using CollisionsFT0Ms = soa::Join; using McCollisionsCentFT0Ms = soa::Join; PresliceUnsorted colPerMcCollision = aod::mccollisionlabel::mcCollisionId; PresliceUnsorted colPerMcCollisionFT0C = aod::mccollisionlabel::mcCollisionId; @@ -735,9 +736,9 @@ struct HfTaskMcValidationRec { using HfCand2ProngWithMCRec = soa::Join; using HfCand3ProngWithMCRec = soa::Join; using CandMcGen = soa::Join; - using CollisionsWithMCLabels = soa::Join; - using CollisionsWithMCLabelsAndCentFT0C = soa::Join; - using CollisionsWithMCLabelsAndCentFT0M = soa::Join; + using CollisionsWithMCLabels = soa::Join; + using CollisionsWithMCLabelsAndCentFT0C = soa::Join; + using CollisionsWithMCLabelsAndCentFT0M = soa::Join; using TracksWithSel = soa::Join; Partition tracksFilteredGlobalTrackWoDCA = requireGlobalTrackWoDCAInFilter(); @@ -1154,8 +1155,8 @@ struct HfTaskMcValidationRec { aod::McCollisions const&, aod::BCsWithTimestamps const&, Coll const& collisions, - Preslice cand2ProngsPerCollision, - Preslice cand3ProngsPerCollision) + const Preslice& cand2ProngsPerCollision, + const Preslice& cand3ProngsPerCollision) { // loop over collisions for (const auto& collision : collisions) { diff --git a/PWGHF/Tasks/taskPidStudies.cxx b/PWGHF/Tasks/taskPidStudies.cxx index 3c9bd0de808..b83bb3dd569 100644 --- a/PWGHF/Tasks/taskPidStudies.cxx +++ b/PWGHF/Tasks/taskPidStudies.cxx @@ -25,6 +25,7 @@ #include "Common/Core/ZorroSummary.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" @@ -203,8 +204,8 @@ struct HfTaskPidStudies { using PidTracks = soa::Join; - using CollSels = soa::Join; - using CollisionsMc = soa::Join; + using CollSels = soa::Join; + using CollisionsMc = soa::Join; using V0sMcRec = soa::Join; using CascsMcRec = soa::Join; diff --git a/PWGHF/Utils/utilsEvSelHf.h b/PWGHF/Utils/utilsEvSelHf.h index dfd1d848306..7ce2b179dad 100644 --- a/PWGHF/Utils/utilsEvSelHf.h +++ b/PWGHF/Utils/utilsEvSelHf.h @@ -109,6 +109,7 @@ enum EventRejection { IsGoodZvtxFT0vsPV, NoSameBunchPileup, Occupancy, + Inel0, NContrib, NoCollInTimeRangeNarrow, NoCollInTimeRangeStandard, @@ -169,6 +170,7 @@ void setEventRejectionLabels(Histo& hRejection, std::string const& softwareTrigg hRejection->GetXaxis()->SetBinLabel(EventRejection::IsGoodZvtxFT0vsPV + 1, "PV #it{z} consistency FT0 timing"); hRejection->GetXaxis()->SetBinLabel(EventRejection::NoSameBunchPileup + 1, "No same-bunch pile-up"); // POTENTIALLY BAD FOR BEAUTY ANALYSES hRejection->GetXaxis()->SetBinLabel(EventRejection::Occupancy + 1, "Occupancy"); + hRejection->GetXaxis()->SetBinLabel(EventRejection::Inel0 + 1, "INEL > 0"); hRejection->GetXaxis()->SetBinLabel(EventRejection::NContrib + 1, "# of PV contributors"); hRejection->GetXaxis()->SetBinLabel(EventRejection::Chi2 + 1, "PV #it{#chi}^{2}"); hRejection->GetXaxis()->SetBinLabel(EventRejection::PositionZ + 1, "PV #it{z}"); @@ -193,6 +195,7 @@ struct HfEventSelection : o2::framework::ConfigurableGroup { o2::framework::Configurable occEstimator{"occEstimator", 1, "Occupancy estimation (1: ITS, 2: FT0C)"}; o2::framework::Configurable occupancyMin{"occupancyMin", 0, "Minimum occupancy"}; o2::framework::Configurable occupancyMax{"occupancyMax", 1000000, "Maximum occupancy"}; + o2::framework::Configurable requireINEL0{"requireINEL0", false, "Require INEL > 0"}; o2::framework::Configurable nPvContributorsMin{"nPvContributorsMin", 0, "Minimum number of PV contributors"}; o2::framework::Configurable chi2PvMax{"chi2PvMax", -1.f, "Maximum PV chi2"}; o2::framework::Configurable zPvPosMin{"zPvPosMin", -10.f, "Minimum PV posZ (cm)"}; @@ -211,9 +214,9 @@ struct HfEventSelection : o2::framework::ConfigurableGroup { o2::framework::Configurable rctCheckZDC{"rctCheckZDC", false, "RCT flag to check whether the ZDC is present or not"}; o2::framework::Configurable rctTreatLimitedAcceptanceAsBad{"rctTreatLimitedAcceptanceAsBad", false, "RCT flag to reject events with limited acceptance for selected detectors"}; o2::framework::Configurable irSource{"irSource", "", "Estimator of the interaction rate (Empty: automatically set. Otherwise recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; - o2::framework::Configurable useUpcZdcTimeCut{"useUpcZdcTimeCut", true, "Apply ZDC time selection for UPC neutron class"}; - o2::framework::Configurable upcZdcTimeMin{"upcZdcTimeMin", -2.f, "Minimum ZDC time for UPC neutron class selection (ns)"}; - o2::framework::Configurable upcZdcTimeMax{"upcZdcTimeMax", 2.f, "Maximum ZDC time for UPC neutron class selection (ns)"}; + o2::framework::Configurable useUpcZdcTimeCut{"useUpcZdcTimeCut", false, "Apply ZDC time selection for UPC neutron class (only relevant for UPC event selection)"}; + o2::framework::Configurable upcZdcTimeMin{"upcZdcTimeMin", -2.f, "Minimum ZDC time for UPC neutron class selection (ns) (only relevant for UPC event selection)"}; + o2::framework::Configurable upcZdcTimeMax{"upcZdcTimeMax", 2.f, "Maximum ZDC time for UPC neutron class selection (ns) (only relevant for UPC event selection)"}; // SG selector SGSelector sgSelector; @@ -401,6 +404,11 @@ struct HfEventSelection : o2::framework::ConfigurableGroup { } } + /// INEL > 0 + if (requireINEL0 && !collision.isInelGt0()) { + SETBIT(rejectionMask, EventRejection::Inel0); + } + /// number of PV contributors if (collision.numContrib() < nPvContributorsMin) { SETBIT(rejectionMask, EventRejection::NContrib); diff --git a/PWGJE/Core/JetBkgSubUtils.cxx b/PWGJE/Core/JetBkgSubUtils.cxx index 91254ddf7a8..b384ae59d75 100644 --- a/PWGJE/Core/JetBkgSubUtils.cxx +++ b/PWGJE/Core/JetBkgSubUtils.cxx @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -41,7 +42,7 @@ JetBkgSubUtils::JetBkgSubUtils(float jetBkgR_out, float bkgEtaMin_out, float bkg constSubAlpha(constSubAlpha_out), constSubRMax(constSubRMax_out), nHardReject(nHardReject_out), - ghostAreaSpec(ghostAreaSpec_out) + ghostAreaSpec(std::move(ghostAreaSpec_out)) { } @@ -162,11 +163,11 @@ std::vector JetBkgSubUtils::doJetConstSub(std::vector #include +#include #include #include @@ -107,7 +108,7 @@ class JetBkgSubUtils constSubRMax = rmax_out; } void setDoRhoMassSub(bool doMSub_out = true) { doRhoMassSub = doMSub_out; } - void setGhostAreaSpec(fastjet::GhostedAreaSpec ghostAreaSpec_out) { ghostAreaSpec = ghostAreaSpec_out; } + void setGhostAreaSpec(fastjet::GhostedAreaSpec ghostAreaSpec_out) { ghostAreaSpec = std::move(ghostAreaSpec_out); } // Getters float getJetBkgR() const { return jetBkgR; } @@ -124,7 +125,7 @@ class JetBkgSubUtils fastjet::Selector getRhoSelector() const { return selRho; } // Calculate the jet mass - double getMd(fastjet::PseudoJet jet) const; + double getMd(const fastjet::PseudoJet& jet) const; protected: float jetBkgR = 0.2; diff --git a/PWGJE/Core/JetDerivedDataUtilities.h b/PWGJE/Core/JetDerivedDataUtilities.h index 0195ca3df07..035293a9b7d 100644 --- a/PWGJE/Core/JetDerivedDataUtilities.h +++ b/PWGJE/Core/JetDerivedDataUtilities.h @@ -63,7 +63,7 @@ enum JCollisionSubGeneratorId { }; template -bool selectCollision(T const& collision, const std::vector& eventSelectionMaskBits, bool skipMBGapEvents = true, bool rctSelection = true, std::string rctLabel = "CBT_hadronPID", bool rejectLimitedAcceptanceRct = false, bool requireZDCRct = false) +bool selectCollision(T const& collision, const std::vector& eventSelectionMaskBits, bool skipMBGapEvents = true, bool rctSelection = true, const std::string& rctLabel = "CBT_hadronPID", bool rejectLimitedAcceptanceRct = false, bool requireZDCRct = false) { if (skipMBGapEvents && collision.getSubGeneratorId() == JCollisionSubGeneratorId::mbGap) { @@ -96,7 +96,7 @@ bool selectCollision(T const& collision, const std::vector& eventSelectionM return !isOrCondition; } -bool eventSelectionMasksContainSelection(const std::string& eventSelectionMasks, std::string selection) +bool eventSelectionMasksContainSelection(const std::string& eventSelectionMasks, const std::string& selection) { size_t position = 0; while ((position = eventSelectionMasks.find(selection, position)) != std::string::npos) { @@ -325,7 +325,7 @@ bool selectTrigger(T const& collision, int triggerMaskBit) return collision.triggerSel() & (1ULL << triggerMaskBit); } -bool triggerMasksContainTrigger(const std::string& triggerMasks, std::string trigger) +bool triggerMasksContainTrigger(const std::string& triggerMasks, const std::string& trigger) { size_t position = 0; while ((position = triggerMasks.find(trigger, position)) != std::string::npos) { @@ -733,7 +733,7 @@ bool selectTrackDcaZ(T const& track, double dcaZmax = 99.) return std::abs(track.dcaZ()) < dcaZmax; } -std::vector initialiseClusterDefinitions(const std::string clusterDefinitions) +std::vector initialiseClusterDefinitions(const std::string& clusterDefinitions) { std::vector clusterDefinitionsVec; if (clusterDefinitions.empty()) { diff --git a/PWGJE/Core/JetFinder.cxx b/PWGJE/Core/JetFinder.cxx index c3c2d091908..0434e5cfa4a 100644 --- a/PWGJE/Core/JetFinder.cxx +++ b/PWGJE/Core/JetFinder.cxx @@ -48,6 +48,11 @@ void JetFinder::setParams() jetDef.set_jet_algorithm(algorithm); areaDef = fastjet::AreaDefinition(areaType, ghostAreaSpec); selJets = fastjet::SelectorPtRange(jetPtMin, jetPtMax) && fastjet::SelectorEtaRange(jetEtaMin, jetEtaMax) && fastjet::SelectorPhiRange(jetPhiMin, jetPhiMax); + + if (phiExclusionMin > -998.0) { + // automatically jets around exclusion region + selJets = selJets && (!fastjet::SelectorPhiRange(phiExclusionMin - jetR, phiExclusionMax + jetR)); + } } /// Performs jet finding diff --git a/PWGJE/Core/JetFinder.h b/PWGJE/Core/JetFinder.h index 8f727bbdbbd..90b9a981f6a 100644 --- a/PWGJE/Core/JetFinder.h +++ b/PWGJE/Core/JetFinder.h @@ -50,6 +50,8 @@ class JetFinder float phiMin = -1. * M_PI; float phiMax = 2. * M_PI; + float phiExclusionMin = -999.; + float phiExclusionMax = 999.; float etaMin = -.9; float etaMax = .9; diff --git a/PWGJE/Core/JetFindingUtilities.h b/PWGJE/Core/JetFindingUtilities.h index 37ca4eddaa5..9d03d9e9054 100644 --- a/PWGJE/Core/JetFindingUtilities.h +++ b/PWGJE/Core/JetFindingUtilities.h @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -136,14 +137,19 @@ template void analyseTracksMultipleCandidates(std::vector& inputParticles, T const& tracks, int trackSelection, U const& candidates) { for (auto& track : tracks) { + bool isSelected = true; if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { continue; } for (auto& candidate : candidates) { if (jetcandidateutilities::isDaughterTrack(track, candidate)) { - continue; + isSelected = false; + break; } } + if (!isSelected) { + continue; + } fastjetutilities::fillTracks(track, inputParticles, track.globalIndex()); } } @@ -278,9 +284,9 @@ bool analyseV0s(std::vector& inputParticles, T const& v0s, f * @param doHFJetFinding set whether only jets containing a HF candidate are saved */ template -void findJets(JetFinder& jetFinder, std::vector& inputParticles, float jetPtMin, float jetPtMax, std::vector jetRadius, float jetAreaFractionMin, T const& collision, U& jetsTable, V& constituentsTable, std::shared_ptr thnSparseJet, bool fillThnSparse, bool doCandidateJetFinding = false) +void findJets(JetFinder& jetFinder, std::vector& inputParticles, float jetPtMin, float jetPtMax, std::vector jetRadius, float jetAreaFractionMin, T const& collision, U& jetsTable, V& constituentsTable, const std::shared_ptr& thnSparseJet, bool fillThnSparse, bool doCandidateJetFinding = false) { - auto jetRValues = static_cast>(jetRadius); + auto jetRValues = static_cast>(std::move(jetRadius)); jetFinder.jetPtMin = jetPtMin; jetFinder.jetPtMax = jetPtMax; for (auto R : jetRValues) { @@ -375,19 +381,25 @@ void analyseParticles(std::vector& inputParticles, const std } } } + bool isSelected = true; if constexpr (jetv0utilities::isV0McTable()) { // note that for V0s the candidate table is given to this function, not a single candidate if (candidate != nullptr) { for (auto const& cand : (*candidate)) { if (cand.mcParticleId() == particle.globalIndex()) { - continue; + isSelected = false; + break; } auto v0Particle = cand.template mcParticle_as(); if (jetcandidateutilities::isDaughterParticle(v0Particle, particle.globalIndex())) { - continue; + isSelected = false; + break; } } } } + if (!isSelected) { + continue; + } fastjetutilities::fillTracks(particle, inputParticles, particle.globalIndex(), JetConstituentStatus::track, pdgParticle->Mass()); } } diff --git a/PWGJE/Core/MlResponseHfTagging.h b/PWGJE/Core/MlResponseHfTagging.h index 4740a087a79..b144d6e145a 100644 --- a/PWGJE/Core/MlResponseHfTagging.h +++ b/PWGJE/Core/MlResponseHfTagging.h @@ -34,10 +34,9 @@ // Fill the map of available input features // the key is the feature's name (std::string) // the value is the corresponding value in EnumInputFeatures -#define FILL_MAP_BJET(FEATURE) \ - { \ - #FEATURE, static_cast(InputFeaturesBTag::FEATURE) \ - } +#define FILL_MAP_BJET(FEATURE) \ + { \ + #FEATURE, static_cast(InputFeaturesBTag::FEATURE)} // Check if the index of mCachedIndices (index associated to a FEATURE) // matches the entry in EnumInputFeatures associated to this FEATURE @@ -424,7 +423,7 @@ class GNNBjetAllocator : public TensorAllocator public: GNNBjetAllocator() : TensorAllocator(), nJetFeat(4), nTrkFeat(13), nFlav(3), nTrkOrigin(5), maxNNodes(40), tfFunc([](float x) { return x; }) {} - GNNBjetAllocator(int64_t nJetFeat, int64_t nTrkFeat, int64_t nFlav, int64_t nTrkOrigin, std::vector& tfJetMean, std::vector& tfJetStdev, std::vector& tfTrkMean, std::vector& tfTrkStdev, int64_t maxNNodes = 40, std::string tfFuncType = "linear") + GNNBjetAllocator(int64_t nJetFeat, int64_t nTrkFeat, int64_t nFlav, int64_t nTrkOrigin, std::vector& tfJetMean, std::vector& tfJetStdev, std::vector& tfTrkMean, std::vector& tfTrkStdev, int64_t maxNNodes = 40, const std::string& tfFuncType = "linear") : TensorAllocator(), nJetFeat(nJetFeat), nTrkFeat(nTrkFeat), nFlav(nFlav), nTrkOrigin(nTrkOrigin), maxNNodes(maxNNodes), tfJetMean(tfJetMean), tfJetStdev(tfJetStdev), tfTrkMean(tfTrkMean), tfTrkStdev(tfTrkStdev), tfFunc([](float x) { return x; }) { if (tfFuncType == "asinh") { diff --git a/PWGJE/DataModel/EMCALClusterDefinition.h b/PWGJE/DataModel/EMCALClusterDefinition.h index 41e87590449..d2278bf7ca7 100644 --- a/PWGJE/DataModel/EMCALClusterDefinition.h +++ b/PWGJE/DataModel/EMCALClusterDefinition.h @@ -16,12 +16,14 @@ #ifndef PWGJE_DATAMODEL_EMCALCLUSTERDEFINITION_H_ #define PWGJE_DATAMODEL_EMCALCLUSTERDEFINITION_H_ +#include #include +#include namespace o2::aod { -enum class ClusterAlgorithm_t { - kV1, +enum class ClusterAlgorithm : uint8_t { + kV1 = 0, kV3 }; /// \struct EMCALClusterDefinition @@ -29,7 +31,7 @@ enum class ClusterAlgorithm_t { /// The cluster definition contains information about the used algorithm, seed threshold, /// cell energy, gradient as well as timing cut struct EMCALClusterDefinition { - ClusterAlgorithm_t algorithm; + ClusterAlgorithm algorithm{ClusterAlgorithm::kV3}; int storageID = -1; // integer ID used to store cluster definition in a flat table int selectedCellType = 1; // EMCal cell type (CURRENTLY NOT USED TO AVOID MULTIPLE CELL LOOPS) std::string name = "kUndefined"; // name of the cluster definition @@ -45,23 +47,11 @@ struct EMCALClusterDefinition { // default constructor EMCALClusterDefinition() = default; // constructor - EMCALClusterDefinition(ClusterAlgorithm_t pAlgorithm, int pStorageID, int pSelectedCellType, std::string pName, double pSeedEnergy, double pMinCellEnergy, double pTimeMin, double pTimeMax, double ptimeDiff, bool pDoGradientCut, double pGradientCut, bool precalcShowerShape5x5) + EMCALClusterDefinition(ClusterAlgorithm pAlgorithm, int pStorageID, int pSelectedCellType, std::string pName, double pSeedEnergy, double pMinCellEnergy, double pTimeMin, double pTimeMax, double ptimeDiff, bool pDoGradientCut, double pGradientCut, bool precalcShowerShape5x5) : algorithm(pAlgorithm), storageID(pStorageID), selectedCellType(pSelectedCellType), name(std::move(pName)), seedEnergy(pSeedEnergy), minCellEnergy(pMinCellEnergy), timeMin(pTimeMin), timeMax(pTimeMax), timeDiff(ptimeDiff), doGradientCut(pDoGradientCut), gradientCut(pGradientCut), recalcShowerShape5x5(precalcShowerShape5x5) { - algorithm = pAlgorithm; - storageID = pStorageID; - selectedCellType = pSelectedCellType; - name = pName; - seedEnergy = pSeedEnergy; - minCellEnergy = pMinCellEnergy; - timeMin = pTimeMin; - timeMax = pTimeMax; - timeDiff = ptimeDiff; - doGradientCut = pDoGradientCut; - gradientCut = pGradientCut; - recalcShowerShape5x5 = precalcShowerShape5x5; } - // implement comparison operators for int std::string and ClusterAlgorithm_t + // implement comparison operators for int std::string and ClusterAlgorithm bool operator==(const EMCALClusterDefinition& rhs) const { return (algorithm == rhs.algorithm && storageID == rhs.storageID && name == rhs.name && seedEnergy == rhs.seedEnergy && minCellEnergy == rhs.minCellEnergy && timeMin == rhs.timeMin && timeMax == rhs.timeMax && timeDiff == rhs.timeDiff && gradientCut == rhs.gradientCut && doGradientCut == rhs.doGradientCut && recalcShowerShape5x5 == rhs.recalcShowerShape5x5); @@ -86,11 +76,11 @@ struct EMCALClusterDefinition { { return !(name == rhs); } - bool operator==(const ClusterAlgorithm_t rhs) const + bool operator==(const ClusterAlgorithm rhs) const { return (algorithm == rhs); } - bool operator!=(const ClusterAlgorithm_t rhs) const + bool operator!=(const ClusterAlgorithm rhs) const { return !(algorithm == rhs); } @@ -106,11 +96,11 @@ struct EMCALClusterDefinition { return name; } - operator ClusterAlgorithm_t() const + operator ClusterAlgorithm() const { return algorithm; } - std::string toString() const + [[nodiscard]] const std::string& toString() const { return name; } diff --git a/PWGJE/DataModel/EMCALClusters.h b/PWGJE/DataModel/EMCALClusters.h index d711a5e08b9..915eecaca51 100644 --- a/PWGJE/DataModel/EMCALClusters.h +++ b/PWGJE/DataModel/EMCALClusters.h @@ -11,7 +11,7 @@ /// \file EMCALClusters.h /// \brief Table definitions for EMCAL analysis clusters -/// \author Raymond Ehlers , ORNL +/// \author Raymond Ehlers , ORNL, Florian Jonas , Marvin Hemmer #ifndef PWGJE_DATAMODEL_EMCALCLUSTERS_H_ #define PWGJE_DATAMODEL_EMCALCLUSTERS_H_ @@ -23,6 +23,7 @@ #include #include +#include #include namespace o2::aod @@ -32,76 +33,112 @@ namespace emcalcluster // define global cluster definitions // New definitions should be added here! -const EMCALClusterDefinition kV3NoSplit(ClusterAlgorithm_t::kV3, 0, 1, "kV3NoSplit", 0.5, 0.1, -10000, 10000, 20000, false, 0., false); -const EMCALClusterDefinition kV3NoSplitLowSeed(ClusterAlgorithm_t::kV3, 1, 1, "kV3NoSplitLowSeed", 0.3, 0.1, -10000, 10000, 20000, false, 0., false); -const EMCALClusterDefinition kV3NoSplitLowerSeed(ClusterAlgorithm_t::kV3, 2, 1, "kV3NoSplitLowerSeed", 0.2, 0.1, -10000, 10000, 20000, false, 0., false); -const EMCALClusterDefinition kV3Default(ClusterAlgorithm_t::kV3, 10, 1, "kV3Default", 0.5, 0.1, -10000, 10000, 20000, true, 0.03, false); -const EMCALClusterDefinition kV3MostSplit(ClusterAlgorithm_t::kV3, 11, 1, "kV3MostSplit", 0.5, 0.1, -10000, 10000, 20000, true, 0., false); -const EMCALClusterDefinition kV3LowSeed(ClusterAlgorithm_t::kV3, 12, 1, "kV3LowSeed", 0.3, 0.1, -10000, 10000, 20000, true, 0.03, false); -const EMCALClusterDefinition kV3MostSplitLowSeed(ClusterAlgorithm_t::kV3, 13, 1, "kV3MostSplitLowSeed", 0.3, 0.1, -10000, 10000, 20000, true, 0., false); -const EMCALClusterDefinition kV3StrictTime(ClusterAlgorithm_t::kV3, 20, 1, "kV3StrictTime", 0.5, 0.1, -500, 500, 20000, true, 0.03, false); -const EMCALClusterDefinition kV3StricterTime(ClusterAlgorithm_t::kV3, 21, 1, "kV3StricterTime", 0.5, 0.1, -100, 100, 20000, true, 0.03, false); -const EMCALClusterDefinition kV3MostStrictTime(ClusterAlgorithm_t::kV3, 22, 1, "kV3MostStrictTime", 0.5, 0.1, -50, 50, 20000, true, 0.03, false); -const EMCALClusterDefinition kV3Default5x5(ClusterAlgorithm_t::kV3, 30, 1, "kV3Default5x5", 0.5, 0.1, -10000, 10000, 20000, true, 0.03, true); -const EMCALClusterDefinition kV3SmallTimeDiff(ClusterAlgorithm_t::kV3, 40, 1, "kV3SmallTimeDiff", 0.5, 0.1, -10000, 10000, 500, true, 0.03, false); -const EMCALClusterDefinition kV3SmallerTimeDiff(ClusterAlgorithm_t::kV3, 41, 1, "kV3SmallerTimeDiff", 0.5, 0.1, -10000, 10000, 100, true, 0.03, false); -const EMCALClusterDefinition kV3SmallestTimeDiff(ClusterAlgorithm_t::kV3, 42, 1, "kV3SmallestTimeDiff", 0.5, 0.1, -10000, 10000, 50, true, 0.03, false); -const EMCALClusterDefinition kV3MostSplitSmallTimeDiff(ClusterAlgorithm_t::kV3, 43, 1, "kV3MostSplitSmallTimeDiff", 0.5, 0.1, -10000, 10000, 500, true, 0., false); -const EMCALClusterDefinition kV3MostSplitSmallerTimeDiff(ClusterAlgorithm_t::kV3, 44, 1, "kV3MostSplitSmallerTimeDiff", 0.5, 0.1, -10000, 10000, 100, true, 0., false); -const EMCALClusterDefinition kV3MostSplitSmallestTimeDiff(ClusterAlgorithm_t::kV3, 45, 1, "kV3MostSplitSmallestTimeDiff", 0.5, 0.1, -10000, 10000, 50, true, 0., false); -const EMCALClusterDefinition kV3MostSplitSmallestTimeDiffLowestSeed(ClusterAlgorithm_t::kV3, 50, 1, "kV3MostSplitSmallestTimeDiffLowestSeed", 0.1, 0.1, -10000, 10000, 50, true, 0., false); -const EMCALClusterDefinition kV3MostSplitSmallestTimeDiffLowSeed(ClusterAlgorithm_t::kV3, 51, 1, "kV3MostSplitSmallestTimeDiffLowSeed", 0.3, 0.1, -10000, 10000, 50, true, 0., false); -const EMCALClusterDefinition kV3MostSplitSmallestTimeDiffLowerSeed(ClusterAlgorithm_t::kV3, 52, 1, "kV3MostSplitSmallestTimeDiffLowerSeed", 0.2, 0.1, -10000, 10000, 50, true, 0., false); +inline const EMCALClusterDefinition kV3NoSplit(ClusterAlgorithm::kV3, 0, 1, "kV3NoSplit", 0.5, 0.1, -10000, 10000, 20000, false, 0., false); +inline const EMCALClusterDefinition kV3NoSplitLowSeed(ClusterAlgorithm::kV3, 1, 1, "kV3NoSplitLowSeed", 0.3, 0.1, -10000, 10000, 20000, false, 0., false); +inline const EMCALClusterDefinition kV3NoSplitLowerSeed(ClusterAlgorithm::kV3, 2, 1, "kV3NoSplitLowerSeed", 0.2, 0.1, -10000, 10000, 20000, false, 0., false); +inline const EMCALClusterDefinition kV3Default(ClusterAlgorithm::kV3, 10, 1, "kV3Default", 0.5, 0.1, -10000, 10000, 20000, true, 0.03, false); +inline const EMCALClusterDefinition kV3MostSplit(ClusterAlgorithm::kV3, 11, 1, "kV3MostSplit", 0.5, 0.1, -10000, 10000, 20000, true, 0., false); +inline const EMCALClusterDefinition kV3LowSeed(ClusterAlgorithm::kV3, 12, 1, "kV3LowSeed", 0.3, 0.1, -10000, 10000, 20000, true, 0.03, false); +inline const EMCALClusterDefinition kV3MostSplitLowSeed(ClusterAlgorithm::kV3, 13, 1, "kV3MostSplitLowSeed", 0.3, 0.1, -10000, 10000, 20000, true, 0., false); +inline const EMCALClusterDefinition kV3StrictTime(ClusterAlgorithm::kV3, 20, 1, "kV3StrictTime", 0.5, 0.1, -500, 500, 20000, true, 0.03, false); +inline const EMCALClusterDefinition kV3StricterTime(ClusterAlgorithm::kV3, 21, 1, "kV3StricterTime", 0.5, 0.1, -100, 100, 20000, true, 0.03, false); +inline const EMCALClusterDefinition kV3MostStrictTime(ClusterAlgorithm::kV3, 22, 1, "kV3MostStrictTime", 0.5, 0.1, -50, 50, 20000, true, 0.03, false); +inline const EMCALClusterDefinition kV3Default5x5(ClusterAlgorithm::kV3, 30, 1, "kV3Default5x5", 0.5, 0.1, -10000, 10000, 20000, true, 0.03, true); +inline const EMCALClusterDefinition kV3SmallTimeDiff(ClusterAlgorithm::kV3, 40, 1, "kV3SmallTimeDiff", 0.5, 0.1, -10000, 10000, 500, true, 0.03, false); +inline const EMCALClusterDefinition kV3SmallerTimeDiff(ClusterAlgorithm::kV3, 41, 1, "kV3SmallerTimeDiff", 0.5, 0.1, -10000, 10000, 100, true, 0.03, false); +inline const EMCALClusterDefinition kV3SmallestTimeDiff(ClusterAlgorithm::kV3, 42, 1, "kV3SmallestTimeDiff", 0.5, 0.1, -10000, 10000, 50, true, 0.03, false); +inline const EMCALClusterDefinition kV3MostSplitSmallTimeDiff(ClusterAlgorithm::kV3, 43, 1, "kV3MostSplitSmallTimeDiff", 0.5, 0.1, -10000, 10000, 500, true, 0., false); +inline const EMCALClusterDefinition kV3MostSplitSmallerTimeDiff(ClusterAlgorithm::kV3, 44, 1, "kV3MostSplitSmallerTimeDiff", 0.5, 0.1, -10000, 10000, 100, true, 0., false); +inline const EMCALClusterDefinition kV3MostSplitSmallestTimeDiff(ClusterAlgorithm::kV3, 45, 1, "kV3MostSplitSmallestTimeDiff", 0.5, 0.1, -10000, 10000, 50, true, 0., false); +inline const EMCALClusterDefinition kV3MostSplitSmallestTimeDiffLowestSeed(ClusterAlgorithm::kV3, 50, 1, "kV3MostSplitSmallestTimeDiffLowestSeed", 0.1, 0.1, -10000, 10000, 50, true, 0., false); +inline const EMCALClusterDefinition kV3MostSplitSmallestTimeDiffLowSeed(ClusterAlgorithm::kV3, 51, 1, "kV3MostSplitSmallestTimeDiffLowSeed", 0.3, 0.1, -10000, 10000, 50, true, 0., false); +inline const EMCALClusterDefinition kV3MostSplitSmallestTimeDiffLowerSeed(ClusterAlgorithm::kV3, 52, 1, "kV3MostSplitSmallestTimeDiffLowerSeed", 0.2, 0.1, -10000, 10000, 50, true, 0., false); + +/// \brief function returns EMCALClusterDefinition for the given storage ID +/// \param storageID storage ID of the cluster definition +/// \return EMCALClusterDefinition for the given storage ID +inline const EMCALClusterDefinition& getClusterDefinitionFromID(int storageID) +{ + switch (storageID) { + case 0: + return kV3NoSplit; + case 1: + return kV3NoSplitLowSeed; + case 2: + return kV3NoSplitLowerSeed; + case 10: + return kV3Default; + case 11: + return kV3MostSplit; + case 12: + return kV3LowSeed; + case 13: + return kV3MostSplitLowSeed; + case 20: + return kV3StrictTime; + case 21: + return kV3StricterTime; + case 22: + return kV3MostStrictTime; + case 30: + return kV3Default5x5; + case 40: + return kV3SmallTimeDiff; + case 41: + return kV3SmallerTimeDiff; + case 42: + return kV3SmallestTimeDiff; + case 43: + return kV3MostSplitSmallTimeDiff; + case 44: + return kV3MostSplitSmallerTimeDiff; + case 45: + return kV3MostSplitSmallestTimeDiff; + case 50: + return kV3MostSplitSmallestTimeDiffLowestSeed; + case 51: + return kV3MostSplitSmallestTimeDiffLowSeed; + case 52: + return kV3MostSplitSmallestTimeDiffLowerSeed; + default: + throw std::invalid_argument("Cluster definition storageID not recognized: " + std::to_string(storageID)); + } +} /// \brief function returns EMCALClusterDefinition for the given name -/// \param name name of the cluster definition +/// \param clusterDefinitionName name of the cluster definition /// \return EMCALClusterDefinition for the given name -inline const EMCALClusterDefinition getClusterDefinitionFromString(const std::string& clusterDefinitionName) +inline const EMCALClusterDefinition& getClusterDefinitionFromString(const std::string& clusterDefinitionName) { - if (clusterDefinitionName == "kV3NoSplit") { - return kV3NoSplit; - } else if (clusterDefinitionName == "kV3NoSplitLowSeed") { - return kV3NoSplitLowSeed; - } else if (clusterDefinitionName == "kV3NoSplitLowerSeed") { - return kV3NoSplitLowerSeed; - } else if (clusterDefinitionName == "kV3Default") { - return kV3Default; - } else if (clusterDefinitionName == "kV3MostSplit") { - return kV3MostSplit; - } else if (clusterDefinitionName == "kV3LowSeed") { - return kV3LowSeed; - } else if (clusterDefinitionName == "kV3MostSplitLowSeed") { - return kV3MostSplitLowSeed; - } else if (clusterDefinitionName == "kV3StrictTime") { - return kV3StrictTime; - } else if (clusterDefinitionName == "kV3StricterTime") { - return kV3StricterTime; - } else if (clusterDefinitionName == "kV3MostStrictTime") { - return kV3MostStrictTime; - } else if (clusterDefinitionName == "kV3Default5x5") { - return kV3Default5x5; - } else if (clusterDefinitionName == "kV3SmallTimeDiff") { - return kV3SmallTimeDiff; - } else if (clusterDefinitionName == "kV3SmallerTimeDiff") { - return kV3SmallerTimeDiff; - } else if (clusterDefinitionName == "kV3SmallestTimeDiff") { - return kV3SmallestTimeDiff; - } else if (clusterDefinitionName == "kV3MostSplitSmallTimeDiff") { - return kV3MostSplitSmallTimeDiff; - } else if (clusterDefinitionName == "kV3MostSplitSmallerTimeDiff") { - return kV3MostSplitSmallerTimeDiff; - } else if (clusterDefinitionName == "kV3MostSplitSmallestTimeDiff") { - return kV3MostSplitSmallestTimeDiff; - } else if (clusterDefinitionName == "kV3MostSplitSmallestTimeDiffLowestSeed") { - return kV3MostSplitSmallestTimeDiffLowestSeed; - } else if (clusterDefinitionName == "kV3MostSplitSmallestTimeDiffLowSeed") { - return kV3MostSplitSmallestTimeDiffLowSeed; - } else if (clusterDefinitionName == "kV3MostSplitSmallestTimeDiffLowerSeed") { - return kV3MostSplitSmallestTimeDiffLowerSeed; - } else { - throw std::invalid_argument("Cluster definition name not recognized"); + static const std::unordered_map nameToID = { + {"kV3NoSplit", 0}, + {"kV3NoSplitLowSeed", 1}, + {"kV3NoSplitLowerSeed", 2}, + {"kV3Default", 10}, + {"kV3MostSplit", 11}, + {"kV3LowSeed", 12}, + {"kV3MostSplitLowSeed", 13}, + {"kV3StrictTime", 20}, + {"kV3StricterTime", 21}, + {"kV3MostStrictTime", 22}, + {"kV3Default5x5", 30}, + {"kV3SmallTimeDiff", 40}, + {"kV3SmallerTimeDiff", 41}, + {"kV3SmallestTimeDiff", 42}, + {"kV3MostSplitSmallTimeDiff", 43}, + {"kV3MostSplitSmallerTimeDiff", 44}, + {"kV3MostSplitSmallestTimeDiff", 45}, + {"kV3MostSplitSmallestTimeDiffLowestSeed", 50}, + {"kV3MostSplitSmallestTimeDiffLowSeed", 51}, + {"kV3MostSplitSmallestTimeDiffLowerSeed", 52}, + }; + + auto it = nameToID.find(clusterDefinitionName); + if (it == nameToID.end()) { + throw std::invalid_argument("Cluster definition name not recognized: " + clusterDefinitionName); } -}; + return getClusterDefinitionFromID(it->second); +} DECLARE_SOA_INDEX_COLUMN(Collision, collision); //! collisionID used as index for matched clusters DECLARE_SOA_INDEX_COLUMN(BC, bc); //! bunch crossing ID used as index for ambiguous clusters diff --git a/PWGJE/DataModel/GammaJetAnalysisTree.h b/PWGJE/DataModel/GammaJetAnalysisTree.h index 5fb142469a2..740c0749a38 100644 --- a/PWGJE/DataModel/GammaJetAnalysisTree.h +++ b/PWGJE/DataModel/GammaJetAnalysisTree.h @@ -73,9 +73,10 @@ namespace gjmcevent DECLARE_SOA_INDEX_COLUMN(GjEvent, gjevent); DECLARE_SOA_COLUMN(Weight, weight, double); DECLARE_SOA_COLUMN(Rho, rho, float); // gen level rho +DECLARE_SOA_COLUMN(PtHard, ptHard, float); // hard-scattering scale DECLARE_SOA_COLUMN(IsMultipleAssigned, isMultipleAssigned, bool); // if the corresponding MC collision matched to this rec collision was also matched to other rec collisions (allows to skip those on analysis level ) } // namespace gjmcevent -DECLARE_SOA_TABLE(GjMCEvents, "AOD", "GJMCEVENT", gjmcevent::GjEventId, gjmcevent::Weight, gjmcevent::Rho, gjmcevent::IsMultipleAssigned) +DECLARE_SOA_TABLE(GjMCEvents, "AOD", "GJMCEVENT", gjmcevent::GjEventId, gjmcevent::Weight, gjmcevent::Rho, gjmcevent::PtHard, gjmcevent::IsMultipleAssigned) // Information about EMCal clusters namespace gjgamma { diff --git a/PWGJE/JetFinders/jetFinder.h b/PWGJE/JetFinders/jetFinder.h index d45cfa15506..493251442b6 100644 --- a/PWGJE/JetFinders/jetFinder.h +++ b/PWGJE/JetFinders/jetFinder.h @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -71,6 +72,8 @@ struct JetFinderTask { o2::framework::Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum track eta"}; o2::framework::Configurable trackPhiMin{"trackPhiMin", -999, "minimum track phi"}; o2::framework::Configurable trackPhiMax{"trackPhiMax", 999, "maximum track phi"}; + o2::framework::Configurable phiExclusionMin{"phiExclusionMin", -999, "minimum of phi exclusion region which is applied for tracks and for jets (jetR is added to the exclusion region for jets)"}; + o2::framework::Configurable phiExclusionMax{"phiExclusionMax", 999, "maximum of phi exclusion region which is applied for tracks and for jets (jetR is added to the exclusion region for jets)"}; o2::framework::Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; o2::framework::Configurable particleSelections{"particleSelections", "PhysicalPrimary", "set particle selections"}; @@ -139,6 +142,15 @@ struct JetFinderTask { jetFinder.phiMin = -1.0 * M_PI; jetFinder.phiMax = 2.0 * M_PI; } + + if (phiExclusionMin > -998.0) { + jetFinder.phiExclusionMin = phiExclusionMin; + jetFinder.phiExclusionMax = phiExclusionMax; + if (phiExclusionMin >= phiExclusionMax) { + throw std::runtime_error("Invalid phi exclusion range: require phiExclusionMin < phiExclusionMax when both are set."); + } + } + jetFinder.jetPhiMin = jetPhiMin; jetFinder.jetPhiMax = jetPhiMax; if (jetPhiMin < -98.0) { @@ -184,8 +196,8 @@ struct JetFinderTask { o2::framework::expressions::Filter collisionFilter = (nabs(o2::aod::jcollision::posZ) < vertexZCut && o2::aod::jcollision::centFT0M >= centralityMin && o2::aod::jcollision::centFT0M < centralityMax && o2::aod::jcollision::trackOccupancyInTimeRange <= trackOccupancyInTimeRangeMax); // should we add a posZ vtx cut here or leave it to analysers? o2::framework::expressions::Filter mcCollisionFilter = (nabs(o2::aod::jmccollision::posZ) < vertexZCut); - o2::framework::expressions::Filter trackCuts = (o2::aod::jtrack::pt >= trackPtMin && o2::aod::jtrack::pt < trackPtMax && o2::aod::jtrack::eta >= trackEtaMin && o2::aod::jtrack::eta <= trackEtaMax && o2::aod::jtrack::phi >= trackPhiMin && o2::aod::jtrack::phi <= trackPhiMax); // do we need eta cut both here and in globalselection? - o2::framework::expressions::Filter partCuts = (o2::aod::jmcparticle::pt >= trackPtMin && o2::aod::jmcparticle::pt < trackPtMax && o2::aod::jmcparticle::eta >= trackEtaMin && o2::aod::jmcparticle::eta <= trackEtaMax && o2::aod::jmcparticle::phi >= trackPhiMin && o2::aod::jmcparticle::phi <= trackPhiMax); + o2::framework::expressions::Filter trackCuts = (o2::aod::jtrack::pt >= trackPtMin && o2::aod::jtrack::pt < trackPtMax && o2::aod::jtrack::eta >= trackEtaMin && o2::aod::jtrack::eta <= trackEtaMax && o2::aod::jtrack::phi >= trackPhiMin && o2::aod::jtrack::phi <= trackPhiMax && (phiExclusionMin < -998.0 || (o2::aod::jtrack::phi <= phiExclusionMin || o2::aod::jtrack::phi >= phiExclusionMax))); // do we need eta cut both here and in globalselection? + o2::framework::expressions::Filter partCuts = (o2::aod::jmcparticle::pt >= trackPtMin && o2::aod::jmcparticle::pt < trackPtMax && o2::aod::jmcparticle::eta >= trackEtaMin && o2::aod::jmcparticle::eta <= trackEtaMax && o2::aod::jmcparticle::phi >= trackPhiMin && o2::aod::jmcparticle::phi <= trackPhiMax && (phiExclusionMin < -998.0 || (o2::aod::jmcparticle::phi <= phiExclusionMin || o2::aod::jmcparticle::phi >= phiExclusionMax))); o2::framework::expressions::Filter clusterFilter = (o2::aod::jcluster::eta >= clusterEtaMin && o2::aod::jcluster::eta <= clusterEtaMax && o2::aod::jcluster::phi >= clusterPhiMin && o2::aod::jcluster::phi <= clusterPhiMax && o2::aod::jcluster::energy >= clusterEnergyMin && o2::aod::jcluster::time > clusterTimeMin && o2::aod::jcluster::time < clusterTimeMax && (!clusterRejectExotics || o2::aod::jcluster::isExotic != true)); void processChargedJets(o2::soa::Filtered::iterator const& collision, diff --git a/PWGJE/JetFinders/jetFinderHF.h b/PWGJE/JetFinders/jetFinderHF.h index 3016cdb5265..ebe5629f1b5 100644 --- a/PWGJE/JetFinders/jetFinderHF.h +++ b/PWGJE/JetFinders/jetFinderHF.h @@ -41,6 +41,7 @@ #include #include +#include #include #include @@ -72,6 +73,8 @@ struct JetFinderHFTask { o2::framework::Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum track eta"}; o2::framework::Configurable trackPhiMin{"trackPhiMin", -999, "minimum track phi"}; o2::framework::Configurable trackPhiMax{"trackPhiMax", 999, "maximum track phi"}; + o2::framework::Configurable phiExclusionMin{"phiExclusionMin", -999, "minimum of phi exclusion region which is applied for tracks and for jets (jetR is added to the exclusion region for jets)"}; + o2::framework::Configurable phiExclusionMax{"phiExclusionMax", 999, "maximum of phi exclusion region which is applied for tracks and for jets (jetR is added to the exclusion region for jets)"}; o2::framework::Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; o2::framework::Configurable particleSelections{"particleSelections", "PhysicalPrimary", "set particle selections"}; @@ -146,6 +149,13 @@ struct JetFinderHFTask { jetFinder.phiMin = -1.0 * M_PI; jetFinder.phiMax = 2.0 * M_PI; } + if (phiExclusionMin > -998.0) { + jetFinder.phiExclusionMin = phiExclusionMin; + jetFinder.phiExclusionMax = phiExclusionMax; + if (phiExclusionMin >= phiExclusionMax) { + throw std::runtime_error("Invalid phi exclusion range: require phiExclusionMin < phiExclusionMax when both are set."); + } + } jetFinder.jetPhiMin = jetPhiMin; jetFinder.jetPhiMax = jetPhiMax; if (jetPhiMin < -98.0) { @@ -186,8 +196,8 @@ struct JetFinderHFTask { o2::framework::expressions::Filter collisionFilter = (nabs(o2::aod::jcollision::posZ) < vertexZCut && o2::aod::jcollision::centFT0M >= centralityMin && o2::aod::jcollision::centFT0M < centralityMax && o2::aod::jcollision::trackOccupancyInTimeRange <= trackOccupancyInTimeRangeMax); o2::framework::expressions::Filter mcCollisionFilter = (nabs(o2::aod::jmccollision::posZ) < vertexZCut); - o2::framework::expressions::Filter trackCuts = (o2::aod::jtrack::pt >= trackPtMin && o2::aod::jtrack::pt < trackPtMax && o2::aod::jtrack::eta >= trackEtaMin && o2::aod::jtrack::eta <= trackEtaMax && o2::aod::jtrack::phi >= trackPhiMin && o2::aod::jtrack::phi <= trackPhiMax); - o2::framework::expressions::Filter partCuts = (o2::aod::jmcparticle::pt >= trackPtMin && o2::aod::jmcparticle::pt < trackPtMax && o2::aod::jmcparticle::eta >= trackEtaMin && o2::aod::jmcparticle::eta <= trackEtaMax && o2::aod::jmcparticle::phi >= trackPhiMin && o2::aod::jmcparticle::phi <= trackPhiMax); + o2::framework::expressions::Filter trackCuts = (o2::aod::jtrack::pt >= trackPtMin && o2::aod::jtrack::pt < trackPtMax && o2::aod::jtrack::eta >= trackEtaMin && o2::aod::jtrack::eta <= trackEtaMax && o2::aod::jtrack::phi >= trackPhiMin && o2::aod::jtrack::phi <= trackPhiMax && (phiExclusionMin < -998.0 || (o2::aod::jtrack::phi <= phiExclusionMin || o2::aod::jtrack::phi >= phiExclusionMax))); + o2::framework::expressions::Filter partCuts = (o2::aod::jmcparticle::pt >= trackPtMin && o2::aod::jmcparticle::pt < trackPtMax && o2::aod::jmcparticle::eta >= trackEtaMin && o2::aod::jmcparticle::eta <= trackEtaMax && o2::aod::jmcparticle::phi >= trackPhiMin && o2::aod::jmcparticle::phi <= trackPhiMax && (phiExclusionMin < -998.0 || (o2::aod::jmcparticle::phi <= phiExclusionMin || o2::aod::jmcparticle::phi >= phiExclusionMax))); o2::framework::expressions::Filter clusterFilter = (o2::aod::jcluster::definition == static_cast(clusterDefinition) && o2::aod::jcluster::eta >= clusterEtaMin && o2::aod::jcluster::eta <= clusterEtaMax && o2::aod::jcluster::phi >= clusterPhiMin && o2::aod::jcluster::phi <= clusterPhiMax && o2::aod::jcluster::energy >= clusterEnergyMin && o2::aod::jcluster::time > clusterTimeMin && o2::aod::jcluster::time < clusterTimeMax && (!clusterRejectExotics || o2::aod::jcluster::isExotic != true)); // o2::framework::expressions::Filter candidateCuts = (o2::aod::hfcand::pt >= candPtMin && o2::aod::hfcand::pt < candPtMax && o2::aod::hfcand::y >= candYMin && o2::aod::hfcand::y < candYMax); diff --git a/PWGJE/JetFinders/jetFinderHFHFBar.h b/PWGJE/JetFinders/jetFinderHFHFBar.h index ec4cfa9d94c..8bc9506ec55 100644 --- a/PWGJE/JetFinders/jetFinderHFHFBar.h +++ b/PWGJE/JetFinders/jetFinderHFHFBar.h @@ -41,6 +41,7 @@ #include #include +#include #include #include @@ -72,6 +73,8 @@ struct JetFinderHFHFBarTask { o2::framework::Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum track eta"}; o2::framework::Configurable trackPhiMin{"trackPhiMin", -999, "minimum track phi"}; o2::framework::Configurable trackPhiMax{"trackPhiMax", 999, "maximum track phi"}; + o2::framework::Configurable phiExclusionMin{"phiExclusionMin", -999, "minimum of phi exclusion region which is applied for tracks and for jets (jetR is added to the exclusion region for jets)"}; + o2::framework::Configurable phiExclusionMax{"phiExclusionMax", 999, "maximum of phi exclusion region which is applied for tracks and for jets (jetR is added to the exclusion region for jets)"}; o2::framework::Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; o2::framework::Configurable particleSelections{"particleSelections", "PhysicalPrimary", "set particle selections"}; @@ -143,6 +146,13 @@ struct JetFinderHFHFBarTask { jetFinder.phiMin = -1.0 * M_PI; jetFinder.phiMax = 2.0 * M_PI; } + if (phiExclusionMin > -998.0) { + jetFinder.phiExclusionMin = phiExclusionMin; + jetFinder.phiExclusionMax = phiExclusionMax; + if (phiExclusionMin >= phiExclusionMax) { + throw std::runtime_error("Invalid phi exclusion range: require phiExclusionMin < phiExclusionMax when both are set."); + } + } jetFinder.jetPhiMin = jetPhiMin; jetFinder.jetPhiMax = jetPhiMax; if (jetPhiMin < -98.0) { @@ -184,8 +194,8 @@ struct JetFinderHFHFBarTask { o2::aod::EMCALClusterDefinition clusterDefinition = o2::aod::emcalcluster::getClusterDefinitionFromString(clusterDefinitionS.value); o2::framework::expressions::Filter collisionFilter = (nabs(o2::aod::jcollision::posZ) < vertexZCut && o2::aod::jcollision::centFT0M >= centralityMin && o2::aod::jcollision::centFT0M < centralityMax && o2::aod::jcollision::trackOccupancyInTimeRange <= trackOccupancyInTimeRangeMax); o2::framework::expressions::Filter mcCollisionFilter = (nabs(o2::aod::jmccollision::posZ) < vertexZCut); - o2::framework::expressions::Filter trackCuts = (o2::aod::jtrack::pt >= trackPtMin && o2::aod::jtrack::pt < trackPtMax && o2::aod::jtrack::eta >= trackEtaMin && o2::aod::jtrack::eta <= trackEtaMax && o2::aod::jtrack::phi >= trackPhiMin && o2::aod::jtrack::phi <= trackPhiMax); - o2::framework::expressions::Filter partCuts = (o2::aod::jmcparticle::pt >= trackPtMin && o2::aod::jmcparticle::pt < trackPtMax && o2::aod::jmcparticle::eta >= trackEtaMin && o2::aod::jmcparticle::eta <= trackEtaMax && o2::aod::jmcparticle::phi >= trackPhiMin && o2::aod::jmcparticle::phi <= trackPhiMax); + o2::framework::expressions::Filter trackCuts = (o2::aod::jtrack::pt >= trackPtMin && o2::aod::jtrack::pt < trackPtMax && o2::aod::jtrack::eta >= trackEtaMin && o2::aod::jtrack::eta <= trackEtaMax && o2::aod::jtrack::phi >= trackPhiMin && o2::aod::jtrack::phi <= trackPhiMax && (phiExclusionMin < -998.0 || (o2::aod::jtrack::phi <= phiExclusionMin || o2::aod::jtrack::phi >= phiExclusionMax))); + o2::framework::expressions::Filter partCuts = (o2::aod::jmcparticle::pt >= trackPtMin && o2::aod::jmcparticle::pt < trackPtMax && o2::aod::jmcparticle::eta >= trackEtaMin && o2::aod::jmcparticle::eta <= trackEtaMax && o2::aod::jmcparticle::phi >= trackPhiMin && o2::aod::jmcparticle::phi <= trackPhiMax && (phiExclusionMin < -998.0 || (o2::aod::jmcparticle::phi <= phiExclusionMin || o2::aod::jmcparticle::phi >= phiExclusionMax))); o2::framework::expressions::Filter clusterFilter = (o2::aod::jcluster::definition == static_cast(clusterDefinition) && o2::aod::jcluster::eta >= clusterEtaMin && o2::aod::jcluster::eta <= clusterEtaMax && o2::aod::jcluster::phi >= clusterPhiMin && o2::aod::jcluster::phi <= clusterPhiMax && o2::aod::jcluster::energy >= clusterEnergyMin && o2::aod::jcluster::time > clusterTimeMin && o2::aod::jcluster::time < clusterTimeMax && (clusterRejectExotics && o2::aod::jcluster::isExotic != true)); // o2::framework::expressions::Filter candidateCuts = (o2::aod::hfcand::pt >= candPtMin && o2::aod::hfcand::pt < candPtMax && o2::aod::hfcand::y >= candYMin && o2::aod::hfcand::y < candYMax); diff --git a/PWGJE/JetFinders/jetFinderV0.h b/PWGJE/JetFinders/jetFinderV0.h index 14c2f977ada..8d3b9b7f660 100644 --- a/PWGJE/JetFinders/jetFinderV0.h +++ b/PWGJE/JetFinders/jetFinderV0.h @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -67,6 +68,8 @@ struct JetFinderV0Task { o2::framework::Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum track eta"}; o2::framework::Configurable trackPhiMin{"trackPhiMin", -999, "minimum track phi"}; o2::framework::Configurable trackPhiMax{"trackPhiMax", 999, "maximum track phi"}; + o2::framework::Configurable phiExclusionMin{"phiExclusionMin", -999, "minimum of phi exclusion region which is applied for tracks and for jets (jetR is added to the exclusion region for jets)"}; + o2::framework::Configurable phiExclusionMax{"phiExclusionMax", 999, "maximum of phi exclusion region which is applied for tracks and for jets (jetR is added to the exclusion region for jets)"}; o2::framework::Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; o2::framework::Configurable particleSelections{"particleSelections", "PhysicalPrimary", "set particle selections"}; @@ -127,6 +130,13 @@ struct JetFinderV0Task { jetFinder.phiMin = -1.0 * M_PI; jetFinder.phiMax = 2.0 * M_PI; } + if (phiExclusionMin > -998.0) { + jetFinder.phiExclusionMin = phiExclusionMin; + jetFinder.phiExclusionMax = phiExclusionMax; + if (phiExclusionMin >= phiExclusionMax) { + throw std::runtime_error("Invalid phi exclusion range: require phiExclusionMin < phiExclusionMax when both are set."); + } + } jetFinder.jetPhiMin = jetPhiMin; jetFinder.jetPhiMax = jetPhiMax; if (jetPhiMin < -98.0) { @@ -174,8 +184,8 @@ struct JetFinderV0Task { o2::framework::expressions::Filter collisionFilter = (nabs(o2::aod::jcollision::posZ) < vertexZCut && o2::aod::jcollision::centFT0M >= centralityMin && o2::aod::jcollision::centFT0M < centralityMax && o2::aod::jcollision::trackOccupancyInTimeRange <= trackOccupancyInTimeRangeMax); o2::framework::expressions::Filter mcCollisionFilter = (nabs(o2::aod::jmccollision::posZ) < vertexZCut); - o2::framework::expressions::Filter trackCuts = (o2::aod::jtrack::pt >= trackPtMin && o2::aod::jtrack::pt < trackPtMax && o2::aod::jtrack::eta >= trackEtaMin && o2::aod::jtrack::eta <= trackEtaMax && o2::aod::jtrack::phi >= trackPhiMin && o2::aod::jtrack::phi <= trackPhiMax); - o2::framework::expressions::Filter partCuts = (o2::aod::jmcparticle::pt >= trackPtMin && o2::aod::jmcparticle::pt < trackPtMax && o2::aod::jmcparticle::eta >= trackEtaMin && o2::aod::jmcparticle::eta <= trackEtaMax && o2::aod::jmcparticle::phi >= trackPhiMin && o2::aod::jmcparticle::phi <= trackPhiMax); + o2::framework::expressions::Filter trackCuts = (o2::aod::jtrack::pt >= trackPtMin && o2::aod::jtrack::pt < trackPtMax && o2::aod::jtrack::eta >= trackEtaMin && o2::aod::jtrack::eta <= trackEtaMax && o2::aod::jtrack::phi >= trackPhiMin && o2::aod::jtrack::phi <= trackPhiMax && (phiExclusionMin < -998.0 || (o2::aod::jtrack::phi <= phiExclusionMin || o2::aod::jtrack::phi >= phiExclusionMax))); + o2::framework::expressions::Filter partCuts = (o2::aod::jmcparticle::pt >= trackPtMin && o2::aod::jmcparticle::pt < trackPtMax && o2::aod::jmcparticle::eta >= trackEtaMin && o2::aod::jmcparticle::eta <= trackEtaMax && o2::aod::jmcparticle::phi >= trackPhiMin && o2::aod::jmcparticle::phi <= trackPhiMax && (phiExclusionMin < -998.0 || (o2::aod::jmcparticle::phi <= phiExclusionMin || o2::aod::jmcparticle::phi >= phiExclusionMax))); // function that generalically processes Data and reco level events template diff --git a/PWGJE/TableProducer/CMakeLists.txt b/PWGJE/TableProducer/CMakeLists.txt index 42d27740b1e..06c12902c91 100644 --- a/PWGJE/TableProducer/CMakeLists.txt +++ b/PWGJE/TableProducer/CMakeLists.txt @@ -116,6 +116,11 @@ o2physics_add_dpl_workflow(slim-tables-producer PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(berkeley-tree-producer + SOURCES berkeleyTreeProducer.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(diff-wake-tree-producer SOURCES diffWakeTreeProducer.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore diff --git a/PWGJE/TableProducer/berkeleyTreeProducer.cxx b/PWGJE/TableProducer/berkeleyTreeProducer.cxx new file mode 100644 index 00000000000..fe49ffdef91 --- /dev/null +++ b/PWGJE/TableProducer/berkeleyTreeProducer.cxx @@ -0,0 +1,208 @@ +// 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. + +/// \file berkeleyTreeProducer.cxx +/// \brief Task to save MC events into the BerkeleyTree format +/// \author Vassu Doomra +/// \author Tucker Hwang + +#include "PWGJE/Core/JetDerivedDataUtilities.h" +#include "PWGJE/DataModel/Jet.h" +#include "PWGJE/DataModel/JetReducedData.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +namespace o2::aod +{ +namespace berkeleytree +{ +DECLARE_SOA_COLUMN(VtxZ, vtxZ, float); +DECLARE_SOA_COLUMN(Weight, weight, float); +DECLARE_SOA_COLUMN(PtHat, ptHat, float); +DECLARE_SOA_COLUMN(Multiplicity, multiplicity, float); +DECLARE_SOA_COLUMN(Occupancy, occupancy, int); +DECLARE_SOA_COLUMN(EventSel, eventSel, uint16_t); +DECLARE_SOA_BITMAP_COLUMN(Rct, rct, 32); + +DECLARE_SOA_COLUMN(DetPt, detPt, std::vector); +DECLARE_SOA_COLUMN(DetEta, detEta, std::vector); +DECLARE_SOA_COLUMN(DetPhi, detPhi, std::vector); +DECLARE_SOA_COLUMN(DetTrackSel, detTrackSel, std::vector); +DECLARE_SOA_COLUMN(DetMcId, detMcId, std::vector); + +DECLARE_SOA_COLUMN(GenPt, genPt, std::vector); +DECLARE_SOA_COLUMN(GenEta, genEta, std::vector); +DECLARE_SOA_COLUMN(GenPhi, genPhi, std::vector); +DECLARE_SOA_COLUMN(GenE, genE, std::vector); +DECLARE_SOA_COLUMN(GenCharge, genCharge, std::vector); +DECLARE_SOA_COLUMN(GenMcId, genMcId, std::vector); +DECLARE_SOA_COLUMN(PdgId, pdgId, std::vector); +} // namespace berkeleytree + +DECLARE_SOA_TABLE(BerkeleyTree, "AOD", "BERKELEYTREE", + berkeleytree::VtxZ, + berkeleytree::Weight, + berkeleytree::PtHat, + berkeleytree::Multiplicity, + berkeleytree::EventSel, + berkeleytree::Occupancy, + berkeleytree::Rct, + berkeleytree::DetPt, + berkeleytree::DetEta, + berkeleytree::DetPhi, + berkeleytree::DetTrackSel, + berkeleytree::DetMcId, + berkeleytree::GenPt, + berkeleytree::GenEta, + berkeleytree::GenPhi, + berkeleytree::GenE, + berkeleytree::GenCharge, + berkeleytree::GenMcId, + berkeleytree::PdgId); +} // namespace o2::aod + +struct BerkeleyTreeProducer { + Service pdg; + + Configurable vertexZCut{"vertexZCut", 10.0f, "maximum Z vertex"}; + Configurable etaMaxDet{"etaMaxDet", 0.9f, "maximum eta for det-level tracks"}; + Configurable etaMaxGen{"etaMaxGen", 0.9f, "maximum eta for gen-level particles"}; + Configurable ptMinDet{"ptMinDet", 0.15f, "minimum pt (GeV) for det-level tracks"}; + Configurable ptMinGen{"ptMinGen", 0.15f, "minimum pt (GeV) for gen-level particles"}; + + Configurable eventSelections{"eventSelections", "sel8", ""}; + Configurable trackSelections{"trackSelections", "globalTracks", ""}; + Configurable skipMBGapEvents{"skipMBGapEvents", true, "skip MB gap events"}; + + Produces tree; + + std::vector eventSelectionBits; + int trackSelection = -1; + + Preslice particlesPerMcCollision = aod::jmcparticle::mcCollisionId; + + bool isChargedParticle(int code) + { + const float chargeUnit = 3.; + auto p = pdg->GetParticle(code); + auto charge = 0.; + if (p != nullptr) { + charge = p->Charge(); + } + return std::abs(charge) >= chargeUnit; + } + + int getCharge(int code) + { + auto p = pdg->GetParticle(code); + if (!p) { + LOG(fatal) << "Cannot find particle with PDG code " << code; + return 0; + } + auto charge = p->Charge() / 3.0; + return std::lround(charge); + } + + void init(InitContext const&) + { + eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits(eventSelections); + trackSelection = jetderiveddatautilities::initialiseTrackSelection(trackSelections); + } + + using JetParticlesWithOriginal = soa::Join; + void processMCJJ(aod::JetCollisionsMCD::iterator const& collision, aod::JetTracksMCD const& tracks, JetParticlesWithOriginal const& mcParticles, aod::JetMcCollisions const&) + { + // do not do any RCT selections, will be done on analysis level + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, false, "", false, false)) + return; + if (std::abs(collision.posZ()) > vertexZCut) + return; + + float weight = collision.has_mcCollision() ? collision.mcCollision().weight() : 1.f; + float pthat = collision.has_mcCollision() ? collision.mcCollision().ptHard() : 1.f; + + std::vector detPt, detEta, detPhi; + std::vector detTrackSel; + std::vector detMcId; // track.mcParticleId() returns int/int32_t, casting to int64_t + + std::vector genPt, genEta, genPhi, genE; + std::vector genCharge, pdgId; + std::vector genMcId; // mcParticle.globalIndex() returns long/int64_t + + for (auto const& track : tracks) { + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) + continue; + + if (std::fabs(track.eta()) > etaMaxDet) + continue; + if (track.pt() < ptMinDet) + continue; + + detPt.push_back(track.pt()); + detEta.push_back(track.eta()); + detPhi.push_back(track.phi()); + detTrackSel.push_back(track.trackSel()); + if (track.has_mcParticle()) + detMcId.push_back(track.mcParticleId()); + else + detMcId.push_back(-1); + } + + int mcId = collision.has_mcCollision() ? collision.mcCollisionId() : -1; + + if (mcId >= 0) { + auto particles = mcParticles.sliceBy(particlesPerMcCollision, mcId); + + for (auto const& p : particles) { + if (!p.isPhysicalPrimary()) + continue; + if (std::fabs(p.eta()) > etaMaxGen) + continue; + if (p.pt() < ptMinGen) + continue; + if (!isChargedParticle(p.pdgCode())) + continue; + + genPt.push_back(p.pt()); + genEta.push_back(p.eta()); + genPhi.push_back(p.phi()); + genE.push_back(p.e()); + genCharge.push_back(getCharge(p.pdgCode())); + genMcId.push_back(p.globalIndex()); + pdgId.push_back(p.pdgCode()); + } + } + + tree(collision.posZ(), weight, pthat, collision.multFT0C(), collision.eventSel(), collision.trackOccupancyInTimeRange(), collision.rct_raw(), detPt, detEta, detPhi, detTrackSel, detMcId, genPt, genEta, genPhi, genE, genCharge, genMcId, pdgId); + } + + PROCESS_SWITCH(BerkeleyTreeProducer, processMCJJ, "MC processing for JJ simulations", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGJE/TableProducer/derivedDataProducer.cxx b/PWGJE/TableProducer/derivedDataProducer.cxx index 3676ab5a6e9..d2a9e5a54c9 100644 --- a/PWGJE/TableProducer/derivedDataProducer.cxx +++ b/PWGJE/TableProducer/derivedDataProducer.cxx @@ -620,7 +620,7 @@ struct JetDerivedDataProducerTask { void processClusters(aod::Collision const&, aod::EMCALClusters const& clusters, aod::EMCALClusterCells const& cells, aod::Calos const&, aod::EMCALMatchedTracks const& matchedTracks, soa::Join const&) { - for (auto cluster : clusters) { + for (const auto& cluster : clusters) { auto const clusterCells = cells.sliceBy(preslices.perClusterCells, cluster.globalIndex()); diff --git a/PWGJE/TableProducer/derivedDataSelector.cxx b/PWGJE/TableProducer/derivedDataSelector.cxx index ecd7aa3a292..a1fd6ed8f2d 100644 --- a/PWGJE/TableProducer/derivedDataSelector.cxx +++ b/PWGJE/TableProducer/derivedDataSelector.cxx @@ -155,9 +155,9 @@ struct JetDerivedDataSelector { void processSelectMcCollisionsPerCollision(aod::JMcCollisions const& mcCollisions, soa::Join const& collisions) { - for (auto mcCollision : mcCollisions) { + for (const auto& mcCollision : mcCollisions) { const auto collisionsPerMcCollision = collisions.sliceBy(CollisionsPerMcCollision, mcCollision.globalIndex()); - for (auto collision : collisionsPerMcCollision) { + for (const auto& collision : collisionsPerMcCollision) { if (collisionFlag[collision.globalIndex()]) { mcCollisionFlag[mcCollision.globalIndex()] = true; } diff --git a/PWGJE/TableProducer/derivedDataWriter.cxx b/PWGJE/TableProducer/derivedDataWriter.cxx index 02c18e31317..67f76d1c62e 100644 --- a/PWGJE/TableProducer/derivedDataWriter.cxx +++ b/PWGJE/TableProducer/derivedDataWriter.cxx @@ -37,6 +37,8 @@ #include #include +#include + #include #include #include @@ -711,11 +713,11 @@ struct JetDerivedDataWriter { const auto particlesPerMcCollision = particles.sliceBy(preslices.ParticlesPerMcCollision, mcCollision.globalIndex()); - for (auto particle : particlesPerMcCollision) { + for (const auto& particle : particlesPerMcCollision) { particleMapping[particle.globalIndex()] = particleTableIndex; particleTableIndex++; } - for (auto particle : particlesPerMcCollision) { + for (const auto& particle : particlesPerMcCollision) { std::vector mothersIds; int daughtersIds[2] = {-1, -1}; diff --git a/PWGJE/TableProducer/emcalCorrectionTask.cxx b/PWGJE/TableProducer/emcalCorrectionTask.cxx index 19a4139d7cb..258cbe8e80c 100644 --- a/PWGJE/TableProducer/emcalCorrectionTask.cxx +++ b/PWGJE/TableProducer/emcalCorrectionTask.cxx @@ -265,8 +265,7 @@ struct EmcalCorrectionTask { mClusterFactories.setExoticCellDiffTime(exoticCellDiffTime); mClusterFactories.setExoticCellMinAmplitude(exoticCellMinAmplitude); mClusterFactories.setExoticCellInCrossMinAmplitude(exoticCellInCrossMinAmplitude); - // TODO: Fix setUseWeightExotic in the O2 code to use bool as argument not float! - mClusterFactories.setUseWeightExotic(static_cast(useWeightExotic)); + mClusterFactories.setUseWeightExotic(useWeightExotic); for (const auto& clusterDefinition : mClusterDefinitions) { mClusterizers.emplace_back(std::make_unique>(clusterDefinition.timeDiff, clusterDefinition.timeMin, clusterDefinition.timeMax, clusterDefinition.gradientCut, clusterDefinition.doGradientCut, clusterDefinition.seedEnergy, clusterDefinition.minCellEnergy)); LOG(info) << "Cluster definition initialized: " << clusterDefinition.toString(); diff --git a/PWGJE/TableProducer/mcOutlierRejector.cxx b/PWGJE/TableProducer/mcOutlierRejector.cxx index 32fed7ebbb3..f0b7672c40a 100644 --- a/PWGJE/TableProducer/mcOutlierRejector.cxx +++ b/PWGJE/TableProducer/mcOutlierRejector.cxx @@ -69,7 +69,7 @@ struct McOutlierRejectorTask { if (selectionObjects.size() != 0) { float selectionObjectPt = 0.0; if constexpr (std::is_same_v, aod::JetTracksMCD> || std::is_same_v, aod::JetParticles>) { - for (auto selectionObject : selectionObjects) { + for (const auto& selectionObject : selectionObjects) { selectionObjectPt = selectionObject.pt(); // may be slow - could save only MC particle then check difference only for tracks IDd as outliers? if constexpr (std::is_same_v, aod::JetTracksMCD>) { // tracks diff --git a/PWGJE/TableProducer/slimTablesProducer.cxx b/PWGJE/TableProducer/slimTablesProducer.cxx index 58fea43fdae..cbaf139646e 100644 --- a/PWGJE/TableProducer/slimTablesProducer.cxx +++ b/PWGJE/TableProducer/slimTablesProducer.cxx @@ -108,9 +108,10 @@ struct SlimTablesProducer { Configurable trackSelections{"trackSelections", "globalTracks", "set track selections; other option: uniformTracks"}; Configurable skipMBGapEvents{"skipMBGapEvents", false, "flag to choose to reject min. bias gap events; jet-level rejection can also be applied at the jet finder level for jets only, here rejection is applied for collision and track process functions for the first time, and on jets in case it was set to false at the jet finder level"}; Configurable applyRCTSelections{"applyRCTSelections", true, "decide to apply RCT selections"}; - + Configurable trackOccupancyInTimeRangeMax{"trackOccupancyInTimeRangeMax", 999999, "maximum track occupancy of tracks in neighbouring collisions in a given time range; only applied to reconstructed collisions (data and mcd jets), not mc collisions (mcp jets)"}; + Configurable trackOccupancyInTimeRangeMin{"trackOccupancyInTimeRangeMin", -999999, "minimum track occupancy of tracks in neighbouring collisions in a given time range; only applied to reconstructed collisions (data and mcd jets), not mc collisions (mcp jets)"}; std::vector eventSelectionBits; - Service pdgDatabase; + Service pdgDatabase{}; int trackSelection = -1; bool doSumw2 = false; @@ -122,15 +123,19 @@ struct SlimTablesProducer { histos.add("h_collisions", "event status;event status;entries", {HistType::kTH1F, {{4, 0.0, 4.0}}}); histos.add("h2_centrality_collisions", "event status vs. centrality;entries;centrality", {HistType::kTH2F, {centralityAxis, {4, 0.0, 4.0}}}, doSumw2); + histos.add("h_occupancy_raw", "occupancy;occupancy;entries", {HistType::kTH1F, {{200, -10, 10000}}}); + auto hColl = histos.get(HIST("h_collisions")); hColl->GetXaxis()->SetBinLabel(1, "All"); hColl->GetXaxis()->SetBinLabel(2, "eventSelection"); + hColl->GetXaxis()->SetBinLabel(3, "occupancycut"); histos.add("h_mcCollMCD_counts_weight", "MC event status;event status;weighted entries", {HistType::kTH1F, {{5, 0.0, 5.0}}}); auto hMCD = histos.get(HIST("h_mcCollMCD_counts_weight")); hMCD->GetXaxis()->SetBinLabel(1, "All"); hMCD->GetXaxis()->SetBinLabel(2, "hasMcCollision"); hMCD->GetXaxis()->SetBinLabel(3, "selectCollision"); + hMCD->GetXaxis()->SetBinLabel(4, "occupancycut"); histos.add("h_mcCollMCP_counts_weight", "MC event status;event status;weighted entries", {HistType::kTH1F, {{7, 0.0, 7.0}}}); auto hMCP = histos.get(HIST("h_mcCollMCP_counts_weight")); @@ -171,6 +176,11 @@ struct SlimTablesProducer { return; } histos.fill(HIST("h_collisions"), 1.5); + histos.fill(HIST("h_occupancy_raw"), collision.trackOccupancyInTimeRange()); + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + return; + } + histos.fill(HIST("h_collisions"), 2.5); slimCollisions(collision.posZ(), collision.collisionTime(), 1.0); auto slimCollIndex = slimCollisions.lastIndex(); for (const auto& track : tracks) { @@ -211,25 +221,35 @@ struct SlimTablesProducer { continue; } histos.fill(HIST("h_mcCollMCD_counts_weight"), 2.5, eventWeightMC); + histos.fill(HIST("h_occupancy_raw"), collision.trackOccupancyInTimeRange()); + // occupancy cut only applied to the reconstructed (MCD) collision, not to the mcCollision + if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + continue; + } + histos.fill(HIST("h_mcCollMCD_counts_weight"), 3.5, eventWeightMC); slimCollisions(collision.posZ(), collision.collisionTime(), eventWeight); auto slimCollIndex = slimCollisions.lastIndex(); auto slicedTracks = tracks.sliceBy(perCollisionTracks, collision.globalIndex()); // tracks associated to the rec collision for (const auto& track : slicedTracks) { - if (!jetderiveddatautilities::selectTrack(track, trackSelection)) + if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { continue; + } histos.fill(HIST("Ntracks_pT"), track.pt(), eventWeight); slimTracks(slimCollIndex, track.px(), track.py(), track.pz()); } slimMcCollisions(mccollision.posZ(), eventWeightMC); auto slimMcCollIndex = slimMcCollisions.lastIndex(); for (const auto& particle : particles) { - if (!particle.isPhysicalPrimary()) + if (!particle.isPhysicalPrimary()) { continue; + } auto pdgParticle = pdgDatabase->GetParticle(particle.pdgCode()); - if (!pdgParticle) + if (!pdgParticle) { continue; - if (pdgParticle->Charge() == 0) // keep charged particles, exclude neutrals + } + if (pdgParticle->Charge() == 0) { // keep charged particles, exclude neutrals continue; + } histos.fill(HIST("Nparticles_pT"), particle.pt(), eventWeightMC); slimParticles(slimMcCollIndex, particle.px(), particle.py(), particle.pz(), particle.energy()); } diff --git a/PWGJE/Tasks/CMakeLists.txt b/PWGJE/Tasks/CMakeLists.txt index d4347cb52e4..a87293c9cca 100644 --- a/PWGJE/Tasks/CMakeLists.txt +++ b/PWGJE/Tasks/CMakeLists.txt @@ -104,6 +104,7 @@ o2physics_add_dpl_workflow(hadron-photon-correlation if(FastJet_FOUND) o2physics_add_dpl_workflow(jet-background-analysis SOURCES jetBackgroundAnalysis.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-substructure @@ -113,6 +114,7 @@ if(FastJet_FOUND) COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-substructure-output SOURCES jetSubstructureOutput.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-substructure-d0 @@ -207,74 +209,92 @@ if(FastJet_FOUND) COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-fragmentation SOURCES jetFragmentation.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-v0-spectra SOURCES v0JetSpectra.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-v0qa SOURCES v0QA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-charged-qa SOURCES jetFinderQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-outlier-qa SOURCES jetOutlierQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-charged-v2 SOURCES jetChargedV2.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-d0-qa SOURCES jetFinderD0QA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-dplus-qa SOURCES jetFinderDplusQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-ds-qa SOURCES jetFinderDsQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-dstar-qa SOURCES jetFinderDstarQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-lc-qa SOURCES jetFinderLcQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-b0-qa SOURCES jetFinderB0QA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-bplus-qa SOURCES jetFinderBplusQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-xictoxipipi-qa SOURCES jetFinderXicToXiPiPiQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-dielectron-qa SOURCES jetFinderDielectronQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-full-qa SOURCES jetFinderFullQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-finder-v0-qa SOURCES jetFinderV0QA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-spectra-charged SOURCES jetSpectraCharged.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-spectra-charged-gen @@ -283,161 +303,200 @@ if(FastJet_FOUND) COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(charged-jet-hadron SOURCES chargedJetHadron.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(trigger-correlations SOURCES triggerCorrelations.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-trigger-charged-qa SOURCES jetTriggerChargedQa.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-full-trigger-qa SOURCES fullJetTriggerQATask.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-matching-qa SOURCES jetMatchingQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-validation-qa SOURCES jetValidationQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-tutorial SOURCES jetTutorial.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-tutorial-skeleton SOURCES jetTutorialSkeleton.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(track-jet-qa SOURCES trackJetQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(track-efficiency SOURCES trackEfficiency.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-hadron-recoil SOURCES jetHadronRecoil.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(recoil-jets SOURCES recoilJets.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-nsubjettiness SOURCES nsubjettiness.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(phi-in-jets SOURCES phiInJets.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(nuclei-in-jets SOURCES nucleiInJets.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2Physics::EventFilteringUtils O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-taggerhf-qa SOURCES jetTaggerHFQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-lund-reclustering SOURCES jetLundReclustering.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore FastJet::FastJet FastJet::Contrib COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-lund-plane SOURCES jetLundPlane.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore FastJet::FastJet FastJet::Contrib COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(hf-fragmentation-function SOURCES hfFragmentationFunction.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-planarflow SOURCES jetPlanarFlow.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-ch-corr SOURCES jetChCorr.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(bjet-tree-creator SOURCES bjetTreeCreator.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(stat-prompt-photon SOURCES statPromptPhoton.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(full-jet-spectra SOURCES fullJetSpectra.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2Physics::EventFilteringUtils O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(bjet-tagging-ml SOURCES bjetTaggingML.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2Physics::MLCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-spectra-ese SOURCES jetSpectraEseTask.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-cross-section-efficiency SOURCES jetCrossSectionEfficiency.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(gamma-jet-tree-producer SOURCES gammaJetTreeProducer.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2::EMCALCalib O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(dijet-finder-charged-qa SOURCES dijetFinderQA.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(bjet-tagging-gnn SOURCES bjetTaggingGnn.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore O2Physics::EventFilteringUtils O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-shape SOURCES jetShape.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-formationtimereclustering SOURCES jetFormationTimeReclustering.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-correlation-d0 SOURCES jetCorrelationD0.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(hf-debug SOURCES hfDebug.cxx + REUSE_FROM JetSubstructureHFOutputPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-debug SOURCES jetDebug.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(substructure-debug SOURCES substructureDebug.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-ds-spec-subs SOURCES jetDsSpecSubs.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-d0-ang-substructure SOURCES jetD0AngSubstructure.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(bjet-cent-mult SOURCES bjetCentMult.cxx + REUSE_FROM JetSubstructureHFPCH PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::PWGJECore O2Physics::AnalysisCore COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(jet-hadrons-pid diff --git a/PWGJE/Tasks/bjetTaggingGnn.cxx b/PWGJE/Tasks/bjetTaggingGnn.cxx index dec0b8acdb8..6b3196e04d9 100644 --- a/PWGJE/Tasks/bjetTaggingGnn.cxx +++ b/PWGJE/Tasks/bjetTaggingGnn.cxx @@ -12,7 +12,7 @@ /// \file bjetTaggingGnn.cxx /// \brief b-jet tagging using GNN /// -/// \author Changhwan Choi , Pusan National University +/// \author Changhwan Choi , Yonsei University #include "PWGJE/Core/JetDerivedDataUtilities.h" #include "PWGJE/Core/JetTaggingUtilities.h" @@ -43,7 +43,6 @@ #include #include #include -#include #include #include @@ -197,8 +196,12 @@ struct BjetTaggingGnn { Configurable trackNppCrit{"trackNppCrit", 0.95, "track not physical primary ratio"}; // jet level configurables + Configurable jetPtNbins{"jetPtNbins", 300, "number of bins for jet pT"}; Configurable jetPtMin{"jetPtMin", 0.0, "minimum jet pT"}; - Configurable jetPtMax{"jetPtMax", 1000.0, "maximum jet pT"}; + Configurable jetPtMax{"jetPtMax", 300.0, "maximum jet pT"}; + Configurable jetPtSubNbins{"jetPtSubNbins", 300, "number of bins for UE-subtracted jet pT"}; + Configurable jetPtSubMin{"jetPtSubMin", -50.0, "minimum UE-subtracted jet pT"}; + Configurable jetPtSubMax{"jetPtSubMax", 250.0, "maximum UE-subtracted jet pT"}; Configurable jetEtaMin{"jetEtaMin", -0.9, "minimum jet pseudorapidity"}; Configurable jetEtaMax{"jetEtaMax", 0.9, "maximum jet pseudorapidity"}; Configurable leadingConstituentPtMin{"leadingConstituentPtMin", -99.0, "minimum pT selection on jet constituent"}; @@ -331,9 +334,9 @@ struct BjetTaggingGnn { const AxisSpec axisTrackpT{200, 0., 200., "#it{p}_{T} (GeV/#it{c})"}; const AxisSpec axisTrackpTFine{1000, 0., 10., "#it{p}_{T} (GeV/#it{c})"}; - const AxisSpec axisJetpT{250, 0., 250., "#it{p}_{T,~ch~jet} (GeV/#it{c})"}; + const AxisSpec axisJetpT{jetPtNbins, jetPtMin, jetPtMax, "#it{p}_{T, ch jet} (GeV/#it{c})"}; // Used in place of axisJetpT for every "_sub"-suffixed histogram (UE-subtracted jet pT can go negative). - const AxisSpec axisJetpTSub{300, -50., 250., "#it{p}_{T,~ch~jet}^{sub} (GeV/#it{c})"}; + const AxisSpec axisJetpTSub{jetPtSubNbins, jetPtSubMin, jetPtSubMax, "#it{p}_{T, ch jet}^{sub} (GeV/#it{c})"}; const AxisSpec axisJetEta{200, -0.8, 0.8, "#it{#eta}_{jet}"}; const AxisSpec axisDb{200, dbMin, dbMax, "#it{D}_{b}"}; const AxisSpec axisDbFine{dbNbins, dbMin, dbMax, "#it{D}_{b}"}; @@ -364,13 +367,19 @@ struct BjetTaggingGnn { if (doprocessMCDJetsSV || doprocessMCDJetsSVSub) { registry.add("h2_SVMass_flavor", "", {HistType::kTH2F, {axisSVMass, axisJetFlavorCat}}, callSumw2); } + // Flavour split into three TH2 (b/c/lf) instead of one TH3 with a flavour axis: GRID-scale hadd + // merging of TH3 has been observed to dump all content into the flavour-axis overflow bin, while the + // equivalent TH2 merges correctly (see fillSVHistograms()/fillMCDJetHistograms() fill sites). auto addSVFlavorHistograms = [&](const AxisSpec& axisJetpT, const std::string& suffix) { - auto hMass = registry.add("h3_SVMass_jetpT_flavor" + suffix, "", HistType::kTH3F, {axisJetpT, axisSVMass, axisJetFlavorCat}, callSumw2); - auto hLxyS = registry.add("h3_SVLxyS_jetpT_flavor" + suffix, "", HistType::kTH3F, {axisJetpT, axisSVLxyS, axisJetFlavorCat}, callSumw2); - auto hDisp = registry.add("h3_SVDispersion_jetpT_flavor" + suffix, "", HistType::kTH3F, {axisJetpT, axisSVDispersion, axisJetFlavorCat}, callSumw2); - setJetFlavorCatAxisLabels(hMass->GetZaxis()); - setJetFlavorCatAxisLabels(hLxyS->GetZaxis()); - setJetFlavorCatAxisLabels(hDisp->GetZaxis()); + registry.add("h2_SVMass_jetpT_b" + suffix, "", HistType::kTH2F, {axisJetpT, axisSVMass}, callSumw2); + registry.add("h2_SVMass_jetpT_c" + suffix, "", HistType::kTH2F, {axisJetpT, axisSVMass}, callSumw2); + registry.add("h2_SVMass_jetpT_lf" + suffix, "", HistType::kTH2F, {axisJetpT, axisSVMass}, callSumw2); + registry.add("h2_SVLxyS_jetpT_b" + suffix, "", HistType::kTH2F, {axisJetpT, axisSVLxyS}, callSumw2); + registry.add("h2_SVLxyS_jetpT_c" + suffix, "", HistType::kTH2F, {axisJetpT, axisSVLxyS}, callSumw2); + registry.add("h2_SVLxyS_jetpT_lf" + suffix, "", HistType::kTH2F, {axisJetpT, axisSVLxyS}, callSumw2); + registry.add("h2_SVDispersion_jetpT_b" + suffix, "", HistType::kTH2F, {axisJetpT, axisSVDispersion}, callSumw2); + registry.add("h2_SVDispersion_jetpT_c" + suffix, "", HistType::kTH2F, {axisJetpT, axisSVDispersion}, callSumw2); + registry.add("h2_SVDispersion_jetpT_lf" + suffix, "", HistType::kTH2F, {axisJetpT, axisSVDispersion}, callSumw2); }; auto addCoreJetHistograms = [&](const AxisSpec& axisJetpT, const std::string& suffix) { registry.add("h_jetpT" + suffix, "", HistType::kTH1F, {axisJetpT}, callSumw2); @@ -477,7 +486,9 @@ struct BjetTaggingGnn { // just the core Db/flavor spectra. Histograms whose value doesn't depend on jetpT are booked once, above. if (doprocessMCDJets || doprocessMCDJetsSV || doprocessMCDJetsSub || doprocessMCDJetsSVSub) { registry.add("h2_Db_flavor", "", {HistType::kTH2F, {axisDbFine, axisJetFlavorCat}}); - registry.add("h3_nTracks_Db_flavor", "", {HistType::kTH3F, {axisNTracks, axisDb, axisJetFlavorCat}}); + registry.add("h2_nTracks_Db_b", "", {HistType::kTH2F, {axisNTracks, axisDb}}); + registry.add("h2_nTracks_Db_c", "", {HistType::kTH2F, {axisNTracks, axisDb}}); + registry.add("h2_nTracks_Db_lf", "", {HistType::kTH2F, {axisNTracks, axisDb}}); registry.add("h2_Db_lfmatch", "lf-jet", {HistType::kTH2F, {axisDbFine, axisLfMatchStatus}}); registry.add("h_Db_npp", "NotPhysPrim", {HistType::kTH1F, {axisDbFine}}); registry.add("h2_Db_npp_flavor", "NotPhysPrim", {HistType::kTH2F, {axisDbFine, axisJetFlavorCat}}); @@ -485,24 +496,26 @@ struct BjetTaggingGnn { setLfMatchStatusAxisLabels(registry.get(HIST("h2_Db_lfmatch"))->GetYaxis()); setLfMatchStatusAxisLabels(registry.get(HIST("h2_Db_npp_lfmatch"))->GetYaxis()); setJetFlavorCatAxisLabels(registry.get(HIST("h2_Db_flavor"))->GetYaxis()); - setJetFlavorCatAxisLabels(registry.get(HIST("h3_nTracks_Db_flavor"))->GetZaxis()); setJetFlavorCatAxisLabels(registry.get(HIST("h2_Db_npp_flavor"))->GetYaxis()); } auto addMCDFlavorAndMatchedHistograms = [&](const AxisSpec& axisJetpT, const std::string& suffix) { auto hJetpTFlavor = registry.add("h2_jetpT_flavor" + suffix, "", HistType::kTH2F, {axisJetpT, axisJetFlavorCat}, callSumw2); - auto hJetpTDbFlavor = registry.add("h3_jetpT_Db_flavor" + suffix, "", HistType::kTH3F, {axisJetpT, axisDb, axisJetFlavorCat}); + registry.add("h2_jetpT_Db_b" + suffix, "", HistType::kTH2F, {axisJetpT, axisDb}); + registry.add("h2_jetpT_Db_c" + suffix, "", HistType::kTH2F, {axisJetpT, axisDb}); + registry.add("h2_jetpT_Db_lf" + suffix, "", HistType::kTH2F, {axisJetpT, axisDb}); auto hJetpTLfmatch = registry.add("h2_jetpT_lfmatch" + suffix, "lf-jet", HistType::kTH2F, {axisJetpT, axisLfMatchStatus}, callSumw2); - auto hJetpTDbLfmatch = registry.add("h3_jetpT_Db_lfmatch" + suffix, "lf-jet", HistType::kTH3F, {axisJetpT, axisDb, axisLfMatchStatus}, callSumw2); setLfMatchStatusAxisLabels(hJetpTLfmatch->GetYaxis()); - setLfMatchStatusAxisLabels(hJetpTDbLfmatch->GetZaxis()); + registry.add("h2_jetpT_Db_lfmatched" + suffix, "lf-jet", HistType::kTH2F, {axisJetpT, axisDb}, callSumw2); + registry.add("h2_jetpT_Db_lfnone" + suffix, "lf-jet", HistType::kTH2F, {axisJetpT, axisDb}, callSumw2); auto hResponse = registry.add("h2_Response_DetjetpT_PartjetpT" + suffix, "", HistType::kTH2F, {axisJetpT, axisJetpT}, callSumw2); - auto hResponseFlavor = registry.add("h3_Response_DetjetpT_PartjetpT_flavor" + suffix, "", HistType::kTH3F, {axisJetpT, axisJetpT, axisJetFlavorCat}, callSumw2); + registry.add("h2_Response_DetjetpT_PartjetpT_b" + suffix, "", HistType::kTH2F, {axisJetpT, axisJetpT}, callSumw2); + registry.add("h2_Response_DetjetpT_PartjetpT_c" + suffix, "", HistType::kTH2F, {axisJetpT, axisJetpT}, callSumw2); + registry.add("h2_Response_DetjetpT_PartjetpT_lf" + suffix, "", HistType::kTH2F, {axisJetpT, axisJetpT}, callSumw2); registry.add("h2_jetpT_Db_npp" + suffix, "NotPhysPrim", HistType::kTH2F, {axisJetpT, axisDb}); - auto hJetpTDbNppFlavor = registry.add("h3_jetpT_Db_npp_flavor" + suffix, "NotPhysPrim", HistType::kTH3F, {axisJetpT, axisDb, axisJetFlavorCat}); + registry.add("h2_jetpT_Db_npp_b" + suffix, "NotPhysPrim", HistType::kTH2F, {axisJetpT, axisDb}); + registry.add("h2_jetpT_Db_npp_c" + suffix, "NotPhysPrim", HistType::kTH2F, {axisJetpT, axisDb}); + registry.add("h2_jetpT_Db_npp_lf" + suffix, "NotPhysPrim", HistType::kTH2F, {axisJetpT, axisDb}); setJetFlavorCatAxisLabels(hJetpTFlavor->GetYaxis()); - setJetFlavorCatAxisLabels(hJetpTDbFlavor->GetZaxis()); - setJetFlavorCatAxisLabels(hResponseFlavor->GetZaxis()); - setJetFlavorCatAxisLabels(hJetpTDbNppFlavor->GetZaxis()); (void)hResponse; registry.add("h_jetpT_matched" + suffix, "", HistType::kTH1F, {axisJetpT}, callSumw2); @@ -766,7 +779,7 @@ struct BjetTaggingGnn { } } - // lf-jets further split by MC-particle-jet match status (see h3_jetpT_Db_lfmatch). + // lf-jets further split by MC-particle-jet match status (see h2_jetpT_Db_lfmatched/h2_jetpT_Db_lfnone). static double getLfMatchStatus(int8_t jetFlavor) { return (jetFlavor == JetTaggingSpecies::none) ? 1. : 0.; @@ -780,11 +793,11 @@ struct BjetTaggingGnn { // Selects the SV with the highest decay length significance out of all SVs matched to the jet, // shared by fillDataJetHistogramsSV()/fillMCDJetHistogramsSV(). Fills the inclusive SV histograms - // (plus the flavour-split variants when flavorCat >= 0, i.e. for MCD jets) and returns the + // (plus the flavour-split variants when jetFlavor >= 0, i.e. for MCD jets) and returns the // selected SV's mass (-1 if the jet has no SV). `jetpT` is passed in already raw-or-UE-subtracted by // the caller (per `withSub`) rather than recomputed here, since this function doesn't otherwise need rho. template - float fillSVHistograms(AnalysisJet const& analysisJet, SecondaryVertices const& /*allSVs*/, float jetpT, double weightEvt = 1.0, double flavorCat = -1.0) + float fillSVHistograms(AnalysisJet const& analysisJet, SecondaryVertices const& /*allSVs*/, float jetpT, double weightEvt = 1.0, int8_t jetFlavor = -1) { auto svs = analysisJet.template secondaryVertices_as(); if (svs.size() == 0) { @@ -801,26 +814,42 @@ struct BjetTaggingGnn { // jetpT-axis histograms below get the "_sub" name instead of a second registry (see `registry`'s // declaration). registry.fill(HIST("h_SVMass"), massSV, weightEvt); - if (flavorCat >= 0.) { - registry.fill(HIST("h2_SVMass_flavor"), massSV, flavorCat, weightEvt); + if (jetFlavor >= 0) { + registry.fill(HIST("h2_SVMass_flavor"), massSV, getJetFlavorCat(jetFlavor), weightEvt); } if constexpr (withSub) { registry.fill(HIST("h2_SVMass_jetpT_sub"), jetpT, massSV, weightEvt); registry.fill(HIST("h2_SVLxyS_jetpT_sub"), jetpT, lxyS, weightEvt); registry.fill(HIST("h2_SVDispersion_jetpT_sub"), jetpT, sv.dispersion(), weightEvt); - if (flavorCat >= 0.) { - registry.fill(HIST("h3_SVMass_jetpT_flavor_sub"), jetpT, massSV, flavorCat, weightEvt); - registry.fill(HIST("h3_SVLxyS_jetpT_flavor_sub"), jetpT, lxyS, flavorCat, weightEvt); - registry.fill(HIST("h3_SVDispersion_jetpT_flavor_sub"), jetpT, sv.dispersion(), flavorCat, weightEvt); + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h2_SVMass_jetpT_b_sub"), jetpT, massSV, weightEvt); + registry.fill(HIST("h2_SVLxyS_jetpT_b_sub"), jetpT, lxyS, weightEvt); + registry.fill(HIST("h2_SVDispersion_jetpT_b_sub"), jetpT, sv.dispersion(), weightEvt); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h2_SVMass_jetpT_c_sub"), jetpT, massSV, weightEvt); + registry.fill(HIST("h2_SVLxyS_jetpT_c_sub"), jetpT, lxyS, weightEvt); + registry.fill(HIST("h2_SVDispersion_jetpT_c_sub"), jetpT, sv.dispersion(), weightEvt); + } else if (jetFlavor >= 0) { + registry.fill(HIST("h2_SVMass_jetpT_lf_sub"), jetpT, massSV, weightEvt); + registry.fill(HIST("h2_SVLxyS_jetpT_lf_sub"), jetpT, lxyS, weightEvt); + registry.fill(HIST("h2_SVDispersion_jetpT_lf_sub"), jetpT, sv.dispersion(), weightEvt); } } else { registry.fill(HIST("h2_SVMass_jetpT"), jetpT, massSV, weightEvt); registry.fill(HIST("h2_SVLxyS_jetpT"), jetpT, lxyS, weightEvt); registry.fill(HIST("h2_SVDispersion_jetpT"), jetpT, sv.dispersion(), weightEvt); - if (flavorCat >= 0.) { - registry.fill(HIST("h3_SVMass_jetpT_flavor"), jetpT, massSV, flavorCat, weightEvt); - registry.fill(HIST("h3_SVLxyS_jetpT_flavor"), jetpT, lxyS, flavorCat, weightEvt); - registry.fill(HIST("h3_SVDispersion_jetpT_flavor"), jetpT, sv.dispersion(), flavorCat, weightEvt); + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h2_SVMass_jetpT_b"), jetpT, massSV, weightEvt); + registry.fill(HIST("h2_SVLxyS_jetpT_b"), jetpT, lxyS, weightEvt); + registry.fill(HIST("h2_SVDispersion_jetpT_b"), jetpT, sv.dispersion(), weightEvt); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h2_SVMass_jetpT_c"), jetpT, massSV, weightEvt); + registry.fill(HIST("h2_SVLxyS_jetpT_c"), jetpT, lxyS, weightEvt); + registry.fill(HIST("h2_SVDispersion_jetpT_c"), jetpT, sv.dispersion(), weightEvt); + } else if (jetFlavor >= 0) { + registry.fill(HIST("h2_SVMass_jetpT_lf"), jetpT, massSV, weightEvt); + registry.fill(HIST("h2_SVLxyS_jetpT_lf"), jetpT, lxyS, weightEvt); + registry.fill(HIST("h2_SVDispersion_jetpT_lf"), jetpT, sv.dispersion(), weightEvt); } } return massSV; @@ -950,7 +979,13 @@ struct BjetTaggingGnn { registry.fill(HIST("h_Db"), analysisJet.scoreML(), weightEvt); registry.fill(HIST("h2_nTracks_Db"), nTracks, analysisJet.scoreML(), weightEvt); registry.fill(HIST("h2_Db_flavor"), analysisJet.scoreML(), flavorCat, weightEvt); - registry.fill(HIST("h3_nTracks_Db_flavor"), nTracks, analysisJet.scoreML(), flavorCat, weightEvt); + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h2_nTracks_Db_b"), nTracks, analysisJet.scoreML(), weightEvt); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h2_nTracks_Db_c"), nTracks, analysisJet.scoreML(), weightEvt); + } else { + registry.fill(HIST("h2_nTracks_Db_lf"), nTracks, analysisJet.scoreML(), weightEvt); + } bool isLf = jetFlavor != JetTaggingSpecies::beauty && jetFlavor != JetTaggingSpecies::charm; if (isLf) { registry.fill(HIST("h2_Db_lfmatch"), analysisJet.scoreML(), getLfMatchStatus(jetFlavor), weightEvt); @@ -968,14 +1003,30 @@ struct BjetTaggingGnn { registry.fill(HIST("h_jetpT_sub"), jetpT, weightEvt); registry.fill(HIST("h2_jetpT_Db_sub"), jetpT, analysisJet.scoreML(), weightEvt); registry.fill(HIST("h2_jetpT_flavor_sub"), jetpT, flavorCat, weightEvt); - registry.fill(HIST("h3_jetpT_Db_flavor_sub"), jetpT, analysisJet.scoreML(), flavorCat, weightEvt); + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h2_jetpT_Db_b_sub"), jetpT, analysisJet.scoreML(), weightEvt); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h2_jetpT_Db_c_sub"), jetpT, analysisJet.scoreML(), weightEvt); + } else { + registry.fill(HIST("h2_jetpT_Db_lf_sub"), jetpT, analysisJet.scoreML(), weightEvt); + } if (isLf) { registry.fill(HIST("h2_jetpT_lfmatch_sub"), jetpT, getLfMatchStatus(jetFlavor), weightEvt); - registry.fill(HIST("h3_jetpT_Db_lfmatch_sub"), jetpT, analysisJet.scoreML(), getLfMatchStatus(jetFlavor), weightEvt); + if (jetFlavor == JetTaggingSpecies::none) { + registry.fill(HIST("h2_jetpT_Db_lfnone_sub"), jetpT, analysisJet.scoreML(), weightEvt); + } else { + registry.fill(HIST("h2_jetpT_Db_lfmatched_sub"), jetpT, analysisJet.scoreML(), weightEvt); + } } if (isNpp) { registry.fill(HIST("h2_jetpT_Db_npp_sub"), jetpT, analysisJet.scoreML(), weightEvt); - registry.fill(HIST("h3_jetpT_Db_npp_flavor_sub"), jetpT, analysisJet.scoreML(), flavorCat, weightEvt); + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h2_jetpT_Db_npp_b_sub"), jetpT, analysisJet.scoreML(), weightEvt); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h2_jetpT_Db_npp_c_sub"), jetpT, analysisJet.scoreML(), weightEvt); + } else { + registry.fill(HIST("h2_jetpT_Db_npp_lf_sub"), jetpT, analysisJet.scoreML(), weightEvt); + } } if (doDataDriven && !doDataDrivenSV) { @@ -1013,14 +1064,30 @@ struct BjetTaggingGnn { registry.fill(HIST("h_jetpT"), jetpT, weightEvt); registry.fill(HIST("h2_jetpT_Db"), jetpT, analysisJet.scoreML(), weightEvt); registry.fill(HIST("h2_jetpT_flavor"), jetpT, flavorCat, weightEvt); - registry.fill(HIST("h3_jetpT_Db_flavor"), jetpT, analysisJet.scoreML(), flavorCat, weightEvt); + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h2_jetpT_Db_b"), jetpT, analysisJet.scoreML(), weightEvt); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h2_jetpT_Db_c"), jetpT, analysisJet.scoreML(), weightEvt); + } else { + registry.fill(HIST("h2_jetpT_Db_lf"), jetpT, analysisJet.scoreML(), weightEvt); + } if (isLf) { registry.fill(HIST("h2_jetpT_lfmatch"), jetpT, getLfMatchStatus(jetFlavor), weightEvt); - registry.fill(HIST("h3_jetpT_Db_lfmatch"), jetpT, analysisJet.scoreML(), getLfMatchStatus(jetFlavor), weightEvt); + if (jetFlavor == JetTaggingSpecies::none) { + registry.fill(HIST("h2_jetpT_Db_lfnone"), jetpT, analysisJet.scoreML(), weightEvt); + } else { + registry.fill(HIST("h2_jetpT_Db_lfmatched"), jetpT, analysisJet.scoreML(), weightEvt); + } } if (isNpp) { registry.fill(HIST("h2_jetpT_Db_npp"), jetpT, analysisJet.scoreML(), weightEvt); - registry.fill(HIST("h3_jetpT_Db_npp_flavor"), jetpT, analysisJet.scoreML(), flavorCat, weightEvt); + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h2_jetpT_Db_npp_b"), jetpT, analysisJet.scoreML(), weightEvt); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h2_jetpT_Db_npp_c"), jetpT, analysisJet.scoreML(), weightEvt); + } else { + registry.fill(HIST("h2_jetpT_Db_npp_lf"), jetpT, analysisJet.scoreML(), weightEvt); + } } if (doDataDriven && !doDataDrivenSV) { @@ -1066,13 +1133,37 @@ struct BjetTaggingGnn { { auto [jetFlavor, nTracks] = fillMCDJetHistograms(analysisJet, allTracks, rho, weightEvt); float jetpT = withSub ? (analysisJet.pt() - rho * analysisJet.area()) : analysisJet.pt(); - float massSV = fillSVHistograms(analysisJet, allSVs, jetpT, weightEvt, getJetFlavorCat(jetFlavor)); + float massSV = fillSVHistograms(analysisJet, allSVs, jetpT, weightEvt, jetFlavor); if (doDataDriven && doDataDrivenSV) { if constexpr (withSub) { registry.fill(HIST("hSparse_Incljets_sub"), jetpT, analysisJet.scoreML(), nTracks, massSV, weightEvt); + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("hSparse_bjets_sub"), jetpT, analysisJet.scoreML(), nTracks, massSV, weightEvt); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("hSparse_cjets_sub"), jetpT, analysisJet.scoreML(), nTracks, massSV, weightEvt); + } else { + registry.fill(HIST("hSparse_lfjets_sub"), jetpT, analysisJet.scoreML(), nTracks, massSV, weightEvt); + if (jetFlavor == JetTaggingSpecies::none) { + registry.fill(HIST("hSparse_lfjets_none_sub"), jetpT, analysisJet.scoreML(), nTracks, massSV, weightEvt); + } else { + registry.fill(HIST("hSparse_lfjets_matched_sub"), jetpT, analysisJet.scoreML(), nTracks, massSV, weightEvt); + } + } } else { registry.fill(HIST("hSparse_Incljets"), jetpT, analysisJet.scoreML(), nTracks, massSV, weightEvt); + if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("hSparse_bjets"), jetpT, analysisJet.scoreML(), nTracks, massSV, weightEvt); + } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("hSparse_cjets"), jetpT, analysisJet.scoreML(), nTracks, massSV, weightEvt); + } else { + registry.fill(HIST("hSparse_lfjets"), jetpT, analysisJet.scoreML(), nTracks, massSV, weightEvt); + if (jetFlavor == JetTaggingSpecies::none) { + registry.fill(HIST("hSparse_lfjets_none"), jetpT, analysisJet.scoreML(), nTracks, massSV, weightEvt); + } else { + registry.fill(HIST("hSparse_lfjets_matched"), jetpT, analysisJet.scoreML(), nTracks, massSV, weightEvt); + } + } } } @@ -1483,11 +1574,14 @@ struct BjetTaggingGnn { registry.fill(HIST("hSparse_pthat_jetpT_sub"), collision.template mcCollision_as().ptHard(), jetpT, mcpJetpT, weightEvt); // Matched jets registry.fill(HIST("h2_jetpT_matched_flavor_sub"), jetpT, getJetFlavorCat(jetFlavor), weightEvt); registry.fill(HIST("h2_jetpT_particle_matched_flavor_sub"), mcpJetpT, getJetFlavorCat(jetFlavor), weightEvt); - registry.fill(HIST("h3_Response_DetjetpT_PartjetpT_flavor_sub"), jetpT, mcpJetpT, getJetFlavorCat(jetFlavor), weightEvt); if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_b_sub"), jetpT, mcpJetpT, weightEvt); registry.fill(HIST("hSparse_pthat_jetpT_b_sub"), collision.template mcCollision_as().ptHard(), jetpT, mcpJetpT, weightEvt); // Matched b-jets } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_c_sub"), jetpT, mcpJetpT, weightEvt); registry.fill(HIST("hSparse_pthat_jetpT_c_sub"), collision.template mcCollision_as().ptHard(), jetpT, mcpJetpT, weightEvt); // Matched c-jets + } else { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_lf_sub"), jetpT, mcpJetpT, weightEvt); } } else { registry.fill(HIST("h2_Response_DetjetpT_PartjetpT"), jetpT, mcpJetpT, weightEvt); @@ -1496,11 +1590,14 @@ struct BjetTaggingGnn { registry.fill(HIST("hSparse_pthat_jetpT"), collision.template mcCollision_as().ptHard(), jetpT, mcpJetpT, weightEvt); // Matched jets registry.fill(HIST("h2_jetpT_matched_flavor"), jetpT, getJetFlavorCat(jetFlavor), weightEvt); registry.fill(HIST("h2_jetpT_particle_matched_flavor"), mcpJetpT, getJetFlavorCat(jetFlavor), weightEvt); - registry.fill(HIST("h3_Response_DetjetpT_PartjetpT_flavor"), jetpT, mcpJetpT, getJetFlavorCat(jetFlavor), weightEvt); if (jetFlavor == JetTaggingSpecies::beauty) { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_b"), jetpT, mcpJetpT, weightEvt); registry.fill(HIST("hSparse_pthat_jetpT_b"), collision.template mcCollision_as().ptHard(), jetpT, mcpJetpT, weightEvt); // Matched b-jets } else if (jetFlavor == JetTaggingSpecies::charm) { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_c"), jetpT, mcpJetpT, weightEvt); registry.fill(HIST("hSparse_pthat_jetpT_c"), collision.template mcCollision_as().ptHard(), jetpT, mcpJetpT, weightEvt); // Matched c-jets + } else { + registry.fill(HIST("h2_Response_DetjetpT_PartjetpT_lf"), jetpT, mcpJetpT, weightEvt); } } } diff --git a/PWGJE/Tasks/bjetTreeCreator.cxx b/PWGJE/Tasks/bjetTreeCreator.cxx index 52e203d91af..7e3c70b70f5 100644 --- a/PWGJE/Tasks/bjetTreeCreator.cxx +++ b/PWGJE/Tasks/bjetTreeCreator.cxx @@ -49,6 +49,8 @@ #include #include +#include + using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -112,8 +114,8 @@ DECLARE_SOA_COLUMN(TrackTPCNCls, tracktpcncls, float); //! The t DECLARE_SOA_COLUMN(TrackTPCNCrossedRows, tracktpcncrossedrows, float); //! The track TPC NCrossedRows // DECLARE_SOA_COLUMN(TrackTPCNSigmaPi, tracktpcnsigmapi, float); //! The track TPC nSigma Pi // DECLARE_SOA_COLUMN(TrackTOFNSigmaPi, tracktofnsigmapi, float); //! The track TOF nSigma Pi -DECLARE_SOA_COLUMN(TrackOrigin, trk_origin, int); //! The track origin label for GNN track origin predictions -DECLARE_SOA_COLUMN(TrackVtxIndex, trk_vtx_index, int); //! The track vertex index for GNN vertex predictions +DECLARE_SOA_COLUMN(TrackOrigin, trk_origin, int); //! The track origin label for GNN track origin predictions +DECLARE_SOA_COLUMN(TrackVtxIndex, trk_vtx_index, int); //! The track vertex index for GNN vertex predictions // DECLARE_SOA_COLUMN(DCATrackJet, dcatrackjet, float); //! The distance between track and jet, unfortunately it cannot be calculated in O2 } // namespace trackInfo diff --git a/PWGJE/Tasks/emcalGammaGammaBcWise.cxx b/PWGJE/Tasks/emcalGammaGammaBcWise.cxx index aa5e99fb70b..445a17b32d4 100644 --- a/PWGJE/Tasks/emcalGammaGammaBcWise.cxx +++ b/PWGJE/Tasks/emcalGammaGammaBcWise.cxx @@ -116,7 +116,7 @@ bool isPhotonAccepted(Photon const& p, emcal::Geometry* emcalGeom = nullptr) } struct Meson { - Meson(Photon p1, Photon p2) : p1(p1), p2(p2) + Meson(const Photon& p1, const Photon& p2) : p1(p1), p2(p2) { pMeson = p1.photon + p2.photon; } diff --git a/PWGJE/Tasks/emcalPi0EnergyScaleCalib.cxx b/PWGJE/Tasks/emcalPi0EnergyScaleCalib.cxx index 61bff6d13e1..e92aa22905a 100644 --- a/PWGJE/Tasks/emcalPi0EnergyScaleCalib.cxx +++ b/PWGJE/Tasks/emcalPi0EnergyScaleCalib.cxx @@ -178,8 +178,8 @@ struct Photon { }; struct Meson { - Meson(Photon p1, Photon p2) : pgamma1(p1), - pgamma2(p2) + Meson(const Photon& p1, const Photon& p2) : pgamma1(p1), + pgamma2(p2) { pMeson = p1.photon + p2.photon; } diff --git a/PWGJE/Tasks/fullJetSpectra.cxx b/PWGJE/Tasks/fullJetSpectra.cxx index 0af05f60cac..7c9fe31090a 100644 --- a/PWGJE/Tasks/fullJetSpectra.cxx +++ b/PWGJE/Tasks/fullJetSpectra.cxx @@ -1185,7 +1185,7 @@ struct FullJetSpectra { if (bcs.size() == 0) { return; } - for (auto bc : bcs) { + for (const auto& bc : bcs) { registry.fill(HIST("hBCCounter"), 0.5); // All BC if (bc.selection_bit(aod::evsel::EventSelectionFlags::kIsTriggerTVX)) { registry.fill(HIST("hBCCounter"), 1.5); // BC+TVX @@ -1197,7 +1197,7 @@ struct FullJetSpectra { } } auto collisionsInBC = collisions.sliceBy(perFoundBC, bc.globalIndex()); - for (auto collision : collisionsInBC) { + for (const auto& collision : collisionsInBC) { registry.fill(HIST("hBCCounter"), 4.5); // CollinBC if (collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { registry.fill(HIST("hBCCounter"), 5.5); // CollinBC+TVX diff --git a/PWGJE/Tasks/fullJetTriggerQATask.cxx b/PWGJE/Tasks/fullJetTriggerQATask.cxx index 4aff2f9ec2e..4409fdd8c34 100644 --- a/PWGJE/Tasks/fullJetTriggerQATask.cxx +++ b/PWGJE/Tasks/fullJetTriggerQATask.cxx @@ -420,7 +420,7 @@ struct JetTriggerQA { } template - void check_maxJetPt(T const jet, U& vecMaxJet) + void check_maxJetPt(T const& jet, U& vecMaxJet) { for (unsigned int i = 0; i < vecMaxJet.size(); i++) { auto maxJet = vecMaxJet[i]; diff --git a/PWGJE/Tasks/gammaJetTreeProducer.cxx b/PWGJE/Tasks/gammaJetTreeProducer.cxx index 732eb1f9106..8096c260dc3 100644 --- a/PWGJE/Tasks/gammaJetTreeProducer.cxx +++ b/PWGJE/Tasks/gammaJetTreeProducer.cxx @@ -1155,7 +1155,7 @@ struct GammaJetTreeProducer { if (std::find(mcCollisionsMultiRecCollisions.begin(), mcCollisionsMultiRecCollisions.end(), mcCollision.globalIndex()) != mcCollisionsMultiRecCollisions.end()) { isMultipleAssigned = true; } - mcEventsTable(eventsTable.lastIndex(), mcCollision.weight(), mcCollision.rho(), isMultipleAssigned); + mcEventsTable(eventsTable.lastIndex(), mcCollision.weight(), mcCollision.rho(), mcCollision.ptHard(), isMultipleAssigned); } // --------------------- diff --git a/PWGJE/Tasks/jetBackgroundAnalysis.cxx b/PWGJE/Tasks/jetBackgroundAnalysis.cxx index 5e6c6d470de..b58e698bb09 100644 --- a/PWGJE/Tasks/jetBackgroundAnalysis.cxx +++ b/PWGJE/Tasks/jetBackgroundAnalysis.cxx @@ -24,11 +24,13 @@ #include #include +#include #include #include #include #include #include +#include #include #include @@ -74,6 +76,8 @@ struct JetBackgroundAnalysisTask { int trackSelection = -1; TRandom3 randomNumber{}; + o2::framework::Service pdgDatabase; + void init(o2::framework::InitContext&) { // selection settings initialisation @@ -93,6 +97,10 @@ struct JetBackgroundAnalysisTask { registry.add("h2_centrality_rho", "; centrality; #it{rho} (GeV/area);", {HistType::kTH2F, {{1100, 0., 110.}, {400, 0., 400.0}}}); registry.add("h2_centrality_rhom", ";centrality; #it{rho}_{m} (GeV/area)", {HistType::kTH2F, {{1100, 0., 110.}, {100, 0., 100.0}}}); } + if (doprocessRhoMCP) { + registry.add("h2_nparticles_rho_mcp", "; N_{tracks}; #it{rho} (GeV/area);", {HistType::kTH2F, {{10000, 0.0, 10000.0}, {400, 0.0, 400.0}}}); + registry.add("h2_nparticles_rhom_mcp", "; N_{tracks}; #it{rho}_{m} (GeV/area);", {HistType::kTH2F, {{10000, 0.0, 10000.0}, {100, 0.0, 100.0}}}); + } if (doprocessBkgFluctuationsData || doprocessBkgFluctuationsMCD) { registry.add("h2_centrality_rhorandomcone", "; centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH2F, {{1100, 0., 110.}, bkgFluctuationsAxis}}); @@ -101,10 +109,20 @@ struct JetBackgroundAnalysisTask { registry.add("h2_centrality_rhorandomconerandomtrackdirectionwithoutoneleadingjets", "; centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH2F, {{1100, 0., 110.}, bkgFluctuationsAxis}}); registry.add("h2_centrality_rhorandomconerandomtrackdirectionwithouttwoleadingjets", "; centrality; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH2F, {{1100, 0., 110.}, bkgFluctuationsAxis}}); } + + if (doprocessBkgFluctuationsMCP) { + registry.add("h_rhorandomcone", "; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH1F, {bkgFluctuationsAxis}}); + registry.add("h_rhorandomconerandomtrackdirection", "; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH1F, {bkgFluctuationsAxis}}); + registry.add("h_rhorandomconewithoutleadingjet", "; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH1F, {bkgFluctuationsAxis}}); + registry.add("h_rhorandomconerandomtrackdirectionwithoutoneleadingjets", "; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH1F, {bkgFluctuationsAxis}}); + registry.add("h_rhorandomconerandomtrackdirectionwithouttwoleadingjets", "; #it{p}_{T,random cone} - #it{area, random cone} * #it{rho} (GeV/c);", {HistType::kTH1F, {bkgFluctuationsAxis}}); + } } Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax); + Filter particleCuts = (aod::jmcparticle::eta > trackEtaMin && aod::jmcparticle::eta < trackEtaMax); Filter eventCuts = (nabs(aod::jcollision::posZ) < vertexZCut); + Filter mcEventCuts = (nabs(aod::jmccollision::posZ) < vertexZCut); template bool trackIsInJet(TTracks const& track, TJets const& jet) @@ -189,7 +207,7 @@ struct JetBackgroundAnalysisTask { float dPhi = RecoDecay::constrainAngle(randomNumber.Uniform(0.0, o2::constants::math::TwoPI) - randomConePhi, static_cast(-o2::constants::math::PI)); // ignores actual phi of track float dEta = randomNumber.Uniform(trackEtaMin, trackEtaMax) - randomConeEta; // ignores actual eta of track if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { - const bool inLead = hasLead && trackIsInJet(track, jets.iteratorAt(0)); + const bool inLead = trackIsInJet(track, jets.iteratorAt(0)); const bool inSub = hasSub && trackIsInJet(track, jets.iteratorAt(1)); if (!inLead) { randomConePtWithoutOneLeadJet += track.pt(); @@ -205,6 +223,86 @@ struct JetBackgroundAnalysisTask { registry.fill(HIST("h2_centrality_rhorandomconerandomtrackdirectionwithouttwoleadingjets"), centrality, randomConePtWithoutTwoLeadJet - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); } + template + void bkgFluctuationsRandomConeMCP(TCollisions const& collision, TJets const& jets, TTracks const& tracks) + { + float randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); + float randomConePhi = randomNumber.Uniform(0.0, o2::constants::math::TwoPI); + float randomConePt = 0; + for (auto const& track : tracks) { + float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, static_cast(-o2::constants::math::PI)); + float dEta = track.eta() - randomConeEta; + if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + randomConePt += track.pt(); + } + } + registry.fill(HIST("h_rhorandomcone"), randomConePt - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); + + // randomised eta,phi for tracks, to assess part of fluctuations coming from statistically independently emitted particles + float randomConePtRandomTrackDirection = 0; + for (auto const& track : tracks) { + float dPhi = RecoDecay::constrainAngle(randomNumber.Uniform(0.0, o2::constants::math::TwoPI) - randomConePhi, static_cast(-o2::constants::math::PI)); // ignores actual phi of track + float dEta = randomNumber.Uniform(trackEtaMin, trackEtaMax) - randomConeEta; // ignores actual eta of track + if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + randomConePtRandomTrackDirection += track.pt(); + } + } + registry.fill(HIST("h_rhorandomconerandomtrackdirection"), randomConePtRandomTrackDirection - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); + + // removing the leading jet from the random cone + const bool hasLead = jets.size() >= 1; + const bool hasSub = jets.size() >= 2; + float randomConePtWithoutLeadingJet = randomConePt; + if (hasLead) { + float dPhiLeadingJet = RecoDecay::constrainAngle(jets.iteratorAt(0).phi() - randomConePhi, static_cast(-o2::constants::math::PI)); + float dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; + + bool jetWasInCone = false; + while ((randomConeLeadJetDeltaR <= 0 && (std::sqrt(dEtaLeadingJet * dEtaLeadingJet + dPhiLeadingJet * dPhiLeadingJet) < jets.iteratorAt(0).r() / 100.0 + randomConeR)) || (randomConeLeadJetDeltaR > 0 && (std::sqrt(dEtaLeadingJet * dEtaLeadingJet + dPhiLeadingJet * dPhiLeadingJet) < randomConeLeadJetDeltaR))) { + jetWasInCone = true; + randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); + randomConePhi = randomNumber.Uniform(0.0, o2::constants::math::TwoPI); + dPhiLeadingJet = RecoDecay::constrainAngle(jets.iteratorAt(0).phi() - randomConePhi, static_cast(-o2::constants::math::PI)); + dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; + } + if (jetWasInCone) { + randomConePtWithoutLeadingJet = 0.0; + for (auto const& track : tracks) { + float dPhi = RecoDecay::constrainAngle(track.phi() - randomConePhi, static_cast(-o2::constants::math::PI)); + float dEta = track.eta() - randomConeEta; + if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + randomConePtWithoutLeadingJet += track.pt(); + } + } + } + } + registry.fill(HIST("h_rhorandomconewithoutleadingjet"), randomConePtWithoutLeadingJet - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); + + // randomised eta,phi for tracks, to assess part of fluctuations coming from statistically independently emitted particles, removing tracks from 2 leading jets + double randomConePtWithoutOneLeadJet = randomConePtRandomTrackDirection; + double randomConePtWithoutTwoLeadJet = randomConePtRandomTrackDirection; + if (hasLead) { + randomConePtWithoutOneLeadJet = 0.0; + randomConePtWithoutTwoLeadJet = 0.0; + for (auto const& track : tracks) { + float dPhi = RecoDecay::constrainAngle(randomNumber.Uniform(0.0, o2::constants::math::TwoPI) - randomConePhi, static_cast(-o2::constants::math::PI)); // ignores actual phi of track + float dEta = randomNumber.Uniform(trackEtaMin, trackEtaMax) - randomConeEta; // ignores actual eta of track + if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { + const bool inLead = trackIsInJet(track, jets.iteratorAt(0)); + const bool inSub = hasSub && trackIsInJet(track, jets.iteratorAt(1)); + if (!inLead) { + randomConePtWithoutOneLeadJet += track.pt(); + if (!hasSub || !inSub) { + randomConePtWithoutTwoLeadJet += track.pt(); + } + } + } + } + } + registry.fill(HIST("h_rhorandomconerandomtrackdirectionwithoutoneleadingjets"), randomConePtWithoutOneLeadJet - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); + registry.fill(HIST("h_rhorandomconerandomtrackdirectionwithouttwoleadingjets"), randomConePtWithoutTwoLeadJet - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); + } + void processRho(soa::Filtered>::iterator const& collision, soa::Filtered const& tracks) { if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents)) { @@ -230,7 +328,23 @@ struct JetBackgroundAnalysisTask { registry.fill(HIST("h2_centrality_rho"), centrality, collision.rho()); registry.fill(HIST("h2_centrality_rhom"), centrality, collision.rhoM()); } - PROCESS_SWITCH(JetBackgroundAnalysisTask, processRho, "QA for rho-area subtracted jets", false); + PROCESS_SWITCH(JetBackgroundAnalysisTask, processRho, "QA for rho-area subtracted jets", true); + + void processRhoMCP(soa::Filtered>::iterator const& mcCollision, soa::Filtered const& particles) + { + // no event selection as this is used for gen-only simulations + int nParticles = 0; + for (auto const& particle : particles) { + auto pdgParticle = pdgDatabase->GetParticle(particle.pdgCode()); + auto pdgCharge = pdgParticle ? std::abs(pdgParticle->Charge()) : -1.0; + if (pdgCharge > 0) { + nParticles++; + } + } + registry.fill(HIST("h2_nparticles_rho_mcp"), nParticles, mcCollision.rho()); + registry.fill(HIST("h2_nparticles_rhom_mcp"), nParticles, mcCollision.rhoM()); + } + PROCESS_SWITCH(JetBackgroundAnalysisTask, processRhoMCP, "QA for rho-area subtracted jets at the MCP level", false); void processBkgFluctuationsData(soa::Filtered>::iterator const& collision, soa::Join const& jets, soa::Filtered const& tracks) { @@ -265,6 +379,13 @@ struct JetBackgroundAnalysisTask { bkgFluctuationsRandomCone(collision, jets, tracks, centrality); } PROCESS_SWITCH(JetBackgroundAnalysisTask, processBkgFluctuationsMCD, "QA for random cone estimation of background fluctuations in mcd", false); + + void processBkgFluctuationsMCP(soa::Filtered>::iterator const& collision, soa::Join const& jets, soa::Filtered const& tracks) + { + // no event selection as this is used for gen-only simulations + bkgFluctuationsRandomConeMCP(collision, jets, tracks); + } + PROCESS_SWITCH(JetBackgroundAnalysisTask, processBkgFluctuationsMCP, "QA for random cone estimation of background fluctuations in mcp", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGJE/Tasks/jetD0AngSubstructure.cxx b/PWGJE/Tasks/jetD0AngSubstructure.cxx index c8df1ac97dd..8a14b780d36 100644 --- a/PWGJE/Tasks/jetD0AngSubstructure.cxx +++ b/PWGJE/Tasks/jetD0AngSubstructure.cxx @@ -698,7 +698,7 @@ struct JetD0AngSubstructure { typename JetTableMCP, typename CandidatesMCD, typename CandidatesMCP> - void analyseMonteCarlo(MCPJetsPerMCCollissionPreslice jetmcpreslice, + void analyseMonteCarlo(const MCPJetsPerMCCollissionPreslice& jetmcpreslice, aod::JetMcCollisions const& mccollisions, aod::JetCollisionsMCD const& collisions, JetTableMCD const& /*mcdjets*/, diff --git a/PWGJE/Tasks/jetDebug.cxx b/PWGJE/Tasks/jetDebug.cxx index 53b440e8ea8..d384f3a5e36 100644 --- a/PWGJE/Tasks/jetDebug.cxx +++ b/PWGJE/Tasks/jetDebug.cxx @@ -147,7 +147,7 @@ struct JetDebugTask { if (jetderiveddatautilities::selectCollision(collision, eventSelection, false, false)) { registry.fill(HIST("h_collisions"), 2.0); } - for (auto track : tracks) { + for (const auto& track : tracks) { registry.fill(HIST("h_track_pt"), track.pt()); registry.fill(HIST("h_track_phi"), track.phi()); registry.fill(HIST("h_track_eta"), track.eta()); @@ -218,7 +218,7 @@ struct JetDebugTask { if (jetderiveddatautilities::selectCollision(collision, eventSelection, false, false)) { registry.fill(HIST("h_collisions"), 2.0); } - for (auto track : tracks) { + for (const auto& track : tracks) { registry.fill(HIST("h_track_pt"), track.pt()); registry.fill(HIST("h_track_phi"), track.phi()); registry.fill(HIST("h_track_eta"), track.eta()); @@ -299,7 +299,7 @@ struct JetDebugTask { void processMCPCharged(aod::JMcCollision const&, soa::Join const& jets, aod::JMcParticles const& tracks) { - for (auto track : tracks) { + for (const auto& track : tracks) { registry.fill(HIST("h_particle_pt"), track.pt()); registry.fill(HIST("h_particle_phi"), track.phi()); registry.fill(HIST("h_particle_eta"), track.eta()); diff --git a/PWGJE/Tasks/jetDsSpecSubs.cxx b/PWGJE/Tasks/jetDsSpecSubs.cxx index d440e03fe4a..593fd0f63e5 100644 --- a/PWGJE/Tasks/jetDsSpecSubs.cxx +++ b/PWGJE/Tasks/jetDsSpecSubs.cxx @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -51,25 +52,137 @@ consteval float getValFromBin(int bin) enum BinExpColCntr { AllCollisions = 1, Sel8ZCut = 2 }; -enum BinExpJetCntr { ChargedJets = 1 }; -enum BinMCColCntr { All = 1, - ZCut = 2, - Matched = 3, - MatchedSel8ZCut = 4 +enum BinMCColCntr { AllMCCollisions = 1, + SelectedMCCollisions = 2, + AssociatedRecoCollisions = 3, + SelectedAssociatedRecoCollisions = 4 }; -enum BinMCJetCntr { DetectorLevelJetInMCCollision = 1, - ParticleLevelJetInMCCollision = 2, - DetectorLevelJetWithMatchedCandidate = 3, - ParticleLevelJetWithMatchedCandidate = 4 +enum BinMCJetCntr { + MCPJets = 1, + MCPJetsWithMCDMatch = 2, + MCDJets = 3, + MCDJetsWithMCPMatch = 4, + MatchedPairs = 5 }; +//============================================================== +// AOD tables for Ds-tagged jet observables +//============================================================== +namespace o2::aod +{ +namespace jet_ds_output +{ +// Jet observables +DECLARE_SOA_COLUMN(JetPt, jetPt, float); +DECLARE_SOA_COLUMN(JetEta, jetEta, float); +DECLARE_SOA_COLUMN(JetPhi, jetPhi, float); +DECLARE_SOA_COLUMN(JetNConst, jetNConst, int); +// Ds observables +DECLARE_SOA_COLUMN(DsPt, dsPt, float); +DECLARE_SOA_COLUMN(DsEta, dsEta, float); +DECLARE_SOA_COLUMN(DsPhi, dsPhi, float); +DECLARE_SOA_COLUMN(DsMass, dsMass, float); +// Ds-jet observables +DECLARE_SOA_COLUMN(ZParallel, zParallel, float); +DECLARE_SOA_COLUMN(DeltaR, deltaR, float); +// MC information +DECLARE_SOA_COLUMN(DsOrigin, dsOrigin, int); +DECLARE_SOA_COLUMN(IsMatched, isMatched, bool); +// Matched MCP <-> MCD observables +// Particle level +DECLARE_SOA_COLUMN(McpJetPt, mcpJetPt, float); +DECLARE_SOA_COLUMN(McpJetEta, mcpJetEta, float); +DECLARE_SOA_COLUMN(McpJetPhi, mcpJetPhi, float); +DECLARE_SOA_COLUMN(McpJetNConst, mcpJetNConst, int); +DECLARE_SOA_COLUMN(McpDsPt, mcpDsPt, float); +DECLARE_SOA_COLUMN(McpDsEta, mcpDsEta, float); +DECLARE_SOA_COLUMN(McpDsPhi, mcpDsPhi, float); +DECLARE_SOA_COLUMN(McpZParallel, mcpZParallel, float); +DECLARE_SOA_COLUMN(McpDeltaR, mcpDeltaR, float); + +DECLARE_SOA_COLUMN(McdJetPt, mcdJetPt, float); +DECLARE_SOA_COLUMN(McdJetEta, mcdJetEta, float); +DECLARE_SOA_COLUMN(McdJetPhi, mcdJetPhi, float); +DECLARE_SOA_COLUMN(McdJetNConst, mcdJetNConst, int); +DECLARE_SOA_COLUMN(McdDsPt, mcdDsPt, float); +DECLARE_SOA_COLUMN(McdDsEta, mcdDsEta, float); +DECLARE_SOA_COLUMN(McdDsPhi, mcdDsPhi, float); +DECLARE_SOA_COLUMN(McdDsMass, mcdDsMass, float); +DECLARE_SOA_COLUMN(McdZParallel, mcdZParallel, float); +DECLARE_SOA_COLUMN(McdDeltaR, mcdDeltaR, float); +// MC truth matching information +DECLARE_SOA_COLUMN(DsFlagMcMatchRec, dsFlagMcMatchRec, int); +DECLARE_SOA_COLUMN(DsFlagMcMatchGen, dsFlagMcMatchGen, int); +// MC truth information +DECLARE_SOA_COLUMN(MatchedDsOrigin, matchedDsOrigin, int); +} // namespace jet_ds_output +// Detector-level Ds-tagged jets +DECLARE_SOA_TABLE(DsMCDJetTable, "AOD", "DSMCDJET", + jet_ds_output::JetPt, + jet_ds_output::JetEta, + jet_ds_output::JetPhi, + jet_ds_output::JetNConst, + jet_ds_output::DsPt, + jet_ds_output::DsEta, + jet_ds_output::DsPhi, + jet_ds_output::DsMass, + jet_ds_output::ZParallel, + jet_ds_output::DeltaR, + jet_ds_output::DsOrigin, + jet_ds_output::DsFlagMcMatchRec, + jet_ds_output::IsMatched); +// Particle-level Ds-tagged jets +DECLARE_SOA_TABLE(DsMCPJetTable, "AOD", "DSMCPJET", + jet_ds_output::JetPt, + jet_ds_output::JetEta, + jet_ds_output::JetPhi, + jet_ds_output::JetNConst, + jet_ds_output::DsPt, + jet_ds_output::DsEta, + jet_ds_output::DsPhi, + jet_ds_output::ZParallel, + jet_ds_output::DeltaR, + jet_ds_output::DsOrigin, + jet_ds_output::DsFlagMcMatchGen, + jet_ds_output::IsMatched); +// Matched particle-level <-> detector-level Ds-tagged jet pairs +DECLARE_SOA_TABLE(DsMatchedJetTable, "AOD", "DSMATCHJET", + // Particle level + jet_ds_output::McpJetPt, + jet_ds_output::McpJetEta, + jet_ds_output::McpJetPhi, + jet_ds_output::McpJetNConst, + jet_ds_output::McpDsPt, + jet_ds_output::McpDsEta, + jet_ds_output::McpDsPhi, + jet_ds_output::McpZParallel, + jet_ds_output::McpDeltaR, + // Detector level + jet_ds_output::McdJetPt, + jet_ds_output::McdJetEta, + jet_ds_output::McdJetPhi, + jet_ds_output::McdJetNConst, + jet_ds_output::McdDsPt, + jet_ds_output::McdDsEta, + jet_ds_output::McdDsPhi, + jet_ds_output::McdDsMass, + jet_ds_output::McdZParallel, + jet_ds_output::McdDeltaR, + // Truth + jet_ds_output::MatchedDsOrigin); +} // namespace o2::aod + struct JetDsSpecSubs { //================== // Type definitions //================== + Produces outputMCDJets; + Produces outputMCPJets; + Produces outputMatchedJets; + using DsCandidatesData = aod::CandidatesDsData; using DsCandidatesMCD = aod::CandidatesDsMCD; using DsCandidatesMCP = aod::CandidatesDsMCP; @@ -90,36 +203,30 @@ struct JetDsSpecSubs { // Slices for access to proper HF MCD jet collision that is associated to MCCollision PresliceUnsorted collisionsPerMCCollisionPreslice = aod::jmccollisionlb::mcCollisionId; - Preslice dsMCDJetsPerEXPCollisionPreslice = aod::jet::collisionId; // Preslice dsMCDJetsEWSPerEXPCollisionPreslice = aod::jet::collisionId; - Preslice dsMCPJetsPerMCCollisionPreslice = aod::jet::mcCollisionId; // Preslice dsMCPJetsEWSPerMCCollisionPreslice = aod::jet::mcCollisionId; // Event configurables Configurable vertexZCut{"vertexZCut", 10.0f, "Accepted z-vertex range"}; - Configurable jetPtMin{"jetPtMin", 5.0, "minimum jet pT cut"}; - Configurable jetR{"jetR", 0.4, "jet resolution parameter"}; + Configurable jetPtMin{"jetPtMin", 3.0, "minimum jet pT cut"}; + // Configurable jetR{"jetR", 0.4, "jet resolution parameter"}; Configurable eventSelections{"eventSelections", "sel8", "choose event selection"}; Configurable trackSelections{"trackSelections", "globalTracks", "set track selections"}; // Event-wise constituent subtraction jet tables - Configurable centralityMin{"centralityMin", -999.f, "Minimum FT0M centrality"}; - Configurable centralityMax{"centralityMax", 999.f, "Maximum FT0M centrality"}; + // Configurable centralityMin{"centralityMin", -999.f, "Minimum FT0M centrality"}; + // Configurable centralityMax{"centralityMax", 999.f, "Maximum FT0M centrality"}; // internals std::vector eventSelectionBits; int trackSelection = -1; // Filters - Filter jetCuts = aod::jet::pt > jetPtMin&& aod::jet::r == nround(jetR.node() * 100.0f); - // Filter collisionFilter = nabs(aod::jcollision::posZ) < vertexZCut; - Filter collisionFilter = - nabs(aod::jcollision::posZ) < vertexZCut && - aod::jcollision::centFT0M >= centralityMin && - aod::jcollision::centFT0M < centralityMax; + // Filter jetCuts = aod::jet::pt > jetPtMin&& aod::jet::r == nround(jetR.node() * 100.0f); + Filter jetCuts = aod::jet::pt > jetPtMin; // Filtered jet tables using FilteredDsDataJets = soa::Filtered; @@ -172,20 +279,20 @@ struct JetDsSpecSubs { registry.add("h_jet_phi_data", "jet #phi;#varphi_{jet};entries", {HistType::kTH1F, {{80, -1., 7.}}}); // Ds QA - registry.add("h_ds_mass_data", ";m_{D_{S}} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{300, 1.7, 2.15}}}); - registry.add("h_ds_pt_data", ";#it{p}_{T,D_{S}} (GeV/#it{c});entries", {HistType::kTH1F, {{250, 0., 100.}}}); + registry.add("h_ds_mass_data", ";m_{D_{S}} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{350, 1.6, 2.3}}}); + registry.add("h_ds_pt_data", ";#it{p}_{T,D_{S}} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 50.}}}); registry.add("h_ds_eta_data", ";#eta_{D_{S}};entries", {HistType::kTH1F, {{100, -1., 1.}}}); registry.add("h_ds_phi_data", ";#varphi_{D_{S}};entries", {HistType::kTH1F, {{80, -1., 7.}}}); // Ds-tagged jet observables - registry.add("h_ds_jet_projection_data", ";z^{D_{S},jet}_{||};entries", {HistType::kTH1F, {{200, 0., 1.2}}}); + registry.add("h_ds_jet_projection_data", ";z^{D_{S},jet}_{||};entries", {HistType::kTH1F, {{200, 0., 1.}}}); registry.add("h_ds_jet_distance_data", ";#DeltaR_{D_{S},jet};entries", {HistType::kTH1F, {{200, 0., 1.}}}); registry.add("h_ds_jet_mass_data", ";m_{jet}^{ch} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{300, 0., 25.}}}); - registry.add("h_ds_jet_lambda11_data", ";#lambda_{1}^{1};entries", {HistType::kTH1F, {{100, 0., 1.}}}); - registry.add("h_ds_jet_lambda21_data", ";#lambda_{2}^{1};entries", {HistType::kTH1F, {{100, 0., 1.}}}); + registry.add("h_ds_jet_lambda11_data", ";#lambda_{1}^{1};entries", {HistType::kTH1F, {{200, 0., 1.}}}); + registry.add("h_ds_jet_lambda21_data", ";#lambda_{2}^{1};entries", {HistType::kTH1F, {{200, 0., 1.}}}); // Main data sparse - registry.add("hSparse_ds_data", ";m_{D_{S}};#it{p}_{T,D_{S}};#it{p}_{T,jet};z^{D_{S},jet}_{||};#DeltaR_{D_{S},jet}", {HistType::kTHnSparseF, {{60, 1.6, 2.3}, {60, 0., 80.}, {60, 0., 100.}, {20, 0., 1.2}, {20, 0., 1.}}}); + registry.add("hSparse_ds_data", ";m_{D_{S}};#it{p}_{T,D_{S}};#it{p}_{T,jet};z^{D_{S},jet}_{||};#DeltaR_{D_{S},jet}", {HistType::kTHnSparseF, {{350, 1.6, 2.3}, {100, 0., 50.}, {100, 0., 100.}, {200, 0., 1.}, {200, 0., 1.}}}); auto hEventCounter = registry.get(HIST("h_event_counter_data")); hEventCounter->GetXaxis()->SetBinLabel(1, "Input collisions"); @@ -196,59 +303,139 @@ struct JetDsSpecSubs { void addMCEfficiencyHistograms() { // General MC counters - registry.add("McEffJet", "N_{jet};", {HistType::kTH1F, {{4, 0., 4.}}}); - registry.add("McEffCol", "N_{collisions};", {HistType::kTH1F, {{4, 0., 4.}}}); - + registry.add("hMCJetCounter", "N_{jet};", {HistType::kTH1F, {{5, 0., 5.}}}); + registry.add("hMCColCounter", "N_{collisions};", {HistType::kTH1F, {{4, 0., 4.}}}); + // Detector-level: all MCD Ds-tagged jets // Detector-level jet QA - registry.add("h_jet_pt_mcd", "detector-level jet pT;#it{p}_{T,jet}^{det} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); + registry.add("h_jet_pt_mcd", "detector-level jet pT;#it{p}_{T,jet}^{det} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 100.}}}); registry.add("h_jet_eta_mcd", "detector-level jet #eta;#eta_{jet}^{det};entries", {HistType::kTH1F, {{100, -1., 1.}}}); registry.add("h_jet_phi_mcd", "detector-level jet #varphi;#varphi_{jet}^{det};entries", {HistType::kTH1F, {{80, -1., 7.}}}); - // Detector-level Ds QA - registry.add("h_ds_pt_mcd", ";#it{p}_{T,D_{S}}^{det} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 100.}}}); + registry.add("h_ds_pt_mcd", ";#it{p}_{T,D_{S}}^{det} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 50.}}}); registry.add("h_ds_eta_mcd", ";#eta_{D_{S}}^{det};entries", {HistType::kTH1F, {{60, -1., 1.}}}); registry.add("h_ds_phi_mcd", ";#varphi_{D_{S}}^{det};entries", {HistType::kTH1F, {{80, -1., 7.}}}); - registry.add("h_ds_mass_mcd", ";m_{D_{S}}^{det} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{200, 1.7, 2.15}}}); - + registry.add("h_ds_mass_mcd", ";m_{D_{S}}^{det} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{350, 1.6, 2.3}}}); // Detector-level sparse histograms - registry.add("hSparse_ds_mcd1", ";m_{D_{S}}^{rec};#it{p}_{T,D_{S}}^{det};#it{p}_{T,jet}^{det};z^{D_{S},jet}_{||,det};Origin(D_{S});Matching status", {HistType::kTHnSparseF, {{60, 1.6, 2.3}, {60, 0., 80.}, {60, 0., 100.}, {20, 0., 1.2}, {2, -0.5, 1.5}, {2, -0.5, 1.5}}}); - registry.add("hSparse_ds_mcd2", ";#it{p}_{T,D_{S}}^{det};#it{p}_{T,jet}^{det};#DeltaR_{D_{S},jet}^{det}", {HistType::kTHnSparseF, {{60, 0., 80.}, {60, 0., 100.}, {20, 0., 1.}}}); - registry.add("hSparse_ds_mcd3", ";#it{p}_{T,jet}^{det};z^{D_{S},jet}_{||,det};#DeltaR_{D_{S},jet}^{det}", {HistType::kTHnSparseF, {{60, 0., 100.}, {20, 0., 1.2}, {20, 0., 1.}}}); - + registry.add( + "hSparse_ds_mcd1", + ";m_{D_{S}}^{rec};#it{p}_{T,D_{S}}^{det};#it{p}_{T,jet}^{det};z^{D_{S},jet}_{||,det};Origin(D_{S});Matching status", + {HistType::kTHnSparseF, + {{350, 1.6, 2.3}, + {100, 0., 50.}, + {100, 0., 100.}, + {200, 0., 1.}, + {3, -0.5, 2.5}, + {2, -0.5, 1.5}}}); + + registry.add( + "hSparse_ds_mcd2", + ";#it{p}_{T,D_{S}}^{det};#it{p}_{T,jet}^{det};#DeltaR_{D_{S},jet}^{det}", + {HistType::kTHnSparseF, + {{100, 0., 50.}, + {100, 0., 100.}, + {200, 0., 1.}}}); + + registry.add( + "hSparse_ds_mcd3", + ";#it{p}_{T,jet}^{det};z^{D_{S},jet}_{||,det};#DeltaR_{D_{S},jet}^{det}", + {HistType::kTHnSparseF, + {{100, 0., 100.}, + {200, 0., 1.}, + {200, 0., 1.}}}); + + // Particle-level: all MCP Ds-tagged jets // Particle-level jet QA - registry.add("h_jet_pt_mcp", "particle-level jet pT;#it{p}_{T,jet}^{part} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); + registry.add("h_jet_pt_mcp", "particle-level jet pT;#it{p}_{T,jet}^{part} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 100.}}}); registry.add("h_jet_eta_mcp", "particle-level jet #eta;#eta_{jet}^{part};entries", {HistType::kTH1F, {{100, -1., 1.}}}); registry.add("h_jet_phi_mcp", "particle-level jet #varphi;#varphi_{jet}^{part};entries", {HistType::kTH1F, {{80, -1., 7.}}}); - // Particle-level Ds QA - registry.add("h_ds_pt_mcp", ";#it{p}_{T,D_{S}}^{part} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 100.}}}); + registry.add("h_ds_pt_mcp", ";#it{p}_{T,D_{S}}^{part} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 50.}}}); registry.add("h_ds_eta_mcp", ";#eta_{D_{S}}^{part};entries", {HistType::kTH1F, {{60, -1., 1.}}}); registry.add("h_ds_phi_mcp", ";#varphi_{D_{S}}^{part};entries", {HistType::kTH1F, {{80, -1., 7.}}}); // Particle-level sparse with origin and matching status - registry.add("hSparse_ds_mcp", ";#it{p}_{T,D_{S}}^{part};#it{p}_{T,jet}^{part};z^{D_{S},jet}_{||,part};#DeltaR_{D_{S},jet}^{part};Origin(D_{S});Matching status", {HistType::kTHnSparseF, {{60, 0., 80.}, {60, 0., 100.}, {20, 0., 1.2}, {20, 0., 1.}, {2, -0.5, 1.5}, {2, -0.5, 1.5}}}); - - auto mcCollisionCounter = registry.get(HIST("McEffCol")); - mcCollisionCounter->GetXaxis()->SetBinLabel(BinMCColCntr::All, "MC collisions"); - mcCollisionCounter->GetXaxis()->SetBinLabel(BinMCColCntr::ZCut, "MC collisions passing z cut"); - mcCollisionCounter->GetXaxis()->SetBinLabel(BinMCColCntr::Matched, "Matched reconstructed collisions"); - mcCollisionCounter->GetXaxis()->SetBinLabel(BinMCColCntr::MatchedSel8ZCut, "Matched collisions passing selections"); - - auto jetCounter = registry.get(HIST("McEffJet")); - jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::DetectorLevelJetInMCCollision, "Detector-level jets"); - jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::ParticleLevelJetInMCCollision, "Particle-level jets"); - jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::DetectorLevelJetWithMatchedCandidate, "Detector jets matched to particle"); - jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::ParticleLevelJetWithMatchedCandidate, "Particle jets matched to detector"); - + registry.add( + "hSparse_ds_mcp", + ";#it{p}_{T,D_{S}}^{part};#it{p}_{T,jet}^{part};z^{D_{S},jet}_{||,part};#DeltaR_{D_{S},jet}^{part};Origin(D_{S});Matching status", + {HistType::kTHnSparseF, + {{100, 0., 50.}, + {100, 0., 100.}, + {200, 0., 1.}, + {200, 0., 1.}, + {3, -0.5, 2.5}, + {2, -0.5, 1.5}}}); + + // Matched detector-level Ds-tagged jets + // Matched detector-level jet QA + registry.add("h_jet_pt_mcd_matched", "matched detector-level jet pT;#it{p}_{T,jet}^{det} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 100.}}}); + registry.add("h_jet_eta_mcd_matched", "matched detector-level jet #eta;#eta_{jet}^{det};entries", {HistType::kTH1F, {{100, -1., 1.}}}); + registry.add("h_jet_phi_mcd_matched", "matched detector-level jet #varphi;#varphi_{jet}^{det};entries", {HistType::kTH1F, {{80, -1., 7.}}}); + // Matched detector-level Ds QA + registry.add("h_ds_pt_mcd_matched", ";#it{p}_{T,D_{S}}^{det} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 50.}}}); + registry.add("h_ds_eta_mcd_matched", ";#eta_{D_{S}}^{det};entries", {HistType::kTH1F, {{60, -1., 1.}}}); + registry.add("h_ds_phi_mcd_matched", ";#varphi_{D_{S}}^{det};entries", {HistType::kTH1F, {{80, -1., 7.}}}); + registry.add("h_ds_mass_mcd_matched", ";m_{D_{S}}^{det} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{350, 1.6, 2.3}}}); + // Matched detector-level sparse histograms + registry.add( + "hSparse_ds_mcd_matched1", + ";m_{D_{S}}^{rec};#it{p}_{T,D_{S}}^{det};#it{p}_{T,jet}^{det};z^{D_{S},jet}_{||,det};Origin(D_{S})", + {HistType::kTHnSparseF, + {{350, 1.6, 2.3}, + {100, 0., 50.}, + {100, 0., 100.}, + {200, 0., 1.}, + {3, -0.5, 2.5}}}); + + registry.add( + "hSparse_ds_mcd_matched2", + ";#it{p}_{T,D_{S}}^{det};#it{p}_{T,jet}^{det};#DeltaR_{D_{S},jet}^{det}", + {HistType::kTHnSparseF, + {{100, 0., 50.}, + {100, 0., 100.}, + {200, 0., 1.}}}); + + registry.add( + "hSparse_ds_mcd_matched3", + ";#it{p}_{T,jet}^{det};z^{D_{S},jet}_{||,det};#DeltaR_{D_{S},jet}^{det}", + {HistType::kTHnSparseF, + {{100, 0., 100.}, + {200, 0., 1.}, + {200, 0., 1.}}}); + + // MCP <-> MCD matched response + registry.add( + "hSparseMatchedJets", + "Matched Ds-tagged jets;#it{p}_{T,jet}^{part};#it{p}_{T,jet}^{det};#it{p}_{T,D_{S}}^{part};#it{p}_{T,D_{S}}^{det};z_{||}^{part};z_{||}^{det};Origin(D_{S});flagMcMatchRec", + {HistType::kTHnSparseF, + {{100, 0., 100.}, + {100, 0., 100.}, + {100, 0., 50.}, + {100, 0., 50.}, + {200, 0., 1.}, + {200, 0., 1.}, + {3, -0.5, 2.5}, + {21, -10.5, 10.5}}}); + + // Counter labels + auto mcCollisionCounter = registry.get(HIST("hMCColCounter")); + mcCollisionCounter->GetXaxis()->SetBinLabel(BinMCColCntr::AllMCCollisions, "All MC coll."); + mcCollisionCounter->GetXaxis()->SetBinLabel(BinMCColCntr::SelectedMCCollisions, "Selected MC coll."); + mcCollisionCounter->GetXaxis()->SetBinLabel(BinMCColCntr::AssociatedRecoCollisions, "MC-associated reco coll."); + mcCollisionCounter->GetXaxis()->SetBinLabel(BinMCColCntr::SelectedAssociatedRecoCollisions, "Selected MC-associated reco coll."); + + auto jetCounter = registry.get(HIST("hMCJetCounter")); + jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::MCPJets, "MCP Ds-jets"); + jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::MCPJetsWithMCDMatch, "MCP jets w/ MCD match"); + jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::MCDJets, "MCD Ds-jets"); + jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::MCDJetsWithMCPMatch, "MCD jets w/ MCP match"); + jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::MatchedPairs, "MCP-MCD pairs"); + + // Matching-status labels auto hSparseMCD = registry.get(HIST("hSparse_ds_mcd1")); - hSparseMCD->GetAxis(4)->SetBinLabel(1, "Prompt"); - hSparseMCD->GetAxis(4)->SetBinLabel(2, "Non-prompt"); hSparseMCD->GetAxis(5)->SetBinLabel(1, "Unmatched"); hSparseMCD->GetAxis(5)->SetBinLabel(2, "Matched"); auto hSparseMCP = registry.get(HIST("hSparse_ds_mcp")); - hSparseMCP->GetAxis(4)->SetBinLabel(1, "Prompt"); - hSparseMCP->GetAxis(4)->SetBinLabel(2, "Non-prompt"); hSparseMCP->GetAxis(5)->SetBinLabel(1, "Unmatched"); hSparseMCP->GetAxis(5)->SetBinLabel(2, "Matched"); } @@ -258,17 +445,17 @@ struct JetDsSpecSubs { registry.add("h_event_counter_mcp_on_the_fly", ";Selection step;MC collisions", {HistType::kTH1F, {{2, 0.5, 2.5}}}); // Particle-level jet QA - registry.add("h_jet_pt_mcp_on_the_fly", ";#it{p}_{T,jet}^{part} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 200.}}}); + registry.add("h_jet_pt_mcp_on_the_fly", ";#it{p}_{T,jet}^{part} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 100.}}}); registry.add("h_jet_eta_mcp_on_the_fly", ";#eta_{jet}^{part};entries", {HistType::kTH1F, {{100, -1., 1.}}}); registry.add("h_jet_phi_mcp_on_the_fly", ";#varphi_{jet}^{part};entries", {HistType::kTH1F, {{80, -1., 7.}}}); // Particle-level Ds QA - registry.add("h_ds_pt_mcp_on_the_fly", ";#it{p}_{T,D_{S}}^{part} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 100.}}}); + registry.add("h_ds_pt_mcp_on_the_fly", ";#it{p}_{T,D_{S}}^{part} (GeV/#it{c});entries", {HistType::kTH1F, {{100, 0., 50.}}}); registry.add("h_ds_eta_mcp_on_the_fly", ";#eta_{D_{S}}^{part};entries", {HistType::kTH1F, {{60, -1., 1.}}}); registry.add("h_ds_phi_mcp_on_the_fly", ";#varphi_{D_{S}}^{part};entries", {HistType::kTH1F, {{80, -1., 7.}}}); // Theoretical particle-level sparse - registry.add("hSparse_ds_mcp_on_the_fly", ";#it{p}_{T,D_{S}}^{part};#it{p}_{T,jet}^{part};z^{D_{S},jet}_{||,part};#DeltaR_{D_{S},jet}^{part};Origin(D_{S})", {HistType::kTHnSparseF, {{60, 0., 80.}, {60, 0., 100.}, {20, 0., 1.2}, {20, 0., 1.}, {2, -0.5, 1.5}}}); + registry.add("hSparse_ds_mcp_on_the_fly", ";#it{p}_{T,D_{S}}^{part};#it{p}_{T,jet}^{part};z^{D_{S},jet}_{||,part};#DeltaR_{D_{S},jet}^{part};Origin(D_{S})", {HistType::kTHnSparseF, {{100, 0., 50.}, {100, 0., 100.}, {200, 0., 1.}, {200, 0., 1.}, {2, -0.5, 1.5}}}); auto hCounter = registry.get(HIST("h_event_counter_mcp_on_the_fly")); hCounter->GetXaxis()->SetBinLabel(1, "Generated collisions"); @@ -474,12 +661,12 @@ struct JetDsSpecSubs { const float mjet = computeJetMass(jetTracks); - TVector3 jetVector(jet.px(), jet.py(), jet.pz()); + const TVector3 jetVector(jet.px(), jet.py(), jet.pz()); // Loop over Ds candidates for (const auto& dsCandidate : jet.template candidates_as()) { - TVector3 dsVector(dsCandidate.px(), dsCandidate.py(), dsCandidate.pz()); + const TVector3 dsVector(dsCandidate.px(), dsCandidate.py(), dsCandidate.pz()); // Axis distance Delta_R const float deltaR = jetutilities::deltaR(jet, dsCandidate); @@ -543,185 +730,327 @@ struct JetDsSpecSubs { } PROCESS_SWITCH(JetDsSpecSubs, processDataChargedSubstructureEWS, "Data charged jets EWS", false); - //===================================================================================== - // MC function - //===================================================================================== - template - void analyseMonteCarloEfficiency(MCDJetsPerCollisionPreslice const& jetmcdpreslice, - MCPJetsPerCollisionPreslice const& jetmcppreslice, - aod::JetMcCollisions const& mccollisions, - aod::JetCollisionsMCD const& collisions, - MCDJetTable const& mcdjets, - MCPJetTable const& mcpjets, - DsCandidatesMCD const&, - DsCandidatesMCP const&) + //================== + // MC function + //================== + + template + void analyseMonteCarloEfficiency( + TMCPJetsPerMCCollisionPreslice const& MCPJetsPerMCCollisionPreslice, + aod::JetMcCollisions const& mccollisions, + aod::JetCollisionsMCD const& collisions, + TJetsMCD const& mcdjets, + TJetsMCP const& mcpjets, + TCandidatesMCD const&, + TCandidatesMCP const&, + aod::JetTracks const&, + aod::JetParticles const&) { + // MC collisions and particle-level Ds-tagged jets for (const auto& mccollision : mccollisions) { - // Count all generated MC collisions - registry.fill(HIST("McEffCol"), getValFromBin(BinMCColCntr::All)); - - // Apply standard event selection and vertex cut - if (!jetderiveddatautilities::selectCollision(mccollision, eventSelectionBits)) { - continue; - } + // All MC collisions + registry.fill(HIST("hMCColCounter"), getValFromBin(BinMCColCntr::AllMCCollisions)); - if (std::abs(mccollision.posZ()) > vertexZCut) { + // MC collision selection + if (!jetderiveddatautilities::selectCollision(mccollision, eventSelectionBits) || + !(std::abs(mccollision.posZ()) < vertexZCut)) { continue; } - // MC collisions passing z_cut selection - registry.fill(HIST("McEffCol"), getValFromBin(BinMCColCntr::ZCut)); + // Selected MC collisions + registry.fill(HIST("hMCColCounter"), getValFromBin(BinMCColCntr::SelectedMCCollisions)); - // Reconstructed collisions associated to this mccollision - const auto collisionsPerMCCollision = collisions.sliceBy(collisionsPerMCCollisionPreslice, mccollision.globalIndex()); - for (const auto& collision : collisionsPerMCCollision) { + // Particle-level jets belonging to the current MC collision + const auto mcpJetsPerMCCollision = mcpjets.sliceBy(MCPJetsPerMCCollisionPreslice, mccollision.globalIndex()); - // Successfully matched reconstructed collision - registry.fill(HIST("McEffCol"), getValFromBin(BinMCColCntr::Matched)); + // Particle-level Ds-tagged jets + for (const auto& mcpjet : mcpJetsPerMCCollision) { - // Apply standard event selection and vertex cut - if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || - !(std::abs(collision.posZ()) < vertexZCut)) { - continue; - } - // Matched collision passing analysis selections - registry.fill(HIST("McEffCol"), getValFromBin(BinMCColCntr::MatchedSel8ZCut)); - - // Detector-level Ds-tagged jets associated with the current reconstructed collision - const auto dsmcdJetsPerCollision = mcdjets.sliceBy(jetmcdpreslice, collision.globalIndex()); - for (const auto& mcdjet : dsmcdJetsPerCollision) { - // Detector-level jet found in a matched collision - registry.fill(HIST("McEffJet"), getValFromBin(BinMCJetCntr::DetectorLevelJetInMCCollision)); - - // Leading Ds candidate associated to the jet - auto mcdDscand = mcdjet.template candidates_first_as(); - - // Check if it's prompt - int origin = (mcdDscand.originMcRec() != RecoDecay::OriginType::Prompt) ? 1 : 0; - - // Matching status: 1 if the detector-level jet has a particle-level partner, 0 otherwise - int isMatchedMCD = mcdjet.has_matchedJetCand() ? 1 : 0; - - // Check whether a matched particle-level jet exists - if (mcdjet.has_matchedJetCand()) { - registry.fill(HIST("McEffJet"), getValFromBin(BinMCJetCntr::DetectorLevelJetWithMatchedCandidate)); - } - - // Compute jet-substructure observables - TVector3 mcd_jetvector(mcdjet.px(), mcdjet.py(), mcdjet.pz()); - TVector3 mcd_candvector(mcdDscand.px(), mcdDscand.py(), mcdDscand.pz()); - - float mcd_zParallel = (mcd_jetvector * mcd_candvector) / (mcd_jetvector * mcd_jetvector); - // Axis distance Delta_R - float mcd_deltaR = jetutilities::deltaR(mcdjet, mcdDscand); - - // Detector-level Jet Histograms - registry.fill(HIST("h_jet_pt_mcd"), mcdjet.pt()); - registry.fill(HIST("h_jet_eta_mcd"), mcdjet.eta()); - registry.fill(HIST("h_jet_phi_mcd"), mcdjet.phi()); - - // Detector-level Ds Histgrams - registry.fill(HIST("h_ds_pt_mcd"), mcdDscand.pt()); - registry.fill(HIST("h_ds_mass_mcd"), mcdDscand.m()); - registry.fill(HIST("h_ds_eta_mcd"), mcdDscand.eta()); - registry.fill(HIST("h_ds_phi_mcd"), mcdDscand.phi()); - - // MCD THnSparse1: invariant mass, p{T,Ds}, pT, z, and origin (prompt/non-prompt) - registry.fill(HIST("hSparse_ds_mcd1"), - mcdDscand.m(), - mcdDscand.pt(), - mcdjet.pt(), - mcd_zParallel, - origin, - isMatchedMCD); - // MCD THnSparse2: invariant p{T,Ds}, pT and DeltaR - registry.fill(HIST("hSparse_ds_mcd2"), - mcdDscand.pt(), - mcdjet.pt(), - mcd_deltaR); - // MCD THnSparse3: invariant pT z and DeltaR - registry.fill(HIST("hSparse_ds_mcd3"), - mcdjet.pt(), - mcd_zParallel, - mcd_deltaR); - } - } - // Particle level - const auto dsmcpJetsPerMCCollision = mcpjets.sliceBy(jetmcppreslice, mccollision.globalIndex()); - for (const auto& mcpjet : dsmcpJetsPerMCCollision) { + registry.fill(HIST("hMCJetCounter"), getValFromBin(BinMCJetCntr::MCPJets)); - registry.fill(HIST("McEffJet"), getValFromBin(BinMCJetCntr::ParticleLevelJetInMCCollision)); + // Obtain the Ds particle associated with the particle-level jet + auto mcpcand = mcpjet.template candidates_first_as(); - // obtain leading HF particle in jet - auto mcpDscand = mcpjet.template candidates_first_as(); + // Particle-level Ds-jet observables + TVector3 jetVecMCP; + jetVecMCP.SetPtEtaPhi(mcpjet.pt(), mcpjet.eta(), mcpjet.phi()); - // Check if it's prompt 0 prompt, 1 non-prompt - int originMCP = (mcpDscand.originMcGen() != RecoDecay::OriginType::Prompt) ? 1 : 0; + TVector3 dsVecMCP; + dsVecMCP.SetPtEtaPhi(mcpcand.pt(), mcpcand.eta(), mcpcand.phi()); - // Matching status: 1 if the particle-level jet has a detector-level partner, 0 otherwise - int isMatched = mcpjet.has_matchedJetCand() ? 1 : 0; + const float zParallelMCP = dsVecMCP.Dot(jetVecMCP) / jetVecMCP.Mag2(); + const float deltaRMCP = jetutilities::deltaR(mcpjet, mcpcand); - if (mcpjet.has_matchedJetCand()) { - registry.fill(HIST("McEffJet"), getValFromBin(BinMCJetCntr::ParticleLevelJetWithMatchedCandidate)); - } - - TVector3 mcp_jetvector(mcpjet.px(), mcpjet.py(), mcpjet.pz()); - TVector3 mcp_candvector(mcpDscand.px(), mcpDscand.py(), mcpDscand.pz()); + const int originMCP = static_cast(mcpcand.originMcGen()); + const int flagMcMatchGen = static_cast(mcpcand.flagMcMatchGen()); + const bool isMatchedMCP = mcpjet.has_matchedJetCand(); - float mcp_zParallel = (mcp_jetvector * mcp_candvector) / (mcp_jetvector * mcp_jetvector); - // Axis distance Delta_R - float mcp_deltaR = jetutilities::deltaR(mcpjet, mcpDscand); - - // Particle-level Jet Histograms + // Particle-level jet QA registry.fill(HIST("h_jet_pt_mcp"), mcpjet.pt()); registry.fill(HIST("h_jet_eta_mcp"), mcpjet.eta()); registry.fill(HIST("h_jet_phi_mcp"), mcpjet.phi()); - // Particle-level Ds Histgrams - registry.fill(HIST("h_ds_pt_mcp"), mcpDscand.pt()); - registry.fill(HIST("h_ds_eta_mcp"), mcpDscand.eta()); - registry.fill(HIST("h_ds_phi_mcp"), mcpDscand.phi()); - - // Main THnSparse: invariant mass, pT, z, DeltaR , and origin (prompt/non-prompt) - registry.fill(HIST("hSparse_ds_mcp"), - mcpDscand.pt(), - mcpjet.pt(), - mcp_zParallel, - mcp_deltaR, - originMCP, - isMatched); + // Particle-level Ds QA + registry.fill(HIST("h_ds_pt_mcp"), mcpcand.pt()); + registry.fill(HIST("h_ds_eta_mcp"), mcpcand.eta()); + registry.fill(HIST("h_ds_phi_mcp"), mcpcand.phi()); + + // Particle-level sparse + registry.fill( + HIST("hSparse_ds_mcp"), + mcpcand.pt(), + mcpjet.pt(), + zParallelMCP, + deltaRMCP, + originMCP, + static_cast(isMatchedMCP)); + + // Store all particle-level Ds-tagged jets + outputMCPJets( + mcpjet.pt(), + mcpjet.eta(), + mcpjet.phi(), + mcpjet.template tracks_as().size() + + mcpjet.template candidates_as().size(), + mcpcand.pt(), + mcpcand.eta(), + mcpcand.phi(), + zParallelMCP, + deltaRMCP, + originMCP, + flagMcMatchGen, + isMatchedMCP); + + // MCP -> MCD matched pairs + if (isMatchedMCP) { + + registry.fill(HIST("hMCJetCounter"), getValFromBin(BinMCJetCntr::MCPJetsWithMCDMatch)); + + for (const auto& mcdjet : mcpjet.template matchedJetCand_as()) { + + const auto& collision = collisions.iteratorAt(mcdjet.collisionId()); + + // Detector-level collision selection + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || + !(std::abs(collision.posZ()) < vertexZCut)) { + continue; + } + + // Obtain the reconstructed Ds candidate + auto mcdcand = mcdjet.template candidates_first_as(); + + // Detector-level Ds-jet observables + TVector3 jetVecMCD; + jetVecMCD.SetPtEtaPhi(mcdjet.pt(), mcdjet.eta(), mcdjet.phi()); + + TVector3 dsVecMCD; + dsVecMCD.SetPtEtaPhi(mcdcand.pt(), mcdcand.eta(), mcdcand.phi()); + + const float zParallelMCD = dsVecMCD.Dot(jetVecMCD) / jetVecMCD.Mag2(); + const float deltaRMCD = jetutilities::deltaR(mcdjet, mcdcand); + + const int originMCD = static_cast(mcdcand.originMcRec()); + const int flagMcMatchRec = static_cast(mcdcand.flagMcMatchRec()); + + // Matched detector-level jet QA + registry.fill(HIST("h_jet_pt_mcd_matched"), mcdjet.pt()); + registry.fill(HIST("h_jet_eta_mcd_matched"), mcdjet.eta()); + registry.fill(HIST("h_jet_phi_mcd_matched"), mcdjet.phi()); + + // Matched detector-level Ds QA + registry.fill(HIST("h_ds_pt_mcd_matched"), mcdcand.pt()); + registry.fill(HIST("h_ds_eta_mcd_matched"), mcdcand.eta()); + registry.fill(HIST("h_ds_phi_mcd_matched"), mcdcand.phi()); + registry.fill(HIST("h_ds_mass_mcd_matched"), mcdcand.m()); + + // Matched detector-level sparse: mass, pT Ds, pT jet, z_parallel, origin + registry.fill( + HIST("hSparse_ds_mcd_matched1"), + mcdcand.m(), + mcdcand.pt(), + mcdjet.pt(), + zParallelMCD, + originMCD); + + // Matched detector-level sparse: pT Ds, pT jet, DeltaR + registry.fill( + HIST("hSparse_ds_mcd_matched2"), + mcdcand.pt(), + mcdjet.pt(), + deltaRMCD); + + // Matched detector-level sparse: pT jet, z_parallel, DeltaR + registry.fill( + HIST("hSparse_ds_mcd_matched3"), + mcdjet.pt(), + zParallelMCD, + deltaRMCD); + + // MCP <-> MCD response + registry.fill( + HIST("hSparseMatchedJets"), + mcpjet.pt(), + mcdjet.pt(), + mcpcand.pt(), + mcdcand.pt(), + zParallelMCP, + zParallelMCD, + originMCP, + flagMcMatchRec); + + // One accepted MCP-MCD pair + registry.fill(HIST("hMCJetCounter"), getValFromBin(BinMCJetCntr::MatchedPairs)); + + // Store matched MCP <-> MCD pair + outputMatchedJets( + // Particle level + mcpjet.pt(), + mcpjet.eta(), + mcpjet.phi(), + mcpjet.template tracks_as().size() + + mcpjet.template candidates_as().size(), + mcpcand.pt(), + mcpcand.eta(), + mcpcand.phi(), + zParallelMCP, + deltaRMCP, + + // Detector level + mcdjet.pt(), + mcdjet.eta(), + mcdjet.phi(), + mcdjet.template tracks_as().size() + + mcdjet.template candidates_as().size(), + mcdcand.pt(), + mcdcand.eta(), + mcdcand.phi(), + mcdcand.m(), + zParallelMCD, + deltaRMCD, + + // MC truth + originMCP); + + } // end of matched MCD jets + } // end of isMatchedMCP + } // end of MCP jets + } // end of MC collisions + + // Detector-level Ds-tagged jets + // This loop is outside the MC-collision loop so that each + // detector-level jet is processed only once. + for (const auto& mcdjet : mcdjets) { + + const auto& collision = collisions.iteratorAt(mcdjet.collisionId()); + + // Detector-level collision selection + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || + !(std::abs(collision.posZ()) < vertexZCut)) { + continue; } - } - } - //===================================================================================== - // MC process - //===================================================================================== + registry.fill(HIST("hMCJetCounter"), getValFromBin(BinMCJetCntr::MCDJets)); + + // Obtain the reconstructed Ds candidate + auto mcdcand = mcdjet.template candidates_first_as(); + + // Detector-level Ds-jet observables + TVector3 jetVecMCD; + jetVecMCD.SetPtEtaPhi(mcdjet.pt(), mcdjet.eta(), mcdjet.phi()); + + TVector3 dsVecMCD; + dsVecMCD.SetPtEtaPhi(mcdcand.pt(), mcdcand.eta(), mcdcand.phi()); + + const float zParallelMCD = dsVecMCD.Dot(jetVecMCD) / jetVecMCD.Mag2(); + const float deltaRMCD = jetutilities::deltaR(mcdjet, mcdcand); + const int originMCD = static_cast(mcdcand.originMcRec()); + const int flagMcMatchRec = static_cast(mcdcand.flagMcMatchRec()); + const bool isMatchedMCD = mcdjet.has_matchedJetCand(); + + if (isMatchedMCD) { + registry.fill(HIST("hMCJetCounter"), getValFromBin(BinMCJetCntr::MCDJetsWithMCPMatch)); + } + + // Detector-level jet QA + registry.fill(HIST("h_jet_pt_mcd"), mcdjet.pt()); + registry.fill(HIST("h_jet_eta_mcd"), mcdjet.eta()); + registry.fill(HIST("h_jet_phi_mcd"), mcdjet.phi()); + + // Detector-level Ds QA + registry.fill(HIST("h_ds_pt_mcd"), mcdcand.pt()); + registry.fill(HIST("h_ds_eta_mcd"), mcdcand.eta()); + registry.fill(HIST("h_ds_phi_mcd"), mcdcand.phi()); + registry.fill(HIST("h_ds_mass_mcd"), mcdcand.m()); + + // Detector-level sparse: mass, pT Ds, pT jet, z_parallel, origin, matching status + registry.fill( + HIST("hSparse_ds_mcd1"), + mcdcand.m(), + mcdcand.pt(), + mcdjet.pt(), + zParallelMCD, + originMCD, + static_cast(isMatchedMCD)); + + // Detector-level sparse: pT Ds, pT jet, DeltaR + registry.fill( + HIST("hSparse_ds_mcd2"), + mcdcand.pt(), + mcdjet.pt(), + deltaRMCD); + + // Detector-level sparse: pT jet, z_parallel, DeltaR + registry.fill( + HIST("hSparse_ds_mcd3"), + mcdjet.pt(), + zParallelMCD, + deltaRMCD); + + // Store all detector-level Ds-tagged jets + outputMCDJets( + mcdjet.pt(), + mcdjet.eta(), + mcdjet.phi(), + mcdjet.template tracks_as().size() + + mcdjet.template candidates_as().size(), + mcdcand.pt(), + mcdcand.eta(), + mcdcand.phi(), + mcdcand.m(), + zParallelMCD, + deltaRMCD, + originMCD, + flagMcMatchRec, + isMatchedMCD); + + } // end of MCD jets + } // end of analyseMonteCarloEfficiency - // MC efficiency analysis using standard Ds-tagged jets (pp) void processMonteCarloEfficiencyDs(aod::JetMcCollisions const& mccollisions, aod::JetCollisionsMCD const& collisions, - FilteredDsMCDJets const& mcdjets, - FilteredDsMCPJets const& mcpjets, + DsMCDJets const& mcdjets, + DsMCPJets const& mcpjets, DsCandidatesMCD const& mcdDscand, - DsCandidatesMCP const& mcpDscand) + DsCandidatesMCP const& mcpDscand, + aod::JetTracks const& tracks, + aod::JetParticles const& particles) { - analyseMonteCarloEfficiency, - Preslice, - FilteredDsMCDJets, - FilteredDsMCPJets, + analyseMonteCarloEfficiency, + DsMCDJets, + DsMCPJets, DsCandidatesMCD, - DsCandidatesMCP>(dsMCDJetsPerEXPCollisionPreslice, - dsMCPJetsPerMCCollisionPreslice, - mccollisions, - collisions, - mcdjets, - mcpjets, - mcdDscand, - mcpDscand); + DsCandidatesMCP>( + dsMCPJetsPerMCCollisionPreslice, + mccollisions, + collisions, + mcdjets, + mcpjets, + mcdDscand, + mcpDscand, + tracks, + particles); } PROCESS_SWITCH(JetDsSpecSubs, processMonteCarloEfficiencyDs, "Non-matched and matched MC Ds and jets", false); @@ -733,11 +1062,11 @@ struct JetDsSpecSubs { FilteredDsMCPJetsOnTheFly const& mcpjets, DsCandidatesMCP const&) { - // Count all generated MC collisions before applying event selections + // Count all generated MC collisions before the vertex selection registry.fill(HIST("h_event_counter_mcp_on_the_fly"), 1); // Apply the generated-vertex selection - if (std::abs(mccollision.posZ()) > vertexZCut) { + if (std::abs(mccollision.posZ()) >= vertexZCut) { return; } @@ -748,34 +1077,41 @@ struct JetDsSpecSubs { for (const auto& mcpjet : mcpjets) { // Retrieve the leading generated Ds candidate associated with the jet - auto mcpDscand = mcpjet.template candidates_first_as(); + const auto mcpCandidate = mcpjet.template candidates_first_as(); // Classify the generated Ds origin: 0 = prompt, 1 = non-prompt - const int originMCP = (mcpDscand.originMcGen() == RecoDecay::OriginType::Prompt) ? 0 : 1; + const auto origin = mcpCandidate.originMcGen(); + + // Keep only prompt and non-prompt generated Ds candidates. + if (origin != RecoDecay::OriginType::Prompt && origin != RecoDecay::OriginType::NonPrompt) { + continue; + } + // Encode prompt and non-prompt origins as 0 and 1, respectively. + const int originMCP = origin == RecoDecay::OriginType::Prompt ? 0 : 1; // Build the particle-level jet and Ds momentum vectors - TVector3 jetVector(mcpjet.px(), mcpjet.py(), mcpjet.pz()); - TVector3 dsVector(mcpDscand.px(), mcpDscand.py(), mcpDscand.pz()); + const TVector3 jetVector(mcpjet.px(), mcpjet.py(), mcpjet.pz()); + const TVector3 candidateVector(mcpCandidate.px(), mcpCandidate.py(), mcpCandidate.pz()); // Compute the longitudinal momentum fraction of the Ds along the jet axis - const float zParallel = (jetVector * dsVector) / (jetVector * jetVector); + const float zParallel = jetVector.Dot(candidateVector) / jetVector.Mag2(); // Compute the angular distance between the Ds candidate and the jet axis - const float deltaR = jetutilities::deltaR(mcpjet, mcpDscand); + const float deltaR = jetutilities::deltaR(mcpjet, mcpCandidate); - // Fill particle-level jet QA histograms + // Fill particle-level jet distributions registry.fill(HIST("h_jet_pt_mcp_on_the_fly"), mcpjet.pt()); registry.fill(HIST("h_jet_eta_mcp_on_the_fly"), mcpjet.eta()); registry.fill(HIST("h_jet_phi_mcp_on_the_fly"), mcpjet.phi()); - // Fill particle-level Ds QA histograms - registry.fill(HIST("h_ds_pt_mcp_on_the_fly"), mcpDscand.pt()); - registry.fill(HIST("h_ds_eta_mcp_on_the_fly"), mcpDscand.eta()); - registry.fill(HIST("h_ds_phi_mcp_on_the_fly"), mcpDscand.phi()); + // Fill particle-level Ds-candidate distributions + registry.fill(HIST("h_ds_pt_mcp_on_the_fly"), mcpCandidate.pt()); + registry.fill(HIST("h_ds_eta_mcp_on_the_fly"), mcpCandidate.eta()); + registry.fill(HIST("h_ds_phi_mcp_on_the_fly"), mcpCandidate.phi()); // Store the particle-level Ds-tagged jet observables and Ds origin registry.fill(HIST("hSparse_ds_mcp_on_the_fly"), - mcpDscand.pt(), + mcpCandidate.pt(), mcpjet.pt(), zParallel, deltaR, diff --git a/PWGJE/Tasks/jetFinderQA.cxx b/PWGJE/Tasks/jetFinderQA.cxx index 0a8cc908ad6..4500148ee63 100644 --- a/PWGJE/Tasks/jetFinderQA.cxx +++ b/PWGJE/Tasks/jetFinderQA.cxx @@ -47,7 +47,6 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; - struct JetFinderQATask { HistogramRegistry registry; @@ -425,6 +424,7 @@ struct JetFinderQATask { registry.add("h_collisions_njets", "N_{jets};", {HistType::kTH1F, {{10000, 0.0, 10000.0}}}, doSumw2); registry.add("h2_centrality_ntracks", "; centrality; N_{tracks};", {HistType::kTH2F, {{1100, 0., 110.0}, {10000, 0.0, 10000.0}}}); + registry.add("h2_runnumber_ntracks", "; run number; N_{tracks}", {HistType::kTH2F, {{1000, 0., 1000.0}, {10000, 0.0, 10000.0}}}); registry.add("h2_centrality_njets", "; centrality; N_{jets};", {HistType::kTH2F, {{1100, 0., 110.0}, {10000, 0.0, 10000.0}}}); registry.add("h2_ntracks_rho", "; N_{tracks}; #it{rho} (GeV/area);", {HistType::kTH2F, {{10000, 0.0, 10000.0}, {400, 0.0, 400.0}}}); registry.add("h2_centrality_rho", "; centrality; #it{rho} (GeV/area);", {HistType::kTH2F, {{1100, 0., 110.}, {400, 0., 400.0}}}); @@ -435,6 +435,8 @@ struct JetFinderQATask { registry.add("h2_track_pt_high_track_sigmapt", "#sigma(#it{p}_{T})/#it{p}_{T}; #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{90, 10., 100.}, {100000, 0.0, 10.0}}}); registry.add("h2_track_pt_track_sigma1overpt", "#sigma(1/#it{p}_{T}); #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{100, 0., 10.}, {10000, 0.0, 1.0}}}); registry.add("h2_track_pt_high_track_sigma1overpt", "#sigma(1/#it{p}_{T}); #it{p}_{T,track} (GeV/#it{c})", {HistType::kTH2F, {{90, 10., 100.}, {10000, 0.0, 1.0}}}); + registry.add("h_ntracksall", "N_{tracks};", {HistType::kTH1I, {nTracksAxis}}); + registry.add("h_ntrackssel", "N_{tracks};", {HistType::kTH1I, {nTracksAxis}}); registry.add("h_mccollision_processid", "mccollision process id;mccollision process id;entries", {HistType::kTH1D, {{200, 0.0, 200.0}}}); @@ -449,6 +451,7 @@ struct JetFinderQATask { registry.add("h_particle_primary_hepmcstatuscode", "primary particle hep mc status code;primary particle hep mc status code;entries", {HistType::kTH1D, {{210, 0.0, 210.0}}}); registry.add("h_particle_primary_process", "primary particle process;primary particle process;entries", {HistType::kTH1D, {{50, 0.0, 50.0}}}); registry.add("h_particle_primary_producedbygenerator", "primary particle producedByGenerator status;primary particle producedByGenerator status;entries", {HistType::kTH1D, {{2, 0.0, 2}}}); + registry.add("h_nparticles_primary", "N(primary particles);", {HistType::kTH1I, {nTracksAxis}}); registry.add("h_jet_pt", "jet pT;#it{p}_{T,jet} (GeV/#it{c}); counts", {HistType::kTH1F, {jetPtAxis}}, doSumw2); registry.add("h_jet_eta", "jet eta;#eta; counts", {HistType::kTH1F, {jetEtaAxis}}, doSumw2); @@ -470,6 +473,7 @@ struct JetFinderQATask { ((checkCentFT0M ? aod::jcollision::centFT0M : aod::jcollision::centFT0C) < centralityMax)); PresliceUnsorted> CollisionsPerMCPCollision = aod::jmccollisionlb::mcCollisionId; PresliceUnsorted> McCollisionsPerMCPCollision = aod::jmccollision::mcCollisionId; + Preslice ParticlesPerMCPCollision = aod::jmcparticle::mcCollisionId; template bool isAcceptedJet(U const& jet) @@ -929,7 +933,7 @@ struct JetFinderQATask { registry.fill(HIST("h_collisions_weighted"), 2.5, eventWeight); } - if (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < collision.trackOccupancyInTimeRange()) { + if (static_cast(collision).trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMin || trackOccupancyInTimeRangeMax < static_cast(collision).trackOccupancyInTimeRange()) { return false; } if (fillHistograms) { @@ -978,7 +982,7 @@ struct JetFinderQATask { if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } - for (auto jet : jets) { + for (const auto& jet : jets) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } @@ -1000,7 +1004,7 @@ struct JetFinderQATask { if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } - for (auto jet : jets) { + for (const auto& jet : jets) { if (!jetfindingutilities::isInEtaAcceptance(jet, jetEtaMin, jetEtaMax, trackEtaMin, trackEtaMax)) { continue; } @@ -1525,6 +1529,7 @@ struct JetFinderQATask { void processQcMultCutCheck(soa::Filtered>::iterator const& collision, soa::Join const&, soa::Join const&, + aod::JBCs const&, soa::Join const& mcdjets, soa::Filtered> const& tracks, soa::Filtered const& mcparticles) @@ -1551,7 +1556,6 @@ struct JetFinderQATask { if (collision.has_mcCollision()) { // the collision is not fake and has one associated mc coll; .mccollision() can be called auto jetMcCollision = collision.mcCollision_as>(); auto aodMcCollision = jetMcCollision.mcCollision_as>(); - registry.fill(HIST("h2_mccollision_pthardfromweight_pthardfromhepmcxsection"), simPtRef / (std::pow(collision.weight(), 1.0 / pTHatExponent)), jetMcCollision.ptHard()); registry.fill(HIST("h2_mccollision_pthardfromweight_pthardfromhepmcxsection_weighted"), simPtRef / (std::pow(collision.weight(), 1.0 / pTHatExponent)), jetMcCollision.ptHard(), eventWeight); registry.fill(HIST("h_mccollision_processid"), aodMcCollision.processId(), eventWeight); @@ -1561,36 +1565,47 @@ struct JetFinderQATask { registry.fill(HIST("h_collisions_ntracks"), tracks.size(), eventWeight); registry.fill(HIST("h2_centrality_ntracks"), collision.centFT0M(), tracks.size(), eventWeight); + registry.fill(HIST("h2_runnumber_ntracks"), (collision.bc_as().runNumber()) % 1000, tracks.size(), eventWeight); registry.fill(HIST("h_collisions_njets"), mcdjets.size(), eventWeight); registry.fill(HIST("h2_centrality_njets"), collision.centFT0M(), mcdjets.size(), eventWeight); registry.fill(HIST("h2_ntracks_rho"), tracks.size(), collision.rho(), eventWeight); registry.fill(HIST("h2_centrality_rho"), collision.centFT0M(), collision.rho(), eventWeight); + int nTracksAll = tracks.size(); + int nTracksSel = 0; for (auto const& track : tracks) { - if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { - continue; + if (jetderiveddatautilities::selectTrack(track, trackSelection)) { + nTracksSel += 1; + registry.fill(HIST("h2_centrality_track_pt"), collision.centFT0M(), track.pt(), eventWeight); + registry.fill(HIST("h2_centrality_track_eta"), collision.centFT0M(), track.eta(), eventWeight); + registry.fill(HIST("h2_track_pt_track_sigma1overpt"), track.pt(), track.sigma1Pt(), eventWeight); + registry.fill(HIST("h2_track_pt_track_sigmapt"), track.pt(), track.sigma1Pt() * track.pt(), eventWeight); + registry.fill(HIST("h2_track_pt_high_track_sigma1overpt"), track.pt(), track.sigma1Pt(), eventWeight); + registry.fill(HIST("h2_track_pt_high_track_sigmapt"), track.pt(), track.sigma1Pt() * track.pt(), eventWeight); } - registry.fill(HIST("h2_centrality_track_pt"), collision.centFT0M(), track.pt(), eventWeight); - registry.fill(HIST("h2_centrality_track_eta"), collision.centFT0M(), track.eta(), eventWeight); - registry.fill(HIST("h2_track_pt_track_sigma1overpt"), track.pt(), track.sigma1Pt(), eventWeight); - registry.fill(HIST("h2_track_pt_track_sigmapt"), track.pt(), track.sigma1Pt() * track.pt(), eventWeight); - registry.fill(HIST("h2_track_pt_high_track_sigma1overpt"), track.pt(), track.sigma1Pt(), eventWeight); - registry.fill(HIST("h2_track_pt_high_track_sigmapt"), track.pt(), track.sigma1Pt() * track.pt(), eventWeight); - } - - for (auto const& mcparticle : mcparticles) { - registry.fill(HIST("h_particle_pdgcode"), mcparticle.pdgCode(), eventWeight); - registry.fill(HIST("h_particle_genstatuscode"), mcparticle.getGenStatusCode(), eventWeight); - registry.fill(HIST("h_particle_hepmcstatuscode"), mcparticle.getHepMCStatusCode(), eventWeight); - registry.fill(HIST("h_particle_process"), mcparticle.getProcess(), eventWeight); - registry.fill(HIST("h_particle_producedbygenerator"), mcparticle.producedByGenerator(), eventWeight); - if (mcparticle.isPhysicalPrimary()) { - registry.fill(HIST("h_particle_primary_pdgcode"), mcparticle.pdgCode(), eventWeight); - registry.fill(HIST("h_particle_primary_genstatuscode"), mcparticle.getGenStatusCode(), eventWeight); - registry.fill(HIST("h_particle_primary_hepmcstatuscode"), mcparticle.getHepMCStatusCode(), eventWeight); - registry.fill(HIST("h_particle_primary_process"), mcparticle.getProcess(), eventWeight); - registry.fill(HIST("h_particle_primary_producedbygenerator"), mcparticle.producedByGenerator(), eventWeight); + } + registry.fill(HIST("h_ntracksall"), nTracksAll); + registry.fill(HIST("h_ntrackssel"), nTracksSel); + + int nParticlesPrimary = 0; + if (collision.has_mcCollision()) { + auto particleMcCollision = mcparticles.sliceBy(ParticlesPerMCPCollision, collision.mcCollisionId()); + for (auto const& mcparticle : particleMcCollision) { + registry.fill(HIST("h_particle_pdgcode"), mcparticle.pdgCode(), eventWeight); + registry.fill(HIST("h_particle_genstatuscode"), mcparticle.getGenStatusCode(), eventWeight); + registry.fill(HIST("h_particle_hepmcstatuscode"), mcparticle.getHepMCStatusCode(), eventWeight); + registry.fill(HIST("h_particle_process"), mcparticle.getProcess(), eventWeight); + registry.fill(HIST("h_particle_producedbygenerator"), mcparticle.producedByGenerator(), eventWeight); + if (mcparticle.isPhysicalPrimary()) { + nParticlesPrimary += 1; + registry.fill(HIST("h_particle_primary_pdgcode"), mcparticle.pdgCode(), eventWeight); + registry.fill(HIST("h_particle_primary_genstatuscode"), mcparticle.getGenStatusCode(), eventWeight); + registry.fill(HIST("h_particle_primary_hepmcstatuscode"), mcparticle.getHepMCStatusCode(), eventWeight); + registry.fill(HIST("h_particle_primary_process"), mcparticle.getProcess(), eventWeight); + registry.fill(HIST("h_particle_primary_producedbygenerator"), mcparticle.producedByGenerator(), eventWeight); + } } + registry.fill(HIST("h_nparticles_primary"), nParticlesPrimary); } for (auto const& mcdjet : mcdjets) { diff --git a/PWGJE/Tasks/jetHFAngularity.cxx b/PWGJE/Tasks/jetHFAngularity.cxx index 95dd8671feb..6b16ff5af58 100644 --- a/PWGJE/Tasks/jetHFAngularity.cxx +++ b/PWGJE/Tasks/jetHFAngularity.cxx @@ -8,7 +8,7 @@ // 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. -// Measure heavy flavour angularity(D0 & Lamdda_c) +// Measure heavy flavour angularity(D0 & Lambda_c) /// \author Rajdeep Nandi /// \author Preeti Dhankher @@ -18,12 +18,12 @@ #include "PWGJE/Core/JetUtilities.h" #include "PWGJE/DataModel/Jet.h" #include "PWGJE/DataModel/JetReducedData.h" -#include "PWGJE/DataModel/JetSubstructure.h" #include "Common/Core/RecoDecay.h" #include #include +#include #include #include #include @@ -33,9 +33,11 @@ #include #include +#include #include #include +#include #include #include @@ -47,6 +49,7 @@ namespace { constexpr int kOriginMcPrompt = 1; // MC origin flag: prompt constexpr int kOriginMcNonPrompt = 2; // MC origin flag: non-prompt +constexpr int8_t kCandSelFlagD0 = 0; } // namespace namespace o2::aod @@ -86,6 +89,7 @@ DECLARE_SOA_COLUMN(JetMatchedPt, jetMatchedPt, float); DECLARE_SOA_COLUMN(JetMatchedEta, jetMatchedEta, float); DECLARE_SOA_COLUMN(JetMatchedPhi, jetMatchedPhi, float); DECLARE_SOA_COLUMN(JetMatchedDR, jetMatchedDR, float); +DECLARE_SOA_COLUMN(JetMatchedD0Pt, jetMatchedD0Pt, float); DECLARE_SOA_TABLE(D0JetObjTable, "AOD", "D0JETOBJTABLE", JetHfDist, @@ -170,7 +174,8 @@ DECLARE_SOA_TABLE(D0JetMCDObjMatchedTable, "AOD", "D0JMCDOBJMATCH", JetMatchedPt, JetMatchedEta, JetMatchedPhi, - JetMatchedDR); + JetMatchedDR, + JetMatchedD0Pt); } // namespace o2::aod @@ -191,6 +196,22 @@ enum BinJetCntr { D0TaggedJets = 2 }; +/// MC-efficiency collision-counter bins (jet-matching based efficiency) +enum BinMCColCntr { + AllMCCollisions = 1, + SelectedMCCollisions = 2, + AssociatedRecoCollisions = 3, + SelectedAssociatedRecoCollisions = 4 +}; + +/// MC-efficiency jet-counter bins (jet-matching based efficiency) +enum BinMCJetCntr { + DetectorLevelJetInMCCollision = 1, + ParticleLevelJetInMCCollision = 2, + DetectorLevelJetWithMatchedCandidate = 3, + ParticleLevelJetWithMatchedCandidate = 4 +}; + struct JetHFAngularityTask { // DATA @@ -244,6 +265,17 @@ struct JetHFAngularityTask { float massD0MCP = -1.f; + // Slices for the jet-matching based MC efficiency calculation + + // Reconstructed collisions associated to a given JetMcCollision + PresliceUnsorted collisionsPerMCCollisionPreslice = aod::jmccollisionlb::mcCollisionId; + + // D0-tagged (matched) MCD jets per reconstructed collision + Preslice d0MCDJetsPerCollisionPreslice = aod::jet::collisionId; + + // D0-tagged (matched) MCP jets per MC collision + Preslice d0MCPJetsPerMCCollisionPreslice = aod::jet::mcCollisionId; + // Filters Filter jetCutsPt = aod::jet::pt > jetPtMin; @@ -297,7 +329,7 @@ struct JetHFAngularityTask { {"h_d0_mlscore2", ";ML score 2 (non-prompt);entries", {HistType::kTH1F, {{100, 0., 1.}}}}, // ----- Sparse: (m_D0, pT_D0, pT_jet, z_parallel, DeltaR) ----- - {"hSparse_d0", ";m_{D^{0}};#it{p}_{T,D^{0}};#it{p}_{T,jet};z_{||};#DeltaR", {HistType::kTHnSparseF, {{300, 1.7, 2.0}, {200, 0., 100.}, {200, 0., 100.}, {200, 0., 2.}, {200, 0., 1.}}}}, + {"hSparse_d0", ";m_{D^{0}};#it{p}_{T,D^{0}};#it{p}_{T,jet};z_{||};#DeltaR;#lambda_{1}^{1};#lambda_{2}^{1}", {HistType::kTHnSparseF, {{300, 1.7, 2.0}, {200, 0., 100.}, {200, 0., 100.}, {200, 0., 2.}, {200, 0., 1.}, {50, 0., 1.}, {50, 0., 1.}}}}, // MC DETECTOR LEVEL (MCD) @@ -323,7 +355,14 @@ struct JetHFAngularityTask { {"h_d0_origin_mcd", ";origin (0=none,1=prompt,2=non-prompt);entries", {HistType::kTH1F, {{3, 0., 3.}}}}, - {"hSparse_d0_mcd", ";m_{D^{0}}^{det};#it{p}_{T,D^{0}}^{det};#it{p}_{T,jet}^{det};z_{||}^{det};#DeltaR^{det}", {HistType::kTHnSparseF, {{300, 1.7, 2.0}, {200, 0., 100.}, {200, 0., 100.}, {200, 0., 2.}, {200, 0., 1.}}}}, + {"hSparse_d0_mcd", ";m_{D^{0}}^{det};#it{p}_{T,D^{0}}^{det};#it{p}_{T,jet}^{det};z_{||}^{det};#DeltaR^{det};#lambda_{1}^{1,det};#lambda_{2}^{1,det}", {HistType::kTHnSparseF, {{300, 1.7, 2.0}, {200, 0., 100.}, {200, 0., 100.}, {200, 0., 2.}, {200, 0., 1.}, {50, 0., 1.}, {50, 0., 1.}}}}, + + {"hSparse_d0_mcd_calib", ";m_{D^{0}}^{det};#it{p}_{T,D^{0}}^{det};#it{p}_{T,jet}^{det};z_{||}^{det};Origin(D^{0});#lambda_{1}^{1,det};#lambda_{2}^{1,det}", {HistType::kTHnSparseF, {{300, 1.7, 2.0}, {200, 0., 100.}, {200, 0., 100.}, {200, 0., 2.}, {3, -0.5, 2.5}, {50, 0., 1.}, {50, 0., 1.}}}}, + + {"h_d0_mass_mcd_signal", ";m_{K#pi}^{det} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{300, 1.7, 2.0}}}}, + {"h_d0_mass_mcd_reflection", ";m_{K#pi}^{det} (GeV/#it{c}^{2});entries", {HistType::kTH1F, {{300, 1.7, 2.0}}}}, + + {"hSparse_d0_mcd_reflection", ";m_{D^{0}}^{det};#it{p}_{T,D^{0}}^{det};#it{p}_{T,jet}^{det};z_{||}^{det};Origin(D^{0});#lambda_{1}^{1,det};#lambda_{2}^{1,det}", {HistType::kTHnSparseF, {{300, 1.7, 2.0}, {200, 0., 100.}, {200, 0., 100.}, {200, 0., 2.}, {3, -0.5, 2.5}, {50, 0., 1.}, {50, 0., 1.}}}}, // MC PARTICLE LEVEL (MCP) @@ -369,17 +408,43 @@ struct JetHFAngularityTask { // Detector-level vs matched particle-level jet pT {"h_jet_pt_response_matrix", ";#it{p}_{T,jet}^{det} (GeV/#it{c});#it{p}_{T,jet}^{part} (GeV/#it{c})", {HistType::kTH2F, {{200, 0., 200.}, {200, 0., 200.}}}}, - + {"h_jet_pt_response_matrix_pr", ";#it{p}_{T,jet}^{det} (GeV/#it{c});#it{p}_{T,jet}^{part} (GeV/#it{c}) (prompt)", {HistType::kTH2F, {{200, 0., 200.}, {200, 0., 200.}}}}, + {"h_jet_pt_response_matrix_np", ";#it{p}_{T,jet}^{det} (GeV/#it{c});#it{p}_{T,jet}^{part} (GeV/#it{c}) (non-prompt)", {HistType::kTH2F, {{200, 0., 200.}, {200, 0., 200.}}}}, + + // Axes: pT_jet^det, pT_D0^det, pT_jet^part, pT_D0^part + {"h_response_d0pt_pr", ";#it{p}_{T,jet}^{det} (GeV/#it{c});#it{p}_{T,D^{0}}^{det} (GeV/#it{c});#it{p}_{T,jet}^{part} (GeV/#it{c});#it{p}_{T,D^{0}}^{part} (GeV/#it{c})", {HistType::kTHnSparseF, {{40, 0., 200.}, {50, 0., 50.}, {40, 0., 200.}, {50, 0., 50.}}}}, + {"h_response_d0pt_np", ";#it{p}_{T,jet}^{det} (GeV/#it{c});#it{p}_{T,D^{0}}^{det} (GeV/#it{c});#it{p}_{T,jet}^{part} (GeV/#it{c});#it{p}_{T,D^{0}}^{part} (GeV/#it{c})", {HistType::kTHnSparseF, {{40, 0., 200.}, {50, 0., 50.}, {40, 0., 200.}, {50, 0., 50.}}}}, + + {"h_kineff_gen_num_pr", ";#it{p}_{T,jet}^{part} (GeV/#it{c});#it{p}_{T,D^{0}}^{part} (GeV/#it{c})", {HistType::kTH2F, {{40, 0., 200.}, {50, 0., 50.}}}}, + {"h_kineff_gen_den_pr", ";#it{p}_{T,jet}^{part} (GeV/#it{c});#it{p}_{T,D^{0}}^{part} (GeV/#it{c})", {HistType::kTH2F, {{40, 0., 200.}, {50, 0., 50.}}}}, + {"h_kineff_gen_num_np", ";#it{p}_{T,jet}^{part} (GeV/#it{c});#it{p}_{T,D^{0}}^{part} (GeV/#it{c})", {HistType::kTH2F, {{40, 0., 200.}, {50, 0., 50.}}}}, + {"h_kineff_gen_den_np", ";#it{p}_{T,jet}^{part} (GeV/#it{c});#it{p}_{T,D^{0}}^{part} (GeV/#it{c})", {HistType::kTH2F, {{40, 0., 200.}, {50, 0., 50.}}}}, + + {"h_kineff_det_num_pr", ";#it{p}_{T,jet}^{det} (GeV/#it{c});#it{p}_{T,D^{0}}^{det} (GeV/#it{c})", {HistType::kTH2F, {{40, 0., 200.}, {50, 0., 50.}}}}, + {"h_kineff_det_den_pr", ";#it{p}_{T,jet}^{det} (GeV/#it{c});#it{p}_{T,D^{0}}^{det} (GeV/#it{c})", {HistType::kTH2F, {{40, 0., 200.}, {50, 0., 50.}}}}, + {"h_kineff_det_num_np", ";#it{p}_{T,jet}^{det} (GeV/#it{c});#it{p}_{T,D^{0}}^{det} (GeV/#it{c})", {HistType::kTH2F, {{40, 0., 200.}, {50, 0., 50.}}}}, + {"h_kineff_det_den_np", ";#it{p}_{T,jet}^{det} (GeV/#it{c});#it{p}_{T,D^{0}}^{det} (GeV/#it{c})", {HistType::kTH2F, {{40, 0., 200.}, {50, 0., 50.}}}}, // ANGULARITY RESPONSE MATRIX {"h_response_angularity_pr", ";#it{p}_{T,jet}^{det} (GeV/#it{c});#lambda_{1}^{1,det};#it{p}_{T,jet}^{part} (GeV/#it{c});#lambda_{1}^{1,part}", {HistType::kTHnSparseF, {{40, 0., 200.}, {50, 0., 1.}, {40, 0., 200.}, {50, 0., 1.}}}}, {"h_response_angularity_np", ";#it{p}_{T,jet}^{det} (GeV/#it{c});#lambda_{1}^{1,det};#it{p}_{T,jet}^{part} (GeV/#it{c});#lambda_{1}^{1,part}", {HistType::kTHnSparseF, {{40, 0., 200.}, {50, 0., 1.}, {40, 0., 200.}, {50, 0., 1.}}}}, + {"h_response_girth_pr", ";#it{p}_{T,jet}^{det} (GeV/#it{c});#lambda_{2}^{1,det};#it{p}_{T,jet}^{part} (GeV/#it{c});#lambda_{2}^{1,part}", {HistType::kTHnSparseF, {{40, 0., 200.}, {50, 0., 1.}, {40, 0., 200.}, {50, 0., 1.}}}}, + {"h_response_girth_np", ";#it{p}_{T,jet}^{det} (GeV/#it{c});#lambda_{2}^{1,det};#it{p}_{T,jet}^{part} (GeV/#it{c});#lambda_{2}^{1,part}", {HistType::kTHnSparseF, {{40, 0., 200.}, {50, 0., 1.}, {40, 0., 200.}, {50, 0., 1.}}}}, {"h_eff_run2_num_pr", ";#it{p}_{T,D^{0}}^{det} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 50.}}}}, {"h_eff_run2_num_np", ";#it{p}_{T,D^{0}}^{det} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 50.}}}}, {"h_eff_run2_den_pr", ";#it{p}_{T,D^{0}}^{part} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 50.}}}}, {"h_eff_run2_den_np", ";#it{p}_{T,D^{0}}^{part} (GeV/#it{c});entries", {HistType::kTH1F, {{200, 0., 50.}}}}, + // MC EFFICIENCY (jet-to-jet matching based) + + {"MC_CollisionCounter", "N_{collisions};", {HistType::kTH1F, {{4, 0., 4.}}}}, + {"MC_JetCounter", "N_{jet};", {HistType::kTH1F, {{4, 0., 4.}}}}, + + {"hSparse_d0_mcd_eff", ";m_{D^{0}}^{det};#it{p}_{T,D^{0}}^{det};#it{p}_{T,jet}^{det};z_{||}^{det};Origin(D^{0});Matching status;#lambda_{1}^{1,det};#lambda_{2}^{1,det};IsReflection", {HistType::kTHnSparseF, {{300, 1.7, 2.0}, {200, 0., 100.}, {200, 0., 100.}, {200, 0., 2.}, {3, -0.5, 2.5}, {2, -0.5, 1.5}, {50, 0., 1.}, {50, 0., 1.}, {2, -0.5, 1.5}}}}, + + {"hSparse_d0_mcp_eff", ";#it{p}_{T,D^{0}}^{part};#it{p}_{T,jet}^{part};z_{||}^{part};Origin(D^{0});Matching status;#lambda_{1}^{1,part};#lambda_{2}^{1,part}", {HistType::kTHnSparseF, {{200, 0., 100.}, {200, 0., 100.}, {200, 0., 2.}, {3, -0.5, 2.5}, {2, -0.5, 1.5}, {50, 0., 1.}, {50, 0., 1.}}}}, + }}; // init() @@ -446,6 +511,55 @@ struct JetHFAngularityTask { auto hGeoCandDisagreeMCD = registry.get(HIST("h_jet_matching_geocand_disagree_mcd")); hGeoCandDisagreeMCD->GetXaxis()->SetBinLabel(1, "disagree"); hGeoCandDisagreeMCD->GetXaxis()->SetBinLabel(2, "agree"); + + // ---- MC efficiency (jet-to-jet matching based) bin labels ---- + auto mcCollisionCounter = registry.get(HIST("MC_CollisionCounter")); + mcCollisionCounter->GetXaxis()->SetBinLabel(BinMCColCntr::AllMCCollisions, "All MC collisions"); + mcCollisionCounter->GetXaxis()->SetBinLabel(BinMCColCntr::SelectedMCCollisions, "Selected MC collisions"); + mcCollisionCounter->GetXaxis()->SetBinLabel(BinMCColCntr::AssociatedRecoCollisions, "MC-Associated reco collisions"); + mcCollisionCounter->GetXaxis()->SetBinLabel(BinMCColCntr::SelectedAssociatedRecoCollisions, "Selected MC-Associated reco collisions"); + + auto jetCounter = registry.get(HIST("MC_JetCounter")); + jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::DetectorLevelJetInMCCollision, "Detector-level D0 jets"); + jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::ParticleLevelJetInMCCollision, "Particle-level D0 jets"); + jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::DetectorLevelJetWithMatchedCandidate, "Detector jets matched to particle"); + jetCounter->GetXaxis()->SetBinLabel(BinMCJetCntr::ParticleLevelJetWithMatchedCandidate, "Particle jets matched to detector"); + + auto hSparseMCDEff = registry.get(HIST("hSparse_d0_mcd_eff")); + hSparseMCDEff->GetAxis(4)->SetBinLabel(1, "none/bkg"); + hSparseMCDEff->GetAxis(4)->SetBinLabel(2, "prompt"); + hSparseMCDEff->GetAxis(4)->SetBinLabel(3, "non-prompt"); + hSparseMCDEff->GetAxis(5)->SetBinLabel(1, "Unmatched"); + hSparseMCDEff->GetAxis(5)->SetBinLabel(2, "Matched"); + hSparseMCDEff->GetAxis(8)->SetBinLabel(1, "Not reflection"); + hSparseMCDEff->GetAxis(8)->SetBinLabel(2, "Reflection"); + + auto hSparseMCPEff = registry.get(HIST("hSparse_d0_mcp_eff")); + hSparseMCPEff->GetAxis(3)->SetBinLabel(1, "none/bkg"); + hSparseMCPEff->GetAxis(3)->SetBinLabel(2, "prompt"); + hSparseMCPEff->GetAxis(3)->SetBinLabel(3, "non-prompt"); + hSparseMCPEff->GetAxis(4)->SetBinLabel(1, "Unmatched"); + hSparseMCPEff->GetAxis(4)->SetBinLabel(2, "Matched"); + + // ---- Reflection sparse bin labels ---- + auto hSparseMCDRefl = registry.get(HIST("hSparse_d0_mcd_reflection")); + hSparseMCDRefl->GetAxis(4)->SetBinLabel(1, "none/bkg"); + hSparseMCDRefl->GetAxis(4)->SetBinLabel(2, "prompt"); + hSparseMCDRefl->GetAxis(4)->SetBinLabel(3, "non-prompt"); + } + + // Helper: reflection identification (MCD only) + + template + bool isReflectedCandidate(CAND const& cand) + { + const int8_t flagMcMatchRec = cand.flagMcMatchRec(); + if (flagMcMatchRec == 0) { + return false; // not truth-matched -> background, not a reflection + } + const bool trueIsD0 = flagMcMatchRec > 0; // sign encodes true species + const bool thisRowIsD0Hypothesis = (cand.candidateSelFlag() == kCandSelFlagD0); // which hypothesis this row uses + return thisRowIsD0Hypothesis != trueIsD0; } // Helper: angularity @@ -494,7 +608,7 @@ struct JetHFAngularityTask { } for (auto const& cand : candidates) { - double m; + double m = 0; if (candMass > 0.) { m = candMass; } else if constexpr (requires { cand.m(); }) { @@ -603,7 +717,8 @@ struct JetHFAngularityTask { registry.fill(HIST("hSparse_d0"), d0Candidate.m(), d0Candidate.pt(), - jet.pt(), zParallel, axisDistance); + jet.pt(), zParallel, axisDistance, + angularity, girth); objJetTable(axisDistance, jet.pt(), @@ -693,6 +808,22 @@ struct JetHFAngularityTask { const int8_t flagMcMatch = d0Candidate.flagMcMatchRec(); const int8_t originMc = d0Candidate.originMcRec(); // 0 none, 1 prompt, 2 non-prompt + // ---- Reflection identification ---- + const bool isReflection = isReflectedCandidate(d0Candidate); + const bool isTrueSignal = (flagMcMatch != 0) && !isReflection; + + if (isReflection) { + registry.fill(HIST("h_d0_mass_mcd_reflection"), d0Candidate.m()); + registry.fill(HIST("hSparse_d0_mcd_reflection"), + d0Candidate.m(), d0Candidate.pt(), jet.pt(), zParallel, originMc, + angularity, girth); + } else if (isTrueSignal) { + registry.fill(HIST("h_d0_mass_mcd_signal"), d0Candidate.m()); + registry.fill(HIST("hSparse_d0_mcd_calib"), + d0Candidate.m(), d0Candidate.pt(), jet.pt(), zParallel, originMc, + angularity, girth); + } + // ---- Histograms ---- registry.fill(HIST("h_d0_mass_mcd"), d0Candidate.m()); registry.fill(HIST("h_d0_pt_mcd"), d0Candidate.pt()); @@ -704,7 +835,8 @@ struct JetHFAngularityTask { registry.fill(HIST("h_d0_origin_mcd"), static_cast(originMc)); registry.fill(HIST("hSparse_d0_mcd"), d0Candidate.m(), d0Candidate.pt(), - jet.pt(), zParallel, axisDistance); + jet.pt(), zParallel, axisDistance, + angularity, girth); if (originMc == kOriginMcPrompt) { registry.fill(HIST("h_eff_run2_num_pr"), d0Candidate.pt()); @@ -752,168 +884,6 @@ struct JetHFAngularityTask { PROCESS_SWITCH(JetHFAngularityTask, processMCDChargedSubstructure, "MC DETECTOR LEVEL: D0-tagged charged jet substructure", false); - // Process: MC DETECTOR-LEVEL, WITH jet-to-jet matching - - void processMCDChargedSubstructureMatched( - soa::Filtered::iterator const& collision, - aod::JetMcCollisions const&, - soa::Filtered const& mcdjets, - D0CandidatesMCD const& /*candidates*/, - D0MCPJetsMatched const& /*mcpjets*/, - D0CandidatesMCP const& /*candidatesP*/, - aod::JetTracks const&, - aod::JetParticles const&) - { - // Event selection (same sel8 + |z| logic as the unmatched MCD process) - - if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { - return; - } - - const float mcWeight = collision.mcCollision().weight(); - - for (const auto& jet : mcdjets) { - - // Jet-level quantities - auto jetTracks = jet.template tracks_as(); - auto jetCandidates = jet.template candidates_as(); - - const int nConst = static_cast(jetTracks.size()) + static_cast(jetCandidates.size()); - const float angularity = computeLambda(jet, jetTracks, jetCandidates, 1.f, 1.f); // λ_1^1 - const float girth = computeLambda(jet, jetTracks, jetCandidates, 2.f, 1.f); // λ_2^1 - const float mjet = computeJetMass(jetTracks, jetCandidates); - - const std::array jetMom{jet.px(), jet.py(), jet.pz()}; - - bool isGeoMatched = false; - float matchedPt = -1.f; - float matchedEta = -999.f; - float matchedPhi = -999.f; - float matchedDR = -1.f; - float matchedAngularity = -1.f; - int geoMatchedGlobalIndex = -1; - int nGeoMatches = 0; - - if (jet.has_matchedJetGeo()) { - - for (const auto& mcpjet : jet.template matchedJetGeo_as()) { - ++nGeoMatches; - - const float dR = jetutilities::deltaR(jet, mcpjet); - registry.fill(HIST("h_jet_matching_dr_mcd_allcand"), dR, mcWeight); - registry.fill(HIST("h_jet_pt_response_matrix_allcand"), jet.pt(), mcpjet.pt(), mcWeight); - - if (!isGeoMatched) { - isGeoMatched = true; - matchedPt = mcpjet.pt(); - matchedEta = mcpjet.eta(); - matchedPhi = mcpjet.phi(); - matchedDR = dR; - geoMatchedGlobalIndex = mcpjet.globalIndex(); - - auto mcpjetParticles = mcpjet.template tracks_as(); - auto mcpjetCandidates = mcpjet.template candidates_as(); - matchedAngularity = computeLambda(mcpjet, mcpjetParticles, mcpjetCandidates, 1.f, 1.f); // λ_1^1 - } - } - } - registry.fill(HIST("h_jet_matching_ngeo_mcd"), nGeoMatches, mcWeight); - - // Candidate-based match - - bool isCandMatched = false; - int candMatchedGlobalIndex = -1; - int nCandMatches = 0; - - if (jet.has_matchedJetCand()) { - for (const auto& mcpjet : jet.template matchedJetCand_as()) { - ++nCandMatches; - if (!isCandMatched) { - isCandMatched = true; - candMatchedGlobalIndex = mcpjet.globalIndex(); - } - } - } - registry.fill(HIST("h_jet_matching_ncand_mcd"), nCandMatches, mcWeight); - - // "Clean" match: both criteria fire AND agree on the same target jet. - - const bool isCleanMatched = isGeoMatched && isCandMatched && - (geoMatchedGlobalIndex == candMatchedGlobalIndex); - - registry.fill(HIST("h_jet_matching_geo_status_mcd"), isGeoMatched ? 1.5f : 0.5f, mcWeight); - registry.fill(HIST("h_jet_matching_cand_status_mcd"), isCandMatched ? 1.5f : 0.5f, mcWeight); - registry.fill(HIST("h_jet_matching_clean_mcd"), isCleanMatched ? 1.5f : 0.5f, mcWeight); - - if (isGeoMatched) { - const bool agree = isCandMatched && (geoMatchedGlobalIndex == candMatchedGlobalIndex); - registry.fill(HIST("h_jet_matching_geocand_disagree_mcd"), agree ? 1.5f : 0.5f, mcWeight); - } - - if (isCleanMatched) { - registry.fill(HIST("h_jet_pt_response_matrix"), jet.pt(), matchedPt, mcWeight); - registry.fill(HIST("h_jet_matching_dr_mcd"), matchedDR, mcWeight); - } - - const int8_t geoStatus = static_cast(isGeoMatched); - const int8_t candStatus = static_cast(isCandMatched); - const int8_t cleanStatus = static_cast(isCleanMatched); - - // ---- D0 candidate loop - for (const auto& d0Candidate : jetCandidates) { - - const std::array d0Mom{d0Candidate.px(), d0Candidate.py(), d0Candidate.pz()}; - - const float zParallel = RecoDecay::dotProd(d0Mom, jetMom) / RecoDecay::mag2(jetMom); - const float axisDistance = jetutilities::deltaR(jet, d0Candidate); - - const int8_t flagMcMatch = d0Candidate.flagMcMatchRec(); - const int8_t originMc = d0Candidate.originMcRec(); - - // Angularity response matrix - - if (isCleanMatched) { - if (originMc == kOriginMcPrompt) { - registry.fill(HIST("h_response_angularity_pr"), jet.pt(), angularity, matchedPt, matchedAngularity, mcWeight); - } else if (originMc == kOriginMcNonPrompt) { - registry.fill(HIST("h_response_angularity_np"), jet.pt(), angularity, matchedPt, matchedAngularity, mcWeight); - } - } - - objJetMCDMatchedTable(axisDistance, - jet.pt(), - jet.eta(), - jet.phi(), - nConst, - angularity, - girth, - mjet, - zParallel, - d0Candidate.pt(), - d0Candidate.eta(), - d0Candidate.phi(), - d0Candidate.m(), - d0Candidate.y(), - d0Candidate.mlScores()[0], - d0Candidate.mlScores()[1], - d0Candidate.mlScores()[2], - flagMcMatch, - originMc, - geoStatus, - candStatus, - cleanStatus, - matchedPt, - matchedEta, - matchedPhi, - matchedDR); - } // end D0 loop - - } // end jet loop - } - - PROCESS_SWITCH(JetHFAngularityTask, processMCDChargedSubstructureMatched, - "MC DETECTOR LEVEL: D0-tagged charged jet substructure WITH jet-to-jet matching (needs jet-matching workflow)", false); - // Process: MC PARTICLE-LEVEL (MCP) void processMCPChargedSubstructure( @@ -969,14 +939,11 @@ struct JetHFAngularityTask { registry.fill(HIST("h_d0_jet_distance_mcp"), axisDistance); registry.fill(HIST("h_d0_origin_mcp"), static_cast(originMc)); - // Run 2 style efficiency denominator - if (originMc == kOriginMcPrompt) { registry.fill(HIST("h_eff_run2_den_pr"), d0Particle.pt()); } else if (originMc == kOriginMcNonPrompt) { registry.fill(HIST("h_eff_run2_den_np"), d0Particle.pt()); } - objJetMCPTable(axisDistance, jet.pt(), jet.eta(), @@ -1012,6 +979,308 @@ struct JetHFAngularityTask { PROCESS_SWITCH(JetHFAngularityTask, processMCPChargedSubstructure, "MC PARTICLE LEVEL: D0-tagged charged jet substructure", false); + + void processMCDChargedSubstructureMatched(aod::JetMcCollisions const& mccollisions, + aod::JetCollisionsMCD const& collisions, + D0MCDJetsMatched const& mcdjets, + D0MCPJetsMatched const& mcpjets, + D0CandidatesMCD const&, + D0CandidatesMCP const&, + aod::JetTracks const&, + aod::JetParticles const&) + { + + const int jetRBin = static_cast(std::lround(static_cast(jetR) * 100.0f)); + + for (const auto& mccollision : mccollisions) { + + registry.fill(HIST("MC_CollisionCounter"), getValFromBin(BinMCColCntr::AllMCCollisions)); + + if (std::abs(mccollision.posZ()) > vertexZCut) { + continue; + } + registry.fill(HIST("MC_CollisionCounter"), getValFromBin(BinMCColCntr::SelectedMCCollisions)); + + // const float mcWeight = mccollision.weight(); + + const auto collisionsPerMCCollision = collisions.sliceBy(collisionsPerMCCollisionPreslice, mccollision.globalIndex()); + for (const auto& collision : collisionsPerMCCollision) { + + registry.fill(HIST("MC_CollisionCounter"), getValFromBin(BinMCColCntr::AssociatedRecoCollisions)); + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits) || + !(std::abs(collision.posZ()) < vertexZCut)) { + continue; + } + registry.fill(HIST("MC_CollisionCounter"), getValFromBin(BinMCColCntr::SelectedAssociatedRecoCollisions)); + + const auto d0mcdJetsPerCollision = mcdjets.sliceBy(d0MCDJetsPerCollisionPreslice, collision.globalIndex()); + for (const auto& mcdjet : d0mcdJetsPerCollision) { + if (mcdjet.pt() <= jetPtMin || mcdjet.r() != jetRBin) { + continue; + } + registry.fill(HIST("MC_JetCounter"), getValFromBin(BinMCJetCntr::DetectorLevelJetInMCCollision)); + + auto jetTracks = mcdjet.template tracks_as(); + auto jetCandidates = mcdjet.template candidates_as(); + + const int nConst = static_cast(jetTracks.size()) + static_cast(jetCandidates.size()); + const float angularity = computeLambda(mcdjet, jetTracks, jetCandidates, 1.f, 1.f); // λ_1^1 + const float girth = computeLambda(mcdjet, jetTracks, jetCandidates, 2.f, 1.f); // λ_2^1 + const float mjet = computeJetMass(jetTracks, jetCandidates); + + const std::array jetMomMCD{mcdjet.px(), mcdjet.py(), mcdjet.pz()}; + + bool isGeoMatched = false; + float matchedPt = -1.f; + float matchedEta = -999.f; + float matchedPhi = -999.f; + float matchedDR = -1.f; + float matchedAngularity = -1.f; + float matchedGirth = -1.f; + float matchedD0Pt = -1.f; // NEW + int geoMatchedGlobalIndex = -1; + int nGeoMatches = 0; + + if (mcdjet.has_matchedJetGeo()) { + for (const auto& mcpjet : mcdjet.template matchedJetGeo_as()) { + ++nGeoMatches; + + const float dR = jetutilities::deltaR(mcdjet, mcpjet); + registry.fill(HIST("h_jet_matching_dr_mcd_allcand"), dR); + registry.fill(HIST("h_jet_pt_response_matrix_allcand"), mcdjet.pt(), mcpjet.pt()); + + if (!isGeoMatched) { + isGeoMatched = true; + matchedPt = mcpjet.pt(); + matchedEta = mcpjet.eta(); + matchedPhi = mcpjet.phi(); + matchedDR = dR; + geoMatchedGlobalIndex = mcpjet.globalIndex(); + + auto mcpjetParticles = mcpjet.template tracks_as(); + auto mcpjetCandidates = mcpjet.template candidates_as(); + matchedAngularity = computeLambda(mcpjet, mcpjetParticles, mcpjetCandidates, 1.f, 1.f); // λ_1^1 + matchedGirth = computeLambda(mcpjet, mcpjetParticles, mcpjetCandidates, 2.f, 1.f); // λ_2^1 + if (!mcpjetCandidates.empty()) { + auto matchedMcpD0 = mcpjet.template candidates_first_as(); + matchedD0Pt = matchedMcpD0.pt(); + } + } + } + } + registry.fill(HIST("h_jet_matching_ngeo_mcd"), nGeoMatches); + + bool isCandMatched = false; + int candMatchedGlobalIndex = -1; + int nCandMatches = 0; + + if (mcdjet.has_matchedJetCand()) { + for (const auto& mcpjet : mcdjet.template matchedJetCand_as()) { + ++nCandMatches; + if (!isCandMatched) { + isCandMatched = true; + candMatchedGlobalIndex = mcpjet.globalIndex(); + } + } + } + registry.fill(HIST("h_jet_matching_ncand_mcd"), nCandMatches); + + // "Clean" match: both criteria fire AND agree on the same target jet. + const bool isCleanMatched = isGeoMatched && isCandMatched && + (geoMatchedGlobalIndex == candMatchedGlobalIndex); + + registry.fill(HIST("h_jet_matching_geo_status_mcd"), isGeoMatched ? 1.5f : 0.5f); + registry.fill(HIST("h_jet_matching_cand_status_mcd"), isCandMatched ? 1.5f : 0.5f); + registry.fill(HIST("h_jet_matching_clean_mcd"), isCleanMatched ? 1.5f : 0.5f); + + if (isGeoMatched) { + const bool agree = isCandMatched && (geoMatchedGlobalIndex == candMatchedGlobalIndex); + registry.fill(HIST("h_jet_matching_geocand_disagree_mcd"), agree ? 1.5f : 0.5f); + } + + if (isCleanMatched) { + registry.fill(HIST("h_jet_pt_response_matrix"), mcdjet.pt(), matchedPt); + registry.fill(HIST("h_jet_matching_dr_mcd"), matchedDR); + } + + const auto geoStatus = static_cast(isGeoMatched); + const auto candStatus = static_cast(isCandMatched); + const auto cleanStatus = static_cast(isCleanMatched); + + const int isCleanMatchedMCD = isCleanMatched ? 1 : 0; + + if (isCleanMatched) { + registry.fill(HIST("MC_JetCounter"), getValFromBin(BinMCJetCntr::DetectorLevelJetWithMatchedCandidate)); + } + + for (const auto& mcdD0cand : jetCandidates) { + + const std::array candMomMCD{mcdD0cand.px(), mcdD0cand.py(), mcdD0cand.pz()}; + const float zParallelMCD = RecoDecay::dotProd(candMomMCD, jetMomMCD) / RecoDecay::mag2(jetMomMCD); + const float axisDistance = jetutilities::deltaR(mcdjet, mcdD0cand); + + const int8_t flagMcMatch = mcdD0cand.flagMcMatchRec(); + const int originMcd = mcdD0cand.originMcRec(); // 0 none/bkg, 1 prompt, 2 non-prompt + + // Reflection identification: candidateSelFlag() hypothesis vs. true species + const bool isReflection = isReflectedCandidate(mcdD0cand); + const int isReflectionFlag = isReflection ? 1 : 0; + const bool isTrueSignal = (flagMcMatch != 0) && !isReflection; + + if (isReflection) { + registry.fill(HIST("h_d0_mass_mcd_reflection"), mcdD0cand.m()); + registry.fill(HIST("hSparse_d0_mcd_reflection"), + mcdD0cand.m(), mcdD0cand.pt(), mcdjet.pt(), zParallelMCD, originMcd, + angularity, girth); + } else if (isTrueSignal) { + registry.fill(HIST("h_d0_mass_mcd_signal"), mcdD0cand.m()); + registry.fill(HIST("hSparse_d0_mcd_calib"), + mcdD0cand.m(), mcdD0cand.pt(), mcdjet.pt(), zParallelMCD, originMcd, + angularity, girth); + } + + registry.fill(HIST("hSparse_d0_mcd_eff"), + mcdD0cand.m(), + mcdD0cand.pt(), + mcdjet.pt(), + zParallelMCD, + originMcd, + isCleanMatchedMCD, + angularity, + girth, + isReflectionFlag); + + if (originMcd == kOriginMcPrompt) { + registry.fill(HIST("h_eff_run2_num_pr"), mcdD0cand.pt()); + registry.fill(HIST("h_kineff_det_den_pr"), mcdjet.pt(), mcdD0cand.pt()); + if (isGeoMatched) { + registry.fill(HIST("h_kineff_det_num_pr"), mcdjet.pt(), mcdD0cand.pt()); + } + } else if (originMcd == kOriginMcNonPrompt) { + registry.fill(HIST("h_eff_run2_num_np"), mcdD0cand.pt()); + registry.fill(HIST("h_kineff_det_den_np"), mcdjet.pt(), mcdD0cand.pt()); + if (isGeoMatched) { + registry.fill(HIST("h_kineff_det_num_np"), mcdjet.pt(), mcdD0cand.pt()); + } + } + + if (isCleanMatched) { + if (originMcd == kOriginMcPrompt) { + registry.fill(HIST("h_jet_pt_response_matrix_pr"), mcdjet.pt(), matchedPt); + registry.fill(HIST("h_response_angularity_pr"), mcdjet.pt(), angularity, matchedPt, matchedAngularity); + registry.fill(HIST("h_response_girth_pr"), mcdjet.pt(), girth, matchedPt, matchedGirth); + registry.fill(HIST("h_response_d0pt_pr"), mcdjet.pt(), mcdD0cand.pt(), matchedPt, matchedD0Pt); + } else if (originMcd == kOriginMcNonPrompt) { + registry.fill(HIST("h_jet_pt_response_matrix_np"), mcdjet.pt(), matchedPt); + registry.fill(HIST("h_response_angularity_np"), mcdjet.pt(), angularity, matchedPt, matchedAngularity); + registry.fill(HIST("h_response_girth_np"), mcdjet.pt(), girth, matchedPt, matchedGirth); + registry.fill(HIST("h_response_d0pt_np"), mcdjet.pt(), mcdD0cand.pt(), matchedPt, matchedD0Pt); + } + } + + objJetMCDMatchedTable(axisDistance, + mcdjet.pt(), + mcdjet.eta(), + mcdjet.phi(), + nConst, + angularity, + girth, + mjet, + zParallelMCD, + mcdD0cand.pt(), + mcdD0cand.eta(), + mcdD0cand.phi(), + mcdD0cand.m(), + mcdD0cand.y(), + mcdD0cand.mlScores()[0], + mcdD0cand.mlScores()[1], + mcdD0cand.mlScores()[2], + flagMcMatch, + originMcd, + geoStatus, + candStatus, + cleanStatus, + matchedPt, + matchedEta, + matchedPhi, + matchedDR, + matchedD0Pt); + } // end D0 candidate loop + } // end MCD jet loop + } // end reconstructed-collision loop + + const auto d0mcpJetsPerMCCollision = mcpjets.sliceBy(d0MCPJetsPerMCCollisionPreslice, mccollision.globalIndex()); + for (const auto& mcpjet : d0mcpJetsPerMCCollision) { + + if (mcpjet.pt() <= jetPtMin || mcpjet.r() != jetRBin) { + continue; + } + + registry.fill(HIST("MC_JetCounter"), getValFromBin(BinMCJetCntr::ParticleLevelJetInMCCollision)); + + auto mcpD0cand = mcpjet.template candidates_first_as(); + + const int originMcp = mcpD0cand.originMcGen(); // 0 none/bkg, 1 prompt, 2 non-prompt + + bool mcpIsCleanMatched = false; + if (mcpjet.has_matchedJetGeo() && mcpjet.has_matchedJetCand()) { + int mcpGeoTarget = -1; + for (const auto& mcdjetGeo : mcpjet.template matchedJetGeo_as()) { + mcpGeoTarget = mcdjetGeo.globalIndex(); + break; // first geo match, mirrors the MCD-side "first match wins" convention + } + int mcpCandTarget = -1; + for (const auto& mcdjetCand : mcpjet.template matchedJetCand_as()) { + mcpCandTarget = mcdjetCand.globalIndex(); + break; + } + mcpIsCleanMatched = (mcpGeoTarget == mcpCandTarget) && (mcpGeoTarget != -1); + } + const int isCleanMatchedMCP = mcpIsCleanMatched ? 1 : 0; + + if (mcpIsCleanMatched) { + registry.fill(HIST("MC_JetCounter"), getValFromBin(BinMCJetCntr::ParticleLevelJetWithMatchedCandidate)); + } + + const std::array jetMomMCP{mcpjet.px(), mcpjet.py(), mcpjet.pz()}; + const std::array candMomMCP{mcpD0cand.px(), mcpD0cand.py(), mcpD0cand.pz()}; + const float zParallelMCP = RecoDecay::dotProd(candMomMCP, jetMomMCP) / RecoDecay::mag2(jetMomMCP); + + auto mcpJetParticles = mcpjet.template tracks_as(); + auto mcpJetCandidates = mcpjet.template candidates_as(); + const float angularityMCP = computeLambda(mcpjet, mcpJetParticles, mcpJetCandidates, 1.f, 1.f); // λ_1^1 + const float girthMCP = computeLambda(mcpjet, mcpJetParticles, mcpJetCandidates, 2.f, 1.f); // λ_2^1 + + registry.fill(HIST("hSparse_d0_mcp_eff"), + mcpD0cand.pt(), + mcpjet.pt(), + zParallelMCP, + originMcp, + isCleanMatchedMCP, + angularityMCP, + girthMCP); + + const bool mcpIsGeoMatched = mcpjet.has_matchedJetGeo(); + if (originMcp == kOriginMcPrompt) { + registry.fill(HIST("h_eff_run2_den_pr"), mcpD0cand.pt()); + registry.fill(HIST("h_kineff_gen_den_pr"), mcpjet.pt(), mcpD0cand.pt()); + if (mcpIsGeoMatched) { + registry.fill(HIST("h_kineff_gen_num_pr"), mcpjet.pt(), mcpD0cand.pt()); + } + } else if (originMcp == kOriginMcNonPrompt) { + registry.fill(HIST("h_eff_run2_den_np"), mcpD0cand.pt()); + registry.fill(HIST("h_kineff_gen_den_np"), mcpjet.pt(), mcpD0cand.pt()); + if (mcpIsGeoMatched) { + registry.fill(HIST("h_kineff_gen_num_np"), mcpjet.pt(), mcpD0cand.pt()); + } + } + } // end MCP jet loop + } // end MC collision loop + } + + PROCESS_SWITCH(JetHFAngularityTask, processMCDChargedSubstructureMatched, + "MC: unified efficiency + jet matching + response matrix + reflection (needs jet-matching workflow)", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGJE/Tasks/jetOutlierQA.cxx b/PWGJE/Tasks/jetOutlierQA.cxx index d0d802a95a8..a9cf7fe6714 100644 --- a/PWGJE/Tasks/jetOutlierQA.cxx +++ b/PWGJE/Tasks/jetOutlierQA.cxx @@ -418,7 +418,7 @@ struct JetOutlierQATask { { // // collision-based outlier checks based on BC and z position - // based on 2-event correlation checks in PWGDQ/Tasks/tableReader_withAssoc.cxx + // based on 2-event correlation checks in PWGDQ/Tasks/tableReader_withAssoc.h // fBCCollMap.clear(); diff --git a/PWGJE/Tasks/jetSpectraCharged.cxx b/PWGJE/Tasks/jetSpectraCharged.cxx index 8b32a44aff4..e54e31b6e96 100644 --- a/PWGJE/Tasks/jetSpectraCharged.cxx +++ b/PWGJE/Tasks/jetSpectraCharged.cxx @@ -85,6 +85,7 @@ struct JetSpectraCharged { Configurable kappa{"kappa", 1.0, "angularity kappa"}; Configurable alpha{"alpha", 1.0, "angularity alpha"}; Configurable useFT0CVariant{"useFT0CVariant", false, "IF checkCentFT0M is false: false -> use standard FT0C centrality selection; true -> use FT0CVariant1"}; + Configurable rhoShift{"rhoShift", 0, "value of artificial rho shift: rho -> rho - rhoShift ; 0 by default"}; std::vector eventSelectionBits; int trackSelection = -1; @@ -347,13 +348,13 @@ struct JetSpectraCharged { return true; } // if isMCGenOnly is true, skip MC selection and accept all of them - float centrality = -1.0; + float mcpCentrality = -1.0; // checkCentFT0M ? centrality = mccollision.centFT0M() : centrality = mccollision.centFT0C(); - centrality = mccollision.centFT0M(); + mcpCentrality = mccollision.centFT0M(); if (fillHistograms) { registry.fill(HIST("h_mccollisions"), 0.5); - registry.fill(HIST("h2_centrality_mccollisions"), centrality, 0.5, eventWeight); + registry.fill(HIST("h2_centrality_mccollisions"), mcpCentrality, 0.5, eventWeight); if (isWeighted) registry.fill(HIST("h_mccollisions_weighted"), 0.5, eventWeight); } @@ -363,7 +364,7 @@ struct JetSpectraCharged { } if (fillHistograms) { registry.fill(HIST("h_mccollisions"), 1.5); - registry.fill(HIST("h2_centrality_mccollisions"), centrality, 1.5, eventWeight); + registry.fill(HIST("h2_centrality_mccollisions"), mcpCentrality, 1.5, eventWeight); if (isWeighted) registry.fill(HIST("h_mccollisions_weighted"), 1.5, eventWeight); } @@ -373,7 +374,7 @@ struct JetSpectraCharged { } if (fillHistograms) { registry.fill(HIST("h_mccollisions"), 2.5); - registry.fill(HIST("h2_centrality_mccollisions"), centrality, 2.5, eventWeight); + registry.fill(HIST("h2_centrality_mccollisions"), mcpCentrality, 2.5, eventWeight); if (isWeighted) registry.fill(HIST("h_mccollisions_weighted"), 2.5, eventWeight); } @@ -389,7 +390,7 @@ struct JetSpectraCharged { occupancyIsGood = true; } - if ((centralityMin < centrality) && (centrality < centralityMax)) { + if ((centralityMin < mcpCentrality) && (mcpCentrality < centralityMax)) { centralityIsGood = true; } } else { @@ -401,9 +402,9 @@ struct JetSpectraCharged { occupancyIsGood = true; } - float centrality = -1.0; - checkCentFT0M ? centrality = collision.centFT0M() : centrality = (useFT0CVariant ? collision.centFT0CVariant1() : collision.centFT0C()); - if ((centralityMin < centrality) && (centrality < centralityMax)) { + float mcdCentrality = -1.0; + checkCentFT0M ? mcdCentrality = collision.centFT0M() : mcdCentrality = (useFT0CVariant ? collision.centFT0CVariant1() : collision.centFT0C()); + if ((centralityMin < mcdCentrality) && (mcdCentrality < centralityMax)) { centralityIsGood = true; } } @@ -414,7 +415,7 @@ struct JetSpectraCharged { } if (fillHistograms) { registry.fill(HIST("h_mccollisions"), 3.5); - registry.fill(HIST("h2_centrality_mccollisions"), centrality, 3.5, eventWeight); + registry.fill(HIST("h2_centrality_mccollisions"), mcpCentrality, 3.5, eventWeight); if (isWeighted) registry.fill(HIST("h_mccollisions_weighted"), 3.5, eventWeight); } @@ -424,7 +425,7 @@ struct JetSpectraCharged { } if (fillHistograms) { registry.fill(HIST("h_mccollisions"), 4.5); - registry.fill(HIST("h2_centrality_mccollisions"), centrality, 4.5, eventWeight); + registry.fill(HIST("h2_centrality_mccollisions"), mcpCentrality, 4.5, eventWeight); if (isWeighted) registry.fill(HIST("h_mccollisions_weighted"), 4.5, eventWeight); } @@ -434,7 +435,7 @@ struct JetSpectraCharged { } if (fillHistograms) { registry.fill(HIST("h_mccollisions"), 5.5); - registry.fill(HIST("h2_centrality_mccollisions"), centrality, 5.5, eventWeight); + registry.fill(HIST("h2_centrality_mccollisions"), mcpCentrality, 5.5, eventWeight); if (isWeighted) registry.fill(HIST("h_mccollisions_weighted"), 5.5, eventWeight); } @@ -521,7 +522,7 @@ struct JetSpectraCharged { if (jet.pt() > pTHatMaxMCD * pTHat || pTHat < pTHatAbsoluteMin) { return; } - double jetcorrpt = jet.pt() - (rho * jet.area()); + double jetcorrpt = jet.pt() - ((rho - rhoShift) * jet.area()); if (jet.r() == round(selectedJetsRadius * 100.0f)) { // fill jet histograms after area-based subtraction registry.fill(HIST("h_jet_pt_rhoareasubtracted"), jetcorrpt, weight); @@ -579,7 +580,7 @@ struct JetSpectraCharged { } if (jet.r() == round(selectedJetsRadius * 100.0f)) { // fill mcp jet histograms - double jetcorrpt = jet.pt() - (rho * jet.area()); + double jetcorrpt = jet.pt() - ((rho - rhoShift) * jet.area()); registry.fill(HIST("h_jet_pt_part_rhoareasubtracted"), jetcorrpt, weight); registry.fill(HIST("h3_jet_pt_jet_eta_jet_phi_part_rhoareasubtracted"), jetcorrpt, jet.eta(), jet.phi(), weight); if (jetcorrpt > 0) { @@ -1028,7 +1029,7 @@ struct JetSpectraCharged { bool hasSel8Coll = false; bool centralityIsGood = false; bool occupancyIsGood = false; - float centrality = mccollision.centFT0M(); + float mcpCentrality = mccollision.centFT0M(); if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly) { if (hasRecoColl && jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { hasSel8Coll = true; @@ -1036,7 +1037,7 @@ struct JetSpectraCharged { if (hasRecoColl && (trackOccupancyInTimeRangeMin < collisions.begin().trackOccupancyInTimeRange()) && (collisions.begin().trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax)) { occupancyIsGood = true; } - if ((centralityMin < centrality) && (centrality < centralityMax)) { + if ((centralityMin < mcpCentrality) && (mcpCentrality < centralityMax)) { centralityIsGood = true; } } else { @@ -1047,9 +1048,9 @@ struct JetSpectraCharged { if ((trackOccupancyInTimeRangeMin < collision.trackOccupancyInTimeRange()) && (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax)) { occupancyIsGood = true; } - float centrality = -1.0; - checkCentFT0M ? centrality = collision.centFT0M() : (centrality = (useFT0CVariant ? collision.centFT0CVariant1() : collision.centFT0C())); - if ((centralityMin < centrality) && (centrality < centralityMax)) { + float mcdCentrality = -1.0; + checkCentFT0M ? mcdCentrality = collision.centFT0M() : (mcdCentrality = (useFT0CVariant ? collision.centFT0CVariant1() : collision.centFT0C())); + if ((centralityMin < mcdCentrality) && (mcdCentrality < centralityMax)) { centralityIsGood = true; } } @@ -1111,7 +1112,7 @@ struct JetSpectraCharged { bool hasSel8Coll = false; bool centralityIsGood = false; bool occupancyIsGood = false; - float centrality = mccollision.centFT0M(); + float mcpCentrality = mccollision.centFT0M(); if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly) { if (hasRecoColl && jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { hasSel8Coll = true; @@ -1119,7 +1120,7 @@ struct JetSpectraCharged { if (hasRecoColl && (trackOccupancyInTimeRangeMin < collisions.begin().trackOccupancyInTimeRange()) && (collisions.begin().trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax)) { occupancyIsGood = true; } - if ((centralityMin < centrality) && (centrality < centralityMax)) { + if ((centralityMin < mcpCentrality) && (mcpCentrality < centralityMax)) { centralityIsGood = true; } } else { @@ -1130,9 +1131,9 @@ struct JetSpectraCharged { if ((trackOccupancyInTimeRangeMin < collision.trackOccupancyInTimeRange()) && (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax)) { occupancyIsGood = true; } - float centrality = -1.0; - checkCentFT0M ? centrality = collision.centFT0M() : (centrality = (useFT0CVariant ? collision.centFT0CVariant1() : collision.centFT0C())); - if ((centralityMin < centrality) && (centrality < centralityMax)) { + float mcdCentrality = -1.0; + checkCentFT0M ? mcdCentrality = collision.centFT0M() : (mcdCentrality = (useFT0CVariant ? collision.centFT0CVariant1() : collision.centFT0C())); + if ((centralityMin < mcdCentrality) && (mcdCentrality < centralityMax)) { centralityIsGood = true; } } diff --git a/PWGJE/Tasks/jetSpectraEseTask.cxx b/PWGJE/Tasks/jetSpectraEseTask.cxx index 22c102be4b5..59d6c7a7598 100644 --- a/PWGJE/Tasks/jetSpectraEseTask.cxx +++ b/PWGJE/Tasks/jetSpectraEseTask.cxx @@ -22,6 +22,7 @@ #include "Common/Core/RecoDecay.h" #include "Common/DataModel/EseTable.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Qvectors.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -78,7 +79,7 @@ struct JetSpectraEseTask { Configurable vertexZCut{"vertexZCut", 10.0, "vertex z cut"}; // Configurable leadingTrackPtCut{"leadingTrackPtCut", 5.0, "leading jet pT cut"}; Configurable jetAreaFractionMin{"jetAreaFractionMin", -99, "used to make a cut on the jet areas"}; - Configurable cfgCentVariant{"cfgCentVariant", false, "Flag for centrality variant 1"}; + Configurable cfgCentrality{"cfgCentrality", "FT0C", "Centrality estimator: FT0C, FT0M, or FT0CVariant1"}; Configurable cfgisPbPb{"cfgisPbPb", false, "Flag for using MC centrality in PbPb"}; Configurable cfgbkgSubMC{"cfgbkgSubMC", true, "Flag for MC background subtraction"}; Configurable cfgUseMCEventWeights{"cfgUseMCEventWeights", false, "Flag for using MC event weights"}; @@ -92,15 +93,17 @@ struct JetSpectraEseTask { Configurable fLeadJetPtCut{"fLeadJetPtCut", false, "Flag for leading jet pT cut"}; Configurable leadJetPtMin{"leadJetPtMin", 20.0, "minimum leading jet pT cut"}; - Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum eta acceptance for tracks"}; - Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum eta acceptance for tracks"}; - Configurable trackPtMin{"trackPtMin", 0.15, "minimum pT acceptance for tracks"}; - Configurable trackPtMax{"trackPtMax", 200.0, "maximum pT acceptance for tracks"}; - Configurable trackDCAzMax{"trackDCAzMax", 2.0, "maximum DCAz for tracks"}; - Configurable cfgNTPCXrows{"cfgNTPCXrows", 70, "minimum number of crossed rows in the TPC for tracks"}; - Configurable cfgNTPCCls{"cfgNTPCCls", 50, "minimum number of clusters in the TPC for tracks"}; - Configurable cfgChi2PrTPCcls{"cfgChi2PrTPCcls", 2.5, "cut for chi2 per TPC cluster for tracks"}; - Configurable cfgChi2PrITScls{"cfgChi2PrITScls", 36, "cut for chi2 per ITS cluster for tracks"}; + struct : ConfigurableGroup { + Configurable trackEtaMin{"trackEtaMin", -0.9, "minimum eta acceptance for tracks"}; + Configurable trackEtaMax{"trackEtaMax", 0.9, "maximum eta acceptance for tracks"}; + Configurable trackPtMin{"trackPtMin", 0.15, "minimum pT acceptance for tracks"}; + Configurable trackPtMax{"trackPtMax", 200.0, "maximum pT acceptance for tracks"}; + Configurable trackDCAzMax{"trackDCAzMax", 2.0, "maximum DCAz for tracks"}; + Configurable cfgNTPCXrows{"cfgNTPCXrows", 70, "minimum number of crossed rows in the TPC for tracks"}; + Configurable cfgNTPCCls{"cfgNTPCCls", 50, "minimum number of clusters in the TPC for tracks"}; + Configurable cfgChi2PrTPCcls{"cfgChi2PrTPCcls", 2.5, "cut for chi2 per TPC cluster for tracks"}; + Configurable cfgChi2PrITScls{"cfgChi2PrITScls", 36, "cut for chi2 per ITS cluster for tracks"}; + } trackCuts; Configurable> trackPtRhoPhi{"trackPtRhoPhi", {0.2, 5.0}, "pT range for tracks used in rho(phi) calculation"}; Configurable> cfgJetEta{"cfgJetEta", {-0.7, 0.7}, "jet eta range for analysis"}; @@ -146,6 +149,7 @@ struct JetSpectraEseTask { Configurable numberEventsMixed{"numberEventsMixed", 5, "number of events mixed in ME process"}; ConfigurableAxis binsCentrality{"binsCentrality", {VARIABLE_WIDTH, 0.0, 10., 30., 50, 70., 100.}, "Mixing bins - centrality"}; ConfigurableAxis binsZVtx{"binsZVtx", {VARIABLE_WIDTH, -10.0f, -2.5f, 2.5f, 10.0f}, "Mixing bins - z-vertex"}; + ConfigurableAxis amplitudeAxis{"amplitudeAxis", {5000, 0, 5000}, "Amplitude"}; Configurable applyRCTSelections{"applyRCTSelections", true, "apply RCT selections"}; Configurable skipMBGapEvents{"skipMBGapEvents", false, "flag to choose to reject min. bias gap events"}; @@ -187,7 +191,7 @@ struct JetSpectraEseTask { bool is3D = false; } cfg; - Filter trackCuts = (aod::jtrack::pt >= trackPtMin && aod::jtrack::pt < trackPtMax && aod::jtrack::eta > trackEtaMin && aod::jtrack::eta < trackEtaMax); + Filter filtertrackCuts = (aod::jtrack::pt >= trackCuts.trackPtMin && aod::jtrack::pt < trackCuts.trackPtMax && aod::jtrack::eta > trackCuts.trackEtaMin && aod::jtrack::eta < trackCuts.trackEtaMax); Filter jetCuts = aod::jet::pt > jetPtMin&& aod::jet::r == nround(jetR.node() * RScale) && nabs(aod::jet::eta) < EtaAcceptance - jetR; Filter colFilter = nabs(aod::jcollision::posZ) < LooseVertexZFilter; Filter mcCollisionFilter = nabs(aod::jmccollision::posZ) < LooseVertexZFilter; @@ -199,8 +203,12 @@ struct JetSpectraEseTask { using ETracks = soa::Join; SliceCache cache; - using BinningType = ColumnBinningPolicy; - BinningType corrBinning{{binsZVtx, binsCentrality}, true}; + using BinningTypeFT0C = ColumnBinningPolicy; + using BinningTypeFT0M = ColumnBinningPolicy; + using BinningTypeFT0CVariant1 = ColumnBinningPolicy; + BinningTypeFT0C corrBinningFT0C{{binsZVtx, binsCentrality}, true}; + BinningTypeFT0M corrBinningFT0M{{binsZVtx, binsCentrality}, true}; + BinningTypeFT0CVariant1 corrBinningFT0CVariant1{{binsZVtx, binsCentrality}, true}; Service pdg{}; enum class DetID { FT0C, @@ -211,6 +219,12 @@ struct JetSpectraEseTask { TPCneg, TPCall }; + enum class CentralityEstimator { FT0C, + FT0M, + FT0CVariant1 }; + + CentralityEstimator centralityEstimator = CentralityEstimator::FT0M; + struct EventPlane { float psi2; float psi3; @@ -242,12 +256,12 @@ struct JetSpectraEseTask { void applySystematicPreset() { systCuts.vertexZCut = vertexZCut.value; - systCuts.trackDCAzMax = trackDCAzMax.value; + systCuts.trackDCAzMax = trackCuts.trackDCAzMax.value; systCuts.dcaXYSigmaMax = NoDCAxySigmaCut; - systCuts.nTPCXrows = cfgNTPCXrows.value; - systCuts.nTPCCls = cfgNTPCCls.value; - systCuts.chi2PrTPCcls = cfgChi2PrTPCcls.value; - systCuts.chi2PrITScls = cfgChi2PrITScls.value; + systCuts.nTPCXrows = trackCuts.cfgNTPCXrows.value; + systCuts.nTPCCls = trackCuts.cfgNTPCCls.value; + systCuts.chi2PrTPCcls = trackCuts.cfgChi2PrTPCcls.value; + systCuts.chi2PrITScls = trackCuts.cfgChi2PrITScls.value; const int flag = cfgSystFlag.value; if (flag < 0) { @@ -313,10 +327,35 @@ struct JetSpectraEseTask { return std::abs(collision.posZ()) < systCuts.vertexZCut; } + template + float getCentrality(TCollision const& collision) const + { + switch (centralityEstimator) { + case CentralityEstimator::FT0C: + return collision.centFT0C(); + case CentralityEstimator::FT0M: + return collision.centFT0M(); + case CentralityEstimator::FT0CVariant1: + return collision.centFT0CVariant1(); + } + return -1.0f; + } + void init(o2::framework::InitContext&) { applySystematicPreset(); + const std::string centralityName = cfgCentrality; + if (centralityName == "FT0C") { + centralityEstimator = CentralityEstimator::FT0C; + } else if (centralityName == "FT0M") { + centralityEstimator = CentralityEstimator::FT0M; + } else if (centralityName == "FT0CVariant1") { + centralityEstimator = CentralityEstimator::FT0CVariant1; + } else { + LOGF(fatal, "JetSpectraEseTask::init() - invalid cfgCentrality='%s'; expected FT0C, FT0M, or FT0CVariant1", centralityName.c_str()); + } + ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); @@ -489,6 +528,8 @@ struct JetSpectraEseTask { registry.addClone("eventQA/hPsi2FT0C", "eventQA/hEPTwistV2"); registry.add("eventQA/h3Centq2FT0Cq2FT0A", ";Centrality;#it{q}_{2}^{FT0C};#it{q}_{2}^{FT0A}", {HistType::kTH3F, {{centAxis}, {250, 0, 35}, {250, 0, 35}}}); + + registry.add("eventQA/h2FT0AchannelAmplitude", ";channelID;amplitude", {HistType::kTH2F, {{100, 0, 100}, {amplitudeAxis}}}); } if (doprocessESEBackground) { LOGF(info, "JetSpectraEseTask::init() - Background Process"); @@ -632,7 +673,7 @@ struct JetSpectraEseTask { double eff{1.0}; if (cfg.is3D) { if (cfg.h3Eff) { - eff = cfg.h3Eff->GetBinContent(cfg.h3Eff->FindBin(track.pt(), track.eta(), vtxZ)); + eff = cfg.h3Eff->GetBinContent(cfg.h3Eff->FindBin(track.pt(), vtxZ, track.eta())); } } else { if (cfg.hEff) { @@ -657,7 +698,7 @@ struct JetSpectraEseTask { TTracks const& tracks) { - auto centrality = cfgCentVariant ? collision.centFT0CVariant1() : collision.centFT0M(); + auto centrality = getCentrality(collision); if (cfgSelCentrality && !isCentralitySelected(centrality)) { return; } @@ -691,7 +732,7 @@ struct JetSpectraEseTask { auto corrL = [&](const auto& j) { return j.pt() - evalRho(rhoFit.get(), jetR, j.phi(), collision.rho()) * j.area(); }; for (const auto& jet : jets) { - if (!jetfindingutilities::isInEtaAcceptance(jet, cfgJetEta->at(0), cfgJetEta->at(1), trackEtaMin, trackEtaMax)) { + if (!jetfindingutilities::isInEtaAcceptance(jet, cfgJetEta->at(0), cfgJetEta->at(1), trackCuts.trackEtaMin, trackCuts.trackEtaMax)) { continue; } // if (!isAcceptedJet(jet)) { @@ -769,13 +810,14 @@ struct JetSpectraEseTask { } } - template - void jetMixed(TCollisions const& collisions, - TJets const& jets, - TTracks const& tracks) + template + void jetMixedWithBinning(TBinning const& corrBinning, + TCollisions const& collisions, + TJets const& jets, + TTracks const& tracks) { auto tracksTuple = std::make_tuple(jets, tracks); - Pair pairData{corrBinning, numberEventsMixed, -1, collisions, tracksTuple, &cache}; + Pair pairData{corrBinning, numberEventsMixed, -1, collisions, tracksTuple, &cache}; for (const auto& [c1, jets1, c2, tracks2] : pairData) { auto bc = c2.template bc_as(); @@ -805,11 +847,11 @@ struct JetSpectraEseTask { } registry.fill(HIST("eventQA/hEventCounterMixed"), kOccupancyCut); - auto centrality = cfgCentVariant ? c1.centFT0CVariant1() : c1.centFT0M(); + auto centrality = getCentrality(c1); if (cfgSelCentrality && !isCentralitySelected(centrality)) { continue; } - auto centrality2 = cfgCentVariant ? c2.centFT0CVariant1() : c2.centFT0M(); + auto centrality2 = getCentrality(c2); if (cfgSelCentrality && !isCentralitySelected(centrality2)) { continue; } @@ -830,7 +872,7 @@ struct JetSpectraEseTask { } registry.fill(HIST("eventQA/hEventCounterMixed"), kRhoLocal); if (fLeadJetPtCut) { - if (!isAcceptedLeadingJet(c1, jets, centrality)) { + if (!isAcceptedLeadingJet(c1, jets1, centrality)) { return; } } @@ -844,7 +886,7 @@ struct JetSpectraEseTask { auto corrL = [&](const auto& j) { return j.pt() - evalRho(rhoFit.get(), jetR, j.phi(), c1.rho()) * j.area(); }; for (const auto& jet : jets1) { - if (!jetfindingutilities::isInEtaAcceptance(jet, cfgJetEta->at(0), cfgJetEta->at(1), trackEtaMin, trackEtaMax)) { + if (!jetfindingutilities::isInEtaAcceptance(jet, cfgJetEta->at(0), cfgJetEta->at(1), trackCuts.trackEtaMin, trackCuts.trackEtaMax)) { continue; } if (!isAcceptedJet>(jet)) { @@ -893,6 +935,24 @@ struct JetSpectraEseTask { } } + template + void jetMixed(TCollisions const& collisions, + TJets const& jets, + TTracks const& tracks) + { + switch (centralityEstimator) { + case CentralityEstimator::FT0C: + jetMixedWithBinning(corrBinningFT0C, collisions, jets, tracks); + break; + case CentralityEstimator::FT0M: + jetMixedWithBinning(corrBinningFT0M, collisions, jets, tracks); + break; + case CentralityEstimator::FT0CVariant1: + jetMixedWithBinning(corrBinningFT0CVariant1, collisions, jets, tracks); + break; + } + } + void processESEDataCharged(soa::Join::iterator const& collision, soa::Filtered> const& jets, soa::Join const& tracks, aod::JBCs const&, ETracks const&) @@ -926,9 +986,12 @@ struct JetSpectraEseTask { } PROCESS_SWITCH(JetSpectraEseTask, processESEDataChargedMixed, "process ese mixed collisions", false); - void processESEEPData(soa::Join::iterator const& collision, + using OgCol = soa::Join; + void processESEEPData(soa::Join::iterator const& collision, soa::Filtered const&, - aod::JetTracks const&) + aod::JetTracks const&, + OgCol const&, + aod::FT0s const&) { if (!isVertexSelected(collision)) { @@ -945,6 +1008,10 @@ struct JetSpectraEseTask { [[maybe_unused]] const auto psi{procEP(collision)}; detCorrelation(collision); + auto originalCollision = + collision.collision_as(); + + ft0Amplitude(collision, originalCollision); } PROCESS_SWITCH(JetSpectraEseTask, processESEEPData, "process ese collisions for filling EP and EPR", false); @@ -965,8 +1032,8 @@ struct JetSpectraEseTask { const auto qPerc{collision.qPERCFT0C()}; auto occupancy{collision.trackOccupancyInTimeRange()}; - registry.fill(HIST("hPsiOccupancy"), collision.centFT0M(), psi.psi2, occupancy); - registry.fill(HIST("hOccupancy"), collision.centFT0M(), occupancy); + registry.fill(HIST("hPsiOccupancy"), getCentrality(collision), psi.psi2, occupancy); + registry.fill(HIST("hOccupancy"), getCentrality(collision), occupancy); if (!isVertexSelected(collision)) { return; @@ -976,29 +1043,29 @@ struct JetSpectraEseTask { return; } registry.fill(HIST("hEventCounterOcc"), count++); - registry.fill(HIST("hOccupancyEv"), collision.centFT0M(), occupancy); + registry.fill(HIST("hOccupancyEv"), getCentrality(collision), occupancy); for (auto const& track : tracks) { if (!jetderiveddatautilities::selectTrack(track, trackSelection)) { continue; } - registry.fill(HIST("hTrackPt"), collision.centFT0M(), track.pt(), qPerc[0], occupancy); - registry.fill(HIST("hSTrackPtPhiEtaOcc"), collision.centFT0M(), track.pt(), track.phi(), track.eta(), occupancy); + registry.fill(HIST("hTrackPt"), getCentrality(collision), track.pt(), qPerc[0], occupancy); + registry.fill(HIST("hSTrackPtPhiEtaOcc"), getCentrality(collision), track.pt(), track.phi(), track.eta(), occupancy); if (track.pt() < cfgOccupancyPtCut->at(0) || track.pt() > cfgOccupancyPtCut->at(1)) { continue; } - registry.fill(HIST("hTrackEta"), collision.centFT0M(), track.eta(), occupancy); - registry.fill(HIST("hTrackPhi"), collision.centFT0M(), track.phi(), occupancy); + registry.fill(HIST("hTrackEta"), getCentrality(collision), track.eta(), occupancy); + registry.fill(HIST("hTrackPhi"), getCentrality(collision), track.phi(), occupancy); } for (const auto& jet : jets) { - if (!jetfindingutilities::isInEtaAcceptance(jet, cfgJetEta->at(0), cfgJetEta->at(1), trackEtaMin, trackEtaMax)) { + if (!jetfindingutilities::isInEtaAcceptance(jet, cfgJetEta->at(0), cfgJetEta->at(1), trackCuts.trackEtaMin, trackCuts.trackEtaMax)) { continue; } if (!isAcceptedJet(jet)) { continue; } - registry.fill(HIST("hSJetPtPhiEtaOcc"), collision.centFT0M(), jet.pt(), jet.phi(), jet.eta(), occupancy); + registry.fill(HIST("hSJetPtPhiEtaOcc"), getCentrality(collision), jet.pt(), jet.phi(), jet.eta(), occupancy); } } PROCESS_SWITCH(JetSpectraEseTask, processESEOccupancy, "process occupancy", false); @@ -1024,7 +1091,7 @@ struct JetSpectraEseTask { bool eventSel = true; for (const auto& col : collisions) { if (cfgisPbPb) - centrality = col.centFT0M(); + centrality = getCentrality(col); if (cfgEvSelOccupancy && !isOccupancyAccepted(col)) fOccupancy = false; if (!jetderiveddatautilities::selectCollision(col, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) @@ -1071,7 +1138,7 @@ struct JetSpectraEseTask { } registry.fill(HIST("mcd/hEventCounter"), counter++); - auto centrality = cfgisPbPb ? collision.centFT0M() : -1; + auto centrality = cfgisPbPb ? getCentrality(collision) : -1; registry.fill(HIST("mcd/hCentralitySel"), centrality); jetLoopMCD(mcdjets, centrality, collision.rho()); @@ -1118,7 +1185,7 @@ struct JetSpectraEseTask { } registry.fill(HIST("mcm/hMCDMatchedEventCounter"), secCount++); - auto centrality = cfgisPbPb ? collision.centFT0M() : -1; + auto centrality = cfgisPbPb ? getCentrality(collision) : -1; if (cfgisPbPb) if (centrality < centRange->at(0) || centrality > centRange->at(1)) registry.fill(HIST("mcm/hMCDMatchedEventCounter"), secCount++); @@ -1167,7 +1234,7 @@ struct JetSpectraEseTask { return; } - auto centrality = cfgisPbPb ? collision.centFT0M() : -1.0f; + auto centrality = cfgisPbPb ? getCentrality(collision) : -1.0f; if (cfgSelCentrality && cfgisPbPb && !isCentralitySelected(centrality)) { return; } @@ -1182,10 +1249,10 @@ struct JetSpectraEseTask { if (!particle.isPhysicalPrimary()) { continue; } - if (particle.pt() < trackPtMin || particle.pt() >= trackPtMax) { + if (particle.pt() < trackCuts.trackPtMin || particle.pt() >= trackCuts.trackPtMax) { continue; } - if (particle.eta() <= trackEtaMin || particle.eta() >= trackEtaMax) { + if (particle.eta() <= trackCuts.trackEtaMin || particle.eta() >= trackCuts.trackEtaMax) { continue; } @@ -1223,7 +1290,7 @@ struct JetSpectraEseTask { continue; } - auto centrality = cfgisPbPb ? collision.centFT0M() : -1.0f; + auto centrality = cfgisPbPb ? getCentrality(collision) : -1.0f; if (cfgSelCentrality && cfgisPbPb && !isCentralitySelected(centrality)) { continue; } @@ -1247,10 +1314,10 @@ struct JetSpectraEseTask { if (!particle.isPhysicalPrimary()) { continue; } - if (particle.pt() < trackPtMin || particle.pt() >= trackPtMax) { + if (particle.pt() < trackCuts.trackPtMin || particle.pt() >= trackCuts.trackPtMax) { continue; } - if (particle.eta() <= trackEtaMin || particle.eta() >= trackEtaMax) { + if (particle.eta() <= trackCuts.trackEtaMin || particle.eta() >= trackCuts.trackEtaMax) { continue; } if (std::find(seenMcParticles.begin(), seenMcParticles.end(), particle.globalIndex()) != seenMcParticles.end()) { @@ -1285,7 +1352,7 @@ struct JetSpectraEseTask { auto redFT0C = redqn(qC); auto redFT0A = redqn(qA); - registry.fill(HIST("eventQA/h3Centq2FT0Cq2FT0A"), col.centFT0M(), redFT0C, redFT0A); + registry.fill(HIST("eventQA/h3Centq2FT0Cq2FT0A"), getCentrality(col), redFT0C, redFT0A); } static constexpr float InvalidValue = 999.; @@ -1343,36 +1410,36 @@ struct JetSpectraEseTask { template void fillEPCos(const collision& col, const std::array& Corr22, const std::array& Corr42, const std::array& Corr44) { - registry.fill(HIST("eventQA/hCos2Psi2AmC"), col.centFT0M(), Corr22[0], col.qPERCFT0C()[0]); - registry.fill(HIST("eventQA/hCos2Psi2AmB"), col.centFT0M(), Corr22[1], col.qPERCFT0C()[0]); - registry.fill(HIST("eventQA/hCos2Psi2BmC"), col.centFT0M(), Corr22[2], col.qPERCFT0C()[0]); + registry.fill(HIST("eventQA/hCos2Psi2AmC"), getCentrality(col), Corr22[0], col.qPERCFT0C()[0]); + registry.fill(HIST("eventQA/hCos2Psi2AmB"), getCentrality(col), Corr22[1], col.qPERCFT0C()[0]); + registry.fill(HIST("eventQA/hCos2Psi2BmC"), getCentrality(col), Corr22[2], col.qPERCFT0C()[0]); - registry.fill(HIST("eventQA/hCos4Psi2AmC"), col.centFT0M(), Corr42[0], col.qPERCFT0C()[0]); - registry.fill(HIST("eventQA/hCos4Psi2AmB"), col.centFT0M(), Corr42[1], col.qPERCFT0C()[0]); - registry.fill(HIST("eventQA/hCos4Psi2BmC"), col.centFT0M(), Corr42[2], col.qPERCFT0C()[0]); + registry.fill(HIST("eventQA/hCos4Psi2AmC"), getCentrality(col), Corr42[0], col.qPERCFT0C()[0]); + registry.fill(HIST("eventQA/hCos4Psi2AmB"), getCentrality(col), Corr42[1], col.qPERCFT0C()[0]); + registry.fill(HIST("eventQA/hCos4Psi2BmC"), getCentrality(col), Corr42[2], col.qPERCFT0C()[0]); - registry.fill(HIST("eventQA/hCos4Psi4AmC"), col.centFT0M(), Corr44[0], col.qPERCFT0C()[0]); - registry.fill(HIST("eventQA/hCos4Psi4AmB"), col.centFT0M(), Corr44[1], col.qPERCFT0C()[0]); - registry.fill(HIST("eventQA/hCos4Psi4BmC"), col.centFT0M(), Corr44[2], col.qPERCFT0C()[0]); + registry.fill(HIST("eventQA/hCos4Psi4AmC"), getCentrality(col), Corr44[0], col.qPERCFT0C()[0]); + registry.fill(HIST("eventQA/hCos4Psi4AmB"), getCentrality(col), Corr44[1], col.qPERCFT0C()[0]); + registry.fill(HIST("eventQA/hCos4Psi4BmC"), getCentrality(col), Corr44[2], col.qPERCFT0C()[0]); } template void fillEP(const collision& col, const std::map& epMap, const std::map& ep3Map, const std::map& ep4Map) { - registry.fill(HIST("eventQA/hPsi2FT0A"), col.centFT0M(), epMap.at("FT0A")); - registry.fill(HIST("eventQA/hPsi2FV0A"), col.centFT0M(), epMap.at("FV0A")); - registry.fill(HIST("eventQA/hPsi2FT0C"), col.centFT0M(), epMap.at("FT0C")); - registry.fill(HIST("eventQA/hPsi2TPCpos"), col.centFT0M(), epMap.at("TPCpos")); - registry.fill(HIST("eventQA/hPsi2TPCneg"), col.centFT0M(), epMap.at("TPCneg")); - - registry.fill(HIST("eventQA/hPsi3FT0A"), col.centFT0M(), ep3Map.at("FT0A")); - registry.fill(HIST("eventQA/hPsi3FT0C"), col.centFT0M(), ep3Map.at("FT0C")); - - registry.fill(HIST("eventQA/hPsi4FT0A"), col.centFT0M(), ep4Map.at("FT0A")); - registry.fill(HIST("eventQA/hPsi4FT0C"), col.centFT0M(), ep4Map.at("FT0C")); - registry.fill(HIST("eventQA/hPsi4FV0A"), col.centFT0M(), ep4Map.at("FV0A")); - registry.fill(HIST("eventQA/hPsi4TPCpos"), col.centFT0M(), ep4Map.at("TPCpos")); - registry.fill(HIST("eventQA/hPsi4TPCneg"), col.centFT0M(), ep4Map.at("TPCneg")); + registry.fill(HIST("eventQA/hPsi2FT0A"), getCentrality(col), epMap.at("FT0A")); + registry.fill(HIST("eventQA/hPsi2FV0A"), getCentrality(col), epMap.at("FV0A")); + registry.fill(HIST("eventQA/hPsi2FT0C"), getCentrality(col), epMap.at("FT0C")); + registry.fill(HIST("eventQA/hPsi2TPCpos"), getCentrality(col), epMap.at("TPCpos")); + registry.fill(HIST("eventQA/hPsi2TPCneg"), getCentrality(col), epMap.at("TPCneg")); + + registry.fill(HIST("eventQA/hPsi3FT0A"), getCentrality(col), ep3Map.at("FT0A")); + registry.fill(HIST("eventQA/hPsi3FT0C"), getCentrality(col), ep3Map.at("FT0C")); + + registry.fill(HIST("eventQA/hPsi4FT0A"), getCentrality(col), ep4Map.at("FT0A")); + registry.fill(HIST("eventQA/hPsi4FT0C"), getCentrality(col), ep4Map.at("FT0C")); + registry.fill(HIST("eventQA/hPsi4FV0A"), getCentrality(col), ep4Map.at("FV0A")); + registry.fill(HIST("eventQA/hPsi4TPCpos"), getCentrality(col), ep4Map.at("TPCpos")); + registry.fill(HIST("eventQA/hPsi4TPCneg"), getCentrality(col), ep4Map.at("TPCneg")); } constexpr int detIDN(const DetID id) { @@ -1403,13 +1470,13 @@ struct JetSpectraEseTask { int detInd{detId * 4 + cfgnTotalSystem * 4 * (nmode - 2)}; if constexpr (fill) { if (collision.qvecAmp()[detInd] > LowFT0Cut && nmode == SecondHarmonic) { - registry.fill(HIST("eventQA/hQvecUncorV2"), collision.centFT0M(), collision.qvecRe()[detInd], collision.qvecIm()[detInd]); - registry.fill(HIST("eventQA/hQvecRectrV2"), collision.centFT0M(), collision.qvecRe()[detInd + 1], collision.qvecIm()[detInd + 1]); - registry.fill(HIST("eventQA/hQvecTwistV2"), collision.centFT0M(), collision.qvecRe()[detInd + 2], collision.qvecIm()[detInd + 2]); - registry.fill(HIST("eventQA/hQvecFinalV2"), collision.centFT0M(), collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3]); - registry.fill(HIST("eventQA/hEPUncorV2"), collision.centFT0M(), 0.5 * std::atan2(collision.qvecIm()[detInd], collision.qvecRe()[detInd])); - registry.fill(HIST("eventQA/hEPRectrV2"), collision.centFT0M(), 0.5 * std::atan2(collision.qvecIm()[detInd + 1], collision.qvecRe()[detInd + 1])); - registry.fill(HIST("eventQA/hEPTwistV2"), collision.centFT0M(), 0.5 * std::atan2(collision.qvecIm()[detInd + 2], collision.qvecRe()[detInd + 2])); + registry.fill(HIST("eventQA/hQvecUncorV2"), getCentrality(collision), collision.qvecRe()[detInd], collision.qvecIm()[detInd]); + registry.fill(HIST("eventQA/hQvecRectrV2"), getCentrality(collision), collision.qvecRe()[detInd + 1], collision.qvecIm()[detInd + 1]); + registry.fill(HIST("eventQA/hQvecTwistV2"), getCentrality(collision), collision.qvecRe()[detInd + 2], collision.qvecIm()[detInd + 2]); + registry.fill(HIST("eventQA/hQvecFinalV2"), getCentrality(collision), collision.qvecRe()[detInd + 3], collision.qvecIm()[detInd + 3]); + registry.fill(HIST("eventQA/hEPUncorV2"), getCentrality(collision), 0.5 * std::atan2(collision.qvecIm()[detInd], collision.qvecRe()[detInd])); + registry.fill(HIST("eventQA/hEPRectrV2"), getCentrality(collision), 0.5 * std::atan2(collision.qvecIm()[detInd + 1], collision.qvecRe()[detInd + 1])); + registry.fill(HIST("eventQA/hEPTwistV2"), getCentrality(collision), 0.5 * std::atan2(collision.qvecIm()[detInd + 2], collision.qvecRe()[detInd + 2])); } } std::vector qVec{}; @@ -1450,6 +1517,27 @@ struct JetSpectraEseTask { } } + template + void ft0Amplitude(const JetCol& coll, const OriginalCol& originalColl) + { + if (!originalColl.has_foundFT0()) { + return; + } + + auto ft0 = originalColl.foundFT0(); + auto centrality = getCentrality(coll); + + if (cfgSelCentrality && !isCentralitySelected(centrality)) { + return; + } + + for (std::size_t iChA = 0; iChA < ft0.channelA().size(); ++iChA) { + float ampl = ft0.amplitudeA()[iChA]; + int ft0AchId = ft0.channelA()[iChA]; + registry.fill(HIST("eventQA/h2FT0AchannelAmplitude"), ft0AchId, ampl); + } + } + template std::unique_ptr fitRho(const Col& col, const EventPlane& ep, TTracks const& tracks, Jets const& jets) { @@ -1504,11 +1592,11 @@ struct JetSpectraEseTask { hPhiPt->Fit(modulationFit.get(), "QN", "", 0, o2::constants::math::TwoPI); if constexpr (fillHist) { - registry.fill(HIST("eventQA/hfitPar0"), col.centFT0M(), modulationFit->GetParameter(0)); - registry.fill(HIST("eventQA/hfitPar1"), col.centFT0M(), modulationFit->GetParameter(1)); - registry.fill(HIST("eventQA/hfitPar2"), col.centFT0M(), modulationFit->GetParameter(2)); - registry.fill(HIST("eventQA/hfitPar3"), col.centFT0M(), modulationFit->GetParameter(3)); - registry.fill(HIST("eventQA/hfitPar4"), col.centFT0M(), modulationFit->GetParameter(4)); + registry.fill(HIST("eventQA/hfitPar0"), getCentrality(col), modulationFit->GetParameter(0)); + registry.fill(HIST("eventQA/hfitPar1"), getCentrality(col), modulationFit->GetParameter(1)); + registry.fill(HIST("eventQA/hfitPar2"), getCentrality(col), modulationFit->GetParameter(2)); + registry.fill(HIST("eventQA/hfitPar3"), getCentrality(col), modulationFit->GetParameter(3)); + registry.fill(HIST("eventQA/hfitPar4"), getCentrality(col), modulationFit->GetParameter(4)); } if (modulationFit->GetParameter(0) <= 0) { @@ -1545,8 +1633,8 @@ struct JetSpectraEseTask { } if constexpr (fillHist) { - registry.fill(HIST("eventQA/hPValueCentCDF"), col.centFT0M(), cDF); - registry.fill(HIST("eventQA/hCentChi2Ndf"), col.centFT0M(), chi2 / (static_cast(nDF))); + registry.fill(HIST("eventQA/hPValueCentCDF"), getCentrality(col), cDF); + registry.fill(HIST("eventQA/hCentChi2Ndf"), getCentrality(col), chi2 / (static_cast(nDF))); static int numSavedRhoFitEvents{0}; if (numSavedRhoFitEvents < NumSavedRhoFitEvents) { @@ -1630,7 +1718,7 @@ struct JetSpectraEseTask { } TRandom3 randomNumber(0); - float randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); + float randomConeEta = randomNumber.Uniform(trackCuts.trackEtaMin + randomConeR, trackCuts.trackEtaMax - randomConeR); float randomConePhi = randomNumber.Uniform(0.0, o2::constants::math::TwoPI); float randomConePt = 0; for (auto const& track : tracks) { @@ -1642,19 +1730,19 @@ struct JetSpectraEseTask { } } } - registry.fill(HIST("hCentRhoRandomCone"), collision.centFT0M(), randomConePt - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); + registry.fill(HIST("hCentRhoRandomCone"), getCentrality(collision), randomConePt - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); float randomConePtRandomTrackDir = 0; for (auto const& track : tracks) { if (jetderiveddatautilities::selectTrack(track, trackSelection)) { float dPhi = RecoDecay::constrainAngle(randomNumber.Uniform(0.0, o2::constants::math::TwoPI) - randomConePhi, -o2::constants::math::PI); - float dEta = randomNumber.Uniform(trackEtaMin, trackEtaMax) - randomConeEta; + float dEta = randomNumber.Uniform(trackCuts.trackEtaMin, trackCuts.trackEtaMax) - randomConeEta; if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { randomConePtRandomTrackDir += track.pt(); } } } - registry.fill(HIST("hCentRhoRandomConeRandomTrackDir"), collision.centFT0M(), randomConePtRandomTrackDir - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); + registry.fill(HIST("hCentRhoRandomConeRandomTrackDir"), getCentrality(collision), randomConePtRandomTrackDir - o2::constants::math::PI * randomConeR * randomConeR * collision.rho()); if (jets.size() > 0) { float dPhiLeadingJet = RecoDecay::constrainAngle(jets.iteratorAt(0).phi() - randomConePhi, -o2::constants::math::PI); @@ -1663,7 +1751,7 @@ struct JetSpectraEseTask { bool jetWasInCone = false; while ((randomConeLeadJetDeltaR <= 0 && (std::sqrt(dEtaLeadingJet * dEtaLeadingJet + dPhiLeadingJet * dPhiLeadingJet) < jets.iteratorAt(0).r() / 100.0 + randomConeR)) || (randomConeLeadJetDeltaR > 0 && (std::sqrt(dEtaLeadingJet * dEtaLeadingJet + dPhiLeadingJet * dPhiLeadingJet) < randomConeLeadJetDeltaR))) { jetWasInCone = true; - randomConeEta = randomNumber.Uniform(trackEtaMin + randomConeR, trackEtaMax - randomConeR); + randomConeEta = randomNumber.Uniform(trackCuts.trackEtaMin + randomConeR, trackCuts.trackEtaMax - randomConeR); randomConePhi = randomNumber.Uniform(0.0, o2::constants::math::TwoPI); dPhiLeadingJet = RecoDecay::constrainAngle(jets.iteratorAt(0).phi() - randomConePhi, -o2::constants::math::PI); dEtaLeadingJet = jets.iteratorAt(0).eta() - randomConeEta; @@ -1691,7 +1779,7 @@ struct JetSpectraEseTask { rho = evalRho(rhoFit.get(), randomConeR, randomConePhi, rho); } float dPhiRC{RecoDecay::constrainAngle(randomConePhi - psi.psi2, -o2::constants::math::PI)}; - registry.fill(HIST("hCentRhoRandomConewoLeadingJet"), collision.centFT0M(), randomConePt - o2::constants::math::PI * randomConeR * randomConeR * rho, dPhiRC, qPerc[0]); + registry.fill(HIST("hCentRhoRandomConewoLeadingJet"), getCentrality(collision), randomConePt - o2::constants::math::PI * randomConeR * randomConeR * rho, dPhiRC, qPerc[0]); double randomConePtWithoutOneLeadJet = 0; double randomConePtWithoutTwoLeadJet = 0; @@ -1699,7 +1787,7 @@ struct JetSpectraEseTask { for (auto const& track : tracks) { if (jetderiveddatautilities::selectTrack(track, trackSelection)) { float dPhi = RecoDecay::constrainAngle(randomNumber.Uniform(0.0, o2::constants::math::TwoPI) - randomConePhi, -o2::constants::math::PI); - float dEta = randomNumber.Uniform(trackEtaMin, trackEtaMax) - randomConeEta; + float dEta = randomNumber.Uniform(trackCuts.trackEtaMin, trackCuts.trackEtaMax) - randomConeEta; if (std::sqrt(dEta * dEta + dPhi * dPhi) < randomConeR) { if (!isTrackInJet(track, jets.iteratorAt(0))) { randomConePtWithoutOneLeadJet += track.pt(); @@ -1711,10 +1799,10 @@ struct JetSpectraEseTask { } } } - registry.fill(HIST("h3CentdeltapTRndmConePhi_rhovsphi"), collision.centFT0M(), randomConePt - o2::constants::math::PI * randomConeR * randomConeR * collision.rho(), dPhiRC); - registry.fill(HIST("h3CentdeltapTRndmConePhi_localrhovsphi"), collision.centFT0M(), randomConePt - o2::constants::math::PI * randomConeR * randomConeR * rho, dPhiRC); - registry.fill(HIST("hCentRhoRandomConeRndTrackDirwoOneLeadingJet"), collision.centFT0M(), randomConePtWithoutOneLeadJet - o2::constants::math::PI * randomConeR * randomConeR * rho, dPhiRC, qPerc[0]); - registry.fill(HIST("hCentRhoRandomConeRndTrackDirwoTwoLeadingJet"), collision.centFT0M(), randomConePtWithoutTwoLeadJet - o2::constants::math::PI * randomConeR * randomConeR * rho, dPhiRC, qPerc[0]); + registry.fill(HIST("h3CentdeltapTRndmConePhi_rhovsphi"), getCentrality(collision), randomConePt - o2::constants::math::PI * randomConeR * randomConeR * collision.rho(), dPhiRC); + registry.fill(HIST("h3CentdeltapTRndmConePhi_localrhovsphi"), getCentrality(collision), randomConePt - o2::constants::math::PI * randomConeR * randomConeR * rho, dPhiRC); + registry.fill(HIST("hCentRhoRandomConeRndTrackDirwoOneLeadingJet"), getCentrality(collision), randomConePtWithoutOneLeadJet - o2::constants::math::PI * randomConeR * randomConeR * rho, dPhiRC, qPerc[0]); + registry.fill(HIST("hCentRhoRandomConeRndTrackDirwoTwoLeadingJet"), getCentrality(collision), randomConePtWithoutTwoLeadJet - o2::constants::math::PI * randomConeR * randomConeR * rho, dPhiRC, qPerc[0]); } template bool isTrackInJet(TTracks const& track, TJets const& jet) @@ -1742,7 +1830,7 @@ struct JetSpectraEseTask { { float weight = 1.0; for (const auto& jet : jets) { - if (!jetfindingutilities::isInEtaAcceptance(jet, cfgJetEta->at(0), cfgJetEta->at(1), trackEtaMin, trackEtaMax)) { + if (!jetfindingutilities::isInEtaAcceptance(jet, cfgJetEta->at(0), cfgJetEta->at(1), trackCuts.trackEtaMin, trackCuts.trackEtaMax)) { continue; } if (!isAcceptedJet(jet)) { @@ -1768,7 +1856,7 @@ struct JetSpectraEseTask { { bool mcLevelIsParticleLevel = true; for (const auto& jet : jets) { - if (!jetfindingutilities::isInEtaAcceptance(jet, cfgJetEta->at(0), cfgJetEta->at(1), trackEtaMin, trackEtaMax)) { + if (!jetfindingutilities::isInEtaAcceptance(jet, cfgJetEta->at(0), cfgJetEta->at(1), trackCuts.trackEtaMin, trackCuts.trackEtaMax)) { continue; } if (!isAcceptedJet(jet, mcLevelIsParticleLevel)) { @@ -1789,7 +1877,7 @@ struct JetSpectraEseTask { void matchedJetLoop(const Jets& jets, const float& centrality, const float& rho, const float& rho2, float weight = 1.0, float pTHat = 999.0) { for (const auto& jet : jets) { - if (!jetfindingutilities::isInEtaAcceptance(jet, cfgJetEta->at(0), cfgJetEta->at(1), trackEtaMin, trackEtaMax)) { + if (!jetfindingutilities::isInEtaAcceptance(jet, cfgJetEta->at(0), cfgJetEta->at(1), trackCuts.trackEtaMin, trackCuts.trackEtaMax)) { continue; } if (!isAcceptedJet(jet)) { @@ -1835,7 +1923,7 @@ struct JetSpectraEseTask { float leadJetEta = -999; bool hasLeadingJet = false; for (const auto& jet : jets) { - if (!jetfindingutilities::isInEtaAcceptance(jet, cfgJetEta->at(0), cfgJetEta->at(1), trackEtaMin, trackEtaMax)) { + if (!jetfindingutilities::isInEtaAcceptance(jet, cfgJetEta->at(0), cfgJetEta->at(1), trackCuts.trackEtaMin, trackCuts.trackEtaMax)) { continue; } if (!isAcceptedJet>(jet)) { @@ -1876,10 +1964,10 @@ struct JetSpectraEseTask { template bool isTrackSelected(TTrack const& track) { - if (track.pt() < trackPtMin || track.pt() >= trackPtMax) { + if (track.pt() < trackCuts.trackPtMin || track.pt() >= trackCuts.trackPtMax) { return false; } - if (track.eta() <= trackEtaMin || track.eta() >= trackEtaMax) { + if (track.eta() <= trackCuts.trackEtaMin || track.eta() >= trackCuts.trackEtaMax) { return false; } if (track.tpcNClsCrossedRows() <= systCuts.nTPCXrows) { diff --git a/PWGJE/Tasks/jetSubstructureOutput.cxx b/PWGJE/Tasks/jetSubstructureOutput.cxx index 954214c7226..6dd90638faa 100644 --- a/PWGJE/Tasks/jetSubstructureOutput.cxx +++ b/PWGJE/Tasks/jetSubstructureOutput.cxx @@ -308,7 +308,7 @@ struct JetSubstructureOutputTask { void processClearMapsMCP(aod::JetMcCollisions const& mcCollisions) { jetMappingMCP.clear(); - for (auto mcCollision : mcCollisions) { + for (const auto& mcCollision : mcCollisions) { mcCollisionOutputTable(mcCollision.posZ(), mcCollision.accepted(), mcCollision.attempted(), mcCollision.xsectGen(), mcCollision.xsectErr(), mcCollision.weight()); } } diff --git a/PWGJE/Tasks/jetTutorial.cxx b/PWGJE/Tasks/jetTutorial.cxx index 828a23a86ce..2c5e011ccc4 100644 --- a/PWGJE/Tasks/jetTutorial.cxx +++ b/PWGJE/Tasks/jetTutorial.cxx @@ -335,7 +335,7 @@ struct JetTutorialTask { if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } - for (auto jet : jets) { + for (const auto& jet : jets) { registry.fill(HIST("h_jet_pt"), jet.pt()); registry.fill(HIST("h_jet_pt_rhosub"), jet.pt() - (collision.rho() * jet.area())); registry.fill(HIST("h_jet_eta"), jet.eta()); @@ -349,7 +349,7 @@ struct JetTutorialTask { if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } - for (auto jet : jets) { + for (const auto& jet : jets) { registry.fill(HIST("h_jet_pt_constsub"), jet.pt()); registry.fill(HIST("h_jet_eta"), jet.eta()); registry.fill(HIST("h_jet_phi"), jet.phi()); @@ -362,7 +362,7 @@ struct JetTutorialTask { if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits)) { return; } - for (auto jet : jets) { + for (const auto& jet : jets) { registry.fill(HIST("h_jet_pt_constsub"), jet.pt()); registry.fill(HIST("h_jet_eta"), jet.eta()); registry.fill(HIST("h_jet_phi"), jet.phi()); diff --git a/PWGJE/Tasks/jetValidationQA.cxx b/PWGJE/Tasks/jetValidationQA.cxx index 999a1feeaef..18942a5b59d 100644 --- a/PWGJE/Tasks/jetValidationQA.cxx +++ b/PWGJE/Tasks/jetValidationQA.cxx @@ -410,7 +410,7 @@ struct mcJetTrackCollisionQa { // fill qa histograms for selected tracks in collision template - void fillMcTrackHistos(ValidationTracks const& mct, coll collision, bool mc) // could give collision as argument for additional association + void fillMcTrackHistos(ValidationTracks const& mct, const coll& collision, bool mc) // could give collision as argument for additional association { for (const auto& track : mct) { if (!jetderiveddatautilities::selectTrack(track, trackSelection) || !(track.collisionId() == collision.globalIndex())) { diff --git a/PWGJE/Tasks/mcGeneratorStudies.cxx b/PWGJE/Tasks/mcGeneratorStudies.cxx index 1fd61f64bfc..fb7e2f081ec 100644 --- a/PWGJE/Tasks/mcGeneratorStudies.cxx +++ b/PWGJE/Tasks/mcGeneratorStudies.cxx @@ -224,7 +224,7 @@ struct MCGeneratorStudies { } template - bool isGammaGammaDecay(TMCParticle mcParticle, TMCParticles mcParticles) + bool isGammaGammaDecay(const TMCParticle& mcParticle, const TMCParticles& mcParticles) { auto daughtersIds = mcParticle.daughtersIds(); if (daughtersIds.size() != 2) @@ -237,7 +237,7 @@ struct MCGeneratorStudies { } template - bool isAccepted(TMCParticle mcParticle, TMCParticles mcParticles) + bool isAccepted(const TMCParticle& mcParticle, const TMCParticles& mcParticles) { auto daughtersIds = mcParticle.daughtersIds(); if (daughtersIds.size() != 2) diff --git a/PWGJE/Tasks/nucleiInJets.cxx b/PWGJE/Tasks/nucleiInJets.cxx index ab6554a4bb0..90cb39529ae 100644 --- a/PWGJE/Tasks/nucleiInJets.cxx +++ b/PWGJE/Tasks/nucleiInJets.cxx @@ -791,7 +791,7 @@ struct nucleiInJets { } template - bool isTrackSelectedWithoutDcaxy(const TrackType track) + bool isTrackSelectedWithoutDcaxy(const TrackType& track) { // standard track selection if (track.pt() < cfgtrkMinPt) @@ -822,7 +822,7 @@ struct nucleiInJets { } template - bool isTrackSelected(const TrackType track) + bool isTrackSelected(const TrackType& track) { if (!isTrackSelectedWithoutDcaxy(track)) return false; diff --git a/PWGJE/Tasks/phiInJets.cxx b/PWGJE/Tasks/phiInJets.cxx index 085da029904..0da2e153923 100644 --- a/PWGJE/Tasks/phiInJets.cxx +++ b/PWGJE/Tasks/phiInJets.cxx @@ -294,7 +294,7 @@ struct phiInJets { ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// template - bool trackSelection(const TrackType track) + bool trackSelection(const TrackType& track) { // basic track cuts if (track.pt() < cfgtrkMinPt) @@ -396,7 +396,7 @@ struct phiInJets { ///////////////////////////////////////////////////////////////////////////// template - double DistinguishJets(const JetType& jets, const TLorentzVector lResonance) + double DistinguishJets(const JetType& jets, const TLorentzVector& lResonance) { if (cDebugLevel > 0) std::cout << "oof, multiple jets fit to the same phi. Time to find the best phi-jet link" << std::endl; @@ -419,7 +419,7 @@ struct phiInJets { } template - double DistinguishJetsMC(const Jet_pt& jet_pt, const Jet_phi& jet_phi, const Jet_eta& jet_eta, const TLorentzVector lResonance) + double DistinguishJetsMC(const Jet_pt& jet_pt, const Jet_phi& jet_phi, const Jet_eta& jet_eta, const TLorentzVector& lResonance) { if (cDebugLevel > 0) std::cout << "oof, multiple jets fit to the same phi. Time to find the best phi-jet link" << std::endl; @@ -593,7 +593,7 @@ struct phiInJets { JEhistos.fill(HIST("hNResoPerEventInJet"), nResoInTrig); int nJets = 0; - for (auto chargedjet : chargedjets) { + for (const auto& chargedjet : chargedjets) { JEhistos.fill(HIST("FJetaHistogram"), chargedjet.eta()); JEhistos.fill(HIST("FJphiHistogram"), chargedjet.phi()); JEhistos.fill(HIST("FJptHistogram"), chargedjet.pt()); diff --git a/PWGJE/Tasks/photonIsolationQA.cxx b/PWGJE/Tasks/photonIsolationQA.cxx index 4f31995b218..d14e523d91e 100644 --- a/PWGJE/Tasks/photonIsolationQA.cxx +++ b/PWGJE/Tasks/photonIsolationQA.cxx @@ -269,7 +269,7 @@ struct PhotonIsolationQA { return Pt_Iso; } - void fillclusterhistos(const auto cluster, HistogramRegistry registry, double weight = 1.0) + void fillclusterhistos(const auto& cluster, HistogramRegistry registry, double weight = 1.0) { registry.fill(HIST("hClusterLocation"), cluster.eta(), cluster.phi()); if (isMC == true) { @@ -397,7 +397,7 @@ struct PhotonIsolationQA { // process monte carlo data void processMC(aod::BCs const& bcs, selectedMcCollisions const& Collisions, selectedMCClusters const& mcclusters, aod::McParticles const&, myGlobTracks const& tracks, o2::aod::EMCALMatchedTracks const& matchedtracks, aod::Calos const&, aod::EMCALClusterCells const& ClusterCells) { - for (auto bc : bcs) { + for (const auto& bc : bcs) { auto collisionsInBC = Collisions.sliceBy(McCollisionsPerBC, bc.globalIndex()); MC_Info.fill(HIST("hCollperBC"), collisionsInBC.size()); if (collisionsInBC.size() == 1) { @@ -461,7 +461,7 @@ struct PhotonIsolationQA { void processData(aod::BCs const& bcs, selectedCollisions const& Collisions, selectedClusters const& clusters, o2::aod::EMCALMatchedTracks const& matchedtracks, myGlobTracks const& tracks, aod::Calos const&, aod::EMCALClusterCells const& ClusterCells) { - for (auto bc : bcs) { + for (const auto& bc : bcs) { auto collisionsInBC = Collisions.sliceBy(collisionsPerBC, bc.globalIndex()); Data_Info.fill(HIST("hCollperBC"), collisionsInBC.size()); if (collisionsInBC.size() == 1) { diff --git a/PWGJE/Tasks/recoilJets.cxx b/PWGJE/Tasks/recoilJets.cxx index 1945e4e825a..ae3f5edebfc 100644 --- a/PWGJE/Tasks/recoilJets.cxx +++ b/PWGJE/Tasks/recoilJets.cxx @@ -203,20 +203,23 @@ struct RecoilJets { ConfigurableAxis axisPtTrackEff{"axisPtTrackEff", {VARIABLE_WIDTH, 0.0, 0.15, 0.2, 0.25, 0.3, 0.4, 0.5, 0.6, 0.8, 1.0, 1.2, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.0, 8.0, 10.0, 12.0, 15.0, 20.0, 25.0, 30.0, 40.0, 50.0, 70.0, 100.0}, "#it{p}_{T} (GeV/#it{c})"}; - ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, -5.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 55.0, 60.0, 65.0, 70.0, 75.0, 80.0, 85.0, 90.0, 95.0, 100.0, 105.0}, "Centrality (%)"}; + ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, -5.0, 0.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 55.0, 60.0, 65.0, 70.0, 75.0, 80.0, 85.0, 90.0, 95.0, 100.0, 105.0}, "Centrality (%)"}; } hist; // ---------- Rho-shift settings ---------- struct RhoShift : ConfigurableGroup { std::string prefix = "rhoShiftTTRef"; - Configurable mb{"mb", 0.283998f, "Rho shift for MB"}; - Configurable ea0To20{"ea0To20", 0.199249f, "Rho shift for EA 0-20%"}; - Configurable ea0To10{"ea0To10", 0.186661f, "Rho shift for EA 0-10%"}; - Configurable ea20To40{"ea20To40", 0.137945f, "Rho shift for EA 20-40%"}; - Configurable ea60To80{"ea60To80", 0.0962535f, "Rho shift for EA 60-80%"}; - Configurable ea50To100{"ea50To100", 0.106919f, "Rho shift for EA 50-100%"}; - Configurable ea80To100{"ea80To100", 0.0871301f, "Rho shift for EA 80-100%"}; + // Values from train 747883 + Configurable mb{"mb", 0.286292f, "Rho shift for MB"}; + Configurable ea0To20{"ea0To20", 0.189813f, "Rho shift for EA 0-20%"}; + Configurable ea0To10{"ea0To10", 0.180575f, "Rho shift for EA 0-10%"}; + Configurable ea20To40{"ea20To40", 0.131103f, "Rho shift for EA 20-40%"}; + Configurable ea60To80{"ea60To80", 0.092541f, "Rho shift for EA 60-80%"}; + Configurable ea50To100{"ea50To100", 0.106569f, "Rho shift for EA 50-100%"}; + Configurable ea80To100{"ea80To100", 0.0998433f, "Rho shift for EA 80-100%"}; + + Configurable mbPart{"mbPart", 0.0f, "Rho shift for MB part. level MC"}; } cfgRhoShift; // Auxiliary variables @@ -576,6 +579,10 @@ struct RecoilJets { kTH2F, {{centAxis.axis, centAxis.axisName}, scaledFT0M}, hist.sumw2); } + spectra.add("hCentFT0C_ScaledFT0C", + "Correlation of CentFT0C vs. scaled FT0C", + kTH2F, {{hist.axisCentrality, nameCentralityAxis}, scaledFT0C}, hist.sumw2); + // Register TTRef recoil spectra with rho-shift correction. for (const auto& ea : eaRhoShifts) { spectra.add(Form("h%s_Recoil_JetPt_Corr_RhoShifted_TTRef", ea.label), @@ -767,6 +774,15 @@ struct RecoilJets { Form("MC events w. TT_{Sig}: %s & #it{p}_{T} of recoil jets", centAxis.label), kTH2F, {{centAxis.axis, centAxis.axisName}, jetPTcorrFinnerBin}, hist.sumw2); } + + // Register TTRef recoil spectra with rho-shift correction + spectra.add("hEA_MB_Recoil_JetPt_Corr_RhoShifted_TTRef_Part", + "EA_MB: recoil jet #it{p}_{T} (#rho shifted)", + kTH1F, {jetPTcorrFinnerBin}, hist.sumw2); + + spectra.add("hEA_MB_RhoShifted_TTRef_Part", + "EA_MB: #rho shifted in events w. TT_{Ref}", + kTH1F, {rho}, hist.sumw2); } // Jet matching analysis @@ -1320,7 +1336,11 @@ struct RecoilJets { float weight = 1.) { // Get the configured scaled FT0M percentile boundaries - const std::vector ft0mEdges = hist.multFT0MThresh; + const std::vector rawFT0MEdges = hist.multFT0MThresh; + + const std::vector ft0mEdges{ + rawFT0MEdges.begin() + 1, + rawFT0MEdges.end()}; bool bSigEv = false; std::vector vPhiOfTT; @@ -1356,6 +1376,9 @@ struct RecoilJets { spectra.fill(HIST("hCentFT0C_FT0MStar"), centFT0C, scaledFT0M, weight); spectra.fill(HIST("hCentFT0M_FT0MStar"), centFT0M, scaledFT0M, weight); + // Correlation: centrality FT0C vs scaled FT0C + spectra.fill(HIST("hCentFT0C_ScaledFT0C"), centFT0C, ft0Metrics.multFT0C, weight); + // Z vertex position vs EA / centrality spectra.fill(HIST("hScaledFT0C_vertexZ"), scaledFT0C, vertexZ, weight); spectra.fill(HIST("hScaledFT0M_vertexZ"), scaledFT0M, vertexZ, weight); @@ -1794,6 +1817,11 @@ struct RecoilJets { spectra.fill(HIST("hCentFT0C_Rho_TTRef_Part"), centFT0C, rho, weight); spectra.fill(HIST("hCentFT0M_Rho_TTRef_Part"), centFT0M, rho, weight); + + //_____________________________________________________ + // Fill EA-dependent rho spectra in events with TTRef with corresponding rho shift + const float rhoRefShifted = rho + cfgRhoShift.mbPart.value; + spectra.fill(HIST("hEA_MB_RhoShifted_TTRef_Part"), rhoRefShifted, weight); } } @@ -1867,6 +1895,11 @@ struct RecoilJets { if (bRecoilJet) { + // Fill EA-dependent TTRef recoil spectra using the corresponding rho shift + const float rhoRefShifted = rho + cfgRhoShift.mbPart.value; + const float jetPtCorrShifted = jetPt - rhoRefShifted * jetArea; + spectra.fill(HIST("hEA_MB_Recoil_JetPt_Corr_RhoShifted_TTRef_Part"), jetPtCorrShifted, weight); + // EA dependence spectra.fill(HIST("hScaledFT0C_Recoil_JetPt_Corr_TTRef_Part"), scaledFT0C, jetPtCorr, weight); spectra.fill(HIST("hScaledFT0M_Recoil_JetPt_Corr_TTRef_Part"), scaledFT0M, jetPtCorr, weight); diff --git a/PWGJE/Tasks/statPromptPhoton.cxx b/PWGJE/Tasks/statPromptPhoton.cxx index f28a5f107b9..a09df380079 100644 --- a/PWGJE/Tasks/statPromptPhoton.cxx +++ b/PWGJE/Tasks/statPromptPhoton.cxx @@ -426,7 +426,7 @@ struct statPromptPhoton { ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// template - bool trackSelection(const TrackType track) + bool trackSelection(const TrackType& track) { // basic track cuts if (track.pt() < cfgtrkMinPt) diff --git a/PWGJE/Tasks/taskEmcExtensiveMcQa.cxx b/PWGJE/Tasks/taskEmcExtensiveMcQa.cxx index f9845724101..0061742548c 100644 --- a/PWGJE/Tasks/taskEmcExtensiveMcQa.cxx +++ b/PWGJE/Tasks/taskEmcExtensiveMcQa.cxx @@ -21,6 +21,7 @@ #include "Common/CCDB/ctpRateFetcher.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include #include @@ -52,7 +53,7 @@ using namespace o2::framework::expressions; using namespace o2::constants; using namespace o2::hf_evsel; using namespace o2::hf_centrality; -using CollisionEvSels = o2::soa::Join; +using CollisionEvSels = o2::soa::Join; using BcEvSelIt = o2::soa::Join::iterator; using SelectedClusters = o2::soa::Filtered>; diff --git a/PWGJE/Tasks/trackEfficiency.cxx b/PWGJE/Tasks/trackEfficiency.cxx index ee4220cba6e..0eed47da158 100644 --- a/PWGJE/Tasks/trackEfficiency.cxx +++ b/PWGJE/Tasks/trackEfficiency.cxx @@ -34,6 +34,7 @@ #include #include +#include #include #include @@ -173,7 +174,7 @@ struct TrackEfficiency { } template - void fillParticlesHistograms(TMCCollision const& /*mcCollision*/, TCollisions const& collisions, TParticles const& mcparticles, TTracks tracks, float weight = 1.0) + void fillParticlesHistograms(TMCCollision const& /*mcCollision*/, TCollisions const& collisions, TParticles const& mcparticles, const TTracks& tracks, float weight = 1.0) { // float centrality = checkCentFT0M ? mcCollision.centFT0M() : mcCollision.centFT0C(); mcCollision.centFT0C() isn't filled at the moment; can be added back when it is float centrality = checkCentFT0M ? collisions.begin().centFT0M() : collisions.begin().centFT0C(); @@ -257,7 +258,7 @@ struct TrackEfficiency { AxisSpec dcaxyAxis = {1000, -1.0, 1.0, "dca_{xy}"}; AxisSpec dcazAxis = {4000, -4.0, 4.0, "dca_{z}"}; - if (doprocessEFficiencyPurity || doprocessEFficiencyPurityWeighted) { + if (doprocessEFficiencyPurity || doprocessEFficiencyPurityWeighted || doprocessQcCheck) { registry.add("hMcCollCutsCounts", "McColl cuts count checks", {HistType::kTH1F, {{10, 0., 10.}}}); registry.get(HIST("hMcCollCutsCounts"))->GetXaxis()->SetBinLabel(1, "allMcColl"); @@ -282,7 +283,7 @@ struct TrackEfficiency { registry.get(HIST("hTrackCutsCounts"))->GetXaxis()->SetBinLabel(2, "trackSel"); registry.get(HIST("hTrackCutsCounts"))->GetXaxis()->SetBinLabel(3, "hasMcParticle"); - if (doprocessEFficiencyPurity) { + if (doprocessEFficiencyPurity || doprocessQcCheck) { registry.get(HIST("hTrackCutsCounts"))->GetXaxis()->SetBinLabel(4, "mcPartIsPrimary"); registry.get(HIST("hTrackCutsCounts"))->GetXaxis()->SetBinLabel(5, "etaAcc"); // not actually applied here but it will give an idea of what will be done in the post processing } @@ -291,7 +292,13 @@ struct TrackEfficiency { registry.get(HIST("hTrackCutsCounts"))->GetXaxis()->SetBinLabel(5, "mcPartIsPrimary"); registry.get(HIST("hTrackCutsCounts"))->GetXaxis()->SetBinLabel(6, "etaAcc"); // not actually applied here but it will give an idea of what will be done in the post processing } - + if (doprocessQcCheck) { + registry.add("h_ntrack_nonassociatedtrack", "Non-associated tracks;N_{tracks};counts", {HistType::kTH1I, {nTracksAxis}}); + registry.add("h_ntrack_associatedtrack_primary", "Associated tracks, primary;N_{tracks};counts", {HistType::kTH1I, {nTracksAxis}}); + registry.add("h_ntrack_associatedtrack_nonprimary", "Associated tracks, non-primary;N_{tracks};counts", {HistType::kTH1I, {nTracksAxis}}); + registry.add("h_ntrack_associatedtrack_split_primary", "Associated split tracks, primary;N_{tracks};counts", {HistType::kTH1I, {nTracksAxis}}); + registry.add("h_ntrack_associatedtrack_split_nonprimary", "Associated split tracks, non-primary;N_{tracks};counts", {HistType::kTH1I, {nTracksAxis}}); + } // ptAxisLow registry.add("h3_particle_pt_particle_eta_particle_phi_mcpartofinterest", "#it{p}_{T, mcpart} (GeV/#it{c}); #eta_{mcpart}; #phi_{mcpart}", {HistType::kTH3F, {ptAxisEff, etaAxisEff, phiAxisEff}}); registry.add("h3_particle_pt_particle_eta_particle_phi_mcpart_nonprimary", "#it{p}_{T, mcpart} (GeV/#it{c}); #eta_{mcpart}; #phi_{mcpart}", {HistType::kTH3F, {ptAxisEff, etaAxisEff, phiAxisEff}}); @@ -1499,6 +1506,206 @@ struct TrackEfficiency { } } PROCESS_SWITCH(TrackEfficiency, processItsTpcMatchingMC, "fills histograms for ITS-TPC matching analysis - MC study, true primary and true secondary separated", false); + + void processQcCheck(aod::JetMcCollisions::iterator const& mcCollision, + soa::SmallGroups const& collisions, // smallgroups gives only the collisions associated to the current mccollision, thanks to the mccollisionlabel pre-integrated in jetcollisionsmcd + soa::Filtered> const& jetTracks, + soa::Join const&, + JetParticlesWithOriginal const& jMcParticles) + { + registry.fill(HIST("hMcCollCutsCounts"), 0.5); // all mcCollisions + + if (!(std::abs(mcCollision.posZ()) < vertexZCut)) { + return; + } + registry.fill(HIST("hMcCollCutsCounts"), 1.5); // mcCollision.posZ() condition + + if (collisions.size() < 1) { + return; + } + registry.fill(HIST("hMcCollCutsCounts"), 2.5); // mcCollisions with at least one reconstructed collision + + if (acceptSplitCollisions == NonSplitOnly && collisions.size() > 1) { + return; + } + registry.fill(HIST("hMcCollCutsCounts"), 3.5); // split mcCollisions condition + + float centrality = -1; + bool hasSel8Coll = false; + bool centralityCheck = false; + bool occupancyCheck = false; + if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly || acceptSplitCollisions == NonSplitOnly) { // check only that the first reconstructed collision passes the check (for the NonSplitOnly case, there's only one associated collision) + if (jetderiveddatautilities::selectCollision(collisions.begin(), eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { // Skipping MC events that have their first associated collision not reconstructed + hasSel8Coll = true; + } + if (!checkOccupancy || ((trackOccupancyInTimeRangeMin < collisions.begin().trackOccupancyInTimeRange()) && (collisions.begin().trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax))) { // check occupancy only in GP Pb-Pb MC + occupancyCheck = true; + } + centrality = checkCentFT0M ? collisions.begin().centFT0M() : collisions.begin().centFT0C(); + if (!cutCentrality || ((centralityMin < centrality) && (centrality < centralityMax))) { // mcCollision.centFT0C() isn't filled at the moment; can use it instead when it is added to O2Physics + centralityCheck = true; + } + } else if (acceptSplitCollisions == SplitOkCheckAnyAssocColl) { // check that at least one of the reconstructed collisions passes the checks + for (auto const& collision : collisions) { + if (jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections)) { // Skipping MC events that have not a single selected reconstructed collision ; effect unclear if mcColl is split + hasSel8Coll = true; + } + if (!checkOccupancy || ((trackOccupancyInTimeRangeMin < collision.trackOccupancyInTimeRange()) && (collision.trackOccupancyInTimeRange() < trackOccupancyInTimeRangeMax))) { // check occupancy only in GP Pb-Pb MC + occupancyCheck = true; + } + centrality = checkCentFT0M ? collision.centFT0M() : collision.centFT0C(); + if (!cutCentrality || ((centralityMin < centrality) && (centrality < centralityMax))) { // effect unclear if mcColl is split + centralityCheck = true; + } + } + } + if (!hasSel8Coll) { + return; + } + registry.fill(HIST("hMcCollCutsCounts"), 4.5); // at least one of the reconstructed collisions associated with this mcCollision is selected + + // float centrality = checkCentFT0M ? mcCollision.centFT0M() : mcCollision.centFT0C(); mcCollision.centFT0C() isn't filled at the moment; can be added back when it is + // if (cutCentrality && (centrality < centralityMin || centralityMax < centrality)) { + // return; + // } + if (!centralityCheck) { + return; + } + registry.fill(HIST("hMcCollCutsCounts"), 5.5); // at least one of the reconstructed collisions associated with this mcCollision is selected with regard to centrality + + float pTHat = mcCollision.ptHard() < pTHatSettingSentinelValue ? mcCollision.ptHard() : simPtRef / (std::pow(mcCollision.weight(), 1.0 / pTHatExponent)); + if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max + return; + } + registry.fill(HIST("hMcCollCutsCounts"), 6.5); // ptHat condition + + if (checkOccupancy) { + if (!occupancyCheck) { + return; + } + registry.fill(HIST("hMcCollCutsCounts"), 7.5); + } + + for (auto const& jMcParticle : jMcParticles) { + registry.fill(HIST("hMcPartCutsCounts"), 0.5); // allPartsInSelMcColl + + if (!isChargedParticle(jMcParticle.pdgCode())) { + continue; + } + registry.fill(HIST("hMcPartCutsCounts"), 1.5); // isCharged + + registry.fill(HIST("h3_particle_pt_particle_eta_particle_phi_mcpart_nonprimary"), jMcParticle.pt(), jMcParticle.eta(), jMcParticle.phi()); + + if (checkPrimaryPart && !jMcParticle.isPhysicalPrimary()) { // global tracks should be mostly primaries + continue; + } + registry.fill(HIST("hMcPartCutsCounts"), 2.5); // isPrimary + + registry.fill(HIST("h3_particle_pt_particle_eta_particle_phi_mcpartofinterest"), jMcParticle.pt(), jMcParticle.eta(), jMcParticle.phi()); + + registry.fill(HIST("h3_particle_pt_high_particle_eta_particle_phi_mcpartofinterest"), jMcParticle.pt(), jMcParticle.eta(), jMcParticle.phi()); + + if ((std::abs(jMcParticle.eta()) < trackEtaAcceptanceCountQA)) { // removed from actual cuts for now because all the histograms have an eta axis + registry.fill(HIST("hMcPartCutsCounts"), 3.5); // etaAccept // not actually applied here but it will give an idea of what will be done in the post processing + } + } + + std::vector seenMcParticlesVector; // is reset every mc collision + + int splitCollCounter = 0; + for (auto const& collision : collisions) { + splitCollCounter++; + if (acceptSplitCollisions == SplitOkCheckFirstAssocCollOnly && splitCollCounter > 1) { + return; + } + + if (!jetderiveddatautilities::selectCollision(collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections) || !(std::abs(collision.posZ()) < vertexZCut)) { + continue; + } + + auto collTracks = jetTracks.sliceBy(tracksPerJCollision, collision.globalIndex()); + int ntrack_nonassociatedtrack = 0; + int ntrack_associatedtrack_nonprimary = 0; + int ntrack_associatedtrack_primary = 0; + int ntrack_associatedtrack_split_nonprimary = 0; + int ntrack_associatedtrack_split_primary = 0; + for (auto const& track : collTracks) { + registry.fill(HIST("hTrackCutsCounts"), 0.5); + + if (!isAcceptedTrack(track)) { + continue; + } + registry.fill(HIST("hTrackCutsCounts"), 1.5); + + if (!track.has_mcParticle()) { + ntrack_nonassociatedtrack += 1; + + registry.fill(HIST("h3_track_pt_track_eta_track_phi_nonassociatedtrack"), track.pt(), track.eta(), track.phi()); + + registry.fill(HIST("h3_track_pt_high_track_eta_track_phi_nonassociatedtrack"), track.pt(), track.eta(), track.phi()); + continue; + } + registry.fill(HIST("hTrackCutsCounts"), 2.5); + + auto jMcParticleFromTrack = track.mcParticle_as(); + if (!jMcParticleFromTrack.isPhysicalPrimary()) { + ntrack_associatedtrack_nonprimary += 1; + + registry.fill(HIST("h3_track_pt_track_eta_track_phi_associatedtrack_nonprimary"), track.pt(), track.eta(), track.phi()); + registry.fill(HIST("h3_particle_pt_particle_eta_particle_phi_associatedtrack_nonprimary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi()); + + registry.fill(HIST("h3_track_pt_high_track_eta_track_phi_associatedtrack_nonprimary"), track.pt(), track.eta(), track.phi()); + registry.fill(HIST("h3_particle_pt_high_particle_eta_particle_phi_associatedtrack_nonprimary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi()); + + if (std::find(seenMcParticlesVector.begin(), seenMcParticlesVector.end(), jMcParticleFromTrack.globalIndex()) != seenMcParticlesVector.end()) { + ntrack_associatedtrack_split_nonprimary += 1; + + registry.fill(HIST("h3_track_pt_track_eta_track_phi_associatedtrack_split_nonprimary"), track.pt(), track.eta(), track.phi()); + registry.fill(HIST("h3_particle_pt_particle_eta_particle_phi_associatedtrack_split_nonprimary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi()); + + registry.fill(HIST("h3_track_pt_high_track_eta_track_phi_associatedtrack_split_nonprimary"), track.pt(), track.eta(), track.phi()); + registry.fill(HIST("h3_particle_pt_high_particle_eta_particle_phi_associatedtrack_split_nonprimary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi()); + } else { + seenMcParticlesVector.push_back(jMcParticleFromTrack.globalIndex()); + } + + continue; + } + + registry.fill(HIST("hTrackCutsCounts"), 3.5); + + ntrack_associatedtrack_primary += 1; + registry.fill(HIST("h3_track_pt_track_eta_track_phi_associatedtrack_primary"), track.pt(), track.eta(), track.phi()); + registry.fill(HIST("h3_particle_pt_particle_eta_particle_phi_associatedtrack_primary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi()); + registry.fill(HIST("h2_particle_pt_track_pt_residual_associatedtrack_primary"), jMcParticleFromTrack.pt(), (jMcParticleFromTrack.pt() - track.pt()) / jMcParticleFromTrack.pt()); + + registry.fill(HIST("h3_track_pt_high_track_eta_track_phi_associatedtrack_primary"), track.pt(), track.eta(), track.phi()); + registry.fill(HIST("h3_particle_pt_high_particle_eta_particle_phi_associatedtrack_primary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi()); + registry.fill(HIST("h2_particle_pt_high_track_pt_high_residual_associatedtrack_primary"), jMcParticleFromTrack.pt(), (jMcParticleFromTrack.pt() - track.pt()) / jMcParticleFromTrack.pt()); + + if (std::find(seenMcParticlesVector.begin(), seenMcParticlesVector.end(), jMcParticleFromTrack.globalIndex()) != seenMcParticlesVector.end()) { + ntrack_associatedtrack_split_primary += 1; + registry.fill(HIST("h3_track_pt_track_eta_track_phi_associatedtrack_split_primary"), track.pt(), track.eta(), track.phi()); + registry.fill(HIST("h3_particle_pt_particle_eta_particle_phi_associatedtrack_split_primary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi()); + + registry.fill(HIST("h3_track_pt_high_track_eta_track_phi_associatedtrack_split_primary"), track.pt(), track.eta(), track.phi()); + registry.fill(HIST("h3_particle_pt_high_particle_eta_particle_phi_associatedtrack_split_primary"), jMcParticleFromTrack.pt(), jMcParticleFromTrack.eta(), jMcParticleFromTrack.phi()); + } else { + seenMcParticlesVector.push_back(jMcParticleFromTrack.globalIndex()); + } + + if (std::abs(jMcParticleFromTrack.eta()) < trackEtaAcceptanceCountQA) { // not actually applied here but it will give an idea of what will be done in the post processing + registry.fill(HIST("hTrackCutsCounts"), 4.5); + } + } + registry.fill(HIST("h_ntrack_nonassociatedtrack"), ntrack_nonassociatedtrack); + registry.fill(HIST("h_ntrack_associatedtrack_nonprimary"), ntrack_associatedtrack_nonprimary); + registry.fill(HIST("h_ntrack_associatedtrack_split_nonprimary"), ntrack_associatedtrack_split_nonprimary); + registry.fill(HIST("h_ntrack_associatedtrack_primary"), ntrack_associatedtrack_primary); + registry.fill(HIST("h_ntrack_associatedtrack_split_primary"), ntrack_associatedtrack_split_primary); + } + } + PROCESS_SWITCH(TrackEfficiency, processQcCheck, "Histograms for QC checks", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/DataModel/LFDoubleCascTables.h b/PWGLF/DataModel/LFDoubleCascTables.h deleted file mode 100644 index 03f77e8f34c..00000000000 --- a/PWGLF/DataModel/LFDoubleCascTables.h +++ /dev/null @@ -1,72 +0,0 @@ -// 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. - -#ifndef PWGLF_DATAMODEL_LFDOUBLECASCTABLES_H_ -#define PWGLF_DATAMODEL_LFDOUBLECASCTABLES_H_ - -#include - -namespace o2::aod -{ - -namespace DoubleCascTables -{ -DECLARE_SOA_COLUMN(PtCasc1, ptCasc1, float); // signed pt of the cascade -DECLARE_SOA_COLUMN(EtaCasc1, etaCasc1, float); -DECLARE_SOA_COLUMN(PhiCasc1, phiCasc1, float); -DECLARE_SOA_COLUMN(CascDecLength1, cascDecLength1, float); -DECLARE_SOA_COLUMN(OmegaMassCasc1, omegaMassCasc1, float); -DECLARE_SOA_COLUMN(XiMassCasc1, xiMassCasc1, float); -DECLARE_SOA_COLUMN(CosPACasc1, cosPACasc1, float); -DECLARE_SOA_COLUMN(DcaBachPVCasc1, dcaBachPVCasc1, float); -DECLARE_SOA_COLUMN(DcaV0BachCasc1, dcaV0BachCasc1, float); -DECLARE_SOA_COLUMN(NSigmaKBach1, nSigmaKBach1, float); - -DECLARE_SOA_COLUMN(PtCasc2, ptCasc2, float); -DECLARE_SOA_COLUMN(EtaCasc2, etaCasc2, float); -DECLARE_SOA_COLUMN(PhiCasc2, phiCasc2, float); -DECLARE_SOA_COLUMN(CascDecLength2, cascDecLength2, float); -DECLARE_SOA_COLUMN(OmegaMassCasc2, omegaMassCasc2, float); -DECLARE_SOA_COLUMN(XiMassCasc2, xiMassCasc2, float); -DECLARE_SOA_COLUMN(CosPACasc2, cosPACasc2, float); -DECLARE_SOA_COLUMN(DcaBachPVCasc2, dcaBachPVCasc2, float); -DECLARE_SOA_COLUMN(DcaV0BachCasc2, dcaV0BachCasc2, float); -DECLARE_SOA_COLUMN(NSigmaKBach2, nSigmaKBach2, float); - -DECLARE_SOA_COLUMN(DoubleOmegaMass, doubleOmegaMass, float); -} // namespace DoubleCascTables - -DECLARE_SOA_TABLE(DoubleCascTable, "AOD", "DOUBLECASCTABLE", - DoubleCascTables::PtCasc1, - DoubleCascTables::EtaCasc1, - DoubleCascTables::PhiCasc1, - DoubleCascTables::CascDecLength1, - DoubleCascTables::OmegaMassCasc1, - DoubleCascTables::XiMassCasc1, - DoubleCascTables::CosPACasc1, - DoubleCascTables::DcaBachPVCasc1, - DoubleCascTables::DcaV0BachCasc1, - DoubleCascTables::NSigmaKBach1, - DoubleCascTables::PtCasc2, - DoubleCascTables::EtaCasc2, - DoubleCascTables::PhiCasc2, - DoubleCascTables::CascDecLength2, - DoubleCascTables::OmegaMassCasc2, - DoubleCascTables::XiMassCasc2, - DoubleCascTables::CosPACasc2, - DoubleCascTables::DcaBachPVCasc2, - DoubleCascTables::DcaV0BachCasc2, - DoubleCascTables::NSigmaKBach2, - DoubleCascTables::DoubleOmegaMass); - -} // namespace o2::aod - -#endif // PWGLF_DATAMODEL_LFDOUBLECASCTABLES_H_ diff --git a/PWGLF/DataModel/LFDoubleOmegaTables.h b/PWGLF/DataModel/LFDoubleOmegaTables.h new file mode 100644 index 00000000000..9cc38e08f43 --- /dev/null +++ b/PWGLF/DataModel/LFDoubleOmegaTables.h @@ -0,0 +1,104 @@ +// 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. + +#ifndef PWGLF_DATAMODEL_LFDOUBLEOMEGATABLES_H_ +#define PWGLF_DATAMODEL_LFDOUBLEOMEGATABLES_H_ + +#include + +#include + +namespace o2::aod +{ + +namespace DoubleOmegaTables +{ +DECLARE_SOA_COLUMN(PtDoubleOmega, ptDoubleOmega, float); +DECLARE_SOA_COLUMN(EtaDoubleOmega, etaDoubleOmega, float); +DECLARE_SOA_COLUMN(PhiDoubleOmega, phiDoubleOmega, float); +DECLARE_SOA_COLUMN(DecayVtxX, decayVtxX, float); +DECLARE_SOA_COLUMN(DecayVtxY, decayVtxY, float); +DECLARE_SOA_COLUMN(DecayVtxZ, decayVtxZ, float); +DECLARE_SOA_COLUMN(PrimaryVtxX, primaryVtxX, float); +DECLARE_SOA_COLUMN(PrimaryVtxY, primaryVtxY, float); +DECLARE_SOA_COLUMN(PrimaryVtxZ, primaryVtxZ, float); +DECLARE_SOA_COLUMN(CosPAOmega, cosPAOmega, float); +DECLARE_SOA_COLUMN(CosPADirectLambda, cosPADirectLambda, float); +DECLARE_SOA_COLUMN(CosPADoubleOmega, cosPADoubleOmega, float); +DECLARE_SOA_COLUMN(DCAxyOmegaToPV, dcaXYOmegaToPV, float); +DECLARE_SOA_COLUMN(DCAzOmegaToPV, dcaZOmegaToPV, float); +DECLARE_SOA_COLUMN(DCAxyDirectLambdaToPV, dcaXYDirectLambdaToPV, float); +DECLARE_SOA_COLUMN(DCAzDirectLambdaToPV, dcaZDirectLambdaToPV, float); +DECLARE_SOA_COLUMN(DCAxyDirectKaonToPV, dcaXYDirectKaonToPV, float); +DECLARE_SOA_COLUMN(DCAzDirectKaonToPV, dcaZDirectKaonToPV, float); +DECLARE_SOA_COLUMN(TPCNSigmaDirectKaon, tpcNSigmaDirectKaon, float); // -999 when TPC is unavailable or the candidate is not reconstructed. +DECLARE_SOA_COLUMN(TOFNSigmaDirectKaon, tofNSigmaDirectKaon, float); // -999 when TOF is unavailable or the candidate is not reconstructed. +// Three bits per daughter (ITS, TPC, TOF), ordered as: Omega kaon, Omega +// proton, Omega pion, direct proton, direct pion, direct kaon (also for c.c.). +// Bits 18-31 are zero; generated-only rows have a zero bitmap. +DECLARE_SOA_COLUMN(DaughterDetectorMap, daughterDetectorMap, uint32_t); +DECLARE_SOA_COLUMN(MassDoubleOmega, massDoubleOmega, float); +DECLARE_SOA_COLUMN(MassOmega, massOmega, float); +DECLARE_SOA_COLUMN(MassXi, massXi, float); + +DECLARE_SOA_COLUMN(GenPt, genPt, float); +DECLARE_SOA_COLUMN(GenEta, genEta, float); +DECLARE_SOA_COLUMN(GenPhi, genPhi, float); +DECLARE_SOA_COLUMN(GenDecayLength, genDecayLength, float); +DECLARE_SOA_COLUMN(PdgDoubleOmega, pdgDoubleOmega, int); +DECLARE_SOA_COLUMN(GenMotherId, genMotherId, int64_t); // MC particle index within the input dataframe. +DECLARE_SOA_COLUMN(IsReco, isReco, bool); +} // namespace DoubleOmegaTables + +#define DOUBLE_OMEGA_RECO_COLUMNS \ + DoubleOmegaTables::PtDoubleOmega, \ + DoubleOmegaTables::EtaDoubleOmega, \ + DoubleOmegaTables::PhiDoubleOmega, \ + DoubleOmegaTables::DecayVtxX, \ + DoubleOmegaTables::DecayVtxY, \ + DoubleOmegaTables::DecayVtxZ, \ + DoubleOmegaTables::PrimaryVtxX, \ + DoubleOmegaTables::PrimaryVtxY, \ + DoubleOmegaTables::PrimaryVtxZ, \ + DoubleOmegaTables::CosPAOmega, \ + DoubleOmegaTables::CosPADirectLambda, \ + DoubleOmegaTables::CosPADoubleOmega, \ + DoubleOmegaTables::DCAxyOmegaToPV, \ + DoubleOmegaTables::DCAzOmegaToPV, \ + DoubleOmegaTables::DCAxyDirectLambdaToPV, \ + DoubleOmegaTables::DCAzDirectLambdaToPV, \ + DoubleOmegaTables::DCAxyDirectKaonToPV, \ + DoubleOmegaTables::DCAzDirectKaonToPV, \ + DoubleOmegaTables::TPCNSigmaDirectKaon, \ + DoubleOmegaTables::TOFNSigmaDirectKaon, \ + DoubleOmegaTables::DaughterDetectorMap, \ + DoubleOmegaTables::MassDoubleOmega, \ + DoubleOmegaTables::MassOmega, \ + DoubleOmegaTables::MassXi + +DECLARE_SOA_TABLE(DoubleOmegaTable, "AOD", "DOUBLEOMEGATABLE", + DOUBLE_OMEGA_RECO_COLUMNS); + +DECLARE_SOA_TABLE(DoubleOmegaTableMC, "AOD", "DBLOMEGAMCTABLE", + DOUBLE_OMEGA_RECO_COLUMNS, + DoubleOmegaTables::GenPt, + DoubleOmegaTables::GenEta, + DoubleOmegaTables::GenPhi, + DoubleOmegaTables::GenDecayLength, + DoubleOmegaTables::PdgDoubleOmega, + DoubleOmegaTables::GenMotherId, + DoubleOmegaTables::IsReco); + +#undef DOUBLE_OMEGA_RECO_COLUMNS + +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_LFDOUBLEOMEGATABLES_H_ diff --git a/PWGLF/DataModel/LFHypernucleiKfTables.h b/PWGLF/DataModel/LFHypernucleiKfTables.h index fdb223af586..41c4f367cf5 100644 --- a/PWGLF/DataModel/LFHypernucleiKfTables.h +++ b/PWGLF/DataModel/LFHypernucleiKfTables.h @@ -94,9 +94,11 @@ namespace hykftrk DECLARE_SOA_INDEX_COLUMN(HypKfColl, hypKfColl); DECLARE_SOA_COLUMN(Rigidity, rigidity, float); //! DECLARE_SOA_COLUMN(TpcNcluster, tpcNcluster, float); //! +DECLARE_SOA_COLUMN(TpcNclsPid, tpcNclsPid, float); //! +DECLARE_SOA_COLUMN(TpcNclsCr, tpcNclsCr, float); //! DECLARE_SOA_COLUMN(TpcNsigma, tpcNsigma, float); //! -DECLARE_SOA_COLUMN(TpcNsigmaNhp, tpcNsigmaNhp, float); //! -DECLARE_SOA_COLUMN(TpcNsigmaNlp, tpcNsigmaNlp, float); //! +DECLARE_SOA_COLUMN(ItsNsigma, itsNsigma, float); //! +DECLARE_SOA_COLUMN(PidForTrk, pidForTrk, uint32_t); //! DECLARE_SOA_COLUMN(TofMass, tofMass, float); //! DECLARE_SOA_COLUMN(IsPVContributor, isPVContributor, bool); //! DECLARE_SOA_COLUMN(SubMass, subMass, float); //! @@ -140,15 +142,17 @@ DECLARE_SOA_TABLE(HypKfTracks, "AOD", "HYPKFTRACK", track::Phi, track::DcaXY, track::DcaZ, - hykftrk::TpcNcluster, track::TPCChi2NCl, track::ITSClusterSizes, track::ITSChi2NCl, hykftrk::Rigidity, track::TPCSignal, + hykftrk::TpcNcluster, + hykftrk::TpcNclsPid, + hykftrk::TpcNclsCr, hykftrk::TpcNsigma, - hykftrk::TpcNsigmaNhp, - hykftrk::TpcNsigmaNlp, + hykftrk::ItsNsigma, + hykftrk::PidForTrk, hykftrk::TofMass, hykftrk::IsPVContributor, hykftrk::Px, diff --git a/PWGLF/DataModel/LFHypernucleiTables.h b/PWGLF/DataModel/LFHypernucleiTables.h index d494fcbf87a..a4162c55f75 100644 --- a/PWGLF/DataModel/LFHypernucleiTables.h +++ b/PWGLF/DataModel/LFHypernucleiTables.h @@ -25,17 +25,21 @@ namespace o2::aod { namespace hyperrec { -DECLARE_SOA_COLUMN(CentralityFT0A, centralityFT0A, float); // centrality with FT0A estimator -DECLARE_SOA_COLUMN(CentralityFT0C, centralityFT0C, float); // centrality with FT0C estimator -DECLARE_SOA_COLUMN(CentralityFT0M, centralityFT0M, float); // centrality with FT0M estimator -DECLARE_SOA_COLUMN(PsiFT0A, psiFT0A, float); // Psi with FT0A estimator -DECLARE_SOA_COLUMN(MultFT0A, multFT0A, float); // Multiplicity with FT0A estimator -DECLARE_SOA_COLUMN(PsiFT0C, psiFT0C, float); // Psi with FT0C estimator -DECLARE_SOA_COLUMN(QFT0C, qFT0C, float); // Amplitude with FT0C estimator -DECLARE_SOA_COLUMN(MultFT0C, multFT0C, float); // Multiplicity with FT0C estimator -DECLARE_SOA_COLUMN(PsiTPC, psiTPC, float); // Psi with TPC estimator -DECLARE_SOA_COLUMN(MultTPC, multTPC, float); // Multiplicity with TPC estimator -DECLARE_SOA_COLUMN(CollisionId, collisionId, int64_t); // CollisionID +DECLARE_SOA_COLUMN(CentralityFT0A, centralityFT0A, float); // centrality with FT0A estimator +DECLARE_SOA_COLUMN(CentralityFT0C, centralityFT0C, float); // centrality with FT0C estimator +DECLARE_SOA_COLUMN(CentralityFT0M, centralityFT0M, float); // centrality with FT0M estimator +DECLARE_SOA_COLUMN(TrackOccupancyInTimeRange, trackOccupancyInTimeRange, int); // Track occupancy in the time range around the collision +DECLARE_SOA_COLUMN(Ft0cOccupancyInTimeRange, ft0cOccupancyInTimeRange, float); // FT0C occupancy in the time range around the collision +DECLARE_SOA_COLUMN(PsiFT0A, psiFT0A, float); // Psi with FT0A estimator +DECLARE_SOA_COLUMN(MultFT0A, multFT0A, float); // Multiplicity with FT0A estimator +DECLARE_SOA_COLUMN(PsiFT0C, psiFT0C, float); // Psi with FT0C estimator +DECLARE_SOA_COLUMN(QFT0C, qFT0C, float); // Amplitude with FT0C estimator +DECLARE_SOA_COLUMN(MultFT0C, multFT0C, float); // Multiplicity with FT0C estimator +DECLARE_SOA_COLUMN(PsiTPC, psiTPC, float); // Psi with TPC estimator +DECLARE_SOA_COLUMN(MultTPC, multTPC, float); // Multiplicity with TPC estimator +DECLARE_SOA_INDEX_COLUMN(Collision, collision); // Collision index +DECLARE_SOA_INDEX_COLUMN_FULL(HeTrack, heTrack, int, Tracks, "_He"); // Original helium daughter track +DECLARE_SOA_INDEX_COLUMN_FULL(PiTrack, piTrack, int, Tracks, "_Pi"); // Original pion daughter track DECLARE_SOA_COLUMN(RunNumber, runNumber, int32_t); // Run number DECLARE_SOA_COLUMN(IsMatter, isMatter, bool); // bool: true for matter @@ -62,19 +66,19 @@ DECLARE_SOA_COLUMN(NTPCpidClusHe, nTPCpidClusHe, uint8_t); // Number DECLARE_SOA_COLUMN(NTPCpidClusPi, nTPCpidClusPi, uint8_t); // Number of TPC clusters with PID information of the Pi daughter DECLARE_SOA_COLUMN(NTPCCrossedRowsHe, nTPCCrossedRowsHe, uint8_t); // Number of TPC crossed rows of the He daughter DECLARE_SOA_COLUMN(NTPCCrossedRowsPi, nTPCCrossedRowsPi, uint8_t); // Number of TPC crossed rows of the Pi daughter -DECLARE_SOA_COLUMN(TPCsignalHe, tpcSignalHe, uint16_t); // TPC signal of the He daughter -DECLARE_SOA_COLUMN(TPCsignalPi, tpcSignalPi, uint16_t); // TPC signal of the Pi daughter -DECLARE_SOA_COLUMN(TPCChi2He, tpcChi2He, float); // TPC chi2 of the He daughter -DECLARE_SOA_COLUMN(ITSChi2He, itsChi2He, float); // ITS chi2 of the He daughter -DECLARE_SOA_COLUMN(ITSChi2Pi, itsChi2Pi, float); // ITS chi2 of the Pi daughter +DECLARE_SOA_COLUMN(TpcSignalHe, tpcSignalHe, uint16_t); // TPC signal of the He daughter +DECLARE_SOA_COLUMN(TpcSignalPi, tpcSignalPi, uint16_t); // TPC signal of the Pi daughter +DECLARE_SOA_COLUMN(TpcChi2He, tpcChi2He, float); // TPC chi2 of the He daughter +DECLARE_SOA_COLUMN(ItsChi2He, itsChi2He, float); // ITS chi2 of the He daughter +DECLARE_SOA_COLUMN(ItsChi2Pi, itsChi2Pi, float); // ITS chi2 of the Pi daughter DECLARE_SOA_COLUMN(TrackedClSize, trackedClSize, int); // int: zero for non-tracked candidates DECLARE_SOA_COLUMN(Flags, flags, uint8_t); // Flags for PID in tracking (bits [0, 3] for negative daughter, [4,7] for positive daughter) -DECLARE_SOA_COLUMN(TPCmomHe, tpcMomHe, float); // TPC momentum of the He daughter -DECLARE_SOA_COLUMN(TPCmomPi, tpcMomPi, float); // TPC momentum of the Pi daughter -DECLARE_SOA_COLUMN(TOFMass, tofMass, float); // TOF mass of the candidate -DECLARE_SOA_COLUMN(ITSclusterSizesHe, itsClusterSizesHe, uint32_t); // ITS cluster size of the He daughter -DECLARE_SOA_COLUMN(ITSclusterSizesPi, itsClusterSizesPi, uint32_t); // ITS cluster size of the Pi daughter -DECLARE_SOA_COLUMN(ITSclusterSizesHyp, itsClusterSizesHyp, uint32_t); // ITS cluster size of the Pi daughter +DECLARE_SOA_COLUMN(TpcMomHe, tpcMomHe, float); // TPC momentum of the He daughter +DECLARE_SOA_COLUMN(TpcMomPi, tpcMomPi, float); // TPC momentum of the Pi daughter +DECLARE_SOA_COLUMN(TofMass, tofMass, float); // TOF mass of the candidate +DECLARE_SOA_COLUMN(ItsClusterSizesHe, itsClusterSizesHe, uint32_t); // ITS cluster size of the He daughter +DECLARE_SOA_COLUMN(ItsClusterSizesPi, itsClusterSizesPi, uint32_t); // ITS cluster size of the Pi daughter +DECLARE_SOA_COLUMN(ItsClusterSizesHyp, itsClusterSizesHyp, uint32_t); // ITS cluster size of the Pi daughter DECLARE_SOA_COLUMN(DcaHe, dcaHe, float); // DCA between He daughter and V0 DECLARE_SOA_COLUMN(DcaPi, dcaPi, float); // DCA between pi daughter and V0 DECLARE_SOA_COLUMN(GenPt, genPt, float); // Pt of the hypertriton @@ -95,6 +99,7 @@ DECLARE_SOA_COLUMN(IsTwoBodyDecay, isTwoBodyDecay, bool); // bool: t DECLARE_SOA_TABLE(DataHypCands, "AOD", "HYPCANDS", o2::soa::Index<>, hyperrec::CentralityFT0A, hyperrec::CentralityFT0C, hyperrec::CentralityFT0M, + hyperrec::TrackOccupancyInTimeRange, hyperrec::Ft0cOccupancyInTimeRange, hyperrec::XPrimVtx, hyperrec::YPrimVtx, hyperrec::ZPrimVtx, hyperrec::RunNumber, hyperrec::IsMatter, @@ -103,14 +108,15 @@ DECLARE_SOA_TABLE(DataHypCands, "AOD", "HYPCANDS", hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, hyperrec::DcaV0Daug, hyperrec::DcaHe, hyperrec::DcaPi, hyperrec::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, hyperrec::NTPCpidClusHe, hyperrec::NTPCpidClusPi, hyperrec::NTPCCrossedRowsHe, hyperrec::NTPCCrossedRowsPi, - hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, hyperrec::TPCChi2He, hyperrec::ITSChi2He, hyperrec::ITSChi2Pi, - hyperrec::TOFMass, - hyperrec::ITSclusterSizesHe, hyperrec::ITSclusterSizesPi, + hyperrec::TpcMomHe, hyperrec::TpcMomPi, hyperrec::TpcSignalHe, hyperrec::TpcSignalPi, hyperrec::TpcChi2He, hyperrec::ItsChi2He, hyperrec::ItsChi2Pi, + hyperrec::TofMass, + hyperrec::ItsClusterSizesHe, hyperrec::ItsClusterSizesPi, hyperrec::Flags, hyperrec::TrackedClSize); DECLARE_SOA_TABLE(DataHypCandsFlow, "AOD", "HYPCANDSFLOW", o2::soa::Index<>, hyperrec::CentralityFT0A, hyperrec::CentralityFT0C, hyperrec::CentralityFT0M, + hyperrec::TrackOccupancyInTimeRange, hyperrec::Ft0cOccupancyInTimeRange, hyperrec::PsiFT0A, hyperrec::MultFT0A, hyperrec::PsiFT0C, hyperrec::MultFT0C, hyperrec::QFT0C, hyperrec::PsiTPC, hyperrec::MultTPC, @@ -122,14 +128,16 @@ DECLARE_SOA_TABLE(DataHypCandsFlow, "AOD", "HYPCANDSFLOW", hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, hyperrec::DcaV0Daug, hyperrec::DcaHe, hyperrec::DcaPi, hyperrec::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, hyperrec::NTPCpidClusHe, hyperrec::NTPCpidClusPi, hyperrec::NTPCCrossedRowsHe, hyperrec::NTPCCrossedRowsPi, - hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, hyperrec::TPCChi2He, hyperrec::ITSChi2He, hyperrec::ITSChi2Pi, - hyperrec::TOFMass, - hyperrec::ITSclusterSizesHe, hyperrec::ITSclusterSizesPi, + hyperrec::TpcMomHe, hyperrec::TpcMomPi, hyperrec::TpcSignalHe, hyperrec::TpcSignalPi, hyperrec::TpcChi2He, hyperrec::ItsChi2He, hyperrec::ItsChi2Pi, + hyperrec::TofMass, + hyperrec::ItsClusterSizesHe, hyperrec::ItsClusterSizesPi, hyperrec::Flags, hyperrec::TrackedClSize); DECLARE_SOA_TABLE(MCHypCands, "AOD", "MCHYPCANDS", o2::soa::Index<>, + hyperrec::CollisionId, hyperrec::HeTrackId, hyperrec::PiTrackId, hyperrec::CentralityFT0A, hyperrec::CentralityFT0C, hyperrec::CentralityFT0M, + hyperrec::TrackOccupancyInTimeRange, hyperrec::Ft0cOccupancyInTimeRange, hyperrec::XPrimVtx, hyperrec::YPrimVtx, hyperrec::ZPrimVtx, hyperrec::RunNumber, hyperrec::IsMatter, @@ -138,9 +146,9 @@ DECLARE_SOA_TABLE(MCHypCands, "AOD", "MCHYPCANDS", hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, hyperrec::DcaV0Daug, hyperrec::DcaHe, hyperrec::DcaPi, hyperrec::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, hyperrec::NTPCpidClusHe, hyperrec::NTPCpidClusPi, hyperrec::NTPCCrossedRowsHe, hyperrec::NTPCCrossedRowsPi, - hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, hyperrec::TPCChi2He, hyperrec::ITSChi2He, hyperrec::ITSChi2Pi, - hyperrec::TOFMass, - hyperrec::ITSclusterSizesHe, hyperrec::ITSclusterSizesPi, + hyperrec::TpcMomHe, hyperrec::TpcMomPi, hyperrec::TpcSignalHe, hyperrec::TpcSignalPi, hyperrec::TpcChi2He, hyperrec::ItsChi2He, hyperrec::ItsChi2Pi, + hyperrec::TofMass, + hyperrec::ItsClusterSizesHe, hyperrec::ItsClusterSizesPi, hyperrec::Flags, hyperrec::TrackedClSize, hyperrec::GenPt, hyperrec::GenPhi, @@ -158,7 +166,9 @@ DECLARE_SOA_TABLE(MCHypCands, "AOD", "MCHYPCANDS", DECLARE_SOA_TABLE(DataHypCandsWColl, "AOD", "HYPCANDSWCOLL", o2::soa::Index<>, - hyperrec::CollisionId, hyperrec::CentralityFT0A, hyperrec::CentralityFT0C, hyperrec::CentralityFT0M, + hyperrec::CollisionId, hyperrec::HeTrackId, hyperrec::PiTrackId, + hyperrec::CentralityFT0A, hyperrec::CentralityFT0C, hyperrec::CentralityFT0M, + hyperrec::TrackOccupancyInTimeRange, hyperrec::Ft0cOccupancyInTimeRange, hyperrec::XPrimVtx, hyperrec::YPrimVtx, hyperrec::ZPrimVtx, hyperrec::RunNumber, hyperrec::IsMatter, @@ -167,9 +177,9 @@ DECLARE_SOA_TABLE(DataHypCandsWColl, "AOD", "HYPCANDSWCOLL", hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, hyperrec::DcaV0Daug, hyperrec::DcaHe, hyperrec::DcaPi, hyperrec::NSigmaHe, hyperrec::NTPCclusHe, hyperrec::NTPCclusPi, hyperrec::NTPCpidClusHe, hyperrec::NTPCpidClusPi, hyperrec::NTPCCrossedRowsHe, hyperrec::NTPCCrossedRowsPi, - hyperrec::TPCmomHe, hyperrec::TPCmomPi, hyperrec::TPCsignalHe, hyperrec::TPCsignalPi, hyperrec::TPCChi2He, hyperrec::ITSChi2He, hyperrec::ITSChi2Pi, - hyperrec::TOFMass, - hyperrec::ITSclusterSizesHe, hyperrec::ITSclusterSizesPi, + hyperrec::TpcMomHe, hyperrec::TpcMomPi, hyperrec::TpcSignalHe, hyperrec::TpcSignalPi, hyperrec::TpcChi2He, hyperrec::ItsChi2He, hyperrec::ItsChi2Pi, + hyperrec::TofMass, + hyperrec::ItsClusterSizesHe, hyperrec::ItsClusterSizesPi, hyperrec::Flags, hyperrec::TrackedClSize); using DataHypCand = DataHypCands::iterator; @@ -187,20 +197,20 @@ DECLARE_SOA_COLUMN(PhiTrit, phiTrit, float); // Phi DECLARE_SOA_COLUMN(EtaTrit, etaTrit, float); // Eta of the triton kink DECLARE_SOA_COLUMN(DcaHyperPv, dcaHyperPv, float); // DCA of the hypertriton to the primary vertex DECLARE_SOA_COLUMN(DcaTritPv, dcaTritPv, float); // DCA of the triton kink to the primary vertex -DECLARE_SOA_COLUMN(DCAKinkTopo, dcaKinkTopo, float); // DCA of the kink topology -DECLARE_SOA_COLUMN(ITSclusterSizesHyper, itsClusterSizesHyper, uint32_t); // ITS cluster size of the hypertriton -DECLARE_SOA_COLUMN(ITSclusterSizesTrit, itsClusterSizesTrit, uint32_t); // ITS cluster size of the triton kink -DECLARE_SOA_COLUMN(PIDinTrackTrit, pidInTrackTrit, uint8_t); // PID in track for the triton kink +DECLARE_SOA_COLUMN(DcaKinkTopo, dcaKinkTopo, float); // DCA of the kink topology +DECLARE_SOA_COLUMN(ItsClusterSizesHyper, itsClusterSizesHyper, uint32_t); // ITS cluster size of the hypertriton +DECLARE_SOA_COLUMN(ItsClusterSizesTrit, itsClusterSizesTrit, uint32_t); // ITS cluster size of the triton kink +DECLARE_SOA_COLUMN(PidInTrackTrit, pidInTrackTrit, uint8_t); // PID in track for the triton kink -DECLARE_SOA_COLUMN(TPCmomTrit, tpcMomTrit, float); // TPC momentum of the triton kink -DECLARE_SOA_COLUMN(TPCsignalTrit, tpcSignalTrit, uint16_t); // TPC signal of the triton kink +DECLARE_SOA_COLUMN(TpcMomTrit, tpcMomTrit, float); // TPC momentum of the triton kink +DECLARE_SOA_COLUMN(TpcSignalTrit, tpcSignalTrit, uint16_t); // TPC signal of the triton kink DECLARE_SOA_COLUMN(NSigmaTPCTrit, nSigmaTPCTrit, float); // Number of tpc sigmas of the triton kink DECLARE_SOA_COLUMN(NSigmaTOFTrit, nSigmaTOFTrit, float); // Number of tof sigmas of the triton kink // MC additional info DECLARE_SOA_COLUMN(GenPtTrit, genPtTrit, float); // Pt of the triton kink DECLARE_SOA_COLUMN(HyperPtITS, hyperPtITS, float); // Pt of the hypertriton from ITS standalone, hypertriton tagged with MC truth -DECLARE_SOA_COLUMN(MCMask, mcMask, bool); // bool: true for fake triton +DECLARE_SOA_COLUMN(McMask, mcMask, bool); // bool: true for fake triton } // namespace hyperkink @@ -210,9 +220,9 @@ DECLARE_SOA_TABLE(DataHypKinkCands, "AOD", "HYPKINKCANDS", hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, hyperrec::IsMatter, hyperkink::PtHyper, hyperkink::PhiHyper, hyperkink::EtaHyper, hyperkink::PtTrit, hyperkink::PhiTrit, hyperkink::EtaTrit, - hyperkink::DcaHyperPv, hyperkink::DcaTritPv, hyperkink::DCAKinkTopo, - hyperkink::ITSclusterSizesHyper, hyperkink::ITSclusterSizesTrit, hyperkink::PIDinTrackTrit, - hyperkink::TPCmomTrit, hyperkink::TPCsignalTrit, hyperkink::NSigmaTPCTrit, hyperkink::NSigmaTOFTrit); + hyperkink::DcaHyperPv, hyperkink::DcaTritPv, hyperkink::DcaKinkTopo, + hyperkink::ItsClusterSizesHyper, hyperkink::ItsClusterSizesTrit, hyperkink::PidInTrackTrit, + hyperkink::TpcMomTrit, hyperkink::TpcSignalTrit, hyperkink::NSigmaTPCTrit, hyperkink::NSigmaTOFTrit); DECLARE_SOA_TABLE(MCHypKinkCands, "AOD", "MCHYPKINKCANDS", o2::soa::Index<>, @@ -220,12 +230,12 @@ DECLARE_SOA_TABLE(MCHypKinkCands, "AOD", "MCHYPKINKCANDS", hyperrec::XDecVtx, hyperrec::YDecVtx, hyperrec::ZDecVtx, hyperrec::IsMatter, hyperkink::PtHyper, hyperkink::PhiHyper, hyperkink::EtaHyper, hyperkink::PtTrit, hyperkink::PhiTrit, hyperkink::EtaTrit, - hyperkink::DcaHyperPv, hyperkink::DcaTritPv, hyperkink::DCAKinkTopo, - hyperkink::ITSclusterSizesHyper, hyperkink::ITSclusterSizesTrit, hyperkink::PIDinTrackTrit, - hyperkink::TPCmomTrit, hyperkink::TPCsignalTrit, hyperkink::NSigmaTPCTrit, hyperkink::NSigmaTOFTrit, + hyperkink::DcaHyperPv, hyperkink::DcaTritPv, hyperkink::DcaKinkTopo, + hyperkink::ItsClusterSizesHyper, hyperkink::ItsClusterSizesTrit, hyperkink::PidInTrackTrit, + hyperkink::TpcMomTrit, hyperkink::TpcSignalTrit, hyperkink::NSigmaTPCTrit, hyperkink::NSigmaTOFTrit, hyperrec::GenXDecVtx, hyperrec::GenYDecVtx, hyperrec::GenZDecVtx, hyperrec::GenPt, hyperkink::GenPtTrit, - hyperrec::IsReco, hyperrec::IsSignal, hyperkink::MCMask, hyperkink::HyperPtITS, + hyperrec::IsReco, hyperrec::IsSignal, hyperkink::McMask, hyperkink::HyperPtITS, hyperrec::IsRecoMCCollision, hyperrec::IsSurvEvSel); } // namespace o2::aod diff --git a/PWGLF/DataModel/LFKinkDecayTables.h b/PWGLF/DataModel/LFKinkDecayTables.h index 0b9137d64b1..a8a5cffa8a3 100644 --- a/PWGLF/DataModel/LFKinkDecayTables.h +++ b/PWGLF/DataModel/LFKinkDecayTables.h @@ -25,6 +25,7 @@ #include #include +#include namespace o2::aod { @@ -162,13 +163,12 @@ DECLARE_SOA_TABLE(SlimKinkCandsMC, "AOD", "SLIMKINKCANDSMC", namespace sigmapluscand { -DECLARE_SOA_COLUMN(XDecVtx, xDecVtx, float); //! Decay vertex of the candidate (x direction) -DECLARE_SOA_COLUMN(YDecVtx, yDecVtx, float); //! Decay vertex of the candidate (y direction) -DECLARE_SOA_COLUMN(ZDecVtx, zDecVtx, float); //! Decay vertex of the candidate (z direction) -DECLARE_SOA_COLUMN(Radius, radius, float); //! Decay radius of the candidate (cm) -DECLARE_SOA_COLUMN(FlightDistance, flightDistance, float); //! Flight distance of the candidate (PV to decay vertex, cm) -DECLARE_SOA_COLUMN(DcaProtonGamma, dcaProtonGamma, float); //! DCA between proton and photon at the fitted vertex (cm) -DECLARE_SOA_COLUMN(Chi2, chi2, float); //! chi2 of the proton-photon vertex fit +DECLARE_SOA_COLUMN(XDecVtx, xDecVtx, float); //! Decay vertex of the candidate (x direction) +DECLARE_SOA_COLUMN(YDecVtx, yDecVtx, float); //! Decay vertex of the candidate (y direction) +DECLARE_SOA_COLUMN(ZDecVtx, zDecVtx, float); //! Decay vertex of the candidate (z direction) +DECLARE_SOA_COLUMN(FlightDistance, flightDistance, float); //! 3D distance from the PV to the decay vertex (cm) +DECLARE_SOA_COLUMN(TransDecayRadius, transDecayRadius, float); //! Transverse decay radius of the candidate (cm), stored directly in the slim tables (no XDecVtx/YDecVtx there) +DECLARE_SOA_COLUMN(DcaProtonGamma, dcaProtonGamma, float); //! DCA between proton and photon at the fitted vertex (cm) DECLARE_SOA_COLUMN(PxProton, pxProton, float); //! Px of the proton DECLARE_SOA_COLUMN(PyProton, pyProton, float); //! Py of the proton @@ -193,6 +193,11 @@ DECLARE_SOA_COLUMN(PhotonOpeningAngle, photonOpeningAngle, float); //! Opening DECLARE_SOA_COLUMN(PhotonPointingAngle, photonPointingAngle, float); //! Angle between the photon momentum and the line from its conversion point to the candidate decay vertex (rad) DECLARE_SOA_COLUMN(PhotonDcaToPV, photonDcaToPV, float); //! DCA of the photon's flight line to the primary vertex (cm) +DECLARE_SOA_COLUMN(RootCenter, rootCenter, float); //! -coefB/(2*coefA) of the missing-photon quadratic solve: negative flags an unphysical phase-space point +DECLARE_SOA_COLUMN(AntiSigmaPointingAngle, antiSigmaPointingAngle, float); //! Angle between the field-unbent proton momentum (from its original reference point) and the PV->decay-vertex direction +DECLARE_SOA_COLUMN(CandDcaToPV, candDcaToPV, float); //! DCA of the candidate's total reconstructed momentum line to the PV (cm) + +DECLARE_SOA_COLUMN(ProtonSign, protonSign, int); //! Charge sign of the proton track (= sign of the whole candidate, since the photon is neutral) DECLARE_SOA_COLUMN(ProtonItsNCls, protonItsNCls, uint8_t); //! Number of ITS clusters of the proton track DECLARE_SOA_COLUMN(ProtonTpcNCls, protonTpcNCls, int16_t); //! Number of found TPC clusters of the proton track DECLARE_SOA_COLUMN(ProtonDcaXY, protonDcaXY, float); //! DCA of the proton track to the primary vertex, xy (cm) @@ -204,26 +209,33 @@ DECLARE_SOA_COLUMN(PhotonNegItsNCls, photonNegItsNCls, uint8_t); //! Number of I DECLARE_SOA_COLUMN(PhotonNegTpcNCls, photonNegTpcNCls, int16_t); //! Number of found TPC clusters of the photon's negative daughter // MC columns -DECLARE_SOA_COLUMN(IsSignal, isSignal, bool); //! True if proton and photon are MC-truth matched to the same Sigma+ - -DECLARE_SOA_COLUMN(ProtonPdgCode, protonPdgCode, int); //! PDG code of the proton's MC particle -DECLARE_SOA_COLUMN(ProtonMotherPdgCode, protonMotherPdgCode, int); //! PDG code of the proton's MC mother -DECLARE_SOA_COLUMN(GammaPdgCode, gammaPdgCode, int); //! PDG code of the measured photon's MC particle -DECLARE_SOA_COLUMN(GammaMotherPdgCode, gammaMotherPdgCode, int); //! PDG code of the photon's MC mother (expected: pi0) -DECLARE_SOA_COLUMN(GammaGMotherPdgCode, gammaGMotherPdgCode, int); //! PDG code of the photon's MC grandmother (expected: Sigma+) - -DECLARE_SOA_COLUMN(XDecVtxMC, xDecVtxMC, float); //! MC-truth Sigma+ decay vertex (x direction) -DECLARE_SOA_COLUMN(YDecVtxMC, yDecVtxMC, float); //! MC-truth Sigma+ decay vertex (y direction) -DECLARE_SOA_COLUMN(ZDecVtxMC, zDecVtxMC, float); //! MC-truth Sigma+ decay vertex (z direction) -DECLARE_SOA_COLUMN(PxProtonMC, pxProtonMC, float); //! MC-truth proton Px -DECLARE_SOA_COLUMN(PyProtonMC, pyProtonMC, float); //! MC-truth proton Py -DECLARE_SOA_COLUMN(PzProtonMC, pzProtonMC, float); //! MC-truth proton Pz -DECLARE_SOA_COLUMN(PxGammaMC, pxGammaMC, float); //! MC-truth momentum of the measured photon (Px) -DECLARE_SOA_COLUMN(PyGammaMC, pyGammaMC, float); //! MC-truth momentum of the measured photon (Py) -DECLARE_SOA_COLUMN(PzGammaMC, pzGammaMC, float); //! MC-truth momentum of the measured photon (Pz) +DECLARE_SOA_COLUMN(CollisionIdCheck, collisionIdCheck, bool); //! True if the proton's collision ID matches the reconstructed collision ID + +DECLARE_SOA_COLUMN(IsSignal, isSignal, bool); //! True if the proton and photon share the same true Sigma+ mother + +DECLARE_SOA_COLUMN(XDecVtxMC, xDecVtxMC, float); //! MC-truth Sigma+ decay vertex (x direction) +DECLARE_SOA_COLUMN(YDecVtxMC, yDecVtxMC, float); //! MC-truth Sigma+ decay vertex (y direction) +DECLARE_SOA_COLUMN(ZDecVtxMC, zDecVtxMC, float); //! MC-truth Sigma+ decay vertex (z direction) +DECLARE_SOA_COLUMN(DecayRadiusMC, decayRadiusMC, float); //! MC-truth Sigma+ decay radius +DECLARE_SOA_COLUMN(MassMC, massMC, float); //! MC-truth invariant mass of the Sigma+ mother +DECLARE_SOA_COLUMN(PxSigmaPlusMC, pxSigmaPlusMC, float); //! MC-truth Sigma+ mother Px +DECLARE_SOA_COLUMN(PySigmaPlusMC, pySigmaPlusMC, float); //! MC-truth Sigma+ mother Py +DECLARE_SOA_COLUMN(PzSigmaPlusMC, pzSigmaPlusMC, float); //! MC-truth Sigma+ mother Pz +DECLARE_SOA_COLUMN(PxProtonMC, pxProtonMC, float); //! MC-truth proton Px +DECLARE_SOA_COLUMN(PyProtonMC, pyProtonMC, float); //! MC-truth proton Py +DECLARE_SOA_COLUMN(PzProtonMC, pzProtonMC, float); //! MC-truth proton Pz +DECLARE_SOA_COLUMN(PxGammaMC, pxGammaMC, float); //! MC-truth momentum of the measured photon (Px) +DECLARE_SOA_COLUMN(PyGammaMC, pyGammaMC, float); //! MC-truth momentum of the measured photon (Py) +DECLARE_SOA_COLUMN(PzGammaMC, pzGammaMC, float); //! MC-truth momentum of the measured photon (Pz) // DYNAMIC COLUMNS +DECLARE_SOA_DYNAMIC_COLUMN(Radius, radius, //! Transverse decay radius of the candidate (cm), from the beam axis + [](float xDecVtx, float yDecVtx) -> float { return std::hypot(xDecVtx, yDecVtx); }); + +DECLARE_SOA_DYNAMIC_COLUMN(Chi2, chi2, //! chi2 of the proton-photon vertex fit; dcaProtonGamma = sqrt(chi2) by construction in the builder + [](float dcaProtonGamma) -> float { return dcaProtonGamma * dcaProtonGamma; }); + DECLARE_SOA_DYNAMIC_COLUMN(PxSigmaPlus, pxSigmaPlus, //! Px of the Sigma+ candidate [](float pxProton, float pxGamma1, float pxGamma2) -> float { return pxProton + pxGamma1 + pxGamma2; }); @@ -244,12 +256,17 @@ DECLARE_SOA_DYNAMIC_COLUMN(MassSigmaPlus, massSigmaPlus, //! Invariant mass of t std::array{pxGamma2, pyGamma2, pzGamma2}}, std::array{o2::constants::physics::MassProton, o2::constants::physics::MassGamma, o2::constants::physics::MassGamma}); }); +DECLARE_SOA_DYNAMIC_COLUMN(PtSigmaPlusMC, ptSigmaPlusMC, //! True pT of the Sigma+ mother + [](float pxSigmaPlusMC, float pySigmaPlusMC) -> float { return std::hypot(pxSigmaPlusMC, pySigmaPlusMC); }); + +DECLARE_SOA_DYNAMIC_COLUMN(YSigmaPlusMC, ySigmaPlusMC, //! True rapidity of the Sigma+ mother + [](float pxSigmaPlusMC, float pySigmaPlusMC, float pzSigmaPlusMC) -> float { return RecoDecay::y(std::array{pxSigmaPlusMC, pySigmaPlusMC, pzSigmaPlusMC}, o2::constants::physics::MassSigmaPlus); }); + } // namespace sigmapluscand DECLARE_SOA_TABLE(SigmaPlusCands, "AOD", "SIGMAPLUSCANDS", - sigmapluscand::XDecVtx, sigmapluscand::YDecVtx, sigmapluscand::ZDecVtx, - sigmapluscand::Radius, sigmapluscand::FlightDistance, - sigmapluscand::DcaProtonGamma, sigmapluscand::Chi2, + sigmapluscand::XDecVtx, sigmapluscand::YDecVtx, sigmapluscand::ZDecVtx, sigmapluscand::FlightDistance, + sigmapluscand::DcaProtonGamma, sigmapluscand::PxProton, sigmapluscand::PyProton, sigmapluscand::PzProton, sigmapluscand::PxGamma1, sigmapluscand::PyGamma1, sigmapluscand::PzGamma1, sigmapluscand::PxGamma2, sigmapluscand::PyGamma2, sigmapluscand::PzGamma2, @@ -257,10 +274,14 @@ DECLARE_SOA_TABLE(SigmaPlusCands, "AOD", "SIGMAPLUSCANDS", sigmapluscand::NSigmaTPCElPos, sigmapluscand::NSigmaTPCElNeg, sigmapluscand::PhotonMass, sigmapluscand::PhotonAlpha, sigmapluscand::PhotonQt, sigmapluscand::PhotonConvRadius, sigmapluscand::PhotonOpeningAngle, sigmapluscand::PhotonPointingAngle, sigmapluscand::PhotonDcaToPV, + sigmapluscand::RootCenter, sigmapluscand::AntiSigmaPointingAngle, sigmapluscand::CandDcaToPV, + sigmapluscand::ProtonSign, sigmapluscand::ProtonItsNCls, sigmapluscand::ProtonTpcNCls, sigmapluscand::ProtonDcaXY, sigmapluscand::ProtonDcaZ, sigmapluscand::PhotonPosItsNCls, sigmapluscand::PhotonPosTpcNCls, sigmapluscand::PhotonNegItsNCls, sigmapluscand::PhotonNegTpcNCls, // dynamic columns + sigmapluscand::Radius, + sigmapluscand::Chi2, sigmapluscand::PxSigmaPlus, sigmapluscand::PySigmaPlus, sigmapluscand::PzSigmaPlus, @@ -268,9 +289,8 @@ DECLARE_SOA_TABLE(SigmaPlusCands, "AOD", "SIGMAPLUSCANDS", sigmapluscand::MassSigmaPlus); DECLARE_SOA_TABLE(SigmaPlusCandsMC, "AOD", "SIGMAPLUSMC", - sigmapluscand::XDecVtx, sigmapluscand::YDecVtx, sigmapluscand::ZDecVtx, - sigmapluscand::Radius, sigmapluscand::FlightDistance, - sigmapluscand::DcaProtonGamma, sigmapluscand::Chi2, + sigmapluscand::XDecVtx, sigmapluscand::YDecVtx, sigmapluscand::ZDecVtx, sigmapluscand::FlightDistance, + sigmapluscand::DcaProtonGamma, sigmapluscand::PxProton, sigmapluscand::PyProton, sigmapluscand::PzProton, sigmapluscand::PxGamma1, sigmapluscand::PyGamma1, sigmapluscand::PzGamma1, sigmapluscand::PxGamma2, sigmapluscand::PyGamma2, sigmapluscand::PzGamma2, @@ -278,14 +298,41 @@ DECLARE_SOA_TABLE(SigmaPlusCandsMC, "AOD", "SIGMAPLUSMC", sigmapluscand::NSigmaTPCElPos, sigmapluscand::NSigmaTPCElNeg, sigmapluscand::PhotonMass, sigmapluscand::PhotonAlpha, sigmapluscand::PhotonQt, sigmapluscand::PhotonConvRadius, sigmapluscand::PhotonOpeningAngle, sigmapluscand::PhotonPointingAngle, sigmapluscand::PhotonDcaToPV, + sigmapluscand::RootCenter, sigmapluscand::AntiSigmaPointingAngle, sigmapluscand::CandDcaToPV, + sigmapluscand::ProtonSign, sigmapluscand::ProtonItsNCls, sigmapluscand::ProtonTpcNCls, sigmapluscand::ProtonDcaXY, sigmapluscand::ProtonDcaZ, sigmapluscand::PhotonPosItsNCls, sigmapluscand::PhotonPosTpcNCls, sigmapluscand::PhotonNegItsNCls, sigmapluscand::PhotonNegTpcNCls, + sigmapluscand::CollisionIdCheck, sigmapluscand::IsSignal, - sigmapluscand::ProtonPdgCode, sigmapluscand::ProtonMotherPdgCode, - sigmapluscand::GammaPdgCode, sigmapluscand::GammaMotherPdgCode, sigmapluscand::GammaGMotherPdgCode, sigmapluscand::XDecVtxMC, sigmapluscand::YDecVtxMC, sigmapluscand::ZDecVtxMC, sigmapluscand::PxProtonMC, sigmapluscand::PyProtonMC, sigmapluscand::PzProtonMC, sigmapluscand::PxGammaMC, sigmapluscand::PyGammaMC, sigmapluscand::PzGammaMC, + sigmapluscand::PxSigmaPlusMC, sigmapluscand::PySigmaPlusMC, sigmapluscand::PzSigmaPlusMC, + sigmapluscand::DecayRadiusMC, sigmapluscand::MassMC, + + // dynamic columns + sigmapluscand::Radius, + sigmapluscand::Chi2, + sigmapluscand::PxSigmaPlus, + sigmapluscand::PySigmaPlus, + sigmapluscand::PzSigmaPlus, + sigmapluscand::PtSigmaPlus, + sigmapluscand::MassSigmaPlus, + sigmapluscand::PtSigmaPlusMC, + sigmapluscand::YSigmaPlusMC); + +DECLARE_SOA_TABLE(SlimSigmaPlusCands, "AOD", "SLIMSIGMAPLUS", + sigmapluscand::TransDecayRadius, + sigmapluscand::CandDcaToPV, + sigmapluscand::DcaProtonGamma, + sigmapluscand::ProtonSign, + sigmapluscand::ProtonDcaXY, sigmapluscand::ProtonDcaZ, + sigmapluscand::PxProton, sigmapluscand::PyProton, sigmapluscand::PzProton, + sigmapluscand::PxGamma1, sigmapluscand::PyGamma1, sigmapluscand::PzGamma1, + sigmapluscand::PxGamma2, sigmapluscand::PyGamma2, sigmapluscand::PzGamma2, + sigmapluscand::NSigmaTPCProton, sigmapluscand::NSigmaTOFProton, + sigmapluscand::NSigmaTPCElPos, sigmapluscand::NSigmaTPCElNeg, + sigmapluscand::PhotonMass, // dynamic columns sigmapluscand::PxSigmaPlus, @@ -294,6 +341,32 @@ DECLARE_SOA_TABLE(SigmaPlusCandsMC, "AOD", "SIGMAPLUSMC", sigmapluscand::PtSigmaPlus, sigmapluscand::MassSigmaPlus); +DECLARE_SOA_TABLE(SlimSigmaPlusCandsMC, "AOD", "SLIMSIGMAPLUSMC", + sigmapluscand::TransDecayRadius, + sigmapluscand::CandDcaToPV, + sigmapluscand::DcaProtonGamma, + sigmapluscand::ProtonSign, + sigmapluscand::ProtonDcaXY, sigmapluscand::ProtonDcaZ, + sigmapluscand::PxProton, sigmapluscand::PyProton, sigmapluscand::PzProton, + sigmapluscand::PxGamma1, sigmapluscand::PyGamma1, sigmapluscand::PzGamma1, + sigmapluscand::PxGamma2, sigmapluscand::PyGamma2, sigmapluscand::PzGamma2, + sigmapluscand::NSigmaTPCProton, sigmapluscand::NSigmaTOFProton, + sigmapluscand::NSigmaTPCElPos, sigmapluscand::NSigmaTPCElNeg, + sigmapluscand::PhotonMass, + sigmapluscand::CollisionIdCheck, + sigmapluscand::IsSignal, + sigmapluscand::DecayRadiusMC, sigmapluscand::MassMC, + sigmapluscand::PxSigmaPlusMC, sigmapluscand::PySigmaPlusMC, sigmapluscand::PzSigmaPlusMC, + + // dynamic columns + sigmapluscand::PxSigmaPlus, + sigmapluscand::PySigmaPlus, + sigmapluscand::PzSigmaPlus, + sigmapluscand::PtSigmaPlus, + sigmapluscand::MassSigmaPlus, + sigmapluscand::PtSigmaPlusMC, + sigmapluscand::YSigmaPlusMC); + } // namespace o2::aod #endif // PWGLF_DATAMODEL_LFKINKDECAYTABLES_H_ diff --git a/PWGLF/DataModel/LFNonPromptCascadeTables.h b/PWGLF/DataModel/LFNonPromptCascadeTables.h index cfef032b6a2..25449bc2f81 100644 --- a/PWGLF/DataModel/LFNonPromptCascadeTables.h +++ b/PWGLF/DataModel/LFNonPromptCascadeTables.h @@ -132,6 +132,9 @@ DECLARE_SOA_COLUMN(EtaGen, etaGen, float); DECLARE_SOA_COLUMN(EtaRec, etaRec, float); DECLARE_SOA_COLUMN(MultGen, multGen, int); DECLARE_SOA_COLUMN(MultGenFT0, multGenFT0, int); +DECLARE_SOA_COLUMN(McCollisionId, mcCollisionId, int); +DECLARE_SOA_COLUMN(RecoCollisionId, recoCollisionId, int); +DECLARE_SOA_COLUMN(McParticleId, mcParticleId, int); } // namespace NPCascadeTable DECLARE_SOA_TABLE(NPCascTable, "AOD", "NPCASCTABLE", @@ -456,6 +459,9 @@ DECLARE_SOA_TABLE(NPCascTableGen, "AOD", "NPCASCTABLEGen", NPCascadeTable::IsFromCharm, NPCascadeTable::MotherDecayDaughters); DECLARE_SOA_TABLE(NPMCChargedTable, "AOD", "NPMCChargedTABLE", + NPCascadeTable::McCollisionId, + NPCascadeTable::RecoCollisionId, + NPCascadeTable::McParticleId, NPCascadeTable::PtGen, NPCascadeTable::PtRec, NPCascadeTable::EtaGen, @@ -465,6 +471,15 @@ DECLARE_SOA_TABLE(NPMCChargedTable, "AOD", "NPMCChargedTABLE", NPCascadeTable::MultGenFT0, NPCascadeTable::MultFT0M, NPCascadeTable::CentFT0M); +DECLARE_SOA_TABLE(NPMCRecoCollisionAssoc, "AOD", "NPMCRecoCollAssn", + NPCascadeTable::McCollisionId, + NPCascadeTable::RecoCollisionId, + NPCascadeTable::MultNTracksNP, + NPCascadeTable::MultGen, + NPCascadeTable::MultGenFT0, + NPCascadeTable::MultFT0M, + NPCascadeTable::CentFT0M, + NPCascadeTable::NoSameBunchPileup); DECLARE_SOA_TABLE(NPCollisionTable, "AOD", "NPCollisionTABLE", NPCascadeTable::RunNumber, NPCascadeTable::GlobalBC, diff --git a/PWGLF/DataModel/LFReducedXi1530KaonTables.h b/PWGLF/DataModel/LFReducedXi1530KaonTables.h new file mode 100644 index 00000000000..7a466201a0b --- /dev/null +++ b/PWGLF/DataModel/LFReducedXi1530KaonTables.h @@ -0,0 +1,379 @@ +// 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. + +/// \file LFReducedXi1530KaonTables.h +/// \brief Reduced data model for Xi(1530)^0--K femtoscopy. +/// +/// The Xi(1530) candidate stores two independent uint64_t selection words: +/// * TrackSelectionBits: daughter PID / track-quality / prompt-pion DCAz; +/// * TopologySelectionBits: Lambda/V0 and Xi/cascade topology, mass and +/// lifetime working points. +/// +/// This split keeps the table compact while retaining both: +/// * the Xi(1530) analysis-note working points/systematic variations; and +/// * the pp Xi-candidate selections used in Run 3 strangeness production. +/// +/// +/// External-kaon DCA choices remain in a compact uint8_t bitmap; raw TPC/TOF +/// n-sigma values are retained for downstream PID studies. + +#ifndef PWGLF_DATAMODEL_LFREDUCEDXI1530KAONTABLES_H_ +#define PWGLF_DATAMODEL_LFREDUCEDXI1530KAONTABLES_H_ + +#include +#include + +#include +#include + +namespace o2::aod +{ + +namespace redxistark +{ +// +1: Xi- pi+ US; -1: anti-Xi+ pi- US; +2/-2: corresponding LS controls. +enum XiStarChannel : int8_t { + kXiStarUS = +1, + kAntiXiStarUS = -1, + kXiStarLS = +2, + kAntiXiStarLS = -2 +}; + +// ----------------------------------------------------------------------------- +// TRACK/PID SELECTION WORD +// ----------------------------------------------------------------------------- +// Bit positions only; numerical thresholds live in producer Configurables. +enum XiStarTrackSelBit : uint8_t { + // Prompt Xi* pion, recipe A: + // no TOF -> TPC only; TOF -> circular sqrt(TPC^2+TOF^2). + kPiFirstPID3Sigma = 0, + kPiFirstPID4Sigma, + kPiFirstPID5Sigma, + kPiFirstPID6Sigma, + + // Prompt Xi* pion, recipe B: + // TPC-only below configurable pT threshold, circular above it. + kPiFirstPtThresholdPID3Sigma, + kPiFirstPtThresholdPID4Sigma, + kPiFirstPtThresholdPID5Sigma, + kPiFirstPtThresholdPID6Sigma, + + // Prompt Xi* pion, pure TPC-only PID. These bits allow the analysis + // to reproduce a TPC-only "all pion tracks" PID strategy downstream, + // independent of whether the prompt pion also has TOF information. + kPiFirstTPC3Sigma, + kPiFirstTPC4Sigma, + kPiFirstTPC5Sigma, + kPiFirstTPC6Sigma, + + // Xi bachelor pion, availability-based hybrid PID. + kXiBachelorPiHybridPID3Sigma, + kXiBachelorPiHybridPID4Sigma, + kXiBachelorPiHybridPID5Sigma, + kXiBachelorPiHybridPID6Sigma, + + // Xi bachelor pion, TPC-only PID. The 4.8-sigma point reproduces the + // dedicated pp-Xi table. + kXiBachelorPiTPC3Sigma, + kXiBachelorPiTPC4Sigma, + kXiBachelorPiTPC4p8Sigma, + kXiBachelorPiTPC5Sigma, + kXiBachelorPiTPC6Sigma, + + // Lambda daughter pion: TPC only. + kLambdaPiTPC3Sigma, + kLambdaPiTPC4Sigma, + kLambdaPiTPC4p8Sigma, + kLambdaPiTPC5Sigma, + kLambdaPiTPC6Sigma, + + // Lambda daughter proton: TPC only. + kLambdaPrTPC3Sigma, + kLambdaPrTPC4Sigma, + kLambdaPrTPC5Sigma, + kLambdaPrTPC6Sigma, + + // Prompt-pion quality. + kPiFirstTPCRows70, + kPiFirstTPCRows80, + kPiFirstTPCRows90, + kPiFirstDCAz1cm, + kPiFirstDCAzDefault, + kPiFirstDCAz0p1cm, + + // Cascade-daughter quality. + kAllCascDaughtersTPCRows50, + kV0DaughtersTPCRows70, + kV0DaughtersTPCRowsVar1, + kV0DaughtersTPCRowsVar2, + + kNXiStarTrackSelBits +}; +static_assert(kNXiStarTrackSelBits <= 64, "Xi(1530) track-selection bitmap exceeds uint64_t capacity"); + +constexpr uint64_t xiStarTrackSelMask(XiStarTrackSelBit bit) +{ + return uint64_t{1} << static_cast(bit); +} + +// ----------------------------------------------------------------------------- +// TOPOLOGY SELECTION WORD +// ----------------------------------------------------------------------------- +enum XiStarTopoSelBit : uint8_t { + // V0 daughter DCA to PV. + kV0PionDcaPV005 = 0, // > 0.05 cm + kV0PionDcaPV006, // > 0.06 cm + kV0PionDcaPV010, // > 0.10 cm + kV0PionDcaPV020, // > 0.20 cm (dedicated Lambda) + + kV0ProtonDcaPV005, // > 0.05 cm + kV0ProtonDcaPV006, // > 0.06 cm + kV0ProtonDcaPV007, // > 0.07 cm (dedicated Lambda) + kV0ProtonDcaPV010, // > 0.10 cm + + // Keep the Xi(1530)-analysis convention requested by the analysis: + // MINIMUM Lambda/V0 DCA to PV. + kV0DcaPV000, // > 0.00 cm + kV0DcaPV003, // > 0.03 cm + kV0DcaPV010, // > 0.10 cm + + // DCA between V0 daughters / native fitter metric. + kV0DcaDaughters1p0, // < 1.0 + kV0DcaDaughters0p5, // < 0.5 + kV0DcaDaughters0p1, // < 0.1 + + // V0 pointing angle. + kV0CosPA097, + kV0CosPA098, + kV0CosPA09876, // pp-Xi selection + kV0CosPA099, + kV0CosPA0995, // dedicated Lambda selection + + // Minimum V0 radius. + kV0Radius0p9, + kV0Radius1p01, + kV0Radius1p2, // pp-Xi selection + kV0Radius2p5, + kV0Radius3p0, // dedicated Lambda selection + + // Lambda mass window. + kLambdaMass10MeV, + kLambdaMass8MeV, + kLambdaMass6MeV, + kLambdaMass11p6MeV, // pp-Xi selection + + // Lambda proper lifetime. Var1/Var2 are reserved for future systematic + // values; their defaults can equal the nominal until values are supplied. + kV0LifetimeDefault, + kV0LifetimeVar1, + kV0LifetimeVar2, + + // Xi bachelor DCA to PV. + kCascBachelorDcaPV005, + kCascBachelorDcaPV006, + kCascBachelorDcaPV010, + + // DCA between bachelor and V0 / native cascade fitter metric. + kCascDcaDaughters1p0, + kCascDcaDaughters0p25, + kCascDcaDaughters0p20, + + // Cascade pointing angle. + kCascCosPA097, + kCascCosPA098, + kCascCosPA09947, // pp-Xi selection + kCascCosPA0995, + + // Minimum cascade radius. + kCascRadius0p9, + kCascRadius1p0, // pp-Xi selection + kCascRadius1p01, + kCascRadius1p3, + + // Xi mass window used by the Xi(1530) analysis. + kXiMass10MeV, + kXiMass8MeV, + kXiMass6MeV, + + // Xi proper-lifetime working points (mL/p in cm). + // Numerical thresholds are Configurable in the producer. + kXiLifetimeDefault, // default: 22.6 cm (~4.6*c*tau_Xi) + kXiLifetimeVar1, // default variation: 15 cm + kXiLifetimeVar2, // default variation: 12 cm + + // Additional pp-Xi cuts. + kBachBaryonDCAxy0020, // > 0.020 cm + kXiRapidity05, // |y_Xi| < 0.5 + + kNXiStarTopoSelBits +}; +static_assert(kNXiStarTopoSelBits <= 64, "Xi(1530) topology-selection bitmap exceeds uint64_t capacity"); + +constexpr uint64_t xiStarTopoSelMask(XiStarTopoSelBit bit) +{ + return uint64_t{1} << static_cast(bit); +} + +} // namespace redxistark + +// ----------------------------------------------------------------------------- +// Event table +// ----------------------------------------------------------------------------- +namespace redxistarkevent +{ +DECLARE_SOA_COLUMN(FT0MPercentile, fT0MPercentile, float); //! FT0M multiplicity percentile (%) +DECLARE_SOA_COLUMN(Bz, bz, float); //! nominal L3 magnetic field along z (T) +} // namespace redxistarkevent + +DECLARE_SOA_TABLE(RedXiStarKEvents, "AOD", "REDXISTARKEVENT", + o2::soa::Index<>, + collision::PosZ, + collision::NumContrib, + redxistarkevent::FT0MPercentile, + redxistarkevent::Bz); +using RedXiStarKEvent = RedXiStarKEvents::iterator; + +// ----------------------------------------------------------------------------- +// Xi(1530) candidate table +// ----------------------------------------------------------------------------- +namespace redxistarcandidate +{ +DECLARE_SOA_INDEX_COLUMN(RedXiStarKEvent, redXiStarKEvent); + +DECLARE_SOA_COLUMN(Channel, channel, int8_t); +DECLARE_SOA_COLUMN(Px, px, float); +DECLARE_SOA_COLUMN(Py, py, float); +DECLARE_SOA_COLUMN(Pz, pz, float); +DECLARE_SOA_COLUMN(Mass, mass, float); //! reconstructed M(Xi pi) + +DECLARE_SOA_COLUMN(TrackSelectionBits, trackSelectionBits, uint64_t); +DECLARE_SOA_COLUMN(TopologySelectionBits, topologySelectionBits, uint64_t); + +// Prompt-pion kinematics are stored for downstream CPR QA. The three +// displaced Xi daughters remain ID-only. +DECLARE_SOA_COLUMN(XiStarPionPt, xiStarPionPt, float); +DECLARE_SOA_COLUMN(XiStarPionEta, xiStarPionEta, float); +DECLARE_SOA_COLUMN(XiStarPionPhi, xiStarPionPhi, float); +DECLARE_SOA_COLUMN(XiStarPionIndex, xiStarPionIndex, int64_t); +DECLARE_SOA_COLUMN(XiBachelorIndex, xiBachelorIndex, int64_t); +DECLARE_SOA_COLUMN(V0PositiveIndex, v0PositiveIndex, int64_t); +DECLARE_SOA_COLUMN(V0NegativeIndex, v0NegativeIndex, int64_t); + +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float px, float py) -> float { + return std::sqrt(px * px + py * py); +}); +DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float px, float py, float pz) -> float { + return std::sqrt(px * px + py * py + pz * pz); +}); +DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, [](float px, float py, float pz) -> float { + const float pt = std::sqrt(px * px + py * py); + return pt > 0.f ? std::asinh(pz / pt) : 0.f; +}); +DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, [](float px, float py) -> float { + return std::atan2(py, px); +}); +} // namespace redxistarcandidate + +DECLARE_SOA_TABLE(XiStarCandidates, "AOD", "REDXSTARCAND", + o2::soa::Index<>, + redxistarcandidate::RedXiStarKEventId, + redxistarcandidate::Channel, + redxistarcandidate::Px, + redxistarcandidate::Py, + redxistarcandidate::Pz, + redxistarcandidate::Mass, + redxistarcandidate::TrackSelectionBits, + redxistarcandidate::TopologySelectionBits, + redxistarcandidate::XiStarPionPt, + redxistarcandidate::XiStarPionEta, + redxistarcandidate::XiStarPionPhi, + redxistarcandidate::XiStarPionIndex, + redxistarcandidate::XiBachelorIndex, + redxistarcandidate::V0PositiveIndex, + redxistarcandidate::V0NegativeIndex, + redxistarcandidate::Pt, + redxistarcandidate::P, + redxistarcandidate::Eta, + redxistarcandidate::Phi); +using XiStarCandidate = XiStarCandidates::iterator; + +// ----------------------------------------------------------------------------- +// External primary-kaon table +// ----------------------------------------------------------------------------- +namespace redxistarkaon +{ +DECLARE_SOA_INDEX_COLUMN(RedXiStarKEvent, redXiStarKEvent); + +enum KaonSelBit : uint8_t { + kKaonDCAxyDefault = 0, + kKaonDCAxyVar1, + kKaonDCAxyVar2, + kKaonDCAzDefault, + kKaonDCAzVar1, + kKaonDCAzVar2, + kNKaonSelBits +}; +static_assert(kNKaonSelBits <= 8, "Kaon selection bitmap exceeds uint8_t capacity"); + +constexpr uint8_t kaonSelMask(KaonSelBit bit) +{ + return uint8_t{1} << static_cast(bit); +} + +DECLARE_SOA_COLUMN(Charge, charge, int8_t); +DECLARE_SOA_COLUMN(Px, px, float); +DECLARE_SOA_COLUMN(Py, py, float); +DECLARE_SOA_COLUMN(Pz, pz, float); +DECLARE_SOA_COLUMN(TrackIndex, trackIndex, int64_t); +DECLARE_SOA_COLUMN(SelectionBits, selectionBits, uint8_t); + +DECLARE_SOA_COLUMN(TPCNClsCrossedRows, tPCNClsCrossedRows, uint8_t); +DECLARE_SOA_COLUMN(TPCNSigmaKa, tPCNSigmaKa, float); +DECLARE_SOA_COLUMN(TOFNSigmaKa, tOFNSigmaKa, float); +DECLARE_SOA_COLUMN(HasTOF, hasTOF, bool); + +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float px, float py) -> float { + return std::sqrt(px * px + py * py); +}); +DECLARE_SOA_DYNAMIC_COLUMN(P, p, [](float px, float py, float pz) -> float { + return std::sqrt(px * px + py * py + pz * pz); +}); +DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, [](float px, float py, float pz) -> float { + const float pt = std::sqrt(px * px + py * py); + return pt > 0.f ? std::asinh(pz / pt) : 0.f; +}); +DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, [](float px, float py) -> float { + return std::atan2(py, px); +}); +} // namespace redxistarkaon + +DECLARE_SOA_TABLE(KaonCandidates, "AOD", "REDXSTARKAON", + o2::soa::Index<>, + redxistarkaon::RedXiStarKEventId, + redxistarkaon::Charge, + redxistarkaon::Px, + redxistarkaon::Py, + redxistarkaon::Pz, + redxistarkaon::TrackIndex, + redxistarkaon::SelectionBits, + redxistarkaon::TPCNClsCrossedRows, + redxistarkaon::TPCNSigmaKa, + redxistarkaon::TOFNSigmaKa, + redxistarkaon::HasTOF, + redxistarkaon::Pt, + redxistarkaon::P, + redxistarkaon::Eta, + redxistarkaon::Phi); +using KaonCandidate = KaonCandidates::iterator; + +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_LFREDUCEDXI1530KAONTABLES_H_ diff --git a/PWGLF/DataModel/LFResonanceTables.h b/PWGLF/DataModel/LFResonanceTables.h index 11fd45842ef..673d2ae8393 100644 --- a/PWGLF/DataModel/LFResonanceTables.h +++ b/PWGLF/DataModel/LFResonanceTables.h @@ -38,6 +38,7 @@ #include #include #include +#include namespace o2::aod { @@ -66,6 +67,7 @@ enum { }; DECLARE_SOA_INDEX_COLUMN_FULL(Collision, collision, int, Collisions, "_Col"); //! DECLARE_SOA_COLUMN(Cent, cent, float); //! Centrality (Multiplicity) percentile (Default: FT0M) +DECLARE_SOA_COLUMN(Multiplicity, multiplicity, float); //! Configurable reconstructed multiplicity estimator DECLARE_SOA_COLUMN(Spherocity, spherocity, float); //! Spherocity of the event DECLARE_SOA_COLUMN(EvtPl, evtPl, float); //! Second harmonic event plane DECLARE_SOA_COLUMN(EvtPlResAB, evtPlResAB, float); //! Second harmonic event plane resolution of A-B sub events @@ -84,16 +86,33 @@ DECLARE_SOA_COLUMN(MCMultiplicity, mcMultiplicity, float); //! MC Multiplicit } // namespace resocollision -// Keep the established ResoCollisionColls schema above unchanged. Automatic -// GroupSlicer association to aod::Collisions requires the canonical physical -// column name fIndexCollisions, so the modular initializer writes this small -// companion table for the hybrid daughter process. +// Legacy version-0 companion schema. Its canonical fIndexCollisions column +// enables GroupSlicer association to aod::Collisions, but also makes the table +// dependent on that source parent. The modular initializer therefore writes +// the scalar-only version 001 declared below instead. namespace resocollisiongroup { DECLARE_SOA_INDEX_COLUMN_FULL_CUSTOM(OriginalCollision, originalCollision, int, Collisions, "Collisions", ""); //! } // namespace resocollisiongroup -DECLARE_SOA_TABLE(ResoCollisions, "AOD", "RESOCOLLISION", +// Scalar-only original-collision mapping for standalone modular output. Unlike +// resocollisiongroup::OriginalCollisionId above, this column carries no index +// target metadata and therefore does not require the source Collisions table +// to be present while merging the derived AO2D. +namespace resocollisiongroup001 +{ +DECLARE_SOA_COLUMN(OriginalCollisionId, originalCollisionId, int); //! Original aod::Collision row number +} // namespace resocollisiongroup001 + +// Optional soft link from a positional ResoMCCollisions_001 row to its source +// generator collision. It is filled only when the source AO2D is retained as +// a linked-derived-data parent. +namespace resomccollision +{ +DECLARE_SOA_INDEX_COLUMN_FULL_CUSTOM(OriginalMcCollision, originalMcCollision, int, McCollisions, "McCollisions", "_MC"); //! +} // namespace resomccollision + +DECLARE_SOA_TABLE(ResoCollisions_000, "AOD", "RESOCOLLISION", o2::soa::Index<>, o2::aod::mult::MultNTracksPV, o2::aod::mult::MultNTracksPVeta1, @@ -104,6 +123,23 @@ DECLARE_SOA_TABLE(ResoCollisions, "AOD", "RESOCOLLISION", resocollision::Cent, resocollision::BMagField, resocollision::IsRecINELgt0); + +// Version 001 stores one configurable multiplicity estimator instead of three +// fixed PV-track multiplicities. The producer configuration determines which +// reconstructed estimator is persisted in the common float payload. +DECLARE_SOA_TABLE_VERSIONED(ResoCollisions_001, "AOD", "RESOCOLLISION", 1, + o2::soa::Index<>, + resocollision::Multiplicity, + collision::PosX, + collision::PosY, + collision::PosZ, + resocollision::Cent, + resocollision::BMagField, + resocollision::IsRecINELgt0); + +// Keep the established generic collision-table alias on version 000. The +// modular producer and its consumers request version 001 explicitly. +using ResoCollisions = ResoCollisions_000; using ResoCollision = ResoCollisions::iterator; DECLARE_SOA_TABLE(ResoCollisionColls, "AOD", "RESOCOLLISIONCOL", @@ -114,6 +150,12 @@ DECLARE_SOA_TABLE(ResoCollisionGroups, "AOD", "RESOCOLLGROUP", resocollisiongroup::OriginalCollisionId); using ResoCollisionGroup = ResoCollisionGroups::iterator; +// Version 001 replaces the hard relation to the source Collisions table with +// a scalar row number. The legacy version-0 schema remains unchanged. +DECLARE_SOA_TABLE_VERSIONED(ResoCollisionGroups_001, "AOD", "RESOCOLLGROUP", 1, + resocollisiongroup001::OriginalCollisionId); +using ResoCollisionGroup_001 = ResoCollisionGroups_001::iterator; + DECLARE_SOA_TABLE(ResoMCCollisions, "AOD", "RESOMCCOLLISION", o2::soa::Index<>, resocollision::IsVtxIn10, @@ -125,6 +167,20 @@ DECLARE_SOA_TABLE(ResoMCCollisions, "AOD", "RESOMCCOLLISION", resocollision::MCMultiplicity); using ResoMCCollision = ResoMCCollisions::iterator; +// Version 001 deliberately persists generator-collision properties only. +// Reconstructed event-selection decisions remain available only in legacy +// version-0 output and must not be mixed into this generator-level payload. +DECLARE_SOA_TABLE_VERSIONED(ResoMCCollisions_001, "AOD", "RESOMCCOLLISION", 1, + o2::soa::Index<>, + resocollision::IsVtxIn10, + resocollision::IsINELgt0, + resocollision::ImpactParameter, + resocollision::MCMultiplicity); + +DECLARE_SOA_TABLE(ResoMCCollisionIds, "AOD", "RESOMCCOLLID", + resomccollision::OriginalMcCollisionId); +using ResoMCCollisionId = ResoMCCollisionIds::iterator; + DECLARE_SOA_TABLE(ResoSpheroCollisions, "AOD", "RESOSPHEROCOLLISION", o2::soa::Index<>, resocollision::Spherocity); @@ -204,6 +260,12 @@ struct ResoTrackFlags { #define DECLARE_DYN_TRKSEL_COLUMN(_Name_, _Getter_, _Mask_) \ DECLARE_SOA_DYNAMIC_COLUMN(_Name_, _Getter_, [](ResoTrackFlags::flagtype flags) -> bool { return ResoTrackFlags::checkFlag(flags, _Mask_); }); +// Keep the default foreign-key target on the legacy ResoCollisions_000 alias. +// Modular v001 consumers use resoCollisionId() as the scalar row reference and +// explicitly call resoCollision_as() only when the parent row must be +// dereferenced, with T equal to the exact bound v001 table type (plain +// aod::ResoCollisions_001 or its analysis Join). The version-equivalence +// declaration below permits binding the same physical index column to v001. DECLARE_SOA_INDEX_COLUMN(ResoCollision, resoCollision); DECLARE_SOA_INDEX_COLUMN(ResoCollisionDF, resoCollisionDF); DECLARE_SOA_INDEX_COLUMN_FULL(Track, track, int, Tracks, "_Trk"); //! Soft link to the original track @@ -246,7 +308,7 @@ DECLARE_SOA_COLUMN(DecayVtxY, decayVtxY, float); DECLARE_SOA_COLUMN(DecayVtxZ, decayVtxZ, float); //! Z position of the decay vertex DECLARE_SOA_COLUMN(Alpha, alpha, float); //! Alpha of the decay vertex DECLARE_SOA_COLUMN(QtArm, qtarm, float); //! Armenteros Qt of the decay vertex, o2-linter: disable=name/o2-column (pre-existing public column name kept for schema and API compatibility) -DECLARE_SOA_COLUMN(TpcSignal10, tpcSignal10, int16_t); //! TPC signal of the track x10 +DECLARE_SOA_COLUMN(TpcSignal10, tpcSignal10, int16_t); //! TPC signal of the track x100 (public column name retained for compatibility) DECLARE_SOA_COLUMN(DaughterTPCNSigmaPosPi10, daughterTPCNSigmaPosPi10, int8_t); //! TPC PID x10 of the positive daughter as Pion DECLARE_SOA_COLUMN(DaughterTPCNSigmaPosKa10, daughterTPCNSigmaPosKa10, int8_t); //! TPC PID x10 of the positive daughter as Kaon DECLARE_SOA_COLUMN(DaughterTPCNSigmaPosPr10, daughterTPCNSigmaPosPr10, int8_t); //! TPC PID x10 of the positive daughter as Proton @@ -340,7 +402,7 @@ DECLARE_SOA_DYNAMIC_COLUMN(DaughterTOFNSigmaBachKa, daughterTOFNSigmaBachKa, [](int8_t daughterTOFNSigmaBachKa10) { return (float)daughterTOFNSigmaBachKa10 / 10.f; }); DECLARE_SOA_DYNAMIC_COLUMN(DaughterTOFNSigmaBachPr, daughterTOFNSigmaBachPr, [](int8_t daughterTOFNSigmaBachPr10) { return (float)daughterTOFNSigmaBachPr10 / 10.f; }); -// TPC signal x10 +// TPC signal x100 DECLARE_SOA_DYNAMIC_COLUMN(TpcSignal, tpcSignal, [](int16_t tpcSignal10) { return (float)tpcSignal10 / 100.f; }); // pT, Eta, Phi @@ -554,6 +616,192 @@ struct ResoMicroTrackSelFlag { DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float px, float py) -> float { return RecoDecay::sqrtSumOfSquares(px, py); }); } // namespace resomicrodaughter +// Version 001 uses signed, lower-inclusive PID bins and keeps the DCAxy/DCAz +// pT-dependent selection results independently from the quantised DCA values. +namespace resomicrodaughter001 +{ +// Keep the original row number as a scalar for standalone pair comparisons. +// The separate typed relation remains available to legacy version-0 users. +DECLARE_SOA_COLUMN(TrackId, trackId, int); //! Original track row number for pair-level comparisons + +/// @brief Compact signed TPC/TOF n-sigma values into two four-bit fields. +/// The upper bit of each field stores the sign. Magnitudes 1..6 represent +/// lower-inclusive 0.25-sigma-wide bins [2.0, 2.25), ..., [3.25, 3.5), while +/// magnitude 0 is |n-sigma| < 2 and magnitude 7 is |n-sigma| >= 3.5. Overflow +/// decodes to signed infinity, while code 8 is reserved for invalid values and +/// decodes to NaN. Missing TOF information is also carried independently by +/// resodaughter::TrackFlags::kHasTOF. +struct PidNSigma { + static constexpr float MinFineNSigma = 2.f; + static constexpr float Step = 0.25f; + static constexpr float MaxNSigma = 3.5f; + static constexpr uint8_t SignMask = 0x08; + static constexpr uint8_t MagnitudeMask = 0x07; + static constexpr uint8_t MaxRegularCode = 6; + static constexpr uint8_t AboveRangeCode = 7; + static constexpr uint8_t InvalidCode = SignMask; + + uint8_t flag; + + PidNSigma(float tpcNSigma, float tofNSigma, bool hasTOF) + { + const uint8_t tpcEncoded = encodeNSigma(tpcNSigma); + const uint8_t tofEncoded = hasTOF ? encodeNSigma(tofNSigma) : InvalidCode; + flag = (tpcEncoded << 4) | tofEncoded; + } + + static uint8_t encodeNSigma(float nSigma) + { + if (!std::isfinite(nSigma)) { + return InvalidCode; + } + const float value = std::abs(nSigma); + if (value < MinFineNSigma) { + return 0; + } + uint8_t magnitude = AboveRangeCode; + if (value < MaxNSigma) { + const int encoded = 1 + static_cast(std::floor((value - MinFineNSigma) / Step)); + magnitude = static_cast(std::clamp(encoded, 1, static_cast(MaxRegularCode))); + } + const uint8_t sign = std::signbit(nSigma) ? SignMask : 0; + return static_cast(sign | magnitude); + } + + static float decodeNSigma(uint8_t encoded) + { + const uint8_t code = encoded & 0x0F; + if (code == InvalidCode) { + return NAN; + } + const uint8_t magnitude = code & MagnitudeMask; + if (magnitude == 0) { + return 0.f; + } + const float value = magnitude == AboveRangeCode + ? std::numeric_limits::infinity() + : MinFineNSigma + static_cast(magnitude - 1) * Step; + return (code & SignMask) != 0 ? -value : value; + } + + static float getTPCNSigma(uint8_t encoded) + { + return decodeNSigma((encoded >> 4) & 0x0F); + } + + static float getTOFNSigma(uint8_t encoded, bool hasTOF) + { + return hasTOF ? decodeNSigma(encoded & 0x0F) : NAN; + } + + operator uint8_t() const { return flag; } +}; + +/// @brief Store two pT-dependent DCA pass bits and two three-bit DCA values. +/// Bits 7 and 6 store the DCAxy and DCAz pass results, respectively. Bits 5..3 +/// and 2..0 store |DCAxy| and |DCAz| in lower-inclusive 0.025 cm bins from 0 +/// to 0.15 cm. Code 6 represents overflow and code 7 an invalid value. +struct DCAEncoding { + static constexpr float MaxDCA = 0.15f; + static constexpr float Step = 0.025f; + static constexpr float InverseStep = 40.f; + static constexpr uint8_t MaxRegularCode = 5; + static constexpr uint8_t AboveRangeCode = 6; + static constexpr uint8_t InvalidCode = 7; + static constexpr uint8_t PassedPtDependentDCAxyMask = 0x80; + static constexpr uint8_t PassedPtDependentDCAzMask = 0x40; + static constexpr uint8_t DCAxyMask = 0x38; + static constexpr uint8_t DCAzMask = 0x07; + static constexpr uint8_t DCAxyShift = 3; + + uint8_t flag = 0; + + DCAEncoding() = default; + DCAEncoding(float dcaXY, float dcaZ, bool passedPtDependentDCAxy, bool passedPtDependentDCAz) + : flag(static_cast((passedPtDependentDCAxy ? PassedPtDependentDCAxyMask : 0) | + (passedPtDependentDCAz ? PassedPtDependentDCAzMask : 0) | + (encodeDCA(dcaXY) << DCAxyShift) | + encodeDCA(dcaZ))) + { + } + + static uint8_t encodeDCA(float dca) + { + const float value = std::abs(dca); + if (!std::isfinite(value)) { + return InvalidCode; + } + if (value >= MaxDCA) { + return AboveRangeCode; + } + const int encoded = static_cast(std::floor(value * InverseStep)); + return static_cast(std::clamp(encoded, 0, static_cast(MaxRegularCode))); + } + + static float decodeDCA(uint8_t encoded) + { + const uint8_t code = encoded & DCAzMask; + if (code == InvalidCode) { + return NAN; + } + return code == AboveRangeCode ? MaxDCA : static_cast(code) * Step; + } + + static float decodeDCAxy(uint8_t encoded) + { + return decodeDCA((encoded & DCAxyMask) >> DCAxyShift); + } + + static float decodeDCAz(uint8_t encoded) + { + return decodeDCA(encoded & DCAzMask); + } + + static bool testPtDependentDCAxy(uint8_t encoded) + { + return (encoded & PassedPtDependentDCAxyMask) != 0; + } + + static bool testPtDependentDCAz(uint8_t encoded) + { + return (encoded & PassedPtDependentDCAzMask) != 0; + } + + operator uint8_t() const { return flag; } +}; + +DECLARE_SOA_COLUMN(TrackSelectionFlags, trackSelectionFlags, uint8_t); //! Packed DCA selection and absolute DCAxy/DCAz values +DECLARE_SOA_DYNAMIC_COLUMN(TpcNSigmaPi, tpcNSigmaPi, + [](uint8_t pidNSigmaPiFlag) { return PidNSigma::getTPCNSigma(pidNSigmaPiFlag); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcNSigmaKa, tpcNSigmaKa, + [](uint8_t pidNSigmaKaFlag) { return PidNSigma::getTPCNSigma(pidNSigmaKaFlag); }); +DECLARE_SOA_DYNAMIC_COLUMN(TpcNSigmaPr, tpcNSigmaPr, + [](uint8_t pidNSigmaPrFlag) { return PidNSigma::getTPCNSigma(pidNSigmaPrFlag); }); +DECLARE_SOA_DYNAMIC_COLUMN(TofNSigmaPi, tofNSigmaPi, + [](uint8_t pidNSigmaPiFlag, uint8_t trackFlags) -> float { + const bool hasTOF = resodaughter::ResoTrackFlags::checkFlag(trackFlags, resodaughter::ResoTrackFlags::kHasTOF); + return PidNSigma::getTOFNSigma(pidNSigmaPiFlag, hasTOF); + }); +DECLARE_SOA_DYNAMIC_COLUMN(TofNSigmaKa, tofNSigmaKa, + [](uint8_t pidNSigmaKaFlag, uint8_t trackFlags) -> float { + const bool hasTOF = resodaughter::ResoTrackFlags::checkFlag(trackFlags, resodaughter::ResoTrackFlags::kHasTOF); + return PidNSigma::getTOFNSigma(pidNSigmaKaFlag, hasTOF); + }); +DECLARE_SOA_DYNAMIC_COLUMN(TofNSigmaPr, tofNSigmaPr, + [](uint8_t pidNSigmaPrFlag, uint8_t trackFlags) -> float { + const bool hasTOF = resodaughter::ResoTrackFlags::checkFlag(trackFlags, resodaughter::ResoTrackFlags::kHasTOF); + return PidNSigma::getTOFNSigma(pidNSigmaPrFlag, hasTOF); + }); +DECLARE_SOA_DYNAMIC_COLUMN(DcaXY, dcaXY, + [](uint8_t trackSelectionFlags) { return DCAEncoding::decodeDCAxy(trackSelectionFlags); }); +DECLARE_SOA_DYNAMIC_COLUMN(DcaZ, dcaZ, + [](uint8_t trackSelectionFlags) { return DCAEncoding::decodeDCAz(trackSelectionFlags); }); +DECLARE_SOA_DYNAMIC_COLUMN(PassedPtDependentDCAxy, passedPtDependentDCAxy, + [](uint8_t trackSelectionFlags) { return DCAEncoding::testPtDependentDCAxy(trackSelectionFlags); }); +DECLARE_SOA_DYNAMIC_COLUMN(PassedPtDependentDCAz, passedPtDependentDCAz, + [](uint8_t trackSelectionFlags) { return DCAEncoding::testPtDependentDCAz(trackSelectionFlags); }); +} // namespace resomicrodaughter001 + // Ultra-micro track representation. The momentum components are quantised // to 1 MeV/c and only one (pion/kaon/proton) PID flag is retained. namespace resoultramicrodaughter @@ -786,6 +1034,45 @@ DECLARE_SOA_TABLE(ResoMicroTracks, "AOD", "RESOMICROTRACK", resodaughter::Sign); using ResoMicroTrack = ResoMicroTracks::iterator; +// Keep ResoMicroTracks as the version-0 API for existing producers and +// consumers. Version-1 users must request ResoMicroTracks_001 explicitly. +DECLARE_SOA_TABLE_VERSIONED(ResoMicroTracks_001, "AOD", "RESOMICROTRACK", 1, + o2::soa::Index<>, + resodaughter::ResoCollisionId, + resomicrodaughter001::TrackId, + resodaughter::Px, + resodaughter::Py, + resodaughter::Pz, + resomicrodaughter::PidNSigmaPiFlag, + resomicrodaughter::PidNSigmaKaFlag, + resomicrodaughter::PidNSigmaPrFlag, + resomicrodaughter001::TrackSelectionFlags, + resodaughter::TrackFlags, + // Dynamic columns + resomicrodaughter::Pt, + resodaughter::Eta, + resodaughter::Phi, + resomicrodaughter001::TpcNSigmaPi, + resomicrodaughter001::TpcNSigmaKa, + resomicrodaughter001::TpcNSigmaPr, + resomicrodaughter001::TofNSigmaPi, + resomicrodaughter001::TofNSigmaKa, + resomicrodaughter001::TofNSigmaPr, + resomicrodaughter001::DcaXY, + resomicrodaughter001::DcaZ, + resomicrodaughter001::PassedPtDependentDCAxy, + resomicrodaughter001::PassedPtDependentDCAz, + resodaughter::PassedITSRefit, + resodaughter::PassedTPCRefit, + resodaughter::IsGlobalTrackWoDCA, + resodaughter::IsGlobalTrack, + resodaughter::IsPrimaryTrack, + resodaughter::IsPVContributor, + resodaughter::HasTOF, + resodaughter::Sign); +// Positional soft-link side table retained for ResoMicroTracks version 000. +// Version 001 stores the same row number as a scalar and should be consumed +// without joining this side table, since both columns expose trackId(). DECLARE_SOA_TABLE(ResoMicroTrackTracks, "AOD", "RESOMICROTRACKTRACK", resodaughter::TrackId); using ResoMicroTrackTrack = ResoMicroTrackTracks::iterator; @@ -1074,6 +1361,17 @@ DECLARE_SOA_TABLE(ResoMCTracks, "AOD", "RESOMCTRACK", resodaughter::ProducedByGenerator); using ResoMCTrack = ResoMCTracks::iterator; +// Positional MC extension for ResoMicroTracks_001. One row must be written for +// every ResoMicroTracks_001 row, including tracks without an MC particle label. +DECLARE_SOA_TABLE_VERSIONED(ResoMCMicroTracks_001, "AOD", "RESOMCMICROTRACK", 1, + mcparticle::PdgCode, + resodaughter::MotherId, + resodaughter::MotherPDG, + resodaughter::SiblingIds, + resodaughter::IsPhysicalPrimary, + resodaughter::ProducedByGenerator); +using ResoMCMicroTrack = ResoMCMicroTracks_001::iterator; + DECLARE_SOA_TABLE(ResoMCV0s, "AOD", "RESOMCV0", mcparticle::PdgCode, resodaughter::MotherId, @@ -1123,6 +1421,34 @@ DECLARE_SOA_TABLE(ResoMCParents, "AOD", "RESOMCPARENT", resodaughter::Phi); using ResoMCParent = ResoMCParents::iterator; +// Module-specific parent rows keep the source MC-particle row number as a +// scalar. This avoids a hard relation to McParticles in standalone derived +// AO2D while preserving the legacy ResoMCParents schema and typed API. +namespace resomcparent001 +{ +DECLARE_SOA_COLUMN(OriginalMcParticleId, originalMcParticleId, int); //! Original aod::McParticle row number +} // namespace resomcparent001 + +DECLARE_SOA_TABLE_VERSIONED(ResoMCParents_001, "AOD", "RESOMCPARENT", 1, + o2::soa::Index<>, + resodaughter::ResoCollisionId, + resomcparent001::OriginalMcParticleId, + mcparticle::PdgCode, + resodaughter::DaughterPDG1, + resodaughter::DaughterPDG2, + resodaughter::IsPhysicalPrimary, + resodaughter::ProducedByGenerator, + resodaughter::Pt, + resodaughter::Px, + resodaughter::Py, + resodaughter::Pz, + mcparticle::Y, + mcparticle::E, + mcparticle::StatusCode, + resodaughter::Eta, + resodaughter::Phi); +using ResoMCParent_001 = ResoMCParents_001::iterator; + using Reso2TracksExt = soa::Join; // without Extra using Reso2TracksMC = soa::Join; using Reso2TracksPID = soa::Join; @@ -1141,4 +1467,11 @@ using ResoCascadesCandidatesMC = soa::Join; } // namespace o2::aod + +namespace o2::soa +{ +// Preserve the legacy v000 default target while allowing an explicitly typed +// resoCollision_as() binding to the exact v001 parent in modular analyses. +DECLARE_EQUIVALENT_FOR_INDEX(aod::ResoCollisions_000, aod::ResoCollisions_001); +} // namespace o2::soa #endif // PWGLF_DATAMODEL_LFRESONANCETABLES_H_ diff --git a/PWGLF/DataModel/LFSigmaTables.h b/PWGLF/DataModel/LFSigmaTables.h index 4d8d08ba6a9..e11567b2d7a 100644 --- a/PWGLF/DataModel/LFSigmaTables.h +++ b/PWGLF/DataModel/LFSigmaTables.h @@ -107,6 +107,22 @@ DECLARE_SOA_DYNAMIC_COLUMN(OPAngle, opAngle, return v1.Angle(v2); }); +// Armenteros-Podolanski variables (photon = positive daughter, lambda = negative daughter) +DECLARE_SOA_DYNAMIC_COLUMN(LStarAlpha, lStarAlpha, //! Armenteros Alpha + [](float photonPx, float photonPy, float photonPz, float lambdaPx, float lambdaPy, float lambdaPz) -> float { + float momTot = RecoDecay::p(photonPx + lambdaPx, photonPy + lambdaPy, photonPz + lambdaPz); + float lQlNeg = RecoDecay::dotProd(std::array{lambdaPx, lambdaPy, lambdaPz}, std::array{photonPx + lambdaPx, photonPy + lambdaPy, photonPz + lambdaPz}) / momTot; + float lQlPos = RecoDecay::dotProd(std::array{photonPx, photonPy, photonPz}, std::array{photonPx + lambdaPx, photonPy + lambdaPy, photonPz + lambdaPz}) / momTot; + return (lQlPos - lQlNeg) / (lQlPos + lQlNeg); + }); + +DECLARE_SOA_DYNAMIC_COLUMN(LStarQtArm, lStarQtarm, //! Armenteros Qt + [](float photonPx, float photonPy, float photonPz, float lambdaPx, float lambdaPy, float lambdaPz) -> float { + float momTot = RecoDecay::p2(photonPx + lambdaPx, photonPy + lambdaPy, photonPz + lambdaPz); + float dp = RecoDecay::dotProd(std::array{lambdaPx, lambdaPy, lambdaPz}, std::array{photonPx + lambdaPx, photonPy + lambdaPy, photonPz + lambdaPz}); + return std::sqrt(RecoDecay::p2(lambdaPx, lambdaPy, lambdaPz) - dp * dp / momTot); // qtarm + }); + // Photon DECLARE_SOA_DYNAMIC_COLUMN(PhotonPt, photonPt, //! Transverse momentum in GeV/c [](float photonPx, float photonPy) -> float { @@ -179,6 +195,8 @@ DECLARE_SOA_TABLE(Sigma0Cores, "AOD", "SIGMA0CORES", sigma0Core::Eta, sigma0Core::Radius, sigma0Core::OPAngle, + sigma0Core::LStarAlpha, + sigma0Core::LStarQtArm, sigma0Core::PhotonPt, sigma0Core::PhotonP, @@ -656,6 +674,12 @@ DECLARE_SOA_DYNAMIC_COLUMN(IsSigma0, isSigma0, DECLARE_SOA_DYNAMIC_COLUMN(IsAntiSigma0, isAntiSigma0, //! IsASigma0 [](int pdgCode) -> bool { return pdgCode == PDG_t::kSigma0Bar; }); //-3212 +DECLARE_SOA_DYNAMIC_COLUMN(IsLambdaStar, isLambdaStar, //! IsLambdaStar + [](int pdgCode) -> bool { return pdgCode == 3124; }); // PYTHIA8 code for Lambda(1520) + +DECLARE_SOA_DYNAMIC_COLUMN(IsAntiLambdaStar, isAntiLambdaStar, //! IsAntiLambdaStar + [](int pdgCode) -> bool { return pdgCode == -3124; }); // PYTHIA8 code for AntiLambda(1520) + DECLARE_SOA_DYNAMIC_COLUMN(MCPx, mcpx, //! Sigma0 px [](float photonMCPx, float lambdaMCPx) -> float { return photonMCPx + lambdaMCPx; }); DECLARE_SOA_DYNAMIC_COLUMN(MCPy, mcpy, //! Sigma0 py @@ -686,6 +710,11 @@ DECLARE_SOA_DYNAMIC_COLUMN(Sigma0MCY, sigma0MCY, return RecoDecay::y(std::array{photonMCPx + lambdaMCPx, photonMCPy + lambdaMCPy, photonMCPz + lambdaMCPz}, o2::constants::physics::MassSigma0); }); +DECLARE_SOA_DYNAMIC_COLUMN(LambdaStarMCY, lambdaStarMCY, + [](float photonMCPx, float photonMCPy, float photonMCPz, float lambdaMCPx, float lambdaMCPy, float lambdaMCPz) -> float { + return RecoDecay::y(std::array{photonMCPx + lambdaMCPx, photonMCPy + lambdaMCPy, photonMCPz + lambdaMCPz}, o2::constants::physics::MassLambda1520); + }); + DECLARE_SOA_DYNAMIC_COLUMN(MCPhi, mcphi, //! Phi in the range [0, 2pi) [](float photonMCPx, float photonMCPy, float lambdaMCPx, float lambdaMCPy) -> float { return RecoDecay::phi(photonMCPx + lambdaMCPx, photonMCPy + lambdaMCPy); }); @@ -767,6 +796,8 @@ DECLARE_SOA_TABLE(Sigma0MCCores, "AOD", "SIGMA0MCCORES", // Dynamic columns sigma0MCCore::IsSigma0, sigma0MCCore::IsAntiSigma0, + sigma0MCCore::IsLambdaStar, + sigma0MCCore::IsAntiLambdaStar, sigma0MCCore::MCPx, sigma0MCCore::MCPy, @@ -775,6 +806,7 @@ DECLARE_SOA_TABLE(Sigma0MCCores, "AOD", "SIGMA0MCCORES", sigma0MCCore::MCP, sigma0MCCore::Sigma0MCMass, sigma0MCCore::Sigma0MCY, + sigma0MCCore::LambdaStarMCY, sigma0MCCore::MCPhi, sigma0MCCore::MCEta, sigma0MCCore::MCOPAngle, diff --git a/PWGLF/DataModel/LFStrangenessPIDTables.h b/PWGLF/DataModel/LFStrangenessPIDTables.h index 067966859ed..848f2a3289f 100644 --- a/PWGLF/DataModel/LFStrangenessPIDTables.h +++ b/PWGLF/DataModel/LFStrangenessPIDTables.h @@ -414,25 +414,33 @@ DECLARE_SOA_COLUMN(TOFNSigmaOmLaPr, tofNSigmaOmLaPr, float); //! baryon track NS DECLARE_SOA_COLUMN(TOFNSigmaOmKa, tofNSigmaOmKa, float); //! bachelor track NSigma from kaon <- om expectation // for wrong hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaElFromLambdaFromXi, tofNSigmaElFromLambdaFromXi, float); //! nigma of positive track from Lambda from Xi under electron hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaElFromXi, tofNSigmaElFromXi, float); //! nigma of bachelor track from Xi under electron hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaElFromLambdaFromOmega, tofNSigmaElFromLambdaFromOmega, float); //! nigma of positive track from Lambda from Omega under electron hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaElFromOmega, tofNSigmaElFromOmega, float); //! nigma of bachelor track from Omega under electron hypothesis - -DECLARE_SOA_COLUMN(TOFNSigmaPiFromLambdaFromXi, tofNSigmaPiFromLambdaFromXi, float); //! nigma of positive track from Lambda from Xi under pion hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaPiFromXi, tofNSigmaPiFromXi, float); //! nigma of bachelor track from Xi under pion hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaPiFromLambdaFromOmega, tofNSigmaPiFromLambdaFromOmega, float); //! nigma of positive track from Lambda from Omega under pion hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaPiFromOmega, tofNSigmaPiFromOmega, float); //! nigma of bachelor track from Omega under pion hypothesis - -DECLARE_SOA_COLUMN(TOFNSigmaKaFromLambdaFromXi, tofNSigmaKaFromLambdaFromXi, float); //! nigma of positive track from Lambda from Xi under kaon hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaKaFromXi, tofNSigmaKaFromXi, float); //! nigma of bachelor track from Xi under kaon hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaKaFromLambdaFromOmega, tofNSigmaKaFromLambdaFromOmega, float); //! nigma of positive track from Lambda from Omega under kaon hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaKaFromOmega, tofNSigmaKaFromOmega, float); //! nigma of bachelor track from Omega under kaon hypothesis - -DECLARE_SOA_COLUMN(TOFNSigmaPrFromLambdaFromXi, tofNSigmaPrFromLambdaFromXi, float); //! nigma of positive track from Lambda from Xi under proton hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaPrFromXi, tofNSigmaPrFromXi, float); //! nigma of bachelor track from Xi under proton hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaPrFromLambdaFromOmega, tofNSigmaPrFromLambdaFromOmega, float); //! nigma of positive track from Lambda from Omega under proton hypothesis -DECLARE_SOA_COLUMN(TOFNSigmaPrFromOmega, tofNSigmaPrFromOmega, float); //! nigma of bachelor track from Omega under proton hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaElPosFromLambdaFromXi, tofNSigmaElPosFromLambdaFromXi, float); //! nigma of positive track from Lambda from Xi under electron hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaElNegFromLambdaFromXi, tofNSigmaElNegFromLambdaFromXi, float); //! nigma of negative track from Lambda from Xi under electron hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaElFromXi, tofNSigmaElFromXi, float); //! nigma of bachelor track from Xi under electron hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaElPosFromLambdaFromOmega, tofNSigmaElPosFromLambdaFromOmega, float); //! nigma of positive track from Lambda from Omega under electron hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaElNegFromLambdaFromOmega, tofNSigmaElNegFromLambdaFromOmega, float); //! nigma of negative track from Lambda from Omega under electron hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaElFromOmega, tofNSigmaElFromOmega, float); //! nigma of bachelor track from Omega under electron hypothesis + +DECLARE_SOA_COLUMN(TOFNSigmaPiPosFromLambdaFromXi, tofNSigmaPiPosFromLambdaFromXi, float); //! nigma of positive track from Lambda from Xi under pion hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaPiNegFromLambdaFromXi, tofNSigmaPiNegFromLambdaFromXi, float); //! nigma of negative track from Lambda from Xi under pion hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaPiFromXi, tofNSigmaPiFromXi, float); //! nigma of bachelor track from Xi under pion hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaPiPosFromLambdaFromOmega, tofNSigmaPiPosFromLambdaFromOmega, float); //! nigma of positive track from Lambda from Omega under pion hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaPiNegFromLambdaFromOmega, tofNSigmaPiNegFromLambdaFromOmega, float); //! nigma of negative track from Lambda from Omega under pion hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaPiFromOmega, tofNSigmaPiFromOmega, float); //! nigma of bachelor track from Omega under pion hypothesis + +DECLARE_SOA_COLUMN(TOFNSigmaKaPosFromLambdaFromXi, tofNSigmaKaPosFromLambdaFromXi, float); //! nigma of positive track from Lambda from Xi under kaon hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaKaNegFromLambdaFromXi, tofNSigmaKaNegFromLambdaFromXi, float); //! nigma of negative track from Lambda from Xi under kaon hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaKaFromXi, tofNSigmaKaFromXi, float); //! nigma of bachelor track from Xi under kaon hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaKaPosFromLambdaFromOmega, tofNSigmaKaPosFromLambdaFromOmega, float); //! nigma of positive track from Lambda from Omega under kaon hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaKaNegFromLambdaFromOmega, tofNSigmaKaNegFromLambdaFromOmega, float); //! nigma of negative track from Lambda from Omega under kaon hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaKaFromOmega, tofNSigmaKaFromOmega, float); //! nigma of bachelor track from Omega under kaon hypothesis + +DECLARE_SOA_COLUMN(TOFNSigmaPrPosFromLambdaFromXi, tofNSigmaPrPosFromLambdaFromXi, float); //! nigma of positive track from Lambda from Xi under proton hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaPrNegFromLambdaFromXi, tofNSigmaPrNegFromLambdaFromXi, float); //! nigma of negative track from Lambda from Xi under proton hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaPrFromXi, tofNSigmaPrFromXi, float); //! nigma of bachelor track from Xi under proton hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaPrPosFromLambdaFromOmega, tofNSigmaPrPosFromLambdaFromOmega, float); //! nigma of positive track from Lambda from Omega under proton hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaPrNegFromLambdaFromOmega, tofNSigmaPrNegFromLambdaFromOmega, float); //! nigma of negative track from Lambda from Omega under proton hypothesis +DECLARE_SOA_COLUMN(TOFNSigmaPrFromOmega, tofNSigmaPrFromOmega, float); //! nigma of bachelor track from Omega under proton hypothesis // dynamics to replace hasTOF (note: that condition does not match track hasTOF!) // note: only single hypothesis check necessary; other hypotheses will always be valid @@ -518,10 +526,14 @@ DECLARE_SOA_TABLE(CascTOFNSigmas, "AOD", "CascTOFNSigmas", // Nsigmas for cascad cascdata::TofXiCompatibility, cascdata::TofOmegaCompatibility); DECLARE_SOA_TABLE(CascTOFNSigmasAll, "AOD", "CascTOFNSigmasAll", // Nsigmas for cascades including wrong hypothesis - cascdata::TOFNSigmaElFromLambdaFromXi, cascdata::TOFNSigmaElFromXi, cascdata::TOFNSigmaElFromLambdaFromOmega, cascdata::TOFNSigmaElFromOmega, - cascdata::TOFNSigmaPiFromLambdaFromXi, cascdata::TOFNSigmaPiFromXi, cascdata::TOFNSigmaPiFromLambdaFromOmega, cascdata::TOFNSigmaPiFromOmega, - cascdata::TOFNSigmaKaFromLambdaFromXi, cascdata::TOFNSigmaKaFromXi, cascdata::TOFNSigmaKaFromLambdaFromOmega, cascdata::TOFNSigmaKaFromOmega, - cascdata::TOFNSigmaPrFromLambdaFromXi, cascdata::TOFNSigmaPrFromXi, cascdata::TOFNSigmaPrFromLambdaFromOmega, cascdata::TOFNSigmaPrFromOmega); + cascdata::TOFNSigmaElPosFromLambdaFromXi, cascdata::TOFNSigmaElNegFromLambdaFromXi, cascdata::TOFNSigmaElFromXi, + cascdata::TOFNSigmaElPosFromLambdaFromOmega, cascdata::TOFNSigmaElNegFromLambdaFromOmega, cascdata::TOFNSigmaElFromOmega, + cascdata::TOFNSigmaPiPosFromLambdaFromXi, cascdata::TOFNSigmaPiNegFromLambdaFromXi, cascdata::TOFNSigmaPiFromXi, + cascdata::TOFNSigmaPiPosFromLambdaFromOmega, cascdata::TOFNSigmaPiNegFromLambdaFromOmega, cascdata::TOFNSigmaPiFromOmega, + cascdata::TOFNSigmaKaPosFromLambdaFromXi, cascdata::TOFNSigmaKaNegFromLambdaFromXi, cascdata::TOFNSigmaKaFromXi, + cascdata::TOFNSigmaKaPosFromLambdaFromOmega, cascdata::TOFNSigmaKaNegFromLambdaFromOmega, cascdata::TOFNSigmaKaFromOmega, + cascdata::TOFNSigmaPrPosFromLambdaFromXi, cascdata::TOFNSigmaPrNegFromLambdaFromXi, cascdata::TOFNSigmaPrFromXi, + cascdata::TOFNSigmaPrPosFromLambdaFromOmega, cascdata::TOFNSigmaPrNegFromLambdaFromOmega, cascdata::TOFNSigmaPrFromOmega); } // namespace o2::aod #endif // PWGLF_DATAMODEL_LFSTRANGENESSPIDTABLES_H_ diff --git a/PWGLF/DataModel/LFStrangenessTables.h b/PWGLF/DataModel/LFStrangenessTables.h index 057ff318f03..56322a0e47c 100644 --- a/PWGLF/DataModel/LFStrangenessTables.h +++ b/PWGLF/DataModel/LFStrangenessTables.h @@ -440,8 +440,10 @@ DECLARE_SOA_TABLE(StraMCCollMults_000, "AOD", "STRAMCCOLLMULTS", //! MC collisio mult::MultMCFT0A, mult::MultMCFT0C, mult::MultMCNParticlesEta05, mult::MultMCNParticlesEta08, mult::MultMCNParticlesEta10, o2::soa::Marker<2>); DECLARE_SOA_TABLE_VERSIONED(StraMCCollMults_001, "AOD", "STRAMCCOLLMULTS", 1, //! MC collision multiplicities mult::MultMCFT0A, mult::MultMCFT0C, mult::MultMCNParticlesEta05, mult::MultMCNParticlesEta08, mult::MultMCNParticlesEta10, stramccollision::TotalMultMCParticles); +DECLARE_SOA_TABLE_VERSIONED(StraMCCollMults_002, "AOD", "STRAMCCOLLMULTS", 2, //! MC collision multiplicities + mult::MultMCFT0A, mult::MultMCFT0C, mult::MultMCFV0A, mult::MultMCFDDA, mult::MultMCFDDC, mult::MultMCNParticlesEta05, mult::MultMCNParticlesEta08, mult::MultMCNParticlesEta10, stramccollision::TotalMultMCParticles); -using StraMCCollMults = StraMCCollMults_001; +using StraMCCollMults = StraMCCollMults_002; namespace dautrack { diff --git a/PWGLF/DataModel/Vtx3BodyTables.h b/PWGLF/DataModel/Vtx3BodyTables.h index bb0dcc89fe1..fbfb258a0f1 100644 --- a/PWGLF/DataModel/Vtx3BodyTables.h +++ b/PWGLF/DataModel/Vtx3BodyTables.h @@ -17,6 +17,8 @@ #ifndef PWGLF_DATAMODEL_VTX3BODYTABLES_H_ #define PWGLF_DATAMODEL_VTX3BODYTABLES_H_ +#include "PWGLF/DataModel/LFHypernucleiTables.h" + #include "Common/Core/RecoDecay.h" #include @@ -128,12 +130,15 @@ DECLARE_SOA_COLUMN(GenCt, genCt, float); // generated Ct of the hy DECLARE_SOA_COLUMN(GenPhi, genPhi, float); // generated Phi of the hypertriton DECLARE_SOA_COLUMN(GenEta, genEta, float); // Eta of the hypertriton DECLARE_SOA_COLUMN(GenRap, genRap, float); // generated rapidity of the hypertriton -DECLARE_SOA_COLUMN(GenPPr, genPPr, float); //! generated momentum proton daughter particle -DECLARE_SOA_COLUMN(GenPPi, genPPi, float); //! generated momentum pion daughter particle -DECLARE_SOA_COLUMN(GenPDe, genPDe, float); //! generated momentum deuteron daughter particle -DECLARE_SOA_COLUMN(GenPtPr, genPtPr, float); //! generated transverse momentum proton daughter particle -DECLARE_SOA_COLUMN(GenPtPi, genPtPi, float); //! generated transverse momentum pion daughter particle -DECLARE_SOA_COLUMN(GenPtDe, genPtDe, float); //! generated transverse momentum deuteron daughter particle +DECLARE_SOA_COLUMN(GenPxPr, genPxPr, float); //! generated Px of proton daughter particle +DECLARE_SOA_COLUMN(GenPyPr, genPyPr, float); //! generated Py of proton daughter particle +DECLARE_SOA_COLUMN(GenPzPr, genPzPr, float); //! generated Pz of proton daughter particle +DECLARE_SOA_COLUMN(GenPxPi, genPxPi, float); //! generated Px of pion daughter particle +DECLARE_SOA_COLUMN(GenPyPi, genPyPi, float); //! generated Py of pion daughter particle +DECLARE_SOA_COLUMN(GenPzPi, genPzPi, float); //! generated Pz of pion daughter particle +DECLARE_SOA_COLUMN(GenPxDe, genPxDe, float); //! generated Px of deuteron daughter particle +DECLARE_SOA_COLUMN(GenPyDe, genPyDe, float); //! generated Py of deuteron daughter particle +DECLARE_SOA_COLUMN(GenPzDe, genPzDe, float); //! generated Pz of deuteron daughter particle DECLARE_SOA_COLUMN(MotherPdgCode, motherPdgCode, int); //! PDG code of the mother particle DECLARE_SOA_COLUMN(PrPdgCode, prPdgCode, int); //! MC particle proton PDG code DECLARE_SOA_COLUMN(PiPdgCode, piPdgCode, int); //! MC particle pion PDG code @@ -271,6 +276,22 @@ DECLARE_SOA_TABLE(Vtx3BodyTrackedInfo, "AOD", "VTX3BODYTR", //! vtx3body::ITSTrackDCAXYToSV, vtx3body::ITSTrackDCAZToSV); +// collision info table +DECLARE_SOA_TABLE(Vtx3BodyCollision, "AOD", "VTX3BODYCOLL", //! + o2::soa::Index<>, + hyperrec::CentralityFT0A, hyperrec::CentralityFT0C, hyperrec::CentralityFT0M, + hyperrec::TrackOccupancyInTimeRange, hyperrec::Ft0cOccupancyInTimeRange, + hyperrec::XPrimVtx, hyperrec::YPrimVtx, hyperrec::ZPrimVtx, + hyperrec::RunNumber); + +DECLARE_SOA_TABLE(McVtx3BodyCollision, "AOD", "MCVTX3BODYCOLL", //! + o2::soa::Index<>, + hyperrec::IsRecoMCCollision, + hyperrec::CentralityFT0A, hyperrec::CentralityFT0C, hyperrec::CentralityFT0M, + hyperrec::TrackOccupancyInTimeRange, hyperrec::Ft0cOccupancyInTimeRange, + hyperrec::XPrimVtx, hyperrec::YPrimVtx, hyperrec::ZPrimVtx, + hyperrec::RunNumber); + // MC candidate table for analysis DECLARE_SOA_TABLE(McVtx3BodyDatas, "AOD", "MC3BODYDATA", //! o2::soa::Index<>, @@ -303,8 +324,9 @@ DECLARE_SOA_TABLE(McVtx3BodyDatas, "AOD", "MC3BODYDATA", //! vtx3body::GenX, vtx3body::GenY, vtx3body::GenZ, vtx3body::GenCt, vtx3body::GenPhi, vtx3body::GenEta, vtx3body::GenRap, - vtx3body::GenPPr, vtx3body::GenPPi, vtx3body::GenPDe, - vtx3body::GenPtPr, vtx3body::GenPtPi, vtx3body::GenPtDe, + vtx3body::GenPxPr, vtx3body::GenPyPr, vtx3body::GenPzPr, + vtx3body::GenPxPi, vtx3body::GenPyPi, vtx3body::GenPzPi, + vtx3body::GenPxDe, vtx3body::GenPyDe, vtx3body::GenPzDe, vtx3body::IsReco, vtx3body::MotherLabel, vtx3body::MotherPdgCode, diff --git a/PWGLF/DataModel/ZDC2StageCalibrationTables.h b/PWGLF/DataModel/ZDC2StageCalibrationTables.h new file mode 100644 index 00000000000..de4a101dac4 --- /dev/null +++ b/PWGLF/DataModel/ZDC2StageCalibrationTables.h @@ -0,0 +1,54 @@ +// 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. + +/// \author Sourav Kundu + +#ifndef PWGLF_DATAMODEL_ZDC2STAGECALIBRATIONTABLES_H_ +#define PWGLF_DATAMODEL_ZDC2STAGECALIBRATIONTABLES_H_ + +#include + +#include + +namespace o2::aod +{ +namespace zdc2stagecalib +{ +DECLARE_SOA_INDEX_COLUMN(Collision, collision); +DECLARE_SOA_COLUMN(TriggerSP, triggerSP, bool); +DECLARE_SOA_COLUMN(RunNumber, runNumber, int32_t); +DECLARE_SOA_COLUMN(GlobalBC, globalBC, uint64_t); +DECLARE_SOA_COLUMN(Centrality, centrality, float); +DECLARE_SOA_COLUMN(Vx, vx, float); +DECLARE_SOA_COLUMN(Vy, vy, float); +DECLARE_SOA_COLUMN(Vz, vz, float); +DECLARE_SOA_COLUMN(QxZDCA, qxZDCA, float); +DECLARE_SOA_COLUMN(QxZDCC, qxZDCC, float); +DECLARE_SOA_COLUMN(QyZDCA, qyZDCA, float); +DECLARE_SOA_COLUMN(QyZDCC, qyZDCC, float); +} // namespace zdc2stagecalib + +DECLARE_SOA_TABLE(ZDC2StageCalibs, "AOD", "ZDC2STGCAL", + zdc2stagecalib::CollisionId, + zdc2stagecalib::TriggerSP, + zdc2stagecalib::RunNumber, + zdc2stagecalib::GlobalBC, + zdc2stagecalib::Centrality, + zdc2stagecalib::Vx, + zdc2stagecalib::Vy, + zdc2stagecalib::Vz, + zdc2stagecalib::QxZDCA, + zdc2stagecalib::QxZDCC, + zdc2stagecalib::QyZDCA, + zdc2stagecalib::QyZDCC); +} // namespace o2::aod + +#endif // PWGLF_DATAMODEL_ZDC2STAGECALIBRATIONTABLES_H_ diff --git a/PWGLF/DataModel/cascqaanalysis.h b/PWGLF/DataModel/cascqaanalysis.h index 3442c074305..eca673c683d 100644 --- a/PWGLF/DataModel/cascqaanalysis.h +++ b/PWGLF/DataModel/cascqaanalysis.h @@ -118,6 +118,7 @@ DECLARE_SOA_COLUMN(Pt, pt, float); DECLARE_SOA_COLUMN(Eta, eta, float); DECLARE_SOA_COLUMN(Phi, phi, float); DECLARE_SOA_COLUMN(MassLambda, masslambda, float); +DECLARE_SOA_COLUMN(CtauLambda, ctaulambda, float); DECLARE_SOA_COLUMN(MassXi, massxi, float); DECLARE_SOA_COLUMN(MassOmega, massomega, float); DECLARE_SOA_COLUMN(V2CEP, v2CEP, float); @@ -182,7 +183,7 @@ DECLARE_SOA_TABLE(CascAnalysisFull, "AOD", "CascAnalysisFull", o2::soa::Index<>, cascadesflow::CosThetaStarLambdaFromOmega, cascadesflow::CosThetaStarLambdaFromXi, cascadesflow::CosThetaStarProton, mycascades::McPdgCode); DECLARE_SOA_TABLE(LambdaAnalysis, "AOD", "LambdaAnalysis", o2::soa::Index<>, - cascadesflow::CentFT0C, cascadesflow::HasEventPlane, cascadesflow::HasSpectatorPlane, cascadesflow::Sign, cascadesflow::Pt, cascadesflow::Phi, cascadesflow::Eta, cascadesflow::MassLambda, cascadesflow::V0Radius, cascadesflow::DcaPosToPV, cascadesflow::DcaNegToPV, cascadesflow::V0CosPA, cascadesflow::DcaV0Daughters, cascadesflow::V2CEP, cascadesflow::PsiT0C, cascadesflow::Pzs2Lambda, cascadesflow::Cos2ThetaLambda, cascadesflow::CosThetaLambda); + cascadesflow::CentFT0C, cascadesflow::HasEventPlane, cascadesflow::HasSpectatorPlane, cascadesflow::Sign, cascadesflow::Pt, cascadesflow::Phi, cascadesflow::Eta, cascadesflow::MassLambda, cascadesflow::CtauLambda, cascadesflow::V0Radius, cascadesflow::DcaPosToPV, cascadesflow::DcaNegToPV, cascadesflow::V0CosPA, cascadesflow::DcaV0Daughters, cascadesflow::V2CEP, cascadesflow::PsiT0C, cascadesflow::Pzs2Lambda, cascadesflow::Cos2ThetaLambda, cascadesflow::CosThetaLambda); namespace myMCcascades { diff --git a/PWGLF/DataModel/mcCentrality.h b/PWGLF/DataModel/mcCentrality.h index 94544949017..2bb14880953 100644 --- a/PWGLF/DataModel/mcCentrality.h +++ b/PWGLF/DataModel/mcCentrality.h @@ -20,6 +20,7 @@ #ifndef PWGLF_DATAMODEL_MCCENTRALITY_H_ #define PWGLF_DATAMODEL_MCCENTRALITY_H_ +// O2 includes #include "Common/DataModel/Centrality.h" #include @@ -38,8 +39,12 @@ DECLARE_SOA_TABLE(McCentFV0As, "AOD", "MCCENTFV0A", o2::soa::Marker<1>, cent::Ce DECLARE_SOA_TABLE(McCentFT0Ms, "AOD", "MCCENTFT0M", o2::soa::Marker<2>, cent::CentFT0M); DECLARE_SOA_TABLE(McCentFT0As, "AOD", "MCCENTFT0A", o2::soa::Marker<3>, cent::CentFT0A); DECLARE_SOA_TABLE(McCentFT0Cs, "AOD", "MCCENTFT0C", o2::soa::Marker<4>, cent::CentFT0C); -DECLARE_SOA_TABLE(McCentFDDMs, "AOD", "MCCENTFDDM", o2::soa::Marker<5>, cent::CentFDDM); -DECLARE_SOA_TABLE(McCentNTPVs, "AOD", "MCCENTNTPV", o2::soa::Marker<6>, cent::CentNTPV); +DECLARE_SOA_TABLE(McCentFT0CVariant1s, "AOD", "MCCENTFT0CVAR1", o2::soa::Marker<5>, cent::CentFT0CVariant1); +DECLARE_SOA_TABLE(McCentFT0CVariant2s, "AOD", "MCCENTFT0CVAR2", o2::soa::Marker<6>, cent::CentFT0CVariant2); +DECLARE_SOA_TABLE(McCentFDDMs, "AOD", "MCCENTFDDM", o2::soa::Marker<7>, cent::CentFDDM); +DECLARE_SOA_TABLE(McCentNTPVs, "AOD", "MCCENTNTPV", o2::soa::Marker<8>, cent::CentNTPV); +DECLARE_SOA_TABLE(McCentNGlobals, "AOD", "MCCENTNGLOBAL", o2::soa::Marker<9>, cent::CentNGlobal); +DECLARE_SOA_TABLE(McCentMFTs, "AOD", "MCCENTMFT", o2::soa::Marker<10>, cent::CentMFT); } // namespace o2::aod diff --git a/PWGLF/TableProducer/Common/CMakeLists.txt b/PWGLF/TableProducer/Common/CMakeLists.txt index 19a1105dc3a..34a8b238d50 100644 --- a/PWGLF/TableProducer/Common/CMakeLists.txt +++ b/PWGLF/TableProducer/Common/CMakeLists.txt @@ -44,3 +44,8 @@ o2physics_add_dpl_workflow(kink-builder SOURCES kinkBuilder.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(zdc2stagecalibration + SOURCES zdc2stagecalibration.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsVertexing + COMPONENT_NAME Analysis) diff --git a/PWGLF/TableProducer/Common/epvector.cxx b/PWGLF/TableProducer/Common/epvector.cxx index a001de0407f..99e401b67d8 100644 --- a/PWGLF/TableProducer/Common/epvector.cxx +++ b/PWGLF/TableProducer/Common/epvector.cxx @@ -210,7 +210,7 @@ struct epvector { } template - bool eventSelected(TCollision collision, const float& centrality) + bool eventSelected(const TCollision& collision, const float& centrality) { if (collision.alias_bit(kTVXinTRD)) { // TRD triggered // return 0; diff --git a/PWGLF/TableProducer/Common/mcCentrality.cxx b/PWGLF/TableProducer/Common/mcCentrality.cxx index 3e017c5808b..2a73fa6f785 100644 --- a/PWGLF/TableProducer/Common/mcCentrality.cxx +++ b/PWGLF/TableProducer/Common/mcCentrality.cxx @@ -17,28 +17,20 @@ /// \brief Task to produce the table for the equalized multiplicity into centrality bins /// -#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/mcCentralityModule.h" -#include "PWGLF/Utils/inelGt.h" +#include "Common/DataModel/Multiplicity.h" #include -#include #include #include #include #include #include -#include #include -#include #include #include -#include -#include - -#include -#include #include using namespace o2; @@ -47,146 +39,37 @@ using namespace o2::framework::expressions; /// Task to produce the response table struct McCentrality { - - // Tables to produce - Produces centFV0A; - Produces centFT0M; - Produces centFT0A; - Produces centFT0C; - Produces centFDDM; - Produces centNTPV; - // Input parameters + o2::framework::Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Service ccdb; - Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - Configurable ccdbTimestamp{"ccdbTimestamp", -1, "timestamp of the object used to query in CCDB the detector response. If 0 the object corresponding to the run number is used, if < 0 the latest object is used"}; - Configurable path{"path", "/tmp/InputCalibMC.root", "path to calib file or ccdb path if begins with ccdb://"}; - Configurable selectPrimaries{"selectPrimaries", true, "Select only primary particles"}; - Service pdgDB; - ConfigurableAxis binsPercentile{"binsPercentile", {VARIABLE_WIDTH, 0, 0.001, 0.01, 1.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0}, "Binning of the percentile axis"}; - ConfigurableAxis binsMultiplicity{"binsMultiplicity", {1000, 0, 5000}, "Binning of the multiplicity axis"}; - Configurable fillFt0M{"fillFt0M", true, "Fills the FT0M histogram"}; - Configurable fillFt0A{"fillFt0A", false, "Fills the FT0A histogram"}; - Configurable fillFt0C{"fillFt0C", false, "Fills the FT0C histogram"}; - Configurable doNotCrashOnNull{"doNotCrashOnNull", false, "If ccdb object does not exist, fill with dummy values"}; - - HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - TH1F* h1dFT0M = nullptr; - TH1F* h1dFT0A = nullptr; - TH1F* h1dFT0C = nullptr; - // TH1F* h1dFDD; - // TH1F* h1dNTP; + o2::pwglf::mccentrality::products products; + o2::pwglf::mccentrality::coreConfigurables baseOpts; + o2::pwglf::mccentrality::BuilderModule mcCentralityBuilderModule; - o2::pwglf::ParticleCounter mCounter; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - void init(o2::framework::InitContext& /*initContext*/) + void init(o2::framework::InitContext& initContext) { // Set up the CCDB ccdb->setURL(ccdbUrl.value); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); - ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); ccdb->setFatalWhenNull(false); - mCounter.mPdgDatabase = pdgDB.service; - mCounter.mSelectPrimaries = selectPrimaries.value; - - if (fillFt0M) { - histos.add("FT0M/percentile", "FT0M percentile.", HistType::kTH1D, {{binsPercentile, "FT0M percentile"}}); - histos.add("FT0M/percentilevsMult", "FT0M percentile.", HistType::kTH2D, {{binsPercentile, "FT0M percentile"}, {binsMultiplicity, "FT0M mult."}}); - } - if (fillFt0A) { - histos.add("FT0A/percentile", "FT0A percentile.", HistType::kTH1D, {{binsPercentile, "FT0A percentile"}}); - histos.add("FT0A/percentilevsMult", "FT0A percentile.", HistType::kTH2D, {{binsPercentile, "FT0A percentile"}, {binsMultiplicity, "FT0A mult."}}); - } - if (fillFt0C) { - histos.add("FT0C/percentile", "FT0C percentile.", HistType::kTH1D, {{binsPercentile, "FT0C percentile"}}); - histos.add("FT0C/percentilevsMult", "FT0C percentile.", HistType::kTH2D, {{binsPercentile, "FT0C percentile"}, {binsMultiplicity, "FT0C mult."}}); - } - - TList* lOfInput = nullptr; - if (path.value.rfind("ccdb://", 0) == 0) { // Getting post calib. from CCDB - path.value.replace(0, 7, ""); - lOfInput = ccdb->get(path); - if (!lOfInput) { - if (doNotCrashOnNull) { - LOG(info) << "Could not find the calibration TList from CCDB in path " << path << ", will fill tables with dummy values"; - } else { - LOG(fatal) << "Could not find the calibration TList from CCDB in path " << path; - return; - } - } - } else { // Getting post calib. from file - TFile* f = TFile::Open(path.value.c_str(), "READ"); - if (!f) { - LOG(fatal) << "The input file " << path << " is not valid"; - } - if (!f->IsOpen()) { - LOG(fatal) << "The input file " << f->GetName() << " is not open"; - } - lOfInput = static_cast(f->Get("ccdb_object")); - if (!lOfInput) { - f->ls(); - LOG(fatal) << "The input file " << path.value << " does not contain the TList ccdb_object"; - } - } - auto getHist = [this, lOfInput](const char* name) -> TH1F* { - if (!lOfInput) { - return nullptr; - } - auto hist = static_cast(lOfInput->FindObject(name)); - if (!hist) { - lOfInput->ls(); - if (this->doNotCrashOnNull) { - LOG(info) << "Could not open histogram " << name << " from TList, will fill tables with dummy values"; - } else { - LOG(fatal) << "Could not open histogram " << name << " from TList"; - } - } - return hist; - }; - if (fillFt0M) { - h1dFT0M = getHist("h1dFT0M"); - } - if (fillFt0A) { - h1dFT0A = getHist("h1dFT0A"); - } - if (fillFt0C) { - h1dFT0C = getHist("h1dFT0C"); - } + mcCentralityBuilderModule.init(baseOpts, histos, initContext); } // Full tables (independent on central calibrations) - void process(aod::McCollision const& /*mcCollision*/, - aod::McParticles const& mcParticles) + void process(soa::Join const& mcCollisions, + aod::BCsWithTimestamps const& bcs) { - const float nFT0A = mCounter.countFT0A(mcParticles); - const float nFT0C = mCounter.countFT0C(mcParticles); - const float nFT0M = nFT0A + nFT0C; - // const float nFV0A = mCounter.countFV0A(mcParticles); - - if (fillFt0M) { - const float valueCentFT0M = h1dFT0M ? h1dFT0M->GetBinContent(h1dFT0M->FindBin(nFT0M)) : 105.0f; - centFT0M(valueCentFT0M); - histos.fill(HIST("FT0M/percentile"), valueCentFT0M); - histos.fill(HIST("FT0M/percentilevsMult"), valueCentFT0M, nFT0M); - } - if (fillFt0A) { - const float valueCentFT0A = h1dFT0A ? h1dFT0A->GetBinContent(h1dFT0A->FindBin(nFT0A)) : 105.0f; - centFT0A(valueCentFT0A); - histos.fill(HIST("FT0A/percentile"), valueCentFT0A); - histos.fill(HIST("FT0A/percentilevsMult"), valueCentFT0A, nFT0A); - } - if (fillFt0C) { - const float valueCentFT0C = h1dFT0C ? h1dFT0C->GetBinContent(h1dFT0C->FindBin(nFT0C)) : 105.0f; - centFT0C(valueCentFT0C); - histos.fill(HIST("FT0C/percentile"), valueCentFT0C); - histos.fill(HIST("FT0C/percentilevsMult"), valueCentFT0C, nFT0C); - } - // const float valueCentFV0A = h1dFT0M->GetBinContent(h1dFT0M->FindBin(nFV0A)); - // centFV0A(valueCentFV0A); + mcCentralityBuilderModule.dataProcess(ccdb, histos, bcs, mcCollisions, products); } }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{adaptAnalysisTask(cfgc)}; } +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Common/zdc2stagecalibration.cxx b/PWGLF/TableProducer/Common/zdc2stagecalibration.cxx new file mode 100644 index 00000000000..3d39e10fbdc --- /dev/null +++ b/PWGLF/TableProducer/Common/zdc2stagecalibration.cxx @@ -0,0 +1,677 @@ +// 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. +// +// \author: sourav kundu +// \email: sourav.kundu@cern.ch + +#include "PWGLF/DataModel/ZDC2StageCalibrationTables.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::aod::rctsel; + +using BCsRun3 = o2::soa::Join; + +struct zdc2stagecalibration { + + o2::framework::Produces zdccaltable; + + struct : ConfigurableGroup { + Configurable cfgURL{"cfgURL", "http://alice-ccdb.cern.ch", "Address of the CCDB to browse"}; + } cfgCcdbParam; + + Service ccdb{}; + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; + Configurable cfgCutCentralityMax{"cfgCutCentralityMax", 80.0f, "Centrality cut Max"}; + Configurable cfgCutCentralityMin{"cfgCutCentralityMin", 0.0f, "Centrality cut Min"}; + Configurable calibrationStage{"calibrationStage", 1, "1: derive detector calibration QA, 2: apply detector calibration and produce corrected Q"}; + Configurable cfgTimeSliceMinutes{"cfgTimeSliceMinutes", 30.0f, "Calibration time-slice width in minutes"}; + Configurable cfgMaxRunHours{"cfgMaxRunHours", 48.0f, "Maximum run duration shown in QA"}; + Configurable followpub{"followpub", true, "flag to use alphaZDC"}; + Configurable usecfactor{"usecfactor", false, "use c factor"}; + Configurable useGainCallib{"useGainCallib", false, "use stage-1 tower gain calibration"}; + Configurable confGainPath{"confGainPath", "", "CCDB path to the run-wise stage-1 gain map"}; + Configurable useSpatialCalib{"useSpatialCalib", false, "use ZDC spatial calibration"}; + Configurable confSpatialPath{"confSpatialPath", "", "CCDB path to ZDC spatial calibration"}; + Configurable deriveSpatialCalib{"deriveSpatialCalib", false, "store spatial regression moments after gain correction"}; + Configurable deriveQRecentering{"deriveQRecentering", false, "store Q-vector recentering regression moments after gain and spatial correction"}; + Configurable useQRecentering{"useQRecentering", false, "apply Q-vector recentering calibration"}; + Configurable confQRecenteringPath{"confQRecenteringPath", "", "CCDB path to the run-wise Q-vector recentering coefficients"}; + + Configurable cfgSpatialCalibBins{ + "cfgSpatialCalibBins", 30, + "number of bins per cross coordinate for spatial calibration"}; + struct : ConfigurableGroup { + Configurable requireRCTFlagChecker{"requireRCTFlagChecker", true, "Check event quality in run condition table"}; + Configurable cfgEvtRCTFlagCheckerLabel{"cfgEvtRCTFlagCheckerLabel", "CBT", "Evt sel: RCT flag checker label"}; + Configurable cfgEvtRCTFlagCheckerZDCCheck{"cfgEvtRCTFlagCheckerZDCCheck", true, "Evt sel: RCT flag checker ZDC check"}; + Configurable cfgEvtRCTFlagCheckerLimitAcceptAsBad{"cfgEvtRCTFlagCheckerLimitAcceptAsBad", false, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + } rctCut; + + RCTFlagsChecker rctChecker; + int currentRunNumber = -999; + int64_t bcSOR = -1; + uint64_t sorTimestamp = 0; + uint64_t eorTimestamp = 0; + TH2D* gainprofile = nullptr; + TH3D* spatialprofile = nullptr; + TH2D* qRecenteringProfile = nullptr; + + static constexpr int kQRecenteringNFeatures = 21; + static constexpr int kQRecenteringNMatrixMoments = kQRecenteringNFeatures * (kQRecenteringNFeatures + 1) / 2; + static constexpr int kQRecenteringNComponents = 4; + static constexpr int kQRecenteringNMoments = kQRecenteringNMatrixMoments + kQRecenteringNComponents * kQRecenteringNFeatures; + + void init(o2::framework::InitContext&) + { + rctChecker.init(rctCut.cfgEvtRCTFlagCheckerLabel, rctCut.cfgEvtRCTFlagCheckerZDCCheck, rctCut.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + + const int nTimeBins = static_cast(std::ceil(cfgMaxRunHours.value * 60.f / cfgTimeSliceMinutes.value)); + AxisSpec timeAxis = {nTimeBins, 0.0, cfgMaxRunHours.value, "time from SOR (h)"}; + AxisSpec towerAxis = {4, 0.0, 4.0, "tower"}; + AxisSpec crossAxis = {120, -1.0, 1.0, "cross asymmetry"}; + AxisSpec momentAxis = {15, 0.0, 15.0, "regression moment"}; + AxisSpec spatialMomentAxis = {6, 0.0, 6.0, "normalized pair regression moment"}; + AxisSpec spatialCalibAxis = {cfgSpatialCalibBins.value, -1.0, 1.0, "cross asymmetry"}; + AxisSpec phiAxis = {72, -3.14159265358979323846, 3.14159265358979323846, "#phi"}; + AxisSpec crossCoordAxis = {2, 0.0, 2.0, "coordinate"}; + AxisSpec ratioAxis = {240, 0.0, 2.4, "#Sigma tower/common"}; + AxisSpec qRecenteringMomentAxis = {kQRecenteringNMoments, 0.0, static_cast(kQRecenteringNMoments), "regression moment"}; + AxisSpec centralityAxis = {80, 0.0, 80.0, "centrality (%)"}; + AxisSpec vertexXYAxis = {100, -0.5, 0.5, "vertex x/y (cm)"}; + AxisSpec vertexZAxis = {100, -10.0, 10.0, "vertex z (cm)"}; + AxisSpec qComponentAxis = {4, 0.0, 4.0, "Q component"}; + + histos.add("hEvtSelInfo", "hEvtSelInfo", kTH1F, {{10, 0.0, 10.0}}); + auto hEvtSelInfo = histos.get(HIST("hEvtSelInfo")); + hEvtSelInfo->GetXaxis()->SetBinLabel(1, "All"); + hEvtSelInfo->GetXaxis()->SetBinLabel(2, "has ZDC"); + hEvtSelInfo->GetXaxis()->SetBinLabel(3, "valid common"); + hEvtSelInfo->GetXaxis()->SetBinLabel(4, "valid towers"); + hEvtSelInfo->GetXaxis()->SetBinLabel(5, "RCT CBT+ZDC"); + hEvtSelInfo->GetXaxis()->SetBinLabel(6, "event sel."); + hEvtSelInfo->GetXaxis()->SetBinLabel(7, "gain valid"); + hEvtSelInfo->GetXaxis()->SetBinLabel(8, "valid Q"); + hEvtSelInfo->GetXaxis()->SetBinLabel(9, "accepted"); + histos.add("GainQA/hSumOverCommonVsTimeZNA", "ZNA tower sum/common vs time;time from SOR (h);#Sigma T_{i}/C", kTH2F, {timeAxis, ratioAxis}); + histos.add("GainQA/hSumOverCommonVsTimeZNC", "ZNC tower sum/common vs time;time from SOR (h);#Sigma T_{i}/C", kTH2F, {timeAxis, ratioAxis}); + histos.add("GainQA/pTowerOverCommonVsTimeZNA", "ZNA individual tower/common vs time;time from SOR (h);tower;", kTProfile2D, {timeAxis, towerAxis}); + histos.add("GainQA/pTowerOverCommonVsTimeZNC", "ZNC individual tower/common vs time;time from SOR (h);tower;", kTProfile2D, {timeAxis, towerAxis}); + histos.add("SpatialQA/pCrossVsTimeZNA", "ZNA cross asymmetry vs time;time from SOR (h);0:X cross, 1:Y cross;", kTProfile2D, {timeAxis, crossCoordAxis}); + histos.add("SpatialQA/pCrossVsTimeZNC", "ZNC cross asymmetry vs time;time from SOR (h);0:X cross, 1:Y cross;", kTProfile2D, {timeAxis, crossCoordAxis}); + histos.add("SpatialQA/pResponseVsCrossXYZNA", "ZNA response map;X cross;Y cross;<#Sigma T_{i}/C>", kTProfile2D, {crossAxis, crossAxis}); + histos.add("SpatialQA/pResponseVsCrossXYZNC", "ZNC response map;X cross;Y cross;<#Sigma T_{i}/C>", kTProfile2D, {crossAxis, crossAxis}); + histos.add("SpatialQA/pCentroidVsTimeZNA", "ZNA centroid vs time;time from SOR (h);0:x, 1:y;", kTProfile2D, {timeAxis, crossCoordAxis}); + histos.add("SpatialQA/pCentroidVsTimeZNC", "ZNC centroid vs time;time from SOR (h);0:x, 1:y;", kTProfile2D, {timeAxis, crossCoordAxis}); + histos.add("SpatialQA/hCrossXYZNA", "ZNA cross occupancy;X cross;Y cross", kTH2F, {crossAxis, crossAxis}); + histos.add("SpatialQA/hCrossXYZNC", "ZNC cross occupancy;X cross;Y cross", kTH2F, {crossAxis, crossAxis}); + histos.add("SpatialQA/pTower1OverCommonVsCrossXYZNA", "ZNA tower 1 response;X cross;Y cross;", kTProfile2D, {crossAxis, crossAxis}); + histos.add("SpatialQA/pTower2OverCommonVsCrossXYZNA", "ZNA tower 2 response;X cross;Y cross;", kTProfile2D, {crossAxis, crossAxis}); + histos.add("SpatialQA/pTower3OverCommonVsCrossXYZNA", "ZNA tower 3 response;X cross;Y cross;", kTProfile2D, {crossAxis, crossAxis}); + histos.add("SpatialQA/pTower4OverCommonVsCrossXYZNA", "ZNA tower 4 response;X cross;Y cross;", kTProfile2D, {crossAxis, crossAxis}); + histos.add("SpatialQA/pTower1OverCommonVsCrossXYZNC", "ZNC tower 1 response;X cross;Y cross;", kTProfile2D, {crossAxis, crossAxis}); + histos.add("SpatialQA/pTower2OverCommonVsCrossXYZNC", "ZNC tower 2 response;X cross;Y cross;", kTProfile2D, {crossAxis, crossAxis}); + histos.add("SpatialQA/pTower3OverCommonVsCrossXYZNC", "ZNC tower 3 response;X cross;Y cross;", kTProfile2D, {crossAxis, crossAxis}); + histos.add("SpatialQA/pTower4OverCommonVsCrossXYZNC", "ZNC tower 4 response;X cross;Y cross;", kTProfile2D, {crossAxis, crossAxis}); + histos.add("PhiQA/hPhiRawZNA", "ZNA #phi raw;#phi;events", kTH1F, {phiAxis}); + histos.add("PhiQA/hPhiRawZNC", "ZNC #phi raw;#phi;events", kTH1F, {phiAxis}); + histos.add("PhiQA/hPhiAfterGainZNA", "ZNA #phi after gain calibration;#phi;events", kTH1F, {phiAxis}); + histos.add("PhiQA/hPhiAfterGainZNC", "ZNC #phi after gain calibration;#phi;events", kTH1F, {phiAxis}); + histos.add("PhiQA/hPhiAfterSpatialZNA", "ZNA #phi after spatial calibration;#phi;events", kTH1F, {phiAxis}); + histos.add("PhiQA/hPhiAfterSpatialZNC", "ZNC #phi after spatial calibration;#phi;events", kTH1F, {phiAxis}); + + // Stage-1 correction input. For each time bin the first 10 y bins contain sum(T_i*T_j), the next 4 contain sum(C*T_i), and the last contains the event count. + histos.add("GainCalibration/hGainMomentsZNA", "ZNA linear-regression moments;time from SOR (h);moment index", kTH2D, {timeAxis, momentAxis}); + histos.add("GainCalibration/hGainMomentsZNC", "ZNC linear-regression moments;time from SOR (h);moment index", kTH2D, {timeAxis, momentAxis}); + // Normalized two-pair spatial regression moments. For each (Xcross,Ycross) cell: + // u=(T1+T4)/C, v=(T2+T3)/C, and moments are u^2, u*v, v^2, u, v, N. + histos.add("SpatialCalibration/hSpatialMomentsZNA", "ZNA normalized pair spatial regression moments;X cross;Y cross;moment index", kTH3D, {spatialCalibAxis, spatialCalibAxis, spatialMomentAxis}); + histos.add("SpatialCalibration/hSpatialMomentsZNC", "ZNC normalized pair spatial regression moments;X cross;Y cross;moment index", kTH3D, {spatialCalibAxis, spatialCalibAxis, spatialMomentAxis}); + + // Q-recentering regression moments. Feature order: + // 0:1, 1:C, 2:T, 3:Vx, 4:Vy, 5:Vz, 6:C2, 7:T2, 8:Vx2, 9:Vy2, 10:Vz2, + // 11:C*T, 12:C*Vx, 13:C*Vy, 14:C*Vz, 15:T*Vx, 16:T*Vy, 17:T*Vz, + // 18:Vx*Vy, 19:Vx*Vz, 20:Vy*Vz. + // Moments 0..230 are the upper triangle of sum(X_i X_j). + // Then 4 blocks of 21 sum(X_i Q): QxA, QyA, QxC, QyC. + histos.add("QRecenteringCalibration/hRegressionMoments", "Q recentering regression moments;moment index;sum", kTH1D, {qRecenteringMomentAxis}); + + histos.add("QRecenteringQA/pQBeforeVsCentrality", "Q before recentering vs centrality;centrality (%);Q component;", kTProfile2D, {centralityAxis, qComponentAxis}); + histos.add("QRecenteringQA/pQBeforeVsTime", "Q before recentering vs time;time from SOR (h);Q component;", kTProfile2D, {timeAxis, qComponentAxis}); + histos.add("QRecenteringQA/pQBeforeVsVx", "Q before recentering vs v_{x};v_{x} (cm);Q component;", kTProfile2D, {vertexXYAxis, qComponentAxis}); + histos.add("QRecenteringQA/pQBeforeVsVy", "Q before recentering vs v_{y};v_{y} (cm);Q component;", kTProfile2D, {vertexXYAxis, qComponentAxis}); + histos.add("QRecenteringQA/pQBeforeVsVz", "Q before recentering vs v_{z};v_{z} (cm);Q component;", kTProfile2D, {vertexZAxis, qComponentAxis}); + histos.add("QRecenteringQA/pQAfterVsCentrality", "Q after recentering vs centrality;centrality (%);Q component;", kTProfile2D, {centralityAxis, qComponentAxis}); + histos.add("QRecenteringQA/pQAfterVsTime", "Q after recentering vs time;time from SOR (h);Q component;", kTProfile2D, {timeAxis, qComponentAxis}); + histos.add("QRecenteringQA/pQAfterVsVx", "Q after recentering vs v_{x};v_{x} (cm);Q component;", kTProfile2D, {vertexXYAxis, qComponentAxis}); + histos.add("QRecenteringQA/pQAfterVsVy", "Q after recentering vs v_{y};v_{y} (cm);Q component;", kTProfile2D, {vertexXYAxis, qComponentAxis}); + histos.add("QRecenteringQA/pQAfterVsVz", "Q after recentering vs v_{z};v_{z} (cm);Q component;", kTProfile2D, {vertexZAxis, qComponentAxis}); + histos.add("PhiQA/hPhiAfterRecenteringZNA", "ZNA #phi after Q recentering;#phi;events", kTH1F, {phiAxis}); + histos.add("PhiQA/hPhiAfterRecenteringZNC", "ZNC #phi after Q recentering;#phi;events", kTH1F, {phiAxis}); + + ccdb->setURL(cfgCcdbParam.cfgURL); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + } + + void updateRun(int runNumber, uint64_t timestamp) + { + if (runNumber == currentRunNumber) { + return; + } + + currentRunNumber = runNumber; + auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::BasicCCDBManager::instance(), runNumber); + sorTimestamp = runInfo.sor; + eorTimestamp = runInfo.eor; + bcSOR = static_cast(runInfo.orbitSOR) * static_cast(o2::constants::lhc::LHCMaxBunches); + gainprofile = nullptr; + spatialprofile = nullptr; + qRecenteringProfile = nullptr; + if (calibrationStage.value == 2 && useGainCallib.value && !confGainPath.value.empty()) { + gainprofile = ccdb->getForTimeStamp(confGainPath.value, timestamp); + if (!gainprofile) { + LOGF(warn, "No ZDC stage-1 gain map found for run %d at timestamp %llu", runNumber, static_cast(timestamp)); + } + } + if (calibrationStage.value == 2 && useSpatialCalib.value && !confSpatialPath.value.empty()) { + spatialprofile = ccdb->getForTimeStamp(confSpatialPath.value, timestamp); + + if (!spatialprofile) { + LOGF(warn, "No ZDC spatial calibration found for run %d at timestamp %llu", runNumber, static_cast(timestamp)); + } + } + if (calibrationStage.value == 2 && useQRecentering.value && !confQRecenteringPath.value.empty()) { + qRecenteringProfile = ccdb->getForTimeStamp(confQRecenteringPath.value, timestamp); + if (!qRecenteringProfile) { + LOGF(warn, "No ZDC Q-recentering calibration found for run %d at timestamp %llu", runNumber, static_cast(timestamp)); + } + } + } + + float getTimeFromSOR(uint64_t globalBC) const + { + if (bcSOR < 0 || globalBC < static_cast(bcSOR)) { + return -1.f; + } + const double deltaBC = static_cast(globalBC - static_cast(bcSOR)); + return static_cast(deltaBC * o2::constants::lhc::LHCBunchSpacingNS * 1.e-9 / 3600.); + } + + double getGain(float timeFromSOR, int channel, bool& gainOK) const + { + if (calibrationStage.value != 2 || !useGainCallib.value) { + return 1.0; + } + if (!gainprofile || timeFromSOR < 0.f) { + gainOK = false; + return 1.0; + } + const double gain = gainprofile->GetBinContent(gainprofile->FindBin(timeFromSOR + 1.e-7, channel + 0.5)); + if (!std::isfinite(gain) || gain <= 0.0) { + gainOK = false; + return 1.0; + } + return gain; + } + + std::array makeQRecenteringFeatures(float centrality, float timeFromSOR, float vx, float vy, float vz) const + { + // Fixed scaling keeps the polynomial basis numerically well behaved and must be + // used identically when solving/applying the CCDB coefficients. + const double c = (static_cast(centrality) - 40.0) / 40.0; + const double runHours = (eorTimestamp > sorTimestamp) ? static_cast(eorTimestamp - sorTimestamp) * 1.e-3 / 3600.0 : static_cast(cfgMaxRunHours.value); + const double t = (runHours > 0.0) ? (2.0 * static_cast(timeFromSOR) / runHours - 1.0) : 0.0; + const double x = static_cast(vx) / 0.1; + const double y = static_cast(vy) / 0.1; + const double z = static_cast(vz) / 10.0; + + return {1.0, c, t, x, y, z, + c * c, t * t, x * x, y * y, z * z, + c * t, c * x, c * y, c * z, + t * x, t * y, t * z, + x * y, x * z, y * z}; + } + + using MyCollisions = o2::soa::Join; + + void process(MyCollisions::iterator const& collision, o2::aod::FT0s const& /*ft0s*/, o2::aod::FV0As const& /*fv0s*/, BCsRun3 const& /*bcs*/, o2::aod::Zdcs const& /*zdcs*/) + { + histos.fill(HIST("hEvtSelInfo"), 0.5); + + const float centrality = collision.centFT0C(); + const float vx = collision.posX(); + const float vy = collision.posY(); + const float vz = collision.posZ(); + auto bc = collision.foundBC_as(); + const int runNumber = bc.runNumber(); + const uint64_t globalBC = bc.globalBC(); + const uint64_t timestamp = bc.timestamp(); + + updateRun(runNumber, timestamp); + const float timeFromSOR = getTimeFromSOR(globalBC); + + auto fillTable = [&](bool trigger, float qxA, float qxC, float qyA, float qyC) { + zdccaltable(collision.globalIndex(), trigger, runNumber, globalBC, centrality, vx, vy, vz, qxA, qxC, qyA, qyC); + }; + + if (!bc.has_zdc()) { + fillTable(false, 0.f, 0.f, 0.f, 0.f); + return; + } + histos.fill(HIST("hEvtSelInfo"), 1.5); + + auto zdc = bc.zdc(); + auto znaEnergy = zdc.energySectorZNA(); + auto zncEnergy = zdc.energySectorZNC(); + const float znaEnergycommon = zdc.energyCommonZNA(); + const float zncEnergycommon = zdc.energyCommonZNC(); + + if (!std::isfinite(znaEnergycommon) || !std::isfinite(zncEnergycommon) || znaEnergycommon <= 0.f || zncEnergycommon <= 0.f) { + fillTable(false, 0.f, 0.f, 0.f, 0.f); + return; + } + histos.fill(HIST("hEvtSelInfo"), 2.5); + + bool validTowers = true; + for (int i = 0; i < 4; ++i) { + if (!std::isfinite(znaEnergy[i]) || !std::isfinite(zncEnergy[i]) || znaEnergy[i] <= 0.f || zncEnergy[i] <= 0.f) { + validTowers = false; + } + } + if (!validTowers) { + fillTable(false, 0.f, 0.f, 0.f, 0.f); + return; + } + histos.fill(HIST("hEvtSelInfo"), 3.5); + + if (rctCut.requireRCTFlagChecker && !rctChecker(collision)) { + fillTable(false, 0.f, 0.f, 0.f, 0.f); + return; + } + histos.fill(HIST("hEvtSelInfo"), 4.5); + + if (!(collision.sel8() && collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV) && std::isfinite(centrality) && centrality > cfgCutCentralityMin && centrality < cfgCutCentralityMax && std::abs(vz) < cfgCutVertex && collision.has_foundFT0())) { + fillTable(false, 0.f, 0.f, 0.f, 0.f); + return; + } + histos.fill(HIST("hEvtSelInfo"), 5.5); + + if (timeFromSOR < 0.f || timeFromSOR >= cfgMaxRunHours.value) { + fillTable(false, 0.f, 0.f, 0.f, 0.f); + return; + } + + constexpr double x[4] = {-1.75, 1.75, -1.75, 1.75}; + constexpr double y[4] = {-1.75, -1.75, 1.75, 1.75}; + + double rawXA = 0.0; + double rawYA = 0.0; + double rawXC = 0.0; + double rawYC = 0.0; + double rawSumA = 0.0; + double rawSumC = 0.0; + for (int i = 0; i < 4; ++i) { + rawXA -= znaEnergy[i] * x[i]; + rawYA += znaEnergy[i] * y[i]; + rawXC += zncEnergy[i] * x[i]; + rawYC += zncEnergy[i] * y[i]; + rawSumA += znaEnergy[i]; + rawSumC += zncEnergy[i]; + } + rawXA /= rawSumA; + rawYA /= rawSumA; + rawXC /= rawSumC; + rawYC /= rawSumC; + const double phiRawA = std::atan2(rawYA, rawXA); + const double phiRawC = std::atan2(rawYC, rawXC); + histos.fill(HIST("PhiQA/hPhiRawZNA"), phiRawA); + histos.fill(HIST("PhiQA/hPhiRawZNC"), phiRawC); + + if (calibrationStage.value == 1) { + std::array momentsA{}; + std::array momentsC{}; + int moment = 0; + for (int i = 0; i < 4; ++i) { + for (int j = i; j < 4; ++j) { + momentsA[moment] = static_cast(znaEnergy[i]) * static_cast(znaEnergy[j]); + momentsC[moment] = static_cast(zncEnergy[i]) * static_cast(zncEnergy[j]); + ++moment; + } + } + for (int i = 0; i < 4; ++i) { + momentsA[10 + i] = static_cast(znaEnergycommon) * static_cast(znaEnergy[i]); + momentsC[10 + i] = static_cast(zncEnergycommon) * static_cast(zncEnergy[i]); + } + momentsA[14] = 1.0; + momentsC[14] = 1.0; + for (int i = 0; i < 15; ++i) { + histos.fill(HIST("GainCalibration/hGainMomentsZNA"), timeFromSOR, i + 0.5, momentsA[i]); + histos.fill(HIST("GainCalibration/hGainMomentsZNC"), timeFromSOR, i + 0.5, momentsC[i]); + } + } + + bool gainOK = true; + std::array znaCorr{}; + std::array zncCorr{}; + for (int i = 0; i < 4; ++i) { + znaCorr[i] = getGain(timeFromSOR, i, gainOK) * znaEnergy[i]; + zncCorr[i] = getGain(timeFromSOR, i + 4, gainOK) * zncEnergy[i]; + } + if (!gainOK) { + fillTable(false, 0.f, 0.f, 0.f, 0.f); + return; + } + histos.fill(HIST("hEvtSelInfo"), 6.5); + + double gainXA = 0.0; + double gainYA = 0.0; + double gainXC = 0.0; + double gainYC = 0.0; + double gainSumA = 0.0; + double gainSumC = 0.0; + for (int i = 0; i < 4; ++i) { + gainXA -= znaCorr[i] * x[i]; + gainYA += znaCorr[i] * y[i]; + gainXC += zncCorr[i] * x[i]; + gainYC += zncCorr[i] * y[i]; + gainSumA += znaCorr[i]; + gainSumC += zncCorr[i]; + } + gainXA /= gainSumA; + gainYA /= gainSumA; + gainXC /= gainSumC; + gainYC /= gainSumC; + const double phiGainA = std::atan2(gainYA, gainXA); + const double phiGainC = std::atan2(gainYC, gainXC); + histos.fill(HIST("PhiQA/hPhiAfterGainZNA"), phiGainA); + histos.fill(HIST("PhiQA/hPhiAfterGainZNC"), phiGainC); + + const double crossLookupXA = (znaCorr[3] - znaCorr[0]) / (znaCorr[3] + znaCorr[0]); + const double crossLookupYA = (znaCorr[2] - znaCorr[1]) / (znaCorr[2] + znaCorr[1]); + const double crossLookupXC = (zncCorr[3] - zncCorr[0]) / (zncCorr[3] + zncCorr[0]); + const double crossLookupYC = (zncCorr[2] - zncCorr[1]) / (zncCorr[2] + zncCorr[1]); + if (calibrationStage.value == 2 && useGainCallib.value && deriveSpatialCalib.value && !useSpatialCalib.value) { + + const double uA = (znaCorr[0] + znaCorr[3]) / static_cast(znaEnergycommon); + const double vA = (znaCorr[1] + znaCorr[2]) / static_cast(znaEnergycommon); + const double uC = (zncCorr[0] + zncCorr[3]) / static_cast(zncEnergycommon); + const double vC = (zncCorr[1] + zncCorr[2]) / static_cast(zncEnergycommon); + + if (std::isfinite(uA) && std::isfinite(vA) && std::isfinite(uC) && std::isfinite(vC)) { + const std::array spatialMomentsA = { + uA * uA, + uA * vA, + vA * vA, + uA, + vA, + 1.0}; + const std::array spatialMomentsC = { + uC * uC, + uC * vC, + vC * vC, + uC, + vC, + 1.0}; + + for (int i = 0; i < 6; ++i) { + histos.fill(HIST("SpatialCalibration/hSpatialMomentsZNA"), crossLookupXA, crossLookupYA, i + 0.5, spatialMomentsA[i]); + histos.fill(HIST("SpatialCalibration/hSpatialMomentsZNC"), crossLookupXC, crossLookupYC, i + 0.5, spatialMomentsC[i]); + } + } + } + + bool spatialOK = true; + if (calibrationStage.value == 2 && useSpatialCalib.value) { + if (!spatialprofile) { + spatialOK = false; + } else { + for (int i = 0; i < 4; ++i) { + const double corrA = spatialprofile->GetBinContent(spatialprofile->FindBin(crossLookupXA, crossLookupYA, i + 0.5)); + const double corrC = spatialprofile->GetBinContent(spatialprofile->FindBin(crossLookupXC, crossLookupYC, i + 4.5)); + if (!std::isfinite(corrA) || corrA <= 0.0 || !std::isfinite(corrC) || corrC <= 0.0) { + spatialOK = false; + break; + } + znaCorr[i] *= corrA; + zncCorr[i] *= corrC; + } + } + } + if (!spatialOK) { + fillTable(false, 0.f, 0.f, 0.f, 0.f); + return; + } + + double sumEnergyA = 0.0; + double sumEnergyC = 0.0; + for (int i = 0; i < 4; ++i) { + sumEnergyA += znaCorr[i]; + sumEnergyC += zncCorr[i]; + } + + const double ratioA = sumEnergyA / znaEnergycommon; + const double ratioC = sumEnergyC / zncEnergycommon; + const double crossXA = (znaCorr[3] - znaCorr[0]) / (znaCorr[3] + znaCorr[0]); + const double crossYA = (znaCorr[2] - znaCorr[1]) / (znaCorr[2] + znaCorr[1]); + const double crossXC = (zncCorr[3] - zncCorr[0]) / (zncCorr[3] + zncCorr[0]); + const double crossYC = (zncCorr[2] - zncCorr[1]) / (zncCorr[2] + zncCorr[1]); + + double centroidXA = 0.0; + double centroidYA = 0.0; + double centroidXC = 0.0; + double centroidYC = 0.0; + for (int i = 0; i < 4; ++i) { + centroidXA -= znaCorr[i] * x[i]; + centroidYA += znaCorr[i] * y[i]; + centroidXC += zncCorr[i] * x[i]; + centroidYC += zncCorr[i] * y[i]; + } + centroidXA /= sumEnergyA; + centroidYA /= sumEnergyA; + centroidXC /= sumEnergyC; + centroidYC /= sumEnergyC; + const double phiSpatialA = std::atan2(centroidYA, centroidXA); + const double phiSpatialC = std::atan2(centroidYC, centroidXC); + histos.fill(HIST("PhiQA/hPhiAfterSpatialZNA"), phiSpatialA); + histos.fill(HIST("PhiQA/hPhiAfterSpatialZNC"), phiSpatialC); + + histos.fill(HIST("GainQA/hSumOverCommonVsTimeZNA"), timeFromSOR, ratioA); + histos.fill(HIST("GainQA/hSumOverCommonVsTimeZNC"), timeFromSOR, ratioC); + for (int i = 0; i < 4; ++i) { + histos.fill(HIST("GainQA/pTowerOverCommonVsTimeZNA"), timeFromSOR, i + 0.5, znaCorr[i] / znaEnergycommon); + histos.fill(HIST("GainQA/pTowerOverCommonVsTimeZNC"), timeFromSOR, i + 0.5, zncCorr[i] / zncEnergycommon); + } + histos.fill(HIST("SpatialQA/pCrossVsTimeZNA"), timeFromSOR, 0.5, crossXA); + histos.fill(HIST("SpatialQA/pCrossVsTimeZNA"), timeFromSOR, 1.5, crossYA); + histos.fill(HIST("SpatialQA/pCrossVsTimeZNC"), timeFromSOR, 0.5, crossXC); + histos.fill(HIST("SpatialQA/pCrossVsTimeZNC"), timeFromSOR, 1.5, crossYC); + histos.fill(HIST("SpatialQA/pResponseVsCrossXYZNA"), crossLookupXA, crossLookupYA, ratioA); + histos.fill(HIST("SpatialQA/pResponseVsCrossXYZNC"), crossLookupXC, crossLookupYC, ratioC); + histos.fill(HIST("SpatialQA/pCentroidVsTimeZNA"), timeFromSOR, 0.5, centroidXA); + histos.fill(HIST("SpatialQA/pCentroidVsTimeZNA"), timeFromSOR, 1.5, centroidYA); + histos.fill(HIST("SpatialQA/pCentroidVsTimeZNC"), timeFromSOR, 0.5, centroidXC); + histos.fill(HIST("SpatialQA/pCentroidVsTimeZNC"), timeFromSOR, 1.5, centroidYC); + histos.fill(HIST("SpatialQA/hCrossXYZNA"), crossLookupXA, crossLookupYA); + histos.fill(HIST("SpatialQA/hCrossXYZNC"), crossLookupXC, crossLookupYC); + + histos.fill(HIST("SpatialQA/pTower1OverCommonVsCrossXYZNA"), crossLookupXA, crossLookupYA, znaCorr[0] / znaEnergycommon); + histos.fill(HIST("SpatialQA/pTower2OverCommonVsCrossXYZNA"), crossLookupXA, crossLookupYA, znaCorr[1] / znaEnergycommon); + histos.fill(HIST("SpatialQA/pTower3OverCommonVsCrossXYZNA"), crossLookupXA, crossLookupYA, znaCorr[2] / znaEnergycommon); + histos.fill(HIST("SpatialQA/pTower4OverCommonVsCrossXYZNA"), crossLookupXA, crossLookupYA, znaCorr[3] / znaEnergycommon); + + histos.fill(HIST("SpatialQA/pTower1OverCommonVsCrossXYZNC"), crossLookupXC, crossLookupYC, zncCorr[0] / zncEnergycommon); + histos.fill(HIST("SpatialQA/pTower2OverCommonVsCrossXYZNC"), crossLookupXC, crossLookupYC, zncCorr[1] / zncEnergycommon); + histos.fill(HIST("SpatialQA/pTower3OverCommonVsCrossXYZNC"), crossLookupXC, crossLookupYC, zncCorr[2] / zncEnergycommon); + histos.fill(HIST("SpatialQA/pTower4OverCommonVsCrossXYZNC"), crossLookupXC, crossLookupYC, zncCorr[3] / zncEnergycommon); + const double alphaZDC = 0.395; + double qxZDCA = 0.0; + double qxZDCC = 0.0; + double qyZDCA = 0.0; + double qyZDCC = 0.0; + double sumA = 0.0; + double sumC = 0.0; + + for (int i = 0; i < 4; ++i) { + double amplA = znaCorr[i]; + double amplC = zncCorr[i]; + if (followpub) { + amplA = std::pow(amplA, alphaZDC); + amplC = std::pow(amplC, alphaZDC); + } + qxZDCA -= amplA * x[i]; + qyZDCA += amplA * y[i]; + qxZDCC += amplC * x[i]; + qyZDCC += amplC * y[i]; + sumA += amplA; + sumC += amplC; + } + + if (sumA <= 1.e-4 || sumC <= 1.e-4) { + fillTable(false, 0.f, 0.f, 0.f, 0.f); + return; + } + + double cZNA = 1.0; + double cZNC = 1.0; + if (usecfactor) { + const double beamEne = 5.36 * 0.5; + const double nSpecnA = sumEnergyA / beamEne; + const double nSpecnC = sumEnergyC / beamEne; + cZNA = 1.89358 - 0.71262 / (nSpecnA + 0.71789); + cZNC = 1.89358 - 0.71262 / (nSpecnC + 0.71789); + } + + qxZDCA = cZNA * qxZDCA / sumA; + qyZDCA = cZNA * qyZDCA / sumA; + qxZDCC = cZNC * qxZDCC / sumC; + qyZDCC = cZNC * qyZDCC / sumC; + + if (!std::isfinite(qxZDCA) || !std::isfinite(qyZDCA) || !std::isfinite(qxZDCC) || !std::isfinite(qyZDCC)) { + fillTable(false, 0.f, 0.f, 0.f, 0.f); + return; + } + + const auto qFeatures = makeQRecenteringFeatures(centrality, timeFromSOR, vx, vy, vz); + std::array qValues = {qxZDCA, qyZDCA, qxZDCC, qyZDCC}; + + for (int i = 0; i < 4; ++i) { + const double component = i + 0.5; + histos.fill(HIST("QRecenteringQA/pQBeforeVsCentrality"), centrality, component, qValues[i]); + histos.fill(HIST("QRecenteringQA/pQBeforeVsTime"), timeFromSOR, component, qValues[i]); + histos.fill(HIST("QRecenteringQA/pQBeforeVsVx"), vx, component, qValues[i]); + histos.fill(HIST("QRecenteringQA/pQBeforeVsVy"), vy, component, qValues[i]); + histos.fill(HIST("QRecenteringQA/pQBeforeVsVz"), vz, component, qValues[i]); + } + + if (calibrationStage.value == 2 && useGainCallib.value && useSpatialCalib.value && deriveQRecentering.value && !useQRecentering.value) { + int moment = 0; + for (int i = 0; i < kQRecenteringNFeatures; ++i) { + for (int j = i; j < kQRecenteringNFeatures; ++j) { + histos.fill(HIST("QRecenteringCalibration/hRegressionMoments"), moment + 0.5, qFeatures[i] * qFeatures[j]); + ++moment; + } + } + for (int component = 0; component < kQRecenteringNComponents; ++component) { + for (int i = 0; i < kQRecenteringNFeatures; ++i) { + const int index = kQRecenteringNMatrixMoments + component * kQRecenteringNFeatures + i; + histos.fill(HIST("QRecenteringCalibration/hRegressionMoments"), index + 0.5, qFeatures[i] * qValues[component]); + } + } + } + + bool qRecenteringOK = true; + if (calibrationStage.value == 2 && useQRecentering.value) { + if (!qRecenteringProfile) { + qRecenteringOK = false; + } else { + for (int component = 0; component < kQRecenteringNComponents; ++component) { + double predictedBias = 0.0; + for (int i = 0; i < kQRecenteringNFeatures; ++i) { + const double coefficient = qRecenteringProfile->GetBinContent(qRecenteringProfile->FindBin(i + 0.5, component + 0.5)); + if (!std::isfinite(coefficient)) { + qRecenteringOK = false; + break; + } + predictedBias += coefficient * qFeatures[i]; + } + if (!qRecenteringOK || !std::isfinite(predictedBias)) { + qRecenteringOK = false; + break; + } + qValues[component] -= predictedBias; + } + } + } + if (!qRecenteringOK) { + fillTable(false, 0.f, 0.f, 0.f, 0.f); + return; + } + + for (int i = 0; i < 4; ++i) { + const double component = i + 0.5; + histos.fill(HIST("QRecenteringQA/pQAfterVsCentrality"), centrality, component, qValues[i]); + histos.fill(HIST("QRecenteringQA/pQAfterVsTime"), timeFromSOR, component, qValues[i]); + histos.fill(HIST("QRecenteringQA/pQAfterVsVx"), vx, component, qValues[i]); + histos.fill(HIST("QRecenteringQA/pQAfterVsVy"), vy, component, qValues[i]); + histos.fill(HIST("QRecenteringQA/pQAfterVsVz"), vz, component, qValues[i]); + } + + const double phiRecenteringA = std::atan2(qValues[1], qValues[0]); + const double phiRecenteringC = std::atan2(qValues[3], qValues[2]); + histos.fill(HIST("PhiQA/hPhiAfterRecenteringZNA"), phiRecenteringA); + histos.fill(HIST("PhiQA/hPhiAfterRecenteringZNC"), phiRecenteringC); + + histos.fill(HIST("hEvtSelInfo"), 7.5); + fillTable(true, static_cast(qValues[0]), static_cast(qValues[2]), static_cast(qValues[1]), static_cast(qValues[3])); + histos.fill(HIST("hEvtSelInfo"), 8.5); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Common/zdcvector.cxx b/PWGLF/TableProducer/Common/zdcvector.cxx index c32e81cdc7f..d1c5eb20766 100644 --- a/PWGLF/TableProducer/Common/zdcvector.cxx +++ b/PWGLF/TableProducer/Common/zdcvector.cxx @@ -113,7 +113,6 @@ struct zdcvector { Configurable storeZdcTime{"storeZdcTime", true, "Store timestamp and time from first event of run"}; RCTFlagsChecker rctChecker; - std::unordered_map runStartTime; void init(o2::framework::InitContext&) { @@ -177,6 +176,8 @@ struct zdcvector { TH2D* gainprofile = nullptr; TProfile* gainprofilevxy = nullptr; + int runNumberForSOR = -1; + uint64_t sorTimestamp = 0; // int lastRunNumberTimeRec = -999; // for time since start of run // int runForStartTime = -999; @@ -230,14 +231,23 @@ struct zdcvector { auto bc = collision.foundBC_as(); const uint64_t timestampzdc = bc.timestamp(); // in milliseconds + if (currentRunNumber != runNumberForSOR) { + + auto runDuration = ccdb->getRunDuration(currentRunNumber, true); + sorTimestamp = static_cast(runDuration.first); + runNumberForSOR = currentRunNumber; + + LOGF(info, + "Run %d: SOR timestamp = %llu ms", + currentRunNumber, + static_cast(sorTimestamp)); + } + float timeInMinutes = 0.f; - auto itStart = runStartTime.find(currentRunNumber); - if (itStart == runStartTime.end()) { - runStartTime[currentRunNumber] = timestampzdc; - timeInMinutes = 0.f; - } else { - timeInMinutes = static_cast(timestampzdc - itStart->second) / 60000.f; + if (timestampzdc >= sorTimestamp && sorTimestamp > 0) { + timeInMinutes = + static_cast(timestampzdc - sorTimestamp) / 60000.f; } // Helper to keep your early-return structure unchanged. diff --git a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx index b71c38eb678..7466a973bcb 100644 --- a/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx +++ b/PWGLF/TableProducer/Nuspex/decay3bodybuilder.cxx @@ -75,7 +75,7 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; -o2::common::core::MetadataHelper metadataInfo; +o2::common::core::MetadataHelper metadataInfo{}; static constexpr int nParameters = 1; static const std::vector tableNames{ @@ -220,34 +220,31 @@ struct decay3bodyBuilder { // Helper struct to contain MC information prior to filling struct mc3Bodyinfo { - int label; - std::array genDecVtx{0.f}; - std::array genMomentum{0.f}; - float genCt; - float genPhi; - float genEta; - float genRapidity; - float genMomProton; - float genMomPion; - float genMomDeuteron; - float genPtProton; - float genPtPion; - float genPtDeuteron; - bool isReco; - int motherLabel; - int motherPdgCode; - int daughterPrPdgCode; - int daughterPiPdgCode; - int daughterDePdgCode; - bool isDeuteronPrimary; - bool survivedEventSel; + int label = -1; + std::array genDecVtx{-1.f, -1.f, -1.f}; + std::array genMomentum{-1.f, -1.f, -1.f}; + float genCt = -1.f; + float genPhi = -1.f; + float genEta = -1.f; + float genRapidity = -1.f; + std::array genMomProton{-1.f, -1.f, -1.f}; + std::array genMomPion{-1.f, -1.f, -1.f}; + std::array genMomDeuteron{-1.f, -1.f, -1.f}; + bool isReco = false; + int motherLabel = -1; + int motherPdgCode = -1; + int daughterPrPdgCode = -1; + int daughterPiPdgCode = -1; + int daughterDePdgCode = -1; + bool isDeuteronPrimary = false; + bool survivedEventSel = false; }; mc3Bodyinfo this3BodyMCInfo; // CCDB and magnetic field - int mRunNumber; - float d_bz; - Service ccdb; + int mRunNumber = 0; + float d_bz = 0.f; + Service ccdb{}; o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; std::unordered_map ccdbCache; // Maps runNumber -> d_bz o2::base::MatLayerCylSet* lut = nullptr; @@ -382,7 +379,7 @@ struct decay3bodyBuilder { // list enabled tables for (int i = 0; i < nTables; i++) { - if (mEnabledTables[i]) { + if (mEnabledTables[i] != 0) { LOGF(info, " -~> Table enabled: %s", tableNames[i]); } } @@ -436,26 +433,26 @@ struct decay3bodyBuilder { } } - if (mEnabledTables[kVtx3BodyDatas] && mEnabledTables[kMcVtx3BodyDatas]) { + if (mEnabledTables[kVtx3BodyDatas] != 0 && mEnabledTables[kMcVtx3BodyDatas] != 0) { LOG(fatal) << "Tables Vtx3BodyDatas and McVtx3BodyDatas cannot both be enabled at the same time. Choose one!"; } // Add histograms separately for different process functions - if (doprocessRealData == true || doprocessMonteCarlo == true) { + if (doprocessRealData || doprocessMonteCarlo) { auto hEventCounter = registry.add("Counters/hEventCounter", "hEventCounter", HistType::kTH1D, {{2, 0.0f, 2.0f}}); hEventCounter->GetXaxis()->SetBinLabel(1, "all"); hEventCounter->GetXaxis()->SetBinLabel(2, "selected"); hEventCounter->LabelsOption("v"); } - if (doprocessMonteCarlo == true) { + if (doprocessMonteCarlo) { auto hMcEventCounter = registry.add("Counters/hMcEventCounter", "hMcEventCounter", HistType::kTH1D, {{2, 0.0f, 2.0f}}); hMcEventCounter->GetXaxis()->SetBinLabel(1, "all"); hMcEventCounter->GetXaxis()->SetBinLabel(2, "reconstructed"); hMcEventCounter->LabelsOption("v"); } - if (doprocessRealData == true || doprocessRealDataReduced == true || doprocessMonteCarlo == true) { + if (doprocessRealData || doprocessRealDataReduced || doprocessMonteCarlo) { if (doTrackQA) { // histograms for all daughter tracks of (selected) 3body candidates registry.add("QA/Tracks/hTrackProtonTPCNcls", "hTrackProtonTPCNcls", HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}); registry.add("QA/Tracks/hTrackPionTPCNcls", "hTrackPionTPCNcls", HistType::kTH1F, {{152, 0, 152, "# TPC clusters"}}); @@ -485,7 +482,7 @@ struct decay3bodyBuilder { } } - if (doprocessRealDataReduced3bodyMixing == true) { + if (doprocessRealDataReduced3bodyMixing) { auto h3bodyCombinationCounter = registry.add("Mixing/h3bodyCombinationCounter", "h3bodyCombinationCounter", HistType::kTH1D, {{4, 0.0f, 4.0f}}); h3bodyCombinationCounter->GetXaxis()->SetBinLabel(1, "total"); h3bodyCombinationCounter->GetXaxis()->SetBinLabel(2, "not same collision"); @@ -516,7 +513,7 @@ struct decay3bodyBuilder { } auto timestamp = bc.timestamp(); - o2::parameters::GRPMagField* grpmag = 0x0; + o2::parameters::GRPMagField* grpmag = nullptr; ccdb->clearCache(ccdbConfigurations.grpmagPath); grpmag = ccdb->getSpecific(ccdbConfigurations.grpmagPath, timestamp); if (!grpmag) { @@ -524,7 +521,7 @@ struct decay3bodyBuilder { } o2::base::Propagator::initFieldFromGRP(grpmag); // Fetch magnetic field from ccdb for current collision - auto d_bz = o2::base::Propagator::Instance()->getNominalBz(); + d_bz = o2::base::Propagator::Instance()->getNominalBz(); LOG(info) << "Retrieved GRP for timestamp " << timestamp << " with magnetic field of " << d_bz << " kG"; // set magnetic field value for DCA fitter @@ -553,9 +550,9 @@ struct decay3bodyBuilder { float getMagFieldFromRunNumber(int runNumber) { - float magField; + float magField{}; // Check if the CCDB data for this run is already cached - if (ccdbCache.find(runNumber) != ccdbCache.end()) { + if (ccdbCache.contains(runNumber)) { LOG(debug) << "CCDB data already cached for run " << runNumber; magField = ccdbCache[runNumber]; // if not, retrieve it from CCDB @@ -732,10 +729,10 @@ struct decay3bodyBuilder { auto trackPion = protonSign > 0 ? trackNeg : trackPos; // get deuteron TOF PID - float tofNSigmaDeuteron; + float tofNSigmaDeuteron{}; if constexpr (!soa::is_table) { // running over derived data tofNSigmaDeuteron = trackDeuteron.tofNSigmaDe(); - } else if constexpr (soa::is_table) { // running over AO2Ds + } else { // running over AO2Ds if constexpr (soa::is_table) { // running over MC (track table with labels) tofNSigmaDeuteron = getTOFnSigma(mRespParamsV3, collision, trackDeuteron); } else { // running over real data @@ -806,11 +803,10 @@ struct decay3bodyBuilder { if (!trackProton.has_mcParticle() || !trackPion.has_mcParticle() || !trackDeuteron.has_mcParticle()) { if (!doStoreMcBkg) { continue; // if not storing MC background, skip candidates where at least one daughter is not matched to MC particle - } else { - this3BodyMCInfo.motherLabel = -5; // at least one of the daughters not matched to MC particle - // fill analysis table (only McVtx3BodyDatas is filled here) - fillAnalysisTables(); } + this3BodyMCInfo.motherLabel = -5; // at least one of the daughters not matched to MC particle + // fill analysis table (only McVtx3BodyDatas is filled here) + fillAnalysisTables(); } else { // all daughters are matched to MC particles, get their MC info // get MC daughter particles auto mcTrackProton = trackProton.template mcParticle_as(); @@ -822,12 +818,9 @@ struct decay3bodyBuilder { this3BodyMCInfo.daughterPiPdgCode = mcTrackPion.pdgCode(); this3BodyMCInfo.daughterDePdgCode = mcTrackDeuteron.pdgCode(); this3BodyMCInfo.isDeuteronPrimary = mcTrackDeuteron.isPhysicalPrimary(); - this3BodyMCInfo.genMomProton = mcTrackProton.p(); - this3BodyMCInfo.genMomPion = mcTrackPion.p(); - this3BodyMCInfo.genMomDeuteron = mcTrackDeuteron.p(); - this3BodyMCInfo.genPtProton = mcTrackProton.pt(); - this3BodyMCInfo.genPtPion = mcTrackPion.pt(); - this3BodyMCInfo.genPtDeuteron = mcTrackDeuteron.pt(); + this3BodyMCInfo.genMomProton = {mcTrackProton.px(), mcTrackProton.py(), mcTrackProton.pz()}; + this3BodyMCInfo.genMomPion = {mcTrackPion.px(), mcTrackPion.py(), mcTrackPion.pz()}; + this3BodyMCInfo.genMomDeuteron = {mcTrackDeuteron.px(), mcTrackDeuteron.py(), mcTrackDeuteron.pz()}; // daughters are matched to MC, now we check if reco mother is true H3L/Anti-H3l and decayed via three-body decay this3BodyMCInfo.motherLabel = checkH3LTruth(mcTrackProton, mcTrackPion, mcTrackDeuteron); // returns global index of mother if true H3L/Anti-H3L mother decaying via three-body decay, otherwise negative value for background @@ -886,18 +879,24 @@ struct decay3bodyBuilder { bool haveProton = false, havePion = false, haveDeuteron = false; bool haveAntiProton = false, haveAntiPion = false, haveAntiDeuteron = false; for (const auto& mcparticleDaughter : mcparticle.template daughters_as()) { - if (mcparticleDaughter.pdgCode() == PDG_t::kProton) + if (mcparticleDaughter.pdgCode() == PDG_t::kProton) { haveProton = true; - if (mcparticleDaughter.pdgCode() == PDG_t::kProtonBar) + } + if (mcparticleDaughter.pdgCode() == PDG_t::kProtonBar) { haveAntiProton = true; - if (mcparticleDaughter.pdgCode() == PDG_t::kPiPlus) + } + if (mcparticleDaughter.pdgCode() == PDG_t::kPiPlus) { havePion = true; - if (mcparticleDaughter.pdgCode() == PDG_t::kPiMinus) + } + if (mcparticleDaughter.pdgCode() == PDG_t::kPiMinus) { haveAntiPion = true; - if (mcparticleDaughter.pdgCode() == o2::constants::physics::Pdg::kDeuteron) + } + if (mcparticleDaughter.pdgCode() == o2::constants::physics::Pdg::kDeuteron) { haveDeuteron = true; - if (mcparticleDaughter.pdgCode() == -o2::constants::physics::Pdg::kDeuteron) + } + if (mcparticleDaughter.pdgCode() == -o2::constants::physics::Pdg::kDeuteron) { haveAntiDeuteron = true; + } } // check if hypertriton decayed via 3-body decay and is particle or anti-particle @@ -905,17 +904,14 @@ struct decay3bodyBuilder { // get daughters for (const auto& mcparticleDaughter : mcparticle.template daughters_as()) { if (std::abs(mcparticleDaughter.pdgCode()) == PDG_t::kProton) { // proton - this3BodyMCInfo.genMomProton = mcparticleDaughter.p(); - this3BodyMCInfo.genPtProton = mcparticleDaughter.pt(); + this3BodyMCInfo.genMomProton = {mcparticleDaughter.px(), mcparticleDaughter.py(), mcparticleDaughter.pz()}; this3BodyMCInfo.daughterPrPdgCode = mcparticleDaughter.pdgCode(); this3BodyMCInfo.genDecVtx = {mcparticleDaughter.vx(), mcparticleDaughter.vy(), mcparticleDaughter.vz()}; } else if (std::abs(mcparticleDaughter.pdgCode()) == PDG_t::kPiPlus) { // pion - this3BodyMCInfo.genMomPion = mcparticleDaughter.p(); - this3BodyMCInfo.genPtPion = mcparticleDaughter.pt(); + this3BodyMCInfo.genMomPion = {mcparticleDaughter.px(), mcparticleDaughter.py(), mcparticleDaughter.pz()}; this3BodyMCInfo.daughterPiPdgCode = mcparticleDaughter.pdgCode(); } else if (std::abs(mcparticleDaughter.pdgCode()) == o2::constants::physics::Pdg::kDeuteron) { // deuteron - this3BodyMCInfo.genMomDeuteron = mcparticleDaughter.p(); - this3BodyMCInfo.genPtDeuteron = mcparticleDaughter.pt(); + this3BodyMCInfo.genMomDeuteron = {mcparticleDaughter.px(), mcparticleDaughter.py(), mcparticleDaughter.pz()}; this3BodyMCInfo.daughterDePdgCode = mcparticleDaughter.pdgCode(); this3BodyMCInfo.isDeuteronPrimary = mcparticleDaughter.isPhysicalPrimary(); } @@ -957,8 +953,9 @@ struct decay3bodyBuilder { this3BodyMCInfo.genDecVtx[0], this3BodyMCInfo.genDecVtx[1], this3BodyMCInfo.genDecVtx[2], this3BodyMCInfo.genCt, mcparticle.phi(), mcparticle.eta(), mcparticle.y(), - this3BodyMCInfo.genMomProton, this3BodyMCInfo.genMomPion, this3BodyMCInfo.genMomDeuteron, - this3BodyMCInfo.genPtProton, this3BodyMCInfo.genPtPion, this3BodyMCInfo.genPtDeuteron, + this3BodyMCInfo.genMomProton[0], this3BodyMCInfo.genMomProton[1], this3BodyMCInfo.genMomProton[2], + this3BodyMCInfo.genMomPion[0], this3BodyMCInfo.genMomPion[1], this3BodyMCInfo.genMomPion[2], + this3BodyMCInfo.genMomDeuteron[0], this3BodyMCInfo.genMomDeuteron[1], this3BodyMCInfo.genMomDeuteron[2], this3BodyMCInfo.isReco, mcparticle.globalIndex(), // motherLabel mcparticle.pdgCode(), // motherPdgCode @@ -1085,13 +1082,13 @@ struct decay3bodyBuilder { void fillAnalysisTables() { // generate analysis tables - if (mEnabledTables[kDecay3BodyIndices]) { + if (mEnabledTables[kDecay3BodyIndices] != 0) { products.decay3bodyindices(helper.decay3body.decay3bodyID, helper.decay3body.protonID, helper.decay3body.pionID, helper.decay3body.deuteronID, helper.decay3body.collisionID); registry.fill(HIST("Counters/hTableBuildingStatistics"), kDecay3BodyIndices); } - if (mEnabledTables[kVtx3BodyDatas]) { + if (mEnabledTables[kVtx3BodyDatas] != 0) { products.vtx3bodydatas(helper.decay3body.sign, helper.decay3body.mass, helper.decay3body.massV0, helper.decay3body.position[0], helper.decay3body.position[1], helper.decay3body.position[2], @@ -1117,14 +1114,14 @@ struct decay3bodyBuilder { helper.decay3body.pidForTrackingDeuteron); registry.fill(HIST("Counters/hTableBuildingStatistics"), kVtx3BodyDatas); } - if (mEnabledTables[kVtx3BodyCovs]) { + if (mEnabledTables[kVtx3BodyCovs] != 0) { products.vtx3bodycovs(helper.decay3body.covProton.data(), helper.decay3body.covPion.data(), helper.decay3body.covDeuteron.data(), helper.decay3body.covariance.data()); registry.fill(HIST("Counters/hTableBuildingStatistics"), kVtx3BodyCovs); } - if (mEnabledTables[kMcVtx3BodyDatas]) { + if (mEnabledTables[kMcVtx3BodyDatas] != 0) { products.mcvtx3bodydatas(helper.decay3body.sign, helper.decay3body.mass, helper.decay3body.massV0, helper.decay3body.position[0], helper.decay3body.position[1], helper.decay3body.position[2], @@ -1153,8 +1150,9 @@ struct decay3bodyBuilder { this3BodyMCInfo.genDecVtx[0], this3BodyMCInfo.genDecVtx[1], this3BodyMCInfo.genDecVtx[2], this3BodyMCInfo.genCt, this3BodyMCInfo.genPhi, this3BodyMCInfo.genEta, this3BodyMCInfo.genRapidity, - this3BodyMCInfo.genMomProton, this3BodyMCInfo.genMomPion, this3BodyMCInfo.genMomDeuteron, - this3BodyMCInfo.genPtProton, this3BodyMCInfo.genPtPion, this3BodyMCInfo.genPtDeuteron, + this3BodyMCInfo.genMomProton[0], this3BodyMCInfo.genMomProton[1], this3BodyMCInfo.genMomProton[2], + this3BodyMCInfo.genMomPion[0], this3BodyMCInfo.genMomPion[1], this3BodyMCInfo.genMomPion[2], + this3BodyMCInfo.genMomDeuteron[0], this3BodyMCInfo.genMomDeuteron[1], this3BodyMCInfo.genMomDeuteron[2], this3BodyMCInfo.isReco, this3BodyMCInfo.motherLabel, this3BodyMCInfo.motherPdgCode, @@ -1189,9 +1187,8 @@ struct decay3bodyBuilder { // fill analysis tables with built candidate fillAnalysisTables(); return; - } else { - return; } + return; } // ______________________________________________________________ @@ -1266,9 +1263,8 @@ struct decay3bodyBuilder { // check if the common mother is a hypertriton if (std::abs(momPdgCode) == o2::constants::physics::Pdg::kHyperTriton) { return momID; - } else { - return -1; // common mother found but not a hypertriton } + return -1; // common mother found but not a hypertriton } // ______________________________________________________________ @@ -1280,8 +1276,9 @@ struct decay3bodyBuilder { mcInfo.genDecVtx[0] = -1., mcInfo.genDecVtx[1] = -1., mcInfo.genDecVtx[2] = -1.; mcInfo.genCt = -1.; mcInfo.genPhi = -1., mcInfo.genEta = -1., mcInfo.genRapidity = -1.; - mcInfo.genMomProton = -1., mcInfo.genMomPion = -1., mcInfo.genMomDeuteron = -1.; - mcInfo.genPtProton = -1., mcInfo.genPtPion = -1., mcInfo.genPtDeuteron = -1.; + mcInfo.genMomProton[0] = -1., mcInfo.genMomProton[1] = -1., mcInfo.genMomProton[2] = -1.; + mcInfo.genMomPion[0] = -1., mcInfo.genMomPion[1] = -1., mcInfo.genMomPion[2] = -1.; + mcInfo.genMomDeuteron[0] = -1., mcInfo.genMomDeuteron[1] = -1., mcInfo.genMomDeuteron[2] = -1.; mcInfo.isReco = false; mcInfo.motherPdgCode = 0; mcInfo.daughterPrPdgCode = -1, mcInfo.daughterPiPdgCode = -1, mcInfo.daughterDePdgCode = -1; @@ -1345,7 +1342,7 @@ struct decay3bodyBuilder { auto yAxis = registry.get(HIST("Mixing/hDecay3BodyRadiusPhi"))->GetYaxis(); for (const auto& decay3body : decay3bodys) { - int bin_Radius, bin_Phi; + int bin_Radius{}, bin_Phi{}; if (decay3bodyBuilderOpts.useKFParticle) { bin_Radius = xAxis->FindBin(decay3body.radiusKF()); bin_Phi = yAxis->FindBin(decay3body.phiKF()); diff --git a/PWGLF/TableProducer/Nuspex/deuteronInTriggeredEvents.cxx b/PWGLF/TableProducer/Nuspex/deuteronInTriggeredEvents.cxx index a62030fc507..9d855c71fda 100644 --- a/PWGLF/TableProducer/Nuspex/deuteronInTriggeredEvents.cxx +++ b/PWGLF/TableProducer/Nuspex/deuteronInTriggeredEvents.cxx @@ -283,7 +283,6 @@ struct DeuteronInTriggeredEvents { Configurable rapidityToggle{"rapidityToggle", false, "If true, use rapidity cuts"}; Configurable tpcChi2ClusMax{"tpcChi2ClusMax", 4.f, "Max TPC Chi2 per cluster"}; Configurable tpcNCrossedRowsMin{"tpcNCrossedRowsMin", 70, "Minimum number of TPC crossed rows"}; - Configurable tpcNCrossedRowsOverFindableMin{"tpcNCrossedRowsOverFindableMin", 0.8f, "Minimum ratio of crossed rows over findable clusters"}; Configurable tpcNClsMin{"tpcNClsMin", 80, "Minimum number of TPC clusters"}; Configurable tpcRigidityMin{"tpcRigidityMin", 0.5f, "Minimum TPC rigidity for tracks"}; Configurable> tpcNSigmaMax{"tpcNSigmaMax", {nuclei::NSigmaTPCdefault[0], 5, 2, nuclei::names, nuclei::nSigmaConfigName}, "TPC nsigma selection for light nuclei"}; @@ -355,7 +354,7 @@ struct DeuteronInTriggeredEvents { HistogramRegistry spectra{"spectra", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - double computeAbsoDecL(aod::McParticles::iterator particle) + double computeAbsoDecL(const aod::McParticles::iterator& particle) { if (!particle.has_daughters()) return -1.f; @@ -777,7 +776,6 @@ struct DeuteronInTriggeredEvents { track.itsNCls() < cfgTrackCut.itsNClusMin || track.tpcNClsFound() < cfgTrackCut.tpcNClsMin || track.tpcNClsCrossedRows() < cfgTrackCut.tpcNCrossedRowsMin || - track.tpcNClsCrossedRows() < cfgTrackCut.tpcNCrossedRowsOverFindableMin * track.tpcNClsFindable() || track.tpcChi2NCl() > cfgTrackCut.tpcChi2ClusMax || track.itsChi2NCl() > cfgTrackCut.itsChi2ClusMax) { continue; @@ -993,7 +991,7 @@ struct DeuteronInTriggeredEvents { } std::vector isReconstructed(particlesMC.size(), false); - for (auto& c : nuclei::candidates) { + for (auto& c : nuclei::candidates) { // o2-linter: disable=const-ref-in-for-loop (candidate is modified in loop) auto label = tracks.iteratorAt(c.globalIndex); if (label.mcParticleId() < -1 || label.mcParticleId() >= particlesMC.size()) { continue; diff --git a/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx b/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx index b533a14b32c..d30182f35dc 100644 --- a/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx +++ b/PWGLF/TableProducer/Nuspex/he3HadronFemto.cxx @@ -57,6 +57,8 @@ #include #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) #include +#include +#include #include #include #include diff --git a/PWGLF/TableProducer/Nuspex/hypKfRecoTask.cxx b/PWGLF/TableProducer/Nuspex/hypKfRecoTask.cxx index 7755a77bc8a..c164f9233ca 100644 --- a/PWGLF/TableProducer/Nuspex/hypKfRecoTask.cxx +++ b/PWGLF/TableProducer/Nuspex/hypKfRecoTask.cxx @@ -20,6 +20,7 @@ #include "PWGLF/DataModel/LFHypernucleiKfTables.h" #include "PWGLF/DataModel/LFPIDTOFGenericTables.h" +#include "Common/CCDB/EventSelectionParams.h" #include "Common/Core/MetadataHelper.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" @@ -198,7 +199,7 @@ struct DaughterParticle { std::array betheParams; std::array trkSettings; bool active; - DaughterParticle(std::string name_, int pdgCode_, double mass_, int charge_, LabeledArray bethe, LabeledArray settings) : name(name_), pdgCode(pdgCode_), charge(charge_), mass(mass_), active(false) + DaughterParticle(const std::string& name_, int pdgCode_, double mass_, int charge_, const LabeledArray& bethe, const LabeledArray& settings) : name(name_), pdgCode(pdgCode_), charge(charge_), mass(mass_), active(false) { for (unsigned int i = 0; i < betheParams.size(); i++) { betheParams[i] = bethe.get(name, i); @@ -220,19 +221,19 @@ struct HyperNucleus { bool active, savePrimary; std::vector daughters, daughterTrackSigns, v0DaughterVec; std::vector primSettings; - HyperNucleus(std::string name_, int pdgCode_, bool active_, std::vector daughters_, std::vector daughterTrackSigns_, std::vector v0DaughterVec_, LabeledArray primSettings_) : pdgCode(pdgCode_), active(active_), savePrimary(active_) + HyperNucleus(const std::string& name_, int pdgCode_, bool active_, const std::vector& daughters_, const std::vector& daughterTrackSigns_, const std::vector& v0DaughterVec_, const LabeledArray& primSettings_) : pdgCode(pdgCode_), active(active_), savePrimary(active_) { - init(name_, daughters_, daughterTrackSigns_, v0DaughterVec_); + init(std::move(name_), std::move(daughters_), std::move(daughterTrackSigns_), std::move(v0DaughterVec_)); for (unsigned int i = 0; i < nSelPrim; i++) { primSettings.push_back(primSettings_.get(name, i)); } } - HyperNucleus(std::string name_, int pdgCode_, bool active_, int hypDaughter, std::vector daughters_, std::vector daughterTrackSigns_) : pdgCode(pdgCode_), active(active_), savePrimary(active_) + HyperNucleus(const std::string& name_, int pdgCode_, bool active_, int hypDaughter, const std::vector& daughters_, const std::vector& daughterTrackSigns_) : pdgCode(pdgCode_), active(active_), savePrimary(active_) { daughters.push_back(hypDaughter); - init(name_, daughters_, daughterTrackSigns_); + init(std::move(name_), std::move(daughters_), std::move(daughterTrackSigns_)); } - void init(std::string name_, std::vector daughters_, std::vector daughterTrackSigns_, std::vector v0DaughterVec_ = {}) + void init(const std::string& name_, const std::vector& daughters_, const std::vector& daughterTrackSigns_, const std::vector& v0DaughterVec_ = {}) { name = TString(name_); for (const int& d : daughters_) @@ -262,11 +263,11 @@ struct DaughterKf { int64_t daughterTrackId; int id, species, sign, hypNucId; KFParticle daughterKfp; - float dcaToPv, dcaToPvXY, dcaToPvZ, tpcNsigma, tpcNsigmaNLP, tpcNsigmaNHP; + float dcaToPv, dcaToPvXY, dcaToPvZ, tpcNsigma, itsNsigma; bool active; std::vector vtx; - DaughterKf(int species_, int64_t daughterTrackId_, int sign_, std::vector vtx_, float tpcNsigma_, float tpcNsigmaNLP_, float tpcNsigmaNHP_) : daughterTrackId(daughterTrackId_), id(uniqueId++), species(species_), sign(sign_), hypNucId(-1), tpcNsigma(tpcNsigma_), tpcNsigmaNLP(tpcNsigmaNLP_), tpcNsigmaNHP(tpcNsigmaNHP_), vtx(vtx_) {} - void addKfp(KFParticle daughterKfp_) + DaughterKf(int species_, int64_t daughterTrackId_, int sign_, std::vector vtx_, float tpcNsigma_, float itsNsigma_) : daughterTrackId(daughterTrackId_), id(uniqueId++), species(species_), sign(sign_), hypNucId(-1), tpcNsigma(tpcNsigma_), itsNsigma(itsNsigma_), vtx(std::move(vtx_)) {} + void addKfp(const KFParticle& daughterKfp_) { daughterKfp = daughterKfp_; dcaToPvXY = daughterKfp.GetDistanceFromVertexXY(&vtx[0]); @@ -290,7 +291,7 @@ struct HyperNucCandidate { bool mcTrue, isPhysPrimary, isPrimaryCandidate, isSecondaryCandidate, isUsedSecondary; int64_t mcParticleId; int tableId; - HyperNucCandidate(int species_, HyperNucCandidate* hypNucDaughter_, std::vector daughters_) : species(species_), hypNucDaughter(hypNucDaughter_), devToPvXY(-999), dcaToPvXY(-999), dcaToPvZ(-999), dcaToVtxXY(-999), dcaToVtxZ(-999), chi2(-999), itsMeanClsSize(-1), mcTrue(false), isPhysPrimary(false), isPrimaryCandidate(false), isSecondaryCandidate(false), isUsedSecondary(false), mcParticleId(-1), tableId(-1) + HyperNucCandidate(int species_, HyperNucCandidate* hypNucDaughter_, const std::vector& daughters_) : species(species_), hypNucDaughter(hypNucDaughter_), devToPvXY(-999), dcaToPvXY(-999), dcaToPvZ(-999), dcaToVtxXY(-999), dcaToVtxZ(-999), chi2(-999), itsMeanClsSize(-1), mcTrue(false), isPhysPrimary(false), isPrimaryCandidate(false), isSecondaryCandidate(false), isUsedSecondary(false), mcParticleId(-1), tableId(-1) { for (const auto& d : daughters_) daughters.push_back(d); @@ -402,7 +403,7 @@ struct HyperNucCandidate { } return calcSubDaughterMass(daughters.at(d1)->daughterKfp, hypNucDaughter->daughters.at(d2)->daughterKfp); } - float calcSubDaughterMass(KFParticle d1, KFParticle d2) + float calcSubDaughterMass(const KFParticle& d1, const KFParticle& d2) { KFParticle subDaughter; subDaughter.SetConstructMethod(2); @@ -475,7 +476,7 @@ struct DaughterCombinations { int nVecs, nCombinations; bool end; std::vector nonV0daughters; - DaughterCombinations(std::vector*>& vecs, std::vector nonV0daughters_) : nVecs(0), nCombinations(1), end(false), nonV0daughters(nonV0daughters_) + DaughterCombinations(std::vector*>& vecs, std::vector nonV0daughters_) : nVecs(0), nCombinations(1), end(false), nonV0daughters(std::move(nonV0daughters_)) { for (const auto& vec : vecs) { nVecs++; @@ -593,7 +594,7 @@ struct HypKfRecoTask { // define histogram axes const AxisSpec axisMagField{10, -10., 10., "magnetic field"}; - const AxisSpec axisNev{3, 0., 3., "Number of events"}; + const AxisSpec axisNev{5, 0., 5., "Number of events"}; const AxisSpec axisRigidity{4000, -10., 10., "#it{p}^{TPC}/#it{z}"}; const AxisSpec axisdEdx{2000, 0, 2000, "d#it{E}/d#it{x}"}; const AxisSpec axisInvMass{1000, 1, 6, "inv mass"}; @@ -644,12 +645,8 @@ struct HypKfRecoTask { const float itsNsigma = getITSnSigma(track, daughterParticles.at(i)); if (daughterParticles.at(i).trkSettings[kMaxITSnSigma] >= 0 && std::abs(itsNsigma) > daughterParticles.at(i).trkSettings[kMaxITSnSigma]) continue; - float tpcNsigmaNlp = NoVal; - if (daughterParticles.at(i).name == "alpha") { - tpcNsigmaNlp = getTPCnSigma(track, daughterParticles.at(i - 1)); - } filldedx(track, i); - foundDaughterKfs.at(i).push_back(DaughterKf(i, track.globalIndex(), track.sign(), primVtx, tpcNsigma, tpcNsigmaNlp, itsNsigma)); + foundDaughterKfs.at(i).push_back(DaughterKf(i, track.globalIndex(), track.sign(), primVtx, tpcNsigma, itsNsigma)); } } // track loop } @@ -906,9 +903,9 @@ struct HypKfRecoTask { if (!trackIndices.getIndex(daughter->species, daughterTrackId, trackTableId)) { const auto& track = tracks.rawIteratorAt(daughterTrackId); outputTrackTable( - daughter->species * track.sign(), track.pt(), track.eta(), track.phi(), daughter->dcaToPvXY, daughter->dcaToPvZ, track.tpcNClsFound(), track.tpcChi2NCl(), - track.itsClusterSizes(), track.itsChi2NCl(), getRigidity(track), track.tpcSignal(), daughter->tpcNsigma, daughter->tpcNsigmaNHP, daughter->tpcNsigmaNLP, - getMass2(track), track.isPVContributor()); + daughter->species * track.sign(), track.pt(), track.eta(), track.phi(), daughter->dcaToPvXY, daughter->dcaToPvZ, track.tpcChi2NCl(), + track.itsClusterSizes(), track.itsChi2NCl(), getRigidity(track), track.tpcSignal(), track.tpcNClsFound(), track.tpcNClsPID(), + track.tpcNClsCrossedRows(), daughter->tpcNsigma, daughter->itsNsigma, track.pidForTracking(), getMass2(track), track.isPVContributor()); trackTableId = outputTrackTable.lastIndex(); trackIndices.add(daughter->species, daughterTrackId, trackTableId); } @@ -1006,7 +1003,8 @@ struct HypKfRecoTask { initCollision(collision); if (!collision.has_mcCollision() || !mcCollInfos.at(collision.mcCollisionId()).passedEvSel) continue; - + if (!collPassedEvSel) + continue; const uint64_t collIdx = collision.globalIndex(); auto tracksByColl = tracksColl.sliceBy(perCollision, collIdx); auto v0TableThisCollision = V0s.sliceBy(perCollisionV0, collIdx); @@ -1107,12 +1105,34 @@ struct HypKfRecoTask { trackIndices.clear(); collHasCandidate = false; collHasMcTrueCandidate = false; + collPassedEvSel = true; histos.fill(HIST("histMagField"), dBz); histos.fill(HIST("histNev"), 0.5); - collPassedEvSel = collision.sel8() && std::abs(collision.posZ()) < cfgVtxCutZ; - occupancy = collision.trackOccupancyInTimeRange(); + if (!collision.sel8()) { + collPassedEvSel = false; + } if (collPassedEvSel) { histos.fill(HIST("histNev"), 1.5); + } + if (std::abs(collision.posZ()) > cfgVtxCutZ) { + collPassedEvSel = false; + } + if (collPassedEvSel) { + histos.fill(HIST("histNev"), 2.5); + } + if (!collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + collPassedEvSel = false; + } + if (collPassedEvSel) { + histos.fill(HIST("histNev"), 3.5); + } + if (!collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + collPassedEvSel = false; + } + + occupancy = collision.trackOccupancyInTimeRange(); + if (collPassedEvSel) { + histos.fill(HIST("histNev"), 4.5); histos.fill(HIST("histVtxZ"), collision.posZ()); histos.fill(HIST("histCentFT0A"), collision.centFT0A()); histos.fill(HIST("histCentFT0C"), collision.centFT0C()); @@ -1311,7 +1331,7 @@ struct HypKfRecoTask { } //---------------------------------------------------------------------------------------------------------------- - int getHypDaughterVec(unsigned int cascade, LabeledArray cfg) + int getHypDaughterVec(unsigned int cascade, const LabeledArray& cfg) { std::string daughter = cfg.get(cascade, 0u); if (std::find(hyperNucNames.begin(), hyperNucNames.end(), daughter) == hyperNucNames.end()) @@ -1319,7 +1339,7 @@ struct HypKfRecoTask { return std::find(hyperNucNames.begin(), hyperNucNames.end(), daughter) - hyperNucNames.begin(); } //---------------------------------------------------------------------------------------------------------------- - std::vector getDaughterVec(unsigned int hypNuc, LabeledArray cfg) + std::vector getDaughterVec(unsigned int hypNuc, const LabeledArray& cfg) { std::vector vec; for (unsigned int i = kD1; i <= kD4; i++) { @@ -1332,7 +1352,7 @@ struct HypKfRecoTask { } //---------------------------------------------------------------------------------------------------------------- - std::vector getDaughterSignVec(unsigned int hypNuc, LabeledArray cfg) + std::vector getDaughterSignVec(unsigned int hypNuc, const LabeledArray& cfg) { std::vector vec; std::string signs = cfg.get(hypNuc, "daughterSigns"); @@ -1345,7 +1365,7 @@ struct HypKfRecoTask { return vec; } //---------------------------------------------------------------------------------------------------------------- - std::vector getV0DaughterVec(unsigned int hypNuc, LabeledArray cfg) + std::vector getV0DaughterVec(unsigned int hypNuc, const LabeledArray& cfg) { std::vector vec; std::string v0ds = cfg.get(hypNuc, "useV0for"); diff --git a/PWGLF/TableProducer/Nuspex/hypKfTreeCreator.cxx b/PWGLF/TableProducer/Nuspex/hypKfTreeCreator.cxx index 3a3a2ab3463..27d7be47253 100644 --- a/PWGLF/TableProducer/Nuspex/hypKfTreeCreator.cxx +++ b/PWGLF/TableProducer/Nuspex/hypKfTreeCreator.cxx @@ -45,11 +45,12 @@ enum Decays { kTwoBody = 2, kThreeBody = 3 }; struct TrackProperties { - TrackProperties() : x(0), y(0), z(0), px(0), py(0), pz(0), tpcNcls(0), itsNcls(0), tpcChi2(0), itsChi2(0), itsMeanClsSizeL(0), rigidity(0), tpcSignal(0), tpcNsigma(0), tpcNsigmaNhp(0), tpcNsigmaNlp(0), tofMass(0), dcaXY(0), dcaZ(0), isPvContributor(0), subMass(0) {} + TrackProperties() : x(0), y(0), z(0), px(0), py(0), pz(0), tpcNcls(0), itsNcls(0), tpcChi2(0), itsChi2(0), itsMeanClsSizeL(0), rigidity(0), tpcSignal(0), tpcNsigma(0), itsNsigma(0), tpcNclsPid(0), tpcNclsCr(0), pidForTrk(0), tofMass(0), dcaXY(0), dcaZ(0), isPvContributor(0), subMass(0) {} float x, y, z, px, py, pz; uint8_t tpcNcls, itsNcls; float tpcChi2, itsChi2, itsMeanClsSizeL; - float rigidity, tpcSignal, tpcNsigma, tpcNsigmaNhp, tpcNsigmaNlp; + float rigidity, tpcSignal, tpcNsigma, itsNsigma, tpcNclsPid, tpcNclsCr; + uint32_t pidForTrk; float tofMass, dcaXY, dcaZ; bool isPvContributor; float subMass; @@ -125,8 +126,10 @@ DECLARE_SOA_COLUMN(D1ITSmeanClsSizeL, d1ITSmeanClsSizeL, float); DECLARE_SOA_COLUMN(D1Rigidity, d1Rigidity, float); DECLARE_SOA_COLUMN(D1TPCsignal, d1TPCsignal, float); DECLARE_SOA_COLUMN(D1TPCnSigma, d1TPCnSigma, float); -DECLARE_SOA_COLUMN(D1TPCnSigmaNhp, d1TPCnSigmaNhp, float); -DECLARE_SOA_COLUMN(D1TPCnSigmaNlp, d1TPCnSigmaNlp, float); +DECLARE_SOA_COLUMN(D1TPCnClsPid, d1TPCnClsPid, uint8_t); +DECLARE_SOA_COLUMN(D1TPCnClsCr, d1TPCnClsCr, uint8_t); +DECLARE_SOA_COLUMN(D1ITSnSigma, d1ITSnSigma, float); +DECLARE_SOA_COLUMN(D1PidForTrk, d1PidForTrk, uint32_t); DECLARE_SOA_COLUMN(D1TOFmass, d1TOFmass, float); DECLARE_SOA_COLUMN(D1DcaXY, d1DcaXY, float); DECLARE_SOA_COLUMN(D1DcaZ, d1DcaZ, float); @@ -145,8 +148,10 @@ DECLARE_SOA_COLUMN(D2ITSmeanClsSizeL, d2ITSmeanClsSizeL, float); DECLARE_SOA_COLUMN(D2Rigidity, d2Rigidity, float); DECLARE_SOA_COLUMN(D2TPCsignal, d2TPCsignal, float); DECLARE_SOA_COLUMN(D2TPCnSigma, d2TPCnSigma, float); -DECLARE_SOA_COLUMN(D2TPCnSigmaNhp, d2TPCnSigmaNhp, float); -DECLARE_SOA_COLUMN(D2TPCnSigmaNlp, d2TPCnSigmaNlp, float); +DECLARE_SOA_COLUMN(D2TPCnClsPid, d2TPCnClsPid, uint8_t); +DECLARE_SOA_COLUMN(D2TPCnClsCr, d2TPCnClsCr, uint8_t); +DECLARE_SOA_COLUMN(D2ITSnSigma, d2ITSnSigma, float); +DECLARE_SOA_COLUMN(D2PidForTrk, d2PidForTrk, uint32_t); DECLARE_SOA_COLUMN(D2TOFmass, d2TOFmass, float); DECLARE_SOA_COLUMN(D2DcaXY, d2DcaXY, float); DECLARE_SOA_COLUMN(D2DcaZ, d2DcaZ, float); @@ -165,8 +170,10 @@ DECLARE_SOA_COLUMN(D3ITSmeanClsSizeL, d3ITSmeanClsSizeL, float); DECLARE_SOA_COLUMN(D3Rigidity, d3Rigidity, float); DECLARE_SOA_COLUMN(D3TPCsignal, d3TPCsignal, float); DECLARE_SOA_COLUMN(D3TPCnSigma, d3TPCnSigma, float); -DECLARE_SOA_COLUMN(D3TPCnSigmaNhp, d3TPCnSigmaNhp, float); -DECLARE_SOA_COLUMN(D3TPCnSigmaNlp, d3TPCnSigmaNlp, float); +DECLARE_SOA_COLUMN(D3TPCnClsPid, d3TPCnClsPid, uint8_t); +DECLARE_SOA_COLUMN(D3TPCnClsCr, d3TPCnClsCr, uint8_t); +DECLARE_SOA_COLUMN(D3ITSnSigma, d3ITSnSigma, float); +DECLARE_SOA_COLUMN(D3PidForTrk, d3PidForTrk, uint32_t); DECLARE_SOA_COLUMN(D3TOFmass, d3TOFmass, float); DECLARE_SOA_COLUMN(D3DcaXY, d3DcaXY, float); DECLARE_SOA_COLUMN(D3DcaZ, d3DcaZ, float); @@ -184,11 +191,11 @@ DECLARE_SOA_COLUMN(D3IsPvContributor, d3IsPvContributor, bool); #define HYPKFHYPNUCMC hypkftree::McTrue, hykfmc::IsPhysicalPrimary -#define HYPKFD1 hypkftree::D1X, hypkftree::D1Y, hypkftree::D1Z, hypkftree::D1Px, hypkftree::D1Py, hypkftree::D1Pz, hypkftree::D1TPCnCls, hypkftree::D1TPCchi2, hypkftree::D1ITSnCls, hypkftree::D1ITSchi2, hypkftree::D1ITSmeanClsSizeL, hypkftree::D1Rigidity, hypkftree::D1TPCsignal, hypkftree::D1TPCnSigma, hypkftree::D1TPCnSigmaNhp, hypkftree::D1TPCnSigmaNlp, hypkftree::D1TOFmass, hypkftree::D1DcaXY, hypkftree::D1DcaZ, hypkftree::D1IsPvContributor +#define HYPKFD1 hypkftree::D1X, hypkftree::D1Y, hypkftree::D1Z, hypkftree::D1Px, hypkftree::D1Py, hypkftree::D1Pz, hypkftree::D1TPCnCls, hypkftree::D1TPCnClsPid, hypkftree::D1TPCnClsCr, hypkftree::D1TPCchi2, hypkftree::D1ITSnCls, hypkftree::D1ITSchi2, hypkftree::D1ITSmeanClsSizeL, hypkftree::D1Rigidity, hypkftree::D1TPCsignal, hypkftree::D1TPCnSigma, hypkftree::D1ITSnSigma, hypkftree::D1PidForTrk, hypkftree::D1TOFmass, hypkftree::D1DcaXY, hypkftree::D1DcaZ, hypkftree::D1IsPvContributor -#define HYPKFD2 hypkftree::D2X, hypkftree::D2Y, hypkftree::D2Z, hypkftree::D2Px, hypkftree::D2Py, hypkftree::D2Pz, hypkftree::D2TPCnCls, hypkftree::D2TPCchi2, hypkftree::D2ITSnCls, hypkftree::D2ITSchi2, hypkftree::D2ITSmeanClsSizeL, hypkftree::D2Rigidity, hypkftree::D2TPCsignal, hypkftree::D2TPCnSigma, hypkftree::D2TPCnSigmaNhp, hypkftree::D2TPCnSigmaNlp, hypkftree::D2TOFmass, hypkftree::D2DcaXY, hypkftree::D2DcaZ, hypkftree::D2IsPvContributor +#define HYPKFD2 hypkftree::D2X, hypkftree::D2Y, hypkftree::D2Z, hypkftree::D2Px, hypkftree::D2Py, hypkftree::D2Pz, hypkftree::D2TPCnCls, hypkftree::D2TPCnClsPid, hypkftree::D2TPCnClsCr, hypkftree::D2TPCchi2, hypkftree::D2ITSnCls, hypkftree::D2ITSchi2, hypkftree::D2ITSmeanClsSizeL, hypkftree::D2Rigidity, hypkftree::D2TPCsignal, hypkftree::D2TPCnSigma, hypkftree::D2ITSnSigma, hypkftree::D2PidForTrk, hypkftree::D2TOFmass, hypkftree::D2DcaXY, hypkftree::D2DcaZ, hypkftree::D2IsPvContributor -#define HYPKFD3 hypkftree::D3X, hypkftree::D3Y, hypkftree::D3Z, hypkftree::D3Px, hypkftree::D3Py, hypkftree::D3Pz, hypkftree::D3TPCnCls, hypkftree::D3TPCchi2, hypkftree::D3ITSnCls, hypkftree::D3ITSchi2, hypkftree::D3ITSmeanClsSizeL, hypkftree::D3Rigidity, hypkftree::D3TPCsignal, hypkftree::D3TPCnSigma, hypkftree::D3TPCnSigmaNhp, hypkftree::D3TPCnSigmaNlp, hypkftree::D3TOFmass, hypkftree::D3DcaXY, hypkftree::D3DcaZ, hypkftree::D3IsPvContributor +#define HYPKFD3 hypkftree::D3X, hypkftree::D3Y, hypkftree::D3Z, hypkftree::D3Px, hypkftree::D3Py, hypkftree::D3Pz, hypkftree::D3TPCnCls, hypkftree::D3TPCnClsPid, hypkftree::D3TPCnClsCr, hypkftree::D3TPCchi2, hypkftree::D3ITSnCls, hypkftree::D3ITSchi2, hypkftree::D3ITSmeanClsSizeL, hypkftree::D3Rigidity, hypkftree::D3TPCsignal, hypkftree::D3TPCnSigma, hypkftree::D3ITSnSigma, hypkftree::D3PidForTrk, hypkftree::D3TOFmass, hypkftree::D3DcaXY, hypkftree::D3DcaZ, hypkftree::D3IsPvContributor #define HYPKFSDMASS hypkftree::D1d2Mass, hypkftree::D1d3Mass, hypkftree::D2d3Mass @@ -252,10 +259,10 @@ struct HypKfTreeCreator { outputTableTwo( cand.species, cand.isMatter, cand.cent, cand.occu, cand.runNumber, cand.passedEvSel, cand.mass, cand.y, cand.pt, cand.ct, cand.cpaPv, cand.maxDcaTracks, cand.maxDcaTracksSv, cand.dcaToPvXY, cand.dcaToPvZ, cand.devToPvXY, cand.chi2, cand.pvx, cand.pvy, cand.pvz, cand.svx, cand.svy, cand.svz, cand.px, cand.py, cand.pz, cand.collisionMcTrue, - cand.mcTrue, cand.mcPhysicalPrimary, d1.x, d1.y, d1.z, d1.px, d1.py, d1.pz, d1.tpcNcls, d1.tpcChi2, d1.itsNcls, d1.itsChi2, d1.itsMeanClsSizeL, - d1.rigidity, d1.tpcSignal, d1.tpcNsigma, d1.tpcNsigmaNhp, d1.tpcNsigmaNlp, d1.tofMass, d1.dcaXY, d1.dcaZ, d1.isPvContributor, - d2.x, d2.y, d2.z, d2.px, d2.py, d2.pz, d2.tpcNcls, d2.tpcChi2, d2.itsNcls, d2.itsChi2, d2.itsMeanClsSizeL, - d2.rigidity, d2.tpcSignal, d2.tpcNsigma, d2.tpcNsigmaNhp, d2.tpcNsigmaNlp, d2.tofMass, d2.dcaXY, d2.dcaZ, d2.isPvContributor); + cand.mcTrue, cand.mcPhysicalPrimary, d1.x, d1.y, d1.z, d1.px, d1.py, d1.pz, d1.tpcNcls, d1.tpcNclsPid, d1.tpcNclsCr, d1.tpcChi2, d1.itsNcls, d1.itsChi2, d1.itsMeanClsSizeL, + d1.rigidity, d1.tpcSignal, d1.tpcNsigma, d1.itsNsigma, d1.pidForTrk, d1.tofMass, d1.dcaXY, d1.dcaZ, d1.isPvContributor, + d2.x, d2.y, d2.z, d2.px, d2.py, d2.pz, d2.tpcNcls, d2.tpcNclsPid, d2.tpcNclsCr, d2.tpcChi2, d2.itsNcls, d2.itsChi2, d2.itsMeanClsSizeL, + d2.rigidity, d2.tpcSignal, d2.tpcNsigma, d2.itsNsigma, d2.pidForTrk, d2.tofMass, d2.dcaXY, d2.dcaZ, d2.isPvContributor); if (isMC && cfgMCCombined) outputTableMcTwo( cand.speciesMC, cand.pdgCode, cand.isMatterMC, cand.isReconstructed, cand.isPhysicalPrimary, cand.passedEvSelMC, cand.yGen, cand.ptGen, cand.ctGen, @@ -263,10 +270,10 @@ struct HypKfTreeCreator { cand.species, cand.isMatter, cand.cent, cand.occu, cand.runNumber, cand.passedEvSel, cand.mass, cand.y, cand.pt, cand.ct, cand.cpaPv, cand.maxDcaTracks, cand.maxDcaTracksSv, cand.dcaToPvXY, cand.dcaToPvZ, cand.devToPvXY, cand.chi2, cand.pvx, cand.pvy, cand.pvz, cand.svx, cand.svy, cand.svz, cand.px, cand.py, cand.pz, cand.collisionMcTrue, - d1.x, d1.y, d1.z, d1.px, d1.py, d1.pz, d1.tpcNcls, d1.tpcChi2, d1.itsNcls, d1.itsChi2, d1.itsMeanClsSizeL, - d1.rigidity, d1.tpcSignal, d1.tpcNsigma, d1.tpcNsigmaNhp, d1.tpcNsigmaNlp, d1.tofMass, d1.dcaXY, d1.dcaZ, d1.isPvContributor, - d2.x, d2.y, d2.z, d2.px, d2.py, d2.pz, d2.tpcNcls, d2.tpcChi2, d2.itsNcls, d2.itsChi2, d2.itsMeanClsSizeL, - d2.rigidity, d2.tpcSignal, d2.tpcNsigma, d2.tpcNsigmaNhp, d2.tpcNsigmaNlp, d2.tofMass, d2.dcaXY, d2.dcaZ, d2.isPvContributor); + d1.x, d1.y, d1.z, d1.px, d1.py, d1.pz, d1.tpcNcls, d1.tpcNclsPid, d1.tpcNclsCr, d1.tpcChi2, d1.itsNcls, d1.itsChi2, d1.itsMeanClsSizeL, + d1.rigidity, d1.tpcSignal, d1.tpcNsigma, d1.itsNsigma, d1.pidForTrk, d1.tofMass, d1.dcaXY, d1.dcaZ, d1.isPvContributor, + d2.x, d2.y, d2.z, d2.px, d2.py, d2.pz, d2.tpcNcls, d2.tpcNclsPid, d2.tpcNclsCr, d2.tpcChi2, d2.itsNcls, d2.itsChi2, d2.itsMeanClsSizeL, + d2.rigidity, d2.tpcSignal, d2.tpcNsigma, d2.itsNsigma, d2.pidForTrk, d2.tofMass, d2.dcaXY, d2.dcaZ, d2.isPvContributor); } if (cfgNprimDaughters == Decays::kThreeBody) { const auto& d1 = cand.daughterTracks.at(0); @@ -277,12 +284,12 @@ struct HypKfTreeCreator { cand.species, cand.isMatter, cand.cent, cand.occu, cand.runNumber, cand.passedEvSel, cand.mass, cand.y, cand.pt, cand.ct, cand.cpaPv, cand.maxDcaTracks, cand.maxDcaTracksSv, cand.dcaToPvXY, cand.dcaToPvZ, cand.devToPvXY, cand.chi2, cand.pvx, cand.pvy, cand.pvz, cand.svx, cand.svy, cand.svz, cand.px, cand.py, cand.pz, cand.collisionMcTrue, cand.mcTrue, cand.mcPhysicalPrimary, - d1.x, d1.y, d1.z, d1.px, d1.py, d1.pz, d1.tpcNcls, d1.tpcChi2, d1.itsNcls, d1.itsChi2, d1.itsMeanClsSizeL, - d1.rigidity, d1.tpcSignal, d1.tpcNsigma, d1.tpcNsigmaNhp, d1.tpcNsigmaNlp, d1.tofMass, d1.dcaXY, d1.dcaZ, d1.isPvContributor, - d2.x, d2.y, d2.z, d2.px, d2.py, d2.pz, d2.tpcNcls, d2.tpcChi2, d2.itsNcls, d2.itsChi2, d2.itsMeanClsSizeL, - d2.rigidity, d2.tpcSignal, d2.tpcNsigma, d2.tpcNsigmaNhp, d2.tpcNsigmaNlp, d2.tofMass, d2.dcaXY, d2.dcaZ, d2.isPvContributor, - d3.x, d3.y, d3.z, d3.px, d3.py, d3.pz, d3.tpcNcls, d3.tpcChi2, d3.itsNcls, d3.itsChi2, d3.itsMeanClsSizeL, - d3.rigidity, d3.tpcSignal, d3.tpcNsigma, d3.tpcNsigmaNhp, d3.tpcNsigmaNlp, d3.tofMass, d3.dcaXY, d3.dcaZ, d3.isPvContributor, + d1.x, d1.y, d1.z, d1.px, d1.py, d1.pz, d1.tpcNcls, d1.tpcNclsPid, d1.tpcNclsCr, d1.tpcChi2, d1.itsNcls, d1.itsChi2, d1.itsMeanClsSizeL, + d1.rigidity, d1.tpcSignal, d1.tpcNsigma, d1.itsNsigma, d1.pidForTrk, d1.tofMass, d1.dcaXY, d1.dcaZ, d1.isPvContributor, + d2.x, d2.y, d2.z, d2.px, d2.py, d2.pz, d2.tpcNcls, d2.tpcNclsPid, d2.tpcNclsCr, d2.tpcChi2, d2.itsNcls, d2.itsChi2, d2.itsMeanClsSizeL, + d2.rigidity, d2.tpcSignal, d2.tpcNsigma, d2.itsNsigma, d2.pidForTrk, d2.tofMass, d2.dcaXY, d2.dcaZ, d2.isPvContributor, + d3.x, d3.y, d3.z, d3.px, d3.py, d3.pz, d3.tpcNcls, d3.tpcNclsPid, d3.tpcNclsCr, d3.tpcChi2, d3.itsNcls, d3.itsChi2, d3.itsMeanClsSizeL, + d3.rigidity, d3.tpcSignal, d3.tpcNsigma, d3.itsNsigma, d3.pidForTrk, d3.tofMass, d3.dcaXY, d3.dcaZ, d3.isPvContributor, d1.subMass, d2.subMass, d3.subMass); if (isMC && cfgMCCombined) outputTableMcThree( @@ -291,12 +298,12 @@ struct HypKfTreeCreator { cand.species, cand.isMatter, cand.cent, cand.occu, cand.runNumber, cand.passedEvSel, cand.mass, cand.y, cand.pt, cand.ct, cand.cpaPv, cand.maxDcaTracks, cand.maxDcaTracksSv, cand.dcaToPvXY, cand.dcaToPvZ, cand.devToPvXY, cand.chi2, cand.pvx, cand.pvy, cand.pvz, cand.svx, cand.svy, cand.svz, cand.px, cand.py, cand.pz, cand.collisionMcTrue, - d1.x, d1.y, d1.z, d1.px, d1.py, d1.pz, d1.tpcNcls, d1.tpcChi2, d1.itsNcls, d1.itsChi2, d1.itsMeanClsSizeL, - d1.rigidity, d1.tpcSignal, d1.tpcNsigma, d1.tpcNsigmaNhp, d1.tpcNsigmaNlp, d1.tofMass, d1.dcaXY, d1.dcaZ, d1.isPvContributor, - d2.x, d2.y, d2.z, d2.px, d2.py, d2.pz, d2.tpcNcls, d2.tpcChi2, d2.itsNcls, d2.itsChi2, d2.itsMeanClsSizeL, - d2.rigidity, d2.tpcSignal, d2.tpcNsigma, d2.tpcNsigmaNhp, d2.tpcNsigmaNlp, d2.tofMass, d2.dcaXY, d2.dcaZ, d2.isPvContributor, - d3.x, d3.y, d3.z, d3.px, d3.py, d3.pz, d3.tpcNcls, d3.tpcChi2, d3.itsNcls, d3.itsChi2, d3.itsMeanClsSizeL, - d3.rigidity, d3.tpcSignal, d3.tpcNsigma, d3.tpcNsigmaNhp, d3.tpcNsigmaNlp, d3.tofMass, d3.dcaXY, d3.dcaZ, d3.isPvContributor, + d1.x, d1.y, d1.z, d1.px, d1.py, d1.pz, d1.tpcNcls, d1.tpcNclsPid, d1.tpcNclsCr, d1.tpcChi2, d1.itsNcls, d1.itsChi2, d1.itsMeanClsSizeL, + d1.rigidity, d1.tpcSignal, d1.tpcNsigma, d1.itsNsigma, d1.pidForTrk, d1.tofMass, d1.dcaXY, d1.dcaZ, d1.isPvContributor, + d2.x, d2.y, d2.z, d2.px, d2.py, d2.pz, d2.tpcNcls, d2.tpcNclsPid, d2.tpcNclsCr, d2.tpcChi2, d2.itsNcls, d2.itsChi2, d2.itsMeanClsSizeL, + d2.rigidity, d2.tpcSignal, d2.tpcNsigma, d2.itsNsigma, d2.pidForTrk, d2.tofMass, d2.dcaXY, d2.dcaZ, d2.isPvContributor, + d3.x, d3.y, d3.z, d3.px, d3.py, d3.pz, d3.tpcNcls, d3.tpcNclsPid, d3.tpcNclsCr, d3.tpcChi2, d3.itsNcls, d3.itsChi2, d3.itsMeanClsSizeL, + d3.rigidity, d3.tpcSignal, d3.tpcNsigma, d3.itsNsigma, d3.pidForTrk, d3.tofMass, d3.dcaXY, d3.dcaZ, d3.isPvContributor, d1.subMass, d2.subMass, d3.subMass); } } @@ -349,8 +356,10 @@ struct HypKfTreeCreator { daughter.rigidity = track.rigidity(); daughter.tpcSignal = track.tpcSignal(); daughter.tpcNsigma = track.tpcNsigma(); - daughter.tpcNsigmaNhp = track.tpcNsigmaNhp(); - daughter.tpcNsigmaNlp = track.tpcNsigmaNlp(); + daughter.itsNsigma = track.itsNsigma(); + daughter.pidForTrk = track.pidForTrk(); + daughter.tpcNclsPid = track.tpcNclsPid(); + daughter.tpcNclsCr = track.tpcNclsCr(); daughter.tofMass = track.tofMass(); daughter.dcaXY = track.dcaXY(); daughter.dcaZ = track.dcaZ(); @@ -438,7 +447,7 @@ struct HypKfTreeCreator { PROCESS_SWITCH(HypKfTreeCreator, processMC, "MC tree", false); //___________________________________________________________________________________________________________________________________________________________ - std::vector dcaTracksAll(std::vector& posVec, TString opt = "") + std::vector dcaTracksAll(std::vector& posVec, const TString& opt = "") { std::vector vec; int n = posVec.size(); @@ -450,7 +459,7 @@ struct HypKfTreeCreator { return vec; } template - std::vector dcaTrackSvAll(std::vector& posVec, T const& hypNuc, TString opt = "") + std::vector dcaTrackSvAll(std::vector& posVec, T const& hypNuc, const TString& opt = "") { std::vector vec; for (size_t i = 0; i < posVec.size(); i++) { @@ -463,14 +472,14 @@ struct HypKfTreeCreator { { return *max_element(vec.begin(), vec.end()); } - float meanValue(std::vector vec) + float meanValue(const std::vector& vec) { float sum = 0; for (const auto& value : vec) sum += value; return sum / vec.size(); } - float mean2Value(std::vector vec) + float mean2Value(const std::vector& vec) { float sum = 0; for (const auto& value : vec) @@ -478,7 +487,7 @@ struct HypKfTreeCreator { return std::sqrt(sum / vec.size()); } - float dcaTracks(std::vector v, int track1, int track2, TString opt = "XY") + float dcaTracks(std::vector v, int track1, int track2, const TString& opt = "XY") { if (opt == "XY") return RecoDecay::distanceXY(v.at(track1), v.at(track2)); @@ -488,7 +497,7 @@ struct HypKfTreeCreator { return RecoDecay::distance(v.at(track1), v.at(track2)); } template - float dcaTrackSv(std::vector& v, int track, T const& hypNuc, TString opt = "") + float dcaTrackSv(std::vector& v, int track, T const& hypNuc, const TString& opt = "") { if (opt == "XY") return RecoDecay::distanceXY(v.at(track), decayVtx(hypNuc)); diff --git a/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx b/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx index b5dc7ca67f2..8b9a782ea3c 100644 --- a/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx +++ b/PWGLF/TableProducer/Nuspex/hyperRecoTask.cxx @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -79,50 +80,11 @@ using EventCandidatesMC = soa::Join betheBlochParNames{"p0", "p1", "p2", "p3", "p4", "resolution"}; static const std::vector particleName{"He3"}; -std::shared_ptr hEvents; -std::shared_ptr hEventsZorro; -std::shared_ptr hZvtx; -std::shared_ptr hCentFT0A; -std::shared_ptr hCentFT0C; -std::shared_ptr hCentFT0M; -std::shared_ptr hNsigma3HeSel; -std::shared_ptr hDeDx3HeSel; -std::shared_ptr hDeDxTot; -std::shared_ptr hH3LMassBefSel; -std::shared_ptr hH3LMassTracked; -std::shared_ptr hH4LMassBefSel; -std::shared_ptr hH4LMassTracked; -std::shared_ptr hDecayChannel; -std::shared_ptr hIsMatterGen; -std::shared_ptr hIsMatterGenTwoBody; -std::shared_ptr hEvtMC; -std::shared_ptr hImpactParamGen; -std::shared_ptr hImpactParamGenOneReco; -std::shared_ptr hImpactParamReco; -std::shared_ptr hGen3HLBeforeEvtSel; -std::shared_ptr hGen3HLAfterSel; -std::shared_ptr hGenOneRecoCentrality; -std::shared_ptr hRecoCentrality; -std::shared_ptr hGenEventsNchEta05; -std::shared_ptr hGenEventsNchEta08; -std::shared_ptr hGenCentralityColvsMultiplicityGenEta05; -std::shared_ptr hGenCentralityColvsMultiplicityGenEta08; -std::shared_ptr hGenCentralityColvsImpactParamGen; -std::shared_ptr hGenCentralityColvsFT0Cmultiplicity; -std::shared_ptr hRecoCentralityColvsMultiplicityRecoEta05; -std::shared_ptr hRecoCentralityColvsMultiplicityRecoEta08; -std::shared_ptr hRecoCentralityColvsImpactParamReco; -std::shared_ptr hRecoCentralityColvsFT0Cmultiplicity; -std::shared_ptr hGen3HLvsImpactParameterBeforeEvtSel; -std::shared_ptr hGen3HLvsImpactParameterAfterSel; -std::shared_ptr hGen3HLvsMultiplicityGenEta05BeforeEvtSel; -std::shared_ptr hGen3HLvsMultiplicityGenEta05AfterSel; -std::shared_ptr hGen3HLvsMultiplicityGenEta08BeforeEvtSel; -std::shared_ptr hGen3HLvsMultiplicityGenEta08AfterSel; -std::shared_ptr hGen3HLvsMultiplicityFT0CBeforeEvtSel; -std::shared_ptr hGen3HLvsMultiplicityFT0CAfterSel; } // namespace @@ -139,8 +101,8 @@ struct hyperCandidate { float genEta() const { return std::asinh(gMom[2] / genPt()); } int v0ID = -1; - int heTrackID; - int piTrackID; + int heTrackID = -1; + int piTrackID = -1; float dcaV0dau = -10; float cosPA = -10; float nSigmaHe3 = -10; @@ -148,12 +110,12 @@ struct hyperCandidate { float piDCAXY = -10; float momHe3TPC = -10.f; float momPiTPC = -10.f; - std::array momHe3; - std::array momPi; - std::array decVtx; - std::array gMom; - std::array gMomHe3; - std::array gDecVtx; + std::array momHe3{}; + std::array momPi{}; + std::array decVtx{}; + std::array gMom{}; + std::array gMomHe3{}; + std::array gDecVtx{}; uint16_t tpcSignalHe3 = 0u; uint16_t tpcSignalPi = 0u; float tpcChi2He3 = 0.f; @@ -183,7 +145,7 @@ struct hyperCandidate { uint8_t flags = 0u; // flags for dughter particles }; -struct hyperRecoTask { +struct HyperRecoTask { Produces outputDataTable; Produces outputDataTableWithFlow; @@ -194,19 +156,19 @@ struct hyperRecoTask { OutputObj zorroSummary{"zorroSummary"}; // PDG codes - Configurable hyperPdg{"hyperPDG", 1010010030, "PDG code of the hyper-mother (could be 3LamH or 4LamH)"}; - Configurable heDauPdg{"heDauPDG", 1000020030, "PDG code of the helium (could be 3He or 4He)"}; + Configurable hyperPdg{"hyperPdg", 1010010030, "PDG code of the hyper-mother (could be 3LamH or 4LamH)"}; + Configurable heDauPdg{"heDauPdg", 1000020030, "PDG code of the helium (could be 3He or 4He)"}; Configurable piDauPdg{"piDauPdg", 211, "PDG code of pion"}; // Selection criteria - Configurable v0cospacut{"hypcospa", 0.95, "V0 CosPA"}; - Configurable masswidth{"hypmasswidth", 0.06, "Mass width (GeV/c^2)"}; - Configurable dcaToPvPion{"dcapvPi", 0., "DCA to PV pion"}; - Configurable dcaToPvHe{"dcapvHe", 0., "DCA to PV helium"}; - Configurable dcav0dau{"hypdcaDau", 1.0, "DCA V0 Daughters"}; + Configurable v0CosPaCut{"v0CosPaCut", 0.95, "V0 CosPA"}; + Configurable massWidth{"massWidth", 0.06, "Mass width (GeV/c^2)"}; + Configurable dcaToPvPion{"dcaToPvPion", 0., "DCA to PV pion"}; + Configurable dcaToPvHe{"dcaToPvHe", 0., "DCA to PV helium"}; + Configurable dcaV0Dau{"dcaV0Dau", 1.0, "DCA V0 Daughters"}; Configurable ptMin{"ptMin", 0.5, "Minimum pT of the hypercandidate"}; - Configurable TPCRigidityMinHe{"TPCRigidityMinHe", 0.2, "Minimum rigidity of the helium candidate"}; - Configurable etaMax{"eta", 1., "eta daughter"}; + Configurable tpcRigidityMinHe{"tpcRigidityMinHe", 0.2, "Minimum rigidity of the helium candidate"}; + Configurable etaMax{"etaMax", 1., "eta daughter"}; Configurable nSigmaMaxHe{"nSigmaMaxHe", 5, "helium dEdx cut (n sigma)"}; Configurable nTPCClusMinHe{"nTPCClusMinHe", 70, "helium NTPC clusters cut"}; Configurable nTPCClusMinPi{"nTPCClusMinPi", -1., "pion NTPC clusters cut"}; @@ -237,8 +199,8 @@ struct hyperRecoTask { Configurable cfgEvSelkIsGoodZvtxFT0vsPV{"cfgEvSelkIsGoodZvtxFT0vsPV", false, "Verifies the consistency between the primary vertex z position from tracking and the z position of the PV from FT0 timing"}; // CCDB options - Configurable d_bz_input{"d_bz", -999, "bz field, -999 is automatic"}; - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable dBzInput{"dBzInput", -999, "bz field, -999 is automatic"}; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable grpPath{"grpPath", "GLO/GRP/GRP", "Path of the grp file"}; Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; @@ -273,9 +235,9 @@ struct hyperRecoTask { HistogramRegistry qaRegistry{"QA", {}, OutputObjHandlingPolicy::AnalysisObject}; - int mRunNumber; - float d_bz; - std::array mBBparamsHe; + int mRunNumber = -1; + float d_bz = 0.f; + std::array mBBparamsHe{}; void init(InitContext const&) { @@ -284,7 +246,7 @@ struct hyperRecoTask { mRunNumber = 0; d_bz = 0; - ccdb->setURL(ccdburl); + ccdb->setURL(ccdbUrl); ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); @@ -316,80 +278,80 @@ struct hyperRecoTask { const AxisSpec ptAxis{binsPt, "#it{p}_{T} (GeV/#it{c})"}; const AxisSpec multAxis = {binsMult, "Multiplicity #eta <0.5"}; - hNsigma3HeSel = qaRegistry.add("hNsigma3HeSel", "; p_{TPC}/z (GeV/#it{c}); n_{#sigma} ({}^{3}He)", HistType::kTH2F, {rigidityAxis, nSigma3HeAxis}); - hDeDx3HeSel = qaRegistry.add("hDeDx3HeSel", ";p_{TPC}/z (GeV/#it{c}); dE/dx", HistType::kTH2F, {rigidityAxis, dedxAxis}); - hDeDxTot = qaRegistry.add("hDeDxTot", ";p_{TPC}/z (GeV/#it{c}); dE/dx", HistType::kTH2F, {rigidityAxis, dedxAxis}); - hH3LMassBefSel = qaRegistry.add("hH3LMassBefSel", ";M (GeV/#it{c}^{2}); ", HistType::kTH1D, {{60, 2.96, 3.04}}); - hH3LMassTracked = qaRegistry.add("hH3LMassTracked", ";M (GeV/#it{c}^{2}); ", HistType::kTH1D, {{60, 2.96, 3.04}}); - hH4LMassBefSel = qaRegistry.add("hH4LMassBefSel", ";M (GeV/#it{c}^{2}); ", HistType::kTH1D, {{60, 3.76, 3.84}}); - hH4LMassTracked = qaRegistry.add("hH4LMassTracked", ";M (GeV/#it{c}^{2}); ", HistType::kTH1D, {{60, 3.76, 3.84}}); + qaRegistry.add("hNsigma3HeSel", "; p_{TPC}/z (GeV/#it{c}); n_{#sigma} ({}^{3}He)", HistType::kTH2F, {rigidityAxis, nSigma3HeAxis}); + qaRegistry.add("hDeDx3HeSel", ";p_{TPC}/z (GeV/#it{c}); dE/dx", HistType::kTH2F, {rigidityAxis, dedxAxis}); + qaRegistry.add("hDeDxTot", ";p_{TPC}/z (GeV/#it{c}); dE/dx", HistType::kTH2F, {rigidityAxis, dedxAxis}); + qaRegistry.add("hH3LMassBefSel", ";M (GeV/#it{c}^{2}); ", HistType::kTH1D, {{60, 2.96, 3.04}}); + qaRegistry.add("hH3LMassTracked", ";M (GeV/#it{c}^{2}); ", HistType::kTH1D, {{60, 2.96, 3.04}}); + qaRegistry.add("hH4LMassBefSel", ";M (GeV/#it{c}^{2}); ", HistType::kTH1D, {{60, 3.76, 3.84}}); + qaRegistry.add("hH4LMassTracked", ";M (GeV/#it{c}^{2}); ", HistType::kTH1D, {{60, 3.76, 3.84}}); - hEvents = qaRegistry.add("hEvents", ";Events; ", HistType::kTH1D, {{5, -0.5, 4.5}}); + const auto hEvents = qaRegistry.add("hEvents", ";Events; ", HistType::kTH1D, {{5, -0.5, 4.5}}); hEvents->GetXaxis()->SetBinLabel(1, "All"); hEvents->GetXaxis()->SetBinLabel(2, "sel8"); hEvents->GetXaxis()->SetBinLabel(3, "z_{vtx}"); hEvents->GetXaxis()->SetBinLabel(4, "kNoSameBunchPileup"); hEvents->GetXaxis()->SetBinLabel(5, "kIsGoodZvtxFT0vsPV"); - hEventsZorro = qaRegistry.add("hEventsZorro", ";Events; ", HistType::kTH1D, {{2, -0.5, 1.5}}); + const auto hEventsZorro = qaRegistry.add("hEventsZorro", ";Events; ", HistType::kTH1D, {{2, -0.5, 1.5}}); hEventsZorro->GetXaxis()->SetBinLabel(1, "Zorro before evsel"); hEventsZorro->GetXaxis()->SetBinLabel(2, "Zorro after evsel"); if (doprocessMC || doprocessMCTracked) { - hDecayChannel = qaRegistry.add("hDecayChannel", ";Decay channel; ", HistType::kTH1D, {{2, -0.5, 1.5}}); + const auto hDecayChannel = qaRegistry.add("hDecayChannel", ";Decay channel; ", HistType::kTH1D, {{2, -0.5, 1.5}}); hDecayChannel->GetXaxis()->SetBinLabel(1, "2-body"); hDecayChannel->GetXaxis()->SetBinLabel(2, "3-body"); - hIsMatterGen = qaRegistry.add("hIsMatterGen", ";; ", HistType::kTH1D, {{2, -0.5, 1.5}}); + const auto hIsMatterGen = qaRegistry.add("hIsMatterGen", ";; ", HistType::kTH1D, {{2, -0.5, 1.5}}); hIsMatterGen->GetXaxis()->SetBinLabel(1, "Matter"); hIsMatterGen->GetXaxis()->SetBinLabel(2, "Antimatter"); - hIsMatterGenTwoBody = qaRegistry.add("hIsMatterGenTwoBody", ";; ", HistType::kTH1D, {{2, -0.5, 1.5}}); + const auto hIsMatterGenTwoBody = qaRegistry.add("hIsMatterGenTwoBody", ";; ", HistType::kTH1D, {{2, -0.5, 1.5}}); hIsMatterGenTwoBody->GetXaxis()->SetBinLabel(1, "Matter"); hIsMatterGenTwoBody->GetXaxis()->SetBinLabel(2, "Antimatter"); } - hZvtx = qaRegistry.add("hZvtx", ";z_{vtx} (cm); ", HistType::kTH1D, {{100, -20, 20}}); - hCentFT0A = qaRegistry.add("hCentFT0A", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); - hCentFT0C = qaRegistry.add("hCentFT0C", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); - hCentFT0M = qaRegistry.add("hCentFT0M", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); + qaRegistry.add("hZvtx", ";z_{vtx} (cm); ", HistType::kTH1D, {{100, -20, 20}}); + qaRegistry.add("hCentFT0A", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); + qaRegistry.add("hCentFT0C", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); + qaRegistry.add("hCentFT0M", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); if (doprocessEventLossMC) { // Infomation for all generated collisions - hEvtMC = qaRegistry.add("QAEvent/hEvtMC", ";; ", HistType::kTH1D, {{3, -0.5, 2.5}}); + const auto hEvtMC = qaRegistry.add("QAEvent/hEvtMC", ";; ", HistType::kTH1D, {{3, -0.5, 2.5}}); hEvtMC->GetXaxis()->SetBinLabel(1, "All gen evts"); hEvtMC->GetXaxis()->SetBinLabel(2, "Gen evts with al least one reconstructed"); hEvtMC->GetXaxis()->SetBinLabel(3, "Gen evts with no reconstructed collisions"); - hGenEventsNchEta05 = qaRegistry.add("QAEvent/hGenEventsNchEta05", ";;", HistType::kTH2D, {{multAxis}, {2, -0.5f, +1.5f}}); + const auto hGenEventsNchEta05 = qaRegistry.add("QAEvent/hGenEventsNchEta05", ";;", HistType::kTH2D, {{multAxis}, {2, -0.5f, +1.5f}}); hGenEventsNchEta05->GetYaxis()->SetBinLabel(1, "All gen. events"); hGenEventsNchEta05->GetYaxis()->SetBinLabel(2, "Gen evts with at least 1 rec. collisions"); - hGenEventsNchEta08 = qaRegistry.add("QAEvent/hGenEventsNchEta08", ";;", HistType::kTH2D, {{multAxis}, {2, -0.5f, +1.5f}}); + const auto hGenEventsNchEta08 = qaRegistry.add("QAEvent/hGenEventsNchEta08", ";;", HistType::kTH2D, {{multAxis}, {2, -0.5f, +1.5f}}); hGenEventsNchEta08->GetYaxis()->SetBinLabel(1, "All gen. events"); hGenEventsNchEta08->GetYaxis()->SetBinLabel(2, "Gen evts with at least 1 rec. collisions"); - hImpactParamGen = qaRegistry.add("QAEvent/McColAll/hImpactParamGen", "Impact parameter of generated MC events; Impact Parameter (b); Counts", HistType::kTH1D, {impactParamAxis}); + qaRegistry.add("QAEvent/McColAll/hImpactParamGen", "Impact parameter of generated MC events; Impact Parameter (b); Counts", HistType::kTH1D, {impactParamAxis}); // Infomation for generated collisions which at least one rec. collision and passed the event selection - hImpactParamGenOneReco = qaRegistry.add("QAEvent/McColPassedEvSel/hImpactParamGenOneReco", "Impact parameter of generated MC events with at least one rec. evt and passed the event selection; Impact Parameter (b); Counts", HistType::kTH1D, {impactParamAxis}); - hGenOneRecoCentrality = qaRegistry.add("QAEvent/McColPassedEvSel/hGenOneRecoCentrality", "Centrality distribution of generated MC events with at least one rec. evt and passed the event selection; Centrality (FT0C %); Counts", HistType::kTH1D, {centFT0CAxis}); - hGenCentralityColvsMultiplicityGenEta05 = qaRegistry.add("QAEvent/McColPassedEvSel/hGenCentralityColvsMultiplicityGenEta05", "Correlation between FT0C centrality and charged particle multiplicity in generated MC events with at least one rec. evt and passed the event selection; Multiplicity #eta <0.5; Counts", HistType::kTH2D, {centFT0CAxis, multAxis}); - hGenCentralityColvsMultiplicityGenEta08 = qaRegistry.add("QAEvent/McColPassedEvSel/hGenCentralityColvsMultiplicityGenEta08", "Correlation between FT0C centrality and charged particle multiplicity in generated MC events with at least one rec. evt and passed the event selection; Multiplicity #eta <0.8; Counts", HistType::kTH2D, {centFT0CAxis, multAxis}); - hGenCentralityColvsImpactParamGen = qaRegistry.add("QAEvent/McColPassedEvSel/hGenCentralityColvsImpactParamGen", "Correlation between FT0C centrality and impact parameter in generated MC events with at least one rec. evt and passed the event selection; Multiplicity #eta <0.8; Counts", HistType::kTH2D, {centFT0CAxis, impactParamAxis}); - hGenCentralityColvsFT0Cmultiplicity = qaRegistry.add("QAEvent/McColPassedEvSel/hGenCentralityColvsFT0Cmultiplicity", "Correlation between FT0C centrality and FT0C multiplicity in generated MC events with at least one rec. evt and passed the event selection; FT0c multiplicity", HistType::kTH2D, {centFT0CAxis, binsFT0CMultAxis}); + qaRegistry.add("QAEvent/McColPassedEvSel/hImpactParamGenOneReco", "Impact parameter of generated MC events with at least one rec. evt and passed the event selection; Impact Parameter (b); Counts", HistType::kTH1D, {impactParamAxis}); + qaRegistry.add("QAEvent/McColPassedEvSel/hGenOneRecoCentrality", "Centrality distribution of generated MC events with at least one rec. evt and passed the event selection; Centrality (FT0C %); Counts", HistType::kTH1D, {centFT0CAxis}); + qaRegistry.add("QAEvent/McColPassedEvSel/hGenCentralityColvsMultiplicityGenEta05", "Correlation between FT0C centrality and charged particle multiplicity in generated MC events with at least one rec. evt and passed the event selection; Multiplicity #eta <0.5; Counts", HistType::kTH2D, {centFT0CAxis, multAxis}); + qaRegistry.add("QAEvent/McColPassedEvSel/hGenCentralityColvsMultiplicityGenEta08", "Correlation between FT0C centrality and charged particle multiplicity in generated MC events with at least one rec. evt and passed the event selection; Multiplicity #eta <0.8; Counts", HistType::kTH2D, {centFT0CAxis, multAxis}); + qaRegistry.add("QAEvent/McColPassedEvSel/hGenCentralityColvsImpactParamGen", "Correlation between FT0C centrality and impact parameter in generated MC events with at least one rec. evt and passed the event selection; Multiplicity #eta <0.8; Counts", HistType::kTH2D, {centFT0CAxis, impactParamAxis}); + qaRegistry.add("QAEvent/McColPassedEvSel/hGenCentralityColvsFT0Cmultiplicity", "Correlation between FT0C centrality and FT0C multiplicity in generated MC events with at least one rec. evt and passed the event selection; FT0c multiplicity", HistType::kTH2D, {centFT0CAxis, binsFT0CMultAxis}); // Infomation for all reconstructed collisions passed the event selection (for Event Splitting) - hImpactParamReco = qaRegistry.add("QAEvent/McColAll/hImpactParamReco", "Impact parameter of generated MC events with at least one rec. evt; Impact Parameter (b); Counts", HistType::kTH1D, {impactParamAxis}); - hRecoCentrality = qaRegistry.add("QAEvent/McColAll/hRecoCentrality", "Centrality distribution of reconstructed MC events passed the event selection; Centrality (FT0C %); Counts", HistType::kTH1D, {centFT0CAxis}); - hRecoCentralityColvsMultiplicityRecoEta05 = qaRegistry.add("QAEvent/McColAll/hRecoCentralityColvsMultiplicityRecoEta05", "Correlation between FT0C centrality and charged particle multiplicity in reconstructed MC events passed the event selection; Multiplicity #eta <0.5; Counts", HistType::kTH2D, {centFT0CAxis, multAxis}); - hRecoCentralityColvsMultiplicityRecoEta08 = qaRegistry.add("QAEvent/McColAll/hRecoCentralityColvsMultiplicityRecoEta08", "Correlation between FT0C centrality and charged particle multiplicity in reconstructed MC events passed the event selection; Multiplicity #eta <0.8; Counts", HistType::kTH2D, {centFT0CAxis, multAxis}); - hRecoCentralityColvsImpactParamReco = qaRegistry.add("QAEvent/McColAll/hRecoCentralityColvsImpactParamReco", "Correlation between FT0C centrality and impact parameter in reconstructed MC events passed the event selection; Impact Parameter (b); Counts", HistType::kTH2D, {centFT0CAxis, impactParamAxis}); - hRecoCentralityColvsFT0Cmultiplicity = qaRegistry.add("QAEvent/McColAll/hRecoCentralityColvsFT0Cmultiplicity", "Correlation between FT0C centrality and FT0C multiplicity in reconstructed MC events passed the event selection; FT0C (%); FT0c multiplicity", HistType::kTH2D, {centFT0CAxis, binsFT0CMultAxis}); + qaRegistry.add("QAEvent/McColAll/hImpactParamReco", "Impact parameter of generated MC events with at least one rec. evt; Impact Parameter (b); Counts", HistType::kTH1D, {impactParamAxis}); + qaRegistry.add("QAEvent/McColAll/hRecoCentrality", "Centrality distribution of reconstructed MC events passed the event selection; Centrality (FT0C %); Counts", HistType::kTH1D, {centFT0CAxis}); + qaRegistry.add("QAEvent/McColAll/hRecoCentralityColvsMultiplicityRecoEta05", "Correlation between FT0C centrality and charged particle multiplicity in reconstructed MC events passed the event selection; Multiplicity #eta <0.5; Counts", HistType::kTH2D, {centFT0CAxis, multAxis}); + qaRegistry.add("QAEvent/McColAll/hRecoCentralityColvsMultiplicityRecoEta08", "Correlation between FT0C centrality and charged particle multiplicity in reconstructed MC events passed the event selection; Multiplicity #eta <0.8; Counts", HistType::kTH2D, {centFT0CAxis, multAxis}); + qaRegistry.add("QAEvent/McColAll/hRecoCentralityColvsImpactParamReco", "Correlation between FT0C centrality and impact parameter in reconstructed MC events passed the event selection; Impact Parameter (b); Counts", HistType::kTH2D, {centFT0CAxis, impactParamAxis}); + qaRegistry.add("QAEvent/McColAll/hRecoCentralityColvsFT0Cmultiplicity", "Correlation between FT0C centrality and FT0C multiplicity in reconstructed MC events passed the event selection; FT0C (%); FT0c multiplicity", HistType::kTH2D, {centFT0CAxis, binsFT0CMultAxis}); // Information of generated 3HL in generated events - hGen3HLBeforeEvtSel = qaRegistry.add("QAEvent/McCol3HL/hGen3HLBeforeEvtSel", "3HL generated #it{p}_{T} distribution in all gen evt;#it{p}_{T} (GeV/#it{c}); Counts", HistType::kTH1D, {ptAxis}); - hGen3HLvsImpactParameterBeforeEvtSel = qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsImpactParameterBeforeEvtSel", "Correlation 3HL generated #it{p}_{T} and impact parameter in all gen evt;#it{p}_{T} (GeV/#it{c}); Impact parameter (b)", HistType::kTH2D, {ptAxis, impactParamAxis}); - hGen3HLvsMultiplicityGenEta05BeforeEvtSel = qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsMultiplicityGenEta05BeforeEvtSel", "Correlation 3HL generated #it{p}_{T} and charged particle multiplicity in all gen evt;#it{p}_{T} (GeV/#it{c}); Multiplicity #eta <0.5", HistType::kTH2D, {ptAxis, multAxis}); - hGen3HLvsMultiplicityGenEta08BeforeEvtSel = qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsMultiplicityGenEta08BeforeEvtSel", "Correlation 3HL generated #it{p}_{T} and charged particle multiplicity in all gen evt;#it{p}_{T} (GeV/#it{c}); Multiplicity #eta <0.8", HistType::kTH2D, {ptAxis, multAxis}); - hGen3HLvsMultiplicityFT0CBeforeEvtSel = qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsMultiplicityFT0CBeforeEvtSel", "Correlation 3HL generated #it{p}_{T} and FT0C multiplicity in all gen evt;#it{p}_{T} (GeV/#it{c}); FT0C Multiplicity", HistType::kTH2D, {ptAxis, binsFT0CMultAxis}); + qaRegistry.add("QAEvent/McCol3HL/hGen3HLBeforeEvtSel", "3HL generated #it{p}_{T} distribution in all gen evt;#it{p}_{T} (GeV/#it{c}); Counts", HistType::kTH1D, {ptAxis}); + qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsImpactParameterBeforeEvtSel", "Correlation 3HL generated #it{p}_{T} and impact parameter in all gen evt;#it{p}_{T} (GeV/#it{c}); Impact parameter (b)", HistType::kTH2D, {ptAxis, impactParamAxis}); + qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsMultiplicityGenEta05BeforeEvtSel", "Correlation 3HL generated #it{p}_{T} and charged particle multiplicity in all gen evt;#it{p}_{T} (GeV/#it{c}); Multiplicity #eta <0.5", HistType::kTH2D, {ptAxis, multAxis}); + qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsMultiplicityGenEta08BeforeEvtSel", "Correlation 3HL generated #it{p}_{T} and charged particle multiplicity in all gen evt;#it{p}_{T} (GeV/#it{c}); Multiplicity #eta <0.8", HistType::kTH2D, {ptAxis, multAxis}); + qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsMultiplicityFT0CBeforeEvtSel", "Correlation 3HL generated #it{p}_{T} and FT0C multiplicity in all gen evt;#it{p}_{T} (GeV/#it{c}); FT0C Multiplicity", HistType::kTH2D, {ptAxis, binsFT0CMultAxis}); // Information of generated 3HL in generated events with at least one rec. event and passed the event selection - hGen3HLAfterSel = qaRegistry.add("QAEvent/McCol3HL/hGen3HLAfterSel", "3HL generated #it{p}_{T} distribution in gen. evts with at least one rec. evt; #it{p}_{T} (GeV/#it{c}); Counts", HistType::kTH1D, {ptAxis}); - hGen3HLvsImpactParameterAfterSel = qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsImpactParameterAfterSel", "Correlation 3HL generated #it{p}_{T} and impact parameter in gen. evts with at least one rec. evt;#it{p}_{T} (GeV/#it{c}); Impact parameter (b)", HistType::kTH2D, {ptAxis, impactParamAxis}); - hGen3HLvsMultiplicityGenEta05AfterSel = qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsMultiplicityGenEta05AfterSel", "Correlation 3HL generated #it{p}_{T} and charged particle multiplicity in gen. evts with at least one rec. evt;#it{p}_{T} (GeV/#it{c}); Multiplicity #eta <0.5", HistType::kTH2D, {ptAxis, multAxis}); - hGen3HLvsMultiplicityGenEta08AfterSel = qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsMultiplicityGenEta08AfterSel", "Correlation 3HL generated #it{p}_{T} and charged particle multiplicity in gen. evts with at least one rec. evt;#it{p}_{T} (GeV/#it{c}); Multiplicity #eta <0.8", HistType::kTH2D, {ptAxis, multAxis}); - hGen3HLvsMultiplicityFT0CAfterSel = qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsMultiplicityFT0CAfterSel", "Correlation 3HL generated #it{p}_{T} and FT0C multiplicity in gen. evts with at least one rec;#it{p}_{T} (GeV/#it{c}); FT0C Multiplicity", HistType::kTH2D, {ptAxis, binsFT0CMultAxis}); + qaRegistry.add("QAEvent/McCol3HL/hGen3HLAfterSel", "3HL generated #it{p}_{T} distribution in gen. evts with at least one rec. evt; #it{p}_{T} (GeV/#it{c}); Counts", HistType::kTH1D, {ptAxis}); + qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsImpactParameterAfterSel", "Correlation 3HL generated #it{p}_{T} and impact parameter in gen. evts with at least one rec. evt;#it{p}_{T} (GeV/#it{c}); Impact parameter (b)", HistType::kTH2D, {ptAxis, impactParamAxis}); + qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsMultiplicityGenEta05AfterSel", "Correlation 3HL generated #it{p}_{T} and charged particle multiplicity in gen. evts with at least one rec. evt;#it{p}_{T} (GeV/#it{c}); Multiplicity #eta <0.5", HistType::kTH2D, {ptAxis, multAxis}); + qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsMultiplicityGenEta08AfterSel", "Correlation 3HL generated #it{p}_{T} and charged particle multiplicity in gen. evts with at least one rec. evt;#it{p}_{T} (GeV/#it{c}); Multiplicity #eta <0.8", HistType::kTH2D, {ptAxis, multAxis}); + qaRegistry.add("QAEvent/McCol3HL/hGen3HLvsMultiplicityFT0CAfterSel", "Correlation 3HL generated #it{p}_{T} and FT0C multiplicity in gen. evts with at least one rec;#it{p}_{T} (GeV/#it{c}); FT0C Multiplicity", HistType::kTH2D, {ptAxis, binsFT0CMultAxis}); } } @@ -408,12 +370,12 @@ struct hyperRecoTask { o2::parameters::GRPMagField* grpmag = 0x0; if (grpo) { o2::base::Propagator::initFieldFromGRP(grpo); - if (d_bz_input < -990) { + if (dBzInput < UseCCDBMagneticFieldThreshold) { // Fetch magnetic field from ccdb for current collision d_bz = grpo->getNominalL3Field(); LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; } else { - d_bz = d_bz_input; + d_bz = dBzInput; } } else { grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); @@ -421,22 +383,22 @@ struct hyperRecoTask { LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; } o2::base::Propagator::initFieldFromGRP(grpmag); - if (d_bz_input < -990) { + if (dBzInput < UseCCDBMagneticFieldThreshold) { // Fetch magnetic field from ccdb for current collision d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; } else { - d_bz = d_bz_input; + d_bz = dBzInput; } } if (!pidPath.value.empty()) { auto he3pid = ccdb->getForTimeStamp>(pidPath.value + "_He3", run3grp_timestamp); std::copy(he3pid->begin(), he3pid->end(), mBBparamsHe.begin()); } else { - for (int i = 0; i < 5; i++) { + for (int i = 0; i < NumBetheBlochParameters; i++) { mBBparamsHe[i] = cfgBetheBlochParams->get("He3", Form("p%i", i)); } - mBBparamsHe[5] = cfgBetheBlochParams->get("He3", "resolution"); + mBBparamsHe[NumBetheBlochParameters] = cfgBetheBlochParams->get("He3", "resolution"); } fitter.setBz(d_bz); mRunNumber = bc.runNumber(); @@ -458,7 +420,7 @@ struct hyperRecoTask { for (const auto& collision : collisions) { auto bc = collision.template bc_as(); initCCDB(bc); - hEvents->Fill(0.); + qaRegistry.fill(HIST("hEvents"), 0.); if (!collision.selection_bit(aod::evsel::kNoITSROFrameBorder) && !disableITSROFCut) { continue; @@ -469,7 +431,7 @@ struct hyperRecoTask { // accounting done after ITS border cut, to properly correct with the MC zorroSelected = zorro.isSelected(collision.template bc_as().globalBC()); if (zorroSelected) { - hEventsZorro->Fill(0.); + qaRegistry.fill(HIST("hEventsZorro"), 0.); } } @@ -477,35 +439,35 @@ struct hyperRecoTask { continue; } - hEvents->Fill(1.); + qaRegistry.fill(HIST("hEvents"), 1.); - if (std::abs(collision.posZ()) > 10) { + if (std::abs(collision.posZ()) > MaxAbsVertexZ) { continue; } - hEvents->Fill(2.); + qaRegistry.fill(HIST("hEvents"), 2.); if (zorroSelected) { - hEventsZorro->Fill(1.); + qaRegistry.fill(HIST("hEventsZorro"), 1.); } if (cfgEvSelkNoSameBunchPileup) { if (!collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { continue; } - hEvents->Fill(3.); + qaRegistry.fill(HIST("hEvents"), 3.); } if (cfgEvSelkIsGoodZvtxFT0vsPV) { if (!collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { continue; } - hEvents->Fill(4.); + qaRegistry.fill(HIST("hEvents"), 4.); } goodCollision[collision.globalIndex()] = true; - hZvtx->Fill(collision.posZ()); - hCentFT0A->Fill(collision.centFT0A()); - hCentFT0C->Fill(collision.centFT0C()); - hCentFT0M->Fill(collision.centFT0M()); + qaRegistry.fill(HIST("hZvtx"), collision.posZ()); + qaRegistry.fill(HIST("hCentFT0A"), collision.centFT0A()); + qaRegistry.fill(HIST("hCentFT0C"), collision.centFT0C()); + qaRegistry.fill(HIST("hCentFT0M"), collision.centFT0M()); } } @@ -515,41 +477,41 @@ struct hyperRecoTask { for (const auto& collision : collisions) { auto bc = collision.template bc_as(); initCCDB(bc); - hEvents->Fill(0.); + qaRegistry.fill(HIST("hEvents"), 0.); if (collision.has_mcCollision()) { recoCollisionIds[collision.mcCollisionId()] = collision.globalIndex(); } if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) continue; - hEvents->Fill(1.); + qaRegistry.fill(HIST("hEvents"), 1.); - if (std::abs(collision.posZ()) > 10) { + if (std::abs(collision.posZ()) > MaxAbsVertexZ) { continue; } - hEvents->Fill(2.); + qaRegistry.fill(HIST("hEvents"), 2.); if (cfgEvSelkNoSameBunchPileup) { if (!collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { continue; } - hEvents->Fill(3.); + qaRegistry.fill(HIST("hEvents"), 3.); } if (cfgEvSelkIsGoodZvtxFT0vsPV) { if (!collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { continue; } - hEvents->Fill(4.); + qaRegistry.fill(HIST("hEvents"), 4.); } if (collision.has_mcCollision()) { isSurvEvSelCollision[collision.mcCollisionId()] = true; } goodCollision[collision.globalIndex()] = true; - hZvtx->Fill(collision.posZ()); - hCentFT0A->Fill(collision.centFT0A()); - hCentFT0C->Fill(collision.centFT0C()); - hCentFT0M->Fill(collision.centFT0M()); + qaRegistry.fill(HIST("hZvtx"), collision.posZ()); + qaRegistry.fill(HIST("hCentFT0A"), collision.centFT0A()); + qaRegistry.fill(HIST("hCentFT0C"), collision.centFT0C()); + qaRegistry.fill(HIST("hCentFT0M"), collision.centFT0M()); } } template @@ -573,11 +535,11 @@ struct hyperRecoTask { hypCand.clusterSizeITSPi = piTrack.itsClusterSizes(); bool heliumPID = heTrack.pidForTracking() == o2::track::PID::Helium3 || heTrack.pidForTracking() == o2::track::PID::Alpha; hypCand.momHe3TPC = (heliumPID && cfgCompensatePIDinTracking) ? heTrack.tpcInnerParam() / 2 : heTrack.tpcInnerParam(); - if (hypCand.momHe3TPC < TPCRigidityMinHe) + if (hypCand.momHe3TPC < tpcRigidityMinHe) return; hypCand.momPiTPC = piTrack.tpcInnerParam(); - hDeDxTot->Fill(hypCand.momHe3TPC * heTrack.sign(), heTrack.tpcSignal()); - hDeDxTot->Fill(hypCand.momPiTPC * piTrack.sign(), piTrack.tpcSignal()); + qaRegistry.fill(HIST("hDeDxTot"), hypCand.momHe3TPC * heTrack.sign(), heTrack.tpcSignal()); + qaRegistry.fill(HIST("hDeDxTot"), hypCand.momPiTPC * piTrack.sign(), piTrack.tpcSignal()); hypCand.flags |= static_cast((heTrack.pidForTracking() & 0xF) << 4); hypCand.flags |= static_cast(piTrack.pidForTracking() & 0xF); auto heTrackCov = getTrackParCov(heTrack); @@ -599,7 +561,7 @@ struct hyperRecoTask { hePropTrack.getPxPyPzGlo(hypCand.momHe3); piPropTrack.getPxPyPzGlo(hypCand.momPi); // the momentum has to be multiplied by 2 (charge) - for (int i = 0; i < 3; i++) { + for (std::size_t i = 0; i < hypCand.momHe3.size(); i++) { hypCand.momHe3[i] *= 2; } float heP2 = hypCand.momHe3[0] * hypCand.momHe3[0] + hypCand.momHe3[1] * hypCand.momHe3[1] + hypCand.momHe3[2] * hypCand.momHe3[2]; @@ -609,9 +571,9 @@ struct hyperRecoTask { float piE = std::sqrt(piP2 + piMass * piMass); float h3lE = he3E + piE; float h4lE = he4E + piE; - std::array hypMom; + std::array hypMom{}; const auto& vtx = fitter.getPCACandidate(); - for (int i = 0; i < 3; i++) { + for (std::size_t i = 0; i < hypCand.decVtx.size(); i++) { hypCand.decVtx[i] = vtx[i]; hypMom[i] = hypCand.momHe3[i] + hypCand.momPi[i]; } @@ -621,22 +583,22 @@ struct hyperRecoTask { float massH3L = std::sqrt(h3lE * h3lE - hypMom[0] * hypMom[0] - hypMom[1] * hypMom[1] - hypMom[2] * hypMom[2]); float massH4L = std::sqrt(h4lE * h4lE - hypMom[0] * hypMom[0] - hypMom[1] * hypMom[1] - hypMom[2] * hypMom[2]); bool isHypMass = false; - if (massH3L > o2::constants::physics::MassHyperTriton - masswidth && massH3L < o2::constants::physics::MassHyperTriton + masswidth) + if (massH3L > o2::constants::physics::MassHyperTriton - massWidth && massH3L < o2::constants::physics::MassHyperTriton + massWidth) isHypMass = true; - if (massH4L > o2::constants::physics::MassHyperhydrog4 - masswidth && massH4L < o2::constants::physics::MassHyperhydrog4 + masswidth) + if (massH4L > o2::constants::physics::MassHyperhydrog4 - massWidth && massH4L < o2::constants::physics::MassHyperhydrog4 + massWidth) isHypMass = true; if (!isHypMass) return; - hH3LMassBefSel->Fill(massH3L); - hH4LMassBefSel->Fill(massH4L); + qaRegistry.fill(HIST("hH3LMassBefSel"), massH3L); + qaRegistry.fill(HIST("hH4LMassBefSel"), massH4L); if (!trackedClSize.empty() && trackedClSize[hypCand.v0ID] > 0) { - hH3LMassTracked->Fill(massH3L); - hH4LMassTracked->Fill(massH4L); + qaRegistry.fill(HIST("hH3LMassTracked"), massH3L); + qaRegistry.fill(HIST("hH4LMassTracked"), massH4L); } hypCand.dcaV0dau = std::sqrt(fitter.getChi2AtPCACandidate()); - if (hypCand.dcaV0dau > dcav0dau) { + if (hypCand.dcaV0dau > dcaV0Dau) { return; } @@ -658,13 +620,13 @@ struct hyperRecoTask { return; } - if (cosPAmax < v0cospacut) { + if (cosPAmax < v0CosPaCut) { return; } auto collision = collisions.rawIteratorAt(collIDmax); std::array primVtx = {collision.posX(), collision.posY(), collision.posZ()}; - for (int i = 0; i < 3; i++) { + for (std::size_t i = 0; i < hypCand.decVtx.size(); i++) { hypCand.decVtx[i] = hypCand.decVtx[i] - primVtx[i]; } @@ -691,8 +653,8 @@ struct hyperRecoTask { hypCand.massTOFHe3 = hypCand.momHe3TPC * 2.f * std::sqrt(1.f / (beta * beta) - 1.f); } - hDeDx3HeSel->Fill(heTrack.sign() * hypCand.momHe3TPC, heTrack.tpcSignal()); - hNsigma3HeSel->Fill(heTrack.sign() * hypCand.momHe3TPC, hypCand.nSigmaHe3); + qaRegistry.fill(HIST("hDeDx3HeSel"), heTrack.sign() * hypCand.momHe3TPC, heTrack.tpcSignal()); + qaRegistry.fill(HIST("hNsigma3HeSel"), heTrack.sign() * hypCand.momHe3TPC, hypCand.nSigmaHe3); hyperCandidates.push_back(hypCand); } @@ -783,7 +745,7 @@ struct hyperRecoTask { } void fillMCinfo(aod::McTrackLabels const& trackLabels, aod::McParticles const&) { - for (auto& hypCand : hyperCandidates) { + for (auto& hypCand : hyperCandidates) { // o2-linter: disable=const-ref-in-for-loop (candidate is enriched with MC information in this loop) auto mcLabHe = trackLabels.rawIteratorAt(hypCand.heTrackID); auto mcLabPi = trackLabels.rawIteratorAt(hypCand.piTrackID); @@ -804,13 +766,13 @@ struct hyperRecoTask { auto secVtx = std::array{mcTrackHe.vx(), mcTrackHe.vy(), mcTrackHe.vz()}; hypCand.gMom = std::array{heMother.px(), heMother.py(), heMother.pz()}; hypCand.gMomHe3 = std::array{mcTrackHe.px(), mcTrackHe.py(), mcTrackHe.pz()}; - for (int i = 0; i < 3; i++) { + for (std::size_t i = 0; i < hypCand.gDecVtx.size(); i++) { hypCand.gDecVtx[i] = secVtx[i] - primVtx[i]; } hypCand.isSignal = true; hypCand.isFakeHeOnITSLayer = mcLabHe.mcMask() & 0x7F; // check if any of the first 7 bits is set hypCand.pdgCode = heMother.pdgCode(); - hypCand.isRecoMCCollision = recoCollisionIds[heMother.mcCollisionId()] > 0; + hypCand.isRecoMCCollision = recoCollisionIds[heMother.mcCollisionId()] >= 0; hypCand.isSurvEvSelection = isSurvEvSelCollision[heMother.mcCollisionId()]; filledMothers.push_back(heMother.globalIndex()); } @@ -829,7 +791,7 @@ struct hyperRecoTask { } processData(collisions, V0s, tracks, ambiTracks, bcs); } - PROCESS_SWITCH(hyperRecoTask, processDataTracked, "Data analysis wit tracked V0s information", false); + PROCESS_SWITCH(HyperRecoTask, processDataTracked, "Data analysis wit tracked V0s information", false); void processData(CollisionsFull const& collisions, aod::V0s const& V0s, TracksFull const& tracks, aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcs) { @@ -844,6 +806,7 @@ struct hyperRecoTask { auto collision = collisions.rawIteratorAt(hypCand.collisionID); float trackedHypClSize = !trackedClSize.empty() ? trackedClSize[hypCand.v0ID] : 0; outputDataTable(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), + collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange(), collision.posX(), collision.posY(), collision.posZ(), mRunNumber, hypCand.isMatter, hypCand.recoPtHe3(), hypCand.recoPhiHe3(), hypCand.recoEtaHe3(), @@ -858,7 +821,7 @@ struct hyperRecoTask { hypCand.clusterSizeITSHe3, hypCand.clusterSizeITSPi, hypCand.flags, trackedHypClSize); } } - PROCESS_SWITCH(hyperRecoTask, processData, "Data analysis", true); + PROCESS_SWITCH(HyperRecoTask, processData, "Data analysis", true); void processDataWithFlow(CollisionsFullWithFlow const& collisions, aod::V0s const& V0s, TracksFull const& tracks, aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcs) { @@ -877,6 +840,7 @@ struct hyperRecoTask { } float trackedHypClSize = !trackedClSize.empty() ? trackedClSize[hypCand.v0ID] : 0; outputDataTableWithFlow(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), + collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange(), collision.psiFT0A(), collision.multFT0A(), collision.psiFT0C(), collision.multFT0C(), collision.qFT0C(), collision.psiTPC(), collision.multTPC(), @@ -894,7 +858,7 @@ struct hyperRecoTask { hypCand.clusterSizeITSHe3, hypCand.clusterSizeITSPi, hypCand.flags, trackedHypClSize); } } - PROCESS_SWITCH(hyperRecoTask, processDataWithFlow, "Data analysis with flow", false); + PROCESS_SWITCH(HyperRecoTask, processDataWithFlow, "Data analysis with flow", false); void processDataWithCollID(CollisionsFull const& collisions, aod::V0s const& V0s, TracksFull const& tracks, aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcs) { @@ -908,7 +872,9 @@ struct hyperRecoTask { for (const auto& hypCand : hyperCandidates) { auto collision = collisions.rawIteratorAt(hypCand.collisionID); float trackedHypClSize = !trackedClSize.empty() ? trackedClSize[hypCand.v0ID] : 0; - outputDataTableWithCollID(hypCand.collisionID, collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), + outputDataTableWithCollID(hypCand.collisionID, hypCand.heTrackID, hypCand.piTrackID, + collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), + collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange(), collision.posX(), collision.posY(), collision.posZ(), mRunNumber, hypCand.isMatter, hypCand.recoPtHe3(), hypCand.recoPhiHe3(), hypCand.recoEtaHe3(), @@ -923,7 +889,7 @@ struct hyperRecoTask { hypCand.clusterSizeITSHe3, hypCand.clusterSizeITSPi, hypCand.flags, trackedHypClSize); } } - PROCESS_SWITCH(hyperRecoTask, processDataWithCollID, "Data analysis with collision ID", false); + PROCESS_SWITCH(HyperRecoTask, processDataWithCollID, "Data analysis with collision ID", false); void processMC(CollisionsFullMC const& collisions, aod::McCollisions const& mcCollisions, aod::V0s const& V0s, TracksFull const& tracks, aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcs, aod::McTrackLabels const& trackLabelsMC, aod::McParticles const& particlesMC) { @@ -945,7 +911,9 @@ struct hyperRecoTask { continue; int chargeFactor = -1 + 2 * (hypCand.pdgCode > 0); float trackedHypClSize = !trackedClSize.empty() ? trackedClSize[hypCand.v0ID] : 0; - outputMCTable(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), + outputMCTable(hypCand.collisionID, hypCand.heTrackID, hypCand.piTrackID, + collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), + collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange(), collision.posX(), collision.posY(), collision.posZ(), mRunNumber, hypCand.isMatter, hypCand.recoPtHe3(), hypCand.recoPhiHe3(), hypCand.recoEtaHe3(), @@ -986,28 +954,28 @@ struct hyperRecoTask { } } if (mcPart.pdgCode() > 0) { - hIsMatterGen->Fill(0.); + qaRegistry.fill(HIST("hIsMatterGen"), 0.); } else { - hIsMatterGen->Fill(1.); + qaRegistry.fill(HIST("hIsMatterGen"), 1.); } if (!isHeFound) { - hDecayChannel->Fill(1.); + qaRegistry.fill(HIST("hDecayChannel"), 1.); } - hDecayChannel->Fill(0.); + qaRegistry.fill(HIST("hDecayChannel"), 0.); if (mcPart.pdgCode() > 0) { - hIsMatterGenTwoBody->Fill(0.); + qaRegistry.fill(HIST("hIsMatterGenTwoBody"), 0.); } else { - hIsMatterGenTwoBody->Fill(1.); + qaRegistry.fill(HIST("hIsMatterGenTwoBody"), 1.); } if (std::find(filledMothers.begin(), filledMothers.end(), mcPart.globalIndex()) != std::end(filledMothers)) { continue; } hyperCandidate hypCand; hypCand.pdgCode = mcPart.pdgCode(); - hypCand.isRecoMCCollision = recoCollisionIds[mcPart.mcCollisionId()] > 0; + hypCand.isRecoMCCollision = recoCollisionIds[mcPart.mcCollisionId()] >= 0; hypCand.isSurvEvSelection = isSurvEvSelCollision[mcPart.mcCollisionId()]; int chargeFactor = -1 + 2 * (hypCand.pdgCode > 0); - for (int i = 0; i < 3; i++) { + for (std::size_t i = 0; i < hypCand.gDecVtx.size(); i++) { hypCand.gDecVtx[i] = (isHeFound ? secVtx[i] : lastDaugVtx[i]) - primVtx[i]; hypCand.gMom[i] = momMother[i]; hypCand.gMomHe3[i] = momHe3[i]; @@ -1017,15 +985,21 @@ struct hyperRecoTask { hypCand.isSignal = true; float centFT0A = -1, centFT0C = -1, centFT0M = -1; + int trackOccupancyInTimeRange = -1; + float ft0cOccupancyInTimeRange = -1.f; if (hypCand.isRecoMCCollision) { auto recoCollision = collisions.rawIteratorAt(recoCollisionIds[mcPart.mcCollisionId()]); centFT0A = recoCollision.centFT0A(); centFT0C = recoCollision.centFT0C(); centFT0M = recoCollision.centFT0M(); + trackOccupancyInTimeRange = recoCollision.trackOccupancyInTimeRange(); + ft0cOccupancyInTimeRange = recoCollision.ft0cOccupancyInTimeRange(); } - outputMCTable(centFT0A, centFT0C, centFT0M, - -1, -1, -1, + outputMCTable(-1, -1, -1, + centFT0A, centFT0C, centFT0M, + trackOccupancyInTimeRange, ft0cOccupancyInTimeRange, + primVtx[0], primVtx[1], primVtx[2], mRunNumber, 0, -1, -1, -1, -1, -1, -1, @@ -1039,7 +1013,7 @@ struct hyperRecoTask { hypCand.isReco, -1, hypCand.isSignal, hypCand.isRecoMCCollision, hypCand.isSurvEvSelection, isHeFound, mcProcess); } } - PROCESS_SWITCH(hyperRecoTask, processMC, "MC analysis", false); + PROCESS_SWITCH(HyperRecoTask, processMC, "MC analysis", false); void processMCTracked(CollisionsFullMC const& collisions, aod::McCollisions const& mcCollisions, aod::V0s const& V0s, aod::TrackedV0s const& tV0s, TracksFull const& tracks, aod::AmbiguousTracks const& ambiTracks, aod::BCsWithTimestamps const& bcs, aod::McTrackLabels const& trackLabelsMC, aod::McParticles const& particlesMC) { @@ -1050,7 +1024,7 @@ struct hyperRecoTask { } processMC(collisions, mcCollisions, V0s, tracks, ambiTracks, bcs, trackLabelsMC, particlesMC); } - PROCESS_SWITCH(hyperRecoTask, processMCTracked, "MC analysis with tracked V0s", false); + PROCESS_SWITCH(HyperRecoTask, processMCTracked, "MC analysis with tracked V0s", false); template bool passEvtSel(const CollType& collision) @@ -1058,7 +1032,7 @@ struct hyperRecoTask { if (!collision.sel8()) return false; - if ((std::abs(collision.posZ())) > 10) + if ((std::abs(collision.posZ())) > MaxAbsVertexZ) return false; if (cfgEvSelkNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) @@ -1072,21 +1046,21 @@ struct hyperRecoTask { void processEventLossMC(McCollisionMults::iterator const& mcCollision, soa::SmallGroups const& collisions, aod::McParticles const& GenParticles) { - if (std::abs(mcCollision.posZ()) > 10) { + if (std::abs(mcCollision.posZ()) > MaxAbsVertexZ) { return; } //////////// Event loss estimation via impact parameter and multiplicity by MCFT0C // Fill all generated events - hEvtMC->Fill(0); - hImpactParamGen->Fill(mcCollision.impactParameter()); - hGenEventsNchEta05->Fill(mcCollision.multMCNParticlesEta05(), 0); - hGenEventsNchEta08->Fill(mcCollision.multMCNParticlesEta08(), 0); + qaRegistry.fill(HIST("QAEvent/hEvtMC"), 0); + qaRegistry.fill(HIST("QAEvent/McColAll/hImpactParamGen"), mcCollision.impactParameter()); + qaRegistry.fill(HIST("QAEvent/hGenEventsNchEta05"), mcCollision.multMCNParticlesEta05(), 0); + qaRegistry.fill(HIST("QAEvent/hGenEventsNchEta08"), mcCollision.multMCNParticlesEta08(), 0); // Fill generated events with no reconstructed collisions if (collisions.size() == 0) { - hEvtMC->Fill(1); + qaRegistry.fill(HIST("QAEvent/hEvtMC"), 1); } // Define the generated events with at least one reconstructed event @@ -1104,24 +1078,24 @@ struct hyperRecoTask { centralityFT0C = col.centFT0C(); } atLeastOneRecoEvt = true; - hImpactParamReco->Fill(mcCollision.impactParameter()); - hRecoCentrality->Fill(col.centFT0C()); - hRecoCentralityColvsMultiplicityRecoEta05->Fill(col.centFT0C(), mcCollision.multMCNParticlesEta05()); - hRecoCentralityColvsMultiplicityRecoEta08->Fill(col.centFT0C(), mcCollision.multMCNParticlesEta08()); - hRecoCentralityColvsImpactParamReco->Fill(col.centFT0C(), mcCollision.impactParameter()); - hRecoCentralityColvsFT0Cmultiplicity->Fill(col.centFT0C(), mcCollision.multMCFT0C()); + qaRegistry.fill(HIST("QAEvent/McColAll/hImpactParamReco"), mcCollision.impactParameter()); + qaRegistry.fill(HIST("QAEvent/McColAll/hRecoCentrality"), col.centFT0C()); + qaRegistry.fill(HIST("QAEvent/McColAll/hRecoCentralityColvsMultiplicityRecoEta05"), col.centFT0C(), mcCollision.multMCNParticlesEta05()); + qaRegistry.fill(HIST("QAEvent/McColAll/hRecoCentralityColvsMultiplicityRecoEta08"), col.centFT0C(), mcCollision.multMCNParticlesEta08()); + qaRegistry.fill(HIST("QAEvent/McColAll/hRecoCentralityColvsImpactParamReco"), col.centFT0C(), mcCollision.impactParameter()); + qaRegistry.fill(HIST("QAEvent/McColAll/hRecoCentralityColvsFT0Cmultiplicity"), col.centFT0C(), mcCollision.multMCFT0C()); } if (atLeastOneRecoEvt) { - hEvtMC->Fill(2); - hGenEventsNchEta05->Fill(mcCollision.multMCNParticlesEta05(), 1); - hGenEventsNchEta08->Fill(mcCollision.multMCNParticlesEta08(), 1); - hImpactParamGenOneReco->Fill(mcCollision.impactParameter()); - hGenOneRecoCentrality->Fill(centralityFT0C); - hGenCentralityColvsMultiplicityGenEta05->Fill(centralityFT0C, mcCollision.multMCNParticlesEta05()); - hGenCentralityColvsMultiplicityGenEta08->Fill(centralityFT0C, mcCollision.multMCNParticlesEta08()); - hGenCentralityColvsImpactParamGen->Fill(centralityFT0C, mcCollision.impactParameter()); - hGenCentralityColvsFT0Cmultiplicity->Fill(centralityFT0C, mcCollision.multMCFT0C()); + qaRegistry.fill(HIST("QAEvent/hEvtMC"), 2); + qaRegistry.fill(HIST("QAEvent/hGenEventsNchEta05"), mcCollision.multMCNParticlesEta05(), 1); + qaRegistry.fill(HIST("QAEvent/hGenEventsNchEta08"), mcCollision.multMCNParticlesEta08(), 1); + qaRegistry.fill(HIST("QAEvent/McColPassedEvSel/hImpactParamGenOneReco"), mcCollision.impactParameter()); + qaRegistry.fill(HIST("QAEvent/McColPassedEvSel/hGenOneRecoCentrality"), centralityFT0C); + qaRegistry.fill(HIST("QAEvent/McColPassedEvSel/hGenCentralityColvsMultiplicityGenEta05"), centralityFT0C, mcCollision.multMCNParticlesEta05()); + qaRegistry.fill(HIST("QAEvent/McColPassedEvSel/hGenCentralityColvsMultiplicityGenEta08"), centralityFT0C, mcCollision.multMCNParticlesEta08()); + qaRegistry.fill(HIST("QAEvent/McColPassedEvSel/hGenCentralityColvsImpactParamGen"), centralityFT0C, mcCollision.impactParameter()); + qaRegistry.fill(HIST("QAEvent/McColPassedEvSel/hGenCentralityColvsFT0Cmultiplicity"), centralityFT0C, mcCollision.multMCFT0C()); } // Construct the H3L 4-vector based on the generated daugthers identification by PDG ROOT::Math::PxPyPzMVector daugh1, daugh2, mother; @@ -1159,28 +1133,28 @@ struct hyperRecoTask { mother = daugh1 + daugh2; // Fill informations for generated 3HL in all generated events - hGen3HLBeforeEvtSel->Fill(mother.pt()); - hGen3HLvsImpactParameterBeforeEvtSel->Fill(mother.pt(), mcCollision.impactParameter()); - hGen3HLvsMultiplicityGenEta05BeforeEvtSel->Fill(mother.pt(), mcCollision.multMCNParticlesEta05()); - hGen3HLvsMultiplicityGenEta08BeforeEvtSel->Fill(mother.pt(), mcCollision.multMCNParticlesEta08()); - hGen3HLvsMultiplicityFT0CBeforeEvtSel->Fill(mother.pt(), mcCollision.multMCFT0C()); + qaRegistry.fill(HIST("QAEvent/McCol3HL/hGen3HLBeforeEvtSel"), mother.pt()); + qaRegistry.fill(HIST("QAEvent/McCol3HL/hGen3HLvsImpactParameterBeforeEvtSel"), mother.pt(), mcCollision.impactParameter()); + qaRegistry.fill(HIST("QAEvent/McCol3HL/hGen3HLvsMultiplicityGenEta05BeforeEvtSel"), mother.pt(), mcCollision.multMCNParticlesEta05()); + qaRegistry.fill(HIST("QAEvent/McCol3HL/hGen3HLvsMultiplicityGenEta08BeforeEvtSel"), mother.pt(), mcCollision.multMCNParticlesEta08()); + qaRegistry.fill(HIST("QAEvent/McCol3HL/hGen3HLvsMultiplicityFT0CBeforeEvtSel"), mother.pt(), mcCollision.multMCFT0C()); // Fill informations for generated 3HL in generated events with at least one reconstructed event if (atLeastOneRecoEvt) { - hGen3HLAfterSel->Fill(mother.pt()); - hGen3HLvsImpactParameterAfterSel->Fill(mother.pt(), mcCollision.impactParameter()); - hGen3HLvsMultiplicityGenEta05AfterSel->Fill(mother.pt(), mcCollision.multMCNParticlesEta05()); - hGen3HLvsMultiplicityGenEta08AfterSel->Fill(mother.pt(), mcCollision.multMCNParticlesEta08()); - hGen3HLvsMultiplicityFT0CAfterSel->Fill(mother.pt(), mcCollision.multMCFT0C()); + qaRegistry.fill(HIST("QAEvent/McCol3HL/hGen3HLAfterSel"), mother.pt()); + qaRegistry.fill(HIST("QAEvent/McCol3HL/hGen3HLvsImpactParameterAfterSel"), mother.pt(), mcCollision.impactParameter()); + qaRegistry.fill(HIST("QAEvent/McCol3HL/hGen3HLvsMultiplicityGenEta05AfterSel"), mother.pt(), mcCollision.multMCNParticlesEta05()); + qaRegistry.fill(HIST("QAEvent/McCol3HL/hGen3HLvsMultiplicityGenEta08AfterSel"), mother.pt(), mcCollision.multMCNParticlesEta08()); + qaRegistry.fill(HIST("QAEvent/McCol3HL/hGen3HLvsMultiplicityFT0CAfterSel"), mother.pt(), mcCollision.multMCFT0C()); } } } - PROCESS_SWITCH(hyperRecoTask, processEventLossMC, "Event loss analysis", false); + PROCESS_SWITCH(HyperRecoTask, processEventLossMC, "Event loss analysis", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/TableProducer/Nuspex/hyperkinkRecoTask.cxx b/PWGLF/TableProducer/Nuspex/hyperkinkRecoTask.cxx index 60af4175db1..cff24b20ee9 100644 --- a/PWGLF/TableProducer/Nuspex/hyperkinkRecoTask.cxx +++ b/PWGLF/TableProducer/Nuspex/hyperkinkRecoTask.cxx @@ -1162,7 +1162,7 @@ struct HyperkinkQa { // QA for mother track selection template - bool motherTrackCheck(const TTrack& track, const std::shared_ptr hist) + bool motherTrackCheck(const TTrack& track, const std::shared_ptr& hist) { hist->Fill(1); @@ -1206,7 +1206,7 @@ struct HyperkinkQa { // qa for daughter track selection template - bool daughterTrackCheck(const TTrack& track, const std::shared_ptr hist, float tpcNSigma) + bool daughterTrackCheck(const TTrack& track, const std::shared_ptr& hist, float tpcNSigma) { hist->Fill(1); diff --git a/PWGLF/TableProducer/Nuspex/lnnRecoTask.cxx b/PWGLF/TableProducer/Nuspex/lnnRecoTask.cxx index a9a823d364c..fd53c9ab92c 100644 --- a/PWGLF/TableProducer/Nuspex/lnnRecoTask.cxx +++ b/PWGLF/TableProducer/Nuspex/lnnRecoTask.cxx @@ -20,6 +20,7 @@ #include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -41,6 +42,8 @@ #include #include +#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) +#include #include #include #include @@ -59,16 +62,20 @@ using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using std::array; + using TracksFull = soa::Join; using TracksFullMC = soa::Join; -using CollisionsFull = soa::Join; -using CollisionsFullMC = soa::Join; +using CollisionsFull = soa::Join; +using CollisionsFullMC = soa::Join; using CollisionCandidates = o2::soa::Join; using CollisionCandidatesMC = o2::soa::Join; using TrackCandidates = o2::soa::Join; using TrackCandidatesMC = o2::soa::Join; +using McCollisionMults = soa::Join; +using EventCandidatesMC = soa::Join; + namespace { constexpr double BetheBlochDefault[1][6]{{-1.e32, -1.e32, -1.e32, -1.e32, -1.e32, -1.e32}}; @@ -83,6 +90,7 @@ std::shared_ptr hCentFT0M; std::shared_ptr hCentFV0A; std::shared_ptr hNsigma3HSel; std::shared_ptr hNsigma3HSelTOF; +std::shared_ptr h2Nsigma3HSelTPCTOF; std::shared_ptr hdEdx3HSel; std::shared_ptr hdEdx3HPosTrack; std::shared_ptr hdEdx3HNegTrack; @@ -92,6 +100,8 @@ std::shared_ptr h3HSignalPtTOF; std::shared_ptr hIsMatterGen; std::shared_ptr hLnnCandLoss; std::shared_ptr hDecayChannel; +// QA centrality scaling +std::shared_ptr h2GlobalTrackMultVsCent; // QA histograms before track selections std::shared_ptr h2FT0CnClusTPCtoTrBfSel; std::shared_ptr h2FT0CnClusTPCtoPiBfSel; @@ -106,20 +116,42 @@ std::shared_ptr h2FT0CptPiBfSelItsTpc; // QA MC tracks from the lnn decay std::shared_ptr hPtGeneratedTrStr; std::shared_ptr hPtGeneratedPiStr; +std::shared_ptr hPtGeneratedLnnStr; +std::shared_ptr hPtTpcTrStr; std::shared_ptr hPtItsTpcTrStr; +std::shared_ptr hPtTrkTpcTrStr; std::shared_ptr hPtTrkItsTpcTrStr; std::shared_ptr hPtItsTpcTofTrStr; std::shared_ptr hPtTrkItsTpcTofTrStr; -std::shared_ptr hPtItsTpcPiStr; -std::shared_ptr hPtTrkItsTpcPiStr; + // QA reco generated candidate and daugher particles from secondary vertex std::shared_ptr h2FT0CPtGenColRecCandMC; std::shared_ptr h2FT0CPtGenColRecTrStrMC; -std::shared_ptr h2FT0CPtGenColRecPiStrMC; // QA signal generated candidate and daugher particles from secondary vertex std::shared_ptr h2FT0CPtGenColGenCandMC; std::shared_ptr h2FT0CPtGenColGenTrStrMC; -std::shared_ptr h2FT0CPtGenColGenPiStrMC; +// Event and signal loss +std::shared_ptr hEvtMC; +std::shared_ptr hImpactParamGen; +std::shared_ptr hImpactParamGenOneReco; +std::shared_ptr hImpactParamReco; +std::shared_ptr hGenLnnBeforeEvtSel; +std::shared_ptr hGenLnnAfterSel; +std::shared_ptr hGenOneRecoCentrality; +std::shared_ptr hRecoCentrality; +std::shared_ptr hGenEventsNchEta08; +std::shared_ptr hGenCentralityColvsMultiplicityGenEta08; +std::shared_ptr hGenCentralityColvsImpactParamGen; +std::shared_ptr hGenCentralityColvsFT0Cmultiplicity; +std::shared_ptr hRecoCentralityColvsMultiplicityRecoEta08; +std::shared_ptr hRecoCentralityColvsImpactParamReco; +std::shared_ptr hRecoCentralityColvsFT0Cmultiplicity; +std::shared_ptr hGenLnnvsImpactParameterBeforeEvtSel; +std::shared_ptr hGenLnnvsImpactParameterAfterSel; +std::shared_ptr hGenLnnvsMultiplicityGenEta08BeforeEvtSel; +std::shared_ptr hGenLnnvsMultiplicityGenEta08AfterSel; +std::shared_ptr hGenLnnvsMultiplicityFT0CBeforeEvtSel; +std::shared_ptr hGenLnnvsMultiplicityFT0CAfterSel; float alphaAP(std::array const& momB, std::array const& momC) { @@ -149,10 +181,6 @@ struct LnnCandidate { float genPhi3H() const { return std::atan2(gMom3H[1], gMom3H[0]); } float genEta3H() const { return std::asinh(gMom3H[2] / genPt3H()); } - float genPtPi() const { return std::hypot(gMomPi[0], gMomPi[1]); } - float genPhiPi() const { return std::atan2(gMomPi[1], gMomPi[0]); } - float genEtaPi() const { return std::asinh(gMomPi[2] / genPtPi()); } - int posTrackID; int negTrackID; float dcaV0dau = -10; @@ -172,7 +200,6 @@ struct LnnCandidate { std::array decVtx; std::array gMom; std::array gMom3H; - std::array gMomPi; std::array gDecVtx; uint16_t tpcSignal3H = 0u; uint16_t tpcSignalPi = 0u; @@ -191,7 +218,7 @@ struct LnnCandidate { uint8_t flags = 0u; // flags for dughter particles }; -struct lnnRecoTask { +struct LnnRecoTask { Produces outputDataTable; Produces outputMCTable; @@ -246,7 +273,7 @@ struct lnnRecoTask { Configurable piDauPdg{"piDauPdg", 211, "PDG Pi"}; // PDG Pi Configurable lnnPdg{"lnnPdg", 1010000030, "PDG Lnn"}; // PDG Lnn - // Histogram configuration QA lnn-task + // histograms axes ConfigurableAxis rigidityBins{"rigidityBins", {200, -10.f, 10.f}, "Binning for rigidity"}; ConfigurableAxis dEdxBins{"dEdxBins", {5000, 0.f, 1000.f}, "Binning for dE/dx"}; ConfigurableAxis nSigmaBins{"nSigmaBins", {200, -5.f, 5.f}, "Binning for n#sigma_{TPC}"}; @@ -263,9 +290,17 @@ struct lnnRecoTask { ConfigurableAxis tpcNClsCrossedRowsBins{"tpcNClsCrossedRowsBins", {260, 30, 165}, "Binning for TPCNClsCrossedRows"}; ConfigurableAxis tpcChi2NClusBins{"tpcChi2NClusBins", {20, 0.5, 10}, "Binning for chi2NClusTPC"}; ConfigurableAxis itsChi2NClusBins{"itsChi2NClusBins", {72, 0, 36}, "Binning for chi2NClusTPC"}; - ConfigurableAxis candPtBins{"candPtBins", {160, 0, 8}, "Binning for lnn cand pt"}; + ConfigurableAxis candPtBins{"candPtBins", {32, -8, 8}, "Binning for lnn cand pt"}; ConfigurableAxis candEtaBins{"candEtaBins", {160, -0.8, 0.8}, "Binning for eta"}; + // histogram axes for EvtLossMC + ConfigurableAxis binsImpactPar{"binsImpactPar", {80, 0, 16}, "Binning of the impact parameter axis"}; + ConfigurableAxis binsCent{"binsCent", {10, 0.0, 100.0}, "Binning of the centrality axis"}; + ConfigurableAxis binsPt{"binsPt", {20, 0, 10}, "Binning of the pt"}; + ConfigurableAxis binsFT0CMult{"binsFT0CMult", {500, 0.0f, +500.0f}, "Binning of the FT0C multiplicity"}; + ConfigurableAxis binsMult{"binsMult", {500, 0.0f, +500.0f}, ""}; + ConfigurableAxis binsglobalTrackMult{"binsglobalTrackMult", {100, 0.f, 1000.f}, "Binning for global track multiplicity"}; + // std vector of candidates std::vector lnnCandidates; // vector to keep track of MC mothers already filled @@ -277,11 +312,15 @@ struct lnnRecoTask { // vector to armazenade h3Track Preslice perCollision = o2::aod::v0::collisionId; + + Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; + Preslice tracksPerCollision = aod::track::collisionId; + HistogramRegistry qaRegistry{"QA", {}, OutputObjHandlingPolicy::AnalysisObject}; - int mRunNumber; - float d_bz; - std::array mBBparams3H; + int mRunNumber{-1}; + float dBz{0.f}; + std::array mBBparams3H{}; static constexpr float KallEvents = 0.; static constexpr float KevAfterSel8 = 1.; @@ -292,7 +331,7 @@ struct lnnRecoTask { void init(InitContext const&) { mRunNumber = 0; - d_bz = 0; + dBz = 0; ccdb->setURL(ccdburl); ccdb->setCaching(true); @@ -311,7 +350,8 @@ struct lnnRecoTask { const AxisSpec rigidityAxis{rigidityBins, "#it{p}^{TPC}/#it{z}"}; const AxisSpec dEdxAxis{dEdxBins, "d#it{E}/d#it{x}"}; - const AxisSpec nSigma3HAxis{nSigmaBins, "n_{#sigma}({}^{3}H)"}; + const AxisSpec nSigma3HtpcAxis{nSigmaBins, "n_{#sigma TPC}({}^{3}H)"}; + const AxisSpec nSigma3HtofAxis{nSigmaBins, "n_{#sigma TOF}({}^{3}H)"}; const AxisSpec zVtxAxis{zVtxBins, "z_{vtx} (cm)"}; const AxisSpec centAxis{centBins, "FT0C (%)"}; const AxisSpec mTOFAxis{mTOFBins, "#frac{m^{2}}{z^{2}}"}; @@ -326,8 +366,16 @@ struct lnnRecoTask { const AxisSpec candPtAxis(candPtBins, "#it{p}_{T} (Gev/#it{c})"); const AxisSpec candEtaAxis(candEtaBins, "#eta"); - hNsigma3HSel = qaRegistry.add("PID/hNsigma3HSel", ";#it{p}^{TPC}/z (GeV/#it{c}); n_{#sigma} ({}^{3}H)", HistType::kTH2F, {rigidityAxis, nSigma3HAxis}); - hNsigma3HSelTOF = qaRegistry.add("PID/hNsigma3HSelTOF", ";#it{p}_{T} (GeV/#it{c}); n_{#sigma} ({}^{3}H)", HistType::kTH2F, {tPtAxis, nSigma3HAxis}); + const AxisSpec impactParamAxis{binsImpactPar, "Impact Parameter (b)"}; + const AxisSpec centFT0CAxis{binsCent, "Centrality (FT0C %)"}; + const AxisSpec binsFT0CMultAxis{binsFT0CMult, "FT0C multiplicity"}; + const AxisSpec ptAxis{binsPt, "#it{p}_{T} (GeV/#it{c})"}; + const AxisSpec multAxis = {binsMult, "Multiplicity #eta <0.5"}; + const AxisSpec globalTrackMultAxis = {binsglobalTrackMult, "N_{global track mult.}"}; + + hNsigma3HSel = qaRegistry.add("PID/hNsigma3HSel", ";#it{p}^{TPC}/z (GeV/#it{c}); n_{#sigma} ({}^{3}H)", HistType::kTH2F, {rigidityAxis, nSigma3HtpcAxis}); + hNsigma3HSelTOF = qaRegistry.add("PID/hNsigma3HSelTOF", ";#it{p}_{T} (GeV/#it{c}); n_{#sigma} ({}^{3}H)", HistType::kTH2F, {tPtAxis, nSigma3HtpcAxis}); + h2Nsigma3HSelTPCTOF = qaRegistry.add("PID/h2Nsigma3HSelTPCTOF", ";n_{#sigma TPC} ({}^{3}H); n_{#sigma TOF} ({}^{3}H)", HistType::kTH2F, {nSigma3HtpcAxis, nSigma3HtofAxis}); hdEdx3HSel = qaRegistry.add("hdEdx3HSel", ";#it{p}^{TPC}/z (GeV/#it{c}); dE/dx", HistType::kTH2F, {rigidityAxis, dEdxAxis}); hdEdx3HPosTrack = qaRegistry.add("PID/hdEdx3HPosTrack", "; #it{p}^{TPC}/z (GeV/#it{c}); dE/dx", HistType::kTH2F, {tPosRigidityAxis, dEdxAxis}); hdEdx3HNegTrack = qaRegistry.add("PID/hdEdx3HNegTrack", "; #it{p}^{TPC}/z (GeV/#it{c}); dE/dx", HistType::kTH2F, {tPNegRigidityAxis, dEdxAxis}); @@ -335,27 +383,16 @@ struct lnnRecoTask { h3HMassPtTOF = qaRegistry.add("PID/hTrMassPtTOF", "; #it{p}_{T} ({}^{3}H) (GeV/#it{c}); #frac{m^{2}}{z^{2}} (GeV^{2}/#it{c}^{4})", HistType::kTH2F, {tPtAxis, mTOFAxis}); h3HSignalPtTOF = qaRegistry.add("PID/h3HSignalPtTOF", "; #it{p}_{T}({}^{3}H) (GeV/#it{c}); #beta_{TOF}", HistType::kTH2F, {tPtAxis, betaAxis}); hEvents = qaRegistry.add("hEvents", ";Events; ", HistType::kTH1D, {{4, -0.5, 3.5}}); - hLnnCandLoss = qaRegistry.add("CandCounts/hLnnCandLoss", ";CandLoss; ", HistType::kTH1D, {{7, -0.5, 6.5}}); - // QA its-tpc and its-tpc-tof tracks before selection - h2FT0CnClusTPCtoTrBfSel = qaRegistry.add("QATracks/h2FT0CnClusTPCtoTrBfSel", ";FT0C (%);N_{clus}^{TPC}", HistType::kTH2F, {centAxis, tpcNClusAxis}); - h2FT0CnClusTPCtoPiBfSel = qaRegistry.add("QATracks/h2FT0CnClusTPCtoPiBfSel", ";FT0C (%);N_{clus}^{TPC}", HistType::kTH2F, {centAxis, tpcNClusAxis}); - h2FT0Cchi2NClTPCtoTrBfSel = qaRegistry.add("QATracks/h2FT0Cchi2NClTPCtoTrBfSel", ";FT0C (%);{#Chi}^{2}/N_{clus}^{TPC} ", HistType::kTH2F, {centAxis, tpcChi2NClusAxis}); - h2FT0Cchi2NClITStoTrBfSel = qaRegistry.add("QATracks/h2FT0Cchi2NClITStoTrBfSel", ";FT0C (%);{#Chi}^{2}/N_{clus}^{ITS}", HistType::kTH2F, {centAxis, itsChi2NClusAxis}); - h2FT0CnTPCNClsCrossedRows3HBfSel = qaRegistry.add("QATracks/h2FT0CnTPCNClsCrossedRows3H", ";FT0C (%);N_{TPC} crossed rows", HistType::kTH2F, {centAxis, tpcNClsCrossedRowsAxis}); - h2FT0CnTPCNClsCrossedRowsPiBfSel = qaRegistry.add("QATracks/h2FT0CnTPCNClsCrossedRowsPi", ";FT0C (%);N_{TPC} crossed rows", HistType::kTH2F, {centAxis, tpcNClsCrossedRowsAxis}); - h2FT0CptTrBfSelItsTpc = qaRegistry.add("QATracks/h2FT0CptTrBfSelItsTpc", ";FT0C (%);#it{p}_{T}", HistType::kTH2F, {centAxis, candPtBins}); - h2FT0CptTrBfSelItsTpcTof = qaRegistry.add("QATracks/h2FT0CptTrBfSelItsTpcTof", ";FT0C (%);#it{p}_{T}", HistType::kTH2F, {centAxis, candPtBins}); - h2FT0CptPiBfSelItsTpc = qaRegistry.add("QATracks/h2FT0CptPiBfSelItsTpc", ";FT0C (%);#it{p}_{T}", HistType::kTH2F, {centAxis, candPtBins}); - // QA its-tpc, its-tpc-tof, and generated MC - hPtItsTpcTrStr = qaRegistry.add("MC/McTracks/hPtItsTpcTrStr", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{10, 0, 100}, {160, 0, 8}}); - hPtTrkItsTpcTrStr = qaRegistry.add("MC/McTracks/hPtTrkItsTpcTrStr", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{10, 0, 100}, {160, 0, 8}}); - hPtItsTpcTofTrStr = qaRegistry.add("MC/McTracks/hPtItsTpcTofTrStr", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{10, 0, 100}, {160, 0, 8}}); - hPtTrkItsTpcTofTrStr = qaRegistry.add("MC/McTracks/hPtTrkItsTpcTofTrStr", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{10, 0, 100}, {160, 0, 8}}); - hPtItsTpcPiStr = qaRegistry.add("MC/McTracks/hPtItsTpcPiStr", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{10, 0, 100}, {160, 0, 8}}); - hPtTrkItsTpcPiStr = qaRegistry.add("MC/McTracks/hPtTrkItsTpcPiStr", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{10, 0, 100}, {160, 0, 8}}); - hPtGeneratedTrStr = qaRegistry.add("MC/McGen/hPtGeneratedTrStr", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{10, 0, 100}, {160, 0, 8}}); - hPtGeneratedPiStr = qaRegistry.add("MC/McGen/hPtGeneratedPiStr", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{10, 0, 100}, {160, 0, 8}}); + h2GlobalTrackMultVsCent = qaRegistry.add("QATracks/h2GlobalTrackMultVsCent", ";FT0C (%); N_{global track mult.}", HistType::kTH2F, {centAxis, globalTrackMultAxis}); + + hZvtx = qaRegistry.add("hZvtx", ";z_{vtx} (cm); ", HistType::kTH1D, {{100, -20, 20}}); + hCentFT0A = qaRegistry.add("hCentFT0A", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); + hCentFT0C = qaRegistry.add("hCentFT0C", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); + hCentFT0M = qaRegistry.add("hCentFT0M", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); + hCentFV0A = qaRegistry.add("hCentFV0A", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); + + hLnnCandLoss = qaRegistry.add("CandCounts/hLnnCandLoss", ";CandLoss; ", HistType::kTH1D, {{7, -0.5, 6.5}}); hEvents->GetXaxis()->SetBinLabel(1, "All"); hEvents->GetXaxis()->SetBinLabel(2, "sel8"); hEvents->GetXaxis()->SetBinLabel(3, "z_{vtx}"); @@ -369,6 +406,27 @@ struct lnnRecoTask { hLnnCandLoss->GetXaxis()->SetBinLabel(5, "!isLnnMass"); hLnnCandLoss->GetXaxis()->SetBinLabel(6, "DCA #it{V}_{0} daughter"); hLnnCandLoss->GetXaxis()->SetBinLabel(7, "cosPA"); + + // QA its-tpc and its-tpc-tof tracks before selection + h2FT0CnClusTPCtoTrBfSel = qaRegistry.add("QATracks/h2FT0CnClusTPCtoTrBfSel", ";FT0C (%);N_{clus}^{TPC}", HistType::kTH2F, {centAxis, tpcNClusAxis}); + h2FT0CnClusTPCtoPiBfSel = qaRegistry.add("QATracks/h2FT0CnClusTPCtoPiBfSel", ";FT0C (%);N_{clus}^{TPC}", HistType::kTH2F, {centAxis, tpcNClusAxis}); + h2FT0Cchi2NClTPCtoTrBfSel = qaRegistry.add("QATracks/h2FT0Cchi2NClTPCtoTrBfSel", ";FT0C (%);{#Chi}^{2}/N_{clus}^{TPC} ", HistType::kTH2F, {centAxis, tpcChi2NClusAxis}); + h2FT0Cchi2NClITStoTrBfSel = qaRegistry.add("QATracks/h2FT0Cchi2NClITStoTrBfSel", ";FT0C (%);{#Chi}^{2}/N_{clus}^{ITS}", HistType::kTH2F, {centAxis, itsChi2NClusAxis}); + h2FT0CnTPCNClsCrossedRows3HBfSel = qaRegistry.add("QATracks/h2FT0CnTPCNClsCrossedRows3H", ";FT0C (%);N_{TPC} crossed rows", HistType::kTH2F, {centAxis, tpcNClsCrossedRowsAxis}); + h2FT0CnTPCNClsCrossedRowsPiBfSel = qaRegistry.add("QATracks/h2FT0CnTPCNClsCrossedRowsPi", ";FT0C (%);N_{TPC} crossed rows", HistType::kTH2F, {centAxis, tpcNClsCrossedRowsAxis}); + h2FT0CptTrBfSelItsTpc = qaRegistry.add("QATracks/h2FT0CptTrBfSelItsTpc", ";FT0C (%);#it{p}_{T}", HistType::kTH2F, {centAxis, candPtAxis}); + h2FT0CptTrBfSelItsTpcTof = qaRegistry.add("QATracks/h2FT0CptTrBfSelItsTpcTof", ";FT0C (%);#it{p}_{T}", HistType::kTH2F, {centAxis, candPtAxis}); + h2FT0CptPiBfSelItsTpc = qaRegistry.add("QATracks/h2FT0CptPiBfSelItsTpc", ";FT0C (%);#it{p}_{T}", HistType::kTH2F, {centAxis, candPtAxis}); + // QA its-tpc, its-tpc-tof, and generated MC + hPtTpcTrStr = qaRegistry.add("MC/McTracks/hPtTpcTrStr", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{10, 0, 100}, {320, -8, 8}}); + hPtTrkTpcTrStr = qaRegistry.add("MC/McTracks/hPtTrkTpcTrStr", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{10, 0, 100}, {320, -8, 8}}); + hPtItsTpcTrStr = qaRegistry.add("MC/McTracks/hPtItsTpcTrStr", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{10, 0, 100}, {320, -8, 8}}); + hPtTrkItsTpcTrStr = qaRegistry.add("MC/McTracks/hPtTrkItsTpcTrStr", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{10, 0, 100}, {320, -8, 8}}); + hPtItsTpcTofTrStr = qaRegistry.add("MC/McTracks/hPtItsTpcTofTrStr", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{10, 0, 100}, {320, -8, 8}}); + hPtTrkItsTpcTofTrStr = qaRegistry.add("MC/McTracks/hPtTrkItsTpcTofTrStr", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{10, 0, 100}, {320, -8, 8}}); + hPtGeneratedTrStr = qaRegistry.add("MC/McGen/hPtGeneratedTrStr", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{10, 0, 100}, {320, -8, 8}}); + hPtGeneratedLnnStr = qaRegistry.add("MC/McGen/hPtGeneratedLnnStr", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {{10, 0, 100}, {320, -8, 8}}); + if (doprocessMC) { hDecayChannel = qaRegistry.add("MC/hDecayChannel", ";Decay channel; ", HistType::kTH1D, {{2, -0.5, 1.5}}); hDecayChannel->GetXaxis()->SetBinLabel(1, "All"); @@ -379,17 +437,44 @@ struct lnnRecoTask { // QA for generated mother candidate and daughter particles h2FT0CPtGenColRecCandMC = qaRegistry.add("MC/RecMcCol/h2FT0CPtGenColRecCandMC", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {centAxis, candPtAxis}); h2FT0CPtGenColRecTrStrMC = qaRegistry.add("MC/RecMcCol/h2FT0CPtGenColRecTrStrMC", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {centAxis, candPtAxis}); - h2FT0CPtGenColRecPiStrMC = qaRegistry.add("MC/RecMcCol/h2FT0CPtGenColRecPiStrMC", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {centAxis, candPtAxis}); // QA signal generated candidate and daugher particles from secondary vertex h2FT0CPtGenColGenCandMC = qaRegistry.add("MC/QASignalGenSV/h2FT0CPtGenColGenCandMC", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {centAxis, candPtAxis}); h2FT0CPtGenColGenTrStrMC = qaRegistry.add("MC/QASignalGenSV/h2FT0CPtGenColGenTrStrMC", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {centAxis, candPtAxis}); - h2FT0CPtGenColGenPiStrMC = qaRegistry.add("MC/QASignalGenSV/h2FT0CPtGenColGenPiStrMC", ";FT0C (%);#it{p}_{T} (GeV/#it{c})", HistType::kTH2F, {centAxis, candPtAxis}); } - hZvtx = qaRegistry.add("hZvtx", ";z_{vtx} (cm); ", HistType::kTH1D, {{100, -20, 20}}); - hCentFT0A = qaRegistry.add("hCentFT0A", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); - hCentFT0C = qaRegistry.add("hCentFT0C", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); - hCentFT0M = qaRegistry.add("hCentFT0M", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); - hCentFV0A = qaRegistry.add("hCentFV0A", ";Centrality; ", HistType::kTH1D, {{100, 0, 100}}); + + if (doprocessSigEvtLossMC) { + // Infomation for all generated collisions + hEvtMC = qaRegistry.add("QAEvent/hEvtMC", ";; ", HistType::kTH1D, {{3, -0.5, 2.5}}); + hEvtMC->GetXaxis()->SetBinLabel(1, "All gen evts"); + hEvtMC->GetXaxis()->SetBinLabel(2, "Gen evts with al least one reconstructed"); + hEvtMC->GetXaxis()->SetBinLabel(3, "Gen evts with no reconstructed collisions"); + hGenEventsNchEta08 = qaRegistry.add("QAEvent/hGenEventsNchEta08", ";;", HistType::kTH2D, {{multAxis}, {2, -0.5f, +1.5f}}); + hGenEventsNchEta08->GetYaxis()->SetBinLabel(1, "All gen. events"); + hGenEventsNchEta08->GetYaxis()->SetBinLabel(2, "Gen evts with at least 1 rec. collisions"); + hImpactParamGen = qaRegistry.add("QAEvent/McColAll/hImpactParamGen", "Impact parameter of generated MC events; Impact Parameter (b); Counts", HistType::kTH1D, {impactParamAxis}); + // Infomation for generated collisions which at least one rec. collision and passed the event selection + hImpactParamGenOneReco = qaRegistry.add("QAEvent/McColPassedEvSel/hImpactParamGenOneReco", "Impact parameter of generated MC events with at least one rec. evt and passed the event selection; Impact Parameter (b); Counts", HistType::kTH1D, {impactParamAxis}); + hGenOneRecoCentrality = qaRegistry.add("QAEvent/McColPassedEvSel/hGenOneRecoCentrality", "Centrality distribution of generated MC events with at least one rec. evt and passed the event selection; Centrality (FT0C %); Counts", HistType::kTH1D, {centFT0CAxis}); + hGenCentralityColvsMultiplicityGenEta08 = qaRegistry.add("QAEvent/McColPassedEvSel/hGenCentralityColvsMultiplicityGenEta08", "Correlation between FT0C centrality and charged particle multiplicity in generated MC events with at least one rec. evt and passed the event selection; Multiplicity #eta <0.8; Counts", HistType::kTH2D, {centFT0CAxis, multAxis}); + hGenCentralityColvsImpactParamGen = qaRegistry.add("QAEvent/McColPassedEvSel/hGenCentralityColvsImpactParamGen", "Correlation between FT0C centrality and impact parameter in generated MC events with at least one rec. evt and passed the event selection; Multiplicity #eta <0.8; Counts", HistType::kTH2D, {centFT0CAxis, impactParamAxis}); + hGenCentralityColvsFT0Cmultiplicity = qaRegistry.add("QAEvent/McColPassedEvSel/hGenCentralityColvsFT0Cmultiplicity", "Correlation between FT0C centrality and FT0C multiplicity in generated MC events with at least one rec. evt and passed the event selection; FT0c multiplicity", HistType::kTH2D, {centFT0CAxis, binsFT0CMultAxis}); + // Infomation for all reconstructed collisions passed the event selection (for Event Splitting) + hImpactParamReco = qaRegistry.add("QAEvent/McColAll/hImpactParamReco", "Impact parameter of generated MC events with at least one rec. evt; Impact Parameter (b); Counts", HistType::kTH1D, {impactParamAxis}); + hRecoCentrality = qaRegistry.add("QAEvent/McColAll/hRecoCentrality", "Centrality distribution of reconstructed MC events passed the event selection; Centrality (FT0C %); Counts", HistType::kTH1D, {centFT0CAxis}); + hRecoCentralityColvsMultiplicityRecoEta08 = qaRegistry.add("QAEvent/McColAll/hRecoCentralityColvsMultiplicityRecoEta08", "Correlation between FT0C centrality and charged particle multiplicity in reconstructed MC events passed the event selection; Multiplicity #eta <0.8; Counts", HistType::kTH2D, {centFT0CAxis, multAxis}); + hRecoCentralityColvsImpactParamReco = qaRegistry.add("QAEvent/McColAll/hRecoCentralityColvsImpactParamReco", "Correlation between FT0C centrality and impact parameter in reconstructed MC events passed the event selection; Impact Parameter (b); Counts", HistType::kTH2D, {centFT0CAxis, impactParamAxis}); + hRecoCentralityColvsFT0Cmultiplicity = qaRegistry.add("QAEvent/McColAll/hRecoCentralityColvsFT0Cmultiplicity", "Correlation between FT0C centrality and FT0C multiplicity in reconstructed MC events passed the event selection; FT0C (%); FT0c multiplicity", HistType::kTH2D, {centFT0CAxis, binsFT0CMultAxis}); + // Information of generated Lnn in generated events + hGenLnnBeforeEvtSel = qaRegistry.add("QAEvent/McColLnn/hGenLnnBeforeEvtSel", "Lnn generated #it{p}_{T} distribution in all gen evt;#it{p}_{T} (GeV/#it{c}); Counts", HistType::kTH1D, {ptAxis}); + hGenLnnvsImpactParameterBeforeEvtSel = qaRegistry.add("QAEvent/McColLnn/hGenLnnvsImpactParameterBeforeEvtSel", "Correlation Lnn generated #it{p}_{T} and impact parameter in all gen evt;#it{p}_{T} (GeV/#it{c}); Impact parameter (b)", HistType::kTH2D, {ptAxis, impactParamAxis}); + hGenLnnvsMultiplicityGenEta08BeforeEvtSel = qaRegistry.add("QAEvent/McColLnn/hGenLnnvsMultiplicityGenEta08BeforeEvtSel", "Correlation Lnn generated #it{p}_{T} and charged particle multiplicity in all gen evt;#it{p}_{T} (GeV/#it{c}); Multiplicity #eta <0.8", HistType::kTH2D, {ptAxis, multAxis}); + hGenLnnvsMultiplicityFT0CBeforeEvtSel = qaRegistry.add("QAEvent/McColLnn/hGenLnnvsMultiplicityFT0CBeforeEvtSel", "Correlation Lnn generated #it{p}_{T} and FT0C multiplicity in all gen evt;#it{p}_{T} (GeV/#it{c}); FT0C Multiplicity", HistType::kTH2D, {ptAxis, binsFT0CMultAxis}); + // Information of generated Lnn in generated events with at least one rec. event and passed the event selection + hGenLnnAfterSel = qaRegistry.add("QAEvent/McColLnn/hGenLnnAfterSel", "Lnn generated #it{p}_{T} distribution in gen. evts with at least one rec. evt; #it{p}_{T} (GeV/#it{c}); Counts", HistType::kTH1D, {ptAxis}); + hGenLnnvsImpactParameterAfterSel = qaRegistry.add("QAEvent/McColLnn/hGenLnnvsImpactParameterAfterSel", "Correlation Lnn generated #it{p}_{T} and impact parameter in gen. evts with at least one rec. evt;#it{p}_{T} (GeV/#it{c}); Impact parameter (b)", HistType::kTH2D, {ptAxis, impactParamAxis}); + hGenLnnvsMultiplicityGenEta08AfterSel = qaRegistry.add("QAEvent/McColLnn/hGenLnnvsMultiplicityGenEta08AfterSel", "Correlation Lnn generated #it{p}_{T} and charged particle multiplicity in gen. evts with at least one rec. evt;#it{p}_{T} (GeV/#it{c}); Multiplicity #eta <0.8", HistType::kTH2D, {ptAxis, multAxis}); + hGenLnnvsMultiplicityFT0CAfterSel = qaRegistry.add("QAEvent/McColLnn/hGenLnnvsMultiplicityFT0CAfterSel", "Correlation Lnn generated #it{p}_{T} and FT0C multiplicity in gen. evts with at least one rec;#it{p}_{T} (GeV/#it{c}); FT0C Multiplicity", HistType::kTH2D, {ptAxis, binsFT0CMultAxis}); + } } // group BCs @@ -398,37 +483,37 @@ struct lnnRecoTask { if (mRunNumber == bc.runNumber()) { return; } - auto run3grp_timestamp = bc.timestamp(); + auto run3grptimestamp = bc.timestamp(); static const double kBzAutoThreshold = -990.; - o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, run3grp_timestamp); + o2::parameters::GRPObject* grpo = ccdb->getForTimeStamp(grpPath, run3grptimestamp); o2::parameters::GRPMagField* grpmag = 0x0; if (grpo) { o2::base::Propagator::initFieldFromGRP(grpo); if (dBzInput < kBzAutoThreshold) { // Fetch magnetic field from ccdb for current collision - d_bz = grpo->getNominalL3Field(); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + dBz = grpo->getNominalL3Field(); + LOG(info) << "Retrieved GRP for timestamp " << run3grptimestamp << " with magnetic field of " << dBz << " kZG"; } else { - d_bz = dBzInput; + dBz = dBzInput; } } else { - grpmag = ccdb->getForTimeStamp(grpmagPath, run3grp_timestamp); + grpmag = ccdb->getForTimeStamp(grpmagPath, run3grptimestamp); if (!grpmag) { - LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp; + LOG(fatal) << "Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grptimestamp; } o2::base::Propagator::initFieldFromGRP(grpmag); if (dBzInput < kBzAutoThreshold) { // Fetch magnetic field from ccdb for current collision - d_bz = std::lround(5.f * grpmag->getL3Current() / 30000.f); - LOG(info) << "Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG"; + dBz = std::lround(5.f * grpmag->getL3Current() / 30000.f); + LOG(info) << "Retrieved GRP for timestamp " << run3grptimestamp << " with magnetic field of " << dBz << " kZG"; } else { - d_bz = dBzInput; + dBz = dBzInput; } } if (!pidPath.value.empty()) { - auto h3pid = ccdb->getForTimeStamp>(pidPath.value + "_3H", run3grp_timestamp); + auto h3pid = ccdb->getForTimeStamp>(pidPath.value + "_3H", run3grptimestamp); std::copy(h3pid->begin(), h3pid->end(), mBBparams3H.begin()); } else { int kNBetheBlochParams = 5; @@ -438,7 +523,7 @@ struct lnnRecoTask { } mBBparams3H[kResolutionIndex] = cfgBetheBlochParams->get("3H", "resolution"); } - fitter.setBz(d_bz); + fitter.setBz(dBz); mRunNumber = bc.runNumber(); } @@ -502,15 +587,16 @@ struct lnnRecoTask { auto& h3Rigidity = lnnCand.isMatter ? posRigidity : negRigidity; auto& piRigidity = lnnCand.isMatter ? negRigidity : posRigidity; - // fill QA track histogram studies to check track signal before selections - h2FT0CnClusTPCtoTrBfSel->Fill(collision.centFT0C(), h3track.tpcNClsFound()); - h2FT0CnClusTPCtoPiBfSel->Fill(collision.centFT0C(), pitrack.tpcNClsFound()); - h2FT0CnTPCNClsCrossedRows3HBfSel->Fill(collision.centFT0C(), h3track.tpcNClsCrossedRows()); - h2FT0CnTPCNClsCrossedRowsPiBfSel->Fill(collision.centFT0C(), pitrack.tpcNClsCrossedRows()); - h2FT0Cchi2NClTPCtoTrBfSel->Fill(collision.centFT0C(), h3track.tpcChi2NCl()); - h2FT0Cchi2NClITStoTrBfSel->Fill(collision.centFT0C(), h3track.itsChi2NCl()); - if (doTrackQA) { + // fill QA track histogram studies to check track signal before selections + + h2FT0CnClusTPCtoTrBfSel->Fill(collision.centFT0C(), h3track.tpcNClsFound()); + h2FT0CnClusTPCtoPiBfSel->Fill(collision.centFT0C(), pitrack.tpcNClsFound()); + h2FT0CnTPCNClsCrossedRows3HBfSel->Fill(collision.centFT0C(), h3track.tpcNClsCrossedRows()); + h2FT0CnTPCNClsCrossedRowsPiBfSel->Fill(collision.centFT0C(), pitrack.tpcNClsCrossedRows()); + h2FT0Cchi2NClTPCtoTrBfSel->Fill(collision.centFT0C(), h3track.tpcChi2NCl()); + h2FT0Cchi2NClITStoTrBfSel->Fill(collision.centFT0C(), h3track.itsChi2NCl()); + bool passedTrTrackITS = h3track.hasITS(); bool passedTrTrackTOF = h3track.hasTOF(); bool passedPiTrackITS = pitrack.hasITS(); @@ -526,11 +612,13 @@ struct lnnRecoTask { } if (h3Rigidity < tpcRigidityMin3H || - h3track.tpcNClsCrossedRows() < nTPCNClsCrossedRows3H || h3track.tpcChi2NCl() < chi2nClusTPCMin || h3track.tpcChi2NCl() > chi2nClusTPCMax || h3track.itsChi2NCl() > chi2nClusITS || - pitrack.tpcNClsCrossedRows() < nTPCNClsCrossedRowsPi) { + h3track.tpcNClsCrossedRows() < nTPCNClsCrossedRows3H || + pitrack.tpcNClsCrossedRows() < nTPCNClsCrossedRowsPi || + h3track.tpcNClsFound() < nTPCClusMin3H || + pitrack.tpcNClsFound() < nTPCClusMinPi) { continue; } @@ -610,10 +698,10 @@ struct lnnRecoTask { continue; } // Definition of lnn mass - float mLNN_HypHI = 3.00; // , but 2993.7 MeV/c**2 + float mLnnHypHi = 3.00; // , but 2993.7 MeV/c**2 float massLNNL = std::sqrt(h3lE * h3lE - lnnMom[0] * lnnMom[0] - lnnMom[1] * lnnMom[1] - lnnMom[2] * lnnMom[2]); bool isLNNMass = false; - if (massLNNL > mLNN_HypHI - masswidth && massLNNL < mLNN_HypHI + masswidth) { + if (massLNNL > mLnnHypHi - masswidth && massLNNL < mLnnHypHi + masswidth) { isLNNMass = true; } if (!isLNNMass) { @@ -658,14 +746,17 @@ struct lnnRecoTask { // Fill 2D map after all selections hdEdx3HSel->Fill(chargeFactor * lnnCand.mom3HTPC, h3track.tpcSignal()); - hdEdx3HPosTrack->Fill(lnnCand.mom3HTPC, h3track.tpcSignal()); - if (!lnnCand.isMatter) { + if (lnnCand.isMatter) { + hdEdx3HPosTrack->Fill(lnnCand.mom3HTPC, h3track.tpcSignal()); + } else { hdEdx3HNegTrack->Fill(-lnnCand.mom3HTPC, h3track.tpcSignal()); } + hNsigma3HSel->Fill(chargeFactor * lnnCand.mom3HTPC, lnnCand.nSigma3H); if (h3track.hasTOF()) { h3HSignalPtTOF->Fill(chargeFactor * h3track.pt(), beta); - hNsigma3HSelTOF->Fill(chargeFactor * h3track.p(), h3track.tofNSigmaTr()); + hNsigma3HSelTOF->Fill(chargeFactor * h3track.pt(), h3track.tofNSigmaTr()); + h2Nsigma3HSelTPCTOF->Fill(lnnCand.nSigma3H, h3track.tofNSigmaTr()); h3HMassPtTOF->Fill(chargeFactor * h3track.pt(), lnnCand.mass2TrTOF); } } @@ -674,7 +765,8 @@ struct lnnRecoTask { // Monte Carlo information void fillMCinfo(aod::McTrackLabels const& trackLabels, aod::McParticles const&) { - for (auto& lnnCand : lnnCandidates) { + for (size_t iCand = 0; iCand < lnnCandidates.size(); ++iCand) { + auto& lnnCand = lnnCandidates[iCand]; auto mcLabPos = trackLabels.rawIteratorAt(lnnCand.posTrackID); auto mcLabNeg = trackLabels.rawIteratorAt(lnnCand.negTrackID); @@ -705,8 +797,6 @@ struct lnnRecoTask { lnnCand.gMom3H = isTrTrack ? mcTrackPos.pVector() : mcTrackNeg.pVector(); - lnnCand.gMomPi = isTrTrack ? mcTrackNeg.pVector() : mcTrackPos.pVector(); - int kNDimGen = 3; for (int i = 0; i < kNDimGen; i++) { lnnCand.gDecVtx[i] = secVtx[i] - posPrimVtx[i]; @@ -744,36 +834,47 @@ struct lnnRecoTask { return motherIsAccepted; } + // Generated MC particles template - void fillMcHistograms(TracksFullMC::iterator const& mcTrack, aod::McParticles::iterator const& mc, Tcoll const& collision) + void fillGeneratedMcHistograms(aod::McParticles::iterator const& mc, Tcoll const& collision) { + const int pdg = std::abs(mc.pdgCode()); + int chargeFactor = -1 + 2 * (mc.pdgCode() > 0); + if (pdg == lnnPdg) { + hPtGeneratedLnnStr->Fill(collision.centFT0C(), chargeFactor * mc.pt()); + } + if (pdg == h3DauPdg) { + if (isLnnDecay(mc)) { + hPtGeneratedTrStr->Fill(collision.centFT0C(), chargeFactor * mc.pt()); + } + } + } + // Reconstructed tracks associated to MC generated particles + template + void fillMcHistograms(TracksFullMC::iterator const& mcTrack, aod::McParticles::iterator const& mc, Tcoll const& collision) + { bool passedTrackITS = mcTrack.hasITS(); bool passedTrackTPC = mcTrack.hasTPC(); bool passedTrackTOF = mcTrack.hasTOF(); int pdg = std::abs(mc.pdgCode()); - + int chargeFactor = -1 + 2 * (mc.pdgCode() > 0); + int chargeTrackFactor = mcTrack.sign(); if (pdg == h3DauPdg) { - hPtGeneratedTrStr->Fill(collision.centFT0C(), mc.pt()); - - if (passedTrackITS && passedTrackTPC) { - hPtItsTpcTrStr->Fill(collision.centFT0C(), mc.pt()); - hPtTrkItsTpcTrStr->Fill(collision.centFT0C(), mcTrack.pt()); - if (passedTrackTOF) { - hPtItsTpcTofTrStr->Fill(collision.centFT0C(), mc.pt()); - hPtTrkItsTpcTofTrStr->Fill(collision.centFT0C(), mcTrack.pt()); + if (passedTrackITS) { + hPtTpcTrStr->Fill(collision.centFT0C(), chargeFactor * mc.pt()); + hPtTrkTpcTrStr->Fill(collision.centFT0C(), chargeTrackFactor * mcTrack.pt()); + if (passedTrackTPC) { + hPtItsTpcTrStr->Fill(collision.centFT0C(), chargeFactor * mc.pt()); + hPtTrkItsTpcTrStr->Fill(collision.centFT0C(), chargeTrackFactor * mcTrack.pt()); + if (passedTrackTOF) { + hPtItsTpcTofTrStr->Fill(collision.centFT0C(), chargeFactor * mc.pt()); + hPtTrkItsTpcTofTrStr->Fill(collision.centFT0C(), chargeTrackFactor * mcTrack.pt()); + } } } } - - if (pdg == piDauPdg) { - hPtGeneratedPiStr->Fill(collision.centFT0C(), mc.pt()); - if (passedTrackITS && passedTrackTPC) { - hPtItsTpcPiStr->Fill(collision.centFT0C(), mc.pt()); - hPtTrkItsTpcPiStr->Fill(collision.centFT0C(), mcTrack.pt()); - } - } } void processData(CollisionsFull const& collisions, aod::V0s const& V0s, TracksFull const& tracks, aod::BCsWithTimestamps const&) @@ -798,6 +899,8 @@ struct lnnRecoTask { } hEvents->Fill(KevPileupCut); + h2GlobalTrackMultVsCent->Fill(collision.centFT0C(), collision.multNTracksGlobal()); + hZvtx->Fill(collision.posZ()); hCentFT0A->Fill(collision.centFT0A()); hCentFT0C->Fill(collision.centFT0C()); @@ -805,10 +908,10 @@ struct lnnRecoTask { hCentFV0A->Fill(collision.centFV0A()); const uint64_t collIdx = collision.globalIndex(); - auto v0Table_thisCollision = V0s.sliceBy(perCollision, collIdx); - v0Table_thisCollision.bindExternalIndices(&tracks); + auto v0TablethisCollision = V0s.sliceBy(perCollision, collIdx); + v0TablethisCollision.bindExternalIndices(&tracks); - fillCandidateData(collision, v0Table_thisCollision); + fillCandidateData(collision, v0TablethisCollision); for (const auto& lnnCand : lnnCandidates) { outputDataTable(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), @@ -825,32 +928,21 @@ struct lnnRecoTask { } } } - PROCESS_SWITCH(lnnRecoTask, processData, "Data analysis", true); + PROCESS_SWITCH(LnnRecoTask, processData, "Data analysis", true); // MC process void processMC(CollisionsFullMC const& collisions, aod::McCollisions const& mcCollisions, aod::V0s const& V0s, aod::BCsWithTimestamps const&, TracksFull const& tracks, TracksFullMC const& tracksMC, aod::McTrackLabels const& trackLabelsMC, aod::McParticles const& particlesMC) { filledMothers.clear(); isGoodCollision.clear(); - isGoodCollision.resize(mcCollisions.size(), false); collisionFT0Ccent.clear(); - collisionFT0Ccent.resize(mcCollisions.size(), -1.f); recoCollisionIds.clear(); + + isGoodCollision.resize(mcCollisions.size(), false); + collisionFT0Ccent.resize(mcCollisions.size(), -1.f); recoCollisionIds.resize(mcCollisions.size(), -1); for (const auto& collision : collisions) { - for (auto const& trackMC : tracksMC) { - - if (!trackMC.has_mcParticle()) - continue; - - auto mc = trackMC.mcParticle(); - - if (!isLnnDecay(mc)) - continue; - - fillMcHistograms(trackMC, mc, collision); - } lnnCandidates.clear(); auto bc = collision.bc_as(); @@ -874,6 +966,8 @@ struct lnnRecoTask { } hEvents->Fill(KevPileupCut); + h2GlobalTrackMultVsCent->Fill(collision.centFT0C(), collision.multNTracksGlobal()); + hZvtx->Fill(collision.posZ()); hCentFT0A->Fill(collision.centFT0A()); hCentFT0C->Fill(collision.centFT0C()); @@ -886,12 +980,33 @@ struct lnnRecoTask { } const uint64_t collIdx = collision.globalIndex(); - auto v0Table_thisCollision = V0s.sliceBy(perCollision, collIdx); - v0Table_thisCollision.bindExternalIndices(&tracks); + auto v0TablethisCollision = V0s.sliceBy(perCollision, collIdx); + v0TablethisCollision.bindExternalIndices(&tracks); - fillCandidateData(collision, v0Table_thisCollision); + fillCandidateData(collision, v0TablethisCollision); fillMCinfo(trackLabelsMC, particlesMC); + // Fill MC gen. particles producing to the current MC collision + const auto mcCollId = collision.mcCollisionId(); + auto particlesThisMcCollision = particlesMC.sliceBy(mcParticlesPerMcCollision, mcCollId); + for (const auto& mc : particlesThisMcCollision) { + fillGeneratedMcHistograms(mc, collision); + } + + // Fill only tracks producing to the current reconstructed collision + auto tracksThisCollision = tracksMC.sliceBy(tracksPerCollision, collIdx); + for (const auto& trackMC : tracksThisCollision) { + if (!trackMC.has_mcParticle()) { + continue; + } + auto mc = trackMC.mcParticle(); + // Select only daughters from the Λnn decay + if (!isLnnDecay(mc)) { + continue; + } + fillMcHistograms(trackMC, mc, collision); + } + for (const auto& lnnCand : lnnCandidates) { if (!lnnCand.isSignal && mcSignalOnly) { continue; @@ -900,7 +1015,6 @@ struct lnnRecoTask { if (lnnCand.recoMcColl && lnnCand.survEvSelection) { h2FT0CPtGenColRecCandMC->Fill(collision.centFT0C(), chargeFactor * lnnCand.genPt()); h2FT0CPtGenColRecTrStrMC->Fill(collision.centFT0C(), chargeFactor * lnnCand.genPt3H()); - h2FT0CPtGenColRecPiStrMC->Fill(collision.centFT0C(), chargeFactor * lnnCand.genPtPi()); } outputMCTable(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), collision.posX(), collision.posY(), collision.posZ(), @@ -926,17 +1040,19 @@ struct lnnRecoTask { } float cent = collisionFT0Ccent[mcPart.mcCollisionId()]; - h2FT0CPtGenColGenCandMC->Fill(cent, mcPart.pt()); + int chargeFactorGen = mcPart.pdgCode() > 0 ? 1 : -1; + + h2FT0CPtGenColGenCandMC->Fill(cent, chargeFactorGen * mcPart.pt()); constexpr std::size_t KVtxDim = 3; std::array secVtx; std::array primVtx = {mcPart.vx(), mcPart.vy(), mcPart.vz()}; - constexpr std::size_t kArrayDim = 3; - std::array momMother = mcPart.pVector(); + constexpr std::size_t KArrayDim = 3; + std::array momMother = mcPart.pVector(); + + std::array mom3H; - std::array mom3H; - std::array momPi; bool is3HFound = false; for (const auto& mcDaught : mcPart.daughters_as()) { @@ -945,13 +1061,13 @@ struct lnnRecoTask { if (pdg == h3DauPdg) { secVtx = {mcDaught.vx(), mcDaught.vy(), mcDaught.vz()}; mom3H = mcDaught.pVector(); - h2FT0CPtGenColGenTrStrMC->Fill(cent, mcDaught.pt()); + h2FT0CPtGenColGenTrStrMC->Fill(cent, chargeFactorGen * mcDaught.pt()); is3HFound = true; break; } - if (pdg == piDauPdg) { - momPi = mcDaught.pVector(); - h2FT0CPtGenColGenPiStrMC->Fill(cent, mcDaught.pt()); + + if (is3HFound) { + break; } } @@ -973,6 +1089,7 @@ struct lnnRecoTask { LnnCandidate lnnCand; lnnCand.pdgCode = mcPart.pdgCode(); lnnCand.survEvSelection = isGoodCollision[mcPart.mcCollisionId()]; + int chargeFactor = -1 + 2 * (lnnCand.pdgCode > 0); int kDimGen = 3; @@ -980,7 +1097,6 @@ struct lnnRecoTask { lnnCand.gDecVtx[i] = secVtx[i] - primVtx[i]; lnnCand.gMom[i] = momMother[i]; lnnCand.gMom3H[i] = mom3H[i]; - lnnCand.gMomPi[i] = momPi[i]; } lnnCand.posTrackID = -1; @@ -1007,12 +1123,133 @@ struct lnnRecoTask { lnnCand.gDecVtx[0], lnnCand.gDecVtx[1], lnnCand.gDecVtx[2], lnnCand.isReco, lnnCand.isSignal, lnnCand.recoMcColl, lnnCand.survEvSelection); } } - PROCESS_SWITCH(lnnRecoTask, processMC, "MC analysis", false); + PROCESS_SWITCH(LnnRecoTask, processMC, "MC analysis", false); + + template + bool passEvtSel(const CollType& collision) + { + if (!collision.sel8()) + return false; + + if ((std::abs(collision.posZ())) > vtxZCut) + return false; + + if (useNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) + return false; + + return true; + } + + void processSigEvtLossMC(McCollisionMults::iterator const& mcCollision, soa::SmallGroups const& collisions, aod::McParticles const& GenParticles) + { + if (std::abs(mcCollision.posZ()) > vtxZCut) { + return; + } + //////////// Event loss estimation via impact parameter and multiplicity by FT0C + + // Fill all generated events + hEvtMC->Fill(0); + hImpactParamGen->Fill(mcCollision.impactParameter()); + hGenEventsNchEta08->Fill(mcCollision.multMCNParticlesEta08(), 0); + + // Fill generated events with no reconstructed collisions + if (collisions.size() == 0) { + hEvtMC->Fill(1); + } + + // Define the generated events with at least one reconstructed event + bool atLeastOneRecoEvt = false; + auto centralityFT0C = -999.; + int biggestNContribs = -1; + + for (auto const& col : collisions) { + if (!passEvtSel(col)) { + continue; + } + // In case of multiple reconstructed collisions associated to the same generated one, only consider the one with the biggest number of contributors + if (biggestNContribs < col.numContrib()) { + biggestNContribs = col.numContrib(); + centralityFT0C = col.centFT0C(); + } + atLeastOneRecoEvt = true; + hImpactParamReco->Fill(mcCollision.impactParameter()); + hRecoCentrality->Fill(col.centFT0C()); + hRecoCentralityColvsMultiplicityRecoEta08->Fill(col.centFT0C(), mcCollision.multMCNParticlesEta08()); + hRecoCentralityColvsImpactParamReco->Fill(col.centFT0C(), mcCollision.impactParameter()); + hRecoCentralityColvsFT0Cmultiplicity->Fill(col.centFT0C(), mcCollision.multMCFT0C()); + } + + if (atLeastOneRecoEvt) { + hEvtMC->Fill(2); + hGenEventsNchEta08->Fill(mcCollision.multMCNParticlesEta08(), 1); + hImpactParamGenOneReco->Fill(mcCollision.impactParameter()); + hGenOneRecoCentrality->Fill(centralityFT0C); + hGenCentralityColvsMultiplicityGenEta08->Fill(centralityFT0C, mcCollision.multMCNParticlesEta08()); + hGenCentralityColvsImpactParamGen->Fill(centralityFT0C, mcCollision.impactParameter()); + hGenCentralityColvsFT0Cmultiplicity->Fill(centralityFT0C, mcCollision.multMCFT0C()); + } + // Construct the H3L 4-vector based on the generated daugthers identification by PDG + ROOT::Math::PxPyPzMVector daugh1, daugh2, mother; + + for (const auto& genParticle : GenParticles) { + if (std::abs(genParticle.y()) > 1) + continue; + if (std::abs(genParticle.pdgCode()) != lnnPdg) + continue; + + auto daughters = genParticle.daughters_as(); + + bool dauTr = false; + bool dauPi = false; + + int trSign = 0; + int piSign = 0; + + for (const auto& daughter : daughters) { + + if (std::abs(daughter.pdgCode()) == h3DauPdg) { + + dauTr = true; + trSign = daughter.pdgCode() > 0 ? 1 : -1; + + daugh1 = ROOT::Math::PxPyPzMVector(daughter.px(), daughter.py(), daughter.pz(), h3Mass); + + } else if (std::abs(daughter.pdgCode()) == piDauPdg) { + + dauPi = true; + piSign = daughter.pdgCode() > 0 ? 1 : -1; + + daugh2 = ROOT::Math::PxPyPzMVector(daughter.px(), daughter.py(), daughter.pz(), piMass); + } + } + + if (!dauTr || !dauPi || (trSign * piSign) > 0) { + continue; + } + + mother = daugh1 + daugh2; + + // Fill informations for generated 3HL in all generated events + hGenLnnBeforeEvtSel->Fill(mother.pt()); + hGenLnnvsImpactParameterBeforeEvtSel->Fill(mother.pt(), mcCollision.impactParameter()); + hGenLnnvsMultiplicityGenEta08BeforeEvtSel->Fill(mother.pt(), mcCollision.multMCNParticlesEta08()); + hGenLnnvsMultiplicityFT0CBeforeEvtSel->Fill(mother.pt(), mcCollision.multMCFT0C()); + + // Fill informations for generated 3HL in generated events with at least one reconstructed event + if (atLeastOneRecoEvt) { + hGenLnnAfterSel->Fill(mother.pt()); + hGenLnnvsImpactParameterAfterSel->Fill(mother.pt(), mcCollision.impactParameter()); + hGenLnnvsMultiplicityGenEta08AfterSel->Fill(mother.pt(), mcCollision.multMCNParticlesEta08()); + hGenLnnvsMultiplicityFT0CAfterSel->Fill(mother.pt(), mcCollision.multMCFT0C()); + } + } + } + PROCESS_SWITCH(LnnRecoTask, processSigEvtLossMC, "Signal and event loss analysis", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/TableProducer/Nuspex/nucleiAntineutronCex.cxx b/PWGLF/TableProducer/Nuspex/nucleiAntineutronCex.cxx index 1eaa90857ee..cdbaf517726 100644 --- a/PWGLF/TableProducer/Nuspex/nucleiAntineutronCex.cxx +++ b/PWGLF/TableProducer/Nuspex/nucleiAntineutronCex.cxx @@ -82,6 +82,11 @@ struct NucleiAntineutronCex { histos.add("antin_eta", "Pseudorapidity;#eta;Entries", kTH1F, {{100, -10., 10.}}); histos.add("antin_p_ITScuts", "Momentum with ITS cuts;|p| (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("antin_pt", "Antineutron transverse momentum;p_{T,#bar{n}} (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("antin_pt_ITScuts", "Antineutron transverse momentum with ITS cuts;p_{T,#bar{n}} (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("antin_pt_closureA", "Generated antineutron p_{T}, closure sample A;p_{T,#bar{n}} (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("antin_pt_closureB", "Generated antineutron p_{T}, closure sample B;p_{T,#bar{n}} (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + // Primary neutrons histos.add("n_p", "Total momentum;|p| (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); histos.add("n_px", "p_{x};p_{x} (GeV/c);Entries", kTH1F, {{100, -10., 10.}}); @@ -120,6 +125,11 @@ struct NucleiAntineutronCex { histos.add("cex_pairmc_vtxz", "MC secondary vertex Z;Z (cm);Entries", kTH1F, {{200, -60., 60.}}); histos.add("cexPairMcPITScuts", "CEX pair momentum (ITS cuts);|p| (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("cexMotherMcP", "Antineutron momentum for true CEX;p_{#bar{n}} (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("cexMotherMcPt", "Antineutron transverse momentum for true CEX;p_{T,#bar{n}} (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("cexMotherMcPt_closureA", "Antineutron p_{T} for true CEX, closure sample A;p_{T,#bar{n}} (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("cexMotherMcPt_closureB", "Antineutron p_{T} for true CEX, closure sample B;p_{T,#bar{n}} (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + // CEX pair normalized to antineutron (MC) histos.add("cexn_pairmc_p", "Pair p / antineutron p;p/p_{#bar{n}};Entries", kTH1F, {{100, 0., 2.}}); histos.add("cexn_pairmc_pt", "Pair p_{T} / antineutron p_{T};p_{T}/p_{T,#bar{n}};Entries", kTH1F, {{100, 0., 2.}}); @@ -137,6 +147,16 @@ struct NucleiAntineutronCex { // Pi0 events histos.add("cexn_pairmc_p_pi0", "Pair p / antineutron p for CEX + #pi^{0};p/p_{#bar{n}};Entries", kTH1F, {{100, 0., 2.}}); + histos.add("cexn_pairmc_pt_pi0", "Pair p_{T} / antineutron p_{T} for CEX + #pi^{0};p_{T}/p_{T,#bar{n}};Entries", kTH1F, {{100, 0., 2.}}); + + histos.add("cexn_pairmc_p_noPi0", "Pair p / antineutron p for two-body CEX;p/p_{#bar{n}};Entries", kTH1F, {{100, 0., 2.}}); + histos.add("cexn_pairmc_pt_noPi0", "Pair p_{T} / antineutron p_{T} for two-body CEX;p_{T}/p_{T,#bar{n}};Entries", kTH1F, {{100, 0., 2.}}); + + histos.add("cexn_pairtrk_p_pi0", "Reconstructed pair p / antineutron p for CEX + #pi^{0};p_{p#bar{p}}^{reco}/p_{#bar{n}};Entries", kTH1F, {{100, 0., 2.}}); + histos.add("cexn_pairtrk_pt_pi0", "Reconstructed pair p_{T} / antineutron p_{T} for CEX + #pi^{0};p_{T,p#bar{p}}^{reco}/p_{T,#bar{n}};Entries", kTH1F, {{100, 0., 2.}}); + + histos.add("cexn_pairtrk_p_noPi0", "Reconstructed pair p / antineutron p for two-body CEX;p_{p#bar{p}}^{reco}/p_{#bar{n}};Entries", kTH1F, {{100, 0., 2.}}); + histos.add("cexn_pairtrk_pt_noPi0", "Reconstructed pair p_{T} / antineutron p_{T} for two-body CEX;p_{T,p#bar{p}}^{reco}/p_{T,#bar{n}};Entries", kTH1F, {{100, 0., 2.}}); // CEX pair from antineutron (TRK) histos.add("cex_pairtrk_angle", "Pair opening angle (tracks);Angle (°);Entries", kTH1F, {{180, 0., 180.}}); @@ -148,6 +168,17 @@ struct NucleiAntineutronCex { histos.add("cex_pairtrkVtxfitDistToPv", "Distance from secondary vertex to PV;dist (cm);Entries", kTH1F, {{240, 0., 120.}}); histos.add("cex_pairtrk_vtxfit_secVtxXY", "Secondary vertex (PCA);X (cm);Y (cm)", kTH2F, {{200, -60., 60.}, {200, -60., 60.}}); histos.add("cex_pairtrk_vtxfit_secVtxZ", "Secondary vertex Z (PCA);Z (cm);Entries", kTH1F, {{240, -60., 60.}}); + histos.add("cexMotherTrkP", "Antineutron momentum for reconstructed CEX;p_{#bar{n}} (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("cexMotherTrkPt", "Antineutron transverse momentum for reconstructed CEX;p_{T,#bar{n}} (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("cexMotherTrkPt_closureA", "Antineutron p_{T} for reconstructed CEX, closure sample A;p_{T,#bar{n}} (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("cexMotherTrkPt_closureB", "Antineutron p_{T} for reconstructed CEX, closure sample B;p_{T,#bar{n}} (GeV/c);Entries", kTH1F, {{100, 0., 10.}}); + histos.add("cexResponseP", "CEX momentum response;p_{#bar{n}}^{MC} (GeV/c);p_{p#bar{p}}^{reco} (GeV/c)", kTH2F, {{100, 0., 10.}, {100, 0., 10.}}); + histos.add("cexResponsePt", "CEX transverse-momentum response;p_{T,#bar{n}}^{MC} (GeV/c);p_{T,p#bar{p}}^{reco} (GeV/c)", kTH2F, {{100, 0., 10.}, {100, 0., 10.}}); + + // CEX reconstructed pair normalized to antineutron + histos.add("cexn_pairtrk_p", "Reconstructed pair p / antineutron p;p_{p#bar{p}}^{reco}/p_{#bar{n}};Entries", kTH1F, {{100, 0., 2.}}); + histos.add("cexn_pairtrk_pt", "Reconstructed pair p_{T} / antineutron p_{T};p_{T,p#bar{p}}^{reco}/p_{T,#bar{n}};Entries", kTH1F, {{100, 0., 2.}}); + histos.add("cexn_pairtrk_pz", "Reconstructed pair p_{z} / antineutron p_{z};p_{z,p#bar{p}}^{reco}/p_{z,#bar{n}};Entries", kTH1F, {{100, -2., 2.}}); // BG pair (not from antineutron) (TRK) histos.add("cexbg_pairtrk_angle", "Background opening angle (tracks);Angle (°);Entries", kTH1F, {{180, 0., 180.}}); @@ -209,6 +240,8 @@ struct NucleiAntineutronCex { double pvtxZ = 0; for (auto const& col : cols) { const auto colId = col.globalIndex(); + const bool isSampleA = (colId % 2 == 0); + auto mcPartsThis = particles.sliceBy(perMcByColl, colId); if (std::isfinite(col.posX()) && std::isfinite(col.posY()) && std::isfinite(col.posZ())) { @@ -225,12 +258,20 @@ struct NucleiAntineutronCex { // Primary antineutrons if (particle.pdgCode() == -kNeutron && particle.isPhysicalPrimary()) { histos.fill(HIST("antin_p"), particle.p()); + histos.fill(HIST("antin_pt"), particle.pt()); histos.fill(HIST("antin_px"), particle.px()); histos.fill(HIST("antin_py"), particle.py()); histos.fill(HIST("antin_pz"), particle.pz()); histos.fill(HIST("antin_eta"), particle.eta()); - if (std::abs(particle.eta()) < kAccMaxEta && std::abs(particle.vz()) < kAccMaxVz) + if (std::abs(particle.eta()) < kAccMaxEta && std::abs(particle.vz()) < kAccMaxVz) { histos.fill(HIST("antin_p_ITScuts"), particle.p()); + histos.fill(HIST("antin_pt_ITScuts"), particle.pt()); + } + if (isSampleA) { + histos.fill(HIST("antin_pt_closureA"), particle.pt()); + } else { + histos.fill(HIST("antin_pt_closureB"), particle.pt()); + } } // Primary neutrons if (particle.pdgCode() == kNeutron && particle.isPhysicalPrimary()) { @@ -509,6 +550,13 @@ struct NucleiAntineutronCex { histos.fill(HIST("cex_pairmc_angle"), mcangleDeg); histos.fill(HIST("cex_pairmc_vtx"), antipVx, antipVy); histos.fill(HIST("cex_pairmc_vtxz"), antipVz); + histos.fill(HIST("cexMotherMcP"), motherP); + histos.fill(HIST("cexMotherMcPt"), motherPt); + if (isSampleA) { + histos.fill(HIST("cexMotherMcPt_closureA"), motherPt); + } else { + histos.fill(HIST("cexMotherMcPt_closureB"), motherPt); + } if (std::abs(motherEta) < kStrictEta && std::abs(motherVz) < kAccMaxVz) histos.fill(HIST("cexPairMcPITScuts"), cexPairMcP); // CEX pair normalized @@ -518,8 +566,17 @@ struct NucleiAntineutronCex { histos.fill(HIST("cexn_pairmc_pt"), cexPairMcPt / motherPt); if (motherPz != 0) histos.fill(HIST("cexn_pairmc_pz"), cexPairMcPz / motherPz); - if (motherP != 0 && pion0) - histos.fill(HIST("cexn_pairmc_p_pi0"), cexPairMcP / motherP); + if (pion0) { + if (motherP != 0.) + histos.fill(HIST("cexn_pairmc_p_pi0"), cexPairMcP / motherP); + if (motherPt != 0.) + histos.fill(HIST("cexn_pairmc_pt_pi0"), cexPairMcPt / motherPt); + } else { + if (motherP != 0.) + histos.fill(HIST("cexn_pairmc_p_noPi0"), cexPairMcP / motherP); + if (motherPt != 0.) + histos.fill(HIST("cexn_pairmc_pt_noPi0"), cexPairMcPt / motherPt); + } } // BG mother if (motherPdg != -kNeutron) { @@ -793,6 +850,34 @@ struct NucleiAntineutronCex { histos.fill(HIST("cex_pairtrkVtxfitDistToPv"), distToPrimary); histos.fill(HIST("cex_pairtrk_vtxfit_secVtxXY"), secX, secY); histos.fill(HIST("cex_pairtrk_vtxfit_secVtxZ"), secZ); + histos.fill(HIST("cexMotherTrkP"), motherP); + histos.fill(HIST("cexMotherTrkPt"), motherPt); + // Response matrices + histos.fill(HIST("cexResponseP"), motherP, cexPairTrkP); + histos.fill(HIST("cexResponsePt"), motherPt, cexPairTrkPt); + // Pi0 track + if (pion0) { + if (motherP != 0.) + histos.fill(HIST("cexn_pairtrk_p_pi0"), cexPairTrkP / motherP); + if (motherPt != 0.) + histos.fill(HIST("cexn_pairtrk_pt_pi0"), cexPairTrkPt / motherPt); + } else { + if (motherP != 0.) + histos.fill(HIST("cexn_pairtrk_p_noPi0"), cexPairTrkP / motherP); + if (motherPt != 0.) + histos.fill(HIST("cexn_pairtrk_pt_noPi0"), cexPairTrkPt / motherPt); + } + if (isSampleA) { + histos.fill(HIST("cexMotherTrkPt_closureA"), motherPt); + } else { + histos.fill(HIST("cexMotherTrkPt_closureB"), motherPt); + } + if (motherP != 0.) + histos.fill(HIST("cexn_pairtrk_p"), cexPairTrkP / motherP); + if (motherPt != 0.) + histos.fill(HIST("cexn_pairtrk_pt"), cexPairTrkPt / motherPt); + if (motherPz != 0.) + histos.fill(HIST("cexn_pairtrk_pz"), cexPairTrkPz / motherPz); } else { histos.fill(HIST("cexbg_pairtrk_p"), cexPairTrkP); histos.fill(HIST("cexbg_pairtrk_pt"), cexPairTrkPt); diff --git a/PWGLF/TableProducer/Nuspex/nucleiSpectra.cxx b/PWGLF/TableProducer/Nuspex/nucleiSpectra.cxx index 5358f18b079..67837173150 100644 --- a/PWGLF/TableProducer/Nuspex/nucleiSpectra.cxx +++ b/PWGLF/TableProducer/Nuspex/nucleiSpectra.cxx @@ -394,7 +394,7 @@ struct nucleiSpectra { HistogramRegistry spectra{"spectra", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - double computeAbsoDecL(aod::McParticles::iterator particle) + double computeAbsoDecL(const aod::McParticles::iterator& particle) { if (!particle.has_daughters()) return -1.f; diff --git a/PWGLF/TableProducer/Nuspex/particleCompositionCorrection.cxx b/PWGLF/TableProducer/Nuspex/particleCompositionCorrection.cxx index 20f740f13c9..b2f5e201476 100644 --- a/PWGLF/TableProducer/Nuspex/particleCompositionCorrection.cxx +++ b/PWGLF/TableProducer/Nuspex/particleCompositionCorrection.cxx @@ -70,7 +70,7 @@ struct ParticleCompositionCorrection { Configurable ptMaxCut{"ptMaxCut", 10.f, "pt max cut"}; Configurable enableQAHistos{"enableQAHistos", true, "enable qa histograms showing the effect of the PCC"}; - Configurable ccdbBasePath{"ccdbBasePath", "/Users/m/makruger/", "ccdb directory contianing the particle fraction networks"}; + Configurable ccdbBasePath{"ccdbBasePath", "/Users/m/mcalmonb/", "ccdb directory contianing the particle fraction networks"}; Configurable modelPathData{"modelPathData", "PCC/data/pp", "Path to the .onnx file containing the particle fractions in data"}; Configurable modelPathMC{"modelPathMC", "PCC/pythia/pp", "Path to the .onnx file containing the particle fractions in MC"}; @@ -97,14 +97,16 @@ void ParticleCompositionCorrection::init(InitContext const&) return; } if (!ccdbBasePath.value.empty()) { - ccdbApi.init("http://ccdb-test.cern.ch:8080"); + // ccdbApi.init("http://ccdb-test.cern.ch:8080"); + ccdbApi.init("http://alice-ccdb.cern.ch"); static const int64_t dummyTimeStamp = 2; - if (!ccdbApi.retrieveBlob(ccdbBasePath.value + modelPathData.value, modelPathData.value, {}, dummyTimeStamp, false, "ParticleFractions_Data.onnx") || !ccdbApi.retrieveBlob(ccdbBasePath.value + modelPathMC.value, modelPathMC.value, {}, dummyTimeStamp, false, "ParticleFractions_MC.onnx")) { + if (!ccdbApi.retrieveBlob(ccdbBasePath.value + modelPathData.value, modelPathData.value, {}, dummyTimeStamp, false, "ParticleFractions_data.onnx") || !ccdbApi.retrieveBlob(ccdbBasePath.value + modelPathMC.value, modelPathMC.value, {}, dummyTimeStamp, false, "ParticleFractions_pythia.onnx")) { LOGP(fatal, "Could not download particle fraction networks!"); } } - particleFractionsData.initModel(modelPathData.value + "/ParticleFractions_Data.onnx", true); - particleFractionsMC.initModel(modelPathMC.value + "/ParticleFractions_MC.onnx", true); + + particleFractionsData.initModel(modelPathData.value + "/ParticleFractions_data.onnx", true); + particleFractionsMC.initModel(modelPathMC.value + "/ParticleFractions_pythia.onnx", true); if (enableQAHistos) { std::vector ptBinEdges = {0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, @@ -113,19 +115,37 @@ void ParticleCompositionCorrection::init(InitContext const&) 6.0, 6.5, 7.0, 8.0, 9.0, 10.0}; const AxisSpec ptAxis{ptBinEdges, "#it{p}_{T} (GeV/#it{c})", "pt"}; - histos.add("frac/data/pion", "", kTProfile, {ptAxis}); + const int maxMult = 100; + const int nBinsMult = maxMult + 1; + const AxisSpec multAxis = {nBinsMult, -0.5, nBinsMult - 0.5, "#it{N}_{ch}", "mult"}; + + histos.add("multDist_INELg0", "", kTH1D, {multAxis}); + histos.add("multDist_fid", "", kTH1D, {multAxis}); + histos.add("multDist_fidVsINELg0", "", kTH2D, {multAxis, multAxis}); + histos.add("frac/data/kaon", "", kTProfile, {ptAxis}); histos.add("frac/data/proton", "", kTProfile, {ptAxis}); histos.add("frac/data/sigma", "", kTProfile, {ptAxis}); + + histos.add("frac/data/kaon_mult", "", kTProfile2D, {multAxis, ptAxis}); + histos.add("frac/data/proton_mult", "", kTProfile2D, {multAxis, ptAxis}); + histos.add("frac/data/sigma_mult", "", kTProfile2D, {multAxis, ptAxis}); + histos.addClone("frac/data/", "frac/mc/"); - histos.add("weight/pion", "", kTProfile, {ptAxis}); histos.add("weight/kaon", "", kTProfile, {ptAxis}); histos.add("weight/proton", "", kTProfile, {ptAxis}); histos.add("weight/sigma", "", kTProfile, {ptAxis}); + histos.add("weight/kaon_mult", "", kTProfile2D, {multAxis, ptAxis}); + histos.add("weight/proton_mult", "", kTProfile2D, {multAxis, ptAxis}); + histos.add("weight/sigma_mult", "", kTProfile2D, {multAxis, ptAxis}); + histos.add("weight/secDec", "", kTProfile, {ptAxis}); histos.add("weight/secMat", "", kTProfile, {ptAxis}); + + histos.add("weight/secDec_mult", "", kTProfile2D, {multAxis, ptAxis}); + histos.add("weight/secMat_mult", "", kTProfile2D, {multAxis, ptAxis}); } } @@ -143,6 +163,11 @@ std::tuple ParticleCompositionCorrection::getWeights(aod::M } auto absPDGCode = std::abs(particle.pdgCode()); // translate abs PDG code to PID variable of neural networks (0: pion, 1: kaon, 2: proton, 3: sigma) + + if (absPDGCode == PDG_t::kPiPlus || absPDGCode == PDG_t::kPi0) { + return noWeights; + } + static const std::map mapPID = { {PDG_t::kPiPlus, 0.f}, {PDG_t::kPi0, 0.f}, @@ -175,25 +200,29 @@ std::tuple ParticleCompositionCorrection::getWeights(aod::M storedWeights[particle.index()] = weights; } if (enableQAHistos && particle.isPhysicalPrimary() && std::abs(particle.eta()) < 0.8) { // o2-linter: disable=magic-number (usual range of charged-partilce measurements) - if (iterMapPID->first == PDG_t::kPiPlus) { - histos.fill(HIST("frac/data/pion"), pt, fracData); - histos.fill(HIST("frac/mc/pion"), pt, fracMC); - histos.fill(HIST("weight/pion"), pt, weight); - } if (iterMapPID->first == PDG_t::kKPlus) { histos.fill(HIST("frac/data/kaon"), pt, fracData); histos.fill(HIST("frac/mc/kaon"), pt, fracMC); + histos.fill(HIST("frac/data/kaon_mult"), dNdEta, pt, fracData); + histos.fill(HIST("frac/mc/kaon_mult"), dNdEta, pt, fracMC); histos.fill(HIST("weight/kaon"), pt, weight); + histos.fill(HIST("weight/kaon_mult"), dNdEta, pt, weight); } if (iterMapPID->first == PDG_t::kProton) { histos.fill(HIST("frac/data/proton"), pt, fracData); histos.fill(HIST("frac/mc/proton"), pt, fracMC); + histos.fill(HIST("frac/data/proton_mult"), dNdEta, pt, fracData); + histos.fill(HIST("frac/mc/proton_mult"), dNdEta, pt, fracMC); histos.fill(HIST("weight/proton"), pt, weight); + histos.fill(HIST("weight/proton_mult"), dNdEta, pt, weight); } if (iterMapPID->first == PDG_t::kSigmaPlus || iterMapPID->first == PDG_t::kSigmaMinus) { histos.fill(HIST("frac/data/sigma"), pt, fracData); histos.fill(HIST("frac/mc/sigma"), pt, fracMC); + histos.fill(HIST("frac/data/sigma_mult"), dNdEta, pt, fracData); + histos.fill(HIST("frac/mc/sigma_mult"), dNdEta, pt, fracMC); histos.fill(HIST("weight/sigma"), pt, weight); + histos.fill(HIST("weight/sigma_mult"), dNdEta, pt, weight); } } return weights; @@ -218,8 +247,10 @@ std::tuple ParticleCompositionCorrection::getWeights(aod::M if (pdgParticle && pdgParticle->Charge() != 0.) { if (particle.getProcess() == TMCProcess::kPDecay) { histos.fill(HIST("weight/secDec"), particle.pt(), weight); + histos.fill(HIST("weight/secDec_mult"), dNdEta, particle.pt(), weight); } else if (particle.getProcess() == TMCProcess::kPHInhelastic || particle.getProcess() == TMCProcess::kPHadronic || particle.getProcess() == TMCProcess::kPHElastic) { histos.fill(HIST("weight/secMat"), particle.pt(), weight); + histos.fill(HIST("weight/secMat_mult"), dNdEta, particle.pt(), weight); } } } @@ -232,6 +263,8 @@ void ParticleCompositionCorrection::process(aod::McCollisions::iterator const&, { // determine dNdEta of the collision float dNdEta = 0.f; + float dNdEtafid = 0.f; + for (const auto& particle : particles) { if (!particle.isPhysicalPrimary()) { continue; @@ -240,10 +273,19 @@ void ParticleCompositionCorrection::process(aod::McCollisions::iterator const&, if (!pdgParticle || pdgParticle->Charge() == 0.) { continue; } - if (std::abs(particle.eta()) >= 0.5) { // o2-linter: disable=magic-number (particle density at mid-rapidity) + if (std::abs(particle.eta()) >= etaCut) { continue; } - ++dNdEta; + if (std::abs(particle.eta()) < 0.5) { // o2-linter: disable=magic-number (particle density at mid-rapidity) + ++dNdEta; + } + ++dNdEtafid; + } + + if (dNdEtafid > 0.f) { + histos.fill(HIST("multDist_INELg0"), dNdEta); + histos.fill(HIST("multDist_fid"), dNdEtafid); + histos.fill(HIST("multDist_fidVsINELg0"), dNdEta, dNdEtafid); } std::map> storedWeights; diff --git a/PWGLF/TableProducer/Nuspex/trackedHypertritonRecoTask.cxx b/PWGLF/TableProducer/Nuspex/trackedHypertritonRecoTask.cxx index 1fddbb346fa..d63be90ba45 100644 --- a/PWGLF/TableProducer/Nuspex/trackedHypertritonRecoTask.cxx +++ b/PWGLF/TableProducer/Nuspex/trackedHypertritonRecoTask.cxx @@ -101,7 +101,9 @@ struct TrackedHypertritonRecoTask { Produces vtx3BodyDatas; Produces vtx3BodyCovs; Produces vtx3BodyTrackedInfo; + Produces vtx3BodyCollision; Produces mcVtx3BodyDatas; + Produces mcVtx3BodyCollision; Service ccdb{}; HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -226,7 +228,7 @@ struct TrackedHypertritonRecoTask { bool isSignal = false; bool isRecoMCCollision = false; bool survivedEventSelection = false; - uint8_t fakeHeITSLayerMap = 0; + uint8_t fakeHeITSLayerMap{}; int motherLabel = -1; int statusCode = 0; }; @@ -238,12 +240,9 @@ struct TrackedHypertritonRecoTask { float genPhi = -1.f; float genEta = -1.f; float genRapidity = -1.f; - float genMomentumProton = -1.f; - float genMomentumPion = -1.f; - float genMomentumDeuteron = -1.f; - float genPtProton = -1.f; - float genPtPion = -1.f; - float genPtDeuteron = -1.f; + std::array genMomProton{-1.f, -1.f, -1.f}; + std::array genMomPion{-1.f, -1.f, -1.f}; + std::array genMomDeuteron{-1.f, -1.f, -1.f}; bool isReco = true; int motherLabel = -1; int motherPdgCode = 0; @@ -251,6 +250,7 @@ struct TrackedHypertritonRecoTask { int pionPdgCode = -1; int deuteronPdgCode = -1; bool isDeuteronPrimary = false; + bool isRecoMCCollision = false; bool survivedEventSelection = false; }; @@ -521,12 +521,9 @@ struct TrackedHypertritonRecoTask { info.pionPdgCode = mcPion.pdgCode(); info.deuteronPdgCode = mcDeuteron.pdgCode(); info.isDeuteronPrimary = mcDeuteron.isPhysicalPrimary(); - info.genMomentumProton = mcProton.p(); - info.genMomentumPion = mcPion.p(); - info.genMomentumDeuteron = mcDeuteron.p(); - info.genPtProton = mcProton.pt(); - info.genPtPion = mcPion.pt(); - info.genPtDeuteron = mcDeuteron.pt(); + info.genMomProton = {mcProton.px(), mcProton.py(), mcProton.pz()}; + info.genMomPion = {mcPion.px(), mcPion.py(), mcPion.pz()}; + info.genMomDeuteron = {mcDeuteron.px(), mcDeuteron.py(), mcDeuteron.pz()}; const int motherLabel = findCommonMother(mcProton, mcPion, mcDeuteron); if (motherLabel < 0) { @@ -548,7 +545,8 @@ struct TrackedHypertritonRecoTask { info.genPhi = mother.phi(); info.genEta = mother.eta(); info.genRapidity = mother.y(); - if (mother.mcCollisionId() >= 0 && mother.mcCollisionId() < static_cast(survivedMCEventSelection.size())) { + if (mother.mcCollisionId() >= 0 && mother.mcCollisionId() < static_cast(recoCollisionForMC.size())) { + info.isRecoMCCollision = recoCollisionForMC[mother.mcCollisionId()] >= 0; info.survivedEventSelection = survivedMCEventSelection[mother.mcCollisionId()]; } return info; @@ -582,9 +580,9 @@ struct TrackedHypertritonRecoTask { std::array xyzpxpypz{}; trackHeliumCov.getPxPyPzGlo(pxpypz); trackHeliumCov.getXYZGlo(xyz); - for (int i = 0; i < 3; ++i) { + for (std::size_t i = 0; i < xyz.size(); ++i) { xyzpxpypz[i] = xyz[i]; - xyzpxpypz[i + 3] = pxpypz[i] * 2; + xyzpxpypz[i + xyz.size()] = pxpypz[i] * 2; } std::array cv{}; trackHeliumCov.getCovXYZPxPyPzGlo(cv); @@ -690,7 +688,7 @@ struct TrackedHypertritonRecoTask { // get SV position const auto& secondaryVertex = fitter2Body.getPCACandidate(); - for (int i = 0; i < 3; i++) { + for (std::size_t i = 0; i < v0.decayVertex.size(); i++) { v0.decayVertex[i] = secondaryVertex[i]; } v0.chi2 = std::sqrt(fitter2Body.getChi2AtPCACandidate()); @@ -744,6 +742,7 @@ struct TrackedHypertritonRecoTask { flags |= static_cast(piTrack.pidForTracking() & 0xf); fillCandidate(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), + collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange(), collision.posX(), collision.posY(), collision.posZ(), runNumber, heTrack.sign() > 0, std::hypot(v0.momHelium[0], v0.momHelium[1]), std::atan2(v0.momHelium[1], v0.momHelium[0]), RecoDecay::eta(v0.momHelium), @@ -780,7 +779,7 @@ struct TrackedHypertritonRecoTask { } template - std::array getItsTrackDCAToSV(TTracked3body tracked3Body) + std::array getItsTrackDCAToSV(TTracked3body const& tracked3Body) { const auto itsTrack = tracked3Body.template itsTrack_as(); auto itsTrackParCov = getTrackParCov(itsTrack); @@ -789,7 +788,8 @@ struct TrackedHypertritonRecoTask { return dcaInfo; } - void fillThreeBodyTables() + template + void fillThreeBodyTables(TCollision const& collision) { const auto& candidate = builder3Body.decay3body; vtx3BodyDatas(static_cast(candidate.sign), @@ -815,6 +815,10 @@ struct TrackedHypertritonRecoTask { static_cast(candidate.pidForTrackingDeuteron)); vtx3BodyCovs(candidate.covProton.data(), candidate.covPion.data(), candidate.covDeuteron.data(), candidate.covariance.data()); vtx3BodyTrackedInfo(candidate.itsTrackDCAToSV[0], candidate.itsTrackDCAToSV[1]); + vtx3BodyCollision(collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), + collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange(), + collision.posX(), collision.posY(), collision.posZ(), + runNumber); } void fillThreeBodyMCTable(ThreeBodyMCInfo const& info) @@ -844,8 +848,9 @@ struct TrackedHypertritonRecoTask { info.genMomentum[0], info.genMomentum[1], info.genMomentum[2], info.genDecayVertex[0], info.genDecayVertex[1], info.genDecayVertex[2], info.genCt, info.genPhi, info.genEta, info.genRapidity, - info.genMomentumProton, info.genMomentumPion, info.genMomentumDeuteron, - info.genPtProton, info.genPtPion, info.genPtDeuteron, + info.genMomProton[0], info.genMomProton[1], info.genMomProton[2], + info.genMomPion[0], info.genMomPion[1], info.genMomPion[2], + info.genMomDeuteron[0], info.genMomDeuteron[1], info.genMomDeuteron[2], static_cast(info.isReco), info.motherLabel, info.motherPdgCode, info.protonPdgCode, info.pionPdgCode, info.deuteronPdgCode, info.isDeuteronPrimary, static_cast(info.survivedEventSelection)); @@ -878,8 +883,9 @@ struct TrackedHypertritonRecoTask { info.genMomentum[0], info.genMomentum[1], info.genMomentum[2], info.genDecayVertex[0], info.genDecayVertex[1], info.genDecayVertex[2], info.genCt, info.genPhi, info.genEta, info.genRapidity, - info.genMomentumProton, info.genMomentumPion, info.genMomentumDeuteron, - info.genPtProton, info.genPtPion, info.genPtDeuteron, + info.genMomProton[0], info.genMomProton[1], info.genMomProton[2], + info.genMomPion[0], info.genMomPion[1], info.genMomPion[2], + info.genMomDeuteron[0], info.genMomDeuteron[1], info.genMomDeuteron[2], 0, info.motherLabel, info.motherPdgCode, info.protonPdgCode, info.pionPdgCode, info.deuteronPdgCode, info.isDeuteronPrimary, static_cast(info.survivedEventSelection)); @@ -910,13 +916,13 @@ struct TrackedHypertritonRecoTask { selectCollisions(collisions, skimmedProcessing); for (const auto& trackedV0 : trackedV0s) { - const auto v0 = trackedV0.v0_as(); - if (v0.collisionId() < 0 || !goodCollision[v0.collisionId()] || (skimmedProcessing && !zorroDecision[v0.collisionId()][kHe])) { + const auto inputV0 = trackedV0.v0_as(); + if (inputV0.collisionId() < 0 || !goodCollision[inputV0.collisionId()] || (skimmedProcessing && !zorroDecision[inputV0.collisionId()][kHe])) { continue; } - const auto collision = v0.collision_as(); - const auto positiveTrack = v0.posTrack_as(); - const auto negativeTrack = v0.negTrack_as(); + const auto collision = inputV0.collision_as(); + const auto positiveTrack = inputV0.posTrack_as(); + const auto negativeTrack = inputV0.negTrack_as(); const float nSigmaPositive = nSigmaHe3(positiveTrack); const float nSigmaNegative = nSigmaHe3(negativeTrack); const bool positiveTrackedAsHe = positiveTrack.pidForTracking() == o2::track::PID::Helium3 || positiveTrack.pidForTracking() == o2::track::PID::Alpha; @@ -971,7 +977,7 @@ struct TrackedHypertritonRecoTask { } fillQAHistograms(trackProton, trackPion, trackDeuteron, true); - fillThreeBodyTables(); + fillThreeBodyTables(collision); } } } @@ -992,13 +998,13 @@ struct TrackedHypertritonRecoTask { std::vector reconstructedThreeBody(mcParticles.size(), false); for (const auto& trackedV0 : trackedV0s) { - const auto v0 = trackedV0.v0_as(); - if (v0.collisionId() < 0 || !goodCollision[v0.collisionId()]) { + const auto inputV0 = trackedV0.v0_as(); + if (inputV0.collisionId() < 0 || !goodCollision[inputV0.collisionId()]) { continue; } - const auto collision = v0.collision_as(); - const auto positiveTrack = v0.posTrack_as(); - const auto negativeTrack = v0.negTrack_as(); + const auto collision = inputV0.collision_as(); + const auto positiveTrack = inputV0.posTrack_as(); + const auto negativeTrack = inputV0.negTrack_as(); const float nSigmaPositive = nSigmaHe3(positiveTrack); const float nSigmaNegative = nSigmaHe3(negativeTrack); const bool positiveTrackedAsHe = positiveTrack.pidForTracking() == o2::track::PID::Helium3 || positiveTrack.pidForTracking() == o2::track::PID::Alpha; @@ -1027,7 +1033,8 @@ struct TrackedHypertritonRecoTask { continue; } buildTwoBody(heTrack, piTrack, collision, trackedV0.itsClsSize(), [&](auto... values) { - mcHypCands(values..., + mcHypCands(collision.globalIndex(), heTrack.globalIndex(), piTrack.globalIndex(), + values..., mcInfo.genPt, mcInfo.genPhi, mcInfo.genEta, mcInfo.genPtHe3, mcInfo.genDecayVertex[0], mcInfo.genDecayVertex[1], mcInfo.genDecayVertex[2], true, mcInfo.fakeHeITSLayerMap, mcInfo.isSignal, @@ -1076,6 +1083,12 @@ struct TrackedHypertritonRecoTask { } fillThreeBodyMCTable(mcInfo); + mcVtx3BodyCollision(true, // IsRecoMCCollision + collision.centFT0A(), collision.centFT0C(), collision.centFT0M(), + collision.trackOccupancyInTimeRange(), collision.ft0cOccupancyInTimeRange(), + collision.posX(), collision.posY(), collision.posZ(), + runNumber); + if (mcInfo.motherLabel >= 0) { reconstructedThreeBody[mcInfo.motherLabel] = true; } @@ -1116,19 +1129,16 @@ struct TrackedHypertritonRecoTask { hasPionTwoBody = true; hasPionThreeBody = true; threeBodyInfo.pionPdgCode = daughter.pdgCode(); - threeBodyInfo.genMomentumPion = daughter.p(); - threeBodyInfo.genPtPion = daughter.pt(); + threeBodyInfo.genMomPion = {daughter.px(), daughter.py(), daughter.pz()}; } else if (daughter.pdgCode() == sign * PDG_t::kProton) { hasProton = true; threeBodyInfo.protonPdgCode = daughter.pdgCode(); - threeBodyInfo.genMomentumProton = daughter.p(); - threeBodyInfo.genPtProton = daughter.pt(); + threeBodyInfo.genMomProton = {daughter.px(), daughter.py(), daughter.pz()}; threeBodyInfo.genDecayVertex = {daughter.vx(), daughter.vy(), daughter.vz()}; } else if (daughter.pdgCode() == sign * constants::physics::Pdg::kDeuteron) { hasDeuteron = true; threeBodyInfo.deuteronPdgCode = daughter.pdgCode(); - threeBodyInfo.genMomentumDeuteron = daughter.p(); - threeBodyInfo.genPtDeuteron = daughter.pt(); + threeBodyInfo.genMomDeuteron = {daughter.px(), daughter.py(), daughter.pz()}; threeBodyInfo.isDeuteronPrimary = daughter.isPhysicalPrimary(); } } @@ -1137,6 +1147,8 @@ struct TrackedHypertritonRecoTask { float centralityFT0A = -1.f; float centralityFT0C = -1.f; float centralityFT0M = -1.f; + int trackOccupancyInTimeRange = -1; + float ft0cOccupancyInTimeRange = -1.f; float primaryVertexX = -1.f; float primaryVertexY = -1.f; float primaryVertexZ = -1.f; @@ -1151,12 +1163,16 @@ struct TrackedHypertritonRecoTask { centralityFT0A = collision.centFT0A(); centralityFT0C = collision.centFT0C(); centralityFT0M = collision.centFT0M(); + trackOccupancyInTimeRange = collision.trackOccupancyInTimeRange(); + ft0cOccupancyInTimeRange = collision.ft0cOccupancyInTimeRange(); primaryVertexX = collision.posX(); primaryVertexY = collision.posY(); primaryVertexZ = collision.posZ(); } } - mcHypCands(centralityFT0A, centralityFT0C, centralityFT0M, + mcHypCands(-1, -1, -1, + centralityFT0A, centralityFT0C, centralityFT0M, + trackOccupancyInTimeRange, ft0cOccupancyInTimeRange, primaryVertexX, primaryVertexY, primaryVertexZ, runNumber, mother.pdgCode() > 0, -1.f, -1.f, -1.f, @@ -1172,11 +1188,40 @@ struct TrackedHypertritonRecoTask { } if (hasProton && hasPionThreeBody && hasDeuteron && !reconstructedThreeBody[mother.globalIndex()]) { + float centralityFT0A = -1.f; + float centralityFT0C = -1.f; + float centralityFT0M = -1.f; + int trackOccupancyInTimeRange = -1; + float ft0cOccupancyInTimeRange = -1.f; + float primaryVertexX = -1.f; + float primaryVertexY = -1.f; + float primaryVertexZ = -1.f; + bool isRecoMCCollision = false; + if (mother.mcCollisionId() >= 0 && mother.mcCollisionId() < static_cast(recoCollisionForMC.size())) { + const int recoCollisionId = recoCollisionForMC[mother.mcCollisionId()]; + isRecoMCCollision = recoCollisionId >= 0; + if (isRecoMCCollision) { + const auto collision = collisions.rawIteratorAt(recoCollisionId); + centralityFT0A = collision.centFT0A(); + centralityFT0C = collision.centFT0C(); + centralityFT0M = collision.centFT0M(); + trackOccupancyInTimeRange = collision.trackOccupancyInTimeRange(); + ft0cOccupancyInTimeRange = collision.ft0cOccupancyInTimeRange(); + primaryVertexX = collision.posX(); + primaryVertexY = collision.posY(); + primaryVertexZ = collision.posZ(); + } + } threeBodyInfo.genCt = RecoDecay::sqrtSumOfSquares(threeBodyInfo.genDecayVertex[0] - mother.vx(), threeBodyInfo.genDecayVertex[1] - mother.vy(), threeBodyInfo.genDecayVertex[2] - mother.vz()) * constants::physics::MassHyperTriton / (mother.p() + 1.e-10f); fillGeneratedThreeBodyMCTable(threeBodyInfo); + mcVtx3BodyCollision(isRecoMCCollision, + centralityFT0A, centralityFT0C, centralityFT0M, + trackOccupancyInTimeRange, ft0cOccupancyInTimeRange, + primaryVertexX, primaryVertexY, primaryVertexZ, + runNumber); } } } diff --git a/PWGLF/TableProducer/Resonances/CMakeLists.txt b/PWGLF/TableProducer/Resonances/CMakeLists.txt index a2776b9dedf..5ce14867844 100644 --- a/PWGLF/TableProducer/Resonances/CMakeLists.txt +++ b/PWGLF/TableProducer/Resonances/CMakeLists.txt @@ -64,3 +64,8 @@ o2physics_add_dpl_workflow(resonance-tree-creator SOURCES resonanceTreeCreator.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(xi1530kaonreducedtable + SOURCES xi1530kaonreducedtable.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGLF/TableProducer/Resonances/HeptaQuarktable.cxx b/PWGLF/TableProducer/Resonances/HeptaQuarktable.cxx index 3171b1c93dd..3516949aa9c 100644 --- a/PWGLF/TableProducer/Resonances/HeptaQuarktable.cxx +++ b/PWGLF/TableProducer/Resonances/HeptaQuarktable.cxx @@ -262,7 +262,7 @@ struct heptaquarktable { auto posThisColl = posTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); auto negThisColl = negTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - for (auto track1 : posThisColl) { + for (const auto& track1 : posThisColl) { if (!selectionTrack(track1)) continue; @@ -279,7 +279,7 @@ struct heptaquarktable { } */ auto track1ID = track1.globalIndex(); - for (auto track2 : negThisColl) { + for (const auto& track2 : negThisColl) { if (!selectionTrack(track2)) continue; diff --git a/PWGLF/TableProducer/Resonances/doublephitable.cxx b/PWGLF/TableProducer/Resonances/doublephitable.cxx index 2e04cd9be96..7845dbdf6b3 100644 --- a/PWGLF/TableProducer/Resonances/doublephitable.cxx +++ b/PWGLF/TableProducer/Resonances/doublephitable.cxx @@ -264,7 +264,7 @@ struct doublephitable { hProcessedEvents->Fill(2.5); auto posThisColl = posTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); auto negThisColl = negTracks->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - for (auto track1 : posThisColl) { + for (const auto& track1 : posThisColl) { // track selection if (!selectionTrack(track1)) { continue; @@ -283,7 +283,7 @@ struct doublephitable { qaRegistry.fill(HIST("hNsigmaPtkaonTOF"), track1.tofNSigmaKa(), track1.pt()); } auto track1ID = track1.globalIndex(); - for (auto track2 : negThisColl) { + for (const auto& track2 : negThisColl) { auto track2ID = track2.globalIndex(); if (track2ID == track1ID) { continue; @@ -600,7 +600,7 @@ struct doublephitable { selectedNeg.reserve(negThisColl.size()); selectedPosITS.reserve(posThisColl.size()); selectedNegITS.reserve(negThisColl.size()); - for (auto track : posThisColl) { + for (const auto& track : posThisColl) { if (!selectionTrack(track)) { continue; } @@ -622,7 +622,7 @@ struct doublephitable { } } - for (auto track : negThisColl) { + for (const auto& track : negThisColl) { if (!selectionTrack(track)) { continue; } diff --git a/PWGLF/TableProducer/Resonances/f1protonInitializer.cxx b/PWGLF/TableProducer/Resonances/f1protonInitializer.cxx index 5c52b6ca4d3..4ec94e32a03 100644 --- a/PWGLF/TableProducer/Resonances/f1protonInitializer.cxx +++ b/PWGLF/TableProducer/Resonances/f1protonInitializer.cxx @@ -222,7 +222,7 @@ struct f1protoninitializer { bool triggerF1 = false; bool triggerF1Proton = false; bool triggerF1ProtonFemto = false; - for (auto track1 : tracks) { + for (const auto& track1 : tracks) { if (!SelectionTrack(track1)) { continue; } @@ -242,7 +242,7 @@ struct f1protoninitializer { qaRegistry.fill(HIST("hNsigmaPtpionTOF"), track1.tofNSigmaPi(), track1.pt()); } auto track1ID = track1.globalIndex(); - for (auto track2 : tracks) { + for (const auto& track2 : tracks) { if (!SelectionTrack(track2)) { continue; } @@ -273,7 +273,7 @@ struct f1protoninitializer { int track2Sign = track2.sign(); numberPiKpair = numberPiKpair + 1; - for (auto track3 : V0s) { + for (const auto& track3 : V0s) { if (!SelectionV0(collision, track3)) { continue; } @@ -308,7 +308,7 @@ struct f1protoninitializer { F1Vector.SetXYZM(track1.px() + track2.px() + track3.px(), track1.py() + track2.py() + track3.py(), track1.pz() + track2.pz() + track3.pz(), massF1); ////////////// proton loop for F1-proton trigger///////////////// - for (auto track4 : tracks) { + for (const auto& track4 : tracks) { auto collisionId4 = track4.collisionId(); if (collisionId1 != collisionId4) { continue; diff --git a/PWGLF/TableProducer/Resonances/f1protonreducedtable.cxx b/PWGLF/TableProducer/Resonances/f1protonreducedtable.cxx index 44ce411c9eb..e64210a9ec7 100644 --- a/PWGLF/TableProducer/Resonances/f1protonreducedtable.cxx +++ b/PWGLF/TableProducer/Resonances/f1protonreducedtable.cxx @@ -355,7 +355,7 @@ struct f1protonreducedtable { return false; } - inline bool passProtonPID(float nsigmaTPC, float nsigmaTOF, float TOFHit, ROOT::Math::PtEtaPhiMVector proton) + inline bool passProtonPID(float nsigmaTPC, float nsigmaTOF, float TOFHit, const ROOT::Math::PtEtaPhiMVector& proton) { // pidMode: // 0 = default: p < thr -> |TPC| < 2.5 ; p >= thr -> TOF mandatory AND circular(TPC,TOF) < 2.0 @@ -424,8 +424,8 @@ struct f1protonreducedtable { return true; } - float getkstar(const ROOT::Math::PtEtaPhiMVector part1, - const ROOT::Math::PtEtaPhiMVector part2) + float getkstar(const ROOT::Math::PtEtaPhiMVector& part1, + const ROOT::Math::PtEtaPhiMVector& part2) { const ROOT::Math::PtEtaPhiMVector trackSum = part1 + part2; const float beta = trackSum.Beta(); @@ -444,7 +444,7 @@ struct f1protonreducedtable { return 0.5 * trackRelK.P(); } - std::vector setValuesBB(o2::ccdb::CcdbApi& ccdbApi, aod::BCsWithTimestamps::iterator const& bunchCrossing, const std::string ccdbPath) + std::vector setValuesBB(o2::ccdb::CcdbApi& ccdbApi, aod::BCsWithTimestamps::iterator const& bunchCrossing, const std::string& ccdbPath) { std::map metadata; auto h = ccdbApi.retrieveFromTFileAny(ccdbPath, metadata, bunchCrossing.timestamp()); diff --git a/PWGLF/TableProducer/Resonances/filterf1proton.cxx b/PWGLF/TableProducer/Resonances/filterf1proton.cxx index c9f56828434..995cd37c504 100644 --- a/PWGLF/TableProducer/Resonances/filterf1proton.cxx +++ b/PWGLF/TableProducer/Resonances/filterf1proton.cxx @@ -355,8 +355,8 @@ struct filterf1proton { return true; } - float getkstar(const ROOT::Math::PtEtaPhiMVector part1, - const ROOT::Math::PtEtaPhiMVector part2) + float getkstar(const ROOT::Math::PtEtaPhiMVector& part1, + const ROOT::Math::PtEtaPhiMVector& part2) { const ROOT::Math::PtEtaPhiMVector trackSum = part1 + part2; const float beta = trackSum.Beta(); @@ -375,7 +375,7 @@ struct filterf1proton { return 0.5 * trackRelK.P(); } - std::vector setValuesBB(o2::ccdb::CcdbApi& ccdbApi, aod::BCsWithTimestamps::iterator const& bunchCrossing, const std::string ccdbPath) + std::vector setValuesBB(o2::ccdb::CcdbApi& ccdbApi, aod::BCsWithTimestamps::iterator const& bunchCrossing, const std::string& ccdbPath) { std::map metadata; auto h = ccdbApi.retrieveFromTFileAny(ccdbPath, metadata, bunchCrossing.timestamp()); diff --git a/PWGLF/TableProducer/Resonances/resonanceInitializer.cxx b/PWGLF/TableProducer/Resonances/resonanceInitializer.cxx index 4dfd2409424..f1ab80425f5 100644 --- a/PWGLF/TableProducer/Resonances/resonanceInitializer.cxx +++ b/PWGLF/TableProducer/Resonances/resonanceInitializer.cxx @@ -596,7 +596,7 @@ struct ResonanceInitializer { // Centralicity estimator selection template - float centEst(ResoColl ResoEvents) + float centEst(const ResoColl& ResoEvents) { float returnValue = -999.0; switch (multEstimator) { @@ -673,7 +673,7 @@ struct ResonanceInitializer { } template - float getEvtPl(ResoColl ResoEvents) + float getEvtPl(const ResoColl& ResoEvents) { float returnValue = -999.0; if (ResoEvents.qvecAmp()[evtPlDetId] > 1e-8) @@ -682,7 +682,7 @@ struct ResonanceInitializer { } template - float getEvtPlRes(ResoColl ResoEvents, int a, int b) + float getEvtPlRes(const ResoColl& ResoEvents, int a, int b) { float returnValue = -999.0; if (ResoEvents.qvecAmp()[a] < 1e-8 || ResoEvents.qvecAmp()[b] < 1e-8) diff --git a/PWGLF/TableProducer/Resonances/resonanceModuleInitializer.cxx b/PWGLF/TableProducer/Resonances/resonanceModuleInitializer.cxx index 1d748682f6c..21e534db7fc 100644 --- a/PWGLF/TableProducer/Resonances/resonanceModuleInitializer.cxx +++ b/PWGLF/TableProducer/Resonances/resonanceModuleInitializer.cxx @@ -13,15 +13,15 @@ /// \brief Initializes variables for the resonance candidate producers /// /// \author Bong-Hwi Lim , Minjae Kim -/// \since Aug.18 2026 +/// \since Aug.31 2026 #include "PWGLF/DataModel/LFResonanceTables.h" #include "PWGLF/DataModel/LFStrangenessTables.h" #include "PWGLF/DataModel/mcCentrality.h" #include "PWGLF/Utils/collisionCuts.h" -#include "Common/CCDB/EventSelectionParams.h" #include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" @@ -40,10 +40,14 @@ #include #include #include -#include #include #include +#include +#include +#include + +#include #include #include #include @@ -73,23 +77,60 @@ using namespace o2::aod::rctsel; struct ResonanceModuleInitializer { static constexpr double BzOverrideThreshold = -990.; static constexpr double MinimumNonzeroBz = 1.e-5; - static constexpr double MinimumChargedParticleCharge = 3.; // ROOT particle charge is stored in units of e/3 - static constexpr int MCCentralityRecoEstimator = 0; - static constexpr int MCCentralityGeneratorEstimator = 1; - static constexpr int MCCentralityImpactParameterEstimator = 2; + static constexpr int CentralityFT0M = 0; + static constexpr int CentralityFT0C = 1; + static constexpr int CentralityFT0A = 2; + static constexpr int CentralityFV0A = 3; + static constexpr int MultiplicityNTracksPV = 0; + static constexpr int MultiplicityNTracksPVeta1 = 1; + static constexpr int MultiplicityNTracksPVetaHalf = 2; + static constexpr int MultiplicityFT0M = 3; + static constexpr int MultiplicityFT0A = 4; + static constexpr int MultiplicityFT0C = 5; + static constexpr int MultiplicityFV0A = 6; + static constexpr int DetailedQARCTStage = o2::analysis::CollisonCuts::kAllpassed + 1; + static constexpr int DetailedQAStages = DetailedQARCTStage + 1; static constexpr float MCVertexZMax = 10.f; - - int mRunNumber = 0; ///< Run number for the current data - int multEstimator = 0; ///< Multiplicity estimator type - float dBz = 0.f; ///< Magnetic field value - float centrality = 0.f; ///< Centrality value for the event - Service ccdb; ///< CCDB manager service - Service pdg; ///< PDG database service - - Produces resoCollisions; ///< Output table for resonance collisions - Produces resoCollisionColls; ///< Output table for collision references - Produces resoCollisionGroups; ///< Canonical original-collision grouping references - Produces resoMCCollisions; ///< Output table for MC resonance collisions + // PDG codes used by the persistent resonance-parent selection. Named O2/ROOT + // values are preferred where available; the remaining resonances are kept as + // local named constants because neither PDG_t nor PhysicsConstants defines them. + static constexpr int PdgKStar0 = o2::constants::physics::Pdg::kK0Star892; + static constexpr int PdgKStarCharged = o2::constants::physics::Pdg::kKPlusStar892; + static constexpr int PdgPhi = o2::constants::physics::Pdg::kPhi; + static constexpr int F0Code980 = 9010221; + static constexpr int F0Code1370 = 10221; + static constexpr int F0Code1500 = 9030221; + static constexpr int F0Code1710 = 10331; + static constexpr int F1Code1285 = 20223; + static constexpr int F1Code1420 = 20333; + static constexpr int F2PrimeCode1525 = 335; + static constexpr int PdgRho0 = PDG_t::kRho770_0; + static constexpr int PdgRhoCharged = PDG_t::kRho770Plus; + static constexpr int SigmaStarPlusCode = 3224; + static constexpr int PdgLambda1520 = o2::constants::physics::Pdg::kLambda1520_Py; + static constexpr int Xi1530Code = 3324; + static constexpr int PdgK1Plus1270 = o2::constants::physics::Pdg::kK1_1270Plus; + static constexpr int Xi1820NeutralCode = 123314; + static constexpr int Xi1820MinusCode = 123324; + static constexpr int Omega2012MinusCode = 123334; + static constexpr int PdgProton = PDG_t::kProton; + static constexpr int PdgLambda0 = PDG_t::kLambda0; + static constexpr int PdgXiMinus = PDG_t::kXiMinus; + static constexpr int PdgXi0 = o2::constants::physics::Pdg::kXi0; + static constexpr int PdgOmegaMinus = PDG_t::kOmegaMinus; + + int mRunNumber = 0; ///< Run number for the current data + int multEstimator = CentralityFT0M; ///< Centrality estimator type + float dBz = 0.f; ///< Magnetic field value + float centrality = 0.f; ///< Centrality value for the event + Service ccdb; ///< CCDB manager service + + Produces resoCollisions; ///< Output table for resonance collisions + Produces resoCollisionColls; ///< Optional source collision soft links + Produces resoCollisionGroups001; ///< Scalar original-collision grouping keys + Produces resoMCCollisions001; ///< Generator-only MC collision extension + Produces resoMCCollisionIds; ///< Optional source generator-collision soft links + Produces reso2mcparents; ///< Generated parents with scalar source-particle IDs // CCDB options struct : ConfigurableGroup { @@ -99,18 +140,21 @@ struct ResonanceModuleInitializer { Configurable lutPath{"lutPath", "GLO/Param/MatLUT", "Path of the Lut parametrization"}; Configurable geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; Configurable cfgFatalWhenNull{"cfgFatalWhenNull", true, "Fatal when null on ccdb access"}; - Configurable cfgBypassCollIndexFill{"cfgBypassCollIndexFill", false, "Unsupported in the modular workflow; must remain false"}; + Configurable cfgBypassCollIndexFill{"cfgBypassCollIndexFill", false, "Deprecated compatibility option; collision mapping tables are always written"}; } CCDB; // General event options struct : ConfigurableGroup { Configurable dBzInput{"dBzInput", -999, "bz field, -999 is automatic"}; Configurable cfgFillQA{"cfgFillQA", true, "Fill QA histograms"}; + Configurable cfgFillDetailedQA{"cfgFillDetailedQA", true, "Fill the Run 3 event-selection stage vs vertex-z vs centrality vs multiplicity THnSparse"}; Configurable cfgBypassCCDB{"cfgBypassCCDB", true, "Bypass loading CCDB part to save CPU time and memory"}; // will be affected to b_z value. - Configurable cfgMultName{"cfgMultName", "FT0M", "The name of multiplicity estimator"}; - Configurable cfgCentralityMC{"cfgCentralityMC", 0, "Centrality estimator for MC (0: Reco, 1: MC, 2: impact parameter)"}; - ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0., 0.01, 0.1, 1.0, 5.0, 10., 15., 20., 30., 40., 50., 70., 100.0, 105.}, "Binning of the centrality axis"}; - ConfigurableAxis cfgVtxBins{"cfgVtxBins", {VARIABLE_WIDTH, -20, -15, -10, -7, -5, -3, -2, -1, 0, 1, 2, 3, 5, 7, 10, 15, 20}, "Mixing bins - z-vertex"}; + Configurable cfgMultName{"cfgMultName", "FT0M", "Centrality estimator: FT0M, FT0C, FT0A, or FV0A"}; + Configurable cfgMultiplicityEstimator{"cfgMultiplicityEstimator", 3, + "Stored multiplicity (NOT percentile): 0 -> NTracksPV, 1 -> NTracksPVeta1, 2 -> NTracksPVetaHalf, 3 -> FT0M, 4 -> FT0A, 5 -> FT0C, 6 -> FV0A"}; + ConfigurableAxis binsCent{"binsCent", {VARIABLE_WIDTH, 0., 0.01, 0.1, 1., 5., 10., 15., 20., 30., 40., 50., 60., 70., 80., 90., 100., 105.}, "Binning of the centrality axis"}; + ConfigurableAxis binsMultiplicity{"binsMultiplicity", {500, 0.f, 5000.f}, "Binning of the reconstructed multiplicity axis for detailed collision QA"}; + ConfigurableAxis cfgVtxBins{"cfgVtxBins", {400, -20.f, 20.f}, "Binning of the collision vertex-z axis for detailed QA"}; } EventConfig; /// Event cuts @@ -119,26 +163,86 @@ struct ResonanceModuleInitializer { Configurable cfgEvtZvtx{"cfgEvtZvtx", 10.f, "Evt sel: Max. z-Vertex (cm)"}; Configurable cfgEvtOccupancyInTimeRange{"cfgEvtOccupancyInTimeRange", -1, "Evt sel: maximum track occupancy"}; Configurable cfgEvtTriggerCheck{"cfgEvtTriggerCheck", false, "Evt sel: check for trigger"}; - Configurable cfgEvtOfflineCheck{"cfgEvtOfflineCheck", true, "Evt sel: check for offline selection"}; - Configurable cfgEvtTriggerTVXSel{"cfgEvtTriggerTVXSel", false, "Evt sel: triggerTVX selection (MB)"}; - Configurable cfgEvtTFBorderCut{"cfgEvtTFBorderCut", false, "Evt sel: apply TF border cut"}; + Configurable cfgEvtOfflineCheck{"cfgEvtOfflineCheck", false, "Evt sel: check for offline selection (sel8)"}; + Configurable cfgEvtTriggerTVXSel{"cfgEvtTriggerTVXSel", true, "Evt sel: triggerTVX selection (MB)"}; + Configurable cfgEvtTFBorderCut{"cfgEvtTFBorderCut", true, "Evt sel: apply TF border cut"}; Configurable cfgEvtUseITSTPCvertex{"cfgEvtUseITSTPCvertex", false, "Evt sel: use at lease on ITS-TPC track for vertexing"}; Configurable cfgEvtCollInTimeRangeNarrow{"cfgEvtCollInTimeRangeNarrow", false, "Evt sel: apply NoCollInTimeRangeNarrow"}; Configurable cfgEvtZvertexTimedifference{"cfgEvtZvertexTimedifference", false, "Evt sel: apply Z-vertex time difference"}; Configurable cfgEvtPileupRejection{"cfgEvtPileupRejection", false, "Evt sel: apply pileup rejection"}; Configurable cfgEvtNoITSROBorderCut{"cfgEvtNoITSROBorderCut", false, "Evt sel: apply NoITSRO border cut"}; - Configurable cfgEvtRun2AliEventCuts{"cfgEvtRun2AliEventCuts", true, "Evt sel: apply Run2 AliEventCuts"}; + Configurable cfgEvtRun2AliEventCuts{"cfgEvtRun2AliEventCuts", false, "Evt sel: apply Run2 AliEventCuts"}; Configurable cfgEvtRun2INELgtZERO{"cfgEvtRun2INELgtZERO", false, "Evt sel: apply Run2 INELgtZERO"}; - Configurable cfgEvtUseRCTFlagChecker{"cfgEvtUseRCTFlagChecker", false, "Evt sel: use RCT flag checker"}; + Configurable cfgEvtUseRCTFlagChecker{"cfgEvtUseRCTFlagChecker", true, "Evt sel: use RCT flag checker"}; + Configurable cfgEvtBCRCT{"cfgEvtBCRCT", false, "Evt sel: check RCT on the nominal associated BCSEL instead of the collision EVSEL"}; Configurable cfgEvtRCTFlagCheckerLabel{"cfgEvtRCTFlagCheckerLabel", "CBT_hadronPID", "Evt sel: RCT flag checker label"}; Configurable cfgEvtRCTFlagCheckerZDCCheck{"cfgEvtRCTFlagCheckerZDCCheck", false, "Evt sel: RCT flag checker ZDC check"}; Configurable cfgEvtRCTFlagCheckerLimitAcceptAsBad{"cfgEvtRCTFlagCheckerLimitAcceptAsBad", false, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"}; + Configurable cfgEvtRCTCheckTableValidity{"cfgEvtRCTCheckTableValidity", false, "Evt sel: reject collisions when the RCT CCDB payload is unavailable"}; } EventCuts; - RCTFlagsChecker rctChecker; + RCTFlagsChecker recoRCTChecker; - HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; + // Generator-level event and resonance QA + struct : ConfigurableGroup { + Configurable cfgGenBCRCT{"cfgGenBCRCT", false, "GenEvent: apply the RCT flag checker to the associated BC"}; + Configurable cfgGenRCTCheckTableValidity{"cfgGenRCTCheckTableValidity", false, "GenEvent: reject MC collisions when the RCT CCDB payload is unavailable"}; + Configurable cfgGenMult05{"cfgGenMult05", true, "GenEvent: multiplicity in |eta| < 0.5"}; + Configurable cfgGenMult10{"cfgGenMult10", false, "GenEvent: multiplicity in |eta| < 1.0"}; + Configurable cfgGenMultFT0M{"cfgGenMultFT0M", false, "GenEvent: generated charged-particle multiplicity in the FT0A + FT0C acceptance"}; + Configurable cfgGenMultFT0C{"cfgGenMultFT0C", false, "GenEvent: generated charged-particle multiplicity in the FT0C acceptance"}; + Configurable cfgGenMultFV0A{"cfgGenMultFV0A", false, "GenEvent: generated charged-particle multiplicity in the FV0A acceptance"}; + Configurable cfgGenMultPercentile{"cfgGenMultPercentile", true, "Use the configured FT0M, FT0C, or FV0A percentile from the MC centrality wagon"}; + Configurable cfgFillMCCollisionSoftLink{"cfgFillMCCollisionSoftLink", false, + "Write the source MC-collision soft link; enable only with the original AO2D as linked parent"}; + Configurable isZvtxcutGen{"isZvtxcutGen", true, "Apply the generator-collision z-vertex cut"}; + Configurable cutzvertexGen{"cutzvertexGen", 10.f, "Maximum absolute generator-collision z vertex (cm)"}; + Configurable checkIsTrueINELgt0{"checkIsTrueINELgt0", true, "Classify true INEL>0 generator collisions"}; + ConfigurableAxis binsCentGen{"binsCentGen", + {VARIABLE_WIDTH, 0., 0.01, 0.1, 1., 5., 10., 15., 20., 30., 40., 50., 60., 70., 80., 90., 100., 105.}, + "Generator centrality axis"}; + ConfigurableAxis ptAxisGen{"ptAxisGen", {400, 0.f, 20.f}, "#it{p}_{T} (GeV/#it{c})"}; + ConfigurableAxis multNTracksAxis{"multNTracksAxis", {500, 0.f, 5000.f}, "Number of charged particles"}; + ConfigurableAxis impactParameterAxis{"impactParameterAxis", {500, 0.f, 50.f}, "Impact parameter (fm)"}; + Configurable isDaughterCheck{"isDaughterCheck", true, "Require the configured two-body decay"}; + Configurable cfgRapidityCutMinGen{"cfgRapidityCutMinGen", -0.5f, "Minimum generated-particle rapidity"}; + Configurable cfgRapidityCutMaxGen{"cfgRapidityCutMaxGen", 0.5f, "Maximum generated-particle rapidity"}; + Configurable pdgTruthMother{"pdgTruthMother", static_cast(Xi1530Code), "Absolute PDG code of the generated mother"}; + Configurable pdgTruthDaughter1{"pdgTruthDaughter1", static_cast(PdgXiMinus), "Absolute PDG code of the first daughter"}; + Configurable pdgTruthDaughter2{"pdgTruthDaughter2", PDG_t::kPiPlus, "Absolute PDG code of the second daughter"}; + Configurable cfgDoSignalLoss{"cfgDoSignalLoss", false, "Save reference particles for mT-scaling signal-loss studies"}; + } GenCuts; + RCTFlagsChecker genRCTChecker; + + // Keep the established ResoMCParents content compatible with the legacy + // initializer. The additional stable-particle species are written only for + // signal-loss studies and are filtered in fillMCParents. + Partition selectedMCParticles = (nabs(aod::mcparticle::pdgCode) == PdgKStar0) // K*(892)0 + || (nabs(aod::mcparticle::pdgCode) == PdgKStarCharged) // K*(892)+ + || (nabs(aod::mcparticle::pdgCode) == PdgPhi) // phi(1020) + || (nabs(aod::mcparticle::pdgCode) == F0Code980) // f0(980) + || (nabs(aod::mcparticle::pdgCode) == F0Code1370) // f0(1370) + || (nabs(aod::mcparticle::pdgCode) == F0Code1500) // f0(1500) + || (nabs(aod::mcparticle::pdgCode) == F0Code1710) // f0(1710) + || (nabs(aod::mcparticle::pdgCode) == F1Code1285) // f1(1285) + || (nabs(aod::mcparticle::pdgCode) == F1Code1420) // f1(1420) + || (nabs(aod::mcparticle::pdgCode) == F2PrimeCode1525) // f2'(1525) + || (nabs(aod::mcparticle::pdgCode) == PdgRho0) // rho(770)0 + || (nabs(aod::mcparticle::pdgCode) == PdgRhoCharged) // rho(770)+ + || (nabs(aod::mcparticle::pdgCode) == SigmaStarPlusCode) // Sigma(1385)+ + || (nabs(aod::mcparticle::pdgCode) == PdgLambda1520) // Lambda(1520) + || (nabs(aod::mcparticle::pdgCode) == Xi1530Code) // Xi(1530)0 + || (nabs(aod::mcparticle::pdgCode) == PdgK1Plus1270) // K1(1270)+ + || (nabs(aod::mcparticle::pdgCode) == Xi1820NeutralCode) // Xi(1820)0 + || (nabs(aod::mcparticle::pdgCode) == Xi1820MinusCode) // Xi(1820)- + || (nabs(aod::mcparticle::pdgCode) == Omega2012MinusCode) // Omega(2012)- + || (nabs(aod::mcparticle::pdgCode) == PdgProton) // proton + || (nabs(aod::mcparticle::pdgCode) == PdgLambda0) // Lambda0 + || (nabs(aod::mcparticle::pdgCode) == PdgXiMinus) // Xi- + || (nabs(aod::mcparticle::pdgCode) == PdgXi0) // Xi0 + || (nabs(aod::mcparticle::pdgCode) == PdgOmegaMinus); // Omega- + Preslice mcParticlesPerMcCollision = aod::mcparticle::mcCollisionId; - Filter collisionFilter = nabs(aod::collision::posZ) < EventCuts.cfgEvtZvtx; + HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; /** * @brief Initializes the task @@ -150,32 +254,65 @@ struct ResonanceModuleInitializer { mRunNumber = 0; dBz = 0; centrality = 0; - // Determine the multiplicity estimator based on the configuration - multEstimator = 0; + // Determine the centrality estimator based on the configuration. if (EventConfig.cfgMultName.value == "FT0M") { - multEstimator = 0; + multEstimator = CentralityFT0M; } else if (EventConfig.cfgMultName.value == "FT0C") { - multEstimator = 1; + multEstimator = CentralityFT0C; } else if (EventConfig.cfgMultName.value == "FT0A") { - multEstimator = 2; + multEstimator = CentralityFT0A; + } else if (EventConfig.cfgMultName.value == "FV0A") { + multEstimator = CentralityFV0A; + } else { + LOGF(fatal, "Unsupported cfgMultName '%s'; choose FT0M, FT0C, FT0A, or FV0A", EventConfig.cfgMultName.value.c_str()); + } + LOGF(info, "Centrality estimator: %d, %s", multEstimator, EventConfig.cfgMultName.value.c_str()); + if (EventConfig.cfgMultiplicityEstimator.value < MultiplicityNTracksPV || + EventConfig.cfgMultiplicityEstimator.value > MultiplicityFV0A) { + LOG(fatal) << "cfgMultiplicityEstimator must be in the range [0, 6]"; } - LOGF(info, "Mult estimator: %d, %s", multEstimator, EventConfig.cfgMultName.value.c_str()); + LOGF(info, "Stored collision multiplicity estimator: %d", EventConfig.cfgMultiplicityEstimator.value); - // Ensure that only one process type is active at a time - if (doprocessRun3 && doprocessRun2) { - LOG(fatal) << "You cannot run both Run2 and Run3 processes at the same time"; + // Run 2 and Run 3 callbacks require different event-selection semantics. + const bool anyRun2Process = doprocessRun2 || doprocessRun2MC; + const bool anyRun3Process = doprocessRun3 || doprocessRun3MC || doprocessMCgen; + if (anyRun2Process && anyRun3Process) { + LOG(fatal) << "Run 2 and Run 3 processes cannot be enabled in the same ResonanceModuleInitializer"; } - if (doprocessRun2MC && doprocessRun3MC) { - LOG(fatal) << "You cannot run both Run2 and Run3 MC processes at the same time"; + if (doprocessRun2 && doprocessRun2MC) { + LOG(fatal) << "processRun2MC writes both ResoCollisions and ResoMCCollisions_001; do not enable processRun2 with it"; } - if (CCDB.cfgBypassCollIndexFill) { - LOG(fatal) << "cfgBypassCollIndexFill is incompatible with ResonanceDaughterInitializer"; + if (doprocessRun3 && doprocessRun3MC) { + LOG(fatal) << "processRun3MC writes both ResoCollisions and ResoMCCollisions_001; do not enable processRun3 with it"; + } + const int enabledGenMultiplicityEstimators = static_cast(GenCuts.cfgGenMult05.value) + + static_cast(GenCuts.cfgGenMult10.value) + + static_cast(GenCuts.cfgGenMultFT0M.value) + + static_cast(GenCuts.cfgGenMultFT0C.value) + + static_cast(GenCuts.cfgGenMultFV0A.value); + if ((doprocessMCgen || doprocessRun2MC || doprocessRun3MC) && enabledGenMultiplicityEstimators > 1) { + LOG(fatal) << "Only one generator multiplicity estimator can be enabled: cfgGenMult05, cfgGenMult10, cfgGenMultFT0M, cfgGenMultFT0C, or cfgGenMultFV0A"; + } + if (doprocessMCgen) { + if (GenCuts.cfgGenMultPercentile && multEstimator != CentralityFT0M && + multEstimator != CentralityFT0C && multEstimator != CentralityFV0A) { + LOGF(fatal, "cfgGenMultPercentile supports cfgMultName=FT0M, FT0C, or FV0A"); + } + if (GenCuts.isZvtxcutGen && + (!std::isfinite(GenCuts.cutzvertexGen.value) || GenCuts.cutzvertexGen.value <= 0.f)) { + LOG(fatal) << "cutzvertexGen must be finite and positive when the generator vertex cut is enabled"; + } + if (!std::isfinite(GenCuts.cfgRapidityCutMinGen.value) || + !std::isfinite(GenCuts.cfgRapidityCutMaxGen.value) || + GenCuts.cfgRapidityCutMinGen.value >= GenCuts.cfgRapidityCutMaxGen.value) { + LOG(fatal) << "Generator rapidity limits must be finite and satisfy cfgRapidityCutMinGen < cfgRapidityCutMaxGen"; + } } // Initialize event selection cuts based on the process type - if (doprocessRun2) { + if (anyRun2Process) { colCuts.setCuts(EventCuts.cfgEvtZvtx, EventCuts.cfgEvtTriggerCheck, EventCuts.cfgEvtOfflineCheck, false); - } else if (doprocessRun3) { + } else if (anyRun3Process) { colCuts.setCuts(EventCuts.cfgEvtZvtx, EventCuts.cfgEvtTriggerCheck, EventCuts.cfgEvtOfflineCheck, true, false, EventCuts.cfgEvtOccupancyInTimeRange); } colCuts.init(&qaRegistry); @@ -189,7 +326,31 @@ struct ResonanceModuleInitializer { colCuts.setApplyRun2AliEventCuts(EventCuts.cfgEvtRun2AliEventCuts); colCuts.setApplyRun2INELgtZERO(EventCuts.cfgEvtRun2INELgtZERO); - rctChecker.init(EventCuts.cfgEvtRCTFlagCheckerLabel, EventCuts.cfgEvtRCTFlagCheckerZDCCheck, EventCuts.cfgEvtRCTFlagCheckerLimitAcceptAsBad); + if (EventConfig.cfgFillDetailedQA && (doprocessRun3 || doprocessRun3MC)) { + AxisSpec selectionStageAxis{DetailedQAStages, -0.5f, static_cast(DetailedQAStages) - 0.5f, "Passed event-selection stage"}; + AxisSpec vertexAxis{EventConfig.cfgVtxBins, "Collision vertex z (cm)"}; + AxisSpec centralityAxis{EventConfig.binsCent, "Centrality (%)"}; + AxisSpec multiplicityAxis{EventConfig.binsMultiplicity, "Multiplicity"}; + qaRegistry.add("Event/h4EventSelectionDetail", "Event-selection cut flow", kTHnSparseD, + {selectionStageAxis, vertexAxis, centralityAxis, multiplicityAxis}); + + auto detailedQA = qaRegistry.get(HIST("Event/h4EventSelectionDetail")); + auto cutCounts = qaRegistry.get(HIST("CollCutCounts")); + for (int stage = o2::analysis::CollisonCuts::kAllEvent; + stage <= o2::analysis::CollisonCuts::kAllpassed; ++stage) { + detailedQA->GetAxis(0)->SetBinLabel(stage + 1, cutCounts->GetXaxis()->GetBinLabel(colCuts.binLabel(stage))); + } + detailedQA->GetAxis(0)->SetBinLabel(DetailedQARCTStage + 1, "RCT"); + } + + recoRCTChecker.init(EventCuts.cfgEvtRCTFlagCheckerLabel, + EventCuts.cfgEvtRCTFlagCheckerZDCCheck, + EventCuts.cfgEvtRCTFlagCheckerLimitAcceptAsBad, + EventCuts.cfgEvtRCTCheckTableValidity.value); + genRCTChecker.init(EventCuts.cfgEvtRCTFlagCheckerLabel, + EventCuts.cfgEvtRCTFlagCheckerZDCCheck, + EventCuts.cfgEvtRCTFlagCheckerLimitAcceptAsBad, + GenCuts.cfgGenRCTCheckTableValidity.value); // Configure CCDB access if not bypassed if (!EventConfig.cfgBypassCCDB) { @@ -201,11 +362,26 @@ struct ResonanceModuleInitializer { ccdb->setCreatedNotAfter(now); // TODO must become global parameter from the train creation time } - // Initialize QA histograms if required - if (EventConfig.cfgFillQA && (doprocessRun3MC || doprocessRun2MC)) { - AxisSpec centAxis = {EventConfig.binsCent, "Centrality (%)"}; - AxisSpec idxMCAxis = {26, -0.5, 25.5, "Index"}; - qaRegistry.add("Event/hMCEventIndices", "hMCEventIndices", kTH2D, {centAxis, idxMCAxis}); + if (doprocessMCgen) { + constexpr std::array MCEventLabels{"All", "z vertex", "BC RCT", "INEL", "INEL>0"}; + AxisSpec centAxisGen = {GenCuts.binsCentGen, "Centrality (%)"}; + AxisSpec eventTypeAxis = {2, 0.f, 2.f, "Event type"}; + qaRegistry.add("EventGen/hNEventsMC", "Generator event selection", kTH1D, {{5, 0.f, 5.f}}); + auto eventCounter = qaRegistry.get(HIST("EventGen/hNEventsMC")); + for (std::size_t i = 0; i < MCEventLabels.size(); ++i) { + eventCounter->GetXaxis()->SetBinLabel(static_cast(i + 1), MCEventLabels[i]); + } + qaRegistry.add("EventGen/h5ResonanceTruth", "Generated resonance", kTHnSparseD, + {eventTypeAxis, GenCuts.ptAxisGen, centAxisGen, GenCuts.multNTracksAxis, GenCuts.impactParameterAxis}); + qaRegistry.add("EventGen/h5ResonanceTruthAnti", "Generated anti-resonance", kTHnSparseD, + {eventTypeAxis, GenCuts.ptAxisGen, centAxisGen, GenCuts.multNTracksAxis, GenCuts.impactParameterAxis}); + qaRegistry.add("EventGen/hZCollisionGen", "Generator collision z vertex", kTH1D, {{100, -20.f, 20.f}}); + qaRegistry.add("EventGen/h4MultCent_genMC", "Generator-event multiplicity and centrality", kTHnSparseD, + {eventTypeAxis, centAxisGen, GenCuts.multNTracksAxis, GenCuts.impactParameterAxis}); + qaRegistry.add("EventGen/h4MultCent_recMC", "Reconstructed-event multiplicity and centrality", kTHnSparseD, + {eventTypeAxis, centAxisGen, GenCuts.multNTracksAxis, GenCuts.impactParameterAxis}); + qaRegistry.add("EventGen/h2CentralityVsMultMC", "Representative reconstructed centrality vs generator multiplicity", kTH2D, + {centAxisGen, GenCuts.multNTracksAxis}); } } @@ -214,7 +390,8 @@ struct ResonanceModuleInitializer { * * @param bc BC iterator */ - void initCCDB(aod::BCsWithTimestamps::iterator const& bc) // Simple copy from LambdaKzeroFinder.cxx + template + void initCCDB(BCType const& bc) // Simple copy from LambdaKzeroFinder.cxx { if (EventConfig.cfgBypassCCDB) { return; @@ -258,203 +435,352 @@ struct ResonanceModuleInitializer { LOGF(info, "Bz set to %f for run: ", dBz, mRunNumber); } - /** - * @brief Checks if the collision is INEL>0 - * - * @tparam MCPart Type of MC particles - * @param mcparts MC particles - * @return true if INEL>0, false otherwise - */ - template - bool isTrueINEL0(MCPart const& mcparts) - { - for (auto const& mcparticle : mcparts) { - if (!mcparticle.isPhysicalPrimary()) { - continue; - } - auto p = pdg->GetParticle(mcparticle.pdgCode()); - if (p != nullptr) { - if (std::abs(p->Charge()) >= MinimumChargedParticleCharge) { - if (std::abs(mcparticle.eta()) < 1) { - return true; - } - } - } - } - return false; - } - /** * @brief Centrality estimator selection * * @tparam ResoColl Type of resonance collision - * @tparam isMC Boolean indicating if it's MC * @param resoEvents Resonance events * @return Centrality value */ - template + template float centEst(ResoColl const& resoEvents) { - float returnValue = -999.0; switch (multEstimator) { - case 0: - returnValue = resoEvents.centFT0M(); - break; - case 1: - if constexpr (isMC) { - LOG(fatal) << "CentFT0C is not available for MC"; - return returnValue; - } else { - returnValue = resoEvents.centFT0C(); - break; - } - case 2: - if constexpr (isMC) { - LOG(fatal) << "CentFT0A is not available for MC"; - return returnValue; - } else { - returnValue = resoEvents.centFT0A(); - break; - } + case CentralityFT0M: + return resoEvents.centFT0M(); + case CentralityFT0C: + return resoEvents.centFT0C(); + case CentralityFT0A: + return resoEvents.centFT0A(); + case CentralityFV0A: + return resoEvents.centFV0A(); default: - returnValue = resoEvents.centFT0M(); - break; + return -999.f; + } + } + + /** + * @brief Returns the configured reconstructed multiplicity estimator + */ + template + float collisionMultiplicity(CollisionType const& collision) + { + switch (EventConfig.cfgMultiplicityEstimator.value) { + case MultiplicityNTracksPV: + return collision.multNTracksPV(); + case MultiplicityNTracksPVeta1: + return collision.multNTracksPVeta1(); + case MultiplicityNTracksPVetaHalf: + return collision.multNTracksPVetaHalf(); + case MultiplicityFT0M: + return collision.multFT0M(); + case MultiplicityFT0A: + return collision.multFT0A(); + case MultiplicityFT0C: + return collision.multFT0C(); + case MultiplicityFV0A: + return collision.multFV0A(); + default: + return -1.f; + } + } + + /// Fill the detailed Run 3 collision QA at one passed selection stage. + template + void fillDetailedCollisionQA(CollisionType const& collision, int selectionStage) + { + qaRegistry.fill(HIST("Event/h4EventSelectionDetail"), + selectionStage, + collision.posZ(), + centEst(collision), + collisionMultiplicity(collision)); + } + + /// Reproduce the configured Run 3 collision cut flow for detailed QA only. + /// The authoritative event decision remains CollisonCuts::isSelected(). + template + void fillDetailedRun3SelectionQA(CollisionType const& collision) + { + fillDetailedCollisionQA(collision, o2::analysis::CollisonCuts::kAllEvent); + if (std::abs(collision.posZ()) > EventCuts.cfgEvtZvtx.value) { + return; + } + fillDetailedCollisionQA(collision, o2::analysis::CollisonCuts::kFlagZvertex); + +// Keep this QA-only mapping synchronized with CollisonCuts without exposing +// its internal selection registry. +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -- X-macro interface of EventSelectionFlagsMapping.def +#define EVSEL_FLAG(enumVal, member, defaultVal, evtSelEnum, setter, getter, label, desc) \ + if (colCuts.getSelection(o2::analysis::CollisonCuts::evtSelEnum)) { \ + if (!collision.selection_bit(o2::aod::evsel::enumVal)) { \ + return; \ + } \ + fillDetailedCollisionQA(collision, o2::analysis::CollisonCuts::evtSelEnum); \ + } +#include "PWGLF/Utils/EventSelectionFlagsMapping.def" // NOLINT(build/include) +#undef EVSEL_FLAG + + if (EventCuts.cfgEvtOfflineCheck.value && !collision.sel8()) { + return; + } + fillDetailedCollisionQA(collision, o2::analysis::CollisonCuts::kFlagSel8); + + if (EventCuts.cfgEvtOccupancyInTimeRange.value > 0 && + collision.trackOccupancyInTimeRange() > EventCuts.cfgEvtOccupancyInTimeRange.value) { + return; } - return returnValue; + fillDetailedCollisionQA(collision, o2::analysis::CollisonCuts::kFlagOccupancy); + fillDetailedCollisionQA(collision, o2::analysis::CollisonCuts::kAllpassed); } - using GenMCCollisions = soa::Join; - float centEstMC(const GenMCCollisions::iterator& collision) { return centEst(collision); } + + using GenMCCollisions = soa::Join; + using Run3MCCollisions = soa::Join; + using Run2MCCollisions = soa::Join; + using GenRecoCollisions = soa::Join; + using BCsWithRCT = soa::Join; /** - * @brief Fills MC particles + * @brief Applies the configured RCT selection to a reconstructed collision * - * @tparam CollisionType Type of collision - * @tparam SelectedMCPartType Type of selected MC particles - * @tparam TotalMCParts Type of total MC particles - * @param collision Collision data - * @param mcParts Selected MC particles - * @param mcParticles Total MC particles + * The collision-level mode reads the RCT value stored in EVSEL. The BC-level + * mode reads the value directly from the nominal BC referenced by collision. */ - template - void fillMCParticles(CollisionType collision, SelectedMCPartType const& mcParts, TotalMCParts const& mcParticles) + template + bool isRecoRCTSelected(CollisionType const& collision) { - for (auto const& mcPart : mcParts) { - std::vector daughterPDGs; - if (mcPart.has_daughters()) { - auto daughter01 = mcParticles.rawIteratorAt(mcPart.daughtersIds()[0] - mcParticles.offset()); - auto daughter02 = mcParticles.rawIteratorAt(mcPart.daughtersIds()[1] - mcParticles.offset()); + if (!EventCuts.cfgEvtUseRCTFlagChecker.value) { + return true; + } + if (!EventCuts.cfgEvtBCRCT.value) { + return recoRCTChecker(collision); + } + const auto bc = collision.template bc_as(); + return recoRCTChecker(bc); + } + + /// Apply the reconstructed Run 3 event and RCT selections. Detailed cut-flow + /// QA is evaluated independently and never controls the event decision. + template + bool isRun3CollisionSelected(CollisionType const& collision) + { + if (EventConfig.cfgFillDetailedQA) { + fillDetailedRun3SelectionQA(collision); + } + if (!colCuts.isSelected(collision, EventConfig.cfgFillQA) || !isRecoRCTSelected(collision)) { + return false; + } + if (EventConfig.cfgFillDetailedQA) { + fillDetailedCollisionQA(collision, DetailedQARCTStage); + } + return true; + } + + /** + * @brief Fills generator-level resonance QA + * + * @tparam MCParticlesType Type of MC-particle group + * @param mcParticles MC particles grouped by generator collision + * @param generatorCentrality Generator or representative reconstructed centrality + * @param multiplicity Generator-level charged-particle multiplicity + * @param impactParameter Generator collision impact parameter + * @param eventType INEL/INEL>0 category + */ + template + void fillMCGenParticles(MCParticlesType const& mcParticles, + float generatorCentrality, + float multiplicity, + float impactParameter, + int eventType) + { + for (auto const& mcPart : mcParticles) { + if (std::abs(mcPart.pdgCode()) != std::abs(GenCuts.pdgTruthMother.value)) { + continue; + } + if (mcPart.y() <= GenCuts.cfgRapidityCutMinGen || mcPart.y() >= GenCuts.cfgRapidityCutMaxGen) { + continue; + } + + std::array daughterPDGs{-1, -1}; + const bool hasDaughters = mcPart.has_daughters(); + const auto daughterIds = mcPart.daughtersIds(); + if (hasDaughters) { + auto daughter01 = mcParticles.rawIteratorAt(daughterIds[0] - mcParticles.offset()); + auto daughter02 = mcParticles.rawIteratorAt(daughterIds[1] - mcParticles.offset()); daughterPDGs = {daughter01.pdgCode(), daughter02.pdgCode()}; + } + if (GenCuts.isDaughterCheck) { + const int daughter1 = std::abs(GenCuts.pdgTruthDaughter1.value); + const int daughter2 = std::abs(GenCuts.pdgTruthDaughter2.value); + const int firstDaughterPDG = std::abs(daughterPDGs[0]); + const int secondDaughterPDG = std::abs(daughterPDGs[1]); + // Match the configured decay to two distinct daughter slots. This is + // important when both configured absolute PDGs are equal (e.g. K+K-): + // one matching daughter must not satisfy both requirements. + const bool matchesConfiguredDecay = + (firstDaughterPDG == daughter1 && secondDaughterPDG == daughter2) || + (firstDaughterPDG == daughter2 && secondDaughterPDG == daughter1); + if (!matchesConfiguredDecay) { + continue; + } + } + + if (mcPart.pdgCode() > 0) { + qaRegistry.fill(HIST("EventGen/h5ResonanceTruth"), eventType, mcPart.pt(), generatorCentrality, multiplicity, impactParameter); } else { - daughterPDGs = {-1, -1}; + qaRegistry.fill(HIST("EventGen/h5ResonanceTruthAnti"), eventType, mcPart.pt(), generatorCentrality, multiplicity, impactParameter); + } + } + } + + /** + * @brief Fills generated resonance parents for one reduced collision + * + * @tparam SelectedMCParticlesType Type of the selected MC-particle slice + * @tparam MCParticlesType Type of the complete MC-particle table + * @param reducedCollisionId Reduced collision referenced by the output rows + * @param selectedParents Selected parent particles in the associated MC collision + * @param mcParticles Complete MC-particle table used to resolve daughter indices + * + * The source MC-particle global index is persisted as a scalar in + * ResoMCParents_001; it is not a relation requiring McParticles at merge time. + */ + template + void fillMCParents(int64_t reducedCollisionId, + SelectedMCParticlesType const& selectedParents, + MCParticlesType const& mcParticles) + { + for (auto const& mcPart : selectedParents) { + if (!GenCuts.cfgDoSignalLoss) { + const int absPdg = std::abs(mcPart.pdgCode()); + if (absPdg == PdgProton || absPdg == PdgLambda0 || absPdg == PdgXiMinus || absPdg == PdgXi0 || absPdg == PdgOmegaMinus) { + continue; + } + } + + std::array daughterPDGs{-1, -1}; + if (mcPart.has_daughters()) { + const auto daughter1 = mcParticles.rawIteratorAt(mcPart.daughtersIds()[0] - mcParticles.offset()); + const auto daughter2 = mcParticles.rawIteratorAt(mcPart.daughtersIds()[1] - mcParticles.offset()); + daughterPDGs = {daughter1.pdgCode(), daughter2.pdgCode()}; } - reso2mcparents(collision.globalIndex(), + reso2mcparents(reducedCollisionId, mcPart.globalIndex(), mcPart.pdgCode(), - daughterPDGs[0], daughterPDGs[1], + daughterPDGs[0], + daughterPDGs[1], mcPart.isPhysicalPrimary(), mcPart.producedByGenerator(), mcPart.pt(), mcPart.px(), mcPart.py(), mcPart.pz(), - mcPart.eta(), - mcPart.phi(), - mcPart.y()); - daughterPDGs.clear(); + mcPart.y(), + mcPart.e(), + mcPart.statusCode()); } } /** - * @brief Fills MC collision data - * - * @tparam isRun2 Boolean indicating if it's Run2 - * @tparam MCCol Type of MC collision - * @tparam MCPart Type of MC particles - * @param mccol MC collision data - * @param mcparts MC particles + * @brief Returns the configured generator-level multiplicity estimator */ - template - void fillMCCollision(MCCol const& mccol, MCPart const& mcparts) - { - const auto& mcColg = mccol.template mcCollision_as(); - float mcCent = 999.0; - if constexpr (isRun2) { - if (EventConfig.cfgCentralityMC == MCCentralityRecoEstimator) { - mcCent = mccol.centRun2V0M(); - } else { - mcCent = mcColg.impactParameter(); - } - } else { - if (EventConfig.cfgCentralityMC == MCCentralityRecoEstimator) { - mcCent = centEst(mccol); - } else if (EventConfig.cfgCentralityMC == MCCentralityGeneratorEstimator) { - mcCent = centEstMC(mcColg); - } else if (EventConfig.cfgCentralityMC == MCCentralityImpactParameterEstimator) { - mcCent = mcColg.impactParameter(); - } + template + float getMCMultiplicity(MCCollision const& mcCollision) + { + if (GenCuts.cfgGenMult05) { + return mcCollision.multMCNParticlesEta05(); + } + if (GenCuts.cfgGenMult10) { + return mcCollision.multMCNParticlesEta10(); + } + if (GenCuts.cfgGenMultFT0M) { + return mcCollision.multMCFT0A() + mcCollision.multMCFT0C(); + } + if (GenCuts.cfgGenMultFT0C) { + return mcCollision.multMCFT0C(); } - const bool inVtx10 = !(std::abs(mcColg.posZ()) > MCVertexZMax); - bool isTrueINELgt0 = isTrueINEL0(mcparts); - bool isTriggerTVX = mccol.selection_bit(aod::evsel::kIsTriggerTVX); - bool isSel8 = mccol.sel8(); - bool isSelected = colCuts.isSelected(mccol, EventConfig.cfgFillQA); - resoMCCollisions(inVtx10, isTrueINELgt0, isTriggerTVX, isSel8, isSelected, mcCent, -1.0f); + if (GenCuts.cfgGenMultFV0A) { + return mcCollision.multMCFV0A(); + } + return -1.f; + } - if (EventConfig.cfgFillQA) { - // QA for trigger efficiency - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kINEL); - if (inVtx10) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kINEL10); - } - if (isTrueINELgt0) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kINELg0); - } - if (inVtx10 && isTrueINELgt0) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kINELg010); - } + /** + * @brief Returns the configured generator-level centrality percentile + */ + template + float getMCCentrality(MCCollision const& mcCollision) const + { + if (!GenCuts.cfgGenMultPercentile.value) { + return 100.5f; + } + switch (multEstimator) { + case CentralityFT0M: + return mcCollision.centFT0M(); + case CentralityFT0C: + return mcCollision.centFT0C(); + case CentralityFV0A: + return mcCollision.centFV0A(); + default: + return 100.5f; + } + } - // TVX MB trigger - if (isTriggerTVX) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kTrig); - } - if (isTriggerTVX && inVtx10) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kTrig10); - } - if (isTriggerTVX && isTrueINELgt0) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kTrigINELg0); - } - if (isTriggerTVX && isTrueINELgt0 && inVtx10) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kTrigINELg010); - } + /** + * @brief Fills the generator-only MC collision extension and optional source link + * + * Accepting only the generator collision here prevents reconstructed event + * selection state from accidentally entering ResoMCCollisions_001. + */ + template + void fillMCCollision001(MCCollision const& mcCollision) + { + const float mcMultiplicity = getMCMultiplicity(mcCollision); + const bool inTrueVtx10 = std::abs(mcCollision.posZ()) < MCVertexZMax; + // Keep the generator-level definition identical to MultsExtraMC: + // at least one physical-primary charged particle within |eta| < 1. + const bool isTrueINELgt0 = mcCollision.isInelGt0(); + resoMCCollisions001(inTrueVtx10, + isTrueINELgt0, + mcCollision.impactParameter(), + mcMultiplicity); + if (GenCuts.cfgFillMCCollisionSoftLink) { + resoMCCollisionIds(mcCollision.globalIndex()); + } + } - // Sel8 event selection - if (isSel8) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kSel8); - } - if (isSel8 && inVtx10) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kSel810); - } - if (isSel8 && isTrueINELgt0) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kSel8INELg0); - } - if (isSel8 && isTrueINELgt0 && inVtx10) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kSel8INELg010); - } + /// Write the Run 3 base collision, optional soft link, and scalar grouping key. + template + void fillRun3Collision(CollisionType const& collision) + { + const bool isRecINELgt0 = collision.isInelGt0(); + centrality = centEst(collision); + resoCollisions(collisionMultiplicity(collision), + collision.posX(), + collision.posY(), + collision.posZ(), + centrality, + dBz, + isRecINELgt0); + resoCollisionColls(collision.globalIndex()); + resoCollisionGroups001(collision.globalIndex()); + } - // CollisionCuts selection - if (isSelected) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kAllCuts); - } - if (isSelected && inVtx10) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kAllCuts10); - } - if (isSelected && isTrueINELgt0) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kAllCutsINELg0); - } - if (isSelected && isTrueINELgt0 && inVtx10) { - qaRegistry.fill(HIST("Event/hMCEventIndices"), mcCent, aod::resocollision::kAllCutsINELg010); - } - } + /// Write the Run 2 base collision, optional soft link, and scalar grouping key. + template + void fillRun2Collision(CollisionType const& collision) + { + centrality = collision.centRun2V0M(); + // The configured Run 3 estimators are not available in the Run 2 input + // schema. Preserve the previous zero-filled Run 2 behaviour. + resoCollisions(0.f, + collision.posX(), + collision.posY(), + collision.posZ(), + centrality, + dBz, + 0); + resoCollisionColls(collision.globalIndex()); + resoCollisionGroups001(collision.globalIndex()); } /** @@ -473,27 +799,19 @@ struct ResonanceModuleInitializer { * @param collision Collision data * @param bc BC data */ - void processRun3(soa::Filtered::iterator const& collision, - aod::BCsWithTimestamps const&) + void processRun3(aod::ResoCollisionCandidates::iterator const& collision, + BCsWithRCT const&) { - auto bc = collision.bc_as(); + auto bc = collision.bc_as(); initCCDB(bc); // Default event selection - if (!colCuts.isSelected(collision, EventConfig.cfgFillQA)) { - return; - } - if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) { + if (!isRun3CollisionSelected(collision)) { return; } if (EventConfig.cfgFillQA) { colCuts.fillQA(collision); } - const bool isRecINELgt0 = collision.isInelGt0(); - centrality = centEst(collision); - - resoCollisions(collision.multNTracksPV(), collision.multNTracksPVeta1(), collision.multNTracksPVetaHalf(), collision.posX(), collision.posY(), collision.posZ(), centEst(collision), dBz, isRecINELgt0); - resoCollisionColls(collision.globalIndex()); - resoCollisionGroups(collision.globalIndex()); + fillRun3Collision(collision); } PROCESS_SWITCH(ResonanceModuleInitializer, processRun3, "Default process for RUN3", false); @@ -503,7 +821,7 @@ struct ResonanceModuleInitializer { * @param collision Collision data * @param bc BC data */ - void processRun2(soa::Filtered::iterator const& collision, + void processRun2(aod::ResoRun2CollisionCandidates::iterator const& collision, aod::BCsWithRun2Info const&) { // auto bc = collision.bc_as(); @@ -514,41 +832,154 @@ struct ResonanceModuleInitializer { if (EventConfig.cfgFillQA) { colCuts.fillQARun2(collision); } - centrality = collision.centRun2V0M(); - - resoCollisions(0, 0, 0, collision.posX(), collision.posY(), collision.posZ(), centrality, dBz, 0); - resoCollisionColls(collision.globalIndex()); - resoCollisionGroups(collision.globalIndex()); + fillRun2Collision(collision); } PROCESS_SWITCH(ResonanceModuleInitializer, processRun2, "process for RUN2", false); + /** + * @brief Processes generator-level MC event and resonance QA + * + * The original MC collision is the grouping key. MC particles are therefore + * grouped automatically, while reconstructed collisions arrive as a 0..N + * SmallGroup through their McCollisionLabels relation. This auxiliary + * callback intentionally fills generator-level QA only and does not write + * reduced AOD tables. RCT quality is evaluated through the generator + * collision's associated BC because it is a run-condition property. + */ + void processMCgen(GenMCCollisions::iterator const& mcCollision, + aod::McParticles const& mcParticles, + soa::SmallGroups const& collisions, + BCsWithRCT const&) + { + auto bc = mcCollision.bc_as(); + initCCDB(bc); + + const auto getReconstructedCentrality = [&](auto const& collision) { + return centEst(collision); + }; + + const float generatorCentrality = getMCCentrality(mcCollision); + const float impactParameter = mcCollision.impactParameter(); + const float multiplicity = getMCMultiplicity(mcCollision); + + qaRegistry.fill(HIST("EventGen/hNEventsMC"), 0.5); + if (GenCuts.isZvtxcutGen && std::abs(mcCollision.posZ()) > GenCuts.cutzvertexGen) { + return; + } + qaRegistry.fill(HIST("EventGen/hNEventsMC"), 1.5); + if (GenCuts.cfgGenBCRCT && !genRCTChecker(bc)) { + return; + } + qaRegistry.fill(HIST("EventGen/hNEventsMC"), 2.5); + qaRegistry.fill(HIST("EventGen/hZCollisionGen"), mcCollision.posZ()); + + int eventType = 0; + qaRegistry.fill(HIST("EventGen/hNEventsMC"), 3.5); + if (GenCuts.checkIsTrueINELgt0 && mcCollision.isInelGt0()) { + eventType = 1; + qaRegistry.fill(HIST("EventGen/hNEventsMC"), 4.5); + } + + bool hasSelectedRecoCollision = false; + int largestNContributors = -1; + float reconstructedCentrality = 100.5f; + for (auto const& collision : collisions) { + if (!isRecoRCTSelected(collision)) { + continue; + } + if (!colCuts.isSelected(collision, false)) { + continue; + } + const int nContributors = static_cast(collision.multPVTotalContributors()); + if (nContributors > largestNContributors) { + largestNContributors = nContributors; + reconstructedCentrality = getReconstructedCentrality(collision); + } + hasSelectedRecoCollision = true; + } + + if (GenCuts.cfgGenMultPercentile) { + fillMCGenParticles(mcParticles, generatorCentrality, multiplicity, impactParameter, eventType); + qaRegistry.fill(HIST("EventGen/h4MultCent_genMC"), eventType, generatorCentrality, multiplicity, impactParameter); + } else { + fillMCGenParticles(mcParticles, reconstructedCentrality, multiplicity, impactParameter, eventType); + qaRegistry.fill(HIST("EventGen/h4MultCent_genMC"), eventType, reconstructedCentrality, multiplicity, impactParameter); + qaRegistry.fill(HIST("EventGen/h2CentralityVsMultMC"), reconstructedCentrality, multiplicity); + } + if (hasSelectedRecoCollision) { + qaRegistry.fill(HIST("EventGen/h4MultCent_recMC"), eventType, reconstructedCentrality, multiplicity, impactParameter); + } + } + PROCESS_SWITCH(ResonanceModuleInitializer, processMCgen, "Process generator-level MC QA", false); + /** * @brief Processes Run3 MC data * + * Reconstructed collisions pass the same event selection and QA sequence as + * Run 3 data before the reduced collision and its MC extension are written. + * * @param collision Collision data - * @param mcParticles MC particles * @param mcCollisions MC collisions + * @param mcParticles MC particles used to fill reduced resonance parents */ - void processRun3MC(soa::Filtered::iterator const& collision, - aod::McParticles const& mcParticles, GenMCCollisions const&) + void processRun3MC(aod::ResoCollisionCandidatesMC::iterator const& collision, + Run3MCCollisions const&, + aod::McParticles const& mcParticles, + BCsWithRCT const&) { - if (EventCuts.cfgEvtUseRCTFlagChecker && !rctChecker(collision)) { + auto bc = collision.bc_as(); + initCCDB(bc); + if (!isRun3CollisionSelected(collision)) { return; } - fillMCCollision(collision, mcParticles); + if (EventConfig.cfgFillQA) { + colCuts.fillQA(collision); + } + if (!collision.has_mcCollision()) { + return; + } + const auto& mcCollision = collision.mcCollision_as(); + + // ResoMCCollisions_001 is a positional extension of ResoCollisions. When + // enabled, ResoMCCollisionIds is written in the same callback and is 1:1. + fillRun3Collision(collision); + const int64_t reducedCollisionId = resoCollisions.lastIndex(); + fillMCCollision001(mcCollision); + + // A generator collision can be associated with more than one reconstructed + // collision. Write one parent set for each reduced collision, as in the + // legacy collision-wise producer, so ResoCollisionId remains unambiguous. + auto selectedParents = selectedMCParticles->sliceBy(mcParticlesPerMcCollision, mcCollision.globalIndex()); + fillMCParents(reducedCollisionId, selectedParents, mcParticles); } PROCESS_SWITCH(ResonanceModuleInitializer, processRun3MC, "process MC for RUN3", false); /** * @brief Processes Run2 MC data * + * Reconstructed collisions pass the same event selection and QA sequence as + * Run 2 data before the reduced collision and its MC extension are written. + * * @param collision Collision data - * @param mcParticles MC particles */ - void processRun2MC(soa::Filtered::iterator const& collision, - aod::McParticles const& mcParticles) + void processRun2MC(aod::ResoRun2CollisionCandidatesMC::iterator const& collision, + Run2MCCollisions const&) { - fillMCCollision(collision, mcParticles); + if (!colCuts.isSelected(collision, EventConfig.cfgFillQA)) { + return; + } + if (EventConfig.cfgFillQA) { + colCuts.fillQARun2(collision); + } + if (!collision.has_mcCollision()) { + return; + } + const auto& mcCollision = collision.mcCollision_as(); + + // Keep the base and MC extension one-to-one; the optional source link is + // written by fillMCCollision001 in the same order. + fillRun2Collision(collision); + fillMCCollision001(mcCollision); } PROCESS_SWITCH(ResonanceModuleInitializer, processRun2MC, "process MC for RUN2", false); }; @@ -572,8 +1003,107 @@ struct ResonanceDaughterInitializer { static constexpr int TrackSelectionGlobalWoDCA = 3; static constexpr int TrackSelectionQuality = 4; static constexpr int TrackSelectionInAcceptance = 5; + static constexpr int PairGateModeConfigured = 0; + static constexpr int PairGateModeEither = 1; static constexpr float MomentumQuantizationScale = 1000.f; static constexpr std::size_t StoredMCRelationCount = 2; + static constexpr std::size_t MaxCandidateDaughters = 3; + + /// Selected-candidate state and the optional global daughter-ID veto set. + /// By default only candidate existence is recorded and daughter reuse is + /// rejected later for each concrete pair through the stored trackId. + struct SelectedCandidateDaughters { + std::vector allDaughterIds; + bool hasSelectedCandidate = false; + bool useGlobalDaughterVeto = false; + + explicit SelectedCandidateDaughters(bool globalDaughterVeto = false) + : useGlobalDaughterVeto(globalDaughterVeto) + { + } + + void addCandidate() + { + hasSelectedCandidate = true; + } + + template + void addCandidate(std::array const& daughterIds) + { + static_assert(DaughterCount <= MaxCandidateDaughters); + allDaughterIds.insert(allDaughterIds.end(), daughterIds.begin(), daughterIds.end()); + hasSelectedCandidate = true; + } + + void finalize() + { + if (!useGlobalDaughterVeto) { + return; + } + std::sort(allDaughterIds.begin(), allDaughterIds.end()); + allDaughterIds.erase(std::unique(allDaughterIds.begin(), allDaughterIds.end()), allDaughterIds.end()); + } + + [[nodiscard]] bool accepts(int64_t trackId) const + { + if (!hasSelectedCandidate) { + return false; + } + if (useGlobalDaughterVeto) { + return !std::binary_search(allDaughterIds.begin(), allDaughterIds.end(), trackId); + } + return true; + } + }; + + /// Producer-side track retention for the candidate types enabled by a callback. + struct PairTrackSelection { + SelectedCandidateDaughters v0Candidates; + SelectedCandidateDaughters cascadeCandidates; + bool useV0Candidates = false; + bool useCascadeCandidates = false; + bool useGlobalDaughterVeto = false; + + explicit PairTrackSelection(bool globalDaughterVeto = false) + : v0Candidates(globalDaughterVeto), + cascadeCandidates(globalDaughterVeto), + useGlobalDaughterVeto(globalDaughterVeto) + { + } + + template + bool operator()(TrackType const& track) const + { + if (!useGlobalDaughterVeto) { + return (useV0Candidates && v0Candidates.hasSelectedCandidate) || + (useCascadeCandidates && cascadeCandidates.hasSelectedCandidate); + } + + const auto trackId = static_cast(track.globalIndex()); + bool hasCandidate = false; + if (useV0Candidates && v0Candidates.hasSelectedCandidate) { + hasCandidate = true; + if (!v0Candidates.accepts(trackId)) { + return false; + } + } + if (useCascadeCandidates && cascadeCandidates.hasSelectedCandidate) { + hasCandidate = true; + if (!cascadeCandidates.accepts(trackId)) { + return false; + } + } + return hasCandidate; + } + }; + + struct KeepAllTracks { + template + bool operator()(TrackType const&) const + { + return true; + } + }; UltraMicroPidSpecies ultraMicroPidSpecies = UltraMicroPidSpecies::Pion; bool warnedUltraMicroMomentumRange = false; @@ -586,8 +1116,9 @@ struct ResonanceDaughterInitializer { Preslice cascadesMCPerCollision = aod::cascdata::collisionId; Produces reso2trks; ///< Output table for resonance tracks Produces resoTrackTracks; ///< Output table for original track row IDs - Produces reso2microtrks; ///< Output table for resonance microtracks - Produces resoMicroTrackTracks; ///< Output table for original microtrack row IDs + Produces reso2microtrks; ///< Output table for resonance microtracks + Produces resoMicroTrackTracks; ///< Positional original-track soft links for microtracks + Produces reso2mcmicrotrks; ///< Positional MC extension for resonance microtracks Produces reso2ultramicrotrks; ///< Output table for resonance ultra-microtracks Produces resoUltraMicroTrackTracks; ///< Output table for original ultra-microtrack row IDs Produces reso2mctracks; ///< Output table for MC resonance tracks @@ -606,86 +1137,96 @@ struct ResonanceDaughterInitializer { struct : ConfigurableGroup { Configurable cfgCutEta{"cfgCutEta", 0.8f, "Eta range for tracks"}; Configurable cfgCutMinPt{"cfgCutMinPt", 0.1f, "Minimum pT for tracks (GeV/c)"}; - Configurable cfgCutMaxPt{"cfgCutMaxPt", 32.767f, "Maximum pT for tracks (GeV/c)"}; - Configurable pidnSigmaPreSelectionCut{"pidnSigmaPreSelectionCut", 5.0f, "TPC PID cut (loose, improve performance)"}; - Configurable mincrossedrows{"mincrossedrows", 70, "Minimum crossed rows for V0 daughter tracks"}; + Configurable cfgCutMaxPt{"cfgCutMaxPt", 999.0f, "Maximum pT for tracks (GeV/c)"}; + Configurable pidnSigmaPreSelectionCut{"pidnSigmaPreSelectionCut", 5.0f, "TPC PID half-width around the configured species mean (loose preselection)"}; + Configurable pidnSigmaPreSelectionCutTOF{"pidnSigmaPreSelectionCutTOF", 5.0f, "TOF PID half-width around the configured species mean (loose preselection)"}; + Configurable pidnSigmaPreSelectionMeanPion{"pidnSigmaPreSelectionMeanPion", 0.000f, "Offset for TPC PID mean for pions"}; + Configurable pidnSigmaPreSelectionMeanKaon{"pidnSigmaPreSelectionMeanKaon", 0.000f, "Offset for TPC PID mean for kaons"}; + Configurable pidnSigmaPreSelectionMeanProton{"pidnSigmaPreSelectionMeanProton", 0.000f, "Offset for TPC PID mean for protons"}; + Configurable pidnSigmaPreSelectionMeanTOFPion{"pidnSigmaPreSelectionMeanTOFPion", 0.000f, "Offset for TOF PID mean for pions"}; + Configurable pidnSigmaPreSelectionMeanTOFKaon{"pidnSigmaPreSelectionMeanTOFKaon", 0.000f, "Offset for TOF PID mean for kaons"}; + Configurable pidnSigmaPreSelectionMeanTOFProton{"pidnSigmaPreSelectionMeanTOFProton", 0.000f, "Offset for TOF PID mean for protons"}; + Configurable cfgUseTOFPIDPreSelection{"cfgUseTOFPIDPreSelection", false, + "Apply the TOF PID cut to tracks with TOF; false ignores TOF PID, and tracks without TOF use TPC only"}; Configurable trackSelection{"trackSelection", 3, "Track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks"}; - Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 2.0, "Track DCAr cut to PV Maximum"}; - Configurable cMaxDCAzToPVcut{"cMaxDCAzToPVcut", 2.0, "Track DCAz cut to PV Maximum"}; - Configurable cMinDCAzToPVcut{"cMinDCAzToPVcut", 0.0, "Track DCAz cut to PV Minimum"}; + Configurable cMaxDCArToPVcut{"cMaxDCArToPVcut", 0.5f, "Track DCAr cut to PV Maximum"}; + Configurable cMaxDCAzToPVcut{"cMaxDCAzToPVcut", 1.0f, "Track DCAz cut to PV Maximum"}; + Configurable cMinDCAzToPVcut{"cMinDCAzToPVcut", 0.0f, "Track DCAz cut to PV Minimum"}; Configurable cfgApplyTightDCAPtDepSelection{"cfgApplyTightDCAPtDepSelection", true, "Apply the pT-dependent tight DCA selection"}; Configurable cfgTightDCAOffset{"cfgTightDCAOffset", 0.004f, "Constant term of the tight DCA threshold (cm)"}; Configurable cfgTightDCAPtCoefficient{"cfgTightDCAPtCoefficient", 0.013f, "Coefficient of the pT-dependent tight DCA threshold"}; Configurable cfgTightDCAPtPower{"cfgTightDCAPtPower", 1.f, "Power in tight DCA = offset + coefficient / pT^power"}; } TrackCuts; - // V0 and V0-daughter cuts + // V0 and V0-daughter cuts : based on loose cuts in V0s production analysis in pp 13.6 TeV struct : ConfigurableGroup { + Configurable mincrossedrowsV0s{"mincrossedrowsV0s", 70, "Minimum crossed rows for V0 daughter tracks"}; Configurable cMinV0PosDCArToPVcut{"cMinV0PosDCArToPVcut", 0.05f, "V0 Positive Track DCAr cut to PV Minimum"}; Configurable cMinV0NegDCArToPVcut{"cMinV0NegDCArToPVcut", 0.05f, "V0 Negative Track DCAr cut to PV Minimum"}; - Configurable cMinV0Radius{"cMinV0Radius", 0.0, "Minimum V0 radius from PV"}; - Configurable cMaxV0Radius{"cMaxV0Radius", 200.0, "Maximum V0 radius from PV"}; - Configurable cMinV0CosPA{"cMinV0CosPA", 0.995, "Minimum V0 CosPA to PV"}; + Configurable cMinV0Radius{"cMinV0Radius", 0.9f, "Minimum V0 radius from PV"}; + Configurable cMaxV0Radius{"cMaxV0Radius", 200.0f, "Maximum V0 radius from PV"}; + Configurable cMinV0CosPA{"cMinV0CosPA", 0.95f, "Minimum V0 CosPA to PV"}; } V0Cuts; - // Cascade and cascade-daughter cuts + // Additional K0s and Lambda0 selections not covered by V0Cuts: based on loose cuts in V0s production analysis in pp 13.6 TeV struct : ConfigurableGroup { - Configurable cfgMinCrossedRowsCascBach{"cfgMinCrossedRowsCascBach", 70, "min crossed rows for bachelor track from cascade"}; - Configurable cMinCascBachDCArToPVcut{"cMinCascBachDCArToPVcut", 0.05f, "Cascade Bachelor Track DCAr cut to PV Minimum"}; - Configurable cMaxCascBachDCArToPVcut{"cMaxCascBachDCArToPVcut", 999.0f, "Cascade Bachelor Track DCAr cut to PV Maximum"}; - Configurable cMaxCascDCAV0Daughters{"cMaxCascDCAV0Daughters", 1.6, "Cascade DCA between V0 daughters Maximum"}; - Configurable cMaxCascDCACascDaughters{"cMaxCascDCACascDaughters", 1.6, "Cascade DCA between Casc daughters Maximum"}; - Configurable cMinCascV0CosPA{"cMinCascV0CosPA", 0.97, "Minimum Cascade V0 CosPA to PV"}; - Configurable cMaxCascV0Radius{"cMaxCascV0Radius", 200.0, "Maximum Cascade V0 radius from PV"}; - Configurable cMinCascV0Radius{"cMinCascV0Radius", 0.0, "Minimum Cascade V0 radius from PV"}; - Configurable cMinCascRadius{"cMinCascRadius", 0.0, "Minimum Cascade radius from PV"}; - Configurable cMaxCascRadius{"cMaxCascRadius", 200.0, "Maximum Cascade radius from PV"}; - Configurable cMinCascCosPA{"cMinCascCosPA", 0.97, "Minimum Cascade CosPA to PV"}; - Configurable cCascMassResol{"cCascMassResol", 999, "Cascade mass resolution"}; + Configurable cfgSecondaryRequire{"cfgSecondaryRequire", true, "Secondary cuts on/off"}; + Configurable cfgSecondaryArmenterosCut{"cfgSecondaryArmenterosCut", false, "cut on Armenteros-Podolanski graph"}; + Configurable cfgSecondaryCrossMassHypothesisCut{"cfgSecondaryCrossMassHypothesisCut", false, "Apply cut based on the lambda mass hypothesis"}; + Configurable cfgByPassDauPIDSelection{"cfgByPassDauPIDSelection", false, "Bypass TPC PID preselection for V0 daughters"}; + Configurable cfgSecondaryDauDCAMax{"cfgSecondaryDauDCAMax", 1.0f, "Maximum DCA between V0 daughters"}; + Configurable cfgSecondaryPtMin{"cfgSecondaryPtMin", 0.0f, "Minimum transverse momentum of Secondary"}; + Configurable cfgSecondaryRapidityMax{"cfgSecondaryRapidityMax", 0.5f, "Maximum rapidity of Secondary"}; + Configurable cfgSecondaryDCAtoPVMax{"cfgSecondaryDCAtoPVMax", 0.4f, "Maximum DCA Secondary to PV"}; + Configurable cfgSecondaryProperLifetimeMax{"cfgSecondaryProperLifetimeMax", 40.f, "Maximum Secondary Lifetime"}; + Configurable cfgSecondaryparamArmenterosCut{"cfgSecondaryparamArmenterosCut", 0.2f, "parameter for Armenteros Cut"}; + Configurable cfgSecondaryMassWindow{"cfgSecondaryMassWindow", 0.03f, "Secondary inv mass selection window (GeV/c^2)"}; + Configurable cfgSecondaryCrossMassCutWindow{"cfgSecondaryCrossMassCutWindow", 0.02f, "Secondary inv mass selection window with (anti)lambda hypothesis (GeV/c^2)"}; + } SecondaryCuts; + + // Cascade and cascade-daughter cuts: based on loose cuts in cascades production analysis in pp 13.6 TeV + struct : ConfigurableGroup { + Configurable cfgMinCrossedRowsCascBach{"cfgMinCrossedRowsCascBach", 50, "min crossed rows for bachelor track from cascade"}; + Configurable cMinCascBachDCArToPVcut{"cMinCascBachDCArToPVcut", 0.05f, "Cascade Bachelor Track DCAr cut to PV Minimum"}; + Configurable cMaxCascBachDCArToPVcut{"cMaxCascBachDCArToPVcut", 200.0f, "Cascade Bachelor Track DCAr cut to PV Maximum"}; + Configurable cMaxCascDCAV0Daughters{"cMaxCascDCAV0Daughters", 0.5f, "Cascade DCA between V0 daughters Maximum"}; + Configurable cMaxCascDCACascDaughters{"cMaxCascDCACascDaughters", 1.2f, "Cascade DCA between Casc daughters Maximum"}; + Configurable cMinCascV0CosPA{"cMinCascV0CosPA", 0.98f, "Minimum Cascade V0 CosPA to PV"}; + Configurable cMaxCascV0Radius{"cMaxCascV0Radius", 200.0f, "Maximum Cascade V0 radius from PV"}; + Configurable cMinCascV0Radius{"cMinCascV0Radius", 0.4f, "Minimum Cascade V0 radius from PV"}; + Configurable cMinCascRadius{"cMinCascRadius", 0.4f, "Minimum Cascade radius from PV"}; + Configurable cMaxCascRadius{"cMaxCascRadius", 200.0f, "Maximum Cascade radius from PV"}; + Configurable cMinCascCosPA{"cMinCascCosPA", 0.99, "Minimum Cascade CosPA to PV"}; + Configurable cMaxXiMassWindow{"cMaxXiMassWindow", 0.02f, "Xi mass Window (GeV/c^2)"}; } CascadeCuts; // Derived dataset selections struct : ConfigurableGroup { - Configurable cfgFillPionTracks{"cfgFillPionTracks", false, "Fill pion tracks"}; - Configurable cfgFillKaonTracks{"cfgFillKaonTracks", false, "Fill kaon tracks"}; - Configurable cfgFillProtonTracks{"cfgFillProtonTracks", false, "Fill proton tracks"}; - Configurable cfgFillPionMicroTracks{"cfgFillPionMicroTracks", false, "Fill pion micro tracks"}; - Configurable cfgFillKaonMicroTracks{"cfgFillKaonMicroTracks", false, "Fill kaon micro tracks"}; - Configurable cfgFillProtonMicroTracks{"cfgFillProtonMicroTracks", false, "Fill proton micro tracks"}; - Configurable cfgFillPionUltraMicroTracks{"cfgFillPionUltraMicroTracks", true, "Fill pion ultra micro tracks"}; - Configurable cfgFillKaonUltraMicroTracks{"cfgFillKaonUltraMicroTracks", false, "Fill kaon ultra micro tracks"}; - Configurable cfgFillProtonUltraMicroTracks{"cfgFillProtonUltraMicroTracks", false, "Fill proton ultra micro tracks"}; - Configurable cfgFillK0s{"cfgFillK0s", false, "Fill K0s"}; - Configurable cfgFillLambda0{"cfgFillLambda0", false, "Fill Lambda0"}; - Configurable cfgBypassNoPairV0s{"cfgBypassNoPairV0s", false, "In a *WithPairGate process, bypass track fill if no V0 passes the configured selections"}; - Configurable cfgBypassNoPairCascades{"cfgBypassNoPairCascades", true, "In a *WithPairGate process, bypass track fill if no cascade passes the configured selections"}; + Configurable cfgFillPionTracks{"cfgFillPionTracks", false, "Apply the pion PID filter to every enabled track table"}; + Configurable cfgFillKaonTracks{"cfgFillKaonTracks", false, "Apply the kaon PID filter to every enabled track table"}; + Configurable cfgFillProtonTracks{"cfgFillProtonTracks", false, "Apply the proton PID filter to every enabled track table"}; + Configurable cfgFillK0s{"cfgFillK0s", true, "Fill K0s"}; + Configurable cfgFillLambda0{"cfgFillLambda0", true, "Fill Lambda0"}; + Configurable cfgPairGateMode{"cfgPairGateMode", 0, + "Combined *WithPairGate mode: 0 -> require every enabled candidate type, " + "1 -> require a selected V0 or cascade"}; + Configurable cfgBypassNoPairV0s{"cfgBypassNoPairV0s", false, + "Require a selected V0 and at least one selected collision track in pair-gate mode 0"}; + Configurable cfgBypassNoPairCascades{"cfgBypassNoPairCascades", true, + "Require a selected cascade and at least one selected collision track in pair-gate mode 0"}; + Configurable cfgGlobalDaughterVeto{"cfgGlobalDaughterVeto", false, + "Pair-gate callbacks only: reject a track if its original ID is a daughter " + "of any selected V0 or cascade; false stores all selected collision tracks " + "for mandatory candidate-local rejection through trackId"}; Configurable cfgFillMicroTracks{"cfgFillMicroTracks", false, "Fill micro tracks"}; Configurable cfgFillUltraMicroTracks{"cfgFillUltraMicroTracks", false, "Fill ultra micro tracks"}; Configurable cfgBypassTrackFill{"cfgBypassTrackFill", false, "Bypass the full ResoTracks table fill"}; - Configurable cfgBypassTrackIndexFill{"cfgBypassTrackIndexFill", false, "Bypass original daughter ID table fill"}; + Configurable cfgBypassTrackIndexFill{"cfgBypassTrackIndexFill", false, + "Bypass optional source-object soft-link side tables; " + "ResoMicroTracks_001 keeps its inline scalar trackId, but Full/Ultra " + "outputs then cannot perform candidate-local daughter rejection"}; } FilterForDerivedTables; - // Secondary selections for K0s and Lambda0 - struct : ConfigurableGroup { - Configurable cfgSecondaryRequire{"cfgSecondaryRequire", false, "Secondary cuts on/off"}; - Configurable cfgSecondaryArmenterosCut{"cfgSecondaryArmenterosCut", false, "cut on Armenteros-Podolanski graph"}; - Configurable cfgSecondaryCrossMassHypothesisCut{"cfgSecondaryCrossMassHypothesisCut", false, "Apply cut based on the lambda mass hypothesis"}; - Configurable cfgByPassDauPIDSelection{"cfgByPassDauPIDSelection", true, "Bypass TPC PID preselection for V0 daughters"}; - Configurable cfgSecondaryDauDCAMax{"cfgSecondaryDauDCAMax", 0.2, "Maximum DCA Secondary daughters to PV"}; - Configurable cfgSecondaryDauPosDCAtoPVMin{"cfgSecondaryDauPosDCAtoPVMin", 0.0, "Minimum DCA Secondary positive daughters to PV"}; - Configurable cfgSecondaryDauNegDCAtoPVMin{"cfgSecondaryDauNegDCAtoPVMin", 0.0, "Minimum DCA Secondary negative daughters to PV"}; - Configurable cfgSecondaryPtMin{"cfgSecondaryPtMin", 0.f, "Minimum transverse momentum of Secondary"}; - Configurable cfgSecondaryRapidityMax{"cfgSecondaryRapidityMax", 0.5, "Maximum rapidity of Secondary"}; - Configurable cfgSecondaryRadiusMin{"cfgSecondaryRadiusMin", 0.0, "Minimum transverse radius of Secondary"}; - Configurable cfgSecondaryRadiusMax{"cfgSecondaryRadiusMax", 999.9, "Maximum transverse radius of Secondary"}; - Configurable cfgSecondaryCosPAMin{"cfgSecondaryCosPAMin", 0.998, "Mininum cosine pointing angle of Secondary"}; - Configurable cfgSecondaryDCAtoPVMax{"cfgSecondaryDCAtoPVMax", 0.4, "Maximum DCA Secondary to PV"}; - Configurable cfgSecondaryProperLifetimeMax{"cfgSecondaryProperLifetimeMax", 20., "Maximum Secondary Lifetime"}; - Configurable cfgSecondaryparamArmenterosCut{"cfgSecondaryparamArmenterosCut", 0.2, "parameter for Armenteros Cut"}; - Configurable cfgSecondaryMassWindow{"cfgSecondaryMassWindow", 0.03, "Secondary inv mass selection window"}; - Configurable cfgSecondaryCrossMassCutWindow{"cfgSecondaryCrossMassCutWindow", 0.05, "Secondary inv mass selection window with (anti)lambda hypothesis"}; - } SecondaryCuts; - // Track selection filter based on configuration Filter trackFilter = (TrackCuts.trackSelection.node() == TrackSelectionNone) || ((TrackCuts.trackSelection.node() == TrackSelectionGlobal) && requireGlobalTrackInFilter()) || // kGlobalTrack = kQualityTracks | kPrimaryTracks | kInAcceptanceTracks @@ -698,11 +1239,17 @@ struct ResonanceDaughterInitializer { aod::track::pt <= TrackCuts.cfgCutMaxPt; HistogramRegistry qaRegistry{"QAHistos", {}, OutputObjHandlingPolicy::AnalysisObject}; - // The daughter task needs this row-wise mapping back to the original collision. - // Keep ResonanceModuleInitializer::cfgBypassCollIndexFill disabled and enable - // the matching Run 2/Run 3 base event process for MC workflows. - using ResoCollisionWithIndex = soa::Join; - using SelectedResoCollisions = soa::Join; + // The daughter task treats fIndexResoCollisions as a scalar v001 row ID. The + // data-model relation keeps its legacy v000 default target; v001 consumers + // must use resoCollision_as() with the exact bound v001 table type for + // dereferencing (aod::ResoCollisions_001 when the parent is not joined). + // Original-collision grouping is provided by the scalar-only version-1 + // ResoCollisionGroups_001 table, avoiding a hard source-AO2D relation. + // Collision mappings are always written; cfgBypassCollIndexFill is retained + // only so existing configuration files remain accepted. + using ResoCollisionWithIndex = soa::Join; + using SelectedResoCollisions = soa::Join; + PresliceUnsorted reducedCollisionsPerOriginalCollision = aod::resocollisiongroup001::originalCollisionId; /** * @brief Initializes the task @@ -711,36 +1258,107 @@ struct ResonanceDaughterInitializer { */ void init(InitContext&) { - const bool processTrackDataEnabled = doprocessData || doprocessDataHybrid || doprocessDataWithPairGate; - const bool processTrackMCEnabled = doprocessMC || doprocessMCWithPairGate; - const bool processV0DataEnabled = doprocessV0Data || doprocessV0DataHybrid; - const bool processCascDataEnabled = doprocessCascData || doprocessCascDataHybrid; + if (FilterForDerivedTables.cfgPairGateMode.value < PairGateModeConfigured || + FilterForDerivedTables.cfgPairGateMode.value > PairGateModeEither) { + LOGF(fatal, "cfgPairGateMode must be 0 (configured gates) or 1 (V0 or cascade)"); + } + const bool useEitherPairGate = FilterForDerivedTables.cfgPairGateMode.value == PairGateModeEither; + const bool processTrackDataEnabled = doprocessData || doprocessDataHybrid || doprocessDataWithPairGate || + doprocessDataWithV0PairGate || doprocessDataWithCascPairGate; + const bool processTrackMCEnabled = doprocessMC || doprocessMCWithPairGate || + doprocessMCWithV0PairGate || doprocessMCWithCascPairGate; + const bool pairTrackProcessEnabled = doprocessDataWithPairGate || doprocessDataWithV0PairGate || + doprocessDataWithCascPairGate || doprocessMCWithPairGate || + doprocessMCWithV0PairGate || doprocessMCWithCascPairGate; + const bool processV0DataEnabled = doprocessV0Data; + const bool processCascDataEnabled = doprocessCascData; + const bool anyDataProcessEnabled = processTrackDataEnabled || processV0DataEnabled || processCascDataEnabled; + const bool anyMCProcessEnabled = processTrackMCEnabled || doprocessV0MC || doprocessCascMC; const int enabledTrackProcesses = static_cast(doprocessData) + static_cast(doprocessDataHybrid) + static_cast(doprocessDataWithPairGate) + + static_cast(doprocessDataWithV0PairGate) + + static_cast(doprocessDataWithCascPairGate) + static_cast(doprocessMC) + - static_cast(doprocessMCWithPairGate); + static_cast(doprocessMCWithPairGate) + + static_cast(doprocessMCWithV0PairGate) + + static_cast(doprocessMCWithCascPairGate); if (enabledTrackProcesses > 1) { LOGF(fatal, "Only one track process can be enabled in ResonanceDaughterInitializer"); } - if (static_cast(doprocessV0Data) + static_cast(doprocessV0DataHybrid) + static_cast(doprocessV0MC) > 1) { + if (pairTrackProcessEnabled && + FilterForDerivedTables.cfgBypassTrackFill && + !FilterForDerivedTables.cfgFillMicroTracks && + !FilterForDerivedTables.cfgFillUltraMicroTracks) { + LOGF(fatal, "A pair-gate process requires at least one enabled Full, Micro, or UltraMicro track output"); + } + if (pairTrackProcessEnabled && !FilterForDerivedTables.cfgGlobalDaughterVeto && + FilterForDerivedTables.cfgBypassTrackIndexFill && + (!FilterForDerivedTables.cfgBypassTrackFill || FilterForDerivedTables.cfgFillUltraMicroTracks)) { + LOGF(warn, + "Default pair-gate mode defers daughter reuse rejection to analysis trackId comparisons, " + "but cfgBypassTrackIndexFill removes that ID from Full/Ultra track outputs"); + } + if (useEitherPairGate && + (doprocessDataWithV0PairGate || doprocessDataWithCascPairGate || + doprocessMCWithV0PairGate || doprocessMCWithCascPairGate)) { + LOGF(fatal, "cfgPairGateMode 1 requires the combined processDataWithPairGate or processMCWithPairGate callback"); + } + if (static_cast(doprocessV0Data) + static_cast(doprocessV0MC) > 1) { LOGF(fatal, "Only one V0 process can be enabled in ResonanceDaughterInitializer"); } - if (static_cast(doprocessCascData) + static_cast(doprocessCascDataHybrid) + static_cast(doprocessCascMC) > 1) { + if (static_cast(doprocessCascData) + static_cast(doprocessCascMC) > 1) { LOGF(fatal, "Only one cascade process can be enabled in ResonanceDaughterInitializer"); } if ((doprocessData || doprocessDataHybrid || doprocessMC) && - (FilterForDerivedTables.cfgBypassNoPairV0s || FilterForDerivedTables.cfgBypassNoPairCascades)) { + (useEitherPairGate || FilterForDerivedTables.cfgBypassNoPairV0s || FilterForDerivedTables.cfgBypassNoPairCascades || + FilterForDerivedTables.cfgGlobalDaughterVeto)) { LOGF(warn, "Pair-gate options are ignored by processData/processDataHybrid/processMC; enable the matching *WithPairGate process to apply them"); } - if (doprocessDataWithPairGate && FilterForDerivedTables.cfgBypassNoPairV0s && !processV0DataEnabled) { - LOGF(fatal, "cfgBypassNoPairV0s requires processV0Data or processV0DataHybrid so an accepted V0 is written for every retained collision"); - } - if (doprocessDataWithPairGate && FilterForDerivedTables.cfgBypassNoPairCascades && !processCascDataEnabled) { - LOGF(fatal, "cfgBypassNoPairCascades requires processCascData or processCascDataHybrid so an accepted cascade is written for every retained collision"); + const auto validatePairGateOutputs = [&](bool pairProcessEnabled, + bool v0OutputEnabled, + bool cascadeOutputEnabled, + char const* processName) { + if (!pairProcessEnabled) { + return; + } + if (useEitherPairGate) { + if (!v0OutputEnabled || !cascadeOutputEnabled) { + LOGF(fatal, "%s with pair-gate mode 1 requires both V0 and cascade output processes", processName); + } + } else { + if (!FilterForDerivedTables.cfgBypassNoPairV0s && !FilterForDerivedTables.cfgBypassNoPairCascades) { + LOGF(fatal, "%s with pair-gate mode 0 requires at least one enabled V0/cascade gate", processName); + } + if (FilterForDerivedTables.cfgBypassNoPairV0s && !v0OutputEnabled) { + LOGF(fatal, "%s requires a V0 output process when cfgBypassNoPairV0s is enabled", processName); + } + if (FilterForDerivedTables.cfgBypassNoPairCascades && !cascadeOutputEnabled) { + LOGF(fatal, "%s requires a cascade output process when cfgBypassNoPairCascades is enabled", processName); + } + } + }; + validatePairGateOutputs(doprocessDataWithPairGate, + processV0DataEnabled, + processCascDataEnabled, + "processDataWithPairGate"); + validatePairGateOutputs(doprocessMCWithPairGate, + doprocessV0MC, + doprocessCascMC, + "processMCWithPairGate"); + if (doprocessDataWithV0PairGate && !processV0DataEnabled) { + LOGF(fatal, "processDataWithV0PairGate requires processV0Data"); + } + if (doprocessDataWithCascPairGate && !processCascDataEnabled) { + LOGF(fatal, "processDataWithCascPairGate requires processCascData"); + } + if (doprocessMCWithV0PairGate && !doprocessV0MC) { + LOGF(fatal, "processMCWithV0PairGate requires processV0MC"); + } + if (doprocessMCWithCascPairGate && !doprocessCascMC) { + LOGF(fatal, "processMCWithCascPairGate requires processCascMC"); } - if (!std::isfinite(TrackCuts.cfgCutMinPt.value) || !std::isfinite(TrackCuts.cfgCutMaxPt.value) || TrackCuts.cfgCutMinPt.value < 0.f || @@ -765,7 +1383,28 @@ struct ResonanceDaughterInitializer { TrackCuts.pidnSigmaPreSelectionCut.value < 0.f) { LOGF(fatal, "pidnSigmaPreSelectionCut must be finite and non-negative"); } - + const std::array tpcPidMeans{TrackCuts.pidnSigmaPreSelectionMeanPion.value, + TrackCuts.pidnSigmaPreSelectionMeanKaon.value, + TrackCuts.pidnSigmaPreSelectionMeanProton.value}; + if (!std::all_of(tpcPidMeans.begin(), tpcPidMeans.end(), [](float mean) { + return std::isfinite(mean); + })) { + LOGF(fatal, "All TPC PID preselection means must be finite"); + } + if (TrackCuts.cfgUseTOFPIDPreSelection.value) { + if (!std::isfinite(TrackCuts.pidnSigmaPreSelectionCutTOF.value) || + TrackCuts.pidnSigmaPreSelectionCutTOF.value < 0.f) { + LOGF(fatal, "pidnSigmaPreSelectionCutTOF must be finite and non-negative when TOF PID selection is enabled"); + } + const std::array tofPidMeans{TrackCuts.pidnSigmaPreSelectionMeanTOFPion.value, + TrackCuts.pidnSigmaPreSelectionMeanTOFKaon.value, + TrackCuts.pidnSigmaPreSelectionMeanTOFProton.value}; + if (!std::all_of(tofPidMeans.begin(), tofPidMeans.end(), [](float mean) { + return std::isfinite(mean); + })) { + LOGF(fatal, "All TOF PID preselection means must be finite when TOF PID selection is enabled"); + } + } if (TrackCuts.cfgApplyTightDCAPtDepSelection.value && (!std::isfinite(TrackCuts.cfgTightDCAOffset.value) || !std::isfinite(TrackCuts.cfgTightDCAPtCoefficient.value) || @@ -775,28 +1414,38 @@ struct ResonanceDaughterInitializer { TrackCuts.cfgTightDCAPtPower.value < 0.f)) { LOGF(fatal, "Tight-DCA offset, pT coefficient, and power must be finite and non-negative"); } - + if (!std::isfinite(V0Cuts.cMinV0CosPA.value) || + V0Cuts.cMinV0CosPA.value < -1. || V0Cuts.cMinV0CosPA.value >= 1.) { + LOGF(fatal, "cMinV0CosPA must be finite and satisfy -1 <= cMinV0CosPA < 1"); + } + if (!std::isfinite(CascadeCuts.cMinCascCosPA.value) || + CascadeCuts.cMinCascCosPA.value < -1. || CascadeCuts.cMinCascCosPA.value >= 1.) { + LOGF(fatal, "cMinCascCosPA must be finite and satisfy -1 <= cMinCascCosPA < 1"); + } + if (!std::isfinite(CascadeCuts.cMinCascRadius.value) || + !std::isfinite(CascadeCuts.cMaxCascRadius.value) || + CascadeCuts.cMinCascRadius.value < 0. || + CascadeCuts.cMaxCascRadius.value <= CascadeCuts.cMinCascRadius.value) { + LOGF(fatal, "Cascade radius limits must be finite and satisfy 0 <= cMinCascRadius < cMaxCascRadius"); + } if (FilterForDerivedTables.cfgFillUltraMicroTracks) { - constexpr float MaxQuantizedMomentum = static_cast(std::numeric_limits::max()) / MomentumQuantizationScale; - const float maxLongitudinalMomentum = TrackCuts.cfgCutMaxPt.value * std::sinh(TrackCuts.cfgCutEta.value); - if (TrackCuts.cfgCutMaxPt.value > MaxQuantizedMomentum || - !std::isfinite(maxLongitudinalMomentum) || - maxLongitudinalMomentum > MaxQuantizedMomentum) { - LOGF(fatal, "Ultra-micro cfgCutMaxPt/cfgCutEta allow momentum components beyond the int16_t quantization range"); - } int enabledUltraMicroSpecies = 0; - enabledUltraMicroSpecies += FilterForDerivedTables.cfgFillPionUltraMicroTracks ? 1 : 0; - enabledUltraMicroSpecies += FilterForDerivedTables.cfgFillKaonUltraMicroTracks ? 1 : 0; - enabledUltraMicroSpecies += FilterForDerivedTables.cfgFillProtonUltraMicroTracks ? 1 : 0; + enabledUltraMicroSpecies += FilterForDerivedTables.cfgFillPionTracks ? 1 : 0; + enabledUltraMicroSpecies += FilterForDerivedTables.cfgFillKaonTracks ? 1 : 0; + enabledUltraMicroSpecies += FilterForDerivedTables.cfgFillProtonTracks ? 1 : 0; if (enabledUltraMicroSpecies != 1) { - LOGF(fatal, "Exactly one pion/kaon/proton PID species must be enabled when filling ultra-micro tracks"); + LOGF(fatal, "Exactly one of cfgFillPionTracks, cfgFillKaonTracks, or cfgFillProtonTracks must be enabled when filling ultra-micro tracks"); } if (TrackCuts.pidnSigmaPreSelectionCut.value > o2::aod::resoultramicrodaughter::PidNSigma::MaxNSigma) { - LOGF(fatal, "Ultra-micro PID encoding requires pidnSigmaPreSelectionCut <= 5"); + LOGF(fatal, "Ultra-micro TPC PID encoding requires pidnSigmaPreSelectionCut <= 5"); } - if (FilterForDerivedTables.cfgFillKaonUltraMicroTracks) { + if (TrackCuts.cfgUseTOFPIDPreSelection.value && + TrackCuts.pidnSigmaPreSelectionCutTOF.value > o2::aod::resoultramicrodaughter::PidNSigma::MaxNSigma) { + LOGF(fatal, "Ultra-micro TOF PID encoding requires pidnSigmaPreSelectionCutTOF <= 5"); + } + if (FilterForDerivedTables.cfgFillKaonTracks) { ultraMicroPidSpecies = UltraMicroPidSpecies::Kaon; - } else if (FilterForDerivedTables.cfgFillProtonUltraMicroTracks) { + } else if (FilterForDerivedTables.cfgFillProtonTracks) { ultraMicroPidSpecies = UltraMicroPidSpecies::Proton; } else { ultraMicroPidSpecies = UltraMicroPidSpecies::Pion; @@ -804,29 +1453,14 @@ struct ResonanceDaughterInitializer { } if (cfgFillQA) { - AxisSpec idxAxis = {8, 0.0, 8.0, "Index"}; + AxisSpec idxAxis = {8, 0.0, 8.0, "Cumulative selection stage"}; AxisSpec ptAxis = {100, 0.0f, 10.0f, "#it{p}_{T} (GeV/#it{c})"}; - // The DCA maps cover the full configured pT range in 0.1 GeV/c steps. - constexpr float DcaPtBinWidth = 0.1f; - const int maxDcaPtBin = static_cast(std::ceil(TrackCuts.cfgCutMaxPt.value / DcaPtBinWidth)); - const int nDcaPtBins = maxDcaPtBin + 1; - const float dcaPtAxisHalfBin = 0.5f * DcaPtBinWidth; - AxisSpec dcaPtAxis = {nDcaPtBins, - -dcaPtAxisHalfBin, - maxDcaPtBin * DcaPtBinWidth + dcaPtAxisHalfBin, - "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec dcaPtAxis = {300, 0.f, 30.f, "#it{p}_{T} (GeV/#it{c})"}; AxisSpec etaAxis = {100, -1.0f, 1.0f, "#eta"}; - AxisSpec phiAxis = {100, 0.0f, TwoPI, "#phi"}; - // Keep the configured signed DCA limits at bin centres so tracks exactly - // on an accepted selection boundary are not moved to overflow. - constexpr int NDcaBins = 201; - constexpr float DcaAxisPaddingFraction = 1.f / 200.f; - const auto configuredDcaXYMax = static_cast(TrackCuts.cMaxDCArToPVcut.value); - const auto configuredDcaZMax = static_cast(TrackCuts.cMaxDCAzToPVcut.value); - const float dcaXYAxisHalfRange = configuredDcaXYMax > 0.f ? configuredDcaXYMax * (1.f + DcaAxisPaddingFraction) : 1.e-4f; - const float dcaZAxisHalfRange = configuredDcaZMax > 0.f ? configuredDcaZMax * (1.f + DcaAxisPaddingFraction) : 1.e-4f; - AxisSpec dcaXYAxis = {NDcaBins, -dcaXYAxisHalfRange, dcaXYAxisHalfRange, "DCA_{xy} (cm)"}; - AxisSpec dcaZAxis = {NDcaBins, -dcaZAxisHalfRange, dcaZAxisHalfRange, "DCA_{z} (cm)"}; + // Keep the azimuthal QA bins aligned with the 18 TPC sectors (10 bins per sector). + AxisSpec phiAxis = {180, 0.0f, TwoPI, "#phi"}; + AxisSpec dcaXYAxis = {1000, -0.5, 0.5, "DCA_{xy} (cm)"}; + AxisSpec dcaZAxis = {1000, -0.5, 0.5, "DCA_{z} (cm)"}; // Tiny PID has 255 discrete values from -6.35 to 6.35 in 0.05 steps. // Extend the histogram limits by half a step so every decoded value is // located at a bin centre instead of on a floating-point bin boundary. @@ -845,28 +1479,34 @@ struct ResonanceDaughterInitializer { if (processTrackDataEnabled || processTrackMCEnabled) { qaRegistry.add("QA/hGoodTrackIndices", "hGoodTrackIndices", kTH1D, {idxAxis}); + auto trackSelection = qaRegistry.get(HIST("QA/hGoodTrackIndices")); + trackSelection->GetXaxis()->SetBinLabel(1, "Before DCA cuts"); + trackSelection->GetXaxis()->SetBinLabel(2, "Finite DCA, |DCA_{xy}| #leq max"); + trackSelection->GetXaxis()->SetBinLabel(3, "min #leq |DCA_{z}| #leq max"); + trackSelection->GetXaxis()->SetBinLabel(8, "Pass DCA selection"); if (processTrackMCEnabled) { qaRegistry.add("QA/hGoodMCTrackIndices", "hGoodMCTrackIndices", kTH1D, {idxAxis}); + qaRegistry.get(HIST("QA/hGoodMCTrackIndices"))->GetXaxis()->SetBinLabel(1, "MC path: before DCA cuts"); } if (cfgDetailTrackQA) { if (!FilterForDerivedTables.cfgBypassTrackFill) { - qaRegistry.add("QA/h4TrackPtEtaPhi", "ResoTracks pT, eta, phi", kTH3F, {ptAxis, etaAxis, phiAxis}); - qaRegistry.add("QA/h2TrackDCAxyVsPt", "ResoTracks DCAxy vs pT", kTH2F, {dcaPtAxis, dcaXYAxis}); - qaRegistry.add("QA/h2TrackDCAzVsPt", "ResoTracks DCAz vs pT", kTH2F, {dcaPtAxis, dcaZAxis}); + qaRegistry.add("QA/h4TrackPtEtaPhi", "ResoTracks pT, eta, phi", kTHnSparseD, {ptAxis, etaAxis, phiAxis}); + qaRegistry.add("QA/h2TrackDCAxyVsPt", "ResoTracks DCAxy vs pT", kTH2D, {dcaPtAxis, dcaXYAxis}); + qaRegistry.add("QA/h2TrackDCAzVsPt", "ResoTracks DCAz vs pT", kTH2D, {dcaPtAxis, dcaZAxis}); qaRegistry.add("QA/h4TrackTPCnSigma", "ResoTracks TPC nSigma Pi, Ka, Pr as pT", kTHnSparseD, {ptAxis, nSigmaTPCAxis, nSigmaTPCAxis, nSigmaTPCAxis}); qaRegistry.add("QA/h4TrackTOFnSigma", "ResoTracks TOF nSigma Pi, Ka, Pr as pT", kTHnSparseD, {ptAxis, nSigmaTOFAxis, nSigmaTOFAxis, nSigmaTOFAxis}); } if (FilterForDerivedTables.cfgFillMicroTracks) { - qaRegistry.add("QA/h4MicroTrackPtEtaPhi", "ResoMicroTracks pT, eta, phi", kTH3F, {ptAxis, etaAxis, phiAxis}); - qaRegistry.add("QA/h2MicroTrackDCAxyVsPt", "ResoMicroTracks DCAxy vs pT", kTH2F, {dcaPtAxis, dcaXYAxis}); - qaRegistry.add("QA/h2MicroTrackDCAzVsPt", "ResoMicroTracks DCAz vs pT", kTH2F, {dcaPtAxis, dcaZAxis}); + qaRegistry.add("QA/h4MicroTrackPtEtaPhi", "ResoMicroTracks pT, eta, phi", kTHnSparseD, {ptAxis, etaAxis, phiAxis}); + qaRegistry.add("QA/h2MicroTrackDCAxyVsPt", "ResoMicroTracks DCAxy vs pT", kTH2D, {dcaPtAxis, dcaXYAxis}); + qaRegistry.add("QA/h2MicroTrackDCAzVsPt", "ResoMicroTracks DCAz vs pT", kTH2D, {dcaPtAxis, dcaZAxis}); qaRegistry.add("QA/h4MicroTrackTPCnSigma", "ResoMicroTracks TPC nSigma Pi, Ka, Pr as pT", kTHnSparseD, {ptAxis, nSigmaTPCAxis, nSigmaTPCAxis, nSigmaTPCAxis}); qaRegistry.add("QA/h4MicroTrackTOFnSigma", "ResoMicroTracks TOF nSigma Pi, Ka, Pr as pT", kTHnSparseD, {ptAxis, nSigmaTOFAxis, nSigmaTOFAxis, nSigmaTOFAxis}); } if (FilterForDerivedTables.cfgFillUltraMicroTracks) { - qaRegistry.add("QA/h4UltraMicroTrackPtEtaPhi", "ResoUltraMicroTracks pT, eta, phi", kTH3F, {ptAxis, etaAxis, phiAxis}); - qaRegistry.add("QA/h2UltraMicroTrackDCAxyVsPt", "ResoUltraMicroTracks DCAxy vs pT", kTH2F, {dcaPtAxis, dcaXYAxis}); - qaRegistry.add("QA/h2UltraMicroTrackDCAzVsPt", "ResoUltraMicroTracks DCAz vs pT", kTH2F, {dcaPtAxis, dcaZAxis}); + qaRegistry.add("QA/h4UltraMicroTrackPtEtaPhi", "ResoUltraMicroTracks pT, eta, phi", kTHnSparseD, {ptAxis, etaAxis, phiAxis}); + qaRegistry.add("QA/h2UltraMicroTrackDCAxyVsPt", "ResoUltraMicroTracks DCAxy vs pT", kTH2D, {dcaPtAxis, dcaXYAxis}); + qaRegistry.add("QA/h2UltraMicroTrackDCAzVsPt", "ResoUltraMicroTracks DCAz vs pT", kTH2D, {dcaPtAxis, dcaZAxis}); qaRegistry.add("QA/h4UltraMicroTrackTPCnSigma", "ResoUltraMicroTracks TPC nSigma Pi, Ka, Pr as pT", kTHnSparseD, {ptAxis, nSigmaTPCAxis, nSigmaTPCAxis, nSigmaTPCAxis}); qaRegistry.add("QA/h4UltraMicroTrackTOFnSigma", "ResoUltraMicroTracks TOF nSigma Pi, Ka, Pr as pT", kTHnSparseD, {ptAxis, nSigmaTOFAxis, nSigmaTOFAxis, nSigmaTOFAxis}); } @@ -875,24 +1515,33 @@ struct ResonanceDaughterInitializer { if (processV0DataEnabled || doprocessV0MC) { qaRegistry.add("QA/hGoodV0Indices", "hGoodV0Indices", kTH1D, {idxAxis}); + auto v0Selection = qaRegistry.get(HIST("QA/hGoodV0Indices")); + v0Selection->GetXaxis()->SetBinLabel(1, "Before V0 cuts"); + v0Selection->GetXaxis()->SetBinLabel(2, "Daughter TPC rows"); + v0Selection->GetXaxis()->SetBinLabel(3, "Daughter |DCA_{xy}| to PV"); + v0Selection->GetXaxis()->SetBinLabel(4, "V0 radius window"); + v0Selection->GetXaxis()->SetBinLabel(5, "V0 cosPA cut passed"); if (doprocessV0MC) { qaRegistry.add("QA/hGoodMCV0Indices", "hGoodMCV0Indices", kTH1D, {idxAxis}); + qaRegistry.get(HIST("QA/hGoodMCV0Indices"))->GetXaxis()->SetBinLabel(1, "Reco V0 cuts passed (MC)"); } - AxisSpec radiusAxis = {100, 0.0, 200.0, "V0 Radius"}; - AxisSpec cosPAAxis = {100, 0.995, 1.0, "V0 CosPA"}; - qaRegistry.add("QA/hV0Radius", "V0 Radius", kTH1F, {radiusAxis}); - qaRegistry.add("QA/hV0CosPA", "V0 CosPA", kTH1F, {cosPAAxis}); } if (processCascDataEnabled || doprocessCascMC) { - AxisSpec radiusAxis = {100, 0.0, 200.0, "Cascade Radius"}; - AxisSpec cosPAAxis = {100, 0.97, 1.0, "Cascade CosPA"}; qaRegistry.add("QA/hGoodCascIndices", "hGoodCascIndices", kTH1D, {idxAxis}); + auto cascadeSelection = qaRegistry.get(HIST("QA/hGoodCascIndices")); + cascadeSelection->GetXaxis()->SetBinLabel(1, "Before cascade cuts"); + cascadeSelection->GetXaxis()->SetBinLabel(2, "Bachelor TPC rows"); + cascadeSelection->GetXaxis()->SetBinLabel(3, "Bachelor DCA_{xy} window"); + cascadeSelection->GetXaxis()->SetBinLabel(4, "V0/cascade daughter DCA"); + cascadeSelection->GetXaxis()->SetBinLabel(5, "Cascade/V0 cosPA"); + cascadeSelection->GetXaxis()->SetBinLabel(6, "V0 radius window"); + cascadeSelection->GetXaxis()->SetBinLabel(7, "Cascade radius window"); + cascadeSelection->GetXaxis()->SetBinLabel(8, "#Xi mass window"); if (doprocessCascMC) { qaRegistry.add("QA/hGoodMCCascIndices", "hGoodMCCascIndices", kTH1D, {idxAxis}); + qaRegistry.get(HIST("QA/hGoodMCCascIndices"))->GetXaxis()->SetBinLabel(1, "Reco cascade cuts passed (MC)"); } - qaRegistry.add("QA/hCascRadius", "Cascade Radius", kTH1F, {radiusAxis}); - qaRegistry.add("QA/hCascCosPA", "Cascade CosPA", kTH1F, {cosPAAxis}); } } if (processTrackDataEnabled || processTrackMCEnabled) { @@ -905,52 +1554,29 @@ struct ResonanceDaughterInitializer { LOGF(info, "ResonanceDaughterInitializer initialized with cascades"); } - // Check if the module is initialized with both data and MC - if ((processTrackDataEnabled && processTrackMCEnabled) || (processV0DataEnabled && doprocessV0MC) || (processCascDataEnabled && doprocessCascMC)) { - LOGF(fatal, "ResonanceDaughterInitializer initialized with both data and MC"); - } // Check if none of the processes are enabled - if (!doprocessDummy && !processTrackDataEnabled && !processTrackMCEnabled && !processV0DataEnabled && !doprocessV0MC && !processCascDataEnabled && !doprocessCascMC) { + if (!doprocessDummy && !anyDataProcessEnabled && !anyMCProcessEnabled) { LOGF(fatal, "ResonanceDaughterInitializer not initialized, enable at least one process"); } } - template - bool filterMicroTrack(T const& track) + static bool passesCenteredPID(float nSigma, float mean, float cut) { - // if no selection is requested, return true - if (!FilterForDerivedTables.cfgFillPionMicroTracks && !FilterForDerivedTables.cfgFillKaonMicroTracks && !FilterForDerivedTables.cfgFillProtonMicroTracks) { - return true; - } - if (FilterForDerivedTables.cfgFillPionMicroTracks) { - if (std::abs(track.tpcNSigmaPi()) < TrackCuts.pidnSigmaPreSelectionCut) { - return true; - } - } - if (FilterForDerivedTables.cfgFillKaonMicroTracks) { - if (std::abs(track.tpcNSigmaKa()) < TrackCuts.pidnSigmaPreSelectionCut) { - return true; - } - } - if (FilterForDerivedTables.cfgFillProtonMicroTracks) { - if (std::abs(track.tpcNSigmaPr()) < TrackCuts.pidnSigmaPreSelectionCut) { - return true; - } - } - return false; + return std::isfinite(nSigma) && std::abs(nSigma - mean) < cut; } - template - bool filterUltraMicroTrack(T const& track) + bool passesPIDPreSelection(float tpcNSigma, + float tofNSigma, + bool hasTOF, + float tpcMean, + float tofMean, + float tpcCut, + float tofCut) const { - switch (ultraMicroPidSpecies) { - case UltraMicroPidSpecies::Pion: - return std::abs(track.tpcNSigmaPi()) < TrackCuts.pidnSigmaPreSelectionCut; - case UltraMicroPidSpecies::Kaon: - return std::abs(track.tpcNSigmaKa()) < TrackCuts.pidnSigmaPreSelectionCut; - case UltraMicroPidSpecies::Proton: - return std::abs(track.tpcNSigmaPr()) < TrackCuts.pidnSigmaPreSelectionCut; + if (!passesCenteredPID(tpcNSigma, tpcMean, tpcCut)) { + return false; } - return false; + return !TrackCuts.cfgUseTOFPIDPreSelection.value || + !hasTOF || passesCenteredPID(tofNSigma, tofMean, tofCut); } template @@ -960,20 +1586,25 @@ struct ResonanceDaughterInitializer { if (!FilterForDerivedTables.cfgFillPionTracks && !FilterForDerivedTables.cfgFillKaonTracks && !FilterForDerivedTables.cfgFillProtonTracks) { return true; } - if (FilterForDerivedTables.cfgFillPionTracks) { - if (std::abs(track.tpcNSigmaPi()) < TrackCuts.pidnSigmaPreSelectionCut) { - return true; - } + const float tpcCut = TrackCuts.pidnSigmaPreSelectionCut.value; + const float tofCut = TrackCuts.pidnSigmaPreSelectionCutTOF.value; + if (FilterForDerivedTables.cfgFillPionTracks && + passesPIDPreSelection(track.tpcNSigmaPi(), track.tofNSigmaPi(), track.hasTOF(), + TrackCuts.pidnSigmaPreSelectionMeanPion.value, + TrackCuts.pidnSigmaPreSelectionMeanTOFPion.value, tpcCut, tofCut)) { + return true; } - if (FilterForDerivedTables.cfgFillKaonTracks) { - if (std::abs(track.tpcNSigmaKa()) < TrackCuts.pidnSigmaPreSelectionCut) { - return true; - } + if (FilterForDerivedTables.cfgFillKaonTracks && + passesPIDPreSelection(track.tpcNSigmaKa(), track.tofNSigmaKa(), track.hasTOF(), + TrackCuts.pidnSigmaPreSelectionMeanKaon.value, + TrackCuts.pidnSigmaPreSelectionMeanTOFKaon.value, tpcCut, tofCut)) { + return true; } - if (FilterForDerivedTables.cfgFillProtonTracks) { - if (std::abs(track.tpcNSigmaPr()) < TrackCuts.pidnSigmaPreSelectionCut) { - return true; - } + if (FilterForDerivedTables.cfgFillProtonTracks && + passesPIDPreSelection(track.tpcNSigmaPr(), track.tofNSigmaPr(), track.hasTOF(), + TrackCuts.pidnSigmaPreSelectionMeanProton.value, + TrackCuts.pidnSigmaPreSelectionMeanTOFProton.value, tpcCut, tofCut)) { + return true; } return false; } @@ -988,13 +1619,8 @@ struct ResonanceDaughterInitializer { return true; } if (v0.dcaV0daughters() > SecondaryCuts.cfgSecondaryDauDCAMax || - std::abs(v0.dcapostopv()) < SecondaryCuts.cfgSecondaryDauPosDCAtoPVMin || - std::abs(v0.dcanegtopv()) < SecondaryCuts.cfgSecondaryDauNegDCAtoPVMin || v0.pt() < SecondaryCuts.cfgSecondaryPtMin || - v0.v0radius() < SecondaryCuts.cfgSecondaryRadiusMin || - v0.v0radius() > SecondaryCuts.cfgSecondaryRadiusMax || - v0.dcav0topv() > SecondaryCuts.cfgSecondaryDCAtoPVMax || - v0.v0cosPA() < SecondaryCuts.cfgSecondaryCosPAMin) { + v0.dcav0topv() > SecondaryCuts.cfgSecondaryDCAtoPVMax) { return false; } if (SecondaryCuts.cfgSecondaryArmenterosCut && @@ -1006,11 +1632,12 @@ struct ResonanceDaughterInitializer { const auto posTrack = v0.template posTrack_as(); const auto negTrack = v0.template negTrack_as(); const bool bypassDaughterPID = SecondaryCuts.cfgByPassDauPIDSelection; + const float daughterPIDCut = TrackCuts.pidnSigmaPreSelectionCut.value; bool selected = false; if (FilterForDerivedTables.cfgFillK0s) { const bool passesK0DaughterPID = bypassDaughterPID || - (std::abs(posTrack.tpcNSigmaPi()) < TrackCuts.pidnSigmaPreSelectionCut && - std::abs(negTrack.tpcNSigmaPi()) < TrackCuts.pidnSigmaPreSelectionCut); + (passesCenteredPID(posTrack.tpcNSigmaPi(), TrackCuts.pidnSigmaPreSelectionMeanPion.value, daughterPIDCut) && + passesCenteredPID(negTrack.tpcNSigmaPi(), TrackCuts.pidnSigmaPreSelectionMeanPion.value, daughterPIDCut)); const bool passesK0 = std::fabs(v0.yK0Short()) <= SecondaryCuts.cfgSecondaryRapidityMax && decayLengthOverMomentum * MassK0Short <= SecondaryCuts.cfgSecondaryProperLifetimeMax && std::fabs(v0.mK0Short() - MassK0Short) <= SecondaryCuts.cfgSecondaryMassWindow && @@ -1022,11 +1649,11 @@ struct ResonanceDaughterInitializer { } if (FilterForDerivedTables.cfgFillLambda0) { const bool passesLambdaPID = bypassDaughterPID || - (std::abs(posTrack.tpcNSigmaPr()) < TrackCuts.pidnSigmaPreSelectionCut && - std::abs(negTrack.tpcNSigmaPi()) < TrackCuts.pidnSigmaPreSelectionCut); + (passesCenteredPID(posTrack.tpcNSigmaPr(), TrackCuts.pidnSigmaPreSelectionMeanProton.value, daughterPIDCut) && + passesCenteredPID(negTrack.tpcNSigmaPi(), TrackCuts.pidnSigmaPreSelectionMeanPion.value, daughterPIDCut)); const bool passesAntiLambdaPID = bypassDaughterPID || - (std::abs(posTrack.tpcNSigmaPi()) < TrackCuts.pidnSigmaPreSelectionCut && - std::abs(negTrack.tpcNSigmaPr()) < TrackCuts.pidnSigmaPreSelectionCut); + (passesCenteredPID(posTrack.tpcNSigmaPi(), TrackCuts.pidnSigmaPreSelectionMeanPion.value, daughterPIDCut) && + passesCenteredPID(negTrack.tpcNSigmaPr(), TrackCuts.pidnSigmaPreSelectionMeanProton.value, daughterPIDCut)); const bool passesLambdaMassAndPID = (std::fabs(v0.mLambda() - MassLambda0) <= SecondaryCuts.cfgSecondaryMassWindow && passesLambdaPID) || (std::fabs(v0.mAntiLambda() - MassLambda0Bar) <= SecondaryCuts.cfgSecondaryMassWindow && passesAntiLambdaPID); @@ -1057,9 +1684,9 @@ struct ResonanceDaughterInitializer { } template - bool isTrackSelected(CollisionType const&, TrackType const& track) + bool isTrackSelected(CollisionType const&, TrackType const& track, bool fillSelectionQA = true) { - if (cfgFillQA) { + if (cfgFillQA && fillSelectionQA) { qaRegistry.fill(HIST("QA/hGoodTrackIndices"), 0.5); if constexpr (isMC) { qaRegistry.fill(HIST("QA/hGoodMCTrackIndices"), 0.5); @@ -1071,13 +1698,13 @@ struct ResonanceDaughterInitializer { if (std::fabs(track.dcaXY()) > TrackCuts.cMaxDCArToPVcut) { return false; } - if (cfgFillQA) { + if (cfgFillQA && fillSelectionQA) { qaRegistry.fill(HIST("QA/hGoodTrackIndices"), 1.5); } if (std::fabs(track.dcaZ()) > TrackCuts.cMaxDCAzToPVcut || std::fabs(track.dcaZ()) < TrackCuts.cMinDCAzToPVcut) { return false; } - if (cfgFillQA) { + if (cfgFillQA && fillSelectionQA) { qaRegistry.fill(HIST("QA/hGoodTrackIndices"), 2.5); qaRegistry.fill(HIST("QA/hGoodTrackIndices"), 7.5); } @@ -1093,7 +1720,7 @@ struct ResonanceDaughterInitializer { auto posTrack = v0.template posTrack_as(); auto negTrack = v0.template negTrack_as(); - if (posTrack.tpcNClsCrossedRows() < TrackCuts.mincrossedrows || negTrack.tpcNClsCrossedRows() < TrackCuts.mincrossedrows) { + if (posTrack.tpcNClsCrossedRows() < V0Cuts.mincrossedrowsV0s || negTrack.tpcNClsCrossedRows() < V0Cuts.mincrossedrowsV0s) { return false; } if (cfgFillQA && fillSelectionQA) { @@ -1173,7 +1800,7 @@ struct ResonanceDaughterInitializer { if (cfgFillQA && fillSelectionQA) { qaRegistry.fill(HIST("QA/hGoodCascIndices"), 6.5); } - if (std::abs(casc.mXi() - MassXiMinus) > CascadeCuts.cCascMassResol) { + if (std::abs(casc.mXi() - MassXiMinus) > CascadeCuts.cMaxXiMassWindow) { return false; } if (cfgFillQA && fillSelectionQA) { @@ -1185,28 +1812,122 @@ struct ResonanceDaughterInitializer { return true; } - /// @brief Check whether a collision has at least one V0 that would be written + /// @brief Find a selected V0 and collect daughter IDs only for the optional global veto template - bool hasSelectedV0(CollisionType const& collision, V0Type const& v0s, TrackType const& tracks) + SelectedCandidateDaughters collectSelectedV0Daughters(CollisionType const& collision, + V0Type const& v0s, + TrackType const& tracks, + bool useGlobalDaughterVeto) { + SelectedCandidateDaughters selectedCandidates{useGlobalDaughterVeto}; for (auto const& v0 : v0s) { - if (isV0Selected(collision, v0, tracks, false) && filterV0(collision, v0, tracks)) { - return true; + if (!isV0Selected(collision, v0, tracks, false) || + !filterV0(collision, v0, tracks)) { + continue; + } + if (!useGlobalDaughterVeto) { + selectedCandidates.addCandidate(); + break; } + selectedCandidates.addCandidate( + std::array{static_cast(v0.posTrackId()), + static_cast(v0.negTrackId())}); } - return false; + selectedCandidates.finalize(); + return selectedCandidates; } - /// @brief Check whether a collision has at least one cascade that would be written + /// @brief Find a selected cascade and collect daughter IDs only for the optional global veto template - bool hasSelectedCascade(CollisionType const& collision, CascType const& cascades, TrackType const& tracks) + SelectedCandidateDaughters collectSelectedCascadeDaughters(CollisionType const& collision, + CascType const& cascades, + TrackType const& tracks, + bool useGlobalDaughterVeto) { + SelectedCandidateDaughters selectedCandidates{useGlobalDaughterVeto}; for (auto const& casc : cascades) { - if (isCascSelected(collision, casc, tracks, false)) { - return true; + if (!isCascSelected(collision, casc, tracks, false)) { + continue; + } + if (!useGlobalDaughterVeto) { + selectedCandidates.addCandidate(); + break; } + selectedCandidates.addCandidate( + std::array{static_cast(casc.posTrackId()), + static_cast(casc.negTrackId()), + static_cast(casc.bachelorId())}); } - return false; + selectedCandidates.finalize(); + return selectedCandidates; + } + + /// @brief Build the per-track selection while preserving the configured collision gate + template + bool preparePairTrackSelection(CollisionType const& collision, + TrackType const& tracks, + V0Type const& v0s, + CascType const& cascades, + V0PresliceType const& v0Preslice, + CascPresliceType const& cascPreslice, + PairTrackSelection& selection) + { + const bool useEitherPairGate = FilterForDerivedTables.cfgPairGateMode.value == PairGateModeEither; + selection.useV0Candidates = useEitherPairGate || FilterForDerivedTables.cfgBypassNoPairV0s; + selection.useCascadeCandidates = useEitherPairGate || FilterForDerivedTables.cfgBypassNoPairCascades; + + if (selection.useV0Candidates) { + auto v0sThisCollision = v0s.sliceBy(v0Preslice, collision.collisionId()); + selection.v0Candidates = + collectSelectedV0Daughters(collision, v0sThisCollision, tracks, selection.useGlobalDaughterVeto); + } + if (selection.useCascadeCandidates && + (!useEitherPairGate || selection.useGlobalDaughterVeto || !selection.v0Candidates.hasSelectedCandidate)) { + auto cascadesThisCollision = cascades.sliceBy(cascPreslice, collision.collisionId()); + selection.cascadeCandidates = + collectSelectedCascadeDaughters(collision, cascadesThisCollision, tracks, selection.useGlobalDaughterVeto); + } + + if (useEitherPairGate) { + return selection.v0Candidates.hasSelectedCandidate || + selection.cascadeCandidates.hasSelectedCandidate; + } + + if (FilterForDerivedTables.cfgBypassNoPairV0s && !selection.v0Candidates.hasSelectedCandidate) { + return false; + } + if (FilterForDerivedTables.cfgBypassNoPairCascades && !selection.cascadeCandidates.hasSelectedCandidate) { + return false; + } + return true; + } + + /// @brief Round and saturate a floating-point value into a persistent integer column + template + static Integer quantizeSaturated(float value, double scale) + { + constexpr Integer LowerLimit = std::numeric_limits::lowest(); + constexpr Integer UpperLimit = std::numeric_limits::max(); + if (std::isnan(value)) { + return UpperLimit; + } + if (!std::isfinite(value)) { + return std::signbit(value) ? LowerLimit : UpperLimit; + } + const double rounded = std::round(static_cast(value) * scale); + if (rounded <= static_cast(LowerLimit)) { + return LowerLimit; + } + if (rounded >= static_cast(UpperLimit)) { + return UpperLimit; + } + return static_cast(rounded); } static bool quantizeP(float p, int16_t& quantized) @@ -1237,28 +1958,137 @@ struct ResonanceDaughterInitializer { return std::isfinite(threshold) ? threshold : -1.f; } - template - void fillUltraMicroTracks(CollisionType const& collision, TrackType const& tracks) + template + bool evaluatePtDependentDCA(TrackType const& track, + bool& passedPtDependentDCAxy, + bool& passedPtDependentDCAz) const { - // Loop over tracks + passedPtDependentDCAxy = false; + passedPtDependentDCAz = false; + if (!TrackCuts.cfgApplyTightDCAPtDepSelection.value) { + return true; + } + const float dcaThreshold = tightDCAThreshold(track.pt()); + if (dcaThreshold < 0.f) { + return false; + } + passedPtDependentDCAxy = std::isfinite(track.dcaXY()) && std::abs(track.dcaXY()) < dcaThreshold; + passedPtDependentDCAz = std::isfinite(track.dcaZ()) && std::abs(track.dcaZ()) < dcaThreshold; + return passedPtDependentDCAxy && passedPtDependentDCAz; + } + + template + bool isFullTrackOutputSelected(CollisionType const& collision, + TrackType const& track, + bool fillSelectionQA = true) + { + return isTrackSelected(collision, track, fillSelectionQA) && filterTrack(track); + } + + template + bool isMicroTrackOutputSelected(CollisionType const& collision, + TrackType const& track, + bool& passedPtDependentDCAxy, + bool& passedPtDependentDCAz) + { + return isMicroTrackSelected(collision, track) && + filterTrack(track) && + evaluatePtDependentDCA(track, passedPtDependentDCAxy, passedPtDependentDCAz); + } + + template + bool isUltraMicroTrackOutputSelected(CollisionType const& collision, TrackType const& track) + { + return isMicroTrackSelected(collision, track) && + filterTrack(track) && + o2::aod::resoultramicrodaughter::DCAEncoding::isValid(track.dcaXY()) && + o2::aod::resoultramicrodaughter::DCAEncoding::isValid(track.dcaZ()); + } + + template + static bool quantizeUltraMicroMomentum(TrackType const& track, + int16_t& px1000, + int16_t& py1000, + int16_t& pz1000) + { + return quantizeP(track.px(), px1000) && + quantizeP(track.py(), py1000) && + quantizeP(track.pz(), pz1000); + } + + /// Check that every enabled track output will receive at least one row. + template + bool hasTracksForEnabledOutputs(CollisionType const& collision, + TrackTableType const& tracks, + TrackPredicate const& keepTrack) + { + constexpr uint8_t FullTrackOutput = 1u << 0; + constexpr uint8_t MicroTrackOutput = 1u << 1; + constexpr uint8_t UltraMicroTrackOutput = 1u << 2; + uint8_t requiredOutputs = 0; + if (!FilterForDerivedTables.cfgBypassTrackFill.value) { + requiredOutputs |= FullTrackOutput; + } + if (FilterForDerivedTables.cfgFillMicroTracks.value) { + requiredOutputs |= MicroTrackOutput; + } + if (FilterForDerivedTables.cfgFillUltraMicroTracks.value) { + requiredOutputs |= UltraMicroTrackOutput; + } + + uint8_t availableOutputs = 0; for (auto const& track : tracks) { - if (!isMicroTrackSelected(collision, track)) { + if (!keepTrack(track)) { continue; } - if (!filterUltraMicroTrack(track)) { + if ((requiredOutputs & FullTrackOutput) != 0 && + (availableOutputs & FullTrackOutput) == 0 && + isFullTrackOutputSelected(collision, track, false)) { + availableOutputs |= FullTrackOutput; + } + if ((requiredOutputs & MicroTrackOutput) != 0 && + (availableOutputs & MicroTrackOutput) == 0) { + bool passedPtDependentDCAxy = false; + bool passedPtDependentDCAz = false; + if (isMicroTrackOutputSelected(collision, track, + passedPtDependentDCAxy, + passedPtDependentDCAz)) { + availableOutputs |= MicroTrackOutput; + } + } + if ((requiredOutputs & UltraMicroTrackOutput) != 0 && + (availableOutputs & UltraMicroTrackOutput) == 0 && + isUltraMicroTrackOutputSelected(collision, track)) { + int16_t px1000 = 0; + int16_t py1000 = 0; + int16_t pz1000 = 0; + if (quantizeUltraMicroMomentum(track, px1000, py1000, pz1000)) { + availableOutputs |= UltraMicroTrackOutput; + } + } + if (availableOutputs == requiredOutputs) { + return true; + } + } + return false; + } + + template + void fillUltraMicroTracks(CollisionType const& collision, TrackType const& tracks, TrackPredicate const& keepTrack) + { + // Loop over tracks + for (auto const& track : tracks) { + if (!keepTrack(track)) { continue; } - if (!o2::aod::resoultramicrodaughter::DCAEncoding::isValid(track.dcaXY()) || - !o2::aod::resoultramicrodaughter::DCAEncoding::isValid(track.dcaZ())) { + if (!isUltraMicroTrackOutputSelected(collision, track)) { continue; } o2::aod::resoultramicrodaughter::DCAEncoding dcaEncoding(track.dcaXY(), track.dcaZ()); int16_t px1000 = 0; int16_t py1000 = 0; int16_t pz1000 = 0; - if (!quantizeP(track.px(), px1000) || - !quantizeP(track.py(), py1000) || - !quantizeP(track.pz(), pz1000)) { + if (!quantizeUltraMicroMomentum(track, px1000, py1000, pz1000)) { if (!warnedUltraMicroMomentumRange) { LOGF(warn, "Skipping ultra-micro tracks with non-finite or out-of-range momentum components"); warnedUltraMicroMomentumRange = true; @@ -1318,28 +2148,36 @@ struct ResonanceDaughterInitializer { * @tparam CollisionType Type of collision * @param collision Collision data * @param tracks Track data + * @note ResoMicroTracks_001 is intended for fixed producer-side selections. + * Exact downstream cuts on its decoded values require zero-centred + * strict PID windows |nSigma| < C with + * C in {2.0, 2.25, 2.5, 2.75, 3.0, 3.25, 3.5}, and strict DCA windows + * |DCA| < C with C = N * 0.025 cm (N = 1, ..., 6). The listed PID + * guarantee assumes a zero mean; shifted PID windows require both + * interval edges to align with encoding boundaries and separate + * validation. PID cuts below 2 sigma and off-grid DCA/PID cuts cannot + * be reconstructed exactly. In particular, pT-dependent DCA cuts must + * be applied to the unquantised values here via + * cfgApplyTightDCAPtDepSelection; consumers should retain that producer + * decision rather than retune the decoded lower-edge DCA values. */ - template - void fillMicroTracks(CollisionType const& collision, TrackType const& tracks) + template + void fillMicroTracks(CollisionType const& collision, TrackType const& tracks, TrackPredicate const& keepTrack) { // Loop over tracks for (auto const& track : tracks) { - if (!isMicroTrackSelected(collision, track)) { + if (!keepTrack(track)) { continue; } - if (!filterMicroTrack(track)) { + bool passedPtDependentDCAxy = false; + bool passedPtDependentDCAz = false; + if (!isMicroTrackOutputSelected(collision, track, + passedPtDependentDCAxy, + passedPtDependentDCAz)) { continue; } - o2::aod::resomicrodaughter::ResoMicroTrackSelFlag trackSelFlag(track.dcaXY(), track.dcaZ()); - if (TrackCuts.cfgApplyTightDCAPtDepSelection) { - const float dcaThreshold = tightDCAThreshold(track.pt()); - if (dcaThreshold >= 0.f && std::abs(track.dcaXY()) < dcaThreshold) { - trackSelFlag.setDCAxy0(); - } - if (dcaThreshold >= 0.f && std::abs(track.dcaZ()) < dcaThreshold) { - trackSelFlag.setDCAz0(); - } - } + const o2::aod::resomicrodaughter001::DCAEncoding trackSelFlag( + track.dcaXY(), track.dcaZ(), passedPtDependentDCAxy, passedPtDependentDCAz); uint8_t trackFlags = (track.passedITSRefit() << 0) | (track.passedTPCRefit() << 1) | (track.isGlobalTrackWoDCA() << 2) | @@ -1358,17 +2196,21 @@ struct ResonanceDaughterInitializer { } } reso2microtrks(collision.globalIndex(), + track.globalIndex(), track.px(), track.py(), track.pz(), - static_cast(o2::aod::resomicrodaughter::PidNSigma(std::abs(track.tpcNSigmaPi()), std::abs(track.tofNSigmaPi()), track.hasTOF())), - static_cast(o2::aod::resomicrodaughter::PidNSigma(std::abs(track.tpcNSigmaKa()), std::abs(track.tofNSigmaKa()), track.hasTOF())), - static_cast(o2::aod::resomicrodaughter::PidNSigma(std::abs(track.tpcNSigmaPr()), std::abs(track.tofNSigmaPr()), track.hasTOF())), + static_cast(o2::aod::resomicrodaughter001::PidNSigma(track.tpcNSigmaPi(), track.tofNSigmaPi(), track.hasTOF())), + static_cast(o2::aod::resomicrodaughter001::PidNSigma(track.tpcNSigmaKa(), track.tofNSigmaKa(), track.hasTOF())), + static_cast(o2::aod::resomicrodaughter001::PidNSigma(track.tpcNSigmaPr(), track.tofNSigmaPr(), track.hasTOF())), static_cast(trackSelFlag), trackFlags); if (!FilterForDerivedTables.cfgBypassTrackIndexFill) { resoMicroTrackTracks(track.globalIndex()); } + if constexpr (isMC) { + fillMCTrack(track, reso2mcmicrotrks); + } } } @@ -1381,18 +2223,18 @@ struct ResonanceDaughterInitializer { * @param collision Collision data * @param tracks Track data */ - template - void fillTracks(CollisionType const& collision, TrackType const& tracks) + template + void fillTracks(CollisionType const& collision, TrackType const& tracks, TrackPredicate const& keepTrack) { if (FilterForDerivedTables.cfgBypassTrackFill) { return; } // Loop over tracks for (auto const& track : tracks) { - if (!isTrackSelected(collision, track)) { + if (!keepTrack(track)) { continue; } - if (!filterTrack(track)) { + if (!isFullTrackOutputSelected(collision, track)) { continue; } uint8_t trackFlags = (track.passedITSRefit() << 0) | @@ -1419,21 +2261,21 @@ struct ResonanceDaughterInitializer { track.pz(), static_cast(track.tpcNClsCrossedRows()), static_cast(track.tpcNClsFound()), - static_cast(std::round(track.dcaXY() * 10000)), - static_cast(std::round(track.dcaZ() * 10000)), - static_cast(std::round(track.tpcNSigmaPi() * 10)), - static_cast(std::round(track.tpcNSigmaKa() * 10)), - static_cast(std::round(track.tpcNSigmaPr() * 10)), - static_cast(std::round(track.tofNSigmaPi() * 10)), - static_cast(std::round(track.tofNSigmaKa() * 10)), - static_cast(std::round(track.tofNSigmaPr() * 10)), - static_cast(std::round(track.tpcSignal() * 100)), + quantizeSaturated(track.dcaXY(), 10000.), + quantizeSaturated(track.dcaZ(), 10000.), + quantizeSaturated(track.tpcNSigmaPi(), 10.), + quantizeSaturated(track.tpcNSigmaKa(), 10.), + quantizeSaturated(track.tpcNSigmaPr(), 10.), + quantizeSaturated(track.tofNSigmaPi(), 10.), + quantizeSaturated(track.tofNSigmaKa(), 10.), + quantizeSaturated(track.tofNSigmaPr(), 10.), + quantizeSaturated(track.tpcSignal(), 100.), trackFlags); if (!FilterForDerivedTables.cfgBypassTrackIndexFill) { resoTrackTracks(track.globalIndex()); } if constexpr (isMC) { - fillMCTrack(track); + fillMCTrack(track, reso2mctracks); } } } @@ -1442,10 +2284,12 @@ struct ResonanceDaughterInitializer { * @brief Fills MC track data * * @tparam TrackType Type of track + * @tparam MCOutputTable Type of positional MC extension to fill * @param track Track data + * @param output Positional MC extension writer */ - template - void fillMCTrack(TrackType const& track) + template + void fillMCTrack(TrackType const& track, Produces& output) { // ------ Temporal lambda function to prevent error in build auto getMothersIndeces = [&](auto const& theMcParticle) { @@ -1498,20 +2342,20 @@ struct ResonanceDaughterInitializer { if (siblingsTemp.size() > 1) { siblings[1] = siblingsTemp[1]; } - reso2mctracks(particle.pdgCode(), - mothers[0], - motherPDGs[0], - siblings.data(), - particle.isPhysicalPrimary(), - particle.producedByGenerator()); + output(particle.pdgCode(), + mothers[0], + motherPDGs[0], + siblings.data(), + particle.isPhysicalPrimary(), + particle.producedByGenerator()); } else { // No MC particle associated - reso2mctracks(0, - mothers[0], - motherPDGs[0], - siblings.data(), - 0, - 0); + output(0, + mothers[0], + motherPDGs[0], + siblings.data(), + 0, + 0); } } @@ -1536,10 +2380,8 @@ struct ResonanceDaughterInitializer { if (!filterV0(collision, v0, tracks)) { continue; } - if (cfgFillQA) { - qaRegistry.fill(HIST("QA/hV0Radius"), v0.v0radius()); - qaRegistry.fill(HIST("QA/hV0CosPA"), v0.v0cosPA()); - } + const auto posTrack = v0.template posTrack_as(); + const auto negTrack = v0.template negTrack_as(); const std::array childIDs{v0.posTrackId(), v0.negTrackId()}; // Original track IDs for downstream pair-level shared-daughter rejection reso2v0s(collision.globalIndex(), v0.pt(), @@ -1547,25 +2389,25 @@ struct ResonanceDaughterInitializer { v0.py(), v0.pz(), childIDs.data(), - (int8_t)(v0.template posTrack_as().tpcNSigmaPi() * 10), - (int8_t)(v0.template posTrack_as().tpcNSigmaKa() * 10), - (int8_t)(v0.template posTrack_as().tpcNSigmaPr() * 10), - (int8_t)(v0.template negTrack_as().tpcNSigmaPi() * 10), - (int8_t)(v0.template negTrack_as().tpcNSigmaKa() * 10), - (int8_t)(v0.template negTrack_as().tpcNSigmaPr() * 10), - (int8_t)(v0.template posTrack_as().tofNSigmaPi() * 10), - (int8_t)(v0.template posTrack_as().tofNSigmaKa() * 10), - (int8_t)(v0.template posTrack_as().tofNSigmaPr() * 10), - (int8_t)(v0.template negTrack_as().tofNSigmaPi() * 10), - (int8_t)(v0.template negTrack_as().tofNSigmaKa() * 10), - (int8_t)(v0.template negTrack_as().tofNSigmaPr() * 10), + quantizeSaturated(posTrack.tpcNSigmaPi(), 10.), + quantizeSaturated(posTrack.tpcNSigmaKa(), 10.), + quantizeSaturated(posTrack.tpcNSigmaPr(), 10.), + quantizeSaturated(negTrack.tpcNSigmaPi(), 10.), + quantizeSaturated(negTrack.tpcNSigmaKa(), 10.), + quantizeSaturated(negTrack.tpcNSigmaPr(), 10.), + quantizeSaturated(posTrack.tofNSigmaPi(), 10.), + quantizeSaturated(posTrack.tofNSigmaKa(), 10.), + quantizeSaturated(posTrack.tofNSigmaPr(), 10.), + quantizeSaturated(negTrack.tofNSigmaPi(), 10.), + quantizeSaturated(negTrack.tofNSigmaKa(), 10.), + quantizeSaturated(negTrack.tofNSigmaPr(), 10.), v0.v0cosPA(), v0.dcaV0daughters(), v0.dcapostopv(), v0.dcanegtopv(), v0.dcav0topv(), - static_cast(v0.template posTrack_as().tpcNClsCrossedRows()), - static_cast(v0.template negTrack_as().tpcNClsCrossedRows()), + static_cast(posTrack.tpcNClsCrossedRows()), + static_cast(negTrack.tpcNClsCrossedRows()), v0.mLambda(), v0.mAntiLambda(), v0.mK0Short(), @@ -1661,9 +2503,9 @@ struct ResonanceDaughterInitializer { daughters = getDaughtersIndeces(v0mc); daughterPDGs = getDaughtersPDGCodes(v0mc); } - if (daughters.size() > StoredMCRelationCount) { - LOGF(info, "daughters.size() is larger than 2"); - } + // if (daughters.size() > StoredMCRelationCount) { + // LOGF(info, "daughters.size() is larger than 2"); + // } daughters.resize(StoredMCRelationCount, -1); daughterPDGs.resize(StoredMCRelationCount, -1); reso2mcv0s(v0mc.pdgCode(), @@ -1710,10 +2552,9 @@ struct ResonanceDaughterInitializer { if (!isCascSelected(collision, casc, tracks)) { continue; } - if (cfgFillQA) { - qaRegistry.fill(HIST("QA/hCascRadius"), casc.cascradius()); - qaRegistry.fill(HIST("QA/hCascCosPA"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ())); - } + const auto posTrack = casc.template posTrack_as(); + const auto negTrack = casc.template negTrack_as(); + const auto bachelor = casc.template bachelor_as(); const std::array childIDs{casc.posTrackId(), casc.negTrackId(), casc.bachelorId()}; // Original track IDs for downstream pair-level shared-daughter rejection reso2cascades(collision.globalIndex(), casc.pt(), @@ -1721,24 +2562,24 @@ struct ResonanceDaughterInitializer { casc.py(), casc.pz(), childIDs.data(), - (int8_t)(casc.template posTrack_as().tpcNSigmaPi() * 10), - (int8_t)(casc.template posTrack_as().tpcNSigmaKa() * 10), - (int8_t)(casc.template posTrack_as().tpcNSigmaPr() * 10), - (int8_t)(casc.template negTrack_as().tpcNSigmaPi() * 10), - (int8_t)(casc.template negTrack_as().tpcNSigmaKa() * 10), - (int8_t)(casc.template negTrack_as().tpcNSigmaPr() * 10), - (int8_t)(casc.template bachelor_as().tpcNSigmaPi() * 10), - (int8_t)(casc.template bachelor_as().tpcNSigmaKa() * 10), - (int8_t)(casc.template bachelor_as().tpcNSigmaPr() * 10), - (int8_t)(casc.template posTrack_as().tofNSigmaPi() * 10), - (int8_t)(casc.template posTrack_as().tofNSigmaKa() * 10), - (int8_t)(casc.template posTrack_as().tofNSigmaPr() * 10), - (int8_t)(casc.template negTrack_as().tofNSigmaPi() * 10), - (int8_t)(casc.template negTrack_as().tofNSigmaKa() * 10), - (int8_t)(casc.template negTrack_as().tofNSigmaPr() * 10), - (int8_t)(casc.template bachelor_as().tofNSigmaPi() * 10), - (int8_t)(casc.template bachelor_as().tofNSigmaKa() * 10), - (int8_t)(casc.template bachelor_as().tofNSigmaPr() * 10), + quantizeSaturated(posTrack.tpcNSigmaPi(), 10.), + quantizeSaturated(posTrack.tpcNSigmaKa(), 10.), + quantizeSaturated(posTrack.tpcNSigmaPr(), 10.), + quantizeSaturated(negTrack.tpcNSigmaPi(), 10.), + quantizeSaturated(negTrack.tpcNSigmaKa(), 10.), + quantizeSaturated(negTrack.tpcNSigmaPr(), 10.), + quantizeSaturated(bachelor.tpcNSigmaPi(), 10.), + quantizeSaturated(bachelor.tpcNSigmaKa(), 10.), + quantizeSaturated(bachelor.tpcNSigmaPr(), 10.), + quantizeSaturated(posTrack.tofNSigmaPi(), 10.), + quantizeSaturated(posTrack.tofNSigmaKa(), 10.), + quantizeSaturated(posTrack.tofNSigmaPr(), 10.), + quantizeSaturated(negTrack.tofNSigmaPi(), 10.), + quantizeSaturated(negTrack.tofNSigmaKa(), 10.), + quantizeSaturated(negTrack.tofNSigmaPr(), 10.), + quantizeSaturated(bachelor.tofNSigmaPi(), 10.), + quantizeSaturated(bachelor.tofNSigmaKa(), 10.), + quantizeSaturated(bachelor.tofNSigmaPr(), 10.), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()), casc.dcaV0daughters(), @@ -1750,9 +2591,9 @@ struct ResonanceDaughterInitializer { casc.dcaXYCascToPV(), casc.dcaZCascToPV(), casc.sign(), - static_cast(casc.template posTrack_as().tpcNClsCrossedRows()), - static_cast(casc.template negTrack_as().tpcNClsCrossedRows()), - static_cast(casc.template bachelor_as().tpcNClsCrossedRows()), + static_cast(posTrack.tpcNClsCrossedRows()), + static_cast(negTrack.tpcNClsCrossedRows()), + static_cast(bachelor.tpcNClsCrossedRows()), casc.mLambda(), casc.mXi(), casc.v0radius(), casc.cascradius(), casc.x(), casc.y(), casc.z()); @@ -1846,9 +2687,9 @@ struct ResonanceDaughterInitializer { daughters = getDaughtersIndeces(cascmc); daughterPDGs = getDaughtersPDGCodes(cascmc); } - if (daughters.size() > StoredMCRelationCount) { - LOGF(info, "daughters.size() is larger than 2"); - } + // if (daughters.size() > StoredMCRelationCount) { + // LOGF(info, "daughters.size() is larger than 2"); + // } daughters.resize(StoredMCRelationCount, -1); daughterPDGs.resize(StoredMCRelationCount, -1); reso2mccascades(cascmc.pdgCode(), @@ -1882,7 +2723,7 @@ struct ResonanceDaughterInitializer { * * @param collision Collision data */ - void processDummy(aod::ResoCollision const&) + void processDummy(aod::ResoCollisions_001::iterator const&) { } PROCESS_SWITCH(ResonanceDaughterInitializer, processDummy, "Process dummy", true); @@ -1894,18 +2735,24 @@ struct ResonanceDaughterInitializer { * @param collision Reduced collision used as the output foreign key * @param tracks Tracks belonging to the corresponding original collision */ - template - void fillTrackTables(CollisionType const& collision, TrackTableType const& tracks) + template + void fillTrackTables(CollisionType const& collision, TrackTableType const& tracks, TrackPredicate const& keepTrack) { - fillTracks(collision, tracks); + fillTracks(collision, tracks, keepTrack); if (FilterForDerivedTables.cfgFillMicroTracks) { - fillMicroTracks(collision, tracks); + fillMicroTracks(collision, tracks, keepTrack); } if (FilterForDerivedTables.cfgFillUltraMicroTracks) { - fillUltraMicroTracks(collision, tracks); + fillUltraMicroTracks(collision, tracks, keepTrack); } } + template + void fillTrackTables(CollisionType const& collision, TrackTableType const& tracks) + { + fillTrackTables(collision, tracks, KeepAllTracks{}); + } + /** * @brief Fills track tables for one original collision * @@ -1939,49 +2786,94 @@ struct ResonanceDaughterInitializer { /** * @brief Processes data tracks using the two-stage hybrid grouping * - * The canonical fIndexCollisions column in ResoCollisionGroups lets - * GroupSlicer associate both reduced collisions and tracks to the same - * original aod::Collision. The tracks argument is therefore already the - * selected slice for this collision and must not be sliced again. + * GroupSlicer associates tracks automatically to the original + * aod::Collision. Reduced collisions retain a scalar original-collision row + * number and are explicitly sliced from the much smaller mapping table. The + * tracks argument is already the selected slice and must not be sliced again. */ - void processDataHybrid(aod::Collision const&, - soa::SmallGroups const& reducedCollisions, + void processDataHybrid(aod::Collision const& originalCollision, + SelectedResoCollisions const& reducedCollisions, soa::Filtered const& tracks) { - if (reducedCollisions.size() == 0) { + auto reducedCollisionsThisCollision = reducedCollisions.sliceBy(reducedCollisionsPerOriginalCollision, originalCollision.globalIndex()); + if (reducedCollisionsThisCollision.size() == 0) { return; } - if (reducedCollisions.size() != 1) { - LOGF(fatal, "Expected exactly one reduced collision for an original collision, found %zu", reducedCollisions.size()); + if (reducedCollisionsThisCollision.size() > 1) { + LOGF(error, "Found %zu reduced collisions for one original collision; skipping the ambiguous association", reducedCollisionsThisCollision.size()); + return; } - auto reducedCollision = reducedCollisions.begin(); + auto reducedCollision = reducedCollisionsThisCollision.begin(); fillTrackTables(reducedCollision, tracks); } PROCESS_SWITCH(ResonanceDaughterInitializer, processDataHybrid, "Process data tracks with the two-stage hybrid grouping", false); /** - * @brief Processes data tracks with configurable selected-V0 and selected-cascade gates + * @brief Processes data tracks with configurable selected V0 and cascade gates */ void processDataWithPairGate(ResoCollisionWithIndex::iterator const& collision, soa::Filtered const& tracks, aod::ResoV0Candidates const& v0s, aod::ResoCascadesCandidates const& cascades) { - if (FilterForDerivedTables.cfgBypassNoPairV0s) { - auto v0sThisCollision = v0s.sliceBy(v0sPerCollision, collision.collisionId()); - if (!hasSelectedV0(collision, v0sThisCollision, tracks)) { - return; - } + auto tracksThisCollision = tracks.sliceBy(tracksPerCollision, collision.collisionId()); + PairTrackSelection pairSelection{FilterForDerivedTables.cfgGlobalDaughterVeto.value}; + if (!preparePairTrackSelection(collision, tracks, v0s, cascades, + v0sPerCollision, cascadesPerCollision, pairSelection)) { + return; } - if (FilterForDerivedTables.cfgBypassNoPairCascades) { - auto cascadesThisCollision = cascades.sliceBy(cascadesPerCollision, collision.collisionId()); - if (!hasSelectedCascade(collision, cascadesThisCollision, tracks)) { - return; - } + if (!hasTracksForEnabledOutputs(collision, tracksThisCollision, pairSelection)) { + return; } - fillTrackTablesForCollision(collision, tracks, tracksPerCollision); + fillTrackTables(collision, tracksThisCollision, pairSelection); + } + PROCESS_SWITCH(ResonanceDaughterInitializer, processDataWithPairGate, "Process data tracks with the configured pair-gate mode", false); + + /** + * @brief Processes data tracks when a selectex0 and collision track exist + * + * This dedicated callback deliberately has no cascade input, so enabling + * the V0 pair gate does not activate the cascade upstream dependency. + */ + void processDataWithV0PairGate(ResoCollisionWithIndex::iterator const& collision, + soa::Filtered const& tracks, + aod::ResoV0Candidates const& v0s) + { + auto tracksThisCollision = tracks.sliceBy(tracksPerCollision, collision.collisionId()); + auto v0sThisCollision = v0s.sliceBy(v0sPerCollision, collision.collisionId()); + PairTrackSelection pairSelection{FilterForDerivedTables.cfgGlobalDaughterVeto.value}; + pairSelection.useV0Candidates = true; + pairSelection.v0Candidates = + collectSelectedV0Daughters(collision, v0sThisCollision, tracks, pairSelection.useGlobalDaughterVeto); + if (!hasTracksForEnabledOutputs(collision, tracksThisCollision, pairSelection)) { + return; + } + fillTrackTables(collision, tracksThisCollision, pairSelection); } - PROCESS_SWITCH(ResonanceDaughterInitializer, processDataWithPairGate, "Process data tracks with configurable pair gates", false); + PROCESS_SWITCH(ResonanceDaughterInitializer, processDataWithV0PairGate, "Process data tracks requiring a selected V0", false); + + /** + * @brief Processes data tracks when a selected cascade and collision track exist + * + * This dedicated callback deliberately has no V0 input, so enabling the + * cascade pair gate does not activate the V0 upstream dependency. + */ + void processDataWithCascPairGate(ResoCollisionWithIndex::iterator const& collision, + soa::Filtered const& tracks, + aod::ResoCascadesCandidates const& cascades) + { + auto tracksThisCollision = tracks.sliceBy(tracksPerCollision, collision.collisionId()); + auto cascadesThisCollision = cascades.sliceBy(cascadesPerCollision, collision.collisionId()); + PairTrackSelection pairSelection{FilterForDerivedTables.cfgGlobalDaughterVeto.value}; + pairSelection.useCascadeCandidates = true; + pairSelection.cascadeCandidates = + collectSelectedCascadeDaughters(collision, cascadesThisCollision, tracks, pairSelection.useGlobalDaughterVeto); + if (!hasTracksForEnabledOutputs(collision, tracksThisCollision, pairSelection)) { + return; + } + fillTrackTables(collision, tracksThisCollision, pairSelection); + } + PROCESS_SWITCH(ResonanceDaughterInitializer, processDataWithCascPairGate, "Process data tracks requiring a selected cascade", false); /** * @brief Processes MC tracks @@ -1999,7 +2891,7 @@ struct ResonanceDaughterInitializer { PROCESS_SWITCH(ResonanceDaughterInitializer, processMC, "Process tracks for MC", false); /** - * @brief Processes MC tracks with configurable V0 and cascade candidate gates + * @brief Processes MC tracks with configurable selected V0 and cascade gates */ void processMCWithPairGate(ResoCollisionWithIndex::iterator const& collision, soa::Filtered const& tracks, @@ -2007,17 +2899,60 @@ struct ResonanceDaughterInitializer { aod::ResoCascadesCandidatesMC const& cascades, aod::McParticles const&) { + auto tracksThisCollision = tracks.sliceBy(tracksMCPerCollision, collision.collisionId()); + PairTrackSelection pairSelection{FilterForDerivedTables.cfgGlobalDaughterVeto.value}; + if (!preparePairTrackSelection(collision, tracks, v0s, cascades, + v0sMCPerCollision, cascadesMCPerCollision, pairSelection)) { + return; + } + if (!hasTracksForEnabledOutputs(collision, tracksThisCollision, pairSelection)) { + return; + } + fillTrackTables(collision, tracksThisCollision, pairSelection); + } + PROCESS_SWITCH(ResonanceDaughterInitializer, processMCWithPairGate, "Process MC tracks with the configured pair-gate mode", false); + + /** + * @brief Processes MC tracks when a selected V0 and collision track exist + */ + void processMCWithV0PairGate(ResoCollisionWithIndex::iterator const& collision, + soa::Filtered const& tracks, + aod::ResoV0CandidatesMC const& v0s, + aod::McParticles const&) + { + auto tracksThisCollision = tracks.sliceBy(tracksMCPerCollision, collision.collisionId()); auto v0sThisCollision = v0s.sliceBy(v0sMCPerCollision, collision.collisionId()); - if (FilterForDerivedTables.cfgBypassNoPairV0s && v0sThisCollision.size() < 1) { + PairTrackSelection pairSelection{FilterForDerivedTables.cfgGlobalDaughterVeto.value}; + pairSelection.useV0Candidates = true; + pairSelection.v0Candidates = + collectSelectedV0Daughters(collision, v0sThisCollision, tracks, pairSelection.useGlobalDaughterVeto); + if (!hasTracksForEnabledOutputs(collision, tracksThisCollision, pairSelection)) { return; } + fillTrackTables(collision, tracksThisCollision, pairSelection); + } + PROCESS_SWITCH(ResonanceDaughterInitializer, processMCWithV0PairGate, "Process MC tracks requiring a selected V0", false); + + /** + * @brief Processes MC tracks when a selected cascade and collision track exist + */ + void processMCWithCascPairGate(ResoCollisionWithIndex::iterator const& collision, + soa::Filtered const& tracks, + aod::ResoCascadesCandidatesMC const& cascades, + aod::McParticles const&) + { + auto tracksThisCollision = tracks.sliceBy(tracksMCPerCollision, collision.collisionId()); auto cascadesThisCollision = cascades.sliceBy(cascadesMCPerCollision, collision.collisionId()); - if (FilterForDerivedTables.cfgBypassNoPairCascades && cascadesThisCollision.size() < 1) { + PairTrackSelection pairSelection{FilterForDerivedTables.cfgGlobalDaughterVeto.value}; + pairSelection.useCascadeCandidates = true; + pairSelection.cascadeCandidates = + collectSelectedCascadeDaughters(collision, cascadesThisCollision, tracks, pairSelection.useGlobalDaughterVeto); + if (!hasTracksForEnabledOutputs(collision, tracksThisCollision, pairSelection)) { return; } - fillTrackTablesForCollision(collision, tracks, tracksMCPerCollision); + fillTrackTables(collision, tracksThisCollision, pairSelection); } - PROCESS_SWITCH(ResonanceDaughterInitializer, processMCWithPairGate, "Process MC tracks with configurable pair gates", false); + PROCESS_SWITCH(ResonanceDaughterInitializer, processMCWithCascPairGate, "Process MC tracks requiring a selected cascade", false); /** * @brief Processes V0 data @@ -2033,29 +2968,6 @@ struct ResonanceDaughterInitializer { } PROCESS_SWITCH(ResonanceDaughterInitializer, processV0Data, "Process V0s for data", false); - /** - * @brief Processes data V0s grouped automatically by their original collision - * - * Both V0s and tracks are already restricted to the current original - * aod::Collision by GroupSlicer. The unfiltered track table is required for - * resolving the positive and negative daughter indices. - */ - void processV0DataHybrid(aod::Collision const&, - soa::SmallGroups const& reducedCollisions, - aod::ResoV0Candidates const& v0s, - aod::ResoTrackCandidates const& tracks) - { - if (reducedCollisions.size() == 0) { - return; - } - if (reducedCollisions.size() != 1) { - LOGF(fatal, "Expected exactly one reduced collision for an original collision, found %zu", reducedCollisions.size()); - } - auto reducedCollision = reducedCollisions.begin(); - fillV0s(reducedCollision, v0s, tracks); - } - PROCESS_SWITCH(ResonanceDaughterInitializer, processV0DataHybrid, "Process data V0s with the two-stage hybrid grouping", false); - /** * @brief Processes MC V0 data * @@ -2084,29 +2996,6 @@ struct ResonanceDaughterInitializer { } PROCESS_SWITCH(ResonanceDaughterInitializer, processCascData, "Process Cascades for data", false); - /** - * @brief Processes data cascades grouped automatically by their original collision - * - * Cascades and tracks arrive as original-collision groups. Keeping this as a - * separate callback from V0 processing avoids enabling either upstream input - * dependency unless its process switch is selected. - */ - void processCascDataHybrid(aod::Collision const&, - soa::SmallGroups const& reducedCollisions, - aod::ResoCascadesCandidates const& cascades, - aod::ResoTrackCandidates const& tracks) - { - if (reducedCollisions.size() == 0) { - return; - } - if (reducedCollisions.size() != 1) { - LOGF(fatal, "Expected exactly one reduced collision for an original collision, found %zu", reducedCollisions.size()); - } - auto reducedCollision = reducedCollisions.begin(); - fillCascades(reducedCollision, cascades, tracks); - } - PROCESS_SWITCH(ResonanceDaughterInitializer, processCascDataHybrid, "Process data cascades with the two-stage hybrid grouping", false); - /** * @brief Processes MC cascade data * diff --git a/PWGLF/TableProducer/Resonances/xi1530kaonreducedtable.cxx b/PWGLF/TableProducer/Resonances/xi1530kaonreducedtable.cxx new file mode 100644 index 00000000000..149879b75d5 --- /dev/null +++ b/PWGLF/TableProducer/Resonances/xi1530kaonreducedtable.cxx @@ -0,0 +1,1203 @@ +// 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. + +/// \file xi1530kaonreducedtable.cxx +/// \brief Producer of compact Xi(1530)^0--K reduced tables for femtoscopy. +/// \author Prottay Das, prottay.das@cern.ch + +#include "PWGLF/DataModel/LFReducedXi1530KaonTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; + +namespace +{ +constexpr float kTinyMomentum = 1.e-6f; + +inline uint8_t toU8(int value) +{ + return static_cast(std::clamp(value, 0, 255)); +} + +inline void setTrackSelBit(uint64_t& word, o2::aod::redxistark::XiStarTrackSelBit bit, bool pass) +{ + if (pass) { + word |= o2::aod::redxistark::xiStarTrackSelMask(bit); + } +} + +inline void setTopoSelBit(uint64_t& word, o2::aod::redxistark::XiStarTopoSelBit bit, bool pass) +{ + if (pass) { + word |= o2::aod::redxistark::xiStarTopoSelMask(bit); + } +} + +inline void setKaonSelBit(uint8_t& word, o2::aod::redxistarkaon::KaonSelBit bit, bool pass) +{ + if (pass) { + word |= o2::aod::redxistarkaon::kaonSelMask(bit); + } +} + +} // namespace + +struct xi1530kaonreducedtable { + // CCDB is used only to store the nominal magnetic field in the reduced event + // row. This keeps the downstream CPR QA self-contained without storing the + // run number or timestamp. + Service ccdb; + Configurable ccdbURL{"ccdbURL", "http://alice-ccdb.cern.ch", "CCDB URL for the magnetic field"}; + + // --------------------------------------------------------------------------- + // Output tables + // --------------------------------------------------------------------------- + Produces redEvents; + Produces xiStarCandidates; + Produces kaonCandidates; + + // --------------------------------------------------------------------------- + // Input table types + // --------------------------------------------------------------------------- + using EventCandidates = soa::Join; + + // One joined track type is used both for primary tracks and for the daughters + // obtained through CascDatas::{posTrack,negTrack,bachelor}_as(). + using TracksFull = soa::Join; + + // --------------------------------------------------------------------------- + // Event selections -- copied from the Xi(1530) Run-3 analysis philosophy. + // --------------------------------------------------------------------------- + struct : ConfigurableGroup { + std::string prefix = "event"; + Configurable zVtxMax{"zVtxMax", 10.f, "Maximum |z_PV| (cm)"}; + Configurable requireSel8{"requireSel8", true, "Require collision.sel8()"}; + Configurable requireINELgt0{"requireINELgt0", true, "Require multNTracksPVeta1 > 0"}; + } eventCuts; + + // --------------------------------------------------------------------------- + // Prompt / first pion from Xi(1530) -> Xi + pi. + // --------------------------------------------------------------------------- + struct : ConfigurableGroup { + std::string prefix = "piFirst"; + + Configurable etaMax{"etaMax", 0.8f, "Maximum |eta|"}; + Configurable ptMin{"ptMin", 0.15f, "Minimum pT (GeV/c)"}; + Configurable requireGlobalTrack{"requireGlobalTrack", true, "Require isGlobalTrack"}; + Configurable requirePVContributor{"requirePVContributor", true, "Require isPVContributor"}; + Configurable minITSInnerBarrelClusters{"minITSInnerBarrelClusters", 1, "Minimum ITS inner-barrel clusters"}; + Configurable minITSClusters{"minITSClusters", 3, "Minimum ITS clusters"}; + + // DCAxy: configurable; nominal/default form is pT dependent. + Configurable dcaXYUsePtDependent{"dcaXYUsePtDependent", true, "Use pT-dependent default DCAxy cut"}; + Configurable dcaXYp0{"dcaXYp0", 0.004f, "DCAxy(pT) p0 (cm)"}; + Configurable dcaXYp1{"dcaXYp1", 0.013f, "DCAxy(pT) p1 (cm GeV/c)"}; + Configurable dcaXYMaxConstant{"dcaXYMaxConstant", 0.1f, "Constant |DCAxy| max if pT-dependent mode is disabled (cm)"}; + + // DCAz: independently configurable; nominal/default form is also pT dependent. + // Two additional alternatives are retained in the track-selection bitmap. + Configurable dcaZUsePtDependent{"dcaZUsePtDependent", true, "Use pT-dependent default DCAz cut"}; + Configurable dcaZp0{"dcaZp0", 0.004f, "DCAz(pT) p0 (cm)"}; + Configurable dcaZp1{"dcaZp1", 0.013f, "DCAz(pT) p1 (cm GeV/c)"}; + Configurable dcaZMaxConstant{"dcaZMaxConstant", 0.1f, "Constant default |DCAz| max if pT-dependent mode is disabled (cm)"}; + Configurable dcaZLoose{"dcaZLoose", 1.0f, "Alternative loose |DCAz| maximum (cm)"}; + Configurable dcaZTightVariation{"dcaZTightVariation", 0.1f, "Alternative |DCAz| maximum (cm)"}; + + // TPC rows: loose/default/tight from the Xi(1530) systematic table. + Configurable tpcRowsLoose{"tpcRowsLoose", 70, "Loose minimum crossed rows (strict >)"}; + Configurable tpcRowsDefault{"tpcRowsDefault", 80, "Default minimum crossed rows (strict >)"}; + Configurable tpcRowsTight{"tpcRowsTight", 90, "Tight minimum crossed rows (strict >)"}; + } piFirstCuts; + + // --------------------------------------------------------------------------- + // PID working points. + // V0 daughters (Lambda pion/proton): TPC only. + // Prompt Xi* pion: retain BOTH pure TPC-only and hybrid TPC/TOF choices. + // Xi bachelor pion: retain BOTH pure TPC-only and hybrid TPC/TOF choices. + // Hybrid means: if no TOF, TPC only; if TOF exists, use a circular + // sqrt(nSigmaTPC^2+nSigmaTOF^2) cut. + // --------------------------------------------------------------------------- + struct : ConfigurableGroup { + std::string prefix = "v0Pid"; + Configurable nSigma3{"nSigma3", 3.f, "V0-daughter TPC PID 3-sigma WP"}; + Configurable nSigma4{"nSigma4", 4.f, "V0-daughter TPC PID 4-sigma WP (dedicated Lambda nominal)"}; + Configurable nSigma4p8{"nSigma4p8", 4.8f, "V0 pion TPC PID pp-Xi WP"}; + Configurable nSigma5{"nSigma5", 5.f, "V0-daughter TPC PID 5-sigma WP / pp-Xi proton WP"}; + Configurable nSigma6{"nSigma6", 6.f, "V0-daughter TPC PID 6-sigma loose envelope"}; + } v0PidCuts; + + struct : ConfigurableGroup { + std::string prefix = "otherTrackPid"; + Configurable nSigma3{"nSigma3", 3.f, "Prompt/bachelor pion PID 3-sigma WP (TPC-only or hybrid)"}; + Configurable nSigma4{"nSigma4", 4.f, "Prompt/bachelor pion PID 4-sigma WP (TPC-only or hybrid)"}; + Configurable nSigma5{"nSigma5", 5.f, "Prompt/bachelor pion PID 5-sigma WP (TPC-only or hybrid)"}; + Configurable nSigma6{"nSigma6", 6.f, "Prompt/bachelor pion PID 6-sigma loose envelope (TPC-only or hybrid)"}; + Configurable bachelorTPC4p8{"bachelorTPC4p8", 4.8f, "TPC-only Xi-bachelor pion pp-Xi WP"}; + } otherTrackPidCuts; + + // Second prompt-pion PID recipe: + // pT < ptThreshold -> TPC-only PID, even if the track has TOF + // pT >= ptThreshold -> circular sqrt(TPC^2 + TOF^2) PID + // By default TOF is required above the threshold. This can be disabled. + // TPC and circular limits are independently configurable for each WP. + struct : ConfigurableGroup { + std::string prefix = "piFirstThresholdPid"; + Configurable ptThreshold{"ptThreshold", 0.5f, "Prompt-pion pT threshold above which circular TPC+TOF PID is applied (GeV/c)"}; + Configurable requireTOFAboveThreshold{"requireTOFAboveThreshold", true, "Require valid TOF for prompt pion at/above ptThreshold"}; + + Configurable tpcNSigma3{"tpcNSigma3", 3.f, "TPC-only limit for threshold PID 3-sigma WP"}; + Configurable tpcNSigma4{"tpcNSigma4", 4.f, "TPC-only limit for threshold PID 4-sigma WP"}; + Configurable tpcNSigma5{"tpcNSigma5", 5.f, "TPC-only limit for threshold PID 5-sigma WP"}; + Configurable tpcNSigma6{"tpcNSigma6", 6.f, "TPC-only limit for threshold PID 6-sigma loose envelope"}; + + Configurable circularNSigma3{"circularNSigma3", 3.f, "Circular TPC+TOF limit for threshold PID 3-sigma WP"}; + Configurable circularNSigma4{"circularNSigma4", 4.f, "Circular TPC+TOF limit for threshold PID 4-sigma WP"}; + Configurable circularNSigma5{"circularNSigma5", 5.f, "Circular TPC+TOF limit for threshold PID 5-sigma WP"}; + Configurable circularNSigma6{"circularNSigma6", 6.f, "Circular TPC+TOF limit for threshold PID 6-sigma loose envelope"}; + } piFirstThresholdPidCuts; + + // --------------------------------------------------------------------------- + // Cascade daughter quality and fixed cascade acceptance/lifetime cuts. + // Exact source-defined topology working points are in the next group. + // --------------------------------------------------------------------------- + struct : ConfigurableGroup { + std::string prefix = "cascadeBase"; + + // Fixed producer-level acceptance / quality cuts. + Configurable daughterEtaMax{"daughterEtaMax", 0.8f, "Maximum |eta| of cascade daughters (fixed producer cut)"}; + Configurable daughterTPCrowsMin{"daughterTPCrowsMin", 50, "Broad minimum TPC crossed rows for all cascade daughters (strict >)"}; + Configurable lambdaPionPtMin{"lambdaPionPtMin", 0.2f, "Minimum Lambda-daughter pion pT (GeV/c), fixed producer cut"}; + Configurable lambdaProtonPtMin{"lambdaProtonPtMin", 0.2f, "Minimum Lambda-daughter proton pT (GeV/c), fixed producer cut"}; + Configurable lambdaRapidityMax{"lambdaRapidityMax", 0.5f, "Maximum |y_Lambda|, fixed producer cut"}; + Configurable cascadeEtaMax{"cascadeEtaMax", 0.8f, "Maximum |eta| of Xi candidate (fixed producer cut)"}; + Configurable cascadePtMin{"cascadePtMin", 0.15f, "Minimum Xi-candidate pT (GeV/c), fixed producer cut"}; + Configurable maxV0Radius{"maxV0Radius", 30.f, "Maximum V0/Lambda radius (cm), fixed producer cut"}; + Configurable maxCascRadius{"maxCascRadius", 200.f, "Maximum cascade radius (cm), fixed producer cut"}; + } cascadeBaseCuts; + + // --------------------------------------------------------------------------- + // Exact topology working points retained in the topology-selection bitmap. + // The producer applies only the loosest UNION envelope of these values. + // --------------------------------------------------------------------------- + struct : ConfigurableGroup { + std::string prefix = "topology"; + + // V0 daughter DCA to PV (minimum, cm). + Configurable v0PionDcaPV005{"v0PionDcaPV005", 0.05f, "Min pion DCA to PV: 0.05 cm"}; + Configurable v0PionDcaPV006{"v0PionDcaPV006", 0.06f, "Min pion DCA to PV: 0.06 cm (Xi* nominal)"}; + Configurable v0PionDcaPV010{"v0PionDcaPV010", 0.10f, "Min pion DCA to PV: 0.10 cm"}; + Configurable v0PionDcaPV020{"v0PionDcaPV020", 0.20f, "Min pion DCA to PV: 0.20 cm (dedicated Lambda)"}; + + Configurable v0ProtonDcaPV005{"v0ProtonDcaPV005", 0.05f, "Min proton DCA to PV: 0.05 cm"}; + Configurable v0ProtonDcaPV006{"v0ProtonDcaPV006", 0.06f, "Min proton DCA to PV: 0.06 cm (Xi* nominal)"}; + Configurable v0ProtonDcaPV007{"v0ProtonDcaPV007", 0.07f, "Min proton DCA to PV: 0.07 cm (dedicated Lambda)"}; + Configurable v0ProtonDcaPV010{"v0ProtonDcaPV010", 0.10f, "Min proton DCA to PV: 0.10 cm"}; + + // As requested, keep the Xi(1530)-analysis MINIMUM DCA(V0,PV) convention. + Configurable v0DcaPV000{"v0DcaPV000", 0.00f, "Min Lambda/V0 DCA to PV: 0.00 cm"}; + Configurable v0DcaPV003{"v0DcaPV003", 0.03f, "Min Lambda/V0 DCA to PV: 0.03 cm"}; + Configurable v0DcaPV010{"v0DcaPV010", 0.10f, "Min Lambda/V0 DCA to PV: 0.10 cm"}; + + // Native CascDatas V0-daughter DCA / fitter metric (maximum). + Configurable v0DcaDaughters1p0{"v0DcaDaughters1p0", 1.0f, "Max V0-daughter DCA/native fitter metric: 1.0"}; + Configurable v0DcaDaughters0p5{"v0DcaDaughters0p5", 0.5f, "Max V0-daughter DCA/native fitter metric: 0.5"}; + Configurable v0DcaDaughters0p1{"v0DcaDaughters0p1", 0.1f, "Max V0-daughter DCA/native fitter metric: 0.1"}; + + Configurable v0CosPA097{"v0CosPA097", 0.97f, "Min V0 cosPA: 0.97"}; + Configurable v0CosPA098{"v0CosPA098", 0.98f, "Min V0 cosPA: 0.98 (Xi* nominal)"}; + Configurable v0CosPA09876{"v0CosPA09876", 0.9876f, "Min V0 cosPA: 0.9876 (pp-Xi)"}; + Configurable v0CosPA099{"v0CosPA099", 0.99f, "Min V0 cosPA: 0.99"}; + Configurable v0CosPA0995{"v0CosPA0995", 0.995f, "Min V0 cosPA: 0.995 (dedicated Lambda)"}; + + Configurable v0Radius0p9{"v0Radius0p9", 0.9f, "Min V0 radius: 0.9 cm"}; + Configurable v0Radius1p01{"v0Radius1p01", 1.01f, "Min V0 radius: 1.01 cm (Xi* nominal)"}; + Configurable v0Radius1p2{"v0Radius1p2", 1.2f, "Min V0 radius: 1.2 cm (pp-Xi)"}; + Configurable v0Radius2p5{"v0Radius2p5", 2.5f, "Min V0 radius: 2.5 cm"}; + Configurable v0Radius3p0{"v0Radius3p0", 3.0f, "Min V0 radius: 3.0 cm (dedicated Lambda)"}; + + Configurable lambdaMass10MeV{"lambdaMass10MeV", 0.010f, "Lambda mass window: 10 MeV/c2"}; + Configurable lambdaMass8MeV{"lambdaMass8MeV", 0.008f, "Lambda mass window: 8 MeV/c2 (Xi* nominal)"}; + Configurable lambdaMass6MeV{"lambdaMass6MeV", 0.006f, "Lambda mass window: 6 MeV/c2"}; + Configurable lambdaMass11p6MeV{"lambdaMass11p6MeV", 0.0116f, "Lambda mass window: 11.6 MeV/c2 (pp-Xi)"}; + + Configurable v0LifetimeDefault{"v0LifetimeDefault", 30.f, "Max Lambda proper lifetime: 30 cm"}; + Configurable v0LifetimeVar1{"v0LifetimeVar1", 30.f, "Reserved Lambda lifetime Var1 max; set when defined"}; + Configurable v0LifetimeVar2{"v0LifetimeVar2", 30.f, "Reserved Lambda lifetime Var2 max; set when defined"}; + + Configurable v0DaughterRows70{"v0DaughterRows70", 70, "Both Lambda daughters: TPC crossed rows >70"}; + Configurable v0DaughterRowsVar1{"v0DaughterRowsVar1", 70, "Reserved Lambda-daughter crossed-row Var1; set when defined"}; + Configurable v0DaughterRowsVar2{"v0DaughterRowsVar2", 70, "Reserved Lambda-daughter crossed-row Var2; set when defined"}; + + // Xi / cascade. + Configurable cascBachelorDcaPV005{"cascBachelorDcaPV005", 0.05f, "Min bachelor DCA to PV: 0.05 cm (pp-Xi)"}; + Configurable cascBachelorDcaPV006{"cascBachelorDcaPV006", 0.06f, "Min bachelor DCA to PV: 0.06 cm (Xi* nominal)"}; + Configurable cascBachelorDcaPV010{"cascBachelorDcaPV010", 0.10f, "Min bachelor DCA to PV: 0.10 cm"}; + + // Native CascDatas cascade-daughter DCA / fitter metric (maximum). + Configurable cascDcaDaughters1p0{"cascDcaDaughters1p0", 1.0f, "Max cascade-daughter DCA/native fitter metric: 1.0"}; + Configurable cascDcaDaughters0p25{"cascDcaDaughters0p25", 0.25f, "Max cascade-daughter DCA/native fitter metric: 0.25 (Xi* and pp-Xi)"}; + Configurable cascDcaDaughters0p20{"cascDcaDaughters0p20", 0.20f, "Max cascade-daughter DCA/native fitter metric: 0.20"}; + + Configurable cascCosPA097{"cascCosPA097", 0.97f, "Min cascade cosPA: 0.97"}; + Configurable cascCosPA098{"cascCosPA098", 0.98f, "Min cascade cosPA: 0.98 (Xi* nominal)"}; + Configurable cascCosPA09947{"cascCosPA09947", 0.9947f, "Min cascade cosPA: 0.9947 (pp-Xi)"}; + Configurable cascCosPA0995{"cascCosPA0995", 0.995f, "Min cascade cosPA: 0.995"}; + + Configurable cascRadius0p9{"cascRadius0p9", 0.9f, "Min cascade radius: 0.9 cm"}; + Configurable cascRadius1p0{"cascRadius1p0", 1.0f, "Min cascade radius: 1.0 cm (pp-Xi)"}; + Configurable cascRadius1p01{"cascRadius1p01", 1.01f, "Min cascade radius: 1.01 cm (Xi* nominal)"}; + Configurable cascRadius1p3{"cascRadius1p3", 1.3f, "Min cascade radius: 1.3 cm"}; + + Configurable xiMass10MeV{"xiMass10MeV", 0.010f, "Xi mass window: 10 MeV/c2"}; + Configurable xiMass8MeV{"xiMass8MeV", 0.008f, "Xi mass window: 8 MeV/c2 (Xi* nominal)"}; + Configurable xiMass6MeV{"xiMass6MeV", 0.006f, "Xi mass window: 6 MeV/c2"}; + + // Xi proper-lifetime working points, mL/p in cm. + // The default 22.6 cm corresponds approximately to 4.6*c*tau_Xi. + Configurable xiLifetimeDefault{"xiLifetimeDefault", 22.6f, "Default Xi proper-lifetime maximum mL/p (cm), ~4.6*c*tau_Xi"}; + Configurable xiLifetimeVar1{"xiLifetimeVar1", 15.0f, "Xi proper-lifetime variation 1 maximum mL/p (cm)"}; + Configurable xiLifetimeVar2{"xiLifetimeVar2", 12.0f, "Xi proper-lifetime variation 2 maximum mL/p (cm)"}; + + Configurable bachBaryonDCAxyPP{"bachBaryonDCAxyPP", 0.020f, "pp-Xi min |DCAxy| between bachelor and baryon (cm)"}; + Configurable xiRapidityPPMax{"xiRapidityPPMax", 0.5f, "pp-Xi maximum |y_Xi|"}; + } topoCuts; + + // --------------------------------------------------------------------------- + // Xi(1530) candidate retention. + // 1.45--1.70 GeV/c2 deliberately contains the existing LS-normalisation + // sidebands; in particular the right sideband extends to about 1.678 GeV/c2. + // There is NO Xi(1530) pT cut here. + // --------------------------------------------------------------------------- + struct : ConfigurableGroup { + std::string prefix = "xiStar"; + Configurable massMin{"massMin", 1.45f, "Minimum retained M(Xi pi) (GeV/c2)"}; + Configurable massMax{"massMax", 1.70f, "Maximum retained M(Xi pi) (GeV/c2)"}; + Configurable rapidityMax{"rapidityMax", 0.5f, "Maximum |y_XiStar|"}; + } xiStarCuts; + + // --------------------------------------------------------------------------- + // External primary K. + // Raw TPC/TOF PID is retained downstream. DCA is NOT stored as floats; + // instead, default/variation decisions are packed into a uint8_t bitmap. + // --------------------------------------------------------------------------- + struct : ConfigurableGroup { + std::string prefix = "kaon"; + Configurable etaMax{"etaMax", 0.8f, "Maximum |eta_K|"}; + Configurable ptMin{"ptMin", 0.15f, "Minimum pT_K (GeV/c)"}; + Configurable requireGlobalTrack{"requireGlobalTrack", true, "Require isGlobalTrack (same quality baseline as prompt pion)"}; + Configurable requirePVContributor{"requirePVContributor", true, "Require isPVContributor"}; + Configurable tpcNSigmaEnvelope{"tpcNSigmaEnvelope", 6.f, "Loose |TPC nSigma_K| producer envelope"}; + + // Default K DCA working points are pT dependent. Optional constant Var1/Var2 + // values are disabled by default (<=0). If enabled, the producer retains the + // union of the default and enabled alternatives, so looser variations remain + // available downstream without storing raw DCA values. + Configurable dcaXYUsePtDependent{"dcaXYUsePtDependent", true, "Use pT-dependent default DCAxy cut"}; + Configurable dcaXYp0{"dcaXYp0", 0.004f, "K DCAxy(pT) p0 (cm)"}; + Configurable dcaXYp1{"dcaXYp1", 0.013f, "K DCAxy(pT) p1 (cm GeV/c)"}; + Configurable dcaXYMaxConstant{"dcaXYMaxConstant", 0.1f, "Constant default |DCAxy| max if pT-dependent mode is disabled (cm)"}; + Configurable dcaXYVar1Max{"dcaXYVar1Max", -1.f, "Optional K |DCAxy| Var1 max; <=0 disables (cm)"}; + Configurable dcaXYVar2Max{"dcaXYVar2Max", -1.f, "Optional K |DCAxy| Var2 max; <=0 disables (cm)"}; + + Configurable dcaZUsePtDependent{"dcaZUsePtDependent", true, "Use pT-dependent default DCAz cut"}; + Configurable dcaZp0{"dcaZp0", 0.004f, "K DCAz(pT) p0 (cm)"}; + Configurable dcaZp1{"dcaZp1", 0.013f, "K DCAz(pT) p1 (cm GeV/c)"}; + Configurable dcaZMaxConstant{"dcaZMaxConstant", 0.1f, "Constant default |DCAz| max if pT-dependent mode is disabled (cm)"}; + Configurable dcaZVar1Max{"dcaZVar1Max", -1.f, "Optional K |DCAz| Var1 max; <=0 disables (cm)"}; + Configurable dcaZVar2Max{"dcaZVar2Max", -1.f, "Optional K |DCAz| Var2 max; <=0 disables (cm)"}; + } kaonCuts; + + // --------------------------------------------------------------------------- + // Minimal QA. Histograms do not contribute to the reduced AOD row size. + // --------------------------------------------------------------------------- + HistogramRegistry qa{"qa", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext const&) + { + ccdb->setURL(ccdbURL.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + + qa.add("hEventCutFlow", "Event cut flow;;events", HistType::kTH1F, {{6, 0.5, 6.5}}); + qa.add("hFT0MPercentile", "FT0M multiplicity percentile of written events;FT0M percentile (%);events", HistType::kTH1F, {{110, 0., 110.}}); + qa.add("hLambdaMass", "Selected loose-envelope Lambda mass;M_{p#pi} (GeV/c^{2});counts", HistType::kTH1F, {{240, 1.09, 1.14}}); + qa.add("hXiMass", "Selected loose-envelope Xi mass;M_{#Lambda#pi} (GeV/c^{2});counts", HistType::kTH1F, {{240, 1.29, 1.35}}); + qa.add("hXiStarMassUS", "US #Xi#pi candidates;M_{#Xi#pi} (GeV/c^{2});counts", HistType::kTH1F, {{500, 1.45, 1.70}}); + qa.add("hXiStarMassLS", "LS #Xi#pi candidates;M_{#Xi#pi} (GeV/c^{2});counts", HistType::kTH1F, {{500, 1.45, 1.70}}); + qa.add("hXiStarMassVsChannel", "#Xi#pi mass vs channel;M_{#Xi#pi} (GeV/c^{2});channel", HistType::kTH2F, {{500, 1.45, 1.70}, {5, -2.5, 2.5}}); + qa.add("hKaonTPCnSigmaVsP", "External K TPC PID;p (GeV/c);n#sigma_{TPC}^{K}", HistType::kTH2F, {{200, 0., 10.}, {160, -8., 8.}}); + qa.add("hKaonTOFnSigmaVsP", "External K TOF PID;p (GeV/c);n#sigma_{TOF}^{K}", HistType::kTH2F, {{200, 0., 10.}, {160, -8., 8.}}); + qa.add("hPiFirstTPCnSigmaVsPt", "Prompt pion TPC PID;p_{T} (GeV/c);n#sigma_{TPC}^{#pi}", HistType::kTH2F, {{200, 0., 10.}, {160, -8., 8.}}); + qa.add("hNObjectsPerWrittenEvent", "Objects in written events;N;type (0=#Xi#pi,1=K)", HistType::kTH2F, {{100, -0.5, 99.5}, {2, -0.5, 1.5}}); + + auto h = qa.get(HIST("hEventCutFlow")); + h->GetXaxis()->SetBinLabel(1, "all"); + h->GetXaxis()->SetBinLabel(2, "|z|<10"); + h->GetXaxis()->SetBinLabel(3, "sel8"); + h->GetXaxis()->SetBinLabel(4, "INEL>0"); + h->GetXaxis()->SetBinLabel(5, "XiPi present"); + h->GetXaxis()->SetBinLabel(6, "written"); + } + + // --------------------------------------------------------------------------- + // Small PODs used only inside one collision. They keep us from writing any + // reduced row until we know the event is useful. + // --------------------------------------------------------------------------- + struct PromptPionTmp { + float px{0.f}, py{0.f}, pz{0.f}; + int8_t charge{0}; + int64_t trackIndex{-1}; + uint64_t trackBits{0}; + }; + + struct XiTmp { + float px{0.f}, py{0.f}, pz{0.f}; + float mass{0.f}; + int8_t sign{0}; + int64_t bachelorIndex{-1}; + int64_t posIndex{-1}; + int64_t negIndex{-1}; + uint64_t trackBits{0}; + uint64_t topologyBits{0}; + }; + + struct XiStarTmp { + int8_t channel{0}; + float px{0.f}, py{0.f}, pz{0.f}; + float mass{0.f}; + uint64_t trackBits{0}; + uint64_t topologyBits{0}; + float pionPt{0.f}, pionEta{0.f}, pionPhi{0.f}; + int64_t pionIndex{-1}; + int64_t bachelorIndex{-1}; + int64_t posIndex{-1}; + int64_t negIndex{-1}; + }; + + struct KaonTmp { + int8_t charge{0}; + float px{0.f}, py{0.f}, pz{0.f}; + int64_t trackIndex{-1}; + uint8_t bits{0}; + uint8_t tpcNClsCrossedRows{0}; + float tpcNSigmaKa{999.f}; + float tofNSigmaKa{-999.f}; + bool hasTOF{false}; + }; + + // --------------------------------------------------------------------------- + // Event selection + // --------------------------------------------------------------------------- + template + bool passEvent(TCollision const& collision) + { + qa.fill(HIST("hEventCutFlow"), 1.0); + + if (std::abs(collision.posZ()) >= eventCuts.zVtxMax) { + return false; + } + qa.fill(HIST("hEventCutFlow"), 2.0); + + if (eventCuts.requireSel8 && !collision.sel8()) { + return false; + } + qa.fill(HIST("hEventCutFlow"), 3.0); + + if (eventCuts.requireINELgt0 && collision.multNTracksPVeta1() < 1) { + return false; + } + qa.fill(HIST("hEventCutFlow"), 4.0); + return true; + } + + // --------------------------------------------------------------------------- + // Prompt-pion selection and bitmap + // --------------------------------------------------------------------------- + template + bool passPionHybridPID(TTrack const& track, float nSigmaLimit) const + { + const float tpc = track.tpcNSigmaPi(); + if (!track.hasTOF()) { + return std::abs(tpc) < nSigmaLimit; + } + const float tof = track.tofNSigmaPi(); + return std::hypot(tpc, tof) < nSigmaLimit; + } + + // Threshold-based prompt-pion PID recipe. + // Below threshold: TPC only, irrespective of whether TOF happens to exist. + // At/above threshold: circular TPC+TOF. If TOF is absent, the configurable + // requireTOFAboveThreshold decides whether the track fails or falls back to TPC. + template + bool passPromptPionThresholdPID(TTrack const& track, + float tpcNSigmaLimit, + float circularNSigmaLimit) const + { + const float tpc = track.tpcNSigmaPi(); + + if (track.pt() < piFirstThresholdPidCuts.ptThreshold.value) { + return std::abs(tpc) < tpcNSigmaLimit; + } + + if (!track.hasTOF()) { + if (piFirstThresholdPidCuts.requireTOFAboveThreshold.value) { + return false; + } + return std::abs(tpc) < tpcNSigmaLimit; + } + + const float tof = track.tofNSigmaPi(); + return std::hypot(tpc, tof) < circularNSigmaLimit; + } + + static float dcaLimit(float pt, bool usePtDependent, float p0, float p1, float constantMax) + { + if (usePtDependent) { + return p0 + p1 / std::max(pt, kTinyMomentum); + } + return constantMax; + } + + float getMagneticField(uint64_t timestamp) + { + auto* grpo = ccdb->getForTimeStamp("/GLO/Config/GRPMagField", timestamp); + if (grpo == nullptr) { + LOGF(fatal, "GRPMagField object not found in CCDB for timestamp %llu", + static_cast(timestamp)); + return 0.f; + } + return 0.1f * grpo->getNominalL3Field(); // kG -> T + } + + template + bool buildPromptPion(TTrack const& track, PromptPionTmp& out) + { + if (std::abs(track.eta()) >= piFirstCuts.etaMax) { + return false; + } + if (track.pt() <= piFirstCuts.ptMin) { + return false; + } + if (piFirstCuts.requireGlobalTrack && !track.isGlobalTrack()) { + return false; + } + if (piFirstCuts.requirePVContributor && !track.isPVContributor()) { + return false; + } + if (track.itsNClsInnerBarrel() < piFirstCuts.minITSInnerBarrelClusters) { + return false; + } + if (track.itsNCls() < piFirstCuts.minITSClusters) { + return false; + } + + const float dcaXYDefault = dcaLimit(track.pt(), piFirstCuts.dcaXYUsePtDependent.value, + piFirstCuts.dcaXYp0.value, piFirstCuts.dcaXYp1.value, + piFirstCuts.dcaXYMaxConstant.value); + if (std::abs(track.dcaXY()) >= dcaXYDefault) { + return false; + } + + const float dcaZDefault = dcaLimit(track.pt(), piFirstCuts.dcaZUsePtDependent.value, + piFirstCuts.dcaZp0.value, piFirstCuts.dcaZp1.value, + piFirstCuts.dcaZMaxConstant.value); + const float dcaZEnvelope = std::max({dcaZDefault, piFirstCuts.dcaZLoose.value, + piFirstCuts.dcaZTightVariation.value}); + if (std::abs(track.dcaZ()) >= dcaZEnvelope) { + return false; + } + + if (track.tpcNClsCrossedRows() <= piFirstCuts.tpcRowsLoose) { + return false; + } + + // Retain the UNION of all prompt-pion PID choices through their loosest + // (6-sigma) working points. The explicit TPC-only envelope is essential: + // a track with valid TOF may fail the circular hybrid cut while still + // satisfying the desired TPC-only selection. + const bool passTPCOnlyEnvelope = + std::abs(track.tpcNSigmaPi()) < otherTrackPidCuts.nSigma6.value; + const bool passAvailabilityEnvelope = + passPionHybridPID(track, otherTrackPidCuts.nSigma6.value); + const bool passThresholdEnvelope = + passPromptPionThresholdPID(track, + piFirstThresholdPidCuts.tpcNSigma6.value, + piFirstThresholdPidCuts.circularNSigma6.value); + if (!(passTPCOnlyEnvelope || passAvailabilityEnvelope || passThresholdEnvelope)) { + return false; + } + + uint64_t trackBits = 0; + + setTrackSelBit(trackBits, redxistark::kPiFirstPID3Sigma, + passPionHybridPID(track, otherTrackPidCuts.nSigma3.value)); + setTrackSelBit(trackBits, redxistark::kPiFirstPID4Sigma, + passPionHybridPID(track, otherTrackPidCuts.nSigma4.value)); + setTrackSelBit(trackBits, redxistark::kPiFirstPID5Sigma, + passPionHybridPID(track, otherTrackPidCuts.nSigma5.value)); + setTrackSelBit(trackBits, redxistark::kPiFirstPID6Sigma, + passPionHybridPID(track, otherTrackPidCuts.nSigma6.value)); + + setTrackSelBit(trackBits, redxistark::kPiFirstPtThresholdPID3Sigma, + passPromptPionThresholdPID(track, + piFirstThresholdPidCuts.tpcNSigma3.value, + piFirstThresholdPidCuts.circularNSigma3.value)); + setTrackSelBit(trackBits, redxistark::kPiFirstPtThresholdPID4Sigma, + passPromptPionThresholdPID(track, + piFirstThresholdPidCuts.tpcNSigma4.value, + piFirstThresholdPidCuts.circularNSigma4.value)); + setTrackSelBit(trackBits, redxistark::kPiFirstPtThresholdPID5Sigma, + passPromptPionThresholdPID(track, + piFirstThresholdPidCuts.tpcNSigma5.value, + piFirstThresholdPidCuts.circularNSigma5.value)); + setTrackSelBit(trackBits, redxistark::kPiFirstPtThresholdPID6Sigma, + passPromptPionThresholdPID(track, + piFirstThresholdPidCuts.tpcNSigma6.value, + piFirstThresholdPidCuts.circularNSigma6.value)); + + // Pure TPC-only prompt-pion PID bits. These remain valid irrespective of + // TOF availability and therefore support an all-pion TPC-only analysis. + const float absPromptTPCPi = std::abs(track.tpcNSigmaPi()); + setTrackSelBit(trackBits, redxistark::kPiFirstTPC3Sigma, + absPromptTPCPi < otherTrackPidCuts.nSigma3.value); + setTrackSelBit(trackBits, redxistark::kPiFirstTPC4Sigma, + absPromptTPCPi < otherTrackPidCuts.nSigma4.value); + setTrackSelBit(trackBits, redxistark::kPiFirstTPC5Sigma, + absPromptTPCPi < otherTrackPidCuts.nSigma5.value); + setTrackSelBit(trackBits, redxistark::kPiFirstTPC6Sigma, + absPromptTPCPi < otherTrackPidCuts.nSigma6.value); + + setTrackSelBit(trackBits, redxistark::kPiFirstTPCRows70, track.tpcNClsCrossedRows() > piFirstCuts.tpcRowsLoose); + setTrackSelBit(trackBits, redxistark::kPiFirstTPCRows80, track.tpcNClsCrossedRows() > piFirstCuts.tpcRowsDefault); + setTrackSelBit(trackBits, redxistark::kPiFirstTPCRows90, track.tpcNClsCrossedRows() > piFirstCuts.tpcRowsTight); + + setTrackSelBit(trackBits, redxistark::kPiFirstDCAz1cm, std::abs(track.dcaZ()) < piFirstCuts.dcaZLoose.value); + setTrackSelBit(trackBits, redxistark::kPiFirstDCAzDefault, std::abs(track.dcaZ()) < dcaZDefault); + setTrackSelBit(trackBits, redxistark::kPiFirstDCAz0p1cm, std::abs(track.dcaZ()) < piFirstCuts.dcaZTightVariation.value); + + out.px = track.px(); + out.py = track.py(); + out.pz = track.pz(); + out.charge = static_cast(track.sign()); + out.trackIndex = track.globalIndex(); + out.trackBits = trackBits; + + qa.fill(HIST("hPiFirstTPCnSigmaVsPt"), track.pt(), track.tpcNSigmaPi()); + return true; + } + + // --------------------------------------------------------------------------- + // External primary-K producer envelope + // --------------------------------------------------------------------------- + template + bool buildKaon(TTrack const& track, KaonTmp& out) + { + if (std::abs(track.eta()) >= kaonCuts.etaMax) { + return false; + } + if (track.pt() <= kaonCuts.ptMin) { + return false; + } + if (kaonCuts.requireGlobalTrack && !track.isGlobalTrack()) { + return false; + } + if (kaonCuts.requirePVContributor && !track.isPVContributor()) { + return false; + } + if (track.itsNClsInnerBarrel() < piFirstCuts.minITSInnerBarrelClusters) { + return false; + } + if (track.itsNCls() < piFirstCuts.minITSClusters) { + return false; + } + if (track.tpcNClsCrossedRows() <= piFirstCuts.tpcRowsLoose) { + return false; + } + if (std::abs(track.tpcNSigmaKa()) >= kaonCuts.tpcNSigmaEnvelope) { + return false; + } + + const float absDcaXY = std::abs(track.dcaXY()); + const float absDcaZ = std::abs(track.dcaZ()); + const float dcaXYDefault = dcaLimit(track.pt(), kaonCuts.dcaXYUsePtDependent.value, + kaonCuts.dcaXYp0.value, kaonCuts.dcaXYp1.value, + kaonCuts.dcaXYMaxConstant.value); + const float dcaZDefault = dcaLimit(track.pt(), kaonCuts.dcaZUsePtDependent.value, + kaonCuts.dcaZp0.value, kaonCuts.dcaZp1.value, + kaonCuts.dcaZMaxConstant.value); + + const bool passXYDefault = absDcaXY < dcaXYDefault; + const bool passXYVar1 = kaonCuts.dcaXYVar1Max.value > 0.f && absDcaXY < kaonCuts.dcaXYVar1Max.value; + const bool passXYVar2 = kaonCuts.dcaXYVar2Max.value > 0.f && absDcaXY < kaonCuts.dcaXYVar2Max.value; + const bool passZDefault = absDcaZ < dcaZDefault; + const bool passZVar1 = kaonCuts.dcaZVar1Max.value > 0.f && absDcaZ < kaonCuts.dcaZVar1Max.value; + const bool passZVar2 = kaonCuts.dcaZVar2Max.value > 0.f && absDcaZ < kaonCuts.dcaZVar2Max.value; + + // Retain the union of enabled DCA working points, but do not store raw DCA. + if (!(passXYDefault || passXYVar1 || passXYVar2) || + !(passZDefault || passZVar1 || passZVar2)) { + return false; + } + + uint8_t bits = 0; + setKaonSelBit(bits, redxistarkaon::kKaonDCAxyDefault, passXYDefault); + setKaonSelBit(bits, redxistarkaon::kKaonDCAxyVar1, passXYVar1); + setKaonSelBit(bits, redxistarkaon::kKaonDCAxyVar2, passXYVar2); + setKaonSelBit(bits, redxistarkaon::kKaonDCAzDefault, passZDefault); + setKaonSelBit(bits, redxistarkaon::kKaonDCAzVar1, passZVar1); + setKaonSelBit(bits, redxistarkaon::kKaonDCAzVar2, passZVar2); + + out.charge = static_cast(track.sign()); + out.px = track.px(); + out.py = track.py(); + out.pz = track.pz(); + out.trackIndex = track.globalIndex(); + out.bits = bits; + out.tpcNClsCrossedRows = toU8(track.tpcNClsCrossedRows()); + out.tpcNSigmaKa = track.tpcNSigmaKa(); + out.hasTOF = track.hasTOF(); + out.tofNSigmaKa = out.hasTOF ? track.tofNSigmaKa() : -999.f; + + const float p = std::sqrt(track.px() * track.px() + track.py() * track.py() + track.pz() * track.pz()); + qa.fill(HIST("hKaonTPCnSigmaVsP"), p, track.tpcNSigmaKa()); + if (track.hasTOF()) { + qa.fill(HIST("hKaonTOFnSigmaVsP"), p, track.tofNSigmaKa()); + } + return true; + } + + // --------------------------------------------------------------------------- + // Xi candidate from a native CascDatas row. + // --------------------------------------------------------------------------- + template + bool buildXi(TCollision const& collision, TCascade const& casc, XiTmp& out) + { + if (casc.sign() == 0) { + return false; + } + if (std::abs(casc.eta()) >= cascadeBaseCuts.cascadeEtaMax) { + return false; + } + if (casc.pt() <= cascadeBaseCuts.cascadePtMin) { + return false; + } + + const auto pos = casc.template posTrack_as(); + const auto neg = casc.template negTrack_as(); + const auto bach = casc.template bachelor_as(); + + // Fixed broad daughter acceptance. The >50 crossed-row pp-Xi WP is also + // explicitly stored as a track-selection bit below. + if (std::abs(pos.eta()) >= cascadeBaseCuts.daughterEtaMax || + std::abs(neg.eta()) >= cascadeBaseCuts.daughterEtaMax || + std::abs(bach.eta()) >= cascadeBaseCuts.daughterEtaMax) { + return false; + } + if (pos.tpcNClsCrossedRows() <= cascadeBaseCuts.daughterTPCrowsMin || + neg.tpcNClsCrossedRows() <= cascadeBaseCuts.daughterTPCrowsMin || + bach.tpcNClsCrossedRows() <= cascadeBaseCuts.daughterTPCrowsMin) { + return false; + } + + // Daughter roles: + // Xi- : pos = proton, neg = pion, bachelor = pion + // anti-Xi+ : pos = pion, neg = proton, bachelor = pion + const bool isXiMinus = casc.sign() < 0; + const auto& lambdaPion = isXiMinus ? neg : pos; + const auto& lambdaProton = isXiMinus ? pos : neg; + + // Dedicated Lambda fixed daughter kinematics. + if (lambdaPion.pt() <= cascadeBaseCuts.lambdaPionPtMin || + lambdaProton.pt() <= cascadeBaseCuts.lambdaProtonPtMin) { + return false; + } + + const float pLambdaX = casc.pxlambda(); + const float pLambdaY = casc.pylambda(); + const float pLambdaZ = casc.pzlambda(); + ROOT::Math::PxPyPzMVector lambda4(pLambdaX, pLambdaY, pLambdaZ, o2::constants::physics::MassLambda0); + if (std::abs(lambda4.Rapidity()) >= cascadeBaseCuts.lambdaRapidityMax) { + return false; + } + + // PID producer envelope: + // * keep TPC-only pion/proton decisions up to 6 sigma; + // * for the bachelor, TPC-only 6 sigma is sufficient to retain both the + // pp-Xi TPC-only selection and all tighter hybrid selections. + if (std::abs(bach.tpcNSigmaPi()) >= otherTrackPidCuts.nSigma6.value || + std::abs(lambdaPion.tpcNSigmaPi()) >= v0PidCuts.nSigma6.value || + std::abs(lambdaProton.tpcNSigmaPr()) >= v0PidCuts.nSigma6.value) { + return false; + } + + const float pionDcaPV = std::abs(isXiMinus ? casc.dcanegtopv() : casc.dcapostopv()); + const float protonDcaPV = std::abs(isXiMinus ? casc.dcapostopv() : casc.dcanegtopv()); + const float v0DcaPV = std::abs(casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ())); + const float v0DcaDaughters = std::abs(casc.dcaV0daughters()); + const float v0CosPA = casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); + const float v0Radius = casc.v0radius(); + const float lambdaMassDiff = std::abs(casc.mLambda() - o2::constants::physics::MassLambda0); + + // Lambda proper-lifetime proxy: L(PV->V0)*m_Lambda/p_Lambda. + const float dxLambda = casc.xlambda() - collision.posX(); + const float dyLambda = casc.ylambda() - collision.posY(); + const float dzLambda = casc.zlambda() - collision.posZ(); + const float lambdaDecayLength = std::sqrt(dxLambda * dxLambda + dyLambda * dyLambda + dzLambda * dzLambda); + const float pLambda = std::sqrt(pLambdaX * pLambdaX + pLambdaY * pLambdaY + pLambdaZ * pLambdaZ); + const float v0ProperLifetime = lambdaDecayLength * o2::constants::physics::MassLambda0 / (pLambda + kTinyMomentum); + + const float bachelorDcaPV = std::abs(casc.dcabachtopv()); + + // IMPORTANT: these are the native CascDatas stored quantities. + const float cascDcaDaughters = std::abs(casc.dcacascdaughters()); + + const float cascCosPA = casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()); + const float cascRadius = casc.cascradius(); + const float xiMassDiff = std::abs(casc.mXi() - o2::constants::physics::MassXiMinus); + const float bachBaryonDCAxy = std::abs(casc.bachBaryonDCAxyToPV()); + + // Xi proper lifetime and rapidity. + const float dxXi = casc.x() - collision.posX(); + const float dyXi = casc.y() - collision.posY(); + const float dzXi = casc.z() - collision.posZ(); + const float xiDecayLength = std::sqrt(dxXi * dxXi + dyXi * dyXi + dzXi * dzXi); + const float pXi = std::sqrt(casc.px() * casc.px() + casc.py() * casc.py() + casc.pz() * casc.pz()); + const float xiProperLifetime = xiDecayLength * casc.mXi() / (pXi + kTinyMomentum); + ROOT::Math::PxPyPzMVector xi4(casc.px(), casc.py(), casc.pz(), casc.mXi()); + const float xiRapidity = xi4.Rapidity(); + + // ----------------------------------------------------------------------- + // Producer envelopes: retain the UNION of all source-defined WPs. + // ----------------------------------------------------------------------- + const float pionDcaPVEnvelope = std::min({topoCuts.v0PionDcaPV005.value, + topoCuts.v0PionDcaPV006.value, + topoCuts.v0PionDcaPV010.value, + topoCuts.v0PionDcaPV020.value}); + const float protonDcaPVEnvelope = std::min({topoCuts.v0ProtonDcaPV005.value, + topoCuts.v0ProtonDcaPV006.value, + topoCuts.v0ProtonDcaPV007.value, + topoCuts.v0ProtonDcaPV010.value}); + const float v0DcaPVEnvelope = std::min({topoCuts.v0DcaPV000.value, + topoCuts.v0DcaPV003.value, + topoCuts.v0DcaPV010.value}); + const float v0DcaDaughtersEnvelope = std::max({topoCuts.v0DcaDaughters1p0.value, + topoCuts.v0DcaDaughters0p5.value, + topoCuts.v0DcaDaughters0p1.value}); + const float v0CosPAEnvelope = std::min({topoCuts.v0CosPA097.value, + topoCuts.v0CosPA098.value, + topoCuts.v0CosPA09876.value, + topoCuts.v0CosPA099.value, + topoCuts.v0CosPA0995.value}); + const float v0RadiusEnvelope = std::min({topoCuts.v0Radius0p9.value, + topoCuts.v0Radius1p01.value, + topoCuts.v0Radius1p2.value, + topoCuts.v0Radius2p5.value, + topoCuts.v0Radius3p0.value}); + const float lambdaMassEnvelope = std::max({topoCuts.lambdaMass10MeV.value, + topoCuts.lambdaMass8MeV.value, + topoCuts.lambdaMass6MeV.value, + topoCuts.lambdaMass11p6MeV.value}); + const float v0LifetimeEnvelope = std::max({topoCuts.v0LifetimeDefault.value, + topoCuts.v0LifetimeVar1.value, + topoCuts.v0LifetimeVar2.value}); + + const float bachelorDcaPVEnvelope = std::min({topoCuts.cascBachelorDcaPV005.value, + topoCuts.cascBachelorDcaPV006.value, + topoCuts.cascBachelorDcaPV010.value}); + const float cascDcaDaughtersEnvelope = std::max({topoCuts.cascDcaDaughters1p0.value, + topoCuts.cascDcaDaughters0p25.value, + topoCuts.cascDcaDaughters0p20.value}); + const float cascCosPAEnvelope = std::min({topoCuts.cascCosPA097.value, + topoCuts.cascCosPA098.value, + topoCuts.cascCosPA09947.value, + topoCuts.cascCosPA0995.value}); + const float xiMassEnvelope = std::max({topoCuts.xiMass10MeV.value, + topoCuts.xiMass8MeV.value, + topoCuts.xiMass6MeV.value}); + const float xiLifetimeEnvelope = std::max({topoCuts.xiLifetimeDefault.value, + topoCuts.xiLifetimeVar1.value, + topoCuts.xiLifetimeVar2.value}); + + if (pionDcaPV <= pionDcaPVEnvelope || + protonDcaPV <= protonDcaPVEnvelope || + v0DcaPV < v0DcaPVEnvelope || + v0DcaDaughters >= v0DcaDaughtersEnvelope || + v0CosPA <= v0CosPAEnvelope || + v0Radius <= v0RadiusEnvelope || + v0Radius >= cascadeBaseCuts.maxV0Radius || + v0ProperLifetime >= v0LifetimeEnvelope || + lambdaMassDiff >= lambdaMassEnvelope || + bachelorDcaPV <= bachelorDcaPVEnvelope || + cascDcaDaughters >= cascDcaDaughtersEnvelope || + cascCosPA <= cascCosPAEnvelope || + cascRadius >= cascadeBaseCuts.maxCascRadius || + xiMassDiff >= xiMassEnvelope || + xiProperLifetime >= xiLifetimeEnvelope) { + return false; + } + + uint64_t trackBits = 0; + uint64_t topologyBits = 0; + + // ----------------------------------------------------------------------- + // Track / PID bits + // ----------------------------------------------------------------------- + setTrackSelBit(trackBits, redxistark::kXiBachelorPiHybridPID3Sigma, + passPionHybridPID(bach, otherTrackPidCuts.nSigma3.value)); + setTrackSelBit(trackBits, redxistark::kXiBachelorPiHybridPID4Sigma, + passPionHybridPID(bach, otherTrackPidCuts.nSigma4.value)); + setTrackSelBit(trackBits, redxistark::kXiBachelorPiHybridPID5Sigma, + passPionHybridPID(bach, otherTrackPidCuts.nSigma5.value)); + setTrackSelBit(trackBits, redxistark::kXiBachelorPiHybridPID6Sigma, + passPionHybridPID(bach, otherTrackPidCuts.nSigma6.value)); + + const float absBachelorTPCPi = std::abs(bach.tpcNSigmaPi()); + setTrackSelBit(trackBits, redxistark::kXiBachelorPiTPC3Sigma, absBachelorTPCPi < otherTrackPidCuts.nSigma3.value); + setTrackSelBit(trackBits, redxistark::kXiBachelorPiTPC4Sigma, absBachelorTPCPi < otherTrackPidCuts.nSigma4.value); + setTrackSelBit(trackBits, redxistark::kXiBachelorPiTPC4p8Sigma, absBachelorTPCPi < otherTrackPidCuts.bachelorTPC4p8.value); + setTrackSelBit(trackBits, redxistark::kXiBachelorPiTPC5Sigma, absBachelorTPCPi < otherTrackPidCuts.nSigma5.value); + setTrackSelBit(trackBits, redxistark::kXiBachelorPiTPC6Sigma, absBachelorTPCPi < otherTrackPidCuts.nSigma6.value); + + const float absLambdaPiTPC = std::abs(lambdaPion.tpcNSigmaPi()); + setTrackSelBit(trackBits, redxistark::kLambdaPiTPC3Sigma, absLambdaPiTPC < v0PidCuts.nSigma3.value); + setTrackSelBit(trackBits, redxistark::kLambdaPiTPC4Sigma, absLambdaPiTPC < v0PidCuts.nSigma4.value); + setTrackSelBit(trackBits, redxistark::kLambdaPiTPC4p8Sigma, absLambdaPiTPC < v0PidCuts.nSigma4p8.value); + setTrackSelBit(trackBits, redxistark::kLambdaPiTPC5Sigma, absLambdaPiTPC < v0PidCuts.nSigma5.value); + setTrackSelBit(trackBits, redxistark::kLambdaPiTPC6Sigma, absLambdaPiTPC < v0PidCuts.nSigma6.value); + + const float absLambdaPrTPC = std::abs(lambdaProton.tpcNSigmaPr()); + setTrackSelBit(trackBits, redxistark::kLambdaPrTPC3Sigma, absLambdaPrTPC < v0PidCuts.nSigma3.value); + setTrackSelBit(trackBits, redxistark::kLambdaPrTPC4Sigma, absLambdaPrTPC < v0PidCuts.nSigma4.value); + setTrackSelBit(trackBits, redxistark::kLambdaPrTPC5Sigma, absLambdaPrTPC < v0PidCuts.nSigma5.value); + setTrackSelBit(trackBits, redxistark::kLambdaPrTPC6Sigma, absLambdaPrTPC < v0PidCuts.nSigma6.value); + + const bool allCascRows50 = + pos.tpcNClsCrossedRows() > cascadeBaseCuts.daughterTPCrowsMin && + neg.tpcNClsCrossedRows() > cascadeBaseCuts.daughterTPCrowsMin && + bach.tpcNClsCrossedRows() > cascadeBaseCuts.daughterTPCrowsMin; + setTrackSelBit(trackBits, redxistark::kAllCascDaughtersTPCRows50, allCascRows50); + + const bool v0Rows70 = + pos.tpcNClsCrossedRows() > topoCuts.v0DaughterRows70 && + neg.tpcNClsCrossedRows() > topoCuts.v0DaughterRows70; + const bool v0RowsVar1 = + pos.tpcNClsCrossedRows() > topoCuts.v0DaughterRowsVar1 && + neg.tpcNClsCrossedRows() > topoCuts.v0DaughterRowsVar1; + const bool v0RowsVar2 = + pos.tpcNClsCrossedRows() > topoCuts.v0DaughterRowsVar2 && + neg.tpcNClsCrossedRows() > topoCuts.v0DaughterRowsVar2; + setTrackSelBit(trackBits, redxistark::kV0DaughtersTPCRows70, v0Rows70); + setTrackSelBit(trackBits, redxistark::kV0DaughtersTPCRowsVar1, v0RowsVar1); + setTrackSelBit(trackBits, redxistark::kV0DaughtersTPCRowsVar2, v0RowsVar2); + + // ----------------------------------------------------------------------- + // V0 / Lambda topology bits + // ----------------------------------------------------------------------- + setTopoSelBit(topologyBits, redxistark::kV0PionDcaPV005, pionDcaPV > topoCuts.v0PionDcaPV005); + setTopoSelBit(topologyBits, redxistark::kV0PionDcaPV006, pionDcaPV > topoCuts.v0PionDcaPV006); + setTopoSelBit(topologyBits, redxistark::kV0PionDcaPV010, pionDcaPV > topoCuts.v0PionDcaPV010); + setTopoSelBit(topologyBits, redxistark::kV0PionDcaPV020, pionDcaPV > topoCuts.v0PionDcaPV020); + + setTopoSelBit(topologyBits, redxistark::kV0ProtonDcaPV005, protonDcaPV > topoCuts.v0ProtonDcaPV005); + setTopoSelBit(topologyBits, redxistark::kV0ProtonDcaPV006, protonDcaPV > topoCuts.v0ProtonDcaPV006); + setTopoSelBit(topologyBits, redxistark::kV0ProtonDcaPV007, protonDcaPV > topoCuts.v0ProtonDcaPV007); + setTopoSelBit(topologyBits, redxistark::kV0ProtonDcaPV010, protonDcaPV > topoCuts.v0ProtonDcaPV010); + + setTopoSelBit(topologyBits, redxistark::kV0DcaPV000, v0DcaPV > topoCuts.v0DcaPV000); + setTopoSelBit(topologyBits, redxistark::kV0DcaPV003, v0DcaPV > topoCuts.v0DcaPV003); + setTopoSelBit(topologyBits, redxistark::kV0DcaPV010, v0DcaPV > topoCuts.v0DcaPV010); + + setTopoSelBit(topologyBits, redxistark::kV0DcaDaughters1p0, v0DcaDaughters < topoCuts.v0DcaDaughters1p0); + setTopoSelBit(topologyBits, redxistark::kV0DcaDaughters0p5, v0DcaDaughters < topoCuts.v0DcaDaughters0p5); + setTopoSelBit(topologyBits, redxistark::kV0DcaDaughters0p1, v0DcaDaughters < topoCuts.v0DcaDaughters0p1); + + setTopoSelBit(topologyBits, redxistark::kV0CosPA097, v0CosPA > topoCuts.v0CosPA097); + setTopoSelBit(topologyBits, redxistark::kV0CosPA098, v0CosPA > topoCuts.v0CosPA098); + setTopoSelBit(topologyBits, redxistark::kV0CosPA09876, v0CosPA > topoCuts.v0CosPA09876); + setTopoSelBit(topologyBits, redxistark::kV0CosPA099, v0CosPA > topoCuts.v0CosPA099); + setTopoSelBit(topologyBits, redxistark::kV0CosPA0995, v0CosPA > topoCuts.v0CosPA0995); + + setTopoSelBit(topologyBits, redxistark::kV0Radius0p9, v0Radius > topoCuts.v0Radius0p9); + setTopoSelBit(topologyBits, redxistark::kV0Radius1p01, v0Radius > topoCuts.v0Radius1p01); + setTopoSelBit(topologyBits, redxistark::kV0Radius1p2, v0Radius > topoCuts.v0Radius1p2); + setTopoSelBit(topologyBits, redxistark::kV0Radius2p5, v0Radius > topoCuts.v0Radius2p5); + setTopoSelBit(topologyBits, redxistark::kV0Radius3p0, v0Radius > topoCuts.v0Radius3p0); + + setTopoSelBit(topologyBits, redxistark::kLambdaMass10MeV, lambdaMassDiff < topoCuts.lambdaMass10MeV); + setTopoSelBit(topologyBits, redxistark::kLambdaMass8MeV, lambdaMassDiff < topoCuts.lambdaMass8MeV); + setTopoSelBit(topologyBits, redxistark::kLambdaMass6MeV, lambdaMassDiff < topoCuts.lambdaMass6MeV); + setTopoSelBit(topologyBits, redxistark::kLambdaMass11p6MeV, lambdaMassDiff < topoCuts.lambdaMass11p6MeV); + + setTopoSelBit(topologyBits, redxistark::kV0LifetimeDefault, v0ProperLifetime < topoCuts.v0LifetimeDefault); + setTopoSelBit(topologyBits, redxistark::kV0LifetimeVar1, v0ProperLifetime < topoCuts.v0LifetimeVar1); + setTopoSelBit(topologyBits, redxistark::kV0LifetimeVar2, v0ProperLifetime < topoCuts.v0LifetimeVar2); + + // ----------------------------------------------------------------------- + // Xi / cascade topology bits + // ----------------------------------------------------------------------- + setTopoSelBit(topologyBits, redxistark::kCascBachelorDcaPV005, bachelorDcaPV > topoCuts.cascBachelorDcaPV005); + setTopoSelBit(topologyBits, redxistark::kCascBachelorDcaPV006, bachelorDcaPV > topoCuts.cascBachelorDcaPV006); + setTopoSelBit(topologyBits, redxistark::kCascBachelorDcaPV010, bachelorDcaPV > topoCuts.cascBachelorDcaPV010); + + setTopoSelBit(topologyBits, redxistark::kCascDcaDaughters1p0, cascDcaDaughters < topoCuts.cascDcaDaughters1p0); + setTopoSelBit(topologyBits, redxistark::kCascDcaDaughters0p25, cascDcaDaughters < topoCuts.cascDcaDaughters0p25); + setTopoSelBit(topologyBits, redxistark::kCascDcaDaughters0p20, cascDcaDaughters < topoCuts.cascDcaDaughters0p20); + + setTopoSelBit(topologyBits, redxistark::kCascCosPA097, cascCosPA > topoCuts.cascCosPA097); + setTopoSelBit(topologyBits, redxistark::kCascCosPA098, cascCosPA > topoCuts.cascCosPA098); + setTopoSelBit(topologyBits, redxistark::kCascCosPA09947, cascCosPA > topoCuts.cascCosPA09947); + setTopoSelBit(topologyBits, redxistark::kCascCosPA0995, cascCosPA > topoCuts.cascCosPA0995); + + setTopoSelBit(topologyBits, redxistark::kCascRadius0p9, cascRadius > topoCuts.cascRadius0p9); + setTopoSelBit(topologyBits, redxistark::kCascRadius1p0, cascRadius > topoCuts.cascRadius1p0); + setTopoSelBit(topologyBits, redxistark::kCascRadius1p01, cascRadius > topoCuts.cascRadius1p01); + setTopoSelBit(topologyBits, redxistark::kCascRadius1p3, cascRadius > topoCuts.cascRadius1p3); + + setTopoSelBit(topologyBits, redxistark::kXiMass10MeV, xiMassDiff < topoCuts.xiMass10MeV); + setTopoSelBit(topologyBits, redxistark::kXiMass8MeV, xiMassDiff < topoCuts.xiMass8MeV); + setTopoSelBit(topologyBits, redxistark::kXiMass6MeV, xiMassDiff < topoCuts.xiMass6MeV); + + setTopoSelBit(topologyBits, redxistark::kXiLifetimeDefault, xiProperLifetime < topoCuts.xiLifetimeDefault.value); + setTopoSelBit(topologyBits, redxistark::kXiLifetimeVar1, xiProperLifetime < topoCuts.xiLifetimeVar1.value); + setTopoSelBit(topologyBits, redxistark::kXiLifetimeVar2, xiProperLifetime < topoCuts.xiLifetimeVar2.value); + + setTopoSelBit(topologyBits, redxistark::kBachBaryonDCAxy0020, bachBaryonDCAxy > topoCuts.bachBaryonDCAxyPP); + setTopoSelBit(topologyBits, redxistark::kXiRapidity05, std::abs(xiRapidity) < topoCuts.xiRapidityPPMax); + + out.px = casc.px(); + out.py = casc.py(); + out.pz = casc.pz(); + out.mass = casc.mXi(); + out.sign = static_cast(casc.sign()); + out.bachelorIndex = bach.globalIndex(); + out.posIndex = pos.globalIndex(); + out.negIndex = neg.globalIndex(); + out.trackBits = trackBits; + out.topologyBits = topologyBits; + + qa.fill(HIST("hLambdaMass"), casc.mLambda()); + qa.fill(HIST("hXiMass"), casc.mXi()); + return true; + } + + // --------------------------------------------------------------------------- + // Xi + prompt-pion -> Xi(1530) candidate. + // --------------------------------------------------------------------------- + bool buildXiStar(XiTmp const& xi, PromptPionTmp const& pion, XiStarTmp& out) + { + // Never allow the prompt pion to reuse a cascade daughter track. + if (pion.trackIndex == xi.bachelorIndex || + pion.trackIndex == xi.posIndex || + pion.trackIndex == xi.negIndex) { + return false; + } + + ROOT::Math::PxPyPzMVector xi4(xi.px, xi.py, xi.pz, xi.mass); + ROOT::Math::PxPyPzMVector pion4(pion.px, pion.py, pion.pz, o2::constants::physics::MassPionCharged); + const auto mother = xi4 + pion4; + + if (std::abs(mother.Rapidity()) >= xiStarCuts.rapidityMax) { + return false; + } + if (mother.M() <= xiStarCuts.massMin || mother.M() >= xiStarCuts.massMax) { + return false; + } + + int8_t channel = 0; + if (xi.sign < 0) { // Xi- + channel = pion.charge > 0 ? redxistark::kXiStarUS : redxistark::kXiStarLS; + } else { // anti-Xi+ + channel = pion.charge < 0 ? redxistark::kAntiXiStarUS : redxistark::kAntiXiStarLS; + } + + out.channel = channel; + out.px = mother.Px(); + out.py = mother.Py(); + out.pz = mother.Pz(); + out.mass = mother.M(); + out.trackBits = xi.trackBits | pion.trackBits; + out.topologyBits = xi.topologyBits; + out.pionPt = std::hypot(pion.px, pion.py); + out.pionEta = out.pionPt > 0.f ? std::asinh(pion.pz / out.pionPt) : 0.f; + out.pionPhi = std::atan2(pion.py, pion.px); + out.pionIndex = pion.trackIndex; + out.bachelorIndex = xi.bachelorIndex; + out.posIndex = xi.posIndex; + out.negIndex = xi.negIndex; + + if (std::abs(channel) == 1) { + qa.fill(HIST("hXiStarMassUS"), out.mass); + } else { + qa.fill(HIST("hXiStarMassLS"), out.mass); + } + qa.fill(HIST("hXiStarMassVsChannel"), out.mass, static_cast(channel)); + return true; + } + + // --------------------------------------------------------------------------- + // Main producer + // --------------------------------------------------------------------------- + void processData(EventCandidates::iterator const& collision, + aod::BCsWithTimestamps const&, + TracksFull const& tracks, + aod::CascDatas const& cascades) + { + if (!passEvent(collision)) { + return; + } + + const float ft0MPercentile = collision.centFT0M(); + qa.fill(HIST("hFT0MPercentile"), ft0MPercentile); + + std::vector promptPions; + std::vector kaons; + std::vector xis; + std::vector xiStars; + + // CPU protection for Hyperloop: Xi candidates are much rarer than ordinary + // primary tracks. Select cascades first and do not scan all primary tracks + // in events that contain no Xi candidate inside the loose envelope. + if (cascades.size() == 0) { + return; + } + xis.reserve(cascades.size()); + for (auto const& casc : cascades) { + XiTmp xi; + if (buildXi(collision, casc, xi)) { + xis.push_back(xi); + } + } + if (xis.empty()) { + return; + } + + // One pass over primary tracks: build prompt-pion and external-K lists. + for (auto const& track : tracks) { + PromptPionTmp pion; + if (buildPromptPion(track, pion)) { + promptPions.push_back(pion); + } + + KaonTmp kaon; + if (buildKaon(track, kaon)) { + kaons.push_back(kaon); + } + } + + if (promptPions.empty()) { + return; + } + + // Build both US and LS Xi-pi candidates. No k* selection is made here. + xiStars.reserve(xis.size() * std::min(promptPions.size(), 8)); + for (auto const& xi : xis) { + for (auto const& pion : promptPions) { + XiStarTmp candidate; + if (buildXiStar(xi, pion, candidate)) { + xiStars.push_back(candidate); + } + } + } + + if (xiStars.empty()) { + return; + } + + qa.fill(HIST("hEventCutFlow"), 5.0); + + const auto bc = collision.bc_as(); + const float bz = getMagneticField(bc.timestamp()); + + redEvents(collision.posZ(), collision.numContrib(), ft0MPercentile, bz); + const auto redEventIndex = redEvents.lastIndex(); + + for (auto const& candidate : xiStars) { + xiStarCandidates(redEventIndex, + candidate.channel, + candidate.px, + candidate.py, + candidate.pz, + candidate.mass, + candidate.trackBits, + candidate.topologyBits, + candidate.pionPt, + candidate.pionEta, + candidate.pionPhi, + candidate.pionIndex, + candidate.bachelorIndex, + candidate.posIndex, + candidate.negIndex); + } + + for (auto const& kaon : kaons) { + kaonCandidates(redEventIndex, + kaon.charge, + kaon.px, + kaon.py, + kaon.pz, + kaon.trackIndex, + kaon.bits, + kaon.tpcNClsCrossedRows, + kaon.tpcNSigmaKa, + kaon.tofNSigmaKa, + kaon.hasTOF); + } + + qa.fill(HIST("hNObjectsPerWrittenEvent"), static_cast(xiStars.size()), 0.f); + qa.fill(HIST("hNObjectsPerWrittenEvent"), static_cast(kaons.size()), 1.f); + qa.fill(HIST("hEventCutFlow"), 6.0); + } + + PROCESS_SWITCH(xi1530kaonreducedtable, processData, "Produce reduced Xi(1530)-K femtoscopy tables", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/CMakeLists.txt b/PWGLF/TableProducer/Strangeness/CMakeLists.txt index 83b05e9a1bc..643c63aa9c0 100644 --- a/PWGLF/TableProducer/Strangeness/CMakeLists.txt +++ b/PWGLF/TableProducer/Strangeness/CMakeLists.txt @@ -51,13 +51,13 @@ o2physics_add_dpl_workflow(cascderivedqaanalysis PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(hstrangecorrelationfilter +o2physics_add_dpl_workflow(hstrangecorrelationfilter # o2-linter: disable=name/o2-workflow (Keep historical workflow name for backward compatibility.) SOURCES hStrangeCorrelationFilter.cxx PUBLIC_LINK_LIBRARIES O2::DCAFitter O2Physics::AnalysisCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(double-casc-tree-creator - SOURCES doubleCascTreeCreator.cxx +o2physics_add_dpl_workflow(double-omega-tree-creator + SOURCES doubleOmegaTreeCreator.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) @@ -81,7 +81,7 @@ o2physics_add_dpl_workflow(lambdakzerospawner PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(sigmaminus-task +o2physics_add_dpl_workflow(sigmaminus-task # o2-linter: disable=name/o2-workflow (Keep historical workflow name for backward compatibility.) SOURCES sigmaminustask.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) @@ -111,7 +111,7 @@ o2physics_add_dpl_workflow(strangenessbuilder PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter KFParticle::KFParticle O2Physics::TPCDriftManager O2Physics::MLCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(v0-selector +o2physics_add_dpl_workflow(v0-selector # o2-linter: disable=name/o2-workflow (Keep historical workflow name for backward compatibility.) SOURCES v0selector.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) @@ -121,18 +121,18 @@ o2physics_add_dpl_workflow(v0qaanalysis PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(lambdalambdatable +o2physics_add_dpl_workflow(lambdalambdatable # o2-linter: disable=name/o2-workflow (Keep historical workflow name for backward compatibility.) SOURCES LambdaLambdatable.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsVertexing COMPONENT_NAME Analysis) # ML selection -o2physics_add_dpl_workflow(lambdakzeromlselectiontreecreator +o2physics_add_dpl_workflow(lambdakzeromlselectiontreecreator # o2-linter: disable=name/o2-workflow (Keep historical workflow name for backward compatibility.) SOURCES lambdakzeroMLSelectionTreeCreator.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(cascademlselectiontreecreator +o2physics_add_dpl_workflow(cascademlselectiontreecreator # o2-linter: disable=name/o2-workflow (Keep historical workflow name for backward compatibility.) SOURCES cascadeMLSelectionTreeCreator.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) @@ -152,12 +152,12 @@ o2physics_add_dpl_workflow(sigma0builder PUBLIC_LINK_LIBRARIES O2::Framework O2::EMCALBase O2Physics::AnalysisCore O2Physics::MLCore O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(lambdajetpolarizationbuilder +o2physics_add_dpl_workflow(lambdajetpolarizationbuilder # o2-linter: disable=name/o2-workflow (Keep historical workflow name for backward compatibility.) SOURCES lambdaJetpolarizationbuilder.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(lambdajetpolarizationions +o2physics_add_dpl_workflow(lambdajetpolarizationions # o2-linter: disable=name/o2-workflow (Keep historical workflow name for backward compatibility.) SOURCES lambdaJetPolarizationIons.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGJECore FastJet::FastJet O2Physics::AnalysisCCDB COMPONENT_NAME Analysis) @@ -172,7 +172,7 @@ o2physics_add_dpl_workflow(lambdaspincorrelation PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(sigmahadcorr +o2physics_add_dpl_workflow(sigmahadcorr # o2-linter: disable=name/o2-workflow (Keep historical workflow name for backward compatibility.) SOURCES sigmaHadCorr.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) @@ -188,3 +188,8 @@ o2physics_add_dpl_workflow(phi-strange-correlator SOURCES phiStrangeCorrelator.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(strangeness-mc-centrality + SOURCES strangenessMcCentrality.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGLF/TableProducer/Strangeness/Converters/CMakeLists.txt b/PWGLF/TableProducer/Strangeness/Converters/CMakeLists.txt index 484d98f1126..e1d42ea534a 100644 --- a/PWGLF/TableProducer/Strangeness/Converters/CMakeLists.txt +++ b/PWGLF/TableProducer/Strangeness/Converters/CMakeLists.txt @@ -139,6 +139,11 @@ o2physics_add_dpl_workflow(stramccollisionconverter PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(stramccollisionconverter2 + SOURCES stramccollisionconverter2.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(strastampsconverter SOURCES strastampsconverter.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore @@ -159,8 +164,8 @@ o2physics_add_dpl_workflow(stramccollmultconverter PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(stramccollisionconverter2 - SOURCES stramccollisionconverter2.cxx +o2physics_add_dpl_workflow(stramccollmultconverter2 + SOURCES stramccollmultconverter2.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) diff --git a/PWGLF/TableProducer/Strangeness/Converters/README.md b/PWGLF/TableProducer/Strangeness/Converters/README.md new file mode 100644 index 00000000000..9779e642606 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/README.md @@ -0,0 +1,58 @@ +# Strangeness table converters + +Converter tasks migrate old versions of the strangeness derived-data tables to +newer ones, so that analyses written against the current data model can still +run over older derived data. Each task reads one or more legacy tables and +produces the corresponding newer version, filling any column that did not exist +in the old table with a dummy value. + +Add the workflow you need to your job with `o2-analysis-lf-`; only the +converters whose *input* tables are actually present in your derived data need +to be enabled. + +The table below is generated automatically from the sources. + +| Converter | Reads | Produces | Description | +|---|---|---|---| +| `stracentconverter.cxx` | `StraCents_000` | `StraCents_001` | Converts Stra Cents from 000 to 001 | +| `stracentconverter2.cxx` | `StraCents_001` | `StraCents_002` | Converts Stra Cents from 001 to 002 | +| `stradautracksconverter.cxx` | `V0Cores` + `V0Extras` + `V0TOFs`, `CascCores` + `CascExtras` + `CascTOFs`, `DauTrackExtras` *(=DauTrackExtras_003)* | `DauTrackTOFPIDs_000` | | +| `stradautracksextraconverter.cxx` | `DauTrackExtras_000` | `DauTrackExtras_001` | Converts V0 version 001 to 002 | +| `stradautracksextraconverter2.cxx` | `DauTrackExtras_001` | `DauTrackExtras_002` | Converts daughter TracksExtra from 1 to 2 | +| `stradautracksextraconverter3.cxx` | `DauTrackExtras_002` | `DauTrackExtras_003` | Converts daughter TracksExtra from 2 to 3 | +| `stradautrackstofpidconverter.cxx` | `V0Cores` + `V0Extras` + `V0TOFs`, `CascCores` + `CascExtras` + `CascTOFs`, `DauTrackExtras` *(=DauTrackExtras_003)* | `DauTrackTOFPIDs` *(=DauTrackTOFPIDs_003)* | | +| `stradautrackstofpidconverter2.cxx` | `StraCollisions`, `DauTrackExtras` *(=DauTrackExtras_003)* + `DauTrackTOFPIDs_000`, `V0CollRefs` + `V0Cores` + `V0Extras` | `DauTrackTOFPIDs_001`
`StraEvTimes_000` | converts DauTrackTOFPIDs_000 to _001 | +| `stradautrackstofpidconverter3.cxx` | `DauTrackTOFPIDs_001`, `StraEvTimes_000` | `DauTrackTOFPIDs_002`
`StraEvTimes_001` | converts DauTrackTOFPIDs_001 to _002 | +| `stradautrackstofpidconverter4.cxx` | `DauTrackTOFPIDs_002`, `StraCollisions` + `StraStamps` *(=StraStamps_001)* | `DauTrackTOFPIDs_003` | converts DauTrackTOFPIDs_002 to _003 | +| `stradautrackstpcpidconverter.cxx` | `DauTrackTPCPIDs_000` | `DauTrackTPCPIDs_001` | converts DauTrackTOFPIDs_000 to _001 | +| `straevselextrasconverter.cxx` | **processAll**: `StraEvSels_005` + `StraEvSelExtras_000`
**processStraEvSelsOnly**: `StraEvSels_005` *(off by default)* | `StraEvSelExtras_001` | | +| `straevselextrasconverter2.cxx` | `StraEvSels` *(=StraEvSels_006)* | `StraEvSelExtras` *(=StraEvSelExtras_001)* | Produce dummy StraEvSelExtras for analysis subscribing to StraEvSelExtras but not saved in the strangeness derived data (typically when running over pp strangeness derived data) | +| `straevselsconverter.cxx` | `StraEvSels_000` + `StraRawCents_004` | `StraEvSels_001` | Converts Stra Event selections from 000 to 001 | +| `straevselsconverter2.cxx` | `StraEvSels_001` | `StraEvSels_002` | Converts Stra Event selections from 000 to 001 | +| `straevselsconverter2rawcents.cxx` | `StraEvSels_001` | `StraRawCents_004` | Converts V0 version 001 to 002 | +| `straevselsconverter2rawcents2.cxx` | `StraEvSels_002` | `StraRawCents_004` | Converts V0 version 001 to 002 | +| `straevselsconverter2rawcents3.cxx` | `StraEvSels_003` | `StraRawCents_004` | Converts V0 version 001 to 002 | +| `straevselsconverter3.cxx` | `StraEvSels_002` | `StraEvSels_003` | Converts Stra Event selections from 000 to 001 | +| `straevselsconverter4.cxx` | `StraEvSels_003` | `StraEvSels_004` | Converts Stra Event selections from 000 to 001 | +| `straevselsconverter5.cxx` | `StraEvSels_004` + `StraStamps` *(=StraStamps_001)* | `StraEvSels_005` | Converts Stra Event selections from 004 to 005 | +| `straevselsconverter6.cxx` | `StraEvSels_005` | `StraEvSels_006` | Converts Stra Event selections from 005 to 006 | +| `stramccollisionconverter.cxx` | `StraMCCollisions_000` | `StraMCCollisions_001` | Converts V0 version 001 to 002 | +| `stramccollisionconverter2.cxx` | `StraMCCollisions_001` | `StraMCCollisions_002` | Converts V0 version 001 to 002 | +| `stramccollmultconverter.cxx` | `StraMCCollMults_000` | `StraMCCollMults_001` | Converts V0 version 001 to 002 | +| `stramccollmultconverter2.cxx` | `StraMCCollMults_001` | `StraMCCollMults_002` | Converts V0 version 001 to 002 | +| `strarawcentsconverter.cxx` | **process000to001**: `StraRawCents_000` *(off by default)*
**process002to003**: `StraRawCents_002` *(off by default)* | `StraRawCents_001`
`StraRawCents_003` | Converts V0 version 001 to 002 | +| `strarawcentsconverter2v4.cxx` | `StraRawCents_003` | `StraRawCents_004` | Converts V0 version 001 to 002 | +| `strastampsconverter.cxx` | `StraStamps_000` | `StraStamps_001` | Converts Stra Stamps from 000 to 001 | +| `v0coresconverter.cxx` | `V0MCCores_000` | `V0MCCores_001` | Converts V0 version 001 to 002 | +| `v0coresconverter2.cxx` | `V0MCCores_001` | `V0MCCores_002` | Converts V0 version 001 to 002 | +| `v0mlscoresconverter.cxx` | `V0Cores` | `V0GammaMLScores`
`V0LambdaMLScores`
`V0AntiLambdaMLScores`
`V0K0ShortMLScores` | Converts V0 version 001 to 002 | +| `zdcneutronsconverter.cxx` | `StraEvSels` *(=StraEvSels_006)* | `ZDCNeutrons`
`ZDCNMCCollRefs` | | + +Notes: + +* Tables joined with `+` are subscribed together in a single argument + (`soa::Join<...>`); a comma separates independent arguments. +* `Name *(=Name_00N)*` means the task subscribes to (or produces) the + unversioned alias, which currently resolves to version `N` in the data model. +* Tasks with more than one `process` function list each one separately; + a switch marked *off by default* must be enabled explicitly. diff --git a/PWGLF/TableProducer/Strangeness/Converters/makeConverterDocumentation.py b/PWGLF/TableProducer/Strangeness/Converters/makeConverterDocumentation.py new file mode 100644 index 00000000000..0914bc295a4 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/makeConverterDocumentation.py @@ -0,0 +1,662 @@ +#!/usr/bin/env python3 +""" +converter_tables.py -- summarise O2Physics converter tasks. + +Scans a directory of O2Physics workflow sources (by default the PWGLF +strangeness Converters directory), works out which AOD tables each task +subscribes to and which it produces, and writes the result as a Markdown +table (README.md) or as JSON/CSV. + +Typical use: + + ./converter_tables.py # print Markdown to stdout + ./converter_tables.py -o README.md # write the README in place + ./converter_tables.py --check # CI: fail if README is stale + ./converter_tables.py --format json + +The parser is regex based: it does not need a compiler, O2 headers or a +build environment, and it deliberately errs on the side of reporting what +it cannot parse (see the --strict flag) rather than silently dropping it. + +Recognised constructs +--------------------- + outputs Produces, Spawns, Builds + inputs arguments of every void process*(...) member function, + including soa::Join<...>, soa::Filtered<...>, ::iterator, + and file-scope `using X = ...;` aliases + extras PROCESS_SWITCH(...) descriptions and default on/off state, + the descriptive comment above the struct, + resolution of unversioned table names (StraEvSels) to the + concrete version they currently alias (StraEvSels_006) + +Written for the ALICE O2Physics repository; stdlib only, Python >= 3.8. +""" + +from __future__ import annotations + +import argparse +import csv +import io +import json +import os +import re +import sys +from dataclasses import dataclass, field, asdict +from pathlib import Path +from typing import Dict, Iterable, List, Optional, Tuple + +# -------------------------------------------------------------------------- +# Source cleaning +# -------------------------------------------------------------------------- + +_STRING_RE = re.compile(r'"(?:\\.|[^"\\])*"') + + +def strip_comments(text: str) -> str: + """Remove // and /* */ comments, preserving line structure. + + Line count is preserved so that reported line numbers stay meaningful. + String literals are protected so that "http://..." is not eaten. + """ + out = [] + i, n = 0, len(text) + while i < n: + c = text[i] + if c == '"': + m = _STRING_RE.match(text, i) + if m: + out.append(m.group(0)) + i = m.end() + continue + out.append(c) + i += 1 + elif c == "'" and i + 2 < n: + j = text.find("'", i + 1) + while j != -1 and text[j - 1] == "\\": + j = text.find("'", j + 1) + if j != -1: + out.append(text[i:j + 1]) + i = j + 1 + continue + out.append(c) + i += 1 + elif text.startswith("//", i): + j = text.find("\n", i) + i = n if j == -1 else j + elif text.startswith("/*", i): + j = text.find("*/", i + 2) + chunk = text[i:] if j == -1 else text[i:j + 2] + out.append("\n" * chunk.count("\n")) + i = n if j == -1 else j + 2 + else: + out.append(c) + i += 1 + return "".join(out) + + +# -------------------------------------------------------------------------- +# Small C++-ish helpers +# -------------------------------------------------------------------------- + +TABLE_RE = re.compile(r"\b(?:o2\s*::\s*)?aod\s*::\s*(\w+)") + + +def match_paren(text: str, open_pos: int) -> int: + """Index of the ')' matching the '(' at open_pos (-1 if unbalanced).""" + depth = 0 + for i in range(open_pos, len(text)): + if text[i] == "(": + depth += 1 + elif text[i] == ")": + depth -= 1 + if depth == 0: + return i + return -1 + + +def split_top_level(text: str, sep: str = ",") -> List[str]: + """Split on `sep`, ignoring separators nested in <>, (), [] or {}.""" + parts, depth, cur = [], 0, [] + for ch in text: + if ch in "<([{": + depth += 1 + elif ch in ">)]}": + depth -= 1 + if ch == sep and depth == 0: + parts.append("".join(cur)) + cur = [] + else: + cur.append(ch) + parts.append("".join(cur)) + return [p.strip() for p in parts if p.strip()] + + +# -------------------------------------------------------------------------- +# Data model: `using X = X_00N;` aliases and versioned declarations +# -------------------------------------------------------------------------- + +ALIAS_RE = re.compile(r"^\s*using\s+(\w+)\s*=\s*([^;]+);", re.M) +VERSIONED_RE = re.compile( + r"DECLARE_SOA_TABLE_VERSIONED\s*\(\s*(\w+)\s*,\s*\"(\w+)\"\s*,\s*\"([^\"]+)\"\s*,\s*(\d+)" +) +PLAIN_TABLE_RE = re.compile( + r"DECLARE_SOA_TABLE(?:_FULL|_STAGED)?\s*\(\s*(\w+)\s*,\s*\"(\w+)\"\s*,\s*\"([^\"]+)\"" +) + + +@dataclass +class DataModel: + """Maps unversioned table names to the version they currently alias.""" + + alias: Dict[str, str] = field(default_factory=dict) # StraEvSels -> StraEvSels_006 + declared: Dict[str, str] = field(default_factory=dict) # name -> "AOD/STRAEVSELS/6" + + def resolve(self, name: str) -> Optional[str]: + """Return Name_00N if `name` is an alias for a versioned table.""" + target = self.alias.get(name) + if not target or target == name: + return None + # only report genuine version aliases (StraEvSels -> StraEvSels_006), + # not renames such as V0Cores -> V0CoresBase + return target if re.fullmatch(re.escape(name) + r"_\d+", target) else None + + @classmethod + def from_paths(cls, paths: Iterable[Path]) -> "DataModel": + dm = cls() + for path in paths: + if not path.exists(): + continue + headers = [path] if path.is_file() else sorted(path.rglob("*.h")) + for header in headers: + try: + src = strip_comments(header.read_text(errors="replace")) + except OSError: + continue + for name, origin, desc, ver in VERSIONED_RE.findall(src): + dm.declared[name] = f"{origin}/{desc}/v{ver}" + for name, origin, desc in PLAIN_TABLE_RE.findall(src): + dm.declared.setdefault(name, f"{origin}/{desc}") + for lhs, rhs in ALIAS_RE.findall(src): + rhs = rhs.strip() + if re.fullmatch(r"(?:o2::)?(?:aod::)?\w+", rhs): + dm.alias[lhs] = rhs.split("::")[-1] + # follow alias chains (A = B, B = B_002) + for name in list(dm.alias): + seen, cur = {name}, dm.alias[name] + while cur in dm.alias and cur not in seen: + seen.add(cur) + cur = dm.alias[cur] + dm.alias[name] = cur + return dm + + +# -------------------------------------------------------------------------- +# Parsed representation of one workflow file +# -------------------------------------------------------------------------- + +@dataclass +class Subscription: + """One argument of a process function: one or more joined tables.""" + + tables: List[str] + joined: bool = False + filtered: bool = False + iterator: bool = False + raw: str = "" + + +@dataclass +class ProcessFn: + name: str + subscriptions: List[Subscription] = field(default_factory=list) + description: str = "" + default_on: Optional[bool] = None # None: no PROCESS_SWITCH (always on) + + +@dataclass +class Task: + file: str + struct: str + comment: str = "" + outputs: List[str] = field(default_factory=list) + processes: List[ProcessFn] = field(default_factory=list) + warnings: List[str] = field(default_factory=list) + + @property + def inputs(self) -> List[str]: + seen, flat = set(), [] + for p in self.processes: + for s in p.subscriptions: + for t in s.tables: + if t not in seen: + seen.add(t) + flat.append(t) + return flat + + +STRUCT_RE = re.compile(r"^\s*struct\s+(\w+)\s*(?::[^{]*)?\{", re.M) +PRODUCES_RE = re.compile(r"\b(Produces|Spawns|Builds)\s*<\s*([^>]+?)\s*>") +PROCESS_RE = re.compile(r"\b(?:void|auto)\s+(process\w*)\s*\(") +SWITCH_RE = re.compile( + r"PROCESS_SWITCH\s*\(\s*(\w+)\s*,\s*(\w+)\s*,\s*\"([^\"]*)\"\s*,\s*(true|false)\s*\)" +) +LOCAL_ALIAS_RE = re.compile(r"^\s*using\s+(\w+)\s*=\s*([^;]+);", re.M) + + +def struct_body(src: str, start: int) -> str: + """Return the body of the struct whose opening brace follows `start`.""" + brace = src.find("{", start) + if brace == -1: + return "" + depth = 0 + for i in range(brace, len(src)): + if src[i] == "{": + depth += 1 + elif src[i] == "}": + depth -= 1 + if depth == 0: + return src[brace + 1:i] + return src[brace + 1:] + + +def leading_comment(raw: str, struct_pos: int) -> str: + """The // comment block immediately above a struct, as one line.""" + lines = raw[:struct_pos].splitlines() + picked: List[str] = [] + for line in reversed(lines): + s = line.strip() + if not s: + if picked: + break + continue + if s.startswith("//"): + body = s.lstrip("/").strip() + if body: + picked.append(body) + continue + break + return " ".join(reversed(picked)).strip() + + +def parse_subscription(arg: str, aliases: Dict[str, str]) -> Optional[Subscription]: + """Turn one process-function argument into a Subscription.""" + expr = arg + # expand file-scope using aliases, repeatedly (aliases may nest) + for _ in range(8): + expanded = re.sub( + r"\b(\w+)\b", + lambda m: aliases.get(m.group(1), m.group(1)), + expr, + ) + if expanded == expr: + break + expr = expanded + + tables = [] + for name in TABLE_RE.findall(expr): + if name not in tables: + tables.append(name) + if not tables: + return None + return Subscription( + tables=tables, + joined="Join" in expr and len(tables) > 1, + filtered="Filtered" in expr, + iterator="::iterator" in expr.replace(" ", ""), + raw=" ".join(arg.split()), + ) + + +def parse_file(path: Path) -> List[Task]: + raw = path.read_text(errors="replace") + src = strip_comments(raw) + + aliases: Dict[str, str] = {} + for lhs, rhs in LOCAL_ALIAS_RE.findall(src): + aliases[lhs] = rhs.strip() + + switches = {(s[0], s[1]): (s[2], s[3] == "true") for s in SWITCH_RE.findall(src)} + + tasks: List[Task] = [] + for m in STRUCT_RE.finditer(src): + struct = m.group(1) + body = struct_body(src, m.start()) + # the descriptive comment lives in the uncleaned source + raw_pos = raw.find(f"struct {struct}") + task = Task( + file=path.name, + struct=struct, + comment=leading_comment(raw, raw_pos) if raw_pos != -1 else "", + ) + + for kind, tmpl in PRODUCES_RE.findall(body): + name = tmpl.split("::")[-1].strip() + label = name if kind == "Produces" else f"{name} ({kind.lower()})" + if label not in task.outputs: + task.outputs.append(label) + + for pm in PROCESS_RE.finditer(body): + open_paren = body.index("(", pm.end() - 1) + close = match_paren(body, open_paren) + if close == -1: + task.warnings.append(f"unbalanced parentheses in {pm.group(1)}()") + continue + fn = ProcessFn(name=pm.group(1)) + for arg in split_top_level(body[open_paren + 1:close]): + sub = parse_subscription(arg, aliases) + if sub: + fn.subscriptions.append(sub) + elif arg.strip(): + task.warnings.append( + f"{fn.name}(): unrecognised argument '{' '.join(arg.split())}'" + ) + desc, default_on = switches.get((struct, fn.name), (None, None)) + fn.description = desc or "" + fn.default_on = default_on + task.processes.append(fn) + + if not task.outputs: + task.warnings.append("no Produces<> found") + if not task.processes: + task.warnings.append("no process() function found") + tasks.append(task) + return tasks + + +# -------------------------------------------------------------------------- +# Consistency checks on the sources themselves +# -------------------------------------------------------------------------- + +VERSION_SUFFIX_RE = re.compile(r"^(.*?)_(\d+)$") +COMMENT_RANGE_RE = re.compile( + r"(?:version\s+|from\s+|v)?(\d{1,3})\s*(?:to|->|-->|=>)\s*v?(\d{1,3})", re.I +) + + +def split_version(name: str) -> Tuple[str, Optional[int]]: + """'StraEvSels_006' -> ('StraEvSels', 6); 'V0Extras' -> ('V0Extras', None).""" + m = VERSION_SUFFIX_RE.match(name) + return (m.group(1), int(m.group(2))) if m else (name, None) + + +def family(task: "Task") -> str: + """Table family a converter belongs to, taken from its first output.""" + if task.outputs: + return split_version(task.outputs[0].split(" ")[0])[0] + return "other" + + +def lint_task(task: "Task", dm: DataModel) -> List[str]: + """Flag descriptive comments that disagree with the parsed code. + + Several converters in the repository carry copy-pasted comments (e.g. + 'Converts V0 version 001 to 002' on a task that converts StraRawCents + 003 to 004). These are harmless to the build but actively mislead the + reader, which is exactly who this summary is for. + """ + issues: List[str] = [] + if not task.comment: + return issues + + out_names = [o.split(" ")[0] for o in task.outputs] + in_names = [t for p in task.processes for s in p.subscriptions for t in s.tables] + out_ver = next((v for _, v in map(split_version, out_names) if v is not None), None) + in_ver = next((v for _, v in map(split_version, in_names) if v is not None), None) + + m = COMMENT_RANGE_RE.search(task.comment) + if m and in_ver is not None and out_ver is not None: + said = (int(m.group(1)), int(m.group(2))) + if said != (in_ver, out_ver): + issues.append( + f"comment says {said[0]} -> {said[1]} but the task converts " + f"{in_ver:03d} -> {out_ver:03d}" + ) + + # a table family named in the comment that the task never touches + mentioned = set(re.findall(r"\b([A-Z][A-Za-z0-9]{3,})\b", task.comment)) + touched = {split_version(n)[0] for n in in_names + out_names} + touched |= {n for n in in_names + out_names} + stray = {w for w in mentioned + if (w in dm.declared or w in dm.alias) + and split_version(w)[0] not in touched and w not in touched} + if stray: + issues.append("comment mentions " + ", ".join(sorted(stray)) + + " which the task does not use") + return issues + + +# -------------------------------------------------------------------------- +# Rendering +# -------------------------------------------------------------------------- + +def fmt_subscription(sub: Subscription, dm: DataModel, resolve: bool) -> str: + names = [] + for t in sub.tables: + target = dm.resolve(t) if resolve else None + names.append(f"`{t}`" + (f" *(={target})*" if target else "")) + text = " + ".join(names) + if sub.filtered: + text += " *(filtered)*" + return text + + +def fmt_inputs(task: Task, dm: DataModel, resolve: bool) -> str: + chunks = [] + multi = len(task.processes) > 1 + for p in task.processes: + if not p.subscriptions: + body = "*(none)*" + else: + body = ", ".join(fmt_subscription(s, dm, resolve) for s in p.subscriptions) + if multi: + flag = "" if p.default_on is None else ("" if p.default_on else " *(off by default)*") + chunks.append(f"**{p.name}**: {body}{flag}") + else: + chunks.append(body) + return "
".join(chunks) if chunks else "*(none)*" + + +def fmt_outputs(task: Task, dm: DataModel, resolve: bool) -> str: + if not task.outputs: + return "*(none)*" + out = [] + for o in task.outputs: + base = o.split(" ")[0] + target = dm.resolve(base) if resolve else None + out.append(f"`{o}`" + (f" *(={target})*" if target else "")) + return "
".join(out) + + +HEADER = """ + + + + +# Strangeness table converters + +Converter tasks migrate old versions of the strangeness derived-data tables to +newer ones, so that analyses written against the current data model can still +run over older derived data. Each task reads one or more legacy tables and +produces the corresponding newer version, filling any column that did not exist +in the old table with a dummy value. + +Add the workflow you need to your job with `o2-analysis-lf-`; only the +converters whose *input* tables are actually present in your derived data need +to be enabled. + +The table below is generated automatically from the sources. +""" + +FOOTER = """ +Notes: + +* Tables joined with `+` are subscribed together in a single argument + (`soa::Join<...>`); a comma separates independent arguments. +* `Name *(=Name_00N)*` means the task subscribes to (or produces) the + unversioned alias, which currently resolves to version `N` in the data model. +* Tasks with more than one `process` function list each one separately; + a switch marked *off by default* must be enabled explicitly. +""" + + +def _table(buf: io.StringIO, tasks: List[Task], dm: DataModel, + resolve: bool, show_comments: bool) -> None: + cols = ["Converter", "Reads", "Produces"] + if show_comments: + cols.append("Description") + buf.write("| " + " | ".join(cols) + " |\n") + buf.write("|" + "|".join(["---"] * len(cols)) + "|\n") + for t in sorted(tasks, key=lambda x: x.file): + row = [ + f"`{t.file}`", + fmt_inputs(t, dm, resolve), + fmt_outputs(t, dm, resolve), + ] + if show_comments: + row.append(t.comment or "") + buf.write("| " + " | ".join(c.replace("|", "\\|") for c in row) + " |\n") + + +def render_markdown(tasks: List[Task], dm: DataModel, resolve: bool, + show_comments: bool, with_header: bool, + group: bool = False) -> str: + buf = io.StringIO() + if with_header: + buf.write(HEADER) + buf.write("\n") + if not group: + _table(buf, tasks, dm, resolve, show_comments) + else: + groups: Dict[str, List[Task]] = {} + for t in tasks: + groups.setdefault(family(t), []).append(t) + for fam in sorted(groups): + buf.write(f"\n## {fam}\n\n") + _table(buf, groups[fam], dm, resolve, show_comments) + if with_header: + buf.write(FOOTER) + return buf.getvalue() + + +def render_json(tasks: List[Task], dm: DataModel) -> str: + payload = [] + for t in sorted(tasks, key=lambda x: x.file): + d = asdict(t) + d["inputs"] = t.inputs + d["resolved"] = {n: dm.resolve(n) for n in t.inputs + t.outputs if dm.resolve(n)} + payload.append(d) + return json.dumps(payload, indent=2) + + +def render_csv(tasks: List[Task]) -> str: + buf = io.StringIO() + w = csv.writer(buf) + w.writerow(["file", "struct", "process", "reads", "produces", "description"]) + for t in sorted(tasks, key=lambda x: x.file): + for p in t.processes or [ProcessFn(name="process")]: + reads = "; ".join(" + ".join(s.tables) for s in p.subscriptions) + w.writerow([t.file, t.struct, p.name, reads, + "; ".join(t.outputs), t.comment]) + return buf.getvalue() + + +# -------------------------------------------------------------------------- +# CLI +# -------------------------------------------------------------------------- + +# DEFAULT_DIR = "PWGLF/TableProducer/Strangeness/Converters" +DEFAULT_DIR = "." + + +def find_repo_root(start: Path) -> Optional[Path]: + for parent in [start.resolve()] + list(start.resolve().parents): + if (parent / ".git").exists() or (parent / "PWGLF").is_dir(): + return parent + return None + + +def main(argv: Optional[List[str]] = None) -> int: + ap = argparse.ArgumentParser( + description="Summarise the input/output tables of O2Physics converter tasks." + ) + ap.add_argument("directory", nargs="?", default=DEFAULT_DIR, + help=f"directory of .cxx workflows (default: {DEFAULT_DIR})") + ap.add_argument("-o", "--output", help="write to this file instead of stdout") + ap.add_argument("--format", choices=["markdown", "json", "csv"], default="markdown") + ap.add_argument("--datamodel", action="append", default=[], + help="extra header file or directory to scan for table " + "declarations and aliases (repeatable)") + ap.add_argument("--no-resolve", action="store_true", + help="do not annotate unversioned names with their current version") + ap.add_argument("--no-comments", action="store_true", + help="omit the Description column") + ap.add_argument("--group", action="store_true", + help="split the table into one section per table family") + ap.add_argument("--lint", action="store_true", + help="also report source comments that contradict the code") + ap.add_argument("--bare", action="store_true", + help="emit only the Markdown table, without the surrounding text") + ap.add_argument("--check", action="store_true", + help="exit 2 if --output exists and differs (for CI)") + ap.add_argument("--strict", action="store_true", + help="exit 1 if any file could not be fully parsed") + args = ap.parse_args(argv) + + directory = Path(args.directory) + if not directory.is_dir(): + print(f"error: {directory} is not a directory", file=sys.stderr) + return 1 + + sources = sorted(p for p in directory.glob("*.cxx")) + if not sources: + print(f"error: no .cxx files in {directory}", file=sys.stderr) + return 1 + + tasks: List[Task] = [] + for src in sources: + tasks.extend(parse_file(src)) + + dm_paths = [Path(p) for p in args.datamodel] + if not dm_paths: + root = find_repo_root(directory) + if root: + dm_paths = [root / "PWGLF" / "DataModel", root / "Common" / "DataModel"] + dm = DataModel.from_paths(dm_paths) + + if args.format == "json": + text = render_json(tasks, dm) + elif args.format == "csv": + text = render_csv(tasks) + else: + text = render_markdown(tasks, dm, not args.no_resolve, + not args.no_comments, not args.bare, + group=args.group) + + problems = [(t.file, w) for t in tasks for w in t.warnings] + if args.lint: + for t in tasks: + problems.extend((t.file, f"[lint] {i}") for i in lint_task(t, dm)) + for f, w in problems: + print(f"warning: {f}: {w}", file=sys.stderr) + + if args.output: + out = Path(args.output) + if args.check: + existing = out.read_text() if out.exists() else None + if existing != text: + print(f"{out} is out of date; regenerate with " + f"`{Path(sys.argv[0]).name} -o {out}`", file=sys.stderr) + return 2 + print(f"{out} is up to date ({len(tasks)} tasks).", file=sys.stderr) + return 0 + out.write_text(text) + print(f"wrote {out} ({len(tasks)} tasks, " + f"{len(sources)} files).", file=sys.stderr) + else: + sys.stdout.write(text) + + return 1 if (args.strict and problems) else 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/PWGLF/TableProducer/Strangeness/Converters/stramccollmultconverter2.cxx b/PWGLF/TableProducer/Strangeness/Converters/stramccollmultconverter2.cxx new file mode 100644 index 00000000000..cc56470aacd --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/Converters/stramccollmultconverter2.cxx @@ -0,0 +1,46 @@ +// 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. +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +// Converts V0 version 001 to 002 +struct stramccollmultconverter2 { + Produces straMCCollMults_002; + + void process(aod::StraMCCollMults_001 const& straMCcolls) + { + straMCCollMults_002.reserve(straMCcolls.size()); + for (auto& straMCcoll : straMCcolls) { + straMCCollMults_002(straMCcoll.multMCFT0A(), + straMCcoll.multMCFT0C(), + -1., // dummy value multMCFV0A + -1., // dummy value multMCFDDA + -1., // dummy value multMCFDDC + straMCcoll.multMCNParticlesEta05(), + straMCcoll.multMCNParticlesEta08(), + straMCcoll.multMCNParticlesEta10(), + straMCcoll.totalMultMCParticles()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/cascadeflow.cxx b/PWGLF/TableProducer/Strangeness/cascadeflow.cxx index f5cac87074d..6d825f80728 100644 --- a/PWGLF/TableProducer/Strangeness/cascadeflow.cxx +++ b/PWGLF/TableProducer/Strangeness/cascadeflow.cxx @@ -417,18 +417,9 @@ struct cascadeFlow { return false; } - if (isFillHisto) + if (isFillHisto) { histos.fill(HIST("hNEvents"), 7.5); - - // TVX in TRD - // if (isNoTVXinTRD && collision.alias_bit(kTVXinTRD)){ - // return false; - // } - - if (isFillHisto) histos.fill(HIST("hNEvents"), 8.5); - - if (isFillHisto) { histos.fill(HIST("hEventNchCorrelation"), collision.multNTracksPVeta1(), collision.multNTracksGlobal()); histos.fill(HIST("hEventPVcontributorsVsCentrality"), collision.centFT0C(), collision.multNTracksPVeta1()); histos.fill(HIST("hEventGlobalTracksVsCentrality"), collision.centFT0C(), collision.multNTracksGlobal()); @@ -438,7 +429,7 @@ struct cascadeFlow { } template - bool IsCascAccepted(TCascade casc, TDaughter negExtra, TDaughter posExtra, TDaughter bachExtra, int& counter) // loose cuts on topological selections of cascades + bool IsCascAccepted(const TCascade& casc, const TDaughter& negExtra, const TDaughter& posExtra, const TDaughter& bachExtra, int& counter) // loose cuts on topological selections of cascades { // TPC cuts as those implemented for the training of the signal if (doNTPCSigmaCut) { @@ -476,7 +467,7 @@ struct cascadeFlow { } template - bool isLambdaAccepted(TDaughter negExtra, TDaughter posExtra, int& counter) // loose cuts on topological selections of v0s + bool isLambdaAccepted(const TDaughter& negExtra, const TDaughter& posExtra, int& counter) // loose cuts on topological selections of v0s { // TPC cuts as those implemented for the training of the signal if (doNTPCSigmaCut) { @@ -492,7 +483,7 @@ struct cascadeFlow { return true; } template - bool isAntiLambdaAccepted(TDaughter negExtra, TDaughter posExtra, int& counter) // loose cuts on topological selections of v0s + bool isAntiLambdaAccepted(const TDaughter& negExtra, const TDaughter& posExtra, int& counter) // loose cuts on topological selections of v0s { // TPC cuts as those implemented for the training of the signal if (doNTPCSigmaCut) { @@ -509,7 +500,7 @@ struct cascadeFlow { } template - bool isV0TopoAccepted(TV0 v0) + bool isV0TopoAccepted(const TV0& v0) { // topological selections if (v0.v0radius() < V0Configs.v0radius) @@ -568,13 +559,11 @@ struct cascadeFlow { int currentRunNumber = -999; int lastRunNumber = -999; - TProfile3D* shiftprofile; - TProfile3D* shiftprofileFT0C; - TProfile3D* shiftprofileFV0A; - TProfile3D* shiftprofileFT0A; - TProfile3D* shiftprofileTPCL; - TProfile3D* shiftprofileTPCR; - std::string fullCCDBShiftCorrPath; + TProfile3D* shiftprofileFT0C = nullptr; + TProfile3D* shiftprofileFV0A = nullptr; + TProfile3D* shiftprofileFT0A = nullptr; + TProfile3D* shiftprofileTPCL = nullptr; + TProfile3D* shiftprofileTPCR = nullptr; std::string fullCCDBShiftCorrPathFT0C; std::string fullCCDBShiftCorrPathFV0A; std::string fullCCDBShiftCorrPathFT0A; @@ -582,7 +571,7 @@ struct cascadeFlow { std::string fullCCDBShiftCorrPathTPCR; template - double ApplyShiftCorrection(TCollision coll, double psiT0C, TProfile3D* shiftprofile) + double ApplyShiftCorrection(const TCollision& coll, double psiT0C, TProfile3D* shiftprofile) { auto deltapsiFT0C = 0.0; int nmode = 2; @@ -597,7 +586,7 @@ struct cascadeFlow { } template - double ComputeEPResolutionwShifts(TCollision coll, double psiT0C, double psiV0A, double psiT0A, double psiTPCA, double psiTPCC, TProfile3D* shiftprofileA, TProfile3D* shiftprofileB, TProfile3D* shiftprofileC, TProfile3D* shiftprofileD, TProfile3D* shiftprofileE) + double ComputeEPResolutionwShifts(const TCollision& coll, double psiT0C, double psiV0A, double psiT0A, double psiTPCA, double psiTPCC, TProfile3D* shiftprofileA, TProfile3D* shiftprofileB, TProfile3D* shiftprofileC, TProfile3D* shiftprofileD, TProfile3D* shiftprofileE) { int nmode = 2; auto deltapsiFT0C = 0.0; @@ -640,16 +629,16 @@ struct cascadeFlow { } // objects to use for acceptance correction - TH2F* hAcceptanceXi; - TH2F* hAcceptanceOmega; - TH2F* hAcceptanceLambda; - TH2F* hAcceptancePrimaryLambda; + TH2F* hAcceptanceXi = nullptr; + TH2F* hAcceptanceOmega = nullptr; + TH2F* hAcceptanceLambda = nullptr; + TH2F* hAcceptancePrimaryLambda = nullptr; // objects to use for resolution correction - TH1F* hReso; + TH1F* hReso = nullptr; // objects to use for centrality weight - TH1F* hCentWeight; + TH1F* hCentWeight = nullptr; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; HistogramRegistry histosMCGen{"histosMCGen", {}, OutputObjHandlingPolicy::AnalysisObject, false, true}; @@ -674,7 +663,7 @@ struct cascadeFlow { } template - void fillTrainingTable(collision_t coll, cascade_t casc, int pdgCode) + void fillTrainingTable(const collision_t& coll, const cascade_t& casc, int pdgCode) { trainingSample(coll.centFT0C(), casc.sign(), @@ -699,7 +688,7 @@ struct cascadeFlow { } template - void fillAnalysedTable(collision_t coll, bool hasEventPlane, bool hasSpectatorPlane, cascade_t casc, float v2CSP, float v2CEP, float v1SP_ZDCA, float v1SP_ZDCC, float PsiT0C, float BDTresponseXi, float BDTresponseOmega, int pdgCode, bachExtra_t bachExtra) + void fillAnalysedTable(const collision_t& coll, bool hasEventPlane, bool hasSpectatorPlane, const cascade_t& casc, float v2CSP, float v2CEP, float v1SP_ZDCA, float v1SP_ZDCC, float PsiT0C, float BDTresponseXi, float BDTresponseOmega, int pdgCode, const bachExtra_t& bachExtra) { double masses[nParticles]{o2::constants::physics::MassXiMinus, o2::constants::physics::MassOmegaMinus}; ROOT::Math::PxPyPzMVector cascadeVector[nParticles], lambdaVector, protonVector; @@ -802,7 +791,7 @@ struct cascadeFlow { } template - void fillAnalysedLambdaTable(collision_t coll, bool hasEventPlane, bool hasSpectatorPlane, int chargeIndex, v0_t v0, float v2CEP, float psiT0C, double pzs2Lambda, double cos2ThetaLambda, double cosThetaLambda) + void fillAnalysedLambdaTable(const collision_t& coll, bool hasEventPlane, bool hasSpectatorPlane, int chargeIndex, const v0_t& v0, float v2CEP, float psiT0C, double pzs2Lambda, double cos2ThetaLambda, double cosThetaLambda) { double invMassLambda = 0; if (chargeIndex == 0) @@ -811,6 +800,7 @@ struct cascadeFlow { invMassLambda = v0.mAntiLambda(); else invMassLambda = v0.mLambda(); + double ctauLambda = v0.distovertotmom(coll.posX(), coll.posY(), coll.posZ()) * o2::constants::physics::MassLambda0; analysisLambdaSample(coll.centFT0C(), hasEventPlane, hasSpectatorPlane, @@ -819,6 +809,7 @@ struct cascadeFlow { v0.phi(), v0.eta(), invMassLambda, + ctauLambda, v0.v0radius(), v0.dcapostopv(), v0.dcanegtopv(), @@ -1230,8 +1221,8 @@ struct cascadeFlow { continue; } - float sigmaRangeXi[2]{getNsigmaMass(cascadev2::Xi, casc.pt(), sideBandStart), getNsigmaMass(cascadev2::Xi, casc.pt(), sideBandEnd)}; - float sigmaRangeOmega[2]{getNsigmaMass(cascadev2::Omega, casc.pt(), sideBandStart), getNsigmaMass(cascadev2::Omega, casc.pt(), sideBandEnd)}; + const float sigmaRangeXi[2]{getNsigmaMass(cascadev2::Xi, casc.pt(), sideBandStart), getNsigmaMass(cascadev2::Xi, casc.pt(), sideBandEnd)}; + const float sigmaRangeOmega[2]{getNsigmaMass(cascadev2::Omega, casc.pt(), sideBandStart), getNsigmaMass(cascadev2::Omega, casc.pt(), sideBandEnd)}; if ((std::abs(casc.mXi() - constants::physics::MassXiMinus) < sigmaRangeXi[0] || std::abs(casc.mXi() - constants::physics::MassXiMinus) > sigmaRangeXi[1]) && @@ -1402,7 +1393,7 @@ struct cascadeFlow { bool isCascCandidate = 0; isCascCandidate = IsCascAccepted(casc, negExtra, posExtra, bachExtra, counter); histos.fill(HIST("hCascade"), counter); - histos.fill(HIST("hCascadeDauSel"), (int)isCascCandidate); + histos.fill(HIST("hCascadeDauSel"), static_cast(isCascCandidate)); if (!isCascCandidate) continue; @@ -1478,7 +1469,7 @@ struct cascadeFlow { // polarization variables double masses[2]{o2::constants::physics::MassXiMinus, o2::constants::physics::MassOmegaMinus}; ROOT::Math::PxPyPzMVector cascadeVector[2], lambdaVector, protonVector; - float cosThetaStarLambda[2], cosThetaStarProton; + double cosThetaStarLambda[2], cosThetaStarProton; double massLambda = casc.mLambda(); if (fillingConfigs.isFillNominalMass) @@ -1733,7 +1724,7 @@ struct cascadeFlow { bool isCascCandidate = 0; isCascCandidate = IsCascAccepted(casc, negExtra, posExtra, bachExtra, counter); histos.fill(HIST("hCascade"), counter); - histos.fill(HIST("hCascadeDauSel"), (int)isCascCandidate); + histos.fill(HIST("hCascadeDauSel"), static_cast(isCascCandidate)); if (!isCascCandidate) continue; @@ -1803,7 +1794,7 @@ struct cascadeFlow { // polarization variables double masses[nParticles]{o2::constants::physics::MassXiMinus, o2::constants::physics::MassOmegaMinus}; ROOT::Math::PxPyPzMVector cascadeVector[nParticles], lambdaVector, protonVector; - float cosThetaStarLambda[nParticles], cosThetaStarProton; + double cosThetaStarLambda[nParticles], cosThetaStarProton; double massLambda = casc.mLambda(); if (fillingConfigs.isFillNominalMass) @@ -2132,7 +2123,6 @@ struct cascadeFlow { centWeight = hCentWeight->GetBinContent(centBin); } - std::vector bdtScore[nParticles]; for (auto const& v0 : V0s) { /// Add some minimal cuts for single track variables (min number of TPC clusters) @@ -2180,11 +2170,11 @@ struct cascadeFlow { histos.fill(HIST("hLambdaCandidate"), 3); continue; // in case of ambiguity between Lambda and AntiLambda, I skip the particle; checked to be zero in range 1.105 - 1.125 } - if (v0.mLambda() > V0Configs.MinMassLambda && v0.mLambda() < V0Configs.MaxMassLambda) + if (v0.mLambda() > V0Configs.MinMassLambda && v0.mLambda() < V0Configs.MaxMassLambda) { chargeIndex = 0; - else if (v0.mAntiLambda() > V0Configs.MinMassLambda && v0.mAntiLambda() < V0Configs.MaxMassLambda) + } else if (v0.mAntiLambda() > V0Configs.MinMassLambda && v0.mAntiLambda() < V0Configs.MaxMassLambda) { chargeIndex = 1; - else { + } else { chargeIndex = 2; // these are bkg candidates histos.fill(HIST("hLambdaCandidate"), 4); } @@ -2209,7 +2199,7 @@ struct cascadeFlow { if (fillingConfigs.isFillNominalMass) massLambda = o2::constants::physics::MassLambda; - float cosThetaStarProton[nCharges]; + double cosThetaStarProton[nCharges] = {0}; ROOT::Math::PxPyPzMVector lambdaVector, protonVector[nCharges]; lambdaVector.SetCoordinates(v0.px(), v0.py(), v0.pz(), massLambda); ROOT::Math::Boost lambdaBoost{lambdaVector.BoostToCM()}; @@ -2251,31 +2241,31 @@ struct cascadeFlow { histos.fill(HIST("hLambdaPhi"), v0.phi()); histos.fill(HIST("hlambdaminuspsiT0C"), lambdaminuspsiT0C); + double invMassLambda = 0; + if (chargeIndex == 0) + invMassLambda = v0.mLambda(); + else if (chargeIndex == 1) + invMassLambda = v0.mAntiLambda(); + else + invMassLambda = v0.mLambda(); + if (fillingConfigs.isFillTHNLambda) { if (fillingConfigs.isFillTHN_V2) - histos.get(HIST("hLambdaV2"))->Fill(collisionCentrality, chargeIndex, v0.pt(), v0.mLambda(), v2CEP); + histos.get(HIST("hLambdaV2"))->Fill(collisionCentrality, chargeIndex, v0.pt(), invMassLambda, v2CEP); if (fillingConfigs.isFillTHN_Pz) { - // histos.get(HIST("hLambdaPzs2"))->Fill(collisionCentrality, chargeIndex, v0.pt(), v0.mLambda(), pzs2Lambda); - histos.get(HIST("hLambdaPzs2"))->Fill(collisionCentrality, chargeIndex, v0.pt(), v0.mLambda(), pzs2Lambda, centWeight); + // histos.get(HIST("hLambdaPzs2"))->Fill(collisionCentrality, chargeIndex, v0.pt(), invMassLambda, pzs2Lambda); + histos.get(HIST("hLambdaPzs2"))->Fill(collisionCentrality, chargeIndex, v0.pt(), invMassLambda, pzs2Lambda, centWeight); } if (fillingConfigs.isFillTHN_Acc) - histos.get(HIST("hLambdaCos2Theta"))->Fill(collisionCentrality, chargeIndex, v0.eta(), v0.pt(), v0.mLambda(), cos2ThetaLambda); + histos.get(HIST("hLambdaCos2Theta"))->Fill(collisionCentrality, chargeIndex, v0.eta(), v0.pt(), invMassLambda, cos2ThetaLambda); } if (fillingConfigs.isFillTHNLambda_PzVsPsi) { if (fillingConfigs.isFillTHN_Pz) - histos.get(HIST("hLambdaPzVsPsi"))->Fill(collisionCentrality, chargeIndex, v0.pt(), v0.mLambda(), cosThetaLambda, 2 * lambdaminuspsiT0C, centWeight); + histos.get(HIST("hLambdaPzVsPsi"))->Fill(collisionCentrality, chargeIndex, v0.pt(), invMassLambda, cosThetaLambda, 2 * lambdaminuspsiT0C, centWeight); if (fillingConfigs.isFillTHN_Acc) - histos.get(HIST("hLambdaCos2ThetaVsPsi"))->Fill(collisionCentrality, chargeIndex, v0.eta(), v0.pt(), v0.mLambda(), cos2ThetaLambda, 2 * lambdaminuspsiT0C); + histos.get(HIST("hLambdaCos2ThetaVsPsi"))->Fill(collisionCentrality, chargeIndex, v0.eta(), v0.pt(), invMassLambda, cos2ThetaLambda, 2 * lambdaminuspsiT0C); } - double invMassLambda = 0; - if (chargeIndex == 0) - invMassLambda = v0.mLambda(); - else if (chargeIndex == 1) - invMassLambda = v0.mAntiLambda(); - else - invMassLambda = v0.mLambda(); - // mass selection if (invMassLambda < V0Configs.MinMassLambdaInTree || invMassLambda > V0Configs.MaxMassLambdaInTree) continue; @@ -2390,7 +2380,7 @@ struct cascadeFlow { bool isCascCandidate = 0; isCascCandidate = IsCascAccepted(casc, negExtra, posExtra, bachExtra, counter); histos.fill(HIST("hCascade"), counter); - histos.fill(HIST("hCascadeDauSel"), (int)isCascCandidate); + histos.fill(HIST("hCascadeDauSel"), static_cast(isCascCandidate)); if (!isCascCandidate) continue; @@ -2549,7 +2539,7 @@ struct cascadeFlow { bool isCascCandidate = 0; isCascCandidate = IsCascAccepted(casc, negExtra, posExtra, bachExtra, counter); histos.fill(HIST("hCascade"), counter); - histos.fill(HIST("hCascadeDauSel"), (int)isCascCandidate); + histos.fill(HIST("hCascadeDauSel"), static_cast(isCascCandidate)); if (!isCascCandidate) continue; diff --git a/PWGLF/TableProducer/Strangeness/cascademcbuilder.cxx b/PWGLF/TableProducer/Strangeness/cascademcbuilder.cxx index 04df29d88c4..614a590caea 100644 --- a/PWGLF/TableProducer/Strangeness/cascademcbuilder.cxx +++ b/PWGLF/TableProducer/Strangeness/cascademcbuilder.cxx @@ -122,7 +122,7 @@ struct cascademcbuilder { } template - void generateCascadeMCinfo(TCascadeTable cascTable, TMCParticleTable mcParticles) + void generateCascadeMCinfo(const TCascadeTable& cascTable, const TMCParticleTable& mcParticles) { // to be used if using the asymmetric mode, kept empty otherwise diff --git a/PWGLF/TableProducer/Strangeness/cascademlselection.cxx b/PWGLF/TableProducer/Strangeness/cascademlselection.cxx index 9f096144fb2..7c828926dbc 100644 --- a/PWGLF/TableProducer/Strangeness/cascademlselection.cxx +++ b/PWGLF/TableProducer/Strangeness/cascademlselection.cxx @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include diff --git a/PWGLF/TableProducer/Strangeness/cascderivedqaanalysis.cxx b/PWGLF/TableProducer/Strangeness/cascderivedqaanalysis.cxx index 6ccb65c9d4d..11129716925 100644 --- a/PWGLF/TableProducer/Strangeness/cascderivedqaanalysis.cxx +++ b/PWGLF/TableProducer/Strangeness/cascderivedqaanalysis.cxx @@ -176,7 +176,7 @@ struct CascDerivedQAanalysis { std::vector> cascadesGrouped; template - bool isCascadeSelected(TCascade casc, TCollision collision, float rapidity, bool isXi) + bool isCascadeSelected(const TCascade& casc, const TCollision& collision, float rapidity, bool isXi) // precalculate this information so that a check is one mask operation, not many { @@ -409,7 +409,7 @@ struct CascDerivedQAanalysis { } template - bool isEventAccepted(TCollision collision, bool fillHists) + bool isEventAccepted(const TCollision& collision, bool fillHists) // check whether the collision passes our collision selections { if (fillHists) { diff --git a/PWGLF/TableProducer/Strangeness/cascqaanalysis.cxx b/PWGLF/TableProducer/Strangeness/cascqaanalysis.cxx index 58aac18208a..ce89b1136b2 100644 --- a/PWGLF/TableProducer/Strangeness/cascqaanalysis.cxx +++ b/PWGLF/TableProducer/Strangeness/cascqaanalysis.cxx @@ -299,7 +299,7 @@ struct Cascqaanalysis { } template - uint16_t getGenNchInFT0Mregion(TMcParticles particles) + uint16_t getGenNchInFT0Mregion(const TMcParticles& particles) { // Particle counting in FITFT0: -3.3<η<-2.1; 3.5<η<4.9 uint16_t nchFT0 = 0; @@ -323,7 +323,7 @@ struct Cascqaanalysis { } template - uint16_t getGenNchInFV0Aregion(TMcParticles particles) + uint16_t getGenNchInFV0Aregion(const TMcParticles& particles) { // Particle counting in FV0A: 2.2<η<5.1 uint16_t nchFV0A = 0; diff --git a/PWGLF/TableProducer/Strangeness/doubleCascTreeCreator.cxx b/PWGLF/TableProducer/Strangeness/doubleCascTreeCreator.cxx deleted file mode 100644 index 736cda47318..00000000000 --- a/PWGLF/TableProducer/Strangeness/doubleCascTreeCreator.cxx +++ /dev/null @@ -1,352 +0,0 @@ -// 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. - -#include "PWGLF/DataModel/LFDoubleCascTables.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" - -#include "Common/CCDB/EventSelectionParams.h" -#include "Common/Core/Zorro.h" -#include "Common/Core/ZorroSummary.h" -#include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponseTPC.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -using namespace o2; -using namespace o2::framework; -using namespace o2::framework::expressions; - -using Collisions = soa::Join::iterator; -using FullCascades = aod::CascDataExt; -using TracksFull = soa::Join; - -struct doubleCascCand { - float ptCasc1 = -999.f; // signed pt of the cascade - float etaCasc1 = -999.f; - float phiCasc1 = -999.f; - float cascDecLength1 = -999.f; - float omegaMassCasc1 = -999.f; - float xiMassCasc1 = -999.f; - float cosPACasc1 = -999.f; - float dcaBachPVCasc1 = -999.f; - float dcaV0BachCasc1 = -999.f; - float nSigmaKBach1 = -999.f; - - float ptCasc2 = -999.f; - float etaCasc2 = -999.f; - float phiCasc2 = -999.f; - float cascDecLength2 = -999.f; - float omegaMassCasc2 = -999.f; - float xiMassCasc2 = -999.f; - float cosPACasc2 = -999.f; - float dcaBachPVCasc2 = -999.f; - float dcaV0BachCasc2 = -999.f; - float nSigmaKBach2 = -999.f; - float doubleOmegaMass = -999.f; -}; - -struct doubleCascTreeCreator { - Produces doubleCascTable; - std::vector doubleCascCands; - Service ccdb; - o2::vertexing::DCAFitterN<2> fitter; - - int mRunNumber; - - Zorro zorro; - OutputObj zorroSummary{"zorroSummary"}; - - Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Skimmed dataset processing"}; - Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; - - ConfigurableAxis centAxis{"centAxis", {106, 0, 106}, "binning for the centrality"}; - ConfigurableAxis zVtxAxis{"zVtxBins", {100, -20.f, 20.f}, "Binning for the vertex z in cm"}; - - // binning of (anti)lambda mass QA histograms - ConfigurableAxis massOmegaAxis{"massOmegaAxis", {400, o2::constants::physics::MassOmegaMinus - 0.05f, o2::constants::physics::MassOmegaMinus + 0.05}, "binning for the Omega invariant-mass"}; - ConfigurableAxis massXiAxis{"massXiAxis", {400, o2::constants::physics::MassXiMinus - 0.05f, o2::constants::physics::MassXiMinus + 0.05f}, "binning for the Xi invariant-mass"}; - - Configurable zVtxMax{"zVtxMax", 10.0f, "maximum z position of the primary vertex"}; - Configurable etaMax{"etaMax", 0.9f, "maximum eta"}; - ConfigurableAxis momAxis{"momAxisFine", {5.e2, 0.f, 5.f}, "momentum axis binning"}; - - Configurable cascPtMin{"cascPtMin", 1.f, "minimum (anti)casc pT (GeV/c)"}; - Configurable cascPtMax{"cascPtMax", 5.f, "maximum (anti)casc pT (GeV/c)"}; - - Configurable minNCrossedRows{"minNCrossedRows", 100, "Minimum number of crossed TPC rows"}; - Configurable minNITSClus{"minNITSClus", 0., "Minimum number of ITS clusters"}; - Configurable minNTPCClus{"minNTPCClus", 80, "Minimum number of TPC clusters"}; - Configurable maxNSharedTPCClus{"maxNSharedTPCClus", 5, "Maximum number of shared TPC clusters"}; - - Configurable minCascCosPA{"minCascCosPA", 0.99f, "Minimum cosine of the pointing angle of the cascade"}; - Configurable nSigmaTPCCut{"nSigmaTPCCut", 3.f, "Number of sigmas for the TPC PID"}; - Configurable dcaBachToPV{"dcaBachToPV", 0.05f, "DCA of the bachelor to the primary vertex"}; - Configurable dcaV0Bach{"dcaV0Bach", 1.f, "DCA between the V0 daughters"}; - Configurable mXiWindow{"mXiWindow", 0.02f, "mXiWindow"}; - Configurable mOmegaWindow{"mOmegaWindow", 0.01f, "mOmegaWindow"}; - - HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - template - bool selectTrack(T const& track) - { - if (std::abs(track.eta()) > etaMax) { - return false; - } - if (track.itsNCls() < minNITSClus || - track.tpcNClsFound() < minNTPCClus || - track.tpcNClsCrossedRows() < minNCrossedRows || - track.tpcNClsCrossedRows() < 0.8 * track.tpcNClsFindable() || - track.tpcNClsShared() > maxNSharedTPCClus) { - return false; - } - return true; - } - - template - void initCCDB(Bc const& bc) - { - if (mRunNumber == bc.runNumber()) { - return; - } - auto timestamp = bc.timestamp(); - LOG(info) << "Retrieved GRP for timestamp " << timestamp; - mRunNumber = bc.runNumber(); - if (cfgSkimmedProcessing) { - zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), "fDoubleOmega,fOmegaXi"); - zorro.populateHistRegistry(histos, bc.runNumber()); - } - } - - void init(o2::framework::InitContext&) - { - mRunNumber = 0; - ccdb->setURL(ccdburl); - ccdb->setCaching(true); - ccdb->setLocalObjectValidityChecking(); - ccdb->setFatalWhenNull(false); - - zorroSummary.setObject(zorro.getZorroSummary()); - - // event QA - histos.add("QA/zVtx", ";#it{z}_{vtx} (cm);Entries", HistType::kTH1F, {zVtxAxis}); - histos.add("QA/massXi1", ";#it{p}_{T} (GeV/#it{c});#it{M}(#Lambda + #pi^{-}) (GeV/#it{c}^{2});Entries", HistType::kTH2F, {momAxis, massXiAxis}); - histos.add("QA/massOmega1", ";#it{p}_{T} (GeV/#it{c});#it{M}(#Omega + #pi^{-}) (GeV/#it{c}^{2});Entries", HistType::kTH2F, {momAxis, massOmegaAxis}); - histos.add("QA/massXi2", ";#it{p}_{T} (GeV/#it{c});#it{M}(#Lambda + #pi^{-}) (GeV/#it{c}^{2});Entries", HistType::kTH2F, {momAxis, massXiAxis}); - histos.add("QA/massOmega2", ";#it{p}_{T} (GeV/#it{c});#it{M}(#Omega + #pi^{-}) (GeV/#it{c}^{2});Entries", HistType::kTH2F, {momAxis, massOmegaAxis}); - } - - template - bool isSelectedCasc(C const& collision, T const&, FullCascades::iterator const& casc) - { - - auto bachelor = casc.bachelor_as(); - auto posDau = casc.posTrack_as(); - auto negDau = casc.negTrack_as(); - - if (!selectTrack(bachelor) || !selectTrack(posDau) || !selectTrack(negDau)) { - return false; - } - if (casc.sign() > 0) { - if (TMath::Abs(posDau.tpcNSigmaPi()) > nSigmaTPCCut || TMath::Abs(negDau.tpcNSigmaPr()) > nSigmaTPCCut) { - return false; - } - } else if (casc.sign() < 0) { - if (TMath::Abs(negDau.tpcNSigmaPi()) > nSigmaTPCCut || TMath::Abs(posDau.tpcNSigmaPr()) > nSigmaTPCCut) { - return false; - } - } - if (TMath::Abs(casc.dcabachtopv()) < dcaBachToPV) { - return false; - } - if (TMath::Abs(casc.dcacascdaughters()) > dcaV0Bach) { - return false; - } - if (casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()) < minCascCosPA) { - return false; - } - if (TMath::Abs(casc.eta()) > etaMax) { - return false; - } - // mass cuts - bool massInWindow = false; - if (casc.mOmega() > o2::constants::physics::MassOmegaMinus - mOmegaWindow && casc.mOmega() < o2::constants::physics::MassOmegaMinus + mOmegaWindow) { - massInWindow = true; - } - if (casc.mXi() > o2::constants::physics::MassXiMinus - mXiWindow && casc.mXi() < o2::constants::physics::MassXiMinus + mXiWindow) { - massInWindow = true; - } - if (!massInWindow) { - return false; - } - return true; - }; - - template - float doubleOmegaMass(T const&, FullCascades::iterator const& casc1, FullCascades::iterator const& casc2) - { - // the fake omega decay is the one with the smaller radius - auto& fakeOmega = casc1.cascradius() < casc2.cascradius() ? casc1 : casc2; - auto& realOmega = casc1.cascradius() < casc2.cascradius() ? casc2 : casc1; - auto kaon = fakeOmega.bachelor_as(); - float momKaon[3] = {kaon.px(), kaon.py(), kaon.pz()}; - float momLambda[3] = {fakeOmega.pxlambda(), fakeOmega.pylambda(), fakeOmega.pzlambda()}; - // now compute real Omega-lambda-kaon mass - float momTot[3] = {momKaon[0] + momLambda[0] + realOmega.px(), momKaon[1] + momLambda[1] + realOmega.py(), momKaon[2] + momLambda[2] + realOmega.pz()}; - float eK = std::sqrt(o2::constants::physics::MassKaonCharged * o2::constants::physics::MassKaonCharged + momKaon[0] * momKaon[0] + momKaon[1] * momKaon[1] + momKaon[2] * momKaon[2]); - float eL = std::sqrt(o2::constants::physics::MassLambda0 * o2::constants::physics::MassLambda0 + momLambda[0] * momLambda[0] + momLambda[1] * momLambda[1] + momLambda[2] * momLambda[2]); - float eO = std::sqrt(o2::constants::physics::MassOmegaMinus * o2::constants::physics::MassOmegaMinus + realOmega.px() * realOmega.px() + realOmega.py() * realOmega.py() + realOmega.pz() * realOmega.pz()); - float eTot = eK + eL + eO; - float mass = std::sqrt(eTot * eTot - momTot[0] * momTot[0] - momTot[1] * momTot[1] - momTot[2] * momTot[2]); - return mass; - } - - template - void fillDoubleCasc(C const& collision, T const& tracks, FullCascades const& cascades) - { - doubleCascCands.clear(); - - for (auto& casc1 : cascades) { - if (!isSelectedCasc(collision, tracks, casc1)) { - continue; - } - histos.fill(HIST("QA/massXi1"), casc1.pt(), casc1.mXi()); - histos.fill(HIST("QA/massOmega1"), casc1.pt(), casc1.mOmega()); - for (auto& casc2 : cascades) { - if (!isSelectedCasc(collision, tracks, casc2)) { - continue; - } - histos.fill(HIST("QA/massXi2"), casc2.pt(), casc2.mXi()); - histos.fill(HIST("QA/massOmega2"), casc2.pt(), casc2.mOmega()); - - // check that the cascades do not share any track - std::vector trackIdsCasc1 = {casc1.posTrackId(), casc1.negTrackId(), casc1.bachelorId()}; - std::vector trackIdsCasc2 = {casc2.posTrackId(), casc2.negTrackId(), casc2.bachelorId()}; - bool shareTrack = false; - for (auto id1 : trackIdsCasc1) { - for (auto id2 : trackIdsCasc2) { - if (id1 == id2) { - shareTrack = true; - break; - } - } - if (shareTrack) { - break; - } - } - if (shareTrack) { - continue; - } - - auto bach1 = casc1.bachelor_as(); - auto bach2 = casc2.bachelor_as(); - - doubleCascCand cand; - cand.ptCasc1 = casc1.pt(); - cand.etaCasc1 = casc1.eta(); - cand.phiCasc1 = casc1.phi(); - cand.cascDecLength1 = std::hypot(casc1.x() - collision.posX(), casc1.y() - collision.posY(), casc1.z() - collision.posZ()); - cand.omegaMassCasc1 = casc1.mOmega(); - cand.xiMassCasc1 = casc1.mXi(); - cand.cosPACasc1 = casc1.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); - cand.dcaBachPVCasc1 = casc1.dcabachtopv(); - cand.dcaV0BachCasc1 = casc1.dcacascdaughters(); - cand.nSigmaKBach1 = bach1.tpcNSigmaKa(); - - cand.ptCasc2 = casc2.pt(); - cand.etaCasc2 = casc2.eta(); - cand.phiCasc2 = casc2.phi(); - cand.cascDecLength2 = std::hypot(casc2.x() - collision.posX(), casc2.y() - collision.posY(), casc2.z() - collision.posZ()); - cand.omegaMassCasc2 = casc2.mOmega(); - cand.xiMassCasc2 = casc2.mXi(); - cand.cosPACasc2 = casc2.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); - cand.dcaBachPVCasc2 = casc2.dcabachtopv(); - cand.dcaV0BachCasc2 = casc2.dcacascdaughters(); - cand.nSigmaKBach2 = bach2.tpcNSigmaKa(); - - cand.doubleOmegaMass = doubleOmegaMass(tracks, casc1, casc2); - - doubleCascCands.push_back(cand); - } - } - }; - - void processData(Collisions const& collision, TracksFull const& tracks, FullCascades const& cascades, aod::BCsWithTimestamps const&) - { - auto bc = collision.bc_as(); - initCCDB(bc); - - if (!collision.sel8()) - return; - - if (std::abs(collision.posZ()) > zVtxMax) - return; - - if (!collision.selection_bit(aod::evsel::kNoITSROFrameBorder) || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) - return; - - if (cfgSkimmedProcessing) { - zorro.isSelected(collision.bc_as().globalBC()); /// Just let Zorro do the accounting - } - histos.fill(HIST("QA/zVtx"), collision.posZ()); - fillDoubleCasc(collision, tracks, cascades); - - for (auto& cand : doubleCascCands) { - doubleCascTable( - cand.ptCasc1, - cand.etaCasc1, - cand.phiCasc1, - cand.cascDecLength1, - cand.omegaMassCasc1, - cand.xiMassCasc1, - cand.cosPACasc1, - cand.dcaBachPVCasc1, - cand.dcaV0BachCasc1, - cand.nSigmaKBach1, - cand.ptCasc2, - cand.etaCasc2, - cand.phiCasc2, - cand.cascDecLength2, - cand.omegaMassCasc2, - cand.xiMassCasc2, - cand.cosPACasc2, - cand.dcaBachPVCasc2, - cand.dcaV0BachCasc2, - cand.nSigmaKBach2, - cand.doubleOmegaMass); - } - } - PROCESS_SWITCH(doubleCascTreeCreator, processData, "process (Run 3)", false); -}; - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; -} diff --git a/PWGLF/TableProducer/Strangeness/doubleOmegaTreeCreator.cxx b/PWGLF/TableProducer/Strangeness/doubleOmegaTreeCreator.cxx new file mode 100644 index 00000000000..0dc52f1beee --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/doubleOmegaTreeCreator.cxx @@ -0,0 +1,1317 @@ +// 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. + +#include "PWGLF/DataModel/LFDoubleOmegaTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/Zorro.h" +#include "Common/Core/ZorroSummary.h" +#include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using CollisionsTable = soa::Join; +using Collisions = CollisionsTable::iterator; +using CollisionsMC = soa::Join; +using FullCascades = aod::CascDataExt; +using TracksFull = soa::Join; +using TracksFullIU = soa::Join; +using TracksFullIUMC = soa::Join; + +struct DoubleOmegaCandidate { + float pt = -999.f; + float eta = -999.f; + float phi = -999.f; + float x = -999.f; + float y = -999.f; + float z = -999.f; + float pvX = -999.f; + float pvY = -999.f; + float pvZ = -999.f; + float cosPAOmega = -999.f; + float cosPADirectLambda = -999.f; + float cosPADoubleOmega = -999.f; + float dcaXYOmegaToPV = -999.f; + float dcaZOmegaToPV = -999.f; + float dcaXYDirectLambdaToPV = -999.f; + float dcaZDirectLambdaToPV = -999.f; + float dcaXYDirectKaonToPV = -999.f; + float dcaZDirectKaonToPV = -999.f; + float tpcNSigmaDirectKaon = -999.f; + float tofNSigmaDirectKaon = -999.f; + uint32_t daughterDetectorMap = 0; + float mass = -999.f; + float massOmega = -999.f; + float massXi = -999.f; +}; + +struct DoubleOmegaMCInfo { + int64_t motherId = -1; + float pt = -999.f; + float eta = -999.f; + float phi = -999.f; + float decayLength = -999.f; + int pdgCode = 0; + // Generated vertices: double-Omega production point (primary vertex), double-Omega + // decay point, and Omega decay point. + std::array genProductionVertex{-999.f, -999.f, -999.f}; + std::array genDecayVertex{-999.f, -999.f, -999.f}; + std::array genOmegaDecayVertex{-999.f, -999.f, -999.f}; +}; + +struct LambdaCandidate { + float px = 0.f; + float py = 0.f; + float pz = 0.f; + float mass = -999.f; +}; + +struct BuiltLambdaCandidate { + LambdaCandidate candidate; + o2::track::TrackParCov parentTrack; + std::array decayVertex{}; + int64_t posTrackId = -1; + int64_t negTrackId = -1; + uint32_t daughterDetectorMap = 0; // Proton, pion; three detector bits each. +}; + +struct BuiltOmegaCandidate { + float px = 0.f; + float py = 0.f; + float pz = 0.f; + float x = 0.f; + float y = 0.f; + float z = 0.f; + float massOmega = -999.f; + float massXi = -999.f; + int8_t sign = 0; + int64_t posTrackId = -1; + int64_t negTrackId = -1; + int64_t bachelorId = -1; + o2::track::TrackParCov parentTrack; + uint32_t daughterDetectorMap = 0; // Kaon, proton, pion; three detector bits each. +}; + +struct doubleOmegaTreeCreator { + Produces doubleOmegaTable; + Produces doubleOmegaTableMC; + Service ccdb{}; + + static constexpr int kDoubleOmegaPdg = 1060020020; + enum FindabilityStep : uint8_t { + kAllGenerated, + kOmegaLambdaKaon, + kTwoLambdasTwoKaons, + kFinalState, + kFindable, + kFindableSelectedTracks, + kFindableCascadeAndV0, + kNFindabilitySteps + }; + std::vector reconstructedDoubleOmegaIds; + + Preslice tracksIUPerCollision = aod::track::collisionId; + Preslice rawCascadesPerCollision = aod::cascade::collisionId; + Preslice rawV0sPerCollision = aod::v0::collisionId; + + int mRunNumber = 0; + float mBz = 0.f; + o2::vertexing::DCAFitterN<2> fitter; + o2::vertexing::DCAFitterN<3> fitter3Body; + + Zorro zorro; + OutputObj zorroSummary{"zorroSummary"}; + + Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Skimmed dataset processing"}; + Configurable cfgApplyEventSelection{"cfgApplyEventSelection", true, "Apply the standard collision event selection"}; + Configurable ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Configurable cfgMaterialCorrection{"cfgMaterialCorrection", static_cast(o2::base::Propagator::MatCorrType::USEMatCorrLUT), "Material correction for the raw V0/cascade fits"}; + + ConfigurableAxis zVtxAxis{"zVtxBins", {100, -20.f, 20.f}, "Binning for the vertex z in cm"}; + ConfigurableAxis massOmegaAxis{"massOmegaAxis", {400, o2::constants::physics::MassOmegaMinus - 0.05f, o2::constants::physics::MassOmegaMinus + 0.05f}, "binning for the Omega invariant-mass"}; + ConfigurableAxis massXiAxis{"massXiAxis", {400, o2::constants::physics::MassXiMinus - 0.05f, o2::constants::physics::MassXiMinus + 0.05f}, "binning for the Xi invariant-mass"}; + ConfigurableAxis massLambdaAxis{"massLambdaAxis", {400, o2::constants::physics::MassLambda0 - 0.05f, o2::constants::physics::MassLambda0 + 0.05f}, "binning for the Lambda invariant-mass"}; + ConfigurableAxis momAxis{"momAxisFine", {5.e2, 0.f, 5.f}, "momentum axis binning"}; + + Configurable zVtxMax{"zVtxMax", 10.0f, "maximum z position of the primary vertex"}; + Configurable etaMax{"etaMax", 0.9f, "maximum eta"}; + Configurable cascPtMin{"cascPtMin", 1.f, "minimum (anti)cascade pT (GeV/c)"}; + Configurable cascPtMax{"cascPtMax", 5.f, "maximum (anti)cascade pT (GeV/c)"}; + + Configurable minNCrossedRows{"minNCrossedRows", 100, "Minimum number of crossed TPC rows"}; + Configurable minNITSClus{"minNITSClus", 0., "Minimum number of ITS clusters"}; + Configurable minNTPCClus{"minNTPCClus", 80, "Minimum number of TPC clusters"}; + Configurable maxNSharedTPCClus{"maxNSharedTPCClus", 5, "Maximum number of shared TPC clusters"}; + + Configurable nSigmaTPCCut{"nSigmaTPCCut", 3.f, "Number of sigmas for the TPC PID"}; + Configurable dcaBachToPV{"dcaBachToPV", 0.05f, "Minimum DCA of a cascade bachelor to the primary vertex"}; + Configurable dcaKaonToPV{"dcaKaonToPV", 0.05f, "Minimum absolute transverse DCA of the direct kaon to the primary vertex"}; + Configurable dcaOmegaToPV{"dcaOmegaToPV", 0.f, "Minimum absolute transverse DCA of the Omega to the primary vertex"}; + Configurable dcaDirectLambdaToPV{"dcaDirectLambdaToPV", 0.f, "Minimum absolute transverse DCA of the direct Lambda to the primary vertex"}; + Configurable dcaV0DauToPV{"dcaV0DauToPV", 0.05f, "Minimum DCA of Lambda daughters to the primary vertex"}; + Configurable dcaV0Bach{"dcaV0Bach", 1.f, "Maximum DCA between the V0 and cascade bachelor"}; + Configurable dcaLambdaDaughters{"dcaLambdaDaughters", 1.f, "Maximum DCA between Lambda daughters"}; + Configurable mXiWindow{"mXiWindow", 0.02f, "Xi mass window used by the cascade compatibility mode"}; + Configurable mOmegaWindow{"mOmegaWindow", 0.01f, "Omega mass window"}; + Configurable mLambdaWindow{"mLambdaWindow", 0.01f, "Lambda mass window"}; + Configurable maxDoubleOmegaMass{"maxDoubleOmegaMass", 3.6f, "Maximum double-Omega invariant mass (GeV/c^2)"}; + Configurable minCosPAOmega{"minCosPAOmega", -1.f, "Minimum Omega cosPA relative to the double-Omega decay vertex"}; + Configurable minCosPADirectLambda{"minCosPADirectLambda", -1.f, "Minimum direct-Lambda cosPA relative to the double-Omega decay vertex"}; + Configurable minCosPADoubleOmega{"minCosPADoubleOmega", -1.f, "Minimum double-Omega cosPA relative to the primary vertex"}; + Configurable minDoubleOmegaDecayRadius{"minDoubleOmegaDecayRadius", 1.f, "Minimum double-Omega transverse decay radius in cm"}; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + template + static uint32_t detectorMap(Track const& track) + { + return static_cast(track.hasITS()) | + (static_cast(track.hasTPC()) << 1) | + (static_cast(track.hasTOF()) << 2); + } + + template + bool selectTrack(T const& track) + { + if (std::abs(track.eta()) > etaMax) { + return false; + } + if (track.itsNCls() < minNITSClus || + track.tpcNClsFound() < minNTPCClus || + track.tpcNClsCrossedRows() < minNCrossedRows || + track.tpcNClsCrossedRows() < 0.8f * track.tpcNClsFindable() || + track.tpcNClsShared() > maxNSharedTPCClus) { + LOG(debug) << "Track failed selection: itsNCls=" << static_cast(track.itsNCls()) << ", tpcNClsFound=" << track.tpcNClsFound() << ", tpcNClsCrossedRows=" << static_cast(track.tpcNClsCrossedRows()) << ", tpcNClsFindable=" << static_cast(track.tpcNClsFindable()) << ", tpcNClsShared=" << static_cast(track.tpcNClsShared()); + return false; + } + return true; + } + + template + void initCCDB(Bc const& bc) + { + if (mRunNumber == bc.runNumber()) { + return; + } + auto* grpmag = ccdb->getForTimeStamp("GLO/Config/GRPMagField", bc.timestamp()); + if (!grpmag) { + LOG(fatal) << "Could not retrieve GRPMagField for timestamp " << bc.timestamp(); + } + o2::base::Propagator::initFieldFromGRP(grpmag); + mBz = o2::base::Propagator::Instance()->getNominalBz(); + fitter.setBz(mBz); + fitter3Body.setBz(mBz); + + if (static_cast(cfgMaterialCorrection.value) == o2::base::Propagator::MatCorrType::USEMatCorrLUT) { + auto* lut = o2::base::MatLayerCylSet::rectifyPtrFromFile(ccdb->getForTimeStamp("GLO/Param/MatLUT", bc.timestamp())); + if (!lut) { + LOG(fatal) << "Could not retrieve material LUT for timestamp " << bc.timestamp(); + } + o2::base::Propagator::Instance()->setMatLUT(lut); + } + fitter.setMatCorrType(static_cast(cfgMaterialCorrection.value)); + fitter3Body.setMatCorrType(static_cast(cfgMaterialCorrection.value)); + + mRunNumber = bc.runNumber(); + if (cfgSkimmedProcessing) { + zorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), "fDoubleOmega,fOmegaXi"); + zorro.populateHistRegistry(histos, bc.runNumber()); + } + } + + void printConfig() const + { + LOG(info) << "doubleOmegaTreeCreator runtime configuration (boolean values: 0=false, 1=true):"; + const auto printValue = [](auto const& config) { + LOG(info) << config.name << " = " << config.value; + }; + const auto printAxis = [](ConfigurableAxis const& axis) { + std::ostringstream values; + values << '['; + for (size_t i = 0; i < axis.value.size(); ++i) { + if (i > 0) { + values << ", "; + } + values << axis.value[i]; + } + values << ']'; + LOG(info) << axis.name << " = " << values.str(); + }; + + printValue(cfgSkimmedProcessing); + printValue(cfgApplyEventSelection); + printValue(ccdburl); + printValue(cfgMaterialCorrection); + printAxis(zVtxAxis); + printAxis(massOmegaAxis); + printAxis(massXiAxis); + printAxis(massLambdaAxis); + printAxis(momAxis); + printValue(zVtxMax); + printValue(etaMax); + printValue(cascPtMin); + printValue(cascPtMax); + printValue(minNCrossedRows); + printValue(minNITSClus); + printValue(minNTPCClus); + printValue(maxNSharedTPCClus); + printValue(nSigmaTPCCut); + printValue(dcaBachToPV); + printValue(dcaKaonToPV); + printValue(dcaOmegaToPV); + printValue(dcaDirectLambdaToPV); + printValue(dcaV0DauToPV); + printValue(dcaV0Bach); + printValue(dcaLambdaDaughters); + printValue(mXiWindow); + printValue(mOmegaWindow); + printValue(mLambdaWindow); + printValue(maxDoubleOmegaMass); + printValue(minCosPAOmega); + printValue(minCosPADirectLambda); + printValue(minCosPADoubleOmega); + printValue(minDoubleOmegaDecayRadius); + printValue(doprocessData); + printValue(doprocessDataFromCascades); + printValue(doprocessMC); + printValue(doprocessFindableTracks); + } + + void init(InitContext const&) + { + printConfig(); + + ccdb->setURL(ccdburl); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + fitter.setPropagateToPCA(true); + fitter.setMaxR(200.); + fitter.setMaxDZIni(4.); + fitter.setMinParamChange(1.e-3); + fitter.setMinRelChi2Change(0.9); + fitter.setUseAbsDCA(true); + + fitter3Body.setPropagateToPCA(true); + fitter3Body.setMaxR(200.); + fitter3Body.setMaxDZIni(4.); + fitter3Body.setMinParamChange(1.e-3); + fitter3Body.setMinRelChi2Change(0.9); + fitter3Body.setUseAbsDCA(true); + + zorroSummary.setObject(zorro.getZorroSummary()); + + histos.add("QA/zVtx", ";#it{z}_{vtx} (cm);Entries", HistType::kTH1F, {zVtxAxis}); + histos.add("QA/massXi", ";#it{p}_{T} (GeV/#it{c});#it{M}(#Lambda + #pi) (GeV/#it{c}^{2});Entries", HistType::kTH2F, {momAxis, massXiAxis}); + histos.add("QA/massOmega", ";#it{p}_{T} (GeV/#it{c});#it{M}(#Lambda + K) (GeV/#it{c}^{2});Entries", HistType::kTH2F, {momAxis, massOmegaAxis}); + histos.add("QA/massLambda", ";#it{p}_{T} (GeV/#it{c});#it{M}(p + #pi) (GeV/#it{c}^{2});Entries", HistType::kTH2F, {momAxis, massLambdaAxis}); + histos.add("MC/generatedAndFindable", ";Double-#Omega;Entries", HistType::kTH1F, {{kNFindabilitySteps, -0.5f, static_cast(kNFindabilitySteps) - 0.5f}}); + auto generatedAndFindable = histos.get(HIST("MC/generatedAndFindable")); + generatedAndFindable->GetXaxis()->SetBinLabel(kAllGenerated + 1, "All generated"); + generatedAndFindable->GetXaxis()->SetBinLabel(kOmegaLambdaKaon + 1, "#Omega + #Lambda + K"); + generatedAndFindable->GetXaxis()->SetBinLabel(kTwoLambdasTwoKaons + 1, "2#Lambda + 2K"); + generatedAndFindable->GetXaxis()->SetBinLabel(kFinalState + 1, "2p + 2#pi^{-} + 2K^{-} (and c.c.)"); + generatedAndFindable->GetXaxis()->SetBinLabel(kFindable + 1, "Findable"); + generatedAndFindable->GetXaxis()->SetBinLabel(kFindableSelectedTracks + 1, "Findable, selected tracks"); + generatedAndFindable->GetXaxis()->SetBinLabel(kFindableCascadeAndV0 + 1, "Findable cascade + V0"); + } + + template + bool isSelectedKaon(Track const& track, int8_t charge) + { + return track.sign() == charge && + selectTrack(track) && + std::abs(track.tpcNSigmaKa()) <= nSigmaTPCCut; + } + + static float invariantMass2Body(std::array const& momentum1, float mass1, + std::array const& momentum2, float mass2) + { + const float momentum1Squared = momentum1[0] * momentum1[0] + momentum1[1] * momentum1[1] + momentum1[2] * momentum1[2]; + const float momentum2Squared = momentum2[0] * momentum2[0] + momentum2[1] * momentum2[1] + momentum2[2] * momentum2[2]; + const float energy = std::sqrt(momentum1Squared + mass1 * mass1) + std::sqrt(momentum2Squared + mass2 * mass2); + const std::array totalMomentum{ + momentum1[0] + momentum2[0], momentum1[1] + momentum2[1], momentum1[2] + momentum2[2]}; + const float massSquared = energy * energy - totalMomentum[0] * totalMomentum[0] - totalMomentum[1] * totalMomentum[1] - totalMomentum[2] * totalMomentum[2]; + return std::sqrt(std::max(0.f, massSquared)); + } + + template + bool buildLambda(Track const& posTrack, Track const& negTrack, int8_t charge, BuiltLambdaCandidate& builtLambda) + { + if (posTrack.sign() <= 0 || negTrack.sign() >= 0 || + !selectTrack(posTrack) || !selectTrack(negTrack)) { + return false; + } + + const bool isMatter = charge < 0; + const float protonNSigma = isMatter ? posTrack.tpcNSigmaPr() : negTrack.tpcNSigmaPr(); + const float pionNSigma = isMatter ? negTrack.tpcNSigmaPi() : posTrack.tpcNSigmaPi(); + if (std::abs(protonNSigma) > nSigmaTPCCut || std::abs(pionNSigma) > nSigmaTPCCut || + std::abs(posTrack.dcaXY()) < dcaV0DauToPV || std::abs(negTrack.dcaXY()) < dcaV0DauToPV) { + LOG(debug) << "Lambda dau don't pass selections: " << "nsigmaPR: " << protonNSigma << ", pionNSigma: " << pionNSigma << ", posTrack.dcaXY(): " << posTrack.dcaXY() << ", negTrack.dcaXY()" << negTrack.dcaXY(); + return false; + } + + auto posTrackParCov = getTrackParCov(posTrack); + auto negTrackParCov = getTrackParCov(negTrack); + int nCandidates = 0; + try { + nCandidates = fitter.process(posTrackParCov, negTrackParCov); + } catch (...) { + LOG(error) << "Exception while fitting Lambda daughter tracks " << posTrack.globalIndex() << ", " << negTrack.globalIndex(); + return false; + } + if (nCandidates == 0) { + return false; + } + + std::array posMomentum{}; + std::array negMomentum{}; + fitter.getTrack(0).getPxPyPzGlo(posMomentum); + fitter.getTrack(1).getPxPyPzGlo(negMomentum); + const std::array lambdaMomentum{ + posMomentum[0] + negMomentum[0], + posMomentum[1] + negMomentum[1], + posMomentum[2] + negMomentum[2]}; + const auto& fittedVertex = fitter.getPCACandidate(); + const std::array decayVertex{ + static_cast(fittedVertex[0]), static_cast(fittedVertex[1]), static_cast(fittedVertex[2])}; + const float mass = isMatter ? invariantMass2Body(posMomentum, o2::constants::physics::MassProton, + negMomentum, o2::constants::physics::MassPionCharged) + : invariantMass2Body(posMomentum, o2::constants::physics::MassPionCharged, + negMomentum, o2::constants::physics::MassProton); + const float dcaDaughters = std::sqrt(std::abs(fitter.getChi2AtPCACandidate())); + const float eta = etaFromMomentum(lambdaMomentum[0], lambdaMomentum[1], lambdaMomentum[2]); + if (std::abs(eta) > etaMax || + dcaDaughters > dcaLambdaDaughters || + std::abs(mass - o2::constants::physics::MassLambda0) > mLambdaWindow) { + return false; + } + + builtLambda.candidate = { + .px = lambdaMomentum[0], + .py = lambdaMomentum[1], + .pz = lambdaMomentum[2], + .mass = mass}; + builtLambda.parentTrack = fitter.createParentTrackParCov(0); + builtLambda.decayVertex = decayVertex; + builtLambda.posTrackId = posTrack.globalIndex(); + builtLambda.negTrackId = negTrack.globalIndex(); + // Keep particle-role ordering for matter and antimatter alike. + builtLambda.daughterDetectorMap = isMatter ? detectorMap(posTrack) | (detectorMap(negTrack) << 3) + : detectorMap(negTrack) | (detectorMap(posTrack) << 3); + return true; + } + + template + bool buildOmega(Track const& posTrack, Track const& negTrack, Track const& bachelor, BuiltOmegaCandidate& builtOmega) + { + if (bachelor.sign() == 0 || + !selectTrack(bachelor) || + std::abs(bachelor.tpcNSigmaKa()) > nSigmaTPCCut || + std::abs(bachelor.dcaXY()) < dcaBachToPV) { + return false; + } + + BuiltLambdaCandidate lambda; + if (!buildLambda(posTrack, negTrack, bachelor.sign(), lambda)) { + return false; + } + + auto v0TrackParCov = lambda.parentTrack; + auto bachelorTrackParCov = getTrackParCov(bachelor); + int nCandidates = 0; + try { + nCandidates = fitter.process(v0TrackParCov, bachelorTrackParCov); + } catch (...) { + LOG(error) << "Exception while fitting Omega daughter tracks " << posTrack.globalIndex() << ", " << negTrack.globalIndex() << ", " << bachelor.globalIndex(); + return false; + } + if (nCandidates == 0) { + return false; + } + + std::array lambdaMomentum{}; + std::array bachelorMomentum{}; + fitter.getTrack(0).getPxPyPzGlo(lambdaMomentum); + fitter.getTrack(1).getPxPyPzGlo(bachelorMomentum); + const std::array omegaMomentum{ + lambdaMomentum[0] + bachelorMomentum[0], + lambdaMomentum[1] + bachelorMomentum[1], + lambdaMomentum[2] + bachelorMomentum[2]}; + const auto& fittedVertex = fitter.getPCACandidate(); + const std::array decayVertex{ + static_cast(fittedVertex[0]), static_cast(fittedVertex[1]), static_cast(fittedVertex[2])}; + const float massOmega = invariantMass2Body(lambdaMomentum, o2::constants::physics::MassLambda0, + bachelorMomentum, o2::constants::physics::MassKaonCharged); + const float massXi = invariantMass2Body(lambdaMomentum, o2::constants::physics::MassLambda0, + bachelorMomentum, o2::constants::physics::MassPionCharged); + const float dcaDaughters = std::sqrt(std::abs(fitter.getChi2AtPCACandidate())); + const float eta = etaFromMomentum(omegaMomentum[0], omegaMomentum[1], omegaMomentum[2]); + if (dcaDaughters > dcaV0Bach || + std::abs(eta) > etaMax || + std::abs(massOmega - o2::constants::physics::MassOmegaMinus) > mOmegaWindow) { + return false; + } + + builtOmega = { + omegaMomentum[0], + omegaMomentum[1], + omegaMomentum[2], + decayVertex[0], + decayVertex[1], + decayVertex[2], + massOmega, + massXi, + static_cast(bachelor.sign()), + posTrack.globalIndex(), + negTrack.globalIndex(), + bachelor.globalIndex(), + fitter.createParentTrackParCov(), + detectorMap(bachelor) | (lambda.daughterDetectorMap << 3)}; + return true; + } + + static float etaFromMomentum(float px, float py, float pz) + { + const float pt = std::hypot(px, py); + return pt > 0.f ? std::asinh(pz / pt) : 0.f; + } + + template + bool buildDoubleOmega(C const& collision, BuiltOmegaCandidate const& omega, BuiltLambdaCandidate const& directLambda, Kaon const& kaon, DoubleOmegaCandidate& cand) + { + auto omegaTrackParCov = omega.parentTrack; + auto lambdaTrackParCov = directLambda.parentTrack; + auto kaonTrackParCov = getTrackParCov(kaon); + int nCandidates = 0; + try { + nCandidates = fitter3Body.process(omegaTrackParCov, lambdaTrackParCov, kaonTrackParCov); + } catch (...) { + LOG(error) << "Exception while fitting the double-Omega candidate"; + return false; + } + if (nCandidates == 0) { + return false; + } + + auto omegaTrackAtVertex = fitter3Body.getTrack(0); + auto lambdaTrackAtVertex = fitter3Body.getTrack(1); + auto kaonTrackAtVertex = fitter3Body.getTrack(2); + std::array omegaMomentum{}; + std::array lambdaMomentum{}; + std::array kaonMomentum{}; + omegaTrackAtVertex.getPxPyPzGlo(omegaMomentum); + lambdaTrackAtVertex.getPxPyPzGlo(lambdaMomentum); + kaonTrackAtVertex.getPxPyPzGlo(kaonMomentum); + + const std::array totalMomentum{ + omegaMomentum[0] + lambdaMomentum[0] + kaonMomentum[0], + omegaMomentum[1] + lambdaMomentum[1] + kaonMomentum[1], + omegaMomentum[2] + lambdaMomentum[2] + kaonMomentum[2]}; + const auto& fittedVertex = fitter3Body.getPCACandidate(); + const std::array decayVertex{ + static_cast(fittedVertex[0]), static_cast(fittedVertex[1]), static_cast(fittedVertex[2])}; + const std::array primaryVertex{collision.posX(), collision.posY(), collision.posZ()}; + const o2::math_utils::Point3D primaryVertexPoint{collision.posX(), collision.posY(), collision.posZ()}; + const std::array omegaDecayVertex{omega.x, omega.y, omega.z}; + + std::array dcaOmega{}; + std::array dcaDirectLambda{}; + std::array dcaDirectKaon{}; + const auto matCorr = static_cast(cfgMaterialCorrection.value); + if (!o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVertexPoint, omegaTrackAtVertex, 2.f, matCorr, &dcaOmega) || + !o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVertexPoint, lambdaTrackAtVertex, 2.f, matCorr, &dcaDirectLambda) || + !o2::base::Propagator::Instance()->propagateToDCABxByBz(primaryVertexPoint, kaonTrackAtVertex, 2.f, matCorr, &dcaDirectKaon)) { + return false; + } + + const auto momentumSquared = [](std::array const& momentum) { + return momentum[0] * momentum[0] + momentum[1] * momentum[1] + momentum[2] * momentum[2]; + }; + const float energy = std::sqrt(momentumSquared(omegaMomentum) + o2::constants::physics::MassOmegaMinus * o2::constants::physics::MassOmegaMinus) + + std::sqrt(momentumSquared(lambdaMomentum) + o2::constants::physics::MassLambda0 * o2::constants::physics::MassLambda0) + + std::sqrt(momentumSquared(kaonMomentum) + o2::constants::physics::MassKaonCharged * o2::constants::physics::MassKaonCharged); + const float massSquared = energy * energy - totalMomentum[0] * totalMomentum[0] - totalMomentum[1] * totalMomentum[1] - totalMomentum[2] * totalMomentum[2]; + + cand.pt = std::hypot(totalMomentum[0], totalMomentum[1]); + cand.eta = etaFromMomentum(totalMomentum[0], totalMomentum[1], totalMomentum[2]); + cand.phi = std::atan2(totalMomentum[1], totalMomentum[0]); + cand.x = decayVertex[0]; + cand.y = decayVertex[1]; + cand.z = decayVertex[2]; + cand.pvX = primaryVertex[0]; + cand.pvY = primaryVertex[1]; + cand.pvZ = primaryVertex[2]; + cand.cosPAOmega = RecoDecay::cpa(decayVertex, omegaDecayVertex, omegaMomentum); + cand.cosPADirectLambda = RecoDecay::cpa(decayVertex, directLambda.decayVertex, lambdaMomentum); + cand.cosPADoubleOmega = RecoDecay::cpa(primaryVertex, decayVertex, totalMomentum); + cand.dcaXYOmegaToPV = dcaOmega[0]; + cand.dcaZOmegaToPV = dcaOmega[1]; + cand.dcaXYDirectLambdaToPV = dcaDirectLambda[0]; + cand.dcaZDirectLambdaToPV = dcaDirectLambda[1]; + cand.dcaXYDirectKaonToPV = dcaDirectKaon[0]; + cand.dcaZDirectKaonToPV = dcaDirectKaon[1]; + cand.tpcNSigmaDirectKaon = kaon.hasTPC() ? kaon.tpcNSigmaKa() : -999.f; + cand.tofNSigmaDirectKaon = kaon.hasTOF() ? kaon.tofNSigmaKa() : -999.f; + cand.daughterDetectorMap = omega.daughterDetectorMap | + (directLambda.daughterDetectorMap << 9) | + (detectorMap(kaon) << 15); + cand.mass = std::sqrt(std::max(0.f, massSquared)); + if (cand.cosPAOmega < minCosPAOmega || + cand.cosPADirectLambda < minCosPADirectLambda || + cand.cosPADoubleOmega < minCosPADoubleOmega || + std::hypot(decayVertex[0], decayVertex[1]) < minDoubleOmegaDecayRadius || + std::abs(cand.dcaXYOmegaToPV) < dcaOmegaToPV || + std::abs(cand.dcaXYDirectLambdaToPV) < dcaDirectLambdaToPV || + std::abs(cand.dcaXYDirectKaonToPV) < dcaKaonToPV || + cand.mass > maxDoubleOmegaMass) { + return false; + } + cand.massOmega = omega.massOmega; + cand.massXi = omega.massXi; + return true; + } + + template + int64_t getLambdaMCLabel(Track const& posTrack, Track const& negTrack, int8_t sign) + { + if (!posTrack.has_mcParticle() || !negTrack.has_mcParticle()) { + return -1; + } + + auto mcPosTrack = posTrack.template mcParticle_as(); + auto mcNegTrack = negTrack.template mcParticle_as(); + const int expectedPosPdg = sign < 0 ? 2212 : 211; + const int expectedNegPdg = sign < 0 ? -211 : -2212; + const int expectedLambdaPdg = sign < 0 ? 3122 : -3122; + if (mcPosTrack.pdgCode() != expectedPosPdg || mcNegTrack.pdgCode() != expectedNegPdg) { + return -1; + } + + for (const auto& posMother : mcPosTrack.template mothers_as()) { + if (posMother.pdgCode() != expectedLambdaPdg) { + continue; + } + for (const auto& negMother : mcNegTrack.template mothers_as()) { + if (posMother.globalIndex() == negMother.globalIndex()) { + return posMother.globalIndex(); + } + } + } + return -1; + } + + template + int64_t getOmegaMCLabel(Track const& posTrack, Track const& negTrack, Track const& bachelorTrack, + int8_t sign, McParticles const& mcParticles) + { + const int64_t lambdaLabel = getLambdaMCLabel(posTrack, negTrack, sign); + if (lambdaLabel < 0 || !bachelorTrack.has_mcParticle()) { + return -1; + } + + auto mcLambda = mcParticles.rawIteratorAt(lambdaLabel); + auto mcBachelor = bachelorTrack.template mcParticle_as(); + const int expectedBachelorPdg = sign < 0 ? -321 : 321; + const int expectedOmegaPdg = sign < 0 ? 3334 : -3334; + if (mcBachelor.pdgCode() != expectedBachelorPdg) { + return -1; + } + + for (const auto& lambdaMother : mcLambda.template mothers_as()) { + if (lambdaMother.pdgCode() != expectedOmegaPdg) { + continue; + } + for (const auto& bachelorMother : mcBachelor.template mothers_as()) { + if (lambdaMother.globalIndex() == bachelorMother.globalIndex()) { + return lambdaMother.globalIndex(); + } + } + } + return -1; + } + + template + bool getMCInfo(DoubleOmegaMCInfo& mcInfo, + Track const& omegaPosTrack, Track const& omegaNegTrack, Track const& omegaBachelorTrack, + Track const& lambdaPosTrack, Track const& lambdaNegTrack, Track const& directKaonTrack, + int8_t sign, McParticles const& mcParticles) + { + const int64_t omegaLabel = getOmegaMCLabel(omegaPosTrack, omegaNegTrack, omegaBachelorTrack, sign, mcParticles); + const int64_t lambdaLabel = getLambdaMCLabel(lambdaPosTrack, lambdaNegTrack, sign); + if (omegaLabel < 0 || lambdaLabel < 0 || !directKaonTrack.has_mcParticle()) { + return false; + } + + auto mcOmega = mcParticles.rawIteratorAt(omegaLabel); + auto mcLambda = mcParticles.rawIteratorAt(lambdaLabel); + auto mcKaon = directKaonTrack.template mcParticle_as(); + const int expectedKaonPdg = sign < 0 ? -321 : 321; + const int expectedDoubleOmegaPdg = sign < 0 ? kDoubleOmegaPdg : -kDoubleOmegaPdg; + if (mcKaon.pdgCode() != expectedKaonPdg) { + return false; + } + + for (const auto& omegaMother : mcOmega.template mothers_as()) { + if (omegaMother.pdgCode() != expectedDoubleOmegaPdg) { + continue; + } + for (const auto& lambdaMother : mcLambda.template mothers_as()) { + if (omegaMother.globalIndex() != lambdaMother.globalIndex()) { + continue; + } + for (const auto& kaonMother : mcKaon.template mothers_as()) { + if (omegaMother.globalIndex() == kaonMother.globalIndex()) { + mcInfo.motherId = omegaMother.globalIndex(); + mcInfo.pt = omegaMother.pt(); + mcInfo.eta = omegaMother.eta(); + mcInfo.phi = omegaMother.phi(); + mcInfo.decayLength = std::hypot(mcOmega.vx() - omegaMother.vx(), + mcOmega.vy() - omegaMother.vy(), + mcOmega.vz() - omegaMother.vz()); + mcInfo.pdgCode = omegaMother.pdgCode(); + return true; + } + } + } + } + return false; + } + + template + bool getGeneratedMCInfo(DoubleOmegaMCInfo& info, McParticle const& particle) + { + if (std::abs(particle.pdgCode()) != kDoubleOmegaPdg) { + return false; + } + + const bool isMatter = particle.pdgCode() > 0; + const int expectedOmegaPdg = isMatter ? 3334 : -3334; + const int expectedLambdaPdg = isMatter ? 3122 : -3122; + const int expectedKaonPdg = isMatter ? -321 : 321; + bool foundOmega = false; + bool foundLambda = false; + bool foundKaon = false; + std::array decayVertex{0.f, 0.f, 0.f}; + std::array omegaDecayVertex{-999.f, -999.f, -999.f}; + + for (const auto& daughter : particle.template daughters_as()) { + if (daughter.pdgCode() == expectedOmegaPdg) { + foundOmega = true; + decayVertex = {daughter.vx(), daughter.vy(), daughter.vz()}; + // The Omega decay point is the production point of any of its daughters. + for (const auto& omegaDaughter : daughter.template daughters_as()) { + omegaDecayVertex = {omegaDaughter.vx(), omegaDaughter.vy(), omegaDaughter.vz()}; + break; + } + } else if (daughter.pdgCode() == expectedLambdaPdg) { + foundLambda = true; + } else if (daughter.pdgCode() == expectedKaonPdg) { + foundKaon = true; + } + } + if (!foundOmega || !foundLambda || !foundKaon) { + return false; + } + + info.motherId = particle.globalIndex(); + info.pt = particle.pt(); + info.eta = particle.eta(); + info.phi = particle.phi(); + info.decayLength = std::hypot(decayVertex[0] - particle.vx(), + decayVertex[1] - particle.vy(), + decayVertex[2] - particle.vz()); + info.pdgCode = particle.pdgCode(); + info.genProductionVertex = {particle.vx(), particle.vy(), particle.vz()}; + info.genDecayVertex = decayVertex; + info.genOmegaDecayVertex = omegaDecayVertex; + return true; + } + + template + bool getLambdaFinalStateIds(McParticle const& lambda, int sign, std::array& finalStateIds) + { + bool foundProton = false; + bool foundPion = false; + for (const auto& daughter : lambda.template daughters_as()) { + if (daughter.pdgCode() == sign * 2212 && !foundProton) { + finalStateIds[0] = daughter.globalIndex(); + foundProton = true; + } else if (daughter.pdgCode() == -sign * 211 && !foundPion) { + finalStateIds[1] = daughter.globalIndex(); + foundPion = true; + } + } + return foundProton && foundPion; + } + + void writeDataCandidate(DoubleOmegaCandidate const& cand) + { + doubleOmegaTable(cand.pt, + cand.eta, + cand.phi, + cand.x, + cand.y, + cand.z, + cand.pvX, + cand.pvY, + cand.pvZ, + cand.cosPAOmega, + cand.cosPADirectLambda, + cand.cosPADoubleOmega, + cand.dcaXYOmegaToPV, + cand.dcaZOmegaToPV, + cand.dcaXYDirectLambdaToPV, + cand.dcaZDirectLambdaToPV, + cand.dcaXYDirectKaonToPV, + cand.dcaZDirectKaonToPV, + cand.tpcNSigmaDirectKaon, + cand.tofNSigmaDirectKaon, + cand.daughterDetectorMap, + cand.mass, + cand.massOmega, + cand.massXi); + } + + void writeMCCandidate(DoubleOmegaCandidate const& cand, DoubleOmegaMCInfo const& mcInfo, bool isReco) + { + doubleOmegaTableMC(cand.pt, + cand.eta, + cand.phi, + cand.x, + cand.y, + cand.z, + cand.pvX, + cand.pvY, + cand.pvZ, + cand.cosPAOmega, + cand.cosPADirectLambda, + cand.cosPADoubleOmega, + cand.dcaXYOmegaToPV, + cand.dcaZOmegaToPV, + cand.dcaXYDirectLambdaToPV, + cand.dcaZDirectLambdaToPV, + cand.dcaXYDirectKaonToPV, + cand.dcaZDirectKaonToPV, + cand.tpcNSigmaDirectKaon, + cand.tofNSigmaDirectKaon, + cand.daughterDetectorMap, + cand.mass, + cand.massOmega, + cand.massXi, + mcInfo.pt, + mcInfo.eta, + mcInfo.phi, + mcInfo.decayLength, + mcInfo.pdgCode, + mcInfo.motherId, + isReco); + } + + template + void logVertexComparison(C const& collision, DoubleOmegaCandidate const& cand, + BuiltOmegaCandidate const& omega, DoubleOmegaMCInfo const& mcInfo) + { + auto logVertex = [](const char* label, std::array const& reco, std::array const& gen) { + LOG(debug) << label + << ": reco = (" << reco[0] << ", " << reco[1] << ", " << reco[2] << ") cm" + << " | gen = (" << gen[0] << ", " << gen[1] << ", " << gen[2] << ") cm" + << " | reco - gen = (" << reco[0] - gen[0] << ", " << reco[1] - gen[1] << ", " << reco[2] - gen[2] << ") cm"; + }; + LOG(debug) << "---------------------------------------- vertices, mother " << mcInfo.motherId + << ", pdgCode = " << mcInfo.pdgCode << ", gen pt = " << mcInfo.pt << " GeV/c"; + logVertex("PV ", {cand.pvX, cand.pvY, cand.pvZ}, mcInfo.genProductionVertex); + logVertex("doubleOmega ", {cand.x, cand.y, cand.z}, mcInfo.genDecayVertex); + logVertex("Omega ", {omega.x, omega.y, omega.z}, mcInfo.genOmegaDecayVertex); + LOG(debug) << "decay length: reco = " + << std::hypot(cand.x - cand.pvX, cand.y - cand.pvY, cand.z - cand.pvZ) + << " cm | gen = " << mcInfo.decayLength << " cm"; + LOG(debug) << "collision " << collision.globalIndex() << " (direct kaon), numContrib = " << collision.numContrib(); + } + + template + void fillFromRawTables(C const& collision, T const& tracks, Cascades const& cascades, V0s const& v0s, + aod::McParticles const* mcParticles = nullptr) + { + for (const auto& rawCascade : cascades) { + const auto omegaV0 = rawCascade.template v0_as(); + const auto omegaPosTrack = omegaV0.template posTrack_as(); + const auto omegaNegTrack = omegaV0.template negTrack_as(); + const auto omegaBachelorTrack = rawCascade.template bachelor_as(); + BuiltOmegaCandidate omega; + if (!buildOmega(omegaPosTrack, omegaNegTrack, omegaBachelorTrack, omega)) { + continue; + } + const float omegaPt = std::hypot(omega.px, omega.py); + histos.fill(HIST("QA/massXi"), omegaPt, omega.massXi); + histos.fill(HIST("QA/massOmega"), omegaPt, omega.massOmega); + const std::array omegaTrackIds{omega.posTrackId, omega.negTrackId, omega.bachelorId}; + + for (const auto& rawV0 : v0s) { + const auto lambdaPosTrack = rawV0.template posTrack_as(); + const auto lambdaNegTrack = rawV0.template negTrack_as(); + BuiltLambdaCandidate lambda; + if (!buildLambda(lambdaPosTrack, lambdaNegTrack, omega.sign, lambda)) { + continue; + } + if (std::find(omegaTrackIds.begin(), omegaTrackIds.end(), lambda.posTrackId) != omegaTrackIds.end() || + std::find(omegaTrackIds.begin(), omegaTrackIds.end(), lambda.negTrackId) != omegaTrackIds.end()) { + continue; + } + histos.fill(HIST("QA/massLambda"), std::hypot(lambda.candidate.px, lambda.candidate.py), lambda.candidate.mass); + + for (const auto& kaon : tracks) { + if (!isSelectedKaon(kaon, omega.sign) || + kaon.globalIndex() == lambda.posTrackId || + kaon.globalIndex() == lambda.negTrackId || + std::find(omegaTrackIds.begin(), omegaTrackIds.end(), kaon.globalIndex()) != omegaTrackIds.end()) { + continue; + } + DoubleOmegaCandidate cand; + if (!buildDoubleOmega(collision, omega, lambda, kaon, cand)) { + continue; + } + if constexpr (isMC) { + if (mcParticles == nullptr) { + continue; + } + DoubleOmegaMCInfo mcInfo; + if (getMCInfo(mcInfo, + omegaPosTrack, omegaNegTrack, omegaBachelorTrack, + lambdaPosTrack, lambdaNegTrack, kaon, + omega.sign, *mcParticles)) { + reconstructedDoubleOmegaIds.push_back(mcInfo.motherId); + writeMCCandidate(cand, mcInfo, true); + } + } else { + writeDataCandidate(cand); + } + } + } + } + } + + template + void fillFromCascades(C const& collision, T const&, Cascades const& cascades) + { + for (const auto& omegaRow : cascades) { + BuiltOmegaCandidate omega; + if (!buildOmega(omegaRow.template posTrack_as(), omegaRow.template negTrack_as(), omegaRow.template bachelor_as(), omega)) { + continue; + } + const float omegaPt = std::hypot(omega.px, omega.py); + histos.fill(HIST("QA/massXi"), omegaPt, omega.massXi); + histos.fill(HIST("QA/massOmega"), omegaPt, omega.massOmega); + const std::array omegaTrackIds{omega.posTrackId, omega.negTrackId, omega.bachelorId}; + + for (const auto& lambdaKaonSource : cascades) { + if (lambdaKaonSource.globalIndex() == omegaRow.globalIndex() || + lambdaKaonSource.sign() != omega.sign) { + continue; + } + + const std::array sourceTrackIds{ + lambdaKaonSource.posTrackId(), lambdaKaonSource.negTrackId(), lambdaKaonSource.bachelorId()}; + bool sharesTrack = false; + for (const auto& omegaTrackId : omegaTrackIds) { + if (std::find(sourceTrackIds.begin(), sourceTrackIds.end(), omegaTrackId) != sourceTrackIds.end()) { + sharesTrack = true; + break; + } + } + if (sharesTrack) { + continue; + } + + auto kaon = lambdaKaonSource.template bachelor_as(); + if (!isSelectedKaon(kaon, omega.sign)) { + continue; + } + BuiltLambdaCandidate lambda; + if (!buildLambda(lambdaKaonSource.template posTrack_as(), lambdaKaonSource.template negTrack_as(), omega.sign, lambda)) { + continue; + } + histos.fill(HIST("QA/massLambda"), std::hypot(lambda.candidate.px, lambda.candidate.py), lambda.candidate.mass); + DoubleOmegaCandidate cand; + if (buildDoubleOmega(collision, omega, lambda, kaon, cand)) { + writeDataCandidate(cand); + } + } + } + } + + // Always take the vertex the direct kaon is associated with. To be improved + template + int64_t selectFindableCollision(Kaon const& kaon) + { + return kaon.collisionId(); + } + + template + bool fillFromSelectedTracks(C const& collisions, T const& tracks, + std::array const& daughterTrackIds, + DoubleOmegaMCInfo const& mcInfo) + { + // Daughter slots: Omega kaon, Omega proton/pion, direct proton/pion, direct kaon. + // Swap proton and pion slots for antimatter to pass positive/negative tracks. + const bool isMatter = mcInfo.pdgCode > 0; + const int8_t charge = isMatter ? -1 : 1; + const auto bachelor = tracks.rawIteratorAt(daughterTrackIds[0]); + if (bachelor.sign() != charge) { + return false; + } + const auto omegaPosTrack = tracks.rawIteratorAt(daughterTrackIds[isMatter ? 1 : 2]); + const auto omegaNegTrack = tracks.rawIteratorAt(daughterTrackIds[isMatter ? 2 : 1]); + const auto lambdaPosTrack = tracks.rawIteratorAt(daughterTrackIds[isMatter ? 3 : 4]); + const auto lambdaNegTrack = tracks.rawIteratorAt(daughterTrackIds[isMatter ? 4 : 3]); + const auto kaon = tracks.rawIteratorAt(daughterTrackIds[5]); + if (!isSelectedKaon(kaon, charge)) { + return false; + } + const int64_t collisionId = selectFindableCollision(kaon); + if (collisionId < 0) { + return false; + } + const auto collision = collisions.rawIteratorAt(collisionId); + const auto bc = collision.template bc_as(); + initCCDB(bc); + + BuiltOmegaCandidate omega; + if (!buildOmega(omegaPosTrack, omegaNegTrack, bachelor, omega)) { + return false; + } + const float omegaPt = std::hypot(omega.px, omega.py); + histos.fill(HIST("QA/massXi"), omegaPt, omega.massXi); + histos.fill(HIST("QA/massOmega"), omegaPt, omega.massOmega); + BuiltLambdaCandidate lambda; + if (!buildLambda(lambdaPosTrack, lambdaNegTrack, charge, lambda)) { + return false; + } + histos.fill(HIST("QA/massLambda"), std::hypot(lambda.candidate.px, lambda.candidate.py), lambda.candidate.mass); + DoubleOmegaCandidate cand; + if (!buildDoubleOmega(collision, omega, lambda, kaon, cand)) { + return false; + } + logVertexComparison(collision, cand, omega, mcInfo); + writeMCCandidate(cand, mcInfo, true); + return true; + } + + template + bool acceptCollision(C const& collision, aod::BCsWithTimestamps const&) + { + auto bc = collision.template bc_as(); + initCCDB(bc); + + if (cfgApplyEventSelection && + (!collision.sel8() || + std::abs(collision.posZ()) > zVtxMax || + !collision.selection_bit(aod::evsel::kNoITSROFrameBorder) || + !collision.selection_bit(aod::evsel::kNoTimeFrameBorder))) { + return false; + } + if (cfgSkimmedProcessing) { + zorro.isSelected(bc.globalBC()); + } + histos.fill(HIST("QA/zVtx"), collision.posZ()); + return true; + } + + void processData(Collisions const& collision, + TracksFullIU const& tracks, + aod::V0s const& v0s, + aod::Cascades const& cascades, + aod::BCsWithTimestamps const& bcs) + { + if (acceptCollision(collision, bcs)) { + fillFromRawTables(collision, tracks, cascades, v0s); + } + } + PROCESS_SWITCH(doubleOmegaTreeCreator, processData, "Reconstruct Omega + Lambda + kaon from raw V0/cascade indices", true); + + void processDataFromCascades(Collisions const& collision, + TracksFull const& tracks, + FullCascades const& cascades, + aod::BCsWithTimestamps const& bcs) + { + if (acceptCollision(collision, bcs)) { + fillFromCascades(collision, tracks, cascades); + } + } + PROCESS_SWITCH(doubleOmegaTreeCreator, processDataFromCascades, "Reconstruct Omega + Lambda + kaon from two cascade rows", false); + + void processMC(CollisionsMC const& collisions, + TracksFullIUMC const& tracks, + aod::V0s const& v0s, + aod::Cascades const& cascades, + aod::McParticles const& mcParticles, + aod::BCsWithTimestamps const& bcs) + { + reconstructedDoubleOmegaIds.clear(); + + for (const auto& collision : collisions) { + auto bc = collision.template bc_as(); + initCCDB(bc); + if (!acceptCollision(collision, bcs)) { + continue; + } + auto tracksThisCollision = tracks.sliceBy(tracksIUPerCollision, collision.globalIndex()); + auto cascadesThisCollision = cascades.sliceBy(rawCascadesPerCollision, collision.globalIndex()); + auto v0sThisCollision = v0s.sliceBy(rawV0sPerCollision, collision.globalIndex()); + v0sThisCollision.bindExternalIndices(&tracks); + cascadesThisCollision.bindExternalIndices(&tracks); + cascadesThisCollision.bindExternalIndices(&v0s); + fillFromRawTables(collision, tracksThisCollision, cascadesThisCollision, v0sThisCollision, &mcParticles); + } + for (const auto& mcParticle : mcParticles) { + DoubleOmegaMCInfo mcInfo; + if (!getGeneratedMCInfo(mcInfo, mcParticle)) { + continue; + } + + if (std::find(reconstructedDoubleOmegaIds.begin(), reconstructedDoubleOmegaIds.end(), mcInfo.motherId) != reconstructedDoubleOmegaIds.end()) { + continue; + } + writeMCCandidate(DoubleOmegaCandidate{}, mcInfo, false); + } + } + PROCESS_SWITCH(doubleOmegaTreeCreator, processMC, "Reconstruct and truth-match Omega + Lambda + kaon in MC", false); + + void processFindableTracks(soa::Join const& collisions, + TracksFullIUMC const& tracks, + aod::Cascades const& cascades, + aod::V0s const& v0s, + aod::McParticles const& mcParticles, + aod::McCollisions const&, + aod::BCsWithTimestamps const&) + { + for (const auto& mcParticle : mcParticles) { + if (std::abs(mcParticle.pdgCode()) != kDoubleOmegaPdg) { + continue; + } + histos.fill(HIST("MC/generatedAndFindable"), kAllGenerated); + + const int sign = mcParticle.pdgCode() > 0 ? 1 : -1; + int64_t omegaId = -1; + int64_t directLambdaId = -1; + int64_t directKaonId = -1; + + // First stage: double-Omega -> Omega + Lambda + kaon. + for (const auto& daughter : mcParticle.daughters_as()) { + if (daughter.pdgCode() == sign * 3334 && omegaId < 0) { + omegaId = daughter.globalIndex(); + } else if (daughter.pdgCode() == sign * 3122 && directLambdaId < 0) { + directLambdaId = daughter.globalIndex(); + } else if (daughter.pdgCode() == -sign * 321 && directKaonId < 0) { + directKaonId = daughter.globalIndex(); + } + } + if (omegaId < 0 || directLambdaId < 0 || directKaonId < 0) { + continue; + } + histos.fill(HIST("MC/generatedAndFindable"), kOmegaLambdaKaon); + + // Second stage: Omega -> Lambda + kaon, giving two Lambdas and two kaons. + const auto omega = mcParticles.rawIteratorAt(omegaId); + int64_t omegaLambdaId = -1; + int64_t omegaKaonId = -1; + for (const auto& daughter : omega.daughters_as()) { + if (daughter.pdgCode() == sign * 3122 && omegaLambdaId < 0) { + omegaLambdaId = daughter.globalIndex(); + } else if (daughter.pdgCode() == -sign * 321 && omegaKaonId < 0) { + omegaKaonId = daughter.globalIndex(); + } + } + if (omegaLambdaId < 0 || omegaKaonId < 0) { + continue; + } + histos.fill(HIST("MC/generatedAndFindable"), kTwoLambdasTwoKaons); + + // Third stage: both Lambdas -> proton + pion. + const auto omegaLambda = mcParticles.rawIteratorAt(omegaLambdaId); + const auto directLambda = mcParticles.rawIteratorAt(directLambdaId); + std::array omegaLambdaFinalStateIds{}; + std::array directLambdaFinalStateIds{}; + if (!getLambdaFinalStateIds(omegaLambda, sign, omegaLambdaFinalStateIds)) { + continue; + } + if (!getLambdaFinalStateIds(directLambda, sign, directLambdaFinalStateIds)) { + continue; + } + histos.fill(HIST("MC/generatedAndFindable"), kFinalState); + + const std::array finalStateIds{ + omegaKaonId, + omegaLambdaFinalStateIds[0], + omegaLambdaFinalStateIds[1], + directLambdaFinalStateIds[0], + directLambdaFinalStateIds[1], + directKaonId}; + std::array reconstructedDaughters{}; + std::array selectedReconstructedDaughters{}; + std::array daughterTrackIds{}; + daughterTrackIds.fill(-1); + // Match by generated daughter, independently of reconstructed collision association. + std::array selectedTrackIds{}; + selectedTrackIds.fill(-1); + for (const auto& track : tracks) { + if (!track.has_mcParticle()) { + continue; + } + const auto daughterId = std::find(finalStateIds.begin(), finalStateIds.end(), track.mcParticleId()); + if (daughterId != finalStateIds.end()) { + const auto daughterIndex = std::distance(finalStateIds.begin(), daughterId); + reconstructedDaughters[daughterIndex] = true; + if (daughterTrackIds[daughterIndex] < 0) { + daughterTrackIds[daughterIndex] = track.globalIndex(); + } + if (selectTrack(track)) { + selectedReconstructedDaughters[daughterIndex] = true; + if (selectedTrackIds[daughterIndex] < 0) { + selectedTrackIds[daughterIndex] = track.globalIndex(); + } + } + } + } + auto printDaughterTracks = [&](const char* tag) { + LOG(debug) << "---------------------------------------- " << tag; + for (std::size_t iDaughter = 0; iDaughter < daughterTrackIds.size(); ++iDaughter) { + LOG(debug) << "+++++++"; + const auto daughterTrack = tracks.rawIteratorAt(daughterTrackIds[iDaughter]); + const auto daughterMCParticle = daughterTrack.mcParticle_as(); + LOG(debug) << "Dau" << iDaughter + 1 + << ": hasITS = " << daughterTrack.hasITS() + << ", hasTPC = " << daughterTrack.hasTPC() + << ", hasTOF = " << daughterTrack.hasTOF() + << ", hasTRD = " << daughterTrack.hasTRD() + << ", isITSAfterburner = " << daughterTrack.isITSAfterburner(); + LOG(debug) << "Dau" << iDaughter + 1 + << ": eta = " << daughterTrack.eta() + << ", pt = " << daughterTrack.pt() + << ", CollisionID = " << daughterTrack.collisionId() + << ", production point = (" << daughterMCParticle.vx() + << ", " << daughterMCParticle.vy() + << ", " << daughterMCParticle.vz() << ") cm"; + } + }; + + bool allDaughtersReconstructed = true; + bool allDaughtersSelected = true; + for (std::size_t iDaughter = 0; iDaughter < reconstructedDaughters.size(); ++iDaughter) { + allDaughtersReconstructed &= reconstructedDaughters[iDaughter]; + allDaughtersSelected &= selectedReconstructedDaughters[iDaughter]; + } + if (allDaughtersReconstructed) { + histos.fill(HIST("MC/generatedAndFindable"), kFindable); + bool omegaInCascade = false; + for (const auto& cascade : cascades) { + const auto cascadeV0 = cascade.v0(); + const std::array cascadeTrackIds{ + cascadeV0.posTrackId(), cascadeV0.negTrackId(), cascade.bachelorId()}; + bool allOmegaTracksInCascade = true; + for (std::size_t iDaughter = 0; iDaughter < 3; ++iDaughter) { + if (std::find(cascadeTrackIds.begin(), cascadeTrackIds.end(), daughterTrackIds[iDaughter]) == cascadeTrackIds.end()) { + allOmegaTracksInCascade = false; + break; + } + } + if (allOmegaTracksInCascade) { + omegaInCascade = true; + break; + } + } + + bool directLambdaInV0 = false; + for (const auto& v0 : v0s) { + const std::array v0TrackIds{v0.posTrackId(), v0.negTrackId()}; + bool allDirectLambdaTracksInV0 = true; + for (std::size_t iDaughter = 3; iDaughter < 5; ++iDaughter) { + if (std::find(v0TrackIds.begin(), v0TrackIds.end(), daughterTrackIds[iDaughter]) == v0TrackIds.end()) { + allDirectLambdaTracksInV0 = false; + break; + } + } + if (allDirectLambdaTracksInV0) { + directLambdaInV0 = true; + break; + } + } + + if (omegaInCascade && directLambdaInV0) { + histos.fill(HIST("MC/generatedAndFindable"), kFindableCascadeAndV0); + printDaughterTracks("findable cascade and V0"); + DoubleOmegaMCInfo mcInfo; + if (!getGeneratedMCInfo(mcInfo, mcParticle)) { + continue; + } + const bool isReco = fillFromSelectedTracks(collisions, tracks, daughterTrackIds, mcInfo); + if (!isReco) { + writeMCCandidate(DoubleOmegaCandidate{}, mcInfo, false); + } + } + } + if (allDaughtersSelected) { + histos.fill(HIST("MC/generatedAndFindable"), kFindableSelectedTracks); + printDaughterTracks("findable selected tracks"); + } + } + } + PROCESS_SWITCH(doubleOmegaTreeCreator, processFindableTracks, "Count findable double-Omega decays and reconstruct selected daughter tracks", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx b/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx index 1a4710576e1..927c13ae023 100644 --- a/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx +++ b/PWGLF/TableProducer/Strangeness/hStrangeCorrelationFilter.cxx @@ -25,6 +25,7 @@ #include "Common/Core/Zorro.h" #include "Common/Core/ZorroSummary.h" #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/CollisionAssociationTables.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponseTOF.h" @@ -82,6 +83,8 @@ struct HStrangeCorrelationFilter { Configurable strangedEdxNSigmaTight{"strangedEdxNSigmaTight", 3, "Nsigmas for strange decay daughters"}; Configurable zorroMask{"zorroMask", "", "zorro trigger class to select on (empty: none)"}; Configurable nSigmaNearXiMassCenter{"nSigmaNearXiMassCenter", 0, "for Oemga analysis only, to check if candidate mass is around Xi"}; + Configurable rejectAmbiguousTracks{"rejectAmbiguousTracks", false, "reject tracks compatible with more than one collision (requires track-to-collision-associator with fillTableOfCollIdsPerTrack)"}; + Configurable rejectAmbiguousAssoc{"rejectAmbiguousAssoc", false, "reject V0/cascade candidates having at least one ambiguous daughter track"}; // used for event selections in Pb-Pb Configurable cfgCutOccupancyHigh{"cfgCutOccupancyHigh", 3000, "High cut on TPC occupancy"}; @@ -210,10 +213,10 @@ struct HStrangeCorrelationFilter { // using V0LinkedTagged = soa::Join; // using CascadesLinkedTagged = soa::Join; - using FullTracks = soa::Join; - using FullTracksMC = soa::Join; - using DauTracks = soa::Join; - using DauTracksMC = soa::Join; + using FullTracks = soa::Join; + using FullTracksMC = soa::Join; + using DauTracks = soa::Join; + using DauTracksMC = soa::Join; // using IDTracks= soa::Join; // prepared for Bayesian PID using IDTracks = soa::Join; using IDTracksMC = soa::Join; @@ -300,12 +303,21 @@ struct HStrangeCorrelationFilter { histos.add("h3dMassLambda", "h3dMassLambda", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisLambdaMass, axesConfigurations.axisMult}); histos.add("h3dMassAntiLambda", "h3dMassAntiLambda", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisLambdaMass, axesConfigurations.axisMult}); } + if (rejectAmbiguousAssoc && (doprocessV0s || doprocessV0sMC)) { + histos.add("hAmbiguousV0Pt", "hAmbiguousV0Pt", kTH1F, {axesConfigurations.axisPtQA}); + } + if (rejectAmbiguousTracks && (doprocessTriggers || doprocessTriggersMC)) { + histos.add("hAmbiguousTriggerPt", "hAmbiguousTriggerPt", kTH1F, {axesConfigurations.axisPtQA}); + } if (doprocessCascades || doprocessCascadesMC) { histos.add("h3dMassXiMinus", "h3dMassXiMinus", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisXiMass, axesConfigurations.axisMult}); histos.add("h3dMassXiPlus", "h3dMassXiPlus", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisXiMass, axesConfigurations.axisMult}); histos.add("h3dMassOmegaMinus", "h3dMassOmegaMinus", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisOmegaMass, axesConfigurations.axisMult}); histos.add("h3dMassOmegaPlus", "h3dMassOmegaPlus", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisOmegaMass, axesConfigurations.axisMult}); } + if (rejectAmbiguousAssoc && (doprocessCascades || doprocessCascadesMC)) { + histos.add("hAmbiguousCascadePt", "hAmbiguousCascadePt", kTH1F, {axesConfigurations.axisPtQA}); + } } void initCCDB(aod::BCsWithTimestamps::iterator const& bc) @@ -410,6 +422,20 @@ struct HStrangeCorrelationFilter { return true; } + // ambiguous track check: the track is compatible with more than one collision, + // or with a collision different from the one it is assigned to (see PWGCF/TableProducer/dptDptFilter.cxx) + template + bool isAmbiguousTrack(TTrack const& track) + { + if (track.compatibleCollIds().size() == 0) { + return false; // no collision association information: not ambiguous + } + if (track.compatibleCollIds().size() == 1) { + return track.collisionId() != track.compatibleCollIds()[0]; + } + return true; // associated to more than one collision + } + // reco-level trigger quality checks (N.B.: DCA is filtered, not selected) template bool isValidTrigger(TTrack const& track) @@ -593,6 +619,10 @@ struct HStrangeCorrelationFilter { if (!isValidTrigger(track)) { continue; } + if (rejectAmbiguousTracks && isAmbiguousTrack(track)) { + histos.fill(HIST("hAmbiguousTriggerPt"), track.pt()); + continue; + } TriggCandidate thisTrigg{}; thisTrigg.pt = track.pt(); thisTrigg.trackId = track.globalIndex(); @@ -634,6 +664,10 @@ struct HStrangeCorrelationFilter { if (!isValidTrigger(track)) { continue; } + if (rejectAmbiguousTracks && isAmbiguousTrack(track)) { + histos.fill(HIST("hAmbiguousTriggerPt"), track.pt()); + continue; + } TriggCandidate thisTrigg{}; thisTrigg.pt = track.pt(); thisTrigg.trackId = track.globalIndex(); @@ -812,6 +846,10 @@ struct HStrangeCorrelationFilter { if (trackSelections.requireClusterInITS && (posdau.itsNCls() < trackSelections.minITSClustersForDaughterTracks || negdau.itsNCls() < trackSelections.minITSClustersForDaughterTracks)) { continue; } + if (rejectAmbiguousAssoc && (isAmbiguousTrack(posdau) || isAmbiguousTrack(negdau))) { + histos.fill(HIST("hAmbiguousV0Pt"), v0.pt()); + continue; + } float dcaDauCutForK0s = v0Selection.dcaDaugToPVForK0s == 0 ? v0Selection.dcaMesonToPV : v0Selection.dcaDaugToPVForK0s; bool isGoodK0Short = (v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < v0Selection.lifetimecutK0S && @@ -947,6 +985,10 @@ struct HStrangeCorrelationFilter { if (trackSelections.requireClusterInITS && (posdau.itsNCls() < trackSelections.minITSClustersForDaughterTracks || negdau.itsNCls() < trackSelections.minITSClustersForDaughterTracks)) { continue; } + if (rejectAmbiguousAssoc && (isAmbiguousTrack(posdau) || isAmbiguousTrack(negdau))) { + histos.fill(HIST("hAmbiguousV0Pt"), v0.pt()); + continue; + } float dcaDauCutForK0s = v0Selection.dcaDaugToPVForK0s == 0 ? v0Selection.dcaMesonToPV : v0Selection.dcaDaugToPVForK0s; bool isGoodK0Short = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < v0Selection.lifetimecutK0S && @@ -1101,6 +1143,10 @@ struct HStrangeCorrelationFilter { if (negTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; } + if (rejectAmbiguousAssoc && (isAmbiguousTrack(bachTrackCast) || isAmbiguousTrack(posTrackCast) || isAmbiguousTrack(negTrackCast))) { + histos.fill(HIST("hAmbiguousCascadePt"), casc.pt()); + continue; + } if (!doPPAnalysis && !cascadeSelectedPbPb(casc, collision.posX(), collision.posY(), collision.posZ())) { continue; } @@ -1270,6 +1316,10 @@ struct HStrangeCorrelationFilter { if (negTrackCast.tpcNClsCrossedRows() < trackSelections.minTPCNCrossedRows) { continue; } + if (rejectAmbiguousAssoc && (isAmbiguousTrack(bachTrackCast) || isAmbiguousTrack(posTrackCast) || isAmbiguousTrack(negTrackCast))) { + histos.fill(HIST("hAmbiguousCascadePt"), casc.pt()); + continue; + } if (!doPPAnalysis && !cascadeSelectedPbPb(casc, collision.posX(), collision.posY(), collision.posZ())) { continue; } diff --git a/PWGLF/TableProducer/Strangeness/lambdaJetPolarizationIons.cxx b/PWGLF/TableProducer/Strangeness/lambdaJetPolarizationIons.cxx index f9253f3469c..d3bcbc0a2ad 100644 --- a/PWGLF/TableProducer/Strangeness/lambdaJetPolarizationIons.cxx +++ b/PWGLF/TableProducer/Strangeness/lambdaJetPolarizationIons.cxx @@ -76,7 +76,6 @@ #include #include #include -#include #include #include #include diff --git a/PWGLF/TableProducer/Strangeness/sigma0builder.cxx b/PWGLF/TableProducer/Strangeness/sigma0builder.cxx index e43f0424ebd..214259f75c4 100644 --- a/PWGLF/TableProducer/Strangeness/sigma0builder.cxx +++ b/PWGLF/TableProducer/Strangeness/sigma0builder.cxx @@ -841,6 +841,8 @@ struct sigma0builder { bool IsSigma0 = false; bool IsAntiSigma0 = false; bool IsKStar = false; + bool IsLambdaStar = false; + bool IsAntiLambdaStar = false; bool IsProducedByGenerator = false; bool IsSterile = false; int MCProcess = -1; @@ -914,8 +916,9 @@ struct sigma0builder { auto v02MC = v02.template v0MCCore_as>(); // Sanity check: Is V0Pair <-> Mother assignment correct? + int expectedPairPDG = doLambdaStar ? 3124 : PDG_t::kSigma0; bool fIsSigma0 = false; - if ((v01MC.pdgCode() == PDG_t::kGamma) && (v01MC.pdgCodeMother() == PDG_t::kSigma0) && (v02MC.pdgCode() == PDG_t::kLambda0) && (v02MC.pdgCodeMother() == PDG_t::kSigma0) && (v01.motherMCPartId() == v02.motherMCPartId())) + if ((v01MC.pdgCode() == PDG_t::kGamma) && (v01MC.pdgCodeMother() == expectedPairPDG) && (v02MC.pdgCode() == PDG_t::kLambda0) && (v02MC.pdgCodeMother() == expectedPairPDG) && (v01.motherMCPartId() == v02.motherMCPartId())) fIsSigma0 = true; bool fIsKStar = false; @@ -1066,11 +1069,11 @@ struct sigma0builder { } } // Check association correctness - if (fIsSigma0 && (MCinfo.V0PairPDGCode == PDG_t::kSigma0)) + if (fIsSigma0 && (MCinfo.V0PairPDGCode == expectedPairPDG)) histos.fill(HIST("MCQA/hSigma0MCCheck"), 1); // match - if (fIsSigma0 && !(MCinfo.V0PairPDGCode == PDG_t::kSigma0)) + if (fIsSigma0 && !(MCinfo.V0PairPDGCode == expectedPairPDG)) histos.fill(HIST("MCQA/hSigma0MCCheck"), 2); // mismatch - if (!fIsSigma0 && (MCinfo.V0PairPDGCode == PDG_t::kSigma0)) + if (!fIsSigma0 && (MCinfo.V0PairPDGCode == expectedPairPDG)) histos.fill(HIST("MCQA/hSigma0MCCheck"), 3); // mismatch // Check association correctness @@ -1627,6 +1630,8 @@ struct sigma0builder { GenInfo.IsSigma0 = mcParticle.pdgCode() == PDG_t::kSigma0; // PDG_t::kSigma0 GenInfo.IsAntiSigma0 = mcParticle.pdgCode() == PDG_t::kSigma0Bar; //-3212 GenInfo.IsKStar = std::abs(mcParticle.pdgCode()) == o2::constants::physics::Pdg::kK0Star892; // 313; + GenInfo.IsLambdaStar = mcParticle.pdgCode() == 3124; // 102134 (PYTHIA8) + GenInfo.IsAntiLambdaStar = mcParticle.pdgCode() == -3124; // -102134 GenInfo.IsProducedByGenerator = mcParticle.producedByGenerator(); GenInfo.MCProcess = mcParticle.getProcess(); GenInfo.MCPt = mcParticle.pt(); @@ -1637,7 +1642,7 @@ struct sigma0builder { GenInfo.MCCollId = mcParticle.mcCollisionId(); // save this reference, please // Checking decay mode if sigma0 or pi0 (it is easier here) - if (GenInfo.IsSigma0 || GenInfo.IsAntiSigma0 || GenInfo.IsPi0 || GenInfo.IsKStar) { + if (GenInfo.IsSigma0 || GenInfo.IsAntiSigma0 || GenInfo.IsPi0 || GenInfo.IsKStar || GenInfo.IsLambdaStar || GenInfo.IsAntiLambdaStar) { // This is a costly operation, so we do it only for pi0s and sigma0s auto const& daughters = mcParticle.template daughters_as(); @@ -1647,7 +1652,7 @@ struct sigma0builder { auto const& GenMothersList = mcParticle.template mothers_as(); GenInfo.PDGCodeMother = (!GenMothersList.empty()) ? GenMothersList.front().pdgCode() : 0; - if ((GenInfo.IsSigma0 || GenInfo.IsAntiSigma0) && genSelections.doQA) { + if ((doLambdaStar ? (GenInfo.IsLambdaStar || GenInfo.IsAntiLambdaStar) : (GenInfo.IsSigma0 || GenInfo.IsAntiSigma0)) && genSelections.doQA) { histos.fill(HIST("GenQA/h2dSigma0MCSourceVsPDGMother"), GenInfo.IsProducedByGenerator, GenInfo.PDGCodeMother); // Checking decay modes and getting daughter pTs @@ -1710,7 +1715,7 @@ struct sigma0builder { histos.fill(HIST("GenQA/hGenSpeciesKStar"), 0); // Checking decay mode - if (GenInfo.IsSigma0 || GenInfo.IsAntiSigma0) { + if (doLambdaStar ? (GenInfo.IsLambdaStar || GenInfo.IsAntiLambdaStar) : (GenInfo.IsSigma0 || GenInfo.IsAntiSigma0)) { histos.fill(HIST("GenQA/hSigma0NDau"), GenInfo.NDaughters); histos.fill(HIST("GenQA/h2dSigma0NDauVsProcess"), GenInfo.NDaughters, GenInfo.MCProcess); @@ -1730,7 +1735,7 @@ struct sigma0builder { histos.fill(HIST("GenQA/h2DGenSigma0TypeVsProducedByGen"), typeIndex, genIndex); // Fill histograms - if (GenInfo.IsSigma0) { + if (doLambdaStar ? GenInfo.IsLambdaStar : GenInfo.IsSigma0) { histos.fill(HIST("GenQA/hGenSpecies"), 2); histos.fill(HIST("GenQA/hGenSigma0"), GenInfo.MCPt); histos.fill(HIST("GenQA/h3dGenSigma0_pTMap"), GenInfo.MCPt, GenInfo.MCDau1Pt, GenInfo.MCDau2Pt); @@ -1739,7 +1744,7 @@ struct sigma0builder { if (GenInfo.IsPrimary) histos.fill(HIST("GenQA/hPrimarySigma0s"), 1); } - if (GenInfo.IsAntiSigma0) { + if (doLambdaStar ? GenInfo.IsAntiLambdaStar : GenInfo.IsAntiSigma0) { histos.fill(HIST("GenQA/hGenSpecies"), 3); histos.fill(HIST("GenQA/hGenAntiSigma0"), GenInfo.MCPt); histos.fill(HIST("GenQA/h3dGenASigma0_pTMap"), GenInfo.MCPt, GenInfo.MCDau1Pt, GenInfo.MCDau2Pt); @@ -1816,9 +1821,10 @@ struct sigma0builder { pi0GenCollRefs(MCGenInfo.MCCollId); // link to stramccollision table } - // Sigma0/ASigma0 - if (fillSigma0Tables && (MCGenInfo.IsSigma0 || MCGenInfo.IsAntiSigma0)) { - sigma0Gens(MCGenInfo.IsSigma0, MCGenInfo.IsProducedByGenerator, MCGenInfo.MCPt, mcParticle.y()); + // Sigma0/ASigma0 (Lambda(1520)/ALambda(1520)) + bool fIsGenSigma0Like = doLambdaStar ? (MCGenInfo.IsLambdaStar || MCGenInfo.IsAntiLambdaStar) : (MCGenInfo.IsSigma0 || MCGenInfo.IsAntiSigma0); + if (fillSigma0Tables && fIsGenSigma0Like) { + sigma0Gens(doLambdaStar ? MCGenInfo.IsLambdaStar : MCGenInfo.IsSigma0, MCGenInfo.IsProducedByGenerator, MCGenInfo.MCPt, mcParticle.y()); sigma0GenCollRefs(MCGenInfo.MCCollId); // link to stramccollision table } diff --git a/PWGLF/TableProducer/Strangeness/sigmaHadCorr.cxx b/PWGLF/TableProducer/Strangeness/sigmaHadCorr.cxx index dc7df2f567a..6f2a8a2336c 100644 --- a/PWGLF/TableProducer/Strangeness/sigmaHadCorr.cxx +++ b/PWGLF/TableProducer/Strangeness/sigmaHadCorr.cxx @@ -37,7 +37,8 @@ #include #include -#include +#include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) +#include #include #include @@ -56,7 +57,7 @@ using TracksFullMC = soa::Join; using CollisionsFullMC = soa::Join; -struct sigmaHadCand { +struct SigmaHadCand { float ptHad() const { @@ -96,22 +97,24 @@ struct sigmaHadCand { float multiplicity = -1.f; }; -struct sigmaHadCorrTask { +struct SigmaHadCorr { - std::vector sigmaHadCandidates; // Vector to store Sigma-hadron candidates Produces outputDataTable; // Output table for Sigma-hadron candidates Produces outputDataTableMC; // Output table for Sigma-hadron candidates in MC + Produces outputKinkCandsMC; // Single-Sigma-level MC truth record, filled before hadron pairing // Histograms are defined with HistogramRegistry HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry rSigmaHad{"sigmaHad", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; // Configurable for event selection - Configurable cutzvertex{"cutZVertex", 10.0f, "Accepted z-vertex range (cm)"}; + Configurable cutZVertex{"cutZVertex", 10.0f, "Accepted z-vertex range (cm)"}; Configurable doSigmaPion{"doSigmaPion", false, "If true, pair Sigma with pions instead of protons"}; Configurable doSigmaMinus{"doSigmaMinus", true, "If true, pair Sigma- candidates, else Sigma+"}; Configurable cutMaxKStar{"cutMaxKStar", 1.5, "Maximum k* for Sigma-hadron pairs (GeV/c)"}; Configurable minPtSigma{"minPtSigma", 1.f, "Minimum pT for Sigma candidates (GeV/c)"}; + Configurable cutRapMotherMC{"cutRapMotherMC", 1.0f, "Rapidity cut for generated mother Sigma in MC"}; + Configurable cutPtGenMC{"cutPtGenMC", 0.5f, "Minimum pT for generated Sigma particles in MC"}; Configurable useRecalculatedSigmaMomentum{"useRecalculatedSigmaMomentum", true, "If true, compute k* using Sigma momentum recalculated from daughter kinematics"}; Configurable cutDCAtoPVSigma{"cutDCAtoPVSigma", 0.1f, "Max DCA to primary vertex for Sigma candidates (cm)"}; Configurable cutSigmaRadius{"cutSigmaRadius", 20.f, "Minimum radius for Sigma candidates (cm)"}; @@ -119,7 +122,7 @@ struct sigmaHadCorrTask { Configurable alphaAPCut{"alphaAPCut", 0., "Alpha AP cut for Sigma candidates"}; Configurable qtAPCutLow{"qtAPCutLow", 0.15, "Lower qT AP cut for Sigma candidates (GeV/c)"}; Configurable qtAPCutHigh{"qtAPCutHigh", 0.2, "Upper qT AP cut for Sigma candidates (GeV/c)"}; - Configurable cutEtaDaught{"cutEtaDaughter", 0.8f, "Eta cut for daughter tracks"}; + Configurable cutEtaDaughter{"cutEtaDaughter", 0.8f, "Eta cut for daughter tracks"}; Configurable ptMinTOFKinkDau{"ptMinTOFKinkDau", 0.75f, "Minimum pT to require TOF for kink daughter PID (GeV/c)"}; Configurable applyTOFPIDKinkDaughter{"applyTOFPIDKinkDaughter", false, "If true, apply TOF PID cut to the kink daughter track"}; @@ -136,8 +139,8 @@ struct sigmaHadCorrTask { Configurable useMultNTracksPV{"useMultNTracksPV", false, "If true, use multNTracksPV for multiplicity and mixing bins; if false, use numContrib"}; Configurable findLastPartonicMother{"findLastPartonicMother", true, "If true, store the initial hard-scattering parton (last partonic mother). If false, store the last parton before hadronization (first partonic mother)"}; - ConfigurableAxis CfgVtxBins{"CfgVtxBins", {10, -10, 10}, "Mixing bins - z-vertex"}; - ConfigurableAxis CfgMultBins{"CfgMultBins", {VARIABLE_WIDTH, 0.0, 40.0, 80.0, 500.0}, "Mixing bins - number of contributor"}; + ConfigurableAxis cfgVtxBins{"cfgVtxBins", {10, -10, 10}, "Mixing bins - z-vertex"}; + ConfigurableAxis cfgMultBins{"cfgMultBins", {VARIABLE_WIDTH, 0.0, 40.0, 80.0, 500.0}, "Mixing bins - number of contributor"}; Configurable nEvtMixingBkg{"nEvtMixingBkg", 5, "Number of events to mix for background reconstruction"}; Preslice kinkCandsPerCollisionPreslice = aod::kinkcand::collisionId; @@ -222,12 +225,13 @@ struct sigmaHadCorrTask { { // Sigma- -> n + pi- (charged daughter = pion, neutral daughter = neutron) // Sigma+ -> p + pi0 (charged daughter = proton, neutral daughter = pi0) + const float epsilon = 1e-6f; float massChargedDau = doSigmaMinus ? o2::constants::physics::MassPionCharged : o2::constants::physics::MassProton; float massNeutralDau = doSigmaMinus ? o2::constants::physics::MassNeutron : o2::constants::physics::MassPionNeutral; float massSigma = doSigmaMinus ? o2::constants::physics::MassSigmaMinus : o2::constants::physics::MassSigmaPlus; float pMother = std::sqrt(sigmaPx * sigmaPx + sigmaPy * sigmaPy + sigmaPz * sigmaPz); - if (pMother < 1e-6f) { + if (pMother < epsilon) { return -999.f; } float versorX = sigmaPx / pMother; @@ -235,29 +239,29 @@ struct sigmaHadCorrTask { float versorZ = sigmaPz / pMother; float eChDau = std::sqrt(massChargedDau * massChargedDau + sigmaDauPx * sigmaDauPx + sigmaDauPy * sigmaDauPy + sigmaDauPz * sigmaDauPz); float a = versorX * sigmaDauPx + versorY * sigmaDauPy + versorZ * sigmaDauPz; - float K = massSigma * massSigma + massChargedDau * massChargedDau - massNeutralDau * massNeutralDau; - float A = 4.f * (eChDau * eChDau - a * a); - float B = -4.f * a * K; - float C = 4.f * eChDau * eChDau * massSigma * massSigma - K * K; - if (std::abs(A) < 1e-6f) { + float coefK = massSigma * massSigma + massChargedDau * massChargedDau - massNeutralDau * massNeutralDau; + float coefA = 4.f * (eChDau * eChDau - a * a); + float coefB = -4.f * a * coefK; + float coefC = 4.f * eChDau * eChDau * massSigma * massSigma - coefK * coefK; + if (std::abs(coefA) < epsilon) { return -999.f; } - float D = B * B - 4.f * A * C; - if (D < 0.f) { + float discriminant = coefB * coefB - 4.f * coefA * coefC; + if (discriminant < 0.f) { return -999.f; } - float sqrtD = std::sqrt(D); - float P1 = (-B + sqrtD) / (2.f * A); - float P2 = (-B - sqrtD) / (2.f * A); - if (P2 < 0.f && P1 < 0.f) { + float sqrtDiscriminant = std::sqrt(discriminant); + float root1 = (-coefB + sqrtDiscriminant) / (2.f * coefA); + float root2 = (-coefB - sqrtDiscriminant) / (2.f * coefA); + if (root2 < 0.f && root1 < 0.f) { return -999.f; } - if (P2 < 0.f) { - return P1; + if (root2 < 0.f) { + return root1; } - float p1Diff = std::abs(P1 - pMother); - float p2Diff = std::abs(P2 - pMother); - return (p1Diff < p2Diff) ? P1 : P2; + float p1Diff = std::abs(root1 - pMother); + float p2Diff = std::abs(root2 - pMother); + return (p1Diff < p2Diff) ? root1 : root2; } std::array getSigmaMomentumForKstar(float sigmaPx, float sigmaPy, float sigmaPz, float sigmaDauPx, float sigmaDauPy, float sigmaDauPz) @@ -309,8 +313,9 @@ struct sigmaHadCorrTask { template int findFirstPartonicMotherPDG(const TMcParticle& mcParticle, const TMcParticles& mcParticles) { + const int notFoundPdg = -999; if (!mcParticle.has_mothers()) { - return -999; + return notFoundPdg; } auto motherIds = mcParticle.mothersIds(); const int defaultMotherSize = 2; @@ -331,10 +336,10 @@ struct sigmaHadCorrTask { return mother.pdgCode(); } int found = findFirstPartonicMotherPDG(mother, mcParticles); - if (found != -999) + if (found != notFoundPdg) return found; } - return -999; + return notFoundPdg; } // Walk up the decay chain iteratively and return the PDG of the last quark or gluon before beam remnants @@ -403,24 +408,19 @@ struct sigmaHadCorrTask { return doSigmaPion ? track.tofNSigmaPi() : track.tofNSigmaPr(); } - TLorentzVector trackSum, PartOneCMS, PartTwoCMS, trackRelK; float getKStar(float sigmaPx, float sigmaPy, float sigmaPz, float pxHad, float pyHad, float pzHad) { - TLorentzVector part1; // Sigma - TLorentzVector part2; // Hadron track (proton/pion) - part1.SetXYZM(sigmaPx, sigmaPy, sigmaPz, getSigmaMassForKstar()); - part2.SetXYZM(pxHad, pyHad, pzHad, getHadTrackMass()); - trackSum = part1 + part2; + ROOT::Math::PxPyPzMVector part1(sigmaPx, sigmaPy, sigmaPz, getSigmaMassForKstar()); // Sigma + ROOT::Math::PxPyPzMVector part2(pxHad, pyHad, pzHad, getHadTrackMass()); // Hadron track (proton/pion) + ROOT::Math::PxPyPzMVector trackSum = part1 + part2; const float beta = trackSum.Beta(); const float betax = beta * std::cos(trackSum.Phi()) * std::sin(trackSum.Theta()); const float betay = beta * std::sin(trackSum.Phi()) * std::sin(trackSum.Theta()); const float betaz = beta * std::cos(trackSum.Theta()); - PartOneCMS.SetXYZM(part1.Px(), part1.Py(), part1.Pz(), part1.M()); - PartTwoCMS.SetXYZM(part2.Px(), part2.Py(), part2.Pz(), part2.M()); const ROOT::Math::Boost boostPRF = ROOT::Math::Boost(-betax, -betay, -betaz); - PartOneCMS = boostPRF(PartOneCMS); - PartTwoCMS = boostPRF(PartTwoCMS); - trackRelK = PartOneCMS - PartTwoCMS; + ROOT::Math::PxPyPzMVector partOneCMS = boostPRF(part1); + ROOT::Math::PxPyPzMVector partTwoCMS = boostPRF(part2); + ROOT::Math::PxPyPzMVector trackRelK = partOneCMS - partTwoCMS; return 0.5 * trackRelK.P(); } @@ -430,7 +430,7 @@ struct sigmaHadCorrTask { if (candidate.pt() < ptMinHad) { return false; } - if (std::abs(getTPCNSigmaHad(candidate)) > cutNSigmaTPC || candidate.tpcNClsFound() < cutNTPCClusHad || std::abs(candidate.eta()) > cutEtaDaught) { + if (std::abs(getTPCNSigmaHad(candidate)) > cutNSigmaTPC || candidate.tpcNClsFound() < cutNTPCClusHad || std::abs(candidate.eta()) > cutEtaDaughter) { return false; } @@ -500,9 +500,10 @@ struct sigmaHadCorrTask { return true; } - template - void fillTreeAndHistograms(aod::KinkCands const& kinkCands, Ttrack const& tracksDauSigma, Ttrack const& tracks, Tcollision const& collision, bool isMC) + template + std::vector fillTreeAndHistograms(aod::KinkCands const& kinkCands, Ttrack const& tracksDauSigma, Ttrack const& tracks, Tcollision const& collision) { + std::vector sigmaHadCandidates; for (const auto& sigmaCand : kinkCands) { auto kinkDauTrack = tracksDauSigma.rawIteratorAt(sigmaCand.trackDaugId()); if (!selectSigma(sigmaCand, kinkDauTrack)) { @@ -528,6 +529,30 @@ struct sigmaHadCorrTask { rSigmaHad.fill(HIST("QA/hSigmaPtRecal"), sigmaPtRecal); rSigmaHad.fill(HIST("QA/h2InvMassVsPtSigma"), sigmaPtRecal, sigmaMassForQa); + // single-Sigma-level MC truth record, filled once per accepted candidate, independent of hadron pairing + if constexpr (IsMC) { + auto mothTrack = tracksDauSigma.rawIteratorAt(sigmaCand.trackMothId()); + if (mothTrack.has_mcParticle() && kinkDauTrack.has_mcParticle()) { + auto mcMoth = mothTrack.template mcParticle_as(); + auto mcDaug = kinkDauTrack.template mcParticle_as(); + float massMC = std::sqrt(mcMoth.e() * mcMoth.e() - mcMoth.p() * mcMoth.p()); + float decayRadiusMC = std::hypot(mcDaug.vx() - mcMoth.vx(), mcDaug.vy() - mcMoth.vy()); + bool collisionIdCheck = false; + if (collision.has_mcCollision()) { + collisionIdCheck = collision.mcCollision().globalIndex() == mcDaug.mcCollisionId(); + } + outputKinkCandsMC(sigmaCand.xDecVtx(), sigmaCand.yDecVtx(), sigmaCand.zDecVtx(), + sigmaCand.pxMoth(), sigmaCand.pyMoth(), sigmaCand.pzMoth(), + sigmaCand.pxDaug(), sigmaCand.pyDaug(), sigmaCand.pzDaug(), + sigmaCand.dcaMothPv(), sigmaCand.dcaDaugPv(), sigmaCand.dcaKinkTopo(), + sigmaCand.mothSign(), + kinkDauTrack.tpcNSigmaPi(), kinkDauTrack.tpcNSigmaPr(), -999.f, + kinkDauTrack.tofNSigmaPi(), kinkDauTrack.tofNSigmaPr(), -999.f, + mcMoth.pdgCode(), mcDaug.pdgCode(), + mcMoth.pt(), mcMoth.pz(), massMC, decayRadiusMC, collisionIdCheck); + } + } + for (const auto& hadTrack : tracks) { if (hadTrack.globalIndex() == sigmaCand.trackDaugId()) { continue; @@ -537,7 +562,7 @@ struct sigmaHadCorrTask { continue; } - sigmaHadCand candidate; + SigmaHadCand candidate; candidate.sigmaCharge = sigmaCand.mothSign(); candidate.sigmaPx = sigmaCand.pxMoth(); candidate.sigmaPy = sigmaCand.pyMoth(); @@ -575,33 +600,35 @@ struct sigmaHadCorrTask { if (hadTrack.hasTOF()) { rSigmaHad.fill(HIST("QA/h2TOFNSigmaHadVsPtHad"), candidate.ptHad(), candidate.nSigmaTOFHad); } - if (fillSparseInvMassKstar && !isMC) { - rSigmaHad.fill(HIST("hSparseSigmaHad"), - candidate.sigmaMass, - kStar, - candidate.sigmaCharge, - candidate.chargeHad, - candidate.sigmaDecRadius, - candidate.sigmaCosPA, - sigmaPtRecal); + if constexpr (!IsMC) { + if (fillSparseInvMassKstar) { + rSigmaHad.fill(HIST("hSparseSigmaHad"), + candidate.sigmaMass, + kStar, + candidate.sigmaCharge, + candidate.chargeHad, + candidate.sigmaDecRadius, + candidate.sigmaCosPA, + sigmaPtRecal); + } } sigmaHadCandidates.push_back(candidate); } } + return sigmaHadCandidates; } void processSameEvent(CollisionsFull const& collisions, aod::KinkCands const& kinkCands, TracksFull const& tracks) { for (auto const& collision : collisions) { - sigmaHadCandidates.clear(); - auto kinkCands_c = kinkCands.sliceBy(kinkCandsPerCollisionPreslice, collision.globalIndex()); - auto tracks_c = tracks.sliceBy(tracksPerCollisionPreslice, collision.globalIndex()); - if (std::abs(collision.posZ()) > cutzvertex || !collision.sel8()) { + auto kinkCandsC = kinkCands.sliceBy(kinkCandsPerCollisionPreslice, collision.globalIndex()); + auto tracksC = tracks.sliceBy(tracksPerCollisionPreslice, collision.globalIndex()); + if (std::abs(collision.posZ()) > cutZVertex || !collision.sel8()) { continue; } rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); - fillTreeAndHistograms(kinkCands_c, tracks, tracks_c, collision, false); + auto sigmaHadCandidates = fillTreeAndHistograms(kinkCandsC, tracks, tracksC, collision); if (fillOutputTree) { // Fill output table for (const auto& candidate : sigmaHadCandidates) { @@ -625,7 +652,7 @@ struct sigmaHadCorrTask { } } } - PROCESS_SWITCH(sigmaHadCorrTask, processSameEvent, "Process Same event", true); + PROCESS_SWITCH(SigmaHadCorr, processSameEvent, "Process Same event", true); // Processing Event Mixing SliceCache cache; @@ -636,17 +663,16 @@ struct sigmaHadCorrTask { { if (useMultNTracksPV.value) { for (auto const& [collision1, collision2] : - selfCombinations(BinningTypeMultNTracksPV{{CfgVtxBins, CfgMultBins}, true}, nEvtMixingBkg, -1, collisions, collisions)) { + selfCombinations(BinningTypeMultNTracksPV{{cfgVtxBins, cfgMultBins}, true}, nEvtMixingBkg, -1, collisions, collisions)) { if (collision1.index() == collision2.index()) continue; - sigmaHadCandidates.clear(); - if (std::abs(collision1.posZ()) > cutzvertex || !collision1.sel8()) + if (std::abs(collision1.posZ()) > cutZVertex || !collision1.sel8()) continue; - if (std::abs(collision2.posZ()) > cutzvertex || !collision2.sel8()) + if (std::abs(collision2.posZ()) > cutZVertex || !collision2.sel8()) continue; - auto kinkCands_c1 = kinkCands.sliceBy(kinkCandsPerCollisionPreslice, collision1.globalIndex()); - auto tracks_c2 = tracks.sliceBy(tracksPerCollisionPreslice, collision2.globalIndex()); - fillTreeAndHistograms(kinkCands_c1, tracks, tracks_c2, collision1, false); + auto kinkCandsC1 = kinkCands.sliceBy(kinkCandsPerCollisionPreslice, collision1.globalIndex()); + auto tracksC2 = tracks.sliceBy(tracksPerCollisionPreslice, collision2.globalIndex()); + auto sigmaHadCandidates = fillTreeAndHistograms(kinkCandsC1, tracks, tracksC2, collision1); if (fillOutputTree) { for (const auto& candidate : sigmaHadCandidates) { outputDataTable(candidate.sigmaCharge, candidate.sigmaPx, candidate.sigmaPy, candidate.sigmaPz, @@ -659,17 +685,16 @@ struct sigmaHadCorrTask { } } else { for (auto const& [collision1, collision2] : - selfCombinations(BinningTypeNumContrib{{CfgVtxBins, CfgMultBins}, true}, nEvtMixingBkg, -1, collisions, collisions)) { + selfCombinations(BinningTypeNumContrib{{cfgVtxBins, cfgMultBins}, true}, nEvtMixingBkg, -1, collisions, collisions)) { if (collision1.index() == collision2.index()) continue; - sigmaHadCandidates.clear(); - if (std::abs(collision1.posZ()) > cutzvertex || !collision1.sel8()) + if (std::abs(collision1.posZ()) > cutZVertex || !collision1.sel8()) continue; - if (std::abs(collision2.posZ()) > cutzvertex || !collision2.sel8()) + if (std::abs(collision2.posZ()) > cutZVertex || !collision2.sel8()) continue; - auto kinkCands_c1 = kinkCands.sliceBy(kinkCandsPerCollisionPreslice, collision1.globalIndex()); - auto tracks_c2 = tracks.sliceBy(tracksPerCollisionPreslice, collision2.globalIndex()); - fillTreeAndHistograms(kinkCands_c1, tracks, tracks_c2, collision1, false); + auto kinkCandsC1 = kinkCands.sliceBy(kinkCandsPerCollisionPreslice, collision1.globalIndex()); + auto tracksC2 = tracks.sliceBy(tracksPerCollisionPreslice, collision2.globalIndex()); + auto sigmaHadCandidates = fillTreeAndHistograms(kinkCandsC1, tracks, tracksC2, collision1); if (fillOutputTree) { for (const auto& candidate : sigmaHadCandidates) { outputDataTable(candidate.sigmaCharge, candidate.sigmaPx, candidate.sigmaPy, candidate.sigmaPz, @@ -682,21 +707,20 @@ struct sigmaHadCorrTask { } } } - PROCESS_SWITCH(sigmaHadCorrTask, processMixedEvent, "Process Mixed event", false); + PROCESS_SWITCH(SigmaHadCorr, processMixedEvent, "Process Mixed event", false); - void processSameEventMC(CollisionsFullMC const& collisions, aod::KinkCands const& kinkCands, TracksFullMC const& tracks, aod::McParticles const& mcParticles) + void processSameEventMC(CollisionsFullMC const& collisions, aod::KinkCands const& kinkCands, TracksFullMC const& tracks, aod::McParticles const& mcParticles, aod::McCollisions const&) { for (auto const& collision : collisions) { - sigmaHadCandidates.clear(); - auto kinkCands_c = kinkCands.sliceBy(kinkCandsPerCollisionPreslice, collision.globalIndex()); - auto tracks_c = tracks.sliceBy(tracksMCPerCollisionPreslice, collision.globalIndex()); + auto kinkCandsC = kinkCands.sliceBy(kinkCandsPerCollisionPreslice, collision.globalIndex()); + auto tracksC = tracks.sliceBy(tracksMCPerCollisionPreslice, collision.globalIndex()); - if (std::abs(collision.posZ()) > cutzvertex || !collision.sel8()) { + if (std::abs(collision.posZ()) > cutZVertex || !collision.sel8()) { continue; } rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); - fillTreeAndHistograms(kinkCands_c, tracks, tracks_c, collision, true); + auto sigmaHadCandidates = fillTreeAndHistograms(kinkCandsC, tracks, tracksC, collision); for (const auto& candidate : sigmaHadCandidates) { auto mcLabelSigma = tracks.rawIteratorAt(candidate.sigmaID); auto mcLabelSigmaDau = tracks.rawIteratorAt(candidate.kinkDauID); @@ -763,24 +787,64 @@ struct sigmaHadCorrTask { } } } + + // all generated Sigma -> chargedDau + neutralDau decays + int pdgChargedDauAbs = doSigmaMinus ? PDG_t::kPiPlus : PDG_t::kProton; + for (const auto& mcPart : mcParticles) { + int pdgMothAbs = std::abs(mcPart.pdgCode()); + bool isValidMother = doSigmaMinus ? (pdgMothAbs == PDG_t::kSigmaMinus || pdgMothAbs == PDG_t::kSigmaPlus) : (pdgMothAbs == PDG_t::kSigmaPlus); + if (!isValidMother) { + continue; + } + if (std::abs(mcPart.y()) > cutRapMotherMC) { + continue; + } + if (mcPart.pt() < cutPtGenMC) { + continue; + } + bool hasChargedDaughter = false; + std::array genDecVtx{-999.f, -999.f, -999.f}; + int daugPdgCode = 0; + for (const auto& daughter : mcPart.daughters_as()) { + if (std::abs(daughter.pdgCode()) == pdgChargedDauAbs) { + hasChargedDaughter = true; + genDecVtx = {daughter.vx(), daughter.vy(), daughter.vz()}; + daugPdgCode = daughter.pdgCode(); + break; + } + } + if (!hasChargedDaughter) { + continue; + } + float massMC = std::sqrt(mcPart.e() * mcPart.e() - mcPart.p() * mcPart.p()); + float decayRadiusMC = std::hypot(genDecVtx[0] - mcPart.vx(), genDecVtx[1] - mcPart.vy()); + outputKinkCandsMC(-999.f, -999.f, -999.f, + -999.f, -999.f, -999.f, + -999.f, -999.f, -999.f, + -999.f, -999.f, -999.f, + mcPart.pdgCode() > 0 ? 1 : -1, + -999.f, -999.f, -999.f, + -999.f, -999.f, -999.f, + mcPart.pdgCode(), daugPdgCode, + mcPart.pt(), mcPart.pz(), massMC, decayRadiusMC, false); + } } - PROCESS_SWITCH(sigmaHadCorrTask, processSameEventMC, "Process Same event MC", false); + PROCESS_SWITCH(SigmaHadCorr, processSameEventMC, "Process Same event MC", false); - void processMixedEventMC(const CollisionsFullMC& collisions, const aod::KinkCands& kinkCands, const TracksFullMC& tracks, const aod::McParticles& mcParticles) + void processMixedEventMC(const CollisionsFullMC& collisions, const aod::KinkCands& kinkCands, const TracksFullMC& tracks, const aod::McParticles& mcParticles, aod::McCollisions const&) { if (useMultNTracksPV.value) { for (auto const& [collision1, collision2] : - selfCombinations(BinningTypeMultNTracksPV{{CfgVtxBins, CfgMultBins}, true}, nEvtMixingBkg, -1, collisions, collisions)) { + selfCombinations(BinningTypeMultNTracksPV{{cfgVtxBins, cfgMultBins}, true}, nEvtMixingBkg, -1, collisions, collisions)) { if (collision1.index() == collision2.index()) continue; - sigmaHadCandidates.clear(); - if (std::abs(collision1.posZ()) > cutzvertex || !collision1.sel8()) + if (std::abs(collision1.posZ()) > cutZVertex || !collision1.sel8()) continue; - if (std::abs(collision2.posZ()) > cutzvertex || !collision2.sel8()) + if (std::abs(collision2.posZ()) > cutZVertex || !collision2.sel8()) continue; - auto kinkCands_c1 = kinkCands.sliceBy(kinkCandsPerCollisionPreslice, collision1.globalIndex()); - auto tracks_c2 = tracks.sliceBy(tracksPerCollisionPreslice, collision2.globalIndex()); - fillTreeAndHistograms(kinkCands_c1, tracks, tracks_c2, collision1, true); + auto kinkCandsC1 = kinkCands.sliceBy(kinkCandsPerCollisionPreslice, collision1.globalIndex()); + auto tracksC2 = tracks.sliceBy(tracksPerCollisionPreslice, collision2.globalIndex()); + auto sigmaHadCandidates = fillTreeAndHistograms(kinkCandsC1, tracks, tracksC2, collision1); for (const auto& candidate : sigmaHadCandidates) { auto mcLabelSigma = tracks.rawIteratorAt(candidate.sigmaID); auto mcLabelSigmaDau = tracks.rawIteratorAt(candidate.kinkDauID); @@ -819,17 +883,16 @@ struct sigmaHadCorrTask { } } else { for (auto const& [collision1, collision2] : - selfCombinations(BinningTypeNumContrib{{CfgVtxBins, CfgMultBins}, true}, nEvtMixingBkg, -1, collisions, collisions)) { + selfCombinations(BinningTypeNumContrib{{cfgVtxBins, cfgMultBins}, true}, nEvtMixingBkg, -1, collisions, collisions)) { if (collision1.index() == collision2.index()) continue; - sigmaHadCandidates.clear(); - if (std::abs(collision1.posZ()) > cutzvertex || !collision1.sel8()) + if (std::abs(collision1.posZ()) > cutZVertex || !collision1.sel8()) continue; - if (std::abs(collision2.posZ()) > cutzvertex || !collision2.sel8()) + if (std::abs(collision2.posZ()) > cutZVertex || !collision2.sel8()) continue; - auto kinkCands_c1 = kinkCands.sliceBy(kinkCandsPerCollisionPreslice, collision1.globalIndex()); - auto tracks_c2 = tracks.sliceBy(tracksPerCollisionPreslice, collision2.globalIndex()); - fillTreeAndHistograms(kinkCands_c1, tracks, tracks_c2, collision1, true); + auto kinkCandsC1 = kinkCands.sliceBy(kinkCandsPerCollisionPreslice, collision1.globalIndex()); + auto tracksC2 = tracks.sliceBy(tracksPerCollisionPreslice, collision2.globalIndex()); + auto sigmaHadCandidates = fillTreeAndHistograms(kinkCandsC1, tracks, tracksC2, collision1); for (const auto& candidate : sigmaHadCandidates) { auto mcLabelSigma = tracks.rawIteratorAt(candidate.sigmaID); auto mcLabelSigmaDau = tracks.rawIteratorAt(candidate.kinkDauID); @@ -868,10 +931,10 @@ struct sigmaHadCorrTask { } } } - PROCESS_SWITCH(sigmaHadCorrTask, processMixedEventMC, "Process Mixed event MC", false); + PROCESS_SWITCH(SigmaHadCorr, processMixedEventMC, "Process Mixed event MC", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/TableProducer/Strangeness/sigmaplusbuilder.cxx b/PWGLF/TableProducer/Strangeness/sigmaplusbuilder.cxx index 739e7859c0f..7969042b519 100644 --- a/PWGLF/TableProducer/Strangeness/sigmaplusbuilder.cxx +++ b/PWGLF/TableProducer/Strangeness/sigmaplusbuilder.cxx @@ -18,19 +18,25 @@ #include "Common/Core/RecoDecay.h" #include "Common/Core/trackUtilities.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" #include +#include #include #include #include #include #include +#include #include #include #include +#include +#include +#include #include #include #include @@ -52,36 +58,61 @@ using namespace o2::framework; using TracksFull = soa::Join; using TracksFullMC = soa::Join; -using CollisionsFull = aod::Collisions; -using CollisionsFullMC = soa::Join; +using CollisionsFull = soa::Join; +using CollisionsFullMC = soa::Join; struct Sigmaplusbuilder { + // event selection + Configurable cutZVertex{"cutZVertex", 10.0f, "Accepted z-vertex range (cm)"}; + // photon (PCM) selection Configurable photonMaxMass{"photonMaxMass", 0.20, "Max photon mass (GeV/c^2)"}; Configurable photonMinRapidity{"photonMinRapidity", -0.8, "Min photon rapidity"}; Configurable photonMaxRapidity{"photonMaxRapidity", 0.8, "Max photon rapidity"}; + Configurable cutRapMotherMC{"cutRapMotherMC", 1.0f, "Rapidity cut for generated mother Sigma+ in MC"}; + Configurable cutPtGenMC{"cutPtGenMC", 0.5f, "Minimum pT for generated Sigma+ in MC"}; Configurable photonDauEtaMin{"photonDauEtaMin", -0.8, "Min eta of photon daughter tracks"}; Configurable photonDauEtaMax{"photonDauEtaMax", 0.8, "Max eta of photon daughter tracks"}; Configurable photonMinRadius{"photonMinRadius", 3.0, "Min photon conversion radius (cm)"}; Configurable photonMaxRadius{"photonMaxRadius", 115., "Max photon conversion radius (cm)"}; Configurable photonMinV0cospa{"photonMinV0cospa", 0.80, "Min V0 CosPA"}; Configurable photonMaxDCAV0Dau{"photonMaxDCAV0Dau", 3.5, "Max DCA between photon daughters (cm)"}; + Configurable photonMaxOpeningAngle{"photonMaxOpeningAngle", 0.4, "Max opening angle between the photon's e+/e- daughter momenta (rad)"}; + Configurable photonMaxDeltaTheta{"photonMaxDeltaTheta", 0.15, "Max |theta_pos - theta_neg| of the photon's daughter tracks (rad)"}; Configurable photonMaxQt{"photonMaxQt", 0.15, "Max Armenteros qT for photons (GeV/c)"}; Configurable photonMaxAlpha{"photonMaxAlpha", 1.0, "Max |Armenteros alpha| for photons"}; - Configurable photonMaxTPCNSigmaEl{"photonMaxTPCNSigmaEl", 15, "Max |TPC nSigma_el| for photon daughters"}; + Configurable photonDauMinTPCNSigmaEl{"photonDauMinTPCNSigmaEl", -5., "Min TPC nSigma_el of the photon daughters"}; + Configurable photonDauMaxTPCNSigmaEl{"photonDauMaxTPCNSigmaEl", 5., "Max TPC nSigma_el of the photon daughters"}; + Configurable photonDauMinTpcNCls{"photonDauMinTpcNCls", 30, "Min number of found TPC clusters for the photon (V0) daughter tracks"}; // proton selection Configurable protonMinPt{"protonMinPt", 0.3, "Minimum proton pT (GeV/c)"}; Configurable protonMaxEta{"protonMaxEta", 0.9, "Maximum |eta| for proton track"}; + Configurable protonMinTpcNCls{"protonMinTpcNCls", 80, "Min number of found TPC clusters for the proton track"}; Configurable protonMaxTPCNSigma{"protonMaxTPCNSigma", 4, "Max |TPC nSigma_pr| for proton"}; Configurable protonMaxTOFNSigma{"protonMaxTOFNSigma", 4, "Max |TOF nSigma_pr| for proton, if TOF available"}; Configurable protonPtMinRequireTOF{"protonPtMinRequireTOF", 0.75, "Above this pT, require TOF PID for proton"}; + Configurable protonRequireTofHit{"protonRequireTofHit", false, "Above protonPtMinRequireTOF, reject a proton with no TOF hit at all"}; + Configurable protonMinDcaToPV{"protonMinDcaToPV", 0.005, "Min DCAxy of the proton track to the PV (cm)"}; + Configurable protonMaxDcaToPV{"protonMaxDcaToPV", 5.0, "Max DCAxy of the proton track to the PV (cm)"}; // proton-photon candidate selection - Configurable candMaxDcaProtonGamma{"candMaxDcaProtonGamma", 5.0, "Max DCA between proton and photon at the fitted vertex (cm)"}; + Configurable candMaxDcaProtonGamma{"candMaxDcaProtonGamma", 0.5, "Max DCA between proton and photon at the fitted vertex (cm)"}; + Configurable candMaxDcaToPV{"candMaxDcaToPV", 0.1, "Max DCA of the candidate's total (reconstructed) momentum line to the PV (cm)"}; + Configurable candRejectNegRootCenter{"candRejectNegRootCenter", true, "Reject candidates with rootCenter<0"}; + Configurable candMaxRootCenter{"candMaxRootCenter", 15, "Max rootCenter=-coefB/(2*coefA) (GeV/c)"}; + Configurable candMinAntiSigmaPointingAngle{"candMinAntiSigmaPointingAngle", 0.0, "Min AntiSigmaPointingAngle (rad)"}; + Configurable candMaxAntiSigmaPointingAngle{"candMaxAntiSigmaPointingAngle", 0.3, "Max AntiSigmaPointingAngle (rad)"}; + Configurable candMaxSigmaMass{"candMaxSigmaMass", 1.35, "Max reconstructed Sigma+ candidate mass (GeV/c^2)"}; + Configurable candMaxRapidity{"candMaxRapidity", 0.9, "Max |rapidity| of the reconstructed Sigma+ candidate"}; Configurable candMinRadius{"candMinRadius", 1.0, "Min candidate decay radius (cm)"}; Configurable candMaxRadius{"candMaxRadius", 100., "Max candidate decay radius (cm)"}; + Configurable candMinFlightDistance{"candMinFlightDistance", 0.0, "Min 3D distance from PV to candidate decay vertex (cm)"}; + Configurable candMaxFlightDistance{"candMaxFlightDistance", 250.0, "Max 3D distance from PV to candidate decay vertex (cm)"}; + Configurable candMaxPhotonOpeningAngle{"candMaxPhotonOpeningAngle", 3.15, "Max photon opening angle (rad), recomputed from the daughters' raw track momenta"}; + Configurable candMaxPhotonPointingAngle{"candMaxPhotonPointingAngle", 0.5, "Max angle between the photon's fitted momentum and the decay-vertex-to-conversion-point line (rad)"}; + Configurable candMaxPhotonDcaToPV{"candMaxPhotonDcaToPV", 250.0, "Max DCA of the photon's flight line to the PV (cm)"}; // missing-photon discriminant retry // resolution-shaped function and tuned parameters from Run 2 used @@ -93,13 +124,17 @@ struct Sigmaplusbuilder { Configurable discrRetryPhiPar0{"discrRetryPhiPar0", 0.000129845, "par0 of the delta-phi resolution function"}; Configurable discrRetryPhiPar1{"discrRetryPhiPar1", 0.00199688, "par1 of the delta-phi resolution function"}; + Configurable fillSlimTables{"fillSlimTables", false, "write the slim candidate tables instead of the full ones"}; + Configurable ccdbPath{"ccdbPath", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; Configurable grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; Produces sigmaPlusCands; Produces sigmaPlusCandsMC; + Produces slimSigmaPlusCands; + Produces slimSigmaPlusCandsMC; - Service ccdb; + Service ccdb{}; o2::vertexing::DCAFitterN<2> fitter; int mRunNumber = 0; float mBz = 0; @@ -123,6 +158,7 @@ struct Sigmaplusbuilder { fitter.setMinParamChange(1e-3); fitter.setMinRelChi2Change(0.9); fitter.setMaxDZIni(1e9); + fitter.setMaxDXYIni(1e9); fitter.setMaxChi2(1e9); fitter.setUseAbsDCA(true); @@ -133,116 +169,195 @@ struct Sigmaplusbuilder { const AxisSpec axisVertexZ{100, -15., 15., "vrtx_{Z} (cm)"}; - const AxisSpec axisPhotonSel{11, -0.5, 10.5, "selection step"}; + const AxisSpec axisPhotonSel{14, -0.5, 13.5, "selection step"}; const AxisSpec axisPhotonMass{200, 0., 0.3, "m_{#gamma} (GeV/c^{2})"}; const AxisSpec axisPhotonPt{100, 0., 5., "#it{p}_{T,#gamma} (GeV/c)"}; const AxisSpec axisPhotonRadius{200, 0., 200., "R_{conv} (cm)"}; const AxisSpec axisAlpha{100, -1., 1., "#alpha_{AP}"}; const AxisSpec axisQt{100, 0., 0.3, "q_{T,AP} (GeV/c)"}; const AxisSpec axisConvXY{200, -100., 100., "conv. point (cm)"}; + const AxisSpec axisNSigmaEl{100, -10., 10., "n#sigma_{el}"}; + const AxisSpec axisTpcNCls{160, -0.5, 159.5, "TPC clusters"}; + const AxisSpec axisPhotonOpeningAngle{180, 0., 3.15, "opening angle (rad)"}; + const AxisSpec axisPhotonDeltaTheta{200, -1., 1., "#Delta#theta (rad)"}; - const AxisSpec axisProtonSel{5, -0.5, 4.5, "selection step"}; + const AxisSpec axisProtonSel{7, -0.5, 6.5, "selection step"}; const AxisSpec axisProtonPt{100, 0., 5., "#it{p}_{T,p} (GeV/c)"}; const AxisSpec axisNSigma{100, -5., 5., "n#sigma"}; + const AxisSpec axisProtonDcaToPV{1000, 0., 5., "DCA_{xy,p} to PV (cm)"}; histos.add("hVertexZ", "hVertexZ", kTH1F, {axisVertexZ}); histos.add("Photon/hSelectionCounter", "Photon/hSelectionCounter", kTH1F, {axisPhotonSel}); auto hPhotonSel = histos.get(HIST("Photon/hSelectionCounter")); hPhotonSel->GetXaxis()->SetBinLabel(1, "All"); - hPhotonSel->GetXaxis()->SetBinLabel(2, "Mass"); - hPhotonSel->GetXaxis()->SetBinLabel(3, "Rapidity"); - hPhotonSel->GetXaxis()->SetBinLabel(4, "Neg eta"); - hPhotonSel->GetXaxis()->SetBinLabel(5, "Pos eta"); + hPhotonSel->GetXaxis()->SetBinLabel(2, "Neg eta"); + hPhotonSel->GetXaxis()->SetBinLabel(3, "Pos eta"); + hPhotonSel->GetXaxis()->SetBinLabel(4, "TPC clusters"); + hPhotonSel->GetXaxis()->SetBinLabel(5, "TPC nSigma_{el}"); hPhotonSel->GetXaxis()->SetBinLabel(6, "DCA daughters"); hPhotonSel->GetXaxis()->SetBinLabel(7, "Radius"); - hPhotonSel->GetXaxis()->SetBinLabel(8, "CosPA"); - hPhotonSel->GetXaxis()->SetBinLabel(9, "Qt"); - hPhotonSel->GetXaxis()->SetBinLabel(10, "Alpha"); - hPhotonSel->GetXaxis()->SetBinLabel(11, "TPC nSigma el"); + hPhotonSel->GetXaxis()->SetBinLabel(8, "Opening angle"); + hPhotonSel->GetXaxis()->SetBinLabel(9, "Delta theta"); + hPhotonSel->GetXaxis()->SetBinLabel(10, "CosPA"); + hPhotonSel->GetXaxis()->SetBinLabel(11, "Rapidity"); + hPhotonSel->GetXaxis()->SetBinLabel(12, "Qt"); + hPhotonSel->GetXaxis()->SetBinLabel(13, "Alpha"); + hPhotonSel->GetXaxis()->SetBinLabel(14, "Mass"); histos.add("Photon/hMass", "Photon/hMass", kTH1F, {axisPhotonMass}); histos.add("Photon/hPt", "Photon/hPt", kTH1F, {axisPhotonPt}); histos.add("Photon/hRadius", "Photon/hRadius", kTH1F, {axisPhotonRadius}); histos.add("Photon/h2ArmenterosPodolanski", "Photon/h2ArmenterosPodolanski", kTH2F, {axisAlpha, axisQt}); histos.add("Photon/h2ConvPointXY", "Photon/h2ConvPointXY", kTH2F, {axisConvXY, axisConvXY}); + histos.add("Photon/h2TPCNSigmaElPosVsPt", "Photon/h2TPCNSigmaElPosVsPt", kTH2F, {axisPhotonPt, axisNSigmaEl}); + histos.add("Photon/h2TPCNSigmaElNegVsPt", "Photon/h2TPCNSigmaElNegVsPt", kTH2F, {axisPhotonPt, axisNSigmaEl}); + histos.add("Photon/h2TPCNClsPosVsPt", "Photon/h2TPCNClsPosVsPt", kTH2F, {axisPhotonPt, axisTpcNCls}); + histos.add("Photon/h2TPCNClsNegVsPt", "Photon/h2TPCNClsNegVsPt", kTH2F, {axisPhotonPt, axisTpcNCls}); + histos.add("Photon/hOpeningAngle", "Photon/hOpeningAngle", kTH1F, {axisPhotonOpeningAngle}); + histos.add("Photon/hDeltaTheta", "Photon/hDeltaTheta", kTH1F, {axisPhotonDeltaTheta}); histos.add("Proton/hSelectionCounter", "Proton/hSelectionCounter", kTH1F, {axisProtonSel}); auto hProtonSel = histos.get(HIST("Proton/hSelectionCounter")); hProtonSel->GetXaxis()->SetBinLabel(1, "All"); hProtonSel->GetXaxis()->SetBinLabel(2, "Pt"); hProtonSel->GetXaxis()->SetBinLabel(3, "Eta"); - hProtonSel->GetXaxis()->SetBinLabel(4, "TPC nSigma"); - hProtonSel->GetXaxis()->SetBinLabel(5, "TOF nSigma"); + hProtonSel->GetXaxis()->SetBinLabel(4, "TPC clusters"); + hProtonSel->GetXaxis()->SetBinLabel(5, "TPC nSigma"); + hProtonSel->GetXaxis()->SetBinLabel(6, "TOF nSigma"); + hProtonSel->GetXaxis()->SetBinLabel(7, "DCA to PV"); histos.add("Proton/hPt", "Proton/hPt", kTH1F, {axisProtonPt}); histos.add("Proton/h2TPCNSigmaVsPt", "Proton/h2TPCNSigmaVsPt", kTH2F, {axisProtonPt, axisNSigma}); histos.add("Proton/h2TOFNSigmaVsPt", "Proton/h2TOFNSigmaVsPt", kTH2F, {axisProtonPt, axisNSigma}); + histos.add("Proton/h2TPCNClsVsPt", "Proton/h2TPCNClsVsPt", kTH2F, {axisProtonPt, axisTpcNCls}); + histos.add("Proton/h2DcaToPVVsPt", "Proton/h2DcaToPVVsPt", kTH2F, {axisProtonPt, axisProtonDcaToPV}); - const AxisSpec axisCandSel{7, -0.5, 6.5, "selection step"}; + const AxisSpec axisCandSel{15, -0.5, 14.5, "selection step"}; + const AxisSpec axisCandPhotonDcaToPV{250, 0., 250., "DCA_{#gamma-line} to PV (cm)"}; const AxisSpec axisDca{100, 0., 10., "DCA(p,#gamma) (cm)"}; + const AxisSpec axisDcaToPV{500, 0., 0.5, "DCA_{cand} to PV (cm)"}; const AxisSpec axisCandRadius{200, 0., 200., "R_{dec} (cm)"}; + const AxisSpec axisFlightDistance{250, 0., 250., "|SV-PV| (cm)"}; const AxisSpec axisDiscriminant{200, -1., 1., "discriminant (GeV^{4}/#it{c}^{4})"}; + const AxisSpec axisRootCenter{400, -10., 10., "-b/(2a) (GeV/#it{c})"}; + const AxisSpec axisAntiSigmaPA{180, 0., 3.15, "AntiPA (rad)"}; const AxisSpec axisMassSigma{200, 1.0, 1.4, "m_{p#gamma#gamma} (GeV/#it{c}^{2})"}; + const AxisSpec axisRapidity{200, -2., 2., "y_{#Sigma^{+}}"}; const AxisSpec axisSigmaPt{100, 0., 6., "#it{p}_{T,#Sigma^{+}} (GeV/#it{c})"}; const AxisSpec axisMomentum{100, 0., 10., "#it{p} (GeV/#it{c})"}; histos.add("Candidate/hSelectionCounter", "Candidate/hSelectionCounter", kTH1F, {axisCandSel}); auto hCandSel = histos.get(HIST("Candidate/hSelectionCounter")); hCandSel->GetXaxis()->SetBinLabel(1, "All pairs"); - hCandSel->GetXaxis()->SetBinLabel(2, "Vertex fit"); - hCandSel->GetXaxis()->SetBinLabel(3, "DCA(p,#gamma)"); - hCandSel->GetXaxis()->SetBinLabel(4, "Radius"); - hCandSel->GetXaxis()->SetBinLabel(5, "Real root"); - hCandSel->GetXaxis()->SetBinLabel(6, "Valid root"); - hCandSel->GetXaxis()->SetBinLabel(7, "Filled"); + hCandSel->GetXaxis()->SetBinLabel(2, "Autocorrelation"); + hCandSel->GetXaxis()->SetBinLabel(3, "Vertex fit"); + hCandSel->GetXaxis()->SetBinLabel(4, "DCA(p,#gamma)"); + hCandSel->GetXaxis()->SetBinLabel(5, "Radius"); + hCandSel->GetXaxis()->SetBinLabel(6, "Flight distance"); + hCandSel->GetXaxis()->SetBinLabel(7, "Real root"); + hCandSel->GetXaxis()->SetBinLabel(8, "Valid root"); + hCandSel->GetXaxis()->SetBinLabel(9, "DCA to PV"); + hCandSel->GetXaxis()->SetBinLabel(10, "Mass"); + hCandSel->GetXaxis()->SetBinLabel(11, "Rapidity"); + hCandSel->GetXaxis()->SetBinLabel(12, "Photon opening angle"); + hCandSel->GetXaxis()->SetBinLabel(13, "Photon pointing angle"); + hCandSel->GetXaxis()->SetBinLabel(14, "Photon DCA to PV"); + hCandSel->GetXaxis()->SetBinLabel(15, "Filled"); histos.add("Candidate/hDcaProtonGamma", "Candidate/hDcaProtonGamma", kTH1F, {axisDca}); + histos.add("Candidate/hDcaToPV", "Candidate/hDcaToPV", kTH1F, {axisDcaToPV}); histos.add("Candidate/hRadius", "Candidate/hRadius", kTH1F, {axisCandRadius}); + histos.add("Candidate/hFlightDistance", "Candidate/hFlightDistance", kTH1F, {axisFlightDistance}); + histos.add("Candidate/hPhotonOpeningAngle", "Candidate/hPhotonOpeningAngle", kTH1F, {axisPhotonOpeningAngle}); + histos.add("Candidate/hPhotonPointingAngle", "Candidate/hPhotonPointingAngle", kTH1F, {axisPhotonOpeningAngle}); + histos.add("Candidate/hPhotonDcaToPV", "Candidate/hPhotonDcaToPV", kTH1F, {axisCandPhotonDcaToPV}); histos.add("Candidate/hDiscriminant", "Candidate/hDiscriminant", kTH1F, {axisDiscriminant}); + histos.add("Candidate/hRootCenter", "Candidate/hRootCenter", kTH1F, {axisRootCenter}); histos.add("Candidate/hMassSigmaPlus", "Candidate/hMassSigmaPlus", kTH1F, {axisMassSigma}); + histos.add("Candidate/hRapidity", "Candidate/hRapidity", kTH1F, {axisRapidity}); histos.add("Candidate/h2MassVsPt", "Candidate/h2MassVsPt", kTH2F, {axisSigmaPt, axisMassSigma}); + histos.add("Candidate/h2MassVsRootCenter", "Candidate/h2MassVsRootCenter", kTH2F, {axisRootCenter, axisMassSigma}); + histos.add("Candidate/hAntiSigmaPointingAngle", "Candidate/hAntiSigmaPointingAngle", kTH1F, {axisAntiSigmaPA}); + histos.add("Candidate/h2MassVsAntiSigmaPointingAngle", "Candidate/h2MassVsAntiSigmaPointingAngle", kTH2F, {axisAntiSigmaPA, axisMassSigma}); const AxisSpec axisDiscrIter{discrRetryMaxIter + 2, -0.5, discrRetryMaxIter + 1.5, "discriminant retry iteration"}; histos.add("Candidate/hDiscriminantRetryIter", "Candidate/hDiscriminantRetryIter", kTH1F, {axisDiscrIter}); - if (doprocessMc) { + if (doprocessMc || doprocessFindable) { histos.add("Photon/True/hSelectionCounter", "Photon/True/hSelectionCounter", kTH1F, {axisPhotonSel}); auto hPhotonSelSignal = histos.get(HIST("Photon/True/hSelectionCounter")); hPhotonSelSignal->GetXaxis()->SetBinLabel(1, "All"); - hPhotonSelSignal->GetXaxis()->SetBinLabel(2, "Mass"); - hPhotonSelSignal->GetXaxis()->SetBinLabel(3, "Rapidity"); - hPhotonSelSignal->GetXaxis()->SetBinLabel(4, "Neg eta"); - hPhotonSelSignal->GetXaxis()->SetBinLabel(5, "Pos eta"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(2, "Neg eta"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(3, "Pos eta"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(4, "TPC clusters"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(5, "TPC nSigma_{el}"); hPhotonSelSignal->GetXaxis()->SetBinLabel(6, "DCA daughters"); hPhotonSelSignal->GetXaxis()->SetBinLabel(7, "Radius"); - hPhotonSelSignal->GetXaxis()->SetBinLabel(8, "CosPA"); - hPhotonSelSignal->GetXaxis()->SetBinLabel(9, "Qt"); - hPhotonSelSignal->GetXaxis()->SetBinLabel(10, "Alpha"); - hPhotonSelSignal->GetXaxis()->SetBinLabel(11, "TPC nSigma el"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(8, "Opening angle"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(9, "Delta theta"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(10, "CosPA"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(11, "Rapidity"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(12, "Qt"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(13, "Alpha"); + hPhotonSelSignal->GetXaxis()->SetBinLabel(14, "Mass"); + + histos.add("Photon/True/h2TPCNSigmaElPosVsPt", "Photon/True/h2TPCNSigmaElPosVsPt", kTH2F, {axisPhotonPt, axisNSigmaEl}); + histos.add("Photon/True/h2TPCNSigmaElNegVsPt", "Photon/True/h2TPCNSigmaElNegVsPt", kTH2F, {axisPhotonPt, axisNSigmaEl}); + histos.add("Photon/True/h2TPCNClsPosVsPt", "Photon/True/h2TPCNClsPosVsPt", kTH2F, {axisPhotonPt, axisTpcNCls}); + histos.add("Photon/True/h2TPCNClsNegVsPt", "Photon/True/h2TPCNClsNegVsPt", kTH2F, {axisPhotonPt, axisTpcNCls}); + } + if (doprocessMc) { histos.add("Photon/True/hMass", "Photon/True/hMass", kTH1F, {axisPhotonMass}); histos.add("Photon/True/hPt", "Photon/True/hPt", kTH1F, {axisPhotonPt}); histos.add("Photon/True/hRadius", "Photon/True/hRadius", kTH1F, {axisPhotonRadius}); histos.add("Photon/True/h2ArmenterosPodolanski", "Photon/True/h2ArmenterosPodolanski", kTH2F, {axisAlpha, axisQt}); histos.add("Photon/True/h2ConvPointXY", "Photon/True/h2ConvPointXY", kTH2F, {axisConvXY, axisConvXY}); + histos.add("Photon/True/hOpeningAngle", "Photon/True/hOpeningAngle", kTH1F, {axisPhotonOpeningAngle}); + histos.add("Photon/True/hDeltaTheta", "Photon/True/hDeltaTheta", kTH1F, {axisPhotonDeltaTheta}); histos.add("Proton/True/hPt", "Proton/True/hPt", kTH1F, {axisProtonPt}); histos.add("Proton/True/h2TPCNSigmaVsPt", "Proton/True/h2TPCNSigmaVsPt", kTH2F, {axisProtonPt, axisNSigma}); histos.add("Proton/True/h2TOFNSigmaVsPt", "Proton/True/h2TOFNSigmaVsPt", kTH2F, {axisProtonPt, axisNSigma}); + histos.add("Proton/True/h2TPCNClsVsPt", "Proton/True/h2TPCNClsVsPt", kTH2F, {axisProtonPt, axisTpcNCls}); + histos.add("Proton/True/h2DcaToPVVsPt", "Proton/True/h2DcaToPVVsPt", kTH2F, {axisProtonPt, axisProtonDcaToPV}); + + histos.add("Proton/True/hSelectionCounter", "Proton/True/hSelectionCounter", kTH1F, {axisProtonSel}); + auto hProtonSelSignal = histos.get(HIST("Proton/True/hSelectionCounter")); + hProtonSelSignal->GetXaxis()->SetBinLabel(1, "All"); + hProtonSelSignal->GetXaxis()->SetBinLabel(2, "Pt"); + hProtonSelSignal->GetXaxis()->SetBinLabel(3, "Eta"); + hProtonSelSignal->GetXaxis()->SetBinLabel(4, "TPC clusters"); + hProtonSelSignal->GetXaxis()->SetBinLabel(5, "TPC nSigma"); + hProtonSelSignal->GetXaxis()->SetBinLabel(6, "TOF nSigma"); + hProtonSelSignal->GetXaxis()->SetBinLabel(7, "DCA to PV"); histos.add("Candidate/True/hSelectionCounter", "Candidate/True/hSelectionCounter", kTH1F, {axisCandSel}); auto hCandSelSignal = histos.get(HIST("Candidate/True/hSelectionCounter")); hCandSelSignal->GetXaxis()->SetBinLabel(1, "All pairs"); - hCandSelSignal->GetXaxis()->SetBinLabel(2, "Vertex fit"); - hCandSelSignal->GetXaxis()->SetBinLabel(3, "DCA(p,#gamma)"); - hCandSelSignal->GetXaxis()->SetBinLabel(4, "Radius"); - hCandSelSignal->GetXaxis()->SetBinLabel(5, "Real root"); - hCandSelSignal->GetXaxis()->SetBinLabel(6, "Valid root"); - hCandSelSignal->GetXaxis()->SetBinLabel(7, "Filled"); + hCandSelSignal->GetXaxis()->SetBinLabel(2, "Autocorrelation"); + hCandSelSignal->GetXaxis()->SetBinLabel(3, "Vertex fit"); + hCandSelSignal->GetXaxis()->SetBinLabel(4, "DCA(p,#gamma)"); + hCandSelSignal->GetXaxis()->SetBinLabel(5, "Radius"); + hCandSelSignal->GetXaxis()->SetBinLabel(6, "Flight distance"); + hCandSelSignal->GetXaxis()->SetBinLabel(7, "Real root"); + hCandSelSignal->GetXaxis()->SetBinLabel(8, "Valid root"); + hCandSelSignal->GetXaxis()->SetBinLabel(9, "DCA to PV"); + hCandSelSignal->GetXaxis()->SetBinLabel(10, "Mass"); + hCandSelSignal->GetXaxis()->SetBinLabel(11, "Rapidity"); + hCandSelSignal->GetXaxis()->SetBinLabel(12, "Photon opening angle"); + hCandSelSignal->GetXaxis()->SetBinLabel(13, "Photon pointing angle"); + hCandSelSignal->GetXaxis()->SetBinLabel(14, "Photon DCA to PV"); + hCandSelSignal->GetXaxis()->SetBinLabel(15, "Filled"); histos.add("Candidate/True/hDcaProtonGamma", "Candidate/True/hDcaProtonGamma", kTH1F, {axisDca}); + histos.add("Candidate/True/hDcaToPV", "Candidate/True/hDcaToPV", kTH1F, {axisDcaToPV}); histos.add("Candidate/True/hRadius", "Candidate/True/hRadius", kTH1F, {axisCandRadius}); + histos.add("Candidate/True/hFlightDistance", "Candidate/True/hFlightDistance", kTH1F, {axisFlightDistance}); + histos.add("Candidate/True/hPhotonOpeningAngle", "Candidate/True/hPhotonOpeningAngle", kTH1F, {axisPhotonOpeningAngle}); + histos.add("Candidate/True/hPhotonPointingAngle", "Candidate/True/hPhotonPointingAngle", kTH1F, {axisPhotonOpeningAngle}); + histos.add("Candidate/True/hPhotonDcaToPV", "Candidate/True/hPhotonDcaToPV", kTH1F, {axisCandPhotonDcaToPV}); const AxisSpec axisVtxRes{200, 0., 20., "|vtx_{fit} - vtx_{MC}| (cm)"}; histos.add("Candidate/True/hVertexResFromMcTruth", "Candidate/True/hVertexResFromMcTruth", kTH1F, {axisVtxRes}); const AxisSpec axisMomRes{200, -1., 1., "(p_{fit} - p_{MC}) / p_{MC}"}; @@ -252,8 +367,13 @@ struct Sigmaplusbuilder { histos.add("Candidate/True/hProtonFlightAngle", "Candidate/True/hProtonFlightAngle", kTH1F, {axisProtonFlightAngle}); histos.add("Candidate/True/hDiscriminant", "Candidate/True/hDiscriminant", kTH1F, {axisDiscriminant}); histos.add("Candidate/True/hDiscriminantRetryIter", "Candidate/True/hDiscriminantRetryIter", kTH1F, {axisDiscrIter}); + histos.add("Candidate/True/hRootCenter", "Candidate/True/hRootCenter", kTH1F, {axisRootCenter}); histos.add("Candidate/True/hMassSigmaPlus", "Candidate/True/hMassSigmaPlus", kTH1F, {axisMassSigma}); + histos.add("Candidate/True/hRapidity", "Candidate/True/hRapidity", kTH1F, {axisRapidity}); histos.add("Candidate/True/h2MassVsPt", "Candidate/True/h2MassVsPt", kTH2F, {axisSigmaPt, axisMassSigma}); + histos.add("Candidate/True/h2MassVsRootCenter", "Candidate/True/h2MassVsRootCenter", kTH2F, {axisRootCenter, axisMassSigma}); + histos.add("Candidate/True/hAntiSigmaPointingAngle", "Candidate/True/hAntiSigmaPointingAngle", kTH1F, {axisAntiSigmaPA}); + histos.add("Candidate/True/h2MassVsAntiSigmaPointingAngle", "Candidate/True/h2MassVsAntiSigmaPointingAngle", kTH2F, {axisAntiSigmaPA, axisMassSigma}); histos.add("MC/hGenSigmaPlusPt", "MC/hGenSigmaPlusPt", kTH1F, {axisSigmaPt}); @@ -277,11 +397,11 @@ struct Sigmaplusbuilder { if (doprocessFindable) { const AxisSpec axisDetectorPresence{3, -0.5, 2.5, "detector"}; const AxisSpec axisDuplicateTrack{2, -0.5, 1.5, "track"}; - const AxisSpec axisV0Presence{2, -0.5, 1.5, "V0 match"}; const AxisSpec axisTPCClusters{160, -0.5, 159.5, "TPC clusters"}; const AxisSpec axisPhotonMomResolution{200, -1., 1., "(#it{p}_{reco,#gamma} - #it{p}_{MC,#gamma})/#it{p}_{MC,#gamma}"}; const AxisSpec axisPhotonCosPA{200, -1., 1., "cosPA_{#gamma}"}; const AxisSpec axisPairMass{200, 0., 0.1, "m_{e^{+}e^{-}} (GeV/#it{c}^{2})"}; + const AxisSpec axisV0Presence{2, -0.5, 1.5, "V0 match"}; histos.add("Findable/hSigmaPlusPt", "Findable/hSigmaPlusPt", kTH1F, {axisSigmaPt}); histos.add("Findable/h2ProtonPtVsSigmaPlusPt", "Findable/h2ProtonPtVsSigmaPlusPt", kTH2F, {axisSigmaPt, axisMomentum}); histos.add("Findable/hElectronPt", "Findable/hElectronPt", kTH1F, {axisMomentum}); @@ -291,14 +411,19 @@ struct Sigmaplusbuilder { histos.add("Findable/hPhotonMomentumResolution", "Findable/hPhotonMomentumResolution", kTH1F, {axisPhotonMomResolution}); histos.add("Findable/hPhotonCosPA", "Findable/hPhotonCosPA", kTH1F, {axisPhotonCosPA}); histos.add("Findable/hConversionPairV0Presence", "Findable/hConversionPairV0Presence", kTH1F, {axisV0Presence}); + histos.add("Findable/hPhotonSearchPresence", "Findable/hPhotonSearchPresence", kTH1F, {axisV0Presence}); histos.add("Findable/hDuplicateConversionTrackCounter", "Findable/hDuplicateConversionTrackCounter", kTH1F, {axisDuplicateTrack}); histos.add("Findable/hDuplicateElectronTPCNClsFound", "Findable/hDuplicateElectronTPCNClsFound", kTH1F, {axisTPCClusters}); histos.add("Findable/hDuplicatePositronTPCNClsFound", "Findable/hDuplicatePositronTPCNClsFound", kTH1F, {axisTPCClusters}); histos.add("Findable/hElectronDetectorPresence", "Findable/hElectronDetectorPresence", kTH1F, {axisDetectorPresence}); histos.add("Findable/hPositronDetectorPresence", "Findable/hPositronDetectorPresence", kTH1F, {axisDetectorPresence}); + auto hConversionPairV0Presence = histos.get(HIST("Findable/hConversionPairV0Presence")); hConversionPairV0Presence->GetXaxis()->SetBinLabel(1, "valid pair"); hConversionPairV0Presence->GetXaxis()->SetBinLabel(2, "in V0"); + auto hPhotonSearchPresence = histos.get(HIST("Findable/hPhotonSearchPresence")); + hPhotonSearchPresence->GetXaxis()->SetBinLabel(1, "valid pair"); + hPhotonSearchPresence->GetXaxis()->SetBinLabel(2, "passed photon selection"); auto hDuplicateConversionTrackCounter = histos.get(HIST("Findable/hDuplicateConversionTrackCounter")); hDuplicateConversionTrackCounter->GetXaxis()->SetBinLabel(1, "e^{-}"); hDuplicateConversionTrackCounter->GetXaxis()->SetBinLabel(2, "e^{+}"); @@ -313,125 +438,261 @@ struct Sigmaplusbuilder { } } - // photon (PCM) candidate selection - template - bool selectPhoton(const TV0& v0) + // photon (electron/positron conversion pair) candidate + template + struct PhotonCand { + float x = 0.f, y = 0.f, z = 0.f; + float px = 0.f, py = 0.f, pz = 0.f; + float mGamma = 0.f; + float alpha = 0.f; + float qtarm = 0.f; + float radius = 0.f; + TTrack negTrack; + TTrack posTrack; + }; + + // photon candidates + template + std::vector> findPhotonsFromV0s(const TV0s& v0s, const TTracks&, const std::array& pv) { - auto posTrack = v0.template posTrack_as(); - auto negTrack = v0.template negTrack_as(); + std::vector> photons; - bool isSignal = false; - if constexpr (IsMC) { - if (posTrack.has_mcParticle() && negTrack.has_mcParticle()) { - auto mcPos = posTrack.template mcParticle_as(); - auto mcNeg = negTrack.template mcParticle_as(); - isSignal = findSigmaPlusMotherOfPhoton(mcPos, mcNeg) >= 0; + for (const auto& v0 : v0s) { + auto posTrack = v0.template posTrack_as(); + auto negTrack = v0.template negTrack_as(); + + bool isSignal = false; + if constexpr (IsMC) { + if (posTrack.has_mcParticle() && negTrack.has_mcParticle()) { + auto mcPos = posTrack.template mcParticle_as(); + auto mcNeg = negTrack.template mcParticle_as(); + isSignal = findSigmaPlusMotherOfPhoton(mcPos, mcNeg) >= 0; + } } - } - auto fillPhotonStep = [&](int step) { - histos.fill(HIST("Photon/hSelectionCounter"), step); + auto fillPhotonStep = [&](int step) { + histos.fill(HIST("Photon/hSelectionCounter"), step); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Photon/True/hSelectionCounter"), step); + } + } + }; + fillPhotonStep(0); + + if (negTrack.eta() < photonDauEtaMin || negTrack.eta() > photonDauEtaMax) { + continue; + } + fillPhotonStep(1); + + if (posTrack.eta() < photonDauEtaMin || posTrack.eta() > photonDauEtaMax) { + continue; + } + fillPhotonStep(2); + + histos.fill(HIST("Photon/h2TPCNClsPosVsPt"), posTrack.pt(), posTrack.tpcNClsFound()); + histos.fill(HIST("Photon/h2TPCNClsNegVsPt"), negTrack.pt(), negTrack.tpcNClsFound()); if constexpr (IsMC) { if (isSignal) { - histos.fill(HIST("Photon/True/hSelectionCounter"), step); + histos.fill(HIST("Photon/True/h2TPCNClsPosVsPt"), posTrack.pt(), posTrack.tpcNClsFound()); + histos.fill(HIST("Photon/True/h2TPCNClsNegVsPt"), negTrack.pt(), negTrack.tpcNClsFound()); } } - }; - fillPhotonStep(0); + if (posTrack.tpcNClsFound() < photonDauMinTpcNCls || negTrack.tpcNClsFound() < photonDauMinTpcNCls) { + continue; + } + fillPhotonStep(3); - if (v0.mGamma() < 0 || v0.mGamma() > photonMaxMass) { - return false; - } - fillPhotonStep(1); + histos.fill(HIST("Photon/h2TPCNSigmaElPosVsPt"), posTrack.pt(), posTrack.tpcNSigmaEl()); + histos.fill(HIST("Photon/h2TPCNSigmaElNegVsPt"), negTrack.pt(), negTrack.tpcNSigmaEl()); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Photon/True/h2TPCNSigmaElPosVsPt"), posTrack.pt(), posTrack.tpcNSigmaEl()); + histos.fill(HIST("Photon/True/h2TPCNSigmaElNegVsPt"), negTrack.pt(), negTrack.tpcNSigmaEl()); + } + } + if (posTrack.tpcNSigmaEl() < photonDauMinTPCNSigmaEl || posTrack.tpcNSigmaEl() > photonDauMaxTPCNSigmaEl || + negTrack.tpcNSigmaEl() < photonDauMinTPCNSigmaEl || negTrack.tpcNSigmaEl() > photonDauMaxTPCNSigmaEl) { + continue; + } + fillPhotonStep(4); - float photonY = RecoDecay::y(std::array{v0.px(), v0.py(), v0.pz()}, o2::constants::physics::MassGamma); - if (photonY < photonMinRapidity || photonY > photonMaxRapidity) { - return false; - } - fillPhotonStep(2); + if (v0.dcaV0daughters() > photonMaxDCAV0Dau) { + continue; + } + fillPhotonStep(5); - if (v0.negativeeta() < photonDauEtaMin || v0.negativeeta() > photonDauEtaMax) { - return false; - } - fillPhotonStep(3); + std::array secVtx{v0.x(), v0.y(), v0.z()}; + float radius = v0.v0radius(); + if (radius < photonMinRadius || radius > photonMaxRadius) { + continue; + } + fillPhotonStep(6); - if (v0.positiveeta() < photonDauEtaMin || v0.positiveeta() > photonDauEtaMax) { - return false; - } - fillPhotonStep(4); + std::array pNeg{v0.pxneg(), v0.pyneg(), v0.pzneg()}; + std::array pPos{v0.pxpos(), v0.pypos(), v0.pzpos()}; - if (std::abs(v0.dcaV0daughters()) > photonMaxDCAV0Dau) { - return false; - } - fillPhotonStep(5); + // opening angle between the daughter momenta + float photonOpeningAngleV0 = std::acos(std::clamp(dot3(pPos, pNeg) / std::sqrt(dot3(pPos, pPos) * dot3(pNeg, pNeg)), -1.f, 1.f)); + histos.fill(HIST("Photon/hOpeningAngle"), photonOpeningAngleV0); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Photon/True/hOpeningAngle"), photonOpeningAngleV0); + } + } + if (photonOpeningAngleV0 > photonMaxOpeningAngle) { + continue; + } + fillPhotonStep(7); - if (v0.v0radius() < photonMinRadius || v0.v0radius() > photonMaxRadius) { - return false; - } - fillPhotonStep(6); + // delta theta between the daughter tracks' own polar angles + float posTheta = 2.f * std::atan(std::exp(-posTrack.eta())); + float negTheta = 2.f * std::atan(std::exp(-negTrack.eta())); + float photonDeltaTheta = posTheta - negTheta; + histos.fill(HIST("Photon/hDeltaTheta"), photonDeltaTheta); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Photon/True/hDeltaTheta"), photonDeltaTheta); + } + } + if (std::abs(photonDeltaTheta) > photonMaxDeltaTheta) { + continue; + } + fillPhotonStep(8); - if (v0.v0cosPA() < photonMinV0cospa) { - return false; - } - fillPhotonStep(7); + std::array pGamma{pNeg[0] + pPos[0], pNeg[1] + pPos[1], pNeg[2] + pPos[2]}; + float gammaP = std::sqrt(dot3(pGamma, pGamma)); - if (v0.qtarm() > photonMaxQt) { - return false; - } - fillPhotonStep(8); + std::array flightVec{secVtx[0] - pv[0], secVtx[1] - pv[1], secVtx[2] - pv[2]}; + float flightNorm = std::sqrt(dot3(flightVec, flightVec)); + float cosPA = dot3(flightVec, pGamma) / (flightNorm * gammaP); + if (cosPA < photonMinV0cospa) { + continue; + } + fillPhotonStep(9); - if (std::abs(v0.alpha()) > photonMaxAlpha) { - return false; - } - fillPhotonStep(9); + float photonY = RecoDecay::y(pGamma, o2::constants::physics::MassGamma); + if (photonY < photonMinRapidity || photonY > photonMaxRapidity) { + continue; + } + fillPhotonStep(10); - if (std::abs(posTrack.tpcNSigmaEl()) > photonMaxTPCNSigmaEl || std::abs(negTrack.tpcNSigmaEl()) > photonMaxTPCNSigmaEl) { - return false; - } - fillPhotonStep(10); + float qtarm = v0.qtarm(); + float alpha = v0.alpha(); + if (qtarm > photonMaxQt) { + continue; + } + fillPhotonStep(11); - histos.fill(HIST("Photon/hMass"), v0.mGamma()); - histos.fill(HIST("Photon/hPt"), v0.pt()); - histos.fill(HIST("Photon/hRadius"), v0.v0radius()); - histos.fill(HIST("Photon/h2ArmenterosPodolanski"), v0.alpha(), v0.qtarm()); - histos.fill(HIST("Photon/h2ConvPointXY"), v0.x(), v0.y()); + if (std::abs(alpha) > photonMaxAlpha) { + continue; + } + fillPhotonStep(12); - return true; + float mGamma = v0.mGamma(); + if (mGamma > photonMaxMass) { + continue; + } + fillPhotonStep(13); + + histos.fill(HIST("Photon/hMass"), mGamma); + histos.fill(HIST("Photon/hPt"), std::hypot(pGamma[0], pGamma[1])); + histos.fill(HIST("Photon/hRadius"), radius); + histos.fill(HIST("Photon/h2ArmenterosPodolanski"), alpha, qtarm); + histos.fill(HIST("Photon/h2ConvPointXY"), secVtx[0], secVtx[1]); + + photons.push_back({secVtx[0], secVtx[1], secVtx[2], pGamma[0], pGamma[1], pGamma[2], mGamma, alpha, qtarm, radius, negTrack, posTrack}); + } + + return photons; } // proton candidate selection - template + template bool selectProton(const TTrack& track) { - histos.fill(HIST("Proton/hSelectionCounter"), 0); + bool isSignal = false; + if constexpr (IsMC) { + if (track.has_mcParticle()) { + auto mcProton = track.template mcParticle_as(); + isSignal = findSigmaPlusMotherOfProton(mcProton) >= 0; + } + } + auto fillProtonStep = [&](int step) { + histos.fill(HIST("Proton/hSelectionCounter"), step); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Proton/True/hSelectionCounter"), step); + } + } + }; + fillProtonStep(0); if (track.pt() < protonMinPt) { return false; } - histos.fill(HIST("Proton/hSelectionCounter"), 1); + fillProtonStep(1); if (std::abs(track.eta()) > protonMaxEta) { return false; } - histos.fill(HIST("Proton/hSelectionCounter"), 2); + fillProtonStep(2); + + histos.fill(HIST("Proton/h2TPCNClsVsPt"), track.pt(), track.tpcNClsFound()); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Proton/True/h2TPCNClsVsPt"), track.pt(), track.tpcNClsFound()); + } + } + if (track.tpcNClsFound() < protonMinTpcNCls) { + return false; + } + fillProtonStep(3); if (std::abs(track.tpcNSigmaPr()) > protonMaxTPCNSigma) { return false; } - histos.fill(HIST("Proton/hSelectionCounter"), 3); + fillProtonStep(4); + // A track with no TOF hit at all is tolerated even above protonPtMinRequireTOF - only an existing-but-failing + // TOF nSigma gets rejected. Set protonRequireTofHit=true to instead mandate a TOF hit above the threshold. if (track.pt() > protonPtMinRequireTOF) { - if (!track.hasTOF() || std::abs(track.tofNSigmaPr()) > protonMaxTOFNSigma) { + if (track.hasTOF()) { + if (std::abs(track.tofNSigmaPr()) > protonMaxTOFNSigma) { + return false; + } + } else if (protonRequireTofHit) { return false; } } - histos.fill(HIST("Proton/hSelectionCounter"), 4); + fillProtonStep(5); + + // proton DCA to PV + histos.fill(HIST("Proton/h2DcaToPVVsPt"), track.pt(), std::abs(track.dcaXY())); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Proton/True/h2DcaToPVVsPt"), track.pt(), std::abs(track.dcaXY())); + } + } + if (std::abs(track.dcaXY()) < protonMinDcaToPV || std::abs(track.dcaXY()) > protonMaxDcaToPV) { + return false; + } + fillProtonStep(6); histos.fill(HIST("Proton/hPt"), track.pt()); histos.fill(HIST("Proton/h2TPCNSigmaVsPt"), track.pt(), track.tpcNSigmaPr()); if (track.hasTOF()) { histos.fill(HIST("Proton/h2TOFNSigmaVsPt"), track.pt(), track.tofNSigmaPr()); } + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Proton/True/hPt"), track.pt()); + histos.fill(HIST("Proton/True/h2TPCNSigmaVsPt"), track.pt(), track.tpcNSigmaPr()); + if (track.hasTOF()) { + histos.fill(HIST("Proton/True/h2TOFNSigmaVsPt"), track.pt(), track.tofNSigmaPr()); + } + } + } return true; } @@ -562,29 +823,31 @@ struct Sigmaplusbuilder { } // Build a Sigma+ -> p pi0 candidate from a proton track and a PCM photon - template - void buildSigmaPlusCandidate(const TTrack& protonTrack, const TV0& photon, const std::array& pv) + // Returns the MC index of the matched true Sigma+ mother if a signal candidate was built, -1 otherwise + template + int buildSigmaPlusCandidate(const TTrack& protonTrack, const PhotonCand& photon, const std::array& pv) { - auto posTrack = photon.template posTrack_as(); - auto negTrack = photon.template negTrack_as(); + auto posTrack = photon.posTrack; + auto negTrack = photon.negTrack; bool isSignal = false; - std::array mcTrueVtx{}; // Sigma+ decay vertex - std::array mcTrueMomProton{}; // true MC proton momentum - std::array mcTrueMomGamma{}; // true MC momentum of the measured photon - int protonPdgCode = 0; - int protonMotherPdgCode = 0; - int gammaPdgCode = 0; - int gammaMotherPdgCode = 0; - int gammaGMotherPdgCode = 0; + bool collisionIdCheck = false; // MC only: true if the proton's true MC collision matches the reconstructed collision + std::array mcTrueVtx{}; // Sigma+ decay vertex + std::array mcTrueMomProton{}; // true MC proton momentum + std::array mcTrueMomGamma{}; // true MC momentum of the measured photon + std::array mcTrueMomSigmaPlus{}; // true MC momentum of the Sigma+ mother + float decayRadiusMC = -999.f; // MC-truth decay radius + float massMC = -999.f; // MC-truth Sigma+ mass + int matchedSigmaId = -1; if constexpr (IsMC) { if (protonTrack.has_mcParticle()) { auto mcProton = protonTrack.template mcParticle_as(); - protonPdgCode = mcProton.pdgCode(); - auto const& protonMothers = mcProton.template mothers_as(); - if (!protonMothers.empty()) { - protonMotherPdgCode = protonMothers.front().pdgCode(); + + auto protonCollision = protonTrack.template collision_as(); + if (protonCollision.has_mcCollision()) { + collisionIdCheck = protonCollision.mcCollision().globalIndex() == mcProton.mcCollisionId(); } + auto const& protonMothers = mcProton.template mothers_as(); int protonSigmaIdx = findSigmaPlusMotherOfProton(mcProton); @@ -595,19 +858,7 @@ struct Sigmaplusbuilder { auto const& posMothers = mcPos.template mothers_as(); if (!posMothers.empty()) { auto mcGamma = posMothers.front(); - gammaPdgCode = mcGamma.pdgCode(); mcTrueMomGamma = {mcGamma.px(), mcGamma.py(), mcGamma.pz()}; - - auto const& gammaMothers = mcGamma.template mothers_as(); - if (!gammaMothers.empty()) { - auto mcPi0 = gammaMothers.front(); - gammaMotherPdgCode = mcPi0.pdgCode(); - - auto const& pi0Mothers = mcPi0.template mothers_as(); - if (!pi0Mothers.empty()) { - gammaGMotherPdgCode = pi0Mothers.front().pdgCode(); - } - } } int photonSigmaIdx = findSigmaPlusMotherOfPhoton(mcPos, mcNeg); @@ -617,6 +868,11 @@ struct Sigmaplusbuilder { if (isSignal) { mcTrueVtx = {mcProton.vx(), mcProton.vy(), mcProton.vz()}; mcTrueMomProton = {mcProton.px(), mcProton.py(), mcProton.pz()}; + auto mcSigmaPlusMother = protonMothers.front(); + mcTrueMomSigmaPlus = {mcSigmaPlusMother.px(), mcSigmaPlusMother.py(), mcSigmaPlusMother.pz()}; + matchedSigmaId = mcSigmaPlusMother.globalIndex(); + decayRadiusMC = std::hypot(mcTrueVtx[0] - mcSigmaPlusMother.vx(), mcTrueVtx[1] - mcSigmaPlusMother.vy()); + massMC = std::sqrt(mcSigmaPlusMother.e() * mcSigmaPlusMother.e() - mcSigmaPlusMother.p() * mcSigmaPlusMother.p()); } } } @@ -631,10 +887,18 @@ struct Sigmaplusbuilder { }; fillCandStep(0); // all pairs + // Reject the pair if the proton track is one of the photon's own e+/e- daughter tracks. + if (protonTrack.globalIndex() == posTrack.globalIndex() || protonTrack.globalIndex() == negTrack.globalIndex()) { + return -1; + } + fillCandStep(1); // autocorrelation + auto protonTrackParCov = getTrackParCov(protonTrack); + std::array protonOrigPos{}; + protonTrackParCov.getXYZGlo(protonOrigPos); std::array zeroCov{}; - auto photonTrackParCov = o2::track::TrackParCov({photon.x(), photon.y(), photon.z()}, {photon.px(), photon.py(), photon.pz()}, zeroCov, 0, true); + auto photonTrackParCov = o2::track::TrackParCov({photon.x, photon.y, photon.z}, {photon.px, photon.py, photon.pz}, zeroCov, 0, true); photonTrackParCov.setAbsCharge(0); photonTrackParCov.setPID(o2::track::PID::Photon); @@ -642,12 +906,12 @@ struct Sigmaplusbuilder { try { nCand = fitter.process(protonTrackParCov, photonTrackParCov); } catch (...) { - return; + return -1; } if (nCand == 0 || !fitter.propagateTracksToVertex()) { - return; + return -1; } - fillCandStep(1); // Vertex fit + fillCandStep(2); // Vertex fit float fitChi2 = fitter.getChi2AtPCACandidate(); float dcaProtonGamma = std::sqrt(fitChi2); @@ -658,9 +922,9 @@ struct Sigmaplusbuilder { } } if (dcaProtonGamma > candMaxDcaProtonGamma) { - return; + return -1; } - fillCandStep(2); // DCA(p,gamma) + fillCandStep(3); // DCA(p,gamma) std::array secVtx = fitter.getPCACandidatePos(); float radius = std::hypot(secVtx[0], secVtx[1]); @@ -673,17 +937,28 @@ struct Sigmaplusbuilder { } } if (radius < candMinRadius || radius > candMaxRadius) { - return; + return -1; } - fillCandStep(3); // radius + fillCandStep(4); // radius // flight direction n and the decay-plane basis n, eIn, eOut std::array flightVec{secVtx[0] - pv[0], secVtx[1] - pv[1], secVtx[2] - pv[2]}; std::array nHat = normalize3(flightVec); float flightDistance = std::sqrt(dot3(flightVec, flightVec)); - std::array pProton; - std::array pGamma1; + histos.fill(HIST("Candidate/hFlightDistance"), flightDistance); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Candidate/True/hFlightDistance"), flightDistance); + } + } + if (flightDistance < candMinFlightDistance || flightDistance > candMaxFlightDistance) { + return -1; + } + fillCandStep(5); // flight distance + + std::array pProton{}; + std::array pGamma1{}; fitter.getTrack(0).getPxPyPzGlo(pProton); fitter.getTrack(1).getPxPyPzGlo(pGamma1); @@ -770,14 +1045,29 @@ struct Sigmaplusbuilder { } } if (discriminant < 0.f) { - return; + return -1; } - fillCandStep(4); // real root + fillCandStep(6); // real root // two roots from the quadratic, among both we keep the mass closest to the nominal Sigma+ mass float sqrtDisc = std::sqrt(discriminant); std::array roots{(-coefB + sqrtDisc) / (2.f * coefA), (-coefB - sqrtDisc) / (2.f * coefA)}; + // perturbation-free center of the two roots + float rootCenter = -coefB / (2.f * coefA); + histos.fill(HIST("Candidate/hRootCenter"), rootCenter); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Candidate/True/hRootCenter"), rootCenter); + } + } + if (candRejectNegRootCenter && rootCenter < 0.f) { + return -1; + } + if (rootCenter > candMaxRootCenter) { + return -1; + } + bool haveCandidate = false; float bestMass = -999.f; std::array bestMomGamma2{}; @@ -802,70 +1092,213 @@ struct Sigmaplusbuilder { } } if (!haveCandidate) { - return; + return -1; } - fillCandStep(5); // valid root + fillCandStep(7); // valid root std::array pSigma{pProton[0] + pGamma1[0] + bestMomGamma2[0], pProton[1] + pGamma1[1] + bestMomGamma2[1], pProton[2] + pGamma1[2] + bestMomGamma2[2]}; float ptSigma = std::hypot(pSigma[0], pSigma[1]); + // candidate DCA to PV + o2::track::TrackPar sigmaTrackPar({secVtx[0], secVtx[1], secVtx[2]}, {pSigma[0], pSigma[1], pSigma[2]}, protonTrack.sign(), true); + std::array dcaSigmaToPv{}; + o2::base::Propagator::Instance()->propagateToDCA(o2::math_utils::Point3D{pv[0], pv[1], pv[2]}, sigmaTrackPar, mBz, 2.f, + o2::base::Propagator::MatCorrType::USEMatCorrNONE, &dcaSigmaToPv); + float candDcaToPV = std::abs(dcaSigmaToPv[0]); + histos.fill(HIST("Candidate/hDcaToPV"), candDcaToPV); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Candidate/True/hDcaToPV"), candDcaToPV); + } + } + if (candDcaToPV > candMaxDcaToPV) { + return -1; + } + fillCandStep(8); // DCA to PV + + // AntiSigmaPointingAngle - Fake pointing angle + std::array protonPath{secVtx[0] - protonOrigPos[0], secVtx[1] - protonOrigPos[1], secVtx[2] - protonOrigPos[2]}; + float protonPathLength = std::sqrt(dot3(protonPath, protonPath)); + float svRadiusFromPv = std::hypot(secVtx[0] - pv[0], secVtx[1] - pv[1]); + float protonOrigRadiusFromPv = std::hypot(protonOrigPos[0] - pv[0], protonOrigPos[1] - pv[1]); + float propDir = (svRadiusFromPv < protonOrigRadiusFromPv) ? -1.f : 1.f; + float qProton = (protonTrack.sign() < 0) ? -1.f : 1.f; + float protonP = std::sqrt(dot3(pProton, pProton)); + float rCurve = protonP * 1000.f / (0.2998f * std::abs(mBz)); + float bzSign = (mBz < 0) ? -1.f : 1.f; + float alphaRot = -propDir * qProton * bzSign * o2::constants::math::PI; + if (protonPathLength / (2.f * rCurve) < 1.f) { + alphaRot = -2.f * propDir * qProton * bzSign * std::asin(protonPathLength / (2.f * rCurve)); + } + std::array pProtonRot{ + pProton[0] * std::cos(alphaRot) - pProton[1] * std::sin(alphaRot), + pProton[0] * std::sin(alphaRot) + pProton[1] * std::cos(alphaRot), + pProton[2]}; + float alphaVtxRot = -propDir * qProton * bzSign * o2::constants::math::PI * 0.5f; + if (flightDistance / (2.f * rCurve) < 1.f) { + alphaVtxRot = -propDir * qProton * bzSign * std::asin(flightDistance / (2.f * rCurve)); + } + std::array sigmaVertexVec{secVtx[0] - pv[0], secVtx[1] - pv[1], secVtx[2] - pv[2]}; + std::array sigmaVertexVecRot{ + sigmaVertexVec[0] * std::cos(alphaVtxRot) - sigmaVertexVec[1] * std::sin(alphaVtxRot), + sigmaVertexVec[0] * std::sin(alphaVtxRot) + sigmaVertexVec[1] * std::cos(alphaVtxRot), + sigmaVertexVec[2]}; + float antiSigmaPointingAngle = std::acos(std::clamp(dot3(pProtonRot, sigmaVertexVecRot) / std::sqrt(dot3(pProtonRot, pProtonRot) * dot3(sigmaVertexVecRot, sigmaVertexVecRot)), -1.f, 1.f)); + histos.fill(HIST("Candidate/hAntiSigmaPointingAngle"), antiSigmaPointingAngle); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Candidate/True/hAntiSigmaPointingAngle"), antiSigmaPointingAngle); + } + } + // window cut + if (antiSigmaPointingAngle < candMinAntiSigmaPointingAngle || antiSigmaPointingAngle > candMaxAntiSigmaPointingAngle) { + return -1; + } + histos.fill(HIST("Candidate/hMassSigmaPlus"), bestMass); histos.fill(HIST("Candidate/h2MassVsPt"), ptSigma, bestMass); + histos.fill(HIST("Candidate/h2MassVsRootCenter"), rootCenter, bestMass); + histos.fill(HIST("Candidate/h2MassVsAntiSigmaPointingAngle"), antiSigmaPointingAngle, bestMass); if constexpr (IsMC) { if (isSignal) { histos.fill(HIST("Candidate/True/hMassSigmaPlus"), bestMass); histos.fill(HIST("Candidate/True/h2MassVsPt"), ptSigma, bestMass); + histos.fill(HIST("Candidate/True/h2MassVsAntiSigmaPointingAngle"), antiSigmaPointingAngle, bestMass); + histos.fill(HIST("Candidate/True/h2MassVsRootCenter"), rootCenter, bestMass); } } - fillCandStep(6); // filled - // photon (V0) opening angle: angle between the e+/e- daughter momenta at their own reference point + if (bestMass > candMaxSigmaMass) { + return -1; + } + fillCandStep(9); // mass + + float candRapidity = RecoDecay::y(pSigma, o2::constants::physics::MassSigmaPlus); + histos.fill(HIST("Candidate/hRapidity"), candRapidity); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Candidate/True/hRapidity"), candRapidity); + } + } + if (std::abs(candRapidity) > candMaxRapidity) { + return -1; + } + fillCandStep(10); // rapidity + + // photon (V0) opening angle, recomputed here from the daughters' own raw track momenta std::array pPosDau{posTrack.px(), posTrack.py(), posTrack.pz()}; std::array pNegDau{negTrack.px(), negTrack.py(), negTrack.pz()}; float photonOpeningAngle = std::acos(std::clamp(dot3(pPosDau, pNegDau) / std::sqrt(dot3(pPosDau, pPosDau) * dot3(pNegDau, pNegDau)), -1.f, 1.f)); + histos.fill(HIST("Candidate/hPhotonOpeningAngle"), photonOpeningAngle); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Candidate/True/hPhotonOpeningAngle"), photonOpeningAngle); + } + } + if (photonOpeningAngle > candMaxPhotonOpeningAngle) { + return -1; + } + fillCandStep(11); // photon opening angle - // photon pointing angle: angle between the fitted photon momentum and the line from its conversion point to the p-gamma decay vertex - std::array convToDecVtx{secVtx[0] - photon.x(), secVtx[1] - photon.y(), secVtx[2] - photon.z()}; - float photonPointingAngle = std::acos(std::clamp(dot3(pGamma1, convToDecVtx) / std::sqrt(dot3(pGamma1, pGamma1) * dot3(convToDecVtx, convToDecVtx)), -1.f, 1.f)); + // photon pointing angle + std::array decVtxToConv{photon.x - secVtx[0], photon.y - secVtx[1], photon.z - secVtx[2]}; + float photonPointingAngle = std::acos(std::clamp(dot3(pGamma1, decVtxToConv) / std::sqrt(dot3(pGamma1, pGamma1) * dot3(decVtxToConv, decVtxToConv)), -1.f, 1.f)); + histos.fill(HIST("Candidate/hPhotonPointingAngle"), photonPointingAngle); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Candidate/True/hPhotonPointingAngle"), photonPointingAngle); + } + } + if (photonPointingAngle > candMaxPhotonPointingAngle) { + return -1; + } + fillCandStep(12); // photon pointing angle - // photon DCA to PV: distance from the PV to the line through the conversion point along the photon momentum direction - std::array convPoint{photon.x(), photon.y(), photon.z()}; - std::array photonDir = normalize3({photon.px(), photon.py(), photon.pz()}); + // photon DCA to PV + std::array convPoint{photon.x, photon.y, photon.z}; + std::array photonDir = normalize3({photon.px, photon.py, photon.pz}); std::array pvToConv{pv[0] - convPoint[0], pv[1] - convPoint[1], pv[2] - convPoint[2]}; std::array pvToConvCrossDir = cross3(pvToConv, photonDir); float photonDcaToPV = std::sqrt(dot3(pvToConvCrossDir, pvToConvCrossDir)); + histos.fill(HIST("Candidate/hPhotonDcaToPV"), photonDcaToPV); + if constexpr (IsMC) { + if (isSignal) { + histos.fill(HIST("Candidate/True/hPhotonDcaToPV"), photonDcaToPV); + } + } + if (photonDcaToPV > candMaxPhotonDcaToPV) { + return -1; + } + fillCandStep(13); // photon DCA to PV + fillCandStep(14); // filled if constexpr (IsMC) { + if (fillSlimTables) { + slimSigmaPlusCandsMC(radius, + candDcaToPV, dcaProtonGamma, + protonTrack.sign(), + protonTrack.dcaXY(), protonTrack.dcaZ(), + pProton[0], pProton[1], pProton[2], + pGamma1[0], pGamma1[1], pGamma1[2], + bestMomGamma2[0], bestMomGamma2[1], bestMomGamma2[2], + protonTrack.tpcNSigmaPr(), protonTrack.tofNSigmaPr(), + posTrack.tpcNSigmaEl(), negTrack.tpcNSigmaEl(), + photon.mGamma, + collisionIdCheck, + isSignal, + decayRadiusMC, massMC, + mcTrueMomSigmaPlus[0], mcTrueMomSigmaPlus[1], mcTrueMomSigmaPlus[2]); + return matchedSigmaId; + } sigmaPlusCandsMC(secVtx[0], secVtx[1], secVtx[2], - radius, flightDistance, dcaProtonGamma, fitChi2, + flightDistance, dcaProtonGamma, pProton[0], pProton[1], pProton[2], pGamma1[0], pGamma1[1], pGamma1[2], bestMomGamma2[0], bestMomGamma2[1], bestMomGamma2[2], protonTrack.tpcNSigmaPr(), protonTrack.tofNSigmaPr(), posTrack.tpcNSigmaEl(), negTrack.tpcNSigmaEl(), - photon.mGamma(), photon.alpha(), photon.qtarm(), photon.v0radius(), + photon.mGamma, photon.alpha, photon.qtarm, photon.radius, photonOpeningAngle, photonPointingAngle, photonDcaToPV, + rootCenter, antiSigmaPointingAngle, candDcaToPV, + protonTrack.sign(), protonTrack.itsNCls(), protonTrack.tpcNClsFound(), protonTrack.dcaXY(), protonTrack.dcaZ(), posTrack.itsNCls(), posTrack.tpcNClsFound(), negTrack.itsNCls(), negTrack.tpcNClsFound(), + collisionIdCheck, isSignal, - protonPdgCode, protonMotherPdgCode, - gammaPdgCode, gammaMotherPdgCode, gammaGMotherPdgCode, mcTrueVtx[0], mcTrueVtx[1], mcTrueVtx[2], mcTrueMomProton[0], mcTrueMomProton[1], mcTrueMomProton[2], - mcTrueMomGamma[0], mcTrueMomGamma[1], mcTrueMomGamma[2]); + mcTrueMomGamma[0], mcTrueMomGamma[1], mcTrueMomGamma[2], + mcTrueMomSigmaPlus[0], mcTrueMomSigmaPlus[1], mcTrueMomSigmaPlus[2], + decayRadiusMC, massMC); } else { + if (fillSlimTables) { + slimSigmaPlusCands(radius, + candDcaToPV, dcaProtonGamma, + protonTrack.sign(), + protonTrack.dcaXY(), protonTrack.dcaZ(), + pProton[0], pProton[1], pProton[2], + pGamma1[0], pGamma1[1], pGamma1[2], + bestMomGamma2[0], bestMomGamma2[1], bestMomGamma2[2], + protonTrack.tpcNSigmaPr(), protonTrack.tofNSigmaPr(), + posTrack.tpcNSigmaEl(), negTrack.tpcNSigmaEl(), + photon.mGamma); + return matchedSigmaId; + } sigmaPlusCands(secVtx[0], secVtx[1], secVtx[2], - radius, flightDistance, dcaProtonGamma, fitChi2, + flightDistance, dcaProtonGamma, pProton[0], pProton[1], pProton[2], pGamma1[0], pGamma1[1], pGamma1[2], bestMomGamma2[0], bestMomGamma2[1], bestMomGamma2[2], protonTrack.tpcNSigmaPr(), protonTrack.tofNSigmaPr(), posTrack.tpcNSigmaEl(), negTrack.tpcNSigmaEl(), - photon.mGamma(), photon.alpha(), photon.qtarm(), photon.v0radius(), + photon.mGamma, photon.alpha, photon.qtarm, photon.radius, photonOpeningAngle, photonPointingAngle, photonDcaToPV, + rootCenter, antiSigmaPointingAngle, candDcaToPV, + protonTrack.sign(), protonTrack.itsNCls(), protonTrack.tpcNClsFound(), protonTrack.dcaXY(), protonTrack.dcaZ(), posTrack.itsNCls(), posTrack.tpcNClsFound(), negTrack.itsNCls(), negTrack.tpcNClsFound()); } + return matchedSigmaId; } void initCCDB(aod::BCs::iterator const& bc) @@ -884,75 +1317,77 @@ struct Sigmaplusbuilder { void processData(CollisionsFull const& collisions, aod::V0Datas const& v0s, TracksFull const& tracks, aod::BCs const&) { for (const auto& collision : collisions) { + if (std::abs(collision.posZ()) > cutZVertex || !collision.sel8()) { + continue; + } initCCDB(collision.bc_as()); histos.fill(HIST("hVertexZ"), collision.posZ()); std::array pv{collision.posX(), collision.posY(), collision.posZ()}; + auto tracksThisCollision = tracks.sliceBy(tracksPerCollision, collision.globalIndex()); auto v0sThisCollision = v0s.sliceBy(v0PerCollision, collision.globalIndex()); - std::vector acceptedPhotons; - for (const auto& v0 : v0sThisCollision) { - if (selectPhoton(v0)) { - acceptedPhotons.push_back(v0); - } - } - auto tracksThisCollision = tracks.sliceBy(tracksPerCollision, collision.globalIndex()); + auto acceptedPhotons = findPhotonsFromV0s(v0sThisCollision, tracksThisCollision, pv); + std::vector acceptedProtons; for (const auto& track : tracksThisCollision) { - if (selectProton(track)) { + if (selectProton(track)) { acceptedProtons.push_back(track); } } for (const auto& photon : acceptedPhotons) { for (const auto& proton : acceptedProtons) { - buildSigmaPlusCandidate(proton, photon, pv); + buildSigmaPlusCandidate(proton, photon, pv); } } } } PROCESS_SWITCH(Sigmaplusbuilder, processData, "Process data", true); - void processMc(CollisionsFullMC const& collisions, aod::V0Datas const& v0s, TracksFullMC const& tracks, aod::BCs const&, aod::McParticles const& mcParticles) + void processMc(CollisionsFullMC const& collisions, aod::V0Datas const& v0s, TracksFullMC const& tracks, aod::BCs const&, aod::McParticles const& mcParticles, aod::McCollisions const&) { + std::vector matchedSigmaPlusMcIds; // Sigma+ MC indices that got at least one signal candidate + for (const auto& collision : collisions) { + if (std::abs(collision.posZ()) > cutZVertex || !collision.sel8()) { + continue; + } initCCDB(collision.bc_as()); histos.fill(HIST("hVertexZ"), collision.posZ()); std::array pv{collision.posX(), collision.posY(), collision.posZ()}; + auto tracksThisCollision = tracks.sliceBy(tracksPerCollisionMC, collision.globalIndex()); auto v0sThisCollision = v0s.sliceBy(v0PerCollision, collision.globalIndex()); - std::vector acceptedPhotons; - for (const auto& v0 : v0sThisCollision) { - if (selectPhoton(v0)) { - acceptedPhotons.push_back(v0); - - histos.fill(HIST("MC/hPhotonTruthQA"), 0); - auto posTrack = v0.template posTrack_as(); - auto negTrack = v0.template negTrack_as(); - if (posTrack.has_mcParticle() && negTrack.has_mcParticle()) { - histos.fill(HIST("MC/hPhotonTruthQA"), 1); - auto mcPos = posTrack.template mcParticle_as(); - auto mcNeg = negTrack.template mcParticle_as(); - - auto const& posMothers = mcPos.template mothers_as(); - auto const& negMothers = mcNeg.template mothers_as(); - if (!posMothers.empty() && !negMothers.empty()) { - auto mcGamma = posMothers.front(); - if (mcGamma.globalIndex() == negMothers.front().globalIndex() && mcGamma.pdgCode() == PDG_t::kGamma) { - histos.fill(HIST("MC/hPhotonTruthQA"), 2); - auto const& pi0Mothers = mcGamma.template mothers_as(); - if (!pi0Mothers.empty() && std::abs(pi0Mothers.front().pdgCode()) == PDG_t::kPi0) { - histos.fill(HIST("MC/hPhotonTruthQA"), 3); - auto const& sigmaMothers = pi0Mothers.front().template mothers_as(); - if (!sigmaMothers.empty() && std::abs(sigmaMothers.front().pdgCode()) == PDG_t::kSigmaPlus) { - histos.fill(HIST("MC/hPhotonTruthQA"), 4); - - histos.fill(HIST("Photon/True/hMass"), v0.mGamma()); - histos.fill(HIST("Photon/True/hPt"), v0.pt()); - histos.fill(HIST("Photon/True/hRadius"), v0.v0radius()); - histos.fill(HIST("Photon/True/h2ArmenterosPodolanski"), v0.alpha(), v0.qtarm()); - histos.fill(HIST("Photon/True/h2ConvPointXY"), v0.x(), v0.y()); - } + + auto acceptedPhotons = findPhotonsFromV0s(v0sThisCollision, tracksThisCollision, pv); + for (const auto& photon : acceptedPhotons) { + histos.fill(HIST("MC/hPhotonTruthQA"), 0); + auto posTrack = photon.posTrack; + auto negTrack = photon.negTrack; + if (posTrack.has_mcParticle() && negTrack.has_mcParticle()) { + histos.fill(HIST("MC/hPhotonTruthQA"), 1); + auto mcPos = posTrack.template mcParticle_as(); + auto mcNeg = negTrack.template mcParticle_as(); + + auto const& posMothers = mcPos.template mothers_as(); + auto const& negMothers = mcNeg.template mothers_as(); + if (!posMothers.empty() && !negMothers.empty()) { + auto mcGamma = posMothers.front(); + if (mcGamma.globalIndex() == negMothers.front().globalIndex() && mcGamma.pdgCode() == PDG_t::kGamma) { + histos.fill(HIST("MC/hPhotonTruthQA"), 2); + auto const& pi0Mothers = mcGamma.template mothers_as(); + if (!pi0Mothers.empty() && std::abs(pi0Mothers.front().pdgCode()) == PDG_t::kPi0) { + histos.fill(HIST("MC/hPhotonTruthQA"), 3); + auto const& sigmaMothers = pi0Mothers.front().template mothers_as(); + if (!sigmaMothers.empty() && std::abs(sigmaMothers.front().pdgCode()) == PDG_t::kSigmaPlus) { + histos.fill(HIST("MC/hPhotonTruthQA"), 4); + + histos.fill(HIST("Photon/True/hMass"), photon.mGamma); + histos.fill(HIST("Photon/True/hPt"), std::hypot(photon.px, photon.py)); + histos.fill(HIST("Photon/True/hRadius"), photon.radius); + histos.fill(HIST("Photon/True/h2ArmenterosPodolanski"), photon.alpha, photon.qtarm); + histos.fill(HIST("Photon/True/h2ConvPointXY"), photon.x, photon.y); } } } @@ -960,10 +1395,9 @@ struct Sigmaplusbuilder { } } - auto tracksThisCollision = tracks.sliceBy(tracksPerCollisionMC, collision.globalIndex()); std::vector acceptedProtons; for (const auto& track : tracksThisCollision) { - if (selectProton(track)) { + if (selectProton(track)) { acceptedProtons.push_back(track); histos.fill(HIST("MC/hProtonTruthQA"), 0); @@ -972,12 +1406,6 @@ struct Sigmaplusbuilder { auto mcProton = track.template mcParticle_as(); if (findSigmaPlusMotherOfProton(mcProton) >= 0) { histos.fill(HIST("MC/hProtonTruthQA"), 2); - - histos.fill(HIST("Proton/True/hPt"), track.pt()); - histos.fill(HIST("Proton/True/h2TPCNSigmaVsPt"), track.pt(), track.tpcNSigmaPr()); - if (track.hasTOF()) { - histos.fill(HIST("Proton/True/h2TOFNSigmaVsPt"), track.pt(), track.tofNSigmaPr()); - } } } } @@ -985,25 +1413,101 @@ struct Sigmaplusbuilder { for (const auto& photon : acceptedPhotons) { for (const auto& proton : acceptedProtons) { - buildSigmaPlusCandidate(proton, photon, pv); + int matchedId = buildSigmaPlusCandidate(proton, photon, pv); + if (matchedId >= 0) { + matchedSigmaPlusMcIds.push_back(matchedId); + } } } } // all generated Sigma+ -> p pi0 decays, regardless of reconstruction for (const auto& mcPart : mcParticles) { - if (isSigmaPlusToProtonPi0(mcPart)) { - histos.fill(HIST("MC/hGenSigmaPlusPt"), mcPart.pt()); + if (!isSigmaPlusToProtonPi0(mcPart)) { + continue; + } + if (std::abs(mcPart.y()) > cutRapMotherMC) { + continue; + } + if (mcPart.pt() < cutPtGenMC) { + continue; + } + histos.fill(HIST("MC/hGenSigmaPlusPt"), mcPart.pt()); + + bool wasReconstructed = std::find(matchedSigmaPlusMcIds.begin(), matchedSigmaPlusMcIds.end(), mcPart.globalIndex()) != matchedSigmaPlusMcIds.end(); + if (wasReconstructed) { + continue; } + + // this true Sigma+ never made it into any signal candidate: still record its truth info, + // with the reconstructed-side columns set to -999 + int pdgProton = mcPart.pdgCode() > 0 ? PDG_t::kProton : PDG_t::kProtonBar; + std::array genDecVtx{-999.f, -999.f, -999.f}; + std::array genMomProton{-999.f, -999.f, -999.f}; + for (const auto& daughter : mcPart.template daughters_as()) { + if (daughter.pdgCode() == pdgProton) { + genDecVtx = {daughter.vx(), daughter.vy(), daughter.vz()}; + genMomProton = {daughter.px(), daughter.py(), daughter.pz()}; + break; + } + } + float genDecayRadiusMC = std::hypot(genDecVtx[0] - mcPart.vx(), genDecVtx[1] - mcPart.vy()); + float genMassMC = std::sqrt(mcPart.e() * mcPart.e() - mcPart.p() * mcPart.p()); + + if (fillSlimTables) { + slimSigmaPlusCandsMC(-999.f, + -999.f, -999.f, + 0, + -999.f, -999.f, + -999.f, -999.f, -999.f, + -999.f, -999.f, -999.f, + -999.f, -999.f, -999.f, + -999.f, -999.f, + -999.f, -999.f, + -999.f, + false, + false, + genDecayRadiusMC, genMassMC, + mcPart.px(), mcPart.py(), mcPart.pz()); + continue; + } + + sigmaPlusCandsMC(-999.f, -999.f, -999.f, + -999.f, -999.f, + -999.f, -999.f, -999.f, + -999.f, -999.f, -999.f, + -999.f, -999.f, -999.f, + -999.f, -999.f, + -999.f, -999.f, + -999.f, -999.f, -999.f, -999.f, + -999.f, -999.f, -999.f, + -999.f, -999.f, -999.f, + 0, + 0, -999, -999.f, -999.f, + 0, -999, 0, -999, + false, + false, + genDecVtx[0], genDecVtx[1], genDecVtx[2], + genMomProton[0], genMomProton[1], genMomProton[2], + -999.f, -999.f, -999.f, + mcPart.px(), mcPart.py(), mcPart.pz(), + genDecayRadiusMC, genMassMC); } } PROCESS_SWITCH(Sigmaplusbuilder, processMc, "Process MC", false); - void processFindable(CollisionsFullMC const& collisions, aod::V0Datas const& v0s, TracksFullMC const& tracks, aod::McParticles const&) + void processFindable(CollisionsFullMC const& collisions, aod::V0Datas const& v0s, TracksFullMC const& tracks, aod::McParticles const&, aod::BCs const&) { + constexpr int MinDauTpcCls = 90; for (const auto& collision : collisions) { + if (std::abs(collision.posZ()) > cutZVertex || !collision.sel8()) { + continue; + } + initCCDB(collision.bc_as()); auto tracksThisCollision = tracks.sliceBy(tracksPerCollisionMC, collision.globalIndex()); auto v0sThisCollision = v0s.sliceBy(v0PerCollision, collision.globalIndex()); + std::array pv{collision.posX(), collision.posY(), collision.posZ()}; + auto acceptedPhotons = findPhotonsFromV0s(v0sThisCollision, tracksThisCollision, pv); for (const auto& protonTrack : tracksThisCollision) { if (!protonTrack.has_mcParticle()) { @@ -1035,7 +1539,7 @@ struct Sigmaplusbuilder { continue; } - if (electronTrack.tpcNClsFound() < 90 || electronTrack.sign() > 0) { + if (electronTrack.tpcNClsFound() < MinDauTpcCls || electronTrack.sign() > 0) { continue; } @@ -1055,7 +1559,7 @@ struct Sigmaplusbuilder { continue; } - if (positronTrack.tpcNClsFound() < 90 || positronTrack.sign() < 0) { + if (positronTrack.tpcNClsFound() < MinDauTpcCls || positronTrack.sign() < 0) { continue; } @@ -1121,10 +1625,10 @@ struct Sigmaplusbuilder { std::array recoGammaMom{electronTrack.px() + positronTrack.px(), electronTrack.py() + positronTrack.py(), electronTrack.pz() + positronTrack.pz()}; float recoGammaP = std::sqrt(dot3(recoGammaMom, recoGammaMom)); - constexpr float electronMass = o2::constants::physics::MassElectron; + constexpr float ElectronMass = o2::constants::physics::MassElectron; float electronP2 = electronTrack.px() * electronTrack.px() + electronTrack.py() * electronTrack.py() + electronTrack.pz() * electronTrack.pz(); float positronP2 = positronTrack.px() * positronTrack.px() + positronTrack.py() * positronTrack.py() + positronTrack.pz() * positronTrack.pz(); - float pairEnergy = std::sqrt(electronP2 + electronMass * electronMass) + std::sqrt(positronP2 + electronMass * electronMass); + float pairEnergy = std::sqrt(electronP2 + ElectronMass * ElectronMass) + std::sqrt(positronP2 + ElectronMass * ElectronMass); float pairMass2 = pairEnergy * pairEnergy - recoGammaP * recoGammaP; histos.fill(HIST("Findable/hElectronPositronMass"), std::sqrt(std::max(pairMass2, 0.f))); @@ -1155,6 +1659,15 @@ struct Sigmaplusbuilder { break; } } + + histos.fill(HIST("Findable/hPhotonSearchPresence"), 0); + for (const auto& photon : acceptedPhotons) { + bool sameChargeMatched = photon.posTrack.globalIndex() == positronTrack.globalIndex() && photon.negTrack.globalIndex() == electronTrack.globalIndex(); + if (sameChargeMatched) { + histos.fill(HIST("Findable/hPhotonSearchPresence"), 1); + break; + } + } histos.fill(HIST("Findable/hElectronPt"), electronTrack.pt()); histos.fill(HIST("Findable/hPositronPt"), positronTrack.pt()); histos.fill(HIST("Findable/hPhotonConversionRadius"), std::hypot(electronVertex[0], electronVertex[1])); diff --git a/PWGLF/TableProducer/Strangeness/stracents.cxx b/PWGLF/TableProducer/Strangeness/stracents.cxx index a50905d6a41..ad34db13e92 100644 --- a/PWGLF/TableProducer/Strangeness/stracents.cxx +++ b/PWGLF/TableProducer/Strangeness/stracents.cxx @@ -38,6 +38,7 @@ #include #include #include +#include #include using namespace o2; @@ -107,7 +108,7 @@ struct straCents { float mMCScalePars[6] = {0.0}; TFormula* mMCScale = nullptr; explicit CalibrationInfo(std::string name) - : name(name), + : name(std::move(name)), mCalibrationStored(false), mhMultSelCalib(nullptr), mMCScalePars{0.0}, @@ -216,7 +217,7 @@ struct straCents { } template - void initCCDB(TCollision collision) + void initCCDB(const TCollision& collision) { if (mRunNumber == collision.runNumber()) { return; @@ -348,7 +349,7 @@ struct straCents { } } else { // we are in Run 3 - auto getccdb = [lCalibObjects_Centrality, collision](struct CalibrationInfo& estimator, const Configurable generatorName, const Configurable notCrashOnNull) { // TODO: to consider the name inside the estimator structure + auto getccdb = [lCalibObjects_Centrality, collision](struct CalibrationInfo& estimator, const Configurable& generatorName, const Configurable& notCrashOnNull) { // TODO: to consider the name inside the estimator structure estimator.mhMultSelCalib = reinterpret_cast(lCalibObjects_Centrality->FindObject(TString::Format("hCalibZeq%s", estimator.name.c_str()).Data())); estimator.mMCScale = reinterpret_cast(lCalibObjects_Centrality->FindObject(TString::Format("%s-%s", generatorName->c_str(), estimator.name.c_str()).Data())); if (estimator.mhMultSelCalib != nullptr) { diff --git a/PWGLF/TableProducer/Strangeness/strangederivedbuilder.cxx b/PWGLF/TableProducer/Strangeness/strangederivedbuilder.cxx index 94cf60e61d6..8007e538f89 100644 --- a/PWGLF/TableProducer/Strangeness/strangederivedbuilder.cxx +++ b/PWGLF/TableProducer/Strangeness/strangederivedbuilder.cxx @@ -264,7 +264,7 @@ struct strangederivedbuilder { std::vector genOmegaPlus; // create collision indices beforehand - std::vector TrackCollIndices; // index -1: no collision + std::vector TrackGlobalBc; std::vector V0CollIndices; // index -1: no collision std::vector CascadeCollIndices; // index -1: no collision std::vector KFCascadeCollIndices; // index -1: no collision @@ -288,7 +288,7 @@ struct strangederivedbuilder { } template - bool isCollisionAccepted(TCollision collision, std::array& nSelected) + bool isCollisionAccepted(TCollision const& collision, std::array& nSelected) // check whether the collision passes our collision selections { if (requireTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { @@ -552,13 +552,13 @@ struct strangederivedbuilder { void populateCollisionTables(coll const& collisions, udcoll const& udCollisions, tracks const& Tracks, v0d const& V0s, cad const& Cascades, kfcad const& KFCascades, tracad const& TraCascades, bcType const& /*bcs*/) { // create collision indices beforehand - TrackCollIndices.clear(); + TrackGlobalBc.clear(); V0CollIndices.clear(); CascadeCollIndices.clear(); KFCascadeCollIndices.clear(); TraCascadeCollIndices.clear(); - TrackCollIndices.resize(Tracks.size(), 0); // index -1: no collision + TrackGlobalBc.resize(Tracks.size(), 0); V0CollIndices.resize(V0s.size(), -1); // index -1: no collision CascadeCollIndices.resize(Cascades.size(), -1); // index -1: no collision KFCascadeCollIndices.resize(KFCascades.size(), -1); // index -1: no collision @@ -645,7 +645,7 @@ struct strangederivedbuilder { } for (const auto& track : TrackTable_thisColl) - TrackCollIndices[track.globalIndex()] = bc.globalBC(); + TrackGlobalBc[track.globalIndex()] = bc.globalBC(); if (fillOnlySelectedCollisions && !isCollisionAccepted(collision, totalNbrCollisionsPerSelection)) { continue; @@ -854,6 +854,7 @@ struct strangederivedbuilder { products.strangeMCColl(mccollision.posX(), mccollision.posY(), mccollision.posZ(), mccollision.impactParameter(), mccollision.eventPlaneAngle(), mccollision.generatorsID()); products.strangeMCMults(mccollision.multMCFT0A(), mccollision.multMCFT0C(), + mccollision.multMCFV0A(), mccollision.multMCFDDA(), mccollision.multMCFDDC(), mccollision.multMCNParticlesEta05(), mccollision.multMCNParticlesEta08(), mccollision.multMCNParticlesEta10(), @@ -1047,7 +1048,7 @@ struct strangederivedbuilder { aod::dautrack::packing::packInInt8(tr.tpcNSigmaPr())); // populate daughter-level TOF information if (tr.hasTOF()) { - products.dauTrackTOFPIDs(TrackCollIndices[tr.globalIndex()], products.dauTrackExtras.lastIndex(), tr.tofSignal(), tr.tofEvTime(), tr.tofEvTimeErr(), tr.length(), tr.tofExpMom()); + products.dauTrackTOFPIDs(TrackGlobalBc[tr.globalIndex()], products.dauTrackExtras.lastIndex(), tr.tofSignal(), tr.tofEvTime(), tr.tofEvTimeErr(), tr.length(), tr.tofExpMom()); } } else { // populate with empty fully-compatible Nsigmas if no corresponding table available diff --git a/PWGLF/TableProducer/Strangeness/strangenessMcCentrality.cxx b/PWGLF/TableProducer/Strangeness/strangenessMcCentrality.cxx new file mode 100644 index 00000000000..31c969b5303 --- /dev/null +++ b/PWGLF/TableProducer/Strangeness/strangenessMcCentrality.cxx @@ -0,0 +1,71 @@ +// 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. + +/// +/// \file mcCentrality.cxx +/// \author Romain Schotter romain.schotter@cern.ch +/// \brief Task to produce the MC centrality table for strangeness derived data +/// + +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/Utils/mcCentralityModule.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +/// Task to produce the response table +struct StrangenessMcCentrality { + // Input parameters + o2::framework::Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; + Service ccdb; + + o2::pwglf::mccentrality::products products; + o2::pwglf::mccentrality::coreConfigurables baseOpts; + o2::pwglf::mccentrality::BuilderModule mcCentralityBuilderModule; + + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(o2::framework::InitContext& initContext) + { + // Set up the CCDB + ccdb->setURL(ccdbUrl.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + mcCentralityBuilderModule.init(baseOpts, histos, initContext); + } + + // Full tables (independent on central calibrations) + void process(aod::StraMCCollMults const& mcCollisions, + aod::StraStamps const& bcs) + { + mcCentralityBuilderModule.dataProcess(ccdb, histos, bcs, mcCollisions, products); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/TableProducer/Strangeness/strangenesstofpid.cxx b/PWGLF/TableProducer/Strangeness/strangenesstofpid.cxx index 83920cfd718..5284394277e 100644 --- a/PWGLF/TableProducer/Strangeness/strangenesstofpid.cxx +++ b/PWGLF/TableProducer/Strangeness/strangenesstofpid.cxx @@ -67,7 +67,6 @@ #include #include #include -#include #include using namespace o2; @@ -245,10 +244,10 @@ struct strangenesstofpid { TH1 *hMeanNegOmPr = nullptr, *hSigmaNegOmPr = nullptr; TH1 *hMeanBachOmKa = nullptr, *hSigmaBachOmKa = nullptr; - int mRunNumber; - float d_bz; - float maxSnp; // max sine phi for propagation - float maxStep; // max step size (cm) for propagation + int mRunNumber = 0; + float d_bz = 0.; + float maxSnp = 0.85; // max sine phi for propagation + float maxStep = 2.00; // max step size (cm) for propagation // enum to keep track of the TOF-related properties for V0s enum tofEnum { kLength = 0, @@ -850,16 +849,31 @@ struct strangenesstofpid { float nSigmaOmKa = o2::aod::cascdata::kNoTOFValue; // n sigma with wrong hypothesis - float nSigmaXiLaEl = o2::aod::cascdata::kNoTOFValue; - float nSigmaXiLaKa = o2::aod::cascdata::kNoTOFValue; - float nSigmaXiEl = o2::aod::cascdata::kNoTOFValue; - float nSigmaXiKa = o2::aod::cascdata::kNoTOFValue; - float nSigmaXiPr = o2::aod::cascdata::kNoTOFValue; - float nSigmaOmLaEl = o2::aod::cascdata::kNoTOFValue; - float nSigmaOmLaKa = o2::aod::cascdata::kNoTOFValue; - float nSigmaOmEl = o2::aod::cascdata::kNoTOFValue; - float nSigmaOmPi = o2::aod::cascdata::kNoTOFValue; - float nSigmaOmPr = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiPositiveLaEl = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiNegativeLaEl = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiBachelorEl = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiPositiveLaPi = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiNegativeLaPi = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiBachelorPi = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiPositiveLaKa = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiNegativeLaKa = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiBachelorKa = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiPositiveLaPr = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiNegativeLaPr = o2::aod::cascdata::kNoTOFValue; + float nSigmaXiBachelorPr = o2::aod::cascdata::kNoTOFValue; + + float nSigmaOmPositiveLaEl = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmNegativeLaEl = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmBachelorEl = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmPositiveLaPi = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmNegativeLaPi = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmBachelorPi = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmPositiveLaKa = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmNegativeLaKa = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmBachelorKa = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmPositiveLaPr = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmNegativeLaPr = o2::aod::cascdata::kNoTOFValue; + float nSigmaOmBachelorPr = o2::aod::cascdata::kNoTOFValue; }; struct trackTofInfo { // holds input track info @@ -1326,54 +1340,35 @@ struct strangenesstofpid { if (nSigmaCalibLoaded) { casctof.nSigmaXiLaPr = (casctof.posDeltaTimeAsXiPr - hMeanPosXiPr->Interpolate(cascade.p())) / hSigmaPosXiPr->Interpolate(cascade.p()); casctof.nSigmaOmLaPr = (casctof.posDeltaTimeAsOmPr - hMeanPosOmPr->Interpolate(cascade.p())) / hSigmaPosOmPr->Interpolate(cascade.p()); - // wrong hypothesis - casctof.nSigmaXiLaEl = -999.; - casctof.nSigmaXiLaKa = -999.; - casctof.nSigmaXiLaPi = -999.; - - casctof.nSigmaOmLaEl = -999.; - casctof.nSigmaOmLaKa = -999.; - casctof.nSigmaOmLaPi = -999.; } } else { casctof.nSigmaXiLaPr = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); casctof.nSigmaOmLaPr = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - - // wrong hypothesis - casctof.nSigmaXiLaEl = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - casctof.nSigmaXiLaKa = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - casctof.nSigmaXiLaPi = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - - casctof.nSigmaOmLaEl = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - casctof.nSigmaOmLaKa = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - casctof.nSigmaOmLaPi = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); } } else { if (useNsigmaCalibStrTOF) { if (nSigmaCalibLoaded) { casctof.nSigmaXiLaPi = (casctof.posDeltaTimeAsXiPi - hMeanPosXiPi->Interpolate(cascade.p())) / hSigmaPosXiPi->Interpolate(cascade.p()); casctof.nSigmaOmLaPi = (casctof.posDeltaTimeAsOmPi - hMeanPosOmPi->Interpolate(cascade.p())) / hSigmaPosOmPi->Interpolate(cascade.p()); - // wrong hypothesis - casctof.nSigmaXiLaEl = -999.; - casctof.nSigmaXiLaKa = -999.; - casctof.nSigmaXiLaPi = -999.; - - casctof.nSigmaOmLaEl = -999.; - casctof.nSigmaOmLaKa = -999.; - casctof.nSigmaOmLaPi = -999.; } } else { casctof.nSigmaXiLaPi = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); casctof.nSigmaOmLaPi = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); + } + } + if (calculateCascadesNSigmaAll.value > 0) { + if (!useNsigmaCalibStrTOF) { // wrong hypothesis - casctof.nSigmaXiLaEl = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - casctof.nSigmaXiLaKa = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - casctof.nSigmaXiLaPr = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - - casctof.nSigmaOmLaEl = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - casctof.nSigmaOmLaKa = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); - casctof.nSigmaOmLaPr = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); + casctof.nSigmaXiPositiveLaEl = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); + casctof.nSigmaXiPositiveLaPi = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); + casctof.nSigmaXiPositiveLaKa = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); + casctof.nSigmaXiPositiveLaPr = mTOFResponse->nSigma(pTof.tofSignal - xiFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); + + casctof.nSigmaOmPositiveLaEl = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); + casctof.nSigmaOmPositiveLaPi = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); + casctof.nSigmaOmPositiveLaKa = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); + casctof.nSigmaOmPositiveLaPr = mTOFResponse->nSigma(pTof.tofSignal - omFlight - lambdaFlight, pTof.tofExpMom, lengthPositive, posTrack.getP(), posTrack.getEta(), pTof.tofEvTime, pTof.tofEvTimeErr); } } @@ -1463,54 +1458,35 @@ struct strangenesstofpid { if (nSigmaCalibLoaded) { casctof.nSigmaXiLaPi = (casctof.negDeltaTimeAsXiPi - hMeanNegXiPi->Interpolate(cascade.p())) / hSigmaNegXiPi->Interpolate(cascade.p()); casctof.nSigmaOmLaPi = (casctof.negDeltaTimeAsOmPi - hMeanNegOmPi->Interpolate(cascade.p())) / hSigmaNegOmPi->Interpolate(cascade.p()); - // wrong hypothesis - casctof.nSigmaXiLaEl = -999.; - casctof.nSigmaXiLaKa = -999.; - casctof.nSigmaXiLaPi = -999.; - - casctof.nSigmaOmLaEl = -999.; - casctof.nSigmaOmLaKa = -999.; - casctof.nSigmaOmLaPi = -999.; } } else { casctof.nSigmaXiLaPi = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); casctof.nSigmaOmLaPi = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - - // wrogn hypothesis - casctof.nSigmaXiLaEl = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - casctof.nSigmaXiLaKa = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - casctof.nSigmaXiLaPr = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - - casctof.nSigmaOmLaEl = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - casctof.nSigmaOmLaKa = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - casctof.nSigmaOmLaPr = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); } } else { if (useNsigmaCalibStrTOF) { if (nSigmaCalibLoaded) { casctof.nSigmaXiLaPr = (casctof.negDeltaTimeAsXiPr - hMeanNegXiPr->Interpolate(cascade.p())) / hSigmaNegXiPr->Interpolate(cascade.p()); casctof.nSigmaOmLaPr = (casctof.negDeltaTimeAsOmPr - hMeanNegOmPr->Interpolate(cascade.p())) / hSigmaNegOmPr->Interpolate(cascade.p()); - // wrong hypothesis - casctof.nSigmaXiLaEl = -999.; - casctof.nSigmaXiLaKa = -999.; - casctof.nSigmaXiLaPi = -999.; - - casctof.nSigmaOmLaEl = -999.; - casctof.nSigmaOmLaKa = -999.; - casctof.nSigmaOmLaPi = -999.; } } else { casctof.nSigmaXiLaPr = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); casctof.nSigmaOmLaPr = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); + } + } + if (calculateCascadesNSigmaAll.value > 0) { + if (!useNsigmaCalibStrTOF) { // wrong hypothesis - casctof.nSigmaXiLaEl = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - casctof.nSigmaXiLaKa = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - casctof.nSigmaXiLaPi = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - - casctof.nSigmaOmLaEl = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - casctof.nSigmaOmLaKa = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); - casctof.nSigmaOmLaPi = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); + casctof.nSigmaXiNegativeLaEl = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); + casctof.nSigmaXiNegativeLaPi = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); + casctof.nSigmaXiNegativeLaKa = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); + casctof.nSigmaXiNegativeLaPr = mTOFResponse->nSigma(nTof.tofSignal - xiFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); + + casctof.nSigmaOmNegativeLaEl = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); + casctof.nSigmaOmNegativeLaPi = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); + casctof.nSigmaOmNegativeLaKa = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); + casctof.nSigmaOmNegativeLaPr = mTOFResponse->nSigma(nTof.tofSignal - omFlight - lambdaFlight, nTof.tofExpMom, lengthNegative, negTrack.getP(), negTrack.getEta(), nTof.tofEvTime, nTof.tofEvTimeErr); } } @@ -1597,28 +1573,25 @@ struct strangenesstofpid { if (nSigmaCalibLoaded) { casctof.nSigmaXiPi = (casctof.bachDeltaTimeAsXiPi - hMeanBachXiPi->Interpolate(cascade.p())) / hSigmaBachXiPi->Interpolate(cascade.p()); casctof.nSigmaOmKa = (casctof.bachDeltaTimeAsOmKa - hMeanBachOmKa->Interpolate(cascade.p())) / hSigmaBachOmKa->Interpolate(cascade.p()); - - // wrong hypothesis - casctof.nSigmaXiEl = -999.; - casctof.nSigmaXiKa = -999.; - casctof.nSigmaXiPr = -999.; - - casctof.nSigmaOmEl = -999.; - casctof.nSigmaOmPi = -999.; - casctof.nSigmaOmPr = -999.; } } else { casctof.nSigmaXiPi = mTOFResponse->nSigma(bTof.tofSignal - xiFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); casctof.nSigmaOmKa = mTOFResponse->nSigma(bTof.tofSignal - omFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); + } - // wrong hypothesis - casctof.nSigmaXiEl = mTOFResponse->nSigma(bTof.tofSignal - xiFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); - casctof.nSigmaXiKa = mTOFResponse->nSigma(bTof.tofSignal - xiFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); - casctof.nSigmaXiPr = mTOFResponse->nSigma(bTof.tofSignal - xiFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); - - casctof.nSigmaOmEl = mTOFResponse->nSigma(bTof.tofSignal - omFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); - casctof.nSigmaOmPi = mTOFResponse->nSigma(bTof.tofSignal - omFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); - casctof.nSigmaOmPr = mTOFResponse->nSigma(bTof.tofSignal - omFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); + if (calculateCascadesNSigmaAll.value > 0) { + if (!useNsigmaCalibStrTOF) { + // wrong hypothesis + casctof.nSigmaXiBachelorEl = mTOFResponse->nSigma(bTof.tofSignal - xiFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); + casctof.nSigmaXiBachelorPi = mTOFResponse->nSigma(bTof.tofSignal - xiFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); + casctof.nSigmaXiBachelorKa = mTOFResponse->nSigma(bTof.tofSignal - xiFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); + casctof.nSigmaXiBachelorPr = mTOFResponse->nSigma(bTof.tofSignal - xiFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); + + casctof.nSigmaOmBachelorEl = mTOFResponse->nSigma(bTof.tofSignal - omFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); + casctof.nSigmaOmBachelorPi = mTOFResponse->nSigma(bTof.tofSignal - omFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); + casctof.nSigmaOmBachelorKa = mTOFResponse->nSigma(bTof.tofSignal - omFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); + casctof.nSigmaOmBachelorPr = mTOFResponse->nSigma(bTof.tofSignal - omFlight, bTof.tofExpMom, lengthBachelor, bachTrack.getP(), bachTrack.getEta(), bTof.tofEvTime, bTof.tofEvTimeErr); + } } // do QA histograms (calibration / QC) @@ -1665,9 +1638,6 @@ struct strangenesstofpid { return casctof; } - std::unordered_map mapCollisionTime; - std::unordered_map mapCollisionTimeError; - void processStandardData(/*aod::BCs const& bcs,*/ aod::Collisions const& collisions, V0OriginalDatas const& V0s, CascOriginalDatas const& cascades, TracksWithAllExtras const& tracks, aod::BCsWithTimestamps const& bcs) { // Fire up CCDB with first collision in record. If no collisions, bypass @@ -1681,14 +1651,6 @@ struct strangenesstofpid { mTOFResponse->processSetup(bcs.iteratorAt(0)); - for (const auto& track : tracks) { - if (mapCollisionTime.find(track.collisionId()) == mapCollisionTime.end()) { - // LOGF(info, "track.collisionId() = %d, track.tofEvTime() = %f, track.tofEvTimeErr() = %f", track.collisionId(), track.tofEvTime(), track.tofEvTimeErr()); - mapCollisionTime[track.collisionId()] = track.tofEvTime(); - mapCollisionTimeError[track.collisionId()] = track.tofEvTimeErr(); - } - } - //________________________________________________________________________ // estimate event times (only necessary for original data) std::vector collisionEventTime(collisions.size(), 0.0); @@ -1746,8 +1708,6 @@ struct strangenesstofpid { pTof.hasTPC = pTra.hasTPC(); pTof.hasTOF = pTra.hasTOF(); pTof.tofExpMom = pTra.tofExpMom(); - // pTof.tofEvTime = reassociateTracks ? mapCollisionTime[V0.collisionId()] : pTra.tofEvTime(); - // pTof.tofEvTimeErr = reassociateTracks ? mapCollisionTimeError[V0.collisionId()] : pTra.tofEvTimeErr(); pTof.tofEvTime = reassociateTracks ? collisionEventTime[V0.collisionId()] : pTra.tofEvTime(); pTof.tofEvTimeErr = reassociateTracks ? collisionEventTimeErr[V0.collisionId()] : pTra.tofEvTimeErr(); // pTof.tofSignal = pTra.tofSignal() + (doBCshift ? deltaTimePos : 0.0f); @@ -1762,8 +1722,6 @@ struct strangenesstofpid { nTof.hasTPC = nTra.hasTPC(); nTof.hasTOF = nTra.hasTOF(); nTof.tofExpMom = nTra.tofExpMom(); - // nTof.tofEvTime = reassociateTracks ? mapCollisionTime[V0.collisionId()] : nTra.tofEvTime(); - // nTof.tofEvTimeErr = reassociateTracks ? mapCollisionTimeError[V0.collisionId()] : nTra.tofEvTimeErr(); nTof.tofEvTime = reassociateTracks ? collisionEventTime[V0.collisionId()] : nTra.tofEvTime(); nTof.tofEvTimeErr = reassociateTracks ? collisionEventTimeErr[V0.collisionId()] : nTra.tofEvTimeErr(); // nTof.tofSignal = nTra.tofSignal() + (doBCshift ? deltaTimeNeg : 0.0f); @@ -1917,10 +1875,14 @@ struct strangenesstofpid { if (calculateCascadesNSigmaAll.value > 0) { casctofnsigmasall( - casctof.nSigmaXiLaEl, casctof.nSigmaXiEl, casctof.nSigmaOmLaEl, casctof.nSigmaOmEl, - casctof.nSigmaXiLaPi, casctof.nSigmaXiPi, casctof.nSigmaOmLaPi, casctof.nSigmaOmPi, - casctof.nSigmaXiLaKa, casctof.nSigmaXiKa, casctof.nSigmaOmLaKa, casctof.nSigmaOmKa, - casctof.nSigmaXiLaPr, casctof.nSigmaXiPr, casctof.nSigmaOmLaPr, casctof.nSigmaOmPr); + casctof.nSigmaXiPositiveLaEl, casctof.nSigmaXiNegativeLaEl, casctof.nSigmaXiBachelorEl, + casctof.nSigmaOmPositiveLaEl, casctof.nSigmaOmNegativeLaEl, casctof.nSigmaOmBachelorEl, + casctof.nSigmaXiPositiveLaPi, casctof.nSigmaXiNegativeLaPi, casctof.nSigmaXiBachelorPi, + casctof.nSigmaOmPositiveLaPi, casctof.nSigmaOmNegativeLaPi, casctof.nSigmaOmBachelorPi, + casctof.nSigmaXiPositiveLaKa, casctof.nSigmaXiNegativeLaKa, casctof.nSigmaXiBachelorKa, + casctof.nSigmaOmPositiveLaKa, casctof.nSigmaOmNegativeLaKa, casctof.nSigmaOmBachelorKa, + casctof.nSigmaXiPositiveLaPr, casctof.nSigmaXiNegativeLaPr, casctof.nSigmaXiBachelorPr, + casctof.nSigmaOmPositiveLaPr, casctof.nSigmaOmNegativeLaPr, casctof.nSigmaOmBachelorPr); } } if (calculateCascTOFPIDs.value) { @@ -1932,9 +1894,6 @@ struct strangenesstofpid { } } } - - mapCollisionTime.clear(); - mapCollisionTimeError.clear(); } void processDerivedData(soa::Join const& collisions, V0DerivedDatas const& V0s, CascDerivedDatas const& cascades, dauTracks const& dauTrackTable, aod::DauTrackTOFPIDs const& dauTrackTOFPIDs) @@ -1963,6 +1922,8 @@ struct strangenesstofpid { initCCDB(collision.runNumber()); } + mTOFResponse->processSetup(collisions.iteratorAt(0)); + // hold indices std::vector tofIndices(dauTrackTable.size(), -1); @@ -2051,6 +2012,18 @@ struct strangenesstofpid { v0tof.nSigmaPositiveLambdaPr, v0tof.nSigmaNegativeLambdaPi, v0tof.nSigmaNegativeLambdaPr, v0tof.nSigmaPositiveLambdaPi, v0tof.nSigmaPositiveK0ShortPi, v0tof.nSigmaNegativeK0ShortPi); + + if (calculateV0sNSigmaAll.value > 0) { + v0tofnsigmasall( + v0tof.nSigmaPositivePhotonEl, v0tof.nSigmaPositiveK0ShortEl, v0tof.nSigmaPositiveLambdaEl, + v0tof.nSigmaNegativePhotonEl, v0tof.nSigmaNegativeK0ShortEl, v0tof.nSigmaNegativeLambdaEl, + v0tof.nSigmaPositivePhotonPi, v0tof.nSigmaPositiveK0ShortPi, v0tof.nSigmaPositiveLambdaPi, + v0tof.nSigmaNegativePhotonPi, v0tof.nSigmaNegativeK0ShortPi, v0tof.nSigmaNegativeLambdaPi, + v0tof.nSigmaPositivePhotonKa, v0tof.nSigmaPositiveK0ShortEl, v0tof.nSigmaPositiveLambdaEl, + v0tof.nSigmaNegativePhotonKa, v0tof.nSigmaNegativeK0ShortEl, v0tof.nSigmaNegativeLambdaEl, + v0tof.nSigmaPositivePhotonPr, v0tof.nSigmaPositiveK0ShortPr, v0tof.nSigmaPositiveLambdaPr, + v0tof.nSigmaNegativePhotonPr, v0tof.nSigmaNegativeK0ShortPr, v0tof.nSigmaNegativeLambdaPr); + } } if (calculateV0TOFPIDs.value) { v0tofpid(v0tof.deltaTimePositiveLambdaPi, v0tof.deltaTimePositiveLambdaPr, @@ -2114,7 +2087,7 @@ struct strangenesstofpid { nTof.tofExpMom = nTofExt.tofExpMom(); nTof.tofEvTime = reassociateTracks.value ? collision.eventTime() : nTofExt.tofEvTime(); - nTof.tofEvTimeErr = reassociateTracks.value ? collision.eventTime() : nTofExt.tofEvTimeErr(); + nTof.tofEvTimeErr = reassociateTracks.value ? collision.eventTimeErr() : nTofExt.tofEvTimeErr(); // nTof.tofEvTimeErr = nTofExt.tofEvTimeErr(); nTof.tofSignal = nTofExt.tofSignal() + (doBCshift.value ? deltaTimeBc : 0.0f); nTof.length = nTofExt.length(); @@ -2147,6 +2120,18 @@ struct strangenesstofpid { casctofnsigmas( casctof.nSigmaXiLaPi, casctof.nSigmaXiLaPr, casctof.nSigmaXiPi, casctof.nSigmaOmLaPi, casctof.nSigmaOmLaPr, casctof.nSigmaOmKa); + + if (calculateCascadesNSigmaAll.value > 0) { + casctofnsigmasall( + casctof.nSigmaXiPositiveLaEl, casctof.nSigmaXiNegativeLaEl, casctof.nSigmaXiBachelorEl, + casctof.nSigmaOmPositiveLaEl, casctof.nSigmaOmNegativeLaEl, casctof.nSigmaOmBachelorEl, + casctof.nSigmaXiPositiveLaPi, casctof.nSigmaXiNegativeLaPi, casctof.nSigmaXiBachelorPi, + casctof.nSigmaOmPositiveLaPi, casctof.nSigmaOmNegativeLaPi, casctof.nSigmaOmBachelorPi, + casctof.nSigmaXiPositiveLaKa, casctof.nSigmaXiNegativeLaKa, casctof.nSigmaXiBachelorKa, + casctof.nSigmaOmPositiveLaKa, casctof.nSigmaOmNegativeLaKa, casctof.nSigmaOmBachelorKa, + casctof.nSigmaXiPositiveLaPr, casctof.nSigmaXiNegativeLaPr, casctof.nSigmaXiBachelorPr, + casctof.nSigmaOmPositiveLaPr, casctof.nSigmaOmNegativeLaPr, casctof.nSigmaOmBachelorPr); + } } if (calculateCascTOFPIDs.value) { casctofpids( diff --git a/PWGLF/Tasks/GlobalEventProperties/PseudorapidityDensityMFT.cxx b/PWGLF/Tasks/GlobalEventProperties/PseudorapidityDensityMFT.cxx index 27e11cebe8b..50ec3c8889e 100644 --- a/PWGLF/Tasks/GlobalEventProperties/PseudorapidityDensityMFT.cxx +++ b/PWGLF/Tasks/GlobalEventProperties/PseudorapidityDensityMFT.cxx @@ -10,8 +10,8 @@ // or submit itself to any jurisdiction. /// \file PseudorapidityDensityMFT.cxx -/// \author Sarah Herrmann /// \author Tulika Tripathy +/// \author Sarah Herrmann /// \brief This code loops over MFT tracks and collisions and fills histograms /// useful to compute dNdeta @@ -69,38 +69,38 @@ using namespace o2::framework::expressions; using namespace o2::aod::track; using namespace o2::aod::rctsel; -AxisSpec ptAxis = {2001, -0.005, 20.005}; -AxisSpec deltazAxis = {6100, -6.1, 6.1}; -AxisSpec zAxis = {3001, -30.1, 30.1}; -AxisSpec phiAxis = {629, 0, o2::constants::math::TwoPI, "Rad", "phi axis"}; -AxisSpec etaAxis = {18, -4.6, -1.}; -// AxisSpec dcaXyAxis = {2000, -10, 10}; -// AxisSpec dcaZAxis = {2000, -10, 10}; -// AxisSpec dcaXAxis = {2000, -10, 10}; -// AxisSpec dcaYAxis = {2000, -10, 10};// previous AxisSpec dcaYAxis = {2000, -10, 10}; - -AxisSpec dcaXyAxis = {6000, -30, 30}; -AxisSpec dcaZAxis = {6000, -30, 30}; -AxisSpec dcaXAxis = {6000, -30, 30}; -AxisSpec dcaYAxis = {6000, -30, 30}; // previous AxisSpec dcaYAxis = {2000, -10, 10}; -// AxisSpec dcaXyAxis = {600, -0.15f, 0.15f}; -// AxisSpec dcaZAxis = {600, -0.15f, 0.15f}; -// AxisSpec dcaXAxis = {600, -0.15f, 0.15f}; -// AxisSpec dcaYAxis = {600, -0.15f, 0.15f}; +const AxisSpec ptAxis = {2001, -0.005, 20.005}; +const AxisSpec deltazAxis = {6100, -6.1, 6.1}; +const AxisSpec zAxis = {3001, -30.1, 30.1}; +const AxisSpec phiAxis = {629, 0, o2::constants::math::TwoPI, "Rad", "phi axis"}; // do not change +const AxisSpec etaAxis = {18, -4.6, -1.}; // do not change +// const AxisSpec dcaXyAxis = {2000, -10, 10}; +// const AxisSpec dcaZAxis = {2000, -10, 10}; +// const AxisSpec dcaXAxis = {2000, -10, 10}; +// const AxisSpec dcaYAxis = {2000, -10, 10};// previous AxisSpec dcaYAxis = {2000, -10, 10}; + +const AxisSpec dcaXyAxis = {6000, -30, 30}; +const AxisSpec dcaZAxis = {6000, -30, 30}; +const AxisSpec dcaXAxis = {6000, -30, 30}; +const AxisSpec dcaYAxis = {6000, -30, 30}; // previous AxisSpec dcaYAxis = {2000, -10, 10}; +// const AxisSpec dcaXyAxis = {600, -0.15f, 0.15f}; +// const AxisSpec dcaZAxis = {600, -0.15f, 0.15f}; +// const AxisSpec dcaXAxis = {600, -0.15f, 0.15f}; +// const AxisSpec dcaYAxis = {600, -0.15f, 0.15f}; // bin width 0.0005 cm: range [-30, 30] cm => 60/0.0005 = 120000 bins // Keep bin width = 0.0005 cm (5 um): range [-1, 1] cm => 2.0/0.0005 = 4000 bins -// AxisSpec axisBinsDCA = {600, -0.15f, 0.15f, "#it{dca}_{xy} (cm)"}; -AxisSpec centAxis = {{0, 10, 20, 30, 40, 50, 60, 70, 80, 100}}; +// const AxisSpec axisBinsDCA = {600, -0.15f, 0.15f, "#it{dca}_{xy} (cm)"}; +const AxisSpec centAxis = {{0, 10, 20, 30, 40, 50, 60, 70, 80, 100}}; // Vertex position axes (cm) -AxisSpec vxAxis = {200, -0.5, 0.5, "V_{x} (cm)"}; -AxisSpec vyAxis = {200, -0.5, 0.5, "V_{y} (cm)"}; +const AxisSpec vxAxis = {200, -0.5, 0.5, "V_{x} (cm)"}; +const AxisSpec vyAxis = {200, -0.5, 0.5, "V_{y} (cm)"}; // Status axis for reco/truth (1=reco, 2=true) -AxisSpec recoTruthStatusAxis = {2, 0.5, 2.5, "status"}; +const AxisSpec recoTruthStatusAxis = {2, 0.5, 2.5, "status"}; // Delta-vertex axes (reco - true) in cm -AxisSpec deltaVxAxis = {400, -0.5, 0.5, "#DeltaV_{x} = V_{x}^{rec}-V_{x}^{true} (cm)"}; -AxisSpec deltaVyAxis = {400, -0.5, 0.5, "#DeltaV_{y} = V_{y}^{rec}-V_{y}^{true} (cm)"}; +const AxisSpec deltaVxAxis = {400, -0.5, 0.5, "#DeltaV_{x} = V_{x}^{rec}-V_{x}^{true} (cm)"}; +const AxisSpec deltaVyAxis = {400, -0.5, 0.5, "#DeltaV_{y} = V_{y}^{rec}-V_{y}^{true} (cm)"}; static constexpr TrackSelectionFlags::flagtype TrackSelectionIts = TrackSelectionFlags::kITSNCls | TrackSelectionFlags::kITSChi2NDF | @@ -153,10 +153,10 @@ struct PseudorapidityDensityMFT { Preslice perMcCol = aod::mcparticle::mcCollisionId; Preslice perColCentral = aod::track::collisionId; - Service pdg; + Service pdg{}; // --- CCDB magnetic field (needed for propagateToDCAhelix in this device) --- - Service ccdbMgr; + Service ccdbMgr{}; Configurable ccdburlMag{"ccdburlMag", "http://alice-ccdb.cern.ch", "CCDB url for GRPMagField"}; Configurable grpmagPathMag{"grpmagPathMag", "GLO/Config/GRPMagField", @@ -165,7 +165,7 @@ struct PseudorapidityDensityMFT { int magRunNumber = -1; float bzMFT = 0.f; o2::parameters::GRPMagField* grpmag = nullptr; - static constexpr double CenterMft[3] = {0., 0., -61.4}; + static constexpr std::array CenterMft{0., 0., -61.4}; enum class GenRecoCutBin : int { AllRecoCollisions = 1, @@ -196,6 +196,7 @@ struct PseudorapidityDensityMFT { NoTimeFrameBorder, NoITSROFrameBorder, NoSameBunchPileup, + UseGoodItsLayersAll, GoodZvtxFT0vsPV, NoCollInRofStandard, NoCollInRofStrict, @@ -294,18 +295,8 @@ struct PseudorapidityDensityMFT { } static constexpr int NoCompatibleCollisions = 0; static constexpr int SingleCompatibleCollision = 1; - - static constexpr int OrphanAmbDegree = 0; - static constexpr int NonAmbiguousAmbDegree = 1; - static constexpr int ChargeUnitTimesThree = 3; - struct EvSelStep { - bool enabled; - uint32_t bit; - GenRecoCutBin bin; - }; - void initMagField(FullBCs::iterator const& bc) { if (magRunNumber == bc.runNumber()) { @@ -324,9 +315,10 @@ struct PseudorapidityDensityMFT { o2::base::Propagator::initFieldFromGRP(grpmag); magRunNumber = bc.runNumber(); - auto* field = static_cast(TGeoGlobalMagField::Instance()->GetField()); + auto* field = dynamic_cast( + TGeoGlobalMagField::Instance()->GetField()); if (field) { - bzMFT = field->getBz(CenterMft); + bzMFT = field->getBz(CenterMft.data()); LOGP(info, "Initialized magnetic field for run {}: bzMFT={} kG", magRunNumber, bzMFT); } else { LOGF(warning, "TGeoGlobalMagField has no field even after initFieldFromGRP; bzMFT=0"); @@ -445,20 +437,20 @@ struct PseudorapidityDensityMFT { "enabled!"); } AxisSpec multAxis = {multBinning, "N_{trk}"}; - auto hstat = registry.get(HIST("EventSelection")); - auto* x = hstat->GetXaxis(); - x->SetBinLabel(static_cast(EventSelectionBin::All), "All"); - x->SetBinLabel(static_cast(EventSelectionBin::Vz), "Vz"); - x->SetBinLabel(static_cast(EventSelectionBin::VzItsRof), "Vz+ITSRof"); - x->SetBinLabel(static_cast(EventSelectionBin::VzSelected), "Vz+Selected"); - x->SetBinLabel(static_cast(EventSelectionBin::Sel8VzInelGt0), "Sel8+Vz+INEL>0"); - x->SetBinLabel(static_cast(EventSelectionBin::SelInelInelFwdGt0), "Sel INEL,INEL_fwd>0"); - x->SetBinLabel(static_cast(EventSelectionBin::Rejected), "Rejected"); - x->SetBinLabel(static_cast(EventSelectionBin::GoodBCs), "Good BCs"); - x->SetBinLabel(static_cast(EventSelectionBin::BCsWithCollisions), "BCs with collisions"); - x->SetBinLabel(static_cast(EventSelectionBin::BCsWithPileupSplitting), "BCs with pile-up/splitting"); - x->SetBinLabel(static_cast(EventSelectionBin::PerCollisionSampleGt0), "percollisionSample>0"); - x->SetBinLabel(static_cast(EventSelectionBin::MidtracksAndPerCollisionSampleGt0), "midtracks+percollisionSample>0"); + auto eventSelectionHist = registry.get(HIST("EventSelection")); + auto* eventSelectionAxis = eventSelectionHist->GetXaxis(); + eventSelectionAxis->SetBinLabel(static_cast(EventSelectionBin::All), "All"); + eventSelectionAxis->SetBinLabel(static_cast(EventSelectionBin::Vz), "Vz"); + eventSelectionAxis->SetBinLabel(static_cast(EventSelectionBin::VzItsRof), "Vz+ITSRof"); + eventSelectionAxis->SetBinLabel(static_cast(EventSelectionBin::VzSelected), "Vz+Selected"); + eventSelectionAxis->SetBinLabel(static_cast(EventSelectionBin::Sel8VzInelGt0), "Sel8+Vz+INEL>0"); + eventSelectionAxis->SetBinLabel(static_cast(EventSelectionBin::SelInelInelFwdGt0), "Sel INEL,INEL_fwd>0"); + eventSelectionAxis->SetBinLabel(static_cast(EventSelectionBin::Rejected), "Rejected"); + eventSelectionAxis->SetBinLabel(static_cast(EventSelectionBin::GoodBCs), "Good BCs"); + eventSelectionAxis->SetBinLabel(static_cast(EventSelectionBin::BCsWithCollisions), "BCs with collisions"); + eventSelectionAxis->SetBinLabel(static_cast(EventSelectionBin::BCsWithPileupSplitting), "BCs with pile-up/splitting"); + eventSelectionAxis->SetBinLabel(static_cast(EventSelectionBin::PerCollisionSampleGt0), "percollisionSample>0"); + eventSelectionAxis->SetBinLabel(static_cast(EventSelectionBin::MidtracksAndPerCollisionSampleGt0), "midtracks+percollisionSample>0"); registry.add({"EventSelectionData", ";cut;events", {HistType::kTH1F, {{16, 0.5, 16.5}}}}); @@ -473,6 +465,7 @@ struct PseudorapidityDensityMFT { x->SetBinLabel(static_cast(DataCutBin::NoTimeFrameBorder), "kNoTimeFrameBorder (if useEvSel)"); x->SetBinLabel(static_cast(DataCutBin::NoITSROFrameBorder), "kNoITSROFrameBorder (if useEvSel)"); x->SetBinLabel(static_cast(DataCutBin::NoSameBunchPileup), "kNoSameBunchPileup"); + x->SetBinLabel(static_cast(DataCutBin::UseGoodItsLayersAll), "kIsGoodITSLayersAll"); x->SetBinLabel(static_cast(DataCutBin::GoodZvtxFT0vsPV), "kIsGoodZvtxFT0vsPV"); x->SetBinLabel(static_cast(DataCutBin::NoCollInRofStandard), "kNoCollInRofStandard (cfg)"); x->SetBinLabel(static_cast(DataCutBin::NoCollInRofStrict), "kNoCollInRofStrict (cfg)"); @@ -1158,12 +1151,12 @@ struct PseudorapidityDensityMFT { ";status;centrality;events", {HistType::kTH1F, {{5, 0.5, 5.5}}}}); auto heff = registry.get(HIST("EventEfficiencymc")); - x = heff->GetXaxis(); - x->SetBinLabel(static_cast(EventEfficiencyBin::Generated), "Generated"); - x->SetBinLabel(static_cast(EventEfficiencyBin::GeneratedInelGt0), "Generated INEL>0"); - x->SetBinLabel(static_cast(EventEfficiencyBin::Reconstructed), "Reconstructed"); - x->SetBinLabel(static_cast(EventEfficiencyBin::Selected), "Selected"); - x->SetBinLabel(static_cast(EventEfficiencyBin::SelectedInelGt0), "Selected INEL>0"); + auto* eventEfficiencyAxis = heff->GetXaxis(); + eventEfficiencyAxis->SetBinLabel(static_cast(EventEfficiencyBin::Generated), "Generated"); + eventEfficiencyAxis->SetBinLabel(static_cast(EventEfficiencyBin::GeneratedInelGt0), "Generated INEL>0"); + eventEfficiencyAxis->SetBinLabel(static_cast(EventEfficiencyBin::Reconstructed), "Reconstructed"); + eventEfficiencyAxis->SetBinLabel(static_cast(EventEfficiencyBin::Selected), "Selected"); + eventEfficiencyAxis->SetBinLabel(static_cast(EventEfficiencyBin::SelectedInelGt0), "Selected INEL>0"); } if (doprocessGen) { @@ -1425,8 +1418,8 @@ struct PseudorapidityDensityMFT { std::vector::iterator> cols; for (const auto& bc : bcs) { if (!useEvSel || - (useEvSel && ((bc.selection_bit(aod::evsel::kIsBBT0A) && - bc.selection_bit(aod::evsel::kIsBBT0C)) != 0))) { + (bc.selection_bit(aod::evsel::kIsBBT0A) && + bc.selection_bit(aod::evsel::kIsBBT0C))) { registry.fill(HIST("EventSelection"), static_cast(EventSelectionBin::GoodBCs)); cols.clear(); for (const auto& collision : collisions) { @@ -1516,7 +1509,7 @@ struct PseudorapidityDensityMFT { { registry.fill(HIST("EventSelection"), static_cast(EventSelectionBin::All)); - if (!useEvSel || (useEvSel && collision.sel8())) { + if (!useEvSel || collision.sel8()) { registry.fill(HIST("EventSelection"), static_cast(EventSelectionBin::VzSelected)); auto z = collision.posZ(); auto perCollisionSample = sampleCentral->sliceByCached( @@ -1542,8 +1535,9 @@ struct PseudorapidityDensityMFT { ((phi > o2::constants::math::PI - cfgPhiCut) && (phi < o2::constants::math::PI + cfgPhiCut)) || (phi > o2::constants::math::TwoPI - cfgPhiCut) || ((phi > ((o2::constants::math::PIHalf - 0.1) * o2::constants::math::PI) - cfgPhiCut) && - (phi < ((o2::constants::math::PIHalf - 0.1) * o2::constants::math::PI) + cfgPhiCut))) + (phi < ((o2::constants::math::PIHalf - 0.1) * o2::constants::math::PI) + cfgPhiCut))) { continue; + } } registry.fill(HIST("TracksEtaZvtx"), track.eta(), z); @@ -1624,16 +1618,17 @@ struct PseudorapidityDensityMFT { const auto passEventSelection = [&](auto const& collision) { struct EvSelStep { - bool enabled; - decltype(aod::evsel::kIsTriggerTVX) bit; - DataCutBin bin; + bool enabled{false}; + decltype(aod::evsel::kIsTriggerTVX) bit{}; + DataCutBin bin{DataCutBin::All}; }; - const std::array steps = {{ + const std::array steps = {{ {useTriggerTVX, aod::evsel::kIsTriggerTVX, DataCutBin::IsTriggerTVX}, {useNoTimeFrameBorderCut, aod::evsel::kNoTimeFrameBorder, DataCutBin::NoTimeFrameBorder}, {useNoITSROFrameBorderCut, aod::evsel::kNoITSROFrameBorder, DataCutBin::NoITSROFrameBorder}, {useNoSameBunchPileup, aod::evsel::kNoSameBunchPileup, DataCutBin::NoSameBunchPileup}, + {useGoodItsLayersAll, aod::evsel::kIsGoodITSLayersAll, DataCutBin::UseGoodItsLayersAll}, {useGoodZvtxFT0vsPV, aod::evsel::kIsGoodZvtxFT0vsPV, DataCutBin::GoodZvtxFT0vsPV}, {useNoCollInRofStandard, aod::evsel::kNoCollInRofStandard, DataCutBin::NoCollInRofStandard}, {useNoCollInRofStrict, aod::evsel::kNoCollInRofStrict, DataCutBin::NoCollInRofStrict}, @@ -1881,8 +1876,9 @@ struct PseudorapidityDensityMFT { ((phi > o2::constants::math::PI - cfgPhiCut) && (phi < o2::constants::math::PI + cfgPhiCut)) || (phi > o2::constants::math::TwoPI - cfgPhiCut) || ((phi > ((o2::constants::math::PIHalf - 0.1) * o2::constants::math::PI) - cfgPhiCut) && - (phi < ((o2::constants::math::PIHalf - 0.1) * o2::constants::math::PI) + cfgPhiCut))) + (phi < ((o2::constants::math::PIHalf - 0.1) * o2::constants::math::PI) + cfgPhiCut))) { continue; + } } registry.fill(HIST("Tracks/Centrality/EtaZvtx"), track.eta(), z, c); @@ -2023,12 +2019,14 @@ struct PseudorapidityDensityMFT { if (usePhiCut) { if ((phi <= PhiVetoLow) || ((phi >= PhiVetoPiMin) && (phi <= PhiVetoPiMax)) || - (phi >= PhiVetoHigh)) + (phi >= PhiVetoHigh)) { continue; + } } if (usePtCut) { - if (ptCut > cfgnPt) + if (ptCut > cfgnPt) { continue; + } } if (cfgnEta1 < particle.eta() && particle.eta() < cfgnEta2 && (phi > cfgPhiCut1 && phi < cfgPhiCut2)) { registry.fill(HIST("TracksEtaZvtxGen_t"), particle.eta(), @@ -2086,7 +2084,7 @@ struct PseudorapidityDensityMFT { if constexpr (ExColsGenCent::template contains()) { cRec = collision.centFT0C(); } - if (!useEvSel || (useEvSel && collision.sel8())) { + if (!useEvSel || collision.sel8()) { if constexpr (ExColsGenCent::template contains()) { if (!atLeastOne) { cGen = cRec; @@ -2162,7 +2160,7 @@ struct PseudorapidityDensityMFT { soa::Join::iterator const& collision, MFTTracksLabeled const& tracks, aod::McParticles const&) { - if (!useEvSel || (useEvSel && collision.sel8())) { + if (!useEvSel || collision.sel8()) { for (const auto& track : tracks) { if (!track.has_mcParticle()) { continue; @@ -2204,9 +2202,9 @@ struct PseudorapidityDensityMFT { const auto countAndPassEvSelGenReco = [&](auto const& collision) { struct EvSelStep { - bool enabled; - decltype(aod::evsel::kIsTriggerTVX) bit; - GenRecoCutBin bin; + bool enabled{false}; + decltype(aod::evsel::kIsTriggerTVX) bit{}; + GenRecoCutBin bin{GenRecoCutBin::AllRecoCollisions}; }; const std::array steps = {{ @@ -2337,7 +2335,7 @@ struct PseudorapidityDensityMFT { } const int recoCol = track.collisionId(); - if (acceptedRecoCols.find(recoCol) == acceptedRecoCols.end()) { + if (!acceptedRecoCols.contains(recoCol)) { continue; } @@ -2511,9 +2509,9 @@ struct PseudorapidityDensityMFT { const auto countAndPassEvSelGenReco = [&](auto const& collision) { struct EvSelStep { - bool enabled; - decltype(aod::evsel::kIsTriggerTVX) bit; - GenRecoCutBin bin; + bool enabled{false}; + decltype(aod::evsel::kIsTriggerTVX) bit{}; + GenRecoCutBin bin{GenRecoCutBin::AllRecoCollisions}; }; const std::array steps = {{ @@ -2671,7 +2669,6 @@ struct PseudorapidityDensityMFT { std::unordered_set uniqueBestRecoCols; if (tracks.size() > 0) { - bool countedPrimary = false; for (const auto& track : tracks) { const auto originalTrack = track.template mfttrack_as(); float ndf = getTrackNdf(originalTrack); @@ -2724,7 +2721,7 @@ struct PseudorapidityDensityMFT { // std::cout << " track.collisionId() " << track.collisionId() << "track.bestCollisionId()" << track.bestCollisionId() << std::endl; // " track.globalIndex() "<(SingleCountBin::Count)); registry.fill(HIST("Purity/SelectedAfterDCAxy/PrimaryAllEta"), mcPart.eta()); - countedPrimary = true; registry.fill(HIST("Purity/PurityOverall"), static_cast(SingleCountBin::Count), - countedPrimary ? static_cast(BoolBin::Yes) - : static_cast(BoolBin::No)); + isPrimaryCharged ? static_cast(BoolBin::Yes) + : static_cast(BoolBin::No)); registry.fill(HIST("Purity/PurityVsEta"), originalTrack.eta(), - countedPrimary ? static_cast(BoolBin::Yes) - : static_cast(BoolBin::No)); + isPrimaryCharged ? static_cast(BoolBin::Yes) + : static_cast(BoolBin::No)); } // hasmclable } // track loop } // track>mid @@ -3249,12 +3245,14 @@ struct PseudorapidityDensityMFT { if (usePhiCut) { if ((phi <= PhiVetoLow) || ((phi >= PhiVetoPiMin) && (phi <= PhiVetoPiMax)) || - (phi >= PhiVetoHigh)) + (phi >= PhiVetoHigh)) { continue; + } } if (usePtCut) { - if (ptCut > cfgnPt) + if (ptCut > cfgnPt) { continue; + } } if (cfgnEta1 < particle.eta() && particle.eta() < cfgnEta2 && (phi > cfgPhiCut1 && phi < cfgPhiCut2)) { if (onlyVz) { diff --git a/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx b/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx index c81c941d864..136f76845be 100644 --- a/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx +++ b/PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx @@ -56,10 +56,8 @@ #include #include #include -#include #include #include -#include #include @@ -85,10 +83,7 @@ using namespace o2::constants::math; using namespace o2::aod::rctsel; auto static constexpr CminCharge = 3.f; -static constexpr int CnullInt = 0; static constexpr float Cnull = 0.0f; -static constexpr int ConeInt = 1; -static constexpr int CtwoInt = 2; static constexpr float Cone = 1.0f; // FV0 specific constants @@ -99,20 +94,11 @@ const std::array cFV0IndexPhi{0, 8, 16, 24, 32}; static constexpr float CmaxEtaFV0 = 5.1; static constexpr float CminEtaFV0 = 2.2; static constexpr float CdEtaFV0 = (CmaxEtaFV0 - CminEtaFV0) / CmaxRingsFV0; -auto static constexpr CminAccFT0A = 3.5f; -auto static constexpr CmaxAccFT0A = 4.9f; -auto static constexpr CminAccFT0C = -3.3f; -auto static constexpr CmaxAccFT0C = -2.1f; // PID names static constexpr int CprocessIdWeak = 4; -static constexpr int Ncharges = 2; static constexpr o2::track::PID::ID Npart = 5; -static constexpr o2::track::PID::ID NpartChrg = Npart * Ncharges; const std::array pDGs{11, 13, 211, 321, 2212}; -const std::array pIdSgn{11, 13, 211, 321, 2212, -11, -13, -211, -321, -2212}; -const std::array pID{"el", "mu", "pi", "ka", "pr"}; -const std::array pIdChrg{"e^{-}", "#mu^{-}", "#pi^{+}", "K^{+}", "p", "e^{+}", "#mu^{+}", "#pi^{-}", "K^{-}", "#bar{p}"}; static constexpr std::array CspeciesAll{"El", "Mu", "Pi", "Ka", "Pr"}; // histogram naming @@ -219,19 +205,36 @@ enum EvtSel { nEvtSel }; +enum class MCEventStatus { + kMcEvtAll = 0, + kEvtSelected, + kEvtHasMcColl, + kEvtSplitVtxRemoved, + nEvtMcEventStatus +}; + struct MultE { static constexpr int CnoMult = 0; - static constexpr int CmultFT0M = 1; - static constexpr int CmultTPC = 2; + static constexpr int CmultFT0C = 1; + static constexpr int CmultFT0M = 2; + static constexpr int CmultTPC = 3; }; - +/* +template +concept hasFT0C = requires(C::iterator const& c) { + c.centFT0C(); +}; +template +concept hasFT0M = requires(C::iterator const& c) { + c.centFT0M(); +}; +*/ struct FlattenictyPikp { HistogramRegistry registryData{"registryData", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry registryMC{"registryMC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; HistogramRegistry registryQC{"registryQC", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; - OutputObj listEfficiency{"Efficiency"}; Service pdg{}; std::vector fv0AmplCorr; @@ -241,7 +244,7 @@ struct FlattenictyPikp { o2::parameters::GRPMagField* grpmag = nullptr; struct : ConfigurableGroup { - Configurable multEst{"multEst", 1, "0: without multiplicity; 1: MultFT0M; 2: MultTPC"}; + Configurable multEst{"multEst", 2, "0: without multiplicity; 1: MultFT0C; 2: MultFT0M; 3: MultTPC"}; Configurable applyCalibGainFromCCDB{"applyCalibGainFromCCDB", false, "equalize detector amplitudes"}; Configurable applyCalibVtxFromCCDB{"applyCalibVtxFromCCDB", false, "equalize Amp vs vtx"}; Configurable applyCalibDeDx{"applyCalibDeDx", false, "calibration of dedx signal"}; @@ -283,13 +286,14 @@ struct FlattenictyPikp { Configurable cutVtxZ{"cutVtxZ", 10.0f, "Accepted z-vertex range"}; Configurable zVtxCutMC{"zVtxCutMC", true, "use Zvtx cut in MC"}; Configurable useINELCutMC{"useINELCutMC", true, "use INEL>0 cut in MC"}; - Configurable removeNoSameBunchPileup{"removeNoSameBunchPileup", true, "Reject collisions in case of pileup with another collision in the same foundBC"}; - Configurable requireIsGoodZvtxFT0vsPV{"requireIsGoodZvtxFT0vsPV", true, "Small difference between z-vertex from PV and from FT0"}; + Configurable removeNoSameBunchPileup{"removeNoSameBunchPileup", false, "Reject collisions in case of pileup with another collision in the same foundBC"}; + Configurable requireIsGoodZvtxFT0vsPV{"requireIsGoodZvtxFT0vsPV", false, "Small difference between z-vertex from PV and from FT0"}; Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", false, "At least one ITS-TPC track (reject vertices built from ITS-only tracks)"}; Configurable requirekIsVertexTOFmatched{"requirekIsVertexTOFmatched", false, "Require kIsVertexTOFmatched: at least one of vertex contributors is matched to TOF"}; Configurable useMultMCmidrap{"useMultMCmidrap", true, "use generated Nch in ∣eta∣ < 0.8"}; Configurable useInelgt0wTVX{"useInelgt0wTVX", true, "Use INEL > 0 condition with TVX trigger, i.e. FT0A and FT0C acceptance"}; Configurable removeSplitVertex{"removeSplitVertex", true, "Remove split vertices"}; + // Configurable customGenCent{"customGenCent", false, "Use custom generated MC centrality estimation"}; } evtSelOpt; struct : ConfigurableGroup { @@ -297,7 +301,7 @@ struct FlattenictyPikp { ConfigurableAxis axisPtV0s{"axisPtV0s", {VARIABLE_WIDTH, 0, 0.15, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.2, 1.4, 1.6, 1.8, 2, 2.2, 2.4, 2.6, 2.8, 3, 3.2, 3.4, 3.6, 3.8, 4, 4.4, 4.8, 5.2, 5.6, 6, 6.4, 6.8, 7.2, 7.6, 8, 8.4, 8.8, 9.2, 9.6, 10, 10.5, 11, 11.5, 12, 12.5, 13, 13.5, 14, 14.5, 15, 20}, "pT V0s binning"}; ConfigurableAxis axisPtFine{"axisPtFine", {250, 0.1f, 20.1f}, "pT fine binning"}; ConfigurableAxis axisFlatPerc{"axisFlatPerc", {102, -0.01, 1.01}, "Flattenicity percentiles binning"}; - ConfigurableAxis axisMultPerc{"axisMultPerc", {VARIABLE_WIDTH, 0., 5., 10., 20., 30., 40., 50., 60., 70., 80., 90., 100.}, "T0 percentiles binning"}; + ConfigurableAxis axisMultPerc{"axisMultPerc", {VARIABLE_WIDTH, 0., 1., 5., 10., 15., 20., 30., 40., 50., 70., 100.}, "Multiplicity percentiles binning"}; ConfigurableAxis axisVertexZ{"axisVertexZ", {80, -20., 20.}, "Vertex z binning"}; ConfigurableAxis axisMult{"axisMult", {301, -0.5, 300.5}, "Multiplicity binning"}; ConfigurableAxis axisDCAxy{"axisDCAxy", {210, -1.05f, 1.05f}, "DCAxy binning"}; @@ -310,7 +314,7 @@ struct FlattenictyPikp { ConfigurableAxis axisNsigmaTPC{"axisNsigmaTPC", {200, -10, 10}, "nsigmaTPC binning"}; ConfigurableAxis axisNsigmaTOF{"axisNsigmaTOF", {200, -10, 10}, "nsigmaTOF binning"}; ConfigurableAxis axisAmplFV0{"axisAmplFV0", {4096, 0, 4096}, "FV0 amplitude (ADC) binning"}; - ConfigurableAxis axisAmplFV0Sum{"axisAmplFV0Sum", {4096, 0, 4096 * 49}, "FV0 amplitude sum (ADC) binning"}; + ConfigurableAxis axisAmplFV0Sum{"axisAmplFV0Sum", {4096, 0, 4096}, "FV0 amplitude sum (ADC) binning"}; ConfigurableAxis axisChannelFV0{"axisChannelFV0", {49, 0., 49.}, "FV0 channel ID binning"}; } binOpt; @@ -319,9 +323,9 @@ struct FlattenictyPikp { Configurable rapMax{"rapMax", 0.5f, "Maximum range of rapidity for tracks"}; Configurable trkPtMin{"trkPtMin", 0.1f, "Minimum pT of tracks"}; Configurable applyNcl{"applyNcl", false, "Apply cut on TPC clusters"}; - Configurable nclTPCMin{"nclTPCMin", 135.0f, "Minimum of number of TPC found clusters"}; + Configurable nclTPCMin{"nclTPCMin", 130.0f, "Minimum of number of TPC found clusters"}; Configurable applyNclPID{"applyNclPID", true, "Apply cut on TPC PID clusters"}; - Configurable nclPidTPCMin{"nclPidTPCMin", 135.0f, "Minimum of number of TPC PID clusters"}; + Configurable nclPidTPCMin{"nclPidTPCMin", 130.0f, "Minimum of number of TPC PID clusters"}; Configurable phiCutPtMin{"phiCutPtMin", 2.0f, "Minimum pT for phi cut"}; Configurable tofBetaPion{"tofBetaPion", 1.0f, "Minimum beta for TOF pions"}; Configurable tofBetaPiMax{"tofBetaPiMax", 5E-5, "Maximum beta for TOF pion selection"}; @@ -347,7 +351,7 @@ struct FlattenictyPikp { struct : ConfigurableGroup { // common selection Configurable v0TypeSel{"v0TypeSel", 1, "select on a certain V0 type (leave negative if no selection desired)"}; - Configurable v0Ymax{"v0Ymax", 0.5f, "Maximum rapidity of V0s"}; + Configurable v0Ymax{"v0Ymax", 0.8f, "Maximum rapidity of V0s"}; Configurable rejectV0sAtTPCSector{"rejectV0sAtTPCSector", true, "Reject V0s close to the TPC sector boundaries"}; Configurable v0requireITS{"v0requireITS", true, "Additional cut on the ITS requirement"}; Configurable nsigmaElTPC{"nsigmaElTPC", 5.0, "max nsigma of TPC for electorn"}; @@ -363,9 +367,9 @@ struct FlattenictyPikp { Configurable v0etamax{"v0etamax", +0.8f, "max eta of V0s"}; Configurable v0minNCrossedRowsTPC{"v0minNCrossedRowsTPC", 70, "Additional cut on the minimum number of crossed rows in the TPC"}; Configurable applyV0sNclFound{"applyV0sNclFound", false, "Apply cut on TPC Found clusters"}; - Configurable v0NclTPCMin{"v0NclTPCMin", 135.0f, "Minimum of number of TPC found clusters"}; + Configurable v0NclTPCMin{"v0NclTPCMin", 130.0f, "Minimum of number of TPC found clusters"}; Configurable applyV0sNclPID{"applyV0sNclPID", true, "Apply cut on TPC PID clusters"}; - Configurable v0NclPidTPCMin{"v0NclPidTPCMin", 135.0f, "Minimum of number of TPC PID clusters"}; + Configurable v0NclPidTPCMin{"v0NclPidTPCMin", 130.0f, "Minimum of number of TPC PID clusters"}; Configurable v0maxChi2PerClusterTPC{"v0maxChi2PerClusterTPC", 4.f, "Additional cut on the maximum value of the chi2 per cluster in the TPC"}; Configurable v0maxChi2PerClusterITS{"v0maxChi2PerClusterITS", 36.f, "Additional cut on the maximum value of the chi2 per cluster in the ITS"}; Configurable v0minITSnClusters{"v0minITSnClusters", 4, "minimum number of found ITS clusters"}; @@ -449,7 +453,7 @@ struct FlattenictyPikp { Configurable maxChi2PerClusterITS{"maxChi2PerClusterITS", 36.f, "Additional cut on the maximum value of the chi2 per cluster in the ITS"}; Configurable minITSnClusters{"minITSnClusters", 5, "minimum number of found ITS clusters"}; Configurable maxDcaXYFactor{"maxDcaXYFactor", 1.f, "Multiplicative factor on the maximum value of the DCA xy"}; - Configurable maxDcaZ{"maxDcaZ", 2.f, "Additional cut on the maximum value of the DCA z"}; + Configurable maxDcaZ{"maxDcaZ", 0.1f, "Additional cut on the maximum value of the DCA z"}; TF1* fPhiCutLow = nullptr; TF1* fPhiCutHigh = nullptr; @@ -459,33 +463,12 @@ struct FlattenictyPikp { std::vector> fEDeDxVsEta; std::vector> vecParamsPLA; - std::array, NpartChrg> hPtGenRecEvt{}; - std::array, NpartChrg> hPtGenPrimRecEvt{}; - std::array, NpartChrg> hPtGenRecEvtGtZero{}; - std::array, NpartChrg> hPtGenPrimRecEvtGtZero{}; - std::array, NpartChrg> hPtEffRec{}; - std::array, NpartChrg> hPtEffGen{}; - std::array, NpartChrg> hPtEffRecGoodCollPrim{}; - std::array, NpartChrg> hPtEffRecGoodCollWeak{}; - std::array, NpartChrg> hPtEffRecGoodCollMat{}; - std::array, NpartChrg> hPtEffGenPrim{}; - std::array, NpartChrg> hPtEffGenWeak{}; - std::array, NpartChrg> hPtEffGenMat{}; - std::array, NpartChrg> hPtEffGenPrimEvtSelGen{}; - std::array, NpartChrg> hPtEffGenWeakEvtSelGen{}; - std::array, NpartChrg> hPtEffGenMatEvtSelGen{}; - std::array, NpartChrg> hDCAxyRecBadCollPrim{}; - std::array, NpartChrg> hDCAxyRecBadCollWeak{}; - std::array, NpartChrg> hDCAxyRecBadCollMat{}; - std::array, NpartChrg> hPtVsDCAxyRecGoodCollPrim{}; - std::array, NpartChrg> hPtVsDCAxyRecGoodCollWeak{}; - std::array, NpartChrg> hPtVsDCAxyRecGoodCollMat{}; - using MyCollisions = soa::Join; using Colls = soa::Join; using CollsGen = soa::Join; - using MCColls = soa::Join; - using CollsMCExtraMult = soa::Join; + using MCColls = soa::Join; + using CollsMCExtraMult = soa::Join; + // using CollsMCExtraMultPercentile = soa::Join; using CollsGenSgn = soa::SmallGroups>; using MyPIDTracks = soa::Join; using MyLabeledTracks = soa::Join; @@ -591,9 +574,12 @@ struct FlattenictyPikp { AxisSpec multAxis{binOpt.axisMultPerc, "multiplicity estimator"}; - switch (defOpt.multEst) { + switch (defOpt.multEst.value) { case MultE::CnoMult: break; + case MultE::CmultFT0C: + multAxis.name = "multFT0C"; + break; case MultE::CmultFT0M: multAxis.name = "multFT0M"; break; @@ -601,7 +587,7 @@ struct FlattenictyPikp { multAxis.name = "multTPC"; break; default: - LOG(fatal) << "No valid option for mult estimator " << defOpt.multEst; + LOGF(fatal, "No valid option for mult estimator %d", defOpt.multEst.value); } if (trkSelOpt.rejectTrkAtTPCSector || v0SelOpt.rejectV0sAtTPCSector) { @@ -637,7 +623,6 @@ struct FlattenictyPikp { registryQC.get(HIST("Tracks/hTrkSel"))->GetXaxis()->SetBinLabel(trkSelTPCBndr + 1, "TPC Boundary"); // Number of tracks vs centrality registryQC.add("Events/hNchVsCent", "Measured Nch vs Cent; centrality; Nch (|#eta|<0.8)", {kTH2F, {nChAxis, multAxis}}); - registryQC.add("Tracks/hPtRes", "#it{p}_{T} resolution;;(#it{p}_{T}_{rec} - #it{p}_{T}_{gen})/#it{p}_{T}_{gen};", kTH2F, {ptAxis, {100, -1.0, 1.0}}); // FV0 QA registryQC.add("FV0/hFV0AmplWCalib", "", {kTH2F, {channelFV0Axis, amplitudeFV0}}); registryQC.add("FV0/hFV0AmplvsVtxzWoCalib", "", {kTH2F, {vtxzAxis, amplitudeFV0Sum}}); @@ -651,19 +636,7 @@ struct FlattenictyPikp { registryQC.print(); if (doprocessFlat) { - // V0 counter - registryData.add("Tracks/V0qa/hV0Sel", "Number of V0s; Cut; #Tracks Passed Cut", {kTH1F, {{nV0Sel, 0, nV0Sel}}}); - registryData.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelAll + 1, "All"); - registryData.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelRejectSameSign + 1, "Reject same sign"); - registryData.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelRejectV0sAtTPCSector + 1, "Reject V0s at TPC sector"); - registryData.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelCosPA + 1, "Cos PA"); - registryData.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelV0radius + 1, "V0 radius"); - registryData.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelDCAposToPV + 1, "DCA pos to PV"); - registryData.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelDaughters + 1, "V0 daughters' sel."); - registryData.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelDCAv0daughter + 1, "DCA v0 daughter"); - registryData.add("Events/hFlatVsMultEst", "hFlatVsMultEst", kTH2F, {flatAxis, multAxis}); - registryData.add("Tracks/postSel/hPVsPtEta", "; #it{p} (GeV/#it{c}); #it{p}_{T} (GeV/#it{c}); #eta;", {kTH3F, {pAxis, ptAxis, etaAxis}}); if (defOpt.fillNclVsPhiCutQaHist || defOpt.fillTrackQaHist || defOpt.filldEdxQaHist || defOpt.fillDCAxyHist) { if (defOpt.fillNclVsPhiCutQaHist) { registryData.add("Tracks/postSel/hPtPhi", "; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9)", {kTH2F, {ptAxis, phiAxisMod}}); @@ -685,6 +658,7 @@ struct FlattenictyPikp { registryData.add("Tracks/postSel/hPt", "", kTH1F, {ptAxis}); registryData.add("Tracks/postSel/hPhi", "", kTH1F, {phiAxis}); registryData.add("Tracks/postSel/hEta", "", kTH1F, {etaAxis}); + registryData.add("Tracks/postSel/hPVsPtEta", "; #it{p} (GeV/#it{c}); #it{p}_{T} (GeV/#it{c}); #eta;", {kTHnSparseF, {pAxis, ptAxis, etaAxis}}); registryData.add("Tracks/postSel/hTpcInnerParamVsP", ";Global track p (GeV/#it{c});Track p at inner wall of the TPC (GeV/#it{c});", kTH2F, {pAxis, pAxis}); registryData.add("Tracks/postSel/hDCAXYvsPt", "", kTH2F, {ptFineAxis, dcaXYAxis}); registryData.add("Tracks/postSel/hDCAZvsPt", "", kTH2F, {ptFineAxis, dcaZAxis}); @@ -709,11 +683,11 @@ struct FlattenictyPikp { } registryData.add("Tracks/postCalib/all/hMIPVsPhi", "; #varphi; #LT dE/dx #GT_{MIP, primary tracks};", {kTH2F, {phiAxis, dEdxAxis}}); registryData.add("Tracks/postCalib/all/pMIPVsPhi", "; #varphi; #LT dE/dx #GT_{MIP, primary tracks};", {kTProfile, {phiAxis}}); - registryData.add("Tracks/postCalib/all/hMIPVsPhiVsEta", "; #varphi; #LT dE/dx #GT_{MIP, primary tracks}; #eta;", {kTH3F, {phiAxis, dEdxAxis, etaAxis}}); + registryData.add("Tracks/postCalib/all/hMIPVsPhiVsEta", "; #varphi; #LT dE/dx #GT_{MIP, primary tracks}; #eta;", {kTHnSparseF, {phiAxis, dEdxAxis, etaAxis}}); registryData.add("Tracks/postCalib/all/hMIPNClTPCPidvsEta", ";#eta; Ncl pid", {kTH2F, {etaAxis, clTpcAxis}}); registryData.add("Tracks/postCalib/all/hPlateauVsPhi", "; #varphi; #LT dE/dx #GT_{Plateau, primary tracks};", {kTH2F, {phiAxis, dEdxAxis}}); registryData.add("Tracks/postCalib/all/pPlateauVsPhi", "; #varphi; #LT dE/dx #GT_{Plateau, primary tracks};", {kTProfile, {phiAxis}}); - registryData.add("Tracks/postCalib/all/hPlateauVsPhiVsEta", "; #varphi; #LT dE/dx #GT_{Plateau, primary tracks}; #eta;", {kTH3F, {phiAxis, dEdxAxis, etaAxis}}); + registryData.add("Tracks/postCalib/all/hPlateauVsPhiVsEta", "; #varphi; #LT dE/dx #GT_{Plateau, primary tracks}; #eta;", {kTHnSparseF, {phiAxis, dEdxAxis, etaAxis}}); registryData.add("Tracks/postCalib/all/hPlateauNClTPCPidvsEta", ";#eta; Ncl pid", {kTH2F, {etaAxis, clTpcAxis}}); registryData.addClone("Tracks/postCalib/all/", "Tracks/preCalib/all/"); if (defOpt.fillChrgType) { @@ -730,29 +704,37 @@ struct FlattenictyPikp { } } registryData.addClone("Tracks/postSel/", "Tracks/preSel/"); - // V0's QA - registryData.add("Tracks/V0qa/hV0Pt", "pT", kTH1F, {ptAxisV0s}); - registryData.add("Tracks/V0qa/hV0ArmPod", ";#alpha; #it{q}_T (GeV/c)", kTH2F, {v0SelOpt.axisArmPodAlpha, v0SelOpt.axisArmPodqT}); - // daughters' QA - registryData.add("Tracks/V0qa/el/Ga/hArmPod", ";#alpha; #it{q}_T (GeV/c)", kTH2F, {v0SelOpt.axisArmPodAlpha, v0SelOpt.axisArmPodqT}); - registryData.add("Tracks/V0qa/pi/K0s/hArmPod", ";#alpha; #it{q}_T (GeV/c)", kTH2F, {v0SelOpt.axisArmPodAlpha, v0SelOpt.axisArmPodqT}); - registryData.add("Tracks/V0qa/el/Ga/hNclVsEta", ";#eta; #it{N}^{TPC}_cl", kTH2F, {etaAxis, clTpcAxis}); - registryData.add("Tracks/V0qa/pi/K0s/hNclVsEta", ";#eta; #it{N}^{TPC}_cl", kTH2F, {etaAxis, clTpcAxis}); - registryData.add("Tracks/V0qa/el/Ga/hNclVsPt", ";#it{p}_{T} (GeV/#it{c}); #it{N}^{TPC}_cl", kTH2F, {ptAxis, clTpcAxis}); - registryData.add("Tracks/V0qa/pi/K0s/hNclVsPt", ";#it{p}_{T} (GeV/#it{c}); #it{N}^{TPC}_cl", kTH2F, {ptAxis, clTpcAxis}); - registryData.add("Tracks/V0qa/el/Ga/hdEdxMIPVsEta", ";#eta; dE/dx", kTH2F, {etaAxis, dEdxAxis}); - registryData.add("Tracks/V0qa/pi/K0s/hdEdxMIPVsEta", ";#eta; dE/dx", kTH2F, {etaAxis, dEdxAxis}); - registryData.addClone("Tracks/V0qa/pi/K0s/", "Tracks/V0qa/pi/La/"); - registryData.addClone("Tracks/V0qa/pi/K0s/", "Tracks/V0qa/pi/ALa/"); - registryData.addClone("Tracks/V0qa/pi/La/", "Tracks/V0qa/pr/La/"); - registryData.addClone("Tracks/V0qa/pi/ALa/", "Tracks/V0qa/pr/ALa/"); - - // charged pT - registryData.add({"Tracks/all/hFlatVsPt", "; #eta; mult; flat; #it{p} (GeV/#it{c}); #it{p}_{T} (GeV/#it{c})", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, ptAxis}}}); // dEdx PID - registryData.add({"Tracks/all/hdEdx", "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, dEdxAxis}}}); + registryData.add({"Tracks/all/hdEdx", "; #eta; mult; flat; #it{p} (GeV/#it{c}); #it{p}_{T} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, pAxis, dEdxAxis}}}); // Clean samples if (defOpt.fillV0Hist) { + // V0 counter + registryData.add("Tracks/V0qa/hV0Sel", "Number of V0s; Cut; #Tracks Passed Cut", {kTH1F, {{nV0Sel, 0, nV0Sel}}}); + registryData.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelAll + 1, "All"); + registryData.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelRejectSameSign + 1, "Reject same sign"); + registryData.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelRejectV0sAtTPCSector + 1, "Reject V0s at TPC sector"); + registryData.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelCosPA + 1, "Cos PA"); + registryData.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelV0radius + 1, "V0 radius"); + registryData.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelDCAposToPV + 1, "DCA pos to PV"); + registryData.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelDaughters + 1, "V0 daughters' sel."); + registryData.get(HIST("Tracks/V0qa/hV0Sel"))->GetXaxis()->SetBinLabel(v0SelDCAv0daughter + 1, "DCA v0 daughter"); + // V0's QA + registryData.add("Tracks/V0qa/hV0Pt", "pT", kTH1F, {ptAxisV0s}); + registryData.add("Tracks/V0qa/hV0ArmPod", ";#alpha; #it{q}_T (GeV/c)", kTH2F, {v0SelOpt.axisArmPodAlpha, v0SelOpt.axisArmPodqT}); + // daughters' QA + registryData.add("Tracks/V0qa/el/Ga/hArmPod", ";#alpha; #it{q}_T (GeV/c)", kTH2F, {v0SelOpt.axisArmPodAlpha, v0SelOpt.axisArmPodqT}); + registryData.add("Tracks/V0qa/pi/K0s/hArmPod", ";#alpha; #it{q}_T (GeV/c)", kTH2F, {v0SelOpt.axisArmPodAlpha, v0SelOpt.axisArmPodqT}); + registryData.add("Tracks/V0qa/el/Ga/hNclVsEta", ";#eta; #it{N}^{TPC}_cl", kTH2F, {etaAxis, clTpcAxis}); + registryData.add("Tracks/V0qa/pi/K0s/hNclVsEta", ";#eta; #it{N}^{TPC}_cl", kTH2F, {etaAxis, clTpcAxis}); + registryData.add("Tracks/V0qa/el/Ga/hNclVsPt", ";#it{p}_{T} (GeV/#it{c}); #it{N}^{TPC}_cl", kTH2F, {ptAxis, clTpcAxis}); + registryData.add("Tracks/V0qa/pi/K0s/hNclVsPt", ";#it{p}_{T} (GeV/#it{c}); #it{N}^{TPC}_cl", kTH2F, {ptAxis, clTpcAxis}); + registryData.add("Tracks/V0qa/el/Ga/hdEdxMIPVsEta", ";#eta; dE/dx", kTH2F, {etaAxis, dEdxAxis}); + registryData.add("Tracks/V0qa/pi/K0s/hdEdxMIPVsEta", ";#eta; dE/dx", kTH2F, {etaAxis, dEdxAxis}); + registryData.addClone("Tracks/V0qa/pi/K0s/", "Tracks/V0qa/pi/La/"); + registryData.addClone("Tracks/V0qa/pi/K0s/", "Tracks/V0qa/pi/ALa/"); + registryData.addClone("Tracks/V0qa/pi/La/", "Tracks/V0qa/pr/La/"); + registryData.addClone("Tracks/V0qa/pi/ALa/", "Tracks/V0qa/pr/ALa/"); + if (defOpt.storeThnSparse) { registryData.add({"Tracks/CleanTof/all/hPiTof", "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, dEdxAxis}}}); registryData.add({"Tracks/CleanV0/all/hEV0", "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, dEdxAxis}}}); @@ -781,9 +763,47 @@ struct FlattenictyPikp { registryData.print(); } - if (doprocessMC) { + if (doprocessMcEfficiency || doprocessMcRecTrack) { + if (defOpt.fillNclVsPhiCutQaHist) { + registryMC.add("Tracks/postSel/hPtPhi", "; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9)", {kTH2F, {ptAxis, phiAxisMod}}); + registryMC.add("Tracks/postSel/hPtPhiNclTPC", "; #eta; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9); N_{cluster}", {kTHnSparseF, {etaAxis, ptAxis, phiAxisMod, clTpcAxis}}); + registryMC.add("Tracks/postSel/hPtPhiNclPIDTPC", "; #eta; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9); N_{PID cluster}", {kTHnSparseF, {etaAxis, ptAxis, phiAxisMod, clTpcAxis}}); + registryMC.add("Tracks/postSel/hPtNclTPC", "; #it{p}_{T} (GeV/#it{c}); N_{cluster}", {kTH2F, {ptAxis, clTpcAxis}}); + registryMC.add("Tracks/postSel/pPtNclTPC", "; #it{p}_{T} (GeV/#it{c}); N_{cluster}", {kTProfile, {ptAxis}}); + registryMC.add("Tracks/postSel/hPtNclPIDTPC", "; #it{p}_{T} (GeV/#it{c}); N_{PID cluster}", {kTH2F, {ptAxis, clTpcAxis}}); + registryMC.add("Tracks/postSel/pPtNclPIDTPC", "; #it{p}_{T} (GeV/#it{c}); N_{PID cluster}", {kTProfile, {ptAxis}}); + } + registryMC.addClone("Tracks/postSel/", "Tracks/preSel/"); + } + + if (doprocessMcEfficiency) { registryMC.add({"Events/ResponseGen", ";N_{ch,FV0};1-#rho_{FV0};", {kTHnSparseF, {multAxis, flatAxis}}}); registryMC.add("Events/h1flatencityFV0MCGen", "", {kTH1F, {flatAxis}}); + registryMC.add("Events/hVtxZRec", "MC Rec vertex z position", kTH1F, {vtxzAxis}); + registryMC.add("Events/hVtxZGenGtOneRec", "MC Rec vertex z position w/ Nrec > 0", kTH1F, {vtxzAxis}); + registryMC.add("Events/hVtxZGen", "Generated vertex z position", kTH1F, {vtxzAxis}); + registryMC.add("Events/hMCEventStatus", "Number of events; Cut; #Evt Passed Cut", {HistType::kTHnSparseF, {{static_cast(MCEventStatus::nEvtMcEventStatus), -0.5, +static_cast(MCEventStatus::nEvtMcEventStatus) - 0.5}, multAxis, flatAxis}}); + std::array(MCEventStatus::nEvtMcEventStatus)> labelEvtSel{ + "All", + "Selected", + "Has Mc Coll", + "Split Vtx Removed"}; + for (int iBin = 0; iBin < static_cast(MCEventStatus::nEvtMcEventStatus); iBin++) { + registryMC.get(HIST("Events/hMCEventStatus"))->GetAxis(0)->SetBinLabel(iBin + 1, labelEvtSel[iBin].data()); + } + registryMC.add({"Tracks/hPtFakes", "Fake tracks; Gen Nch (|#eta|<0.8); flat; #it{p}_{T} (GeV/#it{c})", {kTHnSparseF, {nChAxis, flatAxis, ptAxis}}}); + registryMC.add("Tracks/hPtRes", "#it{p}_{T} resolution;;(#it{p}_{T}_{rec} - #it{p}_{T}_{gen})/#it{p}_{T}_{gen};", kTH2F, {ptAxis, {100, -1.0, 1.0}}); + + for (int i = 0; i < Npart; i++) { + registryMC.add({fmt::format(CpTeffGenPrimRecEvtF.data(), CspeciesAll[i].data()).c_str(), "Gen evt w/ Nrec > 0; mult; flat; #it{p}_{T} (GeV/#it{c})", {kTHnSparseF, {multAxis, flatAxis, ptAxis}}}); + registryMC.add({fmt::format(CpTeffPrimRecEvtF.data(), CspeciesAll[i].data()).c_str(), "Gen evt w/ Nrec > 0 + Evt sel; mult; flat; #it{p}_{T} (GeV/#it{c})", {kTHnSparseF, {multAxis, flatAxis, ptAxis}}}); + registryMC.add({fmt::format(CpTmcClosureRecF.data(), CspeciesAll[i].data()).c_str(), "Gen Nch w/ Nrec > 0 + Evt. sel; Gen Nch (|#eta|<0.8); flat; #it{p}_{T} (GeV/#it{c})", {kTHnSparseF, {nChAxis, flatAxis, ptAxis}}}); + } + LOG(info) << "processMcEfficiency -> Size of the MC histograms:"; + registryMC.print(); + } + + if (doprocessMcSgnEvtLoss) { registryMC.add("Events/hFlatMCGen", "Events/hFlatMCGen", {kTH1F, {flatAxis}}); registryMC.add("Events/hEvtMcGen", "Events/hEvtMcGen", {kTH1F, {{4, 0.f, 4.f}}}); registryMC.get(HIST("Events/hEvtMcGen"))->GetXaxis()->SetBinLabel(1, "all"); @@ -791,11 +811,9 @@ struct FlattenictyPikp { registryMC.get(HIST("Events/hEvtMcGen"))->GetXaxis()->SetBinLabel(3, "INELgt0"); registryMC.get(HIST("Events/hEvtMcGen"))->GetXaxis()->SetBinLabel(4, "INELgt0TVX"); // + registryMC.add("Events/hNchGen", "Gen Nch; Gen Nch (|#eta|<0.8)", {kTH1F, {nChAxis}}); + registryMC.add("Events/hNchGenCent", "Gen cent; mult", {kTH1F, {multAxis}}); registryMC.add("Events/hNchGenVsCent", "Gen Nch vs Cent; mult; Gen Nch (|#eta|<0.8)", {kTH2F, {nChAxis, multAxis}}); - registryMC.add("Events/hVtxZRec", "MC Rec vertex z position", kTH1F, {vtxzAxis}); - registryMC.add("Events/hVtxZGen", "Generated vertex z position", kTH1F, {vtxzAxis}); - registryMC.add("Events/hNchTVX", "Nch in FT0A+FT0C; Nch; status", {kTH2F, {nChAxis, {2, 0, 2}}}); - registryMC.add({"Tracks/hPtFakes", "Fake tracks; Gen Nch (|#eta|<0.8); flat; #it{p}_{T} (GeV/#it{c})", {kTHnSparseF, {nChAxis, flatAxis, ptAxis}}}); // Event loss registryMC.add("Events/hNchVsFlatGenINELgt0", "Gen Nch w/o Evt sel; Gen Nch (|#eta|<0.8); flat", {kTH2F, {nChAxis, flatAxis}}); registryMC.add("Events/hNchVsFlatGenINELgt0wRecEvtSel", "Gen Nch w/ Nrec > 0 + Evt sel; Gen Nch (|#eta|<0.8); flat", {kTH2F, {nChAxis, flatAxis}}); @@ -803,74 +821,28 @@ struct FlattenictyPikp { registryMC.add("Events/hFlatResponse", "Flattenicity response; flat ture; flat measured", {kTH2F, {flatAxis, flatAxis}}); // Event split registryMC.add("Events/hCentVsFlatRecINELgt0", "Gen evt w/o Evt sel; mult; flat", {kTH2F, {multAxis, flatAxis}}); - registryMC.add("Events/hCentVsFlatRecINELgt0wRecEvt", "Gen evt w/ Nrec > 0; mult; flat", {kTH2F, {multAxis, flatAxis}}); registryMC.add("Events/hCentVsFlatRecINELgt0wRecEvtSel", "Gen evt w/ Nrec > 0 + Evt sel; mult; flat", {kTH2F, {multAxis, flatAxis}}); + // Signal loss for (int i = 0; i < Npart; ++i) { - // Signal loss registryMC.add({fmt::format(CpTgenPrimSgnF.data(), CspeciesAll[i].data()).c_str(), "Gen evt w/o Evt sel; Gen Nch (|#eta|<0.8); flat; #it{p}_{T} (GeV/#it{c})", {kTHnSparseF, {nChAxis, flatAxis, ptAxis}}}); registryMC.add({fmt::format(CpTrecCollPrimSgnF.data(), CspeciesAll[i].data()).c_str(), "Gen Nch w/ Nrec > 0; Gen Nch (|#eta|<0.8); flat; #it{p}_{T} (GeV/#it{c})", {kTHnSparseF, {nChAxis, flatAxis, ptAxis}}}); - // Closure test registryMC.add({fmt::format(CpTmcClosureGenPrimF.data(), CspeciesAll[i].data()).c_str(), "Gen evt w/o Evt sel; Gen Nch (|#eta|<0.8); flat; #it{p}_{T} (GeV/#it{c})", {kTHnSparseF, {nChAxis, flatAxis, ptAxis}}}); - registryMC.add({fmt::format(CpTmcClosureRecF.data(), CspeciesAll[i].data()).c_str(), "Gen Nch w/ Nrec > 0 + Evt. sel; Gen Nch (|#eta|<0.8); flat; #it{p}_{T} (GeV/#it{c})", {kTHnSparseF, {nChAxis, flatAxis, ptAxis}}}); - } - if (defOpt.fillNclVsPhiCutQaHist) { - registryMC.add("Tracks/postSel/hPtPhi", "; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9)", {kTH2F, {ptAxis, phiAxisMod}}); - registryMC.add("Tracks/postSel/hPtPhiNclTPC", "; #eta; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9); N_{cluster}", {kTHnSparseF, {etaAxis, ptAxis, phiAxisMod, clTpcAxis}}); - registryMC.add("Tracks/postSel/hPtPhiNclPIDTPC", "; #eta; #it{p}_{T} (GeV/#it{c}); fmod(#varphi,#pi/9); N_{PID cluster}", {kTHnSparseF, {etaAxis, ptAxis, phiAxisMod, clTpcAxis}}); - registryMC.add("Tracks/postSel/hPtNclTPC", "; #it{p}_{T} (GeV/#it{c}); N_{cluster}", {kTH2F, {ptAxis, clTpcAxis}}); - registryMC.add("Tracks/postSel/pPtNclTPC", "; #it{p}_{T} (GeV/#it{c}); N_{cluster}", {kTProfile, {ptAxis}}); - registryMC.add("Tracks/postSel/hPtNclPIDTPC", "; #it{p}_{T} (GeV/#it{c}); N_{PID cluster}", {kTH2F, {ptAxis, clTpcAxis}}); - registryMC.add("Tracks/postSel/pPtNclPIDTPC", "; #it{p}_{T} (GeV/#it{c}); N_{PID cluster}", {kTProfile, {ptAxis}}); - } - registryMC.addClone("Tracks/postSel/", "Tracks/preSel/"); - - for (int i = 0; i < NpartChrg; i++) { - const std::string strID = Form("/%s/%s", (i < Npart) ? "pos" : "neg", pID[i % Npart]); - hPtGenRecEvt[i] = registryMC.add("Tracks/hPtGenRecEvt" + strID, "Gen evt w/ Nrec > 0; mult; flat; #it{p}_{T} (GeV/#it{c})", kTHnSparseF, {multAxis, flatAxis, ptAxis}); - hPtGenPrimRecEvt[i] = registryMC.add("Tracks/hPtGenPrimRecEvt" + strID, "Gen evt w/ Nrec > 0 (primary); mult; flat; #it{p}_{T} (GeV/#it{c})", kTHnSparseF, {multAxis, flatAxis, ptAxis}); - hPtGenRecEvtGtZero[i] = registryMC.add("Tracks/hPtGenRecEvtGtZero" + strID, "Gen evt w/ Nrec > 0; mult; flat; #it{p}_{T} (GeV/#it{c})", kTHnSparseF, {multAxis, flatAxis, ptAxis}); - hPtGenPrimRecEvtGtZero[i] = registryMC.add("Tracks/hPtGenPrimRecEvtGtZero" + strID, "Gen evt w/ Nrec > 0 (primary); mult; flat; #it{p}_{T} (GeV/#it{c})", kTHnSparseF, {multAxis, flatAxis, ptAxis}); - hPtEffGenPrim[i] = registryMC.add("Tracks/hPtEffGenPrim" + strID, "Gen evt w/o rec Evt; mult; flat; #it{p}_{T} (GeV/#it{c})", kTHnSparseF, {multAxis, flatAxis, ptAxis}); - hPtEffGenWeak[i] = registryMC.add("Tracks/hPtEffGenWeak" + strID, "Gen evt w/o rec Evt; mult; flat; #it{p}_{T} (GeV/#it{c})", kTHnSparseF, {multAxis, flatAxis, ptAxis}); - hPtEffGenMat[i] = registryMC.add("Tracks/hPtEffGenMat" + strID, "Gen evt w/o rec Evt; mult; flat; #it{p}_{T} (GeV/#it{c})", kTHnSparseF, {multAxis, flatAxis, ptAxis}); - hPtEffGenPrimEvtSelGen[i] = registryMC.add("Tracks/hPtEffGenPrimEvtSelGen" + strID, "Gen evt w/o rec Evt; mult; flat; #it{p}_{T} (GeV/#it{c})", kTHnSparseF, {multAxis, flatAxis, ptAxis}); - hPtEffGenWeakEvtSelGen[i] = registryMC.add("Tracks/hPtEffGenWeakEvtSelGen" + strID, "Gen evt w/o rec Evt; mult; flat; #it{p}_{T} (GeV/#it{c})", kTHnSparseF, {multAxis, flatAxis, ptAxis}); - hPtEffGenMatEvtSelGen[i] = registryMC.add("Tracks/hPtEffGenMatEvtSelGen" + strID, "Gen evt w/o rec Evt; mult; flat; #it{p}_{T} (GeV/#it{c})", kTHnSparseF, {multAxis, flatAxis, ptAxis}); - hPtEffRecGoodCollPrim[i] = registryMC.add("Tracks/hPtEffRecGoodCollPrim" + strID, "; mult; flat; #it{p}_{T} (GeV/#it{c})", kTHnSparseF, {multAxis, flatAxis, ptAxis}); - hPtEffRecGoodCollWeak[i] = registryMC.add("Tracks/hPtEffRecGoodCollWeak" + strID, "; mult; flat; #it{p}_{T} (GeV/#it{c})", kTHnSparseF, {multAxis, flatAxis, ptAxis}); - hPtEffRecGoodCollMat[i] = registryMC.add("Tracks/hPtEffRecGoodCollMat" + strID, "; mult; flat; #it{p}_{T} (GeV/#it{c})", kTHnSparseF, {multAxis, flatAxis, ptAxis}); - hDCAxyRecBadCollPrim[i] = registryMC.add("Tracks/hDCAxyRecBadCollPrim" + strID, "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {ptAxis, dcaXYAxis}); - hDCAxyRecBadCollWeak[i] = registryMC.add("Tracks/hDCAxyRecBadCollWeak" + strID, "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {ptAxis, dcaXYAxis}); - hDCAxyRecBadCollMat[i] = registryMC.add("Tracks/hDCAxyRecBadCollMat" + strID, "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {ptAxis, dcaXYAxis}); - hPtVsDCAxyRecGoodCollPrim[i] = registryMC.add("Tracks/hPtVsDCAxyRecGoodCollPrim" + strID, "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {ptAxis, dcaXYAxis}); - hPtVsDCAxyRecGoodCollWeak[i] = registryMC.add("Tracks/hPtVsDCAxyRecGoodCollWeak" + strID, "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {ptAxis, dcaXYAxis}); - hPtVsDCAxyRecGoodCollMat[i] = registryMC.add("Tracks/hPtVsDCAxyRecGoodCollMat" + strID, "; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", kTH2F, {ptAxis, dcaXYAxis}); } + LOG(info) << "processMcSgnEvtLoss -> Size of the MC histograms:"; + registryMC.print(); + } + if (doprocessMcRecTrack) { for (int i = 0; i < Npart; i++) { - registryMC.add({fmt::format(CpTeffGenPrimRecEvtF.data(), CspeciesAll[i].data()).c_str(), "Gen evt w/ Nrec > 0; mult; flat; #it{p}_{T} (GeV/#it{c})", {kTHnSparseF, {multAxis, flatAxis, ptAxis}}}); - registryMC.add({fmt::format(CpTeffPrimRecEvtF.data(), CspeciesAll[i].data()).c_str(), "Gen evt w/ Nrec > 0 + Evt sel; mult; flat; #it{p}_{T} (GeV/#it{c})", {kTHnSparseF, {multAxis, flatAxis, ptAxis}}}); + registryMC.add({fmt::format(CdEdxMcRecPrimF.data(), CspeciesAll[i].data()).c_str(), "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, dEdxAxis}}}); + registryMC.add({fmt::format(CdEdxMcRecPrimSelF.data(), CspeciesAll[i].data()).c_str(), "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, dEdxAxis}}}); + registryMC.add({fmt::format(CEtaVsPtVsPMcRecPrimSelF.data(), CspeciesAll[i].data()).c_str(), "; #eta; #it{p}_{T} (GeV/#it{c}); #it{p} (GeV/#it{c})", {kTHnSparseF, {etaAxis, ptAxis, pAxis}}}); registryMC.add({fmt::format(CpTvsDCAxyAllF.data(), CspeciesAll[i].data()).c_str(), "; mult; flat; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", {kTHnSparseF, {multAxis, flatAxis, ptAxis, dcaXYAxis}}}); registryMC.add({fmt::format(CpTvsDCAxyPrimAllF.data(), CspeciesAll[i].data()).c_str(), "; mult; flat; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", {kTHnSparseF, {multAxis, flatAxis, ptAxis, dcaXYAxis}}}); registryMC.add({fmt::format(CpTvsDCAxyWeakAllF.data(), CspeciesAll[i].data()).c_str(), "; mult; flat; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", {kTHnSparseF, {multAxis, flatAxis, ptAxis, dcaXYAxis}}}); registryMC.add({fmt::format(CpTvsDCAxyMatAllF.data(), CspeciesAll[i].data()).c_str(), "; mult; flat; #it{p}_{T} (GeV/#it{c}); DCA_{xy} (cm)", {kTHnSparseF, {multAxis, flatAxis, ptAxis, dcaXYAxis}}}); - registryMC.add({fmt::format(CdEdxMcRecPrimF.data(), CspeciesAll[i].data()).c_str(), "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, dEdxAxis}}}); - registryMC.add({fmt::format(CdEdxMcRecPrimSelF.data(), CspeciesAll[i].data()).c_str(), "; #eta; mult; flat; #it{p} (GeV/#it{c}); dEdx", {kTHnSparseF, {etaAxis, multAxis, flatAxis, pAxis, dEdxAxis}}}); - registryMC.add({fmt::format(CEtaVsPtVsPMcRecPrimSelF.data(), CspeciesAll[i].data()).c_str(), "; #eta; #it{p}_{T} (GeV/#it{c}); #it{p} (GeV/#it{c})", {kTHnSparseF, {etaAxis, ptAxis, pAxis}}}); } - - // Hash list for efficiency - listEfficiency.setObject(new THashList); - static_for<0, 1>([&](auto pidSgn) { - bookMcHist(); - bookMcHist(); - bookMcHist(); - initEfficiency(); - initEfficiency(); - initEfficiency(); - }); - - LOG(info) << "Size of the MC histograms:"; + LOG(info) << "processMcRecTrack -> Size of the MC histograms:"; registryMC.print(); } } @@ -977,15 +949,6 @@ struct FlattenictyPikp { return fCalibDeDxFunc; } - template - bool isPID(const P& mcParticle) - { - static_assert(pidSgn == CnullInt || pidSgn == ConeInt); - static_assert(id > CnullInt && id < Npart); - constexpr int Cidx = id + pidSgn * Npart; - return mcParticle.pdgCode() == pIdSgn[Cidx]; - } - template bool selTOFPi(T const& track) { @@ -1020,7 +983,7 @@ struct FlattenictyPikp { const float mult = getMult(collision); const float flat = fillFlat(collision); for (const auto& track : tracks) { - if (!isGoodTrack(track, magField)) { + if (!isGoodTrack(track, magField)) { continue; } if (track.hasTOF() && (std::sqrt(std::pow(std::fabs(o2::aod::pidutils::tpcNSigma(track)), 2) + std::pow(std::fabs(o2::aod::pidutils::tofNSigma(track)), 2) < trkSelOpt.dcaNsigmaCombinedMax))) { @@ -1052,7 +1015,7 @@ struct FlattenictyPikp { if (defOpt.fillTrackQaHist) { fillTrackQA(track); } - if (!isGoodTrack(track, magField)) { + if (!isGoodTrack(track, magField)) { continue; } if (defOpt.fillTrackQaHist) { @@ -1105,15 +1068,12 @@ struct FlattenictyPikp { // PID TPC dEdx if (defOpt.fillChrgType) { if (track.sign() * track.p() > Cnull) { - registryData.fill(HIST(Cprefix) + HIST(Ccharge[kPos]) + HIST("hFlatVsPt"), track.eta(), mult, flat, track.p(), track.pt()); - registryData.fill(HIST(Cprefix) + HIST(Ccharge[kPos]) + HIST("hdEdx"), track.eta(), mult, flat, track.p(), dEdx); + registryData.fill(HIST(Cprefix) + HIST(Ccharge[kPos]) + HIST("hdEdx"), track.eta(), mult, flat, track.p(), track.pt(), dEdx); } else { - registryData.fill(HIST(Cprefix) + HIST(Ccharge[kNeg]) + HIST("hFlatVsPt"), track.eta(), mult, flat, track.p(), track.pt()); - registryData.fill(HIST(Cprefix) + HIST(Ccharge[kNeg]) + HIST("hdEdx"), track.eta(), mult, flat, track.p(), dEdx); + registryData.fill(HIST(Cprefix) + HIST(Ccharge[kNeg]) + HIST("hdEdx"), track.eta(), mult, flat, track.p(), track.pt(), dEdx); } } else { - registryData.fill(HIST(Cprefix) + HIST(Ccharge[kAll]) + HIST("hFlatVsPt"), track.eta(), mult, flat, track.p(), track.pt()); - registryData.fill(HIST(Cprefix) + HIST(Ccharge[kAll]) + HIST("hdEdx"), track.eta(), mult, flat, track.p(), dEdx); + registryData.fill(HIST(Cprefix) + HIST(Ccharge[kAll]) + HIST("hdEdx"), track.eta(), mult, flat, track.p(), track.pt(), dEdx); } // TOF pions @@ -1337,56 +1297,7 @@ struct FlattenictyPikp { return std::abs(charge) >= CminCharge; } - template - int countPart(P const& particles) - { - auto nCharged = 0; - for (auto const& particle : particles) { - if (!isChrgParticle(particle.pdgCode())) { - continue; - } - if (!particle.isPhysicalPrimary()) { - continue; - } - if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { - continue; - } - nCharged++; - } - return nCharged; - } - - template - bool isInelGt0wTVX(P const& particles) - { - int nChrgMc = 0; - int nChrgFT0A = 0; - int nChrgFT0C = 0; - for (auto const& particle : particles) { - if (!isChrgParticle(particle.pdgCode())) { - continue; - } - if (!particle.isPhysicalPrimary()) { - continue; - } - // trigger TVX - if (particle.eta() > CminAccFT0A && particle.eta() < CmaxAccFT0A) { - nChrgFT0A++; - } - if (particle.eta() > CminAccFT0C && particle.eta() < CmaxAccFT0C) { - nChrgFT0C++; - } - nChrgMc++; - } - if (nChrgFT0A == CnullInt || nChrgFT0C == CnullInt) { - registryMC.fill(HIST("Events/hNchTVX"), nChrgMc, 0.5); - return false; - } - registryMC.fill(HIST("Events/hNchTVX"), nChrgMc, 1.5); - return true; - } - - template + template int countTracks(T const& tracks, C const& collision, aod::BCsWithTimestamps const& /*bcs*/, float mult) { if (trkSelOpt.rejectTrkAtTPCSector || v0SelOpt.rejectV0sAtTPCSector || defOpt.applyCalibGainFromCCDB || defOpt.applyCalibVtxFromCCDB) { @@ -1400,12 +1311,12 @@ struct FlattenictyPikp { auto nTrk = 0; for (auto const& track : tracks) { - if (!isGoodTrack(track, magField)) { + if (!isGoodTrack(track, magField)) { continue; } nTrk++; } - if (fillHis) { + if constexpr (fillHist) { registryQC.fill(HIST("Events/hNchVsCent"), nTrk, mult); } return nTrk; @@ -1440,23 +1351,31 @@ struct FlattenictyPikp { } } - template + template bool isGoodTrack(T const& track, const float magfield) { - registryQC.fill(HIST("Tracks/hTrkSel"), trkSelAll); + if constexpr (fillHist) { + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelAll); + } if (std::abs(track.eta()) > trkSelOpt.trkEtaMax) { return false; } - registryQC.fill(HIST("Tracks/hTrkSel"), trkSelEta); + if constexpr (fillHist) { + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelEta); + } if (track.pt() < trkSelOpt.trkPtMin) { return false; } - registryQC.fill(HIST("Tracks/hTrkSel"), trkSelPt); + if constexpr (fillHist) { + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelPt); + } if constexpr (selDCA) { if (!isDCAxyCut(track)) { return false; } - registryQC.fill(HIST("Tracks/hTrkSel"), trkSelDCA); + if constexpr (fillHist) { + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelDCA); + } if (defOpt.applyDCAParam) { if (defOpt.applyDCAParamFromCCDB) { if (!isDCAParamCut(track)) { @@ -1467,23 +1386,29 @@ struct FlattenictyPikp { return false; } } - registryQC.fill(HIST("Tracks/hTrkSel"), trkSelCustomDCA); + if constexpr (fillHist) { + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelCustomDCA); + } } } if (track.tpcNClsCrossedRows() < minNCrossedRowsTPC) { return false; } - registryQC.fill(HIST("Tracks/hTrkSel"), trkNRowsTPC); + if constexpr (fillHist) { + registryQC.fill(HIST("Tracks/hTrkSel"), trkNRowsTPC); + } if (trkSelOpt.applyNcl && track.tpcNClsFound() < trkSelOpt.nclTPCMin) { return false; } - registryQC.fill(HIST("Tracks/hTrkSel"), trkSelNClsFound); - + if constexpr (fillHist) { + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelNClsFound); + } if (trkSelOpt.applyNclPID && track.tpcNClsPID() < trkSelOpt.nclPidTPCMin) { return false; } - registryQC.fill(HIST("Tracks/hTrkSel"), trkSelNClsPID); - + if constexpr (fillHist) { + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelNClsPID); + } float phimodn = track.phi(); phiMod(phimodn, magfield, track.sign()); if (defOpt.fillNclVsPhiCutQaHist) { @@ -1495,12 +1420,14 @@ struct FlattenictyPikp { if (defOpt.fillNclVsPhiCutQaHist) { fillNclVsPhiCutQaHist(track, phimodn); } - registryQC.fill(HIST("Tracks/hTrkSel"), trkSelTPCBndr); + if constexpr (fillHist) { + registryQC.fill(HIST("Tracks/hTrkSel"), trkSelTPCBndr); + } return true; } template - void fillV0QA(V const& v0, U const& track) + inline void fillV0QA(V const& v0, U const& track) { registryData.fill(HIST(CprefixV0qa) + HIST(PidDir[id]) + HIST(V0Dir[typeMother]) + HIST("hArmPod"), v0.alpha(), v0.qtarm()); registryData.fill(HIST(CprefixV0qa) + HIST(PidDir[id]) + HIST(V0Dir[typeMother]) + HIST("hNclVsEta"), track.eta(), track.tpcNClsPID()); @@ -1722,8 +1649,8 @@ struct FlattenictyPikp { registryData.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hPtVsWOcutDCA"), track.pt(), track.dcaXY()); } } + registryData.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hPVsPtEta"), track.p(), track.pt(), track.eta()); } - registryData.fill(HIST(Cprefix) + HIST(Cstatus[ft]) + HIST("hPVsPtEta"), track.p(), track.pt(), track.eta()); } template @@ -1933,13 +1860,36 @@ struct FlattenictyPikp { return iRing; } + template + float getGenCent(C const& collision) + { + float val = -999.0; + switch (defOpt.multEst.value) { + case MultE::CnoMult: + return val; + case MultE::CmultFT0C: + return collision.centFT0C(); + case MultE::CmultFT0M: + return collision.centFT0M(); + default: + LOGF(fatal, "No valid centrality estimator: %s", defOpt.multEst.value); + return val; + } + } + template float getMult(C const& collision) { float val = -999.0; - switch (defOpt.multEst) { + switch (defOpt.multEst.value) { case MultE::CnoMult: return val; + case MultE::CmultFT0C: + if constexpr (!isMC) { + return collision.centFT0C(); + } else { + return collision.multMCFT0C(); + } break; case MultE::CmultFT0M: if constexpr (!isMC) { @@ -1952,13 +1902,12 @@ struct FlattenictyPikp { if constexpr (!isMC) { return collision.multTPC(); } else { - LOG(fatal) << "No valid multiplicity estimator: " << defOpt.multEst; - return val; + return collision.multMCNParticlesEta08(); } break; default: - return collision.centFT0M(); - break; + LOGF(fatal, "No valid multiplicity estimator: %s", defOpt.multEst.value); + return val; } } @@ -2221,195 +2170,249 @@ struct FlattenictyPikp { return flatFV0; } - template - void bookMcHist() - { - AxisSpec ptAxis{binOpt.axisPt, "#it{p}_{T} (GeV/#it{c})"}; - constexpr int ChistIdx = id + pidSgn * Npart; - auto idx = id; - const std::string strID = Form("/%s/%s", (pidSgn == CnullInt && id < Npart) ? "pos" : "neg", pID[idx]); - hPtEffRec[ChistIdx] = registryMC.add("Tracks/hPtEffRec" + strID, " ; #it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); - hPtEffGen[ChistIdx] = registryMC.add("Tracks/hPtEffGen" + strID, " ; #it{p}_{T} (GeV/#it{c})", kTH1F, {ptAxis}); - } - - template - void initEfficiency() - { - static_assert(pidSgn == CnullInt || pidSgn == ConeInt); - static_assert(id > CnullInt && id < Npart); - constexpr int Cidx = id + pidSgn * Npart; - const TString partName = pIdChrg[Cidx]; - auto lhash = new THashList(); - lhash->SetName(partName); - listEfficiency->Add(lhash); - - auto bookEff = [&](const TString& eName, const auto& h) { - const TAxis* axis = h->GetXaxis(); - TString eTitle = h->GetTitle(); - eTitle.ReplaceAll("Numerator", "").Strip(TString::kBoth); - eTitle = Form("%s;%s;Efficiency", eTitle.Data(), axis->GetTitle()); - lhash->Add(new TEfficiency(eName, eTitle, axis->GetNbins(), axis->GetXbins()->GetArray())); - }; - - const int idx = id + pidSgn * Npart; - bookEff("hEffvsPt", hPtEffRec[idx]); - } + Preslice perCollTrk = aod::track::collisionId; - template - void fillEfficiency() + void processMcEfficiency(CollsMCExtraMult::iterator const& mcCollision, + soa::SmallGroups const& collisions, + aod::BCsWithTimestamps const& /*bcs*/, + aod::FV0As const& /*fv0s*/, + aod::McParticles const& particles, + MyLabeledPIDTracks const& tracks) { - static_assert(pidSgn == CnullInt || pidSgn == ConeInt); - constexpr int ChistIdx = id + pidSgn * Npart; - const char* partName = pIdChrg[ChistIdx]; - auto lhash = dynamic_cast(listEfficiency->FindObject(partName)); - if (!lhash) { - LOG(warning) << "No efficiency object found for particle " << partName; - return; + LOGP(debug, "MC col {} has {} reco cols", mcCollision.globalIndex(), collisions.size()); + auto multMC = -999.; + if (evtSelOpt.useMultMCmidrap) { + multMC = mcCollision.multMCNParticlesEta08(); + } else { + multMC = getMultMC(mcCollision); } + const float flatMC = fillFlatMC(particles); - auto fillEff = [&](const TString& eName, const auto& num, const auto& den) { - auto eff = dynamic_cast(lhash->FindObject(eName)); - if (!eff) { - LOG(warning) << "Cannot find TEfficiency " << eName; - return; + auto multRec = -999.; + auto flatRec = -999.; + bool gtOneRec = false; + for (const auto& collision : collisions) { + if (!isGoodEvent(collision)) { + continue; } - eff->SetTotalHistogram(*den, "f"); - eff->SetPassedHistogram(*num, "f"); - }; - fillEff("hEffvsPt", hPtEffRec[ChistIdx], hPtEffGen[ChistIdx]); - } - - template - void fillMCRecTrack(MyLabeledPIDTracks::iterator const& track, const float mult, const float flat) - { - static_assert(pidSgn == CnullInt || pidSgn == ConeInt); - constexpr int ChistIdx = id + pidSgn * Npart; - // LOG(debug) << "fillMCRecTrack for pidSgn '" << pidSgn << "' and id '" << static_cast(id) << " with index " << ChistIdx; - const aod::McParticles::iterator& mcParticle = track.mcParticle(); - const CollsGen::iterator& collision = track.collision_as>(); - // const CollsGen::iterator& collision = track.collision_as(); - - if (!isChrgParticle(mcParticle.pdgCode())) { - return; - } - if (std::abs(mcParticle.eta()) > trkSelOpt.trkEtaMax) { - return; + if (evtSelOpt.removeSplitVertex && collision.globalIndex() != mcCollision.bestCollisionIndex()) { + continue; + } + gtOneRec = true; + multRec = getMult(collision); + flatRec = fillFlat(collision); } - if (mcParticle.pt() < trkSelOpt.trkPtMin) { - return; + registryMC.fill(HIST("Events/hVtxZGen"), mcCollision.posZ()); + if (gtOneRec) { + registryMC.fill(HIST("Events/hVtxZGenGtOneRec"), mcCollision.posZ()); } - if (!isPID(mcParticle)) { - return; + /* Tracking eff. den */ + for (const auto& particle : particles) { + if (!isChrgParticle(particle.pdgCode())) { + continue; + } + if (!particle.isPhysicalPrimary()) { + continue; + } + if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { + continue; + } + if (gtOneRec) { + static_for<0, 4>([&](auto i) { + constexpr int Cidx = i.value; + if (std::fabs(particle.pdgCode()) == pDGs[Cidx]) { + registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTeffGenPrimRecEvt), multRec, flatRec, particle.pt()); + } + }); + } } - - if ((collision.has_mcCollision() && (mcParticle.mcCollisionId() != collision.mcCollisionId())) || !collision.has_mcCollision()) { - if (!mcParticle.isPhysicalPrimary()) { - if (mcParticle.getProcess() == CprocessIdWeak) { - hDCAxyRecBadCollWeak[ChistIdx]->Fill(track.pt(), track.dcaXY()); - } else { - hDCAxyRecBadCollMat[ChistIdx]->Fill(track.pt(), track.dcaXY()); + /* Tracking eff. num */ + for (const auto& collision : collisions) { + if (trkSelOpt.rejectTrkAtTPCSector || defOpt.applyCalibGainFromCCDB || defOpt.applyCalibVtxFromCCDB) { + auto bc = collision.bc_as(); + int currentRun = bc.runNumber(); + if (runNumber != currentRun) { + initCCDB(bc); + runNumber = currentRun; } - } else { - hDCAxyRecBadCollPrim[ChistIdx]->Fill(track.pt(), track.dcaXY()); } - } + registryMC.fill(HIST("Events/hMCEventStatus"), static_cast(MCEventStatus::kMcEvtAll), multRec, flatRec); + if (!isGoodEvent(collision)) { + continue; + } + registryMC.fill(HIST("Events/hMCEventStatus"), static_cast(MCEventStatus::kEvtSelected), multRec, flatRec); + if (!collision.has_mcCollision()) { + continue; + } + registryMC.fill(HIST("Events/hMCEventStatus"), static_cast(MCEventStatus::kEvtHasMcColl), multRec, flatRec); + if (evtSelOpt.removeSplitVertex && collision.globalIndex() != mcCollision.bestCollisionIndex()) { + continue; + } + registryMC.fill(HIST("Events/hMCEventStatus"), static_cast(MCEventStatus::kEvtSplitVtxRemoved), multRec, flatRec); + registryMC.fill(HIST("Events/hVtxZRec"), collision.posZ()); - if (collision.has_mcCollision() && (mcParticle.mcCollisionId() == collision.mcCollisionId())) { - if (!mcParticle.isPhysicalPrimary()) { - if (mcParticle.getProcess() == CprocessIdWeak) { - hPtEffRecGoodCollWeak[ChistIdx]->Fill(mult, flat, track.pt()); - hPtVsDCAxyRecGoodCollWeak[ChistIdx]->Fill(track.pt(), track.dcaXY()); - } else { - hPtEffRecGoodCollMat[ChistIdx]->Fill(mult, flat, track.pt()); - hPtVsDCAxyRecGoodCollMat[ChistIdx]->Fill(track.pt(), track.dcaXY()); + const auto& groupedTrks = tracks.sliceBy(perCollTrk, collision.globalIndex()); + int nTrk = 0; + for (const auto& track : groupedTrks) { + if (!isGoodTrack(track, magField)) { + continue; } - } else { - hPtEffRecGoodCollPrim[ChistIdx]->Fill(mult, flat, track.pt()); - hPtVsDCAxyRecGoodCollPrim[ChistIdx]->Fill(track.pt(), track.dcaXY()); - if (isDCAxyCut(track)) { - hPtEffRec[ChistIdx]->Fill(mcParticle.pt()); + if (!track.has_mcParticle()) { + registryMC.fill(HIST("Tracks/hPtFakes"), multRec, flatRec, track.pt()); + continue; } + const auto& particle = track.mcParticle_as(); + if (collision.mcCollisionId() != particle.mcCollisionId()) { + continue; + } + if (!isChrgParticle(particle.pdgCode())) { + continue; + } + if (!particle.isPhysicalPrimary()) { + continue; + } + static_for<0, 4>([&](auto i) { + constexpr int Cidx = i.value; + if (std::fabs(particle.pdgCode()) == pDGs[Cidx]) { + registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTeffPrimRecEvt), multRec, flatRec, track.pt()); + registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTmcClosureRec), multMC, flatMC, track.pt()); // closure + } + }); + nTrk++; + registryMC.fill(HIST("Tracks/hPtRes"), particle.pt(), (track.pt() - particle.pt()) / particle.pt()); } + registryQC.fill(HIST("Events/hNchVsCent"), nTrk, multRec); } } + PROCESS_SWITCH(FlattenictyPikp, processMcEfficiency, "process tracking efficiency", false); - template - void fillMCGenRecEvt(aod::McParticles::iterator const& mcParticle, const float mult, const float flat) + void processMcSgnEvtLoss(CollsMCExtraMult::iterator const& mcCollision, + soa::SmallGroups const& collisions, + aod::BCsWithTimestamps const& /*bcs*/, + aod::FV0As const& /*fv0s*/, + aod::McParticles const& particles) { - static_assert(pidSgn == CnullInt || pidSgn == ConeInt); - constexpr int ChistIdx = id + pidSgn * Npart; + LOGP(debug, "MC col {} has {} reco cols", mcCollision.globalIndex(), collisions.size()); + auto multMC = -999; + if (evtSelOpt.useMultMCmidrap) { + multMC = mcCollision.multMCNParticlesEta08(); + } else { + multMC = getMultMC(mcCollision); + } + /* + cauto centMcGen = -1.; + if (evtSelOpt.customGenCent) { + if constexpr (hasFT0C) { + centMcGen = mcCollision.mcpercft0c(); + } else if (hasFT0M) { + centMcGen = mcCollision.mcpercft0m(); + } + } else { + if (defOpt.multEst == MultE::CmultFT0C) { + centMcGen = mcCollision.centFT0C(); + } else if (defOpt.multEst == MultE::CmultFT0M) { + centMcGen = mcCollision.centFT0M(); + } else { + centMcGen = -1.; + } + } + */ + registryMC.fill(HIST("Events/hNchGen"), multMC); + registryMC.fill(HIST("Events/hNchGenCent"), getGenCent(mcCollision)); + const float flatMC = fillFlatMC(particles); + registryMC.fill(HIST("Events/hFlatMCGen"), flatMC); - if (!isPID(mcParticle)) { + /* Signal/event loss den */ + registryMC.fill(HIST("Events/hEvtMcGen"), 0.5); + if (evtSelOpt.zVtxCutMC && std::abs(mcCollision.posZ()) > evtSelOpt.cutVtxZ) { return; } - if constexpr (isGtZeroColl) { - hPtGenRecEvtGtZero[ChistIdx]->Fill(mult, flat, mcParticle.pt()); - if (mcParticle.isPhysicalPrimary()) { - hPtGenPrimRecEvtGtZero[ChistIdx]->Fill(mult, flat, mcParticle.pt()); - hPtEffGen[ChistIdx]->Fill(mcParticle.pt()); - } - } else { - hPtGenRecEvt[ChistIdx]->Fill(mult, flat, mcParticle.pt()); - if (mcParticle.isPhysicalPrimary()) { - hPtGenPrimRecEvt[ChistIdx]->Fill(mult, flat, mcParticle.pt()); + registryMC.fill(HIST("Events/hEvtMcGen"), 1.5); + if (evtSelOpt.useINELCutMC) { + if (!o2::pwglf::isINELgt0mc(particles, pdg)) { + return; } } - } - - template - void fillMCGen(aod::McParticles::iterator const& mcParticle, const float mult, const float flat) - { - static_assert(pidSgn == CnullInt || pidSgn == ConeInt); - constexpr int ChistIdx = id + pidSgn * Npart; - - if (!isPID(mcParticle)) { + registryMC.fill(HIST("Events/hEvtMcGen"), 2.5); + if (evtSelOpt.useInelgt0wTVX && !(mcCollision.multMCFT0C() <= 0 || mcCollision.multMCFT0A() <= 0)) { return; } + registryMC.fill(HIST("Events/hEvtMcGen"), 3.5); + registryMC.fill(HIST("Events/hNchVsFlatGenINELgt0"), multMC, flatMC); // Evt loss den - if constexpr (evtSel) { - if (!mcParticle.isPhysicalPrimary()) { - if (mcParticle.getProcess() == CprocessIdWeak) { - hPtEffGenWeakEvtSelGen[ChistIdx]->Fill(mult, flat, mcParticle.pt()); - } else { - hPtEffGenMatEvtSelGen[ChistIdx]->Fill(mult, flat, mcParticle.pt()); - } - } else { - hPtEffGenPrimEvtSelGen[ChistIdx]->Fill(mult, flat, mcParticle.pt()); + for (const auto& particle : particles) { + if (!isChrgParticle(particle.pdgCode())) { + continue; } - } else { - if (!mcParticle.isPhysicalPrimary()) { - if (mcParticle.getProcess() == CprocessIdWeak) { - hPtEffGenWeak[ChistIdx]->Fill(mult, flat, mcParticle.pt()); - } else { - hPtEffGenMat[ChistIdx]->Fill(mult, flat, mcParticle.pt()); + if (!particle.isPhysicalPrimary()) { + continue; + } + if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { + continue; + } + static_for<0, 4>([&](auto i) { + constexpr int Cidx = i.value; + if (std::fabs(particle.pdgCode()) == pDGs[Cidx]) { + registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTgenPrimSgn), multMC, flatMC, particle.pt()); // Sgn loss den + registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTmcClosureGenPrim), multMC, flatMC, particle.pt()); // closure } - } else { - hPtEffGenPrim[ChistIdx]->Fill(mult, flat, mcParticle.pt()); + }); + } + + /* Signal/event loss num */ + auto multRec = -999.; + auto flatRec = -999.; + bool gtOneRec = false; + for (const auto& collision : collisions) { + if (!isGoodEvent(collision)) { + continue; } + if (evtSelOpt.removeSplitVertex && collision.globalIndex() != mcCollision.bestCollisionIndex()) { + continue; + } + gtOneRec = true; + multRec = getMult(collision); + flatRec = fillFlat(collision); } - } - Preslice perCollTrk = aod::track::collisionId; + registryMC.fill(HIST("Events/hCentVsFlatRecINELgt0"), multRec, flatRec); // Evt split den - void processMC(CollsMCExtraMult::iterator const& mcCollision, - soa::SmallGroups const& collisions, - aod::BCsWithTimestamps const& /*bcs*/, - aod::FV0As const& /*fv0s*/, - aod::McParticles const& particles, - MyLabeledPIDTracks const& tracks) - { - LOGP(debug, "MC col {} has {} reco cols", mcCollision.globalIndex(), collisions.size()); - auto multMC = -1.; - if (evtSelOpt.useMultMCmidrap || defOpt.multEst == CtwoInt) { // use generated Nch in ∣eta∣ < 0.8 - multMC = countPart(particles); - } else { - multMC = getMultMC(mcCollision); // using McCentFT0Ms + if (gtOneRec) { + registryMC.fill(HIST("Events/hCentVsFlatRecINELgt0wRecEvtSel"), multRec, flatRec); // Evt split num + registryMC.fill(HIST("Events/hNchGenVsCent"), multMC, multRec); + registryMC.fill(HIST("Events/hNchVsFlatGenINELgt0wRecEvtSel"), multMC, flatMC); // Evt loss num + registryMC.fill(HIST("Events/hFlatResponse"), flatMC, flatRec); } - const float flatMC = fillFlatMC(particles); - registryMC.fill(HIST("Events/hFlatMCGen"), flatMC); - // Loop on rec collisions - // Obtain here: Numerator of tracking efficiency; Secondary contamination correction + for (const auto& particle : particles) { + if (!isChrgParticle(particle.pdgCode())) { + continue; + } + if (!particle.isPhysicalPrimary()) { + continue; + } + if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { + continue; + } + if (gtOneRec) { + static_for<0, 4>([&](auto i) { + constexpr int Cidx = i.value; + if (std::fabs(particle.pdgCode()) == pDGs[Cidx]) { + registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTrecCollPrimSgn), multMC, flatMC, particle.pt()); // Sgn loss num + } + }); + } + } + } + PROCESS_SWITCH(FlattenictyPikp, processMcSgnEvtLoss, "process signal/event loss", false); + + void processMcRecTrack(CollsMCExtraMult::iterator const& mcCollision, + soa::SmallGroups const& collisions, + aod::BCsWithTimestamps const& /*bcs*/, + aod::FV0As const& /*fv0s*/, + aod::McParticles const& /*particles*/, + MyLabeledPIDTracks const& tracks) + { for (const auto& collision : collisions) { if (trkSelOpt.rejectTrkAtTPCSector || defOpt.applyCalibGainFromCCDB || defOpt.applyCalibVtxFromCCDB) { auto bc = collision.bc_as(); @@ -2419,84 +2422,24 @@ struct FlattenictyPikp { runNumber = currentRun; } } - registryMC.fill(HIST("Events/hCentVsFlatRecINELgt0"), getMult(collision), fillFlat(collision)); // Evt split den if (evtSelOpt.removeSplitVertex && collision.globalIndex() != mcCollision.bestCollisionIndex()) { continue; } - registryMC.fill(HIST("Events/hCentVsFlatRecINELgt0wRecEvt"), getMult(collision), fillFlat(collision)); // Evt split num, w/ Nrec > 0 - - for (const auto& particle : particles) { - if (!isChrgParticle(particle.pdgCode())) { - continue; - } - if (!particle.isPhysicalPrimary()) { - continue; - } - if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { - continue; - } - if (particle.pt() < trkSelOpt.trkPtMin) { - continue; - } - static_for<0, 1>([&](auto pidSgn) { - fillMCGenRecEvt(particle, multMC, flatMC); - fillMCGenRecEvt(particle, multMC, flatMC); - fillMCGenRecEvt(particle, multMC, flatMC); - }); - } if (!isGoodEvent(collision)) { continue; } - const float multRecGt1 = getMult(collision); + const float multRec = getMult(collision); const float flatRec = fillFlat(collision); - registryMC.fill(HIST("Events/hVtxZRec"), collision.posZ()); - registryMC.fill(HIST("Events/hCentVsFlatRecINELgt0wRecEvtSel"), multRecGt1, flatRec); // Evt split num, w/ Nrec > 0 + Evt. sel - registryMC.fill(HIST("Events/hNchGenVsCent"), multMC, multRecGt1); - registryMC.fill(HIST("Events/hNchVsFlatGenINELgt0wRecEvtSel"), multMC, flatMC); // Evt loss num, w/ Nrec > 0 + Evt. sel - registryMC.fill(HIST("Events/hFlatResponse"), flatMC, flatRec); - - // Obtain here: Denominator of tracking efficiency; Numerator event and signal loss - for (const auto& particle : particles) { - if (!isChrgParticle(particle.pdgCode())) { - continue; - } - if (!particle.isPhysicalPrimary()) { - continue; - } - if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { - continue; - } - if (particle.pt() < trkSelOpt.trkPtMin) { - continue; - } - static_for<0, 1>([&](auto pidSgn) { - fillMCGenRecEvt(particle, multMC, flatMC); - fillMCGenRecEvt(particle, multMC, flatMC); - fillMCGenRecEvt(particle, multMC, flatMC); - }); - static_for<0, 4>([&](auto i) { - constexpr int Cidx = i.value; - if (std::fabs(particle.pdgCode()) == pDGs[Cidx]) { - registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTrecCollPrimSgn), multMC, flatMC, particle.pt()); // Sgn loss num - registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTeffGenPrimRecEvt), multRecGt1, flatRec, particle.pt()); // Tracking eff. den - } - }); - } - - // Rec tracks; track selection w/ DCA open (for secondaries), w/ DCA close (for efficiency) - // Obtain here: DCAxy for sec contamination, MC closure const auto& groupedTrks = tracks.sliceBy(perCollTrk, collision.globalIndex()); - int nTrk = 0; for (const auto& track : groupedTrks) { if (!track.has_collision()) { continue; } - if (!isGoodTrack(track, magField)) { + if (!isGoodTrack(track, magField)) { continue; } if (!track.has_mcParticle()) { - registryMC.fill(HIST("Tracks/hPtFakes"), multMC, flatMC, track.pt()); continue; } auto particle = track.mcParticle_as(); @@ -2509,123 +2452,37 @@ struct FlattenictyPikp { if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { continue; } - if (particle.pt() < trkSelOpt.trkPtMin) { - continue; - } - static_for<0, 1>([&](auto pidSgn) { // for checking purposes only: use gen Nch, gen Flat - fillMCRecTrack(track, multMC, flatMC); - fillMCRecTrack(track, multMC, flatMC); - fillMCRecTrack(track, multMC, flatMC); - }); static_for<0, 4>([&](auto i) { constexpr int Cidx = i.value; if (std::fabs(particle.pdgCode()) == pDGs[Cidx]) { if (!particle.isPhysicalPrimary()) { if (particle.getProcess() == CprocessIdWeak) { - registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTvsDCAxyWeakAll), multRecGt1, flatRec, track.pt(), track.dcaXY()); + registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTvsDCAxyWeakAll), multRec, flatRec, track.pt(), track.dcaXY()); } else { - registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTvsDCAxyMatAll), multRecGt1, flatRec, track.pt(), track.dcaXY()); + registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTvsDCAxyMatAll), multRec, flatRec, track.pt(), track.dcaXY()); } } else { - registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTvsDCAxyPrimAll), multRecGt1, flatRec, track.pt(), track.dcaXY()); - registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CdEdxMcRecPrim), track.eta(), multRecGt1, flatRec, track.p(), track.tpcSignal()); + registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTvsDCAxyPrimAll), multRec, flatRec, track.pt(), track.dcaXY()); + registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CdEdxMcRecPrim), track.eta(), multRec, flatRec, track.p(), track.tpcSignal()); } - registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTvsDCAxyAll), multRecGt1, flatRec, track.pt(), track.dcaXY()); + registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTvsDCAxyAll), multRec, flatRec, track.pt(), track.dcaXY()); } }); - if (isGoodTrack(track, magField)) { + if (isGoodTrack(track, magField)) { static_for<0, 4>([&](auto i) { constexpr int Cidx = i.value; - if (std::sqrt(std::pow(std::fabs(o2::aod::pidutils::tpcNSigma(track)), 2) + std::pow(std::fabs(o2::aod::pidutils::tofNSigma(track)), 2) < trkSelOpt.dcaNsigmaCombinedMax)) { - if (std::fabs(particle.pdgCode()) == pDGs[Cidx]) { - if (particle.isPhysicalPrimary()) { - registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CdEdxMcRecPrimSel), track.eta(), multRecGt1, flatRec, track.p(), track.tpcSignal()); - registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CEtaVsPtVsPMcRecPrimSel), track.eta(), track.pt(), track.p()); - registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTeffPrimRecEvt), multRecGt1, flatRec, track.pt()); // Tracking eff. num - registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTmcClosureRec), multMC, flatMC, track.pt()); // closure - } + if (std::fabs(particle.pdgCode()) == pDGs[Cidx]) { + if (particle.isPhysicalPrimary()) { + registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CdEdxMcRecPrimSel), track.eta(), multRec, flatRec, track.p(), track.tpcSignal()); + registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CEtaVsPtVsPMcRecPrimSel), track.eta(), track.pt(), track.p()); } } }); - nTrk++; } - registryQC.fill(HIST("Tracks/hPtRes"), particle.pt(), (track.pt() - particle.pt()) / particle.pt()); } - registryQC.fill(HIST("Events/hNchVsCent"), nTrk, multRecGt1); - } - static_for<0, 1>([&](auto pidSgn) { - fillEfficiency(); - fillEfficiency(); - fillEfficiency(); - }); - - // Loop on generated particles (no requirement on availaability of reconstructed collision; no event selection) - // - for (const auto& particle : particles) { - if (!isChrgParticle(particle.pdgCode())) { - continue; - } - if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { - continue; - } - if (particle.pt() < trkSelOpt.trkPtMin) { - continue; - } - static_for<0, 1>([&](auto pidSgn) { - fillMCGen(particle, multMC, flatMC); - fillMCGen(particle, multMC, flatMC); - fillMCGen(particle, multMC, flatMC); - }); - } - - // Obtain here: Denominator of signal loss and event loss; MC closure - // - registryMC.fill(HIST("Events/hEvtMcGen"), 0.5); - if (evtSelOpt.zVtxCutMC && std::abs(mcCollision.posZ()) > evtSelOpt.cutVtxZ) { - return; - } - registryMC.fill(HIST("Events/hVtxZGen"), mcCollision.posZ()); - registryMC.fill(HIST("Events/hEvtMcGen"), 1.5); - if (evtSelOpt.useINELCutMC) { - if (!o2::pwglf::isINELgt0mc(particles, pdg)) { - return; - } - } - registryMC.fill(HIST("Events/hEvtMcGen"), 2.5); - if (evtSelOpt.useInelgt0wTVX && !isInelGt0wTVX(particles)) { // TVX trigger: FT0A + FT0C acceptance - return; - } - registryMC.fill(HIST("Events/hEvtMcGen"), 3.5); - registryMC.fill(HIST("Events/hNchVsFlatGenINELgt0"), multMC, flatMC); // Evt loss den - - for (const auto& particle : particles) { - if (!isChrgParticle(particle.pdgCode())) { - continue; - } - if (std::abs(particle.eta()) > trkSelOpt.trkEtaMax) { - continue; - } - if (particle.pt() < trkSelOpt.trkPtMin) { - continue; - } - static_for<0, 1>([&](auto pidSgn) { - fillMCGen(particle, multMC, flatMC); - fillMCGen(particle, multMC, flatMC); - fillMCGen(particle, multMC, flatMC); - }); - static_for<0, 4>([&](auto i) { - constexpr int Cidx = i.value; - // LOG(debug) << "fillMCGen for pidSgn '" << pidSgn << "' and id '" << static_cast(id) << " with index " << ChistIdx; - if (particle.isPhysicalPrimary()) { - if (std::fabs(particle.pdgCode()) == pDGs[Cidx]) { - registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTgenPrimSgn), multMC, flatMC, particle.pt()); // Sgn loss den - registryMC.fill(HIST(Cprefix) + HIST(CspeciesAll[Cidx]) + HIST(CpTmcClosureGenPrim), multMC, flatMC, particle.pt()); // closure - } - } - }); } } - PROCESS_SWITCH(FlattenictyPikp, processMC, "process MC", false); + PROCESS_SWITCH(FlattenictyPikp, processMcRecTrack, "process MC rec tracks", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/GlobalEventProperties/heavyionMultiplicity.cxx b/PWGLF/Tasks/GlobalEventProperties/heavyionMultiplicity.cxx index 2e980905565..cb9f407e7e1 100644 --- a/PWGLF/Tasks/GlobalEventProperties/heavyionMultiplicity.cxx +++ b/PWGLF/Tasks/GlobalEventProperties/heavyionMultiplicity.cxx @@ -494,7 +494,7 @@ struct HeavyionMultiplicity { auto cent = -1; if (isApplyCentFT0C) { cent = col.multMCFT0C(); - } else if (isApplyCentFT0M) { + } else if (isApplyCentFT0M || isApplyCentFT0MAnchorCol || isApplyCentFT0MAnchorBC) { cent = col.multMCFT0C() + col.multMCFT0A(); } else if (isApplyCentFV0A) { cent = col.multMCFV0A(); diff --git a/PWGLF/Tasks/Nuspex/CMakeLists.txt b/PWGLF/Tasks/Nuspex/CMakeLists.txt index a1db5c5f0f4..43450b1a161 100644 --- a/PWGLF/Tasks/Nuspex/CMakeLists.txt +++ b/PWGLF/Tasks/Nuspex/CMakeLists.txt @@ -201,8 +201,13 @@ o2physics_add_dpl_workflow(multiplicity-pt PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(flattenicity-pt-spectra + SOURCES flattenicityPtSpectra.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(deuteron-in-jets-trg-pt - SOURCES DeuteronInJetsTrgPt.cxx + SOURCES deuteronInJetsTrgPt.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::PWGJECore FastJet::FastJet FastJet::Contrib O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) diff --git a/PWGLF/Tasks/Nuspex/NucleiHistTask.cxx b/PWGLF/Tasks/Nuspex/NucleiHistTask.cxx index 6ca24667e9a..6239a7b32c3 100644 --- a/PWGLF/Tasks/Nuspex/NucleiHistTask.cxx +++ b/PWGLF/Tasks/Nuspex/NucleiHistTask.cxx @@ -583,7 +583,7 @@ struct NucleiHistTask { if (!isEventSelected(event)) return; - for (auto track : tracks) { // start loop over all tracks + for (const auto& track : tracks) { // start loop over all tracks histTrackcuts_data_spectra->AddBinContent(1); if (event_selection_sel8 && !event.sel8()) @@ -665,7 +665,7 @@ struct NucleiHistTask { auto par = (std::vector)parShiftPt; Particle_Tpc_nSigma_shift->SetParameters(par[0], par[1], par[2], par[3], par[4], par[5]); } - for (auto track : tracks) { + for (const auto& track : tracks) { float TPCnSigma_particle = -100; float TOFnSigma_particle = -100; @@ -886,7 +886,7 @@ struct NucleiHistTask { if (!event_selection_sel8) spectra_reg.fill(HIST("histCentrality"), event.centFT0C()); - for (auto track : tracks) { + for (const auto& track : tracks) { if ((event_selection_sel8 && !event.sel8()) || (enable_Centrality_cut_global && (event.centFT0C() < minCentrality) && (event.centFT0C() > maxCentrality))) continue; diff --git a/PWGLF/Tasks/Nuspex/QAHistTask.cxx b/PWGLF/Tasks/Nuspex/QAHistTask.cxx index 061cad99809..c8ebb7ca97f 100644 --- a/PWGLF/Tasks/Nuspex/QAHistTask.cxx +++ b/PWGLF/Tasks/Nuspex/QAHistTask.cxx @@ -314,7 +314,7 @@ struct QAHistTask { if (!isEventSelected(event)) return; - for (auto track : tracks) { // start loop over all tracks + for (const auto& track : tracks) { // start loop over all tracks if (event_selection_sel8 && !event.sel8()) continue; @@ -564,7 +564,7 @@ struct QAHistTask { if (!isEventSelected(event)) return; - for (auto track : tracks) { + for (const auto& track : tracks) { if (event_selection_sel8 && !event.sel8()) { continue; diff --git a/PWGLF/Tasks/Nuspex/angularCorrelationsInJets.cxx b/PWGLF/Tasks/Nuspex/angularCorrelationsInJets.cxx index a66555f0246..59c8a005ea6 100644 --- a/PWGLF/Tasks/Nuspex/angularCorrelationsInJets.cxx +++ b/PWGLF/Tasks/Nuspex/angularCorrelationsInJets.cxx @@ -618,7 +618,7 @@ struct AngularCorrelationsInJets { } } - void fillMixedEventDeltas(const auto& track, const auto& buffer, int particleType, const TVector3 jetAxis) // correlate tracks from current event with tracks from buffer, i.e. other events + void fillMixedEventDeltas(const auto& track, const auto& buffer, int particleType, const TVector3& jetAxis) // correlate tracks from current event with tracks from buffer, i.e. other events { if (buffer.size() == 0) return; @@ -680,7 +680,7 @@ struct AngularCorrelationsInJets { } // for (int i = 0; i < static_cast(buffer.size()); i++) } - void doCorrelations(const auto& particleVector, const auto& buffer, auto& tempBuffer, int particleType, const TVector3 jetAxis) + void doCorrelations(const auto& particleVector, const auto& buffer, auto& tempBuffer, int particleType, const TVector3& jetAxis) { if (std::isnan(jetAxis.Phi())) return; @@ -743,7 +743,7 @@ struct AngularCorrelationsInJets { } // for (int i = 0; i < static_cast(particleVector.size()); i++) } - void doCorrelationsAnti(const auto& particleVector, const auto& particleVectorAnti, const auto& bufferAnti, auto& tempBuffer, const TVector3 jetAxis) // correlations between proton/antiproton - same story as doCorrelations but different track vectors are correlated + void doCorrelationsAnti(const auto& particleVector, const auto& particleVectorAnti, const auto& bufferAnti, auto& tempBuffer, const TVector3& jetAxis) // correlations between proton/antiproton - same story as doCorrelations but different track vectors are correlated { if (std::isnan(jetAxis.Phi())) return; @@ -775,7 +775,7 @@ struct AngularCorrelationsInJets { } } - void getPerpendicularAxis(TVector3 p, TVector3& u, double sign) + void getPerpendicularAxis(const TVector3& p, TVector3& u, double sign) { // Initialization double ux(0), uy(0), uz(0); @@ -822,7 +822,7 @@ struct AngularCorrelationsInJets { return; } - int analyseJet(int jetCounter, fastjet::PseudoJet jet, const auto& particles, auto& jetProtons, auto& jetAntiprotons, auto& jetPiPlus, auto& jetPiMinus, auto& jetAll, double rhoPerp, double rhoMPerp) + int analyseJet(int jetCounter, const fastjet::PseudoJet& jet, const auto& particles, auto& jetProtons, auto& jetAntiprotons, auto& jetPiPlus, auto& jetPiMinus, auto& jetAll, double rhoPerp, double rhoMPerp) { if (!jet.has_constituents()) return jetCounter; diff --git a/PWGLF/Tasks/Nuspex/antinucleiInJets.cxx b/PWGLF/Tasks/Nuspex/antinucleiInJets.cxx index f2b28bd38bb..624b5bebb22 100644 --- a/PWGLF/Tasks/Nuspex/antinucleiInJets.cxx +++ b/PWGLF/Tasks/Nuspex/antinucleiInJets.cxx @@ -132,7 +132,7 @@ struct JetMatching { struct AntinucleiInJets { - // Random engine (Mersenne Twister) + // Random Engine (Mersenne Twister) std::mt19937 rng; std::uniform_int_distribution generateRandomNr{0, 1}; @@ -205,14 +205,7 @@ struct AntinucleiInJets { // Configuration parameters for CCDB access and reweighting input files Configurable applyReweighting{"applyReweighting", true, "enable reweighting for efficiency"}; Configurable urlToCcdb{"urlToCcdb", "http://alice-ccdb.cern.ch/", "url of the personal ccdb"}; - Configurable pathToFile{"pathToFile", "Users/a/alcaliva/reweightingHistogramsAnalysis/", "path to file"}; - Configurable weightsProton{"weightsProton", "weightsProton", "weightsProton"}; - Configurable weightsLambda{"weightsLambda", "weightsLambda", "weightsLambda"}; - Configurable weightsSigma{"weightsSigma", "weightsSigma", "weightsSigma"}; - Configurable weightsXi{"weightsXi", "weightsXi", "weightsXi"}; - Configurable weightsOmega{"weightsOmega", "weightsOmega", "weightsOmega"}; - Configurable weightsJet{"weightsJet", "weightsJet", "weightsJet"}; - Configurable weightsUe{"weightsUe", "weightsUe", "weightsUe"}; + Configurable pathToFile{"pathToFile", "Users/a/alcaliva/reweightingHistogramsAntinucleiInJets/", "path to file"}; // Number of events Configurable shrinkInterval{"shrinkInterval", 1000, "variable that controls how often shrinking happens"}; @@ -225,16 +218,18 @@ struct AntinucleiInJets { Configurable coalescenceMomentum{"coalescenceMomentum", 0.15, "p0 (GeV/c)"}; // Reweighting histograms - TH1F* primaryAntiprotons; - TH1F* primaryAntiLambda; - TH1F* primaryAntiSigma; - TH1F* primaryAntiXi; - TH1F* primaryAntiOmega; - TH1F* antiprotonsInsideJets; - TH1F* antiprotonsPerpCone; + TH1F* primaryAntiprotons = nullptr; + TH1F* primaryAntiLambda = nullptr; + TH1F* primaryAntiSigma = nullptr; + TH1F* primaryAntiXi = nullptr; + TH1F* primaryAntiOmega = nullptr; + TH1F* antiprotonsInsideJets = nullptr; + TH1F* antiprotonsPerpCone = nullptr; + TH1F* antideuteronsInsideJets = nullptr; + TH1F* antideuteronsPerpCone = nullptr; // CCDB manager service for accessing condition data - Service ccdb; + Service ccdb{}; // Direct interface to the CCDB API for manual data access o2::ccdb::CcdbApi ccdbApi; @@ -284,7 +279,7 @@ struct AntinucleiInJets { ccdb->setLocalObjectValidityChecking(); ccdb->setCreatedNotAfter(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); ccdb->setFatalWhenNull(false); - getReweightingHistograms(ccdb, TString(pathToFile), TString(weightsProton), TString(weightsLambda), TString(weightsSigma), TString(weightsXi), TString(weightsOmega), TString(weightsJet), TString(weightsUe)); + getReweightingHistograms(ccdb, TString(pathToFile)); } // Binning @@ -395,6 +390,8 @@ struct AntinucleiInJets { // Generated spectra of antideuterons registryMC.add("antideuteron_gen_jet", "antideuteron_gen_jet", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); registryMC.add("antideuteron_gen_ue", "antideuteron_gen_ue", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antideuteron_gen_jet_noweight", "antideuteron_gen_jet_noweight", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); + registryMC.add("antideuteron_gen_ue_noweight", "antideuteron_gen_ue_noweight", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); // Generated spectra of antiprotons for closure test registryMC.add("antiproton_gen_jet_data", "antiproton_gen_jet_data", HistType::kTH1F, {{nbins, min, max, "#it{p}_{T} (GeV/#it{c})"}}); @@ -686,7 +683,7 @@ struct AntinucleiInJets { } } - void getReweightingHistograms(o2::framework::Service const& ccdbObj, TString filepath, TString antip, TString antilambda, TString antisigma, TString antixi, TString antiomega, TString jet, TString ue) + void getReweightingHistograms(o2::framework::Service const& ccdbObj, TString const& filepath) { TList* list = ccdbObj->get(filepath.Data()); if (!list) { @@ -695,21 +692,28 @@ struct AntinucleiInJets { } // Get reweighting histograms for primary fraction - primaryAntiprotons = static_cast(list->FindObject(antip)); - primaryAntiLambda = static_cast(list->FindObject(antilambda)); - primaryAntiSigma = static_cast(list->FindObject(antisigma)); - primaryAntiXi = static_cast(list->FindObject(antixi)); - primaryAntiOmega = static_cast(list->FindObject(antiomega)); + primaryAntiprotons = dynamic_cast(list->FindObject("weightsProton")); + primaryAntiLambda = dynamic_cast(list->FindObject("weightsLambda")); + primaryAntiSigma = dynamic_cast(list->FindObject("weightsSigma")); + primaryAntiXi = dynamic_cast(list->FindObject("weightsXi")); + primaryAntiOmega = dynamic_cast(list->FindObject("weightsOmega")); if (!primaryAntiprotons || !primaryAntiSigma || !primaryAntiLambda || !primaryAntiXi || !primaryAntiOmega) { LOGP(error, "Missing one or more reweighting histograms for primary fraction in CCDB list"); } - // Get reweighting histograms for efficiency - antiprotonsInsideJets = static_cast(list->FindObject(jet)); - antiprotonsPerpCone = static_cast(list->FindObject(ue)); + // Get reweighting histograms for antiproton efficiency + antiprotonsInsideJets = dynamic_cast(list->FindObject("weightsJet")); + antiprotonsPerpCone = dynamic_cast(list->FindObject("weightsUe")); if (!antiprotonsInsideJets || !antiprotonsPerpCone) { - LOGP(error, "Missing one or more reweighting histograms for efficiency in CCDB list"); + LOGP(error, "Missing one or more reweighting histograms for antiproton efficiency in CCDB list"); + } + + // Get reweighting histograms for antideuteron efficiency + antideuteronsInsideJets = dynamic_cast(list->FindObject("weightsAntidJet")); + antideuteronsPerpCone = dynamic_cast(list->FindObject("weightsAntidUe")); + if (!antideuteronsInsideJets || !antideuteronsPerpCone) { + LOGP(error, "Missing one or more reweighting histograms for antideuteron efficiency in CCDB list"); } LOGP(info, "Successfully loaded reweighting histograms from CCDB path"); @@ -770,7 +774,7 @@ struct AntinucleiInJets { // Evaluate proton–neutron coalescence for deuteron formation template - bool passDeuteronCoalescence(const ReducedPart& p, const ReducedPart& n, double p0, TRandom3& mRand) + bool passDeuteronCoalescence(const ReducedPart& p, const ReducedPart& n, double p0, TRandom3& random) { // Nucleon masses const double mp = o2::constants::physics::MassProton; @@ -810,7 +814,7 @@ struct AntinucleiInJets { } // Spin-statistical acceptance - if (mRand.Uniform() > SpinFactor) { + if (random.Uniform() > SpinFactor) { return false; } return true; @@ -1784,6 +1788,8 @@ struct AntinucleiInJets { case PDG_t::kSigmaBarMinus: registryMC.fill(HIST("sigmaBar"), particle.pt()); break; + default: + break; } } } @@ -2188,7 +2194,14 @@ struct AntinucleiInJets { // Fill antideuteron spectra if (isAntid) { - registryMC.fill(HIST("antideuteron_gen_jet"), particle.pt()); + double weightJetAntid(1.0); + if (applyReweighting && particle.pt() < antideuteronsInsideJets->GetXaxis()->GetXmax()) { + int ipt = antideuteronsInsideJets->FindBin(particle.pt()); + weightJetAntid = antideuteronsInsideJets->GetBinContent(ipt); + } + + registryMC.fill(HIST("antideuteron_gen_jet"), particle.pt(), weightJetAntid); + registryMC.fill(HIST("antideuteron_gen_jet_noweight"), particle.pt()); } } @@ -2255,8 +2268,16 @@ struct AntinucleiInJets { if (deltaRUe1 > rJet && deltaRUe2 > rJet) continue; + // Calculate weight + double weightUeAntid(1.0); + if (applyReweighting && deuteronVec.Pt() < antideuteronsPerpCone->GetXaxis()->GetXmax()) { + int ipt = antideuteronsPerpCone->FindBin(deuteronVec.Pt()); + weightUeAntid = antideuteronsPerpCone->GetBinContent(ipt); + } + // Fill histogram for antideuterons in the UE - registryMC.fill(HIST("antideuteron_gen_ue"), deuteronVec.Pt()); + registryMC.fill(HIST("antideuteron_gen_ue"), deuteronVec.Pt(), weightUeAntid); + registryMC.fill(HIST("antideuteron_gen_ue_noweight"), deuteronVec.Pt()); } } if (isAtLeastOneJetSelected) { @@ -2512,7 +2533,7 @@ struct AntinucleiInJets { // Fill antiproton spectrum for physical primaries registryMC.fill(HIST("antiproton_prim_jet"), pt); - // Calculate weight + // Calculate weights double weightJet(1.0); if (applyReweighting && mcparticle.pt() < antiprotonsInsideJets->GetXaxis()->GetXmax()) { int ipt = antiprotonsInsideJets->FindBin(mcparticle.pt()); @@ -2549,16 +2570,23 @@ struct AntinucleiInJets { if (std::fabs(dcaxy) > maxDcaxy || std::fabs(dcaz) > maxDcaz) continue; - // Select physical primary antiprotons + // Select physical primary antideuterons if (!mcparticle.isPhysicalPrimary()) continue; + // Calculate weight + double weightJetAntid(1.0); + if (applyReweighting && mcparticle.pt() < antideuteronsInsideJets->GetXaxis()->GetXmax()) { + int ipt = antideuteronsInsideJets->FindBin(mcparticle.pt()); + weightJetAntid = antideuteronsInsideJets->GetBinContent(ipt); + } + // Fill histograms (TPC and TOF) only for selected candidates if (nsigmaTPCDe > minNsigmaTpc && nsigmaTPCDe < maxNsigmaTpc) { - registryMC.fill(HIST("antideuteron_rec_tpc_jet"), pt); + registryMC.fill(HIST("antideuteron_rec_tpc_jet"), pt, weightJetAntid); if (track.hasTOF() && nsigmaTOFDe > minNsigmaTof && nsigmaTOFDe < maxNsigmaTof) { - registryMC.fill(HIST("antideuteron_rec_tof_jet"), pt); + registryMC.fill(HIST("antideuteron_rec_tof_jet"), pt, weightJetAntid); } } } // end of isAntid @@ -2624,7 +2652,7 @@ struct AntinucleiInJets { // Fill antiproton spectrum for physical primaries registryMC.fill(HIST("antiproton_prim_ue"), pt); - // Calculate weight + // Calculate weights double weightUe(1.0); if (applyReweighting && mcparticle.pt() < antiprotonsPerpCone->GetXaxis()->GetXmax()) { int ipt = antiprotonsPerpCone->FindBin(mcparticle.pt()); @@ -2689,16 +2717,23 @@ struct AntinucleiInJets { if (deltaRUe1 > rJet && deltaRUe2 > rJet) continue; - // Select physical primary antiprotons + // Select physical primary antideuterons if (!mcparticle.isPhysicalPrimary()) continue; + // Calculate weight + double weightUeAntid(1.0); + if (applyReweighting && mcparticle.pt() < antideuteronsPerpCone->GetXaxis()->GetXmax()) { + int ipt = antideuteronsPerpCone->FindBin(mcparticle.pt()); + weightUeAntid = antideuteronsPerpCone->GetBinContent(ipt); + } + // Fill histograms (TPC and TOF) only for selected candidates if (nsigmaTPCDe > minNsigmaTpc && nsigmaTPCDe < maxNsigmaTpc) { - registryMC.fill(HIST("antideuteron_rec_tpc_ue"), pt); + registryMC.fill(HIST("antideuteron_rec_tpc_ue"), pt, weightUeAntid); if (track.hasTOF() && nsigmaTOFDe > minNsigmaTof && nsigmaTOFDe < maxNsigmaTof) { - registryMC.fill(HIST("antideuteron_rec_tof_ue"), pt); + registryMC.fill(HIST("antideuteron_rec_tof_ue"), pt, weightUeAntid); } } } @@ -2962,6 +2997,8 @@ struct AntinucleiInJets { case -o2::constants::physics::Pdg::kHelium3: registryMC.fill(HIST("antihelium3_gen_syst"), particle.pt()); break; + default: + break; } } } diff --git a/PWGLF/Tasks/Nuspex/DeuteronInJetsTrgPt.cxx b/PWGLF/Tasks/Nuspex/deuteronInJetsTrgPt.cxx similarity index 83% rename from PWGLF/Tasks/Nuspex/DeuteronInJetsTrgPt.cxx rename to PWGLF/Tasks/Nuspex/deuteronInJetsTrgPt.cxx index 903b319c1aa..82123748283 100644 --- a/PWGLF/Tasks/Nuspex/DeuteronInJetsTrgPt.cxx +++ b/PWGLF/Tasks/Nuspex/deuteronInJetsTrgPt.cxx @@ -9,7 +9,12 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. // -// Task for analysing (anti)deuteron production in jets using pT-triggered data - update: 05-02-2026 +/// \file deuteronInJetsTrgPt.cxx +/// \brief d and antid production in and out of jets using pTjet triggered data +/// +/// \author Cristian Moscatelli +/// \since 02/2026 +// ================ // // Executable : o2-analysis-lf-deuteron-in-jets-trg-pt @@ -73,16 +78,15 @@ struct DeuteronInJetsTrgPt { // Setting default selection criteria to select tracks. May be changed when configuring the analysis. struct : o2::framework::ConfigurableGroup { - std::string prefix{"cfgTrackCut"}; // General specific Configurable requirePvContributor{"requirePvContributor", false, "Require that the track is a PV contributor"}; - Configurable EtaMax{"EtaMax", 0.9f, "Max Eta for track acceptance"}; + Configurable etaMax{"etaMax", 0.9f, "Max Eta for track acceptance"}; Configurable minPt{"minPt", 0.3, "Minimum pt of the tracks"}; Configurable maxDcaxy{"maxDcaxy", 0.05, "Maximum DCAxy"}; Configurable maxDcaz{"maxDcaz", 0.05, "Maximum DCAz"}; // Part relative to ITS - Configurable ITSnClusMin{"ITSnClsMin", 6, "Minimum number of ITS clusters"}; - Configurable ITSchi2ClusMax{"ITSchi2ClusMax", 36.f, "Max ITS Chi2 per cluster"}; + Configurable itsNClusMin{"itsNClusMin", 6, "Minimum number of ITS clusters"}; + Configurable itsChi2ClusMax{"itsChi2ClusMax", 36.f, "Max ITS Chi2 per cluster"}; Configurable applyItsPid{"applyItsPid", false, "apply ITS PID"}; Configurable setMCDefaultItsParams{"setMCDefaultItsParams", true, "Set MC default parameters for ITS PID"}; Configurable nSigmaItsMin{"nSigmaItsMin", -3.0, "nSigmaITS min"}; @@ -90,24 +94,18 @@ struct DeuteronInJetsTrgPt { Configurable ptMaxItsPidProt{"ptMaxItsPidProt", 1.0, "maximum pt for ITS PID for protons"}; Configurable ptMaxItsPidDeut{"ptMaxItsPidDeut", 1.0, "maximum pt for ITS PID for deuterons"}; // Part relative to TPC - Configurable TPCnClsMin{"TPCnClsMin", 100, "Minimum number of TPC clusters"}; - Configurable TPCchi2ClusMin{"TPCchi2ClusMin", 0.f, "Min TPC Chi2 per cluster"}; - Configurable TPCchi2ClusMax{"TPCchi2ClusMax", 4.f, "Max TPC Chi2 per cluster"}; - Configurable TPCnCrossedRowsMin{"TPCnCrossedRowsMin", 100, "Minimum number of TPC crossed rows"}; - Configurable Rtpc{"minRtpc", 0.8, "Minimum value of TPC crossed rows/TPC n cluster findable"}; - Configurable TPCrigidityMin{"TPCrigidityMin", 0.3f, "Minimum TPC rigidity (p/Z) for track"}; - Configurable minNsigmaTpc{"minNsigmaTpc", -3.0, "Minimum nsigma TPC"}; - Configurable maxNsigmaTpc{"maxNsigmaTpc", +3.0, "Maximum nsigma TPC"}; - // Part relatuive to TOF - Configurable minNsigmaTof{"minNsigmaTof", -3.0, "Minimum nsigma TOF"}; - Configurable maxNsigmaTof{"maxNsigmaTof", +3.5, "Maximum nsigma TOF"}; + Configurable tpcNClsMin{"tpcNClsMin", 100, "Minimum number of TPC clusters"}; + Configurable tpcChi2ClusMin{"tpcChi2ClusMin", 0.f, "Min TPC Chi2 per cluster"}; + Configurable tpcChi2ClusMax{"tpcChi2ClusMax", 4.f, "Max TPC Chi2 per cluster"}; + Configurable tpcNCrossedRowsMin{"tpcNCrossedRowsMin", 100, "Minimum number of TPC crossed rows"}; + Configurable minNsigmaTpc{"minNsigmaTpc", -3.0, "Minimum nsigma TPC for TOF analysis"}; + Configurable maxNsigmaTpc{"maxNsigmaTpc", +3.0, "Maximum nsigma TPC for TOF analysis"}; } cfgTrackCut; // Setting default selection criteria for events. May be changes when configuring the analysis. struct : o2::framework::ConfigurableGroup { - std::string prefix{"cgfEventCut"}; Configurable zVtx{"zVtx", 10.0, "Maximum z vertex"}; - } cfgEvCut; + } cfgEventCut; // Skimmed data flag and list of active triggers for processing Configurable cfgSkimmedProcessing{"cfgSkimmedProcessing", false, "Skimmed dataset processing"}; @@ -115,16 +113,15 @@ struct DeuteronInJetsTrgPt { // Setting default selection criteria fr jet identification. May be changes when configuring the analysis. struct : o2::framework::ConfigurableGroup { - std::string prefix{"cgfJetCut"}; Configurable minJetPt{"minJetPt", 10.0, "Minimum pt of the jet after bkg subtraction"}; Configurable rJet{"rJet", 0.3, "Jet parameter R"}; Configurable deltaEtaEdge{"deltaEtaEdge", 0.05, "eta gap from the edge"}; } cfgJetCut; // Setting the number of bins and min and max value for the nsigma distribution - Configurable cfgNbins{"Nbins", 120, "Number of pT-bins"}; - Configurable cfgpt_min{"pt_min", 0.0, "Min pT value of pT-axis"}; - Configurable cfgpt_max{"pt_max", 6.0, "Max pT value of pT-axis"}; + Configurable cfgNbins{"cfgNbins", 120, "Number of pT-bins"}; + Configurable cfgPtMin{"cfgPtMin", 0.0, "Min pT value of pT-axis"}; + Configurable cfgPtMax{"cfgPtMax", 6.0, "Max pT value of pT-axis"}; // CCDB manager service for accessing condition data Service ccdb; @@ -159,45 +156,45 @@ struct DeuteronInJetsTrgPt { itsResponse.setMCDefaultParameters(); // Initialize random seed using high-resolution clock to ensure unique sequences across parallel Grid jobs - auto time_seed = std::chrono::high_resolution_clock::now().time_since_epoch().count(); - mRand.SetSeed(time_seed); + auto timeSeed = std::chrono::high_resolution_clock::now().time_since_epoch().count(); + mRand.SetSeed(timeSeed); // Histrograms for real data if (doprocessData) { registryData.add("number_of_events_data", "number of events in data", HistType::kTH1F, {{4, 0, 4, "counter"}}); // Event counters - registryData.add("settingData", "settingData", HistType::kTH2F, {{100, 0.0, 50.0, "min #it{p}^{jet}_{T} [GeV/#it{c}]"}, {20, 0.0, 1.0, "#it{R}_{jet}"}}); // Configuration + registryData.add("settingData", "settingData", HistType::kTH2F, {{100, 0.0, 50.0, "min #it{p}^{jet}_{T} (GeV/#it{c})"}, {20, 0.0, 1.0, "#it{R}_{jet}"}}); // Configuration registryData.add("jetEffectiveAreaOverPiR2", "jet effective area / piR^2", HistType::kTH1F, {{2000, 0, 2, "Area/#piR^{2}"}}); // Jet effective area over piR^2 // Antiprotons - registryData.add("antiproton_jet_tpc", "antiproton_jet_tpc", HistType::kTH2F, {{cfgNbins, cfgpt_min, cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); - registryData.add("antiproton_jet_tof", "antiproton_jet_tof", HistType::kTH2F, {{cfgNbins, cfgpt_min, cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); - registryData.add("antiproton_ue_tpc", "antiproton_ue_tpc", HistType::kTH2F, {{cfgNbins, cfgpt_min, cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); - registryData.add("antiproton_ue_tof", "antiproton_ue_tof", HistType::kTH2F, {{cfgNbins, cfgpt_min, cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); - registryData.add("antiproton_dca_jet", "antiproton_dca_jet", HistType::kTH2F, {{cfgNbins, cfgpt_min, cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {200, -1.0, 1.0, "DCA_{xy} [cm]"}}); - registryData.add("antiproton_dca_ue", "antiproton_dca_ue", HistType::kTH2F, {{cfgNbins, cfgpt_min, cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {200, -1.0, 1.0, "DCA_{xy} [cm]"}}); + registryData.add("antiproton_jet_tpc", "antiproton_jet_tpc", HistType::kTH2F, {{cfgNbins, cfgPtMin, cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {1000, -20.0, 20.0, "n#sigma_{TPC}"}}); + registryData.add("antiproton_jet_tof", "antiproton_jet_tof", HistType::kTH2F, {{cfgNbins, cfgPtMin, cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {1000, -20.0, 20.0, "n#sigma_{TOF}"}}); + registryData.add("antiproton_ue_tpc", "antiproton_ue_tpc", HistType::kTH2F, {{cfgNbins, cfgPtMin, cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {1000, -20.0, 20.0, "n#sigma_{TPC}"}}); + registryData.add("antiproton_ue_tof", "antiproton_ue_tof", HistType::kTH2F, {{cfgNbins, cfgPtMin, cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {1000, -20.0, 20.0, "n#sigma_{TOF}"}}); + registryData.add("antiproton_dca_jet", "antiproton_dca_jet", HistType::kTH2F, {{cfgNbins, cfgPtMin, cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {2000, -1.0, 1.0, "DCA_{xy} (cm)"}}); + registryData.add("antiproton_dca_ue", "antiproton_dca_ue", HistType::kTH2F, {{cfgNbins, cfgPtMin, cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {2000, -1.0, 1.0, "DCA_{xy} (cm)"}}); // protons - registryData.add("proton_jet_tpc", "proton_jet_tpc", HistType::kTH2F, {{cfgNbins, cfgpt_min, cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); - registryData.add("proton_jet_tof", "proton_jet_tof", HistType::kTH2F, {{cfgNbins, cfgpt_min, cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); - registryData.add("proton_ue_tpc", "proton_ue_tpc", HistType::kTH2F, {{cfgNbins, cfgpt_min, cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); - registryData.add("proton_ue_tof", "proton_ue_tof", HistType::kTH2F, {{cfgNbins, cfgpt_min, cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); - registryData.add("proton_dca_jet", "proton_dca_jet", HistType::kTH2F, {{cfgNbins, cfgpt_min, cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {200, -1.0, 1.0, "DCA_{xy} [cm]"}}); - registryData.add("proton_dca_ue", "proton_dca_ue", HistType::kTH2F, {{cfgNbins, cfgpt_min, cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {200, -1.0, 1.0, "DCA_{xy} [cm]"}}); + registryData.add("proton_jet_tpc", "proton_jet_tpc", HistType::kTH2F, {{cfgNbins, cfgPtMin, cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {1000, -20.0, 20.0, "n#sigma_{TPC}"}}); + registryData.add("proton_jet_tof", "proton_jet_tof", HistType::kTH2F, {{cfgNbins, cfgPtMin, cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {1000, -20.0, 20.0, "n#sigma_{TOF}"}}); + registryData.add("proton_ue_tpc", "proton_ue_tpc", HistType::kTH2F, {{cfgNbins, cfgPtMin, cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {1000, -20.0, 20.0, "n#sigma_{TPC}"}}); + registryData.add("proton_ue_tof", "proton_ue_tof", HistType::kTH2F, {{cfgNbins, cfgPtMin, cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {1000, -20.0, 20.0, "n#sigma_{TOF}"}}); + registryData.add("proton_dca_jet", "proton_dca_jet", HistType::kTH2F, {{cfgNbins, cfgPtMin, cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {2000, -1.0, 1.0, "DCA_{xy} (cm)"}}); + registryData.add("proton_dca_ue", "proton_dca_ue", HistType::kTH2F, {{cfgNbins, cfgPtMin, cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {2000, -1.0, 1.0, "DCA_{xy} (cm)"}}); // Antideuterons - registryData.add("antideuteron_jet_tpc", "antideuteron_jet_tpc", HistType::kTH2F, {{cfgNbins, 2 * cfgpt_min, 2 * cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); - registryData.add("antideuteron_jet_tof", "antideuteron_jet_tof", HistType::kTH2F, {{cfgNbins, 2 * cfgpt_min, 2 * cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); - registryData.add("antideuteron_ue_tpc", "antideuteron_ue_tpc", HistType::kTH2F, {{cfgNbins, 2 * cfgpt_min, 2 * cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); - registryData.add("antideuteron_ue_tof", "antideuteron_ue_tof", HistType::kTH2F, {{cfgNbins, 2 * cfgpt_min, 2 * cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); + registryData.add("antideuteron_jet_tpc", "antideuteron_jet_tpc", HistType::kTH2F, {{cfgNbins, 2 * cfgPtMin, 2 * cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {1000, -20.0, 20.0, "n#sigma_{TPC}"}}); + registryData.add("antideuteron_jet_tof", "antideuteron_jet_tof", HistType::kTH2F, {{cfgNbins, 2 * cfgPtMin, 2 * cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {1000, -20.0, 20.0, "n#sigma_{TOF}"}}); + registryData.add("antideuteron_ue_tpc", "antideuteron_ue_tpc", HistType::kTH2F, {{cfgNbins, 2 * cfgPtMin, 2 * cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {1000, -20.0, 20.0, "n#sigma_{TPC}"}}); + registryData.add("antideuteron_ue_tof", "antideuteron_ue_tof", HistType::kTH2F, {{cfgNbins, 2 * cfgPtMin, 2 * cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {1000, -20.0, 20.0, "n#sigma_{TOF}"}}); // Deuterons - registryData.add("deuteron_jet_tpc", "deuteron_jet_tpc", HistType::kTH2F, {{cfgNbins, 2 * cfgpt_min, 2 * cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); - registryData.add("deuteron_jet_tof", "deuteron_jet_tof", HistType::kTH2F, {{cfgNbins, 2 * cfgpt_min, 2 * cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); - registryData.add("deuteron_ue_tpc", "deuteron_ue_tpc", HistType::kTH2F, {{cfgNbins, 2 * cfgpt_min, 2 * cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {400, -20.0, 20.0, "n#sigma_{TPC}"}}); - registryData.add("deuteron_ue_tof", "deuteron_ue_tof", HistType::kTH2F, {{cfgNbins, 2 * cfgpt_min, 2 * cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {400, -20.0, 20.0, "n#sigma_{TOF}"}}); + registryData.add("deuteron_jet_tpc", "deuteron_jet_tpc", HistType::kTH2F, {{cfgNbins, 2 * cfgPtMin, 2 * cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {1000, -20.0, 20.0, "n#sigma_{TPC}"}}); + registryData.add("deuteron_jet_tof", "deuteron_jet_tof", HistType::kTH2F, {{cfgNbins, 2 * cfgPtMin, 2 * cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {1000, -20.0, 20.0, "n#sigma_{TOF}"}}); + registryData.add("deuteron_ue_tpc", "deuteron_ue_tpc", HistType::kTH2F, {{cfgNbins, 2 * cfgPtMin, 2 * cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {1000, -20.0, 20.0, "n#sigma_{TPC}"}}); + registryData.add("deuteron_ue_tof", "deuteron_ue_tof", HistType::kTH2F, {{cfgNbins, 2 * cfgPtMin, 2 * cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {1000, -20.0, 20.0, "n#sigma_{TOF}"}}); // nsigmaITS for antiproton candidates - registryData.add("antiproton_nsigma_its_data", "antiproton_nsigma_its_data", HistType::kTH2F, {{cfgNbins, cfgpt_min, cfgpt_max, "#it{p}_{T} [GeV/#it{c}]"}, {400, -20.0, 20.0, "n#sigma_{ITS}"}}); + registryData.add("antiproton_nsigma_its_data", "antiproton_nsigma_its_data", HistType::kTH2F, {{cfgNbins, cfgPtMin, cfgPtMax, "#it{p}_{T} (GeV/#it{c})"}, {1000, -20.0, 20.0, "n#sigma_{ITS}"}}); } } @@ -286,7 +283,7 @@ struct DeuteronInJetsTrgPt { static constexpr double DcazMaxTrack = 2.0; // General part - if (std::fabs(track.eta()) > cfgTrackCut.EtaMax) + if (std::fabs(track.eta()) > cfgTrackCut.etaMax) return false; if (track.pt() < MinPtTrack) return false; @@ -319,7 +316,7 @@ struct DeuteronInJetsTrgPt { // General part if (cfgTrackCut.requirePvContributor && !(track.isPVContributor())) return false; // Flag to check if the track contributed to the collision vertex fit - if (std::fabs(track.eta()) > cfgTrackCut.EtaMax) + if (std::fabs(track.eta()) > cfgTrackCut.etaMax) return false; // Eta if (track.pt() < cfgTrackCut.minPt) return false; @@ -328,23 +325,21 @@ struct DeuteronInJetsTrgPt { return false; // Flag to check if track has a ITS match if ((!hasHitITS(track, 1)) && (!hasHitITS(track, 2)) && (!hasHitITS(track, 3))) return false; // Require IB hit - if (track.itsNCls() < cfgTrackCut.ITSnClusMin) + if (track.itsNCls() < cfgTrackCut.itsNClusMin) return false; // Minimum number of ITS cluster - if (track.itsChi2NCl() > cfgTrackCut.ITSchi2ClusMax) + if (track.itsChi2NCl() > cfgTrackCut.itsChi2ClusMax) return false; // Minimum chi2 per cluster in ITS // Part relative to TPC if (!track.hasTPC()) return false; // Flag to check if track has a ITS match - if (track.tpcNClsFound() < cfgTrackCut.TPCnClsMin) + if (track.tpcNClsFound() < cfgTrackCut.tpcNClsMin) return false; // Minimum number of TPC cluster - if (track.tpcNClsCrossedRows() < cfgTrackCut.TPCnCrossedRowsMin) + if (track.tpcNClsCrossedRows() < cfgTrackCut.tpcNCrossedRowsMin) return false; // Minimum number of crossed rows in TPC - if (track.tpcChi2NCl() < cfgTrackCut.TPCchi2ClusMin) + if (track.tpcChi2NCl() < cfgTrackCut.tpcChi2ClusMin) return false; // Minimum chi2 per cluster in TPC - if (track.tpcChi2NCl() > cfgTrackCut.TPCchi2ClusMax) + if (track.tpcChi2NCl() > cfgTrackCut.tpcChi2ClusMax) return false; // Maximum chi2 per cluster in TPC - if (track.tpcCrossedRowsOverFindableCls() < cfgTrackCut.Rtpc) - return false; // R_{TPC} > 0.8 return true; } @@ -359,13 +354,13 @@ struct DeuteronInJetsTrgPt { auto bc = collision.template bc_as(); initCCDB(bc); - // If skimmed processing is enabled, aplly Zorro trigger selection + // If skimmed processing is enabled, apply Zorro trigger selection if (cfgSkimmedProcessing && !zorro.isSelected(collision.template bc_as().globalBC())) return; registryData.fill(HIST("number_of_events_data"), 1.5); // Apply standard event selection - if (!collision.sel8() || std::fabs(collision.posZ()) >= cfgEvCut.zVtx) + if (!collision.sel8() || std::fabs(collision.posZ()) >= cfgEventCut.zVtx) return; registryData.fill(HIST("number_of_events_data"), 2.5); // Save number of collisions that passed standard selections @@ -397,7 +392,7 @@ struct DeuteronInJetsTrgPt { bool isAtLeastOneJetSelected = false; for (auto const& jet : jets) { - if ((std::fabs(jet.eta()) + cfgJetCut.rJet) > (cfgTrackCut.EtaMax - cfgJetCut.deltaEtaEdge)) + if ((std::fabs(jet.eta()) + cfgJetCut.rJet) > (cfgTrackCut.etaMax - cfgJetCut.deltaEtaEdge)) continue; // Jet must be fully contained in the acceptance // Jet pt must be larger than threshold diff --git a/PWGLF/Tasks/Nuspex/flattenicityPtSpectra.cxx b/PWGLF/Tasks/Nuspex/flattenicityPtSpectra.cxx new file mode 100644 index 00000000000..f3af6e7b3ee --- /dev/null +++ b/PWGLF/Tasks/Nuspex/flattenicityPtSpectra.cxx @@ -0,0 +1,313 @@ +// 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. +/// +/// \author Dushmanta Sahu (dushmanta.sahus@cern.ch) +/// \since September 1, 2026 +/// \file flattenicityPtSpectra.cxx +/// \brief Analysis to do flattenicity pt spectra + +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/FT0Corrected.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; + +using MyTracks = soa::Join; + +using MyCollisions = soa::Join; + +struct FlattenicityPtSpectra { + + Configurable etaMin{"etaMin", -0.8f, "Min eta for mid-rapidity tracks"}; + Configurable etaMax{"etaMax", 0.8f, "Max eta for mid-rapidity tracks"}; + Configurable ptMin{"ptMin", 0.15f, "Min pT (GeV/c)"}; + Configurable ptMax{"ptMax", 20.0f, "Max pT (GeV/c)"}; + Configurable minTPCnClsFound{"minTPCnClsFound", 70, "Min TPC found clusters"}; + Configurable maxDCAz{"maxDCAz", 2.0f, "Max |DCAz| (cm)"}; + Configurable maxVtxZ{"maxVtxZ", 10.0f, "Max |vtx z| (cm)"}; + + Configurable minActiveFT0Ch{"minActiveFT0Ch", 4, "Min active FT0 channels for flattenicity"}; + + static constexpr int NChA = 96; + static constexpr int NChC = 96; + static constexpr int NCells = NChA + NChC; // 192 total + + HistogramRegistry registry{ + "registry", + {}, + OutputObjHandlingPolicy::AnalysisObject, + true, + true}; + + template + bool isGoodTrack(TrackType const& track) const + { + if (!track.hasTPC()) + return false; + if (track.tpcNClsFound() < minTPCnClsFound.value) + return false; + if (track.eta() < etaMin.value || track.eta() > etaMax.value) + return false; + if (std::abs(track.dcaZ()) > maxDCAz.value) + return false; + if (track.pt() < ptMin.value || track.pt() > ptMax.value) + return false; + return true; + } + + float calculateFlattenicityFT0(aod::FT0 const& ft0, int minActive) const + { + std::array signals{}; + signals.fill(0.f); + + int nActive = 0; + + int chIdx = 0; + for (const auto& a : ft0.amplitudeA()) { + if (chIdx < NChA) { + float amp = static_cast(a); + if (amp > 0.f) { + signals[chIdx] = amp; + ++nActive; + } + } + ++chIdx; + } + + chIdx = 0; + for (const auto& a : ft0.amplitudeC()) { + if (chIdx < NChC) { + float amp = static_cast(a); + if (amp > 0.f) { + signals[NChA + chIdx] = amp; + ++nActive; + } + } + ++chIdx; + } + + if (nActive < minActive) + return -1.f; + + float mRho = 0.f; + for (int i = 0; i < NCells; ++i) { + mRho += signals[i]; + } + mRho /= static_cast(NCells); + if (mRho <= 0.f) + return -1.f; + + float sRhoTmp = 0.f; + for (int i = 0; i < NCells; ++i) { + if (signals[i] > 0.f) { + float d = signals[i] - mRho; + sRhoTmp += d * d; + } + } + sRhoTmp /= static_cast(NCells) * static_cast(NCells); + float sRho = std::sqrt(sRhoTmp); + + // flattenicity = 1 - sigma/mean, clamped to [0, 1] + float cv = sRho / mRho; + return std::max(0.f, std::min(1.f, 1.f - cv)); + } + + void init(InitContext const&) + { + AxisSpec ptAxis{200, 0.0f, 20.0f, "#it{p}_{T} (GeV/c)"}; + AxisSpec flatAxis{102, -0.01f, 1.01f, "Flattenicity"}; + AxisSpec multAxis{300, 0.f, 3000.f, "FT0M amplitude (a.u.)"}; + AxisSpec nchAxis{500, -0.5f, 499.5f, "Raw N_{ch} (|#eta|<0.8, p_{T}>0.15)"}; + AxisSpec vtxzAxis{200, -20.f, 20.f, "v_{z} (cm)"}; + + registry.add("hEventCounter", + "Event counter", + HistType::kTH1F, {{5, 0.5, 5.5}}); + registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(1, "All"); + registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(2, "vtxZ"); + registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(3, "hasFT0"); + registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(4, "FT0signal"); + registry.get(HIST("hEventCounter"))->GetXaxis()->SetBinLabel(5, "goodFlat"); + + registry.add("hVtxZ", + "Primary vertex z", + HistType::kTH1F, {vtxzAxis}); + + registry.add("hFT0MMultiplicity", + "FT0M amplitude sum", + HistType::kTH1F, {multAxis}); + + registry.add("hFlattenicityDistribution", + "Flattenicity (Gyula method, 192 FT0 ch)", + HistType::kTH1F, {flatAxis}); + + registry.add("hFT0AAmplitude", + "Total FT0A amplitude", + HistType::kTH1F, {{200, 0.f, 2000.f, "Amplitude (a.u.)"}}); + + registry.add("hFT0CAmplitude", + "Total FT0C amplitude", + HistType::kTH1F, {{200, 0.f, 2000.f, "Amplitude (a.u.)"}}); + + // QA: active channel count — use this to tune minActiveFT0Ch + registry.add("hNActiveFT0Channels", + "Active FT0 channels per event (amp > 0)", + HistType::kTH1F, {{193, -0.5f, 192.5f, "N active channels"}}); + + registry.add("hEtaDistribution", + "Eta distribution (selected tracks)", + HistType::kTH1F, {{100, -1.0f, 1.0f, "#eta"}}); + + registry.add("hPhiDistribution", + "Phi distribution (selected tracks)", + HistType::kTH1F, {{100, 0.f, o2::constants::math::TwoPI, "#phi"}}); + + registry.add("hPtSpectrum_All", + "pT spectrum (all selected events)", + HistType::kTH1F, {ptAxis}); + + registry.add("hFT0MMultVsFlattenicity", + "FT0M multiplicity vs Flattenicity;" + "FT0M amplitude (a.u.);Flattenicity", + HistType::kTH2F, {multAxis, flatAxis}); + + registry.add("hFT0MMultVsFlattenicityVsPt", + "FT0M multiplicity vs Flattenicity vs #it{p}_{T};" + "FT0M amplitude (a.u.);Flattenicity;#it{p}_{T} (GeV/c)", + HistType::kTH3F, {multAxis, flatAxis, ptAxis}); + + registry.add("hNchDistribution", + "Raw charged particle multiplicity", + HistType::kTH1F, {nchAxis}); + + registry.add("hNchVsFlattenicity", + "Raw N_{ch} vs Flattenicity;" + "Raw N_{ch};Flattenicity", + HistType::kTH2F, {nchAxis, flatAxis}); + + registry.add("hNchVsFlattenicityVsPt", + "Raw N_{ch} vs Flattenicity vs #it{p}_{T};" + "Raw N_{ch};Flattenicity;#it{p}_{T} (GeV/c)", + HistType::kTH3F, {nchAxis, flatAxis, ptAxis}); + + LOG(info) << "FlattenicityPtSpectra::init — done" + << " NCells=" << NCells + << " minActiveFT0Ch=" << minActiveFT0Ch.value + << " Flattenicity method: Gyula (fixed denominator = total channels)"; + } + + void process(MyCollisions::iterator const& collision, + MyTracks const& tracks, + aod::FT0s const& /*ft0s*/) + { + registry.fill(HIST("hEventCounter"), 1.f); + + if (std::abs(collision.posZ()) > maxVtxZ.value) + return; + registry.fill(HIST("hEventCounter"), 2.f); + registry.fill(HIST("hVtxZ"), collision.posZ()); + + if (!collision.has_foundFT0()) + return; + registry.fill(HIST("hEventCounter"), 3.f); + + auto ft0 = collision.foundFT0(); + + float sumA = 0.f, sumC = 0.f; + int nActive = 0; + for (const auto& a : ft0.amplitudeA()) { + if (a > 0.f) { + sumA += a; + ++nActive; + } + } + for (const auto& a : ft0.amplitudeC()) { + if (a > 0.f) { + sumC += a; + ++nActive; + } + } + + registry.fill(HIST("hFT0AAmplitude"), sumA); + registry.fill(HIST("hFT0CAmplitude"), sumC); + registry.fill(HIST("hNActiveFT0Channels"), static_cast(nActive)); + + if (sumA + sumC <= 0.f) + return; + registry.fill(HIST("hEventCounter"), 4.f); + + float flattenicity = calculateFlattenicityFT0(ft0, minActiveFT0Ch.value); + if (flattenicity < 0.f) + return; + registry.fill(HIST("hEventCounter"), 5.f); + + float multFT0M = collision.multFT0M(); + + registry.fill(HIST("hFT0MMultiplicity"), multFT0M); + registry.fill(HIST("hFlattenicityDistribution"), flattenicity); + registry.fill(HIST("hFT0MMultVsFlattenicity"), multFT0M, flattenicity); + + std::vector goodTracks; + goodTracks.reserve(1000); + + for (const auto& track : tracks) { + if (!isGoodTrack(track)) + continue; + goodTracks.push_back(track); + } + + int rawNch = goodTracks.size(); + + // Fill per-event histograms with Nch + registry.fill(HIST("hNchDistribution"), rawNch); + registry.fill(HIST("hNchVsFlattenicity"), rawNch, flattenicity); + + // Fill per-track histograms using the collected good tracks + for (const auto& track : goodTracks) { + registry.fill(HIST("hEtaDistribution"), track.eta()); + registry.fill(HIST("hPhiDistribution"), track.phi()); + registry.fill(HIST("hPtSpectrum_All"), track.pt()); + registry.fill(HIST("hFT0MMultVsFlattenicityVsPt"), + multFT0M, flattenicity, track.pt()); + + // NEW: Fill Nch-based 3D histogram + registry.fill(HIST("hNchVsFlattenicityVsPt"), + rawNch, flattenicity, track.pt()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Nuspex/hadronnucleicorrelation.cxx b/PWGLF/Tasks/Nuspex/hadronnucleicorrelation.cxx index 33d9ee0e40d..d516e1e7a64 100644 --- a/PWGLF/Tasks/Nuspex/hadronnucleicorrelation.cxx +++ b/PWGLF/Tasks/Nuspex/hadronnucleicorrelation.cxx @@ -9,6 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. // +/// \file hadronnucleicorrelation.cxx /// \brief Hadron-nuclei correlation analysis task /// \author Francesca Ercolessi /// \since 21 April 2024 @@ -40,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -78,7 +78,7 @@ enum Origin { struct HadronNucleiCorrelation { - static constexpr int betahasTOFthr = -100; + static constexpr int BetahasTOFthr = -100; SliceCache cache; @@ -152,32 +152,32 @@ struct HadronNucleiCorrelation { using FilteredTracksMC = soa::Filtered>; // new tables (v3) HistogramRegistry registry{"registry"}; - HistogramRegistry QA{"QA"}; + HistogramRegistry registryQa{"registryQa"}; - using trkType = const FilteredTracks::iterator*; - // using trkTypeMC = const FilteredTracksMC::iterator*; - // typedef std::shared_ptr colType; + using TrkType = const FilteredTracks::iterator*; + // using TrkTypeMC = const FilteredTracksMC::iterator*; + // typedef std::shared_ptr ColType; // typedef std::shared_ptr MCcolType; - std::unique_ptr> Pair = std::make_unique>(); - // std::unique_ptr> PairMC = std::make_unique>(); + std::unique_ptr> pair = std::make_unique>(); + // std::unique_ptr> PairMC = std::make_unique>(); // Data histograms - std::vector> hEtaPhi_SE; - std::vector> hEtaPhi_ME; - std::vector> hCorrEtaPhi_SE; - std::vector> hCorrEtaPhi_ME; - - int nBinspT; - TH2F* hEffpTEta_proton; - TH2F* hEffpTEta_antiproton; - TH2F* hEffpTEta_deuteron; - TH2F* hEffpTEta_antideuteron; - - Service ccdb; + std::vector> hEtaPhiSameEv; + std::vector> hEtaPhiMixdEv; + std::vector> hCorrEtaPhiSameEv; + std::vector> hCorrEtaPhiMixdEv; + + int nBinspT = 0; + TH2F* hEffPtEtaProton = nullptr; + TH2F* hEffPtEtaAntiProton = nullptr; + TH2F* hEffPtEtaDeuteron = nullptr; + TH2F* hEffPtEtaAntiDeuteron = nullptr; + + Service ccdb{}; o2::ccdb::CcdbApi ccdbApi; - Service pdgDB; + Service pdgDB{}; void init(o2::framework::InitContext&) { @@ -188,174 +188,175 @@ struct HadronNucleiCorrelation { ccdb->setFatalWhenNull(false); if (doCorrection) { - GetCorrection(ccdb, TString(fCorrectionPath), TString(fCorrectionHisto)); - } else { - hEffpTEta_proton = nullptr; - hEffpTEta_antiproton = nullptr; - hEffpTEta_deuteron = nullptr; - hEffpTEta_antideuteron = nullptr; + getCorrection(ccdb, TString(fCorrectionPath), TString(fCorrectionHisto)); } - AxisSpec ptBinnedAxis = {pTBins, "#it{p}_{T} of #bar{p} (GeV/c)"}; - AxisSpec etaAxis = {100, -1., 1., "#eta"}; - AxisSpec phiAxis = {157, 0., o2::constants::math::TwoPI, "#phi (rad)"}; - AxisSpec pTAxis = {200, -10.f, 10.f, "p_{T} GeV/c"}; - AxisSpec pTAxis_small = {100, -5.f, 5.f, "p_{T} GeV/c"}; + const AxisSpec ptBinnedAxis = {pTBins, "#it{p}_{T} of #bar{p} (GeV/#it{c})"}; + const AxisSpec etaAxis = {100, -1., 1., "#eta"}; + const AxisSpec phiAxis = {157, 0., o2::constants::math::TwoPI, "#phi (rad)"}; + const AxisSpec ptAxis = {200, -10.f, 10.f, "#it{p}_{T} GeV/#it{c}"}; + const AxisSpec ptAxisSmall = {100, -5.f, 5.f, "#it{p}_{T} GeV/#it{c}"}; - AxisSpec DeltaEtaAxis = {300, -1.5, 1.5, "#Delta#eta"}; - AxisSpec DeltaRapAxis = {300, -1.5, 1.5, "#Delta y"}; + const AxisSpec deltaEtaAxis = {300, -1.5, 1.5, "#Delta#eta"}; + const AxisSpec deltaRapAxis = {300, -1.5, 1.5, "#Delta y"}; - registry.add("hNEvents", "hNEvents", {HistType::kTH1D, {{7, 0.f, 7.f}}}); - registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(1, "Selected"); - registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(2, "Mixing"); + if (doprocessSameEvent || doprocessSameEventEvSel) { + registry.add("hNEvents", "hNEvents", {HistType::kTH1D, {{7, 0.f, 7.f}}}); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(1, "Selected"); + registry.get(HIST("hNEvents"))->GetXaxis()->SetBinLabel(2, "Mixing"); + } - registry.add("hNtrig_total", "hNtrig_total", {HistType::kTH1D, {ptBinnedAxis}}); + // Not used, commented out for now + // registry.add("hNtrig_total", "hNtrig_total", {HistType::kTH1D, {ptBinnedAxis}}); nBinspT = pTBins.value.size() - 1; - TString name = "AntiDeAntiPr"; + TString name = "Undefined"; switch (mode) { - case kDP: + case kDbarPbar: // 0 + name = "AntiDeAntiPr"; + break; + case kDP: // 1 name = "DePr"; break; - case kDbarP: + case kDbarP: // 2 name = "AntiDePr"; break; - case kDPbar: + case kDPbar: // 3 name = "DeAntiPr"; break; - case kPbarP: + case kPbarP: // 4 name = "AntiPrPr"; break; - case kPbarPbar: + case kPbarPbar: // 5 name = "AntiPrAntiPr"; break; - case kPP: + case kPP: // 6 name = "PrPr"; break; - case kPPbar: + case kPPbar: // 7 name = "PrAntiPr"; break; + default: + LOG(fatal) << "Unhandled case " << mode; } if (!isMC) { for (int i = 0; i < nBinspT; i++) { - + const TString ptTag = Form("pt%02.0f%02.0f", pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10); + const TString ptInterval = Form("(%.1f(Form("hEtaPhi_%s_SE_%s", name.Data(), ptTag.Data()), "Raw #Delta y #Delta#phi " + ptInterval, {HistType::kTH3F, {deltaRapAxis, deltaPhiAxis, ptBinnedAxis}})); + hEtaPhiMixdEv.push_back(registry.add(Form("hEtaPhi_%s_ME_%s", name.Data(), ptTag.Data()), "Raw #Delta y #Delta#phi " + ptInterval, {HistType::kTH3F, {deltaRapAxis, deltaPhiAxis, ptBinnedAxis}})); - auto htempSE_AntiDeAntiPr = registry.add(Form("hEtaPhi_%s_SE_pt%02.0f%02.0f", name.Data(), pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), Form("Raw #Delta y #Delta#phi (%.1f(Form("hEtaPhi_%s_ME_pt%02.0f%02.0f", name.Data(), pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), Form("Raw #Delta y #Delta#phi (%.1f(Form("hCorrEtaPhi_%s_SE_pt%02.0f%02.0f", name.Data(), pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), Form("#Delta y #Delta#phi (%.1f(Form("hCorrEtaPhi_%s_ME_pt%02.0f%02.0f", name.Data(), pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), Form("#Delta y #Delta#phi (%.1f(Form("hCorrEtaPhi_%s_SE_%s", name.Data(), ptTag.Data()), "#Delta y #Delta#phi " + ptInterval, {HistType::kTH3F, {deltaRapAxis, deltaPhiAxis, ptBinnedAxis}})); + hCorrEtaPhiMixdEv.push_back(registry.add(Form("hCorrEtaPhi_%s_ME_%s", name.Data(), ptTag.Data()), "#Delta y #Delta#phi " + ptInterval, {HistType::kTH3F, {deltaRapAxis, deltaPhiAxis, ptBinnedAxis}})); } else { + hEtaPhiSameEv.push_back(registry.add(Form("hEtaPhi_%s_SE_%s", name.Data(), ptTag.Data()), "Raw #Delta#eta#Delta#phi " + ptInterval, {HistType::kTH3F, {deltaEtaAxis, deltaPhiAxis, ptBinnedAxis}})); + hEtaPhiMixdEv.push_back(registry.add(Form("hEtaPhi_%s_ME_%s", name.Data(), ptTag.Data()), "Raw #Delta#eta#Delta#phi " + ptInterval, {HistType::kTH3F, {deltaEtaAxis, deltaPhiAxis, ptBinnedAxis}})); - auto htempSE_AntiDeAntiPr = registry.add(Form("hEtaPhi_%s_SE_pt%02.0f%02.0f", name.Data(), pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), Form("Raw #Delta#eta#Delta#phi (%.1f(Form("hEtaPhi_%s_ME_pt%02.0f%02.0f", name.Data(), pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), Form("Raw #Delta#eta#Delta#phi (%.1f(Form("hCorrEtaPhi_%s_SE_pt%02.0f%02.0f", name.Data(), pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), Form("#Delta#eta#Delta#phi (%.1f(Form("hCorrEtaPhi_%s_ME_pt%02.0f%02.0f", name.Data(), pTBins.value.at(i) * 10, pTBins.value.at(i + 1) * 10), Form("#Delta#eta#Delta#phi (%.1f(Form("hCorrEtaPhi_%s_SE_%s", name.Data(), ptTag.Data()), "#Delta#eta#Delta#phi " + ptInterval, {HistType::kTH3F, {deltaEtaAxis, deltaPhiAxis, ptBinnedAxis}})); + hCorrEtaPhiMixdEv.push_back(registry.add(Form("hCorrEtaPhi_%s_ME_%s", name.Data(), ptTag.Data()), "#Delta#eta#Delta#phi " + ptInterval, {HistType::kTH3F, {deltaEtaAxis, deltaPhiAxis, ptBinnedAxis}})); } } } - registry.add("hPrDCAxy", "DCAxy p", {HistType::kTH2D, {{600, -3.f, 3.f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); - registry.add("hAntiPrDCAxy", "DCAxy #bar{p}", {HistType::kTH2D, {{600, -3.f, 3.f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); - registry.add("hDeDCAxy", "DCAxy d", {HistType::kTH2D, {{600, -3.f, 3.f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); - registry.add("hAntiDeDCAxy", "DCAxy #bar{d}", {HistType::kTH2D, {{600, -3.f, 3.f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); + if (doprocessSameEvent || doprocessSameEventEvSel || doprocessMC) { + registry.add("hPrDCAxy", "DCAxy p", {HistType::kTH2D, {{600, -3.f, 3.f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); + registry.add("hAntiPrDCAxy", "DCAxy #bar{p}", {HistType::kTH2D, {{600, -3.f, 3.f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); + registry.add("hDeDCAxy", "DCAxy d", {HistType::kTH2D, {{600, -3.f, 3.f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); + registry.add("hAntiDeDCAxy", "DCAxy #bar{d}", {HistType::kTH2D, {{600, -3.f, 3.f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); + } registry.add("hMult", "multiplicity", {HistType::kTH1D, {{200, 0.f, 200.f, "N_{ch}"}}}); - if (doQA) { + if (doQA && (doprocessSameEvent || doprocessSameEventEvSel || doprocessMC)) { // Track QA - QA.add("QA/hVtxZ_trk", "#it{z}_{vtx}", {HistType::kTH1D, {{150, -15.f, 15.f, "#it{z}_{vtx} (cm)"}}}); - QA.add("QA/hTPCnClusters", "N TPC Clusters; N TPC Clusters", {HistType::kTH1D, {{200, 0.f, 200.f}}}); - QA.add("QA/hTPCSharedClusters", "N TPC Shared Clusters; N TPC SharedClusters", {HistType::kTH1D, {{100, 0.f, 1.f}}}); - QA.add("QA/hTPCchi2", "TPC chi2/Ncls; TPC chi2/Ncls", {HistType::kTH1D, {{100, 0.f, 10.f}}}); - QA.add("QA/hTPCcrossedRowsOverFindableCls", "TPC crossed Rows Over Findable Cls; TPC Crossed Rows Over Findable Cls", {HistType::kTH1D, {{100, 0.f, 2.f}}}); - QA.add("QA/hITSchi2", "ITS chi2/Ncls; ITS chi2/Ncls", {HistType::kTH1D, {{100, 0.f, 20.f}}}); - QA.add("QA/hDCAxy", "DCAxy", {HistType::kTH2D, {{200, -0.2f, 0.2f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); - QA.add("QA/hDCAz", "DCAz", {HistType::kTH2D, {{200, -0.2f, 0.2f, "DCA z (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); - QA.add("QA/TPCChi2VsPZ", "TPCChi2VsPZ", {HistType::kTH2D, {{100, 0.f, 10.f, "p_{TPC}/Z (GeV/c)"}, {120, 0.f, 6.f, "TPC Chi2"}}}); - QA.add("QA/h2dTPCTOF_Pr", "n#sigma TPC vs n#sigma TOF; n#sigma TPC; n#sigma TOF", {HistType::kTH2D, {axisNSigma, axisNSigma}}); - QA.add("QA/h2dTPCTOF_AntiPr", "n#sigma TPC vs n#sigma TOF; n#sigma TPC; n#sigma TOF", {HistType::kTH2D, {axisNSigma, axisNSigma}}); - QA.add("QA/hnSigmaTPCVsPt_El", "n#sigma TPC vs p_{T} for e hypothesis (all tracks); p_{T} (GeV/c); n#sigma TPC", {HistType::kTH2D, {pTAxis, axisNSigma}}); - QA.add("QA/hnSigmaTPCVsPt_Pr", "n#sigma TPC vs p_{T} for p hypothesis (all tracks); p_{T} (GeV/c); n#sigma TPC", {HistType::kTH2D, {pTAxis, axisNSigma}}); - QA.add("QA/hnSigmaTPCVsPt_De", "n#sigma TPC vs p_{T} for d hypothesis (all tracks); p_{T} (GeV/c); n#sigma TPC", {HistType::kTH2D, {pTAxis, axisNSigma}}); - QA.add("QA/hnSigmaTOFVsPt_Pr", "n#sigma TOF vs p_{T} for p hypothesis (all tracks); p_{T} (GeV/c); n#sigma TOF", {HistType::kTH2D, {pTAxis, axisNSigma}}); - QA.add("QA/hnSigmaTOFVsPt_De", "n#sigma TOF vs p_{T} for d hypothesis (all tracks); p_{T} (GeV/c); n#sigma TOF", {HistType::kTH2D, {pTAxis, axisNSigma}}); - QA.add("QA/hnSigmaITSVsPt_Pr", "n#sigma ITS vs p_{T} for p hypothesis (all tracks); p_{T} (GeV/c); n#sigma ITS", {HistType::kTH2D, {pTAxis, axisNSigma}}); - QA.add("QA/hnSigmaITSVsPt_De", "n#sigma ITS vs p_{T} for d hypothesis (all tracks); p_{T} (GeV/c); n#sigma ITS", {HistType::kTH2D, {pTAxis, axisNSigma}}); - QA.add("QA/hdEtadPhistar", ";dPhi*;dEta ", {HistType::kTH2D, {{101, -0.2, 0.2, "dPhi*"}, {101, -0.2, 0.2, "dEta"}}}); + registryQa.add("QA/hVtxZ_trk", "#it{z}_{vtx}", {HistType::kTH1D, {{150, -15.f, 15.f, "#it{z}_{vtx} (cm)"}}}); + registryQa.add("QA/hTPCnClusters", "N TPC Clusters; N TPC Clusters", {HistType::kTH1D, {{200, 0.f, 200.f}}}); + registryQa.add("QA/hTPCSharedClusters", "N TPC Shared Clusters; N TPC SharedClusters", {HistType::kTH1D, {{100, 0.f, 1.f}}}); + registryQa.add("QA/hTPCchi2", "TPC chi2/Ncls; TPC chi2/Ncls", {HistType::kTH1D, {{100, 0.f, 10.f}}}); + registryQa.add("QA/hTPCcrossedRowsOverFindableCls", "TPC crossed Rows Over Findable Cls; TPC Crossed Rows Over Findable Cls", {HistType::kTH1D, {{100, 0.f, 2.f}}}); + registryQa.add("QA/hITSchi2", "ITS chi2/Ncls; ITS chi2/Ncls", {HistType::kTH1D, {{100, 0.f, 20.f}}}); + registryQa.add("QA/hDCAxy", "DCAxy", {HistType::kTH2D, {{200, -0.2f, 0.2f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); + registryQa.add("QA/hDCAz", "DCAz", {HistType::kTH2D, {{200, -0.2f, 0.2f, "DCA z (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); + registryQa.add("QA/TPCChi2VsPZ", "TPCChi2VsPZ", {HistType::kTH2D, {{100, 0.f, 10.f, "p_{TPC}/Z (GeV/c)"}, {120, 0.f, 6.f, "TPC Chi2"}}}); + const AxisSpec tofNSigmaAxis = {axisNSigma, "n#sigma TOF"}; + const AxisSpec tpcNSigmaAxis = {axisNSigma, "n#sigma TPC"}; + const AxisSpec itsNSigmaAxis = {axisNSigma, "n#sigma ITS"}; + registryQa.add("QA/h2dTPCTOF_Pr", "n#sigma TPC vs n#sigma TOF", {HistType::kTH2D, {tpcNSigmaAxis, tofNSigmaAxis}}); + registryQa.add("QA/h2dTPCTOF_AntiPr", "n#sigma TPC vs n#sigma TOF", {HistType::kTH2D, {tpcNSigmaAxis, tofNSigmaAxis}}); + registryQa.add("QA/hnSigmaTPCVsPt_El", "n#sigma TPC vs p_{T} for e hypothesis (all tracks)", {HistType::kTH2D, {ptAxis, tpcNSigmaAxis}}); + registryQa.add("QA/hnSigmaTPCVsPt_Pr", "n#sigma TPC vs p_{T} for p hypothesis (all tracks)", {HistType::kTH2D, {ptAxis, tpcNSigmaAxis}}); + registryQa.add("QA/hnSigmaTPCVsPt_De", "n#sigma TPC vs p_{T} for d hypothesis (all tracks)", {HistType::kTH2D, {ptAxis, tpcNSigmaAxis}}); + registryQa.add("QA/hnSigmaTOFVsPt_Pr", "n#sigma TOF vs p_{T} for p hypothesis (all tracks)", {HistType::kTH2D, {ptAxis, tofNSigmaAxis}}); + registryQa.add("QA/hnSigmaTOFVsPt_De", "n#sigma TOF vs p_{T} for d hypothesis (all tracks)", {HistType::kTH2D, {ptAxis, tofNSigmaAxis}}); + registryQa.add("QA/hnSigmaITSVsPt_Pr", "n#sigma ITS vs p_{T} for p hypothesis (all tracks)", {HistType::kTH2D, {ptAxis, itsNSigmaAxis}}); + registryQa.add("QA/hnSigmaITSVsPt_De", "n#sigma ITS vs p_{T} for d hypothesis (all tracks)", {HistType::kTH2D, {ptAxis, itsNSigmaAxis}}); + registryQa.add("QA/hdEtadPhistar", ";dPhi*;dEta ", {HistType::kTH2D, {{101, -0.2, 0.2, "dPhi*"}, {101, -0.2, 0.2, "dEta"}}}); if (!isMC) { - QA.add("QA/hEtaPr", Form("#eta ditribution for p"), {HistType::kTH1F, {etaAxis}}); - QA.add("QA/hPhiPr", Form("#phi ditribution for p"), {HistType::kTH1F, {phiAxis}}); - QA.add("QA/hEtaAntiPr", Form("#eta ditribution for #bar{p}"), {HistType::kTH1F, {etaAxis}}); - QA.add("QA/hPhiAntiPr", Form("#phi ditribution for #bar{p}"), {HistType::kTH1F, {phiAxis}}); - QA.add("QA/hEtaDe", Form("#eta ditribution for d"), {HistType::kTH1F, {etaAxis}}); - QA.add("QA/hPhiDe", Form("#phi ditribution for d"), {HistType::kTH1F, {phiAxis}}); - QA.add("QA/hEtaAntiDe", Form("#eta ditribution for #bar{d}"), {HistType::kTH1F, {etaAxis}}); - QA.add("QA/hPhiAntiDe", Form("#phi ditribution for #bar{d}"), {HistType::kTH1F, {phiAxis}}); - - QA.add("QA/hnSigmaTPCVsPt_Pr_AfterSel", "n#sigma TPC vs p_{T} for p hypothesis (all tracks); p_{T} (GeV/c); n#sigma TPC", {HistType::kTH2D, {pTAxis, axisNSigma}}); - QA.add("QA/hnSigmaTPCVsPt_De_AfterSel", "n#sigma TPC vs p_{T} for d hypothesis (all tracks); p_{T} (GeV/c); n#sigma TPC", {HistType::kTH2D, {pTAxis, axisNSigma}}); - QA.add("QA/hnSigmaTOFVsPt_Pr_AfterSel", "n#sigma TOF vs p_{T} for p hypothesis (all tracks); p_{T} (GeV/c); n#sigma TOF", {HistType::kTH2D, {pTAxis, axisNSigma}}); - QA.add("QA/hnSigmaTOFVsPt_De_AfterSel", "n#sigma TOF vs p_{T} for d hypothesis (all tracks); p_{T} (GeV/c); n#sigma TOF", {HistType::kTH2D, {pTAxis, axisNSigma}}); - QA.add("QA/hnSigmaITSVsPt_Pr_AfterSel", "n#sigma ITS vs p_{T} for p hypothesis (all tracks); p_{T} (GeV/c); n#sigma ITS", {HistType::kTH2D, {pTAxis, axisNSigma}}); - QA.add("QA/hnSigmaITSVsPt_De_AfterSel", "n#sigma ITS vs p_{T} for d hypothesis (all tracks); p_{T} (GeV/c); n#sigma ITS", {HistType::kTH2D, {pTAxis, axisNSigma}}); - QA.add("QA/h2dTPCTOF_Pr_AfterSel", "n#sigma TPC vs n#sigma TOF; n#sigma TPC; n#sigma TOF", {HistType::kTH2D, {axisNSigma, axisNSigma}}); - QA.add("QA/h2dTPCTOF_AntiPr_AfterSel", "n#sigma TPC vs n#sigma TOF; n#sigma TPC; n#sigma TOF", {HistType::kTH2D, {axisNSigma, axisNSigma}}); + registryQa.add("QA/hEtaPr", Form("#eta ditribution for p"), {HistType::kTH1F, {etaAxis}}); + registryQa.add("QA/hPhiPr", Form("#phi ditribution for p"), {HistType::kTH1F, {phiAxis}}); + registryQa.add("QA/hEtaAntiPr", Form("#eta ditribution for #bar{p}"), {HistType::kTH1F, {etaAxis}}); + registryQa.add("QA/hPhiAntiPr", Form("#phi ditribution for #bar{p}"), {HistType::kTH1F, {phiAxis}}); + registryQa.add("QA/hEtaDe", Form("#eta ditribution for d"), {HistType::kTH1F, {etaAxis}}); + registryQa.add("QA/hPhiDe", Form("#phi ditribution for d"), {HistType::kTH1F, {phiAxis}}); + registryQa.add("QA/hEtaAntiDe", Form("#eta ditribution for #bar{d}"), {HistType::kTH1F, {etaAxis}}); + registryQa.add("QA/hPhiAntiDe", Form("#phi ditribution for #bar{d}"), {HistType::kTH1F, {phiAxis}}); + + registryQa.add("QA/hnSigmaTPCVsPt_Pr_AfterSel", "n#sigma TPC vs p_{T} for p hypothesis (all tracks)", {HistType::kTH2D, {ptAxis, tpcNSigmaAxis}}); + registryQa.add("QA/hnSigmaTPCVsPt_De_AfterSel", "n#sigma TPC vs p_{T} for d hypothesis (all tracks)", {HistType::kTH2D, {ptAxis, tpcNSigmaAxis}}); + registryQa.add("QA/hnSigmaTOFVsPt_Pr_AfterSel", "n#sigma TOF vs p_{T} for p hypothesis (all tracks)", {HistType::kTH2D, {ptAxis, tofNSigmaAxis}}); + registryQa.add("QA/hnSigmaTOFVsPt_De_AfterSel", "n#sigma TOF vs p_{T} for d hypothesis (all tracks)", {HistType::kTH2D, {ptAxis, tofNSigmaAxis}}); + registryQa.add("QA/hnSigmaITSVsPt_Pr_AfterSel", "n#sigma ITS vs p_{T} for p hypothesis (all tracks)", {HistType::kTH2D, {ptAxis, itsNSigmaAxis}}); + registryQa.add("QA/hnSigmaITSVsPt_De_AfterSel", "n#sigma ITS vs p_{T} for d hypothesis (all tracks)", {HistType::kTH2D, {ptAxis, itsNSigmaAxis}}); + registryQa.add("QA/h2dTPCTOF_Pr_AfterSel", "n#sigma TPC vs n#sigma TOF", {HistType::kTH2D, {tpcNSigmaAxis, tofNSigmaAxis}}); + registryQa.add("QA/h2dTPCTOF_AntiPr_AfterSel", "n#sigma TPC vs n#sigma TOF", {HistType::kTH2D, {tpcNSigmaAxis, tofNSigmaAxis}}); } } if (isMC && doprocessMC) { - registry.add("hPrimPrDCAxy", "DCAxy p", {HistType::kTH2D, {{600, -3.f, 3.f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); - registry.add("hPrimAntiPrDCAxy", "DCAxy #bar{p}", {HistType::kTH2D, {{600, -3.f, 3.f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); - registry.add("hPrimDeDCAxy", "DCAxy d", {HistType::kTH2D, {{600, -3.f, 3.f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); - registry.add("hPrimAntiDeDCAxy", "DCAxy #bar{d}", {HistType::kTH2D, {{600, -3.f, 3.f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); - registry.add("hSecMatPrDCAxy", "DCAxy p", {HistType::kTH2D, {{600, -3.f, 3.f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); - registry.add("hSecMatAntiPrDCAxy", "DCAxy #bar{p}", {HistType::kTH2D, {{600, -3.f, 3.f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); - registry.add("hSecMatDeDCAxy", "DCAxy d", {HistType::kTH2D, {{600, -3.f, 3.f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); - registry.add("hSecMatAntiDeDCAxy", "DCAxy #bar{d}", {HistType::kTH2D, {{600, -3.f, 3.f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); - registry.add("hSecWeakPrDCAxy", "DCAxy p", {HistType::kTH2D, {{600, -3.f, 3.f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); - registry.add("hSecWeakAntiPrDCAxy", "DCAxy #bar{p}", {HistType::kTH2D, {{600, -3.f, 3.f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); - registry.add("hSecWeakDeDCAxy", "DCAxy d", {HistType::kTH2D, {{600, -3.f, 3.f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); - registry.add("hSecWeakAntiDeDCAxy", "DCAxy #bar{d}", {HistType::kTH2D, {{600, -3.f, 3.f, "DCA xy (cm)"}, {100, 0.f, 10.f, "p_{T} GeV/c"}}}); - - registry.add("hReco_EtaPhiPt_Proton", "Gen (anti)protons in reco collisions", {HistType::kTH3F, {etaAxis, phiAxis, pTAxis_small}}); - registry.add("hReco_EtaPhiPt_Deuteron", "Gen (anti)deuteron in reco collisions", {HistType::kTH3F, {etaAxis, phiAxis, pTAxis_small}}); - registry.add("hReco_PID_EtaPhiPt_Proton", "Gen (anti)protons + PID in reco collisions", {HistType::kTH3F, {etaAxis, phiAxis, pTAxis_small}}); - registry.add("hReco_PID_EtaPhiPt_Deuteron", "Gen (anti)deuteron + PID in reco collisions", {HistType::kTH3F, {etaAxis, phiAxis, pTAxis_small}}); - registry.add("hReco_EtaPhiPtMC_Proton", "Gen (anti)protons in reco collisions (MC info used)", {HistType::kTH3F, {etaAxis, phiAxis, pTAxis_small}}); - registry.add("hReco_EtaPhiPtMC_Deuteron", "Gen (anti)deuteron in reco collisions (MC info used)", {HistType::kTH3F, {etaAxis, phiAxis, pTAxis_small}}); - registry.add("hReco_Pt_Proton", "Reco (anti)protons in reco collisions", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hReco_Pt_Deuteron", "Reco (anti)deuterons in reco collisions", {HistType::kTH1F, {pTAxis_small}}); - - registry.add("hSec_EtaPhiPt_Proton", "Secondary (anti)protons", {HistType::kTH3F, {etaAxis, phiAxis, pTAxis_small}}); - registry.add("hPrimSec_EtaPhiPt_Proton", "Primary + Secondary (anti)protons", {HistType::kTH3F, {etaAxis, phiAxis, pTAxis_small}}); - - registry.add("hnSigmaTPCVsPt_Pr_MC", "n#sigma TPC vs p_{T} for p hypothesis true MC; p_{T} (GeV/c); n#sigma TPC", {HistType::kTH2F, {pTAxis, axisNSigma}}); - registry.add("hnSigmaTPCVsPt_De_MC", "n#sigma TPC vs p_{T} for d hypothesis true MC; p_{T} (GeV/c); n#sigma TPC", {HistType::kTH2F, {pTAxis, axisNSigma}}); - registry.add("hnSigmaTOFVsPt_Pr_MC", "n#sigma TOF vs p_{T} for p hypothesis true MC; p_{T} (GeV/c); n#sigma TOF", {HistType::kTH2F, {pTAxis, axisNSigma}}); - registry.add("hnSigmaTOFVsPt_De_MC", "n#sigma TOF vs p_{T} for d hypothesis true MC; p_{T} (GeV/c); n#sigma TOF", {HistType::kTH2F, {pTAxis, axisNSigma}}); + const AxisSpec dcaAxis = {600, -3.f, 3.f, "DCA xy (cm)"}; + const AxisSpec mcPtAxis = {100, 0.f, 10.f, "#it{p}_{T} GeV/#it{c}"}; + registry.add("hPrimPrDCAxy", "DCAxy p", {HistType::kTH2D, {dcaAxis, mcPtAxis}}); + registry.add("hPrimAntiPrDCAxy", "DCAxy #bar{p}", {HistType::kTH2D, {dcaAxis, mcPtAxis}}); + registry.add("hPrimDeDCAxy", "DCAxy d", {HistType::kTH2D, {dcaAxis, mcPtAxis}}); + registry.add("hPrimAntiDeDCAxy", "DCAxy #bar{d}", {HistType::kTH2D, {dcaAxis, mcPtAxis}}); + registry.add("hSecMatPrDCAxy", "DCAxy p", {HistType::kTH2D, {dcaAxis, mcPtAxis}}); + registry.add("hSecMatAntiPrDCAxy", "DCAxy #bar{p}", {HistType::kTH2D, {dcaAxis, mcPtAxis}}); + registry.add("hSecMatDeDCAxy", "DCAxy d", {HistType::kTH2D, {dcaAxis, mcPtAxis}}); + registry.add("hSecMatAntiDeDCAxy", "DCAxy #bar{d}", {HistType::kTH2D, {dcaAxis, mcPtAxis}}); + registry.add("hSecWeakPrDCAxy", "DCAxy p", {HistType::kTH2D, {dcaAxis, mcPtAxis}}); + registry.add("hSecWeakAntiPrDCAxy", "DCAxy #bar{p}", {HistType::kTH2D, {dcaAxis, mcPtAxis}}); + registry.add("hSecWeakDeDCAxy", "DCAxy d", {HistType::kTH2D, {dcaAxis, mcPtAxis}}); + registry.add("hSecWeakAntiDeDCAxy", "DCAxy #bar{d}", {HistType::kTH2D, {dcaAxis, mcPtAxis}}); + + registry.add("hReco_EtaPhiPt_Proton", "Gen (anti)protons in reco collisions", {HistType::kTH3F, {etaAxis, phiAxis, ptAxisSmall}}); + registry.add("hReco_EtaPhiPt_Deuteron", "Gen (anti)deuteron in reco collisions", {HistType::kTH3F, {etaAxis, phiAxis, ptAxisSmall}}); + registry.add("hReco_PID_EtaPhiPt_Proton", "Gen (anti)protons + PID in reco collisions", {HistType::kTH3F, {etaAxis, phiAxis, ptAxisSmall}}); + registry.add("hReco_PID_EtaPhiPt_Deuteron", "Gen (anti)deuteron + PID in reco collisions", {HistType::kTH3F, {etaAxis, phiAxis, ptAxisSmall}}); + registry.add("hReco_EtaPhiPtMC_Proton", "Gen (anti)protons in reco collisions (MC info used)", {HistType::kTH3F, {etaAxis, phiAxis, ptAxisSmall}}); + registry.add("hReco_EtaPhiPtMC_Deuteron", "Gen (anti)deuteron in reco collisions (MC info used)", {HistType::kTH3F, {etaAxis, phiAxis, ptAxisSmall}}); + registry.add("hReco_Pt_Proton", "Reco (anti)protons in reco collisions", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hReco_Pt_Deuteron", "Reco (anti)deuterons in reco collisions", {HistType::kTH1F, {ptAxisSmall}}); + + registry.add("hSec_EtaPhiPt_Proton", "Secondary (anti)protons", {HistType::kTH3F, {etaAxis, phiAxis, ptAxisSmall}}); + registry.add("hPrimSec_EtaPhiPt_Proton", "Primary + Secondary (anti)protons", {HistType::kTH3F, {etaAxis, phiAxis, ptAxisSmall}}); + + registry.add("hnSigmaTPCVsPt_Pr_MC", "n#sigma TPC vs p_{T} for p hypothesis true MC; p_{T} (GeV/c); n#sigma TPC", {HistType::kTH2F, {ptAxis, axisNSigma}}); + registry.add("hnSigmaTPCVsPt_De_MC", "n#sigma TPC vs p_{T} for d hypothesis true MC; p_{T} (GeV/c); n#sigma TPC", {HistType::kTH2F, {ptAxis, axisNSigma}}); + registry.add("hnSigmaTOFVsPt_Pr_MC", "n#sigma TOF vs p_{T} for p hypothesis true MC; p_{T} (GeV/c); n#sigma TOF", {HistType::kTH2F, {ptAxis, axisNSigma}}); + registry.add("hnSigmaTOFVsPt_De_MC", "n#sigma TOF vs p_{T} for d hypothesis true MC; p_{T} (GeV/c); n#sigma TOF", {HistType::kTH2F, {ptAxis, axisNSigma}}); registry.add("hResPt_Proton", "; p_{T}(gen) [GeV/c]; p_{T}(reco) - p_{T}(gen) ", {HistType::kTH2F, {{100, 0.f, 10.f, "p_{T}(gen) GeV/c"}, {200, -1.f, 1.f, "p_{T}(reco) - p_{T}(gen) "}}}); registry.add("hResPt_Deuteron", "; p_{T}(gen) [GeV/c]; p_{T}(reco) - p_{T}(gen) ", {HistType::kTH2F, {{100, 0.f, 10.f, "p_{T}(gen) GeV/c"}, {200, -1.f, 1.f, "p_{T}(reco) - p_{T}(gen) "}}}); registry.add("hResPt_AntiProton", "; p_{T}(gen) [GeV/c]; p_{T}(reco) - p_{T}(gen) ", {HistType::kTH2F, {{100, 0.f, 10.f, "p_{T}(gen) GeV/c"}, {200, -1.f, 1.f, "p_{T}(reco) - p_{T}(gen) "}}}); registry.add("hResPt_AntiDeuteron", "; p_{T}(gen) [GeV/c]; p_{T}(reco) - p_{T}(gen) ", {HistType::kTH2F, {{100, 0.f, 10.f, "p_{T}(gen) GeV/c"}, {200, -1.f, 1.f, "p_{T}(reco) - p_{T}(gen) "}}}); - registry.add("hNumeratorPurity_Proton", " p(#bar{p}); p_{T} (GeV/c);S", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hNumeratorPurity_Deuteron", " d(#bar{d}); p_{T} (GeV/c);S", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hDenominatorPurity_Proton", " p(#bar{p}); p_{T} (GeV/c);(S + B)", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hDenominatorPurity_Deuteron", " d(#bar{d}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {pTAxis_small}}); + registry.add("hNumeratorPurity_Proton", " p(#bar{p}); p_{T} (GeV/c);S", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hNumeratorPurity_Deuteron", " d(#bar{d}); p_{T} (GeV/c);S", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hDenominatorPurity_Proton", " p(#bar{p}); p_{T} (GeV/c);(S + B)", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hDenominatorPurity_Deuteron", " d(#bar{d}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {ptAxisSmall}}); if (doMCQA) { @@ -368,37 +369,37 @@ struct HadronNucleiCorrelation { registry.add("hResPhi_AntiProton", "; #phi(gen); #phi(reco) - #phi(gen)", {HistType::kTH2F, {{100, 0.f, o2::constants::math::TwoPI, "#phi(gen)"}, {200, -0.5f, 0.5f, "#phi(reco) - #phi(gen)"}}}); registry.add("hResPhi_AntiDeuteron", "; #phi(gen); #phi(reco) - #phi(gen)", {HistType::kTH2F, {{100, 0.f, o2::constants::math::TwoPI, "#phi(gen)"}, {200, -0.5f, 0.5f, "#phi(reco) - #phi(gen)"}}}); - registry.add("hNumeratorPurity_Proton_TPC", " p(#bar{p}); p_{T} (GeV/c);S", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hNumeratorPurity_Deuteron_TPC", " d(#bar{d}); p_{T} (GeV/c);S", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hNumeratorPurity_Proton_TPCTOF", " p(#bar{p}); p_{T} (GeV/c);S", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hNumeratorPurity_Deuteron_TPCTOF", " d(#bar{d}); p_{T} (GeV/c);S", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hNumeratorPurity_Proton_TPC_or_TOF", " p(#bar{p}); p_{T} (GeV/c);S", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hNumeratorPurity_Deuteron_TPC_or_TOF", " d(#bar{d}); p_{T} (GeV/c);S", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hNumeratorPurity_Proton_TPCEl_or_TOF", " p(#bar{p}); p_{T} (GeV/c);S", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hNumeratorPurity_Proton_TPCEl", " p(#bar{p}); p_{T} (GeV/c);S", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hNumeratorPurity_Deuteron_TPCEl", " d(#bar{d}); p_{T} (GeV/c);S", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hNumeratorPurity_Deuteron_TPCEl_or_TOF", " d(#bar{d}); p_{T} (GeV/c);S", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hDenominatorPurity_Proton_TPC", " p(#bar{p}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hDenominatorPurity_Deuteron_TPC", " d(#bar{d}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hDenominatorPurity_Proton_TPCTOF", " p(#bar{p}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hDenominatorPurity_Deuteron_TPCTOF", " d(#bar{d}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hDenominatorPurity_Proton_TPC_or_TOF", " p(#bar{p}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hDenominatorPurity_Deuteron_TPC_or_TOF", " d(#bar{d}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hDenominatorPurity_Proton_TPCEl", " p(#bar{p}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hDenominatorPurity_Proton_TPCEl_or_TOF", " p(#bar{p}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hDenominatorPurity_Deuteron_TPCEl", " d(#bar{d}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hDenominatorPurity_Deuteron_TPCEl_or_TOF", " d(#bar{d}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {pTAxis_small}}); - - registry.add("hReco_Pt_Proton_TPC", "Reco (anti)protons in reco collisions", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hReco_Pt_Deuteron_TPC", "Reco (anti)deuterons in reco collisions", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hReco_Pt_Proton_TPCTOF", "Reco (anti)protons in reco collisions", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hReco_Pt_Deuteron_TPCTOF", "Reco (anti)deuterons in reco collisions", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hReco_Pt_Proton_TPC_or_TOF", "Reco (anti)protons in reco collisions", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hReco_Pt_Deuteron_TPC_or_TOF", "Reco (anti)deuterons in reco collisions", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hReco_Pt_Proton_TPCEl", "Reco (anti)protons in reco collisions", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hReco_Pt_Proton_TPCEl_or_TOF", "Reco (anti)protons in reco collisions", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hReco_Pt_Deuteron_TPCEl", "Reco (anti)deuterons in reco collisions", {HistType::kTH1F, {pTAxis_small}}); - registry.add("hReco_Pt_Deuteron_TPCEl_or_TOF", "Reco (anti)protons in reco collisions", {HistType::kTH1F, {pTAxis_small}}); + registry.add("hNumeratorPurity_Proton_TPC", " p(#bar{p}); p_{T} (GeV/c);S", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hNumeratorPurity_Deuteron_TPC", " d(#bar{d}); p_{T} (GeV/c);S", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hNumeratorPurity_Proton_TPCTOF", " p(#bar{p}); p_{T} (GeV/c);S", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hNumeratorPurity_Deuteron_TPCTOF", " d(#bar{d}); p_{T} (GeV/c);S", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hNumeratorPurity_Proton_TPC_or_TOF", " p(#bar{p}); p_{T} (GeV/c);S", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hNumeratorPurity_Deuteron_TPC_or_TOF", " d(#bar{d}); p_{T} (GeV/c);S", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hNumeratorPurity_Proton_TPCEl_or_TOF", " p(#bar{p}); p_{T} (GeV/c);S", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hNumeratorPurity_Proton_TPCEl", " p(#bar{p}); p_{T} (GeV/c);S", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hNumeratorPurity_Deuteron_TPCEl", " d(#bar{d}); p_{T} (GeV/c);S", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hNumeratorPurity_Deuteron_TPCEl_or_TOF", " d(#bar{d}); p_{T} (GeV/c);S", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hDenominatorPurity_Proton_TPC", " p(#bar{p}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hDenominatorPurity_Deuteron_TPC", " d(#bar{d}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hDenominatorPurity_Proton_TPCTOF", " p(#bar{p}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hDenominatorPurity_Deuteron_TPCTOF", " d(#bar{d}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hDenominatorPurity_Proton_TPC_or_TOF", " p(#bar{p}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hDenominatorPurity_Deuteron_TPC_or_TOF", " d(#bar{d}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hDenominatorPurity_Proton_TPCEl", " p(#bar{p}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hDenominatorPurity_Proton_TPCEl_or_TOF", " p(#bar{p}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hDenominatorPurity_Deuteron_TPCEl", " d(#bar{d}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hDenominatorPurity_Deuteron_TPCEl_or_TOF", " d(#bar{d}); p_{T} (GeV/c); (S + B)", {HistType::kTH1F, {ptAxisSmall}}); + + registry.add("hReco_Pt_Proton_TPC", "Reco (anti)protons in reco collisions", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hReco_Pt_Deuteron_TPC", "Reco (anti)deuterons in reco collisions", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hReco_Pt_Proton_TPCTOF", "Reco (anti)protons in reco collisions", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hReco_Pt_Deuteron_TPCTOF", "Reco (anti)deuterons in reco collisions", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hReco_Pt_Proton_TPC_or_TOF", "Reco (anti)protons in reco collisions", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hReco_Pt_Deuteron_TPC_or_TOF", "Reco (anti)deuterons in reco collisions", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hReco_Pt_Proton_TPCEl", "Reco (anti)protons in reco collisions", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hReco_Pt_Proton_TPCEl_or_TOF", "Reco (anti)protons in reco collisions", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hReco_Pt_Deuteron_TPCEl", "Reco (anti)deuterons in reco collisions", {HistType::kTH1F, {ptAxisSmall}}); + registry.add("hReco_Pt_Deuteron_TPCEl_or_TOF", "Reco (anti)protons in reco collisions", {HistType::kTH1F, {ptAxisSmall}}); } } @@ -406,8 +407,8 @@ struct HadronNucleiCorrelation { registry.add("Generated/hNEventsMC", "hNEventsMC", {HistType::kTH1D, {{1, 0.f, 1.f}}}); registry.get(HIST("Generated/hNEventsMC"))->GetXaxis()->SetBinLabel(1, "All"); - registry.add("hGen_EtaPhiPt_Proton", "Gen (anti)protons in gen collisions", {HistType::kTH3F, {etaAxis, phiAxis, pTAxis_small}}); - registry.add("hGen_EtaPhiPt_Deuteron", "Gen (anti)deuteron in gen collisions", {HistType::kTH3F, {etaAxis, phiAxis, pTAxis_small}}); + registry.add("hGen_EtaPhiPt_Proton", "Gen (anti)protons in gen collisions", {HistType::kTH3F, {etaAxis, phiAxis, ptAxisSmall}}); + registry.add("hGen_EtaPhiPt_Deuteron", "Gen (anti)deuteron in gen collisions", {HistType::kTH3F, {etaAxis, phiAxis, ptAxisSmall}}); auto hp = registry.add("Generated/hQAProtons", "hQAProtons", {HistType::kTH1D, {{5, 0.f, 5.f}}}); hp->GetXaxis()->SetBinLabel(1, "All"); @@ -415,14 +416,22 @@ struct HadronNucleiCorrelation { hp->GetXaxis()->SetBinLabel(3, "|#eta|<0.8"); hp->GetXaxis()->SetBinLabel(4, "no daughters"); hp->GetXaxis()->SetBinLabel(5, "d daughter"); + registry.addClone("Generated/hQAProtons", "Generated/hQAAntiProtons"); + + registry.addClone("Generated/hQAProtons", "Generated/hQANeutrons"); + registry.addClone("Generated/hQAProtons", "Generated/hQAAntiNeutrons"); auto hd = registry.add("Generated/hQADeuterons", "hQADeuterons", {HistType::kTH1D, {{3, 0.f, 3.f}}}); hd->GetXaxis()->SetBinLabel(1, "All"); hd->GetXaxis()->SetBinLabel(2, "PhysicalPrimary"); hd->GetXaxis()->SetBinLabel(3, "|#eta|<0.8"); + registry.addClone("Generated/hQADeuterons", "Generated/hQAAntiDeuterons"); - registry.add("Generated/hDeuteronsVsPt", "hDeuteronsVsPt; p_{T} (GeV/c);", {HistType::kTH1D, {{100, 0.f, 10.f}}}); - registry.add("Generated/hAntiDeuteronsVsPt", "hAntiDeuteronsVsPt; p_{T} (GeV/c);", {HistType::kTH1D, {{100, 0.f, 10.f}}}); + const AxisSpec ptAxisGen = {100, 0.f, 10.f, "#it{p}_{T} GeV/#it{c}"}; + registry.add("Generated/hDeuteronsVsPt", "hDeuteronsVsPt", {HistType::kTH1D, {ptAxisGen}}); + registry.add("Generated/hAntiDeuteronsVsPt", "hAntiDeuteronsVsPt", {HistType::kTH1D, {ptAxisGen}}); + registry.add("Generated/hProtonsVsPt", "hProtonsVsPt", {HistType::kTH1D, {ptAxisGen}}); + registry.add("Generated/hAntiProtonsVsPt", "hAntiProtonsVsPt", {HistType::kTH1D, {ptAxisGen}}); } } @@ -439,226 +448,102 @@ struct HadronNucleiCorrelation { Filter simvertexFilter = nabs(o2::aod::mccollision::posZ) <= cutzVertex; template - bool IsProton(Type const& track, int sign) + bool isProton(Type const& track, const int sign) { - bool isProton = false; + const bool isTPCPID = std::abs(track.tpcNSigmaPr()) < nsigmaTPC; + const bool isTOFPID = std::abs(track.tofNSigmaPr()) < nsigmaTOF; + const bool isTPCElRejection = rejectionEl && track.beta() < BetahasTOFthr && track.pt() < pTthrprTPCEl && track.tpcNSigmaEl() >= nsigmaElPr; + const bool isITSPID = track.itsNSigmaPr() > nsigmaITSPr; - bool isTPCPID = std::abs(track.tpcNSigmaPr()) < nsigmaTPC; - bool isTOFPID = std::abs(track.tofNSigmaPr()) < nsigmaTOF; - bool isTPCElRejection = rejectionEl && track.beta() < betahasTOFthr && track.pt() < pTthrprTPCEl && track.tpcNSigmaEl() >= nsigmaElPr; - bool isITSPID = track.itsNSigmaPr() > nsigmaITSPr; - - bool isQuadraticPID = TMath::Sqrt(track.tpcNSigmaPr() * track.tpcNSigmaPr() + track.tofNSigmaPr() * track.tofNSigmaPr()) < nsigmaTPC; + const bool isQuadraticPID = std::hypot(track.tpcNSigmaPr(), track.tofNSigmaPr()) < nsigmaTPC; + // Check if the sign of the track matches the expected sign for protons or antiprotons + const bool signCheck = (sign > 0 && track.sign() > 0) || (sign < 0 && track.sign() < 0); if (!doQuadraticPID) { if (isTPCPID) { if (track.pt() < pTthrprTOF) { if (!doITSPID || isITSPID) { - if (sign > 0) { - if (track.sign() > 0) { - isProton = true; - } else if (track.sign() < 0) { - isProton = false; - } - } else if (sign < 0) { - if (track.sign() > 0) { - isProton = false; - } else if (track.sign() < 0) { - isProton = true; - } - } - } - } else if (isTPCElRejection) { - if (sign > 0) { - if (track.sign() > 0) { - isProton = true; - } else if (track.sign() < 0) { - isProton = false; - } - } else if (sign < 0) { - if (track.sign() > 0) { - isProton = false; - } else if (track.sign() < 0) { - isProton = true; - } - } - } else if (isTOFPID) { - if (sign > 0) { - if (track.sign() > 0) { - isProton = true; - } else if (track.sign() < 0) { - isProton = false; - } - } else if (sign < 0) { - if (track.sign() > 0) { - isProton = false; - } else if (track.sign() < 0) { - isProton = true; - } + return signCheck; } + } else if (isTPCElRejection || isTOFPID) { + return signCheck; } } } else { if (track.pt() < pTthrprTOF) { if (isTPCPID) { if (!doITSPID || isITSPID) { - if (sign > 0) { - if (track.sign() > 0) { - isProton = true; - } else if (track.sign() < 0) { - isProton = false; - } - } else if (sign < 0) { - if (track.sign() > 0) { - isProton = false; - } else if (track.sign() < 0) { - isProton = true; - } - } + return signCheck; } } } else if (isQuadraticPID) { - if (sign > 0) { - if (track.sign() > 0) { - isProton = true; - } else if (track.sign() < 0) { - isProton = false; - } - } else if (sign < 0) { - if (track.sign() > 0) { - isProton = false; - } else if (track.sign() < 0) { - isProton = true; - } - } + return signCheck; } } - return isProton; + return false; } template - bool IsDeuteron(Type const& track, int sign) + bool isDeuteron(Type const& track, const int sign) { - bool isDeuteron = false; - bool isTPCPID = std::abs(track.tpcNSigmaDe()) < nsigmaTPC; - bool isTOFPID = std::abs(track.tofNSigmaDe()) < nsigmaTOF; - bool isTPCElRejection = rejectionEl && track.beta() < betahasTOFthr && track.pt() < pTthrdeTPCEl && track.tpcNSigmaEl() >= nsigmaElDe; - bool isITSPID = track.itsNSigmaDe() > nsigmaITSDe; + const bool isTPCPID = std::abs(track.tpcNSigmaDe()) < nsigmaTPC; + const bool isTOFPID = std::abs(track.tofNSigmaDe()) < nsigmaTOF; + const bool isTPCElRejection = rejectionEl && track.beta() < BetahasTOFthr && track.pt() < pTthrdeTPCEl && track.tpcNSigmaEl() >= nsigmaElDe; + const bool isITSPID = track.itsNSigmaDe() > nsigmaITSDe; - bool isQuadraticPID = TMath::Sqrt(track.tpcNSigmaDe() * track.tpcNSigmaDe() + track.tofNSigmaDe() * track.tofNSigmaDe()) < nsigmaTPC; + const bool isQuadraticPID = std::hypot(track.tpcNSigmaDe(), track.tofNSigmaDe()) < nsigmaTPC; + // Check if the sign of the track matches the expected sign for deuterons or antideuterons + const bool signCheck = (sign > 0 && track.sign() > 0) || (sign < 0 && track.sign() < 0); if (!doQuadraticPID) { if (isTPCPID) { if (track.pt() < pTthrdeTOF) { if (!doITSPID || isITSPID) { - if (sign > 0) { - if (track.sign() > 0) { - isDeuteron = true; - } else if (track.sign() < 0) { - isDeuteron = false; - } - } else if (sign < 0) { - if (track.sign() > 0) { - isDeuteron = false; - } else if (track.sign() < 0) { - isDeuteron = true; - } - } - } - } else if (isTPCElRejection) { - if (sign > 0) { - if (track.sign() > 0) { - isDeuteron = true; - } else if (track.sign() < 0) { - isDeuteron = false; - } - } else if (sign < 0) { - if (track.sign() > 0) { - isDeuteron = false; - } else if (track.sign() < 0) { - isDeuteron = true; - } - } - } else if (isTOFPID) { - if (sign > 0) { - if (track.sign() > 0) { - isDeuteron = true; - } else if (track.sign() < 0) { - isDeuteron = false; - } - } else if (sign < 0) { - if (track.sign() > 0) { - isDeuteron = false; - } else if (track.sign() < 0) { - isDeuteron = true; - } + return signCheck; } + } else if (isTPCElRejection || isTOFPID) { + return signCheck; } } } else { if (track.pt() < pTthrprTOF) { if (isTPCPID) { if (!doITSPID || isITSPID) { - if (sign > 0) { - if (track.sign() > 0) { - isDeuteron = true; - } else if (track.sign() < 0) { - isDeuteron = false; - } - } else if (sign < 0) { - if (track.sign() > 0) { - isDeuteron = false; - } else if (track.sign() < 0) { - isDeuteron = true; - } - } + return signCheck; } } } else if (isQuadraticPID) { - if (sign > 0) { - if (track.sign() > 0) { - isDeuteron = true; - } else if (track.sign() < 0) { - isDeuteron = false; - } - } else if (sign < 0) { - if (track.sign() > 0) { - isDeuteron = false; - } else if (track.sign() < 0) { - isDeuteron = true; - } - } + return signCheck; } } - return isDeuteron; + return false; } template bool applyDCAcut(const T1& track) { - bool passcut = true; // pt-dependent selection - if (std::abs(track.dcaXY()) > (dcaPar0 + dcaPar1 / track.pt())) - passcut = false; - - if (doDCAZ && std::abs(track.dcaZ()) > (dcaPar0 + dcaPar1 / track.pt())) - passcut = false; - - return passcut; + if (std::abs(track.dcaXY()) > (dcaPar0 + dcaPar1 / track.pt())) { + return false; + } + if (doDCAZ && std::abs(track.dcaZ()) > (dcaPar0 + dcaPar1 / track.pt())) { + return false; + } + return true; } template void fillHistograms(T1 const& part0, T1 const& part1, bool ME, bool isIdentical) { - Pair->SetPair(&part0, &part1); - Pair->SetIdentical(isIdentical); - if (isIdentical && Pair->IsClosePair(dEta, dPhi, radiusTPC)) { - QA.fill(HIST("QA/hdEtadPhistar"), Pair->GetPhiStarDiff(radiusTPC), Pair->GetEtaDiff()); + pair->SetPair(&part0, &part1); + pair->SetIdentical(isIdentical); + if (isIdentical && pair->IsClosePair(dEta, dPhi, radiusTPC)) { + registryQa.fill(HIST("QA/hdEtadPhistar"), pair->GetPhiStarDiff(radiusTPC), pair->GetEtaDiff()); return; } - if (doClosePairRejection && Pair->IsClosePair(dEta, dPhi, radiusTPC)) { - QA.fill(HIST("QA/hdEtadPhistar"), Pair->GetPhiStarDiff(radiusTPC), Pair->GetEtaDiff()); + if (doClosePairRejection && pair->IsClosePair(dEta, dPhi, radiusTPC)) { + registryQa.fill(HIST("QA/hdEtadPhistar"), pair->GetPhiStarDiff(radiusTPC), pair->GetEtaDiff()); return; } @@ -675,59 +560,62 @@ struct HadronNucleiCorrelation { if (doCorrection) { // Apply corrections switch (mode) { case kDbarPbar: - corr0 = hEffpTEta_antideuteron->Interpolate(part0.pt(), part0.eta()); - corr1 = hEffpTEta_antiproton->Interpolate(part1.pt(), part1.eta()); + corr0 = hEffPtEtaAntiDeuteron->Interpolate(part0.pt(), part0.eta()); + corr1 = hEffPtEtaAntiProton->Interpolate(part1.pt(), part1.eta()); break; case kDP: - corr0 = hEffpTEta_deuteron->Interpolate(part0.pt(), part0.eta()); - corr1 = hEffpTEta_proton->Interpolate(part1.pt(), part1.eta()); + corr0 = hEffPtEtaDeuteron->Interpolate(part0.pt(), part0.eta()); + corr1 = hEffPtEtaProton->Interpolate(part1.pt(), part1.eta()); break; case kDbarP: - corr0 = hEffpTEta_antideuteron->Interpolate(part0.pt(), part0.eta()); - corr1 = hEffpTEta_proton->Interpolate(part1.pt(), part1.eta()); + corr0 = hEffPtEtaAntiDeuteron->Interpolate(part0.pt(), part0.eta()); + corr1 = hEffPtEtaProton->Interpolate(part1.pt(), part1.eta()); break; case kDPbar: - corr0 = hEffpTEta_deuteron->Interpolate(part0.pt(), part0.eta()); - corr1 = hEffpTEta_antiproton->Interpolate(part1.pt(), part1.eta()); + corr0 = hEffPtEtaDeuteron->Interpolate(part0.pt(), part0.eta()); + corr1 = hEffPtEtaAntiProton->Interpolate(part1.pt(), part1.eta()); break; case kPbarP: - corr0 = hEffpTEta_antiproton->Interpolate(part0.pt(), part0.eta()); - corr1 = hEffpTEta_proton->Interpolate(part1.pt(), part1.eta()); + corr0 = hEffPtEtaAntiProton->Interpolate(part0.pt(), part0.eta()); + corr1 = hEffPtEtaProton->Interpolate(part1.pt(), part1.eta()); break; case kPbarPbar: - corr0 = hEffpTEta_antiproton->Interpolate(part0.pt(), part0.eta()); - corr1 = hEffpTEta_antiproton->Interpolate(part1.pt(), part1.eta()); + corr0 = hEffPtEtaAntiProton->Interpolate(part0.pt(), part0.eta()); + corr1 = hEffPtEtaAntiProton->Interpolate(part1.pt(), part1.eta()); break; case kPP: - corr0 = hEffpTEta_proton->Interpolate(part0.pt(), part0.eta()); - corr1 = hEffpTEta_proton->Interpolate(part1.pt(), part1.eta()); + corr0 = hEffPtEtaProton->Interpolate(part0.pt(), part0.eta()); + corr1 = hEffPtEtaProton->Interpolate(part1.pt(), part1.eta()); break; case kPPbar: - corr0 = hEffpTEta_proton->Interpolate(part0.pt(), part0.eta()); - corr1 = hEffpTEta_antiproton->Interpolate(part1.pt(), part1.eta()); + corr0 = hEffPtEtaProton->Interpolate(part0.pt(), part0.eta()); + corr1 = hEffPtEtaAntiProton->Interpolate(part1.pt(), part1.eta()); + break; + default: + LOG(error) << "Unknown mode for efficiency correction: " << mode; break; } } if (ME) { - hEtaPhi_ME[k]->Fill(deltaEta, deltaPhi, part1.pt()); + hEtaPhiMixdEv[k]->Fill(deltaEta, deltaPhi, part1.pt()); if (corr0 != 0 && corr1 != 0) { - hCorrEtaPhi_ME[k]->Fill(deltaEta, deltaPhi, part1.pt(), 1. / (corr0 * corr1)); + hCorrEtaPhiMixdEv[k]->Fill(deltaEta, deltaPhi, part1.pt(), 1. / (corr0 * corr1)); } } else { - hEtaPhi_SE[k]->Fill(deltaEta, deltaPhi, part1.pt()); + hEtaPhiSameEv[k]->Fill(deltaEta, deltaPhi, part1.pt()); if (corr0 != 0 && corr1 != 0) { - hCorrEtaPhi_SE[k]->Fill(deltaEta, deltaPhi, part1.pt(), 1. / (corr0 * corr1)); + hCorrEtaPhiSameEv[k]->Fill(deltaEta, deltaPhi, part1.pt(), 1. / (corr0 * corr1)); } } // SE } // pT condition } // nBinspT loop - Pair->ResetPair(); + pair->ResetPair(); } template - void fillHistogramsGen(T1 const& part0, T1 const& part1, bool ME) + void fillHistogramsGen(T1 const& part0, T1 const& part1, const bool ME) { float deltaEta = part0.eta() - part1.eta(); @@ -739,40 +627,40 @@ struct HadronNucleiCorrelation { if (part0.pt() >= pTBins.value.at(k) && part0.pt() < pTBins.value.at(k + 1)) { if (ME) { - hEtaPhi_ME[k]->Fill(deltaEta, deltaPhi, part1.pt()); - hCorrEtaPhi_ME[k]->Fill(deltaEta, deltaPhi, part1.pt()); + hEtaPhiMixdEv[k]->Fill(deltaEta, deltaPhi, part1.pt()); + hCorrEtaPhiMixdEv[k]->Fill(deltaEta, deltaPhi, part1.pt()); } else { - hEtaPhi_SE[k]->Fill(deltaEta, deltaPhi, part1.pt()); - hCorrEtaPhi_SE[k]->Fill(deltaEta, deltaPhi, part1.pt()); + hEtaPhiSameEv[k]->Fill(deltaEta, deltaPhi, part1.pt()); + hCorrEtaPhiSameEv[k]->Fill(deltaEta, deltaPhi, part1.pt()); } // SE } // pT condition } // nBinspT loop } - void GetCorrection(o2::framework::Service const& ccdbObj, TString filepath, TString histname) + void getCorrection(o2::framework::Service const& ccdbObj, const TString& filepath, const TString& histname) { - TList* l = ccdbObj->get(filepath.Data()); + auto* l = ccdbObj->get(filepath.Data()); if (!l) { LOGP(error, "Could not open corrections file {}", Form("%s", filepath.Data())); return; } - hEffpTEta_proton = static_cast(l->FindObject(Form("%s_proton", histname.Data()))); - if (!hEffpTEta_proton) { + hEffPtEtaProton = dynamic_cast(l->FindObject(Form("%s_proton", histname.Data()))); + if (!hEffPtEtaProton) { LOGP(error, "Could not open histogram {}", Form("%s_proton", histname.Data())); return; } - hEffpTEta_antiproton = static_cast(l->FindObject(Form("%s_antiproton", histname.Data()))); - if (!hEffpTEta_antiproton) { + hEffPtEtaAntiProton = dynamic_cast(l->FindObject(Form("%s_antiproton", histname.Data()))); + if (!hEffPtEtaAntiProton) { LOGP(error, "Could not open histogram {}", Form("%s_antiproton", histname.Data())); return; } - hEffpTEta_deuteron = static_cast(l->FindObject(Form("%s_deuteron", histname.Data()))); - if (!hEffpTEta_deuteron) { + hEffPtEtaDeuteron = dynamic_cast(l->FindObject(Form("%s_deuteron", histname.Data()))); + if (!hEffPtEtaDeuteron) { LOGP(error, "Could not open histogram {}", Form("%s_deuteron", histname.Data())); return; } - hEffpTEta_antideuteron = static_cast(l->FindObject(Form("%s_antideuteron", histname.Data()))); - if (!hEffpTEta_antideuteron) { + hEffPtEtaAntiDeuteron = dynamic_cast(l->FindObject(Form("%s_antideuteron", histname.Data()))); + if (!hEffPtEtaAntiDeuteron) { LOGP(error, "Could not open histogram {}", Form("%s_antideuteron", histname.Data())); return; } @@ -785,7 +673,7 @@ struct HadronNucleiCorrelation { template float getMCMultiplicity(TParticles const& particles) { - float Ncharged = 0.; + float nCharged = 0.; for (const auto& mcParticle : particles) { if (!mcParticle.isPhysicalPrimary()) { @@ -798,12 +686,12 @@ struct HadronNucleiCorrelation { TParticlePDG* p = pdgDB->GetParticle(mcParticle.pdgCode()); if (std::abs(p->Charge()) > 1E-3) { - Ncharged++; + nCharged++; } } - registry.fill(HIST("hMult"), Ncharged); - return Ncharged; + registry.fill(HIST("hMult"), nCharged); + return nCharged; } void processSameEvent(FilteredCollisions::iterator const& collision, FilteredTracks const& tracks) @@ -814,116 +702,135 @@ struct HadronNucleiCorrelation { for (const auto& track : tracks) { - if (track.tpcFractionSharedCls() > maxtpcSharedCls) + if (track.tpcFractionSharedCls() > maxtpcSharedCls) { continue; - if (track.itsNCls() < minitsNCls) + } + if (track.itsNCls() < minitsNCls) { continue; + } - if (IsProton(track, +1)) + if (isProton(track, +1)) { registry.fill(HIST("hPrDCAxy"), track.dcaXY(), track.pt()); - if (IsProton(track, -1)) + } + if (isProton(track, -1)) { registry.fill(HIST("hAntiPrDCAxy"), track.dcaXY(), track.pt()); - if (IsDeuteron(track, +1)) + } + if (isDeuteron(track, +1)) { registry.fill(HIST("hDeDCAxy"), track.dcaXY(), track.pt()); - if (IsDeuteron(track, -1)) + } + if (isDeuteron(track, -1)) { registry.fill(HIST("hAntiDeDCAxy"), track.dcaXY(), track.pt()); + } - if (!applyDCAcut(track)) + if (!applyDCAcut(track)) { continue; + } if (doQA) { - QA.fill(HIST("QA/hTPCnClusters"), track.tpcNClsFound()); - QA.fill(HIST("QA/hTPCSharedClusters"), track.tpcFractionSharedCls()); - QA.fill(HIST("QA/hTPCchi2"), track.tpcChi2NCl()); - QA.fill(HIST("QA/hTPCcrossedRowsOverFindableCls"), track.tpcCrossedRowsOverFindableCls()); - QA.fill(HIST("QA/hITSchi2"), track.itsChi2NCl()); - QA.fill(HIST("QA/hDCAxy"), track.dcaXY(), track.pt()); - QA.fill(HIST("QA/hDCAz"), track.dcaZ(), track.pt()); - QA.fill(HIST("QA/TPCChi2VsPZ"), track.tpcInnerParam() / track.sign(), track.tpcChi2NCl()); - QA.fill(HIST("QA/hVtxZ_trk"), collision.posZ()); - QA.fill(HIST("QA/hnSigmaTPCVsPt_El"), track.pt() * track.sign(), track.tpcNSigmaEl()); - QA.fill(HIST("QA/hnSigmaTPCVsPt_Pr"), track.pt() * track.sign(), track.tpcNSigmaPr()); - QA.fill(HIST("QA/hnSigmaTPCVsPt_De"), track.pt() * track.sign(), track.tpcNSigmaDe()); - QA.fill(HIST("QA/hnSigmaTOFVsPt_Pr"), track.pt() * track.sign(), track.tofNSigmaPr()); - QA.fill(HIST("QA/hnSigmaTOFVsPt_De"), track.pt() * track.sign(), track.tofNSigmaDe()); - QA.fill(HIST("QA/hnSigmaITSVsPt_Pr"), track.pt() * track.sign(), track.itsNSigmaPr()); - QA.fill(HIST("QA/hnSigmaITSVsPt_De"), track.pt() * track.sign(), track.itsNSigmaDe()); - QA.fill(HIST("QA/h2dTPCTOF_AntiPr"), track.tpcNSigmaPr(), track.tofNSigmaPr()); - QA.fill(HIST("QA/h2dTPCTOF_Pr"), track.tpcNSigmaPr(), track.tofNSigmaPr()); - - if (IsProton(track, -1)) { - QA.fill(HIST("QA/hEtaAntiPr"), track.eta()); - QA.fill(HIST("QA/hPhiAntiPr"), track.phi()); - QA.fill(HIST("QA/hnSigmaTOFVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.tofNSigmaPr()); - QA.fill(HIST("QA/hnSigmaTPCVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.tpcNSigmaPr()); - QA.fill(HIST("QA/hnSigmaITSVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.itsNSigmaPr()); - QA.fill(HIST("QA/h2dTPCTOF_AntiPr_AfterSel"), track.tpcNSigmaPr(), track.tofNSigmaPr()); - } - if (IsProton(track, +1)) { - QA.fill(HIST("QA/hEtaPr"), track.eta()); - QA.fill(HIST("QA/hPhiPr"), track.phi()); - QA.fill(HIST("QA/hnSigmaTOFVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.tofNSigmaPr()); - QA.fill(HIST("QA/hnSigmaTPCVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.tpcNSigmaPr()); - QA.fill(HIST("QA/hnSigmaITSVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.itsNSigmaPr()); - QA.fill(HIST("QA/h2dTPCTOF_Pr_AfterSel"), track.tpcNSigmaPr(), track.tofNSigmaPr()); - } - if (IsDeuteron(track, -1)) { - QA.fill(HIST("QA/hEtaAntiDe"), track.eta()); - QA.fill(HIST("QA/hPhiAntiDe"), track.phi()); - QA.fill(HIST("QA/hnSigmaTOFVsPt_De_AfterSel"), track.pt() * track.sign(), track.tofNSigmaDe()); - QA.fill(HIST("QA/hnSigmaTPCVsPt_De_AfterSel"), track.pt() * track.sign(), track.tpcNSigmaDe()); - QA.fill(HIST("QA/hnSigmaITSVsPt_De_AfterSel"), track.pt() * track.sign(), track.itsNSigmaDe()); - } - if (IsDeuteron(track, +1)) { - QA.fill(HIST("QA/hEtaDe"), track.eta()); - QA.fill(HIST("QA/hPhiDe"), track.phi()); - QA.fill(HIST("QA/hnSigmaTOFVsPt_De_AfterSel"), track.pt() * track.sign(), track.tofNSigmaDe()); - QA.fill(HIST("QA/hnSigmaTPCVsPt_De_AfterSel"), track.pt() * track.sign(), track.tpcNSigmaDe()); - QA.fill(HIST("QA/hnSigmaITSVsPt_De_AfterSel"), track.pt() * track.sign(), track.itsNSigmaDe()); + registryQa.fill(HIST("QA/hTPCnClusters"), track.tpcNClsFound()); + registryQa.fill(HIST("QA/hTPCSharedClusters"), track.tpcFractionSharedCls()); + registryQa.fill(HIST("QA/hTPCchi2"), track.tpcChi2NCl()); + registryQa.fill(HIST("QA/hTPCcrossedRowsOverFindableCls"), track.tpcCrossedRowsOverFindableCls()); + registryQa.fill(HIST("QA/hITSchi2"), track.itsChi2NCl()); + registryQa.fill(HIST("QA/hDCAxy"), track.dcaXY(), track.pt()); + registryQa.fill(HIST("QA/hDCAz"), track.dcaZ(), track.pt()); + registryQa.fill(HIST("QA/TPCChi2VsPZ"), track.tpcInnerParam() / track.sign(), track.tpcChi2NCl()); + registryQa.fill(HIST("QA/hVtxZ_trk"), collision.posZ()); + registryQa.fill(HIST("QA/hnSigmaTPCVsPt_El"), track.pt() * track.sign(), track.tpcNSigmaEl()); + registryQa.fill(HIST("QA/hnSigmaTPCVsPt_Pr"), track.pt() * track.sign(), track.tpcNSigmaPr()); + registryQa.fill(HIST("QA/hnSigmaTPCVsPt_De"), track.pt() * track.sign(), track.tpcNSigmaDe()); + registryQa.fill(HIST("QA/hnSigmaTOFVsPt_Pr"), track.pt() * track.sign(), track.tofNSigmaPr()); + registryQa.fill(HIST("QA/hnSigmaTOFVsPt_De"), track.pt() * track.sign(), track.tofNSigmaDe()); + registryQa.fill(HIST("QA/hnSigmaITSVsPt_Pr"), track.pt() * track.sign(), track.itsNSigmaPr()); + registryQa.fill(HIST("QA/hnSigmaITSVsPt_De"), track.pt() * track.sign(), track.itsNSigmaDe()); + registryQa.fill(HIST("QA/h2dTPCTOF_AntiPr"), track.tpcNSigmaPr(), track.tofNSigmaPr()); + registryQa.fill(HIST("QA/h2dTPCTOF_Pr"), track.tpcNSigmaPr(), track.tofNSigmaPr()); + + if (isProton(track, -1)) { + registryQa.fill(HIST("QA/hEtaAntiPr"), track.eta()); + registryQa.fill(HIST("QA/hPhiAntiPr"), track.phi()); + registryQa.fill(HIST("QA/hnSigmaTOFVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.tofNSigmaPr()); + registryQa.fill(HIST("QA/hnSigmaTPCVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.tpcNSigmaPr()); + registryQa.fill(HIST("QA/hnSigmaITSVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.itsNSigmaPr()); + registryQa.fill(HIST("QA/h2dTPCTOF_AntiPr_AfterSel"), track.tpcNSigmaPr(), track.tofNSigmaPr()); + } + if (isProton(track, +1)) { + registryQa.fill(HIST("QA/hEtaPr"), track.eta()); + registryQa.fill(HIST("QA/hPhiPr"), track.phi()); + registryQa.fill(HIST("QA/hnSigmaTOFVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.tofNSigmaPr()); + registryQa.fill(HIST("QA/hnSigmaTPCVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.tpcNSigmaPr()); + registryQa.fill(HIST("QA/hnSigmaITSVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.itsNSigmaPr()); + registryQa.fill(HIST("QA/h2dTPCTOF_Pr_AfterSel"), track.tpcNSigmaPr(), track.tofNSigmaPr()); + } + if (isDeuteron(track, -1)) { + registryQa.fill(HIST("QA/hEtaAntiDe"), track.eta()); + registryQa.fill(HIST("QA/hPhiAntiDe"), track.phi()); + registryQa.fill(HIST("QA/hnSigmaTOFVsPt_De_AfterSel"), track.pt() * track.sign(), track.tofNSigmaDe()); + registryQa.fill(HIST("QA/hnSigmaTPCVsPt_De_AfterSel"), track.pt() * track.sign(), track.tpcNSigmaDe()); + registryQa.fill(HIST("QA/hnSigmaITSVsPt_De_AfterSel"), track.pt() * track.sign(), track.itsNSigmaDe()); + } + if (isDeuteron(track, +1)) { + registryQa.fill(HIST("QA/hEtaDe"), track.eta()); + registryQa.fill(HIST("QA/hPhiDe"), track.phi()); + registryQa.fill(HIST("QA/hnSigmaTOFVsPt_De_AfterSel"), track.pt() * track.sign(), track.tofNSigmaDe()); + registryQa.fill(HIST("QA/hnSigmaTPCVsPt_De_AfterSel"), track.pt() * track.sign(), track.tpcNSigmaDe()); + registryQa.fill(HIST("QA/hnSigmaITSVsPt_De_AfterSel"), track.pt() * track.sign(), track.itsNSigmaDe()); } } } - Pair->SetMagField1(collision.magField()); - Pair->SetMagField2(collision.magField()); + pair->SetMagField1(collision.magField()); + pair->SetMagField2(collision.magField()); if (mode == kPbarPbar || mode == kPP) { // Identical particle combinations for (const auto& [part0, part1] : combinations(CombinationsStrictlyUpperIndexPolicy(tracks, tracks))) { - if (part0.tpcFractionSharedCls() > maxtpcSharedCls) + if (part0.tpcFractionSharedCls() > maxtpcSharedCls) { continue; - if (part0.itsNCls() < minitsNCls) + } + if (part0.itsNCls() < minitsNCls) { continue; - if (part1.tpcFractionSharedCls() > maxtpcSharedCls) + } + if (part1.tpcFractionSharedCls() > maxtpcSharedCls) { continue; - if (part1.itsNCls() < minitsNCls) + } + if (part1.itsNCls() < minitsNCls) { continue; + } - if (!applyDCAcut(part0)) + if (!applyDCAcut(part0)) { continue; - if (!applyDCAcut(part1)) + } + if (!applyDCAcut(part1)) { continue; + } // remove tracks outside pt bins - if (part0.pt() < pTBins.value.at(0) || part0.pt() >= pTBins.value.at(nBinspT)) + if (part0.pt() < pTBins.value.at(0) || part0.pt() >= pTBins.value.at(nBinspT)) { continue; - if (part1.pt() < pTBins.value.at(0) || part1.pt() >= pTBins.value.at(nBinspT)) + } + if (part1.pt() < pTBins.value.at(0) || part1.pt() >= pTBins.value.at(nBinspT)) { continue; + } // mode 6 if (mode == kPP) { - if (!IsProton(part0, +1)) + if (!isProton(part0, +1)) { continue; - if (!IsProton(part1, +1)) + } + if (!isProton(part1, +1)) { continue; + } } // mode 5 if (mode == kPbarPbar) { - if (!IsProton(part0, -1)) + if (!isProton(part0, -1)) { continue; - if (!IsProton(part1, -1)) + } + if (!isProton(part1, -1)) { continue; + } } fillHistograms(part0, part1, false, true); @@ -933,62 +840,82 @@ struct HadronNucleiCorrelation { for (const auto& [part0, part1] : combinations(CombinationsFullIndexPolicy(tracks, tracks))) { - if (part0.tpcFractionSharedCls() > maxtpcSharedCls) + if (part0.tpcFractionSharedCls() > maxtpcSharedCls) { continue; - if (part0.itsNCls() < minitsNCls) + } + if (part0.itsNCls() < minitsNCls) { continue; - if (part1.tpcFractionSharedCls() > maxtpcSharedCls) + } + if (part1.tpcFractionSharedCls() > maxtpcSharedCls) { continue; - if (part1.itsNCls() < minitsNCls) + } + if (part1.itsNCls() < minitsNCls) { continue; + } - if (!applyDCAcut(part0)) + if (!applyDCAcut(part0)) { continue; - if (!applyDCAcut(part1)) + } + if (!applyDCAcut(part1)) { continue; + } // remove tracks outside pt bins - if (part0.pt() < pTBins.value.at(0) || part0.pt() >= pTBins.value.at(nBinspT)) + if (part0.pt() < pTBins.value.at(0) || part0.pt() >= pTBins.value.at(nBinspT)) { continue; - if (part1.pt() < pTBins.value.at(0) || part1.pt() >= pTBins.value.at(nBinspT)) + } + if (part1.pt() < pTBins.value.at(0) || part1.pt() >= pTBins.value.at(nBinspT)) { continue; + } // modes 0,1,2,3,4,7 if (mode == kDbarPbar) { - if (!IsDeuteron(part0, -1)) + if (!isDeuteron(part0, -1)) { continue; - if (!IsProton(part1, -1)) + } + if (!isProton(part1, -1)) { continue; + } } if (mode == kDP) { - if (!IsDeuteron(part0, +1)) + if (!isDeuteron(part0, +1)) { continue; - if (!IsProton(part1, +1)) + } + if (!isProton(part1, +1)) { continue; + } } if (mode == kDbarP) { - if (!IsDeuteron(part0, -1)) + if (!isDeuteron(part0, -1)) { continue; - if (!IsProton(part1, +1)) + } + if (!isProton(part1, +1)) { continue; + } } if (mode == kDPbar) { - if (!IsDeuteron(part0, +1)) + if (!isDeuteron(part0, +1)) { continue; - if (!IsProton(part1, -1)) + } + if (!isProton(part1, -1)) { continue; + } } if (mode == kPbarP) { - if (!IsProton(part0, -1)) + if (!isProton(part0, -1)) { continue; - if (!IsProton(part1, +1)) + } + if (!isProton(part1, +1)) { continue; + } } if (mode == kPPbar) { - if (!IsProton(part0, +1)) + if (!isProton(part0, +1)) { continue; - if (!IsProton(part1, -1)) + } + if (!isProton(part1, -1)) { continue; + } } fillHistograms(part0, part1, false, false); @@ -1005,122 +932,143 @@ struct HadronNucleiCorrelation { for (const auto& track : tracks) { - if (removeSameBunchPileup && !track.template singleCollSel_as().isNoSameBunchPileup()) + if (removeSameBunchPileup && !track.template singleCollSel_as().isNoSameBunchPileup()) { continue; + } - if (track.tpcFractionSharedCls() > maxtpcSharedCls) + if (track.tpcFractionSharedCls() > maxtpcSharedCls) { continue; - if (track.itsNCls() < minitsNCls) + } + if (track.itsNCls() < minitsNCls) { continue; + } - if (IsProton(track, +1)) + if (isProton(track, +1)) { registry.fill(HIST("hPrDCAxy"), track.dcaXY(), track.pt()); - if (IsProton(track, -1)) + } + if (isProton(track, -1)) { registry.fill(HIST("hAntiPrDCAxy"), track.dcaXY(), track.pt()); - if (IsDeuteron(track, +1)) + } + if (isDeuteron(track, +1)) { registry.fill(HIST("hDeDCAxy"), track.dcaXY(), track.pt()); - if (IsDeuteron(track, -1)) + } + if (isDeuteron(track, -1)) { registry.fill(HIST("hAntiDeDCAxy"), track.dcaXY(), track.pt()); + } - if (!applyDCAcut(track)) + if (!applyDCAcut(track)) { continue; + } if (doQA) { - QA.fill(HIST("QA/hTPCnClusters"), track.tpcNClsFound()); - QA.fill(HIST("QA/hTPCSharedClusters"), track.tpcFractionSharedCls()); - QA.fill(HIST("QA/hTPCchi2"), track.tpcChi2NCl()); - QA.fill(HIST("QA/hTPCcrossedRowsOverFindableCls"), track.tpcCrossedRowsOverFindableCls()); - QA.fill(HIST("QA/hITSchi2"), track.itsChi2NCl()); - QA.fill(HIST("QA/hDCAxy"), track.dcaXY(), track.pt()); - QA.fill(HIST("QA/hDCAz"), track.dcaZ(), track.pt()); - QA.fill(HIST("QA/TPCChi2VsPZ"), track.tpcInnerParam() / track.sign(), track.tpcChi2NCl()); - QA.fill(HIST("QA/hVtxZ_trk"), collision.posZ()); - QA.fill(HIST("QA/hnSigmaTPCVsPt_El"), track.pt() * track.sign(), track.tpcNSigmaEl()); - QA.fill(HIST("QA/hnSigmaTPCVsPt_Pr"), track.pt() * track.sign(), track.tpcNSigmaPr()); - QA.fill(HIST("QA/hnSigmaTPCVsPt_De"), track.pt() * track.sign(), track.tpcNSigmaDe()); - QA.fill(HIST("QA/hnSigmaTOFVsPt_Pr"), track.pt() * track.sign(), track.tofNSigmaPr()); - QA.fill(HIST("QA/hnSigmaTOFVsPt_De"), track.pt() * track.sign(), track.tofNSigmaDe()); - QA.fill(HIST("QA/hnSigmaITSVsPt_Pr"), track.pt() * track.sign(), track.itsNSigmaPr()); - QA.fill(HIST("QA/hnSigmaITSVsPt_De"), track.pt() * track.sign(), track.itsNSigmaDe()); - QA.fill(HIST("QA/h2dTPCTOF_AntiPr"), track.tpcNSigmaPr(), track.tofNSigmaPr()); - QA.fill(HIST("QA/h2dTPCTOF_Pr"), track.tpcNSigmaPr(), track.tofNSigmaPr()); - - if (IsProton(track, -1)) { - QA.fill(HIST("QA/hEtaAntiPr"), track.eta()); - QA.fill(HIST("QA/hPhiAntiPr"), track.phi()); - QA.fill(HIST("QA/hnSigmaTOFVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.tofNSigmaPr()); - QA.fill(HIST("QA/hnSigmaTPCVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.tpcNSigmaPr()); - QA.fill(HIST("QA/hnSigmaITSVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.itsNSigmaPr()); - QA.fill(HIST("QA/h2dTPCTOF_AntiPr_AfterSel"), track.tpcNSigmaPr(), track.tofNSigmaPr()); - } - if (IsProton(track, +1)) { - QA.fill(HIST("QA/hEtaPr"), track.eta()); - QA.fill(HIST("QA/hPhiPr"), track.phi()); - QA.fill(HIST("QA/hnSigmaTOFVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.tofNSigmaPr()); - QA.fill(HIST("QA/hnSigmaTPCVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.tpcNSigmaPr()); - QA.fill(HIST("QA/hnSigmaITSVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.itsNSigmaPr()); - QA.fill(HIST("QA/h2dTPCTOF_Pr_AfterSel"), track.tpcNSigmaPr(), track.tofNSigmaPr()); - } - if (IsDeuteron(track, -1)) { - QA.fill(HIST("QA/hEtaAntiDe"), track.eta()); - QA.fill(HIST("QA/hPhiAntiDe"), track.phi()); - QA.fill(HIST("QA/hnSigmaTOFVsPt_De_AfterSel"), track.pt() * track.sign(), track.tofNSigmaDe()); - QA.fill(HIST("QA/hnSigmaTPCVsPt_De_AfterSel"), track.pt() * track.sign(), track.tpcNSigmaDe()); - QA.fill(HIST("QA/hnSigmaITSVsPt_De_AfterSel"), track.pt() * track.sign(), track.itsNSigmaDe()); - } - if (IsDeuteron(track, +1)) { - QA.fill(HIST("QA/hEtaDe"), track.eta()); - QA.fill(HIST("QA/hPhiDe"), track.phi()); - QA.fill(HIST("QA/hnSigmaTOFVsPt_De_AfterSel"), track.pt() * track.sign(), track.tofNSigmaDe()); - QA.fill(HIST("QA/hnSigmaTPCVsPt_De_AfterSel"), track.pt() * track.sign(), track.tpcNSigmaDe()); - QA.fill(HIST("QA/hnSigmaITSVsPt_De_AfterSel"), track.pt() * track.sign(), track.itsNSigmaDe()); + registryQa.fill(HIST("QA/hTPCnClusters"), track.tpcNClsFound()); + registryQa.fill(HIST("QA/hTPCSharedClusters"), track.tpcFractionSharedCls()); + registryQa.fill(HIST("QA/hTPCchi2"), track.tpcChi2NCl()); + registryQa.fill(HIST("QA/hTPCcrossedRowsOverFindableCls"), track.tpcCrossedRowsOverFindableCls()); + registryQa.fill(HIST("QA/hITSchi2"), track.itsChi2NCl()); + registryQa.fill(HIST("QA/hDCAxy"), track.dcaXY(), track.pt()); + registryQa.fill(HIST("QA/hDCAz"), track.dcaZ(), track.pt()); + registryQa.fill(HIST("QA/TPCChi2VsPZ"), track.tpcInnerParam() / track.sign(), track.tpcChi2NCl()); + registryQa.fill(HIST("QA/hVtxZ_trk"), collision.posZ()); + registryQa.fill(HIST("QA/hnSigmaTPCVsPt_El"), track.pt() * track.sign(), track.tpcNSigmaEl()); + registryQa.fill(HIST("QA/hnSigmaTPCVsPt_Pr"), track.pt() * track.sign(), track.tpcNSigmaPr()); + registryQa.fill(HIST("QA/hnSigmaTPCVsPt_De"), track.pt() * track.sign(), track.tpcNSigmaDe()); + registryQa.fill(HIST("QA/hnSigmaTOFVsPt_Pr"), track.pt() * track.sign(), track.tofNSigmaPr()); + registryQa.fill(HIST("QA/hnSigmaTOFVsPt_De"), track.pt() * track.sign(), track.tofNSigmaDe()); + registryQa.fill(HIST("QA/hnSigmaITSVsPt_Pr"), track.pt() * track.sign(), track.itsNSigmaPr()); + registryQa.fill(HIST("QA/hnSigmaITSVsPt_De"), track.pt() * track.sign(), track.itsNSigmaDe()); + registryQa.fill(HIST("QA/h2dTPCTOF_AntiPr"), track.tpcNSigmaPr(), track.tofNSigmaPr()); + registryQa.fill(HIST("QA/h2dTPCTOF_Pr"), track.tpcNSigmaPr(), track.tofNSigmaPr()); + + if (isProton(track, -1)) { + registryQa.fill(HIST("QA/hEtaAntiPr"), track.eta()); + registryQa.fill(HIST("QA/hPhiAntiPr"), track.phi()); + registryQa.fill(HIST("QA/hnSigmaTOFVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.tofNSigmaPr()); + registryQa.fill(HIST("QA/hnSigmaTPCVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.tpcNSigmaPr()); + registryQa.fill(HIST("QA/hnSigmaITSVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.itsNSigmaPr()); + registryQa.fill(HIST("QA/h2dTPCTOF_AntiPr_AfterSel"), track.tpcNSigmaPr(), track.tofNSigmaPr()); + } + if (isProton(track, +1)) { + registryQa.fill(HIST("QA/hEtaPr"), track.eta()); + registryQa.fill(HIST("QA/hPhiPr"), track.phi()); + registryQa.fill(HIST("QA/hnSigmaTOFVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.tofNSigmaPr()); + registryQa.fill(HIST("QA/hnSigmaTPCVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.tpcNSigmaPr()); + registryQa.fill(HIST("QA/hnSigmaITSVsPt_Pr_AfterSel"), track.pt() * track.sign(), track.itsNSigmaPr()); + registryQa.fill(HIST("QA/h2dTPCTOF_Pr_AfterSel"), track.tpcNSigmaPr(), track.tofNSigmaPr()); + } + if (isDeuteron(track, -1)) { + registryQa.fill(HIST("QA/hEtaAntiDe"), track.eta()); + registryQa.fill(HIST("QA/hPhiAntiDe"), track.phi()); + registryQa.fill(HIST("QA/hnSigmaTOFVsPt_De_AfterSel"), track.pt() * track.sign(), track.tofNSigmaDe()); + registryQa.fill(HIST("QA/hnSigmaTPCVsPt_De_AfterSel"), track.pt() * track.sign(), track.tpcNSigmaDe()); + registryQa.fill(HIST("QA/hnSigmaITSVsPt_De_AfterSel"), track.pt() * track.sign(), track.itsNSigmaDe()); + } + if (isDeuteron(track, +1)) { + registryQa.fill(HIST("QA/hEtaDe"), track.eta()); + registryQa.fill(HIST("QA/hPhiDe"), track.phi()); + registryQa.fill(HIST("QA/hnSigmaTOFVsPt_De_AfterSel"), track.pt() * track.sign(), track.tofNSigmaDe()); + registryQa.fill(HIST("QA/hnSigmaTPCVsPt_De_AfterSel"), track.pt() * track.sign(), track.tpcNSigmaDe()); + registryQa.fill(HIST("QA/hnSigmaITSVsPt_De_AfterSel"), track.pt() * track.sign(), track.itsNSigmaDe()); } } } - Pair->SetMagField1(collision.magField()); - Pair->SetMagField2(collision.magField()); + pair->SetMagField1(collision.magField()); + pair->SetMagField2(collision.magField()); if (mode == kPbarPbar || mode == kPP) { // Identical particle combinations for (const auto& [part0, part1] : combinations(CombinationsStrictlyUpperIndexPolicy(tracks, tracks))) { - if (removeSameBunchPileup && !part0.template singleCollSel_as().isNoSameBunchPileup()) + if (removeSameBunchPileup && !part0.template singleCollSel_as().isNoSameBunchPileup()) { continue; + } - if (part0.tpcFractionSharedCls() > maxtpcSharedCls) + if (part0.tpcFractionSharedCls() > maxtpcSharedCls) { continue; - if (part0.itsNCls() < minitsNCls) + } + if (part0.itsNCls() < minitsNCls) { continue; - if (part1.tpcFractionSharedCls() > maxtpcSharedCls) + } + if (part1.tpcFractionSharedCls() > maxtpcSharedCls) { continue; - if (part1.itsNCls() < minitsNCls) + } + if (part1.itsNCls() < minitsNCls) { continue; + } - if (!applyDCAcut(part0)) + if (!applyDCAcut(part0)) { continue; - if (!applyDCAcut(part1)) + } + if (!applyDCAcut(part1)) { continue; + } // remove tracks outside pt bins - if (part0.pt() < pTBins.value.at(0) || part0.pt() >= pTBins.value.at(nBinspT)) + if (part0.pt() < pTBins.value.at(0) || part0.pt() >= pTBins.value.at(nBinspT)) { continue; - if (part1.pt() < pTBins.value.at(0) || part1.pt() >= pTBins.value.at(nBinspT)) + } + if (part1.pt() < pTBins.value.at(0) || part1.pt() >= pTBins.value.at(nBinspT)) { continue; + } // mode 6 if (mode == kPP) { - if (!IsProton(part0, +1)) + if (!isProton(part0, +1)) { continue; - if (!IsProton(part1, +1)) + } + if (!isProton(part1, +1)) { continue; + } } // mode 5 if (mode == kPbarPbar) { - if (!IsProton(part0, -1)) + if (!isProton(part0, -1)) { continue; - if (!IsProton(part1, -1)) + } + if (!isProton(part1, -1)) { continue; + } } fillHistograms(part0, part1, false, true); @@ -1130,65 +1078,86 @@ struct HadronNucleiCorrelation { for (const auto& [part0, part1] : combinations(CombinationsFullIndexPolicy(tracks, tracks))) { - if (removeSameBunchPileup && !part0.template singleCollSel_as().isNoSameBunchPileup()) + if (removeSameBunchPileup && !part0.template singleCollSel_as().isNoSameBunchPileup()) { continue; + } - if (part0.tpcFractionSharedCls() > maxtpcSharedCls) + if (part0.tpcFractionSharedCls() > maxtpcSharedCls) { continue; - if (part0.itsNCls() < minitsNCls) + } + if (part0.itsNCls() < minitsNCls) { continue; - if (part1.tpcFractionSharedCls() > maxtpcSharedCls) + } + if (part1.tpcFractionSharedCls() > maxtpcSharedCls) { continue; - if (part1.itsNCls() < minitsNCls) + } + if (part1.itsNCls() < minitsNCls) { continue; + } - if (!applyDCAcut(part0)) + if (!applyDCAcut(part0)) { continue; - if (!applyDCAcut(part1)) + } + if (!applyDCAcut(part1)) { continue; + } // remove tracks outside pt bins - if (part0.pt() < pTBins.value.at(0) || part0.pt() >= pTBins.value.at(nBinspT)) + if (part0.pt() < pTBins.value.at(0) || part0.pt() >= pTBins.value.at(nBinspT)) { continue; - if (part1.pt() < pTBins.value.at(0) || part1.pt() >= pTBins.value.at(nBinspT)) + } + if (part1.pt() < pTBins.value.at(0) || part1.pt() >= pTBins.value.at(nBinspT)) { continue; + } // modes 0,1,2,3,4,7 if (mode == kDbarPbar) { - if (!IsDeuteron(part0, -1)) + if (!isDeuteron(part0, -1)) { continue; - if (!IsProton(part1, -1)) + } + if (!isProton(part1, -1)) { continue; + } } if (mode == kDP) { - if (!IsDeuteron(part0, +1)) + if (!isDeuteron(part0, +1)) { continue; - if (!IsProton(part1, +1)) + } + if (!isProton(part1, +1)) { continue; + } } if (mode == kDbarP) { - if (!IsDeuteron(part0, -1)) + if (!isDeuteron(part0, -1)) { continue; - if (!IsProton(part1, +1)) + } + if (!isProton(part1, +1)) { continue; + } } if (mode == kDPbar) { - if (!IsDeuteron(part0, +1)) + if (!isDeuteron(part0, +1)) { continue; - if (!IsProton(part1, -1)) + } + if (!isProton(part1, -1)) { continue; + } } if (mode == kPbarP) { - if (!IsProton(part0, -1)) + if (!isProton(part0, -1)) { continue; - if (!IsProton(part1, +1)) + } + if (!isProton(part1, +1)) { continue; + } } if (mode == kPPbar) { - if (!IsProton(part0, +1)) + if (!isProton(part0, +1)) { continue; - if (!IsProton(part1, -1)) + } + if (!isProton(part1, -1)) { continue; + } } fillHistograms(part0, part1, false, false); @@ -1216,84 +1185,109 @@ struct HadronNucleiCorrelation { continue; } - Pair->SetMagField1(magFieldTesla1); - Pair->SetMagField2(magFieldTesla2); + pair->SetMagField1(magFieldTesla1); + pair->SetMagField2(magFieldTesla2); for (const auto& [part0, part1] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { - if (part0.tpcFractionSharedCls() > maxtpcSharedCls) + if (part0.tpcFractionSharedCls() > maxtpcSharedCls) { continue; - if (part0.itsNCls() < minitsNCls) + } + if (part0.itsNCls() < minitsNCls) { continue; - if (part1.tpcFractionSharedCls() > maxtpcSharedCls) + } + if (part1.tpcFractionSharedCls() > maxtpcSharedCls) { continue; - if (part1.itsNCls() < minitsNCls) + } + if (part1.itsNCls() < minitsNCls) { continue; + } - if (!applyDCAcut(part0)) + if (!applyDCAcut(part0)) { continue; - if (!applyDCAcut(part1)) + } + if (!applyDCAcut(part1)) { continue; + } // remove tracks outside pt bins - if (part0.pt() < pTBins.value.at(0) || part0.pt() >= pTBins.value.at(nBinspT)) + if (part0.pt() < pTBins.value.at(0) || part0.pt() >= pTBins.value.at(nBinspT)) { continue; - if (part1.pt() < pTBins.value.at(0) || part1.pt() >= pTBins.value.at(nBinspT)) + } + if (part1.pt() < pTBins.value.at(0) || part1.pt() >= pTBins.value.at(nBinspT)) { continue; + } //{"mode", 0, "0: antid-antip, 1: d-p, 2: antid-p, 3: d-antip, 4: antip-p, 5: antip-antip, 6: p-p, 7: p-antip"}; if (mode == kDbarPbar) { - if (!IsDeuteron(part0, -1)) + if (!isDeuteron(part0, -1)) { continue; - if (!IsProton(part1, -1)) + } + if (!isProton(part1, -1)) { continue; + } } if (mode == kDP) { - if (!IsDeuteron(part0, +1)) + if (!isDeuteron(part0, +1)) { continue; - if (!IsProton(part1, +1)) + } + if (!isProton(part1, +1)) { continue; + } } if (mode == kDbarP) { - if (!IsDeuteron(part0, -1)) + if (!isDeuteron(part0, -1)) { continue; - if (!IsProton(part1, +1)) + } + if (!isProton(part1, +1)) { continue; + } } if (mode == kDPbar) { - if (!IsDeuteron(part0, +1)) + if (!isDeuteron(part0, +1)) { continue; - if (!IsProton(part1, -1)) + } + if (!isProton(part1, -1)) { continue; + } } if (mode == kPbarP) { - if (!IsProton(part0, -1)) + if (!isProton(part0, -1)) { continue; - if (!IsProton(part1, +1)) + } + if (!isProton(part1, +1)) { continue; + } } if (mode == kPbarPbar) { - if (!IsProton(part0, -1)) + if (!isProton(part0, -1)) { continue; - if (!IsProton(part1, -1)) + } + if (!isProton(part1, -1)) { continue; + } } if (mode == kPP) { - if (!IsProton(part0, +1)) + if (!isProton(part0, +1)) { continue; - if (!IsProton(part1, +1)) + } + if (!isProton(part1, +1)) { continue; + } } if (mode == kPPbar) { - if (!IsProton(part0, +1)) + if (!isProton(part0, +1)) { continue; - if (!IsProton(part1, -1)) + } + if (!isProton(part1, -1)) { continue; + } } bool isIdentical = false; - if (mode == kPbarPbar || mode == kPP) + if (mode == kPbarPbar || mode == kPP) { isIdentical = true; + } fillHistograms(part0, part1, true, isIdentical); } @@ -1320,89 +1314,116 @@ struct HadronNucleiCorrelation { continue; } - Pair->SetMagField1(magFieldTesla1); - Pair->SetMagField2(magFieldTesla2); + pair->SetMagField1(magFieldTesla1); + pair->SetMagField2(magFieldTesla2); for (const auto& [part0, part1] : combinations(CombinationsFullIndexPolicy(groupPartsOne, groupPartsTwo))) { - if (removeSameBunchPileup && !part0.template singleCollSel_as().isNoSameBunchPileup()) + if (removeSameBunchPileup && !part0.template singleCollSel_as().isNoSameBunchPileup()) { continue; - if (removeSameBunchPileup && !part1.template singleCollSel_as().isNoSameBunchPileup()) + } + if (removeSameBunchPileup && !part1.template singleCollSel_as().isNoSameBunchPileup()) { continue; + } - if (part0.tpcFractionSharedCls() > maxtpcSharedCls) + if (part0.tpcFractionSharedCls() > maxtpcSharedCls) { continue; - if (part0.itsNCls() < minitsNCls) + } + if (part0.itsNCls() < minitsNCls) { continue; - if (part1.tpcFractionSharedCls() > maxtpcSharedCls) + } + if (part1.tpcFractionSharedCls() > maxtpcSharedCls) { continue; - if (part1.itsNCls() < minitsNCls) + } + if (part1.itsNCls() < minitsNCls) { continue; + } - if (!applyDCAcut(part0)) + if (!applyDCAcut(part0)) { continue; - if (!applyDCAcut(part1)) + } + if (!applyDCAcut(part1)) { continue; + } // remove tracks outside pt bins - if (part0.pt() < pTBins.value.at(0) || part0.pt() >= pTBins.value.at(nBinspT)) + if (part0.pt() < pTBins.value.at(0) || part0.pt() >= pTBins.value.at(nBinspT)) { continue; - if (part1.pt() < pTBins.value.at(0) || part1.pt() >= pTBins.value.at(nBinspT)) + } + if (part1.pt() < pTBins.value.at(0) || part1.pt() >= pTBins.value.at(nBinspT)) { continue; + } //{"mode", 0, "0: antid-antip, 1: d-p, 2: antid-p, 3: d-antip, 4: antip-p, 5: antip-antip, 6: p-p, 7: p-antip"}; if (mode == kDbarPbar) { - if (!IsDeuteron(part0, -1)) + if (!isDeuteron(part0, -1)) { continue; - if (!IsProton(part1, -1)) + } + if (!isProton(part1, -1)) { continue; + } } if (mode == kDP) { - if (!IsDeuteron(part0, +1)) + if (!isDeuteron(part0, +1)) { continue; - if (!IsProton(part1, +1)) + } + if (!isProton(part1, +1)) { continue; + } } if (mode == kDbarP) { - if (!IsDeuteron(part0, -1)) + if (!isDeuteron(part0, -1)) { continue; - if (!IsProton(part1, +1)) + } + if (!isProton(part1, +1)) { continue; + } } if (mode == kDPbar) { - if (!IsDeuteron(part0, +1)) + if (!isDeuteron(part0, +1)) { continue; - if (!IsProton(part1, -1)) + } + if (!isProton(part1, -1)) { continue; + } } if (mode == kPbarP) { - if (!IsProton(part0, -1)) + if (!isProton(part0, -1)) { continue; - if (!IsProton(part1, +1)) + } + if (!isProton(part1, +1)) { continue; + } } if (mode == kPbarPbar) { - if (!IsProton(part0, -1)) + if (!isProton(part0, -1)) { continue; - if (!IsProton(part1, -1)) + } + if (!isProton(part1, -1)) { continue; + } } if (mode == kPP) { - if (!IsProton(part0, +1)) + if (!isProton(part0, +1)) { continue; - if (!IsProton(part1, +1)) + } + if (!isProton(part1, +1)) { continue; + } } if (mode == kPPbar) { - if (!IsProton(part0, +1)) + if (!isProton(part0, +1)) { continue; - if (!IsProton(part1, -1)) + } + if (!isProton(part1, -1)) { continue; + } } bool isIdentical = false; - if (mode == kPbarPbar || mode == kPP) + if (mode == kPbarPbar || mode == kPP) { isIdentical = true; + } fillHistograms(part0, part1, true, isIdentical); } @@ -1413,78 +1434,94 @@ struct HadronNucleiCorrelation { void processMC(FilteredCollisions const&, FilteredTracksMC const& tracks) { for (const auto& track : tracks) { - if (std::abs(track.template singleCollSel_as().posZ()) > cutzVertex) + if (std::abs(track.template singleCollSel_as().posZ()) > cutzVertex) { continue; + } - if (track.tpcFractionSharedCls() > maxtpcSharedCls) + if (track.tpcFractionSharedCls() > maxtpcSharedCls) { continue; - if (track.itsNCls() < minitsNCls) + } + if (track.itsNCls() < minitsNCls) { continue; + } - if (IsProton(track, +1) && track.pdgCode() == PDG_t::kProton) { + if (isProton(track, +1) && track.pdgCode() == PDG_t::kProton) { registry.fill(HIST("hPrDCAxy"), track.dcaXY(), track.pt()); - if (track.origin() == kPrimary) + if (track.origin() == kPrimary) { registry.fill(HIST("hPrimPrDCAxy"), track.dcaXY(), track.pt()); - if (track.origin() == kWeakDecay) + } + if (track.origin() == kWeakDecay) { registry.fill(HIST("hSecWeakPrDCAxy"), track.dcaXY(), track.pt()); - if (track.origin() == kMaterial) + } + if (track.origin() == kMaterial) { registry.fill(HIST("hSecMatPrDCAxy"), track.dcaXY(), track.pt()); + } } - if (IsProton(track, -1) && track.pdgCode() == -PDG_t::kProton) { + if (isProton(track, -1) && track.pdgCode() == -PDG_t::kProton) { registry.fill(HIST("hAntiPrDCAxy"), track.dcaXY(), track.pt()); - if (track.origin() == kPrimary) + if (track.origin() == kPrimary) { registry.fill(HIST("hPrimAntiPrDCAxy"), track.dcaXY(), track.pt()); - if (track.origin() == kWeakDecay) + } + if (track.origin() == kWeakDecay) { registry.fill(HIST("hSecWeakAntiPrDCAxy"), track.dcaXY(), track.pt()); - if (track.origin() == kMaterial) + } + if (track.origin() == kMaterial) { registry.fill(HIST("hSecMatAntiPrDCAxy"), track.dcaXY(), track.pt()); + } } - if (IsDeuteron(track, +1) && track.pdgCode() == o2::constants::physics::Pdg::kDeuteron) { + if (isDeuteron(track, +1) && track.pdgCode() == o2::constants::physics::Pdg::kDeuteron) { registry.fill(HIST("hDeDCAxy"), track.dcaXY(), track.pt()); - if (track.origin() == kPrimary) + if (track.origin() == kPrimary) { registry.fill(HIST("hPrimDeDCAxy"), track.dcaXY(), track.pt()); - if (track.origin() == kWeakDecay) + } + if (track.origin() == kWeakDecay) { registry.fill(HIST("hSecWeakDeDCAxy"), track.dcaXY(), track.pt()); - if (track.origin() == kMaterial) + } + if (track.origin() == kMaterial) { registry.fill(HIST("hSecMatDeDCAxy"), track.dcaXY(), track.pt()); + } } - if (IsDeuteron(track, -1) && track.pdgCode() == -o2::constants::physics::Pdg::kDeuteron) { + if (isDeuteron(track, -1) && track.pdgCode() == -o2::constants::physics::Pdg::kDeuteron) { registry.fill(HIST("hAntiDeDCAxy"), track.dcaXY(), track.pt()); - if (track.origin() == kPrimary) + if (track.origin() == kPrimary) { registry.fill(HIST("hPrimAntiDeDCAxy"), track.dcaXY(), track.pt()); - if (track.origin() == kWeakDecay) + } + if (track.origin() == kWeakDecay) { registry.fill(HIST("hSecWeakAntiDeDCAxy"), track.dcaXY(), track.pt()); - if (track.origin() == kMaterial) + } + if (track.origin() == kMaterial) { registry.fill(HIST("hSecMatAntiDeDCAxy"), track.dcaXY(), track.pt()); + } } - if (!applyDCAcut(track)) + if (!applyDCAcut(track)) { continue; + } // Keep only protons and deuterons // if (std::abs(track.pdgCode()) != PDG_t::kProton && std::abs(track.pdgCode()) != o2::constants::physics::Pdg::kDeuteron) // continue; if (doQA) { - QA.fill(HIST("QA/hTPCnClusters"), track.tpcNClsFound()); - QA.fill(HIST("QA/hTPCSharedClusters"), track.tpcFractionSharedCls()); - QA.fill(HIST("QA/hTPCchi2"), track.tpcChi2NCl()); - QA.fill(HIST("QA/hTPCcrossedRowsOverFindableCls"), track.tpcCrossedRowsOverFindableCls()); - QA.fill(HIST("QA/hITSchi2"), track.itsChi2NCl()); - QA.fill(HIST("QA/hDCAxy"), track.dcaXY(), track.pt()); - QA.fill(HIST("QA/hDCAz"), track.dcaZ(), track.pt()); - QA.fill(HIST("QA/hVtxZ_trk"), track.template singleCollSel_as().posZ()); - QA.fill(HIST("QA/hnSigmaTPCVsPt_El"), track.pt() * track.sign(), track.tpcNSigmaEl()); - QA.fill(HIST("QA/hnSigmaTPCVsPt_Pr"), track.pt() * track.sign(), track.tpcNSigmaPr()); - QA.fill(HIST("QA/hnSigmaTPCVsPt_De"), track.pt() * track.sign(), track.tpcNSigmaDe()); - QA.fill(HIST("QA/hnSigmaTOFVsPt_Pr"), track.pt() * track.sign(), track.tofNSigmaPr()); - QA.fill(HIST("QA/hnSigmaTOFVsPt_De"), track.pt() * track.sign(), track.tofNSigmaDe()); - } - - bool isPr = (IsProton(track, +1) && track.pdgCode() == PDG_t::kProton); - bool isAntiPr = (IsProton(track, -1) && track.pdgCode() == -PDG_t::kProton); - bool isDe = (IsDeuteron(track, +1) && track.pdgCode() == o2::constants::physics::Pdg::kDeuteron); - bool isAntiDe = (IsDeuteron(track, -1) && track.pdgCode() == -o2::constants::physics::Pdg::kDeuteron); + registryQa.fill(HIST("QA/hTPCnClusters"), track.tpcNClsFound()); + registryQa.fill(HIST("QA/hTPCSharedClusters"), track.tpcFractionSharedCls()); + registryQa.fill(HIST("QA/hTPCchi2"), track.tpcChi2NCl()); + registryQa.fill(HIST("QA/hTPCcrossedRowsOverFindableCls"), track.tpcCrossedRowsOverFindableCls()); + registryQa.fill(HIST("QA/hITSchi2"), track.itsChi2NCl()); + registryQa.fill(HIST("QA/hDCAxy"), track.dcaXY(), track.pt()); + registryQa.fill(HIST("QA/hDCAz"), track.dcaZ(), track.pt()); + registryQa.fill(HIST("QA/hVtxZ_trk"), track.template singleCollSel_as().posZ()); + registryQa.fill(HIST("QA/hnSigmaTPCVsPt_El"), track.pt() * track.sign(), track.tpcNSigmaEl()); + registryQa.fill(HIST("QA/hnSigmaTPCVsPt_Pr"), track.pt() * track.sign(), track.tpcNSigmaPr()); + registryQa.fill(HIST("QA/hnSigmaTPCVsPt_De"), track.pt() * track.sign(), track.tpcNSigmaDe()); + registryQa.fill(HIST("QA/hnSigmaTOFVsPt_Pr"), track.pt() * track.sign(), track.tofNSigmaPr()); + registryQa.fill(HIST("QA/hnSigmaTOFVsPt_De"), track.pt() * track.sign(), track.tofNSigmaDe()); + } + + bool isPr = (isProton(track, +1) && track.pdgCode() == PDG_t::kProton); + bool isAntiPr = (isProton(track, -1) && track.pdgCode() == -PDG_t::kProton); + bool isDe = (isDeuteron(track, +1) && track.pdgCode() == o2::constants::physics::Pdg::kDeuteron); + bool isAntiDe = (isDeuteron(track, -1) && track.pdgCode() == -o2::constants::physics::Pdg::kDeuteron); if (isPr) { registry.fill(HIST("hPrimSec_EtaPhiPt_Proton"), track.eta(), track.phi(), track.pt() * +1); @@ -1499,8 +1536,9 @@ struct HadronNucleiCorrelation { } } - if (track.origin() != 0) + if (track.origin() != 0) { continue; + } if (track.pdgCode() == PDG_t::kProton) { registry.fill(HIST("hReco_EtaPhiPt_Proton"), track.eta(), track.phi(), track.pt()); @@ -1577,14 +1615,18 @@ struct HadronNucleiCorrelation { registry.fill(HIST("hNumeratorPurity_Deuteron"), track.pt() * -1); registry.fill(HIST("hReco_Pt_Deuteron"), track.pt() * -1); } - if (IsProton(track, +1)) + if (isProton(track, +1)) { registry.fill(HIST("hDenominatorPurity_Proton"), track.pt()); - if (IsProton(track, -1)) + } + if (isProton(track, -1)) { registry.fill(HIST("hDenominatorPurity_Proton"), track.pt() * -1); - if (IsDeuteron(track, +1)) + } + if (isDeuteron(track, +1)) { registry.fill(HIST("hDenominatorPurity_Deuteron"), track.pt()); - if (IsDeuteron(track, -1)) + } + if (isDeuteron(track, -1)) { registry.fill(HIST("hDenominatorPurity_Deuteron"), track.pt() * -1); + } if (doMCQA) { // Proton @@ -1597,8 +1639,8 @@ struct HadronNucleiCorrelation { registry.fill(HIST("hNumeratorPurity_Proton_TPCTOF"), track.pt()); registry.fill(HIST("hReco_Pt_Proton_TPCTOF"), track.pt()); } - if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.beta() < betahasTOFthr) || - (track.beta() > betahasTOFthr && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && + if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.beta() < BetahasTOFthr) || + (track.beta() > BetahasTOFthr && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && track.pdgCode() == PDG_t::kProton) { registry.fill(HIST("hNumeratorPurity_Proton_TPC_or_TOF"), track.pt()); registry.fill(HIST("hReco_Pt_Proton_TPC_or_TOF"), track.pt()); @@ -1608,8 +1650,8 @@ struct HadronNucleiCorrelation { registry.fill(HIST("hNumeratorPurity_Proton_TPCEl"), track.pt()); registry.fill(HIST("hReco_Pt_Proton_TPCEl"), track.pt()); } - if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElPr && track.beta() < betahasTOFthr) || - (track.beta() > betahasTOFthr && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && + if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElPr && track.beta() < BetahasTOFthr) || + (track.beta() > BetahasTOFthr && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && track.pdgCode() == PDG_t::kProton) { registry.fill(HIST("hNumeratorPurity_Proton_TPCEl_or_TOF"), track.pt()); registry.fill(HIST("hReco_Pt_Proton_TPCEl_or_TOF"), track.pt()); @@ -1625,8 +1667,8 @@ struct HadronNucleiCorrelation { registry.fill(HIST("hNumeratorPurity_Proton_TPCTOF"), track.pt() * -1); registry.fill(HIST("hReco_Pt_Proton_TPCTOF"), track.pt() * -1); } - if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.beta() < betahasTOFthr) || - (track.beta() > betahasTOFthr && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && + if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.beta() < BetahasTOFthr) || + (track.beta() > BetahasTOFthr && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && track.pdgCode() == -PDG_t::kProton) { registry.fill(HIST("hNumeratorPurity_Proton_TPC_or_TOF"), track.pt() * -1); registry.fill(HIST("hReco_Pt_Proton_TPC_or_TOF"), track.pt() * -1); @@ -1636,8 +1678,8 @@ struct HadronNucleiCorrelation { registry.fill(HIST("hNumeratorPurity_Proton_TPCEl"), track.pt() * -1); registry.fill(HIST("hReco_Pt_Proton_TPCEl"), track.pt() * -1); } - if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElPr && track.beta() < betahasTOFthr) || - (track.beta() > betahasTOFthr && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && + if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElPr && track.beta() < BetahasTOFthr) || + (track.beta() > BetahasTOFthr && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && track.pdgCode() == -PDG_t::kProton) { registry.fill(HIST("hNumeratorPurity_Proton_TPCEl_or_TOF"), track.pt() * -1); registry.fill(HIST("hReco_Pt_Proton_TPCEl_or_TOF"), track.pt() * -1); @@ -1653,8 +1695,8 @@ struct HadronNucleiCorrelation { registry.fill(HIST("hNumeratorPurity_Deuteron_TPCTOF"), track.pt()); registry.fill(HIST("hReco_Pt_Deuteron_TPCTOF"), track.pt()); } - if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.beta() < betahasTOFthr) || - (track.beta() > betahasTOFthr && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && + if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.beta() < BetahasTOFthr) || + (track.beta() > BetahasTOFthr && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && track.pdgCode() == o2::constants::physics::Pdg::kDeuteron) { registry.fill(HIST("hNumeratorPurity_Deuteron_TPC_or_TOF"), track.pt()); registry.fill(HIST("hReco_Pt_Deuteron_TPC_or_TOF"), track.pt()); @@ -1664,8 +1706,8 @@ struct HadronNucleiCorrelation { registry.fill(HIST("hNumeratorPurity_Deuteron_TPCEl"), track.pt()); registry.fill(HIST("hReco_Pt_Deuteron_TPCEl"), track.pt()); } - if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElDe && track.beta() < betahasTOFthr) || - (track.beta() > betahasTOFthr && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && + if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElDe && track.beta() < BetahasTOFthr) || + (track.beta() > BetahasTOFthr && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && track.pdgCode() == o2::constants::physics::Pdg::kDeuteron) { registry.fill(HIST("hNumeratorPurity_Deuteron_TPCEl_or_TOF"), track.pt()); registry.fill(HIST("hReco_Pt_Deuteron_TPCEl_or_TOF"), track.pt()); @@ -1681,8 +1723,8 @@ struct HadronNucleiCorrelation { registry.fill(HIST("hNumeratorPurity_Deuteron_TPCTOF"), track.pt() * -1); registry.fill(HIST("hReco_Pt_Deuteron_TPCTOF"), track.pt() * -1); } - if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.beta() < betahasTOFthr) || - (track.beta() > betahasTOFthr && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && + if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.beta() < BetahasTOFthr) || + (track.beta() > BetahasTOFthr && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && track.pdgCode() == -o2::constants::physics::Pdg::kDeuteron) { registry.fill(HIST("hNumeratorPurity_Deuteron_TPC_or_TOF"), track.pt() * -1); registry.fill(HIST("hReco_Pt_Deuteron_TPC_or_TOF"), track.pt() * -1); @@ -1692,56 +1734,64 @@ struct HadronNucleiCorrelation { registry.fill(HIST("hNumeratorPurity_Deuteron_TPCEl"), track.pt() * -1); registry.fill(HIST("hReco_Pt_Deuteron_TPCEl"), track.pt() * -1); } - if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElDe && track.beta() < betahasTOFthr) || - (track.beta() > betahasTOFthr && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && + if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElDe && track.beta() < BetahasTOFthr) || + (track.beta() > BetahasTOFthr && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && track.pdgCode() == -o2::constants::physics::Pdg::kDeuteron) { registry.fill(HIST("hNumeratorPurity_Deuteron_TPCEl_or_TOF"), track.pt() * -1); registry.fill(HIST("hReco_Pt_Deuteron_TPCEl_or_TOF"), track.pt() * -1); } // Denominators - if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.sign() > 0) + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.sign() > 0) { registry.fill(HIST("hDenominatorPurity_Proton_TPC"), track.pt()); - if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF && track.sign() > 0) + } + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF && track.sign() > 0) { registry.fill(HIST("hDenominatorPurity_Proton_TPCTOF"), track.pt()); - if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.beta() < betahasTOFthr) || - (track.beta() > betahasTOFthr && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && - track.sign() > 0) + } + if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.beta() < BetahasTOFthr) || + (track.beta() > BetahasTOFthr && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && + track.sign() > 0) { registry.fill(HIST("hDenominatorPurity_Proton_TPC_or_TOF"), track.pt()); + } if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElPr && track.sign() > 0) { registry.fill(HIST("hDenominatorPurity_Proton_TPCEl"), track.pt()); } - if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElPr && track.beta() < betahasTOFthr) || - (track.beta() > betahasTOFthr && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && + if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElPr && track.beta() < BetahasTOFthr) || + (track.beta() > BetahasTOFthr && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && track.sign() > 0) { registry.fill(HIST("hDenominatorPurity_Proton_TPCEl_or_TOF"), track.pt()); } - if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.sign() < 0) + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.sign() < 0) { registry.fill(HIST("hDenominatorPurity_Proton_TPC"), track.pt() * -1); - if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF && track.sign() < 0) + } + if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF && track.sign() < 0) { registry.fill(HIST("hDenominatorPurity_Proton_TPCTOF"), track.pt() * -1); - if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.beta() < betahasTOFthr) || - (track.beta() > betahasTOFthr && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && - track.sign() < 0) + } + if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.beta() < BetahasTOFthr) || + (track.beta() > BetahasTOFthr && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && + track.sign() < 0) { registry.fill(HIST("hDenominatorPurity_Proton_TPC_or_TOF"), track.pt() * -1); + } if (std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElPr && track.sign() < 0) { registry.fill(HIST("hDenominatorPurity_Proton_TPCEl"), track.pt() * -1); } - if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElPr && track.beta() < betahasTOFthr) || - (track.beta() > betahasTOFthr && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && + if (((std::abs(track.tpcNSigmaPr()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElPr && track.beta() < BetahasTOFthr) || + (track.beta() > BetahasTOFthr && std::abs(track.tpcNSigmaPr()) < nsigmaTPC && std::abs(track.tofNSigmaPr()) < nsigmaTOF)) && track.sign() < 0) { registry.fill(HIST("hDenominatorPurity_Proton_TPCEl_or_TOF"), track.pt() * -1); } - if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.sign() > 0) + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.sign() > 0) { registry.fill(HIST("hDenominatorPurity_Deuteron_TPC"), track.pt()); - if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF && track.sign() > 0) + } + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF && track.sign() > 0) { registry.fill(HIST("hDenominatorPurity_Deuteron_TPCTOF"), track.pt()); - if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.beta() < betahasTOFthr) || - (track.beta() > betahasTOFthr && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && + } + if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.beta() < BetahasTOFthr) || + (track.beta() > BetahasTOFthr && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && track.sign() > 0) { registry.fill(HIST("hDenominatorPurity_Deuteron_TPC_or_TOF"), track.pt()); } @@ -1749,28 +1799,33 @@ struct HadronNucleiCorrelation { track.tpcNSigmaEl() >= nsigmaElDe && track.sign() > 0) { registry.fill(HIST("hDenominatorPurity_Deuteron_TPCEl"), track.pt()); } - if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElDe && track.beta() < betahasTOFthr) || - (track.beta() > betahasTOFthr && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && - track.sign() > 0) + if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElDe && track.beta() < BetahasTOFthr) || + (track.beta() > BetahasTOFthr && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && + track.sign() > 0) { registry.fill(HIST("hDenominatorPurity_Deuteron_TPCEl_or_TOF"), track.pt()); + } - if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.sign() < 0) + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.sign() < 0) { registry.fill(HIST("hDenominatorPurity_Deuteron_TPC"), track.pt() * -1); - if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF && track.sign() < 0) + } + if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF && track.sign() < 0) { registry.fill(HIST("hDenominatorPurity_Deuteron_TPCTOF"), track.pt() * -1); + } if (( - (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.beta() < betahasTOFthr) || - (track.beta() > betahasTOFthr && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && - track.sign() < 0) + (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.beta() < BetahasTOFthr) || + (track.beta() > BetahasTOFthr && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && + track.sign() < 0) { registry.fill(HIST("hDenominatorPurity_Deuteron_TPC_or_TOF"), track.pt() * -1); + } if (std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElDe && track.sign() < 0) { registry.fill(HIST("hDenominatorPurity_Deuteron_TPCEl"), track.pt() * -1); } - if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElDe && track.beta() < betahasTOFthr) || - (track.beta() > betahasTOFthr && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && - track.sign() < 0) + if (((std::abs(track.tpcNSigmaDe()) < nsigmaTPC && track.tpcNSigmaEl() >= nsigmaElDe && track.beta() < BetahasTOFthr) || + (track.beta() > BetahasTOFthr && std::abs(track.tpcNSigmaDe()) < nsigmaTPC && std::abs(track.tofNSigmaDe()) < nsigmaTOF)) && + track.sign() < 0) { registry.fill(HIST("hDenominatorPurity_Deuteron_TPCEl_or_TOF"), track.pt() * -1); + } } } // track } @@ -1782,52 +1837,79 @@ struct HadronNucleiCorrelation { registry.fill(HIST("Generated/hNEventsMC"), 0.5); for (const auto& particle : mcParticles) { - - if (particle.pdgCode() == PDG_t::kProton) { - registry.fill(HIST("Generated/hQAProtons"), 0.5); - } - if (particle.pdgCode() == o2::constants::physics::Pdg::kDeuteron) { - registry.fill(HIST("Generated/hQADeuterons"), 0.5); + auto fillGeneratedQa = [this, &particle](const float binPosition) { + switch (particle.pdgCode()) { + case PDG_t::kProton: + registry.fill(HIST("Generated/hQAProtons"), binPosition); + return true; + case PDG_t::kProtonBar: + registry.fill(HIST("Generated/hQAAntiProtons"), binPosition); + return true; + case PDG_t::kNeutron: + registry.fill(HIST("Generated/hQANeutrons"), binPosition); + return true; + case PDG_t::kNeutronBar: + registry.fill(HIST("Generated/hQAAntiNeutrons"), binPosition); + return true; + case o2::constants::physics::Pdg::kDeuteron: + registry.fill(HIST("Generated/hQADeuterons"), binPosition); + return true; + case -o2::constants::physics::Pdg::kDeuteron: + registry.fill(HIST("Generated/hQAAntiDeuterons"), binPosition); + return true; + default: + return false; + } + }; + if (!fillGeneratedQa(0.5)) { + continue; } - if (isPrim && !particle.isPhysicalPrimary()) { continue; } - if (particle.pdgCode() == PDG_t::kProton) { - registry.fill(HIST("Generated/hQAProtons"), 1.5); - } - if (particle.pdgCode() == o2::constants::physics::Pdg::kDeuteron) { - registry.fill(HIST("Generated/hQADeuterons"), 1.5); - } - if (particle.pdgCode() == o2::constants::physics::Pdg::kDeuteron && std::abs(particle.y()) < yRap) { - registry.fill(HIST("Generated/hDeuteronsVsPt"), particle.pt()); - } - if (particle.pdgCode() == -o2::constants::physics::Pdg::kDeuteron && std::abs(particle.y()) < yRap) { - registry.fill(HIST("Generated/hAntiDeuteronsVsPt"), particle.pt()); + fillGeneratedQa(1.5); + + if (std::abs(particle.y()) < yRap) { + switch (particle.pdgCode()) { + case PDG_t::kProton: + registry.fill(HIST("Generated/hProtonsVsPt"), particle.pt()); + break; + case -PDG_t::kProton: + registry.fill(HIST("Generated/hAntiProtonsVsPt"), particle.pt()); + break; + case o2::constants::physics::Pdg::kDeuteron: + registry.fill(HIST("Generated/hDeuteronsVsPt"), particle.pt()); + break; + case -o2::constants::physics::Pdg::kDeuteron: + registry.fill(HIST("Generated/hAntiDeuteronsVsPt"), particle.pt()); + break; + default: + break; + } } if (std::abs(particle.eta()) > etaCut) { continue; } - if (particle.pdgCode() == PDG_t::kProton) { - registry.fill(HIST("Generated/hQAProtons"), 2.5); - } - if (particle.pdgCode() == o2::constants::physics::Pdg::kDeuteron) { - registry.fill(HIST("Generated/hQADeuterons"), 2.5); - } - - if (particle.pdgCode() == o2::constants::physics::Pdg::kDeuteron) { - registry.fill(HIST("hGen_EtaPhiPt_Deuteron"), particle.eta(), particle.phi(), particle.pt()); - } - if (particle.pdgCode() == -o2::constants::physics::Pdg::kDeuteron) { - registry.fill(HIST("hGen_EtaPhiPt_Deuteron"), particle.eta(), particle.phi(), -1. * particle.pt()); - } - if (particle.pdgCode() == PDG_t::kProton) { - registry.fill(HIST("hGen_EtaPhiPt_Proton"), particle.eta(), particle.phi(), particle.pt()); - } - if (particle.pdgCode() == -PDG_t::kProton) { - registry.fill(HIST("hGen_EtaPhiPt_Proton"), particle.eta(), particle.phi(), -1. * particle.pt()); + fillGeneratedQa(2.5); + + switch (particle.pdgCode()) { + case PDG_t::kProton: + registry.fill(HIST("hGen_EtaPhiPt_Proton"), particle.eta(), particle.phi(), particle.pt()); + break; + case -PDG_t::kProton: + registry.fill(HIST("hGen_EtaPhiPt_Proton"), particle.eta(), particle.phi(), -1. * particle.pt()); + break; + case o2::constants::physics::Pdg::kDeuteron: + registry.fill(HIST("hGen_EtaPhiPt_Deuteron"), particle.eta(), particle.phi(), particle.pt()); + break; + case -o2::constants::physics::Pdg::kDeuteron: + registry.fill(HIST("hGen_EtaPhiPt_Deuteron"), particle.eta(), particle.phi(), -1. * particle.pt()); + break; + default: + LOG(fatal) << "Unhandled PDG code, should not happen, check the code!" << particle.pdgCode(); + break; } } @@ -1850,17 +1932,21 @@ struct HadronNucleiCorrelation { // mode 6 if (mode == kPP) { - if (part0.pdgCode() != PDG_t::kProton) + if (part0.pdgCode() != PDG_t::kProton) { continue; - if (part1.pdgCode() != PDG_t::kProton) + } + if (part1.pdgCode() != PDG_t::kProton) { continue; + } } // mode 5 if (mode == kPbarPbar) { - if (part0.pdgCode() != -PDG_t::kProton) + if (part0.pdgCode() != -PDG_t::kProton) { continue; - if (part1.pdgCode() != -PDG_t::kProton) + } + if (part1.pdgCode() != -PDG_t::kProton) { continue; + } } fillHistogramsGen(part0, part1, false); @@ -1884,40 +1970,52 @@ struct HadronNucleiCorrelation { } if (mode == kDbarPbar) { - if (part0.pdgCode() != -o2::constants::physics::Pdg::kDeuteron) + if (part0.pdgCode() != -o2::constants::physics::Pdg::kDeuteron) { continue; - if (part1.pdgCode() != -PDG_t::kProton) + } + if (part1.pdgCode() != -PDG_t::kProton) { continue; + } } if (mode == kDP) { - if (part0.pdgCode() != o2::constants::physics::Pdg::kDeuteron) + if (part0.pdgCode() != o2::constants::physics::Pdg::kDeuteron) { continue; - if (part1.pdgCode() != PDG_t::kProton) + } + if (part1.pdgCode() != PDG_t::kProton) { continue; + } } if (mode == kDbarP) { - if (part0.pdgCode() != -o2::constants::physics::Pdg::kDeuteron) + if (part0.pdgCode() != -o2::constants::physics::Pdg::kDeuteron) { continue; - if (part1.pdgCode() != PDG_t::kProton) + } + if (part1.pdgCode() != PDG_t::kProton) { continue; + } } if (mode == kDPbar) { - if (part0.pdgCode() != o2::constants::physics::Pdg::kDeuteron) + if (part0.pdgCode() != o2::constants::physics::Pdg::kDeuteron) { continue; - if (part1.pdgCode() != -PDG_t::kProton) + } + if (part1.pdgCode() != -PDG_t::kProton) { continue; + } } if (mode == kPbarP) { - if (part0.pdgCode() != -PDG_t::kProton) + if (part0.pdgCode() != -PDG_t::kProton) { continue; - if (part1.pdgCode() != PDG_t::kProton) + } + if (part1.pdgCode() != PDG_t::kProton) { continue; + } } if (mode == kPPbar) { - if (part0.pdgCode() != PDG_t::kProton) + if (part0.pdgCode() != PDG_t::kProton) { continue; - if (part1.pdgCode() != -PDG_t::kProton) + } + if (part1.pdgCode() != -PDG_t::kProton) { continue; + } } fillHistogramsGen(part0, part1, false); @@ -1963,52 +2061,68 @@ struct HadronNucleiCorrelation { } if (mode == kDbarPbar) { - if (part0.pdgCode() != -o2::constants::physics::Pdg::kDeuteron) + if (part0.pdgCode() != -o2::constants::physics::Pdg::kDeuteron) { continue; - if (part1.pdgCode() != -PDG_t::kProton) + } + if (part1.pdgCode() != -PDG_t::kProton) { continue; + } } if (mode == kDP) { - if (part0.pdgCode() != o2::constants::physics::Pdg::kDeuteron) + if (part0.pdgCode() != o2::constants::physics::Pdg::kDeuteron) { continue; - if (part1.pdgCode() != PDG_t::kProton) + } + if (part1.pdgCode() != PDG_t::kProton) { continue; + } } if (mode == kDbarP) { - if (part0.pdgCode() != -o2::constants::physics::Pdg::kDeuteron) + if (part0.pdgCode() != -o2::constants::physics::Pdg::kDeuteron) { continue; - if (part1.pdgCode() != PDG_t::kProton) + } + if (part1.pdgCode() != PDG_t::kProton) { continue; + } } if (mode == kDPbar) { - if (part0.pdgCode() != o2::constants::physics::Pdg::kDeuteron) + if (part0.pdgCode() != o2::constants::physics::Pdg::kDeuteron) { continue; - if (part1.pdgCode() != -PDG_t::kProton) + } + if (part1.pdgCode() != -PDG_t::kProton) { continue; + } } if (mode == kPbarP) { - if (part0.pdgCode() != -PDG_t::kProton) + if (part0.pdgCode() != -PDG_t::kProton) { continue; - if (part1.pdgCode() != PDG_t::kProton) + } + if (part1.pdgCode() != PDG_t::kProton) { continue; + } } if (mode == kPbarPbar) { - if (part0.pdgCode() != -PDG_t::kProton) + if (part0.pdgCode() != -PDG_t::kProton) { continue; - if (part1.pdgCode() != -PDG_t::kProton) + } + if (part1.pdgCode() != -PDG_t::kProton) { continue; + } } if (mode == kPP) { - if (part0.pdgCode() != PDG_t::kProton) + if (part0.pdgCode() != PDG_t::kProton) { continue; - if (part1.pdgCode() != PDG_t::kProton) + } + if (part1.pdgCode() != PDG_t::kProton) { continue; + } } if (mode == kPPbar) { - if (part0.pdgCode() != PDG_t::kProton) + if (part0.pdgCode() != PDG_t::kProton) { continue; - if (part1.pdgCode() != -PDG_t::kProton) + } + if (part1.pdgCode() != -PDG_t::kProton) { continue; + } } fillHistogramsGen(part0, part1, true); diff --git a/PWGLF/Tasks/Nuspex/helium_flow.cxx b/PWGLF/Tasks/Nuspex/helium_flow.cxx index 74f76d1c18e..5dab83c0db3 100644 --- a/PWGLF/Tasks/Nuspex/helium_flow.cxx +++ b/PWGLF/Tasks/Nuspex/helium_flow.cxx @@ -183,7 +183,7 @@ struct helium_flow { bool containsParticleOfInterest(false); // Loop over Reconstructed Tracks - for (auto track : tracks) { + for (const auto& track : tracks) { // Track Selection if (!passedTrackSelection(track)) diff --git a/PWGLF/Tasks/Nuspex/lfNucleiBATask.cxx b/PWGLF/Tasks/Nuspex/lfNucleiBATask.cxx index 56182078996..9cfb1e69a55 100644 --- a/PWGLF/Tasks/Nuspex/lfNucleiBATask.cxx +++ b/PWGLF/Tasks/Nuspex/lfNucleiBATask.cxx @@ -169,6 +169,7 @@ struct lfNucleiBATask { ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.425, 0.45, 0.475, 0.5, 0.5125, 0.525, 0.5375, 0.55, 0.5625, 0.575, 0.5875, 0.6, 0.6125, 0.625, 0.6375, 0.65, 0.6625, 0.675, 0.6875, 0.7, 0.7125, 0.725, 0.7375, 0.75, 0.7625, 0.775, 0.7875, 0.8, 0.8125, 0.825, 0.8375, 0.85, 0.8625, 0.875, 0.8875, 0.9, 0.9125, 0.925, 0.9375, 0.95, 0.9625, 0.975, 0.9875, 1.0, 1.0125, 1.025, 1.0375, 1.05, 1.0625, 1.075, 1.0875, 1.1, 1.1125, 1.125, 1.1375, 1.15, 1.1625, 1.175, 1.1875, 1.2, 1.2125, 1.225, 1.2375, 1.25, 1.2625, 1.275, 1.2875, 1.3, 1.3125, 1.325, 1.3375, 1.35, 1.3625, 1.375, 1.3875, 1.4, 1.4125, 1.425, 1.4375, 1.45, 1.4625, 1.475, 1.4875, 1.5, 1.5125, 1.525, 1.5375, 1.55, 1.5625, 1.575, 1.5875, 1.6, 1.6125, 1.625, 1.6375, 1.65, 1.6625, 1.675, 1.6875, 1.7, 1.7125, 1.725, 1.7375, 1.75, 1.7625, 1.775, 1.7875, 1.8, 1.8125, 1.825, 1.8375, 1.85, 1.8625, 1.875, 1.8875, 1.9, 1.9125, 1.925, 1.9375, 1.95, 1.9625, 1.975, 1.9875, 2.0, 2.0625, 2.125, 2.1875, 2.25, 2.3125, 2.375, 2.4375, 2.5, 2.625, 2.75, 2.875, 3.0, 3.25, 3.5, 3.75, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0}, ""}; ConfigurableAxis binsPtHe{"binsPtHe", {VARIABLE_WIDTH, 1.0, 1.25, 1.50, 1.75, 2.0, 2.25, 2.50, 2.75, 3.0, 3.25, 3.50, 3.75, 4.0, 4.50, 5.0, 6.0, 7.0, 8.0}, ""}; ConfigurableAxis binsPtZHe{"binsPtZHe", {VARIABLE_WIDTH, 0.5, 0.625, 0.75, 0.875, 1.0, 1.125, 1.25, 1.375, 1.5, 1.625, 1.75, 1.875, 2.0, 2.25, 2.5, 3.0, 3.5, 4.0}, ""}; + ConfigurableAxis binsPtHeMigration{"binsPtHeMigration", {VARIABLE_WIDTH, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.10, 2.20, 2.30, 2.40, 2.50, 2.60, 2.70, 2.80, 2.90, 3.00, 3.25, 3.50, 3.75, 4.00, 4.50, 5.00, 6.00, 7.00, 8.00}, ""}; ConfigurableAxis binsdEdx{"binsdEdx", {600, 0.f, 3000.f}, ""}; ConfigurableAxis binsBeta{"binsBeta", {120, 0.0, 1.2}, ""}; @@ -339,6 +340,7 @@ struct lfNucleiBATask { const AxisSpec ptHeAxis{binsPtHe, "#it{p}_{T} (GeV/#it{c})"}; const AxisSpec pZAxis{binsPt, "#it{p}/z (GeV/#it{c})"}; const AxisSpec ptZHeAxis{binsPtZHe, "#it{p}_{T}/z (GeV/#it{c})"}; + const AxisSpec ptHeMigrAxis{binsPtHeMigration, "#it{p}_{T} (GeV/#it{c})"}; const AxisSpec dedxAxis{binsdEdx, "d#it{E}/d#it{x} A.U."}; const AxisSpec betaAxis{binsBeta, "TOF #beta"}; const AxisSpec dcaxyAxis{binsDCA, "DCAxy (cm)"}; @@ -445,6 +447,32 @@ struct lfNucleiBATask { histoGen.add("events/hNRecoCollPerMCColl_INEL", "Reco collisions per MC collision;N_{reco coll};Counts", HistType::kTH1D, {{6, -0.5, 5.5}}); histoGen.add("events/hNRecoCollPerMCColl_INELgt0", "Reco INEL>0 collisions per MC collision;N_{reco coll};Counts", HistType::kTH1D, {{6, -0.5, 5.5}}); + // Protons + histoGen.add("proton/MCGen/h2ProtonYvsPt", "#it{y} vs #it{p}_{T} (p)", HistType::kTH2F, {{96, -1.2, 1.2}, {800, 0, 8}}); + histoGen.add("proton/MCGen/h2antiProtonYvsPt", "#it{y} vs #it{p}_{T} (p)", HistType::kTH2F, {{96, -1.2, 1.2}, {800, 0, 8}}); + + histoGen.add("proton/MCGen/ptGen_INEL_Prim_P", "generated particles", HistType::kTH1F, {{800, 0, 8}}); + histoGen.add("proton/MCGen/ptGen_INEL_Prim_antiP", "generated particles", HistType::kTH1F, {{800, 0, 8}}); + + histoGen.add("proton/MCGen/ptGen_INELgt0_Prim_P", "generated particles", HistType::kTH1F, {{800, 0, 8}}); + histoGen.add("proton/MCGen/ptGen_INELgt0_Prim_antiP", "generated particles", HistType::kTH1F, {{800, 0, 8}}); + + histoGen.add("proton/MCGenReco/h2ProtonYvsPt", "#it{y} vs #it{p}_{T} (p)", HistType::kTH2F, {{96, -1.2, 1.2}, {800, 0, 8}}); + histoGen.add("proton/MCGenReco/h2antiProtonYvsPt", "#it{y} vs #it{p}_{T} (p)", HistType::kTH2F, {{96, -1.2, 1.2}, {800, 0, 8}}); + + histoGen.add("proton/MCGenReco/ptGen_INEL_Prim_P", "generated particles", HistType::kTH1F, {{800, 0, 8}}); + histoGen.add("proton/MCGenReco/ptGen_INEL_Prim_antiP", "generated particles", HistType::kTH1F, {{800, 0, 8}}); + + histoGen.add("proton/MCGenReco/ptGen_INELgt0_Prim_P", "generated particles", HistType::kTH1F, {{800, 0, 8}}); + histoGen.add("proton/MCGenReco/ptGen_INELgt0_Prim_antiP", "generated particles", HistType::kTH1F, {{800, 0, 8}}); + + histoGen.add("proton/MCReco/ptGen_INEL_Prim_P", "generated particles", HistType::kTH1F, {{800, 0, 8}}); + histoGen.add("proton/MCReco/ptGen_INEL_Prim_antiP", "generated particles", HistType::kTH1F, {{800, 0, 8}}); + + histoGen.add("proton/MCReco/ptGen_INELgt0_Prim_P", "generated particles", HistType::kTH1F, {{800, 0, 8}}); + histoGen.add("proton/MCReco/ptGen_INELgt0_Prim_antiP", "generated particles", HistType::kTH1F, {{800, 0, 8}}); + + // Helium histoGen.add("helium/MCGen/h2HeliumYvsPt", "#it{y} vs #it{p}_{T} (He)", HistType::kTH2F, {{96, -1.2, 1.2}, {ptHeAxis}}); histoGen.add("helium/MCGen/h2antiHeliumYvsPt", "#it{y} vs #it{p}_{T} (He)", HistType::kTH2F, {{96, -1.2, 1.2}, {ptHeAxis}}); @@ -487,6 +515,23 @@ struct lfNucleiBATask { histoGen.add("events/hNRecoCollPerMCCollVsMult_INEL", "Reco collisions per MC collision vs FT0M;N_{reco coll};FT0M percentile", HistType::kTH2D, {{6, -0.5, 5.5}, {binsPercentile}}); histoGen.add("events/hNRecoCollPerMCCollVsMult_INELgt0", "Reco INEL>0 collisions per MC collision vs FT0M;N_{reco coll};FT0M percentile", HistType::kTH2D, {{6, -0.5, 5.5}, {binsPercentile}}); + // Protons + histoGen.add("proton/MCGen/ptGenVsMult_INEL_Prim_P", "generated particles", HistType::kTH2F, {{800, 0, 8}, {binsPercentile}}); + histoGen.add("proton/MCGen/ptGenVsMult_INEL_Prim_antiP", "generated particles", HistType::kTH2F, {{800, 0, 8}, {binsPercentile}}); + histoGen.add("proton/MCGen/ptGenVsMult_INELgt0_Prim_P", "generated particles", HistType::kTH2F, {{800, 0, 8}, {binsPercentile}}); + histoGen.add("proton/MCGen/ptGenVsMult_INELgt0_Prim_antiP", "generated particles", HistType::kTH2F, {{800, 0, 8}, {binsPercentile}}); + + histoGen.add("proton/MCGenReco/ptGenVsMult_INEL_Prim_P", "generated particles", HistType::kTH2F, {{800, 0, 8}, {binsPercentile}}); + histoGen.add("proton/MCGenReco/ptGenVsMult_INEL_Prim_antiP", "generated particles", HistType::kTH2F, {{800, 0, 8}, {binsPercentile}}); + histoGen.add("proton/MCGenReco/ptGenVsMult_INELgt0_Prim_P", "generated particles", HistType::kTH2F, {{800, 0, 8}, {binsPercentile}}); + histoGen.add("proton/MCGenReco/ptGenVsMult_INELgt0_Prim_antiP", "generated particles", HistType::kTH2F, {{800, 0, 8}, {binsPercentile}}); + + histoGen.add("proton/MCReco/ptGenVsMult_INEL_Prim_P", "generated particles", HistType::kTH2F, {{800, 0, 8}, {binsPercentile}}); + histoGen.add("proton/MCReco/ptGenVsMult_INEL_Prim_antiP", "generated particles", HistType::kTH2F, {{800, 0, 8}, {binsPercentile}}); + histoGen.add("proton/MCReco/ptGenVsMult_INELgt0_Prim_P", "generated particles", HistType::kTH2F, {{800, 0, 8}, {binsPercentile}}); + histoGen.add("proton/MCReco/ptGenVsMult_INELgt0_Prim_antiP", "generated particles", HistType::kTH2F, {{800, 0, 8}, {binsPercentile}}); + + // Helium histoGen.add("helium/MCGen/ptGenVsMult_INEL_Prim_He", "generated particles", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); histoGen.add("helium/MCGen/ptGenVsMult_INEL_Prim_antiHe", "generated particles", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); histoGen.add("helium/MCGen/ptGenVsMult_INELgt0_Prim_He", "generated particles", HistType::kTH2F, {{ptHeAxis}, {binsPercentile}}); @@ -577,9 +622,9 @@ struct lfNucleiBATask { if (enableDebug) { histos.add("qa/h1ITSncr", "number of crossed rows in ITS; ITSncr; counts", HistType::kTH1F, {{12, 0, 12}}); - histos.add("qa/h1TPCncr", "number of crossed rows in TPC; TPCncr; counts", HistType::kTH1F, {{150, 60, 170}}); - histos.add("qa/h1rTPC", "ratio of ncr over findable in TPC; rTPC; counts", HistType::kTH1F, {{200, 0.9, 1.8}}); - histos.add("qa/h1TPCnfound", "ratio of found cluster in TPC; TPCnfound; counts", HistType::kTH1F, {{150, 60, 170}}); + histos.add("qa/h1TPCncr", "number of crossed rows in TPC; TPCncr; counts", HistType::kTH1F, {{110, 60, 170}}); + histos.add("qa/h1rTPC", "ratio of ncr over findable in TPC; rTPC; counts", HistType::kTH1F, {{300, 0.45, 1.8}}); + histos.add("qa/h1TPCnfound", "ratio of found cluster in TPC; TPCnfound; counts", HistType::kTH1F, {{110, 60, 170}}); histos.add("qa/h1chi2ITS", "#chi^{2}_{ITS}/n_{ITS}; #chi^{2}_{ITS}/n_{ITS};counts", HistType::kTH1F, {{51, -0.5, 50.5}}); histos.add("qa/h1chi2TPC", "#chi^{2}_{TPC}/n_{TPC}; #chi^{2}_{TPC}/n_{TPC}; counts", HistType::kTH1F, {{11, -0.5, 10.5}}); } @@ -885,6 +930,16 @@ struct lfNucleiBATask { histos.get(HIST("tracks/hItsDeHeChecker"))->GetXaxis()->SetBinLabel(3, "keptDe"); histos.get(HIST("tracks/hItsDeHeChecker"))->GetXaxis()->SetBinLabel(4, "keptHe"); + if (enableDebug) { + debugHistos.add("tracks/helium/migration/h2PtGenVsPtRecoPrimHe", "Primary ^{3}He;#it{p}_{T}^{gen} (GeV/#it{c});#it{p}_{T}^{reco} (GeV/#it{c})", HistType::kTH2F, {{ptHeMigrAxis}, {ptHeMigrAxis}}); + + debugHistos.add("tracks/helium/migration/h2PtGenVsPtRecoPrimAntiHe", "Primary ^{3}#bar{He};#it{p}_{T}^{gen} (GeV/#it{c});#it{p}_{T}^{reco} (GeV/#it{c})", HistType::kTH2F, {{ptHeMigrAxis}, {ptHeMigrAxis}}); + + debugHistos.add("tracks/helium/migration/TOF/h2PtGenVsPtRecoPrimHe", "Primary ^{3}He, TOF;#it{p}_{T}^{gen} (GeV/#it{c});#it{p}_{T}^{reco} (GeV/#it{c})", HistType::kTH2F, {{ptHeMigrAxis}, {ptHeMigrAxis}}); + + debugHistos.add("tracks/helium/migration/TOF/h2PtGenVsPtRecoPrimAntiHe", "Primary ^{3}#bar{He}, TOF;#it{p}_{T}^{gen} (GeV/#it{c});#it{p}_{T}^{reco} (GeV/#it{c})", HistType::kTH2F, {{ptHeMigrAxis}, {ptHeMigrAxis}}); + } + // inclusive production if (enableTrackingEff) { debugHistos.add("tracks/trackingEff/h1_its", "#it{p}_{T} (p)", HistType::kTH1F, {ptAxis}); @@ -4716,7 +4771,7 @@ struct lfNucleiBATask { if (isHeWoTPCpid) { if (outFlagOptions.enableExpSignalTPC) histos.fill(HIST("tracks/helium/h2HeliumTPCExpSignalDiffVsPt"), hePt, track.tpcExpSignalDiffHe()); - histos.fill(HIST("tracks/helium/h2HeliumVspTNSigmaITSHe"), track.p(), nITSHe); + histos.fill(HIST("tracks/helium/h2HeliumVspTNSigmaITSHe"), heP, nITSHe); histos.fill(HIST("tracks/helium/h2HeliumVspTNSigmaTPC"), hePt, track.tpcNSigmaHe()); if (enableDebug && enableHe) debugHistos.fill(HIST("tracks/helium/h2HeCutFlowVsPt"), 2.f * hePt, 7); @@ -4726,7 +4781,7 @@ struct lfNucleiBATask { if (isAntiHeWoTPCpid) { if (outFlagOptions.enableExpSignalTPC) histos.fill(HIST("tracks/helium/h2antiHeliumTPCExpSignalDiffVsPt"), antihePt, track.tpcExpSignalDiffHe()); - histos.fill(HIST("tracks/helium/h2antiHeliumVspTNSigmaITSHe"), track.p(), nITSHe); + histos.fill(HIST("tracks/helium/h2antiHeliumVspTNSigmaITSHe"), antiheP, nITSHe); histos.fill(HIST("tracks/helium/h2antiHeliumVspTNSigmaTPC"), antihePt, track.tpcNSigmaHe()); if (enableDebug) debugHistos.fill(HIST("tracks/helium/h2antiHeCutFlowVsPt"), 2.f * antihePt, 7); @@ -4734,16 +4789,16 @@ struct lfNucleiBATask { histos.fill(HIST("tracks/helium/h3antiHeliumVspTNSigmaTPCVsMult"), antihePt, track.tpcNSigmaHe(), centFT0M); } if (isHeWTPCpid) { - histos.fill(HIST("tracks/helium/h2HeliumVspTNSigmaITSHe_wTPCpid"), track.p(), nITSHe); + histos.fill(HIST("tracks/helium/h2HeliumVspTNSigmaITSHe_wTPCpid"), heP, nITSHe); } if (isAntiHeWTPCpid) { - histos.fill(HIST("tracks/helium/h2antiHeliumVspTNSigmaITSHe_wTPCpid"), track.p(), nITSHe); + histos.fill(HIST("tracks/helium/h2antiHeliumVspTNSigmaITSHe_wTPCpid"), antiheP, nITSHe); } if constexpr (!IsFilteredData) { if (isHeWTPCpid || isAntiHeWTPCpid) { if (nsigmaITSvar.showAverageClusterSize) { - histos.fill(HIST("tracks/helium/averageClusterSize"), track.p(), averageClusterSizeTrk(track)); - histos.fill(HIST("tracks/helium/averageClusterSizePerCoslInv"), track.p(), averageClusterSizePerCoslInv(track)); + histos.fill(HIST("tracks/helium/averageClusterSize"), heP, averageClusterSizeTrk(track)); + histos.fill(HIST("tracks/helium/averageClusterSizePerCoslInv"), antiheP, averageClusterSizePerCoslInv(track)); } } } @@ -6007,6 +6062,14 @@ struct lfNucleiBATask { } } if (isPhysPrim) { + if constexpr (!IsFilteredData) { + if (enableDebug) { + debugHistos.fill(HIST("tracks/helium/migration/h2PtGenVsPtRecoPrimHe"), track.mcParticle().pt(), 2.f * hePt); + if (passHeTPCpid && hasTOFplots) { + debugHistos.fill(HIST("tracks/helium/migration/TOF/h2PtGenVsPtRecoPrimHe"), track.mcParticle().pt(), 2.f * hePt); + } + } + } histos.fill(HIST("tracks/helium/h1HeliumSpectraTruePrim_Z2"), 2 * hePt); if (enableCentrality) { histos.fill(HIST("tracks/helium/h2HeliumSpectraTruePrimVsMult_Z2"), 2 * hePt, centFT0M); @@ -6086,6 +6149,14 @@ struct lfNucleiBATask { } } if (isPhysPrim) { + if constexpr (!IsFilteredData) { + if (enableDebug) { + debugHistos.fill(HIST("tracks/helium/migration/h2PtGenVsPtRecoPrimAntiHe"), track.mcParticle().pt(), 2.f * antihePt); + if (passHeTPCpid && hasTOFplots) { + debugHistos.fill(HIST("tracks/helium/migration/TOF/h2PtGenVsPtRecoPrimAntiHe"), track.mcParticle().pt(), 2.f * antihePt); + } + } + } histos.fill(HIST("tracks/helium/h1antiHeliumSpectraTruePrim_Z2"), 2 * antihePt); if (enableCentrality) { histos.fill(HIST("tracks/helium/h2antiHeliumSpectraTruePrimVsMult_Z2"), 2 * antihePt, centFT0M); @@ -6919,6 +6990,7 @@ struct lfNucleiBATask { float pt = mcParticle.pt(); bool isPhysPrim = mcParticle.isPhysicalPrimary(); + // Helium if (enableHe && isPhysPrim && (std::abs(pdg) == PDGHelium)) { if (pdg > 0) { histoGen.fill(HIST("helium/MCGen/h2HeliumYvsPt"), mcParticle.y(), pt); @@ -6944,6 +7016,32 @@ struct lfNucleiBATask { } } } + + // Proton + if (enablePr && isPhysPrim && (std::abs(pdg) == PDGProton)) { + if (pdg > 0) { + histoGen.fill(HIST("proton/MCGen/h2ProtonYvsPt"), mcParticle.y(), pt); + histoGen.fill(HIST("proton/MCGen/ptGen_INEL_Prim_P"), pt); + if (enableCentrality) + histoGen.fill(HIST("proton/MCGen/ptGenVsMult_INEL_Prim_P"), pt, mcCollision.centFT0M()); + } else { + histoGen.fill(HIST("proton/MCGen/h2antiProtonYvsPt"), mcParticle.y(), pt); + histoGen.fill(HIST("proton/MCGen/ptGen_INEL_Prim_antiP"), pt); + if (enableCentrality) + histoGen.fill(HIST("proton/MCGen/ptGenVsMult_INEL_Prim_antiP"), pt, mcCollision.centFT0M()); + } + if (isINELgt0true) { + if (pdg > 0) { + histoGen.fill(HIST("proton/MCGen/ptGen_INELgt0_Prim_P"), pt); + if (enableCentrality) + histoGen.fill(HIST("proton/MCGen/ptGenVsMult_INELgt0_Prim_P"), pt, mcCollision.centFT0M()); + } else { + histoGen.fill(HIST("proton/MCGen/ptGen_INELgt0_Prim_antiP"), pt); + if (enableCentrality) + histoGen.fill(HIST("proton/MCGen/ptGenVsMult_INELgt0_Prim_antiP"), pt, mcCollision.centFT0M()); + } + } + } } int recoIdxINEL = 0; @@ -6957,6 +7055,8 @@ struct lfNucleiBATask { bool hasNoTFB = collision.selection_bit(aod::evsel::kNoTimeFrameBorder); bool hasNoItsRofFB = collision.selection_bit(aod::evsel::kNoITSROFrameBorder); + bool thisCollisionINELgt0 = false; + histoGen.fill(HIST("events/hMCReco"), 0.5); if (enableCentrality) histoGen.fill(HIST("events/hMCRecoVsMult"), 0.5, mcCollision.centFT0M()); @@ -6984,6 +7084,8 @@ struct lfNucleiBATask { atLeastOneINEL = true; if (collision.isInelGt0() && isINELgt0true) { + thisCollisionINELgt0 = true; + // EVENT SPLITTING DENOMINATOR histoGen.fill(HIST("events/hMCReco"), 2.5); if (enableCentrality) @@ -7012,7 +7114,7 @@ struct lfNucleiBATask { histoGen.fill(HIST("helium/MCReco/ptGenVsMult_INEL_Prim_antiHe"), pt, mcCollision.centFT0M()); } - if (atLeastOneINELgt0) { + if (thisCollisionINELgt0) { if (pdg > 0) { histoGen.fill(HIST("helium/MCReco/ptGen_INELgt0_Prim_He"), pt); if (enableCentrality) @@ -7024,6 +7126,30 @@ struct lfNucleiBATask { } } } + + if (enablePr && isPhysPrim && (std::abs(pdg) == PDGProton)) { + if (pdg > 0) { + histoGen.fill(HIST("proton/MCReco/ptGen_INEL_Prim_P"), pt); + if (enableCentrality) + histoGen.fill(HIST("proton/MCReco/ptGenVsMult_INEL_Prim_P"), pt, mcCollision.centFT0M()); + } else { + histoGen.fill(HIST("proton/MCReco/ptGen_INEL_Prim_antiP"), pt); + if (enableCentrality) + histoGen.fill(HIST("proton/MCReco/ptGenVsMult_INEL_Prim_antiP"), pt, mcCollision.centFT0M()); + } + + if (thisCollisionINELgt0) { + if (pdg > 0) { + histoGen.fill(HIST("proton/MCReco/ptGen_INELgt0_Prim_P"), pt); + if (enableCentrality) + histoGen.fill(HIST("proton/MCReco/ptGenVsMult_INELgt0_Prim_P"), pt, mcCollision.centFT0M()); + } else { + histoGen.fill(HIST("proton/MCReco/ptGen_INELgt0_Prim_antiP"), pt); + if (enableCentrality) + histoGen.fill(HIST("proton/MCReco/ptGenVsMult_INELgt0_Prim_antiP"), pt, mcCollision.centFT0M()); + } + } + } } } @@ -7082,6 +7208,32 @@ struct lfNucleiBATask { } } } + + if (enablePr && isPhysPrim && (std::abs(pdg) == PDGProton)) { + if (pdg > 0) { + histoGen.fill(HIST("proton/MCGenReco/h2ProtonYvsPt"), mcParticle.y(), pt); + histoGen.fill(HIST("proton/MCGenReco/ptGen_INEL_Prim_P"), pt); + if (enableCentrality) + histoGen.fill(HIST("proton/MCGenReco/ptGenVsMult_INEL_Prim_P"), pt, mcCollision.centFT0M()); + } else { + histoGen.fill(HIST("proton/MCGenReco/h2antiProtonYvsPt"), mcParticle.y(), pt); + histoGen.fill(HIST("proton/MCGenReco/ptGen_INEL_Prim_antiP"), pt); + if (enableCentrality) + histoGen.fill(HIST("proton/MCGenReco/ptGenVsMult_INEL_Prim_antiP"), pt, mcCollision.centFT0M()); + } + + if (atLeastOneINELgt0) { + if (pdg > 0) { + histoGen.fill(HIST("proton/MCGenReco/ptGen_INELgt0_Prim_P"), pt); + if (enableCentrality) + histoGen.fill(HIST("proton/MCGenReco/ptGenVsMult_INELgt0_Prim_P"), pt, mcCollision.centFT0M()); + } else { + histoGen.fill(HIST("proton/MCGenReco/ptGen_INELgt0_Prim_antiP"), pt); + if (enableCentrality) + histoGen.fill(HIST("proton/MCGenReco/ptGenVsMult_INELgt0_Prim_antiP"), pt, mcCollision.centFT0M()); + } + } + } } } PROCESS_SWITCH(lfNucleiBATask, processMCGenLosses, "process MCGen losses", false); diff --git a/PWGLF/Tasks/Nuspex/multiplicityPt.cxx b/PWGLF/Tasks/Nuspex/multiplicityPt.cxx index d0daca29368..a78aca0e336 100644 --- a/PWGLF/Tasks/Nuspex/multiplicityPt.cxx +++ b/PWGLF/Tasks/Nuspex/multiplicityPt.cxx @@ -13,47 +13,46 @@ /// \file multiplicityPt.cxx /// \brief Analysis to do PID with MC - Full correction factors for pions, kaons, protons -#include "PWGLF/DataModel/LFParticleIdentification.h" #include "PWGLF/DataModel/mcCentrality.h" -#include "PWGLF/DataModel/spectraTOF.h" #include "PWGLF/Utils/inelGt.h" -#include "Common/Core/RecoDecay.h" +#include "Common/CCDB/EventSelectionParams.h" #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" -#include "Common/DataModel/McCollisionExtra.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" #include #include -#include #include -#include #include +#include #include +#include #include +#include +#include #include #include +#include #include -#include #include +#include +#include #include #include +#include -#include #include #include -#include +#include #include -#include -#include #include +#include #include using namespace o2; diff --git a/PWGLF/Tasks/Nuspex/nucleiEbye.cxx b/PWGLF/Tasks/Nuspex/nucleiEbye.cxx index f970a270906..df645514aba 100644 --- a/PWGLF/Tasks/Nuspex/nucleiEbye.cxx +++ b/PWGLF/Tasks/Nuspex/nucleiEbye.cxx @@ -189,7 +189,7 @@ struct nucleiEbye { return true; } - void fillHistoN(std::shared_ptr hFull, std::shared_ptr const& hTmp, int const subsample, int const centrality) + void fillHistoN(const std::shared_ptr& hFull, std::shared_ptr const& hTmp, int const subsample, int const centrality) { for (int iEta{1}; iEta < hTmp->GetNbinsX() + 1; ++iEta) { for (int iPt{1}; iPt < hTmp->GetNbinsY() + 1; ++iPt) { @@ -202,7 +202,7 @@ struct nucleiEbye { } } - void fillHistoN(std::shared_ptr hFull, std::shared_ptr const& hTmpA, std::shared_ptr const& hTmpB, int const subsample, int const centrality) + void fillHistoN(const std::shared_ptr& hFull, std::shared_ptr const& hTmpA, std::shared_ptr const& hTmpB, int const subsample, int const centrality) { for (int iEta{1}; iEta < hTmpA->GetNbinsX() + 1; ++iEta) { auto eta = hTmpA->GetXaxis()->GetBinCenter(iEta); diff --git a/PWGLF/Tasks/Nuspex/nuclei_in_toward_transv_regions.cxx b/PWGLF/Tasks/Nuspex/nuclei_in_toward_transv_regions.cxx index d00f320dbdc..8756a1b46e4 100644 --- a/PWGLF/Tasks/Nuspex/nuclei_in_toward_transv_regions.cxx +++ b/PWGLF/Tasks/Nuspex/nuclei_in_toward_transv_regions.cxx @@ -236,7 +236,7 @@ struct nuclei_in_toward_transv_regions { int i = -1; // Loop over Reconstructed Tracks - for (auto track : tracks) { + for (const auto& track : tracks) { i++; if (!passedTrackSelectionForJetReconstruction(track)) @@ -256,7 +256,7 @@ struct nuclei_in_toward_transv_regions { auto const& leading_track = tracks.iteratorAt(leading_ID); // Loop over Reconstructed Tracks - for (auto track : tracks) { + for (const auto& track : tracks) { // Track Selection if (!passedTrackSelection(track)) @@ -319,7 +319,7 @@ struct nuclei_in_toward_transv_regions { int i = -1; // Loop over Reconstructed Tracks - for (auto track : tracks_per_coll) { + for (const auto& track : tracks_per_coll) { i++; if (!passedTrackSelectionForJetReconstruction(track)) @@ -338,7 +338,7 @@ struct nuclei_in_toward_transv_regions { auto const& leading_track = tracks_per_coll.iteratorAt(leading_ID); // Loop over Reconstructed Tracks - for (auto track : tracks_per_coll) { + for (const auto& track : tracks_per_coll) { if (!passedTrackSelection(track)) continue; diff --git a/PWGLF/Tasks/Nuspex/nucleitpcPbPb.cxx b/PWGLF/Tasks/Nuspex/nucleitpcPbPb.cxx index 87799179ec4..1658ffb009e 100644 --- a/PWGLF/Tasks/Nuspex/nucleitpcPbPb.cxx +++ b/PWGLF/Tasks/Nuspex/nucleitpcPbPb.cxx @@ -22,6 +22,7 @@ #include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponseITS.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" @@ -70,7 +71,7 @@ using namespace o2::framework::expressions; using CollisionsFull = soa::Join; using TracksFull = soa::Join; using CollisionsFullMC = soa::Join; - +using McCollisionMults = soa::Join; //=================================================================================== // Static configuration tables (species definitions, PID/quality defaults, and // track/DCA correction parameters). None of the values below are changed by @@ -187,6 +188,7 @@ struct NucleitpcPbPb { // ---- Track selection configurables ------------------------------------ Configurable cfgUsePVcontributors{"cfgUsePVcontributors", true, "use tracks that are PV contibutors"}; Configurable cfgPassedITSRefit{"cfgPassedITSRefit", true, "Require ITS refit"}; + Configurable occupancycutrequire{"occupancycutrequire", true, "Require occupancy cut"}; Configurable cfgPassedTPCRefit{"cfgPassedTPCRefit", true, "Require TPC refit"}; Configurable cfgetaRequire{"cfgetaRequire", true, "eta cut require"}; Configurable cfgetaRequireMC{"cfgetaRequireMC", true, "eta cut require for generated particles"}; @@ -197,6 +199,7 @@ struct NucleitpcPbPb { Configurable cfgCutRapiditymax{"cfgCutRapiditymax", 0.5f, "max Rapidity range"}; Configurable cfgtpcNClsFindable{"cfgtpcNClsFindable", 0.8f, "tpcNClsFindable over crossedRows"}; Configurable centcut{"centcut", 80.0f, "centrality cut"}; + Configurable occupancycut{"occupancycut", 1000.0f, "occupancy cut"}; Configurable cfgZvertexRequireMC{"cfgZvertexRequireMC", true, "Pos Z cut in MC"}; // ---- Track quality-cut configurables ----------------------------------- @@ -219,6 +222,7 @@ struct NucleitpcPbPb { // ---- MC-only configurables ----------------------------------------------- Configurable cfgmccorrectionhe4Require{"cfgmccorrectionhe4Require", true, "MC correction for pp he4 particle"}; + Configurable cfgUseEvtSelInNumer{"cfgUseEvtSelInNumer", true, "Event-/signal-loss numerator: require the reco vertex to pass the event selection (true) or merely to exist (false)"}; // ---- DCA cut configurables ------------------------------------------------- Configurable cfgUseDCAxyCorrection{"cfgUseDCAxyCorrection", true, "Use pT-dependent DCAxy cut"}; @@ -259,6 +263,9 @@ struct NucleitpcPbPb { ConfigurableAxis axisDCA{"axisDCA", {400, -10., 10.}, "DCA axis"}; ConfigurableAxis particleAntiAxis{"particleAntiAxis", {2, -0.5, 1.5}, "Particle/Anti-particle"}; // 0 = particle, 1 = anti-particle ConfigurableAxis decayTypeAxis{"decayTypeAxis", {3, -0.5, 2.5}, "Decay type"}; // 0 = primary, 1 = from decay, 2 = material + ConfigurableAxis axisMultMC{"axisMultMC", {500, 0., 5000.}, "N_{ch}^{gen} in |#eta| < 0.5"}; + ConfigurableAxis speciesAxis{"speciesAxis", {NParticles, -0.5, NParticles - 0.5}, "species index"}; + ConfigurableAxis axisImpactPar{"axisImpactPar", {200, 0., 20.}, "impact parameter #it{b} (fm)"}; // ---- CCDB ------------------------------------------------------------------- Service ccdb; @@ -340,23 +347,105 @@ struct NucleitpcPbPb { histos.add("Tpcsignal", "Tpcsignal", kTH2F, {axisRigidity, axisdEdx}); if (doprocessMC) { - histomc.add("hSpectramc", " ", HistType::kTHnSparseF, {particleAntiAxis, axisCent, ptAxis, ptAxis}); + histomc.add("hSpectramc", " ", HistType::kTHnSparseF, {particleAntiAxis, speciesAxis, axisCent, ptAxis, ptAxis}); // Efficiency x Acceptance histomc.add("hDenomEffAcc", "Denominator for Efficiency x Acceptance", - {HistType::kTHnSparseF, {ptAxis, axisCent, particleAntiAxis, decayTypeAxis}}); + {HistType::kTHnSparseF, {ptAxis, axisCent, speciesAxis, particleAntiAxis, decayTypeAxis}}); histomc.add("hNumerEffAcc", "Numerator for Efficiency x Acceptance", - {HistType::kTHnSparseF, {ptAxis, axisCent, particleAntiAxis, decayTypeAxis}}); - - // Signal loss correction - histomc.add("hSignalLossDenom", "Signal Loss Denominator", kTH2F, {axisCent, ptAxis}); - histomc.add("hSignalLossNumer", "Signal Loss Numerator", kTH2F, {axisCent, ptAxis}); - histomc.add("haSignalLossDenom", "anti particle Signal Loss Denominator", kTH2F, {axisCent, ptAxis}); - histomc.add("haSignalLossNumer", "antiparticle Signal Loss Numerator", kTH2F, {axisCent, ptAxis}); - - // Event loss correction - histomc.add("hEventLossDenom", "Event loss denominator", kTH1F, {axisCent}); - histomc.add("hEventLossNumer", "Event loss numerator", kTH1F, {axisCent}); + {HistType::kTHnSparseF, {ptAxis, axisCent, speciesAxis, particleAntiAxis, decayTypeAxis}}); + + // ---- Event loss, multiplicity method ------------------------------------- + histomc.add("hEventLossDenomVsMult", + "All generated events;N_{ch}^{gen} (|#eta|<0.5)", + kTH1F, + {axisMultMC}); + + histomc.add("hEventLossNumerVsMult", + "Generated events with a selected reco vertex;N_{ch}^{gen} (|#eta|<0.5)", + kTH1F, + {axisMultMC}); + + // ---- Event loss, impact-parameter method --------------------------------- + histomc.add("hEventLossDenomVsImpactPar", + "All generated events;#it{b} (fm)", + kTH1F, + {axisImpactPar}); + + histomc.add("hEventLossNumerVsImpactPar", + "Generated events with a selected reco vertex;#it{b} (fm)", + kTH1F, + {axisImpactPar}); + + // ---- Event splitting, Eq. (14) of the analysis note ----------------------- + // splitting = hEventSplittingNgenWithRecoVsCent / hEventSplittingNrecoPassedVsCent + histomc.add("hEventSplittingNgenWithRecoVsCent", + "N_{gen. evt}^{#geq 1 reco evt passed evtsel};centrality (%)", + kTH1F, + {axisCent}); + + histomc.add("hEventSplittingNrecoPassedVsCent", + "N_{reco evt passed evtsel};centrality (%)", + kTH1F, + {axisCent}); + + // ---- Signal loss, multiplicity method: mult vs pT vs species -------------- + histomc.add("hSignalLossDenomVsMult", + ";N_{ch}^{gen};#it{p}_{T} (GeV/#it{c});species", + kTH3F, + {axisMultMC, ptAxis, speciesAxis}); + + histomc.add("hSignalLossNumerVsMult", + ";N_{ch}^{gen};#it{p}_{T} (GeV/#it{c});species", + kTH3F, + {axisMultMC, ptAxis, speciesAxis}); + + histomc.add("haSignalLossDenomVsMult", + ";N_{ch}^{gen};#it{p}_{T} (GeV/#it{c});species", + kTH3F, + {axisMultMC, ptAxis, speciesAxis}); + + histomc.add("haSignalLossNumerVsMult", + ";N_{ch}^{gen};#it{p}_{T} (GeV/#it{c});species", + kTH3F, + {axisMultMC, ptAxis, speciesAxis}); + + // ---- Signal loss, impact-parameter method: b vs pT vs species ------------- + histomc.add("hSignalLossDenomVsImpactPar", + ";#it{b} (fm);#it{p}_{T} (GeV/#it{c});species", + kTH3F, + {axisImpactPar, ptAxis, speciesAxis}); + + histomc.add("hSignalLossNumerVsImpactPar", + ";#it{b} (fm);#it{p}_{T} (GeV/#it{c});species", + kTH3F, + {axisImpactPar, ptAxis, speciesAxis}); + + histomc.add("haSignalLossDenomVsImpactPar", + ";#it{b} (fm);#it{p}_{T} (GeV/#it{c});species", + kTH3F, + {axisImpactPar, ptAxis, speciesAxis}); + + histomc.add("haSignalLossNumerVsImpactPar", + ";#it{b} (fm);#it{p}_{T} (GeV/#it{c});species", + kTH3F, + {axisImpactPar, ptAxis, speciesAxis}); + + // ---- Maps from the generated quantities to centrality --------------------- + histomc.add("hCentralityVsGenMultEta05", + "FT0C centrality vs generated multiplicity;centrality (%);N_{ch}^{gen} (|#eta|<0.5)", + kTH2F, + {axisCent, axisMultMC}); + + histomc.add("hCentralityVsImpactParameter", + "FT0C centrality vs impact parameter;centrality (%);#it{b} (fm)", + kTH2F, + {axisCent, axisImpactPar}); + + histomc.add("hImpactParameter", + "Impact parameter of generated MC events;#it{b} (fm)", + kTH1F, + {axisImpactPar}); histomc.add("histVtxZgen", "histVtxZgen", kTH1F, {axisVtxZ}); histomc.add("histVtxZReco", "histVtxZReco", kTH1F, {axisVtxZ}); @@ -424,6 +513,9 @@ struct NucleitpcPbPb { if (collision.centFT0C() > centcut) continue; histos.fill(HIST("histNev"), 6.5); + if (occupancycutrequire && (occupancy > occupancycut)) + continue; + histos.fill(HIST("histNev"), 7.5); histos.fill(HIST("histCentFTOC_cut"), collision.centFT0C()); auto tracksInColl = tracks.sliceBy(tracksPerCollision, collision.globalIndex()); @@ -532,17 +624,36 @@ struct NucleitpcPbPb { PROCESS_SWITCH(NucleitpcPbPb, processData, "data analysis", false); //==================================================================================== - // processMC: MC reco+gen, for efficiency x acceptance, signal-loss and event-loss + // processMC: MC reco+gen, for efficiency x acceptance, signal-loss, event-loss and + // event-splitting corrections. + // + // Two event classes, used consistently everywhere: + // truth class = generated collisions passing the generated |z| cut + // selected class = truth class + >= 1 reco vertex passing evtsel and reco |z| cut + // + // event loss = numer / denom, binned in multMCNParticlesEta05 (multiplicity + // method) and in the impact parameter (impact-parameter method) + // event splitting = N_gen(>=1 selected reco) / N_reco(passed evtsel), Eq. (14) + // signal loss = generated primaries of the selected class over the truth class + // + // Everything per-species sits inside a fillsparsh loop, as in processData; event + // loss and event splitting are species independent. //==================================================================================== struct McCollInfo { - bool passedEvSel = false; - float centrality = -1.0f; - bool passedEvSelVtZ = false; + bool hasRecoCollision = false; // >= 1 reco vertex, before any selection + bool passedEvSel = false; // >= 1 reco vertex passing event selection + bool passedEvSelVtZ = false; // ... and passing the reco |z| cut + bool genVtxZok = false; // generated |z| inside the cut + float centrality = -1.0f; // FT0C of the highest-numContrib selected vertex + float mult = -1.0f; // multMCNParticlesEta05 + float impactPar = -1.0f; // generated impact parameter (fm) + int bestCollisionId = -1; // globalIndex of that vertex (split-vertex safe) + int biggestNContribs = -1; }; std::vector mcCollInfos; void processMC(CollisionsFullMC const& collisions, - aod::McCollisions const& mcCollisions, + McCollisionMults const& mcCollisions, soa::Join const& tracks, aod::McParticles const& particlesMC, aod::BCsWithTimestamps const&) @@ -550,19 +661,43 @@ struct NucleitpcPbPb { mcCollInfos.clear(); mcCollInfos.resize(mcCollisions.size()); - // ---- Pass 1: store centrality and event-selection flags per MC collision ---- + //-------------------------------------------------------------------------------- + // PASS 1: generated collisions. Generated multiplicity, impact parameter and the + // generated |z| cut. Runs first so genVtxZok is available to every later pass, + // including the splitting numerator which is filled per reconstructed vertex. + //-------------------------------------------------------------------------------- + for (auto const& mcCollision : mcCollisions) { + size_t idx = mcCollision.globalIndex(); + if (idx >= mcCollInfos.size()) + continue; + + auto& info = mcCollInfos[idx]; + info.mult = static_cast(mcCollision.multMCNParticlesEta05()); + info.impactPar = mcCollision.impactParameter(); + + histomc.fill(HIST("histVtxZgen"), mcCollision.posZ()); + + if (cfgZvertexRequireMC && std::abs(mcCollision.posZ()) > cfgZvertex) + continue; + info.genVtxZok = true; + } + + //-------------------------------------------------------------------------------- + // PASS 2: reco -> MC association. Flags are only ever raised, so several reco + // vertices pointing at the same MC collision collapse correctly instead of the + // last one overwriting the earlier ones. The reco |z| cut is applied + // unconditionally, as in processData. + //-------------------------------------------------------------------------------- for (auto const& collision : collisions) { int mcCollIdx = collision.mcCollisionId(); - if (mcCollIdx < 0 || mcCollIdx >= static_cast(mcCollisions.size())) { + if (mcCollIdx < 0 || mcCollIdx >= static_cast(mcCollInfos.size())) continue; - } - mcCollInfos[mcCollIdx].centrality = collision.centFT0C(); // stored without cuts + auto& info = mcCollInfos[mcCollIdx]; + info.hasRecoCollision = true; if (!collision.sel8() && cfgsel8Require) continue; - if (collision.centFT0C() > centcut) - continue; if (removeNoSameBunchPileup && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) continue; if (requireIsGoodZvtxFT0vsPV && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) @@ -572,199 +707,245 @@ struct NucleitpcPbPb { if (removeNoTimeFrameBorder && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) continue; - mcCollInfos[mcCollIdx].passedEvSel = true; + info.passedEvSel = true; - if (std::abs(collision.posZ()) > cfgZvertex && cfgZvertexRequireMC) + if (std::abs(collision.posZ()) > cfgZvertex) continue; - mcCollInfos[mcCollIdx].passedEvSelVtZ = true; - } + info.passedEvSelVtZ = true; - // ---- Event-loss and signal-loss denominators/numerators ---- - for (size_t i = 0; i < mcCollInfos.size(); i++) { - if (mcCollInfos[i].centrality < 0) - continue; // no matching reconstructed collision found + // Splitting numerator: every selected reco vertex, inside the truth class only. + if (info.genVtxZok) { + histomc.fill(HIST("hEventSplittingNrecoPassedVsCent"), collision.centFT0C()); + } - histomc.fill(HIST("hEventLossDenom"), mcCollInfos[i].centrality); - if (mcCollInfos[i].passedEvSel) { - histomc.fill(HIST("hEventLossNumer"), mcCollInfos[i].centrality); + if (collision.numContrib() > info.biggestNContribs) { + info.biggestNContribs = collision.numContrib(); + info.centrality = collision.centFT0C(); + info.bestCollisionId = collision.globalIndex(); } + } - for (auto const& mcParticle : particlesMC) { - if (mcParticle.mcCollisionId() != static_cast(i)) - continue; - if (!mcParticle.isPhysicalPrimary()) - continue; + //-------------------------------------------------------------------------------- + // PASS 3: event level. Species independent -- no fillsparsh loop here. + // Event loss in both methods, splitting denominator, and the two maps used to + // express the generated-quantity-binned corrections as a function of centrality. + //-------------------------------------------------------------------------------- + for (auto const& mcCollision : mcCollisions) { + size_t idx = mcCollision.globalIndex(); + if (idx >= mcCollInfos.size()) + continue; - int particleType = findParticleTypeIndex(mcParticle.pdgCode()); - if (!speciesEnabled(particleType)) - continue; + auto const& info = mcCollInfos[idx]; + if (!info.genVtxZok) + continue; - if (mcParticle.pdgCode() == particlePdgCodes.at(particleType)) { - histomc.fill(HIST("hSignalLossDenom"), mcCollInfos[i].centrality, mcParticle.pt()); - } else if (mcParticle.pdgCode() == -particlePdgCodes.at(particleType)) { - histomc.fill(HIST("haSignalLossDenom"), mcCollInfos[i].centrality, mcParticle.pt()); - } + bool numerOk = cfgUseEvtSelInNumer ? info.passedEvSelVtZ : info.hasRecoCollision; - if (mcCollInfos[i].passedEvSel) { - if (mcParticle.pdgCode() == particlePdgCodes.at(particleType)) { - histomc.fill(HIST("hSignalLossNumer"), mcCollInfos[i].centrality, mcParticle.pt()); - } else if (mcParticle.pdgCode() == -particlePdgCodes.at(particleType)) { - histomc.fill(HIST("haSignalLossNumer"), mcCollInfos[i].centrality, mcParticle.pt()); - } - } + histomc.fill(HIST("hImpactParameter"), info.impactPar); + + // Event loss: the denominator is every generated event of the truth class, + // including those with no reconstructed vertex at all -- that population is + // exactly what is being corrected for. + histomc.fill(HIST("hEventLossDenomVsMult"), info.mult); + histomc.fill(HIST("hEventLossDenomVsImpactPar"), info.impactPar); + if (numerOk) { + histomc.fill(HIST("hEventLossNumerVsMult"), info.mult); + histomc.fill(HIST("hEventLossNumerVsImpactPar"), info.impactPar); + } + + if (info.passedEvSelVtZ) { + // Splitting denominator: generated events with >= 1 selected reco vertex. + histomc.fill(HIST("hEventSplittingNgenWithRecoVsCent"), info.centrality); + histomc.fill(HIST("hCentralityVsGenMultEta05"), info.centrality, info.mult); + histomc.fill(HIST("hCentralityVsImpactParameter"), info.centrality, info.impactPar); } } - // ---- Generated particles: efficiency x acceptance denominator, and reco pass ---- - for (auto const& mcCollision : mcCollisions) { - size_t idx = mcCollision.globalIndex(); - if (idx >= mcCollInfos.size()) + //-------------------------------------------------------------------------------- + // PASS 4: generated particles. Per-species, gated on fillsparsh exactly like + // processData. Signal loss (rapidity only, following the analysis note) and the + // efficiency x acceptance denominator. + //-------------------------------------------------------------------------------- + for (auto const& mcParticle : particlesMC) { + int mcCollIdx = mcParticle.mcCollisionId(); + if (mcCollIdx < 0 || mcCollIdx >= static_cast(mcCollInfos.size())) continue; - float centrality = mcCollInfos[idx].centrality; - bool passedEvSelVtZ = mcCollInfos[idx].passedEvSelVtZ; + auto const& info = mcCollInfos[mcCollIdx]; + if (!info.genVtxZok) + continue; - histomc.fill(HIST("histVtxZgen"), mcCollision.posZ()); + bool numerOk = cfgUseEvtSelInNumer ? info.passedEvSelVtZ : info.hasRecoCollision; - for (auto const& mcParticle : particlesMC) { - if (mcParticle.mcCollisionId() != mcCollision.globalIndex()) - continue; + int pdgCode = mcParticle.pdgCode(); + int particleAnti = (pdgCode > 0) ? 0 : 1; - int pdgCode = mcParticle.pdgCode(); - int particleType = findParticleTypeIndex(pdgCode); - if (!speciesEnabled(particleType)) + for (size_t i = 0; i < primaryParticles.size(); i++) { + if (cfgTrackPIDsettings2->get(i, "fillsparsh") != 1) continue; - - if (std::abs(mcParticle.eta()) > cfgCutEta && cfgetaRequireMC) + if (std::abs(pdgCode) != std::abs(particlePdgCodes.at(i))) continue; + float rapidity = mcParticle.y(); if ((rapidity < cfgCutRapiditymin || rapidity > cfgCutRapiditymax) && cfgRapidityRequireMC) continue; - int particleAnti = (pdgCode > 0) ? 0 : 1; + float pt = mcParticle.pt(); + float fSpecies = static_cast(i); + + // ---- Signal loss: physical primaries only. Denominator = truth class, + // numerator = selected class. Same particle, same cuts, same iteration. + if (mcParticle.isPhysicalPrimary()) { + if (pdgCode > 0) { + histomc.fill(HIST("hSignalLossDenomVsMult"), info.mult, pt, fSpecies); + histomc.fill(HIST("hSignalLossDenomVsImpactPar"), info.impactPar, pt, fSpecies); + if (numerOk) { + histomc.fill(HIST("hSignalLossNumerVsMult"), info.mult, pt, fSpecies); + histomc.fill(HIST("hSignalLossNumerVsImpactPar"), info.impactPar, pt, fSpecies); + } + } else { + histomc.fill(HIST("haSignalLossDenomVsMult"), info.mult, pt, fSpecies); + histomc.fill(HIST("haSignalLossDenomVsImpactPar"), info.impactPar, pt, fSpecies); + if (numerOk) { + histomc.fill(HIST("haSignalLossNumerVsMult"), info.mult, pt, fSpecies); + histomc.fill(HIST("haSignalLossNumerVsImpactPar"), info.impactPar, pt, fSpecies); + } + } + } + + if (!info.passedEvSelVtZ) + continue; + if (std::abs(mcParticle.eta()) > cfgCutEta && cfgetaRequireMC) + continue; int decayType = classifyDecayType(mcParticle); if (decayType == DecayTypeTransport) - continue; // transported secondaries are not part of the denominator - - if (passedEvSelVtZ) { - histomc.fill(HIST("hDenomEffAcc"), mcParticle.pt(), centrality, particleAnti, decayType); - } - } + continue; + histomc.fill(HIST("hDenomEffAcc"), pt, info.centrality, fSpecies, particleAnti, decayType); + } // species loop + } // generated particle loop + + //-------------------------------------------------------------------------------- + // PASS 5: reconstructed tracks. Only the highest-numContrib selected vertex of + // each generated collision is used, so split vertices are not counted twice. + //-------------------------------------------------------------------------------- + for (auto const& collision : collisions) { + int mcCollIdx = collision.mcCollisionId(); + if (mcCollIdx < 0 || mcCollIdx >= static_cast(mcCollInfos.size())) + continue; - if (!passedEvSelVtZ) + auto const& info = mcCollInfos[mcCollIdx]; + if (!info.genVtxZok) + continue; + if (collision.globalIndex() != info.bestCollisionId) continue; - // ---- Find the reconstructed collision matching this MC collision ---- - for (auto const& collision : collisions) { - if (collision.mcCollisionId() != static_cast(idx)) - continue; + auto bc = collision.bc_as(); + initCCDB(bc); + histomc.fill(HIST("histVtxZReco"), collision.posZ()); - auto bc = collision.bc_as(); - initCCDB(bc); - histomc.fill(HIST("histVtxZReco"), collision.posZ()); + auto tracksInColl = tracks.sliceBy(tracksPerCollision, collision.globalIndex()); + for (auto const& track : tracksInColl) { + if (!track.has_mcParticle()) + continue; // skip un-matched reco tracks - auto tracksInColl = tracks.sliceBy(tracksPerCollision, collision.globalIndex()); - for (auto const& track : tracksInColl) { - if (!track.has_mcParticle()) - continue; // skip un-matched reco tracks + auto const& matchedMCParticle = track.mcParticle_as(); + if (matchedMCParticle.mcCollisionId() != mcCollIdx) + continue; - auto const& matchedMCParticle = track.mcParticle_as(); - if (matchedMCParticle.mcCollisionId() != mcCollision.globalIndex()) - continue; + int pdg = matchedMCParticle.pdgCode(); + int decayType = classifyDecayType(matchedMCParticle); - int pdg = matchedMCParticle.pdgCode(); - int decayType = classifyDecayType(matchedMCParticle); + if (!passesBasicRecoTrackCuts(track)) + continue; - if (!passesBasicRecoTrackCuts(track)) + for (size_t i = 0; i < primaryParticles.size(); i++) { + if (cfgTrackPIDsettings2->get(i, "fillsparsh") != 1) + continue; + if (std::abs(pdg) != std::abs(particlePdgCodes.at(i))) continue; - for (size_t i = 0; i < primaryParticles.size(); i++) { - if (std::abs(pdg) != std::abs(particlePdgCodes.at(i))) - continue; - if (cfgTrackPIDsettings2->get(i, "fillsparsh") != 1) - continue; - - float ptReco = computeSpeciesPt(track, i); - ptReco = applyHe34PtCorrection(track, pdg, i, ptReco); + float ptReco = computeSpeciesPt(track, i); + ptReco = applyHe34PtCorrection(track, pdg, i, ptReco); - int particleAnti = (pdg > 0) ? 0 : 1; + int particleAnti = (pdg > 0) ? 0 : 1; + float fSpecies = static_cast(i); - float rapidity = getRapidity(track, i); - if ((rapidity < cfgCutRapiditymin || rapidity > cfgCutRapiditymax) && cfgRapidityRequire) - continue; + float rapidity = getRapidity(track, i); + if ((rapidity < cfgCutRapiditymin || rapidity > cfgCutRapiditymax) && cfgRapidityRequire) + continue; - if (!passesTrackQualityCuts(track, i)) - continue; - if (!passesDCACuts(track, i, ptReco)) - continue; + if (!passesTrackQualityCuts(track, i)) + continue; + if (!passesDCACuts(track, i, ptReco)) + continue; - float tpcNsigma = getTPCnSigma(track, primaryParticles.at(i)); - bool passesNsigma = !((std::abs(tpcNsigma) > cfgTrackPIDsettings->get(i, "maxTPCnSigma")) && cfgmaxTPCnSigmaRequire); - - // Single fill per track: axis 2 (pTReco) always gets the reco pT, - // with all cuts applied except TPC nsigma and hasTOF -- this is - // the denominator population for the TOF matching efficiency. - // Axis 3 (pTOF) gets the same pT value only for tracks that both - // pass the TPC nsigma cut and have TOF -- the numerator - // population -- otherwise it gets a sentinel (-1, landing in the - // pTOF axis underflow bin since ptAxis starts at 0) so it's - // excluded from any real-pT projection of that axis. Filling - // once (not twice) avoids double-counting TOF-matched tracks in - // the pTReco axis relative to non-matched tracks. - bool isTOFmatched = passesNsigma && track.hasTOF(); - float ptTOF = isTOFmatched ? ptReco : -1.0f; - histomc.fill(HIST("hSpectramc"), particleAnti, collision.centFT0C(), ptReco, ptTOF); - - if (!passesNsigma) - continue; + float tpcNsigma = getTPCnSigma(track, primaryParticles.at(i)); + bool passesNsigma = !((std::abs(tpcNsigma) > cfgTrackPIDsettings->get(i, "maxTPCnSigma")) && cfgmaxTPCnSigmaRequire); + + // Single fill per track: axis pTReco always gets the reco pT, with all + // cuts applied except TPC nsigma and hasTOF -- this is the denominator + // population for the TOF matching efficiency. Axis pTOF gets the same pT + // value only for tracks that both pass the TPC nsigma cut and have TOF -- + // the numerator population -- otherwise it gets a sentinel (-1, landing + // in the pTOF axis underflow bin since ptAxis starts at 0) so it's + // excluded from any real-pT projection of that axis. Filling once (not + // twice) avoids double-counting TOF-matched tracks in the pTReco axis + // relative to non-matched tracks. + bool isTOFmatched = passesNsigma && track.hasTOF(); + float ptTOF = isTOFmatched ? ptReco : -1.0f; + histomc.fill(HIST("hSpectramc"), particleAnti, fSpecies, collision.centFT0C(), ptReco, ptTOF); + + if (!passesNsigma) + continue; - // Efficiency x Acceptance numerator (only after the TPC nsigma cut). - histomc.fill(HIST("hNumerEffAcc"), ptReco, collision.centFT0C(), particleAnti, decayType); + // Efficiency x Acceptance numerator. Same transport veto as the + // denominator, otherwise the ratio mixes two different populations. + if (decayType == DecayTypeTransport) + continue; + histomc.fill(HIST("hNumerEffAcc"), ptReco, collision.centFT0C(), fSpecies, particleAnti, decayType); - if (decayType == DecayTypePrimary) { - histos.fill(HIST("dcaXY"), ptReco, track.dcaXY()); - histos.fill(HIST("dcaZ"), ptReco, track.dcaZ()); - histos.fill(HIST("Tpcsignal"), getRigidity(track) * track.sign(), track.tpcSignal()); - } + if (decayType == DecayTypePrimary) { + histos.fill(HIST("dcaXY"), ptReco, track.dcaXY()); + histos.fill(HIST("dcaZ"), ptReco, track.dcaZ()); + histos.fill(HIST("Tpcsignal"), getRigidity(track) * track.sign(), track.tpcSignal()); + } - float ptGen = matchedMCParticle.pt(); - float deltaPt = ptReco - ptGen; - if (pdg == -particlePdgCodes.at(i) && decayType == DecayTypePrimary) { // anti-particle - histomc.fill(HIST("histDeltaPtVsPtGenanti"), ptReco, deltaPt); - histomc.fill(HIST("histPIDtrackanti"), ptReco, track.pidForTracking()); - } - if (pdg == particlePdgCodes.at(i) && decayType == DecayTypePrimary) { // particle - histomc.fill(HIST("histDeltaPtVsPtGen"), ptReco, deltaPt); - histomc.fill(HIST("histPIDtrack"), ptReco, track.pidForTracking()); - } + float ptGen = matchedMCParticle.pt(); + float deltaPt = ptReco - ptGen; + if (pdg == -particlePdgCodes.at(i) && decayType == DecayTypePrimary) { // anti-particle + histomc.fill(HIST("histDeltaPtVsPtGenanti"), ptReco, deltaPt); + histomc.fill(HIST("histPIDtrackanti"), ptReco, track.pidForTracking()); + } + if (pdg == particlePdgCodes.at(i) && decayType == DecayTypePrimary) { // particle + histomc.fill(HIST("histDeltaPtVsPtGen"), ptReco, deltaPt); + histomc.fill(HIST("histPIDtrack"), ptReco, track.pidForTracking()); + } - // Mass^2/z^2 for MC, split by particle/anti-particle. - if (track.hasTOF()) { - float beta = o2::pid::tof::Beta::GetBeta(track); - const float eps = 1e-6f; - if (beta >= eps && beta <= 1.0f - eps) { - float charge = (i == he3 || i == he4) ? 2.f : 1.f; - float p = getRigidity(track); - float massTOF = p * charge * std::sqrt(1.f / (beta * beta) - 1.f); - float massSquareOverChargeSquare = (massTOF * massTOF) / (charge * charge); - - bool skipHe4 = (std::abs(pdg) == particlePdgCodes.at(5)) && cfghe3massrejreq && - (massTOF * massTOF > cfgminmassrejection && massTOF * massTOF < cfgmaxmassrejection); - - if (!skipHe4 && decayType == DecayTypePrimary) { - if (pdg > 0) { - histomc.fill(HIST("hMassVsPtMC"), ptReco, massSquareOverChargeSquare, collision.centFT0C()); - } else { - histomc.fill(HIST("hMassVsPtAntiMC"), ptReco, massSquareOverChargeSquare, collision.centFT0C()); - } + // Mass^2/z^2 for MC, split by particle/anti-particle. + if (track.hasTOF()) { + float beta = o2::pid::tof::Beta::GetBeta(track); + const float eps = 1e-6f; + if (beta >= eps && beta <= 1.0f - eps) { + float charge = (i == he3 || i == he4) ? 2.f : 1.f; + float p = getRigidity(track); + float massTOF = p * charge * std::sqrt(1.f / (beta * beta) - 1.f); + float massSquareOverChargeSquare = (massTOF * massTOF) / (charge * charge); + + bool skipHe4 = (std::abs(pdg) == particlePdgCodes.at(5)) && cfghe3massrejreq && + (massTOF * massTOF > cfgminmassrejection && massTOF * massTOF < cfgmaxmassrejection); + + if (!skipHe4 && decayType == DecayTypePrimary) { + if (pdg > 0) { + histomc.fill(HIST("hMassVsPtMC"), ptReco, massSquareOverChargeSquare, collision.centFT0C()); + } else { + histomc.fill(HIST("hMassVsPtAntiMC"), ptReco, massSquareOverChargeSquare, collision.centFT0C()); } } } - } // species loop - } // track loop - break; // matching reconstructed collision found and processed - } // collision loop - } // mcCollision loop + } + } // species loop + } // track loop + } // collision loop } PROCESS_SWITCH(NucleitpcPbPb, processMC, "MC reco+gen analysis with efficiency corrections", false); diff --git a/PWGLF/Tasks/Nuspex/pccQa.cxx b/PWGLF/Tasks/Nuspex/pccQa.cxx index bb481652550..fe04b0ffc4e 100644 --- a/PWGLF/Tasks/Nuspex/pccQa.cxx +++ b/PWGLF/Tasks/Nuspex/pccQa.cxx @@ -31,6 +31,7 @@ #include +#include #include using namespace o2; @@ -43,6 +44,8 @@ struct PccQa { static constexpr float MaxVtxZ = 10.f; + Configurable maxMult{"maxMult", 100, "max multiplicity"}; + void init(InitContext const&); template @@ -69,23 +72,45 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) void PccQa::init(InitContext const&) { + histos.add("eventCounter", "", kTH1D, {{1, 0.5, 1.5}}); const AxisSpec dcaAxis = {1000, -1., 1., "#it{DCA}_{xy}", "dca"}; std::vector ptBinEdges = {0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.5, 3.0}; const AxisSpec ptAxis{ptBinEdges, "#it{p}_{T} (GeV/#it{c})", "pt"}; + const int nBinsMult = 30; + const AxisSpec nchAxis = {nBinsMult, 0., static_cast(maxMult), "#it{N}_{ch}", "nch"}; + histos.add("DCAxyVsPt", "", kTH2D, {ptAxis, dcaAxis}); + histos.add("DCAxyVsPtVsMult", "", kTH3D, {nchAxis, ptAxis, dcaAxis}); if (doprocessMC) { histos.add("DCAxyVsPt_weighted", "", kTH2D, {ptAxis, dcaAxis}); + histos.add("DCAxyVsPtVsMult_weighted", "", kTH3D, {nchAxis, ptAxis, dcaAxis}); + histos.add("prim/DCAxyVsPt", "", kTH2D, {ptAxis, dcaAxis}); + histos.add("prim/DCAxyVsPtVsMult", "", kTH3D, {nchAxis, ptAxis, dcaAxis}); + + histos.add("prim/DCAxyVsPtVsMult_weighted", "", kTH3D, {nchAxis, ptAxis, dcaAxis}); histos.add("prim/DCAxyVsPt_weighted", "", kTH2D, {ptAxis, dcaAxis}); + histos.add("sec/DCAxyVsPt", "", kTH2D, {ptAxis, dcaAxis}); + histos.add("sec/DCAxyVsPtVsMult", "", kTH3D, {nchAxis, ptAxis, dcaAxis}); + histos.add("sec/DCAxyVsPt_weighted", "", kTH2D, {ptAxis, dcaAxis}); + histos.add("sec/DCAxyVsPtVsMult_weighted", "", kTH3D, {nchAxis, ptAxis, dcaAxis}); + histos.add("sec/dec/DCAxyVsPt", "", kTH2D, {ptAxis, dcaAxis}); + histos.add("sec/dec/DCAxyVsPtVsMult", "", kTH3D, {nchAxis, ptAxis, dcaAxis}); + histos.add("sec/dec/DCAxyVsPt_weighted", "", kTH2D, {ptAxis, dcaAxis}); + histos.add("sec/dec/DCAxyVsPtVsMult_weighted", "", kTH3D, {nchAxis, ptAxis, dcaAxis}); + histos.add("sec/mat/DCAxyVsPt", "", kTH2D, {ptAxis, dcaAxis}); + histos.add("sec/mat/DCAxyVsPtVsMult", "", kTH3D, {nchAxis, ptAxis, dcaAxis}); + histos.add("sec/mat/DCAxyVsPt_weighted", "", kTH2D, {ptAxis, dcaAxis}); + histos.add("sec/mat/DCAxyVsPtVsMult_weighted", "", kTH3D, {nchAxis, ptAxis, dcaAxis}); } } @@ -95,6 +120,7 @@ void PccQa::processData(CollisionTableData::iterator const& collision, TrackTabl } void PccQa::processMC(CollisionTableMCTrue::iterator const&, TrackTableMC const& tracks, CollisionTableMC const& collisions, ParticleTableMC const&) { + for (const auto& collision : collisions) { auto curTracks = tracks.sliceBy(perCollision, collision.globalIndex()); processMeas(collision, curTracks); @@ -105,6 +131,7 @@ void PccQa::processMC(CollisionTableMCTrue::iterator const&, TrackTableMC const& template void PccQa::processMeas(const C& collision, const T& tracks) { + if ((std::abs(collision.posZ()) > MaxVtxZ) || !collision.sel8()) { return; } @@ -115,6 +142,7 @@ void PccQa::processMeas(const C& collision, const T& tracks) continue; } histos.fill(HIST("DCAxyVsPt"), track.pt(), track.dcaXY()); + histos.fill(HIST("DCAxyVsPtVsMult"), tracks.size(), track.pt(), track.dcaXY()); if constexpr (IS_MC) { if (!track.has_mcParticle()) { @@ -123,19 +151,28 @@ void PccQa::processMeas(const C& collision, const T& tracks) const auto& particle = track.template mcParticle_as(); histos.fill(HIST("DCAxyVsPt_weighted"), track.pt(), track.dcaXY(), particle.pccWeight()); + histos.fill(HIST("DCAxyVsPtVsMult_weighted"), tracks.size(), track.pt(), track.dcaXY(), particle.pccWeight()); if (particle.isPhysicalPrimary()) { histos.fill(HIST("prim/DCAxyVsPt"), track.pt(), track.dcaXY()); histos.fill(HIST("prim/DCAxyVsPt_weighted"), track.pt(), track.dcaXY(), particle.pccWeight()); + histos.fill(HIST("prim/DCAxyVsPtVsMult"), tracks.size(), track.pt(), track.dcaXY()); + histos.fill(HIST("prim/DCAxyVsPtVsMult_weighted"), tracks.size(), track.pt(), track.dcaXY(), particle.pccWeight()); } else { histos.fill(HIST("sec/DCAxyVsPt"), track.pt(), track.dcaXY()); histos.fill(HIST("sec/DCAxyVsPt_weighted"), track.pt(), track.dcaXY(), particle.pccWeight()); + histos.fill(HIST("sec/DCAxyVsPtVsMult"), tracks.size(), track.pt(), track.dcaXY()); + histos.fill(HIST("sec/DCAxyVsPtVsMult_weighted"), tracks.size(), track.pt(), track.dcaXY(), particle.pccWeight()); if (particle.getProcess() == TMCProcess::kPDecay) { histos.fill(HIST("sec/dec/DCAxyVsPt"), track.pt(), track.dcaXY()); histos.fill(HIST("sec/dec/DCAxyVsPt_weighted"), track.pt(), track.dcaXY(), particle.pccWeight()); + histos.fill(HIST("sec/dec/DCAxyVsPtVsMult"), tracks.size(), track.pt(), track.dcaXY()); + histos.fill(HIST("sec/dec/DCAxyVsPtVsMult_weighted"), tracks.size(), track.pt(), track.dcaXY(), particle.pccWeight()); } else if (particle.getProcess() == TMCProcess::kPHInhelastic || particle.getProcess() == TMCProcess::kPHadronic || particle.getProcess() == TMCProcess::kPHElastic) { histos.fill(HIST("sec/mat/DCAxyVsPt"), track.pt(), track.dcaXY()); histos.fill(HIST("sec/mat/DCAxyVsPt_weighted"), track.pt(), track.dcaXY(), particle.pccWeight()); + histos.fill(HIST("sec/mat/DCAxyVsPtVsMult"), tracks.size(), track.pt(), track.dcaXY()); + histos.fill(HIST("sec/mat/DCAxyVsPtVsMult_weighted"), tracks.size(), track.pt(), track.dcaXY(), particle.pccWeight()); } } } diff --git a/PWGLF/Tasks/Nuspex/piKpRAA.cxx b/PWGLF/Tasks/Nuspex/piKpRAA.cxx index 4ce6a377592..03f52ce8c5d 100644 --- a/PWGLF/Tasks/Nuspex/piKpRAA.cxx +++ b/PWGLF/Tasks/Nuspex/piKpRAA.cxx @@ -500,8 +500,8 @@ struct PiKpRAA { } if (doprocessSim) { - registry.add("EventCounterMC", ";;Events", kTH1F, {{5, 0, 5}}); - registry.add("zPosMC", "From the association between the MC event & the Rec. Coll with largest number of PV contributors & NO Evy. Sel.;;Entries;", kTH1F, {axisZpos}); + registry.add("EventCounterMC", "From 2nd bin, corresponds to number of MC Coll with associated Rec Coll.;;Events", kTH1F, {{5, 0, 5}}); + registry.add("zPosMC", "From the association between the MC event & the Rec. Coll with largest number of PV contributors & NO Evt. Sel.;;Entries;", kTH1F, {axisZpos}); registry.add("zPosMCAll", "All MC Events;;Entries;", kTH1F, {axisZpos}); registry.add("EtaMCParAllMCColl", "#eta from all MC particles in all MC collisions;#eta;Entries;", kTH1F, {{50, -10.0, 10.0}}); registry.add("EtaMCParAllMCColl_Pion", "#eta from all MC particles in all MC collisions;#eta;Entries;", kTH1F, {{50, -10.0, 10.0}}); @@ -519,7 +519,7 @@ struct PiKpRAA { registry.add("CentralityVsBCVsFT0VsTVXVsEvSel", "All=1 | BC=2 | FT0=3 | TVX=4 | EvSel=5;;Status;", kTH2F, {{axisCent}, {5, 0.5, 5.5}}); registry.add("NumOfRecColl", "Num. of times a MC evt. is reconstructed;N;Entries", kTH1F, {{5, -0.5, 4.5}}); registry.add("NumOfRecCollVsNContri", "Num. of times a MC evt. is reconstructed VS Num. of PV contributors;Number of times a MC event is reconstructed;Number of tracks used for the PV", kTH2F, {{5, -0.5, 4.5}, axisNch}); - registry.add("NumOfRecCollVsNContriWithEvtSel", "Num. of times a MC evt. is reconstructed VS Num. of PV contributors WITH EVT SEL;Number of times a MC event is reconstructed;Number of tracks used for the PV", kTH2F, {{5, -0.5, 4.5}, axisNch}); + // registry.add("NumOfRecCollVsNContriWithEvtSel", "Num. of times a MC evt. is reconstructed VS Num. of PV contributors WITH EVT SEL;Number of times a MC event is reconstructed;Number of tracks used for the PV", kTH2F, {{5, -0.5, 4.5}, axisNch}); // Pt resolution registry.add("PtResolution", "p_{T} resolution;;(pt_{rec} - pt_{gen})/pt_{gen};", kTH2F, {axisPt, {100, -1.0, 1.0}}); @@ -542,13 +542,13 @@ struct PiKpRAA { registry.add("NchMCVsCent", "Generated Nch v.s. Centrality (At least Once Rec. Coll. + Sel. criteria);;Gen. Nch MC", kTH2F, {axisCent, axisNch}); // Needed to measure Event Loss - registry.add("NchMC_WithRecoEvt", "Gen Nch from MC event associated with the Rec. Coll (with largest Num. of contributors) + Evt. Sel.;Gen Nch MC;Entries", kTH1F, {axisNch}); - registry.add("NchMC_AllGen", "Gen Nch of ALL MC events;Gen. Nch;Entries", kTH1F, {axisNch}); - registry.add("NchMC_WithRecColl", "Gen Nch from MC event associated with a Rec. Coll (at least once);Gen. Nch;Entries", kTH1F, {axisNch}); - registry.add("NchMC_WithOnlyRecColl", "Gen Nch from MC event associated with a ONLY ONE Rec. Coll from last Num. of Contributors;Gen. Nch;Entries", kTH1F, {axisNch}); + registry.add("NchMC_WithRecoEvt", "MC Nch from the event associated with the Rec. Coll. (with largest Num. of PV contributors) + Evt. Sel.;Gen Nch MC;Entries", kTH1F, {axisNch}); + registry.add("NchMC_AllGen", "MC Nch of ALL events;Gen. Nch;Entries", kTH1F, {axisNch}); + registry.add("NchMC_WithRecColl", "MC Nch from the event associated with at least one Rec. Coll.;Gen. Nch;Entries", kTH1F, {axisNch}); + registry.add("NchMC_BestCollIdx", "MC Nch from the event associated with ONLY ONE Rec. Coll. with largest Num. of PV contributors;Gen. Nch;Entries", kTH1F, {axisNch}); // Needed to measure Event Splitting - registry.add("Centrality_WRecoEvt", "From the association between the MC event & the Rec. Coll with largest number of PV contributors & NO Evt. Sel.;;Entries", kTH1F, {axisCent}); + // registry.add("Centrality_WRecoEvt", "From the association between the MC event & the Rec. Coll with largest number of PV contributors & NO Evt. Sel.;;Entries", kTH1F, {axisCent}); registry.add("Centrality_WRecoEvtWSelCri", "From the association between the MC event & the Rec. Coll with largest number of PV contributors + Evt. Sel.;;Entries", kTH1F, {axisCent}); registry.add("Centrality_AllRecoEvt", "All Rec. Coll. Irrespective of the times it was reconstructed + Evt. Sel.;;Entries", kTH1F, {axisCent}); @@ -573,9 +573,121 @@ struct PiKpRAA { auto hMcCouter = registry.get(HIST("EventCounterMC")); auto* xMcCounter = hMcCouter->GetXaxis(); xMcCounter->SetBinLabel(1, "All MC Coll"); - xMcCounter->SetBinLabel(2, "Rec Coll with nContributors > 0"); - xMcCounter->SetBinLabel(3, "Rec Coll With largest nContributors"); - xMcCounter->SetBinLabel(4, "Rec TVX-triggered Coll"); + xMcCounter->SetBinLabel(2, "Rec Coll w/ nContributors > 0"); + xMcCounter->SetBinLabel(3, "Rec Coll W/ nContributors > 0 + HasFT0"); + xMcCounter->SetBinLabel(4, "Rec Coll W/ nContributors > 0 + HasFT0 + HasTVX"); + } + + if (doprocessSignalLoss) { + registry.add("EventCounterMC", "From 2nd bin, corresponds to number of MC Coll with associated Rec Coll.;;Events", kTH1F, {{5, 0, 5}}); + registry.add("zPosMC", "From the association between the MC event & the Rec. Coll with largest number of PV contributors & NO Evy. Sel.;;Entries;", kTH1F, {axisZpos}); + registry.add("zPosMCAll", "All MC Events;;Entries;", kTH1F, {axisZpos}); + registry.add("EtaMCParAllMCColl", "#eta from all MC particles in all MC collisions;#eta;Entries;", kTH1F, {{50, -10.0, 10.0}}); + registry.add("EtaMCParAllMCColl_Pion", "#eta from all MC particles in all MC collisions;#eta;Entries;", kTH1F, {{50, -10.0, 10.0}}); + registry.add("EtaMCParAllMCColl_Kaon", "#eta from all MC particles in all MC collisions;#eta;Entries;", kTH1F, {{50, -10.0, 10.0}}); + registry.add("EtaMCParAllMCColl_Proton", "#eta from all MC particles in all MC collisions;#eta;Entries;", kTH1F, {{50, -10.0, 10.0}}); + registry.add("EtaMCParAllMCColl_Electron", "#eta from all MC particles in all MC collisions;#eta;Entries;", kTH1F, {{50, -10.0, 10.0}}); + registry.add("EtaMCParAllMCColl_Rest", "#eta from all MC particles in all MC collisions;#eta;Entries;", kTH1F, {{50, -10.0, 10.0}}); + registry.add("dcaVsPtPiDec", "Secondary pions from decays;#it{p}_{T} (GeV/#it{c});DCA_{xy} (cm);Centrality Perc.;", kTH3F, {axisPt, axisDCAxy, axisCent}); + registry.add("dcaVsPtPrDec", "Secondary protons from decays;#it{p}_{T} (GeV/#it{c});DCA_{xy} (cm);Centrality Perc.;", kTH3F, {axisPt, axisDCAxy, axisCent}); + registry.add("dcaVsPtPiMat", "Secondary pions from material interactions;#it{p}_{T} (GeV/#it{c});DCA_{xy} (cm);Centrality Perc.;", kTH3F, {axisPt, axisDCAxy, axisCent}); + registry.add("dcaVsPtPrMat", "Secondary protons from material interactions;#it{p}_{T} (GeV/#it{c});DCA_{xy} (cm);Centrality Perc.;", kTH3F, {axisPt, axisDCAxy, axisCent}); + registry.add("DCAxyVsPtWithSelection", ";#it{p}_{T} (GeV/#it{c});DCA_{xy} (cm);", kTH2F, {{axisPtFineFixedWidth}, {axisDCAxy}}); + registry.add("DCAzVsPtWithSelection", ";#it{p}_{T} (GeV/#it{c});DCA_{z} (cm);", kTH2F, {{axisPtFineFixedWidth}, {axisDCAxy}}); + + registry.add("NumOfRecColl", "Num. of times a MC evt. is reconstructed;N;Entries", kTH1F, {{5, -0.5, 4.5}}); + registry.add("NumOfRecCollVsNContri", "Num. of times a MC evt. is reconstructed VS Num. of PV contributors;Number of times a MC event is reconstructed;Number of tracks used for the PV", kTH2F, {{8, -0.5, 7.5}, axisNch}); + registry.add("NumOfRecCollVsCentrality", "Num. of times a MC evt. is reconstructed VS Centrality WITH EVT SEL;Number of times a MC event is reconstructed;Number of tracks used for the PV", kTH2F, {{8, -0.5, 7.5}, axisCent}); + + // PT RESOLUTION + registry.add("PtResolution", "p_{T} resolution;;(pt_{rec} - pt_{gen})/pt_{gen};", kTH2F, {axisPt, {100, -1.0, 1.0}}); + + // NUMERATOR OF THE ACCEPTANCE X EFFICIENCY + registry.add("PtPiVsCent_WithRecoEvt", "Generated Events With at least One Rec. Collision + Sel. criteria;;;", kTH2F, {axisPt, axisCent}); + registry.add("PtKaVsCent_WithRecoEvt", "Generated Events With at least One Rec. Collision + Sel. criteria;;;", kTH2F, {axisPt, axisCent}); + registry.add("PtPrVsCent_WithRecoEvt", "Generated Events With at least One Rec. Collision + Sel. criteria;;;", kTH2F, {axisPt, axisCent}); + + // DENOMINATOR OF THE ACCEPTANCE X EFFICIENCY (TRUE PT) + registry.add("PtGenPiVsCent_WithRecoEvt", "Generated Events With at least One Rec. Collision + Sel. criteria;;;", kTH2F, {axisPt, axisCent}); + registry.add("PtGenKaVsCent_WithRecoEvt", "Generated Events With at least One Rec. Collision + Sel. criteria;;;", kTH2F, {axisPt, axisCent}); + registry.add("PtGenPrVsCent_WithRecoEvt", "Generated Events With at least One Rec. Collision + Sel. criteria;;;", kTH2F, {axisPt, axisCent}); + + // DENOMINATOR OF THE ACCEPTANCE X EFFICIENCY + registry.add("PtPiVsCentMC_WithRecoEvt", "Generated Events With at least One Rec. Collision;;;", kTH2F, {axisPt, axisCent}); + registry.add("PtKaVsCentMC_WithRecoEvt", "Generated Events With at least One Rec. Collision;;;", kTH2F, {axisPt, axisCent}); + registry.add("PtPrVsCentMC_WithRecoEvt", "Generated Events With at least One Rec. Collision;;;", kTH2F, {axisPt, axisCent}); + + // FOR MAPPING BETWEN MC NCH AND CENTRALITY. BASED ONLY ON THE COLLISION WITH THE LARGEST NUMBER OF CONTRIBUTORS TO PV + registry.add("NchMCVsCent", "Gen Nch vs Cent (Rec. Coll. W/Largest Contributors + Evt. Sel.);;Gen. Nch MC", kTH2F, {axisCent, axisNch}); + // FOR MAPPING BETWEN MC NCH AND CENTRALITY. ALL THE RECONSTRUCTED COLLISIONS EVENT IF RECONSTRUCTED MULTIPLE TIMES + registry.add("NchMCVsCent_AllRecoEvt", "Gen Nch vs Cent (All Rec. Coll. + Evt. Sel.);;Gen. Nch MC", kTH2F, {axisCent, axisNch}); + + // DENOMINATOR OF THE EVENT LOSS. ALL GEN EVENTS + registry.add("NchMC_AllGen", "MC Nch of ALL events;Gen. Nch;Entries", kTH1F, {axisNch}); + // NUMERATOR OF THE EVENT LOOS. BASED ONLY ON THE COLLISION WITH THE LARGEST NUMBER OF CONTRIBUTORS TO PV + registry.add("NchMC_WithRecoEvt", "Gen Evts W/best Coll Idx + Evt. Sel.;Gen Nch;Entries", kTH1F, {axisNch}); + // NUMERATOR OF THE EVENT LOOS. ALL THE RECONSTRUCTED COLLISIONS EVENT IF RECONSTRUCTED MULTIPLE TIMES + registry.add("NchMC_AllRecoEvt", "Gen Evts W/at leas One Rec. Coll + Evt. Sel.;Gen. Nch;Entries", kTH1F, {axisNch}); + // MC NCH DISTRIBUTION. BASED ONLY ON THE COLLISION WITH THE LARGEST NUMBER OF CONTRIBUTORS TO PV & NO EVT SEL. (QA PURPOSES) + registry.add("NchMC_BestCollIdx", "MC Nch from the event associated with ONLY ONE Rec. Coll. with largest Num. of PV contributors;Gen. Nch;Entries", kTH1F, {axisNch}); + // MC NCH DISTRIBUTION ASSOCIATED TO ALL THE RECONSTRUCTED COLLISIONS & NO EVT. SEL. (QA PURPOSES) + registry.add("NchMC_WithRecColl", "MC Nch from the event associated with at least one Rec. Coll.;Gen. Nch;Entries", kTH1F, {axisNch}); + + // NUMERATOR OF THE EVENT SPLITTING. + registry.add("Centrality_WRecoEvtWSelCri", "From the association between the MC event & the Rec. Coll with largest number of PV contributors + Evt. Sel.;;Entries", kTH1F, {axisCent}); + // DENOMINATOR OF THE EVENT SPLITTING. + registry.add("Centrality_AllRecoEvt", "All Rec. Coll. Irrespective of the times it was reconstructed + Evt. Sel.;;Entries", kTH1F, {axisCent}); + + // NUMERATOR OF THE SIGNAL LOSS. BASED ONLY ON THE COLLISION WITH THE LARGEST NUMBER OF CONTRIBUTORS TO PV + registry.add("PtPiVsNchMC_WithRecoEvt", "Gen Evts W/best Coll Idx + Evt. Sel.;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + registry.add("PtKaVsNchMC_WithRecoEvt", "Gen Evts W/best Coll Idx + Evt. Sel.;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + registry.add("PtPrVsNchMC_WithRecoEvt", "Gen Evts W/best Coll Idx + Evt. Sel.;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + + // NUMERATOR OF THE SIGNAL LOSS. USES ALL THE RECONSTRUCTED COLLISIONS EVENT IF RECONSTRUCTED MULTIPLE TIMES + registry.add("PtPiVsNchMC_AllRecoEvt", "Gen Evts W/at leas One Rec. Coll + Evt. Sel.;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + registry.add("PtKaVsNchMC_AllRecoEvt", "Gen Evts W/at leas One Rec. Coll + Evt. Sel.;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + registry.add("PtPrVsNchMC_AllRecoEvt", "Gen Evts W/at leas One Rec. Coll + Evt. Sel.;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + + // DENOMINATOR OF THE SIGNAL LOSS + registry.add("PtPiVsNchMC_AllGen", "All Generated Events;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + registry.add("PtKaVsNchMC_AllGen", "All Generated Events;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + registry.add("PtPrVsNchMC_AllGen", "All Generated Events;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + + // DENOMINATOR OF THE SIGNAL LOSS. USES ALL THE RECONSTRUCTED COLLISIONS EVENT IF RECONSTRUCTED MULTIPLE TIMES (A LA PI0) + registry.add("PtPiVsNchMC_HasFT0", "Gen Evts W/at leas One Rec. Coll + FT0 Info;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + registry.add("PtKaVsNchMC_HasFT0", "Gen Evts W/at leas One Rec. Coll + FT0 Info;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + registry.add("PtPrVsNchMC_HasFT0", "Gen Evts W/at leas One Rec. Coll + FT0 Info;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + + // DENOMINATOR OF THE SIGNAL LOSS. BASED ONLY ON THE COLLISION WITH THE LARGEST NUMBER OF CONTRIBUTORS TO PV (A LA PI0) + registry.add("PtPiVsNchMC_HasFT0_BestCollIdx", "Gen Evts W/best Coll Idx + FT0 Info;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + registry.add("PtKaVsNchMC_HasFT0_BestCollIdx", "Gen Evts W/best Coll Idx + FT0 Info;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + registry.add("PtPrVsNchMC_HasFT0_BestCollIdx", "Gen Evts W/best Coll Idx + FT0 Info;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + + // NUMERATOR OF THE SIGNAL LOSS. USES ALL THE RECONSTRUCTED COLLISIONS EVENT IF RECONSTRUCTED MULTIPLE TIMES (A LA PI0) + registry.add("PtPiVsNchMC_HasFT0AndTVX", "Gen Evts W/at leas One Rec. Coll + FT0 Info & TVX triggered;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + registry.add("PtKaVsNchMC_HasFT0AndTVX", "Gen Evts W/at leas One Rec. Coll + FT0 Info & TVX triggered;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + registry.add("PtPrVsNchMC_HasFT0AndTVX", "Gen Evts W/at leas One Rec. Coll + FT0 Info & TVX triggered;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + + // DENOMITOR OF THE SIGNAL LOSS. USES ALL THE RECONSTRUCTED COLLISIONS EVENT IF RECONSTRUCTED MULTIPLE TIMES (A LA PI0) + registry.add("PtPiVsNchMC_HasFT0AndTVX_BestCollIdx", "Gen Evts W/best Coll Idx + FT0 Info & TVX triggered;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + registry.add("PtKaVsNchMC_HasFT0AndTVX_BestCollIdx", "Gen Evts W/best Coll Idx + FT0 Info & TVX triggered;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + registry.add("PtPrVsNchMC_HasFT0AndTVX_BestCollIdx", "Gen Evts W/best Coll Idx + FT0 Info & TVX triggered;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + + // registry.add("MCclosure_PtMCPiVsNchMC", "All Generated Events 4 MC closure;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + // registry.add("MCclosure_PtMCKaVsNchMC", "All Generated Events 4 MC closure;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + // registry.add("MCclosure_PtMCPrVsNchMC", "All Generated Events 4 MC closure;;Gen. Nch;", kTH2F, {axisPt, axisNch}); + + // registry.add("MCclosure_PtPiVsNchMC", "Gen Evts With at least one Rec. Coll. + Sel. criteria 4 MC closure;;Gen. Nch (|#eta|<0.8);", kTH2F, {axisPt, axisNch}); + // registry.add("MCclosure_PtKaVsNchMC", "Gen Evts With at least one Rec. Coll. + Sel. criteria 4 MC closure;;Gen. Nch (|#eta|<0.8);", kTH2F, {axisPt, axisNch}); + // registry.add("MCclosure_PtPrVsNchMC", "Gen Evts With at least one Rec. Coll. + Sel. criteria 4 MC closure;;Gen. Nch (|#eta|<0.8);", kTH2F, {axisPt, axisNch}); + + auto hMcCouter = registry.get(HIST("EventCounterMC")); + auto* xMcCounter = hMcCouter->GetXaxis(); + xMcCounter->SetBinLabel(1, "All MC Coll"); + xMcCounter->SetBinLabel(2, "nContributors > 0"); + xMcCounter->SetBinLabel(3, "nContributors > 0 + HasFT0"); + xMcCounter->SetBinLabel(4, "nContributors > 0 + HasFT0 & HasTVX"); + xMcCounter->SetBinLabel(5, "nContributors > 0 + HasFT0 & HasTVX & Only largest Contributors"); } LOG(info) << "\trequireGoodRct=" << requireGoodRct.value; @@ -1511,7 +1623,7 @@ struct PiKpRAA { // To calculate the amount of charged-primary MC particles (|eta|<0.5) // that belongs to a MC event that was reconstructed // and only from the with the largest number of contributors - registry.fill(HIST("NchMC_WithOnlyRecColl"), mcNchInTPCAcc); + registry.fill(HIST("NchMC_BestCollIdx"), mcNchInTPCAcc); } //--------------------------- @@ -1623,7 +1735,7 @@ struct PiKpRAA { // MC Collisions that are reconstructed more than one will be stored here //--------------------------- registry.fill(HIST("Centrality_AllRecoEvt"), centrality); - registry.fill(HIST("NumOfRecCollVsNContriWithEvtSel"), nRecColls, collision.numContrib()); + // registry.fill(HIST("NumOfRecCollVsNContriWithEvtSel"), nRecColls, collision.numContrib()); } //--------------------------- @@ -1669,7 +1781,7 @@ struct PiKpRAA { } } - registry.fill(HIST("Centrality_WRecoEvt"), centrality); + // registry.fill(HIST("Centrality_WRecoEvt"), centrality); registry.fill(HIST("zPosMC"), mccollision.posZ()); registry.fill(HIST("CentralityVsBCVsFT0VsTVXVsEvSel"), centrality, 1.0); @@ -2056,6 +2168,847 @@ struct PiKpRAA { } PROCESS_SWITCH(PiKpRAA, processSim, "Process Sim", false); + void processSignalLoss(aod::McCollisions::iterator const& mccollision, soa::SmallGroups const& collisions, BCsRun3 const& /*bcs*/, aod::FT0s const& /*ft0s*/, aod::McParticles const& mcParticles, TracksMC const& tracksMC) + { + + const auto& kLowEta = (std::vector)vecLowEta; + const auto& kHighEta = (std::vector)vecUpEta; + registry.fill(HIST("EventCounterMC"), 0.5); + + //--------------------------- + // Nch COUNTER IN THE TPC ACCEPTANCE + // ONLY ETA SELECTION IS IMPOSED + //--------------------------- + int nChMCTPCAcc{0}; + for (const auto& particle : mcParticles) { + + auto charge{0.}; + // Get the MC particle + const auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < KminCharge) { + continue; + } + + // Select particle based on its charge + if (trackSelections.signCharge.value == "Positive" && charge < Kzero) { + continue; + } + if (trackSelections.signCharge.value == "Negative" && charge > Kzero) { + continue; + } + + // Is it a primary particle? + if (!particle.isPhysicalPrimary()) { + continue; + } + + // Selects particles based on their vertex creation + // This is added to reject loopers + const float vX{particle.vx()}; + const float vY{particle.vy()}; + if (std::hypot(vX, vY) > trackSelections.particleVtxSel) { + continue; + } + + const float eta{particle.eta()}; + registry.fill(HIST("EtaMCParAllMCColl"), eta); + + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + registry.fill(HIST("EtaMCParAllMCColl_Pion"), eta); + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { + registry.fill(HIST("EtaMCParAllMCColl_Kaon"), eta); + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + registry.fill(HIST("EtaMCParAllMCColl_Proton"), eta); + } else if (particle.pdgCode() == PDG_t::kElectron || particle.pdgCode() == PDG_t::kPositron) { + registry.fill(HIST("EtaMCParAllMCColl_Electron"), eta); + } else { + registry.fill(HIST("EtaMCParAllMCColl_Rest"), eta); + } + + if (std::abs(eta) < tpcNchAcceptance) { + nChMCTPCAcc++; + } + } + + //--------------------------- + // SELECTS MC EVENTS WITH |ZVTX| < ZVTX_CUT + //--------------------------- + if (isZvtxPosSelMC && (std::fabs(mccollision.posZ()) > posZcut)) { + return; + } + + //--------------------------- + // *) DENOMINATOR OF THE SIGNAL LOSS + //--------------------------- + for (const auto& particle : mcParticles) { + if (particle.eta() < trackSelections.minEta || particle.eta() > trackSelections.maxEta) { + continue; + } + + auto charge{0.}; + // Get the MC particle + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < KminCharge) { + continue; + } + + // Selects particle based on its charge + if (trackSelections.signCharge.value == "Positive" && charge < Kzero) { + continue; + } + if (trackSelections.signCharge.value == "Negative" && charge > Kzero) { + continue; + } + + // Selects only primary particles + if (!particle.isPhysicalPrimary()) { + continue; + } + + // Selects particles based on their vertex creation + // This is added to reject loopers + const float vX{particle.vx()}; + const float vY{particle.vy()}; + if (std::hypot(vX, vY) > trackSelections.particleVtxSel) { + continue; + } + + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + registry.fill(HIST("PtPiVsNchMC_AllGen"), particle.pt(), nChMCTPCAcc); // DENOMINATOR OF SIGNAL LOSS + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { + registry.fill(HIST("PtKaVsNchMC_AllGen"), particle.pt(), nChMCTPCAcc); // DENOMINATOR OF SIGNAL LOSS + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + registry.fill(HIST("PtPrVsNchMC_AllGen"), particle.pt(), nChMCTPCAcc); // DENOMINATOR OF SIGNAL LOSS + } else { + continue; + } + } // Loop over Generated Particles + + //--------------------------- + // nChMCTPCAc = CHARGEd PARTICLES WITHIN THE TPC ACCEPTANCE AND WITHOUT PT SELECTION + //--------------------------- + registry.fill(HIST("NchMC_AllGen"), nChMCTPCAcc); // DENOMINATOR OF THE EVENT LOSS + registry.fill(HIST("zPosMCAll"), mccollision.posZ()); + + //--------------------------- + // HOW MANY TIMES WAS THE MC EVENT RECONSTRUED? + //--------------------------- + const auto& nRecColls{collisions.size()}; + registry.fill(HIST("NumOfRecColl"), nRecColls); + + //--------------------------- + // MC EVENTS WITH AT LEAST ONE ASSOCIATED RECONSTRUCTED COLLISION + //--------------------------- + if (nRecColls > KzeroInt) { + + //--------------------------- + // THIS COLLISIONS LOOP ONLY FINDS THE ONE WITH THE LARGEST NUMBER OF CONTRIBUTORS + // IT IS IDENTIFIED BY ITS GLOBAL INDEX (bestCollisionIndex) + // NO EVENT SELECTIONS APPLIED + //--------------------------- + int biggestNContribs{-1}; + int bestCollisionIndex{-1}; + for (const auto& collision : collisions) { + + float centrality{-999.0}; + if (centralitySelector.value == "FT0C") { + centrality = collision.centFT0C(); + } else if (centralitySelector.value == "FT0M") { + centrality = collision.centFT0M(); + } else if (centralitySelector.value == "FV0A") { + centrality = collision.centFV0A(); + } else { + centrality = -999.0; + } + + registry.fill(HIST("NumOfRecCollVsNContri"), nRecColls, collision.numContrib()); + registry.fill(HIST("NumOfRecCollVsCentrality"), nRecColls, centrality); // CENTRALITY FROM THE MULTIPLE TIMES THE MC EVENT WAS RECONSTRUCTED + + //--------------------------- + // GETS THE BESTCOLLISIONINDEX + //--------------------------- + if (biggestNContribs < collision.numContrib()) { + biggestNContribs = collision.numContrib(); + bestCollisionIndex = collision.globalIndex(); + } + + const bool hasft0{collision.has_foundFT0()}; + const bool hastvx{collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)}; + + //--------------------------- + // ALL COLLISIONS WITH N CONTRIBUTORS > 0 + //--------------------------- + registry.fill(HIST("EventCounterMC"), 1.5); + + // NCH IN |ETA| < TPC_ACCEPTANCE + // BELONGING TO A MC EVENT, WHICH POSSIBLY WAS RECONSTRUCTED MULTIPLE TIMES + registry.fill(HIST("NchMC_WithRecColl"), nChMCTPCAcc); + + //--------------------------- + // COLLISIONS WITH FT0 INFO + //--------------------------- + if (hasft0) { + registry.fill(HIST("EventCounterMC"), 2.5); + } + + //--------------------------- + // TVX-triggered collision + //--------------------------- + if (hasft0 && hastvx) { + registry.fill(HIST("EventCounterMC"), 3.5); + } + } + + //--------------------------- + // NO EVENT SELECTIONS APPLIED: ONLY FT0-INFO AND TVX-TRIGGERED REQUIRED + //--------------------------- + for (const auto& collision : collisions) { + + bool isBestCollIndex{false}; + if (bestCollisionIndex == collision.globalIndex()) { + isBestCollIndex = true; + } + + const bool hasft0{collision.has_foundFT0()}; + const bool hastvx{collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)}; + + //--------------------------- + // TVX-triggered collision + //--------------------------- + if (hasft0 && hastvx && isBestCollIndex) { + registry.fill(HIST("EventCounterMC"), 4.5); + } + + // TO CALCULATE NCH IN |ETA| < TPC_ACCEPTANCE + // BELONGING TO A MC EVENT ASSOCIATED WITH + // THE ONLY COLLISION WITH THE LARGEST NUMBER OF CONTRIBUTORS + if (isBestCollIndex) { + registry.fill(HIST("NchMC_BestCollIdx"), nChMCTPCAcc); + } + + //--------------------------- + // LOOPING OVER THE MC TRUTH EVENT + //--------------------------- + for (const auto& particle : mcParticles) { + if (particle.eta() < trackSelections.minEta || particle.eta() > trackSelections.maxEta) { + continue; + } + + auto charge{0.}; + // GET THE MC PARTICLE + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // IS IT A CHARGED PARTICLE? + if (std::abs(charge) < KminCharge) { + continue; + } + + // SELECTS PARTICLE BASED ON ITS CHARGE + if (trackSelections.signCharge.value == "Positive" && charge < Kzero) { + continue; + } + if (trackSelections.signCharge.value == "Negative" && charge > Kzero) { + continue; + } + + // SELECTS ONLY PRIMARY PARTICLES + if (!particle.isPhysicalPrimary()) { + continue; + } + + // SELECTS PARTICLES BASED ON THEIR VERTEX CREATION + // THIS IS ADDED TO REJECT LOOPERS + const float vX{particle.vx()}; + const float vY{particle.vy()}; + if (std::hypot(vX, vY) > trackSelections.particleVtxSel) { + continue; + } + + // TO COMPUTE SIGNAL LOSS AS THE RATIO BETWEEN MC EVENTS WITH FT0 INFO + // AND THOSE WITH FT0 INFO AND TVX-TRIGGERED + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + if (hasft0) { + registry.fill(HIST("PtPiVsNchMC_HasFT0"), particle.pt(), nChMCTPCAcc); + if (isBestCollIndex) { + registry.fill(HIST("PtPiVsNchMC_HasFT0_BestCollIdx"), particle.pt(), nChMCTPCAcc); + } + } + if (hasft0 && hastvx) { + registry.fill(HIST("PtPiVsNchMC_HasFT0AndTVX"), particle.pt(), nChMCTPCAcc); + if (isBestCollIndex) { + registry.fill(HIST("PtPiVsNchMC_HasFT0AndTVX_BestCollIdx"), particle.pt(), nChMCTPCAcc); + } + } + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { + if (hasft0) { + registry.fill(HIST("PtKaVsNchMC_HasFT0"), particle.pt(), nChMCTPCAcc); + if (isBestCollIndex) { + registry.fill(HIST("PtKaVsNchMC_HasFT0_BestCollIdx"), particle.pt(), nChMCTPCAcc); + } + } + if (hasft0 && hastvx) { + registry.fill(HIST("PtKaVsNchMC_HasFT0AndTVX"), particle.pt(), nChMCTPCAcc); + if (isBestCollIndex) { + registry.fill(HIST("PtKaVsNchMC_HasFT0AndTVX_BestCollIdx"), particle.pt(), nChMCTPCAcc); + } + } + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + if (hasft0) { + registry.fill(HIST("PtPrVsNchMC_HasFT0"), particle.pt(), nChMCTPCAcc); + if (isBestCollIndex) { + registry.fill(HIST("PtPrVsNchMC_HasFT0_BestCollIdx"), particle.pt(), nChMCTPCAcc); + } + } + if (hasft0 && hastvx) { + registry.fill(HIST("PtPrVsNchMC_HasFT0AndTVX"), particle.pt(), nChMCTPCAcc); + if (isBestCollIndex) { + registry.fill(HIST("PtPrVsNchMC_HasFT0AndTVX_BestCollIdx"), particle.pt(), nChMCTPCAcc); + } + } + } else { + continue; + } + } // LOOP OVER TRUE MC EVENTS + } + + //--------------------------- + // MC EVENTS RECONSTRUCTED MULTIPLE TIMES ARE STORED HERE + // EVENT SELECTION APPLIED MANUALLY TO AVOID DOUBLE FILLING IN THE EVENTCOUNTER + // *) DENOMINATOR OF THE EVENT SPLITTING + // *) NUMERATOR OF THE EVENT LOSS + // *) NUMERATOR OF SIGNAL LOSS + //--------------------------- + for (const auto& collision : collisions) { + + float centrality{-999.0}; + if (centralitySelector.value == "FT0C") { + centrality = collision.centFT0C(); + } else if (centralitySelector.value == "FT0M") { + centrality = collision.centFT0M(); + } else if (centralitySelector.value == "FV0A") { + centrality = collision.centFV0A(); + } else { + centrality = -999.0; + } + + // HAS BC? + if (selHasBC) { + if (!collision.has_foundBC()) { + continue; + } + } + + // HAS FT0 INFORMATION? + if (selHasFT0) { + if (!collision.has_foundFT0()) { + continue; + } + } + + // USE SEL8? + if (useSel8) { + if (!collision.sel8()) { + continue; + } + } + + // KISTRIGGERTVX + if (selTriggerTVX) { + if (!collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { + continue; + } + } + + // kNoITSROFrameBorder + if (selNoITSROFrameBorder) { + if (!collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + continue; + } + } + + // kNoTimeFrameBorder + if (selNoTimeFrameBorder) { + if (!collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + continue; + } + } + + // Zvtx + if (isZvtxPosSel) { + if (std::fabs(collision.posZ()) > posZcut) { + continue; + } + } + + // Short distance between FT0 & PV vertices + if (selIsGoodZvtxFT0vsPV) { + if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + continue; + } + } + + if (selNoSameBunchPileup) { + if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + continue; + } + } + + if (isCentSel) { + if (centrality < minCentCut || centrality > maxCentCut) { + continue; + } + } + + if (selINELgt0) { + if (!collision.isInelGt0()) { + continue; + } + } + + registry.fill(HIST("NchMCVsCent_AllRecoEvt"), centrality, nChMCTPCAcc); // FOR MAPPING BETWEEN MC NCH AND CENTRALITY + registry.fill(HIST("Centrality_AllRecoEvt"), centrality); // DENOMINATOR OF EVENT SPLITTING + registry.fill(HIST("NchMC_AllRecoEvt"), nChMCTPCAcc); // NUMERATOR OF EVENT LOSS CORRECTION + + for (const auto& particle : mcParticles) { + if (particle.eta() < trackSelections.minEta || particle.eta() > trackSelections.maxEta) { + continue; + } + + auto charge{0.}; + // Get the MC particle + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < KminCharge) { + continue; + } + + // Select particle based on its charge + if (trackSelections.signCharge.value == "Positive" && charge < Kzero) { + continue; + } + if (trackSelections.signCharge.value == "Negative" && charge > Kzero) { + continue; + } + + // IS IT A PRIMARY PARTICLE? + if (!particle.isPhysicalPrimary()) { + continue; + } + + // SELECTS PARTICLES BASED ON THEIR VERTEX CREATION + // THIS IS ADDED TO REJECT LOOPERS + const float vX{particle.vx()}; + const float vY{particle.vy()}; + if (std::hypot(vX, vY) > trackSelections.particleVtxSel) { + continue; + } + + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + registry.fill(HIST("PtPiVsNchMC_AllRecoEvt"), particle.pt(), nChMCTPCAcc); // NUMERATOR OF SIGNAL LOSS + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { + registry.fill(HIST("PtKaVsNchMC_AllRecoEvt"), particle.pt(), nChMCTPCAcc); // NUMERATOR OF SIGNAL LOSS + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + registry.fill(HIST("PtPrVsNchMC_AllRecoEvt"), particle.pt(), nChMCTPCAcc); // NUMERATOR OF SIGNAL LOSS + } else { + continue; + } + } // Loop over generated particles per generated collision + } + + //--------------------------- + // ANALYZE ONLY THE COLLISION WITH THE LARGEST NUMBER OF CONTRIBUTORS + // EVENT SELECTIONS APPLIED + // *) NUMERATOR OF THE EVENT SPLITTING + // *) NUMERATOR OF THE EVENT LOSS + // *) NUMERATOR OF SIGNAL LOSS + // *) DENOMINATOR OF TRACKING EFFICIENCY + // *) NUMERATOR OF TRACKING EFFICIENCY + //--------------------------- + for (const auto& collision : collisions) { + + //--------------------------- + // SELECTS THE COLLISIONS WITH THE LARGEST NUMBER OF CONTRIBUTORS + //--------------------------- + if (bestCollisionIndex != collision.globalIndex()) { + continue; + } + + float centrality{-999.0}; + if (centralitySelector.value == "FT0C") { + centrality = collision.centFT0C(); + } else if (centralitySelector.value == "FT0M") { + centrality = collision.centFT0M(); + } else if (centralitySelector.value == "FV0A") { + centrality = collision.centFV0A(); + } else { + centrality = -999.0; + } + + const auto& foundBC = collision.foundBC_as(); + + registry.fill(HIST("zPosMC"), mccollision.posZ()); + + //--------------------------- + // RCT SELECTION? + //--------------------------- + if (requireGoodRct) { + // CHECKS IF COLLISIONS PASSES RCT SELECTION + const bool isFT0Bad{requireBCRct ? foundBC.rct_bit(kFT0Bad) : collision.rct_bit(kFT0Bad)}; + const bool isITSBad{requireBCRct ? foundBC.rct_bit(kITSBad) : collision.rct_bit(kITSBad)}; + const bool isITSLimAcc{requireBCRct ? foundBC.rct_bit(kITSLimAccMCRepr) : collision.rct_bit(kITSLimAccMCRepr)}; + const bool isTOFBad{requireBCRct ? foundBC.rct_bit(kTOFBad) : collision.rct_bit(kTOFBad)}; + const bool isTOFLimAcc{requireBCRct ? foundBC.rct_bit(kTOFLimAccMCRepr) : collision.rct_bit(kTOFLimAccMCRepr)}; + const bool isTPCTrackingBad{requireBCRct ? foundBC.rct_bit(kTPCBadTracking) : collision.rct_bit(kTPCBadTracking)}; + const bool isTPCPIDBad{requireBCRct ? foundBC.rct_bit(kTPCBadPID) : collision.rct_bit(kTPCBadPID)}; + const bool isTPCLimAcc{requireBCRct ? foundBC.rct_bit(kTPCLimAccMCRepr) : collision.rct_bit(kTPCLimAccMCRepr)}; + + registry.fill(HIST("CentralityVsRCTSel"), centrality, 1.0); + if (!isFT0Bad) { + registry.fill(HIST("CentralityVsRCTSel"), centrality, 2.0); + } + if (!isITSBad) { + registry.fill(HIST("CentralityVsRCTSel"), centrality, 3.0); + } + if (!isITSLimAcc) { + registry.fill(HIST("CentralityVsRCTSel"), centrality, 4.0); + } + if (!isTOFBad) { + registry.fill(HIST("CentralityVsRCTSel"), centrality, 5.0); + } + if (!isTOFLimAcc) { + registry.fill(HIST("CentralityVsRCTSel"), centrality, 6.0); + } + if (!isTPCTrackingBad) { + registry.fill(HIST("CentralityVsRCTSel"), centrality, 7.0); + } + if (!isTPCPIDBad) { + registry.fill(HIST("CentralityVsRCTSel"), centrality, 8.0); + } + if (!isTPCLimAcc) { + registry.fill(HIST("CentralityVsRCTSel"), centrality, 9.0); + } + + registry.fill(HIST("RCTSel"), 1.0); + if (!rctChecker(collision)) { + return; + } + + registry.fill(HIST("RCTSel"), 2.0); + } + + //--------------------------- + // **** EVENT SELECTION **** + //--------------------------- + if (!isEventSelected(collision)) { + return; + } + + //--------------------------- + // NEEDED TO CONSTRUCT THE CORRELATION BETWEEN MC NCH V.S. CENTRALITY + //--------------------------- + registry.fill(HIST("Centrality_WRecoEvtWSelCri"), centrality); // NUMERATOR OF EVENT SPLITTING + registry.fill(HIST("NchMC_WithRecoEvt"), nChMCTPCAcc); // NUMERATOR OF EVENT LOSS CORRECTION + registry.fill(HIST("NchMCVsCent"), centrality, nChMCTPCAcc); // FOR MAPPING BETWEEN MC NCH AND CENTRALITY + registry.fill(HIST("zPos"), collision.posZ()); // VTX-Z OF RECONSTRUED COLLISIONS + EVENT SELECTION + registry.fill(HIST("Centrality"), centrality); // CENTRALITY OF RECONSTRUED COLLISIONS + EVENT SELECTION + + //--------------------------- + // THE GENERATED EVENTS ARE NOT SUBJECTED TO ANY SELECTION CRITERIA + // HOWEVER, THE ASSOCIATED RECONSTRUCTED COLLISIONS HAD TO PASS THE SELECTION CRITERIA + // *) DENOMINATOR OF THE TRACKING EFFICIENCY + //--------------------------- + for (const auto& particle : mcParticles) { + if (particle.eta() < trackSelections.minEta || particle.eta() > trackSelections.maxEta) { + continue; + } + + auto charge{0.}; + // Get the MC particle + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < KminCharge) { + continue; + } + + // Select particle based on its charge + if (trackSelections.signCharge.value == "Positive" && charge < Kzero) { + continue; + } + if (trackSelections.signCharge.value == "Negative" && charge > Kzero) { + continue; + } + + // IS IT A PRIMARY PARTICLE? + if (!particle.isPhysicalPrimary()) { + continue; + } + + // SELECTS PARTICLES BASED ON THEIR VERTEX CREATION + // THIS IS ADDED TO REJECT LOOPERS + const float vX{particle.vx()}; + const float vY{particle.vy()}; + if (std::hypot(vX, vY) > trackSelections.particleVtxSel) { + continue; + } + + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + registry.fill(HIST("PtPiVsCentMC_WithRecoEvt"), particle.pt(), centrality); // DENOMINATOR OF TRACKING EFFICIENCY + registry.fill(HIST("PtPiVsNchMC_WithRecoEvt"), particle.pt(), nChMCTPCAcc); // NUMERATOR OF SIGNAL LOSS + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { + registry.fill(HIST("PtKaVsCentMC_WithRecoEvt"), particle.pt(), centrality); + registry.fill(HIST("PtKaVsNchMC_WithRecoEvt"), particle.pt(), nChMCTPCAcc); + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + registry.fill(HIST("PtPrVsCentMC_WithRecoEvt"), particle.pt(), centrality); + registry.fill(HIST("PtPrVsNchMC_WithRecoEvt"), particle.pt(), nChMCTPCAcc); + } else { + continue; + } + } // Loop over generated particles per generated collision + + const auto& groupedTracks{tracksMC.sliceBy(perCollision, collision.globalIndex())}; + + // ================ + // TRACK SELECTION *** WITHOUT DCAXY AND DCAZ SELECTIONS *** + // *) SECONDARY PARTICLE CORRECTION + // ================ + for (const auto& track : groupedTracks) { + + const bool applyDca{false}; + if (!selectPrimary(track, applyDca)) { + continue; + } + + if (!track.has_mcParticle()) { + continue; + } + + // Get the MC particle + const auto& particle{track.mcParticle()}; + auto charge{0.}; + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < KminCharge) { + continue; + } + + // Select particle based on its charge + if (trackSelections.signCharge.value == "Positive" && charge < Kzero) { + continue; + } + if (trackSelections.signCharge.value == "Negative" && charge > Kzero) { + continue; + } + + registry.fill(HIST("DCAxyVsPt"), track.pt(), track.dcaXY()); + registry.fill(HIST("DCAzVsPt"), track.pt(), track.dcaZ()); + + bool isPrimary{false}; + bool isDecay{false}; + bool isMaterial{false}; + if (particle.isPhysicalPrimary()) { + isPrimary = true; + } else if (particle.getProcess() == TMCProcess::kPDecay) { + isDecay = true; + } else { + isMaterial = true; + } + + bool isPi{false}; + bool isPr{false}; + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + isPi = true; + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + isPr = true; + } else { + continue; + } + + if (isPrimary && !isDecay && !isMaterial) { + + // SELECTS PARTICLES BASED ON THEIR VERTEX CREATION; ADDED TO REJECT LOOPERS + const float vX{particle.vx()}; + const float vY{particle.vy()}; + if (std::hypot(vX, vY) > trackSelections.particleVtxSel) { + continue; + } + + if (isPi && !isPr) { + registry.fill(HIST("dcaVsPtPi"), track.pt(), track.dcaXY(), centrality); + } + if (isPr && !isPi) { + registry.fill(HIST("dcaVsPtPr"), track.pt(), track.dcaXY(), centrality); + } + } + + if (isDecay && !isPrimary && !isMaterial) { + if (isPi && !isPr) { + registry.fill(HIST("dcaVsPtPiDec"), track.pt(), track.dcaXY(), centrality); + } + if (isPr && !isPi) { + registry.fill(HIST("dcaVsPtPrDec"), track.pt(), track.dcaXY(), centrality); + } + } + + if (isMaterial && !isPrimary && !isDecay) { + if (isPi && !isPr) { + registry.fill(HIST("dcaVsPtPiMat"), track.pt(), track.dcaXY(), centrality); + } + if (isPr && !isPi) { + registry.fill(HIST("dcaVsPtPrMat"), track.pt(), track.dcaXY(), centrality); + } + } + } + + // ================ + // TRACK SELECTION WITH *** DCAXY AND DCAZ SELECTIONS *** + // *) NUMERATOR OF THE TRACKING EFFICIENCY + // ================ + int nCh{0}; + for (const auto& track : groupedTracks) { + + const bool applyDca{true}; + if (!selectPrimary(track, applyDca)) { + continue; + } + + // Has MC particle? + if (!track.has_mcParticle()) { + continue; + } + + // Get the MC particle + const auto& particle{track.mcParticle()}; + auto charge{0.}; + auto* pdgParticle = pdg->GetParticle(particle.pdgCode()); + if (pdgParticle != nullptr) { + charge = pdgParticle->Charge(); + } else { + continue; + } + + // Is it a charged particle? + if (std::abs(charge) < KminCharge) { + continue; + } + + // Select particle based on its charge + if (trackSelections.signCharge.value == "Positive" && charge < Kzero) { + continue; + } + if (trackSelections.signCharge.value == "Negative" && charge > Kzero) { + continue; + } + + int indexEta{-999}; + const float eta{track.eta()}; + for (int i = 0; i < KnEtaHists; ++i) { + if (eta >= kLowEta[i] && eta < kHighEta[i]) { + indexEta = i; + break; + } + } + + if (indexEta < KzeroInt || indexEta > KsevenInt) { + continue; + } + + nCh++; + + registry.fill(HIST("MomentumTPCVsP"), track.p(), track.tpcInnerParam()); + registry.fill(HIST("DCAxyVsPtWithSelection"), track.pt(), track.dcaXY()); + registry.fill(HIST("DCAzVsPtWithSelection"), track.pt(), track.dcaZ()); + registry.fill(HIST("EtaVsPhi"), track.eta(), track.phi()); + registry.fill(HIST("NclVsPhiHist"), track.phi(), track.tpcNClsFound()); + registry.fill(HIST("NclVsPhiProfile"), track.phi(), track.tpcNClsFound()); + registry.fill(HIST("NclVsEta"), track.eta(), track.tpcNClsFound()); + registry.fill(HIST("NclVsEtap"), track.eta(), track.tpcNClsFound()); + registry.fill(HIST("NclVsEtaPID"), track.eta(), track.tpcNClsPID()); + registry.fill(HIST("NclVsEtaPIDp"), track.eta(), track.tpcNClsPID()); + + // Rejects non-physical primary particle + if (!particle.isPhysicalPrimary()) { + continue; + } + + // Selects particles based on their vertex creation + // This is added to reject loopers + const float vX{particle.vx()}; + const float vY{particle.vy()}; + if (std::hypot(vX, vY) > trackSelections.particleVtxSel) { + continue; + } + + bool isPi{false}; + bool isKa{false}; + bool isPr{false}; + + if (particle.pdgCode() == PDG_t::kPiPlus || particle.pdgCode() == PDG_t::kPiMinus) { + isPi = true; + } else if (particle.pdgCode() == PDG_t::kKPlus || particle.pdgCode() == PDG_t::kKMinus) { + isKa = true; + } else if (particle.pdgCode() == PDG_t::kProton || particle.pdgCode() == PDG_t::kProtonBar) { + isPr = true; + } else { + continue; + } + + if (isPi && !isKa && !isPr) { + registry.fill(HIST("PtPiVsCent_WithRecoEvt"), track.pt(), centrality); // NUMERATOR OF TRACKING EFFICIENCY + registry.fill(HIST("PtGenPiVsCent_WithRecoEvt"), particle.pt(), centrality); // NUMERATOR OF TRACKING EFFICIENCY + } + if (isKa && !isPi && !isPr) { + registry.fill(HIST("PtKaVsCent_WithRecoEvt"), track.pt(), centrality); + registry.fill(HIST("PtGenKaVsCent_WithRecoEvt"), particle.pt(), centrality); + } + if (isPr && !isPi && !isKa) { + registry.fill(HIST("PtPrVsCent_WithRecoEvt"), track.pt(), centrality); + registry.fill(HIST("PtGenPrVsCent_WithRecoEvt"), particle.pt(), centrality); + } + registry.fill(HIST("PtResolution"), particle.pt(), (track.pt() - particle.pt()) / particle.pt()); + } // Loop over reconstructed tracks + registry.fill(HIST("NchVsCent"), centrality, nCh); + } // Loop over Reco. Collisions: Only the collisions with the largest number of contributors + } // If condition: Only simulated evets with at least one reconstrued collision + } + PROCESS_SWITCH(PiKpRAA, processSignalLoss, "Process Signal loss", false); + template void getArmeterosVariables(const T& ppos, const T& pneg, U& alpha, U& qT) { diff --git a/PWGLF/Tasks/Nuspex/spectraKinkPiKa.cxx b/PWGLF/Tasks/Nuspex/spectraKinkPiKa.cxx index 3adeefd79ee..7d2bb8bcd0a 100644 --- a/PWGLF/Tasks/Nuspex/spectraKinkPiKa.cxx +++ b/PWGLF/Tasks/Nuspex/spectraKinkPiKa.cxx @@ -558,7 +558,7 @@ struct SpectraKinkPiKa { } } - double computeMotherMass(ROOT::Math::PxPyPzMVector pmoth, ROOT::Math::PxPyPzMVector pdaug) + double computeMotherMass(const ROOT::Math::PxPyPzMVector& pmoth, const ROOT::Math::PxPyPzMVector& pdaug) { // Infer neutrino momentum from conservation ROOT::Math::XYZVector pnuvec = pmoth.Vect() - pdaug.Vect(); @@ -573,7 +573,7 @@ struct SpectraKinkPiKa { double m2 = etotal * etotal - ptotalsq; return (m2 > 0) ? std::sqrt(m2) : -1.0; } - double computeQt(ROOT::Math::PxPyPzMVector pmoth, ROOT::Math::PxPyPzMVector pdaug) + double computeQt(const ROOT::Math::PxPyPzMVector& pmoth, const ROOT::Math::PxPyPzMVector& pdaug) { TVector3 pdlab(pdaug.Px(), pdaug.Py(), pdaug.Pz()); // Compute transverse component diff --git a/PWGLF/Tasks/Nuspex/spectraTOF.cxx b/PWGLF/Tasks/Nuspex/spectraTOF.cxx index 6a11e17cf37..6ab1dd8a82d 100644 --- a/PWGLF/Tasks/Nuspex/spectraTOF.cxx +++ b/PWGLF/Tasks/Nuspex/spectraTOF.cxx @@ -131,7 +131,8 @@ struct tofSpectra { Configurable cfgCutNsigma{"cfgCutNsigma", 100.0f, "nsigma cut range for tracks"}; Configurable cfgCutEtaMin{"cfgCutEtaMin", -0.8f, "Min eta range for tracks"}; Configurable cfgCutdcaZMin{"cfgCutdcaZMin", -0.02f, "Min dcaZ range for tracks"}; - Configurable cfgCutY{"cfgCutY", 0.5f, "Y range for tracks"}; + Configurable cfgCutYMax{"cfgCutYMax", 0.5f, "Max Y range for tracks"}; + Configurable cfgCutYMin{"cfgCutYMin", -0.5f, "Min Y range for tracks"}; Configurable lastRequiredTrdCluster{"lastRequiredTrdCluster", 5, "Last cluster to require in TRD for track selection. -1 does not require any TRD cluster"}; Configurable requireTrdOnly{"requireTrdOnly", false, "Require only tracks from TRD"}; Configurable requireNoTrd{"requireNoTrd", false, "Require tracks without TRD"}; @@ -900,7 +901,8 @@ struct tofSpectra { template void fillParticleHistos(const T& track, const C& collision) { - if (std::abs(track.rapidity(PID::getMass(id))) > trkselOptions.cfgCutY) { + const auto rapidity = track.rapidity(PID::getMass(id)); + if (rapidity < trkselOptions.cfgCutYMin || rapidity > trkselOptions.cfgCutYMax) { return; } if constexpr (id == PID::Kaon) { @@ -1556,14 +1558,14 @@ struct tofSpectra { bool isTOFKaon = track.hasTOF() && std::abs(nsigmaTOFKa) < trkselOptions.cfgCutNsigma; bool isTOFProton = track.hasTOF() && std::abs(nsigmaTOFPr) < trkselOptions.cfgCutNsigma; // Precompute rapidity values to avoid redundant calculations - double rapidityPi = std::abs(track.rapidity(PID::getMass(2))); - double rapidityKa = std::abs(track.rapidity(PID::getMass(3))); - double rapidityPr = std::abs(track.rapidity(PID::getMass(4))); + double rapidityPi = track.rapidity(PID::getMass(2)); + double rapidityKa = track.rapidity(PID::getMass(3)); + double rapidityPr = track.rapidity(PID::getMass(4)); if (track.eta() < trkselOptions.cfgCutEtaMin || track.eta() > trkselOptions.cfgCutEtaMax) { return; } if (mcParticle.isPhysicalPrimary()) { - if (isTPCPion && rapidityPi <= trkselOptions.cfgCutY) { + if (isTPCPion && rapidityPi >= trkselOptions.cfgCutYMin && rapidityPi <= trkselOptions.cfgCutYMax) { if (usePDGcode) { if (pdgCode == kPiPlus) { histos.fill(HIST("nsigmatpc/mc_closure/pos/pi"), track.pt(), nsigmaTPCPi, multiplicity); @@ -1575,7 +1577,7 @@ struct tofSpectra { histos.fill(HIST("nsigmatpc/mc_closure/neg/pi"), track.pt(), nsigmaTPCPi, multiplicity); } } - if (isTPCKaon && rapidityKa <= trkselOptions.cfgCutY) { + if (isTPCKaon && rapidityKa >= trkselOptions.cfgCutYMin && rapidityKa <= trkselOptions.cfgCutYMax) { if (usePDGcode) { if (pdgCode == kKPlus) { histos.fill(HIST("nsigmatpc/mc_closure/pos/ka"), track.pt(), nsigmaTPCKa, multiplicity); @@ -1587,7 +1589,7 @@ struct tofSpectra { histos.fill(HIST("nsigmatpc/mc_closure/neg/ka"), track.pt(), nsigmaTPCKa, multiplicity); } } - if (isTPCProton && rapidityPr <= trkselOptions.cfgCutY) { + if (isTPCProton && rapidityPr >= trkselOptions.cfgCutYMin && rapidityPr <= trkselOptions.cfgCutYMax) { if (usePDGcode) { if (pdgCode == kProton) { histos.fill(HIST("nsigmatpc/mc_closure/pos/pr"), track.pt(), nsigmaTPCPr, multiplicity); @@ -1601,7 +1603,7 @@ struct tofSpectra { } // TOF Selection and Histogram Filling - if (isTOFPion && rapidityPi <= trkselOptions.cfgCutY) { + if (isTOFPion && rapidityPi >= trkselOptions.cfgCutYMin && rapidityPi <= trkselOptions.cfgCutYMax) { if (usePDGcode) { if (pdgCode == kPiPlus) { histos.fill(HIST("nsigmatof/mc_closure/pos/pi"), track.pt(), nsigmaTOFPi, multiplicity); @@ -1613,7 +1615,7 @@ struct tofSpectra { histos.fill(HIST("nsigmatof/mc_closure/neg/pi"), track.pt(), nsigmaTOFPi, multiplicity); } } - if (isTOFKaon && rapidityKa <= trkselOptions.cfgCutY) { + if (isTOFKaon && rapidityKa >= trkselOptions.cfgCutYMin && rapidityKa <= trkselOptions.cfgCutYMax) { if (usePDGcode) { if (pdgCode == kKPlus) { histos.fill(HIST("nsigmatof/mc_closure/pos/ka"), track.pt(), nsigmaTOFKa, multiplicity); @@ -1625,7 +1627,7 @@ struct tofSpectra { histos.fill(HIST("nsigmatof/mc_closure/neg/ka"), track.pt(), nsigmaTOFKa, multiplicity); } } - if (isTOFProton && rapidityPr <= trkselOptions.cfgCutY) { + if (isTOFProton && rapidityPr >= trkselOptions.cfgCutYMin && rapidityPr <= trkselOptions.cfgCutYMax) { if (usePDGcode) { if (pdgCode == kProton) { histos.fill(HIST("nsigmatof/mc_closure/pos/pr"), track.pt(), nsigmaTOFPr, multiplicity); @@ -1693,21 +1695,21 @@ struct tofSpectra { const bool isTOFProton = track.hasTOF() && std::abs(nsigmaTOFPr) < trkselOptions.cfgCutNsigma; // Apply rapidity cut for identified particles - if (isTPCPion && std::abs(track.rapidity(PID::getMass(2))) < trkselOptions.cfgCutY) { + if (isTPCPion && track.rapidity(PID::getMass(2)) >= trkselOptions.cfgCutYMin && track.rapidity(PID::getMass(2)) <= trkselOptions.cfgCutYMax) { tpcCount++; if (track.sign() > 0) { histos.fill(HIST("nsigmatpc/test_occupancy/pos/pi"), track.pt(), nsigmaTPCPi, multiplicity, occupancy); } else { histos.fill(HIST("nsigmatpc/test_occupancy/neg/pi"), track.pt(), nsigmaTPCPi, multiplicity, occupancy); } - } else if (isTPCKaon && std::abs(track.rapidity(PID::getMass(3))) < trkselOptions.cfgCutY) { + } else if (isTPCKaon && track.rapidity(PID::getMass(3)) >= trkselOptions.cfgCutYMin && track.rapidity(PID::getMass(3)) <= trkselOptions.cfgCutYMax) { tpcCount++; if (track.sign() > 0) { histos.fill(HIST("nsigmatpc/test_occupancy/pos/ka"), track.pt(), nsigmaTPCKa, multiplicity, occupancy); } else { histos.fill(HIST("nsigmatpc/test_occupancy/neg/ka"), track.pt(), nsigmaTPCKa, multiplicity, occupancy); } - } else if (isTPCProton && std::abs(track.rapidity(PID::getMass(4))) < trkselOptions.cfgCutY) { + } else if (isTPCProton && track.rapidity(PID::getMass(4)) >= trkselOptions.cfgCutYMin && track.rapidity(PID::getMass(4)) <= trkselOptions.cfgCutYMax) { tpcCount++; if (track.sign() > 0) { histos.fill(HIST("nsigmatpc/test_occupancy/pos/pr"), track.pt(), nsigmaTPCPr, multiplicity, occupancy); @@ -1717,21 +1719,21 @@ struct tofSpectra { } // TOF PID histograms - if (isTOFPion && std::abs(track.rapidity(PID::getMass(2))) < trkselOptions.cfgCutY) { + if (isTOFPion && track.rapidity(PID::getMass(2)) >= trkselOptions.cfgCutYMin && track.rapidity(PID::getMass(2)) <= trkselOptions.cfgCutYMax) { tofCount++; if (track.sign() > 0) { histos.fill(HIST("nsigmatof/test_occupancy/pos/pi"), track.pt(), nsigmaTOFPi, multiplicity, occupancy); } else { histos.fill(HIST("nsigmatof/test_occupancy/neg/pi"), track.pt(), nsigmaTOFPi, multiplicity, occupancy); } - } else if (isTOFKaon && std::abs(track.rapidity(PID::getMass(3))) < trkselOptions.cfgCutY) { + } else if (isTOFKaon && track.rapidity(PID::getMass(3)) >= trkselOptions.cfgCutYMin && track.rapidity(PID::getMass(3)) <= trkselOptions.cfgCutYMax) { tofCount++; if (track.sign() > 0) { histos.fill(HIST("nsigmatof/test_occupancy/pos/ka"), track.pt(), nsigmaTOFKa, multiplicity, occupancy); } else { histos.fill(HIST("nsigmatof/test_occupancy/neg/ka"), track.pt(), nsigmaTOFKa, multiplicity, occupancy); } - } else if (isTOFProton && std::abs(track.rapidity(PID::getMass(4))) < trkselOptions.cfgCutY) { + } else if (isTOFProton && track.rapidity(PID::getMass(4)) >= trkselOptions.cfgCutYMin && track.rapidity(PID::getMass(4)) <= trkselOptions.cfgCutYMax) { tofCount++; if (track.sign() > 0) { histos.fill(HIST("nsigmatof/test_occupancy/pos/pr"), track.pt(), nsigmaTOFPr, multiplicity, occupancy); @@ -1975,7 +1977,7 @@ struct tofSpectra { return; } - if (std::abs(mcParticle.y()) > trkselOptions.cfgCutY) { + if (mcParticle.y() < trkselOptions.cfgCutYMin || mcParticle.y() > trkselOptions.cfgCutYMax) { return; } if (enablePureDCAHistogram) { @@ -2624,7 +2626,7 @@ struct tofSpectra { const float multiplicity = getMultiplicity(collision); for (const auto& mcParticle : particlesInCollision) { - if (std::abs(mcParticle.y()) > trkselOptions.cfgCutY) { + if (mcParticle.y() < trkselOptions.cfgCutYMin || mcParticle.y() > trkselOptions.cfgCutYMax) { continue; } static_for<0, 17>([&](auto i) { @@ -2634,7 +2636,7 @@ struct tofSpectra { } } else { for (const auto& mcParticle : mcParticles) { - if (std::abs(mcParticle.y()) > trkselOptions.cfgCutY) { + if (mcParticle.y() < trkselOptions.cfgCutYMin || mcParticle.y() > trkselOptions.cfgCutYMax) { continue; } @@ -2668,7 +2670,7 @@ struct tofSpectra { histos.fill(HIST("MC/MultiplicityRecoEv"), getMultiplicityMC(mcCollision)); } for (const auto& mcParticle : particlesInCollision) { - if (std::abs(mcParticle.y()) > trkselOptions.cfgCutY) { + if (mcParticle.y() < trkselOptions.cfgCutYMin || mcParticle.y() > trkselOptions.cfgCutYMax) { continue; } static_for<0, 17>([&](auto i) { @@ -2699,7 +2701,7 @@ struct tofSpectra { } histos.fill(HIST("MC/MultiplicityMCINELgt1"), getMultiplicityMC(mcCollision)); for (const auto& mcParticle : particlesInCollision) { - if (std::abs(mcParticle.y()) > trkselOptions.cfgCutY) { + if (mcParticle.y() < trkselOptions.cfgCutYMin || mcParticle.y() > trkselOptions.cfgCutYMax) { continue; } static_for<0, 17>([&](auto i) { @@ -2729,8 +2731,8 @@ struct tofSpectra { continue; int pdgCode = mcParticleGen.pdgCode(); float pt = mcParticleGen.pt(); - float absY = std::abs(mcParticleGen.y()); - if (absY > trkselOptions.cfgCutY) { + float rapidity = mcParticleGen.y(); + if (rapidity < trkselOptions.cfgCutYMin || rapidity > trkselOptions.cfgCutYMax) { continue; } @@ -2793,8 +2795,8 @@ struct tofSpectra { int pdgCode = mcParticle.pdgCode(); float pt = mcParticle.pt(); - float absY = std::abs(mcParticle.y()); - if (absY > trkselOptions.cfgCutY) { + float rapidity = mcParticle.y(); + if (rapidity < trkselOptions.cfgCutYMin || rapidity > trkselOptions.cfgCutYMax) { continue; } @@ -2877,7 +2879,7 @@ struct tofSpectra { // Precompute rapidity values to avoid redundant calculations double rapiditypar = std::abs(track.rapidity(PID::getMass(par))); // TPC Selection and histogram filling - if (isTPCpar && rapiditypar <= trkselOptions.cfgCutY) { + if (isTPCpar && rapiditypar >= trkselOptions.cfgCutYMin && rapiditypar <= trkselOptions.cfgCutYMax) { static_for<0, NpCharge - 1>([&](auto i) { if (pdgCode == PDGs[i]) { hMCPdgNsigmaTPC[par - 2][i]->Fill(track.pt(), nsigmaTPCpar, multiplicity); diff --git a/PWGLF/Tasks/Nuspex/spectraTOFLight.cxx b/PWGLF/Tasks/Nuspex/spectraTOFLight.cxx index a38211c95cb..3d6dacff05b 100644 --- a/PWGLF/Tasks/Nuspex/spectraTOFLight.cxx +++ b/PWGLF/Tasks/Nuspex/spectraTOFLight.cxx @@ -22,7 +22,6 @@ #include "PWGLF/Utils/inelGt.h" #include "Common/CCDB/EventSelectionParams.h" -#include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelection.h" #include "Common/Core/TrackSelectionDefaults.h" #include "Common/DataModel/Centrality.h" @@ -37,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -49,10 +47,8 @@ #include #include -#include #include #include -#include #include #include @@ -372,7 +368,7 @@ struct SpectraTOFLight { histos.add(hpt_numtof_str[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); histos.add(hpt_numtof_mat[i].data(), pTCharge[i], kTHnSparseD, {ptAxis, multAxis, dcaXyAxis}); - histos.add(hpt_den_prm_goodev[i].data(), pTCharge[i], kTH3D, {ptAxis, multAxis, etaAxis}); + histos.add(hpt_den_prm_goodev[i].data(), pTCharge[i], kTH2D, {ptAxis, multAxis}); } else { histos.add(hpt_num_prm[i].data(), pTCharge[i], kTH2D, {ptAxis, dcaXyAxis}); @@ -387,7 +383,7 @@ struct SpectraTOFLight { histos.add(hpt_den_str[i].data(), pTCharge[i], kTH1D, {ptAxis}); histos.add(hpt_den_mat[i].data(), pTCharge[i], kTH1D, {ptAxis}); - histos.add(hpt_den_prm_goodev[i].data(), pTCharge[i], kTH2D, {ptAxis, etaAxis}); + histos.add(hpt_den_prm_goodev[i].data(), pTCharge[i], kTH1D, {ptAxis}); } histos.add(hpt_den_prm_mcgoodev[i].data(), pTCharge[i], kTH2D, {ptAxis, multAxis}); if (enableDCAxyzHistograms) { @@ -860,7 +856,8 @@ struct SpectraTOFLight { return; // Skips processing if no corresponding MC collision is found (rare case!) } - const float multiplicity = getMultiplicity(collision); + const auto& mcCollision = collision.mcCollision_as(); + const float multiplicity = getMultiplicityMC(mcCollision); if (mcParticle.pdgCode() != PDGs[i]) { return; @@ -1032,9 +1029,9 @@ struct SpectraTOFLight { if (mcParticle.isPhysicalPrimary()) { if (isEventSelected(collision)) { if (includeCentralityMC) { - histos.fill(HIST(hpt_den_prm_goodev[i]), mcParticle.pt(), multiplicity, mcParticle.eta()); + histos.fill(HIST(hpt_den_prm_goodev[i]), mcParticle.pt(), multiplicity); } else { - histos.fill(HIST(hpt_den_prm_goodev[i]), mcParticle.pt(), mcParticle.eta()); + histos.fill(HIST(hpt_den_prm_goodev[i]), mcParticle.pt()); } } } diff --git a/PWGLF/Tasks/QC/efficiencyQA.cxx b/PWGLF/Tasks/QC/efficiencyQA.cxx index c02606e3de1..822b6bb24b6 100644 --- a/PWGLF/Tasks/QC/efficiencyQA.cxx +++ b/PWGLF/Tasks/QC/efficiencyQA.cxx @@ -322,7 +322,7 @@ struct efficiencyQA { } template - void fillHistTrack(T const& track, std::shared_ptr hist, float const& y, float const& z = 1) + void fillHistTrack(T const& track, const std::shared_ptr& hist, float const& y, float const& z = 1) { bool itsAccept = !(track.itsChi2NCl() > 36. || track.itsNCls() < 4); bool tpcAccept = !(track.tpcCrossedRowsOverFindableCls() < 0.8 || track.tpcNClsCrossedRows() < 70 || track.tpcChi2NCl() > 4. || track.tpcNClsFound() < 90); @@ -347,7 +347,7 @@ struct efficiencyQA { } template - void fillHistTrack(T const& track, std::shared_ptr hist, float const& y, float const& z = 1, float const& t = 1) + void fillHistTrack(T const& track, const std::shared_ptr& hist, float const& y, float const& z = 1, float const& t = 1) { bool itsAccept = !(track.itsChi2NCl() > 36. || track.itsNCls() < 4); bool tpcAccept = !(track.tpcCrossedRowsOverFindableCls() < 0.8 || track.tpcNClsCrossedRows() < 70 || track.tpcChi2NCl() > 4. || track.tpcNClsFound() < 90); diff --git a/PWGLF/Tasks/QC/resonanceqa.cxx b/PWGLF/Tasks/QC/resonanceqa.cxx index c4d6b1aac7c..c30eba9fb9b 100644 --- a/PWGLF/Tasks/QC/resonanceqa.cxx +++ b/PWGLF/Tasks/QC/resonanceqa.cxx @@ -275,7 +275,7 @@ struct resonanceqa { histos.fill(HIST("hCentrality"), multiplicity); histos.fill(HIST("hNcontributor"), collision.numContrib()); histos.fill(HIST("hVtxZ"), collision.posZ()); - for (auto track1 : tracks) { + for (const auto& track1 : tracks) { if (!selectionTrack(track1)) { continue; } @@ -289,7 +289,7 @@ struct resonanceqa { histos.fill(HIST("hNsigmaProtonTPC"), track1.tpcNSigmaPr()); histos.fill(HIST("hNsigmaProtonTOF"), track1.tofNSigmaPr()); auto track1ID = track1.globalIndex(); - for (auto track2 : tracks) { + for (const auto& track2 : tracks) { if (!selectionTrack(track2)) { continue; } @@ -388,7 +388,7 @@ struct resonanceqa { } auto daughtp = false; auto daughtm = false; - for (auto kCurrentDaughter : kDaughters) { + for (const auto& kCurrentDaughter : kDaughters) { if (!kCurrentDaughter.isPhysicalPrimary()) { continue; } @@ -425,7 +425,7 @@ struct resonanceqa { return; } histos.fill(HIST("hMC"), 1.5); - for (auto track1 : tracks) { + for (const auto& track1 : tracks) { if (!selectionTrack(track1)) { continue; } @@ -433,7 +433,7 @@ struct resonanceqa { continue; } auto track1ID = track1.globalIndex(); - for (auto track2 : tracks) { + for (const auto& track2 : tracks) { if (!track2.has_mcParticle()) { continue; } diff --git a/PWGLF/Tasks/QC/straRecoStudy.cxx b/PWGLF/Tasks/QC/straRecoStudy.cxx index 8482f7eafc1..b191f182677 100644 --- a/PWGLF/Tasks/QC/straRecoStudy.cxx +++ b/PWGLF/Tasks/QC/straRecoStudy.cxx @@ -592,7 +592,7 @@ struct straRecoStudy { PROCESS_SWITCH(straRecoStudy, processV0RealData, "Regular V0 analysis in real data", false); template - void processCascadeCandidate(TCascCandidate casc) + void processCascadeCandidate(const TCascCandidate& casc) { // MC association if (!casc.has_collision()) { diff --git a/PWGLF/Tasks/QC/strderivedGenQA.cxx b/PWGLF/Tasks/QC/strderivedGenQA.cxx index 4d1c2878d26..b9223226614 100644 --- a/PWGLF/Tasks/QC/strderivedGenQA.cxx +++ b/PWGLF/Tasks/QC/strderivedGenQA.cxx @@ -518,7 +518,7 @@ struct strderivedGenQA { } template - bool IsEventAccepted(TCollision collision) + bool IsEventAccepted(const TCollision& collision) // check whether the collision passes our collision selections { if (eventSelections.requireSel8 && !collision.sel8()) { diff --git a/PWGLF/Tasks/QC/v0cascadesqa.cxx b/PWGLF/Tasks/QC/v0cascadesqa.cxx index 99c7d37699c..4beab4e9572 100644 --- a/PWGLF/Tasks/QC/v0cascadesqa.cxx +++ b/PWGLF/Tasks/QC/v0cascadesqa.cxx @@ -456,7 +456,7 @@ struct v0cascadesQA { } template - bool isEventAccepted(TCollision collision, bool fillHists) + bool isEventAccepted(const TCollision& collision, bool fillHists) // check whether the collision passes our collision selections { if (fillHists) { @@ -625,7 +625,7 @@ struct v0cascadesQA { } template - bool isV0Accepted(TV0 v0, TCollision collision, float rapidity, int v0Type) + bool isV0Accepted(const TV0& v0, const TCollision& collision, float rapidity, int v0Type) // precalculate this information so that a check is one mask operation, not many { // Base topological variables @@ -816,7 +816,7 @@ struct v0cascadesQA { } template - bool isCascadeSelected(TCascade casc, TCollision collision, float rapidity, int cascType) + bool isCascadeSelected(const TCascade& casc, const TCollision& collision, float rapidity, int cascType) // precalculate this information so that a check is one mask operation, not many { // @@ -1030,7 +1030,7 @@ struct v0cascadesQA { } template - bool checkV0MCAssociation(TV0 v0, int v0Type) + bool checkV0MCAssociation(const TV0& v0, int v0Type) // precalculate this information so that a check is one mask operation, not many { if (!v0.isPhysicalPrimary()) @@ -1054,7 +1054,7 @@ struct v0cascadesQA { } template - bool checkCascadeMCAssociation(TCascade casc, int cascType) + bool checkCascadeMCAssociation(const TCascade& casc, int cascType) // precalculate this information so that a check is one mask operation, not many { if (!casc.isPhysicalPrimary()) diff --git a/PWGLF/Tasks/QC/vertexQA.cxx b/PWGLF/Tasks/QC/vertexQA.cxx index 9dab5ce7f10..45aef295193 100644 --- a/PWGLF/Tasks/QC/vertexQA.cxx +++ b/PWGLF/Tasks/QC/vertexQA.cxx @@ -45,7 +45,7 @@ namespace { constexpr double LHCRFFreq = 400.789e6; constexpr double LHCBunchSpacingNS = 10 * 1.e9 / LHCRFFreq; -double deltaTimeColl(BCcoll const bccoll1, BCcoll const bccoll2) +double deltaTimeColl(BCcoll const& bccoll1, BCcoll const& bccoll2) { auto coll1 = std::get(bccoll1); auto coll2 = std::get(bccoll2); @@ -271,7 +271,7 @@ struct vertexQA { std::vector jumps{0ll}; int64_t lastBC = bcs.rawIteratorAt(0).globalBC(); - for (auto bc : bcs) { + for (const auto& bc : bcs) { if (bc.globalBC() - lastBC > 3564 * 32) { // 32 orbits jumps.push_back(bc.globalIndex()); lastBC = bc.globalBC(); @@ -279,7 +279,7 @@ struct vertexQA { } uint64_t jumpsSentinel{1}; std::vector collisionsIndices{0ll}; - for (auto col : collisions) { + for (const auto& col : collisions) { if (jumpsSentinel == jumps.size()) { break; } diff --git a/PWGLF/Tasks/Resonances/CMakeLists.txt b/PWGLF/Tasks/Resonances/CMakeLists.txt index 938926a5688..956fddc12ef 100644 --- a/PWGLF/Tasks/Resonances/CMakeLists.txt +++ b/PWGLF/Tasks/Resonances/CMakeLists.txt @@ -333,3 +333,8 @@ o2physics_add_dpl_workflow(cha01710analysis SOURCES cha01710analysis.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(xi1530kaoncorrelation + SOURCES xi1530kaoncorrelation.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGLF/Tasks/Resonances/cha01710analysis.cxx b/PWGLF/Tasks/Resonances/cha01710analysis.cxx index 41e5557f37d..8a75cd96a48 100644 --- a/PWGLF/Tasks/Resonances/cha01710analysis.cxx +++ b/PWGLF/Tasks/Resonances/cha01710analysis.cxx @@ -269,7 +269,7 @@ struct Cha01710analysis { template bool selectPionDaughter(T const& track) { - return !(!track.hasTPC() || track.tpcNClsFound() < v0Cuts.cfgV0DaughterTPCNClsMin || track.pt() < v0Cuts.cfgV0DaughterPtMin || std::abs(track.eta()) > v0Cuts.cfgV0DaughterEtaMax || std::abs(track.tpcNSigmaPi()) > v0Cuts.cfgV0DaughterTPCNSigmaPiMax); + return !(track.tpcNClsFound() < v0Cuts.cfgV0DaughterTPCNClsMin || track.pt() < v0Cuts.cfgV0DaughterPtMin || std::abs(track.eta()) > v0Cuts.cfgV0DaughterEtaMax || std::abs(track.tpcNSigmaPi()) > v0Cuts.cfgV0DaughterTPCNSigmaPiMax); } template @@ -298,15 +298,12 @@ struct Cha01710analysis { return V0MassRegion::kReject; } float dm = std::abs(v0.mK0Short() - constants::physics::MassK0Short); + histos.fill(HIST("V0/hMassSelected"), v0.mK0Short(), v0.pt()); + if (dm < v0Cuts.cfgKsMassWindow) { - histos.fill(HIST("V0/hMassSelected"), v0.mK0Short(), v0.pt()); return V0MassRegion::kSignal; } - if (dm > v0Cuts.cfgKsMassWindow) { - histos.fill(HIST("V0/hMassSelected"), v0.mK0Short(), v0.pt()); - return V0MassRegion::kSideband; - } - return V0MassRegion::kReject; + return V0MassRegion::kSideband; } template diff --git a/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx b/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx index a721c73b11f..2020bacdaa4 100644 --- a/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx +++ b/PWGLF/Tasks/Resonances/chargedkstaranalysis.cxx @@ -99,6 +99,7 @@ struct Chargedkstaranalysis { Preslice perMCCollision = o2::aod::mcparticle::mcCollisionId; bool currentIsGen = false; bool mcClosure = false; + bool sigLossDen = false; struct : ConfigurableGroup { ConfigurableAxis cfgvtxbins{"cfgvtxbins", {VARIABLE_WIDTH, -10.0f, -8.f, -6.f, -4.f, -2.f, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f}, "Mixing bins - z-vertex"}; ConfigurableAxis cfgmultbins{"cfgmultbins", {VARIABLE_WIDTH, 0., 1., 5., 10., 30., 50., 70., 100., 110.}, "Mixing bins - multiplicity"}; @@ -584,9 +585,9 @@ struct Chargedkstaranalysis { histosMc.add("h3ChaKstarInvMassDSMcGen", "h3ChaKstarInvMassDSMcGen", kTHnSparseF, {centAxis, ptAxis, invMassAxisReso, thnAxisPOL}, true); histosMc.add("h3ChaKstarInvMassDSMcRec", "h3ChaKstarInvMassDSMcRec", kTHnSparseF, {centAxis, ptAxis, invMassAxisReso, thnAxisPOL}, true); histosMc.add("h3ChaKstarInvMassDSMcRecClosure", "h3ChaKstarInvMassDSMcRecClosure", kTHnSparseF, {centAxis, ptAxis, invMassAxisReso, thnAxisPOL}, true); + histosMc.add("sigLoss_den_pri_threeD", "sigLoss_den_pri_threeD", kTHnSparseF, {centAxis, ptAxis, thnAxisPOL}, true); if (mcCfgs.doBkgMc) { - histosMc.add("h3ChaKstarInvMassRotMcGen", "h3ChaKstarInvMassRotMcGen", kTHnSparseF, {centAxis, ptAxis, invMassAxisReso, thnAxisPOL}, true); histosMc.add("h3ChaKstarInvMassRotMcRec", "h3ChaKstarInvMassRotMcRec", kTHnSparseF, {centAxis, ptAxis, invMassAxisReso, thnAxisPOL}, true); histosMc.add("h3ChaKstarInvMassRotMcRecClosure", "h3ChaKstarInvMassRotMcRecClosure", kTHnSparseF, {centAxis, ptAxis, invMassAxisReso, thnAxisPOL}, true); } @@ -844,9 +845,11 @@ struct Chargedkstaranalysis { // 2. MC Generated Path if (currentIsGen) { - if (isRot) { - histosMc.fill(HIST("h3ChaKstarInvMassRotMcGen"), multiplicity, mother.Pt(), mother.M(), cosTheta); + if (sigLossDen) { + // Fill ONLY the Signal Loss Denominator 3D Histograms + histosMc.fill(HIST("sigLoss_den_pri_threeD"), multiplicity, mother.Pt(), cosTheta); } else { + // Fill standard 4D MC Gen Histograms histosMc.fill(HIST("h3ChaKstarInvMassDSMcGen"), multiplicity, mother.Pt(), mother.M(), cosTheta); } return; @@ -867,7 +870,6 @@ struct Chargedkstaranalysis { } } } - template void fillInvMass(const T& mother, float multiplicity, const T& daughter1, const T& daughter2, bool isMix) { @@ -914,7 +916,7 @@ struct Chargedkstaranalysis { auto phiCS = std::atan2(yAxisCS.Dot(v1CM), xAxisCS.Dot(v1CM)); phiCS = RecoDecay::constrainAngle(phiCS, 0.0); - bool doRotation = !doprocessMC || mcCfgs.doBkgMc; + bool doRotation = !doprocessMC || (!currentIsGen && mcCfgs.doBkgMc); // if (std::abs(mother.Rapidity()) < config.rapidityMotherData) { if (helicityCfgs.activateHelicityFrame) { // helicityVec = mother.Vect(); // 3 vector of mother in COM frame @@ -1453,10 +1455,10 @@ struct Chargedkstaranalysis { const float lCentrality = getCentrality(coll); refCentByMcId.emplace(mcid, lCentrality); } - + currentIsGen = true; + sigLossDen = false; // Calculating the generated Kstar for (const auto& part : mcParticles) { - currentIsGen = true; if (!part.has_mcCollision()) { continue; } @@ -1547,9 +1549,102 @@ struct Chargedkstaranalysis { } } } + sigLossDen = true; + // To calculate the denominator -> To check the all the events have chk892 + for (auto const& part : mcParticles) { + if (!part.has_mcCollision()) { + continue; + } + if (std::abs(part.pdgCode()) != kKstarPlus) { + continue; + } + if (std::abs(part.y()) > kstarCutCfgs.cKstarMaxRap) { + continue; + } + + const auto mcid = part.mcCollisionId(); + if (!refClassIds.contains(mcid)) { + continue; + } + + auto iter = refCentByMcId.find(mcid); + if (iter == refCentByMcId.end()) { + continue; + } + + const float lCentrality = iter->second; + + histos.fill(HIST("Correction/sigLoss_den"), part.pt(), lCentrality); + if (part.vt() == 0) { + histos.fill(HIST("Correction/sigLoss_den_pri"), part.pt(), lCentrality); + } + LorentzVectorSetXYZM lResoSecondary, lDecayDaughter_bach, lResoKstar, lDaughterRot; + lResoKstar = LorentzVectorSetXYZM(part.px(), part.py(), part.pz(), MassKPlusStar892); + const int pionWanted = (part.pdgCode() > 0) ? +kPiPlus : -kPiPlus; + bool hasRightPion = false; + bool hasK0sToPipi = false; + for (const auto& d1 : part.template daughters_as()) { + const int pdg1 = d1.pdgCode(); + if (pdg1 == pionWanted) { + lDecayDaughter_bach = LorentzVectorSetXYZM(d1.px(), d1.py(), d1.pz(), MassPionCharged); + if (helicityCfgs.genKinematicsChecks) { + if (lDecayDaughter_bach.pt() <= trackCutCfgs.cMinPtcut || std::abs(lDecayDaughter_bach.eta()) >= trackCutCfgs.cMaxEtacut) { + continue; + } + } + hasRightPion = true; + } else if (std::abs(pdg1) == kPDGK0) { + for (const auto& d2 : d1.template daughters_as()) { + if (std::abs(d2.pdgCode()) == kPDGK0s) { + if (helicityCfgs.genKinematicsChecks) { + if (d2.pt() <= secondaryCutsCfgs.cSecondaryPtMin || std::abs(d2.eta()) >= secondaryCutsCfgs.cSecondaryRapidityMax) { + continue; + } + } + bool seenPip = false, seenPim = false; + for (const auto& d3 : d2.template daughters_as()) { + if (d3.pdgCode() == +kPiPlus) { + if (helicityCfgs.genKinematicsChecks) { + if (d3.pt() <= trackCutCfgs.cMinPtcut || std::abs(d3.eta()) >= trackCutCfgs.cMaxEtacut) { + continue; + } + } + seenPip = true; + } else if (d3.pdgCode() == -kPiPlus) { + if (helicityCfgs.genKinematicsChecks) { + if (d3.pt() <= trackCutCfgs.cMinPtcut || std::abs(d3.eta()) >= trackCutCfgs.cMaxEtacut) { + continue; + } + } + seenPim = true; + } + } + if (seenPip && seenPim) { + lResoSecondary = LorentzVectorSetXYZM(d2.px(), d2.py(), d2.pz(), MassK0Short); + hasK0sToPipi = true; + break; + } + } + } + } + if (hasRightPion && hasK0sToPipi) { + break; + } + } + + if (!(hasRightPion && hasK0sToPipi)) { + continue; + } + if (helicityCfgs.cCosWithKShot) { + fillInvMass(lResoKstar, lCentrality, lResoSecondary, lDecayDaughter_bach, eventCutCfgs.confIsMix); + } else { + fillInvMass(lResoKstar, lCentrality, lDecayDaughter_bach, lResoSecondary, eventCutCfgs.confIsMix); + } + } + + currentIsGen = false; // To store the recoKstar for (const auto& v0 : v0s) { - currentIsGen = false; auto coll = v0.template collision_as(); if (!coll.has_mcCollision()) { @@ -1691,35 +1786,6 @@ struct Chargedkstaranalysis { histos.fill(HIST("Correction/sigLoss_num_pri"), part.pt(), lCentrality); } } - // To calculate the denominator -> To check the all the events have chk892 - for (auto const& part : mcParticles) { - if (!part.has_mcCollision()) { - continue; - } - if (std::abs(part.pdgCode()) != kKstarPlus) { - continue; - } - if (std::abs(part.y()) > kstarCutCfgs.cKstarMaxRap) { - continue; - } - - const auto mcid = part.mcCollisionId(); - if (!refClassIds.contains(mcid)) { - continue; - } - - auto iter = refCentByMcId.find(mcid); - if (iter == refCentByMcId.end()) { - continue; - } - - const float lCentrality = iter->second; - - histos.fill(HIST("Correction/sigLoss_den"), part.pt(), lCentrality); - if (part.vt() == 0) { - histos.fill(HIST("Correction/sigLoss_den_pri"), part.pt(), lCentrality); - } - } // To calculate the event fraction correction for (const auto& mcid : refClassIds) { histos.fill(HIST("Correction/EF_den"), refCentByMcId[mcid]); diff --git a/PWGLF/Tasks/Resonances/deltaAnalysis.cxx b/PWGLF/Tasks/Resonances/deltaAnalysis.cxx index 263886c0eb5..0d39c167ce7 100644 --- a/PWGLF/Tasks/Resonances/deltaAnalysis.cxx +++ b/PWGLF/Tasks/Resonances/deltaAnalysis.cxx @@ -100,6 +100,7 @@ struct DeltaAnalysis { Configurable cfgCentralityEstimator{"cfgCentralityEstimator", 0, "Centrality estimator: 0=FT0M 1=FT0A 2=FT0C 3=FV0A 4=NTPV"}; Configurable cfgCentMin{"cfgCentMin", 0.f, "Minimum centrality percentile"}; Configurable cfgCentMax{"cfgCentMax", 100.f, "Maximum centrality percentile"}; + Configurable cfgUseMCTruthCentrality{"cfgUseMCTruthCentrality", false, "Use MC truth centrality for generated Delta histograms"}; } evSel; struct : ConfigurableGroup { @@ -189,7 +190,6 @@ struct DeltaAnalysis { struct : ConfigurableGroup { ConfigurableAxis cfgPtAxis{"cfgPtAxis", {VARIABLE_WIDTH, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.8, 3.2, 3.6, 4.0, 5.0, 7.0, 10.0}, "#it{p}_{T} (GeV/#it{c})"}; ConfigurableAxis cfgCentAxis{"cfgCentAxis", {VARIABLE_WIDTH, 0.f, 10.f, 20.f, 30.f, 40.f, 50.f, 60.f, 70.f, 80.f, 90.f, 100.f}, "Centrality (%)"}; - Configurable cfgCentDistBins{"cfgCentDistBins", 1500, "Number of bins for centrality distribution"}; ConfigurableAxis cfgVtxAxis{"cfgVtxAxis", {VARIABLE_WIDTH, -12.f, -10.f, -9.f, -8.f, -7.f, -6.f, -5.f, -4.f, -3.f, -2.f, -1.f, 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 12.f}, "Vertex z [cm]"}; ConfigurableAxis cfgRapAxis{"cfgRapAxis", {20, -1.0, 1.0}, "Rapidity y"}; } axes; @@ -241,7 +241,6 @@ struct DeltaAnalysis { const AxisSpec ptAxis{200, 0., 10., "p_{T} (GeV/c)"}; const AxisSpec massAxis{trackCuts.numberOfInvMassBins, 1.0, 8.0, "M_{inv} (GeV/#it{c}^{2})"}; const AxisSpec centAxis{axes.cfgCentAxis, "Centrality (%)"}; - const AxisSpec centDistAxis{axes.cfgCentDistBins, 0., 105., "Centrality (%)"}; const AxisSpec vtxAxis{axes.cfgVtxAxis, "Vertex z [cm]"}; const AxisSpec rapAxis{axes.cfgRapAxis, "Rapidity y"}; const AxisSpec nSigmaTPCaxis{100, -10., 10., "n#sigma^{TPC}"}; @@ -260,7 +259,7 @@ struct DeltaAnalysis { histos.add("Event/hNcontributor", "PV contributors; N", kTH1F, {{2001, -0.5f, 2000.5f}}); histos.add("Event/hCentrality", "Centrality", kTH1F, {centAxis}); histos.add("Event/hOccupancy", "Occupancy in time range", kTH1F, {occupancyAxis}); - histos.add("Event/centralitydistribution", "Centrality distribution (Data);vCentFT0M;Entries", kTH1F, {centDistAxis}); + histos.add("Event/centralitydistribution", "Centrality distribution (Data);vCentFT0M;Entries", kTH1F, {centAxis}); histos.add("CentQA/hCentralityVsVtxZ", "Centrality vs vertex z", kTH2F, {vtxAxis, centAxis}); histos.add("CentQA/hCentralityVsOccupancy", "Centrality vs occupancy", kTH2F, {occupancyAxis, centAxis}); @@ -430,7 +429,7 @@ struct DeltaAnalysis { histos.add("QAMC/hEtaPhi_rec", "MC Reco #eta vs #varphi; #eta; #varphi", kTH2F, {etaAxis, {72, 0, 6.2832}}); histos.add("MCRecoEvent/hRecoEvents", "Reconstructed INEL>0 events (Nrec, MC reco)", kTH1F, {centAxis}); - histos.add("MCRecoEvent/centralitydistribution", "Centrality distribution (MC);vCentFT0M;Entries", kTH1F, {centDistAxis}); + histos.add("MCRecoEvent/centralitydistribution", "Centrality distribution (MC);vCentFT0M;Entries", kTH1F, {centAxis}); } // ── MC reconstructed event mixing: histograms (gated by the dedicated MC mixing switch, @@ -1899,15 +1898,23 @@ struct DeltaAnalysis { histos.fill(HIST("CutFlow/MCGen/hEventCutFlow"), 4.f); // Final generated event histos.fill(HIST("EfficiencyQA/hGeneratedEventCutFlow"), 3.f); // Final generated event + // ── MODIFIED BLOCK (per user request): centrality-source switch for generated Delta ──── + // Added: evSel.cfgUseMCTruthCentrality (see Configurable added in evSel group above). bool hasAcceptedReco = false; - float genCentrality = mcCollision.centFT0M(); // fallback: MC-truth centrality proxy (see note above) + float genCentrality = mcCollision.centFT0M(); + for (auto const& collision : collisions) { if (passesEventSelection(collision)) { hasAcceptedReco = true; - genCentrality = getCentrality(collision); // real reconstructed centrality of an accepted associated collision + + if (!evSel.cfgUseMCTruthCentrality) { + genCentrality = getCentrality(collision); + } + break; } } + if (hasAcceptedReco) { histos.fill(HIST("EfficiencyQA/hGeneratedEventCutFlow"), 4.f); // Associated reconstructed event accepted } diff --git a/PWGLF/Tasks/Resonances/doubleResonanceScan.cxx b/PWGLF/Tasks/Resonances/doubleResonanceScan.cxx index bc81e47c208..44e196fb8e3 100644 --- a/PWGLF/Tasks/Resonances/doubleResonanceScan.cxx +++ b/PWGLF/Tasks/Resonances/doubleResonanceScan.cxx @@ -213,7 +213,7 @@ struct DoubleResonanceScan { } template - bool trackCut(const TrackType track) + bool trackCut(const TrackType& track) { if constexpr (!IsResoMicrotrack) { if (std::abs(track.pt()) < cMinPtcut) diff --git a/PWGLF/Tasks/Resonances/doublephimeson.cxx b/PWGLF/Tasks/Resonances/doublephimeson.cxx index a14647b525a..b027bfdd2d3 100644 --- a/PWGLF/Tasks/Resonances/doublephimeson.cxx +++ b/PWGLF/Tasks/Resonances/doublephimeson.cxx @@ -75,6 +75,62 @@ struct doublephimeson { Configurable cfgCrossPhiHigh{"cfgCrossPhiHigh", 1.03, "Upper edge of phi mass window for cross-pairing (ghost) veto"}; Configurable useParametrized{"useParametrized", false, "Use pT dependent mass peak and width"}; Configurable useCrossPairRejection{"useCrossPairRejection", true, "Use cross pair phi signal compatibilaty"}; + Configurable cfgFillDataDrivenPhiResolution{ + "cfgFillDataDrivenPhiResolution", true, + "Fill the single-phi daughter-kinematics sparse used for data-driven X resolution and inter-dataset momentum-scale calibration"}; + + Configurable cfgFillSelectedXResolutionSparse{ + "cfgFillSelectedXResolutionSparse", true, + "Fill compact selected-X candidate sparse for data-driven X mass-resolution study"}; + Configurable cfgSelectedXResolutionMassLow{ + "cfgSelectedXResolutionMassLow", 2.63f, + "Lower M(phi-phi) edge for selected-X resolution sparse (GeV/c^2)"}; + Configurable cfgSelectedXResolutionMassHigh{ + "cfgSelectedXResolutionMassHigh", 2.75f, + "Upper M(phi-phi) edge for selected-X resolution sparse (GeV/c^2)"}; + Configurable cfgSelectedXResolutionPtMin{ + "cfgSelectedXResolutionPtMin", 9.0f, + "Minimum pT(phi-phi) for selected-X resolution sparse (GeV/c)"}; + + // Optional 2025 -> 2026 kaon momentum-scale correction used only in + // processopti5. The selected calibration model is a sigmoid plus a quadratic + // tail: + // + // epsilon_corr(%) = p0 + p1/[1 + exp(-(pT_phi-p2)/p3)] + // + p4*pT_phi + p5*pT_phi^2, + // + // with pT_phi, p2 and p3 in GeV/c. Both kaons belonging to a phi candidate + // receive the same scale factor: + // p_corr = (1 + epsilon_corr/100) * p_measured. + // The numerical parameters should be supplied from the JSON file generated + // by CalibratePhiMomentumScaleVsPt.C after the final calibration fit. + Configurable cfgApplyKaonMomentumCorrection{ + "cfgApplyKaonMomentumCorrection", false, + "Apply the pT-dependent kaon momentum-scale correction in processopti5"}; + Configurable cfgMomCorrP0Percent{ + "cfgMomCorrP0Percent", 0.749950, + "p0 of epsilon_corr(pT_phi) in percent"}; + Configurable cfgMomCorrP1Percent{ + "cfgMomCorrP1Percent", 0.421824, + "p1 sigmoid-step amplitude of epsilon_corr in percent"}; + Configurable cfgMomCorrP2GeV{ + "cfgMomCorrP2GeV", 1.614360, + "p2 sigmoid turn-on position in GeV/c"}; + Configurable cfgMomCorrP3GeV{ + "cfgMomCorrP3GeV", 0.290147, + "p3 sigmoid width in GeV/c; must be positive"}; + Configurable cfgMomCorrP4PercentPerGeV{ + "cfgMomCorrP4PercentPerGeV", 0.0279158, + "p4 linear-tail slope in percent per GeV/c"}; + Configurable cfgMomCorrP5PercentPerGeV2{ + "cfgMomCorrP5PercentPerGeV2", 0.0, + "p5 quadratic-tail coefficient in percent per (GeV/c)^2"}; + Configurable cfgMomCorrPtMin{ + "cfgMomCorrPtMin", 0.8, + "Minimum uncorrected phi pT for applying the momentum correction (GeV/c)"}; + Configurable cfgMomCorrPtMax{ + "cfgMomCorrPtMax", 20.0, + "Maximum uncorrected phi pT for applying the momentum correction (GeV/c)"}; // ------------------------------------------------------------ // pT-dependent phi mass peak and width from single-phi BW fits // @@ -156,18 +212,72 @@ struct doublephimeson { ConfigurableAxis configThnAxisDaughterPt{"configThnAxisDaughterPt", {100, 0.0, 100.}, "daughter #it{p}_{T} (GeV/#it{c})"}; ConfigurableAxis configThnAxisKstar{"configThnAxisKstar", {200, 0.0, 2.0}, "#it{k}^{*} (GeV/#it{c})"}; ConfigurableAxis configThnAxisDeltaR{"configThnAxisDeltaR", {VARIABLE_WIDTH, 0.0, 0.0001, 0.0003, 0.0005, 0.0007, 0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.009, 0.01, 0.02, 0.03, 0.04, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 2.0, 10.0}, "#it{k}^{*} (GeV/#it{c})"}; - ConfigurableAxis configThnAxisCosTheta{"configThnAxisCosTheta", {160, 0.0, 3.2}, "cos #theta{*}"}; - ConfigurableAxis configThnAxisNumPhi{"configThnAxisNumPhi", {101, -0.5, 100.5}, "cos #theta{*}"}; + ConfigurableAxis configThnAxisCosTheta{"configThnAxisCosTheta", {10, 0.0, 1.0}, "cos #theta{*}"}; + ConfigurableAxis configThnAxisRapidity{"configThnAxisRapidity", {10, 0.0, 1.0}, "Rapidity"}; + ConfigurableAxis configThnAxisNumPhi{"configThnAxisNumPhi", {6, -0.5, 5.5}, "Number of Kaon daughter have TOF hit"}; ConfigurableAxis configThnAxisDeltaPt{"configThnAxisDeltaPt", {100, 0.0, 1.0}, "delta pt"}; Configurable maxDeltaMPhi{"maxDeltaMPhi", 0.01f, "Delta-m cut on the two phi masses: sqrt((m1-mPDG)^2 + (m2-mPDG)^2) < maxDeltaMPhi (GeV/c^2)"}; // --- NEW: steerable axes from JSON --- ConfigurableAxis configThnAxisDeltaRPhi{"configThnAxisDeltaRPhi", {120, 0.0, 6.0}, "ΔR(φ,φ)"}; ConfigurableAxis configThnAxisZ{"configThnAxisZ", {100, 0.0, 1.0}, "z"}; - ConfigurableAxis configThnAxisA{"configThnAxisA", {100, 0.0, 1.0}, "A"}; + ConfigurableAxis configThnAxisA{"configThnAxisA", {10, 0.0, 1.0}, "A"}; ConfigurableAxis configThnAxisPhiPtVertex{"configThnAxisPhiPtVertex", {100, 0.0, 100.0}, "phi pT (GeV/c)"}; ConfigurableAxis configThnAxisDecayLength{"configThnAxisDecayLength", {200, 0.0, 1.0}, "3D decay length (cm)"}; ConfigurableAxis configThnAxisFitChi2Ndf{"configThnAxisFitChi2Ndf", {200, 0.0, 100.0}, "four-kaon fit chi2/NDF"}; ConfigurableAxis configThnAxisRmsDcaSig{"configThnAxisRmsDcaSig", {300, 0.0, 15.0}, "RMS DCA significance"}; + + // Data-driven mass-resolution inputs. + // + // 1) PhiMassResolutionDataDriven: + // inclusive single-phi calibration, filled after daughter/PID selections + // but before the hard phi-mass window. + // + // 2) SelectedXResolutionDataDriven: + // compact candidate-level sparse filled only for the selected X window. + // It keeps the measured joint pT configuration of the two phis and all + // four kaons, so no pT(X) reweighting or regenerated daughter-pT topology + // is needed later. + ConfigurableAxis cfgDDPhiMassAxis{ + "cfgDDPhiMassAxis", + {100, 0.995, 1.045}, + "m(KK) for data-driven resolution (GeV/c^2)"}; + // The pT edges are deliberately fine around 1--3 GeV/c, where the momentum + // response changes fastest, and coarser at high pT. eta and DeltaPhi are + // retained only as validation axes; the primary extraction integrates them. + ConfigurableAxis cfgDDCalibKaonPtAxis{ + "cfgDDCalibKaonPtAxis", + {VARIABLE_WIDTH, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, + 1.1, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.5, 3.0, + 3.5, 4.0, 5.0, 6.0, 8.0, 10.0, 15.0, 20.0, 30.0, 50.0}, + "kaon pT in single-phi calibration (GeV/c)"}; + ConfigurableAxis cfgDDCalibKaonEtaAxis{ + "cfgDDCalibKaonEtaAxis", + {10, -1.0, 1.0}, + "kaon eta in single-phi calibration"}; + ConfigurableAxis cfgDDCalibDeltaPhiAxis{ + "cfgDDCalibDeltaPhiAxis", + {36, -3.141592653589793, 3.141592653589793}, + "Delta phi(K+,K-) in single-phi calibration"}; + ConfigurableAxis cfgDDPhiPtAxis{ + "cfgDDPhiPtAxis", + {VARIABLE_WIDTH, 0.0, 0.4, 0.5, 0.6, 0.8, 0.9, 1.0, 1.1, 1.2, + 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, + 3.5, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, + 12.0, 14.0, 16.0, 18.0, 20.0, 25.0, 30.0, 40.0, 50.0, 100.0}, + "phi pT for data-driven resolution (GeV/c)"}; + + // Compact pT(X) axis. The sparse itself is only filled for pT(X)>9 GeV/c, + // so there is no need to allocate fine bins below the analysis threshold. + ConfigurableAxis cfgDDSelectedXPtAxis{ + "cfgDDSelectedXPtAxis", + {VARIABLE_WIDTH, 9.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0, + 25.0, 30.0, 40.0, 50.0, 70.0, 100.0}, + "pT(phi-phi) for selected-X data-driven resolution (GeV/c)"}; + + // The selected-X candidate sparse is intentionally restricted at filling + // time to the narrow M(phi-phi) window and pT(X) threshold. M(phi-phi) is + // therefore NOT stored as an axis, keeping the 9D sparse compact. + // Initialize the ananlysis task void init(o2::framework::InitContext&) { @@ -197,16 +307,25 @@ struct doublephimeson { const AxisSpec thnAxisInvMassDeltaPhiSigma{configThnAxisInvMassDeltaPhiSigma, "#it{M} (GeV/#it{c}^{2}) sigma"}; const AxisSpec thnAxisDeltaR{configThnAxisDeltaR, "#Delta R)"}; const AxisSpec thnAxisCosTheta{configThnAxisCosTheta, "cos #theta"}; + const AxisSpec thnAxisRapidity{configThnAxisRapidity, "Rapidity"}; const AxisSpec thnAxisNumPhi{configThnAxisNumPhi, "Number of phi meson"}; const AxisSpec thnAxisPtCorr{configThnAxisPtCorr, "Pt Corr var"}; const AxisSpec thnAxisDeltaRPhi{configThnAxisDeltaRPhi, "#Delta R(#phi,#phi)"}; const AxisSpec thnAxisZ{configThnAxisZ, "z = p_{T1}/(p_{T1}+p_{T2})"}; const AxisSpec thnAxisA{configThnAxisA, "A = |p_{T1}-p_{T2}|/(p_{T1}+p_{T2})"}; - + AxisSpec axisDoublePhiPID{50, 0.0, 5.0, "max daughter n_{#sigma}^{comb}"}; const AxisSpec thnAxisDecayLength{configThnAxisDecayLength, "#it{L}_{3D} (cm)"}; const AxisSpec thnAxisFitChi2Ndf{configThnAxisFitChi2Ndf, "#chi^{2}/NDF"}; const AxisSpec thnAxisRmsDcaSig{configThnAxisRmsDcaSig, "RMS DCA significance"}; + const AxisSpec ddPhiMassAxis{cfgDDPhiMassAxis, "m_{K^{+}K^{-}} (GeV/c^{2})"}; + const AxisSpec ddCalibKaonPtAxis{cfgDDCalibKaonPtAxis, "p_{T,K} (GeV/c)"}; + const AxisSpec ddCalibKaonEtaAxis{cfgDDCalibKaonEtaAxis, "#eta_{K}"}; + const AxisSpec ddCalibDeltaPhiAxis{cfgDDCalibDeltaPhiAxis, "#Delta#varphi_{K^{+}K^{-}}"}; + const AxisSpec ddPhiPtAxis{cfgDDPhiPtAxis, "p_{T,#phi} (GeV/c)"}; + + const AxisSpec ddSelectedXPtAxis{cfgDDSelectedXPtAxis, "p_{T,X} (GeV/c)"}; + histos.add("SEMassUnlike", "SEMassUnlike", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisDeltaR, thnAxisPt, thnAxisDeltaR, thnAxisInvMassDeltaPhi, thnAxisPtCorr}); // histos.add("SEMassLike", "SEMassLike", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisDeltaR, thnAxisInvMassPhi, thnAxisInvMassPhi, thnAxisNumPhi}); histos.add("MEMassUnlike", "MEMassUnlike", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisDeltaR, thnAxisPt, thnAxisDeltaR, thnAxisInvMassDeltaPhi, thnAxisPtCorr}); @@ -236,13 +355,58 @@ struct doublephimeson { thnAxisPtCorr, thnAxisNumPhi}); // pT correlation variable + histos.add("SEMassDoublePhi", "SEMassDoublePhi", HistType::kTHnSparseF, + {thnAxisInvMass, // M(phi-phi) + thnAxisPt, // pT(phi-phi) + thnAxisA, + thnAxisRapidity, + thnAxisInvMassPhi, // m(phi1) + thnAxisInvMassPhi, // m(phi2) + thnAxisInvMassDeltaPhi, // DeltaM_phi + thnAxisNumPhi, + axisDoublePhiPID}); + histos.add("SEMassUnlike_VertexVars", "SEMassUnlike_VertexVars", HistType::kTHnSparseF, {thnAxisInvMass, thnAxisPt, thnAxisInvMassDeltaPhi, thnAxisInvMassPhi, thnAxisInvMassPhi, thnAxisDecayLength, thnAxisFitChi2Ndf, thnAxisRmsDcaSig}); + + // Single-phi calibration input. Axis order: + // 0 m(KK), 1 pT(K+), 2 pT(K-), 3 eta(K+), 4 eta(K-), + // 5 DeltaPhi(K+,K-), 6 pT(phi). + // It is intentionally filled BEFORE minPhiMass/maxPhiMass are applied. + histos.add("PhiMassResolutionDataDriven", "PhiMassResolutionDataDriven", + HistType::kTHnSparseF, + {ddPhiMassAxis, ddCalibKaonPtAxis, ddCalibKaonPtAxis, + ddCalibKaonEtaAxis, ddCalibKaonEtaAxis, + ddCalibDeltaPhiAxis, ddPhiPtAxis}); + + // Selected-X candidate-level resolution sparse. Filled only for + // cfgSelectedXResolutionMassLow < M(phi-phi) < cfgSelectedXResolutionMassHigh + // pT(phi-phi) > cfgSelectedXResolutionPtMin. + // + // Axis order: + // 0 pT(X) + // 1 m(phi1) + // 2 m(phi2) + // 3 pT(phi1) + // 4 pT(phi2) + // 5 pT(K+ from phi1) + // 6 pT(K- from phi1) + // 7 pT(K+ from phi2) + // 8 pT(K- from phi2) + // + // No eta axes and no M(phi-phi) axis are stored. + histos.add("SelectedXResolutionDataDriven", "SelectedXResolutionDataDriven", + HistType::kTHnSparseF, + {ddSelectedXPtAxis, + ddPhiMassAxis, ddPhiMassAxis, + ddPhiPtAxis, ddPhiPtAxis, + ddCalibKaonPtAxis, ddCalibKaonPtAxis, + ddCalibKaonPtAxis, ddCalibKaonPtAxis}); } // get kstar TLorentzVector trackSum, PartOneCMS, PartTwoCMS, trackRelK; - float getkstar(const TLorentzVector part1, - const TLorentzVector part2) + float getkstar(const TLorentzVector& part1, + const TLorentzVector& part2) { // const TLorentzVector trackSum = part1 + part2; trackSum = part1 + part2; @@ -262,39 +426,37 @@ struct doublephimeson { return 0.5 * trackRelK.P(); } - float deepangle2(const ROOT::Math::PtEtaPhiMVector candidate1, - const ROOT::Math::PtEtaPhiMVector candidate2) + float deepangle2(const ROOT::Math::PtEtaPhiMVector& candidate1, + const ROOT::Math::PtEtaPhiMVector& candidate2) { - double pt1, pt2, pz1, pz2, p1, p2, angle; - pt1 = candidate1.Pt(); - pt2 = candidate2.Pt(); - pz1 = candidate1.Pz(); - pz2 = candidate2.Pz(); - p1 = candidate1.P(); - p2 = candidate2.P(); - angle = TMath::ACos((pt1 * pt2 + pz1 * pz2) / (p1 * p2)); + const double pt1 = candidate1.Pt(); + const double pt2 = candidate2.Pt(); + const double pz1 = candidate1.Pz(); + const double pz2 = candidate2.Pz(); + const double p1 = candidate1.P(); + const double p2 = candidate2.P(); + const double angle = TMath::ACos((pt1 * pt2 + pz1 * pz2) / (p1 * p2)); return angle; } - float deepangle(const TLorentzVector candidate1, - const TLorentzVector candidate2) + float deepangle(const TLorentzVector& candidate1, + const TLorentzVector& candidate2) { - double pt1, pt2, pz1, pz2, p1, p2, angle; - pt1 = candidate1.Pt(); - pt2 = candidate2.Pt(); - pz1 = candidate1.Pz(); - pz2 = candidate2.Pz(); - p1 = candidate1.P(); - p2 = candidate2.P(); - angle = TMath::ACos((pt1 * pt2 + pz1 * pz2) / (p1 * p2)); + const double pt1 = candidate1.Pt(); + const double pt2 = candidate2.Pt(); + const double pz1 = candidate1.Pz(); + const double pz2 = candidate2.Pz(); + const double p1 = candidate1.P(); + const double p2 = candidate2.P(); + const double angle = TMath::ACos((pt1 * pt2 + pz1 * pz2) / (p1 * p2)); return angle; } // get cosTheta TLorentzVector daughterCMS; ROOT::Math::XYZVector threeVecDauCM, threeVecMother; - float getCosTheta(const TLorentzVector mother, - const TLorentzVector daughter) + float getCosTheta(const TLorentzVector& mother, + const TLorentzVector& daughter) { threeVecMother = mother.Vect(); const float beta = mother.Beta(); @@ -311,28 +473,122 @@ struct doublephimeson { bool selectionPID(float nsigmaTPC, float nsigmaTOF, int TOFHit, int PIDStrategy, float ptcand) { + if (PIDStrategy == 2003) { + constexpr float radius2Max = 2.5f * 2.5f; + const bool hasTOF = (TOFHit == 1); + + if (!hasTOF) { + // TPC-only branch + if (ptcand < 0.5f) { + return std::abs(nsigmaTPC) < cutNsigmaTPC; + } else { + return nsigmaTPC > -2.0f && + nsigmaTPC < cutNsigmaTPC; + } + + } else { + // TPC+TOF branch + const float radius2 = + nsigmaTPC * nsigmaTPC + + nsigmaTOF * nsigmaTOF; + + if (radius2 >= radius2Max) { + return false; + } + + // Circle only below 2 GeV/c + if (ptcand < 2.0f) { + return true; + } + + float slope = 0.0f; + float intercept = 0.0f; + + if (ptcand < 2.5f) { + slope = 1.29f; + intercept = 3.34f; + } else if (ptcand < 3.0f) { + slope = 0.94f; + intercept = 2.45f; + } else if (ptcand < 4.0f) { + slope = 0.62f; + intercept = 1.55f; + } else if (ptcand < 5.0f) { + slope = 0.32f; + intercept = 1.45f; + } else if (ptcand < 7.0f) { + slope = 0.22f; + intercept = 1.35f; + } else { + slope = 0.10f; + intercept = 1.25f; + } + + return nsigmaTPC < + slope * nsigmaTOF + intercept; + } + } + + if (PIDStrategy == 2004) { + + const bool hasTOF = (TOFHit == 1); + + if (!hasTOF) { + // No TOF hit + return std::abs(nsigmaTPC) < 2.0f; + + } else { + // TOF hit present + + if (ptcand < 2.0f) { + // No TPC or TOF PID cut + return true; + } + + if (ptcand < 2.5f) { + return !(nsigmaTPC > 1.5f && + nsigmaTOF < -1.6f); + } + + if (ptcand < 3.0f) { + return !(nsigmaTPC > 1.0f && + nsigmaTOF < -1.0f); + } + + if (ptcand < 3.5f) { + return !(nsigmaTPC > 1.0f && + nsigmaTOF < -0.8f); + } + + if (ptcand < 4.5f) { + return !(nsigmaTPC > 1.0f && + nsigmaTOF < -0.5f); + } + + // pT >= 4.5 GeV/c + return !(nsigmaTPC > 1.0f && + nsigmaTOF < 1.0f); + } + } + if (PIDStrategy == 1000) { - if (TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.5) { - return true; - } else if (TOFHit != 1 && std::abs(nsigmaTPC) < 2.0) { + if ((TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.5) || + (TOFHit != 1 && std::abs(nsigmaTPC) < 2.0)) { return true; } } if (PIDStrategy == 1001) { - if (TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.0) { - return true; - } else if (TOFHit != 1 && ptcand < 2.5 && std::abs(nsigmaTPC) < 2.0) { - return true; - } else if (TOFHit != 1 && ptcand >= 2.5 && nsigmaTPC > -2.0 && nsigmaTPC < 1.0) { + if ((TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.0) || + (TOFHit != 1 && ptcand < 2.5 && std::abs(nsigmaTPC) < 2.0) || + (TOFHit != 1 && ptcand >= 2.5 && nsigmaTPC > -2.0 && nsigmaTPC < 1.0)) { return true; } } if (PIDStrategy == 1002) { - if (TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.0) { - return true; - } else if (TOFHit != 1 && std::abs(nsigmaTPC) < 2.0) { + if ((TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.0) || + (TOFHit != 1 && std::abs(nsigmaTPC) < 2.0)) { return true; } } @@ -440,11 +696,9 @@ struct doublephimeson { } } } else { - if (TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.5) { - return true; - } else if (TOFHit != 1 && ptcand < 2.0 && nsigmaTPC > -2.5 && nsigmaTPC < 2.0) { - return true; - } else if (TOFHit != 1 && ptcand > 2.0 && nsigmaTPC > -2.5 && nsigmaTPC < 1.0) { + if ((TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.5) || + (TOFHit != 1 && ptcand < 2.0 && nsigmaTPC > -2.5 && nsigmaTPC < 2.0) || + (TOFHit != 1 && ptcand > 2.0 && nsigmaTPC > -2.5 && nsigmaTPC < 1.0)) { return true; } } @@ -504,9 +758,8 @@ struct doublephimeson { } } } else { - if (TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.0) { - return true; - } else if (TOFHit != 1 && nsigmaTPC > -2.5 && nsigmaTPC < 1.0) { + if ((TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.0) || + (TOFHit != 1 && nsigmaTPC > -2.5 && nsigmaTPC < 1.0)) { return true; } } @@ -536,9 +789,8 @@ struct doublephimeson { } else if (ptcand >= 1.0 && ptcand < 2.0 && TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.5) { return true; } else if (ptcand > 2.0) { - if (TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.0) { - return true; - } else if (TOFHit != 1 && nsigmaTPC > -2.5 && nsigmaTPC < 1.0) { + if ((TOFHit == 1 && std::sqrt(nsigmaTOF * nsigmaTOF + nsigmaTPC * nsigmaTPC) < 2.0) || + (TOFHit != 1 && nsigmaTPC > -2.5 && nsigmaTPC < 1.0)) { return true; } } @@ -837,7 +1089,7 @@ struct doublephimeson { return; } int phimult = 0; - for (auto phitrackd1 : phitracks) { + for (auto const& phitrackd1 : phitracks) { if (phitrackd1.phiMass() < minPhiMass1 || phitrackd1.phiMass() > maxPhiMass1) { continue; } @@ -857,7 +1109,7 @@ struct doublephimeson { } phimult = phimult + 1; } - for (auto phitrackd1 : phitracks) { + for (auto const& phitrackd1 : phitracks) { auto kaonplusd1pt = TMath::Sqrt(phitrackd1.phid1Px() * phitrackd1.phid1Px() + phitrackd1.phid1Py() * phitrackd1.phid1Py()); auto kaonminusd1pt = TMath::Sqrt(phitrackd1.phid2Px() * phitrackd1.phid2Px() + phitrackd1.phid2Py() * phitrackd1.phid2Py()); if (kaonplusd1pt > maxKaonPt) { @@ -880,7 +1132,7 @@ struct doublephimeson { Phid1.SetXYZM(phitrackd1.phiPx(), phitrackd1.phiPy(), phitrackd1.phiPz(), phitrackd1.phiMass()); Phi1kaonplus.SetXYZM(phitrackd1.phid1Px(), phitrackd1.phid1Py(), phitrackd1.phid1Pz(), 0.493); Phi1kaonminus.SetXYZM(phitrackd1.phid2Px(), phitrackd1.phid2Py(), phitrackd1.phid2Pz(), 0.493); - for (auto phitrackd2 : phitracks) { + for (auto const& phitrackd2 : phitracks) { auto phid2id = phitrackd2.index(); if (phid2id <= phid1id) { continue; @@ -973,7 +1225,7 @@ struct doublephimeson { } int phimult = 0; - for (auto phitrackd1 : phitracks) { + for (auto const& phitrackd1 : phitracks) { if (phitrackd1.phiMass() < minPhiMass1 || phitrackd1.phiMass() > maxPhiMass1) { continue; } @@ -993,7 +1245,7 @@ struct doublephimeson { } phimult = phimult + 1; } - for (auto phitrackd1 : phitracks) { + for (auto const& phitrackd1 : phitracks) { auto kaonplusd1pt = TMath::Sqrt(phitrackd1.phid1Px() * phitrackd1.phid1Px() + phitrackd1.phid1Py() * phitrackd1.phid1Py()); auto kaonminusd1pt = TMath::Sqrt(phitrackd1.phid2Px() * phitrackd1.phid2Px() + phitrackd1.phid2Py() * phitrackd1.phid2Py()); @@ -1021,7 +1273,7 @@ struct doublephimeson { Phid1.SetXYZM(phitrackd1.phiPx(), phitrackd1.phiPy(), phitrackd1.phiPz(), phitrackd1.phiMass()); Phi1kaonplus.SetXYZM(phitrackd1.phid1Px(), phitrackd1.phid1Py(), phitrackd1.phid1Pz(), 0.493); Phi1kaonminus.SetXYZM(phitrackd1.phid2Px(), phitrackd1.phid2Py(), phitrackd1.phid2Pz(), 0.493); - for (auto phitrackd2 : phitracks) { + for (auto const& phitrackd2 : phitracks) { auto phid2id = phitrackd2.index(); if (phid2id <= phid1id) { continue; @@ -1088,14 +1340,14 @@ struct doublephimeson { for (auto if1 = exoticresonance.begin(); if1 != exoticresonance.end(); ++if1) { auto i5 = std::distance(exoticresonance.begin(), if1); - auto exotic1phi1 = phiresonanced1.at(i5); - auto exotic1phi2 = phiresonanced2.at(i5); - auto exotic1 = exoticresonance.at(i5); + const auto& exotic1phi1 = phiresonanced1.at(i5); + const auto& exotic1phi2 = phiresonanced2.at(i5); + const auto& exotic1 = exoticresonance.at(i5); - auto exotic1kaonplus1 = kaonplus1.at(i5); - auto exotic1kaonminus1 = kaonminus1.at(i5); - auto exotic1kaonplus2 = kaonplus2.at(i5); - auto exotic1kaonminus2 = kaonminus2.at(i5); + const auto& exotic1kaonplus1 = kaonplus1.at(i5); + const auto& exotic1kaonminus1 = kaonminus1.at(i5); + const auto& exotic1kaonplus2 = kaonplus2.at(i5); + const auto& exotic1kaonminus2 = kaonminus2.at(i5); auto deltaRkaonplus1 = TMath::Sqrt(TMath::Power(exotic1kaonplus1.Phi() - exotic1kaonplus2.Phi(), 2.0) + TMath::Power(exotic1kaonplus1.Eta() - exotic1kaonplus2.Eta(), 2.0)); auto deltaRkaonminus1 = TMath::Sqrt(TMath::Power(exotic1kaonminus1.Phi() - exotic1kaonminus2.Phi(), 2.0) + TMath::Power(exotic1kaonminus1.Eta() - exotic1kaonminus2.Eta(), 2.0)); histos.fill(HIST("hDeltaRkaonplus"), deltaRkaonplus1); @@ -1113,14 +1365,14 @@ struct doublephimeson { for (auto if2 = if1 + 1; if2 != exoticresonance.end(); ++if2) { auto i6 = std::distance(exoticresonance.begin(), if2); - auto exotic2phi1 = phiresonanced1.at(i6); - auto exotic2phi2 = phiresonanced2.at(i6); - auto exotic2 = exoticresonance.at(i6); - - auto exotic2kaonplus1 = kaonplus1.at(i6); - auto exotic2kaonminus1 = kaonminus1.at(i6); - auto exotic2kaonplus2 = kaonplus2.at(i6); - auto exotic2kaonminus2 = kaonminus2.at(i6); + const auto& exotic2phi1 = phiresonanced1.at(i6); + const auto& exotic2phi2 = phiresonanced2.at(i6); + const auto& exotic2 = exoticresonance.at(i6); + + const auto& exotic2kaonplus1 = kaonplus1.at(i6); + const auto& exotic2kaonminus1 = kaonminus1.at(i6); + const auto& exotic2kaonplus2 = kaonplus2.at(i6); + const auto& exotic2kaonminus2 = kaonminus2.at(i6); auto deltaRkaonplus2 = TMath::Sqrt(TMath::Power(exotic2kaonplus1.Phi() - exotic2kaonplus2.Phi(), 2.0) + TMath::Power(exotic2kaonplus1.Eta() - exotic2kaonplus2.Eta(), 2.0)); auto deltaRkaonminus2 = TMath::Sqrt(TMath::Power(exotic2kaonminus1.Phi() - exotic2kaonminus2.Phi(), 2.0) + TMath::Power(exotic2kaonminus1.Eta() - exotic2kaonminus2.Eta(), 2.0)); @@ -1146,14 +1398,14 @@ struct doublephimeson { } else { for (auto if1 = exoticresonance.begin(); if1 != exoticresonance.end(); ++if1) { auto i5 = std::distance(exoticresonance.begin(), if1); - auto exotic1phi1 = phiresonanced1.at(i5); - auto exotic1phi2 = phiresonanced2.at(i5); - auto exotic1 = exoticresonance.at(i5); - - auto exotic1kaonplus1 = kaonplus1.at(i5); - auto exotic1kaonminus1 = kaonminus1.at(i5); - auto exotic1kaonplus2 = kaonplus2.at(i5); - auto exotic1kaonminus2 = kaonminus2.at(i5); + const auto& exotic1phi1 = phiresonanced1.at(i5); + const auto& exotic1phi2 = phiresonanced2.at(i5); + const auto& exotic1 = exoticresonance.at(i5); + + const auto& exotic1kaonplus1 = kaonplus1.at(i5); + const auto& exotic1kaonminus1 = kaonminus1.at(i5); + const auto& exotic1kaonplus2 = kaonplus2.at(i5); + const auto& exotic1kaonminus2 = kaonminus2.at(i5); auto deltaRkaonplus1 = TMath::Sqrt(TMath::Power(exotic1kaonplus1.Phi() - exotic1kaonplus2.Phi(), 2.0) + TMath::Power(exotic1kaonplus1.Eta() - exotic1kaonplus2.Eta(), 2.0)); auto deltaRkaonminus1 = TMath::Sqrt(TMath::Power(exotic1kaonminus1.Phi() - exotic1kaonminus2.Phi(), 2.0) + TMath::Power(exotic1kaonminus1.Eta() - exotic1kaonminus2.Eta(), 2.0)); auto deltam1 = TMath::Sqrt(TMath::Power(exotic1phi1.M() - 1.0192, 2.0) + TMath::Power(exotic1phi2.M() - 1.0192, 2.0)); @@ -1574,12 +1826,70 @@ struct doublephimeson { } PROCESS_SWITCH(doublephimeson, processopti4, "Process Optimized same event", true); double dMNominal = 100.0; + void processopti5(aod::RedPhiEvents::iterator const& collision, aod::PhiTracks const& phitracks) { if (additionalEvsel && (collision.numPos() < 2 || collision.numNeg() < 2)) { return; } + constexpr double mPhiPDG = o2::constants::physics::MassPhi; // GeV/c^2 + constexpr double mKPDG = o2::constants::physics::MassKPlus; // GeV/c^2 + + // Build the phi and its daughter-kaon four-vectors. With the correction + // disabled this reproduces the original opti5 construction exactly. With + // it enabled, the scale is evaluated using the uncorrected phi pT, both + // kaon three-momenta are scaled coherently, their energies are recomputed + // using mKPDG, and the corrected phi is rebuilt from the two kaons. + const auto buildPhiAndKaons = [&](const auto& t, + TLorentzVector& phi, + TLorentzVector& kplus, + TLorentzVector& kminus) { + kplus.SetXYZM(t.phid1Px(), t.phid1Py(), t.phid1Pz(), mKPDG); + kminus.SetXYZM(t.phid2Px(), t.phid2Py(), t.phid2Pz(), mKPDG); + phi.SetXYZM(t.phiPx(), t.phiPy(), t.phiPz(), t.phiMass()); + + if (!cfgApplyKaonMomentumCorrection) { + return; + } + + const double uncorrectedPhiPt = std::hypot(t.phiPx(), t.phiPy()); + if (!std::isfinite(uncorrectedPhiPt) || uncorrectedPhiPt <= 0. || + uncorrectedPhiPt < cfgMomCorrPtMin || + uncorrectedPhiPt > cfgMomCorrPtMax) { + return; + } + + const double sigmoidWidth = cfgMomCorrP3GeV; + if (!std::isfinite(sigmoidWidth) || sigmoidWidth <= 0.) { + return; + } + + const double sigmoid = + 1. / (1. + std::exp(-(uncorrectedPhiPt - cfgMomCorrP2GeV) / + sigmoidWidth)); + const double epsilonPercent = + cfgMomCorrP0Percent + + cfgMomCorrP1Percent * sigmoid + + cfgMomCorrP4PercentPerGeV * uncorrectedPhiPt + + cfgMomCorrP5PercentPerGeV2 * uncorrectedPhiPt * uncorrectedPhiPt; + const double scale = 1. + 0.01 * epsilonPercent; + + if (!std::isfinite(scale) || scale <= 0.) { + return; + } + + kplus.SetXYZM(scale * t.phid1Px(), + scale * t.phid1Py(), + scale * t.phid1Pz(), + mKPDG); + kminus.SetXYZM(scale * t.phid2Px(), + scale * t.phid2Py(), + scale * t.phid2Pz(), + mKPDG); + phi = kplus + kminus; + }; + // --- phi multiplicity with PID --- int phimult = 0; // int nBestPairingRejected = 0; @@ -1591,14 +1901,15 @@ struct doublephimeson { histos.fill(HIST("hnsigmaTPCKaonPlusBefore"), t.phid1TPC(), kpluspt); histos.fill(HIST("hnsigmaTPCKaonMinusBefore"), t.phid2TPC(), kminuspt); - if (t.phiMass() < minPhiMass1 || t.phiMass() > maxPhiMass1) { - continue; - } TLorentzVector phi1; - phi1.SetXYZM(t.phiPx(), t.phiPy(), t.phiPz(), t.phiMass()); - if (phi1.Pt() < minPhiPt || phi1.Pt() > maxPhiPt) { - continue; - } + TLorentzVector kplus; + TLorentzVector kminus; + buildPhiAndKaons(t, phi1, kplus, kminus); + const double phi1Mass = cfgApplyKaonMomentumCorrection ? phi1.M() : t.phiMass(); + + // Apply the same daughter/PID requirements before filling the calibration + // sparse. The phi-pT requirement for that sparse is evaluated below from + // the RAW daughters, so it remains independent of any optional correction. if (kpluspt > maxKaonPt || kminuspt > maxKaonPt) { continue; } @@ -1609,10 +1920,39 @@ struct doublephimeson { continue; } + if (cfgFillDataDrivenPhiResolution) { + // IMPORTANT: always store the RAW reconstructed daughter momenta here, + // independent of cfgApplyKaonMomentumCorrection. This keeps the + // resolution calibration data-driven and also allows two data sets to + // be compared later to infer their relative momentum-scale shift + // without circularly applying a pre-existing correction first. + TLorentzVector kplusRaw; + TLorentzVector kminusRaw; + kplusRaw.SetXYZM(t.phid1Px(), t.phid1Py(), t.phid1Pz(), mKPDG); + kminusRaw.SetXYZM(t.phid2Px(), t.phid2Py(), t.phid2Pz(), mKPDG); + const TLorentzVector phiForResolution = kplusRaw + kminusRaw; + const double dPhiKK = TVector2::Phi_mpi_pi(kplusRaw.Phi() - kminusRaw.Phi()); + if (phiForResolution.Pt() >= minPhiPt && phiForResolution.Pt() <= maxPhiPt) { + histos.fill(HIST("PhiMassResolutionDataDriven"), + phiForResolution.M(), + kplusRaw.Pt(), kminusRaw.Pt(), + kplusRaw.Eta(), kminusRaw.Eta(), + dPhiKK, phiForResolution.Pt()); + } + } + + // From here onward keep the original signal-phi definition unchanged. + if (phi1.Pt() < minPhiPt || phi1.Pt() > maxPhiPt) { + continue; + } + if (phi1Mass < minPhiMass1 || phi1Mass > maxPhiMass1) { + continue; + } + histos.fill(HIST("hnsigmaTPCTOFKaon"), t.phid1TPC(), t.phid1TOF(), kpluspt); histos.fill(HIST("hnsigmaTPCKaonPlus"), t.phid1TPC(), kpluspt); histos.fill(HIST("hnsigmaTPCKaonMinus"), t.phid2TPC(), kminuspt); - histos.fill(HIST("hPhiMassVsPt"), t.phiMass(), phi1.Pt()); + histos.fill(HIST("hPhiMassVsPt"), phi1Mass, phi1.Pt()); ++phimult; } @@ -1621,9 +1961,6 @@ struct doublephimeson { return; } - constexpr double mPhiPDG = o2::constants::physics::MassPhi; // GeV/c^2 - constexpr double mKPDG = o2::constants::physics::MassKPlus; // GeV/c^2 - const auto deltaMPhiNominal = [=](double m1, double m2) { const double d1 = m1 - mPhiPDG; const double d2 = m2 - mPhiPDG; @@ -1635,30 +1972,99 @@ struct doublephimeson { const double deta = eta1 - eta2; return std::sqrt(dphi * dphi + deta * deta); }; - const auto minKaonDeltaR = [&](const ROOT::Math::PtEtaPhiMVector& kplus1, - const ROOT::Math::PtEtaPhiMVector& kminus1, - const ROOT::Math::PtEtaPhiMVector& kplus2, - const ROOT::Math::PtEtaPhiMVector& kminus2) { - const double dRkplus = deltaR(kplus1.Phi(), kplus1.Eta(), kplus2.Phi(), kplus2.Eta()); - const double dRkminus = deltaR(kminus1.Phi(), kminus1.Eta(), kminus2.Phi(), kminus2.Eta()); - histos.fill(HIST("hDeltaRkaonplus"), dRkplus); - histos.fill(HIST("hDeltaRkaonminus"), dRkminus); + const auto minKaonDeltaR = + [&](const ROOT::Math::PtEtaPhiMVector& kplus1, + const ROOT::Math::PtEtaPhiMVector& kminus1, + const ROOT::Math::PtEtaPhiMVector& kplus2, + const ROOT::Math::PtEtaPhiMVector& kminus2) { + const double dRpp = + deltaR(kplus1.Phi(), kplus1.Eta(), + kplus2.Phi(), kplus2.Eta()); - double minDR = dRkplus; - minDR = std::min(minDR, dRkminus); - minDR = std::min(minDR, deltaR(kplus1.Phi(), kplus1.Eta(), kminus1.Phi(), kminus1.Eta())); - minDR = std::min(minDR, deltaR(kplus1.Phi(), kplus1.Eta(), kminus2.Phi(), kminus2.Eta())); - minDR = std::min(minDR, deltaR(kplus2.Phi(), kplus2.Eta(), kminus1.Phi(), kminus1.Eta())); - minDR = std::min(minDR, deltaR(kplus2.Phi(), kplus2.Eta(), kminus2.Phi(), kminus2.Eta())); + const double dRmm = + deltaR(kminus1.Phi(), kminus1.Eta(), + kminus2.Phi(), kminus2.Eta()); - return minDR; + const double dRpm = + deltaR(kplus1.Phi(), kplus1.Eta(), + kminus2.Phi(), kminus2.Eta()); + + const double dRmp = + deltaR(kminus1.Phi(), kminus1.Eta(), + kplus2.Phi(), kplus2.Eta()); + + histos.fill(HIST("hDeltaRkaonplus"), dRpp); + histos.fill(HIST("hDeltaRkaonminus"), dRmm); + return std::min({dRpp, dRmm, dRpm, dRmp}); + }; + + const auto phiPtAsymmetry = + [](const auto& phi1, + const auto& phi2) -> double { + const double sumPt = phi1.Pt() + phi2.Pt(); + + if (sumPt <= 0.) { + return -1.; + } + + return std::abs(phi1.Pt() - phi2.Pt()) / sumPt; + }; + + const auto nKaonTOFHits = + [](const auto& t1, const auto& t2) -> int { + return static_cast(t1.phid1TOFHit() == 1) + + static_cast(t1.phid2TOFHit() == 1) + + static_cast(t2.phid1TOFHit() == 1) + + static_cast(t2.phid2TOFHit() == 1); + }; + + const auto doublePhiPIDScore = + [](const auto& t1, const auto& t2) -> double { + const auto kaonPIDScore = + [](double nSigmaTPC, + double nSigmaTOF, + int tofHit) -> double { + // TOFHit is 1 when TOF is available and -1 otherwise. + if (tofHit == 1) { + return std::sqrt( + (nSigmaTPC * nSigmaTPC + + nSigmaTOF * nSigmaTOF)); + } + + // TPC-only track + return std::abs(nSigmaTPC); + }; + + const double pid1 = + kaonPIDScore(t1.phid1TPC(), + t1.phid1TOF(), + t1.phid1TOFHit()); + + const double pid2 = + kaonPIDScore(t1.phid2TPC(), + t1.phid2TOF(), + t1.phid2TOFHit()); + + const double pid3 = + kaonPIDScore(t2.phid1TPC(), + t2.phid1TOF(), + t2.phid1TOFHit()); + + const double pid4 = + kaonPIDScore(t2.phid2TPC(), + t2.phid2TOF(), + t2.phid2TOFHit()); + + return std::max({pid1, pid2, pid3, pid4}); }; std::vector pairV; std::vector phi1V; std::vector phi2V; std::vector minDRV; + std::vector nTOFV; + std::vector pid4KV; for (auto const& t1 : phitracks) { const double kplus1pt = std::hypot(t1.phid1Px(), t1.phid1Py()); @@ -1678,11 +2084,10 @@ struct doublephimeson { TLorentzVector k1p; TLorentzVector k1m; - phi1.SetXYZM(t1.phiPx(), t1.phiPy(), t1.phiPz(), t1.phiMass()); - k1p.SetXYZM(t1.phid1Px(), t1.phid1Py(), t1.phid1Pz(), mKPDG); - k1m.SetXYZM(t1.phid2Px(), t1.phid2Py(), t1.phid2Pz(), mKPDG); + buildPhiAndKaons(t1, phi1, k1p, k1m); + const double phi1Mass = cfgApplyKaonMomentumCorrection ? phi1.M() : t1.phiMass(); - if (t1.phiMass() < minPhiMass1 || t1.phiMass() > maxPhiMass1) { + if (phi1Mass < minPhiMass1 || phi1Mass > maxPhiMass1) { continue; } if (phi1.Pt() < minPhiPt || phi1.Pt() > maxPhiPt) { @@ -1694,6 +2099,7 @@ struct doublephimeson { for (auto const& t2 : phitracks) { const auto id2 = t2.index(); if (id2 <= id1) { + // LOGF(info, "track reject %d %d %f %f", id1, id2, t1.phiMass(), t2.phiMass()); continue; } const double kplus2pt = std::hypot(t2.phid1Px(), t2.phid1Py()); @@ -1713,11 +2119,10 @@ struct doublephimeson { TLorentzVector k2p; TLorentzVector k2m; - phi2.SetXYZM(t2.phiPx(), t2.phiPy(), t2.phiPz(), t2.phiMass()); - k2p.SetXYZM(t2.phid1Px(), t2.phid1Py(), t2.phid1Pz(), mKPDG); - k2m.SetXYZM(t2.phid2Px(), t2.phid2Py(), t2.phid2Pz(), mKPDG); + buildPhiAndKaons(t2, phi2, k2p, k2m); + const double phi2Mass = cfgApplyKaonMomentumCorrection ? phi2.M() : t2.phiMass(); - if (t2.phiMass() < minPhiMass2 || t2.phiMass() > maxPhiMass2) { + if (phi2Mass < minPhiMass1 || phi2Mass > maxPhiMass1) { continue; } if (phi2.Pt() < minPhiPt || phi2.Pt() > maxPhiPt) { @@ -1751,6 +2156,32 @@ struct doublephimeson { continue; // another pairing of these four tracks is better } } + + // Compact candidate-level input for the data-driven X resolution. + // Fill only in the requested X mass window and above the X pT threshold. + // At this point the candidate has already passed: + // - daughter pT/PID selections, + // - phi mass and phi pT selections, + // - pair pT / broad pair-mass selections, + // - shared-track rejection, + // - cross-pairing rejection. + // + // Use the same four-vectors that define the selected candidate. Thus, + // if cfgApplyKaonMomentumCorrection is enabled, the sparse consistently + // stores the corrected candidate kinematics; otherwise it stores raw + // reconstructed kinematics. + if (cfgFillSelectedXResolutionSparse && + pair.Pt() > cfgSelectedXResolutionPtMin && + pair.M() > cfgSelectedXResolutionMassLow && + pair.M() < cfgSelectedXResolutionMassHigh) { + histos.fill(HIST("SelectedXResolutionDataDriven"), + pair.Pt(), + phi1.M(), phi2.M(), + phi1.Pt(), phi2.Pt(), + k1p.Pt(), k1m.Pt(), + k2p.Pt(), k2m.Pt()); + } + histos.fill(HIST("hPhiMass"), phi1.M(), phi2.M(), pair.Pt()); histos.fill(HIST("hPhiMassNormalized"), getNormalizedMPhi(phi1.M(), phi1.Pt()), getNormalizedMPhi(phi2.M(), phi2.Pt()), pair.Pt()); @@ -1760,11 +2191,14 @@ struct doublephimeson { ROOT::Math::PtEtaPhiMVector k2mV(k2m.Pt(), k2m.Eta(), k2m.Phi(), mKPDG); const double minDR = minKaonDeltaR(k1pV, k1mV, k2pV, k2mV); - + const int nTOF = nKaonTOFHits(t1, t2); + const double pid4K = doublePhiPIDScore(t1, t2); pairV.emplace_back(pair.Pt(), pair.Eta(), pair.Phi(), pair.M()); phi1V.emplace_back(phi1.Pt(), phi1.Eta(), phi1.Phi(), phi1.M()); phi2V.emplace_back(phi2.Pt(), phi2.Eta(), phi2.Phi(), phi2.M()); minDRV.emplace_back(minDR); + nTOFV.emplace_back(nTOF); + pid4KV.emplace_back(pid4K); } } @@ -1785,6 +2219,8 @@ struct doublephimeson { const double pairPt = pair.Pt(); const double dRphi = deltaR(p1.Phi(), p1.Eta(), p2.Phi(), p2.Eta()); const double minDR = minDRV[i]; + const double combine4kpid = pid4KV[i]; + const double nkaonTOF = nTOFV[i]; if (!useParametrized) { dMNominal = deltaMPhiNominal(p1.M(), p2.M()); } else { @@ -1801,6 +2237,9 @@ struct doublephimeson { if (ptsum <= 0.0) { continue; } + const double apt = phiPtAsymmetry(p1, p2); + // const double absCosTheta = absCosThetaStar(p1, p2); + if (pairPt > minExoticPt) { histos.fill(HIST("hPtCorrelation"), pairPt, ptcorr); // histos.fill(HIST("hMassCent"), p1.M(), p2.M(), collision.centrality()); @@ -1815,6 +2254,17 @@ struct doublephimeson { dMNominalNsigma, ptcorr, pairV.size()); + + histos.fill(HIST("SEMassDoublePhi"), + M, + pairPt, + apt, + std::abs(pair.Rapidity()), + p1.M(), + p2.M(), + dMNominal, + nkaonTOF, + combine4kpid); } } } diff --git a/PWGLF/Tasks/Resonances/f0980analysis.cxx b/PWGLF/Tasks/Resonances/f0980analysis.cxx index 257e8a464fc..7efd84760e3 100644 --- a/PWGLF/Tasks/Resonances/f0980analysis.cxx +++ b/PWGLF/Tasks/Resonances/f0980analysis.cxx @@ -284,7 +284,7 @@ struct f0980analysis { } template - bool selPion(const TrackType track) + bool selPion(const TrackType& track) { switch (selectType) { case 0: diff --git a/PWGLF/Tasks/Resonances/f0980pbpbanalysis.cxx b/PWGLF/Tasks/Resonances/f0980pbpbanalysis.cxx index bb40ed8b46e..832b4e47a1a 100644 --- a/PWGLF/Tasks/Resonances/f0980pbpbanalysis.cxx +++ b/PWGLF/Tasks/Resonances/f0980pbpbanalysis.cxx @@ -361,7 +361,7 @@ struct F0980pbpbanalysis { // Event selection template - bool eventSelected(TCollision collision, const bool QA) + bool eventSelected(const TCollision& collision, const bool QA) { if (QAConfig.cfgQAEventCut && QA) fillQA(false, collision, 1); @@ -438,7 +438,7 @@ struct F0980pbpbanalysis { // Track selection template - bool trackSelected(const TrackType track, const bool QA) + bool trackSelected(const TrackType& track, const bool QA) { if (QAConfig.cfgQATrackCut && QA) fillQA(false, track, 3); @@ -519,7 +519,7 @@ struct F0980pbpbanalysis { // PID selection template - bool selectionPID(const TrackType track, const bool QA) + bool selectionPID(const TrackType& track, const bool QA) { if (QA) fillQA(false, track, 4); @@ -580,7 +580,7 @@ struct F0980pbpbanalysis { } // PID selection template - bool pairAngleSelection(const TrackType1 track1, const TrackType2 track2) + bool pairAngleSelection(const TrackType1& track1, const TrackType2& track2) { double pt1, pt2, pz1, pz2, p1, p2, angle; pt1 = track1.pt(); @@ -597,7 +597,7 @@ struct F0980pbpbanalysis { } template - float getTpcNSigma(const TrackType track) + float getTpcNSigma(const TrackType& track) { if (cfgListPtl == PtlList::PtlPion) { return track.tpcNSigmaPi(); @@ -607,7 +607,7 @@ struct F0980pbpbanalysis { } template - float getTofNSigma(const TrackType track) + float getTofNSigma(const TrackType& track) { if (cfgListPtl == PtlList::PtlPion) { return track.tofNSigmaPi(); diff --git a/PWGLF/Tasks/Resonances/f1protoncorrelation.cxx b/PWGLF/Tasks/Resonances/f1protoncorrelation.cxx index f466066c980..193cc5e105b 100644 --- a/PWGLF/Tasks/Resonances/f1protoncorrelation.cxx +++ b/PWGLF/Tasks/Resonances/f1protoncorrelation.cxx @@ -464,7 +464,7 @@ struct f1protoncorrelation { /// Magnetic field to be provided in Tesla static constexpr float tmpRadiiTPC[9] = {85., 105., 125., 145., 165., 185., 205., 225., 245.}; - float PhiAtSpecificRadiiTPC(const TLorentzVector part1, const TLorentzVector part2, float charge1 = 0, int charge2 = 0, float magfield1 = 0.0, float magfield2 = 0.0) + float PhiAtSpecificRadiiTPC(const TLorentzVector& part1, const TLorentzVector& part2, float charge1 = 0, int charge2 = 0, float magfield1 = 0.0, float magfield2 = 0.0) { float pt1 = part1.Pt(); float phi1 = part1.Phi(); @@ -496,8 +496,8 @@ struct f1protoncorrelation { // get kstar TLorentzVector trackSum, PartOneCMS, PartTwoCMS, trackRelK; - float getkstar(const TLorentzVector part1, - const TLorentzVector part2) + float getkstar(const TLorentzVector& part1, + const TLorentzVector& part2) { // const TLorentzVector trackSum = part1 + part2; trackSum = part1 + part2; @@ -517,7 +517,7 @@ struct f1protoncorrelation { return 0.5 * trackRelK.P(); } - float getmT(const TLorentzVector part1, const TLorentzVector part2) + float getmT(const TLorentzVector& part1, const TLorentzVector& part2) { trackSum = part1 + part2; float kT = 0.5 * trackSum.Pt(); @@ -543,7 +543,7 @@ struct f1protoncorrelation { } lastRunNumber = currentRunNumber; - for (auto f1track : f1tracks) { + for (const auto& f1track : f1tracks) { if (f1track.f1MassKaonKshort() > maxKKS0Mass) { continue; } @@ -593,7 +593,7 @@ struct f1protoncorrelation { if (typeofCombined == 1) { combinedTPC = (f1track.f1d1TPC() - f1track.f1d2TPC()) / (f1track.f1d1TPC() + f1track.f1d2TPC()); } - for (auto protontrack : protontracks) { + for (const auto& protontrack : protontracks) { Proton.SetXYZM(protontrack.protonPx(), protontrack.protonPy(), protontrack.protonPz(), 0.938); if (Proton.Pt() > momentumProtonMax || Proton.Pt() < momentumProtonMin) { continue; @@ -975,7 +975,7 @@ struct f1protoncorrelation { lastRunNumber = currentRunNumber; auto countf1 = 0; - for (auto f1track : f1tracks) { + for (const auto& f1track : f1tracks) { if (f1track.f1MassKaonKshort() > maxKKS0Mass) continue; @@ -1021,7 +1021,7 @@ struct f1protoncorrelation { continue; // Proton loop - for (auto protontrack : protontracks) { + for (const auto& protontrack : protontracks) { Proton.SetXYZM(protontrack.protonPx(), protontrack.protonPy(), protontrack.protonPz(), 0.938); if ((f1track.f1PionIndex() == protontrack.f1ProtonIndex()) || diff --git a/PWGLF/Tasks/Resonances/heptaquark.cxx b/PWGLF/Tasks/Resonances/heptaquark.cxx index 351ff08ab0a..f5da2552359 100644 --- a/PWGLF/Tasks/Resonances/heptaquark.cxx +++ b/PWGLF/Tasks/Resonances/heptaquark.cxx @@ -261,7 +261,7 @@ struct heptaquark { if (collision.numLambda() < 1 || collision.numPhi() < 2) return; - for (auto hqtrackd1 : hqtracks) { + for (const auto& hqtrackd1 : hqtracks) { if (hqtrackd1.hqId() != 333) continue; @@ -289,7 +289,7 @@ struct heptaquark { auto hqd1id = hqtrackd1.index(); histos.fill(HIST("hPhid1Mass"), HQ1.M(), HQ1.Pt()); - for (auto hqtrackd2 : hqtracks) { + for (const auto& hqtrackd2 : hqtracks) { auto hqd2id = hqtrackd2.index(); if (hqd2id <= hqd1id) continue; @@ -325,7 +325,7 @@ struct heptaquark { histos.fill(HIST("hnsigmaTOFKa"), hqtrackd2.hqd2TOF(), DauVec2.Pt()); histos.fill(HIST("hPhid2Mass"), HQ2.M(), HQ2.Pt()); - for (auto hqtrackd3 : hqtracks) { + for (const auto& hqtrackd3 : hqtracks) { if (std::abs(hqtrackd3.hqId()) != 3122) continue; diff --git a/PWGLF/Tasks/Resonances/highmasslambda.cxx b/PWGLF/Tasks/Resonances/highmasslambda.cxx index c0827bfe7d2..cf2df918881 100644 --- a/PWGLF/Tasks/Resonances/highmasslambda.cxx +++ b/PWGLF/Tasks/Resonances/highmasslambda.cxx @@ -591,7 +591,7 @@ struct highmasslambda { histos.fill(HIST("hVtxZ"), collision.posZ()); histos.fill(HIST("hOccupancy"), occupancy); auto firstprimarytrack = 0; - for (auto track1 : tracks) { + for (const auto& track1 : tracks) { if (!selectionTrack(track1)) { continue; } @@ -626,7 +626,7 @@ struct highmasslambda { histos.fill(HIST("hNsigmaProtonTOF"), track1.tofNSigmaPr(), track1.pt()); } auto track1ID = track1.globalIndex(); - for (auto v0 : V0s) { + for (const auto& v0 : V0s) { if (firstprimarytrack == 0) { histos.fill(HIST("hInvMassKs0before"), v0.mK0Short()); } @@ -872,7 +872,7 @@ struct highmasslambda { histos.fill(HIST("hVtxZ"), collision.posZ()); histos.fill(HIST("hOccupancy"), occupancy); auto firstprimarytrack = 0; - for (auto track1 : tracks) { + for (const auto& track1 : tracks) { if (!selectionTrack(track1)) { continue; } @@ -906,7 +906,7 @@ struct highmasslambda { auto trackParCovBach = getTrackParCov(track1); // auto trackParCovBach = getTrackParCov(bach); - for (auto v0 : V0s) { + for (const auto& v0 : V0s) { if (!SelectionV0(collision, v0)) { continue; } diff --git a/PWGLF/Tasks/Resonances/highmasslambdasvx.cxx b/PWGLF/Tasks/Resonances/highmasslambdasvx.cxx index cc971733c05..c3ece46c3c8 100644 --- a/PWGLF/Tasks/Resonances/highmasslambdasvx.cxx +++ b/PWGLF/Tasks/Resonances/highmasslambdasvx.cxx @@ -573,7 +573,7 @@ struct highmasslambdasvx { histos.fill(HIST("hVtxZ"), collision.posZ()); histos.fill(HIST("hOccupancy"), occupancy); auto firstprimarytrack = 0; - for (auto track1 : tracks) { + for (const auto& track1 : tracks) { if (!selectionTrack(track1)) { continue; } @@ -611,7 +611,7 @@ struct highmasslambdasvx { histos.fill(HIST("hNsigmaProtonTOF"), track1.tofNSigmaPr(), track1.pt()); auto track1ID = track1.globalIndex(); auto trackParCovBach = getTrackParCov(track1); - for (auto v0 : V0s) { + for (const auto& v0 : V0s) { if (!SelectionV0(collision, v0)) { continue; } diff --git a/PWGLF/Tasks/Resonances/initializereventqa.cxx b/PWGLF/Tasks/Resonances/initializereventqa.cxx index 81b12b19534..ad8e4e89ea5 100644 --- a/PWGLF/Tasks/Resonances/initializereventqa.cxx +++ b/PWGLF/Tasks/Resonances/initializereventqa.cxx @@ -169,7 +169,7 @@ struct Initializereventqa { Partition globalTracksIUEta05 = (nabs(aod::track::eta) < globalEta05) && (requireGlobalTrackInFilter()); template - uint16_t getGenNchInFT0Mregion(TMcParticles particles) + uint16_t getGenNchInFT0Mregion(const TMcParticles& particles) { float region1FT0 = -3.3f; float region2FT0 = -2.1f; diff --git a/PWGLF/Tasks/Resonances/k1AnalysisMicro.cxx b/PWGLF/Tasks/Resonances/k1AnalysisMicro.cxx index e636df0f774..0cbab0d427c 100644 --- a/PWGLF/Tasks/Resonances/k1AnalysisMicro.cxx +++ b/PWGLF/Tasks/Resonances/k1AnalysisMicro.cxx @@ -265,7 +265,7 @@ struct K1AnalysisMicro { int kK1Plus = 10323; template - bool trackCut(const TrackType track) + bool trackCut(const TrackType& track) { if constexpr (!IsResoMicrotrack) { // basic track cuts diff --git a/PWGLF/Tasks/Resonances/k892analysis.cxx b/PWGLF/Tasks/Resonances/k892analysis.cxx index 8dea9031fc7..ee26e771a1e 100644 --- a/PWGLF/Tasks/Resonances/k892analysis.cxx +++ b/PWGLF/Tasks/Resonances/k892analysis.cxx @@ -320,7 +320,7 @@ struct K892analysis { double massPi = MassPionCharged; template - bool eventSelected(TCollision collision, const float& centrality) + bool eventSelected(const TCollision& collision, const float& centrality) { // if (collision.alias_bit(kTVXinTRD)) { // // TRD triggered @@ -342,7 +342,7 @@ struct K892analysis { } template - bool trackCut(const TrackType track) + bool trackCut(const TrackType& track) { // basic track cuts if (std::abs(track.pt()) < cMinPtcut) diff --git a/PWGLF/Tasks/Resonances/k892hadronphotonBkg.cxx b/PWGLF/Tasks/Resonances/k892hadronphotonBkg.cxx index 239897406f0..07e7490a3a4 100644 --- a/PWGLF/Tasks/Resonances/k892hadronphotonBkg.cxx +++ b/PWGLF/Tasks/Resonances/k892hadronphotonBkg.cxx @@ -81,6 +81,8 @@ struct k892hadronphotonBkg { Configurable doPPAnalysis{"doPPAnalysis", true, "if in pp, set to true"}; + Configurable doArm{"doArm", true, "Fill the 3D Armenteros histograms"}; + // For ML Selection Configurable useMLScores{"useMLScores", false, "use ML scores to select candidates"}; @@ -244,7 +246,10 @@ struct k892hadronphotonBkg { ConfigurableAxis axisKStarMass{"axisKStarMass", {500, 0.6f, 1.6f}, "M_{K^{*}} (GeV/c^{2})"}; ConfigurableAxis axisLambdaStarMass{"axisLambdaStarMass", {500, 1.1f, 2.1f}, "M_{#Lambda(1520)} (GeV/c^{2})"}; ConfigurableAxis axisIRBinning{"axisIRBinning", {151, -10, 1500}, "Binning for the interaction rate (kHz)"}; + ConfigurableAxis axisAPAlpha{"axisAPAlpha", {220, -1.1f, 1.1f}, "Resonance AP alpha (#gamma = positive leg)"}; + ConfigurableAxis axisAPQt{"axisAPQt", {220, 0.0f, 1.1f}, "Resonance AP q_{T} (GeV/c)"}; ConfigurableAxis axisCandSel{"axisCandSel", {15, 0.5f, +15.5f}, "Candidate Selection"}; + ConfigurableAxis axisOPAngle{"axisOPAngle", {140, 0.0f, 7.0f}, "Opening angle (rad)"}; } axisConfig; void init(InitContext const&) @@ -311,12 +316,18 @@ struct k892hadronphotonBkg { if (kstarBkgConfig.doSameEvtRotation) { histos.add("KStarBkg/h2dRotKStarMassVsPt", "h2dRotKStarMassVsPt", kTH2D, {axisConfig.axisKStarMass, axisConfig.axisPt}); histos.add("KStarBkg/h3dRotKStarMassVsPt", "h3dRotKStarMassVsPt", kTH3D, {axisConfig.axisCentrality, axisConfig.axisPt, axisConfig.axisKStarMass}); - histos.add("KStarBkg/h3dRotKStarPtVsOPAngle", "h3dRotKStarPtVsOPAngle", kTH3D, {{140, 0.f, 7.f}, axisConfig.axisPt, axisConfig.axisKStarMass}); + histos.add("KStarBkg/h3dRotKStarPtVsOPAngle", "h3dRotKStarPtVsOPAngle", kTH3D, {axisConfig.axisOPAngle, axisConfig.axisPt, axisConfig.axisKStarMass}); + if (doArm) { + histos.add("KStarBkg/h4dRotKStarPtVsAPAlphaVsAPQt", "h4dRotKStarPtVsAPAlphaVsAPQt", kTHnD, {axisConfig.axisAPAlpha, axisConfig.axisAPQt, axisConfig.axisPt, axisConfig.axisKStarMass}); + } } if (kstarBkgConfig.doEvtMixing) { histos.add("KStarBkg/h2dMixedKStarMassVsPt", "h2dMixedKStarMassVsPt", kTH2D, {axisConfig.axisKStarMass, axisConfig.axisPt}); histos.add("KStarBkg/h3dMixedKStarMassVsPt", "h3dMixedKStarMassVsPt", kTH3D, {axisConfig.axisCentrality, axisConfig.axisPt, axisConfig.axisKStarMass}); - histos.add("KStarBkg/h3dMixedKStarPtVsOPAngle", "h3dMixedKStarPtVsOPAngle", kTH3D, {{140, 0.f, 7.f}, axisConfig.axisPt, axisConfig.axisKStarMass}); + histos.add("KStarBkg/h3dMixedKStarPtVsOPAngle", "h3dMixedKStarPtVsOPAngle", kTH3D, {axisConfig.axisOPAngle, axisConfig.axisPt, axisConfig.axisKStarMass}); + if (doArm) { + histos.add("KStarBkg/h4dMixedKStarPtVsAPAlphaVsAPQt", "h4dMixedKStarPtVsAPAlphaVsAPQt", kTHnD, {axisConfig.axisAPAlpha, axisConfig.axisAPQt, axisConfig.axisPt, axisConfig.axisKStarMass}); + } } // Lambda(1520) -> Lambda + gamma @@ -327,12 +338,18 @@ struct k892hadronphotonBkg { if (lstarBkgConfig.doSameEvtRotation) { histos.add("LambdaStarBkg/h2dRotLambdaStarMassVsPt", "h2dRotLambdaStarMassVsPt", kTH2D, {axisConfig.axisLambdaStarMass, axisConfig.axisPt}); histos.add("LambdaStarBkg/h3dRotLambdaStarMassVsPt", "h3dRotLambdaStarMassVsPt", kTH3D, {axisConfig.axisCentrality, axisConfig.axisPt, axisConfig.axisLambdaStarMass}); - histos.add("LambdaStarBkg/h3dRotLambdaStarPtVsOPAngle", "h3dRotLambdaStarPtVsOPAngle", kTH3D, {{140, 0.f, 7.f}, axisConfig.axisPt, axisConfig.axisLambdaStarMass}); + histos.add("LambdaStarBkg/h3dRotLambdaStarPtVsOPAngle", "h3dRotLambdaStarPtVsOPAngle", kTH3D, {axisConfig.axisOPAngle, axisConfig.axisPt, axisConfig.axisLambdaStarMass}); + if (doArm) { + histos.add("LambdaStarBkg/h4dRotLambdaStarPtVsAPAlphaVsAPQt", "h4dRotLambdaStarPtVsAPAlphaVsAPQt", kTHnD, {axisConfig.axisAPAlpha, axisConfig.axisAPQt, axisConfig.axisPt, axisConfig.axisLambdaStarMass}); + } } if (lstarBkgConfig.doEvtMixing) { histos.add("LambdaStarBkg/h2dMixedLambdaStarMassVsPt", "h2dMixedLambdaStarMassVsPt", kTH2D, {axisConfig.axisLambdaStarMass, axisConfig.axisPt}); histos.add("LambdaStarBkg/h3dMixedLambdaStarMassVsPt", "h3dMixedLambdaStarMassVsPt", kTH3D, {axisConfig.axisCentrality, axisConfig.axisPt, axisConfig.axisLambdaStarMass}); - histos.add("LambdaStarBkg/h3dMixedLambdaStarPtVsOPAngle", "h3dMixedLambdaStarPtVsOPAngle", kTH3D, {{140, 0.f, 7.f}, axisConfig.axisPt, axisConfig.axisLambdaStarMass}); + histos.add("LambdaStarBkg/h3dMixedLambdaStarPtVsOPAngle", "h3dMixedLambdaStarPtVsOPAngle", kTH3D, {axisConfig.axisOPAngle, axisConfig.axisPt, axisConfig.axisLambdaStarMass}); + if (doArm) { + histos.add("LambdaStarBkg/h4dMixedLambdaStarPtVsAPAlphaVsAPQt", "h4dMixedLambdaStarPtVsAPAlphaVsAPQt", kTHnD, {axisConfig.axisAPAlpha, axisConfig.axisAPQt, axisConfig.axisPt, axisConfig.axisLambdaStarMass}); + } } } @@ -755,6 +772,27 @@ struct k892hadronphotonBkg { return true; } + //_______________________________________________ + // Armenteros-Podolanski variables of the (photon + hadron) pair. + static float armenterosAlpha(std::array const& photonP, + std::array const& hadronP) + { + const std::array momRes{photonP[0] + hadronP[0], photonP[1] + hadronP[1], photonP[2] + hadronP[2]}; + const double momTot = RecoDecay::p(momRes); + const double lQlNeg = RecoDecay::dotProd(hadronP, momRes) / momTot; + const double lQlPos = RecoDecay::dotProd(photonP, momRes) / momTot; + return (lQlPos - lQlNeg) / (lQlPos + lQlNeg); + } + + static float armenterosQt(std::array const& photonP, + std::array const& hadronP) + { + const std::array momRes{photonP[0] + hadronP[0], photonP[1] + hadronP[1], photonP[2] + hadronP[2]}; + const double momTot2 = RecoDecay::p2(momRes); + const double dp = RecoDecay::dotProd(hadronP, momRes); + return std::sqrt(RecoDecay::p2(hadronP) - dp * dp / momTot2); + } + //_______________________________________________ // Compute same-event rotational background within a single collision. template @@ -800,10 +838,10 @@ struct k892hadronphotonBkg { ROOT::Math::PtEtaPhiMVector hRot(hadron.pt(), hadron.eta(), hadron.phi() + theta, HadronMass); ROOT::Math::PtEtaPhiMVector gRot(photon.pt(), photon.eta(), photon.phi() + theta, o2::constants::physics::MassGamma); - auto reso = pGamma + hRot; - if (rotGamma) { - reso = gRot + pHadron; - } + const auto& gammaLeg = rotGamma ? gRot : pGamma; + const auto& hadronLeg = rotGamma ? pHadron : hRot; + + auto reso = gammaLeg + hadronLeg; float rapidity = RecoDecay::y(std::array{static_cast(reso.Px()), static_cast(reso.Py()), @@ -812,22 +850,30 @@ struct k892hadronphotonBkg { if (std::abs(rapidity) > maxRap) continue; - // Opening angle between photon and rotated hadron (QA only, not used as a cut) - double cosOA = pGamma.Vect().Dot(hRot.Vect()) / (pGamma.P() * hRot.P()); - if (rotGamma) { - cosOA = gRot.Vect().Dot(pHadron.Vect()) / (gRot.P() * pHadron.P()); - } - + // Opening angle between photon and hadron + double cosOA = gammaLeg.Vect().Dot(hadronLeg.Vect()) / (gammaLeg.P() * hadronLeg.P()); double openAngle = std::acos(cosOA); + // Armenteros-Podolanski of the rotated pair + const std::array gammaMom{static_cast(gammaLeg.Px()), static_cast(gammaLeg.Py()), static_cast(gammaLeg.Pz())}; + const std::array hadronMom{static_cast(hadronLeg.Px()), static_cast(hadronLeg.Py()), static_cast(hadronLeg.Pz())}; + const float apAlpha = armenterosAlpha(gammaMom, hadronMom); + const float apQt = armenterosQt(gammaMom, hadronMom); + if constexpr (resonance == kResoKStar) { histos.fill(HIST("KStarBkg/h2dRotKStarMassVsPt"), reso.M(), reso.Pt()); histos.fill(HIST("KStarBkg/h3dRotKStarMassVsPt"), centrality, reso.Pt(), reso.M()); histos.fill(HIST("KStarBkg/h3dRotKStarPtVsOPAngle"), openAngle, reso.Pt(), reso.M()); + if (doArm) { + histos.fill(HIST("KStarBkg/h4dRotKStarPtVsAPAlphaVsAPQt"), apAlpha, apQt, reso.Pt(), reso.M()); + } } else { histos.fill(HIST("LambdaStarBkg/h2dRotLambdaStarMassVsPt"), reso.M(), reso.Pt()); histos.fill(HIST("LambdaStarBkg/h3dRotLambdaStarMassVsPt"), centrality, reso.Pt(), reso.M()); histos.fill(HIST("LambdaStarBkg/h3dRotLambdaStarPtVsOPAngle"), openAngle, reso.Pt(), reso.M()); + if (doArm) { + histos.fill(HIST("LambdaStarBkg/h4dRotLambdaStarPtVsAPAlphaVsAPQt"), apAlpha, apQt, reso.Pt(), reso.M()); + } } } } @@ -885,14 +931,26 @@ struct k892hadronphotonBkg { if (std::abs(rapidity) > maxRap) continue; + // Armenteros-Podolanski of the mixed pair + const std::array gammaMom{photon.px(), photon.py(), photon.pz()}; + const std::array hadronMom{hadron.px(), hadron.py(), hadron.pz()}; + const float apAlpha = armenterosAlpha(gammaMom, hadronMom); + const float apQt = armenterosQt(gammaMom, hadronMom); + if constexpr (resonance == kResoKStar) { histos.fill(HIST("KStarBkg/h2dMixedKStarMassVsPt"), mass, pt); histos.fill(HIST("KStarBkg/h3dMixedKStarMassVsPt"), centrality, pt, mass); histos.fill(HIST("KStarBkg/h3dMixedKStarPtVsOPAngle"), openAngle, pt, mass); + if (doArm) { + histos.fill(HIST("KStarBkg/h4dMixedKStarPtVsAPAlphaVsAPQt"), apAlpha, apQt, pt, mass); + } } else { histos.fill(HIST("LambdaStarBkg/h2dMixedLambdaStarMassVsPt"), mass, pt); histos.fill(HIST("LambdaStarBkg/h3dMixedLambdaStarMassVsPt"), centrality, pt, mass); histos.fill(HIST("LambdaStarBkg/h3dMixedLambdaStarPtVsOPAngle"), openAngle, pt, mass); + if (doArm) { + histos.fill(HIST("LambdaStarBkg/h4dMixedLambdaStarPtVsAPAlphaVsAPQt"), apAlpha, apQt, pt, mass); + } } } } diff --git a/PWGLF/Tasks/Resonances/k892pmanalysis.cxx b/PWGLF/Tasks/Resonances/k892pmanalysis.cxx index 0abd5992a29..f30d7c1ae28 100644 --- a/PWGLF/Tasks/Resonances/k892pmanalysis.cxx +++ b/PWGLF/Tasks/Resonances/k892pmanalysis.cxx @@ -197,7 +197,7 @@ struct k892pmanalysis { double massAntiLambda0 = MassLambda0Bar; template - bool trackCut(const TrackType track) + bool trackCut(const TrackType& track) { // basic track cuts if (std::abs(track.pt()) < cMinPtcut) @@ -219,7 +219,7 @@ struct k892pmanalysis { } template - bool V0Cut(const V0Type v0) + bool V0Cut(const V0Type& v0) { // V0 track cuts if (std::abs(v0.eta()) > cMaxV0Etacut) diff --git a/PWGLF/Tasks/Resonances/kaonkaonanalysis.cxx b/PWGLF/Tasks/Resonances/kaonkaonanalysis.cxx index 55d41750b35..19abecac1e1 100644 --- a/PWGLF/Tasks/Resonances/kaonkaonanalysis.cxx +++ b/PWGLF/Tasks/Resonances/kaonkaonanalysis.cxx @@ -454,7 +454,7 @@ struct kaonkaonAnalysisRun3 { histos.fill(HIST("multdist_FT0A"), collision.multFT0A()); histos.fill(HIST("multdist_FT0C"), collision.multFT0C()); } - for (auto track1 : tracks) { + for (const auto& track1 : tracks) { if (!selectionTrack(track1)) { continue; } @@ -467,7 +467,7 @@ struct kaonkaonAnalysisRun3 { histos.fill(HIST("hNsigmaKaonTOF_TPC_before"), track1.tofNSigmaKa(), track1.tpcNSigmaKa()); } auto track1ID = track1.index(); - for (auto track2 : tracks) { + for (const auto& track2 : tracks) { if (!selectionTrack(track2)) { continue; } @@ -605,7 +605,7 @@ struct kaonkaonAnalysisRun3 { } auto daughtp = false; auto daughtm = false; - for (auto kCurrentDaughter : kDaughters) { + for (const auto& kCurrentDaughter : kDaughters) { if (!kCurrentDaughter.isPhysicalPrimary()) { continue; } @@ -634,7 +634,7 @@ struct kaonkaonAnalysisRun3 { histos.fill(HIST("Recmutiplicity"), multiplicity); histos.fill(HIST("hMC"), 5.5); auto oldindex = -999; - for (auto track1 : tracks) { + for (const auto& track1 : tracks) { if (!selectionTrack(track1)) { continue; } @@ -642,7 +642,7 @@ struct kaonkaonAnalysisRun3 { continue; } auto track1ID = track1.index(); - for (auto track2 : tracks) { + for (const auto& track2 : tracks) { if (!track2.has_mcParticle()) { continue; } diff --git a/PWGLF/Tasks/Resonances/kstar0analysis.cxx b/PWGLF/Tasks/Resonances/kstar0analysis.cxx index 3cbc9f29503..4755b2e0a0b 100644 --- a/PWGLF/Tasks/Resonances/kstar0analysis.cxx +++ b/PWGLF/Tasks/Resonances/kstar0analysis.cxx @@ -436,7 +436,7 @@ struct Kstar0analysis { // Centralicity estimator selection template - float centEst(Coll collisions) + float centEst(const Coll& collisions) { float returnValue = -999.0f; switch (centEstimator) { @@ -503,7 +503,7 @@ struct Kstar0analysis { } template - bool trackCut(const TrackType track) + bool trackCut(const TrackType& track) { // basic track cuts if (configTracks.cDCAr7SigCut && std::abs(track.dcaXY()) > (0.004f + 0.013f / (track.pt()))) // 7 - Sigma cut diff --git a/PWGLF/Tasks/Resonances/kstar892analysis.cxx b/PWGLF/Tasks/Resonances/kstar892analysis.cxx index ad8b6d9e3d8..3e7626203df 100644 --- a/PWGLF/Tasks/Resonances/kstar892analysis.cxx +++ b/PWGLF/Tasks/Resonances/kstar892analysis.cxx @@ -331,7 +331,7 @@ struct kstar892analysis { float massPi = MassPionCharged; template - bool trackCut(const TrackType track) + bool trackCut(const TrackType& track) { // TPC if (track.tpcNClsFound() < cfgTPCcluster) diff --git a/PWGLF/Tasks/Resonances/kstarInOO.cxx b/PWGLF/Tasks/Resonances/kstarInOO.cxx index 0a3e99db80c..d16f1be1818 100644 --- a/PWGLF/Tasks/Resonances/kstarInOO.cxx +++ b/PWGLF/Tasks/Resonances/kstarInOO.cxx @@ -963,7 +963,7 @@ struct kstarInOO { } // TrackSlicingMC template - double DistinguishJets(const JetType& jets, ROOT::Math::PxPyPzMVector& lResonance) + double DistinguishJets(const JetType& jets, const ROOT::Math::PxPyPzMVector& lResonance) { if (cDebugLevel > 0) { LOG(info) << "Found multiple jets to the same phi."; @@ -1176,7 +1176,7 @@ struct kstarInOO { bool HasJets = false; int nJets = 0; - for (auto chargedjet : chargedjets) { + for (const auto& chargedjet : chargedjets) { if (std::abs(chargedjet.eta()) > (cfgJetMaxEta - cfgJetdR)) { continue; } @@ -1263,7 +1263,7 @@ struct kstarInOO { bool HasJets = false; int nJets = 0; - for (auto mcdjet : mcdjets) { + for (const auto& mcdjet : mcdjets) { if (std::abs(mcdjet.eta()) > cfgJetMaxEta - cfgJetdR) { continue; } diff --git a/PWGLF/Tasks/Resonances/lambda1405analysis.cxx b/PWGLF/Tasks/Resonances/lambda1405analysis.cxx index 83eb796ac94..06385d1a370 100644 --- a/PWGLF/Tasks/Resonances/lambda1405analysis.cxx +++ b/PWGLF/Tasks/Resonances/lambda1405analysis.cxx @@ -839,7 +839,7 @@ struct lambda1405analysis { aod::KinkCands::iterator const& sigmaCand, TracksFull const& tracks, std::vector& selectedCandidates, - TBinningType binPolicy) + const TBinningType& binPolicy) { lambda1405candidate lambda1405Cand{}; @@ -1112,7 +1112,7 @@ struct lambda1405analysis { } template - void fillOutputData(const TCollision& collision, const TCand& sigmaCands, const TTrack& tracks, TBinningType binPolicy) + void fillOutputData(const TCollision& collision, const TCand& sigmaCands, const TTrack& tracks, const TBinningType& binPolicy) { if (std::abs(collision.posZ()) > eventSelection.cutZVertex || !collision.sel8()) { return; diff --git a/PWGLF/Tasks/Resonances/lambda1520SpherocityAnalysis.cxx b/PWGLF/Tasks/Resonances/lambda1520SpherocityAnalysis.cxx index 390bfd1768a..d5543744f89 100644 --- a/PWGLF/Tasks/Resonances/lambda1520SpherocityAnalysis.cxx +++ b/PWGLF/Tasks/Resonances/lambda1520SpherocityAnalysis.cxx @@ -345,7 +345,7 @@ struct lambdaAnalysis { // kinematic cuts method template - bool kinCuts(trackType trkPr, trackType trkKa, T p, float& alpha) + bool kinCuts(const trackType& trkPr, const trackType& trkKa, const T& p, float& alpha) { // initialize std::vector kinCutsPt = static_cast>(cKinCutsPt); diff --git a/PWGLF/Tasks/Resonances/lambda1520analysis.cxx b/PWGLF/Tasks/Resonances/lambda1520analysis.cxx index d09b4f18dda..b45c29e6070 100644 --- a/PWGLF/Tasks/Resonances/lambda1520analysis.cxx +++ b/PWGLF/Tasks/Resonances/lambda1520analysis.cxx @@ -356,7 +356,7 @@ struct Lambda1520analysis { double massPr = MassProton; template - bool trackCut(const TrackType track) + bool trackCut(const TrackType& track) { // basic track cuts if (std::abs(track.pt()) < cMinPtcut) diff --git a/PWGLF/Tasks/Resonances/lambda1520analysisinOO.cxx b/PWGLF/Tasks/Resonances/lambda1520analysisinOO.cxx index 77a0d4403b1..1aa84ce8085 100644 --- a/PWGLF/Tasks/Resonances/lambda1520analysisinOO.cxx +++ b/PWGLF/Tasks/Resonances/lambda1520analysisinOO.cxx @@ -438,7 +438,7 @@ struct Lstaranalysis { // Centralicity estimator selection template - float centEst(ResoColl ResoEvents) + float centEst(const ResoColl& ResoEvents) { float returnValue = -999.0; switch (multEstimator) { @@ -477,7 +477,7 @@ struct Lstaranalysis { } template - bool trackCut(const TrackType track) + bool trackCut(const TrackType& track) { // basic track cuts if (std::abs(track.pt()) < cMinPtcut) diff --git a/PWGLF/Tasks/Resonances/lambdav2.cxx b/PWGLF/Tasks/Resonances/lambdav2.cxx index ea87a33f1fb..59d6e11bd2c 100644 --- a/PWGLF/Tasks/Resonances/lambdav2.cxx +++ b/PWGLF/Tasks/Resonances/lambdav2.cxx @@ -306,7 +306,7 @@ struct lambdav2 { histos.fill(HIST("hpQxpQytvscent"), centrality, QxpQyt); histos.fill(HIST("hpQxtQypvscent"), centrality, QxtQyp); - for (auto track : tracks) { + for (const auto& track : tracks) { if (!selectionTrack(track)) { continue; } diff --git a/PWGLF/Tasks/Resonances/lstarpbpbv2.cxx b/PWGLF/Tasks/Resonances/lstarpbpbv2.cxx index 216cc36f7b0..f62d6f87927 100644 --- a/PWGLF/Tasks/Resonances/lstarpbpbv2.cxx +++ b/PWGLF/Tasks/Resonances/lstarpbpbv2.cxx @@ -420,7 +420,7 @@ struct lstarpbpbv2 { histos.fill(HIST("ResFT0CFT0ASP"), centrality, QFT0C * QFT0A * TMath::Cos(2.0 * (psiFT0C - psiFT0A))); histos.fill(HIST("ResFT0ATPCSP"), centrality, QTPC * QFT0A * TMath::Cos(2.0 * (psiTPC - psiFT0A))); - for (auto track1 : tracks) { + for (const auto& track1 : tracks) { if (!selectionTrack(track1)) { continue; } @@ -431,7 +431,7 @@ struct lstarpbpbv2 { } track1kaon = true; - for (auto track2 : tracks) { + for (const auto& track2 : tracks) { if (!selectionTrack(track2)) { continue; } diff --git a/PWGLF/Tasks/Resonances/phianalysis.cxx b/PWGLF/Tasks/Resonances/phianalysis.cxx index eff17aa8a87..43a2c49027a 100644 --- a/PWGLF/Tasks/Resonances/phianalysis.cxx +++ b/PWGLF/Tasks/Resonances/phianalysis.cxx @@ -138,7 +138,7 @@ struct phianalysis { double massKa = MassKaonCharged; template - bool trackCut(const TrackType track) + bool trackCut(const TrackType& track) { // basic track cuts if (std::abs(track.pt()) < cMinPtcut) diff --git a/PWGLF/Tasks/Resonances/phianalysisTHnSparse.cxx b/PWGLF/Tasks/Resonances/phianalysisTHnSparse.cxx index 1489f7109f6..85a1bcdb45e 100644 --- a/PWGLF/Tasks/Resonances/phianalysisTHnSparse.cxx +++ b/PWGLF/Tasks/Resonances/phianalysisTHnSparse.cxx @@ -13,8 +13,11 @@ /// \brief Analysis of phi resonance using THnSparse histograms. /// \author Veronika Barbasova (veronika.barbasova@cern.ch) +#include "PWGLF/DataModel/mcCentrality.h" +#include "PWGLF/Utils/inelGt.h" #include "PWGLF/Utils/rsnOutput.h" +#include "Common/CCDB/EventSelectionParams.h" #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" @@ -40,11 +43,14 @@ #include #include +#include +#include #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) #include #include #include #include +#include #include @@ -59,45 +65,51 @@ using namespace o2::framework::expressions; struct PhianalysisTHnSparse { - SliceCache cache; + SliceCache cache, cacheMC, cacheME; struct : ConfigurableGroup { - Configurable produceQA{"produceQA", false, "Produce qa histograms."}; - Configurable produceStats{"produceStats", false, "Produce statistics histograms."}; - Configurable produceTrue{"produceTrue", false, "Produce True and Gen histograms."}; + Configurable produceQA{"produceQA", false, "Produce QA histograms."}; + Configurable produceMC{"produceMC", false, "Produce True and Gen histograms."}; Configurable produceLikesign{"produceLikesign", false, "Produce Like sign histograms."}; Configurable eventMixing{"eventMixing", "none", "Produce Event Mixing histograms of type."}; Configurable produceRotational{"produceRotational", false, "Produce Rotational histograms."}; } produce; - Configurable daughterPos{"daughterPos", 3, "Particle type of the positive dauther according to ReconstructionDataFormats/PID.h (Default = Kaon)"}; - Configurable daughterNeg{"daughterNeg", 3, "Particle type of the negative dauther according to ReconstructionDataFormats/PID.h (Default = Kaon)"}; + Configurable daughterPos{"daughterPos", 3, "Particle type of the positive daughter according to ReconstructionDataFormats/PID.h (Default = Kaon)"}; + Configurable daughterNeg{"daughterNeg", 3, "Particle type of the negative daughter according to ReconstructionDataFormats/PID.h (Default = Kaon)"}; Configurable motherPDG{"motherPDG", 333, "PDG code of mother particle."}; - Configurable daughterPosPDG{"daughterPosPDG", 321, "PDG code of positive dauther particle."}; - Configurable daughterNegPDG{"daughterNegPDG", 321, "PDG code of negative dauther particle."}; + Configurable daughterPosPDG{"daughterPosPDG", 321, "PDG code of positive daughter particle."}; + Configurable daughterNegPDG{"daughterNegPDG", 321, "PDG code of negative daughter particle."}; struct : ConfigurableGroup { - Configurable tpcnSigmaPos{"tpcnSigmaPos", 3.0f, "TPC NSigma cut of the positive particle."}; - Configurable tpcnSigmaNeg{"tpcnSigmaNeg", 3.0f, "TPC NSigma cut of the negative particle."}; - Configurable tpcPidOnly{"tpcPidOnly", false, "Use TPC only for PID."}; - Configurable combinedNSigma{"combinedNSigma", 3.0f, "Combined NSigma cut for combined TPC and TOF NSigma cut."}; - Configurable ptTOFThreshold{"ptTOFThreshold", 0.5f, "Threshold for applying TOF."}; - Configurable rapidity{"rapidity", 0.5f, "Rapidity cut (maximum)."}; - Configurable etatrack{"etatrack", 0.8f, "Eta cut for track."}; - Configurable pt{"pt", 0.15f, "Cut: Minimal value of tracks pt."}; - Configurable dcaXY{"dcaXY", 1.0f, "Cut: Maximal value of tracks DCA XY."}; - Configurable dcaZ{"dcaZ", 1.0f, "Cut: Maximal value of tracks DCA Z."}; - Configurable globalTrack{"globalTrack", false, "Use global track selection."}; - Configurable inelGrater0{"inelGrater0", true, "Select events with INEL>0."}; - Configurable tpcNClsFound{"tpcNClsFound", 70, "Cut: Minimal value of found TPC clasters"}; + Configurable isTriggerTVX{"isTriggerTVX", false, "Apply IsTriggerTVX cut."}; + Configurable noTimeFrameBorder{"noTimeFrameBorder", false, "Apply NoTimeFrameBorder cut."}; + Configurable noITSROFrameBorder{"noITSROFrameBorder", false, "Apply NoITSROFrameBorder cut."}; + Configurable sel8{"sel8", false, "Apply Sel8 cut."}; + Configurable inelGt0{"inelGt0", false, "Select events with INEL>0."}; Configurable vzCut{"vzCut", 10.0f, "Cut: Maximal value of Z vertex position."}; - } cut; + Configurable noSameBunchPileup{"noSameBunchPileup", false, "Apply no same bunch pileup cut."}; + Configurable isVertexITSTPC{"isVertexITSTPC", false, "Apply IsVertexITSTPC cut."}; + Configurable isGoodZvtxFT0vsPV{"isGoodZvtxFT0vsPV", false, "Apply IsGoodZvtxFT0vsPV cut."}; + } eventCuts; struct : ConfigurableGroup { - Configurable verboselevel{"verboselevel", 0, "Verbose level"}; - Configurable refresh{"refresh", 0, "Freqency of print event information."}; - Configurable refreshIndex{"refreshIndex", 0, "Freqency of print event information index."}; - } verbose; + Configurable pt{"pt", 0.15f, "Cut: Minimal value of tracks pt."}; + Configurable etatrack{"etatrack", 1.0f, "Cut: Maximal value of tracks eta."}; + Configurable dcaXY{"dcaXY", 1.0f, "Cut: Maximal value of tracks DCA XY."}; + Configurable dcaZ{"dcaZ", 1.0f, "Cut: Maximal value of tracks DCA Z."}; + Configurable tpcnSigmaPos{"tpcnSigmaPos", 10.0f, "Cut: Maximal value of TPC NSigma of the positive particle."}; + Configurable tpcnSigmaNeg{"tpcnSigmaNeg", 10.0f, "Cut: Maximal value of TPC NSigma of the negative particle."}; + Configurable tpcPidOnly{"tpcPidOnly", false, "Use TPC only for PID."}; + Configurable combinedNSigma{"combinedNSigma", 3.0f, "Cut: Maximal value of NSigma for combined TPC and TOF NSigma cut."}; + Configurable ptTOFThreshold{"ptTOFThreshold", 0.5f, "Cut: Minimal value of tracks pt for using TOF PID."}; + Configurable tpcNClsFound{"tpcNClsFound", 0, "Cut: Minimal value of found TPC clusters"}; + Configurable tpcNClsCrossedRows{"tpcNClsCrossedRows", 0, "Cut: Minimal value of crossed rows in TPC"}; + Configurable globalTrack{"globalTrack", false, "Use isGlobalTrack track selection."}; + Configurable primaryTrack{"primaryTrack", false, "Use isPrimaryTrack track selection."}; + Configurable pvContributor{"pvContributor", false, "Use isPVContributor track selection."}; + Configurable rapidity{"rapidity", 0.5f, "Cut: Maximal value of particle rapidity."}; + } trackCuts; Configurable> sparseAxes{"sparseAxes", std::vector{o2::analysis::rsn::pair_axis::names}, "Axes."}; Configurable> sysAxes{"sysAxes", std::vector{o2::analysis::rsn::systematic_axis::names}, "Axes."}; @@ -107,69 +119,68 @@ struct PhianalysisTHnSparse { ConfigurableAxis vzaxis{"vzaxis", {40, -20., 20.}, "Z vertex position axis binning."}; ConfigurableAxis multiplicityaxis{"multiplicityaxis", {50, 0., 5000.}, "Multiplicity axis binning."}; ConfigurableAxis centralityaxis{"centralityaxis", {20, 0., 100.}, "Centrality axis binning."}; - ConfigurableAxis etaaxis{"etaaxis", {16., -1.0 * static_cast(cut.etatrack), static_cast(cut.etatrack)}, "Pseudorapidity axis binning."}; - ConfigurableAxis rapidityaxis{"rapidityaxis", {10., -1.0 * static_cast(cut.rapidity), static_cast(cut.rapidity)}, "Rapidity axis binning."}; - ConfigurableAxis nsigmaaxisPos{"nsigmaaxisPos", {1, -static_cast(cut.tpcnSigmaPos), static_cast(cut.tpcnSigmaPos)}, "NSigma of positive particle axis binning in THnSparse."}; - ConfigurableAxis nsigmaaxisNeg{"nsigmaaxisNeg", {1, -static_cast(cut.tpcnSigmaNeg), static_cast(cut.tpcnSigmaNeg)}, "NSigma of negative particle axis binning in THnSparse."}; + ConfigurableAxis etaaxis{"etaaxis", {16., -1.0 * static_cast(trackCuts.etatrack), static_cast(trackCuts.etatrack)}, "Pseudorapidity axis binning."}; + ConfigurableAxis rapidityaxis{"rapidityaxis", {10., -1.0 * static_cast(trackCuts.rapidity), static_cast(trackCuts.rapidity)}, "Rapidity axis binning."}; + ConfigurableAxis nsigmaaxisPos{"nsigmaaxisPos", {1, -static_cast(trackCuts.tpcnSigmaPos), static_cast(trackCuts.tpcnSigmaPos)}, "NSigma of positive particle axis binning in THnSparse."}; + ConfigurableAxis nsigmaaxisNeg{"nsigmaaxisNeg", {1, -static_cast(trackCuts.tpcnSigmaNeg), static_cast(trackCuts.tpcnSigmaNeg)}, "NSigma of negative particle axis binning in THnSparse."}; // mixing - using BinningTypeVzMu = ColumnBinningPolicy>; + using BinningTypeVzMu = ColumnBinningPolicy>; using BinningTypeVzCe = ColumnBinningPolicy; - Configurable numberofMixedEvents{"numberofMixedEvents", 5, "Number of events that should be mixed."}; + Configurable nMixedEvents{"nMixedEvents", 5, "Number of events that should be mixed."}; ConfigurableAxis axisVertexMixing{"axisVertexMixing", {5, -10, 10}, "Z vertex axis binning for mixing"}; - ConfigurableAxis axisMultiplicityMixing{"axisMultiplicityMixing", {5, 0, 5000}, "TPC multiplicity for bin"}; - ConfigurableAxis axisCentralityMixing{"axisCentralityMixing", {10, 0, 100}, "Multiplicity percentil binning for mixing"}; + ConfigurableAxis axisMultiplicityMixing{"axisMultiplicityMixing", {5, 0, 5000}, "FT0M amplitude binning for event mixing."}; + ConfigurableAxis axisCentralityMixing{"axisCentralityMixing", {10, 0, 100}, "FT0M centrality percentile binning for event mixing."}; // rotational - Configurable numberofRotations{"numberofRotations", 1, "Number of rotations for rotational background estimation."}; + Configurable nRotations{"nRotations", 1, "Number of rotations for rotational background estimation."}; Configurable startingAngle{"startingAngle", 0, "Starting angle for rotational background estimation."}; // other axes - ConfigurableAxis axisNch{"axisNch", {1000, 0.0f, +1000.0f}, "Number of charged particles."}; - ConfigurableAxis axisResolutionPt{"axisResolutionPt", {1001, -1.0f, +1.0f}, "Resolution of Pt."}; - ConfigurableAxis axisResolutionPtPhi{"axisResolutionPtPhi", {1001, -0.01f, +0.01f}, "Resolution of Pt and Phi."}; - ConfigurableAxis axisResolutionMass{"axisResolutionMass", {1001, -0.01f, +0.01f}, "Resolution of Mass."}; - ConfigurableAxis axisResolutionVz{"axisResolutionVz", {1001, -3.0f, +3.0f}, "Resolution of Vz."}; - ConfigurableAxis massShiftAxis{"massShiftAxis", {1001, -0.02f, 0.02f}, "Mass correction axis."}; + ConfigurableAxis axisNch{"axisNch", {1000, 0.0, +1000.0}, "Number of charged particles."}; + ConfigurableAxis axisResolutionPt{"axisResolutionPt", {1001, -1.0, +1.0}, "Resolution of Pt."}; + ConfigurableAxis axisResolutionPtPhi{"axisResolutionPtPhi", {1001, -0.01, +0.01}, "Resolution of Pt and Phi."}; + ConfigurableAxis axisResolutionMass{"axisResolutionMass", {1001, -0.01, +0.01}, "Resolution of Mass."}; + ConfigurableAxis axisResolutionVz{"axisResolutionVz", {1001, -3.0, +3.0}, "Resolution of Vz."}; + ConfigurableAxis axisQAPt{"axisQAPt", {15, 0.0, 15.0}, "QA Pt axis binning."}; + ConfigurableAxis axisQAMult{"axisQAMult", {10, 0.0, 100.0}, "QA Multiplicity axis binning."}; + ConfigurableAxis axisQACent{"axisQACent", {101, 0.0f, 101.0f}, "QA Centrality axis binning."}; // Axes specifications - AxisSpec posZaxis = {400, -20., 20., "V_{z} (cm)"}; - AxisSpec dcaXYaxis = {1000, -1.0, 1.0, "DCA_{xy} (cm)"}; - AxisSpec dcaZaxis = {1000, -1.0, 1.0, "DCA_{z} (cm)"}; - AxisSpec etaQAaxis = {1000, -1.0, 1.0, "#eta"}; - AxisSpec tpcNClsFoundQAaxis = {110, 50., 160., "tpcNClsFound"}; - AxisSpec massShiftRelAxis = {101, -0.03f, 0.03f, ""}; + AxisSpec vzQAaxis = {200, -20., 20., "V_{z} (cm)"}; + AxisSpec dcaXYQAaxis = {200, -0.5, 0.5, "DCA_{xy} (cm)"}; + AxisSpec dcaZQAaxis = {200, -0.5, 0.5, "DCA_{z} (cm)"}; + AxisSpec etaQAaxis = {200, -1.0, 1.0, "#eta"}; + AxisSpec rapidityQAaxis = {200, -1.0, 1.0, "y"}; + AxisSpec tpcNClsQAaxis = {200, 0., 200., "TPC NClusters"}; + AxisSpec nSigmaTPCQAaxis = {200, -10., 10., "n#sigma_{TPC} K^{#pm}"}; + AxisSpec nSigmaTOFQAaxis = {200, -10., 10., "n#sigma_{TOF} K^{#pm}"}; + AxisSpec pQAaxis = {1490, 0.1, 15.0, "p (GeV/c)"}; + AxisSpec dEdxQAaxis = {2000, 0., 200., "dE/dx (a.u.)"}; + AxisSpec betaQAaxis = {700, 0.5, 1.2, "#beta"}; + AxisSpec dPhiQAaxis = {100, -o2::constants::math::TwoPI, o2::constants::math::TwoPI, "#Delta#phi (rad)"}; + AxisSpec dThetaQAaxis = {100, -o2::constants::math::PI, o2::constants::math::PI, "#Delta#theta (rad)"}; + AxisSpec dEtaQAaxis = {200, -1.0, 1.0, "#Delta#eta"}; HistogramRegistry registry{"registry"}; o2::analysis::rsn::Output* rsnOutput = nullptr; - Service pdg; + Service pdg{}; - int n = 0; float massPos = o2::track::PID::getMass(3); float massNeg = o2::track::PID::getMass(3); int pion = 2; int kaon = 3; int proton = 4; double* pointPair = nullptr; - double* pointSys = nullptr; ROOT::Math::PxPyPzMVector d1, d2, mother, motherGen; - bool produceTrue, produceLikesign, produceQA, produceStats, produceRotational, dataQA, MCTruthQA, globalTrack, inelGrater0, tpcPidOnly = false; - float tpcnSigmaPos = 100.0f; - float tpcnSigmaNeg = 100.0f; - float combinedNSigma = 100.0f; - float ptTOFThreshold = 0.5f; - int tpcNClsFound = 70; + bool dataQA = false; int dauSize = 2; - float vzCut = 10.0f; rsn::MixingType mixingType = rsn::MixingType::none; - Filter triggerFilter = (o2::aod::evsel::sel8 == true); - Filter vtxFilter = (nabs(o2::aod::collision::posZ) < vzCut); - using EventCandidates = soa::Join; using EventCandidate = EventCandidates::iterator; - using TrackCandidates = soa::Join; + using TrackCandidates = soa::Join; using EventCandidatesMC = soa::Join; using TrackCandidatesMC = soa::Join; @@ -194,13 +205,18 @@ struct PhianalysisTHnSparse { LOGF(info, " Positive: %d, mass: %f", static_cast(daughterPos), massPos); LOGF(info, " Negative: %d, mass: %f", static_cast(daughterNeg), massNeg); + AxisSpec centQAAxis = {axisQACent, "FT0M (%)"}; + AxisSpec nchQAAxis = {axisNch, "N_{ch}"}; + AxisSpec multQAAxis = {axisQAMult, "FT0M (%)"}; + AxisSpec ptQAAxis = {axisQAPt, "p_{T} (GeV/c)"}; + // Sparse axes AxisSpec invAxis = {invaxis, "Inv. mass (GeV/c^{2})", "im"}; AxisSpec ptAxis = {ptaxis, "p_{T} (GeV/c)", "pt"}; - AxisSpec muAxis = {multiplicityaxis, "N", "mu"}; - AxisSpec mumAxis = {multiplicityaxis, "N", "mum"}; - AxisSpec ceAxis = {centralityaxis, "N", "ce"}; - AxisSpec cemAxis = {centralityaxis, "N", "cem"}; + AxisSpec muAxis = {multiplicityaxis, "FT0M (Ampl.)", "mu"}; + AxisSpec mumAxis = {multiplicityaxis, "FT0M (Ampl.)", "mum"}; + AxisSpec ceAxis = {centralityaxis, "FT0M (%)", "ce"}; + AxisSpec cemAxis = {centralityaxis, "FT0M (%)", "cem"}; AxisSpec etaAxis = {etaaxis, "#eta", "eta"}; AxisSpec yAxis = {rapidityaxis, "y", "y"}; AxisSpec nsAxisPos = {nsigmaaxisPos, fmt::format("nSigma of positive particle ({})", massPos), "ns1"}; @@ -216,55 +232,43 @@ struct PhianalysisTHnSparse { std::vector allAxes = {invAxis, ptAxis, muAxis, ceAxis, nsAxisPos, nsAxisNeg, etaAxis, yAxis, vzAxis, mumAxis, cemAxis, vzmAxis}; std::vector allAxesSys = {tpcNClsFoundAxis}; - produceQA = static_cast(produce.produceQA); - produceStats = static_cast(produce.produceStats); - produceTrue = static_cast(produce.produceTrue); - produceLikesign = static_cast(produce.produceLikesign); mixingType = rsn::mixingTypeName(static_cast(produce.eventMixing)); - produceRotational = static_cast(produce.produceRotational); - tpcnSigmaPos = static_cast(cut.tpcnSigmaPos); - tpcnSigmaNeg = static_cast(cut.tpcnSigmaNeg); - tpcNClsFound = static_cast(cut.tpcNClsFound); - globalTrack = static_cast(cut.globalTrack); - inelGrater0 = static_cast(cut.inelGrater0); - combinedNSigma = static_cast(cut.combinedNSigma); - tpcPidOnly = static_cast(cut.tpcPidOnly); - ptTOFThreshold = static_cast(cut.ptTOFThreshold); - vzCut = static_cast(cut.vzCut); pointPair = new double[static_cast(o2::analysis::rsn::PairAxisType::unknown)]; - pointSys = new double[static_cast(o2::analysis::rsn::SystematicsAxisType::unknown)]; rsnOutput = new o2::analysis::rsn::OutputSparse(); - rsnOutput->init(sparseAxes, allAxes, sysAxes, allAxesSys, produceTrue, mixingType, produceLikesign, produceRotational, ®istry); + rsnOutput->init(sparseAxes, allAxes, sysAxes, allAxesSys, static_cast(produce.produceMC), mixingType, static_cast(produce.produceLikesign), static_cast(produce.produceRotational), static_cast(eventCuts.inelGt0), ®istry); // Print summary of configuration LOGF(info, "=== PhianalysisTHnSparse configuration summary ==="); - LOGF(info, "produceQA: %s", produceQA ? "true" : "false"); - LOGF(info, "produceStats: %s", produceStats ? "true" : "false"); - LOGF(info, "produceTrue: %s", static_cast(produce.produceTrue) ? "true" : "false"); + LOGF(info, "produceMC: %s", static_cast(produce.produceMC) ? "true" : "false"); LOGF(info, "produceLikesign: %s", static_cast(produce.produceLikesign) ? "true" : "false"); LOGF(info, "produceRotational: %s", static_cast(produce.produceRotational) ? "true" : "false"); LOGF(info, "eventMixing: %s", static_cast(produce.eventMixing).c_str()); + LOGF(info, "inelGt0: %s", static_cast(eventCuts.inelGt0) ? "true" : "false"); + LOGF(info, "noSameBunchPileup: %s", static_cast(eventCuts.noSameBunchPileup) ? "true" : "false"); + LOGF(info, "isVertexITSTPC: %s", static_cast(eventCuts.isVertexITSTPC) ? "true" : "false"); + LOGF(info, "isGoodZvtxFT0vsPV: %s", static_cast(eventCuts.isGoodZvtxFT0vsPV) ? "true" : "false"); + LOGF(info, "vzCut: %.2f", static_cast(eventCuts.vzCut)); LOGF(info, "daughterPos: %d (PDG: %d)", static_cast(daughterPos), static_cast(daughterPosPDG)); LOGF(info, "daughterNeg: %d (PDG: %d)", static_cast(daughterNeg), static_cast(daughterNegPDG)); LOGF(info, "motherPDG: %d", static_cast(motherPDG)); - LOGF(info, "tpcnSigmaPos: %.2f", tpcnSigmaPos); - LOGF(info, "tpcnSigmaNeg: %.2f", tpcnSigmaNeg); - LOGF(info, "tpcPidOnly: %s", tpcPidOnly ? "true" : "false"); - LOGF(info, "combinedNSigma: %.2f", combinedNSigma); - LOGF(info, "ptTOFThreshold: %.2f", ptTOFThreshold); - LOGF(info, "rapidity: %.2f", static_cast(cut.rapidity)); - LOGF(info, "etatrack: %.2f", static_cast(cut.etatrack)); - LOGF(info, "pt (min): %.2f", static_cast(cut.pt)); - LOGF(info, "dcaXY: %.2f", static_cast(cut.dcaXY)); - LOGF(info, "dcaZ: %.2f", static_cast(cut.dcaZ)); - LOGF(info, "globalTrack: %s", globalTrack ? "true" : "false"); - LOGF(info, "inelGrater0: %s", inelGrater0 ? "true" : "false"); - LOGF(info, "tpcNClsFound: %d", tpcNClsFound); - LOGF(info, "vzCut: %.2f", vzCut); - LOGF(info, "mixingType: %d", static_cast(mixingType)); - LOGF(info, "numberofMixedEvents: %d", static_cast(numberofMixedEvents)); - LOGF(info, "numberofRotations: %d", static_cast(numberofRotations)); + LOGF(info, "pt (min): %.2f", static_cast(trackCuts.pt)); + LOGF(info, "eta (max): %.2f", static_cast(trackCuts.etatrack)); + LOGF(info, "dcaXY: %.2f", static_cast(trackCuts.dcaXY)); + LOGF(info, "dcaZ: %.2f", static_cast(trackCuts.dcaZ)); + LOGF(info, "tpcnSigmaPos: %.2f", static_cast(trackCuts.tpcnSigmaPos)); + LOGF(info, "tpcnSigmaNeg: %.2f", static_cast(trackCuts.tpcnSigmaNeg)); + LOGF(info, "tpcPidOnly: %s", static_cast(trackCuts.tpcPidOnly) ? "true" : "false"); + LOGF(info, "combinedNSigma: %.2f", static_cast(trackCuts.combinedNSigma)); + LOGF(info, "ptTOFThreshold: %.2f", static_cast(trackCuts.ptTOFThreshold)); + LOGF(info, "tpcNClsFound: %d", static_cast(trackCuts.tpcNClsFound)); + LOGF(info, "tpcNClsCrossedRows: %d", static_cast(trackCuts.tpcNClsCrossedRows)); + LOGF(info, "globalTrack: %s", static_cast(trackCuts.globalTrack) ? "true" : "false"); + LOGF(info, "primaryTrack: %s", static_cast(trackCuts.primaryTrack) ? "true" : "false"); + LOGF(info, "pvContributor: %s", static_cast(trackCuts.pvContributor) ? "true" : "false"); + LOGF(info, "rapidity: %.2f", static_cast(trackCuts.rapidity)); + LOGF(info, "nMixedEvents: %d", static_cast(nMixedEvents)); + LOGF(info, "nRotations: %d", static_cast(nRotations)); LOGF(info, "startingAngle: %d", static_cast(startingAngle)); LOGF(info, "sparseAxes: "); for (const auto& axis : static_cast>(sparseAxes)) { @@ -276,222 +280,319 @@ struct PhianalysisTHnSparse { } LOGF(info, "==============================================="); - if (produceQA) { - // Event QA - registry.add("QAEvent/hSelection", "Event selection statistics", kTH1D, {{4, 0.0f, 4.0f}}); - auto hEvent = registry.get(HIST("QAEvent/hSelection")); + // ------------------- Event QA ------------------- + + registry.add("QA/Event/hVtxZ", "Vertex position along the z-axis", kTH1F, {vzQAaxis}); + auto hVtxZ = registry.get(HIST("QA/Event/hVtxZ")); + + registry.add("QA/Event/hCent", "FT0M (%)", kTH1F, {{101, 0., 101.}}); + auto hCent = registry.get(HIST("QA/Event/hCent")); + hCent->GetXaxis()->SetTitle("FT0M (%)"); + registry.add("QA/Event/hMult", "Amplitude of non-zero channels in the FT0A + FT0C) ", kTH1F, {{300, 0., 30000.}}); + auto hMult = registry.get(HIST("QA/Event/hMult")); + hMult->GetXaxis()->SetTitle("FT0M Ampl."); + + if (static_cast(produce.produceQA)) { + + registry.add("QA/Event/hSelection", "Event selection statistics", kTH1D, {{11, 0.0f, 11.0f}}); + auto hEvent = registry.get(HIST("QA/Event/hSelection")); hEvent->GetXaxis()->SetBinLabel(1, "all events"); - hEvent->GetXaxis()->SetBinLabel(2, "Events passing trigger sel8"); - hEvent->GetXaxis()->SetBinLabel(3, "Events passing |V_{z}| cut"); - hEvent->GetXaxis()->SetBinLabel(4, "Events passing INEL>0 cut"); + hEvent->GetXaxis()->SetBinLabel(2, Form("|V_{z}| < %0.0f cm", static_cast(eventCuts.vzCut))); + hEvent->GetXaxis()->SetBinLabel(3, "isTriggerTVX"); + hEvent->GetXaxis()->SetBinLabel(4, "noTimeFrameBorder"); + hEvent->GetXaxis()->SetBinLabel(5, "noITSROFrameBorder"); + hEvent->GetXaxis()->SetBinLabel(6, "sel8"); + hEvent->GetXaxis()->SetBinLabel(7, "IsVertexITSTPC"); + hEvent->GetXaxis()->SetBinLabel(8, "noSameBunchPileup"); + hEvent->GetXaxis()->SetBinLabel(9, "IsGoodZvtxFT0vsPV"); + hEvent->GetXaxis()->SetBinLabel(10, "INEL"); + hEvent->GetXaxis()->SetBinLabel(11, "INEL>0"); hEvent->SetMinimum(0.1); - registry.add("QAEvent/hVtxZ", "Vertex position along the z-axis", kTH1F, {posZaxis}); - registry.add("QAEvent/hCent", "Distribution of multiplicity percentile", kTH1F, {{101, 0., 101.}}); - registry.add("QAEvent/hMult", "Multiplicity (amplitude of non-zero channels in the FT0A + FT0C) ", kTH1F, {{300, 0., 30000.}}); + registry.add("QA/Event/hCentNch", "Event centrality vs multiplicity", kTH2F, {centQAAxis, nchQAAxis}); - // Track QA - registry.add("QATrack/hSelection", "Tracks statistics", kTH1D, {{9, 0.0f, 9.0f}}); - auto hTrack = registry.get(HIST("QATrack/hSelection")); + // ----------------------- Track QA ----------------------- + registry.add("QA/Track/hSelection", "Track selection statistics", kTH1D, {{9, 0.0f, 9.0f}}); + auto hTrack = registry.get(HIST("QA/Track/hSelection")); hTrack->GetXaxis()->SetBinLabel(1, "all tracks"); - hTrack->GetXaxis()->SetBinLabel(2, "passed pT cut"); - hTrack->GetXaxis()->SetBinLabel(3, "passed eta cut"); - hTrack->GetXaxis()->SetBinLabel(4, "passed DCA cut"); - hTrack->GetXaxis()->SetBinLabel(5, "passed PID cut"); - hTrack->GetXaxis()->SetBinLabel(6, "passed tpcNClsFound cut"); - hTrack->GetXaxis()->SetBinLabel(7, "passed isPrimaryTrack cut"); - hTrack->GetXaxis()->SetBinLabel(8, "passed isPVContributor cut"); - hTrack->GetXaxis()->SetBinLabel(9, "passed all cuts"); + hTrack->GetXaxis()->SetBinLabel(2, Form("pT > %.2f", static_cast(trackCuts.pt))); + hTrack->GetXaxis()->SetBinLabel(3, Form("eta < %.1f", static_cast(trackCuts.etatrack))); + hTrack->GetXaxis()->SetBinLabel(4, "DCA cuts"); + hTrack->GetXaxis()->SetBinLabel(5, "PID cuts"); + hTrack->GetXaxis()->SetBinLabel(6, Form("tpcNClsFound > %d", static_cast(trackCuts.tpcNClsFound))); + hTrack->GetXaxis()->SetBinLabel(7, Form("tpcNClsCrossedRows > %d", static_cast(trackCuts.tpcNClsCrossedRows))); + hTrack->GetXaxis()->SetBinLabel(8, Form("%s", static_cast(trackCuts.globalTrack) ? "isGlobalTrack" : "isPrimaryTrack")); + hTrack->GetXaxis()->SetBinLabel(9, "isPVContributor"); hTrack->SetMinimum(0.1); - registry.add("QATrack/hRapidity", "Rapidity distribution of K^{+} and K^{-}", kTH1F, {{200, -1, 1}}); - registry.add("QATrack/hEta", "Pseudorapidity distribution of K^{+} and K^{-}", kTH1F, {{200, -1, 1}}); - registry.add("QATrack/hTPCNClsFound", "Distribution of TPC NClsFound of K^{+} and K^{-}", kTH1F, {tpcNClsFoundQAaxis}); - registry.add("QATrack/hDCAxy", "Distribution of DCA_{xy} of K^{+} and K^{-}", kTH1F, {dcaXYaxis}); - registry.add("QATrack/hDCAz", "Distribution of DCA_{z} of K^{+} and K^{-}", kTH1F, {dcaZaxis}); - registry.add("QATrack/hPt", "Distribution of p_{T} of K^{+} and K^{-}", kTH1F, {ptaxis}); - - // Phi candidate QA - registry.add("QAPhi/hRapidity", "Rapidity distribution of #Phi candidates", kTH1F, {{200, -1, 1}}); - registry.add("QAPhi/hEta", "Pseudorapidity distribution of #Phi candidates", kTH1F, {{200, -1, 1}}); - registry.add("QAPhi/hdPhi", "Azimuthal distribution (#Delta#phi) of #Phi candidates", kTH1F, {{100, -o2::constants::math::TwoPI, o2::constants::math::TwoPI}}); - auto hdPhi = registry.get(HIST("QAPhi/hdPhi")); - hdPhi->GetXaxis()->SetTitle("#Delta#phi (rad)"); - - registry.add("QAPhi/h2dPhiPt", "Azimuthal distribution (#Delta#phi) of #Phi candidates vs p_{T}", kTH2F, {ptaxis, {100, -o2::constants::math::TwoPI, o2::constants::math::TwoPI}}); - auto h2dPhiPt = registry.get(HIST("QAPhi/h2dPhiPt")); - h2dPhiPt->GetXaxis()->SetTitle("p_{T} (GeV/c)"); - h2dPhiPt->GetYaxis()->SetTitle("#Delta#phi (rad)"); - - registry.add("QAPhi/hTheta", "Polar distribution of #Phi candidates", kTH1F, {{100, 0.0f, o2::constants::math::PI}}); - auto hTheta = registry.get(HIST("QAPhi/hTheta")); - hTheta->GetXaxis()->SetTitle("#theta (rad)"); - - registry.add("QAPhi/h2dThetaPt", "Polar distribution (#Delta#theta) of #Phi candidates vs p_{T}", kTH2F, {ptaxis, {100, -o2::constants::math::PI, o2::constants::math::PI}}); - - auto h2dThetaPt = registry.get(HIST("QAPhi/h2dThetaPt")); - h2dThetaPt->GetXaxis()->SetTitle("p_{T} (GeV/c)"); - h2dThetaPt->GetYaxis()->SetTitle("#Delta#theta (rad)"); - - // Rotational background QA - if (produceRotational) { - registry.add("QARotational/hRapidity", "Rapidity distribution of #Phi candidates from rotational background", kTH1F, {{200, -1, 1}}); - registry.add("QARotational/hEta", "Pseudorapidity distribution of #Phi candidates from rotational background", kTH1F, {{200, -1, 1}}); - registry.add("QARotational/hdPhi", "Rotational background: Azimuthal distribution (#Delta#phi)", kTH1F, {{100, -o2::constants::math::TwoPI, o2::constants::math::TwoPI}}); - auto hRPhi = registry.get(HIST("QARotational/hdPhi")); - hRPhi->GetXaxis()->SetTitle("#Delta#phi"); - - registry.add("QARotational/h2dPhiPt", "Rotational background: Azimuthal distribution (#Delta#phi) vs p_{T}", kTH2F, {ptaxis, {100, -o2::constants::math::TwoPI, o2::constants::math::TwoPI}}); - auto hR2dPhiPt = registry.get(HIST("QARotational/h2dPhiPt")); - hR2dPhiPt->GetXaxis()->SetTitle("p_{T} (GeV/c)"); - hR2dPhiPt->GetYaxis()->SetTitle("#Delta#phi"); - - registry.add("QARotational/hTheta", "Rotational background: Polar distribution (#theta)", kTH1F, {{100, 0.0f, o2::constants::math::PI}}); - auto hRdTheta = registry.get(HIST("QARotational/hTheta")); - hRdTheta->GetXaxis()->SetTitle("#theta (rad)"); - - registry.add("QARotational/h2dThetaPt", "Rotational background: Polar distribution (#Delta#theta) vs p_{T}", kTH2F, {ptaxis, {100, -o2::constants::math::PI, o2::constants::math::PI}}); - auto hR2dThetaPt = registry.get(HIST("QARotational/h2dThetaPt")); - hR2dThetaPt->GetXaxis()->SetTitle("p_{T} (GeV/c)"); - hR2dThetaPt->GetYaxis()->SetTitle("#Delta#theta"); - } + registry.add("QA/Track/hRapidity", "Rapidity distribution of Tracks", kTH3F, {ptQAAxis, multQAAxis, rapidityQAaxis}); + registry.add("QA/Track/hEta", "Pseudorapidity distribution of Tracks", kTH3F, {ptQAAxis, multQAAxis, etaQAaxis}); + registry.add("QA/Track/hTPCNClsFound", "Number of found TPC clusters of Tracks", kTH3F, {ptQAAxis, multQAAxis, tpcNClsQAaxis}); + registry.add("QA/Track/hTPCNClsCrossedRows", "Number of crossed rows in TPC of Tracks", kTH3F, {ptQAAxis, multQAAxis, tpcNClsQAaxis}); + registry.add("QA/Track/hDCAxy", "Distribution of DCA_{xy} of Tracks", kTH3F, {ptQAAxis, multQAAxis, dcaXYQAaxis}); + registry.add("QA/Track/hDCAz", "Distribution of DCA_{z} of Tracks", kTH3F, {ptQAAxis, multQAAxis, dcaZQAaxis}); + registry.add("QA/Track/hPt", "Distribution of p_{T} of Tracks", kTH2F, {ptQAAxis, multQAAxis}); + + registry.add("QA/Kaon/hRapidity", "Rapidity distribution of K^{+} and K^{-}", kTH3F, {ptQAAxis, multQAAxis, rapidityQAaxis}); + registry.add("QA/Kaon/hEta", "Pseudorapidity distribution of K^{+} and K^{-}", kTH3F, {ptQAAxis, multQAAxis, etaQAaxis}); + registry.add("QA/Kaon/hTPCNClsFound", "Number of found TPC clusters of K^{+} and K^{-}", kTH3F, {ptQAAxis, multQAAxis, tpcNClsQAaxis}); + registry.add("QA/Kaon/hTPCNClsCrossedRows", "Number of crossed rows in TPC of K^{+} and K^{-}", kTH3F, {ptQAAxis, multQAAxis, tpcNClsQAaxis}); + registry.add("QA/Kaon/hDCAxy", "Distribution of DCA_{xy} of K^{+} and K^{-}", kTH3F, {ptQAAxis, multQAAxis, dcaXYQAaxis}); + registry.add("QA/Kaon/hDCAz", "Distribution of DCA_{z} of K^{+} and K^{-}", kTH3F, {ptQAAxis, multQAAxis, dcaZQAaxis}); + registry.add("QA/Kaon/hPt", "Distribution of p_{T} of K^{+} and K^{-}", kTH2F, {ptQAAxis, multQAAxis}); + + // ---------------------- PID QA ---------------------- + + registry.add("QA/PID/hTPCNSigma", "Distribution of TPC nSigma", kTH3F, {ptQAAxis, multQAAxis, nSigmaTPCQAaxis}); + registry.add("QA/PID/hTPCNSigmaK", "Distribution of TPC nSigma of K^{+} and K^{-}", kTH3F, {ptQAAxis, multQAAxis, nSigmaTPCQAaxis}); + registry.add("QA/PID/hTOFNSigma", "Distribution of TOF nSigma", kTH3F, {ptQAAxis, multQAAxis, nSigmaTOFQAaxis}); + registry.add("QA/PID/hTOFNSigmaK", "Distribution of TOF nSigma of K^{+} and K^{-}", kTH3F, {ptQAAxis, multQAAxis, nSigmaTOFQAaxis}); + registry.add("QA/PID/hTPCTOFnSigma", "", kTH3F, {ptQAAxis, nSigmaTPCQAaxis, nSigmaTOFQAaxis}); + + registry.add("QA/PID/hTPCdEdxP", "dE/dx vs p of charged particles", kTH2F, {pQAaxis, dEdxQAaxis}); + registry.add("QA/PID/hTPCdEdxPK", "dE/dx vs p of K^{+} and K^{-}", kTH2F, {pQAaxis, dEdxQAaxis}); + registry.add("QA/PID/hTOFBetaP", "TOF #beta vs p of charged particles", kTH2F, {pQAaxis, betaQAaxis}); + registry.add("QA/PID/hTOFBetaPK", "TOF #beta vs p of K^{+} and K^{-}", kTH2F, {pQAaxis, betaQAaxis}); + + // ----------------------- Phi candidate QA ----------------------- + registry.add("QA/Phi/hRapidity", "Rapidity distribution of #Phi candidates", kTH3F, {ptQAAxis, multQAAxis, rapidityQAaxis}); + registry.add("QA/Phi/hEta", "Pseudorapidity distribution of #Phi candidates", kTH3F, {ptQAAxis, multQAAxis, etaQAaxis}); + registry.add("QA/Phi/hdPhi", "Azimuthal distribution (#Delta#phi) of #Phi candidates", kTH3F, {ptQAAxis, multQAAxis, dPhiQAaxis}); + registry.add("QA/Phi/hdPhideta", "Azimuthal distribution (#Delta#phi) of #Phi candidates vs #eta", kTH2F, {dEtaQAaxis, dPhiQAaxis}); + registry.add("QA/Phi/hdTheta", "Polar distribution (#Delta#theta) of #Phi candidates vs p_{T}", kTH3F, {ptQAAxis, multQAAxis, dThetaQAaxis}); + } - // Mixing QA - if (mixingType != rsn::MixingType::none) { - registry.add("QAMixing/hSelection", "Event mixing selection statistics", kTH1D, {{1, 0.0f, 1.0f}}); - auto hEM = registry.get(HIST("QAMixing/hSelection")); - hEM->GetXaxis()->SetBinLabel(1, "Full event mixing statistics"); - hEM->SetMinimum(0.1); - - registry.add("QAMixing/h2mu1_mu2", "Event Mixing Multiplicity", kTH2F, {axisMultiplicityMixing, axisMultiplicityMixing}); - auto h2EMmu = registry.get(HIST("QAMixing/h2mu1_mu2")); - h2EMmu->GetXaxis()->SetTitle("1.Event multiplicity"); - h2EMmu->GetYaxis()->SetTitle("2.Event multiplicity"); - - registry.add("QAMixing/h2ce1_ce2", "Event Mixing Centrality", kTH2F, {axisCentralityMixing, axisCentralityMixing}); - auto h2EMce = registry.get(HIST("QAMixing/h2ce1_ce2")); - h2EMce->GetXaxis()->SetTitle("1.Event centrality"); - h2EMce->GetYaxis()->SetTitle("2.Event centrality"); - - registry.add("QAMixing/h2vz1_vz2", "Event Mixing Vertex z", kTH2F, {axisVertexMixing, axisVertexMixing}); - auto hEMTvz = registry.get(HIST("QAMixing/h2vz1_vz2")); - hEMTvz->GetXaxis()->SetTitle("1.Event V_{z}"); - hEMTvz->GetYaxis()->SetTitle("2.Event V_{z}"); - } + // Rotational background QA + if (static_cast(produce.produceRotational) && static_cast(produce.produceQA)) { + // Rotation around z axis + registry.add("QA/RotationZ/hRapidity", "Rapidity distribution of #Phi candidates from rotational background", kTH3F, {ptQAAxis, multQAAxis, rapidityQAaxis}); + registry.add("QA/RotationZ/hEta", "Pseudorapidity distribution of #Phi candidates from rotational background", kTH3F, {ptQAAxis, multQAAxis, etaQAaxis}); + registry.add("QA/RotationZ/hdPhi", "Rotational background: Azimuthal distribution (#Delta#phi)", kTH3F, {ptQAAxis, multQAAxis, dPhiQAaxis}); + registry.add("QA/RotationZ/hdPhideta", "Rotational background: Azimuthal distribution (#Delta#phi) vs #eta", kTH2F, {dEtaQAaxis, dPhiQAaxis}); + registry.add("QA/RotationZ/hdTheta", "Rotational background: Polar distribution (#Delta#theta) vs p_{T}", kTH3F, {ptQAAxis, multQAAxis, dThetaQAaxis}); + // Momentum-axis rotation + registry.add("QA/Rotation/hRapidity", "Rapidity distribution of #Phi candidates from rotational background", kTH3F, {ptQAAxis, multQAAxis, rapidityQAaxis}); + registry.add("QA/Rotation/hEta", "Pseudorapidity distribution of #Phi candidates from rotational background", kTH3F, {ptQAAxis, multQAAxis, etaQAaxis}); + registry.add("QA/Rotation/hdPhi", "Rotational background: Azimuthal distribution (#Delta#phi)", kTH3F, {ptQAAxis, multQAAxis, dPhiQAaxis}); + registry.add("QA/Rotation/hdPhideta", "Rotational background: Azimuthal distribution (#Delta#phi) vs #eta", kTH2F, {dEtaQAaxis, dPhiQAaxis}); + registry.add("QA/Rotation/hdTheta", "Rotational background: Polar distribution (#Delta#theta) vs p_{T}", kTH3F, {ptQAAxis, multQAAxis, dThetaQAaxis}); + } + + // Mixing QA + if (mixingType != rsn::MixingType::none && static_cast(produce.produceQA)) { + + registry.add("QA/Mixing/h2mu1_mu2", "Event Mixing Multiplicity", kTH2F, {axisMultiplicityMixing, axisMultiplicityMixing}); + auto h2EMmu = registry.get(HIST("QA/Mixing/h2mu1_mu2")); + h2EMmu->GetXaxis()->SetTitle("1.Event multiplicity"); + h2EMmu->GetYaxis()->SetTitle("2.Event multiplicity"); + + registry.add("QA/Mixing/h2ce1_ce2", "Event Mixing Centrality", kTH2F, {axisCentralityMixing, axisCentralityMixing}); + auto h2EMce = registry.get(HIST("QA/Mixing/h2ce1_ce2")); + h2EMce->GetXaxis()->SetTitle("1.Event centrality"); + h2EMce->GetYaxis()->SetTitle("2.Event centrality"); + + registry.add("QA/Mixing/h2vz1_vz2", "Event Mixing Vertex z", kTH2F, {axisVertexMixing, axisVertexMixing}); + auto hEMTvz = registry.get(HIST("QA/Mixing/h2vz1_vz2")); + hEMTvz->GetXaxis()->SetTitle("1.Event V_{z}"); + hEMTvz->GetYaxis()->SetTitle("2.Event V_{z}"); + + registry.add("QA/Mixing/hdPhideta", "Mixing background: Azimuthal distribution (#Delta#phi) vs #eta", kTH2F, {dEtaQAaxis, dPhiQAaxis}); + } - // PID QA - // TPC - registry.add("QAPID/hTPCnSigma", "Distribution of TPC nSigma of K^{+} and K^{-}", kTH1F, {{200, -10, 10}}); - auto hTPCnSigma = registry.get(HIST("QAPID/hTPCnSigma")); - hTPCnSigma->GetXaxis()->SetTitle("n#sigma_{TPC} K^{#pm}"); - - registry.add("QAPID/h2TPCnSigma", "", kTH2F, {{200, -10, 10}, {200, -10, 10}}); - auto h2TPCnSigma = registry.get(HIST("QAPID/h2TPCnSigma")); - h2TPCnSigma->GetXaxis()->SetTitle("n#sigma_{TPC} K^{+}"); - h2TPCnSigma->GetYaxis()->SetTitle("n#sigma_{TPC} K^{-}"); - - registry.add("QAPID/h2TPCnSigmaPt", "", kTH2F, {ptaxis, {200, -10, 10}}); - auto h2TPCnSigmaPt = registry.get(HIST("QAPID/h2TPCnSigmaPt")); - h2TPCnSigmaPt->GetXaxis()->SetTitle("p_{T} (GeV/c)"); - h2TPCnSigmaPt->GetYaxis()->SetTitle("n#sigma_{TPC} K^{#pm}"); - - // TOF - registry.add("QAPID/hTOFnSigma", "Distribution of TOF nSigma of K^{+} and K^{-}", kTH1F, {{200, -10, 10}}); - auto hTOFnSigma = registry.get(HIST("QAPID/hTOFnSigma")); - hTOFnSigma->GetXaxis()->SetTitle("n#sigma_{TOF} K^{#pm}"); - - registry.add("QAPID/h2TOFnSigma", "", kTH2F, {{200, -10, 10}, {200, -10, 10}}); - auto h2TOFnSigma = registry.get(HIST("QAPID/h2TOFnSigma")); - h2TOFnSigma->GetXaxis()->SetTitle("n#sigma_{TOF} K^{+}"); - h2TOFnSigma->GetYaxis()->SetTitle("n#sigma_{TOF} K^{-}"); - - registry.add("QAPID/h2TOFnSigmaPt", "", kTH2F, {ptaxis, {200, -10, 10}}); - auto h2TOFnSigmaPt = registry.get(HIST("QAPID/h2TOFnSigmaPt")); - h2TOFnSigmaPt->GetXaxis()->SetTitle("p_{T} (GeV/c)"); - h2TOFnSigmaPt->GetYaxis()->SetTitle("n#sigma_{TOF} K^{#pm}"); - - // MC - if (static_cast(produce.produceTrue)) { - // Rec - registry.add("QAMC/Rec/hSelection", "MC Rec Event statistics", kTH1F, {{5, 0.0f, 5.0f}}); - auto hMCEventTruth = registry.get(HIST("QAMC/Rec/hSelection")); - hMCEventTruth->GetXaxis()->SetBinLabel(1, "Full MC Rec event statistics"); - hMCEventTruth->GetXaxis()->SetBinLabel(2, "MC Rec events passing sel8 cut"); - hMCEventTruth->GetXaxis()->SetBinLabel(3, "MC Rec events passing V_{z} cut"); - hMCEventTruth->GetXaxis()->SetBinLabel(4, "MC Rec events with V_{z} cut and INEL>0"); - hMCEventTruth->GetXaxis()->SetBinLabel(5, "Reconstructed #Phi candidates matched to true #Phi"); - hMCEventTruth->SetMinimum(0.1); - - registry.add("QAMC/Rec/hInvMassTrueFalse", "", kTH1F, {invAxis}); // not written events in True distribution due to repetition of mothers - - // Gen - registry.add("QAMC/Gen/hSelection", "MC Gen Event statistics", kTH1F, {{4, 0.0f, 4.0f}}); - auto hMCEventGen = registry.get(HIST("QAMC/Gen/hSelection")); - hMCEventGen->GetXaxis()->SetBinLabel(1, "Full MC Gen event statistics"); - hMCEventGen->GetXaxis()->SetBinLabel(2, "MC Gen events within V_{z} cut"); - hMCEventGen->GetXaxis()->SetBinLabel(3, "MC Gen events with V_{z} cut and INEL>0"); - hMCEventGen->GetXaxis()->SetBinLabel(4, "Generated #Phi candidates"); - hMCEventGen->SetMinimum(0.1); - - // Resolution - registry.add("Factors/h2ResolutionVz", "Resolution of collision V_{z}", kTH2F, {vzaxis, axisResolutionVz}); - auto hResVz = registry.get(HIST("Factors/h2ResolutionVz")); + // ------------------------- MC QA ------------------------- + if (static_cast(produce.produceMC)) { + // Rec + registry.add("QAMC/Rec/hSelection", "MC Rec True Event statistics", kTH1F, {{3, 0.0f, 3.0f}}); + auto hMCEventTruth = registry.get(HIST("QAMC/Rec/hSelection")); + hMCEventTruth->GetXaxis()->SetBinLabel(1, "all Rec"); // All reconstructed events + hMCEventTruth->GetXaxis()->SetBinLabel(2, "INEL"); // All reconstructed events passing event selection cuts + hMCEventTruth->GetXaxis()->SetBinLabel(3, "INEL>0"); // All reconstructed events passing event selection cuts and INEL>0 cut + hMCEventTruth->SetMinimum(0.1); + + // Gen + registry.add("QAMC/Gen/hSelection", "MC Gen Event statistics", kTH1F, {{4, 0.0f, 4.0f}}); + auto hMCEventGen = registry.get(HIST("QAMC/Gen/hSelection")); + hMCEventGen->GetXaxis()->SetBinLabel(1, "all"); // All generated events + hMCEventGen->GetXaxis()->SetBinLabel(2, "ALORE"); // All generated events with at least one reconstructed event + hMCEventGen->GetXaxis()->SetBinLabel(3, "INEL"); // All generated events passing event selection cuts + hMCEventGen->GetXaxis()->SetBinLabel(4, "INEL>0"); // All generated events passing event selection cuts and INEL>0 cut + hMCEventGen->SetMinimum(0.1); + + // Factors + registry.add("QAMC/Factors/hGenEvents", "Generated events", HistType::kTH2F, {nchQAAxis, {5, 0, 5}}); + auto hGenEvents = registry.get(HIST("QAMC/Factors/hGenEvents")); + hGenEvents->GetYaxis()->SetBinLabel(1, "all Gen"); + hGenEvents->GetYaxis()->SetBinLabel(2, "all Rec"); + hGenEvents->GetYaxis()->SetBinLabel(3, "ALORE"); + hGenEvents->GetYaxis()->SetBinLabel(4, "INEL"); + hGenEvents->GetYaxis()->SetBinLabel(5, "INEL>0"); + + registry.add("QAMC/Factors/hRecEvents", "Reconstructed events", HistType::kTH2F, {centQAAxis, {3, 0, 3}}); + auto hRecEvents = registry.get(HIST("QAMC/Factors/hRecEvents")); + hRecEvents->GetYaxis()->SetBinLabel(1, "all Rec"); + hRecEvents->GetYaxis()->SetBinLabel(2, "INEL"); + hRecEvents->GetYaxis()->SetBinLabel(3, "INEL>0"); + + registry.add("QAMC/Factors/hGenALORESelEvents", "Centrality vs. Multiplicity of Generated Events with at least one reconstructed event passing event selection", kTH2F, {centQAAxis, nchQAAxis}); + registry.add("QAMC/Factors/hGenALORESelEventsInelGt0", "Centrality vs. Multiplicity of Generated Events with at least one reconstructed event passing event selection and INEL>0 cut", kTH2F, {centQAAxis, nchQAAxis}); + registry.add("QAMC/Factors/hGenEventsCentNch", "Event centrality vs MC multiplicity", kTH2F, {centQAAxis, nchQAAxis}); + registry.add("QAMC/Factors/hNrecInGen", "Number of collisions in MC", kTH1F, {{4, -0.5, 3.5}}); + + registry.add("QAMC/Factors/hGenPhi", "Generated #Phi", kTH3D, {nchQAAxis, centQAAxis, ptAxis}); + registry.add("QAMC/Factors/hGenALOREPhi", "Generated #Phi in collisions with at least one reconstructed collision", kTH3F, {nchQAAxis, centQAAxis, ptAxis}); + registry.add("QAMC/Factors/hGenALOREPhiInelGt0", "Generated #Phi in collisions with at least one reconstructed collision passing INEL>0 cut", kTH3F, {nchQAAxis, centQAAxis, ptAxis}); + registry.add("QAMC/Factors/hRecPhi", "Reconstructed #Phi", kTH2F, {centQAAxis, ptAxis}); + + // ----------------------- MC Corrections ----------------------- + + registry.add("QAMC/Gen/hNEvents", "Number of MC Gen Events", kTH1F, {{6, 0.0f, 6.0f}}); + auto hNEventsGen = registry.get(HIST("QAMC/Gen/hNEvents")); + hNEventsGen->GetXaxis()->SetBinLabel(1, "all"); // All generated events + hNEventsGen->GetXaxis()->SetBinLabel(2, "V_z cut"); // Generated events passing Vz cut + hNEventsGen->GetXaxis()->SetBinLabel(3, "INEL"); // Generated events passing INEL cut + hNEventsGen->GetXaxis()->SetBinLabel(4, "INEL>0"); // Passing INELgt0 cut --> EL numerator for INEL>0 + hNEventsGen->GetXaxis()->SetBinLabel(5, "ALORE INEL"); // Passing ALORE INEL cut + hNEventsGen->GetXaxis()->SetBinLabel(6, "ALORE INEL>0"); // Passing ALORE INEL>0 cut + hNEventsGen->SetMinimum(0.1); + + registry.add("QAMC/Gen/hNEventsCent", "Generated events", HistType::kTH2F, {centQAAxis, {6, 0, 6}}); + auto hNEventsGenCent = registry.get(HIST("QAMC/Gen/hNEventsCent")); + hNEventsGenCent->GetYaxis()->SetBinLabel(1, "all"); + hNEventsGenCent->GetYaxis()->SetBinLabel(2, "V_z cut"); + hNEventsGenCent->GetYaxis()->SetBinLabel(3, "INEL"); + hNEventsGenCent->GetYaxis()->SetBinLabel(4, "INEL>0"); + hNEventsGenCent->GetYaxis()->SetBinLabel(5, "ALORE INEL"); + hNEventsGenCent->GetYaxis()->SetBinLabel(6, "ALORE INEL>0"); + + registry.add("QAMC/Rec/hNEvents", "Number of MC Rec Events", kTH1F, {{3, 0.0f, 3.0f}}); + auto hNEventsRec = registry.get(HIST("QAMC/Rec/hNEvents")); + hNEventsRec->GetXaxis()->SetBinLabel(1, "all"); // All reconstructed events from generated events passing Vz cut + hNEventsRec->GetXaxis()->SetBinLabel(2, "INEL"); // Reconstructed events passing event selection + hNEventsRec->GetXaxis()->SetBinLabel(3, "INEL>0"); // Reconstructed events passing INEL>0 cut + + registry.add("QAMC/Rec/hNEventsCent", "Reconstructed events", HistType::kTH2F, {centQAAxis, {3, 0, 3}}); + auto hNEventsRecCent = registry.get(HIST("QAMC/Rec/hNEventsCent")); + hNEventsRecCent->GetYaxis()->SetBinLabel(1, "all"); + hNEventsRecCent->GetYaxis()->SetBinLabel(2, "INEL"); + hNEventsRecCent->GetYaxis()->SetBinLabel(3, "INEL>0"); + + registry.add("QAMC/Gen/hNPhiPt", "Generated #Phi", kTH2D, {ptAxis, {5, 0, 5}}); + auto hNPhiGenPt = registry.get(HIST("QAMC/Gen/hNPhiPt")); + hNPhiGenPt->GetYaxis()->SetBinLabel(1, "all INEL"); // All generated #Phi in Gen Events passing Vz cut INEL + hNPhiGenPt->GetYaxis()->SetBinLabel(2, "all INEL>0"); // All generated #Phi in Gen Events passing Vz cut INEL>0 + hNPhiGenPt->GetYaxis()->SetBinLabel(3, "ALORE INEL"); // All generated #Phi in Gen Events with ALORE passing Vz cut INEL + hNPhiGenPt->GetYaxis()->SetBinLabel(4, "ALORE INEL>0"); // All generated #Phi in Gen Events with ALORE passing Vz cut INEL>0 + hNPhiGenPt->GetYaxis()->SetBinLabel(5, "Rec True"); // All reconstructed #Phi in Rec Events passing Vz cut INEL + + registry.add("QAMC/Gen/hNPhiPtCent", "Generated #Phi", kTH3D, {ptAxis, centQAAxis, {5, 0, 5}}); + + // Resolution + if (static_cast(produce.produceQA)) { + registry.add("QAMC/Resolution/h2ResolutionVz", "Resolution of collision V_{z}", kTH2F, {vzaxis, axisResolutionVz}); + auto hResVz = registry.get(HIST("QAMC/Resolution/h2ResolutionVz")); hResVz->GetXaxis()->SetTitle("V_{z}^{rec} (cm)"); hResVz->GetYaxis()->SetTitle("#DeltaV_{z} = V_{z}^{rec} - V_{z}^{gen} (cm)"); - registry.add("Factors/h2ResolutionPt", "Resolution of charged particles p_{T}", kTH2F, {ptaxis, axisResolutionPt}); - auto hResPt = registry.get(HIST("Factors/h2ResolutionPt")); + registry.add("QAMC/Resolution/h2ResolutionPt", "Resolution of charged particles p_{T}", kTH2F, {ptQAAxis, axisResolutionPt}); + auto hResPt = registry.get(HIST("QAMC/Resolution/h2ResolutionPt")); hResPt->GetXaxis()->SetTitle("p_{T}^{rec} (GeV/c)"); hResPt->GetYaxis()->SetTitle("#Deltap_{T} = p_{T}^{rec} - p_{T}^{gen} (GeV/c)"); - registry.add("Factors/h2ResolutionPtPhi", "p_{T} resolution vs p_{T}^{rec}", kTH2F, {ptaxis, axisResolutionPtPhi}); - auto hResPtPhi = registry.get(HIST("Factors/h2ResolutionPtPhi")); + + registry.add("QAMC/Resolution/h2ResolutionPtPhi", "p_{T} resolution vs p_{T}^{rec}", kTH2F, {ptQAAxis, axisResolutionPtPhi}); + auto hResPtPhi = registry.get(HIST("QAMC/Resolution/h2ResolutionPtPhi")); hResPtPhi->GetXaxis()->SetTitle("p_{T}^{rec} (GeV/c)"); hResPtPhi->GetYaxis()->SetTitle("#Deltap_{T} = p_{T}^{rec} - p_{T}^{gen} (GeV/c)"); - registry.add("Factors/h2MassResolution", "Mass resolution vs p_{T}^{rec}", kTH2F, {ptaxis, axisResolutionMass}); - auto hResMass = registry.get(HIST("Factors/h2MassResolution")); + registry.add("QAMC/Resolution/h2MassResolution", "Mass resolution vs p_{T}^{rec}", kTH2F, {ptQAAxis, axisResolutionMass}); + auto hResMass = registry.get(HIST("QAMC/Resolution/h2MassResolution")); hResMass->GetXaxis()->SetTitle("p_{T}^{rec} (GeV/c)"); hResMass->GetYaxis()->SetTitle("#Deltam = m^{gen}_{KK} - m^{rec}_{KK} (GeV/c^{2})"); - - registry.add("Factors/h2MassShift", "Mass shift vs p_{T}^{rec}", kTH2F, {ptaxis, massShiftAxis}); - auto hResMassGen = registry.get(HIST("Factors/h2MassShift")); - hResMassGen->GetXaxis()->SetTitle("p_{T}^{rec} (GeV/c)"); - hResMassGen->GetYaxis()->SetTitle("#Deltam = m^{gen}_{#phi} - m^{gen}_{KK} (GeV/c^{2})"); - - registry.add("Factors/h2MassShiftRel", "Relative mass shift vs p_{T}^{rec}", kTH2F, {ptaxis, massShiftRelAxis}); - auto hMassCorr = registry.get(HIST("Factors/h2MassShiftRel")); - hMassCorr->GetXaxis()->SetTitle("p_{T}^{rec} (GeV/c)"); - hMassCorr->GetYaxis()->SetTitle("m^{gen}_{#phi} - m^{gen}_{KK}/m^{gen}_{#phi}"); } } - // Factors - registry.add("Factors/hCentralityVsMultMC", "Event centrality vs MC multiplicity", kTH2F, {{101, 0.0f, 101.0f}, axisNch}); - registry.add("Factors/hCentralityVsMult", "Event centrality vs multiplicity", kTH2F, {{101, 0.0f, 101.0f}, axisNch}); - registry.add("Factors/hEventCentrality", "Event centrality", kTH1F, {{101, 0, 101}}); - registry.add("Factors/hNrecInGen", "Number of collisions in MC", kTH1F, {{3, -0.5, 2.5}}); - registry.add("Factors/hGenEvents", "Generated events", HistType::kTH2F, {{axisNch}, {4, 0, 4}}); - auto hGenEvents = registry.get(HIST("Factors/hGenEvents")); - hGenEvents->GetYaxis()->SetBinLabel(1, "All generated events"); - hGenEvents->GetYaxis()->SetBinLabel(2, "Generated events passing V_{z} cut"); - hGenEvents->GetYaxis()->SetBinLabel(3, "Generated events passing INEL>0"); - hGenEvents->GetYaxis()->SetBinLabel(4, "Generated events with at least one reconstructed event"); - registry.add("Factors/h2dGenPhi", "Centrality vs p_{T}", kTH2D, {{101, 0.0f, 101.0f}, ptaxis}); - registry.add("Factors/h3dGenPhiVsMultMCVsCentrality", "MC multiplicity vs centrality vs p_{T}", kTH3D, {axisNch, {101, 0.0f, 101.0f}, ptaxis}); } + template + bool selectedEvent(const T& collision) + { + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 0.5); // all events + } + if (std::abs(collision.posZ()) > static_cast(eventCuts.vzCut)) { + return false; + } + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 1.5); // events passing V_{z} cut + } + + if (static_cast(eventCuts.isTriggerTVX) && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 2.5); // events passing trigger TVX cut + } + + if (static_cast(eventCuts.noTimeFrameBorder) && !collision.selection_bit(aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 3.5); // events passing no time frame border cut + } + + if (static_cast(eventCuts.noITSROFrameBorder) && !collision.selection_bit(aod::evsel::kNoITSROFrameBorder)) { + return false; + } + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 4.5); // events passing no ITS RO frame border cut + } + + if (static_cast(eventCuts.sel8) && !collision.sel8()) { + return false; + } + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 5.5); // events passing sel8 cut (contains all the previous cuts) + } + + if (static_cast(eventCuts.isVertexITSTPC) && !collision.selection_bit(aod::evsel::kIsVertexITSTPC)) { + return false; + } + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 6.5); // events passing IsVertexITSTPC cut + } + + if (static_cast(eventCuts.noSameBunchPileup) && !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 7.5); // events passing no same bunch pileup cut + } + + if (static_cast(eventCuts.isGoodZvtxFT0vsPV) && !collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 8.5); // events passing IsGoodZvtxFT0vsPV cut + } + + if (dataQA) { + registry.fill(HIST("QA/Event/hSelection"), 9.5); // INEL + } + + return true; + } template float tpcNsigma(const T& track) { float tpcNsigma = 0.0f; int particleType = (track.sign() > 0) ? static_cast(daughterPos) : static_cast(daughterNeg); - if (particleType == pion) + if (particleType == pion) { tpcNsigma = track.tpcNSigmaPi(); - else if (particleType == kaon) + } else if (particleType == kaon) { tpcNsigma = track.tpcNSigmaKa(); - else if (particleType == proton) + } else if (particleType == proton) { tpcNsigma = track.tpcNSigmaPr(); + } return tpcNsigma; } template @@ -500,77 +601,92 @@ struct PhianalysisTHnSparse { float tofNsigma = 0.0f; int particleType = (track.sign() > 0) ? static_cast(daughterPos) : static_cast(daughterNeg); - if (particleType == pion) + if (particleType == pion) { tofNsigma = track.tofNSigmaPi(); - else if (particleType == kaon) + } else if (particleType == kaon) { tofNsigma = track.tofNSigmaKa(); - else if (particleType == proton) + } else if (particleType == proton) { tofNsigma = track.tofNSigmaPr(); + } return tofNsigma; } template bool selectedTrack(const T& track, bool isPositive) { - if (produceQA && dataQA) - registry.fill(HIST("QATrack/hSelection"), 0.5); // all tracks + if (dataQA) { + registry.fill(HIST("QA/Track/hSelection"), 0.5); + } - // Apply pT cut - if (track.pt() < static_cast(cut.pt)) + if (track.pt() < static_cast(trackCuts.pt)) { return false; - if (produceQA && dataQA) - registry.fill(HIST("QATrack/hSelection"), 1.5); + } + if (dataQA) { + registry.fill(HIST("QA/Track/hSelection"), 1.5); + } - // Apply eta cut - if (std::abs(track.eta()) >= static_cast(cut.etatrack)) + if (std::abs(track.eta()) >= static_cast(trackCuts.etatrack)) { return false; - if (produceQA && dataQA) - registry.fill(HIST("QATrack/hSelection"), 2.5); + } + if (dataQA) { + registry.fill(HIST("QA/Track/hSelection"), 2.5); + } - // Apply DCA cuts - if (std::abs(track.dcaXY()) >= static_cast(cut.dcaXY) || - std::abs(track.dcaZ()) >= static_cast(cut.dcaZ)) + if (std::abs(track.dcaXY()) >= static_cast(trackCuts.dcaXY) || + std::abs(track.dcaZ()) >= static_cast(trackCuts.dcaZ)) { return false; - if (produceQA && dataQA) - registry.fill(HIST("QATrack/hSelection"), 3.5); + } + if (dataQA) { + registry.fill(HIST("QA/Track/hSelection"), 3.5); + } // PID selection: TPC-only for pt < threshold value, TPC+TOF for pt >= threshold value and have TOF, else TPC-only - float nSigmaCut = isPositive ? tpcnSigmaPos : tpcnSigmaNeg; - if (track.pt() < ptTOFThreshold || !track.hasTOF() || tpcPidOnly) { - if (std::abs(tpcNsigma(track)) >= nSigmaCut) + float nSigmaCut = isPositive ? static_cast(trackCuts.tpcnSigmaPos) : static_cast(trackCuts.tpcnSigmaNeg); + if (track.pt() < static_cast(trackCuts.ptTOFThreshold) || !track.hasTOF() || static_cast(trackCuts.tpcPidOnly)) { + if (std::abs(tpcNsigma(track)) >= nSigmaCut) { return false; + } } else { - if (std::sqrt(tpcNsigma(track) * tpcNsigma(track) + tofNsigma(track) * tofNsigma(track)) >= combinedNSigma) + if (std::sqrt(tpcNsigma(track) * tpcNsigma(track) + tofNsigma(track) * tofNsigma(track)) >= static_cast(trackCuts.combinedNSigma)) { return false; + } + } + if (dataQA) { + registry.fill(HIST("QA/Track/hSelection"), 4.5); } - if (produceQA && dataQA) - registry.fill(HIST("QATrack/hSelection"), 4.5); - // Apply tpcNClsFound cut - if (track.tpcNClsFound() < tpcNClsFound) + if (track.tpcNClsFound() < static_cast(trackCuts.tpcNClsFound)) { return false; - if (produceQA && dataQA) - registry.fill(HIST("QATrack/hSelection"), 5.5); + } + if (dataQA) { + registry.fill(HIST("QA/Track/hSelection"), 5.5); + } - if (globalTrack) { - // Apply Global track cuts - if (!track.isGlobalTrack()) + if (track.tpcNClsCrossedRows() < static_cast(trackCuts.tpcNClsCrossedRows)) { + return false; + } + if (dataQA) { + registry.fill(HIST("QA/Track/hSelection"), 6.5); + } + + if (static_cast(trackCuts.globalTrack)) { + if (!track.isGlobalTrack()) { return false; - } else { - // Apply Primary track cuts - if (!track.isPrimaryTrack()) + } + } else if (static_cast(trackCuts.primaryTrack)) { + if (!track.isPrimaryTrack()) { return false; + } + } + if (dataQA) { + registry.fill(HIST("QA/Track/hSelection"), 7.5); } - if (produceQA && dataQA) - registry.fill(HIST("QATrack/hSelection"), 6.5); - // Apply PV Contributor cuts - if (!track.isPVContributor()) + if (static_cast(trackCuts.pvContributor) && !track.isPVContributor()) { return false; - if (produceQA && dataQA) - registry.fill(HIST("QATrack/hSelection"), 7.5); - - if (produceQA && dataQA) - registry.fill(HIST("QATrack/hSelection"), 8.5); + } + if (dataQA) { + registry.fill(HIST("QA/Track/hSelection"), 8.5); + } return true; } @@ -581,11 +697,9 @@ struct PhianalysisTHnSparse { d2 = ROOT::Math::PxPyPzMVector(track2.px(), track2.py(), track2.pz(), massNeg); return d1 + d2; } - bool seletectedMother(const ROOT::Math::PxPyPzMVector& mother) + bool selectedMother(const ROOT::Math::PxPyPzMVector& motherCandidate) { - if (std::abs(mother.Rapidity()) > static_cast(cut.rapidity)) - return false; - return true; + return std::abs(motherCandidate.Rapidity()) <= static_cast(trackCuts.rapidity); } template float getMultiplicity(const T& collision) @@ -617,170 +731,301 @@ struct PhianalysisTHnSparse { return pointPair; } - void processData(EventCandidate const& collision, TrackCandidates const& /*tracks*/) + void processQA(EventCandidate const& collision, TrackCandidates const& tracks) { - auto posDaughters = positive->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - auto negDaughters = negative->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - - int nch = 0; + if (!static_cast(produce.produceQA)) { + return; + } - if (produceQA) - registry.fill(HIST("QAEvent/hSelection"), 0.5); + dataQA = true; + bool selected = selectedEvent(collision); + dataQA = false; - if (!collision.sel8()) + if (!selected) { + return; + } + if (static_cast(eventCuts.inelGt0) && !collision.isInelGt0()) { return; + } + registry.fill(HIST("QA/Event/hSelection"), 10.5); // events passing INEL>0 cut - if (produceQA) - registry.fill(HIST("QAEvent/hSelection"), 1.5); + double centrality = getCentrality(collision); - if (std::abs(collision.posZ()) > vzCut) - return; + int nch = 0; + for (const auto& track : tracks) { - if (produceQA) - registry.fill(HIST("QAEvent/hSelection"), 2.5); + registry.fill(HIST("QA/Track/hEta"), track.pt(), centrality, track.eta()); + registry.fill(HIST("QA/Track/hPt"), track.pt(), centrality); + registry.fill(HIST("QA/Track/hDCAxy"), track.pt(), centrality, track.dcaXY()); + registry.fill(HIST("QA/Track/hDCAz"), track.pt(), centrality, track.dcaZ()); + registry.fill(HIST("QA/Track/hTPCNClsFound"), track.pt(), centrality, track.tpcNClsFound()); + registry.fill(HIST("QA/Track/hTPCNClsCrossedRows"), track.pt(), centrality, track.tpcNClsCrossedRows()); + registry.fill(HIST("QA/Track/hRapidity"), track.pt(), centrality, track.sign() > 0 ? track.rapidity(massPos) : track.rapidity(massNeg)); - if (inelGrater0 && !collision.isInelGt0()) - return; + registry.fill(HIST("QA/PID/hTPCNSigma"), track.pt(), centrality, tpcNsigma(track)); + registry.fill(HIST("QA/PID/hTPCdEdxP"), track.p(), track.tpcSignal()); - registry.fill(HIST("Factors/hEventCentrality"), collision.centFT0M()); + if (track.hasTOF()) { + registry.fill(HIST("QA/PID/hTOFNSigma"), track.pt(), centrality, tofNsigma(track)); + registry.fill(HIST("QA/PID/hTOFBetaP"), track.p(), track.beta()); + } - if (produceQA) { - registry.fill(HIST("QAEvent/hSelection"), 3.5); - registry.fill(HIST("QAEvent/hVtxZ"), collision.posZ()); - registry.fill(HIST("QAEvent/hMult"), getMultiplicity(collision)); - registry.fill(HIST("QAEvent/hCent"), getCentrality(collision)); + if (track.isPrimaryTrack() && std::abs(track.eta()) < static_cast(trackCuts.etatrack)) { + nch++; + } - if (produceStats) { - dataQA = true; - for (const auto& track : posDaughters) { - if (track.isPrimaryTrack() && std::abs(track.eta()) >= static_cast(cut.etatrack)) - nch++; - selectedTrack(track, true); - } - for (const auto& track : negDaughters) { - if (track.isPrimaryTrack() && std::abs(track.eta()) >= static_cast(cut.etatrack)) - nch++; - selectedTrack(track, false); - } - dataQA = false; + dataQA = true; + bool selectedTrackCandidate = selectedTrack(track, track.sign() > 0); + dataQA = false; + + if (!selectedTrackCandidate) { + continue; } - registry.fill(HIST("Factors/hCentralityVsMult"), getCentrality(collision), nch); + + registry.fill(HIST("QA/Kaon/hEta"), track.pt(), centrality, track.eta()); + registry.fill(HIST("QA/Kaon/hPt"), track.pt(), centrality); + registry.fill(HIST("QA/Kaon/hDCAxy"), track.pt(), centrality, track.dcaXY()); + registry.fill(HIST("QA/Kaon/hDCAz"), track.pt(), centrality, track.dcaZ()); + registry.fill(HIST("QA/Kaon/hTPCNClsFound"), track.pt(), centrality, track.tpcNClsFound()); + registry.fill(HIST("QA/Kaon/hTPCNClsCrossedRows"), track.pt(), centrality, track.tpcNClsCrossedRows()); + registry.fill(HIST("QA/Kaon/hRapidity"), track.pt(), centrality, track.sign() > 0 ? track.rapidity(massPos) : track.rapidity(massNeg)); + + registry.fill(HIST("QA/PID/hTPCNSigmaK"), track.pt(), centrality, tpcNsigma(track)); + registry.fill(HIST("QA/PID/hTPCdEdxPK"), track.p(), track.tpcSignal()); + + if (track.hasTOF()) { + registry.fill(HIST("QA/PID/hTOFNSigmaK"), track.pt(), centrality, tofNsigma(track)); + registry.fill(HIST("QA/PID/hTOFBetaPK"), track.p(), track.beta()); + registry.fill(HIST("QA/PID/hTPCTOFnSigma"), track.pt(), tpcNsigma(track), tofNsigma(track)); + } + } + registry.fill(HIST("QA/Event/hCentNch"), getCentrality(collision), nch); + } + PROCESS_SWITCH(PhianalysisTHnSparse, processQA, "Process Event for Data", false); + + void processData(EventCandidate const& collision, TrackCandidates const& /*tracks*/) + { + auto posDaughters = positive->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto negDaughters = negative->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + + if (!selectedEvent(collision)) { + return; + } + if (static_cast(eventCuts.inelGt0) && !collision.isInelGt0()) { + return; } - if (static_cast(verbose.verboselevel) > 0 && static_cast(verbose.refresh) > 0 && collision.globalIndex() % static_cast(verbose.refresh) == static_cast(verbose.refreshIndex)) - LOGF(info, "%d pos=%lld neg=%lld, Z vertex position: %f [cm]", collision.globalIndex(), posDaughters.size(), negDaughters.size(), collision.posZ()); + const auto multiplicity = getMultiplicity(collision); + const auto centrality = getCentrality(collision); + const auto vz = collision.posZ(); + + registry.fill(HIST("QA/Event/hVtxZ"), vz); + registry.fill(HIST("QA/Event/hMult"), multiplicity); + registry.fill(HIST("QA/Event/hCent"), centrality); for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDaughters, negDaughters))) { - if (!selectedTrack(track1, true)) // track1 is positive + if (!selectedTrack(track1, true)) { continue; - if (!selectedTrack(track2, false)) // track2 is negative + } + if (!selectedTrack(track2, false)) { continue; + } mother = calculateMother(track1, track2); - if (!seletectedMother(mother)) + if (!selectedMother(mother)) { continue; + } - if (produceQA) { - registry.fill(HIST("QAPID/h2TPCnSigma"), tpcNsigma(track1), tpcNsigma(track2)); - registry.fill(HIST("QAPID/h2TPCnSigmaPt"), track1.pt(), tpcNsigma(track1)); - registry.fill(HIST("QAPID/h2TPCnSigmaPt"), track2.pt(), tpcNsigma(track2)); - - registry.fill(HIST("QAPID/h2TOFnSigma"), tofNsigma(track1), tofNsigma(track2)); - registry.fill(HIST("QAPID/h2TOFnSigmaPt"), track1.pt(), tofNsigma(track1)); - registry.fill(HIST("QAPID/h2TOFnSigmaPt"), track2.pt(), tofNsigma(track2)); - - registry.fill(HIST("QAPID/hTPCnSigma"), tpcNsigma(track1)); - registry.fill(HIST("QAPID/hTPCnSigma"), tpcNsigma(track2)); - if (track1.hasTOF()) - registry.fill(HIST("QAPID/hTOFnSigma"), tofNsigma(track1)); - if (track2.hasTOF()) - registry.fill(HIST("QAPID/hTOFnSigma"), tofNsigma(track2)); - - registry.fill(HIST("QATrack/hEta"), track1.eta()); - registry.fill(HIST("QATrack/hEta"), track2.eta()); - registry.fill(HIST("QATrack/hPt"), track1.pt()); - registry.fill(HIST("QATrack/hPt"), track2.pt()); - registry.fill(HIST("QATrack/hDCAxy"), track1.dcaXY()); - registry.fill(HIST("QATrack/hDCAxy"), track2.dcaXY()); - registry.fill(HIST("QATrack/hDCAz"), track1.dcaZ()); - registry.fill(HIST("QATrack/hDCAz"), track2.dcaZ()); - registry.fill(HIST("QATrack/hTPCNClsFound"), track1.tpcNClsFound()); - registry.fill(HIST("QATrack/hTPCNClsFound"), track2.tpcNClsFound()); - registry.fill(HIST("QATrack/hRapidity"), track1.rapidity(massPos)); - registry.fill(HIST("QATrack/hRapidity"), track2.rapidity(massNeg)); - - registry.fill(HIST("QAPhi/hRapidity"), mother.Rapidity()); - registry.fill(HIST("QAPhi/hEta"), mother.Eta()); - registry.fill(HIST("QAPhi/hdPhi"), track1.phi() - track2.phi()); - registry.fill(HIST("QAPhi/h2dPhiPt"), mother.Pt(), track1.phi() - track2.phi()); - registry.fill(HIST("QAPhi/hTheta"), mother.Theta()); - registry.fill(HIST("QAPhi/h2dThetaPt"), mother.Pt(), d1.Theta() - d2.Theta()); + if (static_cast(produce.produceQA)) { + registry.fill(HIST("QA/Phi/hRapidity"), mother.Pt(), getCentrality(collision), mother.Rapidity()); + registry.fill(HIST("QA/Phi/hEta"), mother.Pt(), getCentrality(collision), mother.Eta()); + registry.fill(HIST("QA/Phi/hdPhi"), mother.Pt(), getCentrality(collision), track1.phi() - track2.phi()); + registry.fill(HIST("QA/Phi/hdPhideta"), track1.eta() - track2.eta(), track1.phi() - track2.phi()); + registry.fill(HIST("QA/Phi/hdTheta"), mother.Pt(), getCentrality(collision), d1.Theta() - d2.Theta()); } pointPair = fillPointPair(mother.M(), mother.Pt(), - getMultiplicity(collision), - getCentrality(collision), + multiplicity, + centrality, tpcNsigma(track1), tpcNsigma(track2), mother.Eta(), mother.Rapidity(), - collision.posZ(), + vz, 0, 0, 0); rsnOutput->fillUnlikepm(pointPair); - if (produceRotational) { - for (int i = 1; i <= static_cast(numberofRotations); i++) { + if (static_cast(produce.produceRotational)) { + + // Rotational background with rotation of track2 around track1 + for (int i = 1; i <= static_cast(nRotations); i++) { float starting = static_cast(startingAngle) * TMath::DegToRad(); - float angle = starting + i * ((o2::constants::math::TwoPI - 2 * starting) / (static_cast(numberofRotations) + 1)); + float angle = starting + i * ((o2::constants::math::TwoPI - 2 * starting) / (static_cast(nRotations) + 1)); float px2new = track2.px() * std::cos(angle) - track2.py() * std::sin(angle); float py2new = track2.px() * std::sin(angle) + track2.py() * std::cos(angle); - d2 = ROOT::Math::PxPyPzMVector(px2new, py2new, track2.pz(), massNeg); - mother = d1 + d2; - - if (produceQA) { - registry.fill(HIST("QARotational/hRapidity"), mother.Rapidity()); - registry.fill(HIST("QARotational/hEta"), mother.Eta()); - registry.fill(HIST("QARotational/hdPhi"), d1.Phi() - d2.Phi()); - registry.fill(HIST("QARotational/h2dPhiPt"), mother.Pt(), d1.Phi() - d2.Phi()); - registry.fill(HIST("QARotational/hTheta"), mother.Theta()); - registry.fill(HIST("QARotational/h2dThetaPt"), mother.Pt(), d1.Theta() - d2.Theta()); + ROOT::Math::PxPyPzMVector d2rot(px2new, py2new, track2.pz(), massNeg); + auto motherRotZ = d1 + d2rot; + + if (static_cast(produce.produceQA)) { + registry.fill(HIST("QA/RotationZ/hRapidity"), motherRotZ.Pt(), getCentrality(collision), motherRotZ.Rapidity()); + registry.fill(HIST("QA/RotationZ/hEta"), motherRotZ.Pt(), getCentrality(collision), motherRotZ.Eta()); + registry.fill(HIST("QA/RotationZ/hdPhi"), motherRotZ.Pt(), getCentrality(collision), d1.Phi() - d2rot.Phi()); + registry.fill(HIST("QA/RotationZ/hdPhideta"), d1.Eta() - d2rot.Eta(), d1.Phi() - d2rot.Phi()); + registry.fill(HIST("QA/RotationZ/hdTheta"), motherRotZ.Pt(), getCentrality(collision), d1.Theta() - d2rot.Theta()); } - pointPair = fillPointPair(mother.M(), - mother.Pt(), - getMultiplicity(collision), - getCentrality(collision), + + pointPair = fillPointPair(motherRotZ.M(), + motherRotZ.Pt(), + multiplicity, + centrality, tpcNsigma(track1), tpcNsigma(track2), - mother.Eta(), - mother.Rapidity(), - collision.posZ(), + motherRotZ.Eta(), + motherRotZ.Rapidity(), + vz, 0, 0, 0); - rsnOutput->fillRotationpm(pointPair); + rsnOutput->fillRotationZ(pointPair); + } + + // Rotational background with rotation of 90 degrees around mother momentum axis + ROOT::Math::AxisAngle rotationAxis(mother.Vect(), constants::math::PIHalf); + ROOT::Math::Rotation3D rotationMatrix(rotationAxis); + + const auto rotD1 = rotationMatrix * d1; + const auto rotD2 = rotationMatrix * d2; + + if (negDaughters.size() > 1) { + for (const auto& track3 : negDaughters) { + if (track3.globalIndex() == track1.globalIndex() || track3.globalIndex() == track2.globalIndex()) { + continue; + } + if (!selectedTrack(track3, false)) { + continue; + } + ROOT::Math::PxPyPzMVector d3(track3.px(), track3.py(), track3.pz(), massNeg); + auto motherRot = rotD1 + d3; + + if (static_cast(produce.produceQA)) { + registry.fill(HIST("QA/Rotation/hRapidity"), motherRot.Pt(), getCentrality(collision), motherRot.Rapidity()); + registry.fill(HIST("QA/Rotation/hEta"), motherRot.Pt(), getCentrality(collision), motherRot.Eta()); + registry.fill(HIST("QA/Rotation/hdPhi"), motherRot.Pt(), getCentrality(collision), rotD1.Phi() - d3.Phi()); + registry.fill(HIST("QA/Rotation/hdPhideta"), rotD1.Eta() - d3.Eta(), rotD1.Phi() - d3.Phi()); + registry.fill(HIST("QA/Rotation/hdTheta"), motherRot.Pt(), getCentrality(collision), rotD1.Theta() - d3.Theta()); + } + + pointPair = fillPointPair(motherRot.M(), + motherRot.Pt(), + multiplicity, + centrality, + tpcNsigma(track1), + tpcNsigma(track2), + motherRot.Eta(), + motherRot.Rapidity(), + vz, + 0, + 0, + 0); + + rsnOutput->fillRotation(pointPair); + + // Likesign rotation for negative daughters + motherRot = rotD2 + d3; + pointPair = fillPointPair(motherRot.M(), + motherRot.Pt(), + multiplicity, + centrality, + tpcNsigma(track1), + tpcNsigma(track2), + motherRot.Eta(), + motherRot.Rapidity(), + vz, + 0, + 0, + 0); + + rsnOutput->fillRotationLike(pointPair); + } + } + + if (posDaughters.size() > 1) { + for (const auto& track3 : posDaughters) { + + if (track3.globalIndex() == track1.globalIndex() || track3.globalIndex() == track2.globalIndex()) { + continue; + } + + if (!selectedTrack(track3, true)) { + continue; + } + + ROOT::Math::PxPyPzMVector d3(track3.px(), track3.py(), track3.pz(), massPos); + + auto motherRot = rotD2 + d3; + + if (static_cast(produce.produceQA)) { + registry.fill(HIST("QA/Rotation/hRapidity"), motherRot.Pt(), getCentrality(collision), motherRot.Rapidity()); + registry.fill(HIST("QA/Rotation/hEta"), motherRot.Pt(), getCentrality(collision), motherRot.Eta()); + registry.fill(HIST("QA/Rotation/hdPhi"), motherRot.Pt(), getCentrality(collision), rotD2.Phi() - d3.Phi()); + registry.fill(HIST("QA/Rotation/hdPhideta"), rotD2.Eta() - d3.Eta(), rotD2.Phi() - d3.Phi()); + registry.fill(HIST("QA/Rotation/hdTheta"), motherRot.Pt(), getCentrality(collision), rotD2.Theta() - d3.Theta()); + } + + pointPair = fillPointPair(motherRot.M(), + motherRot.Pt(), + multiplicity, + centrality, + tpcNsigma(track1), + tpcNsigma(track2), + motherRot.Eta(), + motherRot.Rapidity(), + vz, + 0, + 0, + 0); + + rsnOutput->fillRotation(pointPair); + + // Likesign rotation for positive daughters + motherRot = rotD1 + d3; + pointPair = fillPointPair(motherRot.M(), + motherRot.Pt(), + multiplicity, + centrality, + tpcNsigma(track1), + tpcNsigma(track2), + motherRot.Eta(), + motherRot.Rapidity(), + vz, + 0, + 0, + 0); + + rsnOutput->fillRotationLike(pointPair); + } } } } - - if (produceLikesign) { + if (static_cast(produce.produceLikesign)) { for (const auto& [track1, track2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(posDaughters, posDaughters))) { - if (!selectedTrack(track1, true)) // both positive + if (!selectedTrack(track1, true)) { continue; - if (!selectedTrack(track2, true)) // both positive + } + if (!selectedTrack(track2, true)) { continue; + } mother = calculateMother(track1, track2); - if (!seletectedMother(mother)) + if (!selectedMother(mother)) { continue; - - if (static_cast(verbose.verboselevel) > 1) - LOGF(info, "Like-sign positive: d1=%ld , d2=%ld , mother=%f", track1.globalIndex(), track2.globalIndex(), mother.M()); + } pointPair = fillPointPair(mother.M(), mother.Pt(), @@ -799,17 +1044,17 @@ struct PhianalysisTHnSparse { } for (const auto& [track1, track2] : combinations(o2::soa::CombinationsStrictlyUpperIndexPolicy(negDaughters, negDaughters))) { - if (!selectedTrack(track1, false)) // both negative + if (!selectedTrack(track1, false)) { continue; - if (!selectedTrack(track2, false)) // both negative + } + if (!selectedTrack(track2, false)) { continue; + } mother = calculateMother(track1, track2); - if (!seletectedMother(mother)) + if (!selectedMother(mother)) { continue; - - if (static_cast(verbose.verboselevel) > 1) - LOGF(info, "Like-sign negative: d1=%ld , d2=%ld , mother=%f", track1.globalIndex(), track2.globalIndex(), mother.M()); + } pointPair = fillPointPair(mother.M(), mother.Pt(), @@ -828,111 +1073,100 @@ struct PhianalysisTHnSparse { } } } - PROCESS_SWITCH(PhianalysisTHnSparse, processData, "Process Event for Data", true); + PROCESS_SWITCH(PhianalysisTHnSparse, processData, "Process Event for Data", false); - void processTrue(EventCandidatesMC::iterator const& collision, TrackCandidatesMC const& tracks, aod::McParticles const& /*mcParticles*/, aod::McCollisions const& /*mcCollisions*/) + void processTrue(EventCandidatesMC::iterator const& collision, TrackCandidatesMC const& tracks, aod::McParticles const& /*mcParticles*/, soa::Join const& /*mcCollisions*/) { - if (!static_cast(produce.produceTrue)) + if (!static_cast(produce.produceMC)) { return; + } registry.fill(HIST("QAMC/Rec/hSelection"), 0.5); + registry.fill(HIST("QAMC/Factors/hRecEvents"), getCentrality(collision), 0.5); - if (!collision.sel8()) + if (!selectedEvent(collision)) { return; + } + bool isINELgt0 = false; + if (collision.isInelGt0()) { + isINELgt0 = true; + } - if (produceQA) - registry.fill(HIST("QAMC/Rec/hSelection"), 1.5); + registry.fill(HIST("QAMC/Rec/hSelection"), 1.5); + registry.fill(HIST("QAMC/Factors/hRecEvents"), getCentrality(collision), 1.5); + if (isINELgt0) { + registry.fill(HIST("QAMC/Rec/hSelection"), 2.5); + registry.fill(HIST("QAMC/Factors/hRecEvents"), getCentrality(collision), 2.5); + } - auto posDaughtersMC = positiveMC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - auto negDaughtersMC = negativeMC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); + auto posDaughtersMC = positiveMC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cacheMC); + auto negDaughtersMC = negativeMC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cacheMC); if (!collision.has_mcCollision()) { - if (static_cast(verbose.verboselevel) > 0) - LOGF(warning, "No MC collision for this collision, skip..."); return; } - auto mcCollision = collision.mcCollision(); - registry.fill(HIST("Factors/h2ResolutionVz"), collision.posZ(), (collision.posZ() - mcCollision.posZ())); - if (std::abs(mcCollision.posZ()) > vzCut) - return; - - if (produceQA) - registry.fill(HIST("QAMC/Rec/hSelection"), 2.5); + const auto& mcCollision = collision.mcCollision_as>(); - if (inelGrater0 && !collision.isInelGt0()) - return; - - if (produceQA) - registry.fill(HIST("QAMC/Rec/hSelection"), 3.5); + if (static_cast(produce.produceQA)) { + registry.fill(HIST("QAMC/Resolution/h2ResolutionVz"), collision.posZ(), (collision.posZ() - mcCollision.posZ())); - for (const auto& track : tracks) { - if (track.has_mcParticle()) { - auto mctrack = track.mcParticle(); - registry.fill(HIST("Factors/h2ResolutionPt"), track.pt(), (track.pt() - mctrack.pt())); + for (const auto& track : tracks) { + if (track.has_mcParticle()) { + auto mctrack = track.mcParticle(); + registry.fill(HIST("QAMC/Resolution/h2ResolutionPt"), track.pt(), (track.pt() - mctrack.pt())); + } } } for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDaughtersMC, negDaughtersMC))) { - - if (!track1.has_mcParticle()) { - if (static_cast(verbose.verboselevel) > 0) - LOGF(warning, "No MC particle for track, skip..."); + if (!track1.has_mcParticle() || !track2.has_mcParticle()) { continue; } - if (!track2.has_mcParticle()) { - if (static_cast(verbose.verboselevel) > 0) - LOGF(warning, "No MC particle for track, skip..."); + if (!selectedTrack(track1, true) || !selectedTrack(track2, false)) { continue; } - if (!selectedTrack(track1, true)) // track1 is positive - continue; - if (!selectedTrack(track2, false)) // track2 is negative - continue; - const auto mctrack1 = track1.mcParticle(); const auto mctrack2 = track2.mcParticle(); int track1PDG = std::abs(mctrack1.pdgCode()); int track2PDG = std::abs(mctrack2.pdgCode()); - if (!(track1PDG == daughterPosPDG && track2PDG == daughterNegPDG)) { + if (track1PDG != daughterPosPDG || track2PDG != daughterNegPDG) { continue; } - n = 0; + + int n = 0; for (const auto& mothertrack1 : mctrack1.mothers_as()) { for (const auto& mothertrack2 : mctrack2.mothers_as()) { - if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) + if (mothertrack1.pdgCode() != mothertrack2.pdgCode()) { continue; + } - if (mothertrack1.globalIndex() != mothertrack2.globalIndex()) + if (mothertrack1.globalIndex() != mothertrack2.globalIndex()) { continue; + } - if (std::abs(mothertrack1.y()) > static_cast(cut.rapidity)) + if (std::abs(mothertrack1.y()) > static_cast(trackCuts.rapidity)) { continue; + } - if (std::abs(mothertrack1.pdgCode()) != motherPDG) + if (std::abs(mothertrack1.pdgCode()) != motherPDG) { continue; + } mother = calculateMother(track1, track2); motherGen = calculateMother(mctrack1, mctrack2); - if (!seletectedMother(mother)) + if (!selectedMother(mother)) { continue; + } if (n > 0) { - if (produceQA) - registry.fill(HIST("QAMC/Rec/hInvMassTrueFalse"), mother.M()); continue; } - if (static_cast(verbose.verboselevel) > 1) { - LOGF(info, "Collision: %ld True: %d, d1=%d (%ld), d2=%d (%ld), mother=%d (%ld)", collision.globalIndex(), n, mctrack1.pdgCode(), mctrack1.globalIndex(), mctrack2.pdgCode(), mctrack2.globalIndex(), mothertrack1.pdgCode(), mothertrack1.globalIndex()); - LOGF(info, "Track %d px: %f, py=%f, pz=%f, px: %f, py=%f, pz=%f", n, track1.px(), track1.py(), track1.pz(), track2.px(), track2.py(), track2.pz()); - LOGF(info, "mcTrack %d px: %f, py=%f, pz=%f, px: %f, py=%f, pz=%f", n, mctrack1.px(), mctrack1.py(), mctrack1.pz(), mctrack2.px(), mctrack2.py(), mctrack2.pz()); - } - pointPair = fillPointPair(mother.M(), mother.Pt(), getMultiplicity(collision), @@ -946,22 +1180,12 @@ struct PhianalysisTHnSparse { 0, 0); - if (produceQA) - registry.fill(HIST("QAMC/Rec/hSelection"), 4.5); - - auto phiP = mothertrack1.p(); - auto phiE = mothertrack1.e(); - auto massGen = std::sqrt(phiE * phiE - phiP * phiP); - - registry.fill(HIST("Factors/h2ResolutionPtPhi"), mother.Pt(), (mother.Pt() - mothertrack1.pt())); - registry.fill(HIST("Factors/h2MassResolution"), mother.Pt(), (motherGen.M() - mother.M())); - registry.fill(HIST("Factors/h2MassShift"), mother.Pt(), (massGen - motherGen.M())); - registry.fill(HIST("Factors/h2MassShiftRel"), mother.Pt(), (massGen - motherGen.M()) / massGen); - - if (static_cast(verbose.verboselevel) > 1) - LOGF(info, "mother.M()=%f, motherGen.M()=%f, massGen =%f", mother.M(), motherGen.M(), massGen); + if (static_cast(produce.produceQA)) { + registry.fill(HIST("QAMC/Resolution/h2ResolutionPtPhi"), mother.Pt(), (mother.Pt() - mothertrack1.pt())); + registry.fill(HIST("QAMC/Resolution/h2MassResolution"), mother.Pt(), (motherGen.M() - mother.M())); + } - rsnOutput->fillUnliketrue(pointPair); + rsnOutput->fillUnlikeTrueRec(pointPair); pointPair = fillPointPair(motherGen.M(), motherGen.Pt(), @@ -976,7 +1200,11 @@ struct PhianalysisTHnSparse { 0, 0); - rsnOutput->fillUnlikegenOld(pointPair); + rsnOutput->fillUnlikeTrueGen(pointPair); + + registry.fill(HIST("QAMC/Factors/hRecPhi"), getCentrality(collision), motherGen.Pt()); + registry.fill(HIST("QAMC/Gen/hNPhiPt"), mothertrack1.pt(), 4.5); + registry.fill(HIST("QAMC/Gen/hNPhiPtCent"), mothertrack1.pt(), mcCollision.centFT0M(), 4.5); n++; } @@ -987,160 +1215,247 @@ struct PhianalysisTHnSparse { void processGen(McCollisionMults::iterator const& mcCollision, soa::SmallGroups const& collisions, LabeledTracks const& /*particles*/, aod::McParticles const& mcParticles) { - if (!static_cast(produce.produceTrue)) + if (!static_cast(produce.produceMC)) { return; + } - if (produceQA) - registry.fill(HIST("QAMC/Gen/hSelection"), 0.5); - - if (std::abs(mcCollision.posZ()) > vzCut) - return; + registry.fill(HIST("QAMC/Factors/hNrecInGen"), collisions.size()); + registry.fill(HIST("QAMC/Gen/hSelection"), 0.5); + registry.fill(HIST("QAMC/Factors/hGenEvents"), mcCollision.multMCNParticlesEta05(), 0.5); - if (produceQA) + if (collisions.size() > 0) { registry.fill(HIST("QAMC/Gen/hSelection"), 1.5); + registry.fill(HIST("QAMC/Factors/hGenEvents"), mcCollision.multMCNParticlesEta05(), 2.5); + } - if (inelGrater0 && !mcCollision.isInelGt0()) - return; + int nContributors = -1; + bool hasSelectedCollision = false; + float centrality = 100.5f; + float multiplicity = 0.f; + bool isInelGt0 = false; - if (produceQA) - registry.fill(HIST("QAMC/Gen/hSelection"), 2.5); + for (const auto& collision : collisions) { + registry.fill(HIST("QAMC/Factors/hGenEvents"), mcCollision.multMCNParticlesEta05(), 1.5); + if (!selectedEvent(collision)) { + continue; + } - if (collisions.size() == 0) - return; + if (collision.isInelGt0()) { + isInelGt0 = true; + } - for (const auto& collision : collisions) { - auto centralityGen = getCentrality(collision); - auto multiplicityGen = getMultiplicity(collision); + if (collision.numContrib() > nContributors) { + nContributors = collision.numContrib(); + centrality = getCentrality(collision); + multiplicity = getMultiplicity(collision); + hasSelectedCollision = true; + } + } + + registry.fill(HIST("QAMC/Factors/hGenEventsCentNch"), centrality, mcCollision.multMCNParticlesEta05()); + + // All generated Phi mesons + for (const auto& particle : mcParticles) { + + if (std::abs(particle.y()) > static_cast(trackCuts.rapidity)) { + continue; + } - for (const auto& particle : mcParticles) { + if (particle.pdgCode() == motherPDG) { - if (std::abs(particle.y()) > static_cast(cut.rapidity)) + auto daughters = particle.daughters_as(); + if (daughters.size() != dauSize) { continue; + } - if (particle.pdgCode() == motherPDG) { + auto daup = false; + auto daun = false; - auto daughters = particle.daughters_as(); - if (daughters.size() != dauSize) - continue; + for (const auto& dau : daughters) { + if (dau.pdgCode() == daughterPosPDG) { + daup = true; + d1 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massPos); + } else if (dau.pdgCode() == -daughterNegPDG) { + daun = true; + d2 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massNeg); + } + } + if (!daup || !daun) { + continue; + } - auto daup = false; - auto daun = false; + mother = d1 + d2; - for (const auto& dau : daughters) { - if (dau.pdgCode() == daughterPosPDG) { - daup = true; - d1 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massPos); - } else if (dau.pdgCode() == -daughterNegPDG) { - daun = true; - d2 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massNeg); - } + registry.fill(HIST("QAMC/Factors/hGenPhi"), mcCollision.multMCNParticlesEta05(), centrality, particle.pt()); + } + } + + if (!hasSelectedCollision) { + return; + } + registry.fill(HIST("QAMC/Gen/hSelection"), 2.5); + registry.fill(HIST("QAMC/Factors/hGenEvents"), mcCollision.multMCNParticlesEta05(), 3.5); + registry.fill(HIST("QAMC/Factors/hGenALORESelEvents"), centrality, mcCollision.multMCNParticlesEta05()); + if (isInelGt0) { + registry.fill(HIST("QAMC/Gen/hSelection"), 3.5); + registry.fill(HIST("QAMC/Factors/hGenEvents"), mcCollision.multMCNParticlesEta05(), 4.5); + registry.fill(HIST("QAMC/Factors/hGenALORESelEventsInelGt0"), centrality, mcCollision.multMCNParticlesEta05()); + } + + // Generated Phi mesons in selected collisions + for (const auto& mcParticle : mcParticles) { + if (std::abs(mcParticle.y()) > static_cast(trackCuts.rapidity)) { + continue; + } + + if (mcParticle.pdgCode() == motherPDG) { + auto daughters = mcParticle.daughters_as(); + if (daughters.size() != dauSize) { + continue; + } + + auto daup = false; + auto daun = false; + + for (const auto& dau : daughters) { + if (dau.pdgCode() == daughterPosPDG) { + daup = true; + d1 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massPos); + } else if (dau.pdgCode() == -daughterNegPDG) { + daun = true; + d2 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massNeg); } - if (!daup || !daun) - continue; + } - mother = d1 + d2; + if (!daup || !daun) { + continue; + } - pointPair = fillPointPair(mother.M(), - mother.Pt(), - multiplicityGen, - centralityGen, - 0, - 0, - mother.Eta(), - mother.Rapidity(), - mcCollision.posZ(), - 0, - 0, - 0); + mother = d1 + d2; + + pointPair = fillPointPair(mother.M(), + mother.Pt(), + multiplicity, + centrality, + 0, + 0, + mother.Eta(), + mother.Rapidity(), + mcCollision.posZ(), + 0, + 0, + 0); - rsnOutput->fillUnlikegen(pointPair); - if (produceQA) - registry.fill(HIST("QAMC/Gen/hSelection"), 3.5); + rsnOutput->fillUnlikeGen(pointPair); + registry.fill(HIST("QAMC/Factors/hGenALOREPhi"), mcCollision.multMCNParticlesEta05(), centrality, mother.Pt()); + if (isInelGt0) { + rsnOutput->fillUnlikeGenInelgt0(pointPair); + registry.fill(HIST("QAMC/Factors/hGenALOREPhiInelGt0"), mcCollision.multMCNParticlesEta05(), centrality, mother.Pt()); } } } } PROCESS_SWITCH(PhianalysisTHnSparse, processGen, "Process MC Generated.", false); - void processMixed(soa::Filtered const& collisions, TrackCandidates const& tracks) + void processMixed(EventCandidates const& collisions, TrackCandidates const& tracks) { - if (mixingType == rsn::MixingType::none) + if (mixingType == rsn::MixingType::none) { return; + } auto tracksTuple = std::make_tuple(tracks); BinningTypeVzCe binningVzCe{{axisVertexMixing, axisCentralityMixing}, true}; - SameKindPair pairVzCe{binningVzCe, static_cast(numberofMixedEvents), -1, collisions, tracksTuple, &cache}; + SameKindPair pairVzCe{binningVzCe, static_cast(nMixedEvents), -1, collisions, tracksTuple, &cacheME}; BinningTypeVzMu binningVzMu{{axisVertexMixing, axisMultiplicityMixing}, true}; - SameKindPair pairVzMu{binningVzMu, static_cast(numberofMixedEvents), -1, collisions, tracksTuple, &cache}; + SameKindPair pairVzMu{binningVzMu, static_cast(nMixedEvents), -1, collisions, tracksTuple, &cacheME}; if (mixingType == rsn::MixingType::ce) { for (const auto& [c1, tracks1, c2, tracks2] : pairVzCe) { - if (produceQA) - registry.fill(HIST("QAMixing/hSelection"), 0.5); - - auto posDaughtersc1 = positive->sliceByCached(aod::track::collisionId, c1.globalIndex(), cache); - auto posDaughtersc2 = positive->sliceByCached(aod::track::collisionId, c2.globalIndex(), cache); - auto negDaughtersc1 = negative->sliceByCached(aod::track::collisionId, c1.globalIndex(), cache); - auto negDaughtersc2 = negative->sliceByCached(aod::track::collisionId, c2.globalIndex(), cache); + if (!selectedEvent(c1) || !selectedEvent(c2)) { + continue; + } + if (static_cast(eventCuts.inelGt0) && (!c1.isInelGt0() || !c2.isInelGt0())) { + continue; + } - if (produceQA) { - registry.fill(HIST("QAMixing/h2mu1_mu2"), getMultiplicity(c1), getMultiplicity(c2)); - registry.fill(HIST("QAMixing/h2ce1_ce2"), getCentrality(c1), getCentrality(c2)); - registry.fill(HIST("QAMixing/h2vz1_vz2"), c1.posZ(), c2.posZ()); + const auto multiplicity1 = getMultiplicity(c1); + const auto multiplicity2 = getMultiplicity(c2); + const auto centrality1 = getCentrality(c1); + const auto centrality2 = getCentrality(c2); + const auto vz1 = c1.posZ(); + const auto vz2 = c2.posZ(); + + auto posDaughtersc1 = positive->sliceByCached(aod::track::collisionId, c1.globalIndex(), cacheME); + auto posDaughtersc2 = positive->sliceByCached(aod::track::collisionId, c2.globalIndex(), cacheME); + auto negDaughtersc1 = negative->sliceByCached(aod::track::collisionId, c1.globalIndex(), cacheME); + auto negDaughtersc2 = negative->sliceByCached(aod::track::collisionId, c2.globalIndex(), cacheME); + + if (static_cast(produce.produceQA)) { + registry.fill(HIST("QA/Mixing/h2mu1_mu2"), multiplicity1, multiplicity2); + registry.fill(HIST("QA/Mixing/h2ce1_ce2"), centrality1, centrality2); + registry.fill(HIST("QA/Mixing/h2vz1_vz2"), vz1, vz2); } for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDaughtersc1, negDaughtersc2))) { - - if (!selectedTrack(track1, true)) // track1 is positive + if (!selectedTrack(track1, true)) { continue; - if (!selectedTrack(track2, false)) // track2 is negative + } + if (!selectedTrack(track2, false)) { continue; + } mother = calculateMother(track1, track2); - if (!seletectedMother(mother)) + if (!selectedMother(mother)) { continue; + } + + if (static_cast(produce.produceQA)) { + registry.fill(HIST("QA/Mixing/hdPhideta"), track1.eta() - track2.eta(), track1.phi() - track2.phi()); + } pointPair = fillPointPair(mother.M(), mother.Pt(), - getMultiplicity(c1), - getCentrality(c1), + multiplicity1, + centrality1, tpcNsigma(track1), tpcNsigma(track2), mother.Eta(), mother.Rapidity(), - c1.posZ(), - getMultiplicity(c2), - getCentrality(c2), - c2.posZ()); + vz1, + multiplicity2, + centrality2, + vz2); rsnOutput->fillMixingpm(pointPair); } for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDaughtersc2, negDaughtersc1))) { - - if (!selectedTrack(track1, true)) // track1 is positive + if (!selectedTrack(track1, true)) { continue; - if (!selectedTrack(track2, false)) // track2 is negative + } + if (!selectedTrack(track2, false)) { continue; + } mother = calculateMother(track1, track2); - if (!seletectedMother(mother)) + if (!selectedMother(mother)) { continue; + } pointPair = fillPointPair(mother.M(), mother.Pt(), - getMultiplicity(c1), - getCentrality(c1), + multiplicity1, + centrality1, tpcNsigma(track1), tpcNsigma(track2), mother.Eta(), mother.Rapidity(), - c1.posZ(), - getMultiplicity(c2), - getCentrality(c2), - c2.posZ()); + vz1, + multiplicity2, + centrality2, + vz2); rsnOutput->fillMixingmp(pointPair); } @@ -1148,72 +1463,87 @@ struct PhianalysisTHnSparse { } if (mixingType == rsn::MixingType::mu) { for (const auto& [c1, tracks1, c2, tracks2] : pairVzMu) { - if (produceQA) - registry.fill(HIST("QAMixing/hSelection"), 0.5); + if (!selectedEvent(c1) || !selectedEvent(c2)) { + continue; + } + if (static_cast(eventCuts.inelGt0) && (!c1.isInelGt0() || !c2.isInelGt0())) { + continue; + } auto posDaughtersc1 = positive->sliceByCached(aod::track::collisionId, c1.globalIndex(), cache); auto posDaughtersc2 = positive->sliceByCached(aod::track::collisionId, c2.globalIndex(), cache); auto negDaughtersc1 = negative->sliceByCached(aod::track::collisionId, c1.globalIndex(), cache); auto negDaughtersc2 = negative->sliceByCached(aod::track::collisionId, c2.globalIndex(), cache); - - if (produceQA) { - registry.fill(HIST("QAMixing/h2mu1_mu2"), getMultiplicity(c1), getMultiplicity(c2)); - registry.fill(HIST("QAMixing/h2ce1_ce2"), getCentrality(c1), getCentrality(c2)); - registry.fill(HIST("QAMixing/h2vz1_vz2"), c1.posZ(), c2.posZ()); + const auto multiplicity1 = getMultiplicity(c1); + const auto multiplicity2 = getMultiplicity(c2); + const auto centrality1 = getCentrality(c1); + const auto centrality2 = getCentrality(c2); + const auto vz1 = c1.posZ(); + const auto vz2 = c2.posZ(); + + if (static_cast(produce.produceQA)) { + registry.fill(HIST("QA/Mixing/h2mu1_mu2"), multiplicity1, multiplicity2); + registry.fill(HIST("QA/Mixing/h2ce1_ce2"), centrality1, centrality2); + registry.fill(HIST("QA/Mixing/h2vz1_vz2"), vz1, vz2); } for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDaughtersc1, negDaughtersc2))) { - if (!selectedTrack(track1, true)) // track1 is positive + if (!selectedTrack(track1, true)) { continue; + } - if (!selectedTrack(track2, false)) // track2 is negative + if (!selectedTrack(track2, false)) { continue; + } mother = calculateMother(track1, track2); - if (!seletectedMother(mother)) + if (!selectedMother(mother)) { continue; + } pointPair = fillPointPair(mother.M(), mother.Pt(), - getMultiplicity(c1), - getCentrality(c1), + multiplicity1, + centrality1, tpcNsigma(track1), tpcNsigma(track2), mother.Eta(), mother.Rapidity(), - c1.posZ(), - getMultiplicity(c2), - getCentrality(c2), - c2.posZ()); + vz1, + multiplicity2, + centrality2, + vz2); rsnOutput->fillMixingpm(pointPair); } for (const auto& [track1, track2] : combinations(o2::soa::CombinationsFullIndexPolicy(posDaughtersc2, negDaughtersc1))) { - if (!selectedTrack(track1, true)) - + if (!selectedTrack(track1, true)) { continue; - if (!selectedTrack(track2, false)) + } + if (!selectedTrack(track2, false)) { continue; + } mother = calculateMother(track1, track2); - if (!seletectedMother(mother)) + if (!selectedMother(mother)) { continue; + } pointPair = fillPointPair(mother.M(), mother.Pt(), - getMultiplicity(c1), - getCentrality(c1), + multiplicity1, + centrality1, tpcNsigma(track1), tpcNsigma(track2), mother.Eta(), mother.Rapidity(), - c1.posZ(), - getMultiplicity(c2), - getCentrality(c2), - c2.posZ()); + vz1, + multiplicity2, + centrality2, + vz2); rsnOutput->fillMixingmp(pointPair); } @@ -1222,38 +1552,44 @@ struct PhianalysisTHnSparse { } PROCESS_SWITCH(PhianalysisTHnSparse, processMixed, "Process Mixing Event.", false); - void processFactors(McCollisionMults::iterator const& mcCollision, soa::SmallGroups const& collisions, LabeledTracks const& /*particles*/, aod::McParticles const& mcParticles) + void processCorr(soa::Join::iterator const& mcCollision, aod::McParticles const& mcParticles, + soa::SmallGroups> const& collisions, + soa::Join const&) { - registry.fill(HIST("Factors/hGenEvents"), mcCollision.multMCNParticlesEta08(), 0.5); - - if (std::abs(mcCollision.posZ()) > vzCut) + if (!static_cast(produce.produceMC)) { return; + } - registry.fill(HIST("Factors/hGenEvents"), mcCollision.multMCNParticlesEta08(), 1.5); + registry.fill(HIST("QAMC/Gen/hNEvents"), 0.5); + registry.fill(HIST("QAMC/Gen/hNEventsCent"), mcCollision.centFT0M(), 0.5); - if (inelGrater0 && !mcCollision.isInelGt0()) + if (std::abs(mcCollision.posZ()) > static_cast(eventCuts.vzCut)) { return; + } + registry.fill(HIST("QAMC/Gen/hNEvents"), 1.5); + registry.fill(HIST("QAMC/Gen/hNEventsCent"), mcCollision.centFT0M(), 1.5); - registry.fill(HIST("Factors/hGenEvents"), mcCollision.multMCNParticlesEta08(), 2.5); + registry.fill(HIST("QAMC/Gen/hNEvents"), 2.5); + registry.fill(HIST("QAMC/Gen/hNEventsCent"), mcCollision.centFT0M(), 2.5); - float centrality = 100.5f; - for (auto const& collision : collisions) { - centrality = collision.centFT0M(); + bool isINELgt0 = false; + if (pwglf::isINELgtNmc(mcParticles, 0, pdg)) { + isINELgt0 = true; + registry.fill(HIST("QAMC/Gen/hNEvents"), 3.5); + registry.fill(HIST("QAMC/Gen/hNEventsCent"), mcCollision.centFT0M(), 3.5); // Event Loss Denominator } - registry.fill(HIST("Factors/hCentralityVsMultMC"), centrality, mcCollision.multMCNParticlesEta08()); - registry.fill(HIST("Factors/hNrecInGen"), collisions.size()); + for (const auto& mcParticle : mcParticles) { - for (const auto& particle : mcParticles) { - - if (std::abs(particle.y()) > static_cast(cut.rapidity)) + if (std::abs(mcParticle.y()) > static_cast(trackCuts.rapidity)) { continue; + } - if (particle.pdgCode() == motherPDG) { - - auto daughters = particle.daughters_as(); - if (daughters.size() != dauSize) + if (mcParticle.pdgCode() == motherPDG) { + auto daughters = mcParticle.daughters_as(); + if (daughters.size() != dauSize) { continue; + } auto daup = false; auto daun = false; @@ -1267,23 +1603,93 @@ struct PhianalysisTHnSparse { d2 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massNeg); } } - if (!daup || !daun) + if (!daup || !daun) { continue; + } + registry.fill(HIST("QAMC/Gen/hNPhiPt"), mcParticle.pt(), 0.5); + registry.fill(HIST("QAMC/Gen/hNPhiPtCent"), mcParticle.pt(), mcCollision.centFT0M(), 0.5); + if (isINELgt0) { + registry.fill(HIST("QAMC/Gen/hNPhiPt"), mcParticle.pt(), 1.5); + registry.fill(HIST("QAMC/Gen/hNPhiPtCent"), mcParticle.pt(), mcCollision.centFT0M(), 1.5); // Signal Loss Denominator + } + } + } - mother = d1 + d2; + int nRecoInelColl = 0; + int nRecoInelGt0Coll = 0; + for (const auto& collision : collisions) { + + registry.fill(HIST("QAMC/Rec/hNEvents"), 0.5); + registry.fill(HIST("QAMC/Rec/hNEventsCent"), mcCollision.centFT0M(), 0.5); - registry.fill(HIST("Factors/h2dGenPhi"), centrality, mother.Pt()); - registry.fill(HIST("Factors/h3dGenPhiVsMultMCVsCentrality"), mcCollision.multMCNParticlesEta08(), centrality, mother.Pt()); + if (!selectedEvent(collision)) { + continue; + } + + nRecoInelColl++; + registry.fill(HIST("QAMC/Rec/hNEvents"), 1.5); + registry.fill(HIST("QAMC/Rec/hNEventsCent"), mcCollision.centFT0M(), 1.5); + + if (collision.isInelGt0()) { + nRecoInelGt0Coll++; + registry.fill(HIST("QAMC/Rec/hNEvents"), 2.5); + registry.fill(HIST("QAMC/Rec/hNEventsCent"), mcCollision.centFT0M(), 2.5); } } - if (collisions.size() == 0) + if (nRecoInelColl < 1) { // At least one reconstructed event/collision return; + } + + registry.fill(HIST("QAMC/Gen/hNEvents"), 4.5); + registry.fill(HIST("QAMC/Gen/hNEventsCent"), mcCollision.centFT0M(), 4.5); + + if (nRecoInelGt0Coll > 0) { + registry.fill(HIST("QAMC/Gen/hNEvents"), 5.5); + registry.fill(HIST("QAMC/Gen/hNEventsCent"), mcCollision.centFT0M(), 5.5); // Event Loss Numerator + } + + for (const auto& mcParticle : mcParticles) { + + if (std::abs(mcParticle.y()) > static_cast(trackCuts.rapidity)) { + continue; + } - registry.fill(HIST("Factors/hGenEvents"), mcCollision.multMCNParticlesEta08(), 3.5); + if (mcParticle.pdgCode() == motherPDG) { + + auto daughters = mcParticle.daughters_as(); + if (daughters.size() != dauSize) { + continue; + } + + auto daup = false; + auto daun = false; + + for (const auto& dau : daughters) { + if (dau.pdgCode() == daughterPosPDG) { + daup = true; + d1 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massPos); + } else if (dau.pdgCode() == -daughterNegPDG) { + daun = true; + d2 = ROOT::Math::PxPyPzMVector(dau.px(), dau.py(), dau.pz(), massNeg); + } + } + if (!daup || !daun) { + continue; + } + + registry.fill(HIST("QAMC/Gen/hNPhiPt"), mcParticle.pt(), 2.5); + registry.fill(HIST("QAMC/Gen/hNPhiPtCent"), mcParticle.pt(), mcCollision.centFT0M(), 2.5); + if (nRecoInelGt0Coll > 0) { + registry.fill(HIST("QAMC/Gen/hNPhiPt"), mcParticle.pt(), 3.5); + registry.fill(HIST("QAMC/Gen/hNPhiPtCent"), mcParticle.pt(), mcCollision.centFT0M(), 3.5); // Signal Loss Numerator + } + } + } } - PROCESS_SWITCH(PhianalysisTHnSparse, processFactors, "Process to obtain normalization factors from MC.", false); + PROCESS_SWITCH(PhianalysisTHnSparse, processCorr, "Process to calculate corrections.", false); }; + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ diff --git a/PWGLF/Tasks/Resonances/phianalysisrun3.cxx b/PWGLF/Tasks/Resonances/phianalysisrun3.cxx index b923303eb1d..2d0218171ae 100644 --- a/PWGLF/Tasks/Resonances/phianalysisrun3.cxx +++ b/PWGLF/Tasks/Resonances/phianalysisrun3.cxx @@ -266,7 +266,7 @@ struct phianalysisrun3 { histos.fill(HIST("hCentrality"), multiplicity); histos.fill(HIST("hNcontributor"), collision.numContrib()); histos.fill(HIST("hVtxZ"), collision.posZ()); - for (auto track1 : tracks) { + for (const auto& track1 : tracks) { if (!selectionTrack(track1)) { continue; } @@ -276,7 +276,7 @@ struct phianalysisrun3 { histos.fill(HIST("hNsigmaKaonTPC"), track1.tpcNSigmaKa()); histos.fill(HIST("hNsigmaKaonTOF"), track1.tofNSigmaKa()); auto track1ID = track1.index(); - for (auto track2 : tracks) { + for (const auto& track2 : tracks) { if (!selectionTrack(track2)) { continue; } @@ -394,7 +394,7 @@ struct phianalysisrun3 { } auto daughtp = false; auto daughtm = false; - for (auto kCurrentDaughter : kDaughters) { + for (const auto& kCurrentDaughter : kDaughters) { if (!kCurrentDaughter.isPhysicalPrimary()) { continue; } @@ -421,7 +421,7 @@ struct phianalysisrun3 { } histos.fill(HIST("hMC"), 5.5); auto oldindex = -999; - for (auto track1 : tracks) { + for (const auto& track1 : tracks) { if (!selectionTrack(track1)) { continue; } @@ -429,7 +429,7 @@ struct phianalysisrun3 { continue; } auto track1ID = track1.index(); - for (auto track2 : tracks) { + for (const auto& track2 : tracks) { if (!track2.has_mcParticle()) { continue; } diff --git a/PWGLF/Tasks/Resonances/phiflowder.cxx b/PWGLF/Tasks/Resonances/phiflowder.cxx index 7ebe626ca24..a76e1dc7fdc 100644 --- a/PWGLF/Tasks/Resonances/phiflowder.cxx +++ b/PWGLF/Tasks/Resonances/phiflowder.cxx @@ -18,6 +18,7 @@ #include #include +#include #include #include #include diff --git a/PWGLF/Tasks/Resonances/phipbpb.cxx b/PWGLF/Tasks/Resonances/phipbpb.cxx index 21e731f8964..ca124250f26 100644 --- a/PWGLF/Tasks/Resonances/phipbpb.cxx +++ b/PWGLF/Tasks/Resonances/phipbpb.cxx @@ -635,7 +635,7 @@ struct phipbpb { int Npostrack = 0; float weight1 = 1.0; float weight2 = 1.0; - for (auto track1 : posThisColl) { + for (const auto& track1 : posThisColl) { // track selection if (!selectionTrack(track1)) { continue; @@ -673,7 +673,7 @@ struct phipbpb { weight1 = 1; } } - for (auto track2 : negThisColl) { + for (const auto& track2 : negThisColl) { // track selection if (!selectionTrack(track2)) { continue; @@ -862,7 +862,7 @@ struct phipbpb { } int Npostrack = 0; - for (auto track1 : posThisColl) { + for (const auto& track1 : posThisColl) { // track selection if (!selectionTrack(track1)) { continue; @@ -881,7 +881,7 @@ struct phipbpb { continue; } auto track1ID = track1.globalIndex(); - for (auto track2 : negThisColl) { + for (const auto& track2 : negThisColl) { // track selection if (!selectionTrack(track2)) { continue; @@ -1465,7 +1465,7 @@ struct phipbpb { auto oldindex = -999; auto Rectrackspart = RecTracks.sliceBy(perCollision, RecCollision.globalIndex()); // loop over reconstructed particle - for (auto track1 : Rectrackspart) { + for (const auto& track1 : Rectrackspart) { if (!selectionTrack(track1)) { continue; } @@ -1479,7 +1479,7 @@ struct phipbpb { continue; } auto track1ID = track1.index(); - for (auto track2 : Rectrackspart) { + for (const auto& track2 : Rectrackspart) { auto track2ID = track2.index(); if (track2ID <= track1ID) { continue; @@ -1576,7 +1576,7 @@ struct phipbpb { } auto daughtp = false; auto daughtm = false; - for (auto kCurrentDaughter : kDaughters) { + for (const auto& kCurrentDaughter : kDaughters) { if (!kCurrentDaughter.isPhysicalPrimary()) { continue; } @@ -1760,7 +1760,7 @@ struct phipbpb { auto oldindex = -999; auto Rectrackspart = RecTracks.sliceBy(perCollision, RecCollision.globalIndex()); // loop over reconstructed particle - for (auto track1 : Rectrackspart) { + for (const auto& track1 : Rectrackspart) { if (!track1.has_mcParticle()) { continue; } @@ -1775,7 +1775,7 @@ struct phipbpb { histos.fill(HIST("hSparsePhiMCRecKaonMissMatchWeight"), centclass, GetPhiInRange(mctrack1.phi() - psiFT0C), TMath::Power(TMath::Cos(4.0 * GetPhiInRange(mctrack1.phi() - psiFT0C)), 1.0), mctrack1.pt(), mctrack1.eta()); } auto track1ID = track1.index(); - for (auto track2 : Rectrackspart) { + for (const auto& track2 : Rectrackspart) { if (!track2.has_mcParticle()) { continue; } @@ -1854,7 +1854,7 @@ struct phipbpb { } auto daughtp = false; auto daughtm = false; - for (auto kCurrentDaughter : kDaughters) { + for (const auto& kCurrentDaughter : kDaughters) { if (!kCurrentDaughter.isPhysicalPrimary()) { continue; } diff --git a/PWGLF/Tasks/Resonances/phispectrapbpbqa.cxx b/PWGLF/Tasks/Resonances/phispectrapbpbqa.cxx index 061c8bd7a6c..d26a5b66045 100644 --- a/PWGLF/Tasks/Resonances/phispectrapbpbqa.cxx +++ b/PWGLF/Tasks/Resonances/phispectrapbpbqa.cxx @@ -362,7 +362,7 @@ struct phispectrapbpbqa { int Npostrack = 0; histos.fill(HIST("hOccupancy"), occupancy, centrality); - for (auto track1 : posThisColl) { + for (const auto& track1 : posThisColl) { if (!selectionTrack(track1)) { continue; } @@ -409,7 +409,7 @@ struct phispectrapbpbqa { // 1) φ at a chosen radius (e.g., outer pad rows ~247 cm) histos.fill(HIST("hPhiMommentum"), track1.phi(), track1.p(), occupancy); - for (auto track2 : negThisColl) { + for (const auto& track2 : negThisColl) { if (track1.sign() * track2.sign() > 0.0) { continue; } @@ -643,7 +643,7 @@ struct phispectrapbpbqa { auto Rectrackspart = RecTracks.sliceBy(perCollision, RecCollision.globalIndex()); // loop over reconstructed particle int ntrack1 = 0; - for (auto track1 : Rectrackspart) { + for (const auto& track1 : Rectrackspart) { if (!selectionTrack(track1)) { continue; } @@ -677,7 +677,7 @@ struct phispectrapbpbqa { histos.fill(HIST("hNsigmaTOFAfterCut"), nSigmaTOF, track1.p(), occupancy); } ntrack1 = ntrack1 + 1; - for (auto track2 : Rectrackspart) { + for (const auto& track2 : Rectrackspart) { auto track2ID = track2.index(); if (track2ID <= track1ID) { continue; @@ -785,7 +785,7 @@ struct phispectrapbpbqa { } auto daughtp = false; auto daughtm = false; - for (auto kCurrentDaughter : kDaughters) { + for (const auto& kCurrentDaughter : kDaughters) { if (!kCurrentDaughter.isPhysicalPrimary()) { continue; } diff --git a/PWGLF/Tasks/Resonances/phitutorial.cxx b/PWGLF/Tasks/Resonances/phitutorial.cxx index 0cd3fecbbe8..d60c63819e6 100644 --- a/PWGLF/Tasks/Resonances/phitutorial.cxx +++ b/PWGLF/Tasks/Resonances/phitutorial.cxx @@ -81,7 +81,7 @@ struct phitutorial { // PREAMBLE COMPLETE, NOW WE DO HELPER FCNS //**************************************// template - bool eventSelection(const EventType event) + bool eventSelection(const EventType& event) { if (!event.sel8()) return false; @@ -98,7 +98,7 @@ struct phitutorial { }; //********************************************// template - bool trackSelection(const TracksType track) + bool trackSelection(const TracksType& track) { if (!track.isGlobalTrack()) return false; diff --git a/PWGLF/Tasks/Resonances/phitutorial_step0.cxx b/PWGLF/Tasks/Resonances/phitutorial_step0.cxx index 6bd6ab64e3d..f3feee957d8 100644 --- a/PWGLF/Tasks/Resonances/phitutorial_step0.cxx +++ b/PWGLF/Tasks/Resonances/phitutorial_step0.cxx @@ -70,7 +70,7 @@ struct phitutorial_step0 { // PREAMBLE COMPLETE, NOW WE DO HELPER FCNS //**************************************// template - bool eventSelection(const EventType event) + bool eventSelection(const EventType& event) { if (!event.sel8()) // This is required to extract good events return false; diff --git a/PWGLF/Tasks/Resonances/phitutorial_step1.cxx b/PWGLF/Tasks/Resonances/phitutorial_step1.cxx index 1e6c5d129a8..6420ab51139 100644 --- a/PWGLF/Tasks/Resonances/phitutorial_step1.cxx +++ b/PWGLF/Tasks/Resonances/phitutorial_step1.cxx @@ -75,7 +75,7 @@ struct phitutorial_step1 { // PREAMBLE COMPLETE, NOW WE DO HELPER FCNS //**************************************// template - bool eventSelection(const EventType event) + bool eventSelection(const EventType& event) { if (!event.sel8()) // This is required to extract good events return false; diff --git a/PWGLF/Tasks/Resonances/phitutorial_step2.cxx b/PWGLF/Tasks/Resonances/phitutorial_step2.cxx index f1f0285e698..b77cccbea39 100644 --- a/PWGLF/Tasks/Resonances/phitutorial_step2.cxx +++ b/PWGLF/Tasks/Resonances/phitutorial_step2.cxx @@ -75,7 +75,7 @@ struct phitutorial_step2 { // PREAMBLE COMPLETE, NOW WE DO HELPER FCNS //**************************************// template - bool eventSelection(const EventType event) + bool eventSelection(const EventType& event) { if (!event.sel8()) // This is required to extract good events return false; @@ -84,7 +84,7 @@ struct phitutorial_step2 { }; //********************************************// template - bool trackSelection(const TracksType track) + bool trackSelection(const TracksType& track) { if (!track.isGlobalTrack()) return false; diff --git a/PWGLF/Tasks/Resonances/phitutorial_step3.cxx b/PWGLF/Tasks/Resonances/phitutorial_step3.cxx index 5278d1b67f3..c2f072e37d0 100644 --- a/PWGLF/Tasks/Resonances/phitutorial_step3.cxx +++ b/PWGLF/Tasks/Resonances/phitutorial_step3.cxx @@ -81,7 +81,7 @@ struct phitutorial_step3 { // PREAMBLE COMPLETE, NOW WE DO HELPER FCNS //**************************************// template - bool eventSelection(const EventType event) + bool eventSelection(const EventType& event) { if (!event.sel8()) // This is required to extract good events return false; @@ -90,7 +90,7 @@ struct phitutorial_step3 { }; //********************************************// template - bool trackSelection(const TracksType track) + bool trackSelection(const TracksType& track) { if (!track.isGlobalTrack()) return false; diff --git a/PWGLF/Tasks/Resonances/rho770analysis.cxx b/PWGLF/Tasks/Resonances/rho770analysis.cxx index 0b7c7f34d31..b07a83bb07b 100644 --- a/PWGLF/Tasks/Resonances/rho770analysis.cxx +++ b/PWGLF/Tasks/Resonances/rho770analysis.cxx @@ -151,7 +151,7 @@ struct rho770analysis { double massKa = MassKaonCharged; template - bool selTrack(const TrackType track) + bool selTrack(const TrackType& track) { if (std::abs(track.pt()) < cfgMinPt) return false; @@ -194,7 +194,7 @@ struct rho770analysis { } template - bool selPion(const TrackType track) + bool selPion(const TrackType& track) { const auto mode = static_cast(selectTypeInt.value); @@ -223,7 +223,7 @@ struct rho770analysis { } template - bool selKaon(const TrackType track) + bool selKaon(const TrackType& track) { const auto mode = static_cast(selectTypeInt.value); diff --git a/PWGLF/Tasks/Resonances/rhoanalysis.cxx b/PWGLF/Tasks/Resonances/rhoanalysis.cxx index a061f78375e..77f4bd5c1e0 100644 --- a/PWGLF/Tasks/Resonances/rhoanalysis.cxx +++ b/PWGLF/Tasks/Resonances/rhoanalysis.cxx @@ -305,11 +305,11 @@ struct rhoanalysis { if (std::abs(events.mcCollision().posZ()) > cfgCutVertex) { return; } - for (auto track1 : tracks) { + for (const auto& track1 : tracks) { histos.fill(HIST("hNsigmaPionTPCvspT"), track1.pt(), track1.tpcNSigmaPi()); if (abs(track1.tpcNSigmaPi()) > nsigmaCutCombined) continue; - for (auto track2 : tracks) { + for (const auto& track2 : tracks) { if (abs(track2.tpcNSigmaPi()) > nsigmaCutCombined) continue; @@ -367,7 +367,7 @@ struct rhoanalysis { if (kDaughters.size() != 2) continue; - for (auto kCurrentDaughter : kDaughters) { + for (const auto& kCurrentDaughter : kDaughters) { if (!kCurrentDaughter.isPhysicalPrimary()) continue; diff --git a/PWGLF/Tasks/Resonances/rsnanalysis.cxx b/PWGLF/Tasks/Resonances/rsnanalysis.cxx index eefe03403a2..9dd65838d5c 100644 --- a/PWGLF/Tasks/Resonances/rsnanalysis.cxx +++ b/PWGLF/Tasks/Resonances/rsnanalysis.cxx @@ -339,7 +339,7 @@ struct rsn_analysis { std::vector> kNegSelectedPions; // // Loop on Tracks - for (auto kCurrentTrack : kTracks) { + for (const auto& kCurrentTrack : kTracks) { // // Track Selection if (!uIsTrackSelected(kCurrentTrack)) @@ -576,7 +576,7 @@ struct rsn_analysis { std::vector> kNegSelectedPions; // // Loop on Tracks - for (auto kCurrentTrack : kTracks) { + for (const auto& kCurrentTrack : kTracks) { // // Track Selection if (!uIsTrackSelected(kCurrentTrack)) @@ -730,7 +730,7 @@ struct rsn_analysis { { // Loop on all mc particles - for (auto kCurrentParticle : mcParticles) { + for (const auto& kCurrentParticle : mcParticles) { // if (!kCurrentParticle.producedByGenerator()) continue; @@ -744,7 +744,7 @@ struct rsn_analysis { auto kHasKaonp = false; auto kHasKaonm = false; if (kDaughters.size() == 2) { - for (auto kCurrentDaughter : kDaughters) { + for (const auto& kCurrentDaughter : kDaughters) { if (kCurrentDaughter.pdgCode() == +321) kHasKaonp = true; if (kCurrentDaughter.pdgCode() == -321) @@ -763,7 +763,7 @@ struct rsn_analysis { auto kHasKaonp = false; auto kHasKaonm = false; if (kDaughters.size() == 2) { - for (auto kCurrentDaughter : kDaughters) { + for (const auto& kCurrentDaughter : kDaughters) { if (fabs(kCurrentDaughter.pdgCode()) == 321) kHasKaonp = true; if (fabs(kCurrentDaughter.pdgCode()) == 211) diff --git a/PWGLF/Tasks/Resonances/sigma.cxx b/PWGLF/Tasks/Resonances/sigma.cxx index 6081fa5a8e5..487a967e93d 100644 --- a/PWGLF/Tasks/Resonances/sigma.cxx +++ b/PWGLF/Tasks/Resonances/sigma.cxx @@ -286,7 +286,7 @@ struct sigma { rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); rEventSelection.fill(HIST("hmult"), multiplicity); - for (auto track1 : tracks) { + for (const auto& track1 : tracks) { if (QAbefore) { histos.fill(HIST("hNsigmaPionTPC_before"), track1.tpcNSigmaPi()); diff --git a/PWGLF/Tasks/Resonances/xi1530Analysis.cxx b/PWGLF/Tasks/Resonances/xi1530Analysis.cxx index ae911cf197a..3e5b70c04b1 100644 --- a/PWGLF/Tasks/Resonances/xi1530Analysis.cxx +++ b/PWGLF/Tasks/Resonances/xi1530Analysis.cxx @@ -229,7 +229,7 @@ struct cascadeXiAnalysis { // kinematic cuts method template - bool kinCuts(U trk1, K trk2, T p, float& alpha) + bool kinCuts(const U& trk1, const K& trk2, const T& p, float& alpha) { // initialize std::vector kinCutsPt = static_cast>(cKinCutsPt); diff --git a/PWGLF/Tasks/Resonances/xi1530Analysisqa.cxx b/PWGLF/Tasks/Resonances/xi1530Analysisqa.cxx index d4169378e9f..3ed15c1328d 100644 --- a/PWGLF/Tasks/Resonances/xi1530Analysisqa.cxx +++ b/PWGLF/Tasks/Resonances/xi1530Analysisqa.cxx @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -28,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -36,12 +35,20 @@ #include #include // IWYU pragma: keep (do not replace with Math/Vector4Dfwd.h) #include -#include #include -#include + +#include +#include +#include +#include #include +#include #include +#include +#include +#include +#include #include using namespace o2; @@ -52,34 +59,55 @@ using namespace o2::constants::physics; using LorentzVectorPtEtaPhiMass = ROOT::Math::PtEtaPhiMVector; using LorentzVectorSetXYZM = ROOT::Math::LorentzVector>; -Service pdgDB; - enum { kData = 0, - kLS, - kMixing, - kMCReco, - kMCTrue, - kMCTruePS, - kINEL10, - kINELg010, - kAllType, + kLS = 1, + kMixing = 2, + kMCReco = 3, + kMCTrue = 4, + kMCTruePS = 5, + kINEL10 = 6, + kINELg010 = 7, + kAllType = 8, kXiStar = 3324 }; struct Xi1530Analysisqa { + // Module-initializer tables; full tracks and cascades retain their schema. + using ResoCollisions = aod::ResoCollisions_001; + // Read original IDs only; no track_as() or original AO2D is needed here. + using ResoTracks = soa::Join; + using ResoMicroTracks = aod::ResoMicroTracks_001; + using ResoMCCols = soa::Join; + + // Own just the event rows: zero-copy slices would retain entire DF buffers. + struct MixingCollision { + float x, y, z, centrality, multiplicity; + int64_t index; + bool recINELgt0; + [[nodiscard]] float posX() const { return x; } + [[nodiscard]] float posY() const { return y; } + [[nodiscard]] float posZ() const { return z; } + [[nodiscard]] int64_t globalIndex() const { return index; } + }; + struct MixingEvent { + MixingCollision collision{}; + std::shared_ptr tracks; + }; + std::map> mixingPools; + float mixingBField = 0.f; + // Basic set-up // SliceCache cache; Preslice perRCol = aod::resodaughter::resoCollisionId; Preslice perCollision = aod::track::collisionId; - Preslice perResoCollision = + Preslice perResoCollision = aod::resodaughter::resoCollisionId; Preslice perResoCollisionCasc = aod::resodaughter::resoCollisionId; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - using ResoMCCols = soa::Join; // Associated with histograms struct : ConfigurableGroup { ConfigurableAxis binsPt{"binsPt", {VARIABLE_WIDTH, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 11.9, 12.0, 12.1, 12.2, 12.3, 12.4, 12.5, 12.6, 12.7, 12.8, 12.9, 13.0, 13.1, 13.2, 13.3, 13.4, 13.5, 13.6, 13.7, 13.8, 13.9, 14.0, 14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 14.7, 14.8, 14.9, 15.0}, "Binning of the pT axis"}; @@ -124,23 +152,24 @@ struct Xi1530Analysisqa { Configurable cfgTPCRows{"cfgTPCRows", 80, "Minimum Number of TPC Crossed Rows "}; - Configurable cfgHasTOF{"cfgHasTOF", false, "Require TOF"}; - Configurable cfgRapidityMinCut{"cfgRapidityMinCut", -0.5, "Rapidity cut for tracks"}; Configurable cfgRapidityMaxCut{"cfgRapidityMaxCut", 0.5, "Rapidity cut for tracks"}; // Primary track DCAxy to PV ConfigurableAxis cDCAtoPVBins{"cDCAtoPVBins", {1500, 0, 0.3}, "Bins for track DCA to PV"}; - Configurable cDCAxytoPVByPtPiFirstP0{"cDCAxytoPVByPtPiFirstP0", 0.004, "Coeff. Track DCAxy cut to PV by pt for Pion First (p0)"}; - Configurable cDCAxyToPVByPtPiFirstExp{"cDCAxyToPVByPtPiFirstExp", 0.013, "Coeff. Track DCAxy cut to PV by pt for Pion First (exp)"}; + Configurable cDCAxyToPVAsPt{"cDCAxyToPVAsPt", true, "Use the pT-dependent pion DCAxy cut; otherwise use cMaxDCAxyToPVCut"}; + Configurable cMaxDCAxyToPVCut{"cMaxDCAxyToPVCut", 0.5f, "Constant maximum pion |DCAxy| (cm) when its pT-dependent cut is disabled"}; + Configurable cDCAxytoPVByPtPiFirstP0{"cDCAxytoPVByPtPiFirstP0", 0.004, "Constant term of the pion pT-dependent DCAxy/z cut (cm)"}; + Configurable cDCAxyToPVByPtPiFirstExp{"cDCAxyToPVByPtPiFirstExp", 0.013, "Coefficient in pion DCAxy/z cut = P0 + coefficient / pT^power (legacy key)"}; + Configurable cDCAxyToPVByPtPiFirstPower{"cDCAxyToPVByPtPiFirstPower", 1.f, "Power in pion DCAxy/z cut = P0 + coefficient / pT^power"}; Configurable cDCAxyToPVAsPtForCasc{"cDCAxyToPVAsPtForCasc", true, "Set DCAxy to PV selection as pt cut"}; Configurable cDCAxyToPVByPtCascP0{"cDCAxyToPVByPtCascP0", 999., "Coeff. for Track DCAxy cut to PV by pt for Cascade (p0)"}; Configurable cDCAxyToPVByPtCascExp{"cDCAxyToPVByPtCascExp", 1., "Coeff. Track DCAxy cut to PV by pt for Cascade (exp)"}; // Primary track DCAz to PV - Configurable cDCAzToPVAsPt{"cDCAzToPVAsPt", true, "DCAz to PV selection as pt"}; + Configurable cDCAzToPVAsPt{"cDCAzToPVAsPt", true, "Use the shared pion pT-dependent DCA cut for DCAz; otherwise use cMaxDCAzToPVCut"}; Configurable cDCAzToPVAsPtForCasc{"cDCAzToPVAsPtForCasc", true, "Set DCA to PV selection as pt cut"}; Configurable cMaxDCAzToPVCut{"cMaxDCAzToPVCut", 0.5, "Track DCAz cut to PV Maximum"}; Configurable cMaxDCAzToPVCutCasc{"cMaxDCAzToPVCutCasc", 0.5, "Track DCAz cut to PV Maximum for casc"}; @@ -173,7 +202,7 @@ struct Xi1530Analysisqa { // Topological selections for Cascades ConfigurableAxis cDCASecondaryBins{"cDCASecondaryBins", {1000, 0, 0.1}, "Bins for DCA to Cascade secondary"}; ConfigurableAxis cProperLifetimeBins{"cProperLifetimeBins", {300, 0, 30}, "Bins for proper lifetime"}; - ConfigurableAxis cDCABachelorToPVBins{"cDCABachelorToPVcutBins", {1000, 0, 0.1}, "Bins for DCA bachelor to PV cut"}; + ConfigurableAxis cDCABachelorToPVcutBins{"cDCABachelorToPVcutBins", {1000, 0, 0.1}, "Bins for DCA bachelor to PV cut"}; Configurable cDCABachlorToPVcut{"cDCABachlorToPVcut", 0.06, "Bachelor DCA cut to PV"}; Configurable cDCAXiDaugthersCutPtRangeLower{"cDCAXiDaugthersCutPtRangeLower", 1., "Xi- DCA cut to PV as pt range lower"}; Configurable cDCAXiDaugthersCutPtRangeUpper{"cDCAXiDaugthersCutPtRangeUpper", 4., "Xi- DCA cut to PV as pt range upper"}; @@ -207,43 +236,55 @@ struct Xi1530Analysisqa { Configurable cPIDBound{"cPIDBound", 6.349, "configurable for replacing to .has"}; ConfigurableAxis cPIDnSigmaBins{"cPIDnSigmaBins", {131, -6.5, 6.5}, "Bins for nSigma PID"}; - Configurable tofAtHighPt{"tofAtHighPt", false, "Use TOF at high pT"}; - Configurable cMinTOFpt{"cMinTOFpt", 0.5, "Maximum TOF pt cut"}; + Configurable tofAtHighPt{"tofAtHighPt", false, "Apply TOF PID only above cMinTOFpt (cascade pT for its daughters)"}; + Configurable cMinTOFpt{"cMinTOFpt", 0.5, "Lower pT threshold for TOF PID when tofAtHighPt is enabled"}; // PID Selections for Pion First - Configurable cMaxtpcnSigmaPionFirst{"cMaxtpcnSigmaPionFirst", 4.0, "TPC nSigma cut for Pion First"}; - Configurable cMaxtofnSigmaPionFirst{"cMaxtofnSigmaPionFirst", 3.0, "TOF nSigma cut for Pion First"}; + Configurable cMintpcnSigmaPionFirst{"cMintpcnSigmaPionFirst", -4.0, "Strict lower TPC (nSigma - mean) bound for Pion First"}; + Configurable cMaxtpcnSigmaPionFirst{"cMaxtpcnSigmaPionFirst", 4.0, "Strict upper TPC (nSigma - mean) bound for Pion First"}; + Configurable cMeantpcnSigmaPionFirst{"cMeantpcnSigmaPionFirst", 0.0, "TPC nSigma mean subtracted for Pion First PID"}; + Configurable cMintofnSigmaPionFirst{"cMintofnSigmaPionFirst", -3.0, "Strict lower TOF (nSigma - mean) bound for Pion First"}; + Configurable cMaxtofnSigmaPionFirst{"cMaxtofnSigmaPionFirst", 3.0, "Strict upper TOF (nSigma - mean) bound for Pion First"}; + Configurable cMeantofnSigmaPionFirst{"cMeantofnSigmaPionFirst", 0.0, "TOF nSigma mean subtracted for Pion First PID"}; Configurable nsigmaCutCombinedPionFirst{"nsigmaCutCombinedPionFirst", -4.0, "Combined nSigma cut for Pion First"}; - Configurable cUseOnlyTOFTrackPionFirst{"cUseOnlyTOFTrackPionFirst", false, "Use only TOF track for PID selection Pion First"}; Configurable cByPassTOFPionFirst{"cByPassTOFPionFirst", true, "By pass TOF Pion First PID selection"}; // PID Selections for Pion Bachelor - Configurable cMaxtpcnSigmaPionBachelor{"cMaxtpcnSigmaPionBachelor", 4.0, "TPC nSigma cut for Pion Bachelor"}; - Configurable cMaxtofnSigmaPionBachelor{"cMaxtofnSigmaPionBachelor", 3.0, "TOF nSigma cut for Pion Bachelor"}; + Configurable cMintpcnSigmaPionBachelor{"cMintpcnSigmaPionBachelor", -4.0, "Strict lower TPC (nSigma - mean) bound for Pion Bachelor"}; + Configurable cMaxtpcnSigmaPionBachelor{"cMaxtpcnSigmaPionBachelor", 4.0, "Strict upper TPC (nSigma - mean) bound for Pion Bachelor"}; + Configurable cMeantpcnSigmaPionBachelor{"cMeantpcnSigmaPionBachelor", 0.0, "TPC nSigma mean subtracted for Pion Bachelor PID"}; + Configurable cMintofnSigmaPionBachelor{"cMintofnSigmaPionBachelor", -3.0, "Strict lower TOF (nSigma - mean) bound for Pion Bachelor"}; + Configurable cMaxtofnSigmaPionBachelor{"cMaxtofnSigmaPionBachelor", 3.0, "Strict upper TOF (nSigma - mean) bound for Pion Bachelor"}; + Configurable cMeantofnSigmaPionBachelor{"cMeantofnSigmaPionBachelor", 0.0, "TOF nSigma mean subtracted for Pion Bachelor PID"}; Configurable nsigmaCutCombinedPionBachelor{"nsigmaCutCombinedPionBachelor", -4.0, "Combined nSigma cut for Pion Bachelor"}; - Configurable cUseOnlyTOFTrackPionBachelor{"cUseOnlyTOFTrackPionBachelor", false, "Use only TOF track for PID selection Pion Bachelor"}; Configurable cByPassTOFPionBachelor{"cByPassTOFPionBachelor", true, "By pass TOF Pion Bachelor PID selection"}; // PID Selections for Pion - Configurable cMaxtpcnSigmaPion{"cMaxtpcnSigmaPion", 4.0, "TPC nSigma cut for Pion"}; - Configurable cMaxtofnSigmaPion{"cMaxtofnSigmaPion", 3.0, "TOF nSigma cut for Pion"}; + Configurable cMintpcnSigmaPion{"cMintpcnSigmaPion", -4.0, "Strict lower TPC (nSigma - mean) bound for Pion"}; + Configurable cMaxtpcnSigmaPion{"cMaxtpcnSigmaPion", 4.0, "Strict upper TPC (nSigma - mean) bound for Pion"}; + Configurable cMeantpcnSigmaPion{"cMeantpcnSigmaPion", 0.0, "TPC nSigma mean subtracted for Pion PID"}; + Configurable cMintofnSigmaPion{"cMintofnSigmaPion", -3.0, "Strict lower TOF (nSigma - mean) bound for Pion"}; + Configurable cMaxtofnSigmaPion{"cMaxtofnSigmaPion", 3.0, "Strict upper TOF (nSigma - mean) bound for Pion"}; + Configurable cMeantofnSigmaPion{"cMeantofnSigmaPion", 0.0, "TOF nSigma mean subtracted for Pion PID"}; Configurable nsigmaCutCombinedPion{"nsigmaCutCombinedPion", -4.0, "Combined nSigma cut for Pion"}; - Configurable cUseOnlyTOFTrackPion{"cUseOnlyTOFTrackPion", false, "Use only TOF track for PID selection Pion"}; Configurable cByPassTOFPion{"cByPassTOFPion", true, "By pass TOF Pion PID selection"}; // PID Selections for Proton - Configurable cMaxtpcnSigmaProton{"cMaxtpcnSigmaProton", 4.0, "TPC nSigma cut for Proton"}; - Configurable cMaxtofnSigmaProton{"cMaxtofnSigmaProton", 3.0, "TOF nSigma cut for Proton"}; + Configurable cMintpcnSigmaProton{"cMintpcnSigmaProton", -4.0, "Strict lower TPC (nSigma - mean) bound for Proton"}; + Configurable cMaxtpcnSigmaProton{"cMaxtpcnSigmaProton", 4.0, "Strict upper TPC (nSigma - mean) bound for Proton"}; + Configurable cMeantpcnSigmaProton{"cMeantpcnSigmaProton", 0.0, "TPC nSigma mean subtracted for Proton PID"}; + Configurable cMintofnSigmaProton{"cMintofnSigmaProton", -3.0, "Strict lower TOF (nSigma - mean) bound for Proton"}; + Configurable cMaxtofnSigmaProton{"cMaxtofnSigmaProton", 3.0, "Strict upper TOF (nSigma - mean) bound for Proton"}; + Configurable cMeantofnSigmaProton{"cMeantofnSigmaProton", 0.0, "TOF nSigma mean subtracted for Proton PID"}; Configurable nsigmaCutCombinedProton{"nsigmaCutCombinedProton", -4.0, "Combined nSigma cut for Proton"}; - Configurable cUseOnlyTOFTrackProton{"cUseOnlyTOFTrackProton", false, "Use only TOF track for PID selection Proton"}; Configurable cByPassTOFProton{"cByPassTOFProton", true, "By pass TOF Proton PID selection"}; } pidConfig; @@ -262,16 +303,12 @@ struct Xi1530Analysisqa { Configurable studyStableXi{"studyStableXi", false, "Study stable Xi"}; - Configurable cMultNTracksPVFull{"cMultNTracksPVFull", false, "Use full PV track multiplicity"}; - Configurable cMultNTracksPVeta1{"cMultNTracksPVeta1", false, "Use PV track multiplicity within |eta|<1"}; - Configurable cMultNTracksPVetaHalf{"cMultNTracksPVetaHalf", true, "Use PV track multiplicity within |eta|<0.5"}; - Configurable cRecoINELgt0{"cRecoINELgt0", true, "check if INEL>0 for reco events"}; + Configurable cMCINELgt0{"cMCINELgt0", true, "Require generator INEL>0 in reconstructed MC and generated-parent processes"}; + Configurable cMCVtxIn10{"cMCVtxIn10", true, "Require generator |vertex z| < 10 cm using isVtxIn10 in reconstructed MC and generated-parent processes"}; Configurable cUseFixedMassXi{"cUseFixedMassXi", false, "Use fixed mass for Xi-"}; - Configurable cUseTruthRapidity{"cUseTruthRapidity", false, "Use truth rapidity for Xi*"}; - - Configurable cConsiderPairOnly{"cConsiderPairOnly", true, "Consider only existing particle pairs in the event"}; + Configurable cUseTruthRapidity{"cUseTruthRapidity", true, "Use truth rapidity for Xi*"}; Configurable cfgFillRotBkg{"cfgFillRotBkg", true, "Fill rotated background"}; Configurable cfgMinRot{"cfgMinRot", 5.0 * constants::math::PI / 6.0, "Minimum of rotation"}; @@ -280,27 +317,32 @@ struct Xi1530Analysisqa { Configurable cfgNrotBkg{"cfgNrotBkg", 4, "Number of rotated copies (background) per each original candidate"}; } additionalConfig; - TRandom* rn = new TRandom(); - //*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*// struct PidSelectionParam { + float cMinTPCnSigma; float cMaxTPCnSigma; + float cMeanTPCnSigma; + float cMinTOFnSigma; float cMaxTOFnSigma; + float cMeanTOFnSigma; bool cByPassTOF; float nsigmaCutCombined; }; void init(o2::framework::InitContext&) { + if (doprocessMEDF && doprocessMEMicro) { + LOGF(fatal, "Enable only one mixing process: processMEDF or processMEMicro"); + } AxisSpec centAxis = {histoConfig.binsCent, "FT0M (%)"}; - AxisSpec dcaxyAxis = {primarytrackConfig.cDCAtoPVBins, "DCA_{#it{xy}} (cm)"}; - AxisSpec dcazAxis = {primarytrackConfig.cDCAtoPVBins, "DCA_{#it{z}} (cm)"}; + AxisSpec dcaxyAxis = {primarytrackConfig.cDCAtoPVBins, "|DCA_{#it{xy}}| (cm)"}; + AxisSpec dcazAxis = {primarytrackConfig.cDCAtoPVBins, "|DCA_{#it{z}}| (cm)"}; AxisSpec dcaSecondaryAxis = {cascadeConfig.cDCASecondaryBins, "DCA_{#it{Secondary}} (cm)"}; - AxisSpec dcaBachAxis = {cascadeConfig.cDCABachelorToPVBins, "DCA_{#it{Bach}} (cm)"}; + AxisSpec dcaBachAxis = {cascadeConfig.cDCABachelorToPVcutBins, "DCA_{#it{Bach}} (cm)"}; AxisSpec dcaDaugAxis = {v0sConfig.cDCADaughtersBins, "DCA_{#it{Daughter}} (cm)"}; AxisSpec cosPAAxis = {cascadeConfig.cCosPABins, "1-cos(PA)"}; - AxisSpec properLifetimeAxis = {cascadeConfig.cProperLifetimeBins, "Proper lifetime (fm/c)"}; + AxisSpec properLifetimeAxis = {cascadeConfig.cProperLifetimeBins, "c#tau (cm)"}; AxisSpec mcLabelAxis = {6, -1.5, 4.5, "MC Label"}; AxisSpec ptAxis = {histoConfig.binsPt, "#it{p}_{T} (GeV/#it{c})"}; AxisSpec ptAxisQA = {histoConfig.binsPtQA, "#it{p}_{T} (GeV/#it{c})"}; @@ -313,7 +355,10 @@ struct Xi1530Analysisqa { if (histoConfig.multQA) { // multiplicity histograms - histos.add("multQA/h2MultCent", "Multiplicity vs Centrality", HistType::kTH2F, {centAxis, histoConfig.multNTracksAxis}); + histos.add("multQA/h2MultCent", "Same-event multiplicity vs centrality (one entry per event)", HistType::kTH2F, {centAxis, histoConfig.multNTracksAxis}); + if (doprocessMEMicro || doprocessMEDF) { + histos.add("multQA/h2MultCentME", "Mixed-event anchor multiplicity vs centrality (one entry per event pair)", HistType::kTH2F, {centAxis, histoConfig.multNTracksAxis}); + } histos.add("multQA/h2MultCentMC", "Multiplicity vs Centrality MC", HistType::kTH2F, {centAxis, histoConfig.multNTracksAxis}); } @@ -403,24 +448,24 @@ struct Xi1530Analysisqa { } // 3d histogram + Flags - histos.add("h3Xi1530invmassDS", "Invariant mass of Xi- differnt sign", kTHnSparseF, {centAxis, ptAxis, invMassAxis, flagAxis}); - histos.add("h3XiinvmassDS", "Invariant mass of Xi- differnt sign", kTHnSparseF, {centAxis, ptAxis, invMassAxisCasc, flagAxis}); + histos.add("h3Xi1530invmassDS", "Invariant mass of Xi- differnt sign", kTHnSparseD, {centAxis, ptAxis, invMassAxis, flagAxis}); + histos.add("h3XiinvmassDS", "Invariant mass of Xi- differnt sign", kTHnSparseD, {centAxis, ptAxis, invMassAxisCasc, flagAxis}); - histos.add("h3Xi1530invmassLS", "Invariant mass of Xi(1530)0 same sign", kTHnSparseF, {centAxis, ptAxis, invMassAxis, flagAxis}); - histos.add("h3Xi1530invmassRotDS", "Invariant mass of Xi(1530)0 rotated DS", kTHnSparseF, {centAxis, ptAxis, invMassAxis, flagAxis}); + histos.add("h3Xi1530invmassLS", "Invariant mass of Xi(1530)0 same sign", kTHnSparseD, {centAxis, ptAxis, invMassAxis, flagAxis}); + histos.add("h3Xi1530invmassRotDS", "Invariant mass of Xi(1530)0 rotated DS", kTHnSparseD, {centAxis, ptAxis, invMassAxis, flagAxis}); - histos.add("h3Xi1530invmassDSAnti", "Invariant mass of Anti-Xi(1530)0 differnt sign", kTHnSparseF, {centAxis, ptAxis, invMassAxis, flagAxis}); - histos.add("h3XiinvmassDSAnti", "Invariant mass of Anti-Xi- differnt sign", kTHnSparseF, {centAxis, ptAxis, invMassAxisCasc, flagAxis}); + histos.add("h3Xi1530invmassDSAnti", "Invariant mass of Anti-Xi(1530)0 differnt sign", kTHnSparseD, {centAxis, ptAxis, invMassAxis, flagAxis}); + histos.add("h3XiinvmassDSAnti", "Invariant mass of Anti-Xi- differnt sign", kTHnSparseD, {centAxis, ptAxis, invMassAxisCasc, flagAxis}); - histos.add("h3Xi1530invmassLSAnti", "Invariant mass of Anti-Xi(1530)0 same sign", kTHnSparseF, {centAxis, ptAxis, invMassAxis, flagAxis}); - histos.add("h3Xi1530invmassRotDSAnti", "Invariant mass of Anti-Xi(1530)0 rotated DS", kTHnSparseF, {centAxis, ptAxis, invMassAxis, flagAxis}); + histos.add("h3Xi1530invmassLSAnti", "Invariant mass of Anti-Xi(1530)0 same sign", kTHnSparseD, {centAxis, ptAxis, invMassAxis, flagAxis}); + histos.add("h3Xi1530invmassRotDSAnti", "Invariant mass of Anti-Xi(1530)0 rotated DS", kTHnSparseD, {centAxis, ptAxis, invMassAxis, flagAxis}); - if (doprocessMEMicro) { - histos.add("h3Xi1530invmassME_DS", "Invariant mass of Xi(1530)0 mixed event DS", kTHnSparseF, {centAxis, ptAxis, invMassAxis, flagAxis}); - histos.add("h3Xi1530invmassME_DSAnti", "Invariant mass of Xi(1530)0 mixed event DSAnti", kTHnSparseF, {centAxis, ptAxis, invMassAxis, flagAxis}); + if (doprocessMEMicro || doprocessMEDF) { + histos.add("h3Xi1530invmassME_DS", "Invariant mass of Xi(1530)0 mixed event DS", kTHnSparseD, {centAxis, ptAxis, invMassAxis, flagAxis}); + histos.add("h3Xi1530invmassME_DSAnti", "Invariant mass of Xi(1530)0 mixed event DSAnti", kTHnSparseD, {centAxis, ptAxis, invMassAxis, flagAxis}); } - if (doprocessMC) { + if (doprocessMC || doprocessMCMicro) { // MC QA histos.add("QAMCTrue/trkDCAxy_pi", "DCAxy distribution of pion track candidates", HistType::kTH2F, {ptAxis, dcaxyAxis}); histos.add("QAMCTrue/trkDCAxy_xi", "DCAxy distribution of Xi- track candidates", HistType::kTH2F, {ptAxis, dcaxyAxis}); @@ -449,19 +494,20 @@ struct Xi1530Analysisqa { histos.add("QAMCTrue/TPC_Nsigma_piminus_all", "TPC NSigma for Pion -;#it{p}_{T} (GeV/#it{c});#sigma_{TPC}^{Pion};", {HistType::kTH3F, {centAxis, ptAxisQA, pidQAAxis}}); } - histos.add("h3RecXi1530invmass", "Invariant mass of Reconstructed MC Xi(1530)0", kTHnSparseF, {centAxis, ptAxis, invMassAxis, ptAxis}); - histos.add("h3RecXiinvmass", "Invariant mass of Reconstructed MC Xi-", kTHnSparseF, {centAxis, ptAxis, invMassAxisCasc, ptAxis}); + histos.add("h3RecXi1530invmass", "Invariant mass of Reconstructed MC Xi(1530)0", kTHnSparseD, {centAxis, ptAxis, invMassAxis, ptAxis}); + histos.add("h3RecXiinvmass", "Invariant mass of Reconstructed MC Xi-", kTHnSparseD, {centAxis, ptAxis, invMassAxisCasc, flagAxis}); - histos.add("h3RecXi1530invmassAnti", "Invariant mass of Reconstructed MC Anti-Xi(1530)0", kTHnSparseF, {centAxis, ptAxis, invMassAxis, ptAxis}); - histos.add("h3RecXiinvmassAnti", "Invariant mass of Reconstructed MC Anti-Xi-", kTHnSparseF, {centAxis, ptAxis, invMassAxisCasc, ptAxis}); + histos.add("h3RecXi1530invmassAnti", "Invariant mass of Reconstructed MC Anti-Xi(1530)0", kTHnSparseD, {centAxis, ptAxis, invMassAxis, ptAxis}); + histos.add("h3RecXiinvmassAnti", "Invariant mass of Reconstructed MC Anti-Xi-", kTHnSparseD, {centAxis, ptAxis, invMassAxisCasc, flagAxis}); - histos.add("h3Xi1530Gen", "pT distribution of True MC Xi(1530)0", kTHnSparseF, {ptAxis, centAxis, histoConfig.multNTracksAxis}); - histos.add("h3Xi1530GenAnti", "pT distribution of True MC Anti-Xi(1530)0", kTHnSparseF, {ptAxis, centAxis, histoConfig.multNTracksAxis}); - - histos.add("Xi1530Rec", "pT distribution of Reconstructed MC Xi(1530)0", kTH2F, {ptAxis, centAxis}); - histos.add("Xi1530RecAnti", "pT distribution of Reconstructed MC Anti-Xi(1530)0", kTH2F, {ptAxis, centAxis}); + histos.add("Xi1530Rec", "pT distribution of Reconstructed MC Xi(1530)0", kTH2D, {ptAxis, centAxis}); + histos.add("Xi1530RecAnti", "pT distribution of Reconstructed MC Anti-Xi(1530)0", kTH2D, {ptAxis, centAxis}); histos.add("Xi1530Recinvmass", "Inv mass distribution of Reconstructed MC Xi(1530)0", kTH1F, {invMassAxis}); } + if (doprocessMC || doprocessMCMicro || doprocessMCTrue) { + histos.add("h3Xi1530Gen", "pT distribution of True MC Xi(1530)0", kTHnSparseD, {ptAxis, centAxis, histoConfig.multNTracksAxis}); + histos.add("h3Xi1530GenAnti", "pT distribution of True MC Anti-Xi(1530)0", kTHnSparseD, {ptAxis, centAxis, histoConfig.multNTracksAxis}); + } // QA for topological, kinematical cut for cascades if (histoConfig.additionalQAplots) { histos.add("QAbefore/V0DCATopPV", "V0s DCA to PV distribution as pt", HistType::kTH2F, {ptAxis, dcaxyAxis}); @@ -521,43 +567,42 @@ struct Xi1530Analysisqa { // Primary track selection for the first pion // template - bool primaryTrackCut(const TrackType track) + bool primaryTrackCut(const TrackType& track) { - if (std::abs(track.eta()) >= primarytrackConfig.cMaxetacut) + if (!std::isfinite(track.pt()) || !std::isfinite(track.eta()) || + !std::isfinite(track.dcaXY()) || !std::isfinite(track.dcaZ())) { + return false; + } + if (std::abs(track.eta()) >= primarytrackConfig.cMaxetacut) { return false; - if (std::abs(track.pt()) <= primarytrackConfig.cMinPtcut) + } + if (std::abs(track.pt()) <= primarytrackConfig.cMinPtcut) { return false; - if constexpr (IsResoMicrotrack) { - if (std::abs(o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(track.trackSelectionFlags())) >= (primarytrackConfig.cDCAxytoPVByPtPiFirstP0 + primarytrackConfig.cDCAxyToPVByPtPiFirstExp * std::pow(track.pt(), -1.))) + } + // Keep double precision and Power=1 equivalent to the previous pow(pt, -1.) cut. + // Evaluate the common threshold only when at least one axis needs it. + const double dcaPtCut = (primarytrackConfig.cDCAxyToPVAsPt || primarytrackConfig.cDCAzToPVAsPt) + ? primarytrackConfig.cDCAxytoPVByPtPiFirstP0.value + primarytrackConfig.cDCAxyToPVByPtPiFirstExp.value * std::pow(track.pt(), -static_cast(primarytrackConfig.cDCAxyToPVByPtPiFirstPower.value)) + : 0.; + const double dcaXYCut = primarytrackConfig.cDCAxyToPVAsPt ? dcaPtCut : primarytrackConfig.cMaxDCAxyToPVCut.value; + const double dcaZCut = primarytrackConfig.cDCAzToPVAsPt ? dcaPtCut : primarytrackConfig.cMaxDCAzToPVCut.value; + if (std::abs(track.dcaXY()) >= dcaXYCut || std::abs(track.dcaZ()) >= dcaZCut) { + return false; + } + if constexpr (!IsResoMicrotrack) { + if (track.tpcNClsFound() <= primarytrackConfig.cfgTPCcluster) { return false; - if (primarytrackConfig.cDCAzToPVAsPt) { - if (std::abs(o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(track.trackSelectionFlags())) >= (primarytrackConfig.cDCAxytoPVByPtPiFirstP0 + primarytrackConfig.cDCAxyToPVByPtPiFirstExp * std::pow(track.pt(), -1.))) - return false; - } else { - if (std::abs(o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(track.trackSelectionFlags())) >= primarytrackConfig.cMaxDCAzToPVCut) - return false; } - } else { - if (std::abs(track.dcaXY()) >= (primarytrackConfig.cDCAxytoPVByPtPiFirstP0 + primarytrackConfig.cDCAxyToPVByPtPiFirstExp * std::pow(track.pt(), -1.))) + if (track.tpcNClsCrossedRows() <= primarytrackConfig.cfgTPCRows) { return false; - if (primarytrackConfig.cDCAzToPVAsPt) { - if (std::abs(track.dcaZ()) >= (primarytrackConfig.cDCAxytoPVByPtPiFirstP0 + primarytrackConfig.cDCAxyToPVByPtPiFirstExp * std::pow(track.pt(), -1.))) - return false; - } else { - if (std::abs(track.dcaZ()) >= primarytrackConfig.cMaxDCAzToPVCut) - return false; } - if (track.tpcNClsFound() <= primarytrackConfig.cfgTPCcluster) - return false; - if (track.tpcNClsCrossedRows() <= primarytrackConfig.cfgTPCRows) - return false; } - if (primarytrackConfig.cfgHasTOF && !track.hasTOF()) - return false; - if (primarytrackConfig.cfgPVContributor && !track.isPVContributor()) + if (primarytrackConfig.cfgPVContributor && !track.isPVContributor()) { return false; - if (primarytrackConfig.cfgPrimaryTrack && !track.isPrimaryTrack()) + } + if (primarytrackConfig.cfgPrimaryTrack && !track.isPrimaryTrack()) { return false; + } return true; } @@ -568,25 +613,34 @@ struct Xi1530Analysisqa { // Primary track selection for cascades, Need to more informations for cascades // template - bool cascprimaryTrackCut(const TracksTypeCasc track) + bool cascprimaryTrackCut(const TracksTypeCasc& track) { - if (std::abs(track.eta()) >= primarytrackConfig.cMaxetacut) + if (std::abs(track.eta()) >= primarytrackConfig.cMaxetacut) { return false; - if (std::abs(track.pt()) <= primarytrackConfig.cMinPtcut) + } + if (std::abs(track.pt()) <= primarytrackConfig.cMinPtcut) { return false; - if (track.nCrossedRowsPos() <= cascadeConfig.cMinNCrossedRowsTPCPos) + } + if (track.nCrossedRowsPos() <= cascadeConfig.cMinNCrossedRowsTPCPos) { return false; - if (track.nCrossedRowsNeg() <= cascadeConfig.cMinNCrossedRowsTPCNeg) + } + if (track.nCrossedRowsNeg() <= cascadeConfig.cMinNCrossedRowsTPCNeg) { return false; - if (track.nCrossedRowsBach() <= cascadeConfig.cMinNCrossedRowsTPCBach) + } + if (track.nCrossedRowsBach() <= cascadeConfig.cMinNCrossedRowsTPCBach) { return false; + } if (primarytrackConfig.cDCAxyToPVAsPtForCasc) { - if (std::abs(track.dcaXYCascToPV()) >= (primarytrackConfig.cDCAxyToPVByPtCascP0 + primarytrackConfig.cDCAxyToPVByPtCascExp * track.pt())) + if (std::abs(track.dcaXYCascToPV()) >= (primarytrackConfig.cDCAxyToPVByPtCascP0 + primarytrackConfig.cDCAxyToPVByPtCascExp * track.pt())) { return false; + } } if (primarytrackConfig.cDCAzToPVAsPtForCasc) { - if (std::abs(track.dcaZCascToPV()) >= (primarytrackConfig.cDCAxyToPVByPtCascP0 + primarytrackConfig.cDCAxyToPVByPtCascExp * std::pow(track.pt(), -1.))) + if (std::abs(track.dcaZCascToPV()) >= (primarytrackConfig.cDCAxyToPVByPtCascP0 + primarytrackConfig.cDCAxyToPVByPtCascExp * std::pow(track.pt(), -1.))) { return false; + } + } else if (std::abs(track.dcaZCascToPV()) >= primarytrackConfig.cMaxDCAzToPVCutCasc) { + return false; } return true; @@ -596,127 +650,105 @@ struct Xi1530Analysisqa { // Topological cuts for cascades template - bool casctopCut(const TracksTypeCasc track) + bool casctopCut(const TracksTypeCasc& track) { // Topological cuts for V0s - if (std::abs(track.daughDCA()) >= v0sConfig.cDCALambdaDaugtherscut) + if (std::abs(track.daughDCA()) >= v0sConfig.cDCALambdaDaugtherscut) { return false; - if (std::abs(track.dcav0topv()) <= v0sConfig.cDCALambdaToPVcut) + } + if (std::abs(track.dcav0topv()) <= v0sConfig.cDCALambdaToPVcut) { return false; + } if (track.sign() < 0) { - if (std::abs(track.dcanegtopv()) <= v0sConfig.cDCAPionToPVcut) + if (std::abs(track.dcanegtopv()) <= v0sConfig.cDCAPionToPVcut) { return false; - if (std::abs(track.dcapostopv()) <= v0sConfig.cDCAProtonToPVcut) + } + if (std::abs(track.dcapostopv()) <= v0sConfig.cDCAProtonToPVcut) { return false; + } } else { - if (std::abs(track.dcanegtopv()) <= v0sConfig.cDCAProtonToPVcut) + if (std::abs(track.dcanegtopv()) <= v0sConfig.cDCAProtonToPVcut) { return false; - if (std::abs(track.dcapostopv()) <= v0sConfig.cDCAPionToPVcut) + } + if (std::abs(track.dcapostopv()) <= v0sConfig.cDCAPionToPVcut) { return false; + } } - if (track.v0CosPA() <= std::cos(v0sConfig.cV0CosPACutPtDepP0 - v0sConfig.cV0CosPACutPtDepP1 * track.pt())) + if (track.v0CosPA() <= std::cos(v0sConfig.cV0CosPACutPtDepP0 - v0sConfig.cV0CosPACutPtDepP1 * track.pt())) { return false; - if (track.transRadius() >= v0sConfig.cMaxV0radiuscut || track.transRadius() <= v0sConfig.cMinV0radiuscut) + } + if (track.transRadius() >= v0sConfig.cMaxV0radiuscut || track.transRadius() <= v0sConfig.cMinV0radiuscut) { return false; - if (std::abs(track.mLambda() - MassLambda) >= v0sConfig.cMasswindowV0cut) + } + if (std::abs(track.mLambda() - MassLambda) >= v0sConfig.cMasswindowV0cut) { return false; + } // Topological Cuts for Cascades - if (std::abs(track.dcabachtopv()) <= cascadeConfig.cDCABachlorToPVcut) + if (std::abs(track.dcabachtopv()) <= cascadeConfig.cDCABachlorToPVcut) { return false; + } if (track.pt() <= cascadeConfig.cDCAXiDaugthersCutPtRangeLower) { - if (track.cascDaughDCA() >= cascadeConfig.cDCAXiDaugthersCutPtDepLower) + if (track.cascDaughDCA() >= cascadeConfig.cDCAXiDaugthersCutPtDepLower) { return false; + } } if (track.pt() >= cascadeConfig.cDCAXiDaugthersCutPtRangeLower && track.pt() <= cascadeConfig.cDCAXiDaugthersCutPtRangeUpper) { - if (track.cascDaughDCA() >= cascadeConfig.cDCAXiDaugthersCutPtDepMiddle) + if (track.cascDaughDCA() >= cascadeConfig.cDCAXiDaugthersCutPtDepMiddle) { return false; + } } if (track.pt() >= cascadeConfig.cDCAXiDaugthersCutPtRangeUpper) { - if (track.cascDaughDCA() >= cascadeConfig.cDCAXiDaugthersCutPtDepUpper) + if (track.cascDaughDCA() >= cascadeConfig.cDCAXiDaugthersCutPtDepUpper) { return false; + } } - if (track.cascCosPA() <= std::cos(cascadeConfig.cCosPACascCutPtDepP0 - cascadeConfig.cCosPACascCutPtDepP1 * track.pt())) + if (track.cascCosPA() <= std::cos(cascadeConfig.cCosPACascCutPtDepP0 - cascadeConfig.cCosPACascCutPtDepP1 * track.pt())) { return false; + } - if (track.cascTransRadius() >= cascadeConfig.cMaxCascradiuscut || track.cascTransRadius() <= cascadeConfig.cMinCascradiuscut) + if (track.cascTransRadius() >= cascadeConfig.cMaxCascradiuscut || track.cascTransRadius() <= cascadeConfig.cMinCascradiuscut) { return false; - if (std::abs(track.mXi() - cascadeConfig.cMassXiminus) >= cascadeConfig.cMasswindowCasccut) + } + if (std::abs(track.mXi() - cascadeConfig.cMassXiminus) >= cascadeConfig.cMasswindowCasccut) { return false; + } return true; } - bool pidSelector(float TPCNsigma, float TOFNsigma, const PidSelectionParam& params, bool tofAtHighPt, float trackPt) + bool pidSelector(float TPCNsigma, float TOFNsigma, const PidSelectionParam& params, bool tofAtHighPt, float trackPt, bool hasTOF) { - bool tpcPIDPassed{false}, tofPIDPassed{false}; - - if (tofAtHighPt && trackPt > pidConfig.cMinTOFpt) { - if (std::abs(TPCNsigma) < params.cMaxTPCnSigma) { - tpcPIDPassed = true; - } - - if (params.cByPassTOF && tpcPIDPassed) { - return true; - } - - if (hasSubsystemInfo(TOFNsigma)) { - if (std::abs(TOFNsigma) < params.cMaxTOFnSigma) { - tofPIDPassed = true; - } - if ((params.nsigmaCutCombined > 0) && - (TPCNsigma * TPCNsigma + TOFNsigma * TOFNsigma < params.nsigmaCutCombined * params.nsigmaCutCombined)) { - tofPIDPassed = true; - } - } else { - tofPIDPassed = true; - } - return tpcPIDPassed && tofPIDPassed; - } else { - - if (std::abs(TPCNsigma) < params.cMaxTPCnSigma) { - tpcPIDPassed = true; - } - - if (params.cByPassTOF && tpcPIDPassed) { - return true; - } - - if (hasSubsystemInfo(TOFNsigma)) { - if (std::abs(TOFNsigma) < params.cMaxTOFnSigma) { - tofPIDPassed = true; - } - if ((params.nsigmaCutCombined > 0) && - (TPCNsigma * TPCNsigma + TOFNsigma * TOFNsigma < params.nsigmaCutCombined * params.nsigmaCutCombined)) { - tofPIDPassed = true; - } - } else { - tofPIDPassed = true; - } - - return tpcPIDPassed && tofPIDPassed; + // Bounds are signed offsets from the detector-specific mean; exclude both edges. + const float centeredTPC = TPCNsigma - params.cMeanTPCnSigma; + const bool passesTPCWindow = params.cMinTPCnSigma < centeredTPC && centeredTPC < params.cMaxTPCnSigma; + if (!passesTPCWindow) { + return false; } + // Missing or bypassed TOF never vetoes a track that passes the TPC window. + if (params.cByPassTOF || (tofAtHighPt && trackPt <= pidConfig.cMinTOFpt) || !hasTOF) { + return true; + } + // Retain TOF-window OR combined acceptance; center both detectors for the latter. + // A present Micro001 TOF value at +/-infinity is overflow, not missing TOF. + const float centeredTOF = TOFNsigma - params.cMeanTOFnSigma; + return (params.cMinTOFnSigma < centeredTOF && centeredTOF < params.cMaxTOFnSigma) || + (params.nsigmaCutCombined > 0 && + centeredTPC * centeredTPC + centeredTOF * centeredTOF < params.nsigmaCutCombined * params.nsigmaCutCombined); } // PID selection for the First Pion // - template + template bool selectionPIDPionFirst(const T& candidate) { - float tpcNsigmaPionFirst, tofNsigmaPionFirst; + const float tpcNsigmaPionFirst = candidate.tpcNSigmaPi(); + const float tofNsigmaPionFirst = candidate.tofNSigmaPi(); float trackPt = candidate.pt(); - if constexpr (IsResoMicrotrack) { - tpcNsigmaPionFirst = o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(candidate.pidNSigmaPiFlag()); - tofNsigmaPionFirst = o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(candidate.pidNSigmaPiFlag()); - } else { - tpcNsigmaPionFirst = candidate.tpcNSigmaPi(); - tofNsigmaPionFirst = candidate.tofNSigmaPi(); - } + PidSelectionParam pionFirstParams = {.cMinTPCnSigma = pidConfig.cMintpcnSigmaPionFirst, .cMaxTPCnSigma = pidConfig.cMaxtpcnSigmaPionFirst, .cMeanTPCnSigma = pidConfig.cMeantpcnSigmaPionFirst, .cMinTOFnSigma = pidConfig.cMintofnSigmaPionFirst, .cMaxTOFnSigma = pidConfig.cMaxtofnSigmaPionFirst, .cMeanTOFnSigma = pidConfig.cMeantofnSigmaPionFirst, .cByPassTOF = pidConfig.cByPassTOFPionFirst, .nsigmaCutCombined = pidConfig.nsigmaCutCombinedPionFirst}; - PidSelectionParam pionFirstParams = {pidConfig.cMaxtpcnSigmaPionFirst, pidConfig.cMaxtofnSigmaPionFirst, pidConfig.cByPassTOFPionFirst, pidConfig.nsigmaCutCombinedPionFirst}; - - return pidSelector(tpcNsigmaPionFirst, tofNsigmaPionFirst, pionFirstParams, pidConfig.tofAtHighPt, trackPt); + return pidSelector(tpcNsigmaPionFirst, tofNsigmaPionFirst, pionFirstParams, pidConfig.tofAtHighPt, trackPt, candidate.hasTOF()); } template @@ -724,9 +756,9 @@ struct Xi1530Analysisqa { { bool lConsistentWithXi{false}, lConsistentWithLambda{false}, lConsistentWithPion{false}, lConsistentWithProton{false}; - float tpcNsigmaBachelor, tofNsigmaBachelor; - float tpcNsigmaPion, tofNsigmaPion; - float tpcNsigmaProton, tofNsigmaProton; + float tpcNsigmaBachelor = 0.f, tofNsigmaBachelor = 0.f; + float tpcNsigmaPion = 0.f, tofNsigmaPion = 0.f; + float tpcNsigmaProton = 0.f, tofNsigmaProton = 0.f; float trackPt = candidate.pt(); if (candidate.sign() < 0) { // Xi- candidates @@ -750,13 +782,13 @@ struct Xi1530Analysisqa { tofNsigmaProton = candidate.daughterTOFNSigmaNegPr(); } - PidSelectionParam bachelorParams = {pidConfig.cMaxtpcnSigmaPionBachelor, pidConfig.cMaxtofnSigmaPionBachelor, pidConfig.cByPassTOFPionBachelor, pidConfig.nsigmaCutCombinedPionBachelor}; - PidSelectionParam pionParams = {pidConfig.cMaxtpcnSigmaPion, pidConfig.cMaxtofnSigmaPion, pidConfig.cByPassTOFPion, pidConfig.nsigmaCutCombinedPion}; - PidSelectionParam protonParams = {pidConfig.cMaxtpcnSigmaProton, pidConfig.cMaxtofnSigmaProton, pidConfig.cByPassTOFProton, pidConfig.nsigmaCutCombinedProton}; + PidSelectionParam bachelorParams = {.cMinTPCnSigma = pidConfig.cMintpcnSigmaPionBachelor, .cMaxTPCnSigma = pidConfig.cMaxtpcnSigmaPionBachelor, .cMeanTPCnSigma = pidConfig.cMeantpcnSigmaPionBachelor, .cMinTOFnSigma = pidConfig.cMintofnSigmaPionBachelor, .cMaxTOFnSigma = pidConfig.cMaxtofnSigmaPionBachelor, .cMeanTOFnSigma = pidConfig.cMeantofnSigmaPionBachelor, .cByPassTOF = pidConfig.cByPassTOFPionBachelor, .nsigmaCutCombined = pidConfig.nsigmaCutCombinedPionBachelor}; + PidSelectionParam pionParams = {.cMinTPCnSigma = pidConfig.cMintpcnSigmaPion, .cMaxTPCnSigma = pidConfig.cMaxtpcnSigmaPion, .cMeanTPCnSigma = pidConfig.cMeantpcnSigmaPion, .cMinTOFnSigma = pidConfig.cMintofnSigmaPion, .cMaxTOFnSigma = pidConfig.cMaxtofnSigmaPion, .cMeanTOFnSigma = pidConfig.cMeantofnSigmaPion, .cByPassTOF = pidConfig.cByPassTOFPion, .nsigmaCutCombined = pidConfig.nsigmaCutCombinedPion}; + PidSelectionParam protonParams = {.cMinTPCnSigma = pidConfig.cMintpcnSigmaProton, .cMaxTPCnSigma = pidConfig.cMaxtpcnSigmaProton, .cMeanTPCnSigma = pidConfig.cMeantpcnSigmaProton, .cMinTOFnSigma = pidConfig.cMintofnSigmaProton, .cMaxTOFnSigma = pidConfig.cMaxtofnSigmaProton, .cMeanTOFnSigma = pidConfig.cMeantofnSigmaProton, .cByPassTOF = pidConfig.cByPassTOFProton, .nsigmaCutCombined = pidConfig.nsigmaCutCombinedProton}; - lConsistentWithXi = pidSelector(tpcNsigmaBachelor, tofNsigmaBachelor, bachelorParams, pidConfig.tofAtHighPt, trackPt); - lConsistentWithPion = pidSelector(tpcNsigmaPion, tofNsigmaPion, pionParams, pidConfig.tofAtHighPt, trackPt); - lConsistentWithProton = pidSelector(tpcNsigmaProton, tofNsigmaProton, protonParams, pidConfig.tofAtHighPt, trackPt); + lConsistentWithXi = pidSelector(tpcNsigmaBachelor, tofNsigmaBachelor, bachelorParams, pidConfig.tofAtHighPt, trackPt, hasSubsystemInfo(tofNsigmaBachelor)); + lConsistentWithPion = pidSelector(tpcNsigmaPion, tofNsigmaPion, pionParams, pidConfig.tofAtHighPt, trackPt, hasSubsystemInfo(tofNsigmaPion)); + lConsistentWithProton = pidSelector(tpcNsigmaProton, tofNsigmaProton, protonParams, pidConfig.tofAtHighPt, trackPt, hasSubsystemInfo(tofNsigmaProton)); lConsistentWithLambda = lConsistentWithProton && lConsistentWithPion; @@ -777,29 +809,27 @@ struct Xi1530Analysisqa { } template - void fillHistograms(const CollisionType& collision, const centType& inCent, const TracksType& dTracks1, const TracksTypeCasc& dTracks2) // Order: ResoColl, ResoTrack, ResoCascTrack + void fillHistograms(const CollisionType& collision, const centType& inCent, const TracksType& dTracks1, const TracksTypeCasc& dTracks2, + const MixingCollision* cascadeCollision = nullptr) // Order: ResoColl, ResoTrack, ResoCascTrack { - auto Cent = inCent; + auto cent = inCent; if (histoConfig.eventQA) { if constexpr (!IsMix) { histos.fill(HIST("QAevent/hVertexZSameE"), collision.posZ()); - histos.fill(HIST("QAevent/hMultiplicityPercentSameE"), Cent); + histos.fill(HIST("QAevent/hMultiplicityPercentSameE"), cent); histos.fill(HIST("QAevent/hCollisionIndexSameE"), collision.globalIndex()); histos.fill(HIST("QAevent/hnTrksSameE"), dTracks1.size()); histos.fill(HIST("QAevent/hnCascsSameE"), dTracks2.size()); } else { histos.fill(HIST("QAevent/hVertexZMixedE"), collision.posZ()); - histos.fill(HIST("QAevent/hMultiplicityPercentMixedE"), Cent); + histos.fill(HIST("QAevent/hMultiplicityPercentMixedE"), cent); histos.fill(HIST("QAevent/hCollisionIndexMixedE"), collision.globalIndex()); histos.fill(HIST("QAevent/hnTrksMixedE"), dTracks1.size()); histos.fill(HIST("QAevent/hnCascsMixedE"), dTracks2.size()); } } - if (additionalConfig.cConsiderPairOnly && (dTracks2.size() < 1 || dTracks1.size() < 1)) - return; - LorentzVectorPtEtaPhiMass lDecayDaughter1, lDecayDaughter2, lResonance, lDaughterRot, lResonanceRot; std::vector pionCandateIndicies = {}; std::vector xiCandateIndicies = {}; @@ -808,55 +838,44 @@ struct Xi1530Analysisqa { for (const auto& trk1 : dTracks1) { auto trk1ptPi = trk1.pt(); - float trk1DCAXY = -1.f; - float trk1DCAZ = -1.f; - float trk1NSigmaPiTPC = -999.f; - float trk1NSigmaPiTOF = -999.f; - if constexpr (IsResoMicrotrack) { - trk1DCAXY = o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(trk1.trackSelectionFlags()); - trk1DCAZ = o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(trk1.trackSelectionFlags()); - trk1NSigmaPiTPC = o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(trk1.pidNSigmaPiFlag()); - trk1NSigmaPiTOF = o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(trk1.pidNSigmaPiFlag()); - } else { - trk1DCAXY = trk1.dcaXY(); - trk1DCAZ = trk1.dcaZ(); - trk1NSigmaPiTPC = trk1.tpcNSigmaPi(); - trk1NSigmaPiTOF = trk1.tofNSigmaPi(); - } + const float trk1DCAXY = trk1.dcaXY(); + const float trk1DCAZ = trk1.dcaZ(); + const float trk1NSigmaPiTPC = trk1.tpcNSigmaPi(); + const float trk1NSigmaPiTOF = trk1.tofNSigmaPi(); // QA before if constexpr (!IsMix) { if (histoConfig.pidPlots) { - histos.fill(HIST("QAbefore/TPC_Nsigma_pi_first_all"), Cent, trk1ptPi, trk1NSigmaPiTPC); - if (hasSubsystemInfo(trk1NSigmaPiTOF)) { - histos.fill(HIST("QAbefore/TOF_Nsigma_pi_first_all"), Cent, trk1ptPi, trk1NSigmaPiTOF); + histos.fill(HIST("QAbefore/TPC_Nsigma_pi_first_all"), cent, trk1ptPi, trk1NSigmaPiTPC); + if (trk1.hasTOF() && !std::isnan(trk1NSigmaPiTOF)) { + histos.fill(HIST("QAbefore/TOF_Nsigma_pi_first_all"), cent, trk1ptPi, trk1NSigmaPiTOF); histos.fill(HIST("QAbefore/TOF_TPC_Map_pi_first_all"), trk1NSigmaPiTOF, trk1NSigmaPiTPC); } } if (histoConfig.additionalQAplots) { - histos.fill(HIST("QAbefore/trkDCAxy_pi"), trk1ptPi, trk1DCAXY); - histos.fill(HIST("QAbefore/trkDCAz_pi"), trk1ptPi, trk1DCAZ); + histos.fill(HIST("QAbefore/trkDCAxy_pi"), trk1ptPi, std::abs(trk1DCAXY)); + histos.fill(HIST("QAbefore/trkDCAz_pi"), trk1ptPi, std::abs(trk1DCAZ)); } } - if (pidConfig.cUseOnlyTOFTrackPionBachelor && hasSubsystemInfo(trk1NSigmaPiTOF)) + if (!selectionPIDPionFirst(trk1)) { // PID selection for the first pion continue; - if (!selectionPIDPionFirst(trk1)) // PID selection for the first pion - continue; - if (!primaryTrackCut(trk1)) // Primary track selections + } + if (!primaryTrackCut(trk1)) { // Primary track selections continue; + } if constexpr (!IsMix) { if (histoConfig.pidPlots) { - histos.fill(HIST("QAafter/TPC_Nsigma_pi_first_all"), Cent, trk1ptPi, trk1NSigmaPiTPC); + histos.fill(HIST("QAafter/TPC_Nsigma_pi_first_all"), cent, trk1ptPi, trk1NSigmaPiTPC); - if (hasSubsystemInfo(trk1NSigmaPiTOF)) { - histos.fill(HIST("QAafter/TOF_Nsigma_pi_first_all"), Cent, trk1ptPi, trk1NSigmaPiTOF); + if (trk1.hasTOF() && !std::isnan(trk1NSigmaPiTOF)) { + histos.fill(HIST("QAafter/TOF_Nsigma_pi_first_all"), cent, trk1ptPi, trk1NSigmaPiTOF); histos.fill(HIST("QAafter/TOF_TPC_Map_pi_first_all"), trk1NSigmaPiTOF, trk1NSigmaPiTPC); } } if (histoConfig.additionalQAplots) { - histos.fill(HIST("QAafter/trkDCAxy_pi"), trk1ptPi, trk1DCAXY); - histos.fill(HIST("QAafter/trkDCAz_pi"), trk1ptPi, trk1DCAZ); + histos.fill(HIST("QAafter/trkDCAxy_pi"), trk1ptPi, std::abs(trk1DCAXY)); + histos.fill(HIST("QAafter/trkDCAz_pi"), trk1ptPi, std::abs(trk1DCAZ)); } } @@ -868,7 +887,7 @@ struct Xi1530Analysisqa { auto trk2ptXi = trk2.pt(); auto massLambdaCand = trk2.mLambda(); auto massXiCand = trk2.mXi(); - auto trk2ProperLifetime = properLifetime(collision, trk2); + auto trk2ProperLifetime = cascadeCollision ? properLifetime(*cascadeCollision, trk2) : properLifetime(collision, trk2); // Topological variables for cascades auto trk2DCAV0TopPV = trk2.dcav0topv(); @@ -909,27 +928,27 @@ struct Xi1530Analysisqa { //// QA plots before the selection // // --- PID QA if (histoConfig.pidPlots) { - histos.fill(HIST("QAbefore/TPC_Nsigma_pi_bachelor_all"), Cent, 0, trk2NSigmaPiBachelorTPC); // can't take pt information for the cascade secondary + histos.fill(HIST("QAbefore/TPC_Nsigma_pi_bachelor_all"), cent, 0, trk2NSigmaPiBachelorTPC); // can't take pt information for the cascade secondary if (hasSubsystemInfo(trk2NSigmaPiBachelorTOF)) { histos.fill(HIST("QAbefore/TOF_TPC_Map_pi_bachelor_all"), trk2NSigmaPiBachelorTOF, trk2NSigmaPiBachelorTPC); } - histos.fill(HIST("QAbefore/TPC_Nsigma_pr_all"), Cent, 0, trk2NSigmaPrPosTPC); + histos.fill(HIST("QAbefore/TPC_Nsigma_pr_all"), cent, 0, trk2NSigmaPrPosTPC); if (hasSubsystemInfo(trk2NSigmaPrPosTOF)) { histos.fill(HIST("QAbefore/TOF_TPC_Map_pr_all"), trk2NSigmaPrPosTOF, trk2NSigmaPrPosTPC); } - histos.fill(HIST("QAbefore/TPC_Nsigma_antipr_all"), Cent, 0, trk2NSigmaPrNegTPC); + histos.fill(HIST("QAbefore/TPC_Nsigma_antipr_all"), cent, 0, trk2NSigmaPrNegTPC); if (hasSubsystemInfo(trk2NSigmaPrNegTOF)) { histos.fill(HIST("QAbefore/TOF_TPC_Map_antipr_all"), trk2NSigmaPrNegTOF, trk2NSigmaPrNegTPC); } - histos.fill(HIST("QAbefore/TPC_Nsigma_pi_all"), Cent, 0, trk2NSigmaPiPosTPC); + histos.fill(HIST("QAbefore/TPC_Nsigma_pi_all"), cent, 0, trk2NSigmaPiPosTPC); if (hasSubsystemInfo(trk2NSigmaPiPosTOF)) { histos.fill(HIST("QAbefore/TOF_TPC_Map_pi_all"), trk2NSigmaPiPosTOF, trk2NSigmaPiPosTPC); } - histos.fill(HIST("QAbefore/TPC_Nsigma_piminus_all"), Cent, 0, trk2NSigmaPiNegTPC); + histos.fill(HIST("QAbefore/TPC_Nsigma_piminus_all"), cent, 0, trk2NSigmaPiNegTPC); if (hasSubsystemInfo(trk2NSigmaPiNegTOF)) { histos.fill(HIST("QAbefore/TOF_TPC_Map_piminus_all"), trk2NSigmaPiNegTOF, trk2NSigmaPiNegTPC); } @@ -937,8 +956,8 @@ struct Xi1530Analysisqa { if (histoConfig.additionalQAplots) { histos.fill(HIST("QAbefore/V0DCATopPV"), trk2ptXi, trk2DCAV0TopPV); - histos.fill(HIST("QAbefore/trkDCAxy_xi"), trk2ptXi, trk2DCAXY); - histos.fill(HIST("QAbefore/trkDCAz_xi"), trk2ptXi, trk2DCAZ); + histos.fill(HIST("QAbefore/trkDCAxy_xi"), trk2ptXi, std::abs(trk2DCAXY)); + histos.fill(HIST("QAbefore/trkDCAz_xi"), trk2ptXi, std::abs(trk2DCAZ)); histos.fill(HIST("QAbefore/V0DCADoughter"), trk2ptXi, trk2DCAV0sDougthers); histos.fill(HIST("QAbefore/CascDCADoughter"), trk2ptXi, trk2DCACascDougthers); histos.fill(HIST("QAbefore/CascDCABachPV"), trk2ptXi, trk2DCABachPV); @@ -957,22 +976,15 @@ struct Xi1530Analysisqa { } } - if (pidConfig.cUseOnlyTOFTrackPionBachelor && !hasSubsystemInfo(trk2NSigmaPiBachelorTOF)) - continue; - if (pidConfig.cUseOnlyTOFTrackProton && !hasSubsystemInfo(trk2NSigmaPrPosTOF)) - continue; - if (pidConfig.cUseOnlyTOFTrackProton && !hasSubsystemInfo(trk2NSigmaPrNegTOF)) - continue; - if (pidConfig.cUseOnlyTOFTrackPion && !hasSubsystemInfo(trk2NSigmaPiPosTOF)) - continue; - if (pidConfig.cUseOnlyTOFTrackPion && !hasSubsystemInfo(trk2NSigmaPiNegTOF)) + if (!selectionPIDCascades(trk2)) { continue; - if (!selectionPIDCascades(trk2)) - continue; - if (!cascprimaryTrackCut(trk2) || !casctopCut(trk2)) // Primary track selections + } + if (!cascprimaryTrackCut(trk2) || !casctopCut(trk2)) { // Primary track selections continue; - if (trk2ProperLifetime >= cascadeConfig.cMaxProperLifetimeCut) + } + if (trk2ProperLifetime >= cascadeConfig.cMaxProperLifetimeCut) { continue; + } // QA after selections if constexpr (!IsMix) { @@ -981,34 +993,34 @@ struct Xi1530Analysisqa { if (histoConfig.pidPlots) { if (trk2.sign() < 0) { - histos.fill(HIST("QAafter/TPC_Nsigma_pi_bachelor_all"), Cent, 0, trk2NSigmaPiBachelorTPC); // not exist pt information in resocascade yet. + histos.fill(HIST("QAafter/TPC_Nsigma_pi_bachelor_all"), cent, 0, trk2NSigmaPiBachelorTPC); // not exist pt information in resocascade yet. if (hasSubsystemInfo(trk2NSigmaPiBachelorTOF)) { histos.fill(HIST("QAafter/TOF_TPC_Map_pi_bachelor_all"), trk2NSigmaPiBachelorTOF, trk2NSigmaPiBachelorTPC); } - histos.fill(HIST("QAafter/TPC_Nsigma_pr_all"), Cent, 0, trk2NSigmaPrPosTPC); + histos.fill(HIST("QAafter/TPC_Nsigma_pr_all"), cent, 0, trk2NSigmaPrPosTPC); if (hasSubsystemInfo(trk2NSigmaPrPosTOF)) { histos.fill(HIST("QAafter/TOF_TPC_Map_pr_all"), trk2NSigmaPrPosTOF, trk2NSigmaPrPosTPC); } - histos.fill(HIST("QAafter/TPC_Nsigma_piminus_all"), Cent, 0, trk2NSigmaPiNegTPC); + histos.fill(HIST("QAafter/TPC_Nsigma_piminus_all"), cent, 0, trk2NSigmaPiNegTPC); if (hasSubsystemInfo(trk2NSigmaPiNegTOF)) { histos.fill(HIST("QAafter/TOF_TPC_Map_piminus_all"), trk2NSigmaPiNegTOF, trk2NSigmaPiNegTPC); } } else { - histos.fill(HIST("QAafter/TPC_Nsigma_pi_bachelor_all"), Cent, 0, trk2NSigmaPiBachelorTPC); // not exist pt information in resocascade yet. + histos.fill(HIST("QAafter/TPC_Nsigma_pi_bachelor_all"), cent, 0, trk2NSigmaPiBachelorTPC); // not exist pt information in resocascade yet. if (hasSubsystemInfo(trk2NSigmaPiBachelorTOF)) { histos.fill(HIST("QAafter/TOF_TPC_Map_pi_bachelor_all"), trk2NSigmaPiBachelorTOF, trk2NSigmaPiBachelorTPC); } - histos.fill(HIST("QAafter/TPC_Nsigma_antipr_all"), Cent, 0, trk2NSigmaPrNegTPC); + histos.fill(HIST("QAafter/TPC_Nsigma_antipr_all"), cent, 0, trk2NSigmaPrNegTPC); if (hasSubsystemInfo(trk2NSigmaPrNegTOF)) { histos.fill(HIST("QAafter/TOF_TPC_Map_antipr_all"), trk2NSigmaPrNegTOF, trk2NSigmaPrNegTPC); } - histos.fill(HIST("QAafter/TPC_Nsigma_pi_all"), Cent, 0, trk2NSigmaPiPosTPC); + histos.fill(HIST("QAafter/TPC_Nsigma_pi_all"), cent, 0, trk2NSigmaPiPosTPC); if (hasSubsystemInfo(trk2NSigmaPiPosTOF)) { histos.fill(HIST("QAafter/TOF_TPC_Map_pi_all"), trk2NSigmaPiPosTOF, trk2NSigmaPiPosTPC); } @@ -1016,8 +1028,8 @@ struct Xi1530Analysisqa { } if (histoConfig.additionalQAplots) { histos.fill(HIST("QAafter/V0DCATopPV"), trk2ptXi, trk2DCAV0TopPV); - histos.fill(HIST("QAafter/trkDCAxy_xi"), trk2ptXi, trk2DCAXY); - histos.fill(HIST("QAafter/trkDCAz_xi"), trk2ptXi, trk2DCAZ); + histos.fill(HIST("QAafter/trkDCAxy_xi"), trk2ptXi, std::abs(trk2DCAXY)); + histos.fill(HIST("QAafter/trkDCAz_xi"), trk2ptXi, std::abs(trk2DCAZ)); histos.fill(HIST("QAafter/V0DCADoughter"), trk2ptXi, trk2DCAV0sDougthers); histos.fill(HIST("QAafter/CascDCADoughter"), trk2ptXi, trk2DCACascDougthers); histos.fill(HIST("QAafter/CascDCABachPV"), trk2ptXi, trk2DCABachPV); @@ -1037,15 +1049,15 @@ struct Xi1530Analysisqa { if (additionalConfig.studyStableXi) { if (trk2.sign() < 0) { - histos.fill(HIST("h3XiinvmassDS"), Cent, trk2ptXi, massXiCand, kData); + histos.fill(HIST("h3XiinvmassDS"), cent, trk2ptXi, massXiCand, kData); } else if (trk2.sign() > 0) { - histos.fill(HIST("h3XiinvmassDSAnti"), Cent, trk2ptXi, massXiCand, kData); + histos.fill(HIST("h3XiinvmassDSAnti"), cent, trk2ptXi, massXiCand, kData); } if constexpr (IsMC) { - if (trk2.motherPDG() > 0) { - histos.fill(HIST("h3RecXiinvmass"), Cent, trk2ptXi, massXiCand, kMCReco); - } else { - histos.fill(HIST("h3RecXiinvmassAnti"), Cent, trk2ptXi, massXiCand, kMCReco); + if (trk2.pdgCode() == kXiMinus) { + histos.fill(HIST("h3RecXiinvmass"), cent, trk2ptXi, massXiCand, kMCReco); + } else if (trk2.pdgCode() == -kXiMinus) { + histos.fill(HIST("h3RecXiinvmassAnti"), cent, trk2ptXi, massXiCand, kMCReco); } } } @@ -1058,11 +1070,19 @@ struct Xi1530Analysisqa { auto pionCand = dTracks1.iteratorAt(trk1cand); for (const auto& trk2cand : xiCandateIndicies) { auto xiCand = dTracks2.iteratorAt(trk2cand); + if constexpr (!IsMix) { + const auto trackId = pionCand.trackId(); + const auto& daughterIds = xiCand.cascadeIndices(); + if (trackId >= 0 && (trackId == daughterIds[0] || trackId == daughterIds[1] || trackId == daughterIds[2])) { + continue; + } + } auto pionCandPt = pionCand.pt(); auto xiCandPt = xiCand.pt(); float massXiCand = xiCand.mXi(); - if (additionalConfig.cUseFixedMassXi) + if (additionalConfig.cUseFixedMassXi) { massXiCand = cascadeConfig.cMassXiminus; + } lDecayDaughter1 = LorentzVectorPtEtaPhiMass(pionCandPt, pionCand.eta(), pionCand.phi(), massPi); lDecayDaughter2 = LorentzVectorPtEtaPhiMass(xiCandPt, xiCand.eta(), xiCand.phi(), massXiCand); @@ -1071,27 +1091,35 @@ struct Xi1530Analysisqa { auto lResonanceMass = lResonance.M(); auto lResonancePt = lResonance.Pt(); - if ((lResonance.Rapidity() <= primarytrackConfig.cfgRapidityMinCut) || (lResonance.Rapidity() >= primarytrackConfig.cfgRapidityMaxCut)) + if ((lResonance.Rapidity() <= primarytrackConfig.cfgRapidityMinCut) || (lResonance.Rapidity() >= primarytrackConfig.cfgRapidityMaxCut)) { continue; + } if (additionalConfig.cfgCutsOnMother) { - if (lResonancePt >= additionalConfig.cMaxPtMotherCut) // excluding candidates in overflow + if (lResonancePt >= additionalConfig.cMaxPtMotherCut) { // excluding candidates in overflow continue; - if (lResonanceMass >= additionalConfig.cMaxMinvMotherCut) // excluding candidates in overflow + } + if (lResonanceMass >= additionalConfig.cMaxMinvMotherCut) { // excluding candidates in overflow continue; + } } if (pionCand.sign() * xiCand.sign() < 0) { // Signal candidates if constexpr (!IsMix) { if (pionCand.sign() > 0) { - if (histoConfig.invMass1D) + if (histoConfig.invMass1D) { histos.fill(HIST("Xi1530invmassDS"), lResonanceMass); - histos.fill(HIST("h3Xi1530invmassDS"), Cent, lResonancePt, lResonanceMass, kData); + } + histos.fill(HIST("h3Xi1530invmassDS"), cent, lResonancePt, lResonanceMass, kData); if (additionalConfig.cfgFillRotBkg) { for (int i = 0; i < additionalConfig.cfgNrotBkg; i++) { - auto lRotAngle = additionalConfig.cfgMinRot + i * ((additionalConfig.cfgMaxRot - additionalConfig.cfgMinRot) / (additionalConfig.cfgNrotBkg - 1)); - histos.fill(HIST("QAevent/hRotBkg"), lRotAngle); + const auto lRotAngle = additionalConfig.cfgNrotBkg == 1 + ? 0.5f * (additionalConfig.cfgMinRot + additionalConfig.cfgMaxRot) + : additionalConfig.cfgMinRot + i * ((additionalConfig.cfgMaxRot - additionalConfig.cfgMinRot) / (additionalConfig.cfgNrotBkg - 1)); + if (histoConfig.eventQA) { + histos.fill(HIST("QAevent/hRotBkg"), lRotAngle); + } if (additionalConfig.cfgRotPion) { lDaughterRot = lDecayDaughter1; ROOT::Math::RotationZ rot(lRotAngle); @@ -1105,18 +1133,27 @@ struct Xi1530Analysisqa { lDaughterRot = LorentzVectorSetXYZM(p3.X(), p3.Y(), p3.Z(), lDaughterRot.M()); lResonanceRot = lDecayDaughter1 + lDaughterRot; } - histos.fill(HIST("h3Xi1530invmassRotDS"), Cent, lResonanceRot.Pt(), lResonanceRot.M(), kData); + if (additionalConfig.cfgCutsOnMother && + (lResonanceRot.Pt() >= additionalConfig.cMaxPtMotherCut || lResonanceRot.M() >= additionalConfig.cMaxMinvMotherCut)) { + continue; + } + histos.fill(HIST("h3Xi1530invmassRotDS"), cent, lResonanceRot.Pt(), lResonanceRot.M(), kData); } } } else if (pionCand.sign() < 0) { - if (histoConfig.invMass1D) + if (histoConfig.invMass1D) { histos.fill(HIST("Xi1530invmassDSAnti"), lResonanceMass); - histos.fill(HIST("h3Xi1530invmassDSAnti"), Cent, lResonancePt, lResonanceMass, kData); + } + histos.fill(HIST("h3Xi1530invmassDSAnti"), cent, lResonancePt, lResonanceMass, kData); if (additionalConfig.cfgFillRotBkg) { for (int i = 0; i < additionalConfig.cfgNrotBkg; i++) { - auto lRotAngle = additionalConfig.cfgMinRot + i * ((additionalConfig.cfgMaxRot - additionalConfig.cfgMinRot) / (additionalConfig.cfgNrotBkg - 1)); - histos.fill(HIST("QAevent/hRotBkg"), lRotAngle); + const auto lRotAngle = additionalConfig.cfgNrotBkg == 1 + ? 0.5f * (additionalConfig.cfgMinRot + additionalConfig.cfgMaxRot) + : additionalConfig.cfgMinRot + i * ((additionalConfig.cfgMaxRot - additionalConfig.cfgMinRot) / (additionalConfig.cfgNrotBkg - 1)); + if (histoConfig.eventQA) { + histos.fill(HIST("QAevent/hRotBkg"), lRotAngle); + } if (additionalConfig.cfgRotPion) { lDaughterRot = lDecayDaughter1; ROOT::Math::RotationZ rot(lRotAngle); @@ -1130,46 +1167,45 @@ struct Xi1530Analysisqa { lDaughterRot = LorentzVectorSetXYZM(p3.X(), p3.Y(), p3.Z(), lDaughterRot.M()); lResonanceRot = lDecayDaughter1 + lDaughterRot; } - histos.fill(HIST("h3Xi1530invmassRotDSAnti"), Cent, lResonanceRot.Pt(), lResonanceRot.M(), kData); + if (additionalConfig.cfgCutsOnMother && + (lResonanceRot.Pt() >= additionalConfig.cMaxPtMotherCut || lResonanceRot.M() >= additionalConfig.cMaxMinvMotherCut)) { + continue; + } + histos.fill(HIST("h3Xi1530invmassRotDSAnti"), cent, lResonanceRot.Pt(), lResonanceRot.M(), kData); } } } } else { if (pionCand.sign() > 0) { - histos.fill(HIST("h3Xi1530invmassME_DS"), Cent, lResonancePt, lResonanceMass, kData); + histos.fill(HIST("h3Xi1530invmassME_DS"), cent, lResonancePt, lResonanceMass, kData); } else if (pionCand.sign() < 0) { - histos.fill(HIST("h3Xi1530invmassME_DSAnti"), Cent, lResonancePt, lResonanceMass, kData); + histos.fill(HIST("h3Xi1530invmassME_DSAnti"), cent, lResonancePt, lResonanceMass, kData); } } if constexpr (IsMC) { - if (std::abs(xiCand.motherPDG()) != kXiStar) + if (std::abs(xiCand.motherPDG()) != kXiStar || pionCand.motherPDG() != xiCand.motherPDG()) { continue; - if (std::abs(pionCand.pdgCode()) != kPiPlus || std::abs(xiCand.pdgCode()) != kXiMinus) + } + const int motherSign = xiCand.motherPDG() > 0 ? 1 : -1; + if (pionCand.pdgCode() != motherSign * kPiPlus || xiCand.pdgCode() != motherSign * kXiMinus) { continue; - if (pionCand.motherId() != xiCand.motherId()) + } + if (xiCand.motherId() < 0 || pionCand.motherId() != xiCand.motherId()) { continue; + } auto lResonancePtMC = xiCand.motherPt(); - if (additionalConfig.cUseTruthRapidity) - continue; - if ((xiCand.motherRap() >= primarytrackConfig.cfgRapidityMaxCut) || (xiCand.motherRap() <= primarytrackConfig.cfgRapidityMinCut)) - continue; - if (histoConfig.truthQA) { - float trk1DCAXY = -1.f; - float trk1DCAZ = -1.f; - float trk1NSigmaPiTPC = -999.f; - float trk1NSigmaPiTOF = -999.f; - if constexpr (IsResoMicrotrack) { - trk1DCAXY = o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(pionCand.trackSelectionFlags()); - trk1DCAZ = o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(pionCand.trackSelectionFlags()); - trk1NSigmaPiTPC = o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(pionCand.pidNSigmaPiFlag()); - trk1NSigmaPiTOF = o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(pionCand.pidNSigmaPiFlag()); - } else { - trk1DCAXY = pionCand.dcaXY(); - trk1DCAZ = pionCand.dcaZ(); - trk1NSigmaPiTPC = pionCand.tpcNSigmaPi(); - trk1NSigmaPiTOF = pionCand.tofNSigmaPi(); + if (additionalConfig.cUseTruthRapidity) { + const bool passesTruthRapidity = xiCand.motherRap() > primarytrackConfig.cfgRapidityMinCut && xiCand.motherRap() < primarytrackConfig.cfgRapidityMaxCut; + if (!passesTruthRapidity) { + continue; } + } + if (histoConfig.truthQA) { + const float trk1DCAXY = pionCand.dcaXY(); + const float trk1DCAZ = pionCand.dcaZ(); + const float trk1NSigmaPiTPC = pionCand.tpcNSigmaPi(); + const float trk1NSigmaPiTOF = pionCand.tofNSigmaPi(); auto trk2DCAXY = xiCand.dcaXYCascToPV(); auto trk2DCAZ = xiCand.dcaZCascToPV(); @@ -1207,80 +1243,88 @@ struct Xi1530Analysisqa { float trk2NSigmaPiPosTOF = xiCand.daughterTOFNSigmaPosPi(); float trk2NSigmaPiNegTOF = xiCand.daughterTOFNSigmaNegPi(); - histos.fill(HIST("QAMCTrue/trkDCAxy_pi"), pionCandPt, trk1DCAXY); - histos.fill(HIST("QAMCTrue/trkDCAz_pi"), pionCandPt, trk1DCAZ); - histos.fill(HIST("QAMCTrue/V0DCATopPV"), xiCandPt, trk2DCAV0TopPV); - histos.fill(HIST("QAMCTrue/trkDCAxy_xi"), xiCandPt, trk2DCAXY); - histos.fill(HIST("QAMCTrue/trkDCAz_xi"), xiCandPt, trk2DCAZ); - - histos.fill(HIST("QAMCTrue/V0DCADoughter"), xiCandPt, trk2DCAV0sDougthers); - histos.fill(HIST("QAMCTrue/CascDCADoughter"), xiCandPt, trk2DCACascDougthers); - histos.fill(HIST("QAMCTrue/CascDCABachPV"), xiCandPt, trk2DCABachPV); - histos.fill(HIST("QAMCTrue/CascDCAPosPV"), xiCandPt, trk2DCAPosPV); - histos.fill(HIST("QAMCTrue/CascDCANegPV"), xiCandPt, trk2DCANegPV); - histos.fill(HIST("QAMCTrue/V0CosPA"), xiCandPt, 1. - trk2V0CosPA); - histos.fill(HIST("QAMCTrue/CascCosPA"), xiCandPt, 1. - trk2CascCosPA); - histos.fill(HIST("QAMCTrue/V0Radius"), xiCandPt, trk2V0Radius); - histos.fill(HIST("QAMCTrue/CascRadius"), xiCandPt, trk2CascRadius); - histos.fill(HIST("QAMCTrue/V0Mass"), xiCandPt, massLambdaCand); - histos.fill(HIST("QAMCTrue/CascMass"), xiCandPt, massXiCand); - histos.fill(HIST("QAMCTrue/ProperLifetime"), xiCandPt, trk2ProperLifetime); - histos.fill(HIST("QAMCTrue/NCrossedRowsPos"), xiCandPt, trks2NCrossedRowsPos); - histos.fill(HIST("QAMCTrue/NCrossedRowsNeg"), xiCandPt, trks2NCrossedRowsNeg); - histos.fill(HIST("QAMCTrue/NCrossedRowsBach"), xiCandPt, trks2NCrossedRowsBach); - - histos.fill(HIST("QAMCTrue/TPC_Nsigma_pi_first_all"), Cent, pionCandPt, trk1NSigmaPiTPC); - if (hasSubsystemInfo(trk1NSigmaPiTOF)) { - histos.fill(HIST("QAMCTrue/TOF_Nsigma_pi_first_all"), Cent, pionCandPt, trk1NSigmaPiTOF); - histos.fill(HIST("QAMCTrue/TOF_TPC_Map_pi_first_all"), trk1NSigmaPiTOF, trk1NSigmaPiTPC); + if (histoConfig.additionalQAplots) { + histos.fill(HIST("QAMCTrue/trkDCAxy_pi"), pionCandPt, std::abs(trk1DCAXY)); + histos.fill(HIST("QAMCTrue/trkDCAz_pi"), pionCandPt, std::abs(trk1DCAZ)); + histos.fill(HIST("QAMCTrue/V0DCATopPV"), xiCandPt, trk2DCAV0TopPV); + histos.fill(HIST("QAMCTrue/trkDCAxy_xi"), xiCandPt, std::abs(trk2DCAXY)); + histos.fill(HIST("QAMCTrue/trkDCAz_xi"), xiCandPt, std::abs(trk2DCAZ)); + + histos.fill(HIST("QAMCTrue/V0DCADoughter"), xiCandPt, trk2DCAV0sDougthers); + histos.fill(HIST("QAMCTrue/CascDCADoughter"), xiCandPt, trk2DCACascDougthers); + histos.fill(HIST("QAMCTrue/CascDCABachPV"), xiCandPt, trk2DCABachPV); + histos.fill(HIST("QAMCTrue/CascDCAPosPV"), xiCandPt, trk2DCAPosPV); + histos.fill(HIST("QAMCTrue/CascDCANegPV"), xiCandPt, trk2DCANegPV); + histos.fill(HIST("QAMCTrue/V0CosPA"), xiCandPt, 1. - trk2V0CosPA); + histos.fill(HIST("QAMCTrue/CascCosPA"), xiCandPt, 1. - trk2CascCosPA); + histos.fill(HIST("QAMCTrue/V0Radius"), xiCandPt, trk2V0Radius); + histos.fill(HIST("QAMCTrue/CascRadius"), xiCandPt, trk2CascRadius); + histos.fill(HIST("QAMCTrue/V0Mass"), xiCandPt, massLambdaCand); + histos.fill(HIST("QAMCTrue/CascMass"), xiCandPt, xiCand.mXi()); + histos.fill(HIST("QAMCTrue/ProperLifetime"), xiCandPt, trk2ProperLifetime); + histos.fill(HIST("QAMCTrue/NCrossedRowsPos"), xiCandPt, trks2NCrossedRowsPos); + histos.fill(HIST("QAMCTrue/NCrossedRowsNeg"), xiCandPt, trks2NCrossedRowsNeg); + histos.fill(HIST("QAMCTrue/NCrossedRowsBach"), xiCandPt, trks2NCrossedRowsBach); } - histos.fill(HIST("QAMCTrue/TPC_Nsigma_pi_bachelor_all"), Cent, 0, trk2NSigmaPiBachelorTPC); // not exist pt information in resocascade yet. - if (hasSubsystemInfo(trk2NSigmaPiBachelorTOF)) { - histos.fill(HIST("QAMCTrue/TOF_TPC_Map_pi_bachelor_all"), trk2NSigmaPiBachelorTOF, trk2NSigmaPiBachelorTPC); - } + if (histoConfig.pidPlots) { + histos.fill(HIST("QAMCTrue/TPC_Nsigma_pi_first_all"), cent, pionCandPt, trk1NSigmaPiTPC); + if (pionCand.hasTOF() && !std::isnan(trk1NSigmaPiTOF)) { + histos.fill(HIST("QAMCTrue/TOF_Nsigma_pi_first_all"), cent, pionCandPt, trk1NSigmaPiTOF); + histos.fill(HIST("QAMCTrue/TOF_TPC_Map_pi_first_all"), trk1NSigmaPiTOF, trk1NSigmaPiTPC); + } - histos.fill(HIST("QAMCTrue/TPC_Nsigma_pr_all"), Cent, 0, trk2NSigmaPrPosTPC); - if (hasSubsystemInfo(trk2NSigmaPrPosTOF)) { - histos.fill(HIST("QAMCTrue/TOF_TPC_Map_pr_all"), trk2NSigmaPrPosTOF, trk2NSigmaPrPosTPC); - } - histos.fill(HIST("QAMCTrue/TPC_Nsigma_antipr_all"), Cent, 0, trk2NSigmaPrNegTPC); - if (hasSubsystemInfo(trk2NSigmaPrNegTOF)) { - histos.fill(HIST("QAMCTrue/TOF_TPC_Map_antipr_all"), trk2NSigmaPrNegTOF, trk2NSigmaPrNegTPC); - } + histos.fill(HIST("QAMCTrue/TPC_Nsigma_pi_bachelor_all"), cent, 0, trk2NSigmaPiBachelorTPC); // not exist pt information in resocascade yet. + if (hasSubsystemInfo(trk2NSigmaPiBachelorTOF)) { + histos.fill(HIST("QAMCTrue/TOF_TPC_Map_pi_bachelor_all"), trk2NSigmaPiBachelorTOF, trk2NSigmaPiBachelorTPC); + } - histos.fill(HIST("QAMCTrue/TPC_Nsigma_piminus_all"), Cent, 0, trk2NSigmaPiNegTPC); - if (hasSubsystemInfo(trk2NSigmaPiNegTOF)) { - histos.fill(HIST("QAMCTrue/TOF_TPC_Map_piminus_all"), trk2NSigmaPiNegTOF, trk2NSigmaPiNegTPC); - } - histos.fill(HIST("QAMCTrue/TPC_Nsigma_pi_all"), Cent, 0, trk2NSigmaPiPosTPC); - if (hasSubsystemInfo(trk2NSigmaPiPosTOF)) { - histos.fill(HIST("QAMCTrue/TOF_TPC_Map_pi_all"), trk2NSigmaPiPosTOF, trk2NSigmaPiPosTPC); + if (xiCand.sign() < 0) { + histos.fill(HIST("QAMCTrue/TPC_Nsigma_pr_all"), cent, 0, trk2NSigmaPrPosTPC); + if (hasSubsystemInfo(trk2NSigmaPrPosTOF)) { + histos.fill(HIST("QAMCTrue/TOF_TPC_Map_pr_all"), trk2NSigmaPrPosTOF, trk2NSigmaPrPosTPC); + } + histos.fill(HIST("QAMCTrue/TPC_Nsigma_piminus_all"), cent, 0, trk2NSigmaPiNegTPC); + if (hasSubsystemInfo(trk2NSigmaPiNegTOF)) { + histos.fill(HIST("QAMCTrue/TOF_TPC_Map_piminus_all"), trk2NSigmaPiNegTOF, trk2NSigmaPiNegTPC); + } + } else { + histos.fill(HIST("QAMCTrue/TPC_Nsigma_antipr_all"), cent, 0, trk2NSigmaPrNegTPC); + if (hasSubsystemInfo(trk2NSigmaPrNegTOF)) { + histos.fill(HIST("QAMCTrue/TOF_TPC_Map_antipr_all"), trk2NSigmaPrNegTOF, trk2NSigmaPrNegTPC); + } + histos.fill(HIST("QAMCTrue/TPC_Nsigma_pi_all"), cent, 0, trk2NSigmaPiPosTPC); + if (hasSubsystemInfo(trk2NSigmaPiPosTOF)) { + histos.fill(HIST("QAMCTrue/TOF_TPC_Map_pi_all"), trk2NSigmaPiPosTOF, trk2NSigmaPiPosTPC); + } + } } } // truthQA // MC histograms if (xiCand.motherPDG() > 0) { - histos.fill(HIST("Xi1530Rec"), lResonancePt, Cent); + histos.fill(HIST("Xi1530Rec"), lResonancePt, cent); histos.fill(HIST("Xi1530Recinvmass"), lResonanceMass); - histos.fill(HIST("h3RecXi1530invmass"), Cent, lResonancePt, lResonanceMass, lResonancePtMC); + histos.fill(HIST("h3RecXi1530invmass"), cent, lResonancePt, lResonanceMass, lResonancePtMC); } else { - histos.fill(HIST("Xi1530RecAnti"), lResonancePt, Cent); + histos.fill(HIST("Xi1530RecAnti"), lResonancePt, cent); histos.fill(HIST("Xi1530Recinvmass"), lResonanceMass); - histos.fill(HIST("h3RecXi1530invmassAnti"), Cent, lResonancePt, lResonanceMass, lResonancePtMC); + histos.fill(HIST("h3RecXi1530invmassAnti"), cent, lResonancePt, lResonanceMass, lResonancePtMC); } } // is MC } else { // Bkg candidates if constexpr (!IsMix) { if (pionCand.sign() < 0) { - if (histoConfig.invMass1D) + if (histoConfig.invMass1D) { histos.fill(HIST("Xi1530invmassLS"), lResonanceMass); - histos.fill(HIST("h3Xi1530invmassLS"), Cent, lResonancePt, lResonanceMass, kLS); + } + histos.fill(HIST("h3Xi1530invmassLS"), cent, lResonancePt, lResonanceMass, kLS); } else if (pionCand.sign() > 0) { - if (histoConfig.invMass1D) + if (histoConfig.invMass1D) { histos.fill(HIST("Xi1530invmassLSAnti"), lResonanceMass); - histos.fill(HIST("h3Xi1530invmassLSAnti"), Cent, lResonancePt, lResonanceMass, kLS); + } + histos.fill(HIST("h3Xi1530invmassLSAnti"), cent, lResonancePt, lResonanceMass, kLS); } } } // -> End if signal or bkg @@ -1288,22 +1332,17 @@ struct Xi1530Analysisqa { } // -> End loop over pion and xi candidates } // -> End fillHistograms - void processData(aod::ResoCollision const& resoCollision, - aod::ResoTracks const& resoTracks, + void processData(ResoCollisions::iterator const& resoCollision, + ResoTracks const& resoTracks, aod::ResoCascades const& cascTracks) { auto inCent = resoCollision.cent(); - auto multiplicity = 0.f; + // Version 001 stores the estimator chosen by cfgMultiplicityEstimator in the producer. + const auto multiplicity = resoCollision.multiplicity(); - if (additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) // Check reco INELgt0 (at least one PV track in |eta| < 1) about the collision + if (additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) { // Check reco INELgt0 (at least one PV track in |eta| < 1) about the collision return; - if (additionalConfig.cMultNTracksPVFull) - multiplicity = resoCollision.multNTracksPV(); - else if (additionalConfig.cMultNTracksPVeta1) - multiplicity = resoCollision.multNTracksPVeta1(); - else if (additionalConfig.cMultNTracksPVetaHalf) - multiplicity = resoCollision.multNTracksPVetaHalf(); - + } if (histoConfig.multQA) { histos.fill(HIST("multQA/h2MultCent"), inCent, multiplicity); } @@ -1313,74 +1352,83 @@ struct Xi1530Analysisqa { // Calculate numerator for the Acceptance x Efficiency void processMC(ResoMCCols::iterator const& resoCollision, soa::Join const& cascTracks, - soa::Join const& resoTracks) + soa::Join const& resoTracks) { auto inCent = resoCollision.cent(); - float multiplicity = 0.f; - if (additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) // Check reco INELgt0 (at least one PV track in |eta| < 1) about the collision - return; - if (additionalConfig.cMultNTracksPVFull) - multiplicity = resoCollision.multNTracksPV(); - else if (additionalConfig.cMultNTracksPVeta1) - multiplicity = resoCollision.multNTracksPVeta1(); - else if (additionalConfig.cMultNTracksPVetaHalf) - multiplicity = resoCollision.multNTracksPVetaHalf(); - - if (!resoCollision.isInAfterAllCuts()) // MC event selection, all cuts missing vtx cut + const auto multiplicity = resoCollision.multiplicity(); + if ((additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) || + (additionalConfig.cMCINELgt0 && !resoCollision.isINELgt0()) || + (additionalConfig.cMCVtxIn10 && !resoCollision.isVtxIn10())) { return; + } + // The modular producer writes only selected reconstructed collisions. if (histoConfig.multQA) { histos.fill(HIST("multQA/h2MultCent"), inCent, multiplicity); } fillHistograms(resoCollision, inCent, resoTracks, cascTracks); } + void processMCMicro(ResoMCCols::iterator const& resoCollision, + soa::Join const& cascTracks, + soa::Join const& resoTracks) + { + if ((additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) || + (additionalConfig.cMCINELgt0 && !resoCollision.isINELgt0()) || + (additionalConfig.cMCVtxIn10 && !resoCollision.isVtxIn10())) { + return; + } + if (histoConfig.multQA) { + histos.fill(HIST("multQA/h2MultCent"), resoCollision.cent(), resoCollision.multiplicity()); + } + fillHistograms(resoCollision, resoCollision.cent(), resoTracks, cascTracks); + } + // Calculate denominator for the Acceptance x Efficiency, actually it is not Trueth info... void processMCTrue(ResoMCCols::iterator const& resoCollision, - aod::ResoMCParents const& resoParents) + aod::ResoMCParents_001 const& resoParents) { auto multiplicity = resoCollision.mcMultiplicity(); auto inCent = resoCollision.cent(); - if (additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) // Check reco INELgt0 (at least one PV track in |eta| < 1) about the collision - return; - if (!resoCollision.isInAfterAllCuts()) + if ((additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) || + (additionalConfig.cMCINELgt0 && !resoCollision.isINELgt0()) || + (additionalConfig.cMCVtxIn10 && !resoCollision.isVtxIn10())) { return; + } if (histoConfig.multQA) { histos.fill(HIST("multQA/h2MultCentMC"), inCent, multiplicity); } for (const auto& part : resoParents) { // loop over all pre-filtered MC particles - if (std::abs(part.pdgCode()) != kXiStar) + if (std::abs(part.pdgCode()) != kXiStar) { continue; - if ((part.y() <= primarytrackConfig.cfgRapidityMinCut) || (part.y() >= primarytrackConfig.cfgRapidityMaxCut)) + } + if ((part.y() <= primarytrackConfig.cfgRapidityMinCut) || (part.y() >= primarytrackConfig.cfgRapidityMaxCut)) { continue; + } bool pass1 = std::abs(part.daughterPDG1()) == kPiPlus || std::abs(part.daughterPDG2()) == kPiPlus; bool pass2 = std::abs(part.daughterPDG1()) == kXiMinus || std::abs(part.daughterPDG2()) == kXiMinus; - if (!pass1 || !pass2) + if (!pass1 || !pass2) { continue; + } - if (part.pdgCode() > 0) + if (part.pdgCode() > 0) { histos.fill(HIST("h3Xi1530Gen"), part.pt(), inCent, multiplicity); - else + } else { histos.fill(HIST("h3Xi1530GenAnti"), part.pt(), inCent, multiplicity); + } } } - void processDataMicro(aod::ResoCollision const& resoCollision, - aod::ResoMicroTracks const& resomicrotracks, + void processDataMicro(ResoCollisions::iterator const& resoCollision, + ResoMicroTracks const& resomicrotracks, aod::ResoCascades const& cascTracks) { - float multiplicity = 0.f; + const auto multiplicity = resoCollision.multiplicity(); auto inCent = resoCollision.cent(); - if (additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) // Check reco INELgt0 (at least one PV track in |eta| < 1) about the collision + if (additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) { // Check reco INELgt0 (at least one PV track in |eta| < 1) about the collision return; - if (additionalConfig.cMultNTracksPVFull) - multiplicity = resoCollision.multNTracksPV(); - else if (additionalConfig.cMultNTracksPVeta1) - multiplicity = resoCollision.multNTracksPVeta1(); - else if (additionalConfig.cMultNTracksPVetaHalf) - multiplicity = resoCollision.multNTracksPVetaHalf(); - + } if (histoConfig.multQA) { histos.fill(HIST("multQA/h2MultCent"), inCent, multiplicity); } @@ -1388,64 +1436,98 @@ struct Xi1530Analysisqa { } using BinningTypeVtxZT0M = ColumnBinningPolicy; - void processMEMicro(aod::ResoCollisions const& resoCollisions, - aod::ResoMicroTracks const& resomicrotracks, + void processMEMicro(ResoCollisions const& resoCollisions, + ResoMicroTracks const& resomicrotracks, aod::ResoCascades const& cascTracks) { + if (mixingConfig.nEvtMixing <= 0) { + return; + } auto tracksTuple = std::make_tuple(resomicrotracks, cascTracks); BinningTypeVtxZT0M colBinning{{mixingConfig.cfgVtxBins, mixingConfig.cfgMultBins}, true}; - Pair pairs{colBinning, mixingConfig.nEvtMixing, -1, resoCollisions, tracksTuple, &cache}; + Pair pairs{colBinning, mixingConfig.nEvtMixing, -1, resoCollisions, tracksTuple, &cache}; for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { - float multiplicity = 0.f; + const auto multiplicity = collision1.multiplicity(); auto inCent = collision1.cent(); - if (additionalConfig.cRecoINELgt0 && !collision1.isRecINELgt0()) // Check reco INELgt0 (at least one PV track in |eta| < 1) about the collision + if (additionalConfig.cRecoINELgt0 && (!collision1.isRecINELgt0() || !collision2.isRecINELgt0())) { continue; - if (additionalConfig.cMultNTracksPVFull) - multiplicity = collision1.multNTracksPV(); - else if (additionalConfig.cMultNTracksPVeta1) - multiplicity = collision1.multNTracksPVeta1(); - else if (additionalConfig.cMultNTracksPVetaHalf) - multiplicity = collision1.multNTracksPVetaHalf(); - + } + if (!std::isfinite(collision1.bMagField()) || collision1.bMagField() != collision2.bMagField()) { + continue; + } if (histoConfig.multQA) { - histos.fill(HIST("multQA/h2MultCent"), inCent, multiplicity); + histos.fill(HIST("multQA/h2MultCentME"), inCent, multiplicity); } - fillHistograms(collision1, inCent, tracks1, tracks2); + const MixingCollision cascadeCollision{.x = collision2.posX(), .y = collision2.posY(), .z = collision2.posZ(), .centrality = collision2.cent(), .multiplicity = collision2.multiplicity(), .index = collision2.globalIndex(), .recINELgt0 = collision2.isRecINELgt0()}; + fillHistograms(collision1, inCent, tracks1, tracks2, &cascadeCollision); } } - // void processMEDF(aod::ResoCollisionDFs const& resoCollisions, aod::ResoTrackDFs const& resotracks, aod::ResoCascadeDFs const& cascTracks) - // { - - /* Will be implemented once the DataFrame for cascade is ready. */ - - // auto tracksTuple = std::make_tuple(resotracks, cascTracks); - - // BinningTypeVtxZT0M colBinning{{mixingConfig.cfgVtxBins, mixingConfig.cfgMultBins}, true}; - // Pair pairs{colBinning, mixingConfig.nEvtMixing, -1, resoCollisions, tracksTuple, &cache}; - - // for (const auto& [collision1, tracks1, collision2, tracks2] : pairs) { + static std::shared_ptr copyMixingTracks(ResoMicroTracks const& tracks) + { + const auto source = tracks.asArrowTableConstrained(); + if (source->num_rows() == 0) { + return arrow::Table::MakeEmpty(source->schema()).ValueOrDie(); + } + std::vector> columns; + columns.reserve(source->num_columns()); + for (const auto& column : source->columns()) { + // Concatenate copies only the slice's rows, releasing the source DF buffers. + columns.push_back(std::make_shared(arrow::Concatenate(column->chunks()).ValueOrDie())); + } + return arrow::Table::Make(source->schema(), columns); + } - // float multiplicity = 0.f; - // auto inCent = collision1.cent(); - // if (histoConfig.multQA) { - // histos.fill(HIST("multQA/h2MultCent"), inCent, multiplicity); - // } - // fillHistograms(collision1, inCent, tracks1, tracks2); - // } - // } + // Cross-DF mixing on module v001 input; no legacy Reso*DF merger is needed. + // History is local to this task instance. Use inputs from one run/condition set. + void processMEDF(ResoCollisions::iterator const& collision, + ResoMicroTracks const& tracks, + aod::ResoCascades const& cascades) + { + if (mixingConfig.nEvtMixing <= 0 || !std::isfinite(collision.bMagField())) { + return; + } + if (mixingBField != collision.bMagField()) { + mixingPools.clear(); + mixingBField = collision.bMagField(); + } + BinningTypeVtxZT0M binning{{mixingConfig.cfgVtxBins, mixingConfig.cfgMultBins}, true}; + const int bin = binning.getBin(std::make_tuple(collision.posZ(), collision.cent())); + if (bin < 0) { + return; + } + const MixingCollision current{.x = collision.posX(), .y = collision.posY(), .z = collision.posZ(), .centrality = collision.cent(), .multiplicity = collision.multiplicity(), .index = collision.globalIndex(), .recINELgt0 = collision.isRecINELgt0()}; + auto& pool = mixingPools[bin]; + for (const auto& previous : pool) { + const auto& anchor = previous.collision; + if (additionalConfig.cRecoINELgt0 && (!anchor.recINELgt0 || !current.recINELgt0)) { + continue; + } + if (histoConfig.multQA) { + histos.fill(HIST("multQA/h2MultCentME"), anchor.centrality, anchor.multiplicity); + } + // Preserve the old pion -> new Cascade direction and the Cascade's own PV. + fillHistograms(anchor, anchor.centrality, ResoMicroTracks{previous.tracks}, cascades, ¤t); + } + // Insert after mixing: DF-local row IDs may repeat, but no event mixes with itself. + pool.push_back({current, copyMixingTracks(tracks)}); + while (pool.size() > static_cast(mixingConfig.nEvtMixing.value)) { + pool.pop_front(); + } + } PROCESS_SWITCH(Xi1530Analysisqa, processData, "Process Event for Data", false); PROCESS_SWITCH(Xi1530Analysisqa, processMC, "Process Event for MC (Reconstructed)", false); + PROCESS_SWITCH(Xi1530Analysisqa, processMCMicro, "Process Event for MC (Reconstructed MicroTrack 001)", false); PROCESS_SWITCH(Xi1530Analysisqa, processMCTrue, "Process Event for MC (Generated)", false); PROCESS_SWITCH(Xi1530Analysisqa, processDataMicro, "Process Event for Data (MicroTrack)", false); PROCESS_SWITCH(Xi1530Analysisqa, processMEMicro, "Process EventMixing (MicroTrack) ", false); - // PROCESS_SWITCH(Xi1530Analysisqa, processMEDF, "Process EventMixing (DataFrame) ", false); + PROCESS_SWITCH(Xi1530Analysisqa, processMEDF, "Process cross-DF EventMixing (MicroTrack 001)", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(context)}; } diff --git a/PWGLF/Tasks/Resonances/xi1530kaoncorrelation.cxx b/PWGLF/Tasks/Resonances/xi1530kaoncorrelation.cxx new file mode 100644 index 00000000000..b48a6b13948 --- /dev/null +++ b/PWGLF/Tasks/Resonances/xi1530kaoncorrelation.cxx @@ -0,0 +1,1067 @@ +// 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. + +/// \file xi1530kaoncorrelation.cxx +/// \brief Xi(1530)^0--K femtoscopic correlation task on compact reduced tables. +/// \author Prottay Das, prottay.das@cern.ch +/// +/// Some information: Same-event and mixed-event processing are intentionally implemented as +/// separate PROCESS_SWITCH functions. The task reconstructs all downstream +/// selections from the producer bitmaps/raw kaon PID, keeps M(Xi pi) as an +/// explicit axis for signal extraction in each k* bin, and uses the +/// reconstructed Xi-pi mass in the k* calculation. +/// +/// Default PID choices: +/// * prompt Xi* pion: TPC-only, 3 sigma; +/// * Xi bachelor pion: TPC-only, 3 sigma; +/// * Lambda pion/proton: TPC-only, 4 sigma; +/// * external K: TPC-only below pT=0.5 GeV/c and circular TPC+TOF above, +/// requiring TOF above threshold. +/// +/// The producer also stores alternative prompt/bachelor PID decisions and raw +/// kaon TPC/TOF PID, so those choices I kept configurable downstream (will change later). + +#include "PWGLF/DataModel/LFReducedXi1530KaonTables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace o2; +using namespace o2::aod; +using namespace o2::framework; +using namespace o2::soa; + +namespace +{ +constexpr float kKaonMass = o2::constants::physics::MassKPlus; +constexpr float kPi = 3.14159265358979323846f; +constexpr float kTwoPi = 2.f * kPi; + +inline bool hasTrackBit(uint64_t word, redxistark::XiStarTrackSelBit bit) +{ + return (word & redxistark::xiStarTrackSelMask(bit)) != 0u; +} + +inline bool hasTopoBit(uint64_t word, redxistark::XiStarTopoSelBit bit) +{ + return (word & redxistark::xiStarTopoSelMask(bit)) != 0u; +} + +inline bool hasKaonBit(uint8_t word, redxistarkaon::KaonSelBit bit) +{ + return (word & redxistarkaon::kaonSelMask(bit)) != 0u; +} + +inline float wrapToPi(float x) +{ + while (x > kPi) { + x -= kTwoPi; + } + while (x <= -kPi) { + x += kTwoPi; + } + return x; +} +} // namespace + +struct xi1530kaoncorrelation { + HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + // --------------------------------------------------------------------------- + // Xi(1530) selection reconstructed from the producer bitmaps. + // + // Default daughter PID is TPC-only; producer-stored alternatives remain selectable. + // --------------------------------------------------------------------------- + struct : ConfigurableGroup { + std::string prefix = "xiStarSelection"; + + Configurable promptPionPIDMode{"promptPionPIDMode", 2, "Prompt pion PID mode: 0=availability hybrid, 1=pT-threshold hybrid, 2=TPC-only"}; + Configurable promptPionPIDWP{"promptPionPIDWP", 0, "Prompt pion TPC PID: 0=3sigma, 1=4sigma, 2=5sigma, 3=6sigma"}; + Configurable bachelorPionPIDMode{"bachelorPionPIDMode", 1, "Xi bachelor pion PID mode: 0=availability hybrid, 1=TPC-only"}; + Configurable bachelorPionPIDWP{"bachelorPionPIDWP", 0, "Xi bachelor pion PID: 0=3sigma, 1=4sigma, 2=4.8sigma, 3=5sigma, 4=6sigma; 4.8 is TPC-only"}; + Configurable lambdaPionPIDWP{"lambdaPionPIDWP", 1, "Lambda pion TPC PID: 0=3sigma, 1=4sigma, 2=4.8sigma, 3=5sigma, 4=6sigma"}; + Configurable lambdaProtonPIDWP{"lambdaProtonPIDWP", 1, "Lambda proton TPC PID: 0=3sigma, 1=4sigma, 2=5sigma, 3=6sigma"}; + + Configurable promptPionRowsWP{"promptPionRowsWP", 1, "Prompt-pion rows: 0=>70, 1=>80, 2=>90"}; + Configurable promptPionDCAzWP{"promptPionDCAzWP", 1, "Prompt-pion DCAz: 0=loose 1 cm bit, 1=producer default bit, 2=tight 0.1 cm bit"}; + Configurable v0DaughterRowsWP{"v0DaughterRowsWP", 1, "Cascade/V0 daughter rows: 0=all cascade daughters broad bit, 1=V0 rows nominal bit, 2=Var1, 3=Var2"}; + + Configurable v0PionDcaPVWP{"v0PionDcaPVWP", 3, "V0 pion DCA-to-PV bit: 0=0.05, 1=0.06, 2=0.10, 3=0.20 cm"}; + Configurable v0ProtonDcaPVWP{"v0ProtonDcaPVWP", 2, "V0 proton DCA-to-PV bit: 0=0.05, 1=0.06, 2=0.07, 3=0.10 cm"}; + Configurable v0DcaPVWP{"v0DcaPVWP", 1, "Minimum Lambda/V0 DCA-to-PV bit: 0=0, 1=0.03, 2=0.10 cm"}; + Configurable v0DcaDaughtersWP{"v0DcaDaughtersWP", 0, "V0 daughter DCA/native metric bit: 0=<1.0, 1=<0.5, 2=<0.1"}; + Configurable v0CosPAWP{"v0CosPAWP", 4, "V0 cosPA bit: 0=0.97, 1=0.98, 2=0.9876, 3=0.99, 4=0.995"}; + Configurable v0RadiusWP{"v0RadiusWP", 4, "V0 minimum-radius bit: 0=0.9, 1=1.01, 2=1.2, 3=2.5, 4=3.0 cm"}; + Configurable lambdaMassWP{"lambdaMassWP", 1, "Lambda mass-window bit: 0=10, 1=8, 2=6, 3=11.6 MeV/c2"}; + Configurable applyV0LifetimeCut{"applyV0LifetimeCut", true, "Apply producer Lambda-lifetime bit"}; + Configurable v0LifetimeWP{"v0LifetimeWP", 0, "Lambda lifetime bit: 0=default, 1=Var1, 2=Var2; thresholds are those used in producer JSON"}; + + Configurable cascBachelorDcaPVWP{"cascBachelorDcaPVWP", 1, "Xi bachelor DCA-to-PV bit: 0=0.05, 1=0.06, 2=0.10 cm"}; + Configurable cascDcaDaughtersWP{"cascDcaDaughtersWP", 1, "Cascade daughter DCA/native metric bit: 0=<1.0, 1=<0.25, 2=<0.20"}; + Configurable cascCosPAWP{"cascCosPAWP", 1, "Cascade cosPA bit: 0=0.97, 1=0.98, 2=0.9947, 3=0.995"}; + Configurable cascRadiusWP{"cascRadiusWP", 2, "Cascade minimum-radius bit: 0=0.9, 1=1.0, 2=1.01, 3=1.3 cm"}; + Configurable xiMassWP{"xiMassWP", 1, "Xi mass-window bit: 0=10, 1=8, 2=6 MeV/c2"}; + Configurable applyXiLifetimeCut{"applyXiLifetimeCut", true, "Apply producer Xi-lifetime bit"}; + Configurable xiLifetimeWP{"xiLifetimeWP", 0, "Xi lifetime bit: 0=default, 1=Var1, 2=Var2; thresholds are those used in producer JSON"}; + + Configurable requirePPBachBaryonDCAxy{"requirePPBachBaryonDCAxy", false, "Require pp-Xi bachelor-baryon DCAxy bit"}; + Configurable requirePPXiRapidity{"requirePPXiRapidity", false, "Require pp-Xi rapidity bit"}; + } xiCuts; + + // --------------------------------------------------------------------------- + // External K selection. + // Raw TPC/TOF n-sigma values are stored by the producer. + // --------------------------------------------------------------------------- + struct : ConfigurableGroup { + std::string prefix = "kaonSelection"; + + Configurable ptMin{"ptMin", 0.15f, "Minimum external-K pT (GeV/c)"}; + Configurable ptMax{"ptMax", 100.f, "Maximum external-K pT (GeV/c)"}; + Configurable tpcRowsMin{"tpcRowsMin", 80, "Minimum TPC crossed rows, strict >"}; + + Configurable dcaXYWP{"dcaXYWP", 0, "K DCAxy bit: 0=default, 1=Var1, 2=Var2"}; + Configurable dcaZWP{"dcaZWP", 0, "K DCAz bit: 0=default, 1=Var1, 2=Var2"}; + + Configurable pidMode{"pidMode", 2, "K PID mode: 0=TPC-only, 1=availability hybrid, 2=pT-threshold hybrid"}; + Configurable pidPtThreshold{"pidPtThreshold", 0.5f, "pT threshold between TPC-only and circular TPC+TOF PID (GeV/c)"}; + Configurable tpcNSigmaMax{"tpcNSigmaMax", 3.f, "Maximum |TPC nSigma_K| below threshold"}; + Configurable circularNSigmaMax{"circularNSigmaMax", 3.f, "Maximum sqrt(TPC^2+TOF^2) above threshold"}; + Configurable requireTOFAboveThreshold{"requireTOFAboveThreshold", true, "Require TOF for K at/above PID threshold"}; + } kaonCuts; + + // --------------------------------------------------------------------------- + // Pair/channel selections. + // --------------------------------------------------------------------------- + struct : ConfigurableGroup { + std::string prefix = "pairSelection"; + + Configurable fillMatter{"fillMatter", true, "Process Xi*-K- matter channels"}; + Configurable fillAntimatter{"fillAntimatter", true, "Process anti-Xi*-K+ antimatter channels"}; + Configurable fillLikeSignControl{"fillLikeSignControl", true, "Keep like-sign Xi-pi control channels (+/-2)"}; + Configurable applySharedTrackCleaning{"applySharedTrackCleaning", true, "Reject SE kaons sharing any Xi* daughter track"}; + } pairCuts; + + // --------------------------------------------------------------------------- + // Event mixing. + // --------------------------------------------------------------------------- + Configurable nEvtMixing{"nEvtMixing", 10, "Number of previous events to mix"}; + ConfigurableAxis cfgMixVtxBins{"cfgMixVtxBins", {VARIABLE_WIDTH, -10.0, -8.0, -6.0, -4.0, -2.0, 0.0, 2.0, 4.0, 6.0, 8.0, 10.0}, "Mixing bins in z vertex (cm)"}; + ConfigurableAxis cfgMixFT0MBins{"cfgMixFT0MBins", {VARIABLE_WIDTH, 0.0, 1.0, 5.0, 10.0, 15.0, 20.0, 30.0, 40.0, 50.0, 70.0, 100.0, 101.0, 110.0}, "Mixing bins in FT0M percentile"}; + ConfigurableAxis cfgMixBzBins{"cfgMixBzBins", {VARIABLE_WIDTH, -1.0, -0.1, 0.1, 1.0}, "Mixing bins in Bz (T)"}; + + using MixingBinning = ColumnBinningPolicy; + MixingBinning mixingBinning{{cfgMixVtxBins, cfgMixFT0MBins, cfgMixBzBins}, true}; + + Preslice xiStarsPerEvent = aod::redxistarcandidate::redXiStarKEventId; + Preslice kaonsPerEvent = aod::redxistarkaon::redXiStarKEventId; + + // --------------------------------------------------------------------------- + // Histogram axes. + // --------------------------------------------------------------------------- + ConfigurableAxis cfgAxisKstar{"cfgAxisKstar", {200, 0.0, 1.0}, "k* axis (GeV/c)"}; + ConfigurableAxis cfgAxisMass{"cfgAxisMass", {500, 1.45, 1.70}, "M(Xi pi) axis (GeV/c2)"}; + ConfigurableAxis cfgAxisMt{"cfgAxisMt", {100, 0.0, 5.0}, "pair mT axis (GeV/c2)"}; + ConfigurableAxis cfgAxisXiPt{"cfgAxisXiPt", {100, 0.0, 10.0}, "Xi(1530) pT axis (GeV/c)"}; + ConfigurableAxis cfgAxisKaonPt{"cfgAxisKaonPt", {100, 0.0, 5.0}, "external K pT axis (GeV/c)"}; + ConfigurableAxis cfgAxisPIDP{"cfgAxisPIDP", {200, 0.0, 10.0}, "momentum axis for PID QA (GeV/c)"}; + ConfigurableAxis cfgAxisPIDNSigma{"cfgAxisPIDNSigma", {160, -8.0, 8.0}, "n-sigma axis for PID QA"}; + + Configurable fillCandidateQA{"fillCandidateQA", true, "Fill selected Xi* and kaon QA"}; + Configurable fillKinematicQA{"fillKinematicQA", true, "Fill k*-mT and k*-pT QA histograms"}; + Configurable fillCPRQA{"fillCPRQA", true, "Fill K--prompt-pion close-pair QA; no CPR cut is applied"}; + Configurable cprKstarMax{"cprKstarMax", 0.5f, "Maximum k* filled in CPR QA (GeV/c)"}; + ConfigurableAxis cfgAxisCPRDEta{"cfgAxisCPRDEta", {120, -0.3, 0.3}, "Delta-eta axis for CPR QA"}; + ConfigurableAxis cfgAxisCPRDPhiStar{"cfgAxisCPRDPhiStar", {120, -0.3, 0.3}, "Delta-phi* axis for CPR QA"}; + ConfigurableAxis cfgAxisCPRKstar{"cfgAxisCPRKstar", {100, 0.0, 0.5}, "k* axis for CPR QA (GeV/c)"}; + Configurable cprRadiusMinCm{"cprRadiusMinCm", 85.f, "Minimum TPC radius used for phi* averaging (cm)"}; + Configurable cprRadiusMaxCm{"cprRadiusMaxCm", 245.f, "Maximum TPC radius used for phi* averaging (cm)"}; + Configurable cprRadiusStepCm{"cprRadiusStepCm", 20.f, "TPC-radius step used for phi* averaging (cm)"}; + + // --------------------------------------------------------------------------- + // Xi(1530) selection helpers. + // --------------------------------------------------------------------------- + bool passPromptPionPID(uint64_t bits) const + { + const int mode = xiCuts.promptPionPIDMode.value; + const int wp = xiCuts.promptPionPIDWP.value; + + if (mode == 0) { + switch (wp) { + case 0: + return hasTrackBit(bits, redxistark::kPiFirstPID3Sigma); + case 1: + return hasTrackBit(bits, redxistark::kPiFirstPID4Sigma); + case 2: + return hasTrackBit(bits, redxistark::kPiFirstPID5Sigma); + case 3: + return hasTrackBit(bits, redxistark::kPiFirstPID6Sigma); + default: + return false; + } + } + + if (mode == 1) { + switch (wp) { + case 0: + return hasTrackBit(bits, redxistark::kPiFirstPtThresholdPID3Sigma); + case 1: + return hasTrackBit(bits, redxistark::kPiFirstPtThresholdPID4Sigma); + case 2: + return hasTrackBit(bits, redxistark::kPiFirstPtThresholdPID5Sigma); + case 3: + return hasTrackBit(bits, redxistark::kPiFirstPtThresholdPID6Sigma); + default: + return false; + } + } + + switch (wp) { + case 0: + return hasTrackBit(bits, redxistark::kPiFirstTPC3Sigma); + case 1: + return hasTrackBit(bits, redxistark::kPiFirstTPC4Sigma); + case 2: + return hasTrackBit(bits, redxistark::kPiFirstTPC5Sigma); + case 3: + return hasTrackBit(bits, redxistark::kPiFirstTPC6Sigma); + default: + return false; + } + } + + bool passBachelorPionPID(uint64_t bits) const + { + const int mode = xiCuts.bachelorPionPIDMode.value; + const int wp = xiCuts.bachelorPionPIDWP.value; + + if (mode == 0) { + switch (wp) { + case 0: + return hasTrackBit(bits, redxistark::kXiBachelorPiHybridPID3Sigma); + case 1: + return hasTrackBit(bits, redxistark::kXiBachelorPiHybridPID4Sigma); + case 3: + return hasTrackBit(bits, redxistark::kXiBachelorPiHybridPID5Sigma); + case 4: + return hasTrackBit(bits, redxistark::kXiBachelorPiHybridPID6Sigma); + default: + return false; // 4.8 sigma exists only for TPC-only. + } + } + + switch (wp) { + case 0: + return hasTrackBit(bits, redxistark::kXiBachelorPiTPC3Sigma); + case 1: + return hasTrackBit(bits, redxistark::kXiBachelorPiTPC4Sigma); + case 2: + return hasTrackBit(bits, redxistark::kXiBachelorPiTPC4p8Sigma); + case 3: + return hasTrackBit(bits, redxistark::kXiBachelorPiTPC5Sigma); + case 4: + return hasTrackBit(bits, redxistark::kXiBachelorPiTPC6Sigma); + default: + return false; + } + } + + bool passLambdaPionTPCPID(uint64_t bits) const + { + switch (xiCuts.lambdaPionPIDWP.value) { + case 0: + return hasTrackBit(bits, redxistark::kLambdaPiTPC3Sigma); + case 1: + return hasTrackBit(bits, redxistark::kLambdaPiTPC4Sigma); + case 2: + return hasTrackBit(bits, redxistark::kLambdaPiTPC4p8Sigma); + case 3: + return hasTrackBit(bits, redxistark::kLambdaPiTPC5Sigma); + case 4: + return hasTrackBit(bits, redxistark::kLambdaPiTPC6Sigma); + default: + return false; + } + } + + bool passLambdaProtonTPCPID(uint64_t bits) const + { + switch (xiCuts.lambdaProtonPIDWP.value) { + case 0: + return hasTrackBit(bits, redxistark::kLambdaPrTPC3Sigma); + case 1: + return hasTrackBit(bits, redxistark::kLambdaPrTPC4Sigma); + case 2: + return hasTrackBit(bits, redxistark::kLambdaPrTPC5Sigma); + case 3: + return hasTrackBit(bits, redxistark::kLambdaPrTPC6Sigma); + default: + return false; + } + } + + template + bool passXiStarSelection(TXiStar const& candidate) const + { + const uint64_t trackBits = candidate.trackSelectionBits(); + const uint64_t topoBits = candidate.topologySelectionBits(); + + if (!passPromptPionPID(trackBits) || + !passBachelorPionPID(trackBits) || + !passLambdaPionTPCPID(trackBits) || + !passLambdaProtonTPCPID(trackBits)) { + return false; + } + + const std::array promptRowsBits{ + redxistark::kPiFirstTPCRows70, + redxistark::kPiFirstTPCRows80, + redxistark::kPiFirstTPCRows90}; + if (!hasTrackBit(trackBits, promptRowsBits[xiCuts.promptPionRowsWP.value])) { + return false; + } + + const std::array promptDCAzBits{ + redxistark::kPiFirstDCAz1cm, + redxistark::kPiFirstDCAzDefault, + redxistark::kPiFirstDCAz0p1cm}; + if (!hasTrackBit(trackBits, promptDCAzBits[xiCuts.promptPionDCAzWP.value])) { + return false; + } + + const std::array v0RowsBits{ + redxistark::kAllCascDaughtersTPCRows50, + redxistark::kV0DaughtersTPCRows70, + redxistark::kV0DaughtersTPCRowsVar1, + redxistark::kV0DaughtersTPCRowsVar2}; + if (!hasTrackBit(trackBits, v0RowsBits[xiCuts.v0DaughterRowsWP.value])) { + return false; + } + + const std::array pionDcaBits{ + redxistark::kV0PionDcaPV005, + redxistark::kV0PionDcaPV006, + redxistark::kV0PionDcaPV010, + redxistark::kV0PionDcaPV020}; + if (!hasTopoBit(topoBits, pionDcaBits[xiCuts.v0PionDcaPVWP.value])) { + return false; + } + + const std::array protonDcaBits{ + redxistark::kV0ProtonDcaPV005, + redxistark::kV0ProtonDcaPV006, + redxistark::kV0ProtonDcaPV007, + redxistark::kV0ProtonDcaPV010}; + if (!hasTopoBit(topoBits, protonDcaBits[xiCuts.v0ProtonDcaPVWP.value])) { + return false; + } + + const std::array v0DcaPVBits{ + redxistark::kV0DcaPV000, + redxistark::kV0DcaPV003, + redxistark::kV0DcaPV010}; + if (!hasTopoBit(topoBits, v0DcaPVBits[xiCuts.v0DcaPVWP.value])) { + return false; + } + + const std::array v0DaughterDCABits{ + redxistark::kV0DcaDaughters1p0, + redxistark::kV0DcaDaughters0p5, + redxistark::kV0DcaDaughters0p1}; + if (!hasTopoBit(topoBits, v0DaughterDCABits[xiCuts.v0DcaDaughtersWP.value])) { + return false; + } + + const std::array v0CosPABits{ + redxistark::kV0CosPA097, + redxistark::kV0CosPA098, + redxistark::kV0CosPA09876, + redxistark::kV0CosPA099, + redxistark::kV0CosPA0995}; + if (!hasTopoBit(topoBits, v0CosPABits[xiCuts.v0CosPAWP.value])) { + return false; + } + + const std::array v0RadiusBits{ + redxistark::kV0Radius0p9, + redxistark::kV0Radius1p01, + redxistark::kV0Radius1p2, + redxistark::kV0Radius2p5, + redxistark::kV0Radius3p0}; + if (!hasTopoBit(topoBits, v0RadiusBits[xiCuts.v0RadiusWP.value])) { + return false; + } + + const std::array lambdaMassBits{ + redxistark::kLambdaMass10MeV, + redxistark::kLambdaMass8MeV, + redxistark::kLambdaMass6MeV, + redxistark::kLambdaMass11p6MeV}; + if (!hasTopoBit(topoBits, lambdaMassBits[xiCuts.lambdaMassWP.value])) { + return false; + } + + if (xiCuts.applyV0LifetimeCut.value) { + const std::array v0LifetimeBits{ + redxistark::kV0LifetimeDefault, + redxistark::kV0LifetimeVar1, + redxistark::kV0LifetimeVar2}; + if (!hasTopoBit(topoBits, v0LifetimeBits[xiCuts.v0LifetimeWP.value])) { + return false; + } + } + + const std::array bachelorDcaBits{ + redxistark::kCascBachelorDcaPV005, + redxistark::kCascBachelorDcaPV006, + redxistark::kCascBachelorDcaPV010}; + if (!hasTopoBit(topoBits, bachelorDcaBits[xiCuts.cascBachelorDcaPVWP.value])) { + return false; + } + + const std::array cascDaughterDCABits{ + redxistark::kCascDcaDaughters1p0, + redxistark::kCascDcaDaughters0p25, + redxistark::kCascDcaDaughters0p20}; + if (!hasTopoBit(topoBits, cascDaughterDCABits[xiCuts.cascDcaDaughtersWP.value])) { + return false; + } + + const std::array cascCosPABits{ + redxistark::kCascCosPA097, + redxistark::kCascCosPA098, + redxistark::kCascCosPA09947, + redxistark::kCascCosPA0995}; + if (!hasTopoBit(topoBits, cascCosPABits[xiCuts.cascCosPAWP.value])) { + return false; + } + + const std::array cascRadiusBits{ + redxistark::kCascRadius0p9, + redxistark::kCascRadius1p0, + redxistark::kCascRadius1p01, + redxistark::kCascRadius1p3}; + if (!hasTopoBit(topoBits, cascRadiusBits[xiCuts.cascRadiusWP.value])) { + return false; + } + + const std::array xiMassBits{ + redxistark::kXiMass10MeV, + redxistark::kXiMass8MeV, + redxistark::kXiMass6MeV}; + if (!hasTopoBit(topoBits, xiMassBits[xiCuts.xiMassWP.value])) { + return false; + } + + if (xiCuts.applyXiLifetimeCut.value) { + const std::array xiLifetimeBits{ + redxistark::kXiLifetimeDefault, + redxistark::kXiLifetimeVar1, + redxistark::kXiLifetimeVar2}; + if (!hasTopoBit(topoBits, xiLifetimeBits[xiCuts.xiLifetimeWP.value])) { + return false; + } + } + + if (xiCuts.requirePPBachBaryonDCAxy.value && + !hasTopoBit(topoBits, redxistark::kBachBaryonDCAxy0020)) { + return false; + } + if (xiCuts.requirePPXiRapidity.value && + !hasTopoBit(topoBits, redxistark::kXiRapidity05)) { + return false; + } + + return true; + } + + // --------------------------------------------------------------------------- + // Kaon selection helpers. + // IMPORTANT: getter spelling follows the attached data model exactly: + // tPCNClsCrossedRows(), tPCNSigmaKa(), tOFNSigmaKa(). + // --------------------------------------------------------------------------- + bool passKaonDCA(uint8_t bits, int wp, bool xy) const + { + if (xy) { + switch (wp) { + case 0: + return hasKaonBit(bits, redxistarkaon::kKaonDCAxyDefault); + case 1: + return hasKaonBit(bits, redxistarkaon::kKaonDCAxyVar1); + case 2: + return hasKaonBit(bits, redxistarkaon::kKaonDCAxyVar2); + default: + return false; + } + } + + switch (wp) { + case 0: + return hasKaonBit(bits, redxistarkaon::kKaonDCAzDefault); + case 1: + return hasKaonBit(bits, redxistarkaon::kKaonDCAzVar1); + case 2: + return hasKaonBit(bits, redxistarkaon::kKaonDCAzVar2); + default: + return false; + } + } + + template + bool passKaonPID(TKaon const& kaon) const + { + const float tpc = kaon.tPCNSigmaKa(); + if (!std::isfinite(tpc)) { + return false; + } + + if (kaonCuts.pidMode.value == 0) { + return std::abs(tpc) < kaonCuts.tpcNSigmaMax.value; + } + + if (kaonCuts.pidMode.value == 1) { + if (!kaon.hasTOF()) { + return std::abs(tpc) < kaonCuts.tpcNSigmaMax.value; + } + const float tof = kaon.tOFNSigmaKa(); + return std::isfinite(tof) && std::hypot(tpc, tof) < kaonCuts.circularNSigmaMax.value; + } + + // Default: pT-threshold hybrid PID. + if (kaon.pt() < kaonCuts.pidPtThreshold.value) { + return std::abs(tpc) < kaonCuts.tpcNSigmaMax.value; + } + + if (!kaon.hasTOF()) { + if (kaonCuts.requireTOFAboveThreshold.value) { + return false; + } + return std::abs(tpc) < kaonCuts.tpcNSigmaMax.value; + } + + const float tof = kaon.tOFNSigmaKa(); + return std::isfinite(tof) && std::hypot(tpc, tof) < kaonCuts.circularNSigmaMax.value; + } + + template + bool passKaonSelection(TKaon const& kaon) const + { + if (kaon.pt() <= kaonCuts.ptMin.value || kaon.pt() >= kaonCuts.ptMax.value) { + return false; + } + if (kaon.tPCNClsCrossedRows() <= kaonCuts.tpcRowsMin.value) { + return false; + } + if (!passKaonDCA(kaon.selectionBits(), kaonCuts.dcaXYWP.value, true) || + !passKaonDCA(kaon.selectionBits(), kaonCuts.dcaZWP.value, false)) { + return false; + } + return passKaonPID(kaon); + } + + // --------------------------------------------------------------------------- + // Pair helpers. + // --------------------------------------------------------------------------- + template + bool sharesTrack(TXiStar const& xiStar, TKaon const& kaon) const + { + const int64_t kIndex = kaon.trackIndex(); + return kIndex == xiStar.xiStarPionIndex() || + kIndex == xiStar.xiBachelorIndex() || + kIndex == xiStar.v0PositiveIndex() || + kIndex == xiStar.v0NegativeIndex(); + } + + bool passChannelSelection(int8_t channel) const + { + if (channel == 0) { + return false; + } + if (channel > 0 && !pairCuts.fillMatter.value) { + return false; + } + if (channel < 0 && !pairCuts.fillAntimatter.value) { + return false; + } + if (std::abs(static_cast(channel)) == 2 && !pairCuts.fillLikeSignControl.value) { + return false; + } + return true; + } + + bool isRequestedChargeCombination(int8_t channel, int8_t kaonCharge) const + { + // +1/+2 are Xi- based -> K- ; -1/-2 are anti-Xi+ based -> K+. + if (channel > 0) { + return kaonCharge < 0; + } + if (channel < 0) { + return kaonCharge > 0; + } + return false; + } + + int promptPionCharge(int8_t channel) const + { + // +1 = Xi- pi+ US, +2 = Xi- pi- LS, + // -1 = antiXi+ pi- US, -2 = antiXi+ pi+ LS. + if (channel == redxistark::kXiStarUS || channel == redxistark::kAntiXiStarLS) { + return +1; + } + return -1; + } + + template + float getKstar(TXiStar const& xiStar, TKaon const& kaon) const + { + const auto m1 = static_cast(xiStar.mass()); + const auto m2 = static_cast(kKaonMass); + + const auto p1x = static_cast(xiStar.px()); + const auto p1y = static_cast(xiStar.py()); + const auto p1z = static_cast(xiStar.pz()); + const auto p2x = static_cast(kaon.px()); + const auto p2y = static_cast(kaon.py()); + const auto p2z = static_cast(kaon.pz()); + + const double e1 = std::sqrt(p1x * p1x + p1y * p1y + p1z * p1z + m1 * m1); + const double e2 = std::sqrt(p2x * p2x + p2y * p2y + p2z * p2z + m2 * m2); + + const double px = p1x + p2x; + const double py = p1y + p2y; + const double pz = p1z + p2z; + const double e = e1 + e2; + const double s = e * e - px * px - py * py - pz * pz; + + if (!std::isfinite(s) || s <= 0.0) { + return -1.f; + } + + const double mPlus = m1 + m2; + const double mMinus = m1 - m2; + const double lambda = (s - mPlus * mPlus) * (s - mMinus * mMinus); + if (!std::isfinite(lambda) || lambda <= 0.0) { + return -1.f; + } + + const double kstar = std::sqrt(lambda) / (2.0 * std::sqrt(s)); + return std::isfinite(kstar) ? static_cast(kstar) : -1.f; + } + + template + float getPairMt(TXiStar const& xiStar, TKaon const& kaon) const + { + const float pairPx = xiStar.px() + kaon.px(); + const float pairPy = xiStar.py() + kaon.py(); + const float kT = 0.5f * std::hypot(pairPx, pairPy); + const float meanMass = 0.5f * (xiStar.mass() + kKaonMass); + return std::sqrt(kT * kT + meanMass * meanMass); + } + + float phiAtTPCAverage(float pt, float phi, int charge, float bz) const + { + if (pt <= 0.f || !std::isfinite(pt) || !std::isfinite(phi) || !std::isfinite(bz)) { + return phi; + } + + float sum = 0.f; + int n = 0; + + const auto nRadiusSteps = static_cast( + (cprRadiusMaxCm.value - cprRadiusMinCm.value) / cprRadiusStepCm.value + 0.5f); + + for (int iRadius = 0; iRadius <= nRadiusSteps; ++iRadius) { + const auto radiusCm = cprRadiusMinCm.value + + static_cast(iRadius) * cprRadiusStepCm.value; + + const float arg = 0.3f * static_cast(charge) * bz * radiusCm * 0.01f / (2.f * pt); + if (std::abs(arg) < 1.f) { + sum += phi - std::asin(arg); + ++n; + } + } + return n > 0 ? sum / static_cast(n) : phi; + } + + template + void fillCPR(bool mixed, + TXiStar const& xiStar, + TKaon const& kaon, + float kstar, + float bzXiEvent, + float bzKaonEvent) + { + if (!fillCPRQA.value || kstar < 0.f || kstar >= cprKstarMax.value) { + return; + } + + const int pionCharge = promptPionCharge(xiStar.channel()); + const float pionPhiTPC = phiAtTPCAverage(xiStar.xiStarPionPt(), xiStar.xiStarPionPhi(), pionCharge, bzXiEvent); + const float kaonPhiTPC = phiAtTPCAverage(kaon.pt(), kaon.phi(), kaon.charge(), bzKaonEvent); + + const float dEta = kaon.eta() - xiStar.xiStarPionEta(); + const float dPhiStar = wrapToPi(kaonPhiTPC - pionPhiTPC); + + if (mixed) { + histos.fill(HIST("hCPRME"), dEta, dPhiStar, kstar, static_cast(xiStar.channel())); + } else { + histos.fill(HIST("hCPRSE"), dEta, dPhiStar, kstar, static_cast(xiStar.channel())); + } + } + + // --------------------------------------------------------------------------- + // Histogram filling helpers. + // --------------------------------------------------------------------------- + template + void fillSameEventPair(TCollision const& collision, TXiStar const& xiStar, TKaon const& kaon) + { + histos.fill(HIST("hPairCounterSE"), 1.f); + + if (!passChannelSelection(xiStar.channel()) || + !isRequestedChargeCombination(xiStar.channel(), kaon.charge())) { + return; + } + histos.fill(HIST("hPairCounterSE"), 2.f); + + if (pairCuts.applySharedTrackCleaning.value && sharesTrack(xiStar, kaon)) { + return; + } + histos.fill(HIST("hPairCounterSE"), 3.f); + + const float kstar = getKstar(xiStar, kaon); + if (kstar < 0.f) { + histos.fill(HIST("hInvalidKstar"), 0.f); + return; + } + histos.fill(HIST("hPairCounterSE"), 4.f); + + const auto channel = static_cast(xiStar.channel()); + const float mt = getPairMt(xiStar, kaon); + + // Getter spelling is fT0MPercentile(), exactly as declared in the data model. + histos.fill(HIST("SEPairs"), kstar, xiStar.mass(), xiStar.pt(), collision.fT0MPercentile(), channel); + histos.fill(HIST("hSEKstarVsChannel"), kstar, channel); + if (fillKinematicQA.value) { + histos.fill(HIST("hSEKstarVsMtVsChannel"), kstar, mt, channel); + histos.fill(HIST("hSEKstarVsXiPtVsChannel"), kstar, xiStar.pt(), channel); + histos.fill(HIST("hSEKstarVsKaonPtVsChannel"), kstar, kaon.pt(), channel); + } + + if (xiStar.channel() == redxistark::kXiStarUS) { + histos.fill(HIST("hSEKstarXiStarKminus"), kstar); + } else if (xiStar.channel() == redxistark::kAntiXiStarUS) { + histos.fill(HIST("hSEKstarAntiXiStarKplus"), kstar); + } + + fillCPR(false, xiStar, kaon, kstar, collision.bz(), collision.bz()); + } + + template + void fillMixedEventPair(TCollision1 const& collision1, + TCollision2 const& collision2, + TXiStar const& xiStar, + TKaon const& kaon) + { + histos.fill(HIST("hPairCounterME"), 1.f); + + if (!passChannelSelection(xiStar.channel()) || + !isRequestedChargeCombination(xiStar.channel(), kaon.charge())) { + return; + } + histos.fill(HIST("hPairCounterME"), 2.f); + + const float kstar = getKstar(xiStar, kaon); + if (kstar < 0.f) { + histos.fill(HIST("hInvalidKstar"), 1.f); + return; + } + histos.fill(HIST("hPairCounterME"), 3.f); + + const auto channel = static_cast(xiStar.channel()); + const float mt = getPairMt(xiStar, kaon); + + histos.fill(HIST("MEPairs"), kstar, xiStar.mass(), xiStar.pt(), collision1.fT0MPercentile(), channel); + histos.fill(HIST("hMEKstarVsChannel"), kstar, channel); + if (fillKinematicQA.value) { + histos.fill(HIST("hMEKstarVsMtVsChannel"), kstar, mt, channel); + } + + if (xiStar.channel() == redxistark::kXiStarUS) { + histos.fill(HIST("hMEKstarXiStarKminus"), kstar); + } else if (xiStar.channel() == redxistark::kAntiXiStarUS) { + histos.fill(HIST("hMEKstarAntiXiStarKplus"), kstar); + } + + fillCPR(true, xiStar, kaon, kstar, collision1.bz(), collision2.bz()); + } + + // --------------------------------------------------------------------------- + // Initialization. + // --------------------------------------------------------------------------- + void init(InitContext const&) + { + auto inRange = [](int value, int lo, int hi) { return value >= lo && value <= hi; }; + + if (!inRange(xiCuts.promptPionPIDMode.value, 0, 2) || + !inRange(xiCuts.bachelorPionPIDMode.value, 0, 1) || + !inRange(xiCuts.promptPionPIDWP.value, 0, 3) || + !inRange(xiCuts.bachelorPionPIDWP.value, 0, 4) || + !inRange(xiCuts.lambdaPionPIDWP.value, 0, 4) || + !inRange(xiCuts.lambdaProtonPIDWP.value, 0, 3)) { + LOGF(fatal, "Invalid Xi(1530) daughter PID mode/working point"); + } + if (xiCuts.bachelorPionPIDMode.value == 0 && xiCuts.bachelorPionPIDWP.value == 2) { + LOGF(fatal, "Xi-bachelor 4.8-sigma PID working point is available only in TPC-only mode"); + } + + if (!inRange(xiCuts.promptPionRowsWP.value, 0, 2) || + !inRange(xiCuts.promptPionDCAzWP.value, 0, 2) || + !inRange(xiCuts.v0DaughterRowsWP.value, 0, 3) || + !inRange(xiCuts.v0PionDcaPVWP.value, 0, 3) || + !inRange(xiCuts.v0ProtonDcaPVWP.value, 0, 3) || + !inRange(xiCuts.v0DcaPVWP.value, 0, 2) || + !inRange(xiCuts.v0DcaDaughtersWP.value, 0, 2) || + !inRange(xiCuts.v0CosPAWP.value, 0, 4) || + !inRange(xiCuts.v0RadiusWP.value, 0, 4) || + !inRange(xiCuts.lambdaMassWP.value, 0, 3) || + !inRange(xiCuts.v0LifetimeWP.value, 0, 2) || + !inRange(xiCuts.cascBachelorDcaPVWP.value, 0, 2) || + !inRange(xiCuts.cascDcaDaughtersWP.value, 0, 2) || + !inRange(xiCuts.cascCosPAWP.value, 0, 3) || + !inRange(xiCuts.cascRadiusWP.value, 0, 3) || + !inRange(xiCuts.xiMassWP.value, 0, 2) || + !inRange(xiCuts.xiLifetimeWP.value, 0, 2)) { + LOGF(fatal, "Invalid Xi(1530) topology/quality working-point index"); + } + + if (!inRange(kaonCuts.dcaXYWP.value, 0, 2) || + !inRange(kaonCuts.dcaZWP.value, 0, 2) || + !inRange(kaonCuts.pidMode.value, 0, 2)) { + LOGF(fatal, "Kaon DCA working points and PID mode must be 0, 1 or 2"); + } + if (kaonCuts.pidPtThreshold.value < 0.f || + kaonCuts.tpcNSigmaMax.value <= 0.f || + kaonCuts.circularNSigmaMax.value <= 0.f) { + LOGF(fatal, "Invalid kaon PID configuration"); + } + if (nEvtMixing.value < 1) { + LOGF(fatal, "nEvtMixing must be >= 1"); + } + if (cprRadiusStepCm.value <= 0.f || cprRadiusMaxCm.value < cprRadiusMinCm.value || + cprKstarMax.value <= 0.f) { + LOGF(fatal, "Invalid CPR configuration"); + } + + const AxisSpec axisKstar{cfgAxisKstar, "#it{k}^{*} (GeV/#it{c})"}; + const AxisSpec axisMass{cfgAxisMass, "#it{M}_{#Xi#pi} (GeV/#it{c}^{2})"}; + const AxisSpec axisFT0M{cfgMixFT0MBins, "FT0M percentile (%)"}; + const AxisSpec axisChannel{5, -2.5, 2.5, "#Xi#pi channel"}; + const AxisSpec axisMt{cfgAxisMt, "#it{m}_{T} (GeV/#it{c}^{2})"}; + const AxisSpec axisXiPt{cfgAxisXiPt, "#it{p}_{T}^{#Xi^{*}} (GeV/#it{c})"}; + const AxisSpec axisKaonPt{cfgAxisKaonPt, "#it{p}_{T}^{K} (GeV/#it{c})"}; + const AxisSpec axisPIDP{cfgAxisPIDP, "#it{p} (GeV/#it{c})"}; + const AxisSpec axisPIDNSigma{cfgAxisPIDNSigma, "n#sigma"}; + + histos.add("hEventCounterSE", "SE event flow;;events", HistType::kTH1F, {{4, 0.5, 4.5}}); + auto hEventSE = histos.get(HIST("hEventCounterSE")); + hEventSE->GetXaxis()->SetBinLabel(1, "reduced event"); + hEventSE->GetXaxis()->SetBinLabel(2, "selected XiPi"); + hEventSE->GetXaxis()->SetBinLabel(3, "selected K"); + hEventSE->GetXaxis()->SetBinLabel(4, "XiPi and K"); + + histos.add("hPairCounterSE", "SE pair flow;;pairs", HistType::kTH1F, {{4, 0.5, 4.5}}); + auto hPairSE = histos.get(HIST("hPairCounterSE")); + hPairSE->GetXaxis()->SetBinLabel(1, "selected XiPi x K"); + hPairSE->GetXaxis()->SetBinLabel(2, "charge matched"); + hPairSE->GetXaxis()->SetBinLabel(3, "pair cleaned"); + hPairSE->GetXaxis()->SetBinLabel(4, "valid kstar"); + + histos.add("hEventCounterME", "ME event-pair flow;;event pairs", HistType::kTH1F, {{2, 0.5, 2.5}}); + auto hEventME = histos.get(HIST("hEventCounterME")); + hEventME->GetXaxis()->SetBinLabel(1, "mixed event pair"); + hEventME->GetXaxis()->SetBinLabel(2, "nonempty selected groups"); + + histos.add("hPairCounterME", "ME pair flow;;pairs", HistType::kTH1F, {{3, 0.5, 3.5}}); + auto hPairME = histos.get(HIST("hPairCounterME")); + hPairME->GetXaxis()->SetBinLabel(1, "selected XiPi x K"); + hPairME->GetXaxis()->SetBinLabel(2, "charge matched"); + hPairME->GetXaxis()->SetBinLabel(3, "valid kstar"); + + histos.add("hInvalidKstar", "Invalid k*;sample;counts", HistType::kTH1F, {{2, -0.5, 1.5}}); + auto hInvalid = histos.get(HIST("hInvalidKstar")); + hInvalid->GetXaxis()->SetBinLabel(1, "SE"); + hInvalid->GetXaxis()->SetBinLabel(2, "ME"); + + histos.add("hSelectedXiStarMassVsChannel", "Selected #Xi#pi candidates;#it{M}_{#Xi#pi} (GeV/#it{c}^{2});channel", HistType::kTH2F, {axisMass, axisChannel}); + histos.add("hSelectedKaonTPCnSigmaVsP", "Selected external K;#it{p} (GeV/#it{c});n#sigma_{TPC}^{K}", HistType::kTH2F, {axisPIDP, axisPIDNSigma}); + histos.add("hSelectedKaonTOFnSigmaVsP", "Selected external K with TOF;#it{p} (GeV/#it{c});n#sigma_{TOF}^{K}", HistType::kTH2F, {axisPIDP, axisPIDNSigma}); + + histos.add("SEPairs", "SE Xi(1530)-K candidates", HistType::kTHnSparseF, {axisKstar, axisMass, axisXiPt, axisFT0M, axisChannel}); + histos.add("MEPairs", "ME Xi(1530)-K candidates", HistType::kTHnSparseF, {axisKstar, axisMass, axisXiPt, axisFT0M, axisChannel}); + + histos.add("hSEKstarVsChannel", "SE;#it{k}^{*} (GeV/#it{c});channel", HistType::kTH2F, {axisKstar, axisChannel}); + histos.add("hMEKstarVsChannel", "ME;#it{k}^{*} (GeV/#it{c});channel", HistType::kTH2F, {axisKstar, axisChannel}); + + histos.add("hSEKstarXiStarKminus", "SE #Xi^{*0}K^{-};#it{k}^{*} (GeV/#it{c});pairs", HistType::kTH1F, {axisKstar}); + histos.add("hSEKstarAntiXiStarKplus", "SE #bar{#Xi}^{*0}K^{+};#it{k}^{*} (GeV/#it{c});pairs", HistType::kTH1F, {axisKstar}); + histos.add("hMEKstarXiStarKminus", "ME #Xi^{*0}K^{-};#it{k}^{*} (GeV/#it{c});pairs", HistType::kTH1F, {axisKstar}); + histos.add("hMEKstarAntiXiStarKplus", "ME #bar{#Xi}^{*0}K^{+};#it{k}^{*} (GeV/#it{c});pairs", HistType::kTH1F, {axisKstar}); + + histos.add("hSEKstarVsMtVsChannel", "SE pair kinematics;#it{k}^{*};#it{m}_{T};channel", HistType::kTH3F, {axisKstar, axisMt, axisChannel}); + histos.add("hMEKstarVsMtVsChannel", "ME pair kinematics;#it{k}^{*};#it{m}_{T};channel", HistType::kTH3F, {axisKstar, axisMt, axisChannel}); + histos.add("hSEKstarVsXiPtVsChannel", "SE pair kinematics;#it{k}^{*};#it{p}_{T}^{#Xi^{*}};channel", HistType::kTH3F, {axisKstar, axisXiPt, axisChannel}); + histos.add("hSEKstarVsKaonPtVsChannel", "SE pair kinematics;#it{k}^{*};#it{p}_{T}^{K};channel", HistType::kTH3F, {axisKstar, axisKaonPt, axisChannel}); + + const AxisSpec axisDEta{cfgAxisCPRDEta, "#Delta#eta(K,#pi_{#Xi^{*}})"}; + const AxisSpec axisDPhiStar{cfgAxisCPRDPhiStar, "#Delta#varphi^{*}(K,#pi_{#Xi^{*}})"}; + const AxisSpec axisCPRKstar{cfgAxisCPRKstar, "#it{k}^{*} (GeV/#it{c})"}; + histos.add("hCPRSE", "SE close-pair QA", HistType::kTHnSparseF, {axisDEta, axisDPhiStar, axisCPRKstar, axisChannel}); + histos.add("hCPRME", "ME close-pair QA", HistType::kTHnSparseF, {axisDEta, axisDPhiStar, axisCPRKstar, axisChannel}); + } + + // --------------------------------------------------------------------------- + // Same-event numerator. + // The framework groups the two daughter tables by RedXiStarKEventId for the + // current reduced-event iterator. + // --------------------------------------------------------------------------- + void processSameEvent(aod::RedXiStarKEvents::iterator const& collision, + aod::XiStarCandidates const& xiStars, + aod::KaonCandidates const& kaons) + { + histos.fill(HIST("hEventCounterSE"), 1.f); + + bool hasSelectedXi = false; + for (auto const& xiStar : xiStars) { + if (!passXiStarSelection(xiStar) || !passChannelSelection(xiStar.channel())) { + continue; + } + hasSelectedXi = true; + if (fillCandidateQA.value) { + histos.fill(HIST("hSelectedXiStarMassVsChannel"), xiStar.mass(), static_cast(xiStar.channel())); + } + } + if (hasSelectedXi) { + histos.fill(HIST("hEventCounterSE"), 2.f); + } + + bool hasSelectedK = false; + for (auto const& kaon : kaons) { + if (!passKaonSelection(kaon)) { + continue; + } + hasSelectedK = true; + if (fillCandidateQA.value) { + histos.fill(HIST("hSelectedKaonTPCnSigmaVsP"), kaon.p(), kaon.tPCNSigmaKa()); + if (kaon.hasTOF()) { + histos.fill(HIST("hSelectedKaonTOFnSigmaVsP"), kaon.p(), kaon.tOFNSigmaKa()); + } + } + } + if (hasSelectedK) { + histos.fill(HIST("hEventCounterSE"), 3.f); + } + if (!(hasSelectedXi && hasSelectedK)) { + return; + } + histos.fill(HIST("hEventCounterSE"), 4.f); + + for (auto const& xiStar : xiStars) { + if (!passXiStarSelection(xiStar) || !passChannelSelection(xiStar.channel())) { + continue; + } + for (auto const& kaon : kaons) { + if (!passKaonSelection(kaon)) { + continue; + } + fillSameEventPair(collision, xiStar, kaon); + } + } + } + PROCESS_SWITCH(xi1530kaoncorrelation, processSameEvent, "Process same-event Xi(1530)-K pairs", true); + + // --------------------------------------------------------------------------- + // Mixed-event denominator. + // Xi*(event A) is paired with K(event B) using z-vertex, FT0M percentile and + // Bz mixing bins. No cross-event shared-track cleaning is applied for now. + // --------------------------------------------------------------------------- + void processMixedEvent(aod::RedXiStarKEvents const& collisions, + aod::XiStarCandidates const& xiStars, + aod::KaonCandidates const& kaons) + + { + for (auto const& [collision1, collision2] : selfCombinations(mixingBinning, nEvtMixing, -1, collisions, collisions)) { + if (collision1.globalIndex() == collision2.globalIndex()) { + continue; + } + histos.fill(HIST("hEventCounterME"), 1.f); + + auto groupXi = xiStars.sliceBy(xiStarsPerEvent, collision1.globalIndex()); + auto groupK = kaons.sliceBy(kaonsPerEvent, collision2.globalIndex()); + + bool hasSelectedXi = false; + for (auto const& xiStar : groupXi) { + if (passXiStarSelection(xiStar) && passChannelSelection(xiStar.channel())) { + hasSelectedXi = true; + break; + } + } + + bool hasSelectedK = false; + for (auto const& kaon : groupK) { + if (passKaonSelection(kaon)) { + hasSelectedK = true; + break; + } + } + + if (!(hasSelectedXi && hasSelectedK)) { + continue; + } + histos.fill(HIST("hEventCounterME"), 2.f); + + for (auto const& xiStar : groupXi) { + if (!passXiStarSelection(xiStar) || !passChannelSelection(xiStar.channel())) { + continue; + } + for (auto const& kaon : groupK) { + if (!passKaonSelection(kaon)) { + continue; + } + fillMixedEventPair(collision1, collision2, xiStar, kaon); + } + } + } + } + PROCESS_SWITCH(xi1530kaoncorrelation, processMixedEvent, "Process mixed-event Xi(1530)-K pairs", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{adaptAnalysisTask(cfgc)}; +} diff --git a/PWGLF/Tasks/Resonances/xi1820Analysis.cxx b/PWGLF/Tasks/Resonances/xi1820Analysis.cxx index 9ed500e286c..12b89e89024 100644 --- a/PWGLF/Tasks/Resonances/xi1820Analysis.cxx +++ b/PWGLF/Tasks/Resonances/xi1820Analysis.cxx @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -38,8 +39,18 @@ #include #include +#include +#include +#include + +#include +#include #include #include +#include +#include +#include +#include #include using namespace o2; @@ -50,12 +61,45 @@ using namespace o2::constants::physics; using LorentzVectorSetXYZM = ROOT::Math::LorentzVector>; struct Xi1820Analysis { + // Module-initializer tables; full tracks and V0s retain their schema. + using ResoCollisions = aod::ResoCollisions_001; + // Original track IDs are used as numbers; no parent AO2D dereference is needed. + using ResoTracks = soa::Join; + using ResoMicroTracks = aod::ResoMicroTracks_001; + using ResoMCCols = soa::Join; + SliceCache cache; Preslice perResoCollisionV0 = aod::resodaughter::resoCollisionId; Preslice perResoCollisionTrack = aod::resodaughter::resoCollisionId; - Preslice perResoCollisionMicroTrack = aod::resodaughter::resoCollisionId; + Preslice perResoCollisionMicroTrack = aod::resodaughter::resoCollisionId; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - using ResoMCCols = soa::Join; + + struct MixingCollision { + float x, y, z, centrality; + bool recINELgt0; + [[nodiscard]] float posX() const { return x; } + [[nodiscard]] float posY() const { return y; } + [[nodiscard]] float posZ() const { return z; } + [[nodiscard]] float cent() const { return centrality; } + }; + struct MixingEvent { + MixingCollision collision{}; + std::shared_ptr daughters; + }; + std::map> mixingPools; + float mixingBField = 0.f; + std::map> neutralMixingPools; + float neutralMixingBField = 0.f; + + template + struct SelectedLambda { + Iterator candidate; + bool isLambda = false, isAntiLambda = false; + }; + + Configurable cfgFillQA{"cfgFillQA", true, "Fill reconstructed daughter QA"}; + Configurable cfgFillEventQA{"cfgFillEventQA", true, "Fill event and rotation QA"}; + Configurable cfgFillTruthQA{"cfgFillTruthQA", true, "Fill MC truth-matched daughter QA"}; // Constants static constexpr float SmallMomentumDenominator = 1e-10f; // Small value to avoid division by zero @@ -86,13 +130,19 @@ struct Xi1820Analysis { Configurable cKaonITSNClusMin{"cKaonITSNClusMin", 2, "Minimum ITS clusters for kaon"}; // Kaon PID selections + Configurable cKaonTPCNSigmaMin{"cKaonTPCNSigmaMin", -3.5f, "Strict lower TPC (nSigma - mean) bound for kaons"}; + Configurable cKaonTPCNSigmaMean{"cKaonTPCNSigmaMean", 0.f, "TPC nSigma mean subtracted for kaons"}; Configurable cKaonTPCNSigmaMax{"cKaonTPCNSigmaMax", 3.5, "Maximum TPC NSigma for kaon (if not using pT-dependent)"}; + Configurable cKaonTOFNSigmaMin{"cKaonTOFNSigmaMin", -999.f, "Strict lower TOF (nSigma - mean) bound for kaons"}; + Configurable cKaonTOFNSigmaMean{"cKaonTOFNSigmaMean", 0.f, "TOF nSigma mean subtracted for kaons"}; + Configurable cKaonBypassTOF{"cKaonBypassTOF", false, "Bypass TOF PID even when TOF information is present"}; Configurable cKaonTOFNSigmaMax{"cKaonTOFNSigmaMax", 999., "Maximum TOF NSigma for kaon (if not using pT-dependent)"}; Configurable cKaonUsePtDepPID{"cKaonUsePtDepPID", false, "Use pT-dependent PID cuts"}; Configurable> cKaonPIDPtBins{"cKaonPIDPtBins", {0.0f, 0.5f, 0.8f, 2.0f, 999.0f}, "pT bin edges for PID cuts (N+1 values for N bins)"}; Configurable> cKaonTPCNSigmaCuts{"cKaonTPCNSigmaCuts", {3.0f, 3.0f, 2.0f, 2.0f}, "TPC NSigma cuts per pT bin (N values)"}; Configurable> cKaonTOFNSigmaCuts{"cKaonTOFNSigmaCuts", {3.0f, 3.0f, 3.0f, 3.0f}, "TOF NSigma cuts per pT bin (N values)"}; - Configurable> cKaonTOFRequired{"cKaonTOFRequired", {0, 0, 0, 0}, "Require TOF per pT bin (N values, 0=false, 1=true)"}; + Configurable> cKaonTPCNSigmaMinCuts{"cKaonTPCNSigmaMinCuts", {-3.f, -3.f, -2.f, -2.f}, "Strict lower centered TPC bounds per pT bin"}; + Configurable> cKaonTOFNSigmaMinCuts{"cKaonTOFNSigmaMinCuts", {-3.f, -3.f, -3.f, -3.f}, "Strict lower centered TOF bounds per pT bin"}; // V0 (Lambda) selections Configurable cV0MinCosPA{"cV0MinCosPA", 0.995, "V0 minimum pointing angle cosine"}; @@ -103,10 +153,14 @@ struct Xi1820Analysis { Configurable cV0RadiusMax{"cV0RadiusMax", 200.0, "V0 decay radius max"}; Configurable cV0DauPosDCAtoPVMin{"cV0DauPosDCAtoPVMin", 0.05, "V0 positive daughter DCA to PV min"}; Configurable cV0DauNegDCAtoPVMin{"cV0DauNegDCAtoPVMin", 0.05, "V0 negative daughter DCA to PV min"}; - Configurable cV0ProperLifetimeMax{"cV0ProperLifetimeMax", 30.0, "Lambda proper lifetime max (cm/c)"}; + Configurable cV0ProperLifetimeMax{"cV0ProperLifetimeMax", 30.0, "Lambda proper lifetime max (cm)"}; Configurable cV0sCrossMassRejection{"cV0sCrossMassRejection", true, "Enable K0s mass rejection for Lambda"}; Configurable cV0sCrossMassRejectionWindow{"cV0sCrossMassRejectionWindow", 0.005, "K0s mass rejection window for Lambda (GeV/c^2)"}; + Configurable cLambdaDaughterPiTPCNSigmaMin{"cLambdaDaughterPiTPCNSigmaMin", -5.f, "Strict lower centered TPC PID bound"}; + Configurable cLambdaDaughterPiTPCNSigmaMean{"cLambdaDaughterPiTPCNSigmaMean", 0.f, "TPC nSigma mean subtracted for the V0 daughter"}; Configurable cLambdaDaughterPiTPCNSigmaMax{"cLambdaDaughterPiTPCNSigmaMax", 5.0, "Maximum TPC NSigma for Lambda daughter pions"}; + Configurable cLambdaDaughterPrTPCNSigmaMin{"cLambdaDaughterPrTPCNSigmaMin", -5.f, "Strict lower centered TPC PID bound"}; + Configurable cLambdaDaughterPrTPCNSigmaMean{"cLambdaDaughterPrTPCNSigmaMean", 0.f, "TPC nSigma mean subtracted for the V0 daughter"}; Configurable cLambdaDaughterPrTPCNSigmaMax{"cLambdaDaughterPrTPCNSigmaMax", 5.0, "Maximum TPC NSigma for Lambda daughter protons"}; Configurable cLambdaPosDaughterMinCrossedRows{"cLambdaPosDaughterMinCrossedRows", 50, "Minimum TPC crossed rows for Lambda positive daughter"}; Configurable cLambdaNegDaughterMinCrossedRows{"cLambdaNegDaughterMinCrossedRows", 50, "Minimum TPC crossed rows for Lambda negative daughter"}; @@ -115,7 +169,7 @@ struct Xi1820Analysis { Configurable cK0sMinCosPA{"cK0sMinCosPA", 0.98, "K0s minimum pointing angle cosine"}; Configurable cK0sMaxDaughDCA{"cK0sMaxDaughDCA", 0.5, "K0s daughter DCA Maximum"}; Configurable cK0sMassWindow{"cK0sMassWindow", 0.025, "Mass window for K0s selection (GeV/c^2)"}; - Configurable cK0sProperLifetimeMax{"cK0sProperLifetimeMax", 20.0, "K0s proper lifetime max (cm/c)"}; + Configurable cK0sProperLifetimeMax{"cK0sProperLifetimeMax", 20.0, "K0s proper lifetime max (cm)"}; Configurable cK0sArmenterosQtMin{"cK0sArmenterosQtMin", 0.0, "K0s Armenteros qt min"}; Configurable cK0sArmenterosAlphaCoeff{"cK0sArmenterosAlphaCoeff", 0.2, "K0s Armenteros alpha max"}; Configurable cK0sDauPosDCAtoPVMin{"cK0sDauPosDCAtoPVMin", 0.05, "K0s positive daughter DCA to PV min"}; @@ -124,6 +178,8 @@ struct Xi1820Analysis { Configurable cK0sRadiusMax{"cK0sRadiusMax", 200.0, "K0s decay radius max"}; Configurable cK0sCrossMassRejection{"cK0sCrossMassRejection", true, "Enable Lambda mass rejection for K0s"}; Configurable cK0sCrossMassRejectionWindow{"cK0sCrossMassRejectionWindow", 0.01, "Lambda mass rejection window for K0s (GeV/c^2)"}; + Configurable cK0sDaughterPiTPCNSigmaMin{"cK0sDaughterPiTPCNSigmaMin", -5.f, "Strict lower centered TPC PID bound"}; + Configurable cK0sDaughterPiTPCNSigmaMean{"cK0sDaughterPiTPCNSigmaMean", 0.f, "TPC nSigma mean subtracted for the V0 daughter"}; Configurable cK0sDaughterPiTPCNSigmaMax{"cK0sDaughterPiTPCNSigmaMax", 5.0, "Maximum TPC NSigma for K0s daughter pions"}; Configurable cK0sPosDaughterMinCrossedRows{"cK0sPosDaughterMinCrossedRows", 50, "Minimum TPC crossed rows for K0s positive daughter"}; Configurable cK0sNegDaughterMinCrossedRows{"cK0sNegDaughterMinCrossedRows", 50, "Minimum TPC crossed rows for K0s negative daughter"}; @@ -135,14 +191,15 @@ struct Xi1820Analysis { // Additional QA and configurations struct : ConfigurableGroup { - Configurable cRecoINELgt0{"cRecoINELgt0", false, "Apply Reco INEL>0 event selection"}; - Configurable cConsiderPairOnly{"cConsiderPairOnly", true, "Consider only the pair of tracks for the charged K + Lambda analysis"}; - Configurable cConsiderHasV0s{"cConsiderHasV0s", true, "Consider only the pair of tracks for the K0s + Lambda analysis"}; + Configurable cRecoINELgt0{"cRecoINELgt0", true, "Apply Reco INEL>0 event selection"}; + Configurable cMCINELgt0{"cMCINELgt0", true, "Require generator INEL>0 in reconstructed MC and generated-parent processes"}; + Configurable cMCVtxIn10{"cMCVtxIn10", true, "Require generator |vertex z| < 10 cm using isVtxIn10 in reconstructed MC and generated-parent processes"}; Configurable cUseTruthRapidity{"cUseTruthRapidity", false, "Use truth rapidity for MC generated target"}; Configurable cUsePtDepDCAForKaons{"cUsePtDepDCAForKaons", true, "Use pT dependent DCA cuts for kaon tracks"}; Configurable cDCAToPVByPtFirstP0{"cDCAToPVByPtFirstP0", 0.004, "pT dependent DCA cut first parameter (cm)"}; - Configurable cDCAToPVByPtFirstExp{"cDCAToPVByPtFirstExp", 0.013, "pT dependent DCA cut second parameter (exponent)"}; + Configurable cDCAToPVByPtFirstExp{"cDCAToPVByPtFirstExp", 0.013, "Coefficient in kaon DCA cut = P0 + coefficient / pT^power (legacy key)"}; + Configurable cDCAToPVByPtFirstPower{"cDCAToPVByPtFirstPower", 1.f, "Power in kaon DCA cut = P0 + coefficient / pT^power"}; Configurable cMaxDcaToPVV0Lambda{"cMaxDcaToPVV0Lambda", 1.0, "Maximum DCA to PV for Lambda candidates (cm)"}; Configurable cMaxDcaToPVV0K0s{"cMaxDcaToPVV0K0s", 1.0, "Maximum DCA to PV for K0s candidates (cm)"}; @@ -165,6 +222,13 @@ struct Xi1820Analysis { void init(InitContext&) { + const int sameEventModes = static_cast(doprocessDataWithTracks) + static_cast(doprocessDataWithMicroTracks) + + static_cast(doprocessMCWithTracks) + static_cast(doprocessMCWithMicroTracks); + const int mixedEventModes = static_cast(doprocessMixedEventWithTracks) + static_cast(doprocessMixedEventWithMicroTracks) + static_cast(doprocessMEDF); + if (sameEventModes > 1 || mixedEventModes > 1 || (doprocessK0sLambda && doprocessMCK0sLambda) || + (doprocessK0sLambdaMixedEvent && doprocessK0sLambdaMEDF)) { + LOG(fatal) << "Enable at most one same-event mode and one mixing mode per charged/neutral channel"; + } AxisSpec centAxis = {binsCent, "V0M (%)"}; AxisSpec ptAxis = {binsPt, "#it{p}_{T} (GeV/#it{c})"}; AxisSpec ptAxisQA = {binsPtQA, "#it{p}_{T} (GeV/#it{c})"}; @@ -175,7 +239,7 @@ struct Xi1820Analysis { AxisSpec dcazAxis = {400, -0.2, 0.2, "DCA_{z} (cm)"}; AxisSpec cosPAAxis = {1000, 0.95, 1.0, "cos(PA)"}; AxisSpec radiusAxis = {200, 0, 200, "Radius (cm)"}; - AxisSpec lifetimeAxis = {200, 0, 50, "Proper lifetime (cm/c)"}; + AxisSpec lifetimeAxis = {200, 0, 50, "Proper lifetime (cm)"}; AxisSpec nsigmaAxis = {100, -5.0, 5.0, "N#sigma"}; AxisSpec armenterosAlphaAxis = {200, -1.0, 1.0, "Armenteros alpha"}; AxisSpec armenterosQtAxis = {500, 0.0, 0.5, "Armenteros qt (GeV/c)"}; @@ -183,16 +247,39 @@ struct Xi1820Analysis { AxisSpec axisDel = {400, -0.5, 7.0, "#DeltaR"}; // Event QA histograms - histos.add("Event/posZ", "Event vertex Z position", kTH1F, {{200, -20., 20., "V_{z} (cm)"}}); - histos.add("Event/centrality", "Event centrality distribution", kTH1D, {centAxis}); - histos.add("Event/posZvsCent", "Vertex Z vs Centrality", kTH2F, {{200, -20., 20., "V_{z} (cm)"}, centAxis}); - histos.add("Event/nV0s", "Number of V0s per event", kTH1F, {{200, 0., 200., "N_{V0s}"}}); - histos.add("Event/nKaons", "Number of kaons per event", kTH1F, {{200, 0., 200., "N_{kaon}"}}); - histos.add("Event/nLambdasAfterCuts", "Number of Lambdas per event after cuts", kTH1F, {{100, 0., 100., "N_{Lambda}"}}); - histos.add("Event/nKaonsAfterCuts", "Number of kaons (or K0s) per event after cuts", kTH1F, {{100, 0., 100., "N_{Kaon}"}}); - histos.add("Event/hRotBkg", "Rotated angle of rotated background", HistType::kTH1F, {axisRot}); - - if (doprocessDataWithTracks || doprocessDataWithMicroTracks || doprocessMCWithTracks || doprocessK0sLambda || doprocessMCK0sLambda) { + if (cfgFillEventQA) { + histos.add("Event/posZ", "Event vertex Z position", kTH1F, {{200, -20., 20., "V_{z} (cm)"}}); + histos.add("Event/centrality", "Event centrality distribution", kTH1D, {centAxis}); + histos.add("Event/posZvsCent", "Vertex Z vs Centrality", kTH2F, {{200, -20., 20., "V_{z} (cm)"}, centAxis}); + histos.add("Event/nV0s", "Number of V0s per event", kTH1F, {{200, 0., 200., "N_{V0s}"}}); + histos.add("Event/nKaons", "Number of kaons per event", kTH1F, {{200, 0., 200., "N_{kaon}"}}); + histos.add("Event/nLambdasAfterCuts", "Number of Lambdas per event after cuts", kTH1F, {{100, 0., 100., "N_{Lambda}"}}); + histos.add("Event/nKaonsAfterCuts", "Number of charged kaons per event after cuts", kTH1F, {{100, 0., 100., "N_{Kaon}"}}); + if (doprocessK0sLambda || doprocessMCK0sLambda) { + histos.add("Event/nK0s", "Number of K0s candidates per event before cuts", kTH1F, {{200, 0., 200., "N_{K^{0}_{S}}"}}); + histos.add("Event/nK0sAfterCuts", "Number of K0s per event after cuts", kTH1F, {{100, 0., 100., "N_{K^{0}_{S}}"}}); + } + histos.add("Event/hRotBkg", "Rotated angle of rotated background", HistType::kTH1F, {axisRot}); + } + + if (cfgFillEventQA && doprocessK0sLambdaMEDF) { + const int mixingDepth = std::max(0, nEvtMixing.value); + const AxisSpec mixingCountAxis{mixingDepth + 1, -0.5, mixingDepth + 0.5, "N_{events}"}; + const AxisSpec mixingVertexAxis{200, -20., 20., "Current-event vertex z (cm)"}; + const AxisSpec mixingCentAxis{110, 0., 110., "Current-event centrality (%)"}; + const AxisSpec mixingV0Axis{201, -0.5, 200.5, "Current-event N_{V0s} before candidate cuts"}; + const AxisSpec previousVertexAxis{200, -20., 20., "Previous-event vertex z (cm)"}; + const AxisSpec previousCentAxis{110, 0., 110., "Previous-event centrality (%)"}; + const AxisSpec previousV0Axis{201, -0.5, 200.5, "Previous-event N_{V0s} before candidate cuts"}; + histos.add("MixingQA/K0sLambdaMEDF/hPosZvsCent", "Current mixing events;Vertex z (cm);Centrality (%)", kTH2F, {mixingVertexAxis, mixingCentAxis}); + histos.add("MixingQA/K0sLambdaMEDF/hPoolSize", "Buffered events before mixing, including INEL-rejected slots (one entry per accepted current event)", kTH1F, {mixingCountAxis}); + histos.add("MixingQA/K0sLambdaMEDF/hNPartners", "Accepted event partners before V0 cuts (one entry per accepted current event)", kTH1F, {mixingCountAxis}); + histos.add("MixingQA/K0sLambdaMEDF/hPosZPair", "Mixed event vertices", kTH2F, {previousVertexAxis, mixingVertexAxis}); + histos.add("MixingQA/K0sLambdaMEDF/hCentPair", "Mixed event centralities", kTH2F, {previousCentAxis, mixingCentAxis}); + histos.add("MixingQA/K0sLambdaMEDF/hV0CountsPair", "Mixed event V0 counts before candidate cuts", kTH2F, {previousV0Axis, mixingV0Axis}); + } + + if (cfgFillQA && (doprocessDataWithTracks || doprocessDataWithMicroTracks || doprocessMCWithTracks || doprocessMCWithMicroTracks || doprocessK0sLambda || doprocessMCK0sLambda)) { // Lambda QA histograms histos.add("QAbefore/lambdaDCAtoPV", "Lambda DCA to PV before cuts", kTH2F, {ptAxisQA, dcaAxis}); histos.add("QAbefore/lambdaMass", "Lambda mass before cuts", kTH1F, {lambdaMassAxis}); @@ -233,7 +320,7 @@ struct Xi1820Analysis { histos.add("QAafter/lambdaArmenterosPodolanski", "Lambda candidate Armenteros-Podolanski after cuts", kTH3F, {armenterosAlphaAxis, armenterosQtAxis, ptAxisQA}); } - if (doprocessDataWithTracks || doprocessDataWithMicroTracks || doprocessMCWithTracks) { + if (cfgFillQA && (doprocessDataWithTracks || doprocessDataWithMicroTracks || doprocessMCWithTracks || doprocessMCWithMicroTracks)) { // Kaon QA histograms histos.add("QAbefore/kaonPt", "Kaon pT before cuts", kTH1F, {ptAxisQA}); histos.add("QAbefore/kaonEta", "Kaon eta before cuts", kTH1F, {{100, -2.0, 2.0, "#eta"}}); @@ -256,7 +343,7 @@ struct Xi1820Analysis { // Resonance histograms - 4 combinations // K+ Lambda - if (doprocessDataWithTracks || doprocessDataWithMicroTracks || doprocessMixedEventWithTracks || doprocessMixedEventWithMicroTracks || doprocessMCWithTracks) { + if (doprocessDataWithTracks || doprocessDataWithMicroTracks || doprocessMixedEventWithTracks || doprocessMixedEventWithMicroTracks || doprocessMEDF || doprocessMCWithTracks || doprocessMCWithMicroTracks) { histos.add("xi1820/kplus_lambda/hInvMassKplusLambda", "Invariant mass of K^{+} + #Lambda", kTH1F, {invMassAxis}); histos.add("xi1820/kplus_lambda/hInvMassKplusLambda_Mix", "Mixed event Invariant mass of K^{+} + #Lambda", kTH1F, {invMassAxis}); @@ -288,27 +375,27 @@ struct Xi1820Analysis { histos.add("xi1820/kminus_antilambda/hMassPtCentKminusAntiLambda", "K^{-} + #bar{#Lambda} mass vs pT vs cent", kTH3D, {invMassAxis, ptAxis, centAxis}); histos.add("xi1820/kminus_antilambda/hMassPtCentKminusAntiLambda_Mix", "Mixed event K^{-} + #bar{#Lambda} mass vs pT vs cent", kTH3D, {invMassAxis, ptAxis, centAxis}); } else { - histos.add("xi1820/kplus_lambda/hMassPtCentDelKplusLambda", "K^{+} + #Lambda mass vs pT vs cent vs #DeltaR", kTHnSparseF, {invMassAxis, ptAxis, centAxis, axisDel}); - histos.add("xi1820/kplus_lambda/hMassPtCentDelKplusLambda_Mix", "Mixed event K^{+} + #Lambda mass vs pT vs cent vs #DeltaR", kTHnSparseF, {invMassAxis, ptAxis, centAxis, axisDel}); + histos.add("xi1820/kplus_lambda/hMassPtCentDelKplusLambda", "K^{+} + #Lambda mass vs pT vs cent vs #DeltaR", kTHnSparseD, {invMassAxis, ptAxis, centAxis, axisDel}); + histos.add("xi1820/kplus_lambda/hMassPtCentDelKplusLambda_Mix", "Mixed event K^{+} + #Lambda mass vs pT vs cent vs #DeltaR", kTHnSparseD, {invMassAxis, ptAxis, centAxis, axisDel}); // K+ Anti-Lambda - histos.add("xi1820/kplus_antilambda/hMassPtCentDelKplusAntiLambda", "K^{+} + #bar{#Lambda} mass vs pT vs cent vs #DeltaR", kTHnSparseF, {invMassAxis, ptAxis, centAxis, axisDel}); - histos.add("xi1820/kplus_antilambda/hMassPtCentDelKplusAntiLambda_Mix", "Mixed event K^{+} + #bar{#Lambda} mass vs pT vs cent vs #DeltaR", kTHnSparseF, {invMassAxis, ptAxis, centAxis, axisDel}); - histos.add("xi1820/kplus_antilambda/hMassPtCentDelKplusAntiLambda_Rot", "Rotated background K^{+} + #bar{#Lambda} mass vs pT vs cent vs #DeltaR", kTHnSparseF, {invMassAxis, ptAxis, centAxis, axisDel}); + histos.add("xi1820/kplus_antilambda/hMassPtCentDelKplusAntiLambda", "K^{+} + #bar{#Lambda} mass vs pT vs cent vs #DeltaR", kTHnSparseD, {invMassAxis, ptAxis, centAxis, axisDel}); + histos.add("xi1820/kplus_antilambda/hMassPtCentDelKplusAntiLambda_Mix", "Mixed event K^{+} + #bar{#Lambda} mass vs pT vs cent vs #DeltaR", kTHnSparseD, {invMassAxis, ptAxis, centAxis, axisDel}); + histos.add("xi1820/kplus_antilambda/hMassPtCentDelKplusAntiLambda_Rot", "Rotated background K^{+} + #bar{#Lambda} mass vs pT vs cent vs #DeltaR", kTHnSparseD, {invMassAxis, ptAxis, centAxis, axisDel}); // K- Lambda - histos.add("xi1820/kminus_lambda/hMassPtCentDelKminusLambda", "K^{-} + #Lambda mass vs pT vs cent vs #DeltaR", kTHnSparseF, {invMassAxis, ptAxis, centAxis, axisDel}); - histos.add("xi1820/kminus_lambda/hMassPtCentDelKminusLambda_Mix", "Mixed event K^{-} + #Lambda mass vs pT vs cent vs #DeltaR", kTHnSparseF, {invMassAxis, ptAxis, centAxis, axisDel}); - histos.add("xi1820/kminus_lambda/hMassPtCentDelKminusLambda_Rot", "Rotated background K^{-} + #Lambda mass vs pT vs cent vs #DeltaR", kTHnSparseF, {invMassAxis, ptAxis, centAxis, axisDel}); + histos.add("xi1820/kminus_lambda/hMassPtCentDelKminusLambda", "K^{-} + #Lambda mass vs pT vs cent vs #DeltaR", kTHnSparseD, {invMassAxis, ptAxis, centAxis, axisDel}); + histos.add("xi1820/kminus_lambda/hMassPtCentDelKminusLambda_Mix", "Mixed event K^{-} + #Lambda mass vs pT vs cent vs #DeltaR", kTHnSparseD, {invMassAxis, ptAxis, centAxis, axisDel}); + histos.add("xi1820/kminus_lambda/hMassPtCentDelKminusLambda_Rot", "Rotated background K^{-} + #Lambda mass vs pT vs cent vs #DeltaR", kTHnSparseD, {invMassAxis, ptAxis, centAxis, axisDel}); // K- Anti-Lambda - histos.add("xi1820/kminus_antilambda/hMassPtCentDelKminusAntiLambda", "K^{-} + #bar{#Lambda} mass vs pT vs cent vs #DeltaR", kTHnSparseF, {invMassAxis, ptAxis, centAxis, axisDel}); - histos.add("xi1820/kminus_antilambda/hMassPtCentDelKminusAntiLambda_Mix", "Mixed event K^{-} + #bar{#Lambda} mass vs pT vs cent vs #DeltaR", kTHnSparseF, {invMassAxis, ptAxis, centAxis, axisDel}); + histos.add("xi1820/kminus_antilambda/hMassPtCentDelKminusAntiLambda", "K^{-} + #bar{#Lambda} mass vs pT vs cent vs #DeltaR", kTHnSparseD, {invMassAxis, ptAxis, centAxis, axisDel}); + histos.add("xi1820/kminus_antilambda/hMassPtCentDelKminusAntiLambda_Mix", "Mixed event K^{-} + #bar{#Lambda} mass vs pT vs cent vs #DeltaR", kTHnSparseD, {invMassAxis, ptAxis, centAxis, axisDel}); } } // MC Reco histograms for charged K + Lambda channel - if (doprocessMCWithTracks) { + if (doprocessMCWithTracks || doprocessMCWithMicroTracks) { histos.add("MC/kplus_antilambda/hMCRecoInvMassKplusAntiLambda", "Invariant mass of Xi(1820) to K^{-} + #Lambda (MC Reco)", kTH1F, {invMassAxis}); histos.add("MC/kplus_antilambda/hMCRecoMassPtCentKplusAntiLambda", "Xi(1820) mass vs pT vs cent (K^{-} + #Lambda) (MC Reco)", kTHnSparseD, {invMassAxis, ptAxis, centAxis, ptAxis}); @@ -317,7 +404,7 @@ struct Xi1820Analysis { } // K0s QA histograms - if (doprocessK0sLambda || doprocessMCK0sLambda) { + if (cfgFillQA && (doprocessK0sLambda || doprocessMCK0sLambda)) { histos.add("QAbefore/k0sDCAtoPV", "K0s DCA to PV before cuts", kTH2F, {ptAxisQA, dcaAxis}); histos.add("QAbefore/k0sMass", "K0s mass before cuts", kTH1F, {{100, 0.4, 0.6, "K^{0}_{S} mass (GeV/#it{c}^{2})"}}); histos.add("QAbefore/k0sPt", "K0s pT before cuts", kTH1F, {ptAxisQA}); @@ -348,7 +435,7 @@ struct Xi1820Analysis { } // K0s + Lambda - if (doprocessK0sLambda || doprocessK0sLambdaMixedEvent || doprocessMCK0sLambda) { + if (doprocessK0sLambda || doprocessK0sLambdaMixedEvent || doprocessK0sLambdaMEDF || doprocessMCK0sLambda) { histos.add("xi1820/k0s_lambda/hInvMassK0sLambda", "Invariant mass of Xi(1820) to K^{0}_{S} + #Lambda", kTH1F, {invMassAxis}); histos.add("xi1820/k0s_lambda/hInvMassK0sLambda_Mix", "Mixed event Invariant mass of Xi(1820) to K^{0}_{S} + #Lambda", kTH1F, {invMassAxis}); @@ -365,14 +452,14 @@ struct Xi1820Analysis { histos.add("xi1820/k0s_antilambda/hMassPtCentK0sAntiLambda_Mix", "Mixed event Xi(1820) mass vs pT vs cent (K^{0}_{S}#bar{#Lambda})", kTH3D, {invMassAxis, ptAxis, centAxis}); histos.add("xi1820/k0s_antilambda/hMassPtCentK0sAntiLambda_Rot", "Rotated background Xi(1820) mass vs pT vs cent (K^{0}_{S}#bar{#Lambda})", kTH3D, {invMassAxis, ptAxis, centAxis}); } else { - histos.add("xi1820/k0s_lambda/hMassPtCentDelK0sLambda", "Xi(1820) mass vs pT vs cent vs #DeltaR (K^{0}_{S}#Lambda)", kTHnSparseF, {{invMassAxis, ptAxis, centAxis, axisDel}}); - histos.add("xi1820/k0s_lambda/hMassPtCentDelK0sLambda_Mix", "Mixed event Xi(1820) mass vs pT vs cent vs #DeltaR (K^{0}_{S}#Lambda)", kTHnSparseF, {{invMassAxis, ptAxis, centAxis, axisDel}}); - histos.add("xi1820/k0s_lambda/hMassPtCentDelK0sLambda_Rot", "Rotated background Xi(1820) mass vs pT vs cent vs #DeltaR (K^{0}_{S}#Lambda)", kTHnSparseF, {{invMassAxis, ptAxis, centAxis, axisDel}}); + histos.add("xi1820/k0s_lambda/hMassPtCentDelK0sLambda", "Xi(1820) mass vs pT vs cent vs #DeltaR (K^{0}_{S}#Lambda)", kTHnSparseD, {{invMassAxis, ptAxis, centAxis, axisDel}}); + histos.add("xi1820/k0s_lambda/hMassPtCentDelK0sLambda_Mix", "Mixed event Xi(1820) mass vs pT vs cent vs #DeltaR (K^{0}_{S}#Lambda)", kTHnSparseD, {{invMassAxis, ptAxis, centAxis, axisDel}}); + histos.add("xi1820/k0s_lambda/hMassPtCentDelK0sLambda_Rot", "Rotated background Xi(1820) mass vs pT vs cent vs #DeltaR (K^{0}_{S}#Lambda)", kTHnSparseD, {{invMassAxis, ptAxis, centAxis, axisDel}}); // K0s + Anti-Lambda - histos.add("xi1820/k0s_antilambda/hMassPtCentDelK0sAntiLambda", "Xi(1820) mass vs pT vs cent vs #DeltaR (K^{0}_{S}#bar{#Lambda})", kTHnSparseF, {{invMassAxis, ptAxis, centAxis, axisDel}}); - histos.add("xi1820/k0s_antilambda/hMassPtCentDelK0sAntiLambda_Mix", "Mixed event Xi(1820) mass vs pT vs cent vs #DeltaR (K^{0}_{S}#bar{#Lambda})", kTHnSparseF, {{invMassAxis, ptAxis, centAxis, axisDel}}); - histos.add("xi1820/k0s_antilambda/hMassPtCentDelK0sAntiLambda_Rot", "Rotated background Xi(1820) mass vs pT vs cent vs #DeltaR (K^{0}_{S}#bar{#Lambda})", kTHnSparseF, {{invMassAxis, ptAxis, centAxis, axisDel}}); + histos.add("xi1820/k0s_antilambda/hMassPtCentDelK0sAntiLambda", "Xi(1820) mass vs pT vs cent vs #DeltaR (K^{0}_{S}#bar{#Lambda})", kTHnSparseD, {{invMassAxis, ptAxis, centAxis, axisDel}}); + histos.add("xi1820/k0s_antilambda/hMassPtCentDelK0sAntiLambda_Mix", "Mixed event Xi(1820) mass vs pT vs cent vs #DeltaR (K^{0}_{S}#bar{#Lambda})", kTHnSparseD, {{invMassAxis, ptAxis, centAxis, axisDel}}); + histos.add("xi1820/k0s_antilambda/hMassPtCentDelK0sAntiLambda_Rot", "Rotated background Xi(1820) mass vs pT vs cent vs #DeltaR (K^{0}_{S}#bar{#Lambda})", kTHnSparseD, {{invMassAxis, ptAxis, centAxis, axisDel}}); } } @@ -384,6 +471,22 @@ struct Xi1820Analysis { histos.add("MC/k0s_antilambda/hMCRecoMassPtCentK0sAntiLambda", "Xi(1820) mass vs pT vs cent (K^{0}_{S}#bar{#Lambda}) (MC Reco)", kTHnSparseD, {invMassAxis, ptAxis, centAxis, ptAxis}); } + if (cfgFillTruthQA && (doprocessMCWithTracks || doprocessMCWithMicroTracks || doprocessMCK0sLambda)) { + histos.add("QAMCTrue/lambdaPt", "Truth-matched Lambda pT per signal pair", kTH1F, {ptAxisQA}); + histos.add("QAMCTrue/lambdaDaughterTPCNSigmaPi", "Truth-matched Lambda pion TPC PID", kTH2F, {ptAxisQA, nsigmaAxis}); + histos.add("QAMCTrue/lambdaDaughterTPCNSigmaPr", "Truth-matched Lambda proton TPC PID", kTH2F, {ptAxisQA, nsigmaAxis}); + if (doprocessMCWithTracks || doprocessMCWithMicroTracks) { + histos.add("QAMCTrue/kaonPt", "Truth-matched kaon pT per signal pair", kTH1F, {ptAxisQA}); + histos.add("QAMCTrue/kaonDCAxy", "Truth-matched kaon DCAxy", kTH2F, {ptAxisQA, dcaxyAxis}); + histos.add("QAMCTrue/kaonDCAz", "Truth-matched kaon DCAz", kTH2F, {ptAxisQA, dcazAxis}); + histos.add("QAMCTrue/kaonTPCNSigma", "Truth-matched kaon TPC PID", kTH2F, {ptAxisQA, nsigmaAxis}); + histos.add("QAMCTrue/kaonTOFNSigma", "Truth-matched kaon TOF PID", kTH2F, {ptAxisQA, nsigmaAxis}); + } + if (doprocessMCK0sLambda) { + histos.add("QAMCTrue/k0sPt", "Truth-matched K0s pT per signal pair", kTH1F, {ptAxisQA}); + } + } + if (doprocessMCGen) { histos.add("multQA/h2MultCentMC", "Multiplicity vs Centrality MC", HistType::kTH2D, {centAxis, additionalConfig.multNTracksAxis}); // MC truth invariant mass vs pT (2D) @@ -398,21 +501,21 @@ struct Xi1820Analysis { AxisSpec rapidityAxis = {100, -2.0, 2.0, "y"}; if (doprocessMCTruth) { - histos.add("MC/hMCTruthXi1820Pt", "MC Generated Xi(1820) pT", kTH1F, {ptAxis}); - histos.add("MC/hMCTruthXi1820PtEta", "MC Generated Xi(1820) pT vs eta", kTH2F, {ptAxis, etaAxis}); - histos.add("MC/hMCTruthXi1820Y", "MC Generated Xi(1820) rapidity", kTH1F, {rapidityAxis}); + histos.add("MC/hMCTruthXi1820Pt", "MC Generated Xi(1820) pT", kTH1D, {ptAxis}); + histos.add("MC/hMCTruthXi1820PtEta", "MC Generated Xi(1820) pT vs eta", kTH2D, {ptAxis, etaAxis}); + histos.add("MC/hMCTruthXi1820Y", "MC Generated Xi(1820) rapidity", kTH1D, {rapidityAxis}); // MC truth invariant mass (from MC particles) - histos.add("MC/hMCTruthInvMassKminusLambda", "MC Truth Inv Mass K^{-}#Lambda", kTH1F, {invMassAxis}); - histos.add("MC/hMCTruthInvMassKplusAntiLambda", "MC Truth Inv Mass K^{+}#bar{#Lambda}", kTH1F, {invMassAxis}); - histos.add("MC/hMCTruthInvMassK0sLambda", "MC Truth Inv Mass K^{0}_{S}#Lambda", kTH1F, {invMassAxis}); - histos.add("MC/hMCTruthInvMassK0sAntiLambda", "MC Truth Inv Mass K^{0}_{S}#bar{#Lambda}", kTH1F, {invMassAxis}); + histos.add("MC/hMCTruthInvMassKminusLambda", "MC Truth Inv Mass K^{-}#Lambda", kTH1D, {invMassAxis}); + histos.add("MC/hMCTruthInvMassKplusAntiLambda", "MC Truth Inv Mass K^{+}#bar{#Lambda}", kTH1D, {invMassAxis}); + histos.add("MC/hMCTruthInvMassK0sLambda", "MC Truth Inv Mass K^{0}_{S}#Lambda", kTH1D, {invMassAxis}); + histos.add("MC/hMCTruthInvMassK0sAntiLambda", "MC Truth Inv Mass K^{0}_{S}#bar{#Lambda}", kTH1D, {invMassAxis}); // MC truth invariant mass vs pT (2D) - histos.add("MC/hMCTruthMassPtKminusLambda", "MC Truth Mass vs pT K^{-}#Lambda", kTH2F, {invMassAxis, ptAxis}); - histos.add("MC/hMCTruthMassPtKplusAntiLambda", "MC Truth Mass vs pT K^{+}#bar{#Lambda}", kTH2F, {invMassAxis, ptAxis}); - histos.add("MC/hMCTruthMassPtK0sLambda", "MC Truth Mass vs pT K^{0}_{S}#Lambda", kTH2F, {invMassAxis, ptAxis}); - histos.add("MC/hMCTruthMassPtK0sAntiLambda", "MC Truth Mass vs pT K^{0}_{S}#bar{#Lambda}", kTH2F, {invMassAxis, ptAxis}); + histos.add("MC/hMCTruthMassPtKminusLambda", "MC Truth Mass vs pT K^{-}#Lambda", kTH2D, {invMassAxis, ptAxis}); + histos.add("MC/hMCTruthMassPtKplusAntiLambda", "MC Truth Mass vs pT K^{+}#bar{#Lambda}", kTH2D, {invMassAxis, ptAxis}); + histos.add("MC/hMCTruthMassPtK0sLambda", "MC Truth Mass vs pT K^{0}_{S}#Lambda", kTH2D, {invMassAxis, ptAxis}); + histos.add("MC/hMCTruthMassPtK0sAntiLambda", "MC Truth Mass vs pT K^{0}_{S}#bar{#Lambda}", kTH2D, {invMassAxis, ptAxis}); } } template @@ -443,36 +546,75 @@ struct Xi1820Analysis { return std::sqrt(dPhi * dPhi + dEta * dEta); } + bool passesRapidity(float rapidity) const + { + return -additionalConfig.cfgRapidityCut.value < rapidity && rapidity < additionalConfig.cfgRapidityCut.value; + } + + template + void fillTruthLambdaQA(const V0Type& lambda, bool isLambda) + { + if (!cfgFillTruthQA) { + return; + } + histos.fill(HIST("QAMCTrue/lambdaPt"), lambda.pt()); + histos.fill(HIST("QAMCTrue/lambdaDaughterTPCNSigmaPi"), lambda.pt(), isLambda ? lambda.daughterTPCNSigmaNegPi() : lambda.daughterTPCNSigmaPosPi()); + histos.fill(HIST("QAMCTrue/lambdaDaughterTPCNSigmaPr"), lambda.pt(), isLambda ? lambda.daughterTPCNSigmaPosPr() : lambda.daughterTPCNSigmaNegPr()); + } + + template + void fillTruthKaonQA(const TrackType& track) + { + if (!cfgFillTruthQA) { + return; + } + histos.fill(HIST("QAMCTrue/kaonPt"), track.pt()); + histos.fill(HIST("QAMCTrue/kaonDCAxy"), track.pt(), track.dcaXY()); + histos.fill(HIST("QAMCTrue/kaonDCAz"), track.pt(), track.dcaZ()); + histos.fill(HIST("QAMCTrue/kaonTPCNSigma"), track.pt(), track.tpcNSigmaKa()); + if (track.hasTOF() && !std::isnan(track.tofNSigmaKa())) { + histos.fill(HIST("QAMCTrue/kaonTOFNSigma"), track.pt(), track.tofNSigmaKa()); + } + } + // Lambda/Anti-Lambda selection template bool v0Cut(const CollisionType& collision, const V0Type& v0, bool isLambda) { // Basic kinematic cuts - if (std::abs(v0.eta()) > cMaxV0Etacut) + if (std::abs(v0.eta()) >= cMaxV0Etacut) { return false; - if (v0.pt() < cMinPtcut) + } + if (v0.pt() <= cMinPtcut) { return false; + } // DCA to PV - if (std::abs(v0.dcav0topv()) > additionalConfig.cMaxDcaToPVV0Lambda) + if (std::abs(v0.dcav0topv()) >= additionalConfig.cMaxDcaToPVV0Lambda) { return false; + } // Topological cuts - if (v0.v0CosPA() < cV0MinCosPA) + if (v0.v0CosPA() <= cV0MinCosPA) { return false; - if (v0.daughDCA() > cV0MaxDaughDCA) + } + if (v0.daughDCA() >= cV0MaxDaughDCA) { return false; + } // Daughter DCA to PV cuts - if (std::abs(v0.dcapostopv()) < cV0DauPosDCAtoPVMin) + if (std::abs(v0.dcapostopv()) <= cV0DauPosDCAtoPVMin) { return false; - if (std::abs(v0.dcanegtopv()) < cV0DauNegDCAtoPVMin) + } + if (std::abs(v0.dcanegtopv()) <= cV0DauNegDCAtoPVMin) { return false; + } // Radius cuts float radius = v0.transRadius(); - if (radius < cV0RadiusMin || radius > cV0RadiusMax) + if (radius <= cV0RadiusMin || radius >= cV0RadiusMax) { return false; + } // Proper lifetime cut float dx = v0.decayVtxX() - collision.posX(); @@ -481,41 +623,52 @@ struct Xi1820Analysis { float l = std::sqrt(dx * dx + dy * dy + dz * dz); float p = std::sqrt(v0.px() * v0.px() + v0.py() * v0.py() + v0.pz() * v0.pz()); auto properLifetime = (l / (p + SmallMomentumDenominator)) * MassLambda; - if (properLifetime > cV0ProperLifetimeMax) + if (properLifetime >= cV0ProperLifetimeMax) { return false; + } // Mass window if (isLambda) { - if (std::abs(v0.mLambda() - MassLambda) > cV0MassWindow) + if (std::abs(v0.mLambda() - MassLambda) >= cV0MassWindow) { return false; + } // TPC Nsigma cuts for daughter tracks - if (std::abs(v0.daughterTPCNSigmaNegPi()) >= cLambdaDaughterPiTPCNSigmaMax) + if (!passesPIDWindow(v0.daughterTPCNSigmaNegPi(), cLambdaDaughterPiTPCNSigmaMin, cLambdaDaughterPiTPCNSigmaMax, cLambdaDaughterPiTPCNSigmaMean)) { return false; - if (std::abs(v0.daughterTPCNSigmaPosPr()) >= cLambdaDaughterPrTPCNSigmaMax) + } + if (!passesPIDWindow(v0.daughterTPCNSigmaPosPr(), cLambdaDaughterPrTPCNSigmaMin, cLambdaDaughterPrTPCNSigmaMax, cLambdaDaughterPrTPCNSigmaMean)) { return false; + } // Note: TOF beta cut that calibrated by primary vertex is not applied for V0 daughters in this moment } else { - if (std::abs(v0.mAntiLambda() - MassLambda) > cV0MassWindow) + if (std::abs(v0.mAntiLambda() - MassLambda) >= cV0MassWindow) { return false; - if (std::abs(v0.daughterTPCNSigmaPosPi()) >= cLambdaDaughterPiTPCNSigmaMax) + } + if (!passesPIDWindow(v0.daughterTPCNSigmaPosPi(), cLambdaDaughterPiTPCNSigmaMin, cLambdaDaughterPiTPCNSigmaMax, cLambdaDaughterPiTPCNSigmaMean)) { return false; - if (std::abs(v0.daughterTPCNSigmaNegPr()) >= cLambdaDaughterPrTPCNSigmaMax) + } + if (!passesPIDWindow(v0.daughterTPCNSigmaNegPr(), cLambdaDaughterPrTPCNSigmaMin, cLambdaDaughterPrTPCNSigmaMax, cLambdaDaughterPrTPCNSigmaMean)) { return false; + } // Note: TOF beta cut that calibrated by primary vertex is not applied for V0 daughters in this moment } if (cV0sCrossMassRejection) { - if (std::abs(v0.mK0Short() - MassK0Short) < cV0sCrossMassRejectionWindow) + if (std::abs(v0.mK0Short() - MassK0Short) <= cV0sCrossMassRejectionWindow) { return false; + } } - if (v0.nCrossedRowsPos() <= cLambdaPosDaughterMinCrossedRows) + if (v0.nCrossedRowsPos() <= cLambdaPosDaughterMinCrossedRows) { return false; - if (v0.nCrossedRowsNeg() <= cLambdaNegDaughterMinCrossedRows) + } + if (v0.nCrossedRowsNeg() <= cLambdaNegDaughterMinCrossedRows) { return false; + } - if (v0.qtarm() > cK0sArmenterosAlphaCoeff * std::fabs(v0.alpha())) + if (v0.qtarm() >= cK0sArmenterosAlphaCoeff * std::fabs(v0.alpha())) { return false; + } return true; } @@ -524,31 +677,39 @@ struct Xi1820Analysis { bool k0sCut(const CollisionType& collision, const V0Type& v0) { // Basic kinematic cuts - if (std::abs(v0.eta()) > cMaxV0Etacut) + if (std::abs(v0.eta()) >= cMaxV0Etacut) { return false; - if (v0.pt() < cMinPtcut) + } + if (v0.pt() <= cMinPtcut) { return false; + } // Topological cuts - if (v0.v0CosPA() < cK0sMinCosPA) + if (v0.v0CosPA() <= cK0sMinCosPA) { return false; - if (v0.daughDCA() > cK0sMaxDaughDCA) + } + if (v0.daughDCA() >= cK0sMaxDaughDCA) { return false; + } // Daughter DCA to PV cuts - if (std::abs(v0.dcapostopv()) < cK0sDauPosDCAtoPVMin) + if (std::abs(v0.dcapostopv()) <= cK0sDauPosDCAtoPVMin) { return false; - if (std::abs(v0.dcanegtopv()) < cK0sDauNegDCAtoPVMin) + } + if (std::abs(v0.dcanegtopv()) <= cK0sDauNegDCAtoPVMin) { return false; + } // Radius cuts float radius = v0.transRadius(); - if (radius < cK0sRadiusMin || radius > cK0sRadiusMax) + if (radius <= cK0sRadiusMin || radius >= cK0sRadiusMax) { return false; + } // DCA to PV - if (std::abs(v0.dcav0topv()) > additionalConfig.cMaxDcaToPVV0K0s) + if (std::abs(v0.dcav0topv()) >= additionalConfig.cMaxDcaToPVV0K0s) { return false; + } // Proper lifetime cut float dx = v0.decayVtxX() - collision.posX(); @@ -557,225 +718,248 @@ struct Xi1820Analysis { float l = std::sqrt(dx * dx + dy * dy + dz * dz); float p = std::sqrt(v0.px() * v0.px() + v0.py() * v0.py() + v0.pz() * v0.pz()); auto properLifetime = (l / (p + SmallMomentumDenominator)) * MassK0Short; - if (properLifetime > cK0sProperLifetimeMax) + if (properLifetime >= cK0sProperLifetimeMax) { return false; + } // Mass window - if (std::abs(v0.mK0Short() - MassK0Short) > cK0sMassWindow) + if (std::abs(v0.mK0Short() - MassK0Short) >= cK0sMassWindow) { return false; + } // Competing V0 rejection: remove (Anti)Λ if (cK0sCrossMassRejection) { - if (std::abs(v0.mLambda() - MassLambda) < cK0sCrossMassRejectionWindow) + if (std::abs(v0.mLambda() - MassLambda) <= cK0sCrossMassRejectionWindow) { return false; - if (std::abs(v0.mAntiLambda() - MassLambda) < cK0sCrossMassRejectionWindow) + } + if (std::abs(v0.mAntiLambda() - MassLambda) <= cK0sCrossMassRejectionWindow) { return false; + } } - if (std::abs(v0.daughterTPCNSigmaPosPi()) >= cK0sDaughterPiTPCNSigmaMax) + if (!passesPIDWindow(v0.daughterTPCNSigmaPosPi(), cK0sDaughterPiTPCNSigmaMin, cK0sDaughterPiTPCNSigmaMax, cK0sDaughterPiTPCNSigmaMean)) { return false; - if (std::abs(v0.daughterTPCNSigmaNegPi()) >= cK0sDaughterPiTPCNSigmaMax) + } + if (!passesPIDWindow(v0.daughterTPCNSigmaNegPi(), cK0sDaughterPiTPCNSigmaMin, cK0sDaughterPiTPCNSigmaMax, cK0sDaughterPiTPCNSigmaMean)) { return false; + } // Note: TOF beta cut that calibrated by primary vertex is not applied for V0 daughters in this moment - if (v0.nCrossedRowsPos() <= cK0sPosDaughterMinCrossedRows) + if (v0.nCrossedRowsPos() <= cK0sPosDaughterMinCrossedRows) { return false; - if (v0.nCrossedRowsNeg() <= cK0sNegDaughterMinCrossedRows) + } + if (v0.nCrossedRowsNeg() <= cK0sNegDaughterMinCrossedRows) { return false; + } - if (v0.qtarm() < cK0sArmenterosAlphaCoeff * std::fabs(v0.alpha())) + if (v0.qtarm() <= cK0sArmenterosAlphaCoeff * std::fabs(v0.alpha())) { return false; + } return true; } - // Helper function to find pT bin index + // Strict signed window, retaining NaN rejection without negated compound comparisons. + static bool passesPIDWindow(float nSigma, float minimum, float maximum, float mean) + { + const float centered = nSigma - mean; + return minimum < centered && centered < maximum; + } + + // Preserve pT-bin membership [low, high); PID window edges themselves are strict. int getPtBinIndex(float pt) { - auto ptBins = static_cast>(cKaonPIDPtBins); - for (size_t i = 0; i < ptBins.size() - 1; i++) { - if (pt >= ptBins[i] && pt < ptBins[i + 1]) { - return i; + const auto& ptBins = cKaonPIDPtBins.value; + for (std::size_t i = 1; i < ptBins.size(); ++i) { + if (pt >= ptBins[i - 1] && pt < ptBins[i]) { + return static_cast(i - 1); } } - return -1; // should not happen if bins are properly configured + return -1; } - // Kaon PID selection - template + template bool kaonPidCut(const TrackType& track) { - float pt = track.pt(); - - if constexpr (IsResoMicrotrack) { - // For ResoMicroTracks - decode PID from flags - float tpcNSigma = o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(track.pidNSigmaKaFlag()); - float tofNSigma = track.hasTOF() ? o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(track.pidNSigmaKaFlag()) : 999.f; - - if (cKaonUsePtDepPID) { - // pT-dependent PID with binning - int ptBin = getPtBinIndex(pt); - if (ptBin < 0) - return false; // safety check - - auto tpcCuts = static_cast>(cKaonTPCNSigmaCuts); - auto tofCuts = static_cast>(cKaonTOFNSigmaCuts); - auto tofRequired = static_cast>(cKaonTOFRequired); - - // Check array sizes - if (ptBin >= static_cast(tpcCuts.size()) || - ptBin >= static_cast(tofCuts.size()) || - ptBin >= static_cast(tofRequired.size())) { - return false; // safety check - } - - // Apply TPC cut - if (std::abs(tpcNSigma) >= tpcCuts[ptBin]) - return false; - - // Apply TOF requirement and cut - if (tofRequired[ptBin] != 0) { - if (!track.hasTOF()) - return false; - if (std::abs(tofNSigma) >= tofCuts[ptBin]) - return false; - } else { - // TOF optional but apply cut if present - if (track.hasTOF() && std::abs(tofNSigma) >= tofCuts[ptBin]) - return false; - } - - return true; + const bool useTOF = !cKaonBypassTOF && track.hasTOF(); + float tpcMin = cKaonTPCNSigmaMin; + float tpcMax = cKaonTPCNSigmaMax; + float tofMin = cKaonTOFNSigmaMin; + float tofMax = cKaonTOFNSigmaMax; + if (cKaonUsePtDepPID) { + const int ptBin = getPtBinIndex(track.pt()); + if (ptBin < 0) { + return false; } - - // Standard PID - bool tpcPass = std::abs(tpcNSigma) < cKaonTPCNSigmaMax; - bool tofPass = track.hasTOF() ? std::abs(tofNSigma) < cKaonTOFNSigmaMax : true; - return tpcPass && tofPass; - } else { - // For ResoTracks - direct access - float tpcNSigma = track.tpcNSigmaKa(); - float tofNSigma = track.hasTOF() ? track.tofNSigmaKa() : 999.f; - - if (cKaonUsePtDepPID) { - // pT-dependent PID with binning - int ptBin = getPtBinIndex(pt); - if (ptBin < 0) - return false; // safety check - - auto tpcCuts = static_cast>(cKaonTPCNSigmaCuts); - auto tofCuts = static_cast>(cKaonTOFNSigmaCuts); - auto tofRequired = static_cast>(cKaonTOFRequired); - - // Check array sizes - if (ptBin >= static_cast(tpcCuts.size()) || - ptBin >= static_cast(tofCuts.size()) || - ptBin >= static_cast(tofRequired.size())) { - return false; // safety check - } - - // Apply TPC cut - if (std::abs(tpcNSigma) >= tpcCuts[ptBin]) + const auto bin = static_cast(ptBin); + if (bin >= cKaonTPCNSigmaCuts.value.size() || bin >= cKaonTPCNSigmaMinCuts.value.size()) { + return false; + } + tpcMin = cKaonTPCNSigmaMinCuts.value[bin]; + tpcMax = cKaonTPCNSigmaCuts.value[bin]; + if (useTOF) { + if (bin >= cKaonTOFNSigmaCuts.value.size() || bin >= cKaonTOFNSigmaMinCuts.value.size()) { return false; - - // Apply TOF requirement and cut - if (tofRequired[ptBin] != 0) { - if (!track.hasTOF()) - return false; - if (std::abs(tofNSigma) >= tofCuts[ptBin]) - return false; - } else { - // TOF optional but apply cut if present - if (track.hasTOF() && std::abs(tofNSigma) >= tofCuts[ptBin]) - return false; } - - return true; + tofMin = cKaonTOFNSigmaMinCuts.value[bin]; + tofMax = cKaonTOFNSigmaCuts.value[bin]; } - - // Standard PID - bool tpcPass = std::abs(tpcNSigma) < cKaonTPCNSigmaMax; - bool tofPass = track.hasTOF() ? std::abs(tofNSigma) < cKaonTOFNSigmaMax : true; - return tpcPass && tofPass; } + if (!passesPIDWindow(track.tpcNSigmaKa(), tpcMin, tpcMax, cKaonTPCNSigmaMean)) { + return false; + } + // No TOF-presence veto: missing or explicitly bypassed TOF uses TPC alone. + return !useTOF || + passesPIDWindow(track.tofNSigmaKa(), tofMin, tofMax, cKaonTOFNSigmaMean); } // Kaon track selection (for both ResoTracks and ResoMicroTracks) template bool kaonCut(const TrackType& track) { - float candPt = track.pt(); - // Basic kinematic cuts - if (candPt < cKaonPtMin) + const float candPt = track.pt(); + if (!std::isfinite(candPt) || !std::isfinite(track.eta()) || + !std::isfinite(track.dcaXY()) || !std::isfinite(track.dcaZ())) { return false; - if (std::abs(track.eta()) > cKaonEtaMax) + } + if (candPt <= cKaonPtMin || std::abs(track.eta()) >= cKaonEtaMax) { + return false; + } + const double dcaPtCut = additionalConfig.cUsePtDepDCAForKaons + ? additionalConfig.cDCAToPVByPtFirstP0.value + additionalConfig.cDCAToPVByPtFirstExp.value * std::pow(candPt, -static_cast(additionalConfig.cDCAToPVByPtFirstPower.value)) + : 0.; + const double dcaXYCut = additionalConfig.cUsePtDepDCAForKaons ? dcaPtCut : cKaonDCAxyMax.value; + const double dcaZCut = additionalConfig.cUsePtDepDCAForKaons ? dcaPtCut : cKaonDCAzMax.value; + if (std::abs(track.dcaXY()) >= dcaXYCut || std::abs(track.dcaZ()) >= dcaZCut) { return false; - - float dcaXY = -999.f; - float dcaZ = -999.f; - - // DCA cuts - different access for ResoMicroTracks - if constexpr (IsResoMicrotrack) { - dcaXY = o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(track.trackSelectionFlags()); - dcaZ = o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(track.trackSelectionFlags()); - - if (additionalConfig.cUsePtDepDCAForKaons) { // Insert pT dependent DCAxy,z cut (tighter than global-track w DCA cut) - if (std::abs(dcaXY) > (additionalConfig.cDCAToPVByPtFirstP0 + additionalConfig.cDCAToPVByPtFirstExp * std::pow(candPt, -1.))) - return false; - if (std::abs(dcaZ) > (additionalConfig.cDCAToPVByPtFirstP0 + additionalConfig.cDCAToPVByPtFirstExp * std::pow(candPt, -1.))) - return false; - } else { - if (std::abs(dcaXY) > cKaonDCAxyMax) - return false; - if (std::abs(dcaZ) > cKaonDCAzMax) - return false; - } - } else { - if (additionalConfig.cUsePtDepDCAForKaons) { // Insert pT dependent DCAxy,z cut (tighter than global-track w DCA cut) - if (std::abs(track.dcaXY()) > (additionalConfig.cDCAToPVByPtFirstP0 + additionalConfig.cDCAToPVByPtFirstExp * std::pow(candPt, -1.))) - return false; - if (std::abs(track.dcaZ()) > (additionalConfig.cDCAToPVByPtFirstP0 + additionalConfig.cDCAToPVByPtFirstExp * std::pow(candPt, -1.))) - return false; - } else { - if (std::abs(track.dcaXY()) > cKaonDCAxyMax) - return false; - if (std::abs(track.dcaZ()) > cKaonDCAzMax) - return false; - } } // Track quality cuts - check if fields are available (only for ResoTracks) if constexpr (!IsResoMicrotrack) { if constexpr (requires { track.tpcNClsFound(); }) { - if (track.tpcNClsFound() < cKaonTPCNClusMin) + if (track.tpcNClsFound() <= cKaonTPCNClusMin) { return false; + } } if constexpr (requires { track.itsNCls(); }) { - if (track.itsNCls() < cKaonITSNClusMin) + if (track.itsNCls() <= cKaonITSNClusMin) { return false; + } } } // PID selection - if (!kaonPidCut(track)) + if (!kaonPidCut(track)) { return false; + } // Flag selections for Primary track selection - if (additionalConfig.cfgPVContributor && !track.isPVContributor()) + if (additionalConfig.cfgPVContributor && !track.isPVContributor()) { return false; - if (additionalConfig.cfgPrimaryTrack && !track.isPrimaryTrack()) + } + if (additionalConfig.cfgPrimaryTrack && !track.isPrimaryTrack()) { return false; + } return true; } - template - void fillChargedKLambda(const CollisionT& collision, const V0sT& v0s, const TracksT& tracks) // Xi(1820) analysis: charged K + Lambda channel + bool hasChargedSameEventProcess() + { + return doprocessDataWithTracks || doprocessDataWithMicroTracks || doprocessMCWithTracks || doprocessMCWithMicroTracks; + } + + // Select each V0 once; QA and event counts must not be weighted by kaon multiplicity. + template + auto selectLambdas(const CollisionT& collision, const V0sT& v0s, bool fillSharedQA = true) + { + std::vector> selected; + selected.reserve(v0s.size()); + for (const auto& v0 : v0s) { + // Lambda QA before cuts + if (!IsMix && cfgFillQA && fillSharedQA) { + histos.fill(HIST("QAbefore/lambdaDCAtoPV"), v0.pt(), v0.dcav0topv()); + histos.fill(HIST("QAbefore/lambdaMass"), v0.mLambda()); + histos.fill(HIST("QAbefore/lambdaMassAnti"), v0.mAntiLambda()); + histos.fill(HIST("QAbefore/lambdaPt"), v0.pt()); + histos.fill(HIST("QAbefore/lambdaEta"), v0.eta()); + histos.fill(HIST("QAbefore/lambdaCosPA"), v0.pt(), v0.v0CosPA()); + histos.fill(HIST("QAbefore/lambdaRadius"), v0.pt(), v0.transRadius()); + histos.fill(HIST("QAbefore/lambdaDauDCA"), v0.pt(), v0.daughDCA()); + histos.fill(HIST("QAbefore/lambdaDauPosDCA"), v0.pt(), std::abs(v0.dcapostopv())); + histos.fill(HIST("QAbefore/lambdaDauNegDCA"), v0.pt(), std::abs(v0.dcanegtopv())); + histos.fill(HIST("QAbefore/lambdaDaughterTPCNSigmaPosPr"), v0.pt(), v0.daughterTPCNSigmaPosPr()); + histos.fill(HIST("QAbefore/lambdaDaughterTPCNSigmaNegPi"), v0.pt(), v0.daughterTPCNSigmaNegPi()); + histos.fill(HIST("QAbefore/lambdaAntiDaughterTPCNSigmaPosPi"), v0.pt(), v0.daughterTPCNSigmaPosPi()); + histos.fill(HIST("QAbefore/lambdaAntiDaughterTPCNSigmaNegPr"), v0.pt(), v0.daughterTPCNSigmaNegPr()); + histos.fill(HIST("QAbefore/lambdaNCrossedRowsPos"), v0.pt(), v0.nCrossedRowsPos()); + histos.fill(HIST("QAbefore/lambdaNCrossedRowsNeg"), v0.pt(), v0.nCrossedRowsNeg()); + + // Calculate proper lifetime manually + float dx = v0.decayVtxX() - collision.posX(); + float dy = v0.decayVtxY() - collision.posY(); + float dz = v0.decayVtxZ() - collision.posZ(); + float l = std::sqrt(dx * dx + dy * dy + dz * dz); + float p = std::sqrt(v0.px() * v0.px() + v0.py() * v0.py() + v0.pz() * v0.pz()); + auto properLifetime = (l / (p + SmallMomentumDenominator)) * MassLambda; + histos.fill(HIST("QAbefore/lambdaProperLifetime"), v0.pt(), properLifetime); + histos.fill(HIST("QAbefore/lambdaArmenterosPodolanski"), v0.alpha(), v0.qtarm(), v0.pt()); + } + + // Try Lambda + bool isLambda = v0Cut(collision, v0, true); + // Try Anti-Lambda + bool isAntiLambda = v0Cut(collision, v0, false); + + if (!isLambda && !isAntiLambda) { + continue; + } + + if (!IsMix && cfgFillQA && fillSharedQA) { + // QA after cuts (fill for whichever passes) + if (isLambda) { + histos.fill(HIST("QAafter/lambdaMass"), v0.mLambda()); + histos.fill(HIST("QAafter/lambdaDaughterTPCNSigmaPosPr"), v0.pt(), v0.daughterTPCNSigmaPosPr()); + histos.fill(HIST("QAafter/lambdaDaughterTPCNSigmaNegPi"), v0.pt(), v0.daughterTPCNSigmaNegPi()); + } + if (isAntiLambda) { + histos.fill(HIST("QAafter/lambdaMassAnti"), v0.mAntiLambda()); + histos.fill(HIST("QAafter/lambdaAntiDaughterTPCNSigmaPosPi"), v0.pt(), v0.daughterTPCNSigmaPosPi()); + histos.fill(HIST("QAafter/lambdaAntiDaughterTPCNSigmaNegPr"), v0.pt(), v0.daughterTPCNSigmaNegPr()); + } + histos.fill(HIST("QAafter/lambdaDCAtoPV"), v0.pt(), v0.dcav0topv()); + histos.fill(HIST("QAafter/lambdaPt"), v0.pt()); + histos.fill(HIST("QAafter/lambdaEta"), v0.eta()); + histos.fill(HIST("QAafter/lambdaCosPA"), v0.pt(), v0.v0CosPA()); + histos.fill(HIST("QAafter/lambdaRadius"), v0.pt(), v0.transRadius()); + histos.fill(HIST("QAafter/lambdaDauDCA"), v0.pt(), v0.daughDCA()); + histos.fill(HIST("QAafter/lambdaDauPosDCA"), v0.pt(), std::abs(v0.dcapostopv())); + histos.fill(HIST("QAafter/lambdaDauNegDCA"), v0.pt(), std::abs(v0.dcanegtopv())); + histos.fill(HIST("QAafter/lambdaNCrossedRowsPos"), v0.pt(), v0.nCrossedRowsPos()); + histos.fill(HIST("QAafter/lambdaNCrossedRowsNeg"), v0.pt(), v0.nCrossedRowsNeg()); + + float dx = v0.decayVtxX() - collision.posX(); + float dy = v0.decayVtxY() - collision.posY(); + float dz = v0.decayVtxZ() - collision.posZ(); + float l = std::sqrt(dx * dx + dy * dy + dz * dz); + float p = std::sqrt(v0.px() * v0.px() + v0.py() * v0.py() + v0.pz() * v0.pz()); + auto properLifetime = (l / (p + SmallMomentumDenominator)) * MassLambda; + histos.fill(HIST("QAafter/lambdaProperLifetime"), v0.pt(), properLifetime); + histos.fill(HIST("QAafter/lambdaArmenterosPodolanski"), v0.alpha(), v0.qtarm(), v0.pt()); + } + + selected.push_back({v0, isLambda, isAntiLambda}); + } + return selected; + } + + template + void fillChargedKLambda(const CollisionT& collision, const V0sT& v0s, const TracksT& tracks, const LambdaCollisionT& lambdaCollision) // Xi(1820) analysis: charged K + Lambda channel { auto cent = collision.cent(); // Fill event QA histograms (only for same-event) - if constexpr (!IsMix) { + if (!IsMix && cfgFillEventQA) { histos.fill(HIST("Event/posZ"), collision.posZ()); histos.fill(HIST("Event/centrality"), cent); histos.fill(HIST("Event/posZvsCent"), collision.posZ(), cent); @@ -783,12 +967,8 @@ struct Xi1820Analysis { histos.fill(HIST("Event/nKaons"), tracks.size()); } - if (additionalConfig.cConsiderPairOnly && (v0s.size() < 1 || tracks.size() < 1)) - return; // skip events that cannot form pairs if the option is enabled (for increasing processing speed when only pairs are of interest) - - // Count candidates after cuts - int nV0sAfterCuts = 0; - int nKaonsAfterCuts = 0; + std::vector selectedKaons; + selectedKaons.reserve(tracks.size()); // Build 4 combinations ROOT::Math::PxPyPzEVector pKaon, pLambda, pRes, lDaughterRot, lResonanceRot; @@ -796,23 +976,16 @@ struct Xi1820Analysis { // Loop over kaon candidates for (const auto& kaon : tracks) { // QA before cuts - if constexpr (!IsMix) { + if (!IsMix && cfgFillQA) { histos.fill(HIST("QAbefore/kaonPt"), kaon.pt()); histos.fill(HIST("QAbefore/kaonEta"), kaon.eta()); - if constexpr (IsResoMicrotrack) { - histos.fill(HIST("QAbefore/kaonDCAxy"), kaon.pt(), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(kaon.trackSelectionFlags())); - histos.fill(HIST("QAbefore/kaonDCAz"), kaon.pt(), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(kaon.trackSelectionFlags())); - histos.fill(HIST("QAbefore/kaonTPCNSigma"), kaon.pt(), o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(kaon.pidNSigmaKaFlag())); - if (kaon.hasTOF()) { - histos.fill(HIST("QAbefore/kaonTOFNSigma"), kaon.pt(), o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(kaon.pidNSigmaKaFlag())); - } - } else { - histos.fill(HIST("QAbefore/kaonDCAxy"), kaon.pt(), kaon.dcaXY()); - histos.fill(HIST("QAbefore/kaonDCAz"), kaon.pt(), kaon.dcaZ()); - histos.fill(HIST("QAbefore/kaonTPCNSigma"), kaon.pt(), kaon.tpcNSigmaKa()); - if (kaon.hasTOF()) { - histos.fill(HIST("QAbefore/kaonTOFNSigma"), kaon.pt(), kaon.tofNSigmaKa()); - } + histos.fill(HIST("QAbefore/kaonDCAxy"), kaon.pt(), kaon.dcaXY()); + histos.fill(HIST("QAbefore/kaonDCAz"), kaon.pt(), kaon.dcaZ()); + histos.fill(HIST("QAbefore/kaonTPCNSigma"), kaon.pt(), kaon.tpcNSigmaKa()); + if (kaon.hasTOF() && !std::isnan(kaon.tofNSigmaKa())) { + histos.fill(HIST("QAbefore/kaonTOFNSigma"), kaon.pt(), kaon.tofNSigmaKa()); + } + if constexpr (!IsResoMicrotrack) { if constexpr (requires { kaon.tpcNClsFound(); }) { histos.fill(HIST("QAbefore/kaonTPCNcls"), kaon.tpcNClsFound()); } @@ -822,28 +995,21 @@ struct Xi1820Analysis { } } - if (!kaonCut(kaon)) + if (!kaonCut(kaon)) { continue; + } - if constexpr (!IsMix) { - nKaonsAfterCuts++; + if (!IsMix && cfgFillQA) { // QA after cuts histos.fill(HIST("QAafter/kaonPt"), kaon.pt()); histos.fill(HIST("QAafter/kaonEta"), kaon.eta()); - if constexpr (IsResoMicrotrack) { - histos.fill(HIST("QAafter/kaonDCAxy"), kaon.pt(), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAxy(kaon.trackSelectionFlags())); - histos.fill(HIST("QAafter/kaonDCAz"), kaon.pt(), o2::aod::resomicrodaughter::ResoMicroTrackSelFlag::decodeDCAz(kaon.trackSelectionFlags())); - histos.fill(HIST("QAafter/kaonTPCNSigma"), kaon.pt(), o2::aod::resomicrodaughter::PidNSigma::getTPCnSigma(kaon.pidNSigmaKaFlag())); - if (kaon.hasTOF()) { - histos.fill(HIST("QAafter/kaonTOFNSigma"), kaon.pt(), o2::aod::resomicrodaughter::PidNSigma::getTOFnSigma(kaon.pidNSigmaKaFlag())); - } - } else { - histos.fill(HIST("QAafter/kaonDCAxy"), kaon.pt(), kaon.dcaXY()); - histos.fill(HIST("QAafter/kaonDCAz"), kaon.pt(), kaon.dcaZ()); - histos.fill(HIST("QAafter/kaonTPCNSigma"), kaon.pt(), kaon.tpcNSigmaKa()); - if (kaon.hasTOF()) { - histos.fill(HIST("QAafter/kaonTOFNSigma"), kaon.pt(), kaon.tofNSigmaKa()); - } + histos.fill(HIST("QAafter/kaonDCAxy"), kaon.pt(), kaon.dcaXY()); + histos.fill(HIST("QAafter/kaonDCAz"), kaon.pt(), kaon.dcaZ()); + histos.fill(HIST("QAafter/kaonTPCNSigma"), kaon.pt(), kaon.tpcNSigmaKa()); + if (kaon.hasTOF() && !std::isnan(kaon.tofNSigmaKa())) { + histos.fill(HIST("QAafter/kaonTOFNSigma"), kaon.pt(), kaon.tofNSigmaKa()); + } + if constexpr (!IsResoMicrotrack) { if constexpr (requires { kaon.tpcNClsFound(); }) { histos.fill(HIST("QAafter/kaonTPCNcls"), kaon.tpcNClsFound()); } @@ -853,304 +1019,272 @@ struct Xi1820Analysis { } } - int kaonCharge = kaon.sign(); - - // Loop over V0 candidates - for (const auto& v0 : v0s) { - // Lambda QA before cuts - if constexpr (!IsMix) { - histos.fill(HIST("QAbefore/lambdaDCAtoPV"), v0.pt(), v0.dcav0topv()); - histos.fill(HIST("QAbefore/lambdaMass"), v0.mLambda()); - histos.fill(HIST("QAbefore/lambdaMassAnti"), v0.mAntiLambda()); - histos.fill(HIST("QAbefore/lambdaPt"), v0.pt()); - histos.fill(HIST("QAbefore/lambdaEta"), v0.eta()); - histos.fill(HIST("QAbefore/lambdaCosPA"), v0.pt(), v0.v0CosPA()); - histos.fill(HIST("QAbefore/lambdaRadius"), v0.pt(), v0.transRadius()); - histos.fill(HIST("QAbefore/lambdaDauDCA"), v0.pt(), v0.daughDCA()); - histos.fill(HIST("QAbefore/lambdaDauPosDCA"), v0.pt(), std::abs(v0.dcapostopv())); - histos.fill(HIST("QAbefore/lambdaDauNegDCA"), v0.pt(), std::abs(v0.dcanegtopv())); - histos.fill(HIST("QAbefore/lambdaDaughterTPCNSigmaPosPr"), v0.pt(), v0.daughterTPCNSigmaPosPr()); - histos.fill(HIST("QAbefore/lambdaDaughterTPCNSigmaNegPi"), v0.pt(), v0.daughterTPCNSigmaNegPi()); - histos.fill(HIST("QAbefore/lambdaAntiDaughterTPCNSigmaPosPi"), v0.pt(), v0.daughterTPCNSigmaPosPi()); - histos.fill(HIST("QAbefore/lambdaAntiDaughterTPCNSigmaNegPr"), v0.pt(), v0.daughterTPCNSigmaNegPr()); - histos.fill(HIST("QAbefore/lambdaNCrossedRowsPos"), v0.pt(), v0.nCrossedRowsPos()); - histos.fill(HIST("QAbefore/lambdaNCrossedRowsNeg"), v0.pt(), v0.nCrossedRowsNeg()); - - // Calculate proper lifetime manually - float dx = v0.decayVtxX() - collision.posX(); - float dy = v0.decayVtxY() - collision.posY(); - float dz = v0.decayVtxZ() - collision.posZ(); - float l = std::sqrt(dx * dx + dy * dy + dz * dz); - float p = std::sqrt(v0.px() * v0.px() + v0.py() * v0.py() + v0.pz() * v0.pz()); - auto properLifetime = (l / (p + SmallMomentumDenominator)) * MassLambda; - histos.fill(HIST("QAbefore/lambdaProperLifetime"), v0.pt(), properLifetime); - histos.fill(HIST("QAbefore/lambdaArmenterosPodolanski"), v0.alpha(), v0.qtarm(), v0.pt()); - } - - // Try Lambda - bool isLambda = v0Cut(collision, v0, true); - // Try Anti-Lambda - bool isAntiLambda = v0Cut(collision, v0, false); - - if (!isLambda && !isAntiLambda) - continue; + selectedKaons.push_back(kaon); + } + const auto selectedLambdas = selectLambdas(lambdaCollision, v0s); + for (const auto& kaon : selectedKaons) { + const int kaonCharge = kaon.sign(); + for (const auto& selected : selectedLambdas) { + const auto& v0 = selected.candidate; if constexpr (!IsMix) { - nV0sAfterCuts++; - // QA after cuts (fill for whichever passes) - if (isLambda) { - histos.fill(HIST("QAafter/lambdaMass"), v0.mLambda()); - histos.fill(HIST("QAafter/lambdaDaughterTPCNSigmaPosPr"), v0.pt(), v0.daughterTPCNSigmaPosPr()); - histos.fill(HIST("QAafter/lambdaDaughterTPCNSigmaNegPi"), v0.pt(), v0.daughterTPCNSigmaNegPi()); - } - if (isAntiLambda) { - histos.fill(HIST("QAafter/lambdaMassAnti"), v0.mAntiLambda()); - histos.fill(HIST("QAafter/lambdaAntiDaughterTPCNSigmaPosPi"), v0.pt(), v0.daughterTPCNSigmaPosPi()); - histos.fill(HIST("QAafter/lambdaAntiDaughterTPCNSigmaNegPr"), v0.pt(), v0.daughterTPCNSigmaNegPr()); + const auto daughterIds = v0DaughterIds(v0); + if (kaon.trackId() == daughterIds[0] || kaon.trackId() == daughterIds[1]) { + continue; } - histos.fill(HIST("QAafter/lambdaDCAtoPV"), v0.pt(), v0.dcav0topv()); - histos.fill(HIST("QAafter/lambdaPt"), v0.pt()); - histos.fill(HIST("QAafter/lambdaEta"), v0.eta()); - histos.fill(HIST("QAafter/lambdaCosPA"), v0.pt(), v0.v0CosPA()); - histos.fill(HIST("QAafter/lambdaRadius"), v0.pt(), v0.transRadius()); - histos.fill(HIST("QAafter/lambdaDauDCA"), v0.pt(), v0.daughDCA()); - histos.fill(HIST("QAafter/lambdaDauPosDCA"), v0.pt(), std::abs(v0.dcapostopv())); - histos.fill(HIST("QAafter/lambdaDauNegDCA"), v0.pt(), std::abs(v0.dcanegtopv())); - histos.fill(HIST("QAafter/lambdaNCrossedRowsPos"), v0.pt(), v0.nCrossedRowsPos()); - histos.fill(HIST("QAafter/lambdaNCrossedRowsNeg"), v0.pt(), v0.nCrossedRowsNeg()); - - float dx = v0.decayVtxX() - collision.posX(); - float dy = v0.decayVtxY() - collision.posY(); - float dz = v0.decayVtxZ() - collision.posZ(); - float l = std::sqrt(dx * dx + dy * dy + dz * dz); - float p = std::sqrt(v0.px() * v0.px() + v0.py() * v0.py() + v0.pz() * v0.pz()); - auto properLifetime = (l / (p + SmallMomentumDenominator)) * MassLambda; - histos.fill(HIST("QAafter/lambdaProperLifetime"), v0.pt(), properLifetime); - histos.fill(HIST("QAafter/lambdaArmenterosPodolanski"), v0.alpha(), v0.qtarm(), v0.pt()); } pKaon = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(kaon.pt(), kaon.eta(), kaon.phi(), MassKaonCharged)); - // K+ + Lambda -> Bkg channel for charged Xi(1820) - if (kaonCharge > 0 && isLambda) { - pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mLambda())); - pRes = pKaon + pLambda; - auto pCandRapidity = pRes.Rapidity(); - if (std::abs(pCandRapidity) >= additionalConfig.cfgRapidityCut) // skip candidate if reconstructed rapidity is outside of cut + // A failed rapidity or truth match skips only this mass hypothesis. + for (const auto& isLambda : std::array{true, false}) { + if (isLambda ? !selected.isLambda : !selected.isAntiLambda) { continue; - if constexpr (!IsMix) { - histos.fill(HIST("xi1820/kplus_lambda/hInvMassKplusLambda"), pRes.M()); - if (!(additionalConfig.cfgDelCheck)) { - histos.fill(HIST("xi1820/kplus_lambda/hMassPtCentKplusLambda"), pRes.M(), pRes.Pt(), cent); - } else { - auto pCandDel = deltaR(pLambda, pKaon); - histos.fill(HIST("xi1820/kplus_lambda/hMassPtCentDelKplusLambda"), pRes.M(), pRes.Pt(), cent, pCandDel); + } + + // K+ + Lambda -> Bkg channel for charged Xi(1820) + if (kaonCharge > 0 && isLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mLambda())); + pRes = pKaon + pLambda; + auto pCandRapidity = pRes.Rapidity(); + if (!passesRapidity(pCandRapidity)) { // skip candidate if reconstructed rapidity is outside of cut + continue; } - } else { - histos.fill(HIST("xi1820/kplus_lambda/hInvMassKplusLambda_Mix"), pRes.M()); - if (!(additionalConfig.cfgDelCheck)) { - histos.fill(HIST("xi1820/kplus_lambda/hMassPtCentKplusLambda_Mix"), pRes.M(), pRes.Pt(), cent); + if constexpr (!IsMix) { + histos.fill(HIST("xi1820/kplus_lambda/hInvMassKplusLambda"), pRes.M()); + if (!(additionalConfig.cfgDelCheck)) { + histos.fill(HIST("xi1820/kplus_lambda/hMassPtCentKplusLambda"), pRes.M(), pRes.Pt(), cent); + } else { + auto pCandDel = deltaR(pLambda, pKaon); + histos.fill(HIST("xi1820/kplus_lambda/hMassPtCentDelKplusLambda"), pRes.M(), pRes.Pt(), cent, pCandDel); + } } else { - auto pCandDel = deltaR(pLambda, pKaon); - histos.fill(HIST("xi1820/kplus_lambda/hMassPtCentDelKplusLambda_Mix"), pRes.M(), pRes.Pt(), cent, pCandDel); + histos.fill(HIST("xi1820/kplus_lambda/hInvMassKplusLambda_Mix"), pRes.M()); + if (!(additionalConfig.cfgDelCheck)) { + histos.fill(HIST("xi1820/kplus_lambda/hMassPtCentKplusLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } else { + auto pCandDel = deltaR(pLambda, pKaon); + histos.fill(HIST("xi1820/kplus_lambda/hMassPtCentDelKplusLambda_Mix"), pRes.M(), pRes.Pt(), cent, pCandDel); + } } - } - } // End of Bkg - - // K+ + Anti-Lambda -> Signal channel for Anti-charged Xi(1820) - if (kaonCharge > 0 && isAntiLambda) { - pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mAntiLambda())); - pRes = pKaon + pLambda; - auto pCandRapidity = pRes.Rapidity(); - if (std::abs(pCandRapidity) >= additionalConfig.cfgRapidityCut) // skip candidate if reconstructed rapidity is outside of cut - continue; - if constexpr (!IsMix) { - histos.fill(HIST("xi1820/kplus_antilambda/hInvMassKplusAntiLambda"), pRes.M()); - if (!(additionalConfig.cfgDelCheck)) { - histos.fill(HIST("xi1820/kplus_antilambda/hMassPtCentKplusAntiLambda"), pRes.M(), pRes.Pt(), cent); - } else { - auto pCandDel = deltaR(pLambda, pKaon); - histos.fill(HIST("xi1820/kplus_antilambda/hMassPtCentDelKplusAntiLambda"), pRes.M(), pRes.Pt(), cent, pCandDel); + } // End of Bkg + + // K+ + Anti-Lambda -> Signal channel for Anti-charged Xi(1820) + if (kaonCharge > 0 && !isLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mAntiLambda())); + pRes = pKaon + pLambda; + auto pCandRapidity = pRes.Rapidity(); + if (!passesRapidity(pCandRapidity)) { // skip candidate if reconstructed rapidity is outside of cut + continue; } - if (additionalConfig.cfgFillRotBkg) { - for (int i = 0; i < additionalConfig.cfgNrotBkg; i++) { - auto lRotAngle = additionalConfig.cfgMinRot + i * ((additionalConfig.cfgMaxRot - additionalConfig.cfgMinRot) / (additionalConfig.cfgNrotBkg - 1)); - histos.fill(HIST("Event/hRotBkg"), lRotAngle - o2::constants::math::PI); - if (additionalConfig.cfgRotKaon) { - lDaughterRot = pKaon; - ROOT::Math::RotationZ rot(lRotAngle); - auto p3 = rot * lDaughterRot.Vect(); - lDaughterRot = LorentzVectorSetXYZM(p3.X(), p3.Y(), p3.Z(), lDaughterRot.M()); - lResonanceRot = lDaughterRot + pLambda; - } else { - lDaughterRot = pLambda; - ROOT::Math::RotationZ rot(lRotAngle); - auto p3 = rot * lDaughterRot.Vect(); - lDaughterRot = LorentzVectorSetXYZM(p3.X(), p3.Y(), p3.Z(), lDaughterRot.M()); - lResonanceRot = pKaon + lDaughterRot; - } - if (!(additionalConfig.cfgDelCheck)) { - histos.fill(HIST("xi1820/kplus_antilambda/hMassPtCentKplusAntiLambda_Rot"), lResonanceRot.M(), lResonanceRot.Pt(), cent); - } else { - auto pRotDel = additionalConfig.cfgRotKaon ? deltaR(lDaughterRot, pLambda) : deltaR(lDaughterRot, pKaon); - histos.fill(HIST("xi1820/kplus_antilambda/hMassPtCentDelKplusAntiLambda_Rot"), lResonanceRot.M(), lResonanceRot.Pt(), cent, pRotDel); + if constexpr (!IsMix) { + histos.fill(HIST("xi1820/kplus_antilambda/hInvMassKplusAntiLambda"), pRes.M()); + if (!(additionalConfig.cfgDelCheck)) { + histos.fill(HIST("xi1820/kplus_antilambda/hMassPtCentKplusAntiLambda"), pRes.M(), pRes.Pt(), cent); + } else { + auto pCandDel = deltaR(pLambda, pKaon); + histos.fill(HIST("xi1820/kplus_antilambda/hMassPtCentDelKplusAntiLambda"), pRes.M(), pRes.Pt(), cent, pCandDel); + } + if (additionalConfig.cfgFillRotBkg) { + for (int i = 0; i < additionalConfig.cfgNrotBkg; i++) { + const auto lRotAngle = additionalConfig.cfgNrotBkg == 1 + ? 0.5f * (additionalConfig.cfgMinRot + additionalConfig.cfgMaxRot) + : additionalConfig.cfgMinRot + i * ((additionalConfig.cfgMaxRot - additionalConfig.cfgMinRot) / (additionalConfig.cfgNrotBkg - 1)); + if (cfgFillEventQA) { + histos.fill(HIST("Event/hRotBkg"), lRotAngle - o2::constants::math::PI); + } + if (additionalConfig.cfgRotKaon) { + lDaughterRot = pKaon; + ROOT::Math::RotationZ rot(lRotAngle); + auto p3 = rot * lDaughterRot.Vect(); + lDaughterRot = LorentzVectorSetXYZM(p3.X(), p3.Y(), p3.Z(), lDaughterRot.M()); + lResonanceRot = lDaughterRot + pLambda; + } else { + lDaughterRot = pLambda; + ROOT::Math::RotationZ rot(lRotAngle); + auto p3 = rot * lDaughterRot.Vect(); + lDaughterRot = LorentzVectorSetXYZM(p3.X(), p3.Y(), p3.Z(), lDaughterRot.M()); + lResonanceRot = pKaon + lDaughterRot; + } + if (!(additionalConfig.cfgDelCheck)) { + histos.fill(HIST("xi1820/kplus_antilambda/hMassPtCentKplusAntiLambda_Rot"), lResonanceRot.M(), lResonanceRot.Pt(), cent); + } else { + auto pRotDel = additionalConfig.cfgRotKaon ? deltaR(lDaughterRot, pLambda) : deltaR(lDaughterRot, pKaon); + histos.fill(HIST("xi1820/kplus_antilambda/hMassPtCentDelKplusAntiLambda_Rot"), lResonanceRot.M(), lResonanceRot.Pt(), cent, pRotDel); + } } } - } - if constexpr (IsMC) { // Calculate Acceptance x efficiency for "the particle" channel - if (std::abs(v0.motherPDG()) != PdgChargedXi1820) - continue; - if (kaon.pdgCode() != PDG_t::kKPlus || v0.pdgCode() != PDG_t::kLambda0Bar) - continue; - if (kaon.motherId() != v0.motherId()) - continue; - auto pMCPt = v0.motherPt(); // Check particle's pT resolution - if (additionalConfig.cUseTruthRapidity && std::abs(v0.motherRap()) >= additionalConfig.cfgRapidityCut) // skip candidate if True rapidity of mother particle is outside of cut - continue; - histos.fill(HIST("MC/kplus_antilambda/hMCRecoInvMassKplusAntiLambda"), pRes.M()); - histos.fill(HIST("MC/kplus_antilambda/hMCRecoMassPtCentKplusAntiLambda"), pRes.M(), pRes.Pt(), cent, pMCPt); - - // Detail QA histograms for truth particle -> Will be updated - } - } else { - histos.fill(HIST("xi1820/kplus_antilambda/hInvMassKplusAntiLambda_Mix"), pRes.M()); - if (!(additionalConfig.cfgDelCheck)) { - histos.fill(HIST("xi1820/kplus_antilambda/hMassPtCentKplusAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent); + if constexpr (IsMC) { // Calculate Acceptance x efficiency for "the particle" channel + if (v0.motherPDG() != -PdgChargedXi1820 || kaon.motherPDG() != v0.motherPDG()) { + continue; + } + if (kaon.pdgCode() != PDG_t::kKPlus || v0.pdgCode() != PDG_t::kLambda0Bar) { + continue; + } + if (v0.motherId() < 0 || kaon.motherId() != v0.motherId()) { + continue; + } + auto pMCPt = v0.motherPt(); // Check particle's pT resolution + if (additionalConfig.cUseTruthRapidity && !passesRapidity(v0.motherRap())) { // skip candidate if True rapidity of mother particle is outside of cut + continue; + } + histos.fill(HIST("MC/kplus_antilambda/hMCRecoInvMassKplusAntiLambda"), pRes.M()); + histos.fill(HIST("MC/kplus_antilambda/hMCRecoMassPtCentKplusAntiLambda"), pRes.M(), pRes.Pt(), cent, pMCPt); + + fillTruthKaonQA(kaon); + fillTruthLambdaQA(v0, false); + } } else { - auto pCandDel = deltaR(pLambda, pKaon); - histos.fill(HIST("xi1820/kplus_antilambda/hMassPtCentDelKplusAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent, pCandDel); + histos.fill(HIST("xi1820/kplus_antilambda/hInvMassKplusAntiLambda_Mix"), pRes.M()); + if (!(additionalConfig.cfgDelCheck)) { + histos.fill(HIST("xi1820/kplus_antilambda/hMassPtCentKplusAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } else { + auto pCandDel = deltaR(pLambda, pKaon); + histos.fill(HIST("xi1820/kplus_antilambda/hMassPtCentDelKplusAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent, pCandDel); + } } - } - } // End of signal - - // K- + Lambda -> Signal channel for Xi(1820)- - if (kaonCharge < 0 && isLambda) { - pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mLambda())); - pRes = pKaon + pLambda; - auto pCandRapidity = pRes.Rapidity(); - if (std::abs(pCandRapidity) >= additionalConfig.cfgRapidityCut) // skip candidate if reconstructed rapidity is outside of cut - continue; - if constexpr (!IsMix) { - histos.fill(HIST("xi1820/kminus_lambda/hInvMassKminusLambda"), pRes.M()); - if (!(additionalConfig.cfgDelCheck)) { - histos.fill(HIST("xi1820/kminus_lambda/hMassPtCentKminusLambda"), pRes.M(), pRes.Pt(), cent); - } else { - auto pCandDel = deltaR(pLambda, pKaon); - histos.fill(HIST("xi1820/kminus_lambda/hMassPtCentDelKminusLambda"), pRes.M(), pRes.Pt(), cent, pCandDel); + } // End of signal + + // K- + Lambda -> Signal channel for Xi(1820)- + if (kaonCharge < 0 && isLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mLambda())); + pRes = pKaon + pLambda; + auto pCandRapidity = pRes.Rapidity(); + if (!passesRapidity(pCandRapidity)) { // skip candidate if reconstructed rapidity is outside of cut + continue; } + if constexpr (!IsMix) { + histos.fill(HIST("xi1820/kminus_lambda/hInvMassKminusLambda"), pRes.M()); + if (!(additionalConfig.cfgDelCheck)) { + histos.fill(HIST("xi1820/kminus_lambda/hMassPtCentKminusLambda"), pRes.M(), pRes.Pt(), cent); + } else { + auto pCandDel = deltaR(pLambda, pKaon); + histos.fill(HIST("xi1820/kminus_lambda/hMassPtCentDelKminusLambda"), pRes.M(), pRes.Pt(), cent, pCandDel); + } - if (additionalConfig.cfgFillRotBkg) { - for (int i = 0; i < additionalConfig.cfgNrotBkg; i++) { - auto lRotAngle = additionalConfig.cfgMinRot + i * ((additionalConfig.cfgMaxRot - additionalConfig.cfgMinRot) / (additionalConfig.cfgNrotBkg - 1)); - histos.fill(HIST("Event/hRotBkg"), lRotAngle - o2::constants::math::PI); - if (additionalConfig.cfgRotKaon) { - lDaughterRot = pKaon; - ROOT::Math::RotationZ rot(lRotAngle); - auto p3 = rot * lDaughterRot.Vect(); - lDaughterRot = LorentzVectorSetXYZM(p3.X(), p3.Y(), p3.Z(), lDaughterRot.M()); - lResonanceRot = lDaughterRot + pLambda; - } else { - lDaughterRot = pLambda; - ROOT::Math::RotationZ rot(lRotAngle); - auto p3 = rot * lDaughterRot.Vect(); - lDaughterRot = LorentzVectorSetXYZM(p3.X(), p3.Y(), p3.Z(), lDaughterRot.M()); - lResonanceRot = pKaon + lDaughterRot; + if (additionalConfig.cfgFillRotBkg) { + for (int i = 0; i < additionalConfig.cfgNrotBkg; i++) { + const auto lRotAngle = additionalConfig.cfgNrotBkg == 1 + ? 0.5f * (additionalConfig.cfgMinRot + additionalConfig.cfgMaxRot) + : additionalConfig.cfgMinRot + i * ((additionalConfig.cfgMaxRot - additionalConfig.cfgMinRot) / (additionalConfig.cfgNrotBkg - 1)); + if (cfgFillEventQA) { + histos.fill(HIST("Event/hRotBkg"), lRotAngle - o2::constants::math::PI); + } + if (additionalConfig.cfgRotKaon) { + lDaughterRot = pKaon; + ROOT::Math::RotationZ rot(lRotAngle); + auto p3 = rot * lDaughterRot.Vect(); + lDaughterRot = LorentzVectorSetXYZM(p3.X(), p3.Y(), p3.Z(), lDaughterRot.M()); + lResonanceRot = lDaughterRot + pLambda; + } else { + lDaughterRot = pLambda; + ROOT::Math::RotationZ rot(lRotAngle); + auto p3 = rot * lDaughterRot.Vect(); + lDaughterRot = LorentzVectorSetXYZM(p3.X(), p3.Y(), p3.Z(), lDaughterRot.M()); + lResonanceRot = pKaon + lDaughterRot; + } + if (!(additionalConfig.cfgDelCheck)) { + histos.fill(HIST("xi1820/kminus_lambda/hMassPtCentKminusLambda_Rot"), lResonanceRot.M(), lResonanceRot.Pt(), cent); + } else { + auto pCandDel = additionalConfig.cfgRotKaon ? deltaR(lDaughterRot, pLambda) : deltaR(lDaughterRot, pKaon); + histos.fill(HIST("xi1820/kminus_lambda/hMassPtCentDelKminusLambda_Rot"), lResonanceRot.M(), lResonanceRot.Pt(), cent, pCandDel); + } } - if (!(additionalConfig.cfgDelCheck)) { - histos.fill(HIST("xi1820/kminus_lambda/hMassPtCentKminusLambda_Rot"), lResonanceRot.M(), lResonanceRot.Pt(), cent); - } else { - auto pCandDel = additionalConfig.cfgRotKaon ? deltaR(lDaughterRot, pLambda) : deltaR(lDaughterRot, pKaon); - histos.fill(HIST("xi1820/kminus_lambda/hMassPtCentDelKminusLambda_Rot"), lResonanceRot.M(), lResonanceRot.Pt(), cent, pCandDel); + } + if constexpr (IsMC) { // Calculate Acceptance x efficiency for "the particle" channel + if (v0.motherPDG() != PdgChargedXi1820 || kaon.motherPDG() != v0.motherPDG()) { + continue; + } + if (kaon.pdgCode() != PDG_t::kKMinus || v0.pdgCode() != PDG_t::kLambda0) { + continue; + } + if (v0.motherId() < 0 || kaon.motherId() != v0.motherId()) { + continue; } + auto pMCPt = v0.motherPt(); // Check particle's pT resolution + if (additionalConfig.cUseTruthRapidity && !passesRapidity(v0.motherRap())) { // skip candidate if True rapidity of mother particle is outside of cut + continue; + } + histos.fill(HIST("MC/kminus_lambda/hMCRecoInvMassKminusLambda"), pRes.M()); + histos.fill(HIST("MC/kminus_lambda/hMCRecoMassPtCentKminusLambda"), pRes.M(), pRes.Pt(), cent, pMCPt); + + fillTruthKaonQA(kaon); + fillTruthLambdaQA(v0, true); } - } - if constexpr (IsMC) { // Calculate Acceptance x efficiency for "the particle" channel - if (std::abs(v0.motherPDG()) != PdgChargedXi1820) - continue; - if (kaon.pdgCode() != PDG_t::kKMinus || v0.pdgCode() != PDG_t::kLambda0) - continue; - if (kaon.motherId() != v0.motherId()) - continue; - auto pMCPt = v0.motherPt(); // Check particle's pT resolution - if (additionalConfig.cUseTruthRapidity && std::abs(v0.motherRap()) >= additionalConfig.cfgRapidityCut) // skip candidate if True rapidity of mother particle is outside of cut - continue; - histos.fill(HIST("MC/kminus_lambda/hMCRecoInvMassKminusLambda"), pRes.M()); - histos.fill(HIST("MC/kminus_lambda/hMCRecoMassPtCentKminusLambda"), pRes.M(), pRes.Pt(), cent, pMCPt); - - // Detail QA histograms for the truth particle -> Will be updated - } - } else { - histos.fill(HIST("xi1820/kminus_lambda/hInvMassKminusLambda_Mix"), pRes.M()); - if (!(additionalConfig.cfgDelCheck)) { - histos.fill(HIST("xi1820/kminus_lambda/hMassPtCentKminusLambda_Mix"), pRes.M(), pRes.Pt(), cent); } else { - auto pCandDel = deltaR(pLambda, pKaon); - histos.fill(HIST("xi1820/kminus_lambda/hMassPtCentDelKminusLambda_Mix"), pRes.M(), pRes.Pt(), cent, pCandDel); + histos.fill(HIST("xi1820/kminus_lambda/hInvMassKminusLambda_Mix"), pRes.M()); + if (!(additionalConfig.cfgDelCheck)) { + histos.fill(HIST("xi1820/kminus_lambda/hMassPtCentKminusLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } else { + auto pCandDel = deltaR(pLambda, pKaon); + histos.fill(HIST("xi1820/kminus_lambda/hMassPtCentDelKminusLambda_Mix"), pRes.M(), pRes.Pt(), cent, pCandDel); + } } - } - } // End of Signal - - // K- + Anti-Lambda -> Bkg channel for charged Xi(1820) - if (kaonCharge < 0 && isAntiLambda) { - pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mAntiLambda())); - pRes = pKaon + pLambda; - auto pCandRapidity = pRes.Rapidity(); - if (std::abs(pCandRapidity) >= additionalConfig.cfgRapidityCut) // skip candidate if reconstructed rapidity is outside of cut - continue; - if constexpr (!IsMix) { - histos.fill(HIST("xi1820/kminus_antilambda/hInvMassKminusAntiLambda"), pRes.M()); - if (!(additionalConfig.cfgDelCheck)) { - histos.fill(HIST("xi1820/kminus_antilambda/hMassPtCentKminusAntiLambda"), pRes.M(), pRes.Pt(), cent); - } else { - auto pCandDel = deltaR(pLambda, pKaon); - histos.fill(HIST("xi1820/kminus_antilambda/hMassPtCentDelKminusAntiLambda"), pRes.M(), pRes.Pt(), cent, pCandDel); + } // End of Signal + + // K- + Anti-Lambda -> Bkg channel for charged Xi(1820) + if (kaonCharge < 0 && !isLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(v0.pt(), v0.eta(), v0.phi(), v0.mAntiLambda())); + pRes = pKaon + pLambda; + auto pCandRapidity = pRes.Rapidity(); + if (!passesRapidity(pCandRapidity)) { // skip candidate if reconstructed rapidity is outside of cut + continue; } - } else { - histos.fill(HIST("xi1820/kminus_antilambda/hInvMassKminusAntiLambda_Mix"), pRes.M()); - if (!(additionalConfig.cfgDelCheck)) { - histos.fill(HIST("xi1820/kminus_antilambda/hMassPtCentKminusAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent); + if constexpr (!IsMix) { + histos.fill(HIST("xi1820/kminus_antilambda/hInvMassKminusAntiLambda"), pRes.M()); + if (!(additionalConfig.cfgDelCheck)) { + histos.fill(HIST("xi1820/kminus_antilambda/hMassPtCentKminusAntiLambda"), pRes.M(), pRes.Pt(), cent); + } else { + auto pCandDel = deltaR(pLambda, pKaon); + histos.fill(HIST("xi1820/kminus_antilambda/hMassPtCentDelKminusAntiLambda"), pRes.M(), pRes.Pt(), cent, pCandDel); + } } else { - auto pCandDel = deltaR(pLambda, pKaon); - histos.fill(HIST("xi1820/kminus_antilambda/hMassPtCentDelKminusAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent, pCandDel); + histos.fill(HIST("xi1820/kminus_antilambda/hInvMassKminusAntiLambda_Mix"), pRes.M()); + if (!(additionalConfig.cfgDelCheck)) { + histos.fill(HIST("xi1820/kminus_antilambda/hMassPtCentKminusAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } else { + auto pCandDel = deltaR(pLambda, pKaon); + histos.fill(HIST("xi1820/kminus_antilambda/hMassPtCentDelKminusAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent, pCandDel); + } } - } - } // End of Bkg - + } // End of Bkg + } // End of mass-hypothesis loop } // End of V0 loop } // Fill event QA for after-cuts counters (only for same-event) - if constexpr (!IsMix) { - histos.fill(HIST("Event/nLambdasAfterCuts"), nV0sAfterCuts); - histos.fill(HIST("Event/nKaonsAfterCuts"), nKaonsAfterCuts); + if (!IsMix && cfgFillEventQA) { + histos.fill(HIST("Event/nLambdasAfterCuts"), selectedLambdas.size()); + histos.fill(HIST("Event/nKaonsAfterCuts"), selectedKaons.size()); } } - template - void fillK0sLambda(const CollisionT& collision, const V0sT& k0sCands, const V0sT& lambdaCands) // Xi(1820) analysis: K0s + Lambda channel, No need to MicroTrack! + template + void fillK0sLambda(const CollisionT& collision, const V0sT& k0sCands, const V0sT& lambdaCands, const LambdaCollisionT& lambdaCollision) // Xi(1820) analysis: K0s + Lambda channel, No need to MicroTrack! { auto cent = collision.cent(); + // The charged same-event callback owns common event/Lambda QA when enabled. + const bool fillSharedQA = !hasChargedSameEventProcess(); // Fill event QA histograms - if constexpr (!IsMix) { - histos.fill(HIST("Event/posZ"), collision.posZ()); - histos.fill(HIST("Event/centrality"), cent); - histos.fill(HIST("Event/posZvsCent"), collision.posZ(), cent); - histos.fill(HIST("Event/nV0s"), lambdaCands.size()); - histos.fill(HIST("Event/nKaons"), k0sCands.size()); + if (!IsMix && cfgFillEventQA) { + if (fillSharedQA) { + histos.fill(HIST("Event/posZ"), collision.posZ()); + histos.fill(HIST("Event/centrality"), cent); + histos.fill(HIST("Event/posZvsCent"), collision.posZ(), cent); + histos.fill(HIST("Event/nV0s"), lambdaCands.size()); + } + histos.fill(HIST("Event/nK0s"), k0sCands.size()); } - if (additionalConfig.cConsiderHasV0s && (lambdaCands.size() < 1)) - return; // skip events that do not have V0s if the option is enabled - - int nV0sAfterCuts = 0; - int nKaonsAfterCuts = 0; + std::vector selectedK0s; + selectedK0s.reserve(k0sCands.size()); // Loop over V0s for K0s for (const auto& k0s : k0sCands) { // K0s QA before cuts - if constexpr (!IsMix) { + if (!IsMix && cfgFillQA) { histos.fill(HIST("QAbefore/k0sDCAtoPV"), k0s.pt(), k0s.dcav0topv()); histos.fill(HIST("QAbefore/k0sMass"), k0s.mK0Short()); histos.fill(HIST("QAbefore/k0sPt"), k0s.pt()); @@ -1173,12 +1307,11 @@ struct Xi1820Analysis { histos.fill(HIST("QAbefore/k0sArmenterosPodolanski"), k0s.alpha(), k0s.qtarm(), k0s.pt()); } - if (!k0sCut(collision, k0s)) + if (!k0sCut(collision, k0s)) { continue; - auto indexK0s = k0s.index(); + } - if constexpr (!IsMix) { - nKaonsAfterCuts++; + if (!IsMix && cfgFillQA) { // K0s QA after cuts histos.fill(HIST("QAafter/k0sDCAtoPV"), k0s.pt(), k0s.dcav0topv()); histos.fill(HIST("QAafter/k0sMass"), k0s.mK0Short()); @@ -1202,213 +1335,179 @@ struct Xi1820Analysis { histos.fill(HIST("QAafter/k0sArmenterosPodolanski"), k0s.alpha(), k0s.qtarm(), k0s.pt()); } - // Loop over V0s for Lambda - for (const auto& lambda : lambdaCands) { - - auto indexLambda = lambda.index(); + selectedK0s.push_back(k0s); + } + const auto selectedLambdas = selectLambdas(lambdaCollision, lambdaCands, fillSharedQA); + for (const auto& k0s : selectedK0s) { + for (const auto& selected : selectedLambdas) { + const auto& lambda = selected.candidate; if constexpr (!IsMix) { - if (indexLambda == indexK0s) // Avoid self-combination - continue; - if (sharesAnyDaughterId(v0DaughterIds(k0s), v0DaughterIds(lambda))) { + if (k0s.globalIndex() == lambda.globalIndex() || + sharesAnyDaughterId(v0DaughterIds(k0s), v0DaughterIds(lambda))) { continue; } - histos.fill(HIST("QAbefore/lambdaDCAtoPV"), lambda.pt(), lambda.dcav0topv()); - histos.fill(HIST("QAbefore/lambdaMass"), lambda.mLambda()); - histos.fill(HIST("QAbefore/lambdaMassAnti"), lambda.mAntiLambda()); - histos.fill(HIST("QAbefore/lambdaPt"), lambda.pt()); - histos.fill(HIST("QAbefore/lambdaEta"), lambda.eta()); - histos.fill(HIST("QAbefore/lambdaCosPA"), lambda.pt(), lambda.v0CosPA()); - histos.fill(HIST("QAbefore/lambdaRadius"), lambda.pt(), lambda.transRadius()); - histos.fill(HIST("QAbefore/lambdaDauDCA"), lambda.pt(), lambda.daughDCA()); - histos.fill(HIST("QAbefore/lambdaDauPosDCA"), lambda.pt(), std::abs(lambda.dcapostopv())); - histos.fill(HIST("QAbefore/lambdaDauNegDCA"), lambda.pt(), std::abs(lambda.dcanegtopv())); - histos.fill(HIST("QAbefore/lambdaDaughterTPCNSigmaPosPr"), lambda.pt(), lambda.daughterTPCNSigmaPosPr()); - histos.fill(HIST("QAbefore/lambdaDaughterTPCNSigmaNegPi"), lambda.pt(), lambda.daughterTPCNSigmaNegPi()); - histos.fill(HIST("QAbefore/lambdaAntiDaughterTPCNSigmaPosPi"), lambda.pt(), lambda.daughterTPCNSigmaPosPi()); - histos.fill(HIST("QAbefore/lambdaAntiDaughterTPCNSigmaNegPr"), lambda.pt(), lambda.daughterTPCNSigmaNegPr()); - histos.fill(HIST("QAbefore/lambdaNCrossedRowsPos"), lambda.pt(), lambda.nCrossedRowsPos()); - histos.fill(HIST("QAbefore/lambdaNCrossedRowsNeg"), lambda.pt(), lambda.nCrossedRowsNeg()); - - // Calculate proper lifetime manually - float dx = lambda.decayVtxX() - collision.posX(); - float dy = lambda.decayVtxY() - collision.posY(); - float dz = lambda.decayVtxZ() - collision.posZ(); - float l = std::sqrt(dx * dx + dy * dy + dz * dz); - float p = std::sqrt(lambda.px() * lambda.px() + lambda.py() * lambda.py() + lambda.pz() * lambda.pz()); - auto properLifetime = (l / (p + SmallMomentumDenominator)) * MassLambda; - histos.fill(HIST("QAbefore/lambdaProperLifetime"), lambda.pt(), properLifetime); - histos.fill(HIST("QAbefore/lambdaArmenterosPodolanski"), lambda.alpha(), lambda.qtarm(), lambda.pt()); - } - - // Try Lambda - bool isLambda = v0Cut(collision, lambda, true); - // Try Anti-Lambda - bool isAntiLambda = v0Cut(collision, lambda, false); - - if (!isLambda && !isAntiLambda) - continue; - - if constexpr (!IsMix) { - nV0sAfterCuts++; - // QA after cuts (fill for whichever passes) - if (isLambda) { - histos.fill(HIST("QAafter/lambdaMass"), lambda.mLambda()); - histos.fill(HIST("QAafter/lambdaDaughterTPCNSigmaPosPr"), lambda.pt(), lambda.daughterTPCNSigmaPosPr()); - histos.fill(HIST("QAafter/lambdaDaughterTPCNSigmaNegPi"), lambda.pt(), lambda.daughterTPCNSigmaNegPi()); - } - if (isAntiLambda) { - histos.fill(HIST("QAafter/lambdaMassAnti"), lambda.mAntiLambda()); - histos.fill(HIST("QAafter/lambdaAntiDaughterTPCNSigmaPosPi"), lambda.pt(), lambda.daughterTPCNSigmaPosPi()); - histos.fill(HIST("QAafter/lambdaAntiDaughterTPCNSigmaNegPr"), lambda.pt(), lambda.daughterTPCNSigmaNegPr()); - } - histos.fill(HIST("QAafter/lambdaDCAtoPV"), lambda.pt(), lambda.dcav0topv()); - histos.fill(HIST("QAafter/lambdaPt"), lambda.pt()); - histos.fill(HIST("QAafter/lambdaEta"), lambda.eta()); - histos.fill(HIST("QAafter/lambdaCosPA"), lambda.pt(), lambda.v0CosPA()); - histos.fill(HIST("QAafter/lambdaRadius"), lambda.pt(), lambda.transRadius()); - histos.fill(HIST("QAafter/lambdaDauDCA"), lambda.pt(), lambda.daughDCA()); - histos.fill(HIST("QAafter/lambdaDauPosDCA"), lambda.pt(), std::abs(lambda.dcapostopv())); - histos.fill(HIST("QAafter/lambdaDauNegDCA"), lambda.pt(), std::abs(lambda.dcanegtopv())); - histos.fill(HIST("QAafter/lambdaNCrossedRowsPos"), lambda.pt(), lambda.nCrossedRowsPos()); - histos.fill(HIST("QAafter/lambdaNCrossedRowsNeg"), lambda.pt(), lambda.nCrossedRowsNeg()); - - float dx = lambda.decayVtxX() - collision.posX(); - float dy = lambda.decayVtxY() - collision.posY(); - float dz = lambda.decayVtxZ() - collision.posZ(); - float l = std::sqrt(dx * dx + dy * dy + dz * dz); - float p = std::sqrt(lambda.px() * lambda.px() + lambda.py() * lambda.py() + lambda.pz() * lambda.pz()); - auto properLifetime = (l / (p + SmallMomentumDenominator)) * MassLambda; - histos.fill(HIST("QAafter/lambdaProperLifetime"), lambda.pt(), properLifetime); - histos.fill(HIST("QAafter/lambdaArmenterosPodolanski"), lambda.alpha(), lambda.qtarm(), lambda.pt()); } // 4-vectors ROOT::Math::PxPyPzEVector pK0s, pLambda, pRes, lDaughterRot, lResonanceRot; pK0s = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(k0s.pt(), k0s.eta(), k0s.phi(), MassK0Short)); - if (isLambda) { - pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(lambda.pt(), lambda.eta(), lambda.phi(), lambda.mLambda())); - pRes = pK0s + pLambda; - auto pCandRapidity = pRes.Rapidity(); - if (std::abs(pCandRapidity) >= additionalConfig.cfgRapidityCut) // skip candidate if reconstructed rapidity is outside of cut + // Lambda and anti-Lambda may both pass; evaluate them independently. + for (const auto& isLambda : std::array{true, false}) { + if (isLambda ? !selected.isLambda : !selected.isAntiLambda) { continue; - if constexpr (!IsMix) { - histos.fill(HIST("xi1820/k0s_lambda/hInvMassK0sLambda"), pRes.M()); - if (!(additionalConfig.cfgDelCheck)) { - histos.fill(HIST("xi1820/k0s_lambda/hMassPtCentK0sLambda"), pRes.M(), pRes.Pt(), cent); - } else { - auto pCandDel = deltaR(pLambda, pK0s); - histos.fill(HIST("xi1820/k0s_lambda/hMassPtCentDelK0sLambda"), pRes.M(), pRes.Pt(), cent, pCandDel); + } + + if (isLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(lambda.pt(), lambda.eta(), lambda.phi(), lambda.mLambda())); + pRes = pK0s + pLambda; + auto pCandRapidity = pRes.Rapidity(); + if (!passesRapidity(pCandRapidity)) { // skip candidate if reconstructed rapidity is outside of cut + continue; } + if constexpr (!IsMix) { + histos.fill(HIST("xi1820/k0s_lambda/hInvMassK0sLambda"), pRes.M()); + if (!(additionalConfig.cfgDelCheck)) { + histos.fill(HIST("xi1820/k0s_lambda/hMassPtCentK0sLambda"), pRes.M(), pRes.Pt(), cent); + } else { + auto pCandDel = deltaR(pLambda, pK0s); + histos.fill(HIST("xi1820/k0s_lambda/hMassPtCentDelK0sLambda"), pRes.M(), pRes.Pt(), cent, pCandDel); + } - if (additionalConfig.cfgFillRotBkg) { - for (int i = 0; i < additionalConfig.cfgNrotBkg; i++) { - auto lRotAngle = additionalConfig.cfgMinRot + i * ((additionalConfig.cfgMaxRot - additionalConfig.cfgMinRot) / (additionalConfig.cfgNrotBkg - 1)); - histos.fill(HIST("Event/hRotBkg"), lRotAngle - o2::constants::math::PI); - lDaughterRot = pK0s; - ROOT::Math::RotationZ rot(lRotAngle); - auto p3 = rot * lDaughterRot.Vect(); - lDaughterRot = LorentzVectorSetXYZM(p3.X(), p3.Y(), p3.Z(), lDaughterRot.M()); - lResonanceRot = lDaughterRot + pLambda; - if (!(additionalConfig.cfgDelCheck)) { - histos.fill(HIST("xi1820/k0s_lambda/hMassPtCentK0sLambda_Rot"), lResonanceRot.M(), lResonanceRot.Pt(), cent); - } else { - auto lRotDel = deltaR(lDaughterRot, pLambda); - histos.fill(HIST("xi1820/k0s_lambda/hMassPtCentDelK0sLambda_Rot"), lResonanceRot.M(), lResonanceRot.Pt(), cent, lRotDel); + if (additionalConfig.cfgFillRotBkg) { + for (int i = 0; i < additionalConfig.cfgNrotBkg; i++) { + const auto lRotAngle = additionalConfig.cfgNrotBkg == 1 + ? 0.5f * (additionalConfig.cfgMinRot + additionalConfig.cfgMaxRot) + : additionalConfig.cfgMinRot + i * ((additionalConfig.cfgMaxRot - additionalConfig.cfgMinRot) / (additionalConfig.cfgNrotBkg - 1)); + if (cfgFillEventQA) { + histos.fill(HIST("Event/hRotBkg"), lRotAngle - o2::constants::math::PI); + } + lDaughterRot = pK0s; + ROOT::Math::RotationZ rot(lRotAngle); + auto p3 = rot * lDaughterRot.Vect(); + lDaughterRot = LorentzVectorSetXYZM(p3.X(), p3.Y(), p3.Z(), lDaughterRot.M()); + lResonanceRot = lDaughterRot + pLambda; + if (!(additionalConfig.cfgDelCheck)) { + histos.fill(HIST("xi1820/k0s_lambda/hMassPtCentK0sLambda_Rot"), lResonanceRot.M(), lResonanceRot.Pt(), cent); + } else { + auto lRotDel = deltaR(lDaughterRot, pLambda); + histos.fill(HIST("xi1820/k0s_lambda/hMassPtCentDelK0sLambda_Rot"), lResonanceRot.M(), lResonanceRot.Pt(), cent, lRotDel); + } } } - } - if constexpr (IsMC) { // Calculate Acceptance x efficiency - if (std::abs(lambda.motherPDG()) != PdgXi1820Zero) - continue; - if (std::abs(k0s.pdgCode()) != PDG_t::kK0Short || lambda.pdgCode() != PDG_t::kLambda0) - continue; - if (k0s.motherId() != lambda.motherId()) - continue; - auto pMCPt = lambda.motherPt(); // Check particle's pT resolution - if (additionalConfig.cUseTruthRapidity && std::abs(lambda.motherRap()) >= additionalConfig.cfgRapidityCut) // skip candidate if True rapidity of mother particle is outside of cut - continue; - histos.fill(HIST("MC/k0s_lambda/hMCRecoInvMassK0sLambda"), pRes.M()); - histos.fill(HIST("MC/k0s_lambda/hMCRecoMassPtCentK0sLambda"), pRes.M(), pRes.Pt(), cent, pMCPt); - // Detail QA histograms for truth particle -> Will be updated - } - } else { - histos.fill(HIST("xi1820/k0s_lambda/hInvMassK0sLambda_Mix"), pRes.M()); - if (!(additionalConfig.cfgDelCheck)) { - histos.fill(HIST("xi1820/k0s_lambda/hMassPtCentK0sLambda_Mix"), pRes.M(), pRes.Pt(), cent); + if constexpr (IsMC) { // Calculate Acceptance x efficiency + if (lambda.motherPDG() != PdgXi1820Zero || k0s.motherPDG() != lambda.motherPDG()) { + continue; + } + if (std::abs(k0s.pdgCode()) != PDG_t::kK0Short || lambda.pdgCode() != PDG_t::kLambda0) { + continue; + } + if (lambda.motherId() < 0 || k0s.motherId() != lambda.motherId()) { + continue; + } + auto pMCPt = lambda.motherPt(); // Check particle's pT resolution + if (additionalConfig.cUseTruthRapidity && !passesRapidity(lambda.motherRap())) { // skip candidate if True rapidity of mother particle is outside of cut + continue; + } + histos.fill(HIST("MC/k0s_lambda/hMCRecoInvMassK0sLambda"), pRes.M()); + histos.fill(HIST("MC/k0s_lambda/hMCRecoMassPtCentK0sLambda"), pRes.M(), pRes.Pt(), cent, pMCPt); + fillTruthLambdaQA(lambda, true); + if (cfgFillTruthQA) { + histos.fill(HIST("QAMCTrue/k0sPt"), k0s.pt()); + } + } } else { - auto pCandDel = deltaR(pLambda, pK0s); - histos.fill(HIST("xi1820/k0s_lambda/hMassPtCentDelK0sLambda_Mix"), pRes.M(), pRes.Pt(), cent, pCandDel); + histos.fill(HIST("xi1820/k0s_lambda/hInvMassK0sLambda_Mix"), pRes.M()); + if (!(additionalConfig.cfgDelCheck)) { + histos.fill(HIST("xi1820/k0s_lambda/hMassPtCentK0sLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } else { + auto pCandDel = deltaR(pLambda, pK0s); + histos.fill(HIST("xi1820/k0s_lambda/hMassPtCentDelK0sLambda_Mix"), pRes.M(), pRes.Pt(), cent, pCandDel); + } } - } - } // End of Lambda - - if (isAntiLambda) { - pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(lambda.pt(), lambda.eta(), lambda.phi(), lambda.mAntiLambda())); - pRes = pK0s + pLambda; - auto pCandRapidity = pRes.Rapidity(); - if (std::abs(pCandRapidity) >= additionalConfig.cfgRapidityCut) // skip candidate if reconstructed rapidity is outside of cut - continue; - if constexpr (!IsMix) { - histos.fill(HIST("xi1820/k0s_antilambda/hInvMassK0sAntiLambda"), pRes.M()); - if (!(additionalConfig.cfgDelCheck)) { - histos.fill(HIST("xi1820/k0s_antilambda/hMassPtCentK0sAntiLambda"), pRes.M(), pRes.Pt(), cent); - } else { - auto pCandDel = deltaR(pLambda, pK0s); - histos.fill(HIST("xi1820/k0s_antilambda/hMassPtCentDelK0sAntiLambda"), pRes.M(), pRes.Pt(), cent, pCandDel); + } // End of Lambda + + if (!isLambda) { + pLambda = ROOT::Math::PxPyPzEVector(ROOT::Math::PtEtaPhiMVector(lambda.pt(), lambda.eta(), lambda.phi(), lambda.mAntiLambda())); + pRes = pK0s + pLambda; + auto pCandRapidity = pRes.Rapidity(); + if (!passesRapidity(pCandRapidity)) { // skip candidate if reconstructed rapidity is outside of cut + continue; } + if constexpr (!IsMix) { + histos.fill(HIST("xi1820/k0s_antilambda/hInvMassK0sAntiLambda"), pRes.M()); + if (!(additionalConfig.cfgDelCheck)) { + histos.fill(HIST("xi1820/k0s_antilambda/hMassPtCentK0sAntiLambda"), pRes.M(), pRes.Pt(), cent); + } else { + auto pCandDel = deltaR(pLambda, pK0s); + histos.fill(HIST("xi1820/k0s_antilambda/hMassPtCentDelK0sAntiLambda"), pRes.M(), pRes.Pt(), cent, pCandDel); + } - if (additionalConfig.cfgFillRotBkg) { - for (int i = 0; i < additionalConfig.cfgNrotBkg; i++) { - auto lRotAngle = additionalConfig.cfgMinRot + i * ((additionalConfig.cfgMaxRot - additionalConfig.cfgMinRot) / (additionalConfig.cfgNrotBkg - 1)); - histos.fill(HIST("Event/hRotBkg"), lRotAngle - o2::constants::math::PI); - lDaughterRot = pK0s; - ROOT::Math::RotationZ rot(lRotAngle); - auto p3 = rot * lDaughterRot.Vect(); - lDaughterRot = LorentzVectorSetXYZM(p3.X(), p3.Y(), p3.Z(), lDaughterRot.M()); - lResonanceRot = lDaughterRot + pLambda; - if (!(additionalConfig.cfgDelCheck)) { - histos.fill(HIST("xi1820/k0s_antilambda/hMassPtCentK0sAntiLambda_Rot"), lResonanceRot.M(), lResonanceRot.Pt(), cent); - } else { - auto lRotDel = deltaR(lDaughterRot, pLambda); - histos.fill(HIST("xi1820/k0s_antilambda/hMassPtCentDelK0sAntiLambda_Rot"), lResonanceRot.M(), lResonanceRot.Pt(), cent, lRotDel); + if (additionalConfig.cfgFillRotBkg) { + for (int i = 0; i < additionalConfig.cfgNrotBkg; i++) { + const auto lRotAngle = additionalConfig.cfgNrotBkg == 1 + ? 0.5f * (additionalConfig.cfgMinRot + additionalConfig.cfgMaxRot) + : additionalConfig.cfgMinRot + i * ((additionalConfig.cfgMaxRot - additionalConfig.cfgMinRot) / (additionalConfig.cfgNrotBkg - 1)); + if (cfgFillEventQA) { + histos.fill(HIST("Event/hRotBkg"), lRotAngle - o2::constants::math::PI); + } + lDaughterRot = pK0s; + ROOT::Math::RotationZ rot(lRotAngle); + auto p3 = rot * lDaughterRot.Vect(); + lDaughterRot = LorentzVectorSetXYZM(p3.X(), p3.Y(), p3.Z(), lDaughterRot.M()); + lResonanceRot = lDaughterRot + pLambda; + if (!(additionalConfig.cfgDelCheck)) { + histos.fill(HIST("xi1820/k0s_antilambda/hMassPtCentK0sAntiLambda_Rot"), lResonanceRot.M(), lResonanceRot.Pt(), cent); + } else { + auto lRotDel = deltaR(lDaughterRot, pLambda); + histos.fill(HIST("xi1820/k0s_antilambda/hMassPtCentDelK0sAntiLambda_Rot"), lResonanceRot.M(), lResonanceRot.Pt(), cent, lRotDel); + } } } - } - if constexpr (IsMC) { // Calculate Acceptance x efficiency - if (std::abs(lambda.motherPDG()) != PdgXi1820Zero) - continue; - if (std::abs(k0s.pdgCode()) != PDG_t::kK0Short || lambda.pdgCode() != PDG_t::kLambda0Bar) - continue; - if (k0s.motherId() != lambda.motherId()) - continue; - auto pMCPt = lambda.motherPt(); // Check particle's pT resolution - if (additionalConfig.cUseTruthRapidity && std::abs(lambda.motherRap()) >= additionalConfig.cfgRapidityCut) // skip candidate if True rapidity of mother particle is outside of cut - continue; - histos.fill(HIST("MC/k0s_antilambda/hMCRecoInvMassK0sAntiLambda"), pRes.M()); - histos.fill(HIST("MC/k0s_antilambda/hMCRecoMassPtCentK0sAntiLambda"), pRes.M(), pRes.Pt(), cent, pMCPt); - // Detail QA histograms for truth particle -> Will be updated - } - } else { - histos.fill(HIST("xi1820/k0s_antilambda/hInvMassK0sAntiLambda_Mix"), pRes.M()); - if (!(additionalConfig.cfgDelCheck)) { - histos.fill(HIST("xi1820/k0s_antilambda/hMassPtCentK0sAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent); + if constexpr (IsMC) { // Calculate Acceptance x efficiency + if (lambda.motherPDG() != -PdgXi1820Zero || k0s.motherPDG() != lambda.motherPDG()) { + continue; + } + if (std::abs(k0s.pdgCode()) != PDG_t::kK0Short || lambda.pdgCode() != PDG_t::kLambda0Bar) { + continue; + } + if (lambda.motherId() < 0 || k0s.motherId() != lambda.motherId()) { + continue; + } + auto pMCPt = lambda.motherPt(); // Check particle's pT resolution + if (additionalConfig.cUseTruthRapidity && !passesRapidity(lambda.motherRap())) { // skip candidate if True rapidity of mother particle is outside of cut + continue; + } + histos.fill(HIST("MC/k0s_antilambda/hMCRecoInvMassK0sAntiLambda"), pRes.M()); + histos.fill(HIST("MC/k0s_antilambda/hMCRecoMassPtCentK0sAntiLambda"), pRes.M(), pRes.Pt(), cent, pMCPt); + fillTruthLambdaQA(lambda, false); + if (cfgFillTruthQA) { + histos.fill(HIST("QAMCTrue/k0sPt"), k0s.pt()); + } + } } else { - auto pCandDel = deltaR(pLambda, pK0s); - histos.fill(HIST("xi1820/k0s_antilambda/hMassPtCentDelK0sAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent, pCandDel); + histos.fill(HIST("xi1820/k0s_antilambda/hInvMassK0sAntiLambda_Mix"), pRes.M()); + if (!(additionalConfig.cfgDelCheck)) { + histos.fill(HIST("xi1820/k0s_antilambda/hMassPtCentK0sAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent); + } else { + auto pCandDel = deltaR(pLambda, pK0s); + histos.fill(HIST("xi1820/k0s_antilambda/hMassPtCentDelK0sAntiLambda_Mix"), pRes.M(), pRes.Pt(), cent, pCandDel); + } } } - } + } // End of mass-hypothesis loop } // End of loop over Lambda candidates } // End of loop over K0s candidates // Fill event QA for after-cuts counters (only for same-event) - if constexpr (!IsMix) { - histos.fill(HIST("Event/nLambdasAfterCuts"), nV0sAfterCuts); - histos.fill(HIST("Event/nKaonsAfterCuts"), nKaonsAfterCuts); + if (!IsMix && cfgFillEventQA) { + if (fillSharedQA) { + histos.fill(HIST("Event/nLambdasAfterCuts"), selectedLambdas.size()); + } + histos.fill(HIST("Event/nK0sAfterCuts"), selectedK0s.size()); } } @@ -1418,137 +1517,265 @@ struct Xi1820Analysis { } PROCESS_SWITCH(Xi1820Analysis, processDummy, "Process Dummy", true); - void processDataWithTracks(const aod::ResoCollision& resoCollision, + void processDataWithTracks(ResoCollisions::iterator const& resoCollision, aod::ResoV0s const& resoV0s, - aod::ResoTracks const& resoTracks) + ResoTracks const& resoTracks) { - if (additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) + if (additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) { return; // skip event if RecoINEL>0 selection is enabled and event does not pass it - fillChargedKLambda(resoCollision, resoV0s, resoTracks); + } + fillChargedKLambda(resoCollision, resoV0s, resoTracks, resoCollision); } PROCESS_SWITCH(Xi1820Analysis, processDataWithTracks, "Process Event with ResoTracks", false); - void processDataWithMicroTracks(const aod::ResoCollision& resoCollision, + void processDataWithMicroTracks(ResoCollisions::iterator const& resoCollision, aod::ResoV0s const& resoV0s, - aod::ResoMicroTracks const& resoMicroTracks) + ResoMicroTracks const& resoMicroTracks) { - if (additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) + if (additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) { return; // skip event if RecoINEL>0 selection is enabled and event does not pass it - fillChargedKLambda(resoCollision, resoV0s, resoMicroTracks); + } + fillChargedKLambda(resoCollision, resoV0s, resoMicroTracks, resoCollision); } PROCESS_SWITCH(Xi1820Analysis, processDataWithMicroTracks, "Process Event with ResoMicroTracks", false); - void processMixedEventWithTracks(const aod::ResoCollisions& resoCollisions, - aod::ResoV0s const& resoV0s, - aod::ResoTracks const& resoTracks) + template + bool acceptsMixedCollisions(const FirstCollision& first, const SecondCollision& second) const { + if (additionalConfig.cRecoINELgt0.value && (!first.isRecINELgt0() || !second.isRecINELgt0())) { + return false; + } + return std::isfinite(first.bMagField()) && first.bMagField() == second.bMagField(); + } - auto v0sTracksTuple = std::make_tuple(resoTracks, resoV0s); - BinningTypeVertexContributor colBinning{{cfgVtxBins, cfgMultBins}, true}; - Pair pairs{colBinning, nEvtMixing, -1, resoCollisions, v0sTracksTuple, &cache}; - + void processMixedEventWithTracks(ResoCollisions const& resoCollisions, + aod::ResoV0s const& resoV0s, + ResoTracks const& resoTracks) + { + if (nEvtMixing <= 0) { + return; + } + auto tracksTuple = std::make_tuple(resoTracks, resoV0s); + BinningTypeVertexContributor binning{{cfgVtxBins, cfgMultBins}, true}; + Pair pairs{binning, nEvtMixing, -1, resoCollisions, tracksTuple, &cache}; for (auto& [collision1, tracks1, collision2, v0s2] : pairs) { // o2-linter: disable=const-ref-in-for-loop (structured bindings from Pair iterator cannot be const) - if (additionalConfig.cRecoINELgt0 && !collision1.isRecINELgt0()) - continue; // skip event if RecoINEL>0 selection is enabled and event does not pass it - fillChargedKLambda(collision1, v0s2, tracks1); + if (!acceptsMixedCollisions(collision1, collision2)) { + continue; + } + fillChargedKLambda(collision1, v0s2, tracks1, collision2); } } PROCESS_SWITCH(Xi1820Analysis, processMixedEventWithTracks, "Process Mixed Event with ResoTracks", false); - void processMixedEventWithMicroTracks(const aod::ResoCollisions& resoCollisions, + void processMixedEventWithMicroTracks(ResoCollisions const& resoCollisions, aod::ResoV0s const& resoV0s, - aod::ResoMicroTracks const& resoMicroTracks) + ResoMicroTracks const& resoMicroTracks) { + if (nEvtMixing <= 0) { + return; + } + auto tracksTuple = std::make_tuple(resoMicroTracks, resoV0s); + BinningTypeVertexContributor binning{{cfgVtxBins, cfgMultBins}, true}; + Pair pairs{binning, nEvtMixing, -1, resoCollisions, tracksTuple, &cache}; + for (auto& [collision1, tracks1, collision2, v0s2] : pairs) { // o2-linter: disable=const-ref-in-for-loop (structured bindings from Pair iterator cannot be const) + if (!acceptsMixedCollisions(collision1, collision2)) { + continue; + } + fillChargedKLambda(collision1, v0s2, tracks1, collision2); + } + } + PROCESS_SWITCH(Xi1820Analysis, processMixedEventWithMicroTracks, "Process Mixed Event with ResoMicroTracks 001", false); - auto v0sTracksTuple = std::make_tuple(resoV0s, resoMicroTracks); - BinningTypeVertexContributor colBinning{{cfgVtxBins, cfgMultBins}, true}; - Pair pairs{colBinning, nEvtMixing, -1, resoCollisions, v0sTracksTuple, &cache}; + template + static std::shared_ptr copyMixingRows(DaughterTable const& daughters) + { + // Copy only this collision's rows, without retaining the source DF buffers. + const auto source = daughters.asArrowTableConstrained(); + if (source->num_rows() == 0) { + return arrow::Table::MakeEmpty(source->schema()).ValueOrDie(); + } + std::vector> columns; + columns.reserve(source->num_columns()); + for (const auto& column : source->columns()) { + columns.push_back(std::make_shared(arrow::Concatenate(column->chunks()).ValueOrDie())); + } + return arrow::Table::Make(source->schema(), columns); + } - for (auto& [collision1, v0s1, collision2, tracks2] : pairs) { // o2-linter: disable=const-ref-in-for-loop (structured bindings from Pair iterator cannot be const) - if (additionalConfig.cRecoINELgt0 && !collision2.isRecINELgt0()) - continue; // skip event if RecoINEL>0 selection is enabled and event does not pass it - fillChargedKLambda(collision2, v0s1, tracks2); + // FIFO history is task-local and retains only the copied MicroTrack rows. + // Use a single run/condition set; a field change clears all stored event pools. + void processMEDF(ResoCollisions::iterator const& collision, + ResoMicroTracks const& tracks, + aod::ResoV0s const& v0s) + { + if (nEvtMixing <= 0 || !std::isfinite(collision.bMagField())) { + return; + } + if (mixingBField != collision.bMagField()) { + mixingPools.clear(); + mixingBField = collision.bMagField(); + } + BinningTypeVertexContributor binning{{cfgVtxBins, cfgMultBins}, true}; + const int bin = binning.getBin(std::make_tuple(collision.posZ(), collision.cent())); + if (bin < 0) { + return; + } + const MixingCollision current{.x = collision.posX(), .y = collision.posY(), .z = collision.posZ(), .centrality = collision.cent(), .recINELgt0 = collision.isRecINELgt0()}; + auto& pool = mixingPools[bin]; + for (const auto& previous : pool) { + if (additionalConfig.cRecoINELgt0 && (!previous.collision.recINELgt0 || !current.recINELgt0)) { + continue; + } + fillChargedKLambda(previous.collision, v0s, ResoMicroTracks{previous.daughters}, current); + } + // Insert after pairing; DF-local IDs may repeat across frames. + pool.push_back({current, copyMixingRows(tracks)}); + while (pool.size() > static_cast(nEvtMixing.value)) { + pool.pop_front(); } } - PROCESS_SWITCH(Xi1820Analysis, processMixedEventWithMicroTracks, "Process Mixed Event with ResoMicroTracks", false); + PROCESS_SWITCH(Xi1820Analysis, processMEDF, "Process cross-DF mixing with MicroTracks 001", false); // K0s + Lambda analysis - void processK0sLambda(const aod::ResoCollision& resoCollision, + void processK0sLambda(ResoCollisions::iterator const& resoCollision, aod::ResoV0s const& resoV0s) { - if (additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) + if (additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) { return; // skip event if RecoINEL>0 selection is enabled and event does not pass it - fillK0sLambda(resoCollision, resoV0s, resoV0s); + } + fillK0sLambda(resoCollision, resoV0s, resoV0s, resoCollision); } PROCESS_SWITCH(Xi1820Analysis, processK0sLambda, "Process K0s + Lambda", false); // K0s + Lambda mixed event analysis - void processK0sLambdaMixedEvent(const aod::ResoCollisions& resoCollisions, + void processK0sLambdaMixedEvent(ResoCollisions const& resoCollisions, aod::ResoV0s const& resoV0s) { + if (nEvtMixing <= 0) { + return; + } auto v0sV0sTuple = std::make_tuple(resoV0s, resoV0s); BinningTypeVertexContributor colBinning{{cfgVtxBins, cfgMultBins}, true}; - Pair pairs{colBinning, nEvtMixing, -1, resoCollisions, v0sV0sTuple, &cache}; + Pair pairs{colBinning, nEvtMixing, -1, resoCollisions, v0sV0sTuple, &cache}; for (auto& [collision1, k0s1, collision2, lambda2] : pairs) { // o2-linter: disable=const-ref-in-for-loop (structured bindings from Pair iterator cannot be const) - if (additionalConfig.cRecoINELgt0 && !collision1.isRecINELgt0()) - continue; // skip event if RecoINEL>0 selection is enabled and event does not pass it - fillK0sLambda(collision1, k0s1, lambda2); + if (!acceptsMixedCollisions(collision1, collision2)) { + continue; + } + fillK0sLambda(collision1, k0s1, lambda2, collision2); } } PROCESS_SWITCH(Xi1820Analysis, processK0sLambdaMixedEvent, "Process K0s + Lambda Mixed Event", false); + // Cross-DF neutral mixing: old-event K0s with current-event Lambda/anti-Lambda. + // Keep a separate bounded V0 pool; use inputs from one run/condition set. + void processK0sLambdaMEDF(ResoCollisions::iterator const& collision, + aod::ResoV0s const& v0s) + { + if (nEvtMixing <= 0 || !std::isfinite(collision.bMagField())) { + return; + } + if (neutralMixingBField != collision.bMagField()) { + neutralMixingPools.clear(); + neutralMixingBField = collision.bMagField(); + } + BinningTypeVertexContributor binning{{cfgVtxBins, cfgMultBins}, true}; + const int bin = binning.getBin(std::make_tuple(collision.posZ(), collision.cent())); + if (bin < 0) { + return; + } + const MixingCollision current{.x = collision.posX(), .y = collision.posY(), .z = collision.posZ(), .centrality = collision.cent(), .recINELgt0 = collision.isRecINELgt0()}; + auto& pool = neutralMixingPools[bin]; + const bool fillCurrentQA = cfgFillEventQA && (!additionalConfig.cRecoINELgt0 || current.recINELgt0); + if (fillCurrentQA) { + histos.fill(HIST("MixingQA/K0sLambdaMEDF/hPosZvsCent"), current.posZ(), current.cent()); + histos.fill(HIST("MixingQA/K0sLambdaMEDF/hPoolSize"), pool.size()); + } + int nPartners = 0; + for (const auto& previous : pool) { + if (additionalConfig.cRecoINELgt0 && (!previous.collision.recINELgt0 || !current.recINELgt0)) { + continue; + } + if (cfgFillEventQA) { + ++nPartners; + histos.fill(HIST("MixingQA/K0sLambdaMEDF/hPosZPair"), previous.collision.posZ(), current.posZ()); + histos.fill(HIST("MixingQA/K0sLambdaMEDF/hCentPair"), previous.collision.cent(), current.cent()); + histos.fill(HIST("MixingQA/K0sLambdaMEDF/hV0CountsPair"), previous.daughters->num_rows(), v0s.size()); + } + // Each V0 uses its own event's PV; original row IDs are not compared across events. + fillK0sLambda(previous.collision, aod::ResoV0s{previous.daughters}, v0s, current); + } + if (fillCurrentQA) { + histos.fill(HIST("MixingQA/K0sLambdaMEDF/hNPartners"), nPartners); + } + // Insert after pairing to avoid self-mixing, even when DF-local IDs repeat. + pool.push_back({current, copyMixingRows(v0s)}); + while (pool.size() > static_cast(nEvtMixing.value)) { + pool.pop_front(); + } + } + PROCESS_SWITCH(Xi1820Analysis, processK0sLambdaMEDF, "Process cross-DF K0s + Lambda mixing", false); + // MC processes for charged K + Lambda analysis void processMCWithTracks(ResoMCCols::iterator const& resoMCcollision, soa::Join const& resoMCV0s, - soa::Join const& resoMCTracks) + soa::Join const& resoMCTracks) { - if (additionalConfig.cRecoINELgt0 && !resoMCcollision.isRecINELgt0()) - return; // skip event if RecoINEL>0 selection is enabled and event does not pass it - if (!resoMCcollision.isInAfterAllCuts()) // MC event selection + if ((additionalConfig.cRecoINELgt0 && !resoMCcollision.isRecINELgt0()) || + (additionalConfig.cMCINELgt0 && !resoMCcollision.isINELgt0()) || + (additionalConfig.cMCVtxIn10 && !resoMCcollision.isVtxIn10())) { return; - fillChargedKLambda(resoMCcollision, resoMCV0s, resoMCTracks); + } + fillChargedKLambda(resoMCcollision, resoMCV0s, resoMCTracks, resoMCcollision); } PROCESS_SWITCH(Xi1820Analysis, processMCWithTracks, "Process MC for charged K + Lambda", false); void processMCK0sLambda(ResoMCCols::iterator const& resoMCCollision, soa::Join const& resoMCV0s) { - if (additionalConfig.cRecoINELgt0 && !resoMCCollision.isRecINELgt0()) - return; // skip event if RecoINEL>0 selection is enabled and event does not pass it - if (!resoMCCollision.isInAfterAllCuts()) // MC event selection + if ((additionalConfig.cRecoINELgt0 && !resoMCCollision.isRecINELgt0()) || + (additionalConfig.cMCINELgt0 && !resoMCCollision.isINELgt0()) || + (additionalConfig.cMCVtxIn10 && !resoMCCollision.isVtxIn10())) { return; - fillK0sLambda(resoMCCollision, resoMCV0s, resoMCV0s); + } + fillK0sLambda(resoMCCollision, resoMCV0s, resoMCV0s, resoMCCollision); } PROCESS_SWITCH(Xi1820Analysis, processMCK0sLambda, "Process MC K0s + Lambda", false); - void processMCWithMicroTracks(const aod::ResoCollision& /*resoCollision*/, - aod::ResoV0s const& /*resoV0s*/, - aod::ResoMicroTracks const& /*resoMicroTracks*/, - aod::McParticles const& /*mcParticles*/) + void processMCWithMicroTracks(ResoMCCols::iterator const& resoCollision, + soa::Join const& resoV0s, + soa::Join const& resoMicroTracks) { - // TODO: Implement MC truth matching for K± + Lambda with MicroTracks - // But is this really necessary? -> Most of the injected MC sizes are already within small-train limit. + if ((additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) || + (additionalConfig.cMCINELgt0 && !resoCollision.isINELgt0()) || + (additionalConfig.cMCVtxIn10 && !resoCollision.isVtxIn10())) { + return; + } + // Module 001 contains only selected reconstructed collisions. + fillChargedKLambda(resoCollision, resoV0s, resoMicroTracks, resoCollision); } - PROCESS_SWITCH(Xi1820Analysis, processMCWithMicroTracks, "Process MC with ResoMicroTracks (placeholder)", false); + PROCESS_SWITCH(Xi1820Analysis, processMCWithMicroTracks, "Process MC with ResoMicroTracks 001", false); void processMCGen(ResoMCCols::iterator const& resoCollision, // Calculate denominator for the acceptance x efficiency and a part of Event-factor (for selected evennts) - aod::ResoMCParents const& resoParents) + aod::ResoMCParents_001 const& resoParents) { auto multiplicity = resoCollision.mcMultiplicity(); auto inCent = resoCollision.cent(); - if (additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) // Check reco INELgt0 - return; - if (!resoCollision.isInAfterAllCuts()) + if ((additionalConfig.cRecoINELgt0 && !resoCollision.isRecINELgt0()) || + (additionalConfig.cMCINELgt0 && !resoCollision.isINELgt0()) || + (additionalConfig.cMCVtxIn10 && !resoCollision.isVtxIn10())) { return; + } histos.fill(HIST("multQA/h2MultCentMC"), inCent, multiplicity); for (const auto& part : resoParents) { // loop over all pre-filtered Gen particle on selected events auto pdgMother = part.pdgCode(); - if (std::abs(pdgMother) != PdgChargedXi1820 && std::abs(pdgMother) != PdgXi1820Zero) + if (std::abs(pdgMother) != PdgChargedXi1820 && std::abs(pdgMother) != PdgXi1820Zero) { continue; - if (std::abs(part.y()) >= additionalConfig.cfgRapidityCut) + } + if (!passesRapidity(part.y())) { continue; // skip if rapidity of the particle is outside of cut + } auto motherPt = part.pt(); auto daughter1PDG = part.daughterPDG1(); auto daughter2PDG = part.daughterPDG2(); @@ -1579,17 +1806,16 @@ struct Xi1820Analysis { void processMCTruth(aod::McParticles const& mcParticles) // ->Let's keep it and use for injected MC QA...! { // Process MC generated particles (no reconstruction requirement) - // Xi(1820)0 PDG code: 123314 (neutral, decays to K+ Lambda or K0s Lambda) - // Note: PDG doesn't have separate codes for charge states in this case + // Charged and neutral Xi(1820) states have distinct PDG codes. for (const auto& mcParticle : mcParticles) { // Look for Xi(1820) - PDG code can vary, check for resonance mass ~1820 MeV int pdg = mcParticle.pdgCode(); - // Xi(1820)0: PDG 123314 - // Check if it's Xi(1820) or similar resonance - if (std::abs(pdg) != PdgChargedXi1820 && std::abs(pdg) != PdgXi1820Zero) + // Select only the configured charged and neutral Xi(1820) states. + if (std::abs(pdg) != PdgChargedXi1820 && std::abs(pdg) != PdgXi1820Zero) { continue; + } // Fill generated level histograms auto pt = mcParticle.pt(); @@ -1602,8 +1828,9 @@ struct Xi1820Analysis { // Get daughters auto daughters = mcParticle.daughters_as(); - if (daughters.size() != ExpectedDaughters) + if (daughters.size() != ExpectedDaughters) { continue; + } int daughter1PDG = 0, daughter2PDG = 0; ROOT::Math::PxPyPzEVector p1, p2, pMother; @@ -1657,7 +1884,7 @@ struct Xi1820Analysis { PROCESS_SWITCH(Xi1820Analysis, processMCTruth, "Process MC Truth particles", false); }; -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +WorkflowSpec defineDataProcessing(ConfigContext const& context) { - return WorkflowSpec{adaptAnalysisTask(cfgc)}; + return WorkflowSpec{adaptAnalysisTask(context)}; } diff --git a/PWGLF/Tasks/Strangeness/cascadeAnalysisLightIonsDerivedData.cxx b/PWGLF/Tasks/Strangeness/cascadeAnalysisLightIonsDerivedData.cxx index 5dba2604ec0..33d3c9c51b0 100644 --- a/PWGLF/Tasks/Strangeness/cascadeAnalysisLightIonsDerivedData.cxx +++ b/PWGLF/Tasks/Strangeness/cascadeAnalysisLightIonsDerivedData.cxx @@ -19,6 +19,7 @@ #include "PWGLF/DataModel/LFStrangenessTables.h" #include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/RCTSelectionFlags.h" #include "Common/Core/RecoDecay.h" #include @@ -48,6 +49,8 @@ using namespace o2::framework::expressions; using namespace o2::constants::math; using namespace o2::constants::physics; +using namespace o2::aod::rctsel; + using SelCollisions = soa::Join; using SimCollisions = soa::Join; using CascadeCandidates = soa::Join; @@ -72,7 +75,7 @@ struct CascadeAnalysisLightIonsDerivedData { o2::ccdb::CcdbApi ccdbApi; Service ccdb; - int mRunNumber; + int mRunNumber{-1}; // Define histogram registries HistogramRegistry registryData{"registryData", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; @@ -137,6 +140,15 @@ struct CascadeAnalysisLightIonsDerivedData { ConfigurableAxis axisNch{"axisNch", {500, 0.0f, +5000.0f}, "Number of charged particles"}; ConfigurableAxis axisMult{"axisMult", {500, 0.0f, +100000.0f}, "Multiplicity"}; + struct : ConfigurableGroup { + std::string prefix = "rctConfigurations"; // JSON group name + Configurable cfgRCTLabel{"cfgRCTLabel", "", "Which detector condition requirements? (CBT, CBT_hadronPID, CBT_electronPID, CBT_calo, CBT_muon, CBT_muon_glo)"}; + Configurable cfgCheckZDC{"cfgCheckZDC", false, "Include ZDC flags in the bit selection (for Pb-Pb only)"}; + Configurable cfgTreatLimitedAcceptanceAsBad{"cfgTreatLimitedAcceptanceAsBad", false, "reject all events where the detectors relevant for the specified Runlist are flagged as LimitedAcceptance"}; + } rctConfigurations; + + RCTFlagsChecker rctFlagsChecker{rctConfigurations.cfgRCTLabel.value}; + // Centrality estimator Configurable centralityEstimator{"centralityEstimator", 0, "0 = FT0C, 1 = FTOM, 2 = FV0A, 3 = NGlobal"}; @@ -172,6 +184,9 @@ struct CascadeAnalysisLightIonsDerivedData { const AxisSpec nsigmaTOFAxis{200, -10, 10, "n#sigma_{TOF}"}; const AxisSpec nsigmaTPCAxis{200, -10, 10, "n#sigma_{TPC}"}; + // Initialise the RCTFlagsChecker + rctFlagsChecker.init(rctConfigurations.cfgRCTLabel.value, rctConfigurations.cfgCheckZDC, rctConfigurations.cfgTreatLimitedAcceptanceAsBad); + // Histograms for data if (doprocessData) { registryData.add("number_of_events_data", "number of events in data", HistType::kTH1D, {{20, -0.5f, +19.5f}}); @@ -185,7 +200,8 @@ struct CascadeAnalysisLightIonsDerivedData { registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(8, "kIsVertexTOFmatched"); registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(9, "kIsVertexTRDmatched"); registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(10, "kNoSameBunchPileup"); - registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(11, "kINELgr0"); + registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(11, "RCT flags"); + registryData.get(HIST("number_of_events_data"))->GetXaxis()->SetBinLabel(12, "kINELgr0"); registryData.add("number_of_events_data_vs_centrality", "number of events in data vs centrality", HistType::kTH2D, {{20, -0.5f, +19.5f}, {101, 0.0f, 101.0f}}); registryData.get(HIST("number_of_events_data_vs_centrality"))->GetXaxis()->SetBinLabel(1, "All collisions"); @@ -198,7 +214,8 @@ struct CascadeAnalysisLightIonsDerivedData { registryData.get(HIST("number_of_events_data_vs_centrality"))->GetXaxis()->SetBinLabel(8, "kIsVertexTOFmatched"); registryData.get(HIST("number_of_events_data_vs_centrality"))->GetXaxis()->SetBinLabel(9, "kIsVertexTRDmatched"); registryData.get(HIST("number_of_events_data_vs_centrality"))->GetXaxis()->SetBinLabel(10, "kNoSameBunchPileup"); - registryData.get(HIST("number_of_events_data_vs_centrality"))->GetXaxis()->SetBinLabel(11, "kINELgr0"); + registryData.get(HIST("number_of_events_data_vs_centrality"))->GetXaxis()->SetBinLabel(11, "RCT flags"); + registryData.get(HIST("number_of_events_data_vs_centrality"))->GetXaxis()->SetBinLabel(12, "kINELgr0"); registryData.get(HIST("number_of_events_data_vs_centrality"))->GetYaxis()->SetTitle("Centrality (%)"); // QC Histograms @@ -248,7 +265,8 @@ struct CascadeAnalysisLightIonsDerivedData { registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(8, "kIsVertexTOFmatched"); registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(9, "kIsVertexTRDmatched"); registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(10, "kNoSameBunchPileup"); - registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(11, "kINELgr0"); + registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(11, "RCT flags"); + registryMC.get(HIST("number_of_events_mc_rec"))->GetXaxis()->SetBinLabel(12, "kINELgr0"); registryMC.add("number_of_events_mc_rec_vs_centrality", "number of events in mc_rec vs centrality", HistType::kTH2D, {{20, -0.5f, +19.5f}, {101, 0.0f, 101.0f}}); registryMC.get(HIST("number_of_events_mc_rec_vs_centrality"))->GetXaxis()->SetBinLabel(1, "All collisions"); @@ -261,7 +279,8 @@ struct CascadeAnalysisLightIonsDerivedData { registryMC.get(HIST("number_of_events_mc_rec_vs_centrality"))->GetXaxis()->SetBinLabel(8, "kIsVertexTOFmatched"); registryMC.get(HIST("number_of_events_mc_rec_vs_centrality"))->GetXaxis()->SetBinLabel(9, "kIsVertexTRDmatched"); registryMC.get(HIST("number_of_events_mc_rec_vs_centrality"))->GetXaxis()->SetBinLabel(10, "kNoSameBunchPileup"); - registryMC.get(HIST("number_of_events_mc_rec_vs_centrality"))->GetXaxis()->SetBinLabel(11, "kINELgr0"); + registryMC.get(HIST("number_of_events_mc_rec_vs_centrality"))->GetXaxis()->SetBinLabel(11, "RCT flags"); + registryMC.get(HIST("number_of_events_mc_rec_vs_centrality"))->GetXaxis()->SetBinLabel(12, "kINELgr0"); registryMC.get(HIST("number_of_events_mc_rec_vs_centrality"))->GetYaxis()->SetTitle("Centrality (%)"); // QC Histograms @@ -342,7 +361,7 @@ struct CascadeAnalysisLightIonsDerivedData { } template - void initCCDB(TCollision collision) + void initCCDB(const TCollision& collision) { if (mRunNumber == collision.runNumber()) { return; @@ -836,12 +855,18 @@ struct CascadeAnalysisLightIonsDerivedData { registryData.fill(HIST("number_of_events_data"), 9 /* Not at same bunch pile-up */); registryData.fill(HIST("number_of_events_data_vs_centrality"), 9, centrality); - if (requireInel0 && collision.multNTracksPVeta1() < 1) { + if (!rctConfigurations.cfgRCTLabel.value.empty() && !rctFlagsChecker(collision)) { return; } - registryData.fill(HIST("number_of_events_data"), 10 /* INEL > 0 */); + registryData.fill(HIST("number_of_events_data"), 10 /* Pass CBT condition */); registryData.fill(HIST("number_of_events_data_vs_centrality"), 10, centrality); + if (requireInel0 && collision.multNTracksPVeta1() < 1) { + return; + } + registryData.fill(HIST("number_of_events_data"), 11 /* INEL > 0 */); + registryData.fill(HIST("number_of_events_data_vs_centrality"), 11, centrality); + // Store the Zvtx registryQC.fill(HIST("hVertexZdata"), collision.posZ()); @@ -985,12 +1010,18 @@ struct CascadeAnalysisLightIonsDerivedData { registryMC.fill(HIST("number_of_events_mc_rec"), 9 /* Not at same bunch pile-up */); registryMC.fill(HIST("number_of_events_mc_rec_vs_centrality"), 9, centralityMcRec); - if (requireInel0 && RecCol.multNTracksPVeta1() < 1) { + if (!rctConfigurations.cfgRCTLabel.value.empty() && !rctFlagsChecker(RecCol)) { return; } - registryMC.fill(HIST("number_of_events_mc_rec"), 10 /* INEL > 0 */); + registryMC.fill(HIST("number_of_events_mc_rec"), 10 /* Pass CBT condition */); registryMC.fill(HIST("number_of_events_mc_rec_vs_centrality"), 10, centralityMcRec); + if (requireInel0 && RecCol.multNTracksPVeta1() < 1) { + return; + } + registryMC.fill(HIST("number_of_events_mc_rec"), 11 /* INEL > 0 */); + registryMC.fill(HIST("number_of_events_mc_rec_vs_centrality"), 11, centralityMcRec); + // Store the Zvtx registryQC.fill(HIST("hVertexZRec"), RecCol.posZ()); @@ -1061,7 +1092,7 @@ struct CascadeAnalysisLightIonsDerivedData { bool isTrueMCCascadeDecay = false; bool isCorrectLambdaDecay = false; - if (isPhysPrim && (isXiMC || isOmegaMC)) + if (isXiMC || isOmegaMC) isTrueMCCascade = true; if (isTrueMCCascade && ((casc.sign() > 0 && cascMC.pdgCodePositive() == PDG_t::kPiPlus && cascMC.pdgCodeNegative() == PDG_t::kProtonBar) || (casc.sign() < 0 && cascMC.pdgCodePositive() == PDG_t::kProton && cascMC.pdgCodeNegative() == PDG_t::kPiMinus))) isCorrectLambdaDecay = true; diff --git a/PWGLF/Tasks/Strangeness/cascadecorrelations.cxx b/PWGLF/Tasks/Strangeness/cascadecorrelations.cxx index c73632268dd..48f11561b4f 100644 --- a/PWGLF/Tasks/Strangeness/cascadecorrelations.cxx +++ b/PWGLF/Tasks/Strangeness/cascadecorrelations.cxx @@ -300,7 +300,7 @@ struct CascadeSelector { } template - void fillMatchedHistos(LabeledCascades::iterator rec, int flag, TCollision collision) + void fillMatchedHistos(const LabeledCascades::iterator& rec, int flag, const TCollision& collision) { if (flag == 0) return; diff --git a/PWGLF/Tasks/Strangeness/cascpolsp.cxx b/PWGLF/Tasks/Strangeness/cascpolsp.cxx index 49f642f653d..123f9605154 100644 --- a/PWGLF/Tasks/Strangeness/cascpolsp.cxx +++ b/PWGLF/Tasks/Strangeness/cascpolsp.cxx @@ -243,7 +243,7 @@ struct cascpolsp { } template - bool IsCascAccepted(TCascade casc, collision_t collision) + bool IsCascAccepted(const TCascade& casc, const collision_t& collision) { if (casc.cascradius() < cfgcasc_radius) diff --git a/PWGLF/Tasks/Strangeness/derivedlambdakzeroanalysis.cxx b/PWGLF/Tasks/Strangeness/derivedlambdakzeroanalysis.cxx index 2a10605f42d..7a273765440 100644 --- a/PWGLF/Tasks/Strangeness/derivedlambdakzeroanalysis.cxx +++ b/PWGLF/Tasks/Strangeness/derivedlambdakzeroanalysis.cxx @@ -31,6 +31,7 @@ #include "PWGLF/DataModel/LFStrangenessMLTables.h" #include "PWGLF/DataModel/LFStrangenessPIDTables.h" #include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/mcCentrality.h" #include "PWGUD/Core/SGSelector.h" #include "Common/CCDB/EventSelectionParams.h" @@ -102,7 +103,7 @@ enum CentEstimator { struct derivedlambdakzeroanalysis { HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - bool isRun3; + bool isRun3 = true; // master analysis switches Configurable analyseK0Short{"analyseK0Short", true, "process K0Short-like candidates"}; @@ -113,6 +114,7 @@ struct derivedlambdakzeroanalysis { Configurable irSource{"irSource", "", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; Configurable centralityEstimator{"centralityEstimator", kCentFT0C, "Run 3 centrality estimator (0:CentFT0C, 1:CentFT0M, 2:CentFT0CVariant1, 3:CentMFT, 4:CentNGlobal, 5:CentFV0A)"}; Configurable doUPCanalysis{"doUPCanalysis", true, "Study V0s in hadronic and UPC collisions"}; + Configurable useMcCentrality{"useMcCentrality", false, "Use MC centrality?"}; Configurable doEventQA{"doEventQA", false, "do event QA histograms"}; Configurable doCompleteTopoQA{"doCompleteTopoQA", false, "do topological variable QA histograms"}; @@ -120,6 +122,7 @@ struct derivedlambdakzeroanalysis { Configurable doTOFQA{"doTOFQA", false, "do TOF QA histograms"}; Configurable doDetectPropQA{"doDetectPropQA", 0, "do Detector/ITS map QA: 0: no, 1: 4D, 2: 5D with mass; 3: plain in 3D"}; Configurable doEtaPhiQA{"doEtaPhiQA", false, "do Eta/Phi QA histograms"}; + Configurable doEventMCQA{"doEventMCQA", false, "do MC event QA histograms"}; Configurable doPlainTopoQA{"doPlainTopoQA", true, "do simple 1D QA of candidates"}; Configurable qaMinPt{"qaMinPt", 0.0f, "minimum pT for QA plots"}; @@ -130,7 +133,7 @@ struct derivedlambdakzeroanalysis { Configurable doMCAssociation{"doMCAssociation", true, "if MC, do MC association"}; Configurable doTreatPiToMuon{"doTreatPiToMuon", false, "Take pi decay into muon into account in MC"}; Configurable doCollisionAssociationQA{"doCollisionAssociationQA", true, "check collision association"}; - Configurable doSecondaryV0s{"doSecondaryV0s", false, "Look at secondary V0s?"}; + Configurable doSecondaryV0s{"doSecondaryV0s", 0, "Look at secondary V0s? 0: No; 1: yes via a loop on V0MCCores; 2: yes via a loop on CascMCCores"}; struct : ConfigurableGroup { std::string prefix = "eventSelections"; // JSON group name @@ -311,8 +314,8 @@ struct derivedlambdakzeroanalysis { o2::ccdb::CcdbApi ccdbApi; Service ccdb; ctpRateFetcher rateFetcher; - int mRunNumber; - float magField; + int mRunNumber = 0.; + float magField = 0.; std::map metadata; o2::parameters::GRPMagField* grpmag = nullptr; @@ -330,6 +333,7 @@ struct derivedlambdakzeroanalysis { ConfigurableAxis axisMultFT0M{"axisMultFT0M", {500, 0.0f, +100000.0f}, "Multiplicity FT0M"}; ConfigurableAxis axisMultFT0C{"axisMultFT0C", {500, 0.0f, +10000.0f}, "Multiplicity FT0C"}; ConfigurableAxis axisMultFV0A{"axisMultFV0A", {500, 0.0f, +100000.0f}, "Multiplicity FV0A"}; + ConfigurableAxis axisRapidity{"axisRapidity", {200, -1.0f, 1.0f}, "rapidity axis for analysis"}; ConfigurableAxis axisRawCentrality{"axisRawCentrality", {VARIABLE_WIDTH, 0.000f, 52.320f, 75.400f, 95.719f, 115.364f, 135.211f, 155.791f, 177.504f, 200.686f, 225.641f, 252.645f, 281.906f, 313.850f, 348.302f, 385.732f, 426.307f, 470.146f, 517.555f, 568.899f, 624.177f, 684.021f, 748.734f, 818.078f, 892.577f, 973.087f, 1058.789f, 1150.915f, 1249.319f, 1354.279f, 1465.979f, 1584.790f, 1710.778f, 1844.863f, 1985.746f, 2134.643f, 2291.610f, 2456.943f, 2630.653f, 2813.959f, 3006.631f, 3207.229f, 3417.641f, 3637.318f, 3865.785f, 4104.997f, 4354.938f, 4615.786f, 4885.335f, 5166.555f, 5458.021f, 5762.584f, 6077.881f, 6406.834f, 6746.435f, 7097.958f, 7462.579f, 7839.165f, 8231.629f, 8635.640f, 9052.000f, 9484.268f, 9929.111f, 10389.350f, 10862.059f, 11352.185f, 11856.823f, 12380.371f, 12920.401f, 13476.971f, 14053.087f, 14646.190f, 15258.426f, 15890.617f, 16544.433f, 17218.024f, 17913.465f, 18631.374f, 19374.983f, 20136.700f, 20927.783f, 21746.796f, 22590.880f, 23465.734f, 24372.274f, 25314.351f, 26290.488f, 27300.899f, 28347.512f, 29436.133f, 30567.840f, 31746.818f, 32982.664f, 34276.329f, 35624.859f, 37042.588f, 38546.609f, 40139.742f, 41837.980f, 43679.429f, 45892.130f, 400000.000f}, "raw centrality signal"}; // for QA @@ -437,24 +441,24 @@ struct derivedlambdakzeroanalysis { selPhysPrimAntiLambda, // for mc tagging }; - uint64_t maskTopological; - uint64_t maskTopoNoV0Radius; - uint64_t maskTopoNoDCANegToPV; - uint64_t maskTopoNoDCAPosToPV; - uint64_t maskTopoNoCosPA; - uint64_t maskTopoNoDCAV0Dau; - uint64_t maskTrackProperties; + uint64_t maskTopological = 0; + uint64_t maskTopoNoV0Radius = 0; + uint64_t maskTopoNoDCANegToPV = 0; + uint64_t maskTopoNoDCAPosToPV = 0; + uint64_t maskTopoNoCosPA = 0; + uint64_t maskTopoNoDCAV0Dau = 0; + uint64_t maskTrackProperties = 0; - uint64_t maskK0ShortSpecific; - uint64_t maskLambdaSpecific; - uint64_t maskAntiLambdaSpecific; + uint64_t maskK0ShortSpecific = 0; + uint64_t maskLambdaSpecific = 0; + uint64_t maskAntiLambdaSpecific = 0; - uint64_t maskSelectionK0Short; - uint64_t maskSelectionLambda; - uint64_t maskSelectionAntiLambda; + uint64_t maskSelectionK0Short = 0; + uint64_t maskSelectionLambda = 0; + uint64_t maskSelectionAntiLambda = 0; - uint64_t secondaryMaskSelectionLambda; - uint64_t secondaryMaskSelectionAntiLambda; + uint64_t secondaryMaskSelectionLambda = 0; + uint64_t secondaryMaskSelectionAntiLambda = 0; void init(InitContext const&) { @@ -733,6 +737,9 @@ struct derivedlambdakzeroanalysis { histos.add("hEventCentrality", "hEventCentrality", kTH1D, {axisConfigurations.axisCentralityFine}); histos.add("hCentralityVsNch", "hCentralityVsNch", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisNch}); + if (useMcCentrality) { + histos.add("hEventVsGenCentrality", "hEventVsGenCentrality", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisCentralityFine}); + } if (doEventQA) { if (isRun3) { histos.add("hEventSelectionVsCentrality", "hEventSelectionVsCentrality", kTH2D, {{23, -0.5f, +22.5f}, axisConfigurations.axisCentralityFine}); @@ -773,6 +780,13 @@ struct derivedlambdakzeroanalysis { } } + if (doEventMCQA) { + histos.add("hMultFT0MVsMultMC", "hMultFT0MVsMultMC;FT0M amplitude;#it{N}_{ch}(|#it{#eta}|<0.5)", kTH2D, {axisConfigurations.axisMultFT0M, axisConfigurations.axisNch}); + histos.add("hMultFT0CVsMultMC", "hMultFT0CVsMultMC;FT0C amplitude;#it{N}_{ch}(|#it{#eta}|<0.5)", kTH2D, {axisConfigurations.axisMultFT0C, axisConfigurations.axisNch}); + histos.add("hMultNGlobalVsMultMC", "hMultNGlobalVsMultMC;#it{N}_{ch}(global tracks);#it{N}_{ch} (|#it{#eta}|<0.5)", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisNch}); + histos.add("hMultFV0AVsMultMC", "hMultFV0AVsMultMC;FV0A amplitude;#it{N}_{ch}(|#it{#eta}|<0.5)", kTH2D, {axisConfigurations.axisMultFV0A, axisConfigurations.axisNch}); + } + histos.add("hEventPVz", "hEventPVz", kTH1D, {{100, -20.0f, +20.0f}}); histos.add("hCentralityVsPVz", "hCentralityVsPVz", kTH2D, {axisConfigurations.axisCentralityFine, {100, -20.0f, +20.0f}}); if (doprocessGeneratedRun3 || doprocessGeneratedRun2) { @@ -1188,12 +1202,23 @@ struct derivedlambdakzeroanalysis { histos.add("GeneralQA/h2dArmenterosAll", "h2dArmenterosAll", kTH2D, {axisConfigurations.axisAPAlpha, axisConfigurations.axisAPQt}); histos.add("GeneralQA/h2dArmenterosSelected", "h2dArmenterosSelected", kTH2D, {axisConfigurations.axisAPAlpha, axisConfigurations.axisAPQt}); + if (doprocessMonteCarloRun3 || doprocessMonteCarloRun2) { + histos.add("GeneralQA/h2dRapVsRapGen", "h2dRapVsRapGen;Rapidity;Generated rapidity", kTH2D, {axisConfigurations.axisRapidity, axisConfigurations.axisRapidity}); + histos.add("GeneralQA/h2dPtVsPtGen", "h2dPtVsPtGen;#it{p}_{T} (GeV/#it{c});#it{p}_{T}^{MC} (GeV/#it{c})", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPt}); + } + // Creation of histograms: MC generated if ((doprocessGeneratedRun3 || doprocessGeneratedRun2)) { - histos.add("hGenEvents", "hGenEvents", kTH2D, {{axisConfigurations.axisNch}, {2, -0.5f, +1.5f}}); - histos.get(HIST("hGenEvents"))->GetYaxis()->SetBinLabel(1, "All gen. events"); - histos.get(HIST("hGenEvents"))->GetYaxis()->SetBinLabel(2, "Gen. with at least 1 rec. events"); - histos.add("hGenEventCentrality", "hGenEventCentrality", kTH1D, {{101, 0.0f, 101.0f}}); + if (useMcCentrality) { + histos.add("hGenEventsVsMcCentrality", "hGenEventsVsMcCentrality", kTH2D, {axisConfigurations.axisCentralityFine, {2, -0.5f, +1.5f}}); + histos.get(HIST("hGenEventsVsMcCentrality"))->GetYaxis()->SetBinLabel(1, "All gen. events"); + histos.get(HIST("hGenEventsVsMcCentrality"))->GetYaxis()->SetBinLabel(2, "Gen. with at least 1 rec. events"); + } else { + histos.add("hGenEvents", "hGenEvents", kTH2D, {{axisConfigurations.axisNch}, {2, -0.5f, +1.5f}}); + histos.get(HIST("hGenEvents"))->GetYaxis()->SetBinLabel(1, "All gen. events"); + histos.get(HIST("hGenEvents"))->GetYaxis()->SetBinLabel(2, "Gen. with at least 1 rec. events"); + } + histos.add("hGenEventCentrality", "hGenEventCentrality", kTH1D, {axisConfigurations.axisCentralityFine}); histos.add("hCentralityVsNcoll_beforeEvSel", "hCentralityVsNcoll_beforeEvSel", kTH2D, {axisConfigurations.axisCentrality, {50, -0.5f, 49.5f}}); histos.add("hCentralityVsNcoll_afterEvSel", "hCentralityVsNcoll_afterEvSel", kTH2D, {axisConfigurations.axisCentrality, {50, -0.5f, 49.5f}}); @@ -1208,41 +1233,68 @@ struct derivedlambdakzeroanalysis { histos.add("h2dGenOmegaMinus", "h2dGenOmegaMinus", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); histos.add("h2dGenOmegaPlus", "h2dGenOmegaPlus", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); - histos.add("h2dGenK0ShortVsMultMC_RecoedEvt", "h2dGenK0ShortVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); - histos.add("h2dGenLambdaVsMultMC_RecoedEvt", "h2dGenLambdaVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); - histos.add("h2dGenAntiLambdaVsMultMC_RecoedEvt", "h2dGenAntiLambdaVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); - histos.add("h2dGenXiMinusVsMultMC_RecoedEvt", "h2dGenXiMinusVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); - histos.add("h2dGenXiPlusVsMultMC_RecoedEvt", "h2dGenXiPlusVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); - histos.add("h2dGenOmegaMinusVsMultMC_RecoedEvt", "h2dGenOmegaMinusVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); - histos.add("h2dGenOmegaPlusVsMultMC_RecoedEvt", "h2dGenOmegaPlusVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); - - histos.add("h2dGenK0ShortVsMultMC", "h2dGenK0ShortVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); - histos.add("h2dGenLambdaVsMultMC", "h2dGenLambdaVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); - histos.add("h2dGenAntiLambdaVsMultMC", "h2dGenAntiLambdaVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); - histos.add("h2dGenXiMinusVsMultMC", "h2dGenXiMinusVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); - histos.add("h2dGenXiPlusVsMultMC", "h2dGenXiPlusVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); - histos.add("h2dGenOmegaMinusVsMultMC", "h2dGenOmegaMinusVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); - histos.add("h2dGenOmegaPlusVsMultMC", "h2dGenOmegaPlusVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + if (useMcCentrality) { + histos.add("h2dGenK0ShortVsMcCentrality_RecoedEvt", "h2dGenK0ShortVsMcCentrality_RecoedEvt", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisPt}); + histos.add("h2dGenLambdaVsMcCentrality_RecoedEvt", "h2dGenLambdaVsMcCentrality_RecoedEvt", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisPt}); + histos.add("h2dGenAntiLambdaVsMcCentrality_RecoedEvt", "h2dGenAntiLambdaVsMcCentrality_RecoedEvt", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisPt}); + histos.add("h2dGenXiMinusVsMcCentrality_RecoedEvt", "h2dGenXiMinusVsMcCentrality_RecoedEvt", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisPt}); + histos.add("h2dGenXiPlusVsMcCentrality_RecoedEvt", "h2dGenXiPlusVsMcCentrality_RecoedEvt", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisPt}); + histos.add("h2dGenOmegaMinusVsMcCentrality_RecoedEvt", "h2dGenOmegaMinusVsMcCentrality_RecoedEvt", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisPt}); + histos.add("h2dGenOmegaPlusVsMcCentrality_RecoedEvt", "h2dGenOmegaPlusVsMcCentrality_RecoedEvt", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisPt}); + + histos.add("h2dGenK0ShortVsMcCentrality", "h2dGenK0ShortVsMcCentrality", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisPt}); + histos.add("h2dGenLambdaVsMcCentrality", "h2dGenLambdaVsMcCentrality", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisPt}); + histos.add("h2dGenAntiLambdaVsMcCentrality", "h2dGenAntiLambdaVsMcCentrality", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisPt}); + histos.add("h2dGenXiMinusVsMcCentrality", "h2dGenXiMinusVsMcCentrality", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisPt}); + histos.add("h2dGenXiPlusVsMcCentrality", "h2dGenXiPlusVsMcCentrality", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisPt}); + histos.add("h2dGenOmegaMinusVsMcCentrality", "h2dGenOmegaMinusVsMcCentrality", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisPt}); + histos.add("h2dGenOmegaPlusVsMcCentrality", "h2dGenOmegaPlusVsMcCentrality", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisPt}); + } else { + histos.add("h2dGenK0ShortVsMultMC_RecoedEvt", "h2dGenK0ShortVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenLambdaVsMultMC_RecoedEvt", "h2dGenLambdaVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenAntiLambdaVsMultMC_RecoedEvt", "h2dGenAntiLambdaVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenXiMinusVsMultMC_RecoedEvt", "h2dGenXiMinusVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenXiPlusVsMultMC_RecoedEvt", "h2dGenXiPlusVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenOmegaMinusVsMultMC_RecoedEvt", "h2dGenOmegaMinusVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenOmegaPlusVsMultMC_RecoedEvt", "h2dGenOmegaPlusVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + + histos.add("h2dGenK0ShortVsMultMC", "h2dGenK0ShortVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenLambdaVsMultMC", "h2dGenLambdaVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenAntiLambdaVsMultMC", "h2dGenAntiLambdaVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenXiMinusVsMultMC", "h2dGenXiMinusVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenXiPlusVsMultMC", "h2dGenXiPlusVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenOmegaMinusVsMultMC", "h2dGenOmegaMinusVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenOmegaPlusVsMultMC", "h2dGenOmegaPlusVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + } if (doSecondaryV0s) { + histos.add("h2dGenSecK0Short", "h2dGenSecK0Short", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); histos.add("h2dGenSecLambda", "h2dGenSecLambda", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); histos.add("h2dGenSecAntiLambda", "h2dGenSecAntiLambda", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); histos.add("h2dGenSecLambdaFromXi", "h2dGenSecLambdaFromXi", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); histos.add("h2dGenSecAntiLambdaFromXi", "h2dGenSecAntiLambdaFromXi", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGenSecLambdaFromXiAndXi0", "h2dGenSecLambdaFromXiAndXi0", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGenSecAntiLambdaFromXiAndXi0", "h2dGenSecAntiLambdaFromXiAndXi0", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); histos.add("h2dGenSecLambdaFromOmega", "h2dGenSecLambdaFromOmega", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); histos.add("h2dGenSecAntiLambdaFromOmega", "h2dGenSecAntiLambdaFromOmega", kTH2D, {axisConfigurations.axisCentrality, axisConfigurations.axisPt}); + histos.add("h2dGenSecK0ShortVsMultMC_RecoedEvt", "h2dGenSecK0ShortVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); histos.add("h2dGenSecLambdaVsMultMC_RecoedEvt", "h2dGenSecLambdaVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); histos.add("h2dGenSecAntiLambdaVsMultMC_RecoedEvt", "h2dGenSecAntiLambdaVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); histos.add("h2dGenSecLambdaFromXiVsMultMC_RecoedEvt", "h2dGenSecLambdaFromXiVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); histos.add("h2dGenSecAntiLambdaFromXiVsMultMC_RecoedEvt", "h2dGenSecAntiLambdaFromXiVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenSecLambdaFromXiAndXi0VsMultMC_RecoedEvt", "h2dGenSecLambdaFromXiAndXi0VsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenSecAntiLambdaFromXiAndXi0VsMultMC_RecoedEvt", "h2dGenSecAntiLambdaFromXiAndXi0VsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); histos.add("h2dGenSecLambdaFromOmegaVsMultMC_RecoedEvt", "h2dGenSecLambdaFromOmegaVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); histos.add("h2dGenSecAntiLambdaFromOmegaVsMultMC_RecoedEvt", "h2dGenSecAntiLambdaFromOmegaVsMultMC_RecoedEvt", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenSecK0ShortVsMultMC", "h2dGenSecK0ShortVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); histos.add("h2dGenSecLambdaVsMultMC", "h2dGenSecLambdaVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); histos.add("h2dGenSecAntiLambdaVsMultMC", "h2dGenSecAntiLambdaVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); histos.add("h2dGenSecLambdaFromXiVsMultMC", "h2dGenSecLambdaFromXiVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); histos.add("h2dGenSecAntiLambdaFromXiVsMultMC", "h2dGenSecAntiLambdaFromXiVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenSecLambdaFromXiAndXi0VsMultMC", "h2dGenSecLambdaFromXiAndXi0VsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); + histos.add("h2dGenSecAntiLambdaFromXiAndXi0VsMultMC", "h2dGenSecAntiLambdaFromXiAndXi0VsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); histos.add("h2dGenSecLambdaFromOmegaVsMultMC", "h2dGenSecLambdaFromOmegaVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); histos.add("h2dGenSecAntiLambdaFromOmegaVsMultMC", "h2dGenSecAntiLambdaFromOmegaVsMultMC", kTH2D, {axisConfigurations.axisNch, axisConfigurations.axisPt}); } @@ -1266,22 +1318,42 @@ struct derivedlambdakzeroanalysis { // If takeMcCentrality is enabled, the centrality is taken from the MC collision; otherwise it is taken // from the reconstructed collision. Returns -1 if no corresponding centrality estimator is found or if no MC collision is associated to the recoed collision. template - auto getCentralityRun3(TCollision const& collision) + auto getCentralityRun3(TCollision const& collision, bool takeMcCentrality = false) { - if (centralityEstimator == kCentFT0C) - return collision.centFT0C(); - else if (centralityEstimator == kCentFT0M) - return collision.centFT0M(); - else if (centralityEstimator == kCentFT0CVariant1) - return collision.centFT0CVariant1(); - else if (centralityEstimator == kCentMFT) - return collision.centMFT(); - else if (centralityEstimator == kCentNGlobal) - return collision.centNGlobal(); - else if (centralityEstimator == kCentFV0A) - return collision.centFV0A(); - - return -1.f; + // Helper lambda to extract centrality from any object exposing the cent* columns + auto extractCentrality = [this](auto const& coll) -> float { + switch (centralityEstimator) { + case kCentFT0C: + return coll.centFT0C(); + case kCentFT0M: + return coll.centFT0M(); + case kCentFT0CVariant1: + return coll.centFT0CVariant1(); + // case kCentMFT: return coll.centMFT(); + case kCentNGlobal: + return coll.centNGlobal(); + case kCentFV0A: + return coll.centFV0A(); + default: + return -1.f; + } + }; + + // check if we are in MC + if constexpr (requires { collision.straMCCollisionId(); }) { + if (takeMcCentrality) { // check if we need to extract centrality from recoed or generated collision + // if recoed collision has a MC collision, de-reference it and extract centrality from it + // otherwise return -1.f + if (collision.has_straMCCollision()) { + auto mcCollision = collision.template straMCCollision_as>(); + return extractCentrality(mcCollision); + } else { + return -1.f; + } + } + } + + return extractCentrality(collision); } // ______________________________________________________ @@ -1297,7 +1369,7 @@ struct derivedlambdakzeroanalysis { } template - void initCCDB(TCollision collision) + void initCCDB(TCollision const& collision) { if (mRunNumber == collision.runNumber()) { return; @@ -1358,7 +1430,7 @@ struct derivedlambdakzeroanalysis { } template - uint64_t computeReconstructionBitmap(TV0 v0, TCollision collision, float rapidityLambda, float rapidityK0Short, float /*pT*/) + uint64_t computeReconstructionBitmap(TV0 const& v0, TCollision const& collision, float rapidityLambda, float rapidityK0Short, float /*pT*/) // precalculate this information so that a check is one mask operation, not many { uint64_t bitMap = 0; @@ -1621,7 +1693,7 @@ struct derivedlambdakzeroanalysis { } template - uint64_t computeMCAssociation(TV0 v0) + uint64_t computeMCAssociation(TV0 const& v0) // precalculate this information so that a check is one mask operation, not many { uint64_t bitMap = 0; @@ -1804,7 +1876,7 @@ struct derivedlambdakzeroanalysis { } template - void analyseCandidate(TV0 v0, float pt, float centrality, uint64_t selMap, uint8_t gapSide, int& nK0Shorts, int& nLambdas, int& nAntiLambdas) + void analyseCandidate(TV0 const& v0, float pt, float rapidityLambda, float rapidityK0Short, float centrality, uint64_t selMap, uint8_t gapSide, int& nK0Shorts, int& nLambdas, int& nAntiLambdas) // precalculate this information so that a check is one mask operation, not many { bool passK0ShortSelections = false; @@ -1989,6 +2061,10 @@ struct derivedlambdakzeroanalysis { histos.fill(HIST("K0Short/h5dPosPhiVsEta"), centrality, v0.positivept(), invMassK0Short, v0.positivephi(), v0.positiveeta()); histos.fill(HIST("K0Short/h5dNegPhiVsEta"), centrality, v0.negativept(), invMassK0Short, v0.negativephi(), v0.negativeeta()); } + if (doprocessMonteCarloRun3 || doprocessMonteCarloRun2) { + histos.fill(HIST("GeneralQA/h2dRapVsRapGen"), v0.yK0Short(), rapidityK0Short); + histos.fill(HIST("GeneralQA/h2dPtVsPtGen"), v0.pt(), pt); + } nK0Shorts++; } if (passLambdaSelections && analyseLambda) { @@ -2075,6 +2151,10 @@ struct derivedlambdakzeroanalysis { histos.fill(HIST("Lambda/h5dPosPhiVsEta"), centrality, v0.positivept(), invMassLambda, v0.positivephi(), v0.positiveeta()); histos.fill(HIST("Lambda/h5dNegPhiVsEta"), centrality, v0.negativept(), invMassLambda, v0.negativephi(), v0.negativeeta()); } + if (doprocessMonteCarloRun3 || doprocessMonteCarloRun2) { + histos.fill(HIST("GeneralQA/h2dRapVsRapGen"), v0.yLambda(), rapidityLambda); + histos.fill(HIST("GeneralQA/h2dPtVsPtGen"), v0.pt(), pt); + } nLambdas++; } if (passAntiLambdaSelections && analyseAntiLambda) { @@ -2161,6 +2241,10 @@ struct derivedlambdakzeroanalysis { histos.fill(HIST("AntiLambda/h5dPosPhiVsEta"), centrality, v0.positivept(), invMassAntiLambda, v0.positivephi(), v0.positiveeta()); histos.fill(HIST("AntiLambda/h5dNegPhiVsEta"), centrality, v0.negativept(), invMassAntiLambda, v0.negativephi(), v0.negativeeta()); } + if (doprocessMonteCarloRun3 || doprocessMonteCarloRun2) { + histos.fill(HIST("GeneralQA/h2dRapVsRapGen"), v0.yLambda(), rapidityLambda); + histos.fill(HIST("GeneralQA/h2dPtVsPtGen"), v0.pt(), pt); + } nAntiLambdas++; } @@ -2207,7 +2291,7 @@ struct derivedlambdakzeroanalysis { } template - void analyseCollisionAssociation(TV0 /*v0*/, float pt, int mcNch, bool correctAssociation, uint64_t selMap) + void analyseCollisionAssociation(TV0 const& /*v0*/, float pt, int mcNch, bool correctAssociation, uint64_t selMap) // analyse collision association { // __________________________________________ @@ -2230,7 +2314,7 @@ struct derivedlambdakzeroanalysis { } template - void fillFeeddownMatrix(TV0 v0, float pt, float centrality, uint64_t selMap) + void fillFeeddownMatrix(TV0 const& v0, float pt, float centrality, uint64_t selMap) // fill feeddown matrix for Lambdas or AntiLambdas // fixme: a potential improvement would be to consider mass windows for the l/al { @@ -2284,7 +2368,7 @@ struct derivedlambdakzeroanalysis { } template - bool isEventAccepted(TCollision collision, bool fillHists) + bool isEventAccepted(TCollision const& collision, bool fillHists) // check whether the collision passes our collision selections { float centrality = -1.0f; @@ -2292,7 +2376,7 @@ struct derivedlambdakzeroanalysis { histos.fill(HIST("hEventSelection"), 0. /* all collisions */); if (doEventQA) { if constexpr (requires { collision.centFT0C(); }) { // check if we are in Run 3 - centrality = getCentralityRun3(collision); + centrality = getCentralityRun3(collision, useMcCentrality); } histos.fill(HIST("hEventSelectionVsCentrality"), 0. /* all collisions */, centrality); } @@ -2672,7 +2756,7 @@ struct derivedlambdakzeroanalysis { void fillReconstructedEventProperties(TCollision const& collision, float& centrality, float& collisionOccupancy, double& interactionRate, int& gapSide, int& selGapSide) { if constexpr (requires { collision.centFT0C(); }) { // check if we are in Run 3 - centrality = getCentralityRun3(collision); + centrality = getCentralityRun3(collision, useMcCentrality); collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); // Fetch interaction rate only if required (in order to limit ccdb calls) interactionRate = !irSource.value.empty() ? rateFetcher.fetch(ccdb.service, collision.timestamp(), collision.runNumber(), irSource) * 1.e-3 : -1; @@ -2682,6 +2766,10 @@ struct derivedlambdakzeroanalysis { centrality = hRawCentrality->GetBinContent(hRawCentrality->FindBin(centralityEstimator == kCentFT0M ? collision.multFT0A() + collision.multFT0C() : collision.multFT0C())); } + if (useMcCentrality) { + histos.fill(HIST("hEventVsGenCentrality"), getCentralityRun3(collision, false), getCentralityRun3(collision, true)); + } + if (doUPCanalysis) { // gap side gapSide = collision.gapSide(); @@ -2754,13 +2842,25 @@ struct derivedlambdakzeroanalysis { continue; } - histos.fill(HIST("hGenEvents"), mcCollision.multMCNParticlesEta05(), 0 /* all gen. events*/); + if constexpr (run3) { + if (useMcCentrality) { + histos.fill(HIST("hGenEventsVsMcCentrality"), getCentralityRun3(mcCollision), 0 /* all gen. events*/); + } else { + histos.fill(HIST("hGenEvents"), mcCollision.multMCNParticlesEta05(), 0 /* all gen. events*/); + } + } else { + histos.fill(HIST("hGenEvents"), mcCollision.multMCNParticlesEta05(), 0 /* all gen. events*/); + } auto groupedCollisions = getGroupedCollisions(collisions, mcCollision.globalIndex()); // Check if there is at least one of the reconstructed collisions associated to this MC collision // If so, we consider it bool atLeastOne = false; int biggestNContribs = -1; + float multFT0M = -1.f; + float multFT0C = -1.f; + float multNGlobal = -1.f; + float multFV0A = -1.f; float centrality = 100.5f; int nCollisions = 0; for (auto const& collision : groupedCollisions) { @@ -2772,7 +2872,11 @@ struct derivedlambdakzeroanalysis { if constexpr (run3) { // check if we are in Run 3 if (biggestNContribs < collision.multPVTotalContributors()) { biggestNContribs = collision.multPVTotalContributors(); - centrality = getCentralityRun3(collision); + centrality = getCentralityRun3(collision, useMcCentrality); + multFT0M = collision.multFT0A() + collision.multFT0C(); + multFT0C = collision.multFT0C(); + multNGlobal = collision.multNTracksGlobal(); + multFV0A = collision.multFV0A(); } } else { // we are in Run 2: there should be only one collision in groupedCollisions centrality = eventSelections.useSPDTrackletsCent ? collision.centRun2SPDTracklets() : collision.centRun2V0M(); @@ -2789,8 +2893,23 @@ struct derivedlambdakzeroanalysis { histos.fill(HIST("hCentralityVsPVzMC"), centrality, mcCollision.posZ()); histos.fill(HIST("hEventPVzMC"), mcCollision.posZ()); + if (doEventMCQA) { + histos.fill(HIST("hMultFT0MVsMultMC"), multFT0M, mcCollision.multMCNParticlesEta05()); + histos.fill(HIST("hMultFT0CVsMultMC"), multFT0C, mcCollision.multMCNParticlesEta05()); + histos.fill(HIST("hMultNGlobalVsMultMC"), multNGlobal, mcCollision.multMCNParticlesEta05()); + histos.fill(HIST("hMultFV0AVsMultMC"), multFV0A, mcCollision.multMCNParticlesEta05()); + } + if (atLeastOne) { - histos.fill(HIST("hGenEvents"), mcCollision.multMCNParticlesEta05(), 1 /* at least 1 rec. event*/); + if constexpr (run3) { + if (useMcCentrality) { + histos.fill(HIST("hGenEventsVsMcCentrality"), getCentralityRun3(mcCollision), 1 /* at least 1 rec. event*/); + } else { + histos.fill(HIST("hGenEvents"), mcCollision.multMCNParticlesEta05(), 1 /* at least 1 rec. event*/); + } + } else { + histos.fill(HIST("hGenEvents"), mcCollision.multMCNParticlesEta05(), 1 /* at least 1 rec. event*/); + } histos.fill(HIST("hGenEventCentrality"), centrality); } @@ -2852,7 +2971,7 @@ struct derivedlambdakzeroanalysis { BITSET(selMap, selPhysPrimLambda); BITSET(selMap, selPhysPrimAntiLambda); - analyseCandidate(v0, v0.pt(), centrality, selMap, selGapSide, nK0Shorts, nLambdas, nAntiLambdas); + analyseCandidate(v0, v0.pt(), v0.yLambda(), v0.yK0Short(), centrality, selMap, selGapSide, nK0Shorts, nLambdas, nAntiLambdas); } // end v0 loop // fill the histograms with the number of reconstructed K0s/Lambda/antiLambda per collision @@ -2869,8 +2988,8 @@ struct derivedlambdakzeroanalysis { // ______________________________________________________ // Simulated processing (subscribes to MC information too) - template - void analyzeRecoedV0sInMonteCarlo(TCollision const& collision, TV0s const& fullV0s) + template + void analyzeRecoedV0sInMonteCarlo(TCollision const& collision, TV0s const& fullV0s, TMCCollisions const& /*mcCollisions*/) { // Fire up CCDB if ((mlConfigurations.useK0ShortScores && mlConfigurations.calculateK0ShortScores) || @@ -2916,7 +3035,7 @@ struct derivedlambdakzeroanalysis { histos.fill(HIST("GeneralQA/h2dArmenterosAll"), v0.alpha(), v0.qtarm()); float ptmc = RecoDecay::sqrtSumOfSquares(v0MC.pxPosMC() + v0MC.pxNegMC(), v0MC.pyPosMC() + v0MC.pyNegMC()); - float ymc = 1e-3; + float ymc = 1e3; if (v0MC.pdgCode() == PDG_t::kK0Short) ymc = RecoDecay::y(std::array{v0MC.pxPosMC() + v0MC.pxNegMC(), v0MC.pyPosMC() + v0MC.pyNegMC(), v0MC.pzPosMC() + v0MC.pzNegMC()}, o2::constants::physics::MassKaonNeutral); else if (std::abs(v0MC.pdgCode()) == PDG_t::kLambda0) @@ -2940,14 +3059,14 @@ struct derivedlambdakzeroanalysis { BITSET(selMap, selPhysPrimAntiLambda); } - analyseCandidate(v0, ptmc, centrality, selMap, selGapSide, nK0Shorts, nLambdas, nAntiLambdas); + analyseCandidate(v0, ptmc, ymc, ymc, centrality, selMap, selGapSide, nK0Shorts, nLambdas, nAntiLambdas); if (doCollisionAssociationQA) { // check collision association explicitly bool correctCollision = false; int mcNch = -1; if (collision.has_straMCCollision()) { - auto mcCollision = collision.template straMCCollision_as>(); + auto mcCollision = collision.template straMCCollision_as(); mcNch = mcCollision.multMCNParticlesEta05(); correctCollision = (v0MC.straMCCollisionId() == mcCollision.globalIndex()); } @@ -2993,7 +3112,7 @@ struct derivedlambdakzeroanalysis { ymc > v0Selections.rapidityMaxCut) continue; - auto mcCollision = v0MC.template straMCCollision_as>(); + auto mcCollision = v0MC.template straMCCollision_as(); if (eventSelections.applyZVtxSelOnMCPV && std::abs(mcCollision.posZ()) > eventSelections.maxZVtxPosition) { continue; } @@ -3009,33 +3128,189 @@ struct derivedlambdakzeroanalysis { if (listBestCollisionIdx[mcCollision.globalIndex()] > -1) { auto collision = collisions.iteratorAt(listBestCollisionIdx[mcCollision.globalIndex()]); if constexpr (requires { collision.centFT0C(); }) { // check if we are in Run 3 - centrality = getCentralityRun3(collision); + centrality = getCentralityRun3(collision, useMcCentrality); } else { // no, we are in Run 2 centrality = eventSelections.useSPDTrackletsCent ? collision.centRun2SPDTracklets() : collision.centRun2V0M(); } if (v0MC.pdgCode() == PDG_t::kK0Short) { - histos.fill(HIST("h2dGenK0ShortVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + if constexpr (run3) { + if (useMcCentrality) { + histos.fill(HIST("h2dGenK0ShortVsMcCentrality_RecoedEvt"), getCentralityRun3(mcCollision), ptmc); + } else { + histos.fill(HIST("h2dGenK0ShortVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } else { + histos.fill(HIST("h2dGenK0ShortVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } } if (v0MC.pdgCode() == PDG_t::kLambda0) { - histos.fill(HIST("h2dGenLambdaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + if constexpr (run3) { + if (useMcCentrality) { + histos.fill(HIST("h2dGenLambdaVsMcCentrality_RecoedEvt"), getCentralityRun3(mcCollision), ptmc); + } else { + histos.fill(HIST("h2dGenLambdaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } else { + histos.fill(HIST("h2dGenLambdaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } } if (v0MC.pdgCode() == PDG_t::kLambda0Bar) { - histos.fill(HIST("h2dGenAntiLambdaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + if constexpr (run3) { + if (useMcCentrality) { + histos.fill(HIST("h2dGenAntiLambdaVsMcCentrality_RecoedEvt"), getCentralityRun3(mcCollision), ptmc); + } else { + histos.fill(HIST("h2dGenAntiLambdaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } else { + histos.fill(HIST("h2dGenAntiLambdaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } } } if (v0MC.pdgCode() == PDG_t::kK0Short) { histos.fill(HIST("h2dGenK0Short"), centrality, ptmc); - histos.fill(HIST("h2dGenK0ShortVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + if constexpr (run3) { + if (useMcCentrality) { + histos.fill(HIST("h2dGenK0ShortVsMcCentrality"), getCentralityRun3(mcCollision), ptmc); + } else { + histos.fill(HIST("h2dGenK0ShortVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } else { + histos.fill(HIST("h2dGenK0ShortVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } } if (v0MC.pdgCode() == PDG_t::kLambda0) { histos.fill(HIST("h2dGenLambda"), centrality, ptmc); - histos.fill(HIST("h2dGenLambdaVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + if constexpr (run3) { + if (useMcCentrality) { + histos.fill(HIST("h2dGenLambdaVsMcCentrality"), getCentralityRun3(mcCollision), ptmc); + } else { + histos.fill(HIST("h2dGenLambdaVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } else { + histos.fill(HIST("h2dGenLambdaVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } } if (v0MC.pdgCode() == PDG_t::kLambda0Bar) { histos.fill(HIST("h2dGenAntiLambda"), centrality, ptmc); - histos.fill(HIST("h2dGenAntiLambdaVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + if constexpr (run3) { + if (useMcCentrality) { + histos.fill(HIST("h2dGenAntiLambdaVsMcCentrality"), getCentralityRun3(mcCollision), ptmc); + } else { + histos.fill(HIST("h2dGenAntiLambdaVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } else { + histos.fill(HIST("h2dGenAntiLambdaVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } + } + + if (doSecondaryV0s == 1) { + for (auto const& v0MC : V0MCCores) { + if (!v0MC.has_straMCCollision()) + continue; + + if (v0MC.isPhysicalPrimary()) // select only secondary Lambda + continue; + + float ptmc = v0MC.ptMC(); + float ymc = 1e3; + if (v0MC.pdgCode() == PDG_t::kK0Short) + ymc = v0MC.rapidityMC(0); + else if (std::abs(v0MC.pdgCode()) == PDG_t::kLambda0) + ymc = v0MC.rapidityMC(1); + + if (ymc < v0Selections.rapidityMinCut || + ymc > v0Selections.rapidityMaxCut) + continue; + + auto mcCollision = v0MC.template straMCCollision_as(); + if (eventSelections.applyZVtxSelOnMCPV && std::abs(mcCollision.posZ()) > eventSelections.maxZVtxPosition) { + continue; + } + if (eventSelections.requireINEL0 && mcCollision.multMCNParticlesEta10() < 1) { + continue; + } + + if (eventSelections.requireINEL1 && mcCollision.multMCNParticlesEta10() < 2) { + continue; + } + + float centrality = 100.5f; + if (listBestCollisionIdx[mcCollision.globalIndex()] > -1) { + auto collision = collisions.iteratorAt(listBestCollisionIdx[mcCollision.globalIndex()]); + if constexpr (requires { collision.centFT0C(); }) { // check if we are in Run 3 + centrality = getCentralityRun3(collision, useMcCentrality); + } else { // no, we are in Run 2 + centrality = eventSelections.useSPDTrackletsCent ? collision.centRun2SPDTracklets() : collision.centRun2V0M(); + } + + if (v0MC.pdgCode() == PDG_t::kK0Short) { + histos.fill(HIST("h2dGenSecK0ShortVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCode() == PDG_t::kLambda0) { + histos.fill(HIST("h2dGenSecLambdaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + if (v0MC.pdgCodeMother() == PDG_t::kXiMinus) { + histos.fill(HIST("h2dGenSecLambdaFromXiVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCodeMother() == PDG_t::kXiMinus || v0MC.pdgCodeMother() == o2::constants::physics::Pdg::kXi0) { + histos.fill(HIST("h2dGenSecLambdaFromXiAndXi0VsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCodeMother() == PDG_t::kOmegaMinus) { + histos.fill(HIST("h2dGenSecLambdaFromOmegaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } + if (v0MC.pdgCode() == PDG_t::kLambda0Bar) { + histos.fill(HIST("h2dGenSecAntiLambdaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + if (v0MC.pdgCodeMother() == PDG_t::kXiPlusBar) { + histos.fill(HIST("h2dGenSecAntiLambdaFromXiVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCodeMother() == PDG_t::kXiPlusBar || v0MC.pdgCodeMother() == -o2::constants::physics::Pdg::kXi0) { + histos.fill(HIST("h2dGenSecAntiLambdaFromXiAndXi0VsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCodeMother() == PDG_t::kOmegaPlusBar) { + histos.fill(HIST("h2dGenSecAntiLambdaFromOmegaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } + } + + if (v0MC.pdgCode() == PDG_t::kK0Short) { + histos.fill(HIST("h2dGenSecK0Short"), centrality, ptmc); + histos.fill(HIST("h2dGenSecK0ShortVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCode() == PDG_t::kLambda0) { + histos.fill(HIST("h2dGenSecLambda"), centrality, ptmc); + histos.fill(HIST("h2dGenSecLambdaVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + if (v0MC.pdgCodeMother() == PDG_t::kXiMinus) { + histos.fill(HIST("h2dGenSecLambdaFromXi"), centrality, ptmc); + histos.fill(HIST("h2dGenSecLambdaFromXiVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCodeMother() == PDG_t::kXiMinus || v0MC.pdgCodeMother() == o2::constants::physics::Pdg::kXi0) { + histos.fill(HIST("h2dGenSecLambdaFromXiAndXi0"), centrality, ptmc); + histos.fill(HIST("h2dGenSecLambdaFromXiAndXi0VsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCodeMother() == PDG_t::kOmegaMinus) { + histos.fill(HIST("h2dGenSecLambdaFromOmega"), centrality, ptmc); + histos.fill(HIST("h2dGenSecLambdaFromOmegaVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } + if (v0MC.pdgCode() == PDG_t::kLambda0Bar) { + histos.fill(HIST("h2dGenSecAntiLambda"), centrality, ptmc); + histos.fill(HIST("h2dGenSecAntiLambdaVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + if (v0MC.pdgCodeMother() == PDG_t::kXiPlusBar) { + histos.fill(HIST("h2dGenSecAntiLambdaFromXi"), centrality, ptmc); + histos.fill(HIST("h2dGenSecAntiLambdaFromXiVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCodeMother() == PDG_t::kXiPlusBar || v0MC.pdgCodeMother() == -o2::constants::physics::Pdg::kXi0) { + histos.fill(HIST("h2dGenSecAntiLambdaFromXiAndXi0"), centrality, ptmc); + histos.fill(HIST("h2dGenSecAntiLambdaFromXiAndXi0VsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + if (v0MC.pdgCodeMother() == PDG_t::kOmegaPlusBar) { + histos.fill(HIST("h2dGenSecAntiLambdaFromOmega"), centrality, ptmc); + histos.fill(HIST("h2dGenSecAntiLambdaFromOmegaVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } } } @@ -3057,7 +3332,7 @@ struct derivedlambdakzeroanalysis { ymc > v0Selections.rapidityMaxCut) continue; - auto mcCollision = cascMC.template straMCCollision_as>(); + auto mcCollision = cascMC.template straMCCollision_as(); if (eventSelections.applyZVtxSelOnMCPV && std::abs(mcCollision.posZ()) > eventSelections.maxZVtxPosition) { continue; } @@ -3073,89 +3348,159 @@ struct derivedlambdakzeroanalysis { if (listBestCollisionIdx[mcCollision.globalIndex()] > -1) { auto collision = collisions.iteratorAt(listBestCollisionIdx[mcCollision.globalIndex()]); if constexpr (requires { collision.centFT0C(); }) { // check if we are in Run 3 - centrality = getCentralityRun3(collision); + centrality = getCentralityRun3(collision, useMcCentrality); } else { // no, we are in Run 2 centrality = eventSelections.useSPDTrackletsCent ? collision.centRun2SPDTracklets() : collision.centRun2V0M(); } if (cascMC.pdgCode() == PDG_t::kXiMinus) { - histos.fill(HIST("h2dGenXiMinusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + if constexpr (run3) { + if (useMcCentrality) { + histos.fill(HIST("h2dGenXiMinusVsMcCentrality_RecoedEvt"), getCentralityRun3(mcCollision), ptmc); + } else { + histos.fill(HIST("h2dGenXiMinusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } else { + histos.fill(HIST("h2dGenXiMinusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } } if (cascMC.pdgCode() == PDG_t::kXiPlusBar) { - histos.fill(HIST("h2dGenXiPlusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + if constexpr (run3) { + if (useMcCentrality) { + histos.fill(HIST("h2dGenXiPlusVsMcCentrality_RecoedEvt"), getCentralityRun3(mcCollision), ptmc); + } else { + histos.fill(HIST("h2dGenXiPlusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } else { + histos.fill(HIST("h2dGenXiPlusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } } if (cascMC.pdgCode() == PDG_t::kOmegaMinus) { - histos.fill(HIST("h2dGenOmegaMinusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + if constexpr (run3) { + if (useMcCentrality) { + histos.fill(HIST("h2dGenOmegaMinusVsMcCentrality_RecoedEvt"), getCentralityRun3(mcCollision), ptmc); + } else { + histos.fill(HIST("h2dGenOmegaMinusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } else { + histos.fill(HIST("h2dGenOmegaMinusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } } if (cascMC.pdgCode() == PDG_t::kOmegaPlusBar) { - histos.fill(HIST("h2dGenOmegaPlusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + if constexpr (run3) { + if (useMcCentrality) { + histos.fill(HIST("h2dGenOmegaPlusVsMcCentrality_RecoedEvt"), getCentralityRun3(mcCollision), ptmc); + } else { + histos.fill(HIST("h2dGenOmegaPlusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } else { + histos.fill(HIST("h2dGenOmegaPlusVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), ptmc); + } } - if (doSecondaryV0s && std::abs(cascMC.pdgCodeV0()) == kLambda0) { + if (doSecondaryV0s == 2 && std::abs(cascMC.pdgCodeV0()) == kLambda0) { float v0PtMc = std::hypot(cascMC.pxPosMC() + cascMC.pxNegMC(), cascMC.pyPosMC() + cascMC.pyNegMC()); - if (cascMC.pdgCodeV0() == kLambda0) { - histos.fill(HIST("h2dGenSecLambdaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), v0PtMc); - } - if (cascMC.pdgCodeV0() == kLambda0Bar) { - histos.fill(HIST("h2dGenSecAntiLambdaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), v0PtMc); - } - if (cascMC.pdgCode() == PDG_t::kXiMinus && cascMC.pdgCodeV0() == kLambda0) { - histos.fill(HIST("h2dGenSecLambdaFromXiVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), v0PtMc); - } - if (cascMC.pdgCode() == PDG_t::kXiPlusBar && cascMC.pdgCodeV0() == kLambda0Bar) { - histos.fill(HIST("h2dGenSecAntiLambdaFromXiVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), v0PtMc); - } - if (cascMC.pdgCode() == PDG_t::kOmegaMinus && cascMC.pdgCodeV0() == kLambda0) { - histos.fill(HIST("h2dGenSecLambdaFromOmegaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), v0PtMc); - } - if (cascMC.pdgCode() == PDG_t::kOmegaPlusBar && cascMC.pdgCodeV0() == kLambda0Bar) { - histos.fill(HIST("h2dGenSecAntiLambdaFromOmegaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), v0PtMc); + float v0RapMc = RecoDecay::y(std::array{cascMC.pxPosMC() + cascMC.pxNegMC(), cascMC.pyPosMC() + cascMC.pyNegMC(), cascMC.pzPosMC() + cascMC.pzNegMC()}, o2::constants::physics::MassLambda); + if (v0Selections.rapidityMinCut < v0RapMc && v0RapMc < v0Selections.rapidityMaxCut) { + if (cascMC.pdgCodeV0() == kLambda0) { + histos.fill(HIST("h2dGenSecLambdaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), v0PtMc); + } + if (cascMC.pdgCodeV0() == kLambda0Bar) { + histos.fill(HIST("h2dGenSecAntiLambdaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), v0PtMc); + } + if (cascMC.pdgCode() == PDG_t::kXiMinus && cascMC.pdgCodeV0() == kLambda0) { + histos.fill(HIST("h2dGenSecLambdaFromXiVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), v0PtMc); + } + if (cascMC.pdgCode() == PDG_t::kXiPlusBar && cascMC.pdgCodeV0() == kLambda0Bar) { + histos.fill(HIST("h2dGenSecAntiLambdaFromXiVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), v0PtMc); + } + if (cascMC.pdgCode() == PDG_t::kOmegaMinus && cascMC.pdgCodeV0() == kLambda0) { + histos.fill(HIST("h2dGenSecLambdaFromOmegaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), v0PtMc); + } + if (cascMC.pdgCode() == PDG_t::kOmegaPlusBar && cascMC.pdgCodeV0() == kLambda0Bar) { + histos.fill(HIST("h2dGenSecAntiLambdaFromOmegaVsMultMC_RecoedEvt"), mcCollision.multMCNParticlesEta05(), v0PtMc); + } } } } if (cascMC.pdgCode() == PDG_t::kXiMinus) { histos.fill(HIST("h2dGenXiMinus"), centrality, ptmc); - histos.fill(HIST("h2dGenXiMinusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + if constexpr (run3) { + if (useMcCentrality) { + histos.fill(HIST("h2dGenXiMinusVsMcCentrality"), getCentralityRun3(mcCollision), ptmc); + } else { + histos.fill(HIST("h2dGenXiMinusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } else { + histos.fill(HIST("h2dGenXiMinusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } } if (cascMC.pdgCode() == PDG_t::kXiPlusBar) { histos.fill(HIST("h2dGenXiPlus"), centrality, ptmc); - histos.fill(HIST("h2dGenXiPlusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + if constexpr (run3) { + if (useMcCentrality) { + histos.fill(HIST("h2dGenXiPlusVsMcCentrality"), getCentralityRun3(mcCollision), ptmc); + } else { + histos.fill(HIST("h2dGenXiPlusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } else { + histos.fill(HIST("h2dGenXiPlusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } } if (cascMC.pdgCode() == PDG_t::kOmegaMinus) { histos.fill(HIST("h2dGenOmegaMinus"), centrality, ptmc); - histos.fill(HIST("h2dGenOmegaMinusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + if constexpr (run3) { + if (useMcCentrality) { + histos.fill(HIST("h2dGenOmegaMinusVsMcCentrality"), getCentralityRun3(mcCollision), ptmc); + } else { + histos.fill(HIST("h2dGenOmegaMinusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } else { + histos.fill(HIST("h2dGenOmegaMinusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } } if (cascMC.pdgCode() == PDG_t::kOmegaPlusBar) { histos.fill(HIST("h2dGenOmegaPlus"), centrality, ptmc); - histos.fill(HIST("h2dGenOmegaPlusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + if constexpr (run3) { + if (useMcCentrality) { + histos.fill(HIST("h2dGenOmegaPlusVsMcCentrality"), getCentralityRun3(mcCollision), ptmc); + } else { + histos.fill(HIST("h2dGenOmegaPlusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } + } else { + histos.fill(HIST("h2dGenOmegaPlusVsMultMC"), mcCollision.multMCNParticlesEta05(), ptmc); + } } - if (doSecondaryV0s && std::abs(cascMC.pdgCodeV0()) == kLambda0) { + if (doSecondaryV0s == 2 && std::abs(cascMC.pdgCodeV0()) == kLambda0) { float v0PtMc = std::hypot(cascMC.pxPosMC() + cascMC.pxNegMC(), cascMC.pyPosMC() + cascMC.pyNegMC()); - if (cascMC.pdgCodeV0() == kLambda0) { - histos.fill(HIST("h2dGenSecLambda"), centrality, v0PtMc); - histos.fill(HIST("h2dGenSecLambdaVsMultMC"), mcCollision.multMCNParticlesEta05(), v0PtMc); - } - if (cascMC.pdgCodeV0() == kLambda0Bar) { - histos.fill(HIST("h2dGenSecAntiLambda"), centrality, v0PtMc); - histos.fill(HIST("h2dGenSecAntiLambdaVsMultMC"), mcCollision.multMCNParticlesEta05(), v0PtMc); - } - if (cascMC.pdgCode() == PDG_t::kXiMinus && cascMC.pdgCodeV0() == kLambda0) { - histos.fill(HIST("h2dGenSecLambdaFromXi"), centrality, v0PtMc); - histos.fill(HIST("h2dGenSecLambdaFromXiVsMultMC"), mcCollision.multMCNParticlesEta05(), v0PtMc); - } - if (cascMC.pdgCode() == PDG_t::kXiPlusBar && cascMC.pdgCodeV0() == kLambda0Bar) { - histos.fill(HIST("h2dGenSecAntiLambdaFromXi"), centrality, v0PtMc); - histos.fill(HIST("h2dGenSecAntiLambdaFromXiVsMultMC"), mcCollision.multMCNParticlesEta05(), v0PtMc); - } - if (cascMC.pdgCode() == PDG_t::kOmegaMinus && cascMC.pdgCodeV0() == kLambda0) { - histos.fill(HIST("h2dGenSecLambdaFromOmega"), centrality, v0PtMc); - histos.fill(HIST("h2dGenSecLambdaFromOmegaVsMultMC"), mcCollision.multMCNParticlesEta05(), v0PtMc); - } - if (cascMC.pdgCode() == PDG_t::kOmegaPlusBar && cascMC.pdgCodeV0() == kLambda0Bar) { - histos.fill(HIST("h2dGenSecAntiLambdaFromOmega"), centrality, v0PtMc); - histos.fill(HIST("h2dGenSecAntiLambdaFromOmegaVsMultMC"), mcCollision.multMCNParticlesEta05(), v0PtMc); + float v0RapMc = RecoDecay::y(std::array{cascMC.pxPosMC() + cascMC.pxNegMC(), cascMC.pyPosMC() + cascMC.pyNegMC(), cascMC.pzPosMC() + cascMC.pzNegMC()}, o2::constants::physics::MassLambda); + if (v0Selections.rapidityMinCut < v0RapMc && v0RapMc < v0Selections.rapidityMaxCut) { + if (cascMC.pdgCodeV0() == kLambda0) { + histos.fill(HIST("h2dGenSecLambda"), centrality, v0PtMc); + histos.fill(HIST("h2dGenSecLambdaVsMultMC"), mcCollision.multMCNParticlesEta05(), v0PtMc); + } + if (cascMC.pdgCodeV0() == kLambda0Bar) { + histos.fill(HIST("h2dGenSecAntiLambda"), centrality, v0PtMc); + histos.fill(HIST("h2dGenSecAntiLambdaVsMultMC"), mcCollision.multMCNParticlesEta05(), v0PtMc); + } + if (cascMC.pdgCode() == PDG_t::kXiMinus && cascMC.pdgCodeV0() == kLambda0) { + histos.fill(HIST("h2dGenSecLambdaFromXi"), centrality, v0PtMc); + histos.fill(HIST("h2dGenSecLambdaFromXiVsMultMC"), mcCollision.multMCNParticlesEta05(), v0PtMc); + } + if (cascMC.pdgCode() == PDG_t::kXiPlusBar && cascMC.pdgCodeV0() == kLambda0Bar) { + histos.fill(HIST("h2dGenSecAntiLambdaFromXi"), centrality, v0PtMc); + histos.fill(HIST("h2dGenSecAntiLambdaFromXiVsMultMC"), mcCollision.multMCNParticlesEta05(), v0PtMc); + } + if (cascMC.pdgCode() == PDG_t::kOmegaMinus && cascMC.pdgCodeV0() == kLambda0) { + histos.fill(HIST("h2dGenSecLambdaFromOmega"), centrality, v0PtMc); + histos.fill(HIST("h2dGenSecLambdaFromOmegaVsMultMC"), mcCollision.multMCNParticlesEta05(), v0PtMc); + } + if (cascMC.pdgCode() == PDG_t::kOmegaPlusBar && cascMC.pdgCodeV0() == kLambda0Bar) { + histos.fill(HIST("h2dGenSecAntiLambdaFromOmega"), centrality, v0PtMc); + histos.fill(HIST("h2dGenSecAntiLambdaFromOmegaVsMultMC"), mcCollision.multMCNParticlesEta05(), v0PtMc); + } } } } @@ -3194,21 +3539,21 @@ struct derivedlambdakzeroanalysis { // ______________________________________________________ // Simulated processing in Run 3 (subscribes to MC information too) - void processMonteCarloRun3(soa::Join::iterator const& collision, V0McCandidates const& fullV0s, DauTracks const&, aod::MotherMCParts const&, soa::Join const& /*mccollisions*/, soa::Join const&) + void processMonteCarloRun3(soa::Join::iterator const& collision, V0McCandidates const& fullV0s, DauTracks const&, aod::MotherMCParts const&, soa::Join const& mccollisions, soa::Join const&) { - analyzeRecoedV0sInMonteCarlo(collision, fullV0s); + analyzeRecoedV0sInMonteCarlo(collision, fullV0s, mccollisions); } // ______________________________________________________ // Simulated processing in Run 2 (subscribes to MC information too) - void processMonteCarloRun2(soa::Join::iterator const& collision, V0McCandidates const& fullV0s, DauTracks const&, aod::MotherMCParts const&, soa::Join const& /*mccollisions*/, soa::Join const&) + void processMonteCarloRun2(soa::Join::iterator const& collision, V0McCandidates const& fullV0s, DauTracks const&, aod::MotherMCParts const&, soa::Join const& mccollisions, soa::Join const&) { - analyzeRecoedV0sInMonteCarlo(collision, fullV0s); + analyzeRecoedV0sInMonteCarlo(collision, fullV0s, mccollisions); } // ______________________________________________________ // Simulated processing in Run 3 (subscribes to MC information too) - void processGeneratedRun3(soa::Join const& mcCollisions, soa::Join const& V0MCCores, soa::Join const& CascMCCores, soa::Join const& collisions) + void processGeneratedRun3(soa::Join const& mcCollisions, soa::Join const& V0MCCores, soa::Join const& CascMCCores, soa::Join const& collisions) { analyzeGeneratedV0s(mcCollisions, V0MCCores, CascMCCores, collisions); } diff --git a/PWGLF/Tasks/Strangeness/derivedupcanalysis.cxx b/PWGLF/Tasks/Strangeness/derivedupcanalysis.cxx index 766593fd89f..1741b68afa0 100644 --- a/PWGLF/Tasks/Strangeness/derivedupcanalysis.cxx +++ b/PWGLF/Tasks/Strangeness/derivedupcanalysis.cxx @@ -489,7 +489,7 @@ struct Derivedupcanalysis { } template - void fillHistogramsV0(TCand cand, TCollision coll, int gap) + void fillHistogramsV0(const TCand& cand, const TCollision& coll, int gap) { float invMass = 0; float ft0ampl = -1.f; @@ -614,7 +614,7 @@ struct Derivedupcanalysis { } template - void fillHistogramsCasc(TCand cand, TCollision coll, const int gap) + void fillHistogramsCasc(const TCand& cand, const TCollision& coll, const int gap) { float invMass = 0; float centrality = -1.f; diff --git a/PWGLF/Tasks/Strangeness/forwardlambdakzeroanalysis.cxx b/PWGLF/Tasks/Strangeness/forwardlambdakzeroanalysis.cxx index 0fc840af0f0..a54014ed606 100644 --- a/PWGLF/Tasks/Strangeness/forwardlambdakzeroanalysis.cxx +++ b/PWGLF/Tasks/Strangeness/forwardlambdakzeroanalysis.cxx @@ -28,15 +28,15 @@ // david.dobrigkeit.chinellato@cern.ch // -#include "PWGLF/DataModel/mcCentrality.h" #include "PWGMM/Mult/DataModel/bestCollisionTable.h" #include "PWGUD/Core/SGSelector.h" #include "Common/CCDB/EventSelectionParams.h" #include "Common/CCDB/RCTSelectionFlags.h" -#include "Common/CCDB/TriggerAliases.h" #include "Common/CCDB/ctpRateFetcher.h" #include "Common/Core/RecoDecay.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" #include @@ -45,25 +45,29 @@ #include #include #include +#include +#include #include #include #include #include #include -#include #include #include #include #include #include +#include +#include +#include +#include +#include #include #include -#include +#include #include -#include - -#include +#include #include #include @@ -122,6 +126,9 @@ struct forwardlambdakzeroanalysis { Configurable doTreatPiToMuon{"doTreatPiToMuon", false, "Take pi decay into muon into account in MC"}; Configurable doMCAssociation{"doMCAssociation", true, "if MC, do MC association"}; + // propagation option + Configurable useNewPropagationToVtx{"useNewPropagationToVtx", true, "Use propagation to vtx based on propagateToDCAhelix (most recent) instead of the one based on propagateToVtxhelixWithMCS"}; + struct : ConfigurableGroup { std::string prefix = "eventSelections"; // JSON group name Configurable requireSel8{"requireSel8", true, "require sel8 event selection"}; @@ -138,6 +145,8 @@ struct forwardlambdakzeroanalysis { Configurable requireNoCollInTimeRangeNarrow{"requireNoCollInTimeRangeNarrow", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds (Run 3 only)"}; Configurable requireNoCollInROFStd{"requireNoCollInROFStd", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF with mult. above a certain threshold (Run 3 only)"}; Configurable requireNoCollInROFStrict{"requireNoCollInROFStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF (Run 3 only)"}; + Configurable requireNoHighMultCollInPrevRof{"requireNoHighMultCollInPrevRof", false, "reject collisions if previous ROF has high multiplicity (Run 3 only)"}; + Configurable requireIsGoodITSLayersAll{"requireIsGoodITSLayersAll", false, "require that the number of inactive chips on all ITS layers is below the maximum allowed values"}; Configurable requireINEL0{"requireINEL0", true, "require INEL>0 event selection"}; Configurable requireINEL1{"requireINEL1", false, "require INEL>1 event selection"}; @@ -156,6 +165,15 @@ struct forwardlambdakzeroanalysis { static constexpr float DefaultLifetimeCuts[1][3] = {{20., 30., 20.}}; + // Armenteros-Podolanski elliptic band: inner and outer ellipse half-axes, in units of the ideal + // two-body ones. The alpha and qT axes are scaled independently, so the band can be made much + // wider in alpha than in qT (the resolution smears the two very differently, in particular for + // Lambda, whose ideal alpha half-width is only ~0.18). A zero inner scale means "no inner ellipse". + // Columns: alphaScaleMin, qtScaleMin, alphaScaleMax, qtScaleMax + static constexpr float DefaultArmPodBand[3][4] = {{0.60, 0.60, 1.15, 1.35}, // K0Short + {0.00, 0.00, 2.00, 1.50}, // Lambda + {0.00, 0.00, 1.30, 1.30}}; // D0 + struct : ConfigurableGroup { std::string prefix = "v0Selections"; // JSON group name @@ -164,7 +182,10 @@ struct forwardlambdakzeroanalysis { Configurable rapidityMax{"rapidityMax", 0.5, "max rapidity"}; Configurable daughterEtaCutMin{"daughterEtaCutMin", 0.8, "min eta for daughters"}; Configurable daughterEtaCutMax{"daughterEtaCutMax", 0.8, "max eta for daughters"}; - Configurable minTrackPt{"minTrackPt", 0.8, "min track pT (GeV/c)"}; + Configurable minTrackPt{"minTrackPt", 0., "min track pT (GeV/c)"}; + Configurable maxTrackPt{"maxTrackPt", 1e+09, "max track pT (GeV/c)"}; + Configurable minTrackPz{"minTrackPz", -1e+09, "min track pZ (GeV/c)"}; + Configurable maxTrackPz{"maxTrackPz", 1e+09, "max track pZ (GeV/c)"}; // Standard 5 topological criteria Configurable v0CosPA{"v0CosPA", 0.97, "min V0 CosPA"}; @@ -181,6 +202,7 @@ struct forwardlambdakzeroanalysis { Configurable minPseudolifetime{"minPseudolifetime", -1e+09, "minimum V0 pseudo-proper lifetime (cm)"}; Configurable maxPseudolifetime{"maxPseudolifetime", 1e+09, "maximum V0 pseudo-proper lifetime (cm)"}; Configurable> lifetimeCut{"lifetimeCut", {DefaultLifetimeCuts[0], 3, {"lifetimecutD0", "lifetimecutLambda", "lifetimecutK0S"}}, "lifetimeCut"}; + Configurable rejectFailedPropagation{"rejectFailedPropagation", true, "Reject tracks which could not be propagated to the primary vertex (DCA = DefaultDCA = 999.)"}; // invariant mass selection Configurable compMassRejectionK0Short{"compMassRejectionK0Short", -1, "Competing K^{0}_{S} mass rejection (GeV/#it{c}^{2})"}; @@ -189,6 +211,27 @@ struct forwardlambdakzeroanalysis { // Additional selection on the AP plot (exclusive for K0Short) // original equation: lArmPt*5>TMath::Abs(lArmAlpha) Configurable armPodCut{"armPodCut", 5.0f, "pT * (cut) > |alpha|, AP cut. Negative: no cut"}; + Configurable minQt{"minQt", -1, "Min Arm. Qt. Negative value means not cut"}; + Configurable maxQt{"maxQt", 1e+09, "Max Arm Qt."}; + Configurable minAlpha{"minAlpha", -1e+09, "Min Arm. Alpha."}; + Configurable maxAlpha{"maxAlpha", 1e+09, "Max Arm Alpha."}; + + // Armenteros-Podolanski elliptic band: keeps only the two-body decay arc of a given species. + // A decay M -> pos + neg populates the ellipse + // ((alpha - alphaCenter) / alphaHalfWidth)^2 + (qT / qStar)^2 = 1 + // with, in the mother rest frame, qStar the daughter momentum (= maximum qT), + // alphaCenter = (E*_pos - E*_neg) / M and alphaHalfWidth = 2 qStar / (beta M). + // The band is the crescent between two ellipses concentric with that one, each with its two + // half-axes scaled independently (the reconstructed distribution is smeared much more along + // alpha than along qT, so a single scale factor for both axes does not describe it): + // qT_up (alpha) = qtScaleMax * qStar * sqrt(1 - ((alpha - alphaCenter) / (alphaScaleMax * alphaHalfWidth))^2) + // qT_low(alpha) = qtScaleMin * qStar * sqrt(1 - ((alpha - alphaCenter) / (alphaScaleMin * alphaHalfWidth))^2) + // (square roots set to zero where their argument is negative). A candidate is kept if it lies + // inside the outer ellipse and outside the inner one; setting an inner scale to zero drops the + // inner ellipse altogether, i.e. keeps the whole filled outer ellipse. + Configurable useArmPodBand{"useArmPodBand", false, "Select the Armenteros-Podolanski arc with an elliptic band (per-species)"}; + Configurable armPodBandUseBeta{"armPodBandUseBeta", true, "Scale the alpha half-width by 1/beta of the candidate (exact ellipse). If false, use the beta -> 1 limit"}; + Configurable> armPodBand{"armPodBand", {DefaultArmPodBand[0], 3, 4, {"K0Short", "Lambda", "D0"}, {"alphaScaleMin", "qtScaleMin", "alphaScaleMax", "qtScaleMax"}}, "Arm.-Pod. band: inner and outer ellipse half-axes, in units of the ideal ones"}; // Track quality Configurable minMFTclusters{"minMFTclusters", -1, "minimum MFT clusters"}; @@ -221,19 +264,21 @@ struct forwardlambdakzeroanalysis { } ccdbConfigurations; o2::ccdb::CcdbApi ccdbApi; - Service ccdb; + Service ccdb{}; ctpRateFetcher rateFetcher; - int mRunNumber; - float magField; + int mRunNumber = 0; + float magField = 0.; std::map metadata; o2::parameters::GRPMagField* grpmag = nullptr; // CCDB options struct : ConfigurableGroup { ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for analysis"}; + ConfigurableAxis axisPz{"axisPz", {100, -10, 10}, "pz axis for analysis"}; ConfigurableAxis axisPtXi{"axisPtXi", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for feeddown from Xi"}; ConfigurableAxis axisPtCoarse{"axisPtCoarse", {VARIABLE_WIDTH, 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 7.0f, 10.0f, 15.0f}, "pt axis for QA"}; - ConfigurableAxis axisPtResol{"axisPtResol", {100, -1.0f, 1.0f}, "Axis for momentum resolution (GeV/c)"}; + ConfigurableAxis axisPtResol{"axisPtResol", {100, -1.0f, 1.0f}, "Axis for transverse momentum resolution (GeV/c)"}; + ConfigurableAxis axisPzResol{"axisPzResol", {100, -1.0f, 1.0f}, "Axis for longitudinal momentum resolution (GeV/c)"}; ConfigurableAxis axisK0Mass{"axisK0Mass", {200, 0.4f, 0.6f}, "Axis for K0S invariant mass (GeV/c2)"}; ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.101f, 1.131f}, "Axis for Lambda invariant mass (GeV/c2)"}; ConfigurableAxis axisD0Mass{"axisD0Mass", {200, 1.75f, 1.95f}, "Axis for D0 invariant mass (GeV/c2)"}; @@ -264,6 +309,8 @@ struct forwardlambdakzeroanalysis { ConfigurableAxis axisMFTchi2{"axisMFTchi2", {1000, 0.0f, 1000.0f}, "#chi^{2}"}; ConfigurableAxis axisMFTchi2NDF{"axisMFTchi2NDF", {100, 0.0f, 100.0f}, "#chi^{2} per MFT clusters"}; ConfigurableAxis axisMFTclus{"axisMFTclus", {10, 0.0f, 10.0f}, "N MFT Clusters"}; + ConfigurableAxis axisPosition{"axisPosition", {100, -50, 50.0f}, "Position x, y, z (cm)"}; + ConfigurableAxis axisPositionDiff{"axisPositionDiff", {100, -10.0f, 10.0f}, "Position x, y, z recoed - generated (cm)"}; // UPC axes ConfigurableAxis axisSelGap{"axisSelGap", {4, -1.5, 2.5}, "Gap side"}; @@ -298,7 +345,7 @@ struct forwardlambdakzeroanalysis { Configurable useTGeoMatCorr{"useTGeoMatCorr", false, "Use material TGeo correction, instead of LUT material correction or no material correction."}; } fitterConfigurations; - o2::base::MatLayerCylSet* lut; // material LUT for DCA fitter + o2::base::MatLayerCylSet* lut{}; // material LUT for DCA fitter o2::vertexing::FwdDCAFitterN<2> fitter; // Taken from https://github.com/AliceO2Group/O2Physics/blob/master/PWGLF/TableProducer/Strangeness/sigma0builder.cxx#L319 @@ -310,6 +357,7 @@ struct forwardlambdakzeroanalysis { float Y = -999.f; float Z = -999.f; float Radius = -999.f; + float Zdist = -999.f; std::array positiveMomentum = {0.0f, 0.0f, 0.0f}; std::array negativeMomentum = {0.0f, 0.0f, 0.0f}; float dcaPosToPVxy = -999.f; @@ -347,6 +395,8 @@ struct forwardlambdakzeroanalysis { float xMc = -999.f; float yMc = -999.f; float zMc = -999.f; + float RadiusMc = -999.f; + float ZdistMc = -999.f; std::array momentumMc = {0.0f, 0.0f, 0.0f}; std::array positiveMomentumMc = {0.0f, 0.0f, 0.0f}; std::array negativeMomentumMc = {0.0f, 0.0f, 0.0f}; @@ -364,6 +414,15 @@ struct forwardlambdakzeroanalysis { int mcCollision = -1; bool isPhysicalPrimary = false; bool motherIsPhysicalPrimary = false; + + float positivePt() const { return std::hypot(positiveMomentum[0], positiveMomentum[1]); } + float negativePt() const { return std::hypot(negativeMomentum[0], negativeMomentum[1]); } + float positivePz() const { return positiveMomentum[2]; } + float negativePz() const { return negativeMomentum[2]; } + float positivePtMc() const { return std::hypot(positiveMomentumMc[0], positiveMomentumMc[1]); } + float negativePtMc() const { return std::hypot(negativeMomentumMc[0], negativeMomentumMc[1]); } + float positivePzMc() const { return positiveMomentumMc[2]; } + float negativePzMc() const { return negativeMomentumMc[2]; } }; // For manual sliceBy @@ -399,6 +458,10 @@ struct forwardlambdakzeroanalysis { selD0PseudoLifetimeMin, selD0PseudoLifetimeMax, selK0ShortArmenteros, + selLambdaArmenteros, + selAntiLambdaArmenteros, + selD0Armenteros, + selAntiD0Armenteros, selPosGoodMFTTrack, selNegGoodMFTTrack, selConsiderK0Short, // for mc tagging @@ -413,23 +476,23 @@ struct forwardlambdakzeroanalysis { selPhysPrimAntiD0, // for mc tagging }; - uint64_t maskTopological; - uint64_t maskTrackProperties; + uint64_t maskTopological = 0; + uint64_t maskTrackProperties = 0; - uint64_t maskK0ShortSpecific; - uint64_t maskLambdaSpecific; - uint64_t maskAntiLambdaSpecific; - uint64_t maskD0Specific; - uint64_t maskAntiD0Specific; + uint64_t maskK0ShortSpecific = 0; + uint64_t maskLambdaSpecific = 0; + uint64_t maskAntiLambdaSpecific = 0; + uint64_t maskD0Specific = 0; + uint64_t maskAntiD0Specific = 0; - uint64_t maskSelectionK0Short; - uint64_t maskSelectionLambda; - uint64_t maskSelectionAntiLambda; - uint64_t maskSelectionD0; - uint64_t maskSelectionAntiD0; + uint64_t maskSelectionK0Short = 0; + uint64_t maskSelectionLambda = 0; + uint64_t maskSelectionAntiLambda = 0; + uint64_t maskSelectionD0 = 0; + uint64_t maskSelectionAntiD0 = 0; - uint64_t secondaryMaskSelectionLambda; - uint64_t secondaryMaskSelectionAntiLambda; + uint64_t secondaryMaskSelectionLambda = 0; + uint64_t secondaryMaskSelectionAntiLambda = 0; void init(InitContext const&) { @@ -472,6 +535,7 @@ struct forwardlambdakzeroanalysis { BITSET(maskLambdaSpecific, selLambdaPseudoLifetimeMax); BITSET(maskLambdaSpecific, selConsiderLambda); BITSET(maskLambdaSpecific, selK0ShortMassRejection); + BITSET(maskLambdaSpecific, selLambdaArmenteros); // Mask for specifically selecting AntiLambda maskAntiLambdaSpecific = 0; BITSET(maskAntiLambdaSpecific, selLambdaRapidityMin); @@ -481,6 +545,7 @@ struct forwardlambdakzeroanalysis { BITSET(maskAntiLambdaSpecific, selLambdaPseudoLifetimeMax); BITSET(maskAntiLambdaSpecific, selConsiderAntiLambda); BITSET(maskAntiLambdaSpecific, selK0ShortMassRejection); + BITSET(maskAntiLambdaSpecific, selAntiLambdaArmenteros); // Mask for specifically selecting D0 maskD0Specific = 0; BITSET(maskD0Specific, selD0RapidityMin); @@ -490,6 +555,7 @@ struct forwardlambdakzeroanalysis { BITSET(maskD0Specific, selD0PseudoLifetimeMax); BITSET(maskD0Specific, selConsiderD0); BITSET(maskD0Specific, selK0ShortMassRejection); + BITSET(maskD0Specific, selD0Armenteros); BITSET(maskD0Specific, selLambdaMassRejection); // Mask for specifically selecting D0 maskAntiD0Specific = 0; @@ -500,6 +566,7 @@ struct forwardlambdakzeroanalysis { BITSET(maskAntiD0Specific, selD0PseudoLifetimeMax); BITSET(maskAntiD0Specific, selConsiderAntiD0); BITSET(maskAntiD0Specific, selK0ShortMassRejection); + BITSET(maskAntiD0Specific, selAntiD0Armenteros); BITSET(maskAntiD0Specific, selLambdaMassRejection); // ask for specific TPC/TOF PID selections @@ -528,7 +595,7 @@ struct forwardlambdakzeroanalysis { rctFlagsChecker.init(rctConfigurations.cfgRCTLabel.value, rctConfigurations.cfgCheckZDC, rctConfigurations.cfgTreatLimitedAcceptanceAsBad); // Event Counters - histos.add("hEventSelection", "hEventSelection", kTH1D, {{23, -0.5f, +22.5f}}); + histos.add("hEventSelection", "hEventSelection", kTH1D, {{25, -0.5f, +24.5f}}); histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(3, "kIsTriggerTVX"); @@ -545,13 +612,15 @@ struct forwardlambdakzeroanalysis { histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(14, "kNoCollInTimeRangeNarrow"); histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(15, "kNoCollInRofStd"); histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(16, "kNoCollInRofStrict"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(17, "INEL>0"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "INEL>1"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(19, "Below min occup."); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(20, "Above max occup."); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(21, "Below min IR"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(22, "Above max IR"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(23, "RCT flags"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(17, "kNoHighMultCollInPrevRof"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "kIsGoodITSLayersAll"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(19, "INEL>0"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(20, "INEL>1"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(21, "Below min occup."); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(22, "Above max occup."); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(23, "Below min IR"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(24, "Above max IR"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(25, "RCT flags"); histos.add("hEventCentrality", "hEventCentrality", kTH1D, {axisConfigurations.axisCentralityFine}); histos.add("hCentralityVsNch", "hCentralityVsNch", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisNch}); @@ -562,6 +631,11 @@ struct forwardlambdakzeroanalysis { histos.add("hEventPVzMC", "hEventPVzMC", kTH1D, {{100, -20.0f, +20.0f}}); histos.add("hCentralityVsPVzMC", "hCentralityVsPVzMC", kTH2D, {axisConfigurations.axisCentralityFine, {100, -20.0f, +20.0f}}); } + if (doprocessMonteCarlo) { + histos.add("hEventPVxDiff", "hEventPVxDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + histos.add("hEventPVyDiff", "hEventPVyDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + histos.add("hEventPVzDiff", "hEventPVzDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + } histos.add("hEventOccupancy", "hEventOccupancy", kTH1D, {axisConfigurations.axisOccupancy}); histos.add("hCentralityVsOccupancy", "hCentralityVsOccupancy", kTH2D, {axisConfigurations.axisCentralityFine, axisConfigurations.axisOccupancy}); @@ -607,7 +681,11 @@ struct forwardlambdakzeroanalysis { hSelectionV0s->GetXaxis()->SetBinLabel(selLambdaPseudoLifetimeMax + 2, "#Lambda pseudo-time max"); hSelectionV0s->GetXaxis()->SetBinLabel(selD0PseudoLifetimeMin + 2, "D^{0} pseudo-time min"); hSelectionV0s->GetXaxis()->SetBinLabel(selD0PseudoLifetimeMax + 2, "D^{0} pseudo-time max"); - hSelectionV0s->GetXaxis()->SetBinLabel(selK0ShortArmenteros + 2, "Arm. pod. cut"); + hSelectionV0s->GetXaxis()->SetBinLabel(selK0ShortArmenteros + 2, "K^{0}_{S} Arm. pod. cut"); + hSelectionV0s->GetXaxis()->SetBinLabel(selLambdaArmenteros + 2, "#Lambda Arm. pod. cut"); + hSelectionV0s->GetXaxis()->SetBinLabel(selAntiLambdaArmenteros + 2, "#bar{#Lambda} Arm. pod. cut"); + hSelectionV0s->GetXaxis()->SetBinLabel(selD0Armenteros + 2, "D^{0} Arm. pod. cut"); + hSelectionV0s->GetXaxis()->SetBinLabel(selAntiD0Armenteros + 2, "#bar{D}^{0} Arm. pod. cut"); hSelectionV0s->GetXaxis()->SetBinLabel(selPosGoodMFTTrack + 2, "Pos. good MFT track"); hSelectionV0s->GetXaxis()->SetBinLabel(selNegGoodMFTTrack + 2, "Neg. good MFT track"); hSelectionV0s->GetXaxis()->SetBinLabel(selConsiderK0Short + 2, "True K^{0}_{S}"); @@ -745,13 +823,23 @@ struct forwardlambdakzeroanalysis { histos.add("hPositiveMFTchi2", "hPositiveMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); histos.add("hNegativeMFTchi2", "hNegativeMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); if (doprocessMonteCarlo) { - histos.add("hPositiveMomResolution", "hPositiveMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); - histos.add("hNegativeMomResolution", "hNegativeMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("hPositivePtResolution", "hPositivePtResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("hNegativePtResolution", "hNegativePtResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("hPositivePzResolution", "hPositivePzResolution", kTH2D, {axisConfigurations.axisPz, axisConfigurations.axisPzResol}); + histos.add("hNegativePzResolution", "hNegativePzResolution", kTH2D, {axisConfigurations.axisPz, axisConfigurations.axisPzResol}); + + histos.add("hV0XDiff", "hV0XDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + histos.add("hV0YDiff", "hV0YDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + histos.add("hV0ZDiff", "hV0ZDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + histos.add("hV0RadiusDiff", "hV0RadiusDiff", kTH2D, {axisConfigurations.axisV0Radius, axisConfigurations.axisPositionDiff}); + histos.add("hV0DistZDiff", "hV0DistZDiff", kTH2D, {axisConfigurations.axisV0Z, axisConfigurations.axisPositionDiff}); + histos.add("hV0PtResolution", "hV0PtResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("hV0PzResolution", "hV0PzResolution", kTH2D, {axisConfigurations.axisPz, axisConfigurations.axisPzResol}); } if (analyseK0Short) { histos.add("K0Short/hPosDCAToPVxy", "hPosDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); - histos.add("K0Short/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVz}); - histos.add("K0Short/hPosDCAToPVz", "hPosDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("K0Short/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("K0Short/hPosDCAToPVz", "hPosDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); histos.add("K0Short/hNegDCAToPVz", "hNegDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); histos.add("K0Short/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); histos.add("K0Short/hCosPA", "hCosPA", kTH1D, {axisConfigurations.axisCosPA}); @@ -784,14 +872,24 @@ struct forwardlambdakzeroanalysis { histos.add("K0Short/hPositiveMFTchi2", "hPositiveMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); histos.add("K0Short/hNegativeMFTchi2", "hNegativeMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); if (doprocessMonteCarlo) { - histos.add("K0Short/hPositiveMomResolution", "hPositiveMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); - histos.add("K0Short/hNegativeMomResolution", "hNegativeMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("K0Short/hPositivePtResolution", "hPositivePtResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("K0Short/hNegativePtResolution", "hNegativePtResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("K0Short/hPositivePzResolution", "hPositivePzResolution", kTH2D, {axisConfigurations.axisPz, axisConfigurations.axisPzResol}); + histos.add("K0Short/hNegativePzResolution", "hNegativePzResolution", kTH2D, {axisConfigurations.axisPz, axisConfigurations.axisPzResol}); + + histos.add("K0Short/hV0XDiff", "hV0XDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + histos.add("K0Short/hV0YDiff", "hV0YDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + histos.add("K0Short/hV0ZDiff", "hV0ZDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + histos.add("K0Short/hV0RadiusDiff", "hV0RadiusDiff", kTH2D, {axisConfigurations.axisV0Radius, axisConfigurations.axisPositionDiff}); + histos.add("K0Short/hV0DistZDiff", "hV0DistZDiff", kTH2D, {axisConfigurations.axisV0Z, axisConfigurations.axisPositionDiff}); + histos.add("K0Short/hV0PtResolution", "hV0PtResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("K0Short/hV0PzResolution", "hV0PzResolution", kTH2D, {axisConfigurations.axisPz, axisConfigurations.axisPzResol}); } } if (analyseLambda) { histos.add("Lambda/hPosDCAToPVxy", "hPosDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); - histos.add("Lambda/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVz}); - histos.add("Lambda/hPosDCAToPVz", "hPosDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("Lambda/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("Lambda/hPosDCAToPVz", "hPosDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); histos.add("Lambda/hNegDCAToPVz", "hNegDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); histos.add("Lambda/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); histos.add("Lambda/hCosPA", "hCosPA", kTH1D, {axisConfigurations.axisCosPA}); @@ -823,14 +921,24 @@ struct forwardlambdakzeroanalysis { histos.add("Lambda/hPositiveMFTchi2", "hPositiveMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); histos.add("Lambda/hNegativeMFTchi2", "hNegativeMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); if (doprocessMonteCarlo) { - histos.add("Lambda/hPositiveMomResolution", "hPositiveMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); - histos.add("Lambda/hNegativeMomResolution", "hNegativeMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("Lambda/hPositivePtResolution", "hPositivePtResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("Lambda/hNegativePtResolution", "hNegativePtResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("Lambda/hPositivePzResolution", "hPositivePzResolution", kTH2D, {axisConfigurations.axisPz, axisConfigurations.axisPzResol}); + histos.add("Lambda/hNegativePzResolution", "hNegativePzResolution", kTH2D, {axisConfigurations.axisPz, axisConfigurations.axisPzResol}); + + histos.add("Lambda/hV0XDiff", "hV0XDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + histos.add("Lambda/hV0YDiff", "hV0YDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + histos.add("Lambda/hV0ZDiff", "hV0ZDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + histos.add("Lambda/hV0RadiusDiff", "hV0RadiusDiff", kTH2D, {axisConfigurations.axisV0Radius, axisConfigurations.axisPositionDiff}); + histos.add("Lambda/hV0DistZDiff", "hV0DistZDiff", kTH2D, {axisConfigurations.axisV0Z, axisConfigurations.axisPositionDiff}); + histos.add("Lambda/hV0PtResolution", "hV0PtResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("Lambda/hV0PzResolution", "hV0PzResolution", kTH2D, {axisConfigurations.axisPz, axisConfigurations.axisPzResol}); } } if (analyseAntiLambda) { histos.add("AntiLambda/hPosDCAToPVxy", "hPosDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); - histos.add("AntiLambda/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVz}); - histos.add("AntiLambda/hPosDCAToPVz", "hPosDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("AntiLambda/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("AntiLambda/hPosDCAToPVz", "hPosDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); histos.add("AntiLambda/hNegDCAToPVz", "hNegDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); histos.add("AntiLambda/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); histos.add("AntiLambda/hCosPA", "hCosPA", kTH1D, {axisConfigurations.axisCosPA}); @@ -862,14 +970,24 @@ struct forwardlambdakzeroanalysis { histos.add("AntiLambda/hPositiveMFTchi2", "hPositiveMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); histos.add("AntiLambda/hNegativeMFTchi2", "hNegativeMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); if (doprocessMonteCarlo) { - histos.add("AntiLambda/hPositiveMomResolution", "hPositiveMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); - histos.add("AntiLambda/hNegativeMomResolution", "hNegativeMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("AntiLambda/hPositivePtResolution", "hPositivePtResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("AntiLambda/hNegativePtResolution", "hNegativePtResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("AntiLambda/hPositivePzResolution", "hPositivePzResolution", kTH2D, {axisConfigurations.axisPz, axisConfigurations.axisPzResol}); + histos.add("AntiLambda/hNegativePzResolution", "hNegativePzResolution", kTH2D, {axisConfigurations.axisPz, axisConfigurations.axisPzResol}); + + histos.add("AntiLambda/hV0XDiff", "hV0XDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + histos.add("AntiLambda/hV0YDiff", "hV0YDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + histos.add("AntiLambda/hV0ZDiff", "hV0ZDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + histos.add("AntiLambda/hV0RadiusDiff", "hV0RadiusDiff", kTH2D, {axisConfigurations.axisV0Radius, axisConfigurations.axisPositionDiff}); + histos.add("AntiLambda/hV0DistZDiff", "hV0DistZDiff", kTH2D, {axisConfigurations.axisV0Z, axisConfigurations.axisPositionDiff}); + histos.add("AntiLambda/hV0PtResolution", "hV0PtResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("AntiLambda/hV0PzResolution", "hV0PzResolution", kTH2D, {axisConfigurations.axisPz, axisConfigurations.axisPzResol}); } } if (analyseD0) { histos.add("D0/hPosDCAToPVxy", "hPosDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); - histos.add("D0/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVz}); - histos.add("D0/hPosDCAToPVz", "hPosDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("D0/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("D0/hPosDCAToPVz", "hPosDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); histos.add("D0/hNegDCAToPVz", "hNegDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); histos.add("D0/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); histos.add("D0/hCosPA", "hCosPA", kTH1D, {axisConfigurations.axisCosPA}); @@ -901,14 +1019,24 @@ struct forwardlambdakzeroanalysis { histos.add("D0/hPositiveMFTchi2", "hPositiveMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); histos.add("D0/hNegativeMFTchi2", "hNegativeMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); if (doprocessMonteCarlo) { - histos.add("D0/hPositiveMomResolution", "hPositiveMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); - histos.add("D0/hNegativeMomResolution", "hNegativeMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("D0/hPositivePtResolution", "hPositivePtResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("D0/hNegativePtResolution", "hNegativePtResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("D0/hPositivePzResolution", "hPositivePzResolution", kTH2D, {axisConfigurations.axisPz, axisConfigurations.axisPzResol}); + histos.add("D0/hNegativePzResolution", "hNegativePzResolution", kTH2D, {axisConfigurations.axisPz, axisConfigurations.axisPzResol}); + + histos.add("D0/hV0XDiff", "hV0XDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + histos.add("D0/hV0YDiff", "hV0YDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + histos.add("D0/hV0ZDiff", "hV0ZDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + histos.add("D0/hV0RadiusDiff", "hV0RadiusDiff", kTH2D, {axisConfigurations.axisV0Radius, axisConfigurations.axisPositionDiff}); + histos.add("D0/hV0DistZDiff", "hV0DistZDiff", kTH2D, {axisConfigurations.axisV0Z, axisConfigurations.axisPositionDiff}); + histos.add("D0/hV0PtResolution", "hV0PtResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("D0/hV0PzResolution", "hV0PzResolution", kTH2D, {axisConfigurations.axisPz, axisConfigurations.axisPzResol}); } } if (analyseAntiD0) { histos.add("AntiD0/hPosDCAToPVxy", "hPosDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); - histos.add("AntiD0/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVz}); - histos.add("AntiD0/hPosDCAToPVz", "hPosDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("AntiD0/hNegDCAToPVxy", "hNegDCAToPVxy", kTH1D, {axisConfigurations.axisDCAtoPVxy}); + histos.add("AntiD0/hPosDCAToPVz", "hPosDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); histos.add("AntiD0/hNegDCAToPVz", "hNegDCAToPVz", kTH1D, {axisConfigurations.axisDCAtoPVz}); histos.add("AntiD0/hDCADaughters", "hDCADaughters", kTH1D, {axisConfigurations.axisDCAdau}); histos.add("AntiD0/hCosPA", "hCosPA", kTH1D, {axisConfigurations.axisCosPA}); @@ -940,8 +1068,18 @@ struct forwardlambdakzeroanalysis { histos.add("AntiD0/hPositiveMFTchi2", "hPositiveMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); histos.add("AntiD0/hNegativeMFTchi2", "hNegativeMFTchi2", kTH1D, {axisConfigurations.axisMFTchi2}); if (doprocessMonteCarlo) { - histos.add("AntiD0/hPositiveMomResolution", "hPositiveMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); - histos.add("AntiD0/hNegativeMomResolution", "hNegativeMomResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("AntiD0/hPositivePtResolution", "hPositivePtResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("AntiD0/hNegativePtResolution", "hNegativePtResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("AntiD0/hPositivePzResolution", "hPositivePzResolution", kTH2D, {axisConfigurations.axisPz, axisConfigurations.axisPzResol}); + histos.add("AntiD0/hNegativePzResolution", "hNegativePzResolution", kTH2D, {axisConfigurations.axisPz, axisConfigurations.axisPzResol}); + + histos.add("AntiD0/hV0XDiff", "hV0XDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + histos.add("AntiD0/hV0YDiff", "hV0YDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + histos.add("AntiD0/hV0ZDiff", "hV0ZDiff", kTH2D, {axisConfigurations.axisPosition, axisConfigurations.axisPositionDiff}); + histos.add("AntiD0/hV0RadiusDiff", "hV0RadiusDiff", kTH2D, {axisConfigurations.axisV0Radius, axisConfigurations.axisPositionDiff}); + histos.add("AntiD0/hV0DistZDiff", "hV0DistZDiff", kTH2D, {axisConfigurations.axisV0Z, axisConfigurations.axisPositionDiff}); + histos.add("AntiD0/hV0PtResolution", "hV0PtResolution", kTH2D, {axisConfigurations.axisPt, axisConfigurations.axisPtResol}); + histos.add("AntiD0/hV0PzResolution", "hV0PzResolution", kTH2D, {axisConfigurations.axisPz, axisConfigurations.axisPzResol}); } } } @@ -1062,7 +1200,7 @@ struct forwardlambdakzeroanalysis { } template - void initCCDB(TBCs const& bcs, TCollision collision) + void initCCDB(TBCs const& bcs, TCollision const& collision) { auto bc = collision.template bc_as(); if (!bcs.size()) { @@ -1105,8 +1243,52 @@ struct forwardlambdakzeroanalysis { fitter.setBz(magField); } + // Ideal Armenteros-Podolanski ellipse of a two-body decay hypothesis: centre and half-axes + struct ArmenterosEllipse { + float alphaCenter; // (E*_pos - E*_neg) / M, vanishes for symmetric decays + float alphaHalfWidth; // 2 qStar / (beta M) + float qStar; // daughter momentum in the mother rest frame = maximum qT + }; + + ArmenterosEllipse armenterosEllipse(float pTot, float massMother, float massPositive, float massNegative) + { + const float energyPositive = (massMother * massMother + massPositive * massPositive - massNegative * massNegative) / (2.f * massMother); + const float qStar = std::sqrt(std::max(0.f, energyPositive * energyPositive - massPositive * massPositive)); + float alphaHalfWidth = 2.f * qStar / massMother; // beta -> 1 limit + if (v0Selections.armPodBandUseBeta && pTot > 1e-3f) { + alphaHalfWidth *= std::hypot(pTot, massMother) / pTot; // 1 / beta of the candidate + } + return ArmenterosEllipse{2.f * energyPositive / massMother - 1.f, alphaHalfWidth, qStar}; + } + + // Normalised distance to the centre of the ideal ellipse, measured with its two half-axes scaled + // independently: 1 on the scaled ellipse itself, smaller inside it, larger outside it. + float armenterosDistance(ArmenterosEllipse const& ellipse, float alphaArm, float qtArm, float alphaScale, float qtScale) + { + return std::hypot((alphaArm - ellipse.alphaCenter) / (alphaScale * ellipse.alphaHalfWidth), qtArm / (qtScale * ellipse.qStar)); + } + + // Crescent-shaped band around the two-body decay arc in the Armenteros-Podolanski plane template - uint64_t computeReconstructionBitmap(TV0 v0, float rapK0s, float rapLambda, float rapD0) + bool passesArmenterosBand(TV0 const& v0, float massMother, float massPositive, float massNegative, const char* species) + { + if (!v0Selections.useArmPodBand) { + return true; + } + const ArmenterosEllipse ellipse = armenterosEllipse(v0.pTot, massMother, massPositive, massNegative); + if (armenterosDistance(ellipse, v0.AlphaArm, v0.QtArm, v0Selections.armPodBand->get(species, "alphaScaleMax"), v0Selections.armPodBand->get(species, "qtScaleMax")) > 1.f) { + return false; // outside the outer ellipse + } + const float alphaScaleMin = v0Selections.armPodBand->get(species, "alphaScaleMin"); + const float qtScaleMin = v0Selections.armPodBand->get(species, "qtScaleMin"); + if (alphaScaleMin < 1e-4f || qtScaleMin < 1e-4f) { + return true; // no inner ellipse requested: the whole outer ellipse is kept + } + return armenterosDistance(ellipse, v0.AlphaArm, v0.QtArm, alphaScaleMin, qtScaleMin) > 1.f; + } + + template + uint64_t computeReconstructionBitmap(TV0 const& v0, float rapK0s, float rapLambda, float rapD0) // precalculate this information so that a check is one mask operation, not many { uint64_t bitMap = 0; @@ -1121,24 +1303,28 @@ struct forwardlambdakzeroanalysis { BITSET(bitMap, selRadiusMax); } // v0 radius min/max selections - if (v0.Z > v0Selections.v0Zmin) { + if (v0.Zdist > v0Selections.v0Zmin) { BITSET(bitMap, selZmin); } - if (v0.Z < v0Selections.v0Zmax) { + if (v0.Zdist < v0Selections.v0Zmax) { BITSET(bitMap, selZmax); } // DCA proton and pion to PV for Lambda and AntiLambda decay hypotheses - if (std::fabs(v0.dcaPosToPVxy) > v0Selections.dcaPosToPVxy) { + if ((!v0Selections.rejectFailedPropagation || std::fabs(v0.dcaPosToPVxy) < o2::track::DefaultDCA) && + std::fabs(v0.dcaPosToPVxy) > v0Selections.dcaPosToPVxy) { BITSET(bitMap, selDCAPosToPVxy); } - if (std::fabs(v0.dcaNegToPVxy) > v0Selections.dcaNegToPVxy) { + if ((!v0Selections.rejectFailedPropagation || std::fabs(v0.dcaNegToPVxy) < o2::track::DefaultDCA) && + std::fabs(v0.dcaNegToPVxy) > v0Selections.dcaNegToPVxy) { BITSET(bitMap, selDCANegToPVxy); } // DCA proton and pion to PV for Lambda and AntiLambda decay hypotheses - if (std::fabs(v0.dcaPosToPVz) > v0Selections.dcaPosToPVz) { + if ((!v0Selections.rejectFailedPropagation || std::fabs(v0.dcaPosToPVz) < o2::track::DefaultDCA) && + std::fabs(v0.dcaPosToPVz) > v0Selections.dcaPosToPVz) { BITSET(bitMap, selDCAPosToPVz); } - if (std::fabs(v0.dcaNegToPVz) > v0Selections.dcaNegToPVz) { + if ((!v0Selections.rejectFailedPropagation || std::fabs(v0.dcaNegToPVz) < o2::track::DefaultDCA) && + std::fabs(v0.dcaNegToPVz) > v0Selections.dcaNegToPVz) { BITSET(bitMap, selDCANegToPVz); } // V0 cosine of pointing angle @@ -1243,9 +1429,26 @@ struct forwardlambdakzeroanalysis { // // armenteros - if (v0Selections.armPodCut < 1e-4 || v0.QtArm * v0Selections.armPodCut > std::abs(v0.AlphaArm)) { + // legacy K0Short "V" cut, plus an optional box and the optional elliptic band around the decay arc + const bool armPodVCut = (v0Selections.armPodCut < 1e-4 || v0.QtArm * v0Selections.armPodCut > std::abs(v0.AlphaArm)); + const bool armPodBox = (v0.QtArm > v0Selections.minQt && v0.QtArm < v0Selections.maxQt && + v0.AlphaArm > v0Selections.minAlpha && v0.AlphaArm < v0Selections.maxAlpha); + if (armPodVCut && armPodBox && + passesArmenterosBand(v0, o2::constants::physics::MassK0Short, o2::constants::physics::MassPiPlus, o2::constants::physics::MassPiMinus, "K0Short")) { BITSET(bitMap, selK0ShortArmenteros); } + if (armPodBox && passesArmenterosBand(v0, o2::constants::physics::MassLambda0, o2::constants::physics::MassProton, o2::constants::physics::MassPiMinus, "Lambda")) { + BITSET(bitMap, selLambdaArmenteros); + } + if (armPodBox && passesArmenterosBand(v0, o2::constants::physics::MassLambda0, o2::constants::physics::MassPiPlus, o2::constants::physics::MassProtonBar, "Lambda")) { + BITSET(bitMap, selAntiLambdaArmenteros); + } + if (armPodBox && passesArmenterosBand(v0, o2::constants::physics::MassD0, o2::constants::physics::MassKPlus, o2::constants::physics::MassPiMinus, "D0")) { + BITSET(bitMap, selD0Armenteros); + } + if (armPodBox && passesArmenterosBand(v0, o2::constants::physics::MassD0, o2::constants::physics::MassPiPlus, o2::constants::physics::MassKMinus, "D0")) { + BITSET(bitMap, selAntiD0Armenteros); + } return bitMap; } @@ -1330,7 +1533,7 @@ struct forwardlambdakzeroanalysis { histos.fill(HIST("hCosPA"), v0.CosPA); histos.fill(HIST("hOpeningAngle"), v0.OpAngle); histos.fill(HIST("hV0Radius"), v0.Radius); - histos.fill(HIST("hV0Z"), v0.Z); + histos.fill(HIST("hV0Z"), v0.Zdist); if (analyseK0Short) { histos.fill(HIST("hV0Rapidity"), v0.rapidityK0s); } else if (analyseLambda || analyseAntiLambda) { @@ -1367,8 +1570,18 @@ struct forwardlambdakzeroanalysis { histos.fill(HIST("hPositiveMFTchi2"), v0.posChi2); histos.fill(HIST("hNegativeMFTchi2"), v0.negChi2); if (doprocessMonteCarlo) { - histos.fill(HIST("hPositiveMomResolution"), v0.pTMc, v0.pTMc - v0.pT); - histos.fill(HIST("hNegativeMomResolution"), v0.pTMc, v0.pTMc - v0.pT); + histos.fill(HIST("hPositivePtResolution"), v0.positivePtMc(), (v0.positivePtMc() - v0.positivePt()) / v0.positivePtMc()); + histos.fill(HIST("hNegativePtResolution"), v0.negativePtMc(), (v0.negativePtMc() - v0.negativePt()) / v0.negativePtMc()); + histos.fill(HIST("hPositivePzResolution"), v0.positivePzMc(), (v0.positivePzMc() - v0.positivePz()) / v0.positivePzMc()); + histos.fill(HIST("hNegativePzResolution"), v0.negativePzMc(), (v0.negativePzMc() - v0.negativePz()) / v0.negativePzMc()); + + histos.fill(HIST("hV0XDiff"), v0.xMc, (v0.xMc - v0.X)); + histos.fill(HIST("hV0YDiff"), v0.yMc, (v0.yMc - v0.Y)); + histos.fill(HIST("hV0ZDiff"), v0.zMc, (v0.zMc - v0.Z)); + histos.fill(HIST("hV0RadiusDiff"), v0.RadiusMc, (v0.RadiusMc - v0.Radius) / v0.RadiusMc); + histos.fill(HIST("hV0DistZDiff"), v0.ZdistMc, (v0.ZdistMc - v0.Zdist) / v0.ZdistMc); + histos.fill(HIST("hV0PtResolution"), v0.pTMc, (v0.pTMc - v0.pT) / v0.pTMc); + histos.fill(HIST("hV0PzResolution"), v0.pZMc, (v0.pZMc - v0.pZ) / v0.pZMc); } } @@ -1407,7 +1620,7 @@ struct forwardlambdakzeroanalysis { histos.fill(HIST("K0Short/hCosPA"), v0.CosPA); histos.fill(HIST("K0Short/hOpeningAngle"), v0.OpAngle); histos.fill(HIST("K0Short/hV0Radius"), v0.Radius); - histos.fill(HIST("K0Short/hV0Z"), v0.Z); + histos.fill(HIST("K0Short/hV0Z"), v0.Zdist); histos.fill(HIST("K0Short/hV0Rapidity"), v0.rapidityK0s); histos.fill(HIST("K0Short/hV0LifetimeK0s"), v0.DistOverTotMom * o2::constants::physics::MassK0Short); histos.fill(HIST("K0Short/hV0LifetimeLambda"), v0.DistOverTotMom * o2::constants::physics::MassLambda); @@ -1434,8 +1647,18 @@ struct forwardlambdakzeroanalysis { histos.fill(HIST("K0Short/hPositiveMFTchi2"), v0.posChi2); histos.fill(HIST("K0Short/hNegativeMFTchi2"), v0.negChi2); if (doprocessMonteCarlo) { - histos.fill(HIST("K0Short/hPositiveMomResolution"), v0.pTMc, v0.pTMc - v0.pT); - histos.fill(HIST("K0Short/hNegativeMomResolution"), v0.pTMc, v0.pTMc - v0.pT); + histos.fill(HIST("K0Short/hPositivePtResolution"), v0.positivePtMc(), (v0.positivePtMc() - v0.positivePt()) / v0.positivePtMc()); + histos.fill(HIST("K0Short/hNegativePtResolution"), v0.negativePtMc(), (v0.negativePtMc() - v0.negativePt()) / v0.negativePtMc()); + histos.fill(HIST("K0Short/hPositivePzResolution"), v0.positivePzMc(), (v0.positivePzMc() - v0.positivePz()) / v0.positivePzMc()); + histos.fill(HIST("K0Short/hNegativePzResolution"), v0.negativePzMc(), (v0.negativePzMc() - v0.negativePz()) / v0.negativePzMc()); + + histos.fill(HIST("K0Short/hV0XDiff"), v0.xMc, (v0.xMc - v0.X)); + histos.fill(HIST("K0Short/hV0YDiff"), v0.yMc, (v0.yMc - v0.Y)); + histos.fill(HIST("K0Short/hV0ZDiff"), v0.zMc, (v0.zMc - v0.Z)); + histos.fill(HIST("K0Short/hV0RadiusDiff"), v0.RadiusMc, (v0.RadiusMc - v0.Radius) / v0.RadiusMc); + histos.fill(HIST("K0Short/hV0DistZDiff"), v0.ZdistMc, (v0.ZdistMc - v0.Zdist) / v0.ZdistMc); + histos.fill(HIST("K0Short/hV0PtResolution"), v0.pTMc, (v0.pTMc - v0.pT) / v0.pTMc); + histos.fill(HIST("K0Short/hV0PzResolution"), v0.pZMc, (v0.pZMc - v0.pZ) / v0.pZMc); } } nK0Shorts++; @@ -1464,7 +1687,7 @@ struct forwardlambdakzeroanalysis { histos.fill(HIST("Lambda/hCosPA"), v0.CosPA); histos.fill(HIST("Lambda/hOpeningAngle"), v0.OpAngle); histos.fill(HIST("Lambda/hV0Radius"), v0.Radius); - histos.fill(HIST("Lambda/hV0Z"), v0.Z); + histos.fill(HIST("Lambda/hV0Z"), v0.Zdist); histos.fill(HIST("Lambda/hV0Rapidity"), v0.rapidityLambda); histos.fill(HIST("Lambda/hV0LifetimeK0s"), v0.DistOverTotMom * o2::constants::physics::MassK0Short); histos.fill(HIST("Lambda/hV0LifetimeLambda"), v0.DistOverTotMom * o2::constants::physics::MassLambda); @@ -1490,8 +1713,18 @@ struct forwardlambdakzeroanalysis { histos.fill(HIST("Lambda/hPositiveMFTchi2"), v0.posChi2); histos.fill(HIST("Lambda/hNegativeMFTchi2"), v0.negChi2); if (doprocessMonteCarlo) { - histos.fill(HIST("Lambda/hPositiveMomResolution"), v0.pTMc, v0.pTMc - v0.pT); - histos.fill(HIST("Lambda/hNegativeMomResolution"), v0.pTMc, v0.pTMc - v0.pT); + histos.fill(HIST("Lambda/hPositivePtResolution"), v0.positivePtMc(), (v0.positivePtMc() - v0.positivePt()) / v0.positivePtMc()); + histos.fill(HIST("Lambda/hNegativePtResolution"), v0.negativePtMc(), (v0.negativePtMc() - v0.negativePt()) / v0.negativePtMc()); + histos.fill(HIST("Lambda/hPositivePzResolution"), v0.positivePzMc(), (v0.positivePzMc() - v0.positivePz()) / v0.positivePzMc()); + histos.fill(HIST("Lambda/hNegativePzResolution"), v0.negativePzMc(), (v0.negativePzMc() - v0.negativePz()) / v0.negativePzMc()); + + histos.fill(HIST("Lambda/hV0XDiff"), v0.xMc, (v0.xMc - v0.X)); + histos.fill(HIST("Lambda/hV0YDiff"), v0.yMc, (v0.yMc - v0.Y)); + histos.fill(HIST("Lambda/hV0ZDiff"), v0.zMc, (v0.zMc - v0.Z)); + histos.fill(HIST("Lambda/hV0RadiusDiff"), v0.RadiusMc, (v0.RadiusMc - v0.Radius) / v0.RadiusMc); + histos.fill(HIST("Lambda/hV0DistZDiff"), v0.ZdistMc, (v0.ZdistMc - v0.Zdist) / v0.ZdistMc); + histos.fill(HIST("Lambda/hV0PtResolution"), v0.pTMc, (v0.pTMc - v0.pT) / v0.pTMc); + histos.fill(HIST("Lambda/hV0PzResolution"), v0.pZMc, (v0.pZMc - v0.pZ) / v0.pZMc); } } nLambdas++; @@ -1520,7 +1753,7 @@ struct forwardlambdakzeroanalysis { histos.fill(HIST("AntiLambda/hCosPA"), v0.CosPA); histos.fill(HIST("AntiLambda/hOpeningAngle"), v0.OpAngle); histos.fill(HIST("AntiLambda/hV0Radius"), v0.Radius); - histos.fill(HIST("AntiLambda/hV0Z"), v0.Z); + histos.fill(HIST("AntiLambda/hV0Z"), v0.Zdist); histos.fill(HIST("AntiLambda/hV0Rapidity"), v0.rapidityLambda); histos.fill(HIST("AntiLambda/hV0LifetimeK0s"), v0.DistOverTotMom * o2::constants::physics::MassK0Short); histos.fill(HIST("AntiLambda/hV0LifetimeLambda"), v0.DistOverTotMom * o2::constants::physics::MassLambda); @@ -1546,8 +1779,18 @@ struct forwardlambdakzeroanalysis { histos.fill(HIST("AntiLambda/hPositiveMFTchi2"), v0.posChi2); histos.fill(HIST("AntiLambda/hNegativeMFTchi2"), v0.negChi2); if (doprocessMonteCarlo) { - histos.fill(HIST("AntiLambda/hPositiveMomResolution"), v0.pTMc, v0.pTMc - v0.pT); - histos.fill(HIST("AntiLambda/hNegativeMomResolution"), v0.pTMc, v0.pTMc - v0.pT); + histos.fill(HIST("AntiLambda/hPositivePtResolution"), v0.positivePtMc(), (v0.positivePtMc() - v0.positivePt()) / v0.positivePtMc()); + histos.fill(HIST("AntiLambda/hNegativePtResolution"), v0.negativePtMc(), (v0.negativePtMc() - v0.negativePt()) / v0.negativePtMc()); + histos.fill(HIST("AntiLambda/hPositivePzResolution"), v0.positivePzMc(), (v0.positivePzMc() - v0.positivePz()) / v0.positivePzMc()); + histos.fill(HIST("AntiLambda/hNegativePzResolution"), v0.negativePzMc(), (v0.negativePzMc() - v0.negativePz()) / v0.negativePzMc()); + + histos.fill(HIST("AntiLambda/hV0XDiff"), v0.xMc, (v0.xMc - v0.X)); + histos.fill(HIST("AntiLambda/hV0YDiff"), v0.yMc, (v0.yMc - v0.Y)); + histos.fill(HIST("AntiLambda/hV0ZDiff"), v0.zMc, (v0.zMc - v0.Z)); + histos.fill(HIST("AntiLambda/hV0RadiusDiff"), v0.RadiusMc, (v0.RadiusMc - v0.Radius) / v0.RadiusMc); + histos.fill(HIST("AntiLambda/hV0DistZDiff"), v0.ZdistMc, (v0.ZdistMc - v0.Zdist) / v0.Zdist); + histos.fill(HIST("AntiLambda/hV0PtResolution"), v0.pTMc, (v0.pTMc - v0.pT) / v0.pTMc); + histos.fill(HIST("AntiLambda/hV0PzResolution"), v0.pZMc, (v0.pZMc - v0.pZ) / v0.pZMc); } } nAntiLambdas++; @@ -1576,7 +1819,7 @@ struct forwardlambdakzeroanalysis { histos.fill(HIST("D0/hCosPA"), v0.CosPA); histos.fill(HIST("D0/hOpeningAngle"), v0.OpAngle); histos.fill(HIST("D0/hV0Radius"), v0.Radius); - histos.fill(HIST("D0/hV0Z"), v0.Z); + histos.fill(HIST("D0/hV0Z"), v0.Zdist); histos.fill(HIST("D0/hV0Rapidity"), v0.rapidityD0); histos.fill(HIST("D0/hV0LifetimeK0s"), v0.DistOverTotMom * o2::constants::physics::MassK0Short); histos.fill(HIST("D0/hV0LifetimeLambda"), v0.DistOverTotMom * o2::constants::physics::MassLambda); @@ -1602,8 +1845,18 @@ struct forwardlambdakzeroanalysis { histos.fill(HIST("D0/hPositiveMFTchi2"), v0.posChi2); histos.fill(HIST("D0/hNegativeMFTchi2"), v0.negChi2); if (doprocessMonteCarlo) { - histos.fill(HIST("D0/hPositiveMomResolution"), v0.pTMc, v0.pTMc - v0.pT); - histos.fill(HIST("D0/hNegativeMomResolution"), v0.pTMc, v0.pTMc - v0.pT); + histos.fill(HIST("D0/hPositivePtResolution"), v0.positivePtMc(), (v0.positivePtMc() - v0.positivePt()) / v0.positivePtMc()); + histos.fill(HIST("D0/hNegativePtResolution"), v0.negativePtMc(), (v0.negativePtMc() - v0.negativePt()) / v0.negativePtMc()); + histos.fill(HIST("D0/hPositivePzResolution"), v0.positivePzMc(), (v0.positivePzMc() - v0.positivePz()) / v0.positivePzMc()); + histos.fill(HIST("D0/hNegativePzResolution"), v0.negativePzMc(), (v0.negativePzMc() - v0.negativePz()) / v0.negativePzMc()); + + histos.fill(HIST("D0/hV0XDiff"), v0.xMc, (v0.xMc - v0.X)); + histos.fill(HIST("D0/hV0YDiff"), v0.yMc, (v0.yMc - v0.Y)); + histos.fill(HIST("D0/hV0ZDiff"), v0.zMc, (v0.zMc - v0.Z)); + histos.fill(HIST("D0/hV0RadiusDiff"), v0.RadiusMc, (v0.RadiusMc - v0.Radius) / v0.RadiusMc); + histos.fill(HIST("D0/hV0DistZDiff"), v0.ZdistMc, (v0.ZdistMc - v0.Zdist) / v0.ZdistMc); + histos.fill(HIST("D0/hV0PtResolution"), v0.pTMc, (v0.pTMc - v0.pT) / v0.pTMc); + histos.fill(HIST("D0/hV0PzResolution"), v0.pZMc, (v0.pZMc - v0.pZ) / v0.pZMc); } } nD0s++; @@ -1632,7 +1885,7 @@ struct forwardlambdakzeroanalysis { histos.fill(HIST("AntiD0/hCosPA"), v0.CosPA); histos.fill(HIST("AntiD0/hOpeningAngle"), v0.OpAngle); histos.fill(HIST("AntiD0/hV0Radius"), v0.Radius); - histos.fill(HIST("AntiD0/hV0Z"), v0.Z); + histos.fill(HIST("AntiD0/hV0Z"), v0.Zdist); histos.fill(HIST("AntiD0/hV0Rapidity"), v0.rapidityD0); histos.fill(HIST("AntiD0/hV0LifetimeK0s"), v0.DistOverTotMom * o2::constants::physics::MassK0Short); histos.fill(HIST("AntiD0/hV0LifetimeLambda"), v0.DistOverTotMom * o2::constants::physics::MassLambda); @@ -1658,8 +1911,18 @@ struct forwardlambdakzeroanalysis { histos.fill(HIST("AntiD0/hPositiveMFTchi2"), v0.posChi2); histos.fill(HIST("AntiD0/hNegativeMFTchi2"), v0.negChi2); if (doprocessMonteCarlo) { - histos.fill(HIST("AntiD0/hPositiveMomResolution"), v0.pTMc, v0.pTMc - v0.pT); - histos.fill(HIST("AntiD0/hNegativeMomResolution"), v0.pTMc, v0.pTMc - v0.pT); + histos.fill(HIST("AntiD0/hPositivePtResolution"), v0.positivePtMc(), (v0.positivePtMc() - v0.positivePt()) / v0.positivePtMc()); + histos.fill(HIST("AntiD0/hNegativePtResolution"), v0.negativePtMc(), (v0.negativePtMc() - v0.negativePt()) / v0.negativePtMc()); + histos.fill(HIST("AntiD0/hPositivePzResolution"), v0.positivePzMc(), (v0.positivePzMc() - v0.positivePz()) / v0.positivePzMc()); + histos.fill(HIST("AntiD0/hNegativePzResolution"), v0.negativePzMc(), (v0.negativePzMc() - v0.negativePz()) / v0.negativePzMc()); + + histos.fill(HIST("AntiD0/hV0XDiff"), v0.xMc, (v0.xMc - v0.X)); + histos.fill(HIST("AntiD0/hV0YDiff"), v0.yMc, (v0.yMc - v0.Y)); + histos.fill(HIST("AntiD0/hV0ZDiff"), v0.zMc, (v0.zMc - v0.Z)); + histos.fill(HIST("AntiD0/hV0RadiusDiff"), v0.RadiusMc, (v0.RadiusMc - v0.Radius) / v0.RadiusMc); + histos.fill(HIST("AntiD0/hV0DistZDiff"), v0.ZdistMc, (v0.ZdistMc - v0.Zdist) / v0.ZdistMc); + histos.fill(HIST("AntiD0/hV0PtResolution"), v0.pTMc, (v0.pTMc - v0.pT) / v0.pTMc); + histos.fill(HIST("AntiD0/hV0PzResolution"), v0.pZMc, (v0.pZMc - v0.pZ) / v0.pZMc); } } nAntiD0s++; @@ -1818,18 +2081,32 @@ struct forwardlambdakzeroanalysis { histos.fill(HIST("hEventSelection"), 15 /* No other collision within the same ITS ROF */); } + if (eventSelections.requireNoHighMultCollInPrevRof && !collision.selection_bit(o2::aod::evsel::kNoHighMultCollInPrevRof)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 16 /* veto an event if FT0C amplitude in previous ITS ROF is above threshold */); + } + + if (eventSelections.requireIsGoodITSLayersAll && !collision.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { + return false; + } + if (fillHists) { + histos.fill(HIST("hEventSelection"), 17 /* numbers of inactive chips on all ITS layers are below maximum allowed values */); + } + if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < 1) { return false; } if (fillHists) { - histos.fill(HIST("hEventSelection"), 16 /* INEL > 0 */); + histos.fill(HIST("hEventSelection"), 18 /* INEL > 0 */); } if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < 2) { return false; } if (fillHists) { - histos.fill(HIST("hEventSelection"), 17 /* INEL > 1 */); + histos.fill(HIST("hEventSelection"), 19 /* INEL > 1 */); } float collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); @@ -1837,14 +2114,14 @@ struct forwardlambdakzeroanalysis { return false; } if (fillHists) { - histos.fill(HIST("hEventSelection"), 18 /* Below min occupancy */); + histos.fill(HIST("hEventSelection"), 20 /* Below min occupancy */); } if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { return false; } if (fillHists) { - histos.fill(HIST("hEventSelection"), 19 /* Above max occupancy */); + histos.fill(HIST("hEventSelection"), 21 /* Above max occupancy */); } // Fetch interaction rate only if required (in order to limit ccdb calls) @@ -1854,21 +2131,21 @@ struct forwardlambdakzeroanalysis { return false; } if (fillHists) { - histos.fill(HIST("hEventSelection"), 20 /* Below min IR */); + histos.fill(HIST("hEventSelection"), 22 /* Below min IR */); } if (eventSelections.maxIR >= 0 && interactionRate > eventSelections.maxIR) { return false; } if (fillHists) { - histos.fill(HIST("hEventSelection"), 21 /* Above max IR */); + histos.fill(HIST("hEventSelection"), 23 /* Above max IR */); } if (!rctConfigurations.cfgRCTLabel.value.empty() && !rctFlagsChecker(collision)) { return false; } if (fillHists) { - histos.fill(HIST("hEventSelection"), 22 /* Pass CBT condition */); + histos.fill(HIST("hEventSelection"), 24 /* Pass CBT condition */); } return true; } @@ -1958,7 +2235,6 @@ struct forwardlambdakzeroanalysis { histos.fill(HIST("hCentralityVsInteractionRate"), centrality, interactionRate); histos.fill(HIST("hInteractionRateVsOccupancy"), interactionRate, collisionOccupancy); - return; } // ______________________________________________________ @@ -2018,7 +2294,6 @@ struct forwardlambdakzeroanalysis { histos.fill(HIST("hGenEventCentrality"), centrality); } } - return; } // BUILDER PART: largely inspired of the strangenessBuilderModule @@ -2057,17 +2332,38 @@ struct forwardlambdakzeroanalysis { //___________________________________________________________________ // Taken from https://github.com/AliceO2Group/AliceO2/blob/be5a2bb6c1be6757b7a496f9e90d470304d98fe7/Common/DCAFitter/include/DCAFitter/FwdDCAFitterN.h#L1281 // Re-adapted for this task - bool propagateToVtx(o2::track::TrackParCovFwd& t, const std::array& PV, const std::array& PVcov) const + template + void propagateToVtx(o2::track::TrackParCovFwd& t, TCollision const& collision, std::array& dca) const { + dca[0] = o2::track::DefaultDCA; + dca[1] = o2::track::DefaultDCA; + dca[2] = o2::track::DefaultDCA; + // propagate track to vertex including MCS effects if material budget included, simple propagation to Z otherwise float x2x0 = 0; - auto mb = lut->getMatBudget(t.getX(), t.getY(), t.getZ(), PV[0], PV[1], PV[2]); + auto mb = lut->getMatBudget(t.getX(), t.getY(), t.getZ(), collision.posX(), collision.posY(), collision.posZ()); x2x0 = static_cast(mb.meanX2X0); - return t.propagateToVtxhelixWithMCS(PV[2], {PV[0], PV[1]}, PVcov, magField, x2x0); + t.propagateToVtxhelixWithMCS(collision.posZ(), {collision.posX(), collision.posY()}, std::array{collision.covXX(), collision.covYY()}, magField, x2x0); + + dca[0] = t.getX() - collision.posX(); + dca[1] = t.getY() - collision.posY(); + dca[2] = t.getZ() - collision.posZ(); + } + + //___________________________________________________________________ + // Taken from https://github.com/AliceO2Group/O2Physics/blob/master/Common/Core/fwdtrackUtilities.h#L183 + // Re-adapted for this task + template + void propagateToVtxNew(o2::track::TrackParCovFwd& t, TCollision const& collision, std::array& dca) const + { + dca[0] = o2::track::DefaultDCA; + dca[1] = o2::track::DefaultDCA; + dca[2] = o2::track::DefaultDCA; + t.propagateToDCAhelix(magField, {collision.posX(), collision.posY(), collision.posZ()}, dca); } - template - std::vector buildV0s(TCollision const& collision, TMFTTracks const& /*mftTracks*/, TTracks const& besttracks, TMCParticles const& mcParticles) + template + std::vector buildV0s(TCollision const& collision, TMFTTracks const& /*mftTracks*/, TTracks const& besttracks, TMCCollisions const& /*mccollisions*/, TMCParticles const& mcParticles) { std::vector v0; for (const auto& [amft1, amft2] : combinations(besttracks, besttracks)) { @@ -2087,6 +2383,19 @@ struct forwardlambdakzeroanalysis { continue; if (mftNegative.pt() < v0Selections.minTrackPt) continue; + if (mftPositive.pt() > v0Selections.maxTrackPt) + continue; + if (mftNegative.pt() > v0Selections.maxTrackPt) + continue; + + if (mftPositive.pz() < v0Selections.minTrackPz) + continue; + if (mftNegative.pz() < v0Selections.minTrackPz) + continue; + if (mftPositive.pz() > v0Selections.maxTrackPz) + continue; + if (mftNegative.pz() > v0Selections.maxTrackPz) + continue; // Consider only tracks of opposite charges if (mftPositive.sign() < 0) @@ -2106,15 +2415,15 @@ struct forwardlambdakzeroanalysis { o2::track::TrackParCovFwd pars2{mftNegative.z(), tpars2, tcovs2, mftNegative.chi2()}; o2::track::TrackParCovFwd pars2Copy{mftNegative.z(), tpars2, tcovs2, mftNegative.chi2()}; - propagateToVtx(pars1Copy, std::array{collision.posX(), collision.posY(), collision.posZ()}, std::array{collision.covXX(), collision.covYY()}); - propagateToVtx(pars2Copy, std::array{collision.posX(), collision.posY(), collision.posZ()}, std::array{collision.covXX(), collision.covYY()}); - float dcaPosToPVx = pars1Copy.getX() - collision.posX(); - float dcaPosToPVy = pars1Copy.getY() - collision.posY(); - float dcaPosToPVz = pars1Copy.getZ() - collision.posZ(); - - float dcaNegToPVx = pars2Copy.getX() - collision.posX(); - float dcaNegToPVy = pars2Copy.getY() - collision.posY(); - float dcaNegToPVz = pars2Copy.getZ() - collision.posZ(); + std::array dcaPosToPV{o2::track::DefaultDCA, o2::track::DefaultDCA, o2::track::DefaultDCA}; + std::array dcaNegToPV{o2::track::DefaultDCA, o2::track::DefaultDCA, o2::track::DefaultDCA}; + if (useNewPropagationToVtx) { + propagateToVtxNew(pars1Copy, collision, dcaPosToPV); + propagateToVtxNew(pars2Copy, collision, dcaNegToPV); + } else { + propagateToVtx(pars1Copy, collision, dcaPosToPV); + propagateToVtx(pars2Copy, collision, dcaNegToPV); + } // Move close to minima int nCand = 0; @@ -2141,15 +2450,15 @@ struct forwardlambdakzeroanalysis { // get decay vertex coordinates Vec3D vtx = fitter.getPCACandidate(); - pairInfo.X = vtx[0] - collision.posX(); - pairInfo.Y = vtx[1] - collision.posY(); - pairInfo.Z = vtx[2] - collision.posZ(); + pairInfo.X = vtx[0]; + pairInfo.Y = vtx[1]; + pairInfo.Z = vtx[2]; // get daughter DCA to PV - pairInfo.dcaPosToPVxy = std::sqrt(dcaPosToPVx * dcaPosToPVx + dcaPosToPVy * dcaPosToPVy); - pairInfo.dcaNegToPVxy = std::sqrt(dcaNegToPVx * dcaNegToPVx + dcaNegToPVy * dcaNegToPVy); - pairInfo.dcaPosToPVz = dcaPosToPVz; - pairInfo.dcaNegToPVz = dcaNegToPVz; + pairInfo.dcaPosToPVxy = std::hypot(dcaPosToPV[0], dcaPosToPV[1]); + pairInfo.dcaNegToPVxy = std::hypot(dcaNegToPV[0], dcaNegToPV[1]); + pairInfo.dcaPosToPVz = dcaPosToPV[2]; + pairInfo.dcaNegToPVz = dcaNegToPV[2]; // get daughter momenta pairInfo.positiveMomentum[0] = lTrack1.getPx(); @@ -2173,20 +2482,21 @@ struct forwardlambdakzeroanalysis { pairInfo.OpAngle = track1Momentum.Angle(track2Momentum); // Radius - pairInfo.Radius = std::sqrt(pairInfo.X * pairInfo.X + pairInfo.Y * pairInfo.Y); + pairInfo.Radius = std::hypot(pairInfo.X - collision.posX(), pairInfo.Y - collision.posY()); + pairInfo.Zdist = (pairInfo.Z - collision.posZ()); // Dist over tot mom. float px = pairInfo.positiveMomentum[0] + pairInfo.negativeMomentum[0]; float py = pairInfo.positiveMomentum[1] + pairInfo.negativeMomentum[1]; float pz = pairInfo.positiveMomentum[2] + pairInfo.negativeMomentum[2]; - pairInfo.DistOverTotMom = std::sqrt(pairInfo.X * pairInfo.X + pairInfo.Y * pairInfo.Y + pairInfo.Z * pairInfo.Z) / std::sqrt(px * px + py * py + pz * pz); + pairInfo.DistOverTotMom = std::hypot(pairInfo.X - collision.posX(), pairInfo.Y - collision.posY(), pairInfo.Z - collision.posZ()) / std::hypot(px, py, pz); // Z dist over pz - pairInfo.ZdistOverPz = pairInfo.Z / pz; + pairInfo.ZdistOverPz = (pairInfo.Z - collision.posZ()) / pz; // V0 Momenta - pairInfo.pT = std::sqrt(px * px + py * py); - pairInfo.pTot = std::sqrt(px * px + py * py + pz * pz); + pairInfo.pT = std::hypot(px, py); + pairInfo.pTot = std::hypot(px, py, pz); pairInfo.pZ = pz; // Armenteros-Podolanski variables @@ -2258,6 +2568,11 @@ struct forwardlambdakzeroanalysis { if (originatingV0.has_mcCollision()) { pairInfo.mcCollision = originatingV0.mcCollisionId(); // save this reference, please + + auto mcCollision = originatingV0.template mcCollision_as(); + // Radius + pairInfo.RadiusMc = std::hypot(pairInfo.xMc - mcCollision.posX(), pairInfo.yMc - mcCollision.posY()); + pairInfo.ZdistMc = (pairInfo.zMc - mcCollision.posZ()); } // acquire information @@ -2266,8 +2581,8 @@ struct forwardlambdakzeroanalysis { pairInfo.momentumMc[0] = originatingV0.px(); pairInfo.momentumMc[1] = originatingV0.py(); pairInfo.momentumMc[2] = originatingV0.pz(); - pairInfo.pTotMc = std::sqrt(pairInfo.momentumMc[0] * pairInfo.momentumMc[0] + pairInfo.momentumMc[1] * pairInfo.momentumMc[1] + pairInfo.momentumMc[2] * pairInfo.momentumMc[2]); - pairInfo.pTMc = std::sqrt(pairInfo.momentumMc[0] * pairInfo.momentumMc[0] + pairInfo.momentumMc[1] * pairInfo.momentumMc[1]); + pairInfo.pTotMc = std::hypot(pairInfo.momentumMc[0], pairInfo.momentumMc[1], pairInfo.momentumMc[2]); + pairInfo.pTMc = std::hypot(pairInfo.momentumMc[0], pairInfo.momentumMc[1]); pairInfo.pZMc = pairInfo.momentumMc[2]; if (pairInfo.pdgCode == PDG_t::kK0Short) @@ -2326,7 +2641,7 @@ struct forwardlambdakzeroanalysis { int nAntiLambdas = 0; int nD0s = 0; int nAntiD0s = 0; - std::vector V0s = buildV0s(collision, mftTracks, besttracks, static_cast(nullptr)); + std::vector V0s = buildV0s(collision, mftTracks, besttracks, static_cast(nullptr), static_cast(nullptr)); for (const auto& v0 : V0s) { // fill AP plot for all V0s histos.fill(HIST("GeneralQA/h2dArmenterosAll"), v0.AlphaArm, v0.QtArm); @@ -2369,8 +2684,8 @@ struct forwardlambdakzeroanalysis { // ______________________________________________________ // Simulated processing (subscribes to MC information too) - template - void analyzeRecoedV0sInMonteCarlo(TCollision const& collision, TMFTTracks const& mftTracks, TTracks const& besttracks, TBCs const& bcs, TMCParticles const& mcParticles) + template + void analyzeRecoedV0sInMonteCarlo(TCollision const& collision, TMCCollisions const& mcCollisions, TMFTTracks const& mftTracks, TTracks const& besttracks, TBCs const& bcs, TMCParticles const& mcParticles) { // Fire up CCDB initCCDB(bcs, collision); @@ -2388,6 +2703,13 @@ struct forwardlambdakzeroanalysis { // Fill recoed event properties fillReconstructedEventProperties(collision, bcs, centrality, collisionOccupancy, interactionRate, gapSide, selGapSide); + if (collision.has_mcCollision()) { + auto mcCollision = collision.template mcCollision_as(); + histos.fill(HIST("hEventPVxDiff"), mcCollision.posX(), (mcCollision.posX() - collision.posX())); + histos.fill(HIST("hEventPVyDiff"), mcCollision.posY(), (mcCollision.posY() - collision.posY())); + histos.fill(HIST("hEventPVzDiff"), mcCollision.posZ(), (mcCollision.posZ() - collision.posZ())); + } + histos.fill(HIST("hInteractionRateVsOccupancy"), interactionRate, collisionOccupancy); // __________________________________________ @@ -2397,7 +2719,7 @@ struct forwardlambdakzeroanalysis { int nAntiLambdas = 0; int nD0s = 0; int nAntiD0s = 0; - std::vector V0s = buildV0s(collision, mftTracks, besttracks, mcParticles); + std::vector V0s = buildV0s(collision, mftTracks, besttracks, mcCollisions, mcParticles); for (const auto& v0 : V0s) { if (v0.label < 0) { continue; @@ -2568,10 +2890,10 @@ struct forwardlambdakzeroanalysis { soa::Join const& tracks, soa::SmallGroups> const& besttracks, aod::BCsWithTimestamps const& bcs, - soa::Join const& /*mccollisions*/, + soa::Join const& mccollisions, aod::McParticles const& mcParticles) { - analyzeRecoedV0sInMonteCarlo(collision, tracks, besttracks, bcs, mcParticles); + analyzeRecoedV0sInMonteCarlo(collision, mccollisions, tracks, besttracks, bcs, mcParticles); } // ______________________________________________________ diff --git a/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx b/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx index b6dc1f3b843..ee589bb163c 100644 --- a/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx +++ b/PWGLF/Tasks/Strangeness/hStrangeCorrelation.cxx @@ -73,6 +73,7 @@ #include #include #include +#include #include #include #include @@ -125,8 +126,10 @@ struct HStrangeCorrelation { Configurable doCorrelationPion{"doCorrelationPion", false, "do Pion correlation"}; Configurable doGenEventSelection{"doGenEventSelection", true, "use event selections when performing closure test for the gen events"}; Configurable selectINELgtZERO{"selectINELgtZERO", true, "select INEL>0 events"}; + Configurable selectINELgtONE{"selectINELgtONE", false, "select INEL>1 events (at least 2 charged particles in |eta| < 1)"}; Configurable zVertexCut{"zVertexCut", 10, "Cut on PV position"}; Configurable requireAllGoodITSLayers{"requireAllGoodITSLayers", false, " require that in the event all ITS are good"}; + Configurable rejectSameBunchPileup{"rejectSameBunchPileup", false, "reject collisions associated with the same found-by-T0 bunch crossing"}; Configurable requireGoodTriggerTVX{"requireGoodTriggerTVX", false, " require acceptable FT0C-FT0A time difference"}; Configurable requireGoodZvtxFT0vsPV{"requireGoodZvtxFT0vsPV", false, " require small difference between z-vertex from PV and from FT0"}; Configurable skipUnderOverflowInTHn{"skipUnderOverflowInTHn", false, "skip under/overflow in THns"}; @@ -140,6 +143,8 @@ struct HStrangeCorrelation { Configurable doMirroringInDelataEta{"doMirroringInDelataEta", false, "if true, fill only positive delta eta and mirror the negative side in post processing, Adjust the delta axis!"}; Configurable doMassSpectrumCheck{"doMassSpectrumCheck", false, "if true, add and fill invariant-mass spectrum"}; Configurable doCorrelationsHadronV0daughter{"doCorrelationsHadronV0daughter", false, "if true, do correlations of hadrons with V0 daughters"}; + Configurable doLocalDensityStudy{"doLocalDensityStudy", false, "if true, create and fill the pt vs eta vs local density spectra of triggers and V0s"}; + Configurable localDensityConeRadius{"localDensityConeRadius", 0.4, "radius of the cone in which the local density is counted"}; } masterConfigurations; // master analysis switches @@ -174,6 +179,7 @@ struct HStrangeCorrelation { ConfigurableAxis axisPtTrigger{"axisPtTrigger", {VARIABLE_WIDTH, 0.0, 1.0, 2.0, 3.0, 100}, "pt associated axis for histograms"}; ConfigurableAxis axisPtQA{"axisPtQA", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for QA histograms"}; ConfigurableAxis axisMassNSigma{"axisMassNSigma", {40, -2, 2}, "Axis for mass Nsigma"}; + ConfigurableAxis axisLocalDensity{"axisLocalDensity", {21, -0.5, 20.5}, "local density (number of tracks in the cone)"}; ConfigurableAxis axisK0ShortMass{"axisK0ShortMass", {200, 0.400f, 0.600f}, "Inv. Mass (GeV/c^{2})"}; ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.01f, 1.21f}, "Inv. Mass (GeV/c^{2})"}; ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 20, 40, 60, 100, 120, 140, 160, 180, 200, 220, 240, 260, 280, 300}, "Binning of the Multiplicity axis in model prediction process"}; @@ -216,7 +222,7 @@ struct HStrangeCorrelation { Configurable assocMaxTPCSharedClusters{"assocMaxTPCSharedClusters", 200, "maximum number of shared TPC clusters (inclusive) for assoc primary tracks"}; Configurable triggerRequireL0{"triggerRequireL0", false, "require ITS L0 cluster for trigger"}; Configurable assocRequireL0{"assocRequireL0", true, "require ITS L0 cluster for assoc primary track"}; - Configurable minTPCChi2PerClusterAssociated{"minTPCChi2PerClusterAssociated", 4.0f, "Minimum TPC chi2 per cluster for associated primary tracks"}; + Configurable maxTPCChi2PerClusterAssociated{"maxTPCChi2PerClusterAssociated", 4.0f, "Maximum TPC chi2 per cluster for associated primary tracks"}; Configurable checksRequireTPCChi2{"checksRequireTPCChi2", false, "require TPC chi2 per cluster for trigger and associated primary tracks"}; Configurable requireClusterInITS{"requireClusterInITS", false, "require cluster in ITS for V0 and cascade daughter tracks"}; Configurable minITSClustersForDaughterTracks{"minITSClustersForDaughterTracks", 1, "Minimum number of ITS clusters for V0 daughter tracks"}; @@ -324,7 +330,12 @@ struct HStrangeCorrelation { // trimmed by skipUnderOverflowInTHn, so what you configure is what you get. ConfigurableAxis axisGenStudyNch{"axisGenStudyNch", {VARIABLE_WIDTH, 0.0f, 2.0f, 5.0f, 10.0f, 15.0f, 20.0f, 25.0f, 30.0f, 40.0f, 60.0f, 100.0f}, "generated charged multiplicity in |#eta| < 0.8"}; Configurable doClosureTestStages{"doClosureTestStages", true, "create and fill the whole ClosureTest/PairLossK0 folder: the truth and any-reconstructed-object stages of the truth h-K0 pair, mirroring the first processPairLossK0MC stages"}; + Configurable doEventQualityStudy{"doEventQualityStudy", false, "add eight EventQuality folders to the closure PairLossK0 study; requires doClosureTestStages"}; + Configurable eventQualityDeltaPhiBins{"eventQualityDeltaPhiBins", 36, "delta phi bins in the sparse event-quality histograms"}; + Configurable eventQualityDeltaEtaBins{"eventQualityDeltaEtaBins", 20, "delta eta bins in the sparse event-quality histograms"}; Configurable applyRecoEventSelection{"applyRecoEventSelection", true, "apply the standard reconstructed-event selection in the K0 pair-loss diagnostic"}; + Configurable fillFinalPairOnce{"fillFinalPairOnce", true, "part 1: fill each truth h-K0 pair at most once at the final stage. Set false to loop over all reconstructed trigger x K0 combinations, as the data path does"}; + Configurable finalPairUseBestCollisionOnly{"finalPairUseBestCollisionOnly", true, "part 1: build the final trigger and K0 objects only in the best collision. Set false to use every associated reconstructed collision that passes the event selection, pairing within one collision, as the data path does"}; Configurable daughterPtMin{"daughterPtMin", 0.05f, "minimum generated daughter pT for the findable K0 category"}; Configurable daughterEtaMax{"daughterEtaMax", 0.9f, "maximum absolute generated daughter eta for the findable K0 category"}; Configurable minRadius{"minRadius", 0.8f, "minimum radius in metres used for the minimum delta-phi-star search"}; @@ -386,22 +397,22 @@ struct HStrangeCorrelation { // objects to use for efficiency corrections TH2F* hEfficiencyTrigger = nullptr; TH3F* hEfficiencyTriggerMult = nullptr; - THnF* hEfficiencyTriggerMultVsPhi = nullptr; + THnT* hEfficiencyTriggerMultVsPhi = nullptr; TH2F* hEfficiencyPion = nullptr; TH2F* hEfficiencyK0Short = nullptr; - THnF* hEfficiencyK0ShortMultVsPhi = nullptr; + THnT* hEfficiencyK0ShortMultVsPhi = nullptr; TH2F* hEfficiencyLambda = nullptr; - THnF* hEfficiencyLambdaMultVsPhi = nullptr; + THnT* hEfficiencyLambdaMultVsPhi = nullptr; TH2F* hEfficiencyAntiLambda = nullptr; - THnF* hEfficiencyAntiLambdaMultVsPhi = nullptr; + THnT* hEfficiencyAntiLambdaMultVsPhi = nullptr; TH2F* hEfficiencyXiMinus = nullptr; - THnF* hEfficiencyXiMinusMultVsPhi = nullptr; + THnT* hEfficiencyXiMinusMultVsPhi = nullptr; TH2F* hEfficiencyXiPlus = nullptr; - THnF* hEfficiencyXiPlusMultVsPhi = nullptr; + THnT* hEfficiencyXiPlusMultVsPhi = nullptr; TH2F* hEfficiencyOmegaMinus = nullptr; - THnF* hEfficiencyOmegaMinusMultVsPhi = nullptr; + THnT* hEfficiencyOmegaMinusMultVsPhi = nullptr; TH2F* hEfficiencyOmegaPlus = nullptr; - THnF* hEfficiencyOmegaPlusMultVsPhi = nullptr; + THnT* hEfficiencyOmegaPlusMultVsPhi = nullptr; TH2F* hEfficiencyHadron = nullptr; TH3F* hEfficiencyHadronMult = nullptr; TH1F* hPurityHadron = nullptr; @@ -524,6 +535,23 @@ struct HStrangeCorrelation { "V0 final selection", "Final reconstructed pair"}; + // Independent event classifications, not cumulative cuts. Values are fixed + // diagnostic bins (labels below), and never change the parent pair selection. + static constexpr int PairLossNEventQualityGroups = 8; + static constexpr std::array PairLossEventQualityNames = { + "NContributors", "PVMaxPull", "PVPurity", "CollisionAssociation", + "TimeResolution", "Occupancy", "GenMultiplicity", "EventShape"}; + static constexpr std::array, PairLossNEventQualityGroups> PairLossEventQualityLabels = {{ + {"no contributors", "1-2", "3-5", "6-10", "11-20", ">=21"}, + {"invalid covariance/pull", "max |pull| <1", "1<=max |pull|<3", "3<=max |pull|<5", "max |pull|>=5", "unused"}, + {"no PV tracks", "missing MC labels", "purity <0.95", "0.95<=purity<1", "purity =1", "unused"}, + {"no matched tracks", "one rec collision", "multiple: best fraction >=0.9", "multiple: 0.5<=fraction<0.9", "multiple: fraction <0.5", "unused"}, + {"invalid time resolution", "0=500 ns", "unused"}, + {"unavailable", "0", "1-99", "100-499", "500-999", ">=1000"}, + {"0", "1-4", "5-9", "10-19", "20-39", ">=40"}, + {"fewer than 3 shape tracks", "S_T<0.3", "0.3<=S_T<0.7", "S_T>=0.7", "unused", "unused"}, + }}; + struct PairLossTrackInfo { int64_t globalIndex = -1; float pt = 0.0f; @@ -538,6 +566,7 @@ struct HStrangeCorrelation { // hStrangeCorrelationFilter.cxx, which uses exactly these two columns. float dcaXY = 0.0f; float signed1Pt = 0.0f; + int64_t collisionId = -1; }; // First-failing-condition breakdown for the stage3->4 gate ("Trigger track, best collision" @@ -593,6 +622,7 @@ struct HStrangeCorrelation { float cosPA = 0.0f; float dcaDaughters = 0.0f; float massNSigma = 0.0f; + int64_t collisionId = -1; }; struct PairLossTruthTrackInfo { @@ -604,6 +634,18 @@ struct HStrangeCorrelation { bool physicalPrimary = false; }; + // One object of a GenStudy h-K0 pair: generated kinematics plus whether it has a + // reconstructed counterpart, in exactly the sense the GenStudy single-particle + // folders use. + struct GenStudyPairObject { + float pt = 0.0f; + float eta = 0.0f; + float phi = 0.0f; + int64_t globalIndex = -1; + int64_t motherIndex = -1; + bool reconstructed = false; + }; + struct PairLossTruthK0Info { int64_t globalIndex = -1; float pt = 0.0f; @@ -697,6 +739,62 @@ struct HStrangeCorrelation { return shiftedDeltaPhi; } + /// Counts how many associated-quality tracks lie inside a cone of radius localDensityConeRadius around (etaRef, phiRef), skipping the listed track indices + template + int computeLocalDensity(float etaRef, float phiRef, TTracks const& tracks, std::initializer_list skipIds) + { + int localDensity = 0; + for (auto const& track : tracks) { + if (std::find(skipIds.begin(), skipIds.end(), track.globalIndex()) != skipIds.end() || !isValidAssocHadron(track)) { + continue; + } + double deltaEta = track.eta() - etaRef; + double deltaPhi = RecoDecay::constrainAngle(track.phi() - phiRef, -PI); + if (std::hypot(deltaEta, deltaPhi) < masterConfigurations.localDensityConeRadius) { + localDensity++; + } + } + return localDensity; + } + + /// Collects the MC index of a particle and of its decay products, so that a particle never contributes to its own local density + template + void collectDescendantIds(TMcParticle const& mcParticle, std::vector& ids, int depth = 0) + { + ids.push_back(mcParticle.globalIndex()); + if (depth >= 3 || !mcParticle.has_daughters()) { + return; + } + for (auto const& daughter : mcParticle.template daughters_as()) { + collectDescendantIds(daughter, ids, depth + 1); + } + } + + /// Generated-level counterpart: the density the reconstruction would have measured around the generated + /// direction, i.e. the same associated-quality tracks of the same collision, so that the axis means the + /// same thing here as in the reconstructed histograms and can be used to correct data binned in it + template + int computeLocalDensityGen(TMcParticle const& mcParticle, TTracks const& tracks) + { + std::vector skipIds; + collectDescendantIds(mcParticle, skipIds); + int localDensity = 0; + for (auto const& track : tracks) { + if (!isValidAssocHadron(track)) { + continue; + } + if (track.has_mcParticle() && std::find(skipIds.begin(), skipIds.end(), track.mcParticleId()) != skipIds.end()) { + continue; + } + double deltaEta = track.eta() - mcParticle.eta(); + double deltaPhi = RecoDecay::constrainAngle(track.phi() - mcParticle.phi(), -PI); + if (std::hypot(deltaEta, deltaPhi) < masterConfigurations.localDensityConeRadius) { + localDensity++; + } + } + return localDensity; + } + static bool isPairLossTriggerPdg(int pdgCode) { const int absPdg = std::abs(pdgCode); @@ -717,7 +815,8 @@ struct HStrangeCorrelation { .itsClusters = track.itsNCls(), .hasLayer0 = static_cast(TESTBIT(track.itsClusterMap(), 0)), .dcaXY = track.dcaXY(), - .signed1Pt = track.signed1Pt()}; + .signed1Pt = track.signed1Pt(), + .collisionId = static_cast(track.collisionId())}; } // Replicates preFilterTracks and isValidTrigger() from hStrangeCorrelationFilter.cxx @@ -817,21 +916,21 @@ struct HStrangeCorrelation { hEfficiencyTrigger = dynamic_cast(listEfficiencies->FindObject("hEfficiencyTrigger")); hEfficiencyTriggerMult = dynamic_cast(listEfficiencies->FindObject("hEfficiencyTriggerMult")); - hEfficiencyTriggerMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyTriggerMultVsPhi")); + hEfficiencyTriggerMultVsPhi = dynamic_cast*>(listEfficiencies->FindObject("hEfficiencyTriggerMultVsPhi")); hEfficiencyK0Short = dynamic_cast(listEfficiencies->FindObject("hEfficiencyK0Short")); - hEfficiencyK0ShortMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyK0ShortMultVsPhi")); + hEfficiencyK0ShortMultVsPhi = dynamic_cast*>(listEfficiencies->FindObject("hEfficiencyK0ShortMultVsPhi")); hEfficiencyLambda = dynamic_cast(listEfficiencies->FindObject("hEfficiencyLambda")); - hEfficiencyLambdaMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyLambdaMultVsPhi")); + hEfficiencyLambdaMultVsPhi = dynamic_cast*>(listEfficiencies->FindObject("hEfficiencyLambdaMultVsPhi")); hEfficiencyAntiLambda = dynamic_cast(listEfficiencies->FindObject("hEfficiencyAntiLambda")); - hEfficiencyAntiLambdaMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyAntiLambdaMultVsPhi")); + hEfficiencyAntiLambdaMultVsPhi = dynamic_cast*>(listEfficiencies->FindObject("hEfficiencyAntiLambdaMultVsPhi")); hEfficiencyXiMinus = dynamic_cast(listEfficiencies->FindObject("hEfficiencyXiMinus")); - hEfficiencyXiMinusMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyXiMinusMultVsPhi")); + hEfficiencyXiMinusMultVsPhi = dynamic_cast*>(listEfficiencies->FindObject("hEfficiencyXiMinusMultVsPhi")); hEfficiencyXiPlus = dynamic_cast(listEfficiencies->FindObject("hEfficiencyXiPlus")); - hEfficiencyXiPlusMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyXiPlusMultVsPhi")); + hEfficiencyXiPlusMultVsPhi = dynamic_cast*>(listEfficiencies->FindObject("hEfficiencyXiPlusMultVsPhi")); hEfficiencyOmegaMinus = dynamic_cast(listEfficiencies->FindObject("hEfficiencyOmegaMinus")); - hEfficiencyOmegaMinusMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyOmegaMinusMultVsPhi")); + hEfficiencyOmegaMinusMultVsPhi = dynamic_cast*>(listEfficiencies->FindObject("hEfficiencyOmegaMinusMultVsPhi")); hEfficiencyOmegaPlus = dynamic_cast(listEfficiencies->FindObject("hEfficiencyOmegaPlus")); - hEfficiencyOmegaPlusMultVsPhi = dynamic_cast(listEfficiencies->FindObject("hEfficiencyOmegaPlusMultVsPhi")); + hEfficiencyOmegaPlusMultVsPhi = dynamic_cast*>(listEfficiencies->FindObject("hEfficiencyOmegaPlusMultVsPhi")); hEfficiencyHadron = dynamic_cast(listEfficiencies->FindObject("hEfficiencyHadron")); hEfficiencyHadronMult = dynamic_cast(listEfficiencies->FindObject("hEfficiencyHadronMult")); hEfficiencyPion = dynamic_cast(listEfficiencies->FindObject("hEfficiencyPion")); @@ -1310,7 +1409,7 @@ struct HStrangeCorrelation { if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) { continue; } - if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) { + if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() > trackSelection.maxTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() > trackSelection.maxTPCChi2PerClusterAssociated)) { continue; } if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) { @@ -1867,7 +1966,7 @@ struct HStrangeCorrelation { if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || bachtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) { continue; } - if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || bachtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) { + if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() > trackSelection.maxTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() > trackSelection.maxTPCChi2PerClusterAssociated || bachtrack.tpcChi2NCl() > trackSelection.maxTPCChi2PerClusterAssociated)) { continue; } if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || bachtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) { @@ -2747,8 +2846,18 @@ struct HStrangeCorrelation { // bin by bin and NotReconstructed/Gen reads directly as the loss. histos.add("PairLossK0/GenStudy/Gen/hTrigger", "generated triggers;#it{p}_{T}^{gen} (GeV/#it{c});#eta^{gen};#varphi^{gen};#it{N}_{ch}^{gen}", kTHnF, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi, axisGenStudyNch}); histos.add("PairLossK0/GenStudy/Gen/hK0Short", "generated K0s;#it{p}_{T}^{gen} (GeV/#it{c});#eta^{gen};#varphi^{gen};#it{N}_{ch}^{gen};findable", kTHnF, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi, axisGenStudyNch, axisGenStudyFindable}); + // h-K0 correlations of the very same objects. Gen/ is every generated pair and the + // four exclusive classes below split it by which of the two objects was + // reconstructed, so Reconstructed + OnlyTriggerReconstructed + OnlyK0Reconstructed + // + NotReconstructed equals Gen bin by bin. + histos.add("PairLossK0/GenStudy/Gen/hCorrelation", "generated h-K0s pairs;#Delta#eta;#Delta#varphi;#it{p}_{T}^{trigger} (GeV/#it{c});#it{p}_{T}^{K^{0}_{S}} (GeV/#it{c});#it{N}_{ch}^{gen}", kTHnF, {axisDeltaEtaNDim, axisDeltaPhiNDim, axisPtTriggerNDim, axisPtAssocNDim, axisGenStudyNch}); histos.addClone("PairLossK0/GenStudy/Gen/", "PairLossK0/GenStudy/Reconstructed/"); histos.addClone("PairLossK0/GenStudy/Gen/", "PairLossK0/GenStudy/NotReconstructed/"); + // Only the correlation exists for the two mixed classes -- a single particle is + // either reconstructed or not, so cloning the single-particle folders here would + // only produce histograms with no meaning. + histos.add("PairLossK0/GenStudy/OnlyTriggerReconstructed/hCorrelation", "h-K0s pairs with only the trigger reconstructed;#Delta#eta;#Delta#varphi;#it{p}_{T}^{trigger} (GeV/#it{c});#it{p}_{T}^{K^{0}_{S}} (GeV/#it{c});#it{N}_{ch}^{gen}", kTHnF, {axisDeltaEtaNDim, axisDeltaPhiNDim, axisPtTriggerNDim, axisPtAssocNDim, axisGenStudyNch}); + histos.add("PairLossK0/GenStudy/OnlyK0Reconstructed/hCorrelation", "h-K0s pairs with only the K0s reconstructed;#Delta#eta;#Delta#varphi;#it{p}_{T}^{trigger} (GeV/#it{c});#it{p}_{T}^{K^{0}_{S}} (GeV/#it{c});#it{N}_{ch}^{gen}", kTHnF, {axisDeltaEtaNDim, axisDeltaPhiNDim, axisPtTriggerNDim, axisPtAssocNDim, axisGenStudyNch}); for (auto const& histogram : {histos.get(HIST("PairLossK0/GenStudy/Gen/hK0Short")), histos.get(HIST("PairLossK0/GenStudy/Reconstructed/hK0Short")), @@ -2804,6 +2913,9 @@ struct HStrangeCorrelation { } histos.add("hTrackEtaVsPtVsPhi", "hTrackEtaVsPtVsPhi", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi}); histos.add("hAssocTrackEtaVsPtVsPhi", "hAssocTrackEtaVsPtVsPhi", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi}); + if (masterConfigurations.doLocalDensityStudy) { + histos.add("hTrackEtaVsPtVsLocalDensity", "hTrackEtaVsPtVsLocalDensity", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisLocalDensity}); + } // histos.add("hTrackAttempt", "Attempt", kTH3F, {axisPtQA, axisEta, axisPhi}); } if (doprocessSameEventHPions || doprocessSameEventHHadrons || doprocessMixedEventHPions || doprocessMixedEventHHadrons) { @@ -2853,6 +2965,10 @@ struct HStrangeCorrelation { histos.add(fmt::format("h{}EtaVsPtVsPhiVsCent", Particlenames[i]).c_str(), "", kTHnF, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi, axesConfigurations.axisMult}); histos.add(fmt::format("h{}EtaVsPtVsPhiVsCentBg", Particlenames[i]).c_str(), "", kTHnF, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi, axesConfigurations.axisMult}); } + if (masterConfigurations.doLocalDensityStudy && i < AssocV0Types) { + histos.add(fmt::format("h{}EtaVsPtVsLocalDensity", Particlenames[i]).c_str(), "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisLocalDensity}); + histos.add(fmt::format("h{}EtaVsPtVsLocalDensityBg", Particlenames[i]).c_str(), "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisLocalDensity}); + } histos.add(fmt::format("h3d{}Spectrum", Particlenames[i]).c_str(), fmt::format("h3d{}Spectrum", Particlenames[i]).c_str(), kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisMult, axesConfigurations.axisMassNSigma}); histos.add(fmt::format("h3d{}SpectrumY", Particlenames[i]).c_str(), fmt::format("h3d{}SpectrumY", Particlenames[i]).c_str(), kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisMult, axesConfigurations.axisMassNSigma}); hStrange = true; @@ -2963,6 +3079,15 @@ struct HStrangeCorrelation { } histos.addClone("Generated/", "GeneratedWithPV/"); + // The density axis is the reconstructed one on both sides: these generated histograms are counted + // from the tracks of the best collision, exactly like their reconstructed counterparts. + if (masterConfigurations.doLocalDensityStudy && masterConfigurations.doPPAnalysis) { + histos.add("GeneratedWithPV/hTriggerLocalDensity", "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisLocalDensity}); + for (int i = 0; i < AssocParticleTypesNoHadron; i++) { + histos.add(fmt::format("GeneratedWithPV/h{}LocalDensity", Particlenames[i]).c_str(), "", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisLocalDensity}); + } + } + // histograms within |y|<0.5, vs multiplicity for (int i = 0; i < AssocParticleTypesNoHadron; i++) { histos.add(fmt::format("GeneratedWithPV/h{}_MidYVsMult", Particlenames[i]).c_str(), "", kTH2F, {axesConfigurations.axisPtQA, axesConfigurations.axisMult}); @@ -3014,6 +3139,32 @@ struct HStrangeCorrelation { histos.add("ClosureTest/PairLossK0/Final/sameEvent/K0Short", "truth h-K0 pairs whose trigger and K0 both have a fully selected reconstructed counterpart in the same reconstructed collision", kTHnF, {axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim, axisVtxZNDim, axisMultNDim}); histos.add("ClosureTest/PairLossK0/Final/hTrigger", "truth triggers with a fully selected reconstructed counterpart;#it{p}_{T}^{truth} (GeV/#it{c});#eta^{truth};#varphi^{truth}", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi}); histos.add("ClosureTest/PairLossK0/Final/hK0Short", "truth K0s with a fully selected reconstructed counterpart;#it{p}_{T}^{truth} (GeV/#it{c});#eta^{truth};#varphi^{truth}", kTH3F, {axesConfigurations.axisPtQA, axesConfigurations.axisEta, axesConfigurations.axisPhi}); + if (pairLossK0Configurations.doEventQualityStudy) { + if (pairLossK0Configurations.eventQualityDeltaPhiBins <= 0 || pairLossK0Configurations.eventQualityDeltaEtaBins <= 0) { + LOGF(fatal, "Event-quality angular bin counts must be positive"); + } + // Six sparse axes; omit vertex and multiplicity dimensions. Each folder + // has exactly three histograms, including its event/trigger denominators. + const std::vector qualityAxes = { + {6, -0.5, 5.5, "event class"}, + {3, -0.5, 2.5, "entry kind"}, + {pairLossK0Configurations.eventQualityDeltaPhiBins, axisRanges[0][0], axisRanges[0][1], "#Delta#varphi^{truth}"}, + {pairLossK0Configurations.eventQualityDeltaEtaBins, axisRanges[1][0], axisRanges[1][1], "#Delta#eta^{truth}"}, + axisPtAssocNDim, + axisPtTriggerNDim, + }; + for (int group = 0; group < PairLossNEventQualityGroups; ++group) { + for (auto const& stage : {"Truth", "AnyTrackBoth", "Final"}) { + auto histogram = histos.add(fmt::format("ClosureTest/PairLossK0/EventQuality/{}/{}", PairLossEventQualityNames[group], stage), "unit-weight counts; select entry kind before projection", kTHnSparseF, qualityAxes); + for (size_t bin = 0; bin < PairLossEventQualityLabels[group].size(); ++bin) { + histogram->GetAxis(0)->SetBinLabel(bin + 1, PairLossEventQualityLabels[group][bin].data()); + } + histogram->GetAxis(1)->SetBinLabel(1, "event (common baseline)"); + histogram->GetAxis(1)->SetBinLabel(2, "trigger"); + histogram->GetAxis(1)->SetBinLabel(3, "pair"); + } + } + } } for (int i = 0; i < AssocParticleTypes; i++) { if (TESTBIT(doCorrelation, i)) { @@ -3123,6 +3274,10 @@ struct HStrangeCorrelation { if (!collision.sel8()) { return false; } + if (!collision.selection_bit(aod::evsel::kIsTriggerTVX) && masterConfigurations.requireGoodTriggerTVX) { + // FT0 vertex (acceptable FT0C-FT0A time difference) collisions + return false; + } if (std::abs(collision.posZ()) > masterConfigurations.zVertexCut) { return false; } @@ -3132,9 +3287,21 @@ struct HStrangeCorrelation { if (!collision.isInelGt0() && masterConfigurations.selectINELgtZERO) { return false; } + if (!collision.isInelGt1() && masterConfigurations.selectINELgtONE) { + return false; + } if (!collision.selection_bit(aod::evsel::kIsGoodITSLayersAll) && masterConfigurations.requireAllGoodITSLayers) { return false; } + if (!collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV) && masterConfigurations.requireGoodZvtxFT0vsPV) { + // removes collisions with large differences between z of PV by tracks and z of PV from FT0 A-C time difference + // use this cut at low multiplicities with caution + return false; + } + if (!collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup) && masterConfigurations.rejectSameBunchPileup) { + // rejects collisions which are associated with the same "found-by-T0" bunch crossing + return false; + } if (zorroMask.value != "") { auto bc = collision.template bc_as(); initZorro(bc); @@ -3403,7 +3570,7 @@ struct HStrangeCorrelation { } } - void runSameEventHV0sCore(aod::AssocV0s const& associatedV0s, aod::TriggerTracks const& triggerTracks, + void runSameEventHV0sCore(aod::AssocV0s const& associatedV0s, aod::TriggerTracks const& triggerTracks, TracksComplete const& tracks, float pvx, float pvy, float pvz, float cent, float multNTracksPVeta1, double bField) { std::variant colBinning = @@ -3444,7 +3611,7 @@ struct HStrangeCorrelation { if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) { continue; } - if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) { + if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() > trackSelection.maxTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() > trackSelection.maxTPCChi2PerClusterAssociated)) { continue; } if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) { @@ -3460,6 +3627,7 @@ struct HStrangeCorrelation { continue; } uint64_t selMap = v0selectionBitmap(v0Data, pvx, pvy, pvz); + const int localDensityV0 = masterConfigurations.doLocalDensityStudy ? computeLocalDensity(v0Data.eta(), v0Data.phi(), tracks, {v0Data.posTrackId(), v0Data.negTrackId()}) : 0; static_for<0, 2>([&](auto i) { constexpr int Index = i.value; @@ -3502,6 +3670,14 @@ struct HStrangeCorrelation { histos.fill(HIST("h") + HIST(V0names[Index]) + HIST("EtaVsPtVsPhiVsCent"), v0Data.pt(), v0Data.eta(), v0Data.phi(), cent, weight); } } + if (masterConfigurations.doLocalDensityStudy) { + if ((-massWindowConfigurations.maxBgNSigma < v0.invMassNSigma(Index) && v0.invMassNSigma(Index) < -massWindowConfigurations.minBgNSigma) || (+massWindowConfigurations.minBgNSigma < v0.invMassNSigma(Index) && v0.invMassNSigma(Index) < +massWindowConfigurations.maxBgNSigma)) { + histos.fill(HIST("h") + HIST(V0names[Index]) + HIST("EtaVsPtVsLocalDensityBg"), v0Data.pt(), v0Data.eta(), localDensityV0, weight); + } + if (-massWindowConfigurations.maxPeakNSigma < v0.invMassNSigma(Index) && v0.invMassNSigma(Index) < +massWindowConfigurations.maxPeakNSigma) { + histos.fill(HIST("h") + HIST(V0names[Index]) + HIST("EtaVsPtVsLocalDensity"), v0Data.pt(), v0Data.eta(), localDensityV0, weight); + } + } } } }); @@ -3526,6 +3702,9 @@ struct HStrangeCorrelation { histos.fill(HIST("hTriggerPrimaryEtaVsPt"), track.pt(), track.eta(), track.phi(), cent); } histos.fill(HIST("hTrackEtaVsPtVsPhi"), track.pt(), track.eta(), track.phi()); + if (masterConfigurations.doLocalDensityStudy) { + histos.fill(HIST("hTrackEtaVsPtVsLocalDensity"), track.pt(), track.eta(), computeLocalDensity(track.eta(), track.phi(), tracks, {track.globalIndex()})); + } } } @@ -3537,7 +3716,7 @@ struct HStrangeCorrelation { } template - void runSameEventHV0s(TCollision const& collision, aod::AssocV0s const& associatedV0s, aod::TriggerTracks const& triggerTracks) + void runSameEventHV0s(TCollision const& collision, aod::AssocV0s const& associatedV0s, aod::TriggerTracks const& triggerTracks, TracksComplete const& tracks) { const float cent = masterConfigurations.doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); @@ -3556,15 +3735,15 @@ struct HStrangeCorrelation { if (efficiencyFlags.applyEfficiencyCorrection) { initEfficiencyFromCCDB(bc); } - runSameEventHV0sCore(associatedV0s, triggerTracks, + runSameEventHV0sCore(associatedV0s, triggerTracks, tracks, collision.posX(), collision.posY(), collision.posZ(), cent, collision.multNTracksPVeta1(), bField); } void processSameEventHV0s(soa::Join::iterator const& collision, aod::AssocV0s const& associatedV0s, aod::TriggerTracks const& triggerTracks, - V0DatasWithoutTrackX const&, TracksComplete const&, aod::BCsWithTimestamps const&) + V0DatasWithoutTrackX const&, TracksComplete const& tracks, aod::BCsWithTimestamps const&) { - runSameEventHV0s(collision, associatedV0s, triggerTracks); + runSameEventHV0s(collision, associatedV0s, triggerTracks, tracks); } void processSameEventHCascades(soa::Join::iterator const& collision, @@ -3646,7 +3825,7 @@ struct HStrangeCorrelation { if (postrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || negtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated || bachtrack.tpcNClsCrossedRows() < trackSelection.minTPCNCrossedRowsAssociated) { continue; } - if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated || bachtrack.tpcChi2NCl() < trackSelection.minTPCChi2PerClusterAssociated)) { + if (trackSelection.checksRequireTPCChi2 && (postrack.tpcChi2NCl() > trackSelection.maxTPCChi2PerClusterAssociated || negtrack.tpcChi2NCl() > trackSelection.maxTPCChi2PerClusterAssociated || bachtrack.tpcChi2NCl() > trackSelection.maxTPCChi2PerClusterAssociated)) { continue; } if (trackSelection.requireClusterInITS && (postrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks || negtrack.itsNCls() < trackSelection.minITSClustersForDaughterTracks)) { @@ -4021,7 +4200,7 @@ struct HStrangeCorrelation { } } - void processMCGenerated(aod::McCollision const& /*mcCollision*/, soa::SmallGroups> const& collisions, aod::McParticles const& mcParticles) + void processMCGenerated(aod::McCollision const& /*mcCollision*/, soa::SmallGroups> const& collisions, aod::McParticles const& mcParticles, TracksCompleteMC const& tracks) { histos.fill(HIST("hClosureTestEventCounter"), 2.5f); @@ -4069,17 +4248,23 @@ struct HStrangeCorrelation { // determine best collision properties int biggestNContribs = -1; + int64_t bestCollisionId = -1; float bestCollisionFT0Mpercentile = -1; float bestCollisionFT0Cpercentile = -1; float bestCollisionVtxZ = 0.0f; bool bestCollisionSel8 = false; bool bestCollisionINELgtZERO = false; + bool bestCollisionINELgtONE = false; + bool bestCollisionNoSameBunchPileup = false; + bool bestCollisionGoodTriggerTVX = false; + bool bestCollisionGoodZvtxFT0vsPV = false; bool isCollisionSelect = false; uint32_t bestCollisionTriggerPresenceMap = 0; for (auto const& collision : collisions) { if (biggestNContribs < collision.numContrib()) { biggestNContribs = collision.numContrib(); + bestCollisionId = collision.globalIndex(); bestCollisionFT0Mpercentile = collision.centFT0M(); bestCollisionFT0Cpercentile = collision.centFT0C(); if (masterConfigurations.applyNewMCSelection) { @@ -4088,6 +4273,10 @@ struct HStrangeCorrelation { bestCollisionSel8 = collision.sel8(); bestCollisionVtxZ = collision.posZ(); bestCollisionINELgtZERO = collision.isInelGt0(); + bestCollisionINELgtONE = collision.isInelGt1(); + bestCollisionNoSameBunchPileup = collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup); + bestCollisionGoodTriggerTVX = collision.selection_bit(aod::evsel::kIsTriggerTVX); + bestCollisionGoodZvtxFT0vsPV = collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV); } if (triggerPresenceMap.size() > 0) { bestCollisionTriggerPresenceMap = triggerPresenceMap[collision.globalIndex()]; @@ -4136,6 +4325,18 @@ struct HStrangeCorrelation { if (!bestCollisionINELgtZERO) { return; } + if (masterConfigurations.selectINELgtONE && !bestCollisionINELgtONE) { + return; + } + if (masterConfigurations.rejectSameBunchPileup && !bestCollisionNoSameBunchPileup) { + return; + } + if (masterConfigurations.requireGoodTriggerTVX && !bestCollisionGoodTriggerTVX) { + return; + } + if (masterConfigurations.requireGoodZvtxFT0vsPV && !bestCollisionGoodZvtxFT0vsPV) { + return; + } } histos.fill(HIST("hClosureTestEventCounter"), 3.5f); @@ -4159,6 +4360,10 @@ struct HStrangeCorrelation { } } + // The local density of a generated particle is counted from the tracks of the best collision, + // the same collision whose centrality already labels these generated histograms. + const auto bestCollisionTracks = tracks.sliceBy(pairLossTracksPerCollision, bestCollisionId); + for (auto const& mcParticle : mcParticles) { if (doAssocPhysicalPrimaryInGen && !mcParticle.isPhysicalPrimary()) { continue; @@ -4171,6 +4376,9 @@ struct HStrangeCorrelation { } else { histos.fill(HIST("GeneratedWithPV/hTrigger"), gpt, geta, bestCollisionFT0Mpercentile); } + if (masterConfigurations.doLocalDensityStudy && masterConfigurations.doPPAnalysis) { + histos.fill(HIST("GeneratedWithPV/hTriggerLocalDensity"), gpt, geta, computeLocalDensityGen(mcParticle, bestCollisionTracks)); + } if (mcParticle.pdgCode() > 0) { histos.fill(HIST("GeneratedWithPV/hPositiveTrigger"), gpt, geta, bestCollisionFT0Mpercentile); } else { @@ -4236,6 +4444,9 @@ struct HStrangeCorrelation { if (std::abs(mcParticle.y()) < ySel) { histos.fill(HIST("GeneratedWithPV/h") + HIST(Particlenames[Index]) + HIST("_MidYVsMult"), gpt, bestCollisionFT0Mpercentile); } + if (masterConfigurations.doLocalDensityStudy && masterConfigurations.doPPAnalysis) { + histos.fill(HIST("GeneratedWithPV/h") + HIST(Particlenames[Index]) + HIST("LocalDensity"), gpt, geta, computeLocalDensityGen(mcParticle, bestCollisionTracks)); + } } }); } @@ -4276,8 +4487,15 @@ struct HStrangeCorrelation { histos.fill(HIST("PairLossK0/GenStudy/hEventCounter"), 0.0f); // Generated-level event selection. No reconstructed variable is used. - if (masterConfigurations.selectINELgtZERO && !o2::pwglf::isINELgt0mc(mcParticles, pdgDB)) { - return; + // INEL>1 implies INEL>0, so only the tighter enabled selection has to be evaluated + if (masterConfigurations.selectINELgtONE) { + if (!o2::pwglf::isINELgt1mc(mcParticles, pdgDB)) { + return; + } + } else if (masterConfigurations.selectINELgtZERO) { + if (!o2::pwglf::isINELgt0mc(mcParticles, pdgDB)) { + return; + } } histos.fill(HIST("PairLossK0/GenStudy/hEventCounter"), 1.0f); if (std::abs(mcCollision.posZ()) > masterConfigurations.zVertexCut) { @@ -4312,6 +4530,8 @@ struct HStrangeCorrelation { // them. std::unordered_set reconstructedTrackMcIds; std::unordered_set reconstructedV0McIds; + std::vector genStudyTriggers; + std::vector genStudyK0s; for (auto const& collision : recCollisions) { const auto trackSlice = tracks.sliceBy(pairLossTracksPerCollision, collision.globalIndex()); for (auto const& track : trackSlice) { @@ -4353,6 +4573,13 @@ struct HStrangeCorrelation { } else { histos.fill(HIST("PairLossK0/GenStudy/NotReconstructed/hTrigger"), genPt, genEta, genPhi, generatedNch); } + genStudyTriggers.push_back(GenStudyPairObject{ + .pt = genPt, + .eta = genEta, + .phi = genPhi, + .globalIndex = static_cast(mcParticle.globalIndex()), + .motherIndex = mcParticle.has_mothers() ? static_cast(mcParticle.mothers_first_as().globalIndex()) : -1, + .reconstructed = reconstructedTrackMcIds.count(mcParticle.globalIndex()) > 0}); } } @@ -4390,6 +4617,38 @@ struct HStrangeCorrelation { } else { histos.fill(HIST("PairLossK0/GenStudy/NotReconstructed/hK0Short"), genPt, genEta, genPhi, generatedNch, k0Findable); } + genStudyK0s.push_back(GenStudyPairObject{ + .pt = genPt, + .eta = genEta, + .phi = genPhi, + .globalIndex = static_cast(mcParticle.globalIndex()), + .motherIndex = -1, + .reconstructed = reconstructedV0McIds.count(mcParticle.globalIndex()) > 0}); + } + } + + // h-K0 correlations of the objects collected above, in generated coordinates. + // Same delta-phi / delta-eta convention as every other correlation in this task + // (trigger minus associated), and the same autocorrelation rejection: a trigger + // that is a decay product of the K0 it would be paired with is skipped. + // Every pair goes into Gen/ and into exactly one of the four exclusive classes. + for (auto const& trigger : genStudyTriggers) { + for (auto const& k0 : genStudyK0s) { + if (trigger.globalIndex == k0.globalIndex || trigger.motherIndex == k0.globalIndex) { + continue; + } + const float deltaPhi = computeDeltaPhi(trigger.phi, k0.phi); + const float deltaEta = trigger.eta - k0.eta; + histos.fill(HIST("PairLossK0/GenStudy/Gen/hCorrelation"), deltaEta, deltaPhi, trigger.pt, k0.pt, generatedNch); + if (trigger.reconstructed && k0.reconstructed) { + histos.fill(HIST("PairLossK0/GenStudy/Reconstructed/hCorrelation"), deltaEta, deltaPhi, trigger.pt, k0.pt, generatedNch); + } else if (trigger.reconstructed) { + histos.fill(HIST("PairLossK0/GenStudy/OnlyTriggerReconstructed/hCorrelation"), deltaEta, deltaPhi, trigger.pt, k0.pt, generatedNch); + } else if (k0.reconstructed) { + histos.fill(HIST("PairLossK0/GenStudy/OnlyK0Reconstructed/hCorrelation"), deltaEta, deltaPhi, trigger.pt, k0.pt, generatedNch); + } else { + histos.fill(HIST("PairLossK0/GenStudy/NotReconstructed/hCorrelation"), deltaEta, deltaPhi, trigger.pt, k0.pt, generatedNch); + } } } }; @@ -4521,6 +4780,10 @@ struct HStrangeCorrelation { float genBestCollisionVtxZ = 0.0f; bool genBestCollisionSel8 = false; bool genBestCollisionINELgtZERO = false; + bool genBestCollisionINELgtONE = false; + bool genBestCollisionNoSameBunchPileup = false; + bool genBestCollisionGoodTriggerTVX = false; + bool genBestCollisionGoodZvtxFT0vsPV = false; bool genCollisionSelected = false; int genLargestNContributors = -1; uint32_t genBestCollisionTriggerPresenceMap = 0; @@ -4537,6 +4800,10 @@ struct HStrangeCorrelation { genBestCollisionSel8 = recCollision.sel8(); genBestCollisionVtxZ = recCollision.posZ(); genBestCollisionINELgtZERO = recCollision.isInelGt0(); + genBestCollisionINELgtONE = recCollision.isInelGt1(); + genBestCollisionNoSameBunchPileup = recCollision.selection_bit(o2::aod::evsel::kNoSameBunchPileup); + genBestCollisionGoodTriggerTVX = recCollision.selection_bit(aod::evsel::kIsTriggerTVX); + genBestCollisionGoodZvtxFT0vsPV = recCollision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV); } if (triggerPresenceMap.size() > 0) { genBestCollisionTriggerPresenceMap = triggerPresenceMap[recCollision.globalIndex()]; @@ -4547,7 +4814,11 @@ struct HStrangeCorrelation { genEventSelected = genEventSelected && genCollisionSelected; } else if (masterConfigurations.doGenEventSelection) { genEventSelected = genEventSelected && genBestCollisionSel8 && std::abs(genBestCollisionVtxZ) <= masterConfigurations.zVertexCut && - genBestCollisionINELgtZERO && genBestCollisionMultiplicity >= axisRanges[5][0] && genBestCollisionMultiplicity <= axisRanges[5][1]; + genBestCollisionINELgtZERO && (!masterConfigurations.selectINELgtONE || genBestCollisionINELgtONE) && + (!masterConfigurations.rejectSameBunchPileup || genBestCollisionNoSameBunchPileup) && + (!masterConfigurations.requireGoodTriggerTVX || genBestCollisionGoodTriggerTVX) && + (!masterConfigurations.requireGoodZvtxFT0vsPV || genBestCollisionGoodZvtxFT0vsPV) && + genBestCollisionMultiplicity >= axisRanges[5][0] && genBestCollisionMultiplicity <= axisRanges[5][1]; } if (genEventSelected && masterConfigurations.doCorrelationK0Short && TESTBIT(doCorrelation, IndexK0)) { @@ -4640,8 +4911,8 @@ struct HStrangeCorrelation { passesFinalSelection = passesFinalSelection && positiveTrack.tpcNClsCrossedRows() >= trackSelection.minTPCNCrossedRowsAssociated && negativeTrack.tpcNClsCrossedRows() >= trackSelection.minTPCNCrossedRowsAssociated; if (trackSelection.checksRequireTPCChi2) { - passesFinalSelection = passesFinalSelection && positiveTrack.tpcChi2NCl() >= trackSelection.minTPCChi2PerClusterAssociated && - negativeTrack.tpcChi2NCl() >= trackSelection.minTPCChi2PerClusterAssociated; + passesFinalSelection = passesFinalSelection && positiveTrack.tpcChi2NCl() <= trackSelection.maxTPCChi2PerClusterAssociated && + negativeTrack.tpcChi2NCl() <= trackSelection.maxTPCChi2PerClusterAssociated; } if (trackSelection.requireClusterInITS) { passesFinalSelection = passesFinalSelection && positiveTrack.itsNCls() >= trackSelection.minITSClustersForDaughterTracks && @@ -4786,7 +5057,8 @@ struct HStrangeCorrelation { for (auto const& recCollision : recCollisions) { const auto recTriggerSlice = triggerTracks.sliceBy(collisionSliceTracks, recCollision.globalIndex()); const auto recV0Slice = associatedV0s.sliceBy(collisionSliceV0s, recCollision.globalIndex()); - runSameEventHV0s(recCollision, recV0Slice, recTriggerSlice); + const auto recTrackSlice = tracks.sliceBy(pairLossTracksPerCollision, recCollision.globalIndex()); + runSameEventHV0s(recCollision, recV0Slice, recTriggerSlice, recTrackSlice); } // Final-minus-Rec counterpart of RecNotInFinal. Both set differences use @@ -4912,80 +5184,100 @@ struct HStrangeCorrelation { PairLossTrackMap triggersInTable; PairLossTrackMap triggersFinal; - const auto triggerSlice = triggerTracks.sliceBy(collisionSliceTracks, bestCollisionId); - for (auto const& triggerEntry : triggerSlice) { - auto track = triggerEntry.track_as(); - const auto trackLabel = trackLabels.iteratorAt(track.globalIndex()); - if (!trackLabel.has_mcParticle()) { - continue; - } - const int64_t mcParticleId = trackLabel.mcParticleId(); - const auto trackInfo = makePairLossTrackInfo(track); - triggersInTable[mcParticleId].push_back(trackInfo); - if (!isValidTrigger(track, triggerEntry.isLeading())) { - continue; - } - if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(triggerEntry.mcMask(), 13)) { - continue; - } - if (masterConfigurations.doTriggPhysicalPrimary && !triggerEntry.mcPhysicalPrimary()) { - continue; - } - triggersFinal[mcParticleId].push_back(trackInfo); - } - PairLossV0Map v0sInTable; PairLossV0Map v0sFinal; - const auto assocV0Slice = associatedV0s.sliceBy(collisionSliceV0s, bestCollisionId); - for (auto const& assocEntry : assocV0Slice) { - auto v0 = assocEntry.v0Core_as(); - const auto v0MC = v0MCCores.iteratorAt(v0.globalIndex()); - if (v0MC.particleIdMC() < 0 || v0MC.pdgCode() != PDG_t::kK0Short || !assocEntry.mcTrue(IndexK0)) { - continue; + for (auto const& finalCollision : recCollisions) { + const int64_t finalCollisionId = static_cast(finalCollision.globalIndex()); + const bool isBestCollision = finalCollisionId == bestCollisionId; + if (!isBestCollision) { + if (pairLossK0Configurations.finalPairUseBestCollisionOnly) { + continue; + } + if (pairLossK0Configurations.applyRecoEventSelection && + !(masterConfigurations.doPPAnalysis ? isCollisionSelected(finalCollision) : isCollisionSelectedPbPb(finalCollision, false))) { + continue; + } } - auto positiveTrack = v0.posTrack_as(); - auto negativeTrack = v0.negTrack_as(); - const PairLossV0Info v0Info{ - .globalIndex = static_cast(v0.globalIndex()), - .positiveTrackId = static_cast(positiveTrack.globalIndex()), - .negativeTrackId = static_cast(negativeTrack.globalIndex()), - .pt = v0.pt(), - .eta = v0.eta(), - .phi = v0.phi(), - .radius = v0.v0radius(), - .cosPA = v0.v0cosPA(), - .dcaDaughters = v0.dcaV0daughters(), - .massNSigma = assocEntry.invMassNSigma(IndexK0)}; - v0sInTable[v0MC.particleIdMC()].push_back(v0Info); - bool passesFinalSelection = true; - if (masterConfigurations.doPPAnalysis) { - passesFinalSelection = v0.v0radius() >= v0Selection.v0RadiusMin && v0.v0radius() <= v0Selection.v0RadiusMax && - std::abs(v0.dcapostopv()) >= v0Selection.dcapostopv && std::abs(v0.dcanegtopv()) >= v0Selection.dcanegtopv && - v0.v0cosPA() >= v0Selection.v0cospa && v0.dcaV0daughters() <= v0Selection.dcaV0dau; - } else { - const float dcaCut = v0Selection.dcaDaugToPVForK0s == 0.0f ? v0Selection.dcaMesonToPV : v0Selection.dcaDaugToPVForK0s; - const bool passesLifetime = v0.distovertotmom(collision.posX(), collision.posY(), collision.posZ()) * o2::constants::physics::MassK0Short < v0Selection.lifetimecutK0S; - const bool passesDaughterDcaAndArmenteros = std::abs(v0.dcapostopv()) > dcaCut && std::abs(v0.dcanegtopv()) > dcaCut && v0.qtarm() * v0Selection.armPodCut > std::abs(v0.alpha()); - passesFinalSelection = v0SelectedPbPb(v0) && passesLifetime && passesDaughterDcaAndArmenteros; - } - passesFinalSelection = passesFinalSelection && positiveTrack.tpcNClsCrossedRows() >= trackSelection.minTPCNCrossedRowsAssociated && - negativeTrack.tpcNClsCrossedRows() >= trackSelection.minTPCNCrossedRowsAssociated; - if (trackSelection.checksRequireTPCChi2) { - passesFinalSelection = passesFinalSelection && positiveTrack.tpcChi2NCl() >= trackSelection.minTPCChi2PerClusterAssociated && - negativeTrack.tpcChi2NCl() >= trackSelection.minTPCChi2PerClusterAssociated; - } - if (trackSelection.requireClusterInITS) { - passesFinalSelection = passesFinalSelection && positiveTrack.itsNCls() >= trackSelection.minITSClustersForDaughterTracks && - negativeTrack.itsNCls() >= trackSelection.minITSClustersForDaughterTracks; + const auto triggerSlice = triggerTracks.sliceBy(collisionSliceTracks, finalCollisionId); + for (auto const& triggerEntry : triggerSlice) { + auto track = triggerEntry.track_as(); + const auto trackLabel = trackLabels.iteratorAt(track.globalIndex()); + if (!trackLabel.has_mcParticle()) { + continue; + } + const int64_t mcParticleId = trackLabel.mcParticleId(); + auto trackInfo = makePairLossTrackInfo(track); + trackInfo.collisionId = finalCollisionId; + if (isBestCollision) { + triggersInTable[mcParticleId].push_back(trackInfo); + } + if (!isValidTrigger(track, triggerEntry.isLeading())) { + continue; + } + if (trackSelection.checkForITSTPCMissmatchMC && bitcheck(triggerEntry.mcMask(), 13)) { + continue; + } + if (masterConfigurations.doTriggPhysicalPrimary && !triggerEntry.mcPhysicalPrimary()) { + continue; + } + triggersFinal[mcParticleId].push_back(trackInfo); } - passesFinalSelection = passesFinalSelection && assocEntry.compatible(IndexK0, trackSelection.dEdxCompatibility) && - (!doAssocPhysicalPrimary || assocEntry.mcPhysicalPrimary()) && - assocEntry.invMassNSigma(IndexK0) > -massWindowConfigurations.maxPeakNSigma && - assocEntry.invMassNSigma(IndexK0) < massWindowConfigurations.maxPeakNSigma && - v0.pt() >= axisRanges[2][0] && v0.pt() <= axisRanges[2][1]; - if (passesFinalSelection) { - v0sFinal[v0MC.particleIdMC()].push_back(v0Info); + + const auto assocV0Slice = associatedV0s.sliceBy(collisionSliceV0s, finalCollisionId); + for (auto const& assocEntry : assocV0Slice) { + auto v0 = assocEntry.v0Core_as(); + const auto v0MC = v0MCCores.iteratorAt(v0.globalIndex()); + if (v0MC.particleIdMC() < 0 || v0MC.pdgCode() != PDG_t::kK0Short || !assocEntry.mcTrue(IndexK0)) { + continue; + } + auto positiveTrack = v0.posTrack_as(); + auto negativeTrack = v0.negTrack_as(); + const PairLossV0Info v0Info{ + .globalIndex = static_cast(v0.globalIndex()), + .positiveTrackId = static_cast(positiveTrack.globalIndex()), + .negativeTrackId = static_cast(negativeTrack.globalIndex()), + .pt = v0.pt(), + .eta = v0.eta(), + .phi = v0.phi(), + .radius = v0.v0radius(), + .cosPA = v0.v0cosPA(), + .dcaDaughters = v0.dcaV0daughters(), + .massNSigma = assocEntry.invMassNSigma(IndexK0), + .collisionId = finalCollisionId}; + if (isBestCollision) { + v0sInTable[v0MC.particleIdMC()].push_back(v0Info); + } + + bool passesFinalSelection = true; + if (masterConfigurations.doPPAnalysis) { + passesFinalSelection = v0.v0radius() >= v0Selection.v0RadiusMin && v0.v0radius() <= v0Selection.v0RadiusMax && + std::abs(v0.dcapostopv()) >= v0Selection.dcapostopv && std::abs(v0.dcanegtopv()) >= v0Selection.dcanegtopv && + v0.v0cosPA() >= v0Selection.v0cospa && v0.dcaV0daughters() <= v0Selection.dcaV0dau; + } else { + const float dcaCut = v0Selection.dcaDaugToPVForK0s == 0.0f ? v0Selection.dcaMesonToPV : v0Selection.dcaDaugToPVForK0s; + const bool passesLifetime = v0.distovertotmom(finalCollision.posX(), finalCollision.posY(), finalCollision.posZ()) * o2::constants::physics::MassK0Short < v0Selection.lifetimecutK0S; + const bool passesDaughterDcaAndArmenteros = std::abs(v0.dcapostopv()) > dcaCut && std::abs(v0.dcanegtopv()) > dcaCut && v0.qtarm() * v0Selection.armPodCut > std::abs(v0.alpha()); + passesFinalSelection = v0SelectedPbPb(v0) && passesLifetime && passesDaughterDcaAndArmenteros; + } + passesFinalSelection = passesFinalSelection && positiveTrack.tpcNClsCrossedRows() >= trackSelection.minTPCNCrossedRowsAssociated && + negativeTrack.tpcNClsCrossedRows() >= trackSelection.minTPCNCrossedRowsAssociated; + if (trackSelection.checksRequireTPCChi2) { + passesFinalSelection = passesFinalSelection && positiveTrack.tpcChi2NCl() <= trackSelection.maxTPCChi2PerClusterAssociated && + negativeTrack.tpcChi2NCl() <= trackSelection.maxTPCChi2PerClusterAssociated; + } + if (trackSelection.requireClusterInITS) { + passesFinalSelection = passesFinalSelection && positiveTrack.itsNCls() >= trackSelection.minITSClustersForDaughterTracks && + negativeTrack.itsNCls() >= trackSelection.minITSClustersForDaughterTracks; + } + passesFinalSelection = passesFinalSelection && assocEntry.compatible(IndexK0, trackSelection.dEdxCompatibility) && + (!doAssocPhysicalPrimary || assocEntry.mcPhysicalPrimary()) && + assocEntry.invMassNSigma(IndexK0) > -massWindowConfigurations.maxPeakNSigma && + assocEntry.invMassNSigma(IndexK0) < massWindowConfigurations.maxPeakNSigma && + v0.pt() >= axisRanges[2][0] && v0.pt() <= axisRanges[2][1]; + if (passesFinalSelection) { + v0sFinal[v0MC.particleIdMC()].push_back(v0Info); + } } } @@ -5106,11 +5398,21 @@ struct HStrangeCorrelation { true, // V0 in AssocV0s: K0 side only true, // V0 final selection: K0 side only contains(triggersFinal, truthTrigger.globalIndex)}; // Final reconstructed pair + std::array triggerStageFills; + triggerStageFills.fill(1); + if (!pairLossK0Configurations.fillFinalPairOnce) { + triggerStageFills[PairLossTriggerPureReco] = static_cast(numberOfMatches(tracksBestCollision, truthTrigger.globalIndex)); + triggerStageFills[PairLossTriggerInTable] = static_cast(numberOfMatches(triggersInTable, truthTrigger.globalIndex)); + triggerStageFills[PairLossTriggerFinal] = static_cast(numberOfMatches(triggersFinal, truthTrigger.globalIndex)); + triggerStageFills[PairLossFinalPair] = static_cast(numberOfMatches(triggersFinal, truthTrigger.globalIndex)); + } for (int stage = 0; stage < PairLossK0NStages; ++stage) { if (!triggerStagePassed[stage]) { continue; } - histos.fill(HIST("PairLossK0/Stage/hTriggers"), stage, truthTrigger.pt, truthTrigger.eta, truthTrigger.phi, collision.posZ(), multiplicity); + for (int fill = 0; fill < triggerStageFills[stage]; ++fill) { + histos.fill(HIST("PairLossK0/Stage/hTriggers"), stage, truthTrigger.pt, truthTrigger.eta, truthTrigger.phi, collision.posZ(), multiplicity); + } } } @@ -5178,13 +5480,14 @@ struct HStrangeCorrelation { histos.fill(HIST("PairLossK0/Matching/hNMatches"), 6.0f, numberOfMatches(v0sFinal, truthK0.globalIndex)); bool pairBeforeAutocorrelation = false; - bool finalPair = false; bool rejectedByAutocorrelation = false; - PairLossTrackInfo selectedTrigger; - PairLossV0Info selectedV0; + std::vector> finalPairCombinations; if (triggerFinal && v0Final) { for (auto const& reconstructedTrigger : triggersFinal.at(truthTrigger.globalIndex)) { for (auto const& reconstructedV0 : v0sFinal.at(truthK0.globalIndex)) { + if (reconstructedTrigger.collisionId != reconstructedV0.collisionId) { + continue; + } const float reconstructedDeltaPhi = computeDeltaPhi(reconstructedTrigger.phi, reconstructedV0.phi); float reconstructedDeltaEta = reconstructedTrigger.eta - reconstructedV0.eta; if (masterConfigurations.doMirroringInDelataEta) { @@ -5198,16 +5501,18 @@ struct HStrangeCorrelation { rejectedByAutocorrelation = true; continue; } - finalPair = true; - selectedTrigger = reconstructedTrigger; - selectedV0 = reconstructedV0; - break; + finalPairCombinations.emplace_back(reconstructedTrigger, reconstructedV0); + if (pairLossK0Configurations.fillFinalPairOnce) { + break; + } } - if (finalPair) { + if (pairLossK0Configurations.fillFinalPairOnce && !finalPairCombinations.empty()) { break; } } } + const bool finalPair = !finalPairCombinations.empty(); + const int finalPairFills = static_cast(finalPairCombinations.size()); // Order must match PairLossK0Stage / PairLossK0StageNames one to one. // positiveDaughterBestCollision and negativeDaughterBestCollision are @@ -5229,13 +5534,16 @@ struct HStrangeCorrelation { if (!stagePassed[stage]) { continue; } - histos.fill(HIST("PairLossK0/Stage/hCounts"), stage); - histos.fill(HIST("PairLossK0/Stage/hPhysics"), stage, truthDeltaPhi, truthDeltaEta, truthK0.pt, truthTrigger.pt, multiplicity); - if (truthK0.findable) { - histos.fill(HIST("PairLossK0/Stage/hCountsFindable"), stage); - histos.fill(HIST("PairLossK0/Stage/hPhysicsFindable"), stage, truthDeltaPhi, truthDeltaEta, truthK0.pt, truthTrigger.pt, multiplicity); - if (closestDeltaPhiStar.valid) { - histos.fill(HIST("PairLossK0/Stage/hClose"), stage, closestDeltaPhiStar.minAbs, closestDeltaEta, truthK0.pt, truthTrigger.pt, magneticFieldSign, closestChargeProduct); + const int stageFills = (stage == PairLossFinalPair && !pairLossK0Configurations.fillFinalPairOnce) ? finalPairFills : 1; + for (int fill = 0; fill < stageFills; ++fill) { + histos.fill(HIST("PairLossK0/Stage/hCounts"), stage); + histos.fill(HIST("PairLossK0/Stage/hPhysics"), stage, truthDeltaPhi, truthDeltaEta, truthK0.pt, truthTrigger.pt, multiplicity); + if (truthK0.findable) { + histos.fill(HIST("PairLossK0/Stage/hCountsFindable"), stage); + histos.fill(HIST("PairLossK0/Stage/hPhysicsFindable"), stage, truthDeltaPhi, truthDeltaEta, truthK0.pt, truthTrigger.pt, multiplicity); + if (closestDeltaPhiStar.valid) { + histos.fill(HIST("PairLossK0/Stage/hClose"), stage, closestDeltaPhiStar.minAbs, closestDeltaEta, truthK0.pt, truthTrigger.pt, magneticFieldSign, closestChargeProduct); + } } } } @@ -5328,7 +5636,7 @@ struct HStrangeCorrelation { } } - if (finalPair) { + for (auto const& [selectedTrigger, selectedV0] : finalPairCombinations) { histos.fill(HIST("PairLossK0/Response/hTriggerPt"), truthTrigger.pt, selectedTrigger.pt); histos.fill(HIST("PairLossK0/Response/hK0Pt"), truthK0.pt, selectedV0.pt); histos.fill(HIST("PairLossK0/Response/hDeltaPhi"), truthDeltaPhi, computeDeltaPhi(selectedTrigger.phi, selectedV0.phi)); @@ -5359,7 +5667,7 @@ struct HStrangeCorrelation { } } - void processClosureTest(aod::McCollision const& /*mcCollision*/, + void processClosureTest(aod::McCollision const& mcCollision, soa::SmallGroups> const& recCollisions, aod::McParticles const& mcParticles, aod::V0MCCores const& v0MCCores, @@ -5436,21 +5744,19 @@ struct HStrangeCorrelation { // recomputed from raw tracks so that this stage cannot drift away from the // reconstructed analysis it exists to be compared against. // - // The sets are built per reconstructed collision and a pair is required to be - // final within one and the same collision: the reconstructed same-event - // correlation only ever pairs a trigger with a V0 sitting in the same vertex, - // so a pair split across two reconstructed vertices of one MC collision must - // not count as final here either. - // - // N.B.: the reconstructed autocorrelation rejection (trigger track identical - // to a V0 daughter track) is deliberately not replicated. It is a no-op as - // soon as the trigger is required to be a physical primary, because - // mcTrue(IndexK0) forces the daughters to be genuine -- hence secondary -- - // K0 decay products. - std::vector, std::unordered_set>> pairLossFinalPerCollision; + // The stage is restricted to the best reconstructed collision and keeps the + // reconstructed kinematics of every matched object, so that the pair test below + // can also impose the reconstructed-coordinate angular range and the + // reconstructed autocorrelation rejection. Both are conditions the reconstructed + // same-event correlation imposes as well, so this Final stage is by construction + // the same object as PairLossK0/Comparison/Final: the truth pairs that really do + // end up in the reconstructed correlation. + PairLossTrackMap pairLossFinalTriggers; + PairLossV0Map pairLossFinalV0s; for (auto const& collision : recCollisions) { - std::unordered_set finalTriggerMcIds; - std::unordered_set finalK0McIds; + if (static_cast(collision.globalIndex()) != pairLossBestCollisionId) { + continue; + } const auto finalTriggerSlice = triggerTracks.sliceBy(collisionSliceTracks, collision.globalIndex()); for (auto const& triggerEntry : finalTriggerSlice) { @@ -5467,7 +5773,7 @@ struct HStrangeCorrelation { if (masterConfigurations.doTriggPhysicalPrimary && !triggerEntry.mcPhysicalPrimary()) { continue; } - finalTriggerMcIds.insert(track.mcParticleId()); + pairLossFinalTriggers[track.mcParticleId()].push_back(makePairLossTrackInfo(track)); } const auto finalV0Slice = associatedV0s.sliceBy(collisionSliceV0s, collision.globalIndex()); @@ -5496,8 +5802,8 @@ struct HStrangeCorrelation { passesFinalSelection = passesFinalSelection && positiveTrack.tpcNClsCrossedRows() >= trackSelection.minTPCNCrossedRowsAssociated && negativeTrack.tpcNClsCrossedRows() >= trackSelection.minTPCNCrossedRowsAssociated; if (trackSelection.checksRequireTPCChi2) { - passesFinalSelection = passesFinalSelection && positiveTrack.tpcChi2NCl() >= trackSelection.minTPCChi2PerClusterAssociated && - negativeTrack.tpcChi2NCl() >= trackSelection.minTPCChi2PerClusterAssociated; + passesFinalSelection = passesFinalSelection && positiveTrack.tpcChi2NCl() <= trackSelection.maxTPCChi2PerClusterAssociated && + negativeTrack.tpcChi2NCl() <= trackSelection.maxTPCChi2PerClusterAssociated; } if (trackSelection.requireClusterInITS) { passesFinalSelection = passesFinalSelection && positiveTrack.itsNCls() >= trackSelection.minITSClustersForDaughterTracks && @@ -5511,34 +5817,54 @@ struct HStrangeCorrelation { if (!passesFinalSelection) { continue; } - finalK0McIds.insert(v0MC.particleIdMC()); - } - - pairLossFinalPerCollision.emplace_back(std::move(finalTriggerMcIds), std::move(finalK0McIds)); - } - - // Object-level membership, used only for the single-particle spectra: at - // least one collision in which the object is fully selected. The pair - // histogram uses pairLossHasFinalPair() instead, which is stricter. + pairLossFinalV0s[v0MC.particleIdMC()].push_back(PairLossV0Info{ + .globalIndex = static_cast(v0.globalIndex()), + .positiveTrackId = static_cast(positiveTrack.globalIndex()), + .negativeTrackId = static_cast(negativeTrack.globalIndex()), + .pt = v0.pt(), + .eta = v0.eta(), + .phi = v0.phi(), + .radius = v0.v0radius(), + .cosPA = v0.v0cosPA(), + .dcaDaughters = v0.dcaV0daughters(), + .massNSigma = assocEntry.invMassNSigma(IndexK0)}); + } + } + + // Object-level membership, used only for the single-particle spectra: the object + // has a fully selected reconstructed counterpart in the best collision. The pair + // histogram uses pairLossHasFinalPair() instead, which is stricter: it also + // requires the reconstructed pair itself to fall in the reconstructed angular + // range and to survive the reconstructed autocorrelation rejection. auto pairLossHasFinalTrigger = [&](int64_t mcId) { - for (auto const& perCollision : pairLossFinalPerCollision) { - if (perCollision.first.count(mcId) > 0) { - return true; - } - } - return false; + return pairLossFinalTriggers.find(mcId) != pairLossFinalTriggers.end(); }; auto pairLossHasFinalK0 = [&](int64_t mcId) { - for (auto const& perCollision : pairLossFinalPerCollision) { - if (perCollision.second.count(mcId) > 0) { - return true; - } - } - return false; + return pairLossFinalV0s.find(mcId) != pairLossFinalV0s.end(); }; auto pairLossHasFinalPair = [&](int64_t triggerMcId, int64_t k0McId) { - for (auto const& perCollision : pairLossFinalPerCollision) { - if (perCollision.first.count(triggerMcId) > 0 && perCollision.second.count(k0McId) > 0) { + const auto triggerMatches = pairLossFinalTriggers.find(triggerMcId); + if (triggerMatches == pairLossFinalTriggers.end()) { + return false; + } + const auto v0Matches = pairLossFinalV0s.find(k0McId); + if (v0Matches == pairLossFinalV0s.end()) { + return false; + } + for (auto const& reconstructedTrigger : triggerMatches->second) { + for (auto const& reconstructedV0 : v0Matches->second) { + float reconstructedDeltaEta = reconstructedTrigger.eta - reconstructedV0.eta; + if (masterConfigurations.doMirroringInDelataEta) { + reconstructedDeltaEta = std::abs(reconstructedDeltaEta); + } + const float reconstructedDeltaPhi = computeDeltaPhi(reconstructedTrigger.phi, reconstructedV0.phi); + if (reconstructedDeltaPhi < axisRanges[0][0] || reconstructedDeltaPhi > axisRanges[0][1] || + reconstructedDeltaEta < axisRanges[1][0] || reconstructedDeltaEta > axisRanges[1][1]) { + continue; + } + if (doAutocorrelationRejection && (reconstructedTrigger.globalIndex == reconstructedV0.positiveTrackId || reconstructedTrigger.globalIndex == reconstructedV0.negativeTrackId)) { + continue; + } return true; } } @@ -5558,6 +5884,116 @@ struct HStrangeCorrelation { const float pairLossBestCollisionVtxZ = collision.posZ(); const float pairLossBestCollisionMultiplicity = masterConfigurations.doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + std::array eventQualityClasses{}; + if (pairLossK0Configurations.doEventQualityStudy) { + // Category edges correspond to the labels declared above. + auto classFromEdges = [](auto value, auto const& edges) { + return static_cast(std::upper_bound(edges.begin(), edges.end(), value) - edges.begin()); + }; + constexpr double PurePVThreshold = 0.95; + constexpr double DominantCollisionFraction = 0.9; + constexpr double MajorityCollisionFraction = 0.5; + constexpr float GenEtaMax = 0.8f; + constexpr float ShapePtMin = 0.15f; + constexpr int MinShapeTracks = 3; + const auto nContributors = collision.numContrib(); + eventQualityClasses[0] = classFromEdges(nContributors, std::array{1u, 3u, 6u, 11u, 21u}); + + // Maximum component pull, not a 3D chi-square: covariance correlations + // are deliberately not used. Invalid covariance gets its own category. + const std::array residuals = {collision.posX() - mcCollision.posX(), collision.posY() - mcCollision.posY(), collision.posZ() - mcCollision.posZ()}; + const std::array variances = {collision.covXX(), collision.covYY(), collision.covZZ()}; + double maxPull = 0.; + bool validPull = true; + for (size_t component = 0; component < variances.size(); ++component) { + if (!std::isfinite(variances[component]) || variances[component] <= 0. || !std::isfinite(residuals[component])) { + validPull = false; + break; + } + maxPull = std::max(maxPull, std::abs(residuals[component]) / std::sqrt(variances[component])); + } + eventQualityClasses[1] = !validPull || !std::isfinite(maxPull) ? 0 : 1 + classFromEdges(maxPull, std::array{1., 3., 5.}); + + std::unordered_set currentMcIds; + int nAnyMatched = 0; + int nGenCharged = 0; + int nShapeTracks = 0; + double sumPt = 0., q2x = 0., q2y = 0.; + for (auto const& particle : mcParticles) { + currentMcIds.insert(particle.globalIndex()); + nAnyMatched += pairLossAnyTrackMcParticleIds.count(particle.globalIndex()) != 0; + if (!particle.isPhysicalPrimary() || !std::isfinite(particle.eta()) || std::abs(particle.eta()) >= GenEtaMax) { + continue; + } + auto const* pdgParticle = pdgDB->GetParticle(particle.pdgCode()); + if (pdgParticle == nullptr || pdgParticle->Charge() == 0.) { + continue; + } + ++nGenCharged; + // Linearized transverse sphericity, using truth primary charged + // particles with |eta|<0.8 and pT>=0.15 GeV/c (not spherocity). + if (std::isfinite(particle.pt()) && particle.pt() >= ShapePtMin && std::isfinite(particle.phi())) { + ++nShapeTracks; + sumPt += particle.pt(); + q2x += particle.pt() * std::cos(2. * particle.phi()); + q2y += particle.pt() * std::sin(2. * particle.phi()); + } + } + int nPVTracks = 0, nLabeledPVTracks = 0, nSameMcPVTracks = 0; + std::unordered_set bestMatchedMcIds; + const auto bestTracks = tracks.sliceBy(pairLossTracksPerCollision, collision.globalIndex()); + for (auto const& track : bestTracks) { + const bool sameMc = track.has_mcParticle() && currentMcIds.count(track.mcParticleId()) != 0; + if (sameMc) { + bestMatchedMcIds.insert(track.mcParticleId()); + } + if (track.isPVContributor()) { + ++nPVTracks; + nLabeledPVTracks += track.has_mcParticle(); + nSameMcPVTracks += sameMc; + } + } + // Missing labels take precedence; purity otherwise uses all PV tracks. + const double purity = nPVTracks > 0 ? static_cast(nSameMcPVTracks) / nPVTracks : 0.; + eventQualityClasses[2] = nPVTracks == 0 ? 0 : nLabeledPVTracks < nPVTracks ? 1 + : purity < PurePVThreshold ? 2 + : nSameMcPVTracks < nPVTracks ? 3 + : 4; + const double bestFraction = nAnyMatched > 0 ? static_cast(bestMatchedMcIds.size()) / nAnyMatched : 0.; + eventQualityClasses[3] = nAnyMatched == 0 ? 0 : recCollisions.size() == 1 ? 1 + : bestFraction >= DominantCollisionFraction ? 2 + : bestFraction >= MajorityCollisionFraction ? 3 + : 4; + const double timeResolution = collision.collisionTimeRes(); // ns + eventQualityClasses[4] = !std::isfinite(timeResolution) || timeResolution <= 0. ? 0 : 1 + classFromEdges(timeResolution, std::array{25., 100., 500.}); + const auto occupancy = collision.trackOccupancyInTimeRange(); + eventQualityClasses[5] = occupancy < 0 ? 0 : 1 + classFromEdges(occupancy, std::array{1, 100, 500, 1000}); + eventQualityClasses[6] = classFromEdges(nGenCharged, std::array{1, 5, 10, 20, 40}); + if (nShapeTracks >= MinShapeTracks && sumPt > 0.) { + const double sphericity = std::clamp(1. - std::hypot(q2x, q2y) / sumPt, 0., 1.); + eventQualityClasses[7] = 1 + classFromEdges(sphericity, std::array{0.3, 0.7}); + } + } + auto fillEventQuality = [&](int entryKind, float deltaPhi, float deltaEta, float assocPt, float triggerPt, bool hasAny, bool hasFinal) { + if (!pairLossK0Configurations.doEventQualityStudy) { + return; + } + static_for<0, PairLossNEventQualityGroups - 1>([&](auto i) { + constexpr int Index = i.value; + histos.fill(HIST("ClosureTest/PairLossK0/EventQuality/") + HIST(PairLossEventQualityNames[Index]) + HIST("/Truth"), eventQualityClasses[Index], entryKind, deltaPhi, deltaEta, assocPt, triggerPt); + if (hasAny) { + histos.fill(HIST("ClosureTest/PairLossK0/EventQuality/") + HIST(PairLossEventQualityNames[Index]) + HIST("/AnyTrackBoth"), eventQualityClasses[Index], entryKind, deltaPhi, deltaEta, assocPt, triggerPt); + } + if (hasFinal) { + histos.fill(HIST("ClosureTest/PairLossK0/EventQuality/") + HIST(PairLossEventQualityNames[Index]) + HIST("/Final"), eventQualityClasses[Index], entryKind, deltaPhi, deltaEta, assocPt, triggerPt); + } + }); + }; + // Unused coordinates lie inside regular bins. Select entry kind before + // projecting; reset pair-coordinate ranges for event/trigger counts. + const float countDeltaPhi = (axisRanges[0][0] + axisRanges[0][1]) * 0.5f; + const float countDeltaEta = (axisRanges[1][0] + axisRanges[1][1]) * 0.5f; + fillEventQuality(0, countDeltaPhi, countDeltaEta, axisRanges[2][0], axisRanges[3][0], true, true); std::vector pairLossTruthTriggers; std::vector pairLossTruthK0s; @@ -5622,6 +6058,9 @@ struct HStrangeCorrelation { // at truth level in Truth/ and AnyTrack/, at any level in AnyTrackK0/ and // AnyTrackBoth/, at fully-selected level in Final/. for (auto const& truthTrigger : pairLossTruthTriggers) { + if (pairLossK0Configurations.doEventQualityStudy) { + fillEventQuality(1, countDeltaPhi, countDeltaEta, axisRanges[2][0], truthTrigger.pt, pairLossAnyTrackMcParticleIds.count(truthTrigger.globalIndex) != 0, pairLossHasFinalTrigger(truthTrigger.globalIndex)); + } histos.fill(HIST("ClosureTest/PairLossK0/Truth/hTrigger"), truthTrigger.pt, truthTrigger.eta, truthTrigger.phi); histos.fill(HIST("ClosureTest/PairLossK0/AnyTrackK0/hTrigger"), truthTrigger.pt, truthTrigger.eta, truthTrigger.phi); if (pairLossAnyTrackMcParticleIds.find(truthTrigger.globalIndex) != pairLossAnyTrackMcParticleIds.end()) { @@ -5672,7 +6111,9 @@ struct HStrangeCorrelation { if (triggerHasAnyTrack && k0HasAnyV0) { histos.fill(HIST("ClosureTest/PairLossK0/AnyTrackBoth/sameEvent/K0Short"), truthDeltaPhi, truthDeltaEta, truthK0.pt, truthTrigger.pt, pairLossBestCollisionVtxZ, pairLossBestCollisionMultiplicity); } - if (pairLossHasFinalPair(truthTrigger.globalIndex, truthK0.globalIndex)) { + const bool hasFinalPair = pairLossHasFinalPair(truthTrigger.globalIndex, truthK0.globalIndex); + fillEventQuality(2, truthDeltaPhi, truthDeltaEta, truthK0.pt, truthTrigger.pt, triggerHasAnyTrack && k0HasAnyV0, hasFinalPair); + if (hasFinalPair) { histos.fill(HIST("ClosureTest/PairLossK0/Final/sameEvent/K0Short"), truthDeltaPhi, truthDeltaEta, truthK0.pt, truthTrigger.pt, pairLossBestCollisionVtxZ, pairLossBestCollisionMultiplicity); } } @@ -5735,6 +6176,10 @@ struct HStrangeCorrelation { float bestCollisionVtxZ = 0.0f; bool bestCollisionSel8 = false; bool bestCollisionINELgtZERO = false; + bool bestCollisionINELgtONE = false; + bool bestCollisionNoSameBunchPileup = false; + bool bestCollisionGoodTriggerTVX = false; + bool bestCollisionGoodZvtxFT0vsPV = false; bool isCollisionSelect = false; int biggestNContribs = -1; uint32_t bestCollisionTriggerPresenceMap = 0; @@ -5749,6 +6194,10 @@ struct HStrangeCorrelation { bestCollisionSel8 = recCollision.sel8(); bestCollisionVtxZ = recCollision.posZ(); bestCollisionINELgtZERO = recCollision.isInelGt0(); + bestCollisionINELgtONE = recCollision.isInelGt1(); + bestCollisionNoSameBunchPileup = recCollision.selection_bit(o2::aod::evsel::kNoSameBunchPileup); + bestCollisionGoodTriggerTVX = recCollision.selection_bit(aod::evsel::kIsTriggerTVX); + bestCollisionGoodZvtxFT0vsPV = recCollision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV); } if (triggerPresenceMap.size() > 0) { bestCollisionTriggerPresenceMap = triggerPresenceMap[recCollision.globalIndex()]; @@ -5776,6 +6225,18 @@ struct HStrangeCorrelation { if (!bestCollisionINELgtZERO) { return; } + if (masterConfigurations.selectINELgtONE && !bestCollisionINELgtONE) { + return; + } + if (masterConfigurations.rejectSameBunchPileup && !bestCollisionNoSameBunchPileup) { + return; + } + if (masterConfigurations.requireGoodTriggerTVX && !bestCollisionGoodTriggerTVX) { + return; + } + if (masterConfigurations.requireGoodZvtxFT0vsPV && !bestCollisionGoodZvtxFT0vsPV) { + return; + } if (bestCollisionCentpercentile > axisRanges[5][1] || bestCollisionCentpercentile < axisRanges[5][0]) { return; } @@ -6105,8 +6566,15 @@ struct HStrangeCorrelation { float multEta08 = -1; float multEta05 = -1; histos.fill(HIST("Prediction/hEventSelection"), 0.5); - if (masterConfigurations.selectINELgtZERO && !o2::pwglf::isINELgt0mc(mcParticles, pdgDB)) { - return; + // INEL>1 implies INEL>0, so only the tighter enabled selection has to be evaluated + if (masterConfigurations.selectINELgtONE) { + if (!o2::pwglf::isINELgt1mc(mcParticles, pdgDB)) { + return; + } + } else if (masterConfigurations.selectINELgtZERO) { + if (!o2::pwglf::isINELgt0mc(mcParticles, pdgDB)) { + return; + } } histos.fill(HIST("Prediction/hEventSelection"), 1.5); if (std::abs(mcCollision.posZ()) > masterConfigurations.zVertexCut) { diff --git a/PWGLF/Tasks/Strangeness/k0_mixed_events.cxx b/PWGLF/Tasks/Strangeness/k0_mixed_events.cxx index a5932d939a6..6790d9e2c57 100644 --- a/PWGLF/Tasks/Strangeness/k0_mixed_events.cxx +++ b/PWGLF/Tasks/Strangeness/k0_mixed_events.cxx @@ -78,34 +78,37 @@ using RecoTracks = soa::Join; -typedef std::shared_ptr trkType; -typedef std::shared_ptr trkTypeData; +using TrackType = const FilteredTracks::iterator; +using TrackTypePtr = std::shared_ptr; +using TrackTypeData = const RecoTracks::iterator; +using TrackTypeDataPtr = std::shared_ptr; -typedef std::shared_ptr colType; +using ColType = const FilteredCollisions::iterator; +using ColTypePtr = std::shared_ptr; -using MyFemtoPair = o2::aod::singletrackselector::FemtoPair; +using MyFemtoPair = o2::aod::singletrackselector::FemtoPair; class ResoPair : public MyFemtoPair { public: ResoPair() {} - ResoPair(trkType const& first, trkType const& second) : MyFemtoPair(first, second) + ResoPair(TrackTypePtr const& first, TrackTypePtr const& second) : MyFemtoPair(first, second) { setPair(first, second); } - ResoPair(trkType const& first, trkType const& second, const bool& isidentical) : MyFemtoPair(first, second, isidentical) {} + ResoPair(TrackTypePtr const& first, TrackTypePtr const& second, const bool& isidentical) : MyFemtoPair(first, second, isidentical) {} bool isClosePair() const { return MyFemtoPair::IsClosePair(mDeltaEta, mDeltaPhi, mRadius); } void setEtaDiff(const float deta) { mDeltaEta = deta; } void setPhiStarDiff(const float dphi) { mDeltaPhi = dphi; } void setRadius(const float r) { mRadius = r; } - void setPair(trkType const& first, trkType const& second) + void setPair(TrackTypePtr const& first, TrackTypePtr const& second) { MyFemtoPair::SetPair(first, second); lDecayDaughter1.SetPtEtaPhiM(first->pt(), first->eta(), first->phi(), particle_mass(GetPDG1())); lDecayDaughter2.SetPtEtaPhiM(second->pt(), second->eta(), second->phi(), particle_mass(GetPDG2())); lResonance = lDecayDaughter1 + lDecayDaughter2; } - void setPair(trkTypeData const& first, trkTypeData const& second) + void setPair(TrackTypeDataPtr const& first, TrackTypeDataPtr const& second) { // MyFemtoPair::SetPair(first, second); lDecayDaughter1.SetPtEtaPhiM(first->pt(), first->eta(), first->phi(), particle_mass(GetPDG1())); @@ -369,8 +372,8 @@ struct K0MixedEvents { void mixTracks(Type const& tracks1, Type const& tracks2, const float centrality) { LOG(debug) << "Mixing tracks of two different events"; - for (auto trk1 : tracks1) { - for (auto trk2 : tracks2) { + for (const auto& trk1 : tracks1) { + for (const auto& trk2 : tracks2) { Pair->setPair(trk1, trk2); @@ -529,9 +532,9 @@ struct K0MixedEvents { void processDerived(FilteredTracks const& tracks, FilteredCollisions const& collisions) { LOG(debug) << "Processing " << collisions.size() << " collisions and " << tracks.size() << " tracks"; - std::map> selectedtracks_1; - std::map> selectedtracks_2; - std::map, std::vector> mixbins; + std::map> selectedtracks_1; + std::map> selectedtracks_2; + std::map, std::vector> mixbins; if (_particlePDG_1 == 0 || _particlePDG_2 == 0) { LOGF(fatal, "One of passed PDG is 0!!!"); } @@ -542,7 +545,7 @@ struct K0MixedEvents { registry.fill(HIST("multPerc"), collision.multPerc()); } - for (auto track : tracks) { + for (const auto& track : tracks) { LOG(debug) << "Track index " << track.singleCollSelId(); if (!isTrackSelected(track)) { continue; @@ -559,7 +562,7 @@ struct K0MixedEvents { if ((track.sign() == _sign_1) && (track.p() < _PIDtrshld_1 ? o2::aod::singletrackselector::TPCselection(track, TPCcuts_1) : o2::aod::singletrackselector::TOFselection(track, TOFcuts_1))) { // filling the map: eventID <-> selected particles1 - selectedtracks_1[track.singleCollSelId()].push_back(std::make_shared(track)); + selectedtracks_1[track.singleCollSelId()].push_back(std::make_shared(track)); registry.fill(HIST("p_first"), track.p()); registry.fill(HIST("dcaXY_first"), track.pt(), track.dcaXY()); @@ -591,7 +594,7 @@ struct K0MixedEvents { } else if ((track.sign() == _sign_2) && (_particlePDGtoReject != 0 || !o2::aod::singletrackselector::TOFselection(track, std::make_pair(_particlePDGtoReject, _rejectWithinNsigmaTOF))) && (track.p() < _PIDtrshld_2 ? o2::aod::singletrackselector::TPCselection(track, TPCcuts_2) : o2::aod::singletrackselector::TOFselection(track, TOFcuts_2))) { // filling the map: eventID <-> selected particles2 if (see condition above ^) - selectedtracks_2[track.singleCollSelId()].push_back(std::make_shared(track)); + selectedtracks_2[track.singleCollSelId()].push_back(std::make_shared(track)); registry.fill(HIST("p_second"), track.p()); registry.fill(HIST("dcaXY_second"), track.pt(), track.dcaXY()); @@ -619,7 +622,7 @@ struct K0MixedEvents { } } - for (auto collision : collisions) { + for (const auto& collision : collisions) { if (selectedtracks_1.find(collision.globalIndex()) == selectedtracks_1.end()) { if (IsIdentical) continue; @@ -627,7 +630,7 @@ struct K0MixedEvents { continue; } - mixbins[std::pair{round(collision.posZ() / _vertexbinwidth), floor(collision.mult() / _multbinwidth)}].push_back(std::make_shared(collision)); + mixbins[std::pair{round(collision.posZ() / _vertexbinwidth), floor(collision.mult() / _multbinwidth)}].push_back(std::make_shared(collision)); } //====================================== mixing starts here ====================================== @@ -711,15 +714,15 @@ struct K0MixedEvents { { initCCDB(bcs.iteratorAt(0)); LOG(debug) << "Processing " << collisions.size() << " collisions and " << tracks.size() << " tracks"; - std::map> selectedtracks_1; - std::map> selectedtracks_2; - std::map, std::vector>> mixbins; + std::map> selectedtracks_1; + std::map> selectedtracks_2; + std::map, std::vector>> mixbins; if (_particlePDG_1 == 0 || _particlePDG_2 == 0) { LOGF(fatal, "One of passed PDG is 0!!!"); } registry.fill(HIST("Trks"), 2.f, tracks.size()); - for (auto collision : collisions) { + for (const auto& collision : collisions) { if (!acceptEvent(collision)) continue; LOG(debug) << "Collision index " << collision.globalIndex(); @@ -727,7 +730,7 @@ struct K0MixedEvents { registry.fill(HIST("multPerc"), collision.centFT0M()); } - for (auto track : tracks) { + for (const auto& track : tracks) { if (!isTrackSelected(track)) { continue; } @@ -757,7 +760,7 @@ struct K0MixedEvents { if ((track.sign() == _sign_1) && (track.p() < _PIDtrshld_1 ? o2::aod::singletrackselector::TPCselection(track, TPCcuts_1) : o2::aod::singletrackselector::TOFselection(track, TOFcuts_1))) { // filling the map: eventID <-> selected particles1 - selectedtracks_1[track.collisionId()].push_back(std::make_shared(track)); + selectedtracks_1[track.collisionId()].push_back(std::make_shared(track)); registry.fill(HIST("p_first"), track.p()); registry.fill(HIST("dcaXY_first"), track.pt(), track.dcaXY()); @@ -789,7 +792,7 @@ struct K0MixedEvents { } else if ((track.sign() == _sign_2) && (_particlePDGtoReject != 0 || !o2::aod::singletrackselector::TOFselection(track, std::make_pair(_particlePDGtoReject, _rejectWithinNsigmaTOF))) && (track.p() < _PIDtrshld_2 ? o2::aod::singletrackselector::TPCselection(track, TPCcuts_2) : o2::aod::singletrackselector::TOFselection(track, TOFcuts_2))) { // filling the map: eventID <-> selected particles2 if (see condition above ^) - selectedtracks_2[track.collisionId()].push_back(std::make_shared(track)); + selectedtracks_2[track.collisionId()].push_back(std::make_shared(track)); registry.fill(HIST("p_second"), track.p()); registry.fill(HIST("dcaXY_second"), track.pt(), track.dcaXY()); @@ -817,7 +820,7 @@ struct K0MixedEvents { } } - for (auto collision : collisions) { + for (const auto& collision : collisions) { if (selectedtracks_1.find(collision.globalIndex()) == selectedtracks_1.end()) { if (IsIdentical) continue; @@ -825,7 +828,7 @@ struct K0MixedEvents { continue; } - mixbins[std::pair{round(collision.posZ() / _vertexbinwidth), floor(collision.multNTracksPVeta1() / _multbinwidth)}].push_back(std::make_shared(collision)); + mixbins[std::pair{round(collision.posZ() / _vertexbinwidth), floor(collision.multNTracksPVeta1() / _multbinwidth)}].push_back(std::make_shared(collision)); } //====================================== mixing starts here ====================================== diff --git a/PWGLF/Tasks/Strangeness/lambdak0sflattenicity.cxx b/PWGLF/Tasks/Strangeness/lambdak0sflattenicity.cxx index ec59b986c51..05c71967ed5 100644 --- a/PWGLF/Tasks/Strangeness/lambdak0sflattenicity.cxx +++ b/PWGLF/Tasks/Strangeness/lambdak0sflattenicity.cxx @@ -21,13 +21,15 @@ #include "PWGLF/Utils/inelGt.h" #include "Common/CCDB/EventSelectionParams.h" +#include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" -#include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" +#include #include +#include #include #include #include @@ -39,16 +41,16 @@ #include #include -#include +#include #include -#include -#include +#include +#include #include #include #include -#include #include +#include #include #include @@ -58,7 +60,7 @@ using namespace o2::framework::expressions; struct Lambdak0sflattenicity { // Histograms are defined with HistogramRegistry - Service pdg; + Service pdg{}; HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, @@ -100,198 +102,459 @@ struct Lambdak0sflattenicity { OutputObjHandlingPolicy::AnalysisObject, true, true}; + HistogramRegistry rCharged{ + "charged", + {}, + OutputObjHandlingPolicy::AnalysisObject, + true, + true}; - static constexpr std::string_view kHEst[8] = { + static constexpr int kNEstimators = 7; + // forward detector segmentation + static constexpr int kNChannelsPerT0Sector = 4; + static constexpr int kNSectorsT0A = 24; + static constexpr int kNSectorsT0C = 28; + // One lattice cell per FT0 readout channel: the four channels of a sector are + // separate quadrants. Gain and vertex maps stay per sector, as CCDB holds them. + static constexpr int kNChannelsFT0A = kNSectorsT0A * kNChannelsPerT0Sector; + static constexpr int kNChannelsFT0C = kNSectorsT0C * kNChannelsPerT0Sector; + static constexpr int kNChannelsPerFV0Ring = 8; + static constexpr int kNFV0EtaRings = 5; + static constexpr int kOuterFV0RingIndex = kNFV0EtaRings - 1; + static constexpr int kNSectorsFV0OuterRing = 16; + // TParticlePDG::Charge() is in units of e/3 + static constexpr float kMinCharge = 0.01f; + + // eFV0FT0C is the weighted amplitude sum, a multiplicity estimator, not a 1-rho + static constexpr std::array kHEst = { "eGlobaltrack", "eFV0", "e1flatencityFV0", "eFT0", - "e1flatencityFT0", "eFV0FT0C", "e1flatencityFV0FT0C", "ePtTrig"}; - static constexpr std::string_view kTEst[8] = { + "e1flatencityFT0", "eFV0FT0C", "ePtTrig"}; + static constexpr std::array kTEst = { "GlobalTrk", "FV0", "1-flatencity_FV0", "FT0", - "1-flatencityFT0", "FV0_FT0C", "1-flatencity_FV0_FT0C", "PtTrig"}; - static constexpr std::string_view kHPtEst[8] = { + "1-flatencityFT0", "FV0_FT0C", "PtTrig"}; + static constexpr std::array kHPtEst = { "ptVsGlobaltrack", "ptVsFV0", "ptVs1flatencityFV0", "ptVsFT0", "ptVs1flatencityFT0", "ptVsFV0FT0C", - "ptVs1flatencityFV0FT0C", "pTVsPtTrig"}; - - // Configurable for histograms - Configurable nBinsVz{"nBinsVz", 100, "N bins in Vz"}; - Configurable nBinsK0sMass{"nBinsK0sMass", 400, "N bins in K0sMass"}; - Configurable nBinsLambdaMass{"nBinsLambdaMass", 400, - "N bins in LambdaMass"}; - Configurable nBinsXiMass{"nBinsXiMass", 400, "N bins in XiMass"}; - - Configurable kK0sEPshiftfromMass{"kK0sEPshiftfromMass", 0.1, "distance of K0s Inv mass histogram start and end points from PDG mass"}; - Configurable kLambdaEPshiftfromMass{"kLambdaEPshiftfromMass", 0.05, "distance of Lambda Inv mass histogram start and end points from PDG mass"}; - Configurable kXiEPshiftfromMass{"kXiEPshiftfromMass", 0.05, "distance of Xi Inv mass histogram start and end points from PDG mass"}; - - Configurable nBinspT{"nBinspT", 250, "N bins in pT"}; - Configurable nBinsFlattenicity{"nBinsFlattenicity", 100, "N bins in Flattenicity"}; - - // Configurable for event selection - - Configurable applyEvSel{"applyEvSel", true, - "Apply event selection to Data and MCRec"}; - Configurable issel8{"issel8", true, - "Accept events that pass sel8 selection"}; - Configurable cutzvertex{"cutzvertex", 10.0f, - "Accepted z-vertex range (cm)"}; - Configurable isINELgt0{"isINELgt0", true, "is INEL gt 0"}; - Configurable isNoTimeFrameBorder{"isNoTimeFrameBorder", true, - "cut branch crossing at the beginning/end of TF"}; - Configurable isNoITSROFrameBorder{"isNoITSROFrameBorder", true, - "cut branch crossing at the beginning/end of ITS ROF"}; - Configurable isVertexITSTPC{"isVertexITSTPC", false, - "Is Vertex ITSTPC"}; - Configurable isNoSameBunchPileup{"isNoSameBunchPileup", false, - "Is No Same Bunch Pileup"}; - Configurable isGoodZvtxFT0vsPV{"isGoodZvtxFT0vsPV", false, - "Is Good Zvtx FT0 vs PV"}; - Configurable isTriggerTVX{"isTriggerTVX", true, - "coincidence of a signal in FT0A and FT0C"}; - - // Configurables for Flattenicity - Configurable flattenicityQA{"flattenicityQA", true, "Store Flattenicity QA plots"}; - Configurable applyCalibCh{"applyCalibCh", false, "equalize FV0"}; - Configurable applyCalibVtx{"applyCalibVtx", false, - "equalize FV0 vs vtx"}; - Configurable applyNorm{"applyNorm", false, "normalization to eta"}; - Configurable isflattenicitywithFV0{"isflattenicitywithFV0", true, - "Calculate Flattenicity with FV0"}; - Configurable isflattenicitywithFT0{"isflattenicitywithFT0", true, - "Calculate Flattenicity with FT0"}; - Configurable isflattenicitywithFV0FT0C{"isflattenicitywithFV0FT0C", true, - "Calculate Flattenicity with FV0+FT0C"}; - - Configurable flattenicityforanalysis{"flattenicityforanalysis", 0, - "Which Flattenicity to be used for analysis, 0 for FV0, 1 for FT0, 2 for FV0+FT0C"}; - Configurable flattenicityforLossCorrRec{"flattenicityforLossCorrRec", true, - "Flattenicity from Rec Tracks are used for Signal and Event loss calculations"}; - // Common Configurable parameters for V0 selection - Configurable v0settingDCAv0dau{"v0settingDCAv0dau", 1, - "DCA V0 Daughters"}; - Configurable v0settingDCApostopv{"v0settingDCApostopv", 0.06, - "DCA Pos To PV"}; - Configurable v0settingDCAnegtopv{"v0settingDCAnegtopv", 0.06, - "DCA Neg To PV"}; - Configurable v0settingDCAbactopv{"v0settingDCAbactopv", 0.06, - "DCA Bchelor To PV"}; - Configurable v0settingRapidity{"v0settingRapidity", 0.5, - "V0 rapidity cut"}; - - // Configurable parameters for V0 selection for KOs - Configurable v0settingCosPAK0s{"v0settingCosPAK0s", 0.97, - "V0 CosPA for K0s"}; - Configurable v0settingRadiusK0s{"v0settingRadiusK0s", 0.5, - "v0radius for K0s"}; - Configurable v0settingcTauK0s{"v0settingcTauK0s", 20, - "v0ctau for K0s"}; - Configurable v0settingMassRejectionK0s{"v0settingMassRejectionK0s", 0.005, - "Competing Mass Rejection cut for K0s"}; - Configurable v0settingArmePodoK0s{"v0settingArmePodoK0s", 0.2, - "Armenteros-Podolanski cut for K0s"}; - - // Configurable parameters for V0 selection for Lambda - Configurable v0settingCosPALambda{"v0settingCosPALambda", 0.995, - "V0 CosPA for Lambda"}; - Configurable v0settingRadiusLambda{"v0settingRadiusLambda", 0.5, - "v0radius for Lambda"}; - Configurable v0settingcTauLambda{"v0settingcTauLambda", 30, - "v0ctau for Lambda"}; - Configurable v0settingMassRejectionLambda{"v0settingMassRejectionLambda", 0.01, - "Competing Mass Rejection cut for Lambda"}; - - // Configurable parameters for PID selection - Configurable nSigmaTPCPion{"nSigmaTPCPion", 5, "nSigmaTPCPion"}; - Configurable nSigmaTPCProton{"nSigmaTPCProton", 5, "nSigmaTPCProton"}; - Configurable nSigmaTPCKaon{"nSigmaTPCKaon", 5, "nSigmaTPCKaon"}; + "pTVsPtTrig"}; + + // Histogram binning. The pT and 1-rho axes are ConfigurableAxis: pass + // {nbins, lo, hi} for uniform bins or {VARIABLE_WIDTH, e0, e1, ...} for the + // edges of the published binning. The 1-rho edges are meant to be the + // percentile class boundaries measured by the processFlatDist* pass, so that + // one class is exactly one bin and no rebinning happens downstream. + struct : ConfigurableGroup { + std::string prefix = "binning"; + Configurable nBinsVz{"nBinsVz", 100, "N bins in Vz"}; + Configurable nBinsK0sMass{"nBinsK0sMass", 400, "N bins in K0sMass"}; + Configurable nBinsLambdaMass{"nBinsLambdaMass", 400, + "N bins in LambdaMass"}; + Configurable nBinsXiMass{"nBinsXiMass", 400, "N bins in XiMass"}; + Configurable kK0sEPshiftfromMass{"kK0sEPshiftfromMass", 0.1, "distance of K0s Inv mass histogram start and end points from PDG mass"}; + Configurable kLambdaEPshiftfromMass{"kLambdaEPshiftfromMass", 0.05, "distance of Lambda Inv mass histogram start and end points from PDG mass"}; + Configurable kXiEPshiftfromMass{"kXiEPshiftfromMass", 0.05, "distance of Xi Inv mass histogram start and end points from PDG mass"}; + ConfigurableAxis axisPtK0s{"axisPtK0s", {250, 0.0f, 25.0f}, "#it{p}_{T} of K0s"}; + ConfigurableAxis axisPtLambda{"axisPtLambda", {250, 0.0f, 25.0f}, "#it{p}_{T} of Lambda and AntiLambda"}; + ConfigurableAxis axisPtXi{"axisPtXi", {250, 0.0f, 25.0f}, "#it{p}_{T} of Xi"}; + ConfigurableAxis axisPtCharged{"axisPtCharged", {250, 0.0f, 25.0f}, "#it{p}_{T} of charged particles"}; + ConfigurableAxis axisPtPid{"axisPtPid", {250, 0.0f, 25.0f}, "#it{p}_{TPC} of the daughter tracks"}; + ConfigurableAxis axisFlat{"axisFlat", {100, 0.0f, 1.0f}, "1-#rho_{ch} of the spectra"}; + // detector effects move the percentiles, so the closure denominator needs + // its own class edges, taken from hFlatDistGen + ConfigurableAxis axisFlatTrue{"axisFlatTrue", {100, 0.0f, 1.0f}, "true 1-#rho_{ch}"}; + ConfigurableAxis axisFlatFine{"axisFlatFine", {2000, 0.0f, 1.0f}, "1-#rho_{ch} used to locate the percentiles"}; + ConfigurableAxis axisCent{"axisCent", {100, 0.0f, 100.0f}, "FT0M percentile"}; + ConfigurableAxis axisNch{"axisNch", {150, -0.5f, 149.5f}, "N_{ch} in the tracking acceptance"}; + ConfigurableAxis axisDcaXy{"axisDcaXy", {200, -1.0f, 1.0f}, "DCA_{xy} (cm)"}; + ConfigurableAxis axisDcaV0ToPv{"axisDcaV0ToPv", {200, 0.0f, 2.0f}, "DCA of the V0 to the PV (cm)"}; + ConfigurableAxis axisPtRes{"axisPtRes", {200, -0.5f, 0.5f}, "(#it{p}_{T}^{rec} - #it{p}_{T}^{gen})/#it{p}_{T}^{gen}"}; + } binning; + + // Event selection + struct : ConfigurableGroup { + std::string prefix = "evSel"; + Configurable applyEvSel{"applyEvSel", true, + "Apply event selection to Data and MCRec"}; + Configurable issel8{"issel8", true, + "Accept events that pass sel8 selection"}; + Configurable cutzvertex{"cutzvertex", 10.0f, + "Accepted z-vertex range (cm)"}; + Configurable isINELgt0{"isINELgt0", true, "is INEL gt 0"}; + Configurable isNoTimeFrameBorder{"isNoTimeFrameBorder", true, + "cut branch crossing at the beginning/end of TF"}; + Configurable isNoITSROFrameBorder{"isNoITSROFrameBorder", true, + "cut branch crossing at the beginning/end of ITS ROF"}; + Configurable isVertexITSTPC{"isVertexITSTPC", false, + "Is Vertex ITSTPC"}; + Configurable isNoSameBunchPileup{"isNoSameBunchPileup", false, + "Is No Same Bunch Pileup"}; + Configurable isGoodZvtxFT0vsPV{"isGoodZvtxFT0vsPV", false, + "Is Good Zvtx FT0 vs PV"}; + Configurable isTriggerTVX{"isTriggerTVX", true, + "coincidence of a signal in FT0A and FT0C"}; + } evSel; + + // Flattenicity estimation + struct : ConfigurableGroup { + std::string prefix = "flatSel"; + Configurable flattenicityQA{"flattenicityQA", true, "Store Flattenicity QA plots"}; + // Both corrections reshape the lattice and therefore move the flattenicity. + // With both off nothing is read from CCDB at all. + Configurable applyCalibCh{"applyCalibCh", false, + "equalize the per-channel gain, from CCDB"}; + Configurable applyCalibVtx{"applyCalibVtx", false, + "equalize the per-cell z-vertex dependence, from CCDB"}; + Configurable applyNorm{"applyNorm", false, "normalization to eta"}; + Configurable isflattenicitywithFV0{"isflattenicitywithFV0", true, + "Calculate Flattenicity with FV0"}; + Configurable isflattenicitywithFT0{"isflattenicitywithFT0", true, + "Calculate Flattenicity with FT0"}; + Configurable flattenicityforanalysis{"flattenicityforanalysis", 0, + "Which Flattenicity to be used for analysis, 0 for FV0, 1 for FT0"}; + // On a sparse lattice sigma/ is quantised -- one lit cell gives exactly + // sqrt((N-1)/N) whatever the amplitude -- which puts spikes in 1-rho. Tune + // against the hNActiveCells* histograms. 0 disables. + Configurable minLitCellsFV0{"minLitCellsFV0", 0, + "Minimum lit FV0 cells (of 48), applied when flattenicityforanalysis=0"}; + Configurable minLitCellsFT0A{"minLitCellsFT0A", 0, + "Minimum lit FT0A cells (of 96), applied when flattenicityforanalysis=1"}; + Configurable minLitCellsFT0C{"minLitCellsFT0C", 0, + "Minimum lit FT0C cells (of 112), applied when flattenicityforanalysis=1"}; + Configurable flattenicityforLossCorrRec{"flattenicityforLossCorrRec", true, + "Flattenicity from Rec Tracks are used for Signal and Event loss calculations"}; + // FV0 only: same cell convention as the detector lattice, so gen vs rec is + // a detector effect and not a difference of definitions + Configurable genFlatDetectorLikeNorm{"genFlatDetectorLikeNorm", true, + "Weight the generator-level FV0 cells the way the detector lattice does"}; + } flatSel; + + // Calibration objects, read per run and only when the corresponding switch is + // on. Same layout as PWGLF/Tasks/GlobalEventProperties/flattenictyPikp.cxx, so + // the objects are interchangeable between the two tasks: the gain is a + // std::vector indexed by the raw detector channel, the z-vertex + // equalization a TProfile2D of (lattice cell, z_vtx). + struct : ConfigurableGroup { + std::string prefix = "ccdbConf"; + Configurable ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", + "url of the ccdb repository"}; + Configurable gainEqPath{"gainEqPath", "Users/s/sprasad/flattenicity/GainEq", + "CCDB directory holding FV0, FT0A and FT0C gain vectors"}; + Configurable vtxEqPath{"vtxEqPath", "Users/s/sprasad/flattenicity/ZvtxEq", + "CCDB directory holding the FV0, FT0A and FT0C z-vertex maps"}; + } ccdbConf; + + // V0 selection + struct : ConfigurableGroup { + std::string prefix = "v0Sel"; + Configurable v0settingDCAv0dau{"v0settingDCAv0dau", 1, + "DCA V0 Daughters"}; + Configurable v0settingDCApostopv{"v0settingDCApostopv", 0.06, + "DCA Pos To PV"}; + Configurable v0settingDCAnegtopv{"v0settingDCAnegtopv", 0.06, + "DCA Neg To PV"}; + Configurable v0settingDCAbactopv{"v0settingDCAbactopv", 0.06, + "DCA Bchelor To PV"}; + Configurable v0settingRapidity{"v0settingRapidity", 0.5, + "V0 rapidity cut"}; + Configurable v0settingCosPAK0s{"v0settingCosPAK0s", 0.97, + "V0 CosPA for K0s"}; + Configurable v0settingRadiusK0s{"v0settingRadiusK0s", 0.5, + "v0radius for K0s"}; + Configurable v0settingcTauK0s{"v0settingcTauK0s", 20, + "v0ctau for K0s"}; + Configurable v0settingMassRejectionK0s{"v0settingMassRejectionK0s", 0.005, + "Competing Mass Rejection cut for K0s"}; + Configurable v0settingArmePodoK0s{"v0settingArmePodoK0s", 0.2, + "Armenteros-Podolanski cut for K0s"}; + Configurable v0settingCosPALambda{"v0settingCosPALambda", 0.995, + "V0 CosPA for Lambda"}; + Configurable v0settingRadiusLambda{"v0settingRadiusLambda", 0.5, + "v0radius for Lambda"}; + Configurable v0settingcTauLambda{"v0settingcTauLambda", 30, + "v0ctau for Lambda"}; + Configurable v0settingMassRejectionLambda{"v0settingMassRejectionLambda", 0.01, + "Competing Mass Rejection cut for Lambda"}; + Configurable v0settingNTPCcrossedRows{"v0settingNTPCcrossedRows", 70, + "Minimum number of TPC crossed pad rows of the V0 daughters, negative: no cut"}; + } v0Sel; + + // Daughter track acceptance and PID + struct : ConfigurableGroup { + std::string prefix = "trkPid"; + Configurable cfgTrkEtaCut{"cfgTrkEtaCut", 0.8f, + "Eta range for tracks"}; + Configurable cfgTrkLowPtCut{"cfgTrkLowPtCut", 0.0f, "Minimum pT"}; + Configurable nSigmaTPCPion{"nSigmaTPCPion", 5, "nSigmaTPCPion"}; + Configurable nSigmaTPCProton{"nSigmaTPCProton", 5, "nSigmaTPCProton"}; + Configurable pidQAWindowK0s{"pidQAWindowK0s", 0.05, + "Half width of the K0s mass window used for the PID QA plots"}; + Configurable pidQAWindowLambda{"pidQAWindowLambda", 0.1, + "Half width of the Lambda mass window used for the PID QA plots"}; + // negative values disable a cut, so the defaults reproduce the previous selection + Configurable minCrossedRowsOverFindable{"minCrossedRowsOverFindable", -1.f, + "Minimum TPC crossed rows over findable clusters"}; + Configurable maxTpcChi2NCl{"maxTpcChi2NCl", -1.f, "Maximum TPC chi2 per cluster"}; + Configurable maxItsChi2NCl{"maxItsChi2NCl", -1.f, "Maximum ITS chi2 per cluster"}; + Configurable minItsNCls{"minItsNCls", -1, "Minimum number of ITS clusters"}; + } trkPid; + + // Cascade selection + struct : ConfigurableGroup { + std::string prefix = "cascSel"; + Configurable nTPCcrossedRows{"nTPCcrossedRows", 52, "Number of TPC crossed pad raws"}; + Configurable cascsettingDCAv0toPV{"cascsettingDCAv0toPV", 0.03, "DCA V0 To PV"}; + Configurable cascsettingDCAv0bach{"cascsettingDCAv0bach", 0.25, "DCA V0 To bachelor"}; + Configurable cascsettingDCAbaryontopv{"cascsettingDCAbaryontopv", 0.05, "DCA of the baryon daughter To PV"}; + Configurable cascsettingDCAmesontopv{"cascsettingDCAmesontopv", 0.1, "DCA of the meson daughter To PV"}; + Configurable cascsettingDCAxybaryonbach{"cascsettingDCAxybaryonbach", 0.02, "DCAxy Bachelor-Baryon To PV, below which the candidate is vetoed"}; + Configurable cascsettingCosPAbaryonbach{"cascsettingCosPAbaryonbach", 0.9999, "CosThetap Bachelor-Baryon, above which the candidate is vetoed"}; + Configurable cascsettingCosPAcascPV{"cascsettingCosPAcascPV", 0.9947, "CosThetap for Cascade to PV"}; + Configurable cascsettingCosPAv0PV{"cascsettingCosPAv0PV", 0.9876, "CosThetap for V0 to PV"}; + Configurable cascsettingv0radius{"cascsettingv0radius", 0.55, "V0 decay radius for cadcades in cm"}; + Configurable cascsettingcascradius{"cascsettingcascradius", 1.01, "Cascade decay radius for cadcades in cm"}; + Configurable cascsettingRapidity{"cascsettingRapidity", 0.5, "Cascade rapidity cut"}; + Configurable cascsettingMassRejectionLambdaXi{"cascsettingMassRejectionLambdaXi", 0.0116, "Casc Mass Rejection cut of Lambda for Xi"}; + Configurable cascsettingMassRejectioOmegaXi{"cascsettingMassRejectioOmegaXi", -1, "Casc Mass Rejection cut of Omega for Xi"}; + Configurable cascsettingproplifetime{"cascsettingproplifetime", 4.6, "Scale for lifetime cut on ctau Xi"}; + } cascSel; + + // values for flattenicityforanalysis + static constexpr int kFlatFromFV0 = 0; + static constexpr int kFlatFromFT0 = 1; + + // FT0M percentile class: run once over the full range for MB and once with a + // narrow window for HM. Grouped because the framework only decomposes 100 + // struct members (Framework/StructToTuple.h) + struct : ConfigurableGroup { + std::string prefix = "eventClass"; + Configurable applyCentSel{"applyCentSel", false, + "Select events in a FT0M percentile window"}; + Configurable cfgCentMin{"cfgCentMin", 0.0f, "Minimum FT0M percentile"}; + Configurable cfgCentMax{"cfgCentMax", 100.0f, "Maximum FT0M percentile"}; + // the processFlatDist* pass fills the MB and the HM 1-rho distributions + // together, so this window is applied to a histogram and not to the event + Configurable cfgCentMaxHM{"cfgCentMaxHM", 1.0f, + "Upper FT0M percentile of the high-multiplicity class"}; + + // keep only primaries in the MC-matched spectra, the rest go to the + // feed-down histograms + Configurable requirePrimaryMC{"requirePrimaryMC", true, + "Require isPhysicalPrimary() on the MC-matched candidate"}; + Configurable genFlatPrimariesOnly{"genFlatPrimariesOnly", true, + "Use only primaries in the generator-level flattenicity"}; + Configurable fillChargedQA{"fillChargedQA", true, + "Fill the charged-particle histograms used for and Qpp"}; + Configurable cfgEtaChargedCut{"cfgEtaChargedCut", 0.8f, + "Eta window of the charged-particle measurement"}; + // mothers outside the Lambda window still feed it, so the matrix is + // normalised in a wider one + Configurable cfgFeedDownMotherRapidity{"cfgFeedDownMotherRapidity", 1.5f, + "Rapidity window of the generated feed-down mothers"}; + } eventClass; // Configurable v0daughter_etacut{"V0DaughterEtaCut", 0.8, // "V0DaughterEtaCut"}; // Configurable v0etacut{"v0etacut", 0.8, "v0etacut"}; - // acceptance cuts for Flattenicity correlation - Configurable cfgTrkEtaCut{"cfgTrkEtaCut", 0.8f, - "Eta range for tracks"}; - Configurable cfgTrkLowPtCut{"cfgTrkLowPtCut", 0.0f, "Minimum pT"}; - - // Additional Cut configurables for Cascades - Configurable nTPCcrossedRows{"nTPCcrossedRows", 52, "Number of TPC crossed pad raws"}; - Configurable cascsettingDCAv0toPV{"cascsettingDCAv0toPV", 0.03, "DCA V0 To PV"}; - Configurable cascsettingDCAv0bach{"cascsettingDCAv0bach", 0.25, "DCA V0 To bachelor"}; - Configurable cascsettingDCAxybaryonbach{"cascsettingDCAxybaryonbach", 0.02, "DCA Baryon To bachelor"}; - Configurable cascsettingCosPAcascPV{"cascsettingCosPAcascPV", 0.9947, "CosThetap for Cascade to PV"}; - Configurable cascsettingCosPAv0PV{"cascsettingCosPAv0PV", 0.9876, "CosThetap for V0 to PV"}; - Configurable cascsettingv0radius{"cascsettingv0radius", 0.55, "V0 decay radius for cadcades in cm"}; - Configurable cascsettingcascradius{"cascsettingcascradius", 1.01, "Cascade decay radius for cadcades in cm"}; - Configurable cascsettingRapidity{"cascsettingRapidity", 0.5, "Cascade rapidity cut"}; - Configurable cascsettingMassRejectionLambdaXi{"cascsettingMassRejectionLambdaXi", 0.0116, "Casc Mass Rejection cut of Lambda for Xi"}; - Configurable cascsettingMassRejectioOmegaXi{"cascsettingMassRejectioOmegaXi", -1, "Casc Mass Rejection cut of Omega for Xi"}; - Configurable cascsettingproplifetime{"cascsettingproplifetime", 4.6, "Scale for lifetime cut on ctau Xi"}; - int nbin = 1; + // hEventsSelected bins for the stages inside estimateFlattenicity(), -1 if unused + int nbinFlatDetHit = -1; + int nbinFlatOccupancy = -1; + int nbinFlattenicity = -1; + + // how far estimateFlattenicity() got, so its rejections show in the cut flow + static constexpr int kFlatStageNoDetector = 0; + static constexpr int kFlatStageLowOccupancy = 1; + static constexpr int kFlatStageNoSignal = 2; + static constexpr int kFlatStageOk = 3; + int flatStage = kFlatStageNoDetector; + // do not fill the detector QA twice when processGenMC runs with a rec-level process + bool fillFlattenicityQAInGenMC = true; + + // the per-event histograms are shared by every rec-level process function, + // so only the one designated in init() fills them + static constexpr int kOwnerNone = -1; + static constexpr int kOwnerFlatDistData = 0; + static constexpr int kOwnerFlatDistMC = 1; + static constexpr int kOwnerRecMCV0 = 2; + static constexpr int kOwnerDataV0 = 3; + static constexpr int kOwnerRecMCCasc = 4; + static constexpr int kOwnerDataCasc = 5; + int eventHistOwner = kOwnerNone; + + // calibration objects, refreshed when the run changes + Service ccdb{}; + int mRunNumber = -1; + std::vector gainFV0; + std::vector gainFT0A; + std::vector gainFT0C; + TProfile2D* vtxEqFV0 = nullptr; + TProfile2D* vtxEqFT0A = nullptr; + TProfile2D* vtxEqFT0C = nullptr; void init(InitContext const&) { // Axes - AxisSpec k0sMassAxis = {nBinsK0sMass, 0.49f - kK0sEPshiftfromMass, 0.49f + kK0sEPshiftfromMass, + AxisSpec k0sMassAxis = {binning.nBinsK0sMass, o2::constants::physics::MassK0Short - binning.kK0sEPshiftfromMass, + o2::constants::physics::MassK0Short + binning.kK0sEPshiftfromMass, "#it{M}_{#pi^{+}#pi^{-}} [GeV/#it{c}^{2}]"}; - AxisSpec lambdaMassAxis = {nBinsLambdaMass, 1.115f - kLambdaEPshiftfromMass, 1.115f + kLambdaEPshiftfromMass, + AxisSpec lambdaMassAxis = {binning.nBinsLambdaMass, o2::constants::physics::MassLambda0 - binning.kLambdaEPshiftfromMass, + o2::constants::physics::MassLambda0 + binning.kLambdaEPshiftfromMass, "#it{M}_{p#pi^{-}} [GeV/#it{c}^{2}]"}; - AxisSpec antilambdaMassAxis = {nBinsLambdaMass, 1.115f - kLambdaEPshiftfromMass, 1.115f + kLambdaEPshiftfromMass, + AxisSpec antilambdaMassAxis = {binning.nBinsLambdaMass, o2::constants::physics::MassLambda0 - binning.kLambdaEPshiftfromMass, + o2::constants::physics::MassLambda0 + binning.kLambdaEPshiftfromMass, "#it{M}_{#pi^{+}#bar{p}} [GeV/#it{c}^{2}]"}; - AxisSpec xiMassAxis = {nBinsXiMass, 1.32f - kXiEPshiftfromMass, 1.32f + kXiEPshiftfromMass, + AxisSpec xiMassAxis = {binning.nBinsXiMass, o2::constants::physics::MassXiMinus - binning.kXiEPshiftfromMass, + o2::constants::physics::MassXiMinus + binning.kXiEPshiftfromMass, "#it{M}_{#Lambda#pi} [GeV/#it{c}^{2}]"}; - AxisSpec vertexZAxis = {nBinsVz, -15., 15., "vrtx_{Z} [cm]"}; - AxisSpec ptAxis = {nBinspT, 0.0f, 25.0f, "#it{p}_{T} (GeV/#it{c})"}; - AxisSpec flatAxis = {nBinsFlattenicity, 0.0f, 1.0f, "1-#rho_{ch}"}; - - int nBinsEst[8] = {100, 500, 102, 500, 102, 500, 102, 150}; - float lowEdgeEst[8] = {-0.5, -0.5, -0.01, -0.5, -0.01, -0.5, -0.01, .0}; - float upEdgeEst[8] = {99.5, 49999.5, 1.01, 499.5, 1.01, 499.5, 1.01, 150.0}; + AxisSpec vertexZAxis = {binning.nBinsVz, -15., 15., "vrtx_{Z} [cm]"}; + AxisSpec ptK0sAxis = {binning.axisPtK0s, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptLambdaAxis = {binning.axisPtLambda, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptXiAxis = {binning.axisPtXi, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec ptChargedAxis = {binning.axisPtCharged, "#it{p}_{T} (GeV/#it{c})"}; + AxisSpec pTPCAxis = {binning.axisPtPid, "#it{p}_{TPC} (GeV/#it{c})"}; + AxisSpec decayRadiusAxis = {100, 0.0f, 100.0f, "Decay Radius (cm)"}; + AxisSpec flatAxis = {binning.axisFlat, "1-#rho_{ch}"}; + AxisSpec flatTrueAxis = {binning.axisFlatTrue, "true 1-#rho_{ch}"}; + AxisSpec flatFineAxis = {binning.axisFlatFine, "1-#rho_{ch}"}; + AxisSpec centAxis = {binning.axisCent, "FT0M percentile"}; + AxisSpec nchAxis = {binning.axisNch, "#it{N}_{ch}"}; + AxisSpec dcaXyAxis = {binning.axisDcaXy, "DCA_{xy} (cm)"}; + AxisSpec dcaV0ToPvAxis = {binning.axisDcaV0ToPv, "DCA_{V0-PV} (cm)"}; + AxisSpec ptResAxis = {binning.axisPtRes, "(#it{p}_{T}^{rec} - #it{p}_{T}^{gen})/#it{p}_{T}^{gen}"}; + AxisSpec motherAxis = {kNFeedDownMothers, -0.5, kNFeedDownMothers - 0.5, "mother"}; + + std::array nBinsEst = {100, 500, 102, 500, 102, 500, 150}; + std::array lowEdgeEst = {-0.5, -0.5, -0.01, -0.5, -0.01, -0.5, .0}; + std::array upEdgeEst = {99.5, 49999.5, 1.01, 499.5, 1.01, 499.5, 150.0}; + + ccdb->setURL(ccdbConf.ccdbUrl.value); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); // Histograms // Event selection rEventSelection.add("hVertexZ", "hVertexZ", {HistType::kTH1D, {vertexZAxis}}); rEventSelection.add("hEventsSelected", "hEventsSelected", - {HistType::kTH1D, {{12, 0, 12}}}); + {HistType::kTH1D, {{15, 0, 15}}}); rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "all"); - if (issel8) { + if (evSel.issel8) { rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "sel8"); } rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "zvertex"); - if (isNoTimeFrameBorder) { + if (evSel.isNoTimeFrameBorder) { rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "TFBorder"); } - if (isNoITSROFrameBorder) { + if (evSel.isNoITSROFrameBorder) { rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "ITSROFBorder"); } - if (isVertexITSTPC) { + if (evSel.isVertexITSTPC) { rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "VertexITSTPC"); } - if (isNoSameBunchPileup) { + if (evSel.isNoSameBunchPileup) { rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "SameBunchPileup"); } - if (isGoodZvtxFT0vsPV) { + if (evSel.isGoodZvtxFT0vsPV) { rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "isGoodZvtxFT0vsPV"); } - if (isTriggerTVX) { + if (evSel.isTriggerTVX) { rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "TVX"); } - if (isINELgt0) { + if (evSel.isINELgt0) { rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "INEL>0"); } + // estimateFlattenicity() drops events on three grounds: no detector record, + // too few lit cells, undefined 1-rho. One counter each. + if (doprocessDataRun3LambdaK0s || doprocessRecMCLambdaK0s || + doprocessDataRun3Cascade || doprocessRecMCRun3Cascade || + doprocessFlatDistData || doprocessFlatDistMC) { + nbinFlatDetHit = nbin; + rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "flatDetHit"); + nbinFlatOccupancy = nbin; + rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "flatOccupancy"); + nbinFlattenicity = nbin; + rEventSelection.get(HIST("hEventsSelected"))->GetXaxis()->SetBinLabel(nbin++, "flattenicity"); + } rEventSelection.add("hFlattenicityDistribution", "hFlattenicityDistribution", {HistType::kTH1D, {flatAxis}}); - if (doprocessRecMCLambdaK0s || doprocessRecMCRun3Cascade) { + rEventSelection.add("hCentFT0M", "hCentFT0M", {HistType::kTH1D, {centAxis}}); + rEventSelection.add("hCentFT0MvsFlattenicity", "hCentFT0MvsFlattenicity", + {HistType::kTH2D, {centAxis, flatAxis}}); + + // 1-rho on the fine axis, the input to the percentile boundaries of + // binning.axisFlat. Filled once per accepted collision, by the owner. + rEventSelection.add("hFlatDistRec", "hFlatDistRec", {HistType::kTH1D, {flatFineAxis}}); + rEventSelection.add("hFlatDistRecINELgt0", "hFlatDistRecINELgt0", {HistType::kTH1D, {flatFineAxis}}); + rEventSelection.add("hFlatDistRecHM", "hFlatDistRecHM", {HistType::kTH1D, {flatFineAxis}}); + rEventSelection.add("hCentFT0MFine", "hCentFT0MFine", {HistType::kTH1D, {{1000, 0.0f, 100.0f, "FT0M percentile"}}}); + if (doprocessRecMCLambdaK0s || doprocessRecMCRun3Cascade || doprocessGenMC || + doprocessFlatDistMC) { + // one entry per generated collision, the sample the closure denominator + // lives in: binning.axisFlatTrue has to be set from this one, or the + // numerator and the denominator do not share a class definition + rEventSelection.add("hFlatDistGen", "hFlatDistGen", {HistType::kTH1D, {flatFineAxis}}); + rEventSelection.add("hFlatDistGenINELgt0", "hFlatDistGenINELgt0", {HistType::kTH1D, {flatFineAxis}}); + rEventSelection.add("hFlatDistGenHM", "hFlatDistGenHM", {HistType::kTH1D, {flatFineAxis}}); + // same, restricted to accepted reconstructed collisions: the ratio to + // hFlatDistGen is the event selection bias on the class assignment + rEventSelection.add("hFlatDistGenInRec", "hFlatDistGenInRec", {HistType::kTH1D, {flatFineAxis}}); + rEventSelection.add("hFlatDistGenInRecINELgt0", "hFlatDistGenInRecINELgt0", {HistType::kTH1D, {flatFineAxis}}); + rEventSelection.add("hFlatDistGenInRecHM", "hFlatDistGenInRecHM", {HistType::kTH1D, {flatFineAxis}}); + } + if (doprocessRecMCLambdaK0s || doprocessRecMCRun3Cascade || doprocessGenMC || + doprocessFlatDistMC) { + rEventSelection.add("hTrueFV0amplvsFlat", "TrueFV0MvsFlat", HistType::kTH2D, + {{500, -0.5, +499.5, "True Nch in FV0 region"}, flatTrueAxis}); + rEventSelection.add("hTrueFT0amplvsFlat", "TrueFT0MvsFlat", HistType::kTH2D, + {{500, -0.5, +499.5, "True Nch in FT0 region"}, flatTrueAxis}); + rEventSelection.add("hNActiveCellsFT0AMCGen", "hNActiveCellsFT0AMCGen", HistType::kTH1D, + {{kNChannelsFT0A + 1, -0.5, kNChannelsFT0A + 0.5, "occupied generated FT0A cells"}}); + rEventSelection.add("hNActiveCellsFT0CMCGen", "hNActiveCellsFT0CMCGen", HistType::kTH1D, + {{kNChannelsFT0C + 1, -0.5, kNChannelsFT0C + 0.5, "occupied generated FT0C cells"}}); + } + if (doprocessRecMCLambdaK0s || doprocessRecMCRun3Cascade || doprocessFlatDistMC) { rEventSelection.add("hFlattenicityDistributionMCGen_Rec", "hFlattenicityDistributionMCGen_Rec", - {HistType::kTH1D, {flatAxis}}); + {HistType::kTH1D, {flatTrueAxis}}); rEventSelection.add("hFlattenicity_Corr_Gen_vs_Rec", "hFlattenicity_Corr_Gen_vs_Rec", - {HistType::kTH2D, {flatAxis, flatAxis}}); + {HistType::kTH2D, {flatTrueAxis, flatAxis}}); + // migration of the class assignment, needed pT-differentially to unfold + rEventSelection.add("hFlatGenVsRecFine", "hFlatGenVsRecFine", + {HistType::kTH2D, {flatFineAxis, flatFineAxis}}); + } + + // Charged particles in |eta| < cfgEtaChargedCut: per class is + // the scale factor of Qpp, and the DCAxy templates give the secondary + // contamination the same way the published analysis obtains it. + if (eventClass.fillChargedQA) { + rCharged.add("hNchVsFlat", "hNchVsFlat", {HistType::kTH2D, {nchAxis, flatAxis}}); + rCharged.add("hPtChVsFlat", "hPtChVsFlat", {HistType::kTH2D, {ptChargedAxis, flatAxis}}); + if (doprocessRecMCLambdaK0s || doprocessRecMCRun3Cascade || doprocessFlatDistMC) { + rCharged.add("hPtChVsFlatRecPrim", "hPtChVsFlatRecPrim", + {HistType::kTH2D, {ptChargedAxis, flatAxis}}); + rCharged.add("hPtChVsFlatGenInRec", "hPtChVsFlatGenInRec", + {HistType::kTH2D, {ptChargedAxis, flatAxis}}); + rCharged.add("hNchVsFlatGenInRec", "hNchVsFlatGenInRec", {HistType::kTH2D, {nchAxis, flatAxis}}); + rCharged.add("hDcaXyPtChPrim", "hDcaXyPtChPrim", + {HistType::kTH3D, {dcaXyAxis, ptChargedAxis, flatAxis}}); + rCharged.add("hDcaXyPtChSec", "hDcaXyPtChSec", + {HistType::kTH3D, {dcaXyAxis, ptChargedAxis, flatAxis}}); + } + if (doprocessDataRun3LambdaK0s || doprocessDataRun3Cascade || doprocessFlatDistData) { + rCharged.add("hDcaXyPtCh", "hDcaXyPtCh", + {HistType::kTH3D, {dcaXyAxis, ptChargedAxis, flatAxis}}); + } + if (doprocessGenMC) { + rCharged.add("hPtChVsFlatGen", "hPtChVsFlatGen", {HistType::kTH2D, {ptChargedAxis, flatAxis}}); + rCharged.add("hNchVsFlatGen", "hNchVsFlatGen", {HistType::kTH2D, {nchAxis, flatAxis}}); + rCharged.add("hPtChVsTrueFlatGen", "hPtChVsTrueFlatGen", {HistType::kTH2D, {ptChargedAxis, flatTrueAxis}}); + rCharged.add("hNchVsTrueFlatGen", "hNchVsTrueFlatGen", {HistType::kTH2D, {nchAxis, flatTrueAxis}}); + } } if (doprocessDataRun3LambdaK0s || doprocessRecMCLambdaK0s) { @@ -306,27 +569,28 @@ struct Lambdak0sflattenicity { {HistType::kTH1D, {{40, -2.0f, 2.0f, "y"}}}); rKzeroShort.add("hctauK0s", "hctauK0s", {HistType::kTH1D, {{40, 0.0f, 40.0f, "c#tau (cm)"}}}); - rKzeroShort.add( - "h2DdecayRadiusK0s", "h2DdecayRadiusK0s", - {HistType::kTH1D, {{100, 0.0f, 1.0f, "Decay Radius (cm)"}}}); + rKzeroShort.add("h2DdecayRadiusK0s", "h2DdecayRadiusK0s", + {HistType::kTH1D, {decayRadiusAxis}}); rKzeroShort.add("hDCAV0DaughtersK0s", "hDCAV0DaughtersK0s", {HistType::kTH1D, {{55, 0.0f, 2.2f, "DCA Daughters"}}}); rKzeroShort.add("hV0CosPAK0s", "hV0CosPAK0s", {HistType::kTH1D, {{100, 0.95f, 1.f, "CosPA"}}}); rKzeroShort.add("hNSigmaPosPionFromK0s", "hNSigmaPosPionFromK0s", - {HistType::kTH2D, {{100, -5.f, 5.f}, {ptAxis}}}); + {HistType::kTH2D, {{100, -5.f, 5.f, "n#sigma_{TPC}"}, {pTPCAxis}}}); rKzeroShort.add("hNSigmaNegPionFromK0s", "hNSigmaNegPionFromK0s", - {HistType::kTH2D, {{100, -5.f, 5.f}, {ptAxis}}}); + {HistType::kTH2D, {{100, -5.f, 5.f, "n#sigma_{TPC}"}, {pTPCAxis}}}); rKzeroShort.add("hMassK0spT", "hMassK0spT", - {HistType::kTH2D, {{k0sMassAxis}, {ptAxis}}}); + {HistType::kTH2D, {{k0sMassAxis}, {ptK0sAxis}}}); rKzeroShort.add("hMassK0spTFlat", "hMassK0spTFlat", - {HistType::kTH3D, {{k0sMassAxis}, {ptAxis}, {flatAxis}}}); + {HistType::kTH3D, {{k0sMassAxis}, {ptK0sAxis}, {flatAxis}}}); rKzeroShort.add("hArmPodoAlphavsQTK0sAfterCut", "hArmPodoAlphavsQTK0sAfterCut", {HistType::kTH2D, {{200, -1, 1, "#alpha"}, {70, 0, 0.35, "Q_{T}"}}}); if (doprocessRecMCLambdaK0s) { rKzeroShort.add("Generated_MCRecoCollCheck_INEL_K0Short", "Generated_MCRecoCollCheck_INEL_K0Short", - {HistType::kTH2D, {{ptAxis}, {flatAxis}}}); + {HistType::kTH2D, {{ptK0sAxis}, {flatAxis}}}); + rKzeroShort.add("Generated_MCRecoCollCheck_INELgt0_K0Short", "Generated_MCRecoCollCheck_INELgt0_K0Short", + {HistType::kTH2D, {{ptK0sAxis}, {flatAxis}}}); } // Lambda reconstruction Mass @@ -340,23 +604,42 @@ struct Lambdak0sflattenicity { {HistType::kTH1D, {{55, 0.0f, 2.2f, "DCA Daughters"}}}); rLambda.add("hV0CosPALambda", "hV0CosPALambda", {HistType::kTH1D, {{100, 0.95f, 1.f, "CosPA"}}}); - rLambda.add("hNSigmaPosPionFromLambda", "hNSigmaPosPionFromLambda", - {HistType::kTH2D, {{100, -5.f, 5.f}, {ptAxis}}}); + rLambda.add("hNSigmaPosProtonFromLambda", "hNSigmaPosProtonFromLambda", + {HistType::kTH2D, {{100, -5.f, 5.f, "n#sigma_{TPC}"}, {pTPCAxis}}}); rLambda.add("hNSigmaNegPionFromLambda", "hNSigmaNegPionFromLambda", - {HistType::kTH2D, {{100, -5.f, 5.f}, {ptAxis}}}); + {HistType::kTH2D, {{100, -5.f, 5.f, "n#sigma_{TPC}"}, {pTPCAxis}}}); rLambda.add("hrapidityLambda", "hrapidityLambda", {HistType::kTH1D, {{40, -2.0f, 2.0f, "y"}}}); rLambda.add("hctauLambda", "hctauLambda", {HistType::kTH1D, {{40, 0.0f, 40.0f, "c#tau (cm)"}}}); rLambda.add("h2DdecayRadiusLambda", "h2DdecayRadiusLambda", - {HistType::kTH1D, {{100, 0.0f, 1.0f, "c#tau (cm)"}}}); + {HistType::kTH1D, {decayRadiusAxis}}); rLambda.add("hMassLambdapT", "hMassLambdapT", - {HistType::kTH2D, {{lambdaMassAxis}, {ptAxis}}}); + {HistType::kTH2D, {{lambdaMassAxis}, {ptLambdaAxis}}}); rLambda.add("hMassLambdapTFlat", "hMassLambdapTFlat", - {HistType::kTH3D, {{lambdaMassAxis}, {ptAxis}, {flatAxis}}}); + {HistType::kTH3D, {{lambdaMassAxis}, {ptLambdaAxis}, {flatAxis}}}); if (doprocessRecMCLambdaK0s) { rLambda.add("Generated_MCRecoCollCheck_INEL_Lambda", "Generated_MCRecoCollCheck_INEL_Lambda", - {HistType::kTH2D, {{ptAxis}, {flatAxis}}}); + {HistType::kTH2D, {{ptLambdaAxis}, {flatAxis}}}); + rLambda.add("Generated_MCRecoCollCheck_INELgt0_Lambda", "Generated_MCRecoCollCheck_INELgt0_Lambda", + {HistType::kTH2D, {{ptLambdaAxis}, {flatAxis}}}); + rLambda.add("hMassFeedDownLambdapTFlat", "hMassFeedDownLambdapTFlat", + {HistType::kTH3D, {{lambdaMassAxis}, {ptLambdaAxis}, {flatAxis}}}); + rLambda.add("hFeedDownLambdaPtVsMotherPt", "hFeedDownLambdaPtVsMotherPt", + {HistType::kTH2D, {{ptLambdaAxis}, {ptLambdaAxis}}}); + rLambda.add("hFeedDownLambdaMatrix", "hFeedDownLambdaMatrix", + {HistType::kTHnSparseF, {{ptLambdaAxis}, {ptLambdaAxis}, {flatAxis}, {motherAxis}}}); + rLambda.add("hFeedDownLambdaMotherPdg", "hFeedDownLambdaMotherPdg", + {HistType::kTH1D, {{motherAxis}}}); + rLambda.get(HIST("hFeedDownLambdaMotherPdg"))->GetXaxis()->SetBinLabel(1, "#Xi^{-}"); + rLambda.get(HIST("hFeedDownLambdaMotherPdg"))->GetXaxis()->SetBinLabel(2, "#Xi^{0}"); + rLambda.get(HIST("hFeedDownLambdaMotherPdg"))->GetXaxis()->SetBinLabel(3, "#Omega^{-}"); + rLambda.get(HIST("hFeedDownLambdaMotherPdg"))->GetXaxis()->SetBinLabel(4, "other"); + // generated mothers in the same events and classes as + // hFeedDownLambdaMatrix, so the matrix is a probability per mother that + // folds with the measured Xi. Xi0 is not measurable and only lives here. + rLambda.add("hGenFeedDownMotherPtFlat", "hGenFeedDownMotherPtFlat", + {HistType::kTHnSparseF, {{ptLambdaAxis}, {flatAxis}, {motherAxis}}}); } // AntiLambda reconstruction @@ -373,27 +656,77 @@ struct Lambdak0sflattenicity { {HistType::kTH1D, {{100, 0.95f, 1.f, "CosPA"}}}); rAntiLambda.add("hNSigmaPosPionFromAntiLambda", "hNSigmaPosPionFromAntiLambda", - {HistType::kTH2D, {{100, -5.f, 5.f}, {ptAxis}}}); - rAntiLambda.add("hNSigmaNegPionFromAntiLambda", - "hNSigmaNegPionFromAntiLambda", - {HistType::kTH2D, {{100, -5.f, 5.f}, {ptAxis}}}); + {HistType::kTH2D, {{100, -5.f, 5.f, "n#sigma_{TPC}"}, {pTPCAxis}}}); + rAntiLambda.add("hNSigmaNegProtonFromAntiLambda", + "hNSigmaNegProtonFromAntiLambda", + {HistType::kTH2D, {{100, -5.f, 5.f, "n#sigma_{TPC}"}, {pTPCAxis}}}); rAntiLambda.add("hrapidityAntiLambda", "hrapidityAntiLambda", {HistType::kTH1D, {{40, -2.0f, 2.0f, "y"}}}); rAntiLambda.add("hctauAntiLambda", "hctauAntiLambda", {HistType::kTH1D, {{40, 0.0f, 40.0f, "c#tau (cm)"}}}); rAntiLambda.add("h2DdecayRadiusAntiLambda", "h2DdecayRadiusAntiLambda", - {HistType::kTH1D, {{100, 0.0f, 1.0f, "c#tau (cm)"}}}); + {HistType::kTH1D, {decayRadiusAxis}}); rAntiLambda.add("hMassAntiLambdapT", "hMassAntiLambdapT", - {HistType::kTH2D, {{antilambdaMassAxis}, {ptAxis}}}); + {HistType::kTH2D, {{antilambdaMassAxis}, {ptLambdaAxis}}}); rAntiLambda.add("hMassAntiLambdapTFlat", "hMassAntiLambdapTFlat", - {HistType::kTH3D, {{antilambdaMassAxis}, {ptAxis}, {flatAxis}}}); + {HistType::kTH3D, {{antilambdaMassAxis}, {ptLambdaAxis}, {flatAxis}}}); if (doprocessRecMCLambdaK0s) { rAntiLambda.add("Generated_MCRecoCollCheck_INEL_AntiLambda", "Generated_MCRecoCollCheck_INEL_AntiLambda", - {HistType::kTH2D, {{ptAxis}, {flatAxis}}}); + {HistType::kTH2D, {{ptLambdaAxis}, {flatAxis}}}); + rAntiLambda.add("Generated_MCRecoCollCheck_INELgt0_AntiLambda", "Generated_MCRecoCollCheck_INELgt0_AntiLambda", + {HistType::kTH2D, {{ptLambdaAxis}, {flatAxis}}}); + rAntiLambda.add("hMassFeedDownAntiLambdapTFlat", "hMassFeedDownAntiLambdapTFlat", + {HistType::kTH3D, {{antilambdaMassAxis}, {ptLambdaAxis}, {flatAxis}}}); + rAntiLambda.add("hFeedDownAntiLambdaPtVsMotherPt", "hFeedDownAntiLambdaPtVsMotherPt", + {HistType::kTH2D, {{ptLambdaAxis}, {ptLambdaAxis}}}); + rAntiLambda.add("hFeedDownAntiLambdaMatrix", "hFeedDownAntiLambdaMatrix", + {HistType::kTHnSparseF, {{ptLambdaAxis}, {ptLambdaAxis}, {flatAxis}, {motherAxis}}}); + rAntiLambda.add("hFeedDownAntiLambdaMotherPdg", "hFeedDownAntiLambdaMotherPdg", + {HistType::kTH1D, {{motherAxis}}}); + rAntiLambda.get(HIST("hFeedDownAntiLambdaMotherPdg"))->GetXaxis()->SetBinLabel(1, "#Xi^{-}"); + rAntiLambda.get(HIST("hFeedDownAntiLambdaMotherPdg"))->GetXaxis()->SetBinLabel(2, "#Xi^{0}"); + rAntiLambda.get(HIST("hFeedDownAntiLambdaMotherPdg"))->GetXaxis()->SetBinLabel(3, "#Omega^{-}"); + rAntiLambda.get(HIST("hFeedDownAntiLambdaMotherPdg"))->GetXaxis()->SetBinLabel(4, "other"); } rCommonHist.add("hArmPodoAlphavsQT", "hArmPodoAlphavsQT", {HistType::kTH2D, {{200, -1, 1, "#alpha"}, {70, 0, 0.35, "Q_{T}"}}}); + + // DCA of the V0 to the PV: primaries peak at zero, feed-down does not, so + // the data distribution can be fitted with the two MC templates + rLambda.add("hDcaV0ToPVLambda", "hDcaV0ToPVLambda", + {HistType::kTH3D, {{dcaV0ToPvAxis}, {ptLambdaAxis}, {flatAxis}}}); + rAntiLambda.add("hDcaV0ToPVAntiLambda", "hDcaV0ToPVAntiLambda", + {HistType::kTH3D, {{dcaV0ToPvAxis}, {ptLambdaAxis}, {flatAxis}}}); + if (doprocessRecMCLambdaK0s) { + rLambda.add("hDcaV0ToPVLambdaPrim", "hDcaV0ToPVLambdaPrim", + {HistType::kTH3D, {{dcaV0ToPvAxis}, {ptLambdaAxis}, {flatAxis}}}); + rLambda.add("hDcaV0ToPVLambdaSec", "hDcaV0ToPVLambdaSec", + {HistType::kTH3D, {{dcaV0ToPvAxis}, {ptLambdaAxis}, {flatAxis}}}); + rAntiLambda.add("hDcaV0ToPVAntiLambdaPrim", "hDcaV0ToPVAntiLambdaPrim", + {HistType::kTH3D, {{dcaV0ToPvAxis}, {ptLambdaAxis}, {flatAxis}}}); + rAntiLambda.add("hDcaV0ToPVAntiLambdaSec", "hDcaV0ToPVAntiLambdaSec", + {HistType::kTH3D, {{dcaV0ToPvAxis}, {ptLambdaAxis}, {flatAxis}}}); + + rKzeroShort.add("hPtResK0s", "hPtResK0s", {HistType::kTH2D, {{ptK0sAxis}, {ptResAxis}}}); + rLambda.add("hPtResLambda", "hPtResLambda", {HistType::kTH2D, {{ptLambdaAxis}, {ptResAxis}}}); + rAntiLambda.add("hPtResAntiLambda", "hPtResAntiLambda", {HistType::kTH2D, {{ptLambdaAxis}, {ptResAxis}}}); + + // numerator classified by the measured 1-rho, denominator by the true + // one: the pair is the MC closure + rKzeroShort.add("Generated_MCRecoCollCheck_INELgt0_K0Short_TrueFlat", "Generated_MCRecoCollCheck_INELgt0_K0Short_TrueFlat", + {HistType::kTH2D, {{ptK0sAxis}, {flatTrueAxis}}}); + rLambda.add("Generated_MCRecoCollCheck_INELgt0_Lambda_TrueFlat", "Generated_MCRecoCollCheck_INELgt0_Lambda_TrueFlat", + {HistType::kTH2D, {{ptLambdaAxis}, {flatTrueAxis}}}); + rAntiLambda.add("Generated_MCRecoCollCheck_INELgt0_AntiLambda_TrueFlat", "Generated_MCRecoCollCheck_INELgt0_AntiLambda_TrueFlat", + {HistType::kTH2D, {{ptLambdaAxis}, {flatTrueAxis}}}); + rKzeroShort.add("hMassK0spTTrueFlat", "hMassK0spTTrueFlat", + {HistType::kTH3D, {{k0sMassAxis}, {ptK0sAxis}, {flatTrueAxis}}}); + rLambda.add("hMassLambdapTTrueFlat", "hMassLambdapTTrueFlat", + {HistType::kTH3D, {{lambdaMassAxis}, {ptLambdaAxis}, {flatTrueAxis}}}); + rAntiLambda.add("hMassAntiLambdapTTrueFlat", "hMassAntiLambdapTTrueFlat", + {HistType::kTH3D, {{antilambdaMassAxis}, {ptLambdaAxis}, {flatTrueAxis}}}); + } } if (doprocessRecMCRun3Cascade || doprocessDataRun3Cascade) { @@ -406,24 +739,45 @@ struct Lambdak0sflattenicity { {HistType::kTH1D, {{40, -2.0f, 2.0f, "y"}}}); rXi.add("hctauXi", "hctauXi", {HistType::kTH1D, {{40, 0.0f, 40.0f, "c#tau (cm)"}}}); - rXi.add( - "h2DdecayRadiusXi", "h2DdecayRadiusXi", - {HistType::kTH1D, {{100, 0.0f, 1.0f, "Decay Radius (cm)"}}}); + rXi.add("h2DdecayRadiusXi", "h2DdecayRadiusXi", + {HistType::kTH1D, {decayRadiusAxis}}); rXi.add("hDCAV0DaughtersXi", "hDCAV0DaughtersXi", {HistType::kTH1D, {{55, 0.0f, 2.2f, "DCA Daughters"}}}); rXi.add("hV0CosPAXi", "hV0CosPAXi", {HistType::kTH1D, {{100, 0.95f, 1.f, "CosPA"}}}); - rXi.add("hNSigmaPosPionFromXi", "hNSigmaPosPionFromXi", - {HistType::kTH2D, {{100, -5.f, 5.f}, {ptAxis}}}); - rXi.add("hNSigmaNegPionFromXi", "hNSigmaNegPionFromXi", - {HistType::kTH2D, {{100, -5.f, 5.f}, {ptAxis}}}); + rXi.add("hNSigmaProtonFromXi", "hNSigmaProtonFromXi", + {HistType::kTH2D, {{100, -5.f, 5.f, "n#sigma_{TPC}"}, {pTPCAxis}}}); + rXi.add("hNSigmaPionFromXi", "hNSigmaPionFromXi", + {HistType::kTH2D, {{100, -5.f, 5.f, "n#sigma_{TPC}"}, {pTPCAxis}}}); + rXi.add("hNSigmaBachPionFromXi", "hNSigmaBachPionFromXi", + {HistType::kTH2D, {{100, -5.f, 5.f, "n#sigma_{TPC}"}, {pTPCAxis}}}); rXi.add("hMassXipT", "hMassXipT", - {HistType::kTH2D, {{xiMassAxis}, {ptAxis}}}); + {HistType::kTH2D, {{xiMassAxis}, {ptXiAxis}}}); rXi.add("hMassXipTFlat", "hMassXipTFlat", - {HistType::kTH3D, {{xiMassAxis}, {ptAxis}, {flatAxis}}}); + {HistType::kTH3D, {{xiMassAxis}, {ptXiAxis}, {flatAxis}}}); if (doprocessRecMCRun3Cascade) { rXi.add("Generated_MCRecoCollCheck_INEL_Xi", "Generated_MCRecoCollCheck_INEL_Xi", - {HistType::kTH2D, {{ptAxis}, {flatAxis}}}); + {HistType::kTH2D, {{ptXiAxis}, {flatAxis}}}); + rXi.add("Generated_MCRecoCollCheck_INELgt0_Xi", "Generated_MCRecoCollCheck_INELgt0_Xi", + {HistType::kTH2D, {{ptXiAxis}, {flatAxis}}}); + rXi.add("hMassFeedDownXipTFlat", "hMassFeedDownXipTFlat", + {HistType::kTH3D, {{xiMassAxis}, {ptXiAxis}, {flatAxis}}}); + rXi.add("hFeedDownXiPtVsMotherPt", "hFeedDownXiPtVsMotherPt", + {HistType::kTH2D, {{ptXiAxis}, {ptXiAxis}}}); + rXi.add("hFeedDownXiMatrix", "hFeedDownXiMatrix", + {HistType::kTHnSparseF, {{ptXiAxis}, {ptXiAxis}, {flatAxis}, {motherAxis}}}); + rXi.add("hFeedDownXiMotherPdg", "hFeedDownXiMotherPdg", + {HistType::kTH1D, {{motherAxis}}}); + rXi.get(HIST("hFeedDownXiMotherPdg"))->GetXaxis()->SetBinLabel(1, "#Xi^{-}"); + rXi.get(HIST("hFeedDownXiMotherPdg"))->GetXaxis()->SetBinLabel(2, "#Xi^{0}"); + rXi.get(HIST("hFeedDownXiMotherPdg"))->GetXaxis()->SetBinLabel(3, "#Omega^{-}"); + rXi.get(HIST("hFeedDownXiMotherPdg"))->GetXaxis()->SetBinLabel(4, "other"); + + rXi.add("hPtResXi", "hPtResXi", {HistType::kTH2D, {{ptXiAxis}, {ptResAxis}}}); + rXi.add("Generated_MCRecoCollCheck_INELgt0_Xi_TrueFlat", "Generated_MCRecoCollCheck_INELgt0_Xi_TrueFlat", + {HistType::kTH2D, {{ptXiAxis}, {flatTrueAxis}}}); + rXi.add("hMassXipTTrueFlat", "hMassXipTTrueFlat", + {HistType::kTH3D, {{xiMassAxis}, {ptXiAxis}, {flatTrueAxis}}}); } } if (doprocessGenMC) { @@ -434,7 +788,7 @@ struct Lambdak0sflattenicity { {HistType::kTH1D, {vertexZAxis}}); rEventSelection.add("hFlattenicityDistributionMCGen", "hFlattenicityDistributionMCGen", - {HistType::kTH1D, {flatAxis}}); + {HistType::kTH1D, {flatTrueAxis}}); rEventSelection.add("hFlattenicityDistributionRecMCGen", "hFlattenicityDistributionRecMCGen", {HistType::kTH1D, {flatAxis}}); @@ -452,93 +806,124 @@ struct Lambdak0sflattenicity { rEventSelection.add("hNEventsMCGenReco", "hNEventsMCGenReco", {HistType::kTH1D, {{2, 0.f, 2.f}}}); rEventSelection.get(HIST("hNEventsMCGenReco"))->GetXaxis()->SetBinLabel(1, "INEL"); rEventSelection.get(HIST("hNEventsMCGenReco"))->GetXaxis()->SetBinLabel(2, "INELgt0"); - rEventSelection.add("hNEventsMCReco", "hNEventsMCReco", {HistType::kTH1D, {{4, 0.f, 4.f}}}); + rEventSelection.add("hNEventsMCReco", "hNEventsMCReco", {HistType::kTH1D, {{3, 0.f, 3.f}}}); rEventSelection.get(HIST("hNEventsMCReco"))->GetXaxis()->SetBinLabel(1, "all"); rEventSelection.get(HIST("hNEventsMCReco"))->GetXaxis()->SetBinLabel(2, "pass ev sel"); rEventSelection.get(HIST("hNEventsMCReco"))->GetXaxis()->SetBinLabel(3, "INELgt0"); - rEventSelection.get(HIST("hNEventsMCReco"))->GetXaxis()->SetBinLabel(4, "check"); - rEventSelection.add("hTrueFV0amplvsFlat", "TrueFV0MvsFlat", HistType::kTH2D, - {{500, -0.5, +499.5, "True Nch in FV0 region"}, flatAxis}); - rKzeroShort.add("pGen_MCGenRecoColl_INEL_K0Short", "pGen_MCGenRecoColl_INEL_K0Short", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptK0sAxis, flatAxis}}); rKzeroShort.add("Generated_MCRecoColl_INEL_K0Short", "Generated_MCRecoColl_INEL_K0Short", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptK0sAxis, flatAxis}}); rKzeroShort.add("pGen_MCGenColl_INEL_K0Short", "pGen_MCGenColl_INEL_K0Short", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptK0sAxis, flatAxis}}); rKzeroShort.add("pGen_MCGenRecoColl_INELgt0_K0Short", "pGen_MCGenRecoColl_INELgt0_K0Short", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptK0sAxis, flatAxis}}); rKzeroShort.add("Generated_MCRecoColl_INELgt0_K0Short", "Generated_MCRecoColl_INELgt0_K0Short", - {HistType::kTH2D, {ptAxis, flatAxis}}); - rKzeroShort.add("Generated_MCRecoCollCheck_INELgt0_K0Short", "Generated_MCRecoCollCheck_INELgt0_K0Short", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptK0sAxis, flatAxis}}); rKzeroShort.add("pGen_MCGenColl_INELgt0_K0Short", "pGen_MCGenColl_INELgt0_K0Short", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptK0sAxis, flatAxis}}); rLambda.add("pGen_MCGenRecoColl_INEL_Lambda", "pGen_MCGenRecoColl_INEL_Lambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rLambda.add("Generated_MCRecoColl_INEL_Lambda", "Generated_MCRecoColl_INEL_Lambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rLambda.add("pGen_MCGenColl_INEL_Lambda", "pGen_MCGenColl_INEL_Lambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rLambda.add("pGen_MCGenRecoColl_INELgt0_Lambda", "pGen_MCGenRecoColl_INELgt0_Lambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rLambda.add("Generated_MCRecoColl_INELgt0_Lambda", "Generated_MCRecoColl_INELgt0_Lambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); - rLambda.add("Generated_MCRecoCollCheck_INELgt0_Lambda", "Generated_MCRecoCollCheck_INELgt0_Lambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rLambda.add("pGen_MCGenColl_INELgt0_Lambda", "pGen_MCGenColl_INELgt0_Lambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rAntiLambda.add("pGen_MCGenRecoColl_INEL_AntiLambda", "pGen_MCGenRecoColl_INEL_AntiLambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rAntiLambda.add("Generated_MCRecoColl_INEL_AntiLambda", "Generated_MCRecoColl_INEL_AntiLambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rAntiLambda.add("pGen_MCGenColl_INEL_AntiLambda", "pGen_MCGenColl_INEL_AntiLambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rAntiLambda.add("pGen_MCGenRecoColl_INELgt0_AntiLambda", "pGen_MCGenRecoColl_INELgt0_AntiLambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rAntiLambda.add("Generated_MCRecoColl_INELgt0_AntiLambda", "Generated_MCRecoColl_INELgt0_AntiLambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); - rAntiLambda.add("Generated_MCRecoCollCheck_INELgt0_AntiLambda", "Generated_MCRecoCollCheck_INELgt0_AntiLambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rAntiLambda.add("pGen_MCGenColl_INELgt0_AntiLambda", "pGen_MCGenColl_INELgt0_AntiLambda", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptLambdaAxis, flatAxis}}); rXi.add("pGen_MCGenRecoColl_INEL_Xi", "pGen_MCGenRecoColl_INEL_Xi", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptXiAxis, flatAxis}}); rXi.add("Generated_MCRecoColl_INEL_Xi", "Generated_MCRecoColl_INEL_Xi", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptXiAxis, flatAxis}}); rXi.add("pGen_MCGenColl_INEL_Xi", "pGen_MCGenColl_INEL_Xi", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptXiAxis, flatAxis}}); rXi.add("pGen_MCGenRecoColl_INELgt0_Xi", "pGen_MCGenRecoColl_INELgt0_Xi", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptXiAxis, flatAxis}}); rXi.add("Generated_MCRecoColl_INELgt0_Xi", "Generated_MCRecoColl_INELgt0_Xi", - {HistType::kTH2D, {ptAxis, flatAxis}}); - rXi.add("Generated_MCRecoCollCheck_INELgt0_Xi", "Generated_MCRecoCollCheck_INELgt0_Xi", - {HistType::kTH2D, {ptAxis, flatAxis}}); + {HistType::kTH2D, {ptXiAxis, flatAxis}}); rXi.add("pGen_MCGenColl_INELgt0_Xi", "pGen_MCGenColl_INELgt0_Xi", - {HistType::kTH2D, {ptAxis, flatAxis}}); - } - - if (flattenicityQA) { + {HistType::kTH2D, {ptXiAxis, flatAxis}}); + + // The same INEL>0 counters against the true 1-rho. Together with the + // reconstructed ones above they give the closure without a second job. + rEventSelection.add("hFlat_RecoColl_MC_INELgt0_TrueFlat", "hFlat_RecoColl_MC_INELgt0_TrueFlat", + {HistType::kTH1D, {flatTrueAxis}}); + rEventSelection.add("hFlat_GenRecoColl_MC_INELgt0_TrueFlat", "hFlat_GenRecoColl_MC_INELgt0_TrueFlat", + {HistType::kTH1D, {flatTrueAxis}}); + rEventSelection.add("hFlat_GenColl_MC_INELgt0_TrueFlat", "hFlat_GenColl_MC_INELgt0_TrueFlat", + {HistType::kTH1D, {flatTrueAxis}}); + rKzeroShort.add("pGen_MCGenRecoColl_INELgt0_K0Short_TrueFlat", "pGen_MCGenRecoColl_INELgt0_K0Short_TrueFlat", + {HistType::kTH2D, {ptK0sAxis, flatTrueAxis}}); + rKzeroShort.add("Generated_MCRecoColl_INELgt0_K0Short_TrueFlat", "Generated_MCRecoColl_INELgt0_K0Short_TrueFlat", + {HistType::kTH2D, {ptK0sAxis, flatTrueAxis}}); + rKzeroShort.add("pGen_MCGenColl_INELgt0_K0Short_TrueFlat", "pGen_MCGenColl_INELgt0_K0Short_TrueFlat", + {HistType::kTH2D, {ptK0sAxis, flatTrueAxis}}); + rLambda.add("pGen_MCGenRecoColl_INELgt0_Lambda_TrueFlat", "pGen_MCGenRecoColl_INELgt0_Lambda_TrueFlat", + {HistType::kTH2D, {ptLambdaAxis, flatTrueAxis}}); + rLambda.add("Generated_MCRecoColl_INELgt0_Lambda_TrueFlat", "Generated_MCRecoColl_INELgt0_Lambda_TrueFlat", + {HistType::kTH2D, {ptLambdaAxis, flatTrueAxis}}); + rLambda.add("pGen_MCGenColl_INELgt0_Lambda_TrueFlat", "pGen_MCGenColl_INELgt0_Lambda_TrueFlat", + {HistType::kTH2D, {ptLambdaAxis, flatTrueAxis}}); + rAntiLambda.add("pGen_MCGenRecoColl_INELgt0_AntiLambda_TrueFlat", "pGen_MCGenRecoColl_INELgt0_AntiLambda_TrueFlat", + {HistType::kTH2D, {ptLambdaAxis, flatTrueAxis}}); + rAntiLambda.add("Generated_MCRecoColl_INELgt0_AntiLambda_TrueFlat", "Generated_MCRecoColl_INELgt0_AntiLambda_TrueFlat", + {HistType::kTH2D, {ptLambdaAxis, flatTrueAxis}}); + rAntiLambda.add("pGen_MCGenColl_INELgt0_AntiLambda_TrueFlat", "pGen_MCGenColl_INELgt0_AntiLambda_TrueFlat", + {HistType::kTH2D, {ptLambdaAxis, flatTrueAxis}}); + rXi.add("pGen_MCGenRecoColl_INELgt0_Xi_TrueFlat", "pGen_MCGenRecoColl_INELgt0_Xi_TrueFlat", + {HistType::kTH2D, {ptXiAxis, flatTrueAxis}}); + rXi.add("Generated_MCRecoColl_INELgt0_Xi_TrueFlat", "Generated_MCRecoColl_INELgt0_Xi_TrueFlat", + {HistType::kTH2D, {ptXiAxis, flatTrueAxis}}); + rXi.add("pGen_MCGenColl_INELgt0_Xi_TrueFlat", "pGen_MCGenColl_INELgt0_Xi_TrueFlat", + {HistType::kTH2D, {ptXiAxis, flatTrueAxis}}); + } + + if (flatSel.flattenicityQA) { rFlattenicity.add("hEv", "Ev", HistType::kTH1D, {{6, -0.5, 5.5, "index activated detector"}}); rFlattenicity.add("hFV0amplRing1to4", "FV01to4", HistType::kTH1D, {{4000, -0.5, +49999.5, "FV0 amplitude"}}); rFlattenicity.add("hFT0Aampl", "FTAampl", HistType::kTH1D, - {{50000, -0.5, +199999.5, "FT0A amplitude"}}); + {{2000, -0.5, +199999.5, "Summed FT0A amplitude"}}); rFlattenicity.add("hFT0Campl", "FTCampl", HistType::kTH1D, - {{10000, -0.5, +4999.5, "FT0C amplitude"}}); + {{2000, -0.5, +99999.5, "Summed FT0C amplitude"}}); rFlattenicity.add("hFT0C", "FT0C", HistType::kTH1D, - {{50000, -0.5, 199999.5, "FT0C amplitudes"}}); + {{2000, -0.5, 1999.5, "FT0C amplitude per channel"}}); rFlattenicity.add("hFT0A", "FT0A", HistType::kTH1D, - {{2000, -0.5, 1999.5, "FT0A amplitudes"}}); + {{2000, -0.5, 1999.5, "FT0A amplitude per channel"}}); + // lattice occupancy, what the minLitCells cuts are tuned on + rFlattenicity.add("hNActiveFT0Channels", "hNActiveFT0Channels", HistType::kTH1D, + {{kNChannelsFT0 + 1, -0.5, kNChannelsFT0 + 0.5, + "FT0 channels with amplitude > 0"}}); + rFlattenicity.add("hNActiveCellsFV0", "hNActiveCellsFV0", HistType::kTH1D, + {{kNCells + 1, -0.5, kNCells + 0.5, "occupied FV0 lattice cells"}}); + rFlattenicity.add("hNActiveCellsFT0A", "hNActiveCellsFT0A", HistType::kTH1D, + {{kNChannelsFT0A + 1, -0.5, kNChannelsFT0A + 0.5, "occupied FT0A lattice cells"}}); + rFlattenicity.add("hNActiveCellsFT0C", "hNActiveCellsFT0C", HistType::kTH1D, + {{kNChannelsFT0C + 1, -0.5, kNChannelsFT0C + 0.5, "occupied FT0C lattice cells"}}); rFlattenicity.add("hFV0amplvsFlat", "FV0MvsFlat", HistType::kTH2D, {{4000, -0.5, +49999.5, "FV0 amplitude"}, flatAxis}); // estimators - for (int iEe = 0; iEe < 8; ++iEe) { + for (int iEe = 0; iEe < kNEstimators; ++iEe) { rFlattenicity.add( kHEst[iEe].data(), "", HistType::kTH2D, {{nBinsEst[iEe], lowEdgeEst[iEe], upEdgeEst[iEe], kTEst[iEe].data()}, @@ -546,7 +931,7 @@ struct Lambdak0sflattenicity { } // vs pT - for (int iEe = 0; iEe < 8; ++iEe) { + for (int iEe = 0; iEe < kNEstimators; ++iEe) { rFlattenicity.add( kHPtEst[iEe].data(), "", HistType::kTProfile, {{nBinsEst[iEe], lowEdgeEst[iEe], upEdgeEst[iEe], kTEst[iEe].data()}}); @@ -610,149 +995,74 @@ struct Lambdak0sflattenicity { if ((doprocessDataRun3LambdaK0s || doprocessDataRun3Cascade) && doprocessGenMC) { LOGF(fatal, "Can not run MCGen and Data process functions together. Try one of these at a time"); } + + // the spectra passes come first, their event counts normalise the yields + if (doprocessRecMCLambdaK0s) { + eventHistOwner = kOwnerRecMCV0; + } else if (doprocessDataRun3LambdaK0s) { + eventHistOwner = kOwnerDataV0; + } else if (doprocessRecMCRun3Cascade) { + eventHistOwner = kOwnerRecMCCasc; + } else if (doprocessDataRun3Cascade) { + eventHistOwner = kOwnerDataCasc; + } else if (doprocessFlatDistMC) { + eventHistOwner = kOwnerFlatDistMC; + } else if (doprocessFlatDistData) { + eventHistOwner = kOwnerFlatDistData; + } + + // tied to the owner so a new process function cannot bring the double fill back + fillFlattenicityQAInGenMC = (eventHistOwner == kOwnerNone); + + // both estimators have a generator-level counterpart, so only check the switch + if (flatSel.flattenicityforanalysis != kFlatFromFV0 && + flatSel.flattenicityforanalysis != kFlatFromFT0) { + LOGF(fatal, "flattenicityforanalysis must be 0 (FV0) or 1 (FT0)"); + } + if (flatSel.flattenicityforanalysis == kFlatFromFV0 && !flatSel.isflattenicitywithFV0) { + LOGF(fatal, "flattenicityforanalysis=0 (FV0) needs isflattenicitywithFV0 enabled"); + } + if (flatSel.flattenicityforanalysis == kFlatFromFT0 && !flatSel.isflattenicitywithFT0) { + LOGF(fatal, "flattenicityforanalysis=1 (FT0) needs isflattenicitywithFT0 enabled"); + } } + // FT0 sectors group kNChannelsPerT0Sector consecutive channels int getT0ASector(int iCh) { - int iSecT0a = -1; - for (int iSec = 0; iSec < 24; ++iSec) { - if (iCh >= 4 * iSec && iCh <= 3 + 4 * iSec) { - iSecT0a = iSec; - break; - } - } - return iSecT0a; + const int iSec = iCh / kNChannelsPerT0Sector; + return (iCh >= 0 && iSec < kNSectorsT0A) ? iSec : -1; } int getT0CSector(int iCh) { - int iSecT0c = -1; - for (int iSec = 0; iSec < 28; ++iSec) { - if (iCh >= 4 * iSec && iCh <= 3 + 4 * iSec) { - iSecT0c = iSec; - break; - } - } - return iSecT0c; + const int iSec = iCh / kNChannelsPerT0Sector; + return (iCh >= 0 && iSec < kNSectorsT0C) ? iSec : -1; } + // four inner rings of kNChannelsPerFV0Ring channels each, the rest is the outer ring int getFV0Ring(int iCh) { - int iRing = -1; - if (iCh < 8) { - iRing = 0; - } else if (iCh >= 8 && iCh < 16) { - iRing = 1; - } else if (iCh >= 16 && iCh < 24) { - iRing = 2; - } else if (iCh >= 24 && iCh < 32) { - iRing = 3; - } else { - iRing = 4; + const int iRing = iCh / kNChannelsPerFV0Ring; + if (iRing < 0) { + return 0; } - return iRing; + return (iRing < kOuterFV0RingIndex) ? iRing : kOuterFV0RingIndex; } + // FV0 channel -> phi-ordered index, a fixed permutation of the 48 channels int getFV0IndexPhi(int iCh) { - int iRing = -1; - - if (iCh >= 0 && iCh < 8) { - if (iCh < 4) { - iRing = iCh; - } else { - if (iCh == 7) { - iRing = 4; - } else if (iCh == 6) { - iRing = 5; - } else if (iCh == 5) { - iRing = 6; - } else if (iCh == 4) { - iRing = 7; - } - } - } else if (iCh >= 8 && iCh < 16) { - if (iCh < 12) { - iRing = iCh; - } else { - if (iCh == 15) { - iRing = 12; - } else if (iCh == 14) { - iRing = 13; - } else if (iCh == 13) { - iRing = 14; - } else if (iCh == 12) { - iRing = 15; - } - } - } else if (iCh >= 16 && iCh < 24) { - if (iCh < 20) { - iRing = iCh; - } else { - if (iCh == 23) { - iRing = 20; - } else if (iCh == 22) { - iRing = 21; - } else if (iCh == 21) { - iRing = 22; - } else if (iCh == 20) { - iRing = 23; - } - } - } else if (iCh >= 24 && iCh < 32) { - if (iCh < 28) { - iRing = iCh; - } else { - if (iCh == 31) { - iRing = 28; - } else if (iCh == 30) { - iRing = 29; - } else if (iCh == 29) { - iRing = 30; - } else if (iCh == 28) { - iRing = 31; - } - } - } else if (iCh == 32) { - iRing = 32; - } else if (iCh == 40) { - iRing = 33; - } else if (iCh == 33) { - iRing = 34; - } else if (iCh == 41) { - iRing = 35; - } else if (iCh == 34) { - iRing = 36; - } else if (iCh == 42) { - iRing = 37; - } else if (iCh == 35) { - iRing = 38; - } else if (iCh == 43) { - iRing = 39; - } else if (iCh == 47) { - iRing = 40; - } else if (iCh == 39) { - iRing = 41; - } else if (iCh == 46) { - iRing = 42; - } else if (iCh == 38) { - iRing = 43; - } else if (iCh == 45) { - iRing = 44; - } else if (iCh == 37) { - iRing = 45; - } else if (iCh == 44) { - iRing = 46; - } else if (iCh == 36) { - iRing = 47; - } - return iRing; + if (iCh < 0 || iCh >= kNCells) { + return -1; + } + return kFV0PhiIndex[iCh]; } float getFlatenicity(std::span signals) { int entries = signals.size(); - float flat = 9999; + float flat = kFlatUndefined; float mRho = 0; for (int iCell = 0; iCell < entries; ++iCell) { mRho += 1.0 * signals[iCell]; @@ -771,207 +1081,419 @@ struct Lambdak0sflattenicity { } return flat; } - float pdgmassK0s = 0.497614; - float pdgmassLambda = 1.115683; - float pdgmassXi = 1.3217; - float pdgmassOmega = 1.67243; - // V0A signal and flatenicity calculation - static constexpr float kCalib[48] = { - 1.01697, 1.122, 1.03854, 1.108, 1.11634, 1.14971, 1.19321, - 1.06866, 0.954675, 0.952695, 0.969853, 0.957557, 0.989784, 1.01549, - 1.02182, 0.976005, 1.01865, 1.06871, 1.06264, 1.02969, 1.07378, - 1.06622, 1.15057, 1.0433, 0.83654, 0.847178, 0.890027, 0.920814, - 0.888271, 1.04662, 0.8869, 0.856348, 0.863181, 0.906312, 0.902166, - 1.00122, 1.03303, 0.887866, 0.892437, 0.906278, 0.884976, 0.864251, - 0.917221, 1.10618, 1.04028, 0.893184, 0.915734, 0.892676}; - // calibration T0C - static constexpr float kCalibT0C[28] = { - 0.949829, 1.05408, 1.00681, 1.00724, 0.990663, 0.973571, 0.9855, - 1.03726, 1.02526, 1.00467, 0.983008, 0.979349, 0.952352, 0.985775, - 1.013, 1.01721, 0.993948, 0.996421, 0.971871, 1.02921, 0.989641, - 1.01885, 1.01259, 0.929502, 1.03969, 1.02496, 1.01385, 1.01711}; - // calibration T0A - static constexpr float kCalibT0A[24] = { - 0.86041, 1.10607, 1.17724, 0.756397, 1.14954, 1.0879, - 0.829438, 1.09014, 1.16515, 0.730077, 1.06722, 0.906344, - 0.824167, 1.14716, 1.20692, 0.755034, 1.11734, 1.00556, - 0.790522, 1.09138, 1.16225, 0.692458, 1.12428, 1.01127}; - // calibration factor MFT vs vtx - static constexpr float kBiningVtxt[30] = { - -14.5, -13.5, -12.5, -11.5, -10.5, -9.5, -8.5, -7.5, -6.5, -5.5, - -4.5, -3.5, -2.5, -1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, - 5.5, 6.5, 7.5, 8.5, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5}; - - // calibration factor FV0 vs vtx - static constexpr float kCalibFV0vtx[30] = { - 0.907962, 0.934607, 0.938929, 0.950987, 0.950817, 0.966362, - 0.968509, 0.972741, 0.982412, 0.984872, 0.994543, 0.996003, - 0.99435, 1.00266, 0.998245, 1.00584, 1.01078, 1.01003, - 1.00726, 1.00872, 1.01726, 1.02015, 1.0193, 1.01106, - 1.02229, 1.02104, 1.03435, 1.00822, 1.01921, 1.01736}; - // calibration FT0A vs vtx - static constexpr float kCalibFT0Avtx[30] = { - 0.924334, 0.950988, 0.959604, 0.965607, 0.970016, 0.979057, - 0.978384, 0.982005, 0.992825, 0.990048, 0.998588, 0.997338, - 1.00102, 1.00385, 0.99492, 1.01083, 1.00703, 1.00494, - 1.00063, 1.0013, 1.00777, 1.01238, 1.01179, 1.00577, - 1.01028, 1.017, 1.02975, 1.0085, 1.00856, 1.01662}; - // calibration FT0C vs vtx - static constexpr float kCalibFT0Cvtx[30] = { - 1.02096, 1.01245, 1.02148, 1.03605, 1.03561, 1.03667, - 1.04229, 1.0327, 1.03674, 1.02764, 1.01828, 1.02331, - 1.01864, 1.015, 1.01197, 1.00615, 0.996845, 0.993051, - 0.985635, 0.982883, 0.981914, 0.964635, 0.967812, 0.95475, - 0.956687, 0.932816, 0.92773, 0.914892, 0.891724, 0.872382}; + // occupied cells of a flattenicity lattice + template + static int countActiveCells(TArray const& lattice) + { + int nActive = 0; + for (const auto& cell : lattice) { + if (cell > 0.f) { + nActive++; + } + } + return nActive; + } static constexpr int kNeta5 = 2; // FT0C + FT0A - static constexpr float kWeigthsEta5[kNeta5] = {0.0490638, 0.010958415}; - static constexpr float kDeltaEeta5[kNeta5] = {1.1, 1.2}; + static constexpr std::array kWeigthsEta5 = {0.0490638, 0.010958415}; + static constexpr std::array kDeltaEeta5 = {1.1, 1.2}; static constexpr int kNeta6 = 2; // FT0C + FV0 - static constexpr float kWeigthsEta6[kNeta6] = {0.0490638, 0.00353962}; - static constexpr float kDeltaEeta6[kNeta6] = {1.1, 2.9}; + static constexpr std::array kWeigthsEta6 = {0.0490638, 0.00353962}; + static constexpr std::array kDeltaEeta6 = {1.1, 2.9}; static constexpr int kInnerFV0 = 32; static constexpr float kMaxEtaFV0 = 5.1; static constexpr float kMinEtaFV0 = 2.2; static constexpr float kDetaFV0 = (kMaxEtaFV0 - kMinEtaFV0) / 5.0; - static constexpr int kNCells = 48; // 48 sectors in FV0 - std::array rhoLattice; - std::array rhoLatticeFV0AMC; - std::array ampchannel; - std::array ampchannelBefore; - static constexpr int kNCellsT0A = 24; - std::array rhoLatticeT0A; - static constexpr int kNCellsT0C = 28; - std::array rhoLatticeT0C; - - std::array estimator; + // 1-rho not available for this collision + static constexpr float kInvalidFlattenicity = -1.f; + // lattice carries no signal, sigma/ undefined + static constexpr float kFlatUndefined = 9999.f; + static constexpr int kNCells = 48; // 48 sectors in FV0 + static constexpr std::array kFV0PhiIndex = { + 0, 1, 2, 3, 7, 6, 5, 4, + 8, 9, 10, 11, 15, 14, 13, 12, + 16, 17, 18, 19, 23, 22, 21, 20, + 24, 25, 26, 27, 31, 30, 29, 28, + 32, 34, 36, 38, 47, 45, 43, 41, + 33, 35, 37, 39, 46, 44, 42, 40}; + std::array rhoLattice{}; + std::array rhoLatticeFV0AMC{}; + std::array ampchannel{}; + std::array ampchannelBefore{}; + std::array rhoLatticeT0A{}; + std::array rhoLatticeT0C{}; + std::array rhoLatticeFT0AMC{}; + std::array rhoLatticeFT0CMC{}; + static constexpr int kNChannelsFT0 = kNChannelsFT0A + kNChannelsFT0C; + + // Generator-level FT0 lattice: detector cell counts and acceptance. The real + // channel map is not an eta-phi grid, so cell shapes are approximate. + static constexpr float kMinEtaFT0A = 3.5f; + static constexpr float kMaxEtaFT0A = 4.9f; + static constexpr float kMinEtaFT0C = -3.3f; + static constexpr float kMaxEtaFT0C = -2.1f; + static constexpr int kNEtaBinsFT0MC = 4; + static constexpr int kNPhiBinsFT0AMC = kNChannelsFT0A / kNEtaBinsFT0MC; + static constexpr int kNPhiBinsFT0CMC = kNChannelsFT0C / kNEtaBinsFT0MC; + + std::array estimator{}; + + // fillCounter=false runs the same cuts without filling hEventsSelected template - bool isEventSelected(TCollision const& collision) + bool isEventSelected(TCollision const& collision, bool fillCounter = true) { float nbinev = 0.5; - rEventSelection.fill(HIST("hEventsSelected"), nbinev); + if (fillCounter) { + rEventSelection.fill(HIST("hEventsSelected"), nbinev); + } - if (issel8 && !collision.sel8()) { + if (evSel.issel8 && !collision.sel8()) { return false; } - if (issel8) { + if (evSel.issel8) { nbinev++; - rEventSelection.fill(HIST("hEventsSelected"), nbinev); + if (fillCounter) { + rEventSelection.fill(HIST("hEventsSelected"), nbinev); + } } - if (std::abs(collision.posZ()) > cutzvertex) { + if (std::abs(collision.posZ()) > evSel.cutzvertex) { return false; } nbinev++; - rEventSelection.fill(HIST("hEventsSelected"), nbinev); + if (fillCounter) { + rEventSelection.fill(HIST("hEventsSelected"), nbinev); + } - if (isNoTimeFrameBorder && + if (evSel.isNoTimeFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { return false; } - if (isNoTimeFrameBorder) { + if (evSel.isNoTimeFrameBorder) { nbinev++; - rEventSelection.fill(HIST("hEventsSelected"), nbinev); + if (fillCounter) { + rEventSelection.fill(HIST("hEventsSelected"), nbinev); + } } - if (isNoITSROFrameBorder && + if (evSel.isNoITSROFrameBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { return false; } - if (isNoITSROFrameBorder) { + if (evSel.isNoITSROFrameBorder) { nbinev++; - rEventSelection.fill(HIST("hEventsSelected"), nbinev); + if (fillCounter) { + rEventSelection.fill(HIST("hEventsSelected"), nbinev); + } } - if (isVertexITSTPC && + if (evSel.isVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { return false; } - if (isVertexITSTPC) { + if (evSel.isVertexITSTPC) { nbinev++; - rEventSelection.fill(HIST("hEventsSelected"), nbinev); + if (fillCounter) { + rEventSelection.fill(HIST("hEventsSelected"), nbinev); + } } - if (isNoSameBunchPileup && + if (evSel.isNoSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { return false; } - if (isNoSameBunchPileup) { + if (evSel.isNoSameBunchPileup) { nbinev++; - rEventSelection.fill(HIST("hEventsSelected"), nbinev); + if (fillCounter) { + rEventSelection.fill(HIST("hEventsSelected"), nbinev); + } } - if (isGoodZvtxFT0vsPV && + if (evSel.isGoodZvtxFT0vsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { return false; } - if (isGoodZvtxFT0vsPV) { + if (evSel.isGoodZvtxFT0vsPV) { nbinev++; - rEventSelection.fill(HIST("hEventsSelected"), nbinev); + if (fillCounter) { + rEventSelection.fill(HIST("hEventsSelected"), nbinev); + } } - if (isTriggerTVX && + if (evSel.isTriggerTVX && !collision.selection_bit(o2::aod::evsel::kIsTriggerTVX)) { return false; } - if (isTriggerTVX) { + if (evSel.isTriggerTVX) { nbinev++; - rEventSelection.fill(HIST("hEventsSelected"), nbinev); + if (fillCounter) { + rEventSelection.fill(HIST("hEventsSelected"), nbinev); + } } - if (isINELgt0 && (collision.isInelGt0() == false)) { + if (eventClass.applyCentSel && (collision.centFT0M() < eventClass.cfgCentMin || collision.centFT0M() > eventClass.cfgCentMax)) { return false; } - if (isINELgt0) { + + if (evSel.isINELgt0 && (collision.isInelGt0() == false)) { + return false; + } + if (evSel.isINELgt0) { nbinev++; - rEventSelection.fill(HIST("hEventsSelected"), nbinev); + if (fillCounter) { + rEventSelection.fill(HIST("hEventsSelected"), nbinev); + } } return true; } - // ============== Flattenicity estimation begins ===================== // - template - float estimateFlattenicity(TCollision const& collision, Tracks const& tracks) + // Daughter track acceptance and quality. The quality cuts are off by default + // and exist so a systematic variation can move them from the JSON. + template + bool isSelectedDaughterTrack(TTrack const& track, float minCrossedRows) + { + if (std::abs(track.eta()) > trkPid.cfgTrkEtaCut || track.pt() < trkPid.cfgTrkLowPtCut) { + return false; + } + if (track.tpcNClsCrossedRows() < minCrossedRows) { + return false; + } + if (trkPid.minCrossedRowsOverFindable > 0.f && + track.tpcCrossedRowsOverFindableCls() < trkPid.minCrossedRowsOverFindable) { + return false; + } + if (trkPid.maxTpcChi2NCl > 0.f && track.tpcChi2NCl() > trkPid.maxTpcChi2NCl) { + return false; + } + if (trkPid.maxItsChi2NCl > 0.f && track.itsChi2NCl() > trkPid.maxItsChi2NCl) { + return false; + } + if (trkPid.minItsNCls > 0 && static_cast(track.itsNCls()) < trkPid.minItsNCls) { + return false; + } + return true; + } + + // cut-flow bins for the stages inside estimateFlattenicity(); without these + // the events it drops leave no trace + void fillFlattenicityStages() + { + if (nbinFlatDetHit > 0 && flatStage >= kFlatStageLowOccupancy) { + rEventSelection.fill(HIST("hEventsSelected"), nbinFlatDetHit - 0.5); + } + if (nbinFlatOccupancy > 0 && flatStage >= kFlatStageNoSignal) { + rEventSelection.fill(HIST("hEventsSelected"), nbinFlatOccupancy - 0.5); + } + if (nbinFlattenicity > 0 && flatStage == kFlatStageOk) { + rEventSelection.fill(HIST("hEventsSelected"), nbinFlattenicity - 0.5); + } + } + + // 1-rho on the fine axis for the percentile boundaries, inclusive, INEL>0 and + // in the top FT0M class + void fillFlatDistRec(float flattenicity, float centFT0M, bool isInelGt0) + { + rEventSelection.fill(HIST("hFlatDistRec"), flattenicity); + rEventSelection.fill(HIST("hCentFT0MFine"), centFT0M); + if (isInelGt0) { + rEventSelection.fill(HIST("hFlatDistRecINELgt0"), flattenicity); + if (centFT0M < eventClass.cfgCentMaxHM) { + rEventSelection.fill(HIST("hFlatDistRecHM"), flattenicity); + } + } + } + + // processGenMC only. A negative centFT0M means no accepted reconstructed + // counterpart, so the collision has no FT0M class and stays out of the HM one. + void fillFlatDistGen(float flattenicityGen, float centFT0M, bool isInelGt0) { - const int nDetVtx = 3; - TGraph* gVtx[nDetVtx]; - const char* nameDet[nDetVtx] = {"AmpV0", "AmpT0A", "AmpT0C"}; + rEventSelection.fill(HIST("hFlatDistGen"), flattenicityGen); + if (isInelGt0) { + rEventSelection.fill(HIST("hFlatDistGenINELgt0"), flattenicityGen); + if (centFT0M >= 0.f && centFT0M < eventClass.cfgCentMaxHM) { + rEventSelection.fill(HIST("hFlatDistGenHM"), flattenicityGen); + } + } + } - float ampl5[kNeta5] = {0, 0}; - float ampl6[kNeta6] = {0, 0}; + // the same from the rec-level process functions, diagnostic only + void fillFlatDistGenInRec(float flattenicityGen, float centFT0M, bool isInelGt0) + { + rEventSelection.fill(HIST("hFlatDistGenInRec"), flattenicityGen); + if (isInelGt0) { + rEventSelection.fill(HIST("hFlatDistGenInRecINELgt0"), flattenicityGen); + if (centFT0M >= 0.f && centFT0M < eventClass.cfgCentMaxHM) { + rEventSelection.fill(HIST("hFlatDistGenInRecHM"), flattenicityGen); + } + } + } - for (int i_d = 0; i_d < nDetVtx; ++i_d) { - gVtx[i_d] = 0; - gVtx[i_d] = new TGraph(); + // Charged tracks in the tracking acceptance: per class is the + // scale factor of Qpp, and the DCAxy distribution carries the secondary + // contamination. + template + int fillChargedRec(TTracks const& tracks, float flattenicity) + { + if (!eventClass.fillChargedQA) { + return 0; } - for (int i_v = 0; i_v < 30; ++i_v) { - gVtx[0]->SetPoint(i_v, kBiningVtxt[i_v], kCalibFV0vtx[i_v]); + int nch = 0; + for (const auto& track : tracks) { + if (!track.isGlobalTrack() || std::abs(track.eta()) > eventClass.cfgEtaChargedCut) { + continue; + } + nch++; + rCharged.fill(HIST("hPtChVsFlat"), track.pt(), flattenicity); + if constexpr (isMC) { + if (!track.has_mcParticle()) { + continue; + } + const auto& mcParticle = track.mcParticle(); + if (mcParticle.isPhysicalPrimary()) { + rCharged.fill(HIST("hPtChVsFlatRecPrim"), track.pt(), flattenicity); + rCharged.fill(HIST("hDcaXyPtChPrim"), track.dcaXY(), track.pt(), flattenicity); + } else { + rCharged.fill(HIST("hDcaXyPtChSec"), track.dcaXY(), track.pt(), flattenicity); + } + } else { + rCharged.fill(HIST("hDcaXyPtCh"), track.dcaXY(), track.pt(), flattenicity); + } } - for (int i_v = 0; i_v < 30; ++i_v) { - gVtx[1]->SetPoint(i_v, kBiningVtxt[i_v], kCalibFT0Avtx[i_v]); + rCharged.fill(HIST("hNchVsFlat"), nch, flattenicity); + return nch; + } + + template + int fillChargedGen(TMcParticles const& mcParticles, float flattenicity, bool trueFlat) + { + if (!eventClass.fillChargedQA) { + return 0; } - for (int i_v = 0; i_v < 30; ++i_v) { - gVtx[2]->SetPoint(i_v, kBiningVtxt[i_v], kCalibFT0Cvtx[i_v]); + int nch = 0; + for (const auto& mcParticle : mcParticles) { + if (!mcParticle.isPhysicalPrimary() || std::abs(mcParticle.eta()) > eventClass.cfgEtaChargedCut) { + continue; + } + auto pdgParticle = pdg->GetParticle(mcParticle.pdgCode()); + if (!(pdgParticle && std::abs(pdgParticle->Charge()) > kMinCharge)) { + continue; + } + nch++; + if (trueFlat) { + rCharged.fill(HIST("hPtChVsTrueFlatGen"), mcParticle.pt(), flattenicity); + } else { + rCharged.fill(HIST("hPtChVsFlatGen"), mcParticle.pt(), flattenicity); + } + } + if (trueFlat) { + rCharged.fill(HIST("hNchVsTrueFlatGen"), nch, flattenicity); + } else { + rCharged.fill(HIST("hNchVsFlatGen"), nch, flattenicity); + } + return nch; + } + + // ================= Calibration objects from CCDB ==================== // + // A missing or malformed object falls back to unity, so a run without + // calibration is left uncorrected instead of being equalized with somebody + // else's constants. + + std::vector fetchGainEq(const std::string& path, int run, std::size_t nChannels) + { + const auto* obj = ccdb->getForRun>(path, run); + if (!obj || obj->size() != nChannels) { + LOGF(warning, "No gain equalization of size %zu at %s for run %d, using unity", + nChannels, path.c_str(), run); + return std::vector(nChannels, 1.f); + } + return *obj; + } + + TProfile2D* fetchVtxEq(const std::string& path, int run) + { + auto* obj = ccdb->getForRun(path, run); + if (!obj) { + LOGF(warning, "No z-vertex equalization at %s for run %d, lattice left uncorrected", + path.c_str(), run); } + return obj; + } - for (int i_d = 0; i_d < nDetVtx; ++i_d) { - gVtx[i_d]->SetName(Form("g%s", nameDet[i_d])); + // called per collision, does nothing unless a correction is switched on + template + void initCcdb(TBC const& bc) + { + const int run = bc.runNumber(); + if (run == mRunNumber) { + return; } + mRunNumber = run; + if (flatSel.applyCalibCh) { + gainFV0 = fetchGainEq(ccdbConf.gainEqPath.value + "/FV0", run, kNCells); + gainFT0A = fetchGainEq(ccdbConf.gainEqPath.value + "/FT0A", run, kNSectorsT0A); + gainFT0C = fetchGainEq(ccdbConf.gainEqPath.value + "/FT0C", run, kNSectorsT0C); + } + if (flatSel.applyCalibVtx) { + vtxEqFV0 = fetchVtxEq(ccdbConf.vtxEqPath.value + "/FV0", run); + vtxEqFT0A = fetchVtxEq(ccdbConf.vtxEqPath.value + "/FT0A", run); + vtxEqFT0C = fetchVtxEq(ccdbConf.vtxEqPath.value + "/FT0C", run); + } + } + + // the gain is divided out, the convention of flattenictyPikp + static float gainEqFactor(std::vector const& gain, std::size_t channel) + { + if (channel >= gain.size() || !(gain[channel] > 0.f)) { + return 1.f; + } + return gain[channel]; + } + + // 1 for a missing map or an empty bin, so a bad bin never zeroes a cell + static float vtxEqFactor(TProfile2D const* map, int cell, float vtxZ) + { + if (!map) { + return 1.f; + } + const float factor = map->GetBinContent(map->GetXaxis()->FindBin(cell), + map->GetYaxis()->FindBin(vtxZ)); + return (factor > 0.f) ? factor : 1.f; + } + + // ============== Flattenicity estimation begins ===================== // + // fillQA=false skips the QA registry, for callers that would fill it twice + template + float estimateFlattenicity(TCollision const& collision, Tracks const& tracks, bool fillQA = true) + { + const bool flattenicityQAhere = flatSel.flattenicityQA && fillQA; + flatStage = kFlatStageNoDetector; + // a detector contributes only if it has a record and the config reads it + const bool hasFV0 = collision.has_foundFV0(); + const bool hasFT0 = collision.has_foundFT0(); + const bool fv0Read = flatSel.isflattenicitywithFV0 && hasFV0; + const bool ft0Read = flatSel.isflattenicitywithFT0 && hasFT0; + if (flatSel.applyCalibCh || flatSel.applyCalibVtx) { + initCcdb(collision.template bc_as>()); + } + std::array ampl5 = {0, 0}; + std::array ampl6 = {0, 0}; + auto vtxZ = collision.posZ(); float sumAmpFV0 = 0; float sumAmpFV01to4Ch = 0; + // gain-equalized but not yet vertex-equalized, the input to the z-vertex QA + float sumAmpFV0BeforeVtx = 0; ampchannel.fill(0.0); ampchannelBefore.fill(0.0); rhoLattice.fill(0); - if ((isflattenicitywithFV0 || isflattenicitywithFV0FT0C) && - collision.has_foundFV0()) { + if (fv0Read) { auto fv0 = collision.foundFV0(); for (std::size_t ich = 0; ich < fv0.amplitude().size(); ich++) { @@ -988,15 +1510,19 @@ struct Lambdak0sflattenicity { phiv0 = ((2.0 * channelv0phi) + 1 - 64.0) * constants::math::TwoPI / (32.0); } ampchannelBefore[channelv0phi] = amplCh; - if (applyCalibCh) { - amplCh *= kCalib[channelv0phi]; + if (flatSel.applyCalibCh) { + amplCh /= gainEqFactor(gainFV0, channelv0); + } + sumAmpFV0BeforeVtx += amplCh; + if (flatSel.applyCalibVtx) { + amplCh *= vtxEqFactor(vtxEqFV0, channelv0phi, vtxZ); } sumAmpFV0 += amplCh; - if (channelv0 >= 8) { // exclude the 1st ch, eta 2.2,4.52 + if (channelv0 >= kNChannelsPerFV0Ring) { // exclude the 1st ring, eta 2.2,4.52 sumAmpFV01to4Ch += amplCh; } - if (flattenicityQA) { + if (flattenicityQAhere) { rFlattenicity.fill(HIST("fEtaPhiFv0"), phiv0, etav0, amplCh); } ampchannel[channelv0phi] = amplCh; @@ -1007,20 +1533,14 @@ struct Lambdak0sflattenicity { } } - if (flattenicityQA) { - rFlattenicity.fill(HIST("hAmpV0vsVtxBeforeCalibration"), vtxZ, sumAmpFV0); - } - if (applyCalibVtx) { - sumAmpFV0 *= gVtx[0]->Eval(vtxZ); - sumAmpFV01to4Ch *= gVtx[0]->Eval(vtxZ); - } - if (flattenicityQA) { + if (flattenicityQAhere) { + rFlattenicity.fill(HIST("hAmpV0vsVtxBeforeCalibration"), vtxZ, sumAmpFV0BeforeVtx); rFlattenicity.fill(HIST("hAmpV0vsVtx"), vtxZ, sumAmpFV0); } } - float flattenicityfv0 = 9999; - if (isflattenicitywithFV0 || isflattenicitywithFV0FT0C) { + float flattenicityfv0 = kFlatUndefined; + if (fv0Read) { flattenicityfv0 = getFlatenicity({rhoLattice.data(), rhoLattice.size()}); } @@ -1040,82 +1560,106 @@ struct Lambdak0sflattenicity { // FT0 float sumAmpFT0A = 0.f; float sumAmpFT0C = 0.f; + int nActiveFT0Ch = 0; + float sumAmpFT0ABeforeVtx = 0.f; + float sumAmpFT0CBeforeVtx = 0.f; rhoLatticeT0A.fill(0); rhoLatticeT0C.fill(0); - if ((isflattenicitywithFT0 || isflattenicitywithFV0FT0C) && - collision.has_foundFT0()) { + if (ft0Read) { auto ft0 = collision.foundFT0(); - if (isflattenicitywithFT0) { - for (std::size_t i_a = 0; i_a < ft0.amplitudeA().size(); i_a++) { - float amplitude = ft0.amplitudeA()[i_a]; - uint8_t channel = ft0.channelA()[i_a]; - int sector = getT0ASector(channel); - if (sector >= 0 && sector < 24) { - rhoLatticeT0A[sector] += amplitude; - if (flattenicityQA) { - rFlattenicity.fill(HIST("hAmpT0AVsChBeforeCalibration"), sector, - amplitude); - } - if (applyCalibCh) { - amplitude *= kCalibT0A[sector]; - } - if (flattenicityQA) { - rFlattenicity.fill(HIST("hAmpT0AVsCh"), sector, amplitude); - } + for (std::size_t i_a = 0; i_a < ft0.amplitudeA().size(); i_a++) { + float amplitude = ft0.amplitudeA()[i_a]; + const int channel = ft0.channelA()[i_a]; + if (amplitude > 0.f) { + nActiveFT0Ch++; + } + const int sector = getT0ASector(channel); + float amplitudeBeforeVtx = amplitude; + if (channel >= 0 && channel < kNChannelsFT0A && sector >= 0) { + if (flattenicityQAhere) { + rFlattenicity.fill(HIST("hAmpT0AVsChBeforeCalibration"), sector, + amplitude); + } + if (flatSel.applyCalibCh) { + amplitude /= gainEqFactor(gainFT0A, sector); + } + if (flattenicityQAhere) { + rFlattenicity.fill(HIST("hAmpT0AVsCh"), sector, amplitude); } - sumAmpFT0A += amplitude; - if (flattenicityQA) { - rFlattenicity.fill(HIST("hFT0A"), amplitude); + amplitudeBeforeVtx = amplitude; + if (flatSel.applyCalibVtx) { + amplitude *= vtxEqFactor(vtxEqFT0A, sector, vtxZ); } + rhoLatticeT0A[channel] += amplitude; + } + sumAmpFT0A += amplitude; + sumAmpFT0ABeforeVtx += amplitudeBeforeVtx; + if (flattenicityQAhere) { + rFlattenicity.fill(HIST("hFT0A"), amplitude); } } for (std::size_t i_c = 0; i_c < ft0.amplitudeC().size(); i_c++) { float amplitude = ft0.amplitudeC()[i_c]; - sumAmpFT0C += amplitude; - uint8_t channel = ft0.channelC()[i_c]; - int sector = getT0CSector(channel); - if (sector >= 0 && sector < 28) { - rhoLatticeT0C[sector] += amplitude; - if (flattenicityQA) { + const int channel = ft0.channelC()[i_c]; + if (amplitude > 0.f) { + nActiveFT0Ch++; + } + const int sector = getT0CSector(channel); + float amplitudeBeforeVtx = amplitude; + if (channel >= 0 && channel < kNChannelsFT0C && sector >= 0) { + if (flattenicityQAhere) { rFlattenicity.fill(HIST("hAmpT0CVsChBeforeCalibration"), sector, amplitude); } - if (applyCalibCh) { - amplitude *= kCalibT0C[sector]; + if (flatSel.applyCalibCh) { + amplitude /= gainEqFactor(gainFT0C, sector); } - if (flattenicityQA) { + if (flattenicityQAhere) { rFlattenicity.fill(HIST("hAmpT0CVsCh"), sector, amplitude); } + amplitudeBeforeVtx = amplitude; + if (flatSel.applyCalibVtx) { + amplitude *= vtxEqFactor(vtxEqFT0C, sector, vtxZ); + } + rhoLatticeT0C[channel] += amplitude; } - if (flattenicityQA) { + sumAmpFT0C += amplitude; + sumAmpFT0CBeforeVtx += amplitudeBeforeVtx; + if (flattenicityQAhere) { rFlattenicity.fill(HIST("hFT0C"), amplitude); } } - if (flattenicityQA) { + if (flattenicityQAhere) { rFlattenicity.fill(HIST("hAmpT0AvsVtxBeforeCalibration"), vtxZ, - sumAmpFT0A); + sumAmpFT0ABeforeVtx); rFlattenicity.fill(HIST("hAmpT0CvsVtxBeforeCalibration"), vtxZ, - sumAmpFT0C); - } - if (applyCalibVtx) { - sumAmpFT0A *= gVtx[1]->Eval(vtxZ); - sumAmpFT0C *= gVtx[2]->Eval(vtxZ); - } - if (flattenicityQA) { + sumAmpFT0CBeforeVtx); rFlattenicity.fill(HIST("hAmpT0AvsVtx"), vtxZ, sumAmpFT0A); rFlattenicity.fill(HIST("hAmpT0CvsVtx"), vtxZ, sumAmpFT0C); } } - float flatenicityT0a = 9999; - if (isflattenicitywithFT0) { + const int nLitFV0 = countActiveCells(rhoLattice); + const int nLitFT0A = countActiveCells(rhoLatticeT0A); + const int nLitFT0C = countActiveCells(rhoLatticeT0C); + if (flattenicityQAhere) { + if (fv0Read) { + rFlattenicity.fill(HIST("hNActiveCellsFV0"), nLitFV0); + } + if (ft0Read) { + rFlattenicity.fill(HIST("hNActiveFT0Channels"), nActiveFT0Ch); + rFlattenicity.fill(HIST("hNActiveCellsFT0A"), nLitFT0A); + rFlattenicity.fill(HIST("hNActiveCellsFT0C"), nLitFT0C); + } + } + + float flatenicityT0a = kFlatUndefined; + float flatenicityT0c = kFlatUndefined; + if (ft0Read) { flatenicityT0a = getFlatenicity({rhoLatticeT0A.data(), rhoLatticeT0A.size()}); - } - float flatenicityT0c = 9999; - if (isflattenicitywithFT0 || isflattenicitywithFV0FT0C) { flatenicityT0c = getFlatenicity({rhoLatticeT0C.data(), rhoLatticeT0C.size()}); } @@ -1125,163 +1669,241 @@ struct Lambdak0sflattenicity { float combinedEstimator5 = 0; float combinedEstimator6 = 0; - for (int iEe = 0; iEe < 8; ++iEe) { + for (int iEe = 0; iEe < kNEstimators; ++iEe) { estimator[iEe] = 0; } - if (collision.has_foundFV0() && collision.has_foundFT0()) { - float allWeights = 0; - // option 5 - ampl5[0] = sumAmpFT0C; - ampl5[1] = sumAmpFT0A; - if (sumAmpFT0C > 0 && sumAmpFT0A > 0) { - isOKEstimator5 = true; - } - if (isOKEstimator5) { - if (applyNorm) { - allWeights = 0; - for (int i5 = 0; i5 < kNeta5; ++i5) { - combinedEstimator5 += - ampl5[i5] * kWeigthsEta5[i5] / kDeltaEeta5[i5]; - allWeights += kWeigthsEta5[i5]; - } - combinedEstimator5 /= allWeights; - } else { - for (int i5 = 0; i5 < kNeta5; ++i5) { - combinedEstimator5 += ampl5[i5] * kWeigthsEta5[i5]; - } + // FV0 and FT0 are missing on different collisions, so require only the + // detector the selected estimator reads + const bool detectorsOk = + (flatSel.flattenicityforanalysis == kFlatFromFT0) ? hasFT0 : hasFV0; + if (!detectorsOk) { + return kInvalidFlattenicity; + } + flatStage = kFlatStageLowOccupancy; + + // Reject a lattice too sparse for sigma/ to be continuous. Only the one + // the analysis estimator reads is tested; the other still fills QA. + const bool occupancyOk = + (flatSel.flattenicityforanalysis == kFlatFromFT0) + ? (nLitFT0A >= flatSel.minLitCellsFT0A && nLitFT0C >= flatSel.minLitCellsFT0C) + : (nLitFV0 >= flatSel.minLitCellsFV0); + if (!occupancyOk) { + return kInvalidFlattenicity; + } + flatStage = kFlatStageNoSignal; + + // an estimator with an unread detector holds a sentinel, keep it out of the QA + const bool estFV0Ok = fv0Read; + const bool estFT0Ok = ft0Read; + const bool estFV0FT0COk = fv0Read && ft0Read; + + float allWeights = 0; + // option 5 + ampl5[0] = sumAmpFT0C; + ampl5[1] = sumAmpFT0A; + if (sumAmpFT0C > 0 && sumAmpFT0A > 0) { + isOKEstimator5 = true; + } + if (isOKEstimator5) { + if (flatSel.applyNorm) { + allWeights = 0; + for (int i5 = 0; i5 < kNeta5; ++i5) { + combinedEstimator5 += + ampl5[i5] * kWeigthsEta5[i5] / kDeltaEeta5[i5]; + allWeights += kWeigthsEta5[i5]; + } + combinedEstimator5 /= allWeights; + } else { + for (int i5 = 0; i5 < kNeta5; ++i5) { + combinedEstimator5 += ampl5[i5] * kWeigthsEta5[i5]; } } - // option 6: FT0C + FV0 - ampl6[0] = sumAmpFT0C; - ampl6[1] = sumAmpFV0; - if (sumAmpFT0C > 0 && sumAmpFV0 > 0) { - isOKEstimator6 = true; - } - if (isOKEstimator6) { - if (applyNorm) { - allWeights = 0; - for (int i6 = 0; i6 < kNeta6; ++i6) { - combinedEstimator6 += - ampl6[i6] * kWeigthsEta6[i6] / kDeltaEeta6[i6]; - allWeights += kWeigthsEta6[i6]; - } - combinedEstimator6 /= allWeights; - } else { - for (int i6 = 0; i6 < kNeta6; ++i6) { - combinedEstimator6 += ampl6[i6] * kWeigthsEta6[i6]; - } + } + // option 6: FT0C + FV0 + ampl6[0] = sumAmpFT0C; + ampl6[1] = sumAmpFV0; + if (sumAmpFT0C > 0 && sumAmpFV0 > 0) { + isOKEstimator6 = true; + } + if (isOKEstimator6) { + if (flatSel.applyNorm) { + allWeights = 0; + for (int i6 = 0; i6 < kNeta6; ++i6) { + combinedEstimator6 += + ampl6[i6] * kWeigthsEta6[i6] / kDeltaEeta6[i6]; + allWeights += kWeigthsEta6[i6]; + } + combinedEstimator6 /= allWeights; + } else { + for (int i6 = 0; i6 < kNeta6; ++i6) { + combinedEstimator6 += ampl6[i6] * kWeigthsEta6[i6]; } } - if (flattenicityQA) { + } + if (flattenicityQAhere) { + if (ft0Read) { rFlattenicity.fill(HIST("hFT0Aampl"), sumAmpFT0A); rFlattenicity.fill(HIST("hFT0Campl"), sumAmpFT0C); + } + if (fv0Read) { rFlattenicity.fill(HIST("hFV0amplRing1to4"), sumAmpFV01to4Ch); - rFlattenicity.fill(HIST("hEv"), 4); - } - estimator[0] = multGlob; - estimator[1] = sumAmpFV0; - estimator[2] = 1.0 - flattenicityfv0; - estimator[3] = combinedEstimator5; - float flatenicityFT0 = (flatenicityT0a + flatenicityT0c) / 2.0; - estimator[4] = 1.0 - flatenicityFT0; - estimator[5] = combinedEstimator6; - float flatenicityFT0v0 = 0.5 * flattenicityfv0 + 0.5 * flatenicityT0c; - estimator[6] = 1.0 - flatenicityFT0v0; - estimator[7] = ptT; - if (flattenicityQA) { - rFlattenicity.fill(HIST(kHEst[0]), estimator[0], estimator[0]); + } + rFlattenicity.fill(HIST("hEv"), 4); + } + estimator[0] = multGlob; + estimator[1] = sumAmpFV0; + estimator[2] = 1.0 - flattenicityfv0; + estimator[3] = combinedEstimator5; + float flatenicityFT0 = (flatenicityT0a + flatenicityT0c) / 2.0; + estimator[4] = 1.0 - flatenicityFT0; + estimator[5] = combinedEstimator6; + estimator[6] = ptT; + if (flattenicityQAhere) { + rFlattenicity.fill(HIST(kHEst[0]), estimator[0], estimator[0]); + rFlattenicity.fill(HIST(kHEst[6]), estimator[6], estimator[0]); + if (estFV0Ok) { rFlattenicity.fill(HIST(kHEst[1]), estimator[1], estimator[0]); rFlattenicity.fill(HIST(kHEst[2]), estimator[2], estimator[0]); + } + if (estFT0Ok) { rFlattenicity.fill(HIST(kHEst[3]), estimator[3], estimator[0]); rFlattenicity.fill(HIST(kHEst[4]), estimator[4], estimator[0]); + } + if (estFV0FT0COk) { rFlattenicity.fill(HIST(kHEst[5]), estimator[5], estimator[0]); - rFlattenicity.fill(HIST(kHEst[6]), estimator[6], estimator[0]); - rFlattenicity.fill(HIST(kHEst[7]), estimator[7], estimator[0]); + } - // plot pt vs estimators - for (const auto& track : tracks) { - if (!track.isGlobalTrack()) { - continue; - } - float pt = track.pt(); - rFlattenicity.fill(HIST(kHPtEst[0]), estimator[0], pt); + // plot pt vs estimators + for (const auto& track : tracks) { + if (!track.isGlobalTrack()) { + continue; + } + float pt = track.pt(); + rFlattenicity.fill(HIST(kHPtEst[0]), estimator[0], pt); + rFlattenicity.fill(HIST(kHPtEst[6]), estimator[6], pt); + if (estFV0Ok) { rFlattenicity.fill(HIST(kHPtEst[1]), estimator[1], pt); rFlattenicity.fill(HIST(kHPtEst[2]), estimator[2], pt); + } + if (estFT0Ok) { rFlattenicity.fill(HIST(kHPtEst[3]), estimator[3], pt); rFlattenicity.fill(HIST(kHPtEst[4]), estimator[4], pt); + } + if (estFV0FT0COk) { rFlattenicity.fill(HIST(kHPtEst[5]), estimator[5], pt); - rFlattenicity.fill(HIST(kHPtEst[6]), estimator[6], pt); - rFlattenicity.fill(HIST(kHPtEst[7]), estimator[7], pt); } + } - if (isflattenicitywithFV0) { - for (int iCh = 0; iCh < 48; ++iCh) { - rFlattenicity.fill(HIST("hAmpV0VsCh"), iCh, ampchannel[iCh]); - rFlattenicity.fill(HIST("hAmpV0VsChBeforeCalibration"), iCh, - ampchannelBefore[iCh]); - } + if (estFV0Ok) { + for (int iCh = 0; iCh < kNCells; ++iCh) { + rFlattenicity.fill(HIST("hAmpV0VsCh"), iCh, ampchannel[iCh]); + rFlattenicity.fill(HIST("hAmpV0VsChBeforeCalibration"), iCh, + ampchannelBefore[iCh]); } - rFlattenicity.fill(HIST("fMultFv0"), sumAmpFV0); + } + if (estFT0Ok) { rFlattenicity.fill(HIST("hFlatFT0CvsFlatFT0A"), flatenicityT0c, flatenicityT0a); } } float finalflattenicity = estimator[2]; - rFlattenicity.fill(HIST("hFV0amplvsFlat"), sumAmpFV0, estimator[2]); + if (flattenicityQAhere && estFV0Ok) { + rFlattenicity.fill(HIST("hFV0amplvsFlat"), sumAmpFV0, estimator[2]); + } - if (flattenicityforanalysis == 1) { + if (flatSel.flattenicityforanalysis == kFlatFromFT0) { finalflattenicity = estimator[4]; } - if (flattenicityforanalysis == 2) { - finalflattenicity = estimator[6]; + // a lattice with no signal leaves a sentinel, which the callers reject as negative + if (finalflattenicity >= 0.f) { + flatStage = kFlatStageOk; } return finalflattenicity; } + // which weak decay produced a non-primary candidate, bins of hFeedDown*MotherPdg + static constexpr int kFdXiMinus = 0; + static constexpr int kFdXiZero = 1; + static constexpr int kFdOmegaMinus = 2; + static constexpr int kFdOther = 3; + static constexpr int kNFeedDownMothers = 4; + + // -1 for a species that does not feed the measured hadrons + static int feedDownSpecies(int pdgCode) + { + switch (std::abs(pdgCode)) { + case PDG_t::kXiMinus: + return kFdXiMinus; + case o2::constants::physics::Pdg::kXi0: + return kFdXiZero; + case PDG_t::kOmegaMinus: + return kFdOmegaMinus; + default: + return -1; + } + } + + template + int getFeedDownMother(TMcParticle const& mcParticle, float& motherPt) + { + motherPt = -1.f; + if (!mcParticle.has_mothers()) { + return kFdOther; + } + for (const auto& mother : mcParticle.template mothers_as()) { + motherPt = mother.pt(); + const int species = feedDownSpecies(mother.pdgCode()); + return (species >= 0) ? species : kFdOther; + } + return kFdOther; + } + + // fillQA=false skips hTrueFV0amplvsFlat, for callers that would fill it twice template - float estimateFlattenicityFV0MC(McParticles const& mcParticles) + float estimateFlattenicityFV0MC(McParticles const& mcParticles, bool fillQA = true) { rhoLatticeFV0AMC.fill(0); - float flattenicity = -1; - float etamin, etamax, minphi, maxphi, dphi; - int isegment = 0, nsectors; int multFV0 = 0; for (const auto& mcParticle : mcParticles) { - if (!(mcParticle.isPhysicalPrimary() && mcParticle.pt() > 0)) { + // the measured 1-rho also sees secondaries; dropping the primary + // requirement is the handle on the leading MC non-closure source + if (eventClass.genFlatPrimariesOnly && !mcParticle.isPhysicalPrimary()) { + continue; + } + if (!(mcParticle.pt() > 0)) { continue; } auto pdgParticle = pdg->GetParticle(mcParticle.pdgCode()); - if (!(pdgParticle && pdgParticle->Charge() > 0.01)) { + if (!(pdgParticle && std::abs(pdgParticle->Charge()) > kMinCharge)) { continue; } - float etap = mcParticle.eta(); - float phip = mcParticle.phi(); - isegment = 0; - - for (int ieta = 0; ieta < 5; ieta++) { - etamax = kMaxEtaFV0 - ieta * kDetaFV0; - if (ieta == 0) { - etamax = kMaxEtaFV0; - } - etamin = kMaxEtaFV0 - (ieta + 1) * kDetaFV0; - if (ieta == 4) { - etamin = kMinEtaFV0; - } - nsectors = 8; - if (ieta == 4) { - nsectors = 16; - } + const float etap = mcParticle.eta(); + const float phip = mcParticle.phi(); + int isegment = 0; + + for (int ieta = 0; ieta < kNFV0EtaRings; ieta++) { + // the outer ring ends exactly at kMinEtaFV0, the rest follow from the ring width + const float etamax = kMaxEtaFV0 - ieta * kDetaFV0; + const float etamin = (ieta == kOuterFV0RingIndex) ? kMinEtaFV0 + : kMaxEtaFV0 - (ieta + 1) * kDetaFV0; + const int nsectors = (ieta == kOuterFV0RingIndex) ? kNSectorsFV0OuterRing + : kNChannelsPerFV0Ring; for (int iphi = 0; iphi < nsectors; iphi++) { - minphi = iphi * constants::math::TwoPI / nsectors; - maxphi = (iphi + 1) * constants::math::TwoPI / nsectors; - dphi = std::abs(maxphi - minphi); + const float minphi = iphi * constants::math::TwoPI / nsectors; + const float maxphi = (iphi + 1) * constants::math::TwoPI / nsectors; + const float dphi = std::abs(maxphi - minphi); if (etap >= etamin && etap < etamax && phip >= minphi && phip < maxphi) { - rhoLatticeFV0AMC[isegment] += 1.0 / std::abs(dphi * kDetaFV0); + // yield per cell with the outer ring halved, as the amplitude is in + // estimateFlattenicity; the alternative normalises to the cell area + rhoLatticeFV0AMC[isegment] += + flatSel.genFlatDetectorLikeNorm + ? ((ieta == kOuterFV0RingIndex) ? 0.5f : 1.0f) + : 1.0 / std::abs(dphi * kDetaFV0); multFV0++; } isegment++; @@ -1289,37 +1911,121 @@ struct Lambdak0sflattenicity { } } - flattenicity = - 1.0 - getFlatenicity({rhoLatticeFV0AMC.data(), rhoLatticeFV0AMC.size()}); - rEventSelection.fill(HIST("hTrueFV0amplvsFlat"), multFV0, estimator[2]); + const float flatFV0 = + getFlatenicity({rhoLatticeFV0AMC.data(), rhoLatticeFV0AMC.size()}); + if (flatFV0 >= kFlatUndefined) { + return kInvalidFlattenicity; + } + const float flattenicity = 1.0 - flatFV0; + if (fillQA) { + rEventSelection.fill(HIST("hTrueFV0amplvsFlat"), multFV0, flattenicity); + } return flattenicity; } + + // Generated counterpart of the FT0 branch of estimateFlattenicity(): same cell + // counts, same average of the two rho. Weights are uniform and a per-side + // constant cancels in sigma/, so genFlatDetectorLikeNorm does not apply. + template + float estimateFlattenicityFT0MC(McParticles const& mcParticles, bool fillQA = true) + { + rhoLatticeFT0AMC.fill(0); + rhoLatticeFT0CMC.fill(0); + int multFT0 = 0; + + const float detaFT0A = (kMaxEtaFT0A - kMinEtaFT0A) / kNEtaBinsFT0MC; + const float detaFT0C = (kMaxEtaFT0C - kMinEtaFT0C) / kNEtaBinsFT0MC; + + for (const auto& mcParticle : mcParticles) { + if (eventClass.genFlatPrimariesOnly && !mcParticle.isPhysicalPrimary()) { + continue; + } + if (!(mcParticle.pt() > 0)) { + continue; + } + auto pdgParticle = pdg->GetParticle(mcParticle.pdgCode()); + if (!(pdgParticle && std::abs(pdgParticle->Charge()) > kMinCharge)) { + continue; + } + + const float etap = mcParticle.eta(); + const float phip = mcParticle.phi(); + const bool inA = (etap >= kMinEtaFT0A && etap < kMaxEtaFT0A); + const bool inC = (etap >= kMinEtaFT0C && etap < kMaxEtaFT0C); + if (!inA && !inC) { + continue; + } + + const int nphi = inA ? kNPhiBinsFT0AMC : kNPhiBinsFT0CMC; + const float eta0 = inA ? kMinEtaFT0A : kMinEtaFT0C; + const float deta = inA ? detaFT0A : detaFT0C; + int ieta = static_cast((etap - eta0) / deta); + int iphi = static_cast(phip * nphi / constants::math::TwoPI); + ieta = std::clamp(ieta, 0, kNEtaBinsFT0MC - 1); + iphi = std::clamp(iphi, 0, nphi - 1); + const int icell = ieta * nphi + iphi; + + if (inA) { + rhoLatticeFT0AMC[icell] += 1.f; + } else { + rhoLatticeFT0CMC[icell] += 1.f; + } + multFT0++; + } + + const float flatA = + getFlatenicity({rhoLatticeFT0AMC.data(), rhoLatticeFT0AMC.size()}); + const float flatC = + getFlatenicity({rhoLatticeFT0CMC.data(), rhoLatticeFT0CMC.size()}); + // in pp one side can be left completely empty, and the average is then undefined + if (flatA >= kFlatUndefined || flatC >= kFlatUndefined) { + return kInvalidFlattenicity; + } + const float flattenicity = 1.0 - (flatA + flatC) / 2.0; + if (fillQA) { + rEventSelection.fill(HIST("hTrueFT0amplvsFlat"), multFT0, flattenicity); + rEventSelection.fill(HIST("hNActiveCellsFT0AMCGen"), countActiveCells(rhoLatticeFT0AMC)); + rEventSelection.fill(HIST("hNActiveCellsFT0CMCGen"), countActiveCells(rhoLatticeFT0CMC)); + } + return flattenicity; + } + + // the generator-level counterpart of whichever estimator the analysis uses + template + float estimateFlattenicityGen(McParticles const& mcParticles, bool fillQA = true) + { + if (flatSel.flattenicityforanalysis == kFlatFromFT0) { + return estimateFlattenicityFT0MC(mcParticles, fillQA); + } + return estimateFlattenicityFV0MC(mcParticles, fillQA); + } // ====================== Flattenicity estimation ends ===================== // Filters on V0s // Cannot filter on dynamic columns, so we cut on DCA to PV and DCA between // daughters only - Filter preFilterV0 = (nabs(aod::v0data::dcapostopv) > v0settingDCApostopv && - nabs(aod::v0data::dcanegtopv) > v0settingDCAnegtopv && - aod::v0data::dcaV0daughters < v0settingDCAv0dau); + Filter preFilterV0 = (nabs(aod::v0data::dcapostopv) > v0Sel.v0settingDCApostopv && + nabs(aod::v0data::dcanegtopv) > v0Sel.v0settingDCAnegtopv && + aod::v0data::dcaV0daughters < v0Sel.v0settingDCAv0dau); Filter trackFilter = - (nabs(aod::track::eta) < cfgTrkEtaCut && aod::track::pt > cfgTrkLowPtCut); + (nabs(aod::track::eta) < trkPid.cfgTrkEtaCut && aod::track::pt > trkPid.cfgTrkLowPtCut); using TrackCandidates = soa::Filtered< soa::Join>; + aod::TrackSelection, aod::pidTPCFullPi, aod::pidTPCFullPr>>; void processDataRun3LambdaK0s( - soa::Join::iterator const& collision, soa::Filtered const& V0s, TrackCandidates const& tracks, soa::Join const& /*bcs*/, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0s*/) { - if (applyEvSel && - !(isEventSelected(collision))) { // Checking if the event passes the - // selection criteria + const bool own = (eventHistOwner == kOwnerDataV0); + if (evSel.applyEvSel && + !(isEventSelected(collision, own))) { // Checking if the event passes the + // selection criteria return; } @@ -1328,18 +2034,28 @@ struct Lambdak0sflattenicity { auto vtxX = collision.posX(); float flattenicity = estimateFlattenicity(collision, tracks); + if (own) { + fillFlattenicityStages(); + } + if (flattenicity < 0.f) { + return; + } + if (own) { - rEventSelection.fill(HIST("hVertexZ"), vtxZ); - rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); + rEventSelection.fill(HIST("hVertexZ"), vtxZ); + rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); + rEventSelection.fill(HIST("hCentFT0M"), collision.centFT0M()); + rEventSelection.fill(HIST("hCentFT0MvsFlattenicity"), collision.centFT0M(), flattenicity); + fillFlatDistRec(flattenicity, collision.centFT0M(), collision.isInelGt0()); + fillChargedRec(tracks, flattenicity); + } for (const auto& v0 : V0s) { const auto& posDaughterTrack = v0.posTrack_as(); const auto& negDaughterTrack = v0.negTrack_as(); - if (std::abs(posDaughterTrack.eta()) > cfgTrkEtaCut || - std::abs(negDaughterTrack.eta()) > cfgTrkEtaCut || - negDaughterTrack.pt() < cfgTrkLowPtCut || - posDaughterTrack.pt() < cfgTrkLowPtCut) { + if (!isSelectedDaughterTrack(posDaughterTrack, v0Sel.v0settingNTPCcrossedRows) || + !isSelectedDaughterTrack(negDaughterTrack, v0Sel.v0settingNTPCcrossedRows)) { continue; } float massK0s = v0.mK0Short(); @@ -1359,9 +2075,9 @@ struct Lambdak0sflattenicity { std::pow(decayvtxZ - vtxZ, 2)); float v0p = std::sqrt(v0.pt() * v0.pt() + v0.pz() * v0.pz()); - float ctauK0s = decaylength * massK0s / v0p; - float ctauLambda = decaylength * massLambda / v0p; - float ctauAntiLambda = decaylength * massAntiLambda / v0p; + float ctauK0s = decaylength * o2::constants::physics::MassK0Short / v0p; + // same PDG mass for Lambda and AntiLambda + float ctauLambda = decaylength * o2::constants::physics::MassLambda0 / v0p; float alpha = v0.alpha(); float qtarm = v0.qtarm(); @@ -1369,16 +2085,16 @@ struct Lambdak0sflattenicity { // Cut on dynamic columns for K0s rCommonHist.fill(HIST("hArmPodoAlphavsQT"), alpha, qtarm); - if (v0.v0cosPA() >= v0settingCosPAK0s && - v0.v0radius() >= v0settingRadiusK0s && - std::abs(posDaughterTrack.tpcNSigmaPi()) <= nSigmaTPCPion && - std::abs(negDaughterTrack.tpcNSigmaPi()) <= nSigmaTPCPion && - ctauK0s < v0settingcTauK0s && - std::abs(v0.rapidity(0)) <= v0settingRapidity && - std::abs(massLambda - pdgmassLambda) > v0settingMassRejectionK0s && - std::abs(massAntiLambda - pdgmassLambda) > - v0settingMassRejectionK0s && - qtarm > v0settingArmePodoK0s * std::abs(alpha)) { + if (v0.v0cosPA() >= v0Sel.v0settingCosPAK0s && + v0.v0radius() >= v0Sel.v0settingRadiusK0s && + std::abs(posDaughterTrack.tpcNSigmaPi()) <= trkPid.nSigmaTPCPion && + std::abs(negDaughterTrack.tpcNSigmaPi()) <= trkPid.nSigmaTPCPion && + ctauK0s < v0Sel.v0settingcTauK0s && + std::abs(v0.rapidity(0)) <= v0Sel.v0settingRapidity && + std::abs(massLambda - o2::constants::physics::MassLambda0) > v0Sel.v0settingMassRejectionK0s && + std::abs(massAntiLambda - o2::constants::physics::MassLambda0) > + v0Sel.v0settingMassRejectionK0s && + qtarm > v0Sel.v0settingArmePodoK0s * std::abs(alpha)) { rKzeroShort.fill(HIST("hMassK0sSelected"), massK0s); rKzeroShort.fill(HIST("hDCAV0DaughtersK0s"), v0.dcaV0daughters()); @@ -1391,7 +2107,7 @@ struct Lambdak0sflattenicity { rKzeroShort.fill(HIST("hArmPodoAlphavsQTK0sAfterCut"), alpha, qtarm); // Filling the PID of the V0 daughters in the region of the K0s peak - if (0.45 < massK0s && massK0s < 0.55) { + if (std::abs(massK0s - o2::constants::physics::MassK0Short) < trkPid.pidQAWindowK0s) { rKzeroShort.fill(HIST("hNSigmaPosPionFromK0s"), posDaughterTrack.tpcNSigmaPi(), posDaughterTrack.tpcInnerParam()); @@ -1402,13 +2118,13 @@ struct Lambdak0sflattenicity { } // Cut on dynamic columns for Lambda - if (v0.v0cosPA() >= v0settingCosPALambda && - v0.v0radius() >= v0settingRadiusLambda && - std::abs(posDaughterTrack.tpcNSigmaPr()) <= nSigmaTPCProton && - std::abs(negDaughterTrack.tpcNSigmaPi()) <= nSigmaTPCPion && - ctauLambda < v0settingcTauLambda && - std::abs(v0.rapidity(1)) <= v0settingRapidity && - std::abs(massK0s - pdgmassK0s) > v0settingMassRejectionLambda) { + if (v0.v0cosPA() >= v0Sel.v0settingCosPALambda && + v0.v0radius() >= v0Sel.v0settingRadiusLambda && + std::abs(posDaughterTrack.tpcNSigmaPr()) <= trkPid.nSigmaTPCProton && + std::abs(negDaughterTrack.tpcNSigmaPi()) <= trkPid.nSigmaTPCPion && + ctauLambda < v0Sel.v0settingcTauLambda && + std::abs(v0.rapidity(1)) <= v0Sel.v0settingRapidity && + std::abs(massK0s - o2::constants::physics::MassK0Short) > v0Sel.v0settingMassRejectionLambda) { rLambda.fill(HIST("hMassLambdaSelected"), massLambda); rLambda.fill(HIST("hDCAV0DaughtersLambda"), v0.dcaV0daughters()); @@ -1418,10 +2134,11 @@ struct Lambdak0sflattenicity { rLambda.fill(HIST("h2DdecayRadiusLambda"), v0.v0radius()); rLambda.fill(HIST("hMassLambdapT"), massLambda, v0.pt()); rLambda.fill(HIST("hMassLambdapTFlat"), massLambda, v0.pt(), flattenicity); + rLambda.fill(HIST("hDcaV0ToPVLambda"), v0.dcav0topv(), v0.pt(), flattenicity); // Filling the PID of the V0 daughters in the region of the Lambda peak - if (1.015 < massLambda && massLambda < 1.215) { - rLambda.fill(HIST("hNSigmaPosPionFromLambda"), + if (std::abs(massLambda - o2::constants::physics::MassLambda0) < trkPid.pidQAWindowLambda) { + rLambda.fill(HIST("hNSigmaPosProtonFromLambda"), posDaughterTrack.tpcNSigmaPr(), posDaughterTrack.tpcInnerParam()); rLambda.fill(HIST("hNSigmaNegPionFromLambda"), @@ -1431,31 +2148,32 @@ struct Lambdak0sflattenicity { } // Cut on dynamic columns for AntiLambda - if (v0.v0cosPA() >= v0settingCosPALambda && - v0.v0radius() >= v0settingRadiusLambda && - std::abs(posDaughterTrack.tpcNSigmaPi()) <= nSigmaTPCPion && - std::abs(negDaughterTrack.tpcNSigmaPr()) <= nSigmaTPCProton && - ctauAntiLambda < v0settingcTauLambda && - std::abs(v0.rapidity(2)) <= v0settingRapidity && - std::abs(massK0s - pdgmassK0s) > v0settingMassRejectionLambda) { + if (v0.v0cosPA() >= v0Sel.v0settingCosPALambda && + v0.v0radius() >= v0Sel.v0settingRadiusLambda && + std::abs(posDaughterTrack.tpcNSigmaPi()) <= trkPid.nSigmaTPCPion && + std::abs(negDaughterTrack.tpcNSigmaPr()) <= trkPid.nSigmaTPCProton && + ctauLambda < v0Sel.v0settingcTauLambda && + std::abs(v0.rapidity(2)) <= v0Sel.v0settingRapidity && + std::abs(massK0s - o2::constants::physics::MassK0Short) > v0Sel.v0settingMassRejectionLambda) { rAntiLambda.fill(HIST("hMassAntiLambdaSelected"), massAntiLambda); rAntiLambda.fill(HIST("hDCAV0DaughtersAntiLambda"), v0.dcaV0daughters()); rAntiLambda.fill(HIST("hV0CosPAAntiLambda"), v0.v0cosPA()); rAntiLambda.fill(HIST("hrapidityAntiLambda"), v0.rapidity(2)); - rAntiLambda.fill(HIST("hctauAntiLambda"), ctauAntiLambda); + rAntiLambda.fill(HIST("hctauAntiLambda"), ctauLambda); rAntiLambda.fill(HIST("h2DdecayRadiusAntiLambda"), v0.v0radius()); rAntiLambda.fill(HIST("hMassAntiLambdapT"), massAntiLambda, v0.pt()); rAntiLambda.fill(HIST("hMassAntiLambdapTFlat"), massAntiLambda, v0.pt(), flattenicity); + rAntiLambda.fill(HIST("hDcaV0ToPVAntiLambda"), v0.dcav0topv(), v0.pt(), flattenicity); // Filling the PID of the V0 daughters in the region of the AntiLambda // peak - if (1.015 < massAntiLambda && massAntiLambda < 1.215) { + if (std::abs(massAntiLambda - o2::constants::physics::MassLambda0) < trkPid.pidQAWindowLambda) { rAntiLambda.fill(HIST("hNSigmaPosPionFromAntiLambda"), posDaughterTrack.tpcNSigmaPi(), posDaughterTrack.tpcInnerParam()); - rAntiLambda.fill(HIST("hNSigmaNegPionFromAntiLambda"), + rAntiLambda.fill(HIST("hNSigmaNegProtonFromAntiLambda"), negDaughterTrack.tpcNSigmaPr(), negDaughterTrack.tpcInnerParam()); } @@ -1465,24 +2183,31 @@ struct Lambdak0sflattenicity { using TrackCandidatesMC = soa::Filtered>; - Preslice>> perCol = aod::track::collisionId; + Preslice>> perCol = aod::v0data::collisionId; + Preslice perColTracksMC = aod::track::collisionId; + // needed by the sliceByCached calls below, else they throw "Disabled cache" Preslice perMCCol = aod::mcparticle::mcCollisionId; SliceCache cache1; void processRecMCLambdaK0s( - soa::Join const& collisions, soa::Filtered> const& V0s, aod::McCollisions const&, TrackCandidatesMC const& tracks, soa::Join const& /*bcs*/, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0s*/, aod::McParticles const& mcParticles) { + const bool own = (eventHistOwner == kOwnerRecMCV0); for (const auto& collision : collisions) { - if (applyEvSel && - !(isEventSelected(collision))) { // Checking if the event passes the - // selection criteria + if (evSel.applyEvSel && + !(isEventSelected(collision, own))) { // Checking if the event passes the + // selection criteria + continue; + } + + if (!collision.has_mcCollision()) { continue; } @@ -1490,23 +2215,43 @@ struct Lambdak0sflattenicity { auto vtxY = collision.posY(); auto vtxX = collision.posX(); - float flattenicity = estimateFlattenicity(collision, tracks); - - rEventSelection.fill(HIST("hVertexZ"), vtxZ); - rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); + auto tracksThisCollision = tracks.sliceBy(perColTracksMC, collision.globalIndex()); + float flattenicity = estimateFlattenicity(collision, tracksThisCollision); + if (own) { + fillFlattenicityStages(); + } + if (flattenicity < 0.f) { + continue; + } + if (own) { + + rEventSelection.fill(HIST("hVertexZ"), vtxZ); + rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); + rEventSelection.fill(HIST("hCentFT0M"), collision.centFT0M()); + rEventSelection.fill(HIST("hCentFT0MvsFlattenicity"), collision.centFT0M(), flattenicity); + fillFlatDistRec(flattenicity, collision.centFT0M(), collision.isInelGt0()); + fillChargedRec(tracksThisCollision, flattenicity); + } auto v0sThisCollision = V0s.sliceBy(perCol, collision.globalIndex()); const auto& mcCollision = collision.mcCollision_as(); + const auto particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache1); + const float flattenicityMCGen = estimateFlattenicityGen(particlesInCollision, own); + if (own) { + rEventSelection.fill(HIST("hFlattenicityDistributionMCGen_Rec"), flattenicityMCGen); + rEventSelection.fill(HIST("hFlattenicity_Corr_Gen_vs_Rec"), flattenicityMCGen, flattenicity); + rEventSelection.fill(HIST("hFlatGenVsRecFine"), flattenicityMCGen, flattenicity); + fillFlatDistGenInRec(flattenicityMCGen, collision.centFT0M(), collision.isInelGt0()); + } + for (const auto& v0 : v0sThisCollision) { const auto& posDaughterTrack = v0.posTrack_as(); const auto& negDaughterTrack = v0.negTrack_as(); - if (std::abs(posDaughterTrack.eta()) > cfgTrkEtaCut || - std::abs(negDaughterTrack.eta()) > cfgTrkEtaCut || - negDaughterTrack.pt() < cfgTrkLowPtCut || - posDaughterTrack.pt() < cfgTrkLowPtCut) { + if (!isSelectedDaughterTrack(posDaughterTrack, v0Sel.v0settingNTPCcrossedRows) || + !isSelectedDaughterTrack(negDaughterTrack, v0Sel.v0settingNTPCcrossedRows)) { continue; } @@ -1531,27 +2276,31 @@ struct Lambdak0sflattenicity { std::pow(decayvtxZ - vtxZ, 2)); float v0p = std::sqrt(v0.pt() * v0.pt() + v0.pz() * v0.pz()); - float ctauK0s = decaylength * massK0s / v0p; - float ctauLambda = decaylength * massLambda / v0p; - float ctauAntiLambda = decaylength * massAntiLambda / v0p; + float ctauK0s = decaylength * o2::constants::physics::MassK0Short / v0p; + // same PDG mass for Lambda and AntiLambda + float ctauLambda = decaylength * o2::constants::physics::MassLambda0 / v0p; float alpha = v0.alpha(); float qtarm = v0.qtarm(); rCommonHist.fill(HIST("hArmPodoAlphavsQT"), alpha, qtarm); auto v0mcParticle = v0.mcParticle(); + const bool isPrimaryV0 = v0mcParticle.isPhysicalPrimary(); + const bool keepForEfficiency = isPrimaryV0 || !eventClass.requirePrimaryMC; + float motherPt = -1.f; // Cut on dynamic columns for K0s - if (v0mcParticle.pdgCode() == PDG_t::kK0Short && v0.v0cosPA() >= v0settingCosPAK0s && - v0.v0radius() >= v0settingRadiusK0s && - std::abs(posDaughterTrack.tpcNSigmaPi()) <= nSigmaTPCPion && - std::abs(negDaughterTrack.tpcNSigmaPi()) <= nSigmaTPCPion && - ctauK0s < v0settingcTauK0s && - std::abs(v0.rapidity(0)) <= v0settingRapidity && - std::abs(massLambda - pdgmassLambda) > v0settingMassRejectionK0s && - std::abs(massAntiLambda - pdgmassLambda) > - v0settingMassRejectionK0s && - qtarm > v0settingArmePodoK0s * std::abs(alpha)) { + if (v0mcParticle.pdgCode() == PDG_t::kK0Short && keepForEfficiency && + v0.v0cosPA() >= v0Sel.v0settingCosPAK0s && + v0.v0radius() >= v0Sel.v0settingRadiusK0s && + std::abs(posDaughterTrack.tpcNSigmaPi()) <= trkPid.nSigmaTPCPion && + std::abs(negDaughterTrack.tpcNSigmaPi()) <= trkPid.nSigmaTPCPion && + ctauK0s < v0Sel.v0settingcTauK0s && + std::abs(v0.rapidity(0)) <= v0Sel.v0settingRapidity && + std::abs(massLambda - o2::constants::physics::MassLambda0) > v0Sel.v0settingMassRejectionK0s && + std::abs(massAntiLambda - o2::constants::physics::MassLambda0) > + v0Sel.v0settingMassRejectionK0s && + qtarm > v0Sel.v0settingArmePodoK0s * std::abs(alpha)) { rKzeroShort.fill(HIST("hMassK0sSelected"), massK0s); rKzeroShort.fill(HIST("hDCAV0DaughtersK0s"), v0.dcaV0daughters()); @@ -1561,10 +2310,13 @@ struct Lambdak0sflattenicity { rKzeroShort.fill(HIST("h2DdecayRadiusK0s"), v0.v0radius()); rKzeroShort.fill(HIST("hMassK0spT"), massK0s, v0.pt()); rKzeroShort.fill(HIST("hMassK0spTFlat"), massK0s, v0.pt(), flattenicity); + rKzeroShort.fill(HIST("hMassK0spTTrueFlat"), massK0s, v0.pt(), flattenicityMCGen); + rKzeroShort.fill(HIST("hPtResK0s"), v0mcParticle.pt(), + (v0.pt() - v0mcParticle.pt()) / v0mcParticle.pt()); rKzeroShort.fill(HIST("hArmPodoAlphavsQTK0sAfterCut"), alpha, qtarm); // Filling the PID of the V0 daughters in the region of the K0s peak - if (0.45 < massK0s && massK0s < 0.55) { + if (std::abs(massK0s - o2::constants::physics::MassK0Short) < trkPid.pidQAWindowK0s) { rKzeroShort.fill(HIST("hNSigmaPosPionFromK0s"), posDaughterTrack.tpcNSigmaPi(), posDaughterTrack.tpcInnerParam()); @@ -1576,114 +2328,189 @@ struct Lambdak0sflattenicity { // Cut on dynamic columns for Lambda if (v0mcParticle.pdgCode() == PDG_t::kLambda0 && - v0.v0cosPA() >= v0settingCosPALambda && - v0.v0radius() >= v0settingRadiusLambda && - std::abs(posDaughterTrack.tpcNSigmaPr()) <= nSigmaTPCProton && - std::abs(negDaughterTrack.tpcNSigmaPi()) <= nSigmaTPCPion && - ctauLambda < v0settingcTauLambda && - std::abs(v0.rapidity(1)) <= v0settingRapidity && - std::abs(massK0s - pdgmassK0s) > v0settingMassRejectionLambda) { - - rLambda.fill(HIST("hMassLambdaSelected"), massLambda); - rLambda.fill(HIST("hDCAV0DaughtersLambda"), v0.dcaV0daughters()); - rLambda.fill(HIST("hV0CosPALambda"), v0.v0cosPA()); - rLambda.fill(HIST("hrapidityLambda"), v0.rapidity(1)); - rLambda.fill(HIST("hctauLambda"), ctauLambda); - rLambda.fill(HIST("h2DdecayRadiusLambda"), v0.v0radius()); - rLambda.fill(HIST("hMassLambdapT"), massLambda, v0.pt()); - rLambda.fill(HIST("hMassLambdapTFlat"), massLambda, v0.pt(), flattenicity); - - // Filling the PID of the V0 daughters in the region of the Lambda peak - if (1.015 < massLambda && massLambda < 1.215) { - rLambda.fill(HIST("hNSigmaPosPionFromLambda"), - posDaughterTrack.tpcNSigmaPr(), - posDaughterTrack.tpcInnerParam()); - rLambda.fill(HIST("hNSigmaNegPionFromLambda"), - negDaughterTrack.tpcNSigmaPi(), - negDaughterTrack.tpcInnerParam()); + v0.v0cosPA() >= v0Sel.v0settingCosPALambda && + v0.v0radius() >= v0Sel.v0settingRadiusLambda && + std::abs(posDaughterTrack.tpcNSigmaPr()) <= trkPid.nSigmaTPCProton && + std::abs(negDaughterTrack.tpcNSigmaPi()) <= trkPid.nSigmaTPCPion && + ctauLambda < v0Sel.v0settingcTauLambda && + std::abs(v0.rapidity(1)) <= v0Sel.v0settingRapidity && + std::abs(massK0s - o2::constants::physics::MassK0Short) > v0Sel.v0settingMassRejectionLambda) { + + // secondaries kept out of the efficiency numerator, booked for the feed-down + if (!isPrimaryV0) { + const int motherIndex = getFeedDownMother(v0mcParticle, motherPt); + rLambda.fill(HIST("hMassFeedDownLambdapTFlat"), massLambda, v0.pt(), flattenicity); + rLambda.fill(HIST("hFeedDownLambdaPtVsMotherPt"), v0.pt(), motherPt); + rLambda.fill(HIST("hFeedDownLambdaMatrix"), v0.pt(), motherPt, flattenicity, motherIndex); + rLambda.fill(HIST("hFeedDownLambdaMotherPdg"), motherIndex); + rLambda.fill(HIST("hDcaV0ToPVLambdaSec"), v0.dcav0topv(), v0.pt(), flattenicity); + } else { + rLambda.fill(HIST("hDcaV0ToPVLambdaPrim"), v0.dcav0topv(), v0.pt(), flattenicity); + } + if (keepForEfficiency) { + + rLambda.fill(HIST("hMassLambdaSelected"), massLambda); + rLambda.fill(HIST("hDCAV0DaughtersLambda"), v0.dcaV0daughters()); + rLambda.fill(HIST("hV0CosPALambda"), v0.v0cosPA()); + rLambda.fill(HIST("hrapidityLambda"), v0.rapidity(1)); + rLambda.fill(HIST("hctauLambda"), ctauLambda); + rLambda.fill(HIST("h2DdecayRadiusLambda"), v0.v0radius()); + rLambda.fill(HIST("hMassLambdapT"), massLambda, v0.pt()); + rLambda.fill(HIST("hMassLambdapTFlat"), massLambda, v0.pt(), flattenicity); + rLambda.fill(HIST("hMassLambdapTTrueFlat"), massLambda, v0.pt(), flattenicityMCGen); + rLambda.fill(HIST("hDcaV0ToPVLambda"), v0.dcav0topv(), v0.pt(), flattenicity); + rLambda.fill(HIST("hPtResLambda"), v0mcParticle.pt(), + (v0.pt() - v0mcParticle.pt()) / v0mcParticle.pt()); + + // Filling the PID of the V0 daughters in the region of the Lambda peak + if (std::abs(massLambda - o2::constants::physics::MassLambda0) < trkPid.pidQAWindowLambda) { + rLambda.fill(HIST("hNSigmaPosProtonFromLambda"), + posDaughterTrack.tpcNSigmaPr(), + posDaughterTrack.tpcInnerParam()); + rLambda.fill(HIST("hNSigmaNegPionFromLambda"), + negDaughterTrack.tpcNSigmaPi(), + negDaughterTrack.tpcInnerParam()); + } } } // Cut on dynamic columns for AntiLambda if (v0mcParticle.pdgCode() == PDG_t::kLambda0Bar && - v0.v0cosPA() >= v0settingCosPALambda && - v0.v0radius() >= v0settingRadiusLambda && - std::abs(posDaughterTrack.tpcNSigmaPi()) <= nSigmaTPCPion && - std::abs(negDaughterTrack.tpcNSigmaPr()) <= nSigmaTPCProton && - ctauAntiLambda < v0settingcTauLambda && - std::abs(v0.rapidity(2)) <= v0settingRapidity && - std::abs(massK0s - pdgmassK0s) > v0settingMassRejectionLambda) { - - rAntiLambda.fill(HIST("hMassAntiLambdaSelected"), massAntiLambda); - rAntiLambda.fill(HIST("hDCAV0DaughtersAntiLambda"), - v0.dcaV0daughters()); - rAntiLambda.fill(HIST("hV0CosPAAntiLambda"), v0.v0cosPA()); - rAntiLambda.fill(HIST("hrapidityAntiLambda"), v0.rapidity(2)); - rAntiLambda.fill(HIST("hctauAntiLambda"), ctauAntiLambda); - rAntiLambda.fill(HIST("h2DdecayRadiusAntiLambda"), v0.v0radius()); - rAntiLambda.fill(HIST("hMassAntiLambdapT"), massAntiLambda, v0.pt()); - rAntiLambda.fill(HIST("hMassAntiLambdapTFlat"), massAntiLambda, v0.pt(), flattenicity); - - // Filling the PID of the V0 daughters in the region of the AntiLambda - // peak - if (1.015 < massAntiLambda && massAntiLambda < 1.215) { - rAntiLambda.fill(HIST("hNSigmaPosPionFromAntiLambda"), - posDaughterTrack.tpcNSigmaPi(), - posDaughterTrack.tpcInnerParam()); - rAntiLambda.fill(HIST("hNSigmaNegPionFromAntiLambda"), - negDaughterTrack.tpcNSigmaPr(), - negDaughterTrack.tpcInnerParam()); + v0.v0cosPA() >= v0Sel.v0settingCosPALambda && + v0.v0radius() >= v0Sel.v0settingRadiusLambda && + std::abs(posDaughterTrack.tpcNSigmaPi()) <= trkPid.nSigmaTPCPion && + std::abs(negDaughterTrack.tpcNSigmaPr()) <= trkPid.nSigmaTPCProton && + ctauLambda < v0Sel.v0settingcTauLambda && + std::abs(v0.rapidity(2)) <= v0Sel.v0settingRapidity && + std::abs(massK0s - o2::constants::physics::MassK0Short) > v0Sel.v0settingMassRejectionLambda) { + + // secondaries kept out of the efficiency numerator, booked for the feed-down + if (!isPrimaryV0) { + const int motherIndex = getFeedDownMother(v0mcParticle, motherPt); + rAntiLambda.fill(HIST("hMassFeedDownAntiLambdapTFlat"), massAntiLambda, v0.pt(), flattenicity); + rAntiLambda.fill(HIST("hFeedDownAntiLambdaPtVsMotherPt"), v0.pt(), motherPt); + rAntiLambda.fill(HIST("hFeedDownAntiLambdaMatrix"), v0.pt(), motherPt, flattenicity, motherIndex); + rAntiLambda.fill(HIST("hFeedDownAntiLambdaMotherPdg"), motherIndex); + rAntiLambda.fill(HIST("hDcaV0ToPVAntiLambdaSec"), v0.dcav0topv(), v0.pt(), flattenicity); + } else { + rAntiLambda.fill(HIST("hDcaV0ToPVAntiLambdaPrim"), v0.dcav0topv(), v0.pt(), flattenicity); + } + if (keepForEfficiency) { + + rAntiLambda.fill(HIST("hMassAntiLambdaSelected"), massAntiLambda); + rAntiLambda.fill(HIST("hDCAV0DaughtersAntiLambda"), + v0.dcaV0daughters()); + rAntiLambda.fill(HIST("hV0CosPAAntiLambda"), v0.v0cosPA()); + rAntiLambda.fill(HIST("hrapidityAntiLambda"), v0.rapidity(2)); + rAntiLambda.fill(HIST("hctauAntiLambda"), ctauLambda); + rAntiLambda.fill(HIST("h2DdecayRadiusAntiLambda"), v0.v0radius()); + rAntiLambda.fill(HIST("hMassAntiLambdapT"), massAntiLambda, v0.pt()); + rAntiLambda.fill(HIST("hMassAntiLambdapTFlat"), massAntiLambda, v0.pt(), flattenicity); + rAntiLambda.fill(HIST("hMassAntiLambdapTTrueFlat"), massAntiLambda, v0.pt(), flattenicityMCGen); + rAntiLambda.fill(HIST("hDcaV0ToPVAntiLambda"), v0.dcav0topv(), v0.pt(), flattenicity); + rAntiLambda.fill(HIST("hPtResAntiLambda"), v0mcParticle.pt(), + (v0.pt() - v0mcParticle.pt()) / v0mcParticle.pt()); + + // Filling the PID of the V0 daughters in the region of the AntiLambda + // peak + if (std::abs(massAntiLambda - o2::constants::physics::MassLambda0) < trkPid.pidQAWindowLambda) { + rAntiLambda.fill(HIST("hNSigmaPosPionFromAntiLambda"), + posDaughterTrack.tpcNSigmaPi(), + posDaughterTrack.tpcInnerParam()); + rAntiLambda.fill(HIST("hNSigmaNegProtonFromAntiLambda"), + negDaughterTrack.tpcNSigmaPr(), + negDaughterTrack.tpcInnerParam()); + } } } } - const auto particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache1); - float flattenicityMCGen = estimateFlattenicityFV0MC(particlesInCollision); - rEventSelection.fill(HIST("hFlattenicityDistributionMCGen_Rec"), flattenicityMCGen); - rEventSelection.fill(HIST("hFlattenicity_Corr_Gen_vs_Rec"), flattenicityMCGen, flattenicity); + const bool isInelGt0Rec = collision.isInelGt0(); + int nchGenInRec = 0; for (const auto& mcParticle : particlesInCollision) { if (!mcParticle.isPhysicalPrimary()) { continue; } - if (std::abs(mcParticle.y()) > 0.5f) { + if (eventClass.fillChargedQA && std::abs(mcParticle.eta()) <= eventClass.cfgEtaChargedCut) { + auto pdgParticle = pdg->GetParticle(mcParticle.pdgCode()); + if (pdgParticle && std::abs(pdgParticle->Charge()) > kMinCharge) { + nchGenInRec++; + rCharged.fill(HIST("hPtChVsFlatGenInRec"), mcParticle.pt(), flattenicity); + } + } + + // normalisation of hFeedDownLambdaMatrix, before the Lambda rapidity cut + if (std::abs(mcParticle.y()) <= eventClass.cfgFeedDownMotherRapidity) { + const int motherSpecies = feedDownSpecies(mcParticle.pdgCode()); + if (motherSpecies >= 0) { + rLambda.fill(HIST("hGenFeedDownMotherPtFlat"), mcParticle.pt(), flattenicity, motherSpecies); + } + } + + if (std::abs(mcParticle.y()) > v0Sel.v0settingRapidity) { continue; } if (mcParticle.pdgCode() == PDG_t::kK0Short) { - rKzeroShort.fill(HIST("Generated_MCRecoCollCheck_INEL_K0Short"), mcParticle.pt(), flattenicity); // K0s + rKzeroShort.fill(HIST("Generated_MCRecoCollCheck_INEL_K0Short"), mcParticle.pt(), flattenicity); + if (isInelGt0Rec) { + rKzeroShort.fill(HIST("Generated_MCRecoCollCheck_INELgt0_K0Short"), mcParticle.pt(), flattenicity); + rKzeroShort.fill(HIST("Generated_MCRecoCollCheck_INELgt0_K0Short_TrueFlat"), mcParticle.pt(), flattenicityMCGen); + } } if (mcParticle.pdgCode() == PDG_t::kLambda0) { - rLambda.fill(HIST("Generated_MCRecoCollCheck_INEL_Lambda"), mcParticle.pt(), flattenicity); // Lambda + rLambda.fill(HIST("Generated_MCRecoCollCheck_INEL_Lambda"), mcParticle.pt(), flattenicity); + if (isInelGt0Rec) { + rLambda.fill(HIST("Generated_MCRecoCollCheck_INELgt0_Lambda"), mcParticle.pt(), flattenicity); + rLambda.fill(HIST("Generated_MCRecoCollCheck_INELgt0_Lambda_TrueFlat"), mcParticle.pt(), flattenicityMCGen); + } } if (mcParticle.pdgCode() == PDG_t::kLambda0Bar) { - rAntiLambda.fill(HIST("Generated_MCRecoCollCheck_INEL_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + rAntiLambda.fill(HIST("Generated_MCRecoCollCheck_INEL_AntiLambda"), mcParticle.pt(), flattenicity); + if (isInelGt0Rec) { + rAntiLambda.fill(HIST("Generated_MCRecoCollCheck_INELgt0_AntiLambda"), mcParticle.pt(), flattenicity); + rAntiLambda.fill(HIST("Generated_MCRecoCollCheck_INELgt0_AntiLambda_TrueFlat"), mcParticle.pt(), flattenicityMCGen); + } } } + if (eventClass.fillChargedQA) { + rCharged.fill(HIST("hNchVsFlatGenInRec"), nchGenInRec, flattenicity); + } } } - // Filter posZFilterMC = (nabs(o2::aod::mccollision::posZ) < cutzvertex); + // Filter posZFilterMC = (nabs(o2::aod::mccollision::posZ) < evSel.cutzvertex); void processGenMC( - o2::aod::McCollision const& mcCollision, const soa::SmallGroups>& collisions, TrackCandidatesMC const& tracks, aod::FT0s const& /*ft0s*/, + o2::aod::McCollision const& mcCollision, const soa::SmallGroups>& collisions, TrackCandidatesMC const& tracks, + soa::Join const& /*bcs*/, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0s*/, o2::aod::McParticles const& mcParticles) { - float flattenicity; - if (flattenicityforLossCorrRec) { - float flattenicityRec = 999.0; - for (const auto& collision : collisions) { - flattenicityRec = estimateFlattenicity(collision, tracks); - // printf("FoundFlattenicity, Gen=%f, Rec=%f \n", flattenicity, flattenicityRec); + // Both estimates are always computed: the reconstructed one classifies the + // numerator of the closure, the true one its denominator. Without a + // reconstructed counterpart the sentinel is kept, it falls in the underflow + // so the loss counters stay complete. + float flattenicityRec = kInvalidFlattenicity; + float centFT0M = -1.f; + for (const auto& collision : collisions) { + if (evSel.applyEvSel && !isEventSelected(collision, false)) { + continue; + } + auto tracksThisCollision = tracks.sliceBy(perColTracksMC, collision.globalIndex()); + flattenicityRec = estimateFlattenicity(collision, tracksThisCollision, fillFlattenicityQAInGenMC); + if (flattenicityRec >= 0.f) { + centFT0M = collision.centFT0M(); + break; } - rEventSelection.fill(HIST("hFlattenicityDistributionRecMCGen"), flattenicityRec); - flattenicity = flattenicityRec; - } else { - float flattenicityGen = estimateFlattenicityFV0MC(mcParticles); - rEventSelection.fill(HIST("hFlattenicityDistributionMCGen"), flattenicityGen); - flattenicity = flattenicityGen; } + const float flattenicityTrue = estimateFlattenicityGen(mcParticles, fillFlattenicityQAInGenMC); + rEventSelection.fill(HIST("hFlattenicityDistributionRecMCGen"), flattenicityRec); + rEventSelection.fill(HIST("hFlattenicityDistributionMCGen"), flattenicityTrue); + + // which of the two drives the loss corrections written without a suffix + const float flattenicity = flatSel.flattenicityforLossCorrRec ? flattenicityRec : flattenicityTrue; //==================================== //===== Event Loss Denominator ======= @@ -1691,20 +2518,33 @@ struct Lambdak0sflattenicity { rEventSelection.fill(HIST("hNEventsMCGen"), 0.5); - if (std::abs(mcCollision.posZ()) > cutzvertex) { + if (std::abs(mcCollision.posZ()) > evSel.cutzvertex) { return; } rEventSelection.fill(HIST("hNEventsMCGen"), 1.5); + + // The FT0M class has no generator-level counterpart, so with a window + // requested the collision only belongs to it through an accepted + // reconstructed one, which is what leaves centFT0M non-negative above. + // Otherwise the generated denominators stay MB while the numerator is HM. + if (eventClass.applyCentSel && centFT0M < 0.f) { + return; + } + rEventSelection.fill(HIST("hFlat_GenColl_MC"), flattenicity); - bool isINELgt0true = false; + const bool isINELgt0true = pwglf::isINELgtNmc(mcParticles, 0, pdg); - if (pwglf::isINELgtNmc(mcParticles, 0, pdg)) { - isINELgt0true = true; + if (isINELgt0true) { rEventSelection.fill(HIST("hNEventsMCGen"), 2.5); rEventSelection.fill(HIST("hFlat_GenColl_MC_INELgt0"), flattenicity); + rEventSelection.fill(HIST("hFlat_GenColl_MC_INELgt0_TrueFlat"), flattenicityTrue); } + fillFlatDistGen(flattenicityTrue, centFT0M, isINELgt0true); + fillChargedGen(mcParticles, flattenicity, false); + fillChargedGen(mcParticles, flattenicityTrue, true); + //===================================== //===== Signal Loss Denominator ======= //===================================== @@ -1714,32 +2554,35 @@ struct Lambdak0sflattenicity { if (!mcParticle.isPhysicalPrimary()) { continue; } - if (std::abs(mcParticle.y()) > 0.5f) { - continue; - } + const bool inV0Rapidity = std::abs(mcParticle.y()) <= v0Sel.v0settingRapidity; + const bool inCascRapidity = std::abs(mcParticle.y()) <= cascSel.cascsettingRapidity; - if (mcParticle.pdgCode() == PDG_t::kK0Short) { - rKzeroShort.fill(HIST("pGen_MCGenColl_INEL_K0Short"), mcParticle.pt(), flattenicity); // K0s + if (inV0Rapidity && mcParticle.pdgCode() == PDG_t::kK0Short) { + rKzeroShort.fill(HIST("pGen_MCGenColl_INEL_K0Short"), mcParticle.pt(), flattenicity); if (isINELgt0true) { - rKzeroShort.fill(HIST("pGen_MCGenColl_INELgt0_K0Short"), mcParticle.pt(), flattenicity); // K0s + rKzeroShort.fill(HIST("pGen_MCGenColl_INELgt0_K0Short"), mcParticle.pt(), flattenicity); + rKzeroShort.fill(HIST("pGen_MCGenColl_INELgt0_K0Short_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } - if (mcParticle.pdgCode() == PDG_t::kLambda0) { - rLambda.fill(HIST("pGen_MCGenColl_INEL_Lambda"), mcParticle.pt(), flattenicity); // Lambda + if (inV0Rapidity && mcParticle.pdgCode() == PDG_t::kLambda0) { + rLambda.fill(HIST("pGen_MCGenColl_INEL_Lambda"), mcParticle.pt(), flattenicity); if (isINELgt0true) { - rLambda.fill(HIST("pGen_MCGenColl_INELgt0_Lambda"), mcParticle.pt(), flattenicity); // Lambda + rLambda.fill(HIST("pGen_MCGenColl_INELgt0_Lambda"), mcParticle.pt(), flattenicity); + rLambda.fill(HIST("pGen_MCGenColl_INELgt0_Lambda_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } - if (mcParticle.pdgCode() == PDG_t::kLambda0Bar) { - rAntiLambda.fill(HIST("pGen_MCGenColl_INEL_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + if (inV0Rapidity && mcParticle.pdgCode() == PDG_t::kLambda0Bar) { + rAntiLambda.fill(HIST("pGen_MCGenColl_INEL_AntiLambda"), mcParticle.pt(), flattenicity); if (isINELgt0true) { - rAntiLambda.fill(HIST("pGen_MCGenColl_INELgt0_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + rAntiLambda.fill(HIST("pGen_MCGenColl_INELgt0_AntiLambda"), mcParticle.pt(), flattenicity); + rAntiLambda.fill(HIST("pGen_MCGenColl_INELgt0_AntiLambda_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } - if (std::abs(mcParticle.pdgCode()) == PDG_t::kXiPlusBar) { - rXi.fill(HIST("pGen_MCGenColl_INEL_Xi"), mcParticle.pt(), flattenicity); // Xi + if (inCascRapidity && std::abs(mcParticle.pdgCode()) == PDG_t::kXiMinus) { + rXi.fill(HIST("pGen_MCGenColl_INEL_Xi"), mcParticle.pt(), flattenicity); if (isINELgt0true) { - rXi.fill(HIST("pGen_MCGenColl_INELgt0_Xi"), mcParticle.pt(), flattenicity); // Xi + rXi.fill(HIST("pGen_MCGenColl_INELgt0_Xi"), mcParticle.pt(), flattenicity); + rXi.fill(HIST("pGen_MCGenColl_INELgt0_Xi_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } } @@ -1753,7 +2596,11 @@ struct Lambdak0sflattenicity { //===================================== rEventSelection.fill(HIST("hNEventsMCReco"), 0.5); - if (applyEvSel && !isEventSelected(collision)) { + // the per-cut ladder of hEventsSelected belongs to the reconstructed-level + // process functions; filling it here as well would double count every + // collision whenever processGenMC runs alongside one of them, which is the + // normal MC configuration. hNEventsMCReco already records all/passed here. + if (evSel.applyEvSel && !isEventSelected(collision, false)) { continue; } rEventSelection.fill(HIST("hEventsSelected"), nbin - 0.5); @@ -1765,6 +2612,7 @@ struct Lambdak0sflattenicity { if (collision.isInelGt0() && isINELgt0true) { rEventSelection.fill(HIST("hNEventsMCReco"), 2.5); rEventSelection.fill(HIST("hFlat_RecoColl_MC_INELgt0"), flattenicity); + rEventSelection.fill(HIST("hFlat_RecoColl_MC_INELgt0_TrueFlat"), flattenicityTrue); recoCollIndexINELgt0++; } @@ -1778,33 +2626,35 @@ struct Lambdak0sflattenicity { if (!mcParticle.isPhysicalPrimary()) { continue; } + const bool inV0Rapidity = std::abs(mcParticle.y()) <= v0Sel.v0settingRapidity; + const bool inCascRapidity = std::abs(mcParticle.y()) <= cascSel.cascsettingRapidity; - if (std::abs(mcParticle.y()) > 0.5f) { - continue; - } - - if (mcParticle.pdgCode() == PDG_t::kK0Short) { - rKzeroShort.fill(HIST("Generated_MCRecoColl_INEL_K0Short"), mcParticle.pt(), flattenicity); // K0s + if (inV0Rapidity && mcParticle.pdgCode() == PDG_t::kK0Short) { + rKzeroShort.fill(HIST("Generated_MCRecoColl_INEL_K0Short"), mcParticle.pt(), flattenicity); if (recoCollIndexINELgt0 > 0) { - rKzeroShort.fill(HIST("Generated_MCRecoColl_INELgt0_K0Short"), mcParticle.pt(), flattenicity); // K0s + rKzeroShort.fill(HIST("Generated_MCRecoColl_INELgt0_K0Short"), mcParticle.pt(), flattenicity); + rKzeroShort.fill(HIST("Generated_MCRecoColl_INELgt0_K0Short_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } - if (mcParticle.pdgCode() == PDG_t::kLambda0) { - rLambda.fill(HIST("Generated_MCRecoColl_INEL_Lambda"), mcParticle.pt(), flattenicity); // Lambda + if (inV0Rapidity && mcParticle.pdgCode() == PDG_t::kLambda0) { + rLambda.fill(HIST("Generated_MCRecoColl_INEL_Lambda"), mcParticle.pt(), flattenicity); if (recoCollIndexINELgt0 > 0) { - rLambda.fill(HIST("Generated_MCRecoColl_INELgt0_Lambda"), mcParticle.pt(), flattenicity); // Lambda + rLambda.fill(HIST("Generated_MCRecoColl_INELgt0_Lambda"), mcParticle.pt(), flattenicity); + rLambda.fill(HIST("Generated_MCRecoColl_INELgt0_Lambda_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } - if (mcParticle.pdgCode() == PDG_t::kLambda0Bar) { - rAntiLambda.fill(HIST("Generated_MCRecoColl_INEL_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + if (inV0Rapidity && mcParticle.pdgCode() == PDG_t::kLambda0Bar) { + rAntiLambda.fill(HIST("Generated_MCRecoColl_INEL_AntiLambda"), mcParticle.pt(), flattenicity); if (recoCollIndexINELgt0 > 0) { - rAntiLambda.fill(HIST("Generated_MCRecoColl_INELgt0_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + rAntiLambda.fill(HIST("Generated_MCRecoColl_INELgt0_AntiLambda"), mcParticle.pt(), flattenicity); + rAntiLambda.fill(HIST("Generated_MCRecoColl_INELgt0_AntiLambda_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } - if (std::abs(mcParticle.pdgCode()) == PDG_t::kXiPlusBar) { - rXi.fill(HIST("Generated_MCRecoColl_INEL_Xi"), mcParticle.pt(), flattenicity); // Xi + if (inCascRapidity && std::abs(mcParticle.pdgCode()) == PDG_t::kXiMinus) { + rXi.fill(HIST("Generated_MCRecoColl_INEL_Xi"), mcParticle.pt(), flattenicity); if (recoCollIndexINELgt0 > 0) { - rXi.fill(HIST("Generated_MCRecoColl_INELgt0_Xi"), mcParticle.pt(), flattenicity); // Xi + rXi.fill(HIST("Generated_MCRecoColl_INELgt0_Xi"), mcParticle.pt(), flattenicity); + rXi.fill(HIST("Generated_MCRecoColl_INELgt0_Xi_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } } @@ -1825,6 +2675,7 @@ struct Lambdak0sflattenicity { if (recoCollIndexINELgt0 > 0) { rEventSelection.fill(HIST("hNEventsMCGenReco"), 1.5); rEventSelection.fill(HIST("hFlat_GenRecoColl_MC_INELgt0"), flattenicity); + rEventSelection.fill(HIST("hFlat_GenRecoColl_MC_INELgt0_TrueFlat"), flattenicityTrue); } //===================================== @@ -1836,54 +2687,117 @@ struct Lambdak0sflattenicity { if (!mcParticle.isPhysicalPrimary()) { continue; } + const bool inV0Rapidity = std::abs(mcParticle.y()) <= v0Sel.v0settingRapidity; + const bool inCascRapidity = std::abs(mcParticle.y()) <= cascSel.cascsettingRapidity; - if (std::abs(mcParticle.y()) > 0.5f) { - continue; - } - - if (mcParticle.pdgCode() == PDG_t::kK0Short) { - rKzeroShort.fill(HIST("pGen_MCGenRecoColl_INEL_K0Short"), mcParticle.pt(), flattenicity); // K0s + if (inV0Rapidity && mcParticle.pdgCode() == PDG_t::kK0Short) { + rKzeroShort.fill(HIST("pGen_MCGenRecoColl_INEL_K0Short"), mcParticle.pt(), flattenicity); if (recoCollIndexINELgt0 > 0) { - rKzeroShort.fill(HIST("pGen_MCGenRecoColl_INELgt0_K0Short"), mcParticle.pt(), flattenicity); // K0s + rKzeroShort.fill(HIST("pGen_MCGenRecoColl_INELgt0_K0Short"), mcParticle.pt(), flattenicity); + rKzeroShort.fill(HIST("pGen_MCGenRecoColl_INELgt0_K0Short_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } - if (mcParticle.pdgCode() == PDG_t::kLambda0) { - rLambda.fill(HIST("pGen_MCGenRecoColl_INEL_Lambda"), mcParticle.pt(), flattenicity); // Lambda + if (inV0Rapidity && mcParticle.pdgCode() == PDG_t::kLambda0) { + rLambda.fill(HIST("pGen_MCGenRecoColl_INEL_Lambda"), mcParticle.pt(), flattenicity); if (recoCollIndexINELgt0 > 0) { - rLambda.fill(HIST("pGen_MCGenRecoColl_INELgt0_Lambda"), mcParticle.pt(), flattenicity); // Lambda + rLambda.fill(HIST("pGen_MCGenRecoColl_INELgt0_Lambda"), mcParticle.pt(), flattenicity); + rLambda.fill(HIST("pGen_MCGenRecoColl_INELgt0_Lambda_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } - if (mcParticle.pdgCode() == PDG_t::kLambda0Bar) { - rAntiLambda.fill(HIST("pGen_MCGenRecoColl_INEL_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + if (inV0Rapidity && mcParticle.pdgCode() == PDG_t::kLambda0Bar) { + rAntiLambda.fill(HIST("pGen_MCGenRecoColl_INEL_AntiLambda"), mcParticle.pt(), flattenicity); if (recoCollIndexINELgt0 > 0) { - rAntiLambda.fill(HIST("pGen_MCGenRecoColl_INELgt0_AntiLambda"), mcParticle.pt(), flattenicity); // AntiLambda + rAntiLambda.fill(HIST("pGen_MCGenRecoColl_INELgt0_AntiLambda"), mcParticle.pt(), flattenicity); + rAntiLambda.fill(HIST("pGen_MCGenRecoColl_INELgt0_AntiLambda_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } - if (std::abs(mcParticle.pdgCode()) == PDG_t::kXiPlusBar) { - rXi.fill(HIST("pGen_MCGenRecoColl_INEL_Xi"), mcParticle.pt(), flattenicity); // Xi + if (inCascRapidity && std::abs(mcParticle.pdgCode()) == PDG_t::kXiMinus) { + rXi.fill(HIST("pGen_MCGenRecoColl_INEL_Xi"), mcParticle.pt(), flattenicity); if (recoCollIndexINELgt0 > 0) { - rXi.fill(HIST("pGen_MCGenRecoColl_INELgt0_Xi"), mcParticle.pt(), flattenicity); // Xi + rXi.fill(HIST("pGen_MCGenRecoColl_INELgt0_Xi"), mcParticle.pt(), flattenicity); + rXi.fill(HIST("pGen_MCGenRecoColl_INELgt0_Xi_TrueFlat"), mcParticle.pt(), flattenicityTrue); } } } } - TRandom2* fRand = new TRandom2(); // Cascade Analysis Starts here - using DauTracks = soa::Join; + using DauTracks = soa::Join; + using LabeledDauTracks = soa::Join; using LabeledCascades = soa::Join; - // float ctauxiPDG = 4.91; // from PDG - // float ctauomegaPDG = 2.461; // from PDG - void processDataRun3Cascade(soa::Join + bool isSelectedXi(TCollision const& collision, TCascade const& casc, + TTrack const& posDaughterTrack, TTrack const& negDaughterTrack, + TTrack const& bacDaughterTrack, float ctauXi) + { + const bool isXiMinus = casc.sign() < 0; + const auto& protonDaughter = isXiMinus ? posDaughterTrack : negDaughterTrack; + const auto& pionDaughter = isXiMinus ? negDaughterTrack : posDaughterTrack; + + // PID, one hypothesis per daughter + if (std::abs(protonDaughter.tpcNSigmaPr()) > trkPid.nSigmaTPCProton || + std::abs(pionDaughter.tpcNSigmaPi()) > trkPid.nSigmaTPCPion || + std::abs(bacDaughterTrack.tpcNSigmaPi()) > trkPid.nSigmaTPCPion) { + return false; + } + + // track quality + if (!isSelectedDaughterTrack(posDaughterTrack, cascSel.nTPCcrossedRows) || + !isSelectedDaughterTrack(negDaughterTrack, cascSel.nTPCcrossedRows) || + !isSelectedDaughterTrack(bacDaughterTrack, cascSel.nTPCcrossedRows)) { + return false; + } + + // topology + const float dcav0pv = casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()); + const float cosPAcasc = casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()); + const float cosPAv0 = casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); + + // DCA to PV per daughter role, not per charge + const float dcaBaryonToPV = isXiMinus ? casc.dcapostopv() : casc.dcanegtopv(); + const float dcaMesonToPV = isXiMinus ? casc.dcanegtopv() : casc.dcapostopv(); + + if (std::abs(dcaBaryonToPV) < cascSel.cascsettingDCAbaryontopv || std::abs(dcaMesonToPV) < cascSel.cascsettingDCAmesontopv || + std::abs(casc.dcabachtopv()) < v0Sel.v0settingDCAbactopv || casc.dcaV0daughters() > v0Sel.v0settingDCAv0dau || + dcav0pv < cascSel.cascsettingDCAv0toPV || casc.dcacascdaughters() > cascSel.cascsettingDCAv0bach) { + return false; + } + // bachelor-baryon veto + if (casc.bachBaryonCosPA() > cascSel.cascsettingCosPAbaryonbach || + std::abs(casc.bachBaryonDCAxyToPV()) < cascSel.cascsettingDCAxybaryonbach) { + return false; + } + if (cosPAcasc < cascSel.cascsettingCosPAcascPV || cosPAv0 < cascSel.cascsettingCosPAv0PV || + casc.cascradius() < cascSel.cascsettingcascradius || casc.v0radius() < cascSel.cascsettingv0radius) { + return false; + } + + // kinematics and competing species + if (std::abs(casc.yXi()) > cascSel.cascsettingRapidity || ctauXi > kCtauXi * cascSel.cascsettingproplifetime) { + return false; + } + if (std::abs(casc.mLambda() - o2::constants::physics::MassLambda0) > cascSel.cascsettingMassRejectionLambdaXi || + std::abs(casc.mOmega() - o2::constants::physics::MassOmegaMinus) < cascSel.cascsettingMassRejectioOmegaXi) { + return false; + } + + return true; + } + + void processDataRun3Cascade(soa::Join::iterator const& collision, aod::CascDataExt const& Cascades, aod::V0Datas const&, DauTracks const& tracks, soa::Join const& /*bcs*/, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0s*/) { - if (applyEvSel && - !(isEventSelected(collision))) { // Checking if the event passes the - // selection criteria + const bool own = (eventHistOwner == kOwnerDataCasc); + if (evSel.applyEvSel && + !(isEventSelected(collision, own))) { // Checking if the event passes the + // selection criteria return; } @@ -1892,9 +2806,21 @@ struct Lambdak0sflattenicity { auto vtxX = collision.posX(); float flattenicity = estimateFlattenicity(collision, tracks); + if (own) { + fillFlattenicityStages(); + } + if (flattenicity < 0.f) { + return; + } + if (own) { - rEventSelection.fill(HIST("hVertexZ"), vtxZ); - rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); + rEventSelection.fill(HIST("hVertexZ"), vtxZ); + rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); + rEventSelection.fill(HIST("hCentFT0M"), collision.centFT0M()); + rEventSelection.fill(HIST("hCentFT0MvsFlattenicity"), collision.centFT0M(), flattenicity); + fillFlatDistRec(flattenicity, collision.centFT0M(), collision.isInelGt0()); + fillChargedRec(tracks, flattenicity); + } for (const auto& casc : Cascades) { @@ -1904,119 +2830,241 @@ struct Lambdak0sflattenicity { float cascPos = std::hypot(casc.x() - vtxX, casc.y() - vtxY, casc.z() - vtxZ); float cascTotMom = std::hypot(casc.px(), casc.py(), casc.pz()); - float ctauXi = pdgmassXi * cascPos / (cascTotMom + 1e-13); - // float ctauOmega =pdgmassOmega * cascPos / (cascTotMom + 1e-13); - float dcav0pv = casc.dcav0topv(vtxX, vtxY, vtxZ); - float cosPAcasc = casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()); + float ctauXi = o2::constants::physics::MassXiMinus * cascPos / (cascTotMom + 1e-13); float cosPAv0 = casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); float massXi = casc.mXi(); rXi.fill(HIST("hMassXi"), massXi); // Cascade - if (posDaughterTrack.tpcNSigmaPi() < nSigmaTPCPion && negDaughterTrack.tpcNSigmaPi() < nSigmaTPCPion && bacDaughterTrack.tpcNSigmaPi() < nSigmaTPCPion && - posDaughterTrack.tpcNSigmaKa() < nSigmaTPCKaon && negDaughterTrack.tpcNSigmaKa() < nSigmaTPCKaon && bacDaughterTrack.tpcNSigmaKa() < nSigmaTPCKaon && - posDaughterTrack.tpcNSigmaPr() < nSigmaTPCProton && negDaughterTrack.tpcNSigmaPr() < nSigmaTPCProton && bacDaughterTrack.tpcNSigmaPr() < nSigmaTPCProton && - posDaughterTrack.tpcNClsCrossedRows() > nTPCcrossedRows && negDaughterTrack.tpcNClsCrossedRows() > nTPCcrossedRows && bacDaughterTrack.tpcNClsCrossedRows() > nTPCcrossedRows && - std::abs(posDaughterTrack.eta()) < cfgTrkEtaCut && std::abs(negDaughterTrack.eta()) < cfgTrkEtaCut && std::abs(bacDaughterTrack.eta()) < cfgTrkEtaCut && - casc.dcapostopv() > v0settingDCApostopv && casc.dcanegtopv() > v0settingDCAnegtopv && casc.dcabachtopv() > v0settingDCAbactopv && casc.dcaV0daughters() < v0settingDCAv0dau && dcav0pv > cascsettingDCAv0toPV && - casc.dcacascdaughters() < cascsettingDCAv0bach && casc.bachBaryonDCAxyToPV() < cascsettingDCAxybaryonbach && cosPAcasc > cascsettingCosPAcascPV && cosPAv0 > cascsettingCosPAv0PV && - casc.cascradius() > cascsettingcascradius && casc.v0radius() > cascsettingv0radius && - std::abs(casc.yXi()) < cascsettingRapidity && ctauXi < 4.91 * cascsettingproplifetime && - std::abs(casc.mLambda() - pdgmassLambda) < cascsettingMassRejectionLambdaXi && std::abs(casc.mOmega() - pdgmassOmega) > cascsettingMassRejectioOmegaXi) { + if (isSelectedXi(collision, casc, posDaughterTrack, negDaughterTrack, bacDaughterTrack, ctauXi)) { + + const bool isXiMinus = casc.sign() < 0; + const auto& protonDaughter = isXiMinus ? posDaughterTrack : negDaughterTrack; + const auto& pionDaughter = isXiMinus ? negDaughterTrack : posDaughterTrack; rXi.fill(HIST("hMassXiSelected"), massXi); rXi.fill(HIST("hDCAV0DaughtersXi"), casc.dcaV0daughters()); rXi.fill(HIST("hV0CosPAXi"), cosPAv0); - rXi.fill(HIST("hrapidityXi"), casc.rapidity(1)); + rXi.fill(HIST("hrapidityXi"), casc.yXi()); rXi.fill(HIST("hctauXi"), ctauXi); - rXi.fill(HIST("h2DdecayRadiusXi"), casc.v0radius()); + rXi.fill(HIST("h2DdecayRadiusXi"), casc.cascradius()); rXi.fill(HIST("hMassXipT"), massXi, casc.pt()); rXi.fill(HIST("hMassXipTFlat"), massXi, casc.pt(), flattenicity); + rXi.fill(HIST("hNSigmaProtonFromXi"), protonDaughter.tpcNSigmaPr(), protonDaughter.tpcInnerParam()); + rXi.fill(HIST("hNSigmaPionFromXi"), pionDaughter.tpcNSigmaPi(), pionDaughter.tpcInnerParam()); + rXi.fill(HIST("hNSigmaBachPionFromXi"), bacDaughterTrack.tpcNSigmaPi(), bacDaughterTrack.tpcInnerParam()); } } } - Preslice> perColCasc = aod::track::collisionId; + Preslice perColCasc = aod::cascade::collisionId; + Preslice perColDauTracksMC = aod::track::collisionId; SliceCache cacheCasc; - void processRecMCRun3Cascade(soa::Join const& collisions, - soa::Join const& Cascades, - aod::V0Datas const&, soa::Join const& tracks, + LabeledCascades const& Cascades, + aod::V0Datas const&, LabeledDauTracks const& tracks, soa::Join const& /*bcs*/, aod::FT0s const& /*ft0s*/, aod::FV0As const& /*fv0s*/, aod::McCollisions const&, aod::McParticles const& mcParticles) { + const bool own = (eventHistOwner == kOwnerRecMCCasc); for (const auto& collision : collisions) { - if (applyEvSel && - !(isEventSelected(collision))) { // Checking if the event passes the - // selection criteria - return; + if (evSel.applyEvSel && + !(isEventSelected(collision, own))) { // Checking if the event passes the + // selection criteria + continue; + } + + if (!collision.has_mcCollision()) { + continue; } auto vtxZ = collision.posZ(); auto vtxY = collision.posY(); auto vtxX = collision.posX(); - float flattenicity = estimateFlattenicity(collision, tracks); - - rEventSelection.fill(HIST("hVertexZ"), vtxZ); - rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); + auto tracksThisCollision = tracks.sliceBy(perColDauTracksMC, collision.globalIndex()); + float flattenicity = estimateFlattenicity(collision, tracksThisCollision); + if (own) { + fillFlattenicityStages(); + } + if (flattenicity < 0.f) { + continue; + } + if (own) { + + rEventSelection.fill(HIST("hVertexZ"), vtxZ); + rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); + rEventSelection.fill(HIST("hCentFT0M"), collision.centFT0M()); + rEventSelection.fill(HIST("hCentFT0MvsFlattenicity"), collision.centFT0M(), flattenicity); + fillFlatDistRec(flattenicity, collision.centFT0M(), collision.isInelGt0()); + fillChargedRec(tracksThisCollision, flattenicity); + } auto cascsThisCollision = Cascades.sliceBy(perColCasc, collision.globalIndex()); const auto& mcCollision = collision.mcCollision_as(); + const auto particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cacheCasc); + const float flattenicityMCGen = estimateFlattenicityGen(particlesInCollision, own); + if (own) { + rEventSelection.fill(HIST("hFlattenicityDistributionMCGen_Rec"), flattenicityMCGen); + rEventSelection.fill(HIST("hFlattenicity_Corr_Gen_vs_Rec"), flattenicityMCGen, flattenicity); + rEventSelection.fill(HIST("hFlatGenVsRecFine"), flattenicityMCGen, flattenicity); + fillFlatDistGenInRec(flattenicityMCGen, collision.centFT0M(), collision.isInelGt0()); + } + for (const auto& casc : cascsThisCollision) { - auto posDaughterTrack = casc.posTrack_as(); - auto negDaughterTrack = casc.negTrack_as(); - auto bacDaughterTrack = casc.bachelor_as(); + // MC truth matching, else the spectra keep the combinatorial background + if (!casc.has_mcParticle()) { + continue; + } + const auto& cascMcParticle = casc.mcParticle(); + + auto posDaughterTrack = casc.posTrack_as(); + auto negDaughterTrack = casc.negTrack_as(); + auto bacDaughterTrack = casc.bachelor_as(); float cascPos = std::hypot(casc.x() - vtxX, casc.y() - vtxY, casc.z() - vtxZ); float cascTotMom = std::hypot(casc.px(), casc.py(), casc.pz()); - float ctauXi = pdgmassXi * cascPos / (cascTotMom + 1e-13); - // float ctauOmega =pdgmassOmega * cascPos / (cascTotMom + 1e-13); - float dcav0pv = casc.dcav0topv(vtxX, vtxY, vtxZ); - float cosPAcasc = casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()); + float ctauXi = o2::constants::physics::MassXiMinus * cascPos / (cascTotMom + 1e-13); float cosPAv0 = casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()); float massXi = casc.mXi(); rXi.fill(HIST("hMassXi"), massXi); // Cascade - if (posDaughterTrack.tpcNSigmaPi() < nSigmaTPCPion && negDaughterTrack.tpcNSigmaPi() < nSigmaTPCPion && bacDaughterTrack.tpcNSigmaPi() < nSigmaTPCPion && - posDaughterTrack.tpcNSigmaKa() < nSigmaTPCKaon && negDaughterTrack.tpcNSigmaKa() < nSigmaTPCKaon && bacDaughterTrack.tpcNSigmaKa() < nSigmaTPCKaon && - posDaughterTrack.tpcNSigmaPr() < nSigmaTPCProton && negDaughterTrack.tpcNSigmaPr() < nSigmaTPCProton && bacDaughterTrack.tpcNSigmaPr() < nSigmaTPCProton && - posDaughterTrack.tpcNClsCrossedRows() > nTPCcrossedRows && negDaughterTrack.tpcNClsCrossedRows() > nTPCcrossedRows && bacDaughterTrack.tpcNClsCrossedRows() > nTPCcrossedRows && - std::abs(posDaughterTrack.eta()) < cfgTrkEtaCut && std::abs(negDaughterTrack.eta()) < cfgTrkEtaCut && std::abs(bacDaughterTrack.eta()) < cfgTrkEtaCut && - casc.dcapostopv() > v0settingDCApostopv && casc.dcanegtopv() > v0settingDCAnegtopv && casc.dcabachtopv() > v0settingDCAbactopv && casc.dcaV0daughters() < v0settingDCAv0dau && dcav0pv > cascsettingDCAv0toPV && - casc.dcacascdaughters() < cascsettingDCAv0bach && casc.bachBaryonDCAxyToPV() < cascsettingDCAxybaryonbach && cosPAcasc > cascsettingCosPAcascPV && cosPAv0 > cascsettingCosPAv0PV && - casc.cascradius() > cascsettingcascradius && casc.v0radius() > cascsettingv0radius && - std::abs(casc.yXi()) < cascsettingRapidity && ctauXi < 4.91 * cascsettingproplifetime && - std::abs(casc.mLambda() - pdgmassLambda) < cascsettingMassRejectionLambdaXi && std::abs(casc.mOmega() - pdgmassOmega) > cascsettingMassRejectioOmegaXi) { + if (std::abs(cascMcParticle.pdgCode()) == PDG_t::kXiMinus && + isSelectedXi(collision, casc, posDaughterTrack, negDaughterTrack, bacDaughterTrack, ctauXi)) { + + const bool isPrimaryCasc = cascMcParticle.isPhysicalPrimary(); + if (!isPrimaryCasc) { + float motherPt = -1.f; + const int motherIndex = getFeedDownMother(cascMcParticle, motherPt); + rXi.fill(HIST("hMassFeedDownXipTFlat"), massXi, casc.pt(), flattenicity); + rXi.fill(HIST("hFeedDownXiPtVsMotherPt"), casc.pt(), motherPt); + rXi.fill(HIST("hFeedDownXiMatrix"), casc.pt(), motherPt, flattenicity, motherIndex); + rXi.fill(HIST("hFeedDownXiMotherPdg"), motherIndex); + } + if (!isPrimaryCasc && eventClass.requirePrimaryMC) { + continue; + } + + const bool isXiMinus = casc.sign() < 0; + const auto& protonDaughter = isXiMinus ? posDaughterTrack : negDaughterTrack; + const auto& pionDaughter = isXiMinus ? negDaughterTrack : posDaughterTrack; rXi.fill(HIST("hMassXiSelected"), massXi); rXi.fill(HIST("hDCAV0DaughtersXi"), casc.dcaV0daughters()); rXi.fill(HIST("hV0CosPAXi"), cosPAv0); - rXi.fill(HIST("hrapidityXi"), casc.rapidity(1)); + rXi.fill(HIST("hrapidityXi"), casc.yXi()); rXi.fill(HIST("hctauXi"), ctauXi); - rXi.fill(HIST("h2DdecayRadiusXi"), casc.v0radius()); + rXi.fill(HIST("h2DdecayRadiusXi"), casc.cascradius()); rXi.fill(HIST("hMassXipT"), massXi, casc.pt()); rXi.fill(HIST("hMassXipTFlat"), massXi, casc.pt(), flattenicity); + rXi.fill(HIST("hMassXipTTrueFlat"), massXi, casc.pt(), flattenicityMCGen); + rXi.fill(HIST("hPtResXi"), cascMcParticle.pt(), + (casc.pt() - cascMcParticle.pt()) / cascMcParticle.pt()); + rXi.fill(HIST("hNSigmaProtonFromXi"), protonDaughter.tpcNSigmaPr(), protonDaughter.tpcInnerParam()); + rXi.fill(HIST("hNSigmaPionFromXi"), pionDaughter.tpcNSigmaPi(), pionDaughter.tpcInnerParam()); + rXi.fill(HIST("hNSigmaBachPionFromXi"), bacDaughterTrack.tpcNSigmaPi(), bacDaughterTrack.tpcInnerParam()); } } - const auto particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cacheCasc); - float flattenicityMCGen = estimateFlattenicityFV0MC(particlesInCollision); - rEventSelection.fill(HIST("hFlattenicityDistributionMCGen_Rec"), flattenicityMCGen); - rEventSelection.fill(HIST("hFlattenicity_Corr_Gen_vs_Rec"), flattenicityMCGen, flattenicity); + const bool isInelGt0Rec = collision.isInelGt0(); for (const auto& mcParticle : particlesInCollision) { - if (mcParticle.isPhysicalPrimary() && std::abs(mcParticle.y()) < 0.5f && std::abs(mcParticle.pdgCode()) == PDG_t::kXiPlusBar) { - rXi.fill(HIST("Generated_MCRecoCollCheck_INEL_Xi"), mcParticle.pt(), flattenicity); // K0s + if (mcParticle.isPhysicalPrimary() && std::abs(mcParticle.y()) <= cascSel.cascsettingRapidity && + std::abs(mcParticle.pdgCode()) == PDG_t::kXiMinus) { + rXi.fill(HIST("Generated_MCRecoCollCheck_INEL_Xi"), mcParticle.pt(), flattenicity); + if (isInelGt0Rec) { + rXi.fill(HIST("Generated_MCRecoCollCheck_INELgt0_Xi"), mcParticle.pt(), flattenicity); + rXi.fill(HIST("Generated_MCRecoCollCheck_INELgt0_Xi_TrueFlat"), mcParticle.pt(), flattenicityMCGen); + } } } } } + // ================== Percentile determination pass ====================== // + // + // Event selection and flattenicity only, so a short run gives the 1-rho + // distribution the percentile boundaries are read off. The boundaries then go + // back into binning.axisFlat for the spectra pass, where one class is exactly + // one bin. + + void processFlatDistData( + soa::Join::iterator const& collision, + TrackCandidates const& tracks, + soa::Join const& /*bcs*/, aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0s*/) + { + const bool own = (eventHistOwner == kOwnerFlatDistData); + if (evSel.applyEvSel && !isEventSelected(collision, own)) { + return; + } + const float flattenicity = estimateFlattenicity(collision, tracks); + if (own) { + fillFlattenicityStages(); + } + if (flattenicity < 0.f) { + return; + } + if (own) { + rEventSelection.fill(HIST("hVertexZ"), collision.posZ()); + rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); + rEventSelection.fill(HIST("hCentFT0M"), collision.centFT0M()); + rEventSelection.fill(HIST("hCentFT0MvsFlattenicity"), collision.centFT0M(), flattenicity); + fillFlatDistRec(flattenicity, collision.centFT0M(), collision.isInelGt0()); + fillChargedRec(tracks, flattenicity); + } + } + + void processFlatDistMC( + soa::Join const& collisions, + aod::McCollisions const&, TrackCandidatesMC const& tracks, + soa::Join const& /*bcs*/, aod::FT0s const& /*ft0s*/, + aod::FV0As const& /*fv0s*/, aod::McParticles const& mcParticles) + { + const bool own = (eventHistOwner == kOwnerFlatDistMC); + for (const auto& collision : collisions) { + if (evSel.applyEvSel && !isEventSelected(collision, own)) { + continue; + } + if (!collision.has_mcCollision()) { + continue; + } + auto tracksThisCollision = tracks.sliceBy(perColTracksMC, collision.globalIndex()); + const float flattenicity = estimateFlattenicity(collision, tracksThisCollision); + if (own) { + fillFlattenicityStages(); + } + if (flattenicity < 0.f) { + continue; + } + if (!own) { + continue; + } + rEventSelection.fill(HIST("hVertexZ"), collision.posZ()); + rEventSelection.fill(HIST("hFlattenicityDistribution"), flattenicity); + rEventSelection.fill(HIST("hCentFT0M"), collision.centFT0M()); + rEventSelection.fill(HIST("hCentFT0MvsFlattenicity"), collision.centFT0M(), flattenicity); + fillFlatDistRec(flattenicity, collision.centFT0M(), collision.isInelGt0()); + fillChargedRec(tracksThisCollision, flattenicity); + + const auto& mcCollision = collision.mcCollision_as(); + const auto particlesInCollision = mcParticles.sliceByCached(aod::mcparticle::mcCollisionId, mcCollision.globalIndex(), cache1); + const float flattenicityMCGen = estimateFlattenicityGen(particlesInCollision); + rEventSelection.fill(HIST("hFlattenicityDistributionMCGen_Rec"), flattenicityMCGen); + rEventSelection.fill(HIST("hFlattenicity_Corr_Gen_vs_Rec"), flattenicityMCGen, flattenicity); + rEventSelection.fill(HIST("hFlatGenVsRecFine"), flattenicityMCGen, flattenicity); + fillFlatDistGenInRec(flattenicityMCGen, collision.centFT0M(), collision.isInelGt0()); + } + } + + PROCESS_SWITCH(Lambdak0sflattenicity, processFlatDistData, "Flattenicity distribution only, data", false); + PROCESS_SWITCH(Lambdak0sflattenicity, processFlatDistMC, "Flattenicity distribution only, MC", false); PROCESS_SWITCH(Lambdak0sflattenicity, processDataRun3LambdaK0s, "Process Run 3 Data LambdaK0s", false); PROCESS_SWITCH(Lambdak0sflattenicity, processRecMCLambdaK0s, "Process Run 3 MC reconstructed LambdaK0s", false); PROCESS_SWITCH(Lambdak0sflattenicity, processGenMC, "Process Run 3 MC generated", false); - PROCESS_SWITCH(Lambdak0sflattenicity, processDataRun3Cascade, "Process Run 3 Data Cascade", true); + PROCESS_SWITCH(Lambdak0sflattenicity, processDataRun3Cascade, "Process Run 3 Data Cascade", false); PROCESS_SWITCH(Lambdak0sflattenicity, processRecMCRun3Cascade, "Process Run 3 mc Rec Cascade", false); }; diff --git a/PWGLF/Tasks/Strangeness/lambdakzeroanalysisMC.cxx b/PWGLF/Tasks/Strangeness/lambdakzeroanalysisMC.cxx index e95ac8eb5ee..2b43a75921d 100644 --- a/PWGLF/Tasks/Strangeness/lambdakzeroanalysisMC.cxx +++ b/PWGLF/Tasks/Strangeness/lambdakzeroanalysisMC.cxx @@ -256,7 +256,7 @@ struct lambdakzeroAnalysisMc { } if (particleMotherOfNeg.has_mothers()) { auto particleGrandMothersOfNegTable = particleMotherOfNeg.mothers_as(); - auto particleGrandMotherOfNeg = particleGrandMothersOfNegTable[0]; + const auto& particleGrandMotherOfNeg = particleGrandMothersOfNegTable[0]; if (particleGrandMotherOfNeg.pdgCode() == 3312 || particleGrandMotherOfNeg.pdgCode() == 3322) { registry.fill(HIST("hLambdaFeedDownMatrix"), particleMotherOfNeg.pt(), particleGrandMotherOfNeg.pt()); } @@ -289,7 +289,7 @@ struct lambdakzeroAnalysisMc { } if (particleMotherOfNeg.has_mothers()) { auto particleGrandMothersOfNegTable = particleMotherOfNeg.mothers_as(); - auto particleGrandMotherOfNeg = particleGrandMothersOfNegTable[0]; + const auto& particleGrandMotherOfNeg = particleGrandMothersOfNegTable[0]; if (particleGrandMotherOfNeg.pdgCode() == -3312 || particleGrandMotherOfNeg.pdgCode() == -3322) { registry.fill(HIST("hAntiLambdaFeedDownMatrix"), particleMotherOfNeg.pt(), particleGrandMotherOfNeg.pt()); } diff --git a/PWGLF/Tasks/Strangeness/lambdalambda.cxx b/PWGLF/Tasks/Strangeness/lambdalambda.cxx index 47ba728a94a..d3659397339 100644 --- a/PWGLF/Tasks/Strangeness/lambdalambda.cxx +++ b/PWGLF/Tasks/Strangeness/lambdalambda.cxx @@ -224,7 +224,7 @@ struct lambdalambda { ROOT::Math::PxPyPzMVector RecoV02Rot, RecoV0V0Rot; template - bool eventSelected(TCollision collision) + bool eventSelected(const TCollision& collision) { if (!collision.sel8()) { return 0; diff --git a/PWGLF/Tasks/Strangeness/lambdapolarization.cxx b/PWGLF/Tasks/Strangeness/lambdapolarization.cxx index a35a319ef3b..df2e1f48373 100644 --- a/PWGLF/Tasks/Strangeness/lambdapolarization.cxx +++ b/PWGLF/Tasks/Strangeness/lambdapolarization.cxx @@ -397,7 +397,7 @@ struct lambdapolarization { ROOT::Math::PxPyPzMVector ProtonVec, PionVec, LambdaVec, ProtonBoostedVec, PionBoostedVec; template - bool eventSelected(TCollision collision) + bool eventSelected(const TCollision& collision) { if (!collision.sel8()) { return 0; diff --git a/PWGLF/Tasks/Strangeness/lambdapolsp.cxx b/PWGLF/Tasks/Strangeness/lambdapolsp.cxx index 61b68f6ac10..1eadddbbf48 100644 --- a/PWGLF/Tasks/Strangeness/lambdapolsp.cxx +++ b/PWGLF/Tasks/Strangeness/lambdapolsp.cxx @@ -50,6 +50,7 @@ #include +#include #include #include #include @@ -189,6 +190,8 @@ struct lambdapolsp { ConfigurableAxis nuasignAxis{"nuaSignAxis", {2, -1.5f, 1.5f}, "charge sign"}; ConfigurableAxis nuaphiAxis{"nuaPhiAxis", {72, 0.f, static_cast(TMath::TwoPi())}, "#varphi"}; Configurable ConfNUA{"ConfNUA", "Users/p/prottay/My/Object/NUAwgtschk", "Path to NUA"}; + + Configurable fillnominal{"fillnominal", true, "flag to fill default histograms"}; } QAgrp; struct : ConfigurableGroup { @@ -497,7 +500,18 @@ struct lambdapolsp { histos.add("hpQxytpvscent", "hpQxytpvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); histos.add("hpQxtQypvscent", "hpQxtQypvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); histos.add("hpQxpQytvscent", "hpQxpQytvscent", HistType::kTHnSparseF, {axisGrp.configcentAxis, spAxis}, true); + + histos.add("hSparseLambdaPolSP_xAwgt", "hSparseLambdaPolSP_xAwgt", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseLambdaPolSP_yAwgt", "hSparseLambdaPolSP_yAwgt", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseLambdaPolSP_xCwgt", "hSparseLambdaPolSP_xCwgt", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseLambdaPolSP_yCwgt", "hSparseLambdaPolSP_yCwgt", HistType::kTHnSparseF, runaxes, true); + + histos.add("hSparseAntiLambdaPolSP_xAwgt", "hSparseAntiLambdaPolSP_xAwgt", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseAntiLambdaPolSP_yAwgt", "hSparseAntiLambdaPolSP_yAwgt", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseAntiLambdaPolSP_xCwgt", "hSparseAntiLambdaPolSP_xCwgt", HistType::kTHnSparseF, runaxes, true); + histos.add("hSparseAntiLambdaPolSP_yCwgt", "hSparseAntiLambdaPolSP_yCwgt", HistType::kTHnSparseF, runaxes, true); } + if (usesubdet) { histos.add("hSparseLambdaCosPsiA", "hSparseLambdaCosPsiA", HistType::kTHnSparseF, runaxes, true); histos.add("hSparseLambdaSinPsiA", "hSparseLambdaSinPsiA", HistType::kTHnSparseF, runaxes, true); @@ -542,12 +556,12 @@ struct lambdapolsp { // histos.add("hSparseLambda_corr2b", "hSparseLambda_corr2b", HistType::kTHnSparseF, runaxes, true); histos.add("hSparseAntiLambda_corr2a", "hSparseAntiLambda_corr2a", HistType::kTHnSparseF, runaxes, true); // histos.add("hSparseAntiLambda_corr2b", "hSparseAntiLambda_corr2b", HistType::kTHnSparseF, runaxes, true); - if (randGrp.useSP) { + /*if (randGrp.useSP) { histos.add("hSparseAntiLambda_avgux", "hSparseAntiLambda_avgux", HistType::kTHnSparseF, {thnAxisInvMass, axisGrp.configthnAxispT, axisGrp.configthnAxisPol, axisGrp.configcentAxis}, true); histos.add("hSparseAntiLambda_avguy", "hSparseAntiLambda_avguy", HistType::kTHnSparseF, {thnAxisInvMass, axisGrp.configthnAxispT, axisGrp.configthnAxisPol, axisGrp.configcentAxis}, true); histos.add("hSparseLambda_avgux", "hSparseLambda_avgux", HistType::kTHnSparseF, {thnAxisInvMass, axisGrp.configthnAxispT, axisGrp.configthnAxisPol, axisGrp.configcentAxis}, true); histos.add("hSparseLambda_avguy", "hSparseLambda_avguy", HistType::kTHnSparseF, {thnAxisInvMass, axisGrp.configthnAxispT, axisGrp.configthnAxisPol, axisGrp.configcentAxis}, true); - } + }*/ } if (distGrp.filldist) { @@ -717,6 +731,14 @@ struct lambdapolsp { HistType::kTHnSparseF, runaxesSyst, true); + + histos.add("hSparseAntiLambda_corr1aSyst", "hSparseAntiLambda_corr1aSyst", HistType::kTHnSparseF, runaxesSyst, true); + histos.add("hSparseAntiLambda_corr1bSyst", "hSparseAntiLambda_corr1bSyst", HistType::kTHnSparseF, runaxesSyst, true); + histos.add("hSparseAntiLambda_corr2aSyst", "hSparseAntiLambda_corr2aSyst", HistType::kTHnSparseF, runaxesSyst, true); + + histos.add("hSparseLambda_corr1aSyst", "hSparseLambda_corr1aSyst", HistType::kTHnSparseF, runaxesSyst, true); + histos.add("hSparseLambda_corr1bSyst", "hSparseLambda_corr1bSyst", HistType::kTHnSparseF, runaxesSyst, true); + histos.add("hSparseLambda_corr2aSyst", "hSparseLambda_corr2aSyst", HistType::kTHnSparseF, runaxesSyst, true); } } @@ -1077,6 +1099,20 @@ struct lambdapolsp { auto PolSP_A = uy * modqxZDCA - ux * modqyZDCA; // u_y QxA - u_x QyA auto PolSP_C = uy * modqxZDCC - ux * modqyZDCC; // u_y QxC - u_x QyC + // SP numerator components separately + auto PolSP_xA = -ux * modqyZDCA; + auto PolSP_yA = uy * modqxZDCA; + + auto PolSP_xC = -ux * modqyZDCC; + auto PolSP_yC = uy * modqxZDCC; + + // acceptance-corrected versions + auto PolSP_xAwgt = PolSP_xA / acvalue; + auto PolSP_yAwgt = PolSP_yA / acvalue; + + auto PolSP_xCwgt = PolSP_xC / acvalue; + auto PolSP_yCwgt = PolSP_yC / acvalue; + if (randGrp.useSP) { Pol = PolSP; PolA = PolSP_A; @@ -1085,120 +1121,195 @@ struct lambdapolsp { PolAwgt = PolSP_A / acvalue; PolCwgt = PolSP_C / acvalue; } + ////////////////////////////// - // Fill histograms using constructed names - if (tag2) { - if (needetaaxis) { - if (usesubdet) { - histos.fill(HIST("hSparseAntiLambdaCosPsiA"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCA))), centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseAntiLambdaCosPsiC"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCC))), centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseAntiLambdaSinPsiA"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCA))), centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseAntiLambdaSinPsiC"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCC))), centrality, desbinvalue, wgtfactor); - } - histos.fill(HIST("hSparseAntiLambdaCosPsi"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDC))), centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseAntiLambdaSinPsi"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDC))), centrality, desbinvalue, wgtfactor); - if (usesubdet) { - histos.fill(HIST("hSparseAntiLambdaPolA"), candmass, candpt, PolA, centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseAntiLambdaPolC"), candmass, candpt, PolC, centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseAntiLambdaPolAwgt"), candmass, candpt, PolAwgt, centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseAntiLambdaPolCwgt"), candmass, candpt, PolCwgt, centrality, desbinvalue, wgtfactor); - } - histos.fill(HIST("hSparseAntiLambdaPol"), candmass, candpt, Pol, centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseAntiLambdaPolwgt"), candmass, candpt, Polwgt, centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseAntiLambda_corr1a"), candmass, candpt, sinPhiStar, centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseAntiLambda_corr1b"), candmass, candpt, cosPhiStar, centrality, desbinvalue, wgtfactor); - // histos.fill(HIST("hSparseAntiLambda_corr1c"), candmass, candpt, phiphiStar, centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseAntiLambda_corr2a"), candmass, candpt, sinThetaStar, centrality, desbinvalue, wgtfactor); - // histos.fill(HIST("hSparseAntiLambda_corr2b"), candmass, candpt, sinThetaStarcosphiphiStar, centrality, desbinvalue, wgtfactor); - if (randGrp.useSP) { - histos.fill(HIST("hSparseAntiLambda_avgux"), candmass, candpt, ux, centrality); - histos.fill(HIST("hSparseAntiLambda_avguy"), candmass, candpt, uy, centrality); - } - } else { - if (usesubdet) { - histos.fill(HIST("hSparseAntiLambdaCosPsiA"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCA))), centrality, wgtfactor); - histos.fill(HIST("hSparseAntiLambdaCosPsiC"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCC))), centrality, wgtfactor); - histos.fill(HIST("hSparseAntiLambdaSinPsiA"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCA))), centrality, wgtfactor); - histos.fill(HIST("hSparseAntiLambdaSinPsiC"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCC))), centrality, wgtfactor); - } - histos.fill(HIST("hSparseAntiLambdaCosPsi"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDC))), centrality, wgtfactor); - histos.fill(HIST("hSparseAntiLambdaSinPsi"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDC))), centrality, wgtfactor); - if (usesubdet) { - histos.fill(HIST("hSparseAntiLambdaPolA"), candmass, candpt, PolA, centrality, wgtfactor); - histos.fill(HIST("hSparseAntiLambdaPolC"), candmass, candpt, PolC, centrality, wgtfactor); - histos.fill(HIST("hSparseAntiLambdaPolAwgt"), candmass, candpt, PolAwgt, centrality, wgtfactor); - histos.fill(HIST("hSparseAntiLambdaPolCwgt"), candmass, candpt, PolCwgt, centrality, wgtfactor); - } - histos.fill(HIST("hSparseAntiLambdaPol"), candmass, candpt, Pol, centrality, wgtfactor); - histos.fill(HIST("hSparseAntiLambdaPolwgt"), candmass, candpt, Polwgt, centrality, wgtfactor); - histos.fill(HIST("hSparseAntiLambda_corr1a"), candmass, candpt, sinPhiStar, centrality, wgtfactor); - histos.fill(HIST("hSparseAntiLambda_corr1b"), candmass, candpt, cosPhiStar, centrality, wgtfactor); - // histos.fill(HIST("hSparseAntiLambda_corr1c"), candmass, candpt, phiphiStar, centrality, wgtfactor); - histos.fill(HIST("hSparseAntiLambda_corr2a"), candmass, candpt, sinThetaStar, centrality, wgtfactor); - // histos.fill(HIST("hSparseAntiLambda_corr2b"), candmass, candpt, sinThetaStarcosphiphiStar, centrality, wgtfactor); - if (randGrp.useSP) { - histos.fill(HIST("hSparseAntiLambda_avgux"), candmass, candpt, ux, centrality); - histos.fill(HIST("hSparseAntiLambda_avguy"), candmass, candpt, uy, centrality); + if (QAgrp.fillnominal) { + // Fill histograms using constructed names + if (tag2) { + if (needetaaxis) { + if (usesubdet) { + histos.fill(HIST("hSparseAntiLambdaCosPsiA"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCA))), centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaCosPsiC"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCC))), centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaSinPsiA"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCA))), centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaSinPsiC"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCC))), centrality, desbinvalue, wgtfactor); + } + histos.fill(HIST("hSparseAntiLambdaCosPsi"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDC))), centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaSinPsi"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDC))), centrality, desbinvalue, wgtfactor); + if (usesubdet) { + histos.fill(HIST("hSparseAntiLambdaPolA"), candmass, candpt, PolA, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaPolC"), candmass, candpt, PolC, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaPolAwgt"), candmass, candpt, PolAwgt, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaPolCwgt"), candmass, candpt, PolCwgt, centrality, desbinvalue, wgtfactor); + } + histos.fill(HIST("hSparseAntiLambdaPol"), candmass, candpt, Pol, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaPolwgt"), candmass, candpt, Polwgt, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambda_corr1a"), candmass, candpt, sinPhiStar, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambda_corr1b"), candmass, candpt, cosPhiStar, centrality, desbinvalue, wgtfactor); + // histos.fill(HIST("hSparseAntiLambda_corr1c"), candmass, candpt, phiphiStar, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseAntiLambda_corr2a"), candmass, candpt, sinThetaStar, centrality, desbinvalue, wgtfactor); + // histos.fill(HIST("hSparseAntiLambda_corr2b"), candmass, candpt, sinThetaStarcosphiphiStar, centrality, desbinvalue, wgtfactor); + if (randGrp.useSP) { + // histos.fill(HIST("hSparseAntiLambda_avgux"), candmass, candpt, ux, centrality); + // histos.fill(HIST("hSparseAntiLambda_avguy"), candmass, candpt, uy, centrality); + + histos.fill(HIST("hSparseAntiLambdaPolwgt"), candmass, candpt, Polwgt, centrality, desbinvalue, wgtfactor); + + histos.fill(HIST("hSparseAntiLambdaPolSP_xAwgt"), + candmass, candpt, PolSP_xAwgt, + centrality, desbinvalue, wgtfactor); + + histos.fill(HIST("hSparseAntiLambdaPolSP_yAwgt"), + candmass, candpt, PolSP_yAwgt, + centrality, desbinvalue, wgtfactor); + + histos.fill(HIST("hSparseAntiLambdaPolSP_xCwgt"), + candmass, candpt, PolSP_xCwgt, + centrality, desbinvalue, wgtfactor); + + histos.fill(HIST("hSparseAntiLambdaPolSP_yCwgt"), + candmass, candpt, PolSP_yCwgt, + centrality, desbinvalue, wgtfactor); + } + + } else { + if (usesubdet) { + histos.fill(HIST("hSparseAntiLambdaCosPsiA"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCA))), centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaCosPsiC"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCC))), centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaSinPsiA"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCA))), centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaSinPsiC"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCC))), centrality, wgtfactor); + } + histos.fill(HIST("hSparseAntiLambdaCosPsi"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDC))), centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaSinPsi"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDC))), centrality, wgtfactor); + if (usesubdet) { + histos.fill(HIST("hSparseAntiLambdaPolA"), candmass, candpt, PolA, centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaPolC"), candmass, candpt, PolC, centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaPolAwgt"), candmass, candpt, PolAwgt, centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaPolCwgt"), candmass, candpt, PolCwgt, centrality, wgtfactor); + } + histos.fill(HIST("hSparseAntiLambdaPol"), candmass, candpt, Pol, centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambdaPolwgt"), candmass, candpt, Polwgt, centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambda_corr1a"), candmass, candpt, sinPhiStar, centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambda_corr1b"), candmass, candpt, cosPhiStar, centrality, wgtfactor); + // histos.fill(HIST("hSparseAntiLambda_corr1c"), candmass, candpt, phiphiStar, centrality, wgtfactor); + histos.fill(HIST("hSparseAntiLambda_corr2a"), candmass, candpt, sinThetaStar, centrality, wgtfactor); + // histos.fill(HIST("hSparseAntiLambda_corr2b"), candmass, candpt, sinThetaStarcosphiphiStar, centrality, wgtfactor); + if (randGrp.useSP) { + // histos.fill(HIST("hSparseAntiLambda_avgux"), candmass, candpt, ux, centrality); + // histos.fill(HIST("hSparseAntiLambda_avguy"), candmass, candpt, uy, centrality); + + histos.fill(HIST("hSparseAntiLambdaPolwgt"), candmass, candpt, Polwgt, centrality, wgtfactor); + + histos.fill(HIST("hSparseAntiLambdaPolSP_xAwgt"), + candmass, candpt, PolSP_xAwgt, + centrality, wgtfactor); + + histos.fill(HIST("hSparseAntiLambdaPolSP_yAwgt"), + candmass, candpt, PolSP_yAwgt, + centrality, wgtfactor); + + histos.fill(HIST("hSparseAntiLambdaPolSP_xCwgt"), + candmass, candpt, PolSP_xCwgt, + centrality, wgtfactor); + + histos.fill(HIST("hSparseAntiLambdaPolSP_yCwgt"), + candmass, candpt, PolSP_yCwgt, + centrality, wgtfactor); + } } } - } - if (tag1) { - if (needetaaxis) { - if (usesubdet) { - histos.fill(HIST("hSparseLambdaCosPsiA"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCA))), centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseLambdaCosPsiC"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCC))), centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseLambdaSinPsiA"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCA))), centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseLambdaSinPsiC"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCC))), centrality, desbinvalue, wgtfactor); - } - histos.fill(HIST("hSparseLambdaCosPsi"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDC))), centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseLambdaSinPsi"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDC))), centrality, desbinvalue, wgtfactor); - if (usesubdet) { - histos.fill(HIST("hSparseLambdaPolA"), candmass, candpt, PolA, centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseLambdaPolC"), candmass, candpt, PolC, centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseLambdaPolAwgt"), candmass, candpt, PolAwgt, centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseLambdaPolCwgt"), candmass, candpt, PolCwgt, centrality, desbinvalue, wgtfactor); - } - histos.fill(HIST("hSparseLambdaPol"), candmass, candpt, Pol, centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseLambdaPolwgt"), candmass, candpt, Polwgt, centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseLambda_corr1a"), candmass, candpt, sinPhiStar, centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseLambda_corr1b"), candmass, candpt, cosPhiStar, centrality, desbinvalue, wgtfactor); - // histos.fill(HIST("hSparseLambda_corr1c"), candmass, candpt, phiphiStar, centrality, desbinvalue, wgtfactor); - histos.fill(HIST("hSparseLambda_corr2a"), candmass, candpt, sinThetaStar, centrality, desbinvalue, wgtfactor); - // histos.fill(HIST("hSparseLambda_corr2b"), candmass, candpt, sinThetaStarcosphiphiStar, centrality, desbinvalue, wgtfactor); - if (randGrp.useSP) { - histos.fill(HIST("hSparseLambda_avgux"), candmass, candpt, ux, centrality); - histos.fill(HIST("hSparseLambda_avguy"), candmass, candpt, uy, centrality); - } - } else { - if (usesubdet) { - histos.fill(HIST("hSparseLambdaCosPsiA"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCA))), centrality, wgtfactor); - histos.fill(HIST("hSparseLambdaCosPsiC"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCC))), centrality, wgtfactor); - histos.fill(HIST("hSparseLambdaSinPsiA"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCA))), centrality, wgtfactor); - histos.fill(HIST("hSparseLambdaSinPsiC"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCC))), centrality, wgtfactor); - } - histos.fill(HIST("hSparseLambdaCosPsi"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDC))), centrality, wgtfactor); - histos.fill(HIST("hSparseLambdaSinPsi"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDC))), centrality, wgtfactor); - if (usesubdet) { - histos.fill(HIST("hSparseLambdaPolA"), candmass, candpt, PolA, centrality, wgtfactor); - histos.fill(HIST("hSparseLambdaPolC"), candmass, candpt, PolC, centrality, wgtfactor); - histos.fill(HIST("hSparseLambdaPolAwgt"), candmass, candpt, PolAwgt, centrality, wgtfactor); - histos.fill(HIST("hSparseLambdaPolCwgt"), candmass, candpt, PolCwgt, centrality, wgtfactor); - } - histos.fill(HIST("hSparseLambdaPol"), candmass, candpt, Pol, centrality, wgtfactor); - histos.fill(HIST("hSparseLambdaPolwgt"), candmass, candpt, Polwgt, centrality, wgtfactor); - histos.fill(HIST("hSparseLambda_corr1a"), candmass, candpt, sinPhiStar, centrality, wgtfactor); - histos.fill(HIST("hSparseLambda_corr1b"), candmass, candpt, cosPhiStar, centrality, wgtfactor); - // histos.fill(HIST("hSparseLambda_corr1c"), candmass, candpt, phiphiStar, centrality, wgtfactor); - histos.fill(HIST("hSparseLambda_corr2a"), candmass, candpt, sinThetaStar, centrality, wgtfactor); - // histos.fill(HIST("hSparseLambda_corr2b"), candmass, candpt, sinThetaStarcosphiphiStar, centrality, wgtfactor); - if (randGrp.useSP) { - histos.fill(HIST("hSparseLambda_avgux"), candmass, candpt, ux, centrality); - histos.fill(HIST("hSparseLambda_avguy"), candmass, candpt, uy, centrality); + if (tag1) { + if (needetaaxis) { + if (usesubdet) { + histos.fill(HIST("hSparseLambdaCosPsiA"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCA))), centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambdaCosPsiC"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCC))), centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambdaSinPsiA"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCA))), centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambdaSinPsiC"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCC))), centrality, desbinvalue, wgtfactor); + } + histos.fill(HIST("hSparseLambdaCosPsi"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDC))), centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambdaSinPsi"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDC))), centrality, desbinvalue, wgtfactor); + if (usesubdet) { + histos.fill(HIST("hSparseLambdaPolA"), candmass, candpt, PolA, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambdaPolC"), candmass, candpt, PolC, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambdaPolAwgt"), candmass, candpt, PolAwgt, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambdaPolCwgt"), candmass, candpt, PolCwgt, centrality, desbinvalue, wgtfactor); + } + histos.fill(HIST("hSparseLambdaPol"), candmass, candpt, Pol, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambdaPolwgt"), candmass, candpt, Polwgt, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambda_corr1a"), candmass, candpt, sinPhiStar, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambda_corr1b"), candmass, candpt, cosPhiStar, centrality, desbinvalue, wgtfactor); + // histos.fill(HIST("hSparseLambda_corr1c"), candmass, candpt, phiphiStar, centrality, desbinvalue, wgtfactor); + histos.fill(HIST("hSparseLambda_corr2a"), candmass, candpt, sinThetaStar, centrality, desbinvalue, wgtfactor); + // histos.fill(HIST("hSparseLambda_corr2b"), candmass, candpt, sinThetaStarcosphiphiStar, centrality, desbinvalue, wgtfactor); + if (randGrp.useSP) { + // histos.fill(HIST("hSparseLambda_avgux"), candmass, candpt, ux, centrality); + // histos.fill(HIST("hSparseLambda_avguy"), candmass, candpt, uy, centrality); + + histos.fill(HIST("hSparseLambdaPolwgt"), candmass, candpt, Polwgt, centrality, desbinvalue, wgtfactor); + + histos.fill(HIST("hSparseLambdaPolSP_xAwgt"), + candmass, candpt, PolSP_xAwgt, + centrality, desbinvalue, wgtfactor); + + histos.fill(HIST("hSparseLambdaPolSP_yAwgt"), + candmass, candpt, PolSP_yAwgt, + centrality, desbinvalue, wgtfactor); + + histos.fill(HIST("hSparseLambdaPolSP_xCwgt"), + candmass, candpt, PolSP_xCwgt, + centrality, desbinvalue, wgtfactor); + + histos.fill(HIST("hSparseLambdaPolSP_yCwgt"), + candmass, candpt, PolSP_yCwgt, + centrality, desbinvalue, wgtfactor); + } + } else { + if (usesubdet) { + histos.fill(HIST("hSparseLambdaCosPsiA"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCA))), centrality, wgtfactor); + histos.fill(HIST("hSparseLambdaCosPsiC"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDCC))), centrality, wgtfactor); + histos.fill(HIST("hSparseLambdaSinPsiA"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCA))), centrality, wgtfactor); + histos.fill(HIST("hSparseLambdaSinPsiC"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDCC))), centrality, wgtfactor); + } + histos.fill(HIST("hSparseLambdaCosPsi"), candmass, candpt, (TMath::Cos(GetPhiInRange(psiZDC))), centrality, wgtfactor); + histos.fill(HIST("hSparseLambdaSinPsi"), candmass, candpt, (TMath::Sin(GetPhiInRange(psiZDC))), centrality, wgtfactor); + if (usesubdet) { + histos.fill(HIST("hSparseLambdaPolA"), candmass, candpt, PolA, centrality, wgtfactor); + histos.fill(HIST("hSparseLambdaPolC"), candmass, candpt, PolC, centrality, wgtfactor); + histos.fill(HIST("hSparseLambdaPolAwgt"), candmass, candpt, PolAwgt, centrality, wgtfactor); + histos.fill(HIST("hSparseLambdaPolCwgt"), candmass, candpt, PolCwgt, centrality, wgtfactor); + } + histos.fill(HIST("hSparseLambdaPol"), candmass, candpt, Pol, centrality, wgtfactor); + histos.fill(HIST("hSparseLambdaPolwgt"), candmass, candpt, Polwgt, centrality, wgtfactor); + histos.fill(HIST("hSparseLambda_corr1a"), candmass, candpt, sinPhiStar, centrality, wgtfactor); + histos.fill(HIST("hSparseLambda_corr1b"), candmass, candpt, cosPhiStar, centrality, wgtfactor); + // histos.fill(HIST("hSparseLambda_corr1c"), candmass, candpt, phiphiStar, centrality, wgtfactor); + histos.fill(HIST("hSparseLambda_corr2a"), candmass, candpt, sinThetaStar, centrality, wgtfactor); + // histos.fill(HIST("hSparseLambda_corr2b"), candmass, candpt, sinThetaStarcosphiphiStar, centrality, wgtfactor); + if (randGrp.useSP) { + // histos.fill(HIST("hSparseLambda_avgux"), candmass, candpt, ux, centrality); + // histos.fill(HIST("hSparseLambda_avguy"), candmass, candpt, uy, centrality); + + histos.fill(HIST("hSparseLambdaPolwgt"), candmass, candpt, Polwgt, centrality, wgtfactor); + + histos.fill(HIST("hSparseLambdaPolSP_xAwgt"), + candmass, candpt, PolSP_xAwgt, + centrality, wgtfactor); + + histos.fill(HIST("hSparseLambdaPolSP_yAwgt"), + candmass, candpt, PolSP_yAwgt, + centrality, wgtfactor); + + histos.fill(HIST("hSparseLambdaPolSP_xCwgt"), + candmass, candpt, PolSP_xCwgt, + centrality, wgtfactor); + + histos.fill(HIST("hSparseLambdaPolSP_yCwgt"), + candmass, candpt, PolSP_yCwgt, + centrality, wgtfactor); + } } } } - if (systGrp.doTopoSyst && systIDs != nullptr && !systIDs->empty()) { @@ -1219,14 +1330,9 @@ struct lambdapolsp { static_cast(isyst), wgtfactor); - histos.fill(HIST("hSparseLambdaPolwgtSyst"), - candmass, - candpt, - Polwgt, - centrality, - desbinvalue, - static_cast(isyst), - wgtfactor); + histos.fill(HIST("hSparseLambda_corr1aSyst"), candmass, candpt, sinPhiStar, centrality, desbinvalue, static_cast(isyst), wgtfactor); + histos.fill(HIST("hSparseLambda_corr1bSyst"), candmass, candpt, cosPhiStar, centrality, desbinvalue, static_cast(isyst), wgtfactor); + histos.fill(HIST("hSparseLambda_corr2aSyst"), candmass, candpt, sinThetaStar, centrality, desbinvalue, static_cast(isyst), wgtfactor); } else { @@ -1238,13 +1344,9 @@ struct lambdapolsp { static_cast(isyst), wgtfactor); - histos.fill(HIST("hSparseLambdaPolwgtSyst"), - candmass, - candpt, - Polwgt, - centrality, - static_cast(isyst), - wgtfactor); + histos.fill(HIST("hSparseLambda_corr1aSyst"), candmass, candpt, sinPhiStar, centrality, static_cast(isyst), wgtfactor); + histos.fill(HIST("hSparseLambda_corr1bSyst"), candmass, candpt, cosPhiStar, centrality, static_cast(isyst), wgtfactor); + histos.fill(HIST("hSparseLambda_corr2aSyst"), candmass, candpt, sinThetaStar, centrality, static_cast(isyst), wgtfactor); } } @@ -1262,14 +1364,9 @@ struct lambdapolsp { static_cast(isyst), wgtfactor); - histos.fill(HIST("hSparseAntiLambdaPolwgtSyst"), - candmass, - candpt, - Polwgt, - centrality, - desbinvalue, - static_cast(isyst), - wgtfactor); + histos.fill(HIST("hSparseAntiLambda_corr1aSyst"), candmass, candpt, sinPhiStar, centrality, desbinvalue, static_cast(isyst), wgtfactor); + histos.fill(HIST("hSparseAntiLambda_corr1bSyst"), candmass, candpt, cosPhiStar, centrality, desbinvalue, static_cast(isyst), wgtfactor); + histos.fill(HIST("hSparseAntiLambda_corr2aSyst"), candmass, candpt, sinThetaStar, centrality, desbinvalue, static_cast(isyst), wgtfactor); } else { @@ -1281,13 +1378,9 @@ struct lambdapolsp { static_cast(isyst), wgtfactor); - histos.fill(HIST("hSparseAntiLambdaPolwgtSyst"), - candmass, - candpt, - Polwgt, - centrality, - static_cast(isyst), - wgtfactor); + histos.fill(HIST("hSparseAntiLambda_corr1aSyst"), candmass, candpt, sinPhiStar, centrality, static_cast(isyst), wgtfactor); + histos.fill(HIST("hSparseAntiLambda_corr1bSyst"), candmass, candpt, cosPhiStar, centrality, static_cast(isyst), wgtfactor); + histos.fill(HIST("hSparseAntiLambda_corr2aSyst"), candmass, candpt, sinThetaStar, centrality, static_cast(isyst), wgtfactor); } } } diff --git a/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx b/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx index 668dd8f7541..1e967865e42 100644 --- a/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx +++ b/PWGLF/Tasks/Strangeness/lambdaspincorrderived.cxx @@ -43,6 +43,7 @@ #include #include +#include #include #include // for std::abs #include @@ -315,8 +316,127 @@ struct lambdaspincorrderived { HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + // ------------------------- + // Systematics control + // ------------------------- + + struct SysFromDeltaPtDeltaEtaDeltaPhi { + // Mixed -event kinematic cut + float minDeltaPt; + float maxDelatPt; + + float minDeltaEta; + float maxDeltaEta; + + float minDeltaPhi; + float maxDeltaPhi; + }; + + struct SysCuts { + // Topology cut + float maxDcaDaughters; + float minRadius; + float maxRadius; + float mincosPA; + float mindcaProton; + float mindcaPion; + float maxdcaV0ToPV; + }; + + std::vector sysCuts; // sysCuts[0] = default; sysCuts[1..] random unique + int nSysTotal = 1; + + void buildSystematicCuts() + { + + // 2/3 options per cut: index 0 = DEFAULT, index 1/2 = variations + // Fill these with the exact values you want (I used your def as index 0 + your old options as 1/2) + const std::array optDcaDaughter{1.00f, 0.90f}; + const std::array optminRadius{1.20f, 1.00f}; + const std::array optmaxRadius{23.0f, 35.0f}; + const std::array optcosPA{0.999f, 0.995f}; + + const std::array optdcaProton{0.07f, 0.05f, 0.08f}; + const std::array optdcaPion{0.2f, 0.1f, 0.3f}; + const std::array optdcaV0ToPV{1.2f, 1.0f, 1.4f}; + + // Helper: build SysCuts from chosen indices (0..2) + auto buildFromIdx = [&](int i0, int i1, int i2, int i3, + int i4, int i5, int i6) -> SysCuts { + SysCuts c{}; + c.maxDcaDaughters = optDcaDaughter[i0]; + c.minRadius = optminRadius[i1]; + c.maxRadius = optmaxRadius[i2]; + c.mincosPA = optcosPA[i3]; + + c.mindcaProton = optdcaProton[i4]; + c.mindcaPion = optdcaPion[i5]; + c.maxdcaV0ToPV = optdcaV0ToPV[i6]; + return c; + }; + sysCuts.clear(); + // sysId=0 must be strict default (all indices = 0) + SysCuts def = buildFromIdx(0, 0, 0, 0, 0, 0, 0); + sysCuts.push_back(def); + // sysId = 1: + sysCuts.push_back(buildFromIdx(1, 0, 0, 0, 0, 0, 0)); + // sysId = 2: + sysCuts.push_back(buildFromIdx(0, 1, 0, 0, 0, 0, 0)); + // sysId = 3 + sysCuts.push_back(buildFromIdx(0, 0, 1, 0, 0, 0, 0)); + // sysId = 4 + sysCuts.push_back(buildFromIdx(0, 0, 0, 1, 0, 0, 0)); + + // sysId = 5 + sysCuts.push_back(buildFromIdx(0, 0, 0, 0, 1, 0, 0)); + // sysId = 6 + sysCuts.push_back(buildFromIdx(0, 0, 0, 0, 2, 0, 0)); + // sysId = 7 + sysCuts.push_back(buildFromIdx(0, 0, 0, 0, 0, 1, 0)); + // sysId = 8 + sysCuts.push_back(buildFromIdx(0, 0, 0, 0, 0, 2, 0)); + // sysId = 9 + sysCuts.push_back(buildFromIdx(0, 0, 0, 0, 0, 0, 1)); + // sysId = 10 + sysCuts.push_back(buildFromIdx(0, 0, 0, 0, 0, 0, 2)); + + nSysTotal = (int)sysCuts.size(); + + // print all configurations + LOGF(info, "========================================"); + LOGF(info, "Total systematic configurations: %d", nSysTotal); + LOGF(info, "sysId=0: DEFAULT (all cuts at default)"); + LOGF(info, "sysId=1: maxDcaDaughters %.2f -> %.2f", + optDcaDaughter[0], optDcaDaughter[1]); + LOGF(info, "sysId=2: minRadius %.2f -> %.2f", + optminRadius[0], optminRadius[1]); + LOGF(info, "sysId=3: maxRadius %.2f -> %.2f", + optmaxRadius[0], optmaxRadius[1]); + LOGF(info, "sysId=4: mincosPA %.3f -> %.3f", + optcosPA[0], optcosPA[1]); + LOGF(info, "sysId=5: mindcaProton %.2f -> %.2f (tighter)", + optdcaProton[0], optdcaProton[1]); + LOGF(info, "sysId=6: mindcaProton %.2f -> %.2f (looser)", + optdcaProton[0], optdcaProton[2]); + LOGF(info, "sysId=7: mindcaPion %.2f -> %.2f (tighter)", + optdcaPion[0], optdcaPion[1]); + LOGF(info, "sysId=8: mindcaPion %.2f -> %.2f (looser)", + optdcaPion[0], optdcaPion[2]); + LOGF(info, "sysId=9: maxdcaV0ToPV %.2f -> %.2f (tighter)", + optdcaV0ToPV[0], optdcaV0ToPV[1]); + LOGF(info, "sysId=10: maxdcaV0ToPV %.2f -> %.2f (looser)", + optdcaV0ToPV[0], optdcaV0ToPV[2]); + LOGF(info, "========================================"); + } + void init(o2::framework::InitContext&) { + buildSystematicCuts(); + + nSysTotal = (int)sysCuts.size(); // or whatever vector you fill + LOGF(info, "sysCuts.size()=%zu nSysTotal=%d", sysCuts.size(), nSysTotal); + const AxisSpec thnAxisSys{nSysTotal, -0.5f, float(nSysTotal) - 0.5f, "sysId"}; + if (fillBasicQAHistos) { histos.add("hPtRadiusV0", "V0 QA;#it{p}_{T}^{V0} (GeV/#it{c});V0 decay radius (cm)", kTH2F, {{100, 0.0, 10.0}, {120, 0.0, 45.0}}); histos.add("hPtYSame", "hPtYSame", kTH2F, {{100, 0.0, 10.0}, {200, -1.0, 1.0}}); @@ -452,6 +572,17 @@ struct lambdaspincorrderived { histos.add("hSparseAntiLambdaLambdaMixed", "hSparseAntiLambdaLambdaMixed", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisR}, true); histos.add("hSparseAntiLambdaAntiLambdaMixed", "hSparseAntiLambdaAntiLambdaMixed", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisR}, true); + // Systematic THnSparse for analysis + histos.add("hSparseLambdaLambdaSys", "hSparseLambdaLambdaSys", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisR, thnAxisSys}, true); + histos.add("hSparseLambdaAntiLambdaSys", "hSparseLambdaAntiLambdaSys", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisR, thnAxisSys}, true); + histos.add("hSparseAntiLambdaLambdaSys", "hSparseAntiLambdLambdaSys", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisR, thnAxisSys}, true); + histos.add("hSparseAntiLambdaAntiLambdaSys", "hSparseAntiLambdaAntiLambdaSys", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisR, thnAxisSys}, true); + + histos.add("hSparseLambdaLambdaMixedSys", "hSparseLambdaLambdaMixedSys", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisR, thnAxisSys}, true); + histos.add("hSparseLambdaAntiLambdaMixedSys", "hSparseLambdaAntiLambdaMixedSys", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisR, thnAxisSys}, true); + histos.add("hSparseAntiLambdaLambdaMixedSys", "hSparseAntiLambdaLambdaMixedSys", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisR, thnAxisSys}, true); + histos.add("hSparseAntiLambdaAntiLambdaMixedSys", "hSparseAntiLambdaAntiLambdaMixedSys", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisR, thnAxisSys}, true); + if (fillAnalysisSparses) { histos.add("hSparseLambdaLambdaAnalysis", "hSparseLambdaLambdaAnalysis", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisDeltaR, configThnAxisDeltaRap, configThnAxisDeltaPhi}, true); histos.add("hSparseLambdaAntiLambdaAnalysis", "hSparseLambdaAntiLambdaAnalysis", HistType::kTHnSparseF, {configThnAxisInvMass, configThnAxisInvMass, configThnAxisPol, configThnAxisDeltaR, configThnAxisDeltaRap, configThnAxisDeltaPhi}, true); @@ -622,6 +753,51 @@ struct lambdaspincorrderived { return true; } + template + bool selectionV0Sys(T1 const& candidate, T2 const& SysCuts) + { + auto particle = ROOT::Math::PtEtaPhiMVector(candidate.lambdaPt(), candidate.lambdaEta(), candidate.lambdaPhi(), candidate.lambdaMass()); + if (std::abs(particle.Rapidity()) > rapidity || std::abs(particle.Eta()) > v0eta) { + return false; + } + if (candidate.lambdaMass() < MassMin || candidate.lambdaMass() > MassMax) { + return false; + } + if (candidate.v0Cospa() < SysCuts.mincosPA) { + return false; + } + if (checkDoubleStatus && candidate.doubleStatus()) { + return false; + } + if (candidate.v0Radius() > SysCuts.maxRadius) { + return false; + } + if (candidate.v0Radius() < SysCuts.minRadius) { + return false; + } + if (candidate.dcaBetweenDaughter() > SysCuts.maxDcaDaughters) { + return false; + } + + if (candidate.dcaV0ToPV() > SysCuts.maxdcaV0ToPV) { + return false; + } + + if (candidate.v0Status() == 0 && (std::abs(candidate.dcaPositive()) < SysCuts.mindcaProton || std::abs(candidate.dcaNegative()) < SysCuts.mindcaPion)) { + return false; + } + if (candidate.v0Status() == 1 && (std::abs(candidate.dcaPositive()) < SysCuts.mindcaPion || std::abs(candidate.dcaNegative()) < SysCuts.mindcaProton)) { + return false; + } + if (candidate.lambdaPt() < ptMin) { + return false; + } + if (candidate.lambdaPt() > ptMax) { + return false; + } + return true; + } + template bool checkKinematics(T1 const& c1, T2 const& c2) { @@ -1066,478 +1242,758 @@ struct lambdaspincorrderived { } } } - static inline int pairTypeCode(int tag1, int tag2) + + void fillHistogramsSys(int tag1, int tag2, + const ROOT::Math::PtEtaPhiMVector& particle1, const ROOT::Math::PtEtaPhiMVector& particle2, + const ROOT::Math::PtEtaPhiMVector& daughpart1, const ROOT::Math::PtEtaPhiMVector& daughpart2, + int datatype, float mixpairweight, int SysId, int replacedLeg = 1, int weightMapLeg = -1) { - if (tag1 == 0 && tag2 == 0) { - return 0; // LL - } else if (tag1 == 0 && tag2 == 1) { - return 1; // LAL - } else if (tag1 == 1 && tag2 == 0) { - return 2; // ALL + + auto lambda1Mass = 0.0; + auto lambda2Mass = 0.0; + if (!usePDGM) { + lambda1Mass = particle1.M(); + lambda2Mass = particle2.M(); } else { - return 3; // ALAL + lambda1Mass = o2::constants::physics::MassLambda; + lambda2Mass = o2::constants::physics::MassLambda; } - } - template - static inline bool hasSharedDaughters(const A& a, const B& b) - { - return (a.protonIndex() == b.protonIndex()) || - (a.pionIndex() == b.pionIndex()) || - (a.protonIndex() == b.pionIndex()) || - (a.pionIndex() == b.protonIndex()); - } + auto particle1Dummy = ROOT::Math::PtEtaPhiMVector(particle1.Pt(), particle1.Eta(), particle1.Phi(), lambda1Mass); + auto particle2Dummy = ROOT::Math::PtEtaPhiMVector(particle2.Pt(), particle2.Eta(), particle2.Phi(), lambda2Mass); + auto pairDummy = particle1Dummy + particle2Dummy; + ROOT::Math::Boost boostPairToCM{pairDummy.BoostToCM()}; - template - static inline bool hasSharedDaughtersMC(const A& a, const B& b) - { - return (a.protonIndexmc() == b.protonIndexmc()) || - (a.pionIndexmc() == b.pionIndexmc()) || - (a.protonIndexmc() == b.pionIndexmc()) || - (a.pionIndexmc() == b.protonIndexmc()); - } + // Step1: Boost both Lambdas to pair rest frame + auto lambda1CM = boostPairToCM(particle1Dummy); + auto lambda2CM = boostPairToCM(particle2Dummy); - ROOT::Math::PtEtaPhiMVector lambda0, proton0; - ROOT::Math::PtEtaPhiMVector lambda, proton; - ROOT::Math::PtEtaPhiMVector lambda2, proton2; + // Step2: Boost each Lambda to its own rest frame + ROOT::Math::Boost boostLambda1ToCM{lambda1CM.BoostToCM()}; + ROOT::Math::Boost boostLambda2ToCM{lambda2CM.BoostToCM()}; - Filter centralityFilter = (nabs(aod::lambdaevent::cent) < centMax && nabs(aod::lambdaevent::cent) > centMin); + // Also boost daughter protons to pair CM + auto proton1pairCM = boostPairToCM(daughpart1); + auto proton2pairCM = boostPairToCM(daughpart2); - using EventCandidates = soa::Filtered; - using AllTrackCandidates = aod::LambdaPairs; + // Then into each Lambda rest frame + auto proton1LambdaRF = boostLambda1ToCM(proton1pairCM); + auto proton2LambdaRF = boostLambda2ToCM(proton2pairCM); - void processData(EventCandidates::iterator const& collision, AllTrackCandidates const& V0s) - { - auto centrality = collision.cent(); - for (const auto& v0 : V0s) { - if (!selectionV0(v0)) { - continue; - } - if (fillBasicQAHistos) { - histos.fill(HIST("hPtRadiusV0"), v0.lambdaPt(), v0.v0Radius()); - } - if (fillBasicQAHistos) { - histos.fill(HIST("ptCent"), v0.lambdaPt(), centrality); - } - if (fillBasicQAHistos) { - histos.fill(HIST("etaCent"), v0.lambdaEta(), centrality); - } - proton = ROOT::Math::PtEtaPhiMVector(v0.protonPt(), v0.protonEta(), v0.protonPhi(), o2::constants::physics::MassProton); - lambda = ROOT::Math::PtEtaPhiMVector(v0.lambdaPt(), v0.lambdaEta(), v0.lambdaPhi(), v0.lambdaMass()); - const double phi = RecoDecay::constrainAngle(v0.lambdaPhi(), 0.0F, harmonic); - const double eta = v0.lambdaEta(); + // STAR-style alternative + ROOT::Math::Boost boostL1_LabToRF{particle1Dummy.BoostToCM()}; + ROOT::Math::Boost boostL2_LabToRF{particle2Dummy.BoostToCM()}; - if (v0.v0Status() == 0) { - histos.fill(HIST("hEtaPhiLambdaRaw"), phi, eta, getNUAWeight(0, v0.lambdaPhi(), v0.lambdaEta())); - } else { - histos.fill(HIST("hEtaPhiAntiLambdaRaw"), phi, eta, getNUAWeight(1, v0.lambdaPhi(), v0.lambdaEta())); - } - for (const auto& v02 : V0s) { - if (v02.index() <= v0.index()) { - continue; - } - if (!selectionV0(v02)) { - continue; - } - if (hasSharedDaughters(v0, v02)) - continue; - proton2 = ROOT::Math::PtEtaPhiMVector(v02.protonPt(), v02.protonEta(), v02.protonPhi(), o2::constants::physics::MassProton); - lambda2 = ROOT::Math::PtEtaPhiMVector(v02.lambdaPt(), v02.lambdaEta(), v02.lambdaPhi(), v02.lambdaMass()); - if ((v0.v0Status() == 0 && v02.v0Status() == 1) || (v0.v0Status() == 1 && v02.v0Status() == 0)) - if (fillBasicQAHistos) - histos.fill(HIST("deltaPhiSame"), RecoDecay::constrainAngle(v0.lambdaPhi() - v02.lambdaPhi(), -TMath::Pi(), harmonicDphi)); - // const int ptype = pairTypeCode(v0.v0Status(), v02.v0Status()); - if (v0.v0Status() == 0 && v02.v0Status() == 0) { - fillHistograms(0, 0, lambda, lambda2, proton, proton2, 0, 1.0); - } - if (v0.v0Status() == 0 && v02.v0Status() == 1) { - fillHistograms(0, 1, lambda, lambda2, proton, proton2, 0, 1.0); - } - if (v0.v0Status() == 1 && v02.v0Status() == 0) { - fillHistograms(0, 1, lambda2, lambda, proton2, proton, 0, 1.0); - } - if (v0.v0Status() == 1 && v02.v0Status() == 1) { - fillHistograms(1, 1, lambda, lambda2, proton, proton2, 0, 1.0); - } - } - } - } - PROCESS_SWITCH(lambdaspincorrderived, processData, "Process data", true); + auto p1_LRF = boostL1_LabToRF(daughpart1); + auto p2_LRF = boostL2_LabToRF(daughpart2); - template - void fillReplacementControlMap(int tag1, int tag2, int leg, bool isTarget, LV const& particle, float weight) - { - if (!fillReplacementQAHistos) { - return; - } - const double pt = particle.Pt(); - const double phi = RecoDecay::constrainAngle(particle.Phi(), 0.0F, harmonic); + TVector3 u1 = TVector3(p1_LRF.Px(), p1_LRF.Py(), p1_LRF.Pz()).Unit(); + TVector3 u2 = TVector3(p2_LRF.Px(), p2_LRF.Py(), p2_LRF.Pz()).Unit(); - double etaOrY = particle.Eta(); - if (userapidity) { - etaOrY = particle.Rapidity(); - } + TVector3 k1(proton1LambdaRF.Px(), proton1LambdaRF.Py(), proton1LambdaRF.Pz()); + k1 = k1.Unit(); + TVector3 k2(proton2LambdaRF.Px(), proton2LambdaRF.Py(), proton2LambdaRF.Pz()); + k2 = k2.Unit(); - if (leg == 1 && isTarget) { - if (tag1 == 0 && tag2 == 0) - histos.fill(HIST("TGT_LL_leg1"), phi, etaOrY, pt, weight); - else if (tag1 == 0 && tag2 == 1) - histos.fill(HIST("TGT_LAL_leg1"), phi, etaOrY, pt, weight); - else if (tag1 == 1 && tag2 == 0) - histos.fill(HIST("TGT_ALL_leg1"), phi, etaOrY, pt, weight); - else if (tag1 == 1 && tag2 == 1) - histos.fill(HIST("TGT_ALAL_leg1"), phi, etaOrY, pt, weight); - return; - } + double cosDeltaTheta_STAR_naive = u1.Dot(u2); + if (cosDeltaTheta_STAR_naive > 1.0) + cosDeltaTheta_STAR_naive = 111.0; + if (cosDeltaTheta_STAR_naive < -1.0) + cosDeltaTheta_STAR_naive = -111.0; - if (leg == 1 && !isTarget) { + double cosDeltaTheta_hel = k1.Dot(k2); + if (cosDeltaTheta_hel > 1.0) + cosDeltaTheta_hel = 111.0; + if (cosDeltaTheta_hel < -1.0) + cosDeltaTheta_hel = -111.0; - // Raw REP map: used to produce CCDB weight. - if (tag1 == 0 && tag2 == 0) - histos.fill(HIST("REP_LL_leg1"), phi, etaOrY, pt, weight); - else if (tag1 == 0 && tag2 == 1) - histos.fill(HIST("REP_LAL_leg1"), phi, etaOrY, pt, weight); - else if (tag1 == 1 && tag2 == 0) - histos.fill(HIST("REP_ALL_leg1"), phi, etaOrY, pt, weight); - else if (tag1 == 1 && tag2 == 1) - histos.fill(HIST("REP_ALAL_leg1"), phi, etaOrY, pt, weight); - // Correct weighted REP QA is filled in fillHistograms(), after the exact final weight is computed. - return; - } + double cosThetaDiff = (cosDef == 0) ? cosDeltaTheta_STAR_naive : cosDeltaTheta_hel; - if (leg == 2 && isTarget) { - if (tag1 == 0 && tag2 == 0) - histos.fill(HIST("TGT_LL_leg2"), phi, etaOrY, pt, weight); - else if (tag1 == 0 && tag2 == 1) - histos.fill(HIST("TGT_LAL_leg2"), phi, etaOrY, pt, weight); - else if (tag1 == 1 && tag2 == 0) - histos.fill(HIST("TGT_ALL_leg2"), phi, etaOrY, pt, weight); - else if (tag1 == 1 && tag2 == 1) - histos.fill(HIST("TGT_ALAL_leg2"), phi, etaOrY, pt, weight); - return; - } + double pt1 = particle1.Pt(); + double dphi1 = RecoDecay::constrainAngle(particle1.Phi(), 0.0F, harmonic); + double deta1 = particle1.Eta(); - if (leg == 2 && !isTarget) { + double pt2 = particle2.Pt(); + double dphi2 = RecoDecay::constrainAngle(particle2.Phi(), 0.0F, harmonic); + double deta2 = particle2.Eta(); - // Raw REP map: used to produce CCDB weight. - if (tag1 == 0 && tag2 == 0) - histos.fill(HIST("REP_LL_leg2"), phi, etaOrY, pt, weight); - else if (tag1 == 0 && tag2 == 1) - histos.fill(HIST("REP_LAL_leg2"), phi, etaOrY, pt, weight); - else if (tag1 == 1 && tag2 == 0) - histos.fill(HIST("REP_ALL_leg2"), phi, etaOrY, pt, weight); - else if (tag1 == 1 && tag2 == 1) - histos.fill(HIST("REP_ALAL_leg2"), phi, etaOrY, pt, weight); - // Correct weighted REP QA is filled in fillHistograms(), after the exact final weight is computed. - return; - } - } - template - void fillFixedLegControlMap(int tag1, int tag2, - int repLeg, - bool isTarget, - LV const& fixedParticle, - float weight) - { - if (!fillFixedLegQAHistos) { - return; - } - const double pt = fixedParticle.Pt(); - const double phi = RecoDecay::constrainAngle(fixedParticle.Phi(), 0.0F, harmonic); + double nuaWeight1 = getNUAWeight(tag1, particle1.Phi(), particle1.Eta()); + double nuaWeight2 = getNUAWeight(tag2, particle2.Phi(), particle2.Eta()); + const double pairNUAWeight = nuaWeight1 * nuaWeight2; - double etaOrY = fixedParticle.Eta(); - if (userapidity) { - etaOrY = fixedParticle.Rapidity(); - } + double dphi_pair = RecoDecay::constrainAngle(dphi1 - dphi2, -TMath::Pi(), harmonicDphi); + double deltaRap = std::abs(particle1.Rapidity() - particle2.Rapidity()); + double deltaR = TMath::Sqrt(deltaRap * deltaRap + dphi_pair * dphi_pair); - if (repLeg == 1) { - // leg1 is replaced, fixed leg is original leg2 - if (isTarget) { - if (tag1 == 0 && tag2 == 0) - histos.fill(HIST("TGT_FIX_LL_forRepLeg1"), phi, etaOrY, pt, weight); - else if (tag1 == 0 && tag2 == 1) - histos.fill(HIST("TGT_FIX_LAL_forRepLeg1"), phi, etaOrY, pt, weight); - else if (tag1 == 1 && tag2 == 0) - histos.fill(HIST("TGT_FIX_ALL_forRepLeg1"), phi, etaOrY, pt, weight); - else if (tag1 == 1 && tag2 == 1) - histos.fill(HIST("TGT_FIX_ALAL_forRepLeg1"), phi, etaOrY, pt, weight); - } else { - if (tag1 == 0 && tag2 == 0) - histos.fill(HIST("SUC_FIX_LL_forRepLeg1"), phi, etaOrY, pt, weight); - else if (tag1 == 0 && tag2 == 1) - histos.fill(HIST("SUC_FIX_LAL_forRepLeg1"), phi, etaOrY, pt, weight); - else if (tag1 == 1 && tag2 == 0) - histos.fill(HIST("SUC_FIX_ALL_forRepLeg1"), phi, etaOrY, pt, weight); - else if (tag1 == 1 && tag2 == 1) - histos.fill(HIST("SUC_FIX_ALAL_forRepLeg1"), phi, etaOrY, pt, weight); - } - return; - } + // only for weight lookup; must match fillReplacementControlMap() + double yOrEta1_forWeight = deta1; + double yOrEta2_forWeight = deta2; - if (repLeg == 2) { - // leg2 is replaced, fixed leg is original leg1 - if (isTarget) { - if (tag1 == 0 && tag2 == 0) - histos.fill(HIST("TGT_FIX_LL_forRepLeg2"), phi, etaOrY, pt, weight); - else if (tag1 == 0 && tag2 == 1) - histos.fill(HIST("TGT_FIX_LAL_forRepLeg2"), phi, etaOrY, pt, weight); - else if (tag1 == 1 && tag2 == 0) - histos.fill(HIST("TGT_FIX_ALL_forRepLeg2"), phi, etaOrY, pt, weight); - else if (tag1 == 1 && tag2 == 1) - histos.fill(HIST("TGT_FIX_ALAL_forRepLeg2"), phi, etaOrY, pt, weight); - } else { - if (tag1 == 0 && tag2 == 0) - histos.fill(HIST("SUC_FIX_LL_forRepLeg2"), phi, etaOrY, pt, weight); - else if (tag1 == 0 && tag2 == 1) - histos.fill(HIST("SUC_FIX_LAL_forRepLeg2"), phi, etaOrY, pt, weight); - else if (tag1 == 1 && tag2 == 0) - histos.fill(HIST("SUC_FIX_ALL_forRepLeg2"), phi, etaOrY, pt, weight); - else if (tag1 == 1 && tag2 == 1) - histos.fill(HIST("SUC_FIX_ALAL_forRepLeg2"), phi, etaOrY, pt, weight); - } - return; + if (userapidity) { + yOrEta1_forWeight = particle1.Rapidity(); + yOrEta2_forWeight = particle2.Rapidity(); } - } - // Processing Event Mixing - SliceCache cache; - using BinningType = ColumnBinningPolicy; - BinningType colBinning{{CfgVtxBins, CfgMultBins}, true}; - Preslice tracksPerCollisionV0 = aod::lambdapair::lambdaeventId; - void processMEV3(EventCandidates const& collisions, AllTrackCandidates const& V0s) - { - auto nBins = colBinning.getAllBinsCount(); - std::vector>> eventPools(nBins); + // `replacedLeg` is the position of the replaced candidate in the ordered pair + // passed to fillHistograms: 1 -> particle1, 2 -> particle2. + // `weightMapLeg` is the physical replacement branch used to select the CCDB map: + // 1 -> REP_*_leg1, 2 -> REP_*_leg2. This distinction is needed for unlike-sign + // pairs where the pair is reordered to Lambda-AntiLambda before filling. + const int replacedPos = replacedLeg; + const int ccdbMapLeg = (weightMapLeg > 0) ? weightMapLeg : replacedLeg; - for (auto& collision1 : collisions) { - const int bin = colBinning.getBin(std::make_tuple(collision1.posz(), collision1.cent())); - if (bin < 0) { - continue; - } + double epsWeightReplaced = 1.0; + double epsWeightFixed = 1.0; - auto poolA = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); + if (useweight && datatype == 1) { + const int wcat = getWeightCategory(tag1, tag2); - // if pool empty, push and continue - if (eventPools[bin].empty()) { - eventPools[bin].emplace_back(collision1.index(), std::move(poolA)); - if ((int)eventPools[bin].size() > nEvtMixing) { - eventPools[bin].pop_front(); + auto getRepEps = [&](int mapLeg, double phi, double yOrEta, double pt) -> double { + TH3D* h = nullptr; + if (mapLeg == 1) { + if (wcat == 0) + h = hweight1; + else if (wcat == 1) + h = hweight2; + else if (wcat == 2) + h = hweight4; + } else if (mapLeg == 2) { + if (wcat == 0) + h = hweight12; + else if (wcat == 1) + h = hweight22; + else if (wcat == 2) + h = hweight42; } - continue; - } + if (!h) { + return 1.0; + } + return h->GetBinContent(h->FindBin(phi, yOrEta, pt)); + }; - for (auto& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(poolA, poolA))) { - if (!selectionV0(t1) || !selectionV0(t2)) { - continue; + auto getFixedEps = [&](int mapLeg, double phi, double yOrEta, double pt) -> double { + TH3D* h = nullptr; + if (mapLeg == 1) { + if (wcat == 0) + h = gFixedLLRep1; + else if (wcat == 1) + h = gFixedULRep1; + else if (wcat == 2) + h = gFixedALALRep1; + } else if (mapLeg == 2) { + if (wcat == 0) + h = gFixedLLRep2; + else if (wcat == 1) + h = gFixedULRep2; + else if (wcat == 2) + h = gFixedALALRep2; } - if (t2.index() <= t1.index()) { - continue; + if (!h) { + return 1.0; } - if (hasSharedDaughters(t1, t2)) - continue; - const bool doMixLeg1 = (cfgMixLegMode.value == 0 || cfgMixLegMode.value == 2); - const bool doMixLeg2 = (cfgMixLegMode.value == 1 || cfgMixLegMode.value == 2); + return h->GetBinContent(h->FindBin(phi, yOrEta, pt)); + }; - struct PV { - AllTrackCandidates* pool; - int nRepl1 = 0; - int nRepl2 = 0; - }; + const double phiRep = (replacedPos == 2) ? dphi2 : dphi1; + const double yRep = (replacedPos == 2) ? yOrEta2_forWeight : yOrEta1_forWeight; + const double ptRep = (replacedPos == 2) ? pt2 : pt1; + epsWeightReplaced = getRepEps(ccdbMapLeg, phiRep, yRep, ptRep); - std::vector usable; - int totalRepl = 0; - int totalRepl1 = 0; - int totalRepl2 = 0; + if (cfgCcdbParam.useFixedWeight) { + const int fixedPos = (replacedPos == 2) ? 1 : 2; + const double phiFix = (fixedPos == 2) ? dphi2 : dphi1; + const double yFix = (fixedPos == 2) ? yOrEta2_forWeight : yOrEta1_forWeight; + const double ptFix = (fixedPos == 2) ? pt2 : pt1; + epsWeightFixed = getFixedEps(ccdbMapLeg, phiFix, yFix, ptFix); + } + } - int mixes = 0; - for (auto it = eventPools[bin].rbegin(); it != eventPools[bin].rend() && mixes < nEvtMixing; ++it, ++mixes) { - const int collision2idx = it->first; - auto& poolB = it->second; + if (datatype == 0) { + const double weight = pairNUAWeight; + if (tag1 == 0 && tag2 == 0) { + histos.fill(HIST("hSparseLambdaLambdaSys"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, SysId, weight); + } else if (tag1 == 0 && tag2 == 1) { + histos.fill(HIST("hSparseLambdaAntiLambdaSys"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, SysId, weight); + } else if (tag1 == 1 && tag2 == 0) { + histos.fill(HIST("hSparseAntiLambdaLambdaSys"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, SysId, weight); + } else if (tag1 == 1 && tag2 == 1) { + histos.fill(HIST("hSparseAntiLambdaAntiLambdaSys"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, SysId, weight); + } - if (collision2idx == collision1.index()) { - continue; - } + } else if (datatype == 1) { + double weight = mixpairweight; - int nRepl1 = 0; - int nRepl2 = 0; + if (useweight) { + const double epsWeightTotal = epsWeightReplaced * epsWeightFixed; - for (auto& tX : poolB) { - if (!selectionV0(tX)) { - continue; - } + if (!std::isfinite(epsWeightTotal) || epsWeightTotal <= 0.0) { + return; + } + weight = mixpairweight / epsWeightTotal; + } - if (doMixLeg1) { - // Single-track replacement: replace a candidate only by the same species. - if (tX.v0Status() == t1.v0Status() && checkKinematics(t1, tX)) { - ++nRepl1; - } - } + // This is the pure mixing-correction weight. + // Do not include NUA here, because TGT/REP/FIX QA maps were filled without NUA. + const double weightMixingQA = weight; - if (doMixLeg2) { - // Single-track replacement: replace a candidate only by the same species. - if (tX.v0Status() == t2.v0Status() && checkKinematics(t2, tX)) { - ++nRepl2; - } - } - } + if (useweight) { + fillFinalWeightedMixingQA(tag1, tag2, ccdbMapLeg, replacedPos, particle1, particle2, weightMixingQA); + } - if (nRepl1 > 0 || nRepl2 > 0) { - usable.push_back(PV{&poolB, nRepl1, nRepl2}); - totalRepl += nRepl1 + nRepl2; - totalRepl1 += nRepl1; - totalRepl2 += nRepl2; - } - } + weight *= pairNUAWeight; + if (!std::isfinite(weight) || weight <= 0.0) { + return; + } - if (totalRepl <= 0) { - continue; - } + if (tag1 == 0 && tag2 == 0) { + histos.fill(HIST("hSparseLambdaLambdaMixedSys"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, SysId, weight); + } else if (tag1 == 0 && tag2 == 1) { + histos.fill(HIST("hSparseLambdaAntiLambdaMixedSys"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, SysId, weight); + } else if (tag1 == 1 && tag2 == 0) { + histos.fill(HIST("hSparseAntiLambdaLambdaMixedSys"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, SysId, weight); + } else if (tag1 == 1 && tag2 == 1) { + histos.fill(HIST("hSparseAntiLambdaAntiLambdaMixedSys"), particle1.M(), particle2.M(), cosThetaDiff, deltaR, SysId, weight); + } + } + } - const float wBase = 1.0f / static_cast(totalRepl); + static inline int pairTypeCode(int tag1, int tag2) + { + if (tag1 == 0 && tag2 == 0) { + return 0; // LL + } else if (tag1 == 0 && tag2 == 1) { + return 1; // LAL + } else if (tag1 == 1 && tag2 == 0) { + return 2; // ALL + } else { + return 3; // ALAL + } + } - // Single-track replacement target must use the same branch normalization - // as the actually used replacement candidates. Per SE pair: - // sum REP_leg1 weights = totalRepl1 / totalRepl - // sum REP_leg2 weights = totalRepl2 / totalRepl - // Therefore TGT leg1/leg2 are filled with the same weights. - if (doMixLeg1 && totalRepl1 > 0) { - fillReplacementControlMap(t1.v0Status(), t2.v0Status(), 1, true, - ROOT::Math::PtEtaPhiMVector(t1.lambdaPt(), t1.lambdaEta(), t1.lambdaPhi(), t1.lambdaMass()), - static_cast(totalRepl1) * wBase); - fillFixedLegControlMap(t1.v0Status(), t2.v0Status(), 1, true, - ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), t2.lambdaMass()), - static_cast(totalRepl1) * wBase); + template + static inline bool hasSharedDaughters(const A& a, const B& b) + { + return (a.protonIndex() == b.protonIndex()) || + (a.pionIndex() == b.pionIndex()) || + (a.protonIndex() == b.pionIndex()) || + (a.pionIndex() == b.protonIndex()); + } + + template + static inline bool hasSharedDaughtersMC(const A& a, const B& b) + { + return (a.protonIndexmc() == b.protonIndexmc()) || + (a.pionIndexmc() == b.pionIndexmc()) || + (a.protonIndexmc() == b.pionIndexmc()) || + (a.pionIndexmc() == b.protonIndexmc()); + } + + ROOT::Math::PtEtaPhiMVector lambda0, proton0; + ROOT::Math::PtEtaPhiMVector lambda, proton; + ROOT::Math::PtEtaPhiMVector lambda2, proton2; + + Filter centralityFilter = (nabs(aod::lambdaevent::cent) < centMax && nabs(aod::lambdaevent::cent) > centMin); + + using EventCandidates = soa::Filtered; + using AllTrackCandidates = aod::LambdaPairs; + + void processData(EventCandidates::iterator const& collision, AllTrackCandidates const& V0s) + { + auto centrality = collision.cent(); + for (const auto& v0 : V0s) { + if (!selectionV0(v0)) { + continue; + } + if (fillBasicQAHistos) { + histos.fill(HIST("hPtRadiusV0"), v0.lambdaPt(), v0.v0Radius()); + } + if (fillBasicQAHistos) { + histos.fill(HIST("ptCent"), v0.lambdaPt(), centrality); + } + if (fillBasicQAHistos) { + histos.fill(HIST("etaCent"), v0.lambdaEta(), centrality); + } + proton = ROOT::Math::PtEtaPhiMVector(v0.protonPt(), v0.protonEta(), v0.protonPhi(), o2::constants::physics::MassProton); + lambda = ROOT::Math::PtEtaPhiMVector(v0.lambdaPt(), v0.lambdaEta(), v0.lambdaPhi(), v0.lambdaMass()); + const double phi = RecoDecay::constrainAngle(v0.lambdaPhi(), 0.0F, harmonic); + const double eta = v0.lambdaEta(); + + if (v0.v0Status() == 0) { + histos.fill(HIST("hEtaPhiLambdaRaw"), phi, eta, getNUAWeight(0, v0.lambdaPhi(), v0.lambdaEta())); + } else { + histos.fill(HIST("hEtaPhiAntiLambdaRaw"), phi, eta, getNUAWeight(1, v0.lambdaPhi(), v0.lambdaEta())); + } + for (const auto& v02 : V0s) { + if (v02.index() <= v0.index()) { + continue; } - if (doMixLeg2 && totalRepl2 > 0) { - fillReplacementControlMap(t1.v0Status(), t2.v0Status(), 2, true, - ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), t2.lambdaMass()), - static_cast(totalRepl2) * wBase); - fillFixedLegControlMap(t1.v0Status(), t2.v0Status(), 2, true, - ROOT::Math::PtEtaPhiMVector(t1.lambdaPt(), t1.lambdaEta(), t1.lambdaPhi(), t1.lambdaMass()), - static_cast(totalRepl2) * wBase); + if (!selectionV0(v02)) { + continue; + } + if (hasSharedDaughters(v0, v02)) + continue; + proton2 = ROOT::Math::PtEtaPhiMVector(v02.protonPt(), v02.protonEta(), v02.protonPhi(), o2::constants::physics::MassProton); + lambda2 = ROOT::Math::PtEtaPhiMVector(v02.lambdaPt(), v02.lambdaEta(), v02.lambdaPhi(), v02.lambdaMass()); + if ((v0.v0Status() == 0 && v02.v0Status() == 1) || (v0.v0Status() == 1 && v02.v0Status() == 0)) + if (fillBasicQAHistos) + histos.fill(HIST("deltaPhiSame"), RecoDecay::constrainAngle(v0.lambdaPhi() - v02.lambdaPhi(), -TMath::Pi(), harmonicDphi)); + // const int ptype = pairTypeCode(v0.v0Status(), v02.v0Status()); + if (v0.v0Status() == 0 && v02.v0Status() == 0) { + fillHistograms(0, 0, lambda, lambda2, proton, proton2, 0, 1.0); + } + if (v0.v0Status() == 0 && v02.v0Status() == 1) { + fillHistograms(0, 1, lambda, lambda2, proton, proton2, 0, 1.0); + } + if (v0.v0Status() == 1 && v02.v0Status() == 0) { + fillHistograms(0, 1, lambda2, lambda, proton2, proton, 0, 1.0); + } + if (v0.v0Status() == 1 && v02.v0Status() == 1) { + fillHistograms(1, 1, lambda, lambda2, proton, proton2, 0, 1.0); } + } + } + } + PROCESS_SWITCH(lambdaspincorrderived, processData, "Process data", true); - for (auto& pv : usable) { - auto& poolB = *pv.pool; + void processDataSys(EventCandidates::iterator const&, AllTrackCandidates const& V0s) + { + for (const auto& v0 : V0s) { - for (auto& tX : poolB) { - if (!selectionV0(tX)) { - continue; - } + std::vector activeSys; + activeSys.reserve((size_t)nSysTotal); - // -------- leg-1 replacement: (tX, t2) - if (doMixLeg1) { - if (tX.v0Status() == t1.v0Status() && checkKinematics(t1, tX)) { - fillReplacementControlMap(tX.v0Status(), t2.v0Status(), 1, false, - ROOT::Math::PtEtaPhiMVector(tX.lambdaPt(), tX.lambdaEta(), tX.lambdaPhi(), tX.lambdaMass()), - wBase); - auto proton = ROOT::Math::PtEtaPhiMVector(tX.protonPt(), tX.protonEta(), tX.protonPhi(), - o2::constants::physics::MassProton); - auto lambda = ROOT::Math::PtEtaPhiMVector(tX.lambdaPt(), tX.lambdaEta(), tX.lambdaPhi(), - tX.lambdaMass()); - auto proton2 = ROOT::Math::PtEtaPhiMVector(t2.protonPt(), t2.protonEta(), t2.protonPhi(), - o2::constants::physics::MassProton); - auto lambda2 = ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), - t2.lambdaMass()); + for (int sysId = 0; sysId < nSysTotal; ++sysId) { + const auto& sc = sysCuts[sysId]; + if (selectionV0Sys(v0, sc)) { + activeSys.push_back(sysId); + } + } - const float dPhi = RecoDecay::constrainAngle( - RecoDecay::constrainAngle(lambda.Phi(), 0.0F, harmonic) - - RecoDecay::constrainAngle(lambda2.Phi(), 0.0F, harmonic), - -TMath::Pi(), harmonicDphi); + if (activeSys.empty()) + continue; - if (fillBasicQAHistos) - histos.fill(HIST("deltaPhiMix"), dPhi, wBase); - fillHistograms(tX.v0Status(), t2.v0Status(), - lambda, lambda2, proton, proton2, - 1, wBase, 1); - } - } + proton = ROOT::Math::PtEtaPhiMVector(v0.protonPt(), v0.protonEta(), v0.protonPhi(), + o2::constants::physics::MassProton); + lambda = ROOT::Math::PtEtaPhiMVector(v0.lambdaPt(), v0.lambdaEta(), v0.lambdaPhi(), + v0.lambdaMass()); - // -------- leg-2 replacement: (t1, tX) - if (doMixLeg2) { - if (tX.v0Status() == t2.v0Status() && checkKinematics(t2, tX)) { - fillReplacementControlMap(t1.v0Status(), tX.v0Status(), 2, false, - ROOT::Math::PtEtaPhiMVector(tX.lambdaPt(), tX.lambdaEta(), tX.lambdaPhi(), tX.lambdaMass()), - wBase); - auto proton = ROOT::Math::PtEtaPhiMVector(t1.protonPt(), t1.protonEta(), t1.protonPhi(), - o2::constants::physics::MassProton); - auto lambda = ROOT::Math::PtEtaPhiMVector(t1.lambdaPt(), t1.lambdaEta(), t1.lambdaPhi(), - t1.lambdaMass()); - auto proton2 = ROOT::Math::PtEtaPhiMVector(tX.protonPt(), tX.protonEta(), tX.protonPhi(), - o2::constants::physics::MassProton); - auto lambda2 = ROOT::Math::PtEtaPhiMVector(tX.lambdaPt(), tX.lambdaEta(), tX.lambdaPhi(), - tX.lambdaMass()); + for (const auto& v02 : V0s) { + if (v02.index() <= v0.index()) + continue; + if (hasSharedDaughters(v0, v02)) + continue; - const float dPhi = RecoDecay::constrainAngle( - RecoDecay::constrainAngle(lambda.Phi(), 0.0F, harmonic) - - RecoDecay::constrainAngle(lambda2.Phi(), 0.0F, harmonic), - -TMath::Pi(), harmonicDphi); + std::vector activePair; + activePair.reserve(activeSys.size()); - if (fillBasicQAHistos) - histos.fill(HIST("deltaPhiMix"), dPhi, wBase); - fillHistograms(t1.v0Status(), tX.v0Status(), - lambda, lambda2, proton, proton2, - 1, wBase, 2); - } - } + for (const auto& sysId : activeSys) { + const auto& sc = sysCuts[sysId]; + if (selectionV0Sys(v02, sc)) { + activePair.push_back(sysId); } } - } - // push current event into pool - auto sliced = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); - eventPools[bin].emplace_back(collision1.index(), std::move(sliced)); - if ((int)eventPools[bin].size() > nEvtMixing) { - eventPools[bin].pop_front(); + if (activePair.empty()) { + continue; + } + + proton2 = ROOT::Math::PtEtaPhiMVector(v02.protonPt(), v02.protonEta(), v02.protonPhi(), + o2::constants::physics::MassProton); + lambda2 = ROOT::Math::PtEtaPhiMVector(v02.lambdaPt(), v02.lambdaEta(), v02.lambdaPhi(), + v02.lambdaMass()); + + for (const auto& sysId : activePair) { + + if (v0.v0Status() == 0 && v02.v0Status() == 0) { + fillHistogramsSys(0, 0, lambda, lambda2, proton, proton2, 0, 1.0, sysId); + } else if (v0.v0Status() == 0 && v02.v0Status() == 1) { + fillHistogramsSys(0, 1, lambda, lambda2, proton, proton2, 0, 1.0, sysId); + } else if (v0.v0Status() == 1 && v02.v0Status() == 0) { + fillHistogramsSys(0, 1, lambda2, lambda, proton2, proton, 0, 1.0, sysId); + } else if (v0.v0Status() == 1 && v02.v0Status() == 1) { + fillHistogramsSys(1, 1, lambda, lambda2, proton, proton2, 0, 1.0, sysId); + } + } } } } - PROCESS_SWITCH(lambdaspincorrderived, processMEV3, "Process data ME (first-leg, pair-3D maps)", false); - - static constexpr int N_STATUS = 2; // v0Status ∈ {0,1} - struct MatchRef { - int64_t collisionIdx; - int64_t rowIndex; - }; + PROCESS_SWITCH(lambdaspincorrderived, processDataSys, "Process Sys analysis", true); - static inline void limitMatchesToNEvents(std::vector& matches, int nMixEvents) + template + void fillReplacementControlMap(int tag1, int tag2, int leg, bool isTarget, LV const& particle, float weight) { - if (nMixEvents <= 0 || matches.empty()) { + + if (!fillReplacementQAHistos) { return; } - std::vector kept; - kept.reserve(matches.size()); + const double pt = particle.Pt(); + const double phi = RecoDecay::constrainAngle(particle.Phi(), 0.0F, harmonic); - std::unordered_set usedEvents; - usedEvents.reserve(nMixEvents * 2); + double etaOrY = particle.Eta(); + if (userapidity) { + etaOrY = particle.Rapidity(); + } - for (const auto& m : matches) { - if (usedEvents.count(m.collisionIdx) || (int)usedEvents.size() < nMixEvents) { - kept.push_back(m); - usedEvents.insert(m.collisionIdx); - } + if (leg == 1 && isTarget) { + if (tag1 == 0 && tag2 == 0) + histos.fill(HIST("TGT_LL_leg1"), phi, etaOrY, pt, weight); + else if (tag1 == 0 && tag2 == 1) + histos.fill(HIST("TGT_LAL_leg1"), phi, etaOrY, pt, weight); + else if (tag1 == 1 && tag2 == 0) + histos.fill(HIST("TGT_ALL_leg1"), phi, etaOrY, pt, weight); + else if (tag1 == 1 && tag2 == 1) + histos.fill(HIST("TGT_ALAL_leg1"), phi, etaOrY, pt, weight); + return; } - matches.swap(kept); - } - struct MixBinnerR { - float ptMin, ptMax, ptStep; - float etaMin, etaMax, etaStep; - float phiMin, phiMax, phiStep; + if (leg == 1 && !isTarget) { - float mMin, mMax, mStep; - int nM_; + // Raw REP map: used to produce CCDB weight. + if (tag1 == 0 && tag2 == 0) + histos.fill(HIST("REP_LL_leg1"), phi, etaOrY, pt, weight); + else if (tag1 == 0 && tag2 == 1) + histos.fill(HIST("REP_LAL_leg1"), phi, etaOrY, pt, weight); + else if (tag1 == 1 && tag2 == 0) + histos.fill(HIST("REP_ALL_leg1"), phi, etaOrY, pt, weight); + else if (tag1 == 1 && tag2 == 1) + histos.fill(HIST("REP_ALAL_leg1"), phi, etaOrY, pt, weight); + // Correct weighted REP QA is filled in fillHistograms(), after the exact final weight is computed. + return; + } - std::vector rEdges; - int nR_; + if (leg == 2 && isTarget) { + if (tag1 == 0 && tag2 == 0) + histos.fill(HIST("TGT_LL_leg2"), phi, etaOrY, pt, weight); + else if (tag1 == 0 && tag2 == 1) + histos.fill(HIST("TGT_LAL_leg2"), phi, etaOrY, pt, weight); + else if (tag1 == 1 && tag2 == 0) + histos.fill(HIST("TGT_ALL_leg2"), phi, etaOrY, pt, weight); + else if (tag1 == 1 && tag2 == 1) + histos.fill(HIST("TGT_ALAL_leg2"), phi, etaOrY, pt, weight); + return; + } - int nPt_, nEta_, nPhi_; + if (leg == 2 && !isTarget) { - MixBinnerR(float ptMin_, float ptMax_, float ptStep_, - float etaAbsMax, float etaStep_, - float phiStep_, - float mMin_, float mMax_, int nMassBins_, - std::vector rEdges_) + // Raw REP map: used to produce CCDB weight. + if (tag1 == 0 && tag2 == 0) + histos.fill(HIST("REP_LL_leg2"), phi, etaOrY, pt, weight); + else if (tag1 == 0 && tag2 == 1) + histos.fill(HIST("REP_LAL_leg2"), phi, etaOrY, pt, weight); + else if (tag1 == 1 && tag2 == 0) + histos.fill(HIST("REP_ALL_leg2"), phi, etaOrY, pt, weight); + else if (tag1 == 1 && tag2 == 1) + histos.fill(HIST("REP_ALAL_leg2"), phi, etaOrY, pt, weight); + // Correct weighted REP QA is filled in fillHistograms(), after the exact final weight is computed. + return; + } + } + template + void fillFixedLegControlMap(int tag1, int tag2, + int repLeg, + bool isTarget, + LV const& fixedParticle, + float weight) + { + if (!fillFixedLegQAHistos) { + return; + } + const double pt = fixedParticle.Pt(); + const double phi = RecoDecay::constrainAngle(fixedParticle.Phi(), 0.0F, harmonic); + + double etaOrY = fixedParticle.Eta(); + if (userapidity) { + etaOrY = fixedParticle.Rapidity(); + } + + if (repLeg == 1) { + // leg1 is replaced, fixed leg is original leg2 + if (isTarget) { + if (tag1 == 0 && tag2 == 0) + histos.fill(HIST("TGT_FIX_LL_forRepLeg1"), phi, etaOrY, pt, weight); + else if (tag1 == 0 && tag2 == 1) + histos.fill(HIST("TGT_FIX_LAL_forRepLeg1"), phi, etaOrY, pt, weight); + else if (tag1 == 1 && tag2 == 0) + histos.fill(HIST("TGT_FIX_ALL_forRepLeg1"), phi, etaOrY, pt, weight); + else if (tag1 == 1 && tag2 == 1) + histos.fill(HIST("TGT_FIX_ALAL_forRepLeg1"), phi, etaOrY, pt, weight); + } else { + if (tag1 == 0 && tag2 == 0) + histos.fill(HIST("SUC_FIX_LL_forRepLeg1"), phi, etaOrY, pt, weight); + else if (tag1 == 0 && tag2 == 1) + histos.fill(HIST("SUC_FIX_LAL_forRepLeg1"), phi, etaOrY, pt, weight); + else if (tag1 == 1 && tag2 == 0) + histos.fill(HIST("SUC_FIX_ALL_forRepLeg1"), phi, etaOrY, pt, weight); + else if (tag1 == 1 && tag2 == 1) + histos.fill(HIST("SUC_FIX_ALAL_forRepLeg1"), phi, etaOrY, pt, weight); + } + return; + } + + if (repLeg == 2) { + // leg2 is replaced, fixed leg is original leg1 + if (isTarget) { + if (tag1 == 0 && tag2 == 0) + histos.fill(HIST("TGT_FIX_LL_forRepLeg2"), phi, etaOrY, pt, weight); + else if (tag1 == 0 && tag2 == 1) + histos.fill(HIST("TGT_FIX_LAL_forRepLeg2"), phi, etaOrY, pt, weight); + else if (tag1 == 1 && tag2 == 0) + histos.fill(HIST("TGT_FIX_ALL_forRepLeg2"), phi, etaOrY, pt, weight); + else if (tag1 == 1 && tag2 == 1) + histos.fill(HIST("TGT_FIX_ALAL_forRepLeg2"), phi, etaOrY, pt, weight); + } else { + if (tag1 == 0 && tag2 == 0) + histos.fill(HIST("SUC_FIX_LL_forRepLeg2"), phi, etaOrY, pt, weight); + else if (tag1 == 0 && tag2 == 1) + histos.fill(HIST("SUC_FIX_LAL_forRepLeg2"), phi, etaOrY, pt, weight); + else if (tag1 == 1 && tag2 == 0) + histos.fill(HIST("SUC_FIX_ALL_forRepLeg2"), phi, etaOrY, pt, weight); + else if (tag1 == 1 && tag2 == 1) + histos.fill(HIST("SUC_FIX_ALAL_forRepLeg2"), phi, etaOrY, pt, weight); + } + return; + } + } + // Processing Event Mixing + SliceCache cache; + using BinningType = ColumnBinningPolicy; + BinningType colBinning{{CfgVtxBins, CfgMultBins}, true}; + Preslice tracksPerCollisionV0 = aod::lambdapair::lambdaeventId; + + void processMEV3(EventCandidates const& collisions, AllTrackCandidates const& V0s) + { + auto nBins = colBinning.getAllBinsCount(); + std::vector>> eventPools(nBins); + + for (const auto& collision1 : collisions) { + const int bin = colBinning.getBin(std::make_tuple(collision1.posz(), collision1.cent())); + if (bin < 0) { + continue; + } + + auto poolA = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); + + // if pool empty, push and continue + if (eventPools[bin].empty()) { + eventPools[bin].emplace_back(collision1.index(), std::move(poolA)); + if ((int)eventPools[bin].size() > nEvtMixing) { + eventPools[bin].pop_front(); + } + continue; + } + + for (const auto& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(poolA, poolA))) { + if (!selectionV0(t1) || !selectionV0(t2)) { + continue; + } + if (t2.index() <= t1.index()) { + continue; + } + if (hasSharedDaughters(t1, t2)) + continue; + const bool doMixLeg1 = (cfgMixLegMode.value == 0 || cfgMixLegMode.value == 2); + const bool doMixLeg2 = (cfgMixLegMode.value == 1 || cfgMixLegMode.value == 2); + + struct PV { + AllTrackCandidates* pool; + int nRepl1 = 0; + int nRepl2 = 0; + }; + + std::vector usable; + int totalRepl = 0; + int totalRepl1 = 0; + int totalRepl2 = 0; + + int mixes = 0; + for (auto it = eventPools[bin].rbegin(); it != eventPools[bin].rend() && mixes < nEvtMixing; ++it, ++mixes) { + const int collision2idx = it->first; + auto& poolB = it->second; + + if (collision2idx == collision1.index()) { + continue; + } + + int nRepl1 = 0; + int nRepl2 = 0; + + for (const auto& tX : poolB) { + if (!selectionV0(tX)) { + continue; + } + + if (doMixLeg1) { + // Single-track replacement: replace a candidate only by the same species. + if (tX.v0Status() == t1.v0Status() && checkKinematics(t1, tX)) { + ++nRepl1; + } + } + + if (doMixLeg2) { + // Single-track replacement: replace a candidate only by the same species. + if (tX.v0Status() == t2.v0Status() && checkKinematics(t2, tX)) { + ++nRepl2; + } + } + } + + if (nRepl1 > 0 || nRepl2 > 0) { + usable.push_back(PV{&poolB, nRepl1, nRepl2}); + totalRepl += nRepl1 + nRepl2; + totalRepl1 += nRepl1; + totalRepl2 += nRepl2; + } + } + + if (totalRepl <= 0) { + continue; + } + + const float wBase = 1.0f / static_cast(totalRepl); + + // Single-track replacement target must use the same branch normalization + // as the actually used replacement candidates. Per SE pair: + // sum REP_leg1 weights = totalRepl1 / totalRepl + // sum REP_leg2 weights = totalRepl2 / totalRepl + // Therefore TGT leg1/leg2 are filled with the same weights. + if (doMixLeg1 && totalRepl1 > 0) { + fillReplacementControlMap(t1.v0Status(), t2.v0Status(), 1, true, + ROOT::Math::PtEtaPhiMVector(t1.lambdaPt(), t1.lambdaEta(), t1.lambdaPhi(), t1.lambdaMass()), + static_cast(totalRepl1) * wBase); + fillFixedLegControlMap(t1.v0Status(), t2.v0Status(), 1, true, + ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), t2.lambdaMass()), + static_cast(totalRepl1) * wBase); + } + if (doMixLeg2 && totalRepl2 > 0) { + fillReplacementControlMap(t1.v0Status(), t2.v0Status(), 2, true, + ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), t2.lambdaMass()), + static_cast(totalRepl2) * wBase); + fillFixedLegControlMap(t1.v0Status(), t2.v0Status(), 2, true, + ROOT::Math::PtEtaPhiMVector(t1.lambdaPt(), t1.lambdaEta(), t1.lambdaPhi(), t1.lambdaMass()), + static_cast(totalRepl2) * wBase); + } + + for (const auto& pv : usable) { + auto& poolB = *pv.pool; + + for (const auto& tX : poolB) { + if (!selectionV0(tX)) { + continue; + } + + // -------- leg-1 replacement: (tX, t2) + if (doMixLeg1) { + if (tX.v0Status() == t1.v0Status() && checkKinematics(t1, tX)) { + fillReplacementControlMap(tX.v0Status(), t2.v0Status(), 1, false, + ROOT::Math::PtEtaPhiMVector(tX.lambdaPt(), tX.lambdaEta(), tX.lambdaPhi(), tX.lambdaMass()), + wBase); + auto proton = ROOT::Math::PtEtaPhiMVector(tX.protonPt(), tX.protonEta(), tX.protonPhi(), + o2::constants::physics::MassProton); + auto lambda = ROOT::Math::PtEtaPhiMVector(tX.lambdaPt(), tX.lambdaEta(), tX.lambdaPhi(), + tX.lambdaMass()); + auto proton2 = ROOT::Math::PtEtaPhiMVector(t2.protonPt(), t2.protonEta(), t2.protonPhi(), + o2::constants::physics::MassProton); + auto lambda2 = ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), + t2.lambdaMass()); + + const float dPhi = RecoDecay::constrainAngle( + RecoDecay::constrainAngle(lambda.Phi(), 0.0F, harmonic) - + RecoDecay::constrainAngle(lambda2.Phi(), 0.0F, harmonic), + -TMath::Pi(), harmonicDphi); + + if (fillBasicQAHistos) + histos.fill(HIST("deltaPhiMix"), dPhi, wBase); + fillHistograms(tX.v0Status(), t2.v0Status(), + lambda, lambda2, proton, proton2, + 1, wBase, 1); + } + } + + // -------- leg-2 replacement: (t1, tX) + if (doMixLeg2) { + if (tX.v0Status() == t2.v0Status() && checkKinematics(t2, tX)) { + fillReplacementControlMap(t1.v0Status(), tX.v0Status(), 2, false, + ROOT::Math::PtEtaPhiMVector(tX.lambdaPt(), tX.lambdaEta(), tX.lambdaPhi(), tX.lambdaMass()), + wBase); + auto proton = ROOT::Math::PtEtaPhiMVector(t1.protonPt(), t1.protonEta(), t1.protonPhi(), + o2::constants::physics::MassProton); + auto lambda = ROOT::Math::PtEtaPhiMVector(t1.lambdaPt(), t1.lambdaEta(), t1.lambdaPhi(), + t1.lambdaMass()); + auto proton2 = ROOT::Math::PtEtaPhiMVector(tX.protonPt(), tX.protonEta(), tX.protonPhi(), + o2::constants::physics::MassProton); + auto lambda2 = ROOT::Math::PtEtaPhiMVector(tX.lambdaPt(), tX.lambdaEta(), tX.lambdaPhi(), + tX.lambdaMass()); + + const float dPhi = RecoDecay::constrainAngle( + RecoDecay::constrainAngle(lambda.Phi(), 0.0F, harmonic) - + RecoDecay::constrainAngle(lambda2.Phi(), 0.0F, harmonic), + -TMath::Pi(), harmonicDphi); + + if (fillBasicQAHistos) + histos.fill(HIST("deltaPhiMix"), dPhi, wBase); + fillHistograms(t1.v0Status(), tX.v0Status(), + lambda, lambda2, proton, proton2, + 1, wBase, 2); + } + } + } + } + } + + // push current event into pool + auto sliced = V0s.sliceBy(tracksPerCollisionV0, collision1.index()); + eventPools[bin].emplace_back(collision1.index(), std::move(sliced)); + if ((int)eventPools[bin].size() > nEvtMixing) { + eventPools[bin].pop_front(); + } + } + } + PROCESS_SWITCH(lambdaspincorrderived, processMEV3, "Process data ME (first-leg, pair-3D maps)", false); + + static constexpr int N_STATUS = 2; // v0Status ∈ {0,1} + struct MatchRef { + int64_t collisionIdx; + int64_t rowIndex; + }; + + static inline void limitMatchesToNEvents(std::vector& matches, int nMixEvents) + { + if (nMixEvents <= 0 || matches.empty()) { + return; + } + std::vector kept; + kept.reserve(matches.size()); + + std::unordered_set usedEvents; + usedEvents.reserve(nMixEvents * 2); + + for (const auto& m : matches) { + if (usedEvents.count(m.collisionIdx) || (int)usedEvents.size() < nMixEvents) { + kept.push_back(m); + usedEvents.insert(m.collisionIdx); + } + } + matches.swap(kept); + } + + struct MixBinnerR { + float ptMin, ptMax, ptStep; + float etaMin, etaMax, etaStep; + float phiMin, phiMax, phiStep; + + float mMin, mMax, mStep; + int nM_; + + std::vector rEdges; + int nR_; + + int nPt_, nEta_, nPhi_; + + MixBinnerR(float ptMin_, float ptMax_, float ptStep_, + float etaAbsMax, float etaStep_, + float phiStep_, + float mMin_, float mMax_, int nMassBins_, + std::vector rEdges_) : ptMin(ptMin_), ptMax(ptMax_), ptStep(ptStep_), @@ -1561,576 +2017,1116 @@ struct lambdaspincorrderived { etaStep = (etaStep > 0.f ? etaStep : 0.1f); phiStep = (phiStep > 0.f ? phiStep : 0.1f); - if (!(mMax > mMin)) { - mMin = 1.09f; - mMax = 1.14f; - } - mStep = (mMax - mMin) / static_cast(nM_); - if (!(mStep > 0.f)) { - nM_ = 5; - mMin = 1.09f; - mMax = 1.14f; - mStep = (mMax - mMin) / static_cast(nM_); - } + if (!(mMax > mMin)) { + mMin = 1.09f; + mMax = 1.14f; + } + mStep = (mMax - mMin) / static_cast(nM_); + if (!(mStep > 0.f)) { + nM_ = 5; + mMin = 1.09f; + mMax = 1.14f; + mStep = (mMax - mMin) / static_cast(nM_); + } + + if (rEdges.size() < 2) { + rEdges = {3.0, 5.0, 7.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0}; + } + nR_ = static_cast(rEdges.size()) - 1; + + nPt_ = std::max(1, static_cast(std::floor((ptMax - ptMin) / ptStep + 0.5f))); + nEta_ = std::max(1, static_cast(std::floor((etaMax - etaMin) / etaStep + 0.5f))); + nPhi_ = std::max(1, static_cast(std::ceil((phiMax - phiMin) / phiStep))); + } + + inline int nPt() const { return nPt_; } + inline int nEta() const { return nEta_; } + inline int nPhi() const { return nPhi_; } + inline int nM() const { return nM_; } + inline int nR() const { return nR_; } + + inline int binFromValue(float v, float vmin, float step, int nBins) const + { + if (!std::isfinite(v) || !std::isfinite(vmin) || !std::isfinite(step) || step <= 0.f || nBins <= 0) { + return -1; + } + const float x = (v - vmin) / step; + int b = static_cast(std::floor(x + 1e-6f)); + if (b < 0) { + return -1; + } + if (b >= nBins) { + b = nBins - 1; + } + return b; + } + + inline int ptBin(float pt) const { return binFromValue(pt, ptMin, ptStep, nPt_); } + inline int etaBin(float eta) const { return binFromValue(eta, etaMin, etaStep, nEta_); } + inline int phiBin(float phi) const { return binFromValue(phi, phiMin, phiStep, nPhi_); } + inline int radiusBin(float r) const + { + if (!std::isfinite(r) || nR_ <= 0) { + return -1; + } + if (r < rEdges.front() || r >= rEdges.back()) { + return -1; + } + auto it = std::upper_bound(rEdges.begin(), rEdges.end(), static_cast(r)); + return static_cast(it - rEdges.begin()) - 1; + } + }; + + struct BufferCandR { + int64_t collisionIdx; + int64_t rowIndex; + uint8_t v0Status; + uint16_t ptBin, etaBin, phiBin, mBin, rBin; + }; + + struct StoredV6Candidate { + int64_t collisionIdx = -1; + int64_t globalIdx = -1; + int status = -1; + bool isDouble = false; + float cospa = 0.f; + float radius = 0.f; + float dcaPos = 0.f; + float dcaNeg = 0.f; + float dcaDau = 0.f; + float lPt = 0.f; + float lEta = 0.f; + float lPhi = 0.f; + float lMass = 0.f; + float pPt = 0.f; + float pEta = 0.f; + float pPhi = 0.f; + int64_t pIndex = -1; + int64_t piIndex = -1; + + int v0Status() const { return status; } + bool doubleStatus() const { return isDouble; } + float v0Cospa() const { return cospa; } + float v0Radius() const { return radius; } + float dcaPositive() const { return dcaPos; } + float dcaNegative() const { return dcaNeg; } + float dcaBetweenDaughter() const { return dcaDau; } + float lambdaPt() const { return lPt; } + float lambdaEta() const { return lEta; } + float lambdaPhi() const { return lPhi; } + float lambdaMass() const { return lMass; } + float protonPt() const { return pPt; } + float protonEta() const { return pEta; } + float protonPhi() const { return pPhi; } + int64_t protonIndex() const { return pIndex; } + int64_t pionIndex() const { return piIndex; } + int64_t globalIndex() const { return globalIdx; } + }; + + struct PendingV6Branch { + StoredV6Candidate target; + StoredV6Candidate fixed; + int colBin = -1; + int replacedLeg = 1; + int age = 0; + uint64_t seed = 0; + }; + + template + StoredV6Candidate storeV6Candidate(T const& t, int64_t collisionIdx) const + { + return {collisionIdx, static_cast(t.globalIndex()), static_cast(t.v0Status()), static_cast(t.doubleStatus()), + t.v0Cospa(), t.v0Radius(), t.dcaPositive(), t.dcaNegative(), t.dcaBetweenDaughter(), + t.lambdaPt(), t.lambdaEta(), t.lambdaPhi(), t.lambdaMass(), + t.protonPt(), t.protonEta(), t.protonPhi(), + static_cast(t.protonIndex()), static_cast(t.pionIndex())}; + } + + template + void fillV6MixedBranch(TRep const& replacement, TFixed const& fixed, int replacedLeg, float controlWeight, float mixWeight) + { + const auto repProton = ROOT::Math::PtEtaPhiMVector(replacement.protonPt(), replacement.protonEta(), replacement.protonPhi(), o2::constants::physics::MassProton); + const auto repLambda = ROOT::Math::PtEtaPhiMVector(replacement.lambdaPt(), replacement.lambdaEta(), replacement.lambdaPhi(), replacement.lambdaMass()); + const auto fixedProton = ROOT::Math::PtEtaPhiMVector(fixed.protonPt(), fixed.protonEta(), fixed.protonPhi(), o2::constants::physics::MassProton); + const auto fixedLambda = ROOT::Math::PtEtaPhiMVector(fixed.lambdaPt(), fixed.lambdaEta(), fixed.lambdaPhi(), fixed.lambdaMass()); + const int repStatus = replacement.v0Status(); + const int fixedStatus = fixed.v0Status(); + + if (replacedLeg == 1) { + fillReplacementControlMap(repStatus, fixedStatus, 1, false, repLambda, controlWeight); + fillFixedLegControlMap(repStatus, fixedStatus, 1, false, fixedLambda, controlWeight); + if ((repStatus == 0 && fixedStatus == 1) || (repStatus == 1 && fixedStatus == 0)) { + if (fillBasicQAHistos) { + histos.fill(HIST("deltaPhiMix"), deltaPhiMinusPiToPi((float)repLambda.Phi(), (float)fixedLambda.Phi()), mixWeight); + } + } + if (repStatus == 0 && fixedStatus == 1) { + fillHistograms(0, 1, repLambda, fixedLambda, repProton, fixedProton, 1, mixWeight, 1, 1); + } else if (repStatus == 1 && fixedStatus == 0) { + fillHistograms(0, 1, fixedLambda, repLambda, fixedProton, repProton, 1, mixWeight, 2, 1); + } else { + fillHistograms(repStatus, fixedStatus, repLambda, fixedLambda, repProton, fixedProton, 1, mixWeight, 1, 1); + } + return; + } + + fillReplacementControlMap(fixedStatus, repStatus, 2, false, repLambda, controlWeight); + fillFixedLegControlMap(fixedStatus, repStatus, 2, false, fixedLambda, controlWeight); + if (fillBasicQAHistos) { + histos.fill(HIST("deltaPhiMix"), deltaPhiMinusPiToPi((float)fixedLambda.Phi(), (float)repLambda.Phi()), mixWeight); + } + if (fixedStatus == 0 && repStatus == 1) { + fillHistograms(0, 1, fixedLambda, repLambda, fixedProton, repProton, 1, mixWeight, 2, 2); + } else if (fixedStatus == 1 && repStatus == 0) { + fillHistograms(0, 1, repLambda, fixedLambda, repProton, fixedProton, 1, mixWeight, 1, 2); + } else { + fillHistograms(fixedStatus, repStatus, fixedLambda, repLambda, fixedProton, repProton, 1, mixWeight, 2, 2); + } + } + + struct StoredV6CandidateMC { + int64_t globalIdx = -1; + int status = -1; + bool isDouble = false; + float cospa = 0.f; + float radius = 0.f; + float dcaPos = 0.f; + float dcaNeg = 0.f; + float dcaDau = 0.f; + float lPt = 0.f; + float lEta = 0.f; + float lPhi = 0.f; + float lMass = 0.f; + float pPt = 0.f; + float pEta = 0.f; + float pPhi = 0.f; + int64_t pIndex = -1; + int64_t piIndex = -1; + + int v0Statusmc() const { return status; } + bool doubleStatusmc() const { return isDouble; } + float v0Cospamc() const { return cospa; } + float v0Radiusmc() const { return radius; } + float dcaPositivemc() const { return dcaPos; } + float dcaNegativemc() const { return dcaNeg; } + float dcaBetweenDaughtermc() const { return dcaDau; } + float lambdaPtmc() const { return lPt; } + float lambdaEtamc() const { return lEta; } + float lambdaPhimc() const { return lPhi; } + float lambdaMassmc() const { return lMass; } + float protonPtmc() const { return pPt; } + float protonEtamc() const { return pEta; } + float protonPhimc() const { return pPhi; } + int64_t protonIndexmc() const { return pIndex; } + int64_t pionIndexmc() const { return piIndex; } + int64_t globalIndex() const { return globalIdx; } + }; + + struct PendingV6BranchMC { + StoredV6CandidateMC target; + StoredV6CandidateMC fixed; + int colBin = -1; + int replacedLeg = 1; + int age = 0; + uint64_t seed = 0; + }; + + struct V6PendingState { + std::deque data; + std::deque mc; + }; + + V6PendingState v6Pending; + + template + StoredV6CandidateMC storeV6CandidateMC(T const& t) const + { + return {static_cast(t.globalIndex()), mcacc::v0Status(t), mcacc::doubleStatus(t), + mcacc::v0CosPA(t), mcacc::v0Radius(t), mcacc::dcaPos(t), mcacc::dcaNeg(t), mcacc::dcaDau(t), + mcacc::lamPt(t), mcacc::lamEta(t), mcacc::lamPhi(t), mcacc::lamMass(t), + mcacc::prPt(t), mcacc::prEta(t), mcacc::prPhi(t), + static_cast(mcacc::prIdx(t)), static_cast(mcacc::piIdx(t))}; + } + + template + void fillV6MixedBranchMC(TRep const& replacement, TFixed const& fixed, int replacedLeg, float controlWeight, float mixWeight) + { + const auto repProton = ROOT::Math::PtEtaPhiMVector(mcacc::prPt(replacement), mcacc::prEta(replacement), mcacc::prPhi(replacement), o2::constants::physics::MassProton); + const auto repLambda = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(replacement), mcacc::lamEta(replacement), mcacc::lamPhi(replacement), mcacc::lamMass(replacement)); + const auto fixedProton = ROOT::Math::PtEtaPhiMVector(mcacc::prPt(fixed), mcacc::prEta(fixed), mcacc::prPhi(fixed), o2::constants::physics::MassProton); + const auto fixedLambda = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(fixed), mcacc::lamEta(fixed), mcacc::lamPhi(fixed), mcacc::lamMass(fixed)); + const int repStatus = mcacc::v0Status(replacement); + const int fixedStatus = mcacc::v0Status(fixed); + + if (replacedLeg == 1) { + fillReplacementControlMap(repStatus, fixedStatus, 1, false, repLambda, controlWeight); + fillFixedLegControlMap(repStatus, fixedStatus, 1, false, fixedLambda, controlWeight); + if (fillBasicQAHistos) { + histos.fill(HIST("deltaPhiMix"), deltaPhiMinusPiToPi((float)repLambda.Phi(), (float)fixedLambda.Phi()), mixWeight); + } + if (repStatus == 0 && fixedStatus == 1) { + fillHistograms(0, 1, repLambda, fixedLambda, repProton, fixedProton, 1, mixWeight, 1, 1); + } else if (repStatus == 1 && fixedStatus == 0) { + fillHistograms(0, 1, fixedLambda, repLambda, fixedProton, repProton, 1, mixWeight, 2, 1); + } else { + fillHistograms(repStatus, fixedStatus, repLambda, fixedLambda, repProton, fixedProton, 1, mixWeight, 1, 1); + } + return; + } + + fillReplacementControlMap(fixedStatus, repStatus, 2, false, repLambda, controlWeight); + fillFixedLegControlMap(fixedStatus, repStatus, 2, false, fixedLambda, controlWeight); + if (fillBasicQAHistos) { + histos.fill(HIST("deltaPhiMix"), deltaPhiMinusPiToPi((float)fixedLambda.Phi(), (float)repLambda.Phi()), mixWeight); + } + if (fixedStatus == 0 && repStatus == 1) { + fillHistograms(0, 1, fixedLambda, repLambda, fixedProton, repProton, 1, mixWeight, 2, 2); + } else if (fixedStatus == 1 && repStatus == 0) { + fillHistograms(0, 1, repLambda, fixedLambda, repProton, fixedProton, 1, mixWeight, 1, 2); + } else { + fillHistograms(fixedStatus, repStatus, fixedLambda, repLambda, fixedProton, repProton, 1, mixWeight, 2, 2); + } + } + + static inline size_t linearKeyR(int colBin, int statBin, + int ptBin, int etaBin, int phiBin, int mBin, int rBin, + int nStatus, int nPt, int nEta, int nPhi, int nM, int nR) + { + return (((((((static_cast(colBin) * nStatus + statBin) * nPt + ptBin) * nEta + etaBin) * nPhi + phiBin) * nM + mBin) * nR + rBin)); + } + + // ------------------------------------- + // 2) MC-only selection + kinematics cuts + // ------------------------------------- + template + bool selectionV0MC(T const& candidate) + { + auto particle = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(candidate), + mcacc::lamEta(candidate), + mcacc::lamPhi(candidate), + mcacc::lamMass(candidate)); + if (std::abs(particle.Rapidity()) > rapidity || std::abs(particle.Eta()) > v0eta) { + return false; + } + if (mcacc::lamMass(candidate) < MassMin || mcacc::lamMass(candidate) > MassMax) { + return false; + } + if (mcacc::v0CosPA(candidate) < v0Configurations.cosPA) { + return false; + } + if (checkDoubleStatus && mcacc::doubleStatus(candidate)) { + return false; + } + if (mcacc::v0Radius(candidate) > v0Configurations.radiusMax) { + return false; + } + if (mcacc::v0Radius(candidate) < v0Configurations.radiusMin) { + return false; + } + if (mcacc::dcaDau(candidate) > v0Configurations.dcaDaughters) { + return false; + } + + if (mcacc::dcaV0ToPVMC(candidate) > v0Configurations.dcaV0ToPV) { + return false; + } + + if (mcacc::v0Status(candidate) == 0 && (std::abs(mcacc::dcaPos(candidate)) < v0Configurations.dcaProton || std::abs(mcacc::dcaNeg(candidate)) < v0Configurations.dcaPion)) { + return false; + } + if (mcacc::v0Status(candidate) == 1 && (std::abs(mcacc::dcaPos(candidate)) < v0Configurations.dcaPion || std::abs(mcacc::dcaNeg(candidate)) < v0Configurations.dcaProton)) { + return false; + } + if (mcacc::lamPt(candidate) < ptMin) { + return false; + } + if (mcacc::lamPt(candidate) > ptMax) { + return false; + } + return true; + } + + template + bool checkKinematicsMC(T1 const& candidate1, T2 const& candidate2) + { + // keep same species/status + if (mcacc::v0Status(candidate1) != mcacc::v0Status(candidate2)) { + return false; + } + + // pT window + if (std::abs(mcacc::lamPt(candidate1) - mcacc::lamPt(candidate2)) > ptMix) { + return false; + } + + // eta or rapidity window (etaMix used as Δη or Δy) + if (!userapidity) { + if (std::abs(mcacc::lamEta(candidate1) - mcacc::lamEta(candidate2)) > etaMix) { + return false; + } + } else { + const auto l1 = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(candidate1), mcacc::lamEta(candidate1), + mcacc::lamPhi(candidate1), mcacc::lamMass(candidate1)); + const auto l2 = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(candidate2), mcacc::lamEta(candidate2), + mcacc::lamPhi(candidate2), mcacc::lamMass(candidate2)); + if (std::abs(l1.Rapidity() - l2.Rapidity()) > etaMix) { + return false; + } + } + + // delta-phi window (wrapped) + const float dphi = deltaPhiMinusPiToPi((float)mcacc::lamPhi(candidate1), + (float)mcacc::lamPhi(candidate2)); + if (std::abs(dphi) > phiMix) { + return false; + } + + // mass window (optional but consistent with data) + if (std::abs(mcacc::lamMass(candidate1) - mcacc::lamMass(candidate2)) > massMix) { + return false; + } + + return true; + } + + // ----------------------------------------- + // 3) MC filter + aliases (distinct from data) + // ----------------------------------------- + Filter centralityFilterMC = (nabs(aod::lambdaeventmc::centmc) < centMax && nabs(aod::lambdaeventmc::centmc) > centMin); + + using EventCandidatesMC = soa::Filtered; + using AllTrackCandidatesMC = aod::LambdaPairmcs; + + // IMPORTANT: MC preslice uses the MC event index column + Preslice tracksPerCollisionV0mc = aod::lambdapairmc::lambdaeventmcId; + + // ----------------------------------------- + // 4) MC Same-event processing (like processData) + // ----------------------------------------- + void processMC(EventCandidatesMC::iterator const& collision, AllTrackCandidatesMC const& V0sMC) + { + const float centrality = mcacc::cent(collision); + + for (const auto& v0 : V0sMC) { + if (!selectionV0MC(v0)) { + continue; + } + if (fillBasicQAHistos) { + histos.fill(HIST("hPtRadiusV0"), mcacc::lamPt(v0), mcacc::v0Radius(v0)); + } + if (fillBasicQAHistos) { + histos.fill(HIST("ptCent"), mcacc::lamPt(v0), centrality); + } + if (fillBasicQAHistos) { + histos.fill(HIST("etaCent"), mcacc::lamEta(v0), centrality); + } + + proton = ROOT::Math::PtEtaPhiMVector(mcacc::prPt(v0), mcacc::prEta(v0), mcacc::prPhi(v0), + o2::constants::physics::MassProton); + lambda = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(v0), mcacc::lamEta(v0), mcacc::lamPhi(v0), + mcacc::lamMass(v0)); + if (mcacc::v0Status(v0) == 0) { + histos.fill(HIST("hEtaPhiLambdaRaw"), lambda.Phi(), lambda.Eta(), getNUAWeight(0, lambda.Phi(), lambda.Eta())); + } else { + histos.fill(HIST("hEtaPhiAntiLambdaRaw"), lambda.Phi(), lambda.Eta(), getNUAWeight(1, lambda.Phi(), lambda.Eta())); + } + + for (const auto& v02 : V0sMC) { + if (v02.index() <= v0.index()) { + continue; + } + if (!selectionV0MC(v02)) { + continue; + } + if (hasSharedDaughtersMC(v0, v02)) + continue; + proton2 = ROOT::Math::PtEtaPhiMVector(mcacc::prPt(v02), mcacc::prEta(v02), mcacc::prPhi(v02), + o2::constants::physics::MassProton); + lambda2 = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(v02), mcacc::lamEta(v02), mcacc::lamPhi(v02), + mcacc::lamMass(v02)); + + histos.fill(HIST("deltaPhiSame"), + RecoDecay::constrainAngle(mcacc::lamPhi(v0) - mcacc::lamPhi(v02), + -TMath::Pi(), harmonicDphi)); + + const int s1 = mcacc::v0Status(v0); + const int s2 = mcacc::v0Status(v02); + + if (s1 == 0 && s2 == 0) { + fillHistograms(0, 0, lambda, lambda2, proton, proton2, 0, 1.0f); + } else if (s1 == 0 && s2 == 1) { + fillHistograms(0, 1, lambda, lambda2, proton, proton2, 0, 1.0f); + } else if (s1 == 1 && s2 == 0) { + fillHistograms(0, 1, lambda2, lambda, proton2, proton, 0, 1.0f); + } else if (s1 == 1 && s2 == 1) { + fillHistograms(1, 1, lambda, lambda2, proton, proton2, 0, 1.0f); + } + } + } + } + PROCESS_SWITCH(lambdaspincorrderived, processMC, "Process MC (SE)", false); + + static inline float phi0To2Pi(float phi) + { + // harmonic=1, min=0 => [0, 2pi) + return RecoDecay::constrainAngle(phi, 0.0f, 1); + } + + static inline float deltaPhiMinusPiToPi(float phiA, float phiB) + { + // returns in [-pi, pi) + const float d = phi0To2Pi(phiA) - phi0To2Pi(phiB); + return RecoDecay::constrainAngle(d, -TMath::Pi(), 1); + } + + static inline float absDeltaPhi(float phiA, float phiB) + { + return std::abs(deltaPhiMinusPiToPi(phiA, phiB)); + } + + // symmetric neighbors for phi with periodic wrap at 0/2pi + static inline void collectNeighborBinsPhi(int b, int nPhi, int nNeighbor, std::vector& out) + { + out.clear(); + if (nPhi <= 0 || b < 0 || b >= nPhi) { + return; + } + + if (2 * nNeighbor + 1 >= nPhi) { + out.reserve(nPhi); + for (int bb = 0; bb < nPhi; ++bb) { + out.push_back(bb); + } + return; + } + + out.reserve(2 * nNeighbor + 1); + for (int d = -nNeighbor; d <= nNeighbor; ++d) { + int bb = (b + d) % nPhi; + if (bb < 0) { + bb += nPhi; + } + out.push_back(bb); + } + + std::sort(out.begin(), out.end()); + out.erase(std::unique(out.begin(), out.end()), out.end()); + } + + static inline void collectNeighborBinsClamp(int b, int nBins, int nNeighbor, std::vector& out) + { + out.clear(); + out.reserve(2 * nNeighbor + 1); + for (int d = -nNeighbor; d <= nNeighbor; ++d) { + const int bb = b + d; + if (bb >= 0 && bb < nBins) { + out.push_back(bb); + } + } + } + static inline void collectNeighborBinsMass(int b, int nBins, int nNeighbor, std::vector& out) + { + out.clear(); + out.reserve(2 * nNeighbor + 1); + + for (int d = -nNeighbor; d <= nNeighbor; ++d) { + const int bb = b + d; + if (bb >= 0 && bb < nBins) { + out.push_back(bb); + } + } + + std::sort(out.begin(), out.end()); + out.erase(std::unique(out.begin(), out.end()), out.end()); + } + + static inline int getMassRegionFromEdges(float m, const std::vector& edges) + { + if (edges.size() != 4) { + return -1; + } + + if (m >= edges[0] && m < edges[1]) + return 0; // low sideband + if (m >= edges[1] && m < edges[2]) + return 1; // signal + if (m >= edges[2] && m < edges[3]) + return 2; // high sideband + + return -1; + } + static inline int getMassMixClassFromEdges(float m, const std::vector& edges) + { + // no mass separation + if (edges.size() == 2) { + if (m >= edges[0] && m < edges[1]) + return 0; + return -1; + } + + // 3 regions: SB low, signal, SB high + if (edges.size() == 4) { + if (m >= edges[0] && m < edges[1]) + return 0; // low sideband + if (m >= edges[1] && m < edges[2]) + return 1; // signal + if (m >= edges[2] && m < edges[3]) + return 0; // high sideband merged with low sideband + return -1; + } + + return -1; + } + static inline uint64_t splitmix64(uint64_t x) + { + // simple deterministic hash for reproducible shuffling + x += 0x9e3779b97f4a7c15ULL; + x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL; + x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL; + return x ^ (x >> 31); + } + + void processMEV6(EventCandidates const& collisions, AllTrackCandidates const& V0s) + { + MixBinnerR mb{ + ptMin.value, + ptMax.value, + ptMix.value, + v0etaMixBuffer.value, + etaMix.value, + phiMix.value, + MassMin.value, + MassMax.value, + cfgV5MassBins.value, + cfgMixRadiusParam.cfgMixRadiusBins.value}; + + const int nCol = colBinning.getAllBinsCount(); + const int nStat = N_STATUS; + const int nPt = mb.nPt(); + const int nEta = mb.nEta(); + const int nPhi = mb.nPhi(); + const int nM = mb.nM(); + const int nR = mb.nR(); + + const size_t nKeys = static_cast(nCol) * nStat * nPt * nEta * nPhi * nM * nR; + std::vector> buffer(nKeys); - if (rEdges.size() < 2) { - rEdges = {3.0, 5.0, 7.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0}; + // -------- PASS 1: fill buffer -------- + for (auto const& col : collisions) { + const int colBin = colBinning.getBin(std::make_tuple(col.posz(), col.cent())); + if (colBin < 0) { + continue; } - nR_ = static_cast(rEdges.size()) - 1; - nPt_ = std::max(1, static_cast(std::floor((ptMax - ptMin) / ptStep + 0.5f))); - nEta_ = std::max(1, static_cast(std::floor((etaMax - etaMin) / etaStep + 0.5f))); - nPhi_ = std::max(1, static_cast(std::ceil((phiMax - phiMin) / phiStep))); - } + auto slice = V0s.sliceBy(tracksPerCollisionV0, col.index()); - inline int nPt() const { return nPt_; } - inline int nEta() const { return nEta_; } - inline int nPhi() const { return nPhi_; } - inline int nM() const { return nM_; } - inline int nR() const { return nR_; } + for (auto const& t : slice) { + if (!selectionV0(t)) { + continue; + } - inline int binFromValue(float v, float vmin, float step, int nBins) const - { - if (!std::isfinite(v) || !std::isfinite(vmin) || !std::isfinite(step) || step <= 0.f || nBins <= 0) { - return -1; - } - const float x = (v - vmin) / step; - int b = static_cast(std::floor(x + 1e-6f)); - if (b < 0) { - return -1; - } - if (b >= nBins) { - b = nBins - 1; - } - return b; - } + const int status = static_cast(t.v0Status()); + if (status < 0 || status >= nStat) { + continue; + } - inline int ptBin(float pt) const { return binFromValue(pt, ptMin, ptStep, nPt_); } - inline int etaBin(float eta) const { return binFromValue(eta, etaMin, etaStep, nEta_); } - inline int phiBin(float phi) const { return binFromValue(phi, phiMin, phiStep, nPhi_); } - inline int radiusBin(float r) const - { - if (!std::isfinite(r) || nR_ <= 0) { - return -1; - } - if (r < rEdges.front() || r >= rEdges.back()) { - return -1; + const int ptB = mb.ptBin(t.lambdaPt()); + + int etaB = mb.etaBin(t.lambdaEta()); + if (userapidity) { + const auto lv = ROOT::Math::PtEtaPhiMVector(t.lambdaPt(), t.lambdaEta(), t.lambdaPhi(), t.lambdaMass()); + etaB = mb.etaBin(lv.Rapidity()); + } + + const int phiB = mb.phiBin(RecoDecay::constrainAngle(t.lambdaPhi(), 0.0, harmonic)); + const int mB = getMassMixClassFromEdges(t.lambdaMass(), massMixEdges.value); + const int rB = mb.radiusBin(t.v0Radius()); + + if (ptB < 0 || etaB < 0 || phiB < 0 || mB < 0 || rB < 0) { + continue; + } + + const size_t key = linearKeyR(colBin, status, ptB, etaB, phiB, mB, rB, + nStat, nPt, nEta, nPhi, nM, nR); + + buffer[key].push_back(BufferCandR{ + .collisionIdx = static_cast(col.index()), + .rowIndex = static_cast(t.globalIndex()), + .v0Status = static_cast(status), + .ptBin = static_cast(ptB), + .etaBin = static_cast(etaB), + .phiBin = static_cast(phiB), + .mBin = static_cast(mB), + .rBin = static_cast(rB)}); } - auto it = std::upper_bound(rEdges.begin(), rEdges.end(), static_cast(r)); - return static_cast(it - rEdges.begin()) - 1; } - }; - - struct BufferCandR { - int64_t collisionIdx; - int64_t rowIndex; - uint8_t v0Status; - uint16_t ptBin, etaBin, phiBin, mBin, rBin; - }; - struct StoredV6Candidate { - int64_t collisionIdx = -1; - int64_t globalIdx = -1; - int status = -1; - bool isDouble = false; - float cospa = 0.f; - float radius = 0.f; - float dcaPos = 0.f; - float dcaNeg = 0.f; - float dcaDau = 0.f; - float lPt = 0.f; - float lEta = 0.f; - float lPhi = 0.f; - float lMass = 0.f; - float pPt = 0.f; - float pEta = 0.f; - float pPhi = 0.f; - int64_t pIndex = -1; - int64_t piIndex = -1; + const int nN_pt = std::max(0, cfgV5NeighborPt.value); + const int nN_eta = std::max(0, cfgV5NeighborEta.value); + const int nN_phi = std::max(0, cfgV5NeighborPhi.value); - int v0Status() const { return status; } - bool doubleStatus() const { return isDouble; } - float v0Cospa() const { return cospa; } - float v0Radius() const { return radius; } - float dcaPositive() const { return dcaPos; } - float dcaNegative() const { return dcaNeg; } - float dcaBetweenDaughter() const { return dcaDau; } - float lambdaPt() const { return lPt; } - float lambdaEta() const { return lEta; } - float lambdaPhi() const { return lPhi; } - float lambdaMass() const { return lMass; } - float protonPt() const { return pPt; } - float protonEta() const { return pEta; } - float protonPhi() const { return pPhi; } - int64_t protonIndex() const { return pIndex; } - int64_t pionIndex() const { return piIndex; } - int64_t globalIndex() const { return globalIdx; } - }; + std::vector ptBins, etaBins, phiBins; + std::vector matches1, matches2; + matches1.reserve(256); + matches2.reserve(256); - struct PendingV6Branch { - StoredV6Candidate target; - StoredV6Candidate fixed; - int colBin = -1; - int replacedLeg = 1; - int age = 0; - uint64_t seed = 0; - }; + auto collectMatchesForReplacedLeg = [&](auto const& tRep, auto const& tKeep, int colBin, int64_t curColIdx, std::vector& matches) { + matches.clear(); - template - StoredV6Candidate storeV6Candidate(T const& t, int64_t collisionIdx) const - { - return {collisionIdx, static_cast(t.globalIndex()), static_cast(t.v0Status()), static_cast(t.doubleStatus()), - t.v0Cospa(), t.v0Radius(), t.dcaPositive(), t.dcaNegative(), t.dcaBetweenDaughter(), - t.lambdaPt(), t.lambdaEta(), t.lambdaPhi(), t.lambdaMass(), - t.protonPt(), t.protonEta(), t.protonPhi(), - static_cast(t.protonIndex()), static_cast(t.pionIndex())}; - } + const int status = static_cast(tRep.v0Status()); + if (status < 0 || status >= nStat) { + return; + } - template - void fillV6MixedBranch(TRep const& replacement, TFixed const& fixed, int replacedLeg, float controlWeight, float mixWeight) - { - const auto repProton = ROOT::Math::PtEtaPhiMVector(replacement.protonPt(), replacement.protonEta(), replacement.protonPhi(), o2::constants::physics::MassProton); - const auto repLambda = ROOT::Math::PtEtaPhiMVector(replacement.lambdaPt(), replacement.lambdaEta(), replacement.lambdaPhi(), replacement.lambdaMass()); - const auto fixedProton = ROOT::Math::PtEtaPhiMVector(fixed.protonPt(), fixed.protonEta(), fixed.protonPhi(), o2::constants::physics::MassProton); - const auto fixedLambda = ROOT::Math::PtEtaPhiMVector(fixed.lambdaPt(), fixed.lambdaEta(), fixed.lambdaPhi(), fixed.lambdaMass()); - const int repStatus = replacement.v0Status(); - const int fixedStatus = fixed.v0Status(); + const int ptB = mb.ptBin(tRep.lambdaPt()); - if (replacedLeg == 1) { - fillReplacementControlMap(repStatus, fixedStatus, 1, false, repLambda, controlWeight); - fillFixedLegControlMap(repStatus, fixedStatus, 1, false, fixedLambda, controlWeight); - if ((repStatus == 0 && fixedStatus == 1) || (repStatus == 1 && fixedStatus == 0)) { - if (fillBasicQAHistos) { - histos.fill(HIST("deltaPhiMix"), deltaPhiMinusPiToPi((float)repLambda.Phi(), (float)fixedLambda.Phi()), mixWeight); - } + int etaB = mb.etaBin(tRep.lambdaEta()); + if (userapidity) { + const auto lv = ROOT::Math::PtEtaPhiMVector(tRep.lambdaPt(), tRep.lambdaEta(), tRep.lambdaPhi(), tRep.lambdaMass()); + etaB = mb.etaBin(lv.Rapidity()); } - if (repStatus == 0 && fixedStatus == 1) { - fillHistograms(0, 1, repLambda, fixedLambda, repProton, fixedProton, 1, mixWeight, 1, 1); - } else if (repStatus == 1 && fixedStatus == 0) { - fillHistograms(0, 1, fixedLambda, repLambda, fixedProton, repProton, 1, mixWeight, 2, 1); - } else { - fillHistograms(repStatus, fixedStatus, repLambda, fixedLambda, repProton, fixedProton, 1, mixWeight, 1, 1); + + const int phiB = mb.phiBin(RecoDecay::constrainAngle(tRep.lambdaPhi(), 0.0, harmonic)); + const int mB = getMassMixClassFromEdges(tRep.lambdaMass(), massMixEdges.value); + const int rB = mb.radiusBin(tRep.v0Radius()); + + if (ptB < 0 || etaB < 0 || phiB < 0 || mB < 0 || rB < 0) { + return; } - return; - } + auto collectFromBins = [&](const std::vector& ptUseBins, + const std::vector& etaUseBins, + const std::vector& phiUseBins) { + for (const auto& ptUse : ptUseBins) { + for (const auto& etaUse : etaUseBins) { + for (const auto& phiUse : phiUseBins) { + const auto& vec = buffer[linearKeyR(colBin, status, ptUse, etaUse, phiUse, mB, rB, + nStat, nPt, nEta, nPhi, nM, nR)]; - fillReplacementControlMap(fixedStatus, repStatus, 2, false, repLambda, controlWeight); - fillFixedLegControlMap(fixedStatus, repStatus, 2, false, fixedLambda, controlWeight); - if (fillBasicQAHistos) { - histos.fill(HIST("deltaPhiMix"), deltaPhiMinusPiToPi((float)fixedLambda.Phi(), (float)repLambda.Phi()), mixWeight); - } - if (fixedStatus == 0 && repStatus == 1) { - fillHistograms(0, 1, fixedLambda, repLambda, fixedProton, repProton, 1, mixWeight, 2, 2); - } else if (fixedStatus == 1 && repStatus == 0) { - fillHistograms(0, 1, repLambda, fixedLambda, repProton, fixedProton, 1, mixWeight, 1, 2); - } else { - fillHistograms(fixedStatus, repStatus, fixedLambda, repLambda, fixedProton, repProton, 1, mixWeight, 2, 2); - } - } + for (auto const& bc : vec) { + if (bc.collisionIdx == curColIdx) + continue; - struct StoredV6CandidateMC { - int64_t globalIdx = -1; - int status = -1; - bool isDouble = false; - float cospa = 0.f; - float radius = 0.f; - float dcaPos = 0.f; - float dcaNeg = 0.f; - float dcaDau = 0.f; - float lPt = 0.f; - float lEta = 0.f; - float lPhi = 0.f; - float lMass = 0.f; - float pPt = 0.f; - float pEta = 0.f; - float pPhi = 0.f; - int64_t pIndex = -1; - int64_t piIndex = -1; + auto tX = V0s.iteratorAt(static_cast(bc.rowIndex)); + + if (!selectionV0(tX)) + continue; + if (!checkKinematics(tRep, tX)) + continue; - int v0Statusmc() const { return status; } - bool doubleStatusmc() const { return isDouble; } - float v0Cospamc() const { return cospa; } - float v0Radiusmc() const { return radius; } - float dcaPositivemc() const { return dcaPos; } - float dcaNegativemc() const { return dcaNeg; } - float dcaBetweenDaughtermc() const { return dcaDau; } - float lambdaPtmc() const { return lPt; } - float lambdaEtamc() const { return lEta; } - float lambdaPhimc() const { return lPhi; } - float lambdaMassmc() const { return lMass; } - float protonPtmc() const { return pPt; } - float protonEtamc() const { return pEta; } - float protonPhimc() const { return pPhi; } - int64_t protonIndexmc() const { return pIndex; } - int64_t pionIndexmc() const { return piIndex; } - int64_t globalIndex() const { return globalIdx; } - }; + if (tX.globalIndex() == tRep.globalIndex()) + continue; + if (tX.globalIndex() == tKeep.globalIndex()) + continue; - struct PendingV6BranchMC { - StoredV6CandidateMC target; - StoredV6CandidateMC fixed; - int colBin = -1; - int replacedLeg = 1; - int age = 0; - uint64_t seed = 0; - }; + if (hasSharedDaughters(tX, tKeep)) + continue; + if (hasSharedDaughters(tX, tRep)) + continue; - struct V6PendingState { - std::deque data; - std::deque mc; - }; + matches.push_back(MatchRef{bc.collisionIdx, bc.rowIndex}); + } + } + } + } + }; - V6PendingState v6Pending; + matches.clear(); - template - StoredV6CandidateMC storeV6CandidateMC(T const& t) const - { - return {static_cast(t.globalIndex()), mcacc::v0Status(t), mcacc::doubleStatus(t), - mcacc::v0CosPA(t), mcacc::v0Radius(t), mcacc::dcaPos(t), mcacc::dcaNeg(t), mcacc::dcaDau(t), - mcacc::lamPt(t), mcacc::lamEta(t), mcacc::lamPhi(t), mcacc::lamMass(t), - mcacc::prPt(t), mcacc::prEta(t), mcacc::prPhi(t), - static_cast(mcacc::prIdx(t)), static_cast(mcacc::piIdx(t))}; - } + // 1) exact bin first + ptBins.clear(); + etaBins.clear(); + phiBins.clear(); - template - void fillV6MixedBranchMC(TRep const& replacement, TFixed const& fixed, int replacedLeg, float controlWeight, float mixWeight) - { - const auto repProton = ROOT::Math::PtEtaPhiMVector(mcacc::prPt(replacement), mcacc::prEta(replacement), mcacc::prPhi(replacement), o2::constants::physics::MassProton); - const auto repLambda = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(replacement), mcacc::lamEta(replacement), mcacc::lamPhi(replacement), mcacc::lamMass(replacement)); - const auto fixedProton = ROOT::Math::PtEtaPhiMVector(mcacc::prPt(fixed), mcacc::prEta(fixed), mcacc::prPhi(fixed), o2::constants::physics::MassProton); - const auto fixedLambda = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(fixed), mcacc::lamEta(fixed), mcacc::lamPhi(fixed), mcacc::lamMass(fixed)); - const int repStatus = mcacc::v0Status(replacement); - const int fixedStatus = mcacc::v0Status(fixed); + ptBins.push_back(ptB); + etaBins.push_back(etaB); + phiBins.push_back(phiB); - if (replacedLeg == 1) { - fillReplacementControlMap(repStatus, fixedStatus, 1, false, repLambda, controlWeight); - fillFixedLegControlMap(repStatus, fixedStatus, 1, false, fixedLambda, controlWeight); - if (fillBasicQAHistos) { - histos.fill(HIST("deltaPhiMix"), deltaPhiMinusPiToPi((float)repLambda.Phi(), (float)fixedLambda.Phi()), mixWeight); - } - if (repStatus == 0 && fixedStatus == 1) { - fillHistograms(0, 1, repLambda, fixedLambda, repProton, fixedProton, 1, mixWeight, 1, 1); - } else if (repStatus == 1 && fixedStatus == 0) { - fillHistograms(0, 1, fixedLambda, repLambda, fixedProton, repProton, 1, mixWeight, 2, 1); - } else { - fillHistograms(repStatus, fixedStatus, repLambda, fixedLambda, repProton, fixedProton, 1, mixWeight, 1, 1); - } - return; - } + collectFromBins(ptBins, etaBins, phiBins); - fillReplacementControlMap(fixedStatus, repStatus, 2, false, repLambda, controlWeight); - fillFixedLegControlMap(fixedStatus, repStatus, 2, false, fixedLambda, controlWeight); - if (fillBasicQAHistos) { - histos.fill(HIST("deltaPhiMix"), deltaPhiMinusPiToPi((float)fixedLambda.Phi(), (float)repLambda.Phi()), mixWeight); - } - if (fixedStatus == 0 && repStatus == 1) { - fillHistograms(0, 1, fixedLambda, repLambda, fixedProton, repProton, 1, mixWeight, 2, 2); - } else if (fixedStatus == 1 && repStatus == 0) { - fillHistograms(0, 1, repLambda, fixedLambda, repProton, fixedProton, 1, mixWeight, 1, 2); - } else { - fillHistograms(fixedStatus, repStatus, fixedLambda, repLambda, fixedProton, repProton, 1, mixWeight, 2, 2); - } - } + // 2) if exact bin gives fewer than required matches, also search neighbors + const int targetMatches = (cfgV5MaxMatches.value > 0) ? cfgV5MaxMatches.value : 1; - static inline size_t linearKeyR(int colBin, int statBin, - int ptBin, int etaBin, int phiBin, int mBin, int rBin, - int nStatus, int nPt, int nEta, int nPhi, int nM, int nR) - { - return (((((((static_cast(colBin) * nStatus + statBin) * nPt + ptBin) * nEta + etaBin) * nPhi + phiBin) * nM + mBin) * nR + rBin)); - } + if ((int)matches.size() < targetMatches) { + std::vector ptBinsN, etaBinsN, phiBinsN; + collectNeighborBinsClamp(ptB, nPt, nN_pt, ptBinsN); + collectNeighborBinsClamp(etaB, nEta, nN_eta, etaBinsN); + collectNeighborBinsPhi(phiB, nPhi, nN_phi, phiBinsN); - // ------------------------------------- - // 2) MC-only selection + kinematics cuts - // ------------------------------------- - template - bool selectionV0MC(T const& candidate) - { - auto particle = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(candidate), - mcacc::lamEta(candidate), - mcacc::lamPhi(candidate), - mcacc::lamMass(candidate)); - if (std::abs(particle.Rapidity()) > rapidity || std::abs(particle.Eta()) > v0eta) { - return false; - } - if (mcacc::lamMass(candidate) < MassMin || mcacc::lamMass(candidate) > MassMax) { - return false; - } - if (mcacc::v0CosPA(candidate) < v0Configurations.cosPA) { - return false; - } - if (checkDoubleStatus && mcacc::doubleStatus(candidate)) { - return false; - } - if (mcacc::v0Radius(candidate) > v0Configurations.radiusMax) { - return false; - } - if (mcacc::v0Radius(candidate) < v0Configurations.radiusMin) { - return false; - } - if (mcacc::dcaDau(candidate) > v0Configurations.dcaDaughters) { - return false; - } + for (const auto& ptUse : ptBinsN) { + for (const auto& etaUse : etaBinsN) { + for (const auto& phiUse : phiBinsN) { + if (ptUse == ptB && etaUse == etaB && phiUse == phiB) + continue; - if (mcacc::dcaV0ToPVMC(candidate) > v0Configurations.dcaV0ToPV) { - return false; - } + const auto& vec = buffer[linearKeyR(colBin, status, ptUse, etaUse, phiUse, mB, rB, + nStat, nPt, nEta, nPhi, nM, nR)]; - if (mcacc::v0Status(candidate) == 0 && (std::abs(mcacc::dcaPos(candidate)) < v0Configurations.dcaProton || std::abs(mcacc::dcaNeg(candidate)) < v0Configurations.dcaPion)) { - return false; - } - if (mcacc::v0Status(candidate) == 1 && (std::abs(mcacc::dcaPos(candidate)) < v0Configurations.dcaPion || std::abs(mcacc::dcaNeg(candidate)) < v0Configurations.dcaProton)) { - return false; - } - if (mcacc::lamPt(candidate) < ptMin) { - return false; - } - if (mcacc::lamPt(candidate) > ptMax) { - return false; - } - return true; - } + for (auto const& bc : vec) { + if (bc.collisionIdx == curColIdx) + continue; - template - bool checkKinematicsMC(T1 const& candidate1, T2 const& candidate2) - { - // keep same species/status - if (mcacc::v0Status(candidate1) != mcacc::v0Status(candidate2)) { - return false; - } + auto tX = V0s.iteratorAt(static_cast(bc.rowIndex)); - // pT window - if (std::abs(mcacc::lamPt(candidate1) - mcacc::lamPt(candidate2)) > ptMix) { - return false; - } + if (!selectionV0(tX)) + continue; + if (!checkKinematics(tRep, tX)) + continue; - // eta or rapidity window (etaMix used as Δη or Δy) - if (!userapidity) { - if (std::abs(mcacc::lamEta(candidate1) - mcacc::lamEta(candidate2)) > etaMix) { - return false; - } - } else { - const auto l1 = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(candidate1), mcacc::lamEta(candidate1), - mcacc::lamPhi(candidate1), mcacc::lamMass(candidate1)); - const auto l2 = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(candidate2), mcacc::lamEta(candidate2), - mcacc::lamPhi(candidate2), mcacc::lamMass(candidate2)); - if (std::abs(l1.Rapidity() - l2.Rapidity()) > etaMix) { - return false; + if (tX.globalIndex() == tRep.globalIndex()) + continue; + if (tX.globalIndex() == tKeep.globalIndex()) + continue; + + if (hasSharedDaughters(tX, tKeep)) + continue; + if (hasSharedDaughters(tX, tRep)) + continue; + + matches.push_back(MatchRef{bc.collisionIdx, bc.rowIndex}); + } + } + } + } } - } - // delta-phi window (wrapped) - const float dphi = deltaPhiMinusPiToPi((float)mcacc::lamPhi(candidate1), - (float)mcacc::lamPhi(candidate2)); - if (std::abs(dphi) > phiMix) { - return false; - } + std::sort(matches.begin(), matches.end(), + [](auto const& a, auto const& b) { + return std::tie(a.collisionIdx, a.rowIndex) < std::tie(b.collisionIdx, b.rowIndex); + }); + matches.erase(std::unique(matches.begin(), matches.end(), + [](auto const& a, auto const& b) { + return a.collisionIdx == b.collisionIdx && a.rowIndex == b.rowIndex; + }), + matches.end()); + }; - // mass window (optional but consistent with data) - if (std::abs(mcacc::lamMass(candidate1) - mcacc::lamMass(candidate2)) > massMix) { - return false; - } + auto downsampleMatches = [&](std::vector& matches, uint64_t seedBase) { + if (cfgV5MaxMatches.value > 0 && (int)matches.size() > cfgV5MaxMatches.value) { + uint64_t seed = cfgMixSeed.value ^ splitmix64(seedBase); + const int K = cfgV5MaxMatches.value; + for (int i = 0; i < K; ++i) { + seed = splitmix64(seed); + const int j = i + (int)(seed % (uint64_t)(matches.size() - i)); + std::swap(matches[i], matches[j]); + } + matches.resize(K); + } + }; - return true; - } + const size_t pendingAtStart = v6Pending.data.size(); + size_t pendingMatched = 0; + size_t pendingExpired = 0; + size_t pendingAdded = 0; + if (!cfgV6CarryUnmatched) { + v6Pending.data.clear(); + } else { + for (auto it = v6Pending.data.begin(); it != v6Pending.data.end();) { + auto& pending = *it; + ++pending.age; + if (cfgV6MaxPendingAge.value > 0 && pending.age > cfgV6MaxPendingAge.value) { + ++pendingExpired; + it = v6Pending.data.erase(it); + continue; + } - // ----------------------------------------- - // 3) MC filter + aliases (distinct from data) - // ----------------------------------------- - Filter centralityFilterMC = (nabs(aod::lambdaeventmc::centmc) < centMax && nabs(aod::lambdaeventmc::centmc) > centMin); + auto& matches = pending.replacedLeg == 1 ? matches1 : matches2; + collectMatchesForReplacedLeg(pending.target, pending.fixed, pending.colBin, -1, matches); + limitMatchesToNEvents(matches, nEvtMixing.value); + downsampleMatches(matches, pending.seed ^ splitmix64(static_cast(pending.age))); - using EventCandidatesMC = soa::Filtered; - using AllTrackCandidatesMC = aod::LambdaPairmcs; + int nAccepted = 0; + for (auto const& m : matches) { + auto replacement = V0s.iteratorAt(static_cast(m.rowIndex)); + if (!selectionV0(replacement) || !checkKinematics(pending.target, replacement)) { + continue; + } + if (replacement.globalIndex() == pending.target.globalIndex() || replacement.globalIndex() == pending.fixed.globalIndex()) { + continue; + } + if (hasSharedDaughters(replacement, pending.target) || hasSharedDaughters(replacement, pending.fixed)) { + continue; + } + ++nAccepted; + } - // IMPORTANT: MC preslice uses the MC event index column - Preslice tracksPerCollisionV0mc = aod::lambdapairmc::lambdaeventmcId; + if (nAccepted == 0) { + ++it; + continue; + } - // ----------------------------------------- - // 4) MC Same-event processing (like processData) - // ----------------------------------------- - void processMC(EventCandidatesMC::iterator const& collision, AllTrackCandidatesMC const& V0sMC) - { - const float centrality = mcacc::cent(collision); + const float controlWeight = 1.0f / static_cast(nAccepted); + const float branchNorm = cfgMixLegMode.value == 2 ? 0.5f : 1.0f; + const float mixWeight = branchNorm * controlWeight; + for (auto const& m : matches) { + auto replacement = V0s.iteratorAt(static_cast(m.rowIndex)); + if (!selectionV0(replacement) || !checkKinematics(pending.target, replacement)) { + continue; + } + if (replacement.globalIndex() == pending.target.globalIndex() || replacement.globalIndex() == pending.fixed.globalIndex()) { + continue; + } + if (hasSharedDaughters(replacement, pending.target) || hasSharedDaughters(replacement, pending.fixed)) { + continue; + } + fillV6MixedBranch(replacement, pending.fixed, pending.replacedLeg, controlWeight, mixWeight); + } + ++pendingMatched; + it = v6Pending.data.erase(it); + } + } - for (const auto& v0 : V0sMC) { - if (!selectionV0MC(v0)) { + // -------- PASS 2: configurable one-leg / two-leg mixing -------- + for (auto const& col1 : collisions) { + const int colBin = colBinning.getBin(std::make_tuple(col1.posz(), col1.cent())); + if (colBin < 0) { continue; } - if (fillBasicQAHistos) { - histos.fill(HIST("hPtRadiusV0"), mcacc::lamPt(v0), mcacc::v0Radius(v0)); - } - if (fillBasicQAHistos) { - histos.fill(HIST("ptCent"), mcacc::lamPt(v0), centrality); - } - if (fillBasicQAHistos) { - histos.fill(HIST("etaCent"), mcacc::lamEta(v0), centrality); - } - proton = ROOT::Math::PtEtaPhiMVector(mcacc::prPt(v0), mcacc::prEta(v0), mcacc::prPhi(v0), - o2::constants::physics::MassProton); - lambda = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(v0), mcacc::lamEta(v0), mcacc::lamPhi(v0), - mcacc::lamMass(v0)); - if (mcacc::v0Status(v0) == 0) { - histos.fill(HIST("hEtaPhiLambdaRaw"), lambda.Phi(), lambda.Eta(), getNUAWeight(0, lambda.Phi(), lambda.Eta())); - } else { - histos.fill(HIST("hEtaPhiAntiLambdaRaw"), lambda.Phi(), lambda.Eta(), getNUAWeight(1, lambda.Phi(), lambda.Eta())); - } + const int64_t curColIdx = static_cast(col1.index()); + auto poolA = V0s.sliceBy(tracksPerCollisionV0, col1.index()); - for (const auto& v02 : V0sMC) { - if (v02.index() <= v0.index()) { + for (auto const& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(poolA, poolA))) { + if (!selectionV0(t1) || !selectionV0(t2)) { continue; } - if (!selectionV0MC(v02)) { + if (t2.index() <= t1.index()) { continue; } - if (hasSharedDaughtersMC(v0, v02)) + if (hasSharedDaughters(t1, t2)) continue; - proton2 = ROOT::Math::PtEtaPhiMVector(mcacc::prPt(v02), mcacc::prEta(v02), mcacc::prPhi(v02), - o2::constants::physics::MassProton); - lambda2 = ROOT::Math::PtEtaPhiMVector(mcacc::lamPt(v02), mcacc::lamEta(v02), mcacc::lamPhi(v02), - mcacc::lamMass(v02)); - - histos.fill(HIST("deltaPhiSame"), - RecoDecay::constrainAngle(mcacc::lamPhi(v0) - mcacc::lamPhi(v02), - -TMath::Pi(), harmonicDphi)); - - const int s1 = mcacc::v0Status(v0); - const int s2 = mcacc::v0Status(v02); + const bool doMixLeg1 = (cfgMixLegMode.value == 0 || cfgMixLegMode.value == 2); + const bool doMixLeg2 = (cfgMixLegMode.value == 1 || cfgMixLegMode.value == 2); - if (s1 == 0 && s2 == 0) { - fillHistograms(0, 0, lambda, lambda2, proton, proton2, 0, 1.0f); - } else if (s1 == 0 && s2 == 1) { - fillHistograms(0, 1, lambda, lambda2, proton, proton2, 0, 1.0f); - } else if (s1 == 1 && s2 == 0) { - fillHistograms(0, 1, lambda2, lambda, proton2, proton, 0, 1.0f); - } else if (s1 == 1 && s2 == 1) { - fillHistograms(1, 1, lambda, lambda2, proton, proton2, 0, 1.0f); + // Fill TGT maps before searching for replacements. This makes TGT the + // true same-event target phase space for the selected pair, matching the + // hPtYSame definition. REP below is filled only for accepted replacements. + if (doMixLeg1) { + fillReplacementControlMap(t1.v0Status(), t2.v0Status(), 1, true, + ROOT::Math::PtEtaPhiMVector(t1.lambdaPt(), t1.lambdaEta(), t1.lambdaPhi(), t1.lambdaMass()), + 1.0f); + fillFixedLegControlMap(t1.v0Status(), t2.v0Status(), 1, true, + ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), t2.lambdaMass()), + 1.0f); + } + if (doMixLeg2) { + fillReplacementControlMap(t1.v0Status(), t2.v0Status(), 2, true, + ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), t2.lambdaMass()), + 1.0f); + fillFixedLegControlMap(t1.v0Status(), t2.v0Status(), 2, true, + ROOT::Math::PtEtaPhiMVector(t1.lambdaPt(), t1.lambdaEta(), t1.lambdaPhi(), t1.lambdaMass()), + 1.0f); } - } - } - } - PROCESS_SWITCH(lambdaspincorrderived, processMC, "Process MC (SE)", false); - static inline float phi0To2Pi(float phi) - { - // harmonic=1, min=0 => [0, 2pi) - return RecoDecay::constrainAngle(phi, 0.0f, 1); - } + if (doMixLeg1) { + collectMatchesForReplacedLeg(t1, t2, colBin, curColIdx, matches1); + limitMatchesToNEvents(matches1, nEvtMixing.value); + downsampleMatches(matches1, (uint64_t)t1.globalIndex() ^ (splitmix64((uint64_t)t2.globalIndex()) + 0x111ULL) ^ splitmix64((uint64_t)curColIdx)); + } else { + matches1.clear(); + } - static inline float deltaPhiMinusPiToPi(float phiA, float phiB) - { - // returns in [-pi, pi) - const float d = phi0To2Pi(phiA) - phi0To2Pi(phiB); - return RecoDecay::constrainAngle(d, -TMath::Pi(), 1); - } + if (doMixLeg2) { + collectMatchesForReplacedLeg(t2, t1, colBin, curColIdx, matches2); + limitMatchesToNEvents(matches2, nEvtMixing.value); + downsampleMatches(matches2, (uint64_t)t2.globalIndex() ^ (splitmix64((uint64_t)t1.globalIndex()) + 0x222ULL) ^ splitmix64((uint64_t)curColIdx)); + } else { + matches2.clear(); + } - static inline float absDeltaPhi(float phiA, float phiB) - { - return std::abs(deltaPhiMinusPiToPi(phiA, phiB)); - } + // Do not fill TGT here. TGT has already been filled above as the + // selected same-event target phase space, independent of replacement success. + int nFill1 = 0; + int nFill2 = 0; + // count actual accepted fills for leg-1 replacement + if (doMixLeg1) { + for (auto const& m : matches1) { + auto tX = V0s.iteratorAt(static_cast(m.rowIndex)); + if (!selectionV0(tX)) + continue; + if (tX.v0Status() != t1.v0Status()) + continue; + if (!checkKinematics(t1, tX)) + continue; + if (tX.globalIndex() == t1.globalIndex()) + continue; + if (tX.globalIndex() == t2.globalIndex()) + continue; + if (hasSharedDaughters(tX, t2)) + continue; + if (hasSharedDaughters(tX, t1)) + continue; + ++nFill1; + } + } - // symmetric neighbors for phi with periodic wrap at 0/2pi - static inline void collectNeighborBinsPhi(int b, int nPhi, int nNeighbor, std::vector& out) - { - out.clear(); - if (nPhi <= 0 || b < 0 || b >= nPhi) { - return; - } + // count actual accepted fills for leg-2 replacement + if (doMixLeg2) { + for (auto const& m : matches2) { + auto tY = V0s.iteratorAt(static_cast(m.rowIndex)); + if (!selectionV0(tY)) + continue; + if (tY.v0Status() != t2.v0Status()) + continue; + if (!checkKinematics(t2, tY)) + continue; + if (tY.globalIndex() == t2.globalIndex()) + continue; + if (tY.globalIndex() == t1.globalIndex()) + continue; + if (hasSharedDaughters(tY, t2)) + continue; + if (hasSharedDaughters(tY, t1)) + continue; + ++nFill2; + } + } - if (2 * nNeighbor + 1 >= nPhi) { - out.reserve(nPhi); - for (int bb = 0; bb < nPhi; ++bb) { - out.push_back(bb); - } - return; - } + if (cfgV6CarryUnmatched) { + const auto hasPendingSpace = [&]() { + return cfgV6MaxPendingBranches.value <= 0 || static_cast(v6Pending.data.size()) < cfgV6MaxPendingBranches.value; + }; + if (doMixLeg1 && nFill1 == 0 && hasPendingSpace()) { + v6Pending.data.push_back({storeV6Candidate(t1, curColIdx), storeV6Candidate(t2, curColIdx), colBin, 1, 0, + static_cast(t1.globalIndex()) ^ splitmix64(static_cast(t2.globalIndex())) ^ splitmix64(static_cast(curColIdx))}); + ++pendingAdded; + } + if (doMixLeg2 && nFill2 == 0 && hasPendingSpace()) { + v6Pending.data.push_back({storeV6Candidate(t2, curColIdx), storeV6Candidate(t1, curColIdx), colBin, 2, 0, + static_cast(t2.globalIndex()) ^ splitmix64(static_cast(t1.globalIndex())) ^ splitmix64(static_cast(curColIdx))}); + ++pendingAdded; + } + } - out.reserve(2 * nNeighbor + 1); - for (int d = -nNeighbor; d <= nNeighbor; ++d) { - int bb = (b + d) % nPhi; - if (bb < 0) { - bb += nPhi; - } - out.push_back(bb); - } + if (nFill1 <= 0 && nFill2 <= 0) { + continue; + } + // Residual-weight QA needs a leg-specific normalization: + // TGT_leg is filled once per same-event target candidate with weight 1. + // REP_leg is the average replacement distribution for that same target. + const float wSELeg1 = (nFill1 > 0) ? 1.0f / static_cast(nFill1) : 0.0f; + const float wSELeg2 = (nFill2 > 0) ? 1.0f / static_cast(nFill2) : 0.0f; - std::sort(out.begin(), out.end()); - out.erase(std::unique(out.begin(), out.end()), out.end()); - } + const int nActiveMixBranches = ((doMixLeg1 && nFill1 > 0) ? 1 : 0) + + ((doMixLeg2 && nFill2 > 0) ? 1 : 0); + float branchNorm = 1.0f; + if (cfgMixLegMode.value == 2) { + branchNorm = cfgV6CarryUnmatched ? 0.5f : 1.0f / static_cast(nActiveMixBranches); + } + const float finalMixWeightLeg1 = branchNorm * wSELeg1; + const float finalMixWeightLeg2 = branchNorm * wSELeg2; - static inline void collectNeighborBinsClamp(int b, int nBins, int nNeighbor, std::vector& out) - { - out.clear(); - out.reserve(2 * nNeighbor + 1); - for (int d = -nNeighbor; d <= nNeighbor; ++d) { - const int bb = b + d; - if (bb >= 0 && bb < nBins) { - out.push_back(bb); - } - } - } - static inline void collectNeighborBinsMass(int b, int nBins, int nNeighbor, std::vector& out) - { - out.clear(); - out.reserve(2 * nNeighbor + 1); + // Do not fill target maps here: TGT has already been filled above, + // before searching for replacements, so that TGT represents all selected + // same-event targets rather than only targets with successful replacements. - for (int d = -nNeighbor; d <= nNeighbor; ++d) { - const int bb = b + d; - if (bb >= 0 && bb < nBins) { - out.push_back(bb); - } - } + if (doMixLeg1 && nFill1 > 0) { + for (auto const& m : matches1) { + auto tX = V0s.iteratorAt(static_cast(m.rowIndex)); + if (!selectionV0(tX)) { + continue; + } + if (tX.v0Status() != t1.v0Status()) + continue; + if (!checkKinematics(t1, tX)) + continue; + if (tX.globalIndex() == t1.globalIndex()) + continue; + if (tX.globalIndex() == t2.globalIndex()) + continue; + if (hasSharedDaughters(tX, t1)) + continue; + if (hasSharedDaughters(tX, t2)) + continue; + fillReplacementControlMap(tX.v0Status(), t2.v0Status(), 1, false, + ROOT::Math::PtEtaPhiMVector(tX.lambdaPt(), tX.lambdaEta(), tX.lambdaPhi(), tX.lambdaMass()), + wSELeg1); + // Fixed leg for leg1 replacement is original t2. + // Fill only for successful replacement. + fillFixedLegControlMap(tX.v0Status(), t2.v0Status(), 1, false, + ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), t2.lambdaMass()), + wSELeg1); + auto proton = ROOT::Math::PtEtaPhiMVector(tX.protonPt(), tX.protonEta(), tX.protonPhi(), o2::constants::physics::MassProton); + auto lambda = ROOT::Math::PtEtaPhiMVector(tX.lambdaPt(), tX.lambdaEta(), tX.lambdaPhi(), tX.lambdaMass()); + auto proton2 = ROOT::Math::PtEtaPhiMVector(t2.protonPt(), t2.protonEta(), t2.protonPhi(), o2::constants::physics::MassProton); + auto lambda2 = ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), t2.lambdaMass()); - std::sort(out.begin(), out.end()); - out.erase(std::unique(out.begin(), out.end()), out.end()); - } + // const int ptype = pairTypeCode(tX.v0Status(), t2.v0Status()); - static inline int getMassRegionFromEdges(float m, const std::vector& edges) - { - if (edges.size() != 4) { - return -1; - } + const float meWeight = finalMixWeightLeg1; + const float dPhi = deltaPhiMinusPiToPi((float)lambda.Phi(), (float)lambda2.Phi()); + if ((tX.v0Status() == 0 && t2.v0Status() == 1) || (tX.v0Status() == 1 && t2.v0Status() == 0)) + if (fillBasicQAHistos) + histos.fill(HIST("deltaPhiMix"), dPhi, meWeight); + const int s1 = tX.v0Status(); + const int s2 = t2.v0Status(); - if (m >= edges[0] && m < edges[1]) - return 0; // low sideband - if (m >= edges[1] && m < edges[2]) - return 1; // signal - if (m >= edges[2] && m < edges[3]) - return 2; // high sideband + if (s1 == 0 && s2 == 1) { + fillHistograms(0, 1, lambda, lambda2, proton, proton2, 1, meWeight, 1, 1); + } else if (s1 == 1 && s2 == 0) { + fillHistograms(0, 1, lambda2, lambda, proton2, proton, 1, meWeight, 2, 1); + } else { + fillHistograms(s1, s2, lambda, lambda2, proton, proton2, 1, meWeight, 1, 1); + } + } + } - return -1; - } - static inline int getMassMixClassFromEdges(float m, const std::vector& edges) - { - // no mass separation - if (edges.size() == 2) { - if (m >= edges[0] && m < edges[1]) - return 0; - return -1; - } + if (doMixLeg2 && nFill2 > 0) { + for (auto const& m : matches2) { + auto tY = V0s.iteratorAt(static_cast(m.rowIndex)); + if (!selectionV0(tY)) { + continue; + } + if (tY.v0Status() != t2.v0Status()) + continue; + if (!checkKinematics(t2, tY)) + continue; + if (tY.globalIndex() == t2.globalIndex()) + continue; + if (tY.globalIndex() == t1.globalIndex()) + continue; + if (hasSharedDaughters(tY, t1)) + continue; + if (hasSharedDaughters(tY, t2)) + continue; + fillReplacementControlMap(t1.v0Status(), tY.v0Status(), 2, false, + ROOT::Math::PtEtaPhiMVector(tY.lambdaPt(), tY.lambdaEta(), tY.lambdaPhi(), tY.lambdaMass()), + wSELeg2); + // Fixed leg for leg2 replacement is original t1. + // Fill only for successful replacement. + fillFixedLegControlMap(t1.v0Status(), tY.v0Status(), 2, false, + ROOT::Math::PtEtaPhiMVector(t1.lambdaPt(), t1.lambdaEta(), t1.lambdaPhi(), t1.lambdaMass()), + wSELeg2); + auto proton = ROOT::Math::PtEtaPhiMVector(t1.protonPt(), t1.protonEta(), t1.protonPhi(), o2::constants::physics::MassProton); + auto lambda = ROOT::Math::PtEtaPhiMVector(t1.lambdaPt(), t1.lambdaEta(), t1.lambdaPhi(), t1.lambdaMass()); + auto proton2 = ROOT::Math::PtEtaPhiMVector(tY.protonPt(), tY.protonEta(), tY.protonPhi(), o2::constants::physics::MassProton); + auto lambda2 = ROOT::Math::PtEtaPhiMVector(tY.lambdaPt(), tY.lambdaEta(), tY.lambdaPhi(), tY.lambdaMass()); - // 3 regions: SB low, signal, SB high - if (edges.size() == 4) { - if (m >= edges[0] && m < edges[1]) - return 0; // low sideband - if (m >= edges[1] && m < edges[2]) - return 1; // signal - if (m >= edges[2] && m < edges[3]) - return 0; // high sideband merged with low sideband - return -1; + // const int ptype = pairTypeCode(t1.v0Status(), tY.v0Status()); + const float meWeight = finalMixWeightLeg2; + const float dPhi = deltaPhiMinusPiToPi((float)lambda.Phi(), (float)lambda2.Phi()); + if (fillBasicQAHistos) + histos.fill(HIST("deltaPhiMix"), dPhi, meWeight); + const int s1 = t1.v0Status(); + const int s2 = tY.v0Status(); + if (s1 == 0 && s2 == 1) { + fillHistograms(0, 1, lambda, lambda2, proton, proton2, 1, meWeight, 2, 2); + } else if (s1 == 1 && s2 == 0) { + fillHistograms(0, 1, lambda2, lambda, proton2, proton, 1, meWeight, 1, 2); + } else { + fillHistograms(s1, s2, lambda, lambda2, proton, proton2, 1, meWeight, 2, 2); + } + } + } + } + } + if (cfgV6LogPending) { + LOGF(info, "MEV6 data pending branches: carriedIn=%zu matched=%zu expired=%zu newlyPropagated=%zu carriedToNext=%zu", + pendingAtStart, pendingMatched, pendingExpired, pendingAdded, v6Pending.data.size()); } - - return -1; - } - static inline uint64_t splitmix64(uint64_t x) - { - // simple deterministic hash for reproducible shuffling - x += 0x9e3779b97f4a7c15ULL; - x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL; - x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL; - return x ^ (x >> 31); } + PROCESS_SWITCH(lambdaspincorrderived, processMEV6, "Process data ME v6 with radius buffer", false); - void processMEV6(EventCandidates const& collisions, AllTrackCandidates const& V0s) + void processMEV6Sys(EventCandidates const& collisions, AllTrackCandidates const& V0s) { MixBinnerR mb{ ptMin.value, @@ -2165,9 +3161,16 @@ struct lambdaspincorrderived { auto slice = V0s.sliceBy(tracksPerCollisionV0, col.index()); for (auto const& t : slice) { - if (!selectionV0(t)) { - continue; + + bool passedAny = false; + for (int sysId = 0; sysId < nSysTotal; ++sysId) { + if (selectionV0Sys(t, sysCuts[sysId])) { + passedAny = true; + break; + } } + if (!passedAny) + continue; const int status = static_cast(t.v0Status()); if (status < 0 || status >= nStat) { @@ -2240,9 +3243,9 @@ struct lambdaspincorrderived { auto collectFromBins = [&](const std::vector& ptUseBins, const std::vector& etaUseBins, const std::vector& phiUseBins) { - for (int ptUse : ptUseBins) { - for (int etaUse : etaUseBins) { - for (int phiUse : phiUseBins) { + for (const auto& ptUse : ptUseBins) { + for (const auto& etaUse : etaUseBins) { + for (const auto& phiUse : phiUseBins) { const auto& vec = buffer[linearKeyR(colBin, status, ptUse, etaUse, phiUse, mB, rB, nStat, nPt, nEta, nPhi, nM, nR)]; @@ -2252,8 +3255,16 @@ struct lambdaspincorrderived { auto tX = V0s.iteratorAt(static_cast(bc.rowIndex)); - if (!selectionV0(tX)) + bool tXPassed = false; + for (int sysId = 0; sysId < nSysTotal; ++sysId) { + if (selectionV0Sys(tX, sysCuts[sysId])) { + tXPassed = true; + break; + } + } + if (!tXPassed) continue; + if (!checkKinematics(tRep, tX)) continue; @@ -2296,9 +3307,9 @@ struct lambdaspincorrderived { collectNeighborBinsClamp(etaB, nEta, nN_eta, etaBinsN); collectNeighborBinsPhi(phiB, nPhi, nN_phi, phiBinsN); - for (int ptUse : ptBinsN) { - for (int etaUse : etaBinsN) { - for (int phiUse : phiBinsN) { + for (const auto& ptUse : ptBinsN) { + for (const auto& etaUse : etaBinsN) { + for (const auto& phiUse : phiBinsN) { if (ptUse == ptB && etaUse == etaB && phiUse == phiB) continue; @@ -2311,8 +3322,16 @@ struct lambdaspincorrderived { auto tX = V0s.iteratorAt(static_cast(bc.rowIndex)); - if (!selectionV0(tX)) + bool tXPassed = false; + for (int sysId = 0; sysId < nSysTotal; ++sysId) { + if (selectionV0Sys(tX, sysCuts[sysId])) { + tXPassed = true; + break; + } + } + if (!tXPassed) continue; + if (!checkKinematics(tRep, tX)) continue; @@ -2430,9 +3449,16 @@ struct lambdaspincorrderived { auto poolA = V0s.sliceBy(tracksPerCollisionV0, col1.index()); for (auto const& [t1, t2] : soa::combinations(o2::soa::CombinationsFullIndexPolicy(poolA, poolA))) { - if (!selectionV0(t1) || !selectionV0(t2)) { - continue; + + std::vector commonSys; + for (int sysId = 0; sysId < nSysTotal; ++sysId) { + if (selectionV0Sys(t1, sysCuts[sysId]) && selectionV0Sys(t2, sysCuts[sysId])) { + commonSys.push_back(sysId); + } } + if (commonSys.empty()) + continue; + if (t2.index() <= t1.index()) { continue; } @@ -2441,9 +3467,7 @@ struct lambdaspincorrderived { const bool doMixLeg1 = (cfgMixLegMode.value == 0 || cfgMixLegMode.value == 2); const bool doMixLeg2 = (cfgMixLegMode.value == 1 || cfgMixLegMode.value == 2); - // Fill TGT maps before searching for replacements. This makes TGT the - // true same-event target phase space for the selected pair, matching the - // hPtYSame definition. REP below is filled only for accepted replacements. + // Fill TGT maps before searching for replacements. if (doMixLeg1) { fillReplacementControlMap(t1.v0Status(), t2.v0Status(), 1, true, ROOT::Math::PtEtaPhiMVector(t1.lambdaPt(), t1.lambdaEta(), t1.lambdaPhi(), t1.lambdaMass()), @@ -2477,15 +3501,22 @@ struct lambdaspincorrderived { matches2.clear(); } - // Do not fill TGT here. TGT has already been filled above as the - // selected same-event target phase space, independent of replacement success. int nFill1 = 0; int nFill2 = 0; + // count actual accepted fills for leg-1 replacement if (doMixLeg1) { for (auto const& m : matches1) { auto tX = V0s.iteratorAt(static_cast(m.rowIndex)); - if (!selectionV0(tX)) + + bool hasCommon = false; + for (const auto& sysId : commonSys) { + if (selectionV0Sys(tX, sysCuts[sysId])) { + hasCommon = true; + break; + } + } + if (!hasCommon) continue; if (tX.v0Status() != t1.v0Status()) continue; @@ -2503,11 +3534,17 @@ struct lambdaspincorrderived { } } - // count actual accepted fills for leg-2 replacement if (doMixLeg2) { for (auto const& m : matches2) { auto tY = V0s.iteratorAt(static_cast(m.rowIndex)); - if (!selectionV0(tY)) + bool hasCommon = false; + for (const auto& sysId : commonSys) { + if (selectionV0Sys(tY, sysCuts[sysId])) { + hasCommon = true; + break; + } + } + if (!hasCommon) continue; if (tY.v0Status() != t2.v0Status()) continue; @@ -2544,9 +3581,7 @@ struct lambdaspincorrderived { if (nFill1 <= 0 && nFill2 <= 0) { continue; } - // Residual-weight QA needs a leg-specific normalization: - // TGT_leg is filled once per same-event target candidate with weight 1. - // REP_leg is the average replacement distribution for that same target. + const float wSELeg1 = (nFill1 > 0) ? 1.0f / static_cast(nFill1) : 0.0f; const float wSELeg2 = (nFill2 > 0) ? 1.0f / static_cast(nFill2) : 0.0f; @@ -2559,16 +3594,11 @@ struct lambdaspincorrderived { const float finalMixWeightLeg1 = branchNorm * wSELeg1; const float finalMixWeightLeg2 = branchNorm * wSELeg2; - // Do not fill target maps here: TGT has already been filled above, - // before searching for replacements, so that TGT represents all selected - // same-event targets rather than only targets with successful replacements. - if (doMixLeg1 && nFill1 > 0) { for (auto const& m : matches1) { auto tX = V0s.iteratorAt(static_cast(m.rowIndex)); - if (!selectionV0(tX)) { + if (!selectionV0(tX)) continue; - } if (tX.v0Status() != t1.v0Status()) continue; if (!checkKinematics(t1, tX)) @@ -2581,35 +3611,38 @@ struct lambdaspincorrderived { continue; if (hasSharedDaughters(tX, t2)) continue; + fillReplacementControlMap(tX.v0Status(), t2.v0Status(), 1, false, ROOT::Math::PtEtaPhiMVector(tX.lambdaPt(), tX.lambdaEta(), tX.lambdaPhi(), tX.lambdaMass()), wSELeg1); - // Fixed leg for leg1 replacement is original t2. - // Fill only for successful replacement. fillFixedLegControlMap(tX.v0Status(), t2.v0Status(), 1, false, ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), t2.lambdaMass()), wSELeg1); + auto proton = ROOT::Math::PtEtaPhiMVector(tX.protonPt(), tX.protonEta(), tX.protonPhi(), o2::constants::physics::MassProton); auto lambda = ROOT::Math::PtEtaPhiMVector(tX.lambdaPt(), tX.lambdaEta(), tX.lambdaPhi(), tX.lambdaMass()); auto proton2 = ROOT::Math::PtEtaPhiMVector(t2.protonPt(), t2.protonEta(), t2.protonPhi(), o2::constants::physics::MassProton); auto lambda2 = ROOT::Math::PtEtaPhiMVector(t2.lambdaPt(), t2.lambdaEta(), t2.lambdaPhi(), t2.lambdaMass()); - // const int ptype = pairTypeCode(tX.v0Status(), t2.v0Status()); - const float meWeight = finalMixWeightLeg1; const float dPhi = deltaPhiMinusPiToPi((float)lambda.Phi(), (float)lambda2.Phi()); if ((tX.v0Status() == 0 && t2.v0Status() == 1) || (tX.v0Status() == 1 && t2.v0Status() == 0)) if (fillBasicQAHistos) histos.fill(HIST("deltaPhiMix"), dPhi, meWeight); + const int s1 = tX.v0Status(); const int s2 = t2.v0Status(); - if (s1 == 0 && s2 == 1) { - fillHistograms(0, 1, lambda, lambda2, proton, proton2, 1, meWeight, 1, 1); - } else if (s1 == 1 && s2 == 0) { - fillHistograms(0, 1, lambda2, lambda, proton2, proton, 1, meWeight, 2, 1); - } else { - fillHistograms(s1, s2, lambda, lambda2, proton, proton2, 1, meWeight, 1, 1); + for (const auto& sysId : commonSys) { + if (selectionV0Sys(tX, sysCuts[sysId])) { + if (s1 == 0 && s2 == 1) { + fillHistogramsSys(0, 1, lambda, lambda2, proton, proton2, 1, meWeight, sysId, 1, 1); + } else if (s1 == 1 && s2 == 0) { + fillHistogramsSys(0, 1, lambda2, lambda, proton2, proton, 1, meWeight, sysId, 2, 1); + } else { + fillHistogramsSys(s1, s2, lambda, lambda2, proton, proton2, 1, meWeight, sysId, 1, 1); + } + } } } } @@ -2617,9 +3650,8 @@ struct lambdaspincorrderived { if (doMixLeg2 && nFill2 > 0) { for (auto const& m : matches2) { auto tY = V0s.iteratorAt(static_cast(m.rowIndex)); - if (!selectionV0(tY)) { + if (!selectionV0(tY)) continue; - } if (tY.v0Status() != t2.v0Status()) continue; if (!checkKinematics(t2, tY)) @@ -2632,32 +3664,37 @@ struct lambdaspincorrderived { continue; if (hasSharedDaughters(tY, t2)) continue; + fillReplacementControlMap(t1.v0Status(), tY.v0Status(), 2, false, ROOT::Math::PtEtaPhiMVector(tY.lambdaPt(), tY.lambdaEta(), tY.lambdaPhi(), tY.lambdaMass()), wSELeg2); - // Fixed leg for leg2 replacement is original t1. - // Fill only for successful replacement. fillFixedLegControlMap(t1.v0Status(), tY.v0Status(), 2, false, ROOT::Math::PtEtaPhiMVector(t1.lambdaPt(), t1.lambdaEta(), t1.lambdaPhi(), t1.lambdaMass()), wSELeg2); + auto proton = ROOT::Math::PtEtaPhiMVector(t1.protonPt(), t1.protonEta(), t1.protonPhi(), o2::constants::physics::MassProton); auto lambda = ROOT::Math::PtEtaPhiMVector(t1.lambdaPt(), t1.lambdaEta(), t1.lambdaPhi(), t1.lambdaMass()); auto proton2 = ROOT::Math::PtEtaPhiMVector(tY.protonPt(), tY.protonEta(), tY.protonPhi(), o2::constants::physics::MassProton); auto lambda2 = ROOT::Math::PtEtaPhiMVector(tY.lambdaPt(), tY.lambdaEta(), tY.lambdaPhi(), tY.lambdaMass()); - // const int ptype = pairTypeCode(t1.v0Status(), tY.v0Status()); const float meWeight = finalMixWeightLeg2; const float dPhi = deltaPhiMinusPiToPi((float)lambda.Phi(), (float)lambda2.Phi()); if (fillBasicQAHistos) histos.fill(HIST("deltaPhiMix"), dPhi, meWeight); + const int s1 = t1.v0Status(); const int s2 = tY.v0Status(); - if (s1 == 0 && s2 == 1) { - fillHistograms(0, 1, lambda, lambda2, proton, proton2, 1, meWeight, 2, 2); - } else if (s1 == 1 && s2 == 0) { - fillHistograms(0, 1, lambda2, lambda, proton2, proton, 1, meWeight, 1, 2); - } else { - fillHistograms(s1, s2, lambda, lambda2, proton, proton2, 1, meWeight, 2, 2); + + for (const auto& sysId : commonSys) { + if (selectionV0Sys(tY, sysCuts[sysId])) { + if (s1 == 0 && s2 == 1) { + fillHistogramsSys(0, 1, lambda, lambda2, proton, proton2, 1, meWeight, sysId, 2, 2); + } else if (s1 == 1 && s2 == 0) { + fillHistogramsSys(0, 1, lambda2, lambda, proton2, proton, 1, meWeight, sysId, 1, 2); + } else { + fillHistogramsSys(s1, s2, lambda, lambda2, proton, proton2, 1, meWeight, sysId, 2, 2); + } + } } } } @@ -2668,7 +3705,7 @@ struct lambdaspincorrderived { pendingAtStart, pendingMatched, pendingExpired, pendingAdded, v6Pending.data.size()); } } - PROCESS_SWITCH(lambdaspincorrderived, processMEV6, "Process data ME v6 with radius buffer", false); + PROCESS_SWITCH(lambdaspincorrderived, processMEV6Sys, "Process data ME v6 Sys analysis", false); void processMCMEV6(EventCandidatesMC const& collisions, AllTrackCandidatesMC const& V0sMC) { @@ -2780,9 +3817,9 @@ struct lambdaspincorrderived { auto collectFromBins = [&](const std::vector& ptUseBins, const std::vector& etaUseBins, const std::vector& phiUseBins) { - for (int ptUse : ptUseBins) { - for (int etaUse : etaUseBins) { - for (int phiUse : phiUseBins) { + for (const auto& ptUse : ptUseBins) { + for (const auto& etaUse : etaUseBins) { + for (const auto& phiUse : phiUseBins) { const auto& vec = buffer[linearKeyR(colBin, status, ptUse, etaUse, phiUse, mB, rB, nStat, nPt, nEta, nPhi, nM, nR)]; @@ -2835,9 +3872,9 @@ struct lambdaspincorrderived { collectNeighborBinsClamp(etaB, nEta, nN_eta, etaBinsN); collectNeighborBinsPhi(phiB, nPhi, nN_phi, phiBinsN); - for (int ptUse : ptBinsN) { - for (int etaUse : etaBinsN) { - for (int phiUse : phiBinsN) { + for (const auto& ptUse : ptBinsN) { + for (const auto& etaUse : etaBinsN) { + for (const auto& phiUse : phiBinsN) { if (ptUse == ptB && etaUse == etaB && phiUse == phiB) { continue; } diff --git a/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx b/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx index b367a43747b..5ae932534dd 100644 --- a/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx +++ b/PWGLF/Tasks/Strangeness/nonPromptCascade.cxx @@ -194,6 +194,7 @@ struct NonPromptCascadeTask { // Produces NPCollsTable; Produces NPMCNTable; + Produces NPMCRecoCollAssocTable; Produces NPRecoCandTable; using TracksExtData = soa::Join; @@ -845,6 +846,7 @@ struct NonPromptCascadeTask { static constexpr float MinEtaFT0C = -3.3f; static constexpr float MaxEtaFT0C = -2.1f; static constexpr float InvalidEta = -999.f; + static constexpr int InvalidId = -1; auto isAcceptedMCParticleFT0 = [&](auto const& mcp) { if (!mcp.isPhysicalPrimary()) { @@ -909,6 +911,9 @@ struct NonPromptCascadeTask { // 2) Map aod::Collisions row id -> dense index in 'colls' // ------------------------------------------------------------ int maxCollRowId = -1; + for (auto const& col : colls) { + maxCollRowId = std::max(maxCollRowId, static_cast(col.globalIndex())); + } for (auto const& trk : tracks) { maxCollRowId = std::max(maxCollRowId, static_cast(trk.collisionId())); } @@ -957,23 +962,6 @@ struct NonPromptCascadeTask { // ------------------------------------------------------------ std::vector isReco(mcParticles.size(), 0); - // MC collision has a reconstructed collision in 'colls'. - // This must be independent of reco-track cuts. - std::vector mcCollisionHasRecoCollision(mcCollisions.size(), 0); - std::vector mcCollisionRecoMultFT0M(mcCollisions.size(), InvalidEta); - std::vector mcCollisionRecoCentFT0M(mcCollisions.size(), InvalidEta); - - for (auto const& col : colls) { - const int mcid = col.mcCollisionId(); - if (mcid >= 0 && static_cast(mcid) < mcCollisionHasRecoCollision.size()) { - mcCollisionHasRecoCollision[mcid] = 1; - mcCollisionRecoMultFT0M[mcid] = col.multFT0M(); - mcCollisionRecoCentFT0M[mcid] = col.centFT0M(); - } else { - LOG(info) << "4 This should never happen ?"; - } - } - // Downscale output table per MC collision std::vector writeMcCollision(mcCollisions.size(), 0); int ds = 1; @@ -997,7 +985,68 @@ struct NonPromptCascadeTask { } // ------------------------------------------------------------ - // 5) Matched reconstructed tracks + // 5) MC-to-reco collision associations. + // Save all associated reconstructed collisions, and keep one + // deterministic representative per MC collision for legacy row + // columns in NPMCChargedTable. + // ------------------------------------------------------------ + std::vector mcCollisionHasRecoCollision(mcCollisions.size(), 0); + std::vector mcCollisionBestRecoCollisionId(mcCollisions.size(), InvalidId); + std::vector mcCollisionBestRecoDenseIndex(mcCollisions.size(), InvalidId); + std::vector mcCollisionRecoMultFT0M(mcCollisions.size(), InvalidEta); + std::vector mcCollisionRecoCentFT0M(mcCollisions.size(), InvalidEta); + int nAssocRows = 0; + + denseIdx = 0; + for (auto const& col : colls) { + const int mcid = col.mcCollisionId(); + const int recoCollisionId = static_cast(col.globalIndex()); + if (mcid >= 0 && static_cast(mcid) < mcCollisionHasRecoCollision.size()) { + mcCollisionHasRecoCollision[mcid] = 1; + + if (writeRecoCollision[denseIdx]) { + NPMCRecoCollAssocTable(mcid, + recoCollisionId, + recoMultDense[denseIdx], + mcMult[mcid], + mcMultFT0[mcid], + col.multFT0M(), + col.centFT0M(), + col.selection_bit(aod::evsel::kNoSameBunchPileup)); + ++nAssocRows; + } + + if (mcCollisionBestRecoDenseIndex[mcid] == InvalidId || + col.multFT0M() > mcCollisionRecoMultFT0M[mcid]) { + mcCollisionBestRecoDenseIndex[mcid] = denseIdx; + mcCollisionBestRecoCollisionId[mcid] = recoCollisionId; + mcCollisionRecoMultFT0M[mcid] = col.multFT0M(); + mcCollisionRecoCentFT0M[mcid] = col.centFT0M(); + } + } else { + LOG(info) << "4 This should never happen ?"; + } + ++denseIdx; + } + + for (int mcid = 0; mcid < static_cast(mcCollisions.size()); ++mcid) { + if (mcCollisionHasRecoCollision[mcid] || !writeMcCollision[mcid]) { + continue; + } + NPMCRecoCollAssocTable(mcid, + InvalidId, + -1, + mcMult[mcid], + mcMultFT0[mcid], + InvalidEta, + InvalidEta, + false); + ++nAssocRows; + } + LOG(info) << "NPMCRecoCollisionAssoc rows filled: " << nAssocRows; + + // ------------------------------------------------------------ + // 6) Matched reconstructed tracks // ------------------------------------------------------------ for (auto const& trk : tracks) { if (!isAcceptedRecoTrack(trk)) { @@ -1017,6 +1066,7 @@ struct NonPromptCascadeTask { auto col = colls.rawIteratorAt(dIdx); const int mcCollId = col.mcCollisionId(); + const int recoCollisionId = static_cast(col.globalIndex()); const float multReco = recoMultDense[dIdx]; const float ptReco = trk.pt(); const float etaReco = trk.eta(); @@ -1026,7 +1076,7 @@ struct NonPromptCascadeTask { if (mcCollId < 0 || static_cast(mcCollId) >= mcCollisions.size()) { if (writeRecoCollision[dIdx]) { // Fake: accepted reco track whose reconstructed collision has no valid MC collision label. - NPMCNTable(-1.f, ptReco, InvalidEta, etaReco, multReco, -1.f, -1.f, multFT0M, centFT0M); + NPMCNTable(InvalidId, recoCollisionId, InvalidId, -1.f, ptReco, InvalidEta, etaReco, multReco, -1.f, -1.f, multFT0M, centFT0M); } continue; } @@ -1035,7 +1085,7 @@ struct NonPromptCascadeTask { if (mcPid < 0 || static_cast(mcPid) >= mcParticles.size()) { if (writeMcCollision[mcCollId]) { // Fake: accepted reco track with invalid or missing MC particle label. - NPMCNTable(-2.f, ptReco, InvalidEta, etaReco, multReco, -2.f, mcMultFT0[mcCollId], multFT0M, centFT0M); + NPMCNTable(mcCollId, recoCollisionId, InvalidId, -2.f, ptReco, InvalidEta, etaReco, multReco, -2.f, mcMultFT0[mcCollId], multFT0M, centFT0M); } continue; } @@ -1046,7 +1096,7 @@ struct NonPromptCascadeTask { if (mcParCollId != mcCollId) { if (writeMcCollision[mcCollId]) { // Fake: reco collision and particle label point to different MC collisions. - NPMCNTable(-3.f, ptReco, InvalidEta, etaReco, multReco, -3.f, mcMultFT0[mcCollId], multFT0M, centFT0M); + NPMCNTable(mcCollId, recoCollisionId, mcPid, -3.f, ptReco, InvalidEta, etaReco, multReco, -3.f, mcMultFT0[mcCollId], multFT0M, centFT0M); } continue; } @@ -1054,7 +1104,7 @@ struct NonPromptCascadeTask { if (!isAcceptedMCParticle(mcPar)) { if (writeMcCollision[mcCollId]) { // Feed-in: accepted reco track matched to truth outside fiducial phase space. - NPMCNTable(-4.f, ptReco, mcPar.eta(), etaReco, multReco, -4.f, mcMultFT0[mcCollId], multFT0M, centFT0M); + NPMCNTable(mcCollId, recoCollisionId, mcPid, -4.f, ptReco, mcPar.eta(), etaReco, multReco, -4.f, mcMultFT0[mcCollId], multFT0M, centFT0M); } continue; } @@ -1073,7 +1123,7 @@ struct NonPromptCascadeTask { if (writeMcCollision[mcCollId]) { // Matched: accepted truth particle reconstructed inside the fiducial reco phase space. - NPMCNTable(ptMC, ptReco, etaMC, etaReco, multReco, multMC, mcMultFT0[mcCollId], multFT0M, centFT0M); + NPMCNTable(mcCollId, recoCollisionId, mcPid, ptMC, ptReco, etaMC, etaReco, multReco, multMC, mcMultFT0[mcCollId], multFT0M, centFT0M); } } @@ -1081,12 +1131,12 @@ struct NonPromptCascadeTask { // 6) MC particles with no accepted reco track, // but from MC collisions that have a reconstructed collision // ------------------------------------------------------------ - for (int pid = 0; pid < static_cast(mcParticles.size()); ++pid) { - if (isReco[pid]) { + for (int mcParticleIndex = 0; mcParticleIndex < static_cast(mcParticles.size()); ++mcParticleIndex) { + if (isReco[mcParticleIndex]) { continue; } - auto mcp = mcParticles.rawIteratorAt(pid); + auto mcp = mcParticles.rawIteratorAt(mcParticleIndex); if (!isAcceptedMCParticle(mcp)) { continue; @@ -1105,6 +1155,7 @@ struct NonPromptCascadeTask { const float multMCFT0 = mcMultFT0[mcid]; const float multFT0M = mcCollisionRecoMultFT0M[mcid]; const float centFT0M = mcCollisionRecoCentFT0M[mcid]; + const int recoCollisionId = mcCollisionBestRecoCollisionId[mcid]; mRegistrydNdeta.fill(HIST("hdNdetaRM/hdNdetaRMNotInRecoTrk"), multMC, @@ -1112,7 +1163,7 @@ struct NonPromptCascadeTask { if (writeMcCollision[mcid]) { // Missed track: accepted truth particle in a reconstructed MC collision, but no accepted reco track. - NPMCNTable(mcp.pt(), -1.f, mcp.eta(), InvalidEta, -1.f, multMC, multMCFT0, multFT0M, centFT0M); + NPMCNTable(mcid, recoCollisionId, mcParticleIndex, mcp.pt(), -1.f, mcp.eta(), InvalidEta, -1.f, multMC, multMCFT0, multFT0M, centFT0M); } } @@ -1127,7 +1178,8 @@ struct NonPromptCascadeTask { const float multMC = mcMult[mcid]; const float multMCFT0 = mcMultFT0[mcid]; - for (auto const& mcp : mcParticles) { + for (int mcParticleIndex = 0; mcParticleIndex < static_cast(mcParticles.size()); ++mcParticleIndex) { + auto mcp = mcParticles.rawIteratorAt(mcParticleIndex); if (mcp.mcCollisionId() != mcid) { continue; } @@ -1142,7 +1194,7 @@ struct NonPromptCascadeTask { if (writeMcCollision[mcid]) { // Missed collision: accepted truth particle from an MC collision with no reconstructed collision. - NPMCNTable(mcp.pt(), -2.f, mcp.eta(), InvalidEta, -2.f, multMC, multMCFT0, InvalidEta, InvalidEta); + NPMCNTable(mcid, InvalidId, mcParticleIndex, mcp.pt(), -2.f, mcp.eta(), InvalidEta, -2.f, multMC, multMCFT0, InvalidEta, InvalidEta); } } } diff --git a/PWGLF/Tasks/Strangeness/sigmaanalysis.cxx b/PWGLF/Tasks/Strangeness/sigmaanalysis.cxx index c7bff11c752..fae9617f013 100644 --- a/PWGLF/Tasks/Strangeness/sigmaanalysis.cxx +++ b/PWGLF/Tasks/Strangeness/sigmaanalysis.cxx @@ -91,6 +91,7 @@ struct sigmaanalysis { // Species Configurable doLambdaStar{"doLambdaStar", false, "Build Lambda(1520) instead of Sigma0"}; + Configurable doArm{"doArm", true, "Fill the 3D Armenteros histograms"}; // Event level Configurable doPPAnalysis{"doPPAnalysis", true, "if in pp, set to true"}; @@ -292,6 +293,7 @@ struct sigmaanalysis { ConfigurableAxis axisPsiPair{"axisPsiPair", {250, -5.0f, 5.0f}, "Psipair for photons"}; ConfigurableAxis axisPhi{"axisPhi", {200, 0, 2 * o2::constants::math::PI}, "Phi for photons"}; ConfigurableAxis axisZ{"axisZ", {120, -120.0f, 120.0f}, "V0 Z position (cm)"}; + ConfigurableAxis axisOPAngle{"axisOPAngle", {140, 0.0f, 7.0f}, "Opening angle (rad)"}; // EMCal-specifc ConfigurableAxis axisClrDefinition{"axisClrDefinition", {51, -0.5, 50.5}, "Cluster Definition"}; @@ -350,6 +352,19 @@ struct sigmaanalysis { histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(19, "Below min IR"); histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(20, "Above max IR"); + // + if (doprocessAnalysedCollisions) { + histos.add("hEventPreSelection", "hEventPreSelection", kTH1D, {{8, -0.5f, +7.5f}}); + histos.get(HIST("hEventPreSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); + histos.get(HIST("hEventPreSelection"))->GetXaxis()->SetBinLabel(2, "kIsTriggerTVX"); + histos.get(HIST("hEventPreSelection"))->GetXaxis()->SetBinLabel(3, "kNoITSROFrameBorder"); + histos.get(HIST("hEventPreSelection"))->GetXaxis()->SetBinLabel(4, "kNoTimeFrameBorder"); + histos.get(HIST("hEventPreSelection"))->GetXaxis()->SetBinLabel(5, "posZ cut"); + histos.get(HIST("hEventPreSelection"))->GetXaxis()->SetBinLabel(6, "kNoSameBunchPileup"); + histos.get(HIST("hEventPreSelection"))->GetXaxis()->SetBinLabel(7, "RCT flags"); + histos.get(HIST("hEventPreSelection"))->GetXaxis()->SetBinLabel(8, "Preselected collisions"); + } + if (fGetIR) { histos.add("GeneralQA/hRunNumberNegativeIR", "", kTH1D, {{1, 0., 1.}}); histos.add("GeneralQA/hInteractionRate", "hInteractionRate", kTH1D, {axisIRBinning}); @@ -442,7 +457,10 @@ struct sigmaanalysis { histos.add(histodir + "/Sigma0/h2dRadiusVspT", "h2dRadiusVspT", kTH2D, {axisV0PairRadius, axisPt}); histos.add(histodir + "/Sigma0/hDCAPairDau", "hDCAPairDau", kTH1D, {axisDCAdau}); histos.add(histodir + "/Sigma0/h3dMass", "h3dMass", kTH3D, {axisCentrality, axisPt, axisSigmaMass}); - histos.add(histodir + "/Sigma0/h3dOPAngleVsMass", "h3dOPAngleVsMass", kTH3D, {{140, 0.0f, +7.0f}, axisPt, axisSigmaMass}); + histos.add(histodir + "/Sigma0/h3dOPAngleVsMass", "h3dOPAngleVsMass", kTH3D, {axisOPAngle, axisPt, axisSigmaMass}); + if (doArm) { + histos.add(histodir + "/Sigma0/h4dAlphaVsQtarmVsMass", "h4dAlphaVsQtarmVsMass", kTHnD, {axisAPAlpha, axisAPQt, axisPt, axisSigmaMass}); + } histos.add(histodir + "/ASigma0/hMass", "hMass", kTH1D, {axisSigmaMass}); histos.add(histodir + "/ASigma0/hPt", "hPt", kTH1D, {axisPt}); @@ -451,7 +469,10 @@ struct sigmaanalysis { histos.add(histodir + "/ASigma0/h2dRadiusVspT", "h2dRadiusVspT", kTH2D, {axisV0PairRadius, axisPt}); histos.add(histodir + "/ASigma0/hDCAPairDau", "hDCAPairDau", kTH1D, {axisDCAdau}); histos.add(histodir + "/ASigma0/h3dMass", "h3dMass", kTH3D, {axisCentrality, axisPt, axisSigmaMass}); - histos.add(histodir + "/ASigma0/h3dOPAngleVsMass", "h3dOPAngleVsMass", kTH3D, {{140, 0.0f, +7.0f}, axisPt, axisSigmaMass}); + histos.add(histodir + "/ASigma0/h3dOPAngleVsMass", "h3dOPAngleVsMass", kTH3D, {axisOPAngle, axisPt, axisSigmaMass}); + if (doArm) { + histos.add(histodir + "/ASigma0/h4dAlphaVsQtarmVsMass", "h4dAlphaVsQtarmVsMass", kTHnD, {axisAPAlpha, axisAPQt, axisPt, axisSigmaMass}); + } // Process MC if (doprocessMonteCarlo || doprocessMonteCarloWithEMCal) { @@ -490,6 +511,9 @@ struct sigmaanalysis { histos.add(histodir + "/MC/Sigma0/h2dMCProcessVsGenRadius", "h2dMCProcessVsGenRadius", kTH2D, {{50, -0.5f, 49.5f}, axisV0PairRadius}); histos.add(histodir + "/MC/Sigma0/h3dMass", "h3dMass", kTH3D, {axisCentrality, axisPt, axisSigmaMass}); histos.add(histodir + "/MC/Sigma0/h3dMCProcess", "h3dMCProcess", kTH3D, {{50, -0.5f, 49.5f}, axisPt, axisSigmaMass}); + if (doArm) { + histos.add(histodir + "/MC/Sigma0/h4dAlphaVsQtarmVsMass", "h4dAlphaVsQtarmVsMass", kTHnD, {axisAPAlpha, axisAPQt, axisPt, axisSigmaMass}); + } histos.add(histodir + "/MC/ASigma0/hPt", "hPt", kTH1D, {axisPt}); histos.add(histodir + "/MC/ASigma0/hMCPt", "hMCPt", kTH1D, {axisPt}); @@ -501,6 +525,12 @@ struct sigmaanalysis { histos.add(histodir + "/MC/ASigma0/h2dMCProcessVsGenRadius", "h2dMCProcessVsGenRadius", kTH2D, {{50, -0.5f, 49.5f}, axisV0PairRadius}); histos.add(histodir + "/MC/ASigma0/h3dMass", "h3dMass", kTH3D, {axisCentrality, axisPt, axisSigmaMass}); histos.add(histodir + "/MC/ASigma0/h3dMCProcess", "h3dMCProcess", kTH3D, {{50, -0.5f, 49.5f}, axisPt, axisSigmaMass}); + if (doArm) { + histos.add(histodir + "/MC/ASigma0/h4dAlphaVsQtarmVsMass", "h4dAlphaVsQtarmVsMass", kTHnD, {axisAPAlpha, axisAPQt, axisPt, axisSigmaMass}); + } + + histos.add(histodir + "/MC/LambdaStar/h3dMCPtvsOPAngle_Sig", "h3dMCPtvsOPAngle_Sig", kTH3D, {{140, 0.f, 7.f}, axisPt, axisSigmaMass}); + histos.add(histodir + "/MC/LambdaStar/h3dMCPtvsOPAngle_Bkg", "h3dMCPtvsOPAngle_Bkg", kTH3D, {{140, 0.f, 7.f}, axisPt, axisSigmaMass}); // pT Resolution: if (fillResoQAhistos) { @@ -768,12 +798,11 @@ struct sigmaanalysis { if (eventSelections.maxIR >= 0 && interactionRate > eventSelections.maxIR) { return false; } - if (fillHists) + if (fillHists) { histos.fill(HIST("hEventSelection"), 19 /* Above max IR */); - - // Fill centrality histogram after event selection - if (fillHists) + // Fill centrality histogram after event selection histos.fill(HIST("hEventCentrality"), centrality); + } histos.fill(HIST("hCentralityVsNch"), centrality, collision.multNTracksPVeta1()); return true; @@ -894,7 +923,7 @@ struct sigmaanalysis { fillGeneratedEventProperties(mcCollisions, collisions); std::vector listBestCollisionIdx = getListOfRecoCollIndices(mcCollisions, collisions); - for (auto& genParticle : genParticles) { + for (const auto& genParticle : genParticles) { float centrality = 100.5f; // Has MC collision @@ -1040,14 +1069,14 @@ struct sigmaanalysis { //_______________________________________ // Sigma and AntiSigma MC association - if (sigma.isSigma0()) { + if (doLambdaStar ? sigma.isLambdaStar() : sigma.isSigma0()) { histos.fill(HIST(MainDir[mode]) + HIST("/MC/Reso/h2dSigma0RadiusResolution"), sigma.mcpt(), sigma.radius() - sigma.mcradius()); // pT resolution if (sigma.mcpt() > 0) { histos.fill(HIST(MainDir[mode]) + HIST("/MC/Reso/h2dSigma0PtResolution"), sigma.mcpt(), (sigma.pt() / sigma.mcpt()) - 1.f); // pT resolution histos.fill(HIST(MainDir[mode]) + HIST("/MC/Reso/h2dSigma0InvPtResolution"), 1.f / sigma.mcpt(), 1.f / sigma.pt() - 1.f / sigma.mcpt()); // pT resolution } } - if (sigma.isAntiSigma0()) { + if (doLambdaStar ? sigma.isAntiLambdaStar() : sigma.isAntiSigma0()) { histos.fill(HIST(MainDir[mode]) + HIST("/MC/Reso/h2dASigma0RadiusResolution"), sigma.mcpt(), sigma.radius() - sigma.mcradius()); // pT resolution if (sigma.mcpt() > 0) histos.fill(HIST(MainDir[mode]) + HIST("/MC/Reso/h2dAntiSigma0PtResolution"), 1.f / sigma.mcpt(), 1.f / sigma.pt() - 1.f / sigma.mcpt()); // pT resolution @@ -1061,8 +1090,8 @@ struct sigmaanalysis { // Check whether it is before or after selections static constexpr std::string_view MainDir[] = {"BeforeSel", "AfterSel"}; - bool fIsSigma = sigma.isSigma0(); - bool fIsAntiSigma = sigma.isAntiSigma0(); + bool fIsSigma = doLambdaStar ? sigma.isLambdaStar() : sigma.isSigma0(); + bool fIsAntiSigma = doLambdaStar ? sigma.isAntiLambdaStar() : sigma.isAntiSigma0(); int PhotonPDGCode = sigma.photonPDGCode(); int PhotonPDGCodeMother = sigma.photonPDGCodeMother(); int LambdaPDGCode = sigma.lambdaPDGCode(); @@ -1180,6 +1209,8 @@ struct sigmaanalysis { //_______________________________________ // Sigmas and Lambdas + float rapidity = doLambdaStar ? sigma.lambdaStarY() : sigma.sigma0Y(); + if (sigma.lambdaAlpha() > 0) { if (fillSelhistos) { histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/h2dTPCvsTOFNSigma_LambdaPr"), sigma.lambdaPosPrTPCNSigma(), sigma.lambdaPrTOFNSigma()); @@ -1193,12 +1224,16 @@ struct sigmaanalysis { histos.fill(HIST(MainDir[mode]) + HIST("/Sigma0/hMass"), sigma.sigma0Mass()); histos.fill(HIST(MainDir[mode]) + HIST("/Sigma0/hPt"), sigma.pt()); - histos.fill(HIST(MainDir[mode]) + HIST("/Sigma0/hY"), sigma.sigma0Y()); + histos.fill(HIST(MainDir[mode]) + HIST("/Sigma0/hY"), rapidity); histos.fill(HIST(MainDir[mode]) + HIST("/Sigma0/hRadius"), sigma.radius()); histos.fill(HIST(MainDir[mode]) + HIST("/Sigma0/h2dRadiusVspT"), sigma.radius(), sigma.pt()); histos.fill(HIST(MainDir[mode]) + HIST("/Sigma0/hDCAPairDau"), sigma.dcadaughters()); histos.fill(HIST(MainDir[mode]) + HIST("/Sigma0/h3dMass"), centrality, sigma.pt(), sigma.sigma0Mass()); histos.fill(HIST(MainDir[mode]) + HIST("/Sigma0/h3dOPAngleVsMass"), sigma.opAngle(), sigma.pt(), sigma.sigma0Mass()); + if (doArm) { + histos.fill(HIST(MainDir[mode]) + HIST("/Sigma0/h4dAlphaVsQtarmVsMass"), sigma.lStarAlpha(), sigma.lStarQtarm(), sigma.pt(), sigma.sigma0Mass()); + } + } else { if (fillSelhistos) { histos.fill(HIST(MainDir[mode]) + HIST("/Lambda/h2dTPCvsTOFNSigma_ALambdaPr"), sigma.lambdaNegPrTPCNSigma(), sigma.aLambdaPrTOFNSigma()); @@ -1212,12 +1247,15 @@ struct sigmaanalysis { histos.fill(HIST(MainDir[mode]) + HIST("/ASigma0/hMass"), sigma.sigma0Mass()); histos.fill(HIST(MainDir[mode]) + HIST("/ASigma0/hPt"), sigma.pt()); - histos.fill(HIST(MainDir[mode]) + HIST("/ASigma0/hY"), sigma.sigma0Y()); + histos.fill(HIST(MainDir[mode]) + HIST("/ASigma0/hY"), rapidity); histos.fill(HIST(MainDir[mode]) + HIST("/ASigma0/hRadius"), sigma.radius()); histos.fill(HIST(MainDir[mode]) + HIST("/ASigma0/h2dRadiusVspT"), sigma.radius(), sigma.pt()); histos.fill(HIST(MainDir[mode]) + HIST("/ASigma0/hDCAPairDau"), sigma.dcadaughters()); histos.fill(HIST(MainDir[mode]) + HIST("/ASigma0/h3dMass"), centrality, sigma.pt(), sigma.sigma0Mass()); histos.fill(HIST(MainDir[mode]) + HIST("/ASigma0/h3dOPAngleVsMass"), sigma.opAngle(), sigma.pt(), sigma.sigma0Mass()); + if (doArm) { + histos.fill(HIST(MainDir[mode]) + HIST("/ASigma0/h4dAlphaVsQtarmVsMass"), sigma.lStarAlpha(), sigma.lStarQtarm(), sigma.pt(), sigma.sigma0Mass()); + } } //_______________________________________ @@ -1266,7 +1304,7 @@ struct sigmaanalysis { } //_______________________________________ // Sigma0 MC association - if (sigma.isSigma0()) { + if (doLambdaStar ? sigma.isLambdaStar() : sigma.isSigma0()) { histos.fill(HIST(MainDir[mode]) + HIST("/MC/Sigma0/hPt"), sigma.pt()); histos.fill(HIST(MainDir[mode]) + HIST("/MC/Sigma0/hMCPt"), sigma.mcpt()); @@ -1274,6 +1312,9 @@ struct sigmaanalysis { histos.fill(HIST(MainDir[mode]) + HIST("/MC/Sigma0/h2dMCPtVsPhotonMCPt"), sigma.mcpt(), sigma.photonmcpt()); histos.fill(HIST(MainDir[mode]) + HIST("/MC/Sigma0/hMass"), sigma.sigma0Mass()); histos.fill(HIST(MainDir[mode]) + HIST("/MC/Sigma0/h3dMass"), centrality, sigma.mcpt(), sigma.sigma0Mass()); + if (doArm) { + histos.fill(HIST(MainDir[mode]) + HIST("/MC/Sigma0/h4dAlphaVsQtarmVsMass"), sigma.lStarAlpha(), sigma.lStarQtarm(), sigma.mcpt(), sigma.sigma0Mass()); + } histos.fill(HIST(MainDir[mode]) + HIST("/MC/Sigma0/hMCProcess"), sigma.mcprocess()); histos.fill(HIST(MainDir[mode]) + HIST("/MC/Sigma0/hGenRadius"), sigma.mcradius()); @@ -1283,7 +1324,7 @@ struct sigmaanalysis { //_______________________________________ // AntiSigma0 MC association - if (sigma.isAntiSigma0()) { + if (doLambdaStar ? sigma.isAntiLambdaStar() : sigma.isAntiSigma0()) { histos.fill(HIST(MainDir[mode]) + HIST("/MC/ASigma0/hPt"), sigma.pt()); histos.fill(HIST(MainDir[mode]) + HIST("/MC/ASigma0/hMCPt"), sigma.mcpt()); @@ -1291,6 +1332,9 @@ struct sigmaanalysis { histos.fill(HIST(MainDir[mode]) + HIST("/MC/ASigma0/h2dMCPtVsPhotonMCPt"), sigma.mcpt(), sigma.photonmcpt()); histos.fill(HIST(MainDir[mode]) + HIST("/MC/ASigma0/hMass"), sigma.sigma0Mass()); histos.fill(HIST(MainDir[mode]) + HIST("/MC/ASigma0/h3dMass"), centrality, sigma.mcpt(), sigma.sigma0Mass()); + if (doArm) { + histos.fill(HIST(MainDir[mode]) + HIST("/MC/ASigma0/h4dAlphaVsQtarmVsMass"), sigma.lStarAlpha(), sigma.lStarQtarm(), sigma.mcpt(), sigma.sigma0Mass()); + } histos.fill(HIST(MainDir[mode]) + HIST("/MC/ASigma0/hMCProcess"), sigma.mcprocess()); histos.fill(HIST(MainDir[mode]) + HIST("/MC/ASigma0/hGenRadius"), sigma.mcradius()); @@ -1298,6 +1342,15 @@ struct sigmaanalysis { histos.fill(HIST(MainDir[mode]) + HIST("/MC/ASigma0/h3dMCProcess"), sigma.mcprocess(), sigma.mcpt(), sigma.sigma0Mass()); } + if (doLambdaStar) { + if (sigma.isAntiLambdaStar() || sigma.isLambdaStar()) { + histos.fill(HIST(MainDir[mode]) + HIST("/MC/LambdaStar/h3dMCPtvsOPAngle_Sig"), sigma.mcopAngle(), sigma.mcpt(), sigma.sigma0Mass()); + } + + if (!sigma.isAntiLambdaStar() && !sigma.isLambdaStar()) { + histos.fill(HIST(MainDir[mode]) + HIST("/MC/LambdaStar/h3dMCPtvsOPAngle_Bkg"), sigma.mcopAngle(), sigma.mcpt(), sigma.sigma0Mass()); + } + } // For background studies: if (fillBkgQAhistos) runBkgAnalysis(sigma); @@ -1621,7 +1674,7 @@ struct sigmaanalysis { // Sigma0 specific selections float rapidity = doLambdaStar ? cand.lambdaStarY() : cand.sigma0Y(); if constexpr (requires { cand.sigma0MCY(); }) { // If MC - rapidity = cand.sigma0MCY(); + rapidity = doLambdaStar ? cand.lambdaStarMCY() : cand.sigma0MCY(); } // Rapidity @@ -1667,7 +1720,8 @@ struct sigmaanalysis { // if MC if constexpr (requires { sigma0.isSigma0(); sigma0.isAntiSigma0(); }) { - if (doMCAssociation && !(sigma0.isSigma0() || sigma0.isAntiSigma0())) + bool fIsMCAssociated = doLambdaStar ? (sigma0.isLambdaStar() || sigma0.isAntiLambdaStar()) : (sigma0.isSigma0() || sigma0.isAntiSigma0()); + if (doMCAssociation && !fIsMCAssociated) continue; if (selRecoFromGenerator && !sigma0.isProducedByGenerator()) @@ -1835,6 +1889,23 @@ struct sigmaanalysis { } } + // ______________________________________________________ + // Simulated processing in Run 2 (subscribes to MC information too) + void processAnalysedCollisions(aod::StraSelections const& straSelections) + { + for (auto const& straSelection : straSelections) { + // Event selection criteria + histos.get(HIST("hEventPreSelection"))->AddBinContent(1, straSelection.totalNbrOfCollisions() /* all collisions */); + histos.get(HIST("hEventPreSelection"))->AddBinContent(2, straSelection.totalIsTriggerTVXCollisions() /* preselected IsTriggerTVX collisions */); + histos.get(HIST("hEventPreSelection"))->AddBinContent(3, straSelection.totalNoITSROFBorderCollisions() /* + preselected NoITSROF collisions */); + histos.get(HIST("hEventPreSelection"))->AddBinContent(4, straSelection.totalNoTFBorderCollisions() /* + preselected NoTF collisions */); + histos.get(HIST("hEventPreSelection"))->AddBinContent(5, straSelection.totalIsGoodZvtxCollisions() /* + preselected |Zvtx| < X cm collisions */); + histos.get(HIST("hEventPreSelection"))->AddBinContent(6, straSelection.totalNoSBPileupCollisions() /* + preselected NoSameBunchPileup collisions */); + histos.get(HIST("hEventPreSelection"))->AddBinContent(7, straSelection.totalIsGoodRCTCollisions() /* + preselected Good RCT collisions */); + histos.get(HIST("hEventPreSelection"))->AddBinContent(8, straSelection.totalNbrOfSelCollisions() /* total number of preselected collisions */); + } + } + void processRealData(soa::Join const& collisions, Sigma0s const& fullSigma0s) { analyzeRecoeSigma0s(collisions, fullSigma0s); @@ -1887,6 +1958,7 @@ struct sigmaanalysis { PROCESS_SWITCH(sigmaanalysis, processPi0RealData, "Do real data analysis for pi0 QA", false); PROCESS_SWITCH(sigmaanalysis, processPi0MonteCarlo, "Do Monte-Carlo-based analysis for pi0 QA", false); PROCESS_SWITCH(sigmaanalysis, processPi0GeneratedRun3, "process MC generated Run 3 for pi0 QA", false); + PROCESS_SWITCH(sigmaanalysis, processAnalysedCollisions, "process filtered events for bookkeeping", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGLF/Tasks/Strangeness/strangeCascTrack.cxx b/PWGLF/Tasks/Strangeness/strangeCascTrack.cxx index 65f4484fdb2..6d115211d88 100644 --- a/PWGLF/Tasks/Strangeness/strangeCascTrack.cxx +++ b/PWGLF/Tasks/Strangeness/strangeCascTrack.cxx @@ -170,7 +170,7 @@ struct StrangeCascTrack { } // checks general selection criteria for collisions template - bool isValidEvent(TEvent collision, bool fillHists) + bool isValidEvent(const TEvent& collision, bool fillHists) { bool passedAllSels = true; //* inel>0 cut @@ -238,7 +238,7 @@ struct StrangeCascTrack { } // checks cascade pt template - bool isValidPt(TCascade cascade, TString particle, int Type) + bool isValidPt(const TCascade& cascade, const TString& particle, int Type) { bool passedSel = true; double ptMin = 0.0; @@ -265,7 +265,7 @@ struct StrangeCascTrack { } // checks general selection criteria for cascades template - std::array isValidCasc(TEvent collision, TCascade cascade, TStdCascade stdcasc, TString particle) + std::array isValidCasc(const TEvent& collision, const TCascade& cascade, const TStdCascade& stdcasc, const TString& particle) { bool passedAllSels = true; // cascade rapidity @@ -342,7 +342,7 @@ struct StrangeCascTrack { } // checks TPC PID of dau tracks template - bool passesTPC(TCascade cascade, TString particle) + bool passesTPC(const TCascade& cascade, const TString& particle) { bool passedSel = true; const auto& posTrack = cascade.template posTrackExtra_as(); @@ -375,7 +375,7 @@ struct StrangeCascTrack { } // checks TOF PID of dau tracks template - bool passesTOF(TCascade cascade, TString particle) + bool passesTOF(const TCascade& cascade, const TString& particle) { bool passedSel = true; if (particle == "Xi") @@ -386,7 +386,7 @@ struct StrangeCascTrack { } // checks whether gen cascade corresponds to PDG code template - bool isValidPDG(TCascade cascade, TString particle) + bool isValidPDG(const TCascade& cascade, const TString& particle) { if (particle == "Xi" && std::abs(cascade.pdgCode()) == PDG_t::kXiMinus) return true; @@ -396,7 +396,7 @@ struct StrangeCascTrack { } // checks whether rec cascade is a truth primary xi or omega template - bool isMCTruth(const TCascade& cascade, TString particle) + bool isMCTruth(const TCascade& cascade, const TString& particle) { if constexpr (requires { cascade.has_cascMCCore(); }) { // safety check: discard rec cascade without gen reference auto cascmccore = cascade.template cascMCCore_as(); @@ -413,7 +413,7 @@ struct StrangeCascTrack { // applies selections for and fills histograms template - void analyseCascade(TEvent collision, TCasc cascade) + void analyseCascade(const TEvent& collision, TCasc cascade) { if constexpr (requires { cascade.topologyChi2(); }) { if (!cascade.has_standardCascade()) diff --git a/PWGLF/Tasks/Strangeness/strangenessInJetsIons.cxx b/PWGLF/Tasks/Strangeness/strangenessInJetsIons.cxx index 6f6a013eb70..0226cd533c7 100644 --- a/PWGLF/Tasks/Strangeness/strangenessInJetsIons.cxx +++ b/PWGLF/Tasks/Strangeness/strangenessInJetsIons.cxx @@ -1449,7 +1449,7 @@ struct StrangenessInJetsIons { // Return true if McCollisions has at least 1 RECO collisions that passed event selections template - bool HasRecoEvent(int mcCollIndex, RecoColls recoCollisions) + bool HasRecoEvent(int mcCollIndex, const RecoColls& recoCollisions) { for (const auto& recoColl : recoCollisions) { if (mcCollIndex == recoColl.mcCollisionId()) { @@ -1569,7 +1569,7 @@ struct StrangenessInJetsIons { // Fill Minimum Bias histograms template - void FillMBEventHistoMCREC(MCRecoCollision collision, + void FillMBEventHistoMCREC(const MCRecoCollision& collision, aod::McParticles const& mcParticles, V0PerColl const& v0sPerColl, CascPerColl const& cascPerColl, @@ -1777,7 +1777,7 @@ struct StrangenessInJetsIons { } template - void fillFeeddownMatrix(TV0 v0, float pt, float centrality, bool passedLambda, bool passedAntiLambda) + void fillFeeddownMatrix(const TV0& v0, float pt, float centrality, bool passedLambda, bool passedAntiLambda) // Fill feeddown matrix for Lambdas or AntiLambdas // Adapted from: PWGLF/Tasks/Strangeness/derivedlambdakzeroanalysis.cxx { diff --git a/PWGLF/Tasks/Strangeness/strangenessderivedbinnedinfo.cxx b/PWGLF/Tasks/Strangeness/strangenessderivedbinnedinfo.cxx index 3dea781c798..01c2bf31acc 100644 --- a/PWGLF/Tasks/Strangeness/strangenessderivedbinnedinfo.cxx +++ b/PWGLF/Tasks/Strangeness/strangenessderivedbinnedinfo.cxx @@ -351,7 +351,7 @@ struct strangenessderivedbinnedinfo { } template - bool isEventAccepted(TCollision collision, bool fillHists) + bool isEventAccepted(const TCollision& collision, bool fillHists) // check whether the collision passes our collision selections { if (fillHists) @@ -499,7 +499,7 @@ struct strangenessderivedbinnedinfo { } template - void fillEventHistograms(TCollision collision, float& centrality, float& occupancy) + void fillEventHistograms(const TCollision& collision, float& centrality, float& occupancy) { if (isPP) { // centrality = collision.centFT0M(); @@ -516,7 +516,7 @@ struct strangenessderivedbinnedinfo { } template - bool isV0Selected(TV0 v0, TCollision collision, float rapidity) + bool isV0Selected(const TV0& v0, const TCollision& collision, float rapidity) // precalculate this information so that a check is one mask operation, not many { // @@ -644,7 +644,7 @@ struct strangenessderivedbinnedinfo { } template - bool isCascadeSelected(TCascade casc, TCollision collision, float rapidity) + bool isCascadeSelected(const TCascade& casc, const TCollision& collision, float rapidity) // precalculate this information so that a check is one mask operation, not many { // diff --git a/PWGLF/Utils/CMakeLists.txt b/PWGLF/Utils/CMakeLists.txt index 8971e4a1597..b81a6eb7198 100644 --- a/PWGLF/Utils/CMakeLists.txt +++ b/PWGLF/Utils/CMakeLists.txt @@ -36,3 +36,7 @@ o2physics_add_library(LfStrangenessBuilderHelper o2physics_add_library(LfStrangenessBuilderModule SOURCES strangenessBuilderModule.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore KFParticle::KFParticle) + +o2physics_add_library(LfCascadeMlResponse + SOURCES cascadeMlResponse.cxx + PUBLIC_LINK_LIBRARIES O2Physics::MLCore) diff --git a/PWGLF/Utils/CascadeMlResponse.h b/PWGLF/Utils/CascadeMlResponse.h index ff72cf922f9..9a2ba4ddf54 100644 --- a/PWGLF/Utils/CascadeMlResponse.h +++ b/PWGLF/Utils/CascadeMlResponse.h @@ -20,6 +20,7 @@ #include "Tools/ML/MlResponse.h" +#include #include namespace o2::analysis diff --git a/PWGLF/Utils/cascadeMlResponse.cxx b/PWGLF/Utils/cascadeMlResponse.cxx new file mode 100644 index 00000000000..43cb3236f9b --- /dev/null +++ b/PWGLF/Utils/cascadeMlResponse.cxx @@ -0,0 +1,18 @@ +// 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. + +/// \file cascadeMlResponse.cxx +/// \brief Helper file providing the compilation command for the CascadeMlResponse header. +/// +/// \author ALICE Collaboration + +// o2-linter: disable=name/workflow-file (not a workflow file) +#include "CascadeMlResponse.h" // IWYU pragma: keep diff --git a/PWGLF/Utils/mcCentralityModule.h b/PWGLF/Utils/mcCentralityModule.h new file mode 100644 index 00000000000..0a7871609aa --- /dev/null +++ b/PWGLF/Utils/mcCentralityModule.h @@ -0,0 +1,736 @@ +// 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. + +/// +/// \file mcCentralityModule.cxx +/// \author Romain Schotter romain.schotter@cern.ch +/// \brief Module to produce MC centrality table based on ANY table containing MC multiplicity +/// + +#ifndef PWGLF_UTILS_MCCENTRALITYMODULE_H_ +#define PWGLF_UTILS_MCCENTRALITYMODULE_H_ + +#include "PWGLF/DataModel/mcCentrality.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//__________________________________________ +// strangeness builder module + +namespace o2 +{ +namespace pwglf +{ +namespace mccentrality // avoid polluting other namespaces +{ + +// statics necessary for the configurables in this namespace +static constexpr int nParameters = 1; +static const std::vector tableNames{ + "McCentFV0As", + "McCentFT0Ms", + "McCentFT0As", + "McCentFT0Cs", + "McCentFT0CVariant1s", + "McCentFT0CVariant2s", + "McCentFDDMs", + "McCentNTPVs", + "McCentNGlobals", + "McCentMFTs"}; + +static constexpr int nTablesConst = 10; +static const std::vector parameterNames{"enable"}; +static const int defaultParameters[nTablesConst][nParameters]{ + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}, + {-1}}; + +// table index : match order above +enum tableIndex { kFV0A = 0, + kFT0M, + kFT0A, + kFT0C, + kFT0CVariant1, + kFT0CVariant2, + kFDDM, + kNTPV, + kNGlobal, + kMFT, + kNestimators }; + +static constexpr const char* DirList[] = { + "FV0A", + "FT0M", + "FT0A", + "FT0C", + "FT0CVariant1", + "FT0CVariant2", + "FDDM", + "NTPV", + "NGlobal", + "MFT"}; + +// mcCentralityModule: 1st-order configurables +struct coreConfigurables : o2::framework::ConfigurableGroup { + o2::framework::Configurable> enabledTables{"enabledTables", + {defaultParameters[0], nTablesConst, nParameters, tableNames, parameterNames}, + "Produce this table: -1 for autodetect; otherwise, 0/1 is false/true"}; + std::vector mEnabledTables; // Vector of enabled tables + + o2::framework::Configurable recalibrateCentrality{"recalibrateCentrality", false, "If true, re-calibrate the MC centrality for the binning in binPercentile."}; + o2::framework::Configurable recalibrateMode{"recalibrateMode", 1, "Strategy to calibrate MC centrality? 0: from low to high mult.; 1: from high to low mult."}; + o2::framework::Configurable minEntries{"minEntries", 100, "Minimum number of entries for estimating the mean value for the recalibration"}; + o2::framework::Configurable doNotCrashOnNull{"doNotCrashOnNull", false, "If ccdb object does not exist, fill with dummy values"}; + + o2::framework::Configurable assignCentralityPerCandidate{"assignCentralityPerCandidate", false, "If true, assign centrality by sampling P(centrality|generated multiplicity) per MC collision instead of the class-averaged (statistical) value"}; + o2::framework::Configurable centralitySamplingSeed{"centralitySamplingSeed", 137, "Base seed of the RNG used to sample centrality in candidate-by-candidate mode (assignCentralityPerCandidate)"}; + o2::framework::ConfigurableAxis binsPercentile{"binsPercentile", {o2::framework::VARIABLE_WIDTH, 0, 1.0, 5.0, 10.0, 15.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0}, "Binning of the percentile axis"}; + o2::framework::ConfigurableAxis binsPercentileFine{"binsPercentileFine", {o2::framework::VARIABLE_WIDTH, 0, 0.001, 0.01, 1.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0}, "Binning of the percentile axis"}; + o2::framework::ConfigurableAxis binsMultiplicity{"binsMultiplicity", {1000, 0, 5000}, "Binning of the multiplicity axis"}; + + // ccdb configurables + o2::framework::Configurable path{"path", "/tmp/InputCalibMC.root", "path to calib file or ccdb path if begins with ccdb://"}; + + // debug option + o2::framework::Configurable verbose{"verbose", false, "If true, display more messages"}; +}; + +struct products : o2::framework::ProducesGroup { + // Tables to produce + o2::framework::Produces centFV0A; + o2::framework::Produces centFT0M; + o2::framework::Produces centFT0A; + o2::framework::Produces centFT0C; + o2::framework::Produces centFT0CVariant1; + o2::framework::Produces centFT0CVariant2; + o2::framework::Produces centFDDM; + o2::framework::Produces centNTPV; + o2::framework::Produces centNGlobal; + o2::framework::Produces centMFT; +}; + +template +concept HasMcMults = requires(typename T::iterator a) { + { a.multMCFT0A() } -> std::convertible_to; + { a.multMCFT0C() } -> std::convertible_to; + { a.multMCFV0A() } -> std::convertible_to; + { a.multMCFDDA() } -> std::convertible_to; + { a.multMCFDDC() } -> std::convertible_to; + { a.multMCNParticlesEta08() } -> std::convertible_to; + { a.multMCNParticlesEta05() } -> std::convertible_to; +}; + +/// Task to produce the response table +struct BuilderModule { + // Input parameters + o2::framework::Service ccdb; + + // declaration of structs here + // (N.B.: will be invisible to the outside, create your own copies) + coreConfigurables baseOpts; + + TList* MCCentralityCalibObjects = nullptr; + TH1D* h1dFV0A = nullptr; + TH1D* h1dFT0M = nullptr; + TH1D* h1dFT0A = nullptr; + TH1D* h1dFT0C = nullptr; + TH1D* h1dFT0CVariant1 = nullptr; + TH1D* h1dFT0CVariant2 = nullptr; + TH1D* h1dFDDM = nullptr; + TH1D* h1dNTPV = nullptr; + TH1D* h1dNGlobal = nullptr; + TH1D* h1dMFT = nullptr; + + // Calibration objects for candidate-by-candidate sampling (assignCentralityPerCandidate): + // x = centrality (%) of the matched reconstructed MC collision, y = generated multiplicity (|eta| < 0.5) + std::vector h2dCentVsGenMult; + TRandom3 fRandomSampler; + + // QA of the on-the-fly calibration (recalibrateCentrality): mean _{|eta|<0.5} in data and MC + // (reco), one entry per centrality class -- filled in extractCentralityCalibration(). + // Must be TProfile, not TH1D+SetBinContent/SetBinError: every grid job redundantly derives the exact + // same calibration from the same CCDB input, and grid-merged output histograms are combined via a + // plain bin-content sum (TH1::Merge), which would turn a mean into N_jobs*mean. TProfile stores the + // underlying sum(w)/sum(wy)/sum(wy^2) per bin and merges those correctly, so the mean/error recomputed + // from the merged output stay correct however many jobs contributed. For the same reason there is no + // ratio histogram here: a ratio of two already-merged means can't be reconstructed after the fact, so + // compute PVMC/PVData downstream from the merged output if you need it, not inside the task. + std::vector> hCalibPVData; + std::vector> hCalibPVMC; + + int nEnabledTables = 0; + int mRunNumber = 0; + + // TAxis + int nCentBins = 0; + std::vector centralityBins; + + // Registers the on-the-fly-calibration QA histograms for one estimator (no-op unless recalibrateCentrality + // is on): mean _{|eta|<0.5} in data and in MC (reco), one entry per centrality class, as TProfile + // (see the comment on hCalibPVData/hCalibPVMC for why TH1D+SetBinContent doesn't survive grid merging). + // Uses the runtime add() overload (returning the type-erased HistPtr) since the estimator name/directory + // is only known at runtime here, unlike fillHistograms() which relies on a compile-time HIST() lookup. + template + void registerCalibQAHistos(THistoRegistry& histos, int idx, const char* name) + { + if (!baseOpts.recalibrateCentrality) { + return; + } + o2::framework::AxisSpec axisCentClass{baseOpts.binsPercentile, Form("%s percentile (%%)", name)}; + hCalibPVData[idx] = std::get>(histos.add(Form("%s/calibPVData", name), Form("#LT #it{N}_{PV}^{Data} #GT vs %s percentile;%s percentile (%%);#LT #it{N}_{PV}^{Data} #GT_{|#it{#eta}|<0.5}", name, name), o2::framework::HistType::kTProfile, {axisCentClass})); + hCalibPVMC[idx] = std::get>(histos.add(Form("%s/calibPVMC", name), Form("#LT #it{N}_{PV}^{MC} #GT (reco) vs %s percentile;%s percentile (%%);#LT #it{N}_{PV}^{MC} #GT_{|#it{#eta}|<0.5} (reco)", name, name), o2::framework::HistType::kTProfile, {axisCentClass})); + } + + // Registers the candidate-by-candidate sampling QA (no-op unless assignCentralityPerCandidate is on): + // sampled percentile vs the generated multiplicity (|eta| < 0.5) actually used to key the sampling, so + // it can be visually compared against the input calibration (hGenMultEta05VsCentrality) to + // check that the sampled distribution reproduces the expected P(centrality|genMult). This is a plain + // TH2D (not a TProfile): unlike the calibration QA above, it stores a distribution to look at, not a + // mean to merge, so ordinary bin-content-sum merging across grid jobs is exactly what's wanted here. + template + void registerCandidateQAHistos(THistoRegistry& histos, const char* name) + { + if (!baseOpts.assignCentralityPerCandidate) { + return; + } + histos.add(Form("%s/percentileVsGenMultEta05", name), Form("Sampled %s percentile vs generated mult (|#it{#eta}|<0.5);%s percentile (%%);generated mult (|#it{#eta}|<0.5)", name, name), o2::framework::HistType::kTH2D, {{baseOpts.binsPercentileFine, Form("%s percentile", name)}, {baseOpts.binsMultiplicity, "generated mult (|#eta|<0.5)"}}); + } + + template + void init(TBaseConfigurables const& inputBaseOpts, THistoRegistry& histos, TInitContext& context) + { + // read in configurations from the task where it's used + // could be grouped even further, but should work + baseOpts = inputBaseOpts; + + baseOpts.mEnabledTables.resize(nTablesConst, 0); + h2dCentVsGenMult.resize(nTablesConst, nullptr); + hCalibPVData.resize(nTablesConst); + hCalibPVMC.resize(nTablesConst); + fRandomSampler.SetSeed(baseOpts.centralitySamplingSeed); + + LOGF(info, "Checking if MC centrality is required"); + auto& workflows = context.services().template get(); + + nEnabledTables = 0; + + TString listOfRequestors[nTablesConst]; + for (int i = 0; i < nTablesConst; i++) { + int f = baseOpts.enabledTables->get(tableNames[i].c_str(), "enable"); + if (f == 1) { + baseOpts.mEnabledTables[i] = 1; + listOfRequestors[i] = "manual enabling"; + nEnabledTables++; + } + if (f == -1) { + // autodetect this table in other devices + for (o2::framework::DeviceSpec const& device : workflows.devices) { + // Step 1: check if this device subscribed to the V0data table + for (auto const& input : device.inputs) { + if (o2::framework::DataSpecUtils::partialMatch(input.matcher, o2::header::DataOrigin("AOD"))) { + auto&& [origin, description, version] = o2::framework::DataSpecUtils::asConcreteDataMatcher(input.matcher); + std::string tableNameWithVersion = tableNames[i]; + if (version > 0) { + tableNameWithVersion += Form("_%03d", version); + } + if (input.matcher.binding == tableNameWithVersion) { + LOGF(info, "Device %s has subscribed to %s (version %i)", device.name, tableNames[i], version); + listOfRequestors[i].Append(Form("%s ", device.name.c_str())); + baseOpts.mEnabledTables[i] = 1; + nEnabledTables++; + } + } + } + } + } + } + + if (nEnabledTables == 0) { + LOGF(info, "MC centrality not required. Will suppress all functionality, including logs, from this point forward."); + return; + } + mRunNumber = 0; + + // TAxis + o2::framework::AxisSpec axisBinsPercentile{baseOpts.binsPercentile, "axisBinsPercentile"}; + nCentBins = axisBinsPercentile.binEdges.size() - 1; + for (std::size_t iCent = 0; iCent < axisBinsPercentile.binEdges.size(); iCent++) { + centralityBins.push_back(axisBinsPercentile.binEdges[iCent]); + } + + if (baseOpts.mEnabledTables[kFV0A]) { + histos.add("FV0A/percentile", "FV0A percentile.", o2::framework::HistType::kTH1D, {{baseOpts.binsPercentileFine, "FV0A percentile"}}); + histos.add("FV0A/percentilevsMult", "FV0A percentile.", o2::framework::HistType::kTH2D, {{baseOpts.binsPercentileFine, "FV0A percentile"}, {baseOpts.binsMultiplicity, "FV0A mult."}}); + registerCalibQAHistos(histos, kFV0A, "FV0A"); + registerCandidateQAHistos(histos, "FV0A"); + } + if (baseOpts.mEnabledTables[kFT0M]) { + histos.add("FT0M/percentile", "FT0M percentile.", o2::framework::HistType::kTH1D, {{baseOpts.binsPercentileFine, "FT0M percentile"}}); + histos.add("FT0M/percentilevsMult", "FT0M percentile.", o2::framework::HistType::kTH2D, {{baseOpts.binsPercentileFine, "FT0M percentile"}, {baseOpts.binsMultiplicity, "FT0M mult."}}); + registerCalibQAHistos(histos, kFT0M, "FT0M"); + registerCandidateQAHistos(histos, "FT0M"); + } + if (baseOpts.mEnabledTables[kFT0A]) { + histos.add("FT0A/percentile", "FT0A percentile.", o2::framework::HistType::kTH1D, {{baseOpts.binsPercentileFine, "FT0A percentile"}}); + histos.add("FT0A/percentilevsMult", "FT0A percentile.", o2::framework::HistType::kTH2D, {{baseOpts.binsPercentileFine, "FT0A percentile"}, {baseOpts.binsMultiplicity, "FT0A mult."}}); + registerCalibQAHistos(histos, kFT0A, "FT0A"); + registerCandidateQAHistos(histos, "FT0A"); + } + if (baseOpts.mEnabledTables[kFT0C]) { + histos.add("FT0C/percentile", "FT0C percentile.", o2::framework::HistType::kTH1D, {{baseOpts.binsPercentileFine, "FT0C percentile"}}); + histos.add("FT0C/percentilevsMult", "FT0C percentile.", o2::framework::HistType::kTH2D, {{baseOpts.binsPercentileFine, "FT0C percentile"}, {baseOpts.binsMultiplicity, "FT0C mult."}}); + registerCalibQAHistos(histos, kFT0C, "FT0C"); + registerCandidateQAHistos(histos, "FT0C"); + } + if (baseOpts.mEnabledTables[kFT0CVariant1]) { + histos.add("FT0CVariant1/percentile", "FT0CVariant1 percentile.", o2::framework::HistType::kTH1D, {{baseOpts.binsPercentileFine, "FT0CVariant1 percentile"}}); + histos.add("FT0CVariant1/percentilevsMult", "FT0CVariant1 percentile.", o2::framework::HistType::kTH2D, {{baseOpts.binsPercentileFine, "FT0CVariant1 percentile"}, {baseOpts.binsMultiplicity, "FT0C mult."}}); + registerCalibQAHistos(histos, kFT0CVariant1, "FT0CVariant1"); + registerCandidateQAHistos(histos, "FT0CVariant1"); + } + if (baseOpts.mEnabledTables[kFT0CVariant2]) { + histos.add("FT0CVariant2/percentile", "FT0CVariant2 percentile.", o2::framework::HistType::kTH1D, {{baseOpts.binsPercentileFine, "FT0CVariant2 percentile"}}); + histos.add("FT0CVariant2/percentilevsMult", "FT0CVariant2 percentile.", o2::framework::HistType::kTH2D, {{baseOpts.binsPercentileFine, "FT0CVariant2 percentile"}, {baseOpts.binsMultiplicity, "FT0C mult."}}); + registerCalibQAHistos(histos, kFT0CVariant2, "FT0CVariant2"); + registerCandidateQAHistos(histos, "FT0CVariant2"); + } + if (baseOpts.mEnabledTables[kFDDM]) { + histos.add("FDDM/percentile", "FDDM percentile.", o2::framework::HistType::kTH1D, {{baseOpts.binsPercentileFine, "FDDM percentile"}}); + histos.add("FDDM/percentilevsMult", "FDDM percentile.", o2::framework::HistType::kTH2D, {{baseOpts.binsPercentileFine, "FDDM percentile"}, {baseOpts.binsMultiplicity, "FDDM mult."}}); + registerCalibQAHistos(histos, kFDDM, "FDDM"); + registerCandidateQAHistos(histos, "FDDM"); + } + if (baseOpts.mEnabledTables[kNTPV]) { + histos.add("NTPV/percentile", "NTPV percentile.", o2::framework::HistType::kTH1D, {{baseOpts.binsPercentileFine, "NTPV percentile"}}); + histos.add("NTPV/percentilevsMult", "NTPV percentile.", o2::framework::HistType::kTH2D, {{baseOpts.binsPercentileFine, "NTPV percentile"}, {baseOpts.binsMultiplicity, "NTPV mult."}}); + registerCalibQAHistos(histos, kNTPV, "NTPV"); + registerCandidateQAHistos(histos, "NTPV"); + } + if (baseOpts.mEnabledTables[kNGlobal]) { + histos.add("NGlobal/percentile", "NGlobal percentile.", o2::framework::HistType::kTH1D, {{baseOpts.binsPercentileFine, "NGlobal percentile"}}); + histos.add("NGlobal/percentilevsMult", "NGlobal percentile.", o2::framework::HistType::kTH2D, {{baseOpts.binsPercentileFine, "NGlobal percentile"}, {baseOpts.binsMultiplicity, "NGlobal mult."}}); + registerCalibQAHistos(histos, kNGlobal, "NGlobal"); + registerCandidateQAHistos(histos, "NGlobal"); + } + if (baseOpts.mEnabledTables[kMFT]) { + histos.add("MFT/percentile", "MFT percentile.", o2::framework::HistType::kTH1D, {{baseOpts.binsPercentileFine, "MFT percentile"}}); + histos.add("MFT/percentilevsMult", "MFT percentile.", o2::framework::HistType::kTH2D, {{baseOpts.binsPercentileFine, "MFT percentile"}, {baseOpts.binsMultiplicity, "MFT mult."}}); + } + + LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + LOGF(info, " MC centrality: basic configuration listing"); + LOGF(info, "*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*"); + // list enabled tables + for (int i = 0; i < nTablesConst; i++) { + // printout to be improved in the future + if (baseOpts.mEnabledTables[i]) { + LOGF(info, " -~> Table enabled: %s, requested by %s", tableNames[i], listOfRequestors[i].Data()); + } + } + } + + template + THist* getHist(const char* name) + { + if (!this->MCCentralityCalibObjects) { + return (THist*)0x0; + } + auto hist = reinterpret_cast(this->MCCentralityCalibObjects->FindObject(name)); + if (!hist) { + if (this->baseOpts.verbose) { + this->MCCentralityCalibObjects->ls(); + } + if (this->baseOpts.doNotCrashOnNull) { + LOG(info) << "Could not open histogram " << name << " from TList, will fill tables with dummy values"; + } else { + LOG(fatal) << "Could not open histogram " << name << " from TList"; + } + } + return hist; + } + + TH1D* extractCentralityCalibration(int idx, const char* name, bool reverse = false) + { + + auto CalibMC = [&](TString const& estimator) { + LOGF(info, "Calibration for %s estimator -> Starting...\n", estimator.Data()); + + std::vector percentile_center(nCentBins); + std::vector epercentile_center(nCentBins); + + // Histograms + TH2D* h2dMultVsCent_Data = getHist(Form("hMultEta05VsCent%s_Data", estimator.Data())); + TH2D* h2dMultRecoVsMultGen_MC = getHist(Form("hMultEta05VsGenMult%s", estimator.Data())); + if (!h2dMultVsCent_Data || !h2dMultRecoVsMultGen_MC) { + return (TH1D*)0x0; + } + + // QA of this on-the-fly calibration: mean _{|eta|<0.5} in data/MC per centrality class, + // registered by registerCalibQAHistos() (only non-null when recalibrateCentrality is on). Filled + // bin-by-bin from projData/projMC below (TProfile::Fill(x, y, weight)), not via SetBinContent, so + // that the mean/error reconstructed from the merged grid output stay statistically correct. + TProfile* hPVData = hCalibPVData[idx].get(); + TProfile* hPVMC = hCalibPVMC[idx].get(); + + TH1D* h1dCalib = h2dMultRecoVsMultGen_MC->ProjectionX(Form("h1d%s", estimator.Data()), 1, h2dMultRecoVsMultGen_MC->GetNbinsX()); + h1dCalib->Reset(); + h1dCalib->SetTitle(Form("%s calibration object", estimator.Data())); + h1dCalib->GetXaxis()->SetTitle(Form("#it{N}_{%s, gen.}", estimator.Data())); + h1dCalib->GetYaxis()->SetTitle(Form("%s percentile (%%)", estimator.Data())); + + // NOTE: candidate-by-candidate assignment (assignCentralityPerCandidate) does not go through this + // mean-matching path at all. It samples directly from the "hGenMultEta05VsCentrality" + // joint histogram (x = reco centrality of the matched MC collision, y = generated mult |eta|<0.5) + // retrieved in initCCDB() below, see h2dCentVsGenMult and dataProcess(). + + if (reverse) { + for (int i = 0; i < nCentBins; i++) { + int irev = i; + percentile_center[i] = (centralityBins[irev] + centralityBins[irev + 1]) / 2; + epercentile_center[i] = (centralityBins[irev] - centralityBins[irev + 1]) / 2; + } + + int startBinMc = h1dCalib->GetNbinsX(); + for (int i = 0; i < nCentBins; i++) { // Loop over centrality bins + // start from the end (from the high multiplicity collisions) + int irev = i; + TH1D* projData = h2dMultVsCent_Data->ProjectionY(Form("projData_%d", i), h2dMultVsCent_Data->GetXaxis()->FindBin(centralityBins[irev] + 1e-5), + h2dMultVsCent_Data->GetXaxis()->FindBin(centralityBins[irev + 1] - 1e-5)); + + double meanMult_Data = projData->GetMean(); + + double meanMult_MC = -1; + double diffMultDataVsMC = 1e+09; + int endBinMc = startBinMc; + for (int j = startBinMc - 1; j >= 1; j--) { + // Loop over MC bins + TH1D* projMC = h2dMultRecoVsMultGen_MC->ProjectionY("", j, startBinMc); + int nEntries = projMC->Integral(); + double meanMC = projMC->GetMean(); + double ldiff = std::abs(meanMC - meanMult_Data); + // std::cout << ldiff << std::endl; + + // if less than 100 entries for estimating the mean, do not consider it + if (nEntries < baseOpts.minEntries) + continue; + + // Find the minimum difference and corresponding MC bin + if (ldiff < diffMultDataVsMC) { + diffMultDataVsMC = ldiff; + meanMult_MC = meanMC; + endBinMc = j; + } + } + if (i == nCentBins - 1) { + endBinMc = 1; + } + + TH1D* projMC = h2dMultRecoVsMultGen_MC->ProjectionY(Form("projMC_%d", i), endBinMc, startBinMc); + + // Refill the per-class mean from the underlying (data/MC) multiplicity distributions, bin by + // bin, so the TProfile accumulates real sum(w)/sum(wy)/sum(wy^2) rather than a precomputed mean. + if (hPVData) { + for (int ybin = 1; ybin <= projData->GetNbinsX(); ybin++) { + double w = projData->GetBinContent(ybin); + if (w > 0) { + hPVData->Fill(percentile_center[i], projData->GetBinCenter(ybin), w); + } + } + } + if (hPVMC) { + for (int ybin = 1; ybin <= projMC->GetNbinsX(); ybin++) { + double w = projMC->GetBinContent(ybin); + if (w > 0) { + hPVMC->Fill(percentile_center[i], projMC->GetBinCenter(ybin), w); + } + } + } + + LOGF(info, "Calibration for %s estimator -> Data centrality bin %g-%g%%\n", estimator.Data(), centralityBins[irev], centralityBins[irev + 1]); + LOGF(info, "Calibration for %s estimator -> MC multiplicity range %g-%g\n", estimator.Data(), projMC->GetBinLowEdge(endBinMc), projMC->GetBinLowEdge(startBinMc)); + LOGF(info, "Calibration for %s estimator -> data = %.4f Vs MC = %.4f (MC/Data = %.4f%%)\n", estimator.Data(), meanMult_Data, meanMult_MC, (meanMult_MC - meanMult_Data) * 100 / meanMult_Data); + LOGF(info, "Calibration for %s estimator -> N entries Data = %g Vs N entries MC = %g\n", estimator.Data(), projData->Integral(), projMC->Integral()); + for (int ibin = 1; ibin <= h1dCalib->GetNbinsX(); ibin++) { + if (ibin <= startBinMc && ibin >= endBinMc) { + h1dCalib->SetBinContent(ibin, percentile_center[i]); + } + } + startBinMc = endBinMc; + } // End loop over centrality bins + } else { + for (int i = 0; i < nCentBins; i++) { + int irev = nCentBins - i; + percentile_center[i] = (centralityBins[irev - 1] + centralityBins[irev]) / 2; + epercentile_center[i] = (centralityBins[irev] - centralityBins[irev - 1]) / 2; + } + int startBinMc = 1; + for (int i = 0; i < nCentBins; i++) { // Loop over centrality bins + // start from the end (from the low multiplicity collisions) + int irev = nCentBins - i; + TH1D* projData = h2dMultVsCent_Data->ProjectionY(Form("projData_%d", i), h2dMultVsCent_Data->GetXaxis()->FindBin(centralityBins[irev - 1] + 1e-5), + h2dMultVsCent_Data->GetXaxis()->FindBin(centralityBins[irev] - 1e-5)); + + double meanMult_Data = projData->GetMean(); + + double meanMult_MC = -1; + double diffMultDataVsMC = 1e+09; + int endBinMc = h1dCalib->GetNbinsX(); + for (int j = startBinMc + 1; j <= h1dCalib->GetNbinsX(); j++) { + // Loop over MC bins + TH1D* projMC = h2dMultRecoVsMultGen_MC->ProjectionY("", startBinMc, j); + int nEntries = projMC->Integral(); + double meanMC = projMC->GetMean(); + double ldiff = std::abs(meanMC - meanMult_Data); + // std::cout << ldiff << std::endl; + + // if less than 100 entries for estimating the mean, do not consider it + if (nEntries < baseOpts.minEntries) + continue; + + // Find the minimum difference and corresponding MC bin + if (ldiff < diffMultDataVsMC) { + diffMultDataVsMC = ldiff; + meanMult_MC = meanMC; + endBinMc = j; + } + } + if (i == nCentBins - 1) { + endBinMc = h2dMultRecoVsMultGen_MC->GetNbinsX(); + } + + TH1D* projMC = h2dMultRecoVsMultGen_MC->ProjectionY(Form("projMC_%d", i), startBinMc, endBinMc); + + // Refill the per-class mean from the underlying (data/MC) multiplicity distributions, bin by + // bin, so the TProfile accumulates real sum(w)/sum(wy)/sum(wy^2) rather than a precomputed mean. + if (hPVData) { + for (int ybin = 1; ybin <= projData->GetNbinsX(); ybin++) { + double w = projData->GetBinContent(ybin); + if (w > 0) { + hPVData->Fill(percentile_center[i], projData->GetBinCenter(ybin), w); + } + } + } + if (hPVMC) { + for (int ybin = 1; ybin <= projMC->GetNbinsX(); ybin++) { + double w = projMC->GetBinContent(ybin); + if (w > 0) { + hPVMC->Fill(percentile_center[i], projMC->GetBinCenter(ybin), w); + } + } + } + + LOGF(info, "Calibration for %s estimator -> Data centrality bin %g-%g%%\n", estimator.Data(), centralityBins[irev - 1], centralityBins[irev]); + LOGF(info, "Calibration for %s estimator -> MC multiplicity range %g-%g\n", estimator.Data(), projMC->GetBinLowEdge(startBinMc), projMC->GetBinLowEdge(endBinMc + 1)); + LOGF(info, "Calibration for %s estimator -> data = %.4f Vs MC = %.4f (MC/Data = %.4f%%)\n", estimator.Data(), meanMult_Data, meanMult_MC, (meanMult_MC - meanMult_Data) * 100 / meanMult_Data); + LOGF(info, "Calibration for %s estimator -> N entries Data = %g Vs N entries MC = %g\n", estimator.Data(), projData->Integral(), projMC->Integral()); + for (int ibin = 1; ibin <= h1dCalib->GetNbinsX(); ibin++) { + if (ibin <= endBinMc && ibin >= startBinMc) { + h1dCalib->SetBinContent(ibin, percentile_center[i]); + } + } + + startBinMc = endBinMc + 1; + } // End loop over centrality bins + } + + LOGF(info, "Calibration for %s estimator -> Done!\n", estimator.Data()); + + return h1dCalib; + }; + return CalibMC(name); + } + + // Loads the calibration object(s) for a single estimator: either the class-averaged TH1D (statistical + // assignment) or, in candidate-by-candidate mode, the raw joint TH2D used to sample P(centrality|genMult). + void loadEstimatorCalibration(int idx, const char* name, TH1D*& h1dOut) + { + if (!baseOpts.mEnabledTables[idx]) { + return; + } + if (baseOpts.assignCentralityPerCandidate) { + // x = reco centrality of the matched MC collision, y = generated multiplicity (|eta| < 0.5) + // filled directly by the calibration-producing task (e.g. centralityQa.cxx); used as-is, no + // mean-matching required since it is already a genuine joint distribution. + h2dCentVsGenMult[idx] = getHist(Form("hGenMultEta05VsCentrality%s", name)); + return; + } + h1dOut = baseOpts.recalibrateCentrality ? extractCentralityCalibration(idx, name, baseOpts.recalibrateMode) : getHist(Form("h1d%s", name)); + } + + template + bool initCCDB(TCCDB& ccdb, TBCs const& bcs) + { + if (!bcs.size()) { + LOGF(warn, "No BC found, skipping this DF."); + return false; // signal to skip this DF + } + + if (mRunNumber == bcs.iteratorAt(0).runNumber()) { + return true; + } + // mark this run as configured + mRunNumber = bcs.iteratorAt(0).runNumber(); + + MCCentralityCalibObjects = ccdb->template getForRun(baseOpts.path, mRunNumber); + if (MCCentralityCalibObjects) { + LOGF(info, "loaded TList with this many objects: %i", MCCentralityCalibObjects->GetEntries()); + } + + loadEstimatorCalibration(kFV0A, "FV0A", h1dFV0A); + loadEstimatorCalibration(kFT0M, "FT0M", h1dFT0M); + loadEstimatorCalibration(kFT0A, "FT0A", h1dFT0A); + loadEstimatorCalibration(kFT0C, "FT0C", h1dFT0C); + loadEstimatorCalibration(kFT0CVariant1, "FT0CVariant1", h1dFT0CVariant1); + loadEstimatorCalibration(kFT0CVariant2, "FT0CVariant2", h1dFT0CVariant2); + loadEstimatorCalibration(kFDDM, "FDDM", h1dFDDM); + loadEstimatorCalibration(kNTPV, "NTPV", h1dNTPV); + loadEstimatorCalibration(kNGlobal, "NGlobal", h1dNGlobal); + if (baseOpts.mEnabledTables[kMFT]) { + // to be added later (multMCMFT not yet available), kept as a dedicated block on purpose + } + LOG(info) << "Fully configured for run: " << mRunNumber; + + return true; + } + + template + void fillHistograms(o2::framework::HistogramRegistry& histos, double percentile, double multiplicity, double genMultEta05) + { + histos.fill(HIST(DirList[tableIndex]) + HIST("/percentile"), percentile); + histos.fill(HIST(DirList[tableIndex]) + HIST("/percentilevsMult"), percentile, multiplicity); + if (baseOpts.assignCentralityPerCandidate) { + // QA of the sampling itself: sampled percentile vs the generated multiplicity it was actually keyed + // on (registered by registerCandidateQAHistos()), so it can be compared to the input calibration. + histos.fill(HIST(DirList[tableIndex]) + HIST("/percentileVsGenMultEta05"), percentile, genMultEta05); + } + } + + // Combines the run number, a per-DF collision sequence number and the estimator index into a single RNG + // seed, so that a given generated collision always draws the same sampled centrality for a given + // estimator, regardless of processing order (note: the sequence number is only unique within one DF, + // it is not a persistent table index). + // This is a simple hash-combine, not a cryptographic hash: the strides just keep the three fields from + // landing on the same seed value for the collision counts typically seen in one run, they don't + // guarantee it. A rare accidental collision only means two unrelated collisions share a random draw, + // which has no systematic effect on the sampled distribution. + ULong64_t computeSamplingSeed(int64_t collisionIndex, int tableIdx) const + { + static constexpr ULong64_t kCollisionStride = 131ull; // > kNestimators, so tableIdx can't alias into the collision term + static constexpr ULong64_t kRunStride = 1000003ull; // prime, well above kCollisionStride * (typical collisions per DF) + return baseOpts.centralitySamplingSeed.value + kRunStride * static_cast(mRunNumber) + + kCollisionStride * static_cast(collisionIndex) + static_cast(tableIdx); + } + + //__________________________________________________ + template + void dataProcess(TCCDB& ccdb, THistoRegistry& histos, TBCs const& bcs, const HasMcMults auto& mcCollisions, TProducts& products) + { + if (nEnabledTables == 0) { + return; // fully suppressed + } + + if (!initCCDB(ccdb, bcs)) + return; + + // Local per-DF sequence number used only to seed the candidate-by-candidate sampling below: not every + // joined mcCollisions type carries an index column (globalIndex()), so we cannot rely on that instead. + int64_t mcCollisionCounter = 0; + for (const auto& mcCollision : mcCollisions) { + const double nFV0A = mcCollision.multMCFV0A(); + const double nFT0A = mcCollision.multMCFT0A(); + const double nFT0C = mcCollision.multMCFT0C(); + const double nFDDA = mcCollision.multMCFDDA(); + const double nFDDC = mcCollision.multMCFDDC(); + const double nGlobal = mcCollision.multMCNParticlesEta08(); + const double nGenMultEta05 = mcCollision.multMCNParticlesEta05(); + // const double nMFT = mcCollision.multMCMFT(); // to be added later + const double nFT0M = nFT0A + nFT0C; + const double nFDDM = nFDDA + nFDDC; + + auto populateTable = [&](auto& table, TH1D* h1dMultCalib, TH2D* h2dCentCalib, double multiplicity, auto tableIndex) { + double percentile = 105.0f; + if (baseOpts.mEnabledTables[tableIndex]) { + if (baseOpts.assignCentralityPerCandidate && h2dCentCalib) { + // Sample P(centrality | genMult) for this generated collision: slice h2dCentCalib at the + // y-bin (generated mult |eta|<0.5) matching this collision and draw from that 1-D distribution. + fRandomSampler.SetSeed(computeSamplingSeed(mcCollisionCounter, tableIndex.value)); + int yBin = h2dCentCalib->GetYaxis()->FindBin(nGenMultEta05); + std::unique_ptr pdf{h2dCentCalib->ProjectionX(Form("pdfCent_%d", tableIndex.value), yBin, yBin)}; + if (pdf->Integral() > 0) { + percentile = pdf->GetRandom(&fRandomSampler); + } + fillHistograms(histos, percentile, multiplicity, nGenMultEta05); + } else if (h1dMultCalib) { + int bin = h1dMultCalib->FindBin(multiplicity); + percentile = h1dMultCalib->GetBinContent(bin); + fillHistograms(histos, percentile, multiplicity, nGenMultEta05); + } + table(percentile); + } + return percentile; + }; + + populateTable(products.centFV0A, h1dFV0A, h2dCentVsGenMult[kFV0A], nFV0A, std::integral_constant{}); + populateTable(products.centFT0M, h1dFT0M, h2dCentVsGenMult[kFT0M], nFT0M, std::integral_constant{}); + populateTable(products.centFT0A, h1dFT0A, h2dCentVsGenMult[kFT0A], nFT0A, std::integral_constant{}); + populateTable(products.centFT0C, h1dFT0C, h2dCentVsGenMult[kFT0C], nFT0C, std::integral_constant{}); + populateTable(products.centFT0CVariant1, h1dFT0CVariant1, h2dCentVsGenMult[kFT0CVariant1], nFT0C, std::integral_constant{}); + populateTable(products.centFT0CVariant2, h1dFT0CVariant2, h2dCentVsGenMult[kFT0CVariant2], nFT0C, std::integral_constant{}); + populateTable(products.centFDDM, h1dFDDM, h2dCentVsGenMult[kFDDM], nFDDM, std::integral_constant{}); + populateTable(products.centNTPV, h1dNTPV, h2dCentVsGenMult[kNTPV], nGlobal, std::integral_constant{}); + populateTable(products.centNGlobal, h1dNGlobal, h2dCentVsGenMult[kNGlobal], nGlobal, std::integral_constant{}); + // populateTable(products.centMFT, h1dMFT, h2dCentVsGenMult[kMFT], nMFT, std::integral_constant{}); // to be added later + + mcCollisionCounter++; + } + } +}; // end mcCentralityModule + +} // namespace mccentrality +} // namespace pwglf +} // namespace o2 + +#endif // PWGLF_UTILS_MCCENTRALITYMODULE_H_ diff --git a/PWGLF/Utils/nucleiUtils.h b/PWGLF/Utils/nucleiUtils.h index 7ecf6a3207f..4d06854cefb 100644 --- a/PWGLF/Utils/nucleiUtils.h +++ b/PWGLF/Utils/nucleiUtils.h @@ -330,7 +330,7 @@ constexpr int EvSelDefault[evSel::kNevSels][1]{ {0}}; template -bool eventSelection(const Tcollision& collision, o2::framework::HistogramRegistry& registry, o2::framework::LabeledArray eventSelections, const float cutVertex, uint32_t& selectionFlag) +bool eventSelection(const Tcollision& collision, o2::framework::HistogramRegistry& registry, const o2::framework::LabeledArray& eventSelections, const float cutVertex, uint32_t& selectionFlag) { selectionFlag = 0; bool isSelected = true; @@ -391,7 +391,7 @@ bool eventSelection(const Tcollision& collision, o2::framework::HistogramRegistr * then fills 1. if the centrality filling fails (return = -1.) */ template -float getCentrality(Tcollision const& collision, const int centralityEstimator, std::shared_ptr hFailCentrality = nullptr) +float getCentrality(Tcollision const& collision, const int centralityEstimator, const std::shared_ptr& hFailCentrality = nullptr) { if (hFailCentrality) { hFailCentrality->Fill(0.); diff --git a/PWGLF/Utils/pidTOFGeneric.h b/PWGLF/Utils/pidTOFGeneric.h index 18b3a937565..8625db1f4e8 100644 --- a/PWGLF/Utils/pidTOFGeneric.h +++ b/PWGLF/Utils/pidTOFGeneric.h @@ -68,14 +68,14 @@ struct TOFCalibConfig { } template - void getCfg(o2::framework::InitContext& initContext, const std::string name, VType& v, const std::string task) + void getCfg(o2::framework::InitContext& initContext, const std::string& name, VType& v, const std::string& task) { if (!o2::common::core::getTaskOptionValue(initContext, task, name, v, false)) { LOG(fatal) << "Could not get " << name << " from " << task << " task"; } } - void inheritFromBaseTask(o2::framework::InitContext& initContext, const std::string task = "tof-signal") + void inheritFromBaseTask(o2::framework::InitContext& initContext, const std::string& task = "tof-signal") { mInitMode = 2; getCfg(initContext, "ccdb-url", mUrl, task); diff --git a/PWGLF/Utils/rsnOutput.h b/PWGLF/Utils/rsnOutput.h index 214d6aa8118..5dfb5e30d09 100644 --- a/PWGLF/Utils/rsnOutput.h +++ b/PWGLF/Utils/rsnOutput.h @@ -28,9 +28,7 @@ #include #include -namespace o2::analysis -{ -namespace rsn +namespace o2::analysis::rsn { enum class EventType { zvertex, @@ -47,14 +45,21 @@ enum class TrackType { enum class PairType { unlikepm, unlikemp, + unlikepmInelgt0, + unlikempInelgt0, likepp, likemm, - unliketrue, + unliketruerec, + unliketruerecInelgt0, + unliketruegen, + unliketruegenInelgt0, unlikegen, - unlikegenold, + unlikegenInelgt0, mixingpm, mixingmp, - rotationpm, + rotationz, + rotation, + rotationlike, all }; @@ -80,13 +85,14 @@ enum class MixingType { none }; -MixingType mixingTypeName(std::string name) +MixingType mixingTypeName(const std::string& name) { - if (name == "ce") + if (name == "ce") { return MixingType::ce; - else if (name == "mu") + } + if (name == "mu") { return MixingType::mu; - + } return MixingType::none; } @@ -94,14 +100,15 @@ enum class SystematicsAxisType { ncl, unknown }; + namespace pair_axis { -std::vector names{"im", "pt", "mu", "ce", "ns1", "ns2", "eta", "y", "vz", "mum", "cem", "vzm"}; +const std::vector names{"im", "pt", "mu", "ce", "ns1", "ns2", "eta", "y", "vz", "mum", "cem", "vzm"}; } namespace systematic_axis { -std::vector names{"ncl"}; +const std::vector names{"ncl"}; } class Output @@ -109,22 +116,23 @@ class Output public: virtual ~Output() = default; - virtual void init(std::vector const& sparseAxes, std::vector const& allAxes, std::vector const& sysAxes, std::vector const& allAxes_sys, bool /*produceTrue*/ = false, MixingType /*eventMixing*/ = MixingType::none, bool /*produceLikesign*/ = false, bool /*produceRotational*/ = false, o2::framework::HistogramRegistry* registry = nullptr) + virtual void init(std::vector const& sparseAxes, std::vector const& allAxes, std::vector const& sysAxes, std::vector const& allAxes_sys, bool /*produceTrue*/, MixingType /*eventMixing*/, bool /*produceLikesign*/, bool /*produceRotational*/, bool /*produceInelgt0*/, o2::framework::HistogramRegistry* registry) { mHistogramRegistry = registry; - if (mHistogramRegistry == nullptr) + if (mHistogramRegistry == nullptr) { mHistogramRegistry = new o2::framework::HistogramRegistry("registry"); + } // check if all axes are added in correct order for (int i = 0; i < static_cast(PairAxisType::unknown); i++) { auto aname = *std::move(allAxes[i].name); LOGF(debug, "Check axis '%s' %d", aname.c_str(), i); - if (aname.compare(pair_axis::names[static_cast(i)])) { + if (aname != pair_axis::names[i]) { LOGF(fatal, "rsn::Output::Error: Order in allAxes is not correct !!! Expected axis '%s' and has '%s'.", aname.c_str(), pair_axis::names[static_cast(i)]); } } - PairAxisType currentType; + PairAxisType currentType = PairAxisType::unknown; for (const auto& c : sparseAxes) { currentType = type(c); if (currentType >= PairAxisType::unknown) { @@ -136,8 +144,8 @@ class Output mCurrentAxisTypes.push_back(currentType); } - if (mFillPoint != nullptr) - delete mFillPoint; + delete mFillPoint; + mFillPoint = new double[mCurrentAxisTypes.size()]; LOGF(info, "Number of axis added: %d", mCurrentAxes.size()); @@ -147,12 +155,12 @@ class Output for (int i = 0; i < static_cast(SystematicsAxisType::unknown); i++) { auto aname = *std::move(allAxes_sys[i].name); LOGF(debug, "Check axis '%s' %d", aname.c_str(), i); - if (aname.compare(systematic_axis::names[static_cast(i)])) { + if (aname != systematic_axis::names[i]) { LOGF(fatal, "rsn::Output::Error: Order in allAxes_sys is not correct !!! Expected axis '%s' and has '%s'.", aname.c_str(), systematic_axis::names[static_cast(i)]); } } - SystematicsAxisType currentTypeSys; + SystematicsAxisType currentTypeSys = SystematicsAxisType::unknown; for (const auto& c : sysAxes) { currentTypeSys = typeSys(c); if (currentTypeSys >= SystematicsAxisType::unknown) { @@ -164,8 +172,8 @@ class Output mCurrentAxisTypesSys.push_back(currentTypeSys); } - if (mFillPointSys != nullptr) - delete mFillPointSys; + delete mFillPointSys; + mFillPointSys = new double[mCurrentAxisTypesSys.size()]; LOGF(info, "Number of systematic axis added: %d", mCurrentAxesSys.size()); @@ -173,7 +181,7 @@ class Output } template - void fillSparse(const T& h, double* point) + void fillSparse(const T& h, const double* point) { int i = 0; for (const auto& at : mCurrentAxisTypes) { @@ -183,7 +191,7 @@ class Output } template - void fillSparseSys(const T& h, double* point) + void fillSparseSys(const T& h, const double* point) { int i = 0; for (const auto& at : mCurrentAxisTypesSys) { @@ -207,17 +215,24 @@ class Output virtual void fillUnlikepm(double* point) = 0; virtual void fillUnlikemp(double* point) = 0; + virtual void fillUnlikepmInelgt0(double* point) = 0; + virtual void fillUnlikempInelgt0(double* point) = 0; virtual void fillLikepp(double* point) = 0; virtual void fillLikemm(double* point) = 0; - virtual void fillUnliketrue(double* point) = 0; - virtual void fillUnlikegen(double* point) = 0; - virtual void fillUnlikegenOld(double* point) = 0; + virtual void fillUnlikeTrueRec(double* point) = 0; + virtual void fillUnlikeTrueGen(double* point) = 0; + virtual void fillUnlikeGen(double* point) = 0; + virtual void fillUnlikeTrueRecInelgt0(double* point) = 0; + virtual void fillUnlikeTrueGenInelgt0(double* point) = 0; + virtual void fillUnlikeGenInelgt0(double* point) = 0; virtual void fillMixingpm(double* point) = 0; virtual void fillMixingmp(double* point) = 0; - virtual void fillRotationpm(double* point) = 0; + virtual void fillRotationZ(double* point) = 0; + virtual void fillRotation(double* point) = 0; + virtual void fillRotationLike(double* point) = 0; virtual void fillSystematics(double* point) = 0; - PairAxisType type(std::string name) + PairAxisType type(const std::string& name) { auto it = std::find(pair_axis::names.begin(), pair_axis::names.end(), name); if (it == pair_axis::names.end()) { @@ -226,7 +241,7 @@ class Output return static_cast(std::distance(pair_axis::names.begin(), it)); } - SystematicsAxisType typeSys(std::string name) + SystematicsAxisType typeSys(const std::string& name) { auto it = std::find(systematic_axis::names.begin(), systematic_axis::names.end(), name); if (it == systematic_axis::names.end()) { @@ -235,22 +250,22 @@ class Output return static_cast(std::distance(systematic_axis::names.begin(), it)); } - std::string name(PairAxisType type) + std::string name(PairAxisType axisType) { - return pair_axis::names[(static_cast(type))]; + return pair_axis::names[(static_cast(axisType))]; } - std::string nameSys(SystematicsAxisType type) + std::string nameSys(SystematicsAxisType axisType) { - return systematic_axis::names[(static_cast(type))]; + return systematic_axis::names[(static_cast(axisType))]; } - o2::framework::AxisSpec axis(std::vector const& allAxes, PairAxisType type) + o2::framework::AxisSpec axis(std::vector const& allAxes, PairAxisType axisType) { - const o2::framework::AxisSpec unknownAxis = {1, 0., 1., "unknown axis", "unknown"}; - if (type == PairAxisType::unknown) - return unknownAxis; - return allAxes[static_cast(type)]; + if (axisType == PairAxisType::unknown) { + return {1, 0., 1., "unknown axis", "unknown"}; + } + return allAxes[static_cast(axisType)]; } protected: @@ -268,32 +283,41 @@ class Output class OutputSparse : public Output { public: - virtual void init(std::vector const& sparseAxes, std::vector const& allAxes, std::vector const& sysAxes, std::vector const& allAxes_sys, bool produceTrue = false, MixingType eventMixing = MixingType::none, bool produceLikesign = false, bool produceRotational = false, o2::framework::HistogramRegistry* registry = nullptr) + void init(std::vector const& sparseAxes, std::vector const& allAxes, std::vector const& sysAxes, std::vector const& allAxes_sys, bool produceTrue, MixingType eventMixing, bool produceLikesign, bool produceRotational, bool produceInelgt0, o2::framework::HistogramRegistry* registry) override { - Output::init(sparseAxes, allAxes, sysAxes, allAxes_sys, produceTrue, eventMixing, produceLikesign, produceRotational, registry); + Output::init(sparseAxes, allAxes, sysAxes, allAxes_sys, produceTrue, eventMixing, produceLikesign, produceRotational, produceInelgt0, registry); mHistogramRegistry->add("unlikepm", "Unlike pm", *mPairHisto); + mHistogramRegistry->add("unlikemp", "Unlike mp", *mPairHisto); + if (produceInelgt0) { + mHistogramRegistry->add("unlikepmInelgt0", "Unlike pm (INEL>0)", *mPairHisto); + mHistogramRegistry->add("unlikempInelgt0", "Unlike mp (INEL>0)", *mPairHisto); + } if (produceLikesign) { mHistogramRegistry->add("likepp", "Like PP", *mPairHisto); mHistogramRegistry->add("likemm", "Like MM", *mPairHisto); } if (produceTrue) { - mHistogramRegistry->add("unliketrue", "Unlike True", *mPairHisto); + mHistogramRegistry->add("unliketruerec", "Unlike True (Rec)", *mPairHisto); + mHistogramRegistry->add("unliketruegen", "Unlike True (Gen)", *mPairHisto); + mHistogramRegistry->add("unliketruerecInelgt0", "Unlike True (Rec) (INEL>0)", *mPairHisto); + mHistogramRegistry->add("unliketruegenInelgt0", "Unlike True (Gen) (INEL>0)", *mPairHisto); mHistogramRegistry->add("unlikegen", "Unlike Gen", *mPairHisto); - mHistogramRegistry->add("unlikegenold", "Unlike Gen Old", *mPairHisto); + mHistogramRegistry->add("unlikegenInelgt0", "Unlike Gen (INEL>0)", *mPairHisto); } if (eventMixing != MixingType::none) { mHistogramRegistry->add("mixingpm", "Event Mixing pm", *mPairHisto); mHistogramRegistry->add("mixingmp", "Event Mixing mp", *mPairHisto); } if (produceRotational) { - mHistogramRegistry->add("rotationpm", "Rotational pm", *mPairHisto); + mHistogramRegistry->add("rotationz", "Rotation around z axis", *mPairHisto); + mHistogramRegistry->add("rotation", "Momentum-axis rotation, unlike-sign", *mPairHisto); + mHistogramRegistry->add("rotationlike", "Momentum-axis rotation, like-sign", *mPairHisto); } mHistogramRegistry->add("Mapping/systematics", "Systematics mapping", *mPairHistoSys); } - virtual void - fill(EventType t, double* point) + void fill(EventType t, double* point) override { switch (t) { case EventType::zvertex: @@ -304,7 +328,7 @@ class OutputSparse : public Output } } - virtual void fill(PairType t, double* point) + void fill(PairType t, double* point) override { switch (t) { case PairType::unlikepm: @@ -319,14 +343,29 @@ class OutputSparse : public Output case PairType::likemm: fillLikemm(point); break; - case PairType::unliketrue: - fillUnliketrue(point); + case PairType::unliketruerec: + fillUnlikeTrueRec(point); break; case PairType::unlikegen: - fillUnlikegen(point); + fillUnlikeGen(point); + break; + case PairType::unliketruegen: + fillUnlikeTrueGen(point); + break; + case PairType::unlikepmInelgt0: + fillUnlikepmInelgt0(point); break; - case PairType::unlikegenold: - fillUnlikegenOld(point); + case PairType::unlikempInelgt0: + fillUnlikempInelgt0(point); + break; + case PairType::unliketruerecInelgt0: + fillUnlikeTrueRecInelgt0(point); + break; + case PairType::unliketruegenInelgt0: + fillUnlikeTrueGenInelgt0(point); + break; + case PairType::unlikegenInelgt0: + fillUnlikeGenInelgt0(point); break; case PairType::mixingpm: fillMixingpm(point); @@ -334,60 +373,94 @@ class OutputSparse : public Output case PairType::mixingmp: fillMixingmp(point); break; - case PairType::rotationpm: - fillRotationpm(point); + case PairType::rotationz: + fillRotationZ(point); + break; + case PairType::rotation: + fillRotation(point); + break; + case PairType::rotationlike: + fillRotationLike(point); break; default: break; } } - virtual void fillUnlikepm(double* point) + void fillUnlikepm(double* point) override { fillSparse(HIST("unlikepm"), point); } - virtual void fillUnlikemp(double* point) + void fillUnlikemp(double* point) override { fillSparse(HIST("unlikemp"), point); } - virtual void fillLikepp(double* point) + void fillLikepp(double* point) override { fillSparse(HIST("likepp"), point); } - virtual void fillLikemm(double* point) + void fillLikemm(double* point) override { fillSparse(HIST("likemm"), point); } - virtual void fillUnliketrue(double* point) + void fillUnlikeTrueRec(double* point) override + { + fillSparse(HIST("unliketruerec"), point); + } + void fillUnlikeTrueGen(double* point) override { - fillSparse(HIST("unliketrue"), point); + fillSparse(HIST("unliketruegen"), point); } - virtual void fillUnlikegen(double* point) + void fillUnlikeGen(double* point) override { fillSparse(HIST("unlikegen"), point); } - virtual void fillUnlikegenOld(double* point) + void fillUnlikepmInelgt0(double* point) override + { + fillSparse(HIST("unlikepmInelgt0"), point); + } + void fillUnlikempInelgt0(double* point) override + { + fillSparse(HIST("unlikempInelgt0"), point); + } + void fillUnlikeTrueRecInelgt0(double* point) override + { + fillSparse(HIST("unliketruerecInelgt0"), point); + } + void fillUnlikeTrueGenInelgt0(double* point) override + { + fillSparse(HIST("unliketruegenInelgt0"), point); + } + void fillUnlikeGenInelgt0(double* point) override { - fillSparse(HIST("unlikegenold"), point); + fillSparse(HIST("unlikegenInelgt0"), point); } - virtual void fillMixingpm(double* point) + + void fillMixingpm(double* point) override { fillSparse(HIST("mixingpm"), point); } - virtual void fillMixingmp(double* point) + void fillMixingmp(double* point) override { fillSparse(HIST("mixingmp"), point); } - virtual void fillRotationpm(double* point) + void fillRotationZ(double* point) override + { + fillSparse(HIST("rotationz"), point); + } + void fillRotation(double* point) override + { + fillSparse(HIST("rotation"), point); + } + void fillRotationLike(double* point) override { - fillSparse(HIST("rotationpm"), point); + fillSparse(HIST("rotationlike"), point); } - virtual void fillSystematics(double* point) + void fillSystematics(double* point) override { fillSparse(HIST("Mapping/systematics"), point); } }; -} // namespace rsn -} // namespace o2::analysis +} // namespace o2::analysis::rsn #endif // PWGLF_UTILS_RSNOUTPUT_H_ diff --git a/PWGLF/Utils/strangenessBuilderHelper.h b/PWGLF/Utils/strangenessBuilderHelper.h index c78f6471de9..6d5b525dcd4 100644 --- a/PWGLF/Utils/strangenessBuilderHelper.h +++ b/PWGLF/Utils/strangenessBuilderHelper.h @@ -253,6 +253,7 @@ class strangenessBuilderHelper fitter.setMaxChi2(1e9); fitter.setUseAbsDCA(true); fitter.setWeightedFinalPCA(false); + fitter.setOldMode(true); // enable old convariance matrix calculation until this has been fully tested v0selections.minCrossedRows = -1; v0selections.dcanegtopv = -1.0f; diff --git a/PWGLF/Utils/strangenessBuilderModule.h b/PWGLF/Utils/strangenessBuilderModule.h index 563b75e6d95..8b343925231 100644 --- a/PWGLF/Utils/strangenessBuilderModule.h +++ b/PWGLF/Utils/strangenessBuilderModule.h @@ -49,6 +49,7 @@ #include #include +#include #include #include #include @@ -334,6 +335,9 @@ struct coreConfigurables : o2::framework::ConfigurableGroup { // test the possibility of refitting with material corrections (DCA Fitter option) o2::framework::Configurable refitWithMaterialCorrection{"refitWithMaterialCorrection", false, "do refit after material corrections were applied"}; + + // enable old convariance matrix calculation until this has been fully tested + o2::framework::Configurable useOldModeDCAFitter{"useOldModeDCAFitter", true, "Use old mode for DCA fitter?"}; }; // strangenessBuilder: V0 building options @@ -824,6 +828,9 @@ class BuilderModule // Set option to refit with material corrections straHelper.fitter.setRefitWithMatCorr(baseOpts.refitWithMaterialCorrection.value); + // set option to enabled the old mode + straHelper.fitter.setOldMode(baseOpts.useOldModeDCAFitter.value); + // Initialise the RCTFlagsChecker if (eventSelectOpts.cfgApplyRCTrequirement) { rctFlagsChecker.init(eventSelectOpts.cfgRCTLabel.value, eventSelectOpts.cfgCheckZDC, eventSelectOpts.cfgTreatLimitedAcceptanceAsBad); @@ -844,6 +851,30 @@ class BuilderModule return idx; } + // Feed the V-drift manager from the aod::TpcCalibCCDBObjects column when the BC table + // carries it, else fall back to a CCDB query. Lets migrated and un-migrated tasks share + // this module unchanged. + template + void updateVDrift(TCollision const& collision) + { + auto const& bc = collision.template bc_as(); + if constexpr (requires { bc.vdriftTgl(); }) { + mVDriftMgr.update(bc.vdriftTgl()); + } else { + mVDriftMgr.update(bc.timestamp()); + } + } + + // Overload for tasks whose BC table carries the V-drift CCDB column: nothing in here + // needs a CCDB manager any more, so they need not own one. + template + bool initCCDB(TBCs const& bcs, TCollisions const& collisions) + { + static_assert(requires(typename TBCs::iterator bc) { bc.vdriftTgl(); }, "initCCDB without a CCDB manager needs a BC table joined with aod::TpcCalibCCDBObjects"); + std::nullptr_t noCCDB{}; + return initCCDB(noCCDB, bcs, collisions); + } + template bool initCCDB(TCCDB& ccdb, TBCs const& bcs, TCollisions const& collisions) { @@ -872,8 +903,12 @@ class BuilderModule if (v0BuilderOpts.generatePhotonCandidates.value && v0BuilderOpts.moveTPCOnlyTracks.value) { // initialize only if needed, avoid unnecessary CCDB calls - mVDriftMgr.init(&ccdb->instance()); - mVDriftMgr.update(timestamp); + if constexpr (requires { bc.vdriftTgl(); }) { + mVDriftMgr.update(bc.vdriftTgl()); + } else { + mVDriftMgr.init(&ccdb->instance()); + mVDriftMgr.update(timestamp); + } } return true; @@ -1021,7 +1056,7 @@ class BuilderModule // handle TPC-only tracks properly (photon conversions) if (v0BuilderOpts.moveTPCOnlyTracks) { if (collision.has_bc()) { - mVDriftMgr.update(collision.template bc_as().timestamp()); + updateVDrift(collision); } if (isPosTPCOnly) { // Nota bene: positive is TPC-only -> this entire V0 merits treatment as photon candidate @@ -1498,7 +1533,7 @@ class BuilderModule continue; } if (v0BuilderOpts.generatePhotonCandidates && v0BuilderOpts.moveTPCOnlyTracks && collision.has_bc()) { - mVDriftMgr.update(collision.template bc_as().timestamp()); + updateVDrift(collision); } } auto const& posTrack = tracks.rawIteratorAt(v0.posTrackId); @@ -1892,11 +1927,31 @@ class BuilderModule if (mcParticle.has_daughters()) { auto const& daughters = mcParticle.template daughters_as(); + // For the K0s (main channel of interest): + // K0s --> pi+ pi- (69.20%) + // K0s --> pi0 pi0 (30.69%) + // For the Lambda (main channel of interest): + // Lambda --> p pi- (64.1%) + // Lambda --> n pi0 (35.9%) for (const auto& dau : daughters) { if (dau.getProcess() != TMCProcess::kPDecay) continue; + // proton, neutron, pi+, e+, pi0 if (dau.pdgCode() > 0) { + // special treatment of Lambda --> neutron pi0 (both PDG codes > 0) + // and K0s --> pi0 pi0 (both PDG codes > 0) + // take neutron as positive daughter and pi0 as negative daughter + // if the first daughter was the pi0 (already assigned as positive), + // then transfer the information to the negative and fill the information + // of the positive daughter with those of the neutrons + if (thisInfo.pdgCodePositive > -1 && thisInfo.pdgCodePositive == PDG_t::kPi0) { + thisInfo.pdgCodeNegative = thisInfo.pdgCodePositive; + thisInfo.processNegative = thisInfo.processPositive; + thisInfo.negP[0] = thisInfo.posP[0]; + thisInfo.negP[1] = thisInfo.posP[1]; + thisInfo.negP[2] = thisInfo.posP[2]; + } thisInfo.pdgCodePositive = dau.pdgCode(); thisInfo.processPositive = dau.getProcess(); thisInfo.posP[0] = dau.px(); @@ -1906,6 +1961,7 @@ class BuilderModule thisInfo.xyz[1] = dau.vy(); thisInfo.xyz[2] = dau.vz(); } + // antiproton, antineutron, pi-, e- (pi0 cannot have negative PDG code) if (dau.pdgCode() < 0) { thisInfo.pdgCodeNegative = dau.pdgCode(); thisInfo.processNegative = dau.getProcess(); @@ -2442,7 +2498,16 @@ class BuilderModule if (dau.getProcess() != TMCProcess::kPDecay) // check whether the daughter comes from a decay continue; - if (std::abs(dau.pdgCode()) == PDG_t::kPiPlus || std::abs(dau.pdgCode()) == PDG_t::kKPlus) { + // Dominant decay channels for charged Xi and Omega are: + // Xi- --> Lambda pi- ; Xi+ --> Lambda pi+ (99.887%) --> recover information of all daughters + // Omega- --> Lambda K- ; Omega+ --> Lambda K+ (67.7%) --> recover information of all daughters + // Omega- --> Xi0 pi- ; Omega+ --> Xi0 pi+ (24.3%) --> recover information of only Xi0 and pions + // Omega- --> Xi- pi0 ; Omega+ --> Xi+ pi0 (8.55%) --> recover information of only Xi and pions + // + // For the Lambda (main channel of interest): + // Lambda --> p pi- (64.1%) + // Lambda --> n pi0 (35.9%) + if (std::abs(dau.pdgCode()) == PDG_t::kPiPlus || std::abs(dau.pdgCode()) == PDG_t::kPi0 || std::abs(dau.pdgCode()) == PDG_t::kKPlus) { thisCascInfo.pdgCodeBachelor = dau.pdgCode(); thisCascInfo.bachP[0] = dau.px(); thisCascInfo.bachP[1] = dau.py(); @@ -2452,6 +2517,7 @@ class BuilderModule thisCascInfo.xyz[2] = dau.vz(); thisCascInfo.mcParticleBachelor = dau.globalIndex(); } + // Treatment of Lambda --> p pi ; Lambda --> n pi if (std::abs(dau.pdgCode()) == PDG_t::kLambda0) { thisCascInfo.pdgCodeV0 = dau.pdgCode(); @@ -2459,7 +2525,21 @@ class BuilderModule if (v0Dau.getProcess() != TMCProcess::kPDecay) continue; + // proton, neutron, pi+, pi0 if (v0Dau.pdgCode() > 0) { + // special treatment of Lambda --> neutron pi0 (both PDG codes > 0) + // take neutron as positive daughter and pi0 as negative daughter + // if the first daughter was the pi0 (already assigned as positive), + // then transfer the information to the negative and fill the information + // of the positive daughter with those of the neutrons + if (thisCascInfo.pdgCodePositive > -1 && thisCascInfo.pdgCodePositive == PDG_t::kPi0) { + thisCascInfo.pdgCodeNegative = thisCascInfo.pdgCodePositive; + thisCascInfo.processNegative = thisCascInfo.processPositive; + thisCascInfo.negP[0] = thisCascInfo.posP[0]; + thisCascInfo.negP[1] = thisCascInfo.posP[1]; + thisCascInfo.negP[2] = thisCascInfo.posP[2]; + thisCascInfo.mcParticleNegative = thisCascInfo.mcParticlePositive; + } thisCascInfo.pdgCodePositive = v0Dau.pdgCode(); thisCascInfo.processPositive = v0Dau.getProcess(); thisCascInfo.posP[0] = v0Dau.px(); @@ -2470,6 +2550,7 @@ class BuilderModule thisCascInfo.lxyz[2] = v0Dau.vz(); thisCascInfo.mcParticlePositive = v0Dau.globalIndex(); } + // antiproton, antineutron, pi- (pi0 cannot have negative PDG code) if (v0Dau.pdgCode() < 0) { thisCascInfo.pdgCodeNegative = v0Dau.pdgCode(); thisCascInfo.processNegative = v0Dau.getProcess(); @@ -2480,6 +2561,37 @@ class BuilderModule } } } + // Special treatment of Xi0 and Xi from Omega --> Xi0 pi ; Omega --> Xi pi0 + if (std::abs(dau.pdgCode()) == PDG_t::kXiMinus || std::abs(dau.pdgCode()) == o2::constants::physics::Pdg::kXi0) { + thisCascInfo.pdgCodeV0 = dau.pdgCode(); + + for (const auto& xiDau : dau.template daughters_as()) { + if (xiDau.getProcess() != TMCProcess::kPDecay) + continue; + + // always put the Lambda in the positive + if (std::abs(xiDau.pdgCode()) == PDG_t::kLambda0) { + thisCascInfo.pdgCodePositive = xiDau.pdgCode(); + thisCascInfo.processPositive = xiDau.getProcess(); + thisCascInfo.posP[0] = xiDau.px(); + thisCascInfo.posP[1] = xiDau.py(); + thisCascInfo.posP[2] = xiDau.pz(); + thisCascInfo.lxyz[0] = xiDau.vx(); + thisCascInfo.lxyz[1] = xiDau.vy(); + thisCascInfo.lxyz[2] = xiDau.vz(); + thisCascInfo.mcParticlePositive = xiDau.globalIndex(); + } + // always put the bachelor or the photon or the pi0 in the negative + if (std::abs(xiDau.pdgCode()) == PDG_t::kPiPlus || std::abs(xiDau.pdgCode()) == PDG_t::kPi0 || std::abs(xiDau.pdgCode()) == PDG_t::kGamma) { + thisCascInfo.pdgCodeNegative = xiDau.pdgCode(); + thisCascInfo.processNegative = xiDau.getProcess(); + thisCascInfo.negP[0] = xiDau.px(); + thisCascInfo.negP[1] = xiDau.py(); + thisCascInfo.negP[2] = xiDau.pz(); + thisCascInfo.mcParticleNegative = xiDau.globalIndex(); + } + } + } } } @@ -2757,6 +2869,16 @@ class BuilderModule return returnValue; } + //__________________________________________________ + // Overload for tasks sourcing every conditions object from CCDB columns; see initCCDB above. + template + void dataProcess(THistoRegistry& histos, TCollisions const& collisions, TMCCollisions const& mccollisions, TV0s const& v0s, TCascades const& cascades, TTrackedCascades const& trackedCascades, TTracks const& tracks, TBCs const& bcs, TMCParticles const& mcParticles, TProducts& products) + { + static_assert(requires(typename TBCs::iterator bc) { bc.vdriftTgl(); }, "dataProcess without a CCDB manager needs a BC table joined with aod::TpcCalibCCDBObjects"); + std::nullptr_t noCCDB{}; + dataProcess(noCCDB, histos, collisions, mccollisions, v0s, cascades, trackedCascades, tracks, bcs, mcParticles, products); + } + //__________________________________________________ template void dataProcess(TCCDB& ccdb, THistoRegistry& histos, TCollisions const& collisions, TMCCollisions const& mccollisions, TV0s const& v0s, TCascades const& cascades, TTrackedCascades const& trackedCascades, TTracks const& tracks, TBCs const& bcs, TMCParticles const& mcParticles, TProducts& products) diff --git a/PWGMM/Mult/Tasks/mftReassociationValidation.cxx b/PWGMM/Mult/Tasks/mftReassociationValidation.cxx index 9d478879792..59b9a20e76b 100644 --- a/PWGMM/Mult/Tasks/mftReassociationValidation.cxx +++ b/PWGMM/Mult/Tasks/mftReassociationValidation.cxx @@ -864,7 +864,7 @@ struct MftReassociationValidation { // ========================= template - float getMultiplicityEstimator(TCollision collision) + float getMultiplicityEstimator(const TCollision& collision) { switch (configCollision.multiplicityEstimator) { case MultiplicityEstimators::MultNTracksPV: @@ -896,7 +896,7 @@ struct MftReassociationValidation { } template - bool isTrueCollisionAmongCompatibleCollisions(TTrack track) + bool isTrueCollisionAmongCompatibleCollisions(const TTrack& track) { auto const& compatibleIds = track.compatibleCollIds(); diff --git a/PWGMM/UE/Tasks/flattenicityTask.cxx b/PWGMM/UE/Tasks/flattenicityTask.cxx index f279984cb9f..ec430c12479 100644 --- a/PWGMM/UE/Tasks/flattenicityTask.cxx +++ b/PWGMM/UE/Tasks/flattenicityTask.cxx @@ -10,11 +10,12 @@ // or submit itself to any jurisdiction. /// \file flattenicityTask.cxx -/// \brief Flattenicity analysis task for UE studies +/// \brief Run-1 calibration task for FT0 flattenicity (fine-binned histograms for percentile extraction) /// \author Eisha Rani -/// \since August 2026 +/// \since September 2026 -#include "Common/DataModel/Centrality.h" +#include "Common/Core/RecoDecay.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/TrackSelectionTables.h" #include @@ -23,400 +24,277 @@ #include #include #include +#include #include -#include - #include #include #include #include -#include -#include -#include using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; using namespace o2::soa; -using namespace o2::constants::physics; -using FullTracks = soa::Join; -using CollisionsWithCent = soa::Join; -using CollisionsWithCentAndMcLabel = soa::Join; +using FullTracks = + soa::Join; + +using CollisionsWithSelection = + soa::Join; struct FlattenicityTask { - // ============================================ - // FT0 Constants - // ============================================ - static constexpr int NPhiSectors = 8; - static constexpr int NEtaA = 12; - static constexpr int NEtaC = 14; - static constexpr int NchA = 96; - static constexpr int NchC = 112; - static constexpr int NCell = NchA + NchC; // 208 + // NOLINTNEXTLINE(misc-include-cleaner) - Service<> is provided by Framework/AnalysisTask.h; there is no separate standalone header for it in this O2 version. + Service pdg{}; + + // ======================================================================== + // FT0 geometry + // ======================================================================== + + static constexpr int NPhiSectors = 8; + static constexpr int NSectorsA = 24; + static constexpr int NSectorsC = 28; + static constexpr int NSectorsCombined = NSectorsA + NSectorsC; // 52 + static constexpr int ChannelsPerSector = 4; + static constexpr int NchA = NSectorsA * ChannelsPerSector; // 96 + static constexpr int NchC = NSectorsC * ChannelsPerSector; // 112 + static constexpr int NCell = NchA + NchC; // 208 + static constexpr int NEtaA = NchA / NPhiSectors; // 12 + static constexpr int NEtaC = NchC / NPhiSectors; // 14 static constexpr float FT0AEtaMin = 3.5; static constexpr float FT0AEtaMax = 4.9; static constexpr float FT0CEtaMin = -3.3; static constexpr float FT0CEtaMax = -2.1; - static constexpr int NPhysicalPrimaryBit = 0x4; + static constexpr float ChargeEpsilon = 1e-6f; - // Centrality percentile class boundaries (used in fillMultiplicityClass) - static constexpr float CentBound1 = 1.0f; - static constexpr float CentBound5 = 5.0f; - static constexpr float CentBound10 = 10.0f; - static constexpr float CentBound20 = 20.0f; - static constexpr float CentBound30 = 30.0f; - static constexpr float CentBound40 = 40.0f; - static constexpr float CentBound50 = 50.0f; - static constexpr float CentBound60 = 60.0f; - static constexpr float CentBound70 = 70.0f; - static constexpr float CentBound80 = 80.0f; - static constexpr float CentBound90 = 90.0f; - static constexpr float CentBound95 = 95.0f; - - // ============================================ - // Histogram Definitions - 100 BINS (bin width = 0.01) - // ============================================ + // ======================================================================== + // Run-1 fine binning + // ======================================================================== + static constexpr int NFlatBins = 10000; + + // ======================================================================== + // Histograms + // ======================================================================== HistogramRegistry histos{ "histos", { - // Event-level - {"hEvents", "Event selection;;Counts", {HistType::kTH1F, {{5, 0, 5}}}}, - - // dNch/deta - {"hNch_INEL", "Nch distribution (INEL>0);N_{ch};Entries", {HistType::kTH1F, {{100, -0.5, 99.5}}}}, - {"hNch_FT0", "Nch distribution (INEL>0 & FT0);N_{ch};Entries", {HistType::kTH1F, {{100, -0.5, 99.5}}}}, - - // ============================================ - // Flattenicity Histograms - 100 BINS! - // Bin width = 0.01, allowing 0-1% and 1-5% classes - // ============================================ - {"hFlattenicityParticles", "Flattenicity from charged particles;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - {"hFlattenicityParticles_vs_Nch", "Flattenicity (particles) vs Nch;N_{ch};1-#rho", {HistType::kTH2F, {{50, -0.5, 99.5}, {100, 0.0, 1.0}}}}, - {"hFlattenicityFT0", "Flattenicity from FT0 detector amplitudes;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - - // FT0 cell occupancy - {"hCellOccupancy", "FT0 cell occupancy;Cell ID;Entries", {HistType::kTH1F, {{NCell, 0, NCell}}}}, - {"hCellOccupancyFT0A", "FT0-A cell occupancy;Cell ID;Entries", {HistType::kTH1F, {{NchA, 0, NchA}}}}, - {"hCellOccupancyFT0C", "FT0-C cell occupancy;Cell ID;Entries", {HistType::kTH1F, {{NchC, 0, NchC}}}}, - - // ============================================ - // MULTIPLICITY CLASSES USING PERCENTILES - // All classes have 100 bins (bin width = 0.01) - // Following Antonio's publication style - // ============================================ - // 0-1% - {"hFlattenicityParticles_0_1", "Flattenicity (particles) class 0-1%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - {"hFlattenicityFT0_0_1", "Flattenicity (FT0) class 0-1%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - // 1-5% - {"hFlattenicityParticles_1_5", "Flattenicity (particles) class 1-5%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - {"hFlattenicityFT0_1_5", "Flattenicity (FT0) class 1-5%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - // 5-10% - {"hFlattenicityParticles_5_10", "Flattenicity (particles) class 5-10%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - {"hFlattenicityFT0_5_10", "Flattenicity (FT0) class 5-10%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - // 10-20% - {"hFlattenicityParticles_10_20", "Flattenicity (particles) class 10-20%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - {"hFlattenicityFT0_10_20", "Flattenicity (FT0) class 10-20%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - // 20-30% - {"hFlattenicityParticles_20_30", "Flattenicity (particles) class 20-30%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - {"hFlattenicityFT0_20_30", "Flattenicity (FT0) class 20-30%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - // 30-40% - {"hFlattenicityParticles_30_40", "Flattenicity (particles) class 30-40%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - {"hFlattenicityFT0_30_40", "Flattenicity (FT0) class 30-40%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - // 40-50% - {"hFlattenicityParticles_40_50", "Flattenicity (particles) class 40-50%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - {"hFlattenicityFT0_40_50", "Flattenicity (FT0) class 40-50%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - // 50-60% - {"hFlattenicityParticles_50_60", "Flattenicity (particles) class 50-60%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - {"hFlattenicityFT0_50_60", "Flattenicity (FT0) class 50-60%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - // 60-70% - {"hFlattenicityParticles_60_70", "Flattenicity (particles) class 60-70%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - {"hFlattenicityFT0_60_70", "Flattenicity (FT0) class 60-70%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - // 70-80% - {"hFlattenicityParticles_70_80", "Flattenicity (particles) class 70-80%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - {"hFlattenicityFT0_70_80", "Flattenicity (FT0) class 70-80%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - // 80-90% - {"hFlattenicityParticles_80_90", "Flattenicity (particles) class 80-90%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - {"hFlattenicityFT0_80_90", "Flattenicity (FT0) class 80-90%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - // 90-95% - {"hFlattenicityParticles_90_95", "Flattenicity (particles) class 90-95%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - {"hFlattenicityFT0_90_95", "Flattenicity (FT0) class 90-95%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - // 95-100% - {"hFlattenicityParticles_95_100", "Flattenicity (particles) class 95-100%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - {"hFlattenicityFT0_95_100", "Flattenicity (FT0) class 95-100%;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, - - // ============================================ - // GEN vs RECO CORRELATION - // Antonio's original request: compare flattenicity at - // generator (MC truth) level vs reconstruction level, - // for the same collision. - // ============================================ - {"hFlatParticles_Gen_vs_Rec", "Flattenicity (particles): gen vs reco;1-#rho (gen);1-#rho (reco)", {HistType::kTH2F, {{100, 0.0, 1.0}, {100, 0.0, 1.0}}}}, - {"hFlatFT0_Gen_vs_Rec", "Flattenicity: gen (particles) vs reco (FT0 amplitudes);1-#rho (gen);1-#rho (reco FT0)", {HistType::kTH2F, {{100, 0.0, 1.0}, {100, 0.0, 1.0}}}}, - {"hFlattenicityGen_MatchedToReco", "Gen-level flattenicity (only events with a reco match);1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, + {"QA/hEvents", "Event selection;selection;Entries", {HistType::kTH1F, {{5, 0, 5}}}}, + {"QA/hNchINEL", "INEL>0 multiplicity (|eta|<0.8);N_{ch};Entries", {HistType::kTH1F, {{100, -0.5, 99.5}}}}, + + {"Truth/hFlattenicityTruthAverage_fine", "MC truth flattenicity - average of FT0A-like/FT0C-like grids;1-#rho;Entries", {HistType::kTH1F, {{NFlatBins, 0.0, 1.0}}}}, + {"Truth/hFlattenicityTruthCombined_fine", "MC truth flattenicity - combined 208-cell grid;1-#rho;Entries", {HistType::kTH1F, {{NFlatBins, 0.0, 1.0}}}}, + {"Reco/hFlattenicityFT0Average_fine", "FT0 flattenicity - average of FT0A and FT0C;1-#rho;Entries", {HistType::kTH1F, {{NFlatBins, 0.0, 1.0}}}}, + {"Reco/hFlattenicityFT0Combined_fine", "FT0 flattenicity - combined FT0A+FT0C;1-#rho;Entries", {HistType::kTH1F, {{NFlatBins, 0.0, 1.0}}}}, + {"Reco/hFT0Mraw_fine", "Raw FT0M amplitude sum;FT0A+FT0C amplitude;Entries", {HistType::kTH1F, {{NFlatBins, 0.0, 20000.0}}}}, + + {"Truth/hFlattenicityTruthAverage", "MC truth flattenicity - average definition;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, + {"Truth/hFlattenicityTruthCombined", "MC truth flattenicity - combined definition;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, + {"Reco/hFlattenicityFT0Average", "FT0 flattenicity - average definition;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, + {"Reco/hFlattenicityFT0Combined", "FT0 flattenicity - combined definition;1-#rho;Entries", {HistType::kTH1F, {{100, 0.0, 1.0}}}}, + {"Reco/hFT0Mraw", "Raw FT0M amplitude sum;FT0A+FT0C amplitude;Entries", {HistType::kTH1F, {{200, 0.0, 20000.0}}}}, + + {"Truth/hCellOccupancy", "Truth FT0 cell occupancy;cell ID;Entries", {HistType::kTH1F, {{NCell, 0, NCell}}}}, + {"Truth/hCellOccupancyFT0A", "Truth FT0A cell occupancy;cell ID;Entries", {HistType::kTH1F, {{NchA, 0, NchA}}}}, + {"Truth/hCellOccupancyFT0C", "Truth FT0C cell occupancy;cell ID;Entries", {HistType::kTH1F, {{NchC, 0, NchC}}}}, }}; - // ============================================ + // ======================================================================== // Configurables - // ============================================ - Configurable cfgPtMin{"cfgPtMin", 0.1, "Minimum pT for tracks"}; - Configurable cfgEtaMax{"cfgEtaMax", 0.8, "Maximum |eta| for tracks"}; - Configurable cfgVzMax{"cfgVzMax", 10.0, "Maximum |vz| for collisions"}; + // ======================================================================== + + Configurable cfgPtMin{"cfgPtMin", 0.0, "Minimum pT for charged particles/tracks (GeV/c) - Antonio's instruction: require pT > 0, not a physical pT-threshold cut"}; + Configurable cfgEtaMax{"cfgEtaMax", 0.8, "Maximum |eta| for INEL>0 and track selection"}; + Configurable cfgVzMax{"cfgVzMax", 10.0, "Maximum absolute collision vertex z (cm)"}; + Configurable cfgApplySel8{"cfgApplySel8", true, "Apply sel8 event selection (set to true for all samples)"}; Configurable cfgNCrossedRowsTPC{"cfgNCrossedRowsTPC", 70, "Minimum TPC crossed rows"}; Configurable cfgChi2PerClusterTPC{"cfgChi2PerClusterTPC", 4.0, "Maximum TPC chi2 per cluster"}; Configurable cfgChi2PerClusterITS{"cfgChi2PerClusterITS", 36.0, "Maximum ITS chi2 per cluster"}; - Configurable cfgDCAZ{"cfgDCAZ", 0.1, "Maximum DCA z"}; - Configurable cfgRequireGoldenChi2{"cfgRequireGoldenChi2", true, "Require golden chi2"}; + Configurable cfgDCAZ{"cfgDCAZ", 0.1, "Maximum absolute DCAz (cm)"}; + Configurable cfgRequireGoldenChi2{"cfgRequireGoldenChi2", true, "Require global/golden track selection"}; - // ============================================ - // Particle charge function - // ============================================ - int getCharge(int pdgCode) + // ======================================================================== + // PDG charge helper + // ======================================================================== + bool isChargedParticle(int pdgCode) { - switch (std::abs(pdgCode)) { - case PDG_t::kPiPlus: // 211 - case PDG_t::kKPlus: // 321 - case PDG_t::kProton: // 2212 - return 1; - case PDG_t::kElectron: // 11 - case PDG_t::kMuonPlus: // 13 - return -1; - default: - return 0; + const auto* pdgParticle = pdg->GetParticle(pdgCode); + if (!pdgParticle) { + return false; + } + if (std::abs(pdgParticle->Charge()) < ChargeEpsilon) { + return false; } + return true; } - // ============================================ - // Flattenicity calculation - // ============================================ - float computeFlattenicity(const std::array& counts) + // ======================================================================== + // Rho / flattenicity calculation + // ======================================================================== + template + float computeRho(const std::array& counts) { - float total = 0.0; - for (int i = 0; i < NCell; i++) { + float total = 0.0f; + for (std::size_t i = 0; i < N; ++i) { total += counts[i]; } - - if (total <= 0) { - return -1.0; + if (total <= 0.0f) { + return -1.0f; } - - float mean = total / NCell; - if (mean <= 0) { - return -1.0; + const float mean = total / static_cast(N); + if (mean <= 0.0f) { + return -1.0f; } + float sumSq = 0.0f; + for (std::size_t i = 0; i < N; ++i) { + const float diff = counts[i] - mean; + sumSq += diff * diff; + } + return std::sqrt(sumSq) / (static_cast(N) * mean); + } - float sumSq = 0.0; - for (int i = 0; i < NCell; i++) { - sumSq += (counts[i] - mean) * (counts[i] - mean); + template + float computeFlattenicity(const std::array& counts) + { + const float rho = computeRho(counts); + if (rho < 0.0f) { + return -1.0f; } + return 1.0f - rho; + } - float rho = std::sqrt(sumSq) / (NCell * mean); - return rho; + // ======================================================================== + // FT0 channel -> sector + // ======================================================================== + int getFT0ASector(int channel) + { + if (channel < 0 || channel >= NchA) { + return -1; + } + return channel / ChannelsPerSector; + } + int getFT0CSector(int channel) + { + if (channel < 0 || channel >= NchC) { + return -1; + } + return channel / ChannelsPerSector; } - // ============================================ - // Assign particle to FT0 cell - // ============================================ + // ======================================================================== + // Generator particle -> 208-cell grid + // ======================================================================== int assignToFT0Cell(float eta, float phi, bool& isFT0A) { - // Check if in FT0 acceptance - bool inFT0A = (eta > FT0AEtaMin && eta < FT0AEtaMax); - bool inFT0C = (eta > FT0CEtaMin && eta < FT0CEtaMax); - + const bool inFT0A = (eta > FT0AEtaMin && eta < FT0AEtaMax); + const bool inFT0C = (eta > FT0CEtaMin && eta < FT0CEtaMax); if (!inFT0A && !inFT0C) { return -1; } - isFT0A = inFT0A; - // Phi bin - int phiBin = static_cast(std::floor(phi / (o2::constants::math::TwoPI / NPhiSectors))); - phiBin = std::max(0, std::min(phiBin, NPhiSectors - 1)); + // Wrap phi into [0, 2pi) using the O2-standard helper - avoids the + // manual +=/-= TwoPI pattern the linter flags (two-pi-add-subtract). + const float wrappedPhi = RecoDecay::constrainAngle(phi, 0.0f); - int cellId = -1; + const float phiWidth = o2::constants::math::TwoPI / static_cast(NPhiSectors); + int phiBin = static_cast(std::floor(wrappedPhi / phiWidth)); + phiBin = std::max(0, std::min(phiBin, NPhiSectors - 1)); if (inFT0A) { - // FT0-A: cells 0-95 - float etaWidth = (FT0AEtaMax - FT0AEtaMin) / NEtaA; + const float etaWidth = (FT0AEtaMax - FT0AEtaMin) / static_cast(NEtaA); int etaBin = static_cast(std::floor((eta - FT0AEtaMin) / etaWidth)); etaBin = std::max(0, std::min(etaBin, NEtaA - 1)); - cellId = etaBin * NPhiSectors + phiBin; - } else if (inFT0C) { - // FT0-C: cells 96-207 - float etaWidth = (FT0CEtaMax - FT0CEtaMin) / NEtaC; - int etaBin = static_cast(std::floor((eta - FT0CEtaMin) / etaWidth)); - etaBin = std::max(0, std::min(etaBin, NEtaC - 1)); - cellId = NchA + etaBin * NPhiSectors + phiBin; + return etaBin * NPhiSectors + phiBin; } - - return cellId; + const float etaWidth = (FT0CEtaMax - FT0CEtaMin) / static_cast(NEtaC); + int etaBin = static_cast(std::floor((eta - FT0CEtaMin) / etaWidth)); + etaBin = std::max(0, std::min(etaBin, NEtaC - 1)); + return NchA + etaBin * NPhiSectors + phiBin; } - // ============================================ - // Track selection - // ============================================ - template - bool isSelectedTrack(const T& track) + // ======================================================================== + // Compute both reco definitions + // ======================================================================== + template + bool computeFT0Flattenicities(const FT0& ft0, float& flattenicityAverage, float& flattenicityCombined, float& sumAmplitude) { - // pT selection - if (track.pt() < cfgPtMin) { - return false; - } - - // Eta selection - if (std::abs(track.eta()) > cfgEtaMax) { - return false; - } - - // TPC crossed rows - if (track.tpcNClsCrossedRows() < cfgNCrossedRowsTPC) { - return false; - } - - // TPC chi2 per cluster - if (track.tpcChi2NCl() > cfgChi2PerClusterTPC) { - return false; - } - - // ITS chi2 per cluster - if (track.itsChi2NCl() > cfgChi2PerClusterITS) { - return false; + std::array countsA{}; + std::array countsC{}; + std::array countsCombined{}; + sumAmplitude = 0.0f; + for (std::size_t i = 0; i < ft0.amplitudeA().size(); ++i) { + const int channel = ft0.channelA()[i]; + const int sector = getFT0ASector(channel); + const float amplitude = ft0.amplitudeA()[i]; + if (sector >= 0 && sector < NSectorsA) { + countsA[sector] += amplitude; + countsCombined[sector] += amplitude; + } + sumAmplitude += amplitude; + } + for (std::size_t i = 0; i < ft0.amplitudeC().size(); ++i) { + const int channel = ft0.channelC()[i]; + const int sector = getFT0CSector(channel); + const float amplitude = ft0.amplitudeC()[i]; + if (sector >= 0 && sector < NSectorsC) { + countsC[sector] += amplitude; + countsCombined[NSectorsA + sector] += amplitude; + } + sumAmplitude += amplitude; } - - // DCA z - if (std::abs(track.dcaZ()) > cfgDCAZ) { + const float rhoA = computeRho(countsA); + const float rhoC = computeRho(countsC); + if (rhoA < 0.0f || rhoC < 0.0f) { return false; } - - // Golden chi2 (global track) - if (cfgRequireGoldenChi2 && !track.isGlobalTrack()) { + flattenicityAverage = 1.0f - 0.5f * (rhoA + rhoC); + const float rhoCombined = computeRho(countsCombined); + if (rhoCombined < 0.0f) { return false; } - + flattenicityCombined = 1.0f - rhoCombined; return true; } - // ============================================ - // Helper function to fill multiplicity class histograms - // ============================================ - void fillMultiplicityClass(float flattenicity, float centrality, bool isParticle) + // ======================================================================== + // processMC + // ======================================================================== + void processMC(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) { - // Particle histograms - if (isParticle) { - if (centrality < CentBound1) { - histos.fill(HIST("hFlattenicityParticles_0_1"), flattenicity); - } else if (centrality < CentBound5) { - histos.fill(HIST("hFlattenicityParticles_1_5"), flattenicity); - } else if (centrality < CentBound10) { - histos.fill(HIST("hFlattenicityParticles_5_10"), flattenicity); - } else if (centrality < CentBound20) { - histos.fill(HIST("hFlattenicityParticles_10_20"), flattenicity); - } else if (centrality < CentBound30) { - histos.fill(HIST("hFlattenicityParticles_20_30"), flattenicity); - } else if (centrality < CentBound40) { - histos.fill(HIST("hFlattenicityParticles_30_40"), flattenicity); - } else if (centrality < CentBound50) { - histos.fill(HIST("hFlattenicityParticles_40_50"), flattenicity); - } else if (centrality < CentBound60) { - histos.fill(HIST("hFlattenicityParticles_50_60"), flattenicity); - } else if (centrality < CentBound70) { - histos.fill(HIST("hFlattenicityParticles_60_70"), flattenicity); - } else if (centrality < CentBound80) { - histos.fill(HIST("hFlattenicityParticles_70_80"), flattenicity); - } else if (centrality < CentBound90) { - histos.fill(HIST("hFlattenicityParticles_80_90"), flattenicity); - } else if (centrality < CentBound95) { - histos.fill(HIST("hFlattenicityParticles_90_95"), flattenicity); - } else { - histos.fill(HIST("hFlattenicityParticles_95_100"), flattenicity); - } - } else { - // FT0 histograms - if (centrality < CentBound1) { - histos.fill(HIST("hFlattenicityFT0_0_1"), flattenicity); - } else if (centrality < CentBound5) { - histos.fill(HIST("hFlattenicityFT0_1_5"), flattenicity); - } else if (centrality < CentBound10) { - histos.fill(HIST("hFlattenicityFT0_5_10"), flattenicity); - } else if (centrality < CentBound20) { - histos.fill(HIST("hFlattenicityFT0_10_20"), flattenicity); - } else if (centrality < CentBound30) { - histos.fill(HIST("hFlattenicityFT0_20_30"), flattenicity); - } else if (centrality < CentBound40) { - histos.fill(HIST("hFlattenicityFT0_30_40"), flattenicity); - } else if (centrality < CentBound50) { - histos.fill(HIST("hFlattenicityFT0_40_50"), flattenicity); - } else if (centrality < CentBound60) { - histos.fill(HIST("hFlattenicityFT0_50_60"), flattenicity); - } else if (centrality < CentBound70) { - histos.fill(HIST("hFlattenicityFT0_60_70"), flattenicity); - } else if (centrality < CentBound80) { - histos.fill(HIST("hFlattenicityFT0_70_80"), flattenicity); - } else if (centrality < CentBound90) { - histos.fill(HIST("hFlattenicityFT0_80_90"), flattenicity); - } else if (centrality < CentBound95) { - histos.fill(HIST("hFlattenicityFT0_90_95"), flattenicity); - } else { - histos.fill(HIST("hFlattenicityFT0_95_100"), flattenicity); - } - } - } - - // ============================================ - // Process MC collisions (generator level only) - // ============================================ - void processMC( - aod::McCollisions const& /* mcCollisions */, - aod::McParticles const& mcParticles) - { - if (mcParticles.size() == 0) { - LOG(warning) << "No MC particles found in this data frame"; + if (std::abs(mcCollision.posZ()) > cfgVzMax) { return; } - - // Initialize counters + // Combined 208-cell truth grid (cells 0..NchA-1 = FT0A-like, NchA..NCell-1 + // = FT0C-like) AND the two separate sub-arrays, filled in parallel, so we + // can compute BOTH truth definitions - average and combined - the same + // way the reco side already does for the real FT0-A/FT0-C sectors. std::array truthCounts{}; + std::array truthCountsA{}; + std::array truthCountsC{}; + int nChINEL = 0; + bool hasFT0A = false, hasFT0C = false; - int nchINEL = 0; - int nchFT0 = 0; - bool hasFT0A = false; - bool hasFT0C = false; - - // Loop over MC particles for (const auto& particle : mcParticles) { - // Check if primary if ((particle.flags() & NPhysicalPrimaryBit) == 0) { continue; } - - // Check if charged - int charge = getCharge(particle.pdgCode()); - if (charge == 0) { - continue; - } - - // pT > 0.1 - if (particle.pt() < cfgPtMin) { + if (!isChargedParticle(particle.pdgCode())) { continue; } - - // INEL>0: |eta| < 1 - if (std::abs(particle.eta()) < 1.0) { - nchINEL++; + if (particle.pt() <= cfgPtMin) { + continue; // Antonio: require pT > 0 } - - // dNch/deta: |eta| < 0.8 if (std::abs(particle.eta()) < cfgEtaMax) { - nchFT0++; + ++nChINEL; } - // FT0 acceptance - bool inFT0A = (particle.eta() > FT0AEtaMin && particle.eta() < FT0AEtaMax); - bool inFT0C = (particle.eta() > FT0CEtaMin && particle.eta() < FT0CEtaMax); - + const bool inFT0A = (particle.eta() > FT0AEtaMin && particle.eta() < FT0AEtaMax); + const bool inFT0C = (particle.eta() > FT0CEtaMin && particle.eta() < FT0CEtaMax); if (inFT0A) { hasFT0A = true; } @@ -424,187 +302,96 @@ struct FlattenicityTask { hasFT0C = true; } - // Assign to FT0 cell bool isFT0A = false; - int cellId = assignToFT0Cell(particle.eta(), particle.phi(), isFT0A); - - if (cellId >= 0 && cellId < NCell) { - truthCounts[cellId] += 1.0; - histos.fill(HIST("hCellOccupancy"), cellId); - if (isFT0A) { - histos.fill(HIST("hCellOccupancyFT0A"), cellId); - } else { - histos.fill(HIST("hCellOccupancyFT0C"), cellId - NchA); - } + const int cellId = assignToFT0Cell(particle.eta(), particle.phi(), isFT0A); + if (cellId < 0 || cellId >= NCell) { + continue; + } + truthCounts[cellId] += 1.0f; + if (isFT0A) { + truthCountsA[cellId] += 1.0f; + } else { + truthCountsC[cellId - NchA] += 1.0f; } - } - - // Event selection - bool isINEL = (nchINEL > 0); - bool isFT0 = (hasFT0A && hasFT0C); - - histos.fill(HIST("hEvents"), 0); // All events - - if (isINEL) { - histos.fill(HIST("hEvents"), 1); // INEL>0 - histos.fill(HIST("hNch_INEL"), nchFT0); - } - - if (isINEL && isFT0) { - histos.fill(HIST("hEvents"), 2); // INEL>0 & FT0 - histos.fill(HIST("hNch_FT0"), nchFT0); - // Compute flattenicity - float rho = computeFlattenicity(truthCounts); - if (rho > 0) { - float flattenicity = 1.0 - rho; - histos.fill(HIST("hFlattenicityParticles"), flattenicity); - histos.fill(HIST("hFlattenicityParticles_vs_Nch"), nchFT0, flattenicity); + histos.fill(HIST("Truth/hCellOccupancy"), cellId); + if (isFT0A) { + histos.fill(HIST("Truth/hCellOccupancyFT0A"), cellId); + } else { + histos.fill(HIST("Truth/hCellOccupancyFT0C"), cellId - NchA); } } - } - PROCESS_SWITCH(FlattenicityTask, processMC, "Process MC events", false); - - // ============================================ - // Process data collisions (reconstruction level only) - // ============================================ - void processData( - CollisionsWithCent::iterator const& collision, - aod::FT0s const& ft0s, - FullTracks const& tracks) - { - // Event selection: |vz| < 10 cm - if (std::abs(collision.posZ()) > cfgVzMax) { + if (nChINEL == 0) { return; } + histos.fill(HIST("QA/hEvents"), 1); + histos.fill(HIST("QA/hNchINEL"), nChINEL); - // Get centrality percentile (0-100) - float centrality = collision.centFT0M(); - - // Find FT0 matching this collision's BC - auto ft0 = ft0s.begin(); - bool foundFT0 = false; - for (const auto& f : ft0s) { - if (f.bcId() == collision.bcId()) { - ft0 = f; - foundFT0 = true; - break; - } - } - if (!foundFT0) { + // Require activity on BOTH sides of the detector (Antonio's instruction), + // for MC truth exactly as already required on the reco side. + if (!hasFT0A || !hasFT0C) { return; } - - // Track selection and counting - std::array recoCounts{}; - - for (const auto& track : tracks) { - if (!isSelectedTrack(track)) { - continue; - } - - // Assign to FT0 cell using track extrapolation - bool isFT0A = false; - int cellId = assignToFT0Cell(track.eta(), track.phi(), isFT0A); - if (cellId >= 0 && cellId < NCell) { - recoCounts[cellId] += 1.0; + histos.fill(HIST("QA/hEvents"), 2); + + // Definition 1: average of two separately-normalized rho's (mirrors the + // reco "average" definition, using the truth-grid A/C sub-arrays). + const float rhoATruth = computeRho(truthCountsA); + const float rhoCTruth = computeRho(truthCountsC); + if (rhoATruth >= 0.0f && rhoCTruth >= 0.0f) { + const float flattenicityTruthAverage = 1.0f - 0.5f * (rhoATruth + rhoCTruth); + if (flattenicityTruthAverage >= 0.0f && flattenicityTruthAverage <= 1.0f) { + histos.fill(HIST("Truth/hFlattenicityTruthAverage_fine"), flattenicityTruthAverage); + histos.fill(HIST("Truth/hFlattenicityTruthAverage"), flattenicityTruthAverage); } } - histos.fill(HIST("hEvents"), 3); // Data events - - // Compute particle flattenicity - float rhoParticles = computeFlattenicity(recoCounts); - if (rhoParticles > 0) { - float flattenicity = 1.0 - rhoParticles; - histos.fill(HIST("hFlattenicityParticles"), flattenicity); - fillMultiplicityClass(flattenicity, centrality, true); - } - - // Compute flattenicity from FT0 amplitudes - std::array ft0Counts{}; - - // FT0-A channels (0-95) - if (ft0.amplitudeA().size() > 0) { - for (std::size_t i = 0; i < ft0.amplitudeA().size(); i++) { - uint8_t channel = ft0.channelA()[i]; - if (channel < NchA) { - ft0Counts[channel] = ft0.amplitudeA()[i]; - } - } - } - - // FT0-C channels (96-207) - if (ft0.amplitudeC().size() > 0) { - for (std::size_t i = 0; i < ft0.amplitudeC().size(); i++) { - uint8_t channel = ft0.channelC()[i]; - if (channel < NchC) { - ft0Counts[NchA + channel] = ft0.amplitudeC()[i]; - } - } - } - - float rhoFT0 = computeFlattenicity(ft0Counts); - if (rhoFT0 > 0) { - float flattenicity = 1.0 - rhoFT0; - histos.fill(HIST("hFlattenicityFT0"), flattenicity); - fillMultiplicityClass(flattenicity, centrality, false); + // Definition 2: one combined rho over the full 208-cell truth grid. + const float flattenicityTruthCombined = computeFlattenicity(truthCounts); + if (flattenicityTruthCombined >= 0.0f) { + histos.fill(HIST("Truth/hFlattenicityTruthCombined_fine"), flattenicityTruthCombined); + histos.fill(HIST("Truth/hFlattenicityTruthCombined"), flattenicityTruthCombined); } } - PROCESS_SWITCH(FlattenicityTask, processData, "Process data events", true); + PROCESS_SWITCH(FlattenicityTask, processMC, "Process MC truth for Run-1 calibration", true); - // ============================================ - // Process GEN vs RECO correlation - // ============================================ - Preslice perMCCol = aod::mcparticle::mcCollisionId; - SliceCache cache; - - void processGenRecCorrelation( - CollisionsWithCentAndMcLabel::iterator const& collision, - aod::McCollisions const&, - aod::McParticles const& mcParticles, - aod::FT0s const& ft0s, - FullTracks const& tracks) + // ======================================================================== + // processData + // ======================================================================== + void processData(CollisionsWithSelection::iterator const& collision, + aod::FT0s const& ft0s, + FullTracks const& tracks) { - if (std::abs(collision.posZ()) > cfgVzMax) { + if (cfgApplySel8 && !collision.sel8()) { return; } - if (!collision.has_mcCollision()) { + if (std::abs(collision.posZ()) > cfgVzMax) { return; } - // ---- Generator level: same truth-flattenicity logic as processMC ---- - const auto& mcCollision = collision.mcCollision(); - const auto& particlesInThisCollision = mcParticles.sliceBy(perMCCol, mcCollision.globalIndex()); - - std::array truthCounts{}; - for (const auto& particle : particlesInThisCollision) { - if ((particle.flags() & NPhysicalPrimaryBit) == 0) { - continue; - } - if (getCharge(particle.pdgCode()) == 0) { + int nChINEL = 0; + for (const auto& track : tracks) { + if (track.collisionId() != collision.globalIndex()) { continue; } - if (particle.pt() < cfgPtMin) { + if (track.pt() <= cfgPtMin) { continue; } - bool isFT0A = false; - int cellId = assignToFT0Cell(particle.eta(), particle.phi(), isFT0A); - if (cellId >= 0 && cellId < NCell) { - truthCounts[cellId] += 1.0; + if (std::abs(track.eta()) < cfgEtaMax) { + ++nChINEL; } } - float rhoGen = computeFlattenicity(truthCounts); - if (rhoGen <= 0) { + if (nChINEL == 0) { return; } - float flatGen = 1.0 - rhoGen; - // ---- Reconstruction level: same reco logic as processData ---- - auto ft0 = ft0s.begin(); + histos.fill(HIST("QA/hEvents"), 3); + histos.fill(HIST("QA/hNchINEL"), nChINEL); + bool foundFT0 = false; + aod::FT0s::iterator ft0; for (const auto& f : ft0s) { if (f.bcId() == collision.bcId()) { ft0 = f; @@ -612,60 +399,35 @@ struct FlattenicityTask { break; } } + if (!foundFT0) { + return; + } - std::array recoCounts{}; - for (const auto& track : tracks) { - if (!isSelectedTrack(track)) { - continue; - } - bool isFT0A = false; - int cellId = assignToFT0Cell(track.eta(), track.phi(), isFT0A); - if (cellId >= 0 && cellId < NCell) { - recoCounts[cellId] += 1.0; - } + float flattenicityAverage = -1.0f, flattenicityCombined = -1.0f, sumFT0M = 0.0f; + if (!computeFT0Flattenicities(ft0, flattenicityAverage, flattenicityCombined, sumFT0M)) { + return; } - float rhoRecParticles = computeFlattenicity(recoCounts); - // Fill gen-level histogram restricted to events with a reco match - histos.fill(HIST("hFlattenicityGen_MatchedToReco"), flatGen); + histos.fill(HIST("Reco/hFT0Mraw"), sumFT0M); + histos.fill(HIST("Reco/hFT0Mraw_fine"), sumFT0M); - if (rhoRecParticles > 0) { - float flatRecParticles = 1.0 - rhoRecParticles; - histos.fill(HIST("hFlatParticles_Gen_vs_Rec"), flatGen, flatRecParticles); + if (flattenicityAverage >= 0.0f && flattenicityAverage <= 1.0f) { + histos.fill(HIST("Reco/hFlattenicityFT0Average_fine"), flattenicityAverage); + histos.fill(HIST("Reco/hFlattenicityFT0Average"), flattenicityAverage); } - - if (foundFT0) { - std::array ft0Counts{}; - if (ft0.amplitudeA().size() > 0) { - for (std::size_t i = 0; i < ft0.amplitudeA().size(); i++) { - uint8_t channel = ft0.channelA()[i]; - if (channel < NchA) { - ft0Counts[channel] = ft0.amplitudeA()[i]; - } - } - } - if (ft0.amplitudeC().size() > 0) { - for (std::size_t i = 0; i < ft0.amplitudeC().size(); i++) { - uint8_t channel = ft0.channelC()[i]; - if (channel < NchC) { - ft0Counts[NchA + channel] = ft0.amplitudeC()[i]; - } - } - } - float rhoRecFT0 = computeFlattenicity(ft0Counts); - if (rhoRecFT0 > 0) { - float flatRecFT0 = 1.0 - rhoRecFT0; - histos.fill(HIST("hFlatFT0_Gen_vs_Rec"), flatGen, flatRecFT0); - } + if (flattenicityCombined >= 0.0f && flattenicityCombined <= 1.0f) { + histos.fill(HIST("Reco/hFlattenicityFT0Combined_fine"), flattenicityCombined); + histos.fill(HIST("Reco/hFlattenicityFT0Combined"), flattenicityCombined); } } - PROCESS_SWITCH(FlattenicityTask, processGenRecCorrelation, "Process gen-vs-reco correlation (needs MC file)", false); + PROCESS_SWITCH(FlattenicityTask, processData, "Process data / MC-reco for Run-1 calibration", true); }; +// ============================================================================ +// Workflow +// ============================================================================ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - WorkflowSpec workflow{}; - workflow.push_back(adaptAnalysisTask(cfgc)); - return workflow; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/PWGUD/AQC/udQC.cxx b/PWGUD/AQC/udQC.cxx index 0edcdc28117..44c2f03a2e8 100644 --- a/PWGUD/AQC/udQC.cxx +++ b/PWGUD/AQC/udQC.cxx @@ -711,7 +711,7 @@ struct UDQC { return; } - for (auto fv0 : fv0s) { + for (const auto& fv0 : fv0s) { registry.get(HIST("FV0/hV0A"))->Fill(fv0.time()); // side A for (size_t ind = 0; ind < fv0.channel().size(); ind++) { @@ -738,7 +738,7 @@ struct UDQC { registry.get(HIST("FT0/hT0AC"))->Fill(collision.t0AC()); } } - for (auto ft0 : ft0s) { + for (const auto& ft0 : ft0s) { registry.get(HIST("FT0/hT0A"))->Fill(ft0.timeA()); registry.get(HIST("FT0/hT0C"))->Fill(ft0.timeC()); @@ -760,7 +760,7 @@ struct UDQC { { // LOGF(debug, " %d", fdds.size()); - for (auto fdd : fdds) { + for (const auto& fdd : fdds) { registry.get(HIST("FDD/hFDDA"))->Fill(fdd.timeA()); registry.get(HIST("FDD/hFDDC"))->Fill(fdd.timeC()); diff --git a/PWGUD/Core/DGCutparHolder.cxx b/PWGUD/Core/DGCutparHolder.cxx index ee003684f5a..146698cca8f 100644 --- a/PWGUD/Core/DGCutparHolder.cxx +++ b/PWGUD/Core/DGCutparHolder.cxx @@ -11,6 +11,7 @@ #include "PWGUD/Core/DGCutparHolder.h" +#include #include // setter @@ -45,7 +46,7 @@ void DGCutparHolder::SetNTracks(int MinNTracks, int MaxNTracks) } void DGCutparHolder::SetNetCharges(std::vector netCharges) { - mNetCharges = netCharges; + mNetCharges = std::move(netCharges); } void DGCutparHolder::SetPidHypothesis(int pidHypo) { @@ -102,11 +103,11 @@ void DGCutparHolder::SetMaxFITtime(float maxFITtime) } void DGCutparHolder::SetFITAmpLimits(std::vector FITAmpLimits) { - mFITAmpLimits = FITAmpLimits; + mFITAmpLimits = std::move(FITAmpLimits); } void DGCutparHolder::SetCollisionSel(std::vector collisionSel) { - mCollisionSel = collisionSel; + mCollisionSel = std::move(collisionSel); } // getter diff --git a/PWGUD/Core/DGCutparHolder.h b/PWGUD/Core/DGCutparHolder.h index a67aefc4080..472a781b535 100644 --- a/PWGUD/Core/DGCutparHolder.h +++ b/PWGUD/Core/DGCutparHolder.h @@ -14,6 +14,7 @@ #include +#include #include // object to hold customizable cut values @@ -40,7 +41,7 @@ class DGCutparHolder bool TOR = true, float maxFITtime = 4, std::vector FITAmpLimits = {0., 0., 0., 0., 0.}, - std::vector collisionSel = {1, 1, 1, 0, 1, 0, 0}) : mNDtcoll{ndtcoll}, mMinNBCs{nMinBCs}, mWithFwdTracks{withFwdTracks}, mGlobalTracksOnly{globalTracksOnly}, mITSOnlyTracks{ITSonlyTracks}, mMinRgtrwTOF{minrgtrwTOF}, mMinNTracks{MinNTracks}, mMaxNTracks{MaxNTracks}, mNetCharges{NetCharges}, mPidHypo{pidHypo}, mMinVertexPosz{MinPosz}, mMaxVertexPosz{MaxPosz}, mMinPt{minPt}, mMaxPt{maxPt}, mMinEta{minEta}, mMaxEta{maxEta}, mMinIVM{minIVM}, mMaxIVM{maxIVM}, mMaxNSigmaTPC{maxNSigmaTPC}, mMaxNSigmaTOF{maxNSigmaTOF}, mTVX{TVX}, mTSC{TSC}, mTCE{TCE}, mTOR{TOR}, mMaxFITtime{maxFITtime}, mFITAmpLimits{FITAmpLimits}, mCollisionSel{collisionSel} + std::vector collisionSel = {1, 1, 1, 0, 1, 0, 0}) : mNDtcoll{ndtcoll}, mMinNBCs{nMinBCs}, mWithFwdTracks{withFwdTracks}, mGlobalTracksOnly{globalTracksOnly}, mITSOnlyTracks{ITSonlyTracks}, mMinRgtrwTOF{minrgtrwTOF}, mMinNTracks{MinNTracks}, mMaxNTracks{MaxNTracks}, mNetCharges{std::move(NetCharges)}, mPidHypo{pidHypo}, mMinVertexPosz{MinPosz}, mMaxVertexPosz{MaxPosz}, mMinPt{minPt}, mMaxPt{maxPt}, mMinEta{minEta}, mMaxEta{maxEta}, mMinIVM{minIVM}, mMaxIVM{maxIVM}, mMaxNSigmaTPC{maxNSigmaTPC}, mMaxNSigmaTOF{maxNSigmaTOF}, mTVX{TVX}, mTSC{TSC}, mTCE{TCE}, mTOR{TOR}, mMaxFITtime{maxFITtime}, mFITAmpLimits{std::move(FITAmpLimits)}, mCollisionSel{std::move(collisionSel)} { } diff --git a/PWGUD/Core/DGPIDSelector.cxx b/PWGUD/Core/DGPIDSelector.cxx index 7e0de287e48..054b548b602 100644 --- a/PWGUD/Core/DGPIDSelector.cxx +++ b/PWGUD/Core/DGPIDSelector.cxx @@ -22,6 +22,7 @@ #include #include #include +#include #include // ----------------------------------------------------------------------------- @@ -87,7 +88,7 @@ DGPIDCuts::DGPIDCuts() DGPIDCuts::DGPIDCuts(std::vector PIDCutValues) { - setPIDCuts(PIDCutValues); + setPIDCuts(std::move(PIDCutValues)); } DGPIDCuts::~DGPIDCuts() @@ -196,7 +197,7 @@ void DGAnaparHolder::SetdBC(int min, int max) mdBCMax = max; } -void DGAnaparHolder::SetFITvetoes(std::vector vetoes) +void DGAnaparHolder::SetFITvetoes(const std::vector& vetoes) { if (vetoes.size() == 5) { @@ -254,22 +255,22 @@ void DGAnaparHolder::SetnCombine(std::size_t nComb) void DGAnaparHolder::SetnetCharges(std::vector charges) { - mNetCharges = charges; + mNetCharges = std::move(charges); } void DGAnaparHolder::SetunlikeCharges(std::vector charges) { - mUnlikeCharges = charges; + mUnlikeCharges = std::move(charges); } void DGAnaparHolder::SetlikeCharges(std::vector charges) { - mLikeCharges = charges; + mLikeCharges = std::move(charges); } void DGAnaparHolder::SetPIDs(std::vector pids) { - mDGPIDs = pids; + mDGPIDs = std::move(pids); } // ----------------------------------------------------------------------------- @@ -435,7 +436,7 @@ void DGPIDSelector::Print() mAnaPars.Print(); } -void DGPIDSelector::init(DGAnaparHolder anaPars) +void DGPIDSelector::init(const DGAnaparHolder& anaPars) { mAnaPars = anaPars; mUnlikeIVMs.clear(); diff --git a/PWGUD/Core/DGPIDSelector.h b/PWGUD/Core/DGPIDSelector.h index de825ab3568..0480a0f2b1c 100644 --- a/PWGUD/Core/DGPIDSelector.h +++ b/PWGUD/Core/DGPIDSelector.h @@ -21,6 +21,7 @@ #include #include #include +#include #include const int numDGPIDCutParameters = 9; @@ -124,7 +125,7 @@ struct DGAnaparHolder { std::vector unlikeCharges = {0}, std::vector likeCharges = {-2, 2}, std::vector DGPIDs = {211, 211}, - std::vector DGPIDCutValues = {}) : mMinNTracks{MinNTracks}, mMaxNTracks{MaxNTracks}, mMinRgtrwTOF{minrgtrwTOF}, mMaxDCAxy{maxDCAxy}, mMaxDCAz{maxDCAz}, mdBCMin{dBCMin}, mdBCMax{dBCMax}, mFITvetoes{FITvetoes}, mITSOnlyTracks{ITSonlyTracks}, mMinNClTPC{minNClTPC}, mMaxNClTPC{maxNClTPC}, mMinChi2NClTPC{minChi2NClTPC}, mMaxChi2NClTPC{maxChi2NClTPC}, mMinpt{minpt}, mMaxpt{maxpt}, mMineta{mineta}, mMaxeta{maxeta}, mMinAlpha{minalpha}, mMaxAlpha{maxalpha}, mMinptsys{minptsys}, mMaxptsys{maxptsys}, mNCombine{nCombine}, mNetCharges{netCharges}, mUnlikeCharges{unlikeCharges}, mLikeCharges{likeCharges}, mDGPIDs{DGPIDs}, mDGPIDCutValues{DGPIDCutValues} + std::vector DGPIDCutValues = {}) : mMinNTracks{MinNTracks}, mMaxNTracks{MaxNTracks}, mMinRgtrwTOF{minrgtrwTOF}, mMaxDCAxy{maxDCAxy}, mMaxDCAz{maxDCAz}, mdBCMin{dBCMin}, mdBCMax{dBCMax}, mFITvetoes{std::move(FITvetoes)}, mITSOnlyTracks{ITSonlyTracks}, mMinNClTPC{minNClTPC}, mMaxNClTPC{maxNClTPC}, mMinChi2NClTPC{minChi2NClTPC}, mMaxChi2NClTPC{maxChi2NClTPC}, mMinpt{minpt}, mMaxpt{maxpt}, mMineta{mineta}, mMaxeta{maxeta}, mMinAlpha{minalpha}, mMaxAlpha{maxalpha}, mMinptsys{minptsys}, mMaxptsys{maxptsys}, mNCombine{nCombine}, mNetCharges{std::move(netCharges)}, mUnlikeCharges{std::move(unlikeCharges)}, mLikeCharges{std::move(likeCharges)}, mDGPIDs{std::move(DGPIDs)}, mDGPIDCutValues{std::move(DGPIDCutValues)} { if (mdBCMin < -16) { mdBCMin = -16; @@ -148,7 +149,7 @@ struct DGAnaparHolder { void SetMinRgtrwTOF(float); void SetmaxDCA(float, float); void SetdBC(int, int); - void SetFITvetoes(std::vector); + void SetFITvetoes(const std::vector&); void SetITSOnlyTracks(bool); void SetNClTPC(int, int); void SetChi2NClTPC(float, float); @@ -239,7 +240,7 @@ struct DGParticle { public: DGParticle(); template - DGParticle(TDatabasePDG* pdg, DGAnaparHolder anaPars, TTrack const& tracks, std::vector comb) + DGParticle(TDatabasePDG* pdg, const DGAnaparHolder& anaPars, TTrack const& tracks, const std::vector& comb) { // compute invariant mass TLorentzVector lvtmp; @@ -284,12 +285,12 @@ struct DGPIDSelector { ~DGPIDSelector(); // setters - void init(DGAnaparHolder anaPars); + void init(const DGAnaparHolder& anaPars); // getters void Print(); template - bool isGoodCombination(std::vector comb, TTrack const& tracks, std::vector acceptedCharges) + bool isGoodCombination(const std::vector& comb, TTrack const& tracks, std::vector acceptedCharges) { // compute net charge of track combination int netCharge = 0.; diff --git a/PWGUD/Core/DGSelector.h b/PWGUD/Core/DGSelector.h index 5c9afa99d00..2fde726a94c 100644 --- a/PWGUD/Core/DGSelector.h +++ b/PWGUD/Core/DGSelector.h @@ -37,7 +37,7 @@ class DGSelector ~DGSelector() { delete fPDG; } template - int Print(DGCutparHolder /*diffCuts*/, CC& collision, BCs& /*bcRange*/, TCs& /*tracks*/, FWs& /*fwdtracks*/) + int Print(const DGCutparHolder& /*diffCuts*/, CC& collision, BCs& /*bcRange*/, TCs& /*tracks*/, FWs& /*fwdtracks*/) { LOGF(info, "Size of array %i", collision.size()); return 1; diff --git a/PWGUD/Core/SGCutParHolder.cxx b/PWGUD/Core/SGCutParHolder.cxx index ba180a97280..45519efebf6 100644 --- a/PWGUD/Core/SGCutParHolder.cxx +++ b/PWGUD/Core/SGCutParHolder.cxx @@ -11,6 +11,7 @@ #include "PWGUD/Core/SGCutParHolder.h" +#include #include // setter @@ -69,7 +70,7 @@ void SGCutParHolder::SetMaxFITtime(float maxFITtime) } void SGCutParHolder::SetFITAmpLimits(std::vector FITAmpLimits) { - mFITAmpLimits = FITAmpLimits; + mFITAmpLimits = std::move(FITAmpLimits); } // getter diff --git a/PWGUD/Core/SGCutParHolder.h b/PWGUD/Core/SGCutParHolder.h index fcee2d79703..d02848fafbe 100644 --- a/PWGUD/Core/SGCutParHolder.h +++ b/PWGUD/Core/SGCutParHolder.h @@ -14,6 +14,7 @@ #include +#include #include // object to hold customizable cut values @@ -32,7 +33,7 @@ class SGCutParHolder float minEta = -1.0, float maxEta = 1.0, float maxFITtime = 4, float minRgtrwTOF = 0., - std::vector FITAmpLimits = {0., 0., 0., 0., 0.}) : mNDtcoll{ndtcoll}, mMinNBCs{nMinBCs}, mWithFwdTracks{withFwdTracks}, mGlobalTracksOnly{globalTracksOnly}, mITSOnlyTracks{ITSonlyTracks}, mMinNTracks{MinNTracks}, mMaxNTracks{MaxNTracks}, mPidHypo{pidHypo}, mMinVertexPosz{MinPosz}, mMaxVertexPosz{MaxPosz}, mMinPt{minPt}, mMaxPt{maxPt}, mMinEta{minEta}, mMaxEta{maxEta}, mMaxFITtime{maxFITtime}, mMinRgtrwTOF{minRgtrwTOF}, mFITAmpLimits{FITAmpLimits} + std::vector FITAmpLimits = {0., 0., 0., 0., 0.}) : mNDtcoll{ndtcoll}, mMinNBCs{nMinBCs}, mWithFwdTracks{withFwdTracks}, mGlobalTracksOnly{globalTracksOnly}, mITSOnlyTracks{ITSonlyTracks}, mMinNTracks{MinNTracks}, mMaxNTracks{MaxNTracks}, mPidHypo{pidHypo}, mMinVertexPosz{MinPosz}, mMaxVertexPosz{MaxPosz}, mMinPt{minPt}, mMaxPt{maxPt}, mMinEta{minEta}, mMaxEta{maxEta}, mMaxFITtime{maxFITtime}, mMinRgtrwTOF{minRgtrwTOF}, mFITAmpLimits{std::move(FITAmpLimits)} { } diff --git a/PWGUD/Core/UDFSParser.cxx b/PWGUD/Core/UDFSParser.cxx index 961412106c8..5ce038fe3de 100644 --- a/PWGUD/Core/UDFSParser.cxx +++ b/PWGUD/Core/UDFSParser.cxx @@ -138,8 +138,8 @@ bool UDFSParser::isNumber(std::string s) } // ----------------------------------------------------------------------------- -std::string UDFSParser::trim(std::string str, - std::string whitespace = " \t") +std::string UDFSParser::trim(const std::string& str, + const std::string& whitespace = " \t") { const auto strBegin = str.find_first_not_of(whitespace); if (strBegin == std::string::npos) diff --git a/PWGUD/Core/UDFSParser.h b/PWGUD/Core/UDFSParser.h index a48fb9f8a4f..1e73957243f 100644 --- a/PWGUD/Core/UDFSParser.h +++ b/PWGUD/Core/UDFSParser.h @@ -60,7 +60,7 @@ class UDFSParser // helper functions for string parsing bool isNumber(std::string s); - std::string trim(std::string str, std::string whitespace); + std::string trim(const std::string& str, const std::string& whitespace); std::vector tokenize(std::string& str, std::string separator = ","); bool isInVector(int num, std::vector vec); diff --git a/PWGUD/Core/UDGoodRunSelector.cxx b/PWGUD/Core/UDGoodRunSelector.cxx index c8203a7a569..0eb377379a3 100644 --- a/PWGUD/Core/UDGoodRunSelector.cxx +++ b/PWGUD/Core/UDGoodRunSelector.cxx @@ -69,7 +69,7 @@ bool UDGoodRunSelector::isGoodRun(int runNumber) } } -std::vector UDGoodRunSelector::goodRuns(std::string runPeriod) +std::vector UDGoodRunSelector::goodRuns(const std::string& runPeriod) { auto it = mrunMap.find(runPeriod.c_str()); if (it != mrunMap.end()) { diff --git a/PWGUD/Core/UDGoodRunSelector.h b/PWGUD/Core/UDGoodRunSelector.h index 1b73f2c3ac4..31cce6f22fd 100644 --- a/PWGUD/Core/UDGoodRunSelector.h +++ b/PWGUD/Core/UDGoodRunSelector.h @@ -33,7 +33,7 @@ struct UDGoodRunSelector { void Print(); bool isGoodRun(int runNumber); std::vector goodRuns() { return mgoodRuns; } - std::vector goodRuns(std::string runPeriod); + std::vector goodRuns(const std::string& runPeriod); int rnumMin() { return mrnMin; } int rnumMax() { return mrnMax; } diff --git a/PWGUD/Core/UDHelpers.h b/PWGUD/Core/UDHelpers.h index a970d82ce27..d014047bcc9 100644 --- a/PWGUD/Core/UDHelpers.h +++ b/PWGUD/Core/UDHelpers.h @@ -243,7 +243,7 @@ T MCcompatibleBCs(F const& collision, int const& ndt, T const& bcs, int const& n // function to check if track provides good PID information // Checks the nSigma for any particle assumption to be within limits. template -bool hasGoodPID(DGCutparHolder diffCuts, TC track) +bool hasGoodPID(const DGCutparHolder& diffCuts, TC track) { // El, Mu, Pi, Ka, and Pr are considered // at least one nSigma must be within set limits @@ -891,7 +891,7 @@ bool cleanCalo(T const& bc, o2::aod::Calos& calos, std::vector& /*lims*/, // ----------------------------------------------------------------------------- // check if all tracks come from same MCCollision template -int64_t sameMCCollision(T tracks, o2::aod::McCollisions, o2::aod::McParticles) +int64_t sameMCCollision(T tracks, const o2::aod::McCollisions&, const o2::aod::McParticles&) { int64_t colID = -1; for (auto const& track : tracks) { diff --git a/PWGUD/Core/UPCJpsiCentralBarrelCorrHelper.h b/PWGUD/Core/UPCJpsiCentralBarrelCorrHelper.h index 83a3eed9053..4404fc0dee2 100644 --- a/PWGUD/Core/UPCJpsiCentralBarrelCorrHelper.h +++ b/PWGUD/Core/UPCJpsiCentralBarrelCorrHelper.h @@ -213,7 +213,7 @@ float* correlation(TLorentzVector* lv1, TLorentzVector* lv2, TLorentzVector* lv) return q; } -double DeltaPhi(TLorentzVector lv1, TLorentzVector lv2) +double DeltaPhi(const TLorentzVector& lv1, const TLorentzVector& lv2) { TLorentzVector lv_sum = lv1 + lv2; TLorentzVector lv_diff = lv1 - lv2; @@ -223,7 +223,7 @@ double DeltaPhi(TLorentzVector lv1, TLorentzVector lv2) return dp; } -double DeltaPhiRandom(TLorentzVector lv1, TLorentzVector lv2) +double DeltaPhiRandom(const TLorentzVector& lv1, const TLorentzVector& lv2) { std::vector indices = {0, 1}; unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); diff --git a/PWGUD/Core/UPCTauCentralBarrelHelperRL.h b/PWGUD/Core/UPCTauCentralBarrelHelperRL.h index ea4652b9b77..9bdaab354e2 100644 --- a/PWGUD/Core/UPCTauCentralBarrelHelperRL.h +++ b/PWGUD/Core/UPCTauCentralBarrelHelperRL.h @@ -52,19 +52,19 @@ enum MyTauChannel { CH_ENUM_COUNTER = 11 }; -void printLargeMessage(std::string info) +void printLargeMessage(const std::string& info) // Helper to printf info message to terminal { LOGF(info, "################################### %s ###################################", info); } -void printMediumMessage(std::string info) +void printMediumMessage(const std::string& info) // Helper to printf info message to terminal { LOGF(info, "+++++++++++++ %s +++++++++++++", info); } -void printDebugMessage(std::string info) +void printDebugMessage(const std::string& info) // Helper to printf info message to terminal { LOGF(debug, "X!X!X!X!X!X!X!X!X %s X!X!X!X!X!X!X!X!X", info); diff --git a/PWGUD/Core/decayTree.cxx b/PWGUD/Core/decayTree.cxx index a96156c0f9c..880942d3285 100644 --- a/PWGUD/Core/decayTree.cxx +++ b/PWGUD/Core/decayTree.cxx @@ -93,7 +93,7 @@ void pidSelector::Print() // angleCut angleCut::angleCut(std::pair rnames, double angleMin, double angleMax) { - fRnames = rnames; + fRnames = std::move(rnames); fAngleMin = angleMin; fAngleMax = angleMax; } @@ -982,7 +982,7 @@ void decayTree::Print() } } -resonance* decayTree::getResonance(std::string name) +resonance* decayTree::getResonance(const std::string& name) { for (const auto& res : fResonances) { if (res->name() == name) { diff --git a/PWGUD/Core/decayTree.h b/PWGUD/Core/decayTree.h index 05cd97968c0..01dae97e12d 100644 --- a/PWGUD/Core/decayTree.h +++ b/PWGUD/Core/decayTree.h @@ -192,9 +192,9 @@ class reconstructedParticle public: // constructor/destructor reconstructedParticle() {} - explicit reconstructedParticle(std::string name, TLorentzVector ivm, std::vector& comb) + explicit reconstructedParticle(std::string name, const TLorentzVector& ivm, std::vector& comb) { - fName = name; + fName = std::move(name); fIVM = ivm; fComb = comb; }; @@ -219,7 +219,7 @@ class reconstructedEvent reconstructedEvent() {} explicit reconstructedEvent(recResType recs, int chargeState, std::vector& comb) { - fRecs = recs; + fRecs = std::move(recs); fComb = comb; fChargeState = chargeState; }; @@ -250,7 +250,7 @@ class resonance void setisFinal() { fisFinal = true; } void setCounter(int counter) { fCounter = counter; } - void setName(std::string name) { fName = name; } + void setName(std::string name) { fName = std::move(name); } void setStatus(int status) { fStatus = status; } void setPID(int pid) { fPID = pid; } void setPIDFun(int pidfun) { fPIDfun = pidfun; } @@ -259,9 +259,9 @@ class resonance fdetectorHits = std::vector{its, tpc, trd, tof}; } void clearParents() { fParents.clear(); } - void addParent(std::string parent) { fParents.push_back(parent); } + void addParent(const std::string& parent) { fParents.push_back(parent); } void setDaughters(std::vector& daughters) { fDaughters = daughters; } - void setIVM(TLorentzVector ivm) + void setIVM(const TLorentzVector& ivm) { fIVM = ivm; fStatus = 1; @@ -299,8 +299,8 @@ class resonance fdcaxyMax = dcaxymax; fdcazMax = dcazmax; } - void setPIDSelector(pidSelector pidcuts) { fpidSelector = pidcuts; } - void setAngleCuts(std::vector anglecuts) { fangleCuts = anglecuts; } + void setPIDSelector(const pidSelector& pidcuts) { fpidSelector = pidcuts; } + void setAngleCuts(std::vector anglecuts) { fangleCuts = std::move(anglecuts); } // histograms void setMassHistAxis(int nbins, double binmin, double binmax) @@ -477,7 +477,7 @@ class decayTree // getters int nFinals() { return fnFinals; } std::vector getResonances() { return fResonances; } - resonance* getResonance(std::string name); + resonance* getResonance(const std::string& name); resonance* getFinal(int counter); std::vector getFinals(resonance* res); std::vector ntrackRange() { return std::vector{fnTracksMin, fnTracksMax}; } diff --git a/PWGUD/DataModel/TauThreeProngEventTables.h b/PWGUD/DataModel/TauThreeProngEventTables.h index ba4e270c941..ca00bd0be6f 100644 --- a/PWGUD/DataModel/TauThreeProngEventTables.h +++ b/PWGUD/DataModel/TauThreeProngEventTables.h @@ -41,14 +41,17 @@ DECLARE_SOA_COLUMN(PosZ, posZ, float); DECLARE_SOA_COLUMN(FlagUPC, flagUPC, int8_t); DECLARE_SOA_COLUMN(OccupancyInTime, occupancyInTime, int); DECLARE_SOA_COLUMN(HadronicRate, hadronicRate, double); -DECLARE_SOA_COLUMN(Trs, trs, int8_t); -DECLARE_SOA_COLUMN(Trofs, trofs, int8_t); -DECLARE_SOA_COLUMN(Hmpr, hmpr, int8_t); -DECLARE_SOA_COLUMN(Tfb, tfb, int8_t); -DECLARE_SOA_COLUMN(ItsRofb, itsRofb, int8_t); -DECLARE_SOA_COLUMN(Sbp, sbp, int8_t); -DECLARE_SOA_COLUMN(ZvtxFT0vsPv, zvtxFT0vsPv, int8_t); -DECLARE_SOA_COLUMN(VtxITSTPC, vtxITSTPC, int8_t); + +// DECLARE_SOA_COLUMN(Trs, trs, int8_t); +// DECLARE_SOA_COLUMN(Trofs, trofs, int8_t); +// DECLARE_SOA_COLUMN(Hmpr, hmpr, int8_t); +// DECLARE_SOA_COLUMN(Tfb, tfb, int8_t); +// DECLARE_SOA_COLUMN(ItsRofb, itsRofb, int8_t); +// DECLARE_SOA_COLUMN(Sbp, sbp, int8_t); +// DECLARE_SOA_COLUMN(ZvtxFT0vsPv, zvtxFT0vsPv, int8_t); +// DECLARE_SOA_COLUMN(VtxITSTPC, vtxITSTPC, int8_t); +DECLARE_SOA_COLUMN(BcSelBits, bcSelBits, uint8_t); + DECLARE_SOA_COLUMN(ZdcAenergy, zdcAenergy, float); DECLARE_SOA_COLUMN(ZdcCenergy, zdcCenergy, float); DECLARE_SOA_COLUMN(ZdcAtime, zdcAtime, float); @@ -121,10 +124,10 @@ DECLARE_SOA_COLUMN(TrueChannel, trueChannel, int); // DECLARE_SOA_COLUMN(TruePosX, truePosX, float); // DECLARE_SOA_COLUMN(TruePosY, truePosY, float); DECLARE_SOA_COLUMN(TruePosZ, truePosZ, float); -// truth tau particles // index 0: tau+ // index 1: tau - -DECLARE_SOA_COLUMN(TrueTauPx, trueTauPx, float[2]); -DECLARE_SOA_COLUMN(TrueTauPy, trueTauPy, float[2]); -DECLARE_SOA_COLUMN(TrueTauPz, trueTauPz, float[2]); +// // truth tau particles // index 0: tau+ // index 1: tau - +// DECLARE_SOA_COLUMN(TrueTauPx, trueTauPx, float[2]); +// DECLARE_SOA_COLUMN(TrueTauPy, trueTauPy, float[2]); +// DECLARE_SOA_COLUMN(TrueTauPz, trueTauPz, float[2]); // truth tau daughter particles - 4 particles DECLARE_SOA_COLUMN(TrueDaugPx, trueDaugPx, float[4]); DECLARE_SOA_COLUMN(TrueDaugPy, trueDaugPy, float[4]); @@ -136,6 +139,7 @@ DECLARE_SOA_COLUMN(True6DaugPy, true6DaugPy, float[6]); DECLARE_SOA_COLUMN(True6DaugPz, true6DaugPz, float[6]); DECLARE_SOA_COLUMN(True6DaugPdgCode, true6DaugPdgCode, int[6]); DECLARE_SOA_COLUMN(Problem, problem, int8_t); +DECLARE_SOA_COLUMN(IsRec, isRec, int8_t); } // namespace tautree DECLARE_SOA_TABLE(DataTauFourTracks, "AOD", "TAUFOURTRACK", @@ -146,8 +150,10 @@ DECLARE_SOA_TABLE(DataTauFourTracks, "AOD", "TAUFOURTRACK", tautree::PosZ, tautree::FlagUPC, tautree::OccupancyInTime, tautree::HadronicRate, // - tautree::Trs, tautree::Trofs, tautree::Hmpr, - tautree::Tfb, tautree::ItsRofb, tautree::Sbp, tautree::ZvtxFT0vsPv, tautree::VtxITSTPC, + tautree::BcSelBits, + // tautree::Trs, tautree::Trofs, tautree::Hmpr, + // tautree::Tfb, tautree::ItsRofb, tautree::Sbp, tautree::ZvtxFT0vsPv, tautree::VtxITSTPC, + // tautree::ZdcAenergy, tautree::ZdcCenergy, tautree::ZdcAtime, tautree::ZdcCtime, // tautree::Qtot, @@ -169,10 +175,14 @@ DECLARE_SOA_TABLE(TrueTauFourTracks, "AOD", "TRUETAU", // tautree::PosX, tautree::PosY, tautree::PosZ, tautree::FlagUPC, tautree::OccupancyInTime, tautree::HadronicRate, - tautree::Trs, tautree::Trofs, tautree::Hmpr, - tautree::Tfb, tautree::ItsRofb, tautree::Sbp, tautree::ZvtxFT0vsPv, tautree::VtxITSTPC, - tautree::ZdcAenergy, tautree::ZdcCenergy, - tautree::ZdcAtime, tautree::ZdcCtime, + // + tautree::BcSelBits, + // tautree::Trs, tautree::Trofs, tautree::Hmpr, + // tautree::Tfb, tautree::ItsRofb, tautree::Sbp, tautree::ZvtxFT0vsPv, tautree::VtxITSTPC, + // + // zdc information do not exist in MC + // tautree::ZdcAenergy, tautree::ZdcCenergy, + // tautree::ZdcAtime, tautree::ZdcCtime, // tautree::Qtot, tautree::TotalFT0AmplitudeA, tautree::TotalFT0AmplitudeC, tautree::TotalFV0AmplitudeA, // tautree::TimeFT0A, tautree::TimeFT0C, tautree::TimeFV0A, @@ -187,11 +197,20 @@ DECLARE_SOA_TABLE(TrueTauFourTracks, "AOD", "TRUETAU", tautree::TrueChannel, // tautree::TrueHasRecoColl, tautree::TruePosZ, - tautree::TrueTauPx, tautree::TrueTauPy, tautree::TrueTauPz, + // tautree::TrueTauPx, tautree::TrueTauPy, tautree::TrueTauPz, tautree::TrueDaugPx, tautree::TrueDaugPy, tautree::TrueDaugPz, tautree::TrueDaugPdgCode, tautree::Problem); +DECLARE_SOA_TABLE(GenTauFourTracks, "AOD", "GENTAU", + tautree::TrueChannel, + tautree::TruePosZ, + // tautree::TrueTauPx, tautree::TrueTauPy, tautree::TrueTauPz, + tautree::TrueDaugPx, tautree::TrueDaugPy, tautree::TrueDaugPz, + tautree::TrueDaugPdgCode, + tautree::Problem, + tautree::IsRec); + DECLARE_SOA_TABLE(DataTauSixTracks, "AOD", "TAUSIXTRACK", tautree::RunNumber, tautree::Bc, tautree::TotalTracks, tautree::NumContrib, tautree::RctOk, @@ -200,8 +219,10 @@ DECLARE_SOA_TABLE(DataTauSixTracks, "AOD", "TAUSIXTRACK", tautree::PosZ, tautree::FlagUPC, tautree::OccupancyInTime, tautree::HadronicRate, // - tautree::Trs, tautree::Trofs, tautree::Hmpr, - tautree::Tfb, tautree::ItsRofb, tautree::Sbp, tautree::ZvtxFT0vsPv, tautree::VtxITSTPC, + tautree::BcSelBits, + // tautree::Trs, tautree::Trofs, tautree::Hmpr, + // tautree::Tfb, tautree::ItsRofb, tautree::Sbp, tautree::ZvtxFT0vsPv, tautree::VtxITSTPC, + // tautree::ZdcAenergy, tautree::ZdcCenergy, tautree::ZdcAtime, tautree::ZdcCtime, // tautree::Qtot, @@ -223,10 +244,14 @@ DECLARE_SOA_TABLE(TrueTauSixTracks, "AOD", "TRUETAUSIX", // tautree::PosX, tautree::PosY, tautree::PosZ, tautree::FlagUPC, tautree::OccupancyInTime, tautree::HadronicRate, - tautree::Trs, tautree::Trofs, tautree::Hmpr, - tautree::Tfb, tautree::ItsRofb, tautree::Sbp, tautree::ZvtxFT0vsPv, tautree::VtxITSTPC, - tautree::ZdcAenergy, tautree::ZdcCenergy, - tautree::ZdcAtime, tautree::ZdcCtime, + // + tautree::BcSelBits, + // tautree::Trs, tautree::Trofs, tautree::Hmpr, + // tautree::Tfb, tautree::ItsRofb, tautree::Sbp, tautree::ZvtxFT0vsPv, tautree::VtxITSTPC, + // + // ZDC information do not exist in MC + // tautree::ZdcAenergy, tautree::ZdcCenergy, + // tautree::ZdcAtime, tautree::ZdcCtime, // tautree::Qtot, tautree::TotalFT0AmplitudeA, tautree::TotalFT0AmplitudeC, tautree::TotalFV0AmplitudeA, // tautree::TimeFT0A, tautree::TimeFT0C, tautree::TimeFV0A, @@ -241,11 +266,20 @@ DECLARE_SOA_TABLE(TrueTauSixTracks, "AOD", "TRUETAUSIX", tautree::TrueChannel, // tautree::TrueHasRecoColl, tautree::TruePosZ, - tautree::TrueTauPx, tautree::TrueTauPy, tautree::TrueTauPz, + // tautree::TrueTauPx, tautree::TrueTauPy, tautree::TrueTauPz, tautree::True6DaugPx, tautree::True6DaugPy, tautree::True6DaugPz, tautree::True6DaugPdgCode, tautree::Problem); +DECLARE_SOA_TABLE(GenTauSixTracks, "AOD", "GENTAUSIX", + tautree::TrueChannel, + tautree::TruePosZ, + // tautree::TrueTauPx, tautree::TrueTauPy, tautree::TrueTauPz, + tautree::True6DaugPx, tautree::True6DaugPy, tautree::True6DaugPz, + tautree::True6DaugPdgCode, + tautree::Problem, + tautree::IsRec); + } // namespace o2::aod #endif // PWGUD_DATAMODEL_TAUTHREEPRONGEVENTTABLES_H_ diff --git a/PWGUD/TableProducer/CMakeLists.txt b/PWGUD/TableProducer/CMakeLists.txt index a69671ab068..ecc22560552 100644 --- a/PWGUD/TableProducer/CMakeLists.txt +++ b/PWGUD/TableProducer/CMakeLists.txt @@ -16,17 +16,17 @@ o2physics_add_dpl_workflow(dg-cand-producer PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGCutparHolder O2Physics::AnalysisCCDB O2Physics::EventFilteringUtils COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(sgcand-producer +o2physics_add_dpl_workflow(sgcand-producer # o2-linter: disable=name/o2-workflow (Keep historical workflow name for backward compatibility) SOURCES SGCandProducer.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::SGCutParHolder O2Physics::AnalysisCCDB O2Physics::FITCutParHolder COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(dgbccand-producer +o2physics_add_dpl_workflow(dgbccand-producer # o2-linter: disable=name/o2-workflow (Keep historical workflow name for backward compatibility) SOURCES DGBCCandProducer.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::DGCutparHolder COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(upccand-producer +o2physics_add_dpl_workflow(upccand-producer # o2-linter: disable=name/o2-workflow (Keep historical workflow name for backward compatibility) SOURCES UPCCandidateProducer.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::UPCCutparHolder COMPONENT_NAME Analysis) @@ -46,12 +46,12 @@ o2physics_add_dpl_workflow(fwd-track-propagation PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::GlobalTracking COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(udmcparticles-to-udtracks +o2physics_add_dpl_workflow(udmcparticles-to-udtracks # o2-linter: disable=name/o2-workflow (Keep historical workflow name for backward compatibility) SOURCES udMcParticles2udTracks.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) -o2physics_add_dpl_workflow(udmccollisions-to-udcollisions +o2physics_add_dpl_workflow(udmccollisions-to-udcollisions # o2-linter: disable=name/o2-workflow (Keep historical workflow name for backward compatibility) SOURCES udMcCollisions2udCollisions.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore COMPONENT_NAME Analysis) @@ -80,3 +80,8 @@ o2physics_add_dpl_workflow(upc-cand-producer-semi-fwd SOURCES upcCandProducerSemiFwd.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::UPCCutparHolder O2::GlobalTracking COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(upc-cand-producer-barrel + SOURCES upcCandProducerBarrel.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::CCDB O2::DataFormatsParameters O2Physics::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/PWGUD/TableProducer/SGCandProducer.cxx b/PWGUD/TableProducer/SGCandProducer.cxx index a45493d792e..8bc472c455f 100644 --- a/PWGUD/TableProducer/SGCandProducer.cxx +++ b/PWGUD/TableProducer/SGCandProducer.cxx @@ -224,7 +224,7 @@ struct SGCandProducer { // function to process reconstructed data template - void processReco(std::string histdir, TCol const& collision, BCs const& bcs, + void processReco(const std::string& histdir, TCol const& collision, BCs const& bcs, TCs const& tracks, FWs const& fwdtracks, aod::FV0As const& fv0as, aod::FT0s const& ft0s, aod::FDDs const& fdds) { diff --git a/PWGUD/TableProducer/UPCCandidateProducer.cxx b/PWGUD/TableProducer/UPCCandidateProducer.cxx index c2606e52f3c..f59c92ca55c 100644 --- a/PWGUD/TableProducer/UPCCandidateProducer.cxx +++ b/PWGUD/TableProducer/UPCCandidateProducer.cxx @@ -655,7 +655,7 @@ struct UpcCandProducer { } template - int64_t getAmbTrackId(TAmbTrack ambTrack) + int64_t getAmbTrackId(const TAmbTrack& ambTrack) { int64_t trkId = -1; if constexpr (tracksSwitch == 0) { // central barrel @@ -671,7 +671,7 @@ struct UpcCandProducer { template void collectAmbTrackBCs(std::unordered_map& ambTrIds, TBCs const& bcs, - TAmbTracks ambTracks) + const TAmbTracks& ambTracks) { for (const auto& ambTrk : ambTracks) { auto trkId = getAmbTrackId(ambTrk); diff --git a/PWGUD/TableProducer/dgCandProducer.cxx b/PWGUD/TableProducer/dgCandProducer.cxx index 6c075229fb1..97a3c423c3e 100644 --- a/PWGUD/TableProducer/dgCandProducer.cxx +++ b/PWGUD/TableProducer/dgCandProducer.cxx @@ -190,7 +190,7 @@ struct DgCandProducer { outputTracksLabel(track.globalIndex()); } - void createHistograms(std::string histdir) + void createHistograms(const std::string& histdir) { const int nXbinsInStatH = 26; std::string labels[nXbinsInStatH] = { @@ -237,7 +237,7 @@ struct DgCandProducer { } template - void fillFIThistograms(TBC const& bc, std::string histdir) + void fillFIThistograms(TBC const& bc, const std::string& histdir) { LOGF(debug, ""); std::array triggers{{true, !udhelpers::cleanFIT(bc, diffCuts.maxFITtime(), diffCuts.FITAmpLimits()), @@ -295,7 +295,7 @@ struct DgCandProducer { } template - void processReco(std::string histdir, TCol const& collision, BCs const& bcs, + void processReco(const std::string& histdir, TCol const& collision, BCs const& bcs, TCs const& tracks, FWs const& fwdtracks, aod::FV0As const& fv0as, aod::FT0s const& ft0s, aod::FDDs const& fdds) { diff --git a/PWGUD/TableProducer/fwdTrackPropagation.cxx b/PWGUD/TableProducer/fwdTrackPropagation.cxx index 655e78535a1..54ae7a43e8d 100644 --- a/PWGUD/TableProducer/fwdTrackPropagation.cxx +++ b/PWGUD/TableProducer/fwdTrackPropagation.cxx @@ -154,7 +154,7 @@ struct FwdTrackPropagation { // debug // LOGP(info, "track {}, before: {} {} {} {} {} {}", t.globalIndex(), t.x(), t.y(), t.z(), t.phi(), t.tgl(), t.signed1Pt()); // LOGP(info, "track {}, after: {} {} {} {} {} {}", t.globalIndex(), pft.getX(), pft.getY(), pft.getZ(), pft.getPhi(), pft.getTgl(), pft.getInvQPt()); - SMatrix55 cov = pft.getCovariances(); + const SMatrix55& cov = pft.getCovariances(); float sigX = std::sqrt(cov(0, 0)); float sigY = std::sqrt(cov(1, 1)); float sigPhi = std::sqrt(cov(2, 2)); diff --git a/PWGUD/TableProducer/tauEventTableProducer.cxx b/PWGUD/TableProducer/tauEventTableProducer.cxx index d91c5dffe8d..2538415540f 100644 --- a/PWGUD/TableProducer/tauEventTableProducer.cxx +++ b/PWGUD/TableProducer/tauEventTableProducer.cxx @@ -213,7 +213,7 @@ struct TauEventTableProducer { std::vector>> cutMyRequiredITSHits{}; - void mySetRequireHitsInITSLayers(int8_t minNRequiredHits, std::set requiredLayers) + void mySetRequireHitsInITSLayers(int8_t minNRequiredHits, const std::set& requiredLayers) { // layer 0 corresponds to the the innermost ITS layer cutMyRequiredITSHits.push_back(std::make_pair(minNRequiredHits, requiredLayers)); diff --git a/PWGUD/TableProducer/tauThreeProngEventTableProducer.cxx b/PWGUD/TableProducer/tauThreeProngEventTableProducer.cxx index 71a250ec375..e0967520da8 100644 --- a/PWGUD/TableProducer/tauThreeProngEventTableProducer.cxx +++ b/PWGUD/TableProducer/tauThreeProngEventTableProducer.cxx @@ -10,7 +10,7 @@ // or submit itself to any jurisdiction. // /// \file tauThreeProngEventTableProducer.cxx -/// \brief Produces derived table from UD tables for tau pair production (3 prong) +/// \brief Produces derived table from UD tables for tau pair production (with 3 prongs) /// /// \author Adam Matyja , IFJ PAN, Cracow /// \since 2025-09-06 @@ -82,9 +82,11 @@ struct TauThreeProngEventTableProducer { // derived output for 4 track topology Produces trueTauFourTracks; Produces dataTauFourTracks; + Produces genTauFourTracks; // derived output for 6 track topology Produces trueTauSixTracks; Produces dataTauSixTracks; + Produces genTauSixTracks; // Global varialbes // Service pdg; @@ -260,16 +262,21 @@ struct TauThreeProngEventTableProducer { registrySkim.add("skim/nTof", ";N_{TOFtrk};events", {HistType::kTH1F, {{10, -1., 9.}}}); } if (doprocessMonteCarlo) { - registrySkim.add("skim/efficiencyMC", ";efficeincy;events", {HistType::kTH1D, {{10, 0., 10.}}}); + registrySkim.add("skim/efficiencyMC", ";efficiency;events", {HistType::kTH1D, {{15, 0., 15.}}}); registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(1, "1: All"); registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(2, "2: N^{#tau}=2"); registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(3, "3: |y^{#tau}| <= 0.9"); - registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(4, "4: 4 or 6 trk"); - registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(5, "5: 4 trk"); - registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(6, "6: 6 trk"); - registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(7, "7: |#eta^{ch}|<0.9"); - registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(8, "8: 7+4 trk"); - registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(9, "9: 7+6 trk"); + registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(4, "4: |#eta^{ch}|<0.9"); + registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(5, "5: 4 or 6 trk"); + registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(6, "e+3#pi"); + registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(7, "#mu+3#pi"); + registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(8, "#pi+3#pi"); + registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(9, "6#pi"); + registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(10, "rec"); + registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(11, "rec e+3#pi"); + registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(12, "rec #mu+3#pi"); + registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(13, "rec #pi+3#pi"); + registrySkim.get(HIST("skim/efficiencyMC"))->GetXaxis()->SetBinLabel(14, "rec 6#pi"); registrySkim.add("skim/problemMC", ";problem;events", {HistType::kTH1D, {{10, 0., 10.}}}); @@ -280,11 +287,52 @@ struct TauThreeProngEventTableProducer { registrySkim.add("skim/tauPtMC", ";p_{T}^{#tau};events", {HistType::kTH1F, {{100, 0, 5.}}}); registrySkim.add("skim/tauDeltaEtaMC", ";#Delta#eta^{#tau};events ", {HistType::kTH1F, {{100, -5., 5.}}}); registrySkim.add("skim/tauDeltaPhiMC", ";#Delta#phi^{#tau}(deg.);events", {HistType::kTH1F, {{100, 131., 181}}}); + registrySkim.add("skim/ditauInvMassMC", ";M_{inv}^{#tau#tau}(GeV/#it{c}^{2});events", {HistType::kTH1F, {{100, 3.4, 13.4}}}); registrySkim.add("skim/nChPartMC", ";N^{ch. part};events", {HistType::kTH1F, {{10, 0, 10.}}}); registrySkim.add("skim/daughterPhiMC", ";#phi^{daughter};events", {HistType::kTH1F, {{100, 0, 6.4}}}); registrySkim.add("skim/daughterEtaMC", ";#eta^{daughter};events", {HistType::kTH1F, {{100, -4., 4.}}}); registrySkim.add("skim/daughterPtMC", ";p_{T}^{daughter};events", {HistType::kTH1F, {{100, 0, 5.0}}}); } + if (doprocessGenerated) { + registrySkim.add("gen/efficiencyMC", ";efficiency;events", {HistType::kTH1D, {{15, 0., 15.}}}); + registrySkim.get(HIST("gen/efficiencyMC"))->GetXaxis()->SetBinLabel(1, "All"); + registrySkim.get(HIST("gen/efficiencyMC"))->GetXaxis()->SetBinLabel(2, "N^{#tau}=2"); + registrySkim.get(HIST("gen/efficiencyMC"))->GetXaxis()->SetBinLabel(3, "|y^{#tau}| <=0.9"); + registrySkim.get(HIST("gen/efficiencyMC"))->GetXaxis()->SetBinLabel(4, "|#eta^{ch}|<=0.9"); + registrySkim.get(HIST("gen/efficiencyMC"))->GetXaxis()->SetBinLabel(5, "4 or 6 trk"); + // registrySkim.get(HIST("gen/efficiencyMC"))->GetXaxis()->SetBinLabel(6, "6: 4 trk"); + // registrySkim.get(HIST("gen/efficiencyMC"))->GetXaxis()->SetBinLabel(7, "7: 6 trk"); + registrySkim.get(HIST("gen/efficiencyMC"))->GetXaxis()->SetBinLabel(6, "e+3#pi"); + registrySkim.get(HIST("gen/efficiencyMC"))->GetXaxis()->SetBinLabel(7, "#mu+3#pi"); + registrySkim.get(HIST("gen/efficiencyMC"))->GetXaxis()->SetBinLabel(8, "#pi+3#pi"); + registrySkim.get(HIST("gen/efficiencyMC"))->GetXaxis()->SetBinLabel(9, "6#pi"); + registrySkim.get(HIST("gen/efficiencyMC"))->GetXaxis()->SetBinLabel(10, "rec"); + registrySkim.get(HIST("gen/efficiencyMC"))->GetXaxis()->SetBinLabel(11, "rec e+3#pi"); + registrySkim.get(HIST("gen/efficiencyMC"))->GetXaxis()->SetBinLabel(12, "rec #mu+3#pi"); + registrySkim.get(HIST("gen/efficiencyMC"))->GetXaxis()->SetBinLabel(13, "rec #pi+3#pi"); + registrySkim.get(HIST("gen/efficiencyMC"))->GetXaxis()->SetBinLabel(14, "rec 6#pi"); + + registrySkim.add("gen/problemMC", ";problem;events", {HistType::kTH1D, {{10, 0., 10.}}}); + registrySkim.get(HIST("gen/problemMC"))->GetXaxis()->SetBinLabel(1, "1: NoProblem"); + registrySkim.get(HIST("gen/problemMC"))->GetXaxis()->SetBinLabel(2, "2: Unused"); + registrySkim.get(HIST("gen/problemMC"))->GetXaxis()->SetBinLabel(3, "3: N^{trk}>6"); + registrySkim.get(HIST("gen/problemMC"))->GetXaxis()->SetBinLabel(4, "4: Unused"); + registrySkim.get(HIST("gen/problemMC"))->GetXaxis()->SetBinLabel(5, "5: Unused"); + registrySkim.get(HIST("gen/problemMC"))->GetXaxis()->SetBinLabel(6, "6: Unused"); + + registrySkim.add("gen/nTauMC", ";N_{#tau};events", {HistType::kTH1D, {{10, 0., 10.}}}); + registrySkim.add("gen/tauRapidityMC", ";y_{#tau};events", {HistType::kTH1F, {{100, -2.5, 2.5}}}); + registrySkim.add("gen/tauPhiMC", ";#phi^{#tau};events", {HistType::kTH1F, {{100, 0, 6.4}}}); + registrySkim.add("gen/tauEtaMC", ";#eta^{#tau};events", {HistType::kTH1F, {{100, -2.5, 2.5}}}); + registrySkim.add("gen/tauPtMC", ";p_{T}^{#tau};events", {HistType::kTH1F, {{100, 0, 5.}}}); + registrySkim.add("gen/tauDeltaEtaMC", ";#Delta#eta^{#tau};events ", {HistType::kTH1F, {{100, -5., 5.}}}); + registrySkim.add("gen/tauDeltaPhiMC", ";#Delta#phi^{#tau}(deg.);events", {HistType::kTH1F, {{100, 131., 181}}}); + registrySkim.add("gen/ditauInvMassMC", ";M_{inv}^{#tau#tau}(GeV/#it{c}^{2});events", {HistType::kTH1F, {{100, 3.4, 13.4}}}); + registrySkim.add("gen/nChPartMC", ";N^{ch. part};events", {HistType::kTH1F, {{10, 0, 10.}}}); + registrySkim.add("gen/daughterPhiMC", ";#phi^{daughter};events", {HistType::kTH1F, {{100, 0, 6.4}}}); + registrySkim.add("gen/daughterEtaMC", ";#eta^{daughter};events", {HistType::kTH1F, {{100, -4., 4.}}}); + registrySkim.add("gen/daughterPtMC", ";p_{T}^{daughter};events", {HistType::kTH1F, {{100, 0, 5.0}}}); + } // histos.add("Truth/hTroubles", "Counter of unwanted issues;;Number of troubles (-)", HistType::kTH1D, {{15, 0.5, 15.5}}); @@ -307,7 +355,7 @@ struct TauThreeProngEventTableProducer { return angle; } - float calculateDeltaPhi(ROOT::Math::LorentzVector> p, ROOT::Math::LorentzVector> p1) + float calculateDeltaPhi(const ROOT::Math::LorentzVector>& p, const ROOT::Math::LorentzVector>& p1) { // float delta = p.Phi(); float delta = RecoDecay::constrainAngle(p.Phi()); @@ -457,7 +505,7 @@ struct TauThreeProngEventTableProducer { // check ITS clusters, how many -1,0,1,7 + 10 if 0,1,2 layers were fired // analysis track quality check template - int numberOfItsClustersCheck(T track) + int numberOfItsClustersCheck(const T& track) { if (!track.hasITS()) return -1; @@ -557,7 +605,7 @@ struct TauThreeProngEventTableProducer { std::vector>> cutMyRequiredITSHits{}; - void mySetRequireHitsInITSLayers(int8_t minNRequiredHits, std::set requiredLayers) + void mySetRequireHitsInITSLayers(int8_t minNRequiredHits, const std::set& requiredLayers) { // layer 0 corresponds to the the innermost ITS layer cutMyRequiredITSHits.push_back(std::make_pair(minNRequiredHits, requiredLayers)); @@ -589,10 +637,9 @@ struct TauThreeProngEventTableProducer { constexpr uint8_t KBit = 1; for (const auto& kITSrequirement : cutMyRequiredITSHits) { auto hits = std::count_if(kITSrequirement.second.begin(), kITSrequirement.second.end(), [&](auto&& requiredLayer) { return itsClusterMap & (KBit << requiredLayer); }); - if ((kITSrequirement.first == -1) && (hits > 0)) { - return false; // no hits were required in specified layers - } else if (hits < kITSrequirement.first) { - return false; // not enough hits found in specified layers + if (((kITSrequirement.first == -1) && (hits > 0)) || // no hits were required in specified layers + (hits < kITSrequirement.first)) { // not enough hits found in specified layers + return false; } } return true; @@ -797,6 +844,26 @@ struct TauThreeProngEventTableProducer { int rct = 0; rct = isGoodRCTflag(dgcand); + // different events flags + int8_t bcSels[8] = {-99, -99, -99, -99, -99, -99, -99, -99}; + uint8_t bcSelBits = 0; + const int nBitsMax = 8; + bcSels[0] = dgcand.trs(); + bcSels[1] = dgcand.trofs(); + bcSels[2] = dgcand.hmpr(); + bcSels[3] = dgcand.tfb(); + bcSels[4] = dgcand.itsROFb(); + bcSels[5] = dgcand.sbp(); + bcSels[6] = dgcand.zVtxFT0vPV(); + bcSels[7] = dgcand.vtxITSTPC(); + + const int offset = 1; + bcSelBits = bcSels[0]; // initialization + for (int ibit = 1; ibit < nBitsMax; ibit++) { + bcSelBits = (bcSelBits << offset); // shift by 1 position towards left + bcSelBits += bcSels[ibit]; // add next bit to the pool + } + // // variables per track // @@ -879,9 +946,12 @@ struct TauThreeProngEventTableProducer { dgcand.posZ(), dgcand.flags(), dgcand.occupancyInTime(), - dgcand.hadronicRate(), // is it necessary - dgcand.trs(), dgcand.trofs(), dgcand.hmpr(), // to test it - dgcand.tfb(), dgcand.itsROFb(), dgcand.sbp(), dgcand.zVtxFT0vPV(), dgcand.vtxITSTPC(), + dgcand.hadronicRate(), // is it necessary + // + bcSelBits, + // dgcand.trs(), dgcand.trofs(), dgcand.hmpr(), // to test it + // dgcand.tfb(), dgcand.itsROFb(), dgcand.sbp(), dgcand.zVtxFT0vPV(), dgcand.vtxITSTPC(), + // energyZNA, energyZNC, timeZNA, timeZNC, // qtot, <<-------- comment out @@ -903,9 +973,12 @@ struct TauThreeProngEventTableProducer { dgcand.posZ(), dgcand.flags(), dgcand.occupancyInTime(), - dgcand.hadronicRate(), // is it necessary - dgcand.trs(), dgcand.trofs(), dgcand.hmpr(), // to test it - dgcand.tfb(), dgcand.itsROFb(), dgcand.sbp(), dgcand.zVtxFT0vPV(), dgcand.vtxITSTPC(), + dgcand.hadronicRate(), // is it necessary + // + bcSelBits, + // dgcand.trs(), dgcand.trofs(), dgcand.hmpr(), // to test it + // dgcand.tfb(), dgcand.itsROFb(), dgcand.sbp(), dgcand.zVtxFT0vPV(), dgcand.vtxITSTPC(), + // energyZNA, energyZNC, timeZNA, timeZNC, // qtot, <<-------- comment out @@ -1061,7 +1134,8 @@ struct TauThreeProngEventTableProducer { LOGF(info, " UDMcCollision size %d, Collisions size %d, UDtracks %d, UDMcParticles %d", mcCollisions.size(), collisions.size(), tracks.size(), mcParticles.size()); // temporary variables - float tmpRapidity = -999.; + // float tmpRapidity = -999.; + float trueTauRapidity[2] = {-999., -999.}; float trueTauEta[2] = {-999., -999.}; float trueTauPhi[2] = {-999., -999.}; @@ -1102,27 +1176,22 @@ struct TauThreeProngEventTableProducer { if (verbose) LOGF(info, "-- MC part pdg %d", particle.pdgCode()); if (std::abs(particle.pdgCode()) != kTauMinus) - continue; // 15 = tau_minus - // if (std::abs(particle.pdgCode()) != 15) continue; // 15 = tau_minus + continue; // 15 = tau_minus if (countMothers < desiredNMothers) { // < 2 // fill info for each tau trueTauX[countMothers] = particle.px(); trueTauY[countMothers] = particle.py(); trueTauZ[countMothers] = particle.pz(); - tmpRapidity = rapidity(particle.e(), trueTauZ[countMothers]); + trueTauRapidity[countMothers] = rapidity(particle.e(), trueTauZ[countMothers]); trueTauEta[countMothers] = RecoDecay::eta(std::array{particle.px(), particle.py(), particle.pz()}); trueTauPhi[countMothers] = RecoDecay::phi(particle.px(), particle.py()); if (verbose) - LOGF(info, "-- tau P(%f,%f,%f), e %f, y %f", particle.px(), particle.py(), particle.pz(), particle.e(), tmpRapidity); - registrySkim.get(HIST("skim/tauRapidityMC"))->Fill(tmpRapidity); - registrySkim.get(HIST("skim/tauPhiMC"))->Fill(trueTauPhi[countMothers]); - registrySkim.get(HIST("skim/tauEtaMC"))->Fill(trueTauEta[countMothers]); - registrySkim.get(HIST("skim/tauPtMC"))->Fill(RecoDecay::pt(particle.px(), particle.py())); - if (std::abs(tmpRapidity) > trkEtacut) { // 0.9 + LOGF(info, "-- tau P(%f,%f,%f), e %f, y %f", particle.px(), particle.py(), particle.pz(), particle.e(), trueTauRapidity[countMothers]); + if (std::abs(trueTauRapidity[countMothers]) > trkEtacut) { // 0.9 tauInRapidity = false; if (verbose) - LOGF(info, "--- tau y %f", tmpRapidity); + LOGF(info, "--- tau y %f", trueTauRapidity[countMothers]); } // rapidity check } // number of taus countMothers++; @@ -1137,6 +1206,15 @@ struct TauThreeProngEventTableProducer { registrySkim.get(HIST("skim/efficiencyMC"))->Fill(1., 1.); // exactly 2 taus + for (int iNmother = 0; iNmother < desiredNMothers; iNmother++) { + registrySkim.get(HIST("skim/tauRapidityMC"))->Fill(trueTauRapidity[iNmother]); + if (tauInRapidity) { + registrySkim.get(HIST("skim/tauPhiMC"))->Fill(trueTauPhi[iNmother]); + registrySkim.get(HIST("skim/tauEtaMC"))->Fill(trueTauEta[iNmother]); + registrySkim.get(HIST("skim/tauPtMC"))->Fill(RecoDecay::pt(trueTauX[iNmother], trueTauY[iNmother])); + } + } + if (!tauInRapidity) { // tau NOT in rapidity -> continue if (verbose) LOGF(info, "-- At least one mother particle (taus) out of rapidity (|y|<0.9). Jump to the next MC event."); @@ -1147,6 +1225,13 @@ struct TauThreeProngEventTableProducer { registrySkim.get(HIST("skim/tauDeltaEtaMC"))->Fill(trueTauEta[0] - trueTauEta[1]); registrySkim.get(HIST("skim/tauDeltaPhiMC"))->Fill(calculateDeltaPhi(trueTauPhi[0], trueTauPhi[1]) * 180. / o2::constants::math::PI); + // inv mass of two taus + ROOT::Math::LorentzVector> tau1; + ROOT::Math::LorentzVector> tau2; + tau1.SetXYZT(trueTauX[0], trueTauY[0], trueTauZ[0], RecoDecay::e(trueTauX[0], trueTauY[0], trueTauZ[0], MassTauPlus)); + tau2.SetXYZT(trueTauX[1], trueTauY[1], trueTauZ[1], RecoDecay::e(trueTauX[1], trueTauY[1], trueTauZ[1], MassTauPlus)); + registrySkim.get(HIST("skim/ditauInvMassMC"))->Fill((tau1 + tau2).M()); + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(2., 1.); // |y_tau| <= 0.9 countMothers = 0; int nChargedDaughtersTau[2] = {0, 0}; @@ -1187,40 +1272,36 @@ struct TauThreeProngEventTableProducer { break; } // end of loop over MC particles - registrySkim.get(HIST("skim/nChPartMC"))->Fill(nChargedDaughtersTau[0] + nChargedDaughtersTau[1]); // N charged particles from taus - // check number of charged particles in MC event - if ((nChargedDaughtersTau[0] + nChargedDaughtersTau[1] != fourTracks) && (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] != sixTracks)) { + if (!partFromTauInEta) { if (verbose) - LOGF(info, "-- Different from 4/6 charged particles (%d) from both taus. Jump to the next MC event.", nChargedDaughtersTau[0] + nChargedDaughtersTau[1]); + LOGF(info, "-- At least one daughter particle from taus out of pseudo-rapidity (|eta|<0.9). Jump to the next MC event."); continue; } - registrySkim.get(HIST("skim/efficiencyMC"))->Fill(3., 1.); // 1+3 (3+3) topology - if (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] == fourTracks) { // 4 - registrySkim.get(HIST("skim/efficiencyMC"))->Fill(4., 1.); - } else if (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] == sixTracks) { // 6 - registrySkim.get(HIST("skim/efficiencyMC"))->Fill(5., 1.); - } + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(3., 1.); // charged particles from tau in |eta|<0.9 - if (!partFromTauInEta) { + registrySkim.get(HIST("skim/nChPartMC"))->Fill(nChargedDaughtersTau[0] + nChargedDaughtersTau[1]); // N charged particles from taus + // check number of charged particles in MC event + if ((nChargedDaughtersTau[0] + nChargedDaughtersTau[1] != fourTracks) && (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] != sixTracks)) { if (verbose) - LOGF(info, "-- At least one daughter particle from taus out of pseudo-rapidity (|eta|<0.9). Jump to the next MC event."); + LOGF(info, "-- Different from 4/6 charged particles (%d) from both taus. Jump to the next MC event.", nChargedDaughtersTau[0] + nChargedDaughtersTau[1]); continue; } - registrySkim.get(HIST("skim/efficiencyMC"))->Fill(6., 1.); // particles from tau in |eta|<0.9 - if (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] == fourTracks) { // 4 - registrySkim.get(HIST("skim/efficiencyMC"))->Fill(7., 1.); - } else if (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] == sixTracks) { // 6 - registrySkim.get(HIST("skim/efficiencyMC"))->Fill(8., 1.); - } + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(4., 1.); // 1+3 (3+3) topology = 4 or 6 tracks + // if (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] == fourTracks) { // 4 + // registrySkim.get(HIST("skim/efficiencyMC"))->Fill(5., 1.); + // } else if (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] == sixTracks) { // 6 + // registrySkim.get(HIST("skim/efficiencyMC"))->Fill(6., 1.); + // } - if (nChargedDaughtersTau[0] == oneProng) // 1 + if ((nChargedDaughtersTau[0] == oneProng) || // 1 + (nChargedDaughtersTau[0] == threeProng && nChargedDaughtersTau[1] == threeProng)) // 3 and 3 zerothTau = 0; else if (nChargedDaughtersTau[1] == oneProng) // 1 zerothTau = 1; - else if (nChargedDaughtersTau[0] == threeProng && nChargedDaughtersTau[1] == threeProng) // 3 and 3 - zerothTau = 0; + // else if (nChargedDaughtersTau[0] == threeProng && nChargedDaughtersTau[1] == threeProng) // 3 and 3 + // zerothTau = 0; // prepare local variables for output table int32_t runNumber = -999; // when no reconstructed collisions is associated to MCcoll it should remain = -999 @@ -1236,11 +1317,13 @@ struct TauThreeProngEventTableProducer { int occupancy = -999; double hadronicRate = -999.; int8_t bcSels[8] = {-99, -99, -99, -99, -99, -99, -99, -99}; - // zdc information - there i sno information in MC - float energyZNA = -999.; - float energyZNC = -999.; - float timeZNA = -999.; - float timeZNC = -999.; + uint8_t bcSelBits = 0; + const int nBitsMax = 8; + // zdc information - there is no information in MC + // float energyZNA = -999.; + // float energyZNC = -999.; + // float timeZNA = -999.; + // float timeZNC = -999.; float amplitudesFIT[3] = {-999., -999., -999.}; // FT0A, FT0C, FV0 // float timesFIT[3] = {-999., -999., -999.}; // FT0A, FT0C, FV0 @@ -1283,7 +1366,7 @@ struct TauThreeProngEventTableProducer { float trueDaugY[6] = {-998., -998., -998., -998., -998., -998.}; float trueDaugZ[6] = {-998., -998., -998., -998., -998., -998.}; int trueDaugPdgCode[6] = {-999, -999, -999, -999, -999, -999}; - // bool problem = false; + MyRecoProblem problem = NO_PROBLEM; registrySkim.get(HIST("skim/problemMC"))->Fill(NO_PROBLEM); @@ -1293,14 +1376,19 @@ struct TauThreeProngEventTableProducer { // 3 = pi+3pi // 4 = 3pi+3pi - if (nElec == oneProng && nPi == threeProng) // 1 + 3 + if (nElec == oneProng && nPi == threeProng) { // 1 + 3 trueChannel = 1; - else if (nMuon == oneProng && nPi == threeProng) // 1 + 3 + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(5., 1.); + } else if (nMuon == oneProng && nPi == threeProng) { // 1 + 3 trueChannel = 2; - else if (nPi == fourTracks) // 4 + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(6., 1.); + } else if (nPi == fourTracks) { // 4 trueChannel = 3; - else if (nPi == sixTracks) // 6 + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(7., 1.); + } else if (nPi == sixTracks) { // 6 trueChannel = 4; + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(8., 1.); + } // LOGF(info, "MC Coll global index %d", mccoll.globalIndex()); // LOGF(info, "2. UDMcCollision size %d, Collisions size %d, UDtracks %d, UDMcParticles %d", mcCollisions.size(), collisions.size(), tracks.size(), mcParticles.size()); @@ -1316,6 +1404,18 @@ struct TauThreeProngEventTableProducer { if (collFromMcColls.size() > 0) { // get the truth and reco-level info if (verbose) LOGF(info, "--- MC Collision has reconstructed collision!"); + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(9., 1.); + // reconstruction in a given channel + if (nElec == oneProng && nPi == threeProng) { // 1 + 3 + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(10., 1.); + } else if (nMuon == oneProng && nPi == threeProng) { // 1 + 3 + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(11., 1.); + } else if (nPi == fourTracks) { // 4 + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(12., 1.); + } else if (nPi == sixTracks) { // 6 + registrySkim.get(HIST("skim/efficiencyMC"))->Fill(13., 1.); + } + // trueHasRecoColl = true; // check there is exactly one reco-level collision associated to generated collision if (collFromMcColls.size() > 1) { @@ -1376,6 +1476,14 @@ struct TauThreeProngEventTableProducer { bcSels[5] = collFromMcColl.sbp(); bcSels[6] = collFromMcColl.zVtxFT0vPV(); bcSels[7] = collFromMcColl.vtxITSTPC(); + + const int offset = 1; + bcSelBits = bcSels[0]; // initialization + for (int ibit = 1; ibit < nBitsMax; ibit++) { + bcSelBits = (bcSelBits << offset); // shift by 1 position towards left + bcSelBits += bcSels[ibit]; // add next bit to the pool + } + // energyZNA = collFromMcColl.energyCommonZNA(); // energyZNC = collFromMcColl.energyCommonZNC(); // if (energyZNA < 0) @@ -1529,148 +1637,403 @@ struct TauThreeProngEventTableProducer { } // end of loop over daughters of taus } // end of loop over MC particles } // end of loop over collisions associated to MC collision + + // decide the channel and set the variable. + trueChannel = trueChannel + countPi0 * 10 + zerothTau * 100; + + // LOGF(info, "Should be written!"); + + if (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] == fourTracks) { // 4 + trueTauFourTracks(runNumber, + bc, // is it necessary + totalTracks, + nPVcontrib, + rct, + // dgcand.posX(), dgcand.posY(), + zVertex, + recoMode, + occupancy, + hadronicRate, // is it necessary + bcSelBits, + // bcSels[0], bcSels[1], bcSels[2], // to test it + // bcSels[3], bcSels[4], bcSels[5], bcSels[6], bcSels[7], + // energyZNA, energyZNC, + // timeZNA, timeZNC, + // qtot, <<-------- comment out + amplitudesFIT[0], amplitudesFIT[1], amplitudesFIT[2], + // timesFIT[0], timesFIT[1], timesFIT[2], + px, py, pz, sign, + dcaXY, dcaZ, + nclTPCcrossedRows, nclTPCfind, nclTPCchi2, trkITSchi2, trkITScl, + tpcSignal, tpcEl, tpcPi, tpcKa, tpcPr, tpcMu, + tofSignal, tofEl, tofPi, tofKa, tofPr, tofMu, + chi2TOF, + // + trueChannel, + // trueHasRecoColl, + mccoll.posZ(), + // trueTauX, trueTauY, trueTauZ, + trueDaugX, trueDaugY, trueDaugZ, + trueDaugPdgCode, problem); + } else if (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] == sixTracks) { // 6 + trueTauSixTracks(runNumber, + bc, // is it necessary + totalTracks, + nPVcontrib, + rct, + // dgcand.posX(), dgcand.posY(), + zVertex, + recoMode, + occupancy, + hadronicRate, // is it necessary + bcSelBits, + // bcSels[0], bcSels[1], bcSels[2], // to test it + // bcSels[3], bcSels[4], bcSels[5], bcSels[6], bcSels[7], + // energyZNA, energyZNC, + // timeZNA, timeZNC, + // qtot, <<-------- comment out + amplitudesFIT[0], amplitudesFIT[1], amplitudesFIT[2], + // timesFIT[0], timesFIT[1], timesFIT[2], + px, py, pz, sign, + dcaXY, dcaZ, + nclTPCcrossedRows, nclTPCfind, nclTPCchi2, trkITSchi2, trkITScl, + tpcSignal, tpcEl, tpcPi, tpcKa, tpcPr, tpcMu, + tofSignal, tofEl, tofPi, tofKa, tofPr, tofMu, + chi2TOF, + // + trueChannel, + // trueHasRecoColl, + mccoll.posZ(), + // trueTauX, trueTauY, trueTauZ, + trueDaugX, trueDaugY, trueDaugZ, + trueDaugPdgCode, problem); + } // end of saving the output + } else { // get only the truth information. The reco-level info is left on default if (verbose) LOGF(info, "MC Collision has NO reconstructed collision!"); - // get particles associated to generated collision - auto const& partsFromMcColl = mcParticles.sliceBy(partPerMcCollision, mccoll.globalIndex()); + } // collisions + + } // mccollisions + } // end of processMonteCarlo + PROCESS_SWITCH(TauThreeProngEventTableProducer, processMonteCarlo, "Iterate UD tables with simulated data created by SG-Candidate-Producer.", false); + + // only MC information and what events are reconstructed + + void processGenerated(aod::UDMcCollisions const& mcCollisions, + aod::UDMcParticles const& mcParticles, + FullMCSGUDCollisions const& collisions) + { + // registrySkim.get(HIST("skim/efficiencyMC"))->Fill(0., 1.); + + const int fourTracks = 4; + const int sixTracks = 6; + const int oneProng = 1; + const int threeProng = 3; + // const float epsilon = 0.000001; + + if (verbose) + LOGF(info, " UDMcCollision size %d, Collisions size %d, UDMcParticles %d", mcCollisions.size(), collisions.size(), mcParticles.size()); + + // temporary variables + float trueTauRapidity[2] = {-999., -999.}; + float trueTauEta[2] = {-999., -999.}; + float trueTauPhi[2] = {-999., -999.}; + + // init variables for tree + float trueTauX[2] = {-999., -999.}; + float trueTauY[2] = {-999., -999.}; + float trueTauZ[2] = {-999., -999.}; + + bool tauInRapidity = true; + bool partFromTauInEta = true; + + // start loop over generated collisions + for (const auto& mccoll : mcCollisions) { + if (verbose) + LOGF(info, "-- McColl GID %d", mccoll.globalIndex()); + registrySkim.get(HIST("gen/efficiencyMC"))->Fill(0., 1.); // all MC collisions + + // set up default values per colission + trueTauX[0] = -999.; + trueTauY[0] = -999.; + trueTauZ[0] = -999.; + trueTauX[1] = -999.; + trueTauY[1] = -999.; + trueTauZ[1] = -999.; + + tauInRapidity = true; + partFromTauInEta = true; + + // get particles associated to generated collision + // auto const& tmpPartsFromMcColl = mcParticles.sliceBy(partPerMcCollision, (int64_t)mccoll.globalIndex()); + auto const& tmpPartsFromMcColl = mcParticles.sliceBy(partPerMcCollision, mccoll.globalIndex()); + + if (verbose) + LOGF(info, "- part from MC coll %d", tmpPartsFromMcColl.size()); + int countMothers = 0; + const int desiredNMothers = 2; + for (const auto& particle : tmpPartsFromMcColl) { if (verbose) - LOGF(info, "NO Coll; partsFromMcColl in MC %d", partsFromMcColl.size()); - // int countMothers = 0; - int countDaughters = 0; - countPi0 = 0; - for (const auto& particle : partsFromMcColl) { - if (verbose) - LOGF(info, "No Coll; part Gid %d, Id %d, pdg %d, hasM %d, hasD %d", particle.globalIndex(), particle.index(), particle.pdgCode(), particle.has_mothers(), particle.has_daughters()); - // select only tauons with checking if particle has no mother - // in UPC MC taus have mothers - // if (particle.has_mothers()) - if (std::abs(particle.pdgCode()) != kTauMinus) // 15 - continue; - // countMothers++; - // check the generated collision does not have more than 2 tauons - // if (countMothers > 2) { - // if (verbose) - // LOGF(info,"Truth collision has more than 2 no mother particles. Breaking the particle loop."); - // // histos.get(HIST("Truth/hTroubles"))->Fill(12); - // // problem = true; - // break; - // } - // // fill info for each tau - // trueTauX[countMothers - 1] = particle.px(); - // trueTauY[countMothers - 1] = particle.py(); - // trueTauZ[countMothers - 1] = particle.pz(); + LOGF(info, "-- MC part pdg %d", particle.pdgCode()); + if (std::abs(particle.pdgCode()) != kTauMinus) + continue; // 15 = tau_minus + if (countMothers < desiredNMothers) { // < 2 + // fill info for each tau + trueTauX[countMothers] = particle.px(); + trueTauY[countMothers] = particle.py(); + trueTauZ[countMothers] = particle.pz(); + trueTauRapidity[countMothers] = rapidity(particle.e(), trueTauZ[countMothers]); + trueTauEta[countMothers] = RecoDecay::eta(std::array{particle.px(), particle.py(), particle.pz()}); + trueTauPhi[countMothers] = RecoDecay::phi(particle.px(), particle.py()); - // get daughters of the tau - const auto& daughters = particle.daughters_as(); if (verbose) - LOGF(info, "NO coll; N_daughters %d", daughters.size()); - // int countDaughters = 0; - for (const auto& daughter : daughters) { + LOGF(info, "-- tau P(%f,%f,%f), e %f, y %f", particle.px(), particle.py(), particle.pz(), particle.e(), trueTauRapidity[countMothers]); + if (std::abs(trueTauRapidity[countMothers]) > trkEtacut) { // 0.9 + tauInRapidity = false; if (verbose) - LOGF(info, "NO Coll; daug id %d, pdg %d", daughter.globalIndex(), daughter.pdgCode()); + LOGF(info, "--- tau y %f", trueTauRapidity[countMothers]); + } // rapidity check + } // number of taus + countMothers++; + } // end of loop over MC paricles + // LOGF(info, "1b. countMothers %d", countMothers); + registrySkim.get(HIST("gen/nTauMC"))->Fill(countMothers); + if (countMothers != desiredNMothers) { // 2 + if (verbose) + LOGF(info, "-- Truth collision has number of mother particles (taus) %d different than 2. Jump to the next MC event.", countMothers); + continue; + } - if (daughter.pdgCode() == kPi0) - countPi0++; + registrySkim.get(HIST("gen/efficiencyMC"))->Fill(1., 1.); // exactly 2 taus - // select only the charged particle (= no pi0 or neutrino) - if (enumMyParticle(daughter.pdgCode()) == -1) - continue; - countDaughters++; + for (int iNmother = 0; iNmother < desiredNMothers; iNmother++) { + registrySkim.get(HIST("gen/tauRapidityMC"))->Fill(trueTauRapidity[iNmother]); + if (tauInRapidity) { + registrySkim.get(HIST("gen/tauPhiMC"))->Fill(trueTauPhi[iNmother]); + registrySkim.get(HIST("gen/tauEtaMC"))->Fill(trueTauEta[iNmother]); + registrySkim.get(HIST("gen/tauPtMC"))->Fill(RecoDecay::pt(trueTauX[iNmother], trueTauY[iNmother])); + } + } - // check whether 1+3 or 3+3 topology is present - if (countDaughters > sixTracks) { // 6 - if (verbose) - LOGF(info, "Truth collision has more than 6 charged daughters from taus. Breaking the daughter loop."); - // histos.get(HIST("Truth/hTroubles"))->Fill(13); - // problem = true; - registrySkim.get(HIST("skim/problemMC"))->Fill(TOO_MANY_DAUGHTERS); - problem = TOO_MANY_DAUGHTERS; - break; - } - // fill info for each daughter - trueDaugX[countDaughters - 1] = daughter.px(); - trueDaugY[countDaughters - 1] = daughter.py(); - trueDaugZ[countDaughters - 1] = daughter.pz(); - trueDaugPdgCode[countDaughters - 1] = daughter.pdgCode(); - } // daughters + if (!tauInRapidity) { // tau NOT in rapidity -> continue + if (verbose) + LOGF(info, "-- At least one mother particle (taus) out of rapidity (|y|<0.9). Jump to the next MC event."); + continue; + } + + // delta eta and delta phi between taus + registrySkim.get(HIST("gen/tauDeltaEtaMC"))->Fill(trueTauEta[0] - trueTauEta[1]); + registrySkim.get(HIST("gen/tauDeltaPhiMC"))->Fill(calculateDeltaPhi(trueTauPhi[0], trueTauPhi[1]) * 180. / o2::constants::math::PI); + + // inv mass of two taus + ROOT::Math::LorentzVector> tau1; + ROOT::Math::LorentzVector> tau2; + tau1.SetXYZT(trueTauX[0], trueTauY[0], trueTauZ[0], RecoDecay::e(trueTauX[0], trueTauY[0], trueTauZ[0], MassTauPlus)); + tau2.SetXYZT(trueTauX[1], trueTauY[1], trueTauZ[1], RecoDecay::e(trueTauX[1], trueTauY[1], trueTauZ[1], MassTauPlus)); + registrySkim.get(HIST("gen/ditauInvMassMC"))->Fill((tau1 + tau2).M()); + + registrySkim.get(HIST("gen/efficiencyMC"))->Fill(2., 1.); // |y_tau| <= 0.9 + countMothers = 0; + int nChargedDaughtersTau[2] = {0, 0}; + int nElec = 0; + int nMuon = 0; + int nPi = 0; + int particleType = -1; + int zerothTau = -10; + int trueChannel = -1; + int countPi0 = -1; + + for (const auto& particle : tmpPartsFromMcColl) { + if (std::abs(particle.pdgCode()) != kTauMinus) + continue; // 15 = tau_minus + const auto& daughters = particle.daughters_as(); + for (const auto& daughter : daughters) { + particleType = enumMyParticle(daughter.pdgCode()); + if (particleType == MyOtherParticle) { // -1 + continue; + } else { + nChargedDaughtersTau[countMothers]++; + if (particleType == MyElectron) // 1 + nElec++; + else if (particleType == MyMuon) // 2 + nMuon++; + else if (particleType == MyPion) // 3 + nPi++; + } + + if (std::abs(RecoDecay::eta(std::array{daughter.px(), daughter.py(), daughter.pz()})) > trkEtacut) // 0.9 + partFromTauInEta = false; + registrySkim.get(HIST("gen/daughterPhiMC"))->Fill(RecoDecay::phi(daughter.px(), daughter.py())); + registrySkim.get(HIST("gen/daughterEtaMC"))->Fill(RecoDecay::eta(std::array{daughter.px(), daughter.py(), daughter.pz()})); + registrySkim.get(HIST("gen/daughterPtMC"))->Fill(RecoDecay::pt(daughter.px(), daughter.py())); + } + countMothers++; + if (countMothers >= desiredNMothers) // 2 + break; + } // end of loop over MC particles + + if (!partFromTauInEta) { + if (verbose) + LOGF(info, "-- At least one daughter particle from taus out of pseudo-rapidity (|eta|<0.9). Jump to the next MC event."); + continue; + } + + registrySkim.get(HIST("gen/efficiencyMC"))->Fill(3., 1.); // charged particles from tau in |eta|<=0.9 + + registrySkim.get(HIST("gen/nChPartMC"))->Fill(nChargedDaughtersTau[0] + nChargedDaughtersTau[1]); // N charged particles from taus + // check number of charged particles in MC event + if ((nChargedDaughtersTau[0] + nChargedDaughtersTau[1] != fourTracks) && (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] != sixTracks)) { + if (verbose) + LOGF(info, "-- Different from 4/6 charged particles (%d) from both taus. Jump to the next MC event.", nChargedDaughtersTau[0] + nChargedDaughtersTau[1]); + continue; + } + + registrySkim.get(HIST("gen/efficiencyMC"))->Fill(4., 1.); // 1+3 (3+3) topology = 4 or 6 tracks + + if ((nChargedDaughtersTau[0] == oneProng) || // 1 + (nChargedDaughtersTau[0] == threeProng && nChargedDaughtersTau[1] == threeProng)) // 3 and 3 + zerothTau = 0; + else if (nChargedDaughtersTau[1] == oneProng) // 1 + zerothTau = 1; + + float trueDaugX[6] = {-998., -998., -998., -998., -998., -998.}; + float trueDaugY[6] = {-998., -998., -998., -998., -998., -998.}; + float trueDaugZ[6] = {-998., -998., -998., -998., -998., -998.}; + int trueDaugPdgCode[6] = {-999, -999, -999, -999, -999, -999}; + + MyRecoProblem problem = NO_PROBLEM; + registrySkim.get(HIST("gen/problemMC"))->Fill(NO_PROBLEM); + + // tau tau event type + // 1 = e+3pi + // 2 = mu+3pi + // 3 = pi+3pi + // 4 = 3pi+3pi + + if (nElec == oneProng && nPi == threeProng) { // 1 + 3 + trueChannel = 1; + registrySkim.get(HIST("gen/efficiencyMC"))->Fill(5., 1.); + } else if (nMuon == oneProng && nPi == threeProng) { // 1 + 3 + trueChannel = 2; + registrySkim.get(HIST("gen/efficiencyMC"))->Fill(6., 1.); + } else if (nPi == fourTracks) { // 4 + trueChannel = 3; + registrySkim.get(HIST("gen/efficiencyMC"))->Fill(7., 1.); + } else if (nPi == sixTracks) { // 6 + trueChannel = 4; + registrySkim.get(HIST("gen/efficiencyMC"))->Fill(8., 1.); + } + + // get particles associated to generated collision + auto const& partsFromMcColl = mcParticles.sliceBy(partPerMcCollision, mccoll.globalIndex()); + if (verbose) + LOGF(info, "partsFromMcColl in MC %d", partsFromMcColl.size()); + int countDaughters = 0; + countPi0 = 0; + for (const auto& particle : partsFromMcColl) { + if (verbose) + LOGF(info, "part Gid %d, Id %d, pdg %d, hasM %d, hasD %d", particle.globalIndex(), particle.index(), particle.pdgCode(), particle.has_mothers(), particle.has_daughters()); + // select only tauons with checking if particle has no mother + // in UPC MC taus have mothers + // if (particle.has_mothers()) + if (std::abs(particle.pdgCode()) != kTauMinus) // 15 + continue; + + // get daughters of the tau + const auto& daughters = particle.daughters_as(); + if (verbose) + LOGF(info, "N_daughters %d", daughters.size()); + for (const auto& daughter : daughters) { if (verbose) - LOGF(info, "End of daughters"); - } // particles - } // collisions + LOGF(info, "daug id %d, pdg %d", daughter.globalIndex(), daughter.pdgCode()); + + if (daughter.pdgCode() == kPi0) + countPi0++; + + // select only the charged particle (= no pi0 or neutrino) + if (enumMyParticle(daughter.pdgCode()) == -1) + continue; + countDaughters++; + + // check whether 1+3 or 3+3 topology is present + if (countDaughters > sixTracks) { // 6 + if (verbose) + LOGF(info, "Truth collision has more than 6 charged daughters from taus. Breaking the daughter loop."); + registrySkim.get(HIST("gen/problemMC"))->Fill(TOO_MANY_DAUGHTERS); + problem = TOO_MANY_DAUGHTERS; + break; + } + // fill info for each daughter + trueDaugX[countDaughters - 1] = daughter.px(); + trueDaugY[countDaughters - 1] = daughter.py(); + trueDaugZ[countDaughters - 1] = daughter.pz(); + trueDaugPdgCode[countDaughters - 1] = daughter.pdgCode(); + } // daughters + + if (verbose) + LOGF(info, "End of daughters"); + } // mcparticles // decide the channel and set the variable. trueChannel = trueChannel + countPi0 * 10 + zerothTau * 100; + // + // check whwther event is reconstructed + // + bool trueHasRecoColl = false; + // find reconstructed collisions associated to the generated collision + auto const& collFromMcColls = collisions.sliceBy(colPerMcCollision, mccoll.globalIndex()); + if (verbose) + LOGF(info, "-- coll from MC Coll %d", collFromMcColls.size()); + // check the generated collision was reconstructed + if (collFromMcColls.size() > 0) { // get the truth and reco-level info + trueHasRecoColl = true; + registrySkim.get(HIST("gen/efficiencyMC"))->Fill(9., 1.); + if (verbose) + LOGF(info, "--- MC Collision has reconstructed collision!"); + + // reconstruction in a given channel + if (nElec == oneProng && nPi == threeProng) { // 1 + 3 + registrySkim.get(HIST("gen/efficiencyMC"))->Fill(10., 1.); + } else if (nMuon == oneProng && nPi == threeProng) { // 1 + 3 + registrySkim.get(HIST("gen/efficiencyMC"))->Fill(11., 1.); + } else if (nPi == fourTracks) { // 4 + registrySkim.get(HIST("gen/efficiencyMC"))->Fill(12., 1.); + } else if (nPi == sixTracks) { // 6 + registrySkim.get(HIST("gen/efficiencyMC"))->Fill(13., 1.); + } + + } else { // get only the truth information. + if (verbose) + LOGF(info, "MC Collision has NO reconstructed collision!"); + } + // LOGF(info, "Should be written!"); if (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] == fourTracks) { // 4 - trueTauFourTracks(runNumber, - bc, // is it necessary - totalTracks, - nPVcontrib, - rct, - // dgcand.posX(), dgcand.posY(), - zVertex, - recoMode, - occupancy, - hadronicRate, // is it necessary - bcSels[0], bcSels[1], bcSels[2], // to test it - bcSels[3], bcSels[4], bcSels[5], bcSels[6], bcSels[7], - energyZNA, energyZNC, - timeZNA, timeZNC, - // qtot, <<-------- comment out - amplitudesFIT[0], amplitudesFIT[1], amplitudesFIT[2], - // timesFIT[0], timesFIT[1], timesFIT[2], - px, py, pz, sign, - dcaXY, dcaZ, - nclTPCcrossedRows, nclTPCfind, nclTPCchi2, trkITSchi2, trkITScl, - tpcSignal, tpcEl, tpcPi, tpcKa, tpcPr, tpcMu, - tofSignal, tofEl, tofPi, tofKa, tofPr, tofMu, - chi2TOF, - // - trueChannel, - // trueHasRecoColl, - mccoll.posZ(), - trueTauX, trueTauY, trueTauZ, - trueDaugX, trueDaugY, trueDaugZ, - trueDaugPdgCode, problem); + genTauFourTracks( + trueChannel, + mccoll.posZ(), + // trueTauX, trueTauY, trueTauZ, + trueDaugX, trueDaugY, trueDaugZ, + trueDaugPdgCode, + problem, + trueHasRecoColl); } else if (nChargedDaughtersTau[0] + nChargedDaughtersTau[1] == sixTracks) { // 6 - trueTauSixTracks(runNumber, - bc, // is it necessary - totalTracks, - nPVcontrib, - rct, - // dgcand.posX(), dgcand.posY(), - zVertex, - recoMode, - occupancy, - hadronicRate, // is it necessary - bcSels[0], bcSels[1], bcSels[2], // to test it - bcSels[3], bcSels[4], bcSels[5], bcSels[6], bcSels[7], - energyZNA, energyZNC, - timeZNA, timeZNC, - // qtot, <<-------- comment out - amplitudesFIT[0], amplitudesFIT[1], amplitudesFIT[2], - // timesFIT[0], timesFIT[1], timesFIT[2], - px, py, pz, sign, - dcaXY, dcaZ, - nclTPCcrossedRows, nclTPCfind, nclTPCchi2, trkITSchi2, trkITScl, - tpcSignal, tpcEl, tpcPi, tpcKa, tpcPr, tpcMu, - tofSignal, tofEl, tofPi, tofKa, tofPr, tofMu, - chi2TOF, - // - trueChannel, - // trueHasRecoColl, - mccoll.posZ(), - trueTauX, trueTauY, trueTauZ, - trueDaugX, trueDaugY, trueDaugZ, - trueDaugPdgCode, problem); - } + genTauSixTracks( + trueChannel, + mccoll.posZ(), + // trueTauX, trueTauY, trueTauZ, + trueDaugX, trueDaugY, trueDaugZ, + trueDaugPdgCode, + problem, + trueHasRecoColl); + } // end of writing output } // mccollisions - } // end of processMonteCarlo - PROCESS_SWITCH(TauThreeProngEventTableProducer, processMonteCarlo, "Iterate UD tables with simulated data created by SG-Candidate-Producer.", false); + } // end of processGenerated + PROCESS_SWITCH(TauThreeProngEventTableProducer, processGenerated, "Iterate UD tables with generated data created by SG-Candidate-Producer.", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) diff --git a/PWGUD/TableProducer/twoTracksEventTableProducer.cxx b/PWGUD/TableProducer/twoTracksEventTableProducer.cxx index 36c5c44112f..cf5f91a34a6 100644 --- a/PWGUD/TableProducer/twoTracksEventTableProducer.cxx +++ b/PWGUD/TableProducer/twoTracksEventTableProducer.cxx @@ -241,7 +241,7 @@ struct TwoTracksEventTableProducer { std::vector>> cutMyRequiredITSHits{}; - void mySetRequireHitsInITSLayers(int8_t minNRequiredHits, std::set requiredLayers) + void mySetRequireHitsInITSLayers(int8_t minNRequiredHits, const std::set& requiredLayers) { // layer 0 corresponds to the the innermost ITS layer cutMyRequiredITSHits.push_back(std::make_pair(minNRequiredHits, requiredLayers)); diff --git a/PWGUD/TableProducer/upcCandProducerBarrel.cxx b/PWGUD/TableProducer/upcCandProducerBarrel.cxx new file mode 100644 index 00000000000..4d2a75be18a --- /dev/null +++ b/PWGUD/TableProducer/upcCandProducerBarrel.cxx @@ -0,0 +1,570 @@ +// 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. + +/// \file upcCandProducerBarrel.cxx +/// \brief Compact candidate table producer for diffraction and UPC studies. +/// Requires: event selection, propagation, TPC PID and TOF PID services +/// \author Nazar Burmasov (JINR), Evgeny Kryshen (JINR) + +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/CCDB/RCTSelectionFlags.h" +#include "Common/Core/TableHelper.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/PIDResponseTOF.h" +#include "Common/DataModel/PIDResponseTPC.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::aod::rctsel; + +namespace +{ +constexpr int NBCsPerOrbit = o2::constants::lhc::LHCMaxBunches; +constexpr int MaxStoredDistance = 15; +constexpr float MaxFITTime = 30.f; + +constexpr int NoSignalMCRef = -1; +constexpr int NoRecoCollision = -1; +constexpr int MultipleRecoTracks = -2; + +constexpr uint16_t MCTrackFakeMask = 1u << 15; + +enum MCParticleFlag : uint8_t { + kNoFlags = 0, + kPhysicalPrimary = 1u << 0, // generated physical primary + kHasRecoTrack = 1u << 1, // has at least one non-fake reconstructed track + kHighMultiplicityCollision = 1u << 2, // matched track belongs to a collision with extra contributors + kHasPVContributor = 1u << 3, // has a track contributing to the PV + kHasAmbiguousTrack = 1u << 4 // has an ambiguous track +}; + +using SignalRef = std::pair; +using DistanceMap = std::vector>; + +DistanceMap buildMinimumDistanceMap(std::vector const& tfIDs, + int64_t bcSOR, int64_t nBCsPerTF, + std::vector& activeBCs, uint32_t maxDistance, + bool skipFirstExactMatch = false) +{ + const uint32_t overflowDistance = maxDistance + 1; + DistanceMap distances(tfIDs.size(), std::vector(nBCsPerTF, overflowDistance)); + if (activeBCs.empty()) { + return distances; + } + // Keep duplicate BCs so collisions at the same BC have distance zero + std::sort(activeBCs.begin(), activeBCs.end()); + // The forward-only cursor makes the scan linear after sorting + size_t nextIndex = 0; + for (size_t iTF = 0; iTF < tfIDs.size(); ++iTF) { + const int64_t tfStartBC = bcSOR + tfIDs[iTF] * nBCsPerTF; + for (int64_t bcInTF = 0; bcInTF < nBCsPerTF; ++bcInTF) { + const int64_t currentBC = tfStartBC + bcInTF; + while (nextIndex < activeBCs.size() && activeBCs[nextIndex] < currentBC) { + ++nextIndex; + } + size_t rightIndex = nextIndex; + // MC maps contain the queried collision itself, so skip one exact self-match + if (skipFirstExactMatch && rightIndex < activeBCs.size() && activeBCs[rightIndex] == currentBC) { + ++rightIndex; + } + int64_t distance = overflowDistance; + if (rightIndex < activeBCs.size()) { + distance = std::min(distance, activeBCs[rightIndex] - currentBC); + } + if (nextIndex > 0) { + distance = std::min(distance, currentBC - activeBCs[nextIndex - 1]); + } + distances[iTF][bcInTF] = static_cast(distance); + } + } + return distances; +} + +void fillVetoHistograms(std::shared_ptr const& hVetoT00, std::shared_ptr const& hVetoTV0, + std::shared_ptr const& hVetoTVD, int bcInOrbit, + uint32_t distanceFT0, uint32_t distanceFV0, uint32_t distanceFDD) +{ + hVetoT00->Fill(bcInOrbit, -1); + hVetoTV0->Fill(bcInOrbit, -1); + hVetoTVD->Fill(bcInOrbit, -1); + for (uint32_t threshold = 0; threshold <= MaxStoredDistance; ++threshold) { + if (distanceFT0 <= threshold) { + continue; + } + hVetoT00->Fill(bcInOrbit, threshold); + if (distanceFV0 <= threshold) { + continue; + } + hVetoTV0->Fill(bcInOrbit, threshold); + if (distanceFDD > threshold) { + hVetoTVD->Fill(bcInOrbit, threshold); + } + } +} +} // namespace + +namespace o2::aod::upc_cand_prod_bar +{ +DECLARE_SOA_COLUMN(RunNumber, runNumber, int32_t); +DECLARE_SOA_COLUMN(GlobalBC, globalBC, uint64_t); +DECLARE_SOA_COLUMN(TfId, tfId, uint32_t); +DECLARE_SOA_COLUMN(Timestamp, timestamp, uint64_t); +DECLARE_SOA_COLUMN(PosX, posX, float); +DECLARE_SOA_COLUMN(PosY, posY, float); +DECLARE_SOA_COLUMN(PosZ, posZ, float); +DECLARE_SOA_COLUMN(Px, px, std::vector); +DECLARE_SOA_COLUMN(Py, py, std::vector); +DECLARE_SOA_COLUMN(Pz, pz, std::vector); +DECLARE_SOA_COLUMN(TpcSignal, tpcSignal, std::vector); +DECLARE_SOA_COLUMN(TpcNSigmaEl, tpcNSigmaEl, std::vector); +DECLARE_SOA_COLUMN(TpcNSigmaPi, tpcNSigmaPi, std::vector); +DECLARE_SOA_COLUMN(TpcNSigmaKa, tpcNSigmaKa, std::vector); +DECLARE_SOA_COLUMN(TpcNSigmaPr, tpcNSigmaPr, std::vector); +DECLARE_SOA_COLUMN(TofNSigmaEl, tofNSigmaEl, std::vector); +DECLARE_SOA_COLUMN(TofNSigmaPi, tofNSigmaPi, std::vector); +DECLARE_SOA_COLUMN(TofNSigmaKa, tofNSigmaKa, std::vector); +DECLARE_SOA_COLUMN(TofNSigmaPr, tofNSigmaPr, std::vector); +DECLARE_SOA_COLUMN(ItsClusterMap, itsClusterMap, std::vector); +DECLARE_SOA_COLUMN(NClusters, nClusters, std::vector); +DECLARE_SOA_COLUMN(Sign, sign, std::vector); +DECLARE_SOA_COLUMN(MinimumDistanceFT0, minimumDistanceFT0, int8_t); +DECLARE_SOA_COLUMN(MinimumDistanceFV0, minimumDistanceFV0, int8_t); +DECLARE_SOA_COLUMN(MinimumDistanceFDD, minimumDistanceFDD, int8_t); +DECLARE_SOA_COLUMN(Pdg, pdg, std::vector); +DECLARE_SOA_COLUMN(MinimumDistanceMCCol, minimumDistanceMCCol, int8_t); +DECLARE_SOA_COLUMN(RecoFlags, recoFlags, std::vector); // See MCParticleFlag for the bit definitions +DECLARE_SOA_COLUMN(RecoCollisionIds, recoCollisionIds, std::vector); // -1: no collision, -2: multiple tracks +DECLARE_SOA_COLUMN(ParticleIds, particleIds, std::vector); +DECLARE_SOA_COLUMN(Mult, mult, int32_t); // number of physical-primary MC particles in the collision +DECLARE_SOA_COLUMN(IsSignal, isSignal, bool); // whether the collision belongs to the configured signal source +} // namespace o2::aod::upc_cand_prod_bar + +namespace o2::aod +{ +DECLARE_SOA_TABLE(UPCBarrelCands, "AOD", "UPCBARRELCANDS", + upc_cand_prod_bar::RunNumber, + upc_cand_prod_bar::GlobalBC, + upc_cand_prod_bar::TfId, + upc_cand_prod_bar::Timestamp, + upc_cand_prod_bar::PosX, + upc_cand_prod_bar::PosY, + upc_cand_prod_bar::PosZ, + upc_cand_prod_bar::Px, + upc_cand_prod_bar::Py, + upc_cand_prod_bar::Pz, + upc_cand_prod_bar::TpcSignal, + upc_cand_prod_bar::TpcNSigmaEl, + upc_cand_prod_bar::TpcNSigmaPi, + upc_cand_prod_bar::TpcNSigmaKa, + upc_cand_prod_bar::TpcNSigmaPr, + upc_cand_prod_bar::TofNSigmaEl, + upc_cand_prod_bar::TofNSigmaPi, + upc_cand_prod_bar::TofNSigmaKa, + upc_cand_prod_bar::TofNSigmaPr, + upc_cand_prod_bar::ItsClusterMap, + upc_cand_prod_bar::NClusters, + upc_cand_prod_bar::Sign, + upc_cand_prod_bar::MinimumDistanceFT0, + upc_cand_prod_bar::MinimumDistanceFV0, + upc_cand_prod_bar::MinimumDistanceFDD); + +DECLARE_SOA_TABLE(UPCBarrelMcColls, "AOD", "UPCBMCCOLL", + upc_cand_prod_bar::TfId, + upc_cand_prod_bar::GlobalBC, + upc_cand_prod_bar::PosX, + upc_cand_prod_bar::PosY, + upc_cand_prod_bar::PosZ, + upc_cand_prod_bar::Px, + upc_cand_prod_bar::Py, + upc_cand_prod_bar::Pz, + upc_cand_prod_bar::Pdg, + upc_cand_prod_bar::Mult, + upc_cand_prod_bar::MinimumDistanceMCCol, + upc_cand_prod_bar::RecoFlags, + upc_cand_prod_bar::RecoCollisionIds, + upc_cand_prod_bar::IsSignal); + +namespace upc_cand_prod_bar +{ +// Array index into UPCBarrelMcColls +DECLARE_SOA_ARRAY_INDEX_COLUMN_FULL_CUSTOM(McCollision, mcCollision, int32_t, UPCBarrelMcColls, "UPCBMCColls", ""); +} // namespace upc_cand_prod_bar + +// Both IDs are -1 if the track has no valid stored signal reference +DECLARE_SOA_TABLE(UPCBarrelMCLabels, "AOD", "UPCBMCLABEL", + upc_cand_prod_bar::McCollisionIds, + upc_cand_prod_bar::ParticleIds); +} // namespace o2::aod + +struct UpcCandProducerBarrel { + Produces selectedCandidates; + Produces selectedMCCollisions; + Produces selectedCandidateMCLabels; + HistogramRegistry registry{"registry", {}}; + Service ccdb{}; + + int cachedRunNumber = -1; + int64_t bcSOR = 0; + int64_t nBCsPerTF = 0; + int configuredOrbitsPerTF = -1; + int configuredTFStartBorder = -1; + int configuredTFEndBorder = -1; + int tfStartBorder = 0; + int tfEndBorder = 0; + std::bitset collidingBCs; + + Configurable nTracks{"nTracks", 2, "Required N tracks in selected collisions"}; + Configurable maxAbsEta{"maxAbsEta", 0.8f, "Maximum |eta| of selected tracks"}; + Configurable minPt{"minPt", 0.2f, "Minimum pT of selected tracks (GeV/c)"}; + Configurable vetoBCWindow{"vetoBCWindow", 0, "FIT veto half-window in BC; <0 disables"}; + Configurable vetoFT0{"vetoFT0", 1, "FT0 veto: 0=off, 1=on"}; + Configurable vetoFV0{"vetoFV0", 0, "FV0 veto: 0=off, 1=on"}; + Configurable vetoFDD{"vetoFDD", 0, "FDD veto: 0=off, 1=on"}; + Configurable signalSourceId{"signalSourceId", 1, "MC source ID stored as embedded signal"}; + + using CollisionsWithSels = soa::Join; + using BCsWithSels = soa::Join; + using TracksWithPID = soa::Join; + using TracksWithPIDMC = soa::Join; + Preslice tracksPerCollision = aod::track::collisionId; + Preslice mcTracksPerCollision = aod::track::collisionId; + PresliceUnsorted tracksPerMCParticle = aod::mctracklabel::mcParticleId; + Preslice particlesPerMCCollision = aod::mcparticle::mcCollisionId; + + RCTFlagsChecker rctChecker{kFDDBad, kFT0Bad, kFV0Bad, kITSBad, kITSLimAccMCRepr, kTPCBadTracking, kTPCLimAccMCRepr, kTPCBadPID, kTOFBad, kTOFLimAccMCRepr, kCcdbObjectLoaded}; + + void init(InitContext& initContext) + { + ccdb->setLocalObjectValidityChecking(); + auto inheritEventSelectionOption = [&](char const* name, int& value) { + if (!o2::common::core::getTaskOptionValue(initContext, "eventselection-run3", name, value, false)) { + LOGF(fatal, "Could not inherit option %s from eventselection-run3", name); + } + }; + inheritEventSelectionOption("bcselOpts.NumberOfOrbitsPerTF", configuredOrbitsPerTF); + inheritEventSelectionOption("bcselOpts.TimeFrameStartBorderMargin", configuredTFStartBorder); + inheritEventSelectionOption("bcselOpts.TimeFrameEndBorderMargin", configuredTFEndBorder); + registry.add("hProcessedTFs", "Processed TFs;;TFs", HistType::kTH1D, {{1, 0., 1.}}); + registry.add("hTVX", "TVX counts per run;run;TVX BCs", HistType::kTH1D, {{NBCsPerOrbit, 0., NBCsPerOrbit}}); + registry.add("hTVXRCT", "TVX counts per run;run;TVX BCs", HistType::kTH1D, {{NBCsPerOrbit, 0., NBCsPerOrbit}}); + registry.add("hVetoT00", ";BC in orbit;veto range (BC);colliding BC count, no RCT mask", HistType::kTH2D, {{NBCsPerOrbit, 0., NBCsPerOrbit}, {17, -1.5, 15.5}}); + registry.add("hVetoTV0", ";BC in orbit;veto range (BC);colliding BC count, no RCT mask", HistType::kTH2D, {{NBCsPerOrbit, 0., NBCsPerOrbit}, {17, -1.5, 15.5}}); + registry.add("hVetoTVD", ";BC in orbit;veto range (BC);colliding BC count, no RCT mask", HistType::kTH2D, {{NBCsPerOrbit, 0., NBCsPerOrbit}, {17, -1.5, 15.5}}); + registry.add("hVetoT00RCT", ";BC in orbit;veto range (BC);colliding BC count, RCT mask", HistType::kTH2D, {{NBCsPerOrbit, 0., NBCsPerOrbit}, {17, -1.5, 15.5}}); + registry.add("hVetoTV0RCT", ";BC in orbit;veto range (BC);colliding BC count, RCT mask", HistType::kTH2D, {{NBCsPerOrbit, 0., NBCsPerOrbit}, {17, -1.5, 15.5}}); + registry.add("hVetoTVDRCT", ";BC in orbit;veto range (BC);colliding BC count, RCT mask", HistType::kTH2D, {{NBCsPerOrbit, 0., NBCsPerOrbit}, {17, -1.5, 15.5}}); + LOGF(info, "Veto config: window=%d FT0=%d FV0=%d FDD=%d", vetoBCWindow.value, vetoFT0.value, vetoFV0.value, vetoFDD.value); + } + + void updateRunInfo(int runNumber) + { + if (runNumber == cachedRunNumber) { + return; + } + const auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(ccdb->instance(), runNumber); + const int64_t orbitsPerTF = configuredOrbitsPerTF < 0 ? runInfo.orbitsPerTF : configuredOrbitsPerTF; + const bool needsEventSelectionParams = configuredTFStartBorder < 0 || configuredTFEndBorder < 0; + const auto* eventSelectionParams = needsEventSelectionParams ? ccdb->getForTimeStamp("EventSelection/EventSelectionParams", runInfo.sor / 2 + runInfo.eor / 2) : nullptr; + if (orbitsPerTF <= 0 || !runInfo.grpLHC || (needsEventSelectionParams && !eventSelectionParams)) { + LOGF(fatal, "Incomplete run information for run %d", runNumber); + } + bcSOR = runInfo.orbitSOR * NBCsPerOrbit; + nBCsPerTF = orbitsPerTF * NBCsPerOrbit; + tfStartBorder = configuredTFStartBorder < 0 ? eventSelectionParams->fTimeFrameStartBorderMargin : configuredTFStartBorder; + tfEndBorder = configuredTFEndBorder < 0 ? eventSelectionParams->fTimeFrameEndBorderMargin : configuredTFEndBorder; + collidingBCs = runInfo.grpLHC->getBunchFilling().getBCPattern(); + cachedRunNumber = runNumber; + } + + template + void processImpl(CollisionsT const& collisions, TracksT const& tracks, PresliceT const& tracksPerColl, + BCsWithSels const& bcs, aod::FT0s const& ft0s, aod::FV0As const& fv0s, + aod::FDDs const& fdds, aod::McCollisions const* mcCollisions = nullptr, + aod::McParticles const* mcParticles = nullptr, + aod::AmbiguousTracks const* ambiguousTracks = nullptr) + { + updateRunInfo(bcs.begin().runNumber()); + std::vector tfIDs; + std::vector tfPassesRCT; + std::vector localTFIndex; + localTFIndex.reserve(bcs.size()); + // Cache the local TF slot for each BC row for collision and MC lookups + for (const auto& bc : bcs) { + const auto tfID = static_cast((static_cast(bc.globalBC()) - bcSOR) / nBCsPerTF); + if (tfIDs.empty() || tfID != tfIDs.back()) { + tfIDs.push_back(tfID); + tfPassesRCT.push_back(static_cast(rctChecker(bc))); + } + localTFIndex.push_back(tfIDs.size() - 1); + } + registry.fill(HIST("hProcessedTFs"), 0.5, static_cast(tfIDs.size())); + + std::unordered_map signalParticleRefs; + if constexpr (isMC) { + std::unordered_set ambiguousTrackIds; + ambiguousTrackIds.reserve(ambiguousTracks->size()); + for (const auto& ambiguousTrack : *ambiguousTracks) { + ambiguousTrackIds.insert(ambiguousTrack.trackId()); + } + + std::vector bcsWithMCCollision; + bcsWithMCCollision.reserve(mcCollisions->size()); + // Use collisions from every source and retain same-BC pile-up + for (const auto& mcCollision : *mcCollisions) { + bcsWithMCCollision.push_back(static_cast(mcCollision.template bc_as().globalBC())); + } + const auto minDistanceMC = buildMinimumDistanceMap(tfIDs, bcSOR, nBCsPerTF, bcsWithMCCollision, MaxStoredDistance, true); + + for (const auto& mcCollision : *mcCollisions) { + const auto bc = mcCollision.template bc_as(); + const auto globalBC = bc.globalBC(); + const auto iTF = localTFIndex[bc.globalIndex()]; + const auto bcInTF = (static_cast(globalBC) - bcSOR) % nBCsPerTF; + const auto particles = mcParticles->sliceBy(particlesPerMCCollision, mcCollision.globalIndex()); + const bool isSignal = mcCollision.getSourceId() == signalSourceId.value; + + std::vector px, py, pz; + std::vector pdg, recoCollisionIds; + std::vector recoFlags; + int32_t mult = 0; + // Output rows follow input MC collisions, making this the compact collision label + const auto newMCCollisionId = static_cast(selectedMCCollisions.lastIndex() + 1); + for (const auto& particle : particles) { + mult += particle.isPhysicalPrimary(); + // Background rows keep only collision metadata and physical-primary multiplicity + if (!isSignal) { + continue; + } + const auto newMCParticleId = static_cast(pdg.size()); + px.push_back(particle.px()); + py.push_back(particle.py()); + pz.push_back(particle.pz()); + pdg.push_back(particle.pdgCode()); + + uint8_t flags = particle.isPhysicalPrimary() ? kPhysicalPrimary : kNoFlags; + int32_t recoCollisionId = NoRecoCollision; + int nRecoTracks = 0; + // Inspect only reconstructed tracks matched to this signal particle + for (const auto& track : tracks.sliceBy(tracksPerMCParticle, particle.globalIndex())) { + if ((track.mcMask() & MCTrackFakeMask) != 0u) { + continue; + } + ++nRecoTracks; + flags |= kHasRecoTrack; + flags |= track.isPVContributor() ? kHasPVContributor : kNoFlags; + flags |= ambiguousTrackIds.contains(track.globalIndex()) ? kHasAmbiguousTrack : kNoFlags; + if (track.has_collision()) { + recoCollisionId = track.collisionId(); + flags |= collisions.iteratorAt(recoCollisionId).numContrib() > nTracks ? kHighMultiplicityCollision : kNoFlags; + } + } + // A single collision label is meaningful only for exactly one reconstructed track + if (nRecoTracks > 1) { + recoCollisionId = MultipleRecoTracks; + } + recoFlags.push_back(flags); + recoCollisionIds.push_back(recoCollisionId); + // Remap original particle IDs to output index for candidate labels + signalParticleRefs.emplace(particle.globalIndex(), SignalRef{newMCCollisionId, newMCParticleId}); + } + selectedMCCollisions(tfIDs[iTF], globalBC, mcCollision.posX(), mcCollision.posY(), mcCollision.posZ(), + px, py, pz, pdg, mult, minDistanceMC[iTF][bcInTF], + recoFlags, recoCollisionIds, isSignal); + } + } + + auto hTVX = registry.get(HIST("hTVX")); + auto hTVXRCT = registry.get(HIST("hTVXRCT")); + + std::vector bcsWithFT0, bcsWithFV0, bcsWithFDD; + bcsWithFT0.reserve(ft0s.size()); + bcsWithFV0.reserve(fv0s.size()); + bcsWithFDD.reserve(fdds.size()); + + for (const auto& ft0 : ft0s) { + const auto bc = ft0.bc_as(); + const auto gbc = bc.globalBC(); + const auto bcInOrbit = gbc % NBCsPerOrbit; + if (ft0.timeA() < MaxFITTime || ft0.timeC() < MaxFITTime) { + bcsWithFT0.push_back(gbc); + } + if (!collidingBCs[bcInOrbit] || !(ft0.triggerMask() & (1U << o2::fit::Triggers::bitVertex))) { + continue; + } + hTVX->Fill(bcInOrbit); + if (!bc.selection_bit(aod::evsel::kNoTimeFrameBorder) || !rctChecker(bc)) { + continue; + } + hTVXRCT->Fill(bcInOrbit); + } + for (const auto& fv0 : fv0s) { + if (fv0.time() < MaxFITTime) { + bcsWithFV0.push_back(fv0.bc_as().globalBC()); + } + } + for (const auto& fdd : fdds) { + if (fdd.timeA() < MaxFITTime || fdd.timeC() < MaxFITTime) { + bcsWithFDD.push_back(fdd.bc_as().globalBC()); + } + } + + const uint32_t scanDistance = std::max(MaxStoredDistance, vetoBCWindow.value); + const DistanceMap minDistanceFT0 = buildMinimumDistanceMap(tfIDs, bcSOR, nBCsPerTF, bcsWithFT0, scanDistance); + const DistanceMap minDistanceFV0 = buildMinimumDistanceMap(tfIDs, bcSOR, nBCsPerTF, bcsWithFV0, scanDistance); + const DistanceMap minDistanceFDD = buildMinimumDistanceMap(tfIDs, bcSOR, nBCsPerTF, bcsWithFDD, scanDistance); + + auto hVetoT00 = registry.get(HIST("hVetoT00")); + auto hVetoTV0 = registry.get(HIST("hVetoTV0")); + auto hVetoTVD = registry.get(HIST("hVetoTVD")); + auto hVetoT00RCT = registry.get(HIST("hVetoT00RCT")); + auto hVetoTV0RCT = registry.get(HIST("hVetoTV0RCT")); + auto hVetoTVDRCT = registry.get(HIST("hVetoTVDRCT")); + for (size_t iTF = 0; iTF < tfIDs.size(); ++iTF) { + const int64_t tfStartBC = bcSOR + static_cast(tfIDs[iTF]) * nBCsPerTF; + for (int64_t bcInTF = tfStartBorder + 1; bcInTF < nBCsPerTF - tfEndBorder; ++bcInTF) { + const int64_t globalBC = tfStartBC + bcInTF; + const int bcInOrbit = globalBC % NBCsPerOrbit; + if (!collidingBCs[bcInOrbit]) { + continue; + } + const auto distanceFT0 = minDistanceFT0[iTF][bcInTF]; + const auto distanceFV0 = minDistanceFV0[iTF][bcInTF]; + const auto distanceFDD = minDistanceFDD[iTF][bcInTF]; + fillVetoHistograms(hVetoT00, hVetoTV0, hVetoTVD, bcInOrbit, distanceFT0, distanceFV0, distanceFDD); + if (tfPassesRCT[iTF] != 0u) { + fillVetoHistograms(hVetoT00RCT, hVetoTV0RCT, hVetoTVDRCT, bcInOrbit, distanceFT0, distanceFV0, distanceFDD); + } + } + } + + for (const auto& collision : collisions) { + if (collision.numContrib() != nTracks || !collision.selection_bit(aod::evsel::kNoTimeFrameBorder) || !rctChecker(collision)) { + continue; + } + auto bc = collision.template bc_as(); + auto gbc = bc.globalBC(); + const auto iTF = localTFIndex[bc.globalIndex()]; + const int64_t bcInTF = (static_cast(gbc) - bcSOR) % nBCsPerTF; + const auto distFT0 = minDistanceFT0[iTF][bcInTF]; + const auto distFV0 = minDistanceFV0[iTF][bcInTF]; + const auto distFDD = minDistanceFDD[iTF][bcInTF]; + const auto vetoWindow = static_cast(vetoBCWindow.value); + if (vetoBCWindow.value >= 0 && (((vetoFT0.value != 0) && distFT0 <= vetoWindow) || ((vetoFV0.value != 0) && distFV0 <= vetoWindow) || ((vetoFDD.value != 0) && distFDD <= vetoWindow))) { + continue; + } + std::vector px, py, pz; + std::vector tpcSignal, tpcNSigmaEl, tpcNSigmaPi, tpcNSigmaKa, tpcNSigmaPr; + std::vector tofNSigmaEl, tofNSigmaPi, tofNSigmaKa, tofNSigmaPr; + std::vector itsClusterMap; + std::vector nClusters; + std::vector sign; + std::vector newMCCollisionIds; + std::vector newParticleIds; + for (const auto& track : tracks.sliceBy(tracksPerColl, collision.globalIndex())) { + if (!track.isPVContributor() || !track.hasITS() || !track.hasTPC() || std::abs(track.eta()) > maxAbsEta.value || track.pt() < minPt.value) { + continue; + } + px.push_back(track.px()); + py.push_back(track.py()); + pz.push_back(track.pz()); + tpcSignal.push_back(track.tpcSignal()); + tpcNSigmaEl.push_back(track.tpcNSigmaEl()); + tpcNSigmaPi.push_back(track.tpcNSigmaPi()); + tpcNSigmaKa.push_back(track.tpcNSigmaKa()); + tpcNSigmaPr.push_back(track.tpcNSigmaPr()); + tofNSigmaEl.push_back(track.tofNSigmaEl()); + tofNSigmaPi.push_back(track.tofNSigmaPi()); + tofNSigmaKa.push_back(track.tofNSigmaKa()); + tofNSigmaPr.push_back(track.tofNSigmaPr()); + itsClusterMap.push_back(track.itsClusterMap()); + nClusters.push_back(track.tpcNClsFound()); + sign.push_back(track.sign()); + if constexpr (isMC) { + // Fake, background, and unmatched particles keep the -1 label + SignalRef label{NoSignalMCRef, NoSignalMCRef}; + if (track.has_mcParticle() && (track.mcMask() & MCTrackFakeMask) == 0u) { + if (const auto ref = signalParticleRefs.find(track.mcParticleId()); ref != signalParticleRefs.end()) { + label = ref->second; + } + } + newMCCollisionIds.push_back(label.first); + newParticleIds.push_back(label.second); + } + } + if (px.size() != static_cast(nTracks)) { + continue; + } + selectedCandidates(bc.runNumber(), gbc, tfIDs[iTF], bc.timestamp(), collision.posX(), collision.posY(), collision.posZ(), + px, py, pz, tpcSignal, tpcNSigmaEl, tpcNSigmaPi, tpcNSigmaKa, tpcNSigmaPr, + tofNSigmaEl, tofNSigmaPi, tofNSigmaKa, tofNSigmaPr, itsClusterMap, nClusters, sign, + std::min(distFT0, MaxStoredDistance + 1), + std::min(distFV0, MaxStoredDistance + 1), + std::min(distFDD, MaxStoredDistance + 1)); + if constexpr (isMC) { + selectedCandidateMCLabels(newMCCollisionIds, newParticleIds); + } + } + } + + void processData(CollisionsWithSels const& collisions, TracksWithPID const& tracks, BCsWithSels const& bcs, + aod::FT0s const& ft0s, aod::FV0As const& fv0s, aod::FDDs const& fdds) + { + processImpl(collisions, tracks, tracksPerCollision, bcs, ft0s, fv0s, fdds); + } + PROCESS_SWITCH(UpcCandProducerBarrel, processData, "Process reconstructed data", true); + + void processMC(CollisionsWithSels const& collisions, TracksWithPIDMC const& tracks, BCsWithSels const& bcs, + aod::FT0s const& ft0s, aod::FV0As const& fv0s, aod::FDDs const& fdds, + aod::McCollisions const& mcCollisions, aod::McParticles const& mcParticles, + aod::AmbiguousTracks const& ambiguousTracks) + { + processImpl(collisions, tracks, mcTracksPerCollision, bcs, ft0s, fv0s, fdds, + &mcCollisions, &mcParticles, &ambiguousTracks); + } + PROCESS_SWITCH(UpcCandProducerBarrel, processMC, "Process reconstructed MC and write compact MC truth", false); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& context) { return WorkflowSpec{adaptAnalysisTask(context)}; } diff --git a/PWGUD/Tasks/CMakeLists.txt b/PWGUD/Tasks/CMakeLists.txt index 7244f33fb0e..bfe050bbe04 100644 --- a/PWGUD/Tasks/CMakeLists.txt +++ b/PWGUD/Tasks/CMakeLists.txt @@ -110,7 +110,7 @@ o2physics_add_dpl_workflow(upc-cand-analyzer COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(upc-cand-producer-qa - SOURCES upcCandidateProducerQa.cpp + SOURCES upcCandidateProducerQa.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2::DetectorsBase COMPONENT_NAME Analysis) diff --git a/PWGUD/Tasks/diffMCDataScanner.cxx b/PWGUD/Tasks/diffMCDataScanner.cxx index 06fa70f5220..6b945059121 100644 --- a/PWGUD/Tasks/diffMCDataScanner.cxx +++ b/PWGUD/Tasks/diffMCDataScanner.cxx @@ -163,7 +163,7 @@ struct collisionsInfo { // count tracks int cntAll = 0; int netCharge = 0; - for (auto track : tracks) { + for (const auto& track : tracks) { cntAll++; netCharge += track.sign(); } @@ -198,7 +198,7 @@ struct collisionsInfo { // loop over FWD tracks LOGF(info, "FWD tracks: %i", fwdtracks.size()); - for (auto fwdtrack : fwdtracks) { + for (const auto& fwdtrack : fwdtracks) { registry.get(HIST("etaFWDAll"))->Fill(fwdtrack.eta()); } @@ -213,7 +213,7 @@ struct collisionsInfo { // registry.get(HIST("globalVsMFTDG"))->Fill(cntGlobal, mfttracks.size()); // loop over FWD tracks - for (auto fwdtrack : fwdtracks) { + for (const auto& fwdtrack : fwdtracks) { registry.get(HIST("etaFWDDG"))->Fill(fwdtrack.eta()); } } @@ -251,7 +251,7 @@ struct BCInfo { // count collisions with good time resoluton auto nColGT = 0; - for (auto col : cols) { + for (const auto& col : cols) { if (col.collisionTimeRes() <= 20.) { nColGT++; } @@ -311,7 +311,7 @@ struct TrackTypes { void process(TCs const& tracks, /*MTs const& mfttracks,*/ FTs const& fwdtracks) { - for (auto track : tracks) { + for (const auto& track : tracks) { LOGF(debug, "isGlobal %i Detector map %i %i %i %i time resolution %f", track.isGlobalTrack(), track.hasITS(), track.hasTPC(), track.hasTRD(), track.hasTOF(), track.trackTimeRes()); @@ -353,7 +353,7 @@ struct TrackTypes { // ForwardTrackTypeEnum has 5 values auto nTypes = 5; - for (auto fwdtrack : fwdtracks) { + for (const auto& fwdtrack : fwdtracks) { registry.get(HIST("FwdType"))->Fill(0., 0., 1.); if (fwdtrack.collisionId() >= 0) { registry.get(HIST("FwdType"))->Fill(1., 0., 1.); @@ -379,7 +379,7 @@ struct MCTracks { void process(CCs const& collisions, aod::McCollisions& /*McCols*/, aod::McParticles& McParts) { - for (auto collision : collisions) { + for (const auto& collision : collisions) { // get McCollision which belongs to collision auto MCCol = collision.mcCollision(); @@ -397,7 +397,7 @@ struct MCTracks { bool hasDiff = false; int prongs = 0; - for (auto mcpart : MCPartSlice) { + for (const auto& mcpart : MCPartSlice) { LOGF(info, " MCPart: %i %i %i %i %i - %i", mcpart.mcCollisionId(), mcpart.isPhysicalPrimary(), mcpart.getProcess(), mcpart.getGenStatusCode(), mcpart.globalIndex(), mcpart.pdgCode()); if (mcpart.pdgCode() == 9900110) { LOGF(info, " rho_diff0 energy: %f", mcpart.e()); @@ -413,8 +413,8 @@ struct MCTracks { // } if (hasDiff && mothers.size() > 1) { - auto mom1 = mothers[0]; - auto mom2 = mothers[1]; + const auto& mom1 = mothers[0]; + const auto& mom2 = mothers[1]; if (mcpart.isPhysicalPrimary() && (mcpart.getGenStatusCode() == 1 || mcpart.getGenStatusCode() == 2) && mom1.globalIndex() != mom2.globalIndex() && @@ -456,7 +456,7 @@ struct TPCnSigma { void process(TCwPIDs& tracks, aod::McParticles const& /*mcParticles*/) { - for (auto track : tracks) { + for (const auto& track : tracks) { if (track.isGlobalTrack()) { nSigmas(track.mcParticle_as().pdgCode(), track.mcParticle_as().pt(), track.tpcNSigmaEl(), track.tpcNSigmaMu(), track.tpcNSigmaPi(), diff --git a/PWGUD/Tasks/diffQA.cxx b/PWGUD/Tasks/diffQA.cxx index 59bdd9a67eb..edecda89087 100644 --- a/PWGUD/Tasks/diffQA.cxx +++ b/PWGUD/Tasks/diffQA.cxx @@ -657,7 +657,7 @@ struct DiffQA { int64_t lastBCwFV0 = fv0s.begin().bc_as().globalBC(); auto lastOrbit = lastBCwFV0 / o2::constants::lhc::LHCMaxBunches; - for (auto fv0 : fv0s) { + for (const auto& fv0 : fv0s) { // side A for (size_t ind = 0; ind < fv0.channel().size(); ind++) { @@ -692,7 +692,7 @@ struct DiffQA { int64_t lastBCwFT0 = ft0s.begin().bc_as().globalBC(); auto lastOrbit = lastBCwFT0 / o2::constants::lhc::LHCMaxBunches; - for (auto ft0 : ft0s) { + for (const auto& ft0 : ft0s) { // side A for (size_t ind = 0; ind < ft0.channelA().size(); ind++) { @@ -883,7 +883,7 @@ struct DiffQA { int64_t lastBCwFDD = fdds.begin().bc_as().globalBC(); auto lastOrbit = lastBCwFDD / o2::constants::lhc::LHCMaxBunches; - for (auto fdd : fdds) { + for (const auto& fdd : fdds) { // side A for (auto ind = 0; ind < 8; ind++) { @@ -947,7 +947,7 @@ struct DiffQA { void processTest(CCs const& collisions, BCs const& bcs) { uint64_t bc1, bc2, bc3; - for (auto col : collisions) { + for (const auto& col : collisions) { bc1 = -1; bc2 = -2; bc3 = -3; diff --git a/PWGUD/Tasks/eventByevent.cxx b/PWGUD/Tasks/eventByevent.cxx index 913319bd785..a146e3ea993 100644 --- a/PWGUD/Tasks/eventByevent.cxx +++ b/PWGUD/Tasks/eventByevent.cxx @@ -242,7 +242,7 @@ struct EventByEvent { return; registry.fill(HIST("hSelectionCounter"), 5); - for (auto t : tracks) { + for (const auto& t : tracks) { if (!trackselector(t, parameters)) continue; @@ -270,14 +270,14 @@ struct EventByEvent { registry.fill(HIST("hSelectionCounter"), 6); if ((rawPionTracks.size() >= 2) && (allTracks.size() >= 2)) { - for (auto pion : onlyPionTracks) { + for (const auto& pion : onlyPionTracks) { p += pion; } registry.fill(HIST("h4TracksPions"), onlyPionTracks.size()); registry.fill(HIST("hSelectionCounter"), 7); - for (auto rtrk : rawPionTracks) { + for (const auto& rtrk : rawPionTracks) { TLorentzVector itrk; itrk.SetXYZM(rtrk.px(), rtrk.py(), rtrk.pz(), o2::constants::physics::MassPionCharged); @@ -293,7 +293,7 @@ struct EventByEvent { int sign = 0; TLorentzVector piplus, piminus; - for (auto rawPion : rawPionTracks) { + for (const auto& rawPion : rawPionTracks) { sign += rawPion.sign(); } diff --git a/PWGUD/Tasks/exclusivePentaquark.cxx b/PWGUD/Tasks/exclusivePentaquark.cxx index 8f21b5f333f..ed5b440add0 100644 --- a/PWGUD/Tasks/exclusivePentaquark.cxx +++ b/PWGUD/Tasks/exclusivePentaquark.cxx @@ -135,7 +135,7 @@ struct ExclusivePentaquark { std::vector rawProtonTracks; std::vector rawProtonTracksTOF; - for (auto trk : tracks) { + for (const auto& trk : tracks) { if (!trk.isPVContributor()) { continue; } diff --git a/PWGUD/Tasks/exclusivePhi.cxx b/PWGUD/Tasks/exclusivePhi.cxx index 499f8e1046f..465d6f4ac0e 100644 --- a/PWGUD/Tasks/exclusivePhi.cxx +++ b/PWGUD/Tasks/exclusivePhi.cxx @@ -48,9 +48,9 @@ struct ExclusivePhi { HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; //_____________________________________________________________________________ - Double_t CosThetaHelicityFrame(TLorentzVector pionPositive, - TLorentzVector pionNegative, - TLorentzVector possibleRhoZero) + Double_t CosThetaHelicityFrame(const TLorentzVector& pionPositive, + const TLorentzVector& pionNegative, + const TLorentzVector& possibleRhoZero) { Double_t HalfSqrtSnn = 2680.; @@ -77,7 +77,7 @@ struct ExclusivePhi { return CosThetaHE; } //------------------------------------------------------------------------------------------------------ - Double_t PhiHelicityFrame(TLorentzVector muonPositive, TLorentzVector muonNegative, TLorentzVector possibleJPsi) + Double_t PhiHelicityFrame(const TLorentzVector& muonPositive, const TLorentzVector& muonNegative, const TLorentzVector& possibleJPsi) { // Half of the energy per pair of the colliding nucleons. @@ -266,7 +266,7 @@ struct ExclusivePhi { std::vector onlyKaonSigma; std::vector rawKaonTracks; - for (auto trk : tracks) { + for (const auto& trk : tracks) { registry.fill(HIST("hSelectionCounter"), 1); if (!trk.isPVContributor()) { continue; @@ -323,7 +323,7 @@ struct ExclusivePhi { if (onlyKaonTracks.size() == 2) { registry.fill(HIST("hSelectionCounter"), 7); - for (auto kaon : onlyKaonTracks) { + for (const auto& kaon : onlyKaonTracks) { phi += kaon; } @@ -373,7 +373,7 @@ struct ExclusivePhi { std::vector allTracksAreITSonlyAndFourITSclusters; int counter = 0; - for (auto t : tracks) { + for (const auto& t : tracks) { registry.fill(HIST("hSelectionCounter2"), 0); if (!t.isPVContributor()) { continue; @@ -466,16 +466,16 @@ struct ExclusivePhi { // if ((collision.posZ() < -10) || (collision.posZ() > 10)) { if (allTracksAreKaons.size() == 2) { registry.fill(HIST("hSelectionCounter2"), 7); - for (auto kaon : allTracksAreKaons) { + for (const auto& kaon : allTracksAreKaons) { phiWithoutPID += kaon; } registry.fill(HIST("hTracksKaons"), allTracksAreKaons.size()); // kaon mass hypothesis with wrong momentum for one track - for (auto kaon : allTracksAreKaonsWrongMomentum) { + for (const auto& kaon : allTracksAreKaonsWrongMomentum) { phiWrongMomentaWithoutPID += kaon; } // pion mass hypothesis - for (auto pion : allTracksArePions) { + for (const auto& pion : allTracksArePions) { phiWithoutPIDPionHypothesis += pion; } @@ -619,7 +619,7 @@ struct ExclusivePhi { if (allTracksAreKaonsBandPID.size() == 2) { TLorentzVector reallyPhi; - for (auto kaon : allTracksAreKaonsBandPID) { + for (const auto& kaon : allTracksAreKaonsBandPID) { reallyPhi += kaon; } diff --git a/PWGUD/Tasks/exclusivePhiLeptons.cxx b/PWGUD/Tasks/exclusivePhiLeptons.cxx index ae4e80c31ed..9576ece02b5 100644 --- a/PWGUD/Tasks/exclusivePhiLeptons.cxx +++ b/PWGUD/Tasks/exclusivePhiLeptons.cxx @@ -157,7 +157,7 @@ struct ExclusivePhiLeptons { std::vector rawElectronTracksTOF; int counterPV = 0; - for (auto trk : tracks) { + for (const auto& trk : tracks) { if (!trk.isPVContributor()) { continue; } diff --git a/PWGUD/Tasks/exclusivePhiLeptonsTrees.cxx b/PWGUD/Tasks/exclusivePhiLeptonsTrees.cxx index 577f25e63c6..5a7ccd7a315 100644 --- a/PWGUD/Tasks/exclusivePhiLeptonsTrees.cxx +++ b/PWGUD/Tasks/exclusivePhiLeptonsTrees.cxx @@ -144,7 +144,7 @@ struct ExclusivePhiLeptonsTrees { // - (px,py,pz,E)1 // - (px,py,pz,E)2 int counterPV = 0; - for (auto trk : tracks) { + for (const auto& trk : tracks) { // ---------------------------------------- // SELECTIONS: // - PV track diff --git a/PWGUD/Tasks/exclusiveRhoTo4Pi.cxx b/PWGUD/Tasks/exclusiveRhoTo4Pi.cxx index c295a40df6e..c508c0b30dd 100644 --- a/PWGUD/Tasks/exclusiveRhoTo4Pi.cxx +++ b/PWGUD/Tasks/exclusiveRhoTo4Pi.cxx @@ -1202,7 +1202,7 @@ struct ExclusiveRhoTo4Pi { PROCESS_SWITCH(ExclusiveRhoTo4Pi, processEventCounterMC, "MC Event Counter Function", false); PROCESS_SWITCH(ExclusiveRhoTo4Pi, processTrackCounterMC, "MC Track Counter Function", false); - double collinSoperPhi(PxPyPzMVector twoPionVector, PxPyPzMVector fourPionVector) + double collinSoperPhi(const PxPyPzMVector& twoPionVector, const PxPyPzMVector& fourPionVector) { PxPyPzEVector pProjCM(0., 0., -momentumBeam, halfSqrtSnn * 208); // projectile PxPyPzEVector pTargCM(0., 0., momentumBeam, halfSqrtSnn * 208); // target @@ -1219,7 +1219,7 @@ struct ExclusiveRhoTo4Pi { return phi; } - double collinSoperCosTheta(PxPyPzMVector twoPionVector, PxPyPzMVector fourPionVector) + double collinSoperCosTheta(const PxPyPzMVector& twoPionVector, const PxPyPzMVector& fourPionVector) { PxPyPzEVector pProjCM(0., 0., -momentumBeam, halfSqrtSnn * 208); // projectile PxPyPzEVector pTargCM(0., 0., momentumBeam, halfSqrtSnn * 208); // target diff --git a/PWGUD/Tasks/exclusiveTwoProtons.cxx b/PWGUD/Tasks/exclusiveTwoProtons.cxx index bc3c4783aba..3b0b081dc86 100644 --- a/PWGUD/Tasks/exclusiveTwoProtons.cxx +++ b/PWGUD/Tasks/exclusiveTwoProtons.cxx @@ -50,7 +50,7 @@ struct ExclusiveTwoProtons { // defining histograms using histogram registry HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; //_____________________________________________________________________________ - Double_t CosThetaHelicityFrame(TLorentzVector posDaughter, TLorentzVector negDaughter, TLorentzVector mother) + Double_t CosThetaHelicityFrame(const TLorentzVector& posDaughter, const TLorentzVector& negDaughter, const TLorentzVector& mother) { Double_t HalfSqrtSnn = 2680.; @@ -77,7 +77,7 @@ struct ExclusiveTwoProtons { return CosThetaHE; } //------------------------------------------------------------------------------------------------------ - Double_t PhiHelicityFrame(TLorentzVector posDaughter, TLorentzVector negDaughter, TLorentzVector mother) + Double_t PhiHelicityFrame(const TLorentzVector& posDaughter, const TLorentzVector& negDaughter, const TLorentzVector& mother) { // Half of the energy per pair of the colliding nucleons. @@ -190,7 +190,7 @@ struct ExclusiveTwoProtons { std::vector rawProtonTracks; std::vector rawProtonTracksTOF; - for (auto trk : tracks) { + for (const auto& trk : tracks) { if (!trk.isPVContributor()) { continue; } diff --git a/PWGUD/Tasks/exclusiveTwoProtonsSG.cxx b/PWGUD/Tasks/exclusiveTwoProtonsSG.cxx index 7d8e3ed9326..def67ca1bd0 100644 --- a/PWGUD/Tasks/exclusiveTwoProtonsSG.cxx +++ b/PWGUD/Tasks/exclusiveTwoProtonsSG.cxx @@ -53,7 +53,7 @@ struct ExclusiveTwoProtonsSG { // defining histograms using histogram registry HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; //_____________________________________________________________________________ - Double_t CosThetaHelicityFrame(TLorentzVector posDaughter, TLorentzVector negDaughter, TLorentzVector mother) + Double_t CosThetaHelicityFrame(const TLorentzVector& posDaughter, const TLorentzVector& negDaughter, const TLorentzVector& mother) { Double_t HalfSqrtSnn = 2680.; @@ -80,7 +80,7 @@ struct ExclusiveTwoProtonsSG { return CosThetaHE; } //------------------------------------------------------------------------------------------------------ - Double_t PhiHelicityFrame(TLorentzVector posDaughter, TLorentzVector negDaughter, TLorentzVector mother) + Double_t PhiHelicityFrame(const TLorentzVector& posDaughter, const TLorentzVector& negDaughter, const TLorentzVector& mother) { // Half of the energy per pair of the colliding nucleons. @@ -211,7 +211,7 @@ struct ExclusiveTwoProtonsSG { std::vector rawProtonTracks; std::vector rawProtonTracksTOF; - for (auto trk : tracks) { + for (const auto& trk : tracks) { if (!trk.isPVContributor()) { continue; } diff --git a/PWGUD/Tasks/flowCorrelationsUpc.cxx b/PWGUD/Tasks/flowCorrelationsUpc.cxx index 57114a3f977..d708c17e5ae 100644 --- a/PWGUD/Tasks/flowCorrelationsUpc.cxx +++ b/PWGUD/Tasks/flowCorrelationsUpc.cxx @@ -281,11 +281,15 @@ struct FlowCorrelationsUpc { return false; } // if A or C gap is requested, keep corresponding neutron class - if (cfgGapSide == 0 || cfgGapSide == 1) { - if ((cfgGapSide == 0 && neutronClass == 1) || (cfgGapSide == 1 && neutronClass == 2)) { // o2-linter: disable=magic-number (ZDC time cut) - // accepted - } else { - return false; + if (cfgGapSideMerge) { + // accepted + } else { + if (cfgGapSide == 0 || cfgGapSide == 1) { + if ((cfgGapSide == 0 && neutronClass == 1) || (cfgGapSide == 1 && neutronClass == 2)) { // o2-linter: disable=magic-number (ZDC time cut) + // accepted + } else { + return false; + } } } } @@ -470,9 +474,11 @@ struct FlowCorrelationsUpc { double phi1 = RecoDecay::phi(momentum1); double eta1 = RecoDecay::eta(momentum1); - float weff1 = 1., wacc1 = 1.; + float weff1 = 1.; + if (!getEfficiencyCorrection(weff1, eta1, pt1, posZ)) + continue; if (system == SameEvent) { - registry.fill(HIST("Trig_hist"), fSampleIndex, posZ, independent, pt1, eventWeight * weff1 * wacc1); + registry.fill(HIST("Trig_hist"), fSampleIndex, posZ, independent, pt1, eventWeight * weff1); } for (auto const& track2 : tracks2) { @@ -495,7 +501,7 @@ struct FlowCorrelationsUpc { double phi2 = RecoDecay::phi(momentum2); double eta2 = RecoDecay::eta(momentum2); - float weff2 = 1., wacc2 = 1.; + float weff2 = 1.; if (mEfficiency) { weff2 = efficiencyCache[track2.filteredIndex()]; } else { @@ -505,7 +511,7 @@ struct FlowCorrelationsUpc { float deltaPhi = RecoDecay::constrainAngle(phi1 - phi2, -PIHalf); float deltaEta = eta1 - eta2; - float weight = eventWeight * weff1 * weff2 * wacc1 * wacc2; + float weight = eventWeight * weff1 * weff2; // Merging cut if (std::abs(deltaEta) < cfgCutMerging) { diff --git a/PWGUD/Tasks/flowCumulantsUpc.cxx b/PWGUD/Tasks/flowCumulantsUpc.cxx index 42ce67577ee..e7ccfdb51e4 100644 --- a/PWGUD/Tasks/flowCumulantsUpc.cxx +++ b/PWGUD/Tasks/flowCumulantsUpc.cxx @@ -640,7 +640,7 @@ struct FlowCumulantsUpc { } template - bool trackSelected(TTrack track) + bool trackSelected(const TTrack& track) { registry.fill(HIST("hTrackCount"), 0.5); if (track.pt() < cfgPtCutMin || track.pt() > cfgPtCutMax) { diff --git a/PWGUD/Tasks/flowLongRangeCorrUpc.cxx b/PWGUD/Tasks/flowLongRangeCorrUpc.cxx index bf6bc60ef98..7fbca9da958 100644 --- a/PWGUD/Tasks/flowLongRangeCorrUpc.cxx +++ b/PWGUD/Tasks/flowLongRangeCorrUpc.cxx @@ -266,7 +266,7 @@ struct FlowLongRangeCorrUpc { } template - bool trackSelected(TTrack track) + bool trackSelected(const TTrack& track) { if (track.pt() < cfgPtCutMin || track.pt() > cfgPtCutMax) { return false; @@ -334,7 +334,7 @@ struct FlowLongRangeCorrUpc { } template - double trackCounter(TTracks tracks, float posZ) + double trackCounter(const TTracks& tracks, float posZ) { float weff1 = 1; double nTracksRaw = 0.; @@ -357,7 +357,7 @@ struct FlowLongRangeCorrUpc { } template - void fillYield(TCollision collision, TTracks tracks) // function to fill the yield and etaphi histograms. + void fillYield(const TCollision& collision, const TTracks& tracks) // function to fill the yield and etaphi histograms. { float weff1 = 1; float vtxz = collision.posZ(); @@ -385,7 +385,7 @@ struct FlowLongRangeCorrUpc { } template - void fillCorrelationsTPCFT0(TTracks tracks1, aod::UDCollisionFITBits const& fitBits, float posZ, int system, int corType) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms + void fillCorrelationsTPCFT0(const TTracks& tracks1, aod::UDCollisionFITBits const& fitBits, float posZ, int system, int corType) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms { if (fitBits.size() > 1) { LOGF(fatal, "fillCorrelationsTPCFT0(): fitBits.size() = %d (expected 0 or 1)", fitBits.size()); diff --git a/PWGUD/Tasks/fwdMuonsUpc.cxx b/PWGUD/Tasks/fwdMuonsUpc.cxx index e7c684064c6..42f0cf8b290 100644 --- a/PWGUD/Tasks/fwdMuonsUpc.cxx +++ b/PWGUD/Tasks/fwdMuonsUpc.cxx @@ -379,7 +379,7 @@ struct FwdMuonsUpc { } // function to compute phi for azimuth anisotropy - void computePhiAnis(ROOT::Math::PxPyPzMVector p1, ROOT::Math::PxPyPzMVector p2, int sign1, float& phiAverage, float& phiCharge) + void computePhiAnis(const ROOT::Math::PxPyPzMVector& p1, const ROOT::Math::PxPyPzMVector& p2, int sign1, float& phiAverage, float& phiCharge) { ROOT::Math::PxPyPzMVector tSum, tDiffAv, tDiffCh; tSum = p1 + p2; diff --git a/PWGUD/Tasks/polarisationRho.cxx b/PWGUD/Tasks/polarisationRho.cxx index 386bd5de510..e320f606f0d 100644 --- a/PWGUD/Tasks/polarisationRho.cxx +++ b/PWGUD/Tasks/polarisationRho.cxx @@ -48,9 +48,9 @@ struct PolarisationRho { HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; //_____________________________________________________________________________ - Double_t CosThetaHelicityFrame(TLorentzVector pionPositive, - TLorentzVector pionNegative, - TLorentzVector possibleRhoZero) + Double_t CosThetaHelicityFrame(const TLorentzVector& pionPositive, + const TLorentzVector& pionNegative, + const TLorentzVector& possibleRhoZero) { Double_t HalfSqrtSnn = 2680.; @@ -77,7 +77,7 @@ struct PolarisationRho { return CosThetaHE; } //------------------------------------------------------------------------------------------------------ - Double_t PhiHelicityFrame(TLorentzVector muonPositive, TLorentzVector muonNegative, TLorentzVector possibleJPsi) + Double_t PhiHelicityFrame(const TLorentzVector& muonPositive, const TLorentzVector& muonNegative, const TLorentzVector& possibleJPsi) { // Half of the energy per pair of the colliding nucleons. @@ -241,7 +241,7 @@ struct PolarisationRho { std::vector onlyKaonTracks; std::vector onlyKaonSigma; std::vector rawKaonTracks; - for (auto t : tracks) { + for (const auto& t : tracks) { if (!t.isPVContributor()) { continue; } @@ -260,7 +260,7 @@ struct PolarisationRho { //_____________________________________ // Creating phis if (onlyKaonTracks.size() == 2) { - for (auto kaon : onlyKaonTracks) { + for (const auto& kaon : onlyKaonTracks) { phi += kaon; } registry.fill(HIST("hNsigEvsKa1"), rawKaonTracks[0].tpcNSigmaKa(), rawKaonTracks[1].tpcNSigmaKa()); @@ -276,7 +276,7 @@ struct PolarisationRho { std::vector allTracksAreKaonsWrongMomentum; std::vector allTracksArePions; int counter = 0; - for (auto t : tracks) { + for (const auto& t : tracks) { if (!t.isPVContributor()) { continue; } @@ -304,13 +304,13 @@ struct PolarisationRho { //_____________________________________ // Creating phis if (allTracksAreKaons.size() == 2) { - for (auto kaon : allTracksAreKaons) { + for (const auto& kaon : allTracksAreKaons) { phiWithoutPID += kaon; } - for (auto kaon : allTracksAreKaonsWrongMomentum) { + for (const auto& kaon : allTracksAreKaonsWrongMomentum) { phiWrongMomentaWithoutPID += kaon; } - for (auto pion : allTracksArePions) { + for (const auto& pion : allTracksArePions) { phiWithoutPIDPionHypothesis += pion; } if (phiWithoutPID.M() < 1.05) { @@ -336,7 +336,7 @@ struct PolarisationRho { std::vector rawPionTracks; registry.fill(HIST("hTracks"), tracks.size()); float sign = 1.; - for (auto t : tracks) { + for (const auto& t : tracks) { if (!t.isPVContributor()) { continue; } @@ -361,7 +361,7 @@ struct PolarisationRho { registry.fill(HIST("hTracksPions"), onlyPionTracks.size()); //_____________________________________ // Creating rhos - for (auto pion : onlyPionTracks) { + for (const auto& pion : onlyPionTracks) { p += pion; } //_____________________________________ @@ -369,7 +369,7 @@ struct PolarisationRho { if (onlyPionTracks.size() == 4) { registry.fill(HIST("hMassFourPions"), p.M()); int signSum = 0; - for (auto rawPion : rawPionTracks) { + for (const auto& rawPion : rawPionTracks) { if (rawPion.sign() > 0) { signSum += 1; } else if (rawPion.sign() < 0) { @@ -385,7 +385,7 @@ struct PolarisationRho { if (onlyPionTracks.size() == 6) { registry.fill(HIST("hMassSixPions"), p.M()); int signSum = 0; - for (auto rawPion : rawPionTracks) { + for (const auto& rawPion : rawPionTracks) { if (rawPion.sign() > 0) { signSum += 1; } else if (rawPion.sign() < 0) { @@ -394,7 +394,7 @@ struct PolarisationRho { } if (signSum == 0) { registry.fill(HIST("hMassSixPionsRightSign"), p.M()); - for (auto pion : onlyPionTracks) { + for (const auto& pion : onlyPionTracks) { registry.fill(HIST("hPhiEtaSixPionsRightSign"), pion.Phi(), pion.Eta()); } } diff --git a/PWGUD/Tasks/sgExcUniverse.cxx b/PWGUD/Tasks/sgExcUniverse.cxx index a02a30b621d..3b1d0c3f8fb 100644 --- a/PWGUD/Tasks/sgExcUniverse.cxx +++ b/PWGUD/Tasks/sgExcUniverse.cxx @@ -140,7 +140,7 @@ struct SGExcUniverse { std::vector iskaon; std::vector ismuon; std::vector iselec; - for (auto t : tracks) { + for (const auto& t : tracks) { TLorentzVector a; if (trackselector(t, parameters)) { px.push_back(t.px()); diff --git a/PWGUD/Tasks/sgExclusivePhi.cxx b/PWGUD/Tasks/sgExclusivePhi.cxx index a68d9ba8cdb..f93a46d578f 100644 --- a/PWGUD/Tasks/sgExclusivePhi.cxx +++ b/PWGUD/Tasks/sgExclusivePhi.cxx @@ -57,9 +57,9 @@ struct sgExclusivePhi { HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; //_____________________________________________________________________________ - Double_t CosThetaHelicityFrame(TLorentzVector pionPositive, - TLorentzVector pionNegative, - TLorentzVector possibleRhoZero) + Double_t CosThetaHelicityFrame(const TLorentzVector& pionPositive, + const TLorentzVector& pionNegative, + const TLorentzVector& possibleRhoZero) { Double_t HalfSqrtSnn = 2680.; @@ -86,7 +86,7 @@ struct sgExclusivePhi { return CosThetaHE; } //------------------------------------------------------------------------------------------------------ - Double_t PhiHelicityFrame(TLorentzVector muonPositive, TLorentzVector muonNegative, TLorentzVector possibleJPsi) + Double_t PhiHelicityFrame(const TLorentzVector& muonPositive, const TLorentzVector& muonNegative, const TLorentzVector& possibleJPsi) { // Half of the energy per pair of the colliding nucleons. @@ -296,7 +296,7 @@ struct sgExclusivePhi { std::vector onlyKaonSigma; std::vector rawKaonTracks; - for (auto trk : tracks) { + for (const auto& trk : tracks) { registry.fill(HIST("hSelectionCounter"), 1); if (!trk.isPVContributor()) { continue; @@ -357,7 +357,7 @@ struct sgExclusivePhi { if (onlyKaonTracks.size() == 2) { registry.fill(HIST("hSelectionCounter"), 7); - for (auto kaon : onlyKaonTracks) { + for (const auto& kaon : onlyKaonTracks) { phi += kaon; } @@ -409,7 +409,7 @@ struct sgExclusivePhi { std::vector booleanAvgClusterSizePerTrackITSonly; int counter = 0; - for (auto t : tracks) { + for (const auto& t : tracks) { registry.fill(HIST("hSelectionCounter2"), 0); if (!t.isPVContributor()) { continue; @@ -521,16 +521,16 @@ struct sgExclusivePhi { if (fabs(collision.posZ()) < 10.) { if (allTracksAreKaons.size() == 2) { registry.fill(HIST("hSelectionCounter2"), 7); - for (auto kaon : allTracksAreKaons) { + for (const auto& kaon : allTracksAreKaons) { phiWithoutPID += kaon; } registry.fill(HIST("hTracksKaons"), allTracksAreKaons.size()); // kaon mass hypothesis with wrong momentum for one track - for (auto kaon : allTracksAreKaonsWrongMomentum) { + for (const auto& kaon : allTracksAreKaonsWrongMomentum) { phiWrongMomentaWithoutPID += kaon; } // pion mass hypothesis - for (auto pion : allTracksArePions) { + for (const auto& pion : allTracksArePions) { phiWithoutPIDPionHypothesis += pion; } @@ -674,7 +674,7 @@ struct sgExclusivePhi { if (allTracksAreKaonsBandPID.size() == 2) { TLorentzVector reallyPhi; - for (auto kaon : allTracksAreKaonsBandPID) { + for (const auto& kaon : allTracksAreKaonsBandPID) { reallyPhi += kaon; } diff --git a/PWGUD/Tasks/sgExclusivePhiITSselections.cxx b/PWGUD/Tasks/sgExclusivePhiITSselections.cxx index d3d8a580b4b..36bb5a2d5e0 100644 --- a/PWGUD/Tasks/sgExclusivePhiITSselections.cxx +++ b/PWGUD/Tasks/sgExclusivePhiITSselections.cxx @@ -168,7 +168,7 @@ struct sgExclusivePhiITSselections { std::vector allTracksAreKaons; std::vector allTracksAreKaonsBandPID; std::vector allTracksAreITSonlyAndFourITSclusters; - for (auto t : tracks) { + for (const auto& t : tracks) { registry.fill(HIST("hSelectionCounter2"), 0); if (!t.isPVContributor()) { continue; @@ -267,7 +267,7 @@ struct sgExclusivePhiITSselections { // in the case that there are ONLY 2 PV if (allTracksAreKaons.size() == 2) { registry.fill(HIST("hSelectionCounter2"), 7); - for (auto kaon : allTracksAreKaons) { + for (const auto& kaon : allTracksAreKaons) { phiWithoutPID += kaon; } registry.fill(HIST("hTracksKaons"), allTracksAreKaons.size()); @@ -314,7 +314,7 @@ struct sgExclusivePhiITSselections { if (allTracksAreKaonsBandPID.size() == 2) { registry.fill(HIST("hTracksKaons"), allTracksAreKaonsBandPID.size() + 10); TLorentzVector reallyPhi; - for (auto kaon : allTracksAreKaonsBandPID) { + for (const auto& kaon : allTracksAreKaonsBandPID) { reallyPhi += kaon; } registry.fill(HIST("KaonBandPHI/hPtPhiIdentifiedKaons"), reallyPhi.Pt()); diff --git a/PWGUD/Tasks/sgFITAnalyzer.cxx b/PWGUD/Tasks/sgFITAnalyzer.cxx index f3369b3a7cb..de44924b0a2 100644 --- a/PWGUD/Tasks/sgFITAnalyzer.cxx +++ b/PWGUD/Tasks/sgFITAnalyzer.cxx @@ -411,7 +411,7 @@ struct SGFITAnalyzer { std::vector goodTracks; std::vector muonTracks; float sign = 0; - for (auto t : dgtracks) { + for (const auto& t : dgtracks) { TLorentzVector a; TLorentzVector b; a.SetXYZM(t.px(), t.py(), t.pz(), mpion); @@ -424,13 +424,13 @@ struct SGFITAnalyzer { } } if (goodTracks.size() == 2) { - for (auto pion : goodTracks) { + for (const auto& pion : goodTracks) { rho += pion; } if (sign == 0 && TMath::Abs(rho.Rapidity()) < .9 && rho.M() > .5 && rho.M() < 1.2 && rho.Pt() < 0.1) coh_rho0 = true; if (muonTracks.size() == 2) { - for (auto muon : muonTracks) { + for (const auto& muon : muonTracks) { jpsi += muon; } if (sign == 0 && TMath::Abs(jpsi.Rapidity()) < .9 && jpsi.M() > 2.8 && jpsi.M() < 3.35 && jpsi.Pt() < 0.1) @@ -737,7 +737,7 @@ struct SGFITAnalyzer { registry.get(HIST("ZDC/MACZNA"))->Fill(PVContributors.size(), zna); registry.get(HIST("ZDC/MACZNC"))->Fill(PVContributors.size(), znc); } - for (auto track : dgtracks) { + for (const auto& track : dgtracks) { registry.get(HIST("tracks/QCAll"))->Fill(0., 1.); registry.get(HIST("tracks/QCAll"))->Fill(1., track.hasITS() * 1.); registry.get(HIST("tracks/QCAll"))->Fill(2., track.hasTPC() * 1.); diff --git a/PWGUD/Tasks/sgFourPiAnalyzer.cxx b/PWGUD/Tasks/sgFourPiAnalyzer.cxx index ef6f1b17a0b..ff3c59d21ed 100644 --- a/PWGUD/Tasks/sgFourPiAnalyzer.cxx +++ b/PWGUD/Tasks/sgFourPiAnalyzer.cxx @@ -114,7 +114,7 @@ struct SGFourPiAnalyzer { gapSide = truegapSide; std::vector goodTracks; float sign = 0; - for (auto t : tracks) { + for (const auto& t : tracks) { int itsNCls = t.itsNCls(); // if (itsNCls) { registry.fill(HIST("ITSNCls"), itsNCls); @@ -128,7 +128,7 @@ struct SGFourPiAnalyzer { } // std::cout << goodTracks.size()< parameters = {PV_cut, dcaZ_cut, dcaXY_cut, tpcChi2_cut, tpcNClsFindable_cut, itsChi2_cut, eta_cut, pt_cut}; // check rho0 signals - for (auto t : tracks) { + for (const auto& t : tracks) { if (trackselector(t, parameters) && t.hasTPC()) { if (truegapSide == 0) { if (t.sign() > 0) { diff --git a/PWGUD/Tasks/sgPIDSpectraTable.cxx b/PWGUD/Tasks/sgPIDSpectraTable.cxx index 75b81336c3d..741281834b7 100644 --- a/PWGUD/Tasks/sgPIDSpectraTable.cxx +++ b/PWGUD/Tasks/sgPIDSpectraTable.cxx @@ -104,7 +104,7 @@ struct SGPIDSpectraTable { float tpcde, tofde, tpcmu, tofmu; TVector3 a; int goodtracks = 0; - for (auto t : tracks) { + for (const auto& t : tracks) { if (trackselector(t, parameters)) { goodtracks++; } @@ -113,7 +113,7 @@ struct SGPIDSpectraTable { return; SGevents(coll.runNumber(), coll.flags(), truegapSide, coll.energyCommonZNA(), coll.energyCommonZNC(), goodtracks, coll.occupancyInTime(), coll.hadronicRate()); // SGevents(coll.runNumber(), coll.flags()); - for (auto t : tracks) { + for (const auto& t : tracks) { if (trackselector(t, parameters)) { a.SetXYZ(t.px(), t.py(), t.pz()); tpcpi = t.hasTPC() ? t.tpcNSigmaPi() : -999; diff --git a/PWGUD/Tasks/sgSixPiAnalyzer.cxx b/PWGUD/Tasks/sgSixPiAnalyzer.cxx index ff288249dc2..bd440e01b1d 100644 --- a/PWGUD/Tasks/sgSixPiAnalyzer.cxx +++ b/PWGUD/Tasks/sgSixPiAnalyzer.cxx @@ -113,7 +113,7 @@ struct SGSixPiAnalyzer { gapSide = truegapSide; std::vector goodTracks; float sign = 0; - for (auto t : tracks) { + for (const auto& t : tracks) { int itsNCls = t.itsNCls(); // if (itsNCls) { registry.fill(HIST("ITSNCls"), itsNCls); @@ -127,7 +127,7 @@ struct SGSixPiAnalyzer { } // std::cout << goodTracks.size()< goodTracks; // Look for D0 and D0bar float sign = 0; - for (auto t : tracks) { + for (const auto& t : tracks) { int itsNCls = t.itsNCls(); // if (itsNCls) { registry.fill(HIST("ITSNCls"), itsNCls); @@ -145,7 +145,7 @@ struct SGTwoPiAnalyzer { } // std::cout << goodTracks.size()<(onlyPionTracksp.size()) == numTwoTracks && static_cast(onlyPionTracksn.size()) == numTwoTracks) { - ROOT::Math::PxPyPzMVector k1 = onlyPionTracksp.at(0); - ROOT::Math::PxPyPzMVector k2 = onlyPionTracksp.at(1); - ROOT::Math::PxPyPzMVector k3 = onlyPionTracksn.at(0); - ROOT::Math::PxPyPzMVector k4 = onlyPionTracksn.at(1); + const ROOT::Math::PxPyPzMVector& k1 = onlyPionTracksp.at(0); + const ROOT::Math::PxPyPzMVector& k2 = onlyPionTracksp.at(1); + const ROOT::Math::PxPyPzMVector& k3 = onlyPionTracksn.at(0); + const ROOT::Math::PxPyPzMVector& k4 = onlyPionTracksn.at(1); phiv = k1 + k2 + k3 + k4; pair1 = k1 + k3; pair2 = k2 + k4; @@ -1109,10 +1109,10 @@ struct SginclusivePhiKstarSD { if (static_cast(onlyPionTracksp.size()) != numTwoTracks && static_cast(onlyPionTracksn.size()) != numTwoTracks) { if (static_cast(onlyPionTracksp.size()) + static_cast(onlyPionTracksn.size()) != numFourTracks) return; - ROOT::Math::PxPyPzMVector l1 = onlyPionTrackspm.at(0); - ROOT::Math::PxPyPzMVector l2 = onlyPionTrackspm.at(1); - ROOT::Math::PxPyPzMVector l3 = onlyPionTrackspm.at(2); - ROOT::Math::PxPyPzMVector l4 = onlyPionTrackspm.at(3); + const ROOT::Math::PxPyPzMVector& l1 = onlyPionTrackspm.at(0); + const ROOT::Math::PxPyPzMVector& l2 = onlyPionTrackspm.at(1); + const ROOT::Math::PxPyPzMVector& l3 = onlyPionTrackspm.at(2); + const ROOT::Math::PxPyPzMVector& l4 = onlyPionTrackspm.at(3); phiv1 = l1 + l2 + l3 + l4; registry.fill(HIST("os_pppp_pT_2_ls"), phiv1.M(), phiv1.Pt(), phiv1.Rapidity()); } diff --git a/PWGUD/Tasks/upcCandidateProducerQa.cpp b/PWGUD/Tasks/upcCandidateProducerQa.cxx similarity index 95% rename from PWGUD/Tasks/upcCandidateProducerQa.cpp rename to PWGUD/Tasks/upcCandidateProducerQa.cxx index 29accce2fe4..19e1deb1244 100644 --- a/PWGUD/Tasks/upcCandidateProducerQa.cpp +++ b/PWGUD/Tasks/upcCandidateProducerQa.cxx @@ -9,15 +9,20 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Common/CCDB/EventSelectionParams.h" -#include "Common/DataModel/EventSelection.h" -#include "CommonConstants/LHCConstants.h" -#include "PWGUD/Core/UPCCutparHolder.h" -#include "PWGUD/Core/UPCHelpers.h" -#include "PWGUD/DataModel/UDTables.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include using namespace o2::framework; using namespace o2::framework::expressions; diff --git a/PWGUD/Tasks/upcFwdJpsiRl.cxx b/PWGUD/Tasks/upcFwdJpsiRl.cxx index 82a21c69137..99b3e457ccf 100644 --- a/PWGUD/Tasks/upcFwdJpsiRl.cxx +++ b/PWGUD/Tasks/upcFwdJpsiRl.cxx @@ -366,7 +366,7 @@ struct UpcFwdJpsiRl { } // compute phi for azimuth anisotropy - void computePhiAnis(LorentzVec p1, LorentzVec p2, int sign1, float& phiAverage, float& phiCharge) + void computePhiAnis(const LorentzVec& p1, const LorentzVec& p2, int sign1, float& phiAverage, float& phiCharge) { auto tSum = p1 + p2; float halfUnity = 0.5; diff --git a/PWGUD/Tasks/upcJpsiCorr.cxx b/PWGUD/Tasks/upcJpsiCorr.cxx index 1732869e0d6..d0f2934069c 100644 --- a/PWGUD/Tasks/upcJpsiCorr.cxx +++ b/PWGUD/Tasks/upcJpsiCorr.cxx @@ -793,7 +793,7 @@ struct UpcJpsiCorr { } template - void fillHistograms(C collision, Ts tracks) + void fillHistograms(const C& collision, const Ts& tracks) { rStatistics.get(HIST("Statistics/hCutCounterCollisions"))->Fill(0); // number of collisions without any cuts diff --git a/PWGUD/Tasks/upcPhotonuclearAnalysisJMG.cxx b/PWGUD/Tasks/upcPhotonuclearAnalysisJMG.cxx index 25b8213263e..bc6408d3b39 100644 --- a/PWGUD/Tasks/upcPhotonuclearAnalysisJMG.cxx +++ b/PWGUD/Tasks/upcPhotonuclearAnalysisJMG.cxx @@ -551,7 +551,7 @@ struct UpcPhotonuclearAnalysisJMG { } template - void fillQAUD(const TTracks tracks, float multiplicity) + void fillQAUD(const TTracks& tracks, float multiplicity) { for (const auto& track : tracks) { if (isTrackCut(track) == false) { diff --git a/PWGUD/Tasks/upcPionAnalysis.cxx b/PWGUD/Tasks/upcPionAnalysis.cxx index 470281f0a77..afd5bbd9829 100644 --- a/PWGUD/Tasks/upcPionAnalysis.cxx +++ b/PWGUD/Tasks/upcPionAnalysis.cxx @@ -85,9 +85,9 @@ struct UPCPionAnalysis { HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; //_____________________________________________________________________________________________ - Double_t CosThetaHelicityFrame(TLorentzVector pionPositive, - TLorentzVector pionNegative, - TLorentzVector possibleRhoZero) + Double_t CosThetaHelicityFrame(const TLorentzVector& pionPositive, + const TLorentzVector& pionNegative, + const TLorentzVector& possibleRhoZero) { Double_t HalfSqrtSnn = 2680.; @@ -114,7 +114,7 @@ struct UPCPionAnalysis { return CosThetaHE; } //------------------------------------------------------------------------------------------------------ - Double_t PhiHelicityFrame(TLorentzVector piPositive, TLorentzVector piNegative, TLorentzVector possibleRho) + Double_t PhiHelicityFrame(const TLorentzVector& piPositive, const TLorentzVector& piNegative, const TLorentzVector& possibleRho) { // Half of the energy per pair of the colliding nucleons. @@ -281,7 +281,7 @@ struct UPCPionAnalysis { return q; } - double DeltaPhi(TLorentzVector lv1, TLorentzVector lv2) + double DeltaPhi(const TLorentzVector& lv1, const TLorentzVector& lv2) { TLorentzVector lv_sum = lv1 + lv2; TLorentzVector lv_diff = lv1 - lv2; @@ -492,7 +492,7 @@ struct UPCPionAnalysis { return; registry.fill(HIST("hSelectionCounter"), 5); - for (auto t : tracks) { + for (const auto& t : tracks) { /*if (!t.isPVContributor()) { continue; @@ -527,7 +527,7 @@ struct UPCPionAnalysis { registry.fill(HIST("hTracksPions"), onlyPionTracks.size()); //_____________________________________ // Creating rhos - for (auto pion : onlyPionTracks) { + for (const auto& pion : onlyPionTracks) { p += pion; } //_____________________________________ @@ -558,7 +558,7 @@ struct UPCPionAnalysis { int sign = 0; TLorentzVector piplus, piminus; - for (auto rawPion : rawPionTracks) { + for (const auto& rawPion : rawPionTracks) { sign += rawPion.sign(); if (rawPion.sign() > 0) { piplus = onlyPionTracks[0]; @@ -600,7 +600,7 @@ struct UPCPionAnalysis { registry.fill(HIST("hRap4Pion"), p.Rapidity()); registry.fill(HIST("hEta4Pion"), p.Eta()); } - for (auto pion : onlyPionTracks) { + for (const auto& pion : onlyPionTracks) { registry.fill(HIST("hPhiEtaFourPionsRightSign"), pion.Phi(), pion.Eta()); } } @@ -614,7 +614,7 @@ struct UPCPionAnalysis { int sign = 0; TLorentzVector piplus, piminus; - for (auto rawPion : rawPionTracks) { + for (const auto& rawPion : rawPionTracks) { sign += rawPion.sign(); if (rawPion.sign() > 0) { piplus = onlyPionTracks[0]; @@ -655,7 +655,7 @@ struct UPCPionAnalysis { registry.fill(HIST("hRap6Pion"), p.Rapidity()); registry.fill(HIST("hEta6Pion"), p.Eta()); registry.fill(HIST("hPt6PionRightSign"), p.Pt()); - for (auto pion : onlyPionTracks) { + for (const auto& pion : onlyPionTracks) { registry.fill(HIST("hPhiEtaSixPionsRightSign"), pion.Phi(), pion.Eta()); } } @@ -668,7 +668,7 @@ struct UPCPionAnalysis { if ((rawPionTracks.size() == 8) && (onlyPionTracks.size() == 8)) { TLorentzVector piplus, piminus; int sign = 0; - for (auto rawPion : rawPionTracks) { + for (const auto& rawPion : rawPionTracks) { sign += rawPion.sign(); if (rawPion.sign() > 0) { @@ -713,7 +713,7 @@ struct UPCPionAnalysis { registry.fill(HIST("hMPt3"), p.M(), p.Pt()); registry.fill(HIST("hRap8pion"), p.Rapidity()); registry.fill(HIST("hEta8Pion"), p.Eta()); - for (auto pion : onlyPionTracks) { + for (const auto& pion : onlyPionTracks) { registry.fill(HIST("hPhiEta8PionsRightSign"), pion.Phi(), pion.Eta()); } } diff --git a/PWGUD/Tasks/upcQuarkoniaCentralBarrel.cxx b/PWGUD/Tasks/upcQuarkoniaCentralBarrel.cxx index b87d5f3eb29..7e4996c13ba 100644 --- a/PWGUD/Tasks/upcQuarkoniaCentralBarrel.cxx +++ b/PWGUD/Tasks/upcQuarkoniaCentralBarrel.cxx @@ -230,7 +230,7 @@ struct upcQuarkoniaCentralBarrel { } template - void fillEventHistograms(TCollision collision, int& selGapSide) + void fillEventHistograms(const TCollision& collision, int& selGapSide) { // in case we want to push the analysis to Pb-Pb UPC int gapSide = collision.gapSide(); @@ -252,7 +252,7 @@ struct upcQuarkoniaCentralBarrel { } template - bool isTrackSelected(TTrack track) + bool isTrackSelected(const TTrack& track) { // // acceptance cut @@ -321,7 +321,7 @@ struct upcQuarkoniaCentralBarrel { } template - bool checkMCAssociation(TTrack track, TTrackMC trackMC) + bool checkMCAssociation(const TTrack& track, const TTrackMC& trackMC) // MC association (if asked) { if (track.sign() * trackMC.pdgCode() != 2212) @@ -332,7 +332,7 @@ struct upcQuarkoniaCentralBarrel { } template - void fillQAplot(TTrack track, bool afterSel = false) + void fillQAplot(const TTrack& track, bool afterSel = false) { // fill QA information about proton/antiproton track if (afterSel) { if (track.sign() > 0) { // Proton Candidates after selections @@ -395,7 +395,7 @@ struct upcQuarkoniaCentralBarrel { } template - void analyseTrackPairCandidate(TTrack proton, TTrack antiProton, TTrackMCs const& fullTrackMCs, uint8_t gapSide) + void analyseTrackPairCandidate(const TTrack& proton, const TTrack& antiProton, TTrackMCs const& fullTrackMCs, uint8_t gapSide) // fill information related to the quarkonium mother { float pt = RecoDecay::pt(proton.px() + antiProton.px(), proton.py() + antiProton.py()); @@ -477,7 +477,7 @@ struct upcQuarkoniaCentralBarrel { } template - void buildProtonAntiProtonPairs(TTracks const& fullTracks, TTrackMCs const& fullMCTracks, std::vector selProtonIndices, std::vector selAntiProtonIndices, uint8_t gapSide) + void buildProtonAntiProtonPairs(TTracks const& fullTracks, TTrackMCs const& fullMCTracks, const std::vector& selProtonIndices, const std::vector& selAntiProtonIndices, uint8_t gapSide) { // 1st loop over all protons for (const auto& proton : fullTracks) { diff --git a/PWGUD/Tasks/upcSemiFwdJpsiRl.cxx b/PWGUD/Tasks/upcSemiFwdJpsiRl.cxx index e9e1dfe834a..e9f7aa1e34a 100644 --- a/PWGUD/Tasks/upcSemiFwdJpsiRl.cxx +++ b/PWGUD/Tasks/upcSemiFwdJpsiRl.cxx @@ -337,7 +337,7 @@ struct UpcSemiFwdJpsiRl { } // azimuth anisotropy phi - void computePhiAnis(LorentzVec p1, LorentzVec p2, int sign1, float& phiAverage, float& phiCharge) + void computePhiAnis(const LorentzVec& p1, const LorentzVec& p2, int sign1, float& phiAverage, float& phiCharge) { auto tSum = p1 + p2; float halfUnity = 0.5; diff --git a/PWGUD/Tasks/upcTauRl.cxx b/PWGUD/Tasks/upcTauRl.cxx index 264dae05eb8..52a085ad67f 100644 --- a/PWGUD/Tasks/upcTauRl.cxx +++ b/PWGUD/Tasks/upcTauRl.cxx @@ -683,7 +683,7 @@ struct UpcTauRl { std::vector>> cutMyRequiredITSHits{}; - void mySetRequireHitsInITSLayers(int8_t minNRequiredHits, std::set requiredLayers) + void mySetRequireHitsInITSLayers(int8_t minNRequiredHits, const std::set& requiredLayers) { // layer 0 corresponds to the the innermost ITS layer cutMyRequiredITSHits.push_back(std::make_pair(minNRequiredHits, requiredLayers)); diff --git a/PWGUD/Tasks/upcTauTau13topo.cxx b/PWGUD/Tasks/upcTauTau13topo.cxx index a14ebd9cb35..d055406f509 100644 --- a/PWGUD/Tasks/upcTauTau13topo.cxx +++ b/PWGUD/Tasks/upcTauTau13topo.cxx @@ -1640,7 +1640,7 @@ struct TauTau13topo { } // helper function to calculate delta alpha - float deltaAlpha(auto particle1, auto particle2) + float deltaAlpha(const auto& particle1, const auto& particle2) { TVector3 vtmp(particle1.px(), particle1.py(), particle1.pz()); @@ -1657,7 +1657,7 @@ struct TauTau13topo { // } // float calculateDeltaPhi(TLorentzVector p, TLorentzVector p1) - float calculateDeltaPhi(ROOT::Math::LorentzVector> p, ROOT::Math::LorentzVector> p1) + float calculateDeltaPhi(const ROOT::Math::LorentzVector>& p, const ROOT::Math::LorentzVector>& p1) { // float delta = p.Phi(); float delta = RecoDecay::constrainAngle(p.Phi()); @@ -1708,7 +1708,7 @@ struct TauTau13topo { // } // helper function to calculate scalar asymmetry - float scalarAsymMC(auto particle1, auto particle2) + float scalarAsymMC(const auto& particle1, const auto& particle2) { // auto pt1 = pt(particle1.px(), particle1.py()); auto pt1 = RecoDecay::pt(particle1.px(), particle1.py()); @@ -1719,7 +1719,7 @@ struct TauTau13topo { } // helper function to calculate vector asymmetry - float vectorAsym(auto particle1, auto particle2) + float vectorAsym(const auto& particle1, const auto& particle2) { auto delta = std::sqrt((particle1.px() - particle2.px()) * (particle1.px() - particle2.px()) + (particle1.py() - particle2.py()) * (particle1.py() - particle2.py())); @@ -1796,7 +1796,7 @@ struct TauTau13topo { } template - int trackCheck(T track) + int trackCheck(const T& track) { // 1 if (track.hasITS() && !track.hasTPC() && !track.hasTRD() && !track.hasTOF()) @@ -1837,7 +1837,7 @@ struct TauTau13topo { // global track check + histogram cuts separatelly template - bool isGlobalTrackCheck(T track) + bool isGlobalTrackCheck(const T& track) { bool isGlobalTrack = true; registry.get(HIST("global/hTrackEfficiencyPVGlobal"))->Fill(0., 1.); @@ -1921,7 +1921,7 @@ struct TauTau13topo { // analysis track quality check with histogram filling template - bool isGoodTrackCheckHisto(T track) + bool isGoodTrackCheckHisto(const T& track) { bool isGoodTrack = true; registry.get(HIST("global/hTrackPVGood"))->Fill(0., 1.); @@ -1973,7 +1973,7 @@ struct TauTau13topo { // analysis track quality check template - bool isGoodTrackCheck(T track) + bool isGoodTrackCheck(const T& track) { if (!track.hasTPC()) return false; @@ -1994,7 +1994,7 @@ struct TauTau13topo { // analysis track quality check template - bool isGoodTOFTrackCheckHisto(T track) + bool isGoodTOFTrackCheckHisto(const T& track) { bool isGoodTrack = true; if (track.hasTOF()) { @@ -2012,7 +2012,7 @@ struct TauTau13topo { // analysis track quality check template - bool isGoodTOFTrackCheck(T track) + bool isGoodTOFTrackCheck(const T& track) { if (!track.hasTOF()) return false; @@ -2024,7 +2024,7 @@ struct TauTau13topo { // check ITS clusters, how many -1,0,1,7 + 10 if 0,1,2 layers were fired // analysis track quality check template - int numberOfItsClustersCheck(T track) + int numberOfItsClustersCheck(const T& track) { if (!track.hasITS()) return -1; diff --git a/Tools/KFparticle/KFUtilities.h b/Tools/KFparticle/KFUtilities.h index b6c6e607a9b..1a9a093a588 100644 --- a/Tools/KFparticle/KFUtilities.h +++ b/Tools/KFparticle/KFUtilities.h @@ -192,7 +192,7 @@ o2::track::TrackParCov getTrackParCovFromKFP(const KFParticle& kfParticle, const /// @param kfp KFParticle /// @param PV KFParticle primary vertex /// @return cpa -float cpaFromKF(KFParticle kfp, KFParticle PV) +float cpaFromKF(const KFParticle& kfp, const KFParticle& PV) { float xVtxP{}, yVtxP{}, zVtxP{}, xVtxS{}, yVtxS{}, zVtxS{}, px{}, py{}, pz{}; @@ -216,7 +216,7 @@ float cpaFromKF(KFParticle kfp, KFParticle PV) /// @param kfp KFParticle /// @param PV KFParticle primary vertex /// @return cpa in xy -float cpaXYFromKF(KFParticle kfp, KFParticle PV) +float cpaXYFromKF(const KFParticle& kfp, const KFParticle& PV) { float xVtxP{}, yVtxP{}, xVtxS{}, yVtxS{}, px{}, py{}; @@ -243,7 +243,7 @@ float cpaXYFromKF(KFParticle kfp, KFParticle PV) /// @param kfpprong1 KFParticele Prong 1 /// @param pdgdb Service PDG data base /// @return cos theta star -float cosThetaStarFromKF(int iProng, int pdgvtx, int pdgprong0, int pdgprong1, KFParticle kfpprong0, KFParticle kfpprong1, const o2::framework::Service& pdgdb) +float cosThetaStarFromKF(int iProng, int pdgvtx, int pdgprong0, int pdgprong1, const KFParticle& kfpprong0, const KFParticle& kfpprong1, const o2::framework::Service& pdgdb) { float px0{}, py0{}, pz0{}, px1{}, py1{}, pz1{}; @@ -269,7 +269,7 @@ float cosThetaStarFromKF(int iProng, int pdgvtx, int pdgprong0, int pdgprong1, K /// @param kfpParticle KFParticle /// @param Vertex KFParticle vertex /// @return impact parameter -float impParXYFromKF(KFParticle kfpParticle, KFParticle Vertex) +float impParXYFromKF(const KFParticle& kfpParticle, const KFParticle& Vertex) { float xVtxP{}, yVtxP{}, zVtxP{}, xVtxS{}, yVtxS{}, zVtxS{}, px{}, py{}, pz{}; @@ -293,7 +293,7 @@ float impParXYFromKF(KFParticle kfpParticle, KFParticle Vertex) /// @param kfpParticle KFParticle /// @param PV KFParticle primary vertex /// @return l/delta l -float ldlFromKF(KFParticle kfpParticle, KFParticle PV) +float ldlFromKF(const KFParticle& kfpParticle, const KFParticle& PV) { const float dxParticle = PV.GetX() - kfpParticle.GetX(); const float dyParticle = PV.GetY() - kfpParticle.GetY(); @@ -312,7 +312,7 @@ float ldlFromKF(KFParticle kfpParticle, KFParticle PV) /// @param kfpParticle KFParticle /// @param PV KFParticle primary vertex /// @return l/delta l in xy plane -float ldlXYFromKF(KFParticle kfpParticle, KFParticle PV) +float ldlXYFromKF(const KFParticle& kfpParticle, const KFParticle& PV) { const float dxParticle = PV.GetX() - kfpParticle.GetX(); const float dyParticle = PV.GetY() - kfpParticle.GetY(); @@ -354,7 +354,7 @@ std::array kfCalculateProngMomentumInSecondaryVertex(KFParticle track, /// @param track1 KFParticle first track (must be passed as a copy) /// @param track2 KFParticle second track (must be passed as a copy) /// @return DCA [cm] in the PCA -float kfCalculateDistanceBetweenParticles(KFParticle track1, KFParticle track2) +float kfCalculateDistanceBetweenParticles(const KFParticle& track1, const KFParticle& track2) { float dS[2]; float dsdr[4][6]; @@ -373,7 +373,7 @@ float kfCalculateDistanceBetweenParticles(KFParticle track1, KFParticle track2) /// @param track1 KFParticle first track (must be passed as a copy) /// @param track2 KFParticle second track (must be passed as a copy) /// @return chi2 in PCA -float kfCalculateChi2geoBetweenParticles(KFParticle track1, KFParticle track2) +float kfCalculateChi2geoBetweenParticles(const KFParticle& track1, const KFParticle& track2) { KFParticle kfPair; const KFParticle* kfDaughters[2] = {&track1, &track2}; diff --git a/Tools/KFparticle/qaKFEventTrack.cxx b/Tools/KFparticle/qaKFEventTrack.cxx index 2242de51154..7ff14e80c1c 100644 --- a/Tools/KFparticle/qaKFEventTrack.cxx +++ b/Tools/KFparticle/qaKFEventTrack.cxx @@ -116,7 +116,7 @@ struct qaKFEventTrack { int pVContrib = 0; void initMagneticFieldCCDB(o2::aod::BCsWithTimestamps::iterator const& bc, int& mRunNumber, - o2::framework::Service const& ccdb, std::string ccdbPathGrp, o2::base::MatLayerCylSet* lut, + o2::framework::Service const& ccdb, const std::string& ccdbPathGrp, o2::base::MatLayerCylSet* lut, bool isRun3) { @@ -536,7 +536,7 @@ struct qaKFEvent { Produces rowKFCollisions; void initMagneticFieldCCDB(o2::aod::BCsWithTimestamps::iterator const& bc, int& mRunNumber, - o2::framework::Service const& ccdb, std::string ccdbPathGrp, o2::base::MatLayerCylSet* lut, + o2::framework::Service const& ccdb, const std::string& ccdbPathGrp, o2::base::MatLayerCylSet* lut, bool isRun3) { diff --git a/Tools/KFparticle/qaKFParticle.cxx b/Tools/KFparticle/qaKFParticle.cxx index 4066ed0f49e..5dff4cd3b05 100644 --- a/Tools/KFparticle/qaKFParticle.cxx +++ b/Tools/KFparticle/qaKFParticle.cxx @@ -156,7 +156,7 @@ struct qaKFParticle { Produces rowKF; void initMagneticFieldCCDB(o2::aod::BCsWithTimestamps::iterator const& bc, int& mRunNumber, - o2::framework::Service const& ccdb, std::string ccdbPathGrp, o2::base::MatLayerCylSet* lut, + o2::framework::Service const& ccdb, const std::string& ccdbPathGrp, o2::base::MatLayerCylSet* lut, bool isRun3) { diff --git a/Tools/KFparticle/qaKFParticleLc.cxx b/Tools/KFparticle/qaKFParticleLc.cxx index 86902d349cd..eb7c68eeaa8 100644 --- a/Tools/KFparticle/qaKFParticleLc.cxx +++ b/Tools/KFparticle/qaKFParticleLc.cxx @@ -152,7 +152,7 @@ struct qaKFParticleLc { Produces rowKFLc; void initMagneticFieldCCDB(o2::aod::BCsWithTimestamps::iterator const& bc, int& mRunNumber, - o2::framework::Service const& ccdb, std::string ccdbPathGrp, o2::base::MatLayerCylSet* lut, + o2::framework::Service const& ccdb, const std::string& ccdbPathGrp, o2::base::MatLayerCylSet* lut, bool isRun3) { diff --git a/Tools/ML/MlResponse.h b/Tools/ML/MlResponse.h index cdc5a130714..393eecba293 100644 --- a/Tools/ML/MlResponse.h +++ b/Tools/ML/MlResponse.h @@ -194,6 +194,40 @@ class MlResponse return std::vector{outputPtr, outputPtr + mNClasses}; } + /// Get vector with model predictions for a batch of candidates + /// \param input a flattened vector containing features for nRows candidates, + /// row-major: [row0_feat0, row0_feat1, ..., row1_feat0, row1_feat1, ...] + /// \param nModel is the model index (same bin must apply to every row in the batch) + /// \param nRows is the number of candidates packed into input + /// \return flat vector of size nRows * mNClasses, row-major: [row][class] + template + std::vector getModelOutputBatched(T1& input, const T2& nModel, std::size_t nRows) + { + if (nModel < 0 || static_cast(nModel) >= mModels.size()) { + LOG(fatal) << "Model index " << nModel << " is out of range! The number of initialised models is " << mModels.size() << ". Please check your configurables."; + } + if (nRows == 0) { + return {}; + } + + const int numInputNodes = mModels[nModel].getNumInputNodes(); + const std::size_t numInputFeatures = input.size(); + + if (numInputFeatures % nRows != 0) { + LOG(fatal) << "Flattened input size (" << numInputFeatures << ") is not divisible by nRows (" << nRows << ")"; + } + const std::size_t featuresPerRow = numInputFeatures / nRows; + if (numInputNodes >= 0 && static_cast(featuresPerRow) != numInputNodes) { + LOG(fatal) << "Number of input nodes in the model " << mPaths[nModel] << " differs from features per row (" << numInputNodes << " vs " << featuresPerRow << ")"; + } + + TypeOutputScore* outputPtr = mModels[nModel].template evalModel(input); + if (outputPtr == nullptr) { + LOG(fatal) << "Batched model evaluation failed for model " << mPaths[nModel]; + } + return std::vector{outputPtr, outputPtr + nRows * mNClasses}; + } + /// ML selections /// \param input is the input features /// \param candVar is the variable value (e.g. pT) used to select which model to use diff --git a/Tools/ML/model.h b/Tools/ML/model.h index 3be08e72fa9..e9997c1501e 100644 --- a/Tools/ML/model.h +++ b/Tools/ML/model.h @@ -77,6 +77,7 @@ class OnnxModel LOG(fatal) << "Shape of tensor " << i << " does not agree with model specification! Output: " << printShape(outputTensors[i].GetTensorTypeAndShapeInfo().GetShape()) << " model: " << printShape(mOutputShapes[i]); } } + // TODO: isn't outputTensors freed after exiting this function thus making the returned pointer pointing to garbage memory resulting in undefined beaviour? T* outputValues = outputTensors.back().GetTensorMutableData(); return outputValues; } catch (const Ort::Exception& exception) { diff --git a/Tools/PIDFeatureExtractor/pidFeatureExtractor.cxx b/Tools/PIDFeatureExtractor/pidFeatureExtractor.cxx index b7c58ebe9f8..6e8625e0cc8 100644 --- a/Tools/PIDFeatureExtractor/pidFeatureExtractor.cxx +++ b/Tools/PIDFeatureExtractor/pidFeatureExtractor.cxx @@ -27,7 +27,6 @@ /// \author Robert Forynski #include "Common/DataModel/Centrality.h" -#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" @@ -36,6 +35,9 @@ #include #include #include +#include +#include +#include #include #include diff --git a/Tools/PIDFeatureExtractor/pidOnnxInference.cxx b/Tools/PIDFeatureExtractor/pidOnnxInference.cxx index 86030e3ff82..4d5caaea90a 100644 --- a/Tools/PIDFeatureExtractor/pidOnnxInference.cxx +++ b/Tools/PIDFeatureExtractor/pidOnnxInference.cxx @@ -35,13 +35,19 @@ #include "Tools/ML/MlResponse.h" +#include +#include #include +#include #include +#include #include #include #include +#include + #include #include #include diff --git a/Tools/PIDML/pidMl.h b/Tools/PIDML/pidMl.h index cb45360052c..5a303c956d4 100644 --- a/Tools/PIDML/pidMl.h +++ b/Tools/PIDML/pidMl.h @@ -17,11 +17,14 @@ #ifndef TOOLS_PIDML_PIDML_H_ #define TOOLS_PIDML_PIDML_H_ +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" +#include #include #include @@ -48,8 +51,22 @@ DECLARE_SOA_COLUMN(TofExpSignalDiffKa, tofExpSignalDiffKa, float); //! Differenc DECLARE_SOA_COLUMN(TpcExpSignalDiffKa, tpcExpSignalDiffKa, float); //! Difference between signal and expected for kaon DECLARE_SOA_COLUMN(TofExpSignalDiffPr, tofExpSignalDiffPr, float); //! Difference between signal and expected for proton DECLARE_SOA_COLUMN(TpcExpSignalDiffPr, tpcExpSignalDiffPr, float); //! Difference between signal and expected for proton +DECLARE_SOA_COLUMN(TpcNClsFound, tpcNClsFound, int16_t); //! Number of found TPC clusters +DECLARE_SOA_COLUMN(TpcNClsPID, tpcNClsPID, int16_t); //! Number of TPC clusters used for PID + +// event selection flags +DECLARE_SOA_COLUMN(EvSelNoSameBunchPileup, evSelNoSameBunchPileup, bool); +DECLARE_SOA_COLUMN(EvSelIsGoodZvtxFT0vsPV, evSelIsGoodZvtxFT0vsPV, bool); +DECLARE_SOA_COLUMN(EvSelIsGoodITSLayersAll, evSelIsGoodITSLayersAll, bool); +DECLARE_SOA_COLUMN(EvSelNoCollInRofStandard, evSelNoCollInRofStandard, bool); +DECLARE_SOA_COLUMN(EvSelNoHighMultCollInPrevRof, evSelNoHighMultCollInPrevRof, bool); +DECLARE_SOA_COLUMN(EvSelIsVertexITSTPC, evSelIsVertexITSTPC, bool); +DECLARE_SOA_COLUMN(EvSelNoCollInTimeRangeStandard, evSelNoCollInTimeRangeStandard, bool); +DECLARE_SOA_COLUMN(EvSelNoITSROFrameBorder, evSelNoITSROFrameBorder, bool); +DECLARE_SOA_COLUMN(EvSelNoTimeFrameBorder, evSelNoTimeFrameBorder, bool); } // namespace pidtracks DECLARE_SOA_TABLE(PidTracksDataMl, "AOD", "PIDTRACKSDATAML", //! Data tracks for prediction and domain adaptation + aod::track::CollisionId, aod::track::TPCSignal, aod::track::TRDSignal, aod::track::TRDPattern, aod::pidtofsignal::TOFSignal, @@ -69,12 +86,22 @@ DECLARE_SOA_TABLE(PidTracksDataMl, "AOD", "PIDTRACKSDATAML", //! Data tracks for aod::track::DcaXY, aod::track::DcaZ); DECLARE_SOA_TABLE(PidTracksData, "AOD", "PIDTRACKSDATA", //! Data tracks for comparative analysis + aod::track::CollisionId, aod::mult::MultFV0A, aod::mult::MultFV0C, pidtracks::MultFV0M, aod::mult::MultFT0A, aod::mult::MultFT0C, pidtracks::MultFT0M, - aod::mult::MultZNA, aod::mult::MultZNC, - aod::mult::MultTracklets, aod::mult::MultTPC, - aod::track::TPCSignal, - aod::track::TRDSignal, aod::track::TRDPattern, + aod::mult::MultZNA, aod::mult::MultZNC, aod::mult::MultTracklets, + aod::mult::MultTPC, aod::mult::MultNTracksPV, + aod::collision::PosZ, aod::evsel::OccupancyMedianTime, aod::cent::CentFT0C, + pidtracks::EvSelNoSameBunchPileup, + pidtracks::EvSelIsGoodZvtxFT0vsPV, + pidtracks::EvSelIsGoodITSLayersAll, + pidtracks::EvSelNoCollInRofStandard, + pidtracks::EvSelNoHighMultCollInPrevRof, + pidtracks::EvSelIsVertexITSTPC, + pidtracks::EvSelNoCollInTimeRangeStandard, + pidtracks::EvSelNoITSROFrameBorder, + pidtracks::EvSelNoTimeFrameBorder, + aod::track::TPCSignal, aod::track::TRDSignal, aod::track::TRDPattern, aod::track::TrackEtaEMCAL, aod::track::TrackPhiEMCAL, aod::pidtofsignal::TOFSignal, @@ -122,8 +149,25 @@ DECLARE_SOA_TABLE(PidTracksData, "AOD", "PIDTRACKSDATA", //! Data tracks for com pidtracks::TpcExpSignalDiffPr, pidtof::TOFNSigmaPr, pidtof::TOFExpSigmaPr, - pidtracks::TofExpSignalDiffPr); + pidtracks::TofExpSignalDiffPr, + aod::track::Snp, + aod::track::Tgl, + aod::track::SigmaY, + aod::track::SigmaZ, + aod::track::SigmaSnp, + aod::track::SigmaTgl, + aod::track::Sigma1Pt, + aod::track::TPCNClsFindable, + pidtracks::TpcNClsFound, + pidtracks::TpcNClsPID, + aod::track::TPCChi2NCl, + aod::track::TrackTime, + aod::track::Length, + aod::track::TOFChi2, + aod::track::ITSClusterMap, + aod::track::TRDChi2); DECLARE_SOA_TABLE(PidTracksMcMl, "AOD", "PIDTRACKSMCML", //! MC tracks for training + aod::track::CollisionId, aod::track::TPCSignal, aod::track::TRDSignal, aod::track::TRDPattern, aod::pidtofsignal::TOFSignal, @@ -145,12 +189,22 @@ DECLARE_SOA_TABLE(PidTracksMcMl, "AOD", "PIDTRACKSMCML", //! MC tracks for train aod::mcparticle::PdgCode, pidtracks::IsPhysicalPrimary); DECLARE_SOA_TABLE(PidTracksMc, "AOD", "PIDTRACKSMC", //! MC tracks for comparative analysis + aod::track::CollisionId, aod::mult::MultFV0A, aod::mult::MultFV0C, pidtracks::MultFV0M, aod::mult::MultFT0A, aod::mult::MultFT0C, pidtracks::MultFT0M, - aod::mult::MultZNA, aod::mult::MultZNC, - aod::mult::MultTracklets, aod::mult::MultTPC, - aod::track::TPCSignal, - aod::track::TRDSignal, aod::track::TRDPattern, + aod::mult::MultZNA, aod::mult::MultZNC, aod::mult::MultTracklets, + aod::mult::MultTPC, aod::mult::MultNTracksPV, + aod::collision::PosZ, aod::evsel::OccupancyMedianTime, aod::cent::CentFT0C, + pidtracks::EvSelNoSameBunchPileup, + pidtracks::EvSelIsGoodZvtxFT0vsPV, + pidtracks::EvSelIsGoodITSLayersAll, + pidtracks::EvSelNoCollInRofStandard, + pidtracks::EvSelNoHighMultCollInPrevRof, + pidtracks::EvSelIsVertexITSTPC, + pidtracks::EvSelNoCollInTimeRangeStandard, + pidtracks::EvSelNoITSROFrameBorder, + pidtracks::EvSelNoTimeFrameBorder, + aod::track::TPCSignal, aod::track::TRDSignal, aod::track::TRDPattern, aod::track::TrackEtaEMCAL, aod::track::TrackPhiEMCAL, aod::pidtofsignal::TOFSignal, @@ -199,6 +253,22 @@ DECLARE_SOA_TABLE(PidTracksMc, "AOD", "PIDTRACKSMC", //! MC tracks for comparati pidtof::TOFNSigmaPr, pidtof::TOFExpSigmaPr, pidtracks::TofExpSignalDiffPr, + aod::track::Snp, + aod::track::Tgl, + aod::track::SigmaY, + aod::track::SigmaZ, + aod::track::SigmaSnp, + aod::track::SigmaTgl, + aod::track::Sigma1Pt, + aod::track::TPCNClsFindable, + pidtracks::TpcNClsFound, + pidtracks::TpcNClsPID, + aod::track::TPCChi2NCl, + aod::track::TrackTime, + aod::track::Length, + aod::track::TOFChi2, + aod::track::ITSClusterMap, + aod::track::TRDChi2, aod::mcparticle::PdgCode, pidtracks::IsPhysicalPrimary); } // namespace o2::aod diff --git a/Tools/PIDML/pidMlProducer.cxx b/Tools/PIDML/pidMlProducer.cxx index 332a2a8209b..2d2968973a4 100644 --- a/Tools/PIDML/pidMlProducer.cxx +++ b/Tools/PIDML/pidMlProducer.cxx @@ -15,13 +15,15 @@ /// \author Maja Kabus /// \author Marek Mytkowski -#include "Tools/PIDML/pidMl.h" -#include "Tools/PIDML/pidUtils.h" -// +#include "Common/CCDB/EventSelectionParams.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/PIDResponseTOF.h" #include "Common/DataModel/PIDResponseTPC.h" #include "Common/DataModel/TrackSelectionTables.h" +#include "Tools/PIDML/pidMl.h" +#include "Tools/PIDML/pidUtils.h" #include #include @@ -41,6 +43,7 @@ #include #include #include +#include #include using namespace o2; @@ -58,18 +61,49 @@ struct PidMlProducer { Produces pidTracksTableMCML; Produces pidTracksTableMC; + // Basic event selection: sel8() + (zVertex < zVertexMax) + (centMin <= FT0C <= centMax) + struct : o2::framework::ConfigurableGroup { + std::string prefix = "confBasicEventSelection"; + + Configurable enableSel8{"enableSel8", true, "enable sel8 cut."}; + Configurable zVertexMax{"zVertexMax", 10., "Maximum Z Vertex value cm."}; + Configurable centMin{"centMin", 0.f, "Minimum centrality (FT0C)."}; + Configurable centMax{"centMax", 200.f, "Maximum centrality (FT0C)."}; + } confBasicEventSelection; + + // Strict event selection: criteria boolean flags (see their details) + TPC occupancy + struct : o2::framework::ConfigurableGroup { + std::string prefix = "confStrictEventSelection"; + Configurable enable{"enable", false, "Enable stricter event selection filtering"}; + + struct : o2::framework::ConfigurableGroup { + std::string prefix = "confStrictEventSelection.criteria"; + Configurable evIsGoodZvtxFT0vsPV{"evIsGoodZvtxFT0vsPV", true, "Require kIsGoodZvtxFT0vsPV selection on events"}; + Configurable evNoSameBunchPileup{"evNoSameBunchPileup", true, "Require kNoSameBunchPileup selection on events"}; + Configurable evIsVertexITSTPC{"evIsVertexITSTPC", true, "Require kIsVertexITSTPC selection on events"}; + Configurable isGoodITSLayersAll{"isGoodITSLayersAll", true, "Require kIsGoodITSLayersAll selection on events"}; + Configurable noITSROFrameBorder{"noITSROFrameBorder", true, "Require kNoITSROFrameBorder selection on events"}; + Configurable noTimeFrameBorder{"noTimeFrameBorder", true, "Require kNoTimeFrameBorder selection on events"}; + Configurable noCollInRofStandard{"noCollInRofStandard", true, "Require kNoCollInRofStandard selection on events"}; + Configurable noHighMultCollInPrevRof{"noHighMultCollInPrevRof", true, "Require kNoHighMultCollInPrevRof selection on events"}; + Configurable noCollInTimeRangeStandard{"noCollInTimeRangeStandard", true, "Require kNoCollInTimeRangeStandard selection on events"}; + Configurable tpcOccupancyMin{"tpcOccupancyMin", 0, "Minimum value for TPC occupancy selection"}; + Configurable tpcOccupancyMax{"tpcOccupancyMax", 500, "Maximum value for TPC occupancy selection"}; + } criteria; + } confStrictEventSelection; + Filter trackFilter = requireGlobalTrackInFilter(); // Data tracks - using BigTracksDataML = soa::Filtered>; - using BigTracksData = soa::Filtered>; + using BigTracksDataML = soa::Filtered>; + using BigTracksData = soa::Filtered>; // MC tracks - using BigTracksMCML = soa::Filtered>; - using BigTracksMC = soa::Filtered>; + using BigTracksMCML = soa::Filtered>; + using BigTracksMC = soa::Filtered>; - using MyCollisionML = aod::Collisions::iterator; - using MyCollision = soa::Join::iterator; + using MyCollisionML = soa::Join::iterator; + using MyCollision = soa::Join::iterator; static constexpr uint32_t NCharges = 2; @@ -230,10 +264,64 @@ struct PidMlProducer { return trdMissing(track) ? static_cast(0U) : track.trdPattern(); } - void processDataML(MyCollisionML const& /*collision*/, BigTracksDataML const& tracks) + // inspired by PWGCF/FemtoUniverse/TableProducer/femtoUniverseProducerTask.cxx + template + bool fillCollisionsCentRun3(CollisionType const& col) + { + // Basic Event Selection + { + const auto& basic_criteria = confBasicEventSelection; + + // Z Vertex filter + if (std::abs(col.posZ()) > basic_criteria.zVertexMax.value) + return false; + + // Selection 8 filters + if (basic_criteria.enableSel8.value && !col.sel8()) + return false; + + // Centrality filter + const auto cent = col.centFT0C(); + if ((cent < basic_criteria.centMin.value) || (cent > basic_criteria.centMax.value)) + return false; + } + + // Strict Event Selection + { + if (!confStrictEventSelection.enable) + return true; + + const auto& criteria = confStrictEventSelection.criteria; + + // TPC Occupancy filter + const auto occupancy = col.trackOccupancyInTimeRange(); + if (occupancy < criteria.tpcOccupancyMin.value || occupancy > criteria.tpcOccupancyMax.value) + return false; + + // Event Selection boolean filters + if ((!criteria.evNoSameBunchPileup.value || col.selection_bit(aod::evsel::kNoSameBunchPileup)) && + (!criteria.evIsGoodZvtxFT0vsPV.value || col.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV)) && + (!criteria.isGoodITSLayersAll.value || col.selection_bit(aod::evsel::kIsGoodITSLayersAll)) && + (!criteria.noCollInRofStandard.value || col.selection_bit(aod::evsel::kNoCollInRofStandard)) && + (!criteria.noHighMultCollInPrevRof.value || col.selection_bit(aod::evsel::kNoHighMultCollInPrevRof)) && + (!criteria.evIsVertexITSTPC.value || col.selection_bit(aod::evsel::kIsVertexITSTPC)) && + (!criteria.noCollInTimeRangeStandard.value || col.selection_bit(aod::evsel::kNoCollInTimeRangeStandard)) && + (!criteria.noITSROFrameBorder.value || col.selection_bit(aod::evsel::kNoITSROFrameBorder)) && + (!criteria.noTimeFrameBorder.value || col.selection_bit(aod::evsel::kNoTimeFrameBorder))) + return true; + + return false; + } + } + + void processDataML(MyCollisionML const& collision, BigTracksDataML const& tracks) { + if (!fillCollisionsCentRun3(collision)) { + return; + } + for (const auto& track : tracks) { - pidTracksTableDataML(track.tpcSignal(), getTRDSignal(track), getTRDPattern(track), + pidTracksTableDataML(track.collisionId(), track.tpcSignal(), getTRDSignal(track), getTRDPattern(track), getTOFSignal(track), getTOFBeta(track), track.p(), track.pt(), track.px(), track.py(), track.pz(), track.sign(), @@ -250,11 +338,25 @@ struct PidMlProducer { void processDataAll(MyCollision const& collision, BigTracksData const& tracks) { + if (!fillCollisionsCentRun3(collision)) { + return; + } + for (const auto& track : tracks) { - pidTracksTableData(collision.multFV0A(), collision.multFV0C(), collision.multFV0M(), + pidTracksTableData(track.collisionId(), collision.multFV0A(), collision.multFV0C(), collision.multFV0M(), collision.multFT0A(), collision.multFT0C(), collision.multFT0M(), - collision.multZNA(), collision.multZNC(), - collision.multTracklets(), collision.multTPC(), + collision.multZNA(), collision.multZNC(), collision.multTracklets(), + collision.multTPC(), collision.multNTracksPV(), + collision.posZ(), collision.trackOccupancyInTimeRange(), collision.centFT0C(), + collision.selection_bit(aod::evsel::kNoSameBunchPileup), + collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV), + collision.selection_bit(aod::evsel::kIsGoodITSLayersAll), + collision.selection_bit(aod::evsel::kNoCollInRofStandard), + collision.selection_bit(aod::evsel::kNoHighMultCollInPrevRof), + collision.selection_bit(aod::evsel::kIsVertexITSTPC), + collision.selection_bit(aod::evsel::kNoCollInTimeRangeStandard), + collision.selection_bit(aod::evsel::kNoITSROFrameBorder), + collision.selection_bit(aod::evsel::kNoTimeFrameBorder), track.tpcSignal(), getTRDSignal(track), getTRDPattern(track), track.trackEtaEmcal(), track.trackPhiEmcal(), getTOFSignal(track), getTOFBeta(track), @@ -274,15 +376,23 @@ struct PidMlProducer { track.tpcNSigmaKa(), track.tpcExpSigmaKa(), track.tpcExpSignalDiffKa(), track.tofNSigmaKa(), track.tofExpSigmaKa(), track.tofExpSignalDiffKa(), track.tpcNSigmaPr(), track.tpcExpSigmaPr(), track.tpcExpSignalDiffPr(), - track.tofNSigmaPr(), track.tofExpSigmaPr(), track.tofExpSignalDiffPr()); + track.tofNSigmaPr(), track.tofExpSigmaPr(), track.tofExpSignalDiffPr(), + track.snp(), track.tgl(), track.sigmaY(), track.sigmaZ(), track.sigmaSnp(), + track.sigmaTgl(), track.sigma1Pt(), track.tpcNClsFindable(), track.tpcNClsFound(), + track.tpcNClsPID(), track.tpcChi2NCl(), track.trackTime(), track.length(), + track.tofChi2(), track.itsClusterMap(), track.trdChi2()); fillHist(track); } } PROCESS_SWITCH(PidMlProducer, processDataAll, "Produce all real data", false); - void processMcMl(MyCollisionML const& /*collision*/, BigTracksMCML const& tracks, aod::McParticles const& /*mctracks*/) + void processMcMl(MyCollisionML const& collision, BigTracksMCML const& tracks, aod::McParticles const& /*mctracks*/) { + if (!fillCollisionsCentRun3(collision)) { + return; + } + for (const auto& track : tracks) { if (!track.has_mcParticle()) { continue; @@ -290,7 +400,7 @@ struct PidMlProducer { const auto mcParticle = track.mcParticle_as(); uint8_t isPrimary = static_cast(mcParticle.isPhysicalPrimary()); uint32_t pdgCode = mcParticle.pdgCode(); - pidTracksTableMCML(track.tpcSignal(), getTRDSignal(track), getTRDPattern(track), + pidTracksTableMCML(track.collisionId(), track.tpcSignal(), getTRDSignal(track), getTRDPattern(track), getTOFSignal(track), getTOFBeta(track), track.p(), track.pt(), track.px(), track.py(), track.pz(), track.sign(), @@ -309,6 +419,10 @@ struct PidMlProducer { void processMcAll(MyCollision const& collision, BigTracksMC const& tracks, aod::McParticles const& /*mctracks*/) { + if (!fillCollisionsCentRun3(collision)) { + return; + } + for (const auto& track : tracks) { if (!track.has_mcParticle()) { continue; @@ -316,10 +430,20 @@ struct PidMlProducer { const auto mcParticle = track.mcParticle_as(); uint8_t isPrimary = static_cast(mcParticle.isPhysicalPrimary()); uint32_t pdgCode = mcParticle.pdgCode(); - pidTracksTableMC(collision.multFV0A(), collision.multFV0C(), collision.multFV0M(), + pidTracksTableMC(track.collisionId(), collision.multFV0A(), collision.multFV0C(), collision.multFV0M(), collision.multFT0A(), collision.multFT0C(), collision.multFT0M(), - collision.multZNA(), collision.multZNC(), - collision.multTracklets(), collision.multTPC(), + collision.multZNA(), collision.multZNC(), collision.multTracklets(), + collision.multTPC(), collision.multNTracksPV(), + collision.posZ(), collision.trackOccupancyInTimeRange(), collision.centFT0C(), + collision.selection_bit(aod::evsel::kNoSameBunchPileup), + collision.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV), + collision.selection_bit(aod::evsel::kIsGoodITSLayersAll), + collision.selection_bit(aod::evsel::kNoCollInRofStandard), + collision.selection_bit(aod::evsel::kNoHighMultCollInPrevRof), + collision.selection_bit(aod::evsel::kIsVertexITSTPC), + collision.selection_bit(aod::evsel::kNoCollInTimeRangeStandard), + collision.selection_bit(aod::evsel::kNoITSROFrameBorder), + collision.selection_bit(aod::evsel::kNoTimeFrameBorder), track.tpcSignal(), getTRDSignal(track), getTRDPattern(track), track.trackEtaEmcal(), track.trackPhiEmcal(), getTOFSignal(track), getTOFBeta(track), @@ -340,6 +464,10 @@ struct PidMlProducer { track.tofNSigmaKa(), track.tofExpSigmaKa(), track.tofExpSignalDiffKa(), track.tpcNSigmaPr(), track.tpcExpSigmaPr(), track.tpcExpSignalDiffPr(), track.tofNSigmaPr(), track.tofExpSigmaPr(), track.tofExpSignalDiffPr(), + track.snp(), track.tgl(), track.sigmaY(), track.sigmaZ(), track.sigmaSnp(), + track.sigmaTgl(), track.sigma1Pt(), track.tpcNClsFindable(), track.tpcNClsFound(), + track.tpcNClsPID(), track.tpcChi2NCl(), track.trackTime(), track.length(), + track.tofChi2(), track.itsClusterMap(), track.trdChi2(), pdgCode, isPrimary); diff --git a/o2linter_config b/o2linter_config index 66b2d074f62..73391d3f8c3 100644 --- a/o2linter_config +++ b/o2linter_config @@ -13,3 +13,25 @@ name/class name/struct name/file-cpp name/file-python +# temporarily demoted +const-ref-in-for-loop +const-ref-in-process +include-iostream +logging +magic-number +name/configurable +name/o2-column +name/o2-table +name/o2-task +name/o2-workflow +name/workflow-file +o2-workflow-options +pdg/database +pdg/explicit-code +pdg/explicit-mass +pdg/known-mass +pwghf/name/struct-class +pwghf/struct-member-order +root/lorentz-vector +std-prefix +two-pi-add-subtract