def _convert_radec_to_altaz(ra, dec, lon, lat, height, time): # Convert supplied UTC date string to a UTC MJD. utc_frame = Ast.TimeFrame('TimeScale=UTC') (nc, utc_epoch) = utc_frame.unformat(1, time) # Convert the UTC MJD to a TDB epoch (i.e. a decimal year). tdb_frame = Ast.TimeFrame('System=JEPOCH,TimeScale=TDB') mapping = utc_frame.convert(tdb_frame) tdb_epoch = mapping.tran(utc_epoch) # Create a Frame describing FK5 coords. Note we need to prefix the # epoch with "J" to indicate that it is a Julian epoch. This is # because values less than 1984.0 are interpreted as Besselian by # default. fk5_frame = Ast.SkyFrame('System=FK5,Epoch=J{0}'.format(tdb_epoch[0][0])) # Create a Frame describing AZEL (aka altaz) coords. azel_frame = Ast.SkyFrame('System=AZEL,Epoch=J{0}'.format(tdb_epoch[0][0])) azel_frame.ObsLon = lon azel_frame.ObsLat = lat azel_frame.ObsAlt = height * 1000.0 # Get the mapping from fk5 to azel. mapping = fk5_frame.convert(azel_frame) # Use it to transform the supplied (ra,dec) values to (az,el) values. coords = mapping.tran([[np.radians(ra)], [np.radians(dec)]]) az = np.degrees(coords[0][0]) el = np.degrees(coords[1][0]) return dict(az=az, alt=el)
def ref_fk4_no_e_fk4(fnout='fk4_no_e_fk4.csv'): """ Accuracy tests for the FK4 (with no E-terms of aberration) to/from FK4 conversion, with arbitrary equinoxes and epoch of observation. """ import starlink.Ast as Ast np.random.seed(12345) N = 200 # Sample uniformly on the unit sphere. These will be either the FK4 # coordinates for the transformation to FK5, or the FK5 coordinates for the # transformation to FK4. ra = np.random.uniform(0., 360., N) dec = np.degrees(np.arcsin(np.random.uniform(-1., 1., N))) # Generate random observation epoch and equinoxes obstime = [f"B{x:7.2f}" for x in np.random.uniform(1950., 2000., N)] ra_fk4ne, dec_fk4ne = [], [] ra_fk4, dec_fk4 = [], [] for i in range(N): # Set up frames for AST frame_fk4ne = Ast.SkyFrame( f'System=FK4-NO-E,Epoch={obstime[i]},Equinox=B1950') frame_fk4 = Ast.SkyFrame( f'System=FK4,Epoch={obstime[i]},Equinox=B1950') # FK4 to FK4 (no E-terms) frameset = frame_fk4.convert(frame_fk4ne) coords = np.degrees( frameset.tran([[np.radians(ra[i])], [np.radians(dec[i])]])) ra_fk4ne.append(coords[0, 0]) dec_fk4ne.append(coords[1, 0]) # FK4 (no E-terms) to FK4 frameset = frame_fk4ne.convert(frame_fk4) coords = np.degrees( frameset.tran([[np.radians(ra[i])], [np.radians(dec[i])]])) ra_fk4.append(coords[0, 0]) dec_fk4.append(coords[1, 0]) # Write out table to a CSV file t = Table() t.add_column(Column(name='obstime', data=obstime)) t.add_column(Column(name='ra_in', data=ra)) t.add_column(Column(name='dec_in', data=dec)) t.add_column(Column(name='ra_fk4ne', data=ra_fk4ne)) t.add_column(Column(name='dec_fk4ne', data=dec_fk4ne)) t.add_column(Column(name='ra_fk4', data=ra_fk4)) t.add_column(Column(name='dec_fk4', data=dec_fk4)) f = open(os.path.join('data', fnout), 'wb') f.write("# This file was generated with the {} script, and the reference " "values were computed using AST\n".format( os.path.basename(__file__))) t.write(f, format='ascii', delimiter=',')
def ref_icrs_fk5(fnout='icrs_fk5.csv'): """ Accuracy tests for the ICRS (with no E-terms of aberration) to/from FK5 conversion, with arbitrary equinoxes and epoch of observation. """ import starlink.Ast as Ast np.random.seed(12345) N = 200 # Sample uniformly on the unit sphere. These will be either the ICRS # coordinates for the transformation to FK5, or the FK5 coordinates for the # transformation to ICRS. ra = np.random.uniform(0., 360., N) dec = np.degrees(np.arcsin(np.random.uniform(-1., 1., N))) # Generate random observation epoch and equinoxes obstime = ["B{0:7.2f}".format(x) for x in np.random.uniform(1950., 2000., N)] equinox_fk5 = ["J{0:7.2f}".format(x) for x in np.random.uniform(1975., 2025., N)] ra_icrs, dec_icrs = [], [] ra_fk5, dec_fk5 = [], [] for i in range(N): # Set up frames for AST frame_icrs = Ast.SkyFrame('System=ICRS,Epoch={epoch}'.format(epoch=obstime[i])) frame_fk5 = Ast.SkyFrame('System=FK5,Epoch={epoch},Equinox={equinox_fk5}'.format(epoch=obstime[i], equinox_fk5=equinox_fk5[i])) # ICRS to FK5 frameset = frame_icrs.convert(frame_fk5) coords = np.degrees(frameset.tran([[np.radians(ra[i])], [np.radians(dec[i])]])) ra_fk5.append(coords[0, 0]) dec_fk5.append(coords[1, 0]) # FK5 to ICRS frameset = frame_fk5.convert(frame_icrs) coords = np.degrees(frameset.tran([[np.radians(ra[i])], [np.radians(dec[i])]])) ra_icrs.append(coords[0, 0]) dec_icrs.append(coords[1, 0]) # Write out table to a CSV file t = Table() t.add_column(Column(name='equinox_fk5', data=equinox_fk5)) t.add_column(Column(name='obstime', data=obstime)) t.add_column(Column(name='ra_in', data=ra)) t.add_column(Column(name='dec_in', data=dec)) t.add_column(Column(name='ra_fk5', data=ra_fk5)) t.add_column(Column(name='dec_fk5', data=dec_fk5)) t.add_column(Column(name='ra_icrs', data=ra_icrs)) t.add_column(Column(name='dec_icrs', data=dec_icrs)) f = open(fnout, 'wb') f.write("# This file was generated with the {0} script, and the reference " "values were computed using AST\n".format(os.path.basename(__file__))) t.write(f, format='ascii', delimiter=',')
def pixtosystem(self, idxs, system=None, coords='data'): if self.coordsys == 'raw': raise WCSError("No usable WCS") if system is None: system = 'icrs' # Get a coordinates object based on ra/dec wcs transform ra_deg, dec_deg = self.pixtoradec(idxs, coords=coords) self.logger.debug("ra, dec = %f, %f" % (ra_deg, dec_deg)) if self.coordsys == 'pixel': # these will actually be x, y pixel values return (ra_deg, dec_deg) # define a transform from reference (icrs/j2000) to user's end choice refframe = self.icrs_trans.getframe(2) toframe = Ast.SkyFrame("System=%s, Epoch=2000.0" % (system.upper())) end_trans = refframe.convert(toframe) # convert to alternate coord ra_rad, dec_rad = math.radians(ra_deg), math.radians(dec_deg) res = end_trans.tran([[ra_rad], [dec_rad]], 1) lon_rad, lat_rad = res[0][0], res[1][0] lon_deg, lat_deg = math.degrees(lon_rad), math.degrees(lat_rad) return lon_deg, lat_deg
def datapt_to_system(self, datapt, system=None, coords='data', naxispath=None): if self.coordsys == 'raw': raise common.WCSError("No usable WCS") if system is None: system = 'icrs' wcspt = self.datapt_to_wcspt(datapt, coords=coords, naxispath=naxispath) if self.coordsys == 'pixel': return wcspt # define a transform from reference (icrs/j2000) to user's end choice refframe = self.icrs_trans.getframe(2) toframe = Ast.SkyFrame("System=%s, Epoch=2000.0" % (system.upper())) end_trans = refframe.convert(toframe) # convert to alternate coord wcspt = np.radians(wcspt) wcspt = end_trans.tran(wcspt.T, 1) wcspt = np.degrees(wcspt) return wcspt.T
def __init__(self, ast_object:Ast.SkyFrame=None, equinox:str=None, system:str=None, epoch:str=None): #if all([naxes, ast_frame]): # raise Exception("The number of axes (naxes) argument cannot be specified with a provided ast_frame.") # TODO: if ast_frame provided, check it is a sky frame (see below) if ast_object and any([equinox, system, epoch]): raise ValueError(f"If 'ast_object' is provided, none of the other parameters ('equinox', 'system', 'epoch') can be specified.") if ast_object: if ast_object.isaskyframe(): super().__init__(ast_object=ast_object) else: raise ValueError(f"The provided 'ast_object' value is not an Ast.SkyFrame (got '{type(ast_object)}').") else: self.astObject = Ast.SkyFrame() if system: if system.upper() in sky_systems: self.system = system else: raise ValueError(f"The provided system must be one of: [{sky_systems}].") if equinox: self.equinox = equinox if epoch: self.epoch = epoch
def load_header(self, header, fobj=None): self.header = {} self.header.update(header.items()) self.fix_bad_headers() source = [] for key, value in header.items(): source.append("%-8.8s= %-70.70s" % (key, repr(value))) # following https://gist.github.com/dsberry/4171277 to get a # usable WCS in Ast try: # read in the header and create the default WCS transform #adapter = Atl.PyFITSAdapter(hdu) #fitschan = Ast.FitsChan(adapter) fitschan = Ast.FitsChan(source) self.wcs = fitschan.read() # self.wcs is a FrameSet, with a Mapping #self.wcs.Report = True self.coordsys = choose_coord_system(self.header) # define a transform from this destination frame to icrs/j2000 refframe = self.wcs.getframe(2) toframe = Ast.SkyFrame("System=ICRS, Equinox=J2000") self.icrs_trans = refframe.convert(toframe) except Exception as e: self.logger.error("Error making WCS object: %s" % (str(e))) self.wcs = None
def __init__(self, equinox:str="2000.0", epoch:str="2000.0") -> ASTSkyFrame: ast_object = Ast.SkyFrame() super().__init__(ast_object=ast_object) self.system = "ICRS" self.equinox = equinox self.epoch = epoch
def get_frame(system): """Convert generic system specification tags to pyast.SkyFrame""" # Create a Frame to describe J2000 FK5 coordinates, and another that # will be used in turn to describe each of the output coordinate systems. # Assume that the epoch of observation is J2000.0. The default values for # the reference equinox will be used (J2000.0 for FK5 and ecliptic, and # B1950.0 for FK4). d = dict() d['fk5'] = 'FK5' d['fk4'] = 'FK4' d['galactic'] = 'Galactic' d['ecliptic'] = 'Ecliptic' d['icrs'] = 'ICRS' return Ast.SkyFrame( 'System=%s,Format(1)=hms.5,Format(2)=dms.5,Epoch=2000.0' % d[system])
# This also becomes the tanflip.fits test file, since pyast writes this # file with # CTYPE1=DEC--TAN # CTYPE2=RA---TAN. # So this provides a test of reading fits files with swapped axes. hdu2.data = hdu.data for key in hdu2.header.keys(): # Remove the QV fields to get a pure TAN type. # (For some reason pyast removes the PV fields, but not QV here.) if 'QV' in key: del hdu2.header[key] hdu2.writeto('tanflip.fits', clobber=True) hdu3 = pyfits.open('test_tpv.fits')[0] fc3 = Ast.FitsChan(Atl.PyFITSAdapter(hdu3)) wcs3 = fc3.read() wcs3 = wcs3.findframe(Ast.SkyFrame()) ra3, dec3 = wcs3.tran(numpy.array([[x], [y]])) print 'ra1 = ', ra1 print 'ra3 = ', ra3 print 'dec1 = ', dec1 print 'dec3 = ', dec3 print 'After write/read round trip through fits file:' print 'error in ra = ', (ra3 - true_ra) * 180. * 3600. / numpy.pi, 'arcsec' print 'error in dec = ', (dec3 - true_dec) * 180. * 3600. / numpy.pi, 'arcsec' # Make a version identical to tanflip.fits, but not actually flipped. hdu4 = pyfits.PrimaryHDU() fc4 = Ast.FitsChan(None, Atl.PyFITSAdapter(hdu4, clear=False), "Encoding=FITS-WCS,FitsAxisOrder=<copy>") fc4.write(wcs3)
https://github.com/timj/starlink-pyast http://dsberry.github.com/starlink/pyast.html """ import numpy as np import starlink.Ast as Ast # Read in initial coordinates as J2000 coordinates data_j2000 = np.radians(np.loadtxt('../initial_coords.txt')) ra_j2000_fk5, dec_j2000_fk5 = data_j2000[:, 0], data_j2000[:, 1] # Create a Frame to describe J2000 FK5 coordinates, and another that # will be used in turn to describe each of the output coordinate systems. # Assume that the epoch of observation is J2000.0. The default values for # the reference equinox will be used (J2000.0 for FK5 and ecliptic, and # B1950.0 for FK4). fk5_frame = Ast.SkyFrame( 'System=FK5,Format(1)=hms.5,Format(2)=dms.5,Epoch=2000.0') out_frame = Ast.SkyFrame('Format(1)=hms.5,Format(2)=dms.5,Epoch=2000.0') # Loop round each output coordinate system, modifying "out_frame" to # describe each one. vals = {} for system in 'FK4', 'Ecliptic', 'Galactic': out_frame.System = system # Get the transformation from FK5 J2000 to the current output system. fk5_to_out = fk5_frame.convert(out_frame) # Transform the FK5 J2000 positions into the curent output system using # the above transformation. vals[system] = fk5_to_out.tran([ra_j2000_fk5, dec_j2000_fk5])
def ref_galactic_fk4(fnout='galactic_fk4.csv'): """ Accuracy tests for the ICRS (with no E-terms of aberration) to/from FK5 conversion, with arbitrary equinoxes and epoch of observation. """ import os import numpy as np import starlink.Ast as Ast from astropy.table import Table, Column np.random.seed(12345) N = 200 # Sample uniformly on the unit sphere. These will be either the ICRS # coordinates for the transformation to FK5, or the FK5 coordinates for the # transformation to ICRS. lon = np.random.uniform(0., 360., N) lat = np.degrees(np.arcsin(np.random.uniform(-1., 1., N))) # Generate random observation epoch and equinoxes obstime = [ "B{0:7.2f}".format(x) for x in np.random.uniform(1950., 2000., N) ] equinox_fk4 = [ "J{0:7.2f}".format(x) for x in np.random.uniform(1975., 2025., N) ] lon_gal, lat_gal = [], [] ra_fk4, dec_fk4 = [], [] for i in range(N): # Set up frames for AST frame_gal = Ast.SkyFrame( 'System=Galactic,Epoch={epoch}'.format(epoch=obstime[i])) frame_fk4 = Ast.SkyFrame( 'System=FK4,Epoch={epoch},Equinox={equinox_fk4}'.format( epoch=obstime[i], equinox_fk4=equinox_fk4[i])) # ICRS to FK5 frameset = frame_gal.convert(frame_fk4) coords = np.degrees( frameset.tran([[np.radians(lon[i])], [np.radians(lat[i])]])) ra_fk4.append(coords[0, 0]) dec_fk4.append(coords[1, 0]) # FK5 to ICRS frameset = frame_fk4.convert(frame_gal) coords = np.degrees( frameset.tran([[np.radians(lon[i])], [np.radians(lat[i])]])) lon_gal.append(coords[0, 0]) lat_gal.append(coords[1, 0]) # Write out table to a CSV file t = Table() t.add_column(Column(name='equinox_fk4', data=equinox_fk4)) t.add_column(Column(name='obstime', data=obstime)) t.add_column(Column(name='lon_in', data=lon)) t.add_column(Column(name='lat_in', data=lat)) t.add_column(Column(name='ra_fk4', data=ra_fk4)) t.add_column(Column(name='dec_fk4', data=dec_fk4)) t.add_column(Column(name='lon_gal', data=lon_gal)) t.add_column(Column(name='lat_gal', data=lat_gal)) f = open(fnout, 'wb') f.write("# This file was generated with the {0} script, and the reference " "values were computed using AST\n".format( os.path.basename(__file__))) t.write(f, format='ascii', delimiter=',')