Example #1
0
    def test_get_aacgm_coord_datetime_date(self):
        """Test single AACGMV2 calculation with date and datetime input"""
        (self.mlat_out, self.mlon_out,
         self.mlt_out) = aacgmv2.get_aacgm_coord(60, 0, 300, self.ddate)
        mlat_2, mlon_2, mlt_2 = aacgmv2.get_aacgm_coord(60, 0, 300, self.dtime)

        np.testing.assert_almost_equal(self.mlat_out, mlat_2, decimal=6)
        np.testing.assert_almost_equal(self.mlon_out, mlon_2, decimal=6)
        np.testing.assert_almost_equal(self.mlt_out, mlt_2, decimal=6)

        del mlat_2, mlon_2, mlt_2
Example #2
0
def geomag_lat(alt, start_time, conv_module):
    ''' Calculates the geomagnetic lattitude data at the given alt (altitude) 
        and start_time. This function uses either Spacepy or aacgmv2 to convert 
        between geographic and geomagnetic coordinates. The moduel used to 
        convert coordinates can be selected by setting the conv_module. Make
        sure to use all lowercase for converting module. Keep in mind SpacePy 
        for some reason is not able to use 2020 data. '''
    arr = np.zeros((181, 360))
    geo_lat = np.zeros((5, 360))
    for j in range(360):
        for i in range(181):
            # Altitude is given in meters but Spacepy uses kilometers.
            coordinates = coords.Coords([alt / 1000, i - 90, j - 180], \
                                'GEO', 'sph')
            # For some reason, 2020 data could not be used.
            if conv_module == 'spacepy':
                coordinates.ticks = Ticktock(['2019-07-17T17:51:15'], 'ISO')
                arr[i][j] = coordinates.convert('MAG', 'sph').lati
            elif conv_module == 'aacgmv2':
                arr[i][j] = (np.array(aacgmv2.get_aacgm_coord(i - 90, j - 180,\
                    int(alt / 1000), start_time)))[0]
            else:
                print("Error: coordinate conversion module is invalid.\n\
                    Please choose between:\n  spacepy\n  aacgmv2\n\
                    Please use all lowercase.")
                exit()
    for j in range(360):
        for i in range(5):
            geo_lat[i, j] = closest(arr[:, j], 30 * i - 60) - 90
    return geo_lat
Example #3
0
 def test_get_aacgm_coord_location_failure(self):
     """Test single value AACGMV2 calculation with a bad location"""
     (self.mlat_out, self.mlon_out,
      self.mlt_out) = aacgmv2.get_aacgm_coord(0, 0, 0, self.dtime)
     if not (np.isnan(self.mlat_out) & np.isnan(self.mlon_out) &
             np.isnan(self.mlt_out)):
         raise AssertionError()
Example #4
0
    def test_get_aacgm_coord_location_failure(self):
        """Test single value AACGMV2 calculation with a bad location"""
        self.in_args.extend([0.0, self.dtime, 'TRACE'])
        self.in_args[0] = 0.0

        self.out = aacgmv2.get_aacgm_coord(*self.in_args)
        np.all(np.isnan(np.array(self.out)))
Example #5
0
def aacgm_coordinates(stid: int, beams: int = None, gates: tuple = None,
                      date: dt.datetime = dt.datetime.now, **kwargs):
    if gates is None:
        gates = [0, SuperDARNRadars.radars[stid].range_gate_45]
    if beams is None:
        beams = SuperDARNRadars.radars[stid].hardware_info.beams

    # Plus 1 is due to the fact fov files index at 1 so in the plotting
    # of the boundary there is a subtraction of 1 to offset this as python
    # converts to index of 0 which my code already accounts for
    beam_corners_lats = np.zeros((gates[1]-gates[0]+1, beams+1))
    beam_corners_lons = np.zeros((gates[1]-gates[0]+1, beams+1))

    for beam in range(0, beams+1):
        for gate in range(gates[0], gates[1]+1):
            lat, lon = gate2geographic_location(stid=stid, beam=beam,
                                                range_gate=gate, height=300,
                                                **kwargs)
            geomag = np.array(aacgmv2.get_aacgm_coord(glat=lat,
                                                      glon=lon,
                                                      height=250,
                                                      dtime=date))
            beam_corners_lats[gate-gates[0], beam] = geomag[0]
            beam_corners_lons[gate-gates[0], beam] = geomag[1]
    y0inx = np.min(np.where(np.isfinite(beam_corners_lats[:,0]))[0])
    return beam_corners_lats[y0inx:], beam_corners_lons[y0inx:]
Example #6
0
    def get_aacgm_geom(self, feature, out_height=300.):
        new_i = []
        # cartopy.feature.COASTLINE
        for _n, i in enumerate(feature.geometries()):
            aa = mapping(i)
            mag_list = []
            geo_coords = aa["coordinates"]
            for _ni, _list in enumerate(geo_coords):
                mlon_check_jump_list = []
                split_mag_list = None
                if len(_list) == 1:
                    _loop_list = _list[0]
                else:
                    _loop_list = _list
                for _ngc, _gc in enumerate(_loop_list):
                    _mc = aacgmv2.get_aacgm_coord(_gc[1], _gc[0], out_height,
                                                  self.plot_date)
                    if numpy.isnan(_mc[0]):
                        continue
                    mlon_check_jump_list.append(_mc[1])
                    if self.coords == "aacgmv2":
                        mag_list.append((_mc[1], _mc[0]))
                    else:
                        if _mc[2] * 15. > 180.:
                            mag_list.append((_mc[2] * 15. - 360., _mc[0]))
                        else:
                            mag_list.append((_mc[2] * 15., _mc[0]))
                # check for unwanted jumps
                mlon_check_jump_list = numpy.array(mlon_check_jump_list)

                jump_arr = numpy.diff(mlon_check_jump_list)
                bad_inds = numpy.where(numpy.abs(jump_arr) > 10.)[0]
                # delete the range of bad values
                # This is further complicated because
                # in some locations mlon jumps from -177 to +178
                # and this causes jumps in the maps! To deal with
                # this we'll split arrays of such jumps
                # (these jumps typically have just one bad ind )
                # and make them into two seperate entities (LineStrings)
                # so that shapely will treat them as two seperate boundaries!
                if len(bad_inds) > 0:
                    if len(bad_inds) > 1:
                        mag_list = [
                            i for j, i in enumerate(mag_list) if j -
                            1 not in numpy.arange(bad_inds[0], bad_inds[1])
                        ]
                    else:
                        split_mag_list = mag_list[bad_inds[0] + 1:]
                        mag_list = mag_list[:bad_inds[0] + 1]
                mag_coords = tuple(mag_list)
                if len(mag_list) > 1:
                    new_i.append(mag_coords)
                if split_mag_list is not None:
                    #             print(split_mag_list)
                    if len(split_mag_list) > 1:
                        new_i.append(tuple(split_mag_list))

        aacgm_coast = MultiLineString(new_i)
        return aacgm_coast
Example #7
0
    def test_get_aacgm_coord(self):
        """Test single value AACGMV2 calculation, defaults to TRACE"""
        (self.mlat_out, self.mlon_out,
         self.mlt_out) = aacgmv2.get_aacgm_coord(60, 0, 300, self.dtime)

        np.testing.assert_almost_equal(self.mlat_out, 58.2247, decimal=4)
        np.testing.assert_almost_equal(self.mlon_out, 81.1761, decimal=4)
        np.testing.assert_almost_equal(self.mlt_out, 0.1889, decimal=4)
Example #8
0
    def plot_radar_label(cls,
                         stid: int,
                         date: dt.datetime,
                         coords: Coords = Coords.AACGM_MLT,
                         projs: Projs = Projs.POLAR,
                         line_color: str = 'black',
                         transform: object = None,
                         **kwargs):
        """
        plots only string at the position of a given radar station ID (stid)

        Parameters
        -----------
            stid: int
                Radar station ID
            date: datetime datetime object
                sets the datetime used to find the coordinates of the
                FOV
            line_color: str
                color of the text
                default: black

        Returns
        -------
            No variables returned
        """
        # Label text
        label_str = ' ' + SuperDARNRadars.radars[stid]\
                    .hardware_info.abbrev.upper()
        # Get location of radar
        lat = SuperDARNRadars.radars[stid].hardware_info.geographic.lat
        lon = SuperDARNRadars.radars[stid].hardware_info.geographic.lon

        # Convert to geomag coords
        if coords == Coords.AACGM_MLT or coords == Coords.AACGM:
            geomag_radar = aacgmv2.get_aacgm_coord(lat, lon, 250, date)
            lat = geomag_radar[0]
            lon = geomag_radar[1]
            if coords == Coords.AACGM_MLT:
                mltshift = geomag_radar[1] -\
                        (aacgmv2.convert_mlt(geomag_radar[1], date) * 15)
                lon = geomag_radar[1] - mltshift
        if projs == Projs.POLAR:
            lon = np.radians(lon)

        theta_text = lon
        # Shift in latitude (dependent on hemisphere)
        if SuperDARNRadars.radars[stid].hemisphere == Hemisphere.North:
            r_text = lat - 5
        else:
            r_text = lat + 5
        plt.text(theta_text,
                 r_text,
                 label_str,
                 ha='center',
                 transform=transform,
                 c=line_color)
        return
Example #9
0
def calculate_magnetic_latitude(glon, glat, dtime):

    for height in arange(0, 100, 0.5):
        calclat, calclon, z = aacgmv2.get_aacgm_coord(glat, glon, height,
                                                      start)
        if np.isnan(calclat) != True:
            return calclat, calclon, height

    return nan, nan, nan
Example #10
0
def print_mag_table(st, table):
    gm = geomag.geomag.GeoMag()
    print "===== MAG ====="
    print "Time (UTC), geodetic latitude (degrees), geodetic longitude (degrees), alt (km above WGS-84 ellipsoid), magnetic declination (degrees), inclination (degrees), total intensity (nT), horizontal (nT), north (nT), east (nT), vertical (nT), magnetic latitude (degrees), magnetic longitude (degrees), magnetic local time (hours)"
    for i in range(0, len(table)):
        mag = gm.GeoMag(table[i][2], table[i][1], table[i][3]*KM_TO_FEET, datetime.date(table[i][0]))
        aacgm = aacgmv2.get_aacgm_coord(table[i][2], table[i][1], table[i][3], table[i][0])
        print "%s, %6.2f, %8.2f, %9.2f, %6.2f, %8.2f, %7.1f, %7.1f, %7.1f, %7.1f, %7.1f, %6.2f, %8.2f, %5.2f" % \
            (table[i][0], table[i][2], table[i][1], table[i][3], mag.dec, mag.dip, mag.ti, mag.bh, mag.bx, mag.by, mag.bz, aacgm[0], aacgm[1], aacgm[2])
Example #11
0
 def test_get_aacgm_coord_maxalt_failure(self):
     """For a single value, test failure for an altitude too high for
     coefficients"""
     method = ""
     (self.mlat_out, self.mlon_out,
      self.mlt_out) = aacgmv2.get_aacgm_coord(60, 0, 2001, self.dtime,
                                              method=method)
     if not (np.isnan(self.mlat_out) & np.isnan(self.mlon_out) &
             np.isnan(self.mlt_out)):
         raise AssertionError()
Example #12
0
def print_mag(st, llap):
    print("===== MAG =====")
    print("Date/Time: %s  Satellite Number: %s" % \
          (llap[0], st.get_satellite_number()))
    d = datetime.date(llap[0])
    gm = geomag.geomag.GeoMag()
    mag = gm.GeoMag(llap[2], llap[1], llap[3] * KM_TO_FEET, d)
    aacgm = aacgmv2.get_aacgm_coord(llap[2], llap[1], llap[3], llap[0])
    print("Geodetic Latitude (degrees)/Geodetic Longitude (degrees)/Altitude (km above WGS-84 ellipsoid)/Declination (degrees)/Inclination (degrees)/Total Intensity (nT)/Horizontal (nT)/North (nT)/East (nT)/Vertical (nT)/Magnetic Latitude (degrees)/Magnetic Longitude(degrees)/Magnetic Local Time (hours):  %s/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s" % \
     (llap[2], llap[1], llap[3], mag.dec, mag.dip, mag.ti, mag.bh, mag.bx, mag.by, mag.bz, aacgm[0], aacgm[1], aacgm[2]))
Example #13
0
    def test_get_aacgm_coord_badidea(self):
        """Test single value AACGMV2 calculation with a bad flag"""
        method = "BADIDEA"
        (self.mlat_out, self.mlon_out,
         self.mlt_out) = aacgmv2.get_aacgm_coord(60, 0, 3000, self.dtime,
                                                 method=method)

        np.testing.assert_almost_equal(self.mlat_out, 64.3568, decimal=4)
        np.testing.assert_almost_equal(self.mlon_out, 83.3027, decimal=4)
        np.testing.assert_almost_equal(self.mlt_out, 0.3307, decimal=4)
        del method
Example #14
0
    def test_warning_below_ground_get_aacgm_coord(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.mlat_out, self.mlon_out,
             self.mlt_out) = aacgmv2.get_aacgm_coord(60, 0, -1, self.dtime)
            if not handler.has_warning(lwarn):
                raise AssertionError()

        handler.close()
Example #15
0
def convert(date, time, intfactor, coordsystem, medfilter):
    directory = str(os.getcwd())
    directory = directory + '\\' + str(date.year) + '\\' + str(date.month) + '\\' + str(date.day)
    with np.load(directory + '\\data.npz') as data:
        tec = data['tec']        
        timeint = timeconvert(time)        
        Z = tec[:,:,timeint]
        
        Z = interpolate(Z, tec, timeint, intfactor) 
        if medfilter:
            Z = medianfilter(Z, tec, timeint)
                       
        lon = np.linspace(-180, 180, 361)
        lat = np.linspace(-90, 90, 181)
        lon2d = np.empty((180, 360))
        lat2d = np.empty((180, 360))
        lon2d[:] = np.nan
        lat2d[:] = np.nan
        if(coordsystem == 'AACGMv2'):
            for i in range(0,179):
                for j in range(0, 359):
                    lat2d[i,j], lon2d[i,j], x = aacgmv2.get_aacgm_coord(i - 90, j - 180, 350, date)
                    
            #remove jumps in longitude by rearranging matrix of lon, lat, and Z
            for row in range(0, 179):
                for element in range(0,358):
                    if (lon2d[row, element] > 0) and (lon2d[row, element+1] < 0) and (180 < (lon2d[row, element] - lon2d[row, element+1])):
                        first = lon2d[row,:element+1]
                        second = lon2d[row,element+1:]
                        lon2d[row,:] = np.append(second, first)
                        first = lat2d[row,:element+1]
                        second = lat2d[row,element+1:]
                        lat2d[row,:] = np.append(second, first)
                        first = Z[row,:element+1]
                        second = Z[row,element+1:]
                        Z[row,:] = np.append(second, first)
            return int(lat2d), int(lon2d), Z
        elif(coordsystem == 'IGRF'):
            lon = np.linspace(-180, 180, 361)
            lat = np.linspace(-90, 90, 181)
            lon2d = np.empty((180, 360))
            lat2d = np.empty((180, 360))
            lon2d[:] = np.nan
            lat2d[:] = np.nan
            for i in range(0,179):
                for j in range(0, 359):
                    _mc = geotomag(i - 90, j - 180, 350, date)
                    lat2d[i,j] = float(_mc.data[:,1])
                    lon2d[i,j] = float(_mc.data[:,2])
            return lat2d, lon2d, Z
        else:
            return lat, lon, Z#Note that return could be 1d or 2d array
Example #16
0
    def test_get_aacgm_coord_mlat_failure(self):
        """Test error return for co-latitudes above 90 for a single value"""
        import logbook
        lerr = u"unrealistic latitude"

        with logbook.TestHandler() as hhigh:
            with pytest.raises(AssertionError):
                (self.mlat_out, self.mlon_out,
                 self.mlt_out) = aacgmv2.get_aacgm_coord(91, 0, 300, self.dtime)
                if not hhigh.has_error(lerr):
                    raise AssertionError()

        with logbook.TestHandler() as hlow:
            with pytest.raises(AssertionError):
                (self.mlat_out, self.mlon_out,
                 self.mlt_out) = aacgmv2.get_aacgm_coord(-91, 0, 300,
                                                         self.dtime)
                if not hlow.has_error(lerr):
                    raise AssertionError()

        hhigh.close()
        hlow.close()
Example #17
0
    def plot_radar_position(cls,
                            stid: int,
                            date: dt.datetime,
                            transform: object = None,
                            coords: Coords = Coords.AACGM_MLT,
                            projs: Projs = Projs.POLAR,
                            line_color: str = 'black',
                            **kwargs):
        """
        plots only a dot at the position of a given radar station ID (stid)

        Parameters
        -----------
            stid: int
                Radar station ID
            date: datetime datetime object
                sets the datetime used to find the coordinates of the
                FOV
            line_color: str
                color of the dot
                default: black

        Returns
        -------
            No variables returned
        """
        # Get location of radar
        lat = SuperDARNRadars.radars[stid].hardware_info.geographic.lat
        lon = SuperDARNRadars.radars[stid].hardware_info.geographic.lon
        # Convert to geomag coords
        if coords == Coords.AACGM_MLT or coords == Coords.AACGM:
            geomag_radar = aacgmv2.get_aacgm_coord(lat, lon, 250, date)
            lat = geomag_radar[0]
            lon = geomag_radar[1]
            if coords == Coords.AACGM_MLT:
                mltshift = geomag_radar[1] -\
                        (aacgmv2.convert_mlt(geomag_radar[1], date) * 15)
                lon = geomag_radar[1] - mltshift
        if projs == Projs.POLAR:
            lon = np.radians(lon)
        # Plot a dot at the radar site
        plt.scatter(lon, lat, c=line_color, s=5, transform=transform)
        return
Example #18
0
 def test_get_aacgm_coord_time_failure(self):
     """Test single value AACGMV2 calculation with a bad datetime"""
     with pytest.raises(AssertionError):
         (self.mlat_out, self.mlon_out,
          self.mlt_out) = aacgmv2.get_aacgm_coord(60, 0, 300, None)
Example #19
0
def geo_lat(LAT, LON, ALT, start_time):
    for i in range(120):
        for j in range(61):
            print(
                np.array(
                    aacgmv2.get_aacgm_coord(3 * j - 90, i, ALT, start_time)))
Example #20
0
 def test_get_aacgm_coord_raise_value_error(self, in_index, value):
     """Test different ways to raise a ValueError"""
     self.in_args.extend([300.0, self.dtime])
     self.in_args[in_index] = value
     with pytest.raises(ValueError):
         self.out = aacgmv2.get_aacgm_coord(*self.in_args)
Example #21
0
 def test_get_aacgm_coord(self, alt, method_code, ref):
     """Test single value AACGMV2 calculation, defaults to TRACE"""
     self.in_args.extend([alt, self.dtime, method_code])
     self.out = aacgmv2.get_aacgm_coord(*self.in_args)
     np.testing.assert_allclose(self.out, ref, rtol=self.rtol)
Example #22
0
def radar_fov(stid: int, coords: str = 'aacgm', date: datetime = None):
    """
	Returning beam/gate coordinates of a specified radar's field-of-view

	Parameters
	----------
	stid: int
		Station ID of radar of choice. See 'superdarn.ca/radar-info' for ID numbers.
	coords: str
		Type of coordinates returned. 'geo' = Geographic, 'aacgm' = AACGMv2
		Default: 'aacgm'
	date: datetime 
		datetime object date to be used for AACGMv2 conversion
		Default: Current day
 
	Returns 
	----------
	latitudes: np.array
		n_beams x n_gates array of geographic or AACGMv2 latitudes for range gate
		corners   	
	longitudes/mlts: np.array 
		n_beams x n_gates array of geographic or AACGMv2 longitudes for range gate 
		corners
	 """

    # Locate base PyDARN directory
    my_path = os.path.abspath(os.path.dirname(__file__))
    base_path = os.path.join(my_path, '..')

    # Find files holding radar beam/gate locations
    beam_lats = base_path+'/radar_fov_files/' + \
     str(stid).zfill(3)+'_lats.txt'
    beam_lons = base_path+'/radar_fov_files/' + \
     str(stid).zfill(3)+'_lons.txt'

    # Read in geographic coordinates
    beam_corners_lats = np.loadtxt(beam_lats)
    beam_corners_lons = np.loadtxt(beam_lons)

    # AACGMv2 conversion
    if coords == 'aacgm':
        if not date:
            date = datetime.datetime.now()

        # Initialise arrays
        fan_shape = beam_corners_lons.shape
        beam_corners_aacgm_lons = np.zeros((fan_shape[0], fan_shape[1]))
        beam_corners_aacgm_lats = np.zeros((fan_shape[0], fan_shape[1]))

        for x in range(fan_shape[0]):
            for y in range(fan_shape[1]):

                # Conversion
                geomag = np.array(
                    aacgmv2.get_aacgm_coord(beam_corners_lats[x, y],
                                            beam_corners_lons[x,
                                                              y], 250, date))

                beam_corners_aacgm_lats[x, y] = geomag[0]
                beam_corners_aacgm_lons[x, y] = geomag[1]

        # Return AACGMv2 latitudes and longitudes
        return beam_corners_aacgm_lats, beam_corners_aacgm_lons
    else:
        # Return geographic coordinates
        return beam_corners_lats, beam_corners_lons
Example #23
0
 def test_get_aacgm_coord_datetime_date(self):
     """Test single AACGMV2 calculation with date and datetime input"""
     self.in_args.extend([300.0, self.ddate, 'TRACE'])
     self.out = aacgmv2.get_aacgm_coord(*self.in_args)
     np.testing.assert_allclose(self.out, [58.2268,81.1613,0.1888],
                                rtol=self.rtol)
Example #24
0
import aacgmv2
import datetime as dt
import numpy as np
import pandas as pd

np.set_printoptions(formatter={"float_kind": lambda x: "{:.2f}".format(x)})
dtime = dt.datetime(2013, 11, 3)
x = pd.read_csv("csv/radar.csv")

for rad, lat, lon in zip(x.rad, x.lat, x.lon):
    print("Rad(%s)" % rad,
          np.array(aacgmv2.get_aacgm_coord(lat, lon, 300, dtime)))

y = pd.read_csv("csv/riometer_details.csv")
for rio, lat, lon in zip(y.RIO, y.LAT, y.LON):
    print("Rio(%s)" % rio, (lat, np.round(np.mod((lon + 180), 360) - 180, 2)),
          np.array(aacgmv2.get_aacgm_coord(lat, lon, 300, dtime)))
Example #25
0
def add_aacgm_coordinates(inst,
                          glat_label='glat',
                          glong_label='glong',
                          alt_label='alt'):
    """ 
    Uses AACGMV2 package to add AACGM coordinates to instrument object.
    
    The Altitude Adjusted Corrected Geomagnetic Coordinates library is used
    to calculate the latitude, longitude, and local time
    of the spacecraft with respect to the geomagnetic field.
    
    Example
    -------
        # function added velow modifies the inst object upon every inst.load call
        inst.custom.add(add_quasi_dipole_coordinates, 'modify', glat_label='custom_label')
    
    Parameters
    ----------
    inst : pysat.Instrument
        Designed with pysat_sgp4 in mind
    glat_label : string
        label used in inst to identify WGS84 geodetic latitude (degrees N)
    glong_label : string
        label used in inst to identify WGS84 geodetic longitude (degrees E)
    alt_label : string
        label used in inst to identify WGS84 geodetic altitude (km, height above surface)
        
    Returns
    -------
    inst
        Input pysat.Instrument object modified to include quasi-dipole coordinates, 'aacgm_lat'
        for magnetic latitude, 'aacgm_long' for longitude, and 'aacgm_mlt' for magnetic local time.
        
    """

    import aacgmv2

    aalat = []
    aalon = []
    mlt = []
    for lat, lon, alt, time in zip(inst[glat_label], inst[glong_label],
                                   inst[alt_label], inst.data.index):
        # aacgmv2 latitude and longitude from geodetic coords
        tlat, tlon, tmlt = aacgmv2.get_aacgm_coord(lat, lon, alt, time)
        aalat.append(tlat)
        aalon.append(tlon)
        mlt.append(tmlt)

    inst['aacgm_lat'] = aalat
    inst['aacgm_long'] = aalon
    inst['aacgm_mlt'] = mlt

    inst.meta['aacgm_lat'] = {
        'units': 'degrees',
        'long_name': 'AACGM latitude'
    }
    inst.meta['aacgm_long'] = {
        'units': 'degrees',
        'long_name': 'AACGM longitude'
    }
    inst.meta['aacgm_mlt'] = {
        'units': 'hrs',
        'long_name': 'AACGM Magnetic local time'
    }

    return
Example #26
0
def occ_full_circle(station,
                    year,
                    month_range=None,
                    day_range=None,
                    gate_range=None,
                    beam_range=None,
                    time_units='mlt',
                    plot_type='contour',
                    local_testing=False):
    """

    Produce a full circle stereographic plot in either ut or mlt (12 at the top).
    Can plot a simple echo count, ground scatter count, or average a fitACF parameter over the provided time range.

    Notes:
        - This program was originally written to be run on maxwell.usask.ca.  This decision was made because
            occurrence investigations often require chewing large amounts of data.
        - Does not distinguish frequency
        - Only considers 45 km data.
            (a warning will be printed if other spatial resolution data is stripped from the dataset)
        - This program uses fitACF 3.0 data.  To change this, modify the source code.

    :param station: str:
            The radar station to consider, a 3 character string (e.g. "rkn").
            For a complete listing of available stations, please see https://superdarn.ca/radar-info
    :param year: int:
            The year to consider.
    :param month_range: (<int>, <int>) (optional):
            Inclusive. The months of the year to consider.  If omitted (or None), then all days will be considered.
    :param day_range: (<int>, <int>) (optional):
            Inclusive. The days of the month to consider.  If omitted (or None), then all days will be considered.
    :param gate_range: (<int>, <int>) (optional):
            Inclusive. The gate range to consider.  If omitted (or None), then all the gates will be considered.
            Note that gates start at 0, so gates (0, 3) is 4 gates.
    :param beam_range: (<int>, <int>) (optional):
            Inclusive. The beam range to consider.  If omitted (or None), then all beams will be considered.
            Note that beams start at 0, so beams (0, 3) is 4 beams.
    :param time_units: str: 'ut' for universal time or 'mlt' for magnetic local time:
            The time units to plot on the circle, 12 is always at the top.  Default is 'mlt'
    :param plot_type: str (optional):
            The type of plot, either 'contour' or 'pixel', default is 'contour'
    :param local_testing: bool (optional):
            Set this to true if you are testing on your local machine.  Program will then use local dummy data.
    :return: matplotlib.pyplot.figure: The figure.
            It can then be modified, added to, printed out, or saved in whichever file format is desired.
    """

    time_units = check_time_units(time_units)
    year = check_year(year)

    all_radars_info = SuperDARNRadars()
    this_radars_info = all_radars_info.radars[pydarn.read_hdw_file(
        station).stid]  # Grab radar info
    radar_id = this_radars_info.hardware_info.stid
    hemisphere = this_radars_info.hemisphere
    radar_lon = this_radars_info.hardware_info.geographic.lon
    radar_lat = this_radars_info.hardware_info.geographic.lat

    gate_range = check_gate_range(gate_range, this_radars_info.hardware_info)
    beam_range = check_beam_range(beam_range, this_radars_info.hardware_info)

    print("Retrieving data...")
    df = get_data_handler(station,
                          year_range=(year, year),
                          month_range=month_range,
                          day_range=day_range,
                          gate_range=gate_range,
                          beam_range=beam_range,
                          occ_data=True,
                          local_testing=local_testing)
    df = only_keep_45km_res_data(df)

    # To compute mlt we need longitudes.. use the middle of the month as magnetic field estimate
    date_time_est, _ = build_datetime_epoch(year, 6, 15, 0)

    print("Computing MLTs for " + str(year) + " data...")
    cell_corners_aacgm_lats, cell_corners_aacgm_lons = radar_fov(
        stid=radar_id, coords='aacgm', date=date_time_est)

    df = add_mlt_to_df(cell_corners_aacgm_lons=cell_corners_aacgm_lons,
                       cell_corners_aacgm_lats=cell_corners_aacgm_lats,
                       df=df)

    # Get our raw x-data
    if time_units == "mlt":
        df['xdata'] = df['mlt']

    else:
        print("Computing UTs for " + str(year) + " data...")

        ut_time = []
        for i in range(len(df)):
            ut_time_here = df['datetime'].iat[i].hour + df['datetime'].iat[i].minute / 60 + \
                           df['datetime'].iat[i].second / 3600

            if ut_time_here > 24:
                ut_time_here = ut_time_here - 24
            elif ut_time_here < 0:
                ut_time_here = ut_time_here + 24

            ut_time.append(ut_time_here)

        df['xdata'] = np.asarray(ut_time)

    print("Preparing the plot...")
    fig = plt.figure(figsize=(5, 5), dpi=300)
    lat_extreme = 40 * hemisphere.value  # deg
    if hemisphere.value == 1:
        ax = fig.add_subplot(1, 1, 1, projection=ccrs.NorthPolarStereo())
    elif hemisphere.value == -1:
        ax = fig.add_subplot(1, 1, 1, projection=ccrs.SouthPolarStereo())
    else:
        raise Exception("hemisphere not recognized")

    ax.set_extent([-180, 180, hemisphere.value * 90, lat_extreme],
                  crs=ccrs.PlateCarree())

    # Compute a circle in axis coordinates which can be used as a boundary
    theta = np.linspace(0, 2 * np.pi, 100)
    center, radius = [0.5, 0.5], 0.5
    vertices = np.vstack([np.sin(theta), np.cos(theta)]).T
    circle = mpath.Path(vertices * radius + center)
    ax.set_boundary(circle, transform=ax.transAxes)

    # Add gridlines and mlt labels
    text_offset_multiplier = 1.03
    gl = ax.gridlines(draw_labels=True, linestyle='--', zorder=5)
    gl.xlocator = mticker.FixedLocator([-180, -135, -90, -45, 0, 45, 90, 135])
    gl.xformatter = LONGITUDE_FORMATTER
    gl.yformatter = LATITUDE_FORMATTER

    # Print clock numbers
    ax.text(0,
            text_offset_multiplier * ax.get_ylim()[1],
            "12",
            ha='center',
            va='bottom')
    ax.text(0,
            text_offset_multiplier * ax.get_ylim()[0],
            "00",
            ha='center',
            va='top')
    ax.text(text_offset_multiplier * ax.get_xlim()[1],
            0,
            "06",
            ha='left',
            va='center')
    ax.text(text_offset_multiplier * ax.get_xlim()[0],
            0,
            "18",
            ha='right',
            va='center')

    # Print time units
    ax.text(text_offset_multiplier * ax.get_xlim()[0],
            text_offset_multiplier * ax.get_ylim()[1],
            time_units.upper(),
            ha='left',
            va='bottom')

    # Convert radar coordinates to aacgm and plot radar track
    radar_lat_aacgm, radar_lon_aacgm, radar_mlt = get_aacgm_coord(
        radar_lat, radar_lon, 0, date_time_est)
    radar_mlts = np.arange(0, 360, 1)
    radar_lats_aacgm = np.asarray([radar_lat_aacgm] * len(radar_mlts))
    ax.plot(radar_mlts,
            radar_lats_aacgm,
            color='k',
            linewidth=0.5,
            linestyle="--",
            transform=ccrs.Geodetic(),
            label="Radar Path")

    # Right now xdata is in the range 0-24, we need to put it in the range 0-360 for circular plotting
    df['xdata'] = 15 * df['xdata']

    print("Computing binned occ rates...")
    # Compute mlt edges
    deg_mlt_per_bin = 2
    n_bins_mlt = int(360 / deg_mlt_per_bin)
    mlt_edges = np.linspace(0, 360, num=(n_bins_mlt + 1))
    delta_mlt = mlt_edges[1] - mlt_edges[0]

    # Compute latitude edges
    n_bins_lat = 90 - abs(lat_extreme)  # One bin per degree of latitude
    lat_edges = np.linspace(lat_extreme, 90, num=(n_bins_lat + 1))
    delta_lat = lat_edges[1] - lat_edges[0]

    contour_data = np.empty(shape=(n_bins_mlt, n_bins_lat))
    contour_data[:] = math.nan

    for mlt_idx, start_mlt in enumerate(mlt_edges):
        if start_mlt == mlt_edges[-1]:
            continue  # The last edge is not a start
        end_mlt = start_mlt + delta_mlt
        df_mlt = df[(df['xdata'] >= start_mlt) & (df['xdata'] <= end_mlt)]

        for lat_idx, start_lat in enumerate(lat_edges):
            if start_lat == lat_edges[-1]:
                continue  # The last edge is not a start

            end_lat = start_lat + delta_lat
            df_mlt_lat = df_mlt[(df_mlt['lat'] >= start_lat)
                                & (df_mlt['lat'] <= end_lat)]

            try:
                contour_data[mlt_idx][lat_idx] = sum(
                    df_mlt_lat['good_echo']) / len(df_mlt_lat)
            except ZeroDivisionError:
                # There are no point in this interval
                contour_data[mlt_idx, lat_idx] = math.nan
            except BaseException as e:
                print("MLT index: " + str(mlt_idx))
                print("LAT index: " + str(lat_idx))
                raise e

    contour_range = [[0, 360], [hemisphere.value * 37, hemisphere.value * 90]]

    # Compute bin centers
    bin_xwidth = (mlt_edges[1] - mlt_edges[0])
    bin_ywidth = (lat_edges[1] - lat_edges[0])
    bin_xcenters = mlt_edges[1:] - bin_xwidth / 2
    bin_ycenters = lat_edges[1:] - bin_ywidth / 2

    levels = 12
    levels = np.linspace(start=0, stop=1, num=(levels + 1))
    if plot_type == "contour":
        plot = ax.contourf(bin_xcenters,
                           bin_ycenters,
                           contour_data.transpose(),
                           cmap='jet',
                           levels=levels,
                           transform=ccrs.PlateCarree())

    elif plot_type == "pixel":
        plot = ax.imshow(np.flip(contour_data.transpose(), axis=0),
                         aspect='auto',
                         cmap="jet",
                         transform=ccrs.PlateCarree())

    else:
        raise Exception("plot_type not recognized")

    cbar = fig.colorbar(plot,
                        ax=ax,
                        shrink=0.75,
                        orientation="horizontal",
                        format='%.2f')
    cbar.ax.tick_params(labelsize=14, labelrotation=30)

    return df, fig
Example #27
0
 def test_get_aacgm_coord_maxalt_failure(self):
     """test get_aacgm_coord failure for an altitude too high for coeffs"""
     self.in_args.extend([2001, self.dtime, ""])
     self.out = aacgmv2.get_aacgm_coord(*self.in_args)
     assert np.all(np.isnan(np.array(self.out)))