ATLAS Offline Software
Toggle main menu visibility
Loading...
Searching...
No Matches
Tools
PyUtils
python
scripts
cmake_newanalysisalg.py
Go to the documentation of this file.
1
# Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
2
3
# @file PyUtils.scripts.cmt_newanalysisalg
4
# @purpose streamline and ease the creation of new athena algs
5
# @author Will Buttinger
6
# @date February 2017
7
8
#Note - this code could use a serious rewrite, I just hacked it together to get something working
9
10
__author__ =
"Will Buttinger"
11
__doc__ =
"streamline and ease the creation of new AthAnalysisAlgorithm"
12
13
14
import
os
15
import
textwrap
16
import
subprocess
17
import
PyUtils.acmdlib
as
acmdlib
18
19
class
Templates
:
20
21
script_template =
"""\
22
#!/usr/bin/env athena
23
24
# Run this application/script like this:
25
# run%(klass)s.py --filesInput file.root --evtMax 100
26
# See --help for more arguments and flag options
27
28
from AthenaConfiguration.AllConfigFlags import initConfigFlags
29
flags = initConfigFlags()
30
flags._parser = flags.getArgumentParser(description=\"\"\"My Demo Application\"\"\") # an argparse.ArgumentParser
31
flags.parser().add_argument('--accessMode',default="POOLAccess", # can add arguments to the parser as usual
32
choices={"POOLAccess","ClassAccess"},help="Input file reading mode (ClassAccess can be faster but is less supported)")
33
# changes to default flag values (done before fillFromArgs so appears in the --help flag system
34
flags.Exec.PrintAlgsSequence = True # displays algsequence at start of job
35
36
37
args = flags.fillFromArgs() # parse command line arguments
38
flags.lock() # lock the flags
39
40
41
# configure main services and input file reading
42
from AthenaConfiguration.MainServicesConfig import MainServicesCfg
43
from AthenaConfiguration.Enums import Format
44
cfg = MainServicesCfg(flags)
45
if flags.Input.Format is Format.BS:
46
# read RAW (bytestream)
47
from ByteStreamCnvSvc.ByteStreamConfig import ByteStreamReadCfg
48
cfg.merge(ByteStreamReadCfg(flags))
49
else:
50
# reading POOL, use argument to decide which read mode
51
if flags.args().accessMode == "POOLAccess":
52
from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
53
cfg.merge(PoolReadCfg(flags))
54
else:
55
from AthenaRootComps.xAODEventSelectorConfig import xAODReadCfg,xAODAccessMode
56
cfg.merge(xAODReadCfg(flags, AccessMode = xAODAccessMode.CLASS_ACCESS))
57
58
# configure output ROOT files from Output.HISTOutputs flag (should be of form: "STREAMNAME:file.root")
59
from AthenaConfiguration.ComponentFactory import CompFactory
60
if flags.Output.HISTFileName != "":
61
outputs = []
62
for file in (flags.Output.HISTFileName if type(flags.Output.HISTFileName)==list else flags.Output.HISTFileName.split(",")):
63
streamName = file.split(":")[0] if ":" in file else "ANALYSIS"
64
fileName = file.split(":")[1] if ":" in file else file
65
outputs += ["{} DATAFILE='{}' OPT='RECREATE'".format(streamName,fileName)]
66
cfg.addService(CompFactory.THistSvc(Output = outputs))
67
68
# add our algorithm
69
cfg.addEventAlgo(CompFactory.%(klass)s(),sequenceName="AthAlgSeq")
70
71
72
# final cfg tweaks before launching:
73
if cfg.getAppProps()["EventLoop"]=="AthenaEventLoopMgr":
74
cfg.getService("AthenaEventLoopMgr").IntervalInSeconds = 5 # enable processing rate reporting every 5s
75
# suppress logging from some core services that we usually don't care about hearing from
76
cfg.getService("MessageSvc").setWarning += ["ClassIDSvc","PoolSvc","AthDictLoaderSvc","AthenaPoolAddressProviderSvc",
77
"ProxyProviderSvc","DBReplicaSvc","MetaDataSvc","MetaDataStore","AthenaPoolCnvSvc",
78
"TagMetaDataStore","EventSelector","CoreDumpSvc","AthMasterSeq","EventPersistencySvc",
79
"ActiveStoreSvc","AthOutSeq","AthRegSeq","FPEAuditor"]
80
81
# run the job
82
if cfg.run().isFailure():
83
exit(1)
84
"""
85
86
alg_hdr_template =
"""\
87
#ifndef %(guard)s
88
#define %(guard)s 1
89
90
#include "AthAnalysisBaseComps/AthAnalysisAlgorithm.h"
91
92
//Example ROOT Includes
93
//#include "TTree.h"
94
//#include "TH1D.h"
95
96
%(namespace_begin)s
97
98
class %(klass)s: public ::AthAnalysisAlgorithm {
99
public:
100
%(klass)s( const std::string& name, ISvcLocator* pSvcLocator );
101
virtual ~%(klass)s();
102
103
///uncomment and implement methods as required
104
105
//IS EXECUTED:
106
virtual StatusCode initialize(); //once, before any input is loaded
107
virtual StatusCode beginInputFile(); //start of each input file, only metadata loaded
108
//virtual StatusCode firstExecute(); //once, after first eventdata is loaded (not per file)
109
virtual StatusCode execute(); //per event
110
//virtual StatusCode endInputFile(); //end of each input file
111
//virtual StatusCode metaDataStop(); //when outputMetaStore is populated by MetaDataTools
112
virtual StatusCode finalize(); //once, after all events processed
113
114
115
///Other useful methods provided by base class are:
116
///evtStore() : ServiceHandle to main event data storegate
117
///inputMetaStore() : ServiceHandle to input metadata storegate
118
///outputMetaStore() : ServiceHandle to output metadata storegate
119
///histSvc() : ServiceHandle to output ROOT service (writing TObjects)
120
///currentFile() : TFile* to the currently open input file
121
///retrieveMetadata(...): See twiki.cern.ch/twiki/bin/view/AtlasProtected/AthAnalysisBase#ReadingMetaDataInCpp
122
123
124
private:
125
126
//Example algorithm property, see constructor for declaration:
127
//int m_nProperty = 0;
128
129
//Example histogram, see initialize method for registration to output histSvc
130
//TH1D* m_myHist = 0;
131
//TTree* m_myTree = 0;
132
133
};
134
%(namespace_end)s
135
#endif //> !%(guard)s
136
"""
137
138
alg_cxx_template =
"""\
139
// %(pkg)s includes
140
#include "%(namespace_klass)s.h"
141
142
//#include "xAODEventInfo/EventInfo.h"
143
144
145
%(namespace_begin)s
146
147
%(klass)s::%(klass)s( const std::string& name, ISvcLocator* pSvcLocator ) : AthAnalysisAlgorithm( name, pSvcLocator ){
148
149
//declareProperty( "Property", m_nProperty = 0, "My Example Integer Property" ); //example property declaration
150
151
}
152
153
154
%(klass)s::~%(klass)s() {}
155
156
157
StatusCode %(klass)s::initialize() {
158
ATH_MSG_INFO ("Initializing " << name() << "...");
159
//
160
//This is called once, before the start of the event loop
161
//Retrieves of tools you have configured in the joboptions go here
162
//
163
164
//HERE IS AN EXAMPLE
165
//We will create a histogram and a ttree and register them to the histsvc
166
//Remember to configure the histsvc stream in the joboptions
167
//
168
//m_myHist = new TH1D("myHist","myHist",100,0,100);
169
//CHECK( histSvc()->regHist("/MYSTREAM/myHist", m_myHist) ); //registers histogram to output stream
170
//m_myTree = new TTree("myTree","myTree");
171
//CHECK( histSvc()->regTree("/MYSTREAM/SubDirectory/myTree", m_myTree) ); //registers tree to output stream inside a sub-directory
172
173
174
return StatusCode::SUCCESS;
175
}
176
177
StatusCode %(klass)s::finalize() {
178
ATH_MSG_INFO ("Finalizing " << name() << "...");
179
//
180
//Things that happen once at the end of the event loop go here
181
//
182
183
184
return StatusCode::SUCCESS;
185
}
186
187
StatusCode %(klass)s::execute() {
188
ATH_MSG_DEBUG ("Executing " << name() << "...");
189
setFilterPassed(false); //optional: start with algorithm not passed
190
191
192
193
//
194
//Your main analysis code goes here
195
//If you will use this algorithm to perform event skimming, you
196
//should ensure the setFilterPassed method is called
197
//If never called, the algorithm is assumed to have 'passed' by default
198
//
199
200
201
//HERE IS AN EXAMPLE
202
//const xAOD::EventInfo* ei = 0;
203
//CHECK( evtStore()->retrieve( ei , "EventInfo" ) );
204
//ATH_MSG_INFO("eventNumber=" << ei->eventNumber() );
205
//m_myHist->Fill( ei->averageInteractionsPerCrossing() ); //fill mu into histogram
206
207
208
setFilterPassed(true); //if got here, assume that means algorithm passed
209
return StatusCode::SUCCESS;
210
}
211
212
StatusCode %(klass)s::beginInputFile() {
213
//
214
//This method is called at the start of each input file, even if
215
//the input file contains no events. Accumulate metadata information here
216
//
217
218
//example of retrieval of CutBookkeepers: (remember you will need to include the necessary header files and use statements in requirements file)
219
// const xAOD::CutBookkeeperContainer* bks = 0;
220
// CHECK( inputMetaStore()->retrieve(bks, "CutBookkeepers") );
221
222
//example of IOVMetaData retrieval (see https://twiki.cern.ch/twiki/bin/viewauth/AtlasProtected/AthAnalysisBase#How_to_access_file_metadata_in_C)
223
//float beamEnergy(0); CHECK( retrieveMetadata("/TagInfo","beam_energy",beamEnergy) );
224
//std::vector<float> bunchPattern; CHECK( retrieveMetadata("/Digitiation/Parameters","BeamIntensityPattern",bunchPattern) );
225
226
227
228
return StatusCode::SUCCESS;
229
}
230
231
%(namespace_end)s
232
"""
233
234
235
236
@acmdlib.command
(
237
name=
'cmake.new-analysisalg'
238
)
239
@acmdlib.argument
(
240
'algname'
,
241
help=
"name of the new alg"
242
)
243
244
def
main(args):
245
"""create a new AthAnalysisAlgorithm inside the current package. Call from within the package directory
246
247
ex:
248
$ acmd cmake new-analysisalg MyAlg
249
"""
250
sc = 0
251
252
full_alg_name = args.algname
253
254
#determine the package from the cwd
255
cwd = os.getcwd()
256
#check that src dir exists and CMakeLists.txt exists (i.e. this is a package)
257
if
not
os.path.isdir(cwd+
"/src"
)
or
not
os.path.isfile(cwd+
"/CMakeLists.txt"
):
258
print
(
"ERROR you must call new-analysisalg from within the package you want to add the algorithm to"
)
259
return
-1
260
261
262
full_pkg_name = os.path.basename(cwd)
263
print
(textwrap.dedent(
"""\
264
::: create alg [%(full_alg_name)s] in pkg [%(full_pkg_name)s]"""
%locals()))
265
266
267
#first we must check that CMakeLists.txt file has the AthAnalysisBaseComps dependency in it
268
foundBaseComps=
False
269
hasxAODEventInfo=
False
270
hasAtlasROOT=
False
271
hasAsgTools=
False
272
lastUse=0
273
lineCount=0
274
hasLibraryLine=
False
275
hasComponentLine=
False
276
for
line
in
open(
'CMakeLists.txt'
):
277
lineCount +=1
278
if
"atlas_add_library"
in
line: hasLibraryLine=
True
279
if
"atlas_add_component"
in
line: hasComponentLine=
True
280
281
#GOT THIS FAR WITH EDITING
282
283
284
285
286
287
#following code borrowed from gen_klass
288
hdr = Templates.alg_hdr_template
289
cxx = Templates.alg_cxx_template
290
291
namespace_klass = full_alg_name.replace(
'::'
,
'__'
)
292
namespace_begin,namespace_end =
""
,
""
293
namespace =
""
294
if
full_alg_name.count(
"::"
)>0:
295
namespace = full_alg_name.split(
"::"
)[0]
296
full_alg_name = full_alg_name.split(
"::"
)[1]
297
namespace_begin =
"namespace %s {"
% namespace
298
namespace_end =
"} //> end namespace %s"
% namespace
299
pass
300
301
guard =
"%s_%s_H"
% (full_pkg_name.upper(), namespace_klass.upper())
302
303
d = dict( pkg=full_pkg_name,
304
klass=full_alg_name,
305
guard=guard,
306
namespace_begin=namespace_begin,
307
namespace_end=namespace_end,namespace_klass=namespace_klass,namespace=namespace
308
)
309
fname = os.path.splitext(
"src/%s"
%namespace_klass)[0]
310
#first check doesn't exist
311
if
os.path.isfile(fname+
'.h'
):
312
print
(
"::: ERROR %s.h already exists"
% fname)
313
return
-1
314
print
(
"::: INFO Creating %s.h"
% fname)
315
o_hdr = open(fname+
'.h'
,
'w'
)
316
o_hdr.writelines(hdr%d)
317
o_hdr.flush()
318
o_hdr.close()
319
320
if
os.path.isfile(fname+
'.cxx'
):
321
print
(
"::: ERROR %s.cxx already exists"
% fname)
322
return
-1
323
print
(
"::: INFO Creating %s.cxx"
% fname)
324
o_cxx = open(fname+
'.cxx'
,
'w'
)
325
o_cxx.writelines(cxx%d)
326
o_cxx.flush()
327
o_cxx.close()
328
329
330
#now add the algorithm to the _entries.cxx file in the components folder
331
#first check they exist
332
if
not
os.path.exists(
"src/components"
): os.mkdir(
"src/components"
)
333
if
not
os.path.isfile(
"src/components/%s_entries.cxx"
%full_pkg_name):
334
print
(
"::: INFO Creating src/components/%s_entries.cxx"
%full_pkg_name)
335
loadFile = open(
"src/components/%s_entries.cxx"
%full_pkg_name,
'w'
)
336
if
len(namespace_begin)>0:
337
d[
"namespace"
] = args.algname.split(
"::"
)[0]
338
loadFile.writelines(
"""
339
#include "../%(namespace_klass)s.h"
340
DECLARE_COMPONENT(%(namespace)s::%(klass)s )
341
"""
%d)
342
else
:
343
loadFile.writelines(
"""
344
#include "../%(namespace_klass)s.h"
345
DECLARE_COMPONENT( %(klass)s )
346
"""
%d)
347
loadFile.flush()
348
loadFile.close()
349
else
:
350
#first check algorithm not already in _entries file
351
inFile=
False
352
for
line
in
open(
"src/components/%s_entries.cxx"
%full_pkg_name):
353
if
len(namespace_begin)==0
and
"DECLARE_COMPONENT"
in
line
and
d[
"klass"
]
in
line: inFile=
True
354
if
len(namespace_begin)>0
and
"DECLARE_COMPONENT"
in
line
and
d[
"klass"
]
in
line
and
d[
"namespace"
]: inFile=
True
355
356
if
not
inFile:
357
print
(
"::: INFO Adding %s to src/components/%s_entries.cxx"
% (args.algname,full_pkg_name))
358
nextAdd=
True
359
with
open(
"src/components/%s_entries.cxx"
%full_pkg_name,
"a"
)
as
f:
360
if
len(namespace_begin)>0:
361
f.write(
""" DECLARE_COMPONENT(%(namespace)s::%(klass)s );"""
%d)
362
else
:
363
f.write(
""" DECLARE_COMPONENT( %(klass)s );"""
%d)
364
365
366
full_script_name =
"run"
+ namespace_klass
367
full_alg_name = namespace_klass
368
369
print
(textwrap.dedent(
"""\
370
::: create script [%(full_script_name)s] for alg [%(full_alg_name)s]"""
%locals()))
371
372
e = dict( klass=full_alg_name,
373
inFile=os.environ[
'ASG_TEST_FILE_MC'
],
374
)
375
fname =
'scripts/%s.py'
% full_script_name
376
#first check doesn't exist
377
if
os.path.isfile(fname):
378
print
(
"::: WARNING %s already exists .. will not overwrite"
% fname)
379
else
:
380
o_hdr = open(fname,
'w'
)
381
o_hdr.writelines(Templates.script_template % e)
382
o_hdr.flush()
383
o_hdr.close()
384
os.chmod(fname, 0o755)
385
386
# symlink the script as a joboption
387
os.symlink(
'../scripts/%s.py'
% full_script_name,
'share/%sJobOptions.py'
% full_alg_name)
388
389
#need to reconfigure cmake so it knows about the new files
390
#rely on the WorkDir_DIR env var for this
391
workDir = os.environ.get(
"WorkDir_DIR"
)
392
if
workDir
is
None
:
393
print
(
"::: ERROR No WorkDir_DIR env var, did you forget to source the setup.sh script?"
)
394
print
(
"::: ERROR Please do this and reconfigure cmake manually!"
)
395
else
:
396
print
(
"::: INFO Reconfiguring cmake %s/../."
% workDir)
397
res = subprocess.getstatusoutput(
'cmake %s/../.'
% workDir)
398
if
res[0]!=0:
399
print
(
"::: WARNING reconfigure unsuccessful. Please reconfigure manually!"
)
400
401
402
print
(
"::: INFO Please ensure your CMakeLists.txt file has "
)
403
print
(
"::: atlas_add_component( %s src/component/*.cxx ... )"
% full_pkg_name)
404
print
(
"::: INFO and necessary dependencies declared "
)
405
print
(
"::: INFO Minimum dependency is: Control/AthAnalysisBaseComps"
)
406
print
void print(char *figname, TCanvas *c1)
Definition
TRTCalib_StrawStatusPlots.cxx:26
python.scripts.cmake_newanalysisalg.Templates
Definition
cmake_newanalysisalg.py:19
Generated on
for ATLAS Offline Software by
1.17.0