Belle II Software light-2607-kasei
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
83Note:
84 The requirements applied by the **eclTrackBremFinder** module used to be too tight, so that for MC15 and proc13 and
85 earlier the alternative `BelleBremRecovery` module was recommended. They were relaxed for MC16 and proc16, and
86 since release-08 this module is the recommended one, see `modularAnalysis.correctBrems`. The current
87 recommendation on the photon selection and on the module parameters is provided by the
88 :ref:`b2help-recommendation` tool.
89
90See also:
91 `eclTrackBremFinder module`_
92
93.. _eclTrackBremFinder module: https://gitlab.desy.de/belle2/software/basf2/-/tree/main/ecl/modules/eclTrackBremFinder
94.. _here: https://gitlab.desy.de/belle2/software/basf2/-/tree/main/ecl/modules/eclTrackBremFinder/src/BremFindingMatchCompute.cc
95)DOC");
97
98 // Add parameters
99 addParam("outputList", m_outputListName, "The output particle list name.");
100 addParam("inputList", m_inputListName,
101 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");
102 addParam("gammaList", m_gammaListName,
103 R"DOC(The photon list containing the preselected bremsstrahlung candidates. *It should already exist* and *the particles in the list must be photons*)DOC");
104 addParam("maximumAcceptance", m_maximumAcceptance,
105 "The maximum value of the relation weight between a bremsstrahlung cluster and a particle track",
107 addParam("multiplePhotons", m_addMultiplePhotons, "If true, use all possible photons to correct the particle's 4-momentum",
109 addParam("usePhotonOnlyOnce", m_usePhotonOnlyOnce,
110 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",
112 addParam("writeOut", m_writeOut,
113 R"DOC(If true, the output ``ParticleList`` will be saved by `RootOutput`. If false, it will be ignored when writing the file.)DOC",
114 m_writeOut);
115}
116
118{
119 //Get input lepton particle list
120 m_inputList.isRequired(m_inputListName);
121
122 DecayDescriptor decDes;
123 decDes.init(m_inputListName);
124
125 m_pdgCode = decDes.getMother()->getPDGCode();
126 //Check for the particles in the lepton list to have a track associated
128 B2ERROR("[BremsFinderModule] Invalid particle list. the particles in " << m_inputListName << " should have an associated track.");
129
130 //Get input photon particle list
131 m_gammaList.isRequired(m_gammaListName);
132
133 decDes.init(m_gammaListName);
134 int temp_pdg = decDes.getMother()->getPDGCode();
135
136 //Check that this is a gamma list
137 if (temp_pdg != Const::photon.getPDGCode())
138 B2ERROR("[BremsFinderModule] Invalid particle list. the particles in " << m_gammaListName << " should be photons!");
139
140 decDes.init(m_outputListName);
141 temp_pdg = decDes.getMother()->getPDGCode();
142 // check the validity of output ParticleList name
144 B2ERROR("[BremsFinderModule] Input and output particle list names are the same: " << m_inputListName);
145 else if (temp_pdg != m_pdgCode) {
146 B2ERROR("[BremsFinderModule] The input and output particle list correspond to different particles: " << m_inputListName << " --> "
148 }
149
150 // output particle
152
153 // make output lists
155 m_outputList.registerInDataStore(m_outputListName, flags);
156 m_outputAntiList.registerInDataStore(m_outputAntiListName, flags);
157
158 m_particles.registerRelationTo(m_pidlikelihoods);
159}
160
162{
163 RelationArray particlesToMCParticles(m_particles, m_mcParticles);
164
165 // new output particle list
166 m_outputList.create();
168
169 m_outputAntiList.create();
171 m_outputAntiList->bindAntiParticleList(*(m_outputList));
172
173 // Number of photons (calculate it here only once)
174 const unsigned int nGamma = m_gammaList->getListSize();
175
176 // Number of leptons (calculate it here only once)
177 const unsigned int nLep = m_inputList->getListSize();
178
179 const std::string relationName = "Bremsstrahlung";
180
181 //In the case of only one track per photon
183 for (unsigned n = 0; n < nGamma; n++) {
184 Particle* gamma = m_gammaList->getParticle(n);
185 //Skip this if it the best match has already been assigned (pathological case: happens only if you use the same gamma list
186 //to correct more than once. Performance studies, in which the same list is used with different options, are an example
187 if (gamma->hasExtraInfo("bestMatchIndex")) continue;
188
189 auto cluster = gamma->getECLCluster();
190 //Get the tracks related to each photon...
191 RelationVector<Track> relatedTracks = cluster->getRelationsTo<Track>("", relationName);
192 double bestWeight = m_maximumAcceptance;
193 unsigned bestMatchIndex = 0;
194 unsigned trkIndex = 0;
195 //Loop over the related tracks...
196 for (auto trk = relatedTracks.begin(); trk != relatedTracks.end(); trk++, trkIndex++) {
197 //... and over the input particles' tracks...
198 for (unsigned i = 0; i < nLep; i++) {
199 const Particle* lepton = m_inputList->getParticle(i);
200 auto leptonTrack = lepton->getTrack();
201 //... check that the particle track corresponds to the related track....
202 if (leptonTrack->getArrayIndex() == trk->getArrayIndex()) {
203 double weight = relatedTracks.weight(trkIndex);
204 if (weight < bestWeight) {
205 bestWeight = weight;
206 //... and only select the best match among the tracks in the input list
207 bestMatchIndex = trk->getArrayIndex();
208 }
209 break; //If the particle corresponding to the related track is found, break the loop over the particles and go for the next related track
210 }
211 }
212 }
213 //... finally, add the best match index as an extra info for the photon
214 gamma->addExtraInfo("bestMatchIndex", bestMatchIndex);
215 }
216 }
217
218 // loop over charged particles, correct them and add them to the output list
219
220 for (unsigned i = 0; i < nLep; i++) {
221 const Particle* lepton = m_inputList->getParticle(i);
222
223 //Get the track of this lepton...
224 auto track = lepton->getTrack();
225
226 //... and get the bremsstrahlung clusters related to this track
227 RelationVector<ECLCluster> bremClusters = track->getRelationsFrom<ECLCluster>("", relationName);
228
229 std::vector<std::pair <double, Particle*> > selectedGammas;
230
231 unsigned j = 0;
232 for (auto bremCluster = bremClusters.begin(); bremCluster != bremClusters.end(); bremCluster++, j++) {
233 double weight = bremClusters.weight(j);
234
235 if (weight > m_maximumAcceptance) continue;
236
237 for (unsigned k = 0; k < nGamma; k++) {
238
239 Particle* gamma = m_gammaList->getParticle(k);
240 auto cluster = gamma->getECLCluster();
241
242 if (bremCluster->getUniqueClusterId() == cluster->getUniqueClusterId()) {
243 if (m_usePhotonOnlyOnce) { //If only one track per photon should be used...
244 if (track->getArrayIndex() == static_cast<int>
245 (gamma->getExtraInfo("bestMatchIndex"))) //... check if this track is the best match ...
246 selectedGammas.push_back(std::make_pair(weight, gamma)); //... and if it is, add it to the selected gammas
247 } else {
248 selectedGammas.push_back(std::make_pair(weight, gamma));
249 }
250 }
251
252 } // Closes for loop on gammas
253
254 } // Closes for loop on brem clusters
255
256 //The 4-momentum of the new lepton in the output particle list
257 ROOT::Math::PxPyPzEVector new4Vec = lepton->get4Vector();
258
259 //Sort weight-particle pairs by weight. Smaller weights go first
260 std::sort(selectedGammas.begin(), selectedGammas.end());
261
262 //Add to this 4-momentum those of the selected photon(s)
263 for (auto const& bremsPair : selectedGammas) {
264 Particle* g = bremsPair.second;
265 new4Vec += g->get4Vector();
266 if (! m_addMultiplePhotons) break; //stop after adding the first photon
267 }
268
269 //Create the new particle with the 4-momentum calculated before
270 Particle correctedLepton(new4Vec, lepton->getPDGCode(), Particle::EFlavorType::c_Flavored, Particle::c_Track,
271 track->getArrayIndex());
272
273 //And add the original lepton as its daughter
274 correctedLepton.appendDaughter(lepton, false);
275
276 const TMatrixFSym& lepErrorMatrix = lepton->getMomentumVertexErrorMatrix();
277 TMatrixFSym corLepMatrix(lepErrorMatrix);
278
279 double bremsGammaEnergySum = 0.0;
280 //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
281 int photonIndex = 0;
282 for (auto const& bremsPair : selectedGammas) {
283 //Add the weights as extra info of the mother
284 Particle* bremsGamma = bremsPair.second;
285 std::string extraInfoName = "bremsWeightWithPhoton" + std::to_string(photonIndex);
286 correctedLepton.addExtraInfo(extraInfoName, bremsPair.first);
287 photonIndex++;
288 bremsGammaEnergySum += Variable::eclClusterE(bremsGamma);
289
290 const TMatrixFSym& gammaErrorMatrix = bremsGamma->getMomentumVertexErrorMatrix();
291 for (int irow = 0; irow <= 3; irow++) {
292 for (int icol = irow; icol <= 3; icol++) corLepMatrix(irow, icol) += gammaErrorMatrix(irow, icol);
293 }
294 correctedLepton.appendDaughter(bremsGamma, false);
295 B2DEBUG(10, "[BremsFinderModule] Found a bremsstrahlung gamma and added its 4-vector to the charged particle");
296 if (! m_addMultiplePhotons) break; //stop after adding the first photon
297 }
298
299 correctedLepton.setMomentumVertexErrorMatrix(corLepMatrix);
300
301 // add the info from original lepton to the new lepton
302 correctedLepton.setVertex(lepton->getVertex());
303 correctedLepton.setPValue(lepton->getPValue());
304 correctedLepton.addExtraInfo("bremsCorrected", float(selectedGammas.size() > 0));
305 correctedLepton.addExtraInfo("bremsCorrectedPhotonEnergy", bremsGammaEnergySum);
306
307 // add the mc relation
308 Particle* newLepton = m_particles.appendNew(correctedLepton);
309 const MCParticle* mcLepton = lepton->getRelated<MCParticle>();
310 const PIDLikelihood* pid = lepton->getPIDLikelihood();
311
312 if (pid) newLepton->addRelationTo(pid);
313
314 if (mcLepton != nullptr) newLepton->addRelationTo(mcLepton);
315
316 m_outputList->addParticle(newLepton);
317
318 } //Closes for loop on leptons
319
320} //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:619
static const ParticleType invalidParticle
Invalid particle, used internally.
Definition Const.h:682
static const ParticleType photon
photon particle
Definition Const.h:674
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
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
Module()
Constructor.
Definition Module.cc:30
@ 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...
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.
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.
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.