# Remove any existing result files list = [glob.glob("*.fits"), glob.glob("*.log"), glob.glob("*.xml")] for files in list: for file in files: os.remove(file) # Setup single observation survey #obs = survey_single() obs = survey_gplane() # Add background model obs = add_background_model(obs) # Simulate events print("Simulate events") obs = obsutils.sim(obs) # Make counts map print("Make counts map") cntmap = obsutils.cntmap(obs) # Fit observations print("Fit observations") like = obsutils.fit(obs) #print like.opt() #print like.obs().models() # Make model map print("Make model map (this step will take some time)") modmap = obsutils.modmap(obs)
def get_sensitivity(self, obs, emin, emax, bkg_model, full_model): """ Determine sensitivity for given observations. Parameters: obs - Observation container emin - Minimum energy for fitting and flux computation emax - Maximum energy for fitting and flux computation bkg_model - Background model full_model - Source model """ # Set TeV->erg conversion factor tev2erg = 1.6021764 # Set energy boundaries self.set_obs_ebounds(emin, emax) # Determine energy boundaries from first observation in the container loge = math.log10(math.sqrt(emin.TeV()*emax.TeV())) e_mean = math.pow(10.0, loge) erg_mean = e_mean * tev2erg # Compute Crab unit (this is the factor with which the Prefactor needs # to be multiplied to get 1 Crab crab_flux = self.get_crab_flux(emin, emax) src_flux = full_model[self.m_srcname].spectral().flux(emin, emax) crab_unit = crab_flux/src_flux # Write header if self.logTerse(): self.log("\n") self.log.header2("Energies: "+str(emin)+" - "+str(emax)) self.log.parformat("Crab flux") self.log(crab_flux) self.log(" ph/cm2/s\n") self.log.parformat("Source model flux") self.log(src_flux) self.log(" ph/cm2/s\n") self.log.parformat("Crab unit factor") self.log(crab_unit) self.log("\n") # Initialise loop crab_flux_value = [] photon_flux_value = [] energy_flux_value = [] sensitivity_value = [] iter = 0 test_crab_flux = 0.1 # Initial test flux in Crab units (100 mCrab) # Loop until we break while True: # Update iteration counter iter += 1 # Write header if self.logExplicit(): self.log.header2("Iteration "+str(iter)) # Set source model. crab_prefactor is the Prefactor that # corresponds to 1 Crab src_model = full_model.copy() crab_prefactor = src_model[self.m_srcname]['Prefactor'].value() * crab_unit src_model[self.m_srcname]['Prefactor'].value(crab_prefactor * test_crab_flux) obs.models(src_model) # Simulate events sim = obsutils.sim(obs, nbins=self.m_enumbins, seed=iter, \ binsz=self.m_binsz, npix=self.m_npix, \ log=self.m_log, debug=self.m_debug) # Determine number of events in simulation nevents = 0.0 for run in sim: nevents += run.events().number() # Write simulation results if self.logExplicit(): self.log.header3("Simulation") self.log.parformat("Number of simulated events") self.log(nevents) self.log("\n") # Fit background only sim.models(bkg_model) like = obsutils.fit(sim, log=self.m_log, debug=self.m_debug) result_bgm = like.obs().models().copy() LogL_bgm = like.opt().value() npred_bgm = like.obs().npred() # Assess quality based on a comparison between Npred and Nevents quality_bgm = npred_bgm-nevents # Write background fit results if self.logExplicit(): self.log.header3("Background model fit") self.log.parformat("log likelihood") self.log(LogL_bgm) self.log("\n") self.log.parformat("Number of predicted events") self.log(npred_bgm) self.log("\n") self.log.parformat("Fit quality") self.log(quality_bgm) self.log("\n") # Start over if the fit quality was bad if abs(quality_bgm) > 3.0: if self.logExplicit(): self.log("Fit quality outside required range. Start over.\n") continue # Write model fit results if self.logExplicit(): for model in result_bgm: self.log.parformat("Model") self.log(model.name()) self.log("\n") for par in model: self.log(str(par)+"\n") # Fit background and test source sim.models(src_model) like = obsutils.fit(sim, log=self.m_log, debug=self.m_debug) result_all = like.obs().models().copy() LogL_all = like.opt().value() npred_all = like.obs().npred() ts = 2.0*(LogL_bgm-LogL_all) # Assess quality based on a comparison between Npred and Nevents quality_all = npred_all-nevents # Write background and test source fit results if self.logExplicit(): self.log.header3("Background and test source model fit") self.log.parformat("Test statistics") self.log(ts) self.log("\n") self.log.parformat("log likelihood") self.log(LogL_all) self.log("\n") self.log.parformat("Number of predicted events") self.log(npred_all) self.log("\n") self.log.parformat("Fit quality") self.log(quality_all) self.log("\n") # for model in result_all: self.log.parformat("Model") self.log(model.name()) self.log("\n") for par in model: self.log(str(par)+"\n") # Start over if the fit quality was bad if abs(quality_all) > 3.0: if self.logExplicit(): self.log("Fit quality outside required range. Start over.\n") continue # Start over if TS was non-positive if ts <= 0.0: if self.logExplicit(): self.log("Non positive TS. Start over.\n") continue # Get fitted Crab, photon and energy fluxes crab_flux = result_all[self.m_srcname]['Prefactor'].value() / crab_prefactor crab_flux_err = result_all[self.m_srcname]['Prefactor'].error() / crab_prefactor photon_flux = result_all[self.m_srcname].spectral().flux(emin, emax) energy_flux = result_all[self.m_srcname].spectral().eflux(emin, emax) # Compute differential sensitivity in unit erg/cm2/s energy = gammalib.GEnergy(e_mean, "TeV") time = gammalib.GTime() sensitivity = result_all[self.m_srcname].spectral().eval(energy, time) * \ erg_mean*erg_mean * 1.0e6 # Compute flux correction factor based on average TS correct = 1.0 if ts > 0: correct = math.sqrt(self.m_ts_thres/ts) # Compute extrapolated fluxes crab_flux = correct * crab_flux photon_flux = correct * photon_flux energy_flux = correct * energy_flux sensitivity = correct * sensitivity crab_flux_value.append(crab_flux) photon_flux_value.append(photon_flux) energy_flux_value.append(energy_flux) sensitivity_value.append(sensitivity) # Write background and test source fit results if self.logExplicit(): self.log.parformat("Photon flux") self.log(photon_flux) self.log(" ph/cm2/s\n") self.log.parformat("Energy flux") self.log(energy_flux) self.log(" erg/cm2/s\n") self.log.parformat("Crab flux") self.log(crab_flux*1000.0) self.log(" mCrab\n") self.log.parformat("Differential sensitivity") self.log(sensitivity) self.log(" erg/cm2/s\n") for model in result_all: self.log.parformat("Model") self.log(model.name()) self.log("\n") for par in model: self.log(str(par)+"\n") elif self.logTerse(): self.log.parformat("Iteration "+str(iter)) self.log("TS=") self.log(ts) self.log(" ") self.log("corr=") self.log(correct) self.log(" ") self.log(photon_flux) self.log(" ph/cm2/s = ") self.log(energy_flux) self.log(" erg/cm2/s = ") self.log(crab_flux*1000.0) self.log(" mCrab = ") self.log(sensitivity) self.log(" erg/cm2/s\n") # Compute sliding average of extrapolated fitted prefactor, # photon and energy flux. This damps out fluctuations and # improves convergence crab_flux = 0.0 photon_flux = 0.0 energy_flux = 0.0 sensitivity = 0.0 num = 0.0 for k in range(self.m_num_avg): inx = len(crab_flux_value) - k - 1 if inx >= 0: crab_flux += crab_flux_value[inx] photon_flux += photon_flux_value[inx] energy_flux += energy_flux_value[inx] sensitivity += sensitivity_value[inx] num += 1.0 crab_flux /= num photon_flux /= num energy_flux /= num sensitivity /= num # Compare average flux to last average if iter > self.m_num_avg: if test_crab_flux > 0: ratio = crab_flux/test_crab_flux # We have 2 convergence criteria: # 1. The average flux does not change # 2. The flux correction factor is small if ratio >= 0.99 and ratio <= 1.01 and \ correct >= 0.9 and correct <= 1.1: if self.logTerse(): self.log(" Converged ("+str(ratio)+")\n") break else: if self.logTerse(): self.log(" Flux is zero.\n") break # Use average for next iteration test_crab_flux = crab_flux # Exit loop if number of trials exhausted if (iter >= self.m_max_iter): if self.logTerse(): self.log(" Test ended after "+str(self.m_max_iter)+" iterations.\n") break # Write fit results if self.logTerse(): self.log.header3("Fit results") self.log.parformat("Test statistics") self.log(ts) self.log("\n") self.log.parformat("Photon flux") self.log(photon_flux) self.log(" ph/cm2/s\n") self.log.parformat("Energy flux") self.log(energy_flux) self.log(" erg/cm2/s\n") self.log.parformat("Crab flux") self.log(crab_flux*1000.0) self.log(" mCrab\n") self.log.parformat("Differential sensitivity") self.log(sensitivity) self.log(" erg/cm2/s\n") self.log.parformat("Number of simulated events") self.log(nevents) self.log("\n") self.log.header3("Background and test source model fitting") self.log.parformat("log likelihood") self.log(LogL_all) self.log("\n") self.log.parformat("Number of predicted events") self.log(npred_all) self.log("\n") for model in result_all: self.log.parformat("Model") self.log(model.name()) self.log("\n") for par in model: self.log(str(par)+"\n") self.log.header3("Background model fit") self.log.parformat("log likelihood") self.log(LogL_bgm) self.log("\n") self.log.parformat("Number of predicted events") self.log(npred_bgm) self.log("\n") for model in result_bgm: self.log.parformat("Model") self.log(model.name()) self.log("\n") for par in model: self.log(str(par)+"\n") # Store result result = {'loge': loge, 'emin': emin.TeV(), 'emax': emax.TeV(), \ 'crab_flux': crab_flux, 'photon_flux': photon_flux, \ 'energy_flux': energy_flux, \ 'sensitivity': sensitivity} # Return result return result
def trial(self, seed, full_model, bkg_model): """ Create the TS for a single trial. Parameters: seed - Random number generator seed """ # Write header if self.logExplicit(): self.log.header2("Trial " + str(seed + 1)) # Simulate events sim = obsutils.sim( self.obs, nbins=self.m_enumbins, seed=seed, binsz=self.m_binsz, npix=self.m_npix, log=self.m_log, debug=self.m_debug, ) # Determine number of events in simulation nevents = 0.0 for run in sim: nevents += run.events().number() # Write simulation results if self.logExplicit(): self.log.header3("Simulation") self.log.parformat("Number of simulated events") self.log(nevents) self.log("\n") # Fit background only sim.models(bkg_model) like_bgm = obsutils.fit(sim, log=self.m_log, debug=self.m_debug) result_bgm = like_bgm.obs().models().copy() LogL_bgm = like_bgm.opt().value() npred_bgm = like_bgm.obs().npred() # Write background fit results if self.logExplicit(): self.log.header3("Background model fit") self.log.parformat("log likelihood") self.log(LogL_bgm) self.log("\n") self.log.parformat("Number of predicted events") self.log(npred_bgm) self.log("\n") for model in result_bgm: self.log.parformat("Model") self.log(model.name()) self.log("\n") for par in model: self.log(str(par) + "\n") # Fit background and test source sim.models(full_model) like_all = obsutils.fit(sim, log=self.m_log, debug=self.m_debug) result_all = like_all.obs().models().copy() LogL_all = like_all.opt().value() npred_all = like_all.obs().npred() ts = 2.0 * (LogL_bgm - LogL_all) # Write background and test source fit results if self.logExplicit(): self.log.header3("Background and test source model fit") self.log.parformat("Test statistics") self.log(ts) self.log("\n") self.log.parformat("log likelihood") self.log(LogL_all) self.log("\n") self.log.parformat("Number of predicted events") self.log(npred_all) self.log("\n") for model in result_all: self.log.parformat("Model") self.log(model.name()) self.log("\n") for par in model: self.log(str(par) + "\n") # Write result elif self.logTerse(): self.log.parformat("Trial " + str(seed)) self.log("TS=") self.log(ts) self.log(" Prefactor=") self.log(result_all[self.m_srcname]["Prefactor"].value()) self.log("+/-") self.log(result_all[self.m_srcname]["Prefactor"].error()) self.log("\n") # Initialise results colnames = [] values = {} # Set TS value colnames.append("TS") values["TS"] = ts # Set logL for background fit colnames.append("LogL_bgm") values["LogL_bgm"] = LogL_bgm # Set logL for full fit colnames.append("LogL_all") values["LogL_all"] = LogL_all # Set Nevents colnames.append("Nevents") values["Nevents"] = nevents # Set Npred for background fit colnames.append("Npred_bkg") values["Npred_bkg"] = npred_bgm # Set Npred for full fit colnames.append("Npred_all") values["Npred_all"] = npred_all # Gather free full fit parameters for i in range(result_all.size()): model = result_all[i] model_name = model.name() for k in range(model.size()): par = model[k] if par.is_free(): # Set parameter name name = model_name + "_" + par.name() # Append value colnames.append(name) values[name] = par.value() # Append error name = "Unc_" + name colnames.append(name) values[name] = par.error() # Bundle together results result = {"colnames": colnames, "values": values} # Return return result
def trial(self, seed): """ Create the pull for a single trial. Parameters: seed - Random number generator seed """ # Write header if self.logExplicit(): self.log.header2("Trial "+str(seed+1)) # Simulate events obs = obsutils.sim(self.obs, \ nbins=self.m_enumbins, \ seed=seed, \ binsz=self.m_binsz, \ npix=self.m_npix, \ edisp=self.m_edisp, \ log=self.m_log, debug=self.m_debug) # Determine number of events in simulation nevents = 0.0 for run in obs: nevents += run.events().number() # Write simulation results if self.logExplicit(): self.log.header3("Simulation") self.log.parformat("Number of simulated events") self.log(nevents) self.log("\n") # Fit model like = obsutils.fit(obs, edisp=self.m_edisp, \ log=self.m_log, debug=self.m_debug) # Store results logL = like.opt().value() npred = like.obs().npred() models = like.obs().models() # Write result header if self.logExplicit(): self.log.header3("Pulls") # Gather results colnames = [] values = {} colnames.append("LogL") colnames.append("Sim_Events") colnames.append("Npred_Events") values["LogL"] = logL values["Sim_Events"] = nevents values["Npred_Events"] = npred for i in range(models.size()): model = models[i] model_name = model.name() for k in range(model.size()): par = model[k] if par.is_free(): # Set parameter name name = model_name+"_"+par.name() # Append parameter, Pull_parameter and Unc_parameter colnames.append(name) colnames.append("Pull_"+name) colnames.append("Unc_"+name) # Compute pull fitted_value = par.value() real_value = self.obs.models()[i][k].value() error = par.error() if error != 0.0: pull = (fitted_value - real_value) / error else: pull = 99.0 # Store results values[name] = fitted_value values["Pull_"+name] = pull values["Unc_"+name] = error # Write result if self.logExplicit(): self.log.parformat(name) self.log(pull) self.log(" (") self.log(fitted_value) self.log(" +/- ") self.log(error) self.log(")\n") # Bundle together results result = {'colnames': colnames, 'values': values} # Return return result