ATLAS Offline Software
Loading...
Searching...
No Matches
CP::SystematicsCache< CalibData > Class Template Referencefinal

helper class to cache systematics varied calibration constants inside a ISystematicsTool or IRentrantSystematicsTool More...

#include <SystematicsCache.h>

Inheritance diagram for CP::SystematicsCache< CalibData >:
Collaboration diagram for CP::SystematicsCache< CalibData >:

Public Member Functions

template<typename T2>
 SystematicsCache (T2 *val_parent)
void initialize (CP::SystematicSet val_affectingSystematics, std::function< StatusCode(const CP::SystematicSet &sys, CalibData &result)> val_calc) noexcept
 initialize with the list of affecting systematics and a function to calculate the calibration data for each systematic
const CP::SystematicSetaffectingSystematics () const noexcept
 the list of affecting systematics
bool isAffectedBySystematic (const SystematicVariation &systematic) const
 whether we are affected by the given systematic variation
StatusCode get (const CP::SystematicSet &sys, const CalibData *&result) const
 get the pointer to the cached calibration data for the given systematic, calculating it if necessary
StatusCode add (const CP::SystematicSet &sys, CalibData value)
 add an individual systematic variation
StatusCode add (const SystematicVariation &variation, CalibData value)
MsgStream & msg () const
MsgStream & msg (const MSG::Level lvl) const
bool msgLvl (const MSG::Level lvl) const
 Test the output level of the object.

Private Attributes

CP::SystematicSet m_affectingSystematics
 the list of affecting systematics
std::function< StatusCode(const CP::SystematicSet &sys, CalibData &result)> m_calc
 the function to calculate the calibration data for a given systematics
tbb::concurrent_unordered_map< CP::SystematicSet, std::shared_ptr< const CalibData >, SystematicSetHash > m_cache ATLAS_THREAD_SAFE
 the cache of previously calculated calibration data
std::mutex m_calcMutex
 a mutex to protext against concurrent execution of m_calc
std::function< MsgStream &()> m_msg
 the message stream we use

Detailed Description

template<typename CalibData>
class CP::SystematicsCache< CalibData >

helper class to cache systematics varied calibration constants inside a ISystematicsTool or IRentrantSystematicsTool

The general pattern for how systematics are supposed to be implemented inside systematics tools is that the first time a specific systematic variation is requested the tool should calculate the calibration constants for that particular systematic, store it in an (unordered) map and look it up from that map in all subsequent uses. This class tries to implement that particular logic in a thread-safe and (reasonably) fool-proof way.

The basic way to use this class is:

class MyTool : public asg::AsgTool, virtual public IMyTool {
...
struct ConfigData {...};
CP::SystematicsCache<ConfigData> m_calibCache {this};
const ConfigData *m_currentConfig {nullptr};
};
StatusCode MyTool :: initialize () {
...
CP::SystematicSet affectingSystematics = ...;
ANA_CHECK (m_calibCache.initialize (std::move (affectingSystematics),
[this] (const CP::SystematicSet& sys,
ConfigData& myconfig) {
myconfig = ...;
return StatusCode;});
ANA_CHECK (applySystematicVariation (CP::SystematicSet()));
return StatusCode::SUCCESS;
}
StatusCode MyTool :: applySystematicVariation (const CP::SystematicSet& sys, ...) {
return m_calibCache.get (sys, m_currentConfig);
}
CP::SystematicSet MyTool :: affectingSystematics () const {
return m_calibCache.affectingSystematics(); }
#define ANA_CHECK(EXP)
check whether the given expression was successful
helper class to cache systematics varied calibration constants inside a ISystematicsTool or IRentrant...
const CP::SystematicSet & affectingSystematics() const noexcept
the list of affecting systematics
Base class for the dual-use tool implementation classes.
Definition AsgTool.h:47
::StatusCode StatusCode
StatusCode definition for legacy code.

There are not too many constraints on the structure and lambda function, just make sure the structure is default constructable and the lambda function is safe to execute while a lock is held (i.e. if you acquire a lock make sure not to create a dead-lock). It is currently not anticipated that this lambda function needs to be thread-safe itself (even if multiple threads use the same tool, they would still just run through the same systematics in the same order). It is guaranteed that the function is called exactly once for each unique set of affecting systematics, and that only a single copy of the calibration data is stored for each unique set of affecting systematics.

Note that while the above example uses a lambda function it is probably a good idea to write this as a separate helper function and have the lambda function wrap that helper. The rationale for that recommendation is that this is usually a rather long function with tedious logic and making it part of initialize can affect the readability of either one.

Definition at line 83 of file SystematicsCache.h.

Constructor & Destructor Documentation

◆ SystematicsCache()

template<typename CalibData>
template<typename T2>
CP::SystematicsCache< CalibData >::SystematicsCache ( T2 * val_parent)

Function Implementations

Definition at line 149 of file SystematicsCache.h.

152 {}
AsgMessagingForward(T *owner)
forwarding constructor

Member Function Documentation

◆ add() [1/2]

template<typename CalibData>
StatusCode CP::SystematicsCache< CalibData >::add ( const CP::SystematicSet & sys,
CalibData value )

add an individual systematic variation

Definition at line 253 of file SystematicsCache.h.

255 {
257 if (emplace_result.second == false)
258 {
259 ANA_MSG_ERROR ("failed to add systematic, already present: " << sys.name());
260 return StatusCode::FAILURE;
261 }
262
263 for (const auto& var : sys)
265
266 return StatusCode::SUCCESS;
267 }
#define ANA_MSG_ERROR(xmsg,...)
Macro printing error messages.
CP::SystematicSet m_affectingSystematics
the list of affecting systematics

◆ add() [2/2]

template<typename CalibData>
StatusCode CP::SystematicsCache< CalibData >::add ( const SystematicVariation & variation,
CalibData value )

Definition at line 272 of file SystematicsCache.h.

274 {
276 sys.insert (variation);
277 return add (sys, std::move (value));
278 }
StatusCode add(const CP::SystematicSet &sys, CalibData value)
add an individual systematic variation

◆ affectingSystematics()

template<typename CalibData>
const CP::SystematicSet & CP::SystematicsCache< CalibData >::affectingSystematics ( ) const
noexcept

the list of affecting systematics

Definition at line 168 of file SystematicsCache.h.

170 {
172 }

◆ get()

template<typename CalibData>
StatusCode CP::SystematicsCache< CalibData >::get ( const CP::SystematicSet & sys,
const CalibData *& result ) const

get the pointer to the cached calibration data for the given systematic, calculating it if necessary

Definition at line 187 of file SystematicsCache.h.

189 {
190 // fast-path, check if we already calculated this
191 auto iter = m_cache.find (sys);
192 if (iter != m_cache.end()) [[likely]]
193 {
194 result = iter->second.get();
195 return StatusCode::SUCCESS;
196 }
197
198 // create a lock to prevent the concurrent (or duplicate)
199 // execution of the \ref m_calc function. if that function is
200 // thread-safe this lock is not strictly necessary. however,
201 // given that it is hard to enforce that the function is indeed
202 // thread-safe and there are essentially no performance gains to
203 // be had, this seems safer (unless \ref m_calc acquires mutexes
204 // in a way that causes a dead-lock).
206
207 // check if another thread already calculated this value while we
208 // acquired the lock
209 iter = m_cache.find (sys);
210 if (iter != m_cache.end())
211 {
212 result = iter->second.get();
213 return StatusCode::SUCCESS;
214 }
215
216 // we will only ever calculate the systematics for our set of
217 // affecting systematics, any systematics that are not affecting
218 // us will be ignored
221
223 {
224 // check if our affecting systematics are known already
225 auto iter = m_cache.find (mysys);
226 if (iter != m_cache.end())
227 mycalib = iter->second;
228 else
229 {
230 // this will now actually calculate the systematics. note
231 // that if this fails, nothing gets cached, but we should also
232 // be aborting
235
236 // store for the affecting systematic
237 auto emplace_result = m_cache.emplace (mysys, value);
238 mycalib = emplace_result.first->second;
239 }
240 }
241
242 // store for user requested systematics as well, which may or may
243 // not be the same as the affecting systematics, but if it is
244 // already there, this will do nothing.
245 m_cache.emplace (sys, mycalib);
246 result = mycalib.get();
247 return StatusCode::SUCCESS;
248 }
virtual void lock()=0
Interface to allow an object to lock itself when made const in SG.
StatusCode get(const CP::SystematicSet &sys, const CalibData *&result) const
get the pointer to the cached calibration data for the given systematic, calculating it if necessary
std::function< StatusCode(const CP::SystematicSet &sys, CalibData &result)> m_calc
the function to calculate the calibration data for a given systematics
std::mutex m_calcMutex
a mutex to protext against concurrent execution of m_calc

◆ initialize()

template<typename CalibData>
void CP::SystematicsCache< CalibData >::initialize ( CP::SystematicSet val_affectingSystematics,
std::function< StatusCode(const CP::SystematicSet &sys, CalibData &result)> val_calc )
noexcept

initialize with the list of affecting systematics and a function to calculate the calibration data for each systematic

Definition at line 156 of file SystematicsCache.h.

◆ isAffectedBySystematic()

template<typename CalibData>
bool CP::SystematicsCache< CalibData >::isAffectedBySystematic ( const SystematicVariation & systematic) const

whether we are affected by the given systematic variation

this is mostly for implementing the ISystematicsTool interface and should probably not be used by anyone.

Definition at line 177 of file SystematicsCache.h.

179 {
180 // this is not technically correct, but what a lot of people do
182 }

◆ msg() [1/2]

template<typename CalibData>
MsgStream & asg::AsgMessagingForward::msg ( ) const

Public Members

Definition at line 54 of file AsgMessagingForward.cxx.

25 {
26 return m_msg();
27 }
std::function< MsgStream &()> m_msg
the message stream we use

◆ msg() [2/2]

template<typename CalibData>
MsgStream & asg::AsgMessagingForward::msg ( const MSG::Level lvl) const

Public Members

Definition at line 61 of file AsgMessagingForward.cxx.

30 {
31 MsgStream& msg = m_msg ();
32 msg << lvl;
33 return msg;
34 }
MsgStream & msg() const

◆ msgLvl()

bool asg::AsgMessagingForward::msgLvl ( const MSG::Level lvl) const
inherited

Test the output level of the object.

Parameters
lvlThe message level to test against
Returns
boolean Indicting if messages at given level will be printed
true If messages at level "lvl" will be printed

Definition at line 11 of file AsgMessagingForward.cxx.

12 {
13 MsgStream& msg = m_msg();
14 if (msg.level() <= lvl)
15 {
16 msg << lvl;
17 return true;
18 } else
19 {
20 return false;
21 }
22 }
MsgStream & msg() const
The standard message stream.

Member Data Documentation

◆ ATLAS_THREAD_SAFE

template<typename CalibData>
tbb::concurrent_unordered_map<CP::SystematicSet,std::shared_ptr<const CalibData>,SystematicSetHash> m_cache CP::SystematicsCache< CalibData >::ATLAS_THREAD_SAFE
mutableprivate

the cache of previously calculated calibration data

Definition at line 134 of file SystematicsCache.h.

◆ m_affectingSystematics

template<typename CalibData>
CP::SystematicSet CP::SystematicsCache< CalibData >::m_affectingSystematics
private

the list of affecting systematics

Private Members

Definition at line 127 of file SystematicsCache.h.

◆ m_calc

template<typename CalibData>
std::function<StatusCode (const CP::SystematicSet& sys, CalibData& result)> CP::SystematicsCache< CalibData >::m_calc
private

the function to calculate the calibration data for a given systematics

Definition at line 131 of file SystematicsCache.h.

◆ m_calcMutex

template<typename CalibData>
std::mutex CP::SystematicsCache< CalibData >::m_calcMutex
mutableprivate

a mutex to protext against concurrent execution of m_calc

see the comment inside get for a detailed explanation of why this is used/needed.

Definition at line 140 of file SystematicsCache.h.

◆ m_msg

std::function<MsgStream& ()> asg::AsgMessagingForward::m_msg
privateinherited

the message stream we use

This used to be a simple pointer to the MsgStream itself, but in AthenaMT the actual object used is local to the thread. So instead of pointing to it directly we are now using a function to look it up, which will get the thread-local object.

Definition at line 77 of file AsgMessagingForward.h.


The documentation for this class was generated from the following file: