Skip to content

Conversation

@lubynets
Copy link
Contributor

@lubynets lubynets commented Sep 8, 2025

  1. Proper lifetime of $\Lambda_{c}$ added into THnSparse in the taskLc workflow.
    2. Bugfix: in the treeCreatorLcToPKPi workflow the invariant mass of $pK\pi$ and $K\pi$ in Lite and Full tables was written either from dynamic column of the DCAFitter or KFParticle depending on the mode in which reconstruction was run. However the KF-related variables have a dedicated table, therefore there is no need to write them into Lite and Full. This PR fixes this issue and enables writing of mentioned invariant masses from only from dynamic column associated with DCAFitter.
    moved to a separate PR12906

@github-actions
Copy link

github-actions bot commented Sep 8, 2025

O2 linter results: ❌ 0 errors, ⚠️ 0 warnings, 🔕 0 disabled

@github-actions github-actions bot changed the title Add proper lifetime into THnSparse at taskLc [PWGHF] Add proper lifetime into THnSparse at taskLc Sep 8, 2025
@mfaggin
Copy link
Collaborator

mfaggin commented Sep 8, 2025

many thanks @lubynets for the development. I have two requests:

  1. I'd propose to put the ct axis optional in the Lc THnSparse object, i.e. adding a Configurable that allows a user to use or not such axis. This would prevent useless increases of THnSparse size for those who do not need such variable
  2. since the fix in the TreeCreator is completely orthogonal, would you mind removing it from here and proposing it in a separate PR?

Many thanks

@zhangbiao-phy
Copy link
Collaborator

zhangbiao-phy commented Sep 8, 2025

many thanks @lubynets for the development. I have two requests:

  1. I'd propose to put the ct axis optional in the Lc THnSparse object, i.e. adding a Configurable that allows a user to use or not such axis. This would prevent useless increases of THnSparse size for those who do not need such variable
  2. since the fix in the TreeCreator is completely orthogonal, would you mind removing it from here and proposing it in a separate PR?

Many thanks

I fully agree with Mattia's point, and this is also what I want to say, Thanks!

@lubynets
Copy link
Contributor Author

lubynets commented Sep 8, 2025

Hi @mfaggin, @zhangbiao-phy cc
Thanks for your feedback.

  1. I share your concerns about the size of the THnSparse, but in current implementation there is already one optional field, occupancy, and adding another one will significantly worsen readability and increase a probability of bug due to many if-else conditions.
    Therefore I propose another solution: make each field optional (i.e. for each THnSparse axis add a corresponding boolean configurable), and then prepare a vector of values to be filled, convert them into Double_t* and call Fill() function only once, without if-else. What do you think about this approach?
    And now, as a temporary solution, I propose to make the lifetime axis with a single bin by default, so those who do not need it will not suffer with increase of the size?

  2. Done.

@lubynets
Copy link
Contributor Author

lubynets commented Sep 8, 2025

P.S. In principle I can do the same (make occupancy and lifetime optional) without doing rest of fields optional.

@mfaggin
Copy link
Collaborator

mfaggin commented Sep 8, 2025

Thanks @lubynets . I'd personally avoid having 1 bool per axis, i.e. I'd just add a Configurable<bool> for the new ct variable. As you said in your last comment, the approach you propose with the vector should be doable also in this case, i.e. define a vector with the values that are always used to fill the THnSparse and add occupancy and ct if needed.

@vkucera
Copy link
Collaborator

vkucera commented Sep 8, 2025

Hi @mfaggin, @zhangbiao-phy cc Thanks for your feedback.

1. I share your concerns about the size of the THnSparse, but in current implementation there is already one optional field, occupancy, and adding another one will significantly worsen readability and increase a probability of bug due to many **if**-**else** conditions.
   Therefore I propose another solution: make _each_ field optional (i.e. for each THnSparse axis add a corresponding boolean configurable), and then prepare a vector of values to be filled, convert them into `Double_t*` and call `Fill()` function only once, without **if**-**else**. What do you think about this approach?
   And now, as a temporary solution, I propose to make the lifetime axis with a single bin by default, so those who do not need it will not suffer with increase of the size?

2. Done.

Great idea! I like it. If THnSparse can be filled with a vector (or an array pointer), we should advocate for this method wherever there are variable numbers of histogram dimensions.

Copy link
Collaborator

@mfaggin mfaggin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a few comments more (I leave them as comments and not as "request changes" so that other reviewers can move on approving it if I go offline in the meantime)

Comment on lines 357 to 362
if (storeProperLifetime) {
for (const auto& axes : std::array<std::vector<AxisSpec>*, 2>{&axesGen, &axesWithBdt}) {
if (!axes->empty()) {
axes->push_back(thnAxisProperLifetime);
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd put this always after the occupancy axis, to maintain backward compatibility with the current version of the code (please, fix the order of the axis and values filling everywhere)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

outputFD = candidate.mlProbLcToPKPi()[MlClassNonPrompt]; /// non-prompt score
}
/// Fill the ML outputScores and variables of candidate
std::vector<Double_t> valuesToFill{massLc, pt, cent, outputBkg, outputPrompt, outputFD, static_cast<Double_t>(numPvContributors), ptRecB, static_cast<Double_t>(originType)};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::vector<Double_t> valuesToFill{massLc, pt, cent, outputBkg, outputPrompt, outputFD, static_cast<Double_t>(numPvContributors), ptRecB, static_cast<Double_t>(originType)};
std::vector<double> valuesToFill{massLc, pt, cent, outputBkg, outputPrompt, outputFD, static_cast<double>(numPvContributors), ptRecB, static_cast<double>(originType)};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

outputFD = candidate.mlProbLcToPiKP()[MlClassNonPrompt]; /// non-prompt score
}
/// Fill the ML outputScores and variables of candidate (todo: add multiplicity)
std::vector<Double_t> valuesToFill{massLc, pt, cent, outputBkg, outputPrompt, outputFD, static_cast<Double_t>(numPvContributors), ptRecB, static_cast<Double_t>(originType)};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::vector<Double_t> valuesToFill{massLc, pt, cent, outputBkg, outputPrompt, outputFD, static_cast<Double_t>(numPvContributors), ptRecB, static_cast<Double_t>(originType)};
std::vector<double> valuesToFill{massLc, pt, cent, outputBkg, outputPrompt, outputFD, static_cast<double>(numPvContributors), ptRecB, static_cast<double>(originType)};


if (particle.originMcGen() == RecoDecay::OriginType::Prompt) {
if (fillTHn) {
std::vector<Double_t> valuesToFill{ptGen, cent, yGen, static_cast<Double_t>(numPvContributors), ptGenB, static_cast<Double_t>(originType)};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::vector<Double_t> valuesToFill{ptGen, cent, yGen, static_cast<Double_t>(numPvContributors), ptGenB, static_cast<Double_t>(originType)};
std::vector<double> valuesToFill{ptGen, cent, yGen, static_cast<double>(numPvContributors), ptGenB, static_cast<double>(originType)};

if (particle.originMcGen() == RecoDecay::OriginType::NonPrompt) {
ptGenB = mcParticles.rawIteratorAt(particle.idxBhadMotherPart()).pt();
if (fillTHn) {
std::vector<Double_t> valuesToFill{ptGen, cent, yGen, static_cast<Double_t>(numPvContributors), ptGenB, static_cast<Double_t>(originType)};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::vector<Double_t> valuesToFill{ptGen, cent, yGen, static_cast<Double_t>(numPvContributors), ptGenB, static_cast<Double_t>(originType)};
std::vector<double> valuesToFill{ptGen, cent, yGen, static_cast<double>(numPvContributors), ptGenB, static_cast<double>(originType)};

outputFD = candidate.mlProbLcToPKPi()[MlClassNonPrompt]; /// non-prompt score
}
/// Fill the ML outputScores and variables of candidate
std::vector<Double_t> valuesToFill{massLc, pt, cent, outputBkg, outputPrompt, outputFD, static_cast<Double_t>(numPvContributors)};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::vector<Double_t> valuesToFill{massLc, pt, cent, outputBkg, outputPrompt, outputFD, static_cast<Double_t>(numPvContributors)};
std::vector<double> valuesToFill{massLc, pt, cent, outputBkg, outputPrompt, outputFD, static_cast<double>(numPvContributors)};

}
registry.get<THnSparse>(HIST("hnLcVarsWithBdt"))->Fill(valuesToFill.data());
} else {
std::vector<Double_t> valuesToFill{massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, static_cast<Double_t>(numPvContributors)};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::vector<Double_t> valuesToFill{massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, static_cast<Double_t>(numPvContributors)};
std::vector<double> valuesToFill{massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, static_cast<double>(numPvContributors)};

outputFD = candidate.mlProbLcToPiKP()[MlClassNonPrompt]; /// non-prompt score
}
/// Fill the ML outputScores and variables of candidate
std::vector<Double_t> valuesToFill{massLc, pt, cent, outputBkg, outputPrompt, outputFD, static_cast<Double_t>(numPvContributors)};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::vector<Double_t> valuesToFill{massLc, pt, cent, outputBkg, outputPrompt, outputFD, static_cast<Double_t>(numPvContributors)};
std::vector<double> valuesToFill{massLc, pt, cent, outputBkg, outputPrompt, outputFD, static_cast<double>(numPvContributors)};

}
registry.get<THnSparse>(HIST("hnLcVarsWithBdt"))->Fill(valuesToFill.data());
} else {
std::vector<Double_t> valuesToFill{massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, static_cast<Double_t>(numPvContributors)};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::vector<Double_t> valuesToFill{massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, static_cast<Double_t>(numPvContributors)};
std::vector<double> valuesToFill{massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, static_cast<double>(numPvContributors)};

registry.get<THnSparse>(HIST("hnLcVarsWithBdt"))->Fill(valuesToFill.data());
} else {

std::vector<Double_t> valuesToFill{massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, static_cast<Double_t>(numPvContributors), ptRecB, static_cast<Double_t>(originType)};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::vector<Double_t> valuesToFill{massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, static_cast<Double_t>(numPvContributors), ptRecB, static_cast<Double_t>(originType)};
std::vector<double> valuesToFill{massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, static_cast<double>(numPvContributors), ptRecB, static_cast<double>(originType)};

Copy link
Collaborator

@mfaggin mfaggin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @lubynets it seems ok to me. Just to be sure before merging: I see that you do not add the ct axis to the axesStd and therefore to the hnLcVars object. Is it what you want or did you simply forget?

@lubynets
Copy link
Contributor Author

lubynets commented Sep 8, 2025

thanks @lubynets it seems ok to me. Just to be sure before merging: I see that you do not add the ct axis to the axesStd and therefore to the hnLcVars object. Is it what you want or did you simply forget?

Thanks for pointing to it! I did it by purpose because I supposed to run analysis always with calculation of Bdt scores.
But since now the lifetime is optional and configurable I think it can be added to the axesStd as well (?) - I mean it will not increase the THnSparse size unless user explicitly enables it, but it will make axesStd more uniform with axesWithBdt.

@alibuild
Copy link
Collaborator

alibuild commented Sep 8, 2025

Error while checking build/O2Physics/o2 for b6ded05 at 2025-09-08 17:53:

[142/2615] Building CXX object Common/TableProducer/CMakeFiles/O2Physicsexe-analysis-ese-table-producer.dir/eseTableProducer.cxx.o
[143/2615] Building CXX object Common/Tools/CMakeFiles/O2Physicslib-trackSelectionRequest.dir/G__O2PhysicstrackSelectionRequest.cxx.o
[144/2615] Linking CXX executable stage/bin/o2-analysis-trackqa-converter-003
[145/2615] Building CXX object Common/Tools/Multiplicity/CMakeFiles/O2Physicslib-multTools.dir/multCalibrator.cxx.o
[146/2615] Linking CXX executable stage/bin/o2-analysis-ese-table-producer
[147/2615] Building CXX object Common/Tools/Multiplicity/CMakeFiles/O2Physicslib-multTools.dir/multMCCalibrator.cxx.o
[148/2615] Building CXX object Common/Tools/CMakeFiles/O2Physicslib-trackSelectionRequest.dir/trackSelectionRequest.cxx.o
[149/2615] Building CXX object Common/Tools/Multiplicity/CMakeFiles/O2Physicslib-multTools.dir/G__O2PhysicsmultTools.cxx.o
[150/2615] Building CXX object Common/Tools/Multiplicity/CMakeFiles/O2Physicslib-multTools.dir/multGlauberNBDFitter.cxx.o
[151/2615] Building CXX object Common/TableProducer/CMakeFiles/O2Physicsexe-analysis-event-selection-service.dir/eventSelectionService.cxx.o
[152/2615] Linking CXX shared library stage/lib64/libO2PhysicstrackSelectionRequest.so
[153/2615] Linking CXX shared library stage/lib64/libO2PhysicsmultTools.so
[154/2615] Building CXX object Common/TableProducer/CMakeFiles/O2Physicsexe-analysis-muon-realignment.dir/muonRealignment.cxx.o
[155/2615] Linking CXX executable stage/bin/o2-analysis-event-selection-service
[INFO] Event selection autoconfiguring from metadata. Availability of info for Run 2/3 is 0
[INFO] Metadata info missing or incomplete. Make sure --aod-file is provided at the end of the last workflow and that the AO2D has metadata stored.
[INFO] Initializing with Run 3 data as default. Please note you will not be able to change settings manually.
[INFO] You should instead make sure the metadata is read in correctly.
[156/2615] Building CXX object Common/TableProducer/CMakeFiles/O2Physicsexe-analysis-mftmch-matching-data.dir/match-mft-mch-data.cxx.o
[157/2615] Building CXX object Common/TableProducer/CMakeFiles/O2Physicsexe-analysis-qvector-table.dir/qVectorsTable.cxx.o
[158/2615] Linking CXX executable stage/bin/o2-analysis-muon-realignment
[159/2615] Building CXX object Common/TableProducer/CMakeFiles/O2Physicsexe-analysis-multcenttable.dir/multCentTable.cxx.o
[160/2615] Linking CXX executable stage/bin/o2-analysis-qvector-table
[161/2615] Linking CXX executable stage/bin/o2-analysis-mftmch-matching-data
[162/2615] Building CXX object Common/TableProducer/CMakeFiles/O2Physicsexe-analysis-event-selection.dir/eventSelection.cxx.o
[163/2615] Generating G__O2PhysicsALICE3Core.cxx, ../../stage/lib64/G__O2PhysicsALICE3Core_rdict.pcm, ../../stage/lib64/libO2PhysicsALICE3Core.rootmap
[164/2615] Linking CXX executable stage/bin/o2-analysis-multcenttable
[165/2615] Building CXX object Common/TableProducer/CMakeFiles/O2Physicsexe-analysis-mftmch-matching-data-mc.dir/match-mft-mch-data-mc.cxx.o
[166/2615] Building CXX object Common/TableProducer/Converters/CMakeFiles/O2Physicsexe-analysis-run2-tiny-to-full-pid.dir/run2TinyToFullPID.cxx.o
[167/2615] Linking CXX executable stage/bin/o2-analysis-event-selection
[168/2615] Building CXX object Common/TableProducer/PID/CMakeFiles/O2Physicsexe-analysis-pid-its.dir/pidITS.cxx.o
[169/2615] Building CXX object Common/Tools/PID/CMakeFiles/O2Physicsexe-pidparam-tpc-response.dir/handleParamTPCResponse.cxx.o
[170/2615] Linking CXX executable stage/bin/o2-analysis-run2-tiny-to-full-pid
[171/2615] Linking CXX executable stage/bin/o2-pidparam-tpc-response
[172/2615] Building CXX object ALICE3/Core/CMakeFiles/O2Physicslib-ALICE3Core.dir/TOFResoALICE3.cxx.o
[173/2615] Building CXX object Common/Tools/PID/CMakeFiles/O2Physicsexe-check-pid-packing.dir/checkPidPacking.cxx.o
[174/2615] Linking CXX executable stage/bin/o2-analysis-pid-its
[175/2615] Linking CXX executable stage/bin/o2-analysis-mftmch-matching-data-mc
[176/2615] Linking CXX executable stage/bin/o2-check-pid-packing
[177/2615] Building CXX object ALICE3/Core/CMakeFiles/O2Physicslib-ALICE3Core.dir/TrackUtilities.cxx.o
[178/2615] Building CXX object ALICE3/Core/CMakeFiles/O2Physicslib-ALICE3Core.dir/DelphesO2TrackSmearer.cxx.o
[179/2615] Building CXX object ALICE3/Core/CMakeFiles/O2Physicslib-ALICE3Core.dir/G__O2PhysicsALICE3Core.cxx.o
[180/2615] Linking CXX shared library stage/lib64/libO2PhysicsALICE3Core.so
[181/2615] Building CXX object Common/TableProducer/CMakeFiles/O2Physicsexe-analysis-multiplicity-table.dir/multiplicityTable.cxx.o
[182/2615] Building CXX object Common/Tasks/CMakeFiles/O2Physicsexe-analysis-centrality-study.dir/centralityStudy.cxx.o
[183/2615] Building CXX object Common/Tasks/CMakeFiles/O2Physicsexe-analysis-muon-qa.dir/qaMuon.cxx.o
[184/2615] Linking CXX executable stage/bin/o2-analysis-multiplicity-table
[185/2615] Building CXX object Common/TableProducer/PID/CMakeFiles/O2Physicsexe-analysis-pid-tof-beta.dir/pidTOFbeta.cxx.o
[186/2615] Linking CXX executable stage/bin/o2-analysis-centrality-study
[187/2615] Generating G__O2PhysicsFastTracker.cxx, ../../stage/lib64/G__O2PhysicsFastTracker_rdict.pcm, ../../stage/lib64/libO2PhysicsFastTracker.rootmap

Full log here.

Copy link
Collaborator

@mfaggin mfaggin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @lubynets

@vkucera
Copy link
Collaborator

vkucera commented Sep 8, 2025

@lubynets Why is there so much code duplication? It seems like the same blocks appear 4 times.

@lubynets
Copy link
Contributor Author

lubynets commented Sep 8, 2025

@lubynets Why is there so much code duplication? It seems like the same blocks appear 4 times.

That was not introduced by my PR, I just inserted proper lifetime everywhere. I also noticed significant code duplication and planned to refactor it. But I think it can be better done in a separate PR (?)

@vkucera
Copy link
Collaborator

vkucera commented Sep 8, 2025

@lubynets Why is there so much code duplication? It seems like the same blocks appear 4 times.

That was not introduced by my PR, I just inserted proper lifetime everywhere. I also noticed significant code duplication and planned to refactor it. But I think it can be better done in a separate PR (?)

Of course I was not referring to the PR changes but to the pre-existing code structure. Thanks if you plan to refactor!

@lubynets
Copy link
Contributor Author

Dear @mfaggin (all code owners cc),
Thanks for approval the PR! Since the failed test build/O2Physics/o2/macOS is not marked as "Required", can you please merge this PR?

@mfaggin mfaggin merged commit eb33730 into AliceO2Group:master Sep 19, 2025
13 of 14 checks passed
@lubynets lubynets deleted the taskLc branch September 19, 2025 08:51
jmunozme pushed a commit to jmunozme/O2Physics that referenced this pull request Oct 3, 2025
jinhyunni pushed a commit to jinhyunni/O2Physics that referenced this pull request Oct 11, 2025
ThePhDane pushed a commit to ThePhDane/O2Physics that referenced this pull request Nov 3, 2025
jloemker pushed a commit to jloemker/O2Physics that referenced this pull request Nov 11, 2025
lmattei01 pushed a commit to lmattei01/O2Physics that referenced this pull request Dec 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pwghf PWG-HF

Development

Successfully merging this pull request may close these issues.

5 participants