214 onlyComponents = [], printDefaults=False, printSequenceTreeOnly=False, prefix=None):
215 msg = logging.getLogger(prefix)
if prefix
else self.
_msg
217 msg.info(
"Event Algorithm Sequences" )
219 def printSeqAndAlgs(seq, nestLevel = 0,
220 onlyComponents = []):
222 if name
in seq._properties:
223 return seq._properties[name]
224 return seq._descriptors[name].default
226 msg.info(
"%s\\__ %s (seq: %s %s)",
" "*nestLevel, seq.name,
227 "SEQ" if __prop(
"Sequential")
else "PAR",
230 msg.info(
"%s\\__ %s",
" "*nestLevel, seq.name)
235 printSeqAndAlgs(c, nestLevel, onlyComponents = onlyComponents )
238 msg.info(
"%s\\__ %s (alg) %s",
" "*nestLevel, c.getFullJobOptName(), self.
_componentsContext.
get(c.name,
""))
240 msg.info(
"%s\\__ %s",
" "*nestLevel, c.name )
241 if summariseProps
and flag:
246 msg.info(
"Top sequence %d", n )
247 printSeqAndAlgs(s, onlyComponents = onlyComponents)
249 if printSequenceTreeOnly:
253 onlyComponents = onlyComponents)
254 msg.info(
"Services" )
255 msg.info( [ s[0].name + (
" (created) " if s[0].name
in self.
_servicesToCreate else "")
256 for s
in filterComponents (self.
_services, onlyComponents) ] )
257 msg.info(
"Public Tools" )
259 for (t, flag)
in filterComponents (self.
_publicTools, onlyComponents):
262 if summariseProps
and flag:
265 msg.info(
"Private Tools")
274 msg.info(
"Auditors" )
277 msg.info(
"theApp properties" )
279 msg.info(
" %s : %s", k, v)
465 def addEventAlgo(self, algorithms,sequenceName=None,primary=False,domain=None):
466 if not isinstance(algorithms, Sequence):
468 algorithms=[algorithms,]
470 if sequenceName
is None:
473 seq = findSubSequence(self.
_sequence,
'AthAlgSeq')
477 seq = findSubSequence(self.
_sequence, sequenceName)
482 for algo
in algorithms:
483 if not isinstance(algo, GaudiConfig2.Configurable):
484 raise TypeError(f
"Attempt to add wrong type: {type(algo).__name__} as event algorithm")
486 if algo.__component_type__ !=
"Algorithm":
487 raise TypeError(f
"Attempt to add an {algo.__component_type__} as event algorithm")
490 context = createContextForDeduplication(
"Merging with existing Event Algorithm", algo.name, self.
_componentsContext)
496 existingAlgInDest = findAlgorithm(seq, algo.name)
497 if not existingAlgInDest:
503 if len(algorithms)>1:
504 self.
_msg.warning(
"Called addEvenAlgo with a list of algorithms and primary==True. "
505 "Designating the first algorithm as primary component")
507 self.
_msg.warning(
"addEventAlgo: Overwriting primary component of this CA. Was %s/%s, now %s/%s",
509 algorithms[0].__cpp_type__, algorithms[0].name)
514 if "trackEventAlgo" in ComponentAccumulator.debugMode:
515 for algo
in algorithms:
971 # Set ROOT batch mode
972 from PyUtils.Helpers import ROOTSetup
973 ROOTSetup(batch = not self.interactive)
975 # Create the Gaudi object early.
976 # Without this here, pyroot can sometimes get confused
977 # and report spurious type mismatch errors about this object.
981 appPropsToSet, mspPropsToSet, bshPropsToSet = self.gatherProps()
983 self._wasMerged = True
984 from Gaudi.Main import BootstrapHelper
986 bsh = BootstrapHelper()
987 app = bsh.createApplicationMgr()
989 for k, v in appPropsToSet.items():
990 self._msg.debug("Setting property %s : %s", k, v)
991 app.setProperty(k, v)
993 # An EventLoopMgr always needs to be explicitly configured as the default
994 # Gaudi one will certainly not work in athena.
995 if "EventLoop" not in appPropsToSet:
996 raise Exception("No EventLoopMgr has been configured. If you are using a custom "
997 "EventLoopMgr, make sure to set the 'EventLoop' App property.")
1001 msp = app.getService("MessageSvc")
1002 for k, v in mspPropsToSet.items():
1003 self._msg.debug("Setting property %s : %s", k, v)
1004 bsh.setProperty(msp, k.encode(), v.encode())
1006 # Feed the jobO service with the remaining options
1007 for comp, name, value in bshPropsToSet:
1008 self._msg.debug("Adding %s.%s = %s", comp, name, value)
1009 app.setOption(f"{comp}.{name}", value)
1014 def gatherProps(self):
1015 appPropsToSet = {k: str(v) for k, v in self._theAppProps.items()}
1020 for svc in self._services:
1022 svc.getFullJobOptName(),
1024 if svc.getFullJobOptName() in self._servicesToCreate:
1025 svcToCreate.append(svc.getFullJobOptName())
1027 # order basic services
1028 for bs in reversed(_basicServicesToCreateOrder):
1029 if bs in svcToCreate:
1030 svcToCreate.insert(0, svcToCreate.pop( svcToCreate.index(bs) ) )
1032 extSvc.append("PyAthena::PyComponentMgr/PyComponentMgr")
1034 appPropsToSet["ExtSvc"] = str(extSvc)
1035 appPropsToSet["CreateSvc"] = str(svcToCreate)
1037 def getCompsToBeAdded(comp, namePrefix=""):
1038 name = namePrefix + comp.getName()
1039 for k, v in comp._properties.items():
1040 # Handle special cases of properties:
1041 # 1.PrivateToolHandles
1042 if isinstance(v, GaudiConfig2.Configurable):
1043 # Add the name of the tool as property to the parent
1044 bshPropsToSet.append((name, k, v.getFullJobOptName()))
1045 # Recursively add properties of this tool to the JobOptionSvc
1046 getCompsToBeAdded(v, namePrefix=name + ".")
1047 # 2. PrivateToolHandleArray
1048 elif isinstance(v, GaudiHandles.PrivateToolHandleArray):
1049 # Add names of tools as properties to the parent
1050 bshPropsToSet.append(
1051 (name, k, str([v1.getFullJobOptName() for v1 in v]),)
1053 # Recursively add properties of tools to JobOptionsSvc
1055 getCompsToBeAdded(v1, namePrefix=name + ".")
1057 # For a list of DataHandle, we need to stringify
1058 # each element individually. Otherwise, we get the repr
1059 # version of the elements, which Gaudi JO will choke on.
1060 if isinstance(v, list) and v and isinstance(v[0], DataHandle):
1061 v = [str(x) for x in v]
1062 # For sequences, need to convert the list of algs to names
1063 elif isSequence(comp) and k == "Members":
1064 v = [alg.getFullJobOptName() for alg in comp.Members]
1065 vstr = "" if v is None else str(v)
1066 bshPropsToSet.append((name, k, vstr))
1069 from AthenaPython import PyAthenaComps
1070 PyAlg = PyAthenaComps.Alg
1071 PySvc = PyAthenaComps.Svc
1077 for svc in self._services:
1078 if svc.getName() != "MessageSvc": # MessageSvc will exist already! Needs special treatment
1079 getCompsToBeAdded(svc)
1080 if isinstance(svc, PySvc):
1083 mspPropsToSet.update((k,str(v)) for k,v in svc._properties.items())
1085 # Algorithms and Sequences
1086 for alg in iterSequences(self._sequence):
1087 getCompsToBeAdded(alg)
1088 if isinstance(alg, PyAlg):
1093 for alg in self._conditionsAlgs:
1094 getCompsToBeAdded(alg)
1095 condalgseq.append(alg.getFullJobOptName())
1096 if isinstance(alg, PyAlg):
1098 bshPropsToSet.append(("AthCondSeq", "Members", str(condalgseq)))
1101 for pt in self._publicTools:
1102 getCompsToBeAdded(pt, namePrefix="ToolSvc.")
1105 for aud in self._auditors:
1106 getCompsToBeAdded(aud)
1108 return appPropsToSet, mspPropsToSet, bshPropsToSet
1110 def run(self,maxEvents=None):
1111 from os import environ
1112 outpklfile = environ.get("PICKLECAFILE", None)
1113 if outpklfile is not None:
1114 if outpklfile: # non-empty string
1115 self._msg.info("Storing configuration in pickle file %s",outpklfile)
1116 with open(outpklfile, "wb") as f:
1118 else: # empty string, just exit
1120 self._msg.info("Exiting after configuration stage")
1121 from Gaudi.Main import BootstrapHelper
1122 return BootstrapHelper.StatusCode(True)
1124 # Make sure python output is flushed before triggering output from Gaudi.
1125 # Otherwise, observed output ordering may differ between py2/py3.
1129 #Set TDAQ_ERS_NO_SIGNAL_HANDLERS to avoid interference with
1130 #TDAQ signal handling
1131 environ['TDAQ_ERS_NO_SIGNAL_HANDLERS']='1'
1132 from AthenaCommon.Debugging import allowPtrace, hookDebugger
1135 checkSequenceConsistency(self._sequence)
1137 app = self.createApp()
1138 self.__verifyFinalSequencesStructure()
1140 #Determine maxEvents
1141 if maxEvents is None:
1142 if "EvtMax" in self._theAppProps:
1143 maxEvents=self._theAppProps["EvtMax"]
1147 if self.interactive == 'init':
1148 printInteractiveMsg_init()
1149 from sys import exit # noqa: F401
1150 startInteractive(locals())
1152 #At this point, we don't need the internal structures of this CA any more, clean them up
1155 self._msg.info(f"Athena job with pid {os.getpid()}")
1157 if (self._debugStage.value == "init"):
1159 sc = app.initialize()
1160 if not sc.isSuccess():
1161 self._msg.error("Failed to initialize AppMgr")
1165 if not sc.isSuccess():
1166 self._msg.error("Failed to start AppMgr")
1169 if (self._debugStage.value=="exec"):
1173 if self.interactive == 'run':
1174 printInteractiveMsg_run()
1175 from AthenaPython.PyAthena import py_svc
1176 sg=py_svc("StoreGateSvc/StoreGateSvc")
1177 startInteractive(locals())
1179 sc = app.run(maxEvents)
1180 if not sc.isSuccess():
1181 self._msg.error("Failure running application")
1185 if not scStop.isSuccess():
1186 self._msg.error("Failed to stop AppMgr")
1189 if (self._debugStage.value == "fini"):
1192 scFin=app.finalize()
1193 if not scFin.isSuccess():
1194 self._msg.error("Failed to finalize AppMgr")
1197 sc1 = app.terminate()
1200 def foreach_component(self, path):
1201 """Utility to set properties of components using wildcards.
1204 ca.foreach_component("*/HLTTop/*/*Hypo*").OutputLevel = VERBOSE
1206 The components name and location in the CF tree are translated into a UNIX-like path
1207 and are matched using the `fnmatch` library. If the property is set successfully
1208 an INFO message is printed else a WARNING.
1210 The convention for paths of nested components is as follows:
1211 Sequence : only the name is used in the path
1212 Algorithm : "type/name" is used
1213 Private Tool : ToolHandle property name plus "type/name" is used
1214 Public Tool : located under "ToolSvc/" and "type/name" is used
1215 Service : located under "SvcMgr/" and "type/name" is used
1217 from AthenaConfiguration.PropSetterProxy import PropSetterProxy
1218 return PropSetterProxy(self, path)