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)
 update_trigconf_keys (args)
 find_is_schema_files ()
 start_oh_infrastructure (args)
 stop_oh_infrastructure (proc)
 configure_from_ca (args, unparsed_args)
 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 832 of file athenaEF.py.

832def arg_detector_mask(s):
833 """Convert detector mask to format expected by eformat"""
834 if s=='all':
835 return RunParams.DEFAULT_DETECTOR_MASK
836 dmask = hex(int(s,16)) # Normalize input to hex-string
837 dmask = dmask.lower().replace('0x', '').replace('l', '') # remove markers
838 return '0' * (32 - len(dmask)) + dmask # (pad with 0s)
839
840
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 824 of file athenaEF.py.

824def arg_sor_time(s) -> str:
825 """Convert possible SOR time arguments to an OWLTime compatible string"""
826 fmt = '%d/%m/%y %H:%M:%S.%f'
827 if s=='now': return dt.now().strftime(fmt)
828 elif s.isdigit(): return dt.fromtimestamp(float(s)/1e9).strftime(fmt)
829 else: return s
830
831

◆ check_args()

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

Definition at line 841 of file athenaEF.py.

841def check_args(parser, args):
842 """Consistency check of command line arguments"""
843
844 if not args.jobOptions and not args.use_database:
845 parser.error("No job options file specified")
846
847 if args.jobOptions and args.jobOptions.endswith('.pkl'):
848 parser.error("Running from a pickle file is not supported in athenaEF.")
849
850 if (not args.file and not args.dump_config_exit
851 and (args.efdf_interface_library or 'TrigDFEmulator') == 'TrigDFEmulator'):
852 parser.error("--file is required unless using --dump-config-exit or online efdf-interface-library")
853
854 if args.use_crest and not args.use_database:
855 parser.error("--use-crest requires --use-database")
856
857 if args.oh_monitoring and args.online_environment:
858 parser.error("--oh-monitoring (-M) and --online-environment are mutually exclusive.")
859
860 if args.timeout is not None and args.timeout <= 0:
861 parser.error("--timeout must be a positive number of milliseconds")
862

◆ configure_from_ca()

configure_from_ca ( args,
unparsed_args )
Configure the job from a CA module and re-execute athenaEF from the resulting JSON.

This function never returns: athenaEF either exits (--dump-config-exit) or replaces
itself with a new athenaEF running from the JSON file it just created.

Definition at line 1142 of file athenaEF.py.

1142def configure_from_ca(args, unparsed_args):
1143 """Configure the job from a CA module and re-execute athenaEF from the resulting JSON.
1144
1145 This function never returns: athenaEF either exits (--dump-config-exit) or replaces
1146 itself with a new athenaEF running from the JSON file it just created.
1147 """
1148 from AthenaCommon import Constants
1149 from AthenaConfiguration.AllConfigFlags import initConfigFlags
1150 from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
1151 from AthenaConfiguration.ComponentFactory import CompFactory
1152 from AthenaConfiguration.MainServicesConfig import addMainSequences
1153 from TrigServices.TrigServicesConfig import commonServicesCfg, setDefaultOnlineFlags
1154
1155 # Create flags with online defaults
1156 flags = initConfigFlags()
1157 setDefaultOnlineFlags(flags)
1158
1159 # set MessageSvc OutputLevel
1160 flags.Exec.OutputLevel = getattr(Constants, args.log_level)
1161
1162 # Enable WebdaqHistSvc for online histogram publishing if requested
1163 if args.oh_monitoring:
1164 flags.Trigger.Online.useOnlineWebdaqHistSvc = True
1165 log.info("Enabled WebdaqHistSvc for online histogram publishing")
1166
1167 # Fill flags from the command line.
1168 AthHLT.unparsedArguments = unparsed_args
1169 AthHLT.fillFromUnparsedArgs(flags)
1170
1171 # NOTE: Do NOT set flags.Input.Files here!
1172 # We keep Input.Files=[] during configuration to ensure the configuration
1173 # is portable and doesn't depend on specific input file metadata.
1174 # Input files are passed to EFInterface for runtime use only.
1175
1176 # Set conditions run number override (for test partitions with fake run numbers)
1177 if args.conditions_run is not None:
1178 log.info("Using conditions from reference run %d (overriding run %s for IOV lookup)",
1179 args.conditions_run, args.run_number)
1180 flags.Input.ConditionsRunNumber = args.conditions_run
1181
1182 # Set number of events
1183 if args.number_of_events is not None and args.number_of_events > 0:
1184 flags.Exec.MaxEvents = args.number_of_events
1185
1186 # Set skip events
1187 if args.skip_events is not None and args.skip_events > 0:
1188 flags.Exec.SkipEvents = args.skip_events
1189
1190 # NOTE: Do NOT set flags.Concurrency.NumThreads or NumConcurrentEvents here.
1191 # Threading is set at runtime via iProperty after configure() - see ConfigRunner.run()
1192
1193 # Enable PerfMon if requested
1194 flags.PerfMon.doFastMonMT = args.perfmon
1195
1196 # Execute precommands
1197 if args.precommand:
1198 log.info("Executing precommand(s)")
1199 for cmd in args.precommand:
1200 log.info(" %s", cmd)
1201 exec(cmd, globals(), {'flags': flags})
1202
1203 # Load from CA module:
1204 # 1. Build the full configuration with services
1205 # 2. Dump to JSON file
1206 # 3. Use AthHLT.reload_from_json to re-exec and reload from JSON
1207 log.info("Loading CA configuration from: %s", args.jobOptions)
1208
1209 # Clone and lock flags for services configuration
1210 locked_flags = flags.clone()
1211 locked_flags.lock()
1212
1213 # Create base CA with framework services
1214 cfg = ComponentAccumulator(CompFactory.AthSequencer("AthMasterSeq", Sequential=True))
1215 cfg.setAppProperty('ExtSvcCreates', False)
1216 cfg.setAppProperty("MessageSvcType", "TrigMessageSvc")
1217 cfg.setAppProperty("JobOptionsSvcType", "TrigConf::JobOptionsSvc")
1218
1219 # Add main sequences and common services (includes TrigServicesCfg)
1220 addMainSequences(locked_flags, cfg)
1221 cfg.merge(commonServicesCfg(locked_flags))
1222
1223 # Now merge user CA config (with unlocked flags)
1224 cfg_func = AthHLT.getCACfg(args.jobOptions)
1225 cfg.merge(cfg_func(flags))
1226
1227 # Execute postcommands before dumping
1228 if args.postcommand:
1229 log.info("Executing postcommand(s)")
1230 for cmd in args.postcommand:
1231 log.info(" %s", cmd)
1232 exec(cmd, globals(), {'flags': flags, 'cfg': cfg})
1233
1234 # Dump configuration to JSON
1235 fname = "HLTJobOptions"
1236 log.info("Dumping configuration to %s.pkl and %s.json", fname, fname)
1237 with open(f"{fname}.pkl", "wb") as f:
1238 cfg.store(f)
1239
1240 from TrigConfIO.JsonUtils import create_joboptions_json
1241 create_joboptions_json(f"{fname}.pkl", f"{fname}.json")
1242
1243 # Check for dump-and-exit
1244 if args.dump_config_exit:
1245 log.info("Configuration dumped to %s.json. Exiting...", fname)
1246 sys.exit(0)
1247
1248 # Re-exec from the JSON. Replaces the process image freeing up the configuration heap.
1249 log.info("Configuration dumped to %s.json. Re-exec...", fname)
1250 AthHLT.reload_from_json(f"{fname}.json", suppress_args=unparsed_args + ['--dump-config'], jobOptions=args.jobOptions)
1251
1252

◆ 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 1030 of file athenaEF.py.

1030def find_is_schema_files():
1031 """
1032 Resolve IS_SCHEMA_FILES to absolute paths using DATAPATH.
1033 rdb_server must be given the schema of every IS type we publish.
1034 """
1035 from AthenaCommon.Utils.unixtools import find_datafile
1036
1037 found = []
1038 for fname in IS_SCHEMA_FILES:
1039 path = find_datafile(fname)
1040 if path:
1041 found.append(os.path.abspath(path))
1042 else:
1043 log.error("IS schema file %s not found on DATAPATH: IS publication will fail with HTTP 400", fname)
1044 return found
1045
1046

◆ 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 483 of file athenaEF.py.

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

◆ 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 320 of file athenaEF.py.

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

◆ 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 811 of file athenaEF.py.

811def load_from_database(db_server, smk, l1psk=None, hltpsk=None, run_params=None, overrides=None):
812 """
813 Load configuration from trigger database using the Super Master Key (SMK).
814
815 Returns a ConfigRunner that uses TrigConf::JobOptionsSvc with TYPE="DB"
816 to load configuration directly from the database.
817 """
818 log.info("Loading job options from database %s with SMK %d", db_server, smk)
819 return ConfigRunner.from_database(db_server, smk, l1psk, hltpsk, run_params, overrides=overrides)
820

◆ 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 794 of file athenaEF.py.

794def load_from_json(json_file, run_params=None, overrides=None):
795 """
796 Load configuration from a Gaudi joboptions JSON file.
797
798 Returns a ConfigRunner with a run() method that executes the configuration
799 using TrigConf::JobOptionsSvc with TYPE="FILE".
800 """
801 with open(json_file, 'r') as f:
802 jocat = json.load(f)
803
804 if jocat.get('filetype') != 'joboptions':
805 raise ValueError(f"Invalid JSON file type: {jocat.get('filetype')}, expected 'joboptions'")
806
807 properties = jocat.get('properties', {})
808 return ConfigRunner.from_json(json_file, run_params, properties, overrides=overrides)
809
810

◆ main()

main ( )

Definition at line 1253 of file athenaEF.py.

1253def main():
1254 parser = argparse.ArgumentParser(prog='athenaEF.py', formatter_class=
1255 lambda prog : argparse.ArgumentDefaultsHelpFormatter(prog, max_help_position=32, width=100),
1256 usage = '%(prog)s [OPTION]... -f FILE jobOptions',
1257 add_help=False)
1258 parser.expert_groups = [] # Keep list of expert option groups
1259
1260
1261 g = parser.add_argument_group('Options')
1262 g.add_argument('jobOptions', nargs='?', help='job options: CA module (package.module:function) or JSON file (.json)')
1263 g.add_argument('--threads', metavar='N', type=int, default=1, help='number of threads')
1264 g.add_argument('--concurrent-events', metavar='N', type=int, help='number of concurrent events if different from --threads')
1265 g.add_argument('--log-level', '-l', metavar='LVL', default='INFO', help='OutputLevel of athena')
1266 g.add_argument('--precommand', '-c', metavar='CMD', action='append', default=[],
1267 help='Python commands executed before job options')
1268 g.add_argument('--postcommand', '-C', metavar='CMD', action='append', default=[],
1269 help='Python commands executed after job options')
1270 g.add_argument('--interactive', '-i', action='store_true', help='interactive mode')
1271 g.add_argument('--help', '-h', nargs='?', choices=['all'], action=MyHelp, help='show help')
1272
1273 g = parser.add_argument_group('Input/Output')
1274 g.add_argument('--file', '--filesInput', '-f', action='append', help='input RAW file')
1275 g.add_argument('--save-output', '-o', metavar='FILE', help='output file name')
1276 g.add_argument('--number-of-events', '--evtMax', '-n', metavar='N', type=int, default=None,
1277 help='processes N events (default: from DB/config, -1 means all)')
1278 g.add_argument('--skip-events', '--skipEvents', '-k', metavar='N', type=int, default=None,
1279 help='skip N first events')
1280 g.add_argument('--loop-files', action=argparse.BooleanOptionalAction, default=None,
1281 help='loop over input files if no more events')
1282 g.add_argument('--efdf-interface-library', metavar='LIB', default=None,
1283 help='name of the EFDF interface shared library to load (default: TrigDFEmulator)')
1284
1285
1286 g = parser.add_argument_group('Performance and debugging')
1287 g.add_argument('--perfmon', action='store_true', help='enable PerfMon')
1288 g.add_argument('--tcmalloc', action='store_true', default=True, help='use tcmalloc')
1289 g.add_argument('--stdcmalloc', action='store_true', help='use stdcmalloc')
1290 g.add_argument('--stdcmath', action='store_true', help='use stdcmath library')
1291 g.add_argument('--imf', action='store_true', default=True, help='use Intel math library')
1292 g.add_argument('--timeout', metavar='MSEC', type=int, default=None,
1293 help='event processing timeout (HardTimeout) in milliseconds. '
1294 f'NB: only the soft timeout ({SOFT_TIMEOUT_FRACTION*100:.0f}%% of it) is enforced')
1295
1296
1297 g = parser.add_argument_group('Conditions')
1298 g.add_argument('--run-number', '-R', metavar='RUN', type=int,
1299 help='run number (if None, read from first event)')
1300 g.add_argument('--lb-number', '-L', metavar='LBN', type=int,
1301 help='lumiblock number (if None, read from first event)')
1302 g.add_argument('--conditions-run', metavar='RUN', type=int, default=None,
1303 help='reference run number for conditions lookup (use when IS run number has no COOL data)')
1304 g.add_argument('--sor-time', type=arg_sor_time,
1305 help='The Start Of Run time. Three formats are accepted: '
1306 '1) the string "now", for current time; '
1307 '2) the number of nanoseconds since epoch (e.g. 1386355338658000000 or int(time.time() * 1e9)); '
1308 '3) human-readable "20/11/18 17:40:42.3043". If not specified the sor-time is read from the conditions DB')
1309 g.add_argument('--detector-mask', metavar='MASK', type=arg_detector_mask,
1310 help='detector mask (if None, read from the conditions DB), use string "all" to enable all detectors')
1311
1312
1313 g = parser.add_argument_group('Database')
1314 g.add_argument('--use-database', '-b', action='store_true',
1315 help='configure from trigger database using SMK')
1316 g.add_argument('--db-server', metavar='DB', default='TRIGGERDB_RUN3', help='DB server name (alias)')
1317 g.add_argument('--smk', type=int, default=None, help='Super Master Key')
1318 g.add_argument('--l1psk', type=int, default=None, help='L1 prescale key')
1319 g.add_argument('--hltpsk', type=int, default=None, help='HLT prescale key')
1320 g.add_argument('--use-crest', action='store_true', default=False,
1321 help='Use CREST for trigger configuration')
1322 g.add_argument('--crest-server', metavar='URL', default=None,
1323 help='CREST server URL (default: $CREST_SERVER or crest.cern.ch)')
1324 g.add_argument('--dump-config', action='store_true', help='Dump joboptions JSON file')
1325 g.add_argument('--dump-config-exit', action='store_true', help='Dump joboptions JSON file and exit')
1326
1327
1328 g = parser.add_argument_group('Magnets')
1329 g.add_argument('--solenoid-current', type=float, default=None,
1330 help='Solenoid current in Amperes (default: nominal current for offline running, required from IS online)')
1331 g.add_argument('--toroids-current', type=float, default=None,
1332 help='Toroids current in Amperes (default: nominal current for offline running, required from IS online)')
1333
1334
1335 g = parser.add_argument_group('Online')
1336 g.add_argument('--online-environment', action='store_true',
1337 help='Enable online environment: read run parameters from IS and trigger '
1338 'configuration keys (SMK, L1PSK, HLTPSK) from OKS via WEBDAQ REST API')
1339 g.add_argument('--partition', metavar='NAME', default=None,
1340 help='TDAQ partition name (defaults to TDAQ_PARTITION environment variable)')
1341 g.add_argument('--webdaq-base', metavar='URL', default=None,
1342 help='WEBDAQ base URL (defaults to TDAQ_WEBDAQ_BASE environment variable)')
1343
1344
1345 g = parser.add_argument_group('Online Histogramming')
1346 g.add_argument('--oh-monitoring', '-M', action='store_true', default=False,
1347 help='enable online histogram publishing via WebdaqHistSvc')
1348
1349
1350 g = parser.add_argument_group('Expert')
1351 parser.expert_groups.append(g)
1352 (args, unparsed_args) = parser.parse_known_args()
1353 check_args(parser, args)
1354
1355 # set ROOT to batch mode (ATR-21890)
1356 from PyUtils.Helpers import ROOTSetup
1357 ROOTSetup(batch=True)
1358
1359 # Enable ROOT thread safety
1360 import ROOT
1361 ROOT.ROOT.EnableThreadSafety()
1362
1363 # set default Python OutputLevel and file inclusion
1364 import AthenaCommon.Logging
1365 AthenaCommon.Logging.log.setLevel(getattr(logging, args.log_level))
1366 AthenaCommon.Logging.log.setFormat("%(asctime)s Py:%(name)-31s %(levelname)7s %(message)s")
1367
1368 # consistency checks for arguments
1369 if not args.concurrent_events:
1370 args.concurrent_events = args.threads
1371
1372 # Determine the source of the configuration.
1373 is_database = args.use_database
1374 is_json = bool(args.jobOptions) and not is_database and args.jobOptions.endswith('.json')
1375 is_ca = not (is_database or is_json)
1376
1377 # CREST configuration (only used with --use-database, see check_args)
1378 log.info("Using CREST for trigger configuration: %s", args.use_crest)
1379 if args.use_crest and args.crest_server is None:
1380 from IOVDbSvc.IOVDbAutoCfgFlags import getCrestConnection
1381 args.crest_server = getCrestConnection()
1382 log.info("Using default CREST server: %s", args.crest_server)
1383
1384 update_run_params(args)
1385
1386 # If the HLT PSK was given on the command line OR from OKS (--online-environment), ignore what is
1387 # stored in COOL and read that key directly from the DB (ATR-25974).
1388 # This is needed because COOL may point to a different HLTPSK for the forced run number.
1389 # NB: must be evaluated before update_trigconf_keys, which fills args.hltpsk from COOL/OKS.
1390 force_psk = args.use_database and ((args.hltpsk is not None) or args.online_environment)
1391
1392 if args.use_database:
1393 # Read trigger config keys from COOL/OKS if not specified
1394 update_trigconf_keys(args)
1395
1396 # Configure from a CA module: athenaEF is re-executed from the JSON (or exits for --dump-config-exit).
1397 if is_ca:
1398 configure_from_ca(args, unparsed_args)
1399
1400
1404 config_source = "the trigger database" if is_database else "a JSON file"
1405
1406 if unparsed_args:
1407 log.warning("Ignoring flag(s) given on the command line, the configuration is read from %s: %s",
1408 config_source, ' '.join(unparsed_args))
1409
1410 # Overrides applied to the configuration at runtime.
1411 # Only options explicitly given on the command line are collected, anything else keeps its DB/jobOptions value.
1412 # NB: Do NOT set the corresponding flags here, that would put them in the SMK.
1413 overrides = RuntimeOverrides()
1414
1415 overrides.set('AvalancheSchedulerSvc.ThreadPoolSize', args.threads)
1416 overrides.set('EventDataSvc.NSlots', args.concurrent_events)
1417
1418 ef_files = args.file if args.file else []
1419 if ef_files:
1420 overrides.set('EFInterfaceSvc.Files', ef_files)
1421 overrides.set('EFInterfaceSvc.T0ProjectTag', args.T0_project_tag)
1422 overrides.set('EFInterfaceSvc.BeamType', args.beam_type)
1423 overrides.set('EFInterfaceSvc.BeamEnergy', args.beam_energy)
1424 overrides.set('EFInterfaceSvc.TriggerType', args.trigger_type)
1425 overrides.set('EFInterfaceSvc.Stream', args.stream)
1426 overrides.set('EFInterfaceSvc.Lumiblock', args.lumiblock)
1427 overrides.set('EFInterfaceSvc.DetMask', args.file_detector_mask)
1428 if args.run_number is not None: # from -R, IS, or the input file
1429 overrides.set('EFInterfaceSvc.RunNumber', args.run_number)
1430 if args.save_output is not None:
1431 overrides.set('EFInterfaceSvc.OutputFileName', args.save_output)
1432 if args.loop_files is not None:
1433 overrides.set('EFInterfaceSvc.LoopOverFiles', args.loop_files)
1434 if args.number_of_events is not None:
1435 overrides.set('EFInterfaceSvc.NumEvents', args.number_of_events)
1436 if args.skip_events is not None:
1437 overrides.set('EFInterfaceSvc.SkipEvents', args.skip_events)
1438 if args.efdf_interface_library is not None:
1439 overrides.set('EFInterfaceSvc.EFDFInterfaceLibraryName', args.efdf_interface_library)
1440
1441 if args.timeout is not None:
1442 overrides.set('HltEventLoopMgr.HardTimeout', float(args.timeout))
1443 overrides.set('HltEventLoopMgr.SoftTimeoutFraction', SOFT_TIMEOUT_FRACTION)
1444 if args.conditions_run is not None:
1445 # Run number used for the conditions IOV lookup
1446 overrides.set('HltEventLoopMgr.forceRunNumber', args.conditions_run)
1447
1448 if force_psk:
1449 overrides.set('HLTPrescaleCondAlg.Source', 'DB')
1450
1451 # Histogram service:
1452 # Offline the command line decides and overrides the SMK/JSON conf (offline behaviour never depends on the SMK).
1453 # Online (--online-environment) we leave the configuration exactly as it is.
1454 if not args.online_environment:
1455 if args.oh_monitoring:
1456 overrides.declare_type('THistSvc', 'WebdaqHistSvc')
1457 overrides.create_service('WebdaqInfoSvc')
1458 else:
1459 overrides.declare_type('THistSvc', 'THistSvc')
1460 overrides.drop_service('WebdaqInfoSvc')
1461
1462 # Postcommands are applied by ConfigRunner.run() after configure(). NB: do not run for --dump-config-exit.
1463 for cmd in args.postcommand:
1464 overrides.add_command(cmd)
1465
1466 # Execute precommands
1467 if args.precommand:
1468 log.info("Executing precommand(s)")
1469 for cmd in args.precommand:
1470 log.info(" %s", cmd)
1471 exec(cmd, globals(), {})
1472
1473 if is_database:
1474 # Load configuration from trigger database
1475 # Handle CREST vs standard DB access
1476 if args.use_crest:
1477 from TrigConfStorage.TriggerCrestUtil import TriggerCrestUtil
1478 crestconn = TriggerCrestUtil.getCrestConnection(args.db_server)
1479 db_alias = f"{args.crest_server}/{crestconn}"
1480 log.info("Loading configuration via CREST from %s with SMK %d", db_alias, args.smk)
1481 else:
1482 db_alias = args.db_server
1483 log.info("Loading configuration from database %s with SMK %d", db_alias, args.smk)
1484
1485 # Get run parameters for prepareForStart
1486 run_params = get_run_params(args).to_dict()
1487 acc = load_from_database(db_alias, args.smk, args.l1psk, args.hltpsk, run_params, overrides=overrides)
1488 log.info("Configuration loaded from database")
1489
1490 else: # is_json
1491 # Load configuration from JSON file
1492 log.info("Loading configuration from JSON file: %s", args.jobOptions)
1493 # Get run parameters for prepareForStart
1494 run_params = get_run_params(args).to_dict()
1495 acc = load_from_json(args.jobOptions, run_params, overrides=overrides)
1496 log.info("Configuration loaded from JSON")
1497
1498 # Dump configuration if requested
1499 if args.dump_config or args.dump_config_exit:
1500 fname = "HLTJobOptions"
1501
1502 if is_database:
1503 # For DB mode, fetch properties via Python API
1504 from TrigConfIO.HLTTriggerConfigAccess import HLTJobOptionsAccess
1505 log.info("Fetching configuration from database for dump...")
1506 jo_access = HLTJobOptionsAccess(dbalias=acc.db_server, smkey=acc.smk)
1507 props = jo_access.algorithms()
1508
1509 log.info("Dumping configuration to %s.json", fname)
1510 hlt_json = {'filetype': 'joboptions', 'properties': props}
1511 with open(f"{fname}.json", "w") as f:
1512 json.dump(hlt_json, f, indent=4, sort_keys=True, ensure_ascii=True)
1513
1514 elif is_json:
1515 # For JSON mode, properties were already loaded
1516 props = acc.properties
1517 if props:
1518 log.info("Dumping configuration to %s.json", fname)
1519 hlt_json = {'filetype': 'joboptions', 'properties': props}
1520 with open(f"{fname}.json", "w") as f:
1521 json.dump(hlt_json, f, indent=4, sort_keys=True, ensure_ascii=True)
1522 else:
1523 log.warning("No properties available to dump")
1524
1525 if args.dump_config_exit:
1526 log.info("Configuration dumped. Exiting...")
1527 sys.exit(0)
1528
1529 # Run the application directly (like athena.py does)
1530 log.info("Starting Athena execution...")
1531
1532 # Create worker directory structure that HLT services expect
1533 # (normally created by HLTMPPU/PSC). Worker ID 1 means single-worker, non-forked mode
1534 # and must match what we pass to hltUpdateAfterFork(worker_id=1) in ConfigRunner.run()
1535 worker_dir = os.path.join(os.getcwd(), "athenaHLT_workers", "athenaHLT-01")
1536 if not os.path.exists(worker_dir):
1537 log.info("Creating worker directory: %s", worker_dir)
1538 os.makedirs(worker_dir, exist_ok=True)
1539
1540 # Start the private TDAQ infrastructure for -M
1541 oh_infra = start_oh_infrastructure(args) if args.oh_monitoring else None
1542
1543 if args.interactive:
1544 log.info("Interactive mode - call acc.run() to execute")
1545 import code
1546 code.interact(local={'acc': acc})
1547 else:
1548 # Run the application
1549 from AthenaCommon import ExitCodes
1550 exitcode = 0
1551 try:
1552 # Pass maxEvents if explicitly set (including -1 for all events)
1553 sc = acc.run(args.number_of_events)
1554 if sc.isFailure():
1555 exitcode = ExitCodes.EXE_ALG_FAILURE
1556 except SystemExit as e:
1557 exitcode = ExitCodes.EXE_ALG_FAILURE if e.code == 1 else e.code
1558 except Exception:
1559 traceback.print_exc()
1560 exitcode = ExitCodes.UNKNOWN_EXCEPTION
1561 finally:
1562 stop_oh_infrastructure(oh_infra)
1563
1564 log.info('Leaving with code %d: "%s"', exitcode, ExitCodes.what(exitcode))
1565 sys.exit(exitcode)
1566
1567
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 1047 of file athenaEF.py.

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

◆ stop_oh_infrastructure()

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

Definition at line 1114 of file athenaEF.py.

1114def stop_oh_infrastructure(proc):
1115 """Terminate the private TDAQ infrastructure (SIGTERM triggers oh_cp + ipc_rm)."""
1116 if proc is None or proc.poll() is not None:
1117 return
1118 import signal
1119 log.info("Stopping OH infrastructure")
1120 proc.send_signal(signal.SIGTERM)
1121 try:
1122 proc.wait(timeout=60)
1123 except Exception:
1124 proc.kill()
1125
1126

◆ update_run_params()

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

Definition at line 863 of file athenaEF.py.

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

◆ update_trigconf_keys()

update_trigconf_keys ( args)
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 957 of file athenaEF.py.

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

◆ log

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

Definition at line 49 of file athenaEF.py.

◆ SOFT_TIMEOUT_FRACTION

float athenaEF.SOFT_TIMEOUT_FRACTION = 0.95

Definition at line 53 of file athenaEF.py.