Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-11-26 02:34:39

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