def angdist(ra, dec, ps, ds=None): """ Calculate angular distance of point sources to point in the sky Parameters ---------- ra: float, R.A. of ROI (in degree) dec: float, DEC. of ROI (in degree) ps: list, list of point sources as generated with pointlike kwargs ------ ds: list, list of point sources as generated with pointlike, if None, don't use it and don't return it Returns ------- list that contains the angular distance in degrees to point sources """ skydir = SkyDir(ra, dec, SkyDir.EQUATORIAL) diffPs = empty(len(ps)) for i, p in enumerate(ps): diffPs[i] = skydir.difference( p.skydir) * 180. / pi # angular separation in degree if not ds == None: diffDs = empty(len(ds)) for i, d in enumerate(ds): diffDs[i] = skydir.difference( d.skydir) * 180. / pi # angular separation in degree return diffPs, diffDs else: return diffPs
def update_positions(self, tsmin=10, qualmax=8): """ use the localization information associated with each source to update position require ts>tsmin, qual<qualmax """ print '---Updating positions---' sources = [ s for s in self.sources if s.skydir is not None and np.any(s.spectral_model.free) ] #print 'sources:', [s.name for s in sources] print '%-15s%6s%8s %8s' % ('name', 'TS', 'qual', 'delta_ts') for source in sources: has_ts = hasattr(source, 'ts') print '%-15s %6.0f' % (source.name, source.ts if has_ts else -1.0), if not hasattr(source, 'ellipse') or source.ellipse is None: print ' no localization info' continue if not has_ts: print ' no TS' continue if source.ts < tsmin: print ' TS<%.0f' % (tsmin) continue newdir = SkyDir(*source.ellipse[:2]) qual, delta_ts = source.ellipse[-2:] print '%6.1f%6.1f' % (qual, delta_ts), if qual > qualmax: print ' qual>%.1f' % qualmax continue print ' %s -> %s, moved %.2f' % ( source.skydir, newdir, np.degrees(newdir.difference(source.skydir))) source.skydir = newdir
def moment_analysis(tsmap, wcs, fudge=1.44): """ perform localization by a moment analysis of a TS map tsmap : array of float: TS values on a grid, must be square wcs : Projector object implements pix2sph function of two ints to return ra,dec fudge : float Additional factor to multiply the ellipse radii (Determined empirically) returns: ra, dec, ax, bx, ang """ vals = np.exp(-0.5* tsmap**2).flatten(); peak_fraction = vals.max()/sum(vals) n = len(vals) nx = ny =int(np.sqrt(n)) #centers of pixels have index +0.5 ix = np.array([ i % nx for i in range(n)]) +0.5 iy = np.array([ i //nx for i in range(n)]) +0.5 norm = 1./sum(vals) t = [sum(u*vals)*norm for u in ix,iy, ix**2, ix*iy, iy**2] center = (t[0],t[1]) C = np.matrix(center) variance = (np.matrix(((t[2], t[3]),(t[3], t[4]))) - C.T * C) ra,dec = wcs.pix2sph(center[0]+0.5,center[1]+0.5) peak = SkyDir(ra,dec) # get coords of center, measure degrees/pixel nc = (nx+1)/2 rac, decc = wcs.pix2sph(nc, nc) scale = wcs.pix2sph(nc, nc+1)[1] - decc size = nx*scale # adjust variance variance = scale**2 * variance offset = np.degrees(peak.difference(SkyDir(rac,decc))) # add effects of binsize var = variance #NO+ np.matrix(np.diag([1,1]))*(scale/3)**2 #Eigenvalue analysis to get ellipse coords u,v =np.linalg.eigh(var) ang =np.degrees(np.arctan2(v[1,1], -v[1,0])) if min(u)< 0.5* max(u): print 'Too elliptical : %s, setting circular' % u u[0]=u[1] = max(u) tt = np.sqrt(u) * fudge if u[1]>u[0]: ax,bx = tt[1], tt[0] ang = 90-ang else: ax,bx = tt return ra, dec, ax,bx, ang
def rotate_equator(skydir,target,anti=False): """ Rotate skydir such that target would be rotated to the celestial equator. A few simple tests: >>> a = SkyDir(0,0) >>> b = SkyDir(30,30) >>> rotate_equator(a, b) SkyDir(330.000,-30.000) >>> anti_rotate_equator(a, b) SkyDir(30.000,30.000) There was previously a bug when the 'target' was the equator. I think it is fixed now: >>> rotate_equator(b, a) SkyDir(30.000,30.000) >>> anti_rotate_equator(b, a) SkyDir(30.000,30.000) Another test: >>> sd = SkyDir(-.2,-.2) >>> target = SkyDir(5,5) >>> l=rotate_equator(sd, target) >>> print '%.2f, %.2f' % (l.ra(), l.dec()) 354.80, -5.20 >>> l=anti_rotate_equator(sd, target) >>> print '%.2f, %.2f' % (l.ra(), l.dec()) 4.80, 4.80 """ if np.allclose([target.ra(), target.dec()], [0,0]): return skydir equator=SkyDir(0,0) axis=target.cross(equator) theta=equator.difference(target) if anti: theta*=-1 newdir=SkyDir(skydir.ra(),skydir.dec()) newdir().rotate(axis(),theta) return newdir
class PeakFinder(object): """Log of analysis stream <pre>%(logstream)s</pre> """ def __init__(self, filename): t = os.path.split(os.path.splitext(filename)[0])[-1].split('_') self.sourcename = ' '.join(t[:-1]).replace('p', '+') self.df = df = SkyImage(filename) wcs = df.projector() self.tsmap = np.array(df.image()) nx, ny = df.naxis1(), df.naxis2() assert nx == ny, 'Array not square?' vals = np.exp(-0.5 * self.tsmap**2) # convert to likelihood from TS norm = 1. / sum(vals) self.peak_fract = norm * vals.max() center, variance = self.moments_analysis(vals) ra, dec = wcs.pix2sph(center[1], center[0]) self.peak = SkyDir(ra, dec) self.scale = wcs.pix2sph(center[0], center[1] + 1)[1] - dec self.size = nx * self.scale self.variance = self.scale**2 * variance rac, decc = wcs.pix2sph(nx / 2, ny / 2) self.offset = np.degrees(self.peak.difference(SkyDir(rac, decc))) def moments_analysis(self, vals): n = len(vals) nx = int(np.sqrt(n)) ix = np.array([i % nx for i in range(n)]) iy = np.array([i // nx for i in range(n)]) norm = 1. / sum(vals) t = [sum(u * vals) * norm for u in ix, iy, ix**2, ix * iy, iy**2] center = (t[0], t[1]) C = np.matrix(center) variance = (np.matrix(((t[2], t[3]), (t[3], t[4]))) - C.T * C) return center, variance def ellipse(self): # add effects of binsize var = self.variance + np.matrix(np.diag([1, 1])) * (self.scale / 3)**2 t, v = np.linalg.eigh(var) ang = np.degrees(np.arcsin(np.array( v)[0][0])) #guess. Needs adjustment depending on which is largest return t[0], t[1], ang
def moment_analysis(tsmap, wcs): """ perform localization by a moment analysis of a TS map tsmap : array of float should be square wcs : Projector object implements pix2sph function of two ints to return ra,dec returns: ra, dec, ax, bx, phi """ vals = np.exp(-0.5 * tsmap**2).flatten() n = len(vals) nx = ny = int(np.sqrt(n)) ix = np.array([i % nx for i in range(n)]) iy = np.array([i // nx for i in range(n)]) norm = 1. / sum(vals) t = [sum(u * vals) * norm for u in ix, iy, ix**2, ix * iy, iy**2] center = (t[0], t[1]) C = np.matrix(center) variance = (np.matrix(((t[2], t[3]), (t[3], t[4]))) - C.T * C) ra, dec = wcs.pix2sph(center[1], center[0]) peak = SkyDir(ra, dec) rac, decc = wcs.pix2sph(nx / 2, ny / 2) scale = wcs.pix2sph(nx / 2, ny / 2 + 1)[1] - decc size = nx * scale variance = scale**2 * variance offset = np.degrees(peak.difference(SkyDir(rac, decc))) # add effects of binsize var = variance + np.matrix(np.diag([1, 1])) * (scale / 3)**2 t, v = np.linalg.eigh(var) ang = np.degrees(np.arctan2(v[1, 1], -v[1, 0])) tt = np.sqrt(t) if t[1] > t[0]: ax, bx = tt[1], tt[0] ang = 90 - ang else: ax, bx = tt return ra, dec, ax, bx, ang
def __call__(self, skydir): """ This funciton is analogous to the BandCALDBPsf.__call__ function except that it always returns the density (probability per unit area). Also, it is different in that it takes in a skydir or WSDL instead of a radial distance. """ if isinstance(skydir, BaseWeightedSkyDirList): difference = np.empty(len(skydir), dtype=float) PythonUtilities.arclength( difference, skydir, self.extended_source.spatial_model.center) return self.val(difference) elif type(skydir) == np.ndarray: return self.val(skydir) elif type(skydir) == list and len(skydir) == 3: skydir = SkyDir(Hep3Vector(skydir[0], skydir[1], skydir[2])) elif type(skydir) == SkyDir: return float( self.val( skydir.difference( self.extended_source.spatial_model.center))) else: raise Exception("Unknown input to AnalyticConvolution.__call__()")