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