Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:33:24

0001 import os
0002 import collections
0003 
0004 def _lowerFirst(s):
0005     return s[0].lower()+s[1:]
0006 
0007 _sampleName = {
0008     "RelValMinBias": "Min Bias",
0009     "RelValTTbar": "TTbar",
0010     "RelValQCD_Pt_600_800": "QCD Pt 600 to 800",
0011     "RelValQCD_Pt_3000_3500": "QCD Pt 3000 to 3500",
0012     "RelValQCD_FlatPt_15_3000": "QCD Flat Pt 15 to 3000",
0013     "RelValZMM": "ZMuMu",
0014     "RelValWjet_Pt_3000_3500": "Wjet Pt 3000 to 3500",
0015     "RelValH125GGgluonfusion": "Higgs to gamma gamma",
0016     "RelValSingleElectronPt35": "Single Electron Pt 35",
0017     "RelValSingleElectronPt35Extended": "Single Electron Pt 35 (extended eta)",
0018     "RelValSingleElectronPt10": "Single Electron Pt 10",
0019     "RelValSingleMuPt1": "Single Muon Pt 1",
0020     "RelValSingleMuPt10": "Single Muon Pt 10",
0021     "RelValSingleMuPt10Extended": "Single Muon Pt 10 (extended eta)",
0022     "RelValSingleMuPt100": "Single Muon Pt 100",
0023     "RelValTenMuE_0_200": "Ten muon Pt 0-200",
0024 }
0025 
0026 _sampleFileName = {
0027     "RelValMinBias": "minbias",
0028     "RelValTTbar": "ttbar",
0029     "RelValQCD_Pt_600_800": "qcd600",
0030     "RelValQCD_Pt_3000_3500": "qcd3000",
0031     "RelValQCD_FlatPt_15_3000": "qcdflat",
0032     "RelValZMM": "zmm",
0033     "RelValWjet_Pt_3000_3500": "wjet3000",
0034     "RelValH125GGgluonfusion": "hgg",
0035     "RelValSingleElectronPt35": "ele35",
0036     "RelValSingleElectronPt35Extended": "ele35ext",
0037     "RelValSingleElectronPt10": "ele10",
0038     "RelValSingleMuPt1": "mu1",
0039     "RelValSingleMuPt10": "mu10",
0040     "RelValSingleMuPt10Extended": "mu10ext",
0041     "RelValSingleMuPt100": "mu100",
0042     "RelValTenMuE_0_200": "tenmu200",
0043 }
0044 
0045 _allName = "All tracks"
0046 _allTPEfficName = _allName+" (all TPs)"
0047 _fromPVName = "Tracks from PV"
0048 _fromPVAllTPName = "Tracks from PV (all TPs)"
0049 _tpPtLess09Name = "All tracks (TP pT < 0.9 GeV)"
0050 _tpEtaGreater2p7Name = "All tracks (TP |eta| > 2.7)"
0051 _conversionName = "Tracks for conversions"
0052 _gsfName = "Electron GSF tracks"
0053 _bhadronName = "All tracks (B-hadron TPs)"
0054 _displacedName = "All tracks (TPs with no tip or lip cuts)"
0055 def _toHP(s):
0056     return "High purity "+_lowerFirst(s)
0057 def _toOriAlgo(s):
0058     return s.replace("tracks", "tracks by originalAlgo")
0059 def _toAlgoMask(s):
0060     return s.replace("tracks", "tracks by algoMask")
0061 def _allToHP(s):
0062     return s.replace("All", "High purity")
0063 def _allToBTV(s):
0064     return s.replace("All", "BTV-like")
0065 def _allPtCut(s):
0066     return s.replace("All tracks", "Tracks pT > 0.9 GeV")
0067 def _ptCut(s):
0068     return s.replace("Tracks", "Tracks pT > 0.9 GeV").replace("tracks", "tracks pT > 0.9 GeV")
0069 def _allToPixel(s):
0070     return s.replace("All", "Pixel")
0071 def _toPixel(s):
0072     return s.replace("Tracks", "Pixel tracks")
0073 _trackQualityNameOrder = collections.OrderedDict([
0074     ("seeding_seeds", "Seeds"),
0075     ("seeding_seedsa", "Seeds A"),
0076     ("seeding_seedsb", "Seeds B"),
0077     ("seeding_seedsc", "Seeds C"),
0078     ("seeding_seedstripl", "Seeds triplets"),
0079     ("seeding_seedspair", "Seeds pairs"),
0080     ("building_", "Built tracks"),
0081     ("", _allName),
0082     ("highPurity", _allToHP(_allName)),
0083     ("Pt09", _allPtCut(_allName)),
0084     ("highPurityPt09", _ptCut(_allToHP(_allName))),
0085     ("ByOriginalAlgo", _toOriAlgo(_allName)),
0086     ("highPurityByOriginalAlgo", _toOriAlgo(_toHP(_allName))),
0087     ("ByAlgoMask", _toAlgoMask(_allName)),
0088     ("highPurityByAlgoMask", _toAlgoMask(_toHP(_allName))),
0089     ("tpPtLess09_", _tpPtLess09Name),
0090     ("tpPtLess09_highPurity", _allToHP(_tpPtLess09Name)),
0091     ("tpPtLess09_ByOriginalAlgo", _toOriAlgo(_tpPtLess09Name)),
0092     ("tpPtLess09_highPurityByOriginalAlgo", _toOriAlgo(_allToHP(_tpPtLess09Name))),
0093     ("tpPtLess09_ByAlgoMask", _toAlgoMask(_tpPtLess09Name)),
0094     ("tpPtLess09_highPurityByAlgoMask", _toAlgoMask(_allToHP(_tpPtLess09Name))),
0095     ("tpEtaGreater2p7_", _tpEtaGreater2p7Name),
0096     ("tpEtaGreater2p7_highPurity", _allToHP(_tpEtaGreater2p7Name)),
0097     ("btvLike", _allToBTV(_allName)),
0098     ("ak4PFJets", "AK4 PF jets"),
0099     ("allTPEffic_", _allTPEfficName),
0100     ("allTPEffic_highPurity", _allToHP(_allTPEfficName)),
0101     ("fromPV_", _fromPVName),
0102     ("fromPV_highPurity", _toHP(_fromPVName)),
0103     ("fromPV_Pt09", _ptCut(_fromPVName)),
0104     ("fromPV_highPurityPt09", _toHP(_ptCut(_fromPVName))),
0105     ("fromPVAllTP_", _fromPVAllTPName),
0106     ("fromPVAllTP_highPurity", _toHP(_fromPVAllTPName)),
0107     ("fromPVAllTP_Pt09", _ptCut(_fromPVAllTPName)),
0108     ("fromPVAllTP_highPurityPt09", _toHP(_ptCut(_fromPVAllTPName))),
0109     ("fromPVAllTP2_", _fromPVAllTPName.replace("PV", "PV v2")),
0110     ("fromPVAllTP2_highPurity", "High purity "+_lowerFirst(_fromPVAllTPName).replace("PV", "PV v2")),
0111     ("fromPVAllTP2_Pt09", _fromPVAllTPName.replace("Tracks", "Tracks pT > 0.9 GeV").replace("PV", "PV v2")),
0112     ("fromPVAllTP2_highPurityPt09", _toHP(_ptCut(_fromPVAllTPName)).replace("PV", "PV v2")),
0113     ("conversion_", _conversionName),
0114     ("gsf_", _gsfName),
0115     ("bhadron_", _bhadronName),
0116     ("bhadron_highPurity", _allToHP(_bhadronName)),
0117     ("bhadron_ByOriginalAlgo", _toOriAlgo(_bhadronName)),
0118     ("bhadron_highPurityByOriginalAlgo", _toOriAlgo(_toHP(_bhadronName))),
0119     ("bhadron_ByAlgoMask", _toAlgoMask(_bhadronName)),
0120     ("bhadron_highPurityByAlgoMask", _toAlgoMask(_allToHP(_bhadronName))),
0121     ("bhadron_btvLike", _allToBTV(_bhadronName)),
0122     ("displaced_", _displacedName),
0123     ("displaced_highPurity", _allToHP(_displacedName)),
0124     ("displaced_ByOriginalAlgo", _toOriAlgo(_displacedName)),
0125     ("displaced_highPurityByOriginalAlgo", _toOriAlgo(_allToHP(_displacedName))),
0126     ("displaced_ByAlgoMask", _toAlgoMask(_displacedName)),
0127     ("displaced_highPurityByAlgoMask", _toAlgoMask(_allToHP(_displacedName))),
0128     # Pixel tracks
0129     ("pixel_", _allToPixel(_allName)),
0130     ("pixel_Pt09", _ptCut(_allToPixel(_allName))),
0131     ("pixelFromPV_", _toPixel(_fromPVName)),
0132     ("pixelFromPV_Pt09", _ptCut(_toPixel(_fromPVName))),
0133     ("pixelFromPVAllTP_", _toPixel(_fromPVAllTPName)),
0134     ("pixelFromPVAllTP_Pt09", _ptCut(_toPixel(_fromPVAllTPName))),
0135     ("pixelbhadron_", _allToPixel(_bhadronName)),
0136     ("pixelbhadron_Pt09", _ptCut(_allToPixel(_bhadronName))),
0137 ])
0138 
0139 _trackAlgoName = {
0140     "ootb": "Out of the box",
0141     "iter0" : "Iterative Step 0",
0142     "iter1" : "Iterative Step 1",
0143     "iter2" : "Iterative Step 2",
0144     "iter3" : "Iterative Step 3",
0145     "iter4" : "Iterative Step 4",
0146     "iter5" : "Iterative Step 5",
0147     "iter6" : "Iterative Step 6",
0148     "iter7" : "Iterative Step 7",
0149     "iter9" : "Iterative Step 9",
0150     "iter10": "Iterative Step 10",
0151     "pixel": "Pixel tracks",
0152 }
0153 
0154 _trackAlgoOrder = [
0155     'ootb',
0156     'initialStepPreSplitting',
0157     'initialStep',
0158     'highPtTripletStep',
0159     'detachedQuadStep',
0160     'detachedTripletStep',
0161     'lowPtQuadStep',
0162     'lowPtTripletStep',
0163     'pixelPairStep',
0164     'mixedTripletStep',
0165     'pixelLessStep',
0166     'tobTecStep',
0167     'displacedGeneralStep',
0168     'jetCoreRegionalStep',
0169     'muonSeededStepInOut',
0170     'muonSeededStepOutIn',
0171     'displacedRegionalStep',
0172     'duplicateMerge',
0173     'convStep',
0174     'conversionStep',
0175     'ckfInOutFromConversions',
0176     'ckfOutInFromConversions',
0177     'electronGsf',
0178     'iter0',
0179     'iter1',
0180     'iter2',
0181     'iter3',
0182     'iter4',
0183     'iter5',
0184     'iter6',
0185     'iter7',
0186     'iter9',
0187     'iter10',
0188     "pixel",
0189 ]
0190 
0191 _pageNameMap = {
0192     "summary": "Summary",
0193     "vertex": "Vertex",
0194     "v0": "V0",
0195     "miniaod": "MiniAOD",
0196     "timing": "Timing",
0197     "hlt": "HLT",
0198     "pixel": "Pixel tracks",
0199     "pf": "PF",
0200 }
0201 
0202 _sectionNameMapOrder = collections.OrderedDict([
0203     # These are for the summary page
0204     ("seeding_seeds", "Seeds"),
0205     ("building", "Built tracks"),
0206     ("", _allName),
0207     ("Pt09", _allPtCut(_allName)),
0208     ("highPurity", _allToHP(_allName)),
0209     ("highPurityPt09", _ptCut(_allToHP(_allName))),
0210     ("tpPtLess09", _tpPtLess09Name),
0211     ("tpPtLess09_highPurity", _allToHP(_tpPtLess09Name)),
0212     ("tpEtaGreater2p7", _tpEtaGreater2p7Name),
0213     ("tpEtaGreater2p7_highPurity", _allToHP(_tpEtaGreater2p7Name)),
0214     ("btvLike", "BTV-like"),
0215     ("ak4PFJets", "AK4 PF jets"),
0216     ("allTPEffic", _allTPEfficName),
0217     ("allTPEffic_highPurity", _allToHP(_allTPEfficName)),
0218     ("fromPV", _fromPVName),
0219     ("fromPV_highPurity", "High purity "+_lowerFirst(_fromPVName)),
0220     ("fromPVAllTP", _fromPVAllTPName),
0221     ("fromPVAllTP_highPurity", "High purity "+_lowerFirst(_fromPVAllTPName)),
0222     ("conversion", _conversionName),
0223     ("gsf", _gsfName),
0224     ("bhadron", _bhadronName),
0225     ("bhadron_highPurity", _allToHP(_bhadronName)),
0226     ("displaced", _displacedName),
0227     ("displaced_highPurity", _allToHP(_displacedName)),
0228     # Pixel tracks
0229     ("pixel", _allToPixel(_allName)),
0230     ("pixelPt09", _ptCut(_allToPixel(_allName))),
0231     ("pixelFromPV", _toPixel(_fromPVName)),
0232     ("pixelFromPVPt09", _ptCut(_toPixel(_fromPVName))),
0233     ("pixelFromPVAllTP", _toPixel(_fromPVAllTPName)),
0234     ("pixelFromPVAllTPPt09", _ptCut(_toPixel(_fromPVAllTPName))),
0235     ("pixelbhadron", _allToPixel(_bhadronName)),
0236     ("pixelbhadronPt09", _ptCut(_allToPixel(_bhadronName))),
0237     # These are for vertices
0238     ("genvertex", "Gen vertices"),
0239     ("pixelVertices", "Pixel vertices"),
0240     ("selectedPixelVertices", "Selected pixel vertices"),
0241     ("firstStepPrimaryVerticesPreSplitting", "firstStepPrimaryVerticesPreSplitting"),
0242     ("firstStepPrimaryVertices", "firstStepPrimaryVertices"),
0243     ("offlinePrimaryVertices", "All vertices (offlinePrimaryVertices)"),
0244     ("selectedOfflinePrimaryVertices", "Selected vertices (selectedOfflinePrimaryVertices)"),
0245     ("offlinePrimaryVerticesWithBS", "All vertices with BS constraint"),
0246     ("selectedOfflinePrimaryVerticesWithBS", "Selected vertices with BS constraint"),
0247     # These are for V0
0248     ("k0", "K0"),
0249     ("lambda", "Lambda"),
0250 ])
0251 _btvLegend = "BTV-like selected tracks"
0252 _allTPEfficLegend = "All tracks, efficiency denominator contains all TrackingParticles"
0253 _fromPVLegend = "Tracks from reco PV vs. TrackingParticles from gen PV (fake rate includes pileup tracks)"
0254 _fromPVPtLegend = "Tracks (pT > 0.9 GeV) from reco PV vs. TrackingParticles from gen PV (fake rate includes pileup tracks)"
0255 _fromPVAllTPLegend = "Tracks from reco PV, fake rate numerator contains all TrackingParticles (separates fake tracks from pileup tracks)"
0256 _fromPVAllTPPtLegend = "Tracks (pT > 0.9 GeV) from reco PV, fake rate numerator contains all TrackingParticles (separates fake tracks from pileup tracks)"
0257 _fromPVAllTP2Legend = "Tracks from reco PV (another method), fake rate numerator contains all TrackingParticles (separates fake tracks from pileup tracks)"
0258 _fromPVAllTPPt2Legend = "Tracks (pT > 0.9 GeV) from reco PV (another method), fake rate numerator contains all TrackingParticles (separates fake tracks from pileup tracks)"
0259 _bhadronLegend = "All tracks, efficiency denominator contains only TrackingParticles from B-hadron decays"
0260 _bhadronPtLegend = "Tracks (pT > 0.9 GeV), efficiency denominator contains only TrackingParticles from B-hadron decays"
0261 
0262 def _sectionNameLegend():
0263     return {
0264         "btvLike": _btvLegend,
0265         "ak4PFJets": "Tracks from AK4 PF jets (jet corrected pT > 10 GeV)",
0266         "allTPEffic": _allTPEfficLegend,
0267         "allTPEffic_": _allTPEfficLegend,
0268         "allTPEffic_highPurity": _allToHP(_allTPEfficLegend),
0269         "fromPV": _fromPVLegend,
0270         "fromPV_": _fromPVLegend,
0271         "fromPV_highPurity": _toHP(_fromPVLegend),
0272         "fromPV_Pt09": _fromPVPtLegend,
0273         "fromPV_highPurity_Pt09": _toHP(_fromPVPtLegend),
0274         "fromPVAllTP": _fromPVAllTPLegend,
0275         "fromPVAllTP_": _fromPVAllTPLegend,
0276         "fromPVAllTP_highPurity": _toHP(_fromPVAllTPLegend),
0277         "fromPVAllTP_Pt09": _fromPVAllTPPtLegend,
0278         "fromPVAllTP_highPurityPt09": _toHP(_fromPVAllTPPtLegend),
0279         "fromPVAllTP2_": _fromPVAllTP2Legend,
0280         "fromPVAllTP2_highPurity": _toHP(_fromPVAllTP2Legend),
0281         "fromPVAllTP2_Pt09": _fromPVAllTPPt2Legend,
0282         "fromPVAllTP2_highPurityPt09": _toHP(_fromPVAllTPPt2Legend),
0283         "bhadron_": _bhadronLegend,
0284         "bhadron_highPurity": _allToHP(_bhadronLegend),
0285         "bhadron_btvLike": _bhadronLegend.replace("All tracks", _btvLegend),
0286         "pixelFromPV_": _fromPVLegend,
0287         "pixelFromPV_Pt09": _fromPVPtLegend,
0288         "pixelFromPVAllTP_": _fromPVAllTPLegend,
0289         "pixelFromPVAllTP_Pt09": _fromPVAllTPPtLegend,
0290         "pixelbhadron_": _bhadronLegend,
0291         "pixelbhadron_Pt09": _bhadronPtLegend,
0292     }
0293 
0294 class Table:
0295     # table [column][row]
0296     def __init__(self, columnHeaders, rowHeaders, table, purpose, page, section):
0297         if len(columnHeaders) != len(table):
0298             raise Exception("Got %d columnHeaders for table with %d columns for page %s, section %s" % (len(columnHeaders), len(table), page, section))
0299         lenRow = len(table[0])
0300         for icol, column in enumerate(table):
0301             if len(column) != lenRow:
0302                 raise Exception("Got non-square table, first column has %d rows, column %d has %d rows" % (lenRow, icol, len(column)))
0303         if len(rowHeaders) != lenRow:
0304             raise Exception("Got %d rowHeaders for table with %d rows" % (len(rowHeaders), lenRow))
0305 
0306         self._columnHeaders = columnHeaders
0307         self._rowHeaders = rowHeaders
0308         self._table = table
0309 
0310         self._purpose = purpose
0311         self._page = page
0312         self._section = section
0313 
0314     def getPurpose(self):
0315         return self._purpose
0316 
0317     def getPage(self):
0318         return self._page
0319 
0320     def getSection(self):
0321         return self._section
0322 
0323     def ncolumns(self):
0324         return len(self._table)
0325 
0326     def nrows(self):
0327         return len(self._table[0])
0328 
0329     def columnHeaders(self):
0330         return self._columnHeaders
0331 
0332     def rowHeaders(self):
0333         return self._rowHeaders
0334 
0335     def tableAsColumnRow(self):
0336         return self._table
0337 
0338     def tableAsRowColumn(self):
0339         return map(list, zip(*self._table))
0340 
0341 class PlotPurpose:
0342     class TrackingIteration: pass
0343     class TrackingSummary: pass
0344     class Vertexing: pass
0345     class MiniAOD: pass
0346     class Timing: pass
0347     class HLT: pass
0348     class Pixel: pass
0349     class PF: pass
0350 
0351 class Page(object):
0352     def __init__(self, title, sampleName):
0353         self._content = [
0354             '<html>',
0355             ' <head>',
0356             '  <title>%s</title>' % title,
0357             ' </head>',
0358             ' <body>',
0359             '  '+sampleName,
0360             '  <br/>',
0361             '  <br/>',
0362         ]
0363 
0364         self._plotSets = {}
0365         self._tables = {}
0366 
0367     def addPlotSet(self, section, plotSet):
0368         if section in self._plotSets:
0369             self._plotSets[section].extend(plotSet)
0370         else:
0371             self._plotSets[section] = plotSet
0372 
0373     def addTable(self, section, table):
0374         self._tables[section] = table
0375 
0376     def isEmpty(self):
0377         for plotSet in self._plotSets.values():
0378             if len(plotSet) > 0:
0379                 return False
0380 
0381         if len(self._tables) > 0:
0382             return False
0383 
0384         return True
0385 
0386     def write(self, fileName):
0387         self._legends = []
0388         self._sectionLegendIndex = {}
0389         self._columnHeaders = []
0390         self._columnHeadersIndex = {}
0391         self._formatPlotSets()
0392         self._formatTables()
0393         self._formatLegend()
0394 
0395         self._content.extend([
0396             ' </body>',
0397             '</html>',
0398         ])
0399 
0400         #print "Writing HTML report page", fileName
0401         f = open(fileName, "w")
0402         for line in self._content:
0403             f.write(line)
0404             f.write("\n")
0405         f.close()
0406 
0407     def _appendLegend(self, section):
0408         leg = ""
0409         legends = _sectionNameLegend()
0410         if section in legends:
0411             if section in self._sectionLegendIndex:
0412                 leg = self._sectionLegendIndex[section]
0413             else:
0414                 legnum = len(self._legends)+1
0415                 leg = "<sup>%d</sup>" % legnum
0416                 leg2 = "<sup>%d)</sup>" % legnum
0417                 self._legends.append("%s %s" % (leg2, legends[section]))
0418                 self._sectionLegendIndex[section] = leg
0419         return leg
0420 
0421     def _formatPlotSets(self):
0422         self._content.extend([
0423             '  <table>'
0424             '   <tr>',
0425         ])
0426 
0427         fileTable = []
0428 
0429         sections = self._orderSets(list(self._plotSets.keys()))
0430         for isec, section in enumerate(sections):
0431             leg = self._appendLegend(section)
0432 
0433             self._content.extend([
0434                 '   <td>%s%s</td>' % (self._mapSectionName(section), leg),
0435             ])
0436             files = [(os.path.basename(f), f) for f in self._plotSets[section]]
0437             for row in fileTable:
0438                 found = False
0439                 for i, (bsf, f) in enumerate(files):
0440                     if bsf == row[0]:
0441                         row.append(f)
0442                         found = True
0443                         del files[i]
0444                         break
0445                 if not found:
0446                     row.append(None)
0447             for bsf, f in files:
0448                 fileTable.append( [bsf] + [None]*isec + [f] )
0449 
0450         self._content.extend([
0451             '   </tr>',
0452         ])
0453 
0454         for row in fileTable:
0455             self._content.append('   <tr>')
0456             bs = row[0]
0457             for elem in row[1:]:
0458                 if elem is not None:
0459                     self._content.append('    <td><a href="%s">%s</a></td>' % (elem, bs))
0460                 else:
0461                     self._content.append('    <td></td>')
0462             self._content.append('   </tr>')
0463 
0464 
0465         self._content.extend([
0466             '  </table>',
0467         ])
0468 
0469         if len(fileTable):
0470             first_row = fileTable[0]
0471             self._content.extend([
0472               '  <a href="%s">Browse Folder</a>' % (first_row[1][0:first_row[1].rfind('/')])
0473             ])
0474 
0475     def _appendColumnHeader(self, header):
0476         leg = ""
0477         if header in self._columnHeadersIndex:
0478             leg = self._columnHeadersIndex[header]
0479         else:
0480             leg = str(chr(ord('A')+len(self._columnHeaders)))
0481             self._columnHeaders.append("%s: %s" % (leg, header))
0482             self._columnHeadersIndex[header] = leg
0483         return leg
0484 
0485     def _formatTables(self):
0486         def _allNone(row):
0487             for item in row:
0488                 if item is not None:
0489                     return False
0490             return True
0491 
0492         sections = self._orderSets(list(self._tables.keys()))
0493         for isec, section in enumerate(sections):
0494             leg = self._appendLegend(section)
0495 
0496             table = self._tables[section]
0497             self._content.extend([
0498                 '  <br/>',
0499                 '  %s%s' % (self._mapSectionName(section), leg),
0500                 '  <table border="1">'
0501             ])
0502 
0503             # table is stored in column-row, need to transpose
0504             data = table.tableAsRowColumn()
0505 
0506             self._content.extend([
0507                 '   <tr>'
0508                 '   <td></td>'
0509             ])
0510             heads = table.columnHeaders()
0511             if max(map(lambda h: len(h), heads)) > 20:
0512                 heads = [self._appendColumnHeader(h) for h in heads]
0513             for head in heads:
0514                 self._content.append('    <td>%s</td>' % head)
0515             self._content.append('   </tr>')
0516 
0517             for irow, row in enumerate(data):
0518                 # Skip row if all values are non-existent
0519                 if _allNone(row):
0520                     continue
0521 
0522                 self._content.extend([
0523                     '   <tr>'
0524                     '    <td>%s</td>' % table.rowHeaders()[irow]
0525                 ])
0526                 # align the number columns to right
0527                 for icol, item in enumerate(row):
0528                     formatted = str(item) if item is not None else ""
0529                     self._content.append('    <td align="right">%s</td>' % formatted)
0530                 self._content.append('   </tr>')
0531 
0532             self._content.append('  </table>')
0533 
0534             for shortenedColumnHeader in self._columnHeaders:
0535                 self._content.append('  %s<br/>' % shortenedColumnHeader)
0536             self._columnHeaders = []
0537             self._columnHeadersIndex = {}
0538 
0539     def _formatLegend(self):
0540         if len(self._legends) > 0:
0541             self._content.extend([
0542                 '  <br/>'
0543                 '  Details:</br>',
0544             ])
0545             for leg in self._legends:
0546                 self._content.append('  %s<br/>' % leg)
0547 
0548 
0549     def _mapSectionName(self, section):
0550         return _sectionNameMapOrder.get(section, section)
0551 
0552     def _orderSets(self, keys):
0553         keys_sorted = sorted(keys)
0554         ret = []
0555         for section in _sectionNameMapOrder.keys():
0556             if section in keys_sorted:
0557                 ret.append(section)
0558                 keys_sorted.remove(section)
0559         ret.extend(keys_sorted)
0560         return ret
0561 
0562 class PageSet(object):
0563     def __init__(self, title, sampleName, sample, fastVsFull, pileupComparison, dqmSubFolderTranslatedToSectionName=None):
0564         self._title = title
0565         self._sampleName = sampleName
0566         self._pages = collections.OrderedDict()
0567         self._dqmSubFolderTranslatedToSectionName = dqmSubFolderTranslatedToSectionName
0568 
0569         self._prefix = ""
0570         if sample.fastsim():
0571             self._prefix += "fast_"
0572             if fastVsFull:
0573                 self._prefix += "full_"
0574 
0575         self._prefix += _sampleFileName.get(sample.label(), sample.label())+"_"
0576         if hasattr(sample, "hasScenario") and sample.hasScenario():
0577             self._prefix += sample.scenario()+"_"
0578 
0579         if hasattr(sample, "hasPileup"):
0580             if sample.hasPileup():
0581                 self._prefix += "pu"+str(sample.pileupNumber())+"_"+sample.pileupType()+"_"
0582             else:
0583                 self._prefix += "nopu_"
0584             if pileupComparison:
0585                 self._prefix += "vspu_"
0586 
0587 
0588     def _getPage(self, key, pageClass):
0589         if key not in self._pages:
0590             page = pageClass(self._title, self._sampleName)
0591             self._pages[key] = page
0592         else:
0593             page = self._pages[key]
0594         return page
0595 
0596     def addPlotSet(self, plotterFolder, dqmSubFolder, plotFiles):
0597         pageKey = plotterFolder.getPage()
0598         if pageKey is None:
0599             if dqmSubFolder is not None:
0600                 pageKey = dqmSubFolder.translated
0601             else:
0602                 pageKey = plotterFolder.getName()
0603 
0604         page = self._getPage(pageKey, Page)
0605         sectionName = plotterFolder.getSection()
0606         if sectionName is None:
0607             if plotterFolder.getPage() is not None and dqmSubFolder is not None:
0608                 if self._dqmSubFolderTranslatedToSectionName is not None:
0609                     sectionName = self._dqmSubFolderTranslatedToSectionName(dqmSubFolder.translated)
0610                 else:
0611                     sectionName = dqmSubFolder.translated
0612             else:
0613                 sectionName = ""
0614 
0615         page.addPlotSet(sectionName, plotFiles)
0616 
0617     def addTable(self, table):
0618         if table is None:
0619             return
0620 
0621         page = self._getPage(table.getPage(), Page)
0622         page.addTable(table.getSection(), table)
0623 
0624     def write(self, baseDir):
0625         #print "TrackingPageSet.write"
0626         ret = []
0627 
0628         keys = self._orderPages(list(self._pages.keys()))
0629         for key in keys:
0630             page = self._pages[key]
0631             if page.isEmpty():
0632                 continue
0633 
0634             fileName = "%s%s.html" % (self._prefix, key)
0635             page.write(os.path.join(baseDir, fileName))
0636             ret.append( (self._mapPagesName(key), fileName) )
0637         return ret
0638 
0639     def _mapPagesName(self, name):
0640         return _pageNameMap.get(name, name)
0641 
0642     def _orderPages(self, keys):
0643         return keys
0644 
0645 
0646 
0647 class TrackingIterPage(Page):
0648     def __init__(self, *args, **kwargs):
0649         super(TrackingIterPage, self).__init__(*args, **kwargs)
0650 
0651     def _mapSectionName(self, quality):
0652         return _trackQualityNameOrder.get(quality, quality)
0653 
0654     def _orderSets(self, qualities):
0655         ret = []
0656         for qual in _trackQualityNameOrder.keys():
0657             if qual in qualities:
0658                 ret.append(qual)
0659                 qualities.remove(qual)
0660         ret.extend(qualities)
0661         return ret
0662 
0663 class TrackingPageSet(PageSet):
0664     def __init__(self, *args, **kwargs):
0665         super(TrackingPageSet, self).__init__(*args, **kwargs)
0666 
0667     def addPlotSet(self, plotterFolder, dqmSubFolder, plotFiles):
0668         (algo, quality) = dqmSubFolder.translated
0669 
0670         pageName = algo
0671         sectionName = quality
0672 
0673         # put all non-iterative stuff under OOTB
0674         #
0675         # it is bit of a hack to access trackingPlots.TrackingPlotFolder this way,
0676         # but it was simple and it works
0677         if algo != "ootb" and not plotterFolder._plotFolder.isAlgoIterative(algo):
0678             pageName = "ootb"
0679             sectionName = algo
0680 
0681         folderName = plotterFolder.getName()
0682         if folderName != "":
0683             sectionName = folderName+"_"+sectionName
0684 
0685         page = self._getPage(pageName, TrackingIterPage)
0686         page.addPlotSet(sectionName, plotFiles)
0687 
0688     def _mapPagesName(self, algo): # algo = pageName
0689         return _trackAlgoName.get(algo, algo)
0690 
0691     def _orderPages(self, algos):
0692         ret = []
0693         for algo in _trackAlgoOrder:
0694             if algo in algos:
0695                 ret.append(algo)
0696                 algos.remove(algo)
0697         ret.extend(algos)
0698         return ret
0699 
0700 
0701 
0702 class IndexSection:
0703     def __init__(self, sample, title, fastVsFull, pileupComparison):
0704         self._sample = sample
0705 
0706         self._sampleName = ""
0707         if sample.fastsim():
0708             self._sampleName += "FastSim "
0709             if fastVsFull:
0710                 self._sampleName += "vs FullSim "
0711 
0712         pileup = ""
0713         if hasattr(sample, "hasPileup"):
0714             pileup = "with no pileup"
0715             if sample.hasPileup():
0716                 pileup = "with %d pileup (%s)" % (sample.pileupNumber(), sample.pileupType())
0717             if pileupComparison is not None:
0718                 pileup += " "+pileupComparison
0719         if hasattr(sample, "customPileupLabel"):
0720             pileup = sample.customPileupLabel()
0721 
0722         scenario = ""
0723         if hasattr(sample, "hasScenario") and sample.hasScenario():
0724             scenario = " (\"%s\")" % sample.scenario()
0725         self._sampleName += "%s sample%s %s" % (_sampleName.get(sample.name(), sample.name()), scenario, pileup)
0726 
0727         params = [title, self._sampleName, sample, fastVsFull, pileupComparison is not None]
0728         self._summaryPage = PageSet(*params)
0729         self._iterationPages = TrackingPageSet(*params)
0730         self._vertexPage = PageSet(*params)
0731         self._miniaodPage = PageSet(*params)
0732         self._timingPage = PageSet(*params)
0733         self._pfPages = PageSet(*params)
0734         self._hltPages = PageSet(*params, dqmSubFolderTranslatedToSectionName=lambda algoQuality: algoQuality[0])
0735         self._pixelPages = TrackingPageSet(*params)
0736         self._otherPages = PageSet(*params)
0737 
0738         self._purposePageMap = {
0739             PlotPurpose.TrackingIteration: self._iterationPages,
0740             PlotPurpose.TrackingSummary: self._summaryPage,
0741             PlotPurpose.Vertexing: self._vertexPage,
0742             PlotPurpose.MiniAOD: self._miniaodPage,
0743             PlotPurpose.Timing: self._timingPage,
0744             PlotPurpose.PF: self._pfPages,
0745             PlotPurpose.HLT: self._hltPages,
0746             PlotPurpose.Pixel: self._pixelPages,
0747         }
0748 
0749     def addPlots(self, plotterFolder, dqmSubFolder, plotFiles):
0750         page = self._purposePageMap.get(plotterFolder.getPurpose(), self._otherPages)
0751         page.addPlotSet(plotterFolder, dqmSubFolder, plotFiles)
0752 
0753     def addTable(self, table):
0754         if table is None:
0755             return
0756 
0757         page = self._purposePageMap.get(table.getPurpose(), self._otherPages)
0758         page.addTable(table)
0759         params = []
0760 
0761     def write(self, baseDir):
0762         ret = [
0763             "  "+self._sampleName,
0764             "  <br/>",
0765             "  <ul>",
0766             ]
0767 
0768         for pages in [self._summaryPage, self._iterationPages, self._pixelPages, self._vertexPage, self._miniaodPage, self._timingPage, self._hltPages, self._pfPages, self._otherPages]:
0769             labelFiles = pages.write(baseDir)
0770             for label, fname in labelFiles:
0771                 ret.append('   <li><a href="%s">%s</a></li>' % (fname, label))
0772 
0773         ret.extend([
0774             '  </ul>',
0775             '  <br/>',
0776         ])
0777 
0778         return ret
0779 
0780 class HtmlReport:
0781     def __init__(self, validationName, newBaseDir):
0782         self._title = "Tracking validation "+validationName
0783         self._newBaseDir = newBaseDir
0784 
0785         self._index = [
0786             '<html>',
0787             ' <head>',
0788             '  <title>%s</title>' % self._title,
0789             ' </head>',
0790             ' <body>',
0791         ]
0792 
0793         self._sections = collections.OrderedDict()
0794 
0795     def addNote(self, note):
0796         self._index.append('  <p>%s</p>'%note)
0797 
0798     def beginSample(self, sample, fastVsFull=False, pileupComparison=None):
0799         # Fast vs. Full becomes just after the corresponding Fast
0800         # Same for PU
0801         rightAfterRefSample = fastVsFull or (pileupComparison is not None)
0802 
0803         key = (sample.digest(), rightAfterRefSample)
0804         if key in self._sections:
0805             self._currentSection = self._sections[key]
0806         else:
0807             self._currentSection = IndexSection(sample, self._title, fastVsFull, pileupComparison)
0808             self._sections[key] = self._currentSection
0809 
0810     def addPlots(self, *args, **kwargs):
0811         self._currentSection.addPlots(*args, **kwargs)
0812 
0813     def addTable(self, *args, **kwargs):
0814         self._currentSection.addTable(*args, **kwargs)
0815 
0816     def write(self):
0817         # Reorder sections such that Fast vs. Full becomes just after the corresponding Fast
0818         keys = self._sections.keys()
0819         newkeys = []
0820         for key in keys:
0821             if not key[1]:
0822                 newkeys.append(key)
0823                 continue
0824             # is fast vs full
0825             ind_fast = newkeys.index( (key[0], False) )
0826             newkeys.insert(ind_fast+1, key)
0827 
0828         for key in newkeys:
0829             section = self._sections[key]
0830             self._index.extend(section.write(self._newBaseDir))
0831 
0832         self._index.extend([
0833             " </body>",
0834             "</html>",
0835         ])
0836 
0837         f = open(os.path.join(self._newBaseDir, "index.html"), "w")
0838         for line in self._index:
0839             f.write(line)
0840             f.write("\n")
0841         f.close()
0842 
0843 class HtmlReportDummy:
0844     def __init__(self):
0845         pass
0846 
0847     def beginSample(self, *args, **kwargs):
0848         pass
0849 
0850     def addPlots(self, *args, **kwargs):
0851         pass
0852 
0853     def addTable(self, *args, **kwargs):
0854         pass