Belle II Software  release-05-02-19
BestCandidateSelectionModule.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2014-2019 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Christian Pulvermacher, Martin Ritter *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 #include <analysis/modules/BestCandidateSelection/BestCandidateSelectionModule.h>
12 
13 #include <analysis/utility/ValueIndexPairSorting.h>
14 
15 #include <analysis/VariableManager/Utility.h>
16 #include <analysis/dataobjects/Particle.h>
17 
18 #include <framework/datastore/StoreArray.h>
19 #include <framework/logging/Logger.h>
20 #include <framework/utilities/MakeROOTCompatible.h>
21 
22 using namespace std;
23 using namespace Belle2;
24 
25 
26 REG_MODULE(BestCandidateSelection)
27 
28 
30  m_variable(nullptr)
31 {
32  //the "undefined order" bit is not strictly true in the current implementation, but details (with anti-particle lists) are tricky
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.
35 
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.
40 
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``
44 parameter.
45 
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.
53 
54 If ``allowMultiRank=False`` (the default) candidates with same value of
55 ``variable`` will have different ranks. If ``allowMultiRank=True`` they will
56 share the same rank.
57 
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.
61 )DOC");
62 
63  setPropertyFlags(c_ParallelProcessingCertified);
64 
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.");
75 
76 }
77 
78 BestCandidateSelectionModule::~BestCandidateSelectionModule() = default;
79 
80 void BestCandidateSelectionModule::initialize()
81 {
82  StoreArray<Particle>().isRequired();
83  m_inputList.isRequired(m_inputListName);
84 
85  m_variable = Variable::Manager::Instance().getVariable(m_variableName);
86  if (!m_variable) {
87  B2ERROR("Variable '" << m_variableName << "' is not available in Variable::Manager!");
88  }
89  if (m_numBest < 0) {
90  B2ERROR("value of numBest must be >= 0!");
91  }
92  m_cut = Variable::Cut::compile(m_cutParameter);
93 
94  // parse the name that the rank will be stored under
95  if (m_outputVariableName.empty()) {
96  std::string root_compatible_VariableName = makeROOTCompatible(m_variableName);
97  m_outputVariableName = root_compatible_VariableName + "_rank";
98  }
99 }
100 
101 void BestCandidateSelectionModule::event()
102 {
103  // input list
104  StoreArray<Particle> particles;
105  if (!m_inputList) {
106  B2WARNING("Input list " << m_inputList.getName() << " was not created?");
107  return;
108  }
109 
110  // create list of particle index and the corresponding value of variable
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());
118  }
119 
120  // use stable sort to make sure we keep the relative order of elements with
121  // same value as it was before
122  if (m_selectLowest) {
123  std::stable_sort(valueToIndex.begin(), valueToIndex.end(), ValueIndexPairSorting::lowerPair<ValueIndexPair>);
124  } else {
125  std::stable_sort(valueToIndex.begin(), valueToIndex.end(), ValueIndexPairSorting::higherPair<ValueIndexPair>);
126  }
127 
128  // assign ranks and (optionally) remove everything but best candidates
129  m_inputList->clear();
130  int rank{1};
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);
138  continue;
139  }
140  if (first_candidate) {
141  first_candidate = false;
142  } else {
143  if (!m_allowMultiRank || (candidate.first != previous_val)) ++rank;
144  }
145 
146  p->addExtraInfo(m_outputVariableName, rank);
147  m_inputList->addParticle(p);
148 
149  previous_val = candidate.first;
150 
151  if (m_numBest != 0 and rank >= m_numBest)
152  break;
153  }
154 }
REG_MODULE
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:652
Belle2::makeROOTCompatible
std::string makeROOTCompatible(std::string str)
Remove special characters that ROOT dislikes in branch names, e.g.
Definition: MakeROOTCompatible.cc:74
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::BestCandidateSelectionModule
Selects Particles with the highest values of 'variable' in the input list and removes all other parti...
Definition: BestCandidateSelectionModule.h:48
Belle2::Particle
Class to store reconstructed particles.
Definition: Particle.h:77
Belle2::StoreArray< Particle >