diff --git a/PhysicsAnalysis/AnalysisCommon/ParticleJetTools/python/DefaultTools.py b/PhysicsAnalysis/AnalysisCommon/ParticleJetTools/python/DefaultTools.py deleted file mode 100644 index 216d829411ffd96399ba44972edb173558be1807..0000000000000000000000000000000000000000 --- a/PhysicsAnalysis/AnalysisCommon/ParticleJetTools/python/DefaultTools.py +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration - - -def declareDefaultTools(): - - from JetRecConfig.JetRecFlags import jetFlags - from JetRecConfig.JetRecStandardToolManager import jtm - from MCTruthClassifier.MCTruthClassifierConf import MCTruthClassifier - from JetRec.JetRecConf import PseudoJetGetter - - try: - from ParticleJetTools.ParticleJetToolsConf import Analysis__JetQuarkLabel - jtm.haveParticleJetTools = True - except: - jtm.haveParticleJetTools = False - if jtm.haveParticleJetTools: - from ParticleJetTools.ParticleJetToolsConf import Analysis__JetConeLabeling - from ParticleJetTools.ParticleJetToolsConf import Analysis__JetPartonTruthLabel - from ParticleJetTools.ParticleJetToolsConf import CopyTruthJetParticles - from ParticleJetTools.ParticleJetToolsConf import ParticleJetDeltaRLabelTool - - ghostScaleFactor = 1e-40 - - #-------------------------------------------------------------- - # Truth selection. - #-------------------------------------------------------------- - - if jetFlags.useTruth: - truthClassifier = MCTruthClassifier(name = "JetMCTruthClassifier", - ParticleCaloExtensionTool="") - jtm += truthClassifier - - jtm += CopyTruthJetParticles("truthpartcopy", OutputName="JetInputTruthParticles", - MCTruthClassifier=truthClassifier) - jtm += CopyTruthJetParticles("truthpartcopywz", OutputName="JetInputTruthParticlesNoWZ", - MCTruthClassifier=truthClassifier, - IncludePromptLeptons=False, - IncludeMuons=True,IncludeNeutrinos=True) - - # Truth. - if jetFlags.useTruth and jtm.haveParticleJetTools: - # ParticleJetTools tools may be omitted in analysi releases. - #ift jtm.haveParticleJetTools: - # Delta-R truth parton label: truthpartondr. - jtm += Analysis__JetQuarkLabel( - "jetquarklabel", - McEventCollection = "TruthEvents" - ) - jtm += Analysis__JetConeLabeling( - "truthpartondr", - JetTruthMatchTool = jtm.jetquarklabel - ) - - # Parton truth label. - jtm += Analysis__JetPartonTruthLabel("partontruthlabel") - - # Cone matching for B, C and tau truth for all but track jets. - jtm += ParticleJetDeltaRLabelTool( - "jetdrlabeler", - LabelName = "HadronConeExclTruthLabelID", - DoubleLabelName = "HadronConeExclExtendedTruthLabelID", - BLabelName = "ConeExclBHadronsFinal", - CLabelName = "ConeExclCHadronsFinal", - TauLabelName = "ConeExclTausFinal", - BParticleCollection = "TruthLabelBHadronsFinal", - CParticleCollection = "TruthLabelCHadronsFinal", - TauParticleCollection = "TruthLabelTausFinal", - PartPtMin = 5000.0, - JetPtMin = 0.0, - DRMax = 0.3, - MatchMode = "MinDR" - ) - - # Cone matching for B, C and tau truth for track jets. - jtm += ParticleJetDeltaRLabelTool( - "trackjetdrlabeler", - LabelName = "HadronConeExclTruthLabelID", - DoubleLabelName = "HadronConeExclExtendedTruthLabelID", - BLabelName = "ConeExclBHadronsFinal", - CLabelName = "ConeExclCHadronsFinal", - TauLabelName = "ConeExclTausFinal", - BParticleCollection = "TruthLabelBHadronsFinal", - CParticleCollection = "TruthLabelCHadronsFinal", - TauParticleCollection = "TruthLabelTausFinal", - PartPtMin = 5000.0, - JetPtMin = 4500.0, - DRMax = 0.3, - MatchMode = "MinDR" - ) - - jtm += PseudoJetGetter( - "truthget", - Label = "Truth", - InputContainer = jtm.truthpartcopy.OutputName, - OutputContainer = "PseudoJetTruth", - GhostScale = 0.0, - SkipNegativeEnergy = True, - - ) - jtm += PseudoJetGetter( - "truthwzget", - Label = "TruthWZ", - InputContainer = jtm.truthpartcopywz.OutputName, - OutputContainer = "PseudoJetTruthWZ", - GhostScale = 0.0, - SkipNegativeEnergy = True, - - ) - jtm += PseudoJetGetter( - "gtruthget", - Label = "GhostTruth", - InputContainer = jtm.truthpartcopy.OutputName, - OutputContainer = "PseudoJetGhostTruth", - GhostScale = ghostScaleFactor, - SkipNegativeEnergy = True, - ) - - # Truth flavor tags. - for ptype in jetFlags.truthFlavorTags(): - jtm += PseudoJetGetter( - "gtruthget_" + ptype, - InputContainer = "TruthLabel" + ptype, - Label = "Ghost" + ptype, - OutputContainer = "PseudoJetGhost" + ptype, - SkipNegativeEnergy = True, - GhostScale = ghostScaleFactor, - ) - - diff --git a/PhysicsAnalysis/AnalysisCommon/ParticleJetTools/python/ParticleJetToolsConfig.py b/PhysicsAnalysis/AnalysisCommon/ParticleJetTools/python/ParticleJetToolsConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..7be92cfb4cd7002994e3e1b5f7b04f448f9b1c4f --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/ParticleJetTools/python/ParticleJetToolsConfig.py @@ -0,0 +1,109 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +######################################################################## +# # +# ParticleJetToolsConfig: A helper module for configuring tools for # +# truth jet reconstruction and classification # +# Author: TJ Khoo # +# # +######################################################################## + +from AthenaCommon import Logging +jrtlog = Logging.logging.getLogger('ParticleJetToolsConfig') + +from ParticleJetTools import ParticleJetToolsConf +from MCTruthClassifier import MCTruthClassifierConf + +# Putting MCTruthClassifier here as we needn't stick jet configs in really foreign packages +def getMCTruthClassifier(): + # Assume mc15 value + firstSimCreatedBarcode = 200000 + truthclassif = MCTruthClassifierConf.MCTruthClassifier( + "JetMCTruthClassifier", + barcodeG4Shift=firstSimCreatedBarcode, + xAODTruthLinkVector="" + ) + # Config neessary only for Athena releases + import os + if "AtlasProject" in os.environ.keys(): + if os.environ["AtlasProject"] in ["Athena","AthDerivation"]: + truthclassif.ParticleCaloExtensionTool="" + return truthclassif + +# Generates truth particle containers for truth labeling +truthpartoptions = { + "Partons":{"ToolType":ParticleJetToolsConf.CopyTruthPartons,"ptmin":5000}, + "BosonTop":{"ToolType":ParticleJetToolsConf.CopyBosonTopLabelTruthParticles,"ptmin":100000}, + "FlavourLabel":{"ToolType":ParticleJetToolsConf.CopyFlavorLabelTruthParticles,"ptmin":5000}, +} +def getCopyTruthLabelParticles(truthtype): + truthcategory = "" + if truthtype == "Partons": + truthcategory = "Partons" + if truthtype in ["WBosons", "ZBosons", "HBosons", "TQuarksFinal"]: + truthcategory = "BosonTop" + else: + truthcategory = "FlavourLabel" + tooltype = truthpartoptions[truthcategory]["ToolType"] + ptmin = truthpartoptions[truthcategory]["ptmin"] + ctp = tooltype("truthpartcopy_{0}".format(truthtype), + PtMin = ptmin, + OutputName = "TruthLabel{0}".format(truthtype)) + return ctp + +# Generates input truth particle containers for truth jets +def getCopyTruthJetParticles(modspec): + truthclassif = getMCTruthClassifier() + + # Commented for now -- we ideally need a dual-use input file peeker + # # Input file is EVNT + # if objKeyStore.isInInput( "McEventCollection", "GEN_EVENT" ): + # barCodeFromMetadata=0 + + truthpartcopy = ParticleJetToolsConf.CopyTruthJetParticles( + "truthpartcopy"+modspec, + OutputName="JetInputTruthParticles"+modspec, + MCTruthClassifier=truthclassif, + BarCodeFromMetadata=2) + if modspec=="NoWZ": + truthpartcopy.IncludePromptLeptons=False + # truthpartcopy.IncludePromptPhotons=False # Needs cherry-pick from 21.2 + truthpartcopy.IncludeMuons=True + truthpartcopy.IncludeNeutrinos=True + return truthpartcopy + +def getJetQuarkLabel(): + jetquarklabel = ParticleJetToolsConf.Analysis__JetQuarkLabel( + "jetquarklabel", + McEventCollection = "TruthEvents" + ) + return jetquarklabel + +def getJetConeLabeling(): + jetquarklabel = getJetQuarkLabel() + truthpartonlabel = ParticleJetToolsConf.Analysis__JetConeLabeling( + "truthpartondr", + JetTruthMatchTool = jetquarklabel + ) + return truthpartonlabel + + # Cone matching for B, C and tau truth for all but track jets. +def getJetDeltaRLabelTool(modspec): + jetptmin = float(modspec) + jetdrlabeler = ParticleJetToolsConf.ParticleJetDeltaRLabelTool( + "jetdrlabeler_jetpt{0}GeV".format(int(jetptmin/1000)), + LabelName = "HadronConeExclTruthLabelID", + DoubleLabelName = "HadronConeExclExtendedTruthLabelID", + BLabelName = "ConeExclBHadronsFinal", + CLabelName = "ConeExclCHadronsFinal", + TauLabelName = "ConeExclTausFinal", + BParticleCollection = "TruthLabelBHadronsFinal", + CParticleCollection = "TruthLabelCHadronsFinal", + TauParticleCollection = "TruthLabelTausFinal", + PartPtMin = 5000., + DRMax = 0.3, + MatchMode = "MinDR" + ) + jetdrlabeler.JetPtMin = jetptmin + return jetdrlabeler + diff --git a/Reconstruction/Jet/JetCalibTools/CMakeLists.txt b/Reconstruction/Jet/JetCalibTools/CMakeLists.txt index cc91dcd05139af95363d29662553e7b32a7ad2fd..085c9517d9ccab5c27363e2d3bb752547976dda9 100644 --- a/Reconstruction/Jet/JetCalibTools/CMakeLists.txt +++ b/Reconstruction/Jet/JetCalibTools/CMakeLists.txt @@ -108,3 +108,4 @@ else() endif() +atlas_install_python_modules( python/*.py ) diff --git a/Reconstruction/Jet/JetCalibTools/python/JetCalibToolsConfig.py b/Reconstruction/Jet/JetCalibTools/python/JetCalibToolsConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..727e82cd76996a9682d7375a9bdf3bd2925af53a --- /dev/null +++ b/Reconstruction/Jet/JetCalibTools/python/JetCalibToolsConfig.py @@ -0,0 +1,166 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +######################################################################## +# # +# JetCalibConfig: A helper module for configuring jet calibration # +# The intention is to encode a limited set of configurations that # +# are sane, to ease consistency for various users. # +# This module should eventually go in JetCalibTools and be kept in # +# sync with the latest available recommendations. # +# Author: TJ Khoo # +# # +######################################################################## + +from AthenaCommon import Logging +jetcaliblog = Logging.logging.getLogger('JetCalibToolsConfig') + +from JetCalibTools import JetCalibToolsConf + +all = ['getJetCalibTool'] + +# These context definitions could be placed in another package and made +# more robust with a small python class to hold the info. +# The convention is: config file, calibarea, default calibration sequence +pflowcontexts = { + "T0":("JES_MC15cRecommendation_PFlow_Aug2016_rel21.config","00-04-77","JetArea_Residual_EtaJES"), + # Omit smearing, to avoid any efficiency loss + "AnalysisLatest":("JES_data2017_2016_2015_Consolidated_PFlow_2018_Rel21.config","00-04-82","JetArea_Residual_EtaJES_GSC"), +} + +topocontexts = { + "T0":("JES_MC15cRecommendation_May2016_rel21.config","00-04-77","JetArea_Residual_EtaJES"), + # Placeholder from a vague approximation of the 2017 setup? + "Trigger":("JES_MC15cRecommendation_May2016_Trigger.config","00-04-77","JetArea_Residual_EtaJES"), + # Omit smearing, to avoid any efficiency loss + "AnalysisLatest":("JES_data2017_2016_2015_Consolidated_EMTopo_2018_Rel21.config","00-04-82","JetArea_Residual_EtaJES_GSC"), +} + +rscanlc2 = { + "RScanLatest":("JES_MC16Recommendation_Rscan2LC_22Feb2018_rel21.config","00-04-81","JetArea_Residual_EtaJES_GSC") +} + +rscanlc6 = { + "RScanLatest":("JES_MC16Recommendation_Rscan6LC_22Feb2018_rel21.config","00-04-81","JetArea_Residual_EtaJES_GSC") +} + +fatjetcontexts = { + "CombinedMass": ("JES_MC16recommendation_FatJet_JMS_comb_19Jan2018.config","00-04-81","EtaJES_JMS"), + "CaloMass": ("JES_MC16recommendation_FatJet_JMS_calo_29Nov2017.config","00-04-81","EtaJES_JMS"), + "TAMass": ("JES_MC16recommendation_FatJet_JMS_TA_29Nov2017.config","00-04-81","EtaJES_JMS"), +} + +# List AFII config files separately, to avoid needing to specify a different context +af2configs = { + "AntiKt4EMPFlow": "JES_MC16Recommendation_AFII_PFlow_April2018_rel21.config", + "AntiKt4EMTopo": "JES_MC16Recommendation_AFII_EMTopo_April2018_rel21.config", + "AntiKt4LCTopo": "JES_MC16Recommendation_AFII_EMTopo_April2018_rel21.config", +} + +calibcontexts = { + # Standard AntiKt4 + "AntiKt4EMPFlow":pflowcontexts, + "AntiKt4EMTopo":topocontexts, + "AntiKt4LCTopo":topocontexts, + # Standard trimmed + "AntiKt10LCTopoTrimmedPtFrac5SmallR20":fatjetcontexts, + # R-Scan + "AntiKt2LCTopo":rscanlc2, + "AntiKt6LCTopo":rscanlc6, + +} + +hasInSitu = ["AntiKt4LCTopo", "AntiKt4EMTopo", "AntiKt4EMPFlow"] + +# This method extracts the relevant configuration, does some consistency checks, +# then forwards the configuration to defineJetCalibTool, returning the output. +# At present the interface allows for the calibseq to be chosen freely, other +# than checking that the data source is data for the in situ correction. +# The calibarea could be made configurable as well, but then might need to be +# added to the tool name to ensure uniqueness. +# Due to the hackiness of DualUseConfig public tool handling, we need to pass +# an AlgSequence... +def getJetCalibTool(jetcollection, context, data_type, calibseq = ""): + # In principle we could autoconfigure + if not data_type in ['data','mc','afii']: + jetcaliblog.error("JetCalibConfig accepts data_type values: 'data', 'mc', 'afii'") + raise ValueError("Unsupported data_type provided: '{0}".format(data_type)) + + if jetcollection.endswith("Jets"): + jetcaliblog.error("Jet collection '{0}'should be specified w/o 'Jets' in the name.".format(jetcollection)) + raise ValueError("Bad jet collection formatting in getJetCalibTool.") + + jetcaliblog.debug("Preparing calibration for {0}, in context {1} on sample type {2}".format(jetcollection,context,data_type)) + + jetcontexts = calibcontexts[jetcollection] + try: + configfile, calibarea, calibseq_def = jetcontexts[context] + calibseq_tmp = calibseq if calibseq else calibseq_def + if data_type == 'data' and calibseq_tmp.endswith("GSC") and jetcollection in hasInSitu: + if calibseq_tmp == calibseq_def: + calibseq_tmp += "_InSitu" + # May not be strictly necessary if already checked in JCT + elif not calibseq_tmp.endswith("InSitu"): + jetcaliblog.warning("Calibration of jets requested in data without in situ calibration.") + configfile_tmp = configfile + if data_type == "afii" and jetcollection in af2configs.keys(): + configfile_tmp = af2configs[jetcollection] + data_type_tmp = data_type + # Most likely an oversight, but R20/21 JetRecCalibrationFinder did not set the data flag + # This affects the residual correction by scaling mu. + # We should revert this later on, set up now for validation purposes + if context == "T0": + data_type_tmp = "data" + return defineJetCalibTool(jetcollection, configfile_tmp, calibarea, calibseq_tmp, data_type_tmp) + except KeyError as e: + jetcaliblog.error("Context '{0}' not found for jet collection '{1}'".format(context,jetcollection)) + jetcaliblog.error("Options are '{0}".format(','.join(jetcontexts.keys()))) + raise e + return None + +# This method actually sets up the tool +def defineJetCalibTool(jetcollection, configfile, calibarea, calibseq, data_type): + # Abbreviate the calib sequence + calibseqshort = ''.join([ step[0] for step in calibseq.split('_') ]) + toolname = "jetcalib_{0}_{1}".format(jetcollection,calibseqshort) + # + jct = JetCalibToolsConf.JetCalibrationTool(toolname, + JetCollection = jetcollection, + ConfigFile = configfile, + CalibArea = calibarea, + CalibSequence = calibseq, + IsData = (data_type == "data") + ) + return jct + +# This method extends the basic config getter to specify the requisite jet +# moments or other inputs +def getJetCalibToolPrereqs(modspec,jetdef): + calibcontext, data_type, calibseq = getCalibSpecsFromString(modspec) + if calibseq=="": + cfg, calibarea, calibseq = calibcontexts[jetdef.basename][calibcontext] + # For now, only dependent on calibseq -- can ignore InSitu, which is + # added when getting the concrete tool + prereqs = [] + prereqs.append("mod:ConstitFourMom") + if "JetArea" in calibseq: + prereqs.append("input:EventDensity") + if "GSC" in calibseq: + prereqs += ["mod:CaloEnergies", + "mod:TrackMoments", + "ghost:MuonSegment"] + jetcaliblog.debug("Prereqs for calibseq '{0}': {1}".format(calibseq,str(prereqs))) + return prereqs + +# This method translates the mod specification string into calibration specifications +def getCalibSpecsFromString(modspec): + calibseq = "" + calibspecs = modspec.split(':') + # Probably want data_type to come from elsewhere + calibcontext, data_type = calibspecs[:2] + if len(calibspecs)>2: calibseq = calibspecs[2] + return calibcontext, data_type, calibseq + +# This method instantiates the JetCalibTool given the input mod specification +def getJetCalibToolFromString(modspec,jetdef): + calibcontext, data_type, calibseq = getCalibSpecsFromString(modspec) + return getJetCalibTool(jetdef.basename,calibcontext,data_type,calibseq) diff --git a/Reconstruction/Jet/JetMomentTools/python/DefaultTools.py b/Reconstruction/Jet/JetMomentTools/python/DefaultTools.py deleted file mode 100644 index 32d39fa8370087c25193ba7030e84e004fe8eb8d..0000000000000000000000000000000000000000 --- a/Reconstruction/Jet/JetMomentTools/python/DefaultTools.py +++ /dev/null @@ -1,378 +0,0 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration - - -from JetMomentTools.JetMomentToolsConf import JetCaloQualityTool -from JetMomentTools.JetMomentToolsConf import JetWidthTool -from JetMomentTools.JetMomentToolsConf import JetCaloEnergies -from JetMomentTools.JetMomentToolsConf import JetECPSFractionTool -from JetMomentTools.JetMomentToolsConf import JetVertexFractionTool -from JetMomentTools.JetMomentToolsConf import JetVertexTaggerTool -from JetMomentTools.JetMomentToolsConf import JetTrackMomentsTool -from JetMomentTools.JetMomentToolsConf import JetTrackSumMomentsTool -from JetMomentTools.JetMomentToolsConf import JetClusterMomentsTool -from JetMomentTools.JetMomentToolsConf import JetVoronoiMomentsTool -from JetMomentTools.JetMomentToolsConf import JetIsolationTool -from JetMomentTools.JetMomentToolsConf import JetLArHVTool -from JetMomentTools.JetMomentToolsConf import JetOriginCorrectionTool -from JetMomentTools.JetMomentToolsConf import JetConstitFourMomTool - -def declareDefaultTools(): - - from JetRecConfig.JetRecFlags import jetFlags - from JetRecConfig.JetRecStandardToolManager import jtm - try: - from JetMomentTools.JetMomentToolsConf import JetCaloCellQualityTool - jtm.haveJetCaloCellQualityTool = True - except ImportError: - jtm.haveJetCaloCellQualityTool = False - - try: - from JetMomentTools.JetMomentToolsConf import JetJetBadChanCorrTool - jtm.haveJetBadChanCorrTool = True - except ImportError: - jtm.haveJetBadChanCorrTool = False - - from JetRecTools.JetRecToolsConf import TrackVertexAssociationTool - from JetRec.JetRecConf import PseudoJetGetter - from JetRecTools.JetRecToolsConf import TrackPseudoJetGetter - from InDetTrackSelectionTool.InDetTrackSelectionToolConf import InDet__InDetTrackSelectionTool - from JetRecTools.JetRecToolsConf import JetTrackSelectionTool - from JetRecTools.JetRecToolsConf import SimpleJetTrackSelectionTool - - #-------------------------------------------------------------- - # Non-substructure moment builders. - #-------------------------------------------------------------- - - # Quality from clusters. - jtm += JetCaloQualityTool( - "caloqual_cluster", - TimingCuts = [5, 10], - Calculations = ["LArQuality", "N90Constituents", "FracSamplingMax", "NegativeE", "Timing", "HECQuality", "Centroid", "AverageLArQF", "BchCorrCell"], - ) - - # Quality from cells. - if jtm.haveJetCaloCellQualityTool: - jtm += JetCaloCellQualityTool( - "caloqual_cell", - LArQualityCut = 4000, - TileQualityCut = 254, - TimingCuts = [5, 10], - Calculations = ["LArQuality", "N90Cells", "FracSamplingMax", "NegativeE", "Timing", "HECQuality", "Centroid", "AverageLArQF"] - ) - - # Jet width. - jtm += JetWidthTool("width", WeightPFOToolEM=jtm.pflowweighter, WeightPFOToolLC=jtm.pflowweighterLC) - - # Calo layer energies. - jtm += JetCaloEnergies("jetens") - - # Read in missing cell map (needed for the following) - # commented out : incompatible with trigger : ATR-9696 - ## if jtm.haveJetRecCalo: - ## def missingCellFileReader(): - ## import os - ## dataPathList = os.environ[ 'DATAPATH' ].split(os.pathsep) - ## dataPathList.insert(0, os.curdir) - ## from AthenaCommon.Utils.unixtools import FindFile - ## RefFileName = FindFile( "JetBadChanCorrTool.root" ,dataPathList, os.R_OK ) - ## from AthenaCommon.AppMgr import ServiceMgr - ## if not hasattr(ServiceMgr, 'THistSvc'): - ## from GaudiSvc.GaudiSvcConf import THistSvc - ## ServiceMgr += THistSvc() - ## ServiceMgr.THistSvc.Input += ["JetBadChanCorrTool DATAFILE=\'%s\' OPT=\'READ\'" % RefFileName] - ## missingCellFileReader.called = True - - ## missingCellFileReader() - - ## jtm += MissingCellListTool( - ## "missingcells", - ## AddCellList = [], - ## RemoveCellList = [], - ## AddBadCells = True, - ## DeltaRmax = 1.0, - ## AddCellFromTool = False, - ## LArMaskBit = 608517, - ## TileMaskBit = 1, - ## MissingCellMapName = "MissingCaloCellsMap" - ## ) - - ## # Bad channel corrections from cells - ## if jtm.haveJetBadChanCorrTool: - ## jtm += JetBadChanCorrTool( - ## "bchcorrcell", - ## NBadCellLimit = 10000, - ## StreamName = "/JetBadChanCorrTool/", - ## ProfileName = "JetBadChanCorrTool.root", - ## ProfileTag = "", - ## UseCone = True, - ## UseCalibScale = False, - ## MissingCellMap = "MissingCaloCellsMap", - ## ForceMissingCellCheck = False, - ## UseClusters = False, - ## ) - - ## # Bad channel corrections from clusters - ## jtm += JetBadChanCorrTool( - ## "bchcorrclus", - ## NBadCellLimit = 0, - ## StreamName = "", - ## ProfileName = "", - ## ProfileTag = "", - ## UseCone = True, - ## UseCalibScale = False, - ## MissingCellMap = "", - ## ForceMissingCellCheck = False, - ## UseClusters = True - ## ) - - # Bad LAr fractions. - jtm += JetECPSFractionTool( - "ecpsfrac", - ) - - #-------------------------------------------------------------- - # Track-vertex association. - #-------------------------------------------------------------- - from TrackVertexAssociationTool.TrackVertexAssociationToolConf import CP__TightTrackVertexAssociationTool - jtm += CP__TightTrackVertexAssociationTool("jetTighTVAtool", dzSinTheta_cut=3, doPV=True) - - jtm += TrackVertexAssociationTool( - "tvassoc", - TrackParticleContainer = jtm.trackContainer, - TrackVertexAssociation = "JetTrackVtxAssoc", - VertexContainer = jtm.vertexContainer, - TrackVertexAssoTool = jtm.jetTighTVAtool, - ) - - jtm += TrackVertexAssociationTool( - "tvassoc_old", - TrackParticleContainer = jtm.trackContainer, - TrackVertexAssociation = "JetTrackVtxAssoc_old", - VertexContainer = jtm.vertexContainer, - MaxTransverseDistance = 1.5, - MaxLongitudinalDistance = 1.0e7, - MaxZ0SinTheta = 1.5 - ) - - #-------------------------------------------------------------- - # Track selection. - #-------------------------------------------------------------- - - # This is the InDet loose selection from - # https://twiki.cern.ch/twiki/bin/view/AtlasProtected/InDetTrackingPerformanceGuidelines - # October 28, 2014 - #jtm += InDet__InDetDetailedTrackSelectionTool( - jtm += InDet__InDetTrackSelectionTool( - "trk_trackselloose", - CutLevel = "Loose" - ) - - jtm += JetTrackSelectionTool( - "trackselloose", - InputContainer = jtm.trackContainer, - OutputContainer = "JetSelectedTracks", - Selector = jtm.trk_trackselloose - ) - - jtm += InDet__InDetTrackSelectionTool( - "trk_trackselloose_trackjets", - CutLevel = "Loose" - ) - - jtm += JetTrackSelectionTool( - "trackselloose_trackjets", - InputContainer = jtm.trackContainer, - OutputContainer = "JetSelectedTracks_LooseTrackJets", - Selector = jtm.trk_trackselloose_trackjets - ) - - if jetFlags.useInDetTrackSelection(): - jtm += JetTrackSelectionTool( - "tracksel", - InputContainer = jtm.trackContainer, - OutputContainer = "JetSelectedTracks", - Selector = jtm.trk_trackselloose - ) - else: - jtm += SimpleJetTrackSelectionTool( - "tracksel", - PtMin = 500.0, - InputContainer = jtm.trackContainer, - OutputContainer = "JetSelectedTracks", - ) - - - # Tracks. - jtm += TrackPseudoJetGetter( - "trackget", - InputContainer = jtm.trackselloose_trackjets.OutputContainer, - Label = "Track", - OutputContainer = "PseudoJetTracks", - TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation, - SkipNegativeEnergy = True, - GhostScale = 0.0 - ) - - - # Ghost tracks. - jtm += TrackPseudoJetGetter( - "gtrackget", - InputContainer = jtm.tracksel.OutputContainer, - Label = "GhostTrack", - OutputContainer = "PseudoJetGhostTracks", - TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation, - SkipNegativeEnergy = True, - GhostScale = 1e-20 - ) - - - # Jet vertex fraction. - jtm += JetVertexFractionTool( - "jvfold", - VertexContainer = jtm.vertexContainer, - AssociatedTracks = "GhostTrack", - TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation, - JVFName = "JVFOld" - ) - - # Jet vertex fraction with selection. - jtm += JetVertexFractionTool( - "jvf", - VertexContainer = jtm.vertexContainer, - AssociatedTracks = "GhostTrack", - TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation, - TrackSelector = jtm.trackselloose, - JVFName = "JVF" - ) - - # Jet vertex tagger. - jtm += JetVertexTaggerTool( - "jvt", - VertexContainer = jtm.vertexContainer, - TrackParticleContainer = jtm.trackContainer, - AssociatedTracks = "GhostTrack", - TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation, - TrackSelector = jtm.trackselloose, - JVTName = "Jvt", - K_JVFCorrScale = 0.01, - Z0Cut = 3.0, - PUTrkPtCut = 30000.0 - ) - - # Jet track info. - jtm += JetTrackMomentsTool( - "trkmoms", - VertexContainer = jtm.vertexContainer, - AssociatedTracks = "GhostTrack", - TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation, - TrackMinPtCuts = [500, 1000], - TrackSelector = jtm.trackselloose - ) - - # Jet track vector sum info - jtm += JetTrackSumMomentsTool( - "trksummoms", - VertexContainer = jtm.vertexContainer, - AssociatedTracks = "GhostTrack", - TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation, - RequireTrackPV = True, - TrackSelector = jtm.trackselloose - ) - - # Jet cluster info. - jtm += JetClusterMomentsTool( - "clsmoms", - DoClsPt = True, - DoClsSecondLambda = True, - DoClsCenterLambda = True, - DoClsSecondR = True - ) - - - jtm += JetVoronoiMomentsTool( - "voromoms", - AreaXmin= -5., - AreaXmax= 5., - AreaYmin= -3.141592, - AreaYmax= 3.141592 - ) - - # Isolations. - # Note absence of PseudoJetGetter property means the jet inputs - # are obtained according to the InputType property of the jet. - jtm += JetIsolationTool( - "jetisol", - IsolationCalculations = ["IsoDelta:2:SumPt", "IsoDelta:3:SumPt"], - ) - jtm += JetIsolationTool( - "run1jetisol", - IsolationCalculations = ["IsoKR:11:Perp", "IsoKR:11:Par", "IsoFixedCone:6:SumPt",], - ) - - - # Bad LAr fractions. - jtm += JetLArHVTool("larhvcorr") - - - # Jet origin correction. - jtm += JetOriginCorrectionTool( - "jetorigincorr", - VertexContainer = jtm.vertexContainer, - OriginCorrectedName = "JetOriginConstitScaleMomentum" - ) - - # Just set the PV without applying origin correction - jtm += JetOriginCorrectionTool( - "jetorigin_setpv", - VertexContainer = jtm.vertexContainer, - OriginCorrectedName = "", - OnlyAssignPV = True, - ) - - -### Not ideal, but because CaloCluster.Scale is an internal class -### it makes the dict load really slow. -### So just copy the enum to a dict... -### Defined in Event/xAOD/xAODCaloEvent/versions/CaloCluster_v1.h -CaloClusterStates = { - "UNKNOWN" : -1, - "UNCALIBRATED" : 0, - "CALIBRATED" : 1, - "ALTCALIBRATED" : 2, - "NSTATES" : 3 - } - -### Workaround for inability of Gaudi to parse single-element tuple -import GaudiPython.Bindings as GPB -_old_setattr = GPB.iProperty.__setattr__ -def _new_setattr(self, name, value): - if type(value) == tuple: - value = list(value) - return _old_setattr(self, name, value) -GPB.iProperty.__setattr__ = _new_setattr -### - -jtm += JetConstitFourMomTool( - "constitfourmom_lctopo", - JetScaleNames = ["DetectorEtaPhi"], - AltConstitColls = ["CaloCalTopoClusters"], - AltConstitScales = [CaloClusterStates["CALIBRATED"]], - AltJetScales = [""] - ) - -jtm += JetConstitFourMomTool( - "constitfourmom_emtopo", - JetScaleNames = ["DetectorEtaPhi","JetLCScaleMomentum"], - AltConstitColls = ["CaloCalTopoClusters","LCOriginTopoClusters" if jetFlags.useTracks() else "CaloCalTopoClusters"], - AltConstitScales = [CaloClusterStates["UNCALIBRATED"],CaloClusterStates["CALIBRATED"]], - AltJetScales = ["",""] - ) - -jtm += JetConstitFourMomTool( - "constitfourmom_pflow", - JetScaleNames = ["DetectorEtaPhi"], - AltConstitColls = [""], - AltConstitScales = [0], - AltJetScales = ["JetConstitScaleMomentum"] - ) - diff --git a/Reconstruction/Jet/JetMomentTools/python/JetMomentToolsConfig.py b/Reconstruction/Jet/JetMomentTools/python/JetMomentToolsConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..a30b13be9b97ed3c18358767b2a6f0b268aef519 --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/python/JetMomentToolsConfig.py @@ -0,0 +1,121 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +######################################################################## +# # +# JetMomentToolsConfig: A helper module for configuring jet moment # +# tools, in support of JetRecConfig.JetModConfig. # +# Author: TJ Khoo # +# # +######################################################################## + +from AthenaCommon import Logging +jetmomentlog = Logging.logging.getLogger('JetMomentToolsConfig') + +from JetRecTools import JetRecToolsConfig +from JetMomentTools import JetMomentToolsConf + +def getCaloQualityTool(): + caloqual = JetMomentToolsConf.JetCaloQualityTool( + "caloqual", + TimingCuts = [5, 10], + Calculations = ["LArQuality", "N90Constituents", "FracSamplingMax", "NegativeE", "Timing", "HECQuality", "Centroid", "AverageLArQF", "BchCorrCell"], + ) + return caloqual + +def getConstitFourMomTool(jetdef): + # All this code needs to live in a JetMomentTools module + + ### Not ideal, but because CaloCluster.Scale is an internal class + ### it makes the dict load really slow. + ### So just copy the enum to a dict... + ### Defined in Event/xAOD/xAODCaloEvent/versions/CaloCluster_v1.h + CaloClusterStates = { + "UNKNOWN" : -1, + "UNCALIBRATED" : 0, + "CALIBRATED" : 1, + "ALTCALIBRATED" : 2, + "NSTATES" : 3 + } + + ### Workaround for inability of Gaudi to parse single-element tuple + try: + import GaudiPython.Bindings as GPB + _old_setattr = GPB.iProperty.__setattr__ + def _new_setattr(self, name, value): + if type(value) == tuple: + value = list(value) + return _old_setattr(self, name, value) + GPB.iProperty.__setattr__ = _new_setattr + except: + pass + ### + cfourmom = JetMomentToolsConf.JetConstitFourMomTool("constitfourmom_{0}".format(jetdef.basename)) + if "LCTopo" in jetdef.basename: + cfourmom.JetScaleNames = ["DetectorEtaPhi"] + cfourmom.AltConstitColls = ["CaloCalTopoClusters"] + cfourmom.AltConstitScales = [CaloClusterStates["CALIBRATED"]] + cfourmom.AltJetScales = [""] + elif "EMTopo" in jetdef.basename: + cfourmom.JetScaleNames = ["DetectorEtaPhi","JetLCScaleMomentum"] + cfourmom.AltConstitColls = ["CaloCalTopoClusters","LCOriginTopoClusters" if "Origin" in jetdef.inputdef.modifiers else "CaloCalTopoClusters"] + cfourmom.AltConstitScales = [CaloClusterStates["UNCALIBRATED"],CaloClusterStates["CALIBRATED"]] + cfourmom.AltJetScales = ["",""] + elif "EMPFlow" in jetdef.basename: + cfourmom.JetScaleNames = ["DetectorEtaPhi"] + cfourmom.AltConstitColls = [""] + cfourmom.AltConstitScales = [0] + cfourmom.AltJetScales = ["JetConstitScaleMomentum"] + + return cfourmom + +# Jet vertex fraction with selection. +def getJVFTool(): + jettrackselloose = JetRecToolsConfig.getTrackSelTool() + + jvf = JetMomentToolsConf.JetVertexFractionTool( + "jvf", + VertexContainer = "PrimaryVertices", + AssociatedTracks = "GhostTrack", + TrackVertexAssociation = "JetTrackVtxAssoc", + TrackParticleContainer = "JetSelectedTracks", + TrackSelector = jettrackselloose, + ) + return jvf + + +def getTrackMomentsTool(): + jettrackselloose = JetRecToolsConfig.getTrackSelTool() + + trackmoments = JetMomentToolsConf.JetTrackMomentsTool( + "trkmoms", + VertexContainer = "PrimaryVertices", + AssociatedTracks = "GhostTrack", + TrackVertexAssociation = "JetTrackVtxAssoc", + TrackMinPtCuts = [500, 1000], + TrackSelector = jettrackselloose + ) + return trackmoments + +def getTrackSumMomentsTool(): + jettrackselloose = JetRecToolsConfig.getTrackSelTool() + + tracksummoments = JetMomentToolsConf.JetTrackSumMomentsTool( + "trksummoms", + VertexContainer = "PrimaryVertices", + AssociatedTracks = "GhostTrack", + TrackVertexAssociation = "JetTrackVtxAssoc", + RequireTrackPV = True, + TrackSelector = jettrackselloose + ) + return tracksummoments + +# This tool sets a decoration saying which the nominal HS PV was. +# Historically it did the origin correction, but now we do this to constituents +def getOriginCorrVxTool(): + origin_setpv = JetMomentToolsConf.JetOriginCorrectionTool( + "jetorigin_setpv", + VertexContainer = "PrimaryVertices", + OriginCorrectedName = "", + OnlyAssignPV = True, + ) + return origin_setpv diff --git a/Reconstruction/Jet/JetRec/python/DefaultTools.py b/Reconstruction/Jet/JetRec/python/DefaultTools.py deleted file mode 100644 index b66bd49c020a2ba0b664bdaaec0809a0e1cdbeb6..0000000000000000000000000000000000000000 --- a/Reconstruction/Jet/JetRec/python/DefaultTools.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration - - -from JetRecConf import JetPseudojetRetriever -from JetRecConf import JetConstituentsRetriever -from JetRecConf import JetRecTool -from JetRecConf import PseudoJetGetter -from JetRecConf import MuonSegmentPseudoJetGetter -from JetRecConf import JetFromPseudojet -from JetRecConf import JetConstitRemover -from JetRecConf import JetSorter - -def declareDefaultTools(): - from JetRecConfig.JetRecFlags import jetFlags - from JetRecConfig.JetRecStandardToolManager import jtm - - ghostScaleFactor = 1e-40 - - #-------------------------------------------------------------- - # Jet reco infrastructure. - #-------------------------------------------------------------- - - # Jet pseudojet retriever. - jtm += JetPseudojetRetriever("jpjretriever") - - # Jet constituent retriever. - labs = [] - if jetFlags.useTracks(): - labs += ["Track"] - labs += ["AntiKt2TrackJet", "AntiKt2TrackJet"] - if jetFlags.useMuonSegments(): - labs += ["MuonSegment",] - if jetFlags.useTruth(): - labs += ["Truth"] - for lab in jetFlags.truthFlavorTags(): - labs += [lab] - jtm += JetConstituentsRetriever( - "jconretriever", - UsePseudojet = True, - UseJetConstituents = True, - PseudojetRetriever = jtm.jpjretriever, - GhostLabels = labs, - GhostScale = ghostScaleFactor - ) - - #-------------------------------------------------------------- - # Pseudojet builders. - #-------------------------------------------------------------- - - # Clusters. - jtm += PseudoJetGetter( - "lcget", - InputContainer = "CaloCalTopoClusters", - Label = "LCTopo", - OutputContainer = "PseudoJetLCTopo", - SkipNegativeEnergy = True, - GhostScale = 0.0 - ) - - # EM clusters. - jtm += PseudoJetGetter( - "emget", - InputContainer = "CaloCalTopoClusters", - Label = "EMTopo", - OutputContainer = "PseudoJetEMTopo", - SkipNegativeEnergy = True, - GhostScale = 0.0 - ) - - - # Muon segments - jtm += MuonSegmentPseudoJetGetter( - "gmusegget", - InputContainer = "MuonSegments", - Label = "GhostMuonSegment", - OutputContainer = "PseudoJetGhostMuonSegment", - Pt = 1.e-20 - ) - - # AntiKt2 track jets. - jtm += PseudoJetGetter( - "gakt2trackget", # give a unique name - InputContainer = jetFlags.containerNamePrefix() + "AntiKt2PV0TrackJets", # SG key - Label = "GhostAntiKt2TrackJet", # this is the name you'll use to retrieve associated ghosts - OutputContainer = "PseudoJetGhostAntiKt2TrackJet", - SkipNegativeEnergy = True, - GhostScale = ghostScaleFactor, # This makes the PseudoJet Ghosts, and thus the reco flow will treat them as so. - ) - -# # AntiKt3 track jets. -# jtm += PseudoJetGetter( -# "gakt3trackget", # give a unique name -# InputContainer = jetFlags.containerNamePrefix() + "AntiKt3PV0TrackJets", # SG key -# Label = "GhostAntiKt3TrackJet", # this is the name you'll use to retrieve associated ghosts -# OutputContainer = "PseudoJetGhostAntiKt3TrackJet", -# SkipNegativeEnergy = True, -# GhostScale = ghostScaleFactor, # This makes the PseudoJet Ghosts, and thus the reco flow will treat them as so. -# ) - - # AntiKt4 track jets. - jtm += PseudoJetGetter( - "gakt4trackget", # give a unique name - InputContainer = jetFlags.containerNamePrefix() + "AntiKt4PV0TrackJets", # SG key - Label = "GhostAntiKt4TrackJet", # this is the name you'll use to retrieve associated ghosts - OutputContainer = "PseudoJetGhostAntiKt4TrackJet", - SkipNegativeEnergy = True, - GhostScale = ghostScaleFactor, # This makes the PseudoJet Ghosts, and thus the reco flow will treat them as so. - ) - - #-------------------------------------------------------------- - # Jet builder. - # The tool manager must have one jet builder. - #-------------------------------------------------------------- - - jtm.addJetBuilderWithArea(JetFromPseudojet( - "jblda", - Attributes = ["ActiveArea", "ActiveArea4vec"] - )) - - jtm.addJetBuilderWithoutArea(JetFromPseudojet( - "jbldna", - Attributes = [] - )) - - # Number of associated muon segments. - #jtm += JetMuonSegmentMomentsTool("muonsegs") - - # Remove constituents (useful for truth jets in evgen pile-up file) - jtm += JetConstitRemover("removeconstit") - - # Sort jets by pT - # May be deisred after calibration or grooming. - jtm += JetSorter("jetsorter") diff --git a/Reconstruction/Jet/JetRec/python/JetRecStandard.py b/Reconstruction/Jet/JetRec/python/JetRecStandard.py index a39a0e09747706da835e882ac0db11fe29cc8192..d5c93c1caa6633b3165d96edc23326fddc9ac0ac 100644 --- a/Reconstruction/Jet/JetRec/python/JetRecStandard.py +++ b/Reconstruction/Jet/JetRec/python/JetRecStandard.py @@ -116,6 +116,6 @@ if jetFlags.eventShapeTools() == None: # Import the jet tool manager. from JetRec.JetRecStandardToolManager import jtm # Import the constituent tool manager -from JetRecTools.JetRecToolsConfig import ctm +from JetRecTools.ConstitToolManager import ctm jetlog.info( myname + "End." ) diff --git a/Reconstruction/Jet/JetRec/python/JetRecStandardTools.py b/Reconstruction/Jet/JetRec/python/JetRecStandardTools.py index e3c1b11dae8fd0485cd6dd416a49a94d469cb37f..d2b0bc2915d1be5dd4a40fb65408e3f306f8cd1e 100644 --- a/Reconstruction/Jet/JetRec/python/JetRecStandardTools.py +++ b/Reconstruction/Jet/JetRec/python/JetRecStandardTools.py @@ -240,7 +240,7 @@ jtm += JetConstituentsRetriever( #-------------------------------------------------------------- # Prepare a sequence of input constituent modifiers -from JetRecTools.JetRecToolsConfig import ctm +from JetRecTools.ConstitToolManager import ctm jtm += ctm.buildConstitModifSequence( "JetConstitSeq_LCOrigin", OutputContainer='LCOriginTopoClusters', InputContainer= 'CaloCalTopoClusters', diff --git a/Reconstruction/Jet/JetRecConfig/CMakeLists.txt b/Reconstruction/Jet/JetRecConfig/CMakeLists.txt index 18ea0632da48d38e9122f7c94643599a28416584..b76e3c087ec8e2b5849f4f8afd5ba4fef410d018 100644 --- a/Reconstruction/Jet/JetRecConfig/CMakeLists.txt +++ b/Reconstruction/Jet/JetRecConfig/CMakeLists.txt @@ -1,3 +1,4 @@ +# $Id: CMakeLists.txt 801725 2017-03-28 19:23:28Z khoo $ ################################################################################ # Package: JetRecConfig ################################################################################ @@ -5,12 +6,6 @@ # Declare the package name: atlas_subdir( JetRecConfig ) -# Declare the package's dependencies: -atlas_depends_on_subdirs( PUBLIC - GaudiKernel ) - # Install files from the package: atlas_install_python_modules( python/*.py ) atlas_install_joboptions( share/*.py ) -atlas_install_joboptions( share/JetRec_jobOptions.py ) - diff --git a/Reconstruction/Jet/JetRecConfig/README.md b/Reconstruction/Jet/JetRecConfig/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d2a01ffe30ce4625c159e4efbbee2d2507afd255 --- /dev/null +++ b/Reconstruction/Jet/JetRecConfig/README.md @@ -0,0 +1,143 @@ +# JetRecConfig: Smart jet reconstruction configuration + +## Introduction + +This package is an attempt to build up jet configuration hierarchically through +modular configuration helpers that stay local to the source packages. + +## Usage + +Before reading further, it may be useful to also refer to the Run 3 configuration +documentation: +https://twiki.cern.ch/twiki/bin/viewauth/AtlasComputing/AthenaJobConfigRun3 + +The backbone of this configuration framework is a set of classes that encode +what is meaningful in a jet definition or jet constituent, such that helper +code can interpret the definitions to generate all necessary tools/algs. +These are defined in `JetDefinition.py`, and currently comprise: +* `JetConstit`: A set of constituents used for jet finding, which may have + constituent modifiers applied. +* `JetDefinition`: A jet configuration, fundamentally the clustering algorithm, + radius, and input constituent type. Can be extended with lists of jet + modifiers. Jet grooming is still to be added (might be a derived class?) +* `JetGhost`: A set of objects to be ghost-associated to the jets. Very + simplistic class at present. +* `JetModifier`: A configuration of a tool that adds jet moments or otherwise + manipulates the jet collection. + +Once the constituent and definition have been defined, these are passed to +the `JetRecConfig.JetRecCfg` function, which builds up all needed +tools and algorithms sequentially, including any of their prerequisites, +such that one is guaranteed a working reconstruction sequence. These are +placed in a ComponentAccumulator, that can be merged with the main +Athena job and potentially with other jet reconstruction sequences. + +As an intermediate step, the dictionary of dependencies for the jet reco job +can be extracted without attempting to configure any Athena tools/algs. This +is done by passing the jet definition to `JetRecConfig.resolveDependencies`, +allowing quick checking of the elements that will be integrated to form the +jet collection, including input collections, ghosts and modifiers. + +If working with standard objects, the user can to do something like +``` +from StandardJetDefs import AntiKt4LCTopo +lcjetcfg = JetRecConfig.JetRecCfg(jetseq,AntiKt4LCTopo) +``` +For minor variations, one can copy and modify the standard definitions: +``` +from StandardJetDefs import LCTopoOrigin, AntiKt4LCTopo +from copy import deepcopy +LCTopoCSSK = deepcopy(LCTopoOrigin) +LCTopoCSSK.modifiers += ["CS","SK"] +AntiKt4LCTopoCSSK = deepcopy(AntiKt4LCTopo) +AntiKt4LCTopoCSSK.inputdef = LCTopoCSSK +lccsskjetcfg = JetRecConfig.JetRecCfg(jetseq,AntiKt4LCTopoCSSK) +``` +The definitions can of course be built up from scratch by users who want full +control. + +At this time, the only use of configuration flags is to peek in the input +file (the first one) to determine if certain prerequisite collections are +present and therefore need not be built. +See: +https://indico.cern.ch/event/697121/contributions/2859415/attachments/1585431/2506572/JobConfig_SoftCoord_Jan18.pdf + +### Note on JetModifier configuration + +To provide a large variety of modifier tool configurations in an organised way, +each modifier tool is configured via the `JetModifier` helper class. This in +turn delegates setup of the configuration to a helper function that specifies +non-default tool properties, and may take into account the details of the jets. +Every modifier keeps track of its prerequisites, which may be other modifiers, +jet input objects (e.g. tracks) or ghosts (e.g. GhostTracks). + +The simplest possible `JetModifier` is one that only needs to produce a default +tool, e.g. +``` +jetsort = JetModifier("JetSorter","jetsort") +``` +Another modifier may not need any special configuration, but does require that +some other mods be run first: +``` +jvt = JetModifier("JetVertexTaggerTool", "jvt", + prereqs = [ "mod:JVF" ]) +``` +Finally, a helper function might be defined to set up the tool correctly, +possibly with input from a string encoding of the modifier setup: +``` +def getJetFilterTool(modspec): + from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator + ca = ComponentAccumulator() + threshold = int(modspec) + jetptfilter = JetRecConf.JetFilterTool("jetptfilter_{0}mev".format(threshold)) + jetptfilter.PtMin = threshold + ca.addPublicTool( jetptfilter ) + return jetptfilter, ca + +"Filter": JetModifier("JetFilterTool","jetptfilter",helperfn=getJetFilterTool), +``` +A helper function can potentially be provided for the prereqs as well. + +This permits us to build up a dictionary of modifier configurations, keyed by +strings, so a user can simply set a list of strings describing how they want +to apply the modifiers, e.g. +``` +AntiKt4LCTopo.modifiers = ["Calib:AnalysisLatest:mc","Sort","JVT"] +``` +which will first ensure that all tools are called that are needed for +calibration, then sort the collection (a filter is also applied, controlled +by other options), and finally compute JVT, again adding all modifiers required +by JVT. In the process, jet track selection and ghost association will be +added to the job. + +The set of standard modifiers (for offline reconstruction) is concentrated +in JetRecConfig/python/StandardJetMods.py, which in turn accesses tool +configuration helpers that are defined in the packages containing the tool +C++ implementations. This allows a local lookup of the specific default +configurations, while making it easy to determine where the source code +for those tools live. + +### Instructions + +To run: +``` +cd $MYWORKDIR +mkdir run +cd run +python JetRecTestCfg.py -H # Get instructions +``` +You can dump printouts of the dependency dict and/or component accumulators +for each jet collection or run a full job in serial or multithreaded modes. + +# TODO + +* Set up configuration helpers for: + * Jet substructure moment tools +* Develop a generic configuration helper for grooming jets + * This should support both finding+grooming and standalone grooming based + on the input collection being pre-made. + * Some autoconfiguration could be useful here? However, missing data + dependencies should be covered by the AthenaMT scheduler. +* Some steering flags will eventually be needed to cope with different + situations. However, hopefully they can mostly just modify the top-level + configurations, without needing anything propagated into the helpers. diff --git a/Reconstruction/Jet/JetRecConfig/python/ConstModHelpers.py b/Reconstruction/Jet/JetRecConfig/python/ConstModHelpers.py new file mode 100644 index 0000000000000000000000000000000000000000..7bd9971894f554e65586f037b62d5671eed95ab9 --- /dev/null +++ b/Reconstruction/Jet/JetRecConfig/python/ConstModHelpers.py @@ -0,0 +1,102 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration + +######################################################################## +# # +# ConstModUtils: A module for configuring constituent modifiers # +# Author: TJ Khoo # +# # +######################################################################## + +from ROOT import xAOD +xAOD.Type.ObjectType + +from AthenaCommon import Logging +constmodlog = Logging.logging.getLogger('ConstModHelpers') + +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator + +from JetRec import JetRecConf +from JetRecTools import JetRecToolsConf +from PFlowUtils import PFlowUtilsConf + +# Tool types and configs can be expanded if the user +# wishes to add their own custom definitions + +# Maybe we need a config class in JetDefinition? +ConstModTools = { + "Origin": JetRecToolsConf.CaloClusterConstituentsOrigin, + "EM": JetRecToolsConf.ClusterAtEMScaleTool, + "Vor": JetRecToolsConf.VoronoiWeightTool, + "CS": JetRecToolsConf.ConstituentSubtractorTool, + "SK": JetRecToolsConf.SoftKillerWeightTool +} + +ConstModConfigs = { + "Origin": {}, + "EM": {}, + "Vor": {"doSpread":False, "nSigma":0}, + "CS": {"MaxEta":5.}, + "SK": {} +} + +def ConstitModCfg(inputtype,sequence,suffix=""): + components = ComponentAccumulator() + + # May wish to pass an empty sequence for regular PFlow + modlist = [] + if inputtype == xAOD.Type.ParticleFlow: + weightPFO = PFlowUtilsConf.CP__WeightPFOTool("weightPFO") + correctPFO = JetRecToolsConf.CorrectPFOTool("correctPFO", + InputType = inputtype, + WeightPFOTool = weightPFO + ) + modlist.append(correctPFO) + inputname = {xAOD.Type.CaloCluster: "TopoCluster", + xAOD.Type.ParticleFlow: "EMPFlow" + }[inputtype] + + for step in sequence: + if step == "LC": + continue # Nothing to do for LC clusters + tool = None + + toolname = "ConstitMod{0}_{1}{2}".format(inputname,step,suffix) + tool = ConstModTools[step](toolname,**ConstModConfigs[step]) + if inputtype == xAOD.Type.ParticleFlow: + tool.IgnoreChargedPFO=True + tool.ApplyToChargedPFO=False + tool.InputType = inputtype + modlist.append(tool) + + sequenceshort = "".join(sequence) + seqname = "ConstitMod{0}_{1}{2}".format(sequenceshort,inputname,suffix) + inputcontainer = "" + outputcontainer = "" + if inputtype==xAOD.Type.ParticleFlow: + inputcontainer = "JetETMiss" + outputcontainer = sequenceshort if sequenceshort else "CHS" + chstool = JetRecToolsConf.ChargedHadronSubtractionTool("chsPFO") + chstool.InputType = inputtype + modlist.append(chstool) + elif inputtype==xAOD.Type.CaloCluster: + inputcontainer = "CaloCalTopoClusters" + outputcontainer = sequenceshort+"TopoClusters" + else: + constmodlog.error("Only ParticleFlow and CaloCluster currently supported!") + raise TypeError("Unsupported input type {0}".format(inputtype)) + + # If no mods are needed, don't give back a tool + if not modlist: return components + + modseq = JetRecToolsConf.JetConstituentModSequence(seqname, + InputType=inputtype, + OutputContainer = outputcontainer, + InputContainer= inputcontainer, + Modifiers = [ mod for mod in modlist] + ) + + constitmodalg = JetRecConf.JetAlgorithm("jetalg_{0}".format(modseq.getName())) + constitmodalg.Tools = [modseq] + components.addEventAlgo( constitmodalg ) + + return components diff --git a/Reconstruction/Jet/JetRecConfig/python/FastJetInterfaceConfig.py b/Reconstruction/Jet/JetRecConfig/python/FastJetInterfaceConfig.py deleted file mode 100644 index d9641147035eca31a06e7ddc30c70eb43925bc47..0000000000000000000000000000000000000000 --- a/Reconstruction/Jet/JetRecConfig/python/FastJetInterfaceConfig.py +++ /dev/null @@ -1,174 +0,0 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration - - -from AthenaCommon.SystemOfUnits import * -from AthenaCommon.Logging import logging - -from JetRec.JetRecConf import FastJetInterfaceTool - -_fastjetLog = logging.getLogger("FastJetInterfaceConfiguration") - -# set up some enumerator values -def enums(name='Enum',**enums): - return type( name, (), enums) - -# recognized keys -fastjet_conf_tags = enums('FastJetConfTags', - Strategy=[ 'default', 'Best', - 'N2MinHeapTiled','N2Tiled', 'N2PoorTiled', 'N2Plain', - 'N3Dumb', - 'NlnN', 'NlnN3pi', 'NlnN4pi', 'NlnNCam4pi', 'NlnNCam2pi2R', 'NlNCam', - 'plugin_strategy' ], - RecombScheme = [ 'default', 'E', 'pt', 'pt2', 'Et', 'Et2', 'BIpt', 'BIpt2' ], - Algorithm = [ 'default', 'kt', 'Kt', 'anti-kt', 'AntiKt', 'cambridge', 'CamKt', - 'genkt', 'passive cambridge', 'passive genkt', - 'CMSCone', 'SISCone'], - JetAreaMethod = [ 'default', 'VoronoiArea', 'ActiveArea', - 'ActiveAreaExplicitGhost', 'PassiveArea', '1GhostPassiveArea' ], - SISSplitMergeScale = [ 'default', 'pttilde', 'PtTilde', 'Pt', 'Et', 'mt' ], - ) - -# Ghosted area parameters -fastjet_gas = enums('FastJetGhostAreaSettings', - def_ghost_maxrap = 6.0, #fastjet::gas::def_ghost_maxrap - def_repeat = 1, #fastjet::gas::def_repeat - def_ghost_area = 0.01, #fastjet::gas::def_ghost_area - def_grid_scatter = 1.0, #fastjet::gas::def_grid_scatter - def_kt_scatter = 0.1, #fastjet::gas::def_kt_scatter - def_mean_ghost_kt = 1e-100,#fastjet::gas::def_mean_ghost_kt - ) - -# ignored keys -config_ignored_keys = enums('SetupIgnoredKeys', - ControlKeys = ["_alreadyChecked_","_locked_","_ignoreUnknown_" ]) - -# Default FastJet configuration dictionary: -# -# Most keys are the same as the corresponding FastJet tags or enumerator names. -# In addition, for backward compatibility, the following tags are recognized: -# -# -defFastJetInterfaceConfigDict = { - # -- overall setup and process control - 'Algorithm' : "anti-kt", - 'JetAreaMethod' : "VoronoiArea", - 'CalculateJetArea' : False, - # -- kt-style parameters - 'Strategy' : "Best", - 'RecombScheme' : "E", - # -- CMS cone parameters - 'CMS_SeedThreshold' : 15.*GeV, - # -- SIS cone parameters - 'SIS_OverlapThreshold' : 0.75, - 'SIS_NumPassMax' : 0, - 'SIS_ProtojetPtMin' : 0.0, - 'SIS_DoCaching' : False, - 'SIS_SplitMergeScale' : 'PtTilde', - 'SIS_SplitMergeStopScale' : 0.0, - # -- jet algorithm parameters - 'Radius' : 0.4, # ATLAS default - 'Inclusive' : True, # ATLAS default - 'InclusivePtMin' : 0.*GeV, - 'ExclusiveDcut' : 0.5, - 'ExclusiveNjets' : 3, - # -- jet area calculation directives and parameters - 'VoronoiEffectiveRfact' : 1.0, # Voronoi - 'GhostMaxRapidity' : fastjet_gas.def_ghost_maxrap, - 'GhostMinRapidity' : -fastjet_gas.def_ghost_maxrap, - 'GhostRepeats' : fastjet_gas.def_repeat, - 'GhostAreaSize' : fastjet_gas.def_ghost_area, - 'GhostGridScatter' : fastjet_gas.def_grid_scatter, - 'GhostKtScatter' : fastjet_gas.def_kt_scatter, - 'GhostMeanKt' : fastjet_gas.def_mean_ghost_kt - } - -# Check whole dictionary or key/value assigments and return dictionary with -# invalid options stripped (if allowed) or exception thrown for invalid options -def checkAndUpdate(**options): - # already checked - if options.get("_alreadyChecked_",False) or options.get("_locked_",False): - return options - - # check what to do with unknowns - ignoreUnknown = options.pop("_ignoreUnknown_",False) - - # check every entry - for k in options.keys(): - if k not in defFastJetInterfaceConfigDict : - if ignoreUnknown : - _fastjetLog.warning("Option %s unknown - ignoring it!"%(k)) - options.pop(k) - else : - _fastjetLog.error("Option %s unknown - abort configuration!"%(k)) - raise Exception - - checkedOptions = dict(defFastJetInterfaceConfigDict) - for k,v in defFastJetInterfaceConfigDict.iteritems(): - t = type(v) - if t in ( list, set, dict ) : - checkedOptions[k] = t(v) - - checkedOptions['_alreadyChecked_'] = True - checkedOptions.update(options) - - # check settings for Strategy - key = "Strategy" - # print checkedOptions - tag = checkedOptions[key] - _fastjetLog.info("Test option %s",key) - if checkedOptions[key] not in fastjet_conf_tags.Strategy : - _fastjetLog.error("Strategy \042%s\042 not recognized - fatal! Allowed values are: ",checkedOptions['Strategy']) - for s in fastjet_conf_tags.Strategy : - _fastjetLog.error("\042%s\042",s) - raise Exception - - # check settings for RecombScheme - if checkedOptions['RecombScheme'] not in fastjet_conf_tags.RecombScheme : - _fastjetLog.error("RecombScheme \042%s\042 not recognized - fatal! Allowed values are: ",checkedOptions['RecombScheme']) - for s in fastjet_conf_tags.RecombScheme : - _fastjetLog.error("\042%s\042",s) - raise Exception - - # check settings for Algorithm - if checkedOptions['Algorithm'] not in fastjet_conf_tags.Algorithm : - _fastjetLog.error("Algorithm \042%s\042 not recognized - fatal! Allowed values are: ",checkedOptions['Algorithm']) - for s in fastjet_conf_tags.Algorithm : - _fastjetLog.error("\042%%s\042",s) - raise Exception - - # check settings for JetAreaMethod - if checkedOptions['JetAreaMethod'] not in fastjet_conf_tags.JetAreaMethod : - _fastjetLog.error("JetAreaMethod \042%s\042 not recognized - fatal! Allowed values are: ",checkedOptions['JetAreaMethod']) - for s in fastjet_conf_tags.JetAreaMethod : - _fastjetLog.error("\042%s\042",s) - raise Exception - - # check settings for SIS split merge scale - if checkedOptions['SIS_SplitMergeScale'] not in fastjet_conf_tags.SISSplitMergeScale : - _fastjetLog.error("SIS_SplitMergeScale \042%2\042 not recognized - fatal! Allowed values are: ",checkedOptions['SIS_SplitMergeScale']) - for s in fastjet_conf_tags.SISSplitMergeScale : - _fastjetLog.error("\042%s\042",s) - raise Exception - - return checkedOptions - - -def getFastJetInterfaceConfig(name,**options): - # get tool configuration - fjTool = FastJetInterfaceTool(name) - from AthenaCommon.AppMgr import ToolSvc - ToolSvc += fjTool - # check job options - options = checkAndUpdate(**options) - # set tool properties - for k,v in options.iteritems(): - if k not in config_ignored_keys.ControlKeys : - setattr(fjTool,k,v) - # return tool configuration object - return fjTool - -#def dumpFastJetInterfaceConfig(**options=**defFastJetInterfaceConfigDict): -# # write out all attributes -# for k,v in options.iteritems(): -# _fastjetLog.message("Config::%s value %s",%(k),%(v)) - diff --git a/Reconstruction/Jet/JetRecConfig/python/JetAlgorithm.py b/Reconstruction/Jet/JetRecConfig/python/JetAlgorithm.py deleted file mode 100644 index 487a68a39f4d0a97464739dcb570b93182711ecf..0000000000000000000000000000000000000000 --- a/Reconstruction/Jet/JetRecConfig/python/JetAlgorithm.py +++ /dev/null @@ -1,165 +0,0 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration - -# JetAlgorithm.py -# -# David Adams -# March 2014 -# October 2014: Update to provide a fn that allow specification of alg sequence. -# -# Configure the jet algorithm after the tool manager has been configured. - -from AthenaCommon import Logging -jetlog = Logging.logging.getLogger('JetRec_jobOptions') - -# Record the jet algorithm here. -# Retrieve this with "from JetRec.JetAlgorithm import jetalg" *after* -# calling addJetRecoToAlgSequence(). -jetalg = None - -# Function to add jet reconstruction to an algorithm sequence -# job: algorithm sequence -# useTruth: Flag to schedule building of selected-truth containers -# eventShapeTools: Keys for the event shape tools to be run -# separateJetAlgs: Run JetRecTools in separate algs (experts only) -# debug: Debug level (0 for quiet). See below. -def addJetRecoToAlgSequence(job =None, useTruth =None, eventShapeTools =None, - separateJetAlgs= None, debug =None): - - myname = "JetAlgorithm: " - - # We need this to modify the global variable. - global jetalg - - # Import message level flags. - from GaudiKernel.Constants import DEBUG - - # Import the jet reconstruction control flags. - from JetRecFlags import jetFlags - - # Import the standard jet tool manager. - from JetRecStandardToolManager import jtm - - # Set sequence and flags as needed. - if job == None: - from AthenaCommon.AlgSequence import AlgSequence - job = AlgSequence() - if useTruth == None: - useTruth = jetFlags.useTruth() - if eventShapeTools == None: - eventShapeTools = jetFlags.eventShapeTools() - if eventShapeTools == None: - eventShapeTools = [] - if separateJetAlgs == None: - separateJetAlgs = jetFlags.separateJetAlgs() - - - from RecExConfig.ObjKeyStore import cfgKeyStore - # Event shape tools. - evstools = [] - evsDict = { - "emtopo" : ("EMTopoEventShape", jtm.emget), - "lctopo" : ("LCTopoEventShape", jtm.lcget), - "empflow" : ("EMPFlowEventShape", jtm.empflowget), - "emcpflow" : ("EMCPFlowEventShape", jtm.emcpflowget), - "lcpflow" : ("LCPFlowEventShape", jtm.lcpflowget), - } - - if jetFlags.useTracks(): - evsDict["emtopo"] = ("EMTopoEventShape", jtm.emoriginget) - evsDict["lctopo"] = ("LCTopoEventShape", jtm.lcoriginget) - jetlog.info( myname + "Event shape tools: " + str(eventShapeTools) ) - - for evskey in eventShapeTools: - from EventShapeTools.EventDensityConfig import configEventDensityTool - if evskey in evsDict: - (toolname, getter) = evsDict[evskey] - if toolname in jtm.tools: - jetlog.info( myname + "Skipping duplicate event shape: " + toolname ) - else: - jetlog.info( myname + "Adding event shape " + evskey ) - if not cfgKeyStore.isInInputFile("xAOD::EventShape",toolname): - jtm += configEventDensityTool(toolname, getter, 0.4) - evstools += [jtm.tools[toolname]] - else: - jetlog.info( myname + "Invalid event shape key: " + evskey ) - raise Exception - - # Add the tool runner. It runs the jetrec tools. - rtools = [] - # Add the truth tools. - if useTruth: - from JetRec.JetFlavorAlgs import scheduleCopyTruthParticles - rtools += scheduleCopyTruthParticles() - - # build truth jet input : - rtools += [ jtm.truthpartcopy, jtm.truthpartcopywz ] - - ## if jetFlags.useCells(): - ## rtools += [jtm.missingcells] commented out : incompatible with trigger : ATR-9696 - if jetFlags.useTracks: - rtools += [jtm.tracksel, - jtm.tvassoc, - jtm.trackselloose_trackjets, - ] - - # Add the algorithm. It runs the jetrec tools. - from JetRec.JetRecConf import JetAlgorithm - ctools = [] - if jetFlags.useTracks: - if not cfgKeyStore.isInInputFile("xAOD::CaloClusterContainer","LCOriginTopoClusters"): - ctools += [jtm.JetConstitSeq_LCOrigin] - if not cfgKeyStore.isInInputFile("xAOD::CaloClusterContainer","EMOriginTopoClusters"): - ctools += [jtm.JetConstitSeq_EMOrigin] - from JetRec.JetRecConf import JetToolRunner - runners = [] - if len(ctools)>0: - jtm += JetToolRunner("jetconstit", - EventShapeTools=[], - Tools=ctools, - Timer=jetFlags.timeJetToolRunner() - ) - jtm.jetconstit - runners = [jtm.jetconstit] - - if jetFlags.separateJetAlgs(): - - jtm += JetToolRunner("jetrun", - EventShapeTools=evstools, - Tools=rtools, - Timer=jetFlags.timeJetToolRunner() - ) - runners += [jetrun] - - job += JetAlgorithm("jetalg") - jetalg = job.jetalg - jetalg.Tools = runners - - for t in jtm.jetrecs: - jalg = JetAlgorithm("jetalg"+t.name()) - jalg.Tools = [t] - job+= jalg - - else: - from JetRec.JetRecConf import JetToolRunner - jtm += JetToolRunner("jetrun", - EventShapeTools=evstools, - Tools=rtools+jtm.jetrecs, - Timer=jetFlags.timeJetToolRunner() - ) - runners += [jtm.jetrun] - - job += JetAlgorithm("jetalg") - jetalg = job.jetalg - jetalg.Tools = runners - if jetFlags.debug > 0: - jtm.setOutputLevel(jtm.jetrun, DEBUG) - jetalg.OutputLevel = DEBUG - if jetFlags.debug > 1: - for tool in jtm.jetrecs: - jtm.setOutputLevel(tool, DEBUG) - if jetFlags.debug > 2: - for tool in jtm.finders: - jtm.setOutputLevel(tool, DEBUG) - if jetFlags.debug > 3: - jtm.setOutputLevel(jtm.jetBuilderWithArea, DEBUG) - jtm.setOutputLevel(jtm.jetBuilderWithoutArea, DEBUG) diff --git a/Reconstruction/Jet/JetRecConfig/python/JetDefinition.py b/Reconstruction/Jet/JetRecConfig/python/JetDefinition.py new file mode 100644 index 0000000000000000000000000000000000000000..5d1496345f7a16b57de5ec2bfeb8387f1ba1c975 --- /dev/null +++ b/Reconstruction/Jet/JetRecConfig/python/JetDefinition.py @@ -0,0 +1,321 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration + +######################################################################## +# # +# JetDefinition: A module for classes encoding definitions of jets and # +# related objects for configuring jet reconstruction # +# Author: TJ Khoo # +# # +######################################################################## + +__all__ = ["JetConstit", "JetGhost", "JetDefinition","xAOD"] + +# Code from JetRecUtils +# define the convention that we write R truncating the decimal point +# if R>=1, then we write R*10 +from AthenaCommon import Logging +jetlog = Logging.logging.getLogger('JetDefinition') + +from ROOT import xAOD +xAOD.Type.ObjectType + +def formatRvalue(parameter): + # impose precision limits where there could be ambiguity + if int(10*parameter)>=1 and int(100*parameter % 10): + #jetlog.warning('Radius parameter {0} exceeds allowable precision of 0.1'.format(parameter)) + raise ValueError('Bad radius parameter') + if int(parameter)>=1: + return "{0:.0f}".format(10*parameter) + else: + return "{0:.1g}".format(10*parameter).replace('.','') + +# Could also split off a VR name builder +def buildJetAlgName(finder, mainParam, variableRMassScale=None, variableRMinRadius=None): # variableRMassScale (Rho) in MeV + if ( variableRMassScale and variableRMinRadius ): + rmaxstr = formatRvalue(mainParam) + rminstr = formatRvalue(variableRMinRadius) + return finder + "VR" + str(int(variableRMassScale/1000)) + "Rmax" + rmaxstr + "Rmin" + rminstr + return finder + formatRvalue(mainParam) + +# A class that defines the type of object used to build a jet +class JetConstit(object): + def __init__(self, type, modifiers=[]): + self.__basetype = type + self.__modifiers = modifiers + + self.defineLabelAndContainerName() + pass + + def __hash__(self): + return hash((self.__basetype,str(self.__modifiers))) + + def __eq__(self,rhs): + return self.__hash__() == rhs.__hash__() + + def __ne__(self,rhs): + return (not __eq__(self,rhs)) + + # Define type and modifiers as properties, with + # custom setter/getter such that if changed, these + # force resetting of the label and container name + @property + def basetype(self): + return self.__basetype + @basetype.setter + def basetype(self,basetype): + self.__basetype = basetype + self.defineLabelAndContainerName() + + @property + def modifiers(self): + return self.__modifiers + @modifiers.setter + def modifiers(self,modifiers): + self.__modifiers = modifiers + self.defineLabelAndContainerName() + + def defineLabelAndContainerName(self): + labelnames = { + xAOD.Type.CaloCluster: "Topo", + xAOD.Type.ParticleFlow: "EMPFlow", + xAOD.Type.TrackParticle: "Track", + xAOD.Type.TruthParticle: "Truth", + xAOD.Type.TrackCaloCluster: "TrackCaloCluster", + xAOD.Type.Jet: "Jets", + } + + self.label = "" + self.inputname = "" + + # Truth "modifiers" specify the selection tool config + # e.g. WZ, WZDressed, DarkHadrons, ... + # Track "modifiers" specifiy the vertex association + # Other "modifiers" determine the constit mods e.g. + # origin correction, PU suppression etc + # Topoclusters should also specify EM or LC + # Jets just specify the jet definition + modstring = "" + if self.__modifiers: + for mod in self.__modifiers: + # Handle special case of topocluster state + if mod in ["EM","LC"]: + self.label += mod + self.inputname += mod + else: + modstring += mod + + if self.__basetype==xAOD.Type.Jet: + self.label += labelnames[self.__basetype] + else: + self.label += labelnames[self.__basetype] + self.label += modstring + if self.__basetype==xAOD.Type.TruthParticle: + self.label = self.label.replace("NoWZ","WZ") + + containernames = { + xAOD.Type.CaloCluster: "TopoClusters", + xAOD.Type.ParticleFlow: "ParticleFlowObjects", + xAOD.Type.TrackParticle: "JetSelectedTracks", + xAOD.Type.TruthParticle: "JetInputTruthParticles", + xAOD.Type.TrackCaloCluster: "TrackCaloClusters", + xAOD.Type.Jet: "Jets", + } + defaultaffixes = { + xAOD.Type.CaloCluster: "CaloCal", + xAOD.Type.ParticleFlow: "CHS", + xAOD.Type.TrackParticle: "", + xAOD.Type.TruthParticle: "", + xAOD.Type.TrackCaloCluster: "CombinedAndNeutral", + xAOD.Type.Jet: "", + } + + if not modstring: + modstring = defaultaffixes[self.__basetype] + modsfirst = [xAOD.Type.TruthParticle, xAOD.Type.TrackCaloCluster] + if self.__basetype in modsfirst: + self.inputname += containernames[self.basetype]+modstring + else: + self.inputname += modstring+containernames[self.basetype] + + pass + + # Define a string conversion for printing + def __str__(self): + return "JetConstit({0}: {1})".format(self.label,self.inputname) + # Need to override __repr__ for printing in lists etc + __repr__ = __str__ + +# Not too clear at this point what other info is needed +# In principle one might want to state the truth types etc +class JetGhost(object): + def __init__(self, inputtype): + self.inputtype = inputtype + self.label = "Ghost"+inputtype + pass + + def __hash__(self): + return hash(self.inputtype) + + def __eq__(self,rhs): + return self.__hash__() == rhs.__hash__() + + def __ne__(self,rhs): + return (not __eq__(self,rhs)) + + # Define a string conversion for printing + def __str__(self): + return "JetGhost(Ghost{0})".format(self.inputtype) + # Need to override __repr__ for printing in lists etc + __repr__ = __str__ + + +class JetDefinition(object): + def __init__(self, algorithm, radius, inputdef, + ptmin=5000., ptminfilter=5000., + ghostdefs=[], modifiers=[]): + + # Should add some type checking here + # Could use JetContainerInfo conversion + self.__algorithm = algorithm + if not self.__algorithm in ["Kt","AntiKt","CamKt"]: + jetlog.error("FastJet algorithm specification was not one of Kt, AntiKt, CamKt!") + raise KeyError("Invalid fastjet algorithm choice: {0}".format(self.algorithm)) + + self.__radius = radius + self.__inputdef = inputdef + self.defineName() + + self.ptmin = ptmin # The pt down to which FastJet is run + self.ptminfilter = ptminfilter # The pt above which xAOD::Jets are kept + if ptmin<1000. or ptminfilter<1000.: + jetlog.warning("Very low filter threshold set: ptmin {0:.0f} MeV, ptminfilter {1:.0f} MeV. Are you sure?") + self.ghostdefs = ghostdefs + self.modifiers = modifiers + + # Should this be a derived class? + self.grooming = None + + # These should probably go in a derived class + self.VRMinRadius = None + self.VRMassScale = None + + pass + + def __hash__(self): + return hash((self.__radius,self.__inputdef,self.ptmin,self.ptminfilter,str(self.ghostdefs),str(self.modifiers))) + + def __eq__(self,rhs): + return self.__hash__() == rhs.__hash__() + + def __ne__(self,rhs): + return (not __eq__(self,rhs)) + + # Define core attributes as properties, with + # custom setter/getter such that if changed, these + # force resetting of the jet name + @property + def algorithm(self): + return self.__algorithm + @algorithm.setter + def algorithm(self,algorithm): + self.__algorithm = algorithm + self.defineName() + + @property + def radius(self): + return self.__radius + @radius.setter + def radius(self,radius): + self.__radius = radius + self.defineName() + + @property + def inputdef(self): + return self.__inputdef + @inputdef.setter + def inputdef(self,inputdef): + self.__inputdef = inputdef + self.defineName() + + def defineName(self): + self.basename = buildJetAlgName(self.__algorithm,self.__radius)+self.__inputdef.label + if self.inputdef.basetype == xAOD.Type.CaloCluster: + # Omit cluster origin correction from jet name + # Keep the origin correction explicit because sometimes we may not + # wish to apply it, whereas PFlow corrections are applied implicitly + self.basename = self.basename.replace("Origin","") + pass + + # Define a string conversion for printing + def __str__(self): + return "JetDefinition({0}, ptmin: {1} MeV)".format(self.basename,self.ptmin) + # Need to override __repr__ for printing in lists etc + __repr__ = __str__ + +######################################################################## +# Helper to instantiate a generic jet modifier +# Tools that typically have more complex properties set should have +# their own dedicated helper functions defined +from AthenaCommon import CfgMgr + +class JetModifier(object): + def __init__(self,tooltype,toolname, + helperfn=None, + prereqs=[],modspec=None,passJetDef=False): + # For the easy cases where no helper function is needed. + # They will be ignored in the case of a helper, + # but are still required such that it's obvious what + # the tool name and type are when defining the config. + self.tooltype = tooltype + self.toolname = toolname + + # The helper function may take up to 2 parameters: + # a "modifier specification" string and the jet + # definition, which will be passed in based + # on the values of modspec and passJetDef. + # + # The helper function always returns the desired + # modifier, and a ComponentAccumulator instance, + # in case additional supporting tools/services + # need to be set up. + if helperfn==None: + self.helperfn = self.getGenericModifier + else: + self.helperfn = helperfn + self.modspec = modspec + self.passJetDef = passJetDef + + # Prereqs is normally a list. + # However, in special cases, the prereqs may + # depend on either or both of modspec and jetdef, + # in which case a helper function can be defined. + self.prereqs = prereqs + + def __hash__(self): + return hash((self.toolname,self.tooltype,self.helperfn.__name__,self.modspec,self.passJetDef,str(self.prereqs))) + + def __eq__(self,rhs): + return self.__hash__() == rhs.__hash__() + + def __ne__(self,rhs): + return (not __eq__(self,rhs)) + + # Define a string conversion for printing + def __str__(self): + return "JetModifier({0}/{1})".format(self.tooltype,self.toolname) + # Need to override __repr__ for printing in lists etc + __repr__ = __str__ + + def getGenericModifier(self,**kwargs): + tool = getattr(CfgMgr,self.tooltype)(self.toolname) + return tool + + def getPrereqs(self,modspec="",jetdef=None): + prereqs = [] + if self.prereqs.__class__ == list: + prereqs += self.prereqs + else: + prereqs += self.prereqs(modspec,jetdef) + jetlog.verbose("Prereqs for {0}: [{1}]".format(self.toolname,", ".join(prereqs))) + return prereqs + diff --git a/Reconstruction/Jet/JetRecConfig/python/JetFlavorAlgs.py b/Reconstruction/Jet/JetRecConfig/python/JetFlavorAlgs.py deleted file mode 100644 index 30ff8c7fc77136641a32df649871f00aa0f420d0..0000000000000000000000000000000000000000 --- a/Reconstruction/Jet/JetRecConfig/python/JetFlavorAlgs.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration - -# JetFlavorAlgs.py -# -# David Adams -# September 2014 - -from AthenaCommon import Logging -jetlog = Logging.logging.getLogger('JetRec_jobOptions') - -# Import the jet reconstruction control flags. -from JetRecFlags import jetFlags - -jetlog.info( str(jetFlags.truthFlavorTags()) ) - -def scheduleCopyTruthParticles(): - myname = "scheduleCopyTruthParticles: " - from JetRecStandardToolManager import jtm - if not jtm.haveParticleJetTools: return - from ParticleJetTools.ParticleJetToolsConf import CopyFlavorLabelTruthParticles - from ParticleJetTools.ParticleJetToolsConf import CopyBosonTopLabelTruthParticles - from ParticleJetTools.ParticleJetToolsConf import CopyTruthPartons - from ParticleJetTools.CopyTruthParticlesAlg import CopyTruthParticlesAlg - - tools = [] - for ptype in jetFlags.truthFlavorTags(): - toolname = "CopyTruthTag" + ptype - if toolname in jtm.tools: - jetlog.info( myname + "Skipping previously-defined tool: " + toolname ) - jetlog.info( jtm.tools[toolname] ) - else: - jetlog.info( myname + "Scheduling " + toolname ) - ptmin = 5000 - if ptype == "Partons": - ctp = CopyTruthPartons(toolname) - elif ptype in ["WBosons", "ZBosons", "HBosons", "TQuarksFinal"]: - ctp = CopyBosonTopLabelTruthParticles(toolname) - ctp.ParticleType = ptype - ptmin = 100000 - else: - ctp = CopyFlavorLabelTruthParticles(toolname) - ctp.ParticleType = ptype - ctp.OutputName = "TruthLabel" + ptype - ctp.PtMin = ptmin - jtm += ctp - #theJob += CopyTruthParticlesAlg(ctp, toolname + "Alg") - jetlog.info( ctp ) - tools.append( ctp ) - return tools diff --git a/Reconstruction/Jet/JetRecConfig/python/JetModConfig.py b/Reconstruction/Jet/JetRecConfig/python/JetModConfig.py new file mode 100644 index 0000000000000000000000000000000000000000..858dfb85994bc95cce1a0b5e939d4be6e51242a9 --- /dev/null +++ b/Reconstruction/Jet/JetRecConfig/python/JetModConfig.py @@ -0,0 +1,96 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +######################################################################## +# # +# JetModConfig: A helper module for configuring jet modifier tools # +# Author: TJ Khoo # +# # +######################################################################## + +from AthenaCommon import Logging +modlog = Logging.logging.getLogger('JetModConfig') + +######################################################################## +# Function for generating a list of JetModifier tools +# Keep a default empty modstrings as we might want to actually +# specify some defaults (e.g. calib/filter/sort) for specific configs +# +# First incarnation is "dumb" but we want this to be "smart" and set up +# the right tools in order, propagating dependencies. +# +def getFinalModifierListAndPrereqs(mods_initial, jetdef): + if len(mods_initial)==0: return [], set() + mods_final = [] + # By the end of the recursion, all mods should have been applied already. + prereqs = set() + + modlog.verbose("Initial mod list: " + str(mods_initial)) + + # Loop over the initial list + # Extract the concrete definition and specifier string + # Then grab any prereqs, and expand if the list contains mods + for mod in mods_initial: + moddef, modspec = getModDefAndSpec( mod ) + modreqs = moddef.getPrereqs(modspec,jetdef) + prereqmods = [] + for req in modreqs: + reqtype, reqspec = req.split(':',1) + if reqtype == "mod": + prereqmods.append(reqspec) + else: + prereqs.add( req ) + # Recursion happens here + prereqmods_final, moreprereqs = getFinalModifierListAndPrereqs( prereqmods, jetdef ) + prereqs.update( moreprereqs ) + mods_final += prereqmods_final + [(moddef,modspec)] + + modlog.verbose("Current input prereqs: {0}".format(prereqs)) + modlog.verbose("Final modlist: {0}".format(mods_final)) + return mods_final, prereqs + +# [Optional] Args are: +# 1. Tool Type (may be ignored if the helper is a custom one) +# 2. Tool Name (may be ignored if the helper is a custom one) +# [3.] Config helper +# [4.] Prereqs (default to []). If "None", will try to get from the function. +# [5.] Flag passJetDef specifying if the helper needs the jet definition +# We use a helper class to encapsulate the modifier configuration + +# Translate modifier string into JetModifier if necessary +# Extracts the modspec from the string or the config object +def getModDefAndSpec(mod): + from StandardJetMods import jetmoddict + moddef = mod + modspec = "" + if mod.__class__ == type("str"): + modkey = mod + if ":" in mod: + modkey, modspec = mod.split(':',1) + moddef = jetmoddict[modkey] + else: + modspec = moddef.modspec + modlog.verbose("Interpreted modifier string {0} as {1} with specification \"{2}\"".format(mod,moddef,modspec)) + return moddef, modspec + +# Translate JetModifier into a concrete tool +def getModifier(jetdef, moddef, modspec): + modtool = None + modlog.verbose("Retrieving modifier {0}".format(str(moddef))) + + # Define some optional keyword arguments + kwargs = {} + if moddef.passJetDef: + kwargs["jetdef"] = jetdef + if modspec!="": + kwargs["modspec"] = modspec + + # Get the modifier tool + try: + modtool = moddef.helperfn(**kwargs) + except Exception as e: + modlog.error( "Unhandled modifier specification {0} for {1}!".format(moddef,jetdef.basename) ) + modlog.error( "Received exception \"{0}\"".format(e) ) + modlog.error( "Helper function is \"{0}\"".format(moddef.helperfn) ) + raise ValueError( "JetModConfig unable to handle mod {0}".format(moddef) ) + + return modtool diff --git a/Reconstruction/Jet/JetRecConfig/python/JetRecCalibrationFinder.py b/Reconstruction/Jet/JetRecConfig/python/JetRecCalibrationFinder.py deleted file mode 100644 index a24bc37aad1fd3ea6c4028b3acfb7009cc227c42..0000000000000000000000000000000000000000 --- a/Reconstruction/Jet/JetRecConfig/python/JetRecCalibrationFinder.py +++ /dev/null @@ -1,128 +0,0 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration - -# JetRecCalibrationFinder.py - -# David Adams -# September 2014 -# -# Class to retrieve the calibration tool for a given jet definition -# and calibration sequence. The calibration tool is created if it -# does not already exist. -# -# Usage: -# from JetRec.JetRecCalibrationFinder import jrcf -# tool = jrcf.find(alg, rad, inp, seq, con) -# -# Arguments: -# alg - Algorithm name: AntiKt, CamKt or Kt -# rad - Jet size parameter, e.g. 0.4 -# inp - Input type: EMTopo or LCTopo -# seq - Calibration sequence as one letter for each step, e.g. "ar" -# a = Active area correction (rho*A) -# r = Pileup residual correction (i.e. using mu and NPV) -# j = JES correction (from MC) -# g = GSC correction (from MC) -# i = Insitu correction (data only) -# con - Configuration file name or entry in jrcf.configDict -# -# To add to the confid dictionary: -# jrcf.configDict["myname"] = "someConfigFile.config" - -from AthenaCommon import Logging -jetlog = Logging.logging.getLogger('JetRec_jobOptions') - -class JetRecCalibrationFinder: - - # Dictionary of calibrations steps. - calibStep = { - "a":"JetArea", - "r":"Residual", - "o":"Origin", - "j":"AbsoluteEtaJES", - "g":"GSC", - "i":"Insitu", - "m":"JMS", - } - - # Dictionary for calibration configurations. - configDict = { - "reco" : "JES_MC15cRecommendation_May2016_rel21.config", - "trigger" : "JES_Full2012dataset_Preliminary_Trigger.config", - "triggerNoPileup" : "JES_Full2012dataset_Preliminary_Trigger_NoPileup.config", - "trigger2016" : "JES_MC15cRecommendation_May2016_Trigger.config", - "triggerTrim" : "JES_MC15recommendation_FatJet_June2015.config", - "pflow" : "JES_MC15cRecommendation_PFlow_Aug2016.config" - } - - def find(self, alg, rad, inpin, seq, configkeyin, evsprefix): - from JetCalibTools.JetCalibToolsConf import JetCalibrationTool - from JetRec.JetRecStandardToolManager import jtm - inp = inpin - # Find the configuration file. - configkey = configkeyin - if configkey == "": configkey = "reco" - if configkey in self.configDict: - configfile = self.configDict[configkey] - else: - configfile = configkey - # Assign name for tool - jetdefn = alg + str(int(10*rad+0.1)) + inp.split("Origin")[0] - tname = "calib_" + jetdefn + "_" + configkey.replace(".","_") + "_" + seq - # Display configuration. - myname = "JetRecCalibrationFinder:find: " - jetlog.info( myname + "Building jet calibration tool." ) - jetlog.info( myname + " Arguments:" ) - jetlog.info( myname + " alg: " + str(alg) ) - jetlog.info( myname + " rad: " + str(rad) ) - jetlog.info( myname + " inp: " + str(inp) ) - jetlog.info( myname + " seq: " + str(seq) ) - jetlog.info( myname + " Jet definition: " + jetdefn ) - jetlog.info( myname + " Configuration file: " + configfile ) - - if tname in jtm.tools: - jetlog.info( myname + " Skipping previously-defined tool: " + tname ) - else: - # build calib tool - jetlog.info( myname + " Creating " + tname ) - # ...define calbration sequence - try: - fullseq = [self.calibStep[l] for l in seq] # translate letters - except KeyError as err: - jetlog.info( myname + " ERROR Invalid sequence: " + seq ) - jetlog.info( myname + " ERROR Unknown sequence key: " + err.message ) - raise err - fullseq = '_'.join(fullseq) # join seq names with a '_' - jetlog.info( myname + " Calibration sequence: " + fullseq ) - # ...define the key for the event shape container - if inpin == "EMTopo": - evssuf="EMTopoEventShape" - elif inpin == "LCTopo": - evssuf="LCTopoEventShape" - elif inpin == "EMTopoOrigin": - evssuf="EMTopoOriginEventShape" - elif inpin == "LCTopoOrigin": - evssuf="LCTopoOriginEventShape" - elif inpin == "EMPFlow": - evssuf="EMPFlowEventShape" - elif inpin == "EMCPFlow": - evssuf="EMCPFlowEventShape" - elif inpin == "LCPFlow": - evssuf="LCPFlowEventShape" - elif inpin.startswith("LCTopoTrimmed"): - evssuf="LCTopoEventShape" - else: - evssuf="INVALID" - jetlog.info( myname + " ERROR: Invalid input specifier: " + inp ) - raise KeyError - evskey = evsprefix + evssuf - jetlog.info( myname + " Event shape key: " + evskey ) - # ...create the tool. - setDetEtaPhi = (configkey != "reco") # Temporary setting to avoid clash with modifiers that set detector eta - jtm += JetCalibrationTool(tname, JetCollection=jetdefn, ConfigFile=configfile, CalibSequence=fullseq, RhoKey=evskey, - DoSetDetectorEta=setDetEtaPhi) - - return jtm.tools[tname] - -# This is the only instance of the above class that should be used to -# that should be used to fetch calibration tools. -jrcf = JetRecCalibrationFinder() diff --git a/Reconstruction/Jet/JetRecConfig/python/JetRecConfig.py b/Reconstruction/Jet/JetRecConfig/python/JetRecConfig.py index ec6c44ccb85e7184aaa9f454c731f7e850d10291..7865879b150986f4b5610e0a24989182e7359e16 100644 --- a/Reconstruction/Jet/JetRecConfig/python/JetRecConfig.py +++ b/Reconstruction/Jet/JetRecConfig/python/JetRecConfig.py @@ -1,712 +1,460 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration + +######################################################################## +# # +# JetRecConfig: A helper module for configuring jet reconstruction # +# Author: TJ Khoo # +# # +######################################################################## + +from AthenaCommon import Logging +jetlog = Logging.logging.getLogger('JetRecConfig') + +from ROOT import xAOD +xAOD.Type.ObjectType + +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator + +# CfgMgr is more convenient but it helps to be explicit about where +# things are defined. +# So, import package conf modules rather than a dozen individual classes +from JetRec import JetRecConf + +__all__ = ["xAOD", "JetRecCfg", "resolveDependencies"] + +######################################################################## +# Top-level function for running jet finding +# (i.e. clustering from inputs) +# This returns a ComponentAccumulator that can be merged with others +# from elsewhere in the job, but will provide everything needed to +# reconstruct one jet collection. +# This could still be modularised further into the subcomponents of the +# jet reconstruction job. For now, based on public tools, as private +# tool migration has not been completed. +# +# Receives the jet definition and input flags, mainly for input file +# peeking such that we don't attempt to reproduce stuff that's already +# in the input file +def JetRecCfg(jetdef, configFlags, jetnameprefix="",jetnamesuffix=""): + components = ComponentAccumulator() + + jetsfullname = jetnameprefix+jetdef.basename+jetnamesuffix+"Jets" + jetlog.info("Setting up to find {0}".format(jetsfullname)) -# JetRecStandardTools.py + deps = resolveDependencies( jetdef ) + + # Schedule the various input collections. + # We don't have to worry about ordering, as the scheduler + # will handle the details. Just merge the components. + # + # To facilitate running in serial mode, we also prepare + # the constituent PseudoJetGetter here (needed for rho) + inputcomps, constitpjkey = JetInputCfgAndConstitPJName(deps["inputs"], configFlags) + components.merge(inputcomps) + pjs = [constitpjkey] + + # Schedule the ghost PseudoJetGetterAlgs + for ghostdef in deps["ghosts"]: + ghostpjcomps, ghostpjkey = GhostPJGCfgAndOutputName( ghostdef ) + components.merge( ghostpjcomps ) + pjs.append( ghostpjkey ) + + # Generate a JetAlgorithm to run the jet finding and modifiers + # (via a JetRecTool instance). + reccomps = JetAlgorithmCfg(jetsfullname, jetdef, pjs, deps["mods"]) + components.merge(reccomps) + + jetlog.info("Scheduled JetAlgorithm instance \"jetalg_{0}\"".format(jetsfullname)) + return components + +######################################################################## +# The real workhorse -- establishes the full sequence of jet reco, +# recursively expanding the prerequisites # -# David Adams -# March 2014 +# Avoids constructing any configurables at this stage, the goal being +# to produce a human-readable job description. +def resolveDependencies(jetdef): + + jetlog.info("Resolving dependencies for {0} definition".format(jetdef.basename)) + + # Accumulate prerequisites of the base constituent type + # We just collect everything and sort out the types later + prereqs = set() # Resolve duplication as we go + prereqs.update( getConstitPrereqs( jetdef.inputdef ) ) + + # Add the Filter modifier if desired (usually it is) + # It might be simpler to just eliminate ptminfilter + # and always make this an explicit modifier + mods_initial = list(jetdef.modifiers) + if jetdef.ptminfilter>1e-9: + filtstr = "Filter:{0:.0f}".format(jetdef.ptminfilter) + # Insert pt filter after calibration if present + idx=-1 + for imod, mod in enumerate(mods_initial): + if mod.startswith("Calib"): + idx = imod+1 + break + mods_initial.insert(idx,filtstr) + + # Accumulate prerequisites of the modifiers, as these are + # the most extensive. Internally resolves modifier chains, + # returning an updated modifiers list + # Need to use a list, as the order matters. + # The elements of the "final" list are tuples extracting + # the modifier specification. + import JetModConfig + mods_final, modprereqs = JetModConfig.getFinalModifierListAndPrereqs( mods_initial, jetdef ) + + # Remove the duplicates in the mod list -- just do this + # once at the end and preserve ordering. + def dedupe(mylist): + outlist = [] + usedset = set() + for item in mylist: + if not (item in usedset): + outlist.append(item) + usedset.add(item) + return outlist + mods_final = dedupe( mods_final ) + + prereqs.update( modprereqs ) + + # Ghost prerequisites are only of type input, so we can + # afford to sort now. + prereqdict = {"ghost":set(), "input":set()} + prereqdict.update( classifyPrereqs(prereqs) ) + + # Copy the explicitly requested ghost defs and add to + # these those required by modifiers. + ghostdefs = set(jetdef.ghostdefs).union(prereqdict["ghost"]) + # Expand from strings to JetGhost objects where needed. + ghostdefs = expandPrereqs( "ghost",ghostdefs ) + + # Accumulate prerequisites of the ghost-associated types + jetlog.info(" Full list of ghosts: ") + for ghostdef in sorted(list(ghostdefs)): + jetlog.info(" " + str(ghostdef)) + gprereqs = getGhostPrereqs(ghostdef) + prereqdict["input"].update( [req.split(':',1)[1] for req in gprereqs] ) + + jetlog.info(" Full list of mods: ") + for mod, modspec in mods_final: + jetlog.info(" " + str(mod) + ("" if not modspec else ": \"{0}\"".format(modspec))) + + # Return a dict of the dependencies, converting sets to lists. + # May want to further separate input deps. + dependencies = { + "inputs": [jetdef.inputdef] + sorted(list( prereqdict["input"] )), + "ghosts": list( ghostdefs ), + "mods": mods_final + } + + # We don't expand the inputs at this stage, as they are diverse + # and don't have a dedicated config class. + # Doing so may trigger another level of expansion if the inputs + # include a jet collection. + return dependencies + +######################################################################## +# Function for classifying prerequisites # -# Define the low-level tools used in jet reconstruction. +def classifyPrereqs(prereqs): + prereqdict = {} + for req in prereqs: + key,val = req.split(":",1) + jetlog.verbose( "Interpreted prereqs: {0} --> {1}".format(key,val) ) + if not key in prereqdict.keys(): + prereqdict[key] = set() + prereqdict[key].add(val) + + return prereqdict + +######################################################################## +# Function for expanding prerequisites into definitions +# Only supporting ghosts for now, but could be extended # -# Tools are configured and put in the global jet tool manager so -# they can be accessed when configuring JetRec tools. +def expandPrereqs(reqtype,prereqs): + reqdefs = set() + from JetDefinition import JetGhost + for req in prereqs: + if reqtype=="ghost": + if req.__class__ == JetGhost: + reqdefs.add( req ) + else: + ghostdef = JetGhost(req) + reqdefs.add( ghostdef ) + jetlog.debug("Expanded prereq {0} to {1}".format(req,ghostdef)) + else: + jetlog.error("Prereqs \"{0}\" unsupported!".format(reqtype)) + return None + return reqdefs + + +######################################################################## +# Function for setting up inputs to jet finding # -# Execute this file to add the definitions to -# JetRecStandardToolManager.jtm, e.g. -# import JetRecConfig.JetRecStandardTools - -# Import the jet flags. -# from JetRecFlags import jetFlags - -# if not "UseTriggerStore " in locals(): -# UseTriggerStore = False - -# # get levels defined VERBOSE=1 etc. -# from GaudiKernel.Constants import * - -# from eflowRec.eflowRecFlags import jobproperties - -# from JetRecStandardToolManager import jtm -# from InDetTrackSelectionTool.InDetTrackSelectionToolConf import InDet__InDetTrackSelectionTool -# from MCTruthClassifier.MCTruthClassifierConf import MCTruthClassifier - -# from PFlowUtils.PFlowUtilsConf import CP__RetrievePFOTool as RetrievePFOTool -# from JetRecTools.JetRecToolsConf import TrackPseudoJetGetter -# from JetRecTools.JetRecToolsConf import JetTrackSelectionTool -# from JetRecTools.JetRecToolsConf import SimpleJetTrackSelectionTool -# from JetRecTools.JetRecToolsConf import TrackVertexAssociationTool -# try: -# from JetRecCalo.JetRecCaloConf import MissingCellListTool -# jtm.haveJetRecCalo = True -# except ImportError: -# jtm.haveJetRecCalo = False -# from JetRecTools.JetRecToolsConf import PFlowPseudoJetGetter -# from JetRec.JetRecConf import JetPseudojetRetriever -# from JetRec.JetRecConf import JetConstituentsRetriever -# from JetRec.JetRecConf import JetRecTool -# from JetRec.JetRecConf import PseudoJetGetter -# from JetRec.JetRecConf import MuonSegmentPseudoJetGetter -# from JetRec.JetRecConf import JetFromPseudojet -# from JetRec.JetRecConf import JetConstitRemover -# from JetRec.JetRecConf import JetSorter -# from JetMomentTools.JetMomentToolsConf import JetCaloQualityTool -# try: -# from JetMomentTools.JetMomentToolsConf import JetCaloCellQualityTool -# jtm.haveJetCaloCellQualityTool = True -# except ImportError: -# jtm.haveJetCaloCellQualityTool = False -# from JetMomentTools.JetMomentToolsConf import JetWidthTool -# from JetMomentTools.JetMomentToolsConf import JetCaloEnergies -# try: -# from JetMomentTools.JetMomentToolsConf import JetJetBadChanCorrTool -# jtm.haveJetBadChanCorrTool = True -# except ImportError: -# jtm.haveJetBadChanCorrTool = False -# from JetMomentTools.JetMomentToolsConf import JetECPSFractionTool -# from JetMomentTools.JetMomentToolsConf import JetVertexFractionTool -# from JetMomentTools.JetMomentToolsConf import JetVertexTaggerTool -# from JetMomentTools.JetMomentToolsConf import JetTrackMomentsTool -# from JetMomentTools.JetMomentToolsConf import JetTrackSumMomentsTool -# from JetMomentTools.JetMomentToolsConf import JetClusterMomentsTool -# from JetMomentTools.JetMomentToolsConf import JetVoronoiMomentsTool -# from JetMomentTools.JetMomentToolsConf import JetIsolationTool -# from JetMomentTools.JetMomentToolsConf import JetLArHVTool -# from JetMomentTools.JetMomentToolsConf import JetOriginCorrectionTool -# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import KtDeltaRTool -# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import NSubjettinessTool -# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import KTSplittingScaleTool -# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import AngularityTool -# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import DipolarityTool -# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import PlanarFlowTool -# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import KtMassDropTool -# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import EnergyCorrelatorTool -# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import CenterOfMassShapesTool -# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import JetPullTool -# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import JetChargeTool -# try: -# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import ShowerDeconstructionTool -# jtm.haveShowerDeconstructionTool = True -# except ImportError: -# jtm.haveShowerDeconstructionTool = False -# try: -# from ParticleJetTools.ParticleJetToolsConf import Analysis__JetQuarkLabel -# jtm.haveParticleJetTools = True -# except: -# jtm.haveParticleJetTools = False -# if jtm.haveParticleJetTools: -# from ParticleJetTools.ParticleJetToolsConf import Analysis__JetConeLabeling -# from ParticleJetTools.ParticleJetToolsConf import Analysis__JetPartonTruthLabel -# from ParticleJetTools.ParticleJetToolsConf import CopyTruthJetParticles -# from ParticleJetTools.ParticleJetToolsConf import ParticleJetDeltaRLabelTool - -# #-------------------------------------------------------------- -# # Track selection. -# #-------------------------------------------------------------- - -# # This is the InDet loose selection from -# # https://twiki.cern.ch/twiki/bin/view/AtlasProtected/InDetTrackingPerformanceGuidelines -# # October 28, 2014 -# #jtm += InDet__InDetDetailedTrackSelectionTool( -# jtm += InDet__InDetTrackSelectionTool( -# "trk_trackselloose", -# minPt = 400.0, -# maxAbsEta = 2.5, -# minNSiHits = 7, -# maxNPixelSharedHits = 1, -# maxOneSharedModule = True, -# maxNSiHoles = 2, -# maxNPixelHoles = 1, -# ) - -# jtm += JetTrackSelectionTool( -# "trackselloose", -# InputContainer = jtm.trackContainer, -# OutputContainer = "JetSelectedTracks", -# Selector = jtm.trk_trackselloose -# ) - -# jtm += InDet__InDetTrackSelectionTool( -# "trk_trackselloose_trackjets", -# CutLevel = "Loose" -# ) - -# jtm += JetTrackSelectionTool( -# "trackselloose_trackjets", -# InputContainer = jtm.trackContainer, -# OutputContainer = "JetSelectedTracks_LooseTrackJets", -# Selector = jtm.trk_trackselloose_trackjets -# ) - -# if jetFlags.useInDetTrackSelection(): -# jtm += JetTrackSelectionTool( -# "tracksel", -# InputContainer = jtm.trackContainer, -# OutputContainer = "JetSelectedTracks", -# Selector = jtm.trk_trackselloose -# ) -# else: -# jtm += SimpleJetTrackSelectionTool( -# "tracksel", -# PtMin = 500.0, -# InputContainer = jtm.trackContainer, -# OutputContainer = "JetSelectedTracks", -# ) - -# #-------------------------------------------------------------- -# # Track-vertex association. -# #-------------------------------------------------------------- -# from TrackVertexAssociationTool.TrackVertexAssociationToolConf import CP__TightTrackVertexAssociationTool -# jtm += CP__TightTrackVertexAssociationTool("jetTighTVAtool", dzSinTheta_cut=3, doPV=True) - -# jtm += TrackVertexAssociationTool( -# "tvassoc", -# TrackParticleContainer = jtm.trackContainer, -# TrackVertexAssociation = "JetTrackVtxAssoc", -# VertexContainer = jtm.vertexContainer, -# TrackVertexAssoTool = jtm.jetTighTVAtool, -# ) - -# jtm += TrackVertexAssociationTool( -# "tvassoc_old", -# TrackParticleContainer = jtm.trackContainer, -# TrackVertexAssociation = "JetTrackVtxAssoc_old", -# VertexContainer = jtm.vertexContainer, -# MaxTransverseDistance = 1.5, -# MaxLongitudinalDistance = 1.0e7, -# MaxZ0SinTheta = 1.5 -# ) - -# #-------------------------------------------------------------- -# # Truth selection. -# #-------------------------------------------------------------- - -# if jetFlags.useTruth: -# truthClassifier = MCTruthClassifier(name = "JetMCTruthClassifier", -# ParticleCaloExtensionTool="") -# jtm += truthClassifier - -# jtm += CopyTruthJetParticles("truthpartcopy", OutputName="JetInputTruthParticles", -# MCTruthClassifier=truthClassifier) -# jtm += CopyTruthJetParticles("truthpartcopywz", OutputName="JetInputTruthParticlesNoWZ", -# MCTruthClassifier=truthClassifier, -# IncludeWZLeptons=False, #IncludeTauLeptons=False, -# IncludeMuons=True,IncludeNeutrinos=True) - - -# #-------------------------------------------------------------- -# # Jet reco infrastructure. -# #-------------------------------------------------------------- - -# # Jet pseudojet retriever. -# jtm += JetPseudojetRetriever("jpjretriever") - -# # Jet constituent retriever. -# labs = [] -# if jetFlags.useTracks(): -# labs += ["Track"] -# labs += ["AntiKt3TrackJet", "AntiKt3TrackJet"] -# if jetFlags.useMuonSegments(): -# labs += ["MuonSegment",] -# if jetFlags.useTruth(): -# labs += ["Truth"] -# for lab in jetFlags.truthFlavorTags(): -# labs += [lab] -# jtm += JetConstituentsRetriever( -# "jconretriever", -# UsePseudojet = True, -# UseJetConstituents = True, -# PseudojetRetriever = jtm.jpjretriever, -# GhostLabels = labs, -# GhostScale = 1.e-20 -# ) - -# #-------------------------------------------------------------- -# # Pseudojet builders. -# #-------------------------------------------------------------- - -# # Clusters. -# jtm += PseudoJetGetter( -# "lcget", -# InputContainer = "CaloCalTopoClusters", -# Label = "LCTopo", -# OutputContainer = "PseudoJetLCTopo", -# SkipNegativeEnergy = True, -# GhostScale = 0.0 -# ) - -# # EM clusters. -# jtm += PseudoJetGetter( -# "emget", -# InputContainer = "CaloCalTopoClusters", -# Label = "EMTopo", -# OutputContainer = "PseudoJetEMTopo", -# SkipNegativeEnergy = True, -# GhostScale = 0.0 -# ) - -# # Tracks. -# jtm += TrackPseudoJetGetter( -# "trackget", -# InputContainer = jtm.trackselloose_trackjets.OutputContainer, -# Label = "Track", -# OutputContainer = "PseudoJetTracks", -# TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation, -# SkipNegativeEnergy = True, -# GhostScale = 0.0 -# ) - -# # Ghost tracks. -# jtm += TrackPseudoJetGetter( -# "gtrackget", -# InputContainer = jtm.tracksel.OutputContainer, -# Label = "GhostTrack", -# OutputContainer = "PseudoJetGhostTracks", -# TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation, -# SkipNegativeEnergy = True, -# GhostScale = 1e-20 -# ) - -# # Muon segments -# jtm += MuonSegmentPseudoJetGetter( -# "gmusegget", -# InputContainer = "MuonSegments", -# Label = "GhostMuonSegment", -# OutputContainer = "PseudoJetGhostMuonSegment", -# Pt = 1.e-20 -# ) - -# # Retriever for pflow objects. -# jtm += RetrievePFOTool("pflowretriever") - -# useVertices = True -# if False == jetFlags.useVertices: -# useVertices = False - -# if True == jobproperties.eflowRecFlags.useUpdated2015ChargedShowerSubtraction: -# useChargedWeights = True -# else: -# useChargedWeights = False - -# useTrackVertexTool = False -# if True == jetFlags.useTrackVertexTool: -# useTrackVertexTool = True - -# # EM-scale pflow. -# jtm += PFlowPseudoJetGetter( -# "empflowget", -# Label = "EMPFlow", -# OutputContainer = "PseudoJetEMPFlow", -# RetrievePFOTool = jtm.pflowretriever, -# InputIsEM = True, -# CalibratePFO = False, -# SkipNegativeEnergy = True, -# UseChargedWeights = useChargedWeights, -# UseVertices = useVertices, -# UseTrackToVertexTool = useTrackVertexTool -# ) - -# # Calibrated EM-scale pflow. -# jtm += PFlowPseudoJetGetter( -# "emcpflowget", -# Label = "EMCPFlow", -# OutputContainer = "PseudoJetEMCPFlow", -# RetrievePFOTool = jtm.pflowretriever, -# InputIsEM = True, -# CalibratePFO = True, -# SkipNegativeEnergy = True, -# UseChargedWeights = useChargedWeights, -# UseVertices = useVertices, -# UseTrackToVertexTool = useTrackVertexTool -# ) - -# # LC-scale pflow. -# jtm += PFlowPseudoJetGetter( -# "lcpflowget", -# Label = "LCPFlow", -# OutputContainer = "PseudoJetLCPFlow", -# RetrievePFOTool = jtm.pflowretriever, -# InputIsEM = False, -# CalibratePFO = False, -# SkipNegativeEnergy = True, -# UseChargedWeights = useChargedWeights, -# UseVertices = useVertices, -# UseTrackToVertexTool = useTrackVertexTool -# ) - -# # AntiKt2 track jets. -# jtm += PseudoJetGetter( -# "gakt2trackget", # give a unique name -# InputContainer = jetFlags.containerNamePrefix() + "AntiKt2PV0TrackJets", # SG key -# Label = "GhostAntiKt2TrackJet", # this is the name you'll use to retrieve associated ghosts -# OutputContainer = "PseudoJetGhostAntiKt2TrackJet", -# SkipNegativeEnergy = True, -# GhostScale = 1.e-20, # This makes the PseudoJet Ghosts, and thus the reco flow will treat them as so. -# ) - -# # AntiKt3 track jets. -# jtm += PseudoJetGetter( -# "gakt3trackget", # give a unique name -# InputContainer = jetFlags.containerNamePrefix() + "AntiKt3PV0TrackJets", # SG key -# Label = "GhostAntiKt3TrackJet", # this is the name you'll use to retrieve associated ghosts -# OutputContainer = "PseudoJetGhostAntiKt3TrackJet", -# SkipNegativeEnergy = True, -# GhostScale = 1.e-20, # This makes the PseudoJet Ghosts, and thus the reco flow will treat them as so. -# ) - -# # AntiKt4 track jets. -# jtm += PseudoJetGetter( -# "gakt4trackget", # give a unique name -# InputContainer = jetFlags.containerNamePrefix() + "AntiKt4PV0TrackJets", # SG key -# Label = "GhostAntiKt4TrackJet", # this is the name you'll use to retrieve associated ghosts -# OutputContainer = "PseudoJetGhostAntiKt4TrackJet", -# SkipNegativeEnergy = True, -# GhostScale = 1.e-20, # This makes the PseudoJet Ghosts, and thus the reco flow will treat them as so. -# ) - -# # Truth. -# if jetFlags.useTruth and jtm.haveParticleJetTools: -# jtm += PseudoJetGetter( -# "truthget", -# Label = "Truth", -# InputContainer = jtm.truthpartcopy.OutputName, -# OutputContainer = "PseudoJetTruth", -# GhostScale = 0.0, -# SkipNegativeEnergy = True, - -# ) -# jtm += PseudoJetGetter( -# "truthwzget", -# Label = "TruthWZ", -# InputContainer = jtm.truthpartcopywz.OutputName, -# OutputContainer = "PseudoJetTruthWZ", -# GhostScale = 0.0, -# SkipNegativeEnergy = True, +# This includes constituent modifications, track selection, copying of +# input truth particles and event density calculations +def JetInputCfgAndConstitPJName(inputdeps, configFlags): + jetlog.info("Setting up jet inputs.") + components = ComponentAccumulator() + + jetlog.info("Inspecting first input file") + # Get the list of SG keys for the first input file + # I consider it silly to run on a set of mixed file types + firstinput = configFlags.Input.Files[0] + import os, pickle + # Cache details in a pickle file + cachename = "fpcache.{0}.pkl".format(firstinput) + fileinfo = None + if os.path.isfile(cachename): + jetlog.debug("Reading file info from cache \"{0}\"".format(cachename)) + fpcache = open(cachename) + fileinfo = pickle.load(fpcache) + else: + from FilePeeker.FilePeeker import PeekFiles + fileinfo = PeekFiles([firstinput])[firstinput] + fpcache = open(cachename,'w') + pickle.dump(fileinfo,fpcache) + jetlog.debug("Wrote file info to cache \"{0}\"".format(cachename)) + # PeekFiles returns a dict for each input file + filecontents = fileinfo["SGKeys"].split(' ') + + constit = inputdeps[0] + # Truth and track particle inputs are handled later + if constit.basetype not in [xAOD.Type.TruthParticle, xAOD.Type.TrackParticle]: + # Protection against reproduction of existing containers + if constit.inputname in filecontents: + jetlog.debug("Input container {0} for label {1} already in input file.".format(constit.inputname, constit.label)) + else: + jetlog.debug("Preparing Constit Mods for label {0} from {1}".format(constit.label,constit.inputname)) + # May need to generate constituent modifier sequences to + # produce the input collection + import ConstModHelpers + constitcomps = ConstModHelpers.ConstitModCfg(constit.basetype,constit.modifiers) + components.merge( constitcomps ) + + # Schedule the constituent PseudoJetGetterAlg + constitpjcomps, constitpjkey = ConstitPJGCfgAndOutputName( constit ) + components.merge( constitpjcomps ) + + # Track selection and vertex association kind of go hand in hand, though it's not + # completely impossible that one might want one and not the other + if "JetSelectedTracks" in inputdeps or "JetTrackVtxAssoc" in inputdeps: + jetlog.debug("Setting up input track containers and track-vertex association") + from JetRecTools import JetRecToolsConfig + # Jet track selection + jettrackselloose = JetRecToolsConfig.getTrackSelTool() + jettvassoc = JetRecToolsConfig.getTrackVertexAssocTool() + + jettrkprepalg = JetRecConf.JetAlgorithm("jetalg_TrackPrep") + jettrkprepalg.Tools = [ jettrackselloose, jettvassoc ] + components.addEventAlgo( jettrkprepalg ) + + # Resolve the rest of the input dependencies + for dep in inputdeps[1:]: + # Generate prequisite truth particle collections + # There may be more than one. + if dep.startswith("JetInputTruthParticles"): + # Special conditions e.g. "WZ" are set as a suffix preceded by ":" + truthmod = '' + if ":" in dep: + truthmod = dep.split(':')[1] + tpcname = "truthpartcopy"+truthmod + jetlog.debug("Setting up input truth particle container JetInputTruthParticles{0}".format(truthmod)) + + from ParticleJetTools.ParticleJetToolsConfig import getCopyTruthJetParticles + tpc = getCopyTruthJetParticles(truthmod) + + tpcalg = JetRecConf.JetAlgorithm("jetalg_{0}".format(tpcname)) + tpcalg.Tools = [tpc] + components.addEventAlgo(tpcalg) + + # Truth particles specifically for truth labels + elif dep.startswith("TruthLabel"): + truthlabel = dep[10:] + tpcname = "truthpartcopy_"+truthlabel + + jetlog.debug("Setting up input truth particle container TruthLabel{0}".format(truthlabel)) + from ParticleJetTools.ParticleJetToolsConfig import getCopyTruthLabelParticles + tpc = getCopyTruthLabelParticles(truthlabel) + + tpcalg = JetRecConf.JetAlgorithm("jetalg_{0}".format(tpcname)) + tpcalg.Tools = [tpc] + components.addEventAlgo(tpcalg) + + # Calculate the event density for jet area subtraction taking the + # jet constituents as input + # Possibly not needed if constituent suppression has been applied. + # Will want to update the standalone ED python for other uses, + # e.g. isolation or rho from constituents that are not used to + # build a particular jet collection (e.g. neutral PFOs) + # + # Needs protection against reproduction of existing containers + elif dep == "EventDensity": + rhokey = "Kt4"+constit.label+"EventShape" + if rhokey in filecontents: + jetlog.debug("Event density {0} for label {1} already in input file.".format(rhokey, constit.label)) + else: + rhotoolname = "EventDensity_Kt4"+constit.label + + jetlog.debug("Setting up event density calculation Kt4{0}".format(constit.label)) + from EventShapeTools import EventShapeToolsConf + rhotool = EventShapeToolsConf.EventDensityTool(rhotoolname) + rhotool.InputContainer = constitpjkey + rhotool.OutputContainer = rhokey + + eventshapealg = EventShapeToolsConf.EventDensityAthAlg("{0}Alg".format(rhotoolname)) + eventshapealg.EventDensityTool = rhotool + components.addEventAlgo(eventshapealg) + + return components, constitpjkey + +######################################################################## +# Functions for generating PseudoJetGetters, including determining +# the prerequisites for their operation +# +def getConstitPrereqs(basedef): + prereqs = [] + if basedef.basetype==xAOD.Type.TrackParticle: + prereqs = ["input:JetSelectedTracks","input:JetTrackVtxAssoc"] + elif basedef.basetype==xAOD.Type.TruthParticle: + prereqs = ["input:JetInputTruthParticles:"+basedef.inputname[22:]] + return prereqs + +def getGhostPrereqs(ghostdef): + jetlog.verbose("Getting ghost PseudoJets of type {0}".format(ghostdef.inputtype)) + + prereqs = [] + if ghostdef.inputtype=="Track": + prereqs = ["input:JetSelectedTracks","input:JetTrackVtxAssoc"] + elif ghostdef.inputtype.startswith("TruthLabel"): + truthsuffix = ghostdef.inputtype[5:] + prereqs = ["input:TruthLabel"+truthsuffix] + elif ghostdef.inputtype == "Truth": + prereqs = ["input:JetInputTruthParticles"] + return prereqs + +def ConstitPJGCfgAndOutputName(basedef): + ca = ComponentAccumulator() + jetlog.debug("Getting PseudoJetAlg for label {0} from {1}".format(basedef.label,basedef.inputname)) + # + getter = JetRecConf.PseudoJetGetter("pjg_"+basedef.label, + InputContainer = basedef.inputname, + OutputContainer = "PseudoJet"+basedef.label, + Label = basedef.label, + SkipNegativeEnergy=True, + GhostScale=0. + ) + + pjgalg = JetRecConf.PseudoJetAlgorithm( + "pjgalg_"+basedef.label, + PJGetter = getter + ) + ca.addEventAlgo( pjgalg ) + return ca, getter.OutputContainer + +def GhostPJGCfgAndOutputName(ghostdef): + ca = ComponentAccumulator() + label = "Ghost"+ghostdef.inputtype + kwargs = { + "OutputContainer": "PseudoJet"+label, + "Label": label, + "SkipNegativeEnergy": True, + "GhostScale": 1e-40 + } + + pjgclass = JetRecConf.PseudoJetGetter + if ghostdef.inputtype=="MuonSegment": + # Muon segments have a specialised type + pjgclass = JetRecConf.MuonSegmentPseudoJetGetter + kwargs = { + "InputContainer":"MuonSegments", + "OutputContainer":"PseudoJet"+label, + "Label":label, + "Pt":1e-20 + } + elif ghostdef.inputtype=="Track": + kwargs["InputContainer"] = "JetSelectedTracks" + elif ghostdef.inputtype.startswith("TruthLabel"): + truthsuffix = ghostdef.inputtype[5:] + kwargs["InputContainer"] = "TruthLabel"+truthsuffix + elif ghostdef.inputtype == "Truth": + kwargs["InputContainer"] = "JetInputTruthParticles" + else: + raise ValueError("Unhandled ghost type {0} received!".format(ghostdef.inputtype)) + + getter = pjgclass("pjg_"+label, **kwargs) + + pjgalg = JetRecConf.PseudoJetAlgorithm( + "pjgalg_"+label, + PJGetter = getter + ) + ca.addEventAlgo( pjgalg ) + return ca, getter.OutputContainer + +######################################################################## +# Function for configuring the jet algorithm and builders, given the +# set of dependencies +# +def JetAlgorithmCfg(jetname, jetdef, pjs, modlist): + jetlog.debug("Configuring JetAlgorithm \"jetalg_{0}\"".format(jetname)) + components = ComponentAccumulator() + + builder = getJetBuilder() + + finder = getJetFinder(jetname, jetdef) + finder.JetBuilder = builder + + import JetModConfig + mods = [] + for moddef,modspec in modlist: + mod = JetModConfig.getModifier(jetdef,moddef,modspec) + mods.append(mod) + + rectool = getJetRecTool(jetname,finder,pjs,mods) + + jetalg = JetRecConf.JetAlgorithm("jetalg_"+jetname) + jetalg.Tools = [rectool] + components.addEventAlgo(jetalg) + + return components -# ) -# jtm += PseudoJetGetter( -# "gtruthget", -# Label = "GhostTruth", -# InputContainer = jtm.truthpartcopy.OutputName, -# OutputContainer = "PseudoJetGhostTruth", -# GhostScale = 1.e-20, -# SkipNegativeEnergy = True, -# ) - -# # Truth flavor tags. -# for ptype in jetFlags.truthFlavorTags(): -# jtm += PseudoJetGetter( -# "gtruthget_" + ptype, -# InputContainer = "TruthLabel" + ptype, -# Label = "Ghost" + ptype, -# OutputContainer = "PseudoJetGhost" + ptype, -# SkipNegativeEnergy = True, -# GhostScale = 1e-20 -# ) - -# # ParticleJetTools tools may be omitted in analysi releases. -# #ift jtm.haveParticleJetTools: -# # Delta-R truth parton label: truthpartondr. -# jtm += Analysis__JetQuarkLabel( -# "jetquarklabel", -# McEventCollection = "TruthEvents" -# ) -# jtm += Analysis__JetConeLabeling( -# "truthpartondr", -# JetTruthMatchTool = jtm.jetquarklabel -# ) - -# # Parton truth label. -# jtm += Analysis__JetPartonTruthLabel("partontruthlabel") - -# # Cone matching for B, C and tau truth for all but track jets. -# jtm += ParticleJetDeltaRLabelTool( -# "jetdrlabeler", -# LabelName = "HadronConeExclTruthLabelID", -# BLabelName = "ConeExclBHadronsFinal", -# CLabelName = "ConeExclCHadronsFinal", -# TauLabelName = "ConeExclTausFinal", -# BParticleCollection = "TruthLabelBHadronsFinal", -# CParticleCollection = "TruthLabelCHadronsFinal", -# TauParticleCollection = "TruthLabelTausFinal", -# PartPtMin = 5000.0, -# JetPtMin = 0.0, -# DRMax = 0.3, -# MatchMode = "MinDR" -# ) - -# # Cone matching for B, C and tau truth for track jets. -# jtm += ParticleJetDeltaRLabelTool( -# "trackjetdrlabeler", -# LabelName = "HadronConeExclTruthLabelID", -# BLabelName = "ConeExclBHadronsFinal", -# CLabelName = "ConeExclCHadronsFinal", -# TauLabelName = "ConeExclTausFinal", -# BParticleCollection = "TruthLabelBHadronsFinal", -# CParticleCollection = "TruthLabelCHadronsFinal", -# TauParticleCollection = "TruthLabelTausFinal", -# PartPtMin = 5000.0, -# JetPtMin = 4500.0, -# DRMax = 0.3, -# MatchMode = "MinDR" -# ) - -# #-------------------------------------------------------------- -# # Jet builder. -# # The tool manager must have one jet builder. -# #-------------------------------------------------------------- - -# jtm.addJetBuilderWithArea(JetFromPseudojet( -# "jblda", -# Attributes = ["ActiveArea", "ActiveArea4vec"] -# )) - -# jtm.addJetBuilderWithoutArea(JetFromPseudojet( -# "jbldna", -# Attributes = [] -# )) - -# #-------------------------------------------------------------- -# # Non-substructure moment builders. -# #-------------------------------------------------------------- - -# # Quality from clusters. -# jtm += JetCaloQualityTool( -# "caloqual_cluster", -# TimingCuts = [5, 10], -# Calculations = ["LArQuality", "N90Constituents", "FracSamplingMax", "NegativeE", "Timing", "HECQuality", "Centroid", "AverageLArQF", "BchCorrCell"], -# ) - -# # Quality from cells. -# if jtm.haveJetCaloCellQualityTool: -# jtm += JetCaloCellQualityTool( -# "caloqual_cell", -# LArQualityCut = 4000, -# TileQualityCut = 254, -# TimingCuts = [5, 10], -# Calculations = ["LArQuality", "N90Cells", "FracSamplingMax", "NegativeE", "Timing", "HECQuality", "Centroid", "AverageLArQF"] -# ) - -# # Jet width. -# jtm += JetWidthTool("width") - -# # Calo layer energies. -# jtm += JetCaloEnergies("jetens") - -# # Read in missing cell map (needed for the following) -# # commented out : incompatible with trigger : ATR-9696 -# ## if jtm.haveJetRecCalo: -# ## def missingCellFileReader(): -# ## import os -# ## dataPathList = os.environ[ 'DATAPATH' ].split(os.pathsep) -# ## dataPathList.insert(0, os.curdir) -# ## from AthenaCommon.Utils.unixtools import FindFile -# ## RefFileName = FindFile( "JetBadChanCorrTool.root" ,dataPathList, os.R_OK ) -# ## from AthenaCommon.AppMgr import ServiceMgr -# ## if not hasattr(ServiceMgr, 'THistSvc'): -# ## from GaudiSvc.GaudiSvcConf import THistSvc -# ## ServiceMgr += THistSvc() -# ## ServiceMgr.THistSvc.Input += ["JetBadChanCorrTool DATAFILE=\'%s\' OPT=\'READ\'" % RefFileName] -# ## missingCellFileReader.called = True - -# ## missingCellFileReader() - -# ## jtm += MissingCellListTool( -# ## "missingcells", -# ## AddCellList = [], -# ## RemoveCellList = [], -# ## AddBadCells = True, -# ## DeltaRmax = 1.0, -# ## AddCellFromTool = False, -# ## LArMaskBit = 608517, -# ## TileMaskBit = 1, -# ## MissingCellMapName = "MissingCaloCellsMap" -# ## ) - -# ## # Bad channel corrections from cells -# ## if jtm.haveJetBadChanCorrTool: -# ## jtm += JetBadChanCorrTool( -# ## "bchcorrcell", -# ## NBadCellLimit = 10000, -# ## StreamName = "/JetBadChanCorrTool/", -# ## ProfileName = "JetBadChanCorrTool.root", -# ## ProfileTag = "", -# ## UseCone = True, -# ## UseCalibScale = False, -# ## MissingCellMap = "MissingCaloCellsMap", -# ## ForceMissingCellCheck = False, -# ## UseClusters = False, -# ## ) - -# ## # Bad channel corrections from clusters -# ## jtm += JetBadChanCorrTool( -# ## "bchcorrclus", -# ## NBadCellLimit = 0, -# ## StreamName = "", -# ## ProfileName = "", -# ## ProfileTag = "", -# ## UseCone = True, -# ## UseCalibScale = False, -# ## MissingCellMap = "", -# ## ForceMissingCellCheck = False, -# ## UseClusters = True -# ## ) - -# # Jet vertex fraction. -# jtm += JetVertexFractionTool( -# "jvfold", -# VertexContainer = jtm.vertexContainer, -# AssociatedTracks = "GhostTrack", -# TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation, -# JVFName = "JVFOld" -# ) - -# # Jet vertex fraction with selection. -# jtm += JetVertexFractionTool( -# "jvf", -# VertexContainer = jtm.vertexContainer, -# AssociatedTracks = "GhostTrack", -# TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation, -# TrackSelector = jtm.trackselloose, -# JVFName = "JVF" -# ) - -# # Jet vertex tagger. -# jtm += JetVertexTaggerTool( -# "jvt", -# VertexContainer = jtm.vertexContainer, -# TrackParticleContainer = jtm.trackContainer, -# AssociatedTracks = "GhostTrack", -# TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation, -# TrackSelector = jtm.trackselloose, -# JVTName = "Jvt", -# K_JVFCorrScale = 0.01, -# Z0Cut = 3.0, -# PUTrkPtCut = 30000.0 -# ) - -# # Jet track info. -# jtm += JetTrackMomentsTool( -# "trkmoms", -# VertexContainer = jtm.vertexContainer, -# AssociatedTracks = "GhostTrack", -# TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation, -# TrackMinPtCuts = [500, 1000], -# TrackSelector = jtm.trackselloose -# ) - -# # Jet track vector sum info -# jtm += JetTrackSumMomentsTool( -# "trksummoms", -# VertexContainer = jtm.vertexContainer, -# AssociatedTracks = "GhostTrack", -# TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation, -# RequireTrackPV = True, -# TrackSelector = jtm.trackselloose -# ) - -# # Jet cluster info. -# jtm += JetClusterMomentsTool( -# "clsmoms", -# DoClsPt = True, -# DoClsSecondLambda = True, -# DoClsCenterLambda = True, -# DoClsSecondR = True -# ) - -# jtm += JetVoronoiMomentsTool( -# "voromoms", -# AreaXmin= -5., -# AreaXmax= 5., -# AreaYmin= -3.141592, -# AreaYmax= 3.141592 -# ) - -# # Number of associated muon segments. -# #jtm += JetMuonSegmentMomentsTool("muonsegs") - -# # Isolations. -# # Note absence of PseudoJetGetter property means the jet inputs -# # are obtained according to the InputType property of the jet. -# jtm += JetIsolationTool( -# "jetisol", -# IsolationCalculations = ["IsoDelta:2:SumPt", "IsoDelta:3:SumPt"], -# ) -# jtm += JetIsolationTool( -# "run1jetisol", -# IsolationCalculations = ["IsoKR:11:Perp", "IsoKR:11:Par", "IsoFixedCone:6:SumPt",], -# ) - -# # Bad LAr fractions. -# jtm += JetLArHVTool("larhvcorr") - -# # Bad LAr fractions. -# jtm += JetECPSFractionTool( -# "ecpsfrac", -# ECPSFractionThreshold = 0.80 -# ) - -# # Jet origin correction. -# jtm += JetOriginCorrectionTool( -# "jetorigincorr", -# VertexContainer = jtm.vertexContainer, -# OriginCorrectedName = "JetOriginConstitScaleMomentum" -# ) - -# #-------------------------------------------------------------- -# # Substructure moment builders. -# #-------------------------------------------------------------- - -# # Nsubjettiness -# jtm += NSubjettinessTool( -# "nsubjettiness", -# Alpha = 1.0 -# ) - -# # KtDR -# jtm += KtDeltaRTool( -# "ktdr", -# JetRadius = 0.4 -# ) - -# # Kt-splitter -# jtm += KTSplittingScaleTool("ktsplitter") - -# # Angularity. -# jtm += AngularityTool("angularity") - -# # Dipolarity. -# jtm += DipolarityTool("dipolarity", SubJetRadius = 0.3) - -# # Planar flow. -# jtm += PlanarFlowTool("planarflow") - -# # Kt mass drop. -# jtm += KtMassDropTool("ktmassdrop") - -# # Energy correlations. -# jtm += EnergyCorrelatorTool("encorr", Beta = 1.0) - -# # COM shapes. -# jtm += CenterOfMassShapesTool("comshapes") - -# # Jet pull -# jtm += JetPullTool( -# "pull", -# UseEtaInsteadOfY = False, -# IncludeTensorMoments = True -# ) - -# # Jet charge -# jtm += JetChargeTool("charge", K=1.0) - -# # Shower deconstruction. -# if jtm.haveShowerDeconstructionTool: -# jtm += ShowerDeconstructionTool("showerdec") - -# # Remove constituents (useful for truth jets in evgen pile-up file) -# jtm += JetConstitRemover("removeconstit") - -# # Sort jets by pT -# # May be deisred after calibration or grooming. -# jtm += JetSorter("jetsorter") - -# # LocalWords: JetRecStandardTools + +######################################################################## +# Function for generating a jet builder, i.e. converter from +# fastjet EDM to xAOD EDM +# +def getJetBuilder(doArea=True): + # Do we have any reasons for not using the area one? + # Maybe CPU reduction if we don't need areas for calibration + builder = JetRecConf.JetFromPseudojet("jetbuild") + if doArea: + builder.Attributes = ["ActiveArea","ActiveAreaFourVector"] + return builder + +######################################################################## +# Function for generating a jet finder, i.e. interface to fastjet +# +def getJetFinder(jetname, jetdef): + finder = JetRecConf.JetFinder("jetfind_"+jetname, + JetAlgorithm = jetdef.algorithm, + JetRadius = jetdef.radius, + PtMin = jetdef.ptmin, + GhostArea = 0.01, + RandomOption = 1, + ) + return finder + +######################################################################## +# Function for generating a JetRecTool +# +def getJetRecTool(jetname, finder, pjs, mods): + # Create the JetRecTool and pass the inputs + jetrec = JetRecConf.JetRecTool("jetrec_"+jetname, + OutputContainer = jetname, + InputPseudoJets = pjs, + JetFinder = finder, + JetModifiers = mods + ) + return jetrec diff --git a/Reconstruction/Jet/JetRecConfig/python/JetRecFlags.py b/Reconstruction/Jet/JetRecConfig/python/JetRecFlags.py deleted file mode 100644 index 00e00d5b8b643db47c75f5487a6ffd672cc57940..0000000000000000000000000000000000000000 --- a/Reconstruction/Jet/JetRecConfig/python/JetRecFlags.py +++ /dev/null @@ -1,240 +0,0 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration - -# JetRecFlags.py -# -# David Adams -# Updated March 2015 -# -# These are flags for controlling the behavior of jet reconstruction -# in RecExCommon (which includes JetRec/JetRec_jobOptions.py) and in -# the example jet reconstruction options RunJetRec.py. -# -# Typical usage is -# from JetRec.JetRecFlags import jetFlags -# if jetFlags.UseTruth: -# doSomethingWithTruth() -# -# Properties: -# Enabled - Skip all jet reco if false (drop whe rec.doJets is added) -# debug - JetRecTools are run a DEBUG level -# useTruth - Truth jets and association are enabled (for MC) -# useTopo - Topocluster jets are enabled -# useTracks - Track jets and association are enabled -# useVertices - Toggles whether PFlow jet reconstruction makes use of vertex information. -# useMuonSegmentss - Muon segemnt association is enabled -# usePFlow - PFlow jets and associations are enabled -# useInDetTrackSelection - The inner detector track selection -# tool is used. This requires track propagator exist. -# jetAODList - The list of jet collections to be written out -# And much more--see below. - -from AthenaCommon.JobProperties import JobProperty, JobPropertyContainer -from AthenaCommon.JobProperties import jobproperties - -class JetRecFlags(JobPropertyContainer): - """ The Jet making flag property container - """ - pass - -class Enabled(JobProperty): - """ If false will prevent run of any Jet Alg - """ - statusOn = True - allowedTypes = ['bool'] # type - StoredValue = True # default value - -class debug(JobProperty): - """ If > 0, debug (or higher) messages are written by jet tools. - """ - statusOn = True - allowedTypes = ['int'] # type - StoredValue = 0 # default value - -class useTruth(JobProperty): - """ If true, truth is present and used in jet reconstruction. - The status is set on in JetRecStandardToolManager. - """ - statusOn = False - allowedTypes = ['bool'] # type - StoredValue = True # default value - -class truthFlavorTags(JobProperty): - """ List of flavor tags for truth tagging jets. - """ - statusOn = True - allowedTypes = ['array'] # type - StoredValue = ["BHadronsInitial", "BHadronsFinal", "BQuarksFinal", - "CHadronsInitial", "CHadronsFinal", "CQuarksFinal", - "TausFinal", - "WBosons", "ZBosons", "HBosons", "TQuarksFinal", - "Partons", - ] - -class useTopo(JobProperty): - """ If true, topoclusters are present and used in jet reconstruction. - The status is set on in JetRecStandardToolManager. - """ - statusOn = False - allowedTypes = ['bool'] # type - StoredValue = True # default value - -class useTracks(JobProperty): - """ If true, tracks and vertices are present and used in jet reconstruction. - The status is set on in JetRecStandardToolManager. - """ - statusOn = False - allowedTypes = ['bool'] # type - StoredValue = True # default value - -class useVertices(JobProperty): - """ If true, vertices are present and used in pflow jet reconstruction. - """ - statusOn = False - allowedTypes = ['bool'] # type - StoredValue = True # default value - -class useMuonSegments(JobProperty): - """ If true, muon segments are present and used in jet reconstruction. - The status is set on in JetRecStandardToolManager. - """ - statusOn = False - allowedTypes = ['bool'] # type - StoredValue = True # default value - -class usePFlow(JobProperty): - """ If true, pflow objects are present and used in jet reconstruction. - The status is set in JetRecStandardToolManager. - """ - statusOn = True - allowedTypes = ['bool'] # type - StoredValue = True # default value - -class eventShapeTools(JobProperty): - """ List of event shape tools that should be called to calculate rho. - Allowed values are "emtopo", "lctopo", "emorig", "lcorig", "empflow", "emcpflow", "lcpflow". - """ - statusOn = True - allowedTypes = ['None', 'list'] # type - StoredValue = None # default value - -class useInDetTrackSelection(JobProperty): - """ If true, the InDet track selection tool is used. - """ - statusOn = True - allowedTypes = ['bool'] # type - StoredValue = False # default value - -class useCells(JobProperty): - """ If true, calo cells are accesible - """ - statusOn = True - allowedTypes = ['bool'] # type - StoredValue = False # default value - -class useCaloQualityTool(JobProperty): - """ If true, the (slow) CaloQuality tool is used - """ - statusOn = True - allowedTypes = ['bool'] # type - StoredValue = True # default value - -class useBTagging(JobProperty): - """ If true, then btagging is done when requested - """ - statusOn = True - allowedTypes = ['bool'] # type - StoredValue = False # default value - -class skipTools(JobProperty): - """ List of modifier tools to exclude - """ - statusOn = True - allowedTypes = ['list'] # type - StoredValue = [] # default value - -class additionalTopoGetters(JobProperty): - """ List of PseudoJet getters to add for Topo jets. - E.g. to tag jets with track jets - """ - statusOn = True - allowedTypes = ['list'] # type - StoredValue = [] # default value - -class defaultCalibOpt(JobProperty): - """ Calibration applied to topo jets during jet building. See JetRecCalibrationFinder. - """ - statusOn = True - allowedTypes = ['str'] # type - StoredValue = "" # default value - -class containerNamePrefix(JobProperty): - """ Prefix for jet collection names - """ - statusOn = True - allowedTypes = ['str'] # type - StoredValue = "" # default value - -class separateJetAlgs(JobProperty): - """ If true, find and build jet containers in separate alg. Used for debugging. - """ - statusOn = True - allowedTypes = ['bool'] # type - StoredValue = False # default value - -class timeJetToolRunner(JobProperty): - """ Timing flag for JetToolRunner: 0 for no timing, 1 for some, 2 for detailed - """ - statusOn = True - allowedTypes = ['int'] # type - StoredValue = 0 # default value - -class timeJetRecTool(JobProperty): - """ Timing flag for JetRecTool: 0 for no timing, 1 for some, 2 for detailed - """ - statusOn = True - allowedTypes = ['int'] # type - StoredValue = 0 # default value - -class jetAODList(JobProperty): - """ The collections to be saved in (x)AOD files - """ - statusOn = True - allowedTypes = ['list'] - StoredValue = [] - -class useTrackVertexTool(JobProperty): - """ Toggles whether to use track-vertex tool (only known client is currently pflow jet finding) - """ - statusOn = True - allowedTypes = ['bool'] - StoredValue = False - - - -jobproperties.add_Container(JetRecFlags) - -jobproperties.JetRecFlags.add_JobProperty(Enabled) -jobproperties.JetRecFlags.add_JobProperty(debug) -jobproperties.JetRecFlags.add_JobProperty(useTruth) -jobproperties.JetRecFlags.add_JobProperty(truthFlavorTags) -jobproperties.JetRecFlags.add_JobProperty(useTopo) -jobproperties.JetRecFlags.add_JobProperty(useTracks) -jobproperties.JetRecFlags.add_JobProperty(useVertices) -jobproperties.JetRecFlags.add_JobProperty(useInDetTrackSelection) -jobproperties.JetRecFlags.add_JobProperty(useMuonSegments) -jobproperties.JetRecFlags.add_JobProperty(usePFlow) -jobproperties.JetRecFlags.add_JobProperty(eventShapeTools) -jobproperties.JetRecFlags.add_JobProperty(jetAODList) -jobproperties.JetRecFlags.add_JobProperty(useCells) -jobproperties.JetRecFlags.add_JobProperty(useCaloQualityTool) -jobproperties.JetRecFlags.add_JobProperty(useBTagging) -jobproperties.JetRecFlags.add_JobProperty(skipTools) -jobproperties.JetRecFlags.add_JobProperty(additionalTopoGetters) -jobproperties.JetRecFlags.add_JobProperty(defaultCalibOpt) -jobproperties.JetRecFlags.add_JobProperty(containerNamePrefix) -jobproperties.JetRecFlags.add_JobProperty(separateJetAlgs) -jobproperties.JetRecFlags.add_JobProperty(timeJetToolRunner) -jobproperties.JetRecFlags.add_JobProperty(timeJetRecTool) -jobproperties.JetRecFlags.add_JobProperty(useTrackVertexTool) - -jetFlags = jobproperties.JetRecFlags diff --git a/Reconstruction/Jet/JetRecConfig/python/JetRecStandard.py b/Reconstruction/Jet/JetRecConfig/python/JetRecStandard.py deleted file mode 100644 index aa958567624f384041119d831bbeeb90d3ce3262..0000000000000000000000000000000000000000 --- a/Reconstruction/Jet/JetRecConfig/python/JetRecStandard.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration - -# JetRecStandard.py -# -# David Adams -# October 2014 -# Updated March 2015 -# -# Wrapper for JetRecStandardToolManager.py that first uses RecExCommon to set flags. -# High-level RecExCommon scripts should use this in place or JetRecStandardToolManager. -# -# Call with -# from JetRec.JetRecStandard import jtm -# -# Jet flags should be set before making this call. Those for truth, clusters, tracks -# and muon segments will be set here iff they are not already set. - -from AthenaCommon import Logging -jetlog = Logging.logging.getLogger('JetRec_jobOptions') - -myname = "JetRecStandard: " -jetlog.info( myname + "Begin.") - -from RecExConfig.RecFlags import rec -from InDetRecExample.InDetJobProperties import InDetFlags -from JetRecFlags import jetFlags - -# Function to display flag value and status. -def sflagstat(flag): - return str(flag()) + " (status=" + str(flag.statusOn) + ")" - -# Import the jet reconstruction control flags. -from JetRecFlags import jetFlags -from RecExConfig.ObjKeyStore import cfgKeyStore - -# Skip truth if rec says it is absent. -# No action if someone has already set the flag. -jetlog.info( myname + "Initial useTruth: " + sflagstat(jetFlags.useTruth)) -jetlog.info( myname + " rec.doTruth: " + str(rec.doTruth()) ) -if not jetFlags.useTruth.statusOn: - jetFlags.useTruth = rec.doTruth() -jetlog.info( myname + " Final useTruth: " + sflagstat(jetFlags.useTruth)) - -# Skip use of topoclusters if not built -# No action if someone has already set the flag. -jetlog.info( myname + "Initial use topoclusters: " + str(jetFlags.useTopo())) -if not jetFlags.useTopo.statusOn: - jetFlags.useTopo = rec.doCalo() -jetlog.info( myname + " Final use topoclusters: " + str(jetFlags.useTopo())) - -# Skip tracks if tracks or vertices are not present in the job. -# No action if someone has already set the flag. -haveTracks = cfgKeyStore.isInTransient('xAOD::TrackParticleContainer','InDetTrackParticles') -haveVertices = cfgKeyStore.isInTransient("xAOD::VertexContainer","PrimaryVertices") -recTracks = rec.doInDet() -recVertices = bool(InDetFlags.doVertexFinding) and (recTracks or haveTracks) -jetlog.info( myname + "Initial useTracks: " + sflagstat(jetFlags.useTracks) ) -jetlog.info( myname + " rec doInDet: " + str(recTracks) ) -jetlog.info( myname + " doVertexFinding: " + str(recVertices) ) -jetlog.info( myname + " have tracks: " + str(haveTracks) ) -jetlog.info( myname + " have vertices: " + str(haveVertices) ) -if not jetFlags.useTracks.statusOn: - jetFlags.useTracks = (recTracks or haveTracks) and (recVertices or haveVertices) -jetlog.info( myname + " Final useTracks: " + sflagstat(jetFlags.useTracks) ) - -if not jetFlags.useVertices.statusOn: - jetFlags.useVertices = (recVertices or haveVertices) -jetlog.info( myname + " useVertices: " + sflagstat(jetFlags.useVertices) ) - -# Disable usage of vertices in pflow jets, if we are using cosmic data. -from AthenaCommon.BeamFlags import jobproperties -if jobproperties.Beam.beamType == 'cosmics': - jetFlags.useVertices = False - -# Skip pflow if we are not using tracks. -jetlog.info( myname + "Initial usePFlow: " + sflagstat(jetFlags.usePFlow) ) -if not jetFlags.usePFlow.statusOn: - jetFlags.usePFlow = jetFlags.useTracks() -jetlog.info( myname + "Final usePFlow: " + sflagstat(jetFlags.usePFlow) ) - -# Skip use of muon segments if not built. -# No action if someone has already set the flag. -jetlog.info( myname + "Initial use muon segments: " + sflagstat(jetFlags.useMuonSegments) ) -if not jetFlags.useMuonSegments.statusOn: - jetFlags.useMuonSegments = rec.doMuon() and rec.doMuonCombined() -jetlog.info( myname + " Final use muon segments: " + sflagstat(jetFlags.useMuonSegments) ) - -# Use rec flag to control BTagging. -# No. Disable this unit we get support from Btagging to do this. -# No action if someone has already set the flag. -jetlog.info( myname + "Initial use Btagging: " + str(jetFlags.useBTagging) ) -jetlog.info( myname + " rec do BTagging: " + str(rec.doBTagging()) ) -if not jetFlags.useBTagging.statusOn: - #jetFlags.useBTagging = rec.doBTagging() - jetFlags.useBTagging = False -jetlog.info( myname + " Final use Btagging: " + str(jetFlags.useBTagging) ) - -# The following can be used to exclude tools from reconstruction. -if 0: - jetFlags.skipTools = ["comshapes"] -jetlog.info( "Skipped tools: %s", jetFlags.skipTools()) - -from RecExConfig.RecAlgsFlags import recAlgs -if not recAlgs.doEFlow(): - jetFlags.usePFlow = False - -# Set the list of rho calculations. -# If caller has set jetFlags.eventShapeTools(), then we use those values. -if jetFlags.eventShapeTools() == None: - jetFlags.eventShapeTools = [] - if jetFlags.useTopo(): - jetFlags.eventShapeTools += ['emtopo', 'lctopo'] - if jetFlags.usePFlow(): - jetFlags.eventShapeTools += ['empflow'] - -# Import the jet tool manager. -from JetRecStandardToolManager import jtm - -jetlog.info( myname + "End." ) diff --git a/Reconstruction/Jet/JetRecConfig/python/JetRecStandardToolManager.py b/Reconstruction/Jet/JetRecConfig/python/JetRecStandardToolManager.py deleted file mode 100644 index c35a8e3abe9af773840f13a888faeb5d9ab379a2..0000000000000000000000000000000000000000 --- a/Reconstruction/Jet/JetRecConfig/python/JetRecStandardToolManager.py +++ /dev/null @@ -1,311 +0,0 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration - -# JetRecStandardToolManager.py -# -# David Adams -# March 2014 -# -# Constructs an instance jtm of the JetToolManager with -# standard definitions for jet tools. -# -# Usage: -# from JetRec.JetRecStandardToolManager import jtm -# jtm.addJetFinder("AntiKt4EMTopoJets", "AntiKt", 0.4, "em", "emtopo_ungroomed") -# -from AthenaCommon import Logging -jetlog = Logging.logging.getLogger('JetRec_jobOptions') - -import copy - -myname = "JetRecStandardToolManager.py: " - -jetlog.info( myname + "Defining standard tools" ) - -######################################################### -# Set and lock flags. -######################################################### - -from JetRecFlags import jetFlags - -# Set status on for flags that are initialized with status off. -jetFlags.useTruth.set_On() -jetFlags.useTopo.set_On() -jetFlags.useTracks.set_On() -jetFlags.usePFlow.set_On() -jetFlags.useMuonSegments.set_On() -jetFlags.useBTagging.set_On() - -# Lock all the flags used here so that later attempts to change -# the value will fail with an error message. -jetFlags.useTruth.lock() -jetFlags.useTopo.lock() -jetFlags.useTracks.lock() -jetFlags.useMuonSegments.lock() -jetFlags.useBTagging.lock() -jetFlags.useCaloQualityTool.lock() -jetFlags.additionalTopoGetters.lock() -jetFlags.truthFlavorTags.lock() -jetFlags.skipTools.lock() - -# Display all flags used here. -jetlog.info( myname + "jetFlags.useTruth: " + str(jetFlags.useTruth()) ) -jetlog.info( myname + "jetFlags.useTopo: " + str(jetFlags.useTopo()) ) -jetlog.info( myname + "jetFlags.useTracks: " + str(jetFlags.useTracks()) ) -jetlog.info( myname + "jetFlags.useMuonSegments: " + str(jetFlags.useMuonSegments()) ) -jetlog.info( myname + "jetFlags.useBTagging: " + str(jetFlags.useBTagging()) ) -jetlog.info( myname + "jetFlags.useCaloQualityTool: " + str(jetFlags.useCaloQualityTool()) ) -jetlog.info( myname + "jetFlags.additionalTopoGetters: " + str(jetFlags.additionalTopoGetters()) ) -jetlog.info( myname + "jetFlags.truthFlavorTags: " + str(jetFlags.truthFlavorTags()) ) -jetlog.info( myname + "jetFlags.skipTools: " + str(jetFlags.skipTools()) ) - -######################################################### -# Create standard tool manager. -######################################################### - -# Import the jet tool manager. -from JetToolSupport import JetToolManager - -# Global jet tool manager with standard definitions -jtm = JetToolManager() - -# Pt thresholds in MeV -jtm.ptminFinder = 2000 -jtm.ptminFilter = 0 - -# Add standard tool definitions to the tool manager. -import JetRecStandardTools - -if 0: - jetlog.info( "First call to JetRecStandardToolManager.py:" ) - from traceback import format_exc - jetlog.info( format_exc() ) - jetlog.info( "Exception" ) - raise Exception - from traceback import print_stack - print_stack() - -######################################################### -# Getters -######################################################### - -# Pseudojet getters -empfgetters = [jtm.empflowget] -emcpfgetters = [jtm.emcpflowget] -lcpfgetters = [jtm.lcpflowget] - -trackgetters = [jtm.trackget] -# Add track ghosts -emgetters = [jtm.emget] -lcgetters = [jtm.lcget] -if jetFlags.useTracks(): - emgetters = [jtm.emoriginget] - lcgetters = [jtm.lcoriginget] - emgetters += [jtm.gtrackget] - lcgetters += [jtm.gtrackget] - empfgetters += [jtm.gtrackget] - emcpfgetters += [jtm.gtrackget] - lcpfgetters += [jtm.gtrackget] - -if jetFlags.useMuonSegments(): - emgetters += [jtm.gmusegget] - lcgetters += [jtm.gmusegget] - empfgetters += [jtm.gmusegget] - emcpfgetters += [jtm.gmusegget] - lcpfgetters += [jtm.gmusegget] -# Add jet ghosts. -if 1: - for gettername in jetFlags.additionalTopoGetters(): - getter = jtm[gettername] - emgetters += [getter] - lcgetters += [getter] -# Add truth getter and truth ghosts. -if jetFlags.useTruth(): - truthgetters = [jtm.truthget] - truthwzgetters = [jtm.truthwzget] - trackgetters += [jtm.gtruthget] - emgetters += [jtm.gtruthget] - lcgetters += [jtm.gtruthget] - empfgetters += [jtm.gtruthget] - emcpfgetters += [jtm.gtruthget] - lcpfgetters += [jtm.gtruthget] - # Add truth cone matching and truth flavor ghosts. - flavorgetters = [] - for ptype in jetFlags.truthFlavorTags(): - flavorgetters += [getattr(jtm, "gtruthget_" + ptype)] - emgetters += flavorgetters - lcgetters += flavorgetters - truthgetters += flavorgetters - truthwzgetters += flavorgetters - trackgetters += flavorgetters - empfgetters += flavorgetters - emcpfgetters += flavorgetters - lcpfgetters += flavorgetters -# Add track jet ghosts. -if jetFlags.useTracks(): - trackjetgetters = [] - trackjetgetters += [jtm.gakt2trackget] -# trackjetgetters += [jtm.gakt3trackget] - trackjetgetters += [jtm.gakt4trackget] - emgetters += trackjetgetters - lcgetters += trackjetgetters - empfgetters += trackjetgetters - emcpfgetters += trackjetgetters - lcpfgetters += trackjetgetters - - -# Add getter lists to jtm indexed by input type name. -jtm.gettersMap["emtopo"] = list(emgetters) -jtm.gettersMap["lctopo"] = list(lcgetters) -jtm.gettersMap["empflow"] = list(empfgetters) -jtm.gettersMap["emcpflow"] = list(emcpfgetters) -jtm.gettersMap["lcpflow"] = list(lcpfgetters) -jtm.gettersMap["track"] = list(trackgetters) -jtm.gettersMap["ztrack"] = list(trackgetters) -jtm.gettersMap["pv0track"] = list(trackgetters) -if jetFlags.useTruth(): - jtm.gettersMap["truth"] = list(truthgetters) - jtm.gettersMap["truthwz"] = list(truthwzgetters) - -######################################################### -# Modifiers -######################################################### - -# Modifiers for ungroomed jets from all input types. -common_ungroomed_modifiers = [ - jtm.width, -] - -# Add parton truth labels and truth jet modifiers. -if jetFlags.useTruth(): - if jtm.haveParticleJetTools: - common_ungroomed_modifiers += [jtm.partontruthlabel] - common_ungroomed_modifiers += [jtm.truthpartondr] - - # Modifiers for truth jets. - truth_ungroomed_modifiers = list(common_ungroomed_modifiers) - if jtm.haveParticleJetTools: - truth_ungroomed_modifiers += [jtm.jetdrlabeler] - -# Modifiers for track jets. -track_ungroomed_modifiers = list(common_ungroomed_modifiers) -if jetFlags.useTruth() and jtm.haveParticleJetTools: - track_ungroomed_modifiers += [jtm.trackjetdrlabeler] - -# Modifiers for topo (and pflow) jets. -ungroomed_modifiers = [jtm.jetens, "calib", jtm.jetsorter] # calibration first. turn off with calibopt -ungroomed_modifiers += ["jetfilter"] -ungroomed_modifiers += common_ungroomed_modifiers -ungroomed_modifiers += [jtm.larhvcorr] -ungroomed_modifiers += [jtm.ecpsfrac] -if jetFlags.useCaloQualityTool(): - ungroomed_modifiers += [jtm.caloqual_cluster] -if jetFlags.useTracks(): - ungroomed_modifiers += [jtm.jvf] - ungroomed_modifiers += [jtm.jvt] - ungroomed_modifiers += [jtm.trkmoms] - ungroomed_modifiers += [jtm.trksummoms] - ungroomed_modifiers += [jtm.charge] - ungroomed_modifiers += ["trackassoc"] - ungroomed_modifiers += [jtm.jetorigin_setpv] -if jetFlags.useTruth(): - ungroomed_modifiers += ["truthassoc"] - if jtm.haveParticleJetTools: - ungroomed_modifiers += [jtm.jetdrlabeler] - -# Modifiers for groomed jets. -groomed_modifiers = [ jtm.jetsorter, - jtm.jetisol, - jtm.ktdr, - jtm.nsubjettiness, - jtm.ktsplitter, - jtm.angularity, - jtm.dipolarity, - jtm.planarflow, - jtm.ktmassdrop, - jtm.encorr, - jtm.comshapes - ] - -# Function to filter out skipped tools. -def filterout(skiptoolnames, tools): - outtools = [] - remtoolnames = [] - nrem = 0 - for tool in tools: - keep = True - for toolname in skiptoolnames: - skiptool = jtm[toolname] - same = tool == skiptool - if same: - keep = False - remtoolnames += [toolname] - if keep: - outtools += [tool] - jetlog.info( myname + "Removed tools: " + str(remtoolnames) ) - return outtools - -# Modifiers for pflow jets. -# Same as topo jets. -# 28may2015 - ecpsfrac is not yet working for pflow in xAOD. -pflow_ungroomed_modifiers = [] -pflow_ungroomed_modifiers += [jtm.constitfourmom_pflow] -pflow_ungroomed_modifiers += filterout(["ecpsfrac"], ungroomed_modifiers) - -# Here add tools to be run for topo jets and NOT for pflow. - -# Cluster moments. -ungroomed_modifiers += [jtm.clsmoms] - -# Voronoi moments. -#ungroomed_modifiers += [jtm.voromoms] - -# Add Btagging. -btags = ["btag"] -if jetFlags.useBTagging(): - ungroomed_modifiers += btags - -# EM only modifiers here -emtopo_ungroomed_modifiers = [] -emtopo_ungroomed_modifiers += [jtm.constitfourmom_emtopo] -emtopo_ungroomed_modifiers += ungroomed_modifiers - -# LC-only modifiers here -lctopo_ungroomed_modifiers = [] -lctopo_ungroomed_modifiers += [jtm.constitfourmom_lctopo] -lctopo_ungroomed_modifiers += ungroomed_modifiers - -# Filter out skipped tools. -if len(jetFlags.skipTools()): - jetlog.info( myname + "Tools to be skipped: " + str(jetFlags.skipTools()) ) - ungroomed_modifiers = filterout(jetFlags.skipTools(), ungroomed_modifiers) - if jetFlags.useTruth(): - truth_ungroomed_modifiers = filterout(jetFlags.skipTools(), truth_ungroomed_modifiers) - track_ungroomed_modifiers = filterout(jetFlags.skipTools(), track_ungroomed_modifiers) - groomed_modifiers = filterout(jetFlags.skipTools(), groomed_modifiers) - pflow_ungroomed_modifiers = filterout(jetFlags.skipTools(), pflow_ungroomed_modifiers) - emtopo_ungroomed_modifiers = filterout(jetFlags.skipTools(), emtopo_ungroomed_modifiers) - lctopo_ungroomed_modifiers = filterout(jetFlags.skipTools(), lctopo_ungroomed_modifiers) - -# Add modifier lists to jtm indexed by modifier type name. -jtm.modifiersMap["none"] = [] -jtm.modifiersMap["ungroomed"] = list(ungroomed_modifiers) - -jtm.modifiersMap["emtopo_ungroomed"] = list(emtopo_ungroomed_modifiers) -jtm.modifiersMap["lctopo_ungroomed"] = list(lctopo_ungroomed_modifiers) -jtm.modifiersMap["pflow_ungroomed"] = list(pflow_ungroomed_modifiers) - -if jetFlags.useTruth(): - jtm.modifiersMap["truth_ungroomed"] = list(truth_ungroomed_modifiers) -jtm.modifiersMap["track_ungroomed"] = list(track_ungroomed_modifiers) -jtm.modifiersMap["groomed"] = list(groomed_modifiers) - -# Also index modifier type names by input type name. -# These are used when the modifier list is omitted. -jtm.modifiersMap["track"] = list(track_ungroomed_modifiers) -jtm.modifiersMap["ztrack"] = list(track_ungroomed_modifiers) -jtm.modifiersMap["pv0track"] = list(track_ungroomed_modifiers) -if jetFlags.useTruth(): - jtm.modifiersMap["truth"] = list(truth_ungroomed_modifiers) - jtm.modifiersMap["truthwz"] = list(truth_ungroomed_modifiers) - -jetlog.info( myname + "End." ) diff --git a/Reconstruction/Jet/JetRecConfig/python/JetRecStandardTools.py b/Reconstruction/Jet/JetRecConfig/python/JetRecStandardTools.py deleted file mode 100644 index 73fc970779c913789e6c56b5ea5bf42eba0aa680..0000000000000000000000000000000000000000 --- a/Reconstruction/Jet/JetRecConfig/python/JetRecStandardTools.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration - -# JetRecStandardTools.py -# -# David Adams -# March 2014 -# -# Define the low-level tools used in jet reconstruction. -# -# Tools are configured and put in the global jet tool manager so -# they can be accessed when configuring JetRec tools. -# -# Execute this file to add the definitions to -# JetRecStandardToolManager.jtm, e.g. -# import JetRecStandardTools - -# Import the jet flags. -from JetRecFlags import jetFlags - -from JetRecStandardToolManager import jtm - -if not "UseTriggerStore " in locals(): - UseTriggerStore = False - -# get levels defined VERBOSE=1 etc. -from GaudiKernel.Constants import * - -try: - from JetRecCalo.JetRecCaloConf import MissingCellListTool - jtm.haveJetRecCalo = True -except ImportError: - jtm.haveJetRecCalo = False - -# Import configurations from jet packages -import JetMomentTools.DefaultTools -import JetSubStructureMomentTools.DefaultTools -import ParticleJetTools.DefaultTools -import JetRec.DefaultTools -import PFlowUtils.DefaultTools -import JetRecTools.DefaultTools - -JetMomentTools.DefaultTools.declareDefaultTools() -JetSubStructureMomentTools.DefaultTools.declareDefaultTools() -ParticleJetTools.DefaultTools.declareDefaultTools() -JetRec.DefaultTools.declareDefaultTools() -PFlowUtils.DefaultTools.declareDefaultTools() -JetRecTools.DefaultTools.declareDefaultTools() diff --git a/Reconstruction/Jet/JetRecConfig/python/JetRecUtils.py b/Reconstruction/Jet/JetRecConfig/python/JetRecUtils.py deleted file mode 100644 index 74ae8129b00821792d7bde861d619f27e0d244d2..0000000000000000000000000000000000000000 --- a/Reconstruction/Jet/JetRecConfig/python/JetRecUtils.py +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration - -from AthenaCommon.AppMgr import ToolSvc - -from AthenaCommon import Logging -jetlog = Logging.logging.getLogger('JetRec_jobOptions') - -def retrieveAODList(): - from JetRecFlags import jetFlags - from RecExConfig.RecFlags import rec - - if rec.doESD(): - return jetFlags.jetAODList() - # then we are merging or doing a AOD ? - # We can not simply copy what we have from input since some - # jobs starts from empty files. See ATEAM-191. - # We hard code the list here while waiting for a more robust solution - l = [ - # event shape objects - 'xAOD::EventShape#Kt4EMPFlowEventShape', 'xAOD::EventShapeAuxInfo#Kt4EMPFlowEventShapeAux.', - 'xAOD::EventShape#Kt4EMTopoOriginEventShape', 'xAOD::EventShapeAuxInfo#Kt4EMTopoOriginEventShapeAux.', - 'xAOD::EventShape#Kt4LCTopoOriginEventShape', 'xAOD::EventShapeAuxInfo#Kt4LCTopoOriginEventShapeAux.', - 'xAOD::EventShape#NeutralParticleFlowIsoCentralEventShape', 'xAOD::EventShapeAuxInfo#NeutralParticleFlowIsoCentralEventShapeAux.', - 'xAOD::EventShape#NeutralParticleFlowIsoForwardEventShape', 'xAOD::EventShapeAuxInfo#NeutralParticleFlowIsoForwardEventShapeAux.', - 'xAOD::EventShape#ParticleFlowIsoCentralEventShape', 'xAOD::EventShapeAuxInfo#ParticleFlowIsoCentralEventShapeAux.', - 'xAOD::EventShape#ParticleFlowIsoForwardEventShape', 'xAOD::EventShapeAuxInfo#ParticleFlowIsoForwardEventShapeAux.', - 'xAOD::EventShape#TopoClusterIsoCentralEventShape', 'xAOD::EventShapeAuxInfo#TopoClusterIsoCentralEventShapeAux.', - 'xAOD::EventShape#TopoClusterIsoForwardEventShape', 'xAOD::EventShapeAuxInfo#TopoClusterIsoForwardEventShapeAux.', - - 'xAOD::JetContainer#AntiKt10LCTopoJets', 'xAOD::JetAuxContainer#AntiKt10LCTopoJetsAux.', - 'xAOD::JetContainer#AntiKt2PV0TrackJets', 'xAOD::JetAuxContainer#AntiKt2PV0TrackJetsAux.', - #'xAOD::JetContainer#AntiKt3PV0TrackJets', 'xAOD::JetAuxContainer#AntiKt3PV0TrackJetsAux.', - 'xAOD::JetContainer#AntiKt4EMPFlowJets', 'xAOD::JetAuxContainer#AntiKt4EMPFlowJetsAux.', - 'xAOD::JetContainer#AntiKt4EMTopoJets', 'xAOD::JetAuxContainer#AntiKt4EMTopoJetsAux.', - 'xAOD::JetContainer#AntiKt4LCTopoJets', 'xAOD::JetAuxContainer#AntiKt4LCTopoJetsAux.', - 'xAOD::JetContainer#AntiKt4PV0TrackJets', 'xAOD::JetAuxContainer#AntiKt4PV0TrackJetsAux.', - #'xAOD::JetContainer#CamKt12LCTopoJets', 'xAOD::JetAuxContainer#CamKt12LCTopoJetsAux.', - - 'xAOD::CaloClusterContainer#EMOriginTopoClusters', 'xAOD::ShallowAuxContainer#EMOriginTopoClustersAux.', - 'xAOD::CaloClusterContainer#LCOriginTopoClusters' , 'xAOD::ShallowAuxContainer#LCOriginTopoClustersAux.', - ] - - if rec.doTruth(): - l += [ - 'xAOD::JetContainer#AntiKt10TruthJets', 'xAOD::JetAuxContainer#AntiKt10TruthJetsAux.', - 'xAOD::JetContainer#AntiKt10TruthWZJets', 'xAOD::JetAuxContainer#AntiKt10TruthWZJetsAux.', - 'xAOD::JetContainer#AntiKt4TruthJets', 'xAOD::JetAuxContainer#AntiKt4TruthJetsAux.', - 'xAOD::JetContainer#AntiKt4TruthWZJets', 'xAOD::JetAuxContainer#AntiKt4TruthWZJetsAux.', - 'xAOD::JetContainer#CamKt12TruthJets', 'xAOD::JetAuxContainer#CamKt12TruthJetsAux.', - 'xAOD::JetContainer#CamKt12TruthWZJets', 'xAOD::JetAuxContainer#CamKt12TruthWZJetsAux.', - ] - - return l - ## inputcontent = objKeyStore['inputFile'].list() - ## typeToSave = [ 'xAOD::JetContainer', 'xAOD::JetAuxContainer', 'xAOD::JetTrigAuxContainer' , 'xAOD::EventShape', 'xAOD::EventShapeAuxInfo' ] - - ## def saveThisObject(o): - ## # we must not write out any HLT jet containers - writing of those is controlled from trigger software, not offline jet software - ## if "HLT_" in o: - ## return False - ## # return True if o is of a desired type - ## return any( o.startswith( typ ) for typ in typeToSave ) - - ## esdjets = [ o for o in inputcontent if saveThisObject(o) ] - - ## return esdjets - -def buildJetAlgName(finder, mainParam, variableRMassScale=0, variableRMinRadius=0): # variableRMassScale (Rho) in MeV - if ( variableRMassScale > 0 ): - return finder + "VR" + str(int(variableRMassScale/1000)) + "Rmax" + str(int(mainParam*10)) + "Rmin" +str(int(variableRMinRadius*10)) - return finder + str(int(mainParam*10)) - -def buildJetContName(finder, mainParam, input, variableRMassScale=0, variableRMinRadius=0): - return buildJetAlgName(finder, mainParam, variableRMassScale, variableRMinRadius) +input+"Jets" # could be more elaborated... - -def interpretJetName(jetcollName, finder = None,input=None, mainParam=None): - # first step : guess the finder, input , mainParam, if needed - if finder is None: - for a in [ 'AntiKt','CamKt','Kt', 'Cone','SISCone','CMSCone']: - if jetcollName.startswith(a): - finder = a - break - if finder is None: - jetrec.info( "Error could not guess jet finder type in ",jetcollName ) - return - - if input is None: - for i in ['LCTopo','Tower','EMTopo', "Truth", "ZTrack", 'PV0Track']: - if i in jetcollName: - input = i - if i== "Tower": - if 'Ghost' in jetcollName: - input = 'Tower' - else: - input = "TopoTower" - break - if input is None: - jetrec.info( "Error could not guess input type in ",jetcollName ) - return - - if mainParam is None: - # get the 2 chars following finder : - mp = jetcollName[len(finder):len(finder)+2] - mp = mp[0] if not mp[1] in '0123456789' else mp - try : - mainParam = float(mp)/10. - except ValueError : - jetrec.info( "Error could not guess main parameter in ",jetcollName ) - return - - return finder, mainParam, input diff --git a/Reconstruction/Jet/JetRecConfig/python/JetToolSupport.py b/Reconstruction/Jet/JetRecConfig/python/JetToolSupport.py deleted file mode 100644 index 0f16025a53c96abcb603fd3b0e4a951d4c81f934..0000000000000000000000000000000000000000 --- a/Reconstruction/Jet/JetRecConfig/python/JetToolSupport.py +++ /dev/null @@ -1,627 +0,0 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration - -# JetToolSupport.py -# -# David Adams -# March 2014 -# -# Defines the jet tool manager (class JetToolManager, JTM for short) -# which can be used to configure jet reconstruction tools. -# -# Use add or "+=" to register a tool both with this an instance of this -# class and with ToolSvc. The advantage of doing it here is there is a -# check to make sure the same name is not used more than once. -# -# Tools are locked when registered. The method setOutputLevel may -# be used to override this lock to change the tool's output level. -# -# Methods are provide to configure a jetrec tool along with its -# associated finder or groomer. The member "jetrecs" holds the full -# list of offline jetrec tools and can be used to configure the tool or -# algorithm that loops over such tools. The member trigjetrecs holds -# the same for the trigger. The members "finders" and -# "groomers" hold the finding and grooming tools used by the jetrec -# tools. -# -# The prefix for messages from this tool is held by the member "prefix" -# and the member "debug" may be set to 1 to obtain more messages. -# -# The members "jetBuilderWithArea" and "jetBuilderWithoutArea" hold the -# jet builders used by all jetrec tools. -# -# The member "ghostArea" specifies the area to use for the ghosts -# generated for jet finding. - -from AthenaCommon import Logging -jetlog = Logging.logging.getLogger('JetRec_jobOptions') - -# import the jet flags. -from JetRecFlags import jetFlags - -# The tool manager -class JetToolManager: - prefix = "JetToolManager: " - debug = 0 - m_jetBuilder = None - jetBuilderWithArea = None - jetBuilderWithoutArea = None - tools = { } - finders = [] - groomers = [] - jetrecs = [] - trigjetrecs = [] - # Jet container names. Add input containers to this list: - # jetcons += ["SomeExistingJetContainer"] - jetcons = [] - # pT thresholds in MeV (for finding and filtering after calibration) - ptminFinder = 2000 - ptminFilter = 10000 - # Map of getter lists. - gettersMap = {} - # Map of modifier lists - modifiersMap = {} - - vertexContainer = "PrimaryVertices" - trackContainer = "InDetTrackParticles" - - # Print a message to the log. - def msg(self, lvl, mymsg): - if lvl <= self.debug: jetlog.debug( self.prefix + str(mymsg) ) - - # Add a tool. - def add(self, mytool): - myname = mytool.name() - self.msg(1, "Adding tool " + myname) - if myname in self.tools: - self.msg(0, "Tool " + myname + " is already registered") - raise LookupError - else: - jetlog.info( type(mytool) ) - self.tools[myname] = mytool - from AthenaCommon.AppMgr import ToolSvc - ToolSvc += mytool - mytool.lock() - setattr(self, myname, mytool) - return mytool - - # Add a tool with a local name (alias). - # Used to provide alternative names for tools with long names. - def addNamed(self, myname, mytool): - if myname in self.tools: - self.msg( "Name " + myname + " is already registered") - raise LookupError - self.tools[myname] = self.add(mytool) - setattr(self, myname, mytool) - return mytool - - # Ad op+= as alternative syntax to add. - def __iadd__(self, mytool): - self.add(mytool) - return self - - # Add for a jet builder. - # The jet builder is used by by all finders an groomers and - # must be added with one of these methods. - def addJetBuilderWithArea(self, mytool): - if self.add(mytool): - self.jetBuilderWithArea = mytool - self.msg(1, "Jet builder with area added: " + mytool.name()) - return mytool - else: - self.msg(0, "Error adding jet builder with area.") - raise LookupError - def addJetBuilderWithoutArea(self, mytool): - if self.add(mytool): - self.jetBuilderWithoutArea = mytool - self.msg(1, "Jet builder without area added: " + mytool.name()) - return mytool - else: - self.msg(0, "Error adding jet builder without area.") - raise LookupError - - # Return the list of modifiers associated with a name. - # If the argument is a list, it is returned directly. - def getModifiers(self, modifiersin, altname =None): - if modifiersin == None: - return self.modifiersMap[altname] - if type(modifiersin) == str: - return self.modifiersMap[modifiersin] - return modifiersin - - # Build the list of modifiers, replacing the string "calib:XXX:CALIB" with - # the appropriate calibration tool. - def buildModifiers(self, modifiersin, finder, getters, altname, output, calibOpt): - from GaudiKernel.Proxy.Configurable import ConfigurableAlgTool - from JetRec.JetRecConf import JetFinder - outmods = [] - inmods = self.getModifiers(modifiersin, altname) - ncalib = 0 - for mod in inmods: - jetlog.info( self.prefix + "Adding modifier " + str(mod) ) - mod0 = "" - # Split mod = a:b:c... into mod0="a" and modarr = [a, b, c, ...] - if type(mod) == str: - if len(mod) == 0: continue - modarr = mod.split(":") - mod0 = modarr[0] - # Fully configured tool. - if isinstance(mod, ConfigurableAlgTool): - self.msg(2, " Adding modifier " + mod.name()) - outmods += [mod] - # Add jet calibration: - # calib:XXX:CALIB - Applies calibration sequence XXX (see JetRecCalibrationFinder) - # using JetCalibrationTool with configuration (or key) CONFIG. - elif mod0 == "calib": - ncalib += 1 - alg = finder.JetAlgorithm - rad = finder.JetRadius - get = getters[0] - inp = get.Label - copt = calibOpt - if type(calibOpt)==str and len(calibOpt): - calargs = calibOpt.split(":") - else: - calargs = modarr[1:] - if len(calargs) == 0: - copt = jetFlags.defaultCalibOpt - if type(copt)==str and len(copt): - calargs = copt.split(":") - else: - jetlog.info( self.prefix + 'ERROR: If the modifier "calib" is used, then calibOpt or jetFlags.CalibOpt must be a non-blank string.' ) - jetlog.info( self.prefix + 'ERROR: Another alternative is to use the modifier string format "calib:<OPT>", e.g. "calib:a"' ) - raise Exception - if len(calargs) == 0 or calargs[0]=="": - jetlog.info( self.prefix + "ERROR: Calibration requested without option." ) - jetlog.info( self.prefix + " Add calibOpt to tool string, jet build command or to jetFlags.defaultCalibOpt" ) - raise Exception - seq = calargs[0] - if seq == "none": - jetlog.info( self.prefix + "Skipping calibration." ) - continue - config = "" - evsprefix = "Kt4" - if len(calargs) > 1: - config = calargs[1] - if len(calargs) > 2: - evsprefix = calargs[2] - self.msg(0, " Adding " + seq + " calibration for " + alg + " R=" + str(rad) + " " + inp) - self.msg(0, " Configuration key/file: " + config) - self.msg(0, " Event shape prefix: " + evsprefix) - from JetRecCalibrationFinder import jrcf - calmod = jrcf.find(alg, rad, inp, seq, config, evsprefix) - jetlog.info( self.prefix + "Adding calib modifier " + str(calmod) ) - outmods += [calmod] - # truthassoc - Does truth jet association replacing the input anme with "Truth" - elif mod == "truthassoc": - sinp = getters[0].Label.split("Origin")[0] - salg = finder.JetAlgorithm - srad = str(int(10*finder.JetRadius)) - cname = output.replace(sinp, "Truth") - if cname == output: - jetlog.info( sinp, cname, output ) - raise TypeError - # Check that the building of the association tool has been scheduled. - if not cname in self.jetcons: - jetlog.info( self.prefix + "Truth association skipped because container is missing: " + cname ) - jetlog.info( self.prefix + "Add to jetcons if input stream is expected to have this." ) - tname = mod + "_" + salg + srad - if not tname in self.tools: - from JetMomentTools.JetMomentToolsConf import JetPtAssociationTool - self += JetPtAssociationTool(tname, InputContainer=cname, AssociationName="GhostTruth") - outmods += [self.tools[tname]] - # trackassoc - Does track jet association replacing the input name with "Track" - elif mod == "trackassoc": - sinp = getters[0].Label.split("Origin")[0] - salg = finder.JetAlgorithm - srad = str(int(10*finder.JetRadius)) - cname = output.replace(sinp, "PV0Track") - if cname == output: - jetlog.info( sinp, cname, output ) - raise TypeError - # Check that the building of the association tool has been scheduled. - if not cname in self.jetcons: - jetlog.info( self.prefix + "Track association skipped because container is missing: " + cname ) - jetlog.info( self.prefix + "Add to jetcons if input stream is expected to have this." ) - else: - tname = mod + "_" + salg + srad - if not tname in self.tools: - from JetMomentTools.JetMomentToolsConf import JetPtAssociationTool - self += JetPtAssociationTool(tname, InputContainer=cname, AssociationName="GhostTrack") - outmods += [self.tools[tname]] - # jetfilter - Filter to remove jets with pT < self.ptminFilter - elif mod == "jetfilter": - if self.ptminFilter <= 0: - jetlog.info( self.prefix + "Jet filter requested without a threshold." ) - raise Exception - tname = "jetpt" + str(self.ptminFilter) - if not tname in self.tools: - from JetRec.JetRecConf import JetFilterTool - self.add( JetFilterTool(tname, PtMin=self.ptminFilter) ) - outmods += [self.tools[tname]] - # btag - btagging - elif mod == "btag": - from BTagging.BTaggingConfiguration import getConfiguration - ConfInstance = getConfiguration() - from AthenaCommon.AppMgr import ToolSvc - sinp = getters[0].Label - salg = finder.JetAlgorithm - srad = str(int(10*finder.JetRadius)) - bspec = salg + srad + sinp - jetlog.info( self.prefix + "Scheduling btagging for " + bspec ) - btagger = ConfInstance.setupJetBTaggerTool(ToolSvc, bspec) - jetlog.info( btagger ) - self.add(btagger) - outmods += [btagger] - elif mod == "largeR": - outmods += jtm.modifiersMap["largeR"] - else: - raise TypeError - # Check calibration. - if calibOpt != "": - if ncalib==0: - jetlog.info( self.prefix + "Calibration option (" + calibOpt + ") provided without any calibration modifiers." ) - elif ncalib > 1: - jetlog.info( self.prefix + "Calibration option (" + calibOpt + ") provided with multiple calibration modifiers." ) - raise Exception - - - return outmods - - # Create a jet finder without a JetRecToosl. - # alg = akgorithm name (Kt, CamKt, AntiKt) - # radius = size parameter - # rndseed: RandomOption for the finder - # gettersin = array of input pseudojet builders (or name in gettersMap) - # modifiersin = list of modifier tools (or name of such in modifiersMap) - # If absent, the gettersin name is used. - # consumers = sequence of jet consumers to run after reco - # ivtx = None: ordinary jet finding - # -1: Separate finding for each vertex - # >=0: Finding only for vertex ivtx. - # ghostArea: if > 0, then ghosts are found with this inverse density - # rndseed: RandomOption for the finder - # variableRMinRadius: Min radius for variable-R finding - # variableRMassScale: Mass scale for variable-R finding - # calibOpt: Calibration option, e.g. "ar". See JetRecCalibrationFinder.py. - # returns lofinder, hifinder where finder is the lowest-level finder and hifinder - # is the highest. - def addJetFinderTool(self, toolname, alg, radius, ivtx =None, - ghostArea =0.0, ptmin =0.0, rndseed =1, - variableRMinRadius =-1.0, variableRMassScale =-1.0): - myname = "JetToolManager:addJetFinderTool: " - if toolname in self.tools: - self.msg(0, "Tool " + myname + " is already registered") - raise LookupError - self.msg(2, "Adding finder tool") - if ghostArea == 0.0: - self.m_jetBuilder = self.jetBuilderWithoutArea - else: - self.m_jetBuilder = self.jetBuilderWithArea - if self.m_jetBuilder == None: - self.msg(0, "Jet builder must be specified") - raise Error - from JetRec.JetRecConf import JetFinder - areaSuffix= "Area" if ghostArea>0.0 else "" - finder = JetFinder(toolname); - finder.JetAlgorithm = alg - finder.JetRadius = radius - finder.VariableRMinRadius = variableRMinRadius - finder.VariableRMassScale = variableRMassScale - finder.RandomOption = rndseed - finder.GhostArea = ghostArea - if ptmin > 0.0: - finder.PtMin = ptmin - else: - finder.PtMin = self.ptminFinder - finder.JetBuilder = self.m_jetBuilder - self += finder - self.finders += [finder] - hifinder = finder; - if type(ivtx) is int: - from JetRec.JetRecConf import JetByVertexFinder - vfinder = JetByVertexFinder( - toolname + "ByVertex", - JetFinder = finder, - Vertex = ivtx - ) - self += vfinder - self.finders += [vfinder] - hifinder = vfinder; - return (finder, hifinder) - - # Create a jet finder and rectool. - # output = name for output container (and JetRecTool) - # alg = akgorithm name (Kt, CamKt, AntiKt) - # radius = size parameter - # rndseed: RandomOption for the finder - # isTrigger: If true, the trigger store is used and the tools is added to - # trigjetrecs instead of jetrecs - # useTriggerStore: If true, the trigger store is used. - # gettersin = array of input pseudojet builders (or name in gettersMap) - # modifiersin = list of modifier tools (or name of such in modifiersMap) - # If absent, the gettersin name is used. - # consumers = sequence of jet consumers to run after reco - # ivtx = None: ordinary jet finding (unless gettersin = ztrack or pv0track) - # -1: Separate finding fore each vertex - # >=0: Finding only for vertex ivtx. - # ghostArea: if > 0, then ghosts are found with this inverse density - # ptminFilter: If > 0, then this is used as the pT threhold for filtering jets. - # rndseed: RandomOption for the finder - # isTrigger: If true, the trigger store is used and the tools is added to - # trigjetrecs instead of jetrecs - # useTriggerStore: If true, the trigger store is used (only for testing) - # variableRMinRadius: Min radius for variable-R finding - # variableRMassScale: Mass scale for variable-R finding - # calibOpt: Calibration option, e.g. "ar". See JetRecCalibrationFinder.py. - def addJetFinder(self, output, alg, radius, gettersin, modifiersin =None, - consumers =None, ivtxin =None, - ghostArea =0.0, ptmin =0.0, ptminFilter =0.0, rndseed =1, - isTrigger =False, useTriggerStore =False, - variableRMinRadius =-1.0, variableRMassScale =-1.0, - calibOpt ="", jetPseudojetCopier ="", - warnIfDuplicate=True, - overwrite=False): - self.msg(2, "Adding finder") - from JetRec.JetRecConf import JetRecTool - if type(gettersin) == str: - getters = self.gettersMap[gettersin] - else: - getters = gettersin - # If jet finding by vertex is not specified, check for special input type names - ivtx = ivtxin - if ivtx == None: - if gettersin == "ztrack": ivtx = -1 # Find tracs separatesly for each vertex - elif gettersin == "pv0track": ivtx = 0 # Find tracks only for 1st vertex - # Retrieve/build the jet finder. - lofinder,hifinder = self.addJetFinderTool(output+"Finder", alg, radius, ivtx, ghostArea, ptmin, rndseed, - variableRMinRadius, variableRMassScale) - jetrec = JetRecTool(output) - jetrec.PseudoJetGetters = getters - jetrec.JetFinder = hifinder - jetrec.OutputContainer = output - ptminSave = self.ptminFilter - if ptminFilter > 0.0: self.ptminFilter = ptminFilter - jetrec.JetModifiers = self.buildModifiers(modifiersin, lofinder, getters, gettersin, output, calibOpt) - if consumers != None: - jetrec.JetConsumers = consumers - self.ptminFilter = ptminSave - jetrec.Trigger = isTrigger or useTriggerStore - jetrec.Timer = jetFlags.timeJetRecTool() - jetrec.WarnIfDuplicate = warnIfDuplicate - jetrec.Overwrite = overwrite - - self += jetrec - if isTrigger: - self.trigjetrecs += [jetrec] - else: - self.jetrecs += [jetrec] - self.jetcons += [output] - return jetrec - - # Create a mass-drop filter and rectool. - # output = name for output container (and JetRecTool) - # mumax = MuMax used in the filter - # ymin = YMin used in the filter - # input = name of the input jet container - # modifiersin = list of modifier tools (or name of such in modifiersMap) - # doArea = whether to write jet areas (default false because work is needed to - # recover this for reclustered jets). - def addJetSplitter(self, output, mumax, ymin, input, modifiersin ="groomed", - isTrigger =False, useTriggerStore =False, doArea =True): - from JetRec.JetRecConf import JetSplitter - from JetRec.JetRecConf import JetRecTool - groomer = JetSplitter(output + "Groomer") - groomer.MuMax = mumax - groomer.YMin = ymin - groomer.BDRS = False - groomer.NSubjetMax = 3 - if doArea: - groomer.JetBuilder = self.jetBuilderWithArea - else: - groomer.JetBuilder = self.jetBuilderWithoutArea - self += groomer - jetrec = JetRecTool(output) - jetrec.JetGroomer = groomer - jetrec.InputContainer = input - jetrec.OutputContainer = output - jetrec.JetModifiers = self.getModifiers(modifiersin) - jetrec.Trigger = isTrigger or useTriggerStore - jetrec.Timer = jetFlags.timeJetRecTool() - self += jetrec - if isTrigger: - self.trigjetrecs += [jetrec] - else: - self.jetrecs += [jetrec] - self.jetcons += [output] - return jetrec - - # Create a Trimmer and rectool. - # output = name for output container (and JetRecTool) - # rclus = RClus used in the trimming - # ptfrac = PtFrac used in the trimming - # input = name of the input jet container - # modifiersin = list of modifier tools (or name of such in modifiersMap) - def addJetTrimmer(self, output, rclus, ptfrac, input, modifiersin ="groomed", - pseudojetRetriever ="jpjretriever", - isTrigger =False, useTriggerStore =False, doArea =True): - from JetRec.JetRecConf import JetTrimmer - from JetRec.JetRecConf import JetRecTool - groomer = JetTrimmer(output + "Groomer") - groomer.RClus = rclus - groomer.PtFrac = ptfrac - if doArea: - groomer.JetBuilder = self.jetBuilderWithArea - else: - groomer.JetBuilder = self.jetBuilderWithoutArea - self += groomer - jetrec = JetRecTool(output) - jetrec.JetGroomer = groomer - jetrec.InputContainer = input - jetrec.OutputContainer = output - jetrec.JetModifiers = self.getModifiers(modifiersin) - jetrec.Trigger = isTrigger or useTriggerStore - jetrec.Timer = jetFlags.timeJetRecTool() - if pseudojetRetriever in self.tools: - jetrec.JetPseudojetRetriever = self.tools[pseudojetRetriever] - else: - jetlog.info( "Requested jet pseudojet retriever is not a registered tool: " \ - + pseudojetRetriever ) - raise KeyError - self += jetrec - if isTrigger: - self.trigjetrecs += [jetrec] - else: - self.jetrecs += [jetrec] - self.jetcons += [output] - return jetrec - - # Create a Pruner and rectool. - # output = name for output container (and JetRecTool) - # rcut = RCut used in the pruning - # zcut = ZCut used in the pruning - # input = name of the input jet container - # modifiersin = list of modifier tools (or name of such in modifiersMap) - def addJetPruner(self, output, rcut, zcut, input, modifiersin ="groomed", - isTrigger =False, useTriggerStore =False, doArea =True): - from JetRec.JetRecConf import JetPruner - from JetRec.JetRecConf import JetRecTool - groomer = JetPruner(output + "Groomer") - groomer.RCut = rcut - groomer.ZCut = zcut - if doArea: - groomer.JetBuilder = self.jetBuilderWithArea - else: - groomer.JetBuilder = self.jetBuilderWithoutArea - self += groomer - jetrec = JetRecTool(output) - jetrec.JetGroomer = groomer - jetrec.InputContainer = input - jetrec.OutputContainer = output - jetrec.JetModifiers = self.getModifiers(modifiersin) - jetrec.Trigger = isTrigger or useTriggerStore - jetrec.Timer = jetFlags.timeJetRecTool() - self += jetrec - if isTrigger: - self.trigjetrecs += [jetrec] - else: - self.jetrecs += [jetrec] - self.jetcons += [output] - return jetrec - - # Create a jet reclusterer and rectool. - # output = name for output container (and JetRecTool) - # alg = akgorithm name (Kt, CamKt, AntiKt) - # radius = size parameter - # input = name for the input jet collection - # rndseed: RandomOption for the finder - # isTrigger: If true, the trigger store is used and the tools is added to - # trigjetrecs instead of jetrecs - # useTriggerStore: If true, the trigger store is used. - # modifiersin = list of modifier tools (or name of such in modifiersMap) - # If absent, the gettersin name is used. - # consumers = sequence of jet consumers to run after reco - # ivtx = None: ordinary jet finding (unless gettersin = ztrack or pv0track) - # -1: Separate finding fore each vertex - # >=0: Finding only for vertex ivtx. - # ghostArea: if > 0, then ghosts are found with this inverse density - # ptminFilter: If > 0, then this is used as the pT threhold for filtering jets. - # rndseed: RandomOption for the finder - # isTrigger: If true, the trigger store is used and the tools is added to - # trigjetrecs instead of jetrecs - # useTriggerStore: If true, the trigger store is used (only for testing) - # variableRMinRadius: Min radius for variable-R finding - # variableRMassScale: Mass scale for variable-R finding - # calibOpt: Calibration option, e.g. "ar". See JetRecCalibrationFinder.py. - def addJetReclusterer(self, output, alg, radius, input, modifiersin =None, - consumers =None, ivtx =None, - ghostArea =0.0, ptmin =0.0, ptminFilter =0.0, rndseed =1, - isTrigger =False, useTriggerStore =False, - variableRMinRadius =-1.0, variableRMassScale =-1.0, - calibOpt ="", jetPseudojetCopier =""): - self.msg(2, "Adding reclusterer") - from JetRec.JetRecConf import JetRecTool - from JetRec.JetRecConf import JetReclusterer - # Retrieve/build the jet finder. - lofinder,hifinder = self.addJetFinderTool(output+"Finder", alg, radius, ivtx, ghostArea, ptmin, rndseed, - variableRMinRadius, variableRMassScale) - reclname = output + "Reclusterer" - groomer = JetReclusterer( - reclname, - JetConstituentsRetriever = self.tools["jconretriever"], - JetFinder = hifinder - ) - self += groomer - jetrec = JetRecTool(output) - jetrec.InputContainer = input - jetrec.OutputContainer = output - jetrec.JetGroomer = groomer - jetrec.JetModifiers = self.getModifiers(modifiersin) - if consumers != None: - jetrec.JetConsumers = consumers - jetrec.Trigger = isTrigger or useTriggerStore - jetrec.Timer = jetFlags.timeJetRecTool() - self += jetrec - if isTrigger: - self.trigjetrecs += [jetrec] - else: - self.jetrecs += [jetrec] - self.jetcons += [output] - return jetrec - - # Create a copying rectool. - # output = name for output container (and JetRecTool) - # output = name for input container - # modifiersin = list of modifier tools (or name of such in modifiersMap) - def addJetCopier(self, output, input, modifiersin, ptminFilter =0.0, radius =0.0, alg ="", inp ="", - isTrigger=False, useTriggerStore=False, calibOpt ="", shallow =True): - from JetRec.JetRecConf import JetRecTool - jetrec = JetRecTool(output) - jetrec.InputContainer = input - jetrec.OutputContainer = output - ptminSave = self.ptminFilter - if ptminFilter > 0.0: self.ptminFilter = ptminFilter - class finder: - JetRadius = radius - JetAlgorithm = alg - class get: - Label = inp - getters = [get] - jetrec.JetModifiers = self.buildModifiers(modifiersin, finder, getters, None, output, calibOpt) - self.ptminFilter = ptminSave - jetrec.Trigger = isTrigger or useTriggerStore - jetrec.Timer = jetFlags.timeJetRecTool() - jetrec.ShallowCopy = shallow - self += jetrec - self.jetrecs += [jetrec] - self.jetcons += [output] - return jetrec - - # Ad op[] to return a tool. - def __getitem__(self, toolname): - return self.tools[toolname] - - # Change the output level of a tool. - def setOutputLevel(self, toolid, level): - from GaudiKernel.Proxy.Configurable import ConfigurableAlgTool - if type(toolid) == str: - tool = self[toolid] - else: - tool = toolid - locked = tool.isLocked() - oldlevel = "undefined" - if locked: - dbglvl = 0 - slock = "locked" - tool.unlock() - else: - dbglvl = 1 - slock = "unlocked" - aname = "OutputLevel" - if hasattr(tool, aname): - oldlevel = getattr(tool, aname) - setattr(tool, aname, level) - if locked: - tool.lock() - self.msg(0, "Changed output level of " + slock + " tool " + tool.name() + \ - " from " + str(oldlevel) + " to " + str(level) + ".") - diff --git a/Reconstruction/Jet/JetRecConfig/python/README.md b/Reconstruction/Jet/JetRecConfig/python/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8c7f6811d28f71d9c7db2d5398277246357e438b --- /dev/null +++ b/Reconstruction/Jet/JetRecConfig/python/README.md @@ -0,0 +1,65 @@ +# JetRecConfig/python + +## Module contents + +### JetRecConfig.py + +* This is the top-level jet reconstruction module, containing the + function JetRecCfg() that returns a configured ComponentAccumulator + with the standalone jet reconstruction sequence. +* The function resolveDependencies() can be called to retrieve a + dict containing the full set of input collections, ghost associations + and jet modifiers needed to satisfy the user's needs as encoded + in the provided JetDefinition. + +### JetDefinition.py + +* This module defines a number of configuration classes used to define + a jet reconstruction job. The classes are listed below together with + the information that they contain. + * JetDefinition -- defines the jet collection + * jet clustering algorithm (kt, Cambridge/Aachen, anti-kt) + * radius + * input type (JetConstit object) + * name + * minimum pt (separately for fastjet and xAOD jet conversion) + * ghost list + * modifier list + * JetConstit -- defines inputs to jet finding + * base type (type of xAOD object) + * modifier list (corrections/filters applied before jet finding) + * JetGhost -- defines objects to be associated with ghost association + * input type (type of xAOD object) + * label (identifier, e.g. type of truth particle [TruthPartons], ...) + * JetModifier -- defines tools that operate on the jet collection + * tooltype + * tool name + * a helper function defining how to configure the tool + * a string describing to the helper function how to configure the tool + * a flag stating whether the jet definition is needed to configure the tool + * a list of prerequisites (inputs, ghosts, other mods) or a helper function returning such a list + +### ConstModHelpers.py + +* This module assists setup of constituent modifiers, i.e. operations + like filtering and four-momentum corrections applied prior to jet finding. +* It is called from JetRecConfig.py + +### JetModConfig.py + +* This module assists configuration of modifiers, including resolving + their dependencies as the job is scheduled. +* When a list of desired modifiers is provided, a full list of all + modifiers needing to be run such that the desired modifiers will + be executed is returned, along with the sets of ghosts and input + collections needing to be set up. + +### StandardJetDefs.py + +* This module holds a library of standard jet and constituent definitions + that are regularly used in reconstruction. + +### StandardJetMods.py + +* This module holds a library of standard jet modifiers that are + frequently scheduled in reconstruction. diff --git a/Reconstruction/Jet/JetRecConfig/python/StandardJetDefs.py b/Reconstruction/Jet/JetRecConfig/python/StandardJetDefs.py new file mode 100644 index 0000000000000000000000000000000000000000..b3a883b43fa4137fbccb46d290d67316cc74ee22 --- /dev/null +++ b/Reconstruction/Jet/JetRecConfig/python/StandardJetDefs.py @@ -0,0 +1,71 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration + +######################################################################## +# # +# StandardJetDefs: A module defining standard definitions for jet # +# constituents and jet algorithms. # +# These can be copied and modified by users who want something a bit # +# different from what is provided. # +# Standard lists of ghost associated particles and modifiers are # +# provided elsewhere. # +# # +# Author: TJ Khoo # +# * Written for the time being to work in R21, but with R22 in mind # +# # +######################################################################## + + +######################################################################## +# Typical jet constituents +from JetDefinition import xAOD, JetConstit +from copy import deepcopy + +# Topoclusters with origin correction. +# We don't currently use raw TopoClusters, though some handling +# could be added to support this. +EMTopoOrigin = JetConstit(xAOD.Type.CaloCluster, ["EM","Origin"]) +LCTopoOrigin = JetConstit(xAOD.Type.CaloCluster, ["LC","Origin"]) +# LC clusters with Constituent Subtraction + SoftKiller +LCTopoCSSK = deepcopy(LCTopoOrigin) +LCTopoCSSK.modifiers += ["CS","SK"] + +# EM-scale particle flow objects with charged hadron subtraction +# For now we don't specify a scale, as only one works well, but +# this could be incorporated into the naming scheme and config +CHSPFlow = JetConstit(xAOD.Type.ParticleFlow) +# Particle Flow Objects with Constituent Subtraction + SoftKiller +CSSKPFlow = deepcopy(CHSPFlow) +CSSKPFlow.modifiers += ["CS","SK"] + +# Track particles from the primary vertex +PV0Track = JetConstit(xAOD.Type.TrackParticle,["PV0"]) + +# Truth particles from the hard scatter vertex prior to Geant4 simulation. +# Neutrinos and muons are omitted; all other stable particles are included. +Truth = JetConstit(xAOD.Type.TruthParticle) + +# Truth particles from the hard scatter vertex prior to Geant4 simulation. +# Prompt electrons, muons and neutrinos are excluded, all other stable particles +# are included, in particular leptons and neutrinos from hadron decays. +TruthWZ = JetConstit(xAOD.Type.TruthParticle,["NoWZ"]) + +######################################################################## +# Typical jet algorithm definitions +# Filter pts, ghost lists and modifier lists can be updated by the user, +# though there is some risk of overwriting... +from JetDefinition import JetDefinition + +# Standard small-radius (0.4) AntiKt jets +AntiKt4LCTopo = JetDefinition("AntiKt",0.4,LCTopoOrigin) +AntiKt4EMTopo = JetDefinition("AntiKt",0.4,EMTopoOrigin) +AntiKt4EMPFlow = JetDefinition("AntiKt",0.4,CHSPFlow) + +# Standard large-radius (1.0) AntiKt ungroomed jets +AntiKt10LCTopo = JetDefinition("AntiKt",1.0,LCTopoOrigin) +AntiKt10LCTopoCSSK = JetDefinition("AntiKt",1.0,LCTopoCSSK) + +# Standard truth jets +AntiKt4Truth = JetDefinition("AntiKt",0.4,Truth) +AntiKt4TruthWZ = JetDefinition("AntiKt",0.4,TruthWZ) +AntiKt10Truth = JetDefinition("AntiKt",1.0,Truth) +AntiKt10TruthWZ = JetDefinition("AntiKt",1.0,TruthWZ) diff --git a/Reconstruction/Jet/JetRecConfig/python/StandardJetMods.py b/Reconstruction/Jet/JetRecConfig/python/StandardJetMods.py new file mode 100644 index 0000000000000000000000000000000000000000..eeaf1f00e57a238ad22d338232020798ae2f08a1 --- /dev/null +++ b/Reconstruction/Jet/JetRecConfig/python/StandardJetMods.py @@ -0,0 +1,105 @@ +from JetDefinition import JetModifier + +######################################################################## +# Define the dictionary of tool configurations using the helpers defined +# in package configs. +# This dict maps a modifier alias to the JetModifier config object +# that in turn will be responsible for generating a configured tool. +# +# [Optional] Args to the JetModifier constructor are: +# 1. Tool Type (ignored if the helper is a custom one) +# 2. Tool Name (ignored if the helper is a custom one) +# [3.] Config helper +# [4.] Prereqs (default to []). Can also be a function. +# [5.] Flag passJetDef specifying if the helper needs the jet definition +# --> should this be by default? prefer to avoid ignored args +jetmoddict = {} + +######################################################################## +# Define the simple modifier setups here -- those defined in JetRec. +from JetRec import JetRecConf +def getJetFilterTool(modspec): + threshold = int(modspec) + jetptfilter = JetRecConf.JetFilterTool("jetptfilter_{0}mev".format(threshold)) + jetptfilter.PtMin = threshold + return jetptfilter +jetrecmods = { + "Sort": JetModifier("JetSorter","jetsort"), + "Filter": JetModifier("JetFilterTool","jetptfilter",helperfn=getJetFilterTool), +} +jetmoddict.update (jetrecmods) + +######################################################################## +# Below, we populate the jetmoddict with modifier definitions for tools +# that are defined in other packages. +# The helper functions for tools in PackageName live in modules called +# PackageName.PackageConfig (modules to be moved) + +# Calibration +from JetCalibTools import JetCalibToolsConfig +jetcalibmods = { + "Calib": JetModifier("JetCalibrationTool","jetcalib_jetcoll_calibseq", + helperfn=JetCalibToolsConfig.getJetCalibToolFromString, + prereqs=JetCalibToolsConfig.getJetCalibToolPrereqs,passJetDef=True) + } +jetmoddict.update(jetcalibmods) + +# TBD: +# All items below in principle will support decoration mode, rather +# than only non-const modification. Mode of operation should be +# determined by interface called from parent tool/alg. + +# Standard jet moments +from JetMomentTools import JetMomentToolsConfig +jetmomentmods = { + # Easy cases, no special config or prereqs, just default tool config + "CaloEnergies": JetModifier("JetCaloEnergies", "jetens"), + "ClusterMoments": JetModifier("JetClusterMomentsTool", "clsmoms"), + "LArHVCorr": JetModifier("JetLArHVTool", "larhvcorr"), + "ECPSFrac": JetModifier("JetECPSFractionTool", "ecpsfrac"), + "Width": JetModifier("JetWidthTool", "width"), + + # More complex cases here + "CaloQuality": JetModifier("JetCaloQualityTool", "caloqual", + helperfn=JetMomentToolsConfig.getCaloQualityTool), + "ConstitFourMom": JetModifier("JetConstitFourMomTool", "jetconstitfourmom_basename", + helperfn=JetMomentToolsConfig.getConstitFourMomTool, + passJetDef=True), + "JVF": JetModifier("JetVertexFractionTool", "jvf", + helperfn=JetMomentToolsConfig.getJVFTool, + prereqs = ["mod:TrackSumMoments"] ), + "JVT": JetModifier("JetVertexTaggerTool", "jvt", + prereqs = [ "mod:JVF" ]), + "OriginSetPV": JetModifier("JetOriginCorrectionTool", "origin_setpv", + prereqs = [ "mod:JVF" ]), + "TrackMoments": JetModifier("JetTrackMomentsTool", "trkmoms", + helperfn=JetMomentToolsConfig.getTrackMomentsTool, + prereqs = [ "input:JetSelectedTracks","input:JetTrackVtxAssoc","ghost:Track" ]), + "TrackSumMoments": JetModifier("JetTrackMomentsTool", "trksummoms", + helperfn=JetMomentToolsConfig.getTrackMomentsTool, + prereqs = [ "input:JetSelectedTracks","input:JetTrackVtxAssoc","ghost:Track" ]), + } +jetmoddict.update(jetmomentmods) + +# Truth labelling moments +from ParticleJetTools import ParticleJetToolsConfig +particlejetmods = { + # Easy cases, no special config or prereqs, just default tool config + "PartonTruthLabel": JetModifier("Analysis__JetPartonTruthLabel","partontruthlabel", + prereqs=["ghost:TruthLabelPartons"]), + + # More complex cases here + "TruthPartonDR": JetModifier("Analysis__JetConeLabeling","truthpartondr", + helperfn=ParticleJetToolsConfig.getJetConeLabeling), + "JetDeltaRLabel": JetModifier("ParticleJetDeltaRLabelTool","jetdrlabeler_jetptmin", + helperfn=ParticleJetToolsConfig.getJetDeltaRLabelTool, + prereqs=["input:TruthLabelBHadronsFinal", + "input:TruthLabelCHadronsFinal", + "input:TruthLabelTausFinal"]) + } +jetmoddict.update(particlejetmods) + +# Todo: jet substructure moment tools + +# This can also be expanded by users if they would rather do this than +# pass in JetModifier instances in the JetDefinition diff --git a/Reconstruction/Jet/JetRecConfig/python/__init__.py b/Reconstruction/Jet/JetRecConfig/python/__init__.py index 74583d364ec2ca794156596c7254d9b234a940c6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/Reconstruction/Jet/JetRecConfig/python/__init__.py +++ b/Reconstruction/Jet/JetRecConfig/python/__init__.py @@ -1,2 +0,0 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration - diff --git a/Reconstruction/Jet/JetRecConfig/share/JetRecTestCfg.py b/Reconstruction/Jet/JetRecConfig/share/JetRecTestCfg.py new file mode 100644 index 0000000000000000000000000000000000000000..5397dfba6a761cd2b70884914b0888a445cbfae0 --- /dev/null +++ b/Reconstruction/Jet/JetRecConfig/share/JetRecTestCfg.py @@ -0,0 +1,206 @@ +from JetRecConfig import JetRecConfig +from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator + +from pprint import pprint, pformat + +from AthenaCommon import Logging +jetlog = Logging.logging.getLogger("testJetRecDeps") + +def JetRecTestCfg(configFlags,args): + + jetlist = configFlags.JetRec.Definitions + if args.printDependencies: + for jetdef in jetlist: + deps = JetRecConfig.resolveDependencies(jetdef) + jetlog.info("Dumping dependency dict for {0}".format(jetdef)) + depstr = pformat(deps) + jetlog.info(depstr) + + if args.printAccumulators: + jetlog.info("Printing component accumulators for each jet collection") + jetcas = [] + for jetdef in jetlist: + jetcomps = JetRecConfig.JetRecCfg(jetdef,configFlags,jetnameprefix=configFlags.JetRec.Prefix) + if args.printAccumulators: + jetcomps.printConfig(withDetails=args.verboseAccumulators,summariseProps=True) + jetcas.append(jetcomps) + + jetlog.info("Printing component accumulator for entire sequence") + components = ComponentAccumulator() + for ca in jetcas: + components.merge(ca) + components.printConfig(args.verboseAccumulators,summariseProps=True) + + return components + +def DefineJetCollections(): + + # Here we define the jet configurations we want to build + # These mod and ghost lists should go in a common module + standardrecomods = ["Width","TrackMoments","TrackSumMoments","JVF","JVT","OriginSetPV", + "CaloEnergies","LArHVCorr"] + clustermods = ["ECPSFrac","ClusterMoments"] + truthmods = ["PartonTruthLabel","TruthPartonDR","JetDeltaRLabel:5000"] + + from JetRecConfig.JetDefinition import JetGhost + ghostlist = ["Track","MuonSegment","Truth"] + standardghosts = [JetGhost(ghosttype) for ghosttype in ghostlist] + flavourghostlist = ["BHadronsInitial", "BHadronsFinal", "BQuarksFinal", + "CHadronsInitial", "CHadronsFinal", "CQuarksFinal", + "TausFinal", + "WBosons", "ZBosons", "HBosons", "TQuarksFinal", + "Partons", + ] + flavourghosts = [JetGhost("TruthLabel"+ghosttype) for ghosttype in flavourghostlist] + standardghosts += flavourghosts + + ######################################################################## + # First a demonstration of just building jets using standard definitions + from JetRecConfig.StandardJetDefs import AntiKt4LCTopo, AntiKt4EMPFlow, AntiKt4Truth, AntiKt4TruthWZ + + # This updates the original jet definitions, so might be a little risky + # in derivation code. Safer would be to always deepcopy into a local variable. + AntiKt4LCTopo.ptminfilter = 15e3 + AntiKt4LCTopo.modifiers = ["Calib:T0:mc","Sort"] + standardrecomods + clustermods + truthmods + AntiKt4LCTopo.ghostdefs = standardghosts + #AntiKt4LCTopo.modifiers = ["Calib:AnalysisLatest:mc"] + + AntiKt4EMPFlow.ptminfilter = 10e3 + AntiKt4EMPFlow.modifiers = ["Calib:T0:mc","Sort"] + standardrecomods + truthmods + AntiKt4EMPFlow.ghostdefs = standardghosts + #AntiKt4EMPFlow.modifiers = ["Calib:AnalysisLatest:mc"] + + from copy import deepcopy + AntiKt4Truth.ptminfilter = 2e3 + + AntiKt4TruthWZ.ptminfilter = 2e3 + + ######################################################################## + # Now we define our own definitions + from JetRecConfig.JetDefinition import JetConstit, JetDefinition, xAOD + LCTopoCSSK = JetConstit(xAOD.Type.CaloCluster, ["LC","Origin","CS","SK"]) + AntiKt4LCTopoCSSK = JetDefinition("AntiKt",0.4,LCTopoCSSK,ptmin=2e3,ptminfilter=2e3) + AntiKt4LCTopoCSSK.modifiers = ["ConstitFourMom"] + standardrecomods + clustermods + truthmods + AntiKt4LCTopoCSSK.ghostdefs = standardghosts + + ######################################################################## + # We can also copy and modify the standard ones + from copy import deepcopy + from JetRecConfig.StandardJetDefs import CHSPFlow + + CSSKPFlow = deepcopy(CHSPFlow) + CSSKPFlow.modifiers = ["CS","SK"] + AntiKt4EMPFlowCSSK = deepcopy(AntiKt4EMPFlow) + AntiKt4EMPFlowCSSK.inputdef = CSSKPFlow + AntiKt4EMPFlowCSSK.modifiers = ["ConstitFourMom"] + standardrecomods + truthmods + AntiKt4EMPFlowCSSK.ptmin = 2e3 + AntiKt4EMPFlowCSSK.ptminfilter = 2e3 + AntiKt4EMPFlowCSSK.ghostdefs = standardghosts + + jetdefs = [#AntiKt4Truth, + #AntiKt4TruthWZ, + AntiKt4LCTopo, + AntiKt4EMPFlow, + AntiKt4LCTopoCSSK, + AntiKt4EMPFlowCSSK] + return jetdefs + +if __name__=="__main__": + from argparse import ArgumentParser + parser = ArgumentParser(prog="JetRecTestCfg: An example configuration module for jet reconstruction", + usage="Call with an input file, pass -n=0 to skip execution, -t 0 for serial or 1 for threaded execution.") + # + parser.add_argument("-H", "--Help", default=False, action="store_true", help="Evidently pyROOT interferes with help :(") + # + parser.add_argument("-f", "--filesIn", type=str, help="Comma-separated list of input files") + parser.add_argument("-M", "--msgLvl", default="INFO", help="The message verbosity") + parser.add_argument("-n", "--nEvents", default=0, type=int, help="The number of events to run. 0 skips execution") + # + parser.add_argument("-t", "--nThreads", default=1, type=int, help="The number of concurrent threads to run. 0 uses serial Athena.") + # + parser.add_argument("-D", "--dumpSG", default=False, action="store_true", help="Toggle StoreGate dump on each event") + parser.add_argument("-d", "--printDependencies", default=False, action="store_true", help="Print the dependency dicts for each jet collection") + parser.add_argument("-a", "--printAccumulators", default=False, action="store_true", help="Print the component accumulators for each jet collection separately") + parser.add_argument("-V", "--verboseAccumulators", default=False, action="store_true", help="Print full details of the AlgSequence for each accumulator") + args = parser.parse_args() + + if args.Help: + parser.print_help() + import sys + sys.exit(0) + + # Setting needed for the ComponentAccumulator to do its thing + from AthenaCommon.Configurable import Configurable + Configurable.configurableRun3Behavior=True + + # Set message levels + from AthenaCommon import Constants + msgLvl = getattr(Constants,args.msgLvl) + from AthenaCommon.Logging import log + log.setLevel(msgLvl) + + # Config flags steer the job at various levels + from AthenaConfiguration.AllConfigFlags import ConfigFlags + ConfigFlags.Input.isMC = True + ConfigFlags.Input.Files = args.filesIn.split(",") + + # Flags relating to multithreaded execution + ConfigFlags.Concurrency.NumThreads = args.nThreads + if args.nThreads>0: + ConfigFlags.Scheduler.ShowDataDeps = True + ConfigFlags.Scheduler.ShowDataFlow = True + ConfigFlags.Scheduler.ShowControlFlow = True + ConfigFlags.Concurrency.NumConcurrentEvents = args.nThreads + + ######################################################################## + # Define flags steering the jet reco config + jetdefs = DefineJetCollections() + ConfigFlags.addFlag("JetRec.Definitions",jetdefs) + ConfigFlags.addFlag("JetRec.Prefix","New") + + # Prevent the flags from being modified + ConfigFlags.lock() + + # Get a ComponentAccumulator setting up the fundamental Athena job + from AthenaConfiguration.MainServicesConfig import MainServicesThreadedCfg + cfg=MainServicesThreadedCfg(ConfigFlags) + + # Add the components for reading in pool files + from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg + cfg.merge(PoolReadCfg(ConfigFlags)) + + # Add the components from our jet reconstruction job + cfg.merge(JetRecTestCfg(ConfigFlags,args)) + + # # build eventinfo attribute list + # from OutputStreamAthenaPool.OutputStreamAthenaPoolConf import EventInfoAttListTool, EventInfoTagBuilder + # EventInfoTagBuilder = EventInfoTagBuilder(AttributeList="SimpleTag") + # cfg.addEventAlgo(EventInfoTagBuilder,"AthAlgSeq") + + # Write what we produced to AOD + # First define the output list + outputlist = [] + originaljets = ["AntiKt4EMPFlowJets"] + for jetcoll in originaljets: + outputlist += ["xAOD::JetContainer#"+jetcoll, + "xAOD::JetAuxContainer#"+jetcoll+"Aux."] + for jetdef in ConfigFlags.JetRec.Definitions: + key = "{0}{1}Jets".format(ConfigFlags.JetRec.Prefix,jetdef.basename) + outputlist += ["xAOD::JetContainer#"+key, + "xAOD::JetAuxContainer#"+key+"Aux."] + + # # Now get the output stream components + # from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg + # cfg.merge(OutputStreamCfg(ConfigFlags,"xAOD",ItemList=outputlist)) + # pprint( cfg.getEventAlgo("OutputStreamxAOD").ItemList ) + + # Optionally, print the contents of the store every event + cfg.getService("StoreGateSvc").Dump = args.dumpSG + + # Save this configuration to a pickle file + f=open("JetRecTest.pkl","w") + cfg.store(f) + f.close() + + # Run the job + cfg.run(maxEvents=args.nEvents) diff --git a/Reconstruction/Jet/JetRecConfig/share/JetRec_jobOptions.py b/Reconstruction/Jet/JetRecConfig/share/JetRec_jobOptions.py deleted file mode 100644 index 297bbfd593f6e3a01c1f0a203334091da92fec34..0000000000000000000000000000000000000000 --- a/Reconstruction/Jet/JetRecConfig/share/JetRec_jobOptions.py +++ /dev/null @@ -1,85 +0,0 @@ -# JetRec_jobOptions.py -# -# David Adams -# February 2014 -# -# RecExCommon job options for running jet reconstruction. -# -# Run with -# > athena.py test_RunJetRec.py -# - -myname = "JetRec_jobOptions: " -print myname + "Begin." - -# Import the jet tool manager. -from JetRecConfig.JetRecStandard import jtm - -#-------------------------------------------------------------- -# Define the finders and groomers. -# Each line configures a finder or groomer and its associated jetrec tool. -# The first argument is the name of the output collection and the jetrec tool. -# The fifth argument is the list of modifiers. -# Non-zero ghostArea enables calculation of active area. -#-------------------------------------------------------------- - -# Finders. -from JetRecConfig.JetRecFlags import jetFlags -if jetFlags.useTruth(): - jtm.addJetFinder("AntiKt4TruthJets", "AntiKt", 0.4, "truth", ptmin= 5000) - jtm.addJetFinder("AntiKt4TruthWZJets", "AntiKt", 0.4, "truthwz", ptmin= 5000) - jtm.addJetFinder("AntiKt10TruthJets", "AntiKt", 1.0, "truth", ptmin=40000) - jtm.addJetFinder("AntiKt10TruthWZJets", "AntiKt", 1.0, "truthwz", ptmin=40000) - jtm.addJetFinder("CamKt12TruthJets", "CamKt", 1.2, "truth", ptmin=40000) - jtm.addJetFinder("CamKt12TruthWZJets", "CamKt", 1.2, "truthwz", ptmin=40000) -if jetFlags.useTracks(): - jtm.addJetFinder("AntiKt2PV0TrackJets", "AntiKt", 0.2, "pv0track", ptmin= 2000) - jtm.addJetFinder("AntiKt3PV0TrackJets", "AntiKt", 0.3, "pv0track", ptmin= 2000) - jtm.addJetFinder("AntiKt4PV0TrackJets", "AntiKt", 0.4, "pv0track", ptmin= 2000) -if jetFlags.useTopo(): - jtm.addJetFinder("AntiKt4EMTopoJets", "AntiKt", 0.4, "emtopo", "calib", ghostArea=0.01, ptmin= 2000, ptminFilter= 5000, calibOpt="aro") - jtm.addJetFinder("AntiKt4LCTopoJets", "AntiKt", 0.4, "lctopo", "calib", ghostArea=0.01, ptmin= 2000, ptminFilter= 7000, calibOpt="aro") - jtm.addJetFinder("AntiKt10LCTopoJets", "AntiKt", 1.0, "lctopo", "calib", ghostArea=0.01, ptmin= 2000, ptminFilter=50000, calibOpt="none") - jtm.addJetFinder("CamKt12LCTopoJets", "CamKt", 1.2, "lctopo", "calib", ghostArea=0.01, ptmin= 2000, ptminFilter=50000, calibOpt="none") -if jetFlags.usePFlow(): - jtm.addJetFinder("AntiKt4EMPFlowJets", "AntiKt", 0.4, "empflow", "pflow", ghostArea=0.01, ptmin= 2000, ptminFilter= 5000, calibOpt="a:pflow") - -#-------------------------------------------------------------- -# Build output container list. -#-------------------------------------------------------------- - -# Both standard and aux container must be listed explicitly. -# For release 19, the container version must be explicit. - -for jetrec in jtm.jetrecs: - jetFlags.jetAODList += [ "xAOD::JetContainer#" + jetrec.name() ] - auxprefix = "" - if jetrec.Trigger: - auxprefix = "Trig" - jetFlags.jetAODList += [ "xAOD::Jet" + auxprefix + "AuxContainer#" + jetrec.name() + "Aux." ] - - -# For testing. These blocks should not be enabled in production. -if jetFlags.debug > 0: - jetlog.info( "JetRec_jobOptions.py: Requested output stream: ") - jetlog.info( "%s", jetFlags.jetAODList ) -if jetFlags.debug > 1: - jetlog.info( "JetRec_jobOptions.py: Setting output level to DEBUG for all jetrecs") - for jetrec in jtm.jetrecs: - jtm.setOutputLevel(jetrec, DEBUG) - -#-------------------------------------------------------------- -# Add jet reco to algorithm sequence. -#-------------------------------------------------------------- -from JetRecConfig.JetAlgorithm import addJetRecoToAlgSequence -addJetRecoToAlgSequence() - -#-------------------------------------------------------------- -# save event shapes set with the JetAlgorithm -#-------------------------------------------------------------- -for esTool in jtm.jetrun.EventShapeTools : - t = getattr(ToolSvc, esTool.getName() ) - jetFlags.jetAODList += [ "xAOD::EventShape#"+t.OutputContainer, - "xAOD::EventShapeAuxInfo#"+t.OutputContainer+'Aux.' ] - -print myname + "Begin." diff --git a/Reconstruction/Jet/JetRecConfig/share/README.md b/Reconstruction/Jet/JetRecConfig/share/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3a768c83199d87b5687f66bfc8e8e4287f13615c --- /dev/null +++ b/Reconstruction/Jet/JetRecConfig/share/README.md @@ -0,0 +1,20 @@ +# JetRecConfig/share + +## JobOptions contents + +### JetRecTestCfg.py + +This module encodes an example/test job for jet reconstruction, +which builds a small number of standard jet collections and writes +them to an output xAOD file. + +Call `python JetRecTestCfg.py -H` for help. + +### test_JetDefinitions_properties.py + +This script tests whether jet definition properties correctly +update all necessary information when they are altered by +a user, for example when using a deepcopy-update pattern to +construct new JetConstit or JetDefinition instances. + +Should be moved to a test/ dir and turned into a unit test. diff --git a/Reconstruction/Jet/JetRecConfig/share/test_JetDefinitions_properties.py b/Reconstruction/Jet/JetRecConfig/share/test_JetDefinitions_properties.py new file mode 100644 index 0000000000000000000000000000000000000000..b614b69554bd667cb5d043b6d3b04efd8a171030 --- /dev/null +++ b/Reconstruction/Jet/JetRecConfig/share/test_JetDefinitions_properties.py @@ -0,0 +1,58 @@ +# A test of the property setting/getting on JetDefinition classes +# We want the defining attributes on each class to trigger resets of +# derived attributes, such as container names, labels etc + +def printJetConstit(name, jetconstit): + print "{0} constituents".format(name) + print " basetype: {0}".format(jetconstit.basetype) + print " modifiers list: {0}".format(str(jetconstit.modifiers)) + print " label: {0}".format(jetconstit.label) + print " input container: {0}".format(jetconstit.inputname) + print "" + +def printJetDefinition(name, jetdef): + print "{0} jets".format(name) + print " algorithm: {0}".format(jetdef.algorithm) + print " radius: {0}".format(jetdef.radius) + print " input label: {0}".format(jetdef.inputdef.label) + print " basename: {0}".format(jetdef.basename) + print " modifiers list: {0}".format(str(jetdef.modifiers)) + print "" + +# Start with a basic constituent and print some information +from JetRecConfig.JetDefinition import * +CHSPFlow = JetConstit(xAOD.Type.ParticleFlow, []) +printJetConstit("CHSPFlow",CHSPFlow) + +# Now copy and progressively change some of the aspects +from copy import deepcopy +CSSKPFlow = deepcopy(CHSPFlow) +printJetConstit("CSSKPFlow (fresh copy from CHSPFlow)",CSSKPFlow) +CSSKPFlow.modifiers += ["CS","SK"] +printJetConstit("CSSKPFlow (set mods)",CSSKPFlow) + +CSSKLCTopo = deepcopy(CSSKPFlow) +printJetConstit("CSSKLCTopo (fresh copy from CSSKPFlow)",CSSKLCTopo) +CSSKLCTopo.basetype = xAOD.Type.CaloCluster +printJetConstit("CSSKLCTopo (set input type)",CSSKLCTopo) + +# Now we do this with a basic jet definition +AntiKt4EMPFlow = JetDefinition("AntiKt",0.4,CHSPFlow,ptminfilter=10e3) +AntiKt4EMPFlow.modifiers = ["Calib:T0:mc","Sort"] +printJetDefinition("AntiKt4EMPFlow",AntiKt4EMPFlow) + +AntiKt4EMPFlowCSSK = deepcopy(AntiKt4EMPFlow) +printJetDefinition("AntiKt4EMPFlowCSSK (fresh copy from AntiKt4EMPFlow)",AntiKt4EMPFlowCSSK) +AntiKt4EMPFlowCSSK.inputdef = CSSKPFlow +AntiKt4EMPFlowCSSK.modifiers = ["JetConstitFourMomTool"] +printJetDefinition("AntiKt4EMPFlowCSSK (update input def)",AntiKt4EMPFlowCSSK) + +AntiKt10EMPFlowCSSK = deepcopy(AntiKt4EMPFlowCSSK) +printJetDefinition("AntiKt10EMPFlowCSSK (fresh copy from AntiKt4EMPFlowCSSK)",AntiKt10EMPFlowCSSK) +AntiKt10EMPFlowCSSK.radius = 1.0 +printJetDefinition("AntiKt10EMPFlowCSSK (update radius)",AntiKt10EMPFlowCSSK) + +CamKt10EMPFlowCSSK = deepcopy(AntiKt10EMPFlowCSSK) +printJetDefinition("CamKt10EMPFlowCSSK (fresh copy from AntiKt10EMPFlowCSSK)",CamKt10EMPFlowCSSK) +CamKt10EMPFlowCSSK.algorithm = "CamKt" +printJetDefinition("CamKt10EMPFlowCSSK (update radius)",CamKt10EMPFlowCSSK) diff --git a/Reconstruction/Jet/JetRecTools/python/ConstitToolManager.py b/Reconstruction/Jet/JetRecTools/python/ConstitToolManager.py new file mode 100644 index 0000000000000000000000000000000000000000..2c7ce136c1fe80722e22f1405bb176a43027c17b --- /dev/null +++ b/Reconstruction/Jet/JetRecTools/python/ConstitToolManager.py @@ -0,0 +1,135 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +import os +from AthenaCommon import Logging, CfgMgr + + +# ----------------------------------- +# ConstitModifier +# ----------------------------------- +class ConstituentToolManager(object): + """This class is modelled after JetToolManager. + It is intended to be a central place where to + * register constituent modifier tools + * map them to shortcut + * collect them in a mod sequencer tool + This class is provided standalone, but could be merged with JetToolManager if needed. + + and example call could be : + + clustModSeq = ctm.buildConstitModifSequence( 'JetWeightedTopoClusters', + inputName= 'CaloCalTopoClusters', + modList = [ 'clust_weight'] ) + + + """ + + # map of tool names or alias to tool instance + # (there can be multiple entries pointing to the same instance) + modifiersMap = dict() + + # map of named standard list of modifiers + standardModifierLists = dict() + + import ROOT + from ROOT import xAOD + xAOD.Type.ObjectType # Trigger dict load + # map of known input collections to their type + inputContainerMap = dict( CaloCalTopoClusters = xAOD.Type.CaloCluster, CaloTopoClusters = xAOD.Type.CaloCluster, + EMOriginTopoClusters = xAOD.Type.CaloCluster, LCOriginTopoClusters = xAOD.Type.CaloCluster, + InDetTrackParticles = xAOD.Type.TrackParticle, JetETMiss = xAOD.Type.ParticleFlow ) + + log = Logging.logging.getLogger("ConstituentToolManager") + + def add(self, tool, alias=None): + """Register a tool in the manager. If alias is given, the tool is also registered under the alias key""" + name = tool.name() + if name in self.modifiersMap: + self.log.warning("Tool named "+name+" already registered. Not adding a new one") + return self.modifiersMap[name] + if alias is not None and alias in self.modifiersMap: + self.log.warning("Tool named "+alias+" already registered. Not adding a new one under this alias. Was "+name) + return self.modifiersMap[alias] + + from AthenaCommon.AppMgr import ToolSvc + + self.modifiersMap[name] = tool + if alias: self.modifiersMap[alias] = tool + return tool + + + def __iadd__(self, tool): + """Enables the += syntax to add tool """ + self.add(tool) + return self + + def buildConstitModifSequence(self, seqName, OutputContainer , InputContainer, modList, InputType=None): + """Returns a configured JetConstituentModSequence instance. + The tool is build according to + seqName (str) : name of the JetConstituentModSequence tool + OutputContainer (str) : name of desired output constituents container (property of JetConstituentModSequence) + InputContainer (str) : name of input constituents container (property of JetConstituentModSequence) + modList (str or list): if str, this is taken as a shortcut to a knonw, default list of modifier tools (from self.standardModifierLists) + if list, entries are eihter configured modifier tools either strings in which case they are shortcut to known modifier tool (in self.modifiersMap). + InputType : (int or None) the type of particles in the input container. If None attempt is made to guess it from InputContainer (from self.inputContainerMap). + + """ + + #seqName = OutputContainer+'_modSeq' + + # Deal with input ----------------- + if InputType is None: + # get it from the known inputs + InputType = self.inputContainerMap[ InputContainer ] + if InputType is None: + self.log.error( seqName+'. Unknown input container : '+InputContainer ) + return + + # deal with modifiers --------------- + if isinstance(modList, str): + modKey = modList + # translate into a known list : + modList = self.standardModifierLists.get( modKey , None) + if modList is None : + self.log.error( seqName+". Unknown shortcut for constit modifier list : "+modKey) + return None + # loop over modList + finalList = [] + for t in modList: + if isinstance(t,str): + # translate into a real tool + tool = self.modifiersMap.get(t,None) + if tool is None: + self.log.error( seqName+". Unknown shortcut for constit modifier list : "+t) + return None + t = tool + t.InputType = InputType + # append to the final list + finalList.append( t ) + + constModSeq = CfgMgr.JetConstituentModSequence( seqName, # the name of the tool + InputContainer = InputContainer, + OutputContainer = OutputContainer, + InputType = InputType, + Modifiers = finalList, # pass the list of modifier we want + ) + self += constModSeq + + return constModSeq + + +# ----------------------------------- +# the main ConstituentToolManager instance +ctm = ConstituentToolManager() +# ----------------------------------- + +# ----------------------------------- +# add standard tools to ctm +ctm.add( CfgMgr.SoftKillerWeightTool("JetConstit_SoftKiller", SKGridSize=0.6) , + alias = 'softkiller' ) + +ctm.add( CfgMgr.ClusterAtEMScaleTool("JetConstit_ClusEM") , + alias = 'clus_emscale' ) + +ctm.add( CfgMgr.CaloClusterConstituentsOrigin("JetConstit_ClusOrigin") , + alias = 'clus_origin' ) diff --git a/Reconstruction/Jet/JetRecTools/python/DefaultTools.py b/Reconstruction/Jet/JetRecTools/python/DefaultTools.py deleted file mode 100644 index e34be27b9704ac484115dba544284e90ed23f90d..0000000000000000000000000000000000000000 --- a/Reconstruction/Jet/JetRecTools/python/DefaultTools.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration - - -def declareDefaultTools(): - from JetRecConfig.JetRecFlags import jetFlags - from JetRecConfig.JetRecStandardToolManager import jtm - from JetRec.JetRecConf import PseudoJetGetter - - #-------------------------------------------------------------- - # Pseudojet builders. - #-------------------------------------------------------------- - - # Prepare a sequence of input constituent modifiers - from JetRecToolsConfig import ctm - jtm += ctm.buildConstitModifSequence( "JetConstitSeq_LCOrigin", - OutputContainer='LCOriginTopoClusters', - InputContainer= 'CaloCalTopoClusters', - modList = [ 'clus_origin' ] ) - - jtm += ctm.buildConstitModifSequence( "JetConstitSeq_EMOrigin", - OutputContainer='EMOriginTopoClusters', - InputContainer= 'CaloCalTopoClusters', - modList = [ 'clus_emscale', 'clus_origin' ] ) - - jtm += PseudoJetGetter( - "lcoriginget", - InputContainer = jtm.JetConstitSeq_LCOrigin.OutputContainer, - Label = "LCTopoOrigin", - OutputContainer = jtm.JetConstitSeq_LCOrigin.OutputContainer+"PseudoJet", - SkipNegativeEnergy = True, - GhostScale = 0.0 - ) - - jtm += PseudoJetGetter( - "emoriginget", - InputContainer = jtm.JetConstitSeq_EMOrigin.OutputContainer, - Label = "EMTopoOrigin", - OutputContainer = jtm.JetConstitSeq_EMOrigin.OutputContainer+"PseudoJet", - SkipNegativeEnergy = True, - GhostScale = 0.0 - ) diff --git a/Reconstruction/Jet/JetRecTools/python/JetRecToolsConfig.py b/Reconstruction/Jet/JetRecTools/python/JetRecToolsConfig.py index 05d7554f12265efd050c635ad023bf9aa88a842d..e52d62176e5b48898a104e35b8d9883dc0568b3a 100644 --- a/Reconstruction/Jet/JetRecTools/python/JetRecToolsConfig.py +++ b/Reconstruction/Jet/JetRecTools/python/JetRecToolsConfig.py @@ -1,166 +1,54 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration - -import os -from AthenaCommon import Logging, CfgMgr - -## # ------------------------------------------------ -## # Bad/Missing Cells list creation -## jtm += MissingCellListTool("MissingCellListTool", -## AddBadCells = True, -## ) -## # ------------------------------------------------ - -# Bad channel correction tools -def badChanInputHistoHelper(): - # keep it as a function for now : might be easier to deal with when - # root-only config will be needed. - # new setup for THistService - dataPathList = os.environ[ 'DATAPATH' ].split(os.pathsep) - dataPathList.insert(0, os.curdir) - from AthenaCommon.Utils.unixtools import FindFile - RefFileName = FindFile( "JetBadChanCorrTool.root" ,dataPathList, os.R_OK ) - - - from AthenaCommon.AppMgr import ServiceMgr - if not hasattr(ServiceMgr, 'THistSvc'): - from GaudiSvc.GaudiSvcConf import THistSvc - ServiceMgr += THistSvc() - ServiceMgr.THistSvc.Input += ["JetBadChanCorrTool DATAFILE=\'%s\' OPT=\'READ\'" % RefFileName] - badChanInputHistoHelper.called = True - - - badChanInputHistoHelper() - from JetRec.JetRecStandard import jtm - jtm += CfgMgr.JetBadChanCorrTool("JetBadChanCorrTool", MissingCellMap="MissingCaloCellsMap") - - -# ----------------------------------- -# ConstitModifier -# ----------------------------------- -class ConstituentToolManager(object): - """This class is modelled after JetToolManager. - It is intended to be a central place where to - * register constituent modifier tools - * map them to shortcut - * collect them in a mod sequencer tool - This class is provided standalone, but could be merged with JetToolManager if needed. - - and example call could be : - - clustModSeq = ctm.buildConstitModifSequence( 'JetWeightedTopoClusters', - inputName= 'CaloCalTopoClusters', - modList = [ 'clust_weight'] ) - - - """ - - # map of tool names or alias to tool instance - # (there can be multiple entries pointing to the same instance) - modifiersMap = dict() - - # map of named standard list of modifiers - standardModifierLists = dict() - - import ROOT - from ROOT import xAOD - xAOD.Type.ObjectType # Trigger dict load - # map of known input collections to their type - inputContainerMap = dict( CaloCalTopoClusters = xAOD.Type.CaloCluster, CaloTopoClusters = xAOD.Type.CaloCluster, - EMOriginTopoClusters = xAOD.Type.CaloCluster, LCOriginTopoClusters = xAOD.Type.CaloCluster, - InDetTrackParticles = xAOD.Type.TrackParticle, JetETMiss = xAOD.Type.ParticleFlow ) - - log = Logging.logging.getLogger("ConstituentToolManager") - - def add(self, tool, alias=None): - """Register a tool in the manager. If alias is given, the tool is also registered under the alias key""" - name = tool.name() - if name in self.modifiersMap: - self.log.warning("Tool named "+name+" already registered. Not adding a new one") - return self.modifiersMap[name] - if alias is not None and alias in self.modifiersMap: - self.log.warning("Tool named "+alias+" already registered. Not adding a new one under this alias. Was "+name) - return self.modifiersMap[alias] - - from AthenaCommon.AppMgr import ToolSvc - - self.modifiersMap[name] = tool - if alias: self.modifiersMap[alias] = tool - return tool - - - def __iadd__(self, tool): - """Enables the += syntax to add tool """ - self.add(tool) - return self - - def buildConstitModifSequence(self, seqName, OutputContainer , InputContainer, modList, InputType=None): - """Returns a configured JetConstituentModSequence instance. - The tool is build according to - seqName (str) : name of the JetConstituentModSequence tool - OutputContainer (str) : name of desired output constituents container (property of JetConstituentModSequence) - InputContainer (str) : name of input constituents container (property of JetConstituentModSequence) - modList (str or list): if str, this is taken as a shortcut to a knonw, default list of modifier tools (from self.standardModifierLists) - if list, entries are eihter configured modifier tools either strings in which case they are shortcut to known modifier tool (in self.modifiersMap). - InputType : (int or None) the type of particles in the input container. If None attempt is made to guess it from InputContainer (from self.inputContainerMap). - - """ - - #seqName = OutputContainer+'_modSeq' - - # Deal with input ----------------- - if InputType is None: - # get it from the known inputs - InputType = self.inputContainerMap[ InputContainer ] - if InputType is None: - self.log.error( seqName+'. Unknown input container : '+InputContainer ) - return - - # deal with modifiers --------------- - if isinstance(modList, str): - modKey = modList - # translate into a known list : - modList = self.standardModifierLists.get( modKey , None) - if modList is None : - self.log.error( seqName+". Unknown shortcut for constit modifier list : "+modKey) - return None - # loop over modList - finalList = [] - for t in modList: - if isinstance(t,str): - # translate into a real tool - tool = self.modifiersMap.get(t,None) - if tool is None: - self.log.error( seqName+". Unknown shortcut for constit modifier list : "+t) - return None - t = tool - t.InputType = InputType - # append to the final list - finalList.append( t ) - - constModSeq = CfgMgr.JetConstituentModSequence( seqName, # the name of the tool - InputContainer = InputContainer, - OutputContainer = OutputContainer, - InputType = InputType, - Modifiers = finalList, # pass the list of modifier we want - ) - self += constModSeq - - return constModSeq - - -# ----------------------------------- -# the main ConstituentToolManager instance -ctm = ConstituentToolManager() -# ----------------------------------- - -# ----------------------------------- -# add standard tools to ctm -ctm.add( CfgMgr.SoftKillerWeightTool("JetConstit_SoftKiller", SKGridSize=0.6) , - alias = 'softkiller' ) - -ctm.add( CfgMgr.ClusterAtEMScaleTool("JetConstit_ClusEM") , - alias = 'clus_emscale' ) - -ctm.add( CfgMgr.CaloClusterConstituentsOrigin("JetConstit_ClusOrigin") , - alias = 'clus_origin' ) +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +######################################################################## +# # +# JetModConfig: A helper module for configuring tools that support # +# jet reconstruction # +# Author: TJ Khoo # +# # +######################################################################## + +from AthenaCommon import Logging +jrtlog = Logging.logging.getLogger('JetRecToolsConfig') + +# Package configurable imports +from InDetTrackSelectionTool import InDetTrackSelectionToolConf +from TrackVertexAssociationTool import TrackVertexAssociationToolConf +from JetRecTools import JetRecToolsConf + +# Could be made more configurable, +# e.g. specify CutLevel via modspec +def getTrackSelTool(): + # Track selector needs its own hierarchical config getter in JetRecTools? + idtrackselloose = InDetTrackSelectionToolConf.InDet__InDetTrackSelectionTool( + "idtrackselloose", + CutLevel = "Loose", + minPt = 500 + ) + jettrackselloose = JetRecToolsConf.JetTrackSelectionTool( + "jettrackselloose", + InputContainer = "InDetTrackParticles", + OutputContainer = "JetSelectedTracks", + Selector = idtrackselloose + ) + return jettrackselloose + +# Could be made more configurable, +# e.g. specify association type +def getTrackVertexAssocTool(): + # Track-vertex association + # In R21 and prior this was the "tight" tool, but that performed poorly + # In fact, keeping it "tight" in R21 was a mistake + # idtvassoc = getUniquePublicTool(algseq,"CP::LooseTrackVertexAssociationTool", + # "idloosetvassoc") + idtvassoc = TrackVertexAssociationToolConf.CP__TightTrackVertexAssociationTool("idtighttvassoc") + + jettvassoc = JetRecToolsConf.TrackVertexAssociationTool( + "jettvassoc", + TrackParticleContainer = "InDetTrackParticles", + TrackVertexAssociation = "JetTrackVtxAssoc", + VertexContainer = "PrimaryVertices", + TrackVertexAssoTool = idtvassoc, + ) + return jettvassoc