Belle II Software development
BestCandidateSelectionModule.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#include <analysis/modules/BestCandidateSelection/BestCandidateSelectionModule.h>
10
11#include <analysis/utility/ValueIndexPairSorting.h>
12
13#include <analysis/DecayDescriptor/DecayDescriptor.h>
14
15#include <framework/logging/Logger.h>
16#include <framework/utilities/MakeROOTCompatible.h>
17
18using namespace std;
19using namespace Belle2;
20
21
22REG_MODULE(BestCandidateSelection);
23
24
26 m_variable(nullptr)
27{
28 setDescription(R"DOC(Sort particles by the value of a given ``variable``
29in the input list and optionally remove particles after the nth position.
30
31Per default particles are sorted in descending order but it can be switched to
32an ascending order by setting ``selectLowest=True``. The convenience functions
33`modularAnalysis.rankByHighest` and `modularAnalysis.rankByLowest` set this
34parameter automatically based on their names.
35
36Particles will receive an extra-info field containing their rank as an integer
37starting at 1 (best). The name of this extra-info field defaults to
38``${variable}_rank`` but can be chosen freely using the ``outputVariable``
39parameter.
40
41All particles in the input list are ranked together in a single ordering,
42regardless of particle type (e.g. B+ and B-, or B0 and B0bar). The sorting is
43guaranteed to be stable: particles with the same value for ``variable`` will
44keep their relative order. That is, a particle "A" which was before another
45particle "B" in the same list and has the same value for ``variable`` will
46also stay before "B" after sorting.
47
48If ``allowMultiRank=False`` (the default) candidates with same value of
49``variable`` will have different ranks. If ``allowMultiRank=True`` they will
50share the same rank.
51
52IF ``numBest>0`` only candidates with this rank or better will remain in the
53output list. If ``allowMultiRank=True`` that means that there can be more than
54``numBest`` candidates in the output list if they share ranks.
55)DOC");
56
58
59 addParam("particleList", m_inputListName, "Name of the ParticleList to rank for best candidate");
60 addParam("variable", m_variableName, "Variable which defines the candidate ranking (see ``selectLowest`` for ordering)");
61 addParam("selectLowest", m_selectLowest, "If true, candidate with lower values of ``variable`` are better, otherwise higher is better", false);
62 addParam("allowMultiRank", m_allowMultiRank, "If true, candidates with identical values get identical rank", false);
63 addParam("numBest", m_numBest, "Keep only particles with this rank or better. If ``allowMultiRank=False`` this is "
64 "identical to the maximum amount of candidates left in the list. Otherwise there may be more candidates if "
65 "some share the same rank (0: keep all)", 0);
66 addParam("cut", m_cutParameter, "Only candidates passing the cut will be ranked. The others will have rank -1.", std::string(""));
67 addParam("outputVariable", m_outputVariableName,
68 "Name for created variable, which contains the rank for the particle. If not provided, the standard name ``${variable}_rank`` is used.");
69 addParam("overwriteRank", m_overwriteRank, "If true, the extraInfo of rank is overwritten when the particle has already the extraInfo.", false);
70
71}
72
74
76{
77 m_particles.isRequired();
78 m_inputList.isRequired(m_inputListName);
79
81 if (!m_variable) {
82 B2ERROR("Variable '" << m_variableName << "' is not available in Variable::Manager!");
83 }
84 if (!(m_variable->variabletype == Variable::Manager::VariableDataType::c_double or m_variable->variabletype == Variable::Manager::VariableDataType::c_int)) {
85 B2ERROR("Variable '" << m_variableName << "' has wrong data type! It must be either double or integer.");
86 }
87 if (m_numBest < 0) {
88 B2ERROR("value of numBest must be >= 0!");
89 } else if (m_numBest != 0) {
90 DecayDescriptor decaydescriptor;
91 decaydescriptor.init(m_inputListName);
92
93 const DecayDescriptorParticle* ddpart = decaydescriptor.getMother();
94 const int pdgCode = ddpart->getPDGCode();
95 const string listLabel = ddpart->getLabel();
96
97 // For final state particles we protect the label "all".
98 if (Const::finalStateParticlesSet.contains(Const::ParticleType(abs(pdgCode))) and listLabel == "all") {
99 B2FATAL("You are trying to apply a best-candidate-selection on the list " << m_inputListName <<
100 " but the label 'all' is protected for lists of final-state particles." <<
101 " It could introduce *very* dangerous bugs.");
102 } else if (listLabel == "MC" or listLabel == "V0") {
103 // the labels MC and V0 are also protected
104 B2FATAL("You are trying to apply a best-candidate-selection on the list " << m_inputListName <<
105 " but the label " << listLabel << " is protected and can not be reduced.");
106 }
107
108 }
109
111
112 // parse the name that the rank will be stored under
113 if (m_outputVariableName.empty()) {
114 std::string root_compatible_VariableName = MakeROOTCompatible::makeROOTCompatible(m_variableName);
115 m_outputVariableName = root_compatible_VariableName + "_rank";
116 }
117}
118
120{
121 // input list
122 if (!m_inputList) {
123 B2WARNING("Input list " << m_inputList.getName() << " was not created?");
124 return;
125 }
126
127 if (m_numBest == 0 and m_inputList->getIsReserved())
128 m_inputList->setEditable(true);
129
130 // create list of particle index and the corresponding value of variable
131 typedef std::pair<double, unsigned int> ValueIndexPair;
132 std::vector<ValueIndexPair> valueToIndex;
133 const unsigned int numParticles = m_inputList->getListSize();
134 valueToIndex.reserve(numParticles);
135 for (const Particle& p : *m_inputList) {
136 double value = 0;
137 auto var_result = m_variable->function(&p);
138 if (std::holds_alternative<double>(var_result)) {
139 value = std::get<double>(var_result);
140 } else if (std::holds_alternative<int>(var_result)) {
141 value = std::get<int>(var_result);
142 }
143 valueToIndex.emplace_back(value, p.getArrayIndex());
144 }
145
146 // use stable sort to make sure we keep the relative order of elements with
147 // same value as it was before
148 if (m_selectLowest) {
149 std::stable_sort(valueToIndex.begin(), valueToIndex.end(), ValueIndexPairSorting::lowerPair<ValueIndexPair>);
150 } else {
151 std::stable_sort(valueToIndex.begin(), valueToIndex.end(), ValueIndexPairSorting::higherPair<ValueIndexPair>);
152 }
153
154 // assign ranks and (optionally) remove everything but best candidates
155 m_inputList->clear();
156 int rank{1};
157 double previous_val{0};
158 bool first_candidate{true};
159 for (const auto& candidate : valueToIndex) {
160 Particle* p = m_particles[candidate.second];
161 if (!m_cut->check(p)) {
162 p->addExtraInfo(m_outputVariableName, -1);
163 m_inputList->addParticle(p);
164 continue;
165 }
166 if (first_candidate) {
167 first_candidate = false;
168 } else {
169 // If allowMultiRank, only increase rank when value changes
170 if (!m_allowMultiRank || (candidate.first != previous_val)) ++rank;
171 }
172
173 if ((m_numBest != 0) and (rank > m_numBest)) // Only keep particles with same rank or below
174 break;
175
176 if (!p->hasExtraInfo(m_outputVariableName))
177 p->addExtraInfo(m_outputVariableName, rank);
178 else if (m_overwriteRank)
179 p->setExtraInfo(m_outputVariableName, rank);
180
181 m_inputList->addParticle(p);
182 previous_val = candidate.first;
183
184
185 }
186
187 if (m_numBest == 0 and m_inputList->getIsReserved())
188 m_inputList->setEditable(false);
189}
bool m_allowMultiRank
Give the same rank to candidates with the same value.
virtual void initialize() override
Initialize the module (set up datastore)
virtual void event() override
Process an event.
std::string m_variableName
Variable which defines the candidate ranking.
StoreArray< Particle > m_particles
StoreArray of Particle objects.
bool m_selectLowest
Select the candidate with the lowest value (instead of highest).
virtual ~BestCandidateSelectionModule() override
Destructor.
std::unique_ptr< Variable::Cut > m_cut
cut object which performs the cuts
StoreObjPtr< ParticleList > m_inputList
input particle list
const Variable::Manager::Var * m_variable
Variable which defines the candidate ranking.
std::string m_cutParameter
Selection for candidates to be ranked.
int m_numBest
Number of best candidates to keep.
bool m_overwriteRank
If true, the extraInfo of rank is overwritten when the particle has already the extraInfo.
std::string m_outputVariableName
Name of generated Ranking-Variable, if specified by user.
std::string m_inputListName
name of input particle list.
The ParticleType class for identifying different particle types.
Definition Const.h:408
static const ParticleSet finalStateParticlesSet
set of final set particles that can be created by the ParticleLoader
Definition Const.h:657
Represents a particle in the DecayDescriptor.
int getPDGCode() const
Return PDG code.
std::string getLabel() const
The label of this particle, "default" returned, when no label set.
The DecayDescriptor stores information about a decay tree or parts of a decay tree.
bool init(const std::string &str)
Initialise the DecayDescriptor from given string.
const DecayDescriptorParticle * getMother() const
return mother.
static std::unique_ptr< GeneralCut > compile(const std::string &cut)
Definition GeneralCut.h:84
static std::string makeROOTCompatible(std::string str)
Remove special characters that ROOT dislikes in branch names, e.g.
void setDescription(const std::string &description)
Sets the description of the module.
Definition Module.cc:214
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
Definition Module.cc:208
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Definition Module.h:80
Class to store reconstructed particles.
Definition Particle.h:76
const Var * getVariable(std::string name)
Get the variable belonging to the given key.
Definition Manager.cc:58
static Manager & Instance()
get singleton instance.
Definition Manager.cc:26
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition Module.h:559
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition Module.h:649
Abstract base class for different kinds of events.
STL namespace.