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 //the "undefined order" bit is not strictly true in the current implementation, but details (with anti-particle lists) are tricky
29 setDescription(R"DOC(Sort particles by the value of a given ``variable``
30in the input list and optionally remove particles after the nth position.
31
32Per default particles are sorted in descending order but it can be switched to
33an ascending order by setting ``selectLowest=True``. The convenience functions
34`modularAnalysis.rankByHighest` and `modularAnalysis.rankByLowest` set this
35parameter automatically based on their names.
36
37Particles will receive an extra-info field containing their rank as an integer
38starting at 1 (best). The name of this extra-info field defaults to
39``${variable}_rank`` but can be chosen freely using the ``outputVariable``
40parameter.
41
42The ranking also takes antiparticles into account, so there will only be one
43B+- candidate with ``rank=1``. The remaining list is sorted from best to worst
44candidate (each charge, e.g. B+/B-, separately). The sorting is guaranteed
45to be stable between particle and anti particle list: particles with the same
46value for ``variable`` will keep their relative order. That is, a particle "A"
47which was before another particle "B" in the same list and has the same value
48for ``variable`` will also stay before "B" after sorting.
49
50If ``allowMultiRank=False`` (the default) candidates with same value of
51``variable`` will have different ranks. If ``allowMultiRank=True`` they will
52share the same rank.
53
54IF ``numBest>0`` only candidates with this rank or better will remain in the
55output list. If ``allowMultiRank=True`` that means that there can be more than
56``numBest`` candidates in the output list if they share ranks.
57)DOC");
58
60
61 addParam("particleList", m_inputListName, "Name of the ParticleList to rank for best candidate");
62 addParam("variable", m_variableName, "Variable which defines the candidate ranking (see ``selectLowest`` for ordering)");
63 addParam("selectLowest", m_selectLowest, "If true, candidate with lower values of ``variable`` are better, otherwise higher is better", false);
64 addParam("allowMultiRank", m_allowMultiRank, "If true, candidates with identical values get identical rank", false);
65 addParam("numBest", m_numBest, "Keep only particles with this rank or better. If ``allowMultiRank=False`` this is "
66 "identical to the maximum amount of candidates left in the list. Otherwise there may be more candidates if "
67 "some share the same rank (0: keep all)", 0);
68 addParam("cut", m_cutParameter, "Only candidates passing the cut will be ranked. The others will have rank -1.", std::string(""));
69 addParam("outputVariable", m_outputVariableName,
70 "Name for created variable, which contains the rank for the particle. If not provided, the standard name ``${variable}_rank`` is used.");
71 addParam("overwriteRank", m_overwriteRank, "If true, the extraInfo of rank is overwritten when the particle has already the extraInfo.", false);
72
73}
74
76
78{
79 m_particles.isRequired();
80 m_inputList.isRequired(m_inputListName);
81
83 if (!m_variable) {
84 B2ERROR("Variable '" << m_variableName << "' is not available in Variable::Manager!");
85 }
86 if (!(m_variable->variabletype == Variable::Manager::VariableDataType::c_double or m_variable->variabletype == Variable::Manager::VariableDataType::c_int)) {
87 B2ERROR("Variable '" << m_variableName << "' has wrong data type! It must be either double or integer.");
88 }
89 if (m_numBest < 0) {
90 B2ERROR("value of numBest must be >= 0!");
91 } else if (m_numBest != 0) {
92 DecayDescriptor decaydescriptor;
93 decaydescriptor.init(m_inputListName);
94
95 const DecayDescriptorParticle* ddpart = decaydescriptor.getMother();
96 const int pdgCode = ddpart->getPDGCode();
97 const string listLabel = ddpart->getLabel();
98
99 // For final state particles we protect the label "all".
100 if (Const::finalStateParticlesSet.contains(Const::ParticleType(abs(pdgCode))) and listLabel == "all") {
101 B2FATAL("You are trying to apply a best-candidate-selection on the list " << m_inputListName <<
102 " but the label 'all' is protected for lists of final-state particles." <<
103 " It could introduce *very* dangerous bugs.");
104 } else if (listLabel == "MC" or listLabel == "V0") {
105 // the labels MC and V0 are also protected
106 B2FATAL("You are trying to apply a best-candidate-selection on the list " << m_inputListName <<
107 " but the label " << listLabel << " is protected and can not be reduced.");
108 }
109
110 }
111
113
114 // parse the name that the rank will be stored under
115 if (m_outputVariableName.empty()) {
116 std::string root_compatible_VariableName = MakeROOTCompatible::makeROOTCompatible(m_variableName);
117 m_outputVariableName = root_compatible_VariableName + "_rank";
118 }
119}
120
122{
123 // input list
124 if (!m_inputList) {
125 B2WARNING("Input list " << m_inputList.getName() << " was not created?");
126 return;
127 }
128
129 if (m_numBest == 0 and m_inputList->getIsReserved())
130 m_inputList->setEditable(true);
131
132 // create list of particle index and the corresponding value of variable
133 typedef std::pair<double, unsigned int> ValueIndexPair;
134 std::vector<ValueIndexPair> valueToIndex;
135 const unsigned int numParticles = m_inputList->getListSize();
136 valueToIndex.reserve(numParticles);
137 for (const Particle& p : *m_inputList) {
138 double value = 0;
139 auto var_result = m_variable->function(&p);
140 if (std::holds_alternative<double>(var_result)) {
141 value = std::get<double>(var_result);
142 } else if (std::holds_alternative<int>(var_result)) {
143 value = std::get<int>(var_result);
144 }
145 valueToIndex.emplace_back(value, p.getArrayIndex());
146 }
147
148 // use stable sort to make sure we keep the relative order of elements with
149 // same value as it was before
150 if (m_selectLowest) {
151 std::stable_sort(valueToIndex.begin(), valueToIndex.end(), ValueIndexPairSorting::lowerPair<ValueIndexPair>);
152 } else {
153 std::stable_sort(valueToIndex.begin(), valueToIndex.end(), ValueIndexPairSorting::higherPair<ValueIndexPair>);
154 }
155
156 // assign ranks and (optionally) remove everything but best candidates
157 m_inputList->clear();
158 int rank{1};
159 double previous_val{0};
160 bool first_candidate{true};
161 for (const auto& candidate : valueToIndex) {
162 Particle* p = m_particles[candidate.second];
163 if (!m_cut->check(p)) {
164 p->addExtraInfo(m_outputVariableName, -1);
165 m_inputList->addParticle(p);
166 continue;
167 }
168 if (first_candidate) {
169 first_candidate = false;
170 } else {
171 // If allowMultiRank, only increase rank when value changes
172 if (!m_allowMultiRank || (candidate.first != previous_val)) ++rank;
173 }
174
175 if ((m_numBest != 0) and (rank > m_numBest)) // Only keep particles with same rank or below
176 break;
177
178 if (!p->hasExtraInfo(m_outputVariableName))
179 p->addExtraInfo(m_outputVariableName, rank);
180 else if (m_overwriteRank)
181 p->setExtraInfo(m_outputVariableName, rank);
182
183 m_inputList->addParticle(p);
184 previous_val = candidate.first;
185
186
187 }
188
189 if (m_numBest == 0 and m_inputList->getIsReserved())
190 m_inputList->setEditable(false);
191}
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.