class MassPlane: def __init__(self,x_bins,x_min,x_max,y_bins,y_min,y_max,plot_DY=False,plot_TT=False,plot_ZA=False,profile=False): self.x_bins = x_bins self.x_min = x_min self.x_max = x_max self.y_bins = y_bins self.y_min = y_min self.y_max = y_max self.model = None self.plot_DY = plot_DY self.plot_TT = plot_TT self.plot_ZA = plot_ZA self.profile = profile self.graph_list = [] # Produce grid # self.produce_grid() def produce_grid(self): self.X,self.Y = np.meshgrid(np.linspace(self.x_min,self.x_max,self.x_bins),np.linspace(self.y_min,self.y_max,self.y_bins)) bool_upper = np.greater_equal(self.Y,self.X) self.X = self.X[bool_upper] self.Y = self.Y[bool_upper] self.x = self.X.reshape(-1,1) self.y = self.Y.reshape(-1,1) # X, Y are 2D arrays, x,y are vectors of points def load_model(self,path_model): self.model = Restore(path_model, custom_objects={'PreprocessLayer': PreprocessLayer}).model self.model_name = os.path.basename(path_model).replace(".zip","") def plotMassPoint(self,mH,mA): print ("Producing plot for MH = %.2f GeV, MA = %.2f"%(mH,mA)) N = self.x.shape[0] params = np.c_[np.ones(N)*mA,np.ones(N)*mH] inputs = np.c_[self.x,self.y,params] output = self.model.predict(inputs) g_DY = ROOT.TGraph2D(N) g_DY.SetNpx(500) g_DY.SetNpy(500) g_TT = ROOT.TGraph2D(N) g_TT.SetNpx(500) g_TT.SetNpy(500) g_ZA = ROOT.TGraph2D(N) g_ZA.SetNpx(500) g_ZA.SetNpy(500) g_DY.SetName(("MassPlane_DY_mH_%s_mA_%s"%(mH,mA)).replace('.','p')) g_TT.SetName(("MassPlane_TT_mH_%s_mA_%s"%(mH,mA)).replace('.','p')) g_ZA.SetName(("MassPlane_ZA_mH_%s_mA_%s"%(mH,mA)).replace('.','p')) for i in range(N): if self.plot_DY: g_DY.SetPoint(i,self.x[i],self.y[i],output[i,0]) if self.plot_TT: g_TT.SetPoint(i,self.x[i],self.y[i],output[i,1]) if self.plot_ZA: g_ZA.SetPoint(i,self.x[i],self.y[i],output[i,2]) if self.plot_DY: self.graph_list.append(g_DY) g_DY.GetHistogram().SetTitle("P(DY) for mass point M_{H} = %.2f GeV, M_{A} = %.2f GeV"%(mH,mA)) g_DY.GetHistogram().GetXaxis().SetTitle("M_{jj} [GeV]") g_DY.GetHistogram().GetYaxis().SetTitle("M_{lljj} [GeV]") g_DY.GetHistogram().GetZaxis().SetTitle("DNN output") g_DY.GetHistogram().GetZaxis().SetRangeUser(0.,1.) g_DY.GetHistogram().SetContour(100) g_DY.GetXaxis().SetTitleOffset(1.2) g_DY.GetYaxis().SetTitleOffset(1.2) g_DY.GetZaxis().SetTitleOffset(1.2) g_DY.GetXaxis().SetTitleSize(0.045) g_DY.GetYaxis().SetTitleSize(0.045) g_DY.GetZaxis().SetTitleSize(0.045) if self.plot_TT: g_TT.GetHistogram().SetTitle("P(t#bar{t}) for mass point M_{H} = %.2f GeV, M_{A} = %.2f GeV"%(mH,mA)) g_TT.GetHistogram().GetXaxis().SetTitle("M_{jj} [GeV]") g_TT.GetHistogram().GetYaxis().SetTitle("M_{lljj} [GeV]") g_TT.GetHistogram().GetZaxis().SetTitle("DNN output") g_TT.GetHistogram().GetZaxis().SetRangeUser(0.,1.) g_TT.GetHistogram().SetContour(100) g_TT.GetXaxis().SetTitleOffset(1.2) g_TT.GetYaxis().SetTitleOffset(1.2) g_TT.GetZaxis().SetTitleOffset(1.2) g_TT.GetXaxis().SetTitleSize(0.045) g_TT.GetYaxis().SetTitleSize(0.045) g_TT.GetZaxis().SetTitleSize(0.045) self.graph_list.append(g_TT) if self.plot_ZA: g_ZA.GetHistogram().SetTitle("P(H#rightarrowZA) for mass point M_{H} = %.2f GeV, M_{A} = %.2f GeV"%(mH,mA)) g_ZA.GetHistogram().GetXaxis().SetTitle("M_{jj} [GeV]") g_ZA.GetHistogram().GetYaxis().SetTitle("M_{lljj} [GeV]") g_ZA.GetHistogram().GetZaxis().SetTitle("DNN output") g_ZA.GetHistogram().GetZaxis().SetRangeUser(0.,1.) g_ZA.GetHistogram().SetContour(100) g_ZA.GetXaxis().SetTitleOffset(1.2) g_ZA.GetYaxis().SetTitleOffset(1.2) g_ZA.GetZaxis().SetTitleOffset(1.2) g_ZA.GetXaxis().SetTitleSize(0.045) g_ZA.GetYaxis().SetTitleSize(0.045) g_ZA.GetZaxis().SetTitleSize(0.045) self.graph_list.append(g_ZA) @staticmethod def getProfiles(g): h = g.GetHistogram() xproj = h.ProjectionX() yproj = h.ProjectionY() array = hist2array(h) # Need to compensate the triangular binning nonzeroXbins = h.GetNbinsY()/np.count_nonzero(array,axis=1) nonzeroYbins = h.GetNbinsX()/np.count_nonzero(array,axis=0) for x in range(1,h.GetNbinsX()): xproj.SetBinContent(x,xproj.GetBinContent(x)*nonzeroXbins[x-1]) for y in range(1,h.GetNbinsY()): yproj.SetBinContent(y,yproj.GetBinContent(y)*nonzeroYbins[y-1]) xproj.GetYaxis().SetTitle("DNN output") yproj.GetYaxis().SetTitle("DNN output") return xproj, yproj def plotOnCanvas(self): setTDRStyle() pdf_path = "MassPlane/"+self.model_name+".pdf" root_path = pdf_path.replace('.pdf','.root') outFile = ROOT.TFile(root_path,"RECREATE") C = ROOT.TCanvas("C","C",800,600) #C.SetLogz() C.Print(pdf_path+"[") for g in self.graph_list: print ("Plotting %s"%g.GetName()) g.Draw("colz") g_copy = g.Clone() contours = np.array([0.90,0.95,0.99]) g_copy.GetHistogram().SetContour(contours.shape[0],contours) g_copy.Draw("cont2 same") g.Write() C.Print(pdf_path,"Title:"+g.GetName()) if self.profile: xproj,yproj = self.getProfiles(g) xproj.Draw("hist") xproj.Write() C.Print(pdf_path,"Title:"+g.GetName()+" X profile") yproj.Draw("hist") C.Print(pdf_path,"Title:"+g.GetName()+" Y profile") yproj.Write() C.Print(pdf_path+"]") outFile.Close() print ("Root file saved as %s"%root_path) def makePavement(self,contours): for contour in contours: print ("Producing pavement for cut %.2f"%contour) pdf_path = "MassPlane/"+self.model_name+("_pave%0.2f"%contour).replace('.','p')+".pdf" root_path = pdf_path.replace('.pdf','.root') outFile = ROOT.TFile(root_path,"RECREATE") C = ROOT.TCanvas("C","C",800,600) opt = 'cont2' new_graph_list = [g.Clone() for g in self.graph_list] # Need them saved in a list otherwise they are deleted and canvas is blank for g in new_graph_list: print ('Adding to contour plot',g.GetName()) g.SetTitle("Pavement for cut %0.2f"%contour) g.GetHistogram().SetContour(1,np.array([contour])) g.Draw(opt) if 'same' not in opt : opt += " same" g.Write() C.Print(pdf_path) outFile.Close()
class LikelihoodMap(): def __init__(self, name, xmin, ymin, xmax, ymax, N, normalize=False): self.xmin = xmin self.ymin = ymin self.xmax = xmax self.ymax = ymax self.N = N self.name = name self.normalize = normalize # Xsec*BR*Acc self.nevents = 0 # count the number of events custom_objects = {'PreprocessLayer': PreprocessLayer} self.model = Restore(os.path.join( '/home/users/f/b/fbury/MoMEMtaNeuralNet/model/', name + '_HToZA.zip'), custom_objects=custom_objects).model #self.model = HyperModel(name,'HToZA') # Make directory output # self.path_output = os.path.join( '/home/ucl/cp3/fbury/MoMEMtaNeuralNet/Plotting/PDF', self.name) if not os.path.exists(self.path_output): os.makedirs(self.path_output) # Get the normalization # if self.normalize: self._importGraphs() # Make the grid # self._make_grid() # Prepare output # self.Z = np.zeros( self.N) # N has chnaged because of unphysical phase space point ################################################ # L(x_i|alpha) = \prod_i 1/sigma_vis W(x_i|alpha) # -ln (L(x_i|alpha)) = \sum_i [ -ln(W(x_i|alpha)) + ln(sigma_vis) ] # = \sum_i [ output_DNN ] + n*ln(sigma_vis) def _make_grid(self): x = np.linspace(self.xmin, self.xmax, self.N) y = np.linspace(self.ymin, self.ymax, self.N) X, Y = np.meshgrid(x, y) mA = X.flatten() mH = Y.flatten() mh = 125 mZ = 90 # Unphysical phase-space points # condition1 = np.greater(mH, mA) condition2 = np.greater(mH, mh) condition3 = np.greater(np.subtract(mH, mA), mZ) #upper = np.logical_and(condition1,condition2) upper = np.logical_and(np.logical_and(condition1, condition2), condition3) # Ensure that mH > mh # Ensure that mH > mA # Ensure that mH-mA > mZ self.mA = mA[upper] self.mH = mH[upper] self.N = self.mA.shape[0] # Normalisation with xsec visible # self.norm = np.ones(self.N) if self.normalize: logging.info('Normalization enabled') for i in range(0, self.N): self.norm[i] *= self.acc.Interpolate(self.mA[i], self.mH[i]) #self.norm[i] *= self.xsec.Interpolate(self.mA[i],self.mH[i]) self.norm[i] *= self.BR_HtoZA.Interpolate( self.mA[i], self.mH[i]) #self.norm[i] *= self.BR_Atobb.Interpolate(self.mA[i],self.mH[i]) self.norm[i] *= 3.3658 * 2 / 100 # Z-> e+e- + Z-> mu+mu- self.norm[i] *= 1e-12 # Xsec in pb # Get log(normalization) # self.norm = np.log10( self.norm ) # if normalize == False => norm =1 => log(norm)=0 (thus not used) # phase space points non physical(xsec=0) -> will produce -inf def AddEvent(self, event): # Get the -log(weight) # inputs = np.c_[np.tile(event, (self.N, 1)), self.mH, self.mA] #outputs = self.model.HyperRestore(inputs) outputs = self.model.predict(inputs, batch_size=512) self.Z += outputs.reshape(-1, ) self.nevents += 1 def MakeGraph(self, title, suffix): self.legend_title = title.replace('.root', '').replace('-', '_') self.suffix = suffix if title.find('DY') != -1: title = 'Drell-Yan events' elif title.find('TT') != -1: title = r't\bar{t} events' else: mH_value = re.findall(r'\d+', title)[2] mA_value = re.findall(r'\d+', title)[3] title = 'Signal events with M_{H} = %s GeV and M_{A} = %s GeV' % ( mH_value, mA_value) # Normalize # if self.normalize: self.Z += self.nevents * self.norm title += ' [Normalized]' self.legend_title += '_norm' # Divide by total entries # self.Z /= self.nevents # Divide by N self.Z *= 2 # Because -2 log L # check for invalids (nan of inf) might be coming from log10 # invalid_entries = np.logical_or(np.isinf(self.Z), np.isnan(self.Z)) max_Z = np.amax(self.Z[np.invert(invalid_entries)]) min_Z = np.amin(self.Z[np.invert(invalid_entries)]) self.Z[invalid_entries] = 0 # removes non physical points # Generate graph # graph = TGraph2D(self.N) print('Generating TGraph2D') manager = enlighten.get_manager() pbar = manager.counter(total=self.N, desc='Progress', unit='Point') for i in range(self.N): graph.SetPoint(i, self.mA[i], self.mH[i], self.Z[i]) pbar.update() manager.stop() #graph = copy.deepcopy(TGraph2D(self.N,self.mA,self.mH,self.Z)) graph.SetTitle( 'Log-Likelihood : %s;M_{A} [GeV]; M_{H} [GeV]; -2log L' % (title)) graph.SetMaximum(max_Z) graph.SetMinimum(min_Z) graph.SetNpx(1000) graph.SetNpy(1000) # Save graph # self.graph = graph self._saveGraph() def _saveGraph(self): full_name = self.path_output + '/likelihood_' + self.suffix + '.root' if os.path.exists(full_name): root_file = TFile(full_name, "update") self.graph.Write(self.legend_title, TObject.kOverwrite) logging.info("New Graph saved in %s" % full_name) else: root_file = TFile(full_name, "recreate") self.graph.Write(self.legend_title) logging.info("Graph replaced in %s" % full_name) def _importGraphs(self): # import the TGraphs 2D # path_graphs = '/home/users/f/b/fbury/MoMEMtaNeuralNet/Plotting/' file_xsec = TFile.Open(os.path.join(path_graphs, 'XsecMap_full.root')) file_acc = TFile.Open( os.path.join(path_graphs, 'AcceptanceMap_full.root')) try: # Deepcopy necessary to avoid seg fault self.xsec = copy.deepcopy(file_xsec.Get('Xsec')) self.BR_HtoZA = copy.deepcopy(file_xsec.Get('BR_HtoZA')) self.BR_Atobb = copy.deepcopy(file_xsec.Get('BR_Atobb')) self.BR_Ztoll = copy.deepcopy(file_xsec.Get('BR_Ztoll')) self.acc = copy.deepcopy(file_acc.Get('Acceptance')) except: self.normalize = False logging.warning('Could not load the Objects -> normalization off') if not isinstance(self.xsec, ROOT.TGraph2D): self.normalize = False logging.warning( 'Xsec is %s and not TGraph2D -> normalization off' % type(self.xsec)) if not isinstance(self.BR_HtoZA, ROOT.TGraph2D): self.normalize = False logging.warning( 'BR_HtoZA is %s and not TGraph2D -> normalization off' % type(self.BR_HtoZA)) if not isinstance(self.BR_Atobb, ROOT.TGraph2D): self.normalize = False logging.warning( 'BR_Atobb is %s and not TGraph2D -> normalization off' % type(self.BR_Atobb)) if not isinstance(self.BR_Ztoll, ROOT.TGraph2D): self.normalize = False logging.warning( 'BR_Ztoll is %s and not TGraph2D -> normalization off' % type(self.BR_Ztoll)) if not isinstance(self.acc, ROOT.TGraph2D): self.normalize = False logging.warning( 'Acceptance is %s and not TGraph2D -> normalization off' % type(self.acc))