Belle II Software  release-06-00-14
ECLTrackBremFinderModule.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 //This module
10 #include <ecl/modules/eclTrackBremFinder/ECLTrackBremFinderModule.h>
11 
12 //Framework
13 #include <framework/dataobjects/EventMetaData.h>
14 #include <framework/logging/Logger.h>
15 #include <framework/gearbox/Const.h>
16 #include <framework/datastore/StoreArray.h>
17 
18 //MDST
19 #include <mdst/dataobjects/ECLCluster.h>
20 #include <mdst/dataobjects/Track.h>
21 #include <mdst/dataobjects/PIDLikelihood.h>
22 #include <mdst/dataobjects/TrackFitResult.h>
23 
24 //Tracking
25 #include <tracking/dataobjects/RecoTrack.h>
26 #include <tracking/dataobjects/BremHit.h>
27 
28 //ECL
29 #include <ecl/modules/eclTrackBremFinder/BestMatchContainer.h>
30 #include <ecl/modules/eclTrackBremFinder/BremFindingMatchCompute.h>
31 
32 
33 using namespace Belle2;
34 
35 REG_MODULE(ECLTrackBremFinder)
36 
38  Module()
39 {
40  setDescription("Use Track direction to pick up possible ECL Brem Cluster");
41  setPropertyFlags(c_ParallelProcessingCertified);
42 
43  addParam("eclClustersStoreArrayName", m_param_eclClustersStoreArrayName, "StoreArray name of the ECLClusters for brem matching",
44  m_param_eclClustersStoreArrayName);
45 
46  addParam("tracksStoreArrayName", m_param_tracksStoreArrayName, "StoreArray name of the Tracks for brem matching",
47  m_param_tracksStoreArrayName);
48 
49  addParam("recoTracksStoreArrayName", m_param_recoTracksStoreArrayName, "StoreArray name of the reco tracks used for brem search",
50  m_param_recoTracksStoreArrayName);
51 
52  addParam("clusterAcceptanceFactor", m_clusterAcceptanceFactor,
53  "Factor which is multiplied onto the cluster position error to check for matches",
54  m_clusterAcceptanceFactor);
55 
56  addParam("virtualHitRadii", m_virtualHitRadii, "Radii where virtual hits for the extrapolation will be generated",
57  m_virtualHitRadii);
58 
59  addParam("relativeClusterEnergy", m_relativeClusterEnergy, "Fraction of the tracks energy the ECL cluster has "
60  "to possess to be considered for bremsstrahlung finding",
61  m_relativeClusterEnergy);
62 
63  addParam("requestedNumberOfCDCHits", m_requestedNumberOfCDCHits, "Minimal/Maximal number of CDC hits, the track has to possess "
64  "to be considered for bremsstrahlung finding",
65  m_requestedNumberOfCDCHits);
66 
67  addParam("electronProbabilityCut", m_electronProbabilityCut, "Cut on the electron probability (from pid) of track",
68  m_electronProbabilityCut);
69 
70  addParam("clusterDistanceCut", m_clusterDistanceCut,
71  "Cut on the distance between the cluster position angle and the extrapolation angle",
72  m_clusterDistanceCut);
73 }
74 
76 {
78  m_eclClusters.registerRelationTo(m_eclClusters);
79 
81 
82  const std::string relationName = "Bremsstrahlung";
83  m_eclClusters.registerRelationTo(m_tracks, DataStore::c_Event, DataStore::c_WriteOut, relationName);
84 
85  m_recoTracks.isRequired();
86 
87  m_bremHits.registerInDataStore();
88  m_bremHits.registerRelationTo(m_eclClusters);
89  m_bremHits.registerRelationTo(m_recoTracks);
90 }
91 
93 {
94 
95 
96  // either use the Clusters matched to tracks (non-neutral) or use the smarter decision
97  // done by the neutral / non-neutral classification code
98  // todo: there needs to be a global (all tracks vs. all clusters) conflict resolution,
99  // sort tracks by Pt, as high energy tracks are more likely to radiate bremsstrahlung photons
100  // with sufficient energy to be detected and reconstructed
101  for (auto& track : m_tracks) {
102 
103  // since the module runs after the reconstruction the pid likelihood can be checked to sort out tracks,
104  // which are not expected to be from electrons
105  const PIDLikelihood* pid = track.getRelated<PIDLikelihood>();
106  if (pid) {
108  Const::ChargedStable mostLikelyPDG = Const::electron;
109  double highestProb = 0;
110  for (Const::ChargedStable pdg : possiblePDGs) {
111  double probability = pid->getProbability(pdg);
112  if (probability > highestProb) {
113  highestProb = probability;
114  mostLikelyPDG = pdg;
115  }
116  }
117  if (mostLikelyPDG != Const::electron || highestProb <= m_electronProbabilityCut) {
118  B2DEBUG(20, "Track is expected not to be from electron");
119  continue;
120  }
121  }
122 
123  const TrackFitResult* trackFitResult = track.getTrackFitResult(Const::ChargedStable(211));
124  double trackMomentum;
125  if (trackFitResult) {
126  trackMomentum = trackFitResult->getMomentum().Mag();
127  // if the momentum of the track is higher than 5 GeV, do not use this track
128  if (trackMomentum > 5.0) {
129  B2DEBUG(20, "Track momentum higher than 5GeV! Track is not used for bremsstrahlung finding");
130  continue;
131  }
132  } else {
133  continue;
134  }
135 
136 
137  B2DEBUG(20, "Checking track for related ECLCluster");
138 
139  // searching for an assigned primary cluster
140  ECLCluster* primaryClusterOfTrack = nullptr;
141  auto relatedClustersToTrack =
142  track.getRelationsWith<ECLCluster>
143  (m_param_eclClustersStoreArrayName); //check the cluster hypothesis ID here (take c_nPhotons hypothesis)!!
144  for (auto& relatedCluster : relatedClustersToTrack) {
145  if (relatedCluster.hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons)) {
146  primaryClusterOfTrack = &relatedCluster;
147  }
148  }
149 
150  // get the RecoTrack to have easy access to individual hits and
151  // their fit state
152  auto recoTrack = track.getRelatedTo<RecoTrack>(m_param_recoTracksStoreArrayName);
153 
154  if (!recoTrack) {
155  // no reco track
156  B2DEBUG(20, "No RecoTrack for this Track");
157  continue;
158  }
159 
160  // check if the RecoTrack has the requested number of CDC hits
161  if (recoTrack->getNumberOfCDCHits() < std::get<0>(m_requestedNumberOfCDCHits) ||
162  recoTrack->getNumberOfCDCHits() > std::get<1>(m_requestedNumberOfCDCHits)) {
163  B2DEBUG(20, "RecoTrack has not requested number of CDC hits");
164  continue;
165  }
166 
167  // set the params for the virtual hits
168  std::vector<std::pair<float, RecoHitInformation*>> extrapolationParams = {};
169  std::vector<genfit::MeasuredStateOnPlane> extrapolatedStates = {};
170  try {
171  for (auto virtualHitRadius : m_virtualHitRadii) {
173  for (auto hit : recoTrack->getRecoHitInformations(true)) {
174  if (hit->useInFit() && recoTrack->hasTrackFitStatus()) {
175  try {
176  auto measState = recoTrack->getMeasuredStateOnPlaneFromRecoHit(hit);
177  float hitRadius = measState.getPos().Perp();
178  float distance = abs(hitRadius - virtualHitRadius);
179  // for higher values the extrapolation will be too bad
180  if (distance < 3) {
181  nearestHitContainer.add(hit, distance);
182  }
183  } catch (NoTrackFitResult&) {
184  B2DEBUG(29, "No track fit result available for this hit! Event: " << m_evtPtr->getEvent());
185  }
186  }
187  if (nearestHitContainer.hasMatch()) {
188  auto nearestHit = nearestHitContainer.getBestMatch();
189  extrapolationParams.push_back({virtualHitRadius, nearestHit});
190  }
191  }
192  }
193 
194  for (auto param : extrapolationParams) {
195  auto fitted_state = recoTrack->getMeasuredStateOnPlaneFromRecoHit(param.second);
196  try {
197  fitted_state.extrapolateToCylinder(param.first);
198  extrapolatedStates.push_back(fitted_state);
199  } catch (genfit::Exception& exception1) {
200  B2DEBUG(20, "Extrapolation failed!");
201  }
202  }
203  } catch (const genfit::Exception& e) {
204  B2WARNING("Exception" << e.what());
205  }
206 
207  // possible improvement: use fast lookup using kd-tree, this is nasty
208  // iterate over full cluster list to find possible compatible clusters
209  for (ECLCluster& cluster : m_eclClusters) {
210  //check if the cluster belongs to a photon or electron
211  if (!cluster.hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons)) {
212  B2DEBUG(20, "Cluster has wrong hypothesis!");
213  continue;
214  }
215 
216  //check if cluster is already related to a track -> if true, can't be bremsstrahlung cluster
217  auto relatedTrack = cluster.getRelatedFrom<Track>();
218  if (relatedTrack) {
219  B2DEBUG(20, "Cluster already related to track, bailing out");
220  continue;
221  }
222 
223  //check if the cluster is already related to a BremHit
224  //procedure: first come, first served
225  auto relatedBremHit = cluster.getRelated<BremHit>();
226  if (relatedBremHit) {
227  B2DEBUG(20, "Cluster already assumed to be bremsstrahlung cluster!");
228  continue;
229  }
230 
231  // check if the cluster energy is higher than the track momentum itself
232  // also check that cluster has more than 2% of the track momentum
233  double relativeEnergy = cluster.getEnergy(ECLCluster::EHypothesisBit::c_nPhotons) / trackMomentum;
234  if (relativeEnergy > 1 || relativeEnergy < m_relativeClusterEnergy) {
235  B2DEBUG(20, "Relative energy of cluster higher than 1 or below threshold!");
236  continue;
237  }
238 
239  typedef std::tuple<ECLCluster*, genfit::MeasuredStateOnPlane, double, double > ClusterMSoPPair;
241 
242  // iterate over all track points and see whether this cluster matches
243  // the track points direction
244  // only VXD hits shall be used
245  for (auto hit : recoTrack->getRecoHitInformations(true)) {
246  if (hit->getTrackingDetector() == RecoHitInformation::c_PXD || hit->getTrackingDetector() == RecoHitInformation::c_SVD) {
247  try {
248  if (!recoTrack->hasTrackFitStatus()) {
249  continue;
250  }
251  auto measState = recoTrack->getMeasuredStateOnPlaneFromRecoHit(hit);
252  auto bremFinder = BremFindingMatchCompute(m_clusterAcceptanceFactor, cluster, measState);
253  if (bremFinder.isMatch()) {
254  ClusterMSoPPair match_pair = std::make_tuple(&cluster, measState, bremFinder.getDistanceHitCluster(),
255  bremFinder.getEffAcceptanceFactor());
256  matchContainer.add(match_pair, bremFinder.getDistanceHitCluster());
257  }
258  } catch (NoTrackFitResult&) {
259  B2DEBUG(29, "No track fit result available for this hit! Event: " << m_evtPtr->getEvent());
260  } catch (genfit::Exception& e) {
261  B2WARNING("Exception" << e.what());
262  }
263  }
264  }
265 
266  // check for matches of the extrapolation of the virtual hits with the cluster position
267  for (auto fitted_state : extrapolatedStates) {
268  auto bremFinder = BremFindingMatchCompute(m_clusterAcceptanceFactor, cluster, fitted_state);
269  if (bremFinder.isMatch()) {
270  ClusterMSoPPair match_pair = std::make_tuple(&cluster, fitted_state, bremFinder.getDistanceHitCluster(),
271  bremFinder.getEffAcceptanceFactor());
272  matchContainer.add(match_pair, bremFinder.getDistanceHitCluster());
273  }
274  }
275 
276 
277  // have we found the best possible track point for this cluster
278  if (matchContainer.hasMatch()) {
279  auto matchClustermSoP = matchContainer.getBestMatch();
280  const auto fitted_state = std::get<1>(matchClustermSoP);
281 
282  const auto fitted_pos = fitted_state.getPos();
283  const auto fitted_mom = fitted_state.getMom();
284  const auto fitted_dir = fitted_state.getDir();
285 
286  const auto hit_theta = fitted_mom.Theta();
287  const auto hit_phi = fitted_mom.Phi();
288 
289  B2DEBUG(20, "Best Cluster" << std::endl
290  << " Cluster Phi=" << std::get<0>(matchClustermSoP)->getPhi() << " Theta=" << std::get<0>(matchClustermSoP)->getTheta()
291  << " TrackHit Phi=" << hit_phi << " Theta=" << hit_theta);
292 
293  // create a BremHit if a match is found
294  // relate this BremHit to the bremsstrahlung cluster and the recoTrack
295  // if the track has a primary cluster, add a relation between bremsstrahlung cluster and primary cluster
296 
297  double effAcceptanceFactor = std::get<3>(matchClustermSoP);
298  ECLCluster* bremCluster = std::get<0>(matchClustermSoP);
299  double clusterDistance = std::get<2>(matchClustermSoP);
300 
301  if (fitted_pos.Perp() <= 16 && clusterDistance <= m_clusterDistanceCut) {
302  m_bremHits.appendNew(recoTrack, bremCluster,
303  fitted_pos, bremCluster->getEnergy(ECLCluster::EHypothesisBit::c_nPhotons),
304  clusterDistance, effAcceptanceFactor);
305 
306  // add a relation between the bremsstrahlung cluster and the track to transfer the information to the analysis
307  // set the acceptance factor as weight
308  bremCluster->addRelationTo(&track, effAcceptanceFactor, "Bremsstrahlung");
309 
310  if (primaryClusterOfTrack) {
311  primaryClusterOfTrack->addRelationTo(bremCluster, effAcceptanceFactor);
312  }
313  }
314  }
315  }
316  }
317 }
Multiple entries can be added, but only the one will be kept, which has the best quality estimator.
TItem const & getBestMatch() const
bool add(TItem item, TEstimator est, EstimatorComparison estComparison=[](TEstimator currentBest, TEstimator newEst) {return newEst< currentBest;})
Add a new item with an estimator value.
Module to compute if an extrapolation to the ECL matches the position of an secondary ECLCLuster to f...
A bremsstrahlung hit that correlates an ECLCluster with a RecoTrack.
Definition: BremHit.h:24
Provides a type-safe way to pass members of the chargedStableSet set.
Definition: Const.h:470
static const ChargedStable muon
muon particle
Definition: Const.h:541
static const ChargedStable pion
charged pion particle
Definition: Const.h:542
static const ChargedStable proton
proton particle
Definition: Const.h:544
static const ChargedStable kaon
charged kaon particle
Definition: Const.h:543
static const ChargedStable electron
electron particle
Definition: Const.h:540
static const ChargedStable deuteron
deuteron particle
Definition: Const.h:545
@ c_WriteOut
Object/array should be saved by output modules.
Definition: DataStore.h:70
@ c_Event
Different object in each event, all objects/arrays are invalidated after event() function has been ca...
Definition: DataStore.h:59
ECL cluster data.
Definition: ECLCluster.h:27
double getEnergy(EHypothesisBit hypothesis) const
Return Energy (GeV).
Definition: ECLCluster.cc:19
@ c_nPhotons
CR is split into n photons (N1)
Module to assign ECL Clusters resulting from Bremsstrahlung to the primary electron track.
virtual void initialize() override
Use this to initialize resources or memory your module needs.
std::vector< float > m_virtualHitRadii
Radii where virtual hits for the extrapolation will be generated The default values are taken from br...
virtual void event() override
Called once for each event.
float m_electronProbabilityCut
Cut on the electron probability (from pid) of track.
StoreArray< BremHit > m_bremHits
StoreArray BremHits.
std::tuple< unsigned int, unsigned int > m_requestedNumberOfCDCHits
Minimal/Maximal number of CDC hits, the track has to possess to be considered for bremsstrahlung find...
double m_clusterAcceptanceFactor
Factor which is multiplied onto the cluster position error to check for matches.
StoreObjPtr< EventMetaData > m_evtPtr
StoreObjPtr EventMetaData.
std::string m_param_tracksStoreArrayName
StoreArray name of the Tracks for brem matching.
StoreArray< Track > m_tracks
StoreArray Track.
std::string m_param_recoTracksStoreArrayName
StoreArray name of the RecoTracks for brem matching.
StoreArray< ECLCluster > m_eclClusters
StoreArray ECLCluster.
std::string m_param_eclClustersStoreArrayName
StoreArray name of the ECLClusters for brem matching.
StoreArray< RecoTrack > m_recoTracks
StoreArray RecoTrack.
double m_relativeClusterEnergy
Fraction of the tracks energy the ECL cluster has to possess to be considered for bremsstrahlung find...
float m_clusterDistanceCut
Cut on the distance between the cluster position angle and the extrapolation angle.
Base class for Modules.
Definition: Module.h:72
Class to collect log likelihoods from TOP, ARICH, dEdx, ECL and KLM aimed for output to mdst includes...
Definition: PIDLikelihood.h:26
This is the Reconstruction Event-Data Model Track.
Definition: RecoTrack.h:76
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).
Values of the result of a track fit with a given particle hypothesis.
TVector3 getMomentum() const
Getter for vector of momentum at closest approach of track in r/phi projection.
Class that bundles various TrackFitResults.
Definition: Track.h:25
Exception class for error handling in GENFIT (provides storage for diagnostic information)
Definition: Exception.h:48
#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.