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 g.add_argument('--application-name', metavar='NAME', default=os.environ.get('TDAQ_APPLICATION_NAME', 'athenaEF'),
1344 help='Application name for OH/ERS. Defaults to TDAQ_APPLICATION_NAME environment variable, else athenaEF)')
1345
1346
1347 g = parser.add_argument_group('Online Histogramming')
1348 g.add_argument('--oh-monitoring', '-M', action='store_true', default=False,
1349 help='enable online histogram publishing via WebdaqHistSvc')
1350
1351
1352 g = parser.add_argument_group('Expert')
1353 parser.expert_groups.append(g)
1354 (args, unparsed_args) = parser.parse_known_args()
1355 # ERS reads the application name from the environment, setting here to enforce consistency
1356 os.environ['TDAQ_APPLICATION_NAME'] = args.application_name
1357 check_args(parser, args)
1358
1359 # set ROOT to batch mode (ATR-21890)
1360 from PyUtils.Helpers import ROOTSetup
1361 ROOTSetup(batch=True)
1362
1363 # Enable ROOT thread safety
1364 import ROOT
1365 ROOT.ROOT.EnableThreadSafety()
1366
1367 # set default Python OutputLevel and file inclusion
1368 import AthenaCommon.Logging
1369 AthenaCommon.Logging.log.setLevel(getattr(logging, args.log_level))
1370 AthenaCommon.Logging.log.setFormat("%(asctime)s Py:%(name)-31s %(levelname)7s %(message)s")
1371
1372 # consistency checks for arguments
1373 if not args.concurrent_events:
1374 args.concurrent_events = args.threads
1375
1376 # Determine the source of the configuration.
1377 is_database = args.use_database
1378 is_json = bool(args.jobOptions) and not is_database and args.jobOptions.endswith('.json')
1379 is_ca = not (is_database or is_json)
1380
1381 # CREST configuration (only used with --use-database, see check_args)
1382 log.info("Using CREST for trigger configuration: %s", args.use_crest)
1383 if args.use_crest and args.crest_server is None:
1384 from IOVDbSvc.IOVDbAutoCfgFlags import getCrestConnection
1385 args.crest_server = getCrestConnection()
1386 log.info("Using default CREST server: %s", args.crest_server)
1387
1388 update_run_params(args)
1389
1390 # If the HLT PSK was given on the command line OR from OKS (--online-environment), ignore what is
1391 # stored in COOL and read that key directly from the DB (ATR-25974).
1392 # This is needed because COOL may point to a different HLTPSK for the forced run number.
1393 # NB: must be evaluated before update_trigconf_keys, which fills args.hltpsk from COOL/OKS.
1394 force_psk = args.use_database and ((args.hltpsk is not None) or args.online_environment)
1395
1396 if args.use_database:
1397 # Read trigger config keys from COOL/OKS if not specified
1398 update_trigconf_keys(args)
1399
1400 # Configure from a CA module: athenaEF is re-executed from the JSON (or exits for --dump-config-exit).
1401 if is_ca:
1402 configure_from_ca(args, unparsed_args)
1403
1404
1408 config_source = "the trigger database" if is_database else "a JSON file"
1409
1410 if unparsed_args:
1411 log.warning("Ignoring flag(s) given on the command line, the configuration is read from %s: %s",
1412 config_source, ' '.join(unparsed_args))
1413
1414 # Overrides applied to the configuration at runtime.
1415 # Only options explicitly given on the command line are collected, anything else keeps its DB/jobOptions value.
1416 # NB: Do NOT set the corresponding flags here, that would put them in the SMK.
1417 overrides = RuntimeOverrides()
1418
1419 overrides.set('AvalancheSchedulerSvc.ThreadPoolSize', args.threads)
1420 overrides.set('EventDataSvc.NSlots', args.concurrent_events)
1421 overrides.set('DataFlowConfig.DF_ApplicationName', args.application_name)
1422
1423 ef_files = args.file if args.file else []
1424 if ef_files:
1425 overrides.set('EFInterfaceSvc.Files', ef_files)
1426 overrides.set('EFInterfaceSvc.T0ProjectTag', args.T0_project_tag)
1427 overrides.set('EFInterfaceSvc.BeamType', args.beam_type)
1428 overrides.set('EFInterfaceSvc.BeamEnergy', args.beam_energy)
1429 overrides.set('EFInterfaceSvc.TriggerType', args.trigger_type)
1430 overrides.set('EFInterfaceSvc.Stream', args.stream)
1431 overrides.set('EFInterfaceSvc.Lumiblock', args.lumiblock)
1432 overrides.set('EFInterfaceSvc.DetMask', args.file_detector_mask)
1433 if args.run_number is not None: # from -R, IS, or the input file
1434 overrides.set('EFInterfaceSvc.RunNumber', args.run_number)
1435 if args.save_output is not None:
1436 overrides.set('EFInterfaceSvc.OutputFileName', args.save_output)
1437 if args.loop_files is not None:
1438 overrides.set('EFInterfaceSvc.LoopOverFiles', args.loop_files)
1439 if args.number_of_events is not None:
1440 overrides.set('EFInterfaceSvc.NumEvents', args.number_of_events)
1441 if args.skip_events is not None:
1442 overrides.set('EFInterfaceSvc.SkipEvents', args.skip_events)
1443 if args.efdf_interface_library is not None:
1444 overrides.set('EFInterfaceSvc.EFDFInterfaceLibraryName', args.efdf_interface_library)
1445
1446 if args.timeout is not None:
1447 overrides.set('HltEventLoopMgr.HardTimeout', float(args.timeout))
1448 overrides.set('HltEventLoopMgr.SoftTimeoutFraction', SOFT_TIMEOUT_FRACTION)
1449 if args.conditions_run is not None:
1450 # Run number used for the conditions IOV lookup
1451 overrides.set('HltEventLoopMgr.forceRunNumber', args.conditions_run)
1452
1453 if force_psk:
1454 overrides.set('HLTPrescaleCondAlg.Source', 'DB')
1455
1456 # Histogram service:
1457 # Offline the command line decides and overrides the SMK/JSON conf (offline behaviour never depends on the SMK).
1458 # Online (--online-environment) we leave the configuration exactly as it is.
1459 if not args.online_environment:
1460 if args.oh_monitoring:
1461 overrides.declare_type('THistSvc', 'WebdaqHistSvc')
1462 overrides.create_service('WebdaqInfoSvc')
1463 else:
1464 overrides.declare_type('THistSvc', 'THistSvc')
1465 overrides.drop_service('WebdaqInfoSvc')
1466
1467 # Postcommands are applied by ConfigRunner.run() after configure(). NB: do not run for --dump-config-exit.
1468 for cmd in args.postcommand:
1469 overrides.add_command(cmd)
1470
1471 # Execute precommands
1472 if args.precommand:
1473 log.info("Executing precommand(s)")
1474 for cmd in args.precommand:
1475 log.info(" %s", cmd)
1476 exec(cmd, globals(), {})
1477
1478 if is_database:
1479 # Load configuration from trigger database
1480 # Handle CREST vs standard DB access
1481 if args.use_crest:
1482 from TrigConfStorage.TriggerCrestUtil import TriggerCrestUtil
1483 crestconn = TriggerCrestUtil.getCrestConnection(args.db_server)
1484 db_alias = f"{args.crest_server}/{crestconn}"
1485 log.info("Loading configuration via CREST from %s with SMK %d", db_alias, args.smk)
1486 else:
1487 db_alias = args.db_server
1488 log.info("Loading configuration from database %s with SMK %d", db_alias, args.smk)
1489
1490 # Get run parameters for prepareForStart
1491 run_params = get_run_params(args).to_dict()
1492 acc = load_from_database(db_alias, args.smk, args.l1psk, args.hltpsk, run_params, overrides=overrides)
1493 log.info("Configuration loaded from database")
1494
1495 else: # is_json
1496 # Load configuration from JSON file
1497 log.info("Loading configuration from JSON file: %s", args.jobOptions)
1498 # Get run parameters for prepareForStart
1499 run_params = get_run_params(args).to_dict()
1500 acc = load_from_json(args.jobOptions, run_params, overrides=overrides)
1501 log.info("Configuration loaded from JSON")
1502
1503 # Dump configuration if requested
1504 if args.dump_config or args.dump_config_exit:
1505 fname = "HLTJobOptions"
1506
1507 if is_database:
1508 # For DB mode, fetch properties via Python API
1509 from TrigConfIO.HLTTriggerConfigAccess import HLTJobOptionsAccess
1510 log.info("Fetching configuration from database for dump...")
1511 jo_access = HLTJobOptionsAccess(dbalias=acc.db_server, smkey=acc.smk)
1512 props = jo_access.algorithms()
1513
1514 log.info("Dumping configuration to %s.json", fname)
1515 hlt_json = {'filetype': 'joboptions', 'properties': props}
1516 with open(f"{fname}.json", "w") as f:
1517 json.dump(hlt_json, f, indent=4, sort_keys=True, ensure_ascii=True)
1518
1519 elif is_json:
1520 # For JSON mode, properties were already loaded
1521 props = acc.properties
1522 if props:
1523 log.info("Dumping configuration to %s.json", fname)
1524 hlt_json = {'filetype': 'joboptions', 'properties': props}
1525 with open(f"{fname}.json", "w") as f:
1526 json.dump(hlt_json, f, indent=4, sort_keys=True, ensure_ascii=True)
1527 else:
1528 log.warning("No properties available to dump")
1529
1530 if args.dump_config_exit:
1531 log.info("Configuration dumped. Exiting...")
1532 sys.exit(0)
1533
1534 # Run the application directly (like athena.py does)
1535 log.info("Starting Athena execution...")
1536
1537 # Create worker directory structure that HLT services expect
1538 # (normally created by HLTMPPU/PSC). Worker ID 1 means single-worker, non-forked mode
1539 # and must match what we pass to hltUpdateAfterFork(worker_id=1) in ConfigRunner.run()
1540 worker_dir = os.path.join(os.getcwd(), "athenaHLT_workers", "athenaHLT-01")
1541 if not os.path.exists(worker_dir):
1542 log.info("Creating worker directory: %s", worker_dir)
1543 os.makedirs(worker_dir, exist_ok=True)
1544
1545 # Start the private TDAQ infrastructure for -M
1546 oh_infra = start_oh_infrastructure(args) if args.oh_monitoring else None
1547
1548 if args.interactive:
1549 log.info("Interactive mode - call acc.run() to execute")
1550 import code
1551 code.interact(local={'acc': acc})
1552 else:
1553 # Run the application
1554 from AthenaCommon import ExitCodes
1555 exitcode = 0
1556 try:
1557 # Pass maxEvents if explicitly set (including -1 for all events)
1558 sc = acc.run(args.number_of_events)
1559 if sc.isFailure():
1560 exitcode = ExitCodes.EXE_ALG_FAILURE
1561 except SystemExit as e:
1562 exitcode = ExitCodes.EXE_ALG_FAILURE if e.code == 1 else e.code
1563 except Exception:
1564 traceback.print_exc()
1565 exitcode = ExitCodes.UNKNOWN_EXCEPTION
1566 finally:
1567 stop_oh_infrastructure(oh_infra)
1568
1569 log.info('Leaving with code %d: "%s"', exitcode, ExitCodes.what(exitcode))
1570 sys.exit(exitcode)
1571
1572
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.