ATLAS Offline Software
ConfigText_unitTest.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 #
3 # Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
4 #
5 # @author Joseph Lambert
6 
7 def compareConfigSeq(seq1, seq2, *, checkOrder=False):
8  """Compares two ConfigSequences"""
9  blocks1 = seq1._blocks
10  blocks2 = seq2._blocks
11  print("Block order for each config sequence")
12  print("\033[4m{0:<30} {1:<30}\033[0m".format("Sequence1", "Sequence2"))
13  for i in range(max(len(blocks1), len(blocks2))):
14  name1, name2 = '', ''
15  if i < len(blocks1):
16  name1 = blocks1[i].__class__.__name__
17  if i < len(blocks2):
18  name2 = blocks2[i].__class__.__name__
19  print(f"{name1:<30} {name2}")
20  if not checkOrder:
21  print("Sorting blocks by name (will not sort blocks with same name)")
22  blocks1.sort(key=lambda x: x.__class__.__name__)
23  blocks2.sort(key=lambda x: x.__class__.__name__)
24  if len(blocks1) != len(blocks2):
25  raise Exception("Number of blocks are different")
26  for i in range(len(blocks1)):
27  block1 = blocks1[i]
28  block2 = blocks2[i]
29  name1 = block1.__class__.__name__
30  name2 = block2.__class__.__name__
31  if name1 != name2:
32  raise Exception(f"In position {i} "
33  f"the first sequence results in {name1} "
34  f"and the second sequence results in {name2}")
35  for name in block1.getOptions():
36  if name == 'groupName':
37  continue
38  value1 = block1.getOptionValue(name)
39  value2 = block2.getOptionValue(name)
40  if value1 != value2:
41  raise Exception(f"For block {name1}, the block "
42  f"option {name} the first sequence results in {value1} "
43  f"and the second sequence results in {value2}")
44 
45 
46 def compareTextBuilder(yamlPath='', *, checkOrder=False) :
47  """
48  Create a configSequence using provided YAML file and a
49  configSequence using ConfigText python commands and compare.
50 
51  Will raise an exception if configSequences differ
52  """
53  # create text config object to build text configurations
54  from AnalysisAlgorithmsConfig.ConfigText import TextConfig
55  config = TextConfig()
56 
57  # CommonServices
58  config.addBlock('CommonServices')
59  config.setOptions(systematicsHistogram='systematicsList')
60 
61  # PileupReweighting
62  config.addBlock('PileupReweighting')
63 
64  # EventCleaning
65  config.addBlock('EventCleaning')
66  config.setOptions (runEventCleaning=True)
67 
68  # Jets
69  config.addBlock('Jets')
70  config.setOptions (containerName='AnaJets')
71  config.setOptions (jetCollection='AntiKt4EMPFlowJets')
72  config.setOptions (runJvtUpdate=False)
73  config.setOptions (runNNJvtUpdate=True)
74  config.setOptions (recalibratePhyslite=False)
75  # Jets.FlavourTagging
76  config.addBlock( 'Jets.FlavourTagging')
77  config.setOptions (containerName='AnaJets')
78  config.setOptions (selectionName='ftag')
79  config.setOptions (btagger='GN2v01')
80  config.setOptions (btagWP='FixedCutBEff_65')
81  config.setOptions (saveScores='All')
82  # Jets.FlavourTaggingEventSF
83  config.addBlock( 'Jets.FlavourTaggingEventSF')
84  config.setOptions (containerName='AnaJets.baselineJvt')
85  config.setOptions (btagger='GN2v01')
86  # Jets.JVT
87  config.addBlock('Jets.JVT', containerName='AnaJets')
88 
89  # Large-R jets
90  config.addBlock('Jets')
91  config.setOptions (containerName='AnaLargeRJets')
92  config.setOptions (jetCollection='AntiKt10UFOCSSKSoftDropBeta100Zcut10Jets')
93  config.setOptions (recalibratePhyslite=False)
94 
95  # Electrons
96  config.addBlock ('Electrons')
97  config.setOptions (containerName='AnaElectrons')
98  config.setOptions (forceFullSimConfig=True)
99  config.setOptions (recalibratePhyslite=False)
100  config.setOptions (decorateTruth=True)
101  # Electrons.WorkingPoint
102  config.addBlock ('Electrons.WorkingPoint')
103  config.setOptions (containerName='AnaElectrons')
104  config.setOptions (selectionName='loose')
105  config.setOptions (forceFullSimConfig=True)
106  config.setOptions (noEffSF=True)
107  config.setOptions (identificationWP='LooseBLayerLH')
108  config.setOptions (isolationWP='Loose_VarRad')
109  config.setOptions (writeTrackD0Z0=True)
110  # Electrons.PtEtaSelection
111  config.addBlock ('Electrons.PtEtaSelection')
112  config.setOptions (containerName='AnaElectrons')
113  config.setOptions (minPt=10000.0)
114  # Electrons.IFFClassification
115  config.addBlock ('Electrons.IFFClassification')
116  config.setOptions (containerName='AnaElectrons')
117  # Electrons.MCTCClassification
118  config.addBlock ('Electrons.MCTCClassification')
119  config.setOptions (containerName='AnaElectrons')
120  config.setOptions (prefix='truth_')
121 
122  # Photons
123  config.addBlock ('Photons', containerName='AnaPhotons')
124  config.setOptions (forceFullSimConfig=True)
125  config.setOptions (recomputeIsEM=False)
126  config.setOptions (recalibratePhyslite=False)
127  config.setOptions (decorateTruth=True)
128  # Photons.WorkingPoint
129  config.addBlock ('Photons.WorkingPoint')
130  config.setOptions (containerName='AnaPhotons')
131  config.setOptions (selectionName='tight')
132  config.setOptions (forceFullSimConfig=True)
133  config.setOptions (qualityWP='Tight')
134  config.setOptions (isolationWP='FixedCutTight')
135  config.setOptions (recomputeIsEM=False)
136  # Photons.PtEtaSelection
137  config.addBlock ('Photons.PtEtaSelection')
138  config.setOptions (containerName='AnaPhotons')
139  config.setOptions (minPt=10000.0)
140 
141  # Muons
142  config.addBlock ('Muons', containerName='AnaMuons')
143  config.setOptions (recalibratePhyslite=False)
144  config.setOptions (decorateTruth=True)
145  # Muons.WorkingPoint
146  config.addBlock ('Muons.WorkingPoint')
147  config.setOptions (containerName='AnaMuons')
148  config.setOptions (selectionName='medium')
149  config.setOptions (quality='Medium')
150  config.setOptions (isolation='Loose_VarRad')
151  config.setOptions (writeTrackD0Z0=True)
152  # Muons.IFFClassification
153  config.addBlock ('Muons.IFFClassification')
154  config.setOptions (containerName='AnaMuons')
155  # Muons.MCTCClassification
156  config.addBlock ('Muons.MCTCClassification')
157  config.setOptions (containerName='AnaMuons')
158  config.setOptions (prefix='truth_')
159 
160  # TauJets
161  config.addBlock ('TauJets', containerName='AnaTauJets')
162  config.setOptions (decorateTruth=True)
163  # TauJets.WorkingPoint
164  config.addBlock ('TauJets.WorkingPoint')
165  config.setOptions (containerName='AnaTauJets')
166  config.setOptions (selectionName='tight')
167  config.setOptions (quality='Tight')
168  # TauJets.TriggerSF
169  tauTriggerChainsSF = {
170  2015: ['HLT_tau25_medium1_tracktwo', 'HLT_tau35_medium1_tracktwo'],
171  2016: ['HLT_tau25_medium1_tracktwo', 'HLT_tau35_medium1_tracktwo'],
172  2017: ['HLT_tau25_medium1_tracktwo', 'HLT_tau35_medium1_tracktwo'],
173  2018: ['HLT_tau25_medium1_tracktwoEF_OR_mediumRNN_tracktwoMVA', 'HLT_tau35_medium1_tracktwoEF_OR_mediumRNN_tracktwoMVA'],
174  }
175  config.addBlock ('TauJets.TriggerSF')
176  config.setOptions (containerName='AnaTauJets')
177  config.setOptions (tauID='Tight')
178  config.setOptions (triggerChainsPerYear=tauTriggerChainsSF)
179  # TauJets.MCTCClassification
180  config.addBlock ('TauJets.MCTCClassification')
181  config.setOptions (containerName='AnaTauJets')
182  config.setOptions (prefix='truth_')
183 
184  config.addBlock ('SystObjectLink')
185  config.setOptions (containerName='AnaJets')
186  config.addBlock ('SystObjectLink')
187  config.setOptions (containerName='AnaLargeRJets')
188  config.addBlock ('SystObjectLink')
189  config.setOptions (containerName='AnaElectrons')
190  config.addBlock ('SystObjectLink')
191  config.setOptions (containerName='AnaPhotons')
192  config.addBlock ('SystObjectLink')
193  config.setOptions (containerName='AnaMuons')
194  config.addBlock ('SystObjectLink')
195  config.setOptions (containerName='AnaTauJets')
196 
197  config.addBlock ('ObjectCutFlow')
198  config.setOptions (containerName='AnaJets')
199  config.setOptions (selectionName='jvt')
200  config.addBlock ('ObjectCutFlow')
201  config.setOptions (containerName='AnaElectrons')
202  config.setOptions (selectionName='loose')
203  config.addBlock ('ObjectCutFlow')
204  config.setOptions (containerName='AnaPhotons')
205  config.setOptions (selectionName='tight')
206  config.addBlock ('ObjectCutFlow')
207  config.setOptions (containerName='AnaMuons')
208  config.setOptions (selectionName='medium')
209  config.addBlock ('ObjectCutFlow')
210  config.setOptions (containerName='AnaTauJets')
211  config.setOptions (selectionName='tight')
212 
213  # GeneratorLevelAnalysis
214  config.addBlock( 'GeneratorLevelAnalysis')
215 
216  # MissingET
217  config.addBlock ('MissingET')
218  config.setOptions (containerName='AnaMET')
219  config.setOptions (jets='AnaJets')
220  config.setOptions (taus='AnaTauJets.tight')
221  config.setOptions (electrons='AnaElectrons.loose')
222  config.setOptions (photons='AnaPhotons.tight')
223  config.setOptions (muons='AnaMuons.medium')
224 
225  # OverlapRemoval
226  config.addBlock( 'OverlapRemoval' )
227  config.setOptions (inputLabel='preselectOR')
228  config.setOptions (outputLabel='passesOR' )
229  config.setOptions (jets='AnaJets.baselineJvt')
230  config.setOptions (taus='AnaTauJets.tight')
231  config.setOptions (electrons='AnaElectrons.loose')
232  config.setOptions (photons='AnaPhotons.tight')
233  config.setOptions (muons='AnaMuons.medium')
234 
235  # Particle-level objects
236  config.addBlock ('PL_Electrons')
237  config.setOptions (containerName='TruthElectrons')
238  config.addBlock ('PL_Electrons.PtEtaSelection')
239  config.setOptions (containerName='TruthElectrons')
240  config.setOptions (skipOnData=True)
241  config.setOptions (useDressedProperties=True)
242  config.setOptions (minPt=20e3)
243  config.addBlock ('PL_Electrons.MCTCClassification')
244  config.setOptions (containerName='TruthElectrons')
245  config.setOptions (prefix='')
246 
247  config.addBlock ('PL_Photons')
248  config.setOptions (containerName='TruthPhotons')
249  config.addBlock ('PL_Photons.PtEtaSelection')
250  config.setOptions (containerName='TruthPhotons')
251  config.setOptions (skipOnData=True)
252  config.setOptions (minPt=20e3)
253 
254  config.addBlock ('PL_Muons')
255  config.setOptions (containerName='TruthMuons')
256  config.addBlock ('PL_Muons.PtEtaSelection')
257  config.setOptions (containerName='TruthMuons')
258  config.setOptions (skipOnData=True)
259  config.setOptions (useDressedProperties=True)
260  config.setOptions (minPt=20e3)
261  config.addBlock ('PL_Muons.MCTCClassification')
262  config.setOptions (containerName='TruthMuons')
263  config.setOptions (prefix='')
264 
265  config.addBlock ('PL_Taus')
266  config.setOptions (containerName='TruthTaus')
267  config.addBlock ('PL_Taus.PtEtaSelection')
268  config.setOptions (containerName='TruthTaus')
269  config.setOptions (skipOnData=True)
270  config.setOptions (minPt=20e3)
271  config.addBlock ('PL_Taus.MCTCClassification')
272  config.setOptions (containerName='TruthTaus')
273  config.setOptions (prefix='')
274 
275  config.addBlock ('PL_Jets')
276  config.setOptions (containerName='AntiKt4TruthDressedWZJets')
277  config.addBlock ('PL_Jets.PtEtaSelection')
278  config.setOptions (containerName='AntiKt4TruthDressedWZJets')
279  config.setOptions (skipOnData=True)
280  config.setOptions (minPt=20e3)
281 
282  config.addBlock ('PL_Neutrinos')
283  config.setOptions (skipOnData=True)
284  config.addBlock ('PL_MissingET')
285  config.setOptions (skipOnData=True)
286 
287  config.addBlock ('PL_OverlapRemoval')
288  config.setOptions (skipOnData=True)
289  config.setOptions (electrons='TruthElectrons')
290  config.setOptions (muons='TruthMuons')
291  config.setOptions (photons='TruthPhotons')
292  config.setOptions (jets='AntiKt4TruthDressedWZJets')
293  config.setOptions (useRapidityForDeltaR=False)
294 
295  # Thinning
296  config.addBlock ('Thinning')
297  config.setOptions (containerName='AnaElectrons')
298  config.setOptions (selectionName='loose')
299  config.setOptions (outputName='OutElectrons')
300  config.addBlock ('Thinning')
301  config.setOptions (containerName='AnaPhotons')
302  config.setOptions (selectionName='tight')
303  config.setOptions (outputName='OutPhotons')
304  config.addBlock ('Thinning')
305  config.setOptions (containerName='AnaMuons')
306  config.setOptions (selectionName='medium')
307  config.setOptions (outputName='OutMuons')
308  config.addBlock ('Thinning')
309  config.setOptions (containerName='AnaTauJets')
310  config.setOptions (selectionName='tight')
311  config.setOptions (outputName='OutTauJets')
312  config.addBlock ('Thinning')
313  config.setOptions (containerName='AnaJets')
314  config.setOptions (outputName='OutJets')
315  config.addBlock ('Thinning')
316  config.setOptions (containerName='AnaLargeRJets')
317  config.setOptions (outputName='OutLargeRJets')
318  config.addBlock ('Thinning')
319  config.setOptions (containerName='TruthElectrons')
320  config.setOptions (skipOnData=True)
321  config.setOptions (outputName='OutTruthElectrons')
322  config.addBlock ('Thinning')
323  config.setOptions (containerName='TruthPhotons')
324  config.setOptions (skipOnData=True)
325  config.setOptions (outputName='OutTruthPhotons')
326  config.addBlock ('Thinning')
327  config.setOptions (containerName='TruthMuons')
328  config.setOptions (skipOnData=True)
329  config.setOptions (outputName='OutTruthMuons')
330  config.addBlock ('Thinning')
331  config.setOptions (containerName='TruthTaus')
332  config.setOptions (skipOnData=True)
333  config.setOptions (outputName='OutTruthTaus')
334  config.addBlock ('Thinning')
335  config.setOptions (containerName='AntiKt4TruthDressedWZJets')
336  config.setOptions (outputName='OutTruthJets')
337  config.setOptions (skipOnData=True)
338 
339  # Trigger
340  triggerChainsPerYear = {
341  2015: ['HLT_e24_lhmedium_L1EM20VH || HLT_e60_lhmedium || HLT_e120_lhloose', 'HLT_mu20_iloose_L1MU15 || HLT_mu40', 'HLT_2g20_tight'],
342  2016: ['HLT_e26_lhtight_nod0_ivarloose || HLT_e60_lhmedium_nod0 || HLT_e140_lhloose_nod0', 'HLT_mu26_ivarmedium || HLT_mu50', 'HLT_g35_loose_g25_loose'],
343  2017: ['HLT_e26_lhtight_nod0_ivarloose || HLT_e60_lhmedium_nod0 || HLT_e140_lhloose_nod0', 'HLT_2g22_tight_L12EM15VHI', 'HLT_mu50'],
344  2018: ['HLT_e26_lhtight_nod0_ivarloose || HLT_e60_lhmedium_nod0 || HLT_e140_lhloose_nod0', 'HLT_g35_medium_g25_medium_L12EM20VH', 'HLT_mu26_ivarmedium', 'HLT_2mu14'],
345  }
346  config.addBlock ('Trigger')
347  config.setOptions (triggerChainsPerYear=triggerChainsPerYear)
348  config.setOptions (noFilter=True)
349  config.setOptions (electrons='AnaElectrons.loose')
350  config.setOptions (photons='AnaPhotons.tight')
351  config.setOptions (muons='AnaMuons.medium')
352  config.setOptions (taus='AnaTauJets.tight')
353  config.setOptions (electronID='Tight')
354  config.setOptions (electronIsol='Tight_VarRad')
355  config.setOptions (photonIsol='TightCaloOnly')
356  config.setOptions (muonID='Tight')
357  config.setOptions (triggerMatchingChainsPerYear=triggerChainsPerYear)
358 
359  # EventSelection
360  # Example cuts used for event selection algorithm test
361  exampleSelectionCuts = {
362  'SUBcommon': """JET_N_BTAG >= 2
363 JET_N 25000 >= 4
364 MET >= 20000
365 SAVE
366 """,
367  'ejets': """IMPORT SUBcommon
368 EL_N 5000 == 1
369 MU_N 3000 == 0
370 MWT < 170000
371 MET+MWT > 40000
372 SAVE
373 """,
374  'mujets': """IMPORT SUBcommon
375 EL_N 5000 == 0
376 MU_N medium 25000 > 0
377 SAVE
378 """
379  }
380  config.addBlock ('EventSelection')
381  config.setOptions (electrons='AnaElectrons.loose')
382  config.setOptions (muons='AnaMuons.medium')
383  config.setOptions (jets='AnaJets.baselineJvt')
384  config.setOptions (met='AnaMET')
385  config.setOptions (btagDecoration='ftag_select_ftag')
386  config.setOptions (noFilter=True)
387  config.setOptions (cutFlowHistograms=True)
388  config.setOptions (selectionCutsDict=exampleSelectionCuts)
389 
390  # Bootstraps
391  config.addBlock ('Bootstraps')
392  config.setOptions (nReplicas=2000)
393  config.setOptions (skipOnMC=False)
394 
395  # LeptonSF
396  config.addBlock ('LeptonSF')
397  config.setOptions (muons='AnaMuons.medium')
398  config.setOptions (photons='AnaPhotons.tight')
399  config.setOptions (lepton_postfix='nominal')
400 
401  # Output
402  outputContainers = {
403  'mu_': 'OutMuons',
404  'el_': 'OutElectrons',
405  'ph_' : 'OutPhotons',
406  'tau_': 'OutTauJets',
407  'jet_': 'OutJets',
408  'larger_jet_': 'OutLargeRJets',
409  'met_': 'AnaMET',
410  '': 'EventInfo'}
411  outputContainersForMC = {'truth_mu_' : 'OutTruthMuons',
412  'truth_el_' : 'OutTruthElectrons',
413  'truth_ph_' : 'OutTruthPhotons',
414  'truth_tau_': 'OutTruthTaus',
415  'truth_jet_': 'OutTruthJets',
416  'truth_met_': 'TruthMET'}
417  config.addBlock ('Output')
418  config.setOptions (treeName='analysis')
419  config.setOptions (vars=[
420  'EventInfo.actualInteractionsPerCrossing -> actualMuScaled',
421  ])
422  config.setOptions (metVars=[
423  'AnaMET_%SYS%.met -> met_%SYS%',
424  ])
425  config.setOptions (truthMetVars=[
426  'TruthMET_NOSYS.met -> truth_met',
427  ])
428  config.setOptions (containers=outputContainers)
429  config.setOptions (containersOnlyForMC=outputContainersForMC)
430  config.setOptions (commands=[
431  "disable actualInteractionsPerCrossing",
432  ])
433 
434  # configure ConfigSequence
435  configSeq = config.configure()
436 
437  # create text config object to build text configurations
438  textConfig = TextConfig(yamlPath)
439  textConfigSeq = textConfig.configure()
440 
441  # compare - will raise error if False
442  compareConfigSeq(configSeq, textConfigSeq, checkOrder=checkOrder)
443 
444 
445 def compareBlockConfig(yamlPath='', *, checkOrder=False) :
446  """
447  Create a configSequence using provided YAML file and a
448  configSequence using the block configuration and compare.
449 
450  Will raise an exception if configSequences differ
451  """
452  from AthenaConfiguration.Enums import LHCPeriod
453  # create configSeq for block configuration
454  from AnalysisAlgorithmsConfig.FullCPAlgorithmsTest import makeTestSequenceBlocks
455  configSeq = makeTestSequenceBlocks(dataType='fullsim', algSeq=None,
456  geometry=LHCPeriod.Run2,
457  isPhyslite=False, forceEGammaFullSimConfig=True,
458  returnConfigSeq=True)
459 
460  # create text config object to build text configurations
461  from AnalysisAlgorithmsConfig.ConfigText import TextConfig
462  textConfig = TextConfig(yamlPath)
463  textConfigSeq = textConfig.configure()
464 
465  # compare - will raise error if False
466  compareConfigSeq(configSeq, textConfigSeq, checkOrder=checkOrder)
467 
468 
469 if __name__ == '__main__':
470  import os
471  import optparse
472  parser = optparse.OptionParser()
473  parser.add_option('--text-config', dest='text_config',
474  default='', action='store',
475  help='YAML file used in unit test')
476  parser.add_option('--compare-block', dest='compare_block',
477  default=False, action='store_true',
478  help='Compare config sequence from YAML and block configuration')
479  parser.add_option('--compare-builder', dest='compare_builder',
480  default=False, action='store_true',
481  help='Compare config sequence from YAML and python configuration')
482  parser.add_option('--check-order', dest='check_order',
483  default=False, action='store_true',
484  help='Require blocks to be in the same order')
485  (options, args) = parser.parse_args()
486  textConfig = options.text_config
487  compareBlock = options.compare_block
488  compareBuilder = options.compare_builder
489  checkOrder = options.check_order
490 
491  from PathResolver import PathResolver
492  textConfig = PathResolver.FindCalibFile(textConfig)
493 
494  if not os.path.isfile(textConfig):
495  raise FileNotFoundError(f"{textConfig} is not a file")
496 
497  # compare YAML and builder
498  if compareBuilder:
499  print("Comparing config sequences from the block and text"
500  "configuration methods")
501  compareTextBuilder(textConfig, checkOrder=checkOrder)
502  # compare YAML and block config
503  if compareBlock:
504  print("Comparing config sequences from the block and block"
505  "configuration methods")
506  compareBlockConfig(textConfig, checkOrder=checkOrder)
python.ConfigText_unitTest.compareConfigSeq
def compareConfigSeq(seq1, seq2, *checkOrder=False)
Definition: ConfigText_unitTest.py:7
PathResolver::FindCalibFile
static std::string FindCalibFile(const std::string &logical_file_name)
Definition: PathResolver.h:108
python.ConfigText_unitTest.compareTextBuilder
def compareTextBuilder(yamlPath='', *checkOrder=False)
Definition: ConfigText_unitTest.py:46
vtune_athena.format
format
Definition: vtune_athena.py:14
max
constexpr double max()
Definition: ap_fixedTest.cxx:33
python.FullCPAlgorithmsTest.makeTestSequenceBlocks
def makeTestSequenceBlocks(dataType, algSeq, isPhyslite, geometry=None, autoconfigFromFlags=None, noSystematics=None, onlyNominalOR=False, forceEGammaFullSimConfig=False, returnConfigSeq=False, bleedingEdge=False)
Definition: FullCPAlgorithmsTest.py:52
python.ConfigText_unitTest.compareBlockConfig
def compareBlockConfig(yamlPath='', *checkOrder=False)
Definition: ConfigText_unitTest.py:445
plotBeamSpotVxVal.range
range
Definition: plotBeamSpotVxVal.py:195
print
void print(char *figname, TCanvas *c1)
Definition: TRTCalib_StrawStatusPlots.cxx:25