CMS 3D CMS Logo

config.py
Go to the documentation of this file.
1 from __future__ import print_function
2 from __future__ import absolute_import
3 # Copyright (C) 2014 Colin Bernet
4 # https://github.com/cbernet/heppy/blob/master/LICENSE
5 
6 from .weight import Weight
7 import copy
8 import glob
9 import six
10 
11 def printComps(comps, details=False):
12  '''
13  Summary printout for a list of components comps.
14  The components are assumed to have a name, and a list of files,
15  like the ones from this module.
16  '''
17  nJobs = 0
18  nCompsWithFiles = 0
19  for c in comps:
20  if not hasattr(c, 'splitFactor'):
21  c.splitFactor = 1
22  print(c.name, c.splitFactor, len(c.files))
23  if len(c.files)==0:
24  continue
25  else:
26  if details:
27  print(c.files[0])
28  nJobs += c.splitFactor
29  nCompsWithFiles += 1
30 
31  print('-'*70)
32  print('# components with files = ', nCompsWithFiles)
33  print('# jobs = ', nJobs)
34 
35 
36 class CFG(object):
37  '''Base configuration class. The attributes are used to store parameters of any type'''
38  def __init__(self, **kwargs):
39  '''All keyword arguments are added as attributes.'''
40  self.__dict__.update( **kwargs )
41 
42  def __str__(self):
43  '''A useful printout'''
44  header = '{type}: {name}'.format( type=self.__class__.__name__,
45  name=self.name)
46  varlines = ['\t{var:<15}: {value}'.format(var=var, value=value) \
47  for var,value in sorted(vars(six.iteritems(self))) \
48  if var is not 'name']
49  all = [ header ]
50  all.extend(varlines)
51  return '\n'.join( all )
52 
53  def clone(self, **kwargs):
54  '''Make a copy of this object, redefining (or adding) some parameters, just
55  like in the CMSSW python configuration files.
56 
57  For example, you can do
58  module1 = cfg.Analyzer(SomeClass,
59  param1 = value1,
60  param2 = value2,
61  param3 = value3,
62  ...)
63  module2 = module1.clone(
64  param2 = othervalue,
65  newparam = newvalue)
66  and module2 will inherit the configuration of module2 except for
67  the value of param2, and for having an extra newparam of value newvalue
68  (the latter may be useful if e.g. newparam were optional, and needed
69  only when param2 == othervalue)
70 
71  Note that, just like in CMSSW, this is a shallow copy and not a deep copy,
72  i.e. if in the example above value1 were to be an object, them module1 and
73  module2 will share the same instance of value1, and not have two copies.
74  '''
75  other = copy.copy(self)
76  for k,v in six.iteritems(kwargs):
77  setattr(other, k, v)
78  return other
79 
80 class Analyzer( CFG ):
81  '''Base analyzer configuration, see constructor'''
82 
83  num_instance = 0
84 
85  def __init__(self, class_object, instance_label=None,
86  verbose=False, **kwargs):
87  '''
88  One could for example define the analyzer configuration for a
89  di-muon framework.Analyzer.Analyzer in the following way:
90 
91  ZMuMuAna = cfg.Analyzer(
92  "ZMuMuAnalyzer",
93  pt1 = 20,
94  pt2 = 20,
95  iso1 = 0.1,
96  iso2 = 0.1,
97  eta1 = 2,
98  eta2 = 2,
99  m_min = 0,
100  m_max = 200
101  )
102 
103  Any kinds of keyword arguments can be added.
104  The name must be present, and must be well chosen, as it will be used
105  by the Looper to find the module containing the Analyzer class.
106  This module should be in your PYTHONPATH. If not, modify your python path
107  accordingly in your script.
108  '''
109 
110  self.class_object = class_object
111  self.__class__.num_instance += 1
112  if instance_label is None:
113  instance_label = str(self.__class__.num_instance)
114  self.instance_label = instance_label
115  self.verbose = verbose
116  super(Analyzer, self).__init__(**kwargs)
117 
118  def __setattr__(self, name, value):
119  '''You may decide to copy an existing analyzer and change
120  its instance_label. In that case, one must stay consistent.'''
121  self.__dict__[name] = value
122  if name == 'instance_label':
123  self.name = self.build_name()
124 
125  def build_name(self):
126  class_name = '.'.join([self.class_object.__module__,
127  self.class_object.__name__])
128  name = '_'.join([class_name, self.instance_label])
129  return name
130 
131  def clone(self, **kwargs):
132  other = super(Analyzer, self).clone(**kwargs)
133  if 'class_object' in kwargs and 'name' not in kwargs:
134  other.name = other.build_name()
135  return other
136 
137 
138 class Service( CFG ):
139 
140  num_instance = 0
141 
142  def __init__(self, class_object, instance_label=None,
143  verbose=False, **kwargs):
144  self.class_object = class_object
145  self.__class__.num_instance += 1
146  if instance_label is None:
147  instance_label = str(self.__class__.num_instance)
148  self.instance_label = instance_label
149  self.__class__.num_instance += 1
150  self.name = self.build_name()
151  self.verbose = verbose
152  super(Service, self).__init__(**kwargs)
153 
154  def build_name(self):
155  class_name = '.'.join([self.class_object.__module__,
156  self.class_object.__name__])
157  name = '_'.join([class_name, self.instance_label])
158  return name
159 
160  def __setattr__(self, name, value):
161  '''You may decide to copy an existing analyzer and change
162  its instance_label. In that case, one must stay consistent.'''
163  self.__dict__[name] = value
164  if name == 'instance_label':
165  self.name = self.build_name()
166 
167  def clone(self, **kwargs):
168  other = super(Service, self).clone(**kwargs)
169  if 'class_object' in kwargs and 'name' not in kwargs:
170  other.name = other.build_name()
171  return other
172 
173 
174 class Sequence( list ):
175  '''A list with print functionalities.
176 
177  Used to define a sequence of analyzers.'''
178  def __str__(self):
179  tmp = []
180  for index, ana in enumerate( self ):
181  tmp.append( '{index} :'.format(index=index) )
182  tmp.append( '{ana} :'.format(ana=ana) )
183  return '\n'.join(tmp)
184 
185 #TODO review inheritance, and in particular constructor args - this is a mess.
186 
187 class Component( CFG ):
188  '''Base component class.
189 
190  See the child classes:
191  DataComponent, MCComponent, EmbedComponent
192  for more information.'''
193  def __init__(self, name, files, tree_name=None, triggers=None, **kwargs):
194  if isinstance(triggers, str):
195  triggers = [triggers]
196  if isinstance(files, str):
197  files = sorted(glob.glob(files))
198  super( Component, self).__init__( name = name,
199  files = files,
200  tree_name = tree_name,
201  triggers = triggers, **kwargs)
203  self.isData = False
204  self.isMC = False
205  self.isEmbed = False
206 
208 
209  def __init__(self, name, files, intLumi=None, triggers=[], json=None):
210  super(DataComponent, self).__init__(name, files, triggers=triggers)
211  self.isData = True
212  self.intLumi = intLumi
213  self.json = json
214 
215  def getWeight( self, intLumi = None):
216  return Weight( genNEvents = -1,
217  xSection = None,
218  genEff = -1,
219  intLumi = self.intLumi,
220  addWeight = 1. )
221 
222 
223 
225  def __init__(self, name, files, triggers=[], xSection=1,
226  nGenEvents=None,
227  effCorrFactor=None, **kwargs ):
228  super( MCComponent, self).__init__( name = name,
229  files = files,
230  triggers = triggers, **kwargs )
231  self.xSection = xSection
232  self.nGenEvents = nGenEvents
233  self.effCorrFactor = effCorrFactor
234  self.isMC = True
235  self.intLumi = 1.
236  self.addWeight = 1.
237 
238  def getWeight( self, intLumi = None):
239  # if intLumi is None:
240  # intLumi = Weight.FBINV
241  #COLIN THIS WEIGHT STUFF IS REALLY BAD!!
242  # use the existing Weight class or not? guess so...
243  return Weight( genNEvents = self.nGenEvents,
244  xSection = self.xSection,
245  intLumi = self.intLumi,
246  genEff = 1/self.effCorrFactor,
247  addWeight = self.addWeight )
248 
249 class Config( object ):
250  '''Main configuration object, holds a sequence of analyzers, and
251  a list of components.'''
252  def __init__(self, components, sequence, services, events_class,preprocessor=None):
253  self.preprocessor = preprocessor
254  self.components = components
255  self.sequence = sequence
256  self.services = services
257  self.events_class = events_class
258 
259  def __str__(self):
260  comp = '\n'.join(map(str, self.components))
261  sequence = str(self.sequence)
262  services = '\n'.join( map(str, self.services))
263  return '\n'.join([comp, sequence, services])
264 
265 
def __init__(self, components, sequence, services, events_class, preprocessor=None)
Definition: config.py:252
def clone(self, kwargs)
Definition: config.py:131
def __init__(self, name, files, triggers=[], xSection=1, nGenEvents=None, effCorrFactor=None, kwargs)
Definition: config.py:227
def getWeight(self, intLumi=None)
Definition: config.py:215
def __str__(self)
Definition: config.py:42
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:66
def printComps(comps, details=False)
Definition: config.py:11
def __setattr__(self, name, value)
Definition: config.py:160
def __init__(self, name, files, intLumi=None, triggers=[], json=None)
Definition: config.py:209
def __init__(self, class_object, instance_label=None, verbose=False, kwargs)
Definition: config.py:143
def clone(self, kwargs)
Definition: config.py:167
def __str__(self)
Definition: config.py:259
static std::string join(char **cmd)
Definition: RemoteFile.cc:18
def build_name(self)
Definition: config.py:125
def build_name(self)
Definition: config.py:154
def __str__(self)
Definition: config.py:178
def getWeight(self, intLumi=None)
Definition: config.py:238
def __init__(self, name, files, tree_name=None, triggers=None, kwargs)
Definition: config.py:193
def __init__(self, class_object, instance_label=None, verbose=False, kwargs)
Definition: config.py:86
def __setattr__(self, name, value)
Definition: config.py:118
def __init__(self, kwargs)
Definition: config.py:38
def clone(self, kwargs)
Definition: config.py:53
#define str(s)
How EventSelector::AcceptEvent() decides whether to accept an event for output otherwise it is excluding the probing of A single or multiple positive and the trigger will pass if any such matching triggers are PASS or EXCEPTION[A criterion thatmatches no triggers at all is detected and causes a throw.] A single negative with an expectation of appropriate bit checking in the decision and the trigger will pass if any such matching triggers are FAIL or EXCEPTION A wildcarded negative criterion that matches more than one trigger in the trigger list("!*","!HLTx*"if it matches 2 triggers or more) will accept the event if all the matching triggers are FAIL.It will reject the event if any of the triggers are PASS or EXCEPTION(this matches the behavior of"!*"before the partial wildcard feature was incorporated).Triggers which are in the READY state are completely ignored.(READY should never be returned since the trigger paths have been run