def get_ants_installed_since(self, query_date, station_types_to_check='all'): """ Get list of antennas installed since query_date. Parameters ---------- query_date : astropy Time Date to get limit check for installation. station_types_to_check : str or list of str Stations types to limit check. """ import cartopy.crs as ccrs station_types_to_check = self.parse_station_types_to_check( station_types_to_check) dt = query_date.gps latlon_p = ccrs.Geodetic() utm_p = ccrs.UTM(self.hera_zone[0]) lat_corr = self.lat_corr[self.hera_zone[1]] found_stations = [] for a in self.session.query(geo_location.GeoLocation).filter( geo_location.GeoLocation.created_gpstime >= dt): if a.station_type_name.lower() in station_types_to_check: a.gps2Time() a.desc = self.station_types[a.station_type_name]['Description'] a.lon, a.lat = latlon_p.transform_point( a.easting, a.northing - lat_corr, utm_p) a.X, a.Y, a.Z = uvutils.XYZ_from_LatLonAlt( radians(a.lat), radians(a.lon), a.elevation) found_stations.append(copy.copy(a)) if self.fp_out is not None and not self.testing: # pragma: no cover self.fp_out.write('{}\n'.format(self._loc_line(a))) return found_stations
def parse_telescope_params(tele_params): """ Parse the "telescope" section of a healvis obsparam. Args: tele_params: Dictionary of telescope parameters Returns: dict of array properties: | Nants_data: Number of antennas | Nants_telescope: Number of antennas | antenna_names: list of antenna names | antenna_numbers: corresponding list of antenna numbers | antenna_positions: Array of ECEF antenna positions | telescope_location: ECEF array center location | telescope_config_file: Path to configuration yaml file | antenna_location_file: Path to csv layout file | telescope_name: observatory name """ layout_csv = tele_params["array_layout"] if not os.path.exists(layout_csv): if not os.path.exists(layout_csv): raise ValueError( "layout_csv file from yaml does not exist: {}".format( layout_csv)) ant_layout = _parse_layout_csv(layout_csv) if isinstance(tele_params["telescope_location"], str): tloc = tele_params["telescope_location"][1:-1] # drop parens tloc = list(map(float, tloc.split(","))) else: tloc = list(tele_params["telescope_location"]) tloc[0] *= np.pi / 180.0 tloc[1] *= np.pi / 180.0 # Convert to radians tloc_xyz = uvutils.XYZ_from_LatLonAlt(*tloc) E, N, U = ant_layout["e"], ant_layout["n"], ant_layout["u"] antnames = ant_layout["name"] return_dict = {} return_dict["Nants_data"] = antnames.size return_dict["Nants_telescope"] = antnames.size return_dict["antenna_names"] = np.array(antnames.tolist()) return_dict["antenna_numbers"] = np.array(ant_layout["number"]) antpos_enu = np.vstack((E, N, U)).T return_dict["antenna_positions"] = ( uvutils.ECEF_from_ENU(antpos_enu, *tloc) - tloc_xyz) return_dict["array_layout"] = layout_csv return_dict["telescope_location"] = tloc_xyz return_dict["telescope_name"] = tele_params["telescope_name"] return return_dict
def get_telescope_location_ecef(lat, lon, alt): """ Compute the telescope location in ECEF coordinates from lat/lon/alt. Args: lat (float) -- telescope latitude, in radians lon (float) -- telescope longitude, in radians alt (float) -- telescope altitude, in meters Returns: ecef -- len(3) array of x,y,z values of telescope location in ECEF coordinates, in meters. """ import pyuvdata.utils as uvutils return uvutils.XYZ_from_LatLonAlt(lat, lon, alt)
def test_XYZ_from_LatLonAlt(): """Test conversion from lat/lon/alt to ECEF xyz with reference values.""" out_xyz = uvutils.XYZ_from_LatLonAlt(ref_latlonalt[0], ref_latlonalt[1], ref_latlonalt[2]) # Got reference by forcing http://www.oc.nps.edu/oc2902w/coord/llhxyz.htm # to give additional precision. assert np.allclose(ref_xyz, out_xyz, rtol=0, atol=1e-3) # test error checking pytest.raises(ValueError, uvutils.XYZ_from_LatLonAlt, ref_latlonalt[0], ref_latlonalt[1], np.array([ref_latlonalt[2], ref_latlonalt[2]])) pytest.raises(ValueError, uvutils.XYZ_from_LatLonAlt, ref_latlonalt[0], np.array([ref_latlonalt[1], ref_latlonalt[1]]), ref_latlonalt[2])
def get_location(self, to_find_list, query_date): """ Get GeoLocation objects for a list of station_names. Parameters ---------- to_find_list : list of str station names to find query_date : string, int, Time, datetime Date to get information for, anything that can be parsed by `get_astropytime`. Returns ------- list of GeoLocation objects GeoLocation objects corresponding to station names. """ import cartopy.crs as ccrs latlon_p = ccrs.Geodetic() utm_p = ccrs.UTM(self.hera_zone[0]) lat_corr = self.lat_corr[self.hera_zone[1]] locations = [] self.query_date = cm_utils.get_astropytime(query_date) for station_name in to_find_list: for a in self.session.query(geo_location.GeoLocation).filter( (func.upper(geo_location.GeoLocation.station_name) == station_name.upper()) & (geo_location.GeoLocation.created_gpstime < self.query_date.gps)): a.gps2Time() a.desc = self.station_types[a.station_type_name]['Description'] a.lon, a.lat = latlon_p.transform_point( a.easting, a.northing - lat_corr, utm_p) a.X, a.Y, a.Z = uvutils.XYZ_from_LatLonAlt( radians(a.lat), radians(a.lon), a.elevation) locations.append(copy.copy(a)) if self.fp_out is not None and not self.testing: # pragma: no cover self.fp_out.write('{}\n'.format(self._loc_line(a))) return locations
fnd_list = geo.get_location([stn[0]], t, station_types=geo.station_types) fnd = fnd_list[0] lat = fnd.lat lon = fnd.lon alt = fnd.elevation ant_nums.append(ant_number) longitudes.append(lon) latitudes.append(lat) elevations.append(alt) # convert to ecef (in meters) ecef_positions = uvutils.XYZ_from_LatLonAlt( np.array(latitudes) * np.pi / 180., np.array(longitudes) * np.pi / 180., elevations) rotecef_positions = uvutils.rotECEF_from_ECEF(ecef_positions.T, cofa_loc.lon * np.pi / 180.) # make an array of antenna positions in the form miriad is expecting c_ns = const.c.to('m/ns').value nants = max(ant_nums) + 1 antpos = np.zeros([nants, 3]) for i, ant in enumerate(ant_nums): antpos[ant, :] = rotecef_positions[i, :] / c_ns # make an aa object freqs = np.array([0.15]) beam = aipy.phs.Beam(freqs) ants = [aipy.phs.Antenna(a[0], a[1], a[2], beam) for a in antpos]
def get_cminfo_correlator(self, hookup_type=None): """ Return a dict with info needed by the correlator. Note: This method requires pyuvdata Parameters ---------- hookup_type : str or None Type of hookup to use (current observing system is 'parts_hera'). If 'None' it will determine which system it thinks it is based on the part-type. The order in which it checks is specified in cm_sysdef. Only change if you know you want a different system (like 'parts_paper'). Default is None. Returns ------- dict cm info formatted for the correlator. Dict keys are: 'antenna_numbers': Antenna numbers (list of integers) 'antenna_names': Station names (we use antenna_names because that's what they're called in data files) (list of strings) 'correlator_inputs': Correlator input strings for x/y (e/n) polarizations (list of 2 element tuples of strings) 'antenna_positions': Antenna positions in relative ECEF coordinates (list of 3-element vectors of floats) 'cm_version': CM git hash (string) 'cofa_lat': latitude of the center-of-array in degrees 'cofa_lon': longitude of the center-of-array in degrees 'cofa_alt': altitude of center-of-array in meters """ from pyuvdata import utils as uvutils from . import cm_handling cm_h = cm_handling.Handling(session=self.session) cm_version = cm_h.get_cm_version() cofa_loc = self.geo.cofa()[0] cofa_xyz = uvutils.XYZ_from_LatLonAlt(cofa_loc.lat * np.pi / 180., cofa_loc.lon * np.pi / 180., cofa_loc.elevation) stations_conn = self.get_connected_stations(at_date='now', hookup_type=hookup_type) stn_arrays = SystemInfo() for stn in stations_conn: stn_arrays.update_arrays(stn) # latitudes, longitudes output by get_connected_stations are in degrees # XYZ_from_LatLonAlt wants radians ecef_positions = uvutils.XYZ_from_LatLonAlt(np.array(stn_arrays.lat) * np.pi / 180., np.array(stn_arrays.lon) * np.pi / 180., stn_arrays.elevation) rel_ecef_positions = ecef_positions - cofa_xyz return {'antenna_numbers': stn_arrays.antenna_number, # This is actually station names, not antenna names, # but antenna_names is what it's called in pyuvdata 'antenna_names': stn_arrays.station_name, # this is a tuple giving the f-engine names for x, y 'correlator_inputs': stn_arrays.correlator_input, 'antenna_positions': rel_ecef_positions.tolist(), 'cm_version': cm_version, 'cofa_lat': cofa_loc.lat, 'cofa_lon': cofa_loc.lon, 'cofa_alt': cofa_loc.elevation}
# Convert UTM to Lat/Lon # LatLon to ECEF using pyuvdata.utils # # Finally convert ECEF to ENU using # coordinates of the center of the array (cofa) # ENU coordinates are wrt center of the array antpos_ENU = {} # Extract cminfo from redis for cofa coordinates cminfo = redis_cm.read_cminfo_from_redis(return_as='dict') cofa_lat = cminfo['cofa_lat'] * np.pi / 180. cofa_lon = cminfo['cofa_lon'] * np.pi / 180. cofa_alt = cminfo['cofa_alt'] for ant, loc in ants.items(): lon, lat = latlon.transform_point(loc['E'], loc['N'] - lat_corr, utm) # Convert the latitute-longitude to ECEF ecef = uvutils.XYZ_from_LatLonAlt(lat * np.pi / 180, lon * np.pi / 180, loc['elevation']) # Convert ECEF to ENU enu = uvutils.ENU_from_ECEF(ecef, cofa_lat, cofa_lon, cofa_alt) antpos_ENU[ant] = enu.tolist() with open('HERA_350_ENU.json', 'w') as fp: json.dump(antpos_ENU, fp)
def test_ENU_tofrom_ECEF(): center_lat = -30.7215261207 * np.pi / 180.0 center_lon = 21.4283038269 * np.pi / 180.0 center_alt = 1051.7 lats = np.array([ -30.72218216, -30.72138101, -30.7212785, -30.7210011, -30.72159853, -30.72206199, -30.72174614, -30.72188775, -30.72183915, -30.72100138 ]) * np.pi / 180.0 lons = np.array([ 21.42728211, 21.42811727, 21.42814544, 21.42795736, 21.42686739, 21.42918772, 21.42785662, 21.4286408, 21.42750933, 21.42896567 ]) * np.pi / 180.0 alts = np.array([ 1052.25, 1051.35, 1051.2, 1051., 1051.45, 1052.04, 1051.68, 1051.87, 1051.77, 1051.06 ]) # used pymap3d, which implements matlab code, as a reference. x = [ 5109327.46674067, 5109339.76407785, 5109344.06370947, 5109365.11297147, 5109372.115673, 5109266.94314734, 5109329.89620962, 5109295.13656657, 5109337.21810468, 5109329.85680612 ] y = [ 2005130.57953031, 2005221.35184577, 2005225.93775268, 2005214.8436201, 2005105.42364036, 2005302.93158317, 2005190.65566222, 2005257.71335575, 2005157.78980089, 2005304.7729239 ] z = [ -3239991.24516348, -3239914.4185286, -3239904.57048431, -3239878.02656316, -3239935.20415493, -3239979.68381865, -3239949.39266985, -3239962.98805772, -3239958.30386264, -3239878.08403833 ] east = [ -97.87631659, -17.87126443, -15.17316938, -33.19049252, -137.60520964, 84.67346748, -42.84049408, 32.28083937, -76.1094745, 63.40285935 ] north = [ -72.7437482, 16.09066646, 27.45724573, 58.21544651, -8.02964511, -59.41961437, -24.39698388, -40.09891961, -34.70965816, 58.18410876 ] up = [ 0.54883333, -0.35004539, -0.50007736, -0.70035299, -0.25148791, 0.33916067, -0.02019057, 0.16979185, 0.06945155, -0.64058124 ] xyz = uvutils.XYZ_from_LatLonAlt(lats, lons, alts) assert np.allclose(np.stack((x, y, z), axis=1), xyz, atol=1e-3) enu = uvutils.ENU_from_ECEF(xyz, center_lat, center_lon, center_alt) assert np.allclose(np.stack((east, north, up), axis=1), enu, atol=1e-3) # check warning if array transposed uvtest.checkWarnings(uvutils.ENU_from_ECEF, [xyz.T, center_lat, center_lon, center_alt], message='The expected shape of ECEF xyz array', category=DeprecationWarning) # check warning if 3 x 3 array uvtest.checkWarnings(uvutils.ENU_from_ECEF, [xyz[0:3], center_lat, center_lon, center_alt], message='The xyz array in ENU_from_ECEF is', category=DeprecationWarning) # check error if only 2 coordinates pytest.raises(ValueError, uvutils.ENU_from_ECEF, xyz[:, 0:2], center_lat, center_lon, center_alt) # check that a round trip gives the original value. xyz_from_enu = uvutils.ECEF_from_ENU(enu, center_lat, center_lon, center_alt) assert np.allclose(xyz, xyz_from_enu, atol=1e-3) # check warning if array transposed uvtest.checkWarnings(uvutils.ECEF_from_ENU, [enu.T, center_lat, center_lon, center_alt], message='The expected shape the ENU array', category=DeprecationWarning) # check warning if 3 x 3 array uvtest.checkWarnings(uvutils.ECEF_from_ENU, [enu[0:3], center_lat, center_lon, center_alt], message='The enu array in ECEF_from_ENU is', category=DeprecationWarning) # check error if only 2 coordinates pytest.raises(ValueError, uvutils.ENU_from_ECEF, enu[:, 0:2], center_lat, center_lon, center_alt) # check passing a single value enu_single = uvutils.ENU_from_ECEF(xyz[0, :], center_lat, center_lon, center_alt) assert np.allclose(np.array((east[0], north[0], up[0])), enu[0, :], atol=1e-3) xyz_from_enu = uvutils.ECEF_from_ENU(enu_single, center_lat, center_lon, center_alt) assert np.allclose(xyz[0, :], xyz_from_enu, atol=1e-3) # error checking pytest.raises(ValueError, uvutils.ENU_from_ECEF, xyz[:, 0:1], center_lat, center_lon, center_alt) pytest.raises(ValueError, uvutils.ECEF_from_ENU, enu[:, 0:1], center_lat, center_lon, center_alt) pytest.raises(ValueError, uvutils.ENU_from_ECEF, xyz / 2., center_lat, center_lon, center_alt)
import numpy as np from astropy import constants, coordinates, units from astropy.time import Time from astropy.coordinates import SkyCoord, EarthLocation, FK5 from pyuvdata import utils as uvutils from hera_mc import geo_handling # get cofa information handling = geo_handling.Handling() cofa = handling.cofa()[0] cofa_lat = cofa.lat * np.pi / 180.0 cofa_lon = cofa.lon * np.pi / 180.0 cofa_alt = cofa.elevation cofa_xyz = uvutils.XYZ_from_LatLonAlt(cofa_lat, cofa_lon, cofa_alt) cofa_enu = uvutils.ENU_from_ECEF(cofa_xyz, cofa_lat, cofa_lon, cofa_alt) # get antennas telescope_location = EarthLocation.from_geocentric(*cofa_xyz, unit=units.m) jd = int(Time.now().jd) if True: time0 = Time.now() time0.location = telescope_location else: time0 = Time(jd, format="jd", location=telescope_location) print("time0: ", time0.jd) ants = handling.get_active_stations(time0, "all") # sort the list by antenna name ants = sorted(ants, key=lambda x: int(x.station_name[2:]))
data.ant_1_array = np.asarray( [str(a)[2:-1] for a in data.ant_1_array]).astype(int) data.ant_2_array = np.asarray( [str(a)[2:-1] for a in data.ant_2_array]).astype(int) # Get antenna locations from hera_mc database mh = Handling() info = mh.get_cminfo_correlator() #with open('cminfo.cp','r') as fp: # info = cp.load(fp) #set telescope data lla = (np.radians(info['cofa_lat']), np.radians(info['cofa_lon']), info['cofa_alt']) data.telescope_location = utils.XYZ_from_LatLonAlt( lla[0], lla[1], lla[2]) data.antenna_positions = info['antenna_positions'] data.antenna_numbers = np.array( info['antenna_numbers']).astype(int) data.antenna_names = np.asarray( [str(a) for a in info['antenna_names']]) data.Nants_telescope = len(data.antenna_numbers) data.Nants_data = 3 # Write times jds = Time(times, format='unix') data.time_array = jds.jd data.set_lsts_from_time_array() # Set ra,dec of zenith during observation