def _set_obs_ebounds(self, emin, emax): """ Set energy boundaries for observation container. Sets the energy boundaries for all observations in the observation container. Args: emin: Minimum energy emax: Maximum energy """ # Loop over all observations in container for obs in self._obs: # Get observation energy boundaries obs_ebounds = obs.events().ebounds() # Get minimum and maximum energy obs_emin = obs_ebounds.emin() obs_emax = obs_ebounds.emax() # Case A: bin fully contained in observation ebounds if obs_emin <= emin and obs_emax >= emax: ebounds = gammalib.GEbounds(emin, emax) # Case B: bin fully outside of obs ebounds elif emax < obs_emin or emin > obs_emax: # Set zero range (inspired by ctselect) e0 = gammalib.GEnergy(0.0, "TeV") ebounds = gammalib.GEbounds(e0, e0) # Case C: bin partly overlapping with observation ebounds else: # Set energy range as obs ebounds were fully contained inside energy bin set_emin = emin set_emax = emax # Adjust energy bin to respect observation energy boundary if emin < obs_emin: set_emin = obs_emin if emax > obs_emax: set_emax = obs_emax #Set energy boundaries ebounds = gammalib.GEbounds(set_emin, set_emax) # Set energy boundaries obs.events().ebounds(ebounds) # Return return
def _set_obs_ebounds(self, emin, emax): """ Set energy boundaries for all observations in container Parameters ---------- emin : `~gammalib.GEnergy` Minimum energy emax : `~gammalib.GEnergy` Maximum energy """ # Loop over all observations in container for i, obs in enumerate(self.obs()): # Get energy boundaries of the observation obs_ebounds = self._obs_ebounds[i] # Get minimum and maximum energy of the observation obs_emin = obs_ebounds.emin() obs_emax = obs_ebounds.emax() # If [emin,emax] is fully contained in the observation energy range # the use [emin,emax] as energy boundaries if obs_emin <= emin and obs_emax >= emax: ebounds = gammalib.GEbounds(emin, emax) # ... otherwise, if [emin,emax] is completely outside the # observation energy range then set the energy boundaries to the # zero-width interval [0,0] elif emax < obs_emin or emin > obs_emax: e0 = gammalib.GEnergy(0.0, 'TeV') ebounds = gammalib.GEbounds(e0, e0) # ... otherwise, if [emin,emax] overlaps partially with the # observation energy range then set the energy boundaries to the # overlapping part else: # Set overlapping energy range set_emin = max(emin, obs_emin) set_emax = min(emax, obs_emax) # Set energy boundaries ebounds = gammalib.GEbounds(set_emin, set_emax) # Set the energy boundaries as the boundaries of the observation obs.events().ebounds(ebounds) # Return return
def __init__(self, *argv): """ Constructor. """ # Set name self._name = 'csobsinfo' self._version = '1.1.0' # Initialise class members self._obj_dir = None self._compute_offset = False self._offsets = [] self._zeniths = [] self._azimuths = [] self._pnt_ra = [] self._pnt_dec = [] self._ebounds = gammalib.GEbounds() self._gti = gammalib.GGti() # Initialise observation container from constructor arguments. self._obs, argv = self._set_input_obs(argv) # Initialise application by calling the appropriate class # constructor. self._init_cscript(argv) # Return return
def generate_background_lookup(): """ Generate background lookup from empty field observations """ # Set filenames obsname = '$HESSDATA/obs/obs_off.xml' filename = 'off_lookup.fits' # Continue only if lookup table does not yet exist if not os.path.isfile(filename): # Initialise lookup table emin = gammalib.GEnergy(0.2, 'TeV') emax = gammalib.GEnergy(50.0, 'TeV') ebds = gammalib.GEbounds(10, emin, emax) lookup = gammalib.GCTAModelSpatialLookup(2.0, 0.2, ebds) # Load empty field observations obs = gammalib.GObservations(obsname) # Fill lookup table lookup.fill(obs) # Save lookup table lookup.save(filename, True) # Return return
def __init__(self, *argv): """ Constructor. """ # Set name self._name = 'csspec' self._version = '1.1.0' # Initialise some members self._ebounds = gammalib.GEbounds() self._fits = None self._binned_mode = False self._srcname = "" self._edisp = False self._calc_ulimit = True self._calc_ts = True self._fix_bkg = False self._fix_srcs = True self._chatter = 2 self._clobber = True self._debug = False # Initialise observation container from constructor arguments. self._obs, argv = self._set_input_obs(argv) # Initialise application by calling the appropriate class # constructor. self._init_cscript(argv) # Return return
def show_events(events, xmlname, duration, emin, emax, ebins=30): """ Show events using matplotlib. """ # Create figure plt.figure(1) plt.title("MC simulated event spectrum (" + str(emin) + '-' + str(emax) + " TeV)") # Setup energy range covered by data ebds = gammalib.GEbounds(ebins, gammalib.GEnergy(emin, "TeV"), gammalib.GEnergy(emax, "TeV")) # Create energy axis energy = [] for i in range(ebds.size()): energy.append(ebds.elogmean(i).TeV()) # Fill histogram counts = [0.0 for i in range(ebds.size())] for event in events: index = ebds.index(event.energy()) counts[index] = counts[index] + 1.0 # Create error bars error = [math.sqrt(c) for c in counts] # Get model values sum = 0.0 models = gammalib.GModels(xmlname) m = models[0] model = [] t = gammalib.GTime() for i in range(ebds.size()): eval = ebds.elogmean(i) ewidth = ebds.emax(i) - ebds.emin(i) f = m.npred(eval, t, obs) * ewidth.MeV() * duration sum += f model.append(f) print(str(sum) + " events expected from spectrum (integration).") # Plot data plt.loglog(energy, counts, 'ro') plt.errorbar(energy, counts, error, fmt=None, ecolor='r') # Plot model plt.plot(energy, model, 'b-') # Set axes plt.xlabel("Energy (TeV)") plt.ylabel("Number of events") # Notify print("PLEASE CLOSE WINDOW TO CONTINUE ...") # Show plot plt.show() # Return return
def plot_spectrum(model, emin=0.01, emax=100.0, enumbins=100, plotfile=''): """ Plot spectral model component Parameters ---------- model : `~gammalib.GModel` Model emin : float, optional Minimum energy (TeV) emax : float, optional Maximum energy (TeV) enumbins : integer, optional Number of energy bins plotfile : str, optional Name of plot file """ # Get spectral component spectrum = model.spectral() # Setup energy axis e_min = gammalib.GEnergy(emin, 'TeV') e_max = gammalib.GEnergy(emax, 'TeV') ebounds = gammalib.GEbounds(enumbins, e_min, e_max) # Setup model plot x = [] y = [] min = 1.0e30 max = 0.0 for i in range(enumbins): energy = ebounds.elogmean(i) value = spectrum.eval(energy) if value > max: max = value if value < min: min = value x.append(energy.TeV()) y.append(value) # Show spectrum plt.figure() plt.title(model.name() + ' (' + spectrum.type() + ')') plt.loglog() plt.grid() plt.loglog(x, y, color='red') plt.xlabel('Energy (TeV)') plt.ylabel(r'dN/dE (ph s$^{-1}$ cm$^{-2}$ MeV$^{-1}$)') #plt.ylim([min,max]) # Show spectrum or save it into file if len(plotfile) > 0: plt.savefig(plotfile) else: plt.show() # Return return
def _check_ebounds(self, filename, bins): """ Check energy boundaries file """ # Load energy boundaries file ebounds = gammalib.GEbounds(filename) # Check number of energy boundaries self.test_value(ebounds.size(), bins) # Return return
def __init__(self, *argv): """ Constructor """ # Initialise application by calling the appropriate class constructor self._init_csobservation(self.__class__.__name__, ctools.__version__, argv) # Set members self._ebounds = gammalib.GEbounds() # Return return
def _get_parameters(self): """ Get user parameters from parfile. """ # Set observation if not done before if self._obs == None or self._obs.size() == 0: self._obs = self._set_obs() # Set models if we have none if self._obs.models().size() == 0: self._obs.models(self["inmodel"].filename()) # Get source name self._srcname = self["srcname"].string() # Read further parameters self._outfile = self["outfile"].filename() self._emin = self["emin"].real() self._emax = self["emax"].real() self._bins = self["bins"].integer() # Read parameters for binned if requested self._enumbins = self["enumbins"].integer() if not self._enumbins == 0: self._npix = self["npix"].integer() self._binsz = self["binsz"].real() # Read remaining parameters self._edisp = self["edisp"].boolean() self._ts_thres = self["sigma"].real() * self["sigma"].real() self._max_iter = self["max_iter"].integer() self._num_avg = self["num_avg"].integer() self._type = self["type"].string() # Set some fixed parameters self._debug = self["debug"].boolean() # Debugging in client tools # Derive some parameters self._ebounds = gammalib.GEbounds(self._bins, gammalib.GEnergy(self._emin, "TeV"), gammalib.GEnergy(self._emax, "TeV")) # Write input parameters into logger if self._logTerse(): self._log_parameters() self._log("\n") # Return return
def _get_parameters(self): """ Get user parameters from parfile """ # Set observation if not done before if self.obs().size() == 0: self.obs(self._set_obs(self['emin'].real(), self['emax'].real())) # Set observation statistic self._set_obs_statistic(gammalib.toupper(self['statistic'].string())) # Set models if we have none if self.obs().models().size() == 0: self.obs().models(self['inmodel'].filename()) # Get source name self._srcname = self['srcname'].string() # Read further parameters emin = self['emin'].real() emax = self['emax'].real() bins = self['bins'].integer() # Query parameters for binned if requested enumbins = self['enumbins'].integer() if not enumbins == 0: self['npix'].integer() self['binsz'].real() # Query input parameters self['sigma'].real() self['max_iter'].integer() self['type'].string() self['outfile'].filename() self['edisp'].boolean() self['debug'].boolean() # Derive some parameters self._ebounds = gammalib.GEbounds(bins, gammalib.GEnergy(emin, 'TeV'), gammalib.GEnergy(emax, 'TeV')) # Write input parameters into logger self._log_parameters(gammalib.TERSE) # Set number of processes for multiprocessing self._nthreads = mputils.nthreads(self) # Return return
def __init__(self, *argv): """ Constructor """ # Initialise application by calling the appropriate class constructor self._init_csobservation(self.__class__.__name__, ctools.__version__, argv) # Initialise other variables self._ebounds = gammalib.GEbounds() self._etruebounds = gammalib.GEbounds() self._src_dir = gammalib.GSkyDir() self._src_reg = gammalib.GSkyRegions() self._models = gammalib.GModels() self._srcname = '' self._bkg_regs = [] self._excl_reg = None self._has_exclusion = False self._srcshape = '' self._rad = 0.0 self._nthreads = 0 # Return return
def __init__(self, *argv): """ Constructor """ # Initialise application by calling the base class constructor self._init_cscript(self.__class__.__name__, ctools.__version__, argv) # Initialise some members self._obs = gammalib.GObservations() self._ebounds = gammalib.GEbounds() self._datapath = os.getenv('VHEFITS', '') self._prodname = '' self._xml = gammalib.GXml() self._models = gammalib.GModels() self._runlist = [] self._runlistfile = gammalib.GFilename() self._bkgpars = 0 self._master_indx = '' self._use_bkg_scale = False self._ev_hiera = [''] self._aeff_hiera = [''] self._psf_hiera = [''] self._bkg_hiera = [''] self._edisp_hiera = [''] self._bkg_mod_hiera = [''] self._bkg_gauss_norm = 1.0 self._bkg_gauss_index = 0.0 self._bkg_gauss_sigma = 1.0 self._bkg_aeff_index = 0.0 self._bkg_aeff_norm = 1.0 self._bkg_range_factor = 1.0 self._hdu_index = '' self._obs_index = '' self._subdir = '' self._debug = False # Initialise empty observation definition XML file self._xml.append( gammalib.GXmlElement('observation_list ' 'title="observation list"')) # Append an observation list to XML instance self._xml.append( gammalib.GXmlElement('observation_list title="observation list"')) self._xml_obslist = self._xml.element('observation_list', 0) # Return return
def createobs(ra=86.171648, dec=-1.4774586, rad=5.0, emin=0.1, emax=100.0, duration=360000.0, deadc=0.95, ): obs = gammalib.GCTAObservation() # Set pointing direction pntdir = gammalib.GSkyDir() pntdir.radec_deg(ra, dec) pnt = gammalib.GCTAPointing() pnt.dir(pntdir) obs.pointing(pnt) # Set ROI roi = gammalib.GCTARoi() instdir = gammalib.GCTAInstDir() instdir.dir(pntdir) roi.centre(instdir) roi.radius(rad) # Set GTI gti = gammalib.GGti() start = gammalib.GTime(0.0) stop = gammalib.GTime(duration) gti.append(start, stop) # Set energy boundaries ebounds = gammalib.GEbounds() e_min = gammalib.GEnergy() e_max = gammalib.GEnergy() e_min.TeV(emin) e_max.TeV(emax) ebounds.append(e_min, e_max) # Allocate event list events = gammalib.GCTAEventList() events.roi(roi) events.gti(gti) events.ebounds(ebounds) obs.events(events) # Set ontime, livetime, and deadtime correction factor obs.ontime(duration) obs.livetime(duration * deadc) obs.deadc(deadc) # Return observation return obs
def generate_background_lookup(obslist=None, suffix=''): """ Generate background lookup from empty field observations Parameters ---------- obslist : list of int, optional Indices of observations to use suffix : str, optional Background lookup file suffix """ # Set filenames obsname = '$HESSDATA/obs/obs_off.xml' filename = 'bkg_lookup%s.fits' % suffix # Continue only if lookup table does not yet exist if not os.path.isfile(filename): # Initialise lookup table emin = gammalib.GEnergy(0.2, 'TeV') emax = gammalib.GEnergy(50.0, 'TeV') ebds = gammalib.GEbounds(10, emin, emax) lookup = gammalib.GCTAModelSpatialLookup(2.0, 0.2, ebds) # Load empty field observations obs = gammalib.GObservations(obsname) # If an observation list was specified then exclude observations # in list if obslist != None: newobs = gammalib.GObservations() for i, run in enumerate(obs): if i not in obslist: newobs.append(run) else: print('Exclude %s' % (run.id())) obs = newobs print('%d observations in lookup table' % (len(obs))) # Fill lookup table lookup.fill(obs) # Save lookup table lookup.save(filename, True) # Return return
def __init__(self, *argv): """ Constructor """ # Initialise application by calling the appropriate class constructor self._init_csobservation(self.__class__.__name__, ctools.__version__, argv) # Initialise data members self._ebounds = gammalib.GEbounds() self._fits = None self._binned_mode = False self._onoff_mode = False self._method = 'AUTO' self._nthreads = 0 # Return return
def __init__(self, *argv): """ Constructor. """ # Set name and version self._name = 'csiactobs' self._version = '1.1.0' # Initialise some members self._ebounds = gammalib.GEbounds() self._datapath = os.getenv('VHEFITS', '') self._inmodels = gammalib.GModels() self._prodname = '' self._xml = gammalib.GXml() self._models = gammalib.GModels() self._runlist = [] self._runlistfile = gammalib.GFilename() self._bkgpars = 0 self._outmodel = gammalib.GFilename() self._outobs = gammalib.GFilename() self._master_indx = '' self._use_bkg_scale = False self._ev_hiera = [''] self._aeff_hiera = [''] self._psf_hiera = [''] self._bkg_hiera = [''] self._edisp_hiera = [''] self._bkg_mod_hiera = [''] self._bkg_gauss_norm = 1.0 self._bkg_gauss_index = 0.0 self._bkg_gauss_sigma = 1.0 self._bkg_aeff_index = 0.0 self._bkg_aeff_norm = 1.0 self._bkg_range_factor = 1.0 self._hdu_index = '' self._obs_index = '' self._subdir = '' self._debug = False # Initialise application by calling the appropriate class # constructor. self._init_cscript(argv) # Return return
def __init__(self, *argv): """ Constructor. """ # Initialise application by calling the appropriate class constructor self._init_csobservation(self.__class__.__name__, ctools.__version__, argv) # Initialise class members self._ebounds = gammalib.GEbounds() self._obs_ebounds = [] self._srcname = '' self._ra = None self._dec = None self._log_clients = False self._models = gammalib.GModels() self._nthreads = 0 # Return return
def __init__(self, *argv): """ Constructor. """ # Initialise application by calling the appropriate class constructor self._init_csobservation(self.__class__.__name__, ctools.__version__, argv) # Initialise class members self._obj_dir = None self._compute_offset = False self._offsets = [] self._zeniths = [] self._azimuths = [] self._pnt_ra = [] self._pnt_dec = [] self._ebounds = gammalib.GEbounds() self._gti = gammalib.GGti() # Return return
def plot_spectrum(model_file, emin=0.03, emax=150.0, enumbins=100): models = gammalib.GModels(model_file) spectral_model = models["Crab"].spectral() e_min = gammalib.GEnergy(emin, "TeV") e_max = gammalib.GEnergy(emax, "TeV") ebounds = gammalib.GEbounds(enumbins, e_min, e_max) x = [] y = [] for i in range(enumbins): energy = ebounds.elogmean(i) value = spectral_model.eval(energy) x.append(energy.TeV()) y.append(value) plt.figure() plt.title(models["Crab"].name() + " (" + spectral_model.type() + ")") plt.grid() plt.loglog(x, y, color="red") plt.xlabel("Energy (TeV)") plt.ylabel("dN/dE ph/cm²/s/MeV") plt.show()
def __init__(self, *argv): """ Constructor. """ # Set name self._name = "cssens" self._version = "1.1.0" # Initialise class members self._obs = gammalib.GObservations() self._ebounds = gammalib.GEbounds() self._obs_ebounds = [] self._srcname = "" self._outfile = gammalib.GFilename() self._ra = None self._dec = None self._edisp = False self._emin = 0.020 self._emax = 200.0 self._bins = 21 self._enumbins = 0 self._npix = 200 self._binsz = 0.05 self._type = "Differential" self._ts_thres = 25.0 self._max_iter = 50 self._num_avg = 3 self._log_clients = False self._debug = False # Initialise application by calling the appropriate class # constructor. self._init_cscript(argv) # Return return
def _etrue_ebounds(self): """ Set true energy boundaries Returns ------- ebounds : `~gammalib.GEbounds()` True energy boundaries """ # Determine minimum and maximum energies emin = self._ebounds.emin() * 0.5 emax = self._ebounds.emax() * 1.2 if emin.TeV() < self['etruemin'].real(): emin = gammalib.GEnergy(self['etruemin'].real(), 'TeV') if emax.TeV() > self['etruemax'].real(): emax = gammalib.GEnergy(self['etruemax'].real(), 'TeV') # Determine number of energy bins n_decades = (emax.log10TeV() - emin.log10TeV()) n_bins = int(n_decades * float(self['etruebins'].integer()) + 0.5) if n_bins < 1: n_bins = 1 # Set energy boundaries ebounds = gammalib.GEbounds(n_bins, emin, emax) # Write header self._log_header1(gammalib.TERSE, 'True energy binning') # Log true energy bins for i in range(ebounds.size()): value = '%s - %s' % (str(ebounds.emin(i)), str(ebounds.emax(i))) self._log_value(gammalib.TERSE, 'Bin %d' % (i + 1), value) # Return energy boundaries return ebounds
def show_residuals(obslist=None, emin=0.2, emax=20.0, ebins=20, npix=200, binsz=0.02, suffix=''): """ Show residuals for all OFF observations Parameters ---------- obslist : list of ints, optional Index of observations to stack emin : float, optional Minimum energy (TeV) emax : float, optional Maximum energy (TeV) ebins : int, optional Number of energy bins npix : int, optional Number of spatial pixels binsz : float, optional Spatial bin size suffix : str, optional Plot filename suffix """ # Set XML filename obsname = '$HESSDATA/obs/obs_off.xml' # Generate background lookup generate_background_lookup(obslist=obslist, suffix=suffix) # If observation list is specified and suffix is empty then build suffix if obslist != None and suffix == '': for obs in obslist: suffix += '_%2.2d' % obs # Set stacked cube filenames cntfile = 'off_stacked_counts%s.fits' % (suffix) modfile = 'off_stacked_model%s.fits' % (suffix) # If stacked cubes exist then load them if os.path.isfile(cntfile) and os.path.isfile(modfile): cntcube_stacked = gammalib.GCTAEventCube(cntfile) modcube_stacked = gammalib.GCTAEventCube(modfile) # ... otherwise generate them else: # Define counts and model cubes for stacking map = gammalib.GSkyMap('TAN', 'CEL', 0.0, 0.0, -binsz, binsz, npix, npix, ebins) ebds = gammalib.GEbounds(ebins, gammalib.GEnergy(emin, 'TeV'), gammalib.GEnergy(emax, 'TeV')) gti = gammalib.GGti(gammalib.GTime(0.0, 's'), gammalib.GTime(1.0, 's')) cntcube_stacked = gammalib.GCTAEventCube(map, ebds, gti) modcube_stacked = gammalib.GCTAEventCube(map, ebds, gti) # Load observations inobs = gammalib.GObservations(obsname) # Loop over runs in observations for i, run in enumerate(inobs): # If an observation list is defined then skip observation if it # is not in list if obslist != None: if i not in obslist: continue # Build observation container with single run obs = gammalib.GObservations() obs.append(run) # Select events obs = select_events(obs, emin=emin, emax=emax) # Generate background model models = get_bkg_model(obs, suffix=suffix) # Attach models to observation container obs.models(models) # Create counts cube cntcube = create_cntcube(obs, emin=emin, emax=emax, ebins=ebins, npix=npix, binsz=binsz) # Create model cube modcube = create_modcube(obs, cntcube) # Stack cubes cntcube_stacked = stack_cube(cntcube_stacked, cntcube) modcube_stacked = stack_cube(modcube_stacked, modcube) # Stop after first run #break # Save cubes cntcube_stacked.save(cntfile, True) modcube_stacked.save(modfile, True) # Plot stacked cubes plot(cntcube_stacked, modcube_stacked, suffix=suffix) plot_sectors(cntcube_stacked, modcube_stacked, suffix=suffix) plot_radial_profiles(cntcube_stacked, modcube_stacked, suffix=suffix) # Return return
def run(self): """ Run the script Raises ------ RuntimeError Invalid pointing definition file format """ # Switch screen logging on in debug mode if self._logDebug(): self._log.cout(True) # Get parameters self._get_parameters() # Write header into logger self._log_header1(gammalib.TERSE, 'Creating observation definition XML file') # Load pointing definition file if it is not already set. Extract # the number of columns and pointings if self._pntdef.size() == 0: self._pntdef = gammalib.GCsv(self['inpnt'].filename(), ',') ncols = self._pntdef.ncols() npnt = self._pntdef.nrows() - 1 # Raise an exception if there is no header information if self._pntdef.nrows() < 1: raise RuntimeError('No header found in pointing definition file.') # Clear observation container self._obs.clear() # Initialise observation identifier counter identifier = 1 # Extract header columns from pointing definition file and put them # into a list header = [] for col in range(ncols): header.append(self._pntdef[0, col]) # Loop over all pointings for pnt in range(npnt): # Set pointing definition CSV file row index row = pnt + 1 # Create empty CTA observation obs = gammalib.GCTAObservation() # Set observation name. If no observation name was given then # use "None". if 'name' in header: name = self._pntdef[row, header.index('name')] else: name = self['name'].string() obs.name(name) # Set observation identifier. If no observation identified was # given the use the internal counter. if 'id' in header: obsid = self._pntdef[row, header.index('id')] else: obsid = '%6.6d' % identifier identifier += 1 obs.id(obsid) # Set pointing. Either use "ra" and "dec" or "lon" and "lat". # If none of these pairs are given then raise an exception. if 'ra' in header and 'dec' in header: ra = float(self._pntdef[row, header.index('ra')]) dec = float(self._pntdef[row, header.index('dec')]) pntdir = gammalib.GSkyDir() pntdir.radec_deg(ra, dec) elif 'lon' in header and 'lat' in header: lon = float(self._pntdef[row, header.index('lon')]) lat = float(self._pntdef[row, header.index('lat')]) pntdir = gammalib.GSkyDir() pntdir.lb_deg(lon, lat) else: raise RuntimeError('No (ra,dec) or (lon,lat) columns ' 'found in pointing definition file.') obs.pointing(gammalib.GCTAPointing(pntdir)) # Set response function. If no "caldb" or "irf" information is # provided then use the user parameter values. if 'caldb' in header: caldb = self._pntdef[row, header.index('caldb')] else: caldb = self['caldb'].string() if 'irf' in header: irf = self._pntdef[row, header.index('irf')] else: irf = self['irf'].string() if caldb != '' and irf != '': obs = self._set_irf(obs, caldb, irf) # Set deadtime correction factor. If no information is provided # then use the user parameter value "deadc". if 'deadc' in header: deadc = float(self._pntdef[row, header.index('deadc')]) else: deadc = self['deadc'].real() obs.deadc(deadc) # Set Good Time Interval. If no information is provided then use # the user parameter values "tmin" and "duration". if 'tmin' in header: self._tmin = float(self._pntdef[row, header.index('tmin')]) if 'duration' in header: duration = float(self._pntdef[row, header.index('duration')]) else: duration = self['duration'].real() tref = gammalib.GTimeReference(self['mjdref'].real(), 's') tmin = self._tmin tmax = self._tmin + duration gti = gammalib.GGti(tref) tstart = gammalib.GTime(tmin, tref) tstop = gammalib.GTime(tmax, tref) self._tmin = tmax gti.append(tstart, tstop) obs.ontime(gti.ontime()) obs.livetime(gti.ontime() * deadc) # Set Energy Boundaries. If no "emin" or "emax" information is # provided then use the user parameter values in case they are # valid. has_emin = False has_emax = False if 'emin' in header: emin = float(self._pntdef[row, header.index('emin')]) has_emin = True else: if self['emin'].is_valid(): emin = self['emin'].real() has_emin = True if 'emax' in header: emax = float(self._pntdef[row, header.index('emax')]) has_emax = True else: if self['emax'].is_valid(): emax = self['emax'].real() has_emax = True has_ebounds = has_emin and has_emax if has_ebounds: ebounds = gammalib.GEbounds(gammalib.GEnergy(emin, 'TeV'), gammalib.GEnergy(emax, 'TeV')) # Set ROI. If no ROI radius is provided then use the user # parameters "rad". has_roi = False if 'rad' in header: rad = float(self._pntdef[row, header.index('rad')]) has_roi = True else: if self['rad'].is_valid(): rad = self['rad'].real() has_roi = True if has_roi: roi = gammalib.GCTARoi(gammalib.GCTAInstDir(pntdir), rad) # Create an empty event list event_list = gammalib.GCTAEventList() event_list.gti(gti) # If available, set the energy boundaries and the ROI if has_ebounds: event_list.ebounds(ebounds) if has_roi: event_list.roi(roi) # Attach event list to CTA observation obs.events(event_list) # Write observation into logger name = obs.instrument() + ' observation' value = 'Name="%s" ID="%s"' % (obs.name(), obs.id()) self._log_value(gammalib.NORMAL, name, value) self._log_string(gammalib.EXPLICIT, str(obs) + '\n') # Append observation self._obs.append(obs) # Return return
def set_obs(pntdir, tstart=0.0, duration=1800.0, deadc=0.95, \ emin=0.1, emax=100.0, rad=5.0, \ irf="South_50h", caldb="prod2", id="000000"): """ Set a single CTA observation. The function sets a single CTA observation containing an empty CTA event list. By looping over this function you can add CTA observations to the observation container. Args: pntdir: Pointing direction [GSkyDir] Kwargs: tstart: Start time (seconds) (default: 0.0) duration: Duration of observation (seconds) (default: 1800.0) deadc: Deadtime correction factor (default: 0.95) emin: Minimum event energy (TeV) (default: 0.1) emax: Maximum event energy (TeV) (default: 100.0) rad: ROI radius used for analysis (deg) (default: 5.0) irf: Instrument response function (default: "South_50h") caldb: Calibration database path (default: "prod2") id: Run identifier (default: "000000") """ # Allocate CTA observation obs_cta = gammalib.GCTAObservation() # Set calibration database db = gammalib.GCaldb() if (gammalib.dir_exists(caldb)): db.rootdir(caldb) else: db.open("cta", caldb) # Set pointing direction pnt = gammalib.GCTAPointing() pnt.dir(pntdir) obs_cta.pointing(pnt) # Set ROI roi = gammalib.GCTARoi() instdir = gammalib.GCTAInstDir() instdir.dir(pntdir) roi.centre(instdir) roi.radius(rad) # Set GTI gti = gammalib.GGti() gti.append(gammalib.GTime(tstart), gammalib.GTime(tstart + duration)) # Set energy boundaries ebounds = gammalib.GEbounds(gammalib.GEnergy(emin, "TeV"), gammalib.GEnergy(emax, "TeV")) # Allocate event list events = gammalib.GCTAEventList() events.roi(roi) events.gti(gti) events.ebounds(ebounds) obs_cta.events(events) # Set instrument response obs_cta.response(irf, db) # Set ontime, livetime, and deadtime correction factor obs_cta.ontime(duration) obs_cta.livetime(duration * deadc) obs_cta.deadc(deadc) obs_cta.id(id) # Return CTA observation return obs_cta
def _background_spectrum(self, run, prefactor, index, emin=0.01, emax=100.0): # Handle constant spectral model if index == 0.0 and self._bkgpars <= 1: spec = gammalib.GModelSpectralConst() spec['Normalization'].min(prefactor / self._bkg_range_factor) spec['Normalization'].max(prefactor * self._bkg_range_factor) spec['Normalization'].value(prefactor) if self._bkgpars == 0: spec['Normalization'].fix() else: spec['Normalization'].free() else: # Create power law model if self._bkgpars <= 2: e = gammalib.GEnergy(1.0, 'TeV') spec = gammalib.GModelSpectralPlaw(prefactor, index, e) # Set parameter ranges spec[0].min(prefactor / self._bkg_range_factor) spec[0].max(prefactor * self._bkg_range_factor) spec[1].scale(1) spec[1].min(-5.0) spec[1].max(5.0) # Set number of free parameters if self._bkgpars == 0: spec[0].fix() spec[1].fix() elif self._bkgpars == 1: spec[0].free() spec[1].fix() else: spec[0].free() spec[1].free() else: # Create reference powerlaw plaw = gammalib.GModelSpectralPlaw( prefactor, index, gammalib.GEnergy(1.0, 'TeV')) # Create spectral model and energy values spec = gammalib.GModelSpectralNodes() bounds = gammalib.GEbounds(self._bkgpars, gammalib.GEnergy(emin, 'TeV'), gammalib.GEnergy(emax, 'TeV'), True) for i in range(bounds.size()): energy = bounds.elogmean(i) value = plaw.eval(energy, gammalib.GTime()) spec.append(energy, value) for par in spec: if 'Energy' in par.name(): par.fix() elif 'Intensity' in par.name(): value = par.value() par.scale(value) par.min(value / self._bkg_range_factor) par.max(value * self._bkg_range_factor) # Return spectrum return spec
def _select_onoff_obs(self, obs, emin, emax): """ Select an energy interval from one CTA On/Off observation Parameters ---------- obs : `~gammalib.GCTAOnOffObservation` Minimum energy emin : `~gammalib.GEnergy()` Minimum energy emax : `~gammalib.GEnergy()` Maximum energy Returns ------- obs : `~gammalib.GCTAOnOffObservation` CTA On/Off observation """ # Select energy bins in etrue and ereco. All etrue energy bins are # selected. A 0.1% margin is added for reconstructed energies to # accomodate for rounding errors. etrue = obs.rmf().etrue() ereco = gammalib.GEbounds() itrue = [i for i in range(obs.rmf().etrue().size())] ireco = [] for i in range(obs.rmf().emeasured().size()): ereco_bin_min = obs.rmf().emeasured().emin(i) ereco_bin_max = obs.rmf().emeasured().emax(i) if ereco_bin_min * 1.001 >= emin and ereco_bin_max * 0.999 <= emax: ereco.append(ereco_bin_min, ereco_bin_max) ireco.append(i) # Extract PHA pha_on = gammalib.GPha(ereco) pha_off = gammalib.GPha(ereco) pha_on.exposure(obs.on_spec().exposure()) pha_off.exposure(obs.on_spec().exposure()) for idst, isrc in enumerate(ireco): # On pha_on[idst] = obs.on_spec()[isrc] pha_on.areascal(idst, obs.on_spec().areascal(isrc)) pha_on.backscal(idst, obs.on_spec().backscal(isrc)) # Off pha_off[idst] = obs.off_spec()[isrc] pha_off.areascal(idst, obs.off_spec().areascal(isrc)) pha_off.backscal(idst, obs.off_spec().backscal(isrc)) # Extract BACKRESP pha_backresp = obs.off_spec()['BACKRESP'] backresp = [] for idst, isrc in enumerate(ireco): backresp.append(pha_backresp[isrc]) pha_off.append('BACKRESP', backresp) # Extract ARF arf = gammalib.GArf(etrue) for idst, isrc in enumerate(itrue): arf[idst] = obs.arf()[isrc] # Extract RMF rmf = gammalib.GRmf(etrue, ereco) for idst_true, isrc_true in enumerate(itrue): for idst_reco, isrc_reco in enumerate(ireco): rmf[idst_true, idst_reco] = obs.rmf()[isrc_true, isrc_reco] # Set On/Off observations obsid = obs.id() statistic = obs.statistic() instrument = obs.instrument() obs = gammalib.GCTAOnOffObservation(pha_on, pha_off, arf, rmf) obs.id(obsid) obs.statistic(statistic) obs.instrument(instrument) # Return observation return obs
def _set_ebounds(self): """ Set energy boundaries """ # If we are in binned or On/Off mode then align the energy boundaries # with the cube of RMF spectrum if self._binned_mode or self._onoff_mode: # Initialise energy boundaries for spectrum self._ebounds = gammalib.GEbounds() # Create energy boundaries according to user parameters ebounds = self._create_ebounds() # Extract binned energy boundaries from first observation in # container. This assumes that all observations have the same # energy binning. But even if this is not the case, the script # should work reasonably well since for each observation the # relevant energy bins will be selected. if self._binned_mode: cube_ebounds = self.obs()[0].events().ebounds() else: cube_ebounds = self.obs()[0].rmf().emeasured() # Loop over user energy boundaries and collect all energy bins # that overlap for i in range(ebounds.size()): # Extract minimum and maximum energy of user energy bin, # including some rounding tolerance emin = ebounds.emin(i).TeV() * 0.999 # Rounding tolerance emax = ebounds.emax(i).TeV() * 1.001 # Rounding tolerance # Set number of overlapping energy bins nbins = 0 # Search first cube bin that is comprised within user energy # bin emin_value = -1.0 for k in range(cube_ebounds.size()): if cube_ebounds.emin(k).TeV() >= emin and \ cube_ebounds.emax(k).TeV() <= emax: emin_value = cube_ebounds.emin(k).TeV() break if emin_value < 0.0: continue # Search last cube bin that is comprised within user energy bin for k in range(cube_ebounds.size()): if cube_ebounds.emin(k).TeV() >= emin and \ cube_ebounds.emax(k).TeV() <= emax: emax_value = cube_ebounds.emax(k).TeV() nbins += 1 # Append energy bin if there are overlapping bins in the # counts cube if nbins > 0: self._ebounds.append(gammalib.GEnergy(emin_value, 'TeV'), gammalib.GEnergy(emax_value, 'TeV')) # Raise an exception if there are no overlapping layers if (len(self._ebounds) == 0): msg = 'Energy range ['+str(cube_ebounds.emin())+ \ ', '+str(cube_ebounds.emax())+'] of counts '+ \ 'cube does not overlap with specified energy '+ \ 'range ['+ \ str(ebounds.emin())+', '+str(ebounds.emax())+'].'+ \ ' Specify overlapping energy range.' raise RuntimeError(msg) # Unbinned mode else: self._ebounds = self._create_ebounds() # Return return
roi = gammalib.GCTARoi() instdir = gammalib.GCTAInstDir() instdir.dir(pntdir) roi.centre(instdir) roi.radius(rad) #Set GTI gti = gammalib.GGti() start = gammalib.GTime(tstart) stop = gammalib.GTime(tstart + duration) gti.append(start, stop) #Set Energy Boundaries ebounds = gammalib.GEbounds() e_min = gammalib.GEnergy(emin, 'TeV') e_max = gammalib.GEnergy(emax, 'TeV') ebounds.append(e_min, e_max) #Allocate event list events = gammalib.GCTAEventList(eventfile) obs.eventfile(eventfile) events.roi(roi) events.gti(gti) events.ebounds(ebounds) obs.events(events) #Set instrument response obs.response(irf, caldb)
def _background_spectrum(self, prefactor, index, emin=0.01, emax=100.0): """ Create a background spectrum model dependent on user parameters Parameters ---------- prefactor : float Power law prefactor of spectral model index : float Power law index of spectral model emin : float Minimum energy (in case a spectral node function is required) emax : float Maximum energy (in case a spectral node function is required) Returns ------- spec : `~gammalib.GModelSpectral()` Spectral model for the background shape """ # Handle constant spectral model if index == 0.0 and self._bkgpars <= 1: spec = gammalib.GModelSpectralConst() # Set parameter range spec['Normalization'].min(prefactor / self._bkg_range_factor) spec['Normalization'].max(prefactor * self._bkg_range_factor) spec['Normalization'].value(prefactor) # Freeze or release normalisation parameter if self._bkgpars == 0: spec['Normalization'].fix() else: spec['Normalization'].free() else: # Create power law model if self._bkgpars <= 2: # Set Power Law model with arbitrary pivot energy pivot = gammalib.GEnergy(1.0, 'TeV') spec = gammalib.GModelSpectralPlaw(prefactor, index, pivot) # Set parameter ranges spec[0].min(prefactor / self._bkg_range_factor) spec[0].max(prefactor * self._bkg_range_factor) spec[1].scale(1) spec[1].min(-5.0) spec[1].max(5.0) # Set number of free parameters if self._bkgpars == 0: spec[0].fix() spec[1].fix() elif self._bkgpars == 1: spec[0].free() spec[1].fix() else: spec[0].free() spec[1].free() else: # Create reference powerlaw pivot = gammalib.GEnergy(1.0, 'TeV') plaw = gammalib.GModelSpectralPlaw(prefactor, index, pivot) # Create spectral model and energy values spec = gammalib.GModelSpectralNodes() # Create logarithmic energy nodes bounds = gammalib.GEbounds(self._bkgpars, gammalib.GEnergy(emin, 'TeV'), gammalib.GEnergy(emax, 'TeV'), True) # Loop over bounds and set intensity value for i in range(bounds.size()): energy = bounds.elogmean(i) value = plaw.eval(energy) # Append energy, value - tuple to node function spec.append(energy, value) # Loop over parameters for par in spec: # Fix energy nodes if 'Energy' in par.name(): par.fix() # Release intensity nodes elif 'Intensity' in par.name(): value = par.value() par.scale(value) par.min(value / self._bkg_range_factor) par.max(value * self._bkg_range_factor) # Return spectrum return spec