Back to home page

Project CMSSW displayed by LXR

 
 

    


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

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     'duplicateMerge',
0172     'convStep',
0173     'conversionStep',
0174     'ckfInOutFromConversions',
0175     'ckfOutInFromConversions',
0176     'electronGsf',
0177     'iter0',
0178     'iter1',
0179     'iter2',
0180     'iter3',
0181     'iter4',
0182     'iter5',
0183     'iter6',
0184     'iter7',
0185     'iter9',
0186     'iter10',
0187     "pixel",
0188 ]
0189 
0190 _pageNameMap = {
0191     "summary": "Summary",
0192     "vertex": "Vertex",
0193     "v0": "V0",
0194     "miniaod": "MiniAOD",
0195     "timing": "Timing",
0196     "hlt": "HLT",
0197     "pixel": "Pixel tracks",
0198     "pf": "PF",
0199 }
0200 
0201 _sectionNameMapOrder = collections.OrderedDict([
0202     # These are for the summary page
0203     ("seeding_seeds", "Seeds"),
0204     ("building", "Built tracks"),
0205     ("", _allName),
0206     ("Pt09", _allPtCut(_allName)),
0207     ("highPurity", _allToHP(_allName)),
0208     ("highPurityPt09", _ptCut(_allToHP(_allName))),
0209     ("tpPtLess09", _tpPtLess09Name),
0210     ("tpPtLess09_highPurity", _allToHP(_tpPtLess09Name)),
0211     ("tpEtaGreater2p7", _tpEtaGreater2p7Name),
0212     ("tpEtaGreater2p7_highPurity", _allToHP(_tpEtaGreater2p7Name)),
0213     ("btvLike", "BTV-like"),
0214     ("ak4PFJets", "AK4 PF jets"),
0215     ("allTPEffic", _allTPEfficName),
0216     ("allTPEffic_highPurity", _allToHP(_allTPEfficName)),
0217     ("fromPV", _fromPVName),
0218     ("fromPV_highPurity", "High purity "+_lowerFirst(_fromPVName)),
0219     ("fromPVAllTP", _fromPVAllTPName),
0220     ("fromPVAllTP_highPurity", "High purity "+_lowerFirst(_fromPVAllTPName)),
0221     ("conversion", _conversionName),
0222     ("gsf", _gsfName),
0223     ("bhadron", _bhadronName),
0224     ("bhadron_highPurity", _allToHP(_bhadronName)),
0225     ("displaced", _displacedName),
0226     ("displaced_highPurity", _allToHP(_displacedName)),
0227     # Pixel tracks
0228     ("pixel", _allToPixel(_allName)),
0229     ("pixelPt09", _ptCut(_allToPixel(_allName))),
0230     ("pixelFromPV", _toPixel(_fromPVName)),
0231     ("pixelFromPVPt09", _ptCut(_toPixel(_fromPVName))),
0232     ("pixelFromPVAllTP", _toPixel(_fromPVAllTPName)),
0233     ("pixelFromPVAllTPPt09", _ptCut(_toPixel(_fromPVAllTPName))),
0234     ("pixelbhadron", _allToPixel(_bhadronName)),
0235     ("pixelbhadronPt09", _ptCut(_allToPixel(_bhadronName))),
0236     # These are for vertices
0237     ("genvertex", "Gen vertices"),
0238     ("pixelVertices", "Pixel vertices"),
0239     ("selectedPixelVertices", "Selected pixel vertices"),
0240     ("firstStepPrimaryVerticesPreSplitting", "firstStepPrimaryVerticesPreSplitting"),
0241     ("firstStepPrimaryVertices", "firstStepPrimaryVertices"),
0242     ("offlinePrimaryVertices", "All vertices (offlinePrimaryVertices)"),
0243     ("selectedOfflinePrimaryVertices", "Selected vertices (selectedOfflinePrimaryVertices)"),
0244     ("offlinePrimaryVerticesWithBS", "All vertices with BS constraint"),
0245     ("selectedOfflinePrimaryVerticesWithBS", "Selected vertices with BS constraint"),
0246     # These are for V0
0247     ("k0", "K0"),
0248     ("lambda", "Lambda"),
0249 ])
0250 _btvLegend = "BTV-like selected tracks"
0251 _allTPEfficLegend = "All tracks, efficiency denominator contains all TrackingParticles"
0252 _fromPVLegend = "Tracks from reco PV vs. TrackingParticles from gen PV (fake rate includes pileup tracks)"
0253 _fromPVPtLegend = "Tracks (pT > 0.9 GeV) from reco PV vs. TrackingParticles from gen PV (fake rate includes pileup tracks)"
0254 _fromPVAllTPLegend = "Tracks from reco PV, fake rate numerator contains all TrackingParticles (separates fake tracks from pileup tracks)"
0255 _fromPVAllTPPtLegend = "Tracks (pT > 0.9 GeV) from reco PV, fake rate numerator contains all TrackingParticles (separates fake tracks from pileup tracks)"
0256 _fromPVAllTP2Legend = "Tracks from reco PV (another method), fake rate numerator contains all TrackingParticles (separates fake tracks from pileup tracks)"
0257 _fromPVAllTPPt2Legend = "Tracks (pT > 0.9 GeV) from reco PV (another method), fake rate numerator contains all TrackingParticles (separates fake tracks from pileup tracks)"
0258 _bhadronLegend = "All tracks, efficiency denominator contains only TrackingParticles from B-hadron decays"
0259 _bhadronPtLegend = "Tracks (pT > 0.9 GeV), efficiency denominator contains only TrackingParticles from B-hadron decays"
0260 
0261 def _sectionNameLegend():
0262     return {
0263         "btvLike": _btvLegend,
0264         "ak4PFJets": "Tracks from AK4 PF jets (jet corrected pT > 10 GeV)",
0265         "allTPEffic": _allTPEfficLegend,
0266         "allTPEffic_": _allTPEfficLegend,
0267         "allTPEffic_highPurity": _allToHP(_allTPEfficLegend),
0268         "fromPV": _fromPVLegend,
0269         "fromPV_": _fromPVLegend,
0270         "fromPV_highPurity": _toHP(_fromPVLegend),
0271         "fromPV_Pt09": _fromPVPtLegend,
0272         "fromPV_highPurity_Pt09": _toHP(_fromPVPtLegend),
0273         "fromPVAllTP": _fromPVAllTPLegend,
0274         "fromPVAllTP_": _fromPVAllTPLegend,
0275         "fromPVAllTP_highPurity": _toHP(_fromPVAllTPLegend),
0276         "fromPVAllTP_Pt09": _fromPVAllTPPtLegend,
0277         "fromPVAllTP_highPurityPt09": _toHP(_fromPVAllTPPtLegend),
0278         "fromPVAllTP2_": _fromPVAllTP2Legend,
0279         "fromPVAllTP2_highPurity": _toHP(_fromPVAllTP2Legend),
0280         "fromPVAllTP2_Pt09": _fromPVAllTPPt2Legend,
0281         "fromPVAllTP2_highPurityPt09": _toHP(_fromPVAllTPPt2Legend),
0282         "bhadron_": _bhadronLegend,
0283         "bhadron_highPurity": _allToHP(_bhadronLegend),
0284         "bhadron_btvLike": _bhadronLegend.replace("All tracks", _btvLegend),
0285         "pixelFromPV_": _fromPVLegend,
0286         "pixelFromPV_Pt09": _fromPVPtLegend,
0287         "pixelFromPVAllTP_": _fromPVAllTPLegend,
0288         "pixelFromPVAllTP_Pt09": _fromPVAllTPPtLegend,
0289         "pixelbhadron_": _bhadronLegend,
0290         "pixelbhadron_Pt09": _bhadronPtLegend,
0291     }
0292 
0293 class Table:
0294     # table [column][row]
0295     def __init__(self, columnHeaders, rowHeaders, table, purpose, page, section):
0296         if len(columnHeaders) != len(table):
0297             raise Exception("Got %d columnHeaders for table with %d columns for page %s, section %s" % (len(columnHeaders), len(table), page, section))
0298         lenRow = len(table[0])
0299         for icol, column in enumerate(table):
0300             if len(column) != lenRow:
0301                 raise Exception("Got non-square table, first column has %d rows, column %d has %d rows" % (lenRow, icol, len(column)))
0302         if len(rowHeaders) != lenRow:
0303             raise Exception("Got %d rowHeaders for table with %d rows" % (len(rowHeaders), lenRow))
0304 
0305         self._columnHeaders = columnHeaders
0306         self._rowHeaders = rowHeaders
0307         self._table = table
0308 
0309         self._purpose = purpose
0310         self._page = page
0311         self._section = section
0312 
0313     def getPurpose(self):
0314         return self._purpose
0315 
0316     def getPage(self):
0317         return self._page
0318 
0319     def getSection(self):
0320         return self._section
0321 
0322     def ncolumns(self):
0323         return len(self._table)
0324 
0325     def nrows(self):
0326         return len(self._table[0])
0327 
0328     def columnHeaders(self):
0329         return self._columnHeaders
0330 
0331     def rowHeaders(self):
0332         return self._rowHeaders
0333 
0334     def tableAsColumnRow(self):
0335         return self._table
0336 
0337     def tableAsRowColumn(self):
0338         return map(list, zip(*self._table))
0339 
0340 class PlotPurpose:
0341     class TrackingIteration: pass
0342     class TrackingSummary: pass
0343     class Vertexing: pass
0344     class MiniAOD: pass
0345     class Timing: pass
0346     class HLT: pass
0347     class Pixel: pass
0348     class PF: pass
0349 
0350 class Page(object):
0351     def __init__(self, title, sampleName):
0352         self._content = [
0353             '<html>',
0354             ' <head>',
0355             '  <title>%s</title>' % title,
0356             ' </head>',
0357             ' <body>',
0358             '  '+sampleName,
0359             '  <br/>',
0360             '  <br/>',
0361         ]
0362 
0363         self._plotSets = {}
0364         self._tables = {}
0365 
0366     def addPlotSet(self, section, plotSet):
0367         if section in self._plotSets:
0368             self._plotSets[section].extend(plotSet)
0369         else:
0370             self._plotSets[section] = plotSet
0371 
0372     def addTable(self, section, table):
0373         self._tables[section] = table
0374 
0375     def isEmpty(self):
0376         for plotSet in self._plotSets.values():
0377             if len(plotSet) > 0:
0378                 return False
0379 
0380         if len(self._tables) > 0:
0381             return False
0382 
0383         return True
0384 
0385     def write(self, fileName):
0386         self._legends = []
0387         self._sectionLegendIndex = {}
0388         self._columnHeaders = []
0389         self._columnHeadersIndex = {}
0390         self._formatPlotSets()
0391         self._formatTables()
0392         self._formatLegend()
0393 
0394         self._content.extend([
0395             ' </body>',
0396             '</html>',
0397         ])
0398 
0399         #print "Writing HTML report page", fileName
0400         f = open(fileName, "w")
0401         for line in self._content:
0402             f.write(line)
0403             f.write("\n")
0404         f.close()
0405 
0406     def _appendLegend(self, section):
0407         leg = ""
0408         legends = _sectionNameLegend()
0409         if section in legends:
0410             if section in self._sectionLegendIndex:
0411                 leg = self._sectionLegendIndex[section]
0412             else:
0413                 legnum = len(self._legends)+1
0414                 leg = "<sup>%d</sup>" % legnum
0415                 leg2 = "<sup>%d)</sup>" % legnum
0416                 self._legends.append("%s %s" % (leg2, legends[section]))
0417                 self._sectionLegendIndex[section] = leg
0418         return leg
0419 
0420     def _formatPlotSets(self):
0421         self._content.extend([
0422             '  <table>'
0423             '   <tr>',
0424         ])
0425 
0426         fileTable = []
0427 
0428         sections = self._orderSets(list(self._plotSets.keys()))
0429         for isec, section in enumerate(sections):
0430             leg = self._appendLegend(section)
0431 
0432             self._content.extend([
0433                 '   <td>%s%s</td>' % (self._mapSectionName(section), leg),
0434             ])
0435             files = [(os.path.basename(f), f) for f in self._plotSets[section]]
0436             for row in fileTable:
0437                 found = False
0438                 for i, (bsf, f) in enumerate(files):
0439                     if bsf == row[0]:
0440                         row.append(f)
0441                         found = True
0442                         del files[i]
0443                         break
0444                 if not found:
0445                     row.append(None)
0446             for bsf, f in files:
0447                 fileTable.append( [bsf] + [None]*isec + [f] )
0448 
0449         self._content.extend([
0450             '   </tr>',
0451         ])
0452 
0453         for row in fileTable:
0454             self._content.append('   <tr>')
0455             bs = row[0]
0456             for elem in row[1:]:
0457                 if elem is not None:
0458                     self._content.append('    <td><a href="%s">%s</a></td>' % (elem, bs))
0459                 else:
0460                     self._content.append('    <td></td>')
0461             self._content.append('   </tr>')
0462 
0463 
0464         self._content.extend([
0465             '  </table>',
0466         ])
0467 
0468         if len(fileTable):
0469             first_row = fileTable[0]
0470             self._content.extend([
0471               '  <a href="%s">Browse Folder</a>' % (first_row[1][0:first_row[1].rfind('/')])
0472             ])
0473 
0474     def _appendColumnHeader(self, header):
0475         leg = ""
0476         if header in self._columnHeadersIndex:
0477             leg = self._columnHeadersIndex[header]
0478         else:
0479             leg = str(chr(ord('A')+len(self._columnHeaders)))
0480             self._columnHeaders.append("%s: %s" % (leg, header))
0481             self._columnHeadersIndex[header] = leg
0482         return leg
0483 
0484     def _formatTables(self):
0485         def _allNone(row):
0486             for item in row:
0487                 if item is not None:
0488                     return False
0489             return True
0490 
0491         sections = self._orderSets(list(self._tables.keys()))
0492         for isec, section in enumerate(sections):
0493             leg = self._appendLegend(section)
0494 
0495             table = self._tables[section]
0496             self._content.extend([
0497                 '  <br/>',
0498                 '  %s%s' % (self._mapSectionName(section), leg),
0499                 '  <table border="1">'
0500             ])
0501 
0502             # table is stored in column-row, need to transpose
0503             data = table.tableAsRowColumn()
0504 
0505             self._content.extend([
0506                 '   <tr>'
0507                 '   <td></td>'
0508             ])
0509             heads = table.columnHeaders()
0510             if max(map(lambda h: len(h), heads)) > 20:
0511                 heads = [self._appendColumnHeader(h) for h in heads]
0512             for head in heads:
0513                 self._content.append('    <td>%s</td>' % head)
0514             self._content.append('   </tr>')
0515 
0516             for irow, row in enumerate(data):
0517                 # Skip row if all values are non-existent
0518                 if _allNone(row):
0519                     continue
0520 
0521                 self._content.extend([
0522                     '   <tr>'
0523                     '    <td>%s</td>' % table.rowHeaders()[irow]
0524                 ])
0525                 # align the number columns to right
0526                 for icol, item in enumerate(row):
0527                     formatted = str(item) if item is not None else ""
0528                     self._content.append('    <td align="right">%s</td>' % formatted)
0529                 self._content.append('   </tr>')
0530 
0531             self._content.append('  </table>')
0532 
0533             for shortenedColumnHeader in self._columnHeaders:
0534                 self._content.append('  %s<br/>' % shortenedColumnHeader)
0535             self._columnHeaders = []
0536             self._columnHeadersIndex = {}
0537 
0538     def _formatLegend(self):
0539         if len(self._legends) > 0:
0540             self._content.extend([
0541                 '  <br/>'
0542                 '  Details:</br>',
0543             ])
0544             for leg in self._legends:
0545                 self._content.append('  %s<br/>' % leg)
0546 
0547 
0548     def _mapSectionName(self, section):
0549         return _sectionNameMapOrder.get(section, section)
0550 
0551     def _orderSets(self, keys):
0552         keys_sorted = sorted(keys)
0553         ret = []
0554         for section in _sectionNameMapOrder.keys():
0555             if section in keys_sorted:
0556                 ret.append(section)
0557                 keys_sorted.remove(section)
0558         ret.extend(keys_sorted)
0559         return ret
0560 
0561 class PageSet(object):
0562     def __init__(self, title, sampleName, sample, fastVsFull, pileupComparison, dqmSubFolderTranslatedToSectionName=None):
0563         self._title = title
0564         self._sampleName = sampleName
0565         self._pages = collections.OrderedDict()
0566         self._dqmSubFolderTranslatedToSectionName = dqmSubFolderTranslatedToSectionName
0567 
0568         self._prefix = ""
0569         if sample.fastsim():
0570             self._prefix += "fast_"
0571             if fastVsFull:
0572                 self._prefix += "full_"
0573 
0574         self._prefix += _sampleFileName.get(sample.label(), sample.label())+"_"
0575         if hasattr(sample, "hasScenario") and sample.hasScenario():
0576             self._prefix += sample.scenario()+"_"
0577 
0578         if hasattr(sample, "hasPileup"):
0579             if sample.hasPileup():
0580                 self._prefix += "pu"+str(sample.pileupNumber())+"_"+sample.pileupType()+"_"
0581             else:
0582                 self._prefix += "nopu_"
0583             if pileupComparison:
0584                 self._prefix += "vspu_"
0585 
0586 
0587     def _getPage(self, key, pageClass):
0588         if key not in self._pages:
0589             page = pageClass(self._title, self._sampleName)
0590             self._pages[key] = page
0591         else:
0592             page = self._pages[key]
0593         return page
0594 
0595     def addPlotSet(self, plotterFolder, dqmSubFolder, plotFiles):
0596         pageKey = plotterFolder.getPage()
0597         if pageKey is None:
0598             if dqmSubFolder is not None:
0599                 pageKey = dqmSubFolder.translated
0600             else:
0601                 pageKey = plotterFolder.getName()
0602 
0603         page = self._getPage(pageKey, Page)
0604         sectionName = plotterFolder.getSection()
0605         if sectionName is None:
0606             if plotterFolder.getPage() is not None and dqmSubFolder is not None:
0607                 if self._dqmSubFolderTranslatedToSectionName is not None:
0608                     sectionName = self._dqmSubFolderTranslatedToSectionName(dqmSubFolder.translated)
0609                 else:
0610                     sectionName = dqmSubFolder.translated
0611             else:
0612                 sectionName = ""
0613 
0614         page.addPlotSet(sectionName, plotFiles)
0615 
0616     def addTable(self, table):
0617         if table is None:
0618             return
0619 
0620         page = self._getPage(table.getPage(), Page)
0621         page.addTable(table.getSection(), table)
0622 
0623     def write(self, baseDir):
0624         #print "TrackingPageSet.write"
0625         ret = []
0626 
0627         keys = self._orderPages(list(self._pages.keys()))
0628         for key in keys:
0629             page = self._pages[key]
0630             if page.isEmpty():
0631                 continue
0632 
0633             fileName = "%s%s.html" % (self._prefix, key)
0634             page.write(os.path.join(baseDir, fileName))
0635             ret.append( (self._mapPagesName(key), fileName) )
0636         return ret
0637 
0638     def _mapPagesName(self, name):
0639         return _pageNameMap.get(name, name)
0640 
0641     def _orderPages(self, keys):
0642         return keys
0643 
0644 
0645 
0646 class TrackingIterPage(Page):
0647     def __init__(self, *args, **kwargs):
0648         super(TrackingIterPage, self).__init__(*args, **kwargs)
0649 
0650     def _mapSectionName(self, quality):
0651         return _trackQualityNameOrder.get(quality, quality)
0652 
0653     def _orderSets(self, qualities):
0654         ret = []
0655         for qual in _trackQualityNameOrder.keys():
0656             if qual in qualities:
0657                 ret.append(qual)
0658                 qualities.remove(qual)
0659         ret.extend(qualities)
0660         return ret
0661 
0662 class TrackingPageSet(PageSet):
0663     def __init__(self, *args, **kwargs):
0664         super(TrackingPageSet, self).__init__(*args, **kwargs)
0665 
0666     def addPlotSet(self, plotterFolder, dqmSubFolder, plotFiles):
0667         (algo, quality) = dqmSubFolder.translated
0668 
0669         pageName = algo
0670         sectionName = quality
0671 
0672         # put all non-iterative stuff under OOTB
0673         #
0674         # it is bit of a hack to access trackingPlots.TrackingPlotFolder this way,
0675         # but it was simple and it works
0676         if algo != "ootb" and not plotterFolder._plotFolder.isAlgoIterative(algo):
0677             pageName = "ootb"
0678             sectionName = algo
0679 
0680         folderName = plotterFolder.getName()
0681         if folderName != "":
0682             sectionName = folderName+"_"+sectionName
0683 
0684         page = self._getPage(pageName, TrackingIterPage)
0685         page.addPlotSet(sectionName, plotFiles)
0686 
0687     def _mapPagesName(self, algo): # algo = pageName
0688         return _trackAlgoName.get(algo, algo)
0689 
0690     def _orderPages(self, algos):
0691         ret = []
0692         for algo in _trackAlgoOrder:
0693             if algo in algos:
0694                 ret.append(algo)
0695                 algos.remove(algo)
0696         ret.extend(algos)
0697         return ret
0698 
0699 
0700 
0701 class IndexSection:
0702     def __init__(self, sample, title, fastVsFull, pileupComparison):
0703         self._sample = sample
0704 
0705         self._sampleName = ""
0706         if sample.fastsim():
0707             self._sampleName += "FastSim "
0708             if fastVsFull:
0709                 self._sampleName += "vs FullSim "
0710 
0711         pileup = ""
0712         if hasattr(sample, "hasPileup"):
0713             pileup = "with no pileup"
0714             if sample.hasPileup():
0715                 pileup = "with %d pileup (%s)" % (sample.pileupNumber(), sample.pileupType())
0716             if pileupComparison is not None:
0717                 pileup += " "+pileupComparison
0718         if hasattr(sample, "customPileupLabel"):
0719             pileup = sample.customPileupLabel()
0720 
0721         scenario = ""
0722         if hasattr(sample, "hasScenario") and sample.hasScenario():
0723             scenario = " (\"%s\")" % sample.scenario()
0724         self._sampleName += "%s sample%s %s" % (_sampleName.get(sample.name(), sample.name()), scenario, pileup)
0725 
0726         params = [title, self._sampleName, sample, fastVsFull, pileupComparison is not None]
0727         self._summaryPage = PageSet(*params)
0728         self._iterationPages = TrackingPageSet(*params)
0729         self._vertexPage = PageSet(*params)
0730         self._miniaodPage = PageSet(*params)
0731         self._timingPage = PageSet(*params)
0732         self._pfPages = PageSet(*params)
0733         self._hltPages = PageSet(*params, dqmSubFolderTranslatedToSectionName=lambda algoQuality: algoQuality[0])
0734         self._pixelPages = TrackingPageSet(*params)
0735         self._otherPages = PageSet(*params)
0736 
0737         self._purposePageMap = {
0738             PlotPurpose.TrackingIteration: self._iterationPages,
0739             PlotPurpose.TrackingSummary: self._summaryPage,
0740             PlotPurpose.Vertexing: self._vertexPage,
0741             PlotPurpose.MiniAOD: self._miniaodPage,
0742             PlotPurpose.Timing: self._timingPage,
0743             PlotPurpose.PF: self._pfPages,
0744             PlotPurpose.HLT: self._hltPages,
0745             PlotPurpose.Pixel: self._pixelPages,
0746         }
0747 
0748     def addPlots(self, plotterFolder, dqmSubFolder, plotFiles):
0749         page = self._purposePageMap.get(plotterFolder.getPurpose(), self._otherPages)
0750         page.addPlotSet(plotterFolder, dqmSubFolder, plotFiles)
0751 
0752     def addTable(self, table):
0753         if table is None:
0754             return
0755 
0756         page = self._purposePageMap.get(table.getPurpose(), self._otherPages)
0757         page.addTable(table)
0758         params = []
0759 
0760     def write(self, baseDir):
0761         ret = [
0762             "  "+self._sampleName,
0763             "  <br/>",
0764             "  <ul>",
0765             ]
0766 
0767         for pages in [self._summaryPage, self._iterationPages, self._pixelPages, self._vertexPage, self._miniaodPage, self._timingPage, self._hltPages, self._pfPages, self._otherPages]:
0768             labelFiles = pages.write(baseDir)
0769             for label, fname in labelFiles:
0770                 ret.append('   <li><a href="%s">%s</a></li>' % (fname, label))
0771 
0772         ret.extend([
0773             '  </ul>',
0774             '  <br/>',
0775         ])
0776 
0777         return ret
0778 
0779 class HtmlReport:
0780     def __init__(self, validationName, newBaseDir):
0781         self._title = "Tracking validation "+validationName
0782         self._newBaseDir = newBaseDir
0783 
0784         self._index = [
0785             '<html>',
0786             ' <head>',
0787             '  <title>%s</title>' % self._title,
0788             ' </head>',
0789             ' <body>',
0790         ]
0791 
0792         self._sections = collections.OrderedDict()
0793 
0794     def addNote(self, note):
0795         self._index.append('  <p>%s</p>'%note)
0796 
0797     def beginSample(self, sample, fastVsFull=False, pileupComparison=None):
0798         # Fast vs. Full becomes just after the corresponding Fast
0799         # Same for PU
0800         rightAfterRefSample = fastVsFull or (pileupComparison is not None)
0801 
0802         key = (sample.digest(), rightAfterRefSample)
0803         if key in self._sections:
0804             self._currentSection = self._sections[key]
0805         else:
0806             self._currentSection = IndexSection(sample, self._title, fastVsFull, pileupComparison)
0807             self._sections[key] = self._currentSection
0808 
0809     def addPlots(self, *args, **kwargs):
0810         self._currentSection.addPlots(*args, **kwargs)
0811 
0812     def addTable(self, *args, **kwargs):
0813         self._currentSection.addTable(*args, **kwargs)
0814 
0815     def write(self):
0816         # Reorder sections such that Fast vs. Full becomes just after the corresponding Fast
0817         keys = self._sections.keys()
0818         newkeys = []
0819         for key in keys:
0820             if not key[1]:
0821                 newkeys.append(key)
0822                 continue
0823             # is fast vs full
0824             ind_fast = newkeys.index( (key[0], False) )
0825             newkeys.insert(ind_fast+1, key)
0826 
0827         for key in newkeys:
0828             section = self._sections[key]
0829             self._index.extend(section.write(self._newBaseDir))
0830 
0831         self._index.extend([
0832             " </body>",
0833             "</html>",
0834         ])
0835 
0836         f = open(os.path.join(self._newBaseDir, "index.html"), "w")
0837         for line in self._index:
0838             f.write(line)
0839             f.write("\n")
0840         f.close()
0841 
0842 class HtmlReportDummy:
0843     def __init__(self):
0844         pass
0845 
0846     def beginSample(self, *args, **kwargs):
0847         pass
0848 
0849     def addPlots(self, *args, **kwargs):
0850         pass
0851 
0852     def addTable(self, *args, **kwargs):
0853         pass