ATLAS Offline Software
Loading...
Searching...
No Matches
athenaEF Namespace Reference

Classes

class  RunParams
class  RuntimeOverrides
class  ConfigRunner
class  MyHelp

Functions

 get_trigconf_keys_from_oks (partition=None, webdaq_base=None, strict=False)
 get_run_params (args=None, from_is=False, partition=None, webdaq_base=None, strict=False, solenoid_current_override=None, toroids_current_override=None)
 load_from_json (json_file, run_params=None, overrides=None)
 load_from_database (db_server, smk, l1psk=None, hltpsk=None, run_params=None, overrides=None)
str arg_sor_time (s)
 The following arg_* methods are used as custom types in argparse.
 arg_detector_mask (s)
 check_args (parser, args)
 update_run_params (args, flags)
 update_trigconf_keys (args, flags)
 find_is_schema_files ()
 start_oh_infrastructure (args)
 stop_oh_infrastructure (proc)
 main ()

Variables

 log = logging.getLogger('athenaEF')
float SOFT_TIMEOUT_FRACTION = 0.95
list IS_SCHEMA_FILES = ['schema/Larg.LArNoiseBurstCandidates.is.schema.xml']

Detailed Description

date"

# defaults
export USETCMALLOC=1
export USEIMF=1

# parse command line arguments
for a in ${@}
do
    case "$a" in
        --stdcmalloc)    USETCMALLOC=0;;
        --tcmalloc)      USETCMALLOC=1;;
        --stdcmath)      USEIMF=0;;
        --imf)           USEIMF=1;;
        --preloadlib*)   export ATHENA_ADD_PRELOAD=${a#*=};;
        --no-ers-signal-handlers)  export TDAQ_ERS_NO_SIGNAL_HANDLERS=1;;
    esac
done

# Do the actual preloading via LD_PRELOAD
source `which athena_preload.sh `

# Now resurrect ourselves as python script
python_path=`which python`
"exec" "$python_path" "-tt" "$0" "$@";

Function Documentation

◆ arg_detector_mask()

arg_detector_mask ( s)
Convert detector mask to format expected by eformat

Definition at line 823 of file athenaEF.py.

823def arg_detector_mask(s):
824 """Convert detector mask to format expected by eformat"""
825 if s=='all':
826 return RunParams.DEFAULT_DETECTOR_MASK
827 dmask = hex(int(s,16)) # Normalize input to hex-string
828 dmask = dmask.lower().replace('0x', '').replace('l', '') # remove markers
829 return '0' * (32 - len(dmask)) + dmask # (pad with 0s)
830
831
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition hcg.cxx:312

◆ arg_sor_time()

str arg_sor_time ( s)

The following arg_* methods are used as custom types in argparse.

Convert possible SOR time arguments to an OWLTime compatible string

Definition at line 815 of file athenaEF.py.

815def arg_sor_time(s) -> str:
816 """Convert possible SOR time arguments to an OWLTime compatible string"""
817 fmt = '%d/%m/%y %H:%M:%S.%f'
818 if s=='now': return dt.now().strftime(fmt)
819 elif s.isdigit(): return dt.fromtimestamp(float(s)/1e9).strftime(fmt)
820 else: return s
821
822

◆ check_args()

check_args ( parser,
args )
Consistency check of command line arguments

Definition at line 832 of file athenaEF.py.

832def check_args(parser, args):
833 """Consistency check of command line arguments"""
834
835 if not args.jobOptions and not args.use_database:
836 parser.error("No job options file specified")
837
838 if (not args.file and not args.dump_config_exit
839 and (args.efdf_interface_library or 'TrigDFEmulator') == 'TrigDFEmulator'):
840 parser.error("--file is required unless using --dump-config-exit or online efdf-interface-library")
841
842 if args.use_crest and not args.use_database:
843 parser.error("--use-crest requires --use-database")
844
845 if args.oh_monitoring and args.online_environment:
846 parser.error("--oh-monitoring (-M) and --online-environment are mutually exclusive.")
847
848 if args.timeout is not None and args.timeout <= 0:
849 parser.error("--timeout must be a positive number of milliseconds")
850

◆ find_is_schema_files()

find_is_schema_files ( )
Resolve IS_SCHEMA_FILES to absolute paths using DATAPATH.
rdb_server must be given the schema of every IS type we publish.

Definition at line 1019 of file athenaEF.py.

1019def find_is_schema_files():
1020 """
1021 Resolve IS_SCHEMA_FILES to absolute paths using DATAPATH.
1022 rdb_server must be given the schema of every IS type we publish.
1023 """
1024 from AthenaCommon.Utils.unixtools import find_datafile
1025
1026 found = []
1027 for fname in IS_SCHEMA_FILES:
1028 path = find_datafile(fname)
1029 if path:
1030 found.append(os.path.abspath(path))
1031 else:
1032 log.error("IS schema file %s not found on DATAPATH: IS publication will fail with HTTP 400", fname)
1033 return found
1034
1035

◆ get_run_params()

get_run_params ( args = None,
from_is = False,
partition = None,
webdaq_base = None,
strict = False,
solenoid_current_override = None,
toroids_current_override = None )
Get run parameters from the appropriate source.

This is the main entry point for obtaining run parameters. It provides
a single place to modify when adding new sources (like WEBDAQ).

Args:
   args: argparse Namespace with command-line arguments (optional)
   from_is: If True, try to read from WEBDAQ first
   partition: Partition name for IS access (defaults to TDAQ_PARTITION env var)
   webdaq_base: WEBDAQ base URL (defaults to TDAQ_WEBDAQ_BASE env var)
   strict: If True, raise an exception if IS read fails (for --online-environment)
   solenoid_current_override: Command-line override for solenoid current
   toroids_current_override: Command-line override for toroids current

Returns:
   RunParams instance

Raises:
   RuntimeError: If strict=True and IS read fails

Definition at line 486 of file athenaEF.py.

487 solenoid_current_override=None, toroids_current_override=None):
488 """
489 Get run parameters from the appropriate source.
490
491 This is the main entry point for obtaining run parameters. It provides
492 a single place to modify when adding new sources (like WEBDAQ).
493
494 Args:
495 args: argparse Namespace with command-line arguments (optional)
496 from_is: If True, try to read from WEBDAQ first
497 partition: Partition name for IS access (defaults to TDAQ_PARTITION env var)
498 webdaq_base: WEBDAQ base URL (defaults to TDAQ_WEBDAQ_BASE env var)
499 strict: If True, raise an exception if IS read fails (for --online-environment)
500 solenoid_current_override: Command-line override for solenoid current
501 toroids_current_override: Command-line override for toroids current
502
503 Returns:
504 RunParams instance
505
506 Raises:
507 RuntimeError: If strict=True and IS read fails
508 """
509 if from_is:
510 return RunParams.from_is(partition=partition, webdaq_base=webdaq_base, strict=strict,
511 solenoid_current_override=solenoid_current_override,
512 toroids_current_override=toroids_current_override)
513 elif args is not None:
514 return RunParams.from_args(args)
515 else:
516 return RunParams()
517
518

◆ get_trigconf_keys_from_oks()

get_trigconf_keys_from_oks ( partition = None,
webdaq_base = None,
strict = False )
Read trigger configuration keys (SMK, L1PSK, HLTPSK) and DB info from OKS via WEBDAQ REST API.

This reads the keys from the partition's TriggerConfiguration object and its
related L1TriggerConfiguration and TriggerDBConnection objects.

OKS Structure:
- Partition -> TriggerConfiguration -> L1TriggerConfiguration (Lvl1PrescaleKey)
- Partition -> TriggerConfiguration -> TriggerDBConnection (SuperMasterKey)
- Partition -> TriggerConfiguration -> HLTImplementationDB (hltPrescaleKey)

Args:
   partition: The partition name (default: from TDAQ_PARTITION env var)
   webdaq_base: Base URL for webis_server (default: from TDAQ_WEBDAQ_BASE env var)
   strict: If True, raise an exception if OKS read fails (for --online-environment)

Returns:
   dict with keys: SMK, L1PSK, HLTPSK, db_alias (values may be None if not found)

Raises:
   RuntimeError: If strict=True and OKS read fails

Definition at line 323 of file athenaEF.py.

323def get_trigconf_keys_from_oks(partition=None, webdaq_base=None, strict=False):
324 """
325 Read trigger configuration keys (SMK, L1PSK, HLTPSK) and DB info from OKS via WEBDAQ REST API.
326
327 This reads the keys from the partition's TriggerConfiguration object and its
328 related L1TriggerConfiguration and TriggerDBConnection objects.
329
330 OKS Structure:
331 - Partition -> TriggerConfiguration -> L1TriggerConfiguration (Lvl1PrescaleKey)
332 - Partition -> TriggerConfiguration -> TriggerDBConnection (SuperMasterKey)
333 - Partition -> TriggerConfiguration -> HLTImplementationDB (hltPrescaleKey)
334
335 Args:
336 partition: The partition name (default: from TDAQ_PARTITION env var)
337 webdaq_base: Base URL for webis_server (default: from TDAQ_WEBDAQ_BASE env var)
338 strict: If True, raise an exception if OKS read fails (for --online-environment)
339
340 Returns:
341 dict with keys: SMK, L1PSK, HLTPSK, db_alias (values may be None if not found)
342
343 Raises:
344 RuntimeError: If strict=True and OKS read fails
345 """
346 import requests
347
348 # Determine the base URL
349 if webdaq_base is None:
350 webdaq_base = os.environ.get('TDAQ_WEBDAQ_BASE')
351
352 if not webdaq_base:
353 msg = "TDAQ_WEBDAQ_BASE not set, cannot read from OKS"
354 if strict:
355 raise RuntimeError(msg + " (required for --online-environment)")
356 log.warning(msg)
357 return {'SMK': None, 'L1PSK': None, 'HLTPSK': None, 'db_alias': None}
358
359 # Determine partition
360 if partition is None:
361 partition = os.environ.get('TDAQ_PARTITION', 'ATLAS')
362
363 log.info("Reading trigger configuration keys from OKS via WEBDAQ: %s (partition=%s)",
364 webdaq_base, partition)
365
366 result = {'SMK': None, 'L1PSK': None, 'HLTPSK': None, 'db_alias': None}
367
368 def extract_oks_data(response_json):
369 """
370 Extract data from OKS compact format: [name, type, attributes, relationships]
371 Returns tuple (attributes_dict, relationships_dict)
372 """
373 if isinstance(response_json, list) and len(response_json) >= 4:
374 return response_json[2], response_json[3] # attributes, relationships
375 elif isinstance(response_json, list) and len(response_json) >= 3:
376 return response_json[2], {} # attributes only
377 return response_json, {} # fallback
378
379 def get_ref_id(ref):
380 """Extract object ID from a relationship reference."""
381 if isinstance(ref, list) and len(ref) >= 2:
382 return ref[0] # [id, class] format
383 elif isinstance(ref, dict) and 'id' in ref:
384 return ref['id']
385 elif isinstance(ref, str):
386 return ref
387 return None
388
389 # OKS API: GET /info/current/{partition}/oks/{class}/{name}?format=compact
390 # Response format: [name, type, attributes, relationships]
391 # - attributes: dict of simple values (strings, ints, etc.)
392 # - relationships: dict of references to other objects
393 try:
394 url = f"{webdaq_base}/info/current/{partition}/oks/Partition/{partition}?format=compact"
395 log.debug("Fetching Partition from OKS: %s", url)
396
397 response = requests.get(url, timeout=10)
398 if response.status_code == 200:
399 part_attrs, part_rels = extract_oks_data(response.json())
400 log.debug("Partition attributes: %s", part_attrs)
401 log.debug("Partition relationships: %s", part_rels)
402
403 # Get TriggerConfiguration reference from relationships
404 trig_conf_id = None
405 if 'TriggerConfiguration' in part_rels:
406 trig_conf_id = get_ref_id(part_rels['TriggerConfiguration'])
407
408 if trig_conf_id:
409 log.debug("TriggerConfiguration ID: %s", trig_conf_id)
410
411 # Get TriggerConfiguration object
412 url = f"{webdaq_base}/info/current/{partition}/oks/TriggerConfiguration/{trig_conf_id}?format=compact"
413 response = requests.get(url, timeout=10)
414 if response.status_code == 200:
415 trig_attrs, trig_rels = extract_oks_data(response.json())
416 log.debug("TriggerConfiguration attributes: %s", trig_attrs)
417 log.debug("TriggerConfiguration relationships: %s", trig_rels)
418
419 # Get L1TriggerConfiguration for L1PSK (relationship 'l1')
420 if 'l1' in trig_rels:
421 l1_id = get_ref_id(trig_rels['l1'])
422 if l1_id:
423 url = f"{webdaq_base}/info/current/{partition}/oks/L1TriggerConfiguration/{l1_id}?format=compact"
424 resp = requests.get(url, timeout=10)
425 if resp.status_code == 200:
426 l1_attrs, _ = extract_oks_data(resp.json())
427 log.debug("L1TriggerConfiguration attributes: %s", l1_attrs)
428 if 'Lvl1PrescaleKey' in l1_attrs:
429 result['L1PSK'] = int(l1_attrs['Lvl1PrescaleKey'])
430 log.info("Got L1PSK=%d from OKS", result['L1PSK'])
431
432 # Get TriggerDBConnection for SMK and db_alias (relationship 'TriggerDBConnection')
433 if 'TriggerDBConnection' in trig_rels:
434 db_id = get_ref_id(trig_rels['TriggerDBConnection'])
435 if db_id:
436 url = f"{webdaq_base}/info/current/{partition}/oks/TriggerDBConnection/{db_id}?format=compact"
437 resp = requests.get(url, timeout=10)
438 if resp.status_code == 200:
439 db_attrs, _ = extract_oks_data(resp.json())
440 log.debug("TriggerDBConnection attributes: %s", db_attrs)
441 if 'SuperMasterKey' in db_attrs:
442 result['SMK'] = int(db_attrs['SuperMasterKey'])
443 log.info("Got SMK=%d from OKS", result['SMK'])
444 if 'Alias' in db_attrs:
445 result['db_alias'] = db_attrs['Alias']
446 log.info("Got db_alias=%s from OKS", result['db_alias'])
447
448 # Get HLTImplementationDB for HLTPSK (relationship 'hlt')
449 if 'hlt' in trig_rels:
450 hlt_id = get_ref_id(trig_rels['hlt'])
451 if hlt_id:
452 url = f"{webdaq_base}/info/current/{partition}/oks/HLTImplementationDB/{hlt_id}?format=compact"
453 resp = requests.get(url, timeout=10)
454 if resp.status_code == 200:
455 hlt_attrs, _ = extract_oks_data(resp.json())
456 log.debug("HLTImplementationDB attributes: %s", hlt_attrs)
457 if 'hltPrescaleKey' in hlt_attrs:
458 result['HLTPSK'] = int(hlt_attrs['hltPrescaleKey'])
459 log.info("Got HLTPSK=%d from OKS", result['HLTPSK'])
460 else:
461 msg = f"Failed to fetch Partition from OKS: HTTP {response.status_code}"
462 if strict:
463 raise RuntimeError(msg + " (required for --online-environment)")
464 log.warning(msg)
465
466 except requests.exceptions.RequestException as e:
467 msg = f"Error fetching trigger keys from OKS: {e}"
468 if strict:
469 raise RuntimeError(msg + " (required for --online-environment)")
470 log.warning(msg)
471 except (ValueError, KeyError, TypeError) as e:
472 msg = f"Error parsing trigger keys from OKS: {e}"
473 if strict:
474 raise RuntimeError(msg + " (required for --online-environment)")
475 log.warning(msg)
476
477 # In strict mode, verify we got the required keys from OKS
478 if strict:
479 missing = [k for k in ['SMK', 'L1PSK', 'HLTPSK'] if result.get(k) is None]
480 if missing:
481 raise RuntimeError(f"Failed to get {', '.join(missing)} from OKS (required for --online-environment)")
482
483 return result
484
485

◆ load_from_database()

load_from_database ( db_server,
smk,
l1psk = None,
hltpsk = None,
run_params = None,
overrides = None )
Load configuration from trigger database using the Super Master Key (SMK).

Returns a ConfigRunner that uses TrigConf::JobOptionsSvc with TYPE="DB"
to load configuration directly from the database.

Definition at line 802 of file athenaEF.py.

802def load_from_database(db_server, smk, l1psk=None, hltpsk=None, run_params=None, overrides=None):
803 """
804 Load configuration from trigger database using the Super Master Key (SMK).
805
806 Returns a ConfigRunner that uses TrigConf::JobOptionsSvc with TYPE="DB"
807 to load configuration directly from the database.
808 """
809 log.info("Loading job options from database %s with SMK %d", db_server, smk)
810 return ConfigRunner.from_database(db_server, smk, l1psk, hltpsk, run_params, overrides=overrides)
811

◆ load_from_json()

load_from_json ( json_file,
run_params = None,
overrides = None )
Load configuration from a Gaudi joboptions JSON file.

Returns a ConfigRunner with a run() method that executes the configuration
using TrigConf::JobOptionsSvc with TYPE="FILE".

Definition at line 785 of file athenaEF.py.

785def load_from_json(json_file, run_params=None, overrides=None):
786 """
787 Load configuration from a Gaudi joboptions JSON file.
788
789 Returns a ConfigRunner with a run() method that executes the configuration
790 using TrigConf::JobOptionsSvc with TYPE="FILE".
791 """
792 with open(json_file, 'r') as f:
793 jocat = json.load(f)
794
795 if jocat.get('filetype') != 'joboptions':
796 raise ValueError(f"Invalid JSON file type: {jocat.get('filetype')}, expected 'joboptions'")
797
798 properties = jocat.get('properties', {})
799 return ConfigRunner.from_json(json_file, run_params, properties, overrides=overrides)
800
801

◆ main()

main ( )

Definition at line 1131 of file athenaEF.py.

1131def main():
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 = [] # Keep list of expert option 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 # set ROOT to batch mode (ATR-21890)
1234 from PyUtils.Helpers import ROOTSetup
1235 ROOTSetup(batch=True)
1236
1237 # Enable ROOT thread safety
1238 import ROOT
1239 ROOT.ROOT.EnableThreadSafety()
1240
1241 # set default Python OutputLevel and file inclusion
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 # consistency checks for arguments
1247 if not args.concurrent_events:
1248 args.concurrent_events = args.threads
1249
1250 # Update args and set athena flags
1251 from AthenaConfiguration.AllConfigFlags import initConfigFlags
1252 from TrigServices.TriggerUnixStandardSetup import setDefaultOnlineFlags
1253
1254 # Create flags with online defaults
1255 flags = initConfigFlags()
1256 setDefaultOnlineFlags(flags)
1257
1258 # set MessageSvc OutputLevel
1259 from AthenaCommon import Constants
1260 flags.Exec.OutputLevel = getattr(Constants, args.log_level)
1261
1262 # Enable WebdaqHistSvc for online histogram publishing if requested
1263 if args.oh_monitoring:
1264 flags.Trigger.Online.useOnlineWebdaqHistSvc = True
1265 log.info("Enabled WebdaqHistSvc for online histogram publishing")
1266
1267 # CREST configuration
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 # If the HLT PSK was given on the command line OR from OKS (--online-environment), ignore what is
1279 # stored in COOL and read that key directly from the DB (ATR-25974).
1280 # This is needed because COOL may point to a different HLTPSK for the forced run number.
1281 # NB: must be evaluated before update_trigconf_keys, which fills args.hltpsk from COOL/OKS.
1282 force_psk = args.use_database and ((args.hltpsk is not None) or args.online_environment)
1283
1284 if args.use_database:
1285 # Read trigger config keys from COOL/OKS if not specified
1286 update_trigconf_keys(args, flags)
1287
1288 # Fill flags from command line (if not running from DB/JSON)
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 # NOTE: Do NOT set flags.Input.Files here!
1295 # We keep Input.Files=[] during configuration to ensure the configuration
1296 # is portable and doesn't depend on specific input file metadata.
1297 # Input files are passed to EFInterface for runtime use only.
1298
1299 # Set conditions run number override (for test partitions with fake run numbers)
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 # Set number of events
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 # Set skip events
1310 if args.skip_events is not None and args.skip_events > 0:
1311 flags.Exec.SkipEvents = args.skip_events
1312
1313 # NOTE: Do NOT set flags.Concurrency.NumThreads or NumConcurrentEvents here.
1314 # Threading is set at runtime via iProperty after configure() - see ConfigRunner.run()
1315
1316 # Enable PerfMon if requested
1317 flags.PerfMon.doFastMonMT = args.perfmon
1318
1319 # Overrides applied to the configuration at runtime.
1320 # Only options explicitly given on the command line are collected, anything else keeps its DB/jobOptions value.
1321 # NB: Do NOT set the corresponding flags here, that would put them in the SMK.
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: # from -R, IS, or the input file
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 # Run number used for the conditions IOV lookup
1355 overrides.set('HltEventLoopMgr.forceRunNumber', args.conditions_run)
1356
1357 if force_psk:
1358 overrides.set('HLTPrescaleCondAlg.Source', 'DB')
1359
1360 # Histogram service:
1361 # Offline the command line decides and overrides the SMK/JSON conf (offline behaviour never depends on the SMK).
1362 # Online (--online-environment) we leave the configuration exactly as it is.
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 # Execute precommands
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 # Determine input type
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 # Load configuration from trigger database
1390 # Handle CREST vs standard DB access
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 # Get run parameters for prepareForStart
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 # Load ComponentAccumulator from pickle file
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 # Load configuration from JSON file
1413 log.info("Loading configuration from JSON file: %s", jobOptions)
1414 # Get run parameters for prepareForStart
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 # Load from CA module:
1421 # 1. Build the full configuration with services
1422 # 2. Dump to JSON file
1423 # 3. Use AthHLT.reload_from_json to re-exec and reload from JSON
1424 log.info("Loading CA configuration from: %s", jobOptions)
1425
1426 # Clone and lock flags for services configuration
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 # Create base CA with framework services
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 # Add main sequences and common services (includes TrigServicesCfg)
1442 addMainSequences(locked_flags, cfg)
1443 cfg.merge(commonServicesCfg(locked_flags))
1444
1445 # Now merge user CA config (with unlocked flags)
1446 cfg_func = AthHLT.getCACfg(jobOptions)
1447 cfg.merge(cfg_func(flags))
1448
1449 # Execute postcommands before dumping
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 = [] # Clear so we don't run them again later
1456
1457 # Dump configuration to JSON
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 # Check for dump-and-exit
1467 if args.dump_config_exit:
1468 log.info("Configuration dumped to %s.json. Exiting...", fname)
1469 sys.exit(0)
1470
1471 # Re-exec from the JSON. Replaces the process image freeing up the configuration heap.
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 # Execute postcommands
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 # Dump configuration if requested
1483 if args.dump_config or args.dump_config_exit:
1484 fname = "HLTJobOptions"
1485
1486 if is_database:
1487 # For DB mode, fetch properties via Python API
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 # For JSON mode, properties were already loaded
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 # For pickle-loaded ComponentAccumulator, gather properties
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 # Note: For CA module, dumping is already handled earlier
1522 # before converting to ConfigRunner
1523
1524 if args.dump_config_exit:
1525 log.info("Configuration dumped. Exiting...")
1526 sys.exit(0)
1527
1528 # Run the application directly (like athena.py does)
1529 log.info("Starting Athena execution...")
1530
1531 # Create worker directory structure that HLT services expect
1532 # (normally created by HLTMPPU/PSC). Worker ID 1 means single-worker, non-forked mode
1533 # and must match what we pass to hltUpdateAfterFork(worker_id=1) in ConfigRunner.run()
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 # Start the private TDAQ infrastructure for -M
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 # Run the application
1548 from AthenaCommon import ExitCodes
1549 exitcode = 0
1550 try:
1551 # Pass maxEvents if explicitly set (including -1 for all events)
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
int main()
Definition hello.cxx:18

◆ start_oh_infrastructure()

start_oh_infrastructure ( args)
Start a private TDAQ infrastructure (offline test of OH publication).

Definition at line 1036 of file athenaEF.py.

1036def start_oh_infrastructure(args):
1037 """Start a private TDAQ infrastructure (offline test of OH publication)."""
1038 import shutil, socket, signal, subprocess, time
1039
1040 infra_script = shutil.which('athenaEF_tdaq_infra.py')
1041 if infra_script is None:
1042 log.error("athenaEF_tdaq_infra.py not found on PATH (required for -M)")
1043 sys.exit(1)
1044
1045 partition = args.partition or 'athenaEF'
1046 host = 'localhost'
1047 # Get a free port for webis
1048 s = socket.socket()
1049 s.bind((host, 0))
1050 port = s.getsockname()[1]
1051 s.close()
1052 oh_server = 'Histogramming' # WebdaqHistSvc.OHServerName default
1053 run_number = args.run_number if args.run_number is not None else 0
1054
1055 # Export variables for the -M case
1056 os.environ['TDAQ_PARTITION'] = partition
1057 os.environ['TDAQ_WEBDAQ_BASE'] = f'http://{host}:{port}'
1058 os.environ['TDAQ_OH_SERVER'] = oh_server
1059
1060 log.info("Starting private OH infrastructure: partition=%s, webdaq=%s, oh_server=%s",
1061 partition, os.environ['TDAQ_WEBDAQ_BASE'], oh_server)
1062
1063 logfile = open('athenaEF_oh_infra.log', 'w')
1064
1065 # PR_SET_PDEATHSIG so the infrastructure is torn down (SIGTERM -> oh_cp +
1066 # ipc_rm) if athenaEF dies unexpectedly, e.g. segfaults mid-run.
1067 from ctypes import cdll
1068 PR_SET_PDEATHSIG = 1
1069 def _pdeathsig():
1070 cdll['libc.so.6'].prctl(PR_SET_PDEATHSIG, signal.SIGTERM)
1071
1072 schemas = find_is_schema_files()
1073 log.info("IS schema files: %s", ', '.join(schemas) or '(none)')
1074
1075 proc = subprocess.Popen(
1076 [infra_script,
1077 '--partition', partition,
1078 '--webdaq-port', str(port),
1079 '--oh-server', oh_server,
1080 '--run-number', str(run_number),
1081 *(arg for f in schemas for arg in ('--schema', f))],
1082 stdout=logfile, stderr=subprocess.STDOUT,
1083 preexec_fn=_pdeathsig, close_fds=True)
1084
1085 # Wait for the readiness marker (or early failure / timeout)
1086 timeout = 120
1087 deadline = time.time() + timeout
1088 while time.time() < deadline:
1089 if proc.poll() is not None:
1090 log.error("OH infrastructure exited early (code %s); see %s", proc.returncode, logfile.name)
1091 sys.exit(1)
1092 with open(logfile.name) as f:
1093 if 'ATHENAEF_INFRA_READY' in f.read():
1094 log.info("OH infrastructure is ready")
1095 return proc
1096 time.sleep(1)
1097
1098 log.error("OH infrastructure did not become ready within %d s; see %s", timeout, logfile.name)
1099 proc.terminate()
1100 sys.exit(1)
1101
1102

◆ stop_oh_infrastructure()

stop_oh_infrastructure ( proc)
Terminate the private TDAQ infrastructure (SIGTERM triggers oh_cp + ipc_rm).

Definition at line 1103 of file athenaEF.py.

1103def stop_oh_infrastructure(proc):
1104 """Terminate the private TDAQ infrastructure (SIGTERM triggers oh_cp + ipc_rm)."""
1105 if proc is None or proc.poll() is not None:
1106 return
1107 import signal
1108 log.info("Stopping OH infrastructure")
1109 proc.send_signal(signal.SIGTERM)
1110 try:
1111 proc.wait(timeout=60)
1112 except Exception:
1113 proc.kill()
1114
1115

◆ update_run_params()

update_run_params ( args,
flags )
Update run parameters from IS, file, or conditions DB

Definition at line 851 of file athenaEF.py.

851def update_run_params(args, flags):
852 """Update run parameters from IS, file, or conditions DB"""
853
854 # If --online-environment is specified, try to read from Information Service first
855 if getattr(args, 'online_environment', False):
856 log.info("Reading run parameters from Information Service via WEBDAQ")
857 # Pass command-line magnet values as overrides (if provided)
858 # strict=True ensures we fail if IS read fails, rather than falling back to defaults
859 # But if user provided magnet values on command line, those take precedence over IS
860 solenoid_override = getattr(args, 'solenoid_current', None)
861 toroids_override = getattr(args, 'toroids_current', None)
862
863 run_params = get_run_params(from_is=True,
864 partition=getattr(args, 'partition', None),
865 webdaq_base=getattr(args, 'webdaq_base', None),
866 strict=True,
867 solenoid_current_override=solenoid_override,
868 toroids_current_override=toroids_override)
869 # Update args with values from IS (if not already set on command line)
870 if args.run_number is None and run_params.run_number is not None:
871 args.run_number = run_params.run_number
872 log.info("Using run_number=%d from IS", args.run_number)
873 if args.lb_number is None and run_params.lb_number is not None:
874 args.lb_number = run_params.lb_number
875 log.info("Using lb_number=%d from IS", args.lb_number)
876 if args.sor_time is None and run_params.sor_time is not None:
877 args.sor_time = run_params.sor_time
878 log.info("Using sor_time=%s from IS", args.sor_time)
879 if args.detector_mask is None and run_params.detector_mask is not None:
880 args.detector_mask = run_params.detector_mask
881 log.info("Using detector_mask=%s from IS", args.detector_mask)
882 # Update magnet currents from IS (run_params already has command-line overrides if provided)
883 args.solenoid_current = run_params.solenoid_current
884 args.toroids_current = run_params.toroids_current
885 args.beam_type = run_params.beam_type
886 args.beam_energy = run_params.beam_energy
887
888 if (args.run_number is not None and args.lb_number is None) or (args.run_number is None and args.lb_number is not None):
889 log.error("Both or neither of the options -R (--run-number) and -L (--lb-number) have to be specified")
890
891 # Read metadata from input file (like HLTMPPy/runner.py getRunParamsFromFile)
892 if args.file:
893 from eformat import EventStorage
894 dr = EventStorage.pickDataReader(args.file[0])
895 if args.run_number is None:
896 args.run_number = dr.runNumber()
897 args.lb_number = dr.lumiblockNumber()
898 args.T0_project_tag = dr.projectTag()
899 args.beam_type = dr.beamType()
900 args.beam_energy = dr.beamEnergy()
901 args.trigger_type = dr.triggerType()
902 args.stream = dr.stream()
903 args.lumiblock = dr.lumiblockNumber()
904 args.file_detector_mask = "{:032x}".format(dr.detectorMask())
905 else:
906 args.T0_project_tag = getattr(args, 'T0_project_tag', '')
907 args.beam_type = getattr(args, 'beam_type', 0)
908 args.beam_energy = getattr(args, 'beam_energy', 0)
909 args.trigger_type = getattr(args, 'trigger_type', 0)
910 args.stream = getattr(args, 'stream', '')
911 args.lumiblock = getattr(args, 'lumiblock', 0)
912 args.file_detector_mask = getattr(args, 'file_detector_mask', '00000000000000000000000000000000')
913
914 sor_params = None
915 if (args.sor_time is None or args.detector_mask is None) and args.run_number is not None:
916 sor_params = AthHLT.get_sor_params(args.run_number)
917 log.debug('SOR parameters: %s', sor_params)
918 if sor_params is None:
919 log.error("Run %d does not exist. If you want to use this run-number specify "
920 "remaining run parameters, e.g.: --sor-time=now --detector-mask=all", args.run_number)
921 sys.exit(1)
922
923 if args.sor_time is None and sor_params is not None:
924 args.sor_time = arg_sor_time(str(sor_params['SORTime']))
925
926 if args.detector_mask is None and sor_params is not None:
927 dmask = sor_params['DetectorMask']
928 if args.run_number < AthHLT.CondDB._run2:
929 dmask = hex(dmask)
930 args.detector_mask = arg_detector_mask(dmask)
931
932 if args.dump_config_exit and not args.run_number:
933 args.run_number = 0
934
935 # Apply defaults for magnet currents if not set (offline mode only)
936 # In online mode, magnets must come from IS or command line (handled above)
937 if getattr(args, 'solenoid_current', None) is None:
938 args.solenoid_current = RunParams.DEFAULT_SOLENOID_CURRENT
939 log.debug("Using default solenoid_current=%.1f", args.solenoid_current)
940 if getattr(args, 'toroids_current', None) is None:
941 args.toroids_current = RunParams.DEFAULT_TOROIDS_CURRENT
942 log.debug("Using default toroids_current=%.1f", args.toroids_current)
943
944

◆ update_trigconf_keys()

update_trigconf_keys ( args,
flags )
Update trigger configuration keys from OKS, COOL, or CREST.

Priority order:
1. Command-line arguments (always take precedence)
2. OKS via WEBDAQ (if --online-environment is set)
3. CREST (if --use-crest is set)
4. COOL (default)

Definition at line 945 of file athenaEF.py.

945def update_trigconf_keys(args, flags):
946 """Update trigger configuration keys from OKS, COOL, or CREST.
947
948 Priority order:
949 1. Command-line arguments (always take precedence)
950 2. OKS via WEBDAQ (if --online-environment is set)
951 3. CREST (if --use-crest is set)
952 4. COOL (default)
953 """
954
955 if args.smk is None or args.l1psk is None or args.hltpsk is None:
956 trigconf = None
957
958 # Try OKS first if --online-environment is set
959 if getattr(args, 'online_environment', False):
960 log.info("Reading trigger configuration keys from OKS (online environment)")
961 # strict=True ensures we fail if OKS read fails, rather than falling back to COOL
962 oks_keys = get_trigconf_keys_from_oks(
963 partition=getattr(args, 'partition', None),
964 webdaq_base=getattr(args, 'webdaq_base', None),
965 strict=True
966 )
967 log.info("Retrieved trigger keys from OKS: %s", oks_keys)
968
969 # With strict=True, we're guaranteed to have all keys or an exception was raised
970 trigconf = {
971 'SMK': oks_keys.get('SMK'),
972 'LVL1PSK': oks_keys.get('L1PSK'),
973 'HLTPSK': oks_keys.get('HLTPSK')
974 }
975 # Also update db_server if provided by OKS and not set on command line
976 if oks_keys.get('db_alias') and args.db_server == 'TRIGGERDB_RUN3':
977 args.db_server = oks_keys['db_alias']
978 log.info("Using db_server=%s from OKS", args.db_server)
979
980 # Fall back to CREST or COOL only if NOT in online-environment mode
981 if trigconf is None:
982 if args.use_crest:
983 crest_server = args.crest_server or flags.Trigger.crestServer
984 log.info("Reading trigger configuration keys from CREST for run %s", args.run_number)
985 trigconf = AthHLT.get_trigconf_keys_crest(args.run_number, args.lb_number, crest_server)
986 log.info("Retrieved trigger keys from CREST: %s", trigconf)
987 else:
988 log.info("Reading trigger configuration keys from COOL for run %s", args.run_number)
989 trigconf = AthHLT.get_trigconf_keys(args.run_number, args.lb_number)
990 log.info("Retrieved trigger keys from COOL: %s", trigconf)
991
992 try:
993 if args.smk is None:
994 args.smk = trigconf['SMK']
995 log.debug("Using SMK=%d from conditions DB/OKS", args.smk)
996 else:
997 log.debug("Using SMK=%d from command line (ignoring DB/OKS value %s)", args.smk, trigconf.get('SMK'))
998 if args.l1psk is None:
999 args.l1psk = trigconf['LVL1PSK']
1000 log.debug("Using L1PSK=%d from conditions DB/OKS", args.l1psk)
1001 else:
1002 log.debug("Using L1PSK=%d from command line (ignoring DB/OKS value %s)", args.l1psk, trigconf.get('LVL1PSK'))
1003 if args.hltpsk is None:
1004 args.hltpsk = trigconf['HLTPSK']
1005 log.debug("Using HLTPSK=%d from conditions DB/OKS", args.hltpsk)
1006 else:
1007 log.debug("Using HLTPSK=%d from command line (ignoring DB/OKS value %s)", args.hltpsk, trigconf.get('HLTPSK'))
1008 except KeyError:
1009 log.error("Cannot read trigger configuration keys from the conditions database for run %d", args.run_number)
1010 sys.exit(1)
1011 else:
1012 log.info("Using trigger configuration keys from command line: SMK=%d, L1PSK=%d, HLTPSK=%d",
1013 args.smk, args.l1psk, args.hltpsk)
1014
1015# IS schema files, installed under <...>/share/schema (e.g. see TrigCaloHypo/CMakeLists.txt).
1016# Add an entry here for every new IS type

Variable Documentation

◆ IS_SCHEMA_FILES

list athenaEF.IS_SCHEMA_FILES = ['schema/Larg.LArNoiseBurstCandidates.is.schema.xml']

Definition at line 1017 of file athenaEF.py.

◆ log

athenaEF.log = logging.getLogger('athenaEF')

Definition at line 52 of file athenaEF.py.

◆ SOFT_TIMEOUT_FRACTION

float athenaEF.SOFT_TIMEOUT_FRACTION = 0.95

Definition at line 56 of file athenaEF.py.