def test_convert_latlon_lat_failure(self): """Test error return for co-latitudes above 90 for a single value""" with pytest.raises(AssertionError): aacgmv2.convert_latlon(91, 0, 300, self.dtime) with pytest.raises(AssertionError): aacgmv2.convert_latlon(-91, 0, 300, self.dtime)
def test_convert_latlon_datetime_date(self): """Test single latlon conversion with date and datetime input""" (self.lat_out, self.lon_out, self.r_out) = aacgmv2.convert_latlon(60, 0, 300, self.ddate) lat_2, lon_2, r_2 = aacgmv2.convert_latlon(60, 0, 300, self.dtime) if self.lat_out != lat_2: raise AssertionError() if self.lon_out != lon_2: raise AssertionError() if self.r_out != r_2: raise AssertionError() del lat_2, lon_2, r_2
def convert_azm_aacgm2geo(azM, latG, lonG, dTime, refAlt=300): # Convert azimuths from AACGM to geodetic refZ = -refAlt * 1E3 # nvector uses z = height in metres down wgs84 = nv.FrameE(name='WGS84') nPole = aacgmv2.convert_latlon(90, 0, refAlt, dTime, method_code="A2G") geoAzimuths = np.ones(azM.shape) * np.nan for ind, mAzm in enumerate(azM): pointA = wgs84.GeoPoint( latitude=latG[ind], longitude=lonG[ind], z=refZ, degrees=True, ) pointPole = wgs84.GeoPoint( latitude=nPole[0], longitude=nPole[1], z=refZ, degrees=True, ) p_AB_N = pointA.delta_to(pointPole) azimuth_offset = p_AB_N.azimuth_deg[0] geoAzimuths[ind] = mAzm + azimuth_offset geoAzimuths[geoAzimuths > 180] -= 360. geoAzimuths[geoAzimuths < -180] += 360. return geoAzimuths
def test_convert_latlon_location_failure(self): """Test single value latlon conversion with a bad location""" (self.lat_out, self.lon_out, self.r_out) = aacgmv2.convert_latlon(0, 0, 0, self.dtime) if not (np.isnan(self.lat_out) & np.isnan(self.lon_out) & np.isnan(self.r_out)): raise AssertionError()
def test_convert_latlon(self): """Test single value latlon conversion""" (self.lat_out, self.lon_out, self.r_out) = aacgmv2.convert_latlon(60, 0, 300, self.dtime) np.testing.assert_almost_equal(self.lat_out, 58.2258, decimal=4) np.testing.assert_almost_equal(self.lon_out, 81.1685, decimal=4) np.testing.assert_almost_equal(self.r_out, 1.0457, decimal=4)
def test_convert_latlon_maxalt_failure(self): """For a single value, test failure for an altitude too high for coefficients""" (self.lat_out, self.lon_out, self.r_out) = aacgmv2.convert_latlon(60, 0, 2001, self.dtime) if not (np.isnan(self.lat_out) & np.isnan(self.lon_out) & np.isnan(self.r_out)): raise AssertionError()
def test_convert_latlon_badidea(self): """Test single value latlon conversion with a bad flag""" code = "G2A | BADIDEA" (self.lat_out, self.lon_out, self.r_out) = aacgmv2.convert_latlon(60, 0, 3000, self.dtime, code) np.testing.assert_almost_equal(self.lat_out, 64.3568, decimal=4) np.testing.assert_almost_equal(self.lon_out, 83.3027, decimal=4) np.testing.assert_almost_equal(self.r_out, 1.4694, decimal=4) del code
def test_warning_below_ground_convert_latlon(self): """ Test that a warning is issued if altitude is below zero""" import logbook lwarn = u"conversion not intended for altitudes < 0 km" with logbook.TestHandler() as handler: (self.lat_out, self.lon_out, self.r_out) = aacgmv2.convert_latlon(60, 0, -1, self.dtime) if not handler.has_warning(lwarn): raise AssertionError() handler.close()
def GetStationInfo(Station=None, Date=None): if Station is None: out = Globals.Stations else: use = np.array( [np.where(Globals.Stations.Code == Station.upper())[0][0]]) out = Globals.Stations[use] if not Date is None: yr, mn, dy = TT.DateSplit(Date) dt = datetime.datetime(year=yr[0], month=mn[0], day=dy[0]) for i in range(out.size): out.mlat[i], out.mlon[i], _ = aacgmv2.convert_latlon( out.glat[i], out.glon[i], 0.0, dt, method_code='G2A') return out
def loc_mag_to_geo(loc, dtime): """ Convert a single location in geomagnetic coords into geodetic coords :param loc: location.Location object with longitude and latitude in geomagnetic coords :param dtime: either datetime object or parse-able string :return: location.Location object with longitude and latitude in geodetic coords """ dtime = _check_time(dtime) converted = aacgmv2.convert_latlon(loc.lat, loc.lon, 100, dtime, method_code='A2G') newloc = Location(converted[0], converted[1]) return newloc
def test_convert_latlon_location_failure(self): """Test single value latlon conversion with a bad location""" self.out = aacgmv2.convert_latlon(0, 0, 0, self.dtime, self.in_args[-1]) assert np.all(np.isnan(np.array(self.out)))
def test_convert_latlon_high_lat(self, lat, ref): """Test single latlon conversion with latitude just out of bounds""" self.in_args[0] = lat self.in_args.extend([300, self.dtime, 'G2A']) self.out = aacgmv2.convert_latlon(*self.in_args) np.testing.assert_allclose(self.out, ref, rtol=self.rtol)
for lat in lats: in_lat = np.asarray([lat] * len(in_lon)) out_lats, out_lons, out_rs = convert_latlon_arr(in_lat, in_lon, heights, date, method_code="A2G") plt.plot(out_lons, out_lats, 'k', markersize=3, transform=ccrs.Geodetic(), label=str(lat) + " deg") # Find the geodetic coordinates for the geomagnetic pole, and plot it as a black dot pole_geodetic_lat_N, pole_geodetic_lon_E, _ = aacgmv2.convert_latlon( hemisphere.value * 90, -90, 0, date, method_code="A2G") plt.plot([pole_geodetic_lon_E, pole_geodetic_lon_E], [pole_geodetic_lat_N, pole_geodetic_lat_N], 'ko', markersize=3, transform=ccrs.Geodetic(), label="Geomagnetic North Pole") ax.add_feature(cfeature.OCEAN) ax.add_feature(cfeature.LAND) # Plot a blue dot at the north pole plt.plot([-90, -90], [90, 90], 'bo', markersize=3, transform=ccrs.Geodetic(),
def print_fit_record(self): """ Print fit level records """ fname = None if self.beams is not None and len(self.beams) > 0: fname = self.out_file_dir + "{rad}.{dn}.{start}.{end}.txt".format( rad=self.rad, dn=self.start_date.strftime("%Y%m%d"), start=self.start_date.strftime("%H%M"), end=self.end_date.strftime("%H%M")) f = open(fname, "w") print("\n Working through: ", self.rad) hdw = pydarn.read_hdw_file(self.rad) fov_obj = rad_fov.CalcFov(hdw=hdw, rsep=self.beams[0].rsep,\ ngates=self.beams[0].nrang, altitude=300.) for b in self.beams: f.write(b.time.strftime("%Y-%m-%d ")) f.write(b.time.strftime("%H:%M:%S ")) f.write(self.rad + " ") f.write(self.file_type + "\n") f.write("bmnum = " + str(b.bmnum)) f.write(" tfreq = " + str(b.tfreq)) f.write(" sky_noise_lev = " + str(round(getattr(b, "noise.sky")))) f.write(" search_noise_lev = " + str(round(getattr(b, "noise.search")))) f.write(" xcf = " + str(getattr(b, "xcf"))) f.write(" scan = " + str(getattr(b, "scan")) + "\n") f.write("npnts = " + str(len(getattr(b, "slist")))) f.write(" nrang = " + str(getattr(b, "nrang"))) f.write(" channel = " + str(getattr(b, "channel"))) f.write(" cpid = " + str(getattr(b, "cp")) + "\n") # Write the table column header f.write("{0:>4s} {13:>5s} {1:>5s} / {2:<5s} {3:>8s} {4:>3s} " "{5:>8s} {6:>8s} {7:>8s} {8:>8s} {9:>8s} {10:>8s} " "{11:>8s} {12:>8s}\n".format("gate", "pwr_0", "pwr_l", "vel", "gsf", "vel_err", "width_l", "geo_lat", "geo_lon", "geo_azm", "mag_lat", "mag_lon", "mag_azm", "range")) # Cycle through each range gate identified as having scatter in # the slist for i, s in enumerate(b.slist): lat_full = fov_obj.latFull[b.bmnum] lon_full = fov_obj.lonFull[b.bmnum] d = geoPack.calcDistPnt(lat_full[s], lon_full[s], 300, distLat=lat_full[s + 1], distLon=lon_full[s + 1], distAlt=300) gazm = d["az"] # get aacgm_coords mlat, mlon, alt = aacgmv2.convert_latlon(lat_full[s], lon_full[s], 300., b.time, method_code="G2A") mlat2, mlon2, alt2 = aacgmv2.convert_latlon( lat_full[s + 1], lon_full[s + 1], 300., b.time, method_code="G2A") d = geoPack.calcDistPnt(mlat, mlon, 300, distLat=mlat2, distLon=mlon2, distAlt=300) mazm = d["az"] f.write( "{0:4d} {13:5d} {1:>5.1f} / {2:<5.1f} {3:>8.1f} " "{4:>3d} {5:>8.1f} {6:>8.1f} {7:>8.2f} {8:>8.2f} " "{9:>8.2f} {10:>8.2f} {11:>8.2f} {12:>8.2f}\n".format( s, getattr(b, "pwr0")[i], getattr(b, "p_l")[i], getattr(b, "v")[i], getattr(b, "gflg")[i], getattr(b, "v_e")[i], getattr(b, "w_l")[i], lat_full[s], lon_full[s], gazm, mlat, mlon, mazm, getattr(b, "frang") + s * getattr(b, "rsep"))) f.write("\n") f.close() return {"fname": fname}
def test_convert_latlon_failure(self, in_rep, in_irep, msg): self.in_args.extend([300, self.dtime, "G2A"]) self.in_args[in_irep] = in_rep with pytest.raises(ValueError, match=msg): aacgmv2.convert_latlon(*self.in_args)
def test_convert_latlon(self, alt, method_code, ref): """Test single value latlon conversion""" self.in_args.extend([alt, self.dtime, method_code]) self.out = aacgmv2.convert_latlon(*self.in_args) np.testing.assert_allclose(self.out, ref, rtol=self.rtol)
def test_convert_latlon_datetime_date(self): """Test single latlon conversion with date and datetime input""" self.in_args.extend([300, self.ddate, 'TRACE']) self.out = aacgmv2.convert_latlon(*self.in_args) np.testing.assert_allclose(self.out, [58.2268,81.1613,1.0457], rtol=self.rtol)
def test_convert_latlon_time_failure(self): """Test single value latlon conversion with a bad datetime""" self.in_args.extend([300, None, 'TRACE']) with pytest.raises(ValueError): self.out = aacgmv2.convert_latlon(*self.in_args)
def test_convert_latlon_maxalt_failure(self): """test convert_latlon failure for an altitude too high for coeffs""" self.in_args.extend([2001, self.dtime, ""]) self.out = aacgmv2.convert_latlon(*self.in_args) assert np.all(np.isnan(np.array(self.out)))
def test_convert_latlon_time_failure(self): """Test single value latlon conversion with a bad datetime""" with pytest.raises(AssertionError): (self.lat_out, self.lon_out, self.r_out) = aacgmv2.convert_latlon(60, 0, 300, None)
def test_convert_latlon_lat_low_failure(self): """Test error return for co-latitudes below -90 for a single value""" with pytest.raises(ValueError): aacgmv2.convert_latlon(-91, 0, 300, self.dtime)
def data_grid_at(in_time, lookback_time, gld=None): # P_A = 5e3 # P_B = 1e5 # tpeak = np.log(P_A/P_B)/(P_A - P_B) # Ipeak = np.exp(-P_A*tpeak) - np.exp(-P_B*tpeak) # Ipeak2Io = 1.0/Ipeak Ipeak2Io = 1.2324 # Conversion between peak current and Io # (i.e., normalize the exponential terms) # Ipeak2Io = 1 # print np.shape(times_to_do) print(f"loading flashes at {in_time}") # data_grid = [] data_grid_cgm = [] data_grid_mag = [] # Ktimes, Kp = load_Kp('data/indices/Kp_1999_2018.dat') # Ktimes = [k + datetime.timedelta(minutes=90) for k in Ktimes] # 3-hour bins; the original script labeled them in the middle of the bin # Ktimes = np.array(Ktimes) # Kp = np.array(Kp) # Get Kpmax -- max value of Kp over the last 24 hours (8 bins): # Kpmax = np.max([Kp[0:-8],Kp[1:-7],Kp[2:-6], Kp[3:-5], Kp[4:-4],Kp[5:-3],Kp[6:-2], Kp[7:-1], Kp[8:]],axis=0) # Kpmtimes = Ktimes[8:] itrpl = interp1d([x.timestamp() for x in Kpmtimes], Kpmax, kind='nearest') Kpm = itrpl(in_time.timestamp()) itrpl = interp1d([x.timestamp() for x in Ktimes], Kp, kind='nearest') Kp_cur = itrpl(in_time.timestamp()) # flashes, flash_times = gld.load_flashes(in_time, lookback_time) t0 = in_time - lookback_time t1 = in_time cur_day = t0.replace(hour=0, minute=0, second=0, microsecond=0) if gld.loaded_day != cur_day: print(f'loading whole day file for {cur_day}') gld.load_day(cur_day) if len(gld.times) > 0: flashes = gld.flashes[(gld.times >=t0) & (gld.times < t1)] flash_times = gld.times[(gld.times >=t0) & (gld.times < t1)] else: flashes = None flash_times = None if flashes is not None: print(f'Loaded {np.shape(flashes)[0]} flashes') # ------------------- day / night calculation -------------------- # Threshold day / night via terminator, in geographic coordinates: is_day = np.zeros_like(flash_times, dtype='bool') t0 = in_time - lookback_time t1 = in_time dt_daynite = datetime.timedelta(minutes=10) # Timestep to generate day/nite terminator tbreaks = [datetime.datetime.fromtimestamp(x) for x in np.arange(t0.timestamp(), t1.timestamp(), dt_daynite.seconds)] for ta in tbreaks: tcenter = ta + dt_daynite/2 tb = ta + dt_daynite # print(f'{ta} and {tb}') # print(f'flash times contain dates between {min(flash_times)} and {max(flash_times)}') # print( np.where((flash_times >=ta) & (flash_times < tb))[0]) hits = np.where((flash_times >=ta) & (flash_times < tb))[0] if len(hits) > 0: local_times = flash_times[hits] # local_lats = flashes[hits,7] # local_lons = flashes[hits,8] local_lats = flashes[hits,2] local_lons = flashes[hits,3] # Get terminator, in geographic coordinates tlons, tlats, tau, dec = daynight_terminator(tcenter, 1, -180, 180) # Lon to lat interpolator interpy = interp1d(tlons, tlats,'linear', fill_value='extrapolate') thresh_lats = interpy(local_lons) # fig, ax = plt.subplots(1,1) # ax.plot(tlons, tlats) # plt.show() if dec > 0: is_day[hits] = local_lats > thresh_lats else: is_day[hits] = local_lats < thresh_lats print(f'{np.sum(is_day)} day bins, {np.sum(~is_day)} night bins') # if CGM: # ----------------------- CGM coordinates ----------------------- # pre_cgm_happy_inds = (np.abs(flashes[:,7]) < 90.) & (np.abs(flashes[:,8]) < 360.) # I_pre = np.array(flashes[:,9]) I_pre = np.array(flashes[:,4]) ft_pre = flash_times[:] # cgmlat, cgmlon = aacgmv2.convert(flashes[pre_cgm_happy_inds,7], flashes[pre_cgm_happy_inds,8], 5.0*np.ones_like(flashes[pre_cgm_happy_inds,7])) # geolats = (flashes[:, 7]) # geolons = (flashes[:, 8]) geolats = (flashes[:, 2]) geolons = (flashes[:, 3]) geoalts = (5.0*np.ones_like(geolats)).tolist() cgmlat = np.zeros([len(geolats)]) cgmlon = np.zeros([len(geolats)]) mlts = np.zeros([len(geolats)]) # Do the loop here, since the vectorized version is having trouble for x in range(len(geolats)): cgmlat[x], cgmlon[x], _ = aacgmv2.convert_latlon(geolats[x], geolons[x], 5.0, ft_pre[x], 'G2A') # Theirs is probably more correct than mine! But it's slow... # mlts[x] = aacgmv2.convert_mlt(cgmlon[x], ft_pre[x], False) mlts[x] = xf.lon2MLT(ft_pre[x], cgmlon[x]) happy_inds = ~np.isnan(cgmlat).flatten() cgmlat = cgmlat[happy_inds] cgmlon = cgmlon[happy_inds] mlts = mlts[happy_inds] is_day_tmp = is_day[happy_inds] cgmlon[cgmlon < 0] += 360. I = I_pre[happy_inds]*Ipeak2Io # print(Kpm) # print(np.shape(cgmlat), np.shape(cgmlon), np.shape(mlts), np.shape(I), Kpm, Kp_cur) # print(mlts) # print(np.shape(cgmlat), np.shape(cgmlon), np.shape(mlts), np.shape(I), np.shape(Kpm*np.ones_like(I))) data_grid_cgm = np.vstack([cgmlat, cgmlon, mlts, I, Kpm*np.ones_like(I), Kp_cur*np.ones_like(I), is_day_tmp]).T # print(data_grid[:,2]) # return data_grid # else: # ----------------------- Magnetic Dipole coordinates ----------------------- for flash, flashtime, day_flag in zip(flashes, flash_times, is_day): # glat = flash[7] # glon = flash[8] # I = flash[9]*Ipeak2Io # Added after stats_v6 # Indices from gld_whole_file glat = flash[2] glon = flash[3] I = flash[4]*Ipeak2Io # Added after stats_v6 # Get location in geomagnetic coordinates mloc = xf.rllgeo2rllmag([1.0, glat, glon], flashtime) # Get MLT: mlt = xf.lon2MLT(flashtime, mloc[2]) data_grid_mag.append([mloc[1], mloc[2], mlt, I, Kpm, Kp_cur, day_flag]) data_grid_mag = np.array(data_grid_mag) # print(data_grid[:,2]) # return data_grid return data_grid_cgm, data_grid_mag else: return None
def geolocate_radar_fov(rad, time=None): """ Geolocate each range cell Input parameters ---------------- rad <str>: Radar code time <datetime> (optional): datetime object to calculate magnetic cordinates Return parameters ----------------- _dict_ { beams <list(int)>: Beams gates <list(int)>: Gates glat [beams, gates] <np.float>: Geogarphic latitude glon [beams, gates] <np.float>: Geogarphic longitude azm [beams, gates] <np.float>: Geogarphic azimuth of ray-bearing mlat [beams, gates] <np.float>: Magnetic latitude mlon [beams, gates] <np.float>: Magnetic longitude mazm [beams, gates] <np.float>: Magnetic azimuth of ray-bearing } Calling sequence ---------------- from geopos import geolocate_radar_fov _dict_ = geolocate_radar_fov("bks") """ logger.info(f"Geolocate radar ({rad}) FoV") hdw = pydarn.read_hdw_file(rad) fov_obj = rad_fov.CalcFov(hdw=hdw, altitude=300.) blen, glen = hdw.beams, hdw.gates if glen >= 110: glen = 110 glat, glon, azm = np.zeros((blen, glen)), np.zeros((blen, glen)), np.zeros( (blen, glen)) mlat, mlon, mazm = np.zeros((blen, glen)) * np.nan, np.zeros( (blen, glen)) * np.nan, np.zeros((blen, glen)) * np.nan for i, b in enumerate(range(blen)): for j, g in enumerate(range(glen)): if j < 110: glat[i, j], glon[i, j] = fov_obj.latCenter[b, g], fov_obj.lonCenter[b, g] d = geoPack.calcDistPnt(fov_obj.latFull[b, g], fov_obj.lonFull[b, g], 300, distLat=fov_obj.latFull[b, g + 1], distLon=fov_obj.lonFull[b, g + 1], distAlt=300) azm[i, j] = d["az"] if time is not None: mlat[i, j], mlon[i, j], _ = aacgmv2.convert_latlon( fov_obj.latFull[b, g], fov_obj.lonFull[b, g], 300., time, method_code="G2A") mlat2, mlon2, _ = aacgmv2.convert_latlon( fov_obj.latFull[b, g + 1], fov_obj.lonFull[b, g + 1], 300., time, method_code="G2A") d = geoPack.calcDistPnt(mlat[i, j], mlon[i, j], 300, distLat=mlat2, distLon=mlon2, distAlt=300) mazm[i, j] = d["az"] _dict_ = { "beams": range(blen), "gates": range(glen), "glat": glat, "glon": glon, "azm": azm, "mlat": mlat, "mlon": mlon, "mazm": mazm } return _dict_