1084 parser = argparse.ArgumentParser(prog='athenaEF.py', formatter_class=
1085 lambda prog : argparse.ArgumentDefaultsHelpFormatter(prog, max_help_position=32, width=100),
1086 usage = '%(prog)s [OPTION]... -f FILE jobOptions',
1087 add_help=False)
1088 parser.expert_groups = []
1089
1090
1091 g = parser.add_argument_group('Options')
1092 g.add_argument('jobOptions', nargs='?', help='job options: CA module (package.module:function), pickle file (.pkl), or JSON file (.json)')
1093 g.add_argument('--threads', metavar='N', type=int, default=1, help='number of threads')
1094 g.add_argument('--concurrent-events', metavar='N', type=int, help='number of concurrent events if different from --threads')
1095 g.add_argument('--log-level', '-l', metavar='LVL', default='INFO', help='OutputLevel of athena')
1096 g.add_argument('--precommand', '-c', metavar='CMD', action='append', default=[],
1097 help='Python commands executed before job options')
1098 g.add_argument('--postcommand', '-C', metavar='CMD', action='append', default=[],
1099 help='Python commands executed after job options')
1100 g.add_argument('--interactive', '-i', action='store_true', help='interactive mode')
1101 g.add_argument('--help', '-h', nargs='?', choices=['all'], action=MyHelp, help='show help')
1102
1103 g = parser.add_argument_group('Input/Output')
1104 g.add_argument('--file', '--filesInput', '-f', action='append', help='input RAW file')
1105 g.add_argument('--save-output', '-o', metavar='FILE', help='output file name')
1106 g.add_argument('--number-of-events', '--evtMax', '-n', metavar='N', type=int, default=None,
1107 help='processes N events (default: from DB/config, -1 means all)')
1108 g.add_argument('--skip-events', '--skipEvents', '-k', metavar='N', type=int, default=None,
1109 help='skip N first events')
1110 g.add_argument('--loop-files', action=argparse.BooleanOptionalAction, default=None,
1111 help='loop over input files if no more events')
1112 g.add_argument('--efdf-interface-library', metavar='LIB', default=None,
1113 help='name of the EFDF interface shared library to load (default: TrigDFEmulator)')
1114
1115
1116 g = parser.add_argument_group('Performance and debugging')
1117 g.add_argument('--perfmon', action='store_true', help='enable PerfMon')
1118 g.add_argument('--tcmalloc', action='store_true', default=True, help='use tcmalloc')
1119 g.add_argument('--stdcmalloc', action='store_true', help='use stdcmalloc')
1120 g.add_argument('--stdcmath', action='store_true', help='use stdcmath library')
1121 g.add_argument('--imf', action='store_true', default=True, help='use Intel math library')
1122 g.add_argument('--show-includes', '-s', action='store_true', help='show printout of included files')
1123
1124
1125 g = parser.add_argument_group('Conditions')
1126 g.add_argument('--run-number', '-R', metavar='RUN', type=int,
1127 help='run number (if None, read from first event)')
1128 g.add_argument('--lb-number', '-L', metavar='LBN', type=int,
1129 help='lumiblock number (if None, read from first event)')
1130 g.add_argument('--conditions-run', metavar='RUN', type=int, default=None,
1131 help='reference run number for conditions lookup (use when IS run number has no COOL data)')
1132 g.add_argument('--sor-time', type=arg_sor_time,
1133 help='The Start Of Run time. Three formats are accepted: '
1134 '1) the string "now", for current time; '
1135 '2) the number of nanoseconds since epoch (e.g. 1386355338658000000 or int(time.time() * 1e9)); '
1136 '3) human-readable "20/11/18 17:40:42.3043". If not specified the sor-time is read from the conditions DB')
1137 g.add_argument('--detector-mask', metavar='MASK', type=arg_detector_mask,
1138 help='detector mask (if None, read from the conditions DB), use string "all" to enable all detectors')
1139
1140
1141 g = parser.add_argument_group('Database')
1142 g.add_argument('--use-database', '-b', action='store_true',
1143 help='configure from trigger database using SMK')
1144 g.add_argument('--db-server', metavar='DB', default='TRIGGERDB_RUN3', help='DB server name (alias)')
1145 g.add_argument('--smk', type=int, default=None, help='Super Master Key')
1146 g.add_argument('--l1psk', type=int, default=None, help='L1 prescale key')
1147 g.add_argument('--hltpsk', type=int, default=None, help='HLT prescale key')
1148 g.add_argument('--use-crest', action='store_true', default=False,
1149 help='Use CREST for trigger configuration')
1150 g.add_argument('--crest-server', metavar='URL', default=None,
1151 help='CREST server URL (defaults to flags.Trigger.crestServer)')
1152 g.add_argument('--dump-config', action='store_true', help='Dump joboptions JSON file')
1153 g.add_argument('--dump-config-exit', action='store_true', help='Dump joboptions JSON file and exit')
1154
1155
1156 g = parser.add_argument_group('Magnets')
1157 g.add_argument('--solenoid-current', type=float, default=None,
1158 help='Solenoid current in Amperes (default: nominal current for offline running, required from IS online)')
1159 g.add_argument('--toroids-current', type=float, default=None,
1160 help='Toroids current in Amperes (default: nominal current for offline running, required from IS online)')
1161
1162
1163 g = parser.add_argument_group('Online')
1164 g.add_argument('--online-environment', action='store_true',
1165 help='Enable online environment: read run parameters from IS and trigger '
1166 'configuration keys (SMK, L1PSK, HLTPSK) from OKS via WEBDAQ REST API')
1167 g.add_argument('--partition', metavar='NAME', default=None,
1168 help='TDAQ partition name (defaults to TDAQ_PARTITION environment variable)')
1169 g.add_argument('--webdaq-base', metavar='URL', default=None,
1170 help='WEBDAQ base URL (defaults to TDAQ_WEBDAQ_BASE environment variable)')
1171
1172
1173 g = parser.add_argument_group('Online Histogramming')
1174 g.add_argument('--oh-monitoring', '-M', action='store_true', default=False,
1175 help='enable online histogram publishing via WebdaqHistSvc')
1176
1177
1178 g = parser.add_argument_group('Expert')
1179 parser.expert_groups.append(g)
1180 (args, unparsed_args) = parser.parse_known_args()
1181 check_args(parser, args)
1182
1183
1184 from PyUtils.Helpers import ROOTSetup
1185 ROOTSetup(batch=True)
1186
1187
1188 import ROOT
1189 ROOT.ROOT.EnableThreadSafety()
1190
1191
1192 import AthenaCommon.Logging
1193 AthenaCommon.Logging.log.setLevel(getattr(logging, args.log_level))
1194 AthenaCommon.Logging.log.setFormat("%(asctime)s Py:%(name)-31s %(levelname)7s %(message)s")
1195 if args.show_includes:
1196 from AthenaCommon.Include import include
1197 include.setShowIncludes( True )
1198
1199
1200 if not args.concurrent_events:
1201 args.concurrent_events = args.threads
1202
1203
1204 from TrigPSC import PscConfig
1205 from TrigPSC.PscDefaultFlags import defaultOnlineFlags
1206
1207
1208 flags = defaultOnlineFlags()
1209
1210
1211 from AthenaCommon import Constants
1212 flags.Exec.OutputLevel = getattr(Constants, args.log_level)
1213
1214
1215 if args.oh_monitoring:
1216 flags.Trigger.Online.useOnlineWebdaqHistSvc = True
1217 log.info("Enabled WebdaqHistSvc for online histogram publishing")
1218
1219
1220 log.info("Using CREST for trigger configuration: %s", args.use_crest)
1221 if args.use_crest:
1222 flags.Trigger.useCrest = True
1223 if args.crest_server:
1224 flags.Trigger.crestServer = args.crest_server
1225 else:
1226 args.crest_server = flags.Trigger.crestServer
1227
1228 update_run_params(args, flags)
1229
1230 if args.use_database:
1231
1232
1233
1234 PscConfig.forcePSK = (args.hltpsk is not None) or args.online_environment
1235
1236 update_trigconf_keys(args, flags)
1237
1238
1239 if not args.use_database and args.jobOptions and not args.jobOptions.endswith('.json'):
1240 PscConfig.unparsedArguments = unparsed_args
1241 for flag_arg in unparsed_args:
1242 flags.fillFromString(flag_arg)
1243
1244 PscConfig.interactive = args.interactive
1245 PscConfig.exitAfterDump = args.dump_config_exit
1246
1247
1248
1249
1250
1251
1252
1253 if args.conditions_run is not None:
1254 log.info("Using conditions from reference run %d (overriding run %s for IOV lookup)",
1255 args.conditions_run, args.run_number)
1256 flags.Input.ConditionsRunNumber = args.conditions_run
1257
1258
1259 if args.number_of_events is not None and args.number_of_events > 0:
1260 flags.Exec.MaxEvents = args.number_of_events
1261
1262
1263 if args.skip_events is not None and args.skip_events > 0:
1264 flags.Exec.SkipEvents = args.skip_events
1265
1266
1267
1268
1269
1270 flags.PerfMon.doFastMonMT = args.perfmon
1271
1272
1273
1274 flags.Trigger.Online.useEFByteStreamSvc = True
1275
1276
1277 ef_files = args.file if args.file else []
1278 ef_overrides = {}
1279 if ef_files:
1280 ef_overrides['Files'] = ef_files
1281
1282 ef_overrides.update({
1283 'T0ProjectTag' : args.T0_project_tag,
1284 'BeamType' : args.beam_type,
1285 'BeamEnergy' : args.beam_energy,
1286 'TriggerType' : args.trigger_type,
1287 'Stream' : args.stream,
1288 'Lumiblock' : args.lumiblock,
1289 'DetMask' : args.file_detector_mask,
1290 })
1291 if args.run_number is not None:
1292 ef_overrides['RunNumber'] = args.run_number
1293 if args.save_output is not None:
1294 ef_overrides['OutputFileName'] = args.save_output
1295 if args.loop_files is not None:
1296 ef_overrides['LoopOverFiles'] = args.loop_files
1297 if args.number_of_events is not None:
1298 ef_overrides['NumEvents'] = args.number_of_events
1299 if args.skip_events is not None:
1300 ef_overrides['SkipEvents'] = args.skip_events
1301 if args.efdf_interface_library is not None:
1302 ef_overrides['EFDFInterfaceLibraryName'] = args.efdf_interface_library
1303
1304
1305 _prop2flag = {'Files': 'Files', 'OutputFileName': 'OutputFileName',
1306 'LoopOverFiles': 'LoopFiles', 'NumEvents': 'NumEvents',
1307 'SkipEvents': 'SkipEvents', 'RunNumber': 'RunNumber',
1308 'T0ProjectTag': 'T0ProjectTag', 'BeamType': 'BeamType',
1309 'BeamEnergy': 'BeamEnergy', 'TriggerType': 'TriggerType',
1310 'Stream': 'Stream', 'Lumiblock': 'Lumiblock', 'DetMask': 'DetMask',
1311 'EFDFInterfaceLibraryName': 'LibraryName'}
1312 for prop, value in ef_overrides.items():
1313 setattr(flags.Trigger.Online.EFInterface, _prop2flag[prop], value)
1314
1315
1316 if args.precommand:
1317 log.info("Executing precommand(s)")
1318 for cmd in args.precommand:
1319 log.info(" %s", cmd)
1320 exec(cmd, globals(), {'flags': flags})
1321
1322
1323 is_database = args.use_database
1324 is_pickle = False
1325 is_json = False
1326
1327 if not is_database and args.jobOptions:
1328 jobOptions = args.jobOptions
1329 is_pickle = jobOptions.endswith('.pkl')
1330 is_json = jobOptions.endswith('.json')
1331
1332 if is_database:
1333
1334
1335 if args.use_crest:
1336 crestconn = TriggerCrestUtil.getCrestConnection(args.db_server)
1337 db_alias = f"{args.crest_server}/{crestconn}"
1338 log.info("Loading configuration via CREST from %s with SMK %d", db_alias, args.smk)
1339 else:
1340 db_alias = args.db_server
1341 log.info("Loading configuration from database %s with SMK %d", db_alias, args.smk)
1342
1343
1344 run_params = get_run_params(args).to_dict()
1345 acc = load_from_database(db_alias, args.smk, args.l1psk, args.hltpsk, run_params,
1346 num_threads=args.threads, num_slots=args.concurrent_events,
1347 ef_overrides=ef_overrides)
1348 log.info("Configuration loaded from database")
1349
1350 elif is_pickle:
1351
1352 log.info("Loading configuration from pickle file: %s", jobOptions)
1353 with open(jobOptions, 'rb') as f:
1354 acc = pickle.load(f)
1355 log.info("Configuration loaded from pickle")
1356
1357 elif is_json:
1358
1359 log.info("Loading configuration from JSON file: %s", jobOptions)
1360
1361 run_params = get_run_params(args).to_dict()
1362 acc = load_from_json(jobOptions, run_params,
1363 num_threads=args.threads, num_slots=args.concurrent_events,
1364 ef_overrides=ef_overrides)
1365 log.info("Configuration loaded from JSON")
1366
1367 else:
1368
1369
1370
1371
1372
1373 log.info("Loading CA configuration from: %s", jobOptions)
1374
1375
1376 from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
1377 from AthenaConfiguration.MainServicesConfig import addMainSequences
1378 from TrigServices.TriggerUnixStandardSetup import commonServicesCfg
1379 from AthenaConfiguration.ComponentFactory import CompFactory
1380
1381 locked_flags = flags.clone()
1382 locked_flags.lock()
1383
1384
1385 cfg = ComponentAccumulator(CompFactory.AthSequencer("AthMasterSeq", Sequential=True))
1386 cfg.setAppProperty('ExtSvcCreates', False)
1387 cfg.setAppProperty("MessageSvcType", "TrigMessageSvc")
1388 cfg.setAppProperty("JobOptionsSvcType", "TrigConf::JobOptionsSvc")
1389
1390
1391 addMainSequences(locked_flags, cfg)
1392 cfg.merge(commonServicesCfg(locked_flags))
1393
1394
1395 cfg_func = AthHLT.getCACfg(jobOptions)
1396 cfg.merge(cfg_func(flags))
1397
1398
1399 if args.postcommand:
1400 log.info("Executing postcommand(s)")
1401 for cmd in args.postcommand:
1402 log.info(" %s", cmd)
1403 exec(cmd, globals(), {'flags': flags, 'cfg': cfg})
1404 args.postcommand = []
1405
1406
1407 fname = "HLTJobOptions"
1408 log.info("Dumping configuration to %s.pkl and %s.json", fname, fname)
1409 with open(f"{fname}.pkl", "wb") as f:
1410 cfg.store(f)
1411
1412 from TrigConfIO.JsonUtils import create_joboptions_json
1413 create_joboptions_json(f"{fname}.pkl", f"{fname}.json")
1414
1415
1416 if args.dump_config_exit:
1417 log.info("Configuration dumped to %s.json. Exiting...", fname)
1418 sys.exit(0)
1419
1420
1421
1422 log.info("Configuration dumped to %s.json. Re-exec...", fname)
1423 AthHLT.reload_from_json(f"{fname}.json", suppress_args=PscConfig.unparsedArguments + ['--dump-config'], jobOptions=args.jobOptions)
1424
1425
1426 if args.postcommand:
1427 log.info("Executing postcommand(s)")
1428 for cmd in args.postcommand:
1429 log.info(" %s", cmd)
1430 exec(cmd, globals(), {'flags': flags, 'acc': acc})
1431
1432
1433 if args.dump_config or args.dump_config_exit:
1434 fname = "HLTJobOptions"
1435
1436 if is_database:
1437
1438 from TrigConfIO.HLTTriggerConfigAccess import HLTJobOptionsAccess
1439 log.info("Fetching configuration from database for dump...")
1440 jo_access = HLTJobOptionsAccess(dbalias=acc.db_server, smkey=acc.smk)
1441 props = jo_access.algorithms()
1442
1443 log.info("Dumping configuration to %s.json", fname)
1444 hlt_json = {'filetype': 'joboptions', 'properties': props}
1445 with open(f"{fname}.json", "w") as f:
1446 json.dump(hlt_json, f, indent=4, sort_keys=True, ensure_ascii=True)
1447
1448 elif is_json:
1449
1450 props = acc.properties
1451 if props:
1452 log.info("Dumping configuration to %s.json", fname)
1453 hlt_json = {'filetype': 'joboptions', 'properties': props}
1454 with open(f"{fname}.json", "w") as f:
1455 json.dump(hlt_json, f, indent=4, sort_keys=True, ensure_ascii=True)
1456 else:
1457 log.warning("No properties available to dump")
1458
1459 elif is_pickle:
1460
1461 app_props, msg_props, comp_props = acc.gatherProps()
1462 props = {"ApplicationMgr": app_props, "MessageSvc": msg_props}
1463 for comp, name, value in comp_props:
1464 props.setdefault(comp, {})[name] = value
1465
1466 log.info("Dumping configuration to %s.json", fname)
1467 hlt_json = {'filetype': 'joboptions', 'properties': props}
1468 with open(f"{fname}.json", "w") as f:
1469 json.dump(hlt_json, f, indent=4, sort_keys=True, ensure_ascii=True)
1470
1471
1472
1473
1474 if args.dump_config_exit:
1475 log.info("Configuration dumped. Exiting...")
1476 sys.exit(0)
1477
1478
1479 log.info("Starting Athena execution...")
1480
1481
1482
1483
1484 worker_dir = os.path.join(os.getcwd(), "athenaHLT_workers", "athenaHLT-01")
1485 if not os.path.exists(worker_dir):
1486 log.info("Creating worker directory: %s", worker_dir)
1487 os.makedirs(worker_dir, exist_ok=True)
1488
1489
1490 oh_infra = start_oh_infrastructure(args) if args.oh_monitoring else None
1491
1492 if args.interactive:
1493 log.info("Interactive mode - call acc.run() to execute")
1494 import code
1495 code.interact(local={'acc': acc, 'flags': flags})
1496 else:
1497
1498 from AthenaCommon import ExitCodes
1499 exitcode = 0
1500 try:
1501
1502 sc = acc.run(args.number_of_events)
1503 if sc.isFailure():
1504 exitcode = ExitCodes.EXE_ALG_FAILURE
1505 except SystemExit as e:
1506 exitcode = ExitCodes.EXE_ALG_FAILURE if e.code == 1 else e.code
1507 except Exception:
1508 traceback.print_exc()
1509 exitcode = ExitCodes.UNKNOWN_EXCEPTION
1510 finally:
1511 stop_oh_infrastructure(oh_infra)
1512
1513 log.info('Leaving with code %d: "%s"', exitcode, ExitCodes.what(exitcode))
1514 sys.exit(exitcode)
1515
1516