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