CMS 3D CMS Logo

ThinnedAssociationsHelper.cc
Go to the documentation of this file.
4 #include <algorithm>
5 
6 #include <fmt/format.h>
7 
8 namespace edm {
9 
11 
13  BranchID const& association,
14  BranchID const& thinned,
15  bool slimmed)
16  : parent_(parent), association_(association), thinned_(thinned), slimmed_(slimmed) {}
17 
19 
20  std::vector<ThinnedAssociationBranches>::const_iterator ThinnedAssociationsHelper::begin() const {
21  return vThinnedAssociationBranches_.begin();
22  }
23 
24  std::vector<ThinnedAssociationBranches>::const_iterator ThinnedAssociationsHelper::end() const {
25  return vThinnedAssociationBranches_.end();
26  }
27 
28  std::vector<ThinnedAssociationBranches>::const_iterator ThinnedAssociationsHelper::parentBegin(
29  BranchID const& parent) const {
33  target,
35  return x.parent() < y.parent();
36  });
37  }
38 
39  std::vector<ThinnedAssociationBranches>::const_iterator ThinnedAssociationsHelper::parentEnd(
40  BranchID const& parent) const {
44  target,
46  return x.parent() < y.parent();
47  });
48  }
49 
50  std::vector<ThinnedAssociationBranches>::const_iterator ThinnedAssociationsHelper::lower_bound(
51  ThinnedAssociationBranches const& branches) const {
52  return std::lower_bound(
55  branches,
57  return x.parent() < y.parent() ? true : y.parent() < x.parent() ? false : x.association() < y.association();
58  });
59  }
60 
62  BranchID const& association,
63  BranchID const& thinned,
64  bool slimmed) {
66  }
67 
69  vThinnedAssociationBranches_.insert(lower_bound(branches), branches);
70  if (branches.isSlimmed()) {
71  try {
73  } catch (edm::Exception& ex) {
74  ex.addContext("Calling ThinnedAssociationsHelper::addAssociation()");
75  ex.addAdditionalInfo(fmt::format("When adding a slimmed collection with BranchID {}", branches.thinned().id()));
76  throw ex;
77  }
78  }
79  }
80 } // namespace edm
81 
82 namespace {
83  struct SlimmedCount {
85  int slimmedChildrenCount;
86  };
87 
88  int countSlimmingChildren(edm::ThinnedAssociationsHelper const& helper,
89  edm::BranchID const& parent,
90  std::vector<SlimmedCount> const& counts);
91  void addSlimmingChildrenCount(edm::ThinnedAssociationsHelper const& helper,
92  edm::ThinnedAssociationBranches const& branches,
93  std::vector<SlimmedCount> const& counts,
94  int& slimmedCount) {
95  int slimmingChildren = countSlimmingChildren(helper, branches.thinned(), counts);
96  if (slimmingChildren > 1) {
98  << "Encountered a parent collection with BranchID " << branches.thinned().id()
99  << " that has more than one thinned children that are either themselves slimmed, or have further thinned "
100  "children that are slimmed. This is not allowed, but this particular check should not fire (it should "
101  "have been caught earlier). Please contact framework developers.";
102  }
103 
104  if (slimmingChildren == 0 and branches.isSlimmed()) {
105  ++slimmingChildren;
106  }
107 
108  slimmedCount += slimmingChildren;
109  if (slimmedCount > 1) {
111  << "Encountered a parent collection with BranchID " << branches.parent().id()
112  << " that has more than one thinned children that are either themselves slimmed, or have further thinned "
113  "children that are slimmed. This is not allowed. In the thinning parentage tree, any parent may have "
114  "slimmed collections in at most one path to any leaf thinned collections of that parent.";
115  }
116  }
117 
118  int countSlimmingChildren(edm::ThinnedAssociationsHelper const& helper,
119  edm::BranchID const& parent,
120  std::vector<SlimmedCount> const& counts) {
121  auto begin = helper.parentBegin(parent);
122  auto end = helper.parentEnd(parent);
123  if (begin == end)
124  return 0;
125 
126  // if already visited, can just return the count
127  auto pos =
128  std::lower_bound(counts.begin(), counts.end(), parent, [](SlimmedCount const& c, edm::BranchID const& b) {
129  return c.parent < b;
130  });
131  if (pos != counts.end() && pos->parent == parent) {
132  return pos->slimmedChildrenCount;
133  }
134 
135  int slimmedCount = 0;
136  for (auto iItem = begin; iItem != end; ++iItem) {
137  addSlimmingChildrenCount(helper, *iItem, counts, slimmedCount);
138  }
139  return slimmedCount;
140  }
141 } // namespace
142 
143 namespace edm {
145  // ThinnedAssociationBranches defines an edge between a parent and
146  // a thinned collection in the parentage tree of the thinned
147  // collections. It is required that for a given parentage tree
148  // there is at most one path from the root node to any leaf nodes
149  // that has slimming edges.
150 
151  std::vector<::SlimmedCount> counts;
152  BranchID prevParent;
153  std::vector<SlimmedCount>::iterator currentCount;
154  for (auto iItem = begin(), iEnd = end(); iItem != iEnd; ++iItem) {
155  if (iItem->parent() == BranchID()) {
156  continue;
157  }
158  if (iItem->parent() == prevParent) {
159  addSlimmingChildrenCount(*this, *iItem, counts, currentCount->slimmedChildrenCount);
160  } else {
161  currentCount = std::lower_bound(
162  counts.begin(), counts.end(), iItem->parent(), [](SlimmedCount const& c, BranchID const& b) {
163  return c.parent < b;
164  });
165  // has the tree with iItem->parent() as root node already been counted?
166  if (currentCount != counts.end() && currentCount->parent == iItem->parent()) {
167  continue;
168  }
169  currentCount = counts.insert(currentCount, ::SlimmedCount{iItem->parent(), 0});
170  addSlimmingChildrenCount(*this, *iItem, counts, currentCount->slimmedChildrenCount);
171  prevParent = iItem->parent();
172  }
173  }
174  }
175 
176  std::vector<std::pair<BranchID, ThinnedAssociationBranches const*>> ThinnedAssociationsHelper::associationToBranches()
177  const {
178  std::vector<std::pair<BranchID, ThinnedAssociationBranches const*>> temp;
179  temp.reserve(vThinnedAssociationBranches_.size());
180  for (auto const& item : vThinnedAssociationBranches_) {
181  temp.push_back(std::make_pair(item.association(), &item));
182  }
183  std::sort(temp.begin(),
184  temp.end(),
185  [](std::pair<BranchID, ThinnedAssociationBranches const*> const& x,
186  std::pair<BranchID, ThinnedAssociationBranches const*> const& y) { return x.first < y.first; });
187  return temp;
188  }
189 
191  std::vector<BranchDescription const*> const& associationDescriptions,
192  std::set<BranchID> const& keptProductsInEvent,
193  std::map<BranchID, bool>& keepAssociation) const {
194  keepAssociation.clear();
195  // Copy the elements in vThinnedAssociationBranches_ into a vector sorted on
196  // the association BranchID so we can do searches on that BranchID faster.
197  std::vector<std::pair<BranchID, ThinnedAssociationBranches const*>> assocToBranches = associationToBranches();
198 
199  for (auto association : associationDescriptions) {
200  if (association
201  ->isAlias()) { // There is no reason to configure an association product with an EDAlias (ignore and drop them if they exist)
202  keepAssociation.insert(std::make_pair(association->branchID(), false));
203  } else {
204  std::set<BranchID> branchesInRecursion;
206  association->branchID(), assocToBranches, branchesInRecursion, keptProductsInEvent, keepAssociation);
207  }
208  }
209  }
210 
212  BranchID const& association,
213  std::vector<std::pair<BranchID, ThinnedAssociationBranches const*>> const& associationToBranches,
214  std::set<BranchID>& branchesInRecursion,
215  std::set<BranchID> const& keptProductsInEvent,
216  std::map<BranchID, bool>& keepAssociation) const {
217  // If we already decided to keep or drop this one, then
218  // return the same decision.
219  auto decision = keepAssociation.find(association);
220  if (decision != keepAssociation.end()) {
221  return decision->second;
222  }
223 
224  // Be careful not to fall into an infinite loop because
225  // of a circular recursion.
226  if (!branchesInRecursion.insert(association).second) {
227  return false;
228  }
229 
230  // If the thinned collection is being kept then keep the association
231  auto branches = std::lower_bound(
232  associationToBranches.begin(),
233  associationToBranches.end(),
234  std::make_pair(association, static_cast<ThinnedAssociationBranches const*>(nullptr)),
235  [](std::pair<BranchID, ThinnedAssociationBranches const*> const& x,
236  std::pair<BranchID, ThinnedAssociationBranches const*> const& y) { return x.first < y.first; });
237  // This should never happen
238  if (branches == associationToBranches.end() || branches->first != association) {
240  "ThinnedAssociationHelper::shouldKeepAssociation could not find branches information, "
241  "contact Framework developers");
242  }
243  BranchID const& thinnedCollection = branches->second->thinned();
244  if (keptProductsInEvent.find(thinnedCollection) != keptProductsInEvent.end()) {
245  keepAssociation.insert(std::make_pair(association, true));
246  return true;
247  }
248  // otherwise loop over any associations where the thinned collection
249  // is also a parent collection and recursively examine those to see
250  // if their thinned collections are being kept.
251  auto iterEnd = parentEnd(thinnedCollection);
252  for (auto match = parentBegin(thinnedCollection); match != iterEnd; ++match) {
254  match->association(), associationToBranches, branchesInRecursion, keptProductsInEvent, keepAssociation)) {
255  keepAssociation.insert(std::make_pair(association, true));
256  return true;
257  }
258  }
259  // drop the association
260  keepAssociation.insert(std::make_pair(association, false));
261  return false;
262  }
263 
265  bool foundMatch = false;
266  for (auto entry = parentBegin(input.parent()), iEnd = parentEnd(input.parent()); entry != iEnd; ++entry) {
267  if (entry->association() == input.association() && entry->thinned() == input.thinned()) {
268  foundMatch = true;
269  break;
270  }
271  }
272  if (!foundMatch) {
273  throw edm::Exception(
275  "ThinnedAssociationHelper::requireMatch, Illegal attempt to merge files with different ThinnedAssociations");
276  }
277  }
278 
280  if (vThinnedAssociationBranches_.empty()) {
282  return;
283  }
284  std::vector<ThinnedAssociationBranches> const& inputData = helper.data();
285  for (auto const& inputEntry : inputData) {
286  requireMatch(inputEntry);
287  }
288  }
289 
291  std::vector<BranchID> const& associationsFromSecondary) {
292  if (associationsFromSecondary.empty())
293  return;
294 
295  std::vector<std::pair<BranchID, ThinnedAssociationBranches const*>> assocToBranches =
296  helper.associationToBranches();
297 
298  for (BranchID const& association : associationsFromSecondary) {
299  auto branches = std::lower_bound(
300  assocToBranches.begin(),
301  assocToBranches.end(),
302  std::make_pair(association, static_cast<ThinnedAssociationBranches const*>(nullptr)),
303  [](std::pair<BranchID, ThinnedAssociationBranches const*> const& x,
304  std::pair<BranchID, ThinnedAssociationBranches const*> const& y) { return x.first < y.first; });
305  // This should never happen
306  if (branches == assocToBranches.end() || branches->first != association) {
308  "ThinnedAssociationHelper::initAssociationsFromSecondary could not find branches "
309  "information, contact Framework developers");
310  }
311  requireMatch(*(branches->second));
312  }
313  }
314 
316  ThinnedAssociationsHelper const& parentThinnedAssociationsHelper,
317  std::map<BranchID, bool> const& keepAssociation,
318  std::map<BranchID::value_type, BranchID::value_type> const& droppedBranchIDToKeptBranchID) {
319  clear();
320  for (auto const& associationBranches : parentThinnedAssociationsHelper.data()) {
321  auto keep = keepAssociation.find(associationBranches.association());
322  if (keep != keepAssociation.end() && keep->second) {
323  BranchID parent = associationBranches.parent();
324  auto iter = droppedBranchIDToKeptBranchID.find(parent.id());
325  if (iter != droppedBranchIDToKeptBranchID.end()) {
326  parent = BranchID(iter->second);
327  }
328  BranchID thinned = associationBranches.thinned();
329  iter = droppedBranchIDToKeptBranchID.find(thinned.id());
330  if (iter != droppedBranchIDToKeptBranchID.end()) {
331  thinned = BranchID(iter->second);
332  }
333  addAssociation(parent, associationBranches.association(), thinned, associationBranches.isSlimmed());
334  }
335  }
336  }
337 
339  std::vector<BranchID> const& associationsFromSecondary, ThinnedAssociationsHelper const& fileAssociationsHelper) {
340  if (associationsFromSecondary.empty())
341  return;
342 
343  std::vector<std::pair<BranchID, ThinnedAssociationBranches const*>> assocToBranches =
344  fileAssociationsHelper.associationToBranches();
345 
346  for (BranchID const& association : associationsFromSecondary) {
347  auto branches = std::lower_bound(
348  assocToBranches.begin(),
349  assocToBranches.end(),
350  std::make_pair(association, static_cast<ThinnedAssociationBranches const*>(nullptr)),
351  [](std::pair<BranchID, ThinnedAssociationBranches const*> const& x,
352  std::pair<BranchID, ThinnedAssociationBranches const*> const& y) { return x.first < y.first; });
353  // This should never happen
354  if (branches == assocToBranches.end() || branches->first != association) {
356  "ThinnedAssociationHelper::initAssociationsFromSecondary could not find branches "
357  "information, contact Framework developers");
358  }
359  addAssociation(*(branches->second));
360  }
361  }
362 } // namespace edm
void initAssociationsFromSecondary(std::vector< BranchID > const &, ThinnedAssociationsHelper const &)
std::vector< ThinnedAssociationBranches >::const_iterator parentEnd(BranchID const &) const
Definition: helper.py:1
std::vector< ThinnedAssociationBranches >::const_iterator lower_bound(ThinnedAssociationBranches const &branches) const
std::vector< std::pair< BranchID, ThinnedAssociationBranches const * > > associationToBranches() const
void updateFromPrimaryInput(ThinnedAssociationsHelper const &)
std::tuple< layerClusterToCaloParticle, caloParticleToLayerCluster > association
static std::string const input
Definition: EdmProvDump.cc:50
std::vector< ThinnedAssociationBranches > const & data() const
unsigned int id() const
Definition: BranchID.h:21
std::vector< ThinnedAssociationBranches >::const_iterator begin() const
void addAdditionalInfo(std::string const &info)
Definition: Exception.cc:173
std::vector< ThinnedAssociationBranches >::const_iterator end() const
void addAssociation(BranchID const &, BranchID const &, BranchID const &, bool slimmed)
void updateFromSecondaryInput(ThinnedAssociationsHelper const &, std::vector< BranchID > const &associationsFromSecondary)
std::vector< ThinnedAssociationBranches > vThinnedAssociationBranches_
void requireMatch(ThinnedAssociationBranches const &input) const
double b
Definition: hdecay.h:120
bool shouldKeepAssociation(BranchID const &association, std::vector< std::pair< BranchID, ThinnedAssociationBranches const *> > const &associationToBranches, std::set< BranchID > &branchesInRecursion, std::set< BranchID > const &keptProductsInEvent, std::map< BranchID, bool > &keepAssociation) const
void addContext(std::string const &context)
Definition: Exception.cc:169
std::vector< ThinnedAssociationBranches >::const_iterator parentBegin(BranchID const &) const
void updateFromParentProcess(ThinnedAssociationsHelper const &parentThinnedAssociationsHelper, std::map< BranchID, bool > const &keepAssociation, std::map< BranchID::value_type, BranchID::value_type > const &droppedBranchIDToKeptBranchID)
HLT enums.
void selectAssociationProducts(std::vector< BranchDescription const *> const &associationDescriptions, std::set< BranchID > const &keptProductsInEvent, std::map< BranchID, bool > &keepAssociation) const
float x
std::string match(BranchDescription const &a, BranchDescription const &b, std::string const &fileName)