CMS 3D CMS Logo

PFlow2DClusterizerWithTime.cc
Go to the documentation of this file.
10 
11 #include "Math/GenVector/VectorUtil.h"
12 #include "TMath.h"
13 #include "vdt/vdtMath.h"
14 
15 #include <iterator>
16 #include <unordered_map>
17 
20 
21 public:
23 
24  ~PFlow2DClusterizerWithTime() override = default;
25  PFlow2DClusterizerWithTime(const B2DGPF&) = delete;
26  B2DGPF& operator=(const B2DGPF&) = delete;
27 
28  void update(const edm::EventSetup& es) override {
29  _positionCalc->update(es);
30  if (_allCellsPosCalc)
31  _allCellsPosCalc->update(es);
33  _convergencePosCalc->update(es);
34  }
35 
37  const std::vector<bool>&,
39  const HcalPFCuts*) override;
40 
41 private:
42  const unsigned _maxIterations;
43  const double _stoppingTolerance;
44  const double _showerSigma2;
45  const double _timeSigma_eb;
46  const double _timeSigma_ee;
47  const bool _excludeOtherSeeds;
48  const double _minFracTot;
49  const double _maxNSigmaTime;
50  const double _minChi2Prob;
52 
53  const std::unordered_map<std::string, int> _layerMap;
54  std::unordered_map<int, double> _recHitEnergyNorms;
55  std::unique_ptr<PFCPositionCalculatorBase> _allCellsPosCalc;
56  std::unique_ptr<PFCPositionCalculatorBase> _convergencePosCalc;
57 
58  std::unique_ptr<CaloRecHitResolutionProvider> _timeResolutionCalcBarrel;
59  std::unique_ptr<CaloRecHitResolutionProvider> _timeResolutionCalcEndcap;
60 
62  const std::vector<bool>&,
64  const HcalPFCuts*) const;
65 
66  void growPFClusters(const reco::PFCluster&,
67  const std::vector<bool>&,
68  const unsigned toleranceScaling,
69  const unsigned iter,
70  double dist,
72  const HcalPFCuts* hcalCuts) const;
73  void clusterTimeResolution(reco::PFCluster& cluster, double& res) const;
74  void clusterTimeResolutionFromSeed(reco::PFCluster& cluster, double& res) const;
75  double dist2Time(const reco::PFCluster&, const reco::PFRecHitRef&, int cell_layer, double prev_timeres2) const;
76  bool passChi2Prob(size_t iCluster,
77  double dist2,
78  std::vector<double>& clus_chi2,
79  std::vector<size_t>& clus_chi2_nhits) const;
81 };
82 
84 
85 #ifdef PFLOW_DEBUG
86 #define LOGVERB(x) edm::LogVerbatim(x)
87 #define LOGWARN(x) edm::LogWarning(x)
88 #define LOGERR(x) edm::LogError(x)
89 #define LOGDRESSED(x) edm::LogInfo(x)
90 #else
91 #define LOGVERB(x) LogTrace(x)
92 #define LOGWARN(x) edm::LogWarning(x)
93 #define LOGERR(x) edm::LogError(x)
94 #define LOGDRESSED(x) LogDebug(x)
95 #endif
96 
98  : PFClusterBuilderBase(conf, cc),
99  _maxIterations(conf.getParameter<unsigned>("maxIterations")),
100  _stoppingTolerance(conf.getParameter<double>("stoppingTolerance")),
101  _showerSigma2(std::pow(conf.getParameter<double>("showerSigma"), 2.0)),
102  _timeSigma_eb(std::pow(conf.getParameter<double>("timeSigmaEB"), 2.0)),
103  _timeSigma_ee(std::pow(conf.getParameter<double>("timeSigmaEE"), 2.0)),
104  _excludeOtherSeeds(conf.getParameter<bool>("excludeOtherSeeds")),
105  _minFracTot(conf.getParameter<double>("minFracTot")),
106  _maxNSigmaTime(std::pow(conf.getParameter<double>("maxNSigmaTime"), 2.0)),
107  _minChi2Prob(conf.getParameter<double>("minChi2Prob")),
108  _clusterTimeResFromSeed(conf.getParameter<bool>("clusterTimeResFromSeed")),
109 
110  _layerMap({{"PS2", (int)PFLayer::PS2},
111  {"PS1", (int)PFLayer::PS1},
112  {"ECAL_ENDCAP", (int)PFLayer::ECAL_ENDCAP},
113  {"ECAL_BARREL", (int)PFLayer::ECAL_BARREL},
114  {"NONE", (int)PFLayer::NONE},
115  {"HCAL_BARREL1", (int)PFLayer::HCAL_BARREL1},
116  {"HCAL_BARREL2_RING0", (int)PFLayer::HCAL_BARREL2},
117  {"HCAL_BARREL2_RING1", 100 * (int)PFLayer::HCAL_BARREL2},
118  {"HCAL_ENDCAP", (int)PFLayer::HCAL_ENDCAP},
119  {"HF_EM", (int)PFLayer::HF_EM},
120  {"HF_HAD", (int)PFLayer::HF_HAD}}) {
121  const std::vector<edm::ParameterSet>& thresholds = conf.getParameterSetVector("recHitEnergyNorms");
122  for (const auto& pset : thresholds) {
123  const std::string& det = pset.getParameter<std::string>("detector");
124  const double& rhE_norm = pset.getParameter<double>("recHitEnergyNorm");
125  auto entry = _layerMap.find(det);
126  if (entry == _layerMap.end()) {
127  throw cms::Exception("InvalidDetectorLayer") << "Detector layer : " << det << " is not in the list of recognized"
128  << " detector layers!";
129  }
130  _recHitEnergyNorms.emplace(_layerMap.find(det)->second, rhE_norm);
131  }
132 
133  const auto& acConf = conf.getParameterSet("allCellsPositionCalc");
134  if (!acConf.empty()) {
135  const std::string& algoac = acConf.getParameter<std::string>("algoName");
136  if (!algoac.empty())
137  _allCellsPosCalc = PFCPositionCalculatorFactory::get()->create(algoac, acConf, cc);
138  }
139  // if necessary a third pos calc for convergence testing
140  const auto& convConf = conf.getParameterSet("positionCalcForConvergence");
141  if (!convConf.empty()) {
142  const std::string& algoconv = convConf.getParameter<std::string>("algoName");
143  if (!algoconv.empty())
144  _convergencePosCalc = PFCPositionCalculatorFactory::get()->create(algoconv, convConf, cc);
145  }
146  const auto& timeResConfBarrel = conf.getParameterSet("timeResolutionCalcBarrel");
147  if (!timeResConfBarrel.empty())
148  _timeResolutionCalcBarrel = std::make_unique<CaloRecHitResolutionProvider>(timeResConfBarrel);
149  const auto& timeResConfEndcap = conf.getParameterSet("timeResolutionCalcEndcap");
150  if (!timeResConfEndcap.empty())
151  _timeResolutionCalcEndcap = std::make_unique<CaloRecHitResolutionProvider>(timeResConfEndcap);
152 }
153 
155  const std::vector<bool>& seedable,
157  const HcalPFCuts* hcalCuts) {
158  reco::PFClusterCollection clustersInTopo;
159  for (const auto& topocluster : input) {
160  clustersInTopo.clear();
161  seedPFClustersFromTopo(topocluster, seedable, clustersInTopo, hcalCuts);
162  const unsigned tolScal = std::pow(std::max(1.0, clustersInTopo.size() - 1.0), 2.0);
163  growPFClusters(topocluster, seedable, tolScal, 0, tolScal, clustersInTopo, hcalCuts);
164  // step added by Josh Bendavid, removes low-fraction clusters
165  // did not impact position resolution with fraction cut of 1e-7
166  // decreases the size of each pf cluster considerably
167  prunePFClusters(clustersInTopo);
168  // recalculate the positions of the pruned clusters
169  if (_convergencePosCalc) {
170  // if defined, use the special position calculation for convergence tests
171  _convergencePosCalc->calculateAndSetPositions(clustersInTopo, hcalCuts);
172  } else {
173  if (clustersInTopo.size() == 1 && _allCellsPosCalc) {
174  _allCellsPosCalc->calculateAndSetPosition(clustersInTopo.back(), hcalCuts);
175  } else {
176  _positionCalc->calculateAndSetPositions(clustersInTopo, hcalCuts);
177  }
178  }
179  for (auto& clusterout : clustersInTopo) {
180  output.insert(output.end(), std::move(clusterout));
181  }
182  }
183 }
184 
186  const std::vector<bool>& seedable,
187  reco::PFClusterCollection& initialPFClusters,
188  const HcalPFCuts* hcalCuts) const {
189  const auto& recHitFractions = topo.recHitFractions();
190  for (const auto& rhf : recHitFractions) {
191  if (!seedable[rhf.recHitRef().key()])
192  continue;
193  initialPFClusters.push_back(reco::PFCluster());
194  reco::PFCluster& current = initialPFClusters.back();
195  current.addRecHitFraction(rhf);
196  current.setSeed(rhf.recHitRef()->detId());
197  if (_convergencePosCalc) {
198  _convergencePosCalc->calculateAndSetPosition(current, hcalCuts);
199  } else {
200  _positionCalc->calculateAndSetPosition(current, hcalCuts);
201  }
202  }
203 }
204 
206  const std::vector<bool>& seedable,
207  const unsigned toleranceScaling,
208  const unsigned iter,
209  double diff,
211  const HcalPFCuts* hcalCuts) const {
212  if (iter >= _maxIterations) {
213  LOGDRESSED("PFlow2DClusterizerWithTime:growAndStabilizePFClusters")
214  << "reached " << _maxIterations << " iterations, terminated position "
215  << "fit with diff = " << diff;
216  }
217  if (iter >= _maxIterations || diff <= _stoppingTolerance * toleranceScaling)
218  return;
219  // reset the rechits in this cluster, keeping the previous position
220  std::vector<reco::PFCluster::REPPoint> clus_prev_pos;
221  // also calculate and keep the previous time resolution
222  std::vector<double> clus_prev_timeres2;
223 
224  for (auto& cluster : clusters) {
225  const reco::PFCluster::REPPoint& repp = cluster.positionREP();
226  clus_prev_pos.emplace_back(repp.rho(), repp.eta(), repp.phi());
227  if (_convergencePosCalc) {
228  if (clusters.size() == 1 && _allCellsPosCalc) {
229  _allCellsPosCalc->calculateAndSetPosition(cluster, hcalCuts);
230  } else {
231  _positionCalc->calculateAndSetPosition(cluster, hcalCuts);
232  }
233  }
234  double resCluster2;
236  clusterTimeResolutionFromSeed(cluster, resCluster2);
237  else
238  clusterTimeResolution(cluster, resCluster2);
239  clus_prev_timeres2.push_back(resCluster2);
240  cluster.resetHitsAndFractions();
241  }
242  // loop over topo cluster and grow current PFCluster hypothesis
243  std::vector<double> dist2, frac;
244 
245  // Store chi2 values and nhits to calculate chi2 prob. inline
246  std::vector<double> clus_chi2;
247  std::vector<size_t> clus_chi2_nhits;
248 
249  double fractot = 0;
250  for (const reco::PFRecHitFraction& rhf : topo.recHitFractions()) {
251  const reco::PFRecHitRef& refhit = rhf.recHitRef();
252  int cell_layer = (int)refhit->layer();
253  if (cell_layer == PFLayer::HCAL_BARREL2 && std::abs(refhit->positionREP().eta()) > 0.34) {
254  cell_layer *= 100;
255  }
256  double recHitEnergyNorm = _recHitEnergyNorms.find(cell_layer)->second;
257  if (hcalCuts != nullptr) { // this means, cutsFromDB is set to True in the producer code
258  if ((cell_layer == PFLayer::HCAL_BARREL1) || (cell_layer == PFLayer::HCAL_ENDCAP)) {
259  HcalDetId thisId = refhit->detId();
260  const HcalPFCut* item = hcalCuts->getValues(thisId.rawId());
261  recHitEnergyNorm = item->noiseThreshold();
262  }
263  }
264 
265  math::XYZPoint topocellpos_xyz(refhit->position());
266  dist2.clear();
267  frac.clear();
268  fractot = 0;
269 
270  // add rechits to clusters, calculating fraction based on distance
271  // need position in vector to get cluster time resolution
272  for (size_t iCluster = 0; iCluster < clusters.size(); ++iCluster) {
273  reco::PFCluster& cluster = clusters[iCluster];
274  const math::XYZPoint& clusterpos_xyz = cluster.position();
275  const math::XYZVector deltav = clusterpos_xyz - topocellpos_xyz;
276  double d2 = deltav.Mag2() / _showerSigma2;
277 
278  double d2time = dist2Time(cluster, refhit, cell_layer, clus_prev_timeres2[iCluster]);
279  d2 += d2time;
280 
281  if (_minChi2Prob > 0. && !passChi2Prob(iCluster, d2time, clus_chi2, clus_chi2_nhits))
282  d2 = 999.;
283 
284  dist2.emplace_back(d2);
285 
286  if (d2 > 100) {
287  LOGDRESSED("PFlow2DClusterizerWithTime:growAndStabilizePFClusters")
288  << "Warning! :: pfcluster-topocell distance is too large! d= " << d2;
289  }
290  // fraction assignment logic
291  double fraction;
292  if (refhit->detId() == cluster.seed() && _excludeOtherSeeds) {
293  fraction = 1.0;
294  } else if (seedable[refhit.key()] && _excludeOtherSeeds) {
295  fraction = 0.0;
296  } else {
297  fraction = cluster.energy() / recHitEnergyNorm * vdt::fast_expf(-0.5 * d2);
298  }
299  fractot += fraction;
300  frac.emplace_back(fraction);
301  }
302  for (unsigned i = 0; i < clusters.size(); ++i) {
303  if (fractot > _minFracTot || (refhit->detId() == clusters[i].seed() && fractot > 0.0)) {
304  frac[i] /= fractot;
305  } else {
306  continue;
307  }
308  // if the fraction has been set to 0, the cell
309  // is now added to the cluster - careful ! (PJ, 19/07/08)
310  // BUT KEEP ONLY CLOSE CELLS OTHERWISE MEMORY JUST EXPLOSES
311  // (PJ, 15/09/08 <- similar to what existed before the
312  // previous bug fix, but keeps the close seeds inside,
313  // even if their fraction was set to zero.)
314  // Also add a protection to keep the seed in the cluster
315  // when the latter gets far from the former. These cases
316  // (about 1% of the clusters) need to be studied, as
317  // they create fake photons, in general.
318  // (PJ, 16/09/08)
319  if (dist2[i] < 100.0 || frac[i] > 0.9999) {
320  clusters[i].addRecHitFraction(reco::PFRecHitFraction(refhit, frac[i]));
321  }
322  }
323  }
324  // recalculate positions and calculate convergence parameter
325  double diff2 = 0.0;
326  for (unsigned i = 0; i < clusters.size(); ++i) {
327  if (_convergencePosCalc) {
328  _convergencePosCalc->calculateAndSetPosition(clusters[i], hcalCuts);
329  } else {
330  if (clusters.size() == 1 && _allCellsPosCalc) {
331  _allCellsPosCalc->calculateAndSetPosition(clusters[i], hcalCuts);
332  } else {
333  _positionCalc->calculateAndSetPosition(clusters[i], hcalCuts);
334  }
335  }
336  const double delta2 = reco::deltaR2(clusters[i].positionREP(), clus_prev_pos[i]);
337  if (delta2 > diff2)
338  diff2 = delta2;
339  }
340  diff = std::sqrt(diff2);
341  dist2.clear();
342  frac.clear();
343  clus_prev_pos.clear(); // avoid badness
344  clus_chi2.clear();
345  clus_chi2_nhits.clear();
346  clus_prev_timeres2.clear();
347  growPFClusters(topo, seedable, toleranceScaling, iter + 1, diff, clusters, hcalCuts);
348 }
349 
351  for (auto& cluster : clusters) {
352  cluster.pruneUsing([&](const reco::PFRecHitFraction& rhf) { return rhf.fraction() > _minFractionToKeep; });
353  }
354 }
355 
357  clusterRes2 = 10000.;
358  for (auto& rhf : cluster.recHitFractions()) {
359  const reco::PFRecHit& rh = *(rhf.recHitRef());
360  if (rh.detId() == cluster.seed()) {
361  cluster.setTime(rh.time());
362  bool isBarrel = (rh.layer() == PFLayer::HCAL_BARREL1 || rh.layer() == PFLayer::HCAL_BARREL2 ||
363  rh.layer() == PFLayer::ECAL_BARREL);
364  if (isBarrel)
365  clusterRes2 = _timeResolutionCalcBarrel->timeResolution2(rh.energy());
366  else
367  clusterRes2 = _timeResolutionCalcEndcap->timeResolution2(rh.energy());
368  cluster.setTimeError(std::sqrt(float(clusterRes2)));
369  }
370  }
371 }
372 
373 void PFlow2DClusterizerWithTime::clusterTimeResolution(reco::PFCluster& cluster, double& clusterRes2) const {
374  double sumTimeSigma2 = 0.;
375  double sumSigma2 = 0.;
376 
377  for (auto& rhf : cluster.recHitFractions()) {
378  const reco::PFRecHit& rh = *(rhf.recHitRef());
379  const double rhf_f = rhf.fraction();
380 
381  if (rhf_f == 0.)
382  continue;
383 
384  bool isBarrel = (rh.layer() == PFLayer::HCAL_BARREL1 || rh.layer() == PFLayer::HCAL_BARREL2 ||
385  rh.layer() == PFLayer::ECAL_BARREL);
386  double res2 = 10000.;
387  if (isBarrel)
388  res2 = _timeResolutionCalcBarrel->timeResolution2(rh.energy());
389  else
390  res2 = _timeResolutionCalcEndcap->timeResolution2(rh.energy());
391 
392  sumTimeSigma2 += rhf_f * rh.time() / res2;
393  sumSigma2 += rhf_f / res2;
394  }
395  if (sumSigma2 > 0.) {
396  clusterRes2 = 1. / sumSigma2;
397  cluster.setTime(sumTimeSigma2 / sumSigma2);
398  cluster.setTimeError(std::sqrt(float(clusterRes2)));
399  } else {
400  clusterRes2 = 999999.;
401  }
402 }
403 
405  const reco::PFRecHitRef& refhit,
406  int cell_layer,
407  double prev_timeres2) const {
408  const double deltaT = cluster.time() - refhit->time();
409  const double t2 = deltaT * deltaT;
410  double res2 = 100.;
411 
412  if (cell_layer == PFLayer::HCAL_BARREL1 || cell_layer == PFLayer::HCAL_BARREL2 ||
413  cell_layer == PFLayer::ECAL_BARREL) {
415  const double resCluster2 = prev_timeres2;
416  res2 = resCluster2 + _timeResolutionCalcBarrel->timeResolution2(refhit->energy());
417  } else {
418  return t2 / _timeSigma_eb;
419  }
420  } else if (cell_layer == PFLayer::HCAL_ENDCAP || cell_layer == PFLayer::HF_EM || cell_layer == PFLayer::HF_HAD ||
421  cell_layer == PFLayer::ECAL_ENDCAP) {
423  const double resCluster2 = prev_timeres2;
424  res2 = resCluster2 + _timeResolutionCalcEndcap->timeResolution2(refhit->energy());
425  } else {
426  return t2 / _timeSigma_ee;
427  }
428  }
429 
430  double distTime2 = t2 / res2;
431  if (distTime2 > _maxNSigmaTime)
432  return 999.; // reject hit
433 
434  return distTime2;
435 }
436 
438  double dist2,
439  std::vector<double>& clus_chi2,
440  std::vector<size_t>& clus_chi2_nhits) const {
441  if (iCluster >= clus_chi2.size()) { // first hit
442  clus_chi2.push_back(dist2);
443  clus_chi2_nhits.push_back(1);
444  return true;
445  } else {
446  double chi2 = clus_chi2[iCluster];
447  size_t nhitsCluster = clus_chi2_nhits[iCluster];
448  chi2 += dist2;
449  if (TMath::Prob(chi2, nhitsCluster) >= _minChi2Prob) {
450  clus_chi2[iCluster] = chi2;
451  clus_chi2_nhits[iCluster] = nhitsCluster + 1;
452  return true;
453  }
454  }
455  return false;
456 }
const math::XYZPoint & position() const
cluster centroid position
Definition: CaloCluster.h:154
void update(const edm::EventSetup &es) override
void seedPFClustersFromTopo(const reco::PFCluster &, const std::vector< bool > &, reco::PFClusterCollection &, const HcalPFCuts *) const
Particle flow cluster, see clustering algorithm in PFClusterAlgo.
Definition: PFCluster.h:42
std::unique_ptr< PFCPositionCalculatorBase > _allCellsPosCalc
uint32_t cc[maxCellsPerHit]
Definition: gpuFishbone.h:49
void clusterTimeResolution(reco::PFCluster &cluster, double &res) const
std::unique_ptr< PosCalc > _positionCalc
DetId seed() const
return DetId of seed
Definition: CaloCluster.h:219
const std::unordered_map< std::string, int > _layerMap
void setTime(float time, float timeError=0)
Definition: PFCluster.h:84
PFLayer::Layer layer() const
rechit layer
Definition: PFRecHit.h:96
Fraction of a PFRecHit (rechits can be shared between several PFCluster&#39;s)
const std::vector< reco::PFRecHitFraction > & recHitFractions() const
vector of rechit fractions
Definition: PFCluster.h:65
#define LOGDRESSED(x)
float time() const
timing for cleaned hits
Definition: PFRecHit.h:102
~PFlow2DClusterizerWithTime() override=default
key_type key() const
Accessor for product key.
Definition: Ref.h:250
Definition: Electron.h:6
const Item * getValues(DetId fId, bool throwOnFail=true) const
static std::string const input
Definition: EdmProvDump.cc:50
void setSeed(const DetId &id)
Definition: CaloCluster.h:146
float time() const
Definition: PFCluster.h:77
unsigned detId() const
rechit detId
Definition: PFRecHit.h:93
Particle flow rechit (rechit + geometry and topology information). See clustering algorithm in PFClus...
Definition: PFRecHit.h:31
T sqrt(T t)
Definition: SSEVec.h:23
double energy() const
cluster energy
Definition: PFCluster.h:74
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
PFlow2DClusterizerWithTime B2DGPF
void setTimeError(float timeError)
Definition: PFCluster.h:88
constexpr auto deltaR2(const T1 &t1, const T2 &t2) -> decltype(t1.eta())
Definition: deltaR.h:16
B2DGPF & operator=(const B2DGPF &)=delete
std::unique_ptr< CaloRecHitResolutionProvider > _timeResolutionCalcBarrel
std::unique_ptr< CaloRecHitResolutionProvider > _timeResolutionCalcEndcap
PFlow2DClusterizerWithTime(const edm::ParameterSet &conf, edm::ConsumesCollector &cc)
XYZVectorD XYZVector
spatial vector with cartesian internal representation
Definition: Vector3D.h:31
constexpr uint32_t rawId() const
get the raw id
Definition: DetId.h:57
XYZPointD XYZPoint
point in space with cartesian internal representation
Definition: Point3D.h:12
void addRecHitFraction(const reco::PFRecHitFraction &frac)
add a given fraction of the rechit
Definition: PFCluster.cc:33
float energy() const
rechit energy
Definition: PFRecHit.h:99
void buildClusters(const reco::PFClusterCollection &, const std::vector< bool > &, reco::PFClusterCollection &outclus, const HcalPFCuts *) override
double dist2Time(const reco::PFCluster &, const reco::PFRecHitRef &, int cell_layer, double prev_timeres2) const
void clusterTimeResolutionFromSeed(reco::PFCluster &cluster, double &res) const
float fast_expf(float x)
ROOT::Math::PositionVector3D< ROOT::Math::CylindricalEta3D< double > > REPPoint
Definition: PFCluster.h:48
std::vector< PFCluster > PFClusterCollection
collection of PFCluster objects
Definition: PFClusterFwd.h:9
void prunePFClusters(reco::PFClusterCollection &) const
std::unique_ptr< PFCPositionCalculatorBase > _convergencePosCalc
#define DEFINE_EDM_PLUGIN(factory, type, name)
Definition: output.py:1
#define get
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:29
bool passChi2Prob(size_t iCluster, double dist2, std::vector< double > &clus_chi2, std::vector< size_t > &clus_chi2_nhits) const
def move(src, dest)
Definition: eostools.py:511
void growPFClusters(const reco::PFCluster &, const std::vector< bool > &, const unsigned toleranceScaling, const unsigned iter, double dist, reco::PFClusterCollection &, const HcalPFCuts *hcalCuts) const
std::unordered_map< int, double > _recHitEnergyNorms