11 #include <analysis/modules/BestCandidateSelection/BestCandidateSelectionModule.h>
13 #include <analysis/utility/ValueIndexPairSorting.h>
15 #include <analysis/VariableManager/Utility.h>
16 #include <analysis/dataobjects/Particle.h>
18 #include <framework/datastore/StoreArray.h>
19 #include <framework/logging/Logger.h>
20 #include <framework/utilities/MakeROOTCompatible.h>
33 setDescription(R
"DOC(Sort particles by the value of a given ``variable``
34 in the input list and optionally remove particles after the nth position.
36 Per default particles are sorted in descending order but it can be switched to
37 an ascending order by setting ``selectLowest=True``. The convenience functions
38 `modularAnalysis.rankByHighest` and `modularAnalysis.rankByLowest` set this
39 parameter automatically based on their names.
41 Particles will receive an extra-info field containing their rank as an integer
42 starting at 1 (best). The name of this extra-info field defaults to
43 ``${variable}_rank`` but can be chosen freely using the ``outputVariable``
46 The ranking also takes antiparticles into account, so there will only be one
47 B+- candidate with ``rank=1``. The remaining list is sorted from best to worst
48 candidate (each charge, e.g. B+/B-, separately). The sorting is guaranteed
49 to be stable between particle and anti particle list: particles with the same
50 value for ``variable`` will keep their relative order. That is, a particle "A"
51 which was before another particle "B" in the same list and has the same value
52 for ``variable`` will also stay before "B" after sorting.
54 If ``allowMultiRank=False`` (the default) candidates with same value of
55 ``variable`` will have different ranks. If ``allowMultiRank=True`` they will
58 IF ``numBest>0`` only candidates with this rank or better will remain in the
59 output list. If ``allowMultiRank=True`` that means that there can be more than
60 ``numBest`` candidates in the output list if they share ranks.
63 setPropertyFlags(c_ParallelProcessingCertified);
65 addParam("particleList", m_inputListName,
"Name of the ParticleList to rank for best candidate");
66 addParam(
"variable", m_variableName,
"Variable which defines the candidate ranking (see ``selectLowest`` for ordering)");
67 addParam(
"selectLowest", m_selectLowest,
"If true, candidate with lower values of ``variable`` are better, otherwise higher is better",
false);
68 addParam(
"allowMultiRank", m_allowMultiRank,
"If true, candidates with identical values get identical rank",
false);
69 addParam(
"numBest", m_numBest,
"Keep only particles with this rank or better. If ``allowMultiRank=False`` this is "
70 "identical to the maximum amount of candidates left in the list. Otherwise there may be more candidates if "
71 "some share the same rank (0: keep all)", 0);
72 addParam(
"cut", m_cutParameter,
"Only candidates passing the cut will be ranked. The others will have rank -1.", std::string(
""));
73 addParam(
"outputVariable", m_outputVariableName,
74 "Name for created variable, which contains the rank for the particle. If not provided, the standard name ``${variable}_rank`` is used.");
78 BestCandidateSelectionModule::~BestCandidateSelectionModule() =
default;
80 void BestCandidateSelectionModule::initialize()
83 m_inputList.isRequired(m_inputListName);
85 m_variable = Variable::Manager::Instance().getVariable(m_variableName);
87 B2ERROR(
"Variable '" << m_variableName <<
"' is not available in Variable::Manager!");
90 B2ERROR(
"value of numBest must be >= 0!");
92 m_cut = Variable::Cut::compile(m_cutParameter);
95 if (m_outputVariableName.empty()) {
97 m_outputVariableName = root_compatible_VariableName +
"_rank";
101 void BestCandidateSelectionModule::event()
106 B2WARNING(
"Input list " << m_inputList.getName() <<
" was not created?");
111 typedef std::pair<double, unsigned int> ValueIndexPair;
112 std::vector<ValueIndexPair> valueToIndex;
113 const unsigned int numParticles = m_inputList->getListSize();
114 valueToIndex.reserve(numParticles);
115 for (
const Particle& p : *m_inputList) {
116 double value = m_variable->function(&p);
117 valueToIndex.emplace_back(value, p.getArrayIndex());
122 if (m_selectLowest) {
123 std::stable_sort(valueToIndex.begin(), valueToIndex.end(), ValueIndexPairSorting::lowerPair<ValueIndexPair>);
125 std::stable_sort(valueToIndex.begin(), valueToIndex.end(), ValueIndexPairSorting::higherPair<ValueIndexPair>);
129 m_inputList->clear();
131 double previous_val{0};
132 bool first_candidate{
true};
133 for (
const auto& candidate : valueToIndex) {
134 Particle* p = particles[candidate.second];
135 if (!m_cut->check(p)) {
136 p->addExtraInfo(m_outputVariableName, -1);
137 m_inputList->addParticle(p);
140 if (first_candidate) {
141 first_candidate =
false;
143 if (!m_allowMultiRank || (candidate.first != previous_val)) ++rank;
146 p->addExtraInfo(m_outputVariableName, rank);
147 m_inputList->addParticle(p);
149 previous_val = candidate.first;
151 if (m_numBest != 0 and rank >= m_numBest)