ATLAS Offline Software
Loading...
Searching...
No Matches
PrescalingTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4#include "PrescalingTool.h"
5
8
9#include "GaudiKernel/IToolSvc.h"
10#include "CLHEP/Random/RandomEngine.h"
11#include "CLHEP/Random/Ranlux64Engine.h"
12
13
14const std::function< CLHEP::HepRandomEngine*(void) > PSTRanluxFactory = []()->CLHEP::HepRandomEngine*{
15 return new CLHEP::Ranlux64Engine();
16};
17
18
20 const std::string& name,
21 const IInterface* parent ) :
22 base_class(type, name, parent),
23 m_RNGEngines( PSTRanluxFactory, SG::getNSlots() ) {}
24
25
27 ATH_CHECK(m_hltPrescaleSetInputKey.initialize( ! m_hltPrescaleSetInputKey.key().empty() ));
28 ATH_CHECK( m_HLTMenuKey.initialize() );
29 ATH_CHECK( m_eventInfoKey.initialize() );
30
31 if ( !m_monTool.empty() ) {
32 ATH_CHECK(m_monTool.retrieve());
33 }
34
35 if (m_keepUnknownChains.value()) {
36 ATH_MSG_WARNING(m_keepUnknownChains.name() << " is set to True. "
37 << "This is OK for testing but do not use this in production");
38 }
39 m_prescaleForUnknownChain = { m_keepUnknownChains.value(), (m_keepUnknownChains.value() ? 1.0 : -1.0) };
40 m_costChainID = HLT::Identifier("HLT_noalg_CostMonDS_L1All");
41 return StatusCode::SUCCESS;
42}
43
44
46
47 // Cleanup in case there was a stop/start transition
48 m_CPSGroups.clear();
49 m_nonCPSChains.clear();
50
52 ATH_CHECK( hltMenuHandle.isValid() );
53
54 std::map<std::string, std::set<std::string>> l1SeedsCheckForCPS;
55 for ( const TrigConf::Chain& chain: *hltMenuHandle ) {
56 HLT::Identifier chainID{ chain.name() };
57 int isCPS = 0;
58 for ( const auto& group: chain.groups() ) {
59 if ( group.find("CPS") != std::string::npos) {
60 m_CPSGroups[group].push_back( chainID );
61 l1SeedsCheckForCPS[group].insert(chain.l1item());
62 isCPS++;
63 }
64 }
65 if ( isCPS ==0 ) {
66 m_nonCPSChains.insert( chainID );
67 }
68 if ( isCPS > 1 ) {
69 ATH_MSG_ERROR("Chain " << chainID << " belongs to more than one CPS groups");
70 return StatusCode::FAILURE;
71 }
72 }
73
74 for ( auto [group, chains]: m_CPSGroups ) {
75 if ( chains.size() == 1 ) {
76 ATH_MSG_ERROR("Only one chain " << chains.front() << " in CPS group " << group << " that makes no sense");
77 return StatusCode::FAILURE;
78 }
79 }
80
81 for ( auto [group, l1SeedsSet]: l1SeedsCheckForCPS) {
82 if ( l1SeedsSet.size() != 1 ) {
83 ATH_MSG_ERROR("Chains in CPS group " << group << " have several different L1 seeds "
84 << std::vector<std::string>(l1SeedsSet.begin(), l1SeedsSet.end()));
85 return StatusCode::FAILURE;
86 }
87 }
88
89 return StatusCode::SUCCESS;
90}
91
92
93StatusCode PrescalingTool::prescaleChains( const EventContext& ctx,
94 const HLT::IDVec& initiallyActive,
95 HLT::IDVec& remainActive,
96 bool forExpressStream) const {
97 if ( initiallyActive.empty() ) {
98 return StatusCode::SUCCESS;
99 }
100
101 // clear the output just in case
102 remainActive.clear();
103
104 if ( m_hltPrescaleSetInputKey.key().empty() ) {
105 // if no prescaling key is configured, treat all prescales according to the property KeepUnknownChains
106 if( m_keepUnknownChains ) {
107 remainActive.reserve( initiallyActive.size() );
108 for( const auto & ch : initiallyActive ) {
109 remainActive.push_back(ch);
110 }
111 }
112 return StatusCode::SUCCESS;
113 }
114
116 ATH_CHECK(hltPrescaleSet.isValid());
117
118 // access to psk
119 ATH_MSG_DEBUG("Using HLT PSK " << hltPrescaleSet->psk());
120 auto mon_lb = Monitored::Scalar<int>("LB", [&](){ return ctx.eventID().lumi_block(); });
121 auto mon_psk = Monitored::Scalar<std::string>("HLTPSK", [&](){ return std::to_string(hltPrescaleSet->psk()); });
122 auto mon = Monitored::Group(m_monTool, mon_lb, mon_psk);
123
124 // prepare the result
125 remainActive.reserve( initiallyActive.size() );
126
127 // create the seed from the event time
134 auto eventInfoHandle = SG::makeHandle( m_eventInfoKey, ctx );
135 CHECK( eventInfoHandle.isValid() );
136 size_t seed = eventInfoHandle->timeStamp() ^ eventInfoHandle->timeStampNSOffset();
137
138 CLHEP::HepRandomEngine* engine = m_RNGEngines.getEngine( ctx );
139 engine->setSeed( seed, 0 );
140
141 auto getPrescale = [&](const HLT::Identifier& ch) -> const TrigConf::HLTPrescalesSet::HLTPrescale& {
142 try {
143 if (forExpressStream) {
144 return hltPrescaleSet->prescale_express( ch.numeric() );
145 } else {
146 return hltPrescaleSet->prescale( ch.numeric() );
147 }
148 } catch(const std::out_of_range & ex) {
149 // if chain with that name is not found in the prescale set
150 if (m_keepUnknownChains.value()) {
151 ATH_MSG_DEBUG("No prescale value for chain " << ch << ", keeping it because "
152 << m_keepUnknownChains.name() << "=" << m_keepUnknownChains.value());
153 } else {
154 ATH_MSG_ERROR("No prescale value for chain " << ch);
155 }
156 }
158 };
159
160 auto decisionPerChain = [&](const HLT::Identifier& ch, double prescaleValue ) -> bool {
161 auto flat = engine->flat();
162 if(ch == m_costChainID) { // this is to explicitly monitor the cost chain
163 auto mon_rndm = Monitored::Scalar<double>("Random", flat);
164 Monitored::Group(m_monTool, mon_rndm);
165 }
166 return flat < 1./ prescaleValue;
167 };
168
169 struct ChainAndPrescale {
172 double relativePrescale{};
173 };
174
175 for ( auto [groupName, chainIDs]: m_CPSGroups) {
176 // check if this group is seeded
177 // only need to find one CPS chain if initiallyActive is L1seeded HLT id's
178 if ( forExpressStream || std::find(initiallyActive.begin(), initiallyActive.end(), chainIDs.front()) != initiallyActive.end() ) {
179 std::vector<ChainAndPrescale> psValueSorted;
180 for ( const HLT::Identifier& ch: chainIDs ) {
181 // in express stream initiallyActive are HLT accept id's, but chainIDs contain all chains in the group
182 // regardless of HLT accept; skip the HLT reject id's to ensure remainActive is a subset of initiallyActive
183 if ( forExpressStream && std::find(initiallyActive.begin(), initiallyActive.end(), ch) == initiallyActive.end() ) {
184 continue;
185 }
186 auto ps = getPrescale(ch);
187 if ( ps.enabled ) // exclude prescaled out chains
188 psValueSorted.emplace_back( ChainAndPrescale({ch, ps}) );
189 }
190 if ( psValueSorted.empty() ) { // sometimes all chains may be presscaled out/disabled
191 continue;
192 }
193 std::sort(psValueSorted.begin(), psValueSorted.end(), [](const ChainAndPrescale& a, const ChainAndPrescale& b){
194 return a.ps.prescale < b.ps.prescale;
195 });
196 // setup relative prescales
197 // the first chain (with the lowest PS is relative w.r.t the all events)
198 psValueSorted.front().relativePrescale = psValueSorted.front().ps.prescale;
199 if ( psValueSorted.size() > 1 ) {
200 for ( auto i = psValueSorted.begin()+1; i < psValueSorted.end(); ++i ) {
201 i->relativePrescale = i->ps.prescale / (i-1)->ps.prescale ;
202 }
203 }
204 if (msgLvl(MSG::DEBUG)) {
205 ATH_MSG_DEBUG("Chains in CPS group '"<< groupName <<"' sorted by PS : ");
206 for ( const ChainAndPrescale& ch: psValueSorted ) {
207 ATH_MSG_DEBUG(" " << ch.id << " " << (ch.ps.enabled ?
208 "prescale relative to the above " + std::to_string(ch.relativePrescale) :
209 "disabled"));
210 }
211 }
212 // do actual prescaling
213 for ( const ChainAndPrescale& ch: psValueSorted ) {
214 const bool decision = decisionPerChain(ch.id, ch.relativePrescale);
215 if ( not decision ) {break;}
216 remainActive.push_back( ch.id );
217 }
218 }
219 }
220
221 // go through all active chains that are not in CPS groups
222 for ( const HLT::Identifier& ch: m_nonCPSChains ) {
223 if ( std::find( initiallyActive.begin(), initiallyActive.end(), ch ) != initiallyActive.end() ) {
224 auto prescale = getPrescale(ch);
225 if ( prescale.enabled ) {
226 const bool decision = decisionPerChain(ch, prescale.prescale);
227 if ( decision ) {
228 remainActive.push_back( ch );
229 }
230 ATH_MSG_DEBUG("Prescaling decision for chain " << ch << " " << decision);
231 } else {
232 ATH_MSG_DEBUG("Chain " << ch << " is disabled, won't keep" );
233 }
234 }
235 }
236
237 return StatusCode::SUCCESS;
238}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Maintain a set of objects, one per slot.
#define CHECK(...)
Evaluate an expression and check for errors.
static Double_t a
const std::function< CLHEP::HepRandomEngine *(void) > PSTRanluxFactory
Group of local monitoring quantities and retain correlation when filling histograms
Declare a monitored scalar variable.
std::map< std::string, HLT::IDVec > m_CPSGroups
virtual StatusCode initialize() override
ATHRNG::RNGWrapper m_RNGEngines
Random engine for calculating prescales.
virtual StatusCode prescaleChains(const EventContext &ctx, const HLT::IDVec &initiallyActive, HLT::IDVec &remainActive, bool forExpressStream=false) const override
The method to prescale chains.
HLT::Identifier m_costChainID
SG::ReadCondHandleKey< TrigConf::HLTPrescalesSet > m_hltPrescaleSetInputKey
ToolHandle< GenericMonitoringTool > m_monTool
TrigConf::HLTPrescalesSet::HLTPrescale m_prescaleForUnknownChain
ChainSet m_nonCPSChains
SG::ReadHandleKey< xAOD::EventInfo > m_eventInfoKey
PrescalingTool()=delete
Gaudi::Property< bool > m_keepUnknownChains
virtual StatusCode start() override
SG::ReadHandleKey< TrigConf::HLTMenu > m_HLTMenuKey
virtual bool isValid() override final
Can the handle be successfully dereferenced?
std::vector< HLT::Identifier > IDVec
Forward declaration.
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.