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