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=[], perSig_lengthOfChainConfigs=None)
 
def getEmptySeqName (stepName, step_number, alignGroup)
 
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=[], currentChainSteps=[], leg_numbering=[], 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 625 of file ChainMerging.py.

625 def build_empty_sequences(emptyChainDicts, step_mult, caller, L1decisions, seqNames, chainName):
626  emptySequences = []
627  for ileg in range(len(L1decisions)):
628  if isFullScanRoI(L1decisions[ileg]):
629  log.debug("[%s] adding FS empty sequence", caller)
630  emptySequences += [functools.partial(EmptyMenuSequenceCfg, None, name=seqNames[ileg]+"FS")]
631  else:
632  log.debug("[%s] adding non-FS empty sequence", caller)
633  emptySequences += [functools.partial(EmptyMenuSequenceCfg, None, name=seqNames[ileg])]
634 
635  log.verbose("[%s] emptyChainDicts %s", caller, emptyChainDicts)
636  log.debug("[%s] %s has number of empty sequences %d and empty legs in stepDicts %d",
637  caller, chainName, len(emptySequences), len(emptyChainDicts))
638  if len(emptySequences) != len(emptyChainDicts):
639  log.error("[%s] %s has a different number of empty sequences/legs %d than stepDicts %d",
640  caller, chainName, len(emptySequences), len(emptyChainDicts))
641 
642  raise Exception(f"[{caller}] Cannot create this chain step, exiting.")
643 
644  for sd in emptyChainDicts:
645  if sd['signature'] == 'Jet' or sd['signature'] == 'Bjet':
646  step_mult += [1]
647  elif len(sd['chainParts']) != 1:
648  log.error("[%s] %s has chainParts has length != 1 within a leg! chain dictionary for this step: \n %s",
649  caller, chainName, sd)
650  raise Exception(f"[{caller}] Cannot create this chain step, exiting.")
651  else:
652  step_mult += [int(sd['chainParts'][0]['multiplicity'])]
653 
654  if len(emptySequences) != len(step_mult):
655  log.error("[%s] %s has a different number of empty sequences/legs %d than multiplicities %d",
656  caller, chainName, len(emptySequences), len(step_mult))
657  raise Exception(f"[{caller}] Cannot create this chain step, exiting.")
658 
659  log.verbose('[%s] step multiplicity %s',caller, step_mult)
660 
661 
662  return emptySequences

◆ check_leg_lengths()

def ChainMerging.check_leg_lengths (   perSig_lengthOfChainConfigs)

Definition at line 90 of file ChainMerging.py.

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

◆ checkStepContent()

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

Definition at line 424 of file ChainMerging.py.

424 def checkStepContent(parallel_steps):
425  """
426  return True if any step contains a real Sequence
427  """
428  for step in parallel_steps:
429  if step is None or step.isEmpty:
430  continue
431  for seq in step.sequenceFunctions:
432  if not isEmptySequenceCfg(seq):
433  return True
434  return False
435 

◆ getCurrentAG()

def ChainMerging.getCurrentAG (   chainStep)

Definition at line 258 of file ChainMerging.py.

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

◆ getEmptySeqName()

def ChainMerging.getEmptySeqName (   stepName,
  step_number,
  alignGroup 
)

Definition at line 238 of file ChainMerging.py.

238 def getEmptySeqName(stepName, step_number, alignGroup):
239  #remove redundant instances of StepN
240  if re.search('^Step[0-9]_',stepName):
241  stepName = stepName[6:]
242  elif re.search('^Step[0-9]{2}_', stepName):
243  stepName = stepName[7:]
244 
245  seqName = 'Empty'+ alignGroup +'Seq'+str(step_number)+ '_'+ stepName
246  return seqName
247 
248 
249 

◆ isFullScanRoI()

def ChainMerging.isFullScanRoI (   inputL1Nav)

Definition at line 250 of file ChainMerging.py.

250 def isFullScanRoI(inputL1Nav):
251  fsRoIList = ['HLTNav_L1FSNOSEED','HLTNav_L1MET','HLTNav_L1J']
252  if inputL1Nav in fsRoIList:
253  return True
254  else:
255  return False
256 
257 

◆ makeCombinedStep()

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

Definition at line 436 of file ChainMerging.py.

436 def makeCombinedStep(parallel_steps, stepNumber, chainDefList, allSteps = [], currentChainSteps = [], leg_numbering = [], alignment_group = ""):
437  stepName = 'merged' #we will renumber all steps after chains are aligned #Step' + str(stepNumber)
438  stepSeq = []
439  stepMult = []
440  log.verbose("[makeCombinedStep] steps %s ", parallel_steps)
441  stepDicts = []
442  comboHypoTools = []
443  comboHypo = None
444 
445  leg_counter = 0
446  currentStepName = ''
447  # if *all* the steps we're trying to merge are either empty sequences or empty steps
448  # we need to create a single empty step instead.
449  hasNonEmptyStep = checkStepContent(parallel_steps)
450 
451  if not hasNonEmptyStep:
452 
453  if len(parallel_steps)>=len(chainDefList) and all(step is None for step in parallel_steps[len(chainDefList):]):
454  # We need to remove manually here the None steps exceeding the len of chainDefList. The right solution
455  # would be to make sure that these cases don't happen upstream, but I am not confident enough with this
456  # code to make such a large (and dangerous) change. But it would be nice to do that in future if possible..
457  parallel_steps=parallel_steps[:len(chainDefList)]
458  log.debug("[makeCombinedStep] removing empty steps exceeding chainDefList size. The new steps are now %s ", parallel_steps)
459 
460  for chain_index, step in enumerate(parallel_steps):
461  # every step is empty but some might have empty sequences and some might not
462  if step is None or len(step.sequenceFunctions) == 0:
463 
464  new_stepDicts = deepcopy(chainDefList[chain_index].steps[-1].stepDicts)
465  currentStepName = 'Empty' + chainDefList[chain_index].alignmentGroups[0]+'Align'+str(stepNumber)+'_'+new_stepDicts[0]['chainParts'][0]['multiplicity']+new_stepDicts[0]['signature']
466  log.debug('[makeCombinedStep] step has no sequences, making empty step %s', currentStepName)
467 
468  # we need a chain dict here, use the one corresponding to this leg of the chain
469  for new_stepDict in new_stepDicts:
470  oldLegName = new_stepDict['chainName']
471  if re.search('^leg[0-9]{3}_',oldLegName):
472  oldLegName = oldLegName[7:]
473  new_stepDict['chainName'] = legName(oldLegName,leg_counter)
474  log.debug("[makeCombinedStep] stepDict naming old: %s, new: %s", oldLegName, new_stepDict['chainName'])
475  stepDicts.append(new_stepDict)
476  leg_counter += 1
477 
478  else:
479  # Standard step with empty sequence(s)
480  currentStepName = step.name
481  #remove redundant instances of StepN_ and merged_ (happens when merging already merged chains)
482 
483  if currentStepName.startswith('merged_'):
484  currentStepName = currentStepName[7:]
485 
486  # update the chain dict list for the combined step with the chain dict from this step
487  log.debug('[makeCombinedStep] adding step dictionaries %s',step.stepDicts)
488 
489  for new_stepDict in deepcopy(step.stepDicts):
490  oldLegName = new_stepDict['chainName']
491  if re.search('^leg[0-9]{3}_',oldLegName):
492  oldLegName = oldLegName[7:]
493  if len(leg_numbering) > 0:
494  leg_counter = leg_numbering[chain_index]
495  new_stepDict['chainName'] = legName(oldLegName,leg_counter)
496  log.debug("[makeCombinedStep] stepDict naming old: %s, new: %s", oldLegName, new_stepDict['chainName'])
497  stepDicts.append(new_stepDict)
498  leg_counter += 1
499 
500  stepName += '_' + currentStepName
501 
502  theChainStep = ChainStep(stepName, Sequences=[], multiplicity=[], chainDicts=stepDicts, comboHypoCfg=ComboHypoCfg)
503  log.debug("[makeCombinedStep] Merged empty step: \n %s", theChainStep)
504  return theChainStep
505 
506  for chain_index, step in enumerate(parallel_steps): #this is a horizontal merge!
507 
508  if step is None or (hasNonEmptyStep and len(step.sequenceFunctions) == 0):
509  # this happens for merging chains with different numbers of steps, we need to "pad" out with empty sequences to propogate the decisions
510  # all other chain parts' steps should contain an empty sequence
511 
512  if chain_index+1 > len(chainDefList):
513  chain_index-=chain_index
514 
515  if alignment_group == "":
516  alignment_group = chainDefList[0].alignmentGroups[0]
517 
518  new_stepDict = deepcopy(chainDefList[chain_index].steps[-1].stepDicts[-1])
519  seqName = getEmptySeqName(new_stepDict['signature'], stepNumber, alignment_group)
520 
521  if isFullScanRoI(chainDefList[chain_index].L1decisions[0]):
522  stepSeq.append(functools.partial(EmptyMenuSequenceCfg, None, name=seqName+"FS"))
523  currentStepName = 'Empty' + alignment_group +'Align'+str(stepNumber)+'_'+new_stepDict['chainParts'][0]['multiplicity']+new_stepDict['signature']+'FS'
524  else:
525  stepSeq.append(functools.partial(EmptyMenuSequenceCfg, None, name=seqName))
526  currentStepName = 'Empty' + alignment_group +'Align'+str(stepNumber)+'_'+new_stepDict['chainParts'][0]['multiplicity']+new_stepDict['signature']
527 
528  log.debug("[makeCombinedStep] chain_index: %s, step name: %s, empty sequence name: %s", chain_index, currentStepName, seqName)
529 
530  #stepNumber is indexed from 1, need the previous step indexed from 0, so do - 2
531  prev_step_mult = -1
532  if stepNumber > 1 and len(currentChainSteps[stepNumber-2].multiplicity) >0:
533  prev_step_mult = int(currentChainSteps[stepNumber-2].multiplicity[chain_index])
534  else:
535  #get the step multiplicity from the step dict. This should be
536  prev_step_mult = int(new_stepDict['chainParts'][0]['multiplicity'])
537  stepMult.append(prev_step_mult)
538  # we need a chain dict here, use the one corresponding to this leg of the chain
539  oldLegName = new_stepDict['chainName']
540  if re.search('^leg[0-9]{3}_',oldLegName):
541  oldLegName = oldLegName[7:]
542  new_stepDict['chainName'] = legName(oldLegName,leg_counter)
543  stepDicts.append(new_stepDict)
544  leg_counter += 1
545  else:
546  # Standard step, append it to the combined step
547  log.debug("[makeCombinedStep] step %s, multiplicity = %s", step.name, str(step.multiplicity))
548  if len(step.sequenceFunctions):
549  log.debug("[makeCombinedStep] with sequences = %s", ' '.join(map(str, [seq.func.__name__ for seq in step.sequenceFunctions])))
550 
551  # this function only works if the input chains are single-object chains (one menu seuqnce)
552  if len(step.sequenceFunctions) > 1:
553  log.debug("[makeCombinedStep] combining in an already combined chain")
554 
555  if ( comboHypo is None or
556  (hasattr(step.comboHypoCfg, '__name__') and step.comboHypoCfg.__name__ != "ComboHypoCfg") ):
557  comboHypo = step.comboHypoCfg
558  currentStepName = step.name
559  #remove redundant instances of StepN_ and merged_ (happens when merging already merged chains)
560  if currentStepName.startswith('merged_'):
561  currentStepName = currentStepName[7:]
562  stepSeq.extend(step.sequenceFunctions)
563  # set the multiplicity of all the legs
564  if len(step.multiplicity) == 0:
565  stepMult.append(0)
566  else:
567  stepMult.extend(step.multiplicity)
568  comboHypoTools.extend(step.comboToolConfs)
569  # update the chain dict list for the combined step with the chain dict from this step
570  log.debug('[makeCombinedStep] adding step dictionaries %s',step.stepDicts)
571  log.debug('[makeCombinedStep] my leg_numbering is: %s, for chain_index %s',leg_numbering, chain_index)
572  for new_stepDict in deepcopy(step.stepDicts):
573  oldLegName = new_stepDict['chainName']
574  if re.search('^leg[0-9]{3}_',oldLegName):
575  oldLegName = oldLegName[7:]
576  if len(leg_numbering) > 0:
577  leg_counter = leg_numbering[chain_index]
578  new_stepDict['chainName'] = legName(oldLegName,leg_counter)
579  log.debug("[makeCombinedStep] stepDict naming old: %s, new: %s", oldLegName, new_stepDict['chainName'])
580  stepDicts.append(new_stepDict)
581  leg_counter += 1
582 
583 
584  # the step naming for combined chains needs to be revisted!!
585  stepName += '_' + currentStepName
586  log.debug('[makeCombinedStep] current step name %s',stepName)
587  # for merged steps, we need to update the name to add the leg name
588 
589  comboHypoTools = list(set(comboHypoTools))
590  theChainStep = ChainStep(stepName, Sequences=stepSeq, multiplicity=stepMult, chainDicts=stepDicts, comboHypoCfg=comboHypo, comboToolConfs=comboHypoTools)
591  log.debug("[makeCombinedStep] Merged step: \n %s", theChainStep)
592 
593 
594  return theChainStep
595 
596 # 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 
)

Definition at line 15 of file ChainMerging.py.

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

◆ mergeParallel()

def ChainMerging.mergeParallel (   chainDefList,
  offset,
  leg_numbering = [],
  perSig_lengthOfChainConfigs = None 
)

Definition at line 118 of file ChainMerging.py.

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

◆ mergeSerial()

def ChainMerging.mergeSerial (   chainDefList,
  chainDefListOrdering 
)

Definition at line 376 of file ChainMerging.py.

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

◆ serial_zip()

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

Definition at line 283 of file ChainMerging.py.

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

◆ zip_longest_parallel()

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

Definition at line 597 of file ChainMerging.py.

597 def zip_longest_parallel(AllSteps, multiplicity, fillvalue=None):
598  from itertools import repeat
599 
600  iterators = [iter(it) for it in AllSteps]
601  inactives =set()
602  if len(iterators)==0:
603  return
604  while True:
605  values = []
606  for i, it in enumerate(iterators): #Here we loop over the different chain parts
607  try:
608  value = next(it)
609  except StopIteration:
610  if i not in inactives:
611  #We want to add the inactive iterator to the list of inactives iterators
612  inactives.add(i)
613  if len(inactives)>=len(iterators):
614  #We want to exit the while True if we reached the end of all iterators.
615  return
616  iterators[i] = repeat(fillvalue, int(multiplicity[i]))
617  value = fillvalue
618  values.append(value)
619  if int(multiplicity[i]) > 1 and value == fillvalue:
620  values.extend([fillvalue]*int(multiplicity[i]-1))
621 
622  yield tuple(values)
623 
624 

Variable Documentation

◆ log

ChainMerging.log

Definition at line 13 of file ChainMerging.py.

max
#define max(a, b)
Definition: cfImp.cxx:41
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
ChainMerging.getCurrentAG
def getCurrentAG(chainStep)
Definition: ChainMerging.py:258
ChainMerging.checkStepContent
def checkStepContent(parallel_steps)
Definition: ChainMerging.py:424
ChainMerging.mergeSerial
def mergeSerial(chainDefList, chainDefListOrdering)
Definition: ChainMerging.py:376
ChainMerging.isFullScanRoI
def isFullScanRoI(inputL1Nav)
Definition: ChainMerging.py:250
MenuComponents.isEmptySequenceCfg
def isEmptySequenceCfg(o)
Definition: MenuComponents.py:381
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:625
python.TrigCompositeUtils.legName
def legName(chainName, legCounter)
Definition: DecisionHandling/python/TrigCompositeUtils.py:12
plotBeamSpotVxVal.range
range
Definition: plotBeamSpotVxVal.py:195
histSizes.list
def list(name, path='/')
Definition: histSizes.py:38
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:224
min
#define min(a, b)
Definition: cfImp.cxx:40
ChainMerging.makeCombinedStep
def makeCombinedStep(parallel_steps, stepNumber, chainDefList, allSteps=[], currentChainSteps=[], leg_numbering=[], alignment_group="")
Definition: ChainMerging.py:436
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:90
ChainMerging.mergeParallel
def mergeParallel(chainDefList, offset, leg_numbering=[], perSig_lengthOfChainConfigs=None)
Definition: ChainMerging.py:118
Cut::all
@ all
Definition: SUSYToolsAlg.cxx:64
ChainMerging.mergeChainDefs
def mergeChainDefs(listOfChainDefs, chainDict, perSig_lengthOfChainConfigs=None)
Definition: ChainMerging.py:15
ChainMerging.getEmptySeqName
def getEmptySeqName(stepName, step_number, alignGroup)
Definition: ChainMerging.py:238
str
Definition: BTagTrackIpAccessor.cxx:11
ChainMerging.serial_zip
def serial_zip(allSteps, chainName, chainDefList, legOrdering)
Definition: ChainMerging.py:283
ChainMerging.zip_longest_parallel
def zip_longest_parallel(AllSteps, multiplicity, fillvalue=None)
Definition: ChainMerging.py:597