11 from .Block
import Block
12 from AthenaCommon.Logging
import logging
13 from .StackedDict
import StackedDict
14 from AthenaConfiguration.ComponentFactory
import CompFactory
16 D3PD = CompFactory.D3PD
19 def _make_name (name, prefix, name_prefix, parent_prefix, default_prefix):
20 """Helper to form the name for object filler tools."""
22 pref = prefix + name_prefix
23 if len (pref) == 0: pref = default_prefix
26 name = parent_prefix + pref +
'Filler'
31 """Helper to perform LOD test.
33 lod: The level-of-detail to test. Either an integer or a callable.
34 reqlev: Requested level of detail for this object. An integer.
35 args: Arguments to be passed to the block.
36 hookargs: Arguments passed to the D3PD object, to be passed
45 doblock = lod (reqlev, args, hookargs)
46 except TypeError
as exc:
47 if (len(exc.args) > 0
and
48 (exc.args[0].find (
'takes exactly 2 arguments') >= 0
or
49 exc.args[0].find (
'takes 2 positional') >= 0)):
50 doblock = lod (reqlev, args)
54 doblock = (lod <= reqlev)
60 """Defer evaluating a block argument until the D3PDObject is instantiated.
62 Sometimes you want to pass an argument to a block function that isn't
63 known at the time the D3PDObject is defined, for example the
64 StoreGate key to use. You could do this with a hook function
65 or a LOD function, but that's a bit cumbersome. Instead, you can
66 use DeferArg. DeferArg stores a string. If a block argument
67 has a value that's an instance of DeferArg, then this string
68 is evaluated at the time the D3PDObject is instantiated.
69 The arguments passed to the D3PDObject will be available
70 in the context in which the string is evaluated.
71 A global dictionary may be provided as an optional argument;
72 any additional keyword arguments will be merged into this
77 FooD3PDObject.defineBlock (1, 'SomeBlock', SomeTool,
78 Name = DeferArg ('"name_" + sgkey'))
80 If FooD3PDObject is then instantiated with a StoreGate key of `Bar',
81 then the Name argument of this block will be set to `name_Bar'.
83 def __init__ (self, str, gdict = globals(), **kw):
92 gdict.update (self.
kw)
93 hookargs = hookargs.copy()
95 return eval (self.
str, gdict, hookargs)
100 """D3PD object creator class.
102 For each type of object written to the D3PD, create
103 an instance of this class. The arguments to the constructor
104 are a function to create the Configurable for the object filler
105 tool and a default value for the variable name prefix
108 After creating the instance, one calls defineBlock to define
109 the blocks of variables that can be written for this object.
111 Finally, one calls the object in order to create the
114 So, a typical usage might look like this.
116 def makeElectronD3PDObject (name, prefix,
118 sgkey = 'ElectronAODCollection')
120 getter = CompFactory.D3PD.SGDataVectorGetterTool \
122 TypeName = 'ElectronContainer',
125 return CompFactory.D3PD.VectorFillerTool (name,
129 ElectronD3PDObject = D3PDObject (makeElectronD3PDObject, 'el_')
131 ElectronD3PDObject.defineBlock (0, 'Kinematics',
132 EventCommonD3PDMaker.FourMomFillerTool)
135 alg += ElectronD3PDObject (level)
141 def __init__ (self, maker, default_prefix = '', default_object_name = '',
142 default_name = None, allow_args = [], **kw):
146 maker: A function to create the IObjFillerTool Configurable
147 for this object. It is called with two fixed arguments,
148 the tool name and the variable name prefix. Any other
149 arguments provided to the call will be passed through.
150 default_prefix: Default variable name prefix for objects
152 default_object_name: Default D3PDObject name, something like
153 'EventInfoD3PDObject'
154 default_name: If specified, the default tool name to use
156 allow_args: Additional arguments that may be passed in when
157 instantiating the D3PDObject, but which are not
158 to be passed to the maker function. This can be
159 used to allow for additional arguments to hook
160 or level-of-detail functions.
162 Any additional arguments are passed into any hook functions.
179 """Define a new block of variables for this object type.
182 lod: Level of detail of this block. See below.
183 name: Name of this block.
184 func: Function to create the block Configurable.
185 prefix: Variable name prefix for this block.
186 kw: Arguments to pass to the creation function.
188 The creation function will be called like this:
190 b.func (name, BlockName = blockname, **b.kw)
192 where name is the name for the tool.
194 However, if b.func is a class deriving from D3PDObject, then the creation
195 function will instead be called like this:
197 b.func (level, name, parent_prefix, **b.kw)
199 LOD is used to control whether this block should be included.
201 In the simple case, this is an integer, and the block is included
202 if the block's level of detail is less than or equal to the
203 requested level of detail (unless the block was explicitly
204 included or excluded).
206 In the general case, LOD may be a function. The first two arguments
207 passed to the function will be the requested level of detail
209 arguments. The requested level of detail will be an integer;
210 it will be 999 if the block was explicitly included, and -999
211 if the block was explicitly excluded. The block filler arguments
212 is a dictionary of keyword arguments. The LOD function should
213 return a boolean value saying whether or not the block should
214 be included. It may also alter the dictionary of arguments
215 (this overrides all other argument settings).
216 The LOD function may optionally take a third argument; if present,
217 this is a dictionary of the arguments passed to the D3PDObject
218 (the same arguments that are passed to hook functions).
220 if prefix
is not None:
222 kw[
'Prefix'] = prefix
228 if isinstance (func, D3PDObject):
229 for n
in func.allBlocknames():
234 self.
_blocks.append (Block (name, lod, func, kw))
239 """Remove the block NAME from this object."""
242 if isinstance (b.func, D3PDObject):
243 if b.func.removeBlock (name,
True):
252 raise ValueError (
'Unknown block name: ', name)
256 if isinstance (bb.func, D3PDObject):
257 for n
in bb.func.allBlocknames():
264 """Define a new hook function for this D3PD object.
266 HOOK is a function that will be called for each instance
267 of this D3PD object after all block filler tools have been
270 The arguments to the hook function are the object filler tool,
271 followed by the arguments that were passed to __call__.
277 """Add a new block name N to the list of all names.
278 Raises an exception if a block name is duplicated.
282 log = logging.getLogger (
'D3PDObject')
283 log.warn (
'Duplicate block name: %s (%s %s %s)',
289 raise ValueError (
'Duplicate block name: %s (%s %s %s)' %
296 self.
_parent._add_blockname (n,
True)
301 """Remove block name N."""
304 self.
_parent._remove_blockname (n)
309 """Return a dictionary the keys of which are the names of all blocks
310 defined for this object. This list will include any blocks defined
326 parent_hookargs = None,
328 """Create a Configurable to fill an object of this type.
331 level: Requested level of detail for this object. An integer.
332 name: Tool name. If omitted, one will be constructed.
333 prefix: Variable name prefix for this object.
334 name_prefix: If name wasn't specified, this is a prefix
335 to add to the tool name.
336 parent_prefix: Variable name prefix for any parent tool.
337 object_name: Name of the D3PDObject, like 'EventInfoD3PDObject'
338 include: List of block names to include, regardless
340 exclude: List of block names to exclude, regardless
342 blockargs: Extra arguments to pass to block filler tools.
343 The keys are block names.
344 Values are dictionaries of keyword arguments.
345 These override anything specified in defineBlock.
346 parent_hookargs: [Not to be used by user code.]
347 Dictionary of hook args from the parent,
348 to be merged into our hook arg dictionary.
349 args, kw: Additional arguments to pass to the maker function.
350 However, any entries in KW that have the form
351 BLOCK_parm, where BLOCK is a known block name,
352 will instead be interpreted as arguments to pass
353 to a block filler tool. These override entries
362 if object_name
is None:
368 name = _make_name (name, prefix, name_prefix, parent_prefix,
372 blockargs = dict ([(k, v.copy())
for (k, v)
in blockargs.items()])
376 for k
in list (kw.keys()):
382 for i
in range(1, len(kk)):
383 this_key =
'_'.join (kk[:i])
385 this_var =
'_'.join (kk[i:])
386 blockargs.setdefault(this_key,{})[this_var] = kw[k]
393 if k
in kw2: del kw2[k]
397 c = self.
_maker (name=name, prefix=prefix, object_name=object_name,
400 except TypeError
as exc:
401 if (len(exc.args) > 0
and
402 exc.args[0].find (
"unexpected keyword argument 'object_name'") >= 0):
403 log = logging.getLogger (
'D3PDObject')
404 log.warn (
"Maker function missing `object_name' formal arg: %s", self.
_maker)
405 c = self.
_maker (name=name, prefix=prefix, *args, **kw2)
412 if parent_hookargs
is None:
415 hookargs = StackedDict (local_hookargs, kw,
417 local_hookargs[
'level'] = level
418 local_hookargs[
'name'] = name
419 local_hookargs[
'prefix'] = prefix
420 local_hookargs[
'name_prefix'] = name_prefix
421 local_hookargs[
'parent_prefix'] = parent_prefix
422 local_hookargs[
'include'] = include
423 local_hookargs[
'exclude'] = exclude
424 local_hookargs[
'blockargs'] = blockargs
425 local_hookargs[
'd3pdo'] = self
429 include, exclude, blockargs, hookargs)
441 D3PDObject._hookArgsStore[c.getName()] = (self.
_hooks, args, hookargs)
447 """Run creation hooks for configurable C.
449 Should be run by the D3PD maker algorithm; not for general use.
451 info = D3PDObject._hookArgsStore.get (c.getName())
453 (hooks, args, hookargs) = info
472 """Return a list of block filler tool configurables.
475 level: Requested level of detail for this object. An integer.
476 parent_name: Name of the parent component.
477 parent_prefix: Variable name prefix for any parent tool.
478 include: List of block names to include, regardless
480 exclude: List of block names to exclude, regardless
482 blockargs: Extra arguments to pass to block filler tools.
483 The keys are block names.
484 Values are dictionaries of keyword arguments.
485 These override anything specified in defineBlock.
486 hookargs: Arguments passed to the D3PD object, to be passed
492 if b.name
in include:
495 elif b.name
in exclude:
504 args.update (blockargs.get (b.name, {}))
511 for k, v
in args.items():
512 if isinstance(v, list):
514 if isinstance(v, DeferArg):
515 args[k] =
v(hookargs)
517 if _testLOD (b.lod, reqlev, args, hookargs):
518 fillername = parent_name +
'_' + b.name
519 if isinstance (b.func, D3PDObject):
522 args[k] = hookargs[k]
523 bf = b.func (level, fillername,
524 parent_prefix = parent_prefix,
527 blockargs = blockargs,
528 parent_hookargs = hookargs,
531 bf = b.func (fillername, **args)
535 D3PDObject._hookArgsStore[bf.getName()] = (b._hooks, args, hookargs)
548 """Create block filler tools for object C, for the specified
552 c: Object for which to create the block fillers.
553 level: Requested level of detail for this object. An integer.
554 parent_prefix: Variable name prefix for any parent tool.
555 include: List of block names to include, regardless
557 exclude: List of block names to exclude, regardless
559 blockargs: Extra arguments to pass to block filler tools.
560 The keys are block names.
561 Values are dictionaries of keyword arguments.
562 These override anything specified in defineBlock.
563 hookargs: Arguments passed to the D3PD object, to be passed
566 for bf
in self.
blockFillers (level, c.getName(), parent_prefix,
567 include, exclude, blockargs,
569 c.BlockFillers += [bf]
575 default_prefix = None,
576 default_object_name = None,
579 """Return a copy of this D3PD object, possibly changing parameters."""
580 if default_prefix
is None:
582 if default_object_name
is None:
584 if default_name
is None:
589 c = D3PDObject (self.
_maker,
598 if isinstance (func, D3PDObject):
600 c.defineBlock (b.lod, b.name, func, **b.kw)
609 default_object_name = '',
612 """Helper to make a D3PDObject for the case where no explicit
613 input object is being used.
616 default_prefix: The default prefix to put in front of variables.
617 default_object_name: The name of the D3PDObject which is created,
618 like 'EventInfoD3PDObject'
619 default_name: If specified, the default tool name to use
621 allow_args: Additional arguments that may be passed in when
622 instantiating the D3PDObject, but which are not
623 to be passed to the maker function. This can be
624 used to allow for additional arguments to hook
625 or level-of-detail functions.
627 Typical usage would be something like this:
630 make_Void_D3PDObject ('trig_', 'METD3PDObject')
633 def make_obj (name, prefix, object_name):
634 from D3PDMakerConfig.D3PDMakerFlags
import D3PDMakerFlags
637 ObjectName = object_name,
639 D3PDMakerFlags.SaveObjectMetadata)
640 return D3PDObject (make_obj, default_prefix, default_object_name,
641 default_name = default_name,
642 allow_args = allow_args)
649 default_object_name = None,
650 default_allowMissing = False,
651 default_getterClass = D3PD.SGObjGetterTool,
653 """Helper to make a D3PDObject for the common case where the default
654 input source is a single object from StoreGate.
657 default_typeName: The default name of the type being
658 fetched from StoreGate.
659 default_sgkey: The default value for the StoreGate key.
660 default_prefix: The default prefix to put in front of variables.
661 default_object_name: The name of the D3PDObject which is created,
662 like 'EventInfoD3PDObject'
663 default_allowMissing: The default value for the AllowMissing
664 property (defaults to False).
665 default_getterClass: Default value to use for the getter class,
666 when we create the getter. Defaults to SGObjGetterTool.
667 allow_args: Additional arguments that may be passed in when
668 instantiating the D3PDObject, but which are not
669 to be passed to the maker function. This can be
670 used to allow for additional arguments to hook
671 or level-of-detail functions.
673 Typical usage would be something like this:
676 make_SG_D3PDObject ('MissingET',
677 D3PDMakerFlags.MissingETSGKey,
678 'met_', 'METD3PDObject')
681 def make_obj (name, prefix, object_name,
684 allowMissing = default_allowMissing,
685 typeName = default_typeName,
686 getterClass = default_getterClass):
687 if sgkey
is None: sgkey = default_sgkey
689 getter = getterClass (name +
'_Getter',
692 from D3PDMakerConfig.D3PDMakerFlags
import D3PDMakerFlags
696 ObjectName = object_name,
697 AllowMissing=allowMissing,
699 D3PDMakerFlags.SaveObjectMetadata)
701 if default_object_name
is None:
702 default_object_name = default_typeName
703 default_object_name = default_object_name.split(
'::')[-1]
705 return D3PDObject (make_obj, default_prefix, default_object_name,
706 sgkey = default_sgkey,
707 typeName = default_typeName,
708 allow_args = allow_args)
715 default_object_name = None,
716 default_allowMissing = False,
717 default_getterFilter = None,
718 default_label = None,
719 default_getterClass = \
720 D3PD.SGDataVectorGetterTool,
723 """Helper to make a D3PDObject for the common case where the default
724 input source is a DataVector container from StoreGate.
727 default_typeName: The default name of the type being
728 fetched from StoreGate.
729 default_sgkey: The default value for the StoreGate key.
730 default_prefix: The default prefix to put in front of variables.
731 default_object_name: The name of the D3PDObject which is created,
732 like 'EventInfoD3PDObject'
733 default_allowMissing: The default value for the AllowMissing
734 property (defaults to False).
735 default_label: The default value to use for the collection label
736 (default to the prefix).
737 default_getterFilter: A collection getter filter to wrap
738 around the primary getter (defaults to no filter).
739 If this is a string, then it is interpreted as the
740 StoreGate key of a SelectedParticles object to use
742 default_getterClass: Default value to use for the getter class,
743 when we create the getter. Defaults to SGDataVectorGetterTool,
744 which is appropriate for iterating over a DataVector.
745 allow_args: Additional arguments that may be passed in when
746 instantiating the D3PDObject, but which are not
747 to be passed to the maker function. This can be
748 used to allow for additional arguments to hook
749 or level-of-detail functions.
751 Typical usage would be something like this:
754 make_SGDataVector_D3PDObject ('JetCollection',
755 D3PDMakerFlags.JetSGKey,
756 'jet_', 'JetD3PDObject')
758 In addition, each object has automatically defined a
759 ContainerFlagFillerTool block named `SelectionFlags'.
760 This means that you can pass in an argument like
762 SelectionFlags_FlagNames [ 'selected@MyContainerType/mine:Objects in mine' ]
764 This will create a flag variable `selected' which will be true if
765 the object contained in the SG container MyContainerType/mine.
766 The string after the colon is used for documentation.
768 def make_obj (name, prefix, object_name,
771 label = default_label,
772 allowMissing = default_allowMissing,
773 getterFilter = default_getterFilter,
774 typeName = default_typeName,
775 getterClass = default_getterClass,
777 if sgkey
is None: sgkey = default_sgkey
778 if label
is None: label = prefix
780 getter = getterClass (name +
'_Getter',
785 if isinstance(getterFilter, str):
787 (name +
'_SelectionGetter',
788 TypeName =
'SelectedParticles',
789 SGKey = getterFilter)
791 (name +
'_GetterFilter',
793 SelectionGetter = selgetter)
795 getter = getterFilter (name +
'_GetterFilter',
797 defs = other_defaults.copy()
799 from D3PDMakerConfig.D3PDMakerFlags
import D3PDMakerFlags
803 ObjectName = object_name,
804 AllowMissing=allowMissing,
806 D3PDMakerFlags.SaveObjectMetadata,
809 if default_object_name
is None:
810 default_object_name = default_typeName
811 if default_object_name.endswith (
'Collection'):
812 default_object_name = default_object_name[:-10]
813 if default_object_name.endswith (
'Container'):
814 default_object_name = default_object_name[:-9]
815 default_object_name = default_object_name.split(
'::')[-1]
817 ret = D3PDObject (make_obj, default_prefix, default_object_name,
818 sgkey = default_sgkey,
819 typeName = default_typeName,
820 allow_args = allow_args)
824 ret.defineBlock (0,
'SelectionFlags',