ATLAS Offline Software
Loading...
Searching...
No Matches
TrigNavigationThinningSvc.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
7#include "getLabel.h"
16#include "GaudiKernel/ThreadLocalContext.h"
17#include <sstream>
18#include <iostream>
19
21
23using namespace HLT;
24
25/**********************************************************************
26 *
27 * Constructors and destructors
28 *
29 **********************************************************************/
30
32 ISvcLocator* pSvcLocator )
33 : base_class(name, pSvcLocator),
34 m_trigDecisionTool("Trig::TrigDecisionTool/TrigDecisionTool")
35{
36 // job option configurable properties
37 declareProperty("TrigDecisionTool", m_trigDecisionTool, "Tool handle to TDT/Navigation.");
38 declareProperty("ChainsRegex", m_chainsRegex="", "Keep only information related to this chains");
39 declareProperty("FeatureInclusionList", m_featureInclusionList, "This features will be kept. This setting overrules the FeatureExclusionList. Only list of types or type#key pairs are supported.");
40 declareProperty("FeatureExclusionList", m_featureExclusionList, "This features will be dropeed. It can be specified as * meaning all, or as a list of typenames, or typename#key pairs.");
41 declareProperty("ReportOperations", m_report=false, "Additional verbosity flag, when enabled the operations on trigger elements are reported (VERBOSE logging level)");
42
55
56
57 std::string possibleActions;
58 for ( auto a: m_actionsMap )
59 possibleActions += a.first +" ";
60 declareProperty("Actions", m_actions, "Operations which need to be done on the navigation"+possibleActions);
61}
62
63
64/**********************************************************************
65 *
66 * Initialization and Finalization
67 *
68 **********************************************************************/
69
71
72 ATH_MSG_DEBUG( "TrigNavigationThinningSvc::initialize()" << name() );
73
74 m_checkToolDeps = false;
75
76 // load the required tools
77 if( not m_trigDecisionTool.empty() ) {
78 if ( m_trigDecisionTool.retrieve().isFailure() ) {
79 ATH_MSG_FATAL ( "Unable to retrieve the TrigDecisionTool!" );
80 ATH_MSG_FATAL ( "Please check your job options file" );
81 return StatusCode::FAILURE;
82 }
83 ATH_MSG_INFO ( "Successfully retrieved the TrigDecisionTool!" );
84 }
85 else {
86 ATH_MSG_FATAL ( "Could not retrieve the TrigDecisionTool as it was not specified!" );
87 return StatusCode::FAILURE;
88 }
89
90 ATH_MSG_DEBUG ( "Leaving TrigNavigationThinningSvc::Initialize" );
91 // make sure that the inclusions/exclusions are self consistent i.e. they can not be sued at the same time
92 if ( m_featureExclusionList.size() and m_featureInclusionList.size() ) {
93 ATH_MSG_ERROR( "Can't use the features inclusion and exclusion lists at the same time.");
94 return StatusCode::FAILURE;
95 }
96
99 if ( m_featureKeepSet.size() or m_featureDropSet.size() ) {
100 ATH_MSG_DEBUG("Configured features removeal keep:" << m_featureInclusionList
101 << " drop: " << m_featureExclusionList );
102 } else {
103 if ( find(m_actions.begin(), m_actions.end(), "DropFeatures") != m_actions.end() ) {
104 ATH_MSG_FATAL("Dropping features is demanded but neither inclusion and exclusion lists are set");
105 return StatusCode::FAILURE;
106 }
107 }
108
109
110
111 // verify if all actions are possible
112 for ( auto& action: m_actions) {
113 if ( m_actionsMap.find(action) == m_actionsMap.end()) {
114 ATH_MSG_FATAL("Action not implemented (check for typo) " << action << " possible " << m_actions);
115 return StatusCode::FAILURE;
116 }
117 }
118 return StatusCode::SUCCESS;
119}
120
121
122StatusCode
124{
125 state.destinationNavigation.clear();
126 ATH_MSG_DEBUG ( "Navigation dropped entirely" );
127 return StatusCode::SUCCESS;
128}
129
130StatusCode
132{
133 state.destinationNavigation.clear();
134 std::vector<unsigned int> cuts;
135 std::vector<uint32_t> temp;
136 state.navigation.serialize(temp, cuts);
137 state.navigation.reset();
138 state.navigation.prepare();
140 ATH_MSG_DEBUG ( "Reloaded the navigation content in TDT (all clients will see reduced navigation content) ..." );
141 return StatusCode::SUCCESS;
142}
143
144
145StatusCode TrigNavigationThinningSvc::save(State& state) const {
146 std::vector<unsigned int> cuts;
147 state.navigation.serialize(state.destinationNavigation, cuts);
148 ATH_MSG_DEBUG ( "Saved the slimmed navigation" );
149 return StatusCode::SUCCESS;
150}
151
152StatusCode
154{
155 state.navigation.reset();
156 state.navigation.prepare();
158 ATH_MSG_DEBUG ( "Restored the original navigation" );
159 return StatusCode::SUCCESS;
160}
161
162
163
164StatusCode TrigNavigationThinningSvc::print(State& state) const {
165 ATH_MSG_DEBUG ( "Navigation printout \n" << state.navigation );
166 return StatusCode::SUCCESS;
167}
168
169StatusCode TrigNavigationThinningSvc::squeeze(State& state) const {
170 for ( auto te: state.navigation.getAllTEs() ) {
171 if ( state.navigation.isInitialNode(te)
172 or state.navigation.isRoINode(te)
173 or state.navigation.isTerminalNode(te)
174 or state.tesToProtect.find(te->getId()) != state.tesToProtect.end())
175 continue;
176 // if ( te->getId() == 4032407525 ) m_report = true;
177 CHECK( removeTriggerElement(state, te) );
178 // m_report = false;
179 }
180
181 return StatusCode::SUCCESS;
182}
183
184
186{
187 // turn the inclusion and exclusion lists into set of pairs <CLID, SubTypeIndex> of this collections which needs to be dropped
188 // in fact this a bit waste of time that we reclaulate this each time, but, one can imagine slimming events from different runs/configurations
189 // but then we sould have to check some configuration in data (i.e. SMK in the HLTResult, and recompute m_deletedFeatures only if it changes)
190 std::set<std::pair<CLID, uint16_t> > toDelete;
191 std::set<std::pair<CLID, uint16_t> > toRetain;
192
193 std::lock_guard<std::recursive_mutex> lock(state.navigation.getMutex());
194
195 const auto& holders = state.navigation.getHolderStorage().getAllHolders<HLTNavDetails::IHolder>();
196 if ( holders.empty() ) { // to prevent issues as in ATR-25282
197 ATH_MSG_ERROR("The navigation does not contain any features. This is likely a configuration problem.");
198 return StatusCode::FAILURE;
199 }
200
201 for( auto h : holders ) {
202 if(!h) { // check if h is null
203 ATH_MSG_WARNING("holder.second is null pointer; skipping...");
204 continue;
205 }
206 //ATH_MSG_VERBOSE("Checking what to do with "
207 // << h->collectionName()+"#"+h->key());
208 // check if this needs to be kept
209 if ( not m_featureKeepSet.empty() ) {
210 if ( m_featureKeepSet.count(h->collectionName())
211 || m_featureKeepSet.count(h->key()) ) {
212 toRetain.insert(std::make_pair(h->typeClid(), h->subTypeIndex() ));
213 ATH_MSG_DEBUG("will be keeping references associated to: " << h->collectionName()<<"#"<<h->key() << " clid: " << h->typeClid() );
214 }
215 }
216 // check if this needs to be dropped
217 if ( not m_featureDropSet.empty() ) {
218 if ( m_featureDropSet.count(h->collectionName())
219 || m_featureDropSet.count(h->key()) ) {
220 toDelete.insert(std::make_pair(h->typeClid(), h->subTypeIndex() ));
221 ATH_MSG_DEBUG("will be dropping references associated to: " << h->collectionName()<<"#"<<h->key() );
222 }
223 }
224 }
225
226
227 if ( not toRetain.empty() )
228 return retainFeatures(state, toRetain);
229 if ( not toDelete.empty() )
230 return removeFeatures(state, toDelete);
231
232 // now that we've removed them from the tree, we need to remove them from
233 // the navigation structure as well. We do this by finding the holders that
234 // match the deleted labels and removing them.
235 // to be implemented !!!
236
237 return StatusCode::SUCCESS;
238}
239
240
242 for ( auto te: state.navigation.getAllTEs() ) {
243 if ( state.navigation.isRoINode(te) )
244 CHECK( removeTriggerElement(state, te) );
245 }
246 return StatusCode::SUCCESS;
247}
248
250 for ( auto te: state.navigation.getAllTEs() ) {
251 if ( state.navigation.isRoINode(te)
252 and te->getRelated(TriggerElement::seedsRelation).empty() )
253 CHECK( removeTriggerElement(state, te) );
254 }
255 return StatusCode::SUCCESS;
256}
257
259 for ( auto te: state.navigation.getAllTEs() ) {
260 if ( te->getFeatureAccessHelpers().empty() )
261 CHECK( removeTriggerElement(state, te) );
262 }
263 return StatusCode::SUCCESS;
264}
265
266
268 if ( m_chainsRegex.empty() ) {
269 return StatusCode::SUCCESS;
270 }
271 // now run over the tree and drop alle TEs except RoIs and intial which are not in the TEs to protect
272 for ( auto te: state.navigation.getAllTEs() ) {
273 if ( state.navigation.isInitialNode(te)
274 or state.navigation.isRoINode(te) ) {
275 continue;
276 }
277 if ( state.tesToProtect.find(te->getId()) == state.tesToProtect.end() ) {
278 CHECK( removeTriggerElement(state, te));
279 }
280 }
281 return StatusCode::SUCCESS;
282}
283
284
285
287StatusCode TrigNavigationThinningSvc::doSlimming( const EventContext& ctx,
288 std::vector<uint32_t>& slimmed_and_serialized) const {
289
290 ATH_MSG_DEBUG(name() << " is obtaining the TrigNavigationThinningSvc lock in slot " << ctx.slot() << " for event " << ctx.eventID().event_number() );
291 std::lock_guard<std::mutex> lock(TrigNavigationThinningSvcMutex::s_mutex);
292
293 // grab the navigation
294 auto navAccess = m_trigDecisionTool->ExperimentalAndExpertMethods();
295 // protected by above lock
296 HLT::NavigationCore *cnav ATLAS_THREAD_SAFE = const_cast<HLT::NavigationCore*>(navAccess.getNavigation());
297
298 if(cnav == 0) {
299 ATH_MSG_WARNING ( "Could not get navigation from Trigger Decision Tool" );
300 ATH_MSG_WARNING ( "Navigation will not be slimmed in this event" );
301 ATH_MSG_DEBUG(name() << " is releasing the TrigNavigationThinningSvc lock");
302 return StatusCode::SUCCESS;
303 }
304
305 State state (ctx, *cnav, slimmed_and_serialized);
307 {
308 state.originalNavigation.clear();
309 std::vector<uint32_t> cuts;
310 cnav->serialize(state.originalNavigation, cuts);
311 }
312
313 for ( auto& action: m_actions ) {
314 ATH_MSG_DEBUG("Applying action " << action << " on the navigation ");
315 auto ifunc = m_actionsMap.find (action);
316 if (ifunc != m_actionsMap.end()) {
317 auto function = ifunc->second;
318 CHECK( (this->*function)(state) );
319 }
320 }
321 ATH_MSG_DEBUG(name() << " is releasing the TrigNavigationThinningSvc lock");
322 return StatusCode::SUCCESS;
323}
324
325
326
328 return StatusCode::SUCCESS;
329}
330
331
332
333StatusCode
335 // remember the configured chain names, as they will be useful later
336 // ??? Originally, this was done once and cached in the tool.
337 // If this takes too long, consider storing it in the detector store.
338 auto chainGroup = m_trigDecisionTool->getChainGroup(m_chainsRegex);
339 ATH_MSG_DEBUG("Will keep information related to this chains" << chainGroup->getListOfTriggers());
340 auto confTEs = chainGroup->getHLTTriggerElements();
341 for ( auto& vec: confTEs) {
342 for ( auto confTEPtr: vec) {
343 state.tesToProtect.insert(confTEPtr->id());
344 }
345 }
346 return StatusCode::SUCCESS;
347}
348
350 TriggerElement *te,
351 bool propagateFeatures) const {
352 // refuse to remove the initial node
353 if(state.navigation.isInitialNode(te)) {
354 return StatusCode::SUCCESS;
355 }
356 if ( m_report ) ATH_MSG_VERBOSE("Removing TE of ID: " << te->getId() );
357
358 // mark the element as transient to prevent it from being serialized
359 te->setTransient();
360
361
362 // propagate the features to its children
363 if ( propagateFeatures )
365
366
367
368 if ( m_report ) ATH_MSG_VERBOSE("Removeing TE of ID: " << te->getId() << " removing same RoI relations" );
369 // for those in the same RoI, we need only remove the relationship from ones who are related
370 const std::vector<TriggerElement*>& sameRoI = te->getRelated(TriggerElement::sameRoIRelation);
371
372 for( auto nodeInRoI : sameRoI ) {
373 if ( m_report ) ATH_MSG_VERBOSE("Removeing TE of ID: " << te->getId() << " bypassing same RoI relation " );
374 // get the relations, and remove the ones that point to te
375 std::vector<TriggerElement*>& relations = nodeInRoI->m_relations[ TriggerElement::sameRoIRelation ];
376 CHECK( removeTriggerElementFromVector (te, relations) );
377 }
378
379 // for those who te is seededBy, we need to remove the seeds relation, and propagate it down
380 // (if te is not terminal)
381
382 std::vector<TriggerElement*> seededBy = te->m_relations[TriggerElement::seededByRelation];
383
384 for(auto seededByNode: seededBy ) {
385
386 // get the relations and remove the ones that point to te
387 std::vector<TriggerElement*>& relations = seededByNode->m_relations[ TriggerElement::seedsRelation ];
388 CHECK( removeTriggerElementFromVector (te, relations) );
389
390
391
392 // now add all the nodes te seeds onto the node we just removed the seeds relation from
393 if(!state.navigation.isTerminalNode(te))
395 }
396
397 // for those who te seeds, we need to remove the seededBy relation, and propagate it up
398 // (if te is not the inital node - hey, you never know!)
399
400 std::vector<TriggerElement*>& seeds = te->m_relations[TriggerElement::seedsRelation];
401
402 for( auto seedsNode: seeds ) {
403
404 // get the relations and remove the ones that point to te
405 std::vector<TriggerElement*>& relations = seedsNode->m_relations[ TriggerElement::seededByRelation ];
406 CHECK ( removeTriggerElementFromVector(te, relations) );
407
408 // now add all the nodes te seeds onto the node we just removed the seeds relation from
409 if(!state.navigation.isInitialNode(te))
411 }
412
413 return StatusCode::SUCCESS;
414}
415
416/**********************************************************************
417 *
418 * Feature Removal
419 *
420 **********************************************************************/
422 const std::set<std::pair<CLID, uint16_t> >& toDelete) const {
423 // we have the following problem:
424 // (a) features are stored as a vector where order can possibly matter
425 // (b) its very time consuming to delete items from the middle of a vector
426 // (c) a large fraction of elements will not have any features deleted
427 //
428 // To handle this, we're going to build an array that keeps track of
429 // whether an element needs be deleted. If none do, nothing gets changed.
430 // If some do, we build a new vector and copy it over. This prevents
431 // the big time sink from deleting elements in the middle of a vector.
432
433 // another option would be to build a new vector when using inclusion
434 // lists and remove elements when using exclusion lists
435 ATH_MSG_DEBUG("Will remove " << toDelete.size()<< " feature type/key");
436 using namespace HLT;
437 for (auto te: state.navigation.getAllTEs()) {
438 for ( auto& fea: te->getFeatureAccessHelpers() ) {
439 if ( toDelete.find( std::make_pair(fea.getCLID(), fea.getIndex().subTypeIndex()) ) != toDelete.end() )
440 fea.setForget(true); // when we mark this then the serialization of TEs will simpley skip this one, easy, no
441 }
442 }
443 // get back here
444 // get rid of the holders themselves
445 //m_navigation->m_featuresByIndex[ h->typeClid() ].erase( h->subTypeIndex() ); // Erasing an element of the map we're looping over
446 //m_navigation->m_featuresByLabel.at( h->typeClid() ).erase( h->label() ); // Use new C++11 map accessor (does bounds check)
447 // delete holder.second;
448
449 return StatusCode::SUCCESS;
450}
451
452
454 const std::set<std::pair<CLID, uint16_t> >& toRetain) const {
455 ATH_MSG_DEBUG("Will retain " << toRetain.size()<< " feature type/key");
456 using namespace HLT;
457 for (auto te: state.navigation.getAllTEs()) {
458 for ( auto& fea: te->getFeatureAccessHelpers() ) {
459 if ( toRetain.find( std::make_pair(fea.getCLID(), fea.getIndex().subTypeIndex()) ) == toRetain.end() )
460 fea.setForget(true); // when we mark this then the serialization of TEs will simpley skip this one, easy, no
461 }
462 }
463 return StatusCode::SUCCESS;
464
465}
466
467StatusCode
469 TriggerElement *) {
470 ATH_MSG_DEBUG ( "Running the adjustIndicesAfterThinning" );
471
472 for ( auto te: state.navigation.getAllTEs() ) {
473 size_t featuresCount = std::count_if(te->getFeatureAccessHelpers().begin(),
474 te->getFeatureAccessHelpers().end(),
475 [](const TriggerElement::FeatureAccessHelper& fea){ return fea.forget(); }
476 );
477 if( featuresCount == 0 ) {
478 CHECK( removeTriggerElement( state, te, false ) );
479 }
480 }
481 return StatusCode::SUCCESS;
482}
483
484/**********************************************************************
485 *
486 * Generic Helper Functions
487 *
488 **********************************************************************/
489StatusCode TrigNavigationThinningSvc::removeTriggerElementFromVector(TriggerElement *te, std::vector<TriggerElement*>& v) const {
490
491 if( v.empty())
492 return StatusCode::SUCCESS;
493
494 std::vector<TriggerElement*>::iterator newend = std::remove( v.begin(), v.end(), te);
495 v.erase(newend, v.end());
496
497 return StatusCode::SUCCESS;
498}
499
501 TriggerElement *te,
502 std::vector<std::string> *inclusionList, std::vector<std::string> *exclusionList) {
503
504 // if the inclusion list exists, then we use that
505 if(inclusionList && inclusionList->size() > 0) {
506
507 // check if the trigger element has a feature that is included in the list
508 int onExclusionList = 0;
509 for(std::vector< TriggerElement::FeatureAccessHelper >::const_iterator iter =
510 te->getFeatureAccessHelpers().begin();
511 iter != te->getFeatureAccessHelpers().end(); ++iter) {
512 // grab the label and check if it was found in the inclusion list
513 if(std::find(inclusionList->begin(), inclusionList->end(), SlimmingHelper::getLabel(state.navigation, *iter )) != inclusionList->end())
514 return true;
515 // now find if its in the exclusion list
516 if(exclusionList && std::find(exclusionList->begin(), exclusionList->end(),
517 SlimmingHelper::getLabel( state.navigation, *iter )) != exclusionList->end())
518 onExclusionList = 1;
519 }
520
521 // if it has a feature on the exclusion list, and none on the inclusion list,
522 // it should be excluded
523 if(onExclusionList)
524 return false;
525
526 // we've gone through the feature list, and nothing was on the exclusion list,
527 // so we should keep it
528 return true;
529 }
530
531 // if we get here, then there's no inclusionList, so we need to use the exclusion list
532
533 // check if it exists - if it doesn't, pass everything
534 if(!exclusionList || exclusionList->size() == 0)
535 return true;
536
537 for(std::vector< TriggerElement::FeatureAccessHelper >::const_iterator iter =
538 te->getFeatureAccessHelpers().begin();
539 iter != te->getFeatureAccessHelpers().end(); ++iter) {
540 // grab the label and check if it was found in the exclusion list
541 if(std::find(exclusionList->begin(), exclusionList->end(), SlimmingHelper::getLabel(state.navigation, *iter )) != exclusionList->end())
542 return false;
543 }
544
545 // if we've made it here, its passed the exclusion list and so should be included
546 return true;
547
548}
549
551 TriggerElement *te,
552 std::vector<TriggerElement*> *inclusionList,
553 std::vector<TriggerElement*> *exclusionList) {
554
555 if(!te)
556 return false;
557
558 // this function never allows inital nodes or RoI nodes to be removed
559 if( state.navigation.isInitialNode(te) || state.navigation.isRoINode(te) )
560 return true;
561
562 // if the inclusion list exists, then we use that
563 // If its on the inclusion list, its kept for sure
564 // If its on the exclusion list, its only kept if
565 // its not on the inclusion list.
566 if(inclusionList && inclusionList->size() > 0) {
567
568 // check if the element is in the list
569 if(std::find_if(inclusionList->begin(), inclusionList->end(),
570 TriggerElementFind(te)) != inclusionList->end())
571 return true;
572 // now, check if its in the exclusion list
573 if(exclusionList && std::find_if(exclusionList->begin(), exclusionList->end(),
574 TriggerElementFind(te)) != exclusionList->end())
575 return false;
576 // if its on neither list, keep it
577 return true;
578 }
579
580 // if we get here, then there's no inclusionList, so we need to use the exclusion list
581
582 // check if it exists - if it doesn't, pass everything
583 if(!exclusionList || exclusionList->size() == 0)
584 return true;
585
586 // check if the te belongs to the exclusion list
587 if(std::find_if(exclusionList->begin(), exclusionList->end(),
588 TriggerElementFind(te)) != exclusionList->end()) {
589 return false;
590 }
591
592 // if we've made it here, its passed the exclusion list and so should be included
593 return true;
594
595}
596
597StatusCode
599
600 if ( not te )
601 return StatusCode::SUCCESS;
602
603 const std::vector<TriggerElement::FeatureAccessHelper>& features = te->getFeatureAccessHelpers() ;
604
605 const std::vector<TriggerElement*> children = te->getRelated(TriggerElement::seedsRelation);
606 for( auto ch: children ) {
607 if ( m_report ) ATH_MSG_VERBOSE("Propagating features to child: " << ch << " " << ch->getId() );
608 // add the parents features to the front of the child features list features list
609 // skip this FEAs which are anyway to be discarded
610 for( auto& fea: features ) {
611 if ( fea.forget() )
612 continue;
613 if ( m_report ){
614 std::stringstream ss;
615 ss << fea;
616 ATH_MSG_VERBOSE("Propagating feature " << ss.str() );
617 }
618 ch->getFeatureAccessHelpers().insert(ch->getFeatureAccessHelpers().begin(), fea );
619 }
620 // te->getFeatureAccessHelpers().insert((*iter)->getFeatureAccessHelpers().begin(), features.begin(), features.end());
621 }
622 return StatusCode::SUCCESS;
623}
624
626
627 // return the id the RoI node
628 if(!te) {
629 m_id = 0;
630 m_RoI = 0;
631 }
632 else {
633 m_id = te->getId();
634
635 const TriggerElement *mother = te;
636 m_RoI = te;
637 while( mother->getRelated(TriggerElement::seededByRelation).size() > 0 ) {
638 m_RoI = mother;
639 mother = m_RoI->getRelated(TriggerElement::seededByRelation)[0];
640 }
641 }
642}
643
645
646 if(!te)
647 return 0;
648
649 // if we didn't initialize the RoI, then we can't match
650 if(!m_RoI)
651 return false;
652
653 // check that the id's match
654 if(te->getId() != m_id)
655 return 0;
656
657 // Note that we can have elements with the same id as long as they are in difference RoI's
658 // Thus, we must ensure that the RoI's are the same
659
660 // Find the RoI
661 const TriggerElement *mother = te;
662 const TriggerElement *RoI = te;
663
664 while( mother->getRelated(TriggerElement::seededByRelation).size() > 0 ) {
665 RoI = mother;
667 }
668
669 // now, RoI equality is defined by all the features that match, where a feature
670 // match is given by a matching CLID, subtypeIndex, and objectIndex
671
672 const std::vector< TriggerElement::FeatureAccessHelper > firstFeatures = m_RoI->getFeatureAccessHelpers();
673 const std::vector< TriggerElement::FeatureAccessHelper > secondFeatures = m_RoI->getFeatureAccessHelpers();
674
675 if(firstFeatures.size() != secondFeatures.size())
676 return false;
677
678 for(unsigned int i = 0; i < firstFeatures.size(); i++) {
679 TriggerElement::FeatureAccessHelper firstFeature = firstFeatures[i];
680 TriggerElement::FeatureAccessHelper secondFeature = secondFeatures[i];
681
682 if(firstFeature.getCLID() != secondFeature.getCLID())
683 return false;
684 if(firstFeature.getIndex().subTypeIndex() != secondFeature.getIndex().subTypeIndex())
685 return false;
686 if(firstFeature.getIndex().objectsBegin() != secondFeature.getIndex().objectsBegin())
687 return false;
688 if(firstFeature.getIndex().objectsEnd() != secondFeature.getIndex().objectsEnd())
689 return false;
690
691 }
692
693 // if we've made it this far, all the features match (what should we do if there
694 // are no features?), so we have found a match!
695
696 return true;
697
698}
699
700
701namespace {
702
703 static const std::size_t RemovedIdx = SG::ThinningDecisionBase::RemovedIdx;
704 struct IndexRecalculator {
705 IndexRecalculator( const SG::ThinningDecisionBase* dec )
706 : m_dec(dec)
707 {}
708
709 size_t getNewIndex(size_t oldIndex) {
710 if ( oldIndex >= m_indices.size() ) {
711 expand(oldIndex);
712 }
713 return m_indices[oldIndex];
714 }
715
716 void expand(size_t maxIndex ) {
717 const size_t checkedSoFar = m_validIndices.size();
718 m_indices.resize(maxIndex+1, RemovedIdx);
719 m_validIndices.resize(maxIndex+1);
720
721 for ( size_t toScan = checkedSoFar; toScan <= maxIndex; ++ toScan ) {
722 size_t newIndex = m_dec->index(toScan);
723 m_validIndices[toScan] = newIndex;
724 }
725
726 for ( size_t toScan = checkedSoFar; toScan <= maxIndex; ++toScan ) {
727 m_indices[toScan] = std::count_if(m_validIndices.begin(), m_validIndices.begin()+toScan,
728 [](const size_t x){ return x != RemovedIdx; } );
729 }
730
731 }
732
733 std::vector<size_t> m_indices = {0}; // the 0 index will be 0 no mater what is slimmed
734 std::vector<size_t> m_validIndices; // the 0 index will be 0 no mater what is slimmed
735 const SG::ThinningDecisionBase* m_dec;
736 };
737}
738
740 const EventContext& ctx = Gaudi::Hive::currentContext();
741 ATH_MSG_DEBUG ( "Running the syncThinning" );
742
743 std::lock_guard<std::recursive_mutex> lock(state.navigation.getMutex());
744
745 const auto& holders = state.navigation.getHolderStorage().getAllHolders<HLTNavDetails::IHolder>();
746 if ( holders.empty() ) { // to prevent issues as in ATR-25282
747 ATH_MSG_ERROR("The navigation does not contain any features. This is likely a configuration problem.");
748 return StatusCode::FAILURE;
749 }
750
751 for(auto holder : holders) {
752 const IProxyDict* ipd = Atlas::getExtendedEventContext(ctx).proxy();
753 if ( not ipd->proxy(holder->containerClid(), holder->label() ) ) {
754 ATH_MSG_DEBUG("Skipping feature missing in the store: " << holder->label());
755 continue;
756 }
757 holder->syncWithSG();
758 const SG::ThinningDecisionBase* dec =
759 SG::getThinningDecision (ctx, holder->label());
760 if ( dec ) {
761 ATH_MSG_DEBUG ( "Thinning occured for this container" << *holder <<", going to ajust the indices" );
762 // ThinningDecisionBase::index method returns the valid new index for unslimmed object and an invalid index ThinningDecisionBase::RemovedIndex for the ones that were removed
763 // The way to calulate new indexes for the ranges describing ROIs (X,Y) is to count the number valid indexes from X to 0 and from Y to 0
764 // This would be quite inefficient so we need to make a vector wiht new indexes
765 // this vector in the end will be of size equal to the original collection and at position X will have new values.
766 // Hoever the difficulty is that we are not able to obtain the size of the collection and we need to build this vector as we meet the indexs during
767 // the scan of TEs.
768 // Since this is quite tricky code it is outsourced to a helper class IndexRecalculator.
769
770 IndexRecalculator recalculator( dec );
771 // now we need to go over the TEs
772 for ( const auto& te: state.navigation.getAllTEs() ) {
773 for ( auto& fea: te->getFeatureAccessHelpers() ) {
774 if ( fea.getCLID() == holder->typeClid()
775 and fea.getIndex().subTypeIndex() == holder->subTypeIndex() ) {
776 uint32_t begin = fea.getIndex().objectsBegin();
777 uint32_t end = fea.getIndex().objectsEnd();
778 uint32_t newEnd = recalculator.getNewIndex(end);
779 uint32_t newBegin = recalculator.getNewIndex(begin);
780
782 idx.updateBeginAndEnd(newBegin, newEnd);
783 //ATH_MSG_DEBUG( "Indices changed to " << newBegin << " " << newEnd);
784
785 }
786 }
787 }
788
789 } // if thinning occures
790 else {
791 // ATH_MSG_DEBUG("Thinning did not occure on the " << * holder );
792 }
793 } // holder loop
794 return StatusCode::SUCCESS;
795}
796
797
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
std::vector< size_t > vec
#define CHECK(...)
Evaluate an expression and check for errors.
static Double_t a
static Double_t ss
Hold thinning decisions for one container.
#define x
Define macros for attributes used to control the static checker.
#define ATLAS_THREAD_SAFE
The NavigationCore class, adds on top of the TrigNavStructure the EDM read-only handling.
virtual void reset(bool inFinalize=false)
resets all the navigation, goes to the factory and asks to withdraw all produced objects
virtual bool serialize(std::vector< uint32_t > &output) const
method serizlizes the navigation structure The structure is serrizlized in following order ....
virtual void prepare()
prepapres the navigation for next event
bool deserialize(const std::vector< uint32_t > &input)
std::vector< HolderType * > getAllHolders() const
static bool isInitialNode(const TriggerElement *te)
queries if node is an initial one
std::vector< TriggerElement * > & getAllTEs()
access needed by slimming tools.
static bool isTerminalNode(const TriggerElement *te)
queries if node is terminal (no more TriggerElement are seeded by it)
std::recursive_mutex & getMutex()
static bool isRoINode(const TriggerElement *te)
queries if node is an RoI type one
TrigHolderStructure & getHolderStorage()
the FeatureAccessHelper is a class used to keep track of features attached to this TE.
const ObjectIndex & getIndex() const
index in the external ojects array
Helper class for conversion from/to int stored in TE and pair of ints used in Navigation Object point...
sub_index_type subTypeIndex() const
to get collection index
index_type objectsEnd() const
to get object number in th ecollection
index_type objectsBegin() const
to get object number in th ecollection
TriggerElement is the basic ingreedient of the interface between HLT algorithms and the navigation It...
@ sameRoIRelation
equilateral relation of all TEs rooted in one RoI
const std::vector< TriggerElement * > & getRelated(Relation rel) const
returns reference to the likns to other TriggerElements related by relation r
const std::vector< FeatureAccessHelper > & getFeatureAccessHelpers() const
returns all features which ara attached to this TE
std::map< Relation, std::vector< TriggerElement * > > m_relations
relations holder (features outside)
virtual SG::DataProxy * proxy(const CLID &id, const std::string &key) const =0
Get proxy with given id and key.
Hold thinning decisions for one container.
static const std::size_t RemovedIdx
Flag used to show that an index has been thinned away.
Used to compare pointers of TriggerElements.
std::vector< std::string > m_actions
StatusCode lateFillConfiguration(State &state) const
configures at the first event
StatusCode syncThinning(State &state) const
reset indexes in the after the thinning
bool toBeIncluded(State &state, HLT::TriggerElement *te, std::vector< std::string > *inclusionList, std::vector< std::string > *exclusionList)
Returns true if the TriggerElement should be included in the navigation tree and false if it should n...
StatusCode save(State &state) const
Save the result of the slimming in the doSlimming argument (vector<uint32_t>)
StatusCode drop(State &state) const
clear the result of the slimming in the doSliming argument (vector<uint32_t>) Makes no sense to combi...
virtual StatusCode finalize() override
StatusCode removeTriggerElement(State &state, HLT::TriggerElement *te, bool propagateFeatures=true) const
Removes the passed trigger element from the navigation structure by removing all references to it in ...
std::map< std::string, Action > m_actionsMap
StatusCode removeFeaturelessTriggerElements(State &state, HLT::TriggerElement *te=0)
Removes all trigger elements with no features from the navigation structure.
StatusCode dropRoIs(State &state) const
Removes RoI nodes, rather aggressive option, should be use as one of last actions as it makes impossi...
StatusCode dropChains(State &state) const
remove info not related to the specified chains
StatusCode removeFeatures(State &state, const std::set< std::pair< CLID, uint16_t > > &doDelete) const
This is a helper function for removeFeatures(HLT::NavigationCore*, ...).
std::vector< std::string > m_featureInclusionList
StatusCode dropFeatures(State &state) const
Removes references to features from the navigation structure.
virtual StatusCode doSlimming(const EventContext &, std::vector< uint32_t > &slimmed_and_serialized) const override
StatusCode retainFeatures(State &state, const std::set< std::pair< CLID, uint16_t > > &toRetain) const
This is a helper function for removeFeatures(HLT::NavigationCore*, ...).
virtual StatusCode initialize() override
StatusCode reload(State &state) const
Reload the slimmed navigation in TDT so that all clients of current job see the chage.
std::set< std::string > m_featureKeepSet
computed from above
StatusCode squeeze(State &state) const
Remove intermediate TEs leaving very flat structure with event node, rois and terminals.
StatusCode dropFeatureless(State &state) const
Removes TEs which have no features (combine wiht squeeze)
StatusCode print(State &state) const
StatusCode removeTriggerElementFromVector(HLT::TriggerElement *te, std::vector< HLT::TriggerElement * > &v) const
Removes all instances of the supplied TriggerElement from the supplied vector.
StatusCode propagateFeaturesToChildren(const HLT::TriggerElement *te) const
Propagates the features on given TE to its children.
bool m_report
TE operations verbosity flag.
StatusCode dropEmptyRoIs(State &state) const
Removes RoI nodes, which do not seed anything.
std::vector< std::string > m_featureExclusionList
ToolHandle< Trig::TrigDecisionTool > m_trigDecisionTool
std::set< std::string > m_featureDropSet
computed from above
TrigNavigationThinningSvc(const std::string &name, ISvcLocator *pSvcLocator)
StatusCode restore(State &state) const
Restore the original navigation structure.
Helper function to get a label for a feature.
Helpers to retrieve the current thinning cache from the event context.
std::string find(const std::string &s)
return a remapped string
Definition hcg.cxx:138
const ExtendedEventContext & getExtendedEventContext(const EventContext &ctx)
Retrieve an extended context from a context object.
It used to be useful piece of code for replacing actual SG with other store of similar functionality ...
const SG::ThinningDecisionBase * getThinningDecision(const EventContext &ctx, const std::string &key)
Retrieve the current thinning decision for key.
DataModel_detail::iterator< DVL > remove(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end, const T &value)
Specialization of remove for DataVector/List.
std::vector< uint32_t > & destinationNavigation
std::set< HLT::te_id_type > tesToProtect