Belle II Software development
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#include <analysis/VariableManager/Utility.h>
23
24using namespace std;
25using namespace Belle2;
26
27//-----------------------------------------------------------------
28// Register module
29//-----------------------------------------------------------------
30
31REG_MODULE(ParticleListManipulator);
32
33//-----------------------------------------------------------------
34// Implementation
35//-----------------------------------------------------------------
36
38 m_variable(nullptr)
39
40{
41 setDescription("Manipulates ParticleLists: copies/merges/performs particle selection");
43
44 // Add parameters
45 addParam("outputListName", m_outputListName, "Output ParticleList name");
46
47 vector<string> defaultList;
48 addParam("inputListNames", m_inputListNames,
49 "list of input ParticleList names", defaultList);
50
51 addParam("cut", m_cutParameter, "Selection criteria to be applied", std::string(""));
52
53 addParam("variable", m_variableName, "Variable which defines the best duplicate (see ``selectLowest`` for ordering)",
54 std::string("mdstIndex"));
55 addParam("preferLowest", m_preferLowest,
56 "If true, duplicate with lowest value of ``variable`` is accepted, otherwise higher one.", true);
57
58 addParam("writeOut", m_writeOut,
59 "If true, the output ParticleList will be saved by RootOutput. If false, it will be ignored when writing the file.", false);
60
61 addParam("ignoreMotherFlavor", m_ignoreMotherFlavor,
62 "If true, the flavor of the mother particle is ignored.", false);
63
64 // initializing the rest of private members
65 m_pdgCode = 0;
67}
68
70{
71 m_particles.isRequired();
72
73 m_pdgCode = 0;
74
75 // check the validity of output ParticleList name
76 bool valid = m_decaydescriptor.init(m_outputListName);
77 if (!valid)
78 B2ERROR("ParticleListManipulatorModule::initialize Invalid output ParticleList name: " << m_outputListName);
79
80 // Output particle
81 const DecayDescriptorParticle* mother = m_decaydescriptor.getMother();
82
83 m_pdgCode = mother->getPDGCode();
84
85 // Some labels are reserved for the particle loader which loads all particles of the corresponding type.
86 // If people apply cuts or merge particle lists, the resulting particle lists are not allowed to have these names.
87 // Otherwise, very dangerous bugs could be introduced.
88 string listLabel = mother->getLabel();
89 // For final state particles, except for neutrons, we protect the label "all".
90 if (Const::finalStateParticlesSet.contains(Const::ParticleType(abs(m_pdgCode))) and listLabel == "all" and
91 abs(m_pdgCode) != Const::neutron.getPDGCode()) {
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 == "V0" and
96 not(("K_S0:mdst" == m_inputListNames[0]) or ("Lambda0:mdst" == m_inputListNames[0]) or ("gamma:v0mdst" == m_inputListNames[0]))) {
97 // the label V0 is 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 if (listLabel == "V0" and
104 (("K_S0:mdst" == m_inputListNames[0]) or ("Lambda0:mdst" == m_inputListNames[0]) or ("gamma:v0mdst" == m_inputListNames[0])))
106
109
110 // Input lists
111 for (const std::string& listName : m_inputListNames) {
112 if (listName == m_outputListName) {
113 B2ERROR("ParticleListManipulatorModule: cannot copy Particles from " << listName <<
114 " to itself! Use applyCuts() (ParticleSelector module) instead.");
115 } else if (!m_decaydescriptor.init(listName)) {
116 B2ERROR("Invalid input ParticleList name: " << listName);
117 } else {
119 }
120 }
121
123 m_particleList.registerInDataStore(m_outputListName, flags);
125 m_antiParticleList.registerInDataStore(m_outputAntiListName, flags);
126 }
127
129 if (!m_variable) {
130 B2ERROR("Variable '" << m_variableName << "' is not available in Variable::Manager!");
131 }
132 if (!(m_variable->variabletype == Variable::Manager::VariableDataType::c_double
133 or m_variable->variabletype == Variable::Manager::VariableDataType::c_int)) {
134 B2ERROR("Variable '" << m_variableName << "' has wrong data type! It must be either double or integer.");
135 }
137}
138
140{
141 // clear the list
142 m_particlesInTheList.clear();
143
144 bool existingList = m_particleList.isValid();
145
146 if (!existingList) {
147 // new particle list: create it
148 m_particleList.create();
150
152 m_antiParticleList.create();
154
155 m_antiParticleList->bindAntiParticleList(*(m_particleList));
156 }
157 } else {
158 // output list already contains Particles
159 // fill m_particlesInTheList with unique
160 // identifiers of particles already in
161 for (unsigned i = 0; i < m_particleList->getListSize(); i++) {
162 const Particle* particle = m_particleList->getParticle(i);
163
164 std::vector<int> idSeq;
166 m_particlesInTheList.push_back(idSeq);
167 }
168 }
169
171 m_particleList->setEditable(true);
172
173 // create list of candidate indices and corresponding sorting values
174 typedef std::pair<double, unsigned int> ValueIndexPair;
175 std::vector<ValueIndexPair> valueToIndex;
176
177 // fill all particles from input lists that pass selection criteria into comparison list
178 for (const auto& inputListName : m_inputListNames) {
179 const StoreObjPtr<ParticleList> inPList(inputListName);
180 if (!inPList.isValid()) continue;
181
182 std::vector<int> fsParticles = inPList->getList(ParticleList::EParticleType::c_FlavorSpecificParticle, false);
183 const std::vector<int>& scParticles = inPList->getList(ParticleList::EParticleType::c_SelfConjugatedParticle, false);
184 const std::vector<int>& fsAntiParticles = inPList->getList(ParticleList::EParticleType::c_FlavorSpecificParticle, true);
185
186 fsParticles.insert(fsParticles.end(), scParticles.begin(), scParticles.end());
187 fsParticles.insert(fsParticles.end(), fsAntiParticles.begin(), fsAntiParticles.end());
188
189 for (int fsParticle : fsParticles) {
190 const Particle* part = m_particles[fsParticle];
191
192 if (m_cut->check(part)) {
193 double value = std::numeric_limits<double>::quiet_NaN();;
194 if (std::holds_alternative<double>(m_variable->function(part))) {
195 value = std::get<double>(m_variable->function(part));
196 } else if (std::holds_alternative<int>(m_variable->function(part))) {
197 value = std::get<int>(m_variable->function(part));
198 }
199 valueToIndex.emplace_back(value, part->getArrayIndex());
200 }
201 }
202 }
203
204 // use stable sort to make sure we keep the relative order of elements with
205 // same value as it was before
206 if (m_preferLowest) {
207 std::stable_sort(valueToIndex.begin(), valueToIndex.end(), ValueIndexPairSorting::lowerPair<ValueIndexPair>);
208 } else {
209 std::stable_sort(valueToIndex.begin(), valueToIndex.end(), ValueIndexPairSorting::higherPair<ValueIndexPair>);
210 }
211
212 // starting from the best candidate add all particles to output list that are not already in it
213 for (const auto& candidate : valueToIndex) {
214 const Particle* part = m_particles[candidate.second];
215
216 std::vector<int> idSeq;
218 bool uniqueSeq = isUnique(idSeq);
219
220 if (uniqueSeq) {
221 m_particleList->addParticle(part);
222 m_particlesInTheList.push_back(idSeq);
223 }
224 }
225
227 m_particleList->setEditable(false);
228
229}
230
231void ParticleListManipulatorModule::fillUniqueIdentifier(const Particle* p, std::vector<int>& idSequence, bool ignoreMotherFlavor)
232{
233 if (ignoreMotherFlavor or abs(p->getPDGCode()) == Const::neutron.getPDGCode()) idSequence.push_back(abs(p->getPDGCode()));
234 else idSequence.push_back(p->getPDGCode());
235
236 if (p->getNDaughters() == 0) {
237 idSequence.push_back(p->getMdstSource());
238 } else {
239 idSequence.push_back(p->getNDaughters());
240 auto daughters = p->getDaughters();
241 // sorting the daughters by their pdgCode to identify decay chains only differing by the order of their daughters
242 sort(daughters.begin(), daughters.end(), [](const auto a, const auto b) {
243 return a->getPDGCode() > b->getPDGCode();
244 });
245 // this is not FSP (go one level down)
246 for (const auto& daughter : daughters)
247 fillUniqueIdentifier(daughter, idSequence, false);
248 }
249}
250
251bool ParticleListManipulatorModule::isUnique(const std::vector<int>& idSeqOUT)
252{
253 for (const auto& idSeqIN : m_particlesInTheList) {
254 bool sameSeq = (idSeqIN == idSeqOUT);
255 if (sameSeq)
256 return false;
257 }
258
259 return true;
260}
The ParticleType class for identifying different particle types.
Definition Const.h:408
static const ParticleType neutron
neutron particle
Definition Const.h:675
static const ParticleSet finalStateParticlesSet
set of final set particles that can be created by the ParticleLoader
Definition Const.h:657
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.
int getPDGCode() const
Return PDG code.
std::string getLabel() const
The label of this particle, "default" returned, when no label set.
static std::unique_ptr< GeneralCut > compile(const std::string &cut)
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:76
int getArrayIndex() const
Returns this object's array index (in StoreArray), or -1 if not found.
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.
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
std::string antiParticleListName(const std::string &listName)
Returns name of anti-particle-list corresponding to listName.
Abstract base class for different kinds of events.
STL namespace.