10 __version__ =
"$Revision: 795362 $"
11 __author__ =
"Will Buttinger"
12 __doc__ =
"streamline and ease the creation of new AthAnalysisAlgorithm"
18 import PyUtils.acmdlib
as acmdlib
22 #Skeleton joboption for a simple analysis job
24 #---- Minimal job options -----
26 jps.AthenaCommonFlags.AccessMode = "ClassAccess" #Choose from TreeAccess,BranchAccess,ClassAccess,AthenaAccess,POOLAccess
27 #jps.AthenaCommonFlags.TreeName = "MyTree" #when using TreeAccess, must specify the input tree name
29 jps.AthenaCommonFlags.HistOutputs = ["MYSTREAM:myfile.root"] #register output files like this. MYSTREAM is used in the code
31 athAlgSeq += CfgMgr.%(klass)s() #adds an instance of your alg to the main alg sequence
34 #---- Options you could specify on command line -----
35 #jps.AthenaCommonFlags.EvtMax=-1 #set on command-line with: --evtMax=-1
36 #jps.AthenaCommonFlags.SkipEvents=0 #set on command-line with: --skipEvents=0
37 #jps.AthenaCommonFlags.FilesInput = ["%(inFile)s"] #set on command-line with: --filesInput=...
40 include("AthAnalysisBaseComps/SuppressLogging.py") #Optional include to suppress as much athena output as possible. Keep at bottom of joboptions so that it doesn't suppress the logging of the things you have configured above
44 script_template =
"""\
47 # Run this application/script like this:
48 # run%(klass)s.py --filesInput file.root --evtMax 100
49 # See --help for more arguments and flag options
51 from AthenaConfiguration.AllConfigFlags import initConfigFlags
52 flags = initConfigFlags()
53 flags._parser = flags.getArgumentParser(description=\"\"\"My Demo Application\"\"\") # an argparse.ArgumentParser
54 flags.parser().add_argument('--accessMode',default="POOLAccess", # can add arguments to the parser as usual
55 choices={"POOLAccess","ClassAccess"},help="Input file reading mode (ClassAccess can be faster but is less supported)")
56 # changes to default flag values (done before fillFromArgs so appears in the --help flag system
57 flags.Exec.PrintAlgsSequence = True # displays algsequence at start of job
60 args = flags.fillFromArgs() # parse command line arguments
61 flags.lock() # lock the flags
64 # configure main services and input file reading
65 from AthenaConfiguration.MainServicesConfig import MainServicesCfg
66 from AthenaConfiguration.Enums import Format
67 cfg = MainServicesCfg(flags)
68 if flags.Input.Format is Format.BS:
69 # read RAW (bytestream)
70 from ByteStreamCnvSvc.ByteStreamConfig import ByteStreamReadCfg
71 cfg.merge(ByteStreamReadCfg(flags))
73 # reading POOL, use argument to decide which read mode
74 if flags.args().accessMode == "POOLAccess":
75 from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
76 cfg.merge(PoolReadCfg(flags))
78 from AthenaRootComps.xAODEventSelectorConfig import xAODReadCfg,xAODAccessMode
79 cfg.merge(xAODReadCfg(flags, AccessMode = xAODAccessMode.CLASS_ACCESS))
81 # configure output ROOT files from Output.HISTOutputs flag (should be of form: "STREAMNAME:file.root")
82 from AthenaConfiguration.ComponentFactory import CompFactory
83 if flags.Output.HISTFileName != "":
85 for file in (flags.Output.HISTFileName if type(flags.Output.HISTFileName)==list else flags.Output.HISTFileName.split(",")):
86 streamName = file.split(":")[0] if ":" in file else "ANALYSIS"
87 fileName = file.split(":")[1] if ":" in file else file
88 outputs += ["{} DATAFILE='{}' OPT='RECREATE'".format(streamName,fileName)]
89 cfg.addService(CompFactory.THistSvc(Output = outputs))
92 cfg.addEventAlgo(CompFactory.%(klass)s(),sequenceName="AthAlgSeq")
95 # final cfg tweaks before launching:
96 if cfg.getAppProps()["EventLoop"]=="AthenaEventLoopMgr":
97 cfg.getService("AthenaEventLoopMgr").IntervalInSeconds = 5 # enable processing rate reporting every 5s
98 # suppress logging from some core services that we usually don't care about hearing from
99 cfg.getService("MessageSvc").setWarning += ["ClassIDSvc","PoolSvc","AthDictLoaderSvc","AthenaPoolAddressProviderSvc",
100 "ProxyProviderSvc","DBReplicaSvc","MetaDataSvc","MetaDataStore","AthenaPoolCnvSvc",
101 "TagMetaDataStore","EventSelector","CoreDumpSvc","AthMasterSeq","EventPersistencySvc",
102 "ActiveStoreSvc","AthOutSeq","AthRegSeq","FPEAuditor"]
105 if cfg.run().isFailure():
109 alg_hdr_template =
"""\
113 #include "AthAnalysisBaseComps/AthAnalysisAlgorithm.h"
115 //Example ROOT Includes
121 class %(klass)s: public ::AthAnalysisAlgorithm {
123 %(klass)s( const std::string& name, ISvcLocator* pSvcLocator );
124 virtual ~%(klass)s();
126 ///uncomment and implement methods as required
129 virtual StatusCode initialize(); //once, before any input is loaded
130 virtual StatusCode beginInputFile(); //start of each input file, only metadata loaded
131 //virtual StatusCode firstExecute(); //once, after first eventdata is loaded (not per file)
132 virtual StatusCode execute(); //per event
133 //virtual StatusCode endInputFile(); //end of each input file
134 //virtual StatusCode metaDataStop(); //when outputMetaStore is populated by MetaDataTools
135 virtual StatusCode finalize(); //once, after all events processed
138 ///Other useful methods provided by base class are:
139 ///evtStore() : ServiceHandle to main event data storegate
140 ///inputMetaStore() : ServiceHandle to input metadata storegate
141 ///outputMetaStore() : ServiceHandle to output metadata storegate
142 ///histSvc() : ServiceHandle to output ROOT service (writing TObjects)
143 ///currentFile() : TFile* to the currently open input file
144 ///retrieveMetadata(...): See twiki.cern.ch/twiki/bin/view/AtlasProtected/AthAnalysisBase#ReadingMetaDataInCpp
149 //Example algorithm property, see constructor for declaration:
150 //int m_nProperty = 0;
152 //Example histogram, see initialize method for registration to output histSvc
153 //TH1D* m_myHist = 0;
154 //TTree* m_myTree = 0;
158 #endif //> !%(guard)s
161 alg_cxx_template =
"""\
163 #include "%(namespace_klass)s.h"
165 //#include "xAODEventInfo/EventInfo.h"
170 %(klass)s::%(klass)s( const std::string& name, ISvcLocator* pSvcLocator ) : AthAnalysisAlgorithm( name, pSvcLocator ){
172 //declareProperty( "Property", m_nProperty = 0, "My Example Integer Property" ); //example property declaration
177 %(klass)s::~%(klass)s() {}
180 StatusCode %(klass)s::initialize() {
181 ATH_MSG_INFO ("Initializing " << name() << "...");
183 //This is called once, before the start of the event loop
184 //Retrieves of tools you have configured in the joboptions go here
188 //We will create a histogram and a ttree and register them to the histsvc
189 //Remember to configure the histsvc stream in the joboptions
191 //m_myHist = new TH1D("myHist","myHist",100,0,100);
192 //CHECK( histSvc()->regHist("/MYSTREAM/myHist", m_myHist) ); //registers histogram to output stream
193 //m_myTree = new TTree("myTree","myTree");
194 //CHECK( histSvc()->regTree("/MYSTREAM/SubDirectory/myTree", m_myTree) ); //registers tree to output stream inside a sub-directory
197 return StatusCode::SUCCESS;
200 StatusCode %(klass)s::finalize() {
201 ATH_MSG_INFO ("Finalizing " << name() << "...");
203 //Things that happen once at the end of the event loop go here
207 return StatusCode::SUCCESS;
210 StatusCode %(klass)s::execute() {
211 ATH_MSG_DEBUG ("Executing " << name() << "...");
212 setFilterPassed(false); //optional: start with algorithm not passed
217 //Your main analysis code goes here
218 //If you will use this algorithm to perform event skimming, you
219 //should ensure the setFilterPassed method is called
220 //If never called, the algorithm is assumed to have 'passed' by default
225 //const xAOD::EventInfo* ei = 0;
226 //CHECK( evtStore()->retrieve( ei , "EventInfo" ) );
227 //ATH_MSG_INFO("eventNumber=" << ei->eventNumber() );
228 //m_myHist->Fill( ei->averageInteractionsPerCrossing() ); //fill mu into histogram
231 setFilterPassed(true); //if got here, assume that means algorithm passed
232 return StatusCode::SUCCESS;
235 StatusCode %(klass)s::beginInputFile() {
237 //This method is called at the start of each input file, even if
238 //the input file contains no events. Accumulate metadata information here
241 //example of retrieval of CutBookkeepers: (remember you will need to include the necessary header files and use statements in requirements file)
242 // const xAOD::CutBookkeeperContainer* bks = 0;
243 // CHECK( inputMetaStore()->retrieve(bks, "CutBookkeepers") );
245 //example of IOVMetaData retrieval (see https://twiki.cern.ch/twiki/bin/viewauth/AtlasProtected/AthAnalysisBase#How_to_access_file_metadata_in_C)
246 //float beamEnergy(0); CHECK( retrieveMetadata("/TagInfo","beam_energy",beamEnergy) );
247 //std::vector<float> bunchPattern; CHECK( retrieveMetadata("/Digitiation/Parameters","BeamIntensityPattern",bunchPattern) );
251 return StatusCode::SUCCESS;
256 testxml_template =
"""\
257 <TEST name="%(namespace_klass)s" type="athena" suite="ASGTests">
258 <options_atn>%(pkg)s/%(namespace_klass)sJobOptions.py</options_atn>
259 <timelimit>5</timelimit>
260 <author> PLEASE ENTER A NAME </author>
261 <mailto> PLEASEENTER@cern.ch </mailto>
263 <errorMessage> Athena exited abnormally </errorMessage>
264 <errorMessage>FAILURE (ERROR)</errorMessage>
265 <returnValue>0</returnValue>
273 name=
'cmake.new-analysisalg'
277 help=
"name of the new alg"
283 help=
'Create a skeleton joboption for execution of the new algorithm'
287 """create a new AthAnalysisAlgorithm inside the current package. Call from within the package directory
290 $ acmd cmake new-analysisalg MyAlg
294 full_alg_name = args.algname
299 if not os.path.isdir(cwd+
"/src")
or not os.path.isfile(cwd+
"/CMakeLists.txt"):
300 print(
"ERROR you must call new-analysisalg from within the package you want to add the algorithm to")
304 full_pkg_name = os.path.basename(cwd)
305 print(textwrap.dedent(
"""\
306 ::: create alg [%(full_alg_name)s] in pkg [%(full_pkg_name)s]""" %locals()))
311 hasxAODEventInfo=
False
317 hasComponentLine=
False
318 for line
in open(
'CMakeLists.txt'):
320 if "atlas_add_library" in line: hasLibraryLine=
True
321 if "atlas_add_component" in line: hasComponentLine=
True
330 hdr = Templates.alg_hdr_template
331 cxx = Templates.alg_cxx_template
333 namespace_klass = full_alg_name.replace(
'::',
'__')
334 namespace_begin,namespace_end =
"",
""
336 if full_alg_name.count(
"::")>0:
337 namespace = full_alg_name.split(
"::")[0]
338 full_alg_name = full_alg_name.split(
"::")[1]
339 namespace_begin =
"namespace %s {" % namespace
340 namespace_end =
"} //> end namespace %s" % namespace
343 guard =
"%s_%s_H" % (full_pkg_name.upper(), namespace_klass.upper())
345 d = dict( pkg=full_pkg_name,
348 namespace_begin=namespace_begin,
349 namespace_end=namespace_end,namespace_klass=namespace_klass,namespace=namespace
351 fname = os.path.splitext(
"src/%s"%namespace_klass)[0]
353 if os.path.isfile(fname+
'.h'):
354 print(
"::: ERROR %s.h already exists" % fname)
356 print(
"::: INFO Creating %s.h" % fname)
357 o_hdr =
open(fname+
'.h',
'w')
358 o_hdr.writelines(hdr%d)
362 if os.path.isfile(fname+
'.cxx'):
363 print(
"::: ERROR %s.cxx already exists" % fname)
365 print(
"::: INFO Creating %s.cxx" % fname)
366 o_cxx =
open(fname+
'.cxx',
'w')
367 o_cxx.writelines(cxx%d)
374 if not os.path.exists(
"src/components"): os.mkdir(
"src/components")
375 if not os.path.isfile(
"src/components/%s_entries.cxx"%full_pkg_name):
376 print(
"::: INFO Creating src/components/%s_entries.cxx"%full_pkg_name)
377 loadFile =
open(
"src/components/%s_entries.cxx"%full_pkg_name,
'w')
378 if len(namespace_begin)>0:
379 d[
"namespace"] = args.algname.split(
"::")[0]
380 loadFile.writelines(
"""
381 #include "../%(namespace_klass)s.h"
382 DECLARE_COMPONENT(%(namespace)s::%(klass)s )
385 loadFile.writelines(
"""
386 #include "../%(namespace_klass)s.h"
387 DECLARE_COMPONENT( %(klass)s )
394 for line
in open(
"src/components/%s_entries.cxx"%full_pkg_name):
395 if len(namespace_begin)==0
and "DECLARE_COMPONENT" in line
and d[
"klass"]
in line: inFile=
True
396 if len(namespace_begin)>0
and "DECLARE_COMPONENT" in line
and d[
"klass"]
in line
and d[
"namespace"]: inFile=
True
399 print(
"::: INFO Adding %s to src/components/%s_entries.cxx"% (args.algname,full_pkg_name))
401 with open(
"src/components/%s_entries.cxx"%full_pkg_name,
"a")
as f:
402 if len(namespace_begin)>0:
403 f.write(
""" DECLARE_COMPONENT(%(namespace)s::%(klass)s );"""%d)
405 f.write(
""" DECLARE_COMPONENT( %(klass)s );"""%d)
410 full_jobo_name = namespace_klass +
"JobOptions"
411 full_script_name =
"run" + namespace_klass
412 full_alg_name = namespace_klass
414 print(textwrap.dedent(
"""\
415 ::: create jobo [%(full_jobo_name)s] and script [%(full_script_name)s] for alg [%(full_alg_name)s]""" %locals()))
418 jobo = Templates.jobo_template
420 e = dict( klass=full_alg_name,
421 inFile=os.environ[
'ASG_TEST_FILE_MC'],
423 fname =
'share/%s.py' % full_jobo_name
425 if os.path.isfile(fname):
426 print(
"::: WARNING %s already exists .. will not overwrite" % fname)
428 o_hdr =
open(fname,
'w')
429 o_hdr.writelines(jobo%e)
433 scripto = Templates.script_template
435 e = dict( klass=full_alg_name,
436 inFile=os.environ[
'ASG_TEST_FILE_MC'],
438 fname =
'scripts/%s.py' % full_script_name
440 if os.path.isfile(fname):
441 print(
"::: WARNING %s already exists .. will not overwrite" % fname)
443 o_hdr =
open(fname,
'w')
444 o_hdr.writelines(scripto%e)
447 os.chmod(fname, 0o755)
451 workDir = os.environ.get(
"WorkDir_DIR")
453 print(
"::: ERROR No WorkDir_DIR env var, did you forget to source the setup.sh script?")
454 print(
"::: ERROR Please do this and reconfigure cmake manually!")
456 print(
"::: INFO Reconfiguring cmake %s/../." % workDir)
457 res = subprocess.getstatusoutput(
'cmake %s/../.' % workDir)
459 print(
"::: WARNING reconfigure unsuccessful. Please reconfigure manually!")
462 print(
"::: INFO Please ensure your CMakeLists.txt file has ")
463 print(
"::: atlas_add_component( %s src/component/*.cxx ... )" % full_pkg_name)
464 print(
"::: INFO and necessary dependencies declared ")
465 print(
"::: INFO Minimum dependency is: Control/AthAnalysisBaseComps")