def visibility_altaz(self, source_radec, site, hardcoded=True): """ To each time grid point associates AltAz coordinates. :param source_radec: source coordinates (astropy SkyCoord object) :param site: (str) :return: """ if not hasattr(self, 'vis_points'): raise AttributeError( 'Must invoke visibility_points() before using this method') if not hardcoded: site_coords = EarthLocation.of_site(site) else: if site.lower() in ('north', 'roque de los muchachos'): #site_coords = EarthLocation.from_geodetic('342.1184', '28.7606', 2326. * u.meter) site_coords = EarthLocation.from_geocentric(5327285.09211954, -1718777.11250295, 3051786.7327476, unit="m") elif site.lower() in ('south', 'paranal'): #site_coords = EarthLocation.from_geodetic('289.5972', '-24.6253', 2635. * u.meter) site_coords = EarthLocation.from_geocentric(1946635.7979987, -5467633.94561753, -2642498.5212285, unit="m") else: raise Warning(f"{site} is not a valid site choice") self.altaz = source_radec.transform_to( AltAz(obstime=self.vis_points, location=site_coords)) return self
def eci2el(x, y, z, dt): """ Convert Earth-Centered Inertial (ECI) cartesian coordinates to ITRS for astropy EarthLocation object. Inputs : x = ECI X-coordinate y = ECI Y-coordinate z = ECI Z-coordinate dt = UTC time (datetime object) """ from astropy.coordinates import GCRS, ITRS, EarthLocation, CartesianRepresentation import astropy.units as u # convert datetime object to astropy time object tt = Time(dt, format='datetime') # Read the coordinates in the Geocentric Celestial Reference System gcrs = GCRS(CartesianRepresentation(x=x, y=y, z=z), obstime=tt) # Convert it to an Earth-fixed frame itrs = gcrs.transform_to(ITRS(obstime=tt)) el = EarthLocation.from_geocentric(itrs.x, itrs.y, itrs.z) return el
def astropy_parallactic_angles(times, antenna_positions, field_centre): """ Computes parallactic angles per timestep for the given reference antenna position and field centre. """ ap = antenna_positions fc = field_centre # Convert from MJD second to MJD times = Time(times / 86400.00, format='mjd', scale='utc') ap = EarthLocation.from_geocentric(ap[:, 0], ap[:, 1], ap[:, 2], unit='m') fc = SkyCoord(ra=fc[0], dec=fc[1], unit=units.rad, frame='fk5') pole = SkyCoord(ra=0, dec=90, unit=units.deg, frame='fk5') cirs_frame = CIRS(obstime=times) pole_cirs = pole.transform_to(cirs_frame) fc_cirs = fc.transform_to(cirs_frame) altaz_frame = AltAz(location=ap[None, :], obstime=times[:, None]) pole_altaz = pole_cirs[:, None].transform_to(altaz_frame) fc_altaz = fc_cirs[:, None].transform_to(altaz_frame) return fc_altaz.position_angle(pole_altaz)
def earth_location_itrf(self, time=None): '''Return RXTE spacecraft location in ITRF coordinates''' if self.tt2tdb_mode.lower().startswith('none'): log.warning('Using location=None for TT to TDB conversion') return None elif self.tt2tdb_mode.lower().startswith('geo'): log.warning('Using location geocenter for TT to TDB conversion') return EarthLocation.from_geocentric(0.0*u.m,0.0*u.m,0.0*u.m) elif self.tt2tdb_mode.lower().startswith('spacecraft'): # First, interpolate ECI geocentric location from orbit file. # These are inertial coorinates aligned with ICRF pos_gcrs = GCRS(CartesianRepresentation(self.X(time.tt.mjd)*u.m, self.Y(time.tt.mjd)*u.m, self.Z(time.tt.mjd)*u.m), obstime=time) # Now transform ECI (GCRS) to ECEF (ITRS) # By default, this uses the WGS84 ellipsoid pos_ITRS = pos_gcrs.transform_to(ITRS(obstime=time)) # Return geocentric ITRS coordinates as an EarthLocation object return pos_ITRS.earth_location else: log.error('Unknown tt2tdb_mode %s, using None', self.tt2tdb_mode) return None
def earth_location_itrf(self, time=None): """Return NICER spacecraft location in ITRF coordinates""" if self.tt2tdb_mode.lower().startswith("pint"): return None elif self.tt2tdb_mode.lower().startswith("geo"): return EarthLocation.from_geocentric(0.0 * u.m, 0.0 * u.m, 0.0 * u.m) elif self.tt2tdb_mode.lower().startswith("astropy"): # First, interpolate ECI geocentric location from orbit file. # These are inertial coorinates aligned with ICRF pos_gcrs = GCRS( CartesianRepresentation( self.X(time.tt.mjd) * u.m, self.Y(time.tt.mjd) * u.m, self.Z(time.tt.mjd) * u.m, ), obstime=time, ) # Now transform ECI (GCRS) to ECEF (ITRS) # By default, this uses the WGS84 ellipsoid pos_ITRS = pos_gcrs.transform_to(ITRS(obstime=time)) # Return geocentric ITRS coordinates as an EarthLocation object return pos_ITRS.earth_location else: log.error("Unknown tt2tdb_mode %s, using None" % self.tt2tdb_mode) return None
def from_itrf(ant_itrf_xyz, ant_labels): """ Instantiate telescope model from ITRF co-ordinates of antennae (aka ECEF-coords, i.e. Earth-Centered-Earth-Fixed reference frame.) Takes care of calculating central Latitude and Longitude from the mean antenna position, and converts the antenna positions into local-XYZ frame. Args: ant_itrf_xyz (numpy.ndarray): Array co-ordinatates in the ITRF frame ant_labels (list[str]): Antennae labels Returns: Telescope: A telescope class with the given array co-ords. """ mean_posn = np.mean(ant_itrf_xyz, axis=0) centre = EarthLocation.from_geocentric(mean_posn[0], mean_posn[1], mean_posn[2], unit=u.m, ) lon, lat, height = centre.to_geodetic() mean_subbed_itrf = ant_itrf_xyz - mean_posn rotation = z_rotation_matrix(lon) ant_local_xyz = np.dot(rotation, mean_subbed_itrf.T).T return Telescope( centre=centre, ant_labels=ant_labels, ant_itrf_xyz=ant_itrf_xyz, ant_local_xyz=ant_local_xyz, )
def get_moon_j2000(epoch, line1, line2, position = None): ''' Code to determine the apparent J2000 position for a given time and at a given position for the observatory. epoch needs to be a datetime or Time object. position is a list/tuple of X/Y/Z positions ''' from astropy.time import Time from astropy.coordinates import get_moon, EarthLocation import astropy.units as u if position is None: position = get_nustar_location(epoch, line1, line2) t = Time(epoch) loc = EarthLocation.from_geocentric(*position * u.km) moon_coords = get_moon(t,loc) # Get just the coordinates in degrees ra_moon, dec_moon = moon_coords.ra.degree * u.deg, moon_coords.dec.degree*u.deg return ra_moon, dec_moon
def load_data(filename): with open(filename) as f: line = f.readline() [x, y, z] = [float(a) for a in line.split()] site = EarthLocation.from_geocentric(x, y, z, unit='meter').to('kilometer') yr, mon, day, hr, min = np.loadtxt(filename, dtype=int, usecols=(0, 1, 2, 3, 4), skiprows=1, unpack=True) sec, ra, de = np.loadtxt(filename, dtype=float, usecols=(5, 6, 7), skiprows=1, unpack=True) angles = np.array([ra, de]) angles = angles.transpose() epochs = [] for i in np.arange(np.size(yr)): s = int(sec[i]) ms = int((sec[i] - s) * 1e6) epoch = Time(datetime(yr[i], mon[i], day[i], hr[i], min[i], s, ms), scale='utc') epochs = np.append(epochs, epoch) return site, epochs, Angle(angles * u.deg)
def __init__(self, name, ft2name, maxextrap=2, overwrite=False): self.FT2 = load_orbit(name, ft2name) # Now build the interpolator. This extrapolation will fail quickly, # which is where maxextrap comes in. tt = self.FT2["MJD_TT"] self.X = InterpolatedUnivariateSpline(tt, self.FT2["X"], ext="extrapolate") self.Y = InterpolatedUnivariateSpline(tt, self.FT2["Y"], ext="extrapolate") self.Z = InterpolatedUnivariateSpline(tt, self.FT2["Z"], ext="extrapolate") self.Vx = InterpolatedUnivariateSpline(tt, self.FT2["Vx"], ext="extrapolate") self.Vy = InterpolatedUnivariateSpline(tt, self.FT2["Vy"], ext="extrapolate") self.Vz = InterpolatedUnivariateSpline(tt, self.FT2["Vz"], ext="extrapolate") self._geocenter = EarthLocation.from_geocentric( 0.0 * u.m, 0.0 * u.m, 0.0 * u.m) self._maxextrap = maxextrap super(SatelliteObs, self).__init__(name=name, overwrite=overwrite)
def earth_location_itrf(self, time=None): '''Return Fermi spacecraft location in ITRF coordinates''' if self.tt2tdb_mode.lower().startswith('none'): log.warning('Using location=None for TT to TDB conversion') return None elif self.tt2tdb_mode.lower().startswith('geo'): log.warning('Using location geocenter for TT to TDB conversion') return EarthLocation.from_geocentric(0.0*u.m,0.0*u.m,0.0*u.m) elif self.tt2tdb_mode.lower().startswith('spacecraft'): # First, interpolate Earth-Centered Inertial (ECI) geocentric # location from orbit file. # These are inertial coordinates aligned with ICRS, called GCRS # <http://docs.astropy.org/en/stable/api/astropy.coordinates.GCRS.html> pos_gcrs = GCRS(CartesianRepresentation(self.X(time.tt.mjd)*u.m, self.Y(time.tt.mjd)*u.m, self.Z(time.tt.mjd)*u.m), obstime=time) # Now transform ECI (GCRS) to ECEF (ITRS) # By default, this uses the WGS84 ellipsoid pos_ITRS = pos_gcrs.transform_to(ITRS(obstime=time)) # Return geocentric ITRS coordinates as an EarthLocation object return pos_ITRS.earth_location else: log.error('Unknown tt2tdb_mode %s, using None', self.tt2tdb_mode) return None
def earth_location_itrf(self, time=None): '''Return POLAR spacecraft location in ITRF coordinates''' if self.tt2tdb_mode.lower().startswith('none'): log.warning('Using location=None for TT to TDB conversion') return None elif self.tt2tdb_mode.lower().startswith('geo'): log.warning('Using location geocenter for TT to TDB conversion') return EarthLocation.from_geocentric(0.0 * u.m, 0.0 * u.m, 0.0 * u.m) elif self.tt2tdb_mode.lower().startswith('spacecraft'): # First, interpolate Earth-Centered Inertial (ECI) geocentric # location from orbit file. # These are inertial coordinates aligned with ICRS, called GCRS # <http://docs.astropy.org/en/stable/api/astropy.coordinates.GCRS.html> pos_gcrs = GCRS(CartesianRepresentation( self.X(time.utc.unix) * u.m, self.Y(time.utc.unix) * u.m, self.Z(time.utc.unix) * u.m), obstime=time) # Now transform ECI (GCRS) to ECEF (ITRS) # By default, this uses the WGS84 ellipsoid pos_ITRS = pos_gcrs.transform_to(ITRS(obstime=time)) # Return geocentric ITRS coordinates as an EarthLocation object return pos_ITRS.earth_location else: log.error('Unknown tt2tdb_mode %s, using None', self.tt2tdb_mode) return None
def eci2el(x,y,z,dt): """ Convert Earth-Centered Inertial (ECI) cartesian coordinates to ITRS for astropy EarthLocation object. Inputs : x = ECI X-coordinate y = ECI Y-coordinate z = ECI Z-coordinate dt = UTC time (datetime object) """ from astropy.coordinates import GCRS, ITRS, EarthLocation, CartesianRepresentation import astropy.units as u # convert datetime object to astropy time object tt=Time(dt,format='datetime') # Read the coordinates in the Geocentric Celestial Reference System gcrs = GCRS(CartesianRepresentation(x=x, y=y,z=z), obstime=tt) # Convert it to an Earth-fixed frame itrs = gcrs.transform_to(ITRS(obstime=tt)) el = EarthLocation.from_geocentric(itrs.x, itrs.y, itrs.z) return el
def eci2lla(x, y, z, dt): """ Convert Earth-Centered Inertial (ECI) cartesian coordinates to latitude, longitude, and altitude, using astropy. Inputs : x = ECI X-coordinate (m) y = ECI Y-coordinate (m) z = ECI Z-coordinate (m) dt = UTC time (datetime object) Outputs : lon = longitude (radians) lat = geodetic latitude (radians) alt = height above WGS84 ellipsoid (m) """ # convert datetime object to astropy time object tt = Time(dt, format='datetime') # Read the coordinates in the Geocentric Celestial Reference System gcrs = GCRS(CartesianRepresentation(x=x * u.m, y=y * u.m, z=z * u.m), obstime=tt) # Convert it to an Earth-fixed frame itrs = gcrs.transform_to(ITRS(obstime=tt)) el = EarthLocation.from_geocentric(itrs.x, itrs.y, itrs.z) # conversion to geodetic lon, lat, alt = el.to_geodetic() # lon_val = lon.value return lon.value, lat.value, alt.value
def get_location(self): arrayHDU = self.get_arrayHDU() header = arrayHDU.header xyz = [header.get('ARRAY' + var, 0) for var in ['X', 'Y', 'Z']] loc = EarthLocation.from_geocentric(*xyz, unit="m") return loc
def set_beam_target(self, target_or_ra, dec=None, load_time=None, verbose=True): """ Given the name of an astronomical target, 'sun', or 'zenith', compute the current topocentric position of the body and point the beam at it. If the 'dec' keyword is not None, the target is intepreted to be a RA. """ # Force to string target_or_ra = str(target_or_ra) if dec is not None: dec = str(dec) # Figure out what to do with the name if target_or_ra.lower() in ('z', 'zen', 'zenith'): ## Zenith is easy az, alt = 0.0, 90.0 else: ## Load in where we are obs = EarthLocation.from_geocentric(*self.station.ecef, unit=u.m) ## Resolve the name into coordinates if dec is not None: ra = Angle(target_or_ra, unit='hourangle') dec = Angle(dec, unit='deg') sc = SkyCoord(ra, dec, frame='fk5') if verbose: print( f"Resolved '{target_or_ra}, {dec}' to RA {sc.ra}, Dec. {sc.dec}" ) elif target_or_ra.lower() in solar_system_ephemeris.bodies: if target_or_ra.lower().startswith('earth'): raise ValueError(f"Invalid target: '{target_or_ra}'") sc = get_body(target_or_ra.lower(), Time.now(), location=obs) if verbose: print( f"Resolved '{target_or_ra}' to {target_or_ra.lower()}") else: sc = SkyCoord.from_name(target_or_ra) if verbose: print( f"Resolved '{target_or_ra}' to RA {sc.ra}, Dec. {sc.dec}" ) ## Figure out where it is right now aa = sc.transform_to(AltAz(obstime=Time.now(), location=obs)) az = aa.az.deg alt = aa.alt.deg if verbose: print(f"Currently at azimuth {aa.az}, altitude {aa.alt}") # Point the beam self.set_beam_pointing(az, alt, degrees=True, load_time=load_time)
def __init__(self, name, tempo_code=None, itoa_code=None, aliases=None, itrf_xyz=None, clock_file='time.dat', clock_dir='PINT', clock_fmt='tempo', include_gps=True, include_bipm=True, bipm_version='BIPM2015'): # ITRF coordinates are required if itrf_xyz is None: raise ValueError( "ITRF coordinates not given for observatory '%s'" % name) # Convert coords to standard format. If no units are given, assume # meters. if not has_astropy_unit(itrf_xyz): xyz = numpy.array(itrf_xyz) * u.m else: xyz = itrf_xyz.to(u.m) # Check for correct array dims if xyz.shape != (3,): raise ValueError( "Incorrect coordinate dimensions for observatory '%s'" % ( name)) # Convert to astropy EarthLocation, ensuring use of ITRF geocentric coordinates self._loc_itrf = EarthLocation.from_geocentric(*xyz) # Save clock file info, the data will be read only if clock # corrections for this site are requested. self.clock_file = clock_file self._multiple_clock_files = not isinstance(clock_file,str) self.clock_dir = clock_dir self.clock_fmt = clock_fmt self._clock = None # The ClockFile object, will be read on demand # If using TEMPO time.dat we need to know the 1-char tempo-style # observatory code. if (clock_dir=='TEMPO' and clock_file=='time.dat' and tempo_code is None): raise ValueError("No tempo_code set for observatory '%s'" % name) # GPS corrections self.include_gps = include_gps self._gps_clock = None # BIPM corrections self.include_bipm = include_bipm self.bipm_version = bipm_version self._bipm_clock = None self.tempo_code = tempo_code if aliases is None: aliases = [] for code in (tempo_code, itoa_code): if code is not None: aliases.append(code) super(TopoObs,self).__init__(name,aliases=aliases, tt2tdb_mode='astropy')
def ecef_to_lla(r: np.ndarray) -> List: """ Converts coordinate in ECEF frame to Lat and Lon :param r: Position in ECEF frame. Numpy array Units [km] """ loc = EarthLocation.from_geocentric(r[0] * u.km, r[1] * u.km, r[2] * u.km) lat = loc.geodetic.lat lon = loc.geodetic.lon alt = loc.geodetic.height lla = [lat, lon, alt] return lla
def test_gaussbeam_values(): """ Make the long-line point sources up to 10 degrees from zenith. Obtain visibilities Confirm that the values match the expected beam values at those zenith angles. """ sigma = 0.05 hera_uv = UVData() hera_uv.read_uvfits(EW_uvfits_file) array_location = EarthLocation.from_geocentric( hera_uv.telescope_location[0], hera_uv.telescope_location[1], hera_uv.telescope_location[2], unit='m') freq = hera_uv.freq_array[0, 0] * units.Hz time = Time(hera_uv.time_array[0], scale='utc', format='jd') catalog, mock_keywords = pyuvsim.create_mock_catalog( time=time, arrangement='long-line', Nsrcs=41, max_za=10., array_location=array_location) beam = pyuvsim.AnalyticBeam('gaussian', sigma=sigma) array = pyuvsim.Telescope('telescope_name', array_location, [beam]) # Need a dummy baseline for this test. antenna1 = pyuvsim.Antenna('ant1', 1, np.array([0, 0, 0]), 0) antenna2 = pyuvsim.Antenna('ant2', 2, np.array([107, 0, 0]), 0) baseline = pyuvsim.Baseline(antenna1, antenna2) coherencies = [] zenith_angles = [] for src in catalog: task = pyuvsim.UVTask(src, time, freq, baseline, array) engine = pyuvsim.UVEngine(task) engine.apply_beam() # task.source.az_za_calc(time, array_location) zenith_angles.append(task.source.az_za[1]) # In radians. coherencies.append( np.real(engine.apparent_coherency[0, 0]).astype( float)) # All four components should be identical coherencies = np.array(coherencies) zenith_angles = np.array(zenith_angles) # Confirm the coherency values (ie., brightnesses) match the beam values. beam_values = np.exp(-(zenith_angles)**2 / (2 * beam.sigma**2)) nt.assert_true(np.all(beam_values**2 == coherencies))
def test_gaussbeam_values(): """ Make the long-line point sources up to 10 degrees from zenith. Confirm that the coherencies match the expected beam values at those zenith angles. """ sigma = 0.05 hera_uv = UVData() hera_uv.read_uvfits(EW_uvfits_file) array_location = EarthLocation.from_geocentric(*hera_uv.telescope_location, unit='m') freq = hera_uv.freq_array[0, 0] * units.Hz time = Time(hera_uv.time_array[0], scale='utc', format='jd') catalog, mock_keywords = pyuvsim.create_mock_catalog( time=time, arrangement='long-line', Nsrcs=41, min_alt=80., array_location=array_location) catalog.update_positions(time, array_location) beam = pyuvsim.AnalyticBeam('gaussian', sigma=sigma) array = pyuvsim.Telescope('telescope_name', array_location, [beam]) # Need a dummy baseline for this test. antenna1 = pyuvsim.Antenna('ant1', 1, np.array([0, 0, 0]), 0) antenna2 = pyuvsim.Antenna('ant2', 2, np.array([107, 0, 0]), 0) baseline = pyuvsim.Baseline(antenna1, antenna2) task = pyuvsim.UVTask(catalog, time, freq, baseline, array) engine = pyuvsim.UVEngine(task) engine.apply_beam() altitudes = task.sources.alt_az[0] # In radians. # All four components should be identical if isinstance(engine.apparent_coherency, units.Quantity): coherency_use = engine.apparent_coherency.to_value("Jy") else: coherency_use = engine.apparent_coherency coherencies = np.real(coherency_use[0, 0] + coherency_use[1, 1]).astype(float) zenith_angles, _ = simutils.altaz_to_zenithangle_azimuth( altitudes, np.zeros_like(np.array(altitudes))) # Confirm the coherency values (ie., brightnesses) match the beam values. beam_values = np.exp(-(zenith_angles)**2 / (2 * beam.sigma**2)) assert np.all(beam_values**2 == coherencies)
def __init__(self, name, ft2name): self.FT2 = load_orbit(name, ft2name) # Now build the interpolator here: tt = self.FT2["MJD_TT"] self.X = InterpolatedUnivariateSpline(tt, self.FT2["X"], ext="raise") self.Y = InterpolatedUnivariateSpline(tt, self.FT2["Y"], ext="raise") self.Z = InterpolatedUnivariateSpline(tt, self.FT2["Z"], ext="raise") self.Vx = InterpolatedUnivariateSpline(tt, self.FT2["Vx"], ext="raise") self.Vy = InterpolatedUnivariateSpline(tt, self.FT2["Vy"], ext="raise") self.Vz = InterpolatedUnivariateSpline(tt, self.FT2["Vz"], ext="raise") self._geocenter = EarthLocation.from_geocentric(0.0 * u.m, 0.0 * u.m, 0.0 * u.m) super(SatelliteObs, self).__init__(name=name)
def to_location(self): """Calculate the observatory location. Uses FITS standard ``OBSGEO-`` headers. Returns ------- location : `astropy.coordinates.EarthLocation` An object representing the location of the telescope. """ cards = [f"OBSGEO-{c}" for c in ("X", "Y", "Z")] coords = [self._header[c] for c in cards] value = EarthLocation.from_geocentric(*coords, unit=u.m) self._used_these_cards(*cards) return value
def test_single_zenith_source_uvdata(): """Test single zenith source using test uvdata file.""" hera_uv = UVData() hera_uv.read_uvfits(EW_uvfits_file) time = Time(hera_uv.time_array[0], scale='utc', format='jd') array_location = EarthLocation.from_geocentric( hera_uv.telescope_location[0], hera_uv.telescope_location[1], hera_uv.telescope_location[2], unit='m') freq = hera_uv.freq_array[0, 0] * units.Hz # get antennas positions into ENU antpos = hera_uv.antenna_positions[0:2, :] + hera_uv.telescope_location antpos = uvutils.ENU_from_ECEF(antpos.T, *hera_uv.telescope_location_lat_lon_alt).T antenna1 = pyuvsim.Antenna('ant1', 1, np.array(antpos[0, :]), 0) antenna2 = pyuvsim.Antenna('ant2', 2, np.array(antpos[1, :]), 0) # setup the things that don't come from pyuvdata: # make a source at zenith time.location = array_location source = create_zenith_source(time, 'zensrc') beam = UVBeam() beam.read_cst_beam(beam_files, beam_type='efield', frequency=[100e6, 123e6], telescope_name='HERA', feed_name='PAPER', feed_version='0.1', feed_pol=['x'], model_name='E-field pattern - Rigging height 4.9m', model_version='1.0') beam_list = [beam] baseline = pyuvsim.Baseline(antenna1, antenna2) array = pyuvsim.Telescope('telescope_name', array_location, beam_list) task = pyuvsim.UVTask(source, time, freq, baseline, array) engine = pyuvsim.UVEngine(task) visibility = engine.make_visibility() nt.assert_true(np.allclose(visibility, np.array([.5, .5, 0, 0]), atol=5e-3))
def get_PP_PD(sp, directions, times, hIon, ncpu): ''' This is a wrapper function to parallelize get_PP_PD_per_source() and unpack the return. Get the Pierce Points and the Pierce Directions for <l> directions, <m> stations and <n> timestamps. Parameters ---------- sp : (m, 3) ndarray Station positions in meters ITRS XYZ directions : (l,2) ndarray Source directions RA and DEC in degree times : (n,) ndarray Array containing timestamps in mjd seconds. hIon : float, Ionosphere height in m ncpu : int, Returns ------- PP : (n,m,l,3) ndarray Pierce points in geocentric ITRS. Unit: meter The (n,m,l3) shape corresponds to (timestamp, station, direction, xyz). PD : (n,l,3) ndarray Pierce direction unit verctors in geocentric ITRS. The directions are oriented such that the point from the source towards earth. The (n,l,3) shape corresponds to (timestamp, direction, xyz). Since the coord sys is geocentric and not horizontal, the source directions are the same for every station. ''' sp = EarthLocation.from_geocentric(x=sp[:, 0], y=sp[:, 1], z=sp[:, 2], unit='meter') itrs = ITRS(obstime=Time(times / (3600 * 24), format='mjd')) map_args = [(sp, d, itrs, hIon) for d in directions] pool = mp.Pool(processes=ncpu) PP_PD = pool.map(get_PP_PD_per_source, map_args) pool.close() # w/o close+join: OSError: [Errno 12] Cannot allocate memory pool.join() # PP shaped as (timestamp, station, sources, xyz) PP = np.array([u for (u, v) in PP_PD]).swapaxes(0, 1).swapaxes(1, 2) # PD shaped as (timestamp, source, xyz) PD = np.array([v for (u, v) in PP_PD]).swapaxes(0, 1) return PP, PD
def search_code_mpc(): """ Reads the MPC Observer Database Returns: observatories (dict): A python dictionaty with all the sites as an Astropy EarthLocation object """ obs = MPC.get_observatory_codes() observatories = {} for line in obs: code = line['Code'] lon = line['Longitude'] * u.deg rcphi = line['cos'] * 6378.137 * u.km rsphi = line['sin'] * 6378.137 * u.km name = line['Name'] site = EarthLocation.from_geocentric(rcphi * np.cos(lon), rcphi * np.sin(lon), rsphi) observatories[code] = (name, site) return observatories
def _gettec(altaz_args): alltec = [] altaz, stationpositions, A12, times, tidAmp, tidLen, tidVel = altaz_args direction = altaz.geocentrictrueecliptic.cartesian.xyz.value for ant in stationpositions: pp, am = post.getPPsimple([200.e3] * direction[0].shape[0], ant, direction) ppa = EarthLocation.from_geocentric(pp[:, 0], pp[:, 1], pp[:, 2], unit=u.m) ppaproj = EarthLocation.from_geodetic(-ppa.lon.deg + A12.lon.deg, -ppa.lat.deg + A12.lat.deg, ppa.height) x = ppaproj.z.value y = ppaproj.y.value tec = _tid(x, times * 3600. * 24, tidAmp, tidLen, tidVel) alltec.append([tec, x, y, altaz.secz]) return alltec
def ECEF2lla(x, y, z): #This function takes a position in ECEF and converts to geodetic position #(lon,lat,alt above ellipsiod) # # Input # x = Position in ECEF (m) # y = Position in ECEF (m) # z = Position in ECEF (m) # Output # lon = geodetic latitude (WGS-84) # lat = geodetic latitude (WGS-84) # alt = altitude above ellipsoid (m) #FIXME: check if obstime is needed el = EarthLocation.from_geocentric(x, y, z, unit=units.m) geo = el.to_geodetic() lat = geo[1] lon = geo[0] alt = geo[2] return lat, lon, alt
def ITRS_to_geodetic(x, y, z, radians=False, ellipsoid=None): '''Use `astropy.coordinates.EarthLocation` to transform from geodetic to ITRS. ''' cord = EarthLocation.from_geocentric( x=x * units.m, y=y * units.m, z=z * units.m, ) lon, lat, height = cord.to_geodetic(ellipsoid=ellipsoid) llh = np.empty((3, ), dtype=np.float64) if radians: u_ = units.rad else: u_ = units.deg llh[0] = lat.to(u_).value llh[1] = lon.to(u_).value llh[2] = height.to(units.m).value return llh
def from_tree(cls, node, ctx): if isinstance(node, (str, list, np.ndarray)): t = time.Time(node) fmt = _astropy_format_to_asdf_format.get(t.format, t.format) if fmt not in _guessable_formats: raise ValueError(f"Invalid time '{node}'") return t value = node['value'] fmt = node.get('format') scale = node.get('scale') location = node.get('location') if location is not None: unit = location.get('unit', u.m) # This ensures that we can read the v.1.0.0 schema and convert it # to the new EarthLocation object, which expects Quantity components for comp in ['x', 'y', 'z']: if not isinstance(location[comp], Quantity): location[comp] = Quantity(location[comp], unit=unit) location = EarthLocation.from_geocentric( location['x'], location['y'], location['z']) return time.Time(value, format=fmt, scale=scale, location=location)
def get_time_frame(self, element): #ref_location = self.table_mapper.search_instance_by_role("coords:StdRefLocation.position", # root_element=ele)[0]['@value'] #print(ref_location) frame_instance = self.table_mapper.search_instance_by_type("coords:TimeFrame", root_element=element)[0] ref_position_block = frame_instance["coords:TimeFrame.refPosition"] ref_scale = self.table_mapper.search_instance_by_role( "coords:StdRefLocation.position", root_element=ref_position_block)[0]['@value'].upper() ref_location_block = frame_instance["coords:TimeFrame.refLocation"] ref_location = self.table_mapper.search_instance_by_role( "coords:StdRefLocation.position", root_element=ref_location_block)[0]['@value'].upper() if ref_scale == "BARYCENTER": ref_scale = "tcb" if ref_location == "GEOCENTRIC": ref_location = EarthLocation.from_geocentric(0,0,0, 'm') astrotime = Time(50000., scale=ref_scale, format='mjd', location=ref_location) return astrotime.scale, astrotime.location, astrotime.format
def from_tree(cls, node, ctx): if isinstance(node, (str, list, np.ndarray)): t = time.Time(node) format = _astropy_format_to_asdf_format.get(t.format, t.format) if format not in _guessable_formats: raise ValueError("Invalid time '{0}'".format(node)) return t value = node['value'] format = node.get('format') scale = node.get('scale') location = node.get('location') if location is not None: unit = location.get('unit', u.m) # This ensures that we can read the v.1.0.0 schema and convert it # to the new EarthLocation object, which expects Quantity components for comp in ['x', 'y', 'z']: if not isinstance(location[comp], Quantity): location[comp] = Quantity(location[comp], unit=unit) location = EarthLocation.from_geocentric( location['x'], location['y'], location['z']) return time.Time(value, format=format, scale=scale, location=location)
def itrs2horizon(station, ts, ts_quasi_mjd, positions, coord_type): ''' Convert cartesian coordinates of targets in ITRF to spherical coordinates in topocentric reference frame for a specific station. Usage: az,alt,r = itrs2horizon(station,ts,ts_quasi_mjd,positions,coord_type) Inputs: station -> [numercial array or list with 3 elements] coordinates of station. It can either be geocentric(x, y, z) coordinates or geodetic(lon, lat, height) coordinates. Unit for (x, y, z) are meter, and for (lon, lat, height) are degree and meter. ts -> [str array] iso-formatted UTC for interpolated prediction ts_quasi_mjd -> [float array] quasi MJD for interpolated prediction positions -> [2d float array] target positions in cartesian coordinates in meters w.r.t. ITRF for interpolated prediction. coord_type -> [str] coordinates type for coordinates of station; it can either be 'geocentric' or 'geodetic'. Outputs: az -> [float array] Azimuth for interpolated prediction in degrees alt -> [float array] Altitude for interpolated prediction in degrees r -> [float array] Range for interpolated prediction in meters ''' if coord_type == 'geocentric': x, y, z = station site = EarthLocation.from_geocentric(x, y, z, unit='m') elif coord_type == 'geodetic': lat, lon, height = station site = EarthLocation.from_geodetic(lon, lat, height) coords = SkyCoord(positions, unit='m', representation_type='cartesian', frame='itrs', obstime=Time(ts)) horizon = coords.transform_to(AltAz(obstime=Time(ts), location=site)) az, alt, r = horizon.az.deg, horizon.alt.deg, horizon.distance.m return az, alt, r
def from_itrf(ant_itrf_xyz, ant_labels): """ Instantiate telescope model from ITRF co-ordinates of antennae (aka ECEF-coords, i.e. Earth-Centered-Earth-Fixed reference frame.) Takes care of calculating central Latitude and Longitude from the mean antenna position, and converts the antenna positions into local-XYZ frame. Args: ant_itrf_xyz (numpy.ndarray): Array co-ordinatates in the ITRF frame ant_labels (list[str]): Antennae labels Returns: Telescope: A telescope class with the given array co-ords. """ mean_posn = np.mean(ant_itrf_xyz, axis=0) centre = EarthLocation.from_geocentric( mean_posn[0], mean_posn[1], mean_posn[2], unit=u.m, ) lon, lat, height = centre.to_geodetic() mean_subbed_itrf = ant_itrf_xyz - mean_posn rotation = z_rotation_matrix(lon) ant_local_xyz = np.dot(rotation, mean_subbed_itrf.T).T return Telescope( centre=centre, ant_labels=ant_labels, ant_itrf_xyz=ant_itrf_xyz, ant_local_xyz=ant_local_xyz, )
def archive_TO_elev_start_end(archive): """ Fonction to give elevation in the first and last subintegration EarthLocation is set for Nancay Input: archives : list of PSRCHIVE archive objects Output float(elev0),float(elevlast) """ try: x, y, z = archive.get_ant_xyz() except: print('warning: archive.get_ant_xyz() faild will used nancay location') x = 4324016.70769 y = 165545.525467 z = 4670271.363 Site = EarthLocation.from_geocentric(x=float(x) * u.m, y=float(y) * u.m, z=float(z) * u.m) ra = archive.get_coordinates().ra().getDegrees() dec = archive.get_coordinates().dec().getDegrees() c = SkyCoord(ra=ra * u.degree, dec=dec * u.degree) MJD0 = archive.get_Integration(0).get_epoch().in_days() MJDlast = archive.get_Integration(int(archive.get_nsubint()) - int(1)).get_epoch().in_days() MJD0 = Time(MJD0, format='mjd') MJDlast = Time(MJDlast, format='mjd') elev0 = c.transform_to(AltAz(obstime=MJD0, location=Site)) elevlast = c.transform_to(AltAz(obstime=MJDlast, location=Site)) return elev0.alt.degree, elevlast.alt.degree
def earth_location_itrf(self, time=None): '''Return NICER spacecraft location in ITRF coordinates''' if self.tt2tdb_mode.lower().startswith('none'): return None elif self.tt2tdb_mode.lower().startswith('geo'): return EarthLocation.from_geocentric(0.0*u.m,0.0*u.m,0.0*u.m) elif self.tt2tdb_mode.lower().startswith('spacecraft'): # First, interpolate ECI geocentric location from orbit file. # These are inertial coorinates aligned with ICRF pos_gcrs = GCRS(CartesianRepresentation(self.X(time.tt.mjd)*u.m, self.Y(time.tt.mjd)*u.m, self.Z(time.tt.mjd)*u.m), obstime=time) # Now transform ECI (GCRS) to ECEF (ITRS) # By default, this uses the WGS84 ellipsoid pos_ITRS = pos_gcrs.transform_to(ITRS(obstime=time)) # Return geocentric ITRS coordinates as an EarthLocation object return pos_ITRS.earth_location else: log.error('Unknown tt2tdb_mode %s, using None', self.tt2tdb_mode) return None
def hx_aer_astropy(x_gcrs, time, observer_lla=None, trans_matrix=None, observer_itrs=None): """ desc: measurement function - convert state into a measurement where measurements are [azimuth, elevation] :param x_gcrs: :param time: :param observer_lla: :param trans_matrix: :param observer_itrs: Observer coordinates in itrs (meters) :return: array[azimuth, elevation, slant] """ object = SkyCoord(x=x_gcrs[0] * u.m, y=x_gcrs[1] * u.m, z=x_gcrs[2] * u.m, frame='gcrs', representation_type='cartesian', obstime=time) if observer_itrs is None: obs = EarthLocation.from_geodetic(lat=observer_lla[0] * u.rad, lon=observer_lla[1] * u.rad, height=observer_lla[2] * u.m) else: obs = EarthLocation.from_geocentric(x=observer_itrs[0] * u.m, y=observer_itrs[1] * u.m, z=observer_itrs[2] * u.m) AltAz_frame = AltAz(obstime=time, location=obs) results = object.transform_to(AltAz_frame) az = results.az.to_value(u.rad) alt = results.alt.to_value(u.rad) sr = results.distance.to_value(u.m) aer = np.array([az, alt, sr]) return aer
def earth_location(self): return EarthLocation.from_geocentric(0.0,0.0,0.0,unit=u.m)
def earth_location_itrf(self, time=None): return EarthLocation.from_geocentric(0.0,0.0,0.0,unit=u.m)
def __init__(self, name, tempo_code=None, itoa_code=None, aliases=None, itrf_xyz=None, clock_file='time.dat', clock_dir='PINT', clock_fmt='tempo', include_gps=True, include_bipm=True, bipm_version='BIPM2015'): """ Required arguments: name = The name of the observatory itrf_xyz = IRTF site coordinates (len-3 array). Can include astropy units. If no units are given, meters are assumed. Optional arguments: tempo_code = 1-character tempo code for the site. Will be automatically added to aliases. Note, this is REQUIRED only if using TEMPO time.dat clock file. itoa_code = 2-character ITOA code. Will be added to aliases. aliases = List of other aliases for the observatory name. clock_file = Name of the clock correction file. Default='time.dat' clock_dir = Location of the clock file. Special values 'TEMPO', 'TEMPO2', or 'PINT' mean to use the standard directory for the package. Otherwise can be set to a full path to the directory containing the clock_file. Default='TEMPO' clock_fmt = Format of clock file (see ClockFile class for allowed values). Default='tempo' include_gps = Set False to disable UTC(GPS)->UTC clock correction. include_bipm= Set False to disable UTC-> TT BIPM clock correction. If False, it only apply TAI->TT correction TT = TAI+32.184s, the same as TEMPO2 TT(TAI) in the parfile. If Ture, it will apply the correction from BIPM TT=TT(BIPMYYYY). See the link: http://www.bipm.org/en/bipm-services/timescales/time-ftp/ttbipm.html bipm_version= Set the version of TT BIPM clock correction file to use, the default is BIPM2015. It has to be in the format like 'BIPM2015' """ # ITRF coordinates are required if itrf_xyz is None: raise ValueError( "ITRF coordinates not given for observatory '%s'" % name) # Convert coords to standard format. If no units are given, assume # meters. if not has_astropy_unit(itrf_xyz): xyz = numpy.array(itrf_xyz) * u.m else: xyz = itrf_xyz.to(u.m) # Check for correct array dims if xyz.shape != (3,): raise ValueError( "Incorrect coordinate dimensions for observatory '%s'" % ( name)) # Convert to astropy EarthLocation, ensuring use of ITRF geocentric coordinates self._loc_itrf = EarthLocation.from_geocentric(*xyz) # Save clock file info, the data will be read only if clock # corrections for this site are requested. self.clock_file = clock_file self.clock_dir = clock_dir self.clock_fmt = clock_fmt self._clock = None # The ClockFile object, will be read on demand # If using TEMPO time.dat we need to know the 1-char tempo-style # observatory code. if (clock_dir=='TEMPO' and clock_file=='time.dat' and tempo_code is None): raise ValueError("No tempo_code set for observatory '%s'" % name) # GPS corrections not implemented yet self.include_gps = include_gps self._gps_clock = None # BIPM corrections not implemented yet self.include_bipm = include_bipm self.bipm_version = bipm_version self._bipm_clock = None self.tempo_code = tempo_code if aliases is None: aliases = [] for code in (tempo_code, itoa_code): if code is not None: aliases.append(code) super(TopoObs,self).__init__(name,aliases=aliases)
def _verify_global_info(global_info): """ Given the global time reference frame information, verify that each global time coordinate attribute will be given a valid value. Parameters ---------- global_info : dict Global time reference frame information. """ # Translate FITS deprecated scale into astropy scale, or else just convert # to lower case for further checks. global_info['scale'] = FITS_DEPRECATED_SCALES.get(global_info['TIMESYS'], global_info['TIMESYS'].lower()) # Verify global time scale if global_info['scale'] not in Time.SCALES: # 'GPS' and 'LOCAL' are FITS recognized time scale values # but are not supported by astropy. if global_info['scale'] == 'gps': warnings.warn( 'Global time scale (TIMESYS) has a FITS recognized time scale ' 'value "GPS". In Astropy, "GPS" is a time from epoch format ' 'which runs synchronously with TAI; GPS is approximately 19 s ' 'ahead of TAI. Hence, this format will be used.', AstropyUserWarning) # Assume that the values are in GPS format global_info['scale'] = 'tai' global_info['format'] = 'gps' if global_info['scale'] == 'local': warnings.warn( 'Global time scale (TIMESYS) has a FITS recognized time scale ' 'value "LOCAL". However, the standard states that "LOCAL" should be ' 'tied to one of the existing scales because it is intrinsically ' 'unreliable and/or ill-defined. Astropy will thus use the default ' 'global time scale "UTC" instead of "LOCAL".', AstropyUserWarning) # Default scale 'UTC' global_info['scale'] = 'utc' global_info['format'] = None else: raise AssertionError( 'Global time scale (TIMESYS) should have a FITS recognized ' 'time scale value (got {!r}). The FITS standard states that ' 'the use of local time scales should be restricted to alternate ' 'coordinates.'.format(global_info['TIMESYS'])) else: # Scale is already set global_info['format'] = None # Check if geocentric global location is specified obs_geo = [global_info[attr] for attr in ('OBSGEO-X', 'OBSGEO-Y', 'OBSGEO-Z') if attr in global_info] # Location full specification is (X, Y, Z) if len(obs_geo) == 3: global_info['location'] = EarthLocation.from_geocentric(*obs_geo, unit=u.m) else: # Check if geodetic global location is specified (since geocentric failed) # First warn the user if geocentric location is partially specified if obs_geo: warnings.warn( 'The geocentric observatory location {} is not completely ' 'specified (X, Y, Z) and will be ignored.'.format(obs_geo), AstropyUserWarning) # Check geodetic location obs_geo = [global_info[attr] for attr in ('OBSGEO-L', 'OBSGEO-B', 'OBSGEO-H') if attr in global_info] if len(obs_geo) == 3: global_info['location'] = EarthLocation.from_geodetic(*obs_geo) else: # Since both geocentric and geodetic locations are not specified, # location will be None. # Warn the user if geodetic location is partially specified if obs_geo: warnings.warn( 'The geodetic observatory location {} is not completely ' 'specified (lon, lat, alt) and will be ignored.'.format(obs_geo), AstropyUserWarning) global_info['location'] = None # Get global time reference # Keywords are listed in order of precedence, as stated by the standard for key, format_ in (('MJDREF', 'mjd'), ('JDREF', 'jd'), ('DATEREF', 'fits')): if key in global_info: global_info['ref_time'] = {'val': global_info[key], 'format': format_} break else: # If none of the three keywords is present, MJDREF = 0.0 must be assumed global_info['ref_time'] = {'val': 0, 'format': 'mjd'}