diff --git a/ALICE3/Core/FastTracker.cxx b/ALICE3/Core/FastTracker.cxx index d43bf10fc6d..ef45e99ca01 100644 --- a/ALICE3/Core/FastTracker.cxx +++ b/ALICE3/Core/FastTracker.cxx @@ -442,11 +442,7 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa inputTrack.getXYZGlo(posIni); const float initialRadius = std::hypot(posIni[0], posIni[1]); const float kTrackingMargin = 0.1; - const int kMaxNumberOfDetectors = 20; - if (kMaxNumberOfDetectors < layers.size()) { - LOG(fatal) << "Too many layers in FastTracker, increase kMaxNumberOfDetectors"; - return -1; // too many layers - } + int firstActiveLayer = -1; // first layer that is not inert for (size_t i = 0; i < layers.size(); ++i) { if (!layers[i].isInert()) { @@ -461,8 +457,12 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa const int xrhosteps = 100; const bool applyAngularCorrection = true; + // 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 + // Loop over all the added layers to prevent crash when adding the tpc + // Should not affect efficiency calculation goodHitProbability.clear(); - for (int i = 0; i < kMaxNumberOfDetectors; ++i) { + for (size_t i = 0; i < layers.size(); ++i) { goodHitProbability.push_back(-1.); } goodHitProbability[0] = 1.; // we use layer zero to accumulate @@ -650,7 +650,7 @@ int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackPa // generate efficiency float eff = 1.; - for (int i = 0; i < kMaxNumberOfDetectors; i++) { + for (size_t i = 0; i < layers.size(); i++) { float iGoodHit = goodHitProbability[i]; if (iGoodHit <= 0) continue; diff --git a/ALICE3/DataModel/OTFMulticharm.h b/ALICE3/DataModel/OTFMulticharm.h index 2c3a715f16c..944aa578ab2 100644 --- a/ALICE3/DataModel/OTFMulticharm.h +++ b/ALICE3/DataModel/OTFMulticharm.h @@ -36,6 +36,7 @@ DECLARE_SOA_INDEX_COLUMN_FULL(XiCCPion, xiCCPion, int, Tracks, "_PiXiCC"); DECLARE_SOA_COLUMN(XicMass, xicMass, float); DECLARE_SOA_COLUMN(XiccMass, xiccMass, float); +DECLARE_SOA_COLUMN(LUTConfigId, lutConfigId, int); //! Index for LUT configuration // kine vars DECLARE_SOA_COLUMN(XiccPt, xiccPt, float); @@ -155,7 +156,8 @@ DECLARE_SOA_TABLE(MCharmCores, "AOD", "MCharmCores", otfmulticharm::XiccProperLength, otfmulticharm::Pi1cPt, otfmulticharm::Pi2cPt, - otfmulticharm::PiccPt); + otfmulticharm::PiccPt, + otfmulticharm::LUTConfigId); DECLARE_SOA_TABLE(MCharmPID, "AOD", "MCharmPID", otfmulticharm::Pi1cTofDeltaInner, diff --git a/ALICE3/DataModel/OTFTracks.h b/ALICE3/DataModel/OTFTracks.h new file mode 100644 index 00000000000..390e3680716 --- /dev/null +++ b/ALICE3/DataModel/OTFTracks.h @@ -0,0 +1,35 @@ +// 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 OTFTracks.h +/// \author Jesper Karlsson Gumprecht +/// \since 11/11/2025 +/// \brief Table to map track to LUT configuration +/// + +#ifndef ALICE3_DATAMODEL_OTFTRACKS_H_ +#define ALICE3_DATAMODEL_OTFTRACKS_H_ + +// O2 includes +#include "Framework/AnalysisDataModel.h" + +namespace o2::aod +{ +namespace otftracks +{ +DECLARE_SOA_COLUMN(LUTConfigId, lutConfigId, int); //! Index for LUT configuration +} // namespace otftracks + +DECLARE_SOA_TABLE(OTFLUTConfigId, "AOD", "OTFLUTConfigId", otftracks::LUTConfigId); +} // namespace o2::aod + +#endif // ALICE3_DATAMODEL_OTFTRACKS_H_ diff --git a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx index 1bf0331e6ee..dd253ca68df 100644 --- a/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx +++ b/ALICE3/TableProducer/OTF/onTheFlyTracker.cxx @@ -28,6 +28,7 @@ #include "ALICE3/Core/FastTracker.h" #include "ALICE3/Core/TrackUtilities.h" #include "ALICE3/DataModel/OTFStrangeness.h" +#include "ALICE3/DataModel/OTFTracks.h" #include "ALICE3/DataModel/collisionAlice3.h" #include "ALICE3/DataModel/tracksAlice3.h" #include "Common/Core/RecoDecay.h" @@ -64,6 +65,7 @@ using namespace o2; using namespace o2::framework; using std::array; +#define getHist(type, name) std::get>(histPointers[name]) struct OnTheFlyTracker { Produces tableCollisions; @@ -79,6 +81,7 @@ struct OnTheFlyTracker { Produces tableTracksAlice3; Produces tableTracksExtraA3; Produces tableUpgradeCascades; + Produces tableOTFLUTConfigId; // optionally produced, empty (to be tuned later) Produces tableStoredTracksExtra; // base table, extend later @@ -90,7 +93,6 @@ struct OnTheFlyTracker { Configurable maxEta{"maxEta", 1.5, "maximum eta to consider viable"}; Configurable multEtaRange{"multEtaRange", 0.8, "eta range to compute the multiplicity"}; Configurable minPt{"minPt", 0.1, "minimum pt to consider viable"}; - Configurable enableLUT{"enableLUT", false, "Enable track smearing"}; Configurable enablePrimarySmearing{"enablePrimarySmearing", false, "Enable smearing of primary particles"}; Configurable enableSecondarySmearing{"enableSecondarySmearing", false, "Enable smearing of weak decay daughters"}; Configurable enableNucleiSmearing{"enableNucleiSmearing", false, "Enable smearing of nuclei"}; @@ -106,15 +108,18 @@ struct OnTheFlyTracker { Configurable doExtraQA{"doExtraQA", false, "do extra 2D QA plots"}; Configurable extraQAwithoutDecayDaughters{"extraQAwithoutDecayDaughters", false, "remove decay daughters from qa plots (yes/no)"}; - Configurable lutEl{"lutEl", "lutCovm.el.dat", "LUT for electrons (if emtpy no LUT is taken)"}; - Configurable lutMu{"lutMu", "lutCovm.mu.dat", "LUT for muons (if emtpy no LUT is taken)"}; - Configurable lutPi{"lutPi", "lutCovm.pi.dat", "LUT for pions (if emtpy no LUT is taken)"}; - Configurable lutKa{"lutKa", "lutCovm.ka.dat", "LUT for kaons (if emtpy no LUT is taken)"}; - Configurable lutPr{"lutPr", "lutCovm.pr.dat", "LUT for protons (if emtpy no LUT is taken)"}; - Configurable lutDe{"lutDe", "", "LUT for deuterons (if emtpy no LUT is taken)"}; - Configurable lutTr{"lutTr", "", "LUT for tritons (if emtpy no LUT is taken)"}; - Configurable lutHe3{"lutHe3", "", "LUT for Helium-3 (if emtpy no LUT is taken)"}; - Configurable lutAl{"lutAl", "", "LUT for Alphas (if emtpy no LUT is taken)"}; + struct : ConfigurableGroup { + std::string prefix = "lookUpTables"; // JSON group name + Configurable> lutEl{"lutEl", std::vector{"lutCovm.el.dat"}, "LUT for electrons (if emtpy no LUT is taken)"}; + Configurable> lutMu{"lutMu", std::vector{"lutCovm.mu.dat"}, "LUT for muons (if emtpy no LUT is taken)"}; + Configurable> lutPi{"lutPi", std::vector{"lutCovm.pi.dat"}, "LUT for pions (if emtpy no LUT is taken)"}; + Configurable> lutKa{"lutKa", std::vector{"lutCovm.ka.dat"}, "LUT for kaons (if emtpy no LUT is taken)"}; + Configurable> lutPr{"lutPr", std::vector{"lutCovm.pr.dat"}, "LUT for protons (if emtpy no LUT is taken)"}; + Configurable> lutDe{"lutDe", std::vector{""}, "LUT for deuterons (if emtpy no LUT is taken)"}; + Configurable> lutTr{"lutTr", std::vector{""}, "LUT for tritons (if emtpy no LUT is taken)"}; + Configurable> lutHe3{"lutHe3", std::vector{""}, "LUT for Helium-3 (if emtpy no LUT is taken)"}; + Configurable> lutAl{"lutAl", std::vector{""}, "LUT for Alphas (if emtpy no LUT is taken)"}; + } lookUpTables; struct : ConfigurableGroup { ConfigurableAxis axisMomentum{"axisMomentum", {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}, "#it{p} (GeV/#it{c})"}; @@ -127,6 +132,7 @@ struct OnTheFlyTracker { ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.101f, 1.131f}, ""}; ConfigurableAxis axisXiMass{"axisXiMass", {200, 1.22f, 1.42f}, ""}; + ConfigurableAxis axisPtRes{"axisPtRes", {200, -0.4f, 0.4f}, "#Delta p_{T} / Reco p_{T}"}; ConfigurableAxis axisDeltaPt{"axisDeltaPt", {200, -1.0f, +1.0f}, "#Delta p_{T}"}; ConfigurableAxis axisDeltaEta{"axisDeltaEta", {200, -0.5f, +0.5f}, "#Delta #eta"}; @@ -140,7 +146,7 @@ struct OnTheFlyTracker { Configurable minSiliconHits{"minSiliconHits", 6, "minimum number of silicon hits to accept track"}; Configurable minSiliconHitsIfTPCUsed{"minSiliconHitsIfTPCUsed", 2, "minimum number of silicon hits to accept track in case TPC info is present"}; Configurable minTPCClusters{"minTPCClusters", 70, "minimum number of TPC hits necessary to consider minSiliconHitsIfTPCUsed"}; - Configurable alice3geo{"alice3geo", "2", "0: ALICE 3 v1, 1: ALICE 3 v4, 2: ALICE 3 Sep 2025, or path to ccdb with a3 geo"}; + Configurable> alice3geo{"alice3geo", std::vector{"2"}, "0: ALICE 3 v1, 1: ALICE 3 v4, 2: ALICE 3 Sep 2025, or path to ccdb with a3 geo (ccdb:Users/u/user/)"}; Configurable applyZacceptance{"applyZacceptance", false, "apply z limits to detector layers or not"}; Configurable applyMSCorrection{"applyMSCorrection", true, "apply ms corrections for secondaries or not"}; Configurable applyElossCorrection{"applyElossCorrection", true, "apply eloss corrections for secondaries or not"}; @@ -174,7 +180,8 @@ struct OnTheFlyTracker { o2::vertexing::DCAFitterN<2> fitter; // FastTracker machinery - o2::fastsim::FastTracker fastTracker; + // o2::fastsim::FastTracker fastTracker; + std::vector> fastTracker; o2::fastsim::FastTracker fastPrimaryTracker; // Class to hold the track information for the O2 vertexing @@ -238,11 +245,12 @@ struct OnTheFlyTracker { // for handling basic QA histograms if requested HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + std::map histPointers; o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; // Track smearer - o2::delphes::DelphesO2TrackSmearer mSmearer; + std::vector> mSmearer; // For processing and vertexing std::vector tracksAlice3; @@ -256,36 +264,101 @@ struct OnTheFlyTracker { TRandom3 rand; Service ccdb; + static constexpr int kMaxLUTConfigs = 20; void init(o2::framework::InitContext&) { - ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setTimestamp(-1); - if (enableLUT) { - mSmearer.setCcdbManager(ccdb.operator->()); - - auto loadLUT = [&](int pdg, const std::string& lutFile) { - bool success = mSmearer.loadTable(pdg, lutFile.c_str()); + if (enablePrimarySmearing) { + auto loadLUT = [&](int icfg, int pdg, const std::vector& tables) { + const bool foundNewCfg = static_cast(icfg) < tables.size(); + const std::string& lutFile = foundNewCfg ? tables[icfg] : tables.front(); + bool success = mSmearer[icfg]->loadTable(pdg, lutFile.c_str()); if (!success && !lutFile.empty()) { LOG(fatal) << "Having issue with loading the LUT " << pdg << " " << lutFile; } + + return foundNewCfg; }; - loadLUT(kElectron, lutEl.value); - loadLUT(kMuonMinus, lutMu.value); - loadLUT(kPiPlus, lutPi.value); - loadLUT(kKPlus, lutKa.value); - loadLUT(kProton, lutPr.value); - loadLUT(o2::constants::physics::kDeuteron, lutDe.value); - loadLUT(o2::constants::physics::kTriton, lutTr.value); - loadLUT(o2::constants::physics::kHelium3, lutHe3.value); - loadLUT(o2::constants::physics::kAlpha, lutAl.value); - - // interpolate efficiencies if requested to do so - mSmearer.interpolateEfficiency(static_cast(interpolateLutEfficiencyVsNch)); - - // smear un-reco'ed tracks if asked to do so - mSmearer.skipUnreconstructed(static_cast(!processUnreconstructedTracks)); + + for (int icfg = 0; icfg < kMaxLUTConfigs; ++icfg) { + mSmearer.emplace_back(std::make_unique()); + mSmearer[icfg]->setCcdbManager(ccdb.operator->()); + + // check if more configs were provided, fall back to first entry + bool newLUTLoaded = false; + newLUTLoaded |= loadLUT(icfg, kElectron, lookUpTables.lutEl.value); + newLUTLoaded |= loadLUT(icfg, kMuonMinus, lookUpTables.lutMu.value); + newLUTLoaded |= loadLUT(icfg, kPiPlus, lookUpTables.lutPi.value); + newLUTLoaded |= loadLUT(icfg, kKPlus, lookUpTables.lutKa.value); + newLUTLoaded |= loadLUT(icfg, kProton, lookUpTables.lutPr.value); + newLUTLoaded |= loadLUT(icfg, o2::constants::physics::kDeuteron, lookUpTables.lutDe.value); + newLUTLoaded |= loadLUT(icfg, o2::constants::physics::kTriton, lookUpTables.lutTr.value); + newLUTLoaded |= loadLUT(icfg, o2::constants::physics::kHelium3, lookUpTables.lutHe3.value); + newLUTLoaded |= loadLUT(icfg, o2::constants::physics::kAlpha, lookUpTables.lutAl.value); + + if (!newLUTLoaded) { + mSmearer.pop_back(); + break; + } + + // interpolate efficiencies if requested to do so + mSmearer[icfg]->interpolateEfficiency(static_cast(interpolateLutEfficiencyVsNch)); + + // smear un-reco'ed tracks if asked to do so + mSmearer[icfg]->skipUnreconstructed(static_cast(!processUnreconstructedTracks)); + + std::string histPath = "Configuration_" + std::to_string(icfg) + "/"; + histPointers.insert({histPath + "hPtGenerated", histos.add((histPath + "hPtGenerated").c_str(), "hPtGenerated", {kTH1D, {{axes.axisMomentum}}})}); + histPointers.insert({histPath + "hPhiGenerated", histos.add((histPath + "hPhiGenerated").c_str(), "hPhiGenerated", {kTH1D, {{100, 0.0f, 2 * M_PI, "#phi (rad)"}}})}); + + histPointers.insert({histPath + "hPtGeneratedEl", histos.add((histPath + "hPtGeneratedEl").c_str(), "hPtGeneratedEl", {kTH1D, {{axes.axisMomentum}}})}); + histPointers.insert({histPath + "hPtGeneratedPi", histos.add((histPath + "hPtGeneratedPi").c_str(), "hPtGeneratedPi", {kTH1D, {{axes.axisMomentum}}})}); + histPointers.insert({histPath + "hPtGeneratedKa", histos.add((histPath + "hPtGeneratedKa").c_str(), "hPtGeneratedKa", {kTH1D, {{axes.axisMomentum}}})}); + histPointers.insert({histPath + "hPtGeneratedPr", histos.add((histPath + "hPtGeneratedPr").c_str(), "hPtGeneratedPr", {kTH1D, {{axes.axisMomentum}}})}); + histPointers.insert({histPath + "hPtReconstructed", histos.add((histPath + "hPtReconstructed").c_str(), "hPtReconstructed", {kTH1D, {{axes.axisMomentum}}})}); + histPointers.insert({histPath + "hPtReconstructedEl", histos.add((histPath + "hPtReconstructedEl").c_str(), "hPtReconstructedEl", {kTH1D, {{axes.axisMomentum}}})}); + histPointers.insert({histPath + "hPtReconstructedPi", histos.add((histPath + "hPtReconstructedPi").c_str(), "hPtReconstructedPi", {kTH1D, {{axes.axisMomentum}}})}); + histPointers.insert({histPath + "hPtReconstructedKa", histos.add((histPath + "hPtReconstructedKa").c_str(), "hPtReconstructedKa", {kTH1D, {{axes.axisMomentum}}})}); + histPointers.insert({histPath + "hPtReconstructedPr", histos.add((histPath + "hPtReconstructedPr").c_str(), "hPtReconstructedPr", {kTH1D, {{axes.axisMomentum}}})}); + + // Collision QA + histPointers.insert({histPath + "hPVz", histos.add((histPath + "hPVz").c_str(), "hPVz", {kTH1D, {{axes.axisVertexZ}}})}); + histPointers.insert({histPath + "hLUTMultiplicity", histos.add((histPath + "hLUTMultiplicity").c_str(), "hLUTMultiplicity", {kTH1D, {{axes.axisMultiplicity}}})}); + histPointers.insert({histPath + "hSimMultiplicity", histos.add((histPath + "hSimMultiplicity").c_str(), "hSimMultiplicity", {kTH1D, {{axes.axisMultiplicity}}})}); + histPointers.insert({histPath + "hRecoMultiplicity", histos.add((histPath + "hRecoMultiplicity").c_str(), "hRecoMultiplicity", {kTH1D, {{axes.axisMultiplicity}}})}); + + if (enableSecondarySmearing) { + fastTracker.emplace_back(std::make_unique()); + fastTracker[icfg]->SetMagneticField(magneticField); + fastTracker[icfg]->SetApplyZacceptance(fastTrackerSettings.applyZacceptance); + fastTracker[icfg]->SetApplyMSCorrection(fastTrackerSettings.applyMSCorrection); + fastTracker[icfg]->SetApplyElossCorrection(fastTrackerSettings.applyElossCorrection); + + if (fastTrackerSettings.alice3geo.value[icfg] == "0") { + fastTracker[icfg]->AddSiliconALICE3v2(fastTrackerSettings.pixelRes); + } else if (fastTrackerSettings.alice3geo.value[icfg] == "1") { + fastTracker[icfg]->AddSiliconALICE3v4(fastTrackerSettings.pixelRes); + fastTracker[icfg]->AddTPC(0.1, 0.1); + } else if (fastTrackerSettings.alice3geo.value[icfg] == "2") { + fastTracker[icfg]->AddSiliconALICE3(fastTrackerSettings.scaleVD, fastTrackerSettings.pixelRes); + } else { + fastTracker[icfg]->AddGenericDetector(fastTrackerSettings.alice3geo.value[icfg], ccdb.operator->()); + } + + // print fastTracker settings + fastTracker[icfg]->Print(); + histPointers.insert({histPath + "hMassXi", histos.add((histPath + "hMassXi").c_str(), "hMassXi", {kTH1D, {{axes.axisXiMass}}})}); + } + + if (doExtraQA) { + histPointers.insert({histPath + "h2dPtRes", histos.add((histPath + "h2dPtRes").c_str(), "h2dPtRes", {kTH2D, {{axes.axisMomentum, axes.axisPtRes}}})}); + histPointers.insert({histPath + "h2dDCAxy", histos.add((histPath + "h2dDCAxy").c_str(), "h2dDCAxy", {kTH2D, {{axes.axisMomentum, axes.axisDCA}}})}); + histPointers.insert({histPath + "h2dDCAz", histos.add((histPath + "h2dDCAz").c_str(), "h2dDCAz", {kTH2D, {{axes.axisMomentum, axes.axisDCA}}})}); + } + + } // end config loop } // Basic QA @@ -303,29 +376,9 @@ struct OnTheFlyTracker { hCovMatOK->GetXaxis()->SetBinLabel(1, "Not OK"); hCovMatOK->GetXaxis()->SetBinLabel(2, "OK"); - histos.add("hPtGenerated", "hPtGenerated", kTH1F, {axes.axisMomentum}); - histos.add("hPhiGenerated", "hPhiGenerated", kTH1F, {{100, 0.0f, 2 * M_PI, "#phi (rad)"}}); - histos.add("hPtGeneratedEl", "hPtGeneratedEl", kTH1F, {axes.axisMomentum}); - histos.add("hPtGeneratedPi", "hPtGeneratedPi", kTH1F, {axes.axisMomentum}); - histos.add("hPtGeneratedKa", "hPtGeneratedKa", kTH1F, {axes.axisMomentum}); - histos.add("hPtGeneratedPr", "hPtGeneratedPr", kTH1F, {axes.axisMomentum}); - histos.add("hPtReconstructed", "hPtReconstructed", kTH1F, {axes.axisMomentum}); - histos.add("hPtReconstructedEl", "hPtReconstructedEl", kTH1F, {axes.axisMomentum}); - histos.add("hPtReconstructedPi", "hPtReconstructedPi", kTH1F, {axes.axisMomentum}); - histos.add("hPtReconstructedKa", "hPtReconstructedKa", kTH1F, {axes.axisMomentum}); - histos.add("hPtReconstructedPr", "hPtReconstructedPr", kTH1F, {axes.axisMomentum}); - - // Collision QA - histos.add("hPVz", "hPVz", kTH1F, {axes.axisVertexZ}); - histos.add("hLUTMultiplicity", "hLUTMultiplicity", kTH1F, {axes.axisMultiplicity}); - histos.add("hSimMultiplicity", "hSimMultiplicity", kTH1F, {axes.axisMultiplicity}); - histos.add("hRecoMultiplicity", "hRecoMultiplicity", kTH1F, {axes.axisMultiplicity}); - if (doExtraQA) { histos.add("h2dVerticesVsContributors", "h2dVerticesVsContributors", kTH2F, {axes.axisMultiplicity, axes.axisNVertices}); histos.add("hRecoVsSimMultiplicity", "hRecoVsSimMultiplicity", kTH2F, {axes.axisMultiplicity, axes.axisMultiplicity}); - histos.add("h2dDCAxy", "h2dDCAxy", kTH2F, {axes.axisMomentum, axes.axisDCA}); - histos.add("h2dDCAz", "h2dDCAz", kTH2F, {axes.axisMomentum, axes.axisDCA}); histos.add("hSimTrackX", "hSimTrackX", kTH1F, {axes.axisX}); histos.add("hRecoTrackX", "hRecoTrackX", kTH1F, {axes.axisX}); @@ -422,28 +475,7 @@ struct OnTheFlyTracker { // Set seed for TGenPhaseSpace rand.SetSeed(seed); - // configure FastTracker - if (enableSecondarySmearing) { - fastTracker.SetMagneticField(magneticField); - fastTracker.SetApplyZacceptance(fastTrackerSettings.applyZacceptance); - fastTracker.SetApplyMSCorrection(fastTrackerSettings.applyMSCorrection); - fastTracker.SetApplyElossCorrection(fastTrackerSettings.applyElossCorrection); - - if (fastTrackerSettings.alice3geo.value == "0") { - fastTracker.AddSiliconALICE3v2(fastTrackerSettings.pixelRes); - } else if (fastTrackerSettings.alice3geo.value == "1") { - fastTracker.AddSiliconALICE3v4(fastTrackerSettings.pixelRes); - fastTracker.AddTPC(0.1, 0.1); - } else if (fastTrackerSettings.alice3geo.value == "2") { - fastTracker.AddSiliconALICE3(fastTrackerSettings.scaleVD, fastTrackerSettings.pixelRes); - } else { - fastTracker.AddGenericDetector(fastTrackerSettings.alice3geo, ccdb.operator->()); - } - - // print fastTracker settings - fastTracker.Print(); - } - + // Configure FastTracker for primaries if (fastPrimaryTrackerSettings.fastTrackPrimaries) { fastPrimaryTracker.SetMagneticField(magneticField); fastPrimaryTracker.SetApplyZacceptance(fastPrimaryTrackerSettings.applyZacceptance); @@ -521,9 +553,10 @@ struct OnTheFlyTracker { } float dNdEta = 0.f; // Charged particle multiplicity to use in the efficiency evaluation - void process(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) + void processWithLUTs(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles, int const& icfg) { int lastTrackIndex = tableStoredTracksCov.lastIndex() + 1; // bookkeep the last added track + const std::string histPath = "Configuration_" + std::to_string(icfg) + "/"; tracksAlice3.clear(); ghostTracksAlice3.clear(); @@ -580,7 +613,8 @@ struct OnTheFlyTracker { dNdEta /= (multEtaRange * 2.0f); uint32_t multiplicityCounter = 0; - histos.fill(HIST("hLUTMultiplicity"), dNdEta); + getHist(TH1, histPath + "hLUTMultiplicity")->Fill(dNdEta); + gRandom->SetSeed(seed); for (const auto& mcParticle : mcParticles) { @@ -614,16 +648,16 @@ struct OnTheFlyTracker { continue; } - histos.fill(HIST("hPtGenerated"), mcParticle.pt()); - histos.fill(HIST("hPhiGenerated"), mcParticle.phi()); + getHist(TH1, histPath + "hPtGenerated")->Fill(mcParticle.pt()); + getHist(TH1, histPath + "hPhiGenerated")->Fill(mcParticle.phi()); if (std::abs(mcParticle.pdgCode()) == kElectron) - histos.fill(HIST("hPtGeneratedEl"), mcParticle.pt()); + getHist(TH1, histPath + "hPtGeneratedEl")->Fill(mcParticle.pt()); if (std::abs(mcParticle.pdgCode()) == kPiPlus) - histos.fill(HIST("hPtGeneratedPi"), mcParticle.pt()); + getHist(TH1, histPath + "hPtGeneratedPi")->Fill(mcParticle.pt()); if (std::abs(mcParticle.pdgCode()) == kKPlus) - histos.fill(HIST("hPtGeneratedKa"), mcParticle.pt()); + getHist(TH1, histPath + "hPtGeneratedKa")->Fill(mcParticle.pt()); if (std::abs(mcParticle.pdgCode()) == kProton) - histos.fill(HIST("hPtGeneratedPr"), mcParticle.pt()); + getHist(TH1, histPath + "hPtGeneratedPr")->Fill(mcParticle.pt()); if (cascadeDecaySettings.doXiQA && mcParticle.pdgCode() == kXiMinus) { histos.fill(HIST("hGenXi"), xiDecayRadius2D, mcParticle.pt()); @@ -667,9 +701,9 @@ struct OnTheFlyTracker { nSiliconHits[i] = 0; nTPCHits[i] = 0; if (enableSecondarySmearing) { - nHits[i] = fastTracker.FastTrack(xiDaughterTrackParCovsPerfect[i], xiDaughterTrackParCovsTracked[i], dNdEta); - nSiliconHits[i] = fastTracker.GetNSiliconPoints(); - nTPCHits[i] = fastTracker.GetNGasPoints(); + nHits[i] = fastTracker[icfg]->FastTrack(xiDaughterTrackParCovsPerfect[i], xiDaughterTrackParCovsTracked[i], dNdEta); + nSiliconHits[i] = fastTracker[icfg]->GetNSiliconPoints(); + nTPCHits[i] = fastTracker[icfg]->GetNGasPoints(); if (nHits[i] < 0) { // QA histos.fill(HIST("hFastTrackerQA"), o2::math_utils::abs(nHits[i])); @@ -680,8 +714,8 @@ struct OnTheFlyTracker { } else { continue; // extra sure } - for (uint32_t ih = 0; ih < fastTracker.GetNHits(); ih++) { - histos.fill(HIST("hFastTrackerHits"), fastTracker.GetHitZ(ih), std::hypot(fastTracker.GetHitX(ih), fastTracker.GetHitY(ih))); + for (uint32_t ih = 0; ih < fastTracker[icfg]->GetNHits(); ih++) { + histos.fill(HIST("hFastTrackerHits"), fastTracker[icfg]->GetHitZ(ih), std::hypot(fastTracker[icfg]->GetHitX(ih), fastTracker[icfg]->GetHitY(ih))); } } else { isReco[i] = true; @@ -830,8 +864,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.GetLayers().size() - 1; i >= 0; --i) { - o2::fastsim::DetLayer layer = fastTracker.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 } @@ -901,6 +935,7 @@ struct OnTheFlyTracker { histos.fill(HIST("hMassLambda"), thisCascade.mLambda); histos.fill(HIST("hMassXi"), thisCascade.mXi); histos.fill(HIST("hFoundVsFindable"), thisCascade.findableClusters, thisCascade.foundClusters); + getHist(TH1, histPath + "hMassXi")->Fill(thisCascade.mXi); } // add this cascade to vector (will fill cursor later with collision ID) @@ -918,7 +953,7 @@ struct OnTheFlyTracker { bool reconstructed = true; if (enablePrimarySmearing && !fastPrimaryTrackerSettings.fastTrackPrimaries) { - reconstructed = mSmearer.smearTrack(trackParCov, mcParticle.pdgCode(), dNdEta); + reconstructed = mSmearer[icfg]->smearTrack(trackParCov, mcParticle.pdgCode(), dNdEta); } else if (fastPrimaryTrackerSettings.fastTrackPrimaries) { o2::track::TrackParCov o2Track; o2::upgrade::convertMCParticleToO2Track(mcParticle, o2Track, pdgDB); @@ -940,17 +975,18 @@ struct OnTheFlyTracker { } // Base QA (note: reco pT here) - histos.fill(HIST("hPtReconstructed"), trackParCov.getPt()); + getHist(TH1, histPath + "hPtReconstructed")->Fill(trackParCov.getPt()); if (std::abs(mcParticle.pdgCode()) == kElectron) - histos.fill(HIST("hPtReconstructedEl"), mcParticle.pt()); + getHist(TH1, histPath + "hPtReconstructedEl")->Fill(trackParCov.getPt()); if (std::abs(mcParticle.pdgCode()) == kPiPlus) - histos.fill(HIST("hPtReconstructedPi"), mcParticle.pt()); + getHist(TH1, histPath + "hPtReconstructedPi")->Fill(trackParCov.getPt()); if (std::abs(mcParticle.pdgCode()) == kKPlus) - histos.fill(HIST("hPtReconstructedKa"), mcParticle.pt()); + getHist(TH1, histPath + "hPtReconstructedKa")->Fill(trackParCov.getPt()); if (std::abs(mcParticle.pdgCode()) == kProton) - histos.fill(HIST("hPtReconstructedPr"), mcParticle.pt()); + getHist(TH1, histPath + "hPtReconstructedPr")->Fill(trackParCov.getPt()); if (doExtraQA) { + getHist(TH2, histPath + "h2dPtRes")->Fill(trackParCov.getPt(), (trackParCov.getPt() - mcParticle.pt()) / trackParCov.getPt()); histos.fill(HIST("hRecoTrackX"), trackParCov.getX()); } @@ -1012,9 +1048,9 @@ struct OnTheFlyTracker { // *+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+*+~+* // debug / informational - histos.fill(HIST("hSimMultiplicity"), multiplicityCounter); - histos.fill(HIST("hRecoMultiplicity"), tracksAlice3.size()); - histos.fill(HIST("hPVz"), primaryVertex.getZ()); + getHist(TH1, histPath + "hSimMultiplicity")->Fill(multiplicityCounter); + getHist(TH1, histPath + "hRecoMultiplicity")->Fill(tracksAlice3.size()); + getHist(TH1, histPath + "hPVz")->Fill(primaryVertex.getZ()); if (doExtraQA) { histos.fill(HIST("hRecoVsSimMultiplicity"), multiplicityCounter, tracksAlice3.size()); @@ -1046,8 +1082,8 @@ struct OnTheFlyTracker { dcaZ = dcaInfo.getZ(); } if (doExtraQA && (!extraQAwithoutDecayDaughters || (extraQAwithoutDecayDaughters && !trackParCov.isDecayDau))) { - histos.fill(HIST("h2dDCAxy"), trackParametrization.getPt(), dcaXY * 1e+4); // in microns, please - histos.fill(HIST("h2dDCAz"), trackParametrization.getPt(), dcaZ * 1e+4); // in microns, please + getHist(TH2, histPath + "h2dDCAxy")->Fill(trackParametrization.getPt(), dcaXY * 1e+4); + getHist(TH2, histPath + "h2dDCAz")->Fill(trackParametrization.getPt(), dcaZ * 1e+4); histos.fill(HIST("hTrackXatDCA"), trackParametrization.getX()); } if (cascadeDecaySettings.doXiQA) { @@ -1073,6 +1109,7 @@ struct OnTheFlyTracker { tableTracksDCACov(dcaInfo.getSigmaY2(), dcaInfo.getSigmaZ2()); } } + tableOTFLUTConfigId(icfg); tableStoredTracks(tableCollisions.lastIndex(), trackType, trackParCov.getX(), trackParCov.getAlpha(), trackParCov.getY(), trackParCov.getZ(), trackParCov.getSnp(), trackParCov.getTgl(), trackParCov.getQ2Pt()); tableTracksExtension(trackParCov.getPt(), trackParCov.getP(), trackParCov.getEta(), trackParCov.getPhi()); @@ -1167,9 +1204,18 @@ struct OnTheFlyTracker { } // do bookkeeping of fastTracker tracking - histos.fill(HIST("hCovMatOK"), 0.0f, fastTracker.GetCovMatNotOK()); - histos.fill(HIST("hCovMatOK"), 1.0f, fastTracker.GetCovMatOK()); + if (enableSecondarySmearing) { + histos.fill(HIST("hCovMatOK"), 0.0f, fastTracker[icfg]->GetCovMatNotOK()); + histos.fill(HIST("hCovMatOK"), 1.0f, fastTracker[icfg]->GetCovMatOK()); + } } // end process + + void process(aod::McCollision const& mcCollision, aod::McParticles const& mcParticles) + { + for (size_t icfg = 0; icfg < mSmearer.size(); ++icfg) { + processWithLUTs(mcCollision, mcParticles, static_cast(icfg)); + } + } }; /// Extends TracksExtra if necessary diff --git a/ALICE3/TableProducer/alice3-multicharmTable.cxx b/ALICE3/TableProducer/alice3-multicharmTable.cxx index 890b645bb51..b642e18ed6a 100644 --- a/ALICE3/TableProducer/alice3-multicharmTable.cxx +++ b/ALICE3/TableProducer/alice3-multicharmTable.cxx @@ -25,6 +25,7 @@ #include "ALICE3/DataModel/OTFRICH.h" #include "ALICE3/DataModel/OTFStrangeness.h" #include "ALICE3/DataModel/OTFTOF.h" +#include "ALICE3/DataModel/OTFTracks.h" #include "ALICE3/DataModel/tracksAlice3.h" #include "Common/Core/RecoDecay.h" #include "Common/Core/TrackSelection.h" @@ -53,7 +54,9 @@ #include #include #include +#include #include +#include using namespace o2; using namespace o2::framework; @@ -64,6 +67,7 @@ using std::array; // #define biton(var, nbit) ((var) |= (static_cast(1) << (nbit))) #define bitoff(var, nbit) ((var) &= ~(static_cast(1) << (nbit))) //((a) &= ~(1ULL<<(b))) #define bitcheck(var, nbit) ((var) & (static_cast(1) << (nbit))) +#define getHist(type, name) std::get>(histPointers[name]) using FullTracksExt = soa::Join; @@ -71,7 +75,7 @@ using FullTracksExt = soa::Join; using labeledTracks = soa::Join; using tofTracks = soa::Join; using richTracks = soa::Join; -using alice3tracks = soa::Join; +using alice3tracks = soa::Join; struct alice3multicharmTable { SliceCache cache; @@ -111,7 +115,7 @@ struct alice3multicharmTable { Configurable minPiCPt{"minPiCPt", 0.15, "Minimum pT for XiC pions"}; Configurable minPiCCPt{"minPiCCPt", 0.3, "Minimum pT for XiCC pions"}; - Configurable minNTracks{"minNTracks", -1, "Minimum number of tracks"}; + Configurable> minNTracks{"minNTracks", {-1}, "Minimum number of tracks"}; Configurable minXiRadius{"minXiRadius", 0.5, "Minimum R2D for XiC decay (cm)"}; Configurable minXiCRadius{"minXiCRadius", 0.001, "Minimum R2D for XiC decay (cm)"}; @@ -149,6 +153,8 @@ struct alice3multicharmTable { o2::vertexing::DCAFitterN<3> fitter3; HistogramRegistry histos{"histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + std::map histPointers; + std::vector savedConfigs; Partition trueXi = aod::mcparticle::pdgCode == 3312; Partition trueXiC = aod::mcparticle::pdgCode == 4232; @@ -389,6 +395,15 @@ struct alice3multicharmTable { return returnValue; } + template + bool checkSameLUTConf(TTrackType const& track1, const int track2) + { + if (track1.lutConfigId() == track2) { + return true; + } + return false; + } + void init(InitContext&) { // initialize O2 2-prong fitter (only once) @@ -484,6 +499,21 @@ struct alice3multicharmTable { } } + void initConf(const int icfg) + { + const bool confExists = std::find(savedConfigs.begin(), savedConfigs.end(), icfg) != savedConfigs.end(); + if (confExists) { + return; + } + savedConfigs.push_back(icfg); + + // do more plots + std::string histPath = "Configuration_" + std::to_string(icfg) + "/"; + histPointers.insert({histPath + "hMassXiCC", histos.add((histPath + "hMassXiCC").c_str(), "hMassXiCC", {kTH1D, {{axisXiCCMass}}})}); + histPointers.insert({histPath + "hNCollisions", histos.add((histPath + "hNCollisions").c_str(), "hNCollisions", {kTH1D, {{2, 0.5, 2.5}}})}); + histPointers.insert({histPath + "hNTracks", histos.add((histPath + "hNTracks").c_str(), "hNTracks", {kTH1D, {{20000, 0, 20000}}})}); + } + //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* void processGenerated(aod::McParticles const&) { @@ -499,51 +529,50 @@ struct alice3multicharmTable { //*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* void processFindXiCC(aod::Collision const& collision, alice3tracks const& tracks, aod::McParticles const&, aod::UpgradeCascades const& cascades) { - histos.fill(HIST("hNCollisions"), 1); - histos.fill(HIST("hNTracks"), tracks.size()); - - if (tracks.size() < minNTracks) - return; - - histos.fill(HIST("hNCollisions"), 2); - // group with this collision // n.b. cascades do not need to be grouped, being used directly in iterator-grouping auto tracksPiFromXiCgrouped = tracksPiFromXiC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); auto tracksPiFromXiCCgrouped = tracksPiFromXiCC->sliceByCached(aod::track::collisionId, collision.globalIndex(), cache); - if (doDCAplots) { - for (auto const& cascade : cascades) { - if (cascade.has_cascadeTrack()) { - auto track = cascade.cascadeTrack_as(); // de-reference cascade track - histos.fill(HIST("h2dDCAxyVsPtXiFromXiC"), track.pt(), track.dcaXY() * 1e+4); - } else { - LOGF(info, "Damn, something is wrong"); - } - } - for (auto const& track : tracks) { - if (bitcheck(track.decayMap(), kTruePiFromXiC)) - histos.fill(HIST("h2dDCAxyVsPtPiFromXiC"), track.pt(), track.dcaXY() * 1e+4); - if (bitcheck(track.decayMap(), kTruePiFromXiCC)) - histos.fill(HIST("h2dDCAxyVsPtPiFromXiCC"), track.pt(), track.dcaXY() * 1e+4); - } + static constexpr int kMaxLUTConfigs = 20; + std::vector nTracks(kMaxLUTConfigs); + for (auto const& track : tracks) { + int lutConfigId = track.lutConfigId(); + nTracks[lutConfigId]++; + + if (bitcheck(track.decayMap(), kTruePiFromXiC)) + histos.fill(HIST("h2dDCAxyVsPtPiFromXiC"), track.pt(), track.dcaXY() * 1e+4); + if (bitcheck(track.decayMap(), kTruePiFromXiCC)) + histos.fill(HIST("h2dDCAxyVsPtPiFromXiCC"), track.pt(), track.dcaXY() * 1e+4); } for (auto const& xiCand : cascades) { - histos.fill(HIST("hMassXi"), xiCand.mXi()); + auto xi = xiCand.cascadeTrack_as(); // de-reference cascade track + int lutConfigId = xi.lutConfigId(); + initConf(lutConfigId); + if (minNTracks.value.size() < static_cast(lutConfigId)) { + if (nTracks[lutConfigId] < minNTracks.value.front()) { + continue; // fallback to first + } + } else { + if (nTracks[lutConfigId] < minNTracks.value[lutConfigId]) { + continue; + } + } + std::string histPath = "Configuration_" + std::to_string(lutConfigId) + "/"; + histos.fill(HIST("hMassXi"), xiCand.mXi()); + histos.fill(HIST("h2dDCAxyVsPtXiFromXiC"), xi.pt(), xi.dcaXY() * 1e+4); if (std::fabs(xiCand.mXi() - o2::constants::physics::MassXiMinus) > massWindowXi) continue; // out of mass region uint32_t nCombinationsC = 0; - auto xi = xiCand.cascadeTrack_as(); // de-reference cascade track auto piFromXi = xiCand.bachTrack_as(); // de-reference bach track auto piFromLa = xiCand.negTrack_as(); // de-reference neg track auto prFromLa = xiCand.posTrack_as(); // de-reference pos track if (!bitcheck(xi.decayMap(), kTrueXiFromXiC)) continue; - if (std::fabs(xi.dcaXY()) < xiFromXiC_dcaXYconstant || std::fabs(xi.dcaZ()) < xiFromXiC_dcaZconstant) continue; // likely a primary xi @@ -555,11 +584,12 @@ struct alice3multicharmTable { histos.fill(HIST("hMinXiDecayRadius"), xiCand.cascRadius()); for (auto const& pi1c : tracksPiFromXiCgrouped) { + if (!checkSameLUTConf(pi1c, lutConfigId)) + continue; if (mcSameMotherCheck && !checkSameMother(xi, pi1c)) continue; if (xiCand.posTrackId() == pi1c.globalIndex() || xiCand.negTrackId() == pi1c.globalIndex() || xiCand.bachTrackId() == pi1c.globalIndex()) continue; // avoid using any track that was already used - if (pi1c.pt() < minPiCPt) continue; // too low momentum @@ -572,15 +602,14 @@ struct alice3multicharmTable { histos.fill(HIST("hInnerTOFTrackTimeRecoPi1c"), pi1cTOFDiffInner); // second pion from XiC decay for starts here for (auto const& pi2c : tracksPiFromXiCgrouped) { + if (!checkSameLUTConf(pi2c, lutConfigId)) + continue; if (mcSameMotherCheck && !checkSameMother(xi, pi2c)) continue; // keep only if same mother - if (pi1c.globalIndex() >= pi2c.globalIndex()) continue; // avoid same-mother, avoid double-counting - if (xiCand.posTrackId() == pi2c.globalIndex() || xiCand.negTrackId() == pi2c.globalIndex() || xiCand.bachTrackId() == pi2c.globalIndex()) continue; // avoid using any track that was already used - if (pi2c.pt() < minPiCPt) continue; // too low momentum @@ -644,6 +673,9 @@ struct alice3multicharmTable { // attempt XiCC finding uint32_t nCombinationsCC = 0; for (auto const& picc : tracksPiFromXiCCgrouped) { + if (!checkSameLUTConf(picc, lutConfigId)) + continue; + if (mcSameMotherCheck && !checkSameMotherExtra(xi, picc)) continue; @@ -736,6 +768,8 @@ struct alice3multicharmTable { histos.fill(HIST("hCharmBuilding"), 3.0f); histos.fill(HIST("hMassXiCC"), thisXiCCcandidate.mass); + getHist(TH1, histPath + "hMassXiCC")->Fill(thisXiCCcandidate.mass); + histos.fill(HIST("hPtXiCC"), thisXiCCcandidate.pt); histos.fill(HIST("hEtaXiCC"), thisXiCCcandidate.eta); histos.fill(HIST("h3dMassXiCC"), thisXiCCcandidate.pt, thisXiCCcandidate.eta, thisXiCCcandidate.mass); @@ -762,9 +796,8 @@ struct alice3multicharmTable { xicProperLength, xicDecayDistanceFromPV, xiccProperLength, - pi1c.pt(), - pi2c.pt(), - picc.pt()); + pi1c.pt(), pi2c.pt(), picc.pt(), + lutConfigId); multiCharmPID( pi1cTOFDiffInner, pi1c.nSigmaPionInnerTOF(), diff --git a/ALICE3/Tasks/alice3-multicharm.cxx b/ALICE3/Tasks/alice3-multicharm.cxx index f001cb6e08c..606322606bd 100644 --- a/ALICE3/Tasks/alice3-multicharm.cxx +++ b/ALICE3/Tasks/alice3-multicharm.cxx @@ -71,6 +71,7 @@ using multiCharmTracksFull = soa::Join histPointers; + std::vector savedConfigs; std::string histPath; std::map pdgToBin; @@ -287,6 +288,20 @@ struct alice3multicharm { } } + void initConf(int icfg) + { + const bool confExists = std::find(savedConfigs.begin(), savedConfigs.end(), icfg) != savedConfigs.end(); + if (confExists) { + return; + } + savedConfigs.push_back(icfg); + + // do more plots + histPath = "Configuration_" + std::to_string(icfg) + "/"; + histPointers.insert({histPath + "hXiccMass", histos.add((histPath + "hXiccMass").c_str(), "hXiccMass", {kTH1D, {{axisXiccMass}}})}); + histPointers.insert({histPath + "h3dXicc", histos.add((histPath + "h3dXicc").c_str(), "h3dXicc", {kTH3D, {{axisPt, axisEta, axisXiccMass}}})}); + } + int getBin(const std::map& pdgToBin, int pdg) { auto it = pdgToBin.find(pdg); @@ -297,6 +312,9 @@ struct alice3multicharm { void genericProcessXicc(TMCharmCands const& xiccCands) { for (const auto& xiccCand : xiccCands) { + int icfg = xiccCand.lutConfigId(); + initConf(icfg); + if (bdt.enableML) { std::vector inputFeatures{ xiccCand.xicDauDCA(), @@ -488,6 +506,10 @@ struct alice3multicharm { histos.fill(HIST("hMCharmBuilding"), 21); } + histPath = "Configuration_" + std::to_string(icfg) + "/"; + getHist(TH1, histPath + "hXiccMass")->Fill(xiccCand.xiccMass()); + getHist(TH3, histPath + "h3dXicc")->Fill(xiccCand.xiccPt(), xiccCand.xiccEta(), xiccCand.xiccMass()); + histos.fill(HIST("SelectionQA/hDCAXicDaughters"), xiccCand.xicDauDCA() * 1e+4); histos.fill(HIST("SelectionQA/hDCAXiccDaughters"), xiccCand.xiccDauDCA() * 1e+4); histos.fill(HIST("SelectionQA/hDCAxyXi"), std::fabs(xiccCand.xiDCAxy() * 1e+4));