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