The creation of monitoring histograms should be done using the “Monitored” infrastructure. For technical details and code examples see the Doxygen documentation.
For the documentation on how this infrastructure is used in Data Quality monitoring offline see the DQRun3FrameworkTutorial TWiki.
Using the “Monitored” infrastructure allows the creation and filling of histograms in a thread-safe
way with the minimum amount of boilerplate code. There is a separation between the monitored
quantity (e.g. energy, momentum, eta, phi) and the final histograms (e.g. momentum vs eta). The
variables themselves are defined and filled in the C++ code, whereas the definition of the
histograms is entirely done in the Python job configuration via the GenericMonitoringTool
. This
allows for maximum flexibility without having to re-compile the code for simple histogram changes.
As a starting point add the following empty ToolHandle
to your class:
#include "AthenaMonitoringKernel/Monitored.h"
[...]
private:
ToolHandle<GenericMonitoringTool> m_monTool{this,"MonTool","","Monitoring tool"};
// empty string as third argument turns off monitoring by default
and a conditional retrieve in your initialize()
method:
if (!m_monTool.empty()) ATH_CHECK(m_monTool.retrieve());
Finally, make sure you link against the AthenaMonitoringKernelLib
library in your CMakeLists.txt
:
atlas_add_component( ...
LINK_LIBRARIES ... AthenaMonitoringKernelLib ... )
The following sections give more details on:
Some of the following examples are show-cased in the
AthExMonitored
package and can be tested via athena.py AthExMonitored/MonitoredOptions.py
.
The simplest monitored variable is a scalar (e.g. integer or floating point value):
{
auto et = Monitored::Scalar<float>("Et");
auto njets = Monitored::Scalar<int>("nJets");
auto phi = Monitored::Scalar("phi", 0.0);
auto eta = Monitored::Scalar("eta", 0.0);
auto cutType = Monitored::Scalar("cutType", "EtaCut");
auto mon = Monitored::Group(m_monTool, et, njets, phi, eta, cutType);
// code to set the values
}
A few remarks to the above code example:
Monitored::Scalar
is irrelevant, which is why we use the auto
keyword. It
suffices to know that it behaves like a regular builtin arithmetic type.1.0
-> double
, 42
->
int
) or can be explicitly set via the template parameter.Refer to the Monitored::Scalar Doxygen for all details and features.
In order to maintain correlations when filling histograms (e.g. eta and phi of a track) the monitored quantities
need to be grouped within a Monitored::Group
. The filling of the histogram occurs when the Monitored::Group
object goes out of scope or when fill()
is called explicitly.
There is support for filling with weights or cut masks. See the Monitored::Group Doxygen for full details.
Any iterable container (e.g. std::vector
, DataVector
) can be monitored directly and one
histogram fill will be performed for each element. The simplest case is if the elements are
convertable to a floating point value:
// monitoring of std::vector<float> vec;
auto eta = Monitored::Collection("eta", vec);
The above should only be used if the values are already stored in this format. Do not fill a vector just for the sake of monitoring. In most cases one of the following methods can be used.
In case the container (e.g. DataVector<Track>
) holds objects with accessors for the monitored
quantity, the third parameter can be used to identify the member method (here Track
class method) that should be called when
retrieving the value or more generally a lambda function:
A monitored collection or scalar can also contain strings. Monitoring them will results in an alphanumeric histogram fill:
Refer to the Monitored::Collection Doxygen for all details and features.
Monitored::Timer and Monitored::ScopedTimer can be used to measure and monitor execution times of code sections.
The histograms are configured in Python:
This will define three 1D histograms and one 2D histogram:
;anothername
.path
is the top-level directory (note however that an additional directory of the name equal to the name of monitored algorithm, tool or service from where the MonTool is invoked).title
uses the same syntax as the TH1
constructor, i.e. 'title;xaxis;yaxis'
.In the above example all histograms would be stored in a directory called MyAlg
if MyAlg
is the instance name of the algorithm with which this tool instance is connected i.e. MyAlg.MontTool = MonTool
. In case of many instances of a given
type (e.g. HypoAlgs, HypoTools) a different grouping (e.g. by the class name) might be more
appropriate. This can be achieved by setting a specific histogram booking path:
monTool.HistPath = "L2CaloHypo/" + threshold
which would e.g. result in all histograms being stored under the path “EXPERT/L2CaloHypo/HLT_e3/…”.
The defineHistogram
method has several additional options. Those that are possibly useful in the HLT case are:
labels=['a','b']
opt='kLBNHistoryDepth=N'
where N
is the number of lumiblocks from which the statistics is accumulated in one copy of the histogram. While running the trigger in emulators/offline the histograms end up in the expert-monitoring.root file and have additional postfix _LB1
, _LB2
if N=1
and _LBX_X+N
if N!=1
.
For online running, lumiblock tagged histograms are published under the same name irrespectively of the LB. If a histogram with whole run statistics is needed in addition it can be booked using the alias
option (see above).opt='kCanRebin'
) - same number of bins, range is doubled when under/overflows are encountered.opt='kAddBinsDynamically'
) - additional bins are added when under/overflows are encountered (use with caution as this option may result in a large histogram).See the Doxygen documentation for all available options.
It is recommended that he configuration of the MonTool
with histograms is placed within separate
function creating an instance of ComponentAccumulator with the MonTool
as private tool.
During developments:
For debugging in nightly tests and monitoring at P1:
eta-phi
, eta-et
) and plots vs mu