def limits(analysis, model, mass, fit_function, noSyst=False, freezeNuisances=None): print "\nCalculating limits for {}, {}, {}, {}".format(analysis, model, mass, fit_function) prefix = 'limits' postfix = "" if noSyst: postfix += "_noSyst" if freezeNuisances: postfix += "_" + args.freezeNuisances.replace(",", "_") datacard = limit_config.get_datacard_filename(analysis, model, mass, fit_function, fitSignal=True) log_base = limit_config.get_combine_log_path_grid(analysis, model, mass, fit_function, "HybridNewGrid", systematics=(not noSyst), frozen_nps=freezeNuisances) command_base = "combine {} -M HybridNew -v5 --frequentist --grid={}".format(datacard, limit_config.get_hn_grid(analysis, model, mass, fit_function)) # Observed #log_observed = log_base.replace(".log", "_obs.log") print "Observed:" log_observed = limit_config.get_combine_log_path_grid(analysis, model, mass, fit_function, "obs", method="HybridNewGrid", systematics=(not noSyst), frozen_nps=freezeNuisances) command_observed = command_base + " 2>&1 | tee {}".format(log_observed) print command_observed os.system(command_observed) # Expected expected_r = {-2:0.025, -1:0.16, 0:0.5, 1:0.84, 2:0.975} for exp in [-2, -1, 0, 1, 2]: print "Expected, " + str(exp) #log_expected = log_base.replace(".log", "_exp{}.log".format(exp)) log_expected = limit_config.get_combine_log_path_grid(analysis, model, mass, fit_function, "exp" + str(exp), method="HybridNewGrid", systematics=(not noSyst), frozen_nps=freezeNuisances) print "[debug] Writing log file to " + log_expected command_expected = command_base + " --expectedFromGrid {} 2>&1 | tee {}".format(expected_r[exp], log_expected) print command_expected os.system(command_expected)
combine_options = "-M GoodnessOfFit -v3 --algo {} -s {} --name {} --mass {} ".format( args.algo, args.seed, job_name, mass ) if args.cplots: combine_options += " --plots " if args.no_signal: combine_options += " --fixedSignalStrength 0" elif args.signal != None: combine_options += " --fixedSignalStrength {} ".format(args.signal) cmd = "combine {} {} 2>&1 | tee {}".format( combine_options, os.path.basename(limit_config.get_datacard_filename(analysis, model, mass, args.fit_function, correctTrigger=args.correctTrigger, qcd=args.qcd, fitTrigger=args.fitTrigger)), log_name) if args.toys: combine_toy_options = "-M GoodnessOfFit -v3 --algo {} -s {} --name {} --mass {} ".format( args.algo, args.seed, job_name + "_toys", mass ) if args.no_signal: combine_toy_options += " --fixedSignalStrength 0" elif args.signal != None: combine_toy_options += " --fixedSignalStrength {} ".format(args.signal) toy_cmd = "combine {} {} -t {} 2>&1 | tee {}".format(
masses[analysis] = [int(x) for x in args.masses.split(",")] else: for analysis in analyses: if "bbl" in analysis: masses[analysis] = xrange(350, 650, 50) elif "bbh" in analysis: masses[analysis] = xrange(600, 1250, 50) if args.fit: cwd = os.getcwd() os.chdir("/uscms/home/dryu/Dijets/data/EightTeeEeVeeBee/Fits/AsimovFits") for analysis in analyses: #for model in models: # for mass in masses[analysis]: # for fit_function in fit_functions: # for expected_signal in expected_signals: # datacard = limit_config.get_datacard_filename(analysis, model, mass, fit_function, #fitSignal=True, correctTrigger=True) # name = os.path.basename(datacard).replace("datacard", "").replace(".txt", "") + "_" + #str(expected_signal) # command = "combine {} -M MaxLikelihoodFit -t -1 --expectSignal {} --name {}".format(#datacard, expected_signal, name) # log = "/uscms/home/dryu/Dijets/data/EightTeeEeVeeBee/Fits/Logs/asimovcheck" + name + "#.log" # os.system(command + " >& " + log) Parallel(n_jobs=4)(delayed(RunAsimovCheck)(limit_config.get_datacard_filename(analysis, model, mass, fit_function, correctTrigger=True), expected_signal, condor=args.condor, workspace=limit_config.get_workspace_filename(analysis, model, mass, correctTrigger=True)) for mass in masses[analysis] for model in models for fit_function in fit_functions for expected_signal in expected_signals) os.chdir(cwd) if args.table: for analysis in analyses: Parallel(n_jobs=4)(delayed(AsimovFitTables)(model, analysis, fit_functions, expected_signal, masses[analysis]) for model in models for expected_signal in expected_signals) if args.plot: for analysis in analyses: Parallel(n_jobs=4)(delayed(AsimovFitPlots)(model, analysis, fit_functions, expected_signal, masses[analysis]) for model in models for expected_signal in expected_signals)
def limits(analysis, model, mass, fit_function, noSyst=False, freezeNuisances=None): print "\nCalculating limits for {}, {}, {}, {}".format( analysis, model, mass, fit_function) prefix = 'limits' postfix = "" if noSyst: postfix += "_noSyst" if freezeNuisances: postfix += "_" + args.freezeNuisances.replace(",", "_") datacard = limit_config.get_datacard_filename(analysis, model, mass, fit_function, fitSignal=True) log_base = limit_config.get_combine_log_path_grid( analysis, model, mass, fit_function, "HybridNewGrid", systematics=(not noSyst), frozen_nps=freezeNuisances) command_base = "combine {} -M HybridNew -v5 --frequentist --grid={}".format( datacard, limit_config.get_hn_grid(analysis, model, mass, fit_function)) # Observed #log_observed = log_base.replace(".log", "_obs.log") print "Observed:" log_observed = limit_config.get_combine_log_path_grid( analysis, model, mass, fit_function, "obs", method="HybridNewGrid", systematics=(not noSyst), frozen_nps=freezeNuisances) command_observed = command_base + " 2>&1 | tee {}".format(log_observed) print command_observed os.system(command_observed) # Expected expected_r = {-2: 0.025, -1: 0.16, 0: 0.5, 1: 0.84, 2: 0.975} for exp in [-2, -1, 0, 1, 2]: print "Expected, " + str(exp) #log_expected = log_base.replace(".log", "_exp{}.log".format(exp)) log_expected = limit_config.get_combine_log_path_grid( analysis, model, mass, fit_function, "exp" + str(exp), method="HybridNewGrid", systematics=(not noSyst), frozen_nps=freezeNuisances) print "[debug] Writing log file to " + log_expected command_expected = command_base + " --expectedFromGrid {} 2>&1 | tee {}".format( expected_r[exp], log_expected) print command_expected os.system(command_expected)
for analysis in analyses: job_mu_values[model][analysis] = {} for gen_mass in gen_masses: if args.mu == 0: job_mu_values[model][analysis][gen_mass] = 0. else: workspace_file = TFile(limit_config.get_workspace_filename(analysis, model, gen_mass, correctTrigger=False, useMCTrigger=True, qcd=False, fitTrigger=True, fitBonly=False), "READ") #workspace_file = TFile(datacard_folders[model][analysis] + "/workspace_qq_m" + str(gen_mass) + ".root", "READ") workspace = workspace_file.Get("w") signal_norm = workspace.var("signal_norm").getVal() job_mu_values[model][analysis][gen_mass] = 19700. * limit_config.limit_p2sigma_estimates[analysis][model][gen_mass] / signal_norm if args.run: for model in models: for analysis in analyses: for gen_mass in gen_masses: names = [] fit_datacards = {} fit_workspaces = {} gen_name = model + "_" + analysis + "/m" + str(gen_mass) + "_mu" + str(args.mu) gen_datacard = limit_config.get_datacard_filename(analysis, model, gen_mass, "dijet4", correctTrigger=False, useMCTrigger=True, qcd=False, fitTrigger=True, fitBonly=False) gen_workspace = limit_config.get_workspace_filename(analysis, model, gen_mass, correctTrigger=False, useMCTrigger=True, qcd=False, fitTrigger=True, fitBonly=False) top_name = model + "_" + analysis + "/genmass_" + str(gen_mass) + "_mu" + str(args.mu) job_names = [] for fit_mass in fit_masses: fit_name = model + "_" + analysis + "/m" + str(fit_mass) + "_mu" + str(args.mu) name = model + "_" + analysis + "_genmass" + str(gen_mass) + "_fitmass_" + str(fit_mass) + "_mu" + str(args.mu) job_names.append(name) fit_datacards[name] = limit_config.get_datacard_filename(analysis, model, fit_mass, "dijet4", correctTrigger=False, useMCTrigger=True, qcd=False, fitTrigger=True, fitBonly=False) fit_workspaces[name] = limit_config.get_workspace_filename(analysis, model, fit_mass, correctTrigger=False, useMCTrigger=True, qcd=False, fitTrigger=True, fitBonly=False) run_many_granularity_studies(top_name, job_names, gen_datacard=gen_datacard, fit_datacards=fit_datacards, gen_workspace=gen_workspace, fit_workspaces=fit_workspaces, n_toys=args.n_toys, mu=job_mu_values[model][analysis][gen_mass])
def main(): # usage description usage = "Example: ./scripts/createDatacards.py --inputData inputs/rawhistV7_Run2015D_scoutingPFHT_UNBLINDED_649_838_JEC_HLTplusV7_Mjj_cor_smooth.root --dataHistname mjj_mjjcor_gev --inputSig inputs/ResonanceShapes_gg_13TeV_Scouting_Spring15.root -f gg -o datacards -l 1866 --lumiUnc 0.027 --massrange 1000 1500 50 --runFit --p1 5 --p2 7 --p3 0.4 --massMin 838 --massMax 2037 --fitStrategy 2" # input parameters parser = ArgumentParser(description='Script that creates combine datacards and corresponding RooFit workspaces',epilog=usage) parser.add_argument("analysis", type=str, help="Analysis name") parser.add_argument("model", type=str, help="Model (Hbb, RSG)") #parser.add_argument("--inputData", dest="inputData", required=True, # help="Input data spectrum", # metavar="INPUT_DATA") parser.add_argument("--dataHistname", dest="dataHistname", type=str, default="h_data", help="Data histogram name", metavar="DATA_HISTNAME") #parser.add_argument("--inputSig", dest="inputSig", required=True, # help="Input signal shapes", # metavar="INPUT_SIGNAL") parser.add_argument("-f", "--final_state", dest="final_state", default="qq", help="Final state (e.g. qq, qg, gg)", metavar="FINAL_STATE") parser.add_argument("--fit_functions", dest="fit_functions", default="f1,f2,f3,f4,f5", help="List of fit functions") #parser.add_argument("-f2", "--type", dest="atype", required=True, help="Type (e.g. hG, lG, hR, lR)") parser.add_argument("-o", "--output_path", dest="output_path", help="Output path where datacards and workspaces will be stored. If not specified, this is derived from limit_configuration.", metavar="OUTPUT_PATH") parser.add_argument("--correctTrigger", dest="correctTrigger", action='store_true', help="Include trigger correction in PDF") parser.add_argument("-l", "--lumi", dest="lumi", default=19700., type=float, help="Integrated luminosity in pb-1 (default: %(default).1f)", metavar="LUMI") parser.add_argument("--massMin", dest="massMin", default=500, type=int, help="Lower bound of the mass range used for fitting (default: %(default)s)", metavar="MASS_MIN") parser.add_argument("--massMax", dest="massMax", default=1200, type=int, help="Upper bound of the mass range used for fitting (default: %(default)s)", metavar="MASS_MAX") parser.add_argument("--fitSignal", action="store_true", help="Use signal fitted shapes (CB+Voigtian) instead of histogram templates") #parser.add_argument("--lumiUnc", dest="lumiUnc", # required=True, type=float, # help="Relative uncertainty in the integrated luminosity", # metavar="LUMI_UNC") #parser.add_argument("--jesUnc", dest="jesUnc", # type=float, # help="Relative uncertainty in the jet energy scale", # metavar="JES_UNC") #parser.add_argument("--jerUnc", dest="jerUnc", # type=float, # help="Relative uncertainty in the jet energy resolution", # metavar="JER_UNC") parser.add_argument("--sqrtS", dest="sqrtS", default=8000., type=float, help="Collision center-of-mass energy (default: %(default).1f)", metavar="SQRTS") parser.add_argument("--fixP3", dest="fixP3", default=False, action="store_true", help="Fix the fit function p3 parameter") parser.add_argument("--runFit", dest="runFit", default=False, action="store_true", help="Run the fit") parser.add_argument("--fitBonly", dest="fitBonly", default=False, action="store_true", help="Run B-only fit") parser.add_argument("--fixBkg", dest="fixBkg", default=False, action="store_true", help="Fix all background parameters") parser.add_argument("--decoBkg", dest="decoBkg", default=False, action="store_true", help="Decorrelate background parameters") parser.add_argument("--fitStrategy", dest="fitStrategy", type=int, default=1, help="Fit strategy (default: %(default).1f)") parser.add_argument("--debug", dest="debug", default=False, action="store_true", help="Debug printout") parser.add_argument("--postfix", dest="postfix", default='', help="Postfix for the output file names (default: %(default)s)") parser.add_argument("--pyes", dest="pyes", default=False, action="store_true", help="Make files for plots") parser.add_argument("--jyes", dest="jyes", default=False, action="store_true", help="Make files for JES/JER plots") parser.add_argument("--pdir", dest="pdir", default='testarea', help="Name a directory for the plots (default: %(default)s)") parser.add_argument("--chi2", dest="chi2", default=False, action="store_true", help="Compute chi squared") parser.add_argument("--widefit", dest="widefit", default=False, action="store_true", help="Fit with wide bin hist") mass_group = parser.add_mutually_exclusive_group(required=True) mass_group.add_argument("--mass", type=int, nargs = '*', default = 1000, help="Mass can be specified as a single value or a whitespace separated list (default: %(default)i)" ) mass_group.add_argument("--massrange", type=int, nargs = 3, help="Define a range of masses to be produced. Format: min max step", metavar = ('MIN', 'MAX', 'STEP') ) mass_group.add_argument("--masslist", help = "List containing mass information" ) args = parser.parse_args() fit_functions = args.fit_functions.split(",") # mass points for which resonance shapes will be produced masses = [] if args.fitBonly: masses.append(750) else: if args.massrange != None: MIN, MAX, STEP = args.massrange masses = range(MIN, MAX+STEP, STEP) elif args.masslist != None: # A mass list was provided print "Will create mass list according to", args.masslist masslist = __import__(args.masslist.replace(".py","")) masses = masslist.masses else: masses = args.mass # sort masses masses.sort() # import ROOT stuff from ROOT import gStyle, TFile, TH1F, TH1D, TGraph, kTRUE, kFALSE, TCanvas, TLegend, TPad, TLine from ROOT import RooHist, RooRealVar, RooDataHist, RooArgList, RooArgSet, RooAddPdf, RooProdPdf, RooEffProd, RooFit, RooGenericPdf, RooWorkspace, RooMsgService, RooHistPdf, RooExtendPdf if not args.debug: RooMsgService.instance().setSilentMode(kTRUE) RooMsgService.instance().setStreamStatus(0,kFALSE) RooMsgService.instance().setStreamStatus(1,kFALSE) # input data file #inputData = TFile(limit_config.get_data_input(args.analysis)) # input data histogram #hData = inputData.Get(args.dataHistname) #hData.SetDirectory(0) data_file = TFile(analysis_config.get_b_histogram_filename(args.analysis, "BJetPlusX_2012")) hData = data_file.Get("BHistograms/h_pfjet_mjj") hData.SetDirectory(0) # input sig file if not args.fitSignal: print "[create_datacards] INFO : Opening resonance shapes file at " + limit_config.get_resonance_shapes(args.analysis, args.model) inputSig = TFile(limit_config.get_resonance_shapes(args.analysis, args.model), "READ") sqrtS = args.sqrtS # mass variable mjj = RooRealVar('mjj','mjj',float(args.massMin),float(args.massMax)) # integrated luminosity and signal cross section lumi = args.lumi signalCrossSection = 1. # set to 1. so that the limit on r can be interpreted as a limit on the signal cross section if args.correctTrigger: trigger_efficiency_pdf = trigger_efficiency.get_pdf(args.analysis, mjj) trigger_efficiency_formula = trigger_efficiency.get_formula(args.analysis, mjj) else: trigger_efficiency_pdf = trigger_efficiency.get_trivial_pdf(mjj) trigger_efficiency_formula = trigger_efficiency.get_trivial_formula(mjj) for mass in masses: print ">> Creating datacard and workspace for %s resonance with m = %i GeV..."%(args.final_state, int(mass)) rooDataHist = RooDataHist('rooDatahist','rooDathist',RooArgList(mjj),hData) if not args.fitSignal: hSig = inputSig.Get( "h_" + args.final_state + "_" + str(int(mass)) ) if not hSig: raise Exception("Couldn't find histogram " + "h_" + args.final_state + "_" + str(int(mass)) + " in file " + limit_config.get_resonance_shapes(args.analysis, args.model)) # normalize signal shape to the expected event yield (works even if input shapes are not normalized to unity) hSig.Scale(signalCrossSection*lumi/hSig.Integral()) # divide by a number that provides roughly an r value of 1-10 rooSigHist = RooDataHist('rooSigHist','rooSigHist',RooArgList(mjj),hSig) print 'Signal acceptance:', (rooSigHist.sumEntries()/hSig.Integral()) # If using fitted signal shapes, load the signal PDF if args.fitSignal: print "[create_datacards] Loading fitted signal PDFs from " + analysis_config.get_signal_fit_file(args.analysis, args.model, mass, "bukin", interpolated=(not mass in analysis_config.simulation.simulated_masses)) f_signal_pdfs = TFile(analysis_config.get_signal_fit_file(args.analysis, args.model, mass, "bukin", interpolated=(not mass in analysis_config.simulation.simulated_masses)), "READ") w_signal = f_signal_pdfs.Get("w_signal") input_parameters = signal_fits.get_parameters(w_signal.pdf("signal")) # Make a new PDF with nuisance parameters signal_pdf_notrig, signal_vars = signal_fits.make_signal_pdf_systematic("bukin", mjj, mass=mass) signal_pdf_name = signal_pdf_notrig.GetName() signal_pdf_notrig.SetName(signal_pdf_name + "_notrig") #signal_pdf = RooProdPdf(signal_pdf_name, signal_pdf_name, signal_pdf_notrig, trigger_efficiency_pdf) signal_pdf = RooEffProd(signal_pdf_name, signal_pdf_name, signal_pdf_notrig, trigger_efficiency_formula) # Copy input parameter values signal_vars["xp_0"].setVal(input_parameters["xp"][0]) signal_vars["xp_0"].setError(input_parameters["xp"][1]) signal_vars["xp_0"].setConstant() signal_vars["sigp_0"].setVal(input_parameters["sigp"][0]) signal_vars["sigp_0"].setError(input_parameters["sigp"][1]) signal_vars["sigp_0"].setConstant() signal_vars["xi_0"].setVal(input_parameters["xi"][0]) signal_vars["xi_0"].setError(input_parameters["xi"][1]) signal_vars["xi_0"].setConstant() signal_vars["rho1_0"].setVal(input_parameters["rho1"][0]) signal_vars["rho1_0"].setError(input_parameters["rho1"][1]) signal_vars["rho1_0"].setConstant() signal_vars["rho2_0"].setVal(input_parameters["rho2"][0]) signal_vars["rho2_0"].setError(input_parameters["rho2"][1]) signal_vars["rho2_0"].setConstant() f_signal_pdfs.Close() signal_parameters = {} signal_pdfs_notrig = {} signal_pdfs = {} signal_norms = {} background_pdfs = {} background_pdfs_notrig = {} background_parameters = {} background_norms = {} signal_epdfs = {} background_epdfs = {} models = {} fit_results = {} for fit_function in fit_functions: print "[create_datacards] INFO : On fit function {}".format(fit_function) if args.fitSignal: # Make a copy of the signal PDF, so that each fitTo call uses its own copy. # The copy should have all variables set constant. #signal_pdfs[fit_function], signal_parameters[fit_function] = signal_fits.copy_signal_pdf("bukin", signal_pdf, mjj, tag=fit_function, include_systematics=True) signal_pdfs_notrig[fit_function] = ROOT.RooBukinPdf(signal_pdf_notrig, signal_pdf_notrig.GetName() + "_" + fit_function) signal_pdfs[fit_function] = RooEffProd(signal_pdf.GetName() + "_" + fit_function, signal_pdf.GetName() + "_" + fit_function, signal_pdfs_notrig[fit_function], trigger_efficiency_formula) #signal_pdfs[fit_function] = RooProdPdf(signal_pdf.GetName() + "_" + fit_function, signal_pdf.GetName() + "_" + fit_function, signal_pdfs_notrig[fit_function], trigger_efficiency_pdf) iterator = signal_pdfs_notrig[fit_function].getVariables().createIterator() this_parameter = iterator.Next() while this_parameter: this_parameter.setConstant() this_parameter = iterator.Next() else: signal_pdfs[fit_function] = RooHistPdf('signal_' + fit_function,'signal_' + fit_function, RooArgSet(mjj), rooSigHist) signal_norms[fit_function] = RooRealVar('signal_norm_' + fit_function, 'signal_norm_' + fit_function, 0., 0., 1e+05) if args.fitBonly: signal_norms[fit_function].setConstant() background_pdfs_notrig[fit_function], background_parameters[fit_function] = make_background_pdf(fit_function, mjj, collision_energy=8000.) background_pdf_name = background_pdfs_notrig[fit_function].GetName() background_pdfs_notrig[fit_function].SetName(background_pdf_name + "_notrig") background_pdfs[fit_function] = RooEffProd(background_pdf_name, background_pdf_name, background_pdfs_notrig[fit_function], trigger_efficiency_formula) #background_pdfs[fit_function] = RooProdPdf(background_pdf_name, background_pdf_name, background_pdfs_notrig[fit_function], trigger_efficiency_pdf) #background_pdfs[fit_function] = background_pdfs_notrig[fit_function] #background_pdfs[fit_function].SetName(background_pdf_name) # Initial values if "trigbbh" in args.analysis: if fit_function == "f3": background_parameters[fit_function]["p1"].setVal(55.) background_parameters[fit_function]["p1"].setMin(20.) background_parameters[fit_function]["p2"].setVal(8.) elif fit_function == "f4": background_parameters[fit_function]["p1"].setVal(28.) background_parameters[fit_function]["p2"].setVal(-22.) background_parameters[fit_function]["p3"].setVal(10.) elif "trigbbl" in args.analysis: if fit_function == "f3": background_parameters[fit_function]["p1"].setVal(82.) background_parameters[fit_function]["p1"].setMin(60.) background_parameters[fit_function]["p2"].setVal(8.) elif fit_function == "f4": background_parameters[fit_function]["p1"].setVal(41.) background_parameters[fit_function]["p2"].setVal(-45.) background_parameters[fit_function]["p3"].setVal(10.) data_integral = hData.Integral(hData.GetXaxis().FindBin(float(args.massMin)),hData.GetXaxis().FindBin(float(args.massMax))) background_norms[fit_function] = RooRealVar('background_' + fit_function + '_norm', 'background_' + fit_function + '_norm', data_integral, 0., 1.e8) signal_epdfs[fit_function] = RooExtendPdf('esignal_' + fit_function, 'esignal_' + fit_function, signal_pdfs[fit_function], signal_norms[fit_function]) background_epdfs[fit_function] = RooExtendPdf('ebackground_' + fit_function, 'ebackground_' + fit_function, background_pdfs[fit_function], background_norms[fit_function]) models[fit_function] = RooAddPdf('model_' + fit_function, 's+b', RooArgList(background_epdfs[fit_function], signal_epdfs[fit_function])) if args.runFit: print "[create_datacards] INFO : Starting fit with function {}".format(fit_function) fit_results[fit_function] = models[fit_function].fitTo(rooDataHist, RooFit.Save(kTRUE), RooFit.Extended(kTRUE), RooFit.Strategy(args.fitStrategy), RooFit.Verbose(0)) print "[create_datacards] INFO : Done with fit {}. Printing results.".format(fit_function) fit_results[fit_function].Print() print "[create_datacards] DEBUG : End args.runFit if block." # needed if want to evaluate limits without background systematics if args.fixBkg: background_norms[fit_function].setConstant() for par_name, par in background_parameters[fit_function].iteritems(): par.setConstant() # ----------------------------------------- #signal_pdfs_syst = {} # JES and JER uncertainties if args.fitSignal: print "[create_datacards] INFO : Getting signal PDFs from " + analysis_config.get_signal_fit_file(args.analysis, args.model, mass, "bukin", interpolated=(not mass in analysis_config.simulation.simulated_masses)) f_signal_pdfs = TFile(analysis_config.get_signal_fit_file(args.analysis, args.model, mass, "bukin", interpolated=(not mass in analysis_config.simulation.simulated_masses))) w_signal = f_signal_pdfs.Get("w_signal") if "jes" in systematics: xp_central = signal_vars["xp_0"].getVal() #print w_signal.pdf("signal__JESUp") #print signal_fits.get_parameters(w_signal.pdf("signal__JESUp")) xp_up = signal_fits.get_parameters(w_signal.pdf("signal__JESUp"))["xpJESUp"][0] xp_down = signal_fits.get_parameters(w_signal.pdf("signal__JESDown"))["xpJESDown"][0] signal_vars["dxp"].setVal(max(abs(xp_up - xp_central), abs(xp_down - xp_central))) if signal_vars["dxp"].getVal() > 2 * mass * 0.1: print "[create_datacards] WARNING : Large dxp value. dxp = {}, xp_down = {}, xp_central = {}, xp_up = {}".format(signal_vars["dxp"].getVal(), xp_down, xp_central, xp_up) signal_vars["alpha_jes"].setVal(0.) signal_vars["alpha_jes"].setConstant(False) else: signal_vars["dxp"].setVal(0.) signal_vars["alpha_jes"].setVal(0.) signal_vars["alpha_jes"].setConstant() signal_vars["dxp"].setError(0.) signal_vars["dxp"].setConstant() if "jer" in systematics: sigp_central = signal_vars["sigp_0"].getVal() sigp_up = signal_fits.get_parameters(w_signal.pdf("signal__JERUp"))["sigpJERUp"][0] sigp_down = signal_fits.get_parameters(w_signal.pdf("signal__JERDown"))["sigpJERDown"][0] signal_vars["dsigp"].setVal(max(abs(sigp_up - sigp_central), abs(sigp_down - sigp_central))) signal_vars["alpha_jer"].setVal(0.) signal_vars["alpha_jer"].setConstant(False) else: signal_vars["dsigp"].setVal(0.) signal_vars["alpha_jer"].setVal(0.) signal_vars["alpha_jer"].setConstant() signal_vars["dsigp"].setError(0.) signal_vars["dsigp"].setConstant() #for variation in ["JERUp", "JERDown"]: # signal_pdfs_syst[variation] = w_signal.pdf("signal__" + variation) #for variation, pdf in signal_pdfs_syst.iteritems(): # signal_parameters = pdf.getVariables() # iter = signal_parameters.createIterator() # var = iter.Next() # while var: # var.setConstant() # var = iter.Next() f_signal_pdfs.Close() else: # dictionaries holding systematic variations of the signal shape hSig_Syst = {} hSig_Syst_DataHist = {} sigCDF = TGraph(hSig.GetNbinsX()+1) if "jes" in systematics or "jer" in systematics: sigCDF.SetPoint(0,0.,0.) integral = 0. for i in range(1, hSig.GetNbinsX()+1): x = hSig.GetXaxis().GetBinLowEdge(i+1) integral = integral + hSig.GetBinContent(i) sigCDF.SetPoint(i,x,integral) if "jes" in systematics: hSig_Syst['JESUp'] = copy.deepcopy(hSig) hSig_Syst['JESDown'] = copy.deepcopy(hSig) if "jer" in systematics: hSig_Syst['JERUp'] = copy.deepcopy(hSig) hSig_Syst['JERDown'] = copy.deepcopy(hSig) # reset signal histograms for key in hSig_Syst.keys(): hSig_Syst[key].Reset() hSig_Syst[key].SetName(hSig_Syst[key].GetName() + '_' + key) # produce JES signal shapes if "jes" in systematics: for i in range(1, hSig.GetNbinsX()+1): xLow = hSig.GetXaxis().GetBinLowEdge(i) xUp = hSig.GetXaxis().GetBinLowEdge(i+1) jes = 1. - systematics["jes"] xLowPrime = jes*xLow xUpPrime = jes*xUp hSig_Syst['JESUp'].SetBinContent(i, sigCDF.Eval(xUpPrime) - sigCDF.Eval(xLowPrime)) jes = 1. + systematics["jes"] xLowPrime = jes*xLow xUpPrime = jes*xUp hSig_Syst['JESDown'].SetBinContent(i, sigCDF.Eval(xUpPrime) - sigCDF.Eval(xLowPrime)) hSig_Syst_DataHist['JESUp'] = RooDataHist('hSig_JESUp','hSig_JESUp',RooArgList(mjj),hSig_Syst['JESUp']) hSig_Syst_DataHist['JESDown'] = RooDataHist('hSig_JESDown','hSig_JESDown',RooArgList(mjj),hSig_Syst['JESDown']) # produce JER signal shapes if "jer" in systematics: for i in range(1, hSig.GetNbinsX()+1): xLow = hSig.GetXaxis().GetBinLowEdge(i) xUp = hSig.GetXaxis().GetBinLowEdge(i+1) jer = 1. - systematics["jer"] xLowPrime = jer*(xLow-float(mass))+float(mass) xUpPrime = jer*(xUp-float(mass))+float(mass) hSig_Syst['JERUp'].SetBinContent(i, sigCDF.Eval(xUpPrime) - sigCDF.Eval(xLowPrime)) jer = 1. + systematics["jer"] xLowPrime = jer*(xLow-float(mass))+float(mass) xUpPrime = jer*(xUp-float(mass))+float(mass) hSig_Syst['JERDown'].SetBinContent(i, sigCDF.Eval(xUpPrime) - sigCDF.Eval(xLowPrime)) hSig_Syst_DataHist['JERUp'] = RooDataHist('hSig_JERUp','hSig_JERUp',RooArgList(mjj),hSig_Syst['JERUp']) hSig_Syst_DataHist['JERDown'] = RooDataHist('hSig_JERDown','hSig_JERDown',RooArgList(mjj),hSig_Syst['JERDown']) # ----------------------------------------- # create a datacard and corresponding workspace postfix = (('_' + args.postfix) if args.postfix != '' else '') wsName = 'workspace_' + args.final_state + '_m' + str(mass) + postfix + '.root' w = RooWorkspace('w','workspace') if args.fitSignal: signal_pdf.SetName("signal") getattr(w,'import')(signal_pdf,RooFit.Rename("signal")) # Create a norm variable "signal_norm" which normalizes the PDF to unity. norm = args.lumi #signal_norm = ROOT.RooRealVar("signal_norm", "signal_norm", 1. / norm, 0.1 / norm, 10. / norm) #if args.analysis == "trigbbh_CSVTM" and mass >= 1100: signal_norm = ROOT.RooRealVar("signal_norm", "signal_norm", norm/100., norm/100. / 10., norm * 10.) #else: # signal_norm = ROOT.RooRealVar("signal_norm", "signal_norm", norm, norm / 10., norm * 10.) print "[create_datacards] INFO : Set signal norm to {}".format(signal_norm.getVal()) signal_norm.setConstant() getattr(w,'import')(signal_norm,ROOT.RooCmdArg()) #if "jes" in systematics: # getattr(w,'import')(signal_pdfs_syst['JESUp'],RooFit.Rename("signal__JESUp")) # getattr(w,'import')(signal_pdfs_syst['JESDown'],RooFit.Rename("signal__JESDown")) #if "jer" in systematics: # getattr(w,'import')(signal_pdfs_syst['JERUp'],RooFit.Rename("signal__JERUp")) # getattr(w,'import')(signal_pdfs_syst['JERDown'],RooFit.Rename("signal__JERDown")) else: getattr(w,'import')(rooSigHist,RooFit.Rename("signal")) if "jes" in systematics: getattr(w,'import')(hSig_Syst_DataHist['JESUp'],RooFit.Rename("signal__JESUp")) getattr(w,'import')(hSig_Syst_DataHist['JESDown'],RooFit.Rename("signal__JESDown")) if "jer" in systematics: getattr(w,'import')(hSig_Syst_DataHist['JERUp'],RooFit.Rename("signal__JERUp")) getattr(w,'import')(hSig_Syst_DataHist['JERDown'],RooFit.Rename("signal__JERDown")) if args.decoBkg: getattr(w,'import')(background_deco,ROOT.RooCmdArg()) else: for fit_function in fit_functions: print "Importing background PDF" print background_pdfs[fit_function] background_pdfs[fit_function].Print() getattr(w,'import')(background_pdfs[fit_function],ROOT.RooCmdArg(),RooFit.Rename("background_" + fit_function), RooFit.RecycleConflictNodes()) w.pdf("background_" + fit_function).Print() getattr(w,'import')(background_norms[fit_function],ROOT.RooCmdArg(),RooFit.Rename("background_" + fit_function + "_norm")) getattr(w,'import')(fit_results[fit_function]) getattr(w,'import')(signal_norms[fit_function],ROOT.RooCmdArg()) if args.fitBonly: getattr(w,'import')(models[fit_function],ROOT.RooCmdArg(),RooFit.RecycleConflictNodes()) getattr(w,'import')(rooDataHist,RooFit.Rename("data_obs")) w.Print() print "Starting save" if args.output_path: if not os.path.isdir( os.path.join(os.getcwd(),args.output_path) ): os.mkdir( os.path.join(os.getcwd(),args.output_path) ) print "[create_datacards] INFO : Writing workspace to file {}".format(os.path.join(args.output_path,wsName)) w.writeToFile(os.path.join(args.output_path,wsName)) else: print "[create_datacards] INFO : Writing workspace to file {}".format(limit_config.get_workspace_filename(args.analysis, args.model, mass, fitBonly=args.fitBonly, fitSignal=args.fitSignal, correctTrigger=args.correctTrigger)) w.writeToFile(limit_config.get_workspace_filename(args.analysis, args.model, mass, fitBonly=args.fitBonly, fitSignal=args.fitSignal, correctTrigger=args.correctTrigger)) # Clean up for name, obj in signal_norms.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in background_pdfs.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in background_pdfs_notrig.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in background_norms.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in signal_pdfs.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in signal_pdfs_notrig.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in signal_epdfs.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in background_epdfs.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in fit_results.iteritems(): if obj: obj.IsA().Destructor(obj) for name, dict_l2 in background_parameters.iteritems(): for name2, obj in dict_l2.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in models.iteritems(): if obj: obj.IsA().Destructor(obj) rooDataHist.IsA().Destructor(rooDataHist) w.IsA().Destructor(w) # Make datacards only if S+B fitted if not args.fitBonly: beffUnc = 0.3 boffUnc = 0.06 for fit_function in fit_functions: if args.output_path: dcName = 'datacard_' + args.final_state + '_m' + str(mass) + postfix + '_' + fit_function + '.txt' print "[create_datacards] INFO : Writing datacard to file {}".format(os.path.join(args.output_path,dcName)) datacard = open(os.path.join(args.output_path,dcName),'w') else: print "[create_datacards] INFO : Writing datacard to file {}".format(limit_config.get_datacard_filename(args.analysis, args.model, mass, fit_function, fitSignal=args.fitSignal, correctTrigger=args.correctTrigger)) datacard = open(limit_config.get_datacard_filename(args.analysis, args.model, mass, fit_function, fitSignal=args.fitSignal, correctTrigger=args.correctTrigger), 'w') datacard.write('imax 1\n') datacard.write('jmax 1\n') datacard.write('kmax *\n') datacard.write('---------------\n') if ("jes" in systematics or "jer" in systematics) and not args.fitSignal: if args.output_path: datacard.write('shapes * * '+wsName+' w:$PROCESS w:$PROCESS__$SYSTEMATIC\n') else: datacard.write('shapes * * '+os.path.basename(limit_config.get_workspace_filename(args.analysis, args.model, mass, fitSignal=args.fitSignal, correctTrigger=args.correctTrigger))+' w:$PROCESS w:$PROCESS__$SYSTEMATIC\n') else: if args.output_path: datacard.write('shapes * * '+wsName+' w:$PROCESS\n') else: datacard.write('shapes * * '+os.path.basename(limit_config.get_workspace_filename(args.analysis, args.model, mass, fitSignal=args.fitSignal, correctTrigger=args.correctTrigger))+' w:$PROCESS\n') datacard.write('---------------\n') datacard.write('bin 1\n') datacard.write('observation -1\n') datacard.write('------------------------------\n') datacard.write('bin 1 1\n') datacard.write('process signal background_' + fit_function + '\n') datacard.write('process 0 1\n') if args.fitSignal: datacard.write('rate 1 1\n') else: datacard.write('rate -1 1\n') datacard.write('------------------------------\n') datacard.write('lumi lnN %f -\n'%(1.+systematics["luminosity"])) datacard.write('beff lnN %f -\n'%(1.+beffUnc)) datacard.write('boff lnN %f -\n'%(1.+boffUnc)) #datacard.write('bkg lnN - 1.03\n') if args.fitSignal: if "jes" in systematics: datacard.write("alpha_jes param 0.0 1.0\n") if "jer" in systematics: datacard.write("alpha_jer param 0.0 1.0\n") else: if "jes" in systematics: datacard.write('JES shape 1 -\n') if "jer" in systematics: datacard.write('JER shape 1 -\n') # flat parameters --- flat prior datacard.write('background_' + fit_function + '_norm flatParam\n') if args.decoBkg: datacard.write('deco_eig1 flatParam\n') datacard.write('deco_eig2 flatParam\n') else: for par_name, par in background_parameters[fit_function].iteritems(): datacard.write(fit_function + "_" + par_name + ' flatParam\n') datacard.close() print "[create_datacards] INFO : Done with this datacard" #print '>> Datacards and workspaces created and stored in %s/'%( os.path.join(os.getcwd(),args.output_path) ) print "All done."
fit_functions = ["dijet4"] #gen_functions = ["f1", "f2", "f4", "f5"] #fit_functions = ["f1"] for mass in masses[analysis]: names = [] gen_datacards = {} fit_datacards = {} gen_workspaces = {} fit_workspaces = {} top_name = model + "_" + analysis + "/m" + str(mass) + "_mu" + str(args.mu) job_names = [] for f_gen in gen_functions: for f_fit in fit_functions: name = model + "_" + analysis + "_m" + str(mass) + "_gen_" + f_gen + "_fit_" + f_fit + "_mu" + str(args.mu) job_names.append(name) gen_datacards[name] = limit_config.get_datacard_filename(analysis, model, mass, f_gen, correctTrigger=False, useMCTrigger=False, qcd=False, fitTrigger=True, fitBonly=False) gen_workspaces[name] = limit_config.get_workspace_filename(analysis, model, mass, correctTrigger=False, useMCTrigger=False, qcd=False, fitTrigger=True, fitBonly=False) fit_datacards[name] = limit_config.get_datacard_filename(analysis, model, mass, f_fit, correctTrigger=False, useMCTrigger=False, qcd=False, fitTrigger=True, fitBonly=False) fit_workspaces[name] = limit_config.get_workspace_filename(analysis, model, mass, correctTrigger=False, useMCTrigger=False, qcd=False, fitTrigger=True, fitBonly=False) #gen_datacards[name] = datacard_folders[model][analysis] + "/datacard_qq_m" + str(mass) + "_" + f_gen + ".txt" #gen_workspaces[name] = datacard_folders[model][analysis] + "/workspace_qq_m" + str(mass) + ".root" #fit_datacards[name] = datacard_folders[model][analysis] + "/datacard_qq_m" + str(mass) + "_" + f_fit + ".txt" #fit_workspaces[name] = datacard_folders[model][analysis] + "/workspace_qq_m" + str(mass) + ".root" run_many_bias_studies(top_name, job_names, gen_datacards=gen_datacards, fit_datacards=fit_datacards, gen_workspaces=gen_workspaces, fit_workspaces=fit_workspaces, n_toys=args.n_toys, mu=job_mu_values[model][analysis][mass], dry_run=args.dry_run) if args.retry: for model in models: for analysis in analyses: for mass in masses[analysis]: names = [] gen_datacards = {}
def main(): # input parameters parser = ArgumentParser( description= 'Script that runs limit calculation for specified mass points') parser.add_argument("-M", "--method", dest="method", required=True, choices=[ 'MaxLikelihoodFit', 'ProfileLikelihood', 'HybridNew', 'Asymptotic', 'MarkovChainMC' ], help="Method to calculate upper limits", metavar="METHOD") parser.add_argument('--analyses', type=str, default="trigbbh_CSVTM,trigbbl_CSVTM", help="Analysis names") parser.add_argument('--models', type=str, default="Hbb,RSG,ZPrime", help="Model names") parser.add_argument( '--qcd', action='store_true', help="Use QCD instead of data (assumes no trigger emulation)") parser.add_argument( '--correctTrigger', action='store_true', help= "Use model with trigger correction (has to have been specified in create_datacards.py)" ) parser.add_argument('--useMCTrigger', action='store_true', help="Use MC trigger") parser.add_argument( '--fitTrigger', action='store_true', help= "Use model with trigger fit (has to have been specified in create_datacards.py)" ) parser.add_argument( '--fitOffB', action='store_true', help= "Include a parametrization of offline b-tag efficiency in background PDF" ) parser.add_argument('--fit_function', type=str, default="f4", help="Name of central fit function") #parser.add_argument("-d", "--datacards_path", dest="datacards_path", required=True, # help="Path to datacards and workspaces", # metavar="DATA_HISTNAME") #parser.add_argument("-f", "--final_state", dest="final_state", required=True, # help="Final state (e.g. qq, qg, gg)", # metavar="FINAL_STATE") #parser.add_argument("-o", "--output_path", dest="output_path", # default='logs', # help="Output path where log files will be stored (default: %(default)s)", # metavar="OUTPUT_PATH") parser.add_argument("--rMin", dest="rMin", type=float, help="Minimum value for the signal strength") parser.add_argument("--rMax", dest="rMax", type=float, help="Maximum value for the signal strength") parser.add_argument( "--rPrior", action="store_true", help="Take rMin and rMax from a previous iteration of limit setting.") parser.add_argument("--rRelAcc", dest="rRelAcc", type=float, help="rRelAcc") parser.add_argument("--rAbsAcc", dest="rAbsAcc", type=float, help="rAbsAcc") parser.add_argument("--level", dest="level", type=float, help="Exp from grid level") parser.add_argument("--toysH", dest="toysH", type=int, help="Number of Toy MC extractions for HybridNew") parser.add_argument("--toys", dest="toys", type=int, help="Number of Toy MC extractions, not for HybridNew") parser.add_argument( "--tries", dest="tries", type=int, default=10, help="Number of times to run the MCMC (default: %(default)i)") parser.add_argument("--robustFit", dest="robustFit", action='store_true', help="combine robustFit option") parser.add_argument( "--proposal", dest="proposal", default='ortho', help="Proposal function for MCMC (default: %(default)s)") parser.add_argument("--noSyst", dest="noSyst", default=False, action="store_true", help="Run without systematic uncertainties") parser.add_argument("--picky", dest="picky", default=False, action="store_true", help="combine picky mode") parser.add_argument("--saveHybridResult", action="store_true", help="--saveHybridResult") parser.add_argument("--strictBounds", dest="strictBounds", default=False, action="store_true", help="Strict bounds on rMax") parser.add_argument( "--testStat", type=str, help= "Test statistics: LEP, TEV, LHC (previously known as Atlas), Profile.") parser.add_argument("--freezeNuisances", dest="freezeNuisances", type=str, help="Freeze nuisance parameters") parser.add_argument("--noHint", dest="noHint", default=False, action="store_true", help="Do not run the hint method") parser.add_argument("--significance", dest="significance", default=False, action="store_true", help="Calculate significance instead of limits") parser.add_argument("--frequentist", dest="freq", default=False, action="store_true", help="Frequentist hybridnew") parser.add_argument("--fork", dest="forkvar", default=False, action="store_true", help="More cores") parser.add_argument("--fitStrategy", dest="fitStrategy", type=int, help="Fit strategy (default: %(default).1f)") parser.add_argument("--condor", dest="condor", default=False, action="store_true", help="Batch process using Condor") parser.add_argument( "--no_retar", dest='no_retar', action="store_true", help= "If --condor is specified, this specifies no retar of src directory (use cached copy)" ) parser.add_argument( "--postfix", dest="postfix", default='', help= "Postfix for the input and output file names (default: %(default)s)") parser.add_argument("--hnsig", dest="hnsig", default=False, action="store_true", help="HybridNew Significance calc") parser.add_argument("--hnsig2", dest="hnsig2", default=False, action="store_true", help="HybridNew Significance calc") parser.add_argument("--minimizerTolerance", dest="minimizerTolerance", type=float, help="--minimizerTolerance option for combine") parser.add_argument("--minimizerAlgoForMinos", dest="minimizerAlgoForMinos", type=str, help="--minimizerAlgoForMinos option for combine") parser.add_argument("--minimizerToleranceForMinos", dest="minimizerToleranceForMinos", type=float, help="--minimizerToleranceForMinos option for combine") parser.add_argument('-v', '--verbose', type=int, help='Verbosity of combine') parser.add_argument( '-m', '--masses', type=str, help= 'Manually specify masses (comma-separated list). Otherwise, taken from limit_configuration.' ) parser.add_argument("--preFitValue", type=float, help="preFitValue option for combine") parser.add_argument("--fitBonly", action="store_true", help="Use workspace created with fitBonly option") #mass_group = parser.add_mutually_exclusive_group(required=True) #mass_group.add_argument("--mass", # type=int, # nargs = '*', # default = 1000, # help="Mass can be specified as a single value or a whitespace separated list (default: %(default)i)" # ) #mass_group.add_argument("--massrange", # type=int, # nargs = 3, # help="Define a range of masses to be produced. Format: min max step", # metavar = ('MIN', 'MAX', 'STEP') # ) #mass_group.add_argument("--masslist", # help = "List containing mass information" # ) args = parser.parse_args() analyses = args.analyses.split(",") models = args.models.split(",") # check if the output directory exists #if not os.path.isdir( os.path.join(os.getcwd(), args.output_path) ): # os.mkdir( os.path.join(os.getcwd(), args.output_path) ) #print os.getcwd() # mass points for which resonance shapes will be produced #masses = [] #if args.massrange != None: # MIN, MAX, STEP = args.massrange # masses = range(MIN, MAX+STEP, STEP) #elif args.masslist != None: # # A mass list was provided # print "Will create mass list according to", args.masslist # masslist = __import__(args.masslist.replace(".py","")) # masses = masslist.masses #else: # masses = args.mass # ## sort masses #masses.sort() masses = {} if args.masses: for analysis in analyses: masses[analysis] = [int(x) for x in args.masses.split(",")] else: masses = limit_config.limit_signal_masses method = args.method if args.significance and method != 'ProfileLikelihood' and method != 'HybridNew': print "** ERROR: ** For significance calculation the ProfileLikelihood or HybridNew method has to be used. Aborting." sys.exit(1) options = '' if args.significance: options = options + ' --significance' if args.freq: options = options + ' --frequentist' if args.hnsig: options = options + ' --significance --saveToys --fullBToys --saveHybridResult -T 500 -i 100 -s 123457' if args.hnsig2: options = options + ' --significance --readHybridResult --toysFile=input.root --expectedFromGrid=0.5' if args.forkvar: options = options + ' --fork 4' if args.testStat: options = options + ' --testStat ' + args.testStat if args.level != None: options = options + ' --expectedFromGrid=%f' % (args.level) if args.fitStrategy: options = options + ' --minimizerStrategy %i' % (args.fitStrategy) if args.noSyst: options = options + ' --systematics 0' if args.freezeNuisances: options = options + ' --freezeNuisances ' + args.freezeNuisances if args.picky: options = options + ' --picky ' if args.saveHybridResult: options = options + " -- saveHybridResult " if args.strictBounds: options = options + ' --strictBounds ' if args.rAbsAcc: options = options + " --rAbsAcc " + str(args.rAbsAcc) + " " if args.rRelAcc: options = options + " --rRelAcc " + str(args.rRelAcc) + " " if args.verbose: options = options + ' -v' + str(args.verbose) if method != 'ProfileLikelihood' and method != 'MaxLikelihoodFit' and args.rMax == None and not args.noHint and not args.significance: options = options + ' --hintMethod ProfileLikelihood' if method == 'HybridNew' and args.toysH != None: options = options + ' --toysH %i' % (args.toysH) if args.toys: options = options + ' --toys ' + str(args.toys) if args.robustFit: options = options + ' --robustFit 1' if args.minimizerTolerance: options += " --minimizerTolerance " + str( args.minimizerTolerance) + " " if args.minimizerAlgoForMinos: options += " --minimizerAlgoForMinos " + str( args.minimizerAlgoForMinos) + " " if args.minimizerToleranceForMinos: options += " --minimizerToleranceForMinos " + str( args.minimizerToleranceForMinos) + " " if args.preFitValue: options += " --preFitValue " + str(args.preFitValue) + " " if args.rPrior: # Take rMin and rMax from +/-2 sigma estimates from a previous iteration. This has to be done per-job, so do it later. pass else: if args.rMin != None: options = options + ' --rMin %f' % (args.rMin) if args.rMax != None: options = options + ' --rMax %f' % (args.rMax) if method == 'MarkovChainMC': options = options + ' --tries %i --proposal %s' % (args.tries, args.proposal) prefix = 'limits' if args.significance: prefix = 'significance' elif method == 'MaxLikelihoodFit': prefix = 'signal_xs' postfix = (('_' + args.postfix) if args.postfix != '' else '') if args.noSyst: postfix += "_noSyst" if args.freezeNuisances: postfix += "_" + args.freezeNuisances.replace(",", "_") if args.fitTrigger: postfix += "_fitTrigger" if args.correctTrigger: postfix += "_correctTrigger" if args.useMCTrigger: postfix += "_useMCTrigger" if args.fitOffB: postfix += "_fitOffB" if args.qcd: postfix += "_qcd" if args.fitBonly: postfix += "_fitBonly" datacards_path = limit_config.paths["datacards"] output_path = limit_config.paths["combine_logs"] condor_path = limit_config.paths["condor"] # change to the appropriate directory if args.condor: os.chdir(output_path) else: os.chdir(datacards_path) first = True for analysis in analyses: for model in models: for mass in masses[analysis]: logName = '{}_{}_{}_{}_m{}{}_{}.log'.format( prefix, method, analysis, model, int(mass), postfix, args.fit_function) job_name = "%s_%s_m%i%s_%s" % (analysis, model, int(mass), postfix, args.fit_function) run_options = options + ' --name _%s_%s_m%i%s_%s --mass %i' % ( analysis, model, int(mass), postfix, args.fit_function, int(mass)) if args.rPrior: run_options += " --rMin " + str( limit_config.limit_m2sigma_estimates[analysis][model] [mass] / 5. * 100.) run_options += " --rMax " + str( limit_config.limit_p2sigma_estimates[analysis][model] [mass] * 5. * 100.) if method == "MaxLikelihoodFit": # Save shapes and plots run_options += " --saveWithUncertainties --saveShapes --plots --out plots_" + job_name if args.condor: cmd = "combine -M %s %s %s 2>&1 | tee %s" % ( method, run_options, os.path.basename( limit_config.get_datacard_filename( analysis, model, mass, args.fit_function, correctTrigger=args.correctTrigger, useMCTrigger=args.useMCTrigger, qcd=args.qcd, fitTrigger=args.fitTrigger, fitBonly=args.fitBonly, fitOffB=args.fitOffB)), os.path.basename( os.path.join(('' if args.condor else output_path), logName))) else: cmd = "combine -M %s %s %s 2>&1 | tee %s" % ( method, run_options, limit_config.get_datacard_filename( analysis, model, mass, args.fit_function, correctTrigger=args.correctTrigger, useMCTrigger=args.useMCTrigger, qcd=args.qcd, fitTrigger=args.fitTrigger, fitBonly=args.fitBonly, fitOffB=args.fitOffB), os.path.join( ('' if args.condor else output_path), logName)) # if using Condor if args.condor: #submission_dir = limit_config.paths["condor"] submission_dir = limit_config.paths["combine_logs"] start_dir = os.getcwd() os.chdir(submission_dir) # create the executable script bash_script_path = os.path.join( submission_dir, 'run_%s_%s_%s_m%i%s.sh' % (method, analysis, model, int(mass), postfix)) #bash_content = bash_template #bash_content = re.sub('DUMMY_CMD',cmd,bash_content) bash_script = open(bash_script_path, 'w') bash_script.write("echo '" + cmd + "'\n") if method == "MaxLikelihoodFit": bash_script.write("mkdir -pv plots_" + job_name + "\n") bash_script.write(cmd) bash_script.close() # Create the condor command condor_command = "csub " + bash_script_path files_to_transfer = [] files_to_transfer.append(bash_script_path) files_to_transfer.append( limit_config.get_datacard_filename( analysis, model, mass, args.fit_function, correctTrigger=args.correctTrigger, useMCTrigger=args.useMCTrigger, qcd=args.qcd, fitTrigger=args.fitTrigger, fitBonly=args.fitBonly, fitOffB=args.fitOffB)) files_to_transfer.append( limit_config.get_workspace_filename( analysis, model, mass, correctTrigger=args.correctTrigger, useMCTrigger=args.useMCTrigger, qcd=args.qcd, fitTrigger=args.fitTrigger, fitBonly=args.fitBonly, fitOffB=args.fitOffB)) condor_command += " -F " + ",".join(files_to_transfer) condor_command += " -l combine_{}_\$\(Cluster\)_\$\(Process\).log".format( logName) condor_command += " -s submit_combine_{}_{}_{}.jdl".format( analysis, model, mass) condor_command += " -d " + submission_dir if method == "MaxLikelihoodFit": condor_command += " -o plots_" + job_name + " " condor_command += " --cmssw" if not first or args.no_retar: condor_command += " --no_retar " print ">> Submitting job for %s %s resonance with m = %i GeV..." % ( analysis, model, int(mass)) print "Submission command: " print condor_command os.system(condor_command) print "---------------------------------------------------------------------------" os.chdir(start_dir) else: print ">> Running combine for %s %s resonance with m = %i GeV..." % ( analysis, model, int(mass)) print "---------------------------------------------------------------------------" if method == "MaxLikelihoodFit": os.system("mkdir -pv plots_" + job_name) print "Running: " + cmd + "\n" os.system(cmd) if first: first = False
def main(): # usage description usage = "Example: ./scripts/createDatacards.py --inputData inputs/rawhistV7_Run2015D_scoutingPFHT_UNBLINDED_649_838_JEC_HLTplusV7_Mjj_cor_smooth.root --dataHistname mjj_mjjcor_gev --inputSig inputs/ResonanceShapes_gg_13TeV_Scouting_Spring15.root -f gg -o datacards -l 1866 --lumiUnc 0.027 --massrange 1000 1500 50 --runFit --p1 5 --p2 7 --p3 0.4 --massMin 838 --massMax 2037 --fitStrategy 2" # input parameters parser = ArgumentParser( description= 'Script that creates combine datacards and corresponding RooFit workspaces', epilog=usage) parser.add_argument("analysis", type=str, help="Analysis name") parser.add_argument("model", type=str, help="Model (Hbb, RSG)") #parser.add_argument("--inputData", dest="inputData", required=True, # help="Input data spectrum", # metavar="INPUT_DATA") parser.add_argument("--dataHistname", dest="dataHistname", type=str, default="h_data", help="Data histogram name", metavar="DATA_HISTNAME") #parser.add_argument("--inputSig", dest="inputSig", required=True, # help="Input signal shapes", # metavar="INPUT_SIGNAL") parser.add_argument("-f", "--final_state", dest="final_state", default="qq", help="Final state (e.g. qq, qg, gg)", metavar="FINAL_STATE") parser.add_argument("--fit_functions", dest="fit_functions", default="f1,f2,f3,f4,f5", help="List of fit functions") #parser.add_argument("-f2", "--type", dest="atype", required=True, help="Type (e.g. hG, lG, hR, lR)") parser.add_argument( "-o", "--output_path", dest="output_path", help= "Output path where datacards and workspaces will be stored. If not specified, this is derived from limit_configuration.", metavar="OUTPUT_PATH") parser.add_argument("--correctTrigger", dest="correctTrigger", action='store_true', help="Include trigger correction in PDF") parser.add_argument( "-l", "--lumi", dest="lumi", default=19700., type=float, help="Integrated luminosity in pb-1 (default: %(default).1f)", metavar="LUMI") parser.add_argument( "--massMin", dest="massMin", default=500, type=int, help= "Lower bound of the mass range used for fitting (default: %(default)s)", metavar="MASS_MIN") parser.add_argument( "--massMax", dest="massMax", default=1200, type=int, help= "Upper bound of the mass range used for fitting (default: %(default)s)", metavar="MASS_MAX") parser.add_argument( "--fitSignal", action="store_true", help= "Use signal fitted shapes (CB+Voigtian) instead of histogram templates" ) #parser.add_argument("--lumiUnc", dest="lumiUnc", # required=True, type=float, # help="Relative uncertainty in the integrated luminosity", # metavar="LUMI_UNC") #parser.add_argument("--jesUnc", dest="jesUnc", # type=float, # help="Relative uncertainty in the jet energy scale", # metavar="JES_UNC") #parser.add_argument("--jerUnc", dest="jerUnc", # type=float, # help="Relative uncertainty in the jet energy resolution", # metavar="JER_UNC") parser.add_argument( "--sqrtS", dest="sqrtS", default=8000., type=float, help="Collision center-of-mass energy (default: %(default).1f)", metavar="SQRTS") parser.add_argument("--fixP3", dest="fixP3", default=False, action="store_true", help="Fix the fit function p3 parameter") parser.add_argument("--runFit", dest="runFit", default=False, action="store_true", help="Run the fit") parser.add_argument("--fitBonly", dest="fitBonly", default=False, action="store_true", help="Run B-only fit") parser.add_argument("--fixBkg", dest="fixBkg", default=False, action="store_true", help="Fix all background parameters") parser.add_argument("--decoBkg", dest="decoBkg", default=False, action="store_true", help="Decorrelate background parameters") parser.add_argument("--fitStrategy", dest="fitStrategy", type=int, default=1, help="Fit strategy (default: %(default).1f)") parser.add_argument("--debug", dest="debug", default=False, action="store_true", help="Debug printout") parser.add_argument( "--postfix", dest="postfix", default='', help="Postfix for the output file names (default: %(default)s)") parser.add_argument("--pyes", dest="pyes", default=False, action="store_true", help="Make files for plots") parser.add_argument("--jyes", dest="jyes", default=False, action="store_true", help="Make files for JES/JER plots") parser.add_argument( "--pdir", dest="pdir", default='testarea', help="Name a directory for the plots (default: %(default)s)") parser.add_argument("--chi2", dest="chi2", default=False, action="store_true", help="Compute chi squared") parser.add_argument("--widefit", dest="widefit", default=False, action="store_true", help="Fit with wide bin hist") mass_group = parser.add_mutually_exclusive_group(required=True) mass_group.add_argument( "--mass", type=int, nargs='*', default=1000, help= "Mass can be specified as a single value or a whitespace separated list (default: %(default)i)" ) mass_group.add_argument( "--massrange", type=int, nargs=3, help="Define a range of masses to be produced. Format: min max step", metavar=('MIN', 'MAX', 'STEP')) mass_group.add_argument("--masslist", help="List containing mass information") args = parser.parse_args() fit_functions = args.fit_functions.split(",") # mass points for which resonance shapes will be produced masses = [] if args.fitBonly: masses.append(750) else: if args.massrange != None: MIN, MAX, STEP = args.massrange masses = range(MIN, MAX + STEP, STEP) elif args.masslist != None: # A mass list was provided print "Will create mass list according to", args.masslist masslist = __import__(args.masslist.replace(".py", "")) masses = masslist.masses else: masses = args.mass # sort masses masses.sort() # import ROOT stuff from ROOT import gStyle, TFile, TH1F, TH1D, TGraph, kTRUE, kFALSE, TCanvas, TLegend, TPad, TLine from ROOT import RooHist, RooRealVar, RooDataHist, RooArgList, RooArgSet, RooAddPdf, RooProdPdf, RooEffProd, RooFit, RooGenericPdf, RooWorkspace, RooMsgService, RooHistPdf, RooExtendPdf if not args.debug: RooMsgService.instance().setSilentMode(kTRUE) RooMsgService.instance().setStreamStatus(0, kFALSE) RooMsgService.instance().setStreamStatus(1, kFALSE) # input data file #inputData = TFile(limit_config.get_data_input(args.analysis)) # input data histogram #hData = inputData.Get(args.dataHistname) #hData.SetDirectory(0) data_file = TFile( analysis_config.get_b_histogram_filename(args.analysis, "BJetPlusX_2012")) hData = data_file.Get("BHistograms/h_pfjet_mjj") hData.SetDirectory(0) # input sig file if not args.fitSignal: print "[create_datacards] INFO : Opening resonance shapes file at " + limit_config.get_resonance_shapes( args.analysis, args.model) inputSig = TFile( limit_config.get_resonance_shapes(args.analysis, args.model), "READ") sqrtS = args.sqrtS # mass variable mjj = RooRealVar('mjj', 'mjj', float(args.massMin), float(args.massMax)) # integrated luminosity and signal cross section lumi = args.lumi signalCrossSection = 1. # set to 1. so that the limit on r can be interpreted as a limit on the signal cross section if args.correctTrigger: trigger_efficiency_pdf = trigger_efficiency.get_pdf(args.analysis, mjj) trigger_efficiency_formula = trigger_efficiency.get_formula( args.analysis, mjj) else: trigger_efficiency_pdf = trigger_efficiency.get_trivial_pdf(mjj) trigger_efficiency_formula = trigger_efficiency.get_trivial_formula( mjj) for mass in masses: print ">> Creating datacard and workspace for %s resonance with m = %i GeV..." % ( args.final_state, int(mass)) rooDataHist = RooDataHist('rooDatahist', 'rooDathist', RooArgList(mjj), hData) if not args.fitSignal: hSig = inputSig.Get("h_" + args.final_state + "_" + str(int(mass))) if not hSig: raise Exception("Couldn't find histogram " + "h_" + args.final_state + "_" + str(int(mass)) + " in file " + limit_config.get_resonance_shapes( args.analysis, args.model)) # normalize signal shape to the expected event yield (works even if input shapes are not normalized to unity) hSig.Scale( signalCrossSection * lumi / hSig.Integral() ) # divide by a number that provides roughly an r value of 1-10 rooSigHist = RooDataHist('rooSigHist', 'rooSigHist', RooArgList(mjj), hSig) print 'Signal acceptance:', (rooSigHist.sumEntries() / hSig.Integral()) # If using fitted signal shapes, load the signal PDF if args.fitSignal: print "[create_datacards] Loading fitted signal PDFs from " + analysis_config.get_signal_fit_file( args.analysis, args.model, mass, "bukin", interpolated=(not mass in analysis_config.simulation.simulated_masses)) f_signal_pdfs = TFile( analysis_config.get_signal_fit_file( args.analysis, args.model, mass, "bukin", interpolated=( not mass in analysis_config.simulation.simulated_masses)), "READ") w_signal = f_signal_pdfs.Get("w_signal") input_parameters = signal_fits.get_parameters( w_signal.pdf("signal")) # Make a new PDF with nuisance parameters signal_pdf_notrig, signal_vars = signal_fits.make_signal_pdf_systematic( "bukin", mjj, mass=mass) signal_pdf_name = signal_pdf_notrig.GetName() signal_pdf_notrig.SetName(signal_pdf_name + "_notrig") #signal_pdf = RooProdPdf(signal_pdf_name, signal_pdf_name, signal_pdf_notrig, trigger_efficiency_pdf) signal_pdf = RooEffProd(signal_pdf_name, signal_pdf_name, signal_pdf_notrig, trigger_efficiency_formula) # Copy input parameter values signal_vars["xp_0"].setVal(input_parameters["xp"][0]) signal_vars["xp_0"].setError(input_parameters["xp"][1]) signal_vars["xp_0"].setConstant() signal_vars["sigp_0"].setVal(input_parameters["sigp"][0]) signal_vars["sigp_0"].setError(input_parameters["sigp"][1]) signal_vars["sigp_0"].setConstant() signal_vars["xi_0"].setVal(input_parameters["xi"][0]) signal_vars["xi_0"].setError(input_parameters["xi"][1]) signal_vars["xi_0"].setConstant() signal_vars["rho1_0"].setVal(input_parameters["rho1"][0]) signal_vars["rho1_0"].setError(input_parameters["rho1"][1]) signal_vars["rho1_0"].setConstant() signal_vars["rho2_0"].setVal(input_parameters["rho2"][0]) signal_vars["rho2_0"].setError(input_parameters["rho2"][1]) signal_vars["rho2_0"].setConstant() f_signal_pdfs.Close() signal_parameters = {} signal_pdfs_notrig = {} signal_pdfs = {} signal_norms = {} background_pdfs = {} background_pdfs_notrig = {} background_parameters = {} background_norms = {} signal_epdfs = {} background_epdfs = {} models = {} fit_results = {} for fit_function in fit_functions: print "[create_datacards] INFO : On fit function {}".format( fit_function) if args.fitSignal: # Make a copy of the signal PDF, so that each fitTo call uses its own copy. # The copy should have all variables set constant. #signal_pdfs[fit_function], signal_parameters[fit_function] = signal_fits.copy_signal_pdf("bukin", signal_pdf, mjj, tag=fit_function, include_systematics=True) signal_pdfs_notrig[fit_function] = ROOT.RooBukinPdf( signal_pdf_notrig, signal_pdf_notrig.GetName() + "_" + fit_function) signal_pdfs[fit_function] = RooEffProd( signal_pdf.GetName() + "_" + fit_function, signal_pdf.GetName() + "_" + fit_function, signal_pdfs_notrig[fit_function], trigger_efficiency_formula) #signal_pdfs[fit_function] = RooProdPdf(signal_pdf.GetName() + "_" + fit_function, signal_pdf.GetName() + "_" + fit_function, signal_pdfs_notrig[fit_function], trigger_efficiency_pdf) iterator = signal_pdfs_notrig[fit_function].getVariables( ).createIterator() this_parameter = iterator.Next() while this_parameter: this_parameter.setConstant() this_parameter = iterator.Next() else: signal_pdfs[fit_function] = RooHistPdf( 'signal_' + fit_function, 'signal_' + fit_function, RooArgSet(mjj), rooSigHist) signal_norms[fit_function] = RooRealVar( 'signal_norm_' + fit_function, 'signal_norm_' + fit_function, 0., 0., 1e+05) if args.fitBonly: signal_norms[fit_function].setConstant() background_pdfs_notrig[fit_function], background_parameters[ fit_function] = make_background_pdf(fit_function, mjj, collision_energy=8000.) background_pdf_name = background_pdfs_notrig[fit_function].GetName( ) background_pdfs_notrig[fit_function].SetName(background_pdf_name + "_notrig") background_pdfs[fit_function] = RooEffProd( background_pdf_name, background_pdf_name, background_pdfs_notrig[fit_function], trigger_efficiency_formula) #background_pdfs[fit_function] = RooProdPdf(background_pdf_name, background_pdf_name, background_pdfs_notrig[fit_function], trigger_efficiency_pdf) #background_pdfs[fit_function] = background_pdfs_notrig[fit_function] #background_pdfs[fit_function].SetName(background_pdf_name) # Initial values if "trigbbh" in args.analysis: if fit_function == "f3": background_parameters[fit_function]["p1"].setVal(55.) background_parameters[fit_function]["p1"].setMin(20.) background_parameters[fit_function]["p2"].setVal(8.) elif fit_function == "f4": background_parameters[fit_function]["p1"].setVal(28.) background_parameters[fit_function]["p2"].setVal(-22.) background_parameters[fit_function]["p3"].setVal(10.) elif "trigbbl" in args.analysis: if fit_function == "f3": background_parameters[fit_function]["p1"].setVal(82.) background_parameters[fit_function]["p1"].setMin(60.) background_parameters[fit_function]["p2"].setVal(8.) elif fit_function == "f4": background_parameters[fit_function]["p1"].setVal(41.) background_parameters[fit_function]["p2"].setVal(-45.) background_parameters[fit_function]["p3"].setVal(10.) data_integral = hData.Integral( hData.GetXaxis().FindBin(float(args.massMin)), hData.GetXaxis().FindBin(float(args.massMax))) background_norms[fit_function] = RooRealVar( 'background_' + fit_function + '_norm', 'background_' + fit_function + '_norm', data_integral, 0., 1.e8) signal_epdfs[fit_function] = RooExtendPdf( 'esignal_' + fit_function, 'esignal_' + fit_function, signal_pdfs[fit_function], signal_norms[fit_function]) background_epdfs[fit_function] = RooExtendPdf( 'ebackground_' + fit_function, 'ebackground_' + fit_function, background_pdfs[fit_function], background_norms[fit_function]) models[fit_function] = RooAddPdf( 'model_' + fit_function, 's+b', RooArgList(background_epdfs[fit_function], signal_epdfs[fit_function])) if args.runFit: print "[create_datacards] INFO : Starting fit with function {}".format( fit_function) fit_results[fit_function] = models[fit_function].fitTo( rooDataHist, RooFit.Save(kTRUE), RooFit.Extended(kTRUE), RooFit.Strategy(args.fitStrategy), RooFit.Verbose(0)) print "[create_datacards] INFO : Done with fit {}. Printing results.".format( fit_function) fit_results[fit_function].Print() print "[create_datacards] DEBUG : End args.runFit if block." # needed if want to evaluate limits without background systematics if args.fixBkg: background_norms[fit_function].setConstant() for par_name, par in background_parameters[ fit_function].iteritems(): par.setConstant() # ----------------------------------------- #signal_pdfs_syst = {} # JES and JER uncertainties if args.fitSignal: print "[create_datacards] INFO : Getting signal PDFs from " + analysis_config.get_signal_fit_file( args.analysis, args.model, mass, "bukin", interpolated=(not mass in analysis_config.simulation.simulated_masses)) f_signal_pdfs = TFile( analysis_config.get_signal_fit_file( args.analysis, args.model, mass, "bukin", interpolated=( not mass in analysis_config.simulation.simulated_masses))) w_signal = f_signal_pdfs.Get("w_signal") if "jes" in systematics: xp_central = signal_vars["xp_0"].getVal() #print w_signal.pdf("signal__JESUp") #print signal_fits.get_parameters(w_signal.pdf("signal__JESUp")) xp_up = signal_fits.get_parameters( w_signal.pdf("signal__JESUp"))["xpJESUp"][0] xp_down = signal_fits.get_parameters( w_signal.pdf("signal__JESDown"))["xpJESDown"][0] signal_vars["dxp"].setVal( max(abs(xp_up - xp_central), abs(xp_down - xp_central))) if signal_vars["dxp"].getVal() > 2 * mass * 0.1: print "[create_datacards] WARNING : Large dxp value. dxp = {}, xp_down = {}, xp_central = {}, xp_up = {}".format( signal_vars["dxp"].getVal(), xp_down, xp_central, xp_up) signal_vars["alpha_jes"].setVal(0.) signal_vars["alpha_jes"].setConstant(False) else: signal_vars["dxp"].setVal(0.) signal_vars["alpha_jes"].setVal(0.) signal_vars["alpha_jes"].setConstant() signal_vars["dxp"].setError(0.) signal_vars["dxp"].setConstant() if "jer" in systematics: sigp_central = signal_vars["sigp_0"].getVal() sigp_up = signal_fits.get_parameters( w_signal.pdf("signal__JERUp"))["sigpJERUp"][0] sigp_down = signal_fits.get_parameters( w_signal.pdf("signal__JERDown"))["sigpJERDown"][0] signal_vars["dsigp"].setVal( max(abs(sigp_up - sigp_central), abs(sigp_down - sigp_central))) signal_vars["alpha_jer"].setVal(0.) signal_vars["alpha_jer"].setConstant(False) else: signal_vars["dsigp"].setVal(0.) signal_vars["alpha_jer"].setVal(0.) signal_vars["alpha_jer"].setConstant() signal_vars["dsigp"].setError(0.) signal_vars["dsigp"].setConstant() #for variation in ["JERUp", "JERDown"]: # signal_pdfs_syst[variation] = w_signal.pdf("signal__" + variation) #for variation, pdf in signal_pdfs_syst.iteritems(): # signal_parameters = pdf.getVariables() # iter = signal_parameters.createIterator() # var = iter.Next() # while var: # var.setConstant() # var = iter.Next() f_signal_pdfs.Close() else: # dictionaries holding systematic variations of the signal shape hSig_Syst = {} hSig_Syst_DataHist = {} sigCDF = TGraph(hSig.GetNbinsX() + 1) if "jes" in systematics or "jer" in systematics: sigCDF.SetPoint(0, 0., 0.) integral = 0. for i in range(1, hSig.GetNbinsX() + 1): x = hSig.GetXaxis().GetBinLowEdge(i + 1) integral = integral + hSig.GetBinContent(i) sigCDF.SetPoint(i, x, integral) if "jes" in systematics: hSig_Syst['JESUp'] = copy.deepcopy(hSig) hSig_Syst['JESDown'] = copy.deepcopy(hSig) if "jer" in systematics: hSig_Syst['JERUp'] = copy.deepcopy(hSig) hSig_Syst['JERDown'] = copy.deepcopy(hSig) # reset signal histograms for key in hSig_Syst.keys(): hSig_Syst[key].Reset() hSig_Syst[key].SetName(hSig_Syst[key].GetName() + '_' + key) # produce JES signal shapes if "jes" in systematics: for i in range(1, hSig.GetNbinsX() + 1): xLow = hSig.GetXaxis().GetBinLowEdge(i) xUp = hSig.GetXaxis().GetBinLowEdge(i + 1) jes = 1. - systematics["jes"] xLowPrime = jes * xLow xUpPrime = jes * xUp hSig_Syst['JESUp'].SetBinContent( i, sigCDF.Eval(xUpPrime) - sigCDF.Eval(xLowPrime)) jes = 1. + systematics["jes"] xLowPrime = jes * xLow xUpPrime = jes * xUp hSig_Syst['JESDown'].SetBinContent( i, sigCDF.Eval(xUpPrime) - sigCDF.Eval(xLowPrime)) hSig_Syst_DataHist['JESUp'] = RooDataHist( 'hSig_JESUp', 'hSig_JESUp', RooArgList(mjj), hSig_Syst['JESUp']) hSig_Syst_DataHist['JESDown'] = RooDataHist( 'hSig_JESDown', 'hSig_JESDown', RooArgList(mjj), hSig_Syst['JESDown']) # produce JER signal shapes if "jer" in systematics: for i in range(1, hSig.GetNbinsX() + 1): xLow = hSig.GetXaxis().GetBinLowEdge(i) xUp = hSig.GetXaxis().GetBinLowEdge(i + 1) jer = 1. - systematics["jer"] xLowPrime = jer * (xLow - float(mass)) + float(mass) xUpPrime = jer * (xUp - float(mass)) + float(mass) hSig_Syst['JERUp'].SetBinContent( i, sigCDF.Eval(xUpPrime) - sigCDF.Eval(xLowPrime)) jer = 1. + systematics["jer"] xLowPrime = jer * (xLow - float(mass)) + float(mass) xUpPrime = jer * (xUp - float(mass)) + float(mass) hSig_Syst['JERDown'].SetBinContent( i, sigCDF.Eval(xUpPrime) - sigCDF.Eval(xLowPrime)) hSig_Syst_DataHist['JERUp'] = RooDataHist( 'hSig_JERUp', 'hSig_JERUp', RooArgList(mjj), hSig_Syst['JERUp']) hSig_Syst_DataHist['JERDown'] = RooDataHist( 'hSig_JERDown', 'hSig_JERDown', RooArgList(mjj), hSig_Syst['JERDown']) # ----------------------------------------- # create a datacard and corresponding workspace postfix = (('_' + args.postfix) if args.postfix != '' else '') wsName = 'workspace_' + args.final_state + '_m' + str( mass) + postfix + '.root' w = RooWorkspace('w', 'workspace') if args.fitSignal: signal_pdf.SetName("signal") getattr(w, 'import')(signal_pdf, RooFit.Rename("signal")) # Create a norm variable "signal_norm" which normalizes the PDF to unity. norm = args.lumi #signal_norm = ROOT.RooRealVar("signal_norm", "signal_norm", 1. / norm, 0.1 / norm, 10. / norm) #if args.analysis == "trigbbh_CSVTM" and mass >= 1100: signal_norm = ROOT.RooRealVar("signal_norm", "signal_norm", norm / 100., norm / 100. / 10., norm * 10.) #else: # signal_norm = ROOT.RooRealVar("signal_norm", "signal_norm", norm, norm / 10., norm * 10.) print "[create_datacards] INFO : Set signal norm to {}".format( signal_norm.getVal()) signal_norm.setConstant() getattr(w, 'import')(signal_norm, ROOT.RooCmdArg()) #if "jes" in systematics: # getattr(w,'import')(signal_pdfs_syst['JESUp'],RooFit.Rename("signal__JESUp")) # getattr(w,'import')(signal_pdfs_syst['JESDown'],RooFit.Rename("signal__JESDown")) #if "jer" in systematics: # getattr(w,'import')(signal_pdfs_syst['JERUp'],RooFit.Rename("signal__JERUp")) # getattr(w,'import')(signal_pdfs_syst['JERDown'],RooFit.Rename("signal__JERDown")) else: getattr(w, 'import')(rooSigHist, RooFit.Rename("signal")) if "jes" in systematics: getattr(w, 'import')(hSig_Syst_DataHist['JESUp'], RooFit.Rename("signal__JESUp")) getattr(w, 'import')(hSig_Syst_DataHist['JESDown'], RooFit.Rename("signal__JESDown")) if "jer" in systematics: getattr(w, 'import')(hSig_Syst_DataHist['JERUp'], RooFit.Rename("signal__JERUp")) getattr(w, 'import')(hSig_Syst_DataHist['JERDown'], RooFit.Rename("signal__JERDown")) if args.decoBkg: getattr(w, 'import')(background_deco, ROOT.RooCmdArg()) else: for fit_function in fit_functions: print "Importing background PDF" print background_pdfs[fit_function] background_pdfs[fit_function].Print() getattr(w, 'import')(background_pdfs[fit_function], ROOT.RooCmdArg(), RooFit.Rename("background_" + fit_function), RooFit.RecycleConflictNodes()) w.pdf("background_" + fit_function).Print() getattr(w, 'import')(background_norms[fit_function], ROOT.RooCmdArg(), RooFit.Rename("background_" + fit_function + "_norm")) getattr(w, 'import')(fit_results[fit_function]) getattr(w, 'import')(signal_norms[fit_function], ROOT.RooCmdArg()) if args.fitBonly: getattr(w, 'import')(models[fit_function], ROOT.RooCmdArg(), RooFit.RecycleConflictNodes()) getattr(w, 'import')(rooDataHist, RooFit.Rename("data_obs")) w.Print() print "Starting save" if args.output_path: if not os.path.isdir(os.path.join(os.getcwd(), args.output_path)): os.mkdir(os.path.join(os.getcwd(), args.output_path)) print "[create_datacards] INFO : Writing workspace to file {}".format( os.path.join(args.output_path, wsName)) w.writeToFile(os.path.join(args.output_path, wsName)) else: print "[create_datacards] INFO : Writing workspace to file {}".format( limit_config.get_workspace_filename( args.analysis, args.model, mass, fitBonly=args.fitBonly, fitSignal=args.fitSignal, correctTrigger=args.correctTrigger)) w.writeToFile( limit_config.get_workspace_filename( args.analysis, args.model, mass, fitBonly=args.fitBonly, fitSignal=args.fitSignal, correctTrigger=args.correctTrigger)) # Clean up for name, obj in signal_norms.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in background_pdfs.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in background_pdfs_notrig.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in background_norms.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in signal_pdfs.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in signal_pdfs_notrig.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in signal_epdfs.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in background_epdfs.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in fit_results.iteritems(): if obj: obj.IsA().Destructor(obj) for name, dict_l2 in background_parameters.iteritems(): for name2, obj in dict_l2.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in models.iteritems(): if obj: obj.IsA().Destructor(obj) rooDataHist.IsA().Destructor(rooDataHist) w.IsA().Destructor(w) # Make datacards only if S+B fitted if not args.fitBonly: beffUnc = 0.3 boffUnc = 0.06 for fit_function in fit_functions: if args.output_path: dcName = 'datacard_' + args.final_state + '_m' + str( mass) + postfix + '_' + fit_function + '.txt' print "[create_datacards] INFO : Writing datacard to file {}".format( os.path.join(args.output_path, dcName)) datacard = open(os.path.join(args.output_path, dcName), 'w') else: print "[create_datacards] INFO : Writing datacard to file {}".format( limit_config.get_datacard_filename( args.analysis, args.model, mass, fit_function, fitSignal=args.fitSignal, correctTrigger=args.correctTrigger)) datacard = open( limit_config.get_datacard_filename( args.analysis, args.model, mass, fit_function, fitSignal=args.fitSignal, correctTrigger=args.correctTrigger), 'w') datacard.write('imax 1\n') datacard.write('jmax 1\n') datacard.write('kmax *\n') datacard.write('---------------\n') if ("jes" in systematics or "jer" in systematics) and not args.fitSignal: if args.output_path: datacard.write('shapes * * ' + wsName + ' w:$PROCESS w:$PROCESS__$SYSTEMATIC\n') else: datacard.write('shapes * * ' + os.path.basename( limit_config.get_workspace_filename( args.analysis, args.model, mass, fitSignal=args.fitSignal, correctTrigger=args.correctTrigger)) + ' w:$PROCESS w:$PROCESS__$SYSTEMATIC\n') else: if args.output_path: datacard.write('shapes * * ' + wsName + ' w:$PROCESS\n') else: datacard.write('shapes * * ' + os.path.basename( limit_config.get_workspace_filename( args.analysis, args.model, mass, fitSignal=args.fitSignal, correctTrigger=args.correctTrigger)) + ' w:$PROCESS\n') datacard.write('---------------\n') datacard.write('bin 1\n') datacard.write('observation -1\n') datacard.write('------------------------------\n') datacard.write('bin 1 1\n') datacard.write('process signal background_' + fit_function + '\n') datacard.write('process 0 1\n') if args.fitSignal: datacard.write('rate 1 1\n') else: datacard.write('rate -1 1\n') datacard.write('------------------------------\n') datacard.write('lumi lnN %f -\n' % (1. + systematics["luminosity"])) datacard.write('beff lnN %f -\n' % (1. + beffUnc)) datacard.write('boff lnN %f -\n' % (1. + boffUnc)) #datacard.write('bkg lnN - 1.03\n') if args.fitSignal: if "jes" in systematics: datacard.write("alpha_jes param 0.0 1.0\n") if "jer" in systematics: datacard.write("alpha_jer param 0.0 1.0\n") else: if "jes" in systematics: datacard.write('JES shape 1 -\n') if "jer" in systematics: datacard.write('JER shape 1 -\n') # flat parameters --- flat prior datacard.write('background_' + fit_function + '_norm flatParam\n') if args.decoBkg: datacard.write('deco_eig1 flatParam\n') datacard.write('deco_eig2 flatParam\n') else: for par_name, par in background_parameters[ fit_function].iteritems(): datacard.write(fit_function + "_" + par_name + ' flatParam\n') datacard.close() print "[create_datacards] INFO : Done with this datacard" #print '>> Datacards and workspaces created and stored in %s/'%( os.path.join(os.getcwd(),args.output_path) ) print "All done."
r_max = args.r_max else: r_max = limit_p2sigma * 100 * 3. print "Using r in [{}, {}]".format(r_min, r_max) #min_logr = log(r_min, 10) #max_logr = log(r_max, 10) #logr_values = [min_logr + ((max_logr - min_logr)*i/(args.n_points - 1)) for i in range(args.n_points)] r_values = [ r_min + ((r_max - r_min) * i / (args.n_points - 1)) for i in range(args.n_points) ] name = "grid_{}_{}_{}_{}".format(analysis, model, mass, postfix) datacard = limit_config.get_datacard_filename( analysis, model, mass, args.fit_function, fitSignal=True) workspace = limit_config.get_workspace_filename( analysis, model, mass, fitSignal=True) setup_grid(name, datacard, workspace, r_values, run=True, toysH=args.toysH, iterations=args.iterations, fork=args.fork) if args.merge: from joblib import Parallel, delayed
limit_p2sigma = limit_config.limit_p2sigma_estimates[analysis][model][mass] limit_m2sigma = limit_config.limit_m2sigma_estimates[analysis][model][mass] limit_range = limit_p2sigma - limit_m2sigma if args.r_min: r_min = args.r_min else: r_min = limit_m2sigma * 100 / 3. if args.r_max: r_max = args.r_max else: r_max = limit_p2sigma * 100 * 3. print "Using r in [{}, {}]".format(r_min, r_max) #min_logr = log(r_min, 10) #max_logr = log(r_max, 10) #logr_values = [min_logr + ((max_logr - min_logr)*i/(args.n_points - 1)) for i in range(args.n_points)] r_values = [r_min + ((r_max - r_min)*i/(args.n_points-1)) for i in range(args.n_points)] name = "grid_{}_{}_{}_{}".format(analysis, model, mass, postfix) datacard = limit_config.get_datacard_filename(analysis, model, mass, args.fit_function, fitSignal=True) workspace = limit_config.get_workspace_filename(analysis, model, mass, fitSignal=True) setup_grid(name, datacard, workspace, r_values, run=True, toysH=args.toysH, iterations=args.iterations, fork=args.fork) if args.merge: from joblib import Parallel, delayed for analysis in analyses: if args.mass: masses = [args.mass] else: masses = limit_config.limit_signal_masses[analysis] Parallel(n_jobs=4)(delayed(merge)(analysis, model, mass, args.fit_function) for mass in masses for model in models)
def main(): # input parameters parser = ArgumentParser(description='Script that runs limit calculation for specified mass points') parser.add_argument("-M", "--method", dest="method", required=True, choices=['MaxLikelihoodFit', 'ProfileLikelihood', 'HybridNew', 'Asymptotic', 'MarkovChainMC'], help="Method to calculate upper limits", metavar="METHOD") parser.add_argument('--analyses', type=str, default="trigbbh_CSVTM,trigbbl_CSVTM", help="Analysis names") parser.add_argument('--models', type=str, default="Hbb,RSG,ZPrime", help="Model names") parser.add_argument('--qcd', action='store_true', help="Use QCD instead of data (assumes no trigger emulation)") parser.add_argument('--correctTrigger', action='store_true', help="Use model with trigger correction (has to have been specified in create_datacards.py)") parser.add_argument('--useMCTrigger', action='store_true', help="Use MC trigger") parser.add_argument('--fitTrigger', action='store_true', help="Use model with trigger fit (has to have been specified in create_datacards.py)") parser.add_argument('--fitOffB', action='store_true', help="Include a parametrization of offline b-tag efficiency in background PDF") parser.add_argument('--fit_function', type=str, default="f4", help="Name of central fit function") #parser.add_argument("-d", "--datacards_path", dest="datacards_path", required=True, # help="Path to datacards and workspaces", # metavar="DATA_HISTNAME") #parser.add_argument("-f", "--final_state", dest="final_state", required=True, # help="Final state (e.g. qq, qg, gg)", # metavar="FINAL_STATE") #parser.add_argument("-o", "--output_path", dest="output_path", # default='logs', # help="Output path where log files will be stored (default: %(default)s)", # metavar="OUTPUT_PATH") parser.add_argument("--rMin", dest="rMin", type=float, help="Minimum value for the signal strength") parser.add_argument("--rMax", dest="rMax", type=float, help="Maximum value for the signal strength") parser.add_argument("--rPrior", action="store_true", help="Take rMin and rMax from a previous iteration of limit setting.") parser.add_argument("--rRelAcc", dest="rRelAcc", type=float, help="rRelAcc") parser.add_argument("--rAbsAcc", dest="rAbsAcc", type=float, help="rAbsAcc") parser.add_argument("--level", dest="level", type=float, help="Exp from grid level") parser.add_argument("--toysH", dest="toysH", type=int, help="Number of Toy MC extractions for HybridNew") parser.add_argument("--toys", dest="toys", type=int, help="Number of Toy MC extractions, not for HybridNew") parser.add_argument("--tries", dest="tries", type=int, default=10, help="Number of times to run the MCMC (default: %(default)i)") parser.add_argument("--robustFit", dest="robustFit", action='store_true', help="combine robustFit option") parser.add_argument("--proposal", dest="proposal", default='ortho', help="Proposal function for MCMC (default: %(default)s)") parser.add_argument("--noSyst", dest="noSyst", default=False, action="store_true", help="Run without systematic uncertainties") parser.add_argument("--picky", dest="picky", default=False, action="store_true", help="combine picky mode") parser.add_argument("--saveHybridResult", action="store_true", help="--saveHybridResult") parser.add_argument("--strictBounds", dest="strictBounds", default=False, action="store_true", help="Strict bounds on rMax") parser.add_argument("--testStat", type=str, help="Test statistics: LEP, TEV, LHC (previously known as Atlas), Profile.") parser.add_argument("--freezeNuisances", dest="freezeNuisances", type=str, help="Freeze nuisance parameters") parser.add_argument("--noHint", dest="noHint", default=False, action="store_true", help="Do not run the hint method") parser.add_argument("--significance", dest="significance", default=False, action="store_true", help="Calculate significance instead of limits") parser.add_argument("--frequentist", dest="freq", default=False, action="store_true", help="Frequentist hybridnew") parser.add_argument("--fork", dest="forkvar", default=False, action="store_true", help="More cores") parser.add_argument("--fitStrategy", dest="fitStrategy", type=int, help="Fit strategy (default: %(default).1f)") parser.add_argument("--condor", dest="condor", default=False, action="store_true", help="Batch process using Condor") parser.add_argument("--no_retar", dest='no_retar', action="store_true", help="If --condor is specified, this specifies no retar of src directory (use cached copy)") parser.add_argument("--postfix", dest="postfix", default='', help="Postfix for the input and output file names (default: %(default)s)") parser.add_argument("--hnsig", dest="hnsig", default=False, action="store_true", help="HybridNew Significance calc") parser.add_argument("--hnsig2", dest="hnsig2", default=False, action="store_true", help="HybridNew Significance calc") parser.add_argument("--minimizerTolerance", dest="minimizerTolerance", type=float, help="--minimizerTolerance option for combine") parser.add_argument("--minimizerAlgoForMinos", dest="minimizerAlgoForMinos", type=str, help="--minimizerAlgoForMinos option for combine") parser.add_argument("--minimizerToleranceForMinos", dest="minimizerToleranceForMinos", type=float, help="--minimizerToleranceForMinos option for combine") parser.add_argument('-v', '--verbose', type=int, help='Verbosity of combine') parser.add_argument('-m', '--masses', type=str, help='Manually specify masses (comma-separated list). Otherwise, taken from limit_configuration.') parser.add_argument("--preFitValue", type=float, help="preFitValue option for combine") parser.add_argument("--fitBonly", action="store_true", help="Use workspace created with fitBonly option") #mass_group = parser.add_mutually_exclusive_group(required=True) #mass_group.add_argument("--mass", # type=int, # nargs = '*', # default = 1000, # help="Mass can be specified as a single value or a whitespace separated list (default: %(default)i)" # ) #mass_group.add_argument("--massrange", # type=int, # nargs = 3, # help="Define a range of masses to be produced. Format: min max step", # metavar = ('MIN', 'MAX', 'STEP') # ) #mass_group.add_argument("--masslist", # help = "List containing mass information" # ) args = parser.parse_args() analyses = args.analyses.split(",") models = args.models.split(",") # check if the output directory exists #if not os.path.isdir( os.path.join(os.getcwd(), args.output_path) ): # os.mkdir( os.path.join(os.getcwd(), args.output_path) ) #print os.getcwd() # mass points for which resonance shapes will be produced #masses = [] #if args.massrange != None: # MIN, MAX, STEP = args.massrange # masses = range(MIN, MAX+STEP, STEP) #elif args.masslist != None: # # A mass list was provided # print "Will create mass list according to", args.masslist # masslist = __import__(args.masslist.replace(".py","")) # masses = masslist.masses #else: # masses = args.mass # ## sort masses #masses.sort() masses = {} if args.masses: for analysis in analyses: masses[analysis] = [int(x) for x in args.masses.split(",")] else: masses = limit_config.limit_signal_masses method = args.method if args.significance and method != 'ProfileLikelihood' and method != 'HybridNew': print "** ERROR: ** For significance calculation the ProfileLikelihood or HybridNew method has to be used. Aborting." sys.exit(1) options = '' if args.significance: options = options + ' --significance' if args.freq: options = options + ' --frequentist' if args.hnsig: options = options + ' --significance --saveToys --fullBToys --saveHybridResult -T 500 -i 100 -s 123457' if args.hnsig2: options = options + ' --significance --readHybridResult --toysFile=input.root --expectedFromGrid=0.5' if args.forkvar: options = options + ' --fork 4' if args.testStat: options = options + ' --testStat ' + args.testStat if args.level != None: options = options + ' --expectedFromGrid=%f'%(args.level) if args.fitStrategy: options = options + ' --minimizerStrategy %i'%(args.fitStrategy) if args.noSyst: options = options + ' --systematics 0' if args.freezeNuisances: options = options + ' --freezeNuisances ' + args.freezeNuisances if args.picky: options = options + ' --picky ' if args.saveHybridResult: options = options + " -- saveHybridResult " if args.strictBounds: options = options + ' --strictBounds ' if args.rAbsAcc: options = options + " --rAbsAcc " + str(args.rAbsAcc) + " " if args.rRelAcc: options = options + " --rRelAcc " + str(args.rRelAcc) + " " if args.verbose: options = options + ' -v' + str(args.verbose) if method != 'ProfileLikelihood' and method != 'MaxLikelihoodFit' and args.rMax == None and not args.noHint and not args.significance: options = options + ' --hintMethod ProfileLikelihood' if method == 'HybridNew' and args.toysH != None: options = options + ' --toysH %i'%(args.toysH) if args.toys: options = options + ' --toys ' + str(args.toys) if args.robustFit: options = options + ' --robustFit 1' if args.minimizerTolerance: options += " --minimizerTolerance " + str(args.minimizerTolerance) + " " if args.minimizerAlgoForMinos: options += " --minimizerAlgoForMinos " + str(args.minimizerAlgoForMinos) + " " if args.minimizerToleranceForMinos: options += " --minimizerToleranceForMinos " + str(args.minimizerToleranceForMinos) + " " if args.preFitValue: options += " --preFitValue " + str(args.preFitValue) + " " if args.rPrior: # Take rMin and rMax from +/-2 sigma estimates from a previous iteration. This has to be done per-job, so do it later. pass else: if args.rMin != None: options = options + ' --rMin %f'%(args.rMin) if args.rMax != None: options = options + ' --rMax %f'%(args.rMax) if method == 'MarkovChainMC': options = options + ' --tries %i --proposal %s'%(args.tries, args.proposal) prefix = 'limits' if args.significance: prefix = 'significance' elif method == 'MaxLikelihoodFit': prefix = 'signal_xs' postfix = (('_' + args.postfix) if args.postfix != '' else '') if args.noSyst: postfix += "_noSyst" if args.freezeNuisances: postfix += "_" + args.freezeNuisances.replace(",", "_") if args.fitTrigger: postfix += "_fitTrigger" if args.correctTrigger: postfix += "_correctTrigger" if args.useMCTrigger: postfix += "_useMCTrigger" if args.fitOffB: postfix += "_fitOffB" if args.qcd: postfix += "_qcd" if args.fitBonly: postfix += "_fitBonly" datacards_path = limit_config.paths["datacards"] output_path = limit_config.paths["combine_logs"] condor_path = limit_config.paths["condor"] # change to the appropriate directory if args.condor: os.chdir(output_path) else: os.chdir(datacards_path) first = True for analysis in analyses: for model in models: for mass in masses[analysis]: logName = '{}_{}_{}_{}_m{}{}_{}.log'.format(prefix, method, analysis, model, int(mass), postfix,args.fit_function) job_name = "%s_%s_m%i%s_%s"%(analysis, model, int(mass),postfix,args.fit_function) run_options = options + ' --name _%s_%s_m%i%s_%s --mass %i'%(analysis, model, int(mass),postfix,args.fit_function,int(mass)) if args.rPrior: run_options += " --rMin " + str(limit_config.limit_m2sigma_estimates[analysis][model][mass] / 5. * 100.) run_options += " --rMax " + str(limit_config.limit_p2sigma_estimates[analysis][model][mass] * 5. * 100.) if method == "MaxLikelihoodFit": # Save shapes and plots run_options += " --saveWithUncertainties --saveShapes --plots --out plots_" + job_name if args.condor: cmd = "combine -M %s %s %s 2>&1 | tee %s"%( method, run_options, os.path.basename(limit_config.get_datacard_filename(analysis, model, mass, args.fit_function, correctTrigger=args.correctTrigger, useMCTrigger=args.useMCTrigger, qcd=args.qcd, fitTrigger=args.fitTrigger, fitBonly=args.fitBonly, fitOffB=args.fitOffB)), os.path.basename(os.path.join(('' if args.condor else output_path),logName))) else: cmd = "combine -M %s %s %s 2>&1 | tee %s"%( method, run_options, limit_config.get_datacard_filename(analysis, model, mass, args.fit_function, correctTrigger=args.correctTrigger, useMCTrigger=args.useMCTrigger, qcd=args.qcd, fitTrigger=args.fitTrigger, fitBonly=args.fitBonly, fitOffB=args.fitOffB), os.path.join(('' if args.condor else output_path),logName)) # if using Condor if args.condor: #submission_dir = limit_config.paths["condor"] submission_dir = limit_config.paths["combine_logs"] start_dir = os.getcwd() os.chdir(submission_dir) # create the executable script bash_script_path = os.path.join(submission_dir,'run_%s_%s_%s_m%i%s.sh'%(method,analysis,model,int(mass),postfix)) #bash_content = bash_template #bash_content = re.sub('DUMMY_CMD',cmd,bash_content) bash_script = open(bash_script_path,'w') bash_script.write("echo '" + cmd + "'\n") if method == "MaxLikelihoodFit": bash_script.write("mkdir -pv plots_" + job_name + "\n") bash_script.write(cmd) bash_script.close() # Create the condor command condor_command = "csub " + bash_script_path files_to_transfer = [] files_to_transfer.append(bash_script_path) files_to_transfer.append(limit_config.get_datacard_filename(analysis, model, mass, args.fit_function, correctTrigger=args.correctTrigger, useMCTrigger=args.useMCTrigger, qcd=args.qcd, fitTrigger=args.fitTrigger, fitBonly=args.fitBonly, fitOffB=args.fitOffB)) files_to_transfer.append(limit_config.get_workspace_filename(analysis, model, mass, correctTrigger=args.correctTrigger, useMCTrigger=args.useMCTrigger, qcd=args.qcd, fitTrigger=args.fitTrigger, fitBonly=args.fitBonly, fitOffB=args.fitOffB)) condor_command += " -F " + ",".join(files_to_transfer) condor_command += " -l combine_{}_\$\(Cluster\)_\$\(Process\).log".format(logName) condor_command += " -s submit_combine_{}_{}_{}.jdl".format(analysis, model, mass) condor_command += " -d " + submission_dir if method == "MaxLikelihoodFit": condor_command += " -o plots_" + job_name + " " condor_command += " --cmssw" if not first or args.no_retar: condor_command += " --no_retar " print ">> Submitting job for %s %s resonance with m = %i GeV..."%(analysis,model, int(mass)) print "Submission command: " print condor_command os.system(condor_command) print "---------------------------------------------------------------------------" os.chdir(start_dir) else: print ">> Running combine for %s %s resonance with m = %i GeV..."%(analysis, model, int(mass)) print "---------------------------------------------------------------------------" if method == "MaxLikelihoodFit": os.system("mkdir -pv plots_" + job_name) print "Running: " + cmd + "\n" os.system(cmd) if first: first = False
def run_single_mass(args, mass): print "[run_single_mass] INFO : Creating datacard and workspace for m = %i GeV..."%(int(mass)) if args.fit_functions == "all": #fit_functions = ["dijet4", "dijet5", "modexp4", "polyx6", "atlas4", "atlas5", "polypower4", "rational3", "rational4"] fit_functions = ["dijet4", "modexp4", "polyx6", "polypower4"] else: fit_functions = args.fit_functions.split(",") # import ROOT stuff from ROOT import gStyle, TFile, TH1F, TH1D, TGraph, kTRUE, kFALSE, TCanvas, TLegend, TPad, TLine from ROOT import RooHist, RooRealVar, RooDataHist, RooArgList, RooArgSet, RooAddPdf, RooProdPdf, RooEffProd, RooFit, RooGenericPdf, RooWorkspace, RooMsgService, RooHistPdf, RooExtendPdf, RooFormulaVar if not args.debug: RooMsgService.instance().setSilentMode(kTRUE) RooMsgService.instance().setStreamStatus(0,kFALSE) RooMsgService.instance().setStreamStatus(1,kFALSE) # Stuff mjj = RooRealVar('mjj','mjj',float(args.massMin),float(args.massMax)) lumi = args.lumi signalCrossSection = 1. # Set to 1 so that the limit on r can be interpreted as a limit on the signal cross section # Input data file if args.qcd: data_sample = "QCD_TuneZ2star_8TeV_pythia6" elif "trigbb" in args.analysis: data_sample = "BJetPlusX_2012" elif "trigmu" in args.analysis: data_sample = "SingleMu_2012" data_file_path = analysis_config.get_b_histogram_filename(args.analysis, data_sample) if args.condor: data_file_path = os.path.basename(data_file_path) data_file = TFile(data_file_path) hData_notrigcorr = data_file.Get("BHistograms/h_pfjet_mjj") hData_notrigcorr.SetDirectory(0) hData_name = hData_notrigcorr.GetName() hData_notrigcorr.SetName(hData_name + "_notrigcorr") # Trigger correction on data if args.fitTrigger: # Make trigger correction objects trigeff_pt_formula, trigeff_vars = trigger_efficiency.get_var_formula(args.analysis, mjj) trigeff_btag_var = RooRealVar("trigeff_btag", "trigeff_btag", 0., 1.) trigeff_btag_var.setVal(trigger_efficiency.online_btag_eff[args.analysis][0]) trigeff_btag_var.setConstant() trigeff_btag_formula = RooFormulaVar("trigeff_btag_formula", "@0", RooArgList(trigeff_btag_var)) #trigeff_btag_var.setConstant() trigeff_total_formula = RooFormulaVar("trigeff_total_formula", "@0*@1", RooArgList(trigeff_btag_var, trigeff_pt_formula)) #for trigeff_var_name, trigeff_var in trigeff_vars.iteritems(): # trigeff_var.setConstant() if args.correctTrigger: # Apply trigger correction to data histogram hData = CorrectTriggerEfficiency(hData_notrigcorr, args.analysis) # Still need b-tagging efficiency to scale the MC if not args.useMCTrigger: trigeff_btag_var = RooRealVar("trigeff_btag", "trigeff_btag", 0., 1.) trigeff_btag_var.setVal(trigger_efficiency.online_btag_eff[args.analysis][0]) trigeff_btag_var.setConstant() trigeff_btag_formula = RooFormulaVar("trigeff_btag_formula", "@0", RooArgList(trigeff_btag_var)) # Use a RooRealVar instead! You want to be able to apply a systematic in combine. # trigeff_btag_formula = RooFormulaVar("trigeff_btag_formula", str(trigger_efficiency.online_btag_eff[args.analysis][0]), RooArgList()) else: hData = hData_notrigcorr if args.qcd: # For QCD, scale the histogram by the online b-tag trigger efficiency. if args.analysis == "NoTrigger_eta1p7_CSVTM": trigeff_btag_formula = RooFormulaVar("trigeff_btag_formula", str(trigger_efficiency.online_btag_eff["trigbbl_CSVTM"][0]), RooArgList()) elif args.analysis == "NoTrigger_eta2p2_CSVTM": trigeff_btag_formula = RooFormulaVar("trigeff_btag_formula", str(trigger_efficiency.online_btag_eff["trigbbh_CSVTM"][0]), RooArgList()) if args.analysis == "NoTrigger_eta1p7_CSVTM": hData.Scale(trigger_efficiency.online_btag_eff["trigbbl_CSVTM"][0]) elif args.analysis == "NoTrigger_eta2p2_CSVTM": hData.Scale(trigger_efficiency.online_btag_eff["trigbbh_CSVTM"][0]) else: print "[create_datacards_parallel] ERROR : QCD fit requested, but analysis != NoTrigger_etaXpY_CSVTM. I don't know what to do!" sys.exit(1) hData.SetName(hData_name) rooDataHist = RooDataHist('rooDatahist','rooDatahist',RooArgList(mjj),hData) if args.correctTrigger: rooDataHist_notrigcorr = RooDataHist("rooDatahist_notrigcorr", "rooDatahist_notrigcorr", RooArgList(mjj), hData_notrigcorr) # Get signal pdf * btag efficiency if args.useMCTrigger: signal_pdf_file = analysis_config.get_signal_fit_file(args.analysis, args.model, mass, "bukin", interpolated=(not mass in analysis_config.simulation.simulated_masses)) if args.condor: signal_pdf_file = os.path.basename(signal_pdf_file) print "[create_datacards] Loading fitted signal PDFs from " + signal_pdf_file f_signal_pdfs = TFile(signal_pdf_file, "READ") f_signal_pdfs.Print() w_signal = f_signal_pdfs.Get("w_signal") w_signal.Print() bukin_pdf = w_signal.pdf("signal_bukin") bukin_pdf.Print() else: if args.analysis == "trigbbl_CSVTM" or args.analysis == "NoTrigger_eta1p7_CSVTM": notrig_analysis = "NoTrigger_eta1p7_CSVTM" elif args.analysis == "trigbbh_CSVTM" or args.analysis == "NoTrigger_eta2p2_CSVTM": notrig_analysis = "NoTrigger_eta2p2_CSVTM" elif args.analysis == "trigbbl_CSVM" or args.analysis == "NoTrigger_eta1p7_CSVM": notrig_analysis = "NoTrigger_eta1p7_CSVM" elif args.analysis == "trigbbh_CSVM" or args.analysis == "NoTrigger_eta2p2_CSVM": notrig_analysis = "NoTrigger_eta2p2_CSVM" else: print "[run_single_mass] ERROR : I don't know a no-trigger variant of analysis {}. Please make one, or specify --useMCTrigger.".format(args.analysis) sys.exit(1) print analysis_config.simulation.simulated_masses signal_pdf_file = analysis_config.get_signal_fit_file(notrig_analysis, args.model, mass, "bukin", interpolated=(not mass in analysis_config.simulation.simulated_masses)) print "[create_datacards] Loading fitted signal PDFs from " + signal_pdf_file if args.condor: signal_pdf_file = os.path.basename(signal_pdf_file) f_signal_pdfs = TFile(signal_pdf_file, "READ") w_signal = f_signal_pdfs.Get("w_signal") bukin_pdf = w_signal.pdf("signal") bukin_pdf.SetName("signal_bukin") input_signal_parameters = signal_fits.get_parameters(bukin_pdf) # Make a new PDF with nuisance parameters signal_pdf_notrig, signal_vars = signal_fits.make_signal_pdf_systematic("bukin", mjj, mass=mass) signal_pdf_name = signal_pdf_notrig.GetName() signal_pdf_notrig.SetName(signal_pdf_name + "_notrig") # Add trigger efficiency if args.useMCTrigger: if args.fitTrigger: # Online b-tagging eff incorporated in Bukin/acceptance, so signal pdf = Bukin * pT efficiency signal_pdf = RooEffProd("signal", "signal", signal_pdf_notrig, trigeff_pt_formula) elif args.correctTrigger: # Signal PDF = bukin; b-tag efficiency already included in normalization signal_pdf = signal_pdf_notrig signal_pdf.SetName(signal_pdf_name) else: if args.fitTrigger: # Signal PDF = bukin * total trigger efficiency signal_pdf = RooEffProd("signal", "signal", signal_pdf_notrig, trigeff_total_formula) elif args.correctTrigger: if args.useMCTrigger: signal_pdf = signal_pdf_notrig signal_pdf.SetName("signal") else: # Signal PDF = bukin * btag efficiency signal_pdf = RooEffProd("signal", "signal", signal_pdf_notrig, trigeff_btag_formula) elif args.qcd: # Signal PDF = bukin * btag efficiency # Same as correctTrigger signal_pdf = RooEffProd("signal", "signal", signal_pdf_notrig, trigeff_btag_formula) # Copy input parameter values signal_vars["xp_0"].setVal(input_signal_parameters["xp"][0]) signal_vars["xp_0"].setError(input_signal_parameters["xp"][1]) signal_vars["xp_0"].setConstant() signal_vars["sigp_0"].setVal(input_signal_parameters["sigp"][0]) signal_vars["sigp_0"].setError(input_signal_parameters["sigp"][1]) signal_vars["sigp_0"].setConstant() signal_vars["xi_0"].setVal(input_signal_parameters["xi"][0]) signal_vars["xi_0"].setError(input_signal_parameters["xi"][1]) signal_vars["xi_0"].setConstant() signal_vars["rho1_0"].setVal(input_signal_parameters["rho1"][0]) signal_vars["rho1_0"].setError(input_signal_parameters["rho1"][1]) signal_vars["rho1_0"].setConstant() signal_vars["rho2_0"].setVal(input_signal_parameters["rho2"][0]) signal_vars["rho2_0"].setError(input_signal_parameters["rho2"][1]) signal_vars["rho2_0"].setConstant() f_signal_pdfs.Close() signal_parameters = {} signal_pdfs_notrig = {} signal_pdfs = {} signal_norms = {} background_pdfs = {} background_pdfs_notrig = {} background_parameters = {} background_norms = {} signal_epdfs = {} background_epdfs = {} models = {} fit_results = {} if args.fitOffB: # Load RooHistPdf if "bbl" in args.analysis or "eta1p7" in args.analysis: eta_region = "eta1p7" offline_btag_eff_vars = { "p0":RooRealVar("offline_btag_eff_p0", "offline_btag_eff_p0", 6.78251e-03, 6.78251e-03 - 10.*7.66906e-05, 6.78251e-03 + 10.*7.66906e-05), "p1":RooRealVar("offline_btag_eff_p1", "offline_btag_eff_p1", -9.55614e-06, -9.55614e-06 - 10.*1.04286e-07, -9.55614e-06 + 10.*1.04286e-07), "p2":RooRealVar("offline_btag_eff_p2", "offline_btag_eff_p2", 4.39468e-09, 4.39468e-09 - 1.e-07, 4.39468e-09 + 1.e-07), } offline_btag_eff_formula = RooFormulaVar("offline_btag_eff", "max(@0+(@1*@3)+(@2*@3*@3), 0.)", RooArgList(offline_btag_eff_vars["p0"], offline_btag_eff_vars["p1"], offline_btag_eff_vars["p2"], mjj)) elif "bbh" in args.analysis or "eta2p2" in args.analysis: eta_region = "eta2p2" offline_btag_eff_vars = { "p0":RooRealVar("offline_btag_eff_p0", "offline_btag_eff_p0", -1.72721e-03, -1.72721e-03 - 10.*3.04992e-05, -1.72721e-03 + 10.*3.04992e-05), "p1":RooRealVar("offline_btag_eff_p1", "offline_btag_eff_p1", 1.72562e-06, 1.72562e-06 - 10.*3.23472e-08, 1.72562e-06 + 10.*3.23472e-08), "p2":RooRealVar("offline_btag_eff_p2", "offline_btag_eff_p2", 8.74866e-03, 8.74866e-03 - 10.*7.81413e-05, 8.74866e-03 + 10.*7.81413e-05), "p3":RooRealVar("offline_btag_eff_p3", "offline_btag_eff_p3", -1.67123e-03, -1.67123e-03 - 10.*4.30607e-05, -1.67123e-03 + 10.*4.30607e-05), } offline_btag_eff_formula = RooFormulaVar("offline_btag_eff", "max(@0+@1*@4+ @2*exp(@3*@4), 0.)", RooArgList(offline_btag_eff_vars["p0"],offline_btag_eff_vars["p1"],offline_btag_eff_vars["p2"],offline_btag_eff_vars["p3"], mjj)) #f_offline_btag_eff = TFile(analysis_config.get_offline_btag_file("CSVTM", eta_region)) #h_offline_btag_eff = f_offline_btag_eff.Get("h_offline_btag_eff") #print h_offline_btag_eff #offline_btag_eff_rdh = RooDataHist("rdh_offline_btag_eff", "rdh_offline_btag_eff", RooArgList(mjj), h_offline_btag_eff) #offline_btag_eff_pdf = RooHistPdf("pdf_offline_btag_eff", "pdf_offline_btag_eff", RooArgSet(mjj), offline_btag_eff_rdh) for fit_function in fit_functions: print "[create_datacards] INFO : On fit function {}".format(fit_function) # Make a copy of the signal PDF, so that each fitTo call uses its own copy. # The copy should have all variables set constant. #signal_pdfs[fit_function], signal_parameters[fit_function] = signal_fits.copy_signal_pdf("bukin", signal_pdf, mjj, tag=fit_function, include_systematics=True) signal_pdfs_notrig[fit_function] = ROOT.RooBukinPdf(signal_pdf_notrig, signal_pdf_notrig.GetName() + "_" + fit_function) iterator = signal_pdfs_notrig[fit_function].getVariables().createIterator() this_parameter = iterator.Next() while this_parameter: this_parameter.setConstant() this_parameter = iterator.Next() # Add trigger efficiency if args.useMCTrigger: if args.fitTrigger: signal_pdfs[fit_function] = RooEffProd(signal_pdf.GetName() + "_" + fit_function, signal_pdf.GetName() + "_" + fit_function, signal_pdfs_notrig[fit_function], trigeff_pt_formula) else: signal_pdfs[fit_function] = signal_pdfs_notrig[fit_function] signal_pdfs[fit_functions].SetName(signal_pdf.GetName() + "_" + fit_function) elif args.fitTrigger: # Signal PDF = bukin * total trigger efficiency signal_pdfs[fit_function] = RooEffProd(signal_pdf.GetName() + "_" + fit_function, signal_pdf.GetName() + "_" + fit_function, signal_pdfs_notrig[fit_function], trigeff_total_formula) elif args.correctTrigger: # Signal PDF = bukin * btag efficiency signal_pdfs[fit_function] = RooEffProd(signal_pdf.GetName() + "_" + fit_function, signal_pdf.GetName() + "_" + fit_function, signal_pdfs_notrig[fit_function], trigeff_btag_formula) elif args.qcd: # Signal PDF = bukin * btag efficiency signal_pdfs[fit_function] = RooEffProd(signal_pdf.GetName() + "_" + fit_function, signal_pdf.GetName() + "_" + fit_function, signal_pdfs_notrig[fit_function], trigeff_btag_formula) signal_norms[fit_function] = RooRealVar('signal_norm_' + fit_function, 'signal_norm_' + fit_function, 0., 0., 1e+05) if args.fitBonly: signal_norms[fit_function].setConstant() # Make background PDF background_pdfs_notrig[fit_function], background_parameters[fit_function] = make_background_pdf(fit_function, mjj, collision_energy=8000.) background_pdf_name = background_pdfs_notrig[fit_function].GetName() background_pdfs_notrig[fit_function].SetName(background_pdf_name + "_notrig") if args.fitTrigger and args.fitOffB: background_pdf_intermediate = RooEffProd(background_pdf_name + "_intermediate", background_pdf_name + "_intermediate", background_pdfs_notrig[fit_function], offline_btag_eff_formula) background_pdfs[fit_function] = RooEffProd(background_pdf_name, background_pdf_name, background_pdf_intermediate, trigeff_pt_formula) elif args.fitTrigger and not args.fitOffB: background_pdfs[fit_function] = RooEffProd(background_pdf_name, background_pdf_name, background_pdfs_notrig[fit_function], trigeff_pt_formula) elif args.fitOffB and not args.fitTrigger: background_pdfs[fit_function] = RooEffProd(background_pdf_name, background_pdf_name, background_pdfs_notrig[fit_function], offline_btag_eff_formula) else: background_pdfs[fit_function] = background_pdfs_notrig[fit_function] background_pdfs[fit_function].SetName(background_pdf_name) # Initial values if "trigbbh" in args.analysis: if fit_function == "dijet4": if mass == 650: background_parameters[fit_function]["p1"].setVal(-2.2473e+01) background_parameters[fit_function]["p2"].setVal(1.4923e+01) background_parameters[fit_function]["p3"].setVal(1.3077e+00) else: background_parameters[fit_function]["p1"].setVal(-13.5877235358) background_parameters[fit_function]["p2"].setVal(14.0659901462) background_parameters[fit_function]["p3"].setVal(1.24550474025) background_parameters[fit_function]["p1"].setMin(-50.) background_parameters[fit_function]["p1"].setMax(50.) elif fit_function == "f2": background_parameters[fit_function]["p1"].setVal(6.06731321562) background_parameters[fit_function]["p2"].setVal(6.06264502704) elif fit_function == "polypower3": background_parameters[fit_function]["p1"].setVal(50.0270215343) background_parameters[fit_function]["p2"].setVal(8.17180937688) background_parameters[fit_function]["p1"].setMin(20.) elif fit_function == "polypower4": background_parameters[fit_function]["p1"].setVal(31.3765210572) background_parameters[fit_function]["p2"].setVal(-22.5800092219) background_parameters[fit_function]["p3"].setVal(9.94548656557) elif fit_function == "f5": background_parameters[fit_function]["p1"].setVal(5.51929170927) background_parameters[fit_function]["p2"].setVal(4.25521547671) elif fit_function == "f6": background_parameters[fit_function]["p1"].setVal(35.) background_parameters[fit_function]["p2"].setVal(-28.) background_parameters[fit_function]["p3"].setVal(0.) background_parameters[fit_function]["p4"].setVal(10.) elif "trigbbl" in args.analysis: if fit_function == "dijet4": background_parameters[fit_function]["p1"].setVal(-32.4727133488) background_parameters[fit_function]["p2"].setVal(18.7641649883) background_parameters[fit_function]["p3"].setVal(1.84028034937) elif fit_function == "f2": background_parameters[fit_function]["p1"].setVal(4.96261586452) background_parameters[fit_function]["p2"].setVal(19.0848105961) if fit_function == "polypower3": background_parameters[fit_function]["p1"].setVal(60.0000032579) background_parameters[fit_function]["p2"].setVal(8.00317534363) background_parameters[fit_function]["p1"].setMin(60.) elif fit_function == "polypower4": background_parameters[fit_function]["p1"].setVal(25.4109169544) background_parameters[fit_function]["p2"].setVal(-42.56719661) background_parameters[fit_function]["p3"].setVal(12.3295648189) elif fit_function == "f5": background_parameters[fit_function]["p1"].setVal(3.74859358646) background_parameters[fit_function]["p2"].setVal(11.4366903839) elif fit_function == "f6": background_parameters[fit_function]["p1"].setVal(35.) background_parameters[fit_function]["p2"].setVal(-43.) background_parameters[fit_function]["p3"].setVal(0.) background_parameters[fit_function]["p4"].setVal(10.) data_integral = hData.Integral(hData.GetXaxis().FindBin(float(args.massMin)),hData.GetXaxis().FindBin(float(args.massMax))) background_norms[fit_function] = RooRealVar('background_' + fit_function + '_norm', 'background_' + fit_function + '_norm', data_integral, 0., 1.e8) signal_epdfs[fit_function] = RooExtendPdf('esignal_' + fit_function, 'esignal_' + fit_function, signal_pdfs[fit_function], signal_norms[fit_function]) background_epdfs[fit_function] = RooExtendPdf('ebackground_' + fit_function, 'ebackground_' + fit_function, background_pdfs[fit_function], background_norms[fit_function]) models[fit_function] = RooAddPdf('model_' + fit_function, 's+b', RooArgList(background_epdfs[fit_function], signal_epdfs[fit_function])) if args.runFit and not args.dconly: print "[create_datacards] INFO : Starting fit with function {}".format(fit_function) models[fit_function].Print() # Fix the trigger efficiency for this fit if args.fitTrigger: trigeff_vars["alpha_trigeff_p0"].setConstant(True) trigeff_vars["alpha_trigeff_p1"].setConstant(True) trigeff_btag_var.setConstant(True) if args.fitOffB: for var in offline_btag_eff_vars.values(): var.setConstant(True) fit_results[fit_function] = models[fit_function].fitTo(rooDataHist, RooFit.Save(kTRUE), RooFit.Extended(kTRUE), RooFit.Strategy(args.fitStrategy), RooFit.Verbose(0)) print "[create_datacards] INFO : Done with fit {}. Printing results.".format(fit_function) fit_results[fit_function].Print() if args.fitTrigger: # Current strategy: freeze the trigger nuisance parameters. trigeff_vars["alpha_trigeff_p0"].setConstant(True) trigeff_vars["alpha_trigeff_p1"].setConstant(True) trigeff_btag_var.setConstant(True) if args.fitOffB: for var in offline_btag_eff_vars.values(): var.setConstant(False) print "[create_datacards] DEBUG : End args.runFit if block." # needed if want to evaluate limits without background systematics if args.fixBkg: background_norms[fit_function].setConstant() for par_name, par in background_parameters[fit_function].iteritems(): par.setConstant() # ----------------------------------------- # Set values of signal systematic variables # JES and JER uncertainties if "jes" in systematics: xp_central = signal_vars["xp_0"].getVal() xp_up = signal_fits.get_parameters(w_signal.pdf("signal__JESUp"))["xpJESUp"][0] xp_down = signal_fits.get_parameters(w_signal.pdf("signal__JESDown"))["xpJESDown"][0] signal_vars["dxp"].setVal(max(abs(xp_up - xp_central), abs(xp_down - xp_central))) if signal_vars["dxp"].getVal() > 2 * mass * 0.1: print "[create_datacards] WARNING : Large dxp value. dxp = {}, xp_down = {}, xp_central = {}, xp_up = {}".format(signal_vars["dxp"].getVal(), xp_down, xp_central, xp_up) signal_vars["alpha_jes"].setVal(0.) signal_vars["alpha_jes"].setConstant(False) else: signal_vars["dxp"].setVal(0.) signal_vars["alpha_jes"].setVal(0.) signal_vars["alpha_jes"].setConstant() signal_vars["dxp"].setError(0.) signal_vars["dxp"].setConstant() if "jer" in systematics: sigp_central = signal_vars["sigp_0"].getVal() sigp_up = signal_fits.get_parameters(w_signal.pdf("signal__JERUp"))["sigpJERUp"][0] sigp_down = signal_fits.get_parameters(w_signal.pdf("signal__JERDown"))["sigpJERDown"][0] signal_vars["dsigp"].setVal(max(abs(sigp_up - sigp_central), abs(sigp_down - sigp_central))) signal_vars["alpha_jer"].setVal(0.) signal_vars["alpha_jer"].setConstant(False) else: signal_vars["dsigp"].setVal(0.) signal_vars["alpha_jer"].setVal(0.) signal_vars["alpha_jer"].setConstant() signal_vars["dsigp"].setError(0.) signal_vars["dsigp"].setConstant() # ----------------------------------------- # create a datacard and corresponding workspace postfix = (('_' + args.postfix) if args.postfix != '' else '') wsName = 'workspace_' + args.final_state + '_m' + str(mass) + postfix + '.root' if not args.dconly: w = RooWorkspace('w','workspace') signal_pdf.SetName("signal") getattr(w,'import')(signal_pdf,RooFit.Rename("signal")) norm = args.lumi signal_norm = ROOT.RooRealVar("signal_norm", "signal_norm", norm/100., norm/100. / 10., norm * 10.) print "[create_datacards] INFO : Set signal norm to {}".format(signal_norm.getVal()) signal_norm.setConstant() getattr(w,'import')(signal_norm,ROOT.RooCmdArg()) for fit_function in fit_functions: print "Importing background PDF" print background_pdfs[fit_function] background_pdfs[fit_function].Print() getattr(w,'import')(background_pdfs[fit_function],ROOT.RooCmdArg(),RooFit.Rename("background_" + fit_function), RooFit.RecycleConflictNodes()) w.pdf("background_" + fit_function).Print() getattr(w,'import')(background_norms[fit_function],ROOT.RooCmdArg(),RooFit.Rename("background_" + fit_function + "_norm")) getattr(w,'import')(fit_results[fit_function]) getattr(w,'import')(signal_norms[fit_function],ROOT.RooCmdArg()) if args.fitBonly: getattr(w,'import')(models[fit_function],ROOT.RooCmdArg(),RooFit.RecycleConflictNodes()) getattr(w,'import')(rooDataHist,RooFit.Rename("data_obs")) if args.correctTrigger: getattr(w,'import')(rooDataHist_notrigcorr, RooFit.Rename("data_obs_notrigcorr")) w.Print() print "Starting save" if args.output_path: if not os.path.isdir( os.path.join(os.getcwd(),args.output_path) ): os.mkdir( os.path.join(os.getcwd(),args.output_path) ) workspace_output_path = os.path.join(args.output_path,wsName) else: workspace_output_path = limit_config.get_workspace_filename(args.analysis, args.model, mass, fitBonly=args.fitBonly, fitTrigger=args.fitTrigger, correctTrigger=args.correctTrigger, useMCTrigger=args.useMCTrigger, qcd=args.qcd, fitOffB=args.fitOffB) if args.condor: workspace_output_path = os.path.basename(workspace_output_path) print "[create_datacards] INFO : Writing workspace to file {}".format(workspace_output_path) w.writeToFile(workspace_output_path) if args.correctTrigger: f_workspace = TFile(workspace_output_path, "UPDATE") hData.Write() hData_notrigcorr.Write() # Clean up for name, obj in signal_norms.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in background_pdfs.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in background_pdfs_notrig.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in background_norms.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in signal_pdfs.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in signal_pdfs_notrig.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in signal_epdfs.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in background_epdfs.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in fit_results.iteritems(): if obj: obj.IsA().Destructor(obj) for name, dict_l2 in background_parameters.iteritems(): for name2, obj in dict_l2.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in models.iteritems(): if obj: obj.IsA().Destructor(obj) rooDataHist.IsA().Destructor(rooDataHist) if not args.dconly: w.IsA().Destructor(w) # Make datacards only if S+B fitted #beffUnc = 0.3 boffUnc = systematics["boff"][args.analysis][args.model].Eval(mass) pdfUnc = systematics["pdfunc"][args.analysis][args.model].Eval(mass) for fit_function in fit_functions: if args.output_path: dcName = 'datacard_' + args.final_state + '_m' + str(mass) + postfix + '_' + fit_function + '.txt' datacard_output_path = os.path.join(args.output_path,dcName) else: datacard_output_path = limit_config.get_datacard_filename(args.analysis, args.model, mass, fit_function, fitTrigger=args.fitTrigger, correctTrigger=args.correctTrigger, useMCTrigger=args.useMCTrigger, qcd=args.qcd, fitOffB=args.fitOffB, fitBonly=args.fitBonly) if args.condor: datacard_output_path = os.path.basename(datacard_output_path) print "[create_datacards] INFO : Writing datacard to file {}".format(datacard_output_path) datacard = open(datacard_output_path, 'w') datacard.write('imax 1\n') datacard.write('jmax 1\n') datacard.write('kmax *\n') datacard.write('---------------\n') if args.output_path: datacard.write('shapes * * '+wsName+' w:$PROCESS\n') else: datacard.write('shapes * * '+os.path.basename(limit_config.get_workspace_filename(args.analysis, args.model, mass, fitTrigger=args.fitTrigger, correctTrigger=args.correctTrigger, useMCTrigger=args.useMCTrigger, qcd=args.qcd, fitOffB=args.fitOffB, fitBonly=args.fitBonly))+' w:$PROCESS\n') datacard.write('---------------\n') datacard.write('bin 1\n') datacard.write('observation -1\n') datacard.write('------------------------------\n') datacard.write('bin 1 1\n') datacard.write('process signal background_' + fit_function + '\n') datacard.write('process 0 1\n') datacard.write('rate 1 1\n') datacard.write('------------------------------\n') datacard.write('lumi lnN %f -\n'%(1.+systematics["luminosity"])) if not args.useMCTrigger: datacard.write('bon lnN %f -\n'%(1.+ (trigger_efficiency.online_btag_eff[args.analysis][2] / trigger_efficiency.online_btag_eff[args.analysis][0]))) else: datacard.write('bon lnN %f -\n'%(1.+ systematics["bon"])) #datacard.write('beff lnN %f -\n'%(1.+beffUnc)) datacard.write('boff lnN %f -\n'%(1.+boffUnc)) datacard.write('pdf lnN %f -\n'%(1.+pdfUnc)) #datacard.write('bkg lnN - 1.03\n') if "jes" in systematics: datacard.write("alpha_jes param 0.0 1.0\n") if "jer" in systematics: datacard.write("alpha_jer param 0.0 1.0\n") if args.fitOffB: if eta_region == "eta1p7": datacard.write("offline_btag_eff_p0 param 6.78251e-03 3.82505e-04\n") datacard.write("offline_btag_eff_p1 param -9.55614e-06 1.13679e-06\n") datacard.write("offline_btag_eff_p2 param 4.39468e-09 7.90724e-10\n") elif eta_region == "eta2p2": datacard.write("offline_btag_eff_p0 param -1.72721e-03 3.04992e-05\n") datacard.write("offline_btag_eff_p1 param 1.72562e-06 3.23472e-08\n") datacard.write("offline_btag_eff_p2 param 8.74866e-03 7.81413e-05\n") datacard.write("offline_btag_eff_p3 param -1.67123e-03 4.30607e-05\n") # Current decision: don't put in nuisance parameters for trigger efficiency sigmoid. Impact is likely small. #if args.fitTrigger: # if "bbl" in args.analysis or "eta1p7" in args.analysis: # datacard.write("alpha_trigeff_p0 param {} {}\n".format(0.0, 1.0)) # datacard.write("alpha_trigeff_p1 param {} {}\n".format(0.0, 1.0)) # Background fit parameters --- flat prior datacard.write('background_' + fit_function + '_norm flatParam\n') for par_name, par in background_parameters[fit_function].iteritems(): datacard.write(fit_function + "_" + par_name + ' flatParam\n') datacard.close() print "[create_datacards] INFO : Done with this datacard" #print '>> Datacards and workspaces created and stored in %s/'%( os.path.join(os.getcwd(),args.output_path) ) print "Done with mass {}.".format(mass)