ATLAS Offline Software
Functions | Variables
ChainMerging Namespace Reference

Functions

def mergeChainDefs (listOfChainDefs, chainDict, perSig_lengthOfChainConfigs=None)
 
def check_leg_lengths (perSig_lengthOfChainConfigs)
 
def mergeParallel (chainDefList, offset, leg_numbering=None, perSig_lengthOfChainConfigs=None)
 
def getMergedEmptyStepName (alignmentGroup, stepNumber, multiplicity, signature)
 
def getEmptySeqName (signature, step_number, alignGroup, order)
 
def isFullScanRoI (inputL1Nav)
 
def getCurrentAG (chainStep)
 
def serial_zip (allSteps, chainName, chainDefList, legOrdering)
 
def mergeSerial (chainDefList, chainDefListOrdering)
 
def checkStepContent (parallel_steps)
 
def makeCombinedStep (parallel_steps, stepNumber, chainDefList, allSteps=None, currentChainSteps=None, leg_numbering=None, alignment_group="")
 
def zip_longest_parallel (AllSteps, multiplicity, fillvalue=None)
 
def build_empty_sequences (emptyChainDicts, step_mult, caller, L1decisions, seqNames, chainName)
 

Variables

 log
 

Function Documentation

◆ build_empty_sequences()

def ChainMerging.build_empty_sequences (   emptyChainDicts,
  step_mult,
  caller,
  L1decisions,
  seqNames,
  chainName 
)

Definition at line 637 of file ChainMerging.py.

637 def build_empty_sequences(emptyChainDicts, step_mult, caller, L1decisions, seqNames, chainName):
638  emptySequences = []
639  for ileg in range(len(L1decisions)):
640  is_fs_string = 'FS' if isFullScanRoI(L1decisions[ileg]) else ''
641  sname = seqNames[ileg]+is_fs_string
642  log.debug("[%s] adding %s empty sequenc with name %s", caller, is_fs_string, sname)
643 
644  thisEmpty = createEmptyMenuSequenceCfg(flags=None, name=sname)
645  emptySequences += [functools.partial(thisEmpty, flags=None, name=sname)]
646 
647 
648  log.verbose("[%s] emptyChainDicts %s", caller, emptyChainDicts)
649  log.debug("[%s] %s has number of empty sequences %d and empty legs in stepDicts %d",
650  caller, chainName, len(emptySequences), len(emptyChainDicts))
651  if len(emptySequences) != len(emptyChainDicts):
652  log.error("[%s] %s has a different number of empty sequences/legs %d than stepDicts %d",
653  caller, chainName, len(emptySequences), len(emptyChainDicts))
654 
655  raise Exception(f"[{caller}] Cannot create this chain step, exiting.")
656 
657  for sd in emptyChainDicts:
658  if sd['signature'] == 'Jet' or sd['signature'] == 'Bjet':
659  step_mult += [1]
660  elif len(sd['chainParts']) != 1:
661  log.error("[%s] %s has chainParts has length != 1 within a leg! chain dictionary for this step: \n %s",
662  caller, chainName, sd)
663  raise Exception(f"[{caller}] Cannot create this chain step, exiting.")
664  else:
665  step_mult += [int(sd['chainParts'][0]['multiplicity'])]
666 
667  if len(emptySequences) != len(step_mult):
668  log.error("[%s] %s has a different number of empty sequences/legs %d than multiplicities %d",
669  caller, chainName, len(emptySequences), len(step_mult))
670  raise Exception(f"[{caller}] Cannot create this chain step, exiting.")
671 
672  log.verbose('[%s] step multiplicity %s',caller, step_mult)
673 
674 
675  return emptySequences

◆ check_leg_lengths()

def ChainMerging.check_leg_lengths (   perSig_lengthOfChainConfigs)

Definition at line 91 of file ChainMerging.py.

91 def check_leg_lengths(perSig_lengthOfChainConfigs):
92  if not perSig_lengthOfChainConfigs: #default is None
93  return "", -1
94  leg_length_dict = {}
95  for leg_lengths, leg_grps in perSig_lengthOfChainConfigs:
96  for grp, length in zip(leg_grps,leg_lengths):
97  if grp in leg_length_dict:
98  leg_length_dict[grp] += [length]
99  else:
100  leg_length_dict[grp] = [length]
101  found_mismatch = False
102  max_length = -1
103  mismatched_ag = ""
104  log.debug("[check_leg_lengths] leg lengths: %s",leg_length_dict)
105  for grp,lengths in leg_length_dict.items():
106  if len(set(lengths)) > 1: #a mismatch!
107  log.debug("[check_leg_lengths] found mismatch for %s given %s", grp, lengths)
108  if found_mismatch:
109  log.error("[check_leg_lengths] Second mismatch in the same chain! I don't know how to deal with this, please resolve. Chain leg lengths: %s",perSig_lengthOfChainConfigs)
110  log.error("[check_leg_lengths] Second mismatch in the same chain! lengths,grp: %s,%s",lengths, grp)
111  raise Exception("[are_lengths_mismatched] Cannot merge chain, exiting.")
112  found_mismatch = True
113  max_length = max(lengths)
114  mismatched_ag = grp
115 
116  return mismatched_ag, max_length
117 
118 

◆ checkStepContent()

def ChainMerging.checkStepContent (   parallel_steps)
return True if any step contains a real Sequence

Definition at line 428 of file ChainMerging.py.

428 def checkStepContent(parallel_steps):
429  """
430  return True if any step contains a real Sequence
431  """
432  for step in parallel_steps:
433  if step is None or step.isEmpty:
434  continue
435  for seq in step.sequenceGens:
436  if not isEmptySequenceCfg(seq):
437  return True
438  return False
439 

◆ getCurrentAG()

def ChainMerging.getCurrentAG (   chainStep)

Definition at line 264 of file ChainMerging.py.

264 def getCurrentAG(chainStep):
265  filled_seq_ag = []
266  for iseq,seq in enumerate(chainStep.sequenceGens):
267  # In the case of dummy configs, they are all empty
268  if isEmptySequenceCfg(seq):
269  continue
270  else:
271  # get the alignment group of the leg that is running a non-empty sequence
272  # if we double-serial merge enough this will have to be recursive. Throw an error here for now
273  # if the length is greater than one. I don't think this will ever come up
274  if len(set(cp['alignmentGroup'] for cp in chainStep.stepDicts[iseq]['chainParts'])) > 1:
275  log.error("[getCurrentAG] The leg has more than one chainPart (%s). Either the alignmentGroup property is bad or this is an unimplemented situation.",chainStep.stepDicts[iseq]['chainParts'])
276  raise Exception("[getCurrentAG] Not sure what is happening here, but I don't know what to do.")
277  filled_seq_ag += [chainStep.stepDicts[iseq]['chainParts'][0]['alignmentGroup']]
278 
279  if len(filled_seq_ag) == 0:
280  log.error("[getCurrentAG] No non-empty sequences were found in %s", chainStep.sequenceGens)
281  log.error("[getCurrentAG] The chainstep is %s", chainStep)
282  raise Exception("[getCurrentAG] Cannot find the current alignment group for this chain")
283  elif len(set(filled_seq_ag)) > 1:
284  log.error("[getCurrentAG] Found more than one alignment group for this step %s", filled_seq_ag)
285  raise Exception("[getCurrentAG] Cannot find the current alignment group for this chain")
286  else:
287  return filled_seq_ag[0]
288 

◆ getEmptySeqName()

def ChainMerging.getEmptySeqName (   signature,
  step_number,
  alignGroup,
  order 
)

Definition at line 251 of file ChainMerging.py.

251 def getEmptySeqName(signature, step_number, alignGroup,order):
252  seqName = 'Empty'+ alignGroup +'Seq'+str(step_number)+ '_'+ str(order) + signature
253  return seqName
254 
255 

◆ getMergedEmptyStepName()

def ChainMerging.getMergedEmptyStepName (   alignmentGroup,
  stepNumber,
  multiplicity,
  signature 
)

Definition at line 246 of file ChainMerging.py.

246 def getMergedEmptyStepName(alignmentGroup, stepNumber, multiplicity, signature):
247  currentStepName = 'Empty' + alignmentGroup +'Align'+str(stepNumber)+'_'+ str(multiplicity) + signature
248  return currentStepName
249 
250 

◆ isFullScanRoI()

def ChainMerging.isFullScanRoI (   inputL1Nav)

Definition at line 256 of file ChainMerging.py.

256 def isFullScanRoI(inputL1Nav):
257  fsRoIList = ['HLTNav_L1FSNOSEED','HLTNav_L1MET','HLTNav_L1J']
258  if inputL1Nav in fsRoIList:
259  return True
260  else:
261  return False
262 
263 

◆ makeCombinedStep()

def ChainMerging.makeCombinedStep (   parallel_steps,
  stepNumber,
  chainDefList,
  allSteps = None,
  currentChainSteps = None,
  leg_numbering = None,
  alignment_group = "" 
)

Definition at line 440 of file ChainMerging.py.

440 def makeCombinedStep(parallel_steps, stepNumber, chainDefList, allSteps = None, currentChainSteps = None, leg_numbering = None, alignment_group = ""):
441  # default mutable values must be initialized to None
442  if allSteps is None: allSteps = []
443  if currentChainSteps is None: currentChainSteps = []
444  if leg_numbering is None: leg_numbering =[]
445 
446  stepName = 'merged' #we will renumber all steps after chains are aligned #Step' + str(stepNumber)
447 
448  log.debug("[makeCombinedStep] stepNumber %d, alignment_group %s, %d steps: [%s], %d chain list: [%s], alignment groups: [%s]", stepNumber, alignment_group, len(parallel_steps), ', '.join([step.name if step is not None else "EMPTY" for step in parallel_steps ]), len(chainDefList), ', '.join([chain.name for chain in chainDefList]), ', '.join([chain.alignmentGroups[0] for chain in chainDefList]))
449 
450 
451  stepDicts = []
452  comboHypoTools = []
453  comboHypo = None
454 
455  leg_counter = 0
456  currentStepName = ''
457  # if *all* the steps we're trying to merge are either empty sequences or empty steps
458  # we need to create a single empty step instead.
459  hasNonEmptyStep = checkStepContent(parallel_steps)
460  log.debug("hasNonEmptyStep %d", hasNonEmptyStep)
461 
462  if not hasNonEmptyStep:
463  # only empty steps here
464  if len(parallel_steps)>=len(chainDefList) and all(step is None for step in parallel_steps[len(chainDefList):]):
465  # We need to remove manually here the None steps exceeding the len of chainDefList. The right solution
466  # would be to make sure that these cases don't happen upstream, but I am not confident enough with this
467  # code to make such a large (and dangerous) change. But it would be nice to do that in future if possible..
468  parallel_steps=parallel_steps[:len(chainDefList)]
469  log.debug("[makeCombinedStep] removing empty steps exceeding chainDefList size. The new steps are now %s ", parallel_steps)
470 
471  for chain_index, step in enumerate(parallel_steps):
472  # every step is empty but some might have empty sequences and some might not
473  if step is None or step.isEmpty:
474  new_stepDicts = deepcopy(chainDefList[chain_index].steps[-1].stepDicts)
475  nLegs = chainDefList[chain_index].steps[-1].nLegs
476  currentStepName = getMergedEmptyStepName(chainDefList[chain_index].alignmentGroups[0], stepNumber, nLegs, new_stepDicts[0]['signature'])
477  log.debug('[makeCombinedStep] step has no sequences, making empty step %s', currentStepName)
478 
479  # we need a chain dict here, use the one corresponding to this leg of the chain
480  for new_stepDict in new_stepDicts:
481  oldLegName = new_stepDict['chainName']
482  if re.search('^leg[0-9]{3}_',oldLegName):
483  oldLegName = oldLegName[7:]
484  new_stepDict['chainName'] = legName(oldLegName,leg_counter)
485  log.debug("[makeCombinedStep] stepDict naming old: %s, new: %s", oldLegName, new_stepDict['chainName'])
486  stepDicts.append(new_stepDict)
487  leg_counter += 1
488 
489  else:
490  # Standard step with empty sequence(s)
491  currentStepName = step.name
492  #remove redundant instances of StepN_ and merged_ (happens when merging already merged chains)
493 
494  if currentStepName.startswith('merged_'):
495  currentStepName = currentStepName[7:]
496 
497  # update the chain dict list for the combined step with the chain dict from this step
498  log.debug('[makeCombinedStep] adding step dictionaries %s',step.stepDicts)
499 
500  for new_stepDict in deepcopy(step.stepDicts):
501  oldLegName = new_stepDict['chainName']
502  if re.search('^leg[0-9]{3}_',oldLegName):
503  oldLegName = oldLegName[7:]
504  if len(leg_numbering) > 0:
505  leg_counter = leg_numbering[chain_index]
506  new_stepDict['chainName'] = legName(oldLegName,leg_counter)
507  log.debug("[makeCombinedStep] stepDict naming old: %s, new: %s", oldLegName, new_stepDict['chainName'])
508  stepDicts.append(new_stepDict)
509  leg_counter += 1
510 
511  stepName += '_' + currentStepName
512 
513  theChainStep = ChainStep(stepName, chainDicts = stepDicts, isEmpty = True)
514  log.debug("[makeCombinedStep] Merged empty step: \n %s", theChainStep)
515  return theChainStep
516 
517  stepSeq = []
518  alignLegsInStep = []
519  # count the number of legs inside this chain part/step (inner legs)
520  # this happens if the step is already the result of a merging, due to the alignemnt, and can have more than one leg
521  # use the alignmentGroups here, which is stored by grouping the legs per alignemnt group
522  # TODO: can be extracted from stepDict['chainParts'][0]['multiplicity']?
523  for num, chain in enumerate(chainDefList):
524  alignLegsInStep.append(len(chain.alignmentGroups))
525  assert(len(alignLegsInStep) == len(parallel_steps))
526 
527  for chain_index, step in enumerate(parallel_steps): #this is a horizontal merge!
528 
529  if step is None or (hasNonEmptyStep and step.isEmpty):
530  # this happens for merging chains with different numbers of steps, we need to "pad" out with empty sequences to propogate the decisions
531  # all other chain parts' steps should contain an empty sequence
532 
533  log.debug("[makeCombinedStep] step %s is Empty and has %d alignemnt group legs", step.name if step is not None else "None", alignLegsInStep[chain_index])
534  if alignment_group == "":
535  alignment_group = chainDefList[0].alignmentGroups[0]
536 
537  # loop over the inner legs of this sub-chain and create one empty sequence per each inner leg
538  for innerLeg in range(alignLegsInStep[chain_index]):
539  new_stepDict = deepcopy(chainDefList[chain_index].steps[-1].stepDicts[-1])
540  seqName = getEmptySeqName( new_stepDict['signature'], stepNumber, alignment_group, innerLeg)
541  log.debug("[makeCombinedStep] creating Empty sequence %s", seqName)
542  signature=new_stepDict['signature']
543  is_fs_string = 'FS' if isFullScanRoI(chainDefList[chain_index].L1decisions[0]) else ''
544  seqName=seqName+is_fs_string
545  signature=new_stepDict['signature']+is_fs_string
546  thisEmpty = createEmptyMenuSequenceCfg(flags=None, name=seqName)
547  stepSeq.append(functools.partial(thisEmpty, flags=None, name=seqName))
548  oldLegName = new_stepDict['chainName']
549  if re.search('^leg[0-9]{3}_',oldLegName):
550  oldLegName = oldLegName[7:]
551  new_stepDict['chainName'] = legName(oldLegName,leg_counter)
552  stepDicts.append(new_stepDict)
553  leg_counter += 1
554 
555  nLegs = alignLegsInStep[chain_index]
556  currentStepName = getMergedEmptyStepName(alignment_group, stepNumber, nLegs, signature)
557 
558  log.debug("[makeCombinedStep] found empty step to be merged, step number: %d chain_index: %s, step name: %s, made new empty sequence name: %s", stepNumber, chain_index, currentStepName, seqName)
559 
560 
561  else:
562  # Standard step, append it to the combined step
563  log.debug("[makeCombinedStep] step %s with nLegs = %s", step.name, str(step.nLegs))
564  if len(step.sequenceGens):
565  log.debug("[makeCombinedStep] with sequences = %s", ' '.join(map(str, [seq.func.__name__ for seq in step.sequenceGens])))
566 
567  # this function only works if the input chains are single-object chains (one menu seuqnce)
568  if len(step.sequenceGens) > 1:
569  log.debug("[makeCombinedStep] combining in an already combined chain")
570 
571  if ( comboHypo is None or
572  (hasattr(step.comboHypoCfg, '__name__') and step.comboHypoCfg.__name__ != "ComboHypoCfg") ):
573  comboHypo = step.comboHypoCfg
574  currentStepName = step.name
575  #remove redundant instances of StepN_ and merged_ (happens when merging already merged chains)
576  if currentStepName.startswith('merged_'):
577  currentStepName = currentStepName[7:]
578  stepSeq.extend(step.sequenceGens)
579  comboHypoTools.extend(step.comboToolConfs)
580  # update the chain dict list for the combined step with the chain dict from this step
581  log.debug('[makeCombinedStep] adding step dictionaries %s',step.stepDicts)
582  log.debug('[makeCombinedStep] my leg_numbering is: %s, for chain_index %s',leg_numbering, chain_index)
583  for new_stepDict in deepcopy(step.stepDicts):
584  oldLegName = new_stepDict['chainName']
585  if re.search('^leg[0-9]{3}_',oldLegName):
586  oldLegName = oldLegName[7:]
587  if len(leg_numbering) > 0:
588  leg_counter = leg_numbering[chain_index]
589  new_stepDict['chainName'] = legName(oldLegName,leg_counter)
590  log.debug("[makeCombinedStep] stepDict naming old: %s, new: %s", oldLegName, new_stepDict['chainName'])
591  stepDicts.append(new_stepDict)
592  leg_counter += 1
593 
594 
595  # the step naming for combined chains needs to be revisted!!
596  stepName += '_' + currentStepName
597  log.debug('[makeCombinedStep] current step name %s, with %d sequences',stepName, len(stepSeq))
598  # for merged steps, we need to update the name to add the leg name
599 
600  comboHypoTools = list(set(comboHypoTools))
601  theChainStep = ChainStep(stepName, SequenceGens = stepSeq, chainDicts = stepDicts,
602  comboHypoCfg = comboHypo, comboToolConfs = comboHypoTools)
603  log.debug("[makeCombinedStep] Merged step index %d: \n %s", stepNumber, theChainStep)
604 
605 
606  return theChainStep
607 
608 # modified version of zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-, which takes into account the multiplicity of the steps

◆ mergeChainDefs()

def ChainMerging.mergeChainDefs (   listOfChainDefs,
  chainDict,
  perSig_lengthOfChainConfigs = None 
)
function to merge chain definitions for all legs, used also by signature code 
chainDefList is a list of Chain() objects
one for each part (leg) in the chain 

Definition at line 15 of file ChainMerging.py.

15 def mergeChainDefs(listOfChainDefs, chainDict, perSig_lengthOfChainConfigs = None):
16  """ function to merge chain definitions for all legs, used also by signature code
17  chainDefList is a list of Chain() objects
18  one for each part (leg) in the chain """
19 
20  strategy = chainDict["mergingStrategy"]
21  offset = chainDict["mergingOffset"]
22  log.debug("[mergeChainDefs] %s: Combine by using %s merging with %d chain defs (legs)", chainDict['chainName'], strategy, len(listOfChainDefs))
23 
24  leg_numbering = []
25 
26  if 'Bjet' in chainDict['signatures'] and 'Jet' in chainDict['signatures']:#and chainDict['Signature'] == 'Bjet':
27  leg_numbering = [it for it,s in enumerate(chainDict['signatures'])]# if s != 'Jet']
28 
29  if strategy=="parallel":
30  return mergeParallel(listOfChainDefs, offset)
31  elif strategy=="serial":
32  return mergeSerial(listOfChainDefs)
33 
34  elif strategy=="auto":
35  ordering = getAlignmentGroupOrdering()
36  merging_dict = {} # maps the chain alignment group with the alignment order dict
37  for ich,cConfig in enumerate(listOfChainDefs):
38  chain_ag = cConfig.alignmentGroups[0]
39  if chain_ag not in ordering:
40  log.error("[mergeChainDefs] Alignment group %s can't be auto-merged because it's not in the grouping list!",chain_ag)
41  if chain_ag in merging_dict:
42  merging_dict[chain_ag] += [ich]
43  else:
44  merging_dict[chain_ag] = [ich]
45 
46  tmp_merged = []
47  tmp_merged_ordering = []
48  for ag in merging_dict:
49  if len(merging_dict[ag]) > 1:
50  log.debug("[mergeChainDefs] parallel merging")
51  new_chain_defs, perSig_lengthOfChainConfigs = mergeParallel(list( listOfChainDefs[i] for i in merging_dict[ag] ), offset, leg_numbering, perSig_lengthOfChainConfigs)
52  tmp_merged += [new_chain_defs]
53  tmp_merged_ordering += [ordering.index(ag)]
54  else:
55  log.debug("[mergeChainDefs] don't need to parallel merge")
56  tmp_merged += [listOfChainDefs[merging_dict[ag][0]]]
57  tmp_merged_ordering += [ordering.index(ag)]
58 
59  #reset the ordering to index from zero (padding comes later!)
60  merged_ordering = [-1]*len(tmp_merged_ordering)
61  copy_ordering = tmp_merged_ordering.copy()
62  tmp_val = 0
63  while len(copy_ordering) > 0:
64  min_index = tmp_merged_ordering.index(min(copy_ordering))
65  copy_ordering.pop(copy_ordering.index(min(copy_ordering)))
66  merged_ordering[min_index] = tmp_val
67  tmp_val += 1
68 
69  # only serial merge if necessary
70  if len(tmp_merged) == 1:
71  if perSig_lengthOfChainConfigs is None:
72  log.debug("[mergeChainDefs] tmp merged has length 1, returning 0th element")
73  return tmp_merged[0]
74  else:
75  log.debug("[mergeChainDefs] tmp merged has length 1, returning 0th element and perSig list")
76  return tmp_merged[0], perSig_lengthOfChainConfigs
77 
78  if perSig_lengthOfChainConfigs is None:
79  log.debug("[mergeChainDefs] serial merging first")
80  return mergeSerial(tmp_merged, merged_ordering) #shouldn't need to modify it here!
81  else:
82  log.debug("[mergeChainDefs] returning mergeSerial result and perSig_lengthOfChainConfigs %s",perSig_lengthOfChainConfigs)
83  return mergeSerial(tmp_merged, merged_ordering), perSig_lengthOfChainConfigs #shouldn't need to modify it here!
84 
85  else:
86  log.error("[mergeChainDefs] Merging failed for %s. Merging strategy '%s' not known.", (listOfChainDefs, strategy))
87  return -1
88 
89 
90 

◆ mergeParallel()

def ChainMerging.mergeParallel (   chainDefList,
  offset,
  leg_numbering = None,
  perSig_lengthOfChainConfigs = None 
)
Performs merging of steps with the same step number 

Definition at line 119 of file ChainMerging.py.

119 def mergeParallel(chainDefList, offset, leg_numbering = None, perSig_lengthOfChainConfigs = None):
120  ''' Performs merging of steps with the same step number '''
121  # default mutable values must be initialized to None
122  if leg_numbering is None: leg_numbering = []
123 
124  if offset != -1:
125  log.error("[mergeParallel] Offset for parallel merging not implemented.")
126  raise Exception("[mergeParallel] Cannot merge this chain, exiting.")
127 
128  log.debug(f"[mergeParallel] Parallel merging for chain alignments {[cConfig.alignmentGroups for cConfig in chainDefList]}")
129  allSteps = []
130  allStepsMult = []
131  nSteps = []
132  chainName = ''
133  l1Decisions = []
134  alignmentGroups = []
135  vertical_alignment_groups = []
136 
137  for iConfig, cConfig in enumerate(chainDefList):
138  if chainName == '':
139  chainName = cConfig.name
140  elif chainName != cConfig.name:
141  log.error("[mergeParallel] Something is wrong with the combined chain name: cConfig.name = %s while chainName = %s", cConfig.name, chainName)
142  raise Exception("[mergeParallel] Cannot merge this chain, exiting.")
143 
144  if len(set(cConfig.alignmentGroups)) == 1:
145  alignmentGroups.append(cConfig.alignmentGroups[0])
146  elif len(cConfig.alignmentGroups) > 1:
147  log.debug("[mergeParallel] Parallel merging an already merged chain with different alignment groups? This is odd! %s",cConfig.alignmentGroups)
148  log.debug("...let's look at the config: %s", perSig_lengthOfChainConfigs)
149  # if the length the matching group in the pre-merged part is shorter than the full one,
150  # we need to patch it up to the full length by adding empty steps so that when
151  # we merge, the longer leg doesn't merge onto the second alignment group
152  align_grp_to_lengthen, max_length = check_leg_lengths(perSig_lengthOfChainConfigs)
153  if max_length > -1:
154  current_leg_ag_length = -1
155  index_modified_leg = -1
156  leg_lengths, leg_ags = perSig_lengthOfChainConfigs[iConfig]
157  for ileg, (length, ag) in enumerate(zip(leg_lengths, leg_ags)):
158  if ag == align_grp_to_lengthen:
159  current_leg_ag_length = length
160  index_modified_leg = ileg
161  log.debug("[mergeParallel] ileg %s, length %s, ag %s: ",ileg, length, ag)
162  break
163  # it's already merged so even if there is more than one in this chain
164  # they had better be the same length already
165 
166  n_new_steps = max_length - current_leg_ag_length
167 
168  previous_step_dicts = cConfig.steps[current_leg_ag_length-1].stepDicts
169  for i in range(1,n_new_steps+1):
170  step_mult = []
171  sigNames = []
172 
173  for ileg,stepDict in enumerate(previous_step_dicts):
174  is_fs_string = 'FS' if isFullScanRoI(cConfig.L1decisions[ileg]) else ''
175  sigNames += [stepDict['chainParts'][0]['signature'] + is_fs_string]
176 
177  seqMultName = '_'.join([sigName for sigName in sigNames])
178  nLegs = 1 # TODO, make it follow the real multiplicity of the step
179  # nLegs = cConfig.steps[current_leg_ag_length-1].nLegs
180  seqStepName = getMergedEmptyStepName(align_grp_to_lengthen, current_leg_ag_length+i, nLegs, seqMultName)
181  seqNames = [getEmptySeqName(previous_step_dicts[iSeq]['signature'], current_leg_ag_length+i, align_grp_to_lengthen,i) for iSeq in range(len(sigNames))]
182 
183  emptySequences = build_empty_sequences(previous_step_dicts, step_mult, 'mergeParallel', cConfig.L1decisions, seqNames, chainName)
184  # insert a step with an empty sequence
185  cConfig.steps.insert(current_leg_ag_length + i - 1, #-1 to go to indexed from zero
186  ChainStep( seqStepName, SequenceGens = emptySequences,
187  chainDicts = previous_step_dicts)
188  )
189 
190 
191  # edited the lengths, so need to update the leg length dict the code we did so!
192  perSig_lengthOfChainConfigs[iConfig][0][index_modified_leg] = max_length
193  else:
194  log.debug("[mergeParallel] Alignment groups are empty for this combined chain")
195 
196  allSteps.append(cConfig.steps)
197  #TODO: instead of the real step multiplicy (len(cConfig.steps[0].nLegs))), we set allStepsMult=[1] because the zip doesn't need it: when a step is missing in one leg, one None step is added, not multiple steps. I think we can remove the allStepsMult in the zip_longest below
198  allStepsMult.append(1)
199  nSteps.append(len(cConfig.steps))
200  l1Decisions.extend(cConfig.L1decisions)
201 
202  # Use zip_longest_parallel so that we get None in case one chain has more steps than the other
203  orderedSteps = list(zip_longest_parallel(allSteps, allStepsMult))
204 
205  if perSig_lengthOfChainConfigs is not None and len(perSig_lengthOfChainConfigs) > 0:
206  in_chain_ag_lengths = {}
207  ag_ordering = getAlignmentGroupOrdering()
208 
209  for ag in ag_ordering:
210  for ag_lengths, sig_ags in perSig_lengthOfChainConfigs:
211  for ag_length, sig_ag in zip(ag_lengths, sig_ags):
212  if (sig_ag in in_chain_ag_lengths and in_chain_ag_lengths[sig_ag] < ag_length) or sig_ag not in in_chain_ag_lengths:
213  in_chain_ag_lengths[sig_ag] = ag_length
214  for ag, ag_length in in_chain_ag_lengths.items():
215  vertical_alignment_groups += [ag]*ag_length
216  else:
217  #it's all one alignment group in this case
218  vertical_alignment_groups = [alignmentGroups[0]]*len(orderedSteps)
219 
220 
221  log.debug("[mergeParallel] alignment groups horizontal: %s", alignmentGroups)
222  log.debug("[mergeParallel] alignment groups vertical: %s", vertical_alignment_groups)
223 
224  combChainSteps =[]
225  log.debug("[mergeParallel] len(orderedSteps): %d", len(orderedSteps))
226  for chain_index in range(len(chainDefList)):
227  log.debug('[mergeParallel] Chain object to merge (i.e. chainDef) %s', chainDefList[chain_index])
228 
229  for step_index, (steps, step_ag) in enumerate(zip(orderedSteps,vertical_alignment_groups)):
230  mySteps = list(steps)
231  log.debug(f"[mergeParallel] Merging step {step_index+1} with alignment group = {step_ag}")
232 
233  combStep = makeCombinedStep(mySteps, step_index+1, chainDefList, orderedSteps, combChainSteps, leg_numbering, step_ag)
234  combChainSteps.append(combStep)
235 
236 
237  combinedChainDef = Chain(chainName, ChainSteps=combChainSteps, L1decisions=l1Decisions,
238  nSteps = nSteps, alignmentGroups = alignmentGroups)
239 
240  log.debug("[mergeParallel] Parallel merged chain %s with these steps:", chainName)
241  for step in combinedChainDef.steps:
242  log.debug('\n %s', step)
243 
244  return combinedChainDef, perSig_lengthOfChainConfigs
245 

◆ mergeSerial()

def ChainMerging.mergeSerial (   chainDefList,
  chainDefListOrdering 
)

Definition at line 380 of file ChainMerging.py.

380 def mergeSerial(chainDefList, chainDefListOrdering):
381  allSteps = []
382  legOrdering = []
383  nSteps = []
384  chainName = ''
385  l1Decisions = []
386  alignmentGroups = []
387  log.debug('[mergeSerial] Merge chainDefList:')
388  log.debug(chainDefList)
389  log.debug('[mergeSerial] wth ordering %s:',chainDefListOrdering)
390 
391  for ic,cOrder in enumerate(chainDefListOrdering):
392 
393  #put these in order of alignment
394  cConfig = chainDefList[chainDefListOrdering.index(ic)]
395  leg_order = chainDefListOrdering.index(ic) #but keep track of where it came from
396 
397  if chainName == '':
398  chainName = cConfig.name
399  elif chainName != cConfig.name:
400  log.error("[mergeSerial] Something is wrong with the combined chain name: cConfig.name = %s while chainName = %s", cConfig.name, chainName)
401  raise Exception("[mergeSerial] Cannot merge this chain, exiting.")
402 
403  #allSteps is ordered such that the first entry in the list is what we want to *run* first
404  allSteps.append(cConfig.steps)
405  legOrdering.append(leg_order)
406  nSteps.extend(cConfig.nSteps)
407  l1Decisions.extend(chainDefList[ic].L1decisions) # do not invert L1Decisions because they follow the order of the sequences inside teh steps
408  alignmentGroups.extend(cConfig.alignmentGroups)
409 
410  serialSteps = serial_zip(allSteps, chainName, chainDefList, legOrdering)
411  combChainSteps =[]
412  for chain_index in range(len(chainDefList)):
413  log.debug('[mergeSerial] Chain object to merge (i.e. chainDef) %s', chainDefList[chain_index])
414  for step_index, steps in enumerate(serialSteps):
415  mySteps = list(steps)
416  combStep = makeCombinedStep(mySteps, step_index+1, chainDefList)
417  combChainSteps.append(combStep)
418 
419  combinedChainDef = Chain(chainName, ChainSteps=combChainSteps, L1decisions=l1Decisions,
420  nSteps = nSteps, alignmentGroups = alignmentGroups)
421 
422  log.debug("[mergeSerial] Serial merged chain %s with number of steps/leg %s with these steps:", chainName, combinedChainDef.nSteps)
423  for step in combinedChainDef.steps:
424  log.debug(' %s', step)
425 
426  return combinedChainDef
427 

◆ serial_zip()

def ChainMerging.serial_zip (   allSteps,
  chainName,
  chainDefList,
  legOrdering 
)

Definition at line 289 of file ChainMerging.py.

289 def serial_zip(allSteps, chainName, chainDefList, legOrdering):
290 
291  #note: allSteps and chainDefList do not have the legs in the same order
292  #the legOrdering is a mapping between the two:
293  # chainDefList[legOrdering[0]] <=> allSteps[0]
294 
295  legs_per_part = [chainDefList[stepPlacement].steps[0].nLegs for stepPlacement in legOrdering]
296  n_parts = len(allSteps)
297  log.debug('[serial_zip] configuring chain with %d parts with multiplicities %s', n_parts, legs_per_part)
298  log.debug('[serial_zip] and leg ordering %s', legOrdering)
299  newsteps = []
300 
301  #per-part (horizontal) iteration by alignment ordering
302  #i.e. if we run muon then electron, allSteps[0] = muon steps, allSteps[1] = electron steps
303  #leg ordering tells us where it was ordered in the chain name, so e_mu in this case would
304  #have legOrdering = [1,0]
305  for chain_index, (chainSteps, stepPlacement) in enumerate(zip(allSteps, legOrdering)):
306 
307  for step_index, step in enumerate(chainSteps): #serial step iteration
308  if step_index == 0:
309  prev_ag_step_index = step_index
310  previousAG = getCurrentAG(step)
311  log.debug('[serial_zip] chain_index: %s step_index: %s, alignment group: %s', chain_index, step_index+1, previousAG)
312  # create list of correct length (chainSteps in parallel)
313  stepList = [None]*n_parts
314 
315  # put the step from the current sub-chain into the right place
316  stepList[stepPlacement] = step
317  log.debug('[serial_zip] Put step: %s', step.name)
318 
319  # all other chain parts' steps should contain an empty sequence
320  for chain_index2, (nLegs, stepPlacement2) in enumerate(zip(legs_per_part, legOrdering)): #more per-leg iteration
321  emptyStep = stepList[stepPlacement2]
322  if emptyStep is None:
323  if chain_index2 == chain_index:
324  log.error("chain_index2 = chain_index, but the stepList still has none!")
325  raise Exception("[serial_zip] duplicating existing leg, why has this happened??")
326 
327  #this WILL NOT work for jets!
328  step_mult = []
329  emptyChainDicts = []
330  if chain_index2 < chain_index:
331  emptyChainDicts = allSteps[chain_index2][-1].stepDicts
332  else:
333  emptyChainDicts = allSteps[chain_index2][0].stepDicts
334 
335  log.debug("[serial_zip] nLegs: %s, len(emptyChainDicts): %s, len(L1decisions): %s", nLegs, len(emptyChainDicts), len(chainDefList[stepPlacement2].L1decisions))
336  sigNames = []
337  for ileg,(emptyChainDict,_) in enumerate(zip(emptyChainDicts,chainDefList[stepPlacement2].L1decisions)):
338  is_fs_string = 'FS' if isFullScanRoI(chainDefList[stepPlacement2].L1decisions[ileg]) else ''
339  sigNames +=[emptyChainDict['chainParts'][0]['signature']+is_fs_string]
340 
341 
342  seqMultName = '_'.join([sigName for sigName in sigNames])
343  currentAG = ''
344 
345  #now we need to know what alignment group this step is in to properly name the empty sequence
346  if len(set(chainDefList[stepPlacement].alignmentGroups)) == 1:
347  currentAG = chainDefList[stepPlacement].alignmentGroups[0]
348  ag_step_index = step_index+1
349  else:
350  # this happens if one of the bits to serial merge is already serial merged.
351  currentAG = getCurrentAG(step)
352  if currentAG == previousAG:
353  ag_step_index = prev_ag_step_index + 1
354  prev_ag_step_index = ag_step_index
355  else:
356  ag_step_index = 1
357  previousAG = currentAG
358  prev_ag_step_index = 1
359 
360  seqStepName = getMergedEmptyStepName(currentAG, ag_step_index, nLegs, seqMultName)
361 
362  seqNames = [getEmptySeqName(emptyChainDicts[iSeq]['signature'], ag_step_index, currentAG,iSeq) for iSeq in range(nLegs)]
363 
364  log.verbose("[serial_zip] step name for this leg: %s", seqStepName)
365  log.verbose("[serial_zip] created empty sequence(s): %s", seqNames)
366  log.verbose("[serial_zip] L1decisions %s ", chainDefList[stepPlacement2].L1decisions)
367 
368  emptySequences = build_empty_sequences(emptyChainDicts, step_mult, 'serial_zip', chainDefList[stepPlacement2].L1decisions, seqNames, chainName)
369 
370  stepList[stepPlacement2] = ChainStep( seqStepName, SequenceGens = emptySequences,
371  chainDicts = emptyChainDicts)
372 
373  newsteps.append(stepList)
374  log.debug('After serial_zip')
375  for s in newsteps:
376  log.debug( ', '.join(map(str, [step.name for step in s]) ) )
377  return newsteps
378 
379 

◆ zip_longest_parallel()

def ChainMerging.zip_longest_parallel (   AllSteps,
  multiplicity,
  fillvalue = None 
)

Definition at line 609 of file ChainMerging.py.

609 def zip_longest_parallel(AllSteps, multiplicity, fillvalue=None):
610 
611  iterators = [iter(it) for it in AllSteps]
612  inactives =set()
613  if len(iterators)==0:
614  return
615  while True:
616  values = []
617  for i, it in enumerate(iterators): #Here we loop over the different chain parts
618  try:
619  value = next(it)
620  except StopIteration:
621  if i not in inactives:
622  #We want to add the inactive iterator to the list of inactives iterators
623  inactives.add(i)
624  if len(inactives)>=len(iterators):
625  #We want to exit the while True if we reached the end of all iterators.
626  return
627  iterators[i] = repeat(fillvalue, int(multiplicity[i]))
628  value = fillvalue
629  values.append(value)
630  if int(multiplicity[i]) > 1 and value == fillvalue:
631  values.extend([fillvalue]*int(multiplicity[i]-1))
632 
633  yield tuple(values)
634 
635 
636 

Variable Documentation

◆ log

ChainMerging.log

Definition at line 13 of file ChainMerging.py.

createLinkingScheme.iter
iter
Definition: createLinkingScheme.py:62
ChainMerging.getCurrentAG
def getCurrentAG(chainStep)
Definition: ChainMerging.py:264
max
constexpr double max()
Definition: ap_fixedTest.cxx:33
ChainMerging.checkStepContent
def checkStepContent(parallel_steps)
Definition: ChainMerging.py:428
min
constexpr double min()
Definition: ap_fixedTest.cxx:26
ChainMerging.mergeSerial
def mergeSerial(chainDefList, chainDefListOrdering)
Definition: ChainMerging.py:380
ChainMerging.isFullScanRoI
def isFullScanRoI(inputL1Nav)
Definition: ChainMerging.py:256
MenuComponents.isEmptySequenceCfg
def isEmptySequenceCfg(o)
Definition: MenuComponents.py:331
fillPileUpNoiseLumi.next
next
Definition: fillPileUpNoiseLumi.py:52
ChainMerging.build_empty_sequences
def build_empty_sequences(emptyChainDicts, step_mult, caller, L1decisions, seqNames, chainName)
Definition: ChainMerging.py:637
python.TrigCompositeUtils.legName
def legName(chainName, legCounter)
Definition: DecisionHandling/python/TrigCompositeUtils.py:12
plotBeamSpotVxVal.range
range
Definition: plotBeamSpotVxVal.py:194
histSizes.list
def list(name, path='/')
Definition: histSizes.py:38
ChainMerging.getMergedEmptyStepName
def getMergedEmptyStepName(alignmentGroup, stepNumber, multiplicity, signature)
Definition: ChainMerging.py:246
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
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
ChainMerging.check_leg_lengths
def check_leg_lengths(perSig_lengthOfChainConfigs)
Definition: ChainMerging.py:91
ChainMerging.makeCombinedStep
def makeCombinedStep(parallel_steps, stepNumber, chainDefList, allSteps=None, currentChainSteps=None, leg_numbering=None, alignment_group="")
Definition: ChainMerging.py:440
ChainMerging.mergeChainDefs
def mergeChainDefs(listOfChainDefs, chainDict, perSig_lengthOfChainConfigs=None)
Definition: ChainMerging.py:15
python.CaloAddPedShiftConfig.int
int
Definition: CaloAddPedShiftConfig.py:45
ChainMerging.getEmptySeqName
def getEmptySeqName(signature, step_number, alignGroup, order)
Definition: ChainMerging.py:251
str
Definition: BTagTrackIpAccessor.cxx:11
ChainMerging.serial_zip
def serial_zip(allSteps, chainName, chainDefList, legOrdering)
Definition: ChainMerging.py:289
ChainMerging.zip_longest_parallel
def zip_longest_parallel(AllSteps, multiplicity, fillvalue=None)
Definition: ChainMerging.py:609
Cut::all
@ all
Definition: SUSYToolsAlg.cxx:67
MenuComponents.createEmptyMenuSequenceCfg
def createEmptyMenuSequenceCfg(flags, name)
Definition: MenuComponents.py:321
ChainMerging.mergeParallel
def mergeParallel(chainDefList, offset, leg_numbering=None, perSig_lengthOfChainConfigs=None)
Definition: ChainMerging.py:119