Belle II Software  release-06-01-15
ParticleListManipulatorModule.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 // Own include
10 #include <analysis/modules/ParticleListManipulator/ParticleListManipulatorModule.h>
11 
12 
13 // framework - DataStore
14 #include <framework/datastore/DataStore.h>
15 
16 // framework aux
17 #include <framework/logging/Logger.h>
18 
19 // utilities
20 #include <analysis/DecayDescriptor/ParticleListName.h>
21 #include <analysis/utility/ValueIndexPairSorting.h>
22 
23 using namespace std;
24 
25 namespace Belle2 {
31  //-----------------------------------------------------------------
32  // Register module
33  //-----------------------------------------------------------------
34 
35  REG_MODULE(ParticleListManipulator)
36 
37  //-----------------------------------------------------------------
38  // Implementation
39  //-----------------------------------------------------------------
40 
42  m_variable(nullptr)
43 
44  {
45  setDescription("Manipulates ParticleLists: copies/merges/performs particle selection");
46  setPropertyFlags(c_ParallelProcessingCertified);
47 
48  // Add parameters
49  addParam("outputListName", m_outputListName, "Output ParticleList name");
50 
51  vector<string> defaultList;
52  addParam("inputListNames", m_inputListNames,
53  "list of input ParticleList names", defaultList);
54 
55  addParam("cut", m_cutParameter, "Selection criteria to be applied", std::string(""));
56 
57  addParam("variable", m_variableName, "Variable which defines the best duplicate (see ``selectLowest`` for ordering)",
58  std::string("mdstIndex"));
59  addParam("preferLowest", m_preferLowest,
60  "If true, duplicate with lowest value of ``variable`` is accepted, otherwise higher one.", true);
61 
62  addParam("writeOut", m_writeOut,
63  "If true, the output ParticleList will be saved by RootOutput. If false, it will be ignored when writing the file.", false);
64 
65  // initializing the rest of private members
66  m_pdgCode = 0;
67  m_isSelfConjugatedParticle = false;
68  }
69 
70  void ParticleListManipulatorModule::initialize()
71  {
72  m_particles.isRequired();
73 
74  m_pdgCode = 0;
75 
76  // check the validity of output ParticleList name
77  bool valid = m_decaydescriptor.init(m_outputListName);
78  if (!valid)
79  B2ERROR("ParticleListManipulatorModule::initialize Invalid output ParticleList name: " << m_outputListName);
80 
81  // Output particle
82  const DecayDescriptorParticle* mother = m_decaydescriptor.getMother();
83 
84  m_pdgCode = mother->getPDGCode();
85 
86  // Some labels are reserved for the particle loader which loads all particles of the corresponding type.
87  // If people apply cuts or merge particle lists, the resulting particle lists are not allowed to have these names.
88  // Otherwise, very dangerous bugs could be introduced.
89  string listLabel = mother->getLabel();
90  // For final state particles we protect the label "all".
91  if (Const::finalStateParticlesSet.contains(Const::ParticleType(abs(m_pdgCode))) and listLabel == "all") {
92  B2FATAL("You have tried to create the list " << m_outputListName <<
93  " but the label 'all' is forbidden for user-defined lists of final-state particles." <<
94  " It could introduce *very* dangerous bugs.");
95  } else if ((listLabel == "MC") or (listLabel == "V0" and not(("K_S0:mdst" == m_inputListNames[0])
96  or ("Lambda0:mdst" == m_inputListNames[0]) or ("gamma:v0mdst" == m_inputListNames[0])))) {
97  // the labels MC, and V0 are also protected
98  // copying of some B2BII V0 lists has to be allowed to not break the FEI
99  B2FATAL("You have tried to create the list " << m_outputListName <<
100  " but the label " << listLabel << " is not allowed for merged or copied particle lists.");
101  }
102 
103  m_outputAntiListName = ParticleListName::antiParticleListName(m_outputListName);
104  m_isSelfConjugatedParticle = (m_outputListName == m_outputAntiListName);
105 
106  // Input lists
107  for (const std::string& listName : m_inputListNames) {
108  if (listName == m_outputListName) {
109  B2ERROR("ParticleListManipulatorModule: cannot copy Particles from " << listName <<
110  " to itself! Use applyCuts() (ParticleSelector module) instead.");
111  } else if (!m_decaydescriptor.init(listName)) {
112  B2ERROR("Invalid input ParticleList name: " << listName);
113  } else {
115  }
116  }
117 
118  DataStore::EStoreFlags flags = m_writeOut ? DataStore::c_WriteOut : DataStore::c_DontWriteOut;
119  m_particleList.registerInDataStore(m_outputListName, flags);
120  if (!m_isSelfConjugatedParticle) {
121  m_antiParticleList.registerInDataStore(m_outputAntiListName, flags);
122  }
123 
124  m_variable = Variable::Manager::Instance().getVariable(m_variableName);
125  if (!m_variable) {
126  B2ERROR("Variable '" << m_variableName << "' is not available in Variable::Manager!");
127  }
128  m_cut = Variable::Cut::compile(m_cutParameter);
129  }
130 
131  void ParticleListManipulatorModule::event()
132  {
133  // clear the list
134  m_particlesInTheList.clear();
135 
136  bool existingList = m_particleList.isValid();
137 
138  if (!existingList) {
139  // new particle list: create it
140  m_particleList.create();
141  m_particleList->initialize(m_pdgCode, m_outputListName);
142 
143  if (!m_isSelfConjugatedParticle) {
144  m_antiParticleList.create();
145  m_antiParticleList->initialize(-1 * m_pdgCode, m_outputAntiListName);
146 
147  m_antiParticleList->bindAntiParticleList(*(m_particleList));
148  }
149  } else {
150  // output list already contains Particles
151  // fill m_particlesInTheList with unique
152  // identifiers of particles already in
153  for (unsigned i = 0; i < m_particleList->getListSize(); i++) {
154  const Particle* particle = m_particleList->getParticle(i);
155 
156  std::vector<int> idSeq;
157  fillUniqueIdentifier(particle, idSeq);
158  m_particlesInTheList.push_back(idSeq);
159  }
160  }
161 
162  // create list of candidate indices and corresponding sorting values
163  typedef std::pair<double, unsigned int> ValueIndexPair;
164  std::vector<ValueIndexPair> valueToIndex;
165 
166  // fill all particles from input lists that pass selection criteria into comparison list
167  for (const auto& inputListName : m_inputListNames) {
168  const StoreObjPtr<ParticleList> inPList(inputListName);
169  if (!inPList.isValid()) continue;
170 
171  std::vector<int> fsParticles = inPList->getList(ParticleList::EParticleType::c_FlavorSpecificParticle, false);
172  const std::vector<int>& scParticles = inPList->getList(ParticleList::EParticleType::c_SelfConjugatedParticle, false);
173  const std::vector<int>& fsAntiParticles = inPList->getList(ParticleList::EParticleType::c_FlavorSpecificParticle, true);
174 
175  fsParticles.insert(fsParticles.end(), scParticles.begin(), scParticles.end());
176  fsParticles.insert(fsParticles.end(), fsAntiParticles.begin(), fsAntiParticles.end());
177 
178  for (int fsParticle : fsParticles) {
179  const Particle* part = m_particles[fsParticle];
180 
181  if (m_cut->check(part)) {
182  valueToIndex.emplace_back(m_variable->function(part), part->getArrayIndex());
183  }
184  }
185  }
186 
187  // use stable sort to make sure we keep the relative order of elements with
188  // same value as it was before
189  if (m_preferLowest) {
190  std::stable_sort(valueToIndex.begin(), valueToIndex.end(), ValueIndexPairSorting::lowerPair<ValueIndexPair>);
191  } else {
192  std::stable_sort(valueToIndex.begin(), valueToIndex.end(), ValueIndexPairSorting::higherPair<ValueIndexPair>);
193  }
194 
195  // starting from the best candidate add all particles to output list that are not already in it
196  for (const auto& candidate : valueToIndex) {
197  const Particle* part = m_particles[candidate.second];
198 
199  std::vector<int> idSeq;
200  fillUniqueIdentifier(part, idSeq);
201  bool uniqueSeq = isUnique(idSeq);
202 
203  if (uniqueSeq) {
204  m_particleList->addParticle(part);
205  m_particlesInTheList.push_back(idSeq);
206  }
207  }
208  }
209 
210  void ParticleListManipulatorModule::fillUniqueIdentifier(const Particle* p, std::vector<int>& idSequence)
211  {
212  idSequence.push_back(p->getPDGCode());
213 
214  if (p->getNDaughters() == 0) {
215  idSequence.push_back(p->getMdstArrayIndex());
216  } else {
217  idSequence.push_back(p->getNDaughters());
218  auto daughters = p->getDaughters();
219  // sorting the daughters by their pdgCode to identify decay chains only differing by the order of their daughters
220  sort(daughters.begin(), daughters.end(), [](const auto a, const auto b) {
221  return a->getPDGCode() > b->getPDGCode();
222  });
223  // this is not FSP (go one level down)
224  for (const auto& daughter : daughters)
225  fillUniqueIdentifier(daughter, idSequence);
226  }
227  }
228 
229  bool ParticleListManipulatorModule::isUnique(const std::vector<int>& idSeqOUT)
230  {
231  for (const auto& idSeqIN : m_particlesInTheList) {
232  bool sameSeq = (idSeqIN == idSeqOUT);
233  if (sameSeq)
234  return false;
235  }
236 
237  return true;
238  }
240 } // end Belle2 namespace
The ParticleType class for identifying different particle types.
Definition: Const.h:289
EStoreFlags
Flags describing behaviours of objects etc.
Definition: DataStore.h:69
Represents a particle in the DecayDescriptor.
Module for copying Particles (actually their indices) from two or more ParticleLists(s) to another Pa...
Class to store reconstructed particles.
Definition: Particle.h:74
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:95
bool isValid() const
Check whether the object was created.
Definition: StoreObjPtr.h:110
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
Abstract base class for different kinds of events.