Belle II Software development
BremsFinderModule.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/BremsCorrection/BremsFinderModule.h>
11
12// framework aux
13#include <framework/gearbox/Const.h>
14#include <framework/logging/Logger.h>
15#include <framework/datastore/RelationArray.h>
16#include <framework/datastore/RelationVector.h>
17
18// dataobjects
19#include <mdst/dataobjects/Track.h>
20#include <mdst/dataobjects/ECLCluster.h>
21
22// utilities
23#include <analysis/DecayDescriptor/ParticleListName.h>
24#include <analysis/DecayDescriptor/DecayDescriptor.h>
25
26// variables
27#include <analysis/variables/ECLVariables.h>
28
29#include <algorithm>
30#include <TMatrixFSym.h>
31
32using namespace std;
33using namespace Belle2;
34
35//-----------------------------------------------------------------
36// Register module
37//-----------------------------------------------------------------
38
39REG_MODULE(BremsFinder);
40
41//-----------------------------------------------------------------
42// Implementation
43//-----------------------------------------------------------------
44
46 Module(), m_pdgCode(0)
47{
48 // set module description (e.g. insert text)
49 setDescription(R"DOC(
50This module copies each particle in the ``inputList`` to the ``outputList`` and uses
51the results of the **eclTrackBremFinder** module to look for possible bremsstrahlung photons; if these
52photons exist, it adds their four momentum to the particle in the ``outputList``.
53It also adds the original particle and these photons as daughters of the new, corrected particle.
54Track and PID information of the original particle are copied onto the new one to facilitate their access
55in the analysis scripts.
56
57The **eclTrackBremFinder** module uses the lepton track PXD and SVD hits and extrapolates them to the ECL;
58then looks for ECL clusters with energies between 0.02 and 1 times the track energy and without associated
59tracks, and checks if the normalized distance between each of these clusters
60and the extrapolated hit is smaller than 0.05. If it is, a *Bremsstrahlung* weighted relation
61between said cluster and the track is established. The weight is determined as
62
63.. math::
64
65 \text{max}\left(\frac{\left|\phi_{\text{cluster}}-\phi_{\text{hit}}\right|}{\Delta\phi_{\text{cluster}}+\Delta\phi_{\text{hit}}}, \, \frac{\left|\theta_{\text{cluster}}-\theta_{\text{hit}}\right|}{\Delta\theta_{\text{cluster}}+\Delta\theta_{\text{hit}}}\right)
66
67where :math:`\phi_i` and :math:`\theta_i` are the azimuthal and polar angles of the ECL cluster and the
68extrapolated hit, and :math:`\Delta x` represents the uncertainty of the value :math:`x`. The details of the
69calculation of these quantities are `here`_. By default, only relations with a weight smaller than 3.0 are stored.
70The user can further reduce the maximally allowed value of this weight to remove unwanted photons from the
71bremsstrahlung correction.
72
73This module looks for photons in the ``gammaList`` whose clusters have a *Bremsstrahlung* relation with the track
74of one of the particles in the ``inputList``, and adds their 4-momentum to the particle's one. It also stores the value
75of each relation weight as ``extraInfo`` of the corrected particle, under the name ``"bremsWeightWithPhotonN"``, where
76N is the index of the photon as daughter of the corrected particle; thus ``"bremsWeightWithPhoton0"`` gives the weight
77of the Bremsstrahlung relation between the new, corrected particle, and the first photon daughter.
78
79Warning:
80 Even in the event of no bremsstrahlung photons found, a new particle is still created, and the original one is still
81 added as its daughter.
82
83Warning:
84 Studies have shown that the requirements that the energy of the photon must be between 0.2 and 1 times the track energy and
85 that only track-photon relations with a weight below three are considered, are too tight. Until these are relaxed and a new
86 processing is done (MC15 and proc 13) it might be better to use the alternative `BelleBremRecovery` module.
87
88See also:
89 `eclTrackBremFinder module`_
90
91.. _eclTrackBremFinder module: https://gitlab.desy.de/belle2/software/basf2/-/tree/main/ecl/modules/eclTrackBremFinder
92.. _here: https://gitlab.desy.de/belle2/software/basf2/-/tree/main/ecl/modules/eclTrackBremFinder/src/BremFindingMatchCompute.cc
93)DOC");
95
96 // Add parameters
97 addParam("outputList", m_outputListName, "The output particle list name.");
98 addParam("inputList", m_inputListName,
99 R"DOC(The initial particle list name containing the particles to correct. *It should already exist* and *the particles must have an associated track.*)DOC");
100 addParam("gammaList", m_gammaListName,
101 R"DOC(The photon list containing the preselected bremsstrahlung candidates. *It should already exist* and *the particles in the list must be photons*)DOC");
102 addParam("maximumAcceptance", m_maximumAcceptance,
103 "The maximum value of the relation weight between a bremsstrahlung cluster and a particle track",
105 addParam("multiplePhotons", m_addMultiplePhotons, "If true, use all possible photons to correct the particle's 4-momentum",
107 addParam("usePhotonOnlyOnce", m_usePhotonOnlyOnce,
108 R"DOC(If true, each brems candidate is used to correct maximum 1 particle (the one with the lowest relation weight among all in the ``inputList``).)DOC",
110 addParam("writeOut", m_writeOut,
111 R"DOC(If true, the output ``ParticleList`` will be saved by `RootOutput`. If false, it will be ignored when writing the file.)DOC",
112 m_writeOut);
113}
114
116{
117 //Get input lepton particle list
118 m_inputList.isRequired(m_inputListName);
119
120 DecayDescriptor decDes;
121 decDes.init(m_inputListName);
122
123 m_pdgCode = decDes.getMother()->getPDGCode();
124 //Check for the particles in the lepton list to have a track associated
126 B2ERROR("[BremsFinderModule] Invalid particle list. the particles in " << m_inputListName << " should have an associated track.");
127
128 //Get input photon particle list
129 m_gammaList.isRequired(m_gammaListName);
130
131 decDes.init(m_gammaListName);
132 int temp_pdg = decDes.getMother()->getPDGCode();
133
134 //Check that this is a gamma list
135 if (temp_pdg != Const::photon.getPDGCode())
136 B2ERROR("[BremsFinderModule] Invalid particle list. the particles in " << m_gammaListName << " should be photons!");
137
138 decDes.init(m_outputListName);
139 temp_pdg = decDes.getMother()->getPDGCode();
140 // check the validity of output ParticleList name
142 B2ERROR("[BremsFinderModule] Input and output particle list names are the same: " << m_inputListName);
143 else if (temp_pdg != m_pdgCode) {
144 B2ERROR("[BremsFinderModule] The input and output particle list correspond to different particles: " << m_inputListName << " --> "
146 }
147
148 // output particle
150
151 // make output lists
153 m_outputList.registerInDataStore(m_outputListName, flags);
154 m_outputAntiList.registerInDataStore(m_outputAntiListName, flags);
155
157}
158
160{
161 RelationArray particlesToMCParticles(m_particles, m_mcParticles);
162
163 // new output particle list
164 m_outputList.create();
166
167 m_outputAntiList.create();
169 m_outputAntiList->bindAntiParticleList(*(m_outputList));
170
171 // Number of photons (calculate it here only once)
172 const unsigned int nGamma = m_gammaList->getListSize();
173
174 // Number of leptons (calculate it here only once)
175 const unsigned int nLep = m_inputList->getListSize();
176
177 const std::string relationName = "Bremsstrahlung";
178
179 //In the case of only one track per photon
181 for (unsigned n = 0; n < nGamma; n++) {
182 Particle* gamma = m_gammaList->getParticle(n);
183 //Skip this if it the best match has already been assigned (pathological case: happens only if you use the same gamma list
184 //to correct more than once. Performance studies, in which the same list is used with different options, are an example
185 if (gamma->hasExtraInfo("bestMatchIndex")) continue;
186
187 auto cluster = gamma->getECLCluster();
188 //Get the tracks related to each photon...
189 RelationVector<Track> relatedTracks = cluster->getRelationsTo<Track>("", relationName);
190 double bestWeight = m_maximumAcceptance;
191 unsigned bestMatchIndex = 0;
192 unsigned trkIndex = 0;
193 //Loop over the related tracks...
194 for (auto trk = relatedTracks.begin(); trk != relatedTracks.end(); trk++, trkIndex++) {
195 //... and over the input particles' tracks...
196 for (unsigned i = 0; i < nLep; i++) {
197 const Particle* lepton = m_inputList->getParticle(i);
198 auto leptonTrack = lepton->getTrack();
199 //... check that the particle track corresponds to the related track....
200 if (leptonTrack->getArrayIndex() == trk->getArrayIndex()) {
201 double weight = relatedTracks.weight(trkIndex);
202 if (weight < bestWeight) {
203 bestWeight = weight;
204 //... and only select the best match among the tracks in the input list
205 bestMatchIndex = trk->getArrayIndex();
206 }
207 break; //If the particle corresponding to the related track is found, break the loop over the particles and go for the next related track
208 }
209 }
210 }
211 //... finally, add the best match index as an extra info for the photon
212 gamma->addExtraInfo("bestMatchIndex", bestMatchIndex);
213 }
214 }
215
216 // loop over charged particles, correct them and add them to the output list
217
218 for (unsigned i = 0; i < nLep; i++) {
219 const Particle* lepton = m_inputList->getParticle(i);
220
221 //Get the track of this lepton...
222 auto track = lepton->getTrack();
223
224 //... and get the bremsstrahlung clusters related to this track
225 RelationVector<ECLCluster> bremClusters = track->getRelationsFrom<ECLCluster>("", relationName);
226
227 std::vector<std::pair <double, Particle*> > selectedGammas;
228
229 unsigned j = 0;
230 for (auto bremCluster = bremClusters.begin(); bremCluster != bremClusters.end(); bremCluster++, j++) {
231 double weight = bremClusters.weight(j);
232
233 if (weight > m_maximumAcceptance) continue;
234
235 for (unsigned k = 0; k < nGamma; k++) {
236
237 Particle* gamma = m_gammaList->getParticle(k);
238 auto cluster = gamma->getECLCluster();
239
240 if (bremCluster->getUniqueClusterId() == cluster->getUniqueClusterId()) {
241 if (m_usePhotonOnlyOnce) { //If only one track per photon should be used...
242 if (track->getArrayIndex() == static_cast<int>
243 (gamma->getExtraInfo("bestMatchIndex"))) //... check if this track is the best match ...
244 selectedGammas.push_back(std::make_pair(weight, gamma)); //... and if it is, add it to the selected gammas
245 } else {
246 selectedGammas.push_back(std::make_pair(weight, gamma));
247 }
248 }
249
250 } // Closes for loop on gammas
251
252 } // Closes for loop on brem clusters
253
254 //The 4-momentum of the new lepton in the output particle list
255 ROOT::Math::PxPyPzEVector new4Vec = lepton->get4Vector();
256
257 //Sort weight-particle pairs by weight. Smaller weights go first
258 std::sort(selectedGammas.begin(), selectedGammas.end());
259
260 //Add to this 4-momentum those of the selected photon(s)
261 for (auto const& bremsPair : selectedGammas) {
262 Particle* g = bremsPair.second;
263 new4Vec += g->get4Vector();
264 if (! m_addMultiplePhotons) break; //stop after adding the first photon
265 }
266
267 //Create the new particle with the 4-momentum calculated before
268 Particle correctedLepton(new4Vec, lepton->getPDGCode(), Particle::EFlavorType::c_Flavored, Particle::c_Track,
269 track->getArrayIndex());
270
271 //And add the original lepton as its daughter
272 correctedLepton.appendDaughter(lepton, false);
273
274 const TMatrixFSym& lepErrorMatrix = lepton->getMomentumVertexErrorMatrix();
275 TMatrixFSym corLepMatrix(lepErrorMatrix);
276
277 double bremsGammaEnergySum = 0.0;
278 //Now, if there are any, add the brems photons as daughters as well. As before, we distinguish between the multiple and only one brems photon cases
279 int photonIndex = 0;
280 for (auto const& bremsPair : selectedGammas) {
281 //Add the weights as extra info of the mother
282 Particle* bremsGamma = bremsPair.second;
283 std::string extraInfoName = "bremsWeightWithPhoton" + std::to_string(photonIndex);
284 correctedLepton.addExtraInfo(extraInfoName, bremsPair.first);
285 photonIndex++;
286 bremsGammaEnergySum += Variable::eclClusterE(bremsGamma);
287
288 const TMatrixFSym& gammaErrorMatrix = bremsGamma->getMomentumVertexErrorMatrix();
289 for (int irow = 0; irow <= 3; irow++) {
290 for (int icol = irow; icol <= 3; icol++) corLepMatrix(irow, icol) += gammaErrorMatrix(irow, icol);
291 }
292 correctedLepton.appendDaughter(bremsGamma, false);
293 B2DEBUG(10, "[BremsFinderModule] Found a bremsstrahlung gamma and added its 4-vector to the charged particle");
294 if (! m_addMultiplePhotons) break; //stop after adding the first photon
295 }
296
297 correctedLepton.setMomentumVertexErrorMatrix(corLepMatrix);
298
299 // add the info from original lepton to the new lepton
300 correctedLepton.setVertex(lepton->getVertex());
301 correctedLepton.setPValue(lepton->getPValue());
302 correctedLepton.addExtraInfo("bremsCorrected", float(selectedGammas.size() > 0));
303 correctedLepton.addExtraInfo("bremsCorrectedPhotonEnergy", bremsGammaEnergySum);
304
305 // add the mc relation
306 Particle* newLepton = m_particles.appendNew(correctedLepton);
307 const MCParticle* mcLepton = lepton->getRelated<MCParticle>();
308 const PIDLikelihood* pid = lepton->getPIDLikelihood();
309
310 if (pid) newLepton->addRelationTo(pid);
311
312 if (mcLepton != nullptr) newLepton->addRelationTo(mcLepton);
313
314 m_outputList->addParticle(newLepton);
315
316 } //Closes for loop on leptons
317
318} //Close event()
virtual void initialize() override
Use this to initialize resources or memory your module needs.
double m_maximumAcceptance
photons whose clusters have relation weights higher than this will not be used for bremsstrahlung cor...
std::string m_gammaListName
input gamma list name
virtual void event() override
Called once for each event.
bool m_addMultiplePhotons
In case there is more than one brems photon, use only the best one (based on the weight of the relati...
StoreObjPtr< ParticleList > m_outputAntiList
StoreObjptr for output antiparticlelist.
StoreArray< Particle > m_particles
StoreArray of Particle objects.
StoreObjPtr< ParticleList > m_outputList
StoreObjptr for output particlelist.
StoreArray< PIDLikelihood > m_pidlikelihoods
StoreArray of PIDLikelihood objects.
StoreObjPtr< ParticleList > m_inputList
StoreObjptr for input charged particle list.
StoreObjPtr< ParticleList > m_gammaList
StoreObjptr for gamma list.
bool m_writeOut
Write the output particle list in the final file?
StoreArray< MCParticle > m_mcParticles
StoreArray of MCParticle objects.
bool m_usePhotonOnlyOnce
Each brems photon can be used to correct only one particle (the one with the smallest relation weight...
int m_pdgCode
PDG code of the particle to be corrected.
std::string m_outputAntiListName
output anti-particle list name
std::string m_inputListName
input particle list name
BremsFinderModule()
Constructor, for setting module description and parameters.
std::string m_outputListName
output particle list name
static const ParticleSet chargedStableSet
set of charged stable particles
Definition: Const.h:618
static const ParticleType invalidParticle
Invalid particle, used internally.
Definition: Const.h:681
static const ParticleType photon
photon particle
Definition: Const.h:673
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
int getPDGCode() const
Return PDG code.
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.
ECL cluster data.
Definition: ECLCluster.h:27
A Class to store the Monte Carlo particle information.
Definition: MCParticle.h:32
Base class for Modules.
Definition: Module.h:72
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 collect log likelihoods from TOP, ARICH, dEdx, ECL and KLM aimed for output to mdst includes...
Definition: PIDLikelihood.h:29
Class to store reconstructed particles.
Definition: Particle.h:76
const Track * getTrack() const
Returns the pointer to the Track object that was used to create this Particle (ParticleType == c_Trac...
Definition: Particle.cc:916
void appendDaughter(const Particle *daughter, const bool updateType=true, const int daughterProperty=c_Ordinary)
Appends index of daughter to daughters index array.
Definition: Particle.cc:707
const ECLCluster * getECLCluster() const
Returns the pointer to the ECLCluster object that was used to create this Particle (if ParticleType =...
Definition: Particle.cc:976
void setVertex(const ROOT::Math::XYZVector &vertex)
Sets position (decay vertex)
Definition: Particle.h:306
double getPValue() const
Returns chi^2 probability of fit if done or -1.
Definition: Particle.h:687
ROOT::Math::XYZVector getVertex() const
Returns vertex position (POCA for charged, IP for neutral FS particles)
Definition: Particle.h:651
bool hasExtraInfo(const std::string &name) const
Return whether the extra info with the given name is set.
Definition: Particle.cc:1351
const PIDLikelihood * getPIDLikelihood() const
Returns the pointer to the PIDLikelihood object that is related to the Track, which was used to creat...
Definition: Particle.cc:947
int getPDGCode(void) const
Returns PDG code.
Definition: Particle.h:465
ROOT::Math::PxPyPzEVector get4Vector() const
Returns Lorentz vector.
Definition: Particle.h:567
void addExtraInfo(const std::string &name, double value)
Sets the user-defined data of given name to the given value.
Definition: Particle.cc:1421
void setMomentumVertexErrorMatrix(const TMatrixFSym &errMatrix)
Sets 7x7 error matrix.
Definition: Particle.cc:424
void setPValue(double pValue)
Sets chi^2 probability of fit.
Definition: Particle.h:377
@ c_Flavored
Is either particle or antiparticle.
Definition: Particle.h:98
TMatrixFSym getMomentumVertexErrorMatrix() const
Returns 7x7 error matrix.
Definition: Particle.cc:451
double getExtraInfo(const std::string &name) const
Return given value if set.
Definition: Particle.cc:1374
Low-level class to create/modify relations between StoreArrays.
Definition: RelationArray.h:62
Class for type safe access to objects that are referred to in relations.
iterator end()
Return iterator to last entry +1.
iterator begin()
Return iterator to first entry.
float weight(int index) const
Get weight with index.
void addRelationTo(const RelationsInterface< BASE > *object, float weight=1.0, const std::string &namedRelation="") const
Add a relation from this object to another object (with caching).
T * getRelated(const std::string &name="", const std::string &namedRelation="") const
Get the object to or from which this object has a relation.
T * appendNew()
Construct a new T object at the end of the array.
Definition: StoreArray.h:246
bool registerRelationTo(const StoreArray< TO > &toArray, DataStore::EDurability durability=DataStore::c_Event, DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut, const std::string &namedRelation="") const
Register a relation to the given StoreArray.
Definition: StoreArray.h:140
Class that bundles various TrackFitResults.
Definition: Track.h: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: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.