CMS 3D CMS Logo

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