ATLAS Offline Software
common.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2 
3 #
4 # File: CaloClusterCorrection/python/common.py
5 # Created: Nov 2006, sss
6 # Purpose: Common utility code for configuring cluster corrections.
7 #
8 
9 from __future__ import print_function
10 
11 from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
12 from AthenaConfiguration.ComponentFactory import CompFactory
13 from AthenaCommon.Logging import logging
14 from fnmatch import fnmatchcase
15 
16 from CaloClusterCorrection.poolfiles import poolfiles
17 
18 from CaloClusterCorrection.constants import \
19  CALOCORR_JO, CALOCORR_POOL, CALOCORR_COOL, \
20  CALOCORR_NOPOOL, CALOCORR_TOPOOL, CALOCORR_DEFAULT_KEY, \
21  sampnames
22 
23 # Used for reporting configuration errors.
24 class CaloCorrectionConfigError (Exception):
25  pass
26 
27 # Keep track of pool files we're already seen.
28 _poolfiles_seen = {}
29 
30 # Keep track of pool folders we've used.
31 _folders_used = {}
32 
33 # Keep track of all tool names, to prevent duplicates.
34 # The value is a (folder, tag, sgkey) tuple.
35 _alltools = {}
36 
37 
38 
39 
121 
122 
123 # Helper: Split up a version specifier SPEC.
124 # Returns (FUNC, VERSION, ORDER, EXTRA_ARGS)
125 def split_version_spec (cspec):
126  func = cspec[0]
127  version = ''
128  order = 0
129  ii = 1
130  if ii < len(cspec) and isinstance (cspec[ii], str):
131  version = cspec[ii]
132  ii += 1
133  if ii < len(cspec) and isinstance (cspec[ii], int):
134  order = cspec[ii]
135  ii += 1
136  extra_args = cspec[ii:]
137  return (func, version, order, extra_args)
138 
139 
140 # Given a cool tag (or GLOBAL for the currently-configured global tag),
141 # return the version of the correction set to use.
142 def _find_version_from_cool_tag (flags, coolTag, corrclass):
143  if coolTag == 'GLOBAL':
144  coolTag = flags.IOVDb.GlobalTag
145 
146  if flags.Input.isMC:
147  folderset = "/CALO/Ofl/" + corrclass
148  connstring = 'COOLOFL_CALO/OFLP200'
149  else:
150  folderset = "/CALO/" + corrclass
151  connstring = 'COOLONL_CALO/' + flags.IOVDb.DatabaseInstance
152 
153  from CoolConvUtilities import AtlCoolLib
154  db = AtlCoolLib.indirectOpen (connstring, readOnly=True)
155  ff = db.getFolderSet (folderset)
156  t = ff.resolveTag (coolTag)
157  # CaloOflSwClusterCorrections.00-02-12-calhits-v9
158  l = t.split ('-')
159  return '-'.join (l[4:])
160 
161 
163  # Must be overridden in derived classes. See above for their meaning.
164  # name = XXX
165  # version_override_flag_name = XXX
166  # correction_generation_flag_name = XXX
167  # correction_generation_default = XXX
168  # versions = XXX
169  # geom_versions = XXX
170  # newest_version = XXX
171 
172  #
173  # Create and return a CA of correction tools.
174  # FLAGS is the configuration flags.
175  # CORRCLASS is the correction class string, as defined in constants.py.
176  # KEY is a string that specifies the correction type.
177  # SUFFIX is a string to add to the end of each tool name.
178  # VERSION specifies which version of corrections to use.
179  # VERSION may also be of the form `@TAG' to force a specific COOL tag TAG,
180  # or it may be `@GLOBAL' to use to globally-configured COOL tag.
181  # In such cases, if there's no direct match of the version string
182  # in the version table, we look for one with a version of `@'.
183  # If no match for that is found, the last entry in the table
184  # will be used.
185  # CORRLIST can be used to explicitly specify which corrections to run.
186  # CELLS_NAME is the SG key to use to find the calorimeter cells,
187  # for those corrections that require it.
188  # SOURCE specifies the source(s) from which tools are configured.
189  # None means to use the default.
190  #
191  def make_corrections (self,
192  flags,
193  corrclass,
194  key = None,
195  suffix = '',
196  version = None,
197  corrlist = None,
198  cells_name = None,
199  source = None,
200  **kw):
201 
202  # Make a logger.
203  log = logging.getLogger ('CaloClusterCorrection')
204 
205  tryhier = False
206 
207  # First, find the appropriate overall version string to use,
208  # if it wasn't specified explicitly.
209  if version is None:
210  # First see if the flag was set to override the version.
211  # at the top-level.
212  v = getattr (flags.Calo.ClusterCorrection, self.version_override_flag_name)
213  if v:
214  version = v
215 
216  if version is None:
217  # No explicitly specified version.
218  # Try to guess it from the data source + geometry string.
219  # Otherwise, use the latest version.
220  geom = flags.GeoModel.AtlasVersion
221  datasource = 'geant4' if flags.Input.isMC else 'data'
222  (version, tryhier) = self.geom_match (datasource, geom)
223 
224  # Get the correction generation.
225  generation = self.get_generation(flags)
226 
227  # Use the default source if one wasn't specified.
228  if source is None:
229  source = flags.Calo.ClusterCorrection.defaultSource
230 
231  if not isinstance (source, list):
232  source = [source]
233  if CALOCORR_COOL not in source:
234  tryhier = False
235 
236  if tryhier and version[0] != '@':
237  cl = corrclass
238  if flags.Input.isMC:
239  cl = cl[0:4] + 'Ofl' + cl[4:]
240  version = "@%s-%s%s" % (cl, generation, version)
241 
242  # Only use COOL if we're actually trying to resolve a COOL tag.
243  # Otherwise we can run into problems: it looks like `ununsed'
244  # COOL tags are removed in DB replicas.
245  if version[0] != '@' and len(source) > 0:
246  if CALOCORR_COOL in source:
247  source.remove (CALOCORR_COOL)
248 
249  (vcorrlist, version) = self.lookup_version (flags, version, corrclass)
250 
251  # Default to the standard list if no explicit correction list.
252  if corrlist is None:
253  corrlist = vcorrlist
254 
255  log.info ("%s corrections for %s (%s) using version %s" %
256  (self.name, key, suffix, version))
257 
258  # Now, walk through the list of corrections.
259  out = ComponentAccumulator()
260  tools = []
261  for cspec in corrlist:
262  (func, this_version, this_order, extra_args) = \
263  split_version_spec (cspec)
264 
265  # If the version or extra args isn't specified here,
266  # look in the internal corrlist to see if we find it there.
267  if this_version == '' or extra_args == []:
268  for vcspec in vcorrlist:
269  if vcspec[0] == func:
270  (vfunc, vversion, vorder, vextra_args) = \
271  split_version_spec (vcspec)
272  if this_version == '':
273  this_version = vversion
274  if extra_args == []:
275  extra_args = vextra_args
276  if this_order == 0:
277  this_order = vorder
278  break
279 
280  elif version[0] == '@' and not corrlist:
281  this_version = version #pragma: NO COVER
282 
283  if this_version == '@':
284  this_version = version
285 
286  # Start building the other variables to use in the call.
287  this_args = dict (extra_args)
288  this_key = key
289  this_suffix = suffix
290  this_cells_name = cells_name
291  this_source = source
292 
293  corrname = func.__name__
294 
295  # Look for any overriders in our keyword list.
296  for (k, v) in kw.items():
297  if k == corrname + '_suffix':
298  this_suffix = v
299  elif k == corrname + '_key':
300  this_key = v
301  elif k == corrname + '_cells_name':
302  this_cells_name = v
303  elif k == corrname + '_source':
304  this_source = v
305  elif k == corrname + '_version':
306  this_version = v
307  elif k == corrname + '_order':
308  this_order = v
309  elif k.startswith (corrname + '_'):
310  this_args[k[len(corrname)+1:]] = v
311 
312  # Make the tool.
313  ca = func (flags,
314  this_cells_name,
315  this_suffix,
316  this_version,
317  this_key,
318  this_source,
319  generation = generation,
320  order = this_order,
321  **this_args)
322  tools.append (out.popToolsAndMerge (ca))
323 
324  out.setPrivateTools (tools)
325  return out
326 
327 
328  # Look up a specific correction version; return the correction
329  # list and the version. Broken out to allow overriding, for
330  # any special version-name handling needed.
331  def lookup_version (self, flags, version, corrclass):
332  vcorrlist = self.versions.get (version)
333  if vcorrlist is None and version.startswith ('@'):
334  findvers = _find_version_from_cool_tag (flags, version[1:], corrclass)
335  vcorrlist = self.versions.get (findvers)
336  if vcorrlist is None:
337  vcorrlist = self.versions.get ('@')
338  if vcorrlist is None:
339  raise CaloCorrectionConfigError\
340  ("Can't find global correction version %s." % version)
341  return (vcorrlist, version)
342 
343 
344  # Match a data source + geometry string against geom_versions.
345  def _geom_match1 (self, geom):
346  for (pat, v) in self.geom_versions:
347  if fnmatchcase (geom, pat):
348  return v
349  return None
350  def geom_match (self, datasource, geom):
351  if not geom: geom = ''
352  vv = self._geom_match1 (datasource + '-' + geom)
353  if not vv:
354  vv = self._geom_match1 (geom)
355  if not vv:
356  vv = self.newest_version
357  tryhier = True
358  if vv.startswith ('NOHIER#'):
359  tryhier = False
360  vv = vv[7:]
361  return (vv, tryhier)
362 
363 
364  # Get the correction generation, with a `-' appended if appropriate.
365  @classmethod
366  def get_generation (cls, flags):
367  generation = cls.correction_generation_default
368  gen2 = getattr (flags.Calo.ClusterCorrection, cls.correction_generation_flag_name)
369  if gen2:
370  generation = gen2
371  if generation != '':
372  generation = generation + '-'
373  return generation
374 
375 
376 
379 
380  def make_ForPool (self, flags, keys, corrclass):
381  # Map from SG key to a list of tool instances.
382  sgkeys = {}
383 
384  # Names of all tools made so far
385  tool_names = set()
386 
387  # Map from (func, version) to (order, globversion).
388  # For consistency checking.
389  ordermap = {}
390 
391  result = ComponentAccumulator()
392  tools = []
393 
394  # Go through each version, and make corrections.
395  for (v,l) in self.versions.items():
396  if v.startswith ('@'): continue
397  last_order = 0
398  last_funcname = '(none)'
399  for c in l:
400  # Consistency check: tool lists should be sorted in order.
401  (func, version, order, extra_args) = split_version_spec (c)
402  if order <= last_order:
403  raise CaloCorrectionConfigError\
404  ("Tools for global version %s are not in order!"
405  " %d(%s) < %d(%s)" % (v, order, func.__name__,
406  last_order, last_funcname))
407  last_order = order
408  last_funcname = func.__name__
409 
410  # Consistency check: a given tool func/version should
411  # always have the same order setting.
412  okey = (func, version)
413  if okey not in ordermap:
414  ordermap[okey] = (order, v)
415  elif ordermap[okey][0] != order:
416  raise CaloCorrectionConfigError\
417  ("Tool %s has order %d in %s but order %d in %s!" %
418  (func.__name__, order, v,
419  ordermap[okey][0], ordermap[okey][1]))
420 
421  # Find the list of valid keys for this tool.
422  valid_keys = func (flags,
423  None,
424  version = version,
425  key = '@VALID_KEYS')
426  if valid_keys is None:
427  valid_keys = keys
428  for key in valid_keys:
429  ca = self.maybe_make_correction_for_pool (flags,
430  sgkeys,
431  tool_names,
432  key, c,
433  corrclass)
434  if ca:
435  tools.append (ca.popPrivateTools())
436  result.merge (ca)
437 
438  result.setPrivateTools (tools)
439 
440  return (sgkeys, result)
441 
442 
444  sgkeys, tool_names, key, cspec,
445  corrclass):
446  (func, version, order, extra_args) = split_version_spec (cspec)
447  name = func.__name__ + '_' + version + '_' + key
448  if name in tool_names:
449  return None
450  ca = func (flags,
451  None, '', version, key, CALOCORR_TOPOOL,
452  generation = self.get_generation (flags),
453  order = order)
454  if ca is None:
455  return None
456  tool = ca.popPrivateTools()
457  if tool is not None and folder(tool).find ('/' + corrclass + '/') >= 0:
458  tool_names.add (name)
459  sgkeys.setdefault (sgkey(tool), []).append (tool)
460  ca.setPrivateTools (tool)
461  return ca
462 
463 
464  # Add a dummy correction object to each folder.
465  def add_dummies (self, sgkeys, valid_keys, generation):
466  CaloDummyCorrection = CompFactory.CaloDummyCorrection # CaloClusterCorrection
467  toolnames = {}
468  for sgkey in sgkeys.keys():
469  ll = sgkey.split ('-')
470  if len(ll) == 1:
471  name = ll[0]
472  else:
473  (name, ver) = ll
474  toolnames[name] = 1
475  for name in toolnames.keys():
476  (corrclass, basename) = name.split ('.')
477  sgkey = name + '-dummy'
478  tagname = "%s.%s%s-dummy" % (corrclass, generation, basename)
479  folder = '/CALO/%s/%s' % (corrclass, basename)
480  sgkeys[sgkey] = []
481  for key in valid_keys:
482  toolname = basename + key + '-dummy'
483  tool = CaloDummyCorrection (toolname)
484  tool.prefix = key + '.'
485  sgkeys[sgkey].append (tool)
486  _alltools[toolname] = (folder, tagname, sgkey)
487  return
488 
489 
490  # Configure algorithms for writing to pool.
491  def config_for_pool (self, flags, keys, corrclass):
492  result = ComponentAccumulator()
493 
494  corr_output_list = []
495  tag_list = []
496 
497  generation = self.get_generation (flags)
498 
499  (sgkeys, ca) = self.make_ForPool (flags, keys, corrclass)
500  ca.popPrivateTools()
501  result.merge (ca)
502  self.add_dummies (sgkeys, keys, generation)
503 
504  for (sgkey, tools) in sgkeys.items():
505  if len (tools) == 0: continue
506  name = 'write_' + sgkey
507  name = name.replace ('.', '_')
508 
509  # In CaloRec
510  alg = CompFactory.CaloClusterCorrDBWriter (name,
511  key = sgkey,
512  ClusterCorrectionTools = tools)
513  result.addEventAlgo (alg)
514 
515 
516  corr_output_list.append ('CaloRec::ToolConstants#' +
517  sgkey + '#' +
518  folder (tools[0]))
519  tag_list.append (tag (tools[0]))
520 
521  print ("Final OutputList:")
522  print (corr_output_list)
523  print (tag_list)
524 
525  return (corr_output_list, tag_list, result)
526 
527 
528 
529 
530 #
531 # Create a correction tool.
532 # FLAGS is the corrections flag object.
533 # VERSIONS is a table listing all the available versions of the corrections.
534 # It is a list of 4-element lists. The last row should correspond to the
535 # most recent version of the correction.
536 # The first column is the version name.
537 # The second column is the Configurable class for the class which implements
538 # the correction. This may also be a dictionary, to be indexed by
539 # a calorimeter sampling.
540 # The third column is a list containing the possible sources for this tool.
541 # This list may contain any of the following:
542 #
543 # - A string giving the name of the parameter class used to initialize
544 # the correction tool via job options. It should be of the form
545 # `MODULE.CLASS'. If MODULE has no dots, we look for it in
546 # CaloClusterCorrection.
547 #
548 # - A string defined in poolfiles, giving the name of a pool file
549 # that contains this correction.
550 #
551 # - The string CALOCORR_COOL, indicating that this correction is available
552 # in COOL.
553 #
554 # - The string CALOCORR_NOPOOL, indicating that this tool is not
555 # to be written to pool/cool (always gets initialized via job options).
556 #
557 # In the case of reading from job options, we look up the specified name.
558 # If this is a dictionary, we look up the requested sampling in the dictionary.
559 # We should then have a class; the names in this class are the parameter
560 # settings to make. If any of them are dictionaries, then we look up the key
561 # in the dictionary.
562 #
563 # In the case of reading from cool, we construct folder and tag names
564 # with the following formats:
565 #
566 # /CALO/<class>/<basename>
567 # <class>.<basename>-<version>
568 #
569 # and a prefix in the format:
570 #
571 # <key><sampling>.
572 #
573 # If we've already read a different version of this correction from
574 # the folder, then the read from cool fails (but we can fall back
575 # on a direct pool read or initialization from job options).
576 # Otherwise, we arrange to read this object; the StoreGate key
577 # will be the same as the folder name.
578 #
579 # In the case of reading from pool, the StoreGate key will be the same
580 # as the tag name we formed above.
581 #
582 # The fourth column is a list of cluster type keys that are valid for
583 # this correction. When reading from pool, if the key we're given doesn't
584 # match one on this list, we replace it with the longest match (first
585 # one wins on ties) from this list. Set this to None or omit it
586 # to skip this.
587 #
588 # NAME is the base name for this tool, excluding the suffix. If set to None,
589 # a name will be constructed from the name of the correction, the version,
590 # the key, and the sampling (if applicable).
591 #
592 # BASENAME is the base name for the correction: a string like `gap',
593 # `etaoff', etc.
594 #
595 # If SUFFIX is not None, it will be added onto the end of the tool name.
596 #
597 # VERSION is a string specifying which of several versions of the correction
598 # to choose. If set to None, the latest version of the correction is chosen.
599 # VERSION may also be of the form `@TAG' to force a specific COOL tag TAG,
600 # or it may be `@GLOBAL' to use to globally-configured COOL tag.
601 # In such cases, if there's no direct match of the version string
602 # in the version table, we look for one with a version of `@'.
603 # If no match for that is found, the last entry in the table
604 # will be used.
605 #
606 # KEY is a string to specify the type of cluster to which the correction
607 # applies. The convention is to use `ele55' for 5x5 electron clusters,
608 # `gam35' for 3x5 photon clusters, and so on.
609 # If KEY is the special string `@VALID_KEYS', then we do not create
610 # a tool. Instead, we return the list of keys that are declared
611 # to be valid for this tool (or None, if none were).
612 #
613 # Some corrections have different tools for different calorimeter samplings.
614 # If this is the case for this correction, SAMPLING should be set to the
615 # applicable sampling. Otherwise, set it to None.
616 #
617 # SOURCE tells from where we should read the calibration constants.
618 # CALOCORR_JO means to read the constants from job options.
619 # Look in the correction's source list to find the parameter class.
620 # CALOCORR_POOL means to read the constants from a pool file.
621 # Look in the correction's source list to find the pool file.
622 # CALOCORR_COOL means to read from cool.
623 # A string of the form `MODULE.NAME' means to use this name
624 # as the parameter class.
625 # A string that's present in the poolfiles dictionary means to read
626 # from this pool file.
627 #
628 # SOURCE may also be a list of these, to try in order.
629 #
630 # SOURCE may also be CALOCORR_TOPOOL, meaning to construct a tool
631 # from job options appropriate for writing to a pool file.
632 #
633 # CONFCLASS gives the Configurable class to use to create the tool.
634 # If set to None, this is taken from the version table.
635 #
636 # CORRCLASS is the correction class string, as defined above.
637 #
638 # GENERATION is the generation string to embed in COOL tags.
639 #
640 # ORDER specifies the relative order in which this tool should be executed.
641 #
642 # Additional keyword arguments may be passed to override any tool
643 # parameters/constants.
644 #
645 def makecorr (flags,
646  versions,
647  name,
648  basename,
649  suffix,
650  version,
651  key,
652  sampling,
653  source,
654  confclass,
655  corrclass,
656  generation = '',
657  order = 0,
658  **kw):
659 
660  # If no version specified, use the last one in the table.
661  if version is None:
662  version = versions[-1][0]
663 
664  # Try to find the requested version.
665  for v in versions:
666  if v[0] == version:
667  break
668  else:
669  if version.startswith ('@'):
670  # A COOL tag is requested.
671  # Look for a table entry of `@'; otherwise, use the last entry.
672  for v in versions:
673  if v[0] == '@':
674  break
675  else:
676  v = versions[-1]
677  else:
678  raise CaloCorrectionConfigError \
679  ("Can't find version `%s' for correction named `%s'." %
680  (version, basename))
681 
682  # The valid keys.
683  valid_keys = None
684  if len (v) >= 4:
685  valid_keys = v[3]
686 
687  # Handle @VALID_KEYS request.
688  if key == '@VALID_KEYS':
689  return valid_keys
690 
691  # Use the default source if one wasn't specified.
692  if source is None:
693  source = flags.Calo.ClusterCorrection.defaultSource
694 
695  # Test to see if this correction specifies nopool.
696  nopool = CALOCORR_NOPOOL in v[2]
697 
698  # Don't try to write a nopool tool to pool.
699  if nopool and source == CALOCORR_TOPOOL:
700  return None
701 
702  # Find the SG key and cool tag.
703  if version.startswith ('@'):
704  sgkey = None
705  if version == '@GLOBAL':
706  fulltag = version
707  else:
708  fulltag = version[1:]
709 
710  if not nopool:
711  # Must read from cool in this case.
712  source = CALOCORR_COOL
713  else:
714  # Construct the SG key name.
715  tmp = basename
716  if version != '':
717  tmp = tmp + "-" + version
718  sgkey = "%s.%s" % (corrclass, tmp)
719  fulltag = "%s.%s%s" % (corrclass, generation, tmp)
720  if flags.Input.isMC:
721  fulltag = fulltag[0:4] + 'Ofl' + fulltag[4:]
722 
723  # The cool folder name.
724  if not flags.Input.isMC:
725  folder = "/CALO/%s/%s" % (corrclass, basename)
726  else:
727  folder = "/CALO/Ofl/%s/%s" % (corrclass, basename)
728 
729  # Prefix to locate constants in the ToolConstants block.
730  prefix = key + sampnames[sampling] + "."
731 
732  # Construct a default tool name if one isn't specified.
733  if name is None:
734  name = basename
735  name = name + sampnames[sampling]
736  if version != '':
737  vv = version
738  if vv[0] == '@':
739  vv = vv[1:]
740  vv = vv.split('-')[-1]
741  name = name + "_" + vv
742  if key != '':
743  name = name + "_" + key
744 
745  # Add a suffix if given.
746  if suffix is not None:
747  name = name + suffix
748 
749  # If this tool was defined earlier, check consistency.
750  if name in _alltools:
751  if _alltools[name] != (folder, fulltag, sgkey):
752  raise CaloCorrectionConfigError ( #pragma: NO COVER
753  "Inconsistent configuration of tool %s. Old (folder,tag,sgkey)=%s; new=%s" % #pragma: NO COVER
754  (name, _alltools[name], (folder, fulltag, sgkey))) #pragma: NO COVER
755  else:
756  _alltools[name] = (folder, fulltag, sgkey)
757 
758  # If no class was explicitly specified, take it from the table.
759  if confclass is None:
760  confclass = v[1]
761 
762  # It may be sampling-dependent.
763  if isinstance (confclass, dict) and sampling is not None:
764  confclass = confclass[sampling]
765 
766  result = ComponentAccumulator()
767 
768  # Create the tool!
769  corr = confclass (name)
770 
771  # Set the prefix for all pool-capable tools.
772  if not nopool:
773  corr.prefix = prefix
774 
775  # Try to find a source from which to configure it.
776  if not isinstance (source, list):
777  source = [source]
778  avail = v[2]
779  wherefrom = None
780  for s in source:
781  if s == CALOCORR_JO or s == CALOCORR_TOPOOL:
782  sel = [x for x in avail if _is_jo_source (x)]
783  if len (sel) > 0 and _config_from_jo(corr, sel[0], key,
784  sampling , valid_keys,
785  order):
786  wherefrom = sel[0]
787  break
788 
789  elif s == CALOCORR_POOL:
790  sel = [x for x in avail if _is_pool_source (x)]
791  if len (sel) > 0:
792  ca2 = _config_from_pool (flags, corr, sel[0], sgkey)
793  if ca2:
794  result.merge (ca2)
795  _mung_prefix (corr, key, valid_keys)
796  wherefrom = sel[0]
797  break
798 
799  elif s == CALOCORR_COOL:
800  sel = [x for x in avail if _is_cool_source (x)]
801  if len (sel) > 0:
802  ca2 = _config_from_cool (flags, corr, folder, fulltag)
803  if ca2:
804  result.merge (ca2)
805  _mung_prefix (corr, key, valid_keys)
806  wherefrom = 'cool'
807  break
808 
809  elif _is_jo_source (s):
810  if _config_from_jo (corr, s, key, sampling, valid_keys, order):
811  wherefrom = s
812  break
813 
814  elif _is_pool_source (s):
815  ca2 = _config_from_pool (flags, corr, s, sgkey)
816  if ca2:
817  result.merge (ca2)
818  _mung_prefix (corr, key, valid_keys)
819  wherefrom = s
820  break
821 
822  if wherefrom is None:
823  raise CaloCorrectionConfigError \
824  ("Can't find any source to configure tool `%s'. Sources: %s" %
825  (name, source))
826 
827  log = logging.getLogger ('CaloClusterCorrection')
828  log.debug (" correction %s (%s, from %s)" % (name, confclass.__name__,
829  wherefrom))
830 
831  # If any other keyword arguments were passed, make those assignments.
832  # This will override anything otherwise read from JO/pool.
833  for (k, val) in kw.items():
834  if val is not None:
835  setattr (corr, k, val)
836 
837  # Done!
838  result.setPrivateTools (corr)
839  return result
840 
841 
842 # Test to see if S looks like a job options source.
844  if s == CALOCORR_COOL: return 0
845  if s == CALOCORR_POOL: return 0
846  if s in poolfiles: return 0
847  if s.find ('.') > 0: return 1
848  return 0
849 
850 
851 # Test to see if S looks like a pool source.
853  return s in poolfiles
854 
855 
856 # Test to see if S looks like a cool source.
858  return s == CALOCORR_COOL
859 
860 
861 # Configure a correction tool from job options.
862 def _config_from_jo (corr, jo, key, sampling, valid_keys, order):
863  # Split off the last dotted field as paramclass.
864  xjo = jo.split ('.')
865  paramclass = xjo[-1]
866  modname = '.'.join (xjo[:-1])
867 
868  # If not otherwise specified, try to find the module
869  # in CaloClusterCorrection.
870  if modname.find ('.') < 0:
871  modname = 'CaloClusterCorrection.' + modname
872 
873  # Import the module and look up the class.
874  mod = __import__ (modname, globals(), locals(), [paramclass])
875  parms = getattr (mod, paramclass)
876 
877  # It may be sampling-dependent.
878  if isinstance (parms, dict) and sampling is not None:
879  parms = parms[sampling]
880 
881  if order != 0 and hasattr (corr, 'order'):
882  corr.order = order
883  if hasattr (corr, 'isDummy'):
884  corr.isDummy = 0
885 
886  log = logging.getLogger ('CaloClusterCorrection')
887 
888  # Go through the names in the class and assign them to the tool.
889  for (k, val) in parms.__dict__.items():
890  # Skip internal names.
891  if k[0] != '_':
892  try:
893  # First try looking up the key.
894  # Note: don't test on val's type here --- it may
895  # be an object instance that implements __getitem__.
896  # We have to try the lookup and catch the error.
897  val = val[key]
898  except KeyError:
899  # We can do a lookup, but didn't find the key.
900  # Use the default key instead.
901  default_keys = parms.__dict__.get ('_default_keys')
902  if default_keys:
903  defkey = _longest_match (key, default_keys)
904  elif valid_keys:
905  defkey = _longest_match (key, valid_keys)
906  else:
907  defkey = CALOCORR_DEFAULT_KEY
908  val = val[defkey]
909 
910  log.debug (" correction %s from JO using %s instead of %s" %
911  (corr.getName(), defkey, key))
912 
913  except TypeError:
914  # Can't look up a key in val --- just use val as-is.
915  pass
916 
917  setattr (corr, k, val)
918  return True
919 
920 
921 # Configure a correction tool from POOL.
922 def _config_from_pool (flags, corr, poolfile, sgkey):
923  if not poolfile or not poolfiles[poolfile]:
924  return False
925 
926  ca = ComponentAccumulator()
927 
928  # If this is the first time we've seen this file,
929  # add it to CondProxyProvider.
930  if poolfile not in _poolfiles_seen:
931  from EventSelectorAthenaPool.CondProxyProviderConfig import CondProxyProviderCfg
932  ca.merge (CondProxyProviderCfg (flags, [poolfiles[poolfile]]))
933 
934  # Tell the tool to look in pool for this key.
935  corr.DBHandleKey = sgkey
936 
937  # Set up a conditions algorithm to convert from the data in DetectorStore
938  # to a conditions object.
939  ToolConstantsCondAlg = CompFactory.ToolConstantsCondAlg # CaloRec
940 
941  name = 'ToolConstantsCondAlg_' + sgkey.replace ('.', '_')
942  alg = ToolConstantsCondAlg (name,
943  DetStoreKey = sgkey,
944  ToolConstantsKey = sgkey)
945  ca.addCondAlgo (alg)
946  return ca
947 
948 
949 # Configure a correction tool from COOL.
950 def _config_from_cool (flags, corr, folder, tag):
951  # Folder name has form /CALO/CORRCLASS/NAME
952  # Find the subdetector name string to use.
953  fsplit = folder.split ('/')
954  if fsplit[2] == 'Ofl':
955  corrclass = folder.split ('/')[4]
956  else:
957  corrclass = folder.split ('/')[3]
958  sndict = flags.Calo.ClusterCorrection.dbSubdetName
959  subdetname = sndict.get (corrclass)
960  if not subdetname:
961  subdetname = sndict.get (None)
962 
963  corr.DBHandleKey = folder
964 
965  # We can't use more than one tag from a folder.
966  oldtag = _folders_used.get (folder)
967  if oldtag is not None and oldtag != tag:
968  return False
969 
970  ca = ComponentAccumulator()
971 
972  _folders_used[folder] = tag
973  if oldtag is None:
974  from IOVDbSvc.IOVDbSvcConfig import addFolders
975  tagstr = '' if tag =='@GLOBAL' else tag
976  sdsuffix = '_OFL' if 'Ofl' in folder else ''
977  ca.merge (addFolders (flags,
978  folder,
979  detDb = subdetname + sdsuffix,
980  className = 'CaloRec::ToolConstants',
981  tag = tagstr))
982 
983  log = logging.getLogger ('CaloClusterCorrection')
984  log.debug ("Adding cool folder `%s' for subdetector name %s" %
985  (folder, subdetname))
986  return ca
987 
988 
989 # When we're reading from pool/cool, the prefix _must_ be one that
990 # exists in the file. Here, we see if the key is on the list of known
991 # keys. If not, then we substitute.
992 def _matchlen (a, b):
993  i = 0
994  while i < len(a) and i < len(b) and a[i] == b[i]:
995  i = i+1
996  return i
997 def _longest_match (key, valid_keys):
998  if not isinstance (valid_keys, list):
999  valid_keys = [valid_keys]
1000  if valid_keys is None or key in valid_keys:
1001  return key
1002  new_key = valid_keys[0]
1003  for k in valid_keys[1:]:
1004  if _matchlen (key, k) > _matchlen (key, new_key):
1005  new_key = k
1006  return new_key
1007 def _mung_prefix (corr, key, valid_keys):
1008  if valid_keys is None or key in valid_keys: return
1009 
1010  # Find the best match.
1011  new_key = _longest_match (key, valid_keys)
1012 
1013  new_prefix = new_key + corr.prefix[len(key):]
1014  corr.prefix = new_prefix
1015  return
1016 
1017 # Return the folder for a tool.
1018 def folder (tool):
1019  return _alltools[tool.getName()][0]
1020 
1021 
1022 # Return the tag for a tool.
1023 def tag (tool):
1024  return _alltools[tool.getName()][1]
1025 
1026 
1027 # Return the SG key for a tool.
1028 def sgkey (tool):
1029  return _alltools[tool.getName()][2]
1030 
1031 
1032 
common.CaloClusterCorrSetup.geom_match
def geom_match(self, datasource, geom)
Definition: common.py:350
common.CaloClusterCorrSetup.config_for_pool
def config_for_pool(self, flags, keys, corrclass)
Definition: common.py:491
common.makecorr
def makecorr(flags, versions, name, basename, suffix, version, key, sampling, source, confclass, corrclass, generation='', order=0, **kw)
Definition: common.py:645
common.sgkey
def sgkey(tool)
Definition: common.py:1028
python.JetAnalysisCommon.ComponentAccumulator
ComponentAccumulator
Definition: JetAnalysisCommon.py:302
common._config_from_pool
def _config_from_pool(flags, corr, poolfile, sgkey)
Definition: common.py:922
common._longest_match
def _longest_match(key, valid_keys)
Definition: common.py:997
common._mung_prefix
def _mung_prefix(corr, key, valid_keys)
Definition: common.py:1007
common.CaloClusterCorrSetup._geom_match1
def _geom_match1(self, geom)
Definition: common.py:345
common.split_version_spec
def split_version_spec(cspec)
Code to handle creating the list of correction tools.
Definition: common.py:125
common.CaloClusterCorrSetup.lookup_version
def lookup_version(self, flags, version, corrclass)
Definition: common.py:331
common._find_version_from_cool_tag
def _find_version_from_cool_tag(flags, coolTag, corrclass)
Definition: common.py:142
common.CaloClusterCorrSetup
Definition: common.py:162
common.CaloCorrectionConfigError
Definition: common.py:24
common.CaloClusterCorrSetup.maybe_make_correction_for_pool
def maybe_make_correction_for_pool(self, flags, sgkeys, tool_names, key, cspec, corrclass)
Definition: common.py:443
common._config_from_jo
def _config_from_jo(corr, jo, key, sampling, valid_keys, order)
Definition: common.py:862
common._is_jo_source
def _is_jo_source(s)
Definition: common.py:843
common._is_pool_source
def _is_pool_source(s)
Definition: common.py:852
CxxUtils::set
constexpr std::enable_if_t< is_bitmask_v< E >, E & > set(E &lhs, E rhs)
Convenience function to set bits in a class enum bitmask.
Definition: bitmask.h:232
TrigJetMonitorAlgorithm.items
items
Definition: TrigJetMonitorAlgorithm.py:79
common.CaloClusterCorrSetup.get_generation
def get_generation(cls, flags)
Definition: common.py:366
common.CaloClusterCorrSetup.add_dummies
def add_dummies(self, sgkeys, valid_keys, generation)
Definition: common.py:465
common._matchlen
def _matchlen(a, b)
Definition: common.py:992
common.CaloClusterCorrSetup.make_corrections
def make_corrections(self, flags, corrclass, key=None, suffix='', version=None, corrlist=None, cells_name=None, source=None, **kw)
Definition: common.py:191
common.tag
def tag(tool)
Definition: common.py:1023
common._config_from_cool
def _config_from_cool(flags, corr, folder, tag)
Definition: common.py:950
common.folder
def folder(tool)
Definition: common.py:1018
common.CaloClusterCorrSetup.make_ForPool
def make_ForPool(self, flags, keys, corrclass)
Code for writing to pool.
Definition: common.py:380
common._is_cool_source
def _is_cool_source(s)
Definition: common.py:857