ATLAS Offline Software
Loading...
Searching...
No Matches
athenaEF.ConfigRunner Class Reference
Collaboration diagram for athenaEF.ConfigRunner:

Public Member Functions

 __init__ (self, job_options_type, job_options_path, run_params=None, properties=None, db_server=None, smk=None, num_threads=1, num_slots=1, ef_files=None)
 from_json (cls, json_file, run_params=None, properties=None, num_threads=1, num_slots=1, ef_files=None)
 from_database (cls, db_server, smk, l1psk=None, hltpsk=None, run_params=None, num_threads=1, num_slots=1, ef_files=None)
 run (self, maxEvents=None)

Public Attributes

str job_options_type = job_options_type
 job_options_path = job_options_path
 run_params = run_params or {}
 properties = properties
 db_server = db_server
 smk = smk
 num_threads = num_threads
 num_slots = num_slots
 ef_files = ef_files or []

Protected Attributes

 _app = None

Detailed Description

Runner class that executes Gaudi configuration from JSON file or database.
Uses TrigConf::JobOptionsSvc with TYPE="FILE" or TYPE="DB" to load configuration.
Same approach used by PSC (Psc.cxx) - it sets JobOptionsType and
JobOptionsPath on the ApplicationMgr, and TrigConf::JobOptionsSvc handles both
FILE and DB modes transparently.

Definition at line 520 of file athenaEF.py.

Constructor & Destructor Documentation

◆ __init__()

athenaEF.ConfigRunner.__init__ ( self,
job_options_type,
job_options_path,
run_params = None,
properties = None,
db_server = None,
smk = None,
num_threads = 1,
num_slots = 1,
ef_files = None )
Args:
   job_options_type: "FILE" or "DB"
   job_options_path: JSON file path (for FILE) or DB connection string (for DB)
   run_params: Run parameters dict for prepareForStart
   properties: Pre-loaded properties dict (optional, for FILE mode)
   db_server: DB server alias (for store() in DB mode)
   smk: Super Master Key (for store() in DB mode)
   num_threads: Number of threads for AvalancheSchedulerSvc.ThreadPoolSize
   num_slots: Number of event slots for EventDataSvc.NSlots
   ef_files: List of input files for EFInterfaceSvc

Definition at line 528 of file athenaEF.py.

530 num_threads=1, num_slots=1, ef_files=None):
531 """
532 Args:
533 job_options_type: "FILE" or "DB"
534 job_options_path: JSON file path (for FILE) or DB connection string (for DB)
535 run_params: Run parameters dict for prepareForStart
536 properties: Pre-loaded properties dict (optional, for FILE mode)
537 db_server: DB server alias (for store() in DB mode)
538 smk: Super Master Key (for store() in DB mode)
539 num_threads: Number of threads for AvalancheSchedulerSvc.ThreadPoolSize
540 num_slots: Number of event slots for EventDataSvc.NSlots
541 ef_files: List of input files for EFInterfaceSvc
542 """
543 self.job_options_type = job_options_type
544 self.job_options_path = job_options_path
545 self.run_params = run_params or {}
546 self.properties = properties
547 self.db_server = db_server # For store() in DB mode
548 self.smk = smk # For store() in DB mode
549 self.num_threads = num_threads
550 self.num_slots = num_slots
551 self.ef_files = ef_files or [] # Input files for EFInterfaceSvc
552 self._app = None
553

Member Function Documentation

◆ from_database()

athenaEF.ConfigRunner.from_database ( cls,
db_server,
smk,
l1psk = None,
hltpsk = None,
run_params = None,
num_threads = 1,
num_slots = 1,
ef_files = None )
Create runner for database (TYPE=DB)

Definition at line 562 of file athenaEF.py.

563 num_threads=1, num_slots=1, ef_files=None):
564 """Create runner for database (TYPE=DB)"""
565 # Build the DB connection string: server=X;smkey=Y;lvl1key=Z;hltkey=W
566 db_path = f"server={db_server};smkey={smk}"
567 if l1psk is not None:
568 db_path += f";lvl1key={l1psk}"
569 if hltpsk is not None:
570 db_path += f";hltkey={hltpsk}"
571 return cls("DB", db_path, run_params, db_server=db_server, smk=smk,
572 num_threads=num_threads, num_slots=num_slots, ef_files=ef_files)
573

◆ from_json()

athenaEF.ConfigRunner.from_json ( cls,
json_file,
run_params = None,
properties = None,
num_threads = 1,
num_slots = 1,
ef_files = None )
Create runner for JSON file (TYPE=FILE)

Definition at line 555 of file athenaEF.py.

556 num_threads=1, num_slots=1, ef_files=None):
557 """Create runner for JSON file (TYPE=FILE)"""
558 return cls("FILE", os.path.abspath(json_file), run_params, properties,
559 num_threads=num_threads, num_slots=num_slots, ef_files=ef_files)
560

◆ run()

athenaEF.ConfigRunner.run ( self,
maxEvents = None )
This follows the same pattern as PSC (Psc.cxx):
1. Create ApplicationMgr via BootstrapHelper
2. Set JobOptionsSvcType, JobOptionsType, JobOptionsPath
3. configure() -> initialize() -> prepareForStart() -> start() ->
   hltUpdateAfterFork() -> run() -> stop() -> finalize() -> terminate()

Definition at line 574 of file athenaEF.py.

574 def run(self, maxEvents=None):
575 """
576 This follows the same pattern as PSC (Psc.cxx):
577 1. Create ApplicationMgr via BootstrapHelper
578 2. Set JobOptionsSvcType, JobOptionsType, JobOptionsPath
579 3. configure() -> initialize() -> prepareForStart() -> start() ->
580 hltUpdateAfterFork() -> run() -> stop() -> finalize() -> terminate()
581 """
582 from Gaudi.Main import BootstrapHelper
583
584 # For FILE mode, load properties from JSON if not already provided
585 if self.job_options_type == "FILE" and self.properties is None:
586 with open(self.job_options_path, 'r') as f:
587 jocat = json.load(f)
588 self.properties = jocat.get('properties', {})
589
590 bsh = BootstrapHelper()
591 app = bsh.createApplicationMgr()
592 self._app = app
593
594 # For FILE mode, set ApplicationMgr properties from JSON before configure
595 if self.job_options_type == "FILE" and self.properties:
596 app_props = self.properties.get('ApplicationMgr', {})
597 for k, v in app_props.items():
598 if k not in ('JobOptionsSvcType', 'JobOptionsType', 'JobOptionsPath'):
599 log.debug("Setting ApplicationMgr.%s = %s", k, v)
600 app.setProperty(k, str(v) if not isinstance(v, str) else v)
601
602 # Set JobOptionsSvc properties like PSC does in Psc.cxx
603 log.info("Configuring TrigConf::JobOptionsSvc with TYPE=%s, PATH=%s",
604 self.job_options_type, self.job_options_path)
605 app.setProperty("JobOptionsSvcType", "TrigConf::JobOptionsSvc")
606 app.setProperty("JobOptionsType", self.job_options_type)
607 app.setProperty("JobOptionsPath", self.job_options_path)
608
609 # Configure the application - TrigConf::JobOptionsSvc will load from FILE or DB
610 app.configure()
611
612 # Override EvtMax AFTER configure() only if explicitly specified by user
613 # Otherwise use whatever value is in the DB
614 if maxEvents is not None:
615 log.info("Setting EvtMax=%d (overriding DB value)", maxEvents)
616 app.setProperty('EvtMax', str(maxEvents))
617
618 # All property overrides below use iProperty and must be done after configure()
619 # but before initialize() - this is the same pattern as PSC (Psc.cxx)
620 from GaudiPython.Bindings import iProperty
621
622 # Override EFInterfaceSvc.NumEvents if user specified it (overrides DB value)
623 if maxEvents is not None:
624 log.info("Setting EFInterfaceSvc.NumEvents=%d (overriding DB value)", maxEvents)
625 iProperty("EFInterfaceSvc").NumEvents = maxEvents
626
627 # Set threading configuration
628 log.info("Setting threading: ThreadPoolSize=%d, NSlots=%d", self.num_threads, self.num_slots)
629 iProperty("AvalancheSchedulerSvc").ThreadPoolSize = self.num_threads
630 iProperty("EventDataSvc").NSlots = self.num_slots
631
632 # Set input files and metadata for EFInterfaceSvc (overrides what's in DB/JSON config)
633 if self.ef_files:
634 log.info("Setting EFInterfaceSvc.Files = %s", self.ef_files)
635 iProperty("EFInterfaceSvc").Files = self.ef_files
636 iProperty("EFInterfaceSvc").T0ProjectTag = self.run_params.get('T0_project_tag', '')
637 iProperty("EFInterfaceSvc").BeamType = self.run_params.get('beam_type', 0)
638 iProperty("EFInterfaceSvc").BeamEnergy = self.run_params.get('beam_energy', 0)
639 iProperty("EFInterfaceSvc").TriggerType = self.run_params.get('trigger_type', 0)
640 iProperty("EFInterfaceSvc").Stream = self.run_params.get('stream', '')
641 iProperty("EFInterfaceSvc").Lumiblock = self.run_params.get('lumiblock', 0)
642 iProperty("EFInterfaceSvc").DetMask = self.run_params.get('detector_mask', '')
643
644 # If HLT PSK is set on command line, read it from DB instead of COOL (ATR-25974)
645 # This is the same logic as TrigPSCPythonDbSetup.py
646 from TrigPSC import PscConfig
647 if PscConfig.forcePSK:
648 log.info("PscConfig.forcePSK is set - configuring HLTPrescaleCondAlg to read from DB instead of COOL")
649 iProperty("HLTPrescaleCondAlg").Source = "DB"
650
651 # Set forceRunNumber on HltEventLoopMgr if conditions_run is specified
652 # This overrides the run number used for IOV lookup in conditions loading
653 conditions_run = self.run_params.get('conditions_run')
654 if conditions_run is not None:
655 log.info("Setting HltEventLoopMgr.forceRunNumber=%d for conditions lookup", conditions_run)
656 iProperty("HltEventLoopMgr").forceRunNumber = conditions_run
657
658 # Initialize
659 sc = app.initialize()
660 if not sc.isSuccess():
661 log.error("Failed to initialize AppMgr")
662 return sc
663
664 # Initialize TrigServicesHelper for lifecycle calls (prepareForStart, prepareForRun, hltUpdateAfterFork)
665 try:
666 from TrigServices.TrigServicesHelper import TrigServicesHelper
667 helper = TrigServicesHelper()
668 except ImportError as e:
669 log.error("TrigServicesHelper not available: %s", e)
670 log.error("Cannot proceed without TrigServicesHelper - required for HLTEventLoopMgr lifecycle")
671 raise RuntimeError("TrigServicesHelper not available") from e
672
673 # Call prepareForStart to set up ByteStreamMetadata (like PSC does)
674 try:
675 run_number = self.run_params['run_number']
676 det_mask = self.run_params['detector_mask']
677 sor_time = self.run_params['sor_time']
678 solenoid_current = self.run_params['solenoid_current']
679 toroids_current = self.run_params['toroids_current']
680
681 log.info("Calling prepareForStart with run=%d, det_mask=0x%s, sor_time=%s",
682 run_number, det_mask, sor_time)
683
684 success = helper.prepareForStart(
685 run_number=run_number,
686 det_mask=det_mask,
687 sor_time=sor_time,
688 solenoid_current=solenoid_current,
689 toroids_current=toroids_current
690 )
691 if not success:
692 log.error("prepareForStart failed")
693 raise RuntimeError("prepareForStart failed")
694 log.info("prepareForStart completed successfully")
695 except Exception as e:
696 log.error("Error calling prepareForStart: %s", e)
697 traceback.print_exc()
698 raise
699
700 # Start
701 sc = app.start()
702 if not sc.isSuccess():
703 log.error("Failed to start AppMgr")
704 return sc
705
706 # prepareForRun initializes COOL folder helper - must be called after start()
707 # which fires the start incident
708 try:
709 log.info("Calling prepareForRun to initialize COOL folder helper")
710 success = helper.prepareForRun()
711 if not success:
712 log.error("prepareForRun failed")
713 raise RuntimeError("prepareForRun failed")
714 log.info("prepareForRun completed successfully")
715 except Exception as e:
716 log.error("Error calling prepareForRun: %s", e)
717 traceback.print_exc()
718 raise
719
720 # hltUpdateAfterFork initializes the scheduler (like PSC does after fork)
721 # worker_id=1 for single-worker, non-forked mode
722 try:
723 log.info("Calling hltUpdateAfterFork to initialize scheduler (worker_id=1)")
724 success = helper.hltUpdateAfterFork(worker_id=1)
725 if not success:
726 log.error("hltUpdateAfterFork failed")
727 raise RuntimeError("hltUpdateAfterFork failed")
728 log.info("hltUpdateAfterFork completed successfully")
729 except Exception as e:
730 log.error("Error calling hltUpdateAfterFork: %s", e)
731 traceback.print_exc()
732 raise
733
734 # Run the event loop
735 # Note: Python signal handlers won't work during C++ execution.
736 nevt = maxEvents if maxEvents is not None else -1
737 sc = app.run(nevt)
738
739 if not sc.isSuccess():
740 log.error("Failure running application")
741 return sc
742
743 # Stop
744 sc = app.stop()
745 if not sc.isSuccess():
746 log.error("Failed to stop AppMgr")
747 return sc
748
749 # Finalize
750 sc = app.finalize()
751 if not sc.isSuccess():
752 log.error("Failed to finalize AppMgr")
753 return sc
754
755 # Terminate
756 sc = app.terminate()
757 return sc
758
759
Helper class to call ITrigEventLoopMgr methods from Python.
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:130
int run(int argc, char *argv[])

Member Data Documentation

◆ _app

athenaEF.ConfigRunner._app = None
protected

Definition at line 552 of file athenaEF.py.

◆ db_server

athenaEF.ConfigRunner.db_server = db_server

Definition at line 547 of file athenaEF.py.

◆ ef_files

athenaEF.ConfigRunner.ef_files = ef_files or []

Definition at line 551 of file athenaEF.py.

◆ job_options_path

athenaEF.ConfigRunner.job_options_path = job_options_path

Definition at line 544 of file athenaEF.py.

◆ job_options_type

athenaEF.ConfigRunner.job_options_type = job_options_type

Definition at line 543 of file athenaEF.py.

◆ num_slots

athenaEF.ConfigRunner.num_slots = num_slots

Definition at line 550 of file athenaEF.py.

◆ num_threads

athenaEF.ConfigRunner.num_threads = num_threads

Definition at line 549 of file athenaEF.py.

◆ properties

athenaEF.ConfigRunner.properties = properties

Definition at line 546 of file athenaEF.py.

◆ run_params

athenaEF.ConfigRunner.run_params = run_params or {}

Definition at line 545 of file athenaEF.py.

◆ smk

athenaEF.ConfigRunner.smk = smk

Definition at line 548 of file athenaEF.py.


The documentation for this class was generated from the following file: