def find_strongest_evaluators(list_of_evaluators, n_best): """ Finds the n_best strongest of all evaluators in given list or dict """ def flat(d, out=[]): """ Transforms a dict of dicts of dicts ... into a single list """ for val in d.values(): if isinstance(val, dict): flat(val, out) else: out += [val,] return out list_of_evaluators = flat(list_of_evaluators) if n_best != 0 and len(list_of_evaluators) == 0: AdvPrint.cerr_exit("evaluator::find_strongest_evaluator \n Cannot find strongest out of 0 evaluators!") # Sort evaluators by cls_exp first best_evaluators = sorted(list_of_evaluators, key=operator.attrgetter('cls_exp')) # If the best evaluator has cls_exp which is not -1, it means that indeed # all considered evaluators had a properly evaluated cls_exp if best_evaluators[0].cls_exp != -1: if n_best == 1: return best_evaluators[0] else: return best_evaluators[:n_best] # otherwise, sort again but now with respect to r_exp_cons best_evaluators = sorted(list_of_evaluators, key=operator.attrgetter('r_exp_cons')) best_evaluators.reverse() # largest r first if n_best == 1: return best_evaluators[0] else: return best_evaluators[:n_best]
def combine_processes(self, other): """ In case of an "add" run, the user might add new events to a given process """ if self.name != other.name: AdvPrint.cerr_exit("'add' feature tried to combine incompatible processes (different names)") for other_ev in other.eventsList: self.eventsList.append(other_ev)
def line_from_data(self, columns): """ Returns the information stated in the list 'columns' as a single line """ line = "" for c in columns: c = c.lower().strip() if c.lower() in ['name', 'id', 'identifier']: line += str(self.name)+" " elif c.lower() in ['analysis', 'ana']: line += str(self.analysis)+" " elif c.lower() in ['sr', 'signalregion']: line += str(self.sr)+" " elif c.lower() in ['totalmc', 'totalmcevents','total_mcevents']: line += str(self.total_mcevents)+" " elif c.lower() in ['totalnorm', 'totalnormevents','total_normevents']: line += str(self.total_normevents)+" " elif c.lower() in ['totalsw', 'totalsumofweights','total_sumofweights']: line += str(self.total_sumofweights)+" " elif c.lower() in ['totalsw2', 'totalsumofweights2','total_sumofweights2']: line += str(self.total_sumofweights2)+" " elif c.lower() in ['signalsw', 'signalsumofweights','signal_sumofweights']: line += str(self.signal_sumofweights)+" " elif c.lower() in ['signalsw2', 'signalsumofweights2','signal_sumofweights2']: line += str(self.signal_sumofweights2)+" " elif c.lower() in ['signalnorm', 'signalnormevents', "signal_normevents", "s"]: line += str(self.signal_normevents)+" " elif c.lower() in ['signalerrstat', 'signal_err_stat', 'signalerrstat', 'sig_err_stat']: line += str(self.signal_err_stat)+" " elif c.lower() in ['signalerrsys', 'signal_err_sys', 'signalerrsys', 'sig_err_sys']: line += str(self.signal_err_sys)+" " elif c.lower() in ['signalerrtot', 'signal_err_tot', "ds", 'signalerrtot', 'sig_err_tot']: line += str(self.signal_err_tot)+" " else: AdvPrint.cerr_exit("resultcollector::line_from_data - column "+c+" unknown!") return line
def printInfo(self): AdvPrint.cout("\t\t ROOT events") AdvPrint.cout("\t\t\t - internal identifier: '"+self.identifier+"'") AdvPrint.cout("\t\t\t - path to eventfile: "+self.full_filename) if self.maxEvents > 0: AdvPrint.cout("\t\t\t - at most "+str(self.maxEvents)+" events are analysed") if self.processed: AdvPrint.cout("\t\t\t [Events already processed, results from earlier run are used!]")
def printLogo(self): """ Obvious""" AdvPrint.cout( """ ____ _ _ __ __ _ _____ _____ ____ / ___| |__ ___ ___| | _| \/ | / \|_ _| ____|___ \ | | | '_ \ / _ \/ __| |/ / |\/| | / _ \ | | | _| __) | | |___| | | | __/ (__| <| | | |/ ___ \| | | |___ / __/ \____|_| |_|\___|\___|_|\_\_| |_/_/ \_\_| |_____|_____| """ ) # TODO: add cite info?
def allowed(self): """ Determines from the given result if the corresponding signal is excluded or not""" # If we have CLs, use CLs if self.cls_obs != -1: return self.cls_obs > 0.05 # otherwise, use r-value elif self.r_obs_cons != -1: return self.r_obs_cons < 1 else: AdvPrint.cerr_exit("evaluator::allowed() Cannot determine allowed/excluded without calculating cls or r-value!")
def add_and_sum(self, other): """ Used to add process by process: event numbers are added and errors are added independently """ # only compatible results should be added if self.analysis != other.analysis or self.sr != other.sr: AdvPrint.cerr_exit( "\t resultCollector::add_and_sum() \n \t Only results of the same analysis and same signal region can be added!" ) # When summing the weights, each subsample has to be properly reweighted: The overall contribtuion should only be proportional to the cross section i.e. totalnormevents. # It should not depend on the MC size of the sample which hence should be divided out. # If 'self' is 0, then the weights are trivially just 'other': if self.total_normevents == 0: weight_self = 0 weight_other = 1 # If 'other' is 0, then the weights are trivially just 'self': elif other.total_normevents == 0: weight_self = 1 weight_other = 0 # otherwise, evaluate weights properly else: weight_self = self.total_normevents / ( other.total_normevents + self.total_normevents) * ( self.total_sumofweights + other.total_sumofweights) / self.total_sumofweights weight_other = other.total_normevents / ( other.total_normevents + self.total_normevents) * ( self.total_sumofweights + other.total_sumofweights) / other.total_sumofweights self.total_mcevents = self.total_mcevents + other.total_mcevents self.total_normevents = self.total_normevents + other.total_normevents # Note thatw weight_self and weight_other are normalised such that self.total_sow * weight_self + other.total_sow * weight_other = self.total_sow + other.total_sow self.total_sumofweights = self.total_sumofweights + other.total_sumofweights self.total_sumofweights2 = self.total_sumofweights2 * weight_self**2 + other.total_sumofweights2 * weight_other**2 self.signal_sumofweights = self.signal_sumofweights * weight_self + other.signal_sumofweights * weight_other self.signal_sumofweights2 = self.signal_sumofweights2 * weight_self**2 + other.signal_sumofweights2 * weight_other**2 self.signal_normevents = self.signal_normevents + other.signal_normevents # note that doing signal_sumofweights/total_sumofweights * total_normevents yields the same! if Info.flags['no_mc_stat_err']: self.signal_err_stat = 0.0 else: self.signal_err_stat = sqrt( self.signal_err_stat**2 + other.signal_err_stat**2 ) # Added in quadrature. Using signal_sumogweights2 yields almost same result (except for the N=0 staterror which comes for each process) self.signal_err_sys = sqrt( self.signal_err_sys**2 + other.signal_err_sys**2) # Added in quadrature self.signal_err_tot = sqrt(self.signal_err_stat**2 + self.signal_err_sys**2)
def allowed(self): """ Determines from the given result if the corresponding signal is excluded or not""" # If we have CLs, use CLs if self.cls_obs != -1: return self.cls_obs > 0.05 # otherwise, use r-value elif self.r_obs_cons != -1: return self.r_obs_cons < 1 else: AdvPrint.cerr_exit( "evaluator::allowed() Cannot determine allowed/excluded without calculating cls or r-value!" )
def setup_pythia8_for_lhe_showering(self): out_path = Info.paths['output_pythia'] procnum = len(Info.files['pythia_cards']) filename = self.name + "card_" + str(procnum) + ".in" fpath = os.path.join(out_path, filename) with open(fpath, 'w') as f: # generate LHE showering card with hepmc output with open(Info.files['pythia_lhe_template'], 'r') as default: for line in default: f.write(line) if len(Info.files["slha"]) > 0: f.write('SLHA:file = ') f.write(Info.files["slha"] + '\n') iRun = 0 run_str = list() for lhe_filename in self.full_filenames: # Check file exists, else skip file if not os.path.isfile(lhe_filename): AdvPrint.cerr( "\t Process:genPy8card():: File not readable:" + lhe_filename) continue iRun += 1 run_str.append("Main:subrun = " + str(iRun) + "\n") if iRun == 1: run_str.append("Beams:frameType = 4\n") else: run_str.append("Beams:newLHEFsameInit = on\n") run_str.append("Beams:LHEF = " + lhe_filename + "\n\n") # Exit if no valid files if iRun < 1: AdvPrint.cerr_exit( "\t Process:genPy8card():: No valid LHE files found") # Write out all subruns if iRun > 1: subrun_str = "Main:numberOfSubruns = " + str(iRun) f.write(subrun_str + '\n\n') for line in run_str: f.write(line) else: f.write("Beams:frameType = 4\n") f.write("Beams:LHEF = " + lhe_filename + "\n\n") default.close() Info.files['pythia_cards'].append(fpath) self.py8_infile = fpath
def __init__(self, name): # Note that the below condition should fail if this __ini__ condition is called from a derived class, as self.__class__.__name__ should be the daughter class name! if self.__class__.__name__ == "Events": AdvPrint.cerr_exit("Internal error: Instance of abstract base class 'Events' created!") self.name = name Info.book_events(self) # sets identifier self.processed = False self.analysis_result_files = dict() self.analysis_signal_files = dict() self.analysis_cutflow_files = dict() self.maxEvents = -1 self.result_output_file = "" self.fritz_config_file = ""
def setup_pythia8_for_lhe_showering(self): out_path = Info.paths['output_pythia'] procnum = len(Info.files['pythia_cards']) filename = self.name+"card_"+str(procnum)+".in" fpath = os.path.join(out_path,filename) with open(fpath,'w') as f: # generate LHE showering card with hepmc output with open(Info.files['pythia_lhe_template'],'r') as default: for line in default: f.write(line) if len(Info.files["slha"]) > 0 : f.write('SLHA:file = ') f.write(Info.files["slha"] + '\n') iRun = 0 run_str = list() for lhe_filename in self.full_filenames: # Check file exists, else skip file if not os.path.isfile(lhe_filename): AdvPrint.cerr("\t Process:genPy8card():: File not readable:"+lhe_filename) continue iRun+=1 run_str.append("Main:subrun = "+str(iRun)+"\n") if iRun == 1: run_str.append("Beams:frameType = 4\n") else: run_str.append("Beams:newLHEFsameInit = on\n") run_str.append("Beams:LHEF = "+lhe_filename+"\n\n") # Exit if no valid files if iRun < 1: AdvPrint.cerr_exit("\t Process:genPy8card():: No valid LHE files found") # Write out all subruns if iRun > 1: subrun_str = "Main:numberOfSubruns = "+str(iRun) f.write( subrun_str + '\n\n' ) for line in run_str: f.write(line) else: f.write("Beams:frameType = 4\n") f.write("Beams:LHEF = "+lhe_filename+"\n\n") default.close() Info.files['pythia_cards'].append(fpath) self.py8_infile = fpath
def __init__(self, name): # Note that the below condition should fail if this __ini__ condition is called from a derived class, as self.__class__.__name__ should be the daughter class name! if self.__class__.__name__ == "Events": AdvPrint.cerr_exit( "Internal error: Instance of abstract base class 'Events' created!" ) self.name = name Info.book_events(self) # sets identifier self.processed = False self.analysis_result_files = dict() self.analysis_signal_files = dict() self.analysis_cutflow_files = dict() self.maxEvents = -1 self.result_output_file = "" self.fritz_config_file = ""
def prepare(self): Pythia8Events.prepare(self) if self.commandstring != "": self.mg5_cards["proc"] = os.path.join( Info.paths["output_mg5"], self.identifier + "_proc_card.dat") with open(self.mg5_cards["proc"], "w") as f: f.write(self.commandstring) if self.mg5_cards["param"] == "" and Info.files["slha"] != "": self.mg5_cards["param"] = Info.files["slha"] if self.py8_infile == "": self.py8_infile = os.path.join(Info.paths["output_pythia"], self.identifier + "_showercard.in") with open(self.py8_infile, "w") as f: with open(Info.files['pythia_mg5minimal_template'], "r") as g: for line in g: f.write(line) f.write("SLHA:file = " + self.mg5_cards["param"] + "\n") if self.mg5_cards["run"] == "": # copy template and fill rlevant information self.mg5_cards["run"] = os.path.join( Info.paths["output_mg5"], self.identifier + "_run_card.dat") with open(self.mg5_cards["run"], "w") as f_out: with open(Info.files["mg5_run_template"], "r") as f_in: for line in f_in: ecmhalf = str( float(Info.parameters["ecm"]) * 1000. / 2.) if self.maxEvents == -1: AdvPrint.cout( "\t " + self.name + ":prepare(): Setting number of to-be-generated events to 5000. Use --maxevents parameter to change this behaviour." ) self.maxEvents = 5000 nevents = str(self.maxEvents) seed = str(Info.parameters["randomseed"]) line = line.replace("@ecmhalf@", ecmhalf).replace( "@nevents@", nevents).replace("@seed@", seed) f_out.write(line) if self.mg5_cards["config"] == "": # copy template and fill rlevant information self.mg5_cards["config"] = os.path.join( Info.paths["output_mg5"], self.identifier + "_me5_configuration.txt") with open(self.mg5_cards["config"], "w") as f: with open(Info.files["me5_configuration_template"], "r") as g: for line in g: f.write(line)
def add_and_sum(self, other): """ Used to add process by process: event numbers are added and errors are added independently """ # only compatible results should be added if self.analysis != other.analysis or self.sr != other.sr: AdvPrint.cerr_exit("\t resultCollector::add_and_sum() \n \t Only results of the same analysis and same signal region can be added!") # When summing the weights, each subsample has to be properly reweighted: The overall contribtuion should only be proportional to the cross section i.e. totalnormevents. # It should not depend on the MC size of the sample which hence should be divided out. # If 'self' is 0, then the weights are trivially just 'other': if self.total_normevents == 0: weight_self = 0 weight_other = 1 # If 'other' is 0, then the weights are trivially just 'self': elif other.total_normevents == 0: weight_self = 1 weight_other = 0 # otherwise, evaluate weights properly else: weight_self = self.total_normevents / (other.total_normevents + self.total_normevents) * (self.total_sumofweights + other.total_sumofweights)/self.total_sumofweights weight_other = other.total_normevents / (other.total_normevents + self.total_normevents) * (self.total_sumofweights + other.total_sumofweights)/other.total_sumofweights self.total_mcevents = self.total_mcevents + other.total_mcevents self.total_normevents = self.total_normevents + other.total_normevents # Note thatw weight_self and weight_other are normalised such that self.total_sow * weight_self + other.total_sow * weight_other = self.total_sow + other.total_sow self.total_sumofweights = self.total_sumofweights + other.total_sumofweights self.total_sumofweights2 = self.total_sumofweights2 * weight_self**2 + other.total_sumofweights2 * weight_other**2 self.signal_sumofweights = self.signal_sumofweights * weight_self + other.signal_sumofweights * weight_other self.signal_sumofweights2 = self.signal_sumofweights2 * weight_self**2 + other.signal_sumofweights2 * weight_other**2 self.signal_normevents = self.signal_normevents + other.signal_normevents # note that doing signal_sumofweights/total_sumofweights * total_normevents yields the same! if Info.flags['no_mc_stat_err']: self.signal_err_stat = 0.0 else: self.signal_err_stat = sqrt(self.signal_err_stat**2 + other.signal_err_stat**2) # Added in quadrature. Using signal_sumogweights2 yields almost same result (except for the N=0 staterror which comes for each process) self.signal_err_sys = sqrt(self.signal_err_sys**2 + other.signal_err_sys**2) # Added in quadrature self.signal_err_tot = sqrt(self.signal_err_stat**2+self.signal_err_sys**2)
def checkInputConsistency(self): """ Checks if the amount of input information given is sufficient to run CheckMATE2 """ # Case 1: no process, no eventfile, no setting if len(self.eventsList) < 1: self.printInfo() AdvPrint.cerr_exit( "\t " + self.name + "::checkInputConsistency():: \n \t" "There are no events to generate and/or analyse") # Case 3: Both k-factor and cross section are non-zero if self.xsec != 0.0 and self.kfac != 0.0: AdvPrint.cerr_exit( "\t " + self.name + ":checkInputConsistency():: \n \t " "Either enter Kfactor or total cross section (which might be Kfactor * LO-cross section)!" ) for e in self.eventsList: from events import DelphesEvents if isinstance(e, DelphesEvents) and len(Info.used_experiments) > 1: AdvPrint.cerr_exit( "\t " + self.name + "::checkInputConsistency():: \n \t" "If you provide a .root file you cannot run analyses that need different detector settings." "Please only run analyses of the experiment the .root file was simulated with " "in Delphes!") for events in self.eventsList: events.check()
def load(self, filename): """ Loads contents for current instance from a valid file """ with open(filename, "r") as f: contents = json.load(f) try: # processes = old processes plus added new ones of current run newProcList = self.procList self.procList = pickle.loads(contents["procList"]) for new_p in newProcList: combined = False for old_p in self.procList: if old_p.name == new_p.name: old_p.combine_processes(new_p) combined = True break if not combined: self.procList.append(new_p) except KeyError: AdvPrint.cerr_exit("Problem loading info file "+inputfile) return self
def __init__(self): #global Info, AdvPrint """ Initialisation of a CheckMATE object leads to an entire run of the CheckMATE procedure""" # Initialisation steps #Info.init() Info.fill_standard_paths_and_files() if len(sys.argv) == 1: self.printUsage() self.printLogo() if len(sys.argv) == 2 and sys.argv[-1] != "-h": Info.fill_info_from_file(sys.argv[1]) self.procList = Info.fill_processes_from_file(sys.argv[1]) else: Info.fill_info_from_parameters() self.procList = Info.fill_processes_from_parameters() if Info.parameters["outputexists"] == "add": self.load(Info.files['internal_processes']) for p in self.procList: p.checkInputConsistency() self.user_param_check() self.prepare_run() # Running the event-based part if self.procList == []: AdvPrint.cerr_exit("No processes are loaded!") for p in self.procList: p.prepare() p.run() AdvPrint.cout("\n") # Evaluate if not Info.flags['skipevaluation']: self.evaluate() # Store internal status Info.save(Info.files['internal_info']) self.save(Info.files['internal_processes'])
def find_strongest_evaluators(list_of_evaluators, n_best): """ Finds the n_best strongest of all evaluators in given list or dict """ def flat(d, out=[]): """ Transforms a dict of dicts of dicts ... into a single list """ for val in d.values(): if isinstance(val, dict): flat(val, out) else: out += [ val, ] return out list_of_evaluators = flat(list_of_evaluators) if n_best != 0 and len(list_of_evaluators) == 0: AdvPrint.cerr_exit( "evaluator::find_strongest_evaluator \n Cannot find strongest out of 0 evaluators!" ) # Sort evaluators by cls_exp first best_evaluators = sorted(list_of_evaluators, key=operator.attrgetter('cls_exp')) # If the best evaluator has cls_exp which is not -1, it means that indeed # all considered evaluators had a properly evaluated cls_exp if best_evaluators[0].cls_exp != -1: if n_best == 1: return best_evaluators[0] else: return best_evaluators[:n_best] # otherwise, sort again but now with respect to r_exp_cons best_evaluators = sorted(list_of_evaluators, key=operator.attrgetter('r_exp_cons')) best_evaluators.reverse() # largest r first if n_best == 1: return best_evaluators[0] else: return best_evaluators[:n_best]
def prepare(self): Pythia8Events.prepare(self) if self.commandstring != "": self.mg5_cards["proc"] = os.path.join(Info.paths["output_mg5"], self.identifier+"_proc_card.dat") with open(self.mg5_cards["proc"], "w") as f: f.write(self.commandstring) if self.mg5_cards["param"] == "" and Info.files["slha"] != "": self.mg5_cards["param"] = Info.files["slha"] if self.py8_infile == "": self.py8_infile = os.path.join(Info.paths["output_pythia"], self.identifier+"_showercard.in") with open(self.py8_infile, "w") as f: with open(Info.files['pythia_mg5minimal_template'], "r") as g: for line in g: f.write(line) f.write("SLHA:file = "+self.mg5_cards["param"]+"\n") if self.mg5_cards["run"] == "": # copy template and fill rlevant information self.mg5_cards["run"] = os.path.join(Info.paths["output_mg5"], self.identifier+"_run_card.dat") with open(self.mg5_cards["run"], "w") as f_out: with open(Info.files["mg5_run_template"], "r") as f_in: for line in f_in: ecmhalf = str(float(Info.parameters["ecm"])*1000./2.) if self.maxEvents == -1: AdvPrint.cout("\t "+self.name+":prepare(): Setting number of to-be-generated events to 5000. Use --maxevents parameter to change this behaviour.") self.maxEvents = 5000 nevents = str(self.maxEvents) seed = str(Info.parameters["randomseed"]) line = line.replace("@ecmhalf@", ecmhalf).replace("@nevents@", nevents).replace("@seed@", seed) f_out.write(line) if self.mg5_cards["config"] == "": # copy template and fill rlevant information self.mg5_cards["config"] = os.path.join(Info.paths["output_mg5"], self.identifier+"_me5_configuration.txt") with open(self.mg5_cards["config"], "w") as f: with open(Info.files["me5_configuration_template"], "r") as g: for line in g: f.write(line)
def load_expdata(self): analysis = self.resultCollector.analysis if analysis == "": return # for pseudo-evaluators sr = self.resultCollector.sr parameters = Info.get_analysis_parameters(analysis) # S95 comparison: r value compares lower s95 limit on s (which is almost 2 sigma) to the model independent limit if sr not in parameters["reference_data"]: AdvPrint.cerr_exit("evaluator::load_expdata unknown signal region "+analysis+" - "+sr) if "S95_obs" not in parameters["reference_data"][sr]: AdvPrint.cerr_exit("evaluator::load_expdata S95_obs value is unknown for "+analysis+" - "+sr) self.s95_obs = float(parameters["reference_data"][sr]["S95_obs"]) # If no expected upper limit is given, observed limit is used if "S95_exp" not in parameters["reference_data"][sr]: self.s95_exp = self.s95_obs self.warnings.append("No expected limit could be found in reference data. Using expected = observed.") else: self.s95_exp = float(parameters["reference_data"][sr]["S95_exp"]) if "obs" not in parameters["reference_data"][sr]: AdvPrint.cerr_exit("evaluator::load_expdata 'obs' is unknown for "+analysis+" - "+sr) self.obs = float(parameters["reference_data"][sr]["obs"]) if "bkg" not in parameters["reference_data"][sr]: AdvPrint.cerr_exit("evaluator::load_expdata 'bkg' is unknown for "+analysis+" - "+sr) self.bkg = float(parameters["reference_data"][sr]["bkg"]) self.bkg_err = -1 if "bkg_err" in parameters["reference_data"][sr]: self.bkg_err = float(parameters["reference_data"][sr]["bkg_err"]) elif "bkg_errp" in parameters["reference_data"][sr]: # Asymmetric error: as a rough approximation, use the mean of the squares self.bkg_err = sqrt(float(parameters["reference_data"][sr]["bkg_errp"])**2 + float(parameters["reference_data"][sr]["bkg_errm"])**2)/sqrt(2.) elif "bkg_err_sys" in parameters["reference_data"][sr]: # Total error = independent quadratic sum of statistical and systematical component self.bkg_err = sqrt(float(parameters["reference_data"][sr]["bkg_err_stat"])**2 + float(parameters["reference_data"][sr]["bkg_err_sys"])**2 ) elif "bkg_err_sysp" in parameters["reference_data"][sr]: self.bkg_err = sqrt(float(parameters["reference_data"][sr]["bkg_err_stat"])**2 + (float(parameters["reference_data"][sr]["bkg_err_sysp"])**2)/2. + (float(parameters["reference_data"][sr]["bkg_err_sysp"])**2)/2.)
def checkInputConsistency(self): """ Checks if the amount of input information given is sufficient to run CheckMATE2 """ # Case 1: no process, no eventfile, no setting if len(self.eventsList) < 1: self.printInfo() AdvPrint.cerr_exit("\t "+self.name+"::checkInputConsistency():: \n \t" "There are no events to generate and/or analyse") # Case 3: Both k-factor and cross section are non-zero if self.xsec != 0.0 and self.kfac != 0.0: AdvPrint.cerr_exit("\t "+self.name+":checkInputConsistency():: \n \t " "Either enter Kfactor or total cross section (which might be Kfactor * LO-cross section)!") for e in self.eventsList: from events import DelphesEvents if isinstance(e, DelphesEvents) and len(Info.used_experiments) > 1: AdvPrint.cerr_exit("\t "+self.name+"::checkInputConsistency():: \n \t" "If you provide a .root file you cannot run analyses that need different detector settings." "Please only run analyses of the experiment the .root file was simulated with " "in Delphes!") for events in self.eventsList: events.check()
def printInfo(self): AdvPrint.cout("\t\tLHE Events") AdvPrint.cout("\t\t\t - internal identifier: '" + self.identifier + "'") counter = 1 for filename in self.full_filenames: if len(self.full_filenames) == 1: AdvPrint.cout("\t\t\t - path to .lhe file: " + filename) else: AdvPrint.cout("\t\t\t - path to .lhe file #" + str(counter) + ": " + filename) counter += 1 if self.py8_infile != "": AdvPrint.cout( "\t\t\t - Pythia8 .in settings file for showering: " + self.py8_infile) if self.maxEvents > 0: AdvPrint.cout("\t\t\t - at most " + str(self.maxEvents) + " events are generated/analysed") if self.processed: AdvPrint.cout( "\t\t\t [Events already processed, results from earlier run are used!]" )
def setup_pythia8_from_process_string(self): """ Generates Pythia8 input card """ out_path = Info.paths['output_pythia'] procnum = len(Info.files['pythia_cards']) filename = self.name + "card_" + str(procnum) + ".in" fpath = os.path.join(out_path, filename) f = open(fpath, 'w') # Part 2: Generate cards based on process string part = self.processString.split('>')[1].strip() proclist = list() if part == 'go go': proclist.append('SUSY:gg2gluinogluino = on\n') proclist.append('SUSY:qqbar2gluinogluino = on\n') elif part == 'go sq': proclist.append('SUSY:qg2squarkgluino = on\n') proclist.append( 'SUSY:idVecA = 1000001,1000002,1000003,1000004,2000001,2000002,2000003,2000004' ) elif part == 'sq sq~': proclist.append('SUSY:gg2squarkantisquark = on\n') proclist.append('SUSY:qqbar2squarkantisquark = on\n') proclist.append( 'SUSY:idVecA = 1000001,1000002,1000003,1000004,2000001,2000002,2000003,2000004' ) elif part == 't1 t1~': proclist.append('SUSY:gg2squarkantisquark = on\n') proclist.append('SUSY:qqbar2squarkantisquark = on\n') proclist.append('SUSY:idA = 1000006\n') elif part == '3gen': proclist.append('SUSY:gg2squarkantisquark = on\n') proclist.append('SUSY:qqbar2squarkantisquark = on\n') proclist.append('SUSY:qq2squarksquark = on\n') proclist.append('SUSY:idVecA = 1000005,100006,2000005,2000006\n') elif part == 'sq sq': proclist.append('SUSY:qq2squarksquark = on\n') proclist.append( 'SUSY:idVecA = 1000001,1000002,1000003,1000004,2000001,2000002,2000003,2000004\n' ) elif part.lower() == "ewsusy": proclist.append('SUSY:qqbar2chi0chi0 = on\n') proclist.append('SUSY:qqbar2chi+-chi0 = on\n') proclist.append('SUSY:qqbar2chi+chi- = on\n') elif part.lower() == "colsusy": proclist.append('SUSY:gg2gluinogluino = on\n') proclist.append('SUSY:qqbar2gluinogluino = on\n') proclist.append('SUSY:qg2squarkgluino = on\n') proclist.append('SUSY:gg2squarkantisquark = on\n') proclist.append('SUSY:qqbar2squarkantisquark = on\n') proclist.append('SUSY:qq2squarksquark = on\n') proclist.append( 'SUSY:idVecA = 1000001,1000002,1000003,1000004,1000005,100006,2000001,2000002,2000003,2000004,2000005,2000006\n' ) elif part.lower() == "allsusy": proclist.append('SUSY:all = on\n') else: AdvPrint.cerr_exit( "\t Process:genPy8card():: Cannot understand process " + part) # Write Pythia cards ecm_str = "Beams:eCM = 8000.\n" if (float(Info.parameters["ecm"]) == 7.0): ecm_str = "Beams:eCM = 7000.\n" elif (float(Info.parameters["ecm"]) == 13.0): ecm_str = "Beams:eCM = 13000.\n" elif (float(Info.parameters["ecm"]) == 14.0): ecm_str = "Beams:eCM = 14000.\n" if len(proclist) == 0: AdvPrint.cerr_exit("No processes found") default = open(Info.files['pythia_settings_template'], 'r') slhafile = Info.files['slha'] for line in default: f.write(line) f.write(ecm_str + '\n') if len(slhafile) > 0: f.write('SLHA:file = ') f.write(slhafile + '\n') else: AdvPrint.cerr_exit("\t Process:genPy8card():: No SLHA file found") for item in proclist: f.write(item) default.close() # if no maximal number set, set number of generated events to 5000 if self.maxEvents == -1: AdvPrint.cout( "\t " + self.name + ":genPy8card(): Setting number of to-be-generated events to 5000. Use --maxevents parameter to change this behaviour." ) self.maxEvents = 5000 f.close() Info.files['pythia_cards'].append(fpath) self.py8_infile = fpath
def printInfo(self): AdvPrint.cout("\tProcess Name: " + self.name) if self.have_xsect: AdvPrint.cout("\tInput Cross section: " + str(self.xsec) + " " + str(self.xsec_unit)) if self.have_xerr: AdvPrint.cout("\tInput cross section error: " + str(self.xerr) + " " + str(self.xerr_unit)) elif self.have_kfac: AdvPrint.cout("\tInput KFactor: " + str(self.kfac)) eventsList = [ef for ef in self.eventsList] if len(eventsList) != 0: AdvPrint.cout( "\tAssociated event files and/or Monte-Carlo generation runs:") for ef in eventsList: ef.printInfo() AdvPrint.cout("") AdvPrint.cout("")
def check(self): if self.mg5_cards["proc"] == "" and self.commandstring == "": AdvPrint.cerr_exit("Error in MG5Events object "+self.name+":\n\t Neither a proc card nor a command string was provided!")
def _print_likelihood(evaluators): tot_likeli = 0. dict_likeli = {} for analysis, v in evaluators.iteritems(): ana_likeli =0. AdvPrint.set_cout_file(Info.files['output_evaluation_likelihood'][analysis], True) AdvPrint.mute() AdvPrint.cout("SR o b db s ds likeli") for sr, ev in v.iteritems(): AdvPrint.cout(sr+" " +str(float(ev.obs))+" " +str(float(ev.bkg))+" " +str(float(ev.bkg_err))+" " +str(ev.resultCollector.signal_normevents)+" " +str(ev.resultCollector.signal_err_tot)+" " +str(ev.likelihood)) ana_likeli += ev.likelihood AdvPrint.format_columnated_file(Info.files['output_evaluation_likelihood'][analysis]) AdvPrint.set_cout_file("#None") AdvPrint.unmute() dict_likeli[analysis] = ana_likeli tot_likeli += ana_likeli AdvPrint.set_cout_file(Info.files['likelihood'], True) AdvPrint.mute() AdvPrint.cout("Analysis -2lnL") for a in dict_likeli: AdvPrint.cout(a+" "+str(dict_likeli[a])) AdvPrint.cout("\nTotal: "+str(tot_likeli)) AdvPrint.format_columnated_file(Info.files['likelihood'])
def get_resultCollectors(self): resultCollectors = dict( ) # list of all collectors of all analyses and all signal regions resultCollector = ResultCollector( self.identifier, "", "") # base collector object which we will just edit and copy for analysis in Info.analyses: # check if results file exists if not os.path.isfile(self.analysis_signal_files[analysis]): AdvPrint.cerr_exit( "\t events::get_resultCollector() \n" "\t Required analysis result file does not exist: \n " "\t\t" + self.analysis_signal_files[analysis] + "\n" "\t It is very likely that something went wrong in the delphes and/or the analysis step. \n" "\t Please check \n " "\t \t " + Info.files['delphes_log'] + " \n " "\t \t " + Info.files['analysis_log'] + "* \n " "\t for error messages and, should you not be able to fix them yourself, contact the authors under \n" "\t \t [email protected]") # setup resultCollector object resultCollector.analysis = analysis resultCollectors[analysis] = dict() signal_regions = Info.get_analysis_parameters( analysis)["signal_regions"] # Read result file f = open(self.analysis_signal_files[analysis], "r") for line in f: # Ignore empty or commented lines line = line.rstrip() if line == "" or line[0] == "#": continue # Read file: line = AdvPrint.remove_extra_spaces(line) tokens = [t for t in line.split(" ") if t != ""] # First, read information on total events number if tokens[0] == "MCEvents:": resultCollector.total_mcevents = float(tokens[1]) elif tokens[0] == " SumOfWeights:": resultCollector.total_sumofweights = float(tokens[1]) elif tokens[0] == " SumOfWeights2:": resultCollector.total_sumofweights2 = float(tokens[1]) elif tokens[0] == " NormEvents:": resultCollector.total_normevents = float(tokens[1]) elif tokens[0] == "XSect:": xsect = float(tokens[1].split(" ")[0]) elif tokens[0] == " Error:": xsecterr = float(tokens[1].split(" ")[0]) else: # SR Sum_W Sum_W2 Acc N_Norm for sr in signal_regions: if tokens[0].startswith(sr): resultCollector.sr = sr # Read number of events resultCollector.signal_sumofweights = float( tokens[1]) resultCollector.signal_sumofweights2 = float( tokens[2]) resultCollector.signal_normevents = float( tokens[4]) # Calculate errors if resultCollector.signal_sumofweights > 0: resultCollector.signal_err_stat = resultCollector.signal_normevents * sqrt( resultCollector.signal_sumofweights2 ) / resultCollector.signal_sumofweights resultCollector.signal_err_sys = resultCollector.signal_normevents * xsecterr / xsect resultCollector.signal_err_tot = sqrt( resultCollector.signal_err_stat**2 + resultCollector.signal_err_sys**2) else: resultCollector.signal_err_stat = 0 resultCollector.signal_err_sys = 0 resultCollector.signal_err_tot = 0 # put copy of resultCollector in collector dict resultCollectors[analysis][sr] = deepcopy( resultCollector) f.close() # Write events file, if wanted if Info.parameters["EventResultFileColumns"] != []: AdvPrint.mute() AdvPrint.set_cout_file(self.result_output_file, True) for col in Info.parameters["EventResultFileColumns"]: AdvPrint.cout(col + " ", "nlb") AdvPrint.cout("") for a in sorted(resultCollectors.keys()): for sr in sorted(resultCollectors[a].keys()): AdvPrint.cout(resultCollectors[a][sr].line_from_data( Info.parameters["EventResultFileColumns"])) AdvPrint.format_columnated_file(self.result_output_file) AdvPrint.set_cout_file("#None") AdvPrint.unmute() return resultCollectors
def print_result(self): AdvPrint.set_cout_file(Info.files["output_result"], True) if self.cls_obs != -1: AdvPrint.cout( "Test: Calculation of CLs(S, dS, B, dB, O) using profile likelihood" ) elif self.likelihood != -1: AdvPrint.cout( "Test: Calculation of approximate (fast) likelihood given in results folder" ) elif self.r_obs != -1: AdvPrint.cout( "Test: Calculation of r = signal/(95%CL limit on signal)") else: AdvPrint.cerr_exit( "evaluator::printResult(): No result has been evaluated!") for w in self.warnings: AdvPrint.cout("\033[33mWarning: " + w + "\033[0m") result = "\033[31mExcluded\033[0m" if self.allowed(): result = "\033[32mAllowed\033[0m" AdvPrint.cout("Result: " + result) if self.cls_obs != -1: AdvPrint.cout("Result for CLs: " + str(self.cls_obs)) #if self.likelihood != -1: # AdvPrint.cout("Result for likelihood: "+str(self.likelihood)) elif self.r_obs != -1: AdvPrint.cout("Result for r: " + str(self.r_obs_cons)) else: AdvPrint.cerr_exit( "evaluator::printResult(): No result has been evaluated!") AdvPrint.cout("Analysis: " + self.resultCollector.analysis) AdvPrint.cout("SR: " + self.resultCollector.sr) AdvPrint.set_cout_file("#None")
def line_from_data(self, columns): """ Returns the information stated in the list 'columns' as a single line """ line = "" for c in columns: c = c.lower().strip() if c.lower() in ['name', 'id', 'identifier']: line += str(self.resultCollector.name) + " " elif c.lower() in ['analysis', 'ana']: line += str(self.resultCollector.analysis) + " " elif c.lower() in ['sr', 'signalregion']: line += str(self.resultCollector.sr) + " " elif c.lower() in ['totalmc', 'totalmcevents']: line += str(self.resultCollector.total_mcevents) + " " elif c.lower() in ['totalnorm', 'totalnormevents']: line += str(self.resultCollector.total_normevents) + " " elif c.lower() in ['totalsw', 'totalsumofweights']: line += str(self.resultCollector.total_sumofweights) + " " elif c.lower() in ['totalsw2', 'totalsumofweights2']: line += str(self.resultCollector.total_sumofweights2) + " " elif c.lower() in ['signalsw', 'signalsumofweights']: line += str(self.resultCollector.signal_sumofweights) + " " elif c.lower() in ['signalsw2', 'signalsumofweights2']: line += str(self.resultCollector.signal_sumofweights2) + " " elif c.lower() in ['signalnorm', 'signalnormevents', 's']: line += str(self.resultCollector.signal_normevents) + " " elif c.lower() in ['signalerrstat', 'signal_err_stat']: line += str(self.resultCollector.signal_err_stat) + " " elif c.lower() in ['signalerrsys', 'signal_err_sys']: line += str(self.resultCollector.signal_err_sys) + " " elif c.lower() in ['signalerrtot', 'ds', 'signal_err_tot']: line += str(self.resultCollector.signal_err_tot) + " " elif c.lower() in ['obs', 'o']: line += str(self.obs) + " " elif c.lower() in ['b', 'bkg']: line += str(self.bkg) + " " elif c.lower() in ['db', 'bkgerr']: line += str(self.bkg_err) + " " elif c.lower() in ['signaleff', 'eff']: line += str(self.signal_eff) + " " elif c.lower() in ['signaleff_err_stat', 'eff_err_stat']: line += str(self.signal_eff_error_stat) + " " elif c.lower() in ['signaleff_err_sys', 'eff_err_sys']: line += str(self.signal_eff_error_sys) + " " elif c.lower() in ['signaleff_err_tot', 'eff_err_tot']: line += str(self.signal_eff_error_tot) + " " elif c.lower() in ['s95obs']: line += str(self.s95_obs) + " " elif c.lower() in ['s95exp']: line += str(self.s95_exp) + " " elif c.lower() in ['robs', 'r_obs']: line += str(self.r_obs) + " " elif c.lower() in ['robscons', 'r_obs_cons']: line += str(self.r_obs_cons) + " " elif c.lower() in ['robsconssysonly', 'r_obs_cons_sysonly']: line += str(self.r_obs_cons_sysonly) + " " elif c.lower() in ['rexp', 'r_exp']: line += str(self.r_exp) + " " elif c.lower() in ['rexpcons', 'r_exp_cons']: line += str(self.r_exp_cons) + " " elif c.lower() in ['rexpconssysonly', 'r_exp_cons_sysonly']: line += str(self.r_exp_cons_sysonly) + " " elif c.lower() in ['clsobs', 'cls_obs']: line += str(self.cls_obs) + " " elif c.lower() in ['clsobs_err', 'cls_obs_err']: line += str(self.cls_obs_err) + " " elif c.lower() in ['clsexp', 'cls_exp']: line += str(self.cls_exp) + " " elif c.lower() in ['clsexp_err', 'cls_exp_err']: line += str(self.cls_exp_err) + " " elif c.lower() in ['likelihood']: line += str(self.likelihood) + " " #todoelif c.lower() in ['likelihood']: # line += str(self.likelihood)+" " else: AdvPrint.cerr_exit("evaluator::line_from_data - column " + c + " unknown!") return line
def setup_pythia8_from_process_string(self): """ Generates Pythia8 input card """ out_path = Info.paths['output_pythia'] procnum = len(Info.files['pythia_cards']) filename = self.name+"card_"+str(procnum)+".in" fpath = os.path.join(out_path,filename) f = open(fpath,'w') # Part 2: Generate cards based on process string part = self.processString.split('>')[1].strip() proclist = list() if part == 'go go': proclist.append('SUSY:gg2gluinogluino = on\n') proclist.append('SUSY:qqbar2gluinogluino = on\n') elif part == 'go sq': proclist.append('SUSY:qg2squarkgluino = on\n') proclist.append('SUSY:idVecA = 1000001,1000002,1000003,1000004,2000001,2000002,2000003,2000004') elif part == 'sq sq~': proclist.append('SUSY:gg2squarkantisquark = on\n') proclist.append('SUSY:qqbar2squarkantisquark = on\n') proclist.append('SUSY:idVecA = 1000001,1000002,1000003,1000004,2000001,2000002,2000003,2000004') elif part == 't1 t1~': proclist.append('SUSY:gg2squarkantisquark = on\n') proclist.append('SUSY:qqbar2squarkantisquark = on\n') proclist.append('SUSY:idA = 1000006\n') elif part == '3gen': proclist.append('SUSY:gg2squarkantisquark = on\n') proclist.append('SUSY:qqbar2squarkantisquark = on\n') proclist.append('SUSY:qq2squarksquark = on\n') proclist.append('SUSY:idVecA = 1000005,100006,2000005,2000006\n') elif part == 'sq sq': proclist.append('SUSY:qq2squarksquark = on\n') proclist.append('SUSY:idVecA = 1000001,1000002,1000003,1000004,2000001,2000002,2000003,2000004\n') elif part.lower() == "ewsusy": proclist.append('SUSY:qqbar2chi0chi0 = on\n') proclist.append('SUSY:qqbar2chi+-chi0 = on\n') proclist.append('SUSY:qqbar2chi+chi- = on\n') elif part.lower() == "colsusy": proclist.append('SUSY:gg2gluinogluino = on\n') proclist.append('SUSY:qqbar2gluinogluino = on\n') proclist.append('SUSY:qg2squarkgluino = on\n') proclist.append('SUSY:gg2squarkantisquark = on\n') proclist.append('SUSY:qqbar2squarkantisquark = on\n') proclist.append('SUSY:qq2squarksquark = on\n') proclist.append('SUSY:idVecA = 1000001,1000002,1000003,1000004,1000005,100006,2000001,2000002,2000003,2000004,2000005,2000006\n') elif part.lower() == "allsusy": proclist.append('SUSY:all = on\n') else: AdvPrint.cerr_exit("\t Process:genPy8card():: Cannot understand process " + part) # Write Pythia cards ecm_str = "Beams:eCM = 8000.\n" if(Info.parameters["ecm"] == 7.0): ecm_str = "Beams:eCM = 7000.\n" elif (Info.parameters["ecm"] == 13.0): ecm_str = "Beams:eCM = 13000\n." elif (Info.parameters["ecm"] == 14.0): ecm_str = "Beams:eCM = 14000.\n" if len(proclist) == 0: AdvPrint.cerr_exit("No processes found") default = open(Info.files['pythia_settings_template'],'r') slhafile = Info.files['slha'] for line in default: f.write(line) f.write(ecm_str + '\n' ) if len(slhafile) > 0 : f.write('SLHA:file = ') f.write(slhafile + '\n') else: AdvPrint.cerr_exit("\t Process:genPy8card():: No SLHA file found") for item in proclist: f.write(item) default.close() # if no maximal number set, set number of generated events to 5000 if self.maxEvents == -1: AdvPrint.cout("\t "+self.name+":genPy8card(): Setting number of to-be-generated events to 5000. Use --maxevents parameter to change this behaviour.") self.maxEvents = 5000 f.close() Info.files['pythia_cards'].append(fpath) self.py8_infile = fpath
def runFritz(self): self.prepareFritz() """ Runs Fritz """ from events import MG5Events for event in self.eventsList: if event.processed: continue fritz_command = Info.files["fritz_bin"]+" "+event.configFile result = subprocess.Popen(fritz_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) maxlen = 0 try: for line in iter(result.stdout.readline, b''): # Print to logfile. If it does not start with the Fritz::Global prefix, it comes from MG5 and should be redirected AdvPrint.mute() if not line.startswith("|~| ") and isinstance(event, MG5Events): AdvPrint.set_cout_file(os.path.join(Info.paths["output_mg5"], "mg5amcatnlo_"+event.identifier+".log")) elif "PYTHIA Rndm::dumpState" in line: AdvPrint.set_cout_file(os.path.join(Info.paths["output_pythia"], "pythia_"+event.identifier+".log")) else: line = line.replace("|~| ", "") AdvPrint.set_cout_file(os.path.join(Info.paths["output_fritz"], "fritz_"+event.identifier+".log")) AdvPrint.cout(line.rstrip()) AdvPrint.set_cout_file("#None") AdvPrint.unmute() # We should not exceed the terminal terminal_width: terminal_width = AdvPrint.get_terminal_width() print_line = " |-> "+str(line.strip()) print_line.replace("\t", " ") while "\r" in print_line: print_line = print_line[print_line.index("\r"):] len_of_print_line = len(print_line) maxlen = max(maxlen, len(print_line)) # As we print line by line in the same terminal row, we have to add spaces if the curr line is shorter than a line before fill_spaces = "" if len(print_line) < maxlen: fill_spaces = " "*(maxlen-len(print_line)) # if line is too long, make it shorter by appropriate amoung if len(print_line+fill_spaces) >= terminal_width and len(print_line) <= terminal_width: fill_spaces = " "*(terminal_width - len(print_line)-1) elif len(print_line) > terminal_width: fill_spaces = "" print_line = print_line[:terminal_width-4]+"..." AdvPrint.cout("\r"+print_line+fill_spaces+"\x1b[0m\r", "nlb") except KeyboardInterrupt: AdvPrint.cout("Caught Keyboard Signal. Aborting Fritz") result.send_signal(signal.SIGTERM) for line in iter(result.stderr.readline, b''): AdvPrint.unmute() AdvPrint.set_cout_file(Info.files['fritz_log']) # remove nasty ROOT6-CLING warnings from on-screen output if "cling::AutoloadingVisitor::InsertIntoAutoloadingState:" in line: AdvPrint.mute() elif "Missing FileEntry for ExRootAnalysis" in line: AdvPrint.mute() elif "requested to autoload type" in line: AdvPrint.mute() AdvPrint.cout(line.rstrip()+"") AdvPrint.set_cout_file("#None") AdvPrint.unmute() AdvPrint.cout("") # Abort if there was an error result.wait() if result.returncode != 0: AdvPrint.cerr_exit("Fritz returned with error. Check logfiles in result folder for more information!") # Remove all empty analysisstdout files for f in [x for x in os.listdir(Info.paths['output_analysis']) if x.startswith("analysisstdout")]: if os.stat(os.path.join(Info.paths['output_analysis'], f)).st_size == 0: os.remove(os.path.join(Info.paths['output_analysis'], f)) # Associate result files to event for a in Info.analyses: event.analysis_signal_files[a] = os.path.join(Info.paths['output_analysis'], event.identifier+'_'+a+'_signal.dat') if os.path.isfile(event.analysis_signal_files[a]): AdvPrint.format_columnated_file(event.analysis_signal_files[a]) event.analysis_cutflow_files[a] = os.path.join(Info.paths['output_analysis'], event.identifier+'_'+a+'_cutflow.dat') if os.path.isfile(event.analysis_cutflow_files[a]): AdvPrint.format_columnated_file(event.analysis_cutflow_files[a]) # finish event.processed = True
def printInfo(self): AdvPrint.cout("\t\tLHE Events") AdvPrint.cout("\t\t\t - internal identifier: '"+self.identifier+"'") counter = 1 for filename in self.full_filenames: if len(self.full_filenames) == 1: AdvPrint.cout("\t\t\t - path to .lhe file: "+filename) else: AdvPrint.cout("\t\t\t - path to .lhe file #"+str(counter)+": "+filename) counter += 1 if self.py8_infile != "": AdvPrint.cout("\t\t\t - Pythia8 .in settings file for showering: "+self.py8_infile) if self.maxEvents > 0: AdvPrint.cout("\t\t\t - at most "+str(self.maxEvents)+" events are generated/analysed") if self.processed: AdvPrint.cout("\t\t\t [Events already processed, results from earlier run are used!]")
def add_and_average(self, other): """ Used to add event samples within the same process: weights are added and event numbers are redetermined """ if self.analysis != other.analysis or self.sr != other.sr: AdvPrint.cerr_exit( "\t resultCollector::add_and_average() \n \t Only results of the same analysis and same signal region can be added!" ) # This number must be equal for all averaged resultCollector (or 0, if this 'other' is the first item that is added) if self.total_normevents == 0: self.total_normevents = other.total_normevents else: weight1 = self.total_mcevents / (self.total_mcevents + other.total_mcevents) weight2 = other.total_mcevents / (self.total_mcevents + other.total_mcevents) self.total_normevents = (self.total_normevents * weight1 + other.total_normevents * weight2) / ( weight1 + weight2) """ the below test is not correct anymore as combined runs of the same process with event gneration via Pythia8 or MadGraph can lead to different values for the respective cross sections. In that case, total_normevents should be given as the weighted mean of the respective total_normevents-numbers, using total_mcevents as the weight #elif (self.total_normevents - other.total_normevents)/float(self.total_normevents + other.total_normevents) > 0.001: # This number must be universal for averaging, can slightly differ due to rounding! # AdvPrint.cerr_exit("\t resultCollector::add_and_average() \n \t Event files that should be averaged ("+self.name+" "+other.name+") have different total normevents in "+self.analysis+" - "+self.sr+". Something must have gone wrong!") """ self.total_mcevents = self.total_mcevents + other.total_mcevents # add mc events self.total_sumofweights = self.total_sumofweights + other.total_sumofweights # add sum of weights self.total_sumofweights2 = self.total_sumofweights2 + other.total_sumofweights2 # add sum of weights^2 # store old relative syserror (beware the case N = 0 and that self and other should be consistent!) rel_sys_error = 0 if self.signal_err_sys != 0: rel_sys_error = self.signal_err_sys / self.signal_normevents if other.signal_err_sys != 0: rel_sys_error = other.signal_err_sys / other.signal_normevents # ds1/s1 must equal ds2/s2, or in other words ds1*s2 = ds2*s1, which avoids rounding problems if self.signal_err_sys != 0 and other.signal_err_sys != 0 and abs( self.signal_err_sys * other.signal_normevents - other.signal_err_sys * self.signal_normevents) > 1E-5: print self.signal_err_sys # debug print self.signal_normevents # debug print other.signal_err_sys # debug print other.signal_normevents # debug print self.signal_err_sys * other.signal_normevents # debug print other.signal_err_sys * self.signal_normevents #debug print self.signal_err_sys * other.signal_normevents - other.signal_err_sys * self.signal_normevents #debug AdvPrint.cerr_exit( "\t resultCollector::add_and_average() \n \t Event files that should be averaged have different syserrors. Something must have gone wrong!" ) # weights can be added self.signal_sumofweights = self.signal_sumofweights + other.signal_sumofweights self.signal_sumofweights2 = self.signal_sumofweights2 + other.signal_sumofweights2 # redetermine event numbers and stat error if self.total_sumofweights != 0: self.signal_normevents = self.total_normevents * self.signal_sumofweights / self.total_sumofweights if self.signal_sumofweights <= 0: # If there are no events in the signal region, ... if Info.flags['no_mc_stat_err']: self.signal_err_stat = 0.0 else: self.signal_err_stat = 1. * self.total_normevents / self.total_sumofweights # ... set staterror to error on 1 Monte Carlo Event under the assumption that all events have equal weight self.signal_err_sys = 0 # ... set syserror to 0 else: if Info.flags['no_mc_stat_err']: self.signal_err_stat = 0.0 else: self.signal_err_stat = self.total_normevents * sqrt( self.signal_sumofweights2) / (self.total_sumofweights) self.signal_err_sys = self.signal_normevents * rel_sys_error # multiply new normevents by old rel_sys_error else: # if there are no events, everything is 0 self.signal_normevents = 0 self.signal_err_stat = 0 self.signal_err_sys = 0 self.signal_err_tot = sqrt(self.signal_err_stat**2 + self.signal_err_sys**2)
def get_resultCollectors(self): resultCollectors = dict() # list of all collectors of all analyses and all signal regions resultCollector = ResultCollector(self.identifier, "", "") # base collector object which we will just edit and copy for analysis in Info.analyses: # check if results file exists if not os.path.isfile(self.analysis_signal_files[analysis]): AdvPrint.cerr_exit("\t events::get_resultCollector() \n" "\t Required analysis result file does not exist: \n " "\t\t"+self.analysis_signal_files[analysis]+"\n" "\t It is very likely that something went wrong in the delphes and/or the analysis step. \n" "\t Please check \n " "\t \t "+Info.files['delphes_log']+" \n " "\t \t "+Info.files['analysis_log']+"* \n " "\t for error messages and, should you not be able to fix them yourself, contact the authors under \n" "\t \t [email protected]") # setup resultCollector object resultCollector.analysis = analysis resultCollectors[analysis] = dict() signal_regions = Info.get_analysis_parameters(analysis)["signal_regions"] # Read result file f = open(self.analysis_signal_files[analysis], "r") for line in f: # Ignore empty or commented lines line = line.rstrip() if line == "" or line[0] == "#": continue # Read file: line = AdvPrint.remove_extra_spaces(line) tokens = [t for t in line.split(" ") if t != ""] # First, read information on total events number if tokens[0] == "MCEvents:": resultCollector.total_mcevents = float(tokens[1]) elif tokens[0] == " SumOfWeights:": resultCollector.total_sumofweights = float(tokens[1]) elif tokens[0] == " SumOfWeights2:": resultCollector.total_sumofweights2 = float(tokens[1]) elif tokens[0] == " NormEvents:": resultCollector.total_normevents = float(tokens[1]) elif tokens[0] == "XSect:": xsect = float(tokens[1].split(" ")[0]) elif tokens[0] == " Error:": xsecterr = float(tokens[1].split(" ")[0]) else: # SR Sum_W Sum_W2 Acc N_Norm for sr in signal_regions: if tokens[0].startswith(sr): resultCollector.sr = sr # Read number of events resultCollector.signal_sumofweights = float(tokens[1]) resultCollector.signal_sumofweights2 = float(tokens[2]) resultCollector.signal_normevents = float(tokens[4]) # Calculate errors if resultCollector.signal_sumofweights > 0: resultCollector.signal_err_stat = resultCollector.signal_normevents*sqrt(resultCollector.signal_sumofweights2)/resultCollector.signal_sumofweights resultCollector.signal_err_sys = resultCollector.signal_normevents*xsecterr/xsect resultCollector.signal_err_tot = sqrt(resultCollector.signal_err_stat**2+resultCollector.signal_err_sys**2) else: resultCollector.signal_err_stat = 0 resultCollector.signal_err_sys = 0 resultCollector.signal_err_tot = 0 # put copy of resultCollector in collector dict resultCollectors[analysis][sr] = deepcopy(resultCollector) f.close() # Write events file, if wanted if Info.parameters["EventResultFileColumns"] != []: AdvPrint.mute() AdvPrint.set_cout_file(self.result_output_file, True) for col in Info.parameters["EventResultFileColumns"]: AdvPrint.cout(col+" ", "nlb") AdvPrint.cout("") for a in sorted(resultCollectors.keys()): for sr in sorted(resultCollectors[a].keys()): AdvPrint.cout(resultCollectors[a][sr].line_from_data(Info.parameters["EventResultFileColumns"])) AdvPrint.format_columnated_file(self.result_output_file) AdvPrint.set_cout_file("#None") AdvPrint.unmute() return resultCollectors
def user_param_check(self): """Prints settings on screen and awaits user confirmation""" analysis_info = dict() AdvPrint.cout("The following settings are used:") AdvPrint.cout("Analyses: ") for analysis in Info.analyses: parameters = Info.get_analysis_parameters(analysis) analysis_info = "" if parameters["expectation_known"] == "n": analysis_info += "[NO EXPECTATION KNOWN -> NO EXCLUSION TEST] " analysis_info += parameters["short_info"] AdvPrint.cout("\t"+analysis+" ("+analysis_info+")") AdvPrint.cout("E_CM: "+str(Info.parameters["ecm"])) AdvPrint.cout("Processes: ") for process in self.procList: process.printInfo() AdvPrint.cout("") AdvPrint.cout("Output Directory: ") AdvPrint.cout("\t"+Info.paths['output']) AdvPrint.cout("Additional Settings: ") if Info.files['slha'] != "": AdvPrint.cout("\t - SLHA file "+Info.files['slha']+" will be used for event generation") if Info.parameters['invisiblePIDs'] != []: AdvPrint.cout("\t - The following PIDs will be considered as invisible for the detector: "+str(Info.parameters['invisiblePIDs']).translate(None, "[]'")) if Info.flags['skipanalysis']: AdvPrint.cout("\t - No analysis step") if Info.flags['skippythia']: AdvPrint.cout("\t - No pythia step") if Info.flags['skipevaluation']: AdvPrint.cout("\t - No evaluation step") if Info.flags['fullcls']: AdvPrint.cout("\t - CLs of all signal regions will be explicitly calculated") if Info.parameters['bestcls'] != 0: AdvPrint.cout("\t - CLs of "+str(Info.parameters['bestcls'])+" best signal region will be explicitly calculated") if Info.flags['likelihood']: AdvPrint.cout("\t - Likelihood will be calculated for each signal region") if Info.flags['no_mc_stat_err']: AdvPrint.cout("\t - No Monte Carlo statistical uncertainty will be included in the evaluation") if Info.flags['eff_tab']: AdvPrint.cout("\t - Efficiency tables will be calculated for each signal region of every analysis run") if Info.flags["controlregions"]: AdvPrint.cout("\t - Analysing control regions") if Info.parameters["outputexists"] == "overwrite": AdvPrint.cout("\t - Old results will be deleted") if Info.parameters["outputexists"] == "add": AdvPrint.cout("\t - New results will be added to old ones") if Info.parameters["randomseed"] != 0: AdvPrint.cout("\t - Fixed random seed of "+str(Info.parameters["randomseed"])) if Info.flags["write_delphes_events"]: AdvPrint.cout("\t - delphes .root files will be written!") if Info.flags["write_pythia_events"]: AdvPrint.cout("\t - pythia .hepmc files will be written!") if Info.parameters["EventResultFileColumns"] != ['analysis', 'sr', 'signal_normevents', 'signal_err_tot']: AdvPrint.cout("\t - print columns "+str(Info.parameters['EventResultFileColumns']).translate(None, "[]'")+" in event result files!") if Info.parameters["ProcessResultFileColumns"] != ['analysis', 'sr', 'signal_normevents', 'signal_err_tot']: AdvPrint.cout("\t - print columns "+str(Info.parameters['ProcessResultFileColumns']).translate(None, "[]'")+" in process result files!") if Info.parameters["TotalEvaluationFileColumns"] != ['analysis', 'sr', 'o', 'b', 'db', 's', 'ds', 's95obs', 's95exp', 'robscons', 'rexpcons']: AdvPrint.cout("\t - print columns "+str(Info.parameters['TotalEvaluationFileColumns']).translate(None, "[]'")+" in total evaluation files!") if Info.parameters["BestPerAnalysisEvaluationFileColumns"] != ['analysis', 'sr', 'o', 'b', 'db', 's', 'ds', 's95obs', 's95exp', 'robscons', 'rexpcons']: AdvPrint.cout("\t - print columns "+str(Info.parameters['BestPerAnalysisEvaluationFileColumns']).translate(None, "[]'")+" in bert-per-analysis evaluation files!") # Let user check correctness of parameters, unless in skipparamcheck. if not Info.flags['skipparamcheck']: while True: c = raw_input("Is this correct? (y/n) ") if c == "y": break elif c == "n": exit(1) AdvPrint.cout("")
def check(self): if self.mg5_cards["proc"] == "" and self.commandstring == "": AdvPrint.cerr_exit( "Error in MG5Events object " + self.name + ":\n\t Neither a proc card nor a command string was provided!")
def runFritz(self): self.prepareFritz() """ Runs Fritz """ from events import MG5Events for event in self.eventsList: if event.processed: continue fritz_command = Info.files["fritz_bin"] + " " + event.configFile result = subprocess.Popen(fritz_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) maxlen = 0 try: for line in iter(result.stdout.readline, b''): # Print to logfile. If it does not start with the Fritz::Global prefix, it comes from MG5 and should be redirected AdvPrint.mute() if not line.startswith("|~| ") and isinstance( event, MG5Events): AdvPrint.set_cout_file( os.path.join( Info.paths["output_mg5"], "mg5amcatnlo_" + event.identifier + ".log")) elif "PYTHIA Rndm::dumpState" in line: AdvPrint.set_cout_file( os.path.join(Info.paths["output_pythia"], "pythia_" + event.identifier + ".log")) else: line = line.replace("|~| ", "") AdvPrint.set_cout_file( os.path.join(Info.paths["output_fritz"], "fritz_" + event.identifier + ".log")) AdvPrint.cout(line.rstrip()) AdvPrint.set_cout_file("#None") AdvPrint.unmute() # We should not exceed the terminal terminal_width: terminal_width = AdvPrint.get_terminal_width() print_line = " |-> " + str(line.strip()) print_line.replace("\t", " ") while "\r" in print_line: print_line = print_line[print_line.index("\r"):] len_of_print_line = len(print_line) maxlen = max(maxlen, len(print_line)) # As we print line by line in the same terminal row, we have to add spaces if the curr line is shorter than a line before fill_spaces = "" if len(print_line) < maxlen: fill_spaces = " " * (maxlen - len(print_line)) # if line is too long, make it shorter by appropriate amoung if len(print_line + fill_spaces) >= terminal_width and len( print_line) <= terminal_width: fill_spaces = " " * (terminal_width - len(print_line) - 1) elif len(print_line) > terminal_width: fill_spaces = "" print_line = print_line[:terminal_width - 4] + "..." AdvPrint.cout( "\r" + print_line + fill_spaces + "\x1b[0m\r", "nlb") except KeyboardInterrupt: AdvPrint.cout("Caught Keyboard Signal. Aborting Fritz") result.send_signal(signal.SIGTERM) for line in iter(result.stderr.readline, b''): AdvPrint.unmute() AdvPrint.set_cout_file(Info.files['fritz_log']) # remove nasty ROOT6-CLING warnings from on-screen output if "cling::AutoloadingVisitor::InsertIntoAutoloadingState:" in line: AdvPrint.mute() elif "Missing FileEntry for ExRootAnalysis" in line: AdvPrint.mute() elif "requested to autoload type" in line: AdvPrint.mute() AdvPrint.cout(line.rstrip() + "") AdvPrint.set_cout_file("#None") AdvPrint.unmute() AdvPrint.cout("") # Abort if there was an error result.wait() if result.returncode != 0: AdvPrint.cerr_exit( "Fritz returned with error. Check logfiles in result folder for more information!" ) # Remove all empty analysisstdout files for f in [ x for x in os.listdir(Info.paths['output_analysis']) if x.startswith("analysisstdout") ]: if os.stat(os.path.join(Info.paths['output_analysis'], f)).st_size == 0: os.remove(os.path.join(Info.paths['output_analysis'], f)) # Associate result files to event for a in Info.analyses: event.analysis_signal_files[a] = os.path.join( Info.paths['output_analysis'], event.identifier + '_' + a + '_signal.dat') if os.path.isfile(event.analysis_signal_files[a]): AdvPrint.format_columnated_file( event.analysis_signal_files[a]) event.analysis_cutflow_files[a] = os.path.join( Info.paths['output_analysis'], event.identifier + '_' + a + '_cutflow.dat') if os.path.isfile(event.analysis_cutflow_files[a]): AdvPrint.format_columnated_file( event.analysis_cutflow_files[a]) # finish event.processed = True
def get_resultCollectors(self): """ Gathers results from all events""" # setup resultCollector object resultCollectors_pr = dict() for analysis in Info.analyses: resultCollectors_pr[analysis] = dict() signal_regions = Info.get_analysis_parameters( analysis)["signal_regions"] for sr in signal_regions: resultCollectors_pr[analysis][sr] = ResultCollector( self.name, analysis, sr) # loop over all associated events and average results in all resultCollectors for event in self.eventsList: resultCollectors_ev = event.get_resultCollectors() for analysis in resultCollectors_pr: for sr in resultCollectors_pr[analysis]: resultCollectors_pr[analysis][sr].add_and_average( resultCollectors_ev[analysis][sr]) # Write process file, if wanted if Info.parameters["ProcessResultFileColumns"] != []: AdvPrint.mute() AdvPrint.set_cout_file(self.result_output_file, True) for col in Info.parameters["ProcessResultFileColumns"]: AdvPrint.cout(col + " ", "nlb") AdvPrint.cout("") for a in sorted(resultCollectors_pr.keys()): for sr in sorted(resultCollectors_pr[a].keys()): AdvPrint.cout(resultCollectors_pr[a][sr].line_from_data( Info.parameters["ProcessResultFileColumns"])) AdvPrint.format_columnated_file(self.result_output_file) AdvPrint.set_cout_file("#None") AdvPrint.unmute() return resultCollectors_pr
def add_and_average(self, other): """ Used to add event samples within the same process: weights are added and event numbers are redetermined """ if self.analysis != other.analysis or self.sr != other.sr: AdvPrint.cerr_exit("\t resultCollector::add_and_average() \n \t Only results of the same analysis and same signal region can be added!") # This number must be equal for all averaged resultCollector (or 0, if this 'other' is the first item that is added) if self.total_normevents == 0: self.total_normevents = other.total_normevents else: weight1 = self.total_mcevents / (self.total_mcevents + other.total_mcevents) weight2 = other.total_mcevents / (self.total_mcevents + other.total_mcevents) self.total_normevents = (self.total_normevents * weight1 + other.total_normevents * weight2)/(weight1 + weight2) """ the below test is not correct anymore as combined runs of the same process with event gneration via Pythia8 or MadGraph can lead to different values for the respective cross sections. In that case, total_normevents should be given as the weighted mean of the respective total_normevents-numbers, using total_mcevents as the weight #elif (self.total_normevents - other.total_normevents)/float(self.total_normevents + other.total_normevents) > 0.001: # This number must be universal for averaging, can slightly differ due to rounding! # AdvPrint.cerr_exit("\t resultCollector::add_and_average() \n \t Event files that should be averaged ("+self.name+" "+other.name+") have different total normevents in "+self.analysis+" - "+self.sr+". Something must have gone wrong!") """ self.total_mcevents = self.total_mcevents + other.total_mcevents # add mc events self.total_sumofweights = self.total_sumofweights + other.total_sumofweights # add sum of weights self.total_sumofweights2 = self.total_sumofweights2 + other.total_sumofweights2 # add sum of weights^2 # store old relative syserror (beware the case N = 0 and that self and other should be consistent!) rel_sys_error = 0 if self.signal_err_sys != 0: rel_sys_error = self.signal_err_sys/self.signal_normevents if other.signal_err_sys != 0: rel_sys_error = other.signal_err_sys/other.signal_normevents # ds1/s1 must equal ds2/s2, or in other words ds1*s2 = ds2*s1, which avoids rounding problems if self.signal_err_sys != 0 and other.signal_err_sys != 0 and abs(self.signal_err_sys*other.signal_normevents - other.signal_err_sys*self.signal_normevents)>1E-5: print self.signal_err_sys # debug print self.signal_normevents # debug print other.signal_err_sys # debug print other.signal_normevents # debug print self.signal_err_sys*other.signal_normevents # debug print other.signal_err_sys*self.signal_normevents #debug print self.signal_err_sys*other.signal_normevents - other.signal_err_sys*self.signal_normevents #debug AdvPrint.cerr_exit("\t resultCollector::add_and_average() \n \t Event files that should be averaged have different syserrors. Something must have gone wrong!") # weights can be added self.signal_sumofweights = self.signal_sumofweights + other.signal_sumofweights self.signal_sumofweights2 = self.signal_sumofweights2 + other.signal_sumofweights2 # redetermine event numbers and stat error if self.total_sumofweights != 0: self.signal_normevents = self.total_normevents * self.signal_sumofweights / self.total_sumofweights if self.signal_sumofweights <= 0: # If there are no events in the signal region, ... if Info.flags['no_mc_stat_err']: self.signal_err_stat = 0.0 else: self.signal_err_stat = 1.*self.total_normevents/self.total_sumofweights # ... set staterror to error on 1 Monte Carlo Event under the assumption that all events have equal weight self.signal_err_sys = 0 # ... set syserror to 0 else: if Info.flags['no_mc_stat_err']: self.signal_err_stat = 0.0 else: self.signal_err_stat = self.total_normevents*sqrt(self.signal_sumofweights2)/(self.total_sumofweights) self.signal_err_sys = self.signal_normevents * rel_sys_error # multiply new normevents by old rel_sys_error else: # if there are no events, everything is 0 self.signal_normevents = 0 self.signal_err_stat = 0 self.signal_err_sys = 0 self.signal_err_tot = sqrt(self.signal_err_stat**2+self.signal_err_sys**2)
def printInfo(self): AdvPrint.cout("\t\tMG5_aMC@NLO Events") AdvPrint.cout("\t\t\t - internal identifier: '" + self.identifier + "'") if self.mg5_cards["proc"] != "": AdvPrint.cout("\t\t\t - proc_card: " + self.mg5_cards["proc"]) if self.commandstring != "": AdvPrint.cout( "\t\t\t - command: " + self.commandstring.replace("\n", "\n\t\t\t ")) if self.mg5_cards["run"] != "": AdvPrint.cout("\t\t\t - run_card: " + self.mg5_cards["run"]) if self.mg5_cards["config"] != "": AdvPrint.cout("\t\t\t - config_card: " + self.mg5_cards["config"]) if self.mg5_cards["param"] != "": AdvPrint.cout("\t\t\t - param_card: " + self.mg5_cards["param"]) if self.maxEvents > 0: AdvPrint.cout("\t\t\t - at most " + str(self.maxEvents) + " events are generated/analsed") if self.py8_infile != "": AdvPrint.cout( "\t\t\t - Pythia8 settings file used for showering: " + self.py8_infile) if self.have_xsth: AdvPrint.cout( "\t\t\t - Pythia8 won't run if parton cross section falls below: " + str(self.xsth) + " " + str(self.xsth_unit))
def printInfo(self): AdvPrint.cout("\t\t Pythia8 Events") AdvPrint.cout("\t\t\t - internal identifier: '" + self.identifier + "'") if self.py8_infile != "": AdvPrint.cout("\t\t\t - .in settings file: " + self.py8_infile) if self.processString != "": AdvPrint.cout("\t\t\t - simplified SUSY process: " + self.processString) if self.maxEvents > 0: AdvPrint.cout("\t\t\t - at most " + str(self.maxEvents) + " events are generated and analysed") if self.processed: AdvPrint.cout( "\t\t\t [Events already processed, results from earlier run are used!]" )
def load_expdata(self): analysis = self.resultCollector.analysis if analysis == "": return # for pseudo-evaluators sr = self.resultCollector.sr parameters = Info.get_analysis_parameters(analysis) # S95 comparison: r value compares lower s95 limit on s (which is almost 2 sigma) to the model independent limit if sr not in parameters["reference_data"]: AdvPrint.cerr_exit( "evaluator::load_expdata unknown signal region " + analysis + " - " + sr) if "S95_obs" not in parameters["reference_data"][sr]: AdvPrint.cerr_exit( "evaluator::load_expdata S95_obs value is unknown for " + analysis + " - " + sr) self.s95_obs = float(parameters["reference_data"][sr]["S95_obs"]) # If no expected upper limit is given, observed limit is used if "S95_exp" not in parameters["reference_data"][sr]: self.s95_exp = self.s95_obs self.warnings.append( "No expected limit could be found in reference data. Using expected = observed." ) else: self.s95_exp = float(parameters["reference_data"][sr]["S95_exp"]) if "obs" not in parameters["reference_data"][sr]: AdvPrint.cerr_exit( "evaluator::load_expdata 'obs' is unknown for " + analysis + " - " + sr) self.obs = float(parameters["reference_data"][sr]["obs"]) if "bkg" not in parameters["reference_data"][sr]: AdvPrint.cerr_exit( "evaluator::load_expdata 'bkg' is unknown for " + analysis + " - " + sr) self.bkg = float(parameters["reference_data"][sr]["bkg"]) self.bkg_err = -1 if "bkg_err" in parameters["reference_data"][sr]: self.bkg_err = float(parameters["reference_data"][sr]["bkg_err"]) elif "bkg_errp" in parameters["reference_data"][sr]: # Asymmetric error: as a rough approximation, use the mean of the squares self.bkg_err = sqrt( float(parameters["reference_data"][sr]["bkg_errp"])**2 + float(parameters["reference_data"][sr]["bkg_errm"])**2) / sqrt( 2.) elif "bkg_err_sys" in parameters["reference_data"][sr]: # Total error = independent quadratic sum of statistical and systematical component self.bkg_err = sqrt( float(parameters["reference_data"][sr]["bkg_err_stat"])**2 + float(parameters["reference_data"][sr]["bkg_err_sys"])**2) elif "bkg_err_sysp" in parameters["reference_data"][sr]: self.bkg_err = sqrt( float(parameters["reference_data"][sr]["bkg_err_stat"])**2 + (float(parameters["reference_data"][sr]["bkg_err_sysp"])**2) / 2. + (float(parameters["reference_data"][sr]["bkg_err_sysp"])**2) / 2.)
def check(self): if self.py8_infile == '' and self.processString == '': AdvPrint.cerr_exit( "ERROR in Pythia8Events-object '" + self.name + "':\n\t Neither a .in file nor a process string was given!")
def check(self): if self.py8_infile == '' and self.processString == '': AdvPrint.cerr_exit("ERROR in Pythia8Events-object '"+self.name+"':\n\t Neither a .in file nor a process string was given!")
def evaluate(self): """ Performs statistical evaluation of the result """ AdvPrint.cout("Evaluating Results") resultCollectors = self.get_resultCollectors() # evaluate all results evaluators = dict() for analysis in resultCollectors: evaluators[analysis] = dict() # only process those results and those signal regions that are given in the reference file for analysis in Info.analyses: signal_regions = Info.get_analysis_parameters(analysis)["signal_regions"] for sr in signal_regions: evaluator = Evaluator(resultCollectors[analysis][sr]) # Calculate everything that should be calculated # TODO: Beware analyses with unknown background evaluator.calc_efficiencies() evaluator.calc_r_values() if Info.flags["likelihood"]: evaluator.calc_likelihood() if Info.flags["fullcls"]: evaluator.calc_cls_values() if Info.flags["zsig"]: evaluator.calc_zsig() evaluators[analysis][sr] = evaluator if Info.parameters["bestcls"] != 0: AdvPrint.cout("Calculating CLs for the "+str(Info.parameters["bestcls"])+" most sensitive signal regions!") best_evaluators = find_strongest_evaluators(evaluators, Info.parameters["bestcls"]) # if "bestcls" is 1, find_strongest_evaluators does not return a list but just the single best if Info.parameters["bestcls"] == 1: best_evaluators = [best_evaluators] for ev in best_evaluators: ev.calc_cls_values() # find best result best_evaluator_per_analysis = dict() for analysis in evaluators: # Find bes of all SRs in analysis best_evaluator_per_analysis[analysis] = find_strongest_evaluators(evaluators[analysis], 1) best_evaluator = find_strongest_evaluators(best_evaluator_per_analysis, 1) AdvPrint.set_cout_file(Info.files['output_totalresults'], True) AdvPrint.mute() for col in Info.parameters["TotalEvaluationFileColumns"]: AdvPrint.cout(col+" ", "nlb") AdvPrint.cout("") for a in sorted(evaluators.keys()): for sr in sorted(evaluators[a].keys()): AdvPrint.cout(evaluators[a][sr].line_from_data(Info.parameters["TotalEvaluationFileColumns"])) AdvPrint.format_columnated_file(Info.files['output_totalresults']) AdvPrint.set_cout_file(Info.files['output_bestsignalregions'], True) AdvPrint.mute() for col in Info.parameters["BestPerAnalysisEvaluationFileColumns"]: AdvPrint.cout(col+" ", "nlb") AdvPrint.cout("") # print analyses in alphabetic order for a in sorted(best_evaluator_per_analysis.keys()): AdvPrint.cout(best_evaluator_per_analysis[a].line_from_data(Info.parameters["BestPerAnalysisEvaluationFileColumns"])) AdvPrint.format_columnated_file(Info.files['output_bestsignalregions']) AdvPrint.set_cout_file("#None") AdvPrint.unmute() best_evaluator.check_warnings() best_evaluator.print_result() if Info.flags['zsig']: _print_zsig(evaluators) if Info.flags['likelihood']: _print_likelihood(evaluators)
def print_result(self): AdvPrint.set_cout_file(Info.files["output_result"], True) if self.cls_obs != -1: AdvPrint.cout("Test: Calculation of CLs(S, dS, B, dB, O) using profile likelihood") elif self.likelihood != -1: AdvPrint.cout("Test: Calculation of approximate (fast) likelihood given in results folder") elif self.r_obs != -1: AdvPrint.cout("Test: Calculation of r = signal/(95%CL limit on signal)") else: AdvPrint.cerr_exit("evaluator::printResult(): No result has been evaluated!") for w in self.warnings: AdvPrint.cout("\033[33mWarning: "+w+"\033[0m") result = "\033[31mExcluded\033[0m" if self.allowed(): result = "\033[32mAllowed\033[0m" AdvPrint.cout("Result: "+result) if self.cls_obs != -1: AdvPrint.cout("Result for CLs: "+str(self.cls_obs)) #if self.likelihood != -1: # AdvPrint.cout("Result for likelihood: "+str(self.likelihood)) elif self.r_obs != -1: AdvPrint.cout("Result for r: "+str(self.r_obs_cons)) else: AdvPrint.cerr_exit("evaluator::printResult(): No result has been evaluated!") AdvPrint.cout("Analysis: "+self.resultCollector.analysis) AdvPrint.cout("SR: "+self.resultCollector.sr) AdvPrint.set_cout_file("#None")
def printInfo(self): AdvPrint.cout("\tProcess Name: "+self.name) if self.have_xsect: AdvPrint.cout("\tInput Cross section: "+str(self.xsec)+" "+str(self.xsec_unit)) if self.have_xerr: AdvPrint.cout("\tInput cross section error: "+str(self.xerr)+" "+str(self.xerr_unit)) elif self.have_kfac: AdvPrint.cout("\tInput KFactor: "+str(self.kfac)) eventsList = [ef for ef in self.eventsList] if len(eventsList) != 0: AdvPrint.cout("\tAssociated event files and/or Monte-Carlo generation runs:") for ef in eventsList: ef.printInfo() AdvPrint.cout("") AdvPrint.cout("")
def get_resultCollectors(self): """ Gathers results from all events""" # setup resultCollector object resultCollectors_pr = dict() for analysis in Info.analyses: resultCollectors_pr[analysis] = dict() signal_regions = Info.get_analysis_parameters(analysis)["signal_regions"] for sr in signal_regions: resultCollectors_pr[analysis][sr] = ResultCollector(self.name, analysis, sr) # loop over all associated events and average results in all resultCollectors for event in self.eventsList: resultCollectors_ev = event.get_resultCollectors() for analysis in resultCollectors_pr: for sr in resultCollectors_pr[analysis]: resultCollectors_pr[analysis][sr].add_and_average(resultCollectors_ev[analysis][sr]) # Write process file, if wanted if Info.parameters["ProcessResultFileColumns"] != []: AdvPrint.mute() AdvPrint.set_cout_file(self.result_output_file, True) for col in Info.parameters["ProcessResultFileColumns"]: AdvPrint.cout(col+" ", "nlb") AdvPrint.cout("") for a in sorted(resultCollectors_pr.keys()): for sr in sorted(resultCollectors_pr[a].keys()): AdvPrint.cout(resultCollectors_pr[a][sr].line_from_data(Info.parameters["ProcessResultFileColumns"])) AdvPrint.format_columnated_file(self.result_output_file) AdvPrint.set_cout_file("#None") AdvPrint.unmute() return resultCollectors_pr
def printInfo(self): AdvPrint.cout("\t\tMG5_aMC@NLO Events") AdvPrint.cout("\t\t\t - internal identifier: '"+self.identifier+"'") if self.mg5_cards["proc"] != "": AdvPrint.cout("\t\t\t - proc_card: "+self.mg5_cards["proc"]) if self.commandstring != "": AdvPrint.cout("\t\t\t - command: "+self.commandstring.replace("\n", "\n\t\t\t ")) if self.mg5_cards["run"] != "": AdvPrint.cout("\t\t\t - run_card: "+self.mg5_cards["run"]) if self.mg5_cards["config"] != "": AdvPrint.cout("\t\t\t - config_card: "+self.mg5_cards["config"]) if self.mg5_cards["param"] != "": AdvPrint.cout("\t\t\t - param_card: "+self.mg5_cards["param"]) if self.maxEvents > 0: AdvPrint.cout("\t\t\t - at most "+str(self.maxEvents)+" events are generated/analsed") if self.py8_infile != "": AdvPrint.cout("\t\t\t - Pythia8 settings file used for showering: "+self.py8_infile) if self.have_xsth: AdvPrint.cout("\t\t\t - Pythia8 won't run if parton cross section falls below: "+str(self.xsth)+" "+str(self.xsth_unit))
def line_from_data(self, columns): """ Returns the information stated in the list 'columns' as a single line """ line = "" for c in columns: c = c.lower().strip() if c.lower() in ['name', 'id', 'identifier']: line += str(self.resultCollector.name)+" " elif c.lower() in ['analysis', 'ana']: line += str(self.resultCollector.analysis)+" " elif c.lower() in ['sr', 'signalregion']: line += str(self.resultCollector.sr)+" " elif c.lower() in ['totalmc', 'totalmcevents']: line += str(self.resultCollector.total_mcevents)+" " elif c.lower() in ['totalnorm', 'totalnormevents']: line += str(self.resultCollector.total_normevents)+" " elif c.lower() in ['totalsw', 'totalsumofweights']: line += str(self.resultCollector.total_sumofweights)+" " elif c.lower() in ['totalsw2', 'totalsumofweights2']: line += str(self.resultCollector.total_sumofweights2)+" " elif c.lower() in ['signalsw', 'signalsumofweights']: line += str(self.resultCollector.signal_sumofweights)+" " elif c.lower() in ['signalsw2', 'signalsumofweights2']: line += str(self.resultCollector.signal_sumofweights2)+" " elif c.lower() in ['signalnorm', 'signalnormevents', 's']: line += str(self.resultCollector.signal_normevents)+" " elif c.lower() in ['signalerrstat','signal_err_stat']: line += str(self.resultCollector.signal_err_stat)+" " elif c.lower() in ['signalerrsys','signal_err_sys']: line += str(self.resultCollector.signal_err_sys)+" " elif c.lower() in ['signalerrtot', 'ds','signal_err_tot']: line += str(self.resultCollector.signal_err_tot)+" " elif c.lower() in ['obs', 'o']: line += str(self.obs)+" " elif c.lower() in ['b', 'bkg']: line += str(self.bkg)+" " elif c.lower() in ['db', 'bkgerr']: line += str(self.bkg_err)+" " elif c.lower() in ['signaleff', 'eff']: line += str(self.signal_eff)+" " elif c.lower() in ['signaleff_err_stat', 'eff_err_stat']: line += str(self.signal_eff_error_stat)+" " elif c.lower() in ['signaleff_err_sys', 'eff_err_sys']: line += str(self.signal_eff_error_sys)+" " elif c.lower() in ['signaleff_err_tot', 'eff_err_tot']: line += str(self.signal_eff_error_tot)+" " elif c.lower() in ['s95obs']: line += str(self.s95_obs)+" " elif c.lower() in ['s95exp']: line += str(self.s95_exp)+" " elif c.lower() in ['robs','r_obs']: line += str(self.r_obs)+" " elif c.lower() in ['robscons','r_obs_cons']: line += str(self.r_obs_cons)+" " elif c.lower() in ['robsconssysonly','r_obs_cons_sysonly']: line += str(self.r_obs_cons_sysonly)+" " elif c.lower() in ['rexp','r_exp']: line += str(self.r_exp)+" " elif c.lower() in ['rexpcons','r_exp_cons']: line += str(self.r_exp_cons)+" " elif c.lower() in ['rexpconssysonly','r_exp_cons_sysonly']: line += str(self.r_exp_cons_sysonly)+" " elif c.lower() in ['clsobs','cls_obs']: line += str(self.cls_obs)+" " elif c.lower() in ['clsobs_err','cls_obs_err']: line += str(self.cls_obs_err)+" " elif c.lower() in ['clsexp','cls_exp']: line += str(self.cls_exp)+" " elif c.lower() in ['clsexp_err','cls_exp_err']: line += str(self.cls_exp_err)+" " elif c.lower() in ['likelihood']: line += str(self.likelihood)+" " #todoelif c.lower() in ['likelihood']: # line += str(self.likelihood)+" " else: AdvPrint.cerr_exit("evaluator::line_from_data - column "+c+" unknown!") return line
def printUsage(self): self.printLogo() AdvPrint.cout( """ ___ |__| _ | _ | |(_)\)/ |(_) """) AdvPrint.cout( "Method 1: Input Parameters") AdvPrint.cout( "\trun -n {name_for_this_run} -a {analysis} -p {process} -xs {crosssection} -xse {crosssection error} -ev {eventfile}") AdvPrint.cout( "Method 2: Input File") AdvPrint.cout( "\trun {inputfile}") AdvPrint.cout( "") AdvPrint.cout( "Examples:") AdvPrint.cout( "\t./CheckMATE -n testrun -a atlas_1405_7875 -p \"gg\" -xs \"1*FB\" -xse \"0.1 FB\" -ev /scratch/all/gluinopair.hepmc") AdvPrint.cout( "\t./CheckMATE testparam.dat") AdvPrint.cout( "") AdvPrint.cout( "Type './CheckMATE -h' for more information about available parameters or check") AdvPrint.cout( "the given 'testparam.dat' file for the desired structure of input files") exit(1)