ControllerView.py
Go to the documentation of this file.
1 import Controller
2 import common_tools as tools
3 import view_tools
4 from BatchLog import BatchLog
5 import os
6 import Canvas
7 import styles
8 import naming_schema
9 import cPickle
10 import datetime
11 import copy
12 from ROOT import TH1D, TH1F, TH2F, TH2D, TProfile2D
13 import samweb_client
14 
15 
17 
18  def __init__(self, controller, verbose=False, testing=False):
19  self.verbose = verbose
20  self.controller = controller
21  self.testing = testing
22  if self.testing:
23  self.plot_base = "%s/figures/%s/v%s/"%(os.environ["NOVAANAVALID_GRID_TEST"],
24  self.controller.name,
25  self.controller.version)
26  else:
27  self.plot_base = "%s/figures/%s/v%s/"%(os.environ["NOVAANAVALID_GRID"],
28  self.controller.name,
29  self.controller.version)
30  tools.mkdir(self.plot_base)
31  # if self.verbose: print "view : ControllerView plot base: %s"%self.plot_base
33  self.creation_time = datetime.datetime.now()
34  self.component_view_run = False
35  self.standard_true_suffixes = naming_schema.standard_truth_suffixes
36 
37  self.plot_groups = {}
38 
39  def component_view(self, canvas):
40  """
41  This will compose a view of each component of the controller
42  individually.
43 
44  These plots are order by category (reco, true, mixed), with
45  one page provided for each dataset and one page provided
46  overlaying all datasets.
47 
48  Components that are not complete are skipped
49  """
50  if self.component_view_run:
51  if self.verbose: print "view : component view has already been run"
52  return
53 
54  if self.verbose: print "view : Controller %s has %i component types"%(self.controller.name,len(self.component_type_keys))
55  self.plot_information = {}
56 
57  for component_type in self.component_type_keys:
58  if self.verbose:
59  print "view : Component type: %s, has %i instances"%(component_type, len(self.component_types[component_type]))
60 
61  self.find_complete_components(component_type)
62  if self.verbose: print "view : found %i complete components"%len(self.complete_components)
63 
64  if len(self.complete_components):
65  self.plot_information[component_type] = {}
66 
67  self.plot_groups[component_type] = []
68  self.draw_component_plots(canvas, component_type)
69 
70  if component_type in self.plot_groups.keys():
71  if self.verbose: print "view : plot groups found: %s"%repr(self.plot_groups[component_type])
72 
73  self.component_view_run = True
74 
75  def draw_component_plots(self, canvas, component_type):
76  plots = {}
77  open_files = []
78  plot_names = []
79 
80  # loop over the current complete components extracting plots and drawing them stand-alone
81  for component in self.complete_components:
82  plots[component.dataset] = {}
83  directories = hasattr(component,"directories") and component.directories
84  plot_dict, open_root_file = tools.openPlots(component.root_file, directories=directories)
85  if self.verbose: print "view : component %s, dataset: %s, opened %i histograms"%(component.name, component.dataset, len(plot_dict.keys()))
86  open_files.append(open_root_file)
87 
88  component.plot_dir = "%s/%s/v%s/%s"%(self.plot_base, component.name, component.version, component.dataset)
89  tools.mkdir(component.plot_dir)
90 
91  # collect the POT from the file
92  if "sensitivity" in component.name:
93  component.pot = False
94  area_norm = False
95  else:
96  component.pot = self.get_pot(plot_dict)
97  area_norm = True
98  if self.verbose: print "view : PoT: %.2e"%component.pot
99 
100  # first draw all plots
101  for plot_name in plot_dict.keys():
102  if ("true" in plot_name) and ("data" in naming_schema.datasetToLabel(component.dataset)): continue
103 
104  plot_names.append(plot_name)
105  plots[component.dataset][plot_name] = plot_dict[plot_name]
106  # don't draw truth components individually
107  if (tools.getHistogramTrueLevel(plot_name) != ""): continue
108 
109  if self.verbose: print "view : plot name: %s"%(plot_name)
110 
111  if plot_name.count("_vs_") > 1:
112  this_area_norm = False
113  this_pot_norm = False
114  else:
115  this_area_norm = area_norm
116  this_pot_norm = component.pot
117 
118  # draw the plot
119  path = self.draw_plots( [plot_dict[plot_name]], component.plot_dir, plot_name, [component], canvas)
120  if (this_area_norm):
121  self.draw_plots( [plot_dict[plot_name]], component.plot_dir, plot_name, [component], canvas, normalisation="area")
122  if (this_pot_norm):
123  self.draw_plots( [plot_dict[plot_name]], component.plot_dir, plot_name, [component], canvas, normalisation="pot")
124 
125  # fill the plot information
126  self.plot_information[component_type][path] = self.get_plot_information([plot_dict[plot_name]], [component], area_norm=this_area_norm, pot_norm=this_pot_norm)
127  if self.plot_information[component_type][path].group not in self.plot_groups[component.name]: self.plot_groups[component.name].append(self.plot_information[component_type][path].group)
128 
129  # If we have the standard truth suffixes, draw them
130  if (not self.has_standard_truth_types(plot_name, plot_dict.keys())): continue
131  if self.verbose: print "view : - has standard truth components"
132  self.plot_information[component_type][path].true_components = True
133 
134  sub_plots = []
135  sub_comps = []
136  fraction_of = []
137  for suffix in self.standard_true_suffixes:
138  sub_plots.append(plot_dict["%s%s"%(plot_name,suffix)])
139  sub_comps.append(component)
140  fraction_of.append(0)
141  plot_name = "%s-truth_components"%plot_name
142  plots[component.dataset][plot_name] = sub_plots
143 
144  self.draw_plots( sub_plots, component.plot_dir, plot_name, sub_comps, canvas)
145  if (this_area_norm):
146  self.draw_plots( sub_plots, component.plot_dir, plot_name, sub_comps, canvas, normalisation="area", fraction_of=fraction_of)
147  if (this_pot_norm):
148  self.draw_plots( sub_plots, component.plot_dir, plot_name, sub_comps, canvas, normalisation="pot")
149 
150  plot_names = list(set(plot_names))
151  # next draw them overlaid
152  self.group_components()
153  for plot_name in plot_names:
154  for component_group in self.grouped_components:
155  components = []
156  for component in component_group:
157  if (plot_name not in plots[component.dataset].keys()): continue
158  if ("true" in plot_name) and ("data" in naming_schema.datasetToLabel(component.dataset)): continue
159  components.append(component)
160  if len(components) < 2: continue
161 
162  to_show = [plots[c.dataset][plot_name] for c in components]
163  joined_name = "_".join([c.dataset for c in components])
164  if len(joined_name) > 25: joined_name = joined_name[:25]
165 
166  overlay_dir = "%s/%s/v%s/%s"%(self.plot_base, component.name, component.version, joined_name)
167  tools.mkdir(overlay_dir)
168 
169  path = self.draw_plots( to_show, overlay_dir, plot_name, [c for c in components], canvas, ratios=True)
170  self.draw_plots( to_show, overlay_dir, plot_name, [c for c in components], canvas, normalisation="area", ratios=True)
171  if (component.pot):
172  self.draw_plots( to_show, overlay_dir, plot_name, [c for c in components], canvas, normalisation="pot", ratios=True)
173 
174  # fill the plot information
175  self.plot_information[component_type][path] = self.get_plot_information(to_show, components)
176  if self.plot_information[component_type][path].group not in self.plot_groups[component.name]: self.plot_groups[component.name].append(self.plot_information[component_type][path].group)
177 
178  # If any components have truth sub-divisions add these
179  any_truth = False
180  truth_to_show = []
181  comps = []
182  fraction_of = []
183  for i,component in enumerate(components):
184  component = copy.copy(component)
185  if ("%s-truth_components"%plot_name in plots[component.dataset].keys()):
186  any_truth = True
187  if self.verbose: print "view : plot: %s, component: %s has truth components"%(plot_name, component.dataset)
188 
189  truth_plots = plots[component.dataset]["%s-truth_components"%plot_name]
190  component.true_components = True
191  for j,plot in enumerate(truth_plots):
192  truth_to_show.append(plot)
193  fraction_of.append(i)
194  comps.append(component)
195  else:
196  truth_to_show.append(plots[component.dataset][plot_name])
197  fraction_of.append(i)
198  comps.append(component)
199 
200  if any_truth:
201  self.plot_information[component_type][path].true_components = True
202  plot_name = "%s-truth_components"%(plot_name)
203  self.draw_plots( truth_to_show, overlay_dir, plot_name, comps, canvas)
204  self.draw_plots( truth_to_show, overlay_dir, plot_name, comps, canvas, normalisation="area", fraction_of=fraction_of)
205  if (component.pot):
206  self.draw_plots( truth_to_show, overlay_dir, plot_name, comps, canvas, normalisation="pot")
207 
208 
209  for open_file in open_files:
210  open_file.Close()
211 
212  def has_standard_truth_types(self, name, all_names):
213  for suffix in self.standard_true_suffixes:
214  if "%s%s"%(name,suffix) not in all_names: return False
215  return True
216 
217  def get_plot_information(self, plots, components, area_norm=False, pot_norm=True):
218  info = tools.getPlotStats(plots, area_norm=area_norm)
219 
220  info.datasets = [c.dataset for c in components]
221  info.names = [naming_schema.datasetToLabel(c.label) for c in components]
222  info.component_name = components[0].name
223  info.component_version = components[0].version
224  info.controller_name = self.controller.name
225  info.controller_version = self.controller.version
226  if len(components) ==1:
227  info.group = naming_schema.datasetToLabel(components[0].label)
228  elif "_nd_" in components[0].dataset:
229  info.group = "ND overlays"
230  else:
231  info.group = "FD overlays"
232 
233  if components[0].pot and pot_norm: info.normalisations.append(("PoT","pot_norm_"))
234  return info
235 
236  def draw_plots(self, \
237  plots, output_dir, plot_name, components, canvas, \
238  normalisation=False, fraction_of=False, \
239  ratios=False, \
240  ratio_ranges=[ ("",[]), ("zoom_",[0.81,1.19]) ], \
241  log=True):
242  draw_config = styles.parseDrawingConfig(plot_name, components)
243  try:
244  latex_label = naming_schema.recoLevelName(tools.getHistogramRecoLevel(plot_name))
245  except:
246  latex_label = ""
247 
248  if (normalisation == "area"):
249  new_plots = []
250  for i,plot in enumerate(plots):
251  if (type(plot) not in [TH1F, TH1D]): return
252  base_area = 100.
253  if fraction_of:
254  try:
255  area = base_area * (plot.GetSumOfWeights() / plots[fraction_of[i]].GetSumOfWeights())
256  except ZeroDivisionError:
257  area = 0.
258  else:
259  area = base_area
260  new_plots.append(view_tools.normaliseHistogram(plot, area=area))
261  plots = new_plots
262  draw_config.axis_labels = "%s;Normalised Entries [%%]"%(draw_config.axis_labels.split(";")[0])
263  plot_name = "area_norm_%s"%(plot_name)
264 
265  elif (normalisation == "pot"):
266  new_plots = []
267  for i,plot in enumerate(plots):
268  if (type(plot) not in [TH1F, TH1D]): return
269  try:
270  area = plot.GetSumOfWeights() * (tools.STANDARD_POT / components[i].pot)
271  except ZeroDivisionError:
272  area = 0.
273  new_plots.append(view_tools.normaliseHistogram(plot, area=area))
274  plots = new_plots
275  draw_config.axis_labels = "%s;Entries / %.0e PoT"%(draw_config.axis_labels.split(";")[0],tools.STANDARD_POT)
276  plot_name = "pot_norm_%s"%(plot_name)
277 
278  elif (normalisation):
279  print "view : Unknown normalisation: %s"%repr(normalisation)
280  exit(1)
281 
282  name = "%s/%s"%(output_dir,plot_name)
283 
284  canvas.draw(plots,
285  draw_config.labels,
286  draw_config.axis_labels,
287  colours=draw_config.colours,
288  lines=draw_config.lines,
289  markers=draw_config.markers,
290  draw_options=draw_config.draw_options,
291  latex_label=latex_label,
292  save_as=name)
293 
294  if log:
295  log_name = "%s/log_%s"%(output_dir,plot_name)
296  canvas.draw(plots,
297  draw_config.labels,
298  draw_config.axis_labels,
299  colours=draw_config.colours,
300  lines=draw_config.lines,
301  markers=draw_config.markers,
302  draw_options=draw_config.draw_options,
303  latex_label=latex_label,
304  log_y=True,
305  save_as=log_name)
306 
307  if ratios and (len(plots) > 1) and (type(plots[0]) in [TH1F, TH1D, TH2D, TH2F, TProfile2D]):
308  ratios = view_tools.makeRatioHistograms(plots[1:],[plots[0]])
309  if (normalisation == "area"): prefix = "Area normalised ratio"
310  elif (normalisation == "pot"): prefix = "PoT normalised ratio"
311  else: prefix = "Ratio"
312  ratio_axis_labels = "%s;%s to %s"%(draw_config.axis_labels.split(";")[0], prefix, draw_config.labels[0])
313 
314  for ratio_range in ratio_ranges:
315  prefix = ratio_range[0]
316  if type(plots[0]) in [TH1F, TH1D]:
317  y_range = ratio_range[1]
318  z_range = []
319  else:
320  y_range = []
321  z_range = ratio_range[1]
322 
323  if (len(ratios) == 1) and (type(ratios[0]) in [TH2D, TH2F, TProfile2D]):
324  draw_config.draw_options[0] = "COLZ"
325 
326  ratio_name = "%s/ratio_%s%s"%(output_dir,prefix,plot_name)
327  canvas.draw(ratios,
328  draw_config.labels[1:],
329  ratio_axis_labels,
330  y_range=y_range,
331  z_range=z_range,
332  colours=draw_config.colours[1:],
333  lines=draw_config.lines[1:],
334  markers=draw_config.markers[1:],
335  draw_options=draw_config.draw_options[1:],
336  latex_label=latex_label,
337  save_as=ratio_name)
338  return name
339 
340 
341  def get_pot(self, plot_dict):
342  pot_name = "meta-TotalPOT"
343  if pot_name in plot_dict.keys():
344  return plot_dict[pot_name].GetBinContent(1)
345  return False
346 
347  def component_status(self, component_type):
348  for i_c,component in enumerate(self.component_types[component_type]):
349  if self.verbose: print "view : [%i]: dataset: %s"%(i_c, component.dataset)
350 
351  self.check_log_status(component)
352  self.check_root_files(component)
353 
354  def find_complete_components(self, component_type):
356  for i_c,component in enumerate(self.component_types[component_type]):
357  if self.verbose: print "view : [%i]: dataset: %s"%(i_c, component.dataset)
358 
359  if component.sam:
360  if (not self.check_sam_status(component)): continue
361  else:
362  if (not self.check_log_status(component)): continue
363  if (not self.check_root_files(component)): continue
364 
365  self.complete_components.append(component)
366 
367  def check_root_files(self, component):
368  # for now only accept components that produce exactly one root file
369  root_files = tools.findRootOutput(component, testing=self.testing)
370  if len(root_files) != 1:
371  print "view: component %s, has %i root files"%(component.name, len(root_files))
372  tools.findRootOutput(component, verbose=True, testing=self.testing)
373  return False
374  # to avoid repeated calls lets assign the root file to the component
375  component.root_file = root_files[0]
376  return True
377 
378  def check_log_status(self, component):
379  job_sub_id = tools.getJobID(component.lines)
380  logs = BatchLog(tools.fetchLogs(job_sub_id, component.run_time))
381 
382  if (logs.log_status() != "completed") or (logs.err_status() != "no error"):
383  # print "view : component hasn't completed successfully"
384  print "view : - log status: ",logs.log_status()
385  print "view : - err status: ",logs.err_status()
386  return False
387 
388  return True
389 
390  def check_sam_status(self, component):
391  # has the SAM job completed
392  if (not hasattr(component, "sam_view")):
393  component.setup_sam_view()
394 
395  sam_status = component.get_sam_status(self.sam)
396  if (sam_status != "complete") and ("ended complete" not in sam_status):
397  component.sam_view.print_summary(self.sam)
398  print "view : SAM status: ",sam_status
399  return False
400 
401  # have the output files been merged
402  if self.verbose: print "view : Merge status: %s"%component.get_sam_merge_status()
403  if component.get_sam_merge_status() == "complete":
404  return True
405 
406  return False
407 
409  """
410  return a mapping of component types to components
411  """
412  self.component_types = {}
413  self.sam = False
414  for component in self.controller.components:
415  if component.name in ["hello_world"]: continue
416  if component.name not in self.component_types.keys():
417  self.component_types[component.name] = []
418  self.component_types[component.name].append(component)
419  if hasattr(component, "sam") and component.sam and (not self.sam):
420  self.sam = samweb_client.SAMWebClient("nova")
421 
422  self.component_type_keys = self.component_types.keys()
423  self.component_type_keys.sort()
424 
425  def group_components(self):
426  """
427  this looks at the current complete components and groups them
428  """
430  # ND and FD
431  nd_components = [c for c in self.complete_components if "_nd_" in c.dataset]
432  if len(nd_components): self.grouped_components.append(nd_components)
433 
434  fd_components = [c for c in self.complete_components if "_fd_" in c.dataset]
435  if len(fd_components): self.grouped_components.append(fd_components)
436 
437  def find_plot_types(self, plots):
438  """
439  plots can have different truth levels and different reco levels, group them here
440  """
441  plots.sort()
442  self.plot_types = []
443  self.reco_levels = []
444  self.true_levels = []
445  for plot in plots:
446  category = tools.getHistogramCategory(plot)
447  observable = tools.getHistogramObservable(plot)
448  plot_type = "%s-%s"%(category,observable)
449  if (plot_type not in self.plot_types): self.plot_types.append(plot_type)
450  reco_level = tools.getHistogramRecoLevel(plot)
451  if (reco_level not in self.reco_levels): self.reco_levels.append(reco_level)
452  true_level = tools.getHistogramTrueLevel(plot)
453  if (true_level not in self.true_levels): self.true_levels.append(true_level)
454  if self.verbose: print "view : found %i plot types, %i reco-levels and %i true-levels"%(len(self.plot_types),len(self.reco_levels),len(self.true_levels))
455 
456  def write(self, output_name):
457  self.file_name = output_name
458  print "view : Saving as: %s"%self.file_name
459  cPickle.dump(self,open(self.file_name,"w"))
keys
Reco plots.
Definition: caf_analysis.py:46
def get_plot_information(self, plots, components, area_norm=False, pot_norm=True)
def component_status(self, component_type)
def component_view(self, canvas)
def __init__(self, controller, verbose=False, testing=False)
def draw_component_plots(self, canvas, component_type)
def find_plot_types(self, plots)
void append()
Definition: append.C:24
def check_root_files(self, component)
def check_sam_status(self, component)
def has_standard_truth_types(self, name, all_names)
def parseDrawingConfig(plot_name, components, verbose=False)
parse drawing configuration options from the name of a histogram and a list of components ...
Definition: styles.py:10
def write(self, output_name)
def datasetToLabel(name)
convert the dataset name to a label
def check_log_status(self, component)
procfile open("FD_BRL_v0.txt")
def draw_plots(self, plots, output_dir, plot_name, components, canvas, normalisation=False, fraction_of=False, ratios=False, ratio_ranges=[("",[]), zoom_, log=True)
exit(0)
def find_complete_components(self, component_type)
def get_pot(self, plot_dict)
def makeRatioHistograms(numerators, denominators, preserve_errors=True, sumw2=True, verbose=False)
divide lists of histograms
Definition: view_tools.py:212
def normaliseHistogram(histogram, area=1., verbose=False, preserve_errors=True)
normalise a histogram
Definition: view_tools.py:166
def recoLevelName(name)
get a reconstructed level