CMS 3D CMS Logo

RealisticHitToClusterAssociator.h
Go to the documentation of this file.
1 #ifndef __RecoParticleFlow_PFClusterProducer_RealisticHitToClusterAssociator_H__
2 #define __RecoParticleFlow_PFClusterProducer_RealisticHitToClusterAssociator_H__
3 // Author: Felice Pantaleo
5 // Date: 30/06/2017
6 // Email: felice@cern.ch
8 #include <vector>
9 #include <cmath>
10 #include <unordered_map>
11 #include "RealisticCluster.h"
12 
13 namespace
14 {
15 
16 float getDecayLength(unsigned int layer, unsigned int fhOffset, unsigned int bhOffset)
17 {
18  constexpr float eeDecayLengthInLayer = 2.f;
19  constexpr float fhDecayLengthInLayer = 1.5f;
20  constexpr float bhDecayLengthInLayer = 1.f;
21 
22  if (layer <= fhOffset)
23  return eeDecayLengthInLayer;
24  else if (layer > fhOffset && layer <= bhOffset)
25  return fhDecayLengthInLayer;
26  else
27  return bhDecayLengthInLayer;
28 }
29 }
30 
31 
33 {
34  using Hit3DPosition = std::array<float,3>;
35 
36  public:
37 
38  struct RealisticHit
39  {
40  struct HitToCluster
41  {
42  unsigned int simClusterId_;
46  };
47 
49  float totalEnergy_;
50  unsigned int layerId_;
51  std::vector<HitToCluster> hitToCluster_;
52  };
53 
54  void init(std::size_t numberOfHits, std::size_t numberOfSimClusters,
55  std::size_t numberOfLayers)
56  {
57  realisticHits_.resize(numberOfHits);
58  realisticSimClusters_.resize(numberOfSimClusters);
59  for(auto& sc: realisticSimClusters_)
60  sc.setLayersNum(numberOfLayers);
61  }
62 
63  void insertHitPosition(float x, float y, float z, unsigned int hitIndex)
64  {
65  realisticHits_[hitIndex].hitPosition_ = {{x,y,z}};
66  }
67 
68  void insertLayerId(unsigned int layerId, unsigned int hitIndex)
69  {
70  realisticHits_[hitIndex].layerId_ = layerId;
71  }
72 
73  void insertHitEnergy(float energy, unsigned int hitIndex)
74  {
75  realisticHits_[hitIndex].totalEnergy_ = energy;
76  }
77 
78  void insertSimClusterIdAndFraction(unsigned int scIdx, float fraction,
79  unsigned int hitIndex, float associatedEnergy)
80  {
81  realisticHits_[hitIndex].hitToCluster_.emplace_back(RealisticHit::HitToCluster{scIdx, fraction, 0.f, 0.f});
82  realisticSimClusters_[scIdx].setMaxEnergyHit(realisticHits_[hitIndex].layerId_, associatedEnergy, realisticHits_[hitIndex].hitPosition_);
83  }
84 
85  float XYdistanceFromMaxHit(unsigned int hitId, unsigned int clusterId)
86  {
87  auto l = realisticHits_[hitId].layerId_;
88  const auto& maxHitPosition = realisticSimClusters_[clusterId].getMaxEnergyPosition(l);
89  float distanceSquared = std::pow((realisticHits_[hitId].hitPosition_[0] - maxHitPosition[0]),2) + std::pow((realisticHits_[hitId].hitPosition_[1] - maxHitPosition[1]),2);
90  return std::sqrt(distanceSquared);
91  }
92 
93  float XYdistanceFromPointOnSameLayer(unsigned int hitId, const Hit3DPosition& point)
94  {
95  float distanceSquared = std::pow((realisticHits_[hitId].hitPosition_[0] - point[0]),2) + std::pow((realisticHits_[hitId].hitPosition_[1] - point[1]),2);
96  return std::sqrt(distanceSquared);
97  }
98 
99  void computeAssociation( float exclusiveFraction, bool useMCFractionsForExclEnergy, unsigned int fhOffset, unsigned int bhOffset)
100  {
101  //if more than exclusiveFraction of a hit's energy belongs to a cluster, that rechit is not counted as shared
102  unsigned int numberOfHits = realisticHits_.size();
103  std::vector<float> partialEnergies;
104  for(unsigned int hitId = 0; hitId < numberOfHits; ++hitId)
105  {
106  partialEnergies.clear();
107  std::vector<unsigned int> removeAssociation;
108  auto& realisticHit = realisticHits_[hitId];
109  unsigned int numberOfClusters = realisticHit.hitToCluster_.size();
110  if(numberOfClusters == 1)
111  {
112  unsigned int simClusterId = realisticHit.hitToCluster_[0].simClusterId_;
113  float assignedFraction = 1.f;
114  realisticHit.hitToCluster_[0].realisticEnergyFraction_ = assignedFraction;
115  float assignedEnergy = realisticHit.totalEnergy_;
116  realisticSimClusters_[simClusterId].increaseEnergy(assignedEnergy);
117  realisticSimClusters_[simClusterId].addHitAndFraction(hitId, assignedFraction);
118  realisticSimClusters_[simClusterId].increaseExclusiveEnergy(assignedEnergy);
119  }
120  else
121  {
122  partialEnergies.resize(numberOfClusters,0.f);
123  unsigned int layer = realisticHit.layerId_;
124  float sumE = 0.f;
125  float energyDecayLength = getDecayLength(layer, fhOffset, bhOffset);
126  for(unsigned int clId = 0; clId < numberOfClusters; ++clId )
127  {
128  auto simClusterId = realisticHit.hitToCluster_[clId].simClusterId_;
129  realisticHit.hitToCluster_[clId].distanceFromMaxHit_ = XYdistanceFromMaxHit(hitId,simClusterId);
130  // partial energy is computed based on the distance from the maximum energy hit and its energy
131  // partial energy is only needed to compute a fraction and it's not the energy assigned to the cluster
132  auto maxEnergyOnLayer = realisticSimClusters_[simClusterId].getMaxEnergy(layer);
133  if(maxEnergyOnLayer>0.f)
134  {
135  partialEnergies[clId] = maxEnergyOnLayer * std::exp(-realisticHit.hitToCluster_[clId].distanceFromMaxHit_/energyDecayLength);
136  }
137  sumE += partialEnergies[clId];
138  }
139  if(sumE > 0.f)
140  {
141  float invSumE = 1.f/sumE;
142  for(unsigned int clId = 0; clId < numberOfClusters; ++clId )
143  {
144  unsigned int simClusterIndex = realisticHit.hitToCluster_[clId].simClusterId_;
145  float assignedFraction = partialEnergies[clId]*invSumE;
146  if(assignedFraction > 1e-3)
147  {
148  realisticHit.hitToCluster_[clId].realisticEnergyFraction_ = assignedFraction;
149  float assignedEnergy = assignedFraction *realisticHit.totalEnergy_;
150  realisticSimClusters_[simClusterIndex].increaseEnergy(assignedEnergy);
151  realisticSimClusters_[simClusterIndex].addHitAndFraction(hitId, assignedFraction);
152  // if the hits energy belongs for more than exclusiveFraction to a cluster, also the cluster's
153  // exclusive energy is increased. The exclusive energy will be needed to evaluate if
154  // a realistic cluster will be invisible, i.e. absorbed by other clusters
155  if( (useMCFractionsForExclEnergy and realisticHit.hitToCluster_[clId].mcEnergyFraction_ > exclusiveFraction) or
156  (!useMCFractionsForExclEnergy and assignedFraction > exclusiveFraction) )
157  {
158  realisticSimClusters_[simClusterIndex].increaseExclusiveEnergy(assignedEnergy);
159  }
160  }
161  else
162  {
163  removeAssociation.push_back(simClusterIndex);
164  }
165  }
166  }
167  }
168 
169  while(!removeAssociation.empty())
170  {
171  auto clusterToRemove = removeAssociation.back();
172  removeAssociation.pop_back();
173 
174  realisticHit.hitToCluster_.erase(std::remove_if(realisticHit.hitToCluster_.begin(), realisticHit.hitToCluster_.end(), [clusterToRemove](const RealisticHit::HitToCluster& x)
175  {
176  return x.simClusterId_ == clusterToRemove;
177  }), realisticHit.hitToCluster_.end());
178  }
179  }
180  }
181 
183  {
184  unsigned int numberOfRealSimClusters = realisticSimClusters_.size();
185 
186  for(unsigned int clId= 0; clId < numberOfRealSimClusters; ++clId)
187  {
188  if(realisticSimClusters_[clId].getExclusiveEnergyFraction() < invisibleFraction)
189  {
190  realisticSimClusters_[clId].setVisible(false);
191  auto& hAndF = realisticSimClusters_[clId].hitsIdsAndFractions();
192  std::unordered_map < unsigned int, float> energyInNeighbors;
193  float totalSharedEnergy=0.f;
194 
195  for(auto& elt : hAndF)
196  {
197  unsigned int hitId = elt.first;
198  float fraction = elt.second;
199  auto& realisticHit = realisticHits_[hitId];
200 
201  if(realisticHit.hitToCluster_.size() >1 && fraction < 1.f)
202  {
203  float correction = 1.f - fraction;
204  unsigned int numberOfClusters = realisticHit.hitToCluster_.size();
205  int clusterToRemove = -1;
206  for(unsigned int i = 0; i< numberOfClusters; ++i)
207  {
208  auto simClusterIndex = realisticHit.hitToCluster_[i].simClusterId_;
209  if(simClusterIndex == clId)
210  {
211  clusterToRemove = i;
212  }
213  else
214  if(realisticSimClusters_[simClusterIndex].isVisible())
215  {
216  float oldFraction = realisticHit.hitToCluster_[i].realisticEnergyFraction_;
217  float newFraction = oldFraction/correction;
218  float oldEnergy = oldFraction*realisticHit.totalEnergy_;
219  float newEnergy= newFraction*realisticHit.totalEnergy_;
220  float sharedEnergy = newEnergy-oldEnergy;
221  energyInNeighbors[simClusterIndex] +=sharedEnergy;
222  totalSharedEnergy +=sharedEnergy;
223  realisticSimClusters_[simClusterIndex].increaseEnergy(sharedEnergy);
224  realisticSimClusters_[simClusterIndex].modifyFractionForHitId(newFraction, hitId);
225  realisticHit.hitToCluster_[i].realisticEnergyFraction_ = newFraction;
226  if(newFraction > exclusiveFraction)
227  {
228  realisticSimClusters_[simClusterIndex].increaseExclusiveEnergy(sharedEnergy);
229  if(oldFraction <=exclusiveFraction)
230  {
231  realisticSimClusters_[simClusterIndex].increaseExclusiveEnergy(oldEnergy);
232  }
233  }
234  }
235  }
236  realisticSimClusters_[realisticHit.hitToCluster_[clusterToRemove].simClusterId_].modifyFractionForHitId(0.f, hitId);
237  realisticHit.hitToCluster_.erase(realisticHit.hitToCluster_.begin()+clusterToRemove);
238  }
239  }
240 
241  for(auto& elt : hAndF)
242  {
243  unsigned int hitId = elt.first;
244  auto& realisticHit = realisticHits_[hitId];
245  if(realisticHit.hitToCluster_.size()==1 and realisticHit.hitToCluster_[0].simClusterId_ == clId and totalSharedEnergy > 0.f)
246  {
247  for (auto& pair: energyInNeighbors)
248  {
249  // hits that belonged completely to the absorbed cluster are redistributed
250  // based on the fraction of energy shared in the shared hits
251  float sharedFraction = pair.second/totalSharedEnergy;
252  float assignedEnergy = realisticHit.totalEnergy_*sharedFraction;
253  realisticSimClusters_[pair.first].increaseEnergy(assignedEnergy);
254  realisticSimClusters_[pair.first].addHitAndFraction(hitId, sharedFraction);
255  realisticHit.hitToCluster_.emplace_back(RealisticHit::HitToCluster{pair.first, 0.f, -1.f, sharedFraction});
256  if(sharedFraction > exclusiveFraction)
257  realisticSimClusters_[pair.first].increaseExclusiveEnergy(assignedEnergy);
258  }
259  }
260  }
261 
262  }
263  }
264  }
265 
267  {
268  for(auto& cluster : realisticSimClusters_)
269  {
270  if(cluster.isVisible())
271  {
272  unsigned int layersNum = cluster.getLayersNum();
273  std::vector<float> totalEnergyPerLayer(layersNum, 0.f);
274  std::vector<float> xEnergyPerLayer(layersNum, 0.f);
275  std::vector<float> yEnergyPerLayer(layersNum, 0.f);
276  std::vector<float> zPositionPerLayer(layersNum, 0.f);
277  const auto& hAndF = cluster.hitsIdsAndFractions();
278  for(auto& elt : hAndF)
279  {
280  auto hitId = elt.first;
281  auto fraction = elt.second;
282  const auto & hit = realisticHits_[hitId];
283  const auto & hitPos = hit.hitPosition_;
284  auto layerId = hit.layerId_;
285  auto hitEinCluster = hit.totalEnergy_*fraction;
286  totalEnergyPerLayer[layerId]+= hitEinCluster;
287  xEnergyPerLayer[layerId] += hitPos[0]*hitEinCluster;
288  yEnergyPerLayer[layerId] += hitPos[1]*hitEinCluster;
289  zPositionPerLayer[layerId] = hitPos[2];
290  }
291  Hit3DPosition centerOfGravity;
292  for(unsigned int layerId=0; layerId<layersNum; layerId++)
293  {
294  auto energyOnLayer = totalEnergyPerLayer[layerId];
295  if(energyOnLayer > 0.f)
296  {
297  centerOfGravity = {{xEnergyPerLayer[layerId]/energyOnLayer,yEnergyPerLayer[layerId]/energyOnLayer, zPositionPerLayer[layerId] }};
298  cluster.setCenterOfGravity(layerId,centerOfGravity );
299  }
300  }
301  }
302  }
303  }
304 
306  {
307  for(auto& cluster : realisticSimClusters_)
308  {
309  if(cluster.isVisible())
310  {
311  auto& hAndF = cluster.hitsIdsAndFractions();
312  for(unsigned int i = 0; i<hAndF.size(); ++i)
313  {
314  auto hitId = hAndF[i].first;
315  const auto & hit = realisticHits_[hitId];
316  auto layerId = hit.layerId_;
317  if(XYdistanceFromPointOnSameLayer(hitId, cluster.getCenterOfGravity(layerId)) > maxDistance)
318  {
319  cluster.increaseEnergy(-hit.totalEnergy_*hAndF[i].second);
320  cluster.modifyFractionByIndex(0.f, i);
321  }
322  }
323  }
324  }
325  }
326 
327  const std::vector< RealisticCluster > & realisticClusters() const
328  { return realisticSimClusters_;}
329 
330  private:
331  // the vector of the Realistic SimClusters
332  std::vector< RealisticCluster > realisticSimClusters_;
333  // the vector of the Realistic SimClusters
334  std::vector< RealisticHit > realisticHits_;
335  };
336 
337 
338 
339 #endif
void insertLayerId(unsigned int layerId, unsigned int hitIndex)
float sharedEnergy(reco::CaloCluster const &clu1, reco::CaloCluster const &clu2, EcalRecHitCollection const &barrelRecHits, EcalRecHitCollection const &endcapRecHits)
void init(std::size_t numberOfHits, std::size_t numberOfSimClusters, std::size_t numberOfLayers)
void insertSimClusterIdAndFraction(unsigned int scIdx, float fraction, unsigned int hitIndex, float associatedEnergy)
T sqrt(T t)
Definition: SSEVec.h:18
void computeAssociation(float exclusiveFraction, bool useMCFractionsForExclEnergy, unsigned int fhOffset, unsigned int bhOffset)
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e< void, edm::EventID const &, edm::Timestamp const & > We also list in braces which AR_WATCH_USING_METHOD_ is used for those or
Definition: Activities.doc:12
void findAndMergeInvisibleClusters(float invisibleFraction, float exclusiveFraction)
void insertHitPosition(float x, float y, float z, unsigned int hitIndex)
double f[11][100]
void insertHitEnergy(float energy, unsigned int hitIndex)
const std::vector< RealisticCluster > & realisticClusters() const
std::vector< RealisticCluster > realisticSimClusters_
float XYdistanceFromMaxHit(unsigned int hitId, unsigned int clusterId)
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:40
#define constexpr
float XYdistanceFromPointOnSameLayer(unsigned int hitId, const Hit3DPosition &point)
*vegas h *****************************************************used in the default bin number in original ***version of VEGAS is ***a higher bin number might help to derive a more precise ***grade subtle point
Definition: invegas.h:5