CMS 3D CMS Logo

PFBlockAlgo.cc
Go to the documentation of this file.
7 
8 #include <algorithm>
9 #include <iostream>
10 #include <array>
11 #include <iterator>
12 #include <sstream>
13 #include <type_traits>
14 #include <utility>
15 
16 using namespace std;
17 using namespace reco;
18 
19 #define INIT_ENTRY(name) \
20  { #name, name }
21 
22 namespace {
23  class QuickUnion {
24  std::vector<unsigned> id_;
25  std::vector<unsigned> size_;
26  int count_;
27 
28  public:
29  QuickUnion(const unsigned NBranches) {
30  count_ = NBranches;
31  id_.resize(NBranches);
32  size_.resize(NBranches);
33  for (unsigned i = 0; i < NBranches; ++i) {
34  id_[i] = i;
35  size_[i] = 1;
36  }
37  }
38 
39  int count() const { return count_; }
40 
41  unsigned find(unsigned p) {
42  while (p != id_[p]) {
43  id_[p] = id_[id_[p]];
44  p = id_[p];
45  }
46  return p;
47  }
48 
49  bool connected(unsigned p, unsigned q) { return find(p) == find(q); }
50 
51  void unite(unsigned p, unsigned q) {
52  unsigned rootP = find(p);
53  unsigned rootQ = find(q);
54  id_[p] = q;
55 
56  if (size_[rootP] < size_[rootQ]) {
57  id_[rootP] = rootQ;
58  size_[rootQ] += size_[rootP];
59  } else {
60  id_[rootQ] = rootP;
61  size_[rootP] += size_[rootQ];
62  }
63  --count_;
64  }
65  };
66 } // namespace
67 
68 //for debug only
69 //#define PFLOW_DEBUG
70 
72  : debug_(false),
73  elementTypes_({INIT_ENTRY(PFBlockElement::TRACK),
74  INIT_ENTRY(PFBlockElement::PS1),
75  INIT_ENTRY(PFBlockElement::PS2),
78  INIT_ENTRY(PFBlockElement::GSF),
79  INIT_ENTRY(PFBlockElement::BREM),
80  INIT_ENTRY(PFBlockElement::HFEM),
81  INIT_ENTRY(PFBlockElement::HFHAD),
82  INIT_ENTRY(PFBlockElement::SC),
84  INIT_ENTRY(PFBlockElement::HGCAL)}) {}
85 
86 void PFBlockAlgo::setLinkers(const std::vector<edm::ParameterSet>& confs) {
87  constexpr unsigned rowsize = reco::PFBlockElement::kNBETypes;
88  for (unsigned i = 0; i < rowsize; ++i) {
89  for (unsigned j = 0; j < rowsize; ++j) {
90  linkTestSquare_[i][j] = 0;
91  }
92  }
93  linkTests_.resize(rowsize * rowsize);
94  const std::string prefix("PFBlockElement::");
95  const std::string pfx_kdtree("KDTree");
96  for (const auto& conf : confs) {
97  const std::string& linkerName = conf.getParameter<std::string>("linkerName");
98  const std::string& linkTypeStr = conf.getParameter<std::string>("linkType");
99  size_t split = linkTypeStr.find(':');
100  if (split == std::string::npos) {
101  throw cms::Exception("MalformedLinkType") << "\"" << linkTypeStr << "\" is not a valid link type definition."
102  << " This string should have the form \"linkFrom:linkTo\"";
103  }
104  std::string link1(prefix + linkTypeStr.substr(0, split));
105  std::string link2(prefix + linkTypeStr.substr(split + 1, std::string::npos));
106  if (!(elementTypes_.count(link1) && elementTypes_.count(link2))) {
107  throw cms::Exception("InvalidBlockElementType")
108  << "One of \"" << link1 << "\" or \"" << link2 << "\" are invalid block element types!";
109  }
110  const PFBlockElement::Type type1 = elementTypes_.at(link1);
111  const PFBlockElement::Type type2 = elementTypes_.at(link2);
112  const unsigned index = rowsize * std::max(type1, type2) + std::min(type1, type2);
114  linkTestSquare_[type1][type2] = index;
115  linkTestSquare_[type2][type1] = index;
116  // setup KDtree if requested
117  const bool useKDTree = conf.getParameter<bool>("useKDTree");
118  if (useKDTree) {
119  kdtrees_.emplace_back(KDTreeLinkerFactory::get()->create(pfx_kdtree + linkerName, conf));
120  kdtrees_.back()->setTargetType(std::min(type1, type2));
121  kdtrees_.back()->setFieldType(std::max(type1, type2));
122  } // useKDTree
123  } // loop over confs
124 }
125 
126 void PFBlockAlgo::setImporters(const std::vector<edm::ParameterSet>& confs, edm::ConsumesCollector& sumes) {
127  importers_.reserve(confs.size());
128  for (const auto& conf : confs) {
129  const std::string& importerName = conf.getParameter<std::string>("importerName");
130  importers_.emplace_back(BlockElementImporterFactory::get()->create(importerName, conf, sumes));
131  }
132 }
133 
135 #ifdef PFLOW_DEBUG
136  if (debug_)
137  cout << "~PFBlockAlgo - number of remaining elements: " << elements_.size() << endl;
138 #endif
139 }
140 
142  // Glowinski & Gouzevitch
143  for (const auto& kdtree : kdtrees_) {
144  kdtree->process();
145  }
146  // !Glowinski & Gouzevitch
148  // the blocks have not been passed to the event, and need to be cleared
149  blocks.reserve(elements_.size());
150 
151  QuickUnion qu(elements_.size());
152  const auto elem_size = elements_.size();
153  for (unsigned i = 0; i < elem_size; ++i) {
154  for (unsigned j = i + 1; j < elem_size; ++j) {
155  if (qu.connected(i, j))
156  continue;
157  if (!linkTests_[linkTestSquare_[elements_[i]->type()][elements_[j]->type()]]) {
158  j = ranges_[elements_[j]->type()].second;
159  continue;
160  }
161  auto p1(elements_[i].get()), p2(elements_[j].get());
162  const PFBlockElement::Type type1 = p1->type();
163  const PFBlockElement::Type type2 = p2->type();
164  const unsigned index = linkTestSquare_[type1][type2];
165  if (linkTests_[index]->linkPrefilter(p1, p2)) {
166  const double dist = linkTests_[index]->testLink(p1, p2);
167  // compute linking info if it is possible
168  if (dist > -0.5) {
169  qu.unite(i, j);
170  }
171  }
172  }
173  }
174 
175  std::unordered_multimap<unsigned, unsigned> blocksmap(elements_.size());
176  std::vector<unsigned> keys;
177  keys.reserve(elements_.size());
178  for (unsigned i = 0; i < elements_.size(); ++i) {
179  unsigned key = i;
180  while (key != qu.find(key))
181  key = qu.find(key); // make sure we always find the root node...
182  auto pos = std::lower_bound(keys.begin(), keys.end(), key);
183  if (pos == keys.end() || *pos != key) {
184  keys.insert(pos, key);
185  }
186  blocksmap.emplace(key, i);
187  }
188 
189  for (auto key : keys) {
190  blocks.push_back(reco::PFBlock());
191  auto range = blocksmap.equal_range(key);
192  auto& the_block = blocks.back();
193  ElementList::value_type::pointer p1(elements_[range.first->second].get());
194  the_block.addElement(p1);
195  const unsigned block_size = blocksmap.count(key) + 1;
196  //reserve up to 1M or 8MB; pay rehash cost for more
197  std::unordered_map<std::pair<unsigned int, unsigned int>, double> links(min(1000000u, block_size * block_size));
198  auto itr = range.first;
199  ++itr;
200  for (; itr != range.second; ++itr) {
201  ElementList::value_type::pointer p2(elements_[itr->second].get());
202  const PFBlockElement::Type type1 = p1->type();
203  const PFBlockElement::Type type2 = p2->type();
204  the_block.addElement(p2);
205  const unsigned index = linkTestSquare_[type1][type2];
206  if (nullptr != linkTests_[index]) {
207  const double dist = linkTests_[index]->testLink(p1, p2);
208  links.emplace(std::make_pair(p1->index(), p2->index()), dist);
209  }
210  }
211  packLinks(the_block, links);
212  }
213 
214  elements_.clear();
215 
216  return blocks;
217 }
218 
220  const std::unordered_map<std::pair<unsigned int, unsigned int>, double>& links) const {
221  constexpr unsigned rowsize = reco::PFBlockElement::kNBETypes;
222 
223  const edm::OwnVector<reco::PFBlockElement>& els = block.elements();
224 
225  block.bookLinkData();
226  unsigned elsize = els.size();
227  //First Loop: update all link data
228  for (unsigned i1 = 0; i1 < elsize; ++i1) {
229  for (unsigned i2 = 0; i2 < i1; ++i2) {
230  // no reflexive link
231  //if( i1==i2 ) continue;
232 
233  double dist = -1;
234 
235  bool linked = false;
236 
237  // are these elements already linked ?
238  // this can be optimized
239  const auto link_itr = links.find(std::make_pair(i2, i1));
240  if (link_itr != links.end()) {
241  dist = link_itr->second;
242  linked = true;
243  }
244 
245  if (!linked) {
246  const PFBlockElement::Type type1 = els[i1].type();
247  const PFBlockElement::Type type2 = els[i2].type();
248  const auto minmax = std::minmax(type1, type2);
249  const unsigned index = rowsize * minmax.second + minmax.first;
250  bool bTestLink =
251  (nullptr == linkTests_[index] ? false : linkTests_[index]->linkPrefilter(&(els[i1]), &(els[i2])));
252  if (bTestLink)
253  link(&els[i1], &els[i2], dist);
254  }
255 
256  //loading link data according to link test used: RECHIT
257  //block.setLink( i1, i2, chi2, block.linkData() );
258  block.setLink(i1, i2, dist, block.linkData());
259  }
260  }
261 }
262 
263 inline void PFBlockAlgo::link(const reco::PFBlockElement* el1, const reco::PFBlockElement* el2, double& dist) const {
264  constexpr unsigned rowsize = reco::PFBlockElement::kNBETypes;
265  dist = -1.0;
266  const PFBlockElement::Type type1 = el1->type();
267  const PFBlockElement::Type type2 = el2->type();
268  const unsigned index = rowsize * std::max(type1, type2) + std::min(type1, type2);
269  if (debug_) {
270  std::cout << " PFBlockAlgo links type1 " << type1 << " type2 " << type2 << std::endl;
271  }
272 
273  // index is always checked in the preFilter above, no need to check here
274  dist = linkTests_[index]->testLink(el1, el2);
275 }
276 
278  for (auto& importer : importers_) {
279  importer->updateEventSetup(es);
280  }
281 }
282 
283 // see plugins/importers and plugins/kdtrees
284 // for the definitions of available block element importers
285 // and kdtree preprocessors
287  // import block elements as defined in python configuration
288  ranges_.fill(std::make_pair(0, 0));
289  elements_.clear();
290  for (const auto& importer : importers_) {
291  importer->importToBlock(evt, elements_);
292  }
293 
294  std::sort(elements_.begin(), elements_.end(), [](const auto& a, const auto& b) { return a->type() < b->type(); });
295 
296  // list is now partitioned, so mark the boundaries so we can efficiently skip chunks
297  unsigned current_type = (!elements_.empty() ? elements_[0]->type() : 0);
298  unsigned last_type = (!elements_.empty() ? elements_.back()->type() : 0);
299  ranges_[current_type].first = 0;
300  ranges_[last_type].second = elements_.size() - 1;
301  for (size_t i = 0; i < elements_.size(); ++i) {
302  const auto the_type = elements_[i]->type();
303  if (the_type != current_type) {
304  ranges_[the_type].first = i;
305  ranges_[current_type].second = i - 1;
306  current_type = the_type;
307  }
308  }
309  // -------------- Loop over block elements ---------------------
310 
311  // Here we provide to all KDTree linkers the collections to link.
312  // Glowinski & Gouzevitch
313 
314  for (ElementList::iterator it = elements_.begin(); it != elements_.end(); ++it) {
315  for (const auto& kdtree : kdtrees_) {
316  if ((*it)->type() == kdtree->targetType()) {
317  kdtree->insertTargetElt(it->get());
318  }
319  if ((*it)->type() == kdtree->fieldType()) {
320  kdtree->insertFieldClusterElt(it->get());
321  }
322  }
323  }
324  //std::cout << "(new) imported: " << elements_.size() << " elements!" << std::endl;
325 }
326 
327 std::ostream& operator<<(std::ostream& out, const PFBlockAlgo& a) {
328  if (!out)
329  return out;
330 
331  out << "====== Particle Flow Block Algorithm ======= ";
332  out << endl;
333  out << "number of unassociated elements : " << a.elements_.size() << endl;
334  out << endl;
335 
336  for (auto const& element : a.elements_) {
337  out << "\t" << *element << endl;
338  }
339 
340  return out;
341 }
342 
343 // a little history, ideas we may want to keep around for later
344 /*
345  // Links between the two preshower layers are not used for now - disable
346  case PFBlockLink::PS1andPS2:
347  {
348  PFClusterRef ps1ref = lowEl->clusterRef();
349  PFClusterRef ps2ref = highEl->clusterRef();
350  assert( !ps1ref.isNull() );
351  assert( !ps2ref.isNull() );
352  // PJ - 14-May-09 : A link by rechit is needed here !
353  // dist = testPS1AndPS2( *ps1ref, *ps2ref );
354  dist = -1.;
355  linktest = PFBlock::LINKTEST_RECHIT;
356  break;
357  }
358  case PFBlockLink::TRACKandPS1:
359  case PFBlockLink::TRACKandPS2:
360  {
361  //cout<<"TRACKandPS"<<endl;
362  PFRecTrackRef trackref = lowEl->trackRefPF();
363  PFClusterRef clusterref = highEl->clusterRef();
364  assert( !trackref.isNull() );
365  assert( !clusterref.isNull() );
366  // PJ - 14-May-09 : A link by rechit is needed here !
367  dist = testTrackAndPS( *trackref, *clusterref );
368  linktest = PFBlock::LINKTEST_RECHIT;
369  break;
370  }
371  // GSF Track/Brem Track and preshower cluster links are not used for now - disable
372  case PFBlockLink::PS1andGSF:
373  case PFBlockLink::PS2andGSF:
374  {
375  PFClusterRef psref = lowEl->clusterRef();
376  assert( !psref.isNull() );
377  const reco::PFBlockElementGsfTrack * GsfEl = dynamic_cast<const reco::PFBlockElementGsfTrack*>(highEl);
378  const PFRecTrack * myTrack = &(GsfEl->GsftrackPF());
379  // PJ - 14-May-09 : A link by rechit is needed here !
380  dist = testTrackAndPS( *myTrack, *psref );
381  linktest = PFBlock::LINKTEST_RECHIT;
382  break;
383  }
384  case PFBlockLink::PS1andBREM:
385  case PFBlockLink::PS2andBREM:
386  {
387  PFClusterRef psref = lowEl->clusterRef();
388  assert( !psref.isNull() );
389  const reco::PFBlockElementBrem * BremEl = dynamic_cast<const reco::PFBlockElementBrem*>(highEl);
390  const PFRecTrack * myTrack = &(BremEl->trackPF());
391  // PJ - 14-May-09 : A link by rechit is needed here !
392  dist = testTrackAndPS( *myTrack, *psref );
393  linktest = PFBlock::LINKTEST_RECHIT;
394  break;
395  }
396  */
FastTimerService_cff.range
range
Definition: FastTimerService_cff.py:34
PluginFactory.h
testProducerWithPsetDescEmpty_cfi.i2
i2
Definition: testProducerWithPsetDescEmpty_cfi.py:46
PFBlockAlgo::buildElements
void buildElements(const edm::Event &)
Definition: PFBlockAlgo.cc:286
mps_fire.i
i
Definition: mps_fire.py:355
PFBlockAlgo::debug_
bool debug_
if true, debug printouts activated
Definition: PFBlockAlgo.h:75
funct::false
false
Definition: Factorize.h:34
min
T min(T a, T b)
Definition: MathUtil.h:58
AlCaHLTBitMon_ParallelJobs.p
p
Definition: AlCaHLTBitMon_ParallelJobs.py:153
reco::PFBlock
Block of elements.
Definition: PFBlock.h:26
gather_cfg.cout
cout
Definition: gather_cfg.py:144
pos
Definition: PixelAliasList.h:18
testProducerWithPsetDescEmpty_cfi.i1
i1
Definition: testProducerWithPsetDescEmpty_cfi.py:45
data-class-funcs.q
q
Definition: data-class-funcs.py:169
ErrorObj.h
ProductRegistryHelper.h
relativeConstraints.keys
keys
Definition: relativeConstraints.py:89
reco
fixed size matrix
Definition: AlignmentAlgorithmBase.h:45
cms::dd::split
std::vector< std::string_view > split(std::string_view, const char *)
beamerCreator.create
def create(alignables, pedeDump, additionalData, outputFile, config)
Definition: beamerCreator.py:44
HLT_2018_cff.useKDTree
useKDTree
Definition: HLT_2018_cff.py:12202
spr::find
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:19
WorkerMaker.h
reco::PFBlockElement::Type
Type
Definition: PFBlockElement.h:30
ECAL
Definition: HCALResponse.h:21
HLT_2018_cff.importerName
importerName
Definition: HLT_2018_cff.py:12233
p2
double p2[4]
Definition: TauolaWrapper.h:90
PFBlockAlgo::link
void link(const reco::PFBlockElement *el1, const reco::PFBlockElement *el2, double &dist) const
check whether 2 elements are linked. Returns distance
Definition: PFBlockAlgo.cc:263
PFBlockAlgo::elements_
ElementList elements_
Definition: PFBlockAlgo.h:71
PFBlockAlgo::~PFBlockAlgo
~PFBlockAlgo()
Definition: PFBlockAlgo.cc:134
HCAL
Definition: HCALResponse.h:21
DigiToRawDM_cff.HO
HO
Definition: DigiToRawDM_cff.py:23
b
double b
Definition: hdecay.h:118
PFBlockAlgo::kdtrees_
std::vector< std::unique_ptr< KDTreeLinkerBase > > kdtrees_
Definition: PFBlockAlgo.h:86
cuda_std::lower_bound
__host__ constexpr __device__ RandomIt lower_bound(RandomIt first, RandomIt last, const T &value, Compare comp={})
Definition: cudastdAlgorithm.h:27
AlCaHLTBitMon_QueryRunRegistry.string
string
Definition: AlCaHLTBitMon_QueryRunRegistry.py:256
reco::PFBlockCollection
std::vector< PFBlock > PFBlockCollection
collection of PFBlock objects
Definition: PFBlockFwd.h:10
INIT_ENTRY
#define INIT_ENTRY(name)
Definition: PFBlockAlgo.cc:19
a
double a
Definition: hdecay.h:119
PFBlockAlgo::linkTests_
std::vector< std::unique_ptr< BlockElementLinkerBase > > linkTests_
Definition: PFBlockAlgo.h:83
SiStripPI::max
Definition: SiStripPayloadInspectorHelper.h:169
PFBlockAlgo::elementTypes_
const std::unordered_map< std::string, reco::PFBlockElement::Type > elementTypes_
Definition: PFBlockAlgo.h:82
KineDebug3::count
void count()
Definition: KinematicConstrainedVertexUpdatorT.h:21
PFBlockAlgo::linkTestSquare_
unsigned int linkTestSquare_[reco::PFBlockElement::kNBETypes][reco::PFBlockElement::kNBETypes]
Definition: PFBlockAlgo.h:84
PFBlockAlgo::setImporters
void setImporters(const std::vector< edm::ParameterSet > &, edm::ConsumesCollector &)
Definition: PFBlockAlgo.cc:126
HLT_2018_cff.linkerName
linkerName
Definition: HLT_2018_cff.py:12203
p1
double p1[4]
Definition: TauolaWrapper.h:89
PFBlockAlgo::ranges_
ElementRanges ranges_
Definition: PFBlockAlgo.h:72
groupFilesInBlocks.block
block
Definition: groupFilesInBlocks.py:150
edm::EventSetup
Definition: EventSetup.h:57
PFBlockAlgo.h
PFBlockAlgo
Particle Flow Algorithm.
Definition: PFBlockAlgo.h:34
itr
std::vector< std::pair< float, float > >::iterator itr
Definition: HGCDigitizer.cc:28
get
#define get
PFBlockAlgo::findBlocks
reco::PFBlockCollection findBlocks()
build blocks
Definition: PFBlockAlgo.cc:141
PFBlockAlgo::updateEventSetup
void updateEventSetup(const edm::EventSetup &)
Definition: PFBlockAlgo.cc:277
reco::PFBlockElement
Abstract base class for a PFBlock element (track, cluster...)
Definition: PFBlockElement.h:26
PFBlockAlgo::packLinks
void packLinks(reco::PFBlock &block, const std::unordered_map< std::pair< unsigned int, unsigned int >, double > &links) const
Definition: PFBlockAlgo.cc:219
type
type
Definition: HCALResponse.h:21
std
Definition: JetResolutionObject.h:76
reco::PFBlockElement::kNBETypes
Definition: PFBlockElement.h:44
Exception
Definition: hltDiff.cc:246
electronStore.links
links
Definition: electronStore.py:149
reco::PFBlockElement::type
Type type() const
Definition: PFBlockElement.h:69
PFBlockAlgo::importers_
std::vector< std::unique_ptr< BlockElementImporterBase > > importers_
Definition: PFBlockAlgo.h:80
AlignmentPI::index
index
Definition: AlignmentPayloadInspectorHelper.h:46
MillePedeFileConverter_cfg.out
out
Definition: MillePedeFileConverter_cfg.py:31
ParameterSetDescriptionFiller.h
operator<<
std::ostream & operator<<(std::ostream &out, const PFBlockAlgo &a)
Definition: PFBlockAlgo.cc:327
dqmiolumiharvest.j
j
Definition: dqmiolumiharvest.py:66
PFBlockAlgo::PFBlockAlgo
PFBlockAlgo()
Definition: PFBlockAlgo.cc:71
edm::Event
Definition: Event.h:73
crabWrapper.key
key
Definition: crabWrapper.py:19
edm::OwnVector::size
size_type size() const
Definition: OwnVector.h:300
gather_cfg.blocks
blocks
Definition: gather_cfg.py:90
edm::ConsumesCollector
Definition: ConsumesCollector.h:39
edm::OwnVector< reco::PFBlockElement >
PFBlockAlgo::setLinkers
void setLinkers(const std::vector< edm::ParameterSet > &)
Definition: PFBlockAlgo.cc:86
ZMuMuAnalysisNtupler_cff.prefix
prefix
Definition: ZMuMuAnalysisNtupler_cff.py:14