Belle II Software  release-08-01-10
PurityCalculatorTools.h
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 #pragma once
10 
11 #include <tracking/spacePointCreation/MCVXDPurityInfo.h>
12 
13 #include <framework/datastore/RelationVector.h>
14 #include <mdst/dataobjects/MCParticle.h>
15 
16 #include <tracking/spacePointCreation/SpacePoint.h>
17 //#include <vxd/dataobjects/VXDTrueHit.h>
18 #include <pxd/dataobjects/PXDTrueHit.h>
19 #include <svd/dataobjects/SVDTrueHit.h>
20 
21 #include <tracking/spacePointCreation/MapHelperFunctions.h>
22 
23 #include <vector>
24 #include <utility> // for pair
25 #include <unordered_map>
26 #include <cmath> // for fabs
27 
28 namespace Belle2 { // make seperate sub-namespace for this?
39  static bool findWeightInVector(std::vector<std::pair<int, double> >& vec, double weight)
40  {
41  const double epsilon = 1e-4; // no real need for accuracy here since weights are rather far apart!
42  return (std::find_if(vec.begin(), vec.end(),
43  [&epsilon, &weight](const std::pair<int, double>& p)
44  { return fabs(p.second - weight) <= epsilon; })
45  != vec.end());
46  }
47 
54  template<typename TrueHitType>
55  static std::vector<std::pair<int, double> > getMCParticles(const Belle2::SpacePoint* spacePoint)
56  {
57  // CAUTION: getting all TrueHits here (i.e. from all StoreArrays)
58  Belle2::RelationVector<TrueHitType> trueHits = spacePoint->getRelationsTo<TrueHitType>("ALL");
59  std::vector<std::pair<int, double> > mcParticles;
60  B2DEBUG(29, "Found " << trueHits.size() << " TrueHits related to SpacePoint " << spacePoint->getArrayIndex());
61 
62  for (size_t iTH = 0; iTH < trueHits.size(); ++iTH) {
63  B2DEBUG(29, "Trying to get MCParticles from TrueHit " << trueHits[iTH]->getArrayIndex() <<
64  " from Array " << trueHits[iTH]->getArrayName());
65  Belle2::MCParticle* mcPart = trueHits[iTH]->template getRelatedFrom<Belle2::MCParticle>("ALL");
66 
67  int mcPartId = -1; // default value for MCPartId (not found)
68  if (mcPart != nullptr) {
69  mcPartId = mcPart->getArrayIndex();
70  B2DEBUG(29, "TrueHit is related to MCParticle " << mcPartId);
71  } else {
72  B2DEBUG(20, "Found no MCParticle related to TrueHit " << trueHits[iTH]->getArrayIndex() <<
73  " from Array " << trueHits[iTH]->getArrayName());
74  }
75  mcParticles.push_back(std::make_pair(mcPartId, trueHits.weight(iTH)));
76  }
77 
78  // sort & unique to filter out double MCIds (if the relations are set correct, this only happens if more than one TrueHits point to the same MCParticle)
79  std::sort(mcParticles.begin(), mcParticles.end());
80  auto newEnd = std::unique(mcParticles.begin(), mcParticles.end(),
81  [](const std::pair<int, double>& a, const std::pair<int, double>& b) { return a.first == b.first; }
82  );
83  if (newEnd != mcParticles.end()) B2DEBUG(20,
84  "More than one TrueHits (related to one SpacePoint) are related to the same MCParticle!");
85  mcParticles.resize(std::distance(mcParticles.begin(), newEnd));
86 
87  // check if there were noise Clusters in the SpacePoint
88  // only case left for PXD is missing TrueHit for underlying Cluster, everything else is covered!
89  if (spacePoint->getType() == VXD::SensorInfoBase::PXD) {
90  if (mcParticles.empty()) mcParticles.push_back(std::make_pair(-2, 1)); // if no Id in vector there is no relation to TrueHit
91  } else if (spacePoint->getType() == VXD::SensorInfoBase::SVD) { // for SVD some more tests are needed!
92  // check if there is one MCParticle that is related to both Clusters of the SpacePoint
93  if (!findWeightInVector(mcParticles, 2)) { // if not both related check which ones should have a relation and act accordingly
94  const std::pair<bool, bool>& clusters = spacePoint->getIfClustersAssigned();
95  bool uGood = clusters.first && findWeightInVector(mcParticles, 11);
96  bool vGood = clusters.second && findWeightInVector(mcParticles, 21);
97  if (!uGood && !vGood) mcParticles.push_back(std::make_pair(-2, 2)); // if both Clusters are not related -> weight is 2
98  else if (uGood && !vGood) mcParticles.push_back(std::make_pair(-2, 21)); // if only V-Cluster is not related -> weight is 21
99  else if (!uGood && vGood) mcParticles.push_back(std::make_pair(-2, 11)); // if only U-Cluster is not related -> weight is 11
100  }
101  } else {
102  B2ERROR("Unknown DetectorType in getMCParticles! This is just a notification! Needs to be handled!"); // should not happen
103  }
104 
105  return mcParticles;
106  }
107 
111  static void increaseClusterCounters(const Belle2::SpacePoint* spacePoint, std::array<unsigned, 3>& clusterCtr)
112  {
113  if (spacePoint->getType() == Belle2::VXD::SensorInfoBase::PXD) {
114  clusterCtr[0]++;
115  B2DEBUG(29, "SpacePoint contains PXDCluster");
116  } else {
117  std::pair<bool, bool> setClusters = spacePoint->getIfClustersAssigned();
118  if (setClusters.first) {
119  clusterCtr[1]++;
120  B2DEBUG(29, "SpacePoint contains U SVDCluster");
121  }
122  if (setClusters.second) {
123  clusterCtr[2]++;
124  B2DEBUG(29, "SpacePoint contains V SVDCluster");
125  }
126  }
127  }
128 
132  static std::vector<size_t> getAccessorsFromWeight(double weight)
133  {
134  if (weight < 1.5 && weight > 0) return {0}; // weight 1 -> PXD
135  if (weight < 2.5 && weight > 0) return { 1, 2 }; // weight 2 -> both Clusters with relation to MCParticle
136  if (weight < 20 && weight > 0) return {1}; // weight 11 -> only U-Cluster related to MCParticle
137  if (weight > 20 && weight < 30) return {2}; // weight 21 -> only V-Cluster related to MCParticle
138 
139  return std::vector<size_t>(); // empty vector else
140  }
141 
149  static std::vector<Belle2::MCVXDPurityInfo> createPurityInfosVec(const std::vector<const Belle2::SpacePoint*>& spacePoints)
150  {
151  std::array<unsigned, 3> totalClusters = { {0, 0, 0 } };
152  // WARNING: relying on the fact here that all array entries will be initialized to 0
153  std::unordered_map<int, std::array<unsigned, 3> > mcClusters;
154 
155  unsigned nClusters = 0; // NOTE: only needed for DEBUG output -> remove?
156 
157  for (const Belle2::SpacePoint* spacePoint : spacePoints) {
158  B2DEBUG(29, "Now processing SpacePoint " << spacePoint->getArrayIndex() << " from Array " << spacePoint->getArrayName());
159  increaseClusterCounters(spacePoint, totalClusters);
160 
161  nClusters += spacePoint->getNClustersAssigned();
162 
163  std::vector<std::pair<int, double> > mcParticles;
164  if (spacePoint->getType() == VXD::SensorInfoBase::PXD) mcParticles = getMCParticles<PXDTrueHit>(spacePoint);
165  else if (spacePoint->getType() == VXD::SensorInfoBase::SVD) mcParticles = getMCParticles<SVDTrueHit>(spacePoint);
166  else if (spacePoint->getType() == VXD::SensorInfoBase::VXD) {B2DEBUG(25, "found generic spacePoint, treating it as virtualIP");}
167  else B2FATAL("Unknown DetectorType (" << spacePoint->getType() << ") in createPurityInfos! Skipping this SpacePoint " <<
168  spacePoint->getArrayIndex() << " from Array " << spacePoint->getArrayName());
169 
170  for (const std::pair<int, double>& particle : mcParticles) {
171  std::vector<size_t> accessors = getAccessorsFromWeight(particle.second);
172  for (size_t acc : accessors) {
173  mcClusters[particle.first][acc]++;
174  }
175  }
176  }
177  B2DEBUG(29, "container contained " << spacePoints.size() << " SpacePoint with " << nClusters << " Clusters");
178 
179  // create MCVXDPurityInfos and add them to the return vector
180  std::vector<Belle2::MCVXDPurityInfo> purityInfos;
181  for (int mcId : getUniqueKeys(mcClusters)) {
182  // cppcheck-suppress useStlAlgorithm
183  purityInfos.push_back(MCVXDPurityInfo(mcId, totalClusters, mcClusters[mcId]));
184  }
185 
186  // sort in descending order before return
187  std::sort(purityInfos.begin(), purityInfos.end(),
188  [](const MCVXDPurityInfo & left, const MCVXDPurityInfo & right) { return left > right; }
189  );
190  return purityInfos;
191  }
192 
201  template<typename SPContainer>
202  static std::vector<Belle2::MCVXDPurityInfo> createPurityInfos(const SPContainer* container)
203  {
204  return createPurityInfosVec(container->getHits());
205  }
206 
217  template<typename SPContainer>
218  static std::vector<Belle2::MCVXDPurityInfo> createPurityInfos(const SPContainer& container)
219  {
220  return createPurityInfos(&container);
221  }
223 } // end namespace Belle2
A Class to store the Monte Carlo particle information.
Definition: MCParticle.h:32
int getArrayIndex() const
Get 0-based index of the particle in the corresponding MCParticle list.
Definition: MCParticle.h:244
The MC VXD Purity info container class.
Class for type safe access to objects that are referred to in relations.
size_t size() const
Get number of relations.
float weight(int index) const
Get weight with index.
int getArrayIndex() const
Returns this object's array index (in StoreArray), or -1 if not found.
RelationVector< TO > getRelationsTo(const std::string &name="", const std::string &namedRelation="") const
Get the relations that point from this object to another store array.
SpacePoint typically is build from 1 PXDCluster or 1-2 SVDClusters.
Definition: SpacePoint.h:42
std::pair< bool, bool > getIfClustersAssigned() const
Returns, if u(v)-coordinate is based on cluster information.
Definition: SpacePoint.h:162
Belle2::VXD::SensorInfoBase::SensorType getType() const
Return SensorType (PXD, SVD, ...) on which the SpacePoint lives.
Definition: SpacePoint.h:145
@ VXD
Any type of VXD Sensor.
static bool findWeightInVector(std::vector< std::pair< int, double > > &vec, double weight)
find the given weight in the given vector of pair<int,double> NOTE: the criteria for finding are rath...
static void increaseClusterCounters(const Belle2::SpacePoint *spacePoint, std::array< unsigned, 3 > &clusterCtr)
increase the appropriate Cluster counter by asking the SpacePoint which type he has and which Cluster...
static std::vector< Belle2::MCVXDPurityInfo > createPurityInfosVec(const std::vector< const Belle2::SpacePoint * > &spacePoints)
create a vector of MCVXDPurityInfos objects for a std::vector<Belle2::SpacePoints>.
std::vector< typename MapType::key_type > getUniqueKeys(const MapType &aMap)
get the unique keys of a map (i.e.
static std::vector< Belle2::MCVXDPurityInfo > createPurityInfos(const SPContainer *container)
create a vector of MCVXDPurityInfos objects for any given container holding SpacePoints and providing...
static std::vector< std::pair< int, double > > getMCParticles(const Belle2::SpacePoint *spacePoint)
get the related MCParticles to the TrueHit.
static std::vector< size_t > getAccessorsFromWeight(double weight)
convert the relation weight (SpacePoint <-> TrueHit) to a type that can be used to access arrays
Abstract base class for different kinds of events.