def main(args): with fitsio.FITS(args.catalogue) as infile: hdu = infile[1] ra1 = hdu['RA_1'][:] dec1 = hdu['DEC_1'][:] ra2 = hdu['ra_2'][:] dec2 = hdu['dec_2'][:] coords1 = ICRS(ra=ra1, dec=dec1, unit=(u.radian, u.radian)) coords2 = ICRS(ra=ra2, dec=dec2, unit=(u.degree, u.degree)) separations = coords1.separation(coords2).degree * 3600. fig, axes = plt.subplots(figsize=(11, 8)) axes.hist(separations, 30, histtype='step') axes.set_xlabel(r'Separation / arcseconds') axes.grid(True) fig.tight_layout() if args.output is not None: fig.savefig(args.output, bbox_inches='tight') else: plt.show()
def test_coord_get(): # Test default (instance=None) obs = Helioprojective.observer assert obs is "earth" # Test get obstime = "2013-04-01" obs = Helioprojective(observer="earth", obstime=obstime).observer earth = get_earth(obstime) assert isinstance(obs, HeliographicStonyhurst) assert_quantity_allclose(obs.lon, earth.lon) assert_quantity_allclose(obs.lat, earth.lat) assert_quantity_allclose(obs.radius, earth.radius) # Test get obstime = "2013-04-01" obs = Helioprojective(obstime=obstime).observer earth = get_earth(obstime) assert isinstance(obs, HeliographicStonyhurst) assert_quantity_allclose(obs.lon, earth.lon) assert_quantity_allclose(obs.lat, earth.lat) assert_quantity_allclose(obs.radius, earth.radius) # Test get mars obstime = Time(parse_time("2013-04-01")) obs = Helioprojective(observer="mars", obstime=obstime).observer out_icrs = ICRS(get_body_barycentric("mars", obstime)) mars = out_icrs.transform_to(HeliographicStonyhurst(obstime=obstime)) assert isinstance(obs, HeliographicStonyhurst) assert_quantity_allclose(obs.lon, mars.lon) assert_quantity_allclose(obs.lat, mars.lat) assert_quantity_allclose(obs.radius, mars.radius)
def main(args): with fitsio.FITS(args.catalogue) as infile: hdu = infile[1] ra1 = hdu['RA_1'][:] dec1 = hdu['DEC_1'][:] ra2 = hdu['ra_2'][:] dec2 = hdu['dec_2'][:] x = hdu['X_coordinate'][:] y = hdu['Y_coordinate'][:] coords1 = ICRS(ra=ra1, dec=dec1, unit=(u.radian, u.radian)) coords2 = ICRS(ra=ra2, dec=dec2, unit=(u.degree, u.degree)) separations = coords1.separation(coords2).degree * 3600. fig, axes = plt.subplots(2, 2, sharex=True, figsize=(11, 8)) [(x_axis, y_axis), (x_zoomed, y_zoomed)] = axes nsigma = 5 nbins = 2048 / 128 print('Using {} bins'.format(nbins)) x_axis.plot(x, separations, 'k.', color='0.4') x_axis.set_ylabel(r'X') ledges, x_binned = compute_binned(x, separations, nbins) _, x_binned_error = compute_binned_errors(x, separations, ledges) bin_centres = compute_bin_centres(ledges) for ax in [x_axis, x_zoomed]: ax.errorbar(bin_centres[:-1], x_binned[:-1], x_binned_error[:-1], color='r', ls='None') ax.plot(ledges, x_binned, color='r', drawstyle='steps-post') y_axis.plot(y, separations, 'k.', color='0.4') y_axis.set_ylabel(r'y') ledges, y_binned = compute_binned(y, separations, nbins) _, y_binned_error = compute_binned_errors(y, separations, ledges) for ax in [y_axis, y_zoomed]: ax.errorbar(bin_centres[:-1], y_binned[:-1], x_binned_error[:-1], color='r', ls='None') ax.plot(ledges, y_binned, color='r', drawstyle='steps-post') link_y_limits(x_zoomed, y_zoomed) for ax in axes.flatten(): ax.grid(True) fig.tight_layout() if args.output is not None: fig.savefig(args.output, bbox_inches='tight') else: plt.show()
def test_radec_to_munu(): from astropy import units as u from astropy.coordinates import ICRS from .. import SDSSMuNu radec = ICRS(ra=0.0*u.deg,dec=0.0*u.deg) munu = radec.transform_to(SDSSMuNu(stripe=10)) assert munu.mu.value == 0.0 assert munu.nu.value == 0.0 assert munu.incl.value == 0.0
def eq2gal(self,ra,dec): try: ra = Angle(ra) dec = Angle(dec) c = ICRS(ra=ra, dec=dec) return c.transform_to(Galactic) except Exception as e: print(e) return 0
def v_hist(): """""" t = Table.read("../data/deimos.fits") print(t.keys()) N = len(t) ra = np.zeros(N)*u.deg dec = np.zeros(N)*u.deg for j in range(N): ra[j] = Angle(t['RA'][j] + ' hours') dec[j] = Angle(t['DEC'][j] + 'degrees') # fname = '../data/TriS-1.out' ra_s, dec_s, i, priority, inmask = np.loadtxt(fname, usecols=(1,2,4,6,8), unpack=True, dtype='|S11, |S11, <f4, <f4, <i4', skiprows=4) Nm = np.size(ra_s) ra_m = np.zeros(Nm)*u.deg dec_m = np.zeros(Nm)*u.deg for j in range(Nm): ra_m[j] = Angle(ra_s[j] + ' hours') dec_m[j] = Angle(dec_s[j] + 'degrees') # match catalogs ref = ICRS(ra_m, dec_m, unit=(u.degree, u.degree)) cat = ICRS(ra, dec, unit=(u.degree, u.degree)) id1, d21, d31 = cat.match_to_catalog_sky(ref) matches = d21<0.5*u.arcsec t_priority = priority[id1] i_m = i[id1] indices = (t['ZQUALITY']>-1) t['Z'] *= 300000 add_npcolumn(t, name="priority", vec=t_priority) #print(t_priority, np.size(t_priority)) plt.close() plt.figure() plt.subplot(221) plt.hist(t['Z'], bins=np.arange(-400,200,10), histtype='step', color='k') plt.hist(t['Z'][indices], bins=np.arange(-400,200,10), histtype='step', color='b') plt.hist(t['Z'][t_priority>=500], bins=np.arange(-400,200,10), histtype='step', color='r') plt.minorticks_on() plt.subplot(222) plt.plot(i_m[indices], t['Z'][indices], 'ko') print(t['Z'][t_priority>=500], i_m[t_priority>=500]) print(np.max(i_m[indices]))
def test_icrs_altaz_moonish(testframe): """ Check that something expressed in *ICRS* as being moon-like goes to the right AltAz distance """ # we use epv00 instead of get_sun because get_sun includes aberration earth_pv_helio, earth_pv_bary = epv00(*get_jd12(testframe.obstime, 'tdb')) earth_icrs_xyz = earth_pv_bary[0]*u.au moonoffset = [0, 0, MOONDIST.value]*MOONDIST.unit moonish_icrs = ICRS(CartesianRepresentation(earth_icrs_xyz + moonoffset)) moonaa = moonish_icrs.transform_to(testframe) # now check that the distance change is similar to earth radius assert 1000*u.km < np.abs(moonaa.distance - MOONDIST).to(u.au) < 7000*u.km
def test_array_separation(): c1 = ICRS([0, 0]*u.deg, [0, 0]*u.deg) c2 = ICRS([1, 2]*u.deg, [0, 0]*u.deg) npt.assert_array_almost_equal(c1.separation(c2).degree, [1, 2]) c3 = ICRS([0, 3.]*u.deg, [0., 0]*u.deg, distance=[1, 1.] * u.kpc) c4 = ICRS([1, 1.]*u.deg, [0., 0]*u.deg, distance=[1, 1.] * u.kpc) # the 3-1 separation should be twice the 0-1 separation, but not *exactly* the same sep = c3.separation_3d(c4) sepdiff = sep[1] - (2 * sep[0]) assert abs(sepdiff.value) < 1e-5 assert sepdiff != 0
def test_icrs_gcrscirs_sunish(testframe): """ check that the ICRS barycenter goes to about the right distance from various ~geocentric frames (other than testframe) """ # slight offset to avoid divide-by-zero errors icrs = ICRS(0*u.deg, 0*u.deg, distance=10*u.km) gcrs = icrs.transform_to(GCRS(obstime=testframe.obstime)) assert (EARTHECC - 1)*u.au < gcrs.distance.to(u.au) < (EARTHECC + 1)*u.au cirs = icrs.transform_to(CIRS(obstime=testframe.obstime)) assert (EARTHECC - 1)*u.au < cirs.distance.to(u.au) < (EARTHECC + 1)*u.au itrs = icrs.transform_to(ITRS(obstime=testframe.obstime)) assert (EARTHECC - 1)*u.au < itrs.spherical.distance.to(u.au) < (EARTHECC + 1)*u.au
def test_array_coordinates_transformations(arrshape, distance): """ Test transformation on coordinates with array content (first length-2 1D, then a 3D array) """ # M31 coordinates from test_transformations raarr = np.ones(arrshape) * 10.6847929 decarr = np.ones(arrshape) * 41.2690650 if distance is not None: distance = np.ones(arrshape) * distance print(raarr, decarr, distance) c = ICRS(ra=raarr*u.deg, dec=decarr*u.deg, distance=distance) g = c.transform_to(Galactic) assert g.l.shape == arrshape npt.assert_array_almost_equal(g.l.degree, 121.17440967) npt.assert_array_almost_equal(g.b.degree, -21.57299631) if distance is not None: assert g.distance.unit == c.distance.unit # now make sure round-tripping works through FK5 c2 = c.transform_to(FK5).transform_to(ICRS) npt.assert_array_almost_equal(c.ra.radian, c2.ra.radian) npt.assert_array_almost_equal(c.dec.radian, c2.dec.radian) assert c2.ra.shape == arrshape if distance is not None: assert c2.distance.unit == c.distance.unit # also make sure it's possible to get to FK4, which uses a direct transform function. fk4 = c.transform_to(FK4) npt.assert_array_almost_equal(fk4.ra.degree, 10.0004, decimal=4) npt.assert_array_almost_equal(fk4.dec.degree, 40.9953, decimal=4) assert fk4.ra.shape == arrshape if distance is not None: assert fk4.distance.unit == c.distance.unit # now check the reverse transforms run cfk4 = fk4.transform_to(ICRS) assert cfk4.ra.shape == arrshape
def ra_dec_distance(ra1, dec1, ra2, dec2, use_icrs=False, arcsec=False): # conversion between degree and radians pi = 3.1415926536 d2r = pi/180.00 if use_icrs: coord1 = ICRS(ra=ra1, dec=dec1, unit=(u.degree,u.degree)) coord2 = ICRS(ra=ra2, dec=dec2, unit=(u.degree,u.degree)) else: coord1 = FK5(ra=ra1, dec=dec1, unit=(u.degree,u.degree)) coord2 = FK5(ra=ra2, dec=dec2, unit=(u.degree,u.degree)) # The separation is in unit of arcsecond or degree if arcsec: sep = coord1.separation(coord2).arcsecond else: sep = (coord1.separation(coord2).radian / d2r ) return sep
def test_icrs_cirs(): """ Check a few cases of ICRS<->CIRS for consistency. Also includes the CIRS<->CIRS transforms at different times, as those go through ICRS """ ra, dec, dist = randomly_sample_sphere(200) inod = ICRS(ra=ra, dec=dec) iwd = ICRS(ra=ra, dec=dec, distance=dist*u.pc) cframe1 = CIRS() cirsnod = inod.transform_to(cframe1) # uses the default time # first do a round-tripping test inod2 = cirsnod.transform_to(ICRS) assert_allclose(inod.ra, inod2.ra) assert_allclose(inod.dec, inod2.dec) # now check that a different time yields different answers cframe2 = CIRS(obstime=Time('J2005', scale='utc')) cirsnod2 = inod.transform_to(cframe2) assert not allclose(cirsnod.ra, cirsnod2.ra, rtol=1e-8) assert not allclose(cirsnod.dec, cirsnod2.dec, rtol=1e-8) # parallax effects should be included, so with and w/o distance should be different cirswd = iwd.transform_to(cframe1) assert not allclose(cirswd.ra, cirsnod.ra, rtol=1e-8) assert not allclose(cirswd.dec, cirsnod.dec, rtol=1e-8) # and the distance should transform at least somehow assert not allclose(cirswd.distance, iwd.distance, rtol=1e-8) # now check that the cirs self-transform works as expected cirsnod3 = cirsnod.transform_to(cframe1) # should be a no-op assert_allclose(cirsnod.ra, cirsnod3.ra) assert_allclose(cirsnod.dec, cirsnod3.dec) cirsnod4 = cirsnod.transform_to(cframe2) # should be different assert not allclose(cirsnod4.ra, cirsnod.ra, rtol=1e-8) assert not allclose(cirsnod4.dec, cirsnod.dec, rtol=1e-8) cirsnod5 = cirsnod4.transform_to(cframe1) # should be back to the same assert_allclose(cirsnod.ra, cirsnod5.ra) assert_allclose(cirsnod.dec, cirsnod5.dec)
def test_table_can_be_read_and_coords_good(): objs = Table.read(TABLE_NAME, format='ascii', delimiter=',') columns = ['object', 'ra', 'dec'] for col in columns: assert col in objs.colnames for row in objs: try: simbad_pos = ICRS.from_name(row['object']) except name_resolve.NameResolveError: continue table_pos = ICRS(row['ra'], row['dec'], unit=(u.hour, u.degree)) # CHANGE ASSERT TO IF/THEN, print name then assert 0 sep = table_pos.separation(simbad_pos).arcsec warn = '' if sep > MAX_SEP: warn = ('Bad RA/Dec for object {}, ' 'separation is {} arcsec'.format(row['object'], sep)) print (warn) assert len(warn) == 0
def test_regression_3920(): """ Issue: https://github.com/astropy/astropy/issues/3920 """ loc = EarthLocation.from_geodetic(0*u.deg, 0*u.deg, 0) time = Time('2010-1-1') aa = AltAz(location=loc, obstime=time) sc = SkyCoord(10*u.deg, 3*u.deg) assert sc.transform_to(aa).shape == tuple() # That part makes sense: the input is a scalar so the output is too sc2 = SkyCoord(10*u.deg, 3*u.deg, 1*u.AU) assert sc2.transform_to(aa).shape == tuple() # in 3920 that assert fails, because the shape is (1,) # check that the same behavior occurs even if transform is from low-level classes icoo = ICRS(sc.data) icoo2 = ICRS(sc2.data) assert icoo.transform_to(aa).shape == tuple() assert icoo2.transform_to(aa).shape == tuple()
def get_radec(self): """ Extracts the RA and Dec information from the data container. This is not necessary, and some of the data containers may not even have WCS info, but extracting the coordinates if it does simplifies some later tasks. """ """ Extract the information into the new containers """ self.ra = None self.dec = None if self.rafield is not None: try: self.ra = self.data[self.rafield].copy() except: try: self.ra = self.data['x_world'].copy() except: self.ra = None if self.decfield is not None: try: self.dec = self.data[self.decfield].copy() except: try: self.dec = self.data['y_world'].copy() except: self.dec = None """ Put data into a SkyCoords container for easy coordinate-based calculations """ if (self.ra is not None) and (self.dec is not None): """ Determine whether the RA coordinate is in hours or in degrees For now this test is made simple: if the format of the RA data is a string, then the data is expected to be in hms format, otherwise expect decimal degrees. """ if type(self.ra[0]) is str or type(self.ra[0]) is np.string_: raunit = u.hourangle else: raunit = u.deg self.radec = SkyCoord(self.ra,self.dec,unit=(raunit,u.deg)) """ If radec has not been set, report this information (consider raising an exception in future versions of the code) """ if self.radec is None: print '' print 'WARNING: get_radec was called but RA and Dec information was' print ' not found. Please check the format of your catalog.' print ''
class SkyCircle(object): """A circle on the sky. Parameters ---------- center : `~astropy.coordinates.coordsystems.SphericalCoordinatesBase` Circle center coordinate radius : `~astropy.coordinates.angles.Angle` Circle radius """ def __init__(self, center, radius): from astropy.coordinates import ICRS, Angle self.center = ICRS(center) self.radius = Angle(radius) def contains(self, coordinate): """Checks if the coordinate lies inside the circle. Parameters ---------- coordinate : `~astropy.coordinates.coordsystems.SphericalCoordinatesBase` Coordinate to check for containment. Returns ------- contains : bool Does this region contain the coordinate? """ return self.center.separation(coordinate) <= self.radius def intersects(self, other): """Checks if two sky circles overlap. Parameters ---------- other : `~SkyCircle` Other region. """ return self.center.separation(other.center) <= self.radius + other.radius
def main(args): with fitsio.FITS(args.catalogue) as infile: hdu = infile[1] ra1 = hdu['RA_1'][:] dec1 = hdu['DEC_1'][:] ra2 = hdu['ra_2'][:] dec2 = hdu['dec_2'][:] jmag = hdu['jmag'][:] coords1 = ICRS(ra=ra1, dec=dec1, unit=(u.radian, u.radian)) coords2 = ICRS(ra=ra2, dec=dec2, unit=(u.degree, u.degree)) separations = coords1.separation(coords2).degree * 3600. nbins = 30 height, xedges, yedges = np.histogram2d(jmag, separations, nbins) fig, axis = plt.subplots(figsize=(11, 8)) mappable = axis.pcolormesh(xedges[:-1], yedges[:-1], np.log10(height.T + 1), cmap=plt.cm.binary) axis.plot(jmag, separations, 'k.', alpha=0.2) stat, ledges, _ = stats.binned_statistic(jmag, separations, statistic='median', bins=nbins) axis.plot(ledges[:-1], stat, drawstyle='steps-post', color='r') axis.set_xlabel(r'2MASS J Magnitude') axis.set_ylabel(r'Separation / arcseconds') axis.grid(True) fig.tight_layout() if args.output is not None: fig.savefig(args.output, bbox_inches='tight') else: plt.show()
def sdss_IAU_id_to_ra_dec(sdssids, matchtocatalog=None): """ Converts IAU SDSS identifiers (e.g.,"J151503.37+421253.9") to their RA/Decs Returns an ICRS object if `matchtocatalog` is None, otherwise `catalogidx, skysep` """ import re from astropy.coordinates import ICRS, Latitude, Longitude rex = re.compile(r'J(\d{2})(\d{2})(\d{2}(?:\.\d{1,2})?)' r'([+-])(\d{2})(\d{2})(\d{2}(?:\.\d)?)') if isinstance(sdssids, six.string_types): sdssids = [sdssids] ras = [] decs = [] for idi in sdssids: res = rex.match(idi) if res is None: raise ValueError('Could not match ' + idi) res = res.groups() rah, ram, rasc = res[:3] desgn, ded, dem, des = res[-4:] ras.append(':'.join((rah, ram, rasc))) decs.append(desgn + ':'.join((ded, dem, des))) coords = ICRS(ra=Longitude(ras, u.hourangle), dec=Latitude(decs, u.degree)) if matchtocatalog: if not hasattr(matchtocatalog, 'match_to_catalog_sky'): matchtocatalog = ICRS(ra=np.array(matchtocatalog['ra'])*u.deg, dec=np.array(matchtocatalog['dec'])*u.deg) idx, sep, sep3d = coords.match_to_catalog_sky(matchtocatalog) return idx, sep.to(u.arcsec) else: return coords
def get_body_heliographic_stonyhurst(body, time='now'): """ Return a `~sunpy.coordinates.frames.HeliographicStonyhurst` frame for the location of a solar-system body at a specified time. Parameters ---------- body : `str` The solar-system body for which to calculate positions time : various Time to use as `~astropy.time.Time` or in a parse_time-compatible format Returns ------- out : `~sunpy.coordinates.frames.HeliographicStonyhurst` Location of the solar-system body in the `~sunpy.coordinates.HeliographicStonyhurst` frame """ obstime = parse_time(time) body_icrs = ICRS(get_body_barycentric(body, obstime)) body_hgs = body_icrs.transform_to(HGS(obstime=obstime)) return body_hgs
def azel2radec(az_deg, el_deg, lat_deg, lon_deg, t): """convert astronomical target horizontal azimuth, elevation to ecliptic right ascension, declination (degrees)""" if PY2 or Time is None: # non-AstroPy method, less accurate return vazel2radec(az_deg, el_deg, lat_deg, lon_deg, t) t = str2dt(t) obs = EarthLocation(lat=lat_deg * u.deg, lon=lon_deg * u.deg) direc = AltAz(location=obs, obstime=Time(t), az=az_deg * u.deg, alt=el_deg * u.deg) sky = SkyCoord(direc.transform_to(ICRS())) return sky.ra.deg, sky.dec.deg
def test_skycoord_transforms(): # An EarthLocation object should still get copied over # under transformations. eloc = EarthLocation.from_geodetic(0.0, 10.0) coords = ltest.get_catalog() altaz = coords.transform_to(AltAz(location=eloc, obstime=Time.now())) assert altaz.location == eloc gcrs = altaz.transform_to(GCRS()) assert gcrs.location == eloc icrs = altaz.transform_to(ICRS()) assert icrs.location == eloc
def plot_hpix(self, hpix, nside, order='nested', color='blue', edgecolor='black', zorder=1, alpha=1): bounds = HEALPix(nside=nside, order=order, frame=ICRS()) corners = bounds.boundaries_skycoord(np.unique(hpix), step=1) poly = MultiPolygon(Polygon(np.array([-(corners[idx].ra.deg - 360 * (corners[idx].ra.deg > 180)), corners[idx].dec.deg]).T) \ for idx in range(len(corners.ra)) if not any(abs(corners[idx].ra.deg - 360 * (corners[idx].ra.deg > 180) - 180) == 0)) self.ax.add_geometries([poly], crs=ccrs.PlateCarree(), facecolor=color, alpha=alpha, edgecolor=edgecolor, zorder=zorder)
def get_r(RA, DEC): R = np.zeros(len(RA)) ys = np.zeros(len(RA)) for i in range(0, len(RA)): aux = SkyCoord(RA[i], DEC[i]) aux = aux.icrs ra = str(int(aux.ra.hms.h)) + 'h' + str(int( aux.ra.hms.m)) + 'm' + str(int(aux.ra.hms.s)) + 's' dec = str(int(aux.dec.dms.d)) + 'd' + str(abs(int( aux.dec.dms.m))) + 'm' + str(abs(int(aux.dec.dms.s))) + 's' coordinates = ra + ' ' + dec coord = ICRS(coordinates) ygc, r = correct_rgc(coord, galcenter, Angle(str(inps[3])), Angle(str(inps[2])), Distance(inps[4], unit=u.kpc)) R[i] = r.value ys[i] = ygc return R, ys
def build_ephem_interpolant(body, period, t_span, rtol=1e-5): """Interpolates ephemerides data Parameters ---------- body : Body Source body. period : ~astropy.units.Quantity Orbital period. t_span : list(~astropy.units.Quantity) Initial and final epochs. rtol : float, optional Relative tolerance. Controls the number of sampled data points, defaults to 1e-5. Returns ------- intrp : ~scipy.interpolate.interpolate.interp1d Interpolated function. """ h = (period * rtol).to(u.day).value t_span = (t_span[0].to(u.day).value, t_span[1].to(u.day).value + 0.01) t_values = np.linspace(*t_span, int( (t_span[1] - t_span[0]) / h)) # type: ignore r_values = np.zeros((t_values.shape[0], 3)) for i, t in enumerate(t_values): epoch = Time(t, format="jd", scale="tdb") r = get_body_barycentric(body.name, epoch) r = (ICRS( x=r.x, y=r.y, z=r.z, representation_type=CartesianRepresentation).transform_to( GCRS(obstime=epoch)).represent_as(CartesianRepresentation)) r_values[i] = r.xyz.to(u.km) t_values = ((t_values - t_span[0]) * u.day).to(u.s).value return interp1d(t_values, r_values, kind="cubic", axis=0, assume_sorted=True)
def hdu_to_imagemodel(in_hdu): """ Workaround for initializing a `jwst.datamodels.ImageModel` from a normal FITS ImageHDU that could contain HST header keywords and unexpected WCS definition. TBD Parameters ---------- in_hdu : `astropy.io.fits.ImageHDU` Returns ------- img : `jwst.datamodels.ImageModel` """ from astropy.io.fits import ImageHDU, HDUList from astropy.coordinates import ICRS from jwst.datamodels import util import gwcs hdu = ImageHDU(data=in_hdu.data, header=in_hdu.header) new_header = strip_telescope_header(hdu.header) hdu.header = new_header # Initialize data model img = util.open(HDUList([hdu])) # Initialize GWCS tform = gwcs.wcs.utils.make_fitswcs_transform(new_header) hwcs = gwcs.WCS(forward_transform=tform, output_frame=ICRS()) # gwcs.CelestialFrame()) sh = hdu.data.shape hwcs.bounding_box = ((-0.5, sh[0]-0.5), (-0.5, sh[1]-0.5)) # Put gWCS in meta, where blot/drizzle expect to find it img.meta.wcs = hwcs return img
def get_body_heliographic_stonyhurst(body, time='now', observer=None): """ Return a `~sunpy.coordinates.frames.HeliographicStonyhurst` frame for the location of a solar-system body at a specified time. Parameters ---------- body : `str` The solar-system body for which to calculate positions time : various Time to use as `~astropy.time.Time` or in a parse_time-compatible format observer : `~astropy.coordinates.SkyCoord` If not None, the returned coordinate is the apparent location (i.e., accounts for light travel time) Returns ------- out : `~sunpy.coordinates.frames.HeliographicStonyhurst` Location of the solar-system body in the `~sunpy.coordinates.HeliographicStonyhurst` frame """ obstime = parse_time(time) if observer is None: body_icrs = get_body_barycentric(body, obstime) else: observer_icrs = SkyCoord(observer).icrs.cartesian # This implementation is modeled after Astropy's `_get_apparent_body_position` light_travel_time = 0.*u.s emitted_time = obstime delta_light_travel_time = 1.*u.s # placeholder value while np.any(np.fabs(delta_light_travel_time) > 1.0e-8*u.s): body_icrs = get_body_barycentric(body, emitted_time) distance = (body_icrs - observer_icrs).norm() delta_light_travel_time = light_travel_time - distance / speed_of_light light_travel_time = distance / speed_of_light emitted_time = obstime - light_travel_time log.info(f"Apparent body location accounts for {light_travel_time.to('s').value:.2f}" " seconds of light travel time") body_hgs = ICRS(body_icrs).transform_to(HGS(obstime=obstime)) return body_hgs
def compute_healpix_vertices(depth, ipix, wcs): path_vertices = np.array([]) codes = np.array([]) depth = int(depth) step = 1 if depth < 3: step = 2 ipix_lon, ipix_lat = cdshealpix.vertices(ipix, depth) ipix_lon = ipix_lon[:, [2, 3, 0, 1]] ipix_lat = ipix_lat[:, [2, 3, 0, 1]] ipix_boundaries = SkyCoord(ipix_lon, ipix_lat, frame=ICRS()) # Projection on the given WCS xp, yp = skycoord_to_pixel(ipix_boundaries, wcs=wcs) c1 = np.vstack((xp[:, 0], yp[:, 0])).T c2 = np.vstack((xp[:, 1], yp[:, 1])).T c3 = np.vstack((xp[:, 2], yp[:, 2])).T c4 = np.vstack((xp[:, 3], yp[:, 3])).T # if depth < 3: # c5 = np.vstack((xp[:, 4], yp[:, 4])).T # c6 = np.vstack((xp[:, 5], yp[:, 5])).T # c7 = np.vstack((xp[:, 6], yp[:, 6])).T # c8 = np.vstack((xp[:, 7], yp[:, 7])).T # cells = np.hstack((c1, c2, c3, c4, c5, c6, c7, c8, np.zeros((c1.shape[0], 2)))) # path_vertices = cells.reshape((9*c1.shape[0], 2)) # single_code = np.array([Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY]) # else: cells = np.hstack((c1, c2, c3, c4, np.zeros((c1.shape[0], 2)))) path_vertices = cells.reshape((5 * c1.shape[0], 2)) single_code = np.array( [Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY]) codes = np.tile(single_code, c1.shape[0]) return path_vertices, codes
def merge_cat(tmass, ukidss, vista): moc_vista = MOC() read_moc_fits(moc_vista, '../data/vista/moc_vista.fits') moc_ukidss = MOC() read_moc_fits(moc_ukidss, '../data/ukidss/moc_ukidss.fits') moc_order = moc_vista.order hp = HEALPix(nside=2**moc_order, order='nested', frame=ICRS()) moc_allsky = MOC(0, tuple(range(12))) moc_tmass = moc_allsky - moc_ukidss - moc_vista moc_vista = moc_vista - moc_ukidss vista_final = utils.sources_inmoc(vista, hp, moc_vista, moc_order=moc_order, ra='posRA', dec='posDec') vista_final.rename_column('NVTobjID', 'NIRobjID') vista_final.add_column( Table.Column(['VISTA'] * len(vista_final), name='NIR_SURVEY')) tmass_final = utils.sources_inmoc(tmass, hp, moc_tmass, moc_order=moc_order, ra='posRA', dec='posDec') tmass_final.rename_column('NTMobjID', 'NIRobjID') tmass_final.add_column( Table.Column(['2MASS'] * len(tmass_final), name='NIR_SURVEY')) ukidss.rename_column('NUKobjID', 'NIRobjID') ukidss.add_column(Table.Column(['UKIDSS'] * len(ukidss), name='NIR_SURVEY')) xmatchcat_final = vstack([tmass_final, vista_final, ukidss]) msk = np.logical_or(xmatchcat_final['NIR_SURVEY'] == 'UKIDSS', xmatchcat_final['NIR_SURVEY'] == '2MASS') msk = np.logical_and(xmatchcat_final['NIRobjID'].mask, msk) return xmatchcat_final
def _fullsky_projection(self, wcs: WCS, shape: tuple, display_visible_sky: bool): """ """ values = copy.deepcopy(self.value) if display_visible_sky: values[~self.visible_sky] = np.nan if isinstance(values, da.Array): with ProgressBar() if log.getEffectiveLevel() <= logging.INFO else DummyCtMgr(): values = values.compute() with np.errstate(invalid='ignore'): # Ignore the invalid value in bilinear_interpolation (astropy-healpix) array, _ = reproject_from_healpix( (values, ICRS()), wcs, nested=False, shape_out=shape ) return array
def test_ephemerides(): """ We test that using different ephemerides gives very similar results for transformations """ t = Time("2014-12-25T07:00") moon = SkyCoord( GCRS(318.10579159 * u.deg, -11.65281165 * u.deg, 365042.64880308 * u.km, obstime=t)) icrs_frame = ICRS() hcrs_frame = HCRS(obstime=t) ecl_frame = HeliocentricMeanEcliptic(equinox=t) cirs_frame = CIRS(obstime=t) moon_icrs_builtin = moon.transform_to(icrs_frame) moon_hcrs_builtin = moon.transform_to(hcrs_frame) moon_helioecl_builtin = moon.transform_to(ecl_frame) moon_cirs_builtin = moon.transform_to(cirs_frame) with solar_system_ephemeris.set('jpl'): moon_icrs_jpl = moon.transform_to(icrs_frame) moon_hcrs_jpl = moon.transform_to(hcrs_frame) moon_helioecl_jpl = moon.transform_to(ecl_frame) moon_cirs_jpl = moon.transform_to(cirs_frame) # most transformations should differ by an amount which is # non-zero but of order milliarcsecs sep_icrs = moon_icrs_builtin.separation(moon_icrs_jpl) sep_hcrs = moon_hcrs_builtin.separation(moon_hcrs_jpl) sep_helioecl = moon_helioecl_builtin.separation(moon_helioecl_jpl) sep_cirs = moon_cirs_builtin.separation(moon_cirs_jpl) assert_allclose([sep_icrs, sep_hcrs, sep_helioecl], 0.0 * u.deg, atol=10 * u.mas) assert all(sep > 10 * u.microarcsecond for sep in (sep_icrs, sep_hcrs, sep_helioecl)) # CIRS should be the same assert_allclose(sep_cirs, 0.0 * u.deg, atol=1 * u.microarcsecond)
def test_array_coordinates_transformations(arrshape, distance): """ Test transformation on coordinates with array content (first length-2 1D, then a 3D array) """ # M31 coordinates from test_transformations raarr = np.ones(arrshape) * 10.6847929 decarr = np.ones(arrshape) * 41.2690650 if distance is not None: distance = np.ones(arrshape) * distance print(raarr, decarr, distance) c = ICRS(ra=raarr * u.deg, dec=decarr * u.deg, distance=distance) g = c.transform_to(Galactic()) assert g.l.shape == arrshape npt.assert_array_almost_equal(g.l.degree, 121.17440967) npt.assert_array_almost_equal(g.b.degree, -21.57299631) if distance is not None: assert g.distance.unit == c.distance.unit # now make sure round-tripping works through FK5 c2 = c.transform_to(FK5()).transform_to(ICRS()) npt.assert_array_almost_equal(c.ra.radian, c2.ra.radian) npt.assert_array_almost_equal(c.dec.radian, c2.dec.radian) assert c2.ra.shape == arrshape if distance is not None: assert c2.distance.unit == c.distance.unit # also make sure it's possible to get to FK4, which uses a direct transform function. fk4 = c.transform_to(FK4()) npt.assert_array_almost_equal(fk4.ra.degree, 10.0004, decimal=4) npt.assert_array_almost_equal(fk4.dec.degree, 40.9953, decimal=4) assert fk4.ra.shape == arrshape if distance is not None: assert fk4.distance.unit == c.distance.unit # now check the reverse transforms run cfk4 = fk4.transform_to(ICRS()) assert cfk4.ra.shape == arrshape
def test_spectralcoord_with_obstarget(tmpdir): sc = SpectralCoord(10 * u.GHz, observer=ICRS(1 * u.km, 2 * u.km, 3 * u.km, representation_type='cartesian'), target=Galactic(10 * u.deg, 20 * u.deg, distance=30 * u.pc)) tree = dict(spectralcoord=sc) def check(asdffile): assert isinstance(asdffile['spectralcoord'], SpectralCoord) assert_quantity_allclose(asdffile['spectralcoord'].quantity, 10 * u.GHz) assert isinstance(asdffile['spectralcoord'].observer, ICRS) assert isinstance(asdffile['spectralcoord'].target, Galactic) assert_roundtrip_tree(tree, tmpdir, asdf_check_func=check)
def apply_mask(self, mask): """ Remove particles from source arrays according to a mask. Parameters ---------- mask : array-like, containing boolean-like Remove particles with indices corresponding to False values from the source arrays. """ self.T_g = self.T_g[mask] self.mHI_g = self.mHI_g[mask] self.coordinates_g = self.coordinates_g[mask] self.sky_coordinates = ICRS(self.coordinates_g) self.hsm_g = self.hsm_g[mask] self.npart = np.sum(mask) if self.npart == 0: raise RuntimeError('No source particles in target region.') return
def test_calculate_parallactic_angle(self) -> None: # TODO: Implement test (DM-21336) radec_icrs = ICRS(Angle(0.0, unit=u.hourangle), Angle(-80.0, unit=u.deg)) location = EarthLocation.from_geodetic(lon=-70.747698 * u.deg, lat=-30.244728 * u.deg, height=2663.0 * u.m) current_time = astropy_time_from_tai_unix(current_tai()) current_time.location = location par_angle = calculate_parallactic_angle( location, current_time.sidereal_time("mean"), radec_icrs, ) assert par_angle is not None
def get_radial_vals(star_list): """create a list containing non-zero Radial Velocities. The input star_list is a list object returned by job.results() Parameters ---------- star_list : list returned by job.results() Returns ------- v_gsr : list of coordinates containing non-zero radial_velicities """ i = 0 count = len(star_list) x = [] # make a fancy progressbar to monitor progress since this this iterates over # typically long star lists widgets = [ ' [', progressbar.Timer(), '] ', progressbar.Bar(), ' (', progressbar.ETA(), ') ', ] with progressbar.ProgressBar(max_value=count, widgets=widgets) as bar2: for star in star_list: ra = star['ra'] * u.deg dec = star['dec'] * u.deg radial = star['radial_velocity'] * u.km / u.s star_icrs = ICRS(ra=ra, dec=dec, radial_velocity=radial) # convert to GSR from barycentric x.append(rv_to_gsr(star_icrs).value) count = count + 1 i = i + 1 bar2.update(i) return x
def _create_coord_from_offset(observer, radial_velocity): """ Generates a default target or observer from a provided observer or target with an offset defined such as to create the provided radial velocity. Parameters ---------- observer : `~astropy.coordinates.BaseCoordinateFrame` or `~astropy.coordinates.SkyCoord` Observer frame off which to base the target frame. radial_velocity : `~astropy.units.Quantity` Radial velocity used to calculate appropriate offsets between provided observer and generated target. Returns ------- target : `~astropy.coordinates.BaseCoordinateFrame` or `~astropy.coordinates.SkyCoord` Generated target frame. """ # The generated observer or target will be set up along the same y and z # coordinates as the target or observer, but offset along the x direction observer_icrs = observer.transform_to(ICRS()) d = observer_icrs.cartesian.norm() drep = CartesianRepresentation( [DEFAULT_DISTANCE.to(d.unit), 0 * d.unit, 0 * d.unit]) obs_vel = observer_icrs.cartesian.differentials['s'] target = (observer_icrs.cartesian.without_differentials() + drep).with_differentials( CartesianDifferential([ _relativistic_velocity_addition( obs_vel.d_x, radial_velocity), obs_vel.d_y.to(radial_velocity.unit), obs_vel.d_z.to(radial_velocity.unit) ])) return observer_icrs.realize_frame(target)
def from_body(cls, body, epochs, *, attractor=None, plane=Planes.EARTH_EQUATOR): """Return `Ephem` for a `SolarSystemPlanet` at certain epochs. Parameters ---------- body: ~poliastro.bodies.SolarSystemPlanet Body. epochs: ~astropy.time.Time Epochs to sample the body positions. attractor : ~poliastro.bodies.SolarSystemPlanet, optional Body to use as central location, if not given the Solar System Barycenter will be used. plane : ~poliastro.frames.Planes, optional Fundamental plane of the frame, default to Earth Equator. """ if epochs.isscalar: epochs = epochs.reshape(1) if epochs.scale != "tdb": epochs = epochs.tdb warn( "Input time was converted to scale='tdb' with value " f"{epochs.tdb.value}. Use Time(..., scale='tdb') instead.", TimeScaleWarning, stacklevel=2, ) r, v = get_body_barycentric_posvel(body.name, epochs) coordinates = r.with_differentials(v.represent_as(CartesianDifferential)) destination_frame = _get_destination_frame(attractor, plane, epochs) if destination_frame is not None: coordinates = ( ICRS(coordinates) .transform_to(destination_frame) .represent_as(CartesianRepresentation, CartesianDifferential) ) return cls(coordinates, epochs, plane)
def test_icrs_cirs(): """ Check a few cases of ICRS<->CIRS for consistency. Also includes the CIRS<->CIRS transforms at different times, as those go through ICRS """ ra, dec, dist = randomly_sample_sphere(200) inod = ICRS(ra=ra, dec=dec) iwd = ICRS(ra=ra, dec=dec, distance=dist * u.pc) cframe1 = CIRS() cirsnod = inod.transform_to(cframe1) # uses the default time # first do a round-tripping test inod2 = cirsnod.transform_to(ICRS) assert_allclose(inod.ra, inod2.ra) assert_allclose(inod.dec, inod2.dec) # now check that a different time yields different answers cframe2 = CIRS(obstime=Time('J2005', scale='utc')) cirsnod2 = inod.transform_to(cframe2) assert not allclose(cirsnod.ra, cirsnod2.ra, rtol=1e-8) assert not allclose(cirsnod.dec, cirsnod2.dec, rtol=1e-8) # parallax effects should be included, so with and w/o distance should be different cirswd = iwd.transform_to(cframe1) assert not allclose(cirswd.ra, cirsnod.ra, rtol=1e-8) assert not allclose(cirswd.dec, cirsnod.dec, rtol=1e-8) # and the distance should transform at least somehow assert not allclose(cirswd.distance, iwd.distance, rtol=1e-8) # now check that the cirs self-transform works as expected cirsnod3 = cirsnod.transform_to(cframe1) # should be a no-op assert_allclose(cirsnod.ra, cirsnod3.ra) assert_allclose(cirsnod.dec, cirsnod3.dec) cirsnod4 = cirsnod.transform_to(cframe2) # should be different assert not allclose(cirsnod4.ra, cirsnod.ra, rtol=1e-8) assert not allclose(cirsnod4.dec, cirsnod.dec, rtol=1e-8) cirsnod5 = cirsnod4.transform_to(cframe1) # should be back to the same assert_allclose(cirsnod.ra, cirsnod5.ra) assert_allclose(cirsnod.dec, cirsnod5.dec)
def EarthPosition(t, ephem='builtin'): ''' The position of Earth at time, t, w.r.t. the Sun using astropy.coordinates.solar_system_ephemeris. ''' # logger = logging.getLogger() # logger.critical('As of 1.3, astropy has changed the behavior of some functions, giving diverging answers from previous versions') T = Time(t, format='jd', scale='utc') # pos_bary, vel_bary = get_body_barycentric_posvel('earth', time=T) with solar_system_ephemeris.set(ephem): pos_bary = get_body_barycentric('earth', time=T) pos_ICRS = ICRS(pos_bary) hcrs_frame = HCRS(obstime=T) Pos_HCRS = np.vstack((SkyCoord(pos_ICRS).transform_to(hcrs_frame). cartesian.xyz.to(u.meter).value)) Pos_HCI = HCRS2HCI(Pos_HCRS) return Pos_HCI
def geomotion_velocity(time, skycoord, frame="heliocentric"): """ Perform a barycentric/heliocentric velocity correction. For the correciton, this routine uses the ephemeris: astropy.coordinates.solar_system_ephemeris.set For more information see `~astropy.coordinates.solar_system_ephemeris`. Parameters ---------- time : astropy.time.Time The time of observation, including the location. skycoord: astropy.coordinates.SkyCoord The RA and DEC of the pointing, as a SkyCoord quantity. frame : str The reference frame that should be used for the calculation. Returns ------- vcorr : float The velocity correction that should be added to the original velocity. """ # Check that the RA/DEC of the object is ICRS compatible if not skycoord.is_transformable_to(ICRS()): msgs.error("Cannot transform RA/DEC of object to the ICRS") # Calculate ICRS position and velocity of Earth's geocenter ep, ev = solar_system.get_body_barycentric_posvel('earth', time) # Calculate GCRS position and velocity of observatory op, ov = time.location.get_gcrs_posvel(time) # ICRS and GCRS are axes-aligned. Can add the velocities velocity = ev + ov if frame == "heliocentric": # ICRS position and velocity of the Sun sp, sv = solar_system.get_body_barycentric_posvel('sun', time) velocity += sv # Get unit ICRS vector in direction of SkyCoord sc_cartesian = skycoord.icrs.represent_as( UnitSphericalRepresentation).represent_as(CartesianRepresentation) return sc_cartesian.dot(velocity).to(units.km / units.s).value
def sanitize_image(image, output_file, overwrite=False): """ Transform a FITS image so that it is in equatorial coordinates with a TAN projection and floating-point values, all of which are required to work correctly in WWT at the moment. Image can be a filename, an HDU, or a tuple of (array, WCS). """ # The reproject package understands the different inputs to this function # so we can just transparently pass it through. wcs, shape_out = find_optimal_celestial_wcs([image], frame=ICRS(), projection='TAN') array, footprint = reproject_interp(image, wcs, shape_out=shape_out) fits.writeto(output_file, array.astype(np.float32), wcs.to_header(), overwrite=overwrite)
def __new__(cls, *args, **kwargs): # We don't want to call this method if we've already set up # an skyoffset frame for this class. if not (issubclass(cls, ReferencePlaneFrame) and cls is not ReferencePlaneFrame): # We get the origin argument, and handle it here. Default is ICRS: # the user might want to use arbitrary reference plane coordinates # without every transforming them origin_frame = kwargs.get('origin', ICRS()) if hasattr(origin_frame, 'frame'): origin_frame = origin_frame.frame newcls = _make_cls(origin_frame.__class__) return newcls.__new__(newcls, *args, **kwargs) # http://stackoverflow.com/questions/19277399/why-does-object-new-work-differently-in-these-three-cases # See above for why this is necessary. Basically, because some child # may override __new__, we must override it here to never pass # arguments to the object.__new__ method. if super().__new__ is object.__new__: return super().__new__(cls) return super().__new__(cls, *args, **kwargs)
def test_observer_init_rv_behavior(): """ Test basic initialization behavior or observer/target and redshift/rv """ # Start off by specifying the radial velocity only sc_init = SpectralCoord([4000, 5000] * u.AA, radial_velocity=100 * u.km / u.s) assert sc_init.observer is None assert sc_init.target is None assert_quantity_allclose(sc_init.radial_velocity, 100 * u.km / u.s) # Next, set the observer, and check that the radial velocity hasn't changed with pytest.warns(AstropyUserWarning, match='No velocity defined on frame'): sc_init.observer = ICRS( CartesianRepresentation([0 * u.km, 0 * u.km, 0 * u.km])) assert sc_init.observer is not None assert_quantity_allclose(sc_init.radial_velocity, 100 * u.km / u.s) # Setting the target should now cause the original radial velocity to be # dropped in favor of the automatically computed one sc_init.target = SkyCoord(CartesianRepresentation( [1 * u.km, 0 * u.km, 0 * u.km]), frame='icrs', radial_velocity=30 * u.km / u.s) assert sc_init.target is not None assert_quantity_allclose(sc_init.radial_velocity, 30 * u.km / u.s) # The observer can only be set if originally None - now that it isn't # setting it again should fail with pytest.raises(ValueError, match='observer has already been set'): sc_init.observer = GCRS( CartesianRepresentation([0 * u.km, 1 * u.km, 0 * u.km])) # And similarly, changing the target should not be possible with pytest.raises(ValueError, match='target has already been set'): sc_init.target = GCRS( CartesianRepresentation([0 * u.km, 1 * u.km, 0 * u.km]))
def radec(ra, dec): """ Equatorial coordinates :param ra: Right ascension in degrees :type ra: float :param dec: Declination in degrees :type dec: float :returns: :class:`astropy.coordinates.ICRS` object :rtype: :class:`astropy.coordinates.ICRS` :Example: >>> from nenupysim.astro import eq_coord >>> radec = eq_coord( ra=51, dec=39, ) """ return ICRS(ra=ra * u.deg, dec=dec * u.deg)
def azel2radec( az_deg: float, el_deg: float, lat_deg: float, lon_deg: float, time: datetime, usevallado: bool = False ) -> Tuple[float, float]: """ viewing angle (az, el) to sky coordinates (ra, dec) Parameters ---------- az_deg : float azimuth [degrees clockwize from North] el_deg : float elevation [degrees above horizon (neglecting aberration)] lat_deg : float observer latitude [-90, 90] lon_deg : float observer longitude [-180, 180] (degrees) time : datetime.datetime or str time of observation usevallado : bool, optional default use astropy. If true, use Vallado algorithm Returns ------- ra_deg : float ecliptic right ascension (degress) dec_deg : float ecliptic declination (degrees) """ if usevallado or Time is None: # non-AstroPy method, less accurate return vazel2radec(az_deg, el_deg, lat_deg, lon_deg, time) obs = EarthLocation(lat=lat_deg * u.deg, lon=lon_deg * u.deg) direc = AltAz(location=obs, obstime=Time(str2dt(time)), az=az_deg * u.deg, alt=el_deg * u.deg) sky = SkyCoord(direc.transform_to(ICRS())) return sky.ra.deg, sky.dec.deg
def __init__(self, nside, coordsystem, order='nested', array=None): """ grid: HEALPix map object nside: HEALPix nside parameter (int, power of 2) order: pixel ordering scheme of the HEALPix map coordsystem: Coordsystem object that describes the coordinate system Note: The HEALPix map used for the grid is initialized with a dummy ICRS coordinate frame, that is not used in practise as healpy nor astropy don't support ECEF/Geographic coordinate systems. Instead the grid coordinates are defined through a coordinate system obtained from the LAL library. """ if array is not None: assert len(array) == healpy.nside2npix(nside), "Data array has incorrect size" self.grid = HEALPix(nside=nside, order=order, frame=ICRS()) self.nside = nside self.order = order self.coordsystem = coordsystem self.data = numpy.empty(healpy.nside2npix(nside)) if array is None else array
def to_icrs(self): """Creates a new Orbit object with its coordinates transformed to ICRS. Notice that, strictly speaking, the center of ICRS is the Solar System Barycenter and not the Sun, and therefore these orbits cannot be propagated in the context of the two body problem. Therefore, this function exists merely for practical purposes. .. versionadded:: 0.11.0 """ coords = self.frame.realize_frame(self.represent_as(CartesianRepresentation)) coords.representation_type = CartesianRepresentation icrs_cart = coords.transform_to(ICRS).represent_as(CartesianRepresentation) # TODO: The attractor is in fact the Solar System Barycenter ss = self.from_vectors( Sun, r=icrs_cart.xyz, v=icrs_cart.differentials["s"].d_xyz, epoch=self.epoch ) ss._frame = ICRS() # Hack! return ss
def build_ephem_interpolant(body, period, t_span, rtol=1e-5): h = (period * rtol).to(u.day).value t_span = (t_span[0].to(u.day).value, t_span[1].to(u.day).value + 0.01) t_values = np.linspace(*t_span, int((t_span[1] - t_span[0]) / h)) r_values = np.zeros((t_values.shape[0], 3)) for i, t in enumerate(t_values): epoch = Time(t, format="jd", scale="tdb") r = get_body_barycentric(body.name, epoch) r = (ICRS( x=r.x, y=r.y, z=r.z, representation_type=CartesianRepresentation).transform_to( GCRS(obstime=epoch)).represent_as(CartesianRepresentation)) r_values[i] = r.xyz.to(u.km) t_values = ((t_values - t_span[0]) * u.day).to(u.s).value return interp1d(t_values, r_values, kind="cubic", axis=0, assume_sorted=True)
def test_gcrs_altaz(): """ Check GCRS<->AltAz transforms for round-tripping. Has multiple paths """ from astropy.coordinates import EarthLocation ra, dec, _ = randomly_sample_sphere(1) gcrs = GCRS(ra=ra[0], dec=dec[0], obstime='J2000') # check array times sure N-d arrays work times = Time(np.linspace(2456293.25, 2456657.25, 51) * u.day, format='jd') loc = EarthLocation(lon=10 * u.deg, lat=80. * u.deg) aaframe = AltAz(obstime=times, location=loc) aa1 = gcrs.transform_to(aaframe) aa2 = gcrs.transform_to(ICRS()).transform_to(CIRS()).transform_to(aaframe) aa3 = gcrs.transform_to(ITRS()).transform_to(CIRS()).transform_to(aaframe) # make sure they're all consistent assert_allclose(aa1.alt, aa2.alt) assert_allclose(aa1.az, aa2.az) assert_allclose(aa1.alt, aa3.alt) assert_allclose(aa1.az, aa3.az)
def visibility_main(): """Plot a single target.""" parser = argparse.ArgumentParser(description="A visibility plotter for a single target.") parser.add_argument("target", type=six.text_type, help="Object name as resolved by SIMBAD") parser.add_argument("-d","--date", help="Date before night, as parsed by Astropy.", default=Time.now()) parser.add_argument("-o","--output", type=six.text_type, help="Output filename.") parser.add_argument("-O", "--observatory", type=six.text_type, help="Observatory Name", default="Mauna Kea") parser.add_argument("--tz", type=six.text_type, help="Local Timezone.") parser.add_argument("--show", action="store_true", help="Show, don't save.") options = parser.parse_args() # Setup Target t = Target(name=options.target, position=ICRS.from_name(options.target)) date = Time(options.date, scale='utc') if not options.output: options.output = "visibility_{0}_{1:%Y%m%d}.pdf".format(t.name.replace(" ", "_"), date.datetime) o = Observatory.from_name(options.observatory) print(o) t.compute(o) print(t) # Setup Figure fig = plt.figure() bbox = (0.1, 0.1, 0.65, 0.8) # l, b, w, h v_ax = fig.add_axes(bbox) v = VisibilityPlot(o, date) v.add(t) v(v_ax, moon_distance_maximum=(60 * u.degree)) if options.show: plt.show() else: plt.savefig(options.output) subprocess.call(["open", options.output])
def match_objects(folder_labels): print("----------------------------------------") print("Running Module 2: Match Objects") # stores all "_" filter txt files (eventually will group by similar exposure times in event there are more than one J,Ks files j_files = np.hstack(np.array(glob.glob('Data/{}/*-J.txt'.format(folder))) for folder in folder_labels) k_files = np.hstack(np.array(glob.glob('Data/{}/*-Ks.txt'.format(folder))) for folder in folder_labels) print j_files print k_files j_filter_data = np.empty([0,5]) ra1 = np.empty([0,1]) ra2 = np.empty([0,1]) k_filter_data = np.empty([0,5]) dec1 = np.empty([0,1]) dec2 = np.empty([0,1]) print '\nPlease wait while all data is loaded from files...' # appends data from all J filter files in folder if multiple for j in j_files: # generate numpy array from txt files new_data1 = np.genfromtxt(j, unpack = False) j_filter_data = np.vstack([j_filter_data, new_data1]) print 'Data from J filter file', j, 'loaded...' print j_filter_data.shape ra1 = j_filter_data[:,3] dec1 = j_filter_data[:,4] print 'J Filter shape:', ra1.shape, dec1.shape # appends data from all Ks filter files in folder if multiple for k in k_files: new_data2 = np.genfromtxt(k, unpack = False) k_filter_data = np.vstack([k_filter_data, new_data2]) print 'Data from Ks filter file', k, 'loaded...' print k_filter_data.shape ra2 = k_filter_data[:,3] dec2 = k_filter_data[:,4] print 'Ks Filter shape:', ra2.shape, dec2.shape print 'Data from all files loaded.' print '\nPlease wait while objects are matched across the J and Ks Filter...' # j filter ra/dec info to be compared # in units of degrees obj_1 = ICRS(ra1, dec1, unit=(u.degree, u.degree)) # k filter ra/dec info to be compared # in units of degrees obj_2 = ICRS(ra2, dec2, unit=(u.degree, u.degree)) # This function will match all objects from obj_1 (j-filter) with an object in obj_2 (ks-filter) # By its nature, match_to_catalog_sky compares object data against catalog of sky, which would yield a closest match for every object # In our application, we compare two different sets of object data to each other, which should not guarantee a match # This means that we will get as many matches as there are objects in the smaller object data set (in this case, the j-filter will always have less objects) # This could be problematic since a "closest" match will be made relative to the available objects in obj_2 (ks-filter) # So a match does not necessarily constitute a match for us # To remedy this, I have run the matched objects through another test to compare the sum of differences against a set tolerance # This will ensure that all matches are within a controlled and tolerable closeness idx, d2d, d3d = obj_1.match_to_catalog_sky(obj_2) # match j band to k band since there are more objects in k # gets data matches from k-filter data based on matched indexes returned by match_to_catalog_sky matches = k_filter_data[idx,:] # appends all data columns for matched objects in a [:,10] array # j-filter # 0 -> Classification # 1 -> Aper_flux_3 # 2 -> Aper_flux_3_err # 3 -> RA # 4 -> DEC # k-filter # 5 -> Classification # 6 -> Aper_flux_3 # 7 -> Aper_flux_3_err # 8 -> RA # 9 -> DEC filter_matches = np.column_stack([j_filter_data, matches]) # CHANGE THE TOLERANCE TO SEE WHAT WORKS BEST tolerance = 0.0001 # compares sum of differences between RA/DEC values to set tolerance to ensure quality matches # see long comment above to see reasoning within_tol_index = ((abs(filter_matches[:,3]-filter_matches[:,8]) < tolerance) & (abs(filter_matches[:,4]-filter_matches[:,9]) < tolerance)).nonzero() stellar_obj_matches = (np.squeeze((filter_matches[within_tol_index,:]), axis=0)) print '\nNumber of matches found', stellar_obj_matches.shape np.savetxt('Resources/J_Ks-matches.txt', stellar_obj_matches, fmt=['%.1f', '%.10f', '%.10f', '%.10f', '%.10f','%.1f', '%.10f', '%.10f', '%.10f', '%.10f'], delimiter=' ')
def __init__(self, center, radius): from astropy.coordinates import ICRS, Angle self.center = ICRS(center) self.radius = Angle(radius)
def test_radec_to_munu(self): radec = ICRS(ra=0.0*u.deg, dec=0.0*u.deg) munu = radec.transform_to(SDSSMuNu(stripe=10)) assert munu.mu.value == 0.0 assert munu.nu.value == 0.0 assert munu.incl.value == 0.0
def proc_m67(file_path=None,outdir=None, bias_fil=None): from astropy.coordinates import ICRS from astropy.io import ascii from astropy import units as u from astropy.io.fits import getdata import xastropy.PH136.experiments.hrdiagram as hrd # Defaults if file_path == None: file_path = 'Raw/' if outdir == None: outdir = 'Science/' # Bias frame if bias_fil == None: bias_fil = 'Bias.fits' bias_img,bias_head = getdata(bias_fil,0,header=True) # Read Log data = ascii.read('simple.log',delimiter='|') nfil = len(data) all_coord = ICRS(ra=data['RA'], dec=data['DEC'], unit=(u.hour,u.degree)) # M67 coords m67_rac = '08:54:24' m67_decc = '+11:49:00' m67_c = ICRS(m67_rac, m67_decc, unit=(u.hour,u.degree)) # Find all M67 sep = (m67_c.separation(all_coord)).degree im67, = np.where( sep < 1. ) # 1 degree m67 = data[im67] # 5 positions m67_ra = ['08:52:02.2', '08:52:15.3', '08:51:49.9', '08:51:50.0', '08:52:16.2'] m67_dec = ['+11:52:41.0', '+11:55:51.0', '+11:55:53.0', '+11:49:38.0', '+11:49:40.0'] m67_pointings = ICRS(ra=m67_ra, dec=m67_dec, unit=(u.hour, u.degree)) # Filters all_filt=np.array(m67['Filter']) filters,ifilt = np.unique(all_filt,return_index=True) # Loop on Filterse all_fil = [] for ff in filters: # Load Sky frame skyfil = 'Sky_'+ff+'.fits' sky_img,head = getdata(skyfil,0,header=True) # Images idx = np.where(m67['Filter'] == ff) # Loop on images for kk in np.concatenate(idx,axis=0): # Read img,head = getdata(m67[kk]['File'],0,header=True) # Bias subtract img = img - bias_img # Trim timg = hrd.trimflip_img(img) # Flat field timg = timg / sky_img # Normalize by exposure timg = timg / m67[kk]['Exp'] # Filename coord = ICRS(head['RA'], head['DEC'], unit=(u.hour,u.degree)) sep = (coord.separation(m67_pointings)).degree ipos = np.argmin(sep) outfil = outdir+'M67_C'+str(ipos)+'_t'+str(int(m67[kk]['Exp']))+'_'+ff+'.fits' # Check for duplicate flg_skip = 0 mt = [i for i in range(len(all_fil)) if all_fil[i] == outfil] if len(mt) > 0: print 'Duplicate image', outfil print 'Skipping...' continue all_fil.append(outfil) # Write print 'Writing ', outfil fits.writeto(outfil, timg, clobber=True) return
def proc_sa104(file_path=None,outdir=None, bias_fil=None): from astropy.coordinates import ICRS from astropy.io import ascii from astropy import units as u from astropy.io.fits import getdata import xastropy.PH136.experiments.hrdiagram as hrd # Defaults if file_path == None: file_path = 'Raw/' if outdir == None: outdir = 'Std/' # Bias frame if bias_fil == None: bias_fil = 'Bias.fits' bias_img,bias_head = getdata(bias_fil,0,header=True) # Read Log data = ascii.read('simple.log',delimiter='|') nfil = len(data) all_coord = ICRS(ra=data['RA'], dec=data['DEC'], unit=(u.hour,u.degree)) # M67 coords sa104_rac = '12:43:44.3' sa104_decc = '-00:29:40.0' sa104_c = ICRS(sa104_rac, sa104_decc, unit=(u.hour,u.degree)) # Find all SA 104 sep = (sa104_c.separation(all_coord)).degree isa104, = np.where( sep < 1. ) # 1 degree sa104 = data[isa104] # Filters all_filt=np.array(sa104['Filter']) filters,ifilt = np.unique(all_filt,return_index=True) # Loop on Filterse all_fil = [] for ff in filters: # Load Sky frame skyfil = 'Sky_'+ff+'.fits' sky_img,head = getdata(skyfil,0,header=True) # Images idx = np.where(sa104['Filter'] == ff) # Loop on images for kk in np.concatenate(idx,axis=0): # Read img,head = getdata(sa104[kk]['File'],0,header=True) # Bias subtract img = img - bias_img # Trim timg = hrd.trimflip_img(img) # Flat field timg = timg / sky_img # Normalize by exposure timg = timg / sa104[kk]['Exp'] # Filename outfil = outdir+'SA104_t'+str(int(sa104[kk]['Exp']))+'_'+ff+'.fits' # Check for duplicate flg_skip = 0 mt = [i for i in range(len(all_fil)) if all_fil[i] == outfil] if len(mt) > 0: print 'Duplicate image', outfil print 'Skipping...' continue all_fil.append(outfil) # Write print 'Writing ', outfil fits.writeto(outfil, timg, head, clobber=True) return
def set_targets(self, v_plotter): """Setup the single target.""" t = Target(name=self.opts.target, position=ICRS.from_name(self.opts.target)) self.log.log(_ll(2), t) v_plotter.add(t)
class Secat: """ The __init__ method has been changed to return something like a record array, which has the same number of rows as the old 2D float array, but which stores each row as a single tuple. It is thus a 1D array, sort of like a structure array in C. The columns can be accessed by field name, which for now is just 'f0', 'f1', etc., unless the input catalog is in SExtractor's FITS LDAC format, in which case the field names actually correspond to the SExtractor variable names. The code used to expect the old 2D float array format. It should have all been updated, but there may still be some issues. """ def __init__(self, incat, catformat='ldac', verbose=True, namecol=None, racol=None, deccol=None, rafield=None, decfield=None, usecols=False): """ This method gets called when the user types something like secat = Secat(infile) Inputs: incat - input table data. This can be in one of two forms: 1. a file containing the catalog (most common) 2. a Table instance containing the catalog data catformat - format of the input file, if incat is a filename. The options are: ascii - asciitab - ldac - sdssfits - secat - NOTE: this parameter is not used if incat is a Table rather than the name of an input file """ """ Set a flag showing whether the file has been modified """ self.modified = False """ Set other default values """ self.radec = None self.rafield = None self.decfield = None self.centpos = None self.galmask = None self.starmask = None """ Start by loading the catalog information """ incattype = (str(type(incat))).split('.')[-1] if incattype[0:3] == 'Tab' or incattype[0:4] == 'FITS': self.data = incat.copy() if rafield: self.rafield = rafield if decfield: self.decfield = decfield self.nrows = len(incat) self.ncols = len(incat.columns) self.catformat = 'Table' elif isinstance(incat, str): self.load_from_file(incat, catformat=catformat, verbose=verbose, namecol=namecol, racol=racol, deccol=deccol, rafield=rafield, decfield=decfield, usecols=usecols) else: print('') print('ERROR: input catalog must either be a filename or a Table') print(' Input catalog type is' + str(type(incat))) print('') return None #----------------------------------------------------------------------- def load_from_file(self, incat, catformat='ldac', verbose=True, namecol=None, racol=None, deccol=None, rafield=None, decfield=None, usecols=False): if verbose: print "" print "Loading data from catalog file %s" % incat print "-----------------------------------------------" print "Expected catalog format: %s" % catformat print "" """ Define a flag for successful reading of input catalog """ read_success = True """ Read in catalog in a manner appropriate to the catformat """ if catformat == 'secat': try: self.data = ascii.read(incat) ncols = len(self.data.colnames) nrows = len(self.data) """ Set the field names """ self.rafield = 'ALPHA_J2000' self.decfield = 'DELTA_J2000' except: print " ERROR. Problem in loading file %s" % incat print " Check to make sure filename matches an existing file." print "" print " This also may have failed if the input file is in the" print " SExtractor FITS LDAC format. Checking that..." print "" read_success = False elif catformat == 'asciitab': f = open(incat) foo = f.readline() f.close() if foo[0] == '#': try: self.data = ascii.read(incat, guess=False, format='commented_header') except: print('') print('ERROR: Could not read data from %s' % incat) print(' Tried using "commented_header" format but failed') print(' Please check input file.') print('') raise IOError else: try: self.data = ascii.read(incat) except: print '' print 'ERROR: Could not properly read data from %s' % incat print 'Tried using the automatic formatting but failed' print ' Please check input file.' print '' raise IOError ncols = len(self.data.colnames) nrows = len(self.data) """ Set the field names """ if rafield: self.rafield = rafield if decfield: self.decfield = decfield elif catformat=='ascii': """ ASCII format """ try: """ Set up the data format in the catalog """ foo = np.loadtxt(incat,dtype='S30') ncols = foo.shape[1] del foo coltypes = np.ones(ncols,dtype='S3') coltypes[:] = 'f8' if namecol is not None: print "Object name column: %d" % namecol coltypes[namecol] = 'S30' colstr = '' for i in range(ncols): colstr = '%s,%s' % (colstr,coltypes[i]) colstr = colstr[1:] dt = np.dtype(colstr) """ Actually read in the data """ self.informat = 'ascii' self.data = np.loadtxt(incat,dtype=dt) nrows = self.data.shape[0] """ Set the field names """ if racol is not None: self.rafield = 'f%d' % racol else: self.rafield = None if deccol is not None: self.decfield = 'f%d' % deccol else: self.decfield = None if namecol is not None: self.namefield = 'f%d' % namecol else: self.namefield = None except: print " ERROR. Problem in loading file %s" % incat print " Check to make sure filename matches an existing file." print " " print " This may have failed if there is a string column in" print " the input catalog (e.g., for an object name). " print " If this is the case, use the namecol to indicate which " print " column contains the string values (column numbers are " print " zero-indexed)" print "" print " This also may have failed if the input file is in the" print " SExtractor FITS LDAC format. Checking that..." print "" read_success = False elif catformat.lower()=='ldac' or read_success==False: try: self.data = Table.read(incat, format='fits', hdu=2) except: print " ERROR. Problem in loading file %s" % incat print " Check to make sure filename matches an existing file." print " " return self.informat = 'ldac' nrows = len(self.data) ncols = len(self.data.columns) """ Set the field names """ self.rafield = 'ALPHA_J2000' self.decfield = 'DELTA_J2000' elif catformat.lower()=='sdssfits' or read_success==False: try: self.data = Table.read(incat, format='fits', hdu=1) except: print " ERROR. Problem in loading file %s" % incat print " Check to make sure filename matches an existing file." print " " return self.informat = 'sdss' nrows = len(self.data) ncols = len(self.data.columns) """ Set the field names """ self.rafield = 'ra' self.decfield = 'dec' """ Split the stars from the galaxies, according to the SDSS classification. In the SDSS scheme, type=3 is a galaxy and type=6 is a star """ if 'type' in self.data.colnames: oclass = self.data['type'] elif 'type_r' in self.data.colnames: oclass = self.data['type_r'] else: oclass = None if oclass is not None: self.galmask = oclass == 3 self.starmask = oclass == 6 else: self.galmask = np.ones(dtype=bool) self.starmask = None print('Read SDSS catalog from %s' % incat) print('Number of galaxies: %5d' % self.galmask.sum()) if self.starmask is not None: print('Number of stars: %5d' % self.starmask.sum()) else: print '' print 'Unrecognized format. Must be one of:' print ' ascii, secat, ldac, sdssfits' sys.exit() if verbose: print "Number of rows: %d" % nrows print "Number of columns: %d" % ncols if self.rafield is not None: print 'RA field name: %s' % self.rafield if self.decfield is not None: print 'Dec field name: %s' % self.decfield self.infile = incat self.catformat = catformat self.nrows = nrows self.ncols = ncols #----------------------------------------------------------------------- def close_ldac(self): """ Closes the catalog. If the catalog is in fits format and it has been modified (as shown by the modified parameter in this Secat class) then use flush rather than close. """ """ Close the file if it is in the expected format """ if self.informat == 'ldac': if self.modified: self.hdu.flush() print 'Updating input fits LDAC file: %s' % self.infile else: self.hdu.close() else: print '' print 'WARNING. Calling close_ldac but file is not in ldac format' print '' #---------------------------------------------------------------------- def make_magmask(self, magname, mfaint=None, mbright=None): """ Makes a mask that is True for magnitudes brighter than mfaint and fainter than mbright. Note that one of these two could have the value None, in which case it would be ignored. For example, if mbright is None, then the mask will be True for all galaxies brighter than mfaint Inputs: magname - the name in the catalog for the column that represents the object magnitudes. This could be something like, e.g., 'r' or 'MAG_AUTO' """ mag = self.data[magname] if mfaint is None and mbright is None: self.magmask = np.ones(self.nrows,dtype=bool) elif mfaint is None: self.magmask = mag >= mbright elif mbright is None: self.magmask = mag <= mfaint else: self.magmask = (mag >= mbright) & (mag <= mfaint) #----------------------------------------------------------------------- def get_radec(self): """ Extracts the RA and Dec information from the data container. This is not necessary, and some of the data containers may not even have WCS info, but extracting the coordinates if it does simplifies some later tasks. """ """ Extract the information into the new containers """ self.ra = None self.dec = None if self.rafield is not None: try: self.ra = self.data[self.rafield].copy() except: try: self.ra = self.data['x_world'].copy() except: self.ra = None if self.decfield is not None: try: self.dec = self.data[self.decfield].copy() except: try: self.dec = self.data['y_world'].copy() except: self.dec = None """ Put data into a SkyCoords container for easy coordinate-based calculations """ if (self.ra is not None) and (self.dec is not None): """ Determine whether the RA coordinate is in hours or in degrees For now this test is made simple: if the format of the RA data is a string, then the data is expected to be in hms format, otherwise expect decimal degrees. """ if type(self.ra[0]) is str or type(self.ra[0]) is np.string_: raunit = u.hourangle else: raunit = u.deg self.radec = SkyCoord(self.ra,self.dec,unit=(raunit,u.deg)) """ If radec has not been set, report this information (consider raising an exception in future versions of the code) """ if self.radec is None: print '' print 'WARNING: get_radec was called but RA and Dec information was' print ' not found. Please check the format of your catalog.' print '' #---------------------------------------------------------------------- def read_centpos(self, posfile, verbose=False): """ Reads a position in from a file and converts it to an astropy SkyCoord format. NOTE: right now this is hard-wired to just read in a file in the standard Keck starlist format: label rahr ramin rasec decdeg decamin decasec equinox which matches the *.pos in CDF's Lenses/Data/* directories Inputs: posfile - file containing the RA and dec """ """ Read the data from the file """ posinfo = ascii.read(posfile, names=['object', 'rahr', 'ramin', 'rasec', 'decdeg', 'decamin', 'decasec', 'equinox']) """ Convert to SkyCoord format """ i = posinfo[0] ra = '%d:%d:%f' % (i['rahr'], i['ramin'], i['rasec']) dec = '%d:%d:%f' % (i['decdeg'], i['decamin'], i['decasec']) radec = SkyCoord(ra, dec, unit=(u.hourangle, u.deg)) """ Print out information if requested """ if verbose: print('') print('Object: %s' % i['object']) print('Coordinates: %s %s' % \ (radec.ra.to_string(unit=u.hourangle, decimal=False, sep=':', precision=3, pad=True), radec.dec.to_string(decimal=False, sep=':', precision=3, alwayssign=True, pad=True))) """ Save the output within the class """ self.centpos = radec #---------------------------------------------------------------------- def sort_by_pos(self, centpos): """ Sorts the catalog in terms of distance from some central position, which is passed as a SkyCoord variable (from astropy.coordinates) """ """ First check to see that we actual have WCS information """ if self.radec is None: print '' print 'ERROR: sort_by_pos. No WCS information in catalog' print '' return """ Otherwise, use the SkyCoords functionality to easily sort """ sep = self.radec.separation(centpos) try: offsets = self.radec.spherical_offsets_to(centpos) except: offsets = None ind = np.argsort(sep.arcsec) if self.catformat == 'ascii': self.data = self.data[ind,:] else: print self.catformat self.data = self.data[ind] """ Also sort things that are outside the data table """ self.radec = self.radec[ind] self.ra = self.ra[ind] self.dec = self.ra[ind] self.sep = sep[ind] if offsets is None: self.dx = None self.dy = None else: self.dx = (offsets[0].arcsecond)[ind] self.dy = (offsets[1].arcsecond)[ind] self.sortind = ind #----------------------------------------------------------------------- def make_reg_file(self, outfile, rcirc, color='green', fluxcol=None, fluxerrcol=None, labcol=None, labdx=0.0012, labdy=0.0012, plot_high_snr=False, mask=None, snrgood=10.): """ Uses the RA and Dec info in the catalog to make a region file that can be used with ds9. """ """ Start by putting the RA and Dec info into a somewhat more convenient format """ self.get_radec() if self.radec is None: print "" print "ERROR: Could not read RA and Dec information from input file" return """ If the flux information is given, then report on high SNR detections """ ngood = 0 snrmask = None if fluxcol is not None and fluxerrcol is not None: if self.informat == 'ldac': if type(fluxcol) is int: flux = self.data.field(fluxcol) fluxerr = self.data.field(fluxerrcol) else: flux = self.data[fluxcol] fluxerr = self.data[fluxerrcol] else: flux = self.data['f%d' %fluxcol] fluxerr = self.data['f%d' % fluxerrcol] snr = flux / fluxerr snrmask = snr>snrgood """ Mask the input data if requested """ print('Total objects in catalog: %d' % len(self.radec)) if mask is not None: radec = self.radec[mask] selmask = mask print('Objects selected by mask: %d' % len(radec)) else: radec = self.radec selmask = np.ones(len(radec), dtype=bool) ntot = len(radec) radeg = radec.ra.degree decdeg = radec.dec.degree """ Select the high SNR objects, if requested """ if snrmask is not None: selsnrmask = (selmask) & (snrmask) radecgood = self.radec[selsnrmask] ngood = len(radecgood) print 'Of those, objects with SNR>%.1f: %d' % (snrgood,ngood) gradeg = radecgood.ra.degree gdecdeg = radecgood.dec.degree """ Write the output region file """ f = open(outfile,'w') f.write('global color=%s\n' % color) for i in range(ntot): f.write('fk5;circle(%10.6f,%+10.6f,%.1f")\n' % (radeg[i],decdeg[i],rcirc)) if plot_high_snr and ngood>0: f.write('global color=red\n') for i in range(ngood): f.write('fk5;circle(%10.6f,%+10.6f,0.0011)\n' \ %(gradeg[i],gdecdeg[i])) """ Add labels if requested """ if labcol is not None: lab = self.data[labcol][selmask] cosdec = np.cos(pi * self.dec[selmask] / 180.) xx = self.ra[selmask] + labdx * cosdec yy = self.dec[selmask] + labdy f.write('global color=%s\n' % color) for i in range(ntot): f.write('fk5;text(%10.6f,%+10.6f) # text={%s}\n'% \ (xx[i],yy[i],str(lab[i]))) """ Wrap up """ print "Wrote region file %s" % outfile f.close() #----------------------------------------------------------------------- #def plot_radec(self, symb='bo'): #----------------------------------------------------------------------- def plot_fwhm(self, fwhmcol='FWHM_IMAGE', magcol='MAG_AUTO', xlim=(0,15), ylim=(28,16)): """ Plots FWHM vs. magnitude. This can be used to find the stellar locus and, thus, determine the seeing. Inputs: fwhmcol - column name for the FWHM data. Default = 'fwhm_image' magcol - column name for the magnitude data. Default = 'mag_auto' xlim - initial limits for FWHM axis on plot. Default = (0,15) ylim - initial limits for mag axis on plot. Default = (28,16) """ try: fwhm = self.data[fwhmcol] except KeyError: print '' print 'Catalog does not contain a %d column' % fwhmcol print '' return try: mag = self.data[magcol] except KeyError: print '' print 'Catalog does not contain a %d column' % magcol print '' return plt.plot(fwhm,mag,'bo') plt.xlim(xlim) plt.ylim(ylim) plt.xlabel('FWHM (pixels)') plt.ylabel('Magnitude') plt.show() #----------------------------------------------------------------------- def plot_nhist(self, magcol='MAG_AUTO', usestarmask=False, magmin=15, magmax=28, color='b', alpha=1.): """ Plots a histogram of galaxy magnitudes (similar to a log N-log S plot) that can be used to determine the magnitude to which the catalog is complete. A minimum FWHM can be set in order to select objects that are likely to be galaxies, but this is not required. Inputs: magcol - column containing the magnitudes. Default = 'mag_auto' usestarmask - when this parameter is set to True, then use the starmask mask to select the galaxies. NOTE: this means that the set_starmask method has to have been run for each of the input catalogs, or else all objects will be plotted Default=False magmin - minimum magnitude to use for the plot. Default=15 magmax - maximum magnitude to use for the plot. Default=28 """ """ Get the magnitudes to be plotted """ if usestarmask: if self.starmask is None: print('') print('WARNING: you have set usestarmask=True but there are') print(' no stars selected by the starmask') print('Please make sure that set_starmask has been run BEFORE' 'runing plot_nhist') print(' if you want to use this mask') print('') return else: mag = (self.data[self.starmask==False][magcol]).copy() else: mag = self.data[magcol].copy() mag = mag[np.isfinite(mag)] """ Plot the histogram """ nbins = int(2 * (magmax - magmin)) plt.hist(mag,range=(magmin, magmax), bins=nbins, color=color, alpha=alpha) del(mag) #----------------------------------------------------------------------- def match_radec(self, ra2, dec2, rmatch, dra2=0., ddec2=0., doplot=True): """ *** UNDER CONSTRUCTION! DO NOT USE YET. *** Given a list of ra,dec coordinates (ra2, dec2), possibly from a second catalog, and a match tolerance, find the matches to the catalog contained in self.data Inputs: ra2 - RA (decimal degrees) for catalog dec2 - Dec (decimal degrees) for second catalog rmatch - max distance for a valid match (arcsec) dra2 - optional offset in ARCSEC to apply to ra2, if there is a known offset between the catalogs (default=0.0) ddec2 - optional offset in ARCSEC to apply to dec2, if there is a known offset between the catalogs (default=0.0) """ print "" print "Matching catalogs: basic info" print "--------------------------------------------" print " Catalog 1: %d coordinates" % self.ra.size print " Catalog 2: %d coordinates" % ra2.size """ Initialize containers for output information """ ramatch = np.zeros(self.ra.size) decmatch = np.zeros(self.ra.size) self.nmatch = np.zeros(self.ra.size,dtype=int) self.matchdx = np.zeros(self.ra.size) self.matchdy = np.zeros(self.ra.size) self.indmatch = np.ones(self.ra.size,dtype=int) * -1 """ Correct for known shifts """ ra2 = ra2.copy() + dra2/(3600.*np.cos(dec2)) dec2 = dec2.copy() + ddec2/3600. """ Loop over catalog """ print "" print "Searching for matches..." print "------------------------------" for i in range(self.ra.size): dx,dy = coords.sky_to_darcsec(self.ra[i],self.dec[i],ra2,dec2) dpos = np.sqrt(dx**2 + dy**2) isort = np.argsort(dpos) if dpos[isort[0]]<=rmatch: ramatch[i] = self.ra[i] decmatch[i] = self.dec[i] self.matchdx[i] = dx[isort[0]] self.matchdy[i] = dy[isort[0]] self.nmatch[i] = dpos[dpos<=rmatch].size self.indmatch[i] = isort[0] del dx,dy,dpos print " Number of matches between the catalogs: %d" % \ (self.nmatch>0).sum() mra = ramatch[self.nmatch>0] mdec = decmatch[self.nmatch>0] mdx = self.matchdx[self.nmatch>0] mdy = self.matchdy[self.nmatch>0] mdx0 = np.median(mdx) mdy0 = np.median(mdy) print " Median offset for matches (RA): %+6.2f arcsec" % mdx0 print " Median offset for matches (Dec): %+6.2f arcsec" % mdy0 """ Plot up some offsets, if desired """ if doplot: plt.figure(1) plt.scatter(mdx,mdy) plt.axis('scaled') plt.xlabel(r'$\Delta \alpha$ (arcsec)') plt.ylabel(r'$\Delta \delta$ (arcsec)') plt.title('Offsets between matched sources (rmatch = %5.2f)' % rmatch) plt.axvline(0.0,color='r') plt.axhline(0.0,color='r') plt.plot(np.array([mdx0]),np.array([mdy0]),'r*',ms=20) plt.xlim(-1.1*rmatch,1.1*rmatch) plt.ylim(-1.1*rmatch,1.1*rmatch) plt.figure(2) # ax1 = plt.subplot(221) plt.scatter(mra,mdy) plt.setp(ax1.get_xticklabels(), visible=False) plt.ylabel(r'$\Delta \delta$ (arcsec)') plt.axhline(0.0,color='r') # ax2 = plt.subplot(223, sharex=ax1) plt.scatter(mra,mdx) plt.xlabel(r'$\alpha$') plt.ylabel(r'$\Delta \alpha$ (arcsec)') plt.axhline(0.0,color='r') # ax3 = plt.subplot(222, sharey=ax1) plt.scatter(mdec,mdy) plt.axhline(0.0,color='r') plt.setp(ax3.get_xticklabels(), visible=False) plt.setp(ax3.get_yticklabels(), visible=False) # ax4 = plt.subplot(224) plt.scatter(mdec,mdx) plt.xlabel(r'$\delta$') plt.axhline(0.0,color='r') plt.setp(ax4.get_yticklabels(), visible=False) plt.show() """ Clean up """ del ramatch,decmatch del mdx,mdy,mra,mdec #----------------------------------------------------------------------- def print_ccmap(self, outfile, verbose=True): """ Prints out a file that can be used as the input for the pyraf ccmap task. This file has 4 columns: x y RA Dec Inputs: outfile - output file to be used as input for ccmap verbose - print task info """ if verbose: print "" print "Printing to file for use in ccmap: %s" % outfile print "" f = open(outfile,'w') f.write('# (x,y) catalog: %s\n' % self.infile) f.write('# Astrometric catalog: %s\n' % self.matchcat) f.write('# Columns are x y RA Dec\n') for i in range(self.nmatch): f.write('%8.2f %8.2f %11.7f %+11.7f\n' % \ (self.matchx[i],self.matchy[i],self.matchra[i], self.matchdec[i])) f.close() #----------------------------------------------------------------------- def find_closest_xy(self, xast, yast, xcol, ycol): """ Finds the closest match, in (x,y) space to each member of the astrometric catalog (represented by xast,yast). """ self.matchind = np.zeros(xast.size, dtype=int) xfield = 'f%d' % xcol yfield = 'f%d' % ycol for i in range(xast.size): dx = xast[i] - self.data[xfield] dy = yast[i] - self.data[yfield] dpos = dx**2 + dy**2 sindex = np.argsort(dpos) self.matchind[i] = sindex[0] self.matchdx = xast - self.data[xfield][self.matchind] self.matchdy = yast - self.data[yfield][self.matchind] #----------------------------------------------------------------------- def match_xy(self, xa, ya, max_offset=None, xcol=8, ycol=9, verbose=True): """ Find the closest match to each astrometric catalog object and calculate the offsets. Do two loops, to deal with possible confusion of sources on first pass through """ dxmed = 0 dymed = 0 for i in range(2): if verbose: print '' print 'Pass %d' % (i+1) print '------------------------' xa0 = xa - dxmed ya0 = ya - dymed self.find_closest_xy(xa0,ya0,xcol,ycol) dxmed = np.median(self.matchdx) dymed = np.median(self.matchdy) if max_offset is not None: dpos = np.sqrt(self.matchdx**2 + self.matchdy**2) goodmask = dpos<max_offset if verbose: print "Applying a maximum offset cut of %7.1f pixels" % max_offset print "Median shifts before clipping: %7.2f %7.2f" % (dxmed,dymed) else: goodmask = np.ones(xa.size,dtype=bool) dxm = self.matchdx[goodmask] dym = self.matchdy[goodmask] dxmed = np.median(dxm) dymed = np.median(dym) if verbose: print "Median shifts after pass: %7.2f %7.2f" % (dxmed,dymed) """ Transfer information into object and clean up """ if verbose: print '' print 'Found %d astrometric objects within FOV of image' % xa.size print 'Matched %d objects to astrometric catalog.' % dxm.size self.nmatch = dxm.size self.goodmask = goodmask.copy() self.matchind = self.matchind[goodmask] del xa0,ya0,goodmask #----------------------------------------------------------------------- def match_fits_to_ast(self, fitsfile, astcat, outfile=None, max_offset=None, racol=1, deccol=2, xcol=8, ycol=9, doplot=True, edgedist=50., imhdu=0, verbose=True): """ Given the fits file from which this object (self) was defined and an astrometric catalog, find the closest matches of the astrometric objects to those contained in this object, using the WCS information in the fits header. """ if(verbose): print "Running match_fits_to_ast with:" print " fitsfile = %s" % fitsfile print " astcat = %s" % astcat self.infits = fitsfile self.matchcat = astcat """ Start by opening the fits file and reading the appropriate columns from the catalogs """ hdulist = imf.open_fits(fitsfile) hdr = hdulist[imhdu].header if verbose: print "" hdulist.info() """ Select the astrometric catalog objects that fall within the fits file FOV (at least with its current WCS) """ raa,deca,xa,ya,astmask = select_good_ast(astcat,hdr,racol,deccol,edgedist) if verbose: print 'Found %d astrometric objects within FOV of image' % raa.size """ Find the closest match to each astrometric catalog object """ self.match_xy(xa,ya,max_offset,xcol,ycol,verbose) """ Transfer info about matches into the object """ xfield = 'f%d' % xcol yfield = 'f%d' % ycol self.astmask = astmask.copy() self.matchx = self.data[xfield][self.matchind].copy() self.matchy = self.data[yfield][self.matchind].copy() self.matchra = raa[self.goodmask].copy() self.matchdec = deca[self.goodmask].copy() self.matchdx = self.matchdx[self.goodmask] self.matchdy = self.matchdy[self.goodmask] """ Plot the offsets if desired """ if doplot: dxmed = np.median(self.matchdx) dymed = np.median(self.matchdx) plt.figure() plt.scatter(self.matchdx,self.matchdy) plt.xlabel('x offset (pix)') plt.ylabel('y offset (pix)') plt.axhline(color='k') plt.axvline(color='k') plt.axvline(dxmed,color='r') plt.axhline(dymed,color='r') print "" print "Black lines represent x=0 and y=0 axes" print "Red lines show median offsets of dx_med=%7.2f and dy_med=%7.2f" \ % (dxmed,dymed) #plt.show() """ Write the output file, in a format appropriate for input to ccmap """ if outfile is not None: self.print_ccmap(outfile,verbose) """ Clean up """ hdulist.close() del hdr,raa,deca,xa,ya,astmask # ----------------------------------------------------------------------- def set_starmask(self, mask): """ Takes the input mask and assigns it to an internal mask associated with this instance of the Secat class. The internal mask is called starmask and has values of True for objects that have been identified as stars by the provided external mask. The external mask will be based on some characteristics in the catalog. Examples could be objects with a SExtractor CLASS_STAR value greater than 0.7, or a FWHM_IMAGE less than a certain value, or ... """ self.starmask = mask
def match_Stars(fits_file, save_location='./', nobsfile='obsout', standard_stars_file='standard_stars.dat', out_nobsfile='final_obsout', header_line=5, SN_coord=None, dist_treshold = 0.0004, sel_3D=True ): '''- fits_file is the full path of the reference fits file. - save_location is the directory in which the output will be saved. - nobsfile is the full path of the nobsfile. - standard_stars_file is the full path of the standard stars file. - phot_band is the photometric reference band. - index_band is the indec of the band in the standard_stars_file. - offset is an integer which changes the nobsfile line that is used to name the star. e.g, if g is the reference but the band order in nobsfile is u then g the offset should be'1' - header_line is the line number of the header of the standard_stars_file - dist_treshold the match is discarded if the stars are farther apart than this value (degrees) The output is four images showing the matched stars plus 'final_obsout', which is the nobsfile with the star names in place.''' import pyfits hdulist = pyfits.open(fits_file) prihdr = hdulist[0].header phot_band = prihdr['filter1'] index_band = phot_band.lower() print phot_band if SN_coord==None: SN_c = ICRS(prihdr['RA']+prihdr['DEC'], unit = (u.hourangle, u.degree)) SN_coord = [SN_c.ra.degree, SN_c.dec.degree] obsout_file = nobsfile gri_file = standard_stars_file if os.path.isfile(fits_file) == True: w = WCS(fits_file) ## obsout = genfromtxt(obsout_file,dtype=None, missing_values='INDEF') gri = genfromtxt(gri_file,dtype=None, missing_values='INDEF', skip_header=header_line-1,names=True) ## def marker_size_(in_mag): return 20*(nanmax(in_mag)-in_mag)/(nanmax(in_mag)-nanmin(in_mag)) def select_phot_(in_v,phot_out,phot_list): out_v = copy(in_v) for i in range(size(out_v)): if phot_list[i]!=phot_out: out_v[i]=nan return out_v ## figure(figsize=(8,8)) # all_pix2world is from http://docs.astropy.org/en/stable/wcs/ lon, lat =w.all_pix2world(obsout['f4'], obsout['f5'], 0) lon = select_phot_( lon , phot_out=phot_band, phot_list=obsout['f1']) lat = select_phot_( lat , phot_out=phot_band, phot_list=obsout['f1']) scatter(lon,lat,marker='o',s=marker_size_(obsout['f6']) ) scatter(gri['RA'],gri['dec'],color='r',marker='o',s=marker_size_(gri[index_band]) ) plot(SN_coord[0],SN_coord[1],'+g') gca().invert_yaxis() savefig(save_location+'out1.pdf') # # match_to_catalog_sky is from https://www.sites.google.com/site/mrpaulhancock/blog/theage-oldproblemofcross-matchingastronomicalsources indx1 = [i for i in range(size(lon)) if not isnan(lon*lat)[i]] cat1_ra = lon[indx1] cat1_dec = lat[indx1] cat2_ra = gri['RA'] cat2_dec = gri['dec'] cat3_ra = [SN_coord[0]] cat3_dec = [SN_coord[1]] cat1 = ICRS(cat1_ra,cat1_dec,unit = (u.degree,u.degree)) cat2 = ICRS(cat2_ra,cat2_dec,unit = (u.degree,u.degree)) cat3 = ICRS(cat3_ra,cat3_dec,unit = (u.degree,u.degree)) index_list,dist2d,dist3d = cat2.match_to_catalog_sky(cat1) index_list_SN,dist2d_3,dist3d_3 = cat3.match_to_catalog_sky(cat1) indexes_gri = [] indexes_obsout = [] distances=[] for i in range(size(gri)): j = indx1[index_list[i]] cos_dec = cos(lat[j]*pi/(180.)) dist_ = ( sqrt(sum(array([(lon[j] - gri['RA'][i])*cos_dec , lat[j] - gri['dec'][i]])**2)) ) if dist_ < dist_treshold: indexes_gri.append(i) indexes_obsout.append(j) distances.append(dist_) if sel_3D: valuesA_=[] valuesB_=[] for i in indexes_gri: j = indx1[index_list[i]] valuesA_.append(obsout['f6'][j]) valuesB_.append(gri[index_band][i]) valuesA_=array(valuesA_);valuesB_=array(valuesB_) sigma_res = median(abs(valuesA_- valuesB_ - median(valuesA_ - valuesB_))) res_ = abs(valuesA_- valuesB_ - median(valuesA_ - valuesB_)) indexes_gri_new = [] indexes_obsout = [] distances=[] ii=0 for i in indexes_gri: j = indx1[index_list[i]] cos_dec = cos(lat[j]*pi/(180.)) dist_ = ( sqrt(sum(array([(lon[j] - gri['RA'][i])*cos_dec , lat[j] - gri['dec'][i]])**2)) ) if dist_ < dist_treshold: if not sel_3D or res_[ii] < 4.*sigma_res: indexes_gri_new.append(i) indexes_obsout.append(j) distances.append(dist_) ii+=1 indexes_gri = indexes_gri_new indexes_gri_new = [] indexes_obsout = [] distances=[] ii=0 for i in indexes_gri: j = indx1[index_list[i]] cos_dec = cos(lat[j]*pi/(180.)) dist_ = ( sqrt(sum(array([(lon[j] - gri['RA'][i])*cos_dec , lat[j] - gri['dec'][i]])**2)) ) if dist_ < dist_treshold: if not sel_3D or res_[ii] < 3.*sigma_res: indexes_gri_new.append(i) indexes_obsout.append(j) distances.append(dist_) ii+=1 indexes_gri = indexes_gri_new indexes_obsout_SN = nan j = indx1[index_list_SN[0]] cos_dec = cos(lat[j]*pi/(180.)) dist_ = ( sqrt(sum(array([(lon[j] - SN_coord[0])*cos_dec , lat[j] - SN_coord[1]])**2)) ) if dist_ < dist_treshold: #indexes_gri.append(i) indexes_obsout_SN = j figure() hist(distances,1000,label='catalog stars') plot([dist_ ,dist_],[0,1],'g', linewidth=10, label='SN') plot([dist_treshold,dist_treshold],[0,3],':k', label='dist_treshold') xlim((0,0.002)) xlabel('distance (degree)') ylabel('N stars') legend() savefig(save_location+'out2.pdf') # figure(figsize=(8,8)) offset = list(obsout['f1']).index(phot_band) for i in indexes_gri: j = indx1[index_list[i]] obsout[j-offset][0]=gri[i][0] scatter(lon[j],lat[j],marker='o',s=marker_size_(obsout['f6'])[j] ) scatter(gri['RA'][i],gri['dec'][i],color='r',marker='o',s=marker_size_(gri[index_band])[i] ) plot(SN_coord[0],SN_coord[1],'+g') plot([lon[j],gri['RA'][i]],[lat[j],gri['dec'][i]]) if not isnan(indexes_obsout_SN): j=indexes_obsout_SN obsout[j-offset][0] = 'SN' scatter(lon[j],lat[j],marker='o',color='g',s=marker_size_(obsout['f6'])[j] ) gca().invert_yaxis() savefig(save_location+'out3.pdf') # figure() for i in indexes_gri: j = indx1[index_list[i]] plot( obsout['f6'][j],gri[index_band][i],'bo') savefig(save_location+'out4.pdf') ## Save final_obsout f=open(save_location+out_nobsfile,'w+') for j in range(len(obsout)): for k in range(len(obsout[j])): if k <len(obsout[j])-1: f.write(str(obsout[j][k]).replace('nan','INDEF').replace('False','INDEF')) for h in range(13-len(str(obsout[j][k]).replace('nan','INDEF').replace('False','INDEF'))): f.write(' ') else: f.write(str(obsout[j][k]).replace('nan','INDEF').replace('False','INDEF')+'\n') f.close() else: print fits_file + 'not found' return