From 4502b7b449ee93697738731b0efea16486b33c01 Mon Sep 17 00:00:00 2001
From: Nikola Dikic <nikola.dikic@cern.ch>
Date: Thu, 5 Dec 2019 21:37:14 +0100
Subject: [PATCH] First template for AFP Run3 Monitoring

---
 .../AFP/Run3AFPMonitoring/CMakeLists.txt      |  86 +++++++++
 .../AFPHitsMonitorAlgorithm.h                 |  26 +++
 .../python/PoolFileCatalog.xml                |  12 ++
 .../python/Run3AFPExampleMonitorAlgorithm.py  | 165 ++++++++++++++++++
 .../python/eventLoopHeartBeat.txt             |   1 +
 .../src/AFPHitsMonitorAlgorithm.cxx           |  96 ++++++++++
 .../components/Run3AFPMonitoring_entries.cxx  |   7 +
 7 files changed, 393 insertions(+)
 create mode 100644 ForwardDetectors/AFP/Run3AFPMonitoring/CMakeLists.txt
 create mode 100644 ForwardDetectors/AFP/Run3AFPMonitoring/Run3AFPMonitoring/AFPHitsMonitorAlgorithm.h
 create mode 100644 ForwardDetectors/AFP/Run3AFPMonitoring/python/PoolFileCatalog.xml
 create mode 100644 ForwardDetectors/AFP/Run3AFPMonitoring/python/Run3AFPExampleMonitorAlgorithm.py
 create mode 100644 ForwardDetectors/AFP/Run3AFPMonitoring/python/eventLoopHeartBeat.txt
 create mode 100644 ForwardDetectors/AFP/Run3AFPMonitoring/src/AFPHitsMonitorAlgorithm.cxx
 create mode 100644 ForwardDetectors/AFP/Run3AFPMonitoring/src/components/Run3AFPMonitoring_entries.cxx

diff --git a/ForwardDetectors/AFP/Run3AFPMonitoring/CMakeLists.txt b/ForwardDetectors/AFP/Run3AFPMonitoring/CMakeLists.txt
new file mode 100644
index 000000000000..4ed7b4100b5d
--- /dev/null
+++ b/ForwardDetectors/AFP/Run3AFPMonitoring/CMakeLists.txt
@@ -0,0 +1,86 @@
+################################################################################
+# Package: Run3AFPMonitoring
+################################################################################
+
+# Declare the package name:
+atlas_subdir( Run3AFPMonitoring )
+
+# Declare the package's dependencies:
+atlas_depends_on_subdirs(
+    PUBLIC
+        Control/AthenaBaseComps
+        Control/AthenaMonitoringKernel
+        GaudiKernel
+        LumiBlock/LumiBlockComps
+        LumiBlock/LumiBlockData
+        Trigger/TrigEvent/TrigDecisionInterface
+    PRIVATE
+        Control/AthenaMonitoring
+        AtlasTest/TestTools
+        Control/AthenaKernel
+        Control/CxxUtils
+        Control/SGMon/SGAudCore
+        Database/AthenaPOOL/AthenaPoolUtilities
+        Event/xAOD/xAODEventInfo
+        Event/EventInfo
+        Tools/LWHists
+        Trigger/TrigAnalysis/TrigDecisionTool
+        Trigger/TrigAnalysis/TrigAnalysisInterfaces
+        MuonSpectrometer/MuonAlignment/MuonAlignmentData
+)
+
+# External dependencies:
+find_package( CORAL COMPONENTS CoralBase CoralKernel RelationalAccess )
+find_package( Boost )
+find_package( ROOT COMPONENTS Core )
+
+# Component(s) in the package:
+atlas_add_library(
+    Run3AFPMonitoringLib
+    src/*.cxx
+    PUBLIC_HEADERS
+        Run3AFPMonitoring
+    INCLUDE_DIRS
+        ${ROOT_INCLUDE_DIRS}
+    PRIVATE_INCLUDE_DIRS
+        ${Boost_INCLUDE_DIRS}
+        ${CORAL_INCLUDE_DIRS}
+    LINK_LIBRARIES
+        ${Boost_LIBRARIES}
+        ${ROOT_LIBRARIES}
+        AthenaBaseComps
+        AthenaMonitoringLib
+        AthenaMonitoringKernelLib
+        GaudiKernel
+        LumiBlockCompsLib
+        LumiBlockData
+        TrigDecisionToolLib
+    PRIVATE_LINK_LIBRARIES
+        ${CORAL_LIBRARIES}
+        AthenaKernel
+        SGAudCore
+        AthenaPoolUtilities
+        EventInfo
+        LWHists
+)
+
+atlas_add_component(
+    Run3AFPMonitoring
+    src/components/*.cxx
+    INCLUDE_DIRS
+        ${CORAL_INCLUDE_DIRS}
+    LINK_LIBRARIES
+        Run3AFPMonitoringLib
+        AthenaMonitoringLib
+        AthenaMonitoringKernelLib
+        LumiBlockData
+        LWHists
+        SGAudCore
+        TrigDecisionToolLib
+)
+
+# Install files from the package:
+#atlas_install_python_modules( python/*.py 
+#                              POST_BUILD_CMD ${ATLAS_FLAKE8} )
+atlas_install_joboptions( share/*.py )
+#atlas_install_scripts( share/Run3DQTestingDriver.py share/hist_file_dump.py share/hist_diff.sh )
diff --git a/ForwardDetectors/AFP/Run3AFPMonitoring/Run3AFPMonitoring/AFPHitsMonitorAlgorithm.h b/ForwardDetectors/AFP/Run3AFPMonitoring/Run3AFPMonitoring/AFPHitsMonitorAlgorithm.h
new file mode 100644
index 000000000000..3ea7e50f3364
--- /dev/null
+++ b/ForwardDetectors/AFP/Run3AFPMonitoring/Run3AFPMonitoring/AFPHitsMonitorAlgorithm.h
@@ -0,0 +1,26 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef AFPHITSMONITORALGORITHM_H
+#define AFPHITSMONITORALGORITHM_H
+
+#include "AthenaMonitoring/AthMonitorAlgorithm.h"
+#include "AthenaMonitoringKernel/Monitored.h"
+
+#include "TRandom3.h"
+
+class AFPHitsMonitorAlgorithm : public AthMonitorAlgorithm {
+public:
+    AFPHitsMonitorAlgorithm( const std::string& name, ISvcLocator* pSvcLocator );
+    virtual ~AFPHitsMonitorAlgorithm();
+    virtual StatusCode initialize() override;
+    virtual StatusCode fillHistograms( const EventContext& ctx ) const override;
+private:
+    Gaudi::Property<bool> m_doRandom {this,"RandomHist",false};
+    std::vector<int> m_abGroups1;
+    std::vector<std::vector<int>> m_abGroups2;
+    std::map<std::string,int> m_cGroups1;
+    std::map<std::string,std::map<std::string,int>> m_cGroups2;
+};
+#endif
diff --git a/ForwardDetectors/AFP/Run3AFPMonitoring/python/PoolFileCatalog.xml b/ForwardDetectors/AFP/Run3AFPMonitoring/python/PoolFileCatalog.xml
new file mode 100644
index 000000000000..5f18c9c49da1
--- /dev/null
+++ b/ForwardDetectors/AFP/Run3AFPMonitoring/python/PoolFileCatalog.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
+<!-- Edited By POOL -->
+<!DOCTYPE POOLFILECATALOG SYSTEM "InMemory">
+<POOLFILECATALOG>
+  <File ID="23288CC6-5921-944B-BF66-F99ACC97ABBB">
+    <physical>
+      <pfn filetype="ROOT_All" name="/cvmfs/atlas-nightlies.cern.ch/repo/data/data-art/CommonInputs/data16_13TeV.00311321.physics_Main.recon.AOD.r9264/AOD.11038520._000001.pool.root.1"/>
+    </physical>
+    <logical/>
+  </File>
+
+</POOLFILECATALOG>
diff --git a/ForwardDetectors/AFP/Run3AFPMonitoring/python/Run3AFPExampleMonitorAlgorithm.py b/ForwardDetectors/AFP/Run3AFPMonitoring/python/Run3AFPExampleMonitorAlgorithm.py
new file mode 100644
index 000000000000..2fc18abd1e0f
--- /dev/null
+++ b/ForwardDetectors/AFP/Run3AFPMonitoring/python/Run3AFPExampleMonitorAlgorithm.py
@@ -0,0 +1,165 @@
+#
+#  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+#
+
+'''@file ExampleMonitorAlgorithm.py kristin
+@author C. D. Burton
+@author P. Onyisi
+@date 2018-01-11
+@brief Example python configuration for the Run III AthenaMonitoring package
+'''
+
+def Run3AFPExampleMonitoringConfig(inputFlags):
+    '''Function to configures some algorithms in the monitoring system.'''
+
+    ### STEP 1 ###
+    # If you need to set up special tools, etc., you will need your own ComponentAccumulator;
+    # uncomment the following 2 lines and use the last three lines of this function instead of the ones
+    # just before
+    # from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+    # result = ComponentAccumulator()
+
+    # The following class will make a sequence, configure algorithms, and link
+    # them to GenericMonitoringTools
+    from AthenaMonitoring import AthMonitorCfgHelper
+    helper = AthMonitorCfgHelper(inputFlags,'Run3AFPMonitorCfg')
+
+
+    ### STEP 2 ###
+    # Adding an algorithm to the helper. Here, we will use the example 
+    # algorithm in the AthenaMonitoring package. Just pass the type to the 
+    # helper. Then, the helper will instantiate an instance and set up the 
+    # base class configuration following the inputFlags. The returned object 
+    # is the algorithm.
+    from Run3AFPMonitoring.Run3AFPMonitoringConf import AFPHitsMonitorAlgorithm
+    exampleMonAlg = helper.addAlgorithm(AFPHitsMonitorAlgorithm,'exampleMonAlg')
+
+    # You can actually make multiple instances of the same algorithm and give 
+    # them different configurations
+    anotherExampleMonAlg = helper.addAlgorithm(AFPHitsMonitorAlgorithm,'AnotherExampleMonAlg')
+
+    # # If for some really obscure reason you need to instantiate an algorithm
+    # # yourself, the AddAlgorithm method will still configure the base 
+    # # properties and add the algorithm to the monitoring sequence.
+    # helper.AddAlgorithm(myExistingAlg)
+
+
+    ### STEP 3 ###
+    # Edit properties of a algorithm
+    # some generic property
+    #exampleMonAlg.RandomHist = True
+    # to enable a trigger filter, for example:
+    #exampleMonAlg.TriggerChain = 'HLT_mu26_ivarmedium'
+
+    ### STEP 4 ###
+    # Add some tools. N.B. Do not use your own trigger decion tool. Use the
+    # standard one that is included with AthMonitorAlgorithm.
+
+    # # Then, add a tool that doesn't have its own configuration function. In
+    # # this example, no accumulator is returned, so no merge is necessary.
+    # from MyDomainPackage.MyDomainPackageConf import MyDomainTool
+    # exampleMonAlg.MyDomainTool = MyDomainTool()
+
+    # Add a generic monitoring tool (a "group" in old language). The returned 
+    # object here is the standard GenericMonitoringTool.
+    myGroup = helper.addGroup(
+        exampleMonAlg,
+        'ExampleMonitor',
+        'OneRing/'
+    )
+
+    # Add a GMT for the other example monitor algorithm
+    anotherGroup = helper.addGroup(anotherExampleMonAlg,'ExampleMonitor')
+
+
+    ### STEP 5 ###
+    # Configure histograms
+    myGroup.defineHistogram('lumiPerBCID',title='Luminosity,WithCommaInTitle;L/BCID;Events',
+                            path='ToRuleThemAll',xbins=40,xmin=0.0,xmax=80.0)
+    myGroup.defineHistogram('lb', title='Luminosity Block;lb;Events',
+                            path='ToFindThem',xbins=1000,xmin=-0.5,xmax=999.5,weight='testweight')
+    myGroup.defineHistogram('random', title='LB;x;Events',
+                            path='ToBringThemAll',xbins=30,xmin=0,xmax=1,opt='kLBNHistoryDepth=10')
+    myGroup.defineHistogram('random', title='title;x;y',path='ToBringThemAll',
+                            xbins=[0,.1,.2,.4,.8,1.6])
+    myGroup.defineHistogram('random,pT', type='TH2F', title='title;x;y',path='ToBringThemAll',
+                            xbins=[0,.1,.2,.4,.8,1.6],ybins=[0,10,30,40,60,70,90])
+    # myGroup.defineHistogram('pT_passed,pT',type='TEfficiency',title='Test TEfficiency;x;Eff',
+    #                         path='AndInTheDarkness',xbins=100,xmin=0.0,xmax=50.0)
+
+    anotherGroup.defineHistogram('lbWithFilter',title='Lumi;lb;Events',
+                                 path='top',xbins=1000,xmin=-0.5,xmax=999.5)
+    anotherGroup.defineHistogram('run',title='Run Number;run;Events',
+                                 path='top',xbins=1000000,xmin=-0.5,xmax=999999.5)
+
+    # Example defining an array of histograms. This is useful if one seeks to create a
+    # number of histograms in an organized manner. (For instance, one plot for each ASIC
+    # in the subdetector, and these components are mapped in eta, phi, and layer.) Thus,
+    # one might have an array of TH1's such as quantity[etaIndex][phiIndex][layerIndex].
+    for alg in [exampleMonAlg,anotherExampleMonAlg]:
+        # Using an array of groups
+        array = helper.addArray([2],alg,'ExampleMonitor')
+        array.defineHistogram('a,b',title='AB',type='TH2F',path='Eta',
+                              xbins=10,xmin=0.0,xmax=10.0,
+                              ybins=10,ymin=0.0,ymax=10.0)
+        array.defineHistogram('c',title='C',path='Eta',
+                              xbins=10,xmin=0.0,xmax=10.0)
+        array = helper.addArray([4,2],alg,'ExampleMonitor')
+        array.defineHistogram('a',title='A',path='EtaPhi',
+                              xbins=10,xmin=0.0,xmax=10.0)
+        # Using a map of groups
+        layerList = ['layer1','layer2']
+        clusterList = ['clusterX','clusterB']
+        array = helper.addArray([layerList],alg,'ExampleMonitor')
+        array.defineHistogram('c',title='C',path='Layer',
+                              xbins=10,xmin=0,xmax=10.0)
+        array = helper.addArray([layerList,clusterList],alg,'ExampleMonitor')
+        array.defineHistogram('c',title='C',path='LayerCluster',
+                              xbins=10,xmin=0,xmax=10.0)
+
+    ### STEP 6 ###
+    # Finalize. The return value should be a tuple of the ComponentAccumulator
+    # and the sequence containing the created algorithms. If we haven't called
+    # any configuration other than the AthMonitorCfgHelper here, then we can 
+    # just return directly (and not create "result" above)
+    return helper.result()
+    
+    # # Otherwise, merge with result object and return
+    # acc = helper.result()
+    # result.merge(acc)
+    # return result
+
+if __name__=='__main__':
+    # Setup the Run III behavior
+    from AthenaCommon.Configurable import Configurable
+    Configurable.configurableRun3Behavior = 1
+
+    # Setup logs
+    from AthenaCommon.Logging import log
+    from AthenaCommon.Constants import INFO
+    log.setLevel(INFO)
+
+    # Set the Athena configuration flags
+    from AthenaConfiguration.AllConfigFlags import ConfigFlags
+    nightly = '/cvmfs/atlas-nightlies.cern.ch/repo/data/data-art/CommonInputs/'
+    file = 'data16_13TeV.00311321.physics_Main.recon.AOD.r9264/AOD.11038520._000001.pool.root.1'
+    ConfigFlags.Input.Files = [nightly+file]
+    ConfigFlags.Input.isMC = False
+    ConfigFlags.Output.HISTFileName = 'ExampleMonitorOutput.root'
+    
+    ConfigFlags.lock()
+
+    # Initialize configuration object, add accumulator, merge, and run.
+    from AthenaConfiguration.MainServicesConfig import MainServicesSerialCfg 
+    from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+    cfg = MainServicesSerialCfg()
+    cfg.merge(PoolReadCfg(ConfigFlags))
+
+    exampleMonitorAcc = Run3AFPExampleMonitoringConfig(ConfigFlags)
+    cfg.merge(exampleMonitorAcc)
+
+    # If you want to turn on more detailed messages ...
+    # exampleMonitorAcc.getEventAlgo('ExampleMonAlg').OutputLevel = 2 # DEBUG
+    cfg.printConfig(withDetails=False) # set True for exhaustive info
+
+    cfg.run(10) #use cfg.run(20) to only run on first 20 events
diff --git a/ForwardDetectors/AFP/Run3AFPMonitoring/python/eventLoopHeartBeat.txt b/ForwardDetectors/AFP/Run3AFPMonitoring/python/eventLoopHeartBeat.txt
new file mode 100644
index 000000000000..0cd8dced0633
--- /dev/null
+++ b/ForwardDetectors/AFP/Run3AFPMonitoring/python/eventLoopHeartBeat.txt
@@ -0,0 +1 @@
+  done processing event #779703711, run #311321 10 events read so far  <<<===
diff --git a/ForwardDetectors/AFP/Run3AFPMonitoring/src/AFPHitsMonitorAlgorithm.cxx b/ForwardDetectors/AFP/Run3AFPMonitoring/src/AFPHitsMonitorAlgorithm.cxx
new file mode 100644
index 000000000000..4c38efd5127c
--- /dev/null
+++ b/ForwardDetectors/AFP/Run3AFPMonitoring/src/AFPHitsMonitorAlgorithm.cxx
@@ -0,0 +1,96 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "Run3AFPMonitoring/AFPHitsMonitorAlgorithm.h"
+
+AFPHitsMonitorAlgorithm::AFPHitsMonitorAlgorithm( const std::string& name, ISvcLocator* pSvcLocator )
+:AthMonitorAlgorithm(name,pSvcLocator)
+,m_doRandom(true)
+{}
+
+
+AFPHitsMonitorAlgorithm::~AFPHitsMonitorAlgorithm() {}
+
+
+StatusCode AFPHitsMonitorAlgorithm::initialize() {
+    using namespace Monitored;
+    m_abGroups1 = buildToolMap<int>(m_tools,"ExampleMonitor",2);
+    m_abGroups2 = buildToolMap<std::vector<int>>(m_tools,"ExampleMonitor",4,2);
+
+    std::vector<std::string> layers = {"layer1","layer2"};
+    std::vector<std::string> clusters = {"clusterX","clusterB"};
+    m_cGroups1 = buildToolMap<int>(m_tools,"ExampleMonitor",layers);
+    m_cGroups2 = buildToolMap<std::map<std::string,int>>(m_tools,"ExampleMonitor",layers,clusters);
+    return AthMonitorAlgorithm::initialize();
+}
+
+
+StatusCode AFPHitsMonitorAlgorithm::fillHistograms( const EventContext& ctx ) const {
+    using namespace Monitored;
+
+    // Declare the quantities which should be monitored
+    auto lumiPerBCID = Monitored::Scalar<float>("lumiPerBCID",0.0);
+    auto lb = Monitored::Scalar<int>("lb",0);
+    auto run = Monitored::Scalar<int>("run",0);
+    auto random = Monitored::Scalar<float>("random",0.0);
+    auto testweight = Monitored::Scalar<float>("testweight",1.0);
+
+    // Two variables (value and passed) needed for TEfficiency
+    auto pT = Monitored::Scalar<float>("pT",0.0);
+    auto pT_passed = Monitored::Scalar<bool>("pT_passed",false);
+
+    // Set the values of the monitored variables for the event
+    lumiPerBCID = lbAverageInteractionsPerCrossing(ctx);
+    lb = GetEventInfo(ctx)->lumiBlock();
+    run = GetEventInfo(ctx)->runNumber();
+    testweight = 2.0;
+    
+    TRandom3 r(ctx.eventID().event_number());
+    // Example of using flags
+    if (m_doRandom) {
+        random = r.Rndm();
+    }
+
+    // Fake efficiency calculator
+    pT = r.Landau(15);
+    pT_passed = pT>r.Poisson(15);
+
+    // Fill. First argument is the tool name, all others are the variables to be saved.
+    fill("ExampleMonitor",lumiPerBCID,lb,random,pT,pT_passed,testweight);
+
+    // Alternative fill method. Get the group yourself, and pass it to the fill function.
+    auto tool = getGroup("ExampleMonitor");
+    fill(tool,run);
+
+    // Fill with a vector; useful in some circumstances.
+    std::vector<std::reference_wrapper<Monitored::IMonitoredVariable>> varVec = {lumiPerBCID,pT};
+    fill("ExampleMonitor",varVec);
+    fill(tool,varVec);
+
+    // Filling using a pre-defined array of groups.
+    auto a = Scalar<float>("a",0.0);
+    auto b = Scalar<float>("b",1.0);
+    auto c = Scalar<float>("c",2.0);
+    for ( auto iEta : {0,1} ) {
+        // 1) Valid but inefficient fill
+        fill("ExampleMonitor_"+std::to_string(iEta),a,b,c);
+        // 2) Faster way to fill a vector of histograms
+        fill(m_tools[m_abGroups1[iEta]],a,b,c);
+        for ( auto iPhi : {0,1} ) {
+            // Same efficient method for 2D array
+            fill(m_tools[m_abGroups2[iEta][iPhi]],a,b);
+        }
+    }
+
+    // Filling using a pre-defined map of groups.
+    for ( auto& layer : std::vector<std::string>({"layer1","layer2"}) ) {
+        fill(m_tools[m_cGroups1.at(layer)],c);
+        for ( auto& cluster : std::vector<std::string>({"clusterX","clusterB"}) ) {
+            // Same efficient method for 2D map
+            fill(m_tools[m_cGroups2.at(layer).at(cluster)],c);
+        }
+    }
+
+    return StatusCode::SUCCESS;
+}
diff --git a/ForwardDetectors/AFP/Run3AFPMonitoring/src/components/Run3AFPMonitoring_entries.cxx b/ForwardDetectors/AFP/Run3AFPMonitoring/src/components/Run3AFPMonitoring_entries.cxx
new file mode 100644
index 000000000000..9d55fb58b6d0
--- /dev/null
+++ b/ForwardDetectors/AFP/Run3AFPMonitoring/src/components/Run3AFPMonitoring_entries.cxx
@@ -0,0 +1,7 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "Run3AFPMonitoring/AFPHitsMonitorAlgorithm.h"
+
+DECLARE_COMPONENT( AFPHitsMonitorAlgorithm )
-- 
GitLab