Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-07-23 02:26:12

0001 from __future__ import absolute_import
0002 from builtins import range
0003 import os
0004 import copy
0005 import collections
0006 
0007 import ROOT
0008 ROOT.gROOT.SetBatch(True)
0009 ROOT.PyConfig.IgnoreCommandLineOptions = True
0010 
0011 from .plotting import Subtract, FakeDuplicate, CutEfficiency, Transform, AggregateBins, ROC, Plot, PlotEmpty, PlotGroup, PlotOnSideGroup, PlotFolder, Plotter
0012 from .html import PlotPurpose
0013 from . import plotting
0014 from . import validation
0015 from . import html
0016 
0017 ########################################
0018 #
0019 # Per track collection plots
0020 #
0021 ########################################
0022 
0023 _maxEff = [0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 0.8, 1.025, 1.2, 1.5, 2]
0024 _maxFake = [0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 0.8, 1.025]
0025 
0026 #_minMaxResol = [1e-5, 2e-5, 5e-5, 1e-4, 2e-4, 5e-4, 1e-3, 2e-3, 5e-3, 1e-2, 2e-2, 5e-2, 0.1, 0.2, 0.5, 1]
0027 _minMaxResol = [1e-5, 4e-5, 1e-4, 4e-4, 1e-3, 4e-3, 1e-2, 4e-2, 0.1, 0.4, 1]
0028 _minMaxN = [5e-1, 5, 5e1, 5e2, 5e3, 5e4, 5e5, 5e6, 5e7, 5e8, 5e9]
0029 
0030 _minHits = [0, 5, 10]
0031 _maxHits = [5, 10, 20, 40, 60, 80]
0032 _minLayers = [0, 5, 10]
0033 _maxLayers = [5, 10, 25]
0034 _maxPixelLayers = 8
0035 _min3DLayers = [0, 5, 10]
0036 _max3DLayers = [5, 10, 20]
0037 _minZ = [-60, -40, -20, -10, -5]
0038 _maxZ = [5, 10, 20, 40, 60]
0039 _minPU = [0, 10, 20, 50, 100, 150]
0040 _maxPU = [20, 50, 65, 80, 100, 150, 200, 250]
0041 _minMaxTracks = [0, 200, 500, 1000, 1500, 2000]
0042 _minMaxMVA = [-1.025, -0.5, 0, 0.5, 1.025]
0043 _maxDRJ = 0.1
0044 
0045 def _minMaxResidual(ma):
0046     return ([-x for x in ma], ma)
0047 
0048 (_minResidualPhi, _maxResidualPhi) = _minMaxResidual([1e-4, 2e-4]) # rad
0049 (_minResidualCotTheta, _maxResidualCotTheta) = _minMaxResidual([1e-4, 2e-4])
0050 (_minResidualDxy, _maxResidualDxy) = _minMaxResidual([10, 20, 50, 100]) # um
0051 (_minResidualDz, _maxResidualDz) = (_minResidualDxy, _maxResidualDxy)
0052 (_minResidualPt, _maxResidualPt) = _minMaxResidual([1, 1.5, 2, 5]) # %
0053 
0054 
0055 _legendDy_1row = 0.46
0056 _legendDy_2rows = -0.025
0057 _legendDy_2rows_3cols = -0.17
0058 _legendDy_4rows = 0.09
0059 
0060 # Ok, because of the way the "reference release" histograms are
0061 # stored, this histogram is not accessible for the summary plots. To
0062 # be fixed later with (large) reorganization of how things work.
0063 #_trackingNumberOfEventsHistogram = "DQMData/Run 1/Tracking/Run summary/Track/general_trackingParticleRecoAsssociation/tracks"
0064 
0065 _trackingIterationOrderHistogram = "DQMData/Run 1/Tracking/Run summary/TrackBuilding/num_reco_coll"
0066 
0067 def _makeEffFakeDupPlots(postfix, quantity, unit="", common={}, effopts={}, fakeopts={}):
0068     p = postfix
0069     q = quantity
0070     xq = q
0071     if unit != "":
0072         xq += " (" + unit + ")"
0073 
0074     effargs  = dict(xtitle="TP "+xq   , ytitle="efficiency vs "+q          , ymax=_maxEff)
0075     fakeargs = dict(xtitle="track "+xq, ytitle="fake+duplicates rate vs "+q, ymax=_maxFake)
0076     effargs.update(common)
0077     fakeargs.update(common)
0078     effargs.update(effopts)
0079     fakeargs.update(fakeopts)
0080 
0081     return [
0082         Plot("effic_vs_"+p, **effargs),
0083         Plot(FakeDuplicate("fakeduprate_vs_"+p, assoc="num_assoc(recoToSim)_"+p, dup="num_duplicate_"+p, reco="num_reco_"+p, title="fake+duplicates vs "+q), **fakeargs)
0084     ]
0085 
0086 def _makeFakeDupPileupPlots(postfix, quantity, unit="", xquantity="", xtitle=None, common={}):
0087     p = postfix
0088     q = quantity
0089     if xtitle is None:
0090         if xquantity != "":
0091             xq = xquantity
0092         else:
0093             xq = q
0094             if unit != "":
0095                 xq += " (" + unit + ")"
0096         xtitle="track "+xq
0097 
0098     return [
0099         Plot("fakerate_vs_"+p   , xtitle=xtitle, ytitle="fakerate vs "+q       , ymax=_maxFake, **common),
0100         Plot("duplicatesRate_"+p, xtitle=xtitle, ytitle="duplicates rate vs "+q, ymax=_maxFake, **common),
0101         Plot("pileuprate_"+p    , xtitle=xtitle, ytitle="pileup rate vs "+q    , ymax=_maxFake, **common),
0102     ]
0103 
0104 def _makeFakeDist(postfix):
0105     return Subtract("num_fake_"+postfix, "num_reco_"+postfix, "num_assoc(recoToSim)_"+postfix)
0106 
0107 def _makeDistPlots(postfix, quantity, common={}):
0108     p = postfix
0109     q = quantity
0110 
0111     args = dict(xtitle="track "+q, ylog=True, ymin=_minMaxN, ymax=_minMaxN)
0112     args.update(common)
0113 
0114     return [
0115         Plot("num_reco_"+p            , ytitle="tracks", **args),
0116         Plot("num_assoc(recoToSim)_"+p, ytitle="true tracks", **args),
0117         Plot(_makeFakeDist(p), ytitle="fake tracks", **args),
0118         Plot("num_duplicate_"+p       , ytitle="duplicate tracks", **args),
0119     ]
0120 
0121 def _makeDistSimPlots(postfix, quantity, common={}):
0122     p = postfix
0123     q = quantity
0124 
0125     args = dict(xtitle="TP "+q, ylog=True, ymin=_minMaxN, ymax=_minMaxN)
0126     args.update(common)
0127 
0128     return [
0129         Plot("num_simul_"+p            , ytitle="TrackingParticles", **args),
0130         Plot("num_assoc(simToReco)_"+p, ytitle="Reconstructed TPs", **args),
0131     ]
0132 
0133 def _makeMVAPlots(num, hp=False):
0134     pfix = "_hp" if hp else ""
0135     pfix2 = "Hp" if hp else ""
0136 
0137     xtitle = "MVA%d output"%num
0138     xtitlecut = "Cut on MVA%d output"%num
0139     args = dict(xtitle=xtitle, ylog=True, ymin=_minMaxN, ymax=_minMaxN)
0140 
0141     argsroc = dict(
0142         xtitle="Efficiency (excl. trk eff)", ytitle="Fake rate",
0143         xmax=_maxEff, ymax=_maxFake,
0144         drawStyle="EP",
0145     )
0146     argsroc2 = dict(
0147         ztitle="Cut on MVA%d"%num,
0148         xtitleoffset=5, ytitleoffset=6.5, ztitleoffset=4,
0149         adjustMarginRight=0.12
0150     )
0151     argsroc2.update(argsroc)
0152     argsroc2["drawStyle"] = "pcolz"
0153 
0154     argsprofile = dict(ymin=_minMaxMVA, ymax=_minMaxMVA)
0155 
0156     true_cuteff = CutEfficiency("trueeff_vs_mva%dcut%s"%(num,pfix), "num_assoc(recoToSim)_mva%dcut%s"%(num,pfix))
0157     fake_cuteff = CutEfficiency("fakeeff_vs_mva%dcut%s"%(num,pfix), Subtract("num_fake_mva%dcut%s"%(num,pfix), "num_reco_mva%dcut%s"%(num,pfix), "num_assoc(recoToSim)_mva%dcut%s"%(num,pfix)))
0158 
0159     return [
0160         PlotGroup("mva%d%s"%(num,pfix2), [
0161             Plot("num_assoc(recoToSim)_mva%d%s"%(num,pfix), ytitle="true tracks", **args),
0162             Plot(Subtract("num_fake_mva%d%s"%(num,pfix), "num_reco_mva%d%s"%(num,pfix), "num_assoc(recoToSim)_mva%d%s"%(num,pfix)), ytitle="fake tracks", **args),
0163             Plot("effic_vs_mva%dcut%s"%(num,pfix), xtitle=xtitlecut, ytitle="Efficiency (excl. trk eff)", ymax=_maxEff),
0164             #
0165             Plot("fakerate_vs_mva%dcut%s"%(num,pfix), xtitle=xtitlecut, ytitle="Fake rate", ymax=_maxFake),
0166             Plot(ROC("effic_vs_fake_mva%d%s"%(num,pfix), "effic_vs_mva%dcut%s"%(num,pfix), "fakerate_vs_mva%dcut%s"%(num,pfix)), **argsroc),
0167             Plot(ROC("effic_vs_fake_mva%d%s"%(num,pfix), "effic_vs_mva%dcut%s"%(num,pfix), "fakerate_vs_mva%dcut%s"%(num,pfix), zaxis=True), **argsroc2),
0168             # Same signal efficiency, background efficiency, and ROC definitions as in TMVA
0169             Plot(true_cuteff, xtitle=xtitlecut, ytitle="True track selection efficiency", ymax=_maxEff),
0170             Plot(fake_cuteff, xtitle=xtitlecut, ytitle="Fake track selection efficiency", ymax=_maxEff),
0171             Plot(ROC("true_eff_vs_fake_rej_mva%d%s"%(num,pfix), true_cuteff, Transform("fake_rej_mva%d%s"%(num,pfix), fake_cuteff, lambda x: 1-x)), xtitle="True track selection efficiency", ytitle="Fake track rejection", xmax=_maxEff, ymax=_maxEff),
0172         ], ncols=3, legendDy=_legendDy_1row),
0173         PlotGroup("mva%d%sPtEta"%(num,pfix2), [
0174             Plot("mva_assoc(recoToSim)_mva%d%s_pT"%(num,pfix), xtitle="Track p_{T} (GeV)", ytitle=xtitle+" for true tracks", xlog=True, **argsprofile),
0175             Plot("mva_fake_mva%d%s_pT"%(num,pfix), xtitle="Track p_{T} (GeV)", ytitle=xtitle+" for fake tracks", xlog=True, **argsprofile),
0176             Plot("mva_assoc(recoToSim)_mva%d%s_eta"%(num,pfix), xtitle="Track #eta", ytitle=xtitle+" for true tracks", **argsprofile),
0177             Plot("mva_fake_mva%d%s_eta"%(num,pfix), xtitle="Track #eta", ytitle=xtitle+" for fake tracks", **argsprofile),
0178         ], legendDy=_legendDy_2rows)
0179     ]
0180 
0181 _effandfakePtEtaPhi = PlotGroup("effandfakePtEtaPhi", [
0182     Plot("efficPt", title="Efficiency vs p_{T}", xtitle="TP p_{T} (GeV)", ytitle="efficiency vs p_{T}", xlog=True, ymax=_maxEff),
0183     Plot(FakeDuplicate("fakeduprate_vs_pT", assoc="num_assoc(recoToSim)_pT", dup="num_duplicate_pT", reco="num_reco_pT", title="fake+duplicates vs p_{T}"),
0184          xtitle="track p_{T} (GeV)", ytitle="fake+duplicates rate vs p_{T}", ymax=_maxFake, xlog=True),
0185     Plot("effic", xtitle="TP #eta", ytitle="efficiency vs #eta", title="", ymax=_maxEff),
0186     Plot(FakeDuplicate("fakeduprate_vs_eta", assoc="num_assoc(recoToSim)_eta", dup="num_duplicate_eta", reco="num_reco_eta", title=""),
0187          xtitle="track #eta", ytitle="fake+duplicates rate vs #eta", ymax=_maxFake),
0188 ] +
0189     _makeEffFakeDupPlots("phi", "#phi")
0190 )
0191 
0192 _effandfakeDxyDzBS = PlotGroup("effandfakeDxyDzBS",
0193                                _makeEffFakeDupPlots("dxy"  , "dxy"    , "cm") +
0194                                _makeEffFakeDupPlots("dz"   , "dz"     , "cm"),
0195                                legendDy=_legendDy_2rows
0196 )
0197 _effandfakeDxyDzPV = PlotGroup("effandfakeDxyDzPV",
0198                                _makeEffFakeDupPlots("dxypv"       , "dxy(PV)", "cm") +
0199                                _makeEffFakeDupPlots("dxypv_zoomed", "dxy(PV)", "cm") +
0200                                _makeEffFakeDupPlots("dzpv"        , "dz(PV)" , "cm") +
0201                                _makeEffFakeDupPlots("dzpv_zoomed" , "dz(PV)" , "cm"),
0202                                legendDy=_legendDy_4rows
0203 )
0204 _effandfakeHitsLayers = PlotGroup("effandfakeHitsLayers",
0205                                   _makeEffFakeDupPlots("hit"       , "hits"        , common=dict(xmin=_minHits    , xmax=_maxHits)) +
0206                                   _makeEffFakeDupPlots("layer"     , "layers"      , common=dict(xmin=_minLayers  , xmax=_maxLayers)) +
0207                                   _makeEffFakeDupPlots("pixellayer", "pixel layers", common=dict(                   xmax=_maxPixelLayers)) +
0208                                   _makeEffFakeDupPlots("3Dlayer"   , "3D layers"   , common=dict(xmin=_min3DLayers, xmax=_max3DLayers)),
0209                                   legendDy=_legendDy_4rows
0210 )
0211 _common = {"ymin": 0, "ymax": _maxEff}
0212 _effandfakePos = PlotGroup("effandfakePos",
0213                            _makeEffFakeDupPlots("vertpos", "vert r", "cm", fakeopts=dict(xtitle="track ref. point r (cm)", ytitle="fake+duplicates vs. r"), common=dict(xlog=True)) +
0214                            _makeEffFakeDupPlots("zpos"   , "vert z", "cm", fakeopts=dict(xtitle="track ref. point z (cm)", ytitle="fake+duplicates vs. z")) +
0215                            _makeEffFakeDupPlots("simpvz" , "Sim. PV z", "cm", common=dict(xtitle="Sim. PV z (cm)", xmin=_minZ, xmax=_maxZ))
0216 )
0217 _effandfakeDeltaRPU = PlotGroup("effandfakeDeltaRPU",
0218                                 _makeEffFakeDupPlots("dr"     , "#DeltaR", effopts=dict(xtitle="TP min #DeltaR"), fakeopts=dict(xtitle="track min #DeltaR"), common=dict(xlog=True)) +
0219                                 _makeEffFakeDupPlots("drj" , "#DeltaR(track, jet)", effopts=dict(xtitle="#DeltaR(TP, jet)", ytitle="efficiency vs #DeltaR(TP, jet"), fakeopts=dict(xtitle="#DeltaR(track, jet)"), common=dict(xlog=True, xmax=_maxDRJ))+
0220                                 _makeEffFakeDupPlots("pu"     , "PU"     , common=dict(xtitle="Pileup", xmin=_minPU, xmax=_maxPU)),
0221                                 legendDy=_legendDy_4rows
0222 )
0223 
0224 
0225 _algos_common = dict(removeEmptyBins=True, xbinlabelsize=10, xbinlabeloption="d")
0226 _duplicateAlgo = PlotOnSideGroup("duplicateAlgo", Plot("duplicates_oriAlgo_vs_oriAlgo", drawStyle="COLZ", adjustMarginLeft=0.1, adjustMarginRight=0.1, **_algos_common))
0227 
0228 _dupandfakePtEtaPhi = PlotGroup("dupandfakePtEtaPhi", [
0229     Plot("fakeratePt", xtitle="track p_{T} (GeV)", ytitle="fakerate vs p_{T}", xlog=True, ymax=_maxFake),
0230     Plot("duplicatesRate_Pt", xtitle="track p_{T} (GeV)", ytitle="duplicates rate vs p_{T}", ymax=_maxFake, xlog=True),
0231     Plot("pileuprate_Pt", xtitle="track p_{T} (GeV)", ytitle="pileup rate vs p_{T}", ymax=_maxFake, xlog=True),
0232     Plot("fakerate", xtitle="track #eta", ytitle="fakerate vs #eta", title="", ymax=_maxFake),
0233     Plot("duplicatesRate", xtitle="track #eta", ytitle="duplicates rate vs #eta", title="", ymax=_maxFake),
0234     Plot("pileuprate", xtitle="track #eta", ytitle="pileup rate vs #eta", title="", ymax=_maxFake),
0235 ] + _makeFakeDupPileupPlots("phi", "#phi"),
0236                          ncols=3
0237 )
0238 _dupandfakeDxyDzBS = PlotGroup("dupandfakeDxyDzBS",
0239                                _makeFakeDupPileupPlots("dxy"  , "dxy"    , "cm") +
0240                                _makeFakeDupPileupPlots("dz"   , "dz"     , "cm"),
0241                                ncols=3, legendDy=_legendDy_2rows_3cols
0242 )
0243 _dupandfakeDxyDzPV = PlotGroup("dupandfakeDxyDzPV",
0244                                _makeFakeDupPileupPlots("dxypv"       , "dxy(PV)", "cm") +
0245                                _makeFakeDupPileupPlots("dxypv_zoomed", "dxy(PV)", "cm") +
0246                                _makeFakeDupPileupPlots("dzpv"        , "dz(PV)" , "cm") +
0247                                _makeFakeDupPileupPlots("dzpv_zoomed" , "dz(PV)" , "cm"),
0248                                ncols=3, legendDy=_legendDy_4rows
0249 )
0250 _dupandfakeHitsLayers = PlotGroup("dupandfakeHitsLayers",
0251                                   _makeFakeDupPileupPlots("hit"       , "hits"        , common=dict(xmin=_minHits    , xmax=_maxHits)) +
0252                                   _makeFakeDupPileupPlots("layer"     , "layers"      , common=dict(xmin=_minLayers  , xmax=_maxLayers)) +
0253                                   _makeFakeDupPileupPlots("pixellayer", "pixel layers", common=dict(                   xmax=_maxPixelLayers)) +
0254                                   _makeFakeDupPileupPlots("3Dlayer"   , "3D layers"   , common=dict(xmin=_min3DLayers, xmax=_max3DLayers)),
0255                                   ncols=3, legendDy=_legendDy_4rows
0256 )
0257 _dupandfakePos = PlotGroup("dupandfakePos",
0258                            _makeFakeDupPileupPlots("vertpos", "r", "cm", xquantity="ref. point r (cm)", common=dict(xlog=True)) +
0259                            _makeFakeDupPileupPlots("zpos"   , "z", "cm", xquantity="ref. point z (cm)") +
0260                            _makeFakeDupPileupPlots("simpvz" , "Sim. PV z", xtitle="Sim. PV z (cm)", common=dict(xmin=_minZ, xmax=_maxZ)),
0261                            ncols=3,
0262 )
0263 _dupandfakeDeltaRPU = PlotGroup("dupandfakeDeltaRPU",
0264                                 _makeFakeDupPileupPlots("dr"     , "#DeltaR", xquantity="min #DeltaR", common=dict(xlog=True)) +
0265                                 _makeFakeDupPileupPlots("drj"     , "#DeltaR(track, jet)", xtitle="#DeltaR(track, jet)", common=dict(xlog=True, xmax=_maxDRJ)) +
0266                                 _makeFakeDupPileupPlots("pu"     , "PU"     , xtitle="Pileup", common=dict(xmin=_minPU, xmax=_maxPU)),
0267                                 ncols=3
0268 )
0269 _seedingLayerSet_common = dict(removeEmptyBins=True, xbinlabelsize=8, xbinlabeloption="d", adjustMarginRight=0.1)
0270 _dupandfakeSeedingPlots = _makeFakeDupPileupPlots("seedingLayerSet", "seeding layers", xtitle="", common=_seedingLayerSet_common)
0271 _dupandfakeChi2Seeding = PlotGroup("dupandfakeChi2Seeding",
0272                                    _makeFakeDupPileupPlots("chi2", "#chi^{2}") +
0273                                    _dupandfakeSeedingPlots,
0274                                    ncols=3, legendDy=_legendDy_2rows_3cols
0275 )
0276 
0277 _common = {
0278     "ytitle": "Fake+pileup rate",
0279     "ymax": _maxFake,
0280     "drawStyle": "EP",
0281 }
0282 _common2 = {}
0283 _common2.update(_common)
0284 _common2["drawStyle"] = "pcolz"
0285 _common2["ztitleoffset"] = 1.5
0286 _common2["xtitleoffset"] = 7
0287 _common2["ytitleoffset"] = 10
0288 _common2["ztitleoffset"] = 6
0289 _pvassociation1 = PlotGroup("pvassociation1", [
0290     Plot(ROC("effic_vs_fakepileup_dzpvcut", "effic_vs_dzpvcut", FakeDuplicate("fakepileup_vs_dzpvcut", assoc="num_assoc(recoToSim)_dzpvcut", reco="num_reco_dzpvcut", dup="num_pileup_dzpvcut")),
0291              xtitle="Efficiency vs. cut on dz(PV)", **_common),
0292     Plot(ROC("effic_vs_fakepileup2_dzpvcut", "effic_vs_dzpvcut", FakeDuplicate("fakepileup_vs_dzpvcut", assoc="num_assoc(recoToSim)_dzpvcut", reco="num_reco_dzpvcut", dup="num_pileup_dzpvcut"), zaxis=True),
0293              xtitle="Efficiency", ztitle="Cut on dz(PV)", **_common2),
0294     #
0295     Plot(ROC("effic_vs_fakepileup_dzpvsigcut",  "effic_vs_dzpvsigcut", FakeDuplicate("fakepileup_vs_dzpvsigcut", assoc="num_assoc(recoToSim)_dzpvsigcut", reco="num_reco_dzpvsigcut", dup="num_pileup_dzpvsigcut")),
0296              xtitle="Efficiency vs. cut on dz(PV)/dzError", **_common),
0297     Plot(ROC("effic_vs_fakepileup2_dzpvsigcut",  "effic_vs_dzpvsigcut", FakeDuplicate("fakepileup_vs_dzpvsigcut", assoc="num_assoc(recoToSim)_dzpvsigcut", reco="num_reco_dzpvsigcut", dup="num_pileup_dzpvsigcut"), zaxis=True),
0298              xtitle="Efficiency", ztitle="Cut on dz(PV)/dzError", **_common2),
0299 ], onlyForPileup=True,
0300                          legendDy=_legendDy_4rows
0301 )
0302 _pvassociation2 = PlotGroup("pvassociation2", [
0303     Plot("effic_vs_dzpvcut", xtitle="Cut on dz(PV) (cm)", ytitle="Efficiency vs. cut on dz(PV)", ymax=_maxEff),
0304     Plot("effic_vs_dzpvcut2", xtitle="Cut on dz(PV) (cm)", ytitle="Efficiency (excl. trk eff)", ymax=_maxEff),
0305     Plot("fakerate_vs_dzpvcut", xtitle="Cut on dz(PV) (cm)", ytitle="Fake rate vs. cut on dz(PV)", ymax=_maxFake),
0306     Plot("pileuprate_dzpvcut", xtitle="Cut on dz(PV) (cm)", ytitle="Pileup rate vs. cut on dz(PV)", ymax=_maxFake),
0307     #
0308     Plot("effic_vs_dzpvsigcut", xtitle="Cut on dz(PV)/dzError", ytitle="Efficiency vs. cut on dz(PV)/dzError", ymax=_maxEff),
0309     Plot("effic_vs_dzpvsigcut2", xtitle="Cut on dz(PV)/dzError", ytitle="Efficiency (excl. trk eff)", ymax=_maxEff),
0310     Plot("fakerate_vs_dzpvsigcut", xtitle="Cut on dz(PV)/dzError", ytitle="Fake rate vs. cut on dz(PV)/dzError", ymax=_maxFake),
0311     Plot("pileuprate_dzpvsigcut", xtitle="Cut on dz(PV)/dzError", ytitle="Pileup rate vs. cut on dz(PV)/dzError", ymax=_maxFake),
0312 ], onlyForPileup=True,
0313                          legendDy=_legendDy_4rows
0314 )
0315 
0316 
0317 # These don't exist in FastSim
0318 _common = {"normalizeToUnitArea": True, "stat": True, "drawStyle": "hist"}
0319 _dedx = PlotGroup("dedx", [
0320     Plot("h_dedx_estim1", xtitle="dE/dx, harm2", **_common),
0321     Plot("h_dedx_estim2", xtitle="dE/dx, trunc40", **_common),
0322     Plot("h_dedx_nom1", xtitle="dE/dx number of measurements", title="", **_common),
0323     Plot("h_dedx_sat1", xtitle="dE/dx number of measurements with saturation", title="", **_common),
0324     ],
0325                   legendDy=_legendDy_2rows
0326 )
0327 
0328 _chargemisid = PlotGroup("chargemisid", [
0329     Plot("chargeMisIdRate", xtitle="#eta", ytitle="charge mis-id rate vs #eta", ymax=0.05),
0330     Plot("chargeMisIdRate_Pt", xtitle="p_{T}", ytitle="charge mis-id rate vs p_{T}", xmax=300, ymax=0.1, xlog=True),
0331     Plot("chargeMisIdRate_hit", xtitle="hits", ytitle="charge mis-id rate vs hits", title=""),
0332     Plot("chargeMisIdRate_phi", xtitle="#phi", ytitle="charge mis-id rate vs #phi", title="", ymax=0.01),
0333     Plot("chargeMisIdRate_dxy", xtitle="dxy", ytitle="charge mis-id rate vs dxy", ymax=0.1),
0334     Plot("chargeMisIdRate_dz", xtitle="dz", ytitle="charge mis-id rate vs dz", ymax=0.1)
0335 ])
0336 _common = {"stat": True, "normalizeToUnitArea": True, "ylog": True, "ymin": 1e-6, "drawStyle": "hist"}
0337 _hitsAndPt = PlotGroup("hitsAndPt", [
0338     Plot("missing_inner_layers", xmin=_minLayers, xmax=_maxLayers, ymax=1, **_common),
0339     Plot("missing_outer_layers", xmin=_minLayers, xmax=_maxLayers, ymax=1, **_common),
0340     Plot("hits_eta", xtitle="track #eta", ytitle="<hits> vs #eta", ymin=_minHits, ymax=_maxHits, statyadjust=[0,0,-0.15],
0341          fallback={"name": "nhits_vs_eta", "profileX": True}),
0342     Plot("hits", stat=True, xtitle="track hits", xmin=_minHits, xmax=_maxHits, ylog=True, ymin=[5e-1, 5, 5e1, 5e2, 5e3], drawStyle="hist"),
0343     Plot("num_simul_pT", xtitle="TP p_{T}", xlog=True, ymax=[1e-1, 2e-1, 5e-1, 1], **_common),
0344     Plot("num_reco_pT", xtitle="track p_{T}", xlog=True, ymax=[1e-1, 2e-1, 5e-1, 1], **_common)
0345 ])
0346 _tuning = PlotGroup("tuning", [
0347     Plot("chi2", stat=True, normalizeToUnitArea=True, ylog=True, ymin=1e-6, ymax=[0.1, 0.2, 0.5, 1.0001], drawStyle="hist", xtitle="#chi^{2}", ratioUncertainty=False),
0348     Plot("chi2_prob", stat=True, normalizeToUnitArea=True, drawStyle="hist", xtitle="Prob(#chi^{2})"),
0349     Plot("chi2mean", title="", xtitle="#eta", ytitle="< #chi^{2} / ndf >", ymin=[0, 0.5], ymax=[2, 2.5, 3, 5],
0350          fallback={"name": "chi2_vs_eta", "profileX": True}),
0351     Plot("ptres_vs_eta_Mean", scale=100, title="", xtitle="TP #eta (PCA to beamline)", ytitle="< #delta p_{T} / p_{T} > (%)", ymin=_minResidualPt, ymax=_maxResidualPt),
0352     Plot("chi2mean_vs_pt", title="", xtitle="p_{T}", ytitle="< #chi^{2} / ndf >", ymin=[0, 0.5], ymax=[2, 2.5, 3, 5], xlog=True, fallback={"name": "chi2_vs_pt", "profileX": True}),
0353     Plot("chi2mean_vs_drj", title="", xtitle="#DeltaR(track, jet)", ytitle="< #chi^{2} / ndf >", ymin=[0, 0.5], ymax=[2, 2.5, 3, 5], xlog=True, xmax=_maxDRJ, fallback={"name": "chi2_vs_drj", "profileX": True}),
0354     Plot("ptres_vs_pt_Mean", title="", xtitle="p_{T}", ytitle="< #delta p_{T}/p_{T} > (%)", scale=100, ymin=_minResidualPt, ymax=_maxResidualPt,xlog=True)
0355 ],
0356                    legendDy=_legendDy_4rows
0357 )
0358 _common = {"stat": True, "fit": True, "normalizeToUnitArea": True, "drawStyle": "hist", "drawCommand": "", "xmin": -10, "xmax": 10, "ylog": True, "ymin": 5e-5, "ymax": [0.01, 0.05, 0.1, 0.2, 0.5, 0.8, 1.025], "ratioUncertainty": False}
0359 _pulls = PlotGroup("pulls", [
0360     Plot("pullPt", **_common),
0361     Plot("pullQoverp", **_common),
0362     Plot("pullPhi", **_common),
0363     Plot("pullTheta", **_common),
0364     Plot("pullDxy", **_common),
0365     Plot("pullDz", **_common),
0366 ],
0367                    legendDx=0.1, legendDw=-0.1, legendDh=-0.015
0368 )
0369 _common = {"title": "", "ylog": True, "xtitle": "TP #eta (PCA to beamline)", "ymin": _minMaxResol, "ymax": _minMaxResol}
0370 _resolutionsEta = PlotGroup("resolutionsEta", [
0371     Plot("phires_vs_eta_Sigma", ytitle="#sigma(#delta #phi) (rad)", **_common),
0372     Plot("cotThetares_vs_eta_Sigma", ytitle="#sigma(#delta cot(#theta))", **_common),
0373     Plot("dxyres_vs_eta_Sigma", ytitle="#sigma(#delta d_{xy}) (cm)", **_common),
0374     Plot("dzres_vs_eta_Sigma", ytitle="#sigma(#delta d_{z}) (cm)", **_common),
0375     Plot("ptres_vs_eta_Sigma", ytitle="#sigma(#delta p_{T}/p_{T})", **_common),
0376 ])
0377 _common = {"title": "", "ylog": True, "xlog": True, "xtitle": "TP p_{T} (PCA to beamline)", "xmin": 0.1, "xmax": 1000, "ymin": _minMaxResol, "ymax": _minMaxResol}
0378 _resolutionsPt = PlotGroup("resolutionsPt", [
0379     Plot("phires_vs_pt_Sigma", ytitle="#sigma(#delta #phi) (rad)", **_common),
0380     Plot("cotThetares_vs_pt_Sigma", ytitle="#sigma(#delta cot(#theta))", **_common),
0381     Plot("dxyres_vs_pt_Sigma", ytitle="#sigma(#delta d_{xy}) (cm)", **_common),
0382     Plot("dzres_vs_pt_Sigma", ytitle="#sigma(#delta d_{z}) (cm)", **_common),
0383     Plot("ptres_vs_pt_Sigma", ytitle="#sigma(#delta p_{T}/p_{T})", **_common),
0384 ])
0385 _common = {"title": "", "ylog": True, "xtitle": "TP #Phi (PCA to beamline)", "ymin": _minMaxResol, "ymax": _minMaxResol}
0386 _resolutionsPhi = PlotGroup("resolutionsPhi", [
0387     Plot("dxyres_vs_phi_Sigma", ytitle="#sigma(#delta d_{xy}) (cm)", **_common),
0388     Plot("dzres_vs_phi_Sigma", ytitle="#sigma(#delta d_{z}) (cm)", **_common),
0389     Plot("phires_vs_phi_Sigma", ytitle="#sigma(#delta #phi) (rad)", **_common),
0390     Plot("ptres_vs_phi_Sigma", ytitle="#sigma(#delta p_{T}/p_{T})", **_common),
0391 ])
0392 
0393 ## Extended set of plots
0394 _extDistPtEtaPhi = PlotGroup("distPtEtaPhi",
0395                              _makeDistPlots("pT", "p_{T} (GeV)", common=dict(xlog=True)) +
0396                              _makeDistPlots("eta", "#eta") +
0397                              _makeDistPlots("phi", "#phi"),
0398                              ncols=4)
0399 _extDistDxyDzBS = PlotGroup("distDxyDzBS",
0400                             _makeDistPlots("dxy"  , "dxy (cm)") +
0401                             _makeDistPlots("dz"   , "dz (cm)"),
0402                             ncols=4, legendDy=_legendDy_2rows)
0403 _extDistDxyDzPV = PlotGroup("distDxyDzPV",
0404                             _makeDistPlots("dxypv"       , "dxy(PV) (cm)") +
0405                             _makeDistPlots("dxypv_zoomed", "dxy(PV) (cm)") +
0406                             _makeDistPlots("dzpv"        , "dz(PV) (cm)") +
0407                             _makeDistPlots("dzpv_zoomed" , "dz(PV) (cm)"),
0408                             ncols=4, legendDy=_legendDy_4rows)
0409 _extDistHitsLayers = PlotGroup("distHitsLayers",
0410                                _makeDistPlots("hit"       , "hits"        , common=dict(xmin=_minHits    , xmax=_maxHits)) +
0411                                _makeDistPlots("layer"     , "layers"      , common=dict(xmin=_minLayers  , xmax=_maxLayers)) +
0412                                _makeDistPlots("pixellayer", "pixel layers", common=dict(                   xmax=_maxPixelLayers)) +
0413                                _makeDistPlots("3Dlayer"   , "3D layers"   , common=dict(xmin=_min3DLayers, xmax=_max3DLayers)),
0414                                ncols=4, legendDy=_legendDy_4rows,
0415 )
0416 _extDistPos = PlotGroup("distPos",
0417                               _makeDistPlots("vertpos", "ref. point r (cm)", common=dict(xlog=True)) +
0418                               _makeDistPlots("zpos"   , "ref. point z (cm)") +
0419                               _makeDistPlots("simpvz" , "Sim. PV z (cm)", common=dict(xmin=_minZ, xmax=_maxZ)),
0420                               ncols=3,
0421 )
0422 _extDistDeltaR = PlotGroup("distDeltaR",
0423                               _makeDistPlots("dr"     , "min #DeltaR", common=dict(xlog=True)) +
0424                               _makeDistPlots("drj"     , "#DeltaR(track, jet)", common=dict(xlog=True, xmax=_maxDRJ)),
0425                               ncols=2, legendDy=_legendDy_2rows,
0426 )
0427 _extDistSeedingPlots = _makeDistPlots("seedingLayerSet", "seeding layers", common=dict(xtitle="", **_seedingLayerSet_common))
0428 _extDistChi2Seeding = PlotGroup("distChi2Seeding",
0429                                 _makeDistPlots("chi2", "#chi^{2}") +
0430                                 _extDistSeedingPlots,
0431                                 ncols=4, legendDy=_legendDy_2rows_3cols
0432 )
0433 _common = dict(title="", xtitle="TP #eta (PCA to beamline)")
0434 _extResidualEta = PlotGroup("residualEta", [
0435     Plot("phires_vs_eta_Mean", ytitle="< #delta #phi > (rad)", ymin=_minResidualPhi, ymax=_maxResidualPhi, **_common),
0436     Plot("cotThetares_vs_eta_Mean", ytitle="< #delta cot(#theta) >", ymin=_minResidualCotTheta, ymax=_maxResidualCotTheta, **_common),
0437     Plot("dxyres_vs_eta_Mean", ytitle="< #delta d_{xy} > (#mum)", scale=10000, ymin=_minResidualDxy, ymax=_maxResidualDxy, **_common),
0438     Plot("dzres_vs_eta_Mean", ytitle="< #delta d_{z} > (#mum)", scale=10000, ymin=_minResidualDz, ymax=_maxResidualDz, **_common),
0439     Plot("ptres_vs_eta_Mean", ytitle="< #delta p_{T}/p_{T} > (%)", scale=100, ymin=_minResidualPt, ymax=_maxResidualPt, **_common), # same as in tuning, but to be complete
0440 ])
0441 _common = dict(title="", xlog=True, xtitle="TP p_{T} (PCA to beamline)", xmin=0.1, xmax=1000)
0442 _extResidualPt = PlotGroup("residualPt", [
0443     Plot("phires_vs_pt_Mean", ytitle="< #delta #phi > (rad)", ymin=_minResidualPhi, ymax=_maxResidualPhi, **_common),
0444     Plot("cotThetares_vs_pt_Mean", ytitle="< #delta cot(#theta > )", ymin=_minResidualCotTheta, ymax=_maxResidualCotTheta, **_common),
0445     Plot("dxyres_vs_pt_Mean", ytitle="< #delta d_{xy} > (#mum)", scale=10000, ymin=_minResidualDxy, ymax=_maxResidualDxy, **_common),
0446     Plot("dzres_vs_pt_Mean", ytitle="< #delta d_{z} > (#mum)", scale=10000, ymin=_minResidualDz, ymax=_maxResidualDz, **_common),
0447     Plot("ptres_vs_pt_Mean", ytitle="< #delta p_{T}/p_{T} > (%)", scale=100, ymin=_minResidualPt, ymax=_maxResidualPt, **_common), # same as in tuning, but to be complete
0448 ])
0449 _common = dict(title="", ytitle="Selected tracks/TrackingParticles", ymax=_maxEff)
0450 _extNrecVsNsim = PlotGroup("nrecVsNsim", [
0451     Plot("nrec_vs_nsim", title="", xtitle="TrackingParticles", ytitle="Tracks", profileX=True, xmin=_minMaxTracks, xmax=_minMaxTracks, ymin=_minMaxTracks, ymax=_minMaxTracks),
0452     Plot("nrecPerNsim_vs_pu", xtitle="Pileup", xmin=_minPU, xmax=_maxPU, **_common),
0453     Plot("nrecPerNsimPt", xtitle="p_{T} (GeV)", xlog=True, **_common),
0454     Plot("nrecPerNsim", xtitle="#eta", **_common)
0455 ], legendDy=_legendDy_2rows)
0456 _extHitsLayers = PlotGroup("hitsLayers", [
0457     Plot("PXLhits_vs_eta", xtitle="#eta", ytitle="<pixel hits>"),
0458     Plot("PXLlayersWithMeas_vs_eta", xtitle="#eta", ytitle="<pixel layers>"),
0459     Plot("STRIPhits_vs_eta", xtitle="#eta", ytitle="<strip hits>"),
0460     Plot("STRIPlayersWithMeas_vs_eta", xtitle="#eta", ytitle="<strip layers>"),
0461 ], legendDy=_legendDy_2rows)
0462 
0463 
0464 ## Extended set of plots also for simulation
0465 _extDistSimPtEtaPhi = PlotGroup("distsimPtEtaPhi",
0466                                 _makeDistSimPlots("pT", "p_{T} (GeV)", common=dict(xlog=True)) +
0467                                 _makeDistSimPlots("eta", "#eta") +
0468                                 _makeDistSimPlots("phi", "#phi"),
0469                                 ncols=2)
0470 _extDistSimDxyDzBS = PlotGroup("distsimDxyDzBS",
0471                                _makeDistSimPlots("dxy"  , "dxy (cm)") +
0472                                _makeDistSimPlots("dz"   , "dz (cm)"),
0473                                ncols=2, legendDy=_legendDy_2rows)
0474 _extDistSimDxyDzPV = PlotGroup("distsimDxyDzPV",
0475                                _makeDistSimPlots("dxypv"       , "dxy(PV) (cm)") +
0476                                _makeDistSimPlots("dxypv_zoomed", "dxy(PV) (cm)") +
0477                                _makeDistSimPlots("dzpv"        , "dz(PV) (cm)") +
0478                                _makeDistSimPlots("dzpv_zoomed" , "dz(PV) (cm)"),
0479                                ncols=2, legendDy=_legendDy_4rows)
0480 _extDistSimHitsLayers = PlotGroup("distsimHitsLayers",
0481                                   _makeDistSimPlots("hit"       , "hits"        , common=dict(xmin=_minHits    , xmax=_maxHits)) +
0482                                   _makeDistSimPlots("layer"     , "layers"      , common=dict(xmin=_minLayers  , xmax=_maxLayers)) +
0483                                   _makeDistSimPlots("pixellayer", "pixel layers", common=dict(                   xmax=_maxPixelLayers)) +
0484                                   _makeDistSimPlots("3Dlayer"   , "3D layers"   , common=dict(xmin=_min3DLayers, xmax=_max3DLayers)),
0485                                   ncols=2, legendDy=_legendDy_4rows,
0486 )
0487 _extDistSimPos = PlotGroup("distsimPos",
0488                                  _makeDistSimPlots("vertpos", "vert r (cm)", common=dict(xlog=True)) +
0489                                  _makeDistSimPlots("zpos"   , "vert z (cm)") +
0490                                  _makeDistSimPlots("simpvz" , "Sim. PV z (cm)", common=dict(xmin=_minZ, xmax=_maxZ)),
0491                                  ncols=3,
0492 )
0493 _extDistSimDeltaR = PlotGroup("distsimDeltaR",
0494                                  _makeDistSimPlots("dr"     , "min #DeltaR", common=dict(xlog=True)) +
0495                                  _makeDistSimPlots("drj" , "#DeltaR(TP, jet)", common=dict(xlog=True, xmax=_maxDRJ)),
0496                                  ncols=2, legendDy=_legendDy_2rows,
0497 )
0498 
0499 ########################################
0500 #
0501 # Summary plots
0502 #
0503 ########################################
0504 
0505 _possibleTrackingNonIterationColls = [
0506     'ak4PFJets',
0507     'btvLike',
0508 ]
0509 _possibleTrackingColls = [
0510     'initialStepPreSplitting',
0511     'initialStep',
0512     'highPtTripletStep', # phase1
0513     'detachedQuadStep', # phase1
0514     'detachedTripletStep',
0515     'lowPtQuadStep', # phase1
0516     'lowPtTripletStep',
0517     'pixelPairStepA', # seeds
0518     'pixelPairStepB', # seeds
0519     'pixelPairStepC', # seeds
0520     'pixelPairStep',
0521     'mixedTripletStepA', # seeds
0522     'mixedTripletStepB', # seeds
0523     'mixedTripletStep',
0524     'pixelLessStep',
0525     'tobTecStepPair',  # seeds
0526     'tobTecStepTripl', # seeds
0527     'tobTecStep',
0528     'displacedGeneralStep',
0529     'jetCoreRegionalStep',
0530     'muonSeededStepInOut',
0531     'muonSeededStepOutIn',
0532     'duplicateMerge',
0533 ] + _possibleTrackingNonIterationColls
0534 _possibleTrackingCollsOld = {
0535     "Zero"  : "iter0",
0536     "First" : "iter1",
0537     "Second": "iter2",
0538     "Third" : "iter3",
0539     "Fourth": "iter4",
0540     "Fifth" : "iter5",
0541     "Sixth" : "iter6",
0542     "Seventh": "iter7",
0543     "Ninth" : "iter9",
0544     "Tenth" : "iter10",
0545 }
0546 
0547 def _trackingSubFoldersFallbackSLHC_Phase1PU140(subfolder):
0548     ret = subfolder.replace("trackingParticleRecoAsssociation", "AssociatorByHitsRecoDenom")
0549     for (old, new) in [("InitialStep",         "Zero"),
0550                        ("HighPtTripletStep",   "First"),
0551                        ("LowPtQuadStep",       "Second"),
0552                        ("LowPtTripletStep",    "Third"),
0553                        ("DetachedQuadStep",    "Fourth"),
0554                        ("PixelPairStep",       "Fifth"),
0555                        ("MuonSeededStepInOut", "Ninth"),
0556                        ("MuonSeededStepOutIn", "Tenth")]:
0557         ret = ret.replace(old, new)
0558     if ret == subfolder:
0559         return None
0560     return ret
0561 def _trackingRefFileFallbackSLHC_Phase1PU140(path):
0562     for (old, new) in [("initialStep",         "iter0"),
0563                        ("highPtTripletStep",   "iter1"),
0564                        ("lowPtQuadStep",       "iter2"),
0565                        ("lowPtTripletStep",    "iter3"),
0566                        ("detachedQuadStep",    "iter4"),
0567                        ("pixelPairStep",       "iter5"),
0568                        ("muonSeededStepInOut", "iter9"),
0569                        ("muonSeededStepOutIn", "iter10")]:
0570         path = path.replace(old, new)
0571     return path
0572 
0573 def _trackingSubFoldersFallbackFromPV(subfolder):
0574     return subfolder.replace("trackingParticleRecoAsssociation", "trackingParticleRecoAsssociationSignal")
0575 def _trackingSubFoldersFallbackConversion(subfolder):
0576     return subfolder.replace("quickAssociatorByHits", "quickAssociatorByHitsConversion")
0577 def _trackingSubFoldersFallbackPreSplitting(subfolder):
0578     return subfolder.replace("quickAssociatorByHits", "quickAssociatorByHitsPreSplitting")
0579 
0580 # Additional "quality" flags than highPurity. In a separate list to
0581 # allow customization.
0582 _additionalTrackQualities = [
0583     "Pt09",
0584     "ByOriginalAlgo",
0585     "ByAlgoMask"
0586 ]
0587 def _mapCollectionToAlgoQuality(collName):
0588     if "Hp" in collName:
0589         quality = "highPurity"
0590     else:
0591         quality = ""
0592     collNameNoQuality = collName.replace("Hp", "")
0593     for qual in _additionalTrackQualities:
0594         if qual in collName:
0595             quality += qual
0596             collNameNoQuality = collNameNoQuality.replace(qual, "")
0597 
0598     collNameNoQuality = collNameNoQuality.replace("Tracks", "", 1) # make summary naming consistent with iteration folders
0599     collNameLow = collNameNoQuality.lower().replace("frompv2", "").replace("frompv", "").replace("frompvalltp", "").replace("alltp", "")
0600 
0601     if collNameLow.find("seed") == 0:
0602         collNameLow = collNameLow[4:]
0603         if collNameLow == "initialstepseedspresplitting":
0604             collNameLow = "initialsteppresplittingseeds"
0605         elif collNameLow == "muonseededseedsinout":
0606             collNameLow = "muonseededstepinoutseeds"
0607         elif collNameLow == "muonseededseedsoutin":
0608             collNameLow = "muonseededstepoutinseeds"
0609 
0610         i_seeds = collNameLow.index("seeds")
0611         quality = collNameLow[i_seeds:]+quality
0612 
0613         collNameLow = collNameLow[:i_seeds]
0614 
0615     algo = None
0616     prefixes = ["cutsreco", "cutsrecofrompv", "cutsrecofrompv2", "cutsrecofrompvalltp", "cutsrecoetagreater2p7"]
0617     if collNameLow in ["general", "generalfrompv", "generaletagreater2p7"]+prefixes:
0618         algo = "ootb"
0619     elif collNameLow in ["pixel", "pixelfrompv", "pixelfrompvalltp"]:
0620         algo = "pixel"
0621     else:
0622         def testColl(coll):
0623             for pfx in prefixes:
0624                 if coll == collNameLow.replace(pfx, ""):
0625                     return True
0626             return False
0627 
0628         for coll in _possibleTrackingColls:
0629             if testColl(coll.lower()):
0630                 algo = coll
0631                 break
0632         # next try "old style"
0633         if algo is None:
0634             for coll, name in _possibleTrackingCollsOld.items():
0635                 if testColl(coll.lower()):
0636                     algo = name
0637                     break
0638 
0639         # fallback
0640         if algo is None:
0641             algo = collNameNoQuality
0642 
0643     # fix for track collection naming convention
0644     if algo == "muonSeededInOut":
0645         algo = "muonSeededStepInOut"
0646     if algo == "muonSeededOutIn":
0647         algo = "muonSeededStepOutIn"
0648 
0649     return (algo, quality)
0650 
0651 def _collhelper(name):
0652     return (name, [name])
0653 _collLabelMap = collections.OrderedDict(map(_collhelper, ["generalTracks"]+_possibleTrackingColls))
0654 _collLabelMapHp = collections.OrderedDict(map(_collhelper, ["generalTracks"]+[n for n in _possibleTrackingColls if "Step" in n]))
0655 def _summaryBinRename(binLabel, highPurity, byOriginalAlgo, byAlgoMask, ptCut, seeds):
0656     (algo, quality) = _mapCollectionToAlgoQuality(binLabel)
0657     if algo == "ootb":
0658         algo = "generalTracks"
0659     ret = None
0660 
0661     if byOriginalAlgo:
0662         if algo != "generalTracks" and "ByOriginalAlgo" not in quality: # keep generalTracks bin as well
0663             return None
0664         quality = quality.replace("ByOriginalAlgo", "")
0665     if byAlgoMask:
0666         if algo != "generalTracks" and "ByAlgoMask" not in quality: # keep generalTracks bin as well
0667             return None
0668         quality = quality.replace("ByAlgoMask", "")
0669     if ptCut:
0670         if "Pt09" not in quality:
0671             return None
0672         quality = quality.replace("Pt09", "")
0673 
0674     if highPurity:
0675         if quality == "highPurity":
0676             ret = algo
0677     elif seeds:
0678         i_seeds = quality.find("seeds")
0679         if i_seeds == 0:
0680             ret = algo
0681             seedSubColl = quality[i_seeds+5:]
0682             if seedSubColl != "":
0683                 ret += seedSubColl[0].upper() + seedSubColl[1:]
0684     else:
0685         if quality == "":
0686             ret = algo
0687 
0688     return ret
0689 
0690 def _constructSummary(mapping=None, highPurity=False, byOriginalAlgo=False, byAlgoMask=False, ptCut=False, seeds=False, midfix=""):
0691     _common = {"drawStyle": "EP", "xbinlabelsize": 10, "xbinlabeloption": "d"}
0692     _commonN = dict(ylog=True, ymin=_minMaxN, ymax=_minMaxN,
0693                     normalizeToNumberOfEvents=True,
0694     )
0695     _commonN.update(_common)
0696     _commonAB = dict(mapping=mapping,
0697                      renameBin=lambda bl: _summaryBinRename(bl, highPurity, byOriginalAlgo, byAlgoMask, ptCut, seeds),
0698                      ignoreMissingBins=True,
0699                      originalOrder=True,
0700     )
0701     if byOriginalAlgo or byAlgoMask:
0702         _commonAB["minExistingBins"] = 2
0703     prefix = "summary"+midfix
0704 
0705     h_eff = "effic_vs_coll"
0706     h_fakerate = "fakerate_vs_coll"
0707     h_duplicaterate = "duplicatesRate_coll"
0708     h_pileuprate = "pileuprate_coll"
0709 
0710     h_reco = "num_reco_coll"
0711     h_true = "num_assoc(recoToSim)_coll"
0712     h_fake = Subtract("num_fake_coll_orig", "num_reco_coll", "num_assoc(recoToSim)_coll")
0713     h_duplicate = "num_duplicate_coll"
0714     h_pileup = "num_pileup_coll"
0715     if mapping is not None:
0716         h_eff = AggregateBins("efficiency", h_eff, **_commonAB)
0717         h_fakerate = AggregateBins("fakerate", h_fakerate, **_commonAB)
0718         h_duplicaterate = AggregateBins("duplicatesRate", h_duplicaterate, **_commonAB)
0719         h_pileuprate = AggregateBins("pileuprate", h_pileuprate, **_commonAB)
0720 
0721         h_reco = AggregateBins("num_reco_coll", h_reco, **_commonAB)
0722         h_true = AggregateBins("num_true_coll", h_true, **_commonAB)
0723         h_fake = AggregateBins("num_fake_coll", h_fake, **_commonAB)
0724         h_duplicate = AggregateBins("num_duplicate_coll", h_duplicate, **_commonAB)
0725         h_pileup = AggregateBins("num_pileup_coll", h_pileup, **_commonAB)
0726 
0727     summary = PlotGroup(prefix, [
0728         Plot(h_eff, title="Efficiency vs collection", ytitle="Efficiency", ymin=1e-3, ymax=1, ylog=True, **_common),
0729         Plot(h_fakerate, title="Fakerate vs collection", ytitle="Fake rate", ymax=_maxFake, **_common),
0730         #
0731         Plot(h_duplicaterate, title="Duplicates rate vs collection", ytitle="Duplicates rate", ymax=_maxFake, **_common),
0732         Plot(h_pileuprate, title="Pileup rate vs collection", ytitle="Pileup rate", ymax=_maxFake, **_common),
0733         ],
0734                         legendDy=_legendDy_2rows
0735     )
0736     summaryN = PlotGroup(prefix+"_ntracks", [
0737         # FIXME
0738         #Plot(h_reco, ytitle="Tracks/event", title="Number of tracks/event vs collection", **_commonN),
0739         #Plot(h_true, ytitle="True tracks/event", title="Number of true tracks/event vs collection", **_commonN),
0740         #Plot(h_fake, ytitle="Fake tracks/event", title="Number of fake tracks/event vs collection", **_commonN),
0741         #Plot(h_duplicate, ytitle="Duplicate tracks/event", title="Number of duplicate tracks/event vs collection", **_commonN),
0742         #Plot(h_pileup, ytitle="Pileup tracks/event", title="Number of pileup tracks/event vs collection", **_commonN),
0743         Plot(h_reco, ytitle="Tracks", title="Number of tracks vs collection", **_commonN),
0744         Plot(h_true, ytitle="True tracks", title="Number of true tracks vs collection", **_commonN),
0745         Plot(h_fake, ytitle="Fake tracks", title="Number of fake tracks vs collection", **_commonN),
0746         Plot(h_duplicate, ytitle="Duplicate tracks", title="Number of duplicate tracks vs collection", **_commonN),
0747         Plot(h_pileup, ytitle="Pileup tracks", title="Number of pileup tracks vs collection", **_commonN),
0748     ])
0749 
0750     return (summary, summaryN)
0751 
0752 (_summaryRaw,              _summaryRawN)              = _constructSummary(midfix="Raw")
0753 (_summary,                 _summaryN)                 = _constructSummary(_collLabelMap)
0754 (_summaryHp,               _summaryNHp)               = _constructSummary(_collLabelMapHp, highPurity=True)
0755 (_summaryByOriginalAlgo,   _summaryByOriginalAlgoN)   = _constructSummary(_collLabelMapHp, byOriginalAlgo=True, midfix="ByOriginalAlgo")
0756 (_summaryByOriginalAlgoHp, _summaryByOriginalAlgoNHp) = _constructSummary(_collLabelMapHp, byOriginalAlgo=True, midfix="ByOriginalAlgo", highPurity=True)
0757 (_summaryByAlgoMask,       _summaryByAlgoMaskN)       = _constructSummary(_collLabelMapHp, byAlgoMask=True, midfix="ByAlgoMask")
0758 (_summaryByAlgoMaskHp,     _summaryByAlgoMaskNHp)     = _constructSummary(_collLabelMapHp, byAlgoMask=True, midfix="ByAlgoMask", highPurity=True)
0759 (_summaryPt09,             _summaryPt09N)             = _constructSummary(_collLabelMap, ptCut=True, midfix="Pt09")
0760 (_summaryPt09Hp,           _summaryPt09NHp)           = _constructSummary(_collLabelMap, ptCut=True, midfix="Pt09", highPurity=True)
0761 (_summarySeeds,            _summarySeedsN)            = _constructSummary(_collLabelMapHp, seeds=True)
0762 
0763 ########################################
0764 #
0765 # PackedCandidate plots
0766 #
0767 ########################################
0768 
0769 _common = {"normalizeToUnitArea": True, "ylog": True, "ymin": [1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2], "ymax": [1e-2, 1e-1, 1.1]}
0770 _commonStatus = {}
0771 _commonStatus.update(_common)
0772 _commonStatus.update({"xbinlabelsize": 10, "xbinlabeloption": "d", "drawStyle": "hist", "adjustMarginRight": 0.08})
0773 _commonLabelSize = {}
0774 _commonLabelSize.update(_common)
0775 _commonLabelSize.update({"xlabelsize": 17})
0776 
0777 _packedCandidateFlow = PlotGroup("flow", [
0778     Plot("selectionFlow", xbinlabelsize=10, xbinlabeloption="d", adjustMarginRight=0.1, drawStyle="hist", ylog=True, ymin=[0.9, 9, 9e1, 9e2, 9e3, 9e4, 9e5, 9e6, 9e7]),
0779     Plot("diffCharge", xtitle="Charge", **_common),
0780     Plot("diffIsHighPurity", xtitle="High purity status", **_common),
0781     Plot("diffNdof", xtitle="ndof", **_common),
0782     Plot("diffNormalizedChi2", xtitle="#chi^{2}/ndof", **_common),
0783 ])
0784 
0785 _packedCandidateHitsHitPattern = PlotGroup("hitsHitPattern", [
0786     Plot("diffHitPatternNumberOfValidHits", xtitle="Valid hits (via HitPattern)", **_common),
0787     Plot("diffHitPatternNumberOfValidPixelHits", xtitle="Valid pixel hits (via HitPattern)", **_common),
0788     Plot("diffHitPatternHasValidHitInFirstPixelBarrel", xtitle="Has valid hit in BPix1 layer (via HitPattern)", **_common),
0789     Plot("diffHitPatternNumberOfLostPixelHits", xtitle="Lost pixel hits (via HitPattern)", **_common),
0790 ],
0791                                            legendDy=_legendDy_2rows
0792 )
0793 _packedCandidateHits = PlotGroup("hits", [
0794     Plot("diffNumberOfHits", xtitle="Hits",  **_common),
0795     Plot("diffNumberOfPixelHits", xtitle="Pixel hits", **_common),
0796     Plot("diffLostInnerHits", xtitle="Lost inner hits", **_common),
0797     Plot("numberHitsOverMax", xtitle="Number of overflown hits", **_common),
0798     Plot("numberPixelHitsOverMax", xtitle="Number of overflown pixel hits", **_common),
0799     Plot("numberStripHitsOverMax", xtitle="Number of overflown strip hits", **_common),
0800 ],
0801                                  ncols=3, legendDy=_legendDy_2rows_3cols
0802 )
0803 
0804 _packedCandidateLayers = PlotGroup("layers", [
0805     PlotEmpty(),
0806     Plot("diffNumberOfPixelLayers", xtitle="Pixel layers",  **_common),
0807     Plot("diffNumberOfStripLayers", xtitle="Strip layers", **_common),
0808     #
0809     Plot("diffHitPatternTrackerLayersWithMeasurement", xtitle="Layers (via HitPattern)", **_common),
0810     Plot("diffHitPatternPixelLayersWithMeasurement", xtitle="Pixel layers (via HitPattern)", **_common),
0811     Plot("diffHitPatternStripLayersWithMeasurement", xtitle="Strip layers (via HitPattern)", **_common),
0812     #
0813     Plot("numberLayersOverMax", xtitle="Number of overflown layers", **_common),
0814     Plot("numberPixelLayersOverMax", xtitle="Number of overflown pixel layers", **_common),
0815     Plot("numberStripLayersOverMax", xtitle="Number of overflown strip layers", **_common),
0816 ],
0817                                    ncols=3
0818 )
0819 
0820 
0821 _packedCandidateImpactParameter1 = PlotGroup("impactParameter1", [
0822     Plot("diffDxyAssocPV", xtitle="dxy(assocPV)", adjustMarginRight=0.02, **_commonLabelSize),
0823     Plot("diffDxyAssocPVStatus", **_commonStatus),
0824     Plot("diffDxyAssocPVUnderOverFlowSign", xtitle="dxy(assocPV)", **_common),
0825     Plot("diffDzAssocPV", xtitle="dz(assocPV)", adjustMarginRight=0.02, **_commonLabelSize),
0826     Plot("diffDzAssocPVStatus", **_commonStatus),
0827     Plot("diffDzAssocPVUnderOverFlowSign", xtitle="dz(assocPV)", **_common),
0828     Plot("diffDxyError", xtitle="dxyError()", adjustMarginRight=0.02, **_commonLabelSize),
0829     Plot("diffDszError", xtitle="dszError()", adjustMarginRight=0.02, **_commonLabelSize),
0830     Plot("diffDzError", xtitle="dzError()", adjustMarginRight=0.02, **_commonLabelSize),
0831 
0832 ],
0833                                              ncols=3
0834 )
0835 
0836 _packedCandidateImpactParameter2 = PlotGroup("impactParameter2", [
0837     Plot("diffDxyPV", xtitle="dxy(PV) via PC", **_commonLabelSize),
0838     Plot("diffDzPV", xtitle="dz(PV) via PC", **_commonLabelSize),
0839     Plot("diffTrackDxyAssocPV", xtitle="dxy(PV) via PC::bestTrack()", **_commonLabelSize),
0840     Plot("diffTrackDzAssocPV", xtitle="dz(PV) via PC::bestTrack()", **_commonLabelSize),
0841     Plot("diffTrackDxyError", xtitle="dxyError() via PC::bestTrack()", adjustMarginRight=0.02, **_commonLabelSize),
0842     Plot("diffTrackDzError", xtitle="dzError() via PC::bestTrack()", **_commonLabelSize),
0843 ])
0844 
0845 _packedCandidateCovarianceMatrix1 = PlotGroup("covarianceMatrix1", [
0846     Plot("diffCovQoverpQoverp", xtitle="cov(qoverp, qoverp)", **_commonLabelSize),
0847     Plot("diffCovQoverpQoverpStatus", **_commonStatus),
0848     Plot("diffCovQoverpQoverpUnderOverFlowSign", xtitle="cov(qoverp, qoverp)", **_common),
0849     Plot("diffCovLambdaLambda", xtitle="cov(lambda, lambda)", **_commonLabelSize),
0850     Plot("diffCovLambdaLambdaStatus", **_commonStatus),
0851     Plot("diffCovLambdaLambdaUnderOverFlowSign", xtitle="cov(lambda, lambda)", **_common),
0852     Plot("diffCovLambdaDsz", xtitle="cov(lambda, dsz)", **_commonLabelSize),
0853     Plot("diffCovLambdaDszStatus", **_commonStatus),
0854     Plot("diffCovLambdaDszUnderOverFlowSign", xtitle="cov(lambda, dsz)", **_common),
0855     Plot("diffCovPhiPhi", xtitle="cov(phi, phi)", **_commonLabelSize),
0856     Plot("diffCovPhiPhiStatus", **_commonStatus),
0857     Plot("diffCovPhiPhiUnderOverFlowSign", xtitle="cov(phi, phi)", **_common),
0858 ],
0859                                               ncols=3, legendDy=_legendDy_4rows
0860 )
0861 _packedCandidateCovarianceMatrix2 = PlotGroup("covarianceMatrix2", [
0862     Plot("diffCovPhiDxy", xtitle="cov(phi, dxy)", **_commonLabelSize),
0863     Plot("diffCovPhiDxyStatus", **_commonStatus),
0864     Plot("diffCovPhiDxyUnderOverFlowSign", xtitle="cov(phi, dxy)", **_common),
0865     Plot("diffCovDxyDxy", xtitle="cov(dxy, dxy)", adjustMarginRight=0.02, **_commonLabelSize),
0866     Plot("diffCovDxyDxyStatus", **_commonStatus),
0867     Plot("diffCovDxyDxyUnderOverFlowSign", xtitle="cov(dxy, dxy)", **_common),
0868     Plot("diffCovDxyDsz", xtitle="cov(dxy, dsz)", adjustMarginRight=0.02, **_commonLabelSize),
0869     Plot("diffCovDxyDszStatus", **_commonStatus),
0870     Plot("diffCovDxyDszUnderOverFlowSign", xtitle="cov(dxy, dsz)", **_common),
0871     Plot("diffCovDszDsz", xtitle="cov(dsz, dsz)", adjustMarginRight=0.02, **_commonLabelSize),
0872     Plot("diffCovDszDszStatus", **_commonStatus),
0873     Plot("diffCovDszDszUnderOverFlowSign", xtitle="cov(dsz, dsz)", **_common),
0874 ],
0875                                               ncols=3, legendDy=_legendDy_4rows
0876 )
0877 
0878 _common["xlabelsize"] = 16
0879 _packedCandidateVertex = PlotGroup("vertex", [
0880     Plot("diffVx", xtitle="Reference point x", **_common),
0881     Plot("diffVy", xtitle="Reference point y", **_common),
0882     Plot("diffVz", xtitle="Reference point z", **_common),
0883 ],
0884                                    legendDy=_legendDy_2rows
0885 )
0886 
0887 _common["adjustMarginRight"] = 0.05
0888 _packedCandidateKinematics = PlotGroup("kinematics", [
0889     Plot("diffPt", xtitle="p_{T}", **_common),
0890     Plot("diffPtError", xtitle="p_{T} error", **_common),
0891     Plot("diffEta", xtitle="#eta", **_common),
0892     Plot("diffEtaError", xtitle="#eta error", **_common),
0893     Plot("diffPhi", xtitle="#phi", **_common),
0894 ])
0895 
0896 class TrackingPlotFolder(PlotFolder):
0897     def __init__(self, *args, **kwargs):
0898         self._fallbackRefFiles = kwargs.pop("fallbackRefFiles", [])
0899         PlotFolder.__init__(self, *args, **kwargs)
0900 
0901     def translateSubFolder(self, dqmSubFolderName):
0902         spl = dqmSubFolderName.split("_")
0903         if len(spl) != 2:
0904             return None
0905         collName = spl[0]
0906         return _mapCollectionToAlgoQuality(collName)
0907 
0908     def iterSelectionName(self, plotFolderName, translatedDqmSubFolder):
0909         (algoOrig, quality) = translatedDqmSubFolder
0910 
0911         for fallback in [lambda n: n]+self._fallbackRefFiles:
0912             algo = fallback(algoOrig)
0913 
0914             ret = ""
0915             if plotFolderName != "":
0916                 ret += "_"+plotFolderName
0917             if quality != "":
0918                 ret += "_"+quality
0919             if not (algo == "ootb" and quality != ""):
0920                 ret += "_"+algo
0921             yield ret
0922 
0923     def limitSubFolder(self, limitOnlyTo, translatedDqmSubFolder):
0924         """Return True if this subfolder should be processed
0925 
0926         Arguments:
0927         limitOnlyTo            -- Function '(algo, quality) -> bool'
0928         translatedDqmSubFolder -- Return value of translateSubFolder
0929         """
0930         (algo, quality) = translatedDqmSubFolder
0931         return limitOnlyTo(algo, quality)
0932 
0933     # track-specific hack
0934     def isAlgoIterative(self, algo):
0935         return algo not in _possibleTrackingNonIterationColls
0936 
0937 class TrackingSummaryTable:
0938     class GeneralTracks: pass
0939     class GeneralTracksPt09: pass
0940     class HighPurity: pass
0941     class HighPurityPt09: pass
0942     class BTVLike: pass
0943     class AK4PFJets: pass
0944     class Pixel: pass
0945     class PixelPt09: pass
0946 
0947     def __init__(self, section, collection=GeneralTracks):
0948         self._collection = collection
0949         self._purpose = PlotPurpose.TrackingSummary
0950         self._page = "summary"
0951         self._section = section
0952 
0953     def getPurpose(self):
0954         return self._purpose
0955 
0956     def getPage(self):
0957         return self._page
0958 
0959     def getSection(self, dqmSubFolder):
0960         return self._section
0961 
0962     def create(self, tdirectory):
0963         def _getAlgoQuality(data, algo, quality):
0964             for label, value in data.items():
0965                 (a, q) = _mapCollectionToAlgoQuality(label)
0966                 if a == algo and q == quality:
0967                     return value[0] # value is (value, uncertainty) tuple
0968             return None
0969         def _getN(hname):
0970             h = tdirectory.Get(hname)
0971             if not h:
0972                 return None
0973             data = plotting._th1ToOrderedDict(h)
0974             if self._collection == TrackingSummaryTable.GeneralTracks:
0975                 return _getAlgoQuality(data, "ootb", "")
0976             elif self._collection == TrackingSummaryTable.GeneralTracksPt09:
0977                 return _getAlgoQuality(data, "ootb", "Pt09")
0978             elif self._collection == TrackingSummaryTable.HighPurity:
0979                 return _getAlgoQuality(data, "ootb", "highPurity")
0980             elif self._collection == TrackingSummaryTable.HighPurityPt09:
0981                 return _getAlgoQuality(data, "ootb", "highPurityPt09")
0982             elif self._collection == TrackingSummaryTable.BTVLike:
0983                 return _getAlgoQuality(data, "btvLike", "")
0984             elif self._collection == TrackingSummaryTable.AK4PFJets:
0985                 return _getAlgoQuality(data, "ak4PFJets", "")
0986             elif self._collection == TrackingSummaryTable.Pixel:
0987                 return _getAlgoQuality(data, "pixel", "")
0988             elif self._collection == TrackingSummaryTable.PixelPt09:
0989                 return _getAlgoQuality(data, "pixel", "Pt09")
0990             else:
0991                 raise Exception("Collection not recognized, %s" % str(self._collection))
0992         def _formatOrNone(num, func):
0993             if num is None:
0994                 return None
0995             return func(num)
0996 
0997         n_tps = _formatOrNone(_getN("num_simul_coll"), int)
0998         n_m_tps = _formatOrNone(_getN("num_assoc(simToReco)_coll"), int)
0999 
1000         n_tracks = _formatOrNone(_getN("num_reco_coll"), int)
1001         n_true = _formatOrNone(_getN("num_assoc(recoToSim)_coll"), int)
1002         if n_tracks is not None and n_true is not None:
1003             n_fake = n_tracks-n_true
1004         else:
1005             n_fake = None
1006         n_pileup = _formatOrNone(_getN("num_pileup_coll"), int)
1007         n_duplicate = _formatOrNone(_getN("num_duplicate_coll"), int)
1008 
1009         eff = _formatOrNone(_getN("effic_vs_coll"), lambda n: "%.4f" % n)
1010         eff_nopt = _formatOrNone(_getN("effic_vs_coll_allPt"), lambda n: "%.4f" % n)
1011         fake = _formatOrNone(_getN("fakerate_vs_coll"), lambda n: "%.4f" % n)
1012         duplicate = _formatOrNone(_getN("duplicatesRate_coll"), lambda n: "%.4f" % n)
1013 
1014         ret = [eff, n_tps, n_m_tps,
1015                eff_nopt, fake, duplicate,
1016                n_tracks, n_true, n_fake, n_pileup, n_duplicate]
1017         if ret.count(None) == len(ret):
1018             return None
1019         return ret
1020 
1021     def headers(self):
1022         return [
1023             "Efficiency",
1024             "Number of TrackingParticles (after cuts)",
1025             "Number of matched TrackingParticles",
1026             "Efficiency (w/o pT cut)",
1027             "Fake rate",
1028             "Duplicate rate",
1029             "Number of tracks",
1030             "Number of true tracks",
1031             "Number of fake tracks",
1032             "Number of pileup tracks",
1033             "Number of duplicate tracks"
1034         ]
1035 
1036 # Provide a "PlotGroup" interface, but provide a html page
1037 class TrackingSeedingLayerTable:
1038     def __init__(self, fileName, plots, titles, isRate, **kwargs):
1039         self._plots = plots
1040         self._titles = titles
1041         self._fileName = fileName
1042         self._format = "%.4g" if isRate else "%d"
1043 
1044         if len(plots) != len(titles):
1045             raise Exception("Number of plots (%d) has to be the same as number of titles (%d)" % (len(plots), len(titles)))
1046 
1047         def _set(attr, default):
1048             setattr(self, "_"+attr, kwargs.get(attr, default))
1049 
1050         _set("onlyForPileup", False)
1051 
1052     def onlyForPileup(self):
1053         """Return True if the PlotGroup is intended only for pileup samples"""
1054         return self._onlyForPileup
1055 
1056     def create(self, tdirectoryNEvents, requireAllHistograms=False):
1057         # [plot][histo]
1058         for plot in self._plots:
1059             plot.create(tdirectoryNEvents, requireAllHistograms)
1060 
1061     def draw(self, legendLabels, prefix=None, directory="", *args, **kwargs):
1062         # Do not make the table if it would be empty
1063         onlyEmptyPlots = True
1064         for plot in self._plots:
1065             if not plot.isEmpty():
1066                 onlyEmptyPlots = False
1067                 break
1068         if onlyEmptyPlots:
1069             return []
1070 
1071         haveShortLabels = False
1072         legendLabels = legendLabels[:]
1073         if max(map(len, legendLabels)) > 20:
1074             haveShortLabels = True
1075             labels_short = [str(chr(ord('A')+i)) for i in range(len(legendLabels))]
1076             for i, ls in enumerate(labels_short):
1077                 legendLabels[i] = "%s: %s" % (ls, legendLabels[i])
1078         else:
1079             labels_short = legendLabels
1080 
1081         content = [
1082             '<html>',
1083             ' <body>',
1084             '  <table border="1">',
1085             '   <tr>',
1086         ]
1087 
1088 
1089         histos_linear = []
1090         histos_index = []
1091         labels = []
1092         for plot, title in zip(self._plots, self._titles):
1093             h_tmp = []
1094             l_tmp = []
1095             for h, l in zip(plot._histograms, labels_short):
1096                 if h is not None:
1097                     h_tmp.append(len(histos_linear))
1098                     histos_linear.append(h)
1099                     l_tmp.append(l)
1100 
1101             if len(h_tmp) > 0:
1102                 histos_index.append(h_tmp)
1103                 labels.append(l_tmp)
1104                 content.extend([
1105                     '    <td></td>',
1106                     '    <td colspan="%d">%s</td>' % (len(h_tmp), title),
1107                 ])
1108 
1109         if len(histos_linear) == 0:
1110             return []
1111 
1112         content.extend([
1113             '   </tr>',
1114             '   <tr>',
1115         ])
1116 
1117         xbinlabels = plotting._mergeBinLabelsX(histos_linear)
1118         histos_linear = plotting._th1IncludeOnlyBins(histos_linear, xbinlabels)
1119         if len(histos_linear) == 0:
1120             return []
1121         (histos_linear_new, xbinlabels) = plotting._th1RemoveEmptyBins(histos_linear, xbinlabels)
1122         # in practice either all histograms are returned, or none, but let's add a check anyway
1123         if len(histos_linear_new) > 0 and len(histos_linear_new) != len(histos_linear):
1124             raise Exception("This should never happen. len(histos_linear_new) %d != len(histos_linear) %d" % (len(histos_linear_new), len(histos_linear)))
1125         histos_linear = histos_linear_new
1126         if len(histos_linear) == 0:
1127             return []
1128 
1129         data = [ [h.GetBinContent(i) for i in range(1, h.GetNbinsX()+1)] for h in histos_linear]
1130         table = html.Table(["dummy"]*len(histos_linear), xbinlabels, data, None, None, None)
1131         data = table.tableAsRowColumn()
1132 
1133         for labs in labels:
1134             content.append('    <td></td>')
1135             content.extend(['    <td>%s</td>' % lab for lab in labs])
1136         content.extend([
1137             '   </tr>',
1138         ])
1139 
1140         for irow, row in enumerate(data):
1141             content.extend([
1142                 '    <tr>',
1143                 '     <td>%s</td>' % table.rowHeaders()[irow]
1144             ])
1145 
1146             for hindices in histos_index:
1147                 for hindex in hindices:
1148                     item = row[hindex]
1149                     formatted = self._format%item if item is not None else ""
1150                     content.append('     <td align="right">%s</td>' % formatted)
1151                 content.append('    <td></td>')
1152             del content[-1]
1153             content.append('    </tr>')
1154 
1155         content.append('  </table>')
1156         if haveShortLabels:
1157             for lab in legendLabels:
1158                 content.append('  %s<br/>' % lab)
1159 
1160         content.extend([
1161             ' </body>',
1162             '<html>'
1163         ])
1164 
1165         name = self._fileName
1166         if prefix is not None:
1167             name = prefix+name
1168         name += ".html"
1169         name = os.path.join(directory, name)
1170 
1171         with open(name, "w") as f:
1172             for line in content:
1173                 f.write(line)
1174                 f.write("\n")
1175         return [name]
1176 
1177 _dupandfakeSeedingTable = TrackingSeedingLayerTable("dupandfakeSeeding", [p.clone() for p in _dupandfakeSeedingPlots],
1178                                                     ["Fake rate", "Duplicate rate", "Pileup rate"], isRate=True)
1179 _extDistSeedingTable = TrackingSeedingLayerTable("distSeeding", [p.clone() for p in _extDistSeedingPlots],
1180                                                  ["All tracks", "True tracks", "Fake tracks", "Duplicate tracks"], isRate=False)
1181 
1182 def _trackingFolders(lastDirName="Track"):
1183     return [
1184         "DQMData/Run 1/Tracking/Run summary/"+lastDirName,
1185         "DQMData/Tracking/"+lastDirName,
1186         "DQMData/Run 1/RecoTrackV/Run summary/"+lastDirName,
1187         "DQMData/RecoTrackV/"+lastDirName,
1188     ]
1189 
1190 _simBasedPlots = [
1191     _effandfakePtEtaPhi,
1192     _effandfakeDxyDzBS,
1193     _effandfakeDxyDzPV,
1194     _effandfakeHitsLayers,
1195     _effandfakePos,
1196     _effandfakeDeltaRPU,
1197     _duplicateAlgo,
1198 ]
1199 _recoBasedPlots = [
1200     _dupandfakePtEtaPhi,
1201     _dupandfakeDxyDzBS,
1202     _dupandfakeDxyDzPV,
1203     _dupandfakeHitsLayers,
1204     _dupandfakePos,
1205     _dupandfakeDeltaRPU,
1206     _dupandfakeChi2Seeding,
1207     _dupandfakeSeedingTable,
1208     _pvassociation1,
1209     _pvassociation2,
1210     _dedx,
1211 #    _chargemisid,
1212     _hitsAndPt,
1213     _pulls,
1214     _resolutionsEta,
1215     _resolutionsPhi,
1216     _resolutionsPt,
1217     _tuning,
1218 ]
1219 _seedingBuildingPlots = _simBasedPlots + [
1220     _dupandfakePtEtaPhi,
1221     _dupandfakeDxyDzBS,
1222     _dupandfakeDxyDzPV,
1223     _dupandfakeHitsLayers,
1224     _dupandfakePos,
1225     _dupandfakeDeltaRPU,
1226     _dupandfakeChi2Seeding,
1227     _dupandfakeSeedingTable,
1228     _hitsAndPt,
1229 ] + _makeMVAPlots(1) \
1230   + _makeMVAPlots(2) \
1231   + _makeMVAPlots(2, hp=True) \
1232   + _makeMVAPlots(3) \
1233   + _makeMVAPlots(3, hp=True)
1234 # add more if needed
1235 _buildingExtendedPlots = [
1236     _pulls,
1237     _resolutionsEta,
1238     _resolutionsPhi,
1239     _resolutionsPt,
1240     _tuning,
1241 ]
1242 _extendedPlots = [
1243     _extDistPtEtaPhi,
1244     _extDistDxyDzBS,
1245     _extDistDxyDzPV,
1246     _extDistHitsLayers,
1247     _extDistPos,
1248     _extDistDeltaR,
1249     _extDistChi2Seeding,
1250     _extDistSeedingTable,
1251     _extResidualEta,
1252     _extResidualPt,
1253     _extNrecVsNsim,
1254     _extHitsLayers,
1255     _extDistSimPtEtaPhi,
1256     _extDistSimDxyDzBS,
1257     _extDistSimDxyDzPV,
1258     _extDistSimHitsLayers,
1259     _extDistSimPos,
1260     _extDistSimDeltaR,
1261 ]
1262 _summaryPlots = [
1263     _summary,
1264     _summaryN,
1265     _summaryByOriginalAlgo,
1266     _summaryByOriginalAlgoN,
1267     _summaryByAlgoMask,
1268     _summaryByAlgoMaskN,
1269     _summaryPt09,
1270     _summaryPt09N,
1271 ]
1272 _summaryPlotsHp = [
1273     _summaryHp,
1274     _summaryNHp,
1275     _summaryByOriginalAlgoHp,
1276     _summaryByOriginalAlgoNHp,
1277     _summaryByAlgoMaskHp,
1278     _summaryByAlgoMaskNHp,
1279     _summaryPt09Hp,
1280     _summaryPt09NHp,
1281 ]
1282 _summaryPlotsSeeds = [
1283     _summarySeeds,
1284     _summarySeedsN,
1285 ]
1286 _packedCandidatePlots = [
1287     _packedCandidateFlow,
1288     _packedCandidateKinematics,
1289     _packedCandidateVertex,
1290     _packedCandidateImpactParameter1,
1291     _packedCandidateImpactParameter2,
1292     _packedCandidateCovarianceMatrix1,
1293     _packedCandidateCovarianceMatrix2,
1294     _packedCandidateHits,
1295     _packedCandidateHitsHitPattern,
1296     _packedCandidateLayers,
1297 ]
1298 plotter = Plotter()
1299 plotterExt = Plotter()
1300 def _appendTrackingPlots(lastDirName, name, algoPlots, onlyForPileup=False, onlyForElectron=False, onlyForConversion=False, onlyForBHadron=False, seeding=False, building=False, rawSummary=False, highPuritySummary=True):
1301     folders = _trackingFolders(lastDirName)
1302     # to keep backward compatibility, this set of plots has empty name
1303     limiters = dict(onlyForPileup=onlyForPileup, onlyForElectron=onlyForElectron, onlyForConversion=onlyForConversion, onlyForBHadron=onlyForBHadron)
1304     commonForTPF = dict(purpose=PlotPurpose.TrackingIteration, fallbackRefFiles=[
1305         _trackingRefFileFallbackSLHC_Phase1PU140
1306     ], **limiters)
1307     common = dict(fallbackDqmSubFolders=[
1308         _trackingSubFoldersFallbackSLHC_Phase1PU140,
1309         _trackingSubFoldersFallbackFromPV, _trackingSubFoldersFallbackConversion,
1310         _trackingSubFoldersFallbackPreSplitting])
1311     plotter.append(name, folders, TrackingPlotFolder(*algoPlots, **commonForTPF), **common)
1312     extendedPlots = []
1313     if building:
1314         extendedPlots.extend(_buildingExtendedPlots)
1315     extendedPlots.extend(_extendedPlots)
1316     plotterExt.append(name, folders, TrackingPlotFolder(*extendedPlots, **commonForTPF), **common)
1317 
1318     summaryName = ""
1319     if name != "":
1320         summaryName += name+"_"
1321     summaryName += "summary"
1322     summaryPlots = []
1323     if rawSummary:
1324         summaryPlots.extend([_summaryRaw, _summaryRawN])
1325     summaryPlots.extend(_summaryPlots)
1326 
1327     common = dict(loopSubFolders=False, purpose=PlotPurpose.TrackingSummary, page="summary",
1328                   #numberOfEventsHistogram=_trackingNumberOfEventsHistogram, # FIXME
1329                   **limiters)
1330     plotter.append(summaryName, folders,
1331                    PlotFolder(*summaryPlots, section=name, **common))
1332     if highPuritySummary:
1333         plotter.append(summaryName+"_highPurity", folders,
1334                        PlotFolder(*_summaryPlotsHp, section=name+"_highPurity" if name != "" else "highPurity", **common),
1335                        fallbackNames=[summaryName]) # backward compatibility for release validation, the HP plots used to be in the same directory with all-track plots
1336     if seeding:
1337         plotter.append(summaryName+"_seeds", folders,
1338                        PlotFolder(*_summaryPlotsSeeds, section=name+"_seeds", **common))
1339 
1340     plotter.appendTable(summaryName, folders, TrackingSummaryTable(section=name))
1341     plotter.appendTable(summaryName, folders, TrackingSummaryTable(section=name+"Pt09", collection=TrackingSummaryTable.GeneralTracksPt09))
1342     if highPuritySummary:
1343         sectionName = name+"_highPurity" if name != "" else "highPurity"
1344         plotter.appendTable(summaryName+"_highPurity", folders, TrackingSummaryTable(section=sectionName, collection=TrackingSummaryTable.HighPurity))
1345         plotter.appendTable(summaryName+"_highPurity", folders, TrackingSummaryTable(section=sectionName+"Pt09", collection=TrackingSummaryTable.HighPurityPt09))
1346     if name == "":
1347         plotter.appendTable(summaryName, folders, TrackingSummaryTable(section="btvLike", collection=TrackingSummaryTable.BTVLike))
1348         plotter.appendTable(summaryName, folders, TrackingSummaryTable(section="ak4PFJets", collection=TrackingSummaryTable.AK4PFJets))
1349 _appendTrackingPlots("Track", "", _simBasedPlots+_recoBasedPlots)
1350 _appendTrackingPlots("TrackTPPtLess09", "tpPtLess09", _simBasedPlots)
1351 _appendTrackingPlots("TrackTPEtaGreater2p7", "tpEtaGreater2p7", _simBasedPlots+_recoBasedPlots)
1352 _appendTrackingPlots("TrackAllTPEffic", "allTPEffic", _simBasedPlots, onlyForPileup=True)
1353 _appendTrackingPlots("TrackFromPV", "fromPV", _simBasedPlots+_recoBasedPlots, onlyForPileup=True)
1354 _appendTrackingPlots("TrackFromPVAllTP", "fromPVAllTP", _simBasedPlots+_recoBasedPlots, onlyForPileup=True)
1355 _appendTrackingPlots("TrackFromPVAllTP2", "fromPVAllTP2", _simBasedPlots+_recoBasedPlots, onlyForPileup=True)
1356 _appendTrackingPlots("TrackSeeding", "seeding", _seedingBuildingPlots, seeding=True)
1357 _appendTrackingPlots("TrackBuilding", "building", _seedingBuildingPlots, building=True)
1358 _appendTrackingPlots("TrackConversion", "conversion", _simBasedPlots+_recoBasedPlots, onlyForConversion=True, rawSummary=True, highPuritySummary=False)
1359 _appendTrackingPlots("TrackGsf", "gsf", _simBasedPlots+_recoBasedPlots, onlyForElectron=True, rawSummary=True, highPuritySummary=False)
1360 _appendTrackingPlots("TrackBHadron", "bhadron", _simBasedPlots+_recoBasedPlots, onlyForBHadron=True)
1361 _appendTrackingPlots("TrackDisplaced", "displaced", _simBasedPlots+_recoBasedPlots)
1362 # Pixel tracks
1363 def _appendPixelTrackingPlots(lastDirName, name):
1364     _common = dict(purpose=PlotPurpose.Pixel, page="pixel")
1365     _folders = _trackingFolders(lastDirName)
1366 
1367     plotter.append(name, _folders, TrackingPlotFolder(*(_simBasedPlots+_recoBasedPlots), **_common))
1368     plotterExt.append(name, _folders, TrackingPlotFolder(*_extendedPlots, **_common))
1369 
1370     plotter.append(name+"_summary",  _folders, PlotFolder(_summaryRaw, _summaryRawN, loopSubFolders=False, purpose=PlotPurpose.TrackingSummary, page="summary", section=name))
1371     plotter.append(name+"_summary",  _folders, PlotFolder(_summaryRaw, _summaryRawN, loopSubFolders=False, purpose=PlotPurpose.TrackingSummary, page="summary", section=name+"Pt09"))
1372     plotter.appendTable(name+"_summary", _folders, TrackingSummaryTable(section=name, collection=TrackingSummaryTable.Pixel))
1373     plotter.appendTable(name+"_summary", _folders, TrackingSummaryTable(section=name+"Pt09", collection=TrackingSummaryTable.PixelPt09))
1374 _appendPixelTrackingPlots("PixelTrack", "pixel")
1375 _appendPixelTrackingPlots("PixelTrackFromPV", "pixelFromPV")
1376 _appendPixelTrackingPlots("PixelTrackFromPVAllTP", "pixelFromPVAllTP")
1377 _appendPixelTrackingPlots("PixelTrackBHadron", "pixelbhadron")
1378 
1379 
1380 # MiniAOD
1381 plotter.append("packedCandidate", _trackingFolders("PackedCandidate"),
1382                PlotFolder(*_packedCandidatePlots, loopSubFolders=False,
1383                           purpose=PlotPurpose.MiniAOD, page="miniaod", section="PackedCandidate"))
1384 plotter.append("packedCandidateLostTracks", _trackingFolders("PackedCandidate/lostTracks"),
1385                PlotFolder(*_packedCandidatePlots, loopSubFolders=False,
1386                           purpose=PlotPurpose.MiniAOD, page="miniaod", section="PackedCandidate (lostTracks)"))
1387 
1388 # HLT
1389 _hltFolder = [
1390     "DQMData/Run 1/HLT/Run summary/Tracking/ValidationWRTtp",
1391 ]
1392 plotterHLT = Plotter()
1393 plotterHLTExt = Plotter()
1394 _common = dict(purpose=PlotPurpose.HLT, page="hlt")
1395 plotterHLT.append("hlt", _hltFolder, TrackingPlotFolder(*(_simBasedPlots+_recoBasedPlots), **_common))
1396 plotterHLTExt.append("hlt", _hltFolder, TrackingPlotFolder(*_extendedPlots, **_common))
1397 
1398 # Timing
1399 class Iteration:
1400     def __init__(self, name, clusterMasking=None, seeding=None, building=None, fit=None, selection=None, other=[]):
1401         self._name = name
1402 
1403         def _set(param, name, modules):
1404             if param is not None:
1405                 setattr(self, name, param)
1406             else:
1407                 setattr(self, name, modules)
1408 
1409         _set(clusterMasking, "_clusterMasking", [self._name+"Clusters"])
1410         # it's fine to include e.g. quadruplets here also for pair
1411         # steps, as non-existing modules are just ignored
1412         _set(seeding, "_seeding", [self._name+"SeedingLayers", self._name+"TrackingRegions", self._name+"HitDoublets", self._name+"HitTriplets", self._name+"HitQuadruplets", self._name+"Seeds"])
1413         trackCandidates = self._name+"TrackCandidates"
1414         _set(building, "_building", [trackCandidates+"MkFitSeeds", trackCandidates+"MkFit", trackCandidates])
1415         _set(fit, "_fit", [self._name+"Tracks"])
1416         _set(selection, "_selection", [self._name])
1417         self._other = other
1418 
1419     def name(self):
1420         return self._name
1421 
1422     def all(self):
1423         return self._clusterMasking+self._seeding+self._building+self._fit+self._selection+self._other
1424 
1425     def clusterMasking(self):
1426         return self._clusterMasking
1427 
1428     def seeding(self):
1429         return self._seeding
1430 
1431     def building(self):
1432         return self._building
1433 
1434     def fit(self):
1435         return self._fit
1436 
1437     def selection(self):
1438         return self._selection
1439 
1440     def other(self):
1441         return self._other
1442 
1443     def modules(self):
1444         return [("ClusterMask", self.clusterMasking()),
1445                 ("Seeding", self.seeding()),
1446                 ("Building", self.building()),
1447                 ("Fit", self.fit()),
1448                 ("Selection", self.selection()),
1449                 ("Other", self.other())]
1450 
1451 
1452 _iterations = [
1453     Iteration("initialStepPreSplitting", clusterMasking=[],
1454               seeding=["initialStepSeedLayersPreSplitting",
1455                        "initialStepTrackingRegionsPreSplitting",
1456                        "initialStepHitDoubletsPreSplitting",
1457                        "initialStepHitTripletsPreSplitting",
1458                        "initialStepHitQuadrupletsPreSplitting",
1459                        "initialStepSeedsPreSplitting"],
1460               building=["initialStepTrackCandidatesPreSplitting",
1461                         "initialStepTrackCandidatesMkFitSeedsPreSplitting",
1462                         "initialStepTrackCandidatesMkFitPreSplitting"],
1463               fit=["initialStepTracksPreSplitting"],
1464               other=["firstStepPrimaryVerticesPreSplitting",
1465                      "initialStepTrackRefsForJetsPreSplitting",
1466                      "caloTowerForTrkPreSplitting",
1467                      "ak4CaloJetsForTrkPreSplitting",
1468                      "jetsForCoreTrackingPreSplitting",
1469                      "siPixelClusters",
1470                      "siPixelRecHits",
1471                      "MeasurementTrackerEvent",
1472                      "siPixelClusterShapeCache",
1473                      "mkFitSiPixelHitsPreSplitting",
1474                      "mkFitSiStripHits",
1475                      "mkFitEventOfHitsPreSplitting"]),
1476     Iteration("initialStep", clusterMasking=[],
1477               selection=["initialStepClassifier1",
1478                          "initialStepClassifier2",
1479                          "initialStepClassifier3",
1480                          "initialStep",
1481                          "initialStepSelector"],
1482               other=["firstStepPrimaryVerticesUnsorted",
1483                      "initialStepTrackRefsForJets",
1484                      "caloTowerForTrk",
1485                      "ak4CaloJetsForTrk",
1486                      "firstStepPrimaryVertices",
1487                      "mkFitSiPixelHits",
1488                      "mkFitEventOfHits"]),
1489     Iteration("highPtTripletStep",
1490               selection=["highPtTripletStepClassifier1",
1491                          "highPtTripletStepClassifier2",
1492                          "highPtTripletStepClassifier3",
1493                          "highPtTripletStep",
1494                          "highPtTripletStepSelector"]),
1495     Iteration("detachedQuadStep",
1496               selection=["detachedQuadStepClassifier1",
1497                          "detachedQuadStepClassifier2",
1498                          "detachedQuadStep",
1499                          "detachedQuadStepSelector"]),
1500     Iteration("detachedTripletStep",
1501               selection=["detachedTripletStepClassifier1",
1502                          "detachedTripletStepClassifier2",
1503                          "detachedTripletStep",
1504                          "detachedTripletStepSelector"]),
1505     Iteration("lowPtQuadStep",
1506               selection=["lowPtQuadStepClassifier1",
1507                          "lowPtQuadStepClassifier2",
1508                          "lowPtQuadStep",
1509                          "lowPtQuadStepSelector"]),
1510     Iteration("lowPtTripletStep",
1511               selection=["lowPtTripletStepClassifier1",
1512                          "lowPtTripletStepClassifier2",
1513                          "lowPtTripletStep",
1514                          "lowPtTripletStepSelector"]),
1515     Iteration("pixelPairStep",
1516               seeding=["pixelPairStepSeedLayers",
1517                        "pixelPairStepSeedLayersB",
1518                        "pixelPairStepSeedLayersC",
1519                        "pixelPairStepTrackingRegions",
1520                        "pixelPairStepTrackingRegionsB",
1521                        "pixelPairStepTrackingRegionsC",
1522                        "pixelPairStepTrackingRegionsSeedLayersB",
1523                        "pixelPairStepHitDoublets",
1524                        "pixelPairStepHitDoubletsB",
1525                        "pixelPairStepHitDoubletsC",
1526                        "pixelPairStepSeedsA",
1527                        "pixelPairStepSeedsB",
1528                        "pixelPairStepSeedsC",
1529                        "pixelPairStepSeeds",],
1530               selection=["pixelPairStep",
1531                          "pixelPairStepSelector"]),
1532     Iteration("mixedTripletStep",
1533               seeding=["mixedTripletStepSeedLayersA",
1534                        "mixedTripletStepSeedLayersB",
1535                        "mixedTripletStepTrackingRegionsA",
1536                        "mixedTripletStepTrackingRegionsB",
1537                        "mixedTripletStepHitDoubletsA",
1538                        "mixedTripletStepHitDoubletsB",
1539                        "mixedTripletStepHitTripletsA",
1540                        "mixedTripletStepHitTripletsB",
1541                        "mixedTripletStepSeedsA",
1542                        "mixedTripletStepSeedsB",
1543                        "mixedTripletStepSeeds"],
1544               selection=["mixedTripletStepClassifier1",
1545                          "mixedTripletStepClassifier2",
1546                          "mixedTripletStep",
1547                          "mixedTripletStepSelector"]),
1548     Iteration("pixelLessStep",
1549               selection=["pixelLessStepClassifier1",
1550                          "pixelLessStepClassifier2",
1551                          "pixelLessStep",
1552                          "pixelLessStepSelector"]),
1553     Iteration("tobTecStep",
1554               seeding=["tobTecStepSeedLayersTripl",
1555                        "tobTecStepSeedLayersPair",
1556                        "tobTecStepTrackingRegionsTripl",
1557                        "tobTecStepTrackingRegionsPair",
1558                        "tobTecStepHitDoubletsTripl",
1559                        "tobTecStepHitDoubletsPair",
1560                        "tobTecStepHitTripletsTripl",
1561                        "tobTecStepSeedsTripl",
1562                        "tobTecStepSeedsPair",
1563                        "tobTecStepSeeds"],
1564               selection=["tobTecStepClassifier1",
1565                          "tobTecStepClassifier2",
1566                          "tobTecStep",
1567                          "tobTecStepSelector"]),
1568     Iteration("displacedGeneralStep",
1569               seeding=["displacedGeneralStepSeedLayers",
1570                        "displacedGeneralStepTrackingRegions",
1571                        "displacedGeneralStepHitDoublets",
1572                        "displacedGeneralStepHitTriplets",
1573                        "displacedGeneralStepSeeds"],
1574               selection=["displacedGeneralStepClassifier1",
1575                          "displacedGeneralStepClassifier2",
1576                          "displacedGeneralStep",
1577                          "displacedGeneralStepSelector"]),
1578     Iteration("jetCoreRegionalStep",
1579               clusterMasking=[],
1580               other=["jetsForCoreTracking",
1581                      "firstStepGoodPrimaryVertices",
1582                      ]),
1583     Iteration("muonSeededSteps",
1584               clusterMasking=[],
1585               seeding=["muonSeededSeedsInOut",
1586                        "muonSeededSeedsOutIn"],
1587               building=["muonSeededTrackCandidatesInOut",
1588                         "muonSeededTrackCandidatesOutIn"],
1589               fit=["muonSeededTracksInOut",
1590                    "muonSeededTracksOutIn"],
1591               selection=["muonSeededTracksInOutClassifier",
1592                          "muonSeededTracksInOutSelector",
1593                          "muonSeededTracksOutIntClassifier",
1594                          "muonSeededTracksOutIntSelector"],
1595 #              other=["earlyMuons"]
1596           ),
1597     Iteration("duplicateMerge",
1598               clusterMasking=[], seeding=[],
1599               building=["duplicateTrackCandidates"],
1600               fit=["mergedDuplicateTracks"],
1601               selection=["duplicateTrackClassifier"]),
1602     Iteration("generalTracks",
1603               clusterMasking=[], seeding=[], building=[], fit=[], selection=[],
1604               other=["preDuplicateMergingGeneralTracks",
1605                      "generalTracks"]),
1606     Iteration("ConvStep",
1607               clusterMasking=["convClusters"],
1608               seeding=["convLayerPairs",
1609                        "photonConvTrajSeedFromSingleLeg"],
1610               building=["convTrackCandidates"],
1611               fit=["convStepTracks"],
1612               selection=["convStepSelector"]),
1613     Iteration("Other", clusterMasking=[], seeding=[], building=[], fit=[], selection=[],
1614               other=["trackerClusterCheckPreSplitting",
1615                      "trackerClusterCheck"]),
1616 ]
1617 
1618 def _iterModuleMap(includeConvStep=True, onlyConvStep=False):
1619     iterations = _iterations
1620     if not includeConvStep:
1621         iterations = [i for i in iterations if i.name() != "ConvStep"]
1622     if onlyConvStep:
1623         iterations = [i for i in iterations if i.name() == "ConvStep"]
1624     return collections.OrderedDict([(i.name(), i.all()) for i in iterations])
1625 def _stepModuleMap():
1626     def getProp(prop):
1627         ret = []
1628         for i in _iterations:
1629             if i.name() == "ConvStep":
1630                 continue
1631             ret.extend(getattr(i, prop)())
1632         return ret
1633 
1634     return collections.OrderedDict([
1635         ("ClusterMask", getProp("clusterMasking")),
1636         ("Seeding", getProp("seeding")),
1637         ("Building", getProp("building")),
1638         ("Fitting", getProp("fit")),
1639         ("Selection", getProp("selection")),
1640         ("Other", getProp("other"))
1641     ])
1642 
1643 class TimePerEventPlot:
1644     def __init__(self, name, timeHisto):
1645         self._name = name
1646         self._timeHisto = timeHisto
1647         self._eventsHisto = "path time_real"
1648         self._cache = {}
1649 
1650     def __str__(self):
1651         return self._name
1652 
1653     def _create(self, tdirectory):
1654         timeTh1 = plotting._getOrCreateObject(tdirectory, self._timeHisto)
1655         if timeTh1 is None:
1656             return None
1657 
1658         eventsTh1 = plotting._getOrCreateObject(tdirectory, self._eventsHisto)
1659         if eventsTh1 is None:
1660             return None
1661         nevents = eventsTh1.GetEntries()
1662         if nevents == 0:
1663             return None
1664 
1665         ret = timeTh1.Clone(self._name)
1666         xaxis = ret.GetXaxis()
1667         for i in range(1, ret.GetNbinsX()+1):
1668             ret.SetBinContent(i, ret.GetBinContent(i)/nevents)
1669             ret.SetBinError(i, ret.GetBinError(i)/nevents)
1670             xaxis.SetBinLabel(i, xaxis.GetBinLabel(i).replace(" (unscheduled)", ""))
1671         return ret
1672 
1673     def create(self, tdirectory):
1674         path = tdirectory.GetPath()
1675         if path not in self._cache:
1676             self._cache[path] = self._create(tdirectory)
1677         return self._cache[path]
1678 
1679 class TimePerTrackPlot:
1680     def __init__(self, name, timeHisto, selectedTracks=False):
1681         self._name = name
1682         self._timeHisto = timeHisto
1683         self._selectedTracks = selectedTracks
1684 
1685     def __str__(self):
1686         return self._name
1687 
1688     def _getDirectory(self, tfile):
1689         for dirName in _trackingFolders():
1690             tdir = tfile.Get(dirName)
1691             if tdir != None:
1692                 return tdir
1693         return None
1694 
1695     def create(self, tdirectory):
1696         timeTh1 = plotting._getOrCreateObject(tdirectory, self._timeHisto)
1697         if timeTh1 is None:
1698             return None
1699 
1700         # this is bit of a hack, but as long as it is needed only
1701         # here, I won't invest in better solution
1702         tfile = tdirectory.GetFile()
1703         trkDir = self._getDirectory(tfile)
1704         if trkDir is None:
1705             return None
1706 
1707         iterMap = copy.copy(_collLabelMapHp)
1708         del iterMap["generalTracks"]
1709         del iterMap["jetCoreRegionalStep"] # this is expensive per track on purpose
1710         if self._selectedTracks:
1711             renameBin = lambda bl: _summaryBinRename(bl, highPurity=True, byOriginalAlgo=False, byAlgoMask=True, ptCut=False, seeds=False)
1712         else:
1713             renameBin = lambda bl: _summaryBinRename(bl, highPurity=False, byOriginalAlgo=False, byAlgoMask=False, ptCut=False, seeds=False)
1714         recoAB = AggregateBins("tmp", "num_reco_coll", mapping=iterMap,ignoreMissingBins=True, renameBin=renameBin)
1715         h_reco_per_iter = recoAB.create(trkDir)
1716         if h_reco_per_iter is None:
1717             return None
1718         values = {}
1719         for i in range(1, h_reco_per_iter.GetNbinsX()+1):
1720             values[h_reco_per_iter.GetXaxis().GetBinLabel(i)] = h_reco_per_iter.GetBinContent(i)
1721 
1722 
1723         result = []
1724         for i in range(1, timeTh1.GetNbinsX()+1):
1725             iterName = timeTh1.GetXaxis().GetBinLabel(i)
1726             if iterName in values:
1727                 ntrk = values[iterName]
1728                 result.append( (iterName,
1729                                 timeTh1.GetBinContent(i)/ntrk if ntrk > 0 else 0,
1730                                 timeTh1.GetBinError(i)/ntrk if ntrk > 0 else 0) )
1731 
1732         if len(result) == 0:
1733             return None
1734 
1735         res = ROOT.TH1F(self._name, self._name, len(result), 0, len(result))
1736         for i, (label, value, error) in enumerate(result):
1737             res.GetXaxis().SetBinLabel(i+1, label)
1738             res.SetBinContent(i+1, value)
1739             res.SetBinError(i+1, error)
1740 
1741         return res
1742 
1743 class TrackingIterationOrder:
1744     def __init__(self):
1745         self._cache = {}
1746 
1747     def _findOrder(self, f):
1748         h = f.Get(_trackingIterationOrderHistogram)
1749         if not h:
1750             return None
1751         xaxis = h.GetXaxis()
1752         def _edit(s):
1753             # remove "Tracks" from the track producer name to get the iteration name
1754             # muonSeeded iterations do not have "Step" in the producer name, so add it here
1755             return s.replace("Tracks", "").replace("muonSeeded", "muonSeededStep")
1756         return [_edit(xaxis.GetBinLabel(i)) for i in range(1, h.GetNbinsX()+1)]
1757 
1758     def __call__(self, tdirectory, labels):
1759         ret = list(range(0, len(labels)))
1760         f = tdirectory.GetFile()
1761         if not f:
1762             return ret
1763 
1764         if not f.GetName() in self._cache:
1765             r = self._findOrder(f)
1766             if r is None:
1767                 return ret
1768             self._cache[f.GetName()] = r
1769         order = self._cache[f.GetName()]
1770 
1771         # O(N^2) I know, but we're talking about O(10) elements...
1772         orderIndices = []
1773         for l in order:
1774             try:
1775                 orderIndices.append(labels.index(l))
1776             except ValueError:
1777                 pass
1778         ret = []
1779         for i, l in enumerate(labels):
1780             if l in order:
1781                 try:
1782                     found = orderIndices.index(i)
1783                     if found == 0:
1784                         ret.append(i)
1785                     else:
1786                         ret.append(orderIndices[0])
1787                 except ValueError:
1788                     ret.append(orderIndices[0])
1789                 orderIndices.pop(0)
1790             else:
1791                 ret.append(i)
1792         return ret
1793 
1794 _time_per_event_cpu = TimePerEventPlot("timePerEvent", "module_time_thread_total")
1795 _time_per_event_real = TimePerEventPlot("timePerEvent", "module_time_real_total")
1796 
1797 class TrackingTimingTable:
1798     def __init__(self):
1799         self._purpose = PlotPurpose.Timing
1800         self._page = "timing"
1801         self._section = "timing"
1802 
1803     def getPurpose(self):
1804         return self._purpose
1805 
1806     def getPage(self):
1807         return self._page
1808 
1809     def getSection(self, dqmSubFolder):
1810         return self._section
1811 
1812     def _getValues(self, tdirectory, histo):
1813         h = tdirectory.Get(histo)
1814         totalReco = None
1815         if h:
1816             totalReco = "%.1f" % h.Integral()
1817 
1818         creator = AggregateBins("iteration", histo, _iterModuleMap(includeConvStep=False), ignoreMissingBins=True)
1819         h = creator.create(tdirectory)
1820         totalTracking = None
1821         if h:
1822             totalTracking = "%.1f" % h.Integral()
1823 
1824         creator = AggregateBins("iteration", histo, _iterModuleMap(onlyConvStep=True), ignoreMissingBins=True)
1825         h = creator.create(tdirectory)
1826         totalConvStep = None
1827         if h:
1828             totalConvStep = "%.1f" % h.Integral()
1829 
1830         return [
1831             totalReco,
1832             totalTracking,
1833             totalConvStep,
1834         ]
1835 
1836     def create(self, tdirectory):
1837         cpuValues = self._getValues(tdirectory, _time_per_event_cpu)
1838         realValues = self._getValues(tdirectory, _time_per_event_real)
1839 
1840         return cpuValues + realValues
1841 
1842     def headers(self):
1843         return [
1844             "Average reco CPU time / event (ms)",
1845             "Average tracking (w/o convStep) CPU time / event (ms)",
1846             "Average convStep CPU time / event (ms)",
1847             "Average reco real time / event (ms)",
1848             "Average tracking (w/o convStep) real time / event (ms)",
1849             "Average convStep real time / event (ms)",
1850         ]
1851 
1852 _common = {
1853     "drawStyle": "P",
1854     "xbinlabelsize": 10,
1855     "xbinlabeloption": "d"
1856 }
1857 
1858 _iteration_reorder = TrackingIterationOrder()
1859 _time_per_iter_cpu = AggregateBins("iteration", _time_per_event_cpu, _iterModuleMap(), ignoreMissingBins=True, reorder=_iteration_reorder)
1860 _time_per_iter_real = AggregateBins("iteration", _time_per_event_real, _iterModuleMap(), ignoreMissingBins=True, reorder=_iteration_reorder)
1861 
1862 _timing_summaryCPU = PlotGroup("summaryCPU", [
1863     Plot(_time_per_iter_cpu,
1864          ytitle="Average CPU time (ms)", title="Average CPU time / event", legendDx=-0.4, **_common),
1865     Plot(AggregateBins("iteration_fraction", _time_per_event_cpu, _iterModuleMap(), ignoreMissingBins=True, reorder=_iteration_reorder),
1866          ytitle="Fraction", title="", normalizeToUnitArea=True, **_common),
1867     #
1868     Plot(AggregateBins("step", _time_per_event_cpu, _stepModuleMap(), ignoreMissingBins=True),
1869          ytitle="Average CPU time (ms)", title="Average CPU time / event", **_common),
1870     Plot(AggregateBins("step_fraction", _time_per_event_cpu, _stepModuleMap(), ignoreMissingBins=True),
1871          ytitle="Fraction", title="", normalizeToUnitArea=True, **_common),
1872     #
1873     Plot(TimePerTrackPlot("iteration_track", _time_per_iter_cpu, selectedTracks=False),
1874          ytitle="Average CPU time / built track (ms)", title="Average CPU time / built track", **_common),
1875     Plot(TimePerTrackPlot("iteration_trackhp", _time_per_iter_cpu, selectedTracks=True),
1876          ytitle="Average CPU time / selected track (ms)", title="Average CPU time / selected HP track by algoMask", **_common),
1877     ],
1878 )
1879 _timing_summaryReal = PlotGroup("summaryReal", [
1880     Plot(_time_per_iter_real,
1881          ytitle="Average real time (ms)", title="Average real time / event", legendDx=-0.4, **_common),
1882     Plot(AggregateBins("iteration_fraction", _time_per_event_real, _iterModuleMap(), ignoreMissingBins=True, reorder=_iteration_reorder),
1883          ytitle="Fraction", title="", normalizeToUnitArea=True, **_common),
1884     #
1885     Plot(AggregateBins("step", _time_per_event_real, _stepModuleMap(), ignoreMissingBins=True),
1886          ytitle="Average real time (ms)", title="Average real time / event", **_common),
1887     Plot(AggregateBins("step_fraction", _time_per_event_real, _stepModuleMap(), ignoreMissingBins=True),
1888          ytitle="Fraction", title="", normalizeToUnitArea=True, **_common),
1889     #
1890     Plot(TimePerTrackPlot("iteration_track", _time_per_iter_real, selectedTracks=False),
1891          ytitle="Average real time / built track (ms)", title="Average real time / built track", **_common),
1892     Plot(TimePerTrackPlot("iteration_trackhp", _time_per_iter_real, selectedTracks=True),
1893          ytitle="Average real time / selected track (ms)", title="Average real time / selected HP track by algoMask", **_common),
1894     ],
1895 )
1896 
1897 _timing_iterationsCPU = PlotGroup("iterationsCPU", [
1898     Plot(AggregateBins(i.name(), _time_per_event_cpu, collections.OrderedDict(i.modules()), ignoreMissingBins=True),
1899          ytitle="Average CPU time (ms)", title=i.name(), **_common)
1900     for i in _iterations
1901 ],
1902                                ncols=4, legend=False
1903 )
1904 _timing_iterationsReal = PlotGroup("iterationsReal", [
1905     Plot(AggregateBins(i.name(), _time_per_event_real, collections.OrderedDict(i.modules()), ignoreMissingBins=True),
1906          ytitle="Average real time (ms)", title=i.name(), **_common)
1907     for i in _iterations
1908 ],
1909                                ncols=4, legend=False
1910 )
1911 
1912 # TODO: to be updated to new FastTimerService format later
1913 #_pixelTiming = PlotGroup("pixelTiming", [
1914 #    Plot(AggregateBins("pixel", "reconstruction_step_module_average", {"pixelTracks": ["pixelTracks"]}), ytitle="Average processing time [ms]", title="Average processing time / event", drawStyle="HIST")
1915 #])
1916 
1917 _timeFolders = [
1918 #    "DQMData/Run 1/DQM/Run summary/TimerService/process RECO paths/path reconstruction_step",
1919     "DQMData/Run 1/DQM/Run summary/TimerService/process RECO paths/path prevalidation_step", # because of unscheduled, it's actually prevalidation_step that has all the tracking modules?
1920 ]
1921 timePlotter = Plotter()
1922 timePlotter.append("timing", _timeFolders, PlotFolder(
1923     _timing_summaryCPU,
1924     _timing_iterationsCPU,
1925     _timing_summaryReal,
1926     _timing_iterationsReal,
1927     # _pixelTiming,
1928     loopSubFolders=False, purpose=PlotPurpose.Timing, page="timing"
1929 ))
1930 timePlotter.appendTable("timing", _timeFolders, TrackingTimingTable())
1931 
1932 _common = {"stat": True, "normalizeToUnitArea": True, "drawStyle": "hist"}
1933 _tplifetime = PlotGroup("tplifetime", [
1934     Plot("TPlip", xtitle="TP lip", **_common),
1935     Plot("TPtip", xtitle="TP tip", **_common),
1936 ])
1937 
1938 tpPlotter = Plotter()
1939 tpPlotter.append("tp", [
1940     "DQMData/Run 1/Tracking/Run summary/TrackingMCTruth/TrackingParticle",
1941     "DQMData/Tracking/TrackingMCTruth/TrackingParticle",
1942 ], PlotFolder(
1943     _tplifetime,
1944 ))