10 from __future__
import with_statement
12 __version__ =
"$Revision: 795362 $"
13 __author__ =
"Will Buttinger"
14 __doc__ =
"streamline and ease the creation of new AthAnalysisAlgorithm"
20 import PyUtils.acmdlib
as acmdlib
24 #Skeleton joboption for a simple analysis job
26 #---- Minimal job options -----
28 jps.AthenaCommonFlags.AccessMode = "ClassAccess" #Choose from TreeAccess,BranchAccess,ClassAccess,AthenaAccess,POOLAccess
29 #jps.AthenaCommonFlags.TreeName = "MyTree" #when using TreeAccess, must specify the input tree name
31 jps.AthenaCommonFlags.HistOutputs = ["MYSTREAM:myfile.root"] #register output files like this. MYSTREAM is used in the code
33 athAlgSeq += CfgMgr.%(klass)s() #adds an instance of your alg to the main alg sequence
36 #---- Options you could specify on command line -----
37 #jps.AthenaCommonFlags.EvtMax=-1 #set on command-line with: --evtMax=-1
38 #jps.AthenaCommonFlags.SkipEvents=0 #set on command-line with: --skipEvents=0
39 #jps.AthenaCommonFlags.FilesInput = ["%(inFile)s"] #set on command-line with: --filesInput=...
42 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
46 script_template =
"""\
49 # Run this application/script like this:
50 # run%(klass)s.py --filesInput file.root --evtMax 100
51 # See --help for more arguments and flag options
53 from AthenaConfiguration.AllConfigFlags import initConfigFlags
54 flags = initConfigFlags()
55 flags._parser = flags.getArgumentParser(description=\"\"\"My Demo Application\"\"\") # an argparse.ArgumentParser
56 flags.parser().add_argument('--accessMode',default="POOLAccess", # can add arguments to the parser as usual
57 choices={"POOLAccess","ClassAccess"},help="Input file reading mode (ClassAccess can be faster but is less supported)")
58 # changes to default flag values (done before fillFromArgs so appears in the --help flag system
59 flags.Exec.PrintAlgsSequence = True # displays algsequence at start of job
62 args = flags.fillFromArgs() # parse command line arguments
63 flags.lock() # lock the flags
66 # configure main services and input file reading
67 from AthenaConfiguration.MainServicesConfig import MainServicesCfg
68 from AthenaConfiguration.Enums import Format
69 cfg = MainServicesCfg(flags)
70 if flags.Input.Format is Format.BS:
71 # read RAW (bytestream)
72 from ByteStreamCnvSvc.ByteStreamConfig import ByteStreamReadCfg
73 cfg.merge(ByteStreamReadCfg(flags))
75 # reading POOL, use argument to decide which read mode
76 if flags.args().accessMode == "POOLAccess":
77 from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
78 cfg.merge(PoolReadCfg(flags))
80 from AthenaRootComps.xAODEventSelectorConfig import xAODReadCfg,xAODAccessMode
81 cfg.merge(xAODReadCfg(flags, AccessMode = xAODAccessMode.CLASS_ACCESS))
83 # configure output ROOT files from Output.HISTOutputs flag (should be of form: "STREAMNAME:file.root")
84 from AthenaConfiguration.ComponentFactory import CompFactory
85 if flags.Output.HISTFileName != "":
87 for file in (flags.Output.HISTFileName if type(flags.Output.HISTFileName)==list else flags.Output.HISTFileName.split(",")):
88 streamName = file.split(":")[0] if ":" in file else "ANALYSIS"
89 fileName = file.split(":")[1] if ":" in file else file
90 outputs += ["{} DATAFILE='{}' OPT='RECREATE'".format(streamName,fileName)]
91 cfg.addService(CompFactory.THistSvc(Output = outputs))
94 cfg.addEventAlgo(CompFactory.%(klass)s(),sequenceName="AthAlgSeq")
97 # final cfg tweaks before launching:
98 cfg.getService("AthenaEventLoopMgr").IntervalInSeconds = 5 # enable processing rate reporting every 5s
99 # suppress logging from some core services that we usually don't care about hearing from
100 cfg.getService("MessageSvc").setWarning += ["ClassIDSvc","PoolSvc","AthDictLoaderSvc","AthenaPoolAddressProviderSvc",
101 "ProxyProviderSvc","DBReplicaSvc","MetaDataSvc","MetaDataStore","AthenaPoolCnvSvc",
102 "TagMetaDataStore","EventSelector","CoreDumpSvc","AthMasterSeq","EventPersistencySvc",
103 "ActiveStoreSvc","AthOutSeq","AthRegSeq","FPEAuditor"]
106 if cfg.run().isFailure():
111 alg_hdr_template =
"""\
115 #include "AthAnalysisBaseComps/AthAnalysisAlgorithm.h"
117 //Example ROOT Includes
123 class %(klass)s: public ::AthAnalysisAlgorithm {
125 %(klass)s( const std::string& name, ISvcLocator* pSvcLocator );
126 virtual ~%(klass)s();
128 ///uncomment and implement methods as required
131 virtual StatusCode initialize(); //once, before any input is loaded
132 virtual StatusCode beginInputFile(); //start of each input file, only metadata loaded
133 //virtual StatusCode firstExecute(); //once, after first eventdata is loaded (not per file)
134 virtual StatusCode execute(); //per event
135 //virtual StatusCode endInputFile(); //end of each input file
136 //virtual StatusCode metaDataStop(); //when outputMetaStore is populated by MetaDataTools
137 virtual StatusCode finalize(); //once, after all events processed
140 ///Other useful methods provided by base class are:
141 ///evtStore() : ServiceHandle to main event data storegate
142 ///inputMetaStore() : ServiceHandle to input metadata storegate
143 ///outputMetaStore() : ServiceHandle to output metadata storegate
144 ///histSvc() : ServiceHandle to output ROOT service (writing TObjects)
145 ///currentFile() : TFile* to the currently open input file
146 ///retrieveMetadata(...): See twiki.cern.ch/twiki/bin/view/AtlasProtected/AthAnalysisBase#ReadingMetaDataInCpp
151 //Example algorithm property, see constructor for declaration:
152 //int m_nProperty = 0;
154 //Example histogram, see initialize method for registration to output histSvc
155 //TH1D* m_myHist = 0;
156 //TTree* m_myTree = 0;
160 #endif //> !%(guard)s
163 alg_cxx_template =
"""\
165 #include "%(namespace_klass)s.h"
167 //#include "xAODEventInfo/EventInfo.h"
172 %(klass)s::%(klass)s( const std::string& name, ISvcLocator* pSvcLocator ) : AthAnalysisAlgorithm( name, pSvcLocator ){
174 //declareProperty( "Property", m_nProperty = 0, "My Example Integer Property" ); //example property declaration
179 %(klass)s::~%(klass)s() {}
182 StatusCode %(klass)s::initialize() {
183 ATH_MSG_INFO ("Initializing " << name() << "...");
185 //This is called once, before the start of the event loop
186 //Retrieves of tools you have configured in the joboptions go here
190 //We will create a histogram and a ttree and register them to the histsvc
191 //Remember to configure the histsvc stream in the joboptions
193 //m_myHist = new TH1D("myHist","myHist",100,0,100);
194 //CHECK( histSvc()->regHist("/MYSTREAM/myHist", m_myHist) ); //registers histogram to output stream
195 //m_myTree = new TTree("myTree","myTree");
196 //CHECK( histSvc()->regTree("/MYSTREAM/SubDirectory/myTree", m_myTree) ); //registers tree to output stream inside a sub-directory
199 return StatusCode::SUCCESS;
202 StatusCode %(klass)s::finalize() {
203 ATH_MSG_INFO ("Finalizing " << name() << "...");
205 //Things that happen once at the end of the event loop go here
209 return StatusCode::SUCCESS;
212 StatusCode %(klass)s::execute() {
213 ATH_MSG_DEBUG ("Executing " << name() << "...");
214 setFilterPassed(false); //optional: start with algorithm not passed
219 //Your main analysis code goes here
220 //If you will use this algorithm to perform event skimming, you
221 //should ensure the setFilterPassed method is called
222 //If never called, the algorithm is assumed to have 'passed' by default
227 //const xAOD::EventInfo* ei = 0;
228 //CHECK( evtStore()->retrieve( ei , "EventInfo" ) );
229 //ATH_MSG_INFO("eventNumber=" << ei->eventNumber() );
230 //m_myHist->Fill( ei->averageInteractionsPerCrossing() ); //fill mu into histogram
233 setFilterPassed(true); //if got here, assume that means algorithm passed
234 return StatusCode::SUCCESS;
237 StatusCode %(klass)s::beginInputFile() {
239 //This method is called at the start of each input file, even if
240 //the input file contains no events. Accumulate metadata information here
243 //example of retrieval of CutBookkeepers: (remember you will need to include the necessary header files and use statements in requirements file)
244 // const xAOD::CutBookkeeperContainer* bks = 0;
245 // CHECK( inputMetaStore()->retrieve(bks, "CutBookkeepers") );
247 //example of IOVMetaData retrieval (see https://twiki.cern.ch/twiki/bin/viewauth/AtlasProtected/AthAnalysisBase#How_to_access_file_metadata_in_C)
248 //float beamEnergy(0); CHECK( retrieveMetadata("/TagInfo","beam_energy",beamEnergy) );
249 //std::vector<float> bunchPattern; CHECK( retrieveMetadata("/Digitiation/Parameters","BeamIntensityPattern",bunchPattern) );
253 return StatusCode::SUCCESS;
258 testxml_template =
"""\
259 <TEST name="%(namespace_klass)s" type="athena" suite="ASGTests">
260 <options_atn>%(pkg)s/%(namespace_klass)sJobOptions.py</options_atn>
261 <timelimit>5</timelimit>
262 <author> PLEASE ENTER A NAME </author>
263 <mailto> PLEASEENTER@cern.ch </mailto>
265 <errorMessage> Athena exited abnormally </errorMessage>
266 <errorMessage>FAILURE (ERROR)</errorMessage>
267 <returnValue>0</returnValue>
275 name=
'cmake.new-analysisalg'
279 help=
"name of the new alg"
285 help=
'Create a skeleton joboption for execution of the new algorithm'
289 """create a new AthAnalysisAlgorithm inside the current package. Call from within the package directory
292 $ acmd cmake new-analysisalg MyAlg
296 full_alg_name = args.algname
301 if not os.path.isdir(cwd+
"/src")
or not os.path.isfile(cwd+
"/CMakeLists.txt"):
302 print(
"ERROR you must call new-analysisalg from within the package you want to add the algorithm to")
306 full_pkg_name = os.path.basename(cwd)
307 print(textwrap.dedent(
"""\
308 ::: create alg [%(full_alg_name)s] in pkg [%(full_pkg_name)s]""" %locals()))
313 hasxAODEventInfo=
False
319 hasComponentLine=
False
320 for line
in open(
'CMakeLists.txt'):
322 if "atlas_add_library" in line: hasLibraryLine=
True
323 if "atlas_add_component" in line: hasComponentLine=
True
332 hdr = Templates.alg_hdr_template
333 cxx = Templates.alg_cxx_template
335 namespace_klass = full_alg_name.replace(
'::',
'__')
336 namespace_begin,namespace_end =
"",
""
338 if full_alg_name.count(
"::")>0:
339 namespace = full_alg_name.split(
"::")[0]
340 full_alg_name = full_alg_name.split(
"::")[1]
341 namespace_begin =
"namespace %s {" % namespace
342 namespace_end =
"} //> end namespace %s" % namespace
345 guard =
"%s_%s_H" % (full_pkg_name.upper(), namespace_klass.upper())
347 d = dict( pkg=full_pkg_name,
350 namespace_begin=namespace_begin,
351 namespace_end=namespace_end,namespace_klass=namespace_klass,namespace=namespace
353 fname = os.path.splitext(
"src/%s"%namespace_klass)[0]
355 if os.path.isfile(fname+
'.h'):
356 print(
"::: ERROR %s.h already exists" % fname)
358 print(
"::: INFO Creating %s.h" % fname)
359 o_hdr =
open(fname+
'.h',
'w')
360 o_hdr.writelines(hdr%d)
364 if os.path.isfile(fname+
'.cxx'):
365 print(
"::: ERROR %s.cxx already exists" % fname)
367 print(
"::: INFO Creating %s.cxx" % fname)
368 o_cxx =
open(fname+
'.cxx',
'w')
369 o_cxx.writelines(cxx%d)
376 if not os.path.exists(
"src/components"): os.mkdir(
"src/components")
377 if not os.path.isfile(
"src/components/%s_entries.cxx"%full_pkg_name):
378 print(
"::: INFO Creating src/components/%s_entries.cxx"%full_pkg_name)
379 loadFile =
open(
"src/components/%s_entries.cxx"%full_pkg_name,
'w')
380 if len(namespace_begin)>0:
381 d[
"namespace"] = args.algname.split(
"::")[0]
382 loadFile.writelines(
"""
383 #include "../%(namespace_klass)s.h"
384 DECLARE_COMPONENT(%(namespace)s::%(klass)s )
387 loadFile.writelines(
"""
388 #include "../%(namespace_klass)s.h"
389 DECLARE_COMPONENT( %(klass)s )
396 for line
in open(
"src/components/%s_entries.cxx"%full_pkg_name):
397 if len(namespace_begin)==0
and "DECLARE_COMPONENT" in line
and d[
"klass"]
in line: inFile=
True
398 if len(namespace_begin)>0
and "DECLARE_COMPONENT" in line
and d[
"klass"]
in line
and d[
"namespace"]: inFile=
True
401 print(
"::: INFO Adding %s to src/components/%s_entries.cxx"% (args.algname,full_pkg_name))
403 with open(
"src/components/%s_entries.cxx"%full_pkg_name,
"a")
as f:
404 if len(namespace_begin)>0:
405 f.write(
""" DECLARE_COMPONENT(%(namespace)s::%(klass)s );"""%d)
407 f.write(
""" DECLARE_COMPONENT( %(klass)s );"""%d)
412 full_jobo_name = namespace_klass +
"JobOptions"
413 full_script_name =
"run" + namespace_klass
414 full_alg_name = namespace_klass
416 print(textwrap.dedent(
"""\
417 ::: create jobo [%(full_jobo_name)s] and script [%(full_script_name)s] for alg [%(full_alg_name)s]""" %locals()))
420 jobo = Templates.jobo_template
422 e = dict( klass=full_alg_name,
423 inFile=os.environ[
'ASG_TEST_FILE_MC'],
425 fname =
'share/%s.py' % full_jobo_name
427 if os.path.isfile(fname):
428 print(
"::: WARNING %s already exists .. will not overwrite" % fname)
430 o_hdr =
open(fname,
'w')
431 o_hdr.writelines(jobo%e)
435 scripto = Templates.script_template
437 e = dict( klass=full_alg_name,
438 inFile=os.environ[
'ASG_TEST_FILE_MC'],
440 fname =
'scripts/%s.py' % full_script_name
442 if os.path.isfile(fname):
443 print(
"::: WARNING %s already exists .. will not overwrite" % fname)
445 o_hdr =
open(fname,
'w')
446 o_hdr.writelines(scripto%e)
449 os.chmod(fname, 0o755)
453 workDir = os.environ.get(
"WorkDir_DIR")
455 print(
"::: ERROR No WorkDir_DIR env var, did you forget to source the setup.sh script?")
456 print(
"::: ERROR Please do this and reconfigure cmake manually!")
458 print(
"::: INFO Reconfiguring cmake %s/../." % workDir)
459 res = subprocess.getstatusoutput(
'cmake %s/../.' % workDir)
461 print(
"::: WARNING reconfigure unsuccessful. Please reconfigure manually!")
464 print(
"::: INFO Please ensure your CMakeLists.txt file has ")
465 print(
"::: atlas_add_component( %s src/component/*.cxx ... )" % full_pkg_name)
466 print(
"::: INFO and necessary dependencies declared ")
467 print(
"::: INFO Minimum dependency is: Control/AthAnalysisBaseComps")