def survey_single(): """ Creates a single observation survey for test purposes. """ # Allocate observation container obs = gammalib.GObservations() # Set single pointing at galactic centre pntdir = gammalib.GSkyDir() pntdir.lb_deg(0.0, 0.0) run = obsutils.set_obs(pntdir) obs.append(run) # Define single point source with Crab flux at galactic centre center = gammalib.GSkyDir() center.lb_deg(0.0, 0.0) point_spatial = gammalib.GModelSpatialPointSource(center) point_spectrum = crab_spec() point = gammalib.GModelSky(point_spatial, point_spectrum) point.name('GC source') # Create model container models = gammalib.GModels() models.append(point) obs.models(models) # Return observation container return obs
def set_lmc(hours=250.0, lst=True): """ Setup LMC KSP. Parameters ---------- hours : float, optional Total observation duration (h) lst : bool, optional Use LSTs Returns ------- obsdef : list of dict List of pointing definitions """ # Initialise observation definition obsdef = [] # Set LMC centre centre = gammalib.GSkyDir() centre.radec_deg(80.0, -69.0) # Set offset angle and number of pointings offset = 1.0 # degrees n_pnt = 12 # Prepare computations dphi = 360.0/n_pnt duration = hours*3600.0/float(n_pnt) # Loop over pointings for ipnt in range(n_pnt): # Compute pointing direction pnt = centre.copy() pnt.rotate_deg(ipnt*dphi, offset) lon = pnt.l_deg() lat = pnt.b_deg() # Set positions and duration obs = {'lon': lon, 'lat': lat, 'duration': duration} # Add IRF caldb = 'prod2' if lst: irf = 'South_50h' else: irf = 'South_50h' obs['caldb'] = caldb obs['irf'] = irf # Append observation obsdef.append(obs) # Dump statistics print('Number of pointings: %d (%.2f s)' % (n_pnt,duration)) # Return observation definition return obsdef
def _get_parameters(self): """ Get parameters from parfile and setup the observation """ # Get parameters if self.obs().size() == 0: self._require_inobs('csobsinfo::get_parameters') self.obs(self._get_observations(False)) # Initialise object position self._obj_dir = gammalib.GSkyDir() # Get (optional) offset parameters self._compute_offset = self['offset'].boolean() if self._compute_offset: ra = self['ra'].real() dec = self['dec'].real() self._obj_dir.radec_deg(ra, dec) # Read ahead DS9 filename if self._read_ahead(): self['outds9file'].query() # Write input parameters into logger self._log_parameters(gammalib.TERSE) # Return return
def _query_src_direction(self): """ Set up the source direction parameter """ # Initialise source direction self._src_dir = gammalib.GSkyDir() # Get coordinate systel coordsys = self['coordsys'].string() # If coordinate system is celestial then query "ra" and "dec" if coordsys == 'CEL': ra = self['ra'].real() dec = self['dec'].real() self._src_dir.radec_deg(ra, dec) # ... otherwise, if coordinate system is galactic then query "glon" # and "glat" elif coordsys == 'GAL': glon = self['glon'].real() glat = self['glat'].real() self._src_dir.lb_deg(glon, glat) # Return return
def set_map(obsdef, radius=2.0): """ Set map from observation definition dictionary Parameters ---------- obsdef : list of dict List of pointing definitions """ # Create sky map map = gammalib.GSkyMap('CAR', 'GAL', 340.0, 0.0, -0.1, 0.1, 950, 100) # Loop over observations for obs in obsdef: # Set sky region centre = gammalib.GSkyDir() centre.lb_deg(obs['lon'], obs['lat']) circle = gammalib.GSkyRegionCircle(centre, radius) region = gammalib.GSkyRegionMap(circle) exposure = region.map().copy() exposure *= obs['duration']/3600.0 # Add sky region map += exposure # Return map return map
def print_values_gammalib(): """Print some Gammalib model values that can be used for unit tests. Gammalib uses normalised PDFs, i.e. eval() returns probability / steradian so that the integral is one. """ import numpy as np import gammalib # We need some dummy variables center = gammalib.GSkyDir() center.radec_deg(0, 0) energy = gammalib.GEnergy() time = gammalib.GTime() FWHM_TO_SIGMA = 1. / np.sqrt(8 * np.log(2)) g = gammalib.GModelSpatialRadialGauss( center, PIX_TO_DEG * FWHM_TO_SIGMA * GAUSS_FWHM) d = gammalib.GModelSpatialRadialDisk(center, PIX_TO_DEG * DISK_R0) s = gammalib.GModelSpatialRadialShell(center, PIX_TO_DEG * SHELL_R0, PIX_TO_DEG * SHELL_WIDTH) models = [('g', g), ('d', d), ('s', s)] for name, model in models: for theta in THETAS: theta_radians = np.radians(PIX_TO_DEG * theta) gammalib_value = model.eval(theta_radians, energy, time) sherpa_value = INTEGRAL * gammalib_value * np.radians( PIX_TO_DEG)**2 print name, theta, sherpa_value
def create_region_maps(rad_on=0.6, rad_off=[0.8, 1.0]): """ Create region maps Parameters ---------- rad_on : float, optional On region radius (deg) rad_off : list of float, optional Off region minimum and maximum radius (deg) """ # Set centre centre = gammalib.GSkyDir() centre.radec_deg(258.1125, -39.6867) # Create sky maps srcreg = gammalib.GSkyMap('TAN', 'CEL', 258.1125, -39.6867, 0.01, 0.01, 300, 300) bkgreg = gammalib.GSkyMap('TAN', 'CEL', 258.1125, -39.6867, 0.01, 0.01, 300, 300) # Fill sky map for i in range(srcreg.npix()): rad = centre.dist_deg(srcreg.inx2dir(i)) if rad <= rad_on: srcreg[i] = 1 if rad > rad_off[0] and rad < rad_off[1]: bkgreg[i] = 1 # Save maps srcreg.save('rx_srcreg_map.fits', True) bkgreg.save('rx_bkgreg_map.fits', True) # Return return
def zenith_moon(time, array='South'): """ Compute zenith angle of the Moon at a given time Parameters ---------- time : `~gammalib.GTime()` Time for which the Moon zenith angle is to be computed array : string, optional Array site Returns ------- zenith : float Moon zenith angle in (degrees) """ # Compute Right Ascension and Declination of Moon in degrees and convert # the Declination into radians moon = gammalib.GSkyDir() moon.moon(time) # Get zenith angle zenith = zenith_dir(time, moon, array=array) # Return zenith angle return zenith
def bin2gammalib(filename, flux_thresh, outdir): data = open(filename).readlines() # convert phasogram to numpy array phasogram = np.genfromtxt(data[14:]) # only include model if peak in lightcurve is > threshold if np.max(phasogram[:, 2]) > flux_thresh: # final name num = int(data[0].split('#')[-1]) name = 'bin{:03d}'.format(num) # spatial model # read Galactic longitude lon = float(data[1].split(' ')[-1]) # Galactic latitude is random with Gaussian distribution with 95% containment at bmax lat = np.random.normal(0, bmax / 2) src_dir = gammalib.GSkyDir() src_dir.lb_deg(lon, lat) spatial = gammalib.GModelSpatialPointSource(src_dir) # spectral model # average flux in ph/cm2/s f0 = np.average(phasogram[:, 1]) # convert to differential flux at eref in ph/cm2/s/MeV n0 = (gamma - 1) * f0 / eref spectral = gammalib.GModelSpectralPlaw( n0, -gamma, gammalib.GEnergy(np.double(eref), 'MeV')) # orbital phase model # create phasogram file fname = 'phasecurve_' + name + '.fits' phasogram_file(phasogram, outdir + fname, outdir) # period in days per = float(data[4].split(' ')[-1]) # convert to frequency in s per *= 86400 f0 = 1 / per temporal = gammalib.GModelTemporalPhaseCurve( gammalib.GFilename(fname), t0, np.random.random(), # phase at t0 randomly drawn f0, 0., 0., # orbit is stable, no derivatives 1., True) # normalized so that spectral model represents average flux # assemble final model model = gammalib.GModelSky(spatial, spectral, temporal) model.name(name) else: # empty model lat = 0. model = gammalib.GModelSky() return model, lat
def set_patch(tmin, xmin, xmax, duration, array): obsdef = [] # set as many observations as allowed by total duration time and observation length n_pnt = int(duration / obs_time) - 2 # - 2 to allow for margin in get_positions xstep = 2 * (xmax - xmin) / n_pnt pointings = get_positions(xmin, xmax, nrows, step, fixed_xstep=xstep) # Set observations total_duration = 0 for pnt in pointings: # Set positions, start time and duration obs = {'lon': pnt['x'], 'lat': pnt['y'], 'rad': rad, \ 'tmin': tmin, 'duration': obs_time * 3600.} # Update start time for next pointing tmin = set_tmin_for_next_pointing(tmin, obs_time * 3600.) # Find Dec for pointing pnt_dir = gammalib.GSkyDir() pnt_dir.lb_deg(pnt['x'], pnt['y']) dec = pnt_dir.dec_deg() # Automatic IRF setting # Set geographic latitude of array if array == 'North': geolat = +28.7569 else: geolat = -24.58 # Compute best possible zenith angle zenith = abs(dec - geolat) # Assign IRF zenith if zenith < 30.0: irfz = 20 elif zenith < 50.0: irfz = 40 else: irfz = 60 irf = '{}_z{}_50h'.format(array, irfz) # Set IRF information obs['caldb'] = caldb obs['irf'] = irf # Append observation obsdef.append(obs) # Add to total duration total_duration += obs_time # check that total duration is preserved if total_duration == duration: pass else: print( 'WARNING: total duration of {} h and requested observation of {} do not match'.format( total_duration, duration)) return obsdef
def set_irf(site, obs, caldb, lst=True): """ Setup Instrument Response Function Parameters ---------- site : str Array site (either 'South' or 'North') obs : dict Dictionary with pointing information caldb : str Calibration database lst : bool, optional Use LSTs Returns ------- irf : str IRF name """ # Handle 'prod2' if caldb == 'prod2': if site == 'North': irf = 'North_50h' else: irf = 'South_50h' # Handle 'prod3' and 'prod3b' else: # Compute Right Ascension and Declination of pointing pnt = gammalib.GSkyDir() pnt.lb_deg(obs['lon'], obs['lat']) #ra = pnt.ra_deg() dec = pnt.dec_deg() # Set geographic latitude of array if site == 'North': geolat = +28.7569 else: geolat = -24.58 # Compute best possible zenith angle zenith = abs(dec - geolat) # Set IRF if site == 'North': irf = 'North' else: irf = 'South' if zenith < 30.0: irf += '_z20' else: irf += '_z40' irf += '_50h' # Return IRF return irf
def write_obsdef(filename, obsdef, idstart): """ Write observation definition dictionary Parameters ---------- filename : str Observation definition file name obsdef : list of dict List of pointing definitions idstart : int First identifier of observation definition file """ # Open file f = open(filename, 'w') # Write header f.write('id,ra,dec,tmin,duration,caldb,irf,emin,emax\n') # Initialise identifier obsid = idstart # Loop over pointings for obs in obsdef: # If we have lon,lat then convert into RA,Dec if 'lon' in obs and 'lat' in obs: lon = obs['lon'] lat = obs['lat'] pnt = gammalib.GSkyDir() pnt.lb_deg(lon,lat) ra = pnt.ra_deg() dec = pnt.dec_deg() else: ra = obs['ra'] dec = obs['dec'] # Set site dependent energy thresholds if 'South' in obs['irf']: emin = 0.030 emax = 160.0 else: emin = 0.030 emax = 50.0 # Write information f.write('%6.6d,%8.4f,%8.4f,%.4f,%.4f,%s,%s,%.3f,%.1f\n' % (obsid, ra, dec, obs['tmin'], obs['duration'], obs['caldb'], \ obs['irf'], emin, emax)) # Increment identifier obsid += 1 # Close file f.close() # Return return
def _set_obs(self, lpnt=0.0, bpnt=0.0, emin=0.1, emax=100.0): """ Set an observation container. Kwargs: lpnt: Galactic longitude of pointing [deg] (default: 0.0) bpnt: Galactic latitude of pointing [deg] (default: 0.0) emin: Minimum energy [TeV] (default: 0.1) emax: Maximum energy [TeV] (default: 100.0) Returns: Observation container. """ # If an observation was provided on input then load it from XML # file filename = self["inobs"].filename() if filename != "NONE" and filename != "": obs = self._get_observations() # ... otherwise allocate a single observation else: # Read relevant user parameters caldb = self["caldb"].string() irf = self["irf"].string() deadc = self["deadc"].real() duration = self["duration"].real() rad = self["rad"].real() # Allocate observation container obs = gammalib.GObservations() # Set single pointing pntdir = gammalib.GSkyDir() pntdir.lb_deg(lpnt, bpnt) # Create CTA observation run = obsutils.set_obs(pntdir, caldb=caldb, irf=irf, duration=duration, deadc=deadc, emin=emin, emax=emax, rad=rad) # Append observation to container obs.append(run) # Set source position offset = self["offset"].real() pntdir.lb_deg(lpnt, bpnt + offset) self._ra = pntdir.ra_deg() self._dec = pntdir.dec_deg() # Return observation container return obs
def set_hgps(pointings, exposure=28.0*60.0, caldb='hess'): """ Setup H.E.S.S. Galactic plane survey Parameters ---------- pointings : list of dict HGPS pointings Returns ------- obsdef : list of dict List of pointing definitions """ # Initialise observation definition obsdef = [] # Initialise start time in seconds (1-1-2021) tmin = 7671.0 * 86400.0 # Set geographic latitude of H.E.S.S. array geolat = -23.27178 # Loop over all pointings for pointing in pointings: # Compute Right Ascension and Declination of pointing pnt = gammalib.GSkyDir() pnt.lb_deg(pointing['lon'], pointing['lat']) ra = pnt.ra_deg() dec = pnt.dec_deg() # Compute best possible zenith angle zenith = abs(dec - geolat) # Set IRF irf = 'dummy' # Set positions, start time and duration obs = {'lon': pointing['lon'], \ 'lat': pointing['lat'], \ 'tmin': tmin, \ 'duration': exposure, 'zenith': zenith, 'caldb': caldb, 'irf': irf} # Update start time for next pointing; add 2 min for slew tmin += exposure + 120.0 # Append observation obsdef.append(obs) # Return observation definition return obsdef
def get_pointings(filename): """ Extract pointings from CSV file Parameters ---------- filename : str File name of observation definition CSV file Returns ------- pnt : list of dict Pointings """ # Initialise pointings pnt = [] # Open CSV file csv = gammalib.GCsv(filename, ',') # Loop over rows for i in range(csv.nrows()): # Skip header if i == 0: continue # Extract information id = csv[i, 1] lon = float(csv[i, 2]) lat = float(csv[i, 3]) tstart = float(csv[i, 5]) duration = float(csv[i, 6]) irf = csv[i, 8] zenith = float(csv[i, 11]) # Convert direction dir = gammalib.GSkyDir() dir.lb_deg(lon, lat) # Derive attributes south = 'South' in irf # Create entry entry = {'id': id, 'l': lon, 'b': lat, 'ra': dir.ra_deg(), 'dec': dir.dec_deg(), 'time': tstart, 'duration': duration, \ 'zenith': zenith, 'south': south} # Append pointing pnt.append(entry) # Return pointings return pnt
def set_obs_patterns(pattern, ra=83.6331, dec=22.0145, offset=1.5): """ Sets a number of standard patterns Parameters ---------- pattern : str Observation pattern ("single", "four") ra : float, optional Right Ascension of pattern centre (deg) dec : float, optional Declination of pattern centre (deg) offset : float, optional Offset from pattern centre (deg) Returns ------- obsdeflist : list Observation definition list """ # Initialise observation definition list obsdeflist = [] # If the pattern is a single observation then append the Right Ascension # and Declination to the observation definition list if pattern == 'single': obsdef = {'ra': ra, 'dec': dec} obsdeflist.append(obsdef) # ... otherwise, if the pattern is four observations then append four # observations offset by a certain amount from the pattern centre to the # observation definition list elif pattern == 'four': # Set pattern centre centre = gammalib.GSkyDir() centre.radec_deg(ra, dec) # Append pointings for phi in [0.0, 90.0, 180.0, 270.0]: pntdir = centre.copy() pntdir.rotate_deg(phi, offset) obsdeflist.append({'ra': pntdir.ra_deg(), 'dec': pntdir.dec_deg()}) # ... otherwise raise an exception since we have an unknown pattern else: msg = 'Observation pattern "%s" not recognized.' % (pattern) raise RuntimeError(msg) # Return observation definition list return obsdeflist
def survey_gplane(lrange=10, lstep=2): """ Creates a single observation survey for test purposes. Keywords: lrange - Longitude range (integer deg) lstep - Longitude step size (integer deg) """ # Allocate observation container obs = gammalib.GObservations() # Loop over longitudes for l in range(-lrange,lrange+lstep,lstep): # Set pointing pntdir = gammalib.GSkyDir() pntdir.lb_deg(l, 0.0) run = obsutils.set_obs(pntdir) run.id(str(l)) obs.append(run) # Define single point source with Crab flux at galactic centre center = gammalib.GSkyDir() center.lb_deg(0.0, 0.0) point_spatial = gammalib.GModelSpatialPointSource(center) point_spectrum = crab_spec() point = gammalib.GModelSky(point_spatial, point_spectrum) point.name('GC source') # Create model container models = gammalib.GModels() models.append(point) obs.models(models) # Return observation container return obs
def write_obsdef(filename, obsdef, idstart, emin, emax): """ Write observation definition file Parameters ---------- filename : str Observation definition file name obsdef : list of dict List of pointing definitions idstart : int First identifier of observation definition file emin : float Minimum energy (TeV) emax : float Maximum energy (TeV) """ # Open file f = open(filename, 'w') # Write header f.write('name,id,lon,lat,rad,tmin,duration,caldb,irf,emin,emax,zenith\n') # Initialise identifier obsid = idstart # Loop over pointings for obs in obsdef: # We have lon,lat then convert into RA,Dec lon = obs['lon'] lat = obs['lat'] pnt = gammalib.GSkyDir() pnt.lb_deg(lon, lat) ra = pnt.ra_deg() dec = pnt.dec_deg() # Write information f.write('%s,%6.6d,%8.4f,%8.4f,%8.4f,%.4f,%.4f,%s,%s,%.3f,%.1f,%.2f\n' % (obs['name'], obsid, obs['lon'], obs['lat'], obs['rad'], obs['tmin'], obs['duration'], obs['caldb'], obs['irf'], emin, emax, obs['zenith'])) # Increment identifier obsid += 1 # Close file f.close()
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 create_models(): """ """ # Create model container models = gammalib.GModels() # Create a power law model for the Crab crabdir = gammalib.GSkyDir() crabdir.radec_deg(83.6331, 22.0145) spatial = gammalib.GModelSpatialPointSource(crabdir) energy = gammalib.GEnergy(100.0, "MeV") spectral = gammalib.GModelSpectralPlaw(5.7e-16, -2.48, energy) model = gammalib.GModelSky(spatial, spectral) models.append(model) # Return models return models
def open_observation(self, obsfilename): print('Open observation') obs = gammalib.GObservations() self.obsconf = ObservationConfiguration(obsfilename, self.runconf.timesys, self.runconf.timeunit, self.runconf.skyframeref, self.runconf.skyframeunitref) print(self.obsconf.caldb) pntdir = gammalib.GSkyDir() in_pnttype = self.obsconf.point_frame print(in_pnttype) if in_pnttype == 'fk5': pntdir.radec_deg(self.obsconf.point_ra, self.obsconf.point_dec) #if in_pnttype == 'equatorial' : #pntdir.radec_deg(self.obs_ra, self.obs_dec) #if in_pnttype == 'galactic' : # pntdir.radec_deg(self.in_l, self.in_b) #pntdir.radec_deg(self.obsconf.obs_point_ra, self.obsconf.obs_point_dec) tstart = self.obsconf.tstart - self.runconf.timeref print(tstart) if self.runconf.timeref_timesys == 'mjd': tstart = tstart * 86400. print("TSTART " + str(tstart)) obs1 = obsutils.set_obs(pntdir, tstart, self.obsconf.duration, 1.0, \ self.obsconf.emin, self.obsconf.emax, self.obsconf.roi_fov, \ self.obsconf.irf, self.obsconf.caldb, self.obsconf.id) print(obs1) obs.append(obs1) #print(obs1) return obs
def create_model(flux, index=-2.48, fitidx=False): """ Add standard CTA background model to observations container. We use a simple power law here, scaled to Konrad's E configuration performance table. Parameters: flux - Flux in Crab units """ # Define background model bgd_radial = gammalib.GCTAModelRadialGauss(3.0) bgd_spectrum = gammalib.GModelSpectralPlaw(61.8, -1.85) bgd_spectrum["Prefactor"].scale(1.0e-6) bgd_spectrum["PivotEnergy"].value(1.0) bgd_spectrum["PivotEnergy"].scale(1.0e6) if fitidx: bgd_spectrum["Index"].free() else: bgd_spectrum["Index"].fix() bgd_model = gammalib.GCTAModelRadialAcceptance(bgd_radial, bgd_spectrum) bgd_model.name("Background") bgd_model.instruments("CTA") # Define source spectrum location = gammalib.GSkyDir() location.radec_deg(83.6331, 22.0145) src_spatial = gammalib.GModelSpatialPtsrc(location) src_spectrum = gammalib.GModelSpectralPlaw(flux, index) src_spectrum["Prefactor"].scale(5.7e-16) src_spectrum["PivotEnergy"].value(0.3) src_spectrum["PivotEnergy"].scale(1.0e6) if fitidx: src_spectrum["Index"].free() else: src_spectrum["Index"].fix() src_model = gammalib.GModelPointSource(src_spatial, src_spectrum) src_model.name("Test") # Add models to container models = gammalib.GModels() models.append(bgd_model) models.append(src_model) # Return model container return models
def _setup_sim(self, two=False): """ Setup method for sim() function test """ # Set-up observation container pnt = gammalib.GSkyDir() pnt.radec_deg(83.6331, 22.0145) obs = gammalib.GObservations() run = obsutils.set_obs(pnt, duration=20.0, emin=1.0, emax=10.0) run.id('0') obs.append(run) if two: run.id('1') obs.append(run) # Append model obs.models(gammalib.GModels(self._model)) # Return return obs
def write_obsdef(filename, obsdef): """ Write observation definition file Parameters ---------- filename : str Observation definition file name obsdef : list of dict List of pointing definitions """ # Open file file = open(filename, 'w') # Write header file.write('ra,dec,duration,caldb,irf\n') # Loop over pointings for obs in obsdef: # If we have lon,lat then convert into RA,Dec if 'lon' in obs and 'lat' in obs: lon = obs['lon'] lat = obs['lat'] dir = gammalib.GSkyDir() dir.lb_deg(lon,lat) ra = dir.ra_deg() dec = dir.dec_deg() else: ra = obs['ra'] dec = obs['dec'] # Write information file.write('%8.4f,%8.4f,%.4f,%s,%s\n' % (ra, dec, obs['duration'], obs['caldb'], obs['irf'])) # Close file file.close() # Return return
def _select_circle(self, obs): """ Select observation in a pointing circle Parameters ---------- obs : `~gammalib.GCTAObservation` CTA observation Returns ------- select : bool Observation selection flag """ # Get coordinate system of selection circle coordsys = self['coordsys'].string() # Get pointing direction pnt = obs.pointing().dir() # Set selection circle centre centre = gammalib.GSkyDir() if coordsys == 'CEL': centre.radec_deg(self['ra'].real(), self['dec'].real()) else: centre.lb_deg(self['glon'].real(), self['glat'].real()) # Set selection flag according to distance if centre.dist_deg(pnt) <= self['rad'].real(): select = True msg = 'inside selection circle' else: select = False msg = 'outside selection circle' # Log observation selection self._log_selection(obs, msg) # Return selection flag return select
def _test_set_obs(self): """ Test set_obs() function """ # Setup pointing direction pnt = gammalib.GSkyDir() pnt.radec_deg(83.63, 22.51) # Setup one CTA observation res = obsutils.set_obs(pnt, emin=1.0, emax=10.0) # Check result self.test_value(res.eventtype(), 'EventList', 'Check event type') self.test_value(res.events().ebounds().emin().TeV(), 1.0, 'Check minimum energy') self.test_value(res.events().ebounds().emax().TeV(), 10.0, 'Check maximum energy') self.test_value(res.pointing().dir().ra_deg(), 83.63, 'Check pointing Right Ascension') self.test_value(res.pointing().dir().dec_deg(), 22.51, 'Check pointing declination') # Setup one CTA observation for local caldb directory res = obsutils.set_obs(pnt, caldb=self._datadir, irf='irf_file.fits', emin=1.0, emax=10.0) # Check result self.test_value(res.eventtype(), 'EventList', 'Check event type') self.test_value(res.events().ebounds().emin().TeV(), 1.0, 'Check minimum energy') self.test_value(res.events().ebounds().emax().TeV(), 10.0, 'Check maximum energy') self.test_value(res.pointing().dir().ra_deg(), 83.63, 'Check pointing Right Ascension') self.test_value(res.pointing().dir().dec_deg(), 22.51, 'Check pointing declination') # Return return
def set_obs_patterns(pattern, ra=83.6331, dec=22.0145, offset=1.5): """ Sets a number of standard patterns. Parameters: pattern - Observation pattern. Possible options are: - "single": single pointing - "four": four pointings 'offset' around pattern centre Keywords: ra - Right Ascension of pattern centre [deg] (default: 83.6331) dec - Declination of pattern centre [deg] (default: 22.0145) offset - Offset from pattern centre [deg] (default: 1.5) """ # Initialise observation definition list obsdeflist = [] # Add patterns if pattern == "single": obsdef = {'ra': ra, 'dec': dec} obsdeflist.append(obsdef) elif pattern == "four": # Set pattern centre centre = gammalib.GSkyDir() centre.radec_deg(ra, dec) # Append pointings for phi in [0.0, 90.0, 180.0, 270.0]: pntdir = centre.copy() pntdir.rotate_deg(phi, offset) obsdeflist.append({'ra': pntdir.ra_deg(), 'dec': pntdir.dec_deg()}) else: print("Warning: Observation pattern '" + str(pattern) + "' not recognized.") # Return observation definition list return obsdeflist
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 residual_radial(cntcube, modcube, ebins=4, rad=2.0, dr=0.1): """ Determine radial residuals Parameters ---------- cntcube : `~gammalib.GCTAEventCube` Counts cube modcube : `~gammalib.GCTAEventCube` Model cube ebins : int, optional Number of energy bins rad : float, optional Maximum radius dr : float, optional Radius binsize Returns ------- residual : dict Residual dictionary """ # Extract energy boundaries ebounds = cntcube.ebounds().copy() # Extract counts and model cubes sky maps cnt = cntcube.counts() mod = modcube.counts() # Define radius axis nr = int(rad / dr + 0.5) radius = [(r + 0.5) * dr for r in range(nr)] # Define energy binning nebins = ebounds.size() debins = float(ebins) / float(nebins) # Initialise result arrays counts = [[0.0 for r in range(nr)] for e in range(ebins)] model = [[0.0 for r in range(nr)] for e in range(ebins)] pixels = [[0.0 for r in range(nr)] for e in range(ebins)] # Initialise centre direction centre = gammalib.GSkyDir() centre.radec_deg(0.0, 0.0) # Loop over cube pixels for k in range(cnt.npix()): # Compute theta angle (deg) theta = centre.dist_deg(cnt.inx2dir(k)) # Get radius index ir = int(theta / dr) # Skip pixel if it is not inside radius axis if ir < 0 or ir >= nr: continue # Loop over energies for i in range(nebins): # Get energy index ie = int(float(i) * debins) # Skip layer if it is not inside energy bins if ie < 0 or ie >= ebins: continue # Add cube content to array counts[ie][ir] += cnt[k, i] model[ie][ir] += mod[k, i] pixels[ie][ir] += 1.0 # Build result dictionary residual = [] for ie in range(ebins): # Compute normalised arrays rad_array = [] counts_array = [] error_array = [] model_array = [] residual_array = [] for ir in range(nr): if pixels[ie][ir] > 0.0: if model[ie][ir] > 0.0: if counts[ie][ir] > 0.0: res = math.sqrt( 2.0 * (counts[ie][ir] * math.log(counts[ie][ir] / model[ie][ir]) + model[ie][ir] - counts[ie][ir])) else: res = model[ie][ir] if counts[ie][ir] < model[ie][ir]: res *= -1.0 else: res = 0.0 rad_array.append(radius[ir]) counts_array.append(counts[ie][ir] / pixels[ie][ir]) error_array.append(math.sqrt(counts[ie][ir]) / pixels[ie][ir]) model_array.append(model[ie][ir] / pixels[ie][ir]) residual_array.append(res) # Build result dictionary iemin = int(ie / debins + 0.5) iemax = int((ie + 1) / debins - 0.5) result = { 'emin': ebounds.emin(iemin).TeV(), 'emax': ebounds.emax(iemax).TeV(), 'radius': rad_array, 'counts': counts_array, 'error': error_array, 'model': model_array, 'residual': residual_array } # Append dictionary residual.append(result) # Return residual return residual
def append_fhl(models, bmax, bin_models, bin_dict, bin_distx, bin_disty, bin_radr, bin_frlog, snr_models, snr_dict, snr_distx, snr_disty, snr_radr, snr_frlog, isnr_models, isnr_dict, isnr_distx, isnr_disty, isnr_radr, isnr_frlog, dist_sigma=3., sig50_thresh=3., eph_thresh=100.): """ Append missing models from Fermi high-energy catalog to gammalib model container :param models: ~gammalib.GModels, gammalib model container :param bmax: float, maximum latitude of models to include :param dist_sigma: float, minimum distance in sigma's from pre-existing source to add as new :param sig50_thresh: float, threshold sigma on significance above 50 GeV to apply :param eph_thresh: float, minimum energy of detected photons required :return: result: dictionary """ # filter FHL table based on latitude and hardness # hard sources are seleted based on significance above 50 GeV and highest photon energy # calculate significance above 50 GeV sig50 = np.sqrt(np.sum(np.power(fhl['Sqrt_TS_Band'][:,2:], 2),axis=1)) # filter fsources = fhl[(np.abs(fhl['GLAT']) <= bmax) & (sig50 >= sig50_thresh) & ( fhl['HEP_Energy'] >= eph_thresh)] # prepare new gammalib model container newpt = 0 newext = 0 n_bin_del = 0 n_snr_del = 0 n_isnr_del = 0 newmodels = gammalib.GModels() # keep track also of artificial cutoffs ecut_pwn = [] ecut_snr = [] ecut_unid = [] ecut_agn = [] n_ecut_pwn = 0 n_ecut_snr = 0 n_ecut_agn = 0 n_ecut_unid = 0 msg = '' # loop over fermi sources for fsource in fsources: # assume source is new new = 1 # fermi source position as gammalib.GSkyDir fdir = gammalib.GSkyDir() ra = np.double(fsource['RAJ2000']) dec = np.double(fsource['DEJ2000']) fdir.radec_deg(ra, dec) ######################################### treat pointlike sources for Fermi ########### if fsource['Extended_Source_Name'] == '': # case of sources pointlike for Fermi # loop over gammalib container and determine closest neighbor # initialize at 1000 dist_min = 1000. for source in models: dir = get_model_dir(source) dist = fdir.dist_deg(dir) dist_min = np.minimum(dist, dist_min) if dist_min < dist_sigma * fsource['Conf_95_SemiMajor'] / 2: # closeby source foud in container, source will not be added new = 0 else: # source will be added to container, set spatial model spatial = gammalib.GModelSpatialPointSource(fdir) newpt += 1 ######################################### treat extended sources for Fermi ############ else: # retrieve Fermi extended source radius ext_fsource = ext_fhl[ext_fhl['Source_Name'] == fsource['Extended_Source_Name']][0] fradius = np.double(ext_fsource['Model_SemiMajor']) # "corrected" distance, i.e, centre distance - radius of source # initialize at 1000 dist_corr = 1000. for source in models: dir = get_model_dir(source) dist = fdir.dist_deg(dir) # get source radius according to model used radius = get_model_radius(source) # use as radius the max between Fermi and model radius = np.maximum(fradius,radius) # subtract from distance the max radius dist -= radius dist_corr = np.minimum(dist,dist_corr) if dist_corr < 0.: # overlapping source foud in container, source will not be added new = 0 else: # source will be added to container, set spatial model fradius2 = np.double(ext_fsource['Model_SemiMinor']) fpangle = np.double(ext_fsource['Model_PosAng']) # retrieve Fermi spatial model to set it in container if ext_fsource['Model_Form'] == 'Disk': if fradius2 == fradius: spatial = gammalib.GModelSpatialRadialDisk(fdir,fradius) else: spatial = gammalib.GModelSpatialEllipticalDisk(fdir, fradius, fradius2, fpangle) elif ext_fsource['Model_Form'] == '2D Gaussian': if fradius2 == fradius: spatial = gammalib.GModelSpatialRadialGauss(fdir,fradius) else: spatial = gammalib.GModelSpatialEllipticalGauss(fdir, fradius, fradius2, fpangle) elif ext_fsource['Model_Form'] == 'Ring': spatial = gammalib.GModelSpatialRadialShell(fdir,fradius, fradius2) elif ext_fsource['Model_Form'] == 'Map': print('{} modeled by spatial template, which is not implemented, skip'.format(fsource['Source_Name'])) new = 0 else: print('{} modeled by model type {}, which is not implemented, skip'.format(fsource['Source_Name'],ext_fsource['Model_Form'])) new = 0 if new == 1: newext +=1 ######################################### spectra ##################################### if new == 1: # spectral model eref = gammalib.GEnergy(np.double(fsource['Pivot_Energy']), 'GeV') norm = np.double(fsource['Flux_Density']) norm *= 1.e-3 # ph GeV-1 -> ph MeV-1 # use power law model only if signifcance of curvature < 1 # this avoids extrapolating hard power laws not justified by the data if fsource['Signif_Curve'] < 1: index = np.double(fsource['PowerLaw_Index']) if index < 2.4: # correction for fake pevatrons if fsource['CLASS'] == 'PWN' or fsource['CLASS'] == 'pwn': # dummy model to obtain search radius mod = gammalib.GModelSky(spatial, gammalib.GModelSpectralPlaw()) # search radius rad = get_model_radius(mod) + 0.2 # set cutoff ecut = get_cutoff(ra, dec, 'PSR', rad_search=rad) ecut_pwn.append(ecut) n_ecut_pwn += 1 elif fsource['CLASS'] == 'SNR' or fsource['CLASS'] == 'snr': gname = fsource['ASSOC1'] if 'SNR' in gname: pass else: gname = None # compute cutoff # we use default value for particle spectral index because measurements are highly uncertain ecut = get_cutoff(ra, dec, 'SNR', name=gname) ecut_snr.append(ecut) n_ecut_snr += 1 elif fsource['CLASS'] == 'bll' or fsource['CLASS'] == 'bcu' or fsource['CLASS'] == 'fsrq': ecut = get_cutoff(ra, dec, 'AGN', z = fsource['Redshift']) ecut_agn.append(ecut) n_ecut_agn += 1 else: if fsource['CLASS'] == '' or fsource['CLASS'] == 'unknown': pass else: # set warning if we have hard source of unexpected type msg += 'FHL source {} of type {} has an unxepctedly hard spectrum ' \ 'with index {}. We are setting a random artificial cutoff\n'.format( fsource['Source_Name'], fsource['CLASS'], index) print(msg) ecut = get_cutoff(ra, dec, 'UNID') ecut_unid.append(ecut) n_ecut_unid += 1 ecut = gammalib.GEnergy(np.double(ecut), 'TeV') spectral = gammalib.GModelSpectralExpPlaw(norm, -index, eref, ecut) else: spectral = gammalib.GModelSpectralPlaw(norm, -index, eref) else: index = np.double(fsource['Spectral_Index']) curvature = np.double(fsource['beta']) spectral = gammalib.GModelSpectralLogParabola(norm, -index, eref, curvature) # assemble model and append to container model = gammalib.GModelSky(spatial, spectral) model.name(fsource['Source_Name']) newmodels.append(model) # delete synthetic sources as needed if fsource['CLASS'] == 'HMB' or fsource['CLASS'] == 'hmb' or fsource['CLASS'] == 'BIN' or fsource['CLASS'] == 'bin': rname, bin_dict, distx, disty, radr, frlog = find_source_to_delete(bin_dict, fdir.l_deg(), fdir.b_deg(), get_model_radius(model), flux_Crab(model,1.,1000.)) bin_models.remove(rname) n_bin_del += 1 bin_distx.append(distx) bin_disty.append(disty) bin_radr.append(radr) bin_frlog.append(frlog) elif fsource['CLASS'] == 'PWN' or fsource['CLASS'] == 'pwn' or fsource['CLASS'] == 'spp': # implement synthetic PWNe here pass elif fsource['CLASS'] == 'SNR' or fsource['CLASS'] == 'snr': # determine if snr is interacting assoc = snr_class[snr_class['ASSOC1'] == fsource['ASSOC1']] if assoc[0]['is int'] == 'yes': # interacting rname, isnr_dict, distx, disty, radr, frlog = find_source_to_delete(isnr_dict, fdir.l_deg(), fdir.b_deg(), get_model_radius(model), flux_Crab(model, 1.,1000.)) isnr_models.remove(rname) n_isnr_del += 1 isnr_distx.append(distx) isnr_disty.append(disty) isnr_radr.append(radr) isnr_frlog.append(frlog) else: # young rname, snr_dict, distx, disty, radr, frlog = find_source_to_delete(snr_dict, fdir.l_deg(), fdir.b_deg(), get_model_radius(model), flux_Crab(model,1.,1000.)) snr_models.remove(rname) n_snr_del += 1 snr_distx.append(distx) snr_disty.append(disty) snr_radr.append(radr) snr_frlog.append(frlog) else: pass else: # source already present, skip pass # add new models to original container for model in newmodels: models.append(model) # assemble output in dictionary result = { 'models' : models, 'newpt' : newpt, 'newext' : newext, 'ecut_pwn' : ecut_pwn, 'ecut_snr' : ecut_snr, 'ecut_agn' : ecut_agn, 'ecut_unid' : ecut_unid, 'n_ecut_pwn' : n_ecut_pwn, 'n_ecut_snr' : n_ecut_snr, 'n_ecut_agn' : n_ecut_agn, 'n_ecut_unid' : n_ecut_unid, 'msg' : msg, 'bin_models' : bin_models, 'bin_dict' : bin_dict, 'n_bin_del' : n_bin_del, 'bin_distx' : bin_distx, 'bin_disty' : bin_disty, 'bin_radr' : bin_radr, 'bin_frlog' : bin_frlog, 'snr_models': snr_models, 'snr_dict': snr_dict, 'n_snr_del': n_snr_del, 'snr_distx': snr_distx, 'snr_disty': snr_disty, 'snr_radr': snr_radr, 'snr_frlog': snr_frlog, 'isnr_models': isnr_models, 'isnr_dict': isnr_dict, 'n_isnr_del': n_isnr_del, 'isnr_distx': isnr_distx, 'isnr_disty': isnr_disty, 'isnr_radr': isnr_radr, 'isnr_frlog': isnr_frlog } return result