File indexing completed on 2023-03-17 11:15:49
0001 from __future__ import print_function
0002 from __future__ import absolute_import
0003
0004
0005
0006 from .weight import Weight
0007 import copy
0008 import glob
0009
0010 def printComps(comps, details=False):
0011 '''
0012 Summary printout for a list of components comps.
0013 The components are assumed to have a name, and a list of files,
0014 like the ones from this module.
0015 '''
0016 nJobs = 0
0017 nCompsWithFiles = 0
0018 for c in comps:
0019 if not hasattr(c, 'splitFactor'):
0020 c.splitFactor = 1
0021 print(c.name, c.splitFactor, len(c.files))
0022 if len(c.files)==0:
0023 continue
0024 else:
0025 if details:
0026 print(c.files[0])
0027 nJobs += c.splitFactor
0028 nCompsWithFiles += 1
0029
0030 print('-'*70)
0031 print('# components with files = ', nCompsWithFiles)
0032 print('# jobs = ', nJobs)
0033
0034
0035 class CFG(object):
0036 '''Base configuration class. The attributes are used to store parameters of any type'''
0037 def __init__(self, **kwargs):
0038 '''All keyword arguments are added as attributes.'''
0039 self.__dict__.update( **kwargs )
0040
0041 def __str__(self):
0042 '''A useful printout'''
0043 header = '{type}: {name}'.format( type=self.__class__.__name__,
0044 name=self.name)
0045 varlines = ['\t{var:<15}: {value}'.format(var=var, value=value) \
0046 for var,value in sorted(vars(self.items())) \
0047 if var is not 'name']
0048 all = [ header ]
0049 all.extend(varlines)
0050 return '\n'.join( all )
0051
0052 def clone(self, **kwargs):
0053 '''Make a copy of this object, redefining (or adding) some parameters, just
0054 like in the CMSSW python configuration files.
0055
0056 For example, you can do
0057 module1 = cfg.Analyzer(SomeClass,
0058 param1 = value1,
0059 param2 = value2,
0060 param3 = value3,
0061 ...)
0062 module2 = module1.clone(
0063 param2 = othervalue,
0064 newparam = newvalue)
0065 and module2 will inherit the configuration of module2 except for
0066 the value of param2, and for having an extra newparam of value newvalue
0067 (the latter may be useful if e.g. newparam were optional, and needed
0068 only when param2 == othervalue)
0069
0070 Note that, just like in CMSSW, this is a shallow copy and not a deep copy,
0071 i.e. if in the example above value1 were to be an object, them module1 and
0072 module2 will share the same instance of value1, and not have two copies.
0073 '''
0074 other = copy.copy(self)
0075 for k,v in kwargs.items():
0076 setattr(other, k, v)
0077 return other
0078
0079 class Analyzer( CFG ):
0080 '''Base analyzer configuration, see constructor'''
0081
0082 num_instance = 0
0083
0084 def __init__(self, class_object, instance_label=None,
0085 verbose=False, **kwargs):
0086 '''
0087 One could for example define the analyzer configuration for a
0088 di-muon framework.Analyzer.Analyzer in the following way:
0089
0090 ZMuMuAna = cfg.Analyzer(
0091 "ZMuMuAnalyzer",
0092 pt1 = 20,
0093 pt2 = 20,
0094 iso1 = 0.1,
0095 iso2 = 0.1,
0096 eta1 = 2,
0097 eta2 = 2,
0098 m_min = 0,
0099 m_max = 200
0100 )
0101
0102 Any kinds of keyword arguments can be added.
0103 The name must be present, and must be well chosen, as it will be used
0104 by the Looper to find the module containing the Analyzer class.
0105 This module should be in your PYTHONPATH. If not, modify your python path
0106 accordingly in your script.
0107 '''
0108
0109 self.class_object = class_object
0110 self.__class__.num_instance += 1
0111 if instance_label is None:
0112 instance_label = str(self.__class__.num_instance)
0113 self.instance_label = instance_label
0114 self.verbose = verbose
0115 super(Analyzer, self).__init__(**kwargs)
0116
0117 def __setattr__(self, name, value):
0118 '''You may decide to copy an existing analyzer and change
0119 its instance_label. In that case, one must stay consistent.'''
0120 self.__dict__[name] = value
0121 if name == 'instance_label':
0122 self.name = self.build_name()
0123
0124 def build_name(self):
0125 class_name = '.'.join([self.class_object.__module__,
0126 self.class_object.__name__])
0127 name = '_'.join([class_name, self.instance_label])
0128 return name
0129
0130 def clone(self, **kwargs):
0131 other = super(Analyzer, self).clone(**kwargs)
0132 if 'class_object' in kwargs and 'name' not in kwargs:
0133 other.name = other.build_name()
0134 return other
0135
0136
0137 class Service( CFG ):
0138
0139 num_instance = 0
0140
0141 def __init__(self, class_object, instance_label=None,
0142 verbose=False, **kwargs):
0143 self.class_object = class_object
0144 self.__class__.num_instance += 1
0145 if instance_label is None:
0146 instance_label = str(self.__class__.num_instance)
0147 self.instance_label = instance_label
0148 self.__class__.num_instance += 1
0149 self.name = self.build_name()
0150 self.verbose = verbose
0151 super(Service, self).__init__(**kwargs)
0152
0153 def build_name(self):
0154 class_name = '.'.join([self.class_object.__module__,
0155 self.class_object.__name__])
0156 name = '_'.join([class_name, self.instance_label])
0157 return name
0158
0159 def __setattr__(self, name, value):
0160 '''You may decide to copy an existing analyzer and change
0161 its instance_label. In that case, one must stay consistent.'''
0162 self.__dict__[name] = value
0163 if name == 'instance_label':
0164 self.name = self.build_name()
0165
0166 def clone(self, **kwargs):
0167 other = super(Service, self).clone(**kwargs)
0168 if 'class_object' in kwargs and 'name' not in kwargs:
0169 other.name = other.build_name()
0170 return other
0171
0172
0173 class Sequence( list ):
0174 '''A list with print functionalities.
0175
0176 Used to define a sequence of analyzers.'''
0177 def __str__(self):
0178 tmp = []
0179 for index, ana in enumerate( self ):
0180 tmp.append( '{index} :'.format(index=index) )
0181 tmp.append( '{ana} :'.format(ana=ana) )
0182 return '\n'.join(tmp)
0183
0184
0185
0186 class Component( CFG ):
0187 '''Base component class.
0188
0189 See the child classes:
0190 DataComponent, MCComponent, EmbedComponent
0191 for more information.'''
0192 def __init__(self, name, files, tree_name=None, triggers=None, **kwargs):
0193 if isinstance(triggers, str):
0194 triggers = [triggers]
0195 if isinstance(files, str):
0196 files = sorted(glob.glob(files))
0197 super( Component, self).__init__( name = name,
0198 files = files,
0199 tree_name = tree_name,
0200 triggers = triggers, **kwargs)
0201 self.dataset_entries = 0
0202 self.isData = False
0203 self.isMC = False
0204 self.isEmbed = False
0205
0206 class DataComponent( Component ):
0207
0208 def __init__(self, name, files, intLumi=None, triggers=[], json=None):
0209 super(DataComponent, self).__init__(name, files, triggers=triggers)
0210 self.isData = True
0211 self.intLumi = intLumi
0212 self.json = json
0213
0214 def getWeight( self, intLumi = None):
0215 return Weight( genNEvents = -1,
0216 xSection = None,
0217 genEff = -1,
0218 intLumi = self.intLumi,
0219 addWeight = 1. )
0220
0221
0222
0223 class MCComponent( Component ):
0224 def __init__(self, name, files, triggers=[], xSection=1,
0225 nGenEvents=None,
0226 effCorrFactor=None, **kwargs ):
0227 super( MCComponent, self).__init__( name = name,
0228 files = files,
0229 triggers = triggers, **kwargs )
0230 self.xSection = xSection
0231 self.nGenEvents = nGenEvents
0232 self.effCorrFactor = effCorrFactor
0233 self.isMC = True
0234 self.intLumi = 1.
0235 self.addWeight = 1.
0236
0237 def getWeight( self, intLumi = None):
0238
0239
0240
0241
0242 return Weight( genNEvents = self.nGenEvents,
0243 xSection = self.xSection,
0244 intLumi = self.intLumi,
0245 genEff = 1/self.effCorrFactor,
0246 addWeight = self.addWeight )
0247
0248 class Config( object ):
0249 '''Main configuration object, holds a sequence of analyzers, and
0250 a list of components.'''
0251 def __init__(self, components, sequence, services, events_class,preprocessor=None):
0252 self.preprocessor = preprocessor
0253 self.components = components
0254 self.sequence = sequence
0255 self.services = services
0256 self.events_class = events_class
0257
0258 def __str__(self):
0259 comp = '\n'.join(map(str, self.components))
0260 sequence = str(self.sequence)
0261 services = '\n'.join( map(str, self.services))
0262 return '\n'.join([comp, sequence, services])
0263
0264