From c16c10937395fc3ddf104053a1dfe5954f35a388 Mon Sep 17 00:00:00 2001 From: Bryna Hazelton Date: Mon, 16 Jul 2018 12:53:11 -0700 Subject: [PATCH 1/5] Make all coordinate conversions use same axes order Add future deprecation warnings for old ordering. --- docs/tutorial.rst | 2 +- pyuvdata/tests/test_utils.py | 45 ++++++++--- pyuvdata/tests/test_uvdata.py | 4 +- pyuvdata/utils.py | 148 +++++++++++++++++++++------------- pyuvdata/uvdata.py | 9 ++- 5 files changed, 132 insertions(+), 76 deletions(-) diff --git a/docs/tutorial.rst b/docs/tutorial.rst index f04a139d6e..afd1b05e19 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -327,7 +327,7 @@ a) Getting antenna positions in topocentric frame in units of meters >>> uvd = UVData() >>> uvd.read_miriad('pyuvdata/data/new.uvA') >>> antpos = uvd.antenna_positions + uvd.telescope_location # get antennas positions in ECEF - >>> antpos = uvutils.ENU_from_ECEF(antpos.T, *uvd.telescope_location_lat_lon_alt).T # convert to topo (ENU) coords. + >>> antpos = uvutils.ENU_from_ECEF(antpos, *uvd.telescope_location_lat_lon_alt) # convert to topo (ENU) coords. UVData: Selecting data diff --git a/pyuvdata/tests/test_utils.py b/pyuvdata/tests/test_utils.py index 295fe91286..0f92a56952 100644 --- a/pyuvdata/tests/test_utils.py +++ b/pyuvdata/tests/test_utils.py @@ -7,12 +7,12 @@ import os import nose.tools as nt +import numpy as np from astropy import units from astropy.time import Time from astropy.coordinates import SkyCoord, Angle from astropy.io import fits import pyuvdata -import numpy as np from pyuvdata.data import DATA_PATH import pyuvdata.utils as uvutils import pyuvdata.tests as uvtest @@ -47,9 +47,15 @@ def test_LatLonAlt_from_XYZ(): nt.assert_raises(ValueError, pyuvdata.LatLonAlt_from_XYZ, ref_latlonalt) # test passing multiple values - xyz_mult = np.stack((np.array(ref_xyz), np.array(ref_xyz)), axis=1) + xyz_mult = np.stack((np.array(ref_xyz), np.array(ref_xyz))) lat_vec, lon_vec, alt_vec = pyuvdata.LatLonAlt_from_XYZ(xyz_mult) nt.assert_true(np.allclose(ref_latlonalt, (lat_vec[1], lon_vec[1], alt_vec[1]), rtol=0, atol=1e-3)) + # check warning if array transposed + uvtest.checkWarnings(pyuvdata.LatLonAlt_from_XYZ, [xyz_mult.T], + message='The expected shape of ECEF xyz array', + category=PendingDeprecationWarning) + # check error if only 2 coordinates + nt.assert_raises(ValueError, pyuvdata.LatLonAlt_from_XYZ, xyz_mult[:, 0:2]) # test error checking nt.assert_raises(ValueError, pyuvdata.LatLonAlt_from_XYZ, ref_xyz[0:1]) @@ -92,25 +98,41 @@ def test_ENU_tofrom_ECEF(): -0.02019057, 0.16979185, 0.06945155, -0.64058124] xyz = pyuvdata.XYZ_from_LatLonAlt(lats, lons, alts) - nt.assert_true(np.allclose(np.stack((x, y, z)), xyz, atol=1e-3)) + nt.assert_true(np.allclose(np.stack((x, y, z), axis=1), xyz, atol=1e-3)) enu = pyuvdata.ENU_from_ECEF(xyz, center_lat, center_lon, center_alt) - nt.assert_true(np.allclose(np.stack((east, north, up)), enu, atol=1e-3)) + nt.assert_true(np.allclose(np.stack((east, north, up), axis=1), enu, atol=1e-3)) + # check warning if array transposed + uvtest.checkWarnings(pyuvdata.ENU_from_ECEF, [xyz.T, center_lat, center_lon, + center_alt], + message='The expected shape of ECEF xyz array', + category=PendingDeprecationWarning) + # check error if only 2 coordinates + nt.assert_raises(ValueError, pyuvdata.ENU_from_ECEF, xyz[:, 0:2], + center_lat, center_lon, center_alt) # check that a round trip gives the original value. xyz_from_enu = pyuvdata.ECEF_from_ENU(enu, center_lat, center_lon, center_alt) nt.assert_true(np.allclose(xyz, xyz_from_enu, atol=1e-3)) + # check warning if array transposed + uvtest.checkWarnings(pyuvdata.ECEF_from_ENU, [enu.T, center_lat, center_lon, + center_alt], + message='The expected shape the ENU array', + category=PendingDeprecationWarning) + # check error if only 2 coordinates + nt.assert_raises(ValueError, pyuvdata.ENU_from_ECEF, enu[:, 0:2], center_lat, + center_lon, center_alt) # check passing a single value - enu_single = pyuvdata.ENU_from_ECEF(xyz[:, 0], center_lat, center_lon, center_alt) - nt.assert_true(np.allclose(np.stack((east[0], north[0], up[0])), enu[:, 0], atol=1e-3)) + enu_single = pyuvdata.ENU_from_ECEF(xyz[0, :], center_lat, center_lon, center_alt) + nt.assert_true(np.allclose(np.array((east[0], north[0], up[0])), enu[0, :], atol=1e-3)) xyz_from_enu = pyuvdata.ECEF_from_ENU(enu_single, center_lat, center_lon, center_alt) - nt.assert_true(np.allclose(xyz[:, 0], xyz_from_enu, atol=1e-3)) + nt.assert_true(np.allclose(xyz[0, :], xyz_from_enu, atol=1e-3)) # error checking - nt.assert_raises(ValueError, pyuvdata.ENU_from_ECEF, xyz[0:1, :], center_lat, center_lon, center_alt) - nt.assert_raises(ValueError, pyuvdata.ECEF_from_ENU, enu[0:1, :], center_lat, center_lon, center_alt) + nt.assert_raises(ValueError, pyuvdata.ENU_from_ECEF, xyz[:, 0:1], center_lat, center_lon, center_alt) + nt.assert_raises(ValueError, pyuvdata.ECEF_from_ENU, enu[:, 0:1], center_lat, center_lon, center_alt) nt.assert_raises(ValueError, pyuvdata.ENU_from_ECEF, xyz / 2., center_lat, center_lon, center_alt) @@ -140,7 +162,6 @@ def test_mwa_ecef_conversion(): # transpose these arrays to get them into the right shape txt_topo = txt_topo.T uvw_topo = uvw_topo.T - enh = enh.T # ARRAYX, ARRAYY, ARRAYZ in ECEF frame from Cotter file arrcent = f['arrcent'] @@ -152,7 +173,7 @@ def test_mwa_ecef_conversion(): # add in array center to get real ECEF ecef_xyz = new_xyz + arrcent - enu = uvutils.ENU_from_ECEF(ecef_xyz.T, lat, lon, alt) + enu = uvutils.ENU_from_ECEF(ecef_xyz, lat, lon, alt) nt.assert_true(np.allclose(enu, enh)) @@ -179,7 +200,7 @@ def test_phasing_funcs(): # in east/north/up frame (relative to array center) in meters: (Nants, 3) ants_enu = np.array([-101.94, 0156.41, 0001.24]) - ant_xyz_abs = uvutils.ECEF_from_ENU(ants_enu.T, lat_lon_alt[0], lat_lon_alt[1], lat_lon_alt[2]).T + ant_xyz_abs = uvutils.ECEF_from_ENU(ants_enu, lat_lon_alt[0], lat_lon_alt[1], lat_lon_alt[2]) ant_xyz_rel_itrs = ant_xyz_abs - array_center_xyz ant_xyz_rel_rot = uvutils.rotECEF_from_ECEF(ant_xyz_rel_itrs, lat_lon_alt[1]) diff --git a/pyuvdata/tests/test_uvdata.py b/pyuvdata/tests/test_uvdata.py index 6c9455e03b..c7d0448f5c 100644 --- a/pyuvdata/tests/test_uvdata.py +++ b/pyuvdata/tests/test_uvdata.py @@ -362,8 +362,8 @@ def test_phase_unphaseHERA(): # check that they match if you phase & unphase using antenna locations # first replace the uvws with the right values - antenna_enu = uvutils.ENU_from_ECEF((UV_raw.antenna_positions + UV_raw.telescope_location).T, - *UV_raw.telescope_location_lat_lon_alt).T + antenna_enu = uvutils.ENU_from_ECEF((UV_raw.antenna_positions + UV_raw.telescope_location), + *UV_raw.telescope_location_lat_lon_alt) uvw_calc = np.zeros_like(UV_raw.uvw_array) unique_times, unique_inds = np.unique(UV_raw.time_array, return_index=True) for ind, jd in enumerate(unique_times): diff --git a/pyuvdata/utils.py b/pyuvdata/utils.py index 04b816bc31..f95a827251 100644 --- a/pyuvdata/utils.py +++ b/pyuvdata/utils.py @@ -37,35 +37,44 @@ def LatLonAlt_from_XYZ(xyz): Calculate lat/lon/alt from ECEF x,y,z. Args: - xyz: numpy array, shape (3, Npts), with ECEF x,y,z coordinates + xyz: numpy array, shape (Npts, 3), with ECEF x,y,z coordinates Returns: - tuple of latitude, longitude, altitude numpy arrays (if Npts > 1) or values (if Npts = 1) in radians & meters + tuple of latitude, longitude, altitude numpy arrays (if Npts > 1) or + values (if Npts = 1) in radians & meters """ # convert to a numpy array xyz = np.array(xyz) - if xyz.shape[0] != 3: - raise ValueError( - 'The first dimension of the ECEF xyz array must be length 3') + if xyz.ndim > 1 and xyz.shape[1] != 3: + if xyz.shape[0] == 3: + warnings.warn('The expected shape of ECEF xyz array is (Npts, 3). ' + 'Support for arrays shaped (3, Npts) will go away in a ' + 'future version.', PendingDeprecationWarning) + xyz_use = xyz.T + else: + raise ValueError('The expected shape of ECEF xyz array is (Npts, 3).') + + else: + xyz_use = xyz - xyz_use = xyz if xyz_use.ndim == 1: - xyz_use = xyz_use[:, np.newaxis] + xyz_use = xyz_use[np.newaxis, :] # checking for acceptable values - if np.any(np.linalg.norm(xyz, axis=0) < 6.35e6) or np.any(np.linalg.norm(xyz, axis=0) > 6.39e6): + if (np.any(np.linalg.norm(xyz_use, axis=1) < 6.35e6) + or np.any(np.linalg.norm(xyz_use, axis=1) > 6.39e6)): raise ValueError( 'xyz values should be ECEF x, y, z coordinates in meters') # see wikipedia geodetic_datum and Datum transformations of # GPS positions PDF in docs/references folder - gps_p = np.sqrt(xyz_use[0, :]**2 + xyz_use[1, :]**2) - gps_theta = np.arctan2(xyz_use[2, :] * gps_a, gps_p * gps_b) - latitude = np.arctan2(xyz_use[2, :] + e_prime_squared * gps_b + gps_p = np.sqrt(xyz_use[:, 0]**2 + xyz_use[:, 1]**2) + gps_theta = np.arctan2(xyz_use[:, 2] * gps_a, gps_p * gps_b) + latitude = np.arctan2(xyz_use[:, 2] + e_prime_squared * gps_b * np.sin(gps_theta)**3, gps_p - e_squared * gps_a * np.cos(gps_theta)**3) - longitude = np.arctan2(xyz_use[1, :], xyz_use[0, :]) + longitude = np.arctan2(xyz_use[:, 1], xyz_use[:, 0]) gps_N = gps_a / np.sqrt(1 - e_squared * np.sin(latitude)**2) altitude = ((gps_p / np.cos(latitude)) - gps_N) @@ -86,7 +95,7 @@ def XYZ_from_LatLonAlt(latitude, longitude, altitude): altitude: altitude in meters, can be a single value or a vector of length Npts Returns: - numpy array, shape (3, Npts) (if Npts > 1) or (3,) (if Npts = 1), with ECEF x,y,z coordinates + numpy array, shape (Npts, 3) (if Npts > 1) or (3,) (if Npts = 1), with ECEF x,y,z coordinates """ latitude = np.array(latitude) longitude = np.array(longitude) @@ -102,10 +111,10 @@ def XYZ_from_LatLonAlt(latitude, longitude, altitude): # see wikipedia geodetic_datum and Datum transformations of # GPS positions PDF in docs/references folder gps_N = gps_a / np.sqrt(1 - e_squared * np.sin(latitude)**2) - xyz = np.zeros((3, Npts)) - xyz[0, :] = ((gps_N + altitude) * np.cos(latitude) * np.cos(longitude)) - xyz[1, :] = ((gps_N + altitude) * np.cos(latitude) * np.sin(longitude)) - xyz[2, :] = ((gps_b**2 / gps_a**2 * gps_N + altitude) * np.sin(latitude)) + xyz = np.zeros((Npts, 3)) + xyz[:, 0] = ((gps_N + altitude) * np.cos(latitude) * np.cos(longitude)) + xyz[:, 1] = ((gps_N + altitude) * np.cos(latitude) * np.sin(longitude)) + xyz[:, 2] = ((gps_b**2 / gps_a**2 * gps_N + altitude) * np.sin(latitude)) xyz = np.squeeze(xyz) return xyz @@ -155,47 +164,60 @@ def ENU_from_ECEF(xyz, latitude, longitude, altitude): Calculate local ENU (east, north, up) coordinates from ECEF coordinates. Args: - xyz: numpy array, shape (3, Npts), with ECEF x,y,z coordinates + xyz: numpy array, shape (Npts, 3), with ECEF x,y,z coordinates latitude: latitude of center of ENU coordinates in radians longitude: longitude of center of ENU coordinates in radians altitude: altitude of center of ENU coordinates in radians Returns: - numpy array, shape (3, Npts), with local ENU coordinates + numpy array, shape (Npts, 3), with local ENU coordinates """ - if xyz.shape[0] != 3: - raise ValueError( - 'The first dimension of the ECEF xyz array must be length 3') + xyz = np.array(xyz) + if xyz.ndim > 1 and xyz.shape[1] != 3: + if xyz.shape[0] == 3: + warnings.warn('The expected shape of ECEF xyz array is (Npts, 3). ' + 'Support for arrays shaped (3, Npts) will go away in a ' + 'future version.', PendingDeprecationWarning) + xyz_in = xyz.T + transpose = True + else: + raise ValueError('The expected shape of ECEF xyz array is (Npts, 3).') + else: + xyz_in = xyz + transpose = False + + if xyz_in.ndim == 1: + xyz_in = xyz_in[np.newaxis, :] # check that these are sensible ECEF values -- their magnitudes need to be # on the order of Earth's radius - ecef_magnitudes = np.linalg.norm(xyz, axis=0) + ecef_magnitudes = np.linalg.norm(xyz_in, axis=1) sensible_radius_range = (6.35e6, 6.39e6) - if np.any(ecef_magnitudes <= sensible_radius_range[0]) or np.any(ecef_magnitudes >= sensible_radius_range[1]): + if (np.any(ecef_magnitudes <= sensible_radius_range[0]) + or np.any(ecef_magnitudes >= sensible_radius_range[1])): raise ValueError( 'ECEF vector magnitudes must be on the order of the radius of the earth') xyz_center = XYZ_from_LatLonAlt(latitude, longitude, altitude) - xyz_in = xyz - if xyz_in.ndim == 1: - xyz_in = xyz_in[:, np.newaxis] xyz_use = np.zeros_like(xyz_in) - xyz_use[0, :] = xyz_in[0, :] - xyz_center[0] - xyz_use[1, :] = xyz_in[1, :] - xyz_center[1] - xyz_use[2, :] = xyz_in[2, :] - xyz_center[2] + xyz_use[:, 0] = xyz_in[:, 0] - xyz_center[0] + xyz_use[:, 1] = xyz_in[:, 1] - xyz_center[1] + xyz_use[:, 2] = xyz_in[:, 2] - xyz_center[2] enu = np.zeros_like(xyz_use) - enu[0, :] = (-np.sin(longitude) * xyz_use[0, :] - + np.cos(longitude) * xyz_use[1, :]) - enu[1, :] = (-np.sin(latitude) * np.cos(longitude) * xyz_use[0, :] - - np.sin(latitude) * np.sin(longitude) * xyz_use[1, :] - + np.cos(latitude) * xyz_use[2, :]) - enu[2, :] = (np.cos(latitude) * np.cos(longitude) * xyz_use[0, :] - + np.cos(latitude) * np.sin(longitude) * xyz_use[1, :] - + np.sin(latitude) * xyz_use[2, :]) + enu[:, 0] = (-np.sin(longitude) * xyz_use[:, 0] + + np.cos(longitude) * xyz_use[:, 1]) + enu[:, 1] = (-np.sin(latitude) * np.cos(longitude) * xyz_use[:, 0] + - np.sin(latitude) * np.sin(longitude) * xyz_use[:, 1] + + np.cos(latitude) * xyz_use[:, 2]) + enu[:, 2] = (np.cos(latitude) * np.cos(longitude) * xyz_use[:, 0] + + np.cos(latitude) * np.sin(longitude) * xyz_use[:, 1] + + np.sin(latitude) * xyz_use[:, 2]) if len(xyz.shape) == 1: enu = np.squeeze(enu) + elif transpose: + return enu.T return enu @@ -205,36 +227,48 @@ def ECEF_from_ENU(enu, latitude, longitude, altitude): Calculate ECEF coordinates from local ENU (east, north, up) coordinates. Args: - enu: numpy array, shape (3, Npts), with local ENU coordinates + enu: numpy array, shape (Npts, 3), with local ENU coordinates latitude: latitude of center of ENU coordinates in radians longitude: longitude of center of ENU coordinates in radians Returns: - numpy array, shape (3, Npts), with ECEF x,y,z coordinates - """ - if enu.shape[0] != 3: - raise ValueError( - 'The first dimension of the local ENU array must be length 3') + numpy array, shape (Npts, 3), with ECEF x,y,z coordinates + """ + enu = np.array(enu) + if enu.ndim > 1 and enu.shape[1] != 3: + if enu.shape[0] == 3: + warnings.warn('The expected shape of the ENU array is (Npts, 3). ' + 'Support for arrays shaped (3, Npts) will go away in a ' + 'future version.', PendingDeprecationWarning) + enu_use = enu.T + transpose = True + else: + raise ValueError('The expected shape of the ENU array array is (Npts, 3).') + else: + enu_use = enu + transpose = False - enu_use = enu if enu_use.ndim == 1: - enu_use = enu_use[:, np.newaxis] + enu_use = enu_use[np.newaxis, :] + xyz = np.zeros_like(enu_use) - xyz[0, :] = (-np.sin(latitude) * np.cos(longitude) * enu_use[1, :] - - np.sin(longitude) * enu_use[0, :] - + np.cos(latitude) * np.cos(longitude) * enu_use[2, :]) - xyz[1, :] = (-np.sin(latitude) * np.sin(longitude) * enu_use[1, :] - + np.cos(longitude) * enu_use[0, :] - + np.cos(latitude) * np.sin(longitude) * enu_use[2, :]) - xyz[2, :] = (np.cos(latitude) * enu_use[1, :] - + np.sin(latitude) * enu_use[2, :]) + xyz[:, 0] = (-np.sin(latitude) * np.cos(longitude) * enu_use[:, 1] + - np.sin(longitude) * enu_use[:, 0] + + np.cos(latitude) * np.cos(longitude) * enu_use[:, 2]) + xyz[:, 1] = (-np.sin(latitude) * np.sin(longitude) * enu_use[:, 1] + + np.cos(longitude) * enu_use[:, 0] + + np.cos(latitude) * np.sin(longitude) * enu_use[:, 2]) + xyz[:, 2] = (np.cos(latitude) * enu_use[:, 1] + + np.sin(latitude) * enu_use[:, 2]) xyz_center = XYZ_from_LatLonAlt(latitude, longitude, altitude) - xyz[0, :] = xyz[0, :] + xyz_center[0] - xyz[1, :] = xyz[1, :] + xyz_center[1] - xyz[2, :] = xyz[2, :] + xyz_center[2] + xyz[:, 0] = xyz[:, 0] + xyz_center[0] + xyz[:, 1] = xyz[:, 1] + xyz_center[1] + xyz[:, 2] = xyz[:, 2] + xyz_center[2] if len(enu.shape) == 1: xyz = np.squeeze(xyz) + elif transpose: + return xyz.T return xyz diff --git a/pyuvdata/uvdata.py b/pyuvdata/uvdata.py index 61003ef481..6a1679551a 100644 --- a/pyuvdata/uvdata.py +++ b/pyuvdata/uvdata.py @@ -646,8 +646,8 @@ def unphase_to_drift(self, phase_frame=None, use_ant_pos=False): itrs_uvw_coord = frame_uvw_coord.transform_to('itrs') # now convert them to ENU, which is the space uvws are in - self.uvw_array[inds, :] = uvutils.ENU_from_ECEF(itrs_uvw_coord.cartesian.get_xyz().value, - *itrs_lat_lon_alt).T + self.uvw_array[inds, :] = uvutils.ENU_from_ECEF(itrs_uvw_coord.cartesian.get_xyz().value.T, + *itrs_lat_lon_alt) # remove phase center self.phase_center_frame = None @@ -765,7 +765,7 @@ def phase(self, ra, dec, epoch='J2000', phase_frame='icrs', use_ant_pos=False): # convert them to ECEF to transform between frames uvws_use = self.uvw_array[inds, :] - uvw_ecef = uvutils.ECEF_from_ENU(uvws_use.T, *itrs_lat_lon_alt).T + uvw_ecef = uvutils.ECEF_from_ENU(uvws_use, *itrs_lat_lon_alt) itrs_uvw_coord = SkyCoord(x=uvw_ecef[:, 0] * units.m, y=uvw_ecef[:, 1] * units.m, @@ -2174,7 +2174,8 @@ def get_ENU_antpos(self, center=True, pick_data_ants=False): antpos : ndarray, antenna positions in TOPO frame and units of meters, shape=(Nants, 3) ants : ndarray, antenna numbers matching ordering of antpos, shape=(Nants,) """ - antpos = uvutils.ENU_from_ECEF((self.antenna_positions + self.telescope_location).T, *self.telescope_location_lat_lon_alt).T + antpos = uvutils.ENU_from_ECEF((self.antenna_positions + self.telescope_location), + *self.telescope_location_lat_lon_alt) ants = self.antenna_numbers if pick_data_ants: From 165b3735c2c9a43ada2dcca1a9746c8cf86faa13 Mon Sep 17 00:00:00 2001 From: Bryna Hazelton Date: Mon, 16 Jul 2018 14:46:30 -0700 Subject: [PATCH 2/5] undo accidental change to uvh5.py --- pyuvdata/uvh5.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyuvdata/uvh5.py b/pyuvdata/uvh5.py index 0602f2e6d9..1efc4dd1e1 100644 --- a/pyuvdata/uvh5.py +++ b/pyuvdata/uvh5.py @@ -94,7 +94,7 @@ def _read_header(self, header): self.Nants_telescope = int(header['Nants_telescope'].value) self.ant_1_array = header['ant_1_array'].value self.ant_2_array = header['ant_2_array'].value - self.antenna_names = [uvutils._bytes_to_str(n) for n in header['antenna_names'].value] + self.antenna_names = [uvutils.bytes_to_str(n) for n in header['antenna_names'].value] self.antenna_numbers = header['antenna_numbers'].value # get baseline array @@ -335,7 +335,7 @@ def _write_header(self, header): header['Npols'] = self.Npols header['Nspws'] = self.Nspws header['Ntimes'] = self.Ntimes - header['antenna_names'] = [uvutils._str_to_bytes(n) for n in self.antenna_names] + header['antenna_names'] = [uvutils.str_to_bytes(n) for n in self.antenna_names] header['antenna_numbers'] = self.antenna_numbers header['uvw_array'] = self.uvw_array header['vis_units'] = self.vis_units From 2e3b0804a266eab85b533256949268bad99868ff Mon Sep 17 00:00:00 2001 From: Bryna Hazelton Date: Tue, 17 Jul 2018 17:05:03 -0700 Subject: [PATCH 3/5] fix error after rebase --- pyuvdata/uvh5.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyuvdata/uvh5.py b/pyuvdata/uvh5.py index 1efc4dd1e1..0602f2e6d9 100644 --- a/pyuvdata/uvh5.py +++ b/pyuvdata/uvh5.py @@ -94,7 +94,7 @@ def _read_header(self, header): self.Nants_telescope = int(header['Nants_telescope'].value) self.ant_1_array = header['ant_1_array'].value self.ant_2_array = header['ant_2_array'].value - self.antenna_names = [uvutils.bytes_to_str(n) for n in header['antenna_names'].value] + self.antenna_names = [uvutils._bytes_to_str(n) for n in header['antenna_names'].value] self.antenna_numbers = header['antenna_numbers'].value # get baseline array @@ -335,7 +335,7 @@ def _write_header(self, header): header['Npols'] = self.Npols header['Nspws'] = self.Nspws header['Ntimes'] = self.Ntimes - header['antenna_names'] = [uvutils.str_to_bytes(n) for n in self.antenna_names] + header['antenna_names'] = [uvutils._str_to_bytes(n) for n in self.antenna_names] header['antenna_numbers'] = self.antenna_numbers header['uvw_array'] = self.uvw_array header['vis_units'] = self.vis_units From 7727e2b1889f0866f2ae85bf995413ee761be904 Mon Sep 17 00:00:00 2001 From: Bryna Hazelton Date: Wed, 18 Jul 2018 09:24:19 -0700 Subject: [PATCH 4/5] fix shape bug after rebase --- pyuvdata/uvdata.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/pyuvdata/uvdata.py b/pyuvdata/uvdata.py index 6a1679551a..cf0f8b82c8 100644 --- a/pyuvdata/uvdata.py +++ b/pyuvdata/uvdata.py @@ -877,18 +877,15 @@ def set_uvws_from_antenna_positions(self, allow_phasing=False, 'allow_phasing=True.' ) antenna_locs_ENU = uvutils.ENU_from_ECEF( - (self.antenna_positions + self.telescope_location).T, - *self.telescope_location_lat_lon_alt - ).T + (self.antenna_positions + self.telescope_location), + *self.telescope_location_lat_lon_alt) uvw_array = np.zeros((self.baseline_array.size, 3)) for baseline in list(set(self.baseline_array)): baseline_inds = np.where(self.baseline_array == baseline)[0] - ant1_index = np.where( - self.antenna_numbers == self.ant_1_array[baseline_inds[0]] - )[0][0] - ant2_index = np.where( - self.antenna_numbers == self.ant_2_array[baseline_inds[0]] - )[0][0] + ant1_index = np.where(self.antenna_numbers + == self.ant_1_array[baseline_inds[0]])[0][0] + ant2_index = np.where(self.antenna_numbers + == self.ant_2_array[baseline_inds[0]])[0][0] uvw_array[baseline_inds, :] = (antenna_locs_ENU[ant2_index, :] - antenna_locs_ENU[ant1_index, :]) self.uvw_array = uvw_array From b10a22dff3f2db9c7650433fa887bd75e2b71060 Mon Sep 17 00:00:00 2001 From: Bryna Hazelton Date: Wed, 18 Jul 2018 14:13:29 -0700 Subject: [PATCH 5/5] Add warnings for shape (3,3) arrays --- pyuvdata/tests/test_utils.py | 15 +++++++++++++++ pyuvdata/utils.py | 18 ++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/pyuvdata/tests/test_utils.py b/pyuvdata/tests/test_utils.py index 0f92a56952..a0c6d56251 100644 --- a/pyuvdata/tests/test_utils.py +++ b/pyuvdata/tests/test_utils.py @@ -54,6 +54,11 @@ def test_LatLonAlt_from_XYZ(): uvtest.checkWarnings(pyuvdata.LatLonAlt_from_XYZ, [xyz_mult.T], message='The expected shape of ECEF xyz array', category=PendingDeprecationWarning) + # check warning if 3 x 3 array + xyz_3 = np.stack((np.array(ref_xyz), np.array(ref_xyz), np.array(ref_xyz))) + uvtest.checkWarnings(pyuvdata.LatLonAlt_from_XYZ, [xyz_3], + message='The xyz array in LatLonAlt_from_XYZ is', + category=PendingDeprecationWarning) # check error if only 2 coordinates nt.assert_raises(ValueError, pyuvdata.LatLonAlt_from_XYZ, xyz_mult[:, 0:2]) @@ -107,6 +112,11 @@ def test_ENU_tofrom_ECEF(): center_alt], message='The expected shape of ECEF xyz array', category=PendingDeprecationWarning) + # check warning if 3 x 3 array + uvtest.checkWarnings(pyuvdata.ENU_from_ECEF, [xyz[0:3], center_lat, center_lon, + center_alt], + message='The xyz array in ENU_from_ECEF is', + category=PendingDeprecationWarning) # check error if only 2 coordinates nt.assert_raises(ValueError, pyuvdata.ENU_from_ECEF, xyz[:, 0:2], center_lat, center_lon, center_alt) @@ -119,6 +129,11 @@ def test_ENU_tofrom_ECEF(): center_alt], message='The expected shape the ENU array', category=PendingDeprecationWarning) + # check warning if 3 x 3 array + uvtest.checkWarnings(pyuvdata.ECEF_from_ENU, [enu[0:3], center_lat, center_lon, + center_alt], + message='The enu array in ECEF_from_ENU is', + category=PendingDeprecationWarning) # check error if only 2 coordinates nt.assert_raises(ValueError, pyuvdata.ENU_from_ECEF, enu[:, 0:2], center_lat, center_lon, center_alt) diff --git a/pyuvdata/utils.py b/pyuvdata/utils.py index f95a827251..590b95e1d5 100644 --- a/pyuvdata/utils.py +++ b/pyuvdata/utils.py @@ -57,6 +57,12 @@ def LatLonAlt_from_XYZ(xyz): else: xyz_use = xyz + if xyz.shape == (3, 3): + warnings.warn('The xyz array in LatLonAlt_from_XYZ is being ' + 'interpreted as (Npts, 3). Historically this function ' + 'has supported (3, Npts) arrays, please verify that ' + 'array ordering is as expected.', PendingDeprecationWarning) + if xyz_use.ndim == 1: xyz_use = xyz_use[np.newaxis, :] @@ -186,6 +192,12 @@ def ENU_from_ECEF(xyz, latitude, longitude, altitude): xyz_in = xyz transpose = False + if xyz.shape == (3, 3): + warnings.warn('The xyz array in ENU_from_ECEF is being ' + 'interpreted as (Npts, 3). Historically this function ' + 'has supported (3, Npts) arrays, please verify that ' + 'array ordering is as expected.', PendingDeprecationWarning) + if xyz_in.ndim == 1: xyz_in = xyz_in[np.newaxis, :] @@ -248,6 +260,12 @@ def ECEF_from_ENU(enu, latitude, longitude, altitude): enu_use = enu transpose = False + if enu.shape == (3, 3): + warnings.warn('The enu array in ECEF_from_ENU is being ' + 'interpreted as (Npts, 3). Historically this function ' + 'has supported (3, Npts) arrays, please verify that ' + 'array ordering is as expected.', PendingDeprecationWarning) + if enu_use.ndim == 1: enu_use = enu_use[np.newaxis, :]