Belle II Software  release-08-01-10
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 header.
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 using namespace Belle2;
25 
26 //-----------------------------------------------------------------
27 // Register module
28 //-----------------------------------------------------------------
29 
30 REG_MODULE(ParticleListManipulator);
31 
32 //-----------------------------------------------------------------
33 // Implementation
34 //-----------------------------------------------------------------
35 
36 ParticleListManipulatorModule::ParticleListManipulatorModule():
37  m_variable(nullptr)
38 
39 {
40  setDescription("Manipulates ParticleLists: copies/merges/performs particle selection");
42 
43  // Add parameters
44  addParam("outputListName", m_outputListName, "Output ParticleList name");
45 
46  vector<string> defaultList;
47  addParam("inputListNames", m_inputListNames,
48  "list of input ParticleList names", defaultList);
49 
50  addParam("cut", m_cutParameter, "Selection criteria to be applied", std::string(""));
51 
52  addParam("variable", m_variableName, "Variable which defines the best duplicate (see ``selectLowest`` for ordering)",
53  std::string("mdstIndex"));
54  addParam("preferLowest", m_preferLowest,
55  "If true, duplicate with lowest value of ``variable`` is accepted, otherwise higher one.", true);
56 
57  addParam("writeOut", m_writeOut,
58  "If true, the output ParticleList will be saved by RootOutput. If false, it will be ignored when writing the file.", false);
59 
60  addParam("ignoreMotherFlavor", m_ignoreMotherFlavor,
61  "If true, the flavor of the mother particle is ignored.", false);
62 
63  // initializing the rest of private members
64  m_pdgCode = 0;
66 }
67 
69 {
70  m_particles.isRequired();
71 
72  m_pdgCode = 0;
73 
74  // check the validity of output ParticleList name
76  if (!valid)
77  B2ERROR("ParticleListManipulatorModule::initialize Invalid output ParticleList name: " << m_outputListName);
78 
79  // Output particle
81 
82  m_pdgCode = mother->getPDGCode();
83 
84  // Some labels are reserved for the particle loader which loads all particles of the corresponding type.
85  // If people apply cuts or merge particle lists, the resulting particle lists are not allowed to have these names.
86  // Otherwise, very dangerous bugs could be introduced.
87  string listLabel = mother->getLabel();
88  // For final state particles we protect the label "all".
89  if (Const::finalStateParticlesSet.contains(Const::ParticleType(abs(m_pdgCode))) and listLabel == "all") {
90  B2FATAL("You have tried to create the list " << m_outputListName <<
91  " but the label 'all' is forbidden for user-defined lists of final-state particles." <<
92  " It could introduce *very* dangerous bugs.");
93  } else if (listLabel == "V0" and
94  not(("K_S0:mdst" == m_inputListNames[0]) or ("Lambda0:mdst" == m_inputListNames[0]) or ("gamma:v0mdst" == m_inputListNames[0]))) {
95  // the label V0 is also protected
96  // copying of some B2BII V0 lists has to be allowed to not break the FEI
97  B2FATAL("You have tried to create the list " << m_outputListName <<
98  " but the label " << listLabel << " is not allowed for merged or copied particle lists.");
99  }
100 
101  if (listLabel == "V0" and
102  (("K_S0:mdst" == m_inputListNames[0]) or ("Lambda0:mdst" == m_inputListNames[0]) or ("gamma:v0mdst" == m_inputListNames[0])))
103  m_exceptionForV0B2BII = true;
104 
107 
108  // Input lists
109  for (const std::string& listName : m_inputListNames) {
110  if (listName == m_outputListName) {
111  B2ERROR("ParticleListManipulatorModule: cannot copy Particles from " << listName <<
112  " to itself! Use applyCuts() (ParticleSelector module) instead.");
113  } else if (!m_decaydescriptor.init(listName)) {
114  B2ERROR("Invalid input ParticleList name: " << listName);
115  } else {
117  }
118  }
119 
121  m_particleList.registerInDataStore(m_outputListName, flags);
123  m_antiParticleList.registerInDataStore(m_outputAntiListName, flags);
124  }
125 
127  if (!m_variable) {
128  B2ERROR("Variable '" << m_variableName << "' is not available in Variable::Manager!");
129  }
130  if (!(m_variable->variabletype == Variable::Manager::VariableDataType::c_double
131  or m_variable->variabletype == Variable::Manager::VariableDataType::c_int)) {
132  B2ERROR("Variable '" << m_variableName << "' has wrong data type! It must be either double or integer.");
133  }
135 }
136 
138 {
139  // clear the list
140  m_particlesInTheList.clear();
141 
142  bool existingList = m_particleList.isValid();
143 
144  if (!existingList) {
145  // new particle list: create it
146  m_particleList.create();
148 
150  m_antiParticleList.create();
152 
153  m_antiParticleList->bindAntiParticleList(*(m_particleList));
154  }
155  } else {
156  // output list already contains Particles
157  // fill m_particlesInTheList with unique
158  // identifiers of particles already in
159  for (unsigned i = 0; i < m_particleList->getListSize(); i++) {
160  const Particle* particle = m_particleList->getParticle(i);
161 
162  std::vector<int> idSeq;
163  fillUniqueIdentifier(particle, idSeq, m_ignoreMotherFlavor);
164  m_particlesInTheList.push_back(idSeq);
165  }
166  }
167 
169  m_particleList->setEditable(true);
170 
171  // create list of candidate indices and corresponding sorting values
172  typedef std::pair<double, unsigned int> ValueIndexPair;
173  std::vector<ValueIndexPair> valueToIndex;
174 
175  // fill all particles from input lists that pass selection criteria into comparison list
176  for (const auto& inputListName : m_inputListNames) {
177  const StoreObjPtr<ParticleList> inPList(inputListName);
178  if (!inPList.isValid()) continue;
179 
180  std::vector<int> fsParticles = inPList->getList(ParticleList::EParticleType::c_FlavorSpecificParticle, false);
181  const std::vector<int>& scParticles = inPList->getList(ParticleList::EParticleType::c_SelfConjugatedParticle, false);
182  const std::vector<int>& fsAntiParticles = inPList->getList(ParticleList::EParticleType::c_FlavorSpecificParticle, true);
183 
184  fsParticles.insert(fsParticles.end(), scParticles.begin(), scParticles.end());
185  fsParticles.insert(fsParticles.end(), fsAntiParticles.begin(), fsAntiParticles.end());
186 
187  for (int fsParticle : fsParticles) {
188  const Particle* part = m_particles[fsParticle];
189 
190  if (m_cut->check(part)) {
191  double value = std::numeric_limits<double>::quiet_NaN();;
192  if (std::holds_alternative<double>(m_variable->function(part))) {
193  value = std::get<double>(m_variable->function(part));
194  } else if (std::holds_alternative<int>(m_variable->function(part))) {
195  value = std::get<int>(m_variable->function(part));
196  }
197  valueToIndex.emplace_back(value, part->getArrayIndex());
198  }
199  }
200  }
201 
202  // use stable sort to make sure we keep the relative order of elements with
203  // same value as it was before
204  if (m_preferLowest) {
205  std::stable_sort(valueToIndex.begin(), valueToIndex.end(), ValueIndexPairSorting::lowerPair<ValueIndexPair>);
206  } else {
207  std::stable_sort(valueToIndex.begin(), valueToIndex.end(), ValueIndexPairSorting::higherPair<ValueIndexPair>);
208  }
209 
210  // starting from the best candidate add all particles to output list that are not already in it
211  for (const auto& candidate : valueToIndex) {
212  const Particle* part = m_particles[candidate.second];
213 
214  std::vector<int> idSeq;
216  bool uniqueSeq = isUnique(idSeq);
217 
218  if (uniqueSeq) {
219  m_particleList->addParticle(part);
220  m_particlesInTheList.push_back(idSeq);
221  }
222  }
223 
225  m_particleList->setEditable(false);
226 
227 }
228 
229 void ParticleListManipulatorModule::fillUniqueIdentifier(const Particle* p, std::vector<int>& idSequence, bool ignoreMotherFlavor)
230 {
231  if (ignoreMotherFlavor) idSequence.push_back(abs(p->getPDGCode()));
232  else idSequence.push_back(p->getPDGCode());
233 
234  if (p->getNDaughters() == 0) {
235  idSequence.push_back(p->getParticleSource());
236  idSequence.push_back(p->getMdstArrayIndex());
237  } else {
238  idSequence.push_back(p->getNDaughters());
239  auto daughters = p->getDaughters();
240  // sorting the daughters by their pdgCode to identify decay chains only differing by the order of their daughters
241  sort(daughters.begin(), daughters.end(), [](const auto a, const auto b) {
242  return a->getPDGCode() > b->getPDGCode();
243  });
244  // this is not FSP (go one level down)
245  for (const auto& daughter : daughters)
246  fillUniqueIdentifier(daughter, idSequence, false);
247  }
248 }
249 
250 bool ParticleListManipulatorModule::isUnique(const std::vector<int>& idSeqOUT)
251 {
252  for (const auto& idSeqIN : m_particlesInTheList) {
253  bool sameSeq = (idSeqIN == idSeqOUT);
254  if (sameSeq)
255  return false;
256  }
257 
258  return true;
259 }
The ParticleType class for identifying different particle types.
Definition: Const.h:399
static const ParticleSet finalStateParticlesSet
set of final set particles that can be created by the ParticleLoader
Definition: Const.h:648
EStoreFlags
Flags describing behaviours of objects etc.
Definition: DataStore.h:69
@ c_WriteOut
Object/array should be saved by output modules.
Definition: DataStore.h:70
@ c_DontWriteOut
Object/array should be NOT saved by output modules.
Definition: DataStore.h:71
Represents a particle in the DecayDescriptor.
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)
Creates an instance of a cut and returns a unique_ptr to it, if you need a copy-able object instead y...
Definition: GeneralCut.h:84
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
bool m_isSelfConjugatedParticle
flag that indicates whether an anti-particle does not exist and therefore the output anti-ParticleLis...
bool m_preferLowest
Select the duplicate with the lowest value (instead of highest).
virtual void initialize() override
Initialize the Module.
virtual void event() override
Event processor.
std::string m_variableName
Variable which defines the best duplicate.
std::vector< std::string > m_inputListNames
input ParticleList names
StoreArray< Particle > m_particles
StoreArray of Particles.
std::vector< std::vector< int > > m_particlesInTheList
This vector holds unique identifiers (vector of ints) of all particles that are already included in t...
std::unique_ptr< Variable::Cut > m_cut
cut object which performs the cuts
bool m_ignoreMotherFlavor
flag whether flavor of mother particle should be ignored
bool isUnique(const std::vector< int > &idSequence)
Compares input idSequence to all sequences already included in the list.
const Variable::Manager::Var * m_variable
Variable which defines the best duplicate selection.
void fillUniqueIdentifier(const Particle *p, std::vector< int > &idSequence, bool ignoreMotherFlavor)
Fills unique identifier for the input particle.
DecayDescriptor m_decaydescriptor
Decay descriptor of the particle being selected.
bool m_exceptionForV0B2BII
true if the output List is V0 and input is K_S0:mdst, Lambda0:mdst, or gamma:v0mdst
StoreObjPtr< ParticleList > m_particleList
output particle list
std::string m_outputAntiListName
output anti-particle list name
StoreObjPtr< ParticleList > m_antiParticleList
output anti-particle list
std::string m_outputListName
output ParticleList name
Class to store reconstructed particles.
Definition: Particle.h:75
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:96
bool isValid() const
Check whether the object was created.
Definition: StoreObjPtr.h:111
const Var * getVariable(std::string name)
Get the variable belonging to the given key.
Definition: Manager.cc:57
static Manager & Instance()
get singleton instance.
Definition: Manager.cc:25
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:560
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
std::string antiParticleListName(const std::string &listName)
Returns name of anti-particle-list corresponding to listName.
Abstract base class for different kinds of events.
VariableDataType variabletype
data type of variable
Definition: Manager.h:133
FunctionPtr function
Pointer to function.
Definition: Manager.h:147