diff --git a/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/python/ConfigAccumulator.py b/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/python/ConfigAccumulator.py index 6085d8986fe378ae2ec4159aebd6f87b0c1c24b2..ffeee43e1fc696d7cfca98715becc11f946b2580 100644 --- a/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/python/ConfigAccumulator.py +++ b/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/python/ConfigAccumulator.py @@ -32,9 +32,10 @@ class ContainerConfig : This tracks the naming of all temporary containers, as well as all the selection decorations.""" - def __init__ (self, name, sourceName) : + def __init__ (self, name, sourceName, *, originalName = None) : self.name = name self.sourceName = sourceName + self.originalName = originalName self.index = 0 self.maxIndex = None self.viewIndex = 1 @@ -141,16 +142,23 @@ class ConfigAccumulator : DualUseConfig.addPrivateTool (self._currentAlg, type, name) - def setSourceName (self, containerName, sourceName) : - """set the (default) name of the original container + def setSourceName (self, containerName, sourceName, + *, originalName = None) : + """set the (default) name of the source/original container This is essentially meant to allow using e.g. the muon configuration and the user not having to manually specify that they want to use the Muons/AnalysisMuons container from the input file. + + In addition it allows to set the original name of the + container (which may be different from the source name), which + is mostly/exclusively used for jet containers, so that + subsequent configurations know which jet container they + operate on. """ if containerName not in self._containerConfig : - self._containerConfig[containerName] = ContainerConfig (containerName, sourceName) + self._containerConfig[containerName] = ContainerConfig (containerName, sourceName, originalName = originalName) def readName (self, containerName) : @@ -185,6 +193,21 @@ class ConfigAccumulator : return self._containerConfig[containerName].index == 0 + def originalName (self, containerName) : + """get the "original" name of the given container + + This is mostly/exclusively used for jet containers, so that + subsequent configurations know which jet container they + operate on. + """ + if containerName not in self._containerConfig : + raise Exception ("container unknown: " + containerName) + result = self._containerConfig[containerName].originalName + if result is None : + raise Exception ("no original name for: " + containerName) + return result + + def nextPass (self) : """switch to the next configuration pass diff --git a/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/python/FullCPAlgorithmsTest.py b/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/python/FullCPAlgorithmsTest.py index 31d0db7bba42c61c1ec02fa5c4b6401ee30511bd..6b8c1a8462e64a54bf6f5ac74eaf21b95df69921 100644 --- a/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/python/FullCPAlgorithmsTest.py +++ b/PhysicsAnalysis/Algorithms/AnalysisAlgorithmsConfig/python/FullCPAlgorithmsTest.py @@ -101,15 +101,14 @@ def makeSequenceOld (dataType, algSeq, vars, forCompare, isPhyslite, noPhysliteB btagger = "DL1r" btagWP = "FixedCutBEff_77" makeFTagAnalysisSequence( jetSequence, dataType, jetContainer, noEfficiency = False, legacyRecommendations = True, - enableCutflow=True, btagger = btagger, btagWP = btagWP ) - if not forCompare : + enableCutflow=True, btagger = btagger, btagWP = btagWP, kinematicSelection = True ) + vars += [ + 'OutJets_%SYS%.ftag_select_' + btagger + '_' + btagWP + ' -> jet_ftag_select_%SYS%', + ] + if dataType != 'data' : vars += [ - 'OutJets_%SYS%.ftag_select_' + btagger + '_' + btagWP + ' -> jet_ftag_select_%SYS%', + 'OutJets_%SYS%.ftag_effSF_' + btagger + '_' + btagWP + '_%SYS% -> jet_ftag_eff_%SYS%' ] - if dataType != 'data' : - vars += [ - 'OutJets_%SYS%.ftag_effSF_' + btagger + '_' + btagWP + '_%SYS% -> jet_ftag_eff_%SYS%' - ] jetSequence.configure( inputName = input, outputName = 'AnaJets_%SYS%' ) @@ -562,6 +561,20 @@ def makeSequenceBlocks (dataType, algSeq, vars, forCompare, isPhyslite, noPhysli 'OutJets_%SYS%.jvt_effSF_%SYS% -> jet_jvtEfficiency_%SYS%', ] + if not noPhysliteBroken : + from FTagAnalysisAlgorithms.FTagAnalysisConfig import makeFTagAnalysisConfig + btagger = "DL1r" + btagWP = "FixedCutBEff_77" + makeFTagAnalysisConfig( configSeq, 'AnaJets', noEfficiency = False, legacyRecommendations = True, + btagger = btagger, btagWP = btagWP, kinematicSelection = True ) + vars += [ + 'OutJets_%SYS%.ftag_select_' + btagger + '_' + btagWP + ' -> jet_ftag_select_%SYS%', + ] + if dataType != 'data' : + vars += [ + 'OutJets_%SYS%.ftag_effSF_' + btagger + '_' + btagWP + '_%SYS% -> jet_ftag_eff_%SYS%' + ] + if dataType != 'data' : # Include, and then set up the generator analysis sequence: diff --git a/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/python/FTagAnalysisConfig.py b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/python/FTagAnalysisConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..fc9f689f999be6dc65678f56be6da1697c1457ea --- /dev/null +++ b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/python/FTagAnalysisConfig.py @@ -0,0 +1,169 @@ +# Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration + +# AnaAlgorithm import(s): +from AnalysisAlgorithmsConfig.ConfigBlock import ConfigBlock + + +class FTagConfig (ConfigBlock): + """the ConfigBlock for the flavor tagging config""" + + def __init__ (self, containerName) : + super (FTagConfig, self).__init__ () + self.containerName = containerName + self.btagWP = "FixedCutBEff_77" + self.btagger = "DL1r" + self.generator = "default" + self.postfix = "" + self.kinematicSelection = True + self.noEfficiency = False + self.legacyRecommendations = False + self.minPt = None + + def makeAlgs (self, config) : + + jetCollection = config.originalName (self.containerName) + selectionName = self.postfix + if selectionName is None or selectionName == '' : + selectionName = self.btagger + '_' + self.btagWP + + postfix = selectionName + if postfix != "" and postfix[0] != '_' : + postfix = '_' + postfix + + # Kinematic selection depending on validity of the calibration + # https://twiki.cern.ch/twiki/bin/view/AtlasProtected/BTagCalibrationRecommendationsRelease21 + minPt = self.minPt + if minPt is None: + if "EMPFlow" in jetCollection: + minPt = 20e3 + elif "EMTopo" in jetCollection: + minPt = 20e3 + elif "VRTrack" in jetCollection: + minPt = 10e3 + + if self.generator not in ["default", "Pythia8", "Sherpa221", "Sherpa228", "Sherpa2210", "Herwig7", "Herwig713", "Herwig721", "amc@NLO"]: + raise ValueError ("invalid generator type: " + self.generator) + + # MC/MC scale factors configuration + DSID = "default" + if self.generator == "Sherpa221": + DSID = "410250" + elif self.generator == "Sherpa228": + DSID = "421152" + elif self.generator == "Sherpa2210": + DSID = "700122" + elif self.generator == "Herwig7": + DSID = "410558" + elif self.generator == "Herwig713": + DSID = "411233" + elif self.generator == "Herwig721": + DSID = "600666" + elif self.generator == "amc@NLO": + DSID = "410464" + + if self.legacyRecommendations: + # Remove b-tagging calibration from the container name + btIndex = jetCollection.find('_BTagging') + if btIndex == -1: + jetCollection += '_BTagging201903' + + # CDI file + # https://twiki.cern.ch/twiki/bin/view/AtlasProtected/BTagCalibrationRecommendationsRelease21 + bTagCalibFile = "xAODBTaggingEfficiency/13TeV/2020-21-13TeV-MC16-CDI-2021-04-16_v1.root" + + # This is the new calibration file, but it seems to have issues in some cases + #bTagCalibFile = "xAODBTaggingEfficiency/13TeV/2022-22-13TeV-MC20-CDI-2022-07-28_v1.root" + + if self.kinematicSelection: + # Set up the ftag kinematic selection algorithm(s): + alg = config.createAlgorithm( 'CP::AsgSelectionAlg', 'FTagKinSelectionAlg'+postfix ) + config.addPrivateTool( 'selectionTool', 'CP::AsgPtEtaSelectionTool' ) + alg.selectionTool.minPt = minPt + alg.selectionTool.maxEta = 2.5 + alg.selectionDecoration = 'ftag_kin_select_' + selectionName + ',as_char' + alg.preselection = config.getPreselection (self.containerName, selectionName) + config.addSelection (self.containerName, selectionName, + alg.selectionDecoration, + bits=1, preselection=True) + alg.particles = config.readName (self.containerName) + + # Set up the ftag selection algorithm(s): + alg = config.createAlgorithm( 'CP::AsgSelectionAlg', 'FTagSelectionAlg' + postfix ) + config.addPrivateTool( 'selectionTool', 'BTaggingSelectionTool' ) + alg.selectionTool.TaggerName = self.btagger + alg.selectionTool.OperatingPoint = self.btagWP + alg.selectionTool.JetAuthor = jetCollection + alg.selectionTool.FlvTagCutDefinitionsFileName = bTagCalibFile + alg.selectionTool.MinPt = minPt + alg.preselection = config.getPreselection (self.containerName, selectionName) + alg.selectionDecoration = 'ftag_select_' + selectionName + ',as_char' + alg.particles = config.readName (self.containerName) + + if self.btagWP == 'Continuous': + alg = config.createAlgorithm( 'CP::BTaggingInformationDecoratorAlg', 'FTagInfoAlg' + postfix ) + config.addPrivateTool( 'selectionTool', 'BTaggingSelectionTool' ) + alg.selectionTool.TaggerName = self.btagger + alg.selectionTool.OperatingPoint = self.btagWP + alg.selectionTool.JetAuthor = jetCollection + alg.selectionTool.FlvTagCutDefinitionsFileName = bTagCalibFile + alg.selectionTool.MinPt = minPt + alg.preselection = config.getPreselection (self.containerName, selectionName) + alg.quantileDecoration = 'ftag_quantile_' + selectionName + alg.jets = config.readName (self.containerName) + + if not self.noEfficiency and config.dataType() != 'data': + # Set up the efficiency calculation algorithm: + alg = config.createAlgorithm( 'CP::BTaggingEfficiencyAlg', + 'FTagEfficiencyScaleFactorAlg' + postfix ) + config.addPrivateTool( 'efficiencyTool', 'BTaggingEfficiencyTool' ) + alg.efficiencyTool.TaggerName = self.btagger + alg.efficiencyTool.OperatingPoint = self.btagWP + alg.efficiencyTool.JetAuthor = jetCollection + alg.efficiencyTool.ScaleFactorFileName = bTagCalibFile + alg.efficiencyTool.SystematicsStrategy = "Envelope" + alg.efficiencyTool.MinPt = minPt + if DSID != "default": + alg.efficiencyTool.EfficiencyBCalibrations = DSID + alg.efficiencyTool.EfficiencyTCalibrations = DSID + alg.efficiencyTool.EfficiencyCCalibrations = DSID + alg.efficiencyTool.EfficiencyLightCalibrations = DSID + alg.scaleFactorDecoration = 'ftag_effSF_' + selectionName + '_%SYS%' + alg.selectionDecoration = 'ftag_select_' + selectionName + ',as_char' + alg.onlyEfficiency = self.btagWP == 'Continuous' + alg.outOfValidity = 2 + alg.outOfValidityDeco = 'no_ftag_' + selectionName + alg.preselection = config.getPreselection (self.containerName, selectionName) + alg.jets = config.readName (self.containerName) + + +def makeFTagAnalysisConfig( seq, containerName, + btagWP = "FixedCutBEff_77", + btagger = "DL1r", + generator = "default", + postfix = "", + kinematicSelection = True, + noEfficiency = False, + legacyRecommendations = False, + minPt = None ): + """Create a ftag analysis algorithm config + + Keyword arguments: + btagWP -- Flavour tagging working point + btagger -- Flavour tagger + generator -- Generator for MC/MC scale factors + kinematicSelection -- Wether to run kinematic selection + noEfficiency -- Wether to run efficiencies calculation + legacyRecommendations -- Use legacy recommendations without shallow copied containers + minPt -- Kinematic selection for jet calibration validity (depending on jet collection) + """ + + config = FTagConfig (containerName) + config.btagWP = btagWP + config.btagger = btagger + config.generator = generator + config.postfix = postfix + config.kinematicSelection = kinematicSelection + config.noEfficiency = noEfficiency + config.legacyRecommendations = legacyRecommendations + config.minPt = minPt + seq.append (config) diff --git a/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/python/FTagAnalysisSequence.py b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/python/FTagAnalysisSequence.py index ab6e0ca47fcbed8e320a6a9e9d32744c55b63c13..cf260c396591f79de2747fc2b45a916997c527e5 100644 --- a/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/python/FTagAnalysisSequence.py +++ b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/python/FTagAnalysisSequence.py @@ -13,7 +13,8 @@ def makeFTagAnalysisSequence( seq, dataType, jetCollection, noEfficiency = False, legacyRecommendations = False, enableCutflow = False, - minPt = None ): + minPt = None, + makeViewContainer = False): """Create a ftag analysis algorithm sequence for now the sequence is passed in, I'm unsure if I can concatenate @@ -42,6 +43,10 @@ def makeFTagAnalysisSequence( seq, dataType, jetCollection, elif "VRTrack" in jetCollection: minPt = 10e3 + preselectionList = [] + if preselection is not None and preselection != '' : + preselectionList.append (preselection) + if dataType not in ["data", "mc", "afii"] : raise ValueError ("invalid data type: " + dataType) @@ -88,15 +93,18 @@ def makeFTagAnalysisSequence( seq, dataType, jetCollection, alg.selectionTool.minPt = minPt alg.selectionTool.maxEta = 2.5 alg.selectionDecoration = 'ftag_kin_select_' + btagger + '_' + btagWP + alg.preselection = '&&'.join (preselectionList) + preselectionList.append (alg.selectionDecoration) seq.append( alg, inputPropName = 'particles' ) - # Set up an algorithm that makes a view container using the selections - # performed previously: - alg = createAlgorithm( 'CP::AsgViewFromSelectionAlg', - 'FTagKinViewFromSelectionAlg'+postfix ) - alg.selection = [ 'ftag_kin_select_' + btagger + '_' + btagWP ] - seq.append( alg, inputPropName = 'input', outputPropName = 'output', - stageName = 'selection' ) + if makeViewContainer : + # Set up an algorithm that makes a view container using the selections + # performed previously: + alg = createAlgorithm( 'CP::AsgViewFromSelectionAlg', + 'FTagKinViewFromSelectionAlg'+postfix ) + alg.selection = [ 'ftag_kin_select_' + btagger + '_' + btagWP ] + seq.append( alg, inputPropName = 'input', outputPropName = 'output', + stageName = 'selection' ) # Set up the ftag selection algorithm(s): alg = createAlgorithm( 'CP::AsgSelectionAlg', 'FTagSelectionAlg' + btagger + btagWP + postfix ) @@ -106,8 +114,7 @@ def makeFTagAnalysisSequence( seq, dataType, jetCollection, alg.selectionTool.JetAuthor = jetCollection alg.selectionTool.FlvTagCutDefinitionsFileName = bTagCalibFile alg.selectionTool.MinPt = minPt - if preselection is not None: - alg.preselection = preselection + alg.preselection = '&&'.join (preselectionList) alg.selectionDecoration = 'ftag_select_' + btagger + '_' + btagWP + ',as_char' seq.append( alg, inputPropName = 'particles', stageName = 'selection' ) @@ -120,8 +127,7 @@ def makeFTagAnalysisSequence( seq, dataType, jetCollection, alg.selectionTool.JetAuthor = jetCollection alg.selectionTool.FlvTagCutDefinitionsFileName = bTagCalibFile alg.selectionTool.MinPt = minPt - if preselection is not None: - alg.preselection = preselection + alg.preselection = '&&'.join (preselectionList) alg.quantileDecoration = 'ftag_quantile_' + btagger seq.append( alg, inputPropName = 'jets', stageName = 'selection' ) @@ -148,8 +154,7 @@ def makeFTagAnalysisSequence( seq, dataType, jetCollection, alg.onlyEfficiency = btagWP == 'Continuous' alg.outOfValidity = 2 alg.outOfValidityDeco = 'no_ftag_' + btagger + '_' + btagWP - if preselection is not None: - alg.preselection = preselection + alg.preselection = '&&'.join (preselectionList) seq.append( alg, inputPropName = 'jets', stageName = 'efficiency' ) pass diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetAnalysisConfig.py b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetAnalysisConfig.py index eccec1db8890f516857eab2c5091272c54bfbf94..0da23ee33d6a9cb8c61926d2f28776fb80eff5c7 100644 --- a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetAnalysisConfig.py +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetAnalysisConfig.py @@ -27,9 +27,9 @@ class PreJetAnalysisConfig (ConfigBlock) : def makeAlgs (self, config) : if config.isPhyslite() : - config.setSourceName (self.containerName, "AnalysisJets") + config.setSourceName (self.containerName, "AnalysisJets", originalName = self.jetCollection) else : - config.setSourceName (self.containerName, self.jetCollection) + config.setSourceName (self.containerName, self.jetCollection, originalName = self.jetCollection) # Relink original jets in case of b-tagging calibration if self.runOriginalObjectLink :