CMS 3D CMS Logo

HGCalImagingAlgo.cc
Go to the documentation of this file.
2 
3 // Geometry
8 
10 //
12 #include "tbb/task_arena.h"
13 #include "tbb/tbb.h"
14 
15 using namespace hgcal_clustering;
16 
18  // loop over all hits and create the Hexel structure, skip energies below ecut
19 
20  if (dependSensor_) {
21  // for each layer and wafer calculate the thresholds (sigmaNoise and energy)
22  // once
23  computeThreshold();
24  }
25 
26  std::vector<bool> firstHit(2 * (maxlayer + 1), true);
27  for (unsigned int i = 0; i < hits.size(); ++i) {
28 
29  const HGCRecHit &hgrh = hits[i];
30  DetId detid = hgrh.detid();
31  unsigned int layer = rhtools_.getLayerWithOffset(detid);
32  float thickness = 0.f;
33  // set sigmaNoise default value 1 to use kappa value directly in case of
34  // sensor-independent thresholds
35  float sigmaNoise = 1.f;
36  if (dependSensor_) {
37  thickness = rhtools_.getSiThickness(detid);
38  int thickness_index = rhtools_.getSiThickIndex(detid);
39  if (thickness_index == -1)
40  thickness_index = 3;
41  double storedThreshold = thresholds_[layer - 1][thickness_index];
42  sigmaNoise = sigmaNoise_[layer - 1][thickness_index];
43 
44  if (hgrh.energy() < storedThreshold)
45  continue; // this sets the ZS threshold at ecut times the sigma noise
46  // for the sensor
47  }
48  if (!dependSensor_ && hgrh.energy() < ecut_)
49  continue;
50 
51  // map layers from positive endcap (z) to layer + maxlayer+1 to prevent
52  // mixing up hits from different sides
53  layer += int(rhtools_.zside(detid) > 0) * (maxlayer + 1);
54 
55  // determine whether this is a half-hexagon
56  bool isHalf = rhtools_.isHalfCell(detid);
57  const GlobalPoint position(rhtools_.getPosition(detid));
58 
59  // here's were the KDNode is passed its dims arguments - note that these are
60  // *copied* from the Hexel
61  points_[layer].emplace_back(
62  Hexel(hgrh, detid, isHalf, sigmaNoise, thickness, &rhtools_),
63  position.x(), position.y());
64 
65  // for each layer, store the minimum and maximum x and y coordinates for the
66  // KDTreeBox boundaries
67  if (firstHit[layer]) {
68  minpos_[layer][0] = position.x();
69  minpos_[layer][1] = position.y();
70  maxpos_[layer][0] = position.x();
71  maxpos_[layer][1] = position.y();
72  firstHit[layer] = false;
73  } else {
74  minpos_[layer][0] = std::min((float)position.x(), minpos_[layer][0]);
75  minpos_[layer][1] = std::min((float)position.y(), minpos_[layer][1]);
76  maxpos_[layer][0] = std::max((float)position.x(), maxpos_[layer][0]);
77  maxpos_[layer][1] = std::max((float)position.y(), maxpos_[layer][1]);
78  }
79 
80  } // end loop hits
81 }
82 // Create a vector of Hexels associated to one cluster from a collection of
83 // HGCalRecHits - this can be used directly to make the final cluster list -
84 // this method can be invoked multiple times for the same event with different
85 // input (reset should be called between events)
87  layerClustersPerLayer_.resize(2 * maxlayer + 2);
88  // assign all hits in each layer to a cluster core or halo
89  tbb::this_task_arena::isolate([&] {
90  tbb::parallel_for(size_t(0), size_t(2 * maxlayer + 2), [&](size_t i) {
91  KDTreeBox bounds(minpos_[i][0], maxpos_[i][0], minpos_[i][1], maxpos_[i][1]);
92  KDTree hit_kdtree;
93  hit_kdtree.build(points_[i], bounds);
94 
95  unsigned int actualLayer =
96  i > maxlayer
97  ? (i - (maxlayer + 1))
98  : i; // maps back from index used for KD trees to actual layer
99 
100  double maxdensity = calculateLocalDensity(
101  points_[i], hit_kdtree, actualLayer); // also stores rho (energy
102  // density) for each point (node)
103  // calculate distance to nearest point with higher density storing
104  // distance (delta) and point's index
105  calculateDistanceToHigher(points_[i]);
106  findAndAssignClusters(points_[i], hit_kdtree, maxdensity, bounds,
107  actualLayer, layerClustersPerLayer_[i]);
108  });
109  });
110  //Now that we have the density per point we can store it
111 for(auto const& p: points_) { setDensity(p); }
112 }
113 
114 std::vector<reco::BasicCluster> HGCalImagingAlgo::getClusters(bool doSharing) {
115 
117  std::vector<std::pair<DetId, float>> thisCluster;
118  for (auto &clsOnLayer : layerClustersPerLayer_) {
119  for (unsigned int i = 0; i < clsOnLayer.size(); ++i) {
120  double energy = 0;
121  Point position;
122 
123  //Will save the maximum density hit of the cluster
124  size_t rsmax = max_index(clsOnLayer[i]);
125 
126  if (doSharing) {
127 
128  std::vector<unsigned> seeds = findLocalMaximaInCluster(clsOnLayer[i]);
129  // sharing found seeds.size() sub-cluster seeds in cluster i
130 
131  std::vector<std::vector<double>> fractions;
132  // first pass can have noise it in
133  shareEnergy(clsOnLayer[i], seeds, fractions);
134 
135  // reset and run second pass after vetoing seeds
136  // that result in trivial clusters (less than 2 effective cells)
137 
138  for (unsigned isub = 0; isub < fractions.size(); ++isub) {
139  double effective_hits = 0.0;
140  double energy =
141  calculateEnergyWithFraction(clsOnLayer[i], fractions[isub]);
142  Point position =
143  calculatePositionWithFraction(clsOnLayer[i], fractions[isub]);
144 
145  for (unsigned ihit = 0; ihit < fractions[isub].size(); ++ihit) {
146  const double fraction = fractions[isub][ihit];
147  if (fraction > 1e-7) {
148  effective_hits += fraction;
149  thisCluster.emplace_back(clsOnLayer[i][ihit].data.detid,
150  fraction);
151  }
152  }
153 
154  if (verbosity_ < pINFO) {
155  std::cout << "\t******** NEW CLUSTER (SHARING) ********"
156  << std::endl;
157  std::cout << "\tEff. No. of cells = " << effective_hits
158  << std::endl;
159  std::cout << "\t Energy = " << energy << std::endl;
160  std::cout << "\t Phi = " << position.phi()
161  << std::endl;
162  std::cout << "\t Eta = " << position.eta()
163  << std::endl;
164  std::cout << "\t*****************************" << std::endl;
165  }
166  clusters_v_.emplace_back(energy, position, caloID, thisCluster,
167  algoId_);
168  if (!clusters_v_.empty()){ clusters_v_.back().setSeed( clsOnLayer[i][rsmax].data.detid); }
169  thisCluster.clear();
170  }
171  } else {
172  position = calculatePosition(clsOnLayer[i]); // energy-weighted position
173  // std::vector< KDNode >::iterator it;
174  for (auto &it : clsOnLayer[i]) {
175  energy += it.data.isHalo ? 0. : it.data.weight;
176  // use fraction to store whether this is a Halo hit or not
177  thisCluster.emplace_back(it.data.detid, (it.data.isHalo ? 0.f : 1.f));
178  }
179  if (verbosity_ < pINFO) {
180  std::cout << "******** NEW CLUSTER (HGCIA) ********" << std::endl;
181  std::cout << "Index " << i << std::endl;
182  std::cout << "No. of cells = " << clsOnLayer[i].size() << std::endl;
183  std::cout << " Energy = " << energy << std::endl;
184  std::cout << " Phi = " << position.phi() << std::endl;
185  std::cout << " Eta = " << position.eta() << std::endl;
186  std::cout << "*****************************" << std::endl;
187  }
188  clusters_v_.emplace_back(energy, position, caloID, thisCluster, algoId_);
189  if (!clusters_v_.empty()){ clusters_v_.back().setSeed( clsOnLayer[i][rsmax].data.detid); }
190  thisCluster.clear();
191  }
192  }
193  }
194  return clusters_v_;
195 }
196 
198 HGCalImagingAlgo::calculatePosition(std::vector<KDNode> &v) const {
199  float total_weight = 0.f;
200  float x = 0.f;
201  float y = 0.f;
202 
203  unsigned int v_size = v.size();
204  unsigned int maxEnergyIndex = 0;
205  float maxEnergyValue = 0;
206 
207  // loop over hits in cluster candidate
208  // determining the maximum energy hit
209  for (unsigned int i = 0; i < v_size; i++) {
210  if (v[i].data.weight > maxEnergyValue) {
211  maxEnergyValue = v[i].data.weight;
212  maxEnergyIndex = i;
213  }
214  }
215 
216  // Si cell or Scintillator. Used to set approach and parameters
217  int thick = rhtools_.getSiThickIndex(v[maxEnergyIndex].data.detid);
218 
219  // for hits within positionDeltaRho_c_ from maximum energy hit
220  // build up weight for energy-weighted position
221  // and save corresponding hits indices
222  std::vector<unsigned int> innerIndices;
223  for (unsigned int i = 0; i < v_size; i++) {
224  if (thick == -1 ||
225  distance2(v[i].data, v[maxEnergyIndex].data) < positionDeltaRho_c_[thick]){
226  innerIndices.push_back(i);
227 
228  float rhEnergy = v[i].data.weight;
229  total_weight += rhEnergy;
230  // just fill x, y for scintillator
231  // for Si it is overwritten later anyway
232  if(thick == -1){
233  x += v[i].data.x * rhEnergy;
234  y += v[i].data.y * rhEnergy;
235  }
236  }
237  }
238  // just loop on reduced vector of interesting indices
239  // to compute log weighting
240  if(thick != -1 && total_weight != 0.){ // Silicon case
241  float total_weight_log = 0.f;
242  float x_log = 0.f;
243  float y_log = 0.f;
244  for (auto idx : innerIndices) {
245  float rhEnergy = v[idx].data.weight;
246  if(rhEnergy == 0.) continue;
247  float Wi = std::max(thresholdW0_[thick] + log(rhEnergy/total_weight), 0.);
248  x_log += v[idx].data.x * Wi;
249  y_log += v[idx].data.y * Wi;
250  total_weight_log += Wi;
251  }
252  total_weight = total_weight_log;
253  x = x_log;
254  y = y_log;
255  }
256 
257  if (total_weight != 0.) {
258  auto inv_tot_weight = 1. / total_weight;
259  return math::XYZPoint(x * inv_tot_weight,
260  y * inv_tot_weight,
261  v[maxEnergyIndex].data.z);
262  }
263  return math::XYZPoint(0, 0, 0);
264 }
265 
266 double HGCalImagingAlgo::calculateLocalDensity(std::vector<KDNode> &nd,
267  KDTree &lp,
268  const unsigned int layer) const {
269 
270  double maxdensity = 0.;
271  float delta_c; // maximum search distance (critical distance) for local
272  // density calculation
273  if (layer <= lastLayerEE)
274  delta_c = vecDeltas_[0];
275  else if (layer <= lastLayerFH)
276  delta_c = vecDeltas_[1];
277  else
278  delta_c = vecDeltas_[2];
279 
280  // for each node calculate local density rho and store it
281  for (unsigned int i = 0; i < nd.size(); ++i) {
282  // speec up search by looking within +/- delta_c window only
283  KDTreeBox search_box(nd[i].dims[0] - delta_c, nd[i].dims[0] + delta_c,
284  nd[i].dims[1] - delta_c, nd[i].dims[1] + delta_c);
285  std::vector<KDNode> found;
286  lp.search(search_box, found);
287  const unsigned int found_size = found.size();
288  for (unsigned int j = 0; j < found_size; j++) {
289  if (distance(nd[i].data, found[j].data) < delta_c) {
290  nd[i].data.rho += found[j].data.weight;
291  maxdensity = std::max(maxdensity, nd[i].data.rho);
292  }
293  } // end loop found
294  } // end loop nodes
295  return maxdensity;
296 }
297 
298 double
299 HGCalImagingAlgo::calculateDistanceToHigher(std::vector<KDNode> &nd) const {
300 
301  // sort vector of Hexels by decreasing local density
302  std::vector<size_t> rs = sorted_indices(nd);
303 
304  double maxdensity = 0.0;
305  int nearestHigher = -1;
306 
307  if (!rs.empty())
308  maxdensity = nd[rs[0]].data.rho;
309  else
310  return maxdensity; // there are no hits
311  double dist2 = 0.;
312  // start by setting delta for the highest density hit to
313  // the most distant hit - this is a convention
314 
315  for (auto &j : nd) {
316  double tmp = distance2(nd[rs[0]].data, j.data);
317  if (tmp > dist2)
318  dist2 = tmp;
319  }
320  nd[rs[0]].data.delta = std::sqrt(dist2);
321  nd[rs[0]].data.nearestHigher = nearestHigher;
322 
323  // now we save the largest distance as a starting point
324  const double max_dist2 = dist2;
325  const unsigned int nd_size = nd.size();
326 
327  for (unsigned int oi = 1; oi < nd_size;
328  ++oi) { // start from second-highest density
329  dist2 = max_dist2;
330  unsigned int i = rs[oi];
331  // we only need to check up to oi since hits
332  // are ordered by decreasing density
333  // and all points coming BEFORE oi are guaranteed to have higher rho
334  // and the ones AFTER to have lower rho
335  for (unsigned int oj = 0; oj < oi; ++oj) {
336  unsigned int j = rs[oj];
337  // Limit the search box
338  if ((nd[i].data.x - nd[j].data.x)*(nd[i].data.x - nd[j].data.x) > dist2) continue;
339  if ((nd[i].data.y - nd[j].data.y)*(nd[i].data.y - nd[j].data.y) > dist2) continue;
340  double tmp = distance2(nd[i].data, nd[j].data);
341  if (tmp <= dist2) { // this "<=" instead of "<" addresses the (rare) case
342  // when there are only two hits
343  dist2 = tmp;
344  nearestHigher = j;
345  }
346  }
347  nd[i].data.delta = std::sqrt(dist2);
348  nd[i].data.nearestHigher =
349  nearestHigher; // this uses the original unsorted hitlist
350  }
351  return maxdensity;
352 }
354  std::vector<KDNode> &nd, KDTree &lp, double maxdensity, KDTreeBox &bounds,
355  const unsigned int layer,
356  std::vector<std::vector<KDNode>> &clustersOnLayer) const {
357 
358  // this is called once per layer and endcap...
359  // so when filling the cluster temporary vector of Hexels we resize each time
360  // by the number of clusters found. This is always equal to the number of
361  // cluster centers...
362 
363  unsigned int nClustersOnLayer = 0;
364  float delta_c; // critical distance
365  if (layer <= lastLayerEE)
366  delta_c = vecDeltas_[0];
367  else if (layer <= lastLayerFH)
368  delta_c = vecDeltas_[1];
369  else
370  delta_c = vecDeltas_[2];
371 
372  std::vector<size_t> rs =
373  sorted_indices(nd); // indices sorted by decreasing rho
374  std::vector<size_t> ds =
375  sort_by_delta(nd); // sort in decreasing distance to higher
376 
377  const unsigned int nd_size = nd.size();
378  for (unsigned int i = 0; i < nd_size; ++i) {
379 
380  if (nd[ds[i]].data.delta < delta_c)
381  break; // no more cluster centers to be looked at
382  if (dependSensor_) {
383 
384  float rho_c = kappa_ * nd[ds[i]].data.sigmaNoise;
385  if (nd[ds[i]].data.rho < rho_c)
386  continue; // set equal to kappa times noise threshold
387 
388  } else if (nd[ds[i]].data.rho * kappa_ < maxdensity)
389  continue;
390 
391  nd[ds[i]].data.clusterIndex = nClustersOnLayer;
392  if (verbosity_ < pINFO) {
393  std::cout << "Adding new cluster with index " << nClustersOnLayer
394  << std::endl;
395  std::cout << "Cluster center is hit " << ds[i] << std::endl;
396  }
397  nClustersOnLayer++;
398  }
399 
400  // at this point nClustersOnLayer is equal to the number of cluster centers -
401  // if it is zero we are done
402  if (nClustersOnLayer == 0)
403  return nClustersOnLayer;
404 
405  // assign remaining points to clusters, using the nearestHigher set from
406  // previous step (always set except
407  // for top density hit that is skipped...)
408  for (unsigned int oi = 1; oi < nd_size; ++oi) {
409  unsigned int i = rs[oi];
410  int ci = nd[i].data.clusterIndex;
411  if (ci ==
412  -1) { // clusterIndex is initialised with -1 if not yet used in cluster
413  nd[i].data.clusterIndex = nd[nd[i].data.nearestHigher].data.clusterIndex;
414  }
415  }
416 
417  // make room in the temporary cluster vector for the additional clusterIndex
418  // clusters
419  // from this layer
420  if (verbosity_ < pINFO) {
421  std::cout << "resizing cluster vector by " << nClustersOnLayer << std::endl;
422  }
423  clustersOnLayer.resize(nClustersOnLayer);
424 
425  // assign points closer than dc to other clusters to border region
426  // and find critical border density
427  std::vector<double> rho_b(nClustersOnLayer, 0.);
428  lp.clear();
429  lp.build(nd, bounds);
430  // now loop on all hits again :( and check: if there are hits from another
431  // cluster within d_c -> flag as border hit
432  for (unsigned int i = 0; i < nd_size; ++i) {
433  int ci = nd[i].data.clusterIndex;
434  bool flag_isolated = true;
435  if (ci != -1) {
436  KDTreeBox search_box(nd[i].dims[0] - delta_c, nd[i].dims[0] + delta_c,
437  nd[i].dims[1] - delta_c, nd[i].dims[1] + delta_c);
438  std::vector<KDNode> found;
439  lp.search(search_box, found);
440 
441  const unsigned int found_size = found.size();
442  for (unsigned int j = 0; j < found_size;
443  j++) { // start from 0 here instead of 1
444  // check if the hit is not within d_c of another cluster
445  if (found[j].data.clusterIndex != -1) {
446  float dist = distance(found[j].data, nd[i].data);
447  if (dist < delta_c && found[j].data.clusterIndex != ci) {
448  // in which case we assign it to the border
449  nd[i].data.isBorder = true;
450  break;
451  }
452  // because we are using two different containers, we have to make sure
453  // that we don't unflag the
454  // hit when it finds *itself* closer than delta_c
455  if (dist < delta_c && dist != 0. &&
456  found[j].data.clusterIndex == ci) {
457  // in this case it is not an isolated hit
458  // the dist!=0 is because the hit being looked at is also inside the
459  // search box and at dist==0
460  flag_isolated = false;
461  }
462  }
463  }
464  if (flag_isolated)
465  nd[i].data.isBorder =
466  true; // the hit is more than delta_c from any of its brethren
467  }
468  // check if this border hit has density larger than the current rho_b and
469  // update
470  if (nd[i].data.isBorder && rho_b[ci] < nd[i].data.rho)
471  rho_b[ci] = nd[i].data.rho;
472  } // end loop all hits
473 
474  // flag points in cluster with density < rho_b as halo points, then fill the
475  // cluster vector
476  for (unsigned int i = 0; i < nd_size; ++i) {
477  int ci = nd[i].data.clusterIndex;
478  if (ci != -1) {
479  if (nd[i].data.rho <= rho_b[ci])
480  nd[i].data.isHalo = true;
481  clustersOnLayer[ci].push_back(nd[i]);
482  if (verbosity_ < pINFO) {
483  std::cout << "Pushing hit " << i << " into cluster with index " << ci
484  << std::endl;
485  }
486  }
487  }
488 
489  // prepare the offset for the next layer if there is one
490  if (verbosity_ < pINFO) {
491  std::cout << "moving cluster offset by " << nClustersOnLayer << std::endl;
492  }
493  return nClustersOnLayer;
494 }
495 
496 // find local maxima within delta_c, marking the indices in the cluster
497 std::vector<unsigned>
498 HGCalImagingAlgo::findLocalMaximaInCluster(const std::vector<KDNode> &cluster) {
499  std::vector<unsigned> result;
500  std::vector<bool> seed(cluster.size(), true);
501  float delta_c = 2.;
502 
503  for (unsigned i = 0; i < cluster.size(); ++i) {
504  for (unsigned j = 0; j < cluster.size(); ++j) {
505  if (i != j and distance(cluster[i].data, cluster[j].data) < delta_c) {
506  if (cluster[i].data.weight < cluster[j].data.weight) {
507  seed[i] = false;
508  break;
509  }
510  }
511  }
512  }
513 
514  for (unsigned i = 0; i < cluster.size(); ++i) {
515  if (seed[i] && cluster[i].data.weight > 5e-4) {
516  // seed at i with energy cluster[i].weight
517  result.push_back(i);
518  }
519  }
520 
521  // Found result.size() sub-clusters in input cluster of length cluster.size()
522 
523  return result;
524 }
525 
527  const std::vector<KDNode> &hits, const std::vector<double> &fractions) {
528  double norm(0.0), x(0.0), y(0.0), z(0.0);
529  for (unsigned i = 0; i < hits.size(); ++i) {
530  const double weight = fractions[i] * hits[i].data.weight;
531  norm += weight;
532  x += weight * hits[i].data.x;
533  y += weight * hits[i].data.y;
534  z += weight * hits[i].data.z;
535  }
536  math::XYZPoint result(x, y, z);
537  result /= norm;
538  return result;
539 }
540 
542  const std::vector<KDNode> &hits, const std::vector<double> &fractions) {
543  double result = 0.0;
544  for (unsigned i = 0; i < hits.size(); ++i) {
545  result += fractions[i] * hits[i].data.weight;
546  }
547  return result;
548 }
549 
551  const std::vector<KDNode> &incluster, const std::vector<unsigned> &seeds,
552  std::vector<std::vector<double>> &outclusters) {
553  std::vector<bool> isaseed(incluster.size(), false);
554  outclusters.clear();
555  outclusters.resize(seeds.size());
556  std::vector<Point> centroids(seeds.size());
557  std::vector<double> energies(seeds.size());
558 
559  if (seeds.size() == 1) { // short circuit the case of a lone cluster
560  outclusters[0].clear();
561  outclusters[0].resize(incluster.size(), 1.0);
562  return;
563  }
564 
565  // saving seeds
566 
567  // create quick seed lookup
568  for (unsigned i = 0; i < seeds.size(); ++i) {
569  isaseed[seeds[i]] = true;
570  }
571 
572  // initialize clusters to be shared
573  // centroids start off at seed positions
574  // seeds always have fraction 1.0, to stabilize fit
575  // initializing fit
576  for (unsigned i = 0; i < seeds.size(); ++i) {
577  outclusters[i].resize(incluster.size(), 0.0);
578  for (unsigned j = 0; j < incluster.size(); ++j) {
579  if (j == seeds[i]) {
580  outclusters[i][j] = 1.0;
581  centroids[i] = math::XYZPoint(incluster[j].data.x, incluster[j].data.y,
582  incluster[j].data.z);
583  energies[i] = incluster[j].data.weight;
584  }
585  }
586  }
587 
588  // run the fit while we are less than max iterations, and clusters are still
589  // moving
590  const double minFracTot = 1e-20;
591  unsigned iter = 0;
592  const unsigned iterMax = 50;
594  const double stoppingTolerance = 1e-8;
595  const auto numberOfSeeds = seeds.size();
596  auto toleranceScaling =
597  numberOfSeeds > 2 ? (numberOfSeeds - 1) * (numberOfSeeds - 1) : 1;
598  std::vector<Point> prevCentroids;
599  std::vector<double> frac(numberOfSeeds), dist2(numberOfSeeds);
600  while (iter++ < iterMax && diff > stoppingTolerance * toleranceScaling) {
601  for (unsigned i = 0; i < incluster.size(); ++i) {
602  const Hexel &ihit = incluster[i].data;
603  double fracTot(0.0);
604  for (unsigned j = 0; j < numberOfSeeds; ++j) {
605  double fraction = 0.0;
606  double d2 = (std::pow(ihit.x - centroids[j].x(), 2.0) +
607  std::pow(ihit.y - centroids[j].y(), 2.0) +
608  std::pow(ihit.z - centroids[j].z(), 2.0)) /
609  sigma2_;
610  dist2[j] = d2;
611  // now we set the fractions up based on hit type
612  if (i == seeds[j]) { // this cluster's seed
613  fraction = 1.0;
614  } else if (isaseed[i]) {
615  fraction = 0.0;
616  } else {
617  fraction = energies[j] * std::exp(-0.5 * d2);
618  }
619  fracTot += fraction;
620  frac[j] = fraction;
621  }
622  // now that we have calculated all fractions for all hits
623  // assign the new fractions
624  for (unsigned j = 0; j < numberOfSeeds; ++j) {
625  if (fracTot > minFracTot || (i == seeds[j] && fracTot > 0.0)) {
626  outclusters[j][i] = frac[j] / fracTot;
627  } else {
628  outclusters[j][i] = 0.0;
629  }
630  }
631  }
632 
633  // save previous centroids
634  prevCentroids = std::move(centroids);
635  // finally update the position of the centroids from the last iteration
636  centroids.resize(numberOfSeeds);
637  double diff2 = 0.0;
638  for (unsigned i = 0; i < numberOfSeeds; ++i) {
639  centroids[i] = calculatePositionWithFraction(incluster, outclusters[i]);
640  energies[i] = calculateEnergyWithFraction(incluster, outclusters[i]);
641  // calculate convergence parameters
642  const double delta2 = (prevCentroids[i] - centroids[i]).perp2();
643  diff2 = std::max(delta2, diff2);
644  }
645  // update convergance parameter outside loop
646  diff = std::sqrt(diff2);
647  }
648 }
649 
651  // To support the TDR geometry and also the post-TDR one (v9 onwards), we
652  // need to change the logic of the vectors containing signal to noise and
653  // thresholds. The first 3 indices will keep on addressing the different
654  // thicknesses of the Silicon detectors, while the last one, number 3 (the
655  // fourth) will address the Scintillators. This change will support both
656  // geometries at the same time.
657 
658  if (initialized_)
659  return; // only need to calculate thresholds once
660 
661  initialized_ = true;
662 
663  std::vector<double> dummy;
664  const unsigned maxNumberOfThickIndices = 3;
665  dummy.resize(maxNumberOfThickIndices + 1, 0); // +1 to accomodate for the Scintillators
666  thresholds_.resize(maxlayer, dummy);
667  sigmaNoise_.resize(maxlayer, dummy);
668 
669  for (unsigned ilayer = 1; ilayer <= maxlayer; ++ilayer) {
670  for (unsigned ithick = 0; ithick < maxNumberOfThickIndices; ++ithick) {
671  float sigmaNoise =
672  0.001f * fcPerEle_ * nonAgedNoises_[ithick] * dEdXweights_[ilayer] /
673  (fcPerMip_[ithick] * thicknessCorrection_[ithick]);
674  thresholds_[ilayer - 1][ithick] = sigmaNoise * ecut_;
675  sigmaNoise_[ilayer - 1][ithick] = sigmaNoise;
676  }
677  float scintillators_sigmaNoise = 0.001f * noiseMip_ * dEdXweights_[ilayer];
678  thresholds_[ilayer - 1][maxNumberOfThickIndices] = ecut_ * scintillators_sigmaNoise;
679  sigmaNoise_[ilayer -1][maxNumberOfThickIndices] = scintillators_sigmaNoise;
680  }
681 
682 }
683 
684 void HGCalImagingAlgo::setDensity(const std::vector<KDNode> &nd){
685 
686  // for each node calculate local density rho and store it
687  for (auto &i : nd){
688  density_[ i.data.detid ] = i.data.rho ;
689  } // end loop nodes
690 }
691 
692 //Density
694  return density_;
695 }
696 
constexpr float energy() const
Definition: CaloRecHit.h:31
double calculateEnergyWithFraction(const std::vector< KDNode > &, const std::vector< double > &)
math::XYZPoint calculatePositionWithFraction(const std::vector< KDNode > &, const std::vector< double > &)
double calculateLocalDensity(std::vector< KDNode > &, KDTree &, const unsigned int) const
constexpr const DetId & detid() const
Definition: CaloRecHit.h:35
Definition: weight.py:1
std::vector< reco::BasicCluster > getClusters(bool) override
void makeClusters() override
hgcal_clustering::Density Density
Definition: HGCalCLUEAlgo.h:29
void shareEnergy(const std::vector< KDNode > &, const std::vector< unsigned > &, std::vector< std::vector< double > > &)
std::pair< double, double > calculatePosition(TVirtualPad *myPad, int boundary)
T sqrt(T t)
Definition: SSEVec.h:18
std::vector< size_t > sorted_indices(const std::vector< T > &v)
void search(const KDTreeBox &searchBox, std::vector< DATA > &resRecHitList)
T min(T a, T b)
Definition: MathUtil.h:58
void setDensity(const std::vector< KDNode > &nd)
std::vector< unsigned > findLocalMaximaInCluster(const std::vector< KDNode > &)
Density getDensity() override
void populate(const HGCRecHitCollection &hits) override
void build(std::vector< KDTreeNodeInfo< DATA > > &eltList, const KDTreeBox &region)
Definition: DetId.h:18
XYZPointD XYZPoint
point in space with cartesian internal representation
Definition: Point3D.h:12
T perp2() const
Squared magnitude of transverse component.
std::vector< std::vector< double > > tmp
Definition: MVATrainer.cc:100
char data[epos_bytes_allocation]
Definition: EPOS_Wrapper.h:82
size_type size() const
double calculateDistanceToHigher(std::vector< KDNode > &) const
Structure Point Contains parameters of Gaussian fits to DMRs.
Definition: DMRtrends.cc:55
static int position[264][3]
Definition: ReadPGInfo.cc:509
math::XYZPoint calculatePosition(std::vector< KDNode > &) const
size_t max_index(const std::vector< T > &v)
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:40
def move(src, dest)
Definition: eostools.py:511
int findAndAssignClusters(std::vector< KDNode > &, KDTree &, double, KDTreeBox &, const unsigned int, std::vector< std::vector< KDNode > > &) const