Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-11-25 02:29:50

0001 # Copyright (C) 2014 Colin Bernet
0002 # https://github.com/cbernet/heppy/blob/master/LICENSE
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 #TODO review inheritance, and in particular constructor args - this is a mess.
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         # if intLumi is None:
0237         #    intLumi = Weight.FBINV
0238         #COLIN THIS WEIGHT STUFF IS REALLY BAD!!
0239         # use the existing Weight class or not? guess so...
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