diff --git a/TileCalorimeter/TileMonitoring/CMakeLists.txt b/TileCalorimeter/TileMonitoring/CMakeLists.txt index 4614de9887add6d961a016f86ee0483595818ce1..1056e141472d423c08a4661b7652f7f84ad3f92c 100644 --- a/TileCalorimeter/TileMonitoring/CMakeLists.txt +++ b/TileCalorimeter/TileMonitoring/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration +# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration # Declare the package name: atlas_subdir( TileMonitoring ) @@ -138,3 +138,8 @@ atlas_add_test( TileTBCellMonitorAlgorithm_test SCRIPT python -m TileMonitoring.TileTBCellMonitorAlgorithm PROPERTIES TIMEOUT 600 POST_EXEC_SCRIPT nopost.sh) + +atlas_add_test( RunTileTBMonitoring_test + SCRIPT python -m TileMonitoring.RunTileTBMonitoring --use-sqlite '' + PROPERTIES TIMEOUT 600 + POST_EXEC_SCRIPT nopost.sh) diff --git a/TileCalorimeter/TileMonitoring/python/RunTileTBMonitoring.py b/TileCalorimeter/TileMonitoring/python/RunTileTBMonitoring.py new file mode 100644 index 0000000000000000000000000000000000000000..c1bb97d5f71cec068bd749dabf33d5bdc9ff55b0 --- /dev/null +++ b/TileCalorimeter/TileMonitoring/python/RunTileTBMonitoring.py @@ -0,0 +1,321 @@ +#!/usr/bin/env python +# +# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration +# +''' +@file RunTileTBMonitoring.py +@brief Script to run Tile TestBeam Reconstrcution/Monitoring +''' + +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator +from AthenaConfiguration.Enums import Format, BeamType +from AthenaConfiguration.AutoConfigFlags import GetFileMD +from TileConfiguration.TileConfigFlags import TileRunType + +import os +import sys + + +def configureFlagsAndArgsFromPartition(flags, args, partition, log): + """ + Configure the flags and args from partition in online + + Configure the following flags from partition in online: + run type, run number, beam type, beam energy, project + + Configure the following args from partition in online: args.nsamples + """ + + from ipc import IPCPartition + from ispy import ISObject + ipcPartition = IPCPartition(partition) + if not ipcPartition.isValid(): + log.error('Partition: ' + ipcPartition.name() + ' is not valid') + sys.exit(1) + + # Set up default values + runType = 'Physics' + beamType = 'collisions' + beamEnergy = 200 # In TileTB: [GeV] + runNumber = 2400000 + project = 'data_H8' + + try: + runParams = ISObject(ipcPartition, 'RunParams.SOR_RunParams', 'RunParams') + except Exception: + log.warning(f'No Run Parameters in IS => Set defaults: partition: {partition}, beam type: {beamType}' + + f', beam energy: {beamEnergy}, run number: {runNumber}, project tag: {project}') + else: + runParams.checkout() + beamType = runParams.beam_type + beamEnergy = runParams.beam_energy + runNumber = runParams.run_number + project = runParams.T0_project_tag + runType = runParams.run_type + log.info(f'RUN CONFIGURATION: run type: {runType}, beam type: {beamType}' + + f', beam energy: {beamEnergy}, run number: {runNumber}, project: {project}') + + try: + cisParams = ISObject(ipcPartition, 'TileParams.cispar', 'TileCISparameters') + except Exception: + log.info('Could not find Tile Parameters in IS') + else: + try: + cisParams.checkout() + except Exception: + log.info("Could not get Tile Parameters from IS") + else: + log.info(f'TILE CONFIGURATION: CISPAR size: {len(cisParams.data)}') + cispar = 'TILE CONFIGURATION: CISPAR: ' + for d in cisParams.data: + cispar += ' ' + str(d) + log.info(cispar) + + if len(cisParams.data) == 16: + data = cisParams.data + if data[12] == 1: + runType = 'Physics' + elif data[12] == 2: + runType = 'Laser' + elif data[12] == 4: + runType = 'Pedestals' + elif data[12] == 8: + runType = 'CIS' + + log.info(f'TILE CONFIGURATION: RunType: {runType}, Mode: {data[0]}, Samples: {data[1]}, Pipeline: {data[2]}' + + f', I3Delay: {data[3]}, Event: {data[4]}, Phase: {data[5]}, DAC: {data[6]}, Capacity: {data[7]}') + + # Try to get number of samples from partition + nSamples = 15 # Default number of samples + try: + dspConfig = ISObject(ipcPartition, 'TileParams.TileCal_DSPConfig', 'TileCal_IS_DSPConfig') + except Exception: + log.info("Could not find Tile DSP Config in IS => set default number of samples to {nSamples}") + else: + try: + dspConfig.checkout() + except Exception: + log.info("Could not get Tile DSP Config from IS => set default number of samples to {nSamples}") + else: + nSamples = dspConfig.samples + log.info("Set number of samples from DSP Config in IS: {nSamples}") + + if 'Physics' in runType: + flags.Tile.RunType = TileRunType.PHY + elif 'CIS' in runType: + flags.Tile.RunType = TileRunType.MONOCIS if 'mono' in runType else TileRunType.CIS + elif 'Laser' in runType: + flags.Tile.RunType = TileRunType.LAS + elif 'Pedestals' in runType: + flags.Tile.RunType = TileRunType.PED + + flags.Beam.Type = BeamType(beamType) + flags.Beam.Energy = beamEnergy + flags.Input.ProjectName = project + flags.Input.RunNumbers = [runNumber] + args.nsamples = nSamples + + +def TileTestBeamMonitoringCfg(flags, fragIDs=[0x100, 0x101, 0x200, 0x201, 0x402], **kwargs): + + ''' Function to configure Tile TestBeam monitoring.''' + + acc = ComponentAccumulator() + + from TileMonitoring.TileTBBeamMonitorAlgorithm import TileTBBeamMonitoringConfig + acc.merge(TileTBBeamMonitoringConfig(flags, fragIDs=fragIDs)) + + from TileMonitoring.TileTBMonitorAlgorithm import TileTBMonitoringConfig + acc.merge(TileTBMonitoringConfig(flags, fragIDs=fragIDs)) + + from TileMonitoring.TileTBPulseMonitorAlgorithm import TileTBPulseMonitoringConfig + acc.merge(TileTBPulseMonitoringConfig(flags, timeRange=[-200, 200], fragIDs=fragIDs)) + + from TileMonitoring.TileTBCellMonitorAlgorithm import TileTBCellMonitoringConfig + acc.merge(TileTBCellMonitoringConfig(flags, timeRange=[-200, 200], fragIDs=fragIDs)) + + from TileMonitoring.TileDigitsFlxMonitorAlgorithm import TileDigitsFlxMonitoringConfig + acc.merge(TileDigitsFlxMonitoringConfig(flags, TileDigitsContainerFlx="TileDigitsFlxFiltered")) + + from TileMonitoring.TileRawChannelFlxMonitorAlgorithm import TileRawChannelFlxMonitoringConfig + acc.merge(TileRawChannelFlxMonitoringConfig(flags, TileRawChannelContainerFlx="TileRawChannelFlxFit")) + + return acc + + +if __name__ == '__main__': + + # Setup logs + from AthenaCommon.Logging import log + from AthenaCommon.Constants import INFO + log.setLevel(INFO) + + # Set the Athena configuration flags + from AthenaConfiguration.AllConfigFlags import initConfigFlags + from AthenaConfiguration.TestDefaults import defaultTestFiles + + flags = initConfigFlags() + parser = flags.getArgumentParser() + parser.add_argument('--preExec', help='Code to execute before locking configs') + parser.add_argument('--postExec', help='Code to execute after setup') + parser.add_argument('--printConfig', action='store_true', help='Print detailed Athena configuration') + parser.add_argument('--dumpArguments', action='store_true', help='Print arguments and exit') + parser.add_argument('--frag-ids', dest='fragIDs', nargs="*", default=['0x100', '0x101', '0x200', '0x201', '0x402'], + help='Tile Frag IDs of modules to be monitored. Empty=ALL') + parser.add_argument('--demo-cabling', dest='demoCabling', type=int, default=2018, help='Time Demonatrator cabling to be used') + parser.add_argument('--nsamples', type=int, default=15, help='Number of samples') + parser.add_argument('--use-sqlite', dest='useSqlite', default='/afs/cern.ch/user/t/tiledemo/public/efmon/condb/tileSqlite.db', + help='Providing local SQlite file, conditions constants will be used from it') + + parser.add_argument('--stateless', action="store_true", help='Run Online Tile TB monitoring in partition') + parser.add_argument('--partition', default="", help='EMON, Partition name, default taken from $TDAQ_PARTITION if not set') + parser.add_argument('--key', type=str, default='ReadoutApplication', help='EMON, Selection key, e.g.: ReadoutApplication (TileTB)') + parser.add_argument('--keyValue', default=['TileREB-ROS'], help='EMON, Key values, e.g.: TileREB-ROS (TileTB)') + parser.add_argument('--keyCount', type=int, default=0, help='EMON, key count, e.g. 5 to get five random SFIs') + parser.add_argument('--publishName', default='TilePT-stateless-tb', help='EMON, Name under which to publish histograms') + parser.add_argument('--include', default="", help='EMON, Regular expression to select histograms to publish') + parser.add_argument('--lvl1Items', default=[], help='EMON, A list of L1 bit numbers, default []') + parser.add_argument('--lvl1Names', default=[], help='EMON, A list of L1 bit names, default []') + parser.add_argument('--lvl1Logic', default='Ignore', choices=['And','Or','Ignore'], help='EMON, default: Ignore') + parser.add_argument('--lvl1Origin', default='TAV', choices=['TBP','TAP','TAV'], help='EMON, default: TAV') + parser.add_argument('--streamType', default='physics', help='EMON, HLT stream type (e.g. physics or calibration)') + parser.add_argument('--streamNames', default=['tile'], help='EMON, List of HLT stream names') + parser.add_argument('--streamLogic', default='Ignore', choices=['And','Or','Ignore'], help='EMON, default: Ignore') + parser.add_argument('--triggerType', type=int, default=256, help='EMON, LVL1 8 bit trigger type, default: 256') + parser.add_argument('--groupName', default="TileTBMon", help='EMON, Name of the monitoring group') + + update_group = parser.add_mutually_exclusive_group() + update_group.add_argument('--frequency', type=int, default=0, help='EMON, Frequency (in number of events) of publishing histograms') + update_group.add_argument('--updatePeriod', type=int, default=30, help='EMON, Frequency (in seconds) of publishing histograms') + + args, _ = parser.parse_known_args() + + if args.dumpArguments: + log.info('=====>>> FINAL ARGUMENTS FOLLOW') + print('{:40} : {}'.format('Argument Name', 'Value')) + for a,v in (vars(args)).items(): + print(f'{a:40} : {v}') + sys.exit(0) + + fragIDs = [int(fragID, base=16) for fragID in args.fragIDs] + + # Initially the following flags are not set up (they must be provided) + flags.Input.Files = [] + + # Initial configuration flags from command line arguments (to be used to set up defaults) + flags.fillFromArgs(parser=parser) + + # =======>>> Set the Athena configuration flags to defaults (can be overriden via comand line) + flags.DQ.useTrigger = False + flags.DQ.enableLumiAccess = False + flags.Exec.MaxEvents = 3 + flags.Common.isOnline = True + flags.GeoModel.AtlasVersion = 'ATLAS-R2-2015-04-00-00' + + flags.Tile.doFit = True + flags.Tile.useDCS = False + flags.Tile.NoiseFilter = 0 + flags.Tile.correctTime = False + flags.Tile.correctTimeJumps = False + flags.Tile.BestPhaseFromCOOL = False + flags.Tile.doOverflowFit = False + + flags.Exec.PrintAlgsSequence = True + + if args.stateless: + flags.Input.isMC = False + flags.Input.Format = Format.BS + partition = args.partition if args.partition else os.getenv('TDAQ_PARTITION', 'TileTB') + configureFlagsAndArgsFromPartition(flags, args, partition, log) + else: + flags.Tile.RunType = TileRunType.PHY + flags.Beam.Type = BeamType.Collisions + # Get beam energy from meta data (Tile TB setup: [GeV]) + flags.Beam.Energy = GetFileMD(flags.Input.Files).get("beam_energy", 100) + + if not (args.filesInput or flags.Input.Files): + flags.Input.Files = defaultTestFiles.RAW_RUN2 + + # =======>>> Override default configuration flags from command line arguments + flags.fillFromArgs(parser=parser) + + if not flags.Output.HISTFileName: + runNumber = flags.Input.RunNumbers[0] + flags.Output.HISTFileName = f'tiletbmon_{runNumber}.root' + + if args.preExec: + log.info('Executing preExec: %s', args.preExec) + exec(args.preExec) + + flags.lock() + + log.info('=====>>> FINAL CONFIG FLAGS SETTINGS FOLLOW:') + flags.dump(pattern='Tile.*|Input.*|Exec.*|IOVDb.[D|G].*', evaluate=True) + + # =======>>> Initialize configuration object, add accumulator, merge, and run + from AthenaConfiguration.MainServicesConfig import MainServicesCfg + cfg = MainServicesCfg(flags) + + # =======>>> Configure Tile raw data (digits) reading + from TileByteStream.TileByteStreamConfig import TileRawDataReadingCfg + cfg.merge( TileRawDataReadingCfg(flags, readMuRcv=False, + readDigits=True, + readRawChannel=True, + readDigitsFlx=True, + readBeamElem=True, + stateless=args.stateless) ) + + if args.stateless: + bsEmonInputSvc = cfg.getService('ByteStreamInputSvc') + bsEmonInputSvc.Partition = args.partition + bsEmonInputSvc.Key = args.key + bsEmonInputSvc.KeyValue = args.keyValue + bsEmonInputSvc.KeyCount = args.keyCount + bsEmonInputSvc.PublishName = args.publishName + bsEmonInputSvc.ISServer = 'Histogramming' + bsEmonInputSvc.UpdatePeriod = args.updatePeriod + bsEmonInputSvc.Frequency = args.frequency + bsEmonInputSvc.LVL1Items = args.lvl1Items + bsEmonInputSvc.LVL1Names = args.lvl1Names + bsEmonInputSvc.LVL1Logic = args.lvl1Logic + bsEmonInputSvc.LVL1Origin = args.lvl1Origin + bsEmonInputSvc.StreamType = args.streamType + bsEmonInputSvc.StreamNames = args.streamNames + bsEmonInputSvc.StreamLogic = args.streamLogic + bsEmonInputSvc.GroupName = args.groupName + bsEmonInputSvc.ProcessCorruptedEvents = True + bsEmonInputSvc.BufferSize = 2000 + + # =======>>> Configure reconstruction of Tile TestBeam data + from TileTBRec.TileTestBeamRecoConfig import TileTestBeamRecoCfg + cfg.merge( TileTestBeamRecoCfg(flags, useDemoCabling=args.demoCabling, nsamples=args.nsamples) ) + cfg.merge( TileTestBeamRecoCfg(flags, useDemoCabling=args.demoCabling, nsamples=16, useFELIX=True) ) + + if args.useSqlite: + cfg.getService('IOVDbSvc').overrideTags += [ + f'<prefix>/TILE</prefix> <db>sqlite://;schema={args.useSqlite};dbname={flags.IOVDb.DatabaseInstance}</db>', + # ROD folder does not exist in Sqlite file at the moment (should be added) + f'<prefix>/TILE/ONL01/STATUS/ROD</prefix> <db>COOLONL_TILE/{flags.IOVDb.DatabaseInstance}</db>' + ] + + # =======>>> Configure Tile TestBeam monitoring + cfg.merge(TileTestBeamMonitoringCfg(flags, fragIDs=fragIDs)) + + # =======>>> Configure ROD to ROB mapping + # Scan first event for all fragments to create proper ROD to ROB map + cfg.getCondAlgo('TileHid2RESrcIDCondAlg').RODStatusProxy = None + + # =======>>> Any last things to do? + if args.postExec: + log.info('Executing postExec: %s', args.postExec) + exec(args.postExec) + + if args.printConfig: + cfg.printConfig(withDetails=True, summariseProps=True, printDefaults=True) + + if args.config_only: + cfg.store(open('TileTestBeamMonitoring.pkl', 'wb')) + else: + sc = cfg.run() + # Success should be 0 + sys.exit(not sc.isSuccess())