ATLAS Offline Software
Toggle main menu visibility
Loading...
Searching...
No Matches
PhysicsAnalysis
Algorithms
AnalysisAlgorithmsConfig
python
ConfigSequence.py
Go to the documentation of this file.
1
# Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
2
3
from
AnalysisAlgorithmsConfig.ConfigBlock
import
ConfigBlock
4
from
AnaAlgorithm.Logging
import
logging
5
logCPAlgCfgSeq = logging.getLogger(
'CPAlgCfgSeq'
)
6
7
from
functools
import
wraps
8
from
random
import
randrange
9
import
re
10
11
_instanceNameExpr = re.compile (
'^[_a-zA-Z0-9]*$'
)
12
13
def
groupBlocks
(func):
14
"""
15
Decorates a configSequence or function with 'seq' as a
16
argument.
17
18
Sets groupName to the name of the decorated function or
19
class plus an integer for each ConfigBlock in the configSequence.
20
21
Blocks with the same groupName can be configured together.
22
"""
23
@wraps(func)
24
def
wrapper(**kwargs):
25
func(**kwargs)
26
groupName = f
"{func.__name__}_{randrange(10**8):08}"
27
for
block
in
kwargs[
'seq'
]:
28
block.setOptionValue(
'groupName'
, groupName)
29
return
wrapper
30
31
class
ConfigSequence
:
32
"""a sequence of ConfigBlock objects
33
34
This could in principle just be a simple python list, and maybe we
35
change it to that at some point (10 Mar 22). Having it as its own
36
class allows to implement some helper functions.
37
38
This implements an interface similar to ConfigBlock, but it
39
doesn't derive from it, as ConfigBlock will likely gain
40
functionality in the future that wouldn't work for a sequence (or
41
wouldn't work in the same way).
42
43
"""
44
45
def
__init__
(self) :
46
self.
_blocks
= []
47
48
49
def
append
(self, block) :
50
"""append a configuration block to the sequence"""
51
self.
_blocks
.append (block)
52
53
54
def
makeAlgs
(self, config) :
55
"""call makeAlgs() on all blocks
56
57
This will create the actual algorithm configurables based on
58
how the blocks are configured right now.
59
"""
60
for
block
in
self.
_blocks
:
61
if
not
block.isUsedForConfig(config):
62
continue
63
config.setAlgPostfix(block.instanceName())
64
block.checkExpertSettings (config)
65
block.makeAlgs (config)
66
config.setAlgPostfix(
''
)
# reset algPostfix after all blocks are configured
67
ConfigBlock.instance_counts.clear()
# reset for a possible next config run
68
69
70
def
applyConfigOverrides
(self, config):
71
"""
72
Apply any properties that were set in the block's
73
'propertyOverrides' option.
74
"""
75
for
block
in
self.
_blocks
:
76
if
not
block.isUsedForConfig(config):
77
continue
78
config.setAlgPostfix(block.instanceName())
79
block.applyConfigOverrides(config)
80
config.setAlgPostfix(
''
)
# reset algPostfix after all blocks are configured
81
82
def
reorderAlgs
(self):
83
"""
84
Check for blocks with dependencies.
85
86
If a block required another block that is not present, will
87
throw an error; Otherwise, will move block immediately after
88
required block. If dependency is not required, will move
89
after other block, if it is present.
90
91
Note: this implementation can only move blocks forward.
92
"""
93
def
moveBlock(blocks):
94
for
i, block
in
enumerate(blocks):
95
# the 'ignoreDependencies' option is added with a dep.
96
ignore = block.getOptionValue(
'ignoreDependencies'
)
97
if
block.hasDependencies():
98
depIdx = i
99
for
dep
in
block.getDependencies():
100
if
dep.blockName
in
ignore:
101
continue
102
# find dep with largest idx
103
depIndices = [index
for
index, value
in
enumerate(blocks)
104
if
value.getBlockName() == dep.blockName]
105
if
depIndices:
106
lastIdx =
max
(depIndices)
107
if
lastIdx > depIdx:
108
depIdx = lastIdx
109
elif
dep.required:
110
raise
ValueError(f
"{dep} block is required"
111
f
" for {block} but was not found."
)
112
# check to see if block is already in front of deps
113
if
depIdx > i:
114
logCPAlgCfgSeq.info(f
"Moving {block} after {blocks[depIdx]}"
)
115
# depIdx > i so after pop, depIdx -= 1 -> depIdx is after dep
116
blocks.insert(depIdx, blocks.pop(i))
117
return
False
118
# nothing to move
119
return
True
120
MAXTRIES = 1000
121
for
_
in
range(MAXTRIES):
122
if
moveBlock(self.
_blocks
):
123
# sorted
124
break
125
else
:
126
raise
Exception(
"Could not order blocks based on dependencies"
127
f
" in {MAXTRIES} moves."
)
128
129
130
def
fullConfigure
(self, config) :
131
"""do the full configuration on this sequence
132
133
This sequence needs to be the only sequence, i.e. it needs to
134
contain all the blocks that will be configured, as it will
135
perform all configuration steps at once.
136
"""
137
for
block
in
self.
_blocks
:
138
instanceName = block.instanceName()
139
if
_instanceNameExpr.match (instanceName)
is
None
:
140
raise
ValueError (f
'invalid block instance name: {instanceName} for {block.factoryName()}'
)
141
142
self.
reorderAlgs
()
143
self.
makeAlgs
(config)
144
self.
applyConfigOverrides
(config)
145
config.renameFinalContainers()
146
147
148
def
setOptionValue
(self, name, value, **kwargs) :
149
"""set the given option on the sequence
150
151
The name should generally be of the form
152
"groupName.optionName" to identify what group the option
153
belongs to.
154
155
For simplicity I also allow a ".optionName" here, which will
156
then set the property in the last group added. That makes it
157
fairly straightforward to add new blocks, set options on them,
158
and then move on to the next blocks. Please note that this
159
mechanism ought to be viewed as strictly as a temporary
160
convenience, and this short cut may go away once better
161
alternatives are available.
162
163
WARNING: The backend to option handling is slated to be
164
replaced at some point. This particular function may change
165
behavior, interface or be removed/replaced entirely.
166
"""
167
names = name.split(
'.'
)
168
# <optionName>
169
optionName = names.pop(-1)
170
# <groupName>.<optionName>, or
171
# .<optionName> (backwards compatibility)
172
groupName = names.pop(0)
if
names
else
''
173
if
names:
174
raise
ValueError(f
'Option name can be either <groupName>.<optionName>'
175
f
' or <optionName> not {name}'
)
176
blocks = self.
_blocks
177
# check if last block added has an instance name
178
if
not
groupName:
179
groupName = blocks[-1].getOptionValue(
'groupName'
)
180
if
groupName:
181
used =
False
182
# set optionName for all blocks with groupName
183
for
block
in
blocks:
184
if
( block.getOptionValue(
'groupName'
) == groupName
185
and
block.hasOption(optionName) ):
186
block.setOptionValue (optionName, value, **kwargs)
187
used =
True
188
if
not
used:
189
raise
ValueError(f
'{optionName} not found in blocks with '
190
f
'group name {groupName}'
)
191
else
:
192
# set option for last added block
193
blocks[-1].setOptionValue (optionName, value, **kwargs)
194
195
196
def
printOptions
(self, verbose=False):
197
"""
198
Prints options and their values for each config block in a config sequence
199
"""
200
for
config
in
self:
201
logCPAlgCfgSeq.info(config.__class__.__name__)
202
config.printOptions(verbose=verbose)
203
204
205
def
getOptions
(self):
206
"""get information on options for last block in sequence"""
207
# get groupName for last added block
208
groupName = self.
_blocks
[-1].getOptionValue(
'groupName'
)
209
blocks = [self.
_blocks
[-1]]
210
# get all blocks with the same groupName
211
if
groupName:
212
for
block
in
self.
_blocks
[:-1]:
213
if
block.getOptionValue(
'groupName'
) == groupName:
214
blocks.append(block)
215
options = []
216
# get options for all blocks with same groupName
217
for
block
in
blocks:
218
for
name, o
in
block.getOptions().items():
219
val = getattr(block, name)
220
valDefault = o.default
221
valType = o.type
222
valRequired = o.required
223
noneAction = o.noneAction
224
options.append({
'name'
: name,
'defaultValue'
: valDefault,
225
'type'
: valType,
'required'
: valRequired,
226
'noneAction'
: noneAction,
'value'
: val})
227
return
options
228
229
230
def
setOptions
(self, options):
231
"""Set options for a ConfigBlock"""
232
algOptions = self.
getOptions
()
233
for
opt
in
algOptions:
234
name = opt[
'name'
]
235
if
name
in
options:
236
self.
setOptionValue
(f
'.{name}'
, options[name])
237
logCPAlgCfgSeq.debug(f
" {name}: {options[name]}"
)
238
else
:
239
if
opt[
'required'
]:
240
raise
ValueError(f
'{name} is required but not included in config'
)
241
# add default used to config
242
defaultVal = opt[
'value'
]
if
opt[
'value'
]
is
not
None
else
opt[
'defaultValue'
]
243
# do not overwrite groupName unless set by user
244
if
name !=
'groupName'
:
245
options[name] = defaultVal
246
logCPAlgCfgSeq.debug(f
" {name}: {defaultVal}"
)
247
# refresh and return options
248
return
self.
getOptions
()
249
250
251
def
groupBlocks
(self, groupName=''):
252
"""
253
Assigns all blocks in configSequence groupName. If no name is
254
provided, the name is set to group_ plus an integer.
255
256
Blocks with the same groupName can be configured together.
257
"""
258
if
not
groupName:
259
groupName = f
"group_{randrange(10**8):08}"
260
for
block
in
self.
_blocks
:
261
block.setOptionValue(
'groupName'
, groupName)
262
263
264
def
setFactoryName
(self, factoryName):
265
"""
266
Set the factory name for all blocks in the sequence.
267
268
This is used to set a common factory name for all blocks, which
269
can be useful for debugging or logging purposes.
270
"""
271
if
len(self.
_blocks
) == 1:
272
self.
_blocks
[0].
setFactoryName
(factoryName)
273
else
:
274
# append [index] to factoryName for each block
275
for
index, block
in
enumerate(self.
_blocks
):
276
block.setFactoryName(f
"{factoryName}[{index}:{block.__class__.__name__}]"
)
277
278
def
__iadd__
( self, sequence ):
279
"""Add another sequence to this one
280
281
This function is used to add another sequence to this sequence
282
using the '+=' operator.
283
"""
284
# Check that the received object is of the right type:
285
if
not
isinstance( sequence, ConfigSequence ):
286
raise
TypeError(
'The received object is not of type ConfigSequence'
)
287
288
for
block
in
sequence._blocks :
289
self.
_blocks
.append (block)
290
291
# Return the modified object:
292
return
self
293
294
295
def
__iter__
( self ):
296
"""Create an iterator over all the configurations in this sequence
297
298
This is to allow for a Python-like iteration over all
299
configuration blocks that are part of the sequence.
300
"""
301
# Create the iterator to process the internal list of algorithms:
302
return
self.
_blocks
.
__iter__
()
max
#define max(a, b)
Definition
cfImp.cxx:41
python.ConfigSequence.ConfigSequence
Definition
ConfigSequence.py:31
python.ConfigSequence.ConfigSequence.__iadd__
__iadd__(self, sequence)
Definition
ConfigSequence.py:278
python.ConfigSequence.ConfigSequence.__iter__
__iter__(self)
Definition
ConfigSequence.py:295
python.ConfigSequence.ConfigSequence.groupBlocks
groupBlocks(self, groupName='')
Definition
ConfigSequence.py:251
python.ConfigSequence.ConfigSequence.setOptionValue
setOptionValue(self, name, value, **kwargs)
Definition
ConfigSequence.py:148
python.ConfigSequence.ConfigSequence._blocks
list _blocks
Definition
ConfigSequence.py:46
python.ConfigSequence.ConfigSequence.append
append(self, block)
Definition
ConfigSequence.py:49
python.ConfigSequence.ConfigSequence.reorderAlgs
reorderAlgs(self)
Definition
ConfigSequence.py:82
python.ConfigSequence.ConfigSequence.__init__
__init__(self)
Definition
ConfigSequence.py:45
python.ConfigSequence.ConfigSequence.makeAlgs
makeAlgs(self, config)
Definition
ConfigSequence.py:54
python.ConfigSequence.ConfigSequence.fullConfigure
fullConfigure(self, config)
Definition
ConfigSequence.py:130
python.ConfigSequence.ConfigSequence.setFactoryName
setFactoryName(self, factoryName)
Definition
ConfigSequence.py:264
python.ConfigSequence.ConfigSequence.setOptions
setOptions(self, options)
Definition
ConfigSequence.py:230
python.ConfigSequence.ConfigSequence.printOptions
printOptions(self, verbose=False)
Definition
ConfigSequence.py:196
python.ConfigSequence.ConfigSequence.getOptions
getOptions(self)
Definition
ConfigSequence.py:205
python.ConfigSequence.ConfigSequence.applyConfigOverrides
applyConfigOverrides(self, config)
Definition
ConfigSequence.py:70
python.ConfigSequence.groupBlocks
groupBlocks(func)
Definition
ConfigSequence.py:13
Generated on
for ATLAS Offline Software by
1.17.0