CMS 3D CMS Logo

TH2PolyOfflineMaps.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 from __future__ import print_function
4 import sys
5 import os
6 from ROOT import *
7 from copy import deepcopy
8 from array import array
9 import six
10 
11 gROOT.SetBatch() # don't pop up canvases
12 
13 #Find Data files
14 
15 def getFileInPath(rfile):
16  import os
17  for dir in os.environ['CMSSW_SEARCH_PATH'].split(":"):
18  if os.path.exists(os.path.join(dir,rfile)): return os.path.join(dir,rfile)
19  return None
20 
21 
22 # Default values
23 inputFileName = "DQM_V0013_R000292154__StreamExpressCosmics__Commissioning2017-Express-v1__DQMIO.root"
24 limitsFileName = "limits.dat"
25 outputDirectoryName = "OUT/"
26 minMaxFileName = "minmax.out"
27 #detIDsFileName = "DATA/detids.dat"
28 detIDsFileName = getFileInPath('DQM/SiStripMonitorClient/data/detids.dat')
29 #default one
30 baseRootDirs = ["DQMData/Run 292154/PixelPhase1/Run summary/Phase1_MechanicalView"
31  ,"DQMData/Run 292154/PixelPhase1/Run summary/Tracks"
32  ]
33 
34 
35 maxPxBarrel = 4
36 maxPxForward = 3
37 barrelLadderShift = [0, 14, 44, 90]
38 
39 forwardDiskXShift = [25, 75, 125]
40 forwardDiskYShift = 45; # to make +DISK on top in the 'strip-like' layout
41 
42 plotWidth, plotHeight = 3000, 2000
43 extremeBinsNum = 20
44 
45 limits = ["num_digis 0.01 90 1 0",
46  "num_clusters 0.01 25 1 0",
47  "Trechitsize_y 0.01 10 0 0",
48  "Trechitsize_x 0.01 10 0 0",
49  "Tresidual_y 0.0000001 0.004 0 1",
50  "Tresidual_x 0.0000001 0.004 0 1",
51  "Tcharge 2000 80000 0 0",
52  "Thitefficiency 0.95 1 0 0",
53  #"Tmissing 0.01 500 0 0",
54  "Tnum_clusters_ontrack 0.01 15 1 0",
55  "Tsize 0.01 15 0 0",
56  #"Tvalid 0.01 90 0 0",
57  "adc 0.01 256 0 0",
58  "charge 2000 80000 0 0",
59  "size 0.01 15 0 0",]
60 
62 
63  ###
64  # LOTS OF CODE BORROWED FROM: PYTHONBINREADER, PIXELTRACKERMAP
65  ###
66 
67  ############################################################################
68 
69  def __TraverseDirTree(self, dir):
70 
71  try:
72  currPath = (dir.GetPath().split(":/"))[1]
73  except:
74  print("Exception raised: Path not found in the input file")
75  return
76 
77  for obj in dir.GetListOfKeys():
78  if not obj.IsFolder():
79  if obj.ReadObjectAny(TClass.GetClass("TH2")):
80  th2 = deepcopy(obj.ReadObj())
81  name = th2.GetName()
82  if 6 < th2.GetNbinsX() < 10 and name.find("per") != -1 and name.find("Lumisection") == -1: #take only module lvl plots
83  print(''.join([dir.GetPath(), '/', name]))
84 
85  # fix when there are plots starting with the same strings in different directories
86  prefix = ""
87  for i in self.dirs:
88  if currPath.startswith(i):
89  prefix = self.dirsAliases[i]
90  break
91  # print(currPath, prefix)
92  th2.SetName(prefix + th2.GetName())
93  self.listOfNumHistograms.append(th2)
94  else:
95  self.__TraverseDirTree(obj.ReadObj())
96 
97  def __GetPartStr(self, isXlowerThanZero, isYlowerThanZero):
98  if isXlowerThanZero and isYlowerThanZero:
99  return "mO"
100  if isXlowerThanZero and isYlowerThanZero == False:
101  return "mI"
102  if isXlowerThanZero == False and isYlowerThanZero:
103  return "pO"
104  if isXlowerThanZero == False and isYlowerThanZero == False:
105  return "pI"
106 
107  def __GetBarrelSector(self, layer, signedLadder, signedModule): #adapted from PixelBarrelName
108  theLadder = abs(signedLadder)
109  theModule = abs(signedModule)
110 
111  sector = 0
112 
113  if layer == 1:
114 
115  if theLadder == 1:
116  if theModule >= 2:
117  return 1
118  else:
119  return 2
120  if theLadder == 2:
121  if theModule >= 3:
122  return 2
123  else:
124  return 3
125  if theLadder == 3:
126  if theModule >= 4:
127  return 3
128  else:
129  return 4
130  if theLadder == 4:
131  if theModule >= 2:
132  return 5
133  else:
134  return 6
135  if theLadder == 5:
136  if theModule >= 3:
137  return 6
138  else:
139  return 7
140  if theLadder == 6:
141  if theModule >= 4:
142  return 7
143  else:
144  return 8
145  # here is used simplified form of assignment, see source file for reference
146  elif layer == 2:
147  i = theLadder // 5
148  sector = i * 3
149  shortLadder = theLadder - 5 * i
150  for i in range(0, shortLadder, 2):
151  sector = sector + 1
152  return sector
153  elif layer == 3:
154  sector = 1
155  for i in range(2, theLadder, 3):
156  if (i + 1) % 3 == 0:
157  sector = sector + 1
158  return sector
159  elif layer == 4:
160  sector = (theLadder + 3) // 4
161  return sector
162 
163  def __BuildOnlineBarrelName(self, signedModule, signedLadder, layer): #in Phase1 it is assumed that there are only full modules
164  thePart = self.__GetPartStr(signedModule < 0, signedLadder < 0)
165  theSector = str(self.__GetBarrelSector(layer, signedLadder, signedModule))
166  return "BPix_B" + thePart + "_SEC" + theSector + "_LYR" + str(layer) + "_LDR" + str(abs(signedLadder)) + "F_MOD" + str(abs(signedModule))
167 
168  def __BuildOnlineDiskName(self, signedDisk, signedBlade, panel, ring):
169  thePart = self.__GetPartStr(signedDisk < 0, signedBlade < 0)
170  return "FPix_B" + thePart + "_D" + str(abs(signedDisk)) + "_BLD" + str(abs(signedBlade)) + "_PNL" + str(panel) + "_RNG" + str(ring)
171 
172  def __GroupHistograms(self):
173  currentGroupName = ""
174  groupOfHists = []
176 
177  ##### GROUP ALL LAYERS/RINGS HAVING SIMILAR INFORMATION
178  for obj in self.listOfNumHistograms:
179  objName = obj.GetName()
180  objNameSplit = objName.split("_")
181  objNameCollected = ''.join(objNameSplit[0:-1])
182  if objNameCollected != currentGroupName:
183  if len(groupOfHists):
184  self.groupedHistograms.append(groupOfHists)
185  groupOfHists = []
186 
187  currentGroupName = objNameCollected
188  groupOfHists.append(obj)
189  self.groupedHistograms.append(groupOfHists) #the last group
190 
191  def __AddNamedBins(self, geoFile, tX, tY, sX, sY, applyModuleRotation = False):
192 
193  for line in geoFile:
194  lineSpl = line.strip().split("\"")
195 
196  detId = lineSpl[0].split(" ")[0]
197 
198  vertices = lineSpl[1]
199  xy = vertices.split(" ")
200  x, y = array('d'), array('d')
201  verNum = 1
202  for coord in xy:
203  coordSpl = coord.split(",")
204  if applyModuleRotation:
205  x.append(-(float(coordSpl[0]) * sX + tX))
206  y.append((float(coordSpl[1]) * sY + tY))
207  else:
208  x.append(float(coordSpl[0]) * sX + tX)
209  y.append(float(coordSpl[1]) * sY + tY)
210  verNum = verNum + 1
211  #close polygon
212  x.append(x[0])
213  y.append(y[0])
214 
215  # print(detId, vertices)
216  # print(x)
217  # print(y)
218  if applyModuleRotation:
219  bin = TGraph(verNum, y, x)
220  else:
221  bin = TGraph(verNum, x, y)
222  # bin = TGraph(verNum, y, x) # rotation by 90 deg (so that it had the same layout as for the strips)
223  bin.SetName(detId)
224 
225  self.__BaseTrackerMap.AddBin(bin)
226 
228 
229  self.__BaseTrackerMap = TH2Poly("Summary", "", -10, 160, -70, 70)
230  # self.__BaseTrackerMap = TH2Poly("Summary", "Tracker Map", 0, 0, 0, 0)
231  self.__BaseTrackerMap.SetFloat(1)
232  self.__BaseTrackerMap.GetXaxis().SetTitle("")
233  self.__BaseTrackerMap.GetYaxis().SetTitle("")
234  self.__BaseTrackerMap.SetOption("COLZ L")
235  self.__BaseTrackerMap.SetStats(0)
236 
237  # BARREL FIRST
238  for i in range(maxPxBarrel):
239  with open(self.geometryFilenames[i], "r") as geoFile:
240  currBarrelTranslateX = 0
241  currBarrelTranslateY = barrelLadderShift[i]
242 
243  self.__AddNamedBins(geoFile, currBarrelTranslateX, currBarrelTranslateY, 1, 1, True)
244 
245  # break # debug only 1st layer
246 
247  # MINUS FORWARD
248  for i in range(-maxPxForward, 0):
249  with open(self.geometryFilenames[maxPxBarrel + maxPxForward + i], "r") as geoFile:
250  currForwardTranslateX = forwardDiskXShift[-i - 1]
251  currForwardTranslateY = -forwardDiskYShift
252 
253  self.__AddNamedBins(geoFile, currForwardTranslateX, currForwardTranslateY, 1, 1)
254 
255  # PLUS FORWARD
256  for i in range(maxPxForward):
257  with open(self.geometryFilenames[maxPxBarrel + maxPxForward + i], "r") as geoFile:
258  currForwardTranslateX = forwardDiskXShift[i]
259  currForwardTranslateY = forwardDiskYShift
260 
261  self.__AddNamedBins(geoFile, currForwardTranslateX, currForwardTranslateY, 1, 1)
262 
263  # self.__BaseTrackerMap.Fill("305139728", 2)
264 
265  print("Base Tracker Map: constructed")
266 
267  ############################################################################
268  def __init__(self, inputDQMName, outputDirName, minMaxFileName, limits, modDicName, runNumber, dirs, dirsAliases):
269 # def __init__(self, inputDQMName, outputDirName, minMaxFileName, limitsFileName, modDicName, runNumber, dirs, dirsAliases):
270  self.inputFileName = inputDQMName
271  self.outputDirName = outputDirName
272  self.minMaxFileName = minMaxFileName
273 # self.limitsFileName = limitsFileName
274  self.detIDsFileName = modDicName
275  self.limits = limits
276 
277  self.runNumber = runNumber
278  self.dirs = dirs
279  self.dirsAliases = dirsAliases
280 
281  self.inputFile = TFile(self.inputFileName)
283  self.availableNames = []
284 
285  self.maxLadderToLayer = {6:1, 14:2, 22:3, 32:4}
286  self.maxBladeToRing = {11:1, 17:2}
287 
289  for i in range(maxPxBarrel):
290  self.geometryFilenames.append(getFileInPath("DQM/SiStripMonitorClient/data/Geometry/vertices_barrel_" + str(i + 1)))
291 # self.geometryFilenames.append("DATA/Geometry/vertices_barrel_" + str(i + 1))
292  for i in range(-maxPxForward, maxPxForward + 1):
293  if i == 0:
294  continue #there is no 0 disk
295  self.geometryFilenames.append(getFileInPath("DQM/SiStripMonitorClient/data/Geometry/vertices_forward_" + str(i)))
296 # self.geometryFilenames.append("DATA/Geometry/vertices_forward_" + str(i))
297 
298  self.internalData = {}
299 
300  if self.inputFile.IsOpen():
301  print("%s opened successfully!" % (self.inputFileName))
302  #Get all neeeded histograms
303  for dir in self.dirs:
304  self.__TraverseDirTree(self.inputFile.Get(dir))
305  # print("Histograms to read %d" % (len(self.listOfNumHistograms)))
306 
307  self.detDict = {}
308 
309  with open(self.detIDsFileName, "r") as detIDs: # create dictionary online -> rawid
310  for entry in detIDs:
311  items = entry.replace("\n", " ").split(" ")
312  self.detDict.update({items[1] : int(items[0])})
313  # init internal data structure
314  self.internalData.update({int(items[0]) : {}})
315 
316  self.rawToOnlineDict = dict((v,k) for k,v in six.iteritems(self.detDict))
317 
318  self.__GroupHistograms()
319 
321 
322  else:
323  print("Unable to open file %s" % (self.inputFileName))
324 
325  ### CREATE LIMITS DICTIONARY
326 
327  self.limitsDic = {}
328  for y in limits:
329 
330  lineSpl = y.strip().split(" ")
331 
332  if len(lineSpl) < 5:
333  continue
334 
335  currName = lineSpl[0]
336  zMin = float(lineSpl[1])
337  zMax = float(lineSpl[2])
338  isLog = False if lineSpl[3] == "0" else True
339  isAbs = False if lineSpl[4] == "0" else True
340 
341  self.limitsDic.update({currName : {"zMin" : zMin, "zMax" : zMax, "isLog" : isLog, "isAbs" : isAbs}})
342  # print limitsDic
343 
344  def ReadHistograms(self):
345  if self.inputFile.IsOpen():
346  for group in self.groupedHistograms:
347  # name = ''.join(group[0].GetName().split("_")[0:-1])
348  if len(group) == 0:
349  return
350  print(group[0].GetName())
351  name = ''.join(group[0].GetName().split("_per_")[0])
352  self.availableNames.append(name)
353  # print(name)
354  for obj in group:
355  nbinsX = obj.GetNbinsX()
356  nbinsY = obj.GetNbinsY()
357 
358  if nbinsX == 9: # BARREL
359  maxX = nbinsX // 2
360  maxY = nbinsY // 2
361 
362  for x in range(-maxX, maxX + 1):
363  if x == 0:
364  continue
365  for y in range(-maxY, maxY + 1, 1):
366  if y == 0:
367  continue
368  onlineName = self.__BuildOnlineBarrelName(x, y, self.maxLadderToLayer[maxY])
369  self.internalData[self.detDict[onlineName]].update({name : obj.GetBinContent(x + maxX + 1, y + maxY + 1)})
370 
371  elif nbinsX == 7: # FORWARD
372  maxX = nbinsX // 2
373  maxY = nbinsY // 4
374 
375  for x in range(-maxX, maxX + 1):
376  if x == 0:
377  continue
378  for y in range(-maxY, maxY + 1):
379  if int(y) == 0:
380  continue
381  for panel in range(1, 3):
382  onlineName = self.__BuildOnlineDiskName(x, y, panel, self.maxBladeToRing[maxY])
383  self.internalData[self.detDict[onlineName]].update({name : obj.GetBinContent(x + maxX + 1, (y + maxY) * 2 + (3-panel))})
384  else:
385  print("Unrecognized plot")
386  else:
387  print("Histograms saved to internal data structure")
388 
389  def DumpData(self):
390  for key in self.internalData:
391  print("#"*20)
392  print(key)
393  module = self.internalData[key]
394  for d in module:
395  print((d, module[d]))
396 
397  print(len(self.internalData))
398 
399  for i in self.availableNames:
400  print(i)
401  print(len(self.availableNames))
402 
403  def PrintTrackerMaps(self):
404  monitoredValues = []
405  gStyle.SetPalette(1)
406  for key in self.internalData:
407  monitoredValues = self.internalData[key].keys()
408  # print(monitoredValues)
409  break
410 
411  if os.path.exists(self.outputDirName) == False: # check whether directory exists
412  os.system("mkdir " + self.outputDirName)
413 
414  with open(self.outputDirName + self.minMaxFileName, "w") as minMaxFile:
415 
416  for mv in monitoredValues:
417  currentHist = deepcopy(self.__BaseTrackerMap)
418  # currentHist.SetTitle("Run " + self.runNumber + ": Tracker Map for " + mv) // to make it compatible between ROOT v.
419  histoTitle = "Run " + self.runNumber + ": Tracker Map for " + mv
420 
421  applyLogScale = False
422  applyAbsValue = False
423  if mv in self.limitsDic:
424  limitsElem = self.limitsDic[mv]
425 
426  print(mv + " found in limits dictionary - applying custom limits...")
427 
428  currentHist.SetMinimum(limitsElem["zMin"])
429  currentHist.SetMaximum(limitsElem["zMax"])
430  applyLogScale = limitsElem["isLog"]
431  applyAbsValue = limitsElem["isAbs"]
432 
433  listOfVals = []
434  onlineName = ""
435  for detId in self.internalData:
436  val = (self.internalData[detId])[mv]
437  onlineName = self.rawToOnlineDict[detId]
438  listOfVals.append([val, detId, onlineName])
439  if applyAbsValue:
440  currentHist.Fill(str(detId), abs(val))
441  else:
442  currentHist.Fill(str(detId), val)
443 
444  listOfVals = sorted(listOfVals, key = lambda item: item[0])
445 
446  minMaxFile.write("\n" + mv + "\n\n")
447 
448  minMaxFile.write("MIN:\n")
449  for i in range(extremeBinsNum):
450  minMaxFile.write("\t" + str(listOfVals[i][1]) + " " + str(listOfVals[i][2]) + " " + str(listOfVals[i][0]) + "\n")
451 
452  minMaxFile.write("MAX:\n")
453  for i in range(extremeBinsNum):
454  minMaxFile.write("\t" + str(listOfVals[-i - 1][1]) + " " + str(listOfVals[-i - 1][2]) + " " + str(listOfVals[-i - 1][0]) + "\n")
455 
456  c1 = TCanvas(mv, mv, plotWidth , plotHeight)
457 
458  if applyLogScale:
459  c1.SetLogz()
460 
461 
462 
463  currentHist.Draw("AC COLZ L")
464 
465  gPad.Update()
466  palette = currentHist.FindObject("palette");
467  palette.SetX1NDC(0.89);
468  palette.SetX2NDC(0.91);
469  palette.SetLabelSize(0.05);
470  gPad.Update()
471 
472 
473 
474  ### IMPORTANT - REALTIVE POSITIONING IS MESSY IN CURRENT VERION OF PYROOT
475  ### IT CAN CHANGE FROM VERSION TO VERSION, SO YOU HAVE TO ADJUST IT FOR YOUR NEEDS
476  ### !!!!!!!!!!!!!
477 
478  # draw axes (z, phi -> BARREL; x, y -> FORWARD)
479  ###################################################
480 
481  ### z arrow
482  arrow = TArrow(0.05, 27.0, 0.05, -30.0, 0.02, "|>")
483  arrow.SetLineWidth(4)
484  arrow.Draw()
485  ### phi arrow
486  phiArrow = TArrow(0.0, 27.0, 30.0, 27.0, 0.02, "|>")
487  phiArrow.SetLineWidth(4)
488  phiArrow.Draw()
489  ### x arror
490  xArrow = TArrow(25.0, 44.5, 50.0, 44.5, 0.02, "|>")
491  xArrow.SetLineWidth(4)
492  xArrow.Draw()
493  ### y arror
494  yArrow = TArrow(25.0, 44.5, 25.0, 69.5, 0.02, "|>")
495  yArrow.SetLineWidth(4)
496  yArrow.Draw()
497 
498  ###################################################
499 
500  # add some captions
501  txt = TLatex()
502  txt.SetNDC()
503  txt.SetTextFont(1)
504  txt.SetTextColor(1)
505  txt.SetTextAlign(22)
506  txt.SetTextAngle(0)
507 
508  # draw new-style title
509  txt.SetTextSize(0.05)
510  txt.DrawLatex(0.5, 0.95, histoTitle)
511 
512  txt.SetTextSize(0.03)
513 
514  txt.DrawLatex(0.5, 0.125, "-DISK")
515  txt.DrawLatex(0.5, 0.075, "NUMBER ->")
516  txt.DrawLatex(0.5, 0.875, "+DISK")
517 
518  txt.DrawLatex(0.17, 0.35, "+z")
519  txt.DrawLatexNDC(0.36, 0.685, "+phi") # WAY TO FORCE IT TO DRAW LATEX CORRECTLY NOT FOUND ('#' DOESN'T WORK)
520  txt.DrawLatex(0.38, 0.73, "+x")
521  txt.DrawLatex(0.26, 0.875, "+y")
522 
523  txt.SetTextAngle(90)
524  txt.DrawLatex(0.17, 0.5, "BARREL")
525 
526  #save to the png
527  c1.Print(self.outputDirName + mv + ".png")
528 
529  def __del__(self):
530  if self.inputFile.IsOpen():
531  self.inputFile.Close()
532 
533 #--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--
534 for i in range(1, len(sys.argv), 1):
535  if i == 1:
536  inputFileName = sys.argv[i]
537  elif i == 2:
538  plotWidth = int(sys.argv[i])
539  elif i == 3:
540  plotHeight = int(sys.argv[i])
541 # elif i == 4:
542 # limitsFileName = sys.argv[i]
543 # elif i == 5:
544  elif i == 4:
545  detIDsFileName = sys.argv[i]
546 
547 deductedRunNumber = inputFileName.split("_R000")[1][0:6]
548 print(deductedRunNumber)
549 
550 baseRootDirs = ["DQMData/Run " + deductedRunNumber + "/PixelPhase1/Run summary/Phase1_MechanicalView" #maybe read it from the input file???
551  ,"DQMData/Run " + deductedRunNumber + "/PixelPhase1/Run summary/Tracks"
552  ]
553 
554 baseRootDirsAliases = {baseRootDirs[0]:""
555  , baseRootDirs[1]:"T"
556  }
557 
558 readerObj = TH2PolyOfflineMaps(inputFileName, outputDirectoryName, minMaxFileName, limits, detIDsFileName, deductedRunNumber, baseRootDirs, baseRootDirsAliases)
559 #readerObj = TH2PolyOfflineMaps(inputFileName, outputDirectoryName, minMaxFileName, limitsFileName, detIDsFileName, deductedRunNumber, baseRootDirs, baseRootDirsAliases)
560 readerObj.ReadHistograms()
561 # readerObj.DumpData()
562 readerObj.PrintTrackerMaps()
def __GetBarrelSector(self, layer, signedLadder, signedModule)
def __TraverseDirTree(self, dir)
LOTS OF CODE BORROWED FROM: PYTHONBINREADER, PIXELTRACKERMAP.
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:65
def __BuildOnlineDiskName(self, signedDisk, signedBlade, panel, ring)
def __init__(self, inputDQMName, outputDirName, minMaxFileName, limits, modDicName, runNumber, dirs, dirsAliases)
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
static std::string join(char **cmd)
Definition: RemoteFile.cc:18
def __GetPartStr(self, isXlowerThanZero, isYlowerThanZero)
def __BuildOnlineBarrelName(self, signedModule, signedLadder, layer)
#define update(a, b)
def __AddNamedBins(self, geoFile, tX, tY, sX, sY, applyModuleRotation=False)
#define str(s)
double split
Definition: MVATrainer.cc:139