From 1930ccb5f28998013abe66bf3e0e21e71cd6cde1 Mon Sep 17 00:00:00 2001
From: Tim Martin <tim.martin@cern.ch>
Date: Wed, 20 Jul 2016 12:57:31 +0200
Subject: [PATCH] 'Remove obsolete code using retired flags, update fetching of
 L1 PSK' (TrigCostMonitor-01-20-18)

	* Remove obsolete code using retired flags, update fetching of L1 PSK
	* Tag TrigCostMonitor-01-20-18

2016-07-12  Tim Martin
	* Address writing out too many configs
	* Tag TrigCostMonitor-01-20-17
---
 .../TrigCostMonitor/CMakeLists.txt            |   1 +
 .../TrigCostMonitor/TrigCostTool.h            |   3 +
 .../TrigCostMonitor/TrigNtConfTool.h          |   3 +
 .../TrigCostMonitor/cmt/requirements          |   8 +
 .../python/TrigCostMonitorConfig.py           |  88 +-------
 .../TrigCostMonitor/share/RunAOD.py           | 210 ------------------
 .../TrigCostMonitor/src/TrigCostTool.cxx      |  47 +++-
 .../TrigCostMonitor/src/TrigNtConfTool.cxx    |  88 +++++---
 8 files changed, 123 insertions(+), 325 deletions(-)
 delete mode 100644 Trigger/TrigMonitoring/TrigCostMonitor/share/RunAOD.py

diff --git a/Trigger/TrigMonitoring/TrigCostMonitor/CMakeLists.txt b/Trigger/TrigMonitoring/TrigCostMonitor/CMakeLists.txt
index c6fbb118bdd..25d4bc00ec7 100644
--- a/Trigger/TrigMonitoring/TrigCostMonitor/CMakeLists.txt
+++ b/Trigger/TrigMonitoring/TrigCostMonitor/CMakeLists.txt
@@ -41,6 +41,7 @@ find_package( COOL COMPONENTS CoolKernel CoolApplication )
 find_package( CORAL COMPONENTS CoralBase CoralKernel RelationalAccess )
 find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread MathMore Minuit Minuit2 Matrix Physics HistPainter Rint )
 find_package( tdaq-common )
+find_package( tdaq-common COMPONENTS CTPfragment )
 
 # tag NEEDS_CORAL_BASE was not recognized in automatic conversion in cmt2cmake
 
diff --git a/Trigger/TrigMonitoring/TrigCostMonitor/TrigCostMonitor/TrigCostTool.h b/Trigger/TrigMonitoring/TrigCostMonitor/TrigCostMonitor/TrigCostTool.h
index b4c33ad6579..57d12845025 100644
--- a/Trigger/TrigMonitoring/TrigCostMonitor/TrigCostMonitor/TrigCostTool.h
+++ b/Trigger/TrigMonitoring/TrigCostMonitor/TrigCostMonitor/TrigCostTool.h
@@ -99,6 +99,9 @@ class TrigCostTool : public AthAlgTool, virtual public IMonitorToolBase {
   float        m_execPrescale;     // Prescale for collecting extended data
   float        m_doOperationalInfo;// Value of doOperationalInfo in parent steering alg. Only for reference here
 
+  unsigned int  m_configReductionValue; // Random chance, 1/Value, that this PU gets chosen to write out configs to T0.
+  bool          m_doConfigReduction; // Reduce duplicate configs being sent by every PU online. Only send from 1/configReuctionValue PUs
+
   // Athena tool and service handles
   const HLT::TrigSteer                  *m_parentAlg;
   TrigTimer                             *m_timer;
diff --git a/Trigger/TrigMonitoring/TrigCostMonitor/TrigCostMonitor/TrigNtConfTool.h b/Trigger/TrigMonitoring/TrigCostMonitor/TrigCostMonitor/TrigNtConfTool.h
index 60c6e071f48..2d2f0cc7d6c 100644
--- a/Trigger/TrigMonitoring/TrigCostMonitor/TrigCostMonitor/TrigNtConfTool.h
+++ b/Trigger/TrigMonitoring/TrigCostMonitor/TrigCostMonitor/TrigNtConfTool.h
@@ -64,6 +64,8 @@ namespace Trig
     bool ReadFromDB(TrigMonConfig &confg, unsigned run, unsigned lumi);
     bool ReadKeysDB(unsigned run);
 
+    uint32_t GetL1PSK(bool updateValue = false);
+
   private:
 
     typedef std::map<Trig::ConfigKeys, TrigMonConfig> ConfigMap;
@@ -101,6 +103,7 @@ namespace Trig
     ConfigMap                      m_configMap;   // Map: Trigger config keys -> TrigMonConfig
 
     unsigned                       m_dbOrConfSvcPass; // This should be set to 1 for ConfigService pass or 2 for DB pass 
+    unsigned                       m_currentL1PSK; // Cache current L1 PSK as read from CTP_RD0 online
   };
 }
 
diff --git a/Trigger/TrigMonitoring/TrigCostMonitor/cmt/requirements b/Trigger/TrigMonitoring/TrigCostMonitor/cmt/requirements
index e0756340741..8571e3f669b 100644
--- a/Trigger/TrigMonitoring/TrigCostMonitor/cmt/requirements
+++ b/Trigger/TrigMonitoring/TrigCostMonitor/cmt/requirements
@@ -48,6 +48,8 @@ use TrigConfL1Data           TrigConfL1Data-*           Trigger/TrigConfiguratio
 use TrigConfHLTData          TrigConfHLTData-*          Trigger/TrigConfiguration
 use TrigConfStorage          TrigConfStorage-*          Trigger/TrigConfiguration
 
+use CTPfragment              *
+
 use TrigDataAccessMonitoring TrigDataAccessMonitoring-* Trigger/TrigDataAccess
 use TrigInterfaces           TrigInterfaces-*           Trigger/TrigSteer
 use TrigNavigation           TrigNavigation-*           Trigger/TrigEvent
@@ -56,9 +58,11 @@ use TrigT1Interfaces	     TrigT1Interfaces-*         Trigger/TrigT1
 use TrigT1Result	         TrigT1Result-*             Trigger/TrigT1
 use TrigSerializeResult      TrigSerializeResult-*      Trigger/TrigDataAccess
 
+
 macro_append TrigCostMonitorLib_cppflags " `xml2-config --cflags`"
 macro_append TrigCostMonitorLib_use_linkopts " -L$(ROOTSYS)/lib -lXMLIO -lXMLParser"
 macro_append TrigCostMonitorLib_use_linkopts " -lxml2" slc4-gcc34 " /usr/lib/libxml2.so.2"
+macro_append TrigCostMonitorLib_use_linkopts " -lCTPfragment "
 
 apply_pattern lcgdict dict=TrigCostMonitor \
 	              selectionfile=selection.xml \
@@ -66,3 +70,7 @@ apply_pattern lcgdict dict=TrigCostMonitor \
 
 #macro cppdebugflags '$(cppdebugflags_s)'
 end_private
+
+# Following needs to be public
+macro_append TrigCostMonitorLib_use_linkopts " -lers -leformat -leformat_write "
+
diff --git a/Trigger/TrigMonitoring/TrigCostMonitor/python/TrigCostMonitorConfig.py b/Trigger/TrigMonitoring/TrigCostMonitor/python/TrigCostMonitorConfig.py
index f0a2a0e1407..f5cef6924e0 100644
--- a/Trigger/TrigMonitoring/TrigCostMonitor/python/TrigCostMonitorConfig.py
+++ b/Trigger/TrigMonitoring/TrigCostMonitor/python/TrigCostMonitorConfig.py
@@ -65,6 +65,7 @@ def prepareCostTool(target):
     tool.saveEventTimers  = True
     tool.stopAfterNEvent  = 800
     tool.execPrescale     = 1.0
+    tool.doConfigReduction = True # Online, only send config info from 1/50 PU nodes to reduce wasted bandwidth (only 1 copy needed at T0) 
     
     tool.toolConf     = Trig__TrigNtConfTool('Conf'+target)
     tool.toolEBWeight = Trig__TrigNtEBWeightTool('Ebwt'+target)
@@ -293,93 +294,6 @@ def prepareCostRun(name, option = 'hlt'):
 
     log.info('Prepared TrigCostRun algorithm instance: '+run.getName())
     return run
-
-#----------------------------------------------------------------------
-# prepare TrigCostAlg configuration for running offline trigger
-#
-def prepareCostAlg(name, option, suffix):
-
-    from AthenaCommon.AppMgr import ServiceMgr as svcMgr
-    if not hasattr(svcMgr, 'THistSvc'):
-        from GaudiSvc.GaudiSvcConf import THistSvc
-        svcMgr += THistSvc()
-
-    alg = TrigCostAlg(name)
-    log = logging.getLogger('prepareCostAlg')
-
-    conf_tool = Trig__TrigNtConfTool('CostConf_'+suffix)
-    post_tool = Trig__TrigNtPostTool('CostPost_'+suffix)    
-    vars_tool = Trig__TrigNtVarsTool('CostVars_'+suffix)
-
-    from TriggerJobOpts.TriggerFlags import TriggerFlags
-    conf_tool.triggerMenuSetup = TriggerFlags.triggerMenuSetup.get_Value()
-    conf_tool.L1PrescaleSet    = TriggerFlags.L1PrescaleSet.get_Value()
-    conf_tool.HLTPrescaleSet   = TriggerFlags.HLTPrescaleSet.get_Value()
-
-    alg.mergeEvent      = True
-    alg.printEvent      = True
-    vars_tool.collectTD = False
-
-    #
-    # Add all tools except TrigNtSaveTool - these tools have to be last in tool sequence
-    #
-    alg.tools += [conf_tool, vars_tool, post_tool]
-
-    #
-    # Attempt to add additional tools
-    #
-    try:
-        from TrigCostAthena.TrigCostAthenaConfig import CostAthenaToolsList
-        
-        for atool in CostAthenaToolsList:
-            alg.tools += [ atool ]
-            log.info('Added TrigCostAthena tool: '+atool.name())
-    except:
-        log.info('TrigCostAthena extra tools are not available... continue without them')
-            
-    #
-    # Add TrigNtSaveTool tool(s) - last after all other tools
-    #
-    if option.count('cost'):
-        svcMgr.THistSvc.Output += ["TrigCostAL DATAFILE='TrigCostAL.root' OPT='RECREATE'"]
-
-        save_cost = Trig__TrigNtSaveTool('CostSave_full_'+suffix)
-        save_cost.streamConfig  = 'TrigCostAL'
-        save_cost.streamEvent   = 'TrigCostAL'
-        save_cost.writeFile     = False
-        save_cost.writeRateOnly = False
-        
-        alg.tools += [save_cost]
-        
-    if option.count('rate'):
-        svcMgr.THistSvc.Output += ["TrigRateAL DATAFILE='TrigRateAL.root' OPT='RECREATE'"]
-
-        save_rate = Trig__TrigNtSaveTool('CostSave_rate_'+suffix)
-        save_rate.streamConfig  = 'TrigRateAL'
-        save_rate.streamEvent   = 'TrigRateAL'
-        save_rate.writeFile     = False
-        save_rate.writeRateOnly = True
-
-        alg.tools += [save_rate]
-
-    return alg
-
-#----------------------------------------------------------------------
-# Configure full offline cost algorithm
-#
-def setupCostAlg(config = ''):
-
-    log = logging.getLogger('setupCostAlg')
-    
-    from AthenaCommon.AlgSequence import AlgSequence
-    topSeq = AlgSequence()
-
-    if not hasattr(topSeq, 'TrigDecMaker'):
-        log.info('Setup TrigDecisionMaker...')
-        from TrigDecisionMaker.TrigDecisionMakerConfig import WriteTrigDecision
-        trigDecWriter = WriteTrigDecision()
-            
-    topSeq += prepareCostAlg('TrigCostAlg_offline', 'cost rate', 'offline')
     
 #----------------------------------------------------------------------
 # prepare TrigCostAlg configuration for reading online LV1 and HLT results
diff --git a/Trigger/TrigMonitoring/TrigCostMonitor/share/RunAOD.py b/Trigger/TrigMonitoring/TrigCostMonitor/share/RunAOD.py
deleted file mode 100644
index ebf033f2815..00000000000
--- a/Trigger/TrigMonitoring/TrigCostMonitor/share/RunAOD.py
+++ /dev/null
@@ -1,210 +0,0 @@
-
-#
-# This macro generates PhysicsNtuple data from AOD files
-#
-# Example command:
-#
-#  $ athena -c 'testMuon=True;EvtMax=200;setOption="minbias"' $TestArea/PhysicsNtuple/PhysicsAthena/share/savePhysicsData.py
-#
-#  -- testMuon, testData or testElec are used to select an input test file at CERN.
-#
-#  -- setOption string is passed to PhysicsAthenaConfig.preparePhysicsData function
-#
-
-from AthenaCommon.Logging import logging
-spd_log = logging.getLogger('RunAOD.py')
-
-#----------------------------------------------------------------------------------
-# Read list of input files from local directory
-#
-def readInput():
-
-    import os, string, sys
-    filelist = []
-    
-    try:
-        mylist = open("input_files.txt")
-        
-        for line in mylist.readlines():
-            if line.count('ESD') > 0 or line.count('AOD') > 0:
-                filelist.append(line.rstrip())
-                print 'Added file: ',line
-        mylist.close()
-    except:
-        pass
-
-    return filelist
-            
-#----------------------------------------------------------------------------------
-# Start script and configure input files
-#
-data_files = []
-if 'InputFiles' not in dir() :
-
-    pennww = 'root://eosatlas//eos/atlas/atlascerngroupdisk/penn-ww/test/'
-
-    if   ('testData10' in dir()):
-        data_files = [pennww+'data10_7TeV.00166466.physics_JetTauEtmiss.merge.AOD.r1774_p327_p333_tid207114_00/AOD.207114._000137.pool.root.1']
-    elif ('testMuon10' in dir()):
-        data_files = [pennww+'data10_7TeV.00166466.physics_Muons.merge.AOD.r1774_p327_p333_tid207199_00/AOD.207199._000026.pool.root.1']
-    elif ('testElec10' in dir()):
-        data_files = [pennww+'data10_7TeV.00166466.physics_Egamma.merge.AOD.r1774_p327_p333_tid207275_00/AOD.207275._000048.pool.root.4']                
-    elif ('testData11' in dir() or 'testData' in dir()):
-        data_files = [pennww+'data11_7TeV.00180636.physics_JetTauEtmiss.merge.AOD.f371_m824/data11_7TeV.00180636.physics_JetTauEtmiss.merge.AOD.f371_m824._lb0095-lb0096._0001.1']
-    elif ('testMuon11' in dir() or 'testMuon' in dir()):
-        data_files = [pennww+'data11_7TeV.00180636.physics_Muons.merge.AOD.f371_m824/data11_7TeV.00180636.physics_Muons.merge.AOD.f371_m824._lb0149-lb0151._0001.1']
-    elif ('testElec11' in dir() or 'testElec' in dir()):
-        data_files = [pennww+'data11_7TeV.00180636.physics_Egamma.merge.AOD.f371_m824/data11_7TeV.00180636.physics_Egamma.merge.AOD.f371_m824._lb0737-lb0739._0001.1']
-    elif ('testMuon12' in dir()):
-        data_files = [pennww+'data12_8TeV.00201555.physics_Muons.merge.AOD.f437_m1126/data12_8TeV.00201555.physics_Muons.merge.AOD.f437_m1126._lb0095._0001.1']
-    elif ('testElec12' in dir()):
-        data_files = [pennww+'data12_8TeV.00201555.physics_Egamma.merge.AOD.f437_m1126/data12_8TeV.00201555.physics_Egamma.merge.AOD.f437_m1126._lb0126._0001.1']    
-    elif ('testMC10' in dir()):
-        data_files = [pennww+'mc10_7TeV.105925.McAtNlo_JIMMY_WpWm_munuenu.merge.AOD.e598_s933_s946_r1831_r2040_tid266759_00/AOD.266759._000008.pool.root.1']
-    elif ('testMC11' in dir()):
-        data_files = [pennww+'mc11_7TeV.106047.PythiaZmumu_no_filter.merge.AOD.e815_s1272_s1274_r3043_r2993/AOD.645509._001019.pool.root.1']
-    elif ('testMC12' in dir()):
-        data_files = [pennww+'mc12_8TeV.147807.PowhegPythia8_AU2CT10_Zmumu.merge.AOD.e1169_s1469_s1470_r3542_r3549_tid779181_00/AOD.779181._000485.pool.root.1']
-    elif ('testFile' in dir()):
-        data_files = [testFile]
-    
-    if ('data_files' not in dir()) or len(data_files) < 1:
-        data_files = readInput()
-    
-    if len(data_files) < 1:
-        spd_log.error('Missing input files...')
-        import sys
-        sys.exit(1)
-    
-else :
-    data_files = InputFiles
-
-if not ('EvtMax' in dir()):
-    EvtMax = -1
-
-if ('setEvent' in dir()):
-    EvtMax = setEvent
-    
-#----------------------------------------------------------------------------------
-# Do auto configuration
-#
-spd_log.info('Do auto configuration...')
-
-from AthenaCommon.AthenaCommonFlags import athenaCommonFlags
-athenaCommonFlags.FilesInput.set_Value_and_Lock( data_files )
-athenaCommonFlags.EvtMax.set_Value_and_Lock( EvtMax )
-
-spd_log.info('Update EvtMax to: %d' %athenaCommonFlags.EvtMax())
-del EvtMax
-
-from RecExConfig.InputFilePeeker import inputFileSummary
-from RecExConfig.RecFlags import rec
-
-rec.AutoConfiguration = [ 'everything' ]
-rec.readRDO                 .set_Value_and_Lock( False )
-rec.doCBNT                  .set_Value_and_Lock( False )
-rec.doWriteESD              .set_Value_and_Lock( False )
-rec.doWriteAOD              .set_Value_and_Lock( False )
-rec.doWriteTAG              .set_Value_and_Lock( False )
-rec.doWriteTAGCOM           .set_Value_and_Lock( False )
-rec.doESD                   .set_Value_and_Lock( False )
-rec.doAOD                   .set_Value_and_Lock( False )
-rec.doDPD                   .set_Value_and_Lock( False )
-rec.doHist                  .set_Value_and_Lock( False )
-rec.doPerfMon               .set_Value_and_Lock( False )
-rec.doForwardDet            .set_Value_and_Lock( False )
-rec.doFloatingPointException.set_Value_and_Lock( False )
-rec.doTrigger               .set_Value_and_Lock( True )
-rec.RootNtupleOutput        .set_Value_and_Lock( 'test.root' )
-rec.RootHistoOutput         .set_Value_and_Lock( 'test.root' )
-
-#from RecExConfig.RecAlgsFlags  import recAlgs
-#recAlgs.doMissingET.set_Value_and_Lock(True)
-
-
-from PerfMonComps.PerfMonFlags import jobproperties as pmon_properties
-
-pmon_properties.PerfMonFlags.doSemiDetailedMonitoring.set_Value_and_Lock(False)
-
-# To Re-run the Electron ID
-#from egammaRec.egammaRecFlags import jobproperties
-#jobproperties.egammaRecFlags.doAODRender.set_Value_and_Lock(True)
-
-include('RecExCommon/RecExCommon_topOptions.py')
-
-spd_log.info('Finished setting up RecExConfig...')
-
-if ('printAuto' in dir()):
-    spd_log.info('Print inputFileSummary with %d element(s)' %len(inputFileSummary))
-    
-    for k, v in inputFileSummary.iteritems():
-        print k, v
-        
-#----------------------------------------------------------------------------------
-# Set up trigger
-#
-from TriggerJobOpts.TriggerFlags import TriggerFlags
-#setMenu = 'Physics_pp_v1'
-#TriggerFlags.triggerMenuSetup = setMenu
-TriggerFlags.readLVL1configFromXML=False
-TriggerFlags.readHLTconfigFromXML=False
-TriggerFlags.inputLVL1configFile=''
-TriggerFlags.inputHLTconfigFile=''
-
-TriggerFlags.readBS   = False
-TriggerFlags.doLVL1   = True
-TriggerFlags.doLVL2   = True
-TriggerFlags.doEF     = True
-TriggerFlags.doNtuple = True
-
-#TriggerFlags.L1PrescaleSet  = 'L1Prescales100_' +TriggerFlags.triggerMenuSetup()
-#TriggerFlags.HLTPrescaleSet = 'HLTPrescales100_'+TriggerFlags.triggerMenuSetup()
-TriggerFlags.configurationSourceList=['xml']
-TriggerFlags.enableMonitoring = [ 'Time', 'CostAthena' ]
-TriggerFlags.disableRandomPrescale=False
-
-from TriggerJobOpts.TriggerConfigGetter import TriggerConfigGetter
-TriggerConfigGetter('ReadPool')
-
-#----------------------------------------------------------------------------------
-# Useful formatting options and debugging information
-#
-ServiceMgr.MessageSvc.OutputLevel = INFO
-ServiceMgr.MessageSvc.defaultLimit = 10000000
-ServiceMgr.MessageSvc.Format = '% F%50W%S%7W%R%T %0W%M'
-
-if ('dumpSG' in dir()) and dumpSG:
-    StoreGateSvc = Service('StoreGateSvc')
-    StoreGateSvc.Dump = True
-
-if ('dumpMC' in dir()) and dumpMC:
-    from TruthExamples.TruthExamplesConf import DumpMC
-    DumpMC.McEventKey = 'GEN_AOD'
-    topSeq += DumpMC()
-
-if not hasattr(ServiceMgr, 'AthenaEventLoopMgr'):
-    from AthenaServices.AthenaServicesConf import AthenaEventLoopMgr
-    ServiceMgr += AthenaEventLoopMgr()
-
-ServiceMgr.AthenaEventLoopMgr.EventPrintoutInterval = 100
-
-if ('allowAbort' in dir()) and allowAbort:
-    spd_log.info('Enable job abort on exception')
-    from AthenaCommon.AthenaCommonFlags import jobproperties
-    jobproperties.AthenaCommonFlags.RuntimeStrictness.set_Value_and_Lock('abort')
-
-
-from TrigCostMonitor.TrigCostMonitorConfig import readInputFiles
-inputfilelist = readInputFiles('input_files.txt','AOD')
-
-from TrigCostMonitor.TrigCostMonitorConfig import setupCostAlg, setupCostJob, setupCostExtras
-setupCostAlg()
-setupCostJob()
-setupCostExtras()
-
-#from TrigCostMonitor.TrigCostMonitorConfig import prepareCostAlg
-#runAlg = prepareCostAlg('TrigCostAlg', 'rate', 'read')
-
-#from AthenaCommon.AlgSequence import AlgSequence
-#topSeq = AlgSequence()
-#topSeq += [runAlg]
diff --git a/Trigger/TrigMonitoring/TrigCostMonitor/src/TrigCostTool.cxx b/Trigger/TrigMonitoring/TrigCostMonitor/src/TrigCostTool.cxx
index d6eb79e4dc2..f64bda4412e 100644
--- a/Trigger/TrigMonitoring/TrigCostMonitor/src/TrigCostTool.cxx
+++ b/Trigger/TrigMonitoring/TrigCostMonitor/src/TrigCostTool.cxx
@@ -44,6 +44,8 @@ TrigCostTool::TrigCostTool(const std::string& type,
   :AthAlgTool(type, name, parent),
    m_appId(0),
    m_appName(), 
+   m_configReductionValue(0),
+   m_doConfigReduction(0),
    m_parentAlg(0),
    m_timer(0),
    m_timerSvc("TrigTimerSvc/TrigTimerSvc", name),
@@ -95,6 +97,9 @@ TrigCostTool::TrigCostTool(const std::string& type,
   declareProperty("onlySaveCostEvent",m_onlySaveCostEvent= true, "Only save events which have passed the OPI prescale which run all scale tools");
   declareProperty("obeyCostChainPS",  m_obeyCostChainPS  = true, "Only monitor events if the cost chain prescale is > 0");
 
+  declareProperty("configReductionValue", m_configReductionValue = 50, "Random chance, 1/Value, that this PU gets chosen to write out configs to T0.");
+  declareProperty("doConfigReduction", m_doConfigReduction = false, "Reduce duplicate configs being sent by every PU online. Only send from 1/configReuctionValue PUs.");
+
   declareProperty("stopAfterNEvent",  m_stopAfterNEvent  = 1000);
   declareProperty("execPrescale",     m_execPrescale     = 1.0);
   declareProperty("doOperationalInfo",m_doOperationalInfo= 1.0, "Parent steering value of doOperationalInfo, used to control how often CostMon executes"); // Only for reference here
@@ -201,6 +206,8 @@ StatusCode TrigCostTool::initialize()
     }
   }
 
+  m_appId = m_configReductionValue;
+
   ATH_MSG_INFO("level            = " << m_level            );
   ATH_MSG_INFO("monitoringLogic  = " << m_monitoringLogic  );
   ATH_MSG_INFO("monitoringStream = " << m_monitoringStream );
@@ -219,6 +226,8 @@ StatusCode TrigCostTool::initialize()
   ATH_MSG_INFO("doOperationalInfo= " << m_doOperationalInfo);
   ATH_MSG_INFO("printEvent       = " << m_printEvent       );
   ATH_MSG_INFO("obeyCostChainPS  = " << m_obeyCostChainPS  );
+  ATH_MSG_INFO("doConfigReduction= " << m_doConfigReduction);
+  ATH_MSG_INFO("configReducValue = " << m_configReductionValue);
 
   return StatusCode::SUCCESS;
 }
@@ -311,6 +320,25 @@ StatusCode TrigCostTool::fillHists()
 
   const unsigned opiLevel = m_parentAlg->getAlgoConfig()->getSteeringOPILevel(); // Have I passed the OPI "prescale"?
 
+  // Get My PU name
+  if (m_appId == m_configReductionValue) {
+    const HLT::HLTResult *hlt_result = 0;
+    if(!evtStore()->contains<HLT::HLTResult>(m_hltResult)) {
+      ATH_MSG_DEBUG("StoreGate does not contain HLTResult: " << m_hltResult);
+    } else if(evtStore()->retrieve<HLT::HLTResult>(hlt_result, m_hltResult).isFailure() || !hlt_result) {
+       ATH_MSG_DEBUG("Failed to retrieve HLTResult: " << m_hltResult);
+    } else {
+      const std::vector<uint32_t> &extraData = hlt_result->getExtras();
+      if(extraData.empty()) {
+        ATH_MSG_DEBUG("Extra data is empty");
+      } else {
+        StringSerializer().deserialize(extraData, m_appName); 
+        m_appId = TrigConf::HLTUtils::string2hash(m_appName, "APP_ID_TCT");
+        ATH_MSG_DEBUG("Running on " << m_appName << " with hash " << m_appId);
+      }
+    }
+  }
+
   // Have I passed my own personal "prescale" (not this is currently not used)
   bool _prescaleDecision = true;
   if (m_execPrescale) {
@@ -412,6 +440,16 @@ StatusCode TrigCostTool::fillHists()
       return StatusCode::SUCCESS;
     }    
 
+    // See if this PU is writing CONFIG data
+    if (m_doConfigReduction == true) {
+      if (m_appId % m_configReductionValue != 0) {
+        m_bufferConfig.clear();
+        ATH_MSG_DEBUG( "This PU, " << m_appName << ", hash " << m_appId << " is not divisible by " << m_configReductionValue << " NOT writing");
+      } else {
+        ATH_MSG_DEBUG( "This PU, " << m_appName << ", hash " << m_appId << " is divisible by " << m_configReductionValue << " writing config");
+      }
+    }
+
     if(!m_bufferConfig.empty()) {
 
       std::string config_key;
@@ -614,7 +652,14 @@ void TrigCostTool::ProcessConfig(xAOD::EventInfo* info)
         }
       }
 
-      if(m_writeConfig || (m_writeAlways && m_level == "EF") || (m_writeAlways && m_level == "HLT")) {
+      bool writeConfig = true;
+      if      (m_writeAlways == true) writeConfig = true; // First check WriteAlways flag
+      else if (m_writeConfig == false) writeConfig = false; // Next comes WriteConfig flag. This is normally true.
+      else if (m_costForCAF == true) writeConfig = true; // If offline, then we don't have any other preconditions
+      else if (m_obeyCostChainPS == true && m_costChainPS > 0) writeConfig = true; // Online, we normally only write out if we are in stable beams
+      else if (m_obeyCostChainPS == true && m_costChainPS <= 0) writeConfig = false;
+      
+      if(writeConfig) {
         m_bufferConfig.push_back(new TrigMonConfig(m_config_sv));
         ATH_MSG_DEBUG( "ProcessConfig - writing out full svc configuration" );
       }
diff --git a/Trigger/TrigMonitoring/TrigCostMonitor/src/TrigNtConfTool.cxx b/Trigger/TrigMonitoring/TrigCostMonitor/src/TrigNtConfTool.cxx
index 85e59bd29ee..e4d144683b1 100644
--- a/Trigger/TrigMonitoring/TrigCostMonitor/src/TrigNtConfTool.cxx
+++ b/Trigger/TrigMonitoring/TrigCostMonitor/src/TrigNtConfTool.cxx
@@ -19,6 +19,10 @@
 #include "TrigConfL1Data/CTPConfig.h"
 #include "TrigConfL1Data/Menu.h"
 #include "TrigConfL1Data/PrescaleSet.h"
+#include "TrigT1Result/CTP_RDO.h"
+#include "CTPfragment/CTPfragment.h"
+#include "CTPfragment/CTPExtraWordsFormat.h"
+#include "CTPfragment/Issue.h"
 
 // Loader classes
 #include "TrigConfStorage/StorageMgr.h"
@@ -48,7 +52,8 @@ Trig::TrigNtConfTool::TrigNtConfTool(const std::string &name,
    m_countConfig_db(0),
    m_countConfig_sv(0),
    m_run(0),
-   m_dbOrConfSvcPass(0)
+   m_dbOrConfSvcPass(0),
+   m_currentL1PSK(0)
 {
   declareInterface<Trig::ITrigNtTool>(this);
 
@@ -120,7 +125,7 @@ bool Trig::TrigNtConfTool::Fill(TrigMonConfig *confg)
   ATH_MSG_DEBUG("Filling Trigger Configuration using Option: " << m_dbOrConfSvcPass << ". (1=ConfSvc, 2=DB)." );
 
   // Require each call of "Fill" to act on only one of DB or ConfSvc
-  if(m_dbOrConfSvcPass < 1 && m_dbOrConfSvcPass > 2) {
+  if(m_dbOrConfSvcPass != 1 && m_dbOrConfSvcPass != 2) {
     ATH_MSG_WARNING("Set one of SetOption(1) for ConfSvc OR SetOption(2) for DB to true before calling Fill" );
     return false;
   }
@@ -187,6 +192,43 @@ bool Trig::TrigNtConfTool::Fill(TrigMonEvent &event)
   return true;
 }
 
+uint32_t Trig::TrigNtConfTool::GetL1PSK(bool updateValue) {
+
+  if (updateValue == true) {
+    ATH_MSG_DEBUG("Updating L1 PSK value from CTP fragment.");
+
+    const CTP_RDO* ctpRDO = nullptr; 
+    ctpRDO = evtStore()->tryConstRetrieve<CTP_RDO>();
+    if (!ctpRDO) {
+      ATH_MSG_WARNING("Could not retrieve CTP_RDO (converted from CTP DAQ ROB). Cannot update L1 prescale key in HLT Cost Monitoring.");
+      return m_currentL1PSK;
+    }
+
+    // Expect at least 2 initial words, plus our payload, plus extra folders (optional)
+    std::vector<uint32_t> l1ExtraPayload = ctpRDO->getEXTRAWords();
+    if (l1ExtraPayload.size() < 3) {
+      ATH_MSG_WARNING("Extra data in CTP_RDO was size < 3. Cannot update L1 prescale key in HLT Cost Monitoring.");
+      return m_currentL1PSK;
+    }
+
+    // Remove first two entries (time since previous crossing and turn counter)
+    l1ExtraPayload.erase(l1ExtraPayload.begin(), l1ExtraPayload.begin()+2);
+
+    // Extra check - we don't want CTPfragment to trip up decoding this
+    if (l1ExtraPayload.size() > 1 && l1ExtraPayload.at(1) > l1ExtraPayload.size() - 2) {
+      ATH_MSG_WARNING("Mal-formatted extra payload data. Cannot update L1 prescale key in HLT Cost Monitoring.");
+      return m_currentL1PSK;
+    }
+
+    CTPfragment::ExtraPayload ctp_payload(l1ExtraPayload);
+    m_currentL1PSK = ctp_payload.getL1PSK();
+    ATH_MSG_DEBUG("L1 PSK is now " << m_currentL1PSK);
+ 
+  }
+
+  return m_currentL1PSK;
+}
+
 //---------------------------------------------------------------------------------------
 bool Trig::TrigNtConfTool::GetKeysChangedFromSv(TrigMonConfig &confg) {
 
@@ -196,27 +238,18 @@ bool Trig::TrigNtConfTool::GetKeysChangedFromSv(TrigMonConfig &confg) {
      return true;
   }
 
-  // Latter calls
-  // Get if any of the keys have changed 
-  //
-  const TrigConf::CTPConfig *ctp_confg = m_configSvc->ctpConfig();
-  if(!ctp_confg) {
-    ATH_MSG_WARNING("Failed to get CTPConfig or Menu" );
-    return false;
+  if ( m_configSvc->masterKey() != confg.getMasterKey() ) {
+    ATH_MSG_DEBUG("Master key has changed from " << confg.getMasterKey() << " to " << m_configSvc->masterKey() << " - (re)fill " );
+    return true;
+  } else if ( (int)GetL1PSK() != (int)confg.getLV1PrescaleKey() ) {
+    ATH_MSG_DEBUG("L1 key has changed from " << confg.getLV1PrescaleKey() << " to " << GetL1PSK() << " - (re)fill " );
+    return true;
+  } else  if ( m_configSvc->hltPrescaleKey() != confg.getHLTPrescaleKey() ) {
+    ATH_MSG_DEBUG("HLT key has changed from " << confg.getHLTPrescaleKey() << " to " << m_configSvc->hltPrescaleKey() << " - (re)fill " );
+    return true;
   }
-
-   if ( m_configSvc->masterKey() != confg.getMasterKey() ) {
-     ATH_MSG_DEBUG("Master key has changed from " << confg.getMasterKey() << " to " << m_configSvc->masterKey() << " - (re)fill " );
-     return true;
-   } else if ( (int)ctp_confg->prescaleSetId() != (int)confg.getLV1PrescaleKey() ) {
-     ATH_MSG_DEBUG("L1 key has changed from " << confg.getMasterKey() << " to " << ctp_confg->prescaleSetId() << " - (re)fill " );
-     return true;
-   } else  if ( m_configSvc->hltPrescaleKey() != confg.getHLTPrescaleKey() ) {
-     ATH_MSG_DEBUG("HLT key has changed from " << confg.getHLTPrescaleKey() << " to " << m_configSvc->hltPrescaleKey() << " - (re)fill " );
-     return true;
-   }
-   ATH_MSG_DEBUG("No kyes have changed from ConfigSvc - no need to fetch config again " );
-   return false;
+  ATH_MSG_DEBUG("No kyes have changed from ConfigSvc - no need to fetch config again " );
+  return false;
 
 }
 
@@ -226,6 +259,7 @@ bool Trig::TrigNtConfTool::ReadFromSv(TrigMonConfig &confg)
   //
   // Fill trigger configuration from config service
   //
+  GetL1PSK(true); // Update cached value for L1 PSK
 
   // Do we need to update?
   if (GetKeysChangedFromSv(confg) == false) {
@@ -258,12 +292,12 @@ bool Trig::TrigNtConfTool::ReadFromSv(TrigMonConfig &confg)
     return false;
   }
 
-  ATH_MSG_INFO("Exporting a new TrigConf from ConfigSvc for : SMK,L1,HLT=" << m_configSvc->masterKey() << "," << ctp_confg->prescaleSetId() << "," << m_configSvc->hltPrescaleKey() );
+  ATH_MSG_INFO("Exporting a new TrigConf from ConfigSvc for : SMK,L1,HLT=" << m_configSvc->masterKey() << "," << GetL1PSK() << "," << m_configSvc->hltPrescaleKey() );
 
   std::stringstream _ss1, _ss2, _ss3;
   _ss1 << m_configSvc->masterKey();
   _ss1 >> m_triggerMenuSetup;
-  _ss2 << ctp_confg->prescaleSetId();
+  _ss2 << GetL1PSK();
   _ss2 >> m_L1PrescaleSet;
   _ss3 << m_configSvc->hltPrescaleKey();
   _ss3 >> m_HLTPrescaleSet;
@@ -277,14 +311,14 @@ bool Trig::TrigNtConfTool::ReadFromSv(TrigMonConfig &confg)
     if(m_configSvc->hltPrescaleKey()  != confg.getHLTPrescaleKey()) {
       conf.UpdateHLT(confg, *chn_confg);
     }
-    if((unsigned)ctp_confg->prescaleSetId() != confg.getLV1PrescaleKey()) {
+    if((unsigned)GetL1PSK() != confg.getLV1PrescaleKey()) {
       conf.UpdateLV1(confg, *ctp_confg);
     }
 
     ATH_MSG_DEBUG("SMK has not changed: " << confg.getMasterKey() << ", just reading in updates prescales." );
     
     confg.setTriggerKeys(m_configSvc->masterKey(), 
-       ctp_confg->prescaleSetId(), 
+       GetL1PSK(), 
        m_configSvc->hltPrescaleKey());
 
     conf.FillVar(confg, m_triggerMenuSetup, m_L1PrescaleSet, m_HLTPrescaleSet);
@@ -350,7 +384,7 @@ bool Trig::TrigNtConfTool::ReadFromSv(TrigMonConfig &confg)
 
 
   confg.setTriggerKeys(m_configSvc->masterKey(), 
-           ctp_confg->prescaleSetId(), 
+           GetL1PSK(), 
            m_configSvc->hltPrescaleKey());
   
   confg.addValue("SOURCE", "CONFIG_SVC");
-- 
GitLab