ATLAS Offline Software
Loading...
Searching...
No Matches
FastReducer.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "./FastReducer.h"
9
10#include <map>
11#include <algorithm>
12#include <sstream>
13
15public:
16 DepthComparison(const Tree& t) : m_tree(t){}
17 bool operator () (const std::size_t& lhs, const std::size_t rhs){
18 return m_tree.depth(rhs) > m_tree.depth(lhs);
19 }
20private:
21 const Tree& m_tree;
22};
23
24
26 bool operator () (const std::vector<std::size_t>& lhs,
27 const std::vector<std::size_t>& rhs){
28 if(lhs.size() < rhs.size()){return true;}
29 if(rhs.size() < rhs.size()){return false;}
30
31 for(std::size_t i = 0; i < lhs.size(); ++i){
32 if(lhs[i] > rhs[i]){return false;}
33 }
34
35 return true;
36 }
37
38};
39
40
42 const ConditionPtrs& conditions,
43 const ConditionFilters& filters,
44 const ConditionFilterInds& filterInds,
45 const Tree& tree,
46 xAODJetCollector& jetCollector,
47 const Collector& collector):
48 m_conditions(conditions), m_conditionFilters(filters),
49 m_conditionFilterInds(filterInds), m_tree(tree) {
50
51 // create an empty vector of indices of satisfying jet groups
52 // for each Condition.
53 for(std::size_t i = 0; i < m_tree.size(); ++i){
54 m_satisfiedBy.emplace(i, std::vector<std::size_t>{});
55 m_testedBy.emplace(i, std::set<std::size_t>{});
56 m_conditionMult.push_back(conditions[i]->multiplicity());
57 m_conditionCap.push_back(conditions[i]->capacity());
58 m_conditionClique.push_back(conditions[i]->clique());
59 }
60
61
63 collector)){
64 if(collector){
65 collector->collect("FastReducer early return",
66 "from findInitialJetGroups");
67 dumpDataStructures(collector);
68 }
69 return; // m_pass retains initial value ie false
70 }
71
72
73 if(!propagateJetGroups(collector)){
74 // error propagating edges. e.g. unsatisfied condition
75 if(collector){
76 collector->collect("FastReducer early return",
77 "from propagateJetGroups");
78 dumpDataStructures(collector);
79 }
80 return; // early return, leave m_pass = false
81 }
82
83 m_pass = true;
84 if(collector){
85 collector->collect("FastReducer returning",
86 "from propagateJetGroups");
87 dumpDataStructures(collector);
88 }
89
90 collectLeafJets(jetCollector, collector);
91
92}
93
95 const Collector& collector) const {
96
97 // basic passing jet reporting
98
99 // find the indices of the jets that make up the jet groups that pass
100 // the root node.
101
102 //.. obtain the passing jet groups for the root node...
103
104 std::set<std::size_t> rootSatJetGroupInds(m_satisfiedBy.at(0).begin(),
105 m_satisfiedBy.at(0).end());
106
107 // ...obtain the elemental jet group indicies...
108
109 std::set<std::size_t> rootElSatJetGroupInds;
110 for (const auto& ji : rootSatJetGroupInds) {
111 rootElSatJetGroupInds.insert(m_jg2elemjgs.at(ji).begin(),
112 m_jg2elemjgs.at(ji).end());
113 }
114
115
116
117 // now do the same for the leaf nodes
118
119
120 auto leaves = m_tree.leaves();
121 // obtain the jet group indices for the jet groups satisfying the leaf conds
122 for (const auto& ci : leaves) { // for each leaf node...
123 std::set<std::size_t> satJetGroupInds;
124
125 // ... collect the (possibly compound) jet group indices...
126 satJetGroupInds.insert(m_satisfiedBy.at(ci).cbegin(),
127 m_satisfiedBy.at(ci).cend());
128
129 // ...obtain the corresponding elemental jet group indices...
130 std::set<std::size_t> elSatJetGroupInds;
131 for (const auto& ji : satJetGroupInds) {
132 elSatJetGroupInds.insert(m_jg2elemjgs.at(ji).begin(),
133 m_jg2elemjgs.at(ji).end());
134 }
135
136 // .. get the leg label for the condition (possibly "")
137 auto conditionLabel = (m_conditions.at(ci))->label();
138
139 if (collector) {
140 std::stringstream ss;
141 ss << "elSatJettGroupInds.size() "
142 << conditionLabel
143 << ": "
144 << elSatJetGroupInds.size();
145 collector->collect("FastReducer", ss.str());
146 }
147
148 // ... use the elemental jet group indices to recover the jets
149
150 // if the leaf not jet is one of the jets that contributes to
151 // passing root, store it in the collector, labelled by the leaf node
152 // chainLegLabel
153
154 auto end = rootElSatJetGroupInds.end();
155 for(const auto& ji : elSatJetGroupInds) {
156
157 if (rootElSatJetGroupInds.find(ji) != end){
158 jetCollector.addJets(m_indJetGroup.at(ji).begin(), //jets py ptrs
159 m_indJetGroup.at(ji).end(),
160 conditionLabel);
161 }
162 }
163 }
164 if (collector) {
165 collector->collect("FastReducer",
166 "collected " + std::to_string(jetCollector.size()));
167 }
168}
169
170
172 const Collector& collector) {
173
174
175 /*
176 Will now test the incoming jets against the leaf conditions.
177 */
178
179 auto leaves = m_tree.leaves();
180
181 // if a jet group satisfies a condition, note the fact,
182 // and store it by index
183
184 for(const auto& leaf: leaves){
185
186 auto filtered_jets = jv;
187 auto& filter_ind = m_conditionFilterInds[leaf];
188 if (filter_ind != -1) {
189 const auto& filter = m_conditionFilters[filter_ind];
190 filtered_jets = filter->filter(filtered_jets, collector);
191 }
192
193 auto iters = std::make_pair(filtered_jets.begin(),
194 filtered_jets.end());
195
196 recordFiltering(leaf, jv.size(), filtered_jets.size(), collector);
197
198 auto grouper = grouperByCapacityFactory(m_conditions[leaf]->capacity(),
199 iters.first,
200 iters.second);
201
202 while(true){
203 auto jg = grouper->next(); // obtain a vector of jet ptrs
204 if (jg.empty()) {break;}
205
206 auto jg_ind = m_jgRegister.record(jg); // obtain an int index for the jg
207 m_testedBy[leaf].insert(jg_ind);
208
209 if (m_conditions[leaf]->isSatisfied(jg, collector)){
210
211 if(collector){recordJetGroup(jg_ind, jg, collector);}
212
213 // note the index if the jet group if it passes a Condition
214 m_satisfiedBy[leaf].push_back(jg_ind);
215
216 // keep track of the indices for the individual jets that
217 // make up the passing jet group.
218 //
219 // m_jg2elemjgs[idx] = {idx1, idx2, idx3}
220 // where idx is the index of the jet group, and {} is a
221 // vector containing the individual jet group indices of
222 // the jet group with index idx.
223 //
224 // if the jet group contains a single jet, this reduces to
225 // m_jg2elemjgs[idx] = {idx}
226
227 std::vector<std::size_t>& elem_indices = m_jg2elemjgs[jg_ind];
228 if (elem_indices.empty()) { // first time jg_ind is seen
229 if (jg.size() > 1) {
230 elem_indices.reserve(jg.size());
231 for (const auto& hj : jg){
232
233 // deal with a jet member of the jet group
234 auto single_jet_group = std::vector{hj};
235 auto single_jet_index = m_jgRegister.record(single_jet_group);
236 auto& single_jet_elems = m_jg2elemjgs[single_jet_index];
237 if (single_jet_elems.empty()) {
238 single_jet_elems.push_back(single_jet_index);
239 m_indJetGroup.emplace(single_jet_index, single_jet_group);
240 }
241
242 // add the index of the individual jet to m_jg2elemjgs[jg_ind]
243 elem_indices.push_back(single_jet_index);
244 }
245 } else {
246 // one jet in the jet group: its index maps onto a vector containing
247 // only its index.
248 elem_indices.push_back(jg_ind);
249 }
250 }
251
252 // update jet gtoup index to jet group map.
253 m_indJetGroup.emplace(jg_ind, jg);
254 }
255 }
256 }
257
258 if(collector){
259 for(const auto& p : m_indJetGroup){
260 recordJetGroup(p.first, p.second, collector);
261 }
262 }
263
264 // check all leaf conditions are satisfied
265 for (const auto& i : leaves) {
266 if (!capacitySatisfied(i, collector)) {
267 return false;
268 }
269 }
270
271 return true;
272
273}
274
275
277
278
279 // construct jet groups according from jet groups that pass child
280 // conditions.
281 // This method controls which nodes to process.
282 // It checks whether all sibling nodes are processed.
283 // if so, processing of the parent is delegated to propagate_()
284
285 //The parent of the next condition to be processed
286 // is found, and from the parent the condition's siblings are found,
287
288 typedef std::priority_queue<std::size_t,
289 std::vector<std::size_t>,
290 DepthComparison> DepthQueue;
291
292 auto comparator = DepthComparison(m_tree);
293 DepthQueue to_process(comparator); // conditions to be processed.
294
295 // keep track if a condition's sibling has been processed.
296 std::vector<bool> checked(m_conditions.size(), false);
297
298 // initialise the queue with satisfied leaf conditions indices.
299 for(const auto& item : m_satisfiedBy){
300 if(!(item.second.empty())){
301 to_process.push(item.first);
302 }
303 }
304
305 while(!to_process.empty()){
306
307 auto k = to_process.top();
308 to_process.pop();
309
310 if(checked[k]){
311 continue;
312 }
313
314 if(k == 0){
315 // have propagated to the root node
316 if(m_satisfiedBy.at(0).empty()){
317 if(collector){
318 collector->collect("FastReducer",
319 "Condition node 0 fails");
320 }
321 return false;
322 } else {
323 return true; // event passes
324 }
325 }
326
327 auto siblings = m_tree.siblings(k);
328 for(const auto& s : siblings){
329 checked[s] = true;
330 }
331
332 // check if combinations of groups satisfying children satisfy their parent
333 if(!propagate_(k,
334 siblings,
335 collector)){
336 return false;
337 }
338
339 std::size_t par = m_tree.parent(k);
340 to_process.push(par);
341 }
342 return true;
343}
344
345
346bool FastReducer::propagate_(std::size_t child,
347 const std::vector<std::size_t>& siblings,
348 const Collector& collector){
349
350 // all combinations of the jet groups passing the sibings are
351 // constructed. One by one these combinations are tested for
352 // parent satisfaction.
353
354
355 // Edges are contructed between satisfying jet groups and the parent.
356 // if any such edge is constructed, the calling rroutine is notified so it
357 // can scheduling processing the parent as a child.
358
359 std::size_t par = m_tree.parent(child);
360
361 // child == 0 do not attempt to process parent of node.
362 if(child == 0){return true;}
363
364
365 // calculate the external product of the jet groups
366 // eg if condition c1 is satisfied by jg11 and jg12, while its only
367 // sibling c2 is satisfied by jg21, the external jet groups are
368 // jg11jg21, jg12jg21. Each of these are flattened.
369
370 auto jg_product = makeJetGroupProduct(siblings,
376 m_conditions[par]->capacity(),
377 m_tree.is_simple(),
378 collector);
379
380 // obtain the next product of jet groups passing siblings
381 auto jg_indices = jg_product->next(collector);
382
383 // step through the jet groups found by combining ghe child groups
384 // check ecach combination to see if it satisfies the parent. If so
385 // add an edge from the contributing children, and from the new jet group to the parent.
386
387 while (!jg_indices.empty()){ // empty jg_inidices: end of iteration
388 if (!std::is_sorted(jg_indices.begin(), jg_indices.end())) {
389 throw std::runtime_error("Jet hypo unsorted jet group");
390 }
391
392 for (const auto& ind : jg_indices) {
393 if (m_jg2elemjgs.at(ind).size() != 1) {
394 throw std::runtime_error("Jet hypo jet group with non-elementary index");
395 }
396 }
397
398
399 // use the elemental jet group indices to form a vector of jet pointers
400 HypoJetVector jg;
401 for(const auto& i : jg_indices){
402 const auto& jetGroup = m_indJetGroup.at(i);
403 jg.insert(jg.end(), jetGroup.begin(), jetGroup.end());
404 }
405
406 // obtain an index for the new jet group.
407 auto cur_jg = m_jgRegister.record(jg);
408
409 // keep track of which jet groups a Condition sees.
410 if(m_testedBy[par].find(cur_jg) != m_testedBy[par].end()){
411 jg_indices = jg_product->next(collector);
412 continue;
413 }
414
415 m_testedBy[par].insert(cur_jg);
416
417 // check if parent is satisfied by a jet group (vector of jet ptrs)
418 if (m_conditions[par]->isSatisfied(jg, collector)){// par is a tree ind.
419
420 // get an index for this vector of elementary jet group indices
421 m_satisfiedBy[par].push_back(cur_jg);
422
423 m_jg2elemjgs[cur_jg] = jg_indices;
424 if(collector){recordJetGroup(cur_jg, jg, collector);}
425 }
426
427 jg_indices = jg_product->next(collector);
428 }
429
430 // check if enough jet groups pass the parent condition
431 bool par_satisfied =
432 m_conditions[par]->multiplicitySatisfied(m_satisfiedBy[par].size(),
433 collector);
434 if(collector and !par_satisfied){
435 collector->collect("FastReducer",
436 "Condition node " + std::to_string(par) +
437 " unsatisfied");
438 }
439
440 return par_satisfied;
441}
442
443
444
445std::string FastReducer::toString() const {
446 std::stringstream ss;
447 ss << "FastReducer:\n";
448 ss << " treeVector: " << m_tree << '\n';;
449 ss << "FastReducer Conditions ["
450 << m_conditions.size() << "]: \n";
451
452 std::size_t count{0u};
453 for(const auto& c : m_conditions){
454 auto sc = std::to_string(count++);
455 sc.insert(sc.begin(), 3-sc.length(), ' ');
456 ss << sc <<": "<< c->toString() + '\n';
457 }
458
459 return ss.str();
460}
461
462
464
465 std::stringstream ss;
466 ss << "FastReducer data structure dumps\nindToJetGroup:\n";
467 for(const auto& pair : m_indJetGroup){
468 ss << pair.first << " [";
469 for(const auto& j : pair.second){
470 ss << static_cast<const void*>(j.get()) << " ";
471 }
472 ss << "]\n";
473 }
474
475 ss << "satisfiedBy: \n";
476 for(const auto& pair : m_satisfiedBy){
477 ss << pair.first << " [";
478 for(const auto& i : pair.second){
479 ss << i << " ";
480 }
481 ss << "]\n";
482 }
483
484
485 ss << "testedBy: \n";
486 for(const auto& pair : m_testedBy){
487 ss << pair.first << " [";
488 for(const auto& i : pair.second){
489 ss << i << " ";
490 }
491 ss << "]\n";
492 }
493
494 ss << "jg to elemental jgs: \n";
495
496 for(const auto& pair : m_jg2elemjgs){
497 ss << pair.first << " [";
498 for(const auto& i : pair.second){
499 ss << i << " ";
500 }
501 ss << "]\n";
502 }
503 ss <<'\n';
504
505 return ss.str();
506 }
507
508 void FastReducer::dumpDataStructures(const Collector& collector) const {
509
510 if(!collector){return;}
511
512 collector->collect("FastReducer",
514 }
515
516
517void FastReducer::recordJetGroup(std::size_t ind,
518 const HypoJetVector& jg,
519 const Collector& collector) const {
520
521 std::stringstream ss0;
522 ss0 << "FastReducer jet group "
523 << ind << " [" << jg.size() <<"]:";
524
525 std::stringstream ss1;
526 for(auto ip : jg){
527 const void* address = static_cast<const void*>(ip.get());
528 ss1 << "\n " << address << " eta " << ip->eta()
529 << " e " << ip->e()
530 << " et " << ip->et();
531 }
532 ss1 << '\n';
533 collector->collect(ss0.str(), ss1.str());
534}
535
536void FastReducer::recordFiltering(std::size_t leaf_ind,
537 std::size_t n_injets,
538 int n_filteredjets,
539 const Collector& collector) const {
540
541 if(!collector) {return;}
542
543 std::stringstream ss0;
544 ss0 << "FastReducer filtering Condition index: " << leaf_ind;
545
546 std::stringstream ss1;
547 ss1 << "n jets. in: " << n_injets << " filtered: " << n_filteredjets << '\n';
548
549 collector->collect(ss0.str(), ss1.str());
550}
551
552bool FastReducer::pass() const { return m_pass; }
553
554
556 const Collector& collector) const {
557 // Check that the number of satisfying jet groups is sufficient to
558 // satisfy the capacity of the Condition. Uses include handling
559 // of Conditions which represent multiple identical conditions.
560
561 auto jgMult = m_satisfiedBy.at(ind).size();
562 auto capSat = m_conditions.at(ind)->multiplicitySatisfied(jgMult, collector);
563 if (!capSat and collector) {
564 collector->collect("FastReduce", "Condition " + std::to_string(ind)
565 + " unsatisfied multiplicity, aborting");
566 }
567
568 return capSat;
569}
std::vector< int > ConditionFilterInds
Definition FastReducer.h:33
std::vector< std::unique_ptr< IHypoJetVectorFilter > > ConditionFilters
Definition FastReducer.h:30
std::unique_ptr< ITrigJetHypoInfoCollector > Collector
Definition FastReducer.h:22
std::unique_ptr< IJetGrouper > grouperByCapacityFactory(unsigned int cap, const HypoJetCIter &b, const HypoJetCIter &e)
std::vector< pHypoJet > HypoJetVector
Definition HypoJetDefs.h:27
std::unique_ptr< IJetGroupProduct > makeJetGroupProduct(const std::vector< std::size_t > &siblings, const CondInd2JetGroupsInds &satisfiedBy, const std::vector< std::size_t > &condMult, const std::vector< unsigned int > &condCap, const std::vector< int > &condClique, const JetGroupInd2ElemInds &jg2elemjgs, std::size_t parentCap, bool simpleTree, const Collector &)
static Double_t ss
static Double_t sc
std::vector< ConditionPtr > ConditionPtrs
bool operator()(const std::size_t &lhs, const std::size_t rhs)
DepthComparison(const Tree &t)
const Tree & m_tree
JetGroupInd2ElemInds m_jg2elemjgs
map jet group indices to indices of incoming jet groups
Definition FastReducer.h:87
std::vector< int > m_conditionClique
Definition FastReducer.h:61
std::vector< unsigned int > m_conditionCap
Definition FastReducer.h:60
Tree m_tree
tree structure for Conditions objects.
Definition FastReducer.h:72
bool pass() const
determine whether a set of jets satisfies all hypo conditions.
CondInd2JetGroupsInds m_satisfiedBy
Definition FastReducer.h:75
bool m_pass
event pass flag
Definition FastReducer.h:91
void collectLeafJets(xAODJetCollector &jetCollector, const Collector &collector) const
const ConditionPtrs & m_conditions
Definition FastReducer.h:58
ConditionFilterInds m_conditionFilterInds
Definition FastReducer.h:65
bool propagate_(std::size_t child, const std::vector< std::size_t > &siblings, const Collector &)
std::vector< std::size_t > m_conditionMult
Definition FastReducer.h:59
void dumpDataStructures(const Collector &) const
std::string toString() const
std::map< std::size_t, std::set< std::size_t > > m_testedBy
map Condition index onto a set of indices the condition has been tested with - used to prevent retest...
Definition FastReducer.h:81
void recordJetGroup(std::size_t ind, const HypoJetVector &jg, const Collector &collector) const
FastReducer(const HypoJetVector &jv, const ConditionPtrs &conditionObjects, const ConditionFilters &conditionFilters, const ConditionFilterInds &conditionFilterInds, const Tree &conditionsTree, xAODJetCollector &jetCollector, const Collector &collector)
JetGroupRegister m_jgRegister
Definition FastReducer.h:95
bool capacitySatisfied(std::size_t ind, const Collector &collector) const
const ConditionFilters & m_conditionFilters
Definition FastReducer.h:64
void recordFiltering(std::size_t leaf_ind, std::size_t n_inputjets, int n_filteredjets, const Collector &collector) const
std::string dataStructuresToStr() const
std::map< std::size_t, HypoJetVector > m_indJetGroup
map jet group indices to jet groups
Definition FastReducer.h:84
bool propagateJetGroups(const Collector &collector)
bool findInitialJetGroups(const HypoJetVector &jv, const Collector &collector)
set up the data structures for propagation.
virtual void collect(const std::string &, const std::string &)=0
Definition Tree.h:18
STL class.
void addJets(const HypoJetCIter &begin, const HypoJetCIter &end, int chainPartInd=-1)
std::size_t size() const
std::string find(const std::string &s)
return a remapped string
Definition hcg.cxx:138
int count(std::string s, const std::string &regx)
count how many occurances of a regx are in a string
Definition hcg.cxx:146
bool operator()(const std::vector< std::size_t > &lhs, const std::vector< std::size_t > &rhs)
TChain * tree