Esempio n. 1
0
    def to_APEX(self, append_mlt=False, **kwargs):
        import apexpy as apex
        from geospacelab.cs._apex import APEX

        cs_in = self

        ut_type = type(cs_in.ut)
        if ut_type is list:
            uts = np.array(cs_in.ut)
        elif ut_type is np.ndarray:
            uts = cs_in.ut

        mlt = None
        if issubclass(self.ut.__class__, datetime.datetime):
            apex_obj = apex.Apex(cs_in.ut)
            mlat, mlon = apex_obj.convert(
                cs_in.coords.lat,
                cs_in.coords.lon,
                'geo',
                'apex',
                height=cs_in.coords.height,
            )
            if append_mlt:
                mlt = apex_obj.mlon2mlt(mlon, cs_in.ut)
        else:
            if uts.shape[0] != cs_in.coords.lat.shape[0]:
                mylog.StreamLogger.error(
                    "Datetimes must have the same length as cs!")
                return

            mlat = np.empty_like(cs_in.coords.lat)
            mlon = np.empty_like(cs_in.coords.lat)
            mlt = np.empty_like(cs_in.coords.lat)
            for ind_dt, dt in enumerate(uts.flatten()):
                # print(ind_dt, dt, cs.lat[ind_dt, 0])
                apex_obj = apex.Apex(dt)
                mlat[ind_dt], mlon[ind_dt] = apex_obj.convert(
                    cs_in.coords.lat[ind_dt],
                    cs_in.coords.lon[ind_dt],
                    'geo',
                    'apex',
                    height=cs_in.coords.height[ind_dt])
                if append_mlt:
                    mlt[ind_dt] = apex_obj.mlon2mlt(mlon[ind_dt], dt)

        cs_new = APEX(coords={
            'lat': mlat,
            'lon': mlon,
            'height': cs_in.coords.height,
            'mlt': mlt
        },
                      ut=cs_in.ut)

        return cs_new
Esempio n. 2
0
def getMagneticProperties(Time, GeodeticLat, GeodeticLon, Altitude):
    apObj = ap.Apex(Time)
    if GeodeticLon > 180: GeodeticLon -= 360
    MagneticLatitude, MagneticLongitude = apObj.geo2qd(
        GeodeticLat, GeodeticLon, Altitude
    )  # geo2qd return quasi-dipole coordiantes - geo2apex returns modified apex coordinates
    MagneticLocalTime = apObj.mlon2mlt(MagneticLongitude, Time)
    return MagneticLatitude, MagneticLongitude, MagneticLocalTime
Esempio n. 3
0
def main():
    """Entry point for the script"""

    desc = 'Converts between geodetic, modified apex, quasi-dipole and MLT'
    parser = argparse.ArgumentParser(description=desc, prog='apexpy')

    parser.add_argument('source', metavar='SOURCE',
                        choices=['geo', 'apex', 'qd', 'mlt'],
                        help='Convert from {geo, apex, qd, mlt}')
    parser.add_argument('dest', metavar='DEST',
                        choices=['geo', 'apex', 'qd', 'mlt'],
                        help='Convert to {geo, apex, qd, mlt}')
    desc = 'YYYY[MM[DD[HHMMSS]]] date/time for IGRF coefficients, time part '
    desc += 'required for MLT calculations'
    parser.add_argument('date', metavar='DATE', help=desc)
    parser.add_argument('--height', dest='height', default=0, metavar='HEIGHT',
                        type=float, help='height for conversion')
    parser.add_argument('--refh', dest='refh', metavar='REFH', type=float,
                        default=0,
                        help='reference height for modified apex coordinates')

    parser.add_argument('-i', '--input', dest='file_in', metavar='FILE_IN',
                        type=argparse.FileType('r'), default=STDIN,
                        help='input file (stdin if none specified)')
    parser.add_argument('-o', '--output', dest='file_out', metavar='FILE_OUT',
                        type=argparse.FileType('wb'), default=STDOUT,
                        help='output file (stdout if none specified)')

    args = parser.parse_args()

    array = np.loadtxt(args.file_in, ndmin=2)

    if 'mlt' in [args.source, args.dest] and len(args.date) < 14:
        desc = 'full date/time YYYYMMDDHHMMSS required for MLT calculations'
        raise ValueError(desc)
    if 9 <= len(args.date) <= 13:
        desc = 'full date/time must be given as YYYYMMDDHHMMSS, not ' + \
               'YYYYMMDDHHMMSS'[:len(args.date)]
        raise ValueError(desc)
    datetime = dt.datetime.strptime(args.date,
                                    '%Y%m%d%H%M%S'[:len(args.date)-2])
    A = apexpy.Apex(date=datetime, refh=args.refh)
    lats, lons = A.convert(array[:, 0], array[:, 1], args.source, args.dest,
                           args.height, datetime=datetime)
    np.savetxt(args.file_out, np.column_stack((lats, lons)), fmt='%.8f')
Esempio n. 4
0
def plotSlice(im=None, t=None, time=None,  latline=None, lonline=None, line=None, skip=None, average=False,
              magnetic=False, ax=False, figsize=None, conjugate=True, height=350):

    lat = np.arange(-90,90)
    lon = np.arange(-180,180)

    def conjugate_img(img):
        nanind = np.where(np.isnan(img))
        nanindices = list(zip(nanind[0], nanind[1]))
        conj = img
        for nanindex in nanindices:
            conj[nanindex] = np.flipud(img)[nanindex]
        return conj

    im = np.array(im)
    A = ap.Apex(date=t[0])

    with warnings.catch_warnings():
        warnings.simplefilter("ignore", category=RuntimeWarning)
        if magnetic is False:  # geo
            if latline is None:
                y = range(-90, 90)
                lonline += 180
                if average:
                    image = np.nanmean(np.array([[im[0:, lonline % 360, 0:]], [im[0:, ((lonline+1) % 360), 0:]],
                                       [im[0:, ((lonline-1) % 360), 0:]]]), axis=0)
                    image = np.squeeze(image)  # remove singular dimension
                else:
                    image = np.array(im)[0:, lonline % 360, 0:]
            elif lonline is None:
                y = range(-180, 180)
                latline += 90
                if average:
                    image = np.nanmean(np.array([[im[0:, 0:, latline % 180]], [im[0:, 0:, (latline+1) % 180]],
                                       [im[0:, 0:, (latline-1) % 180]]]), axis=0)
                    image = np.squeeze(image)
                else:
                    image = np.array(im)[0:, 0:, latline % 180]
            image = np.flipud(np.rot90(image))

        else:  # magnetic
            indexmake = np.vectorize(lambda x: int(round(x)))
            image = np.array([])
            mask = np.zeros((im.shape[2], im.shape[1]), dtype=bool)

            if latline is None:  # longitude
                y = range(-90, 90)
                lat_ind, lon_ind = np.round(A.convert(range(-90, 90), lonline, 'apex', 'geo'))
                indices = indexmake(np.array(list(zip(lat_ind + 90, lon_ind + 180))))
                indices = list(map(tuple, indices))

                for index in indices:
                    mask[index[0] % 180, index[1] % 360] = True
                mask = np.rot90(mask)

                if average:
                    for index in indices:
                        image = np.append(image, np.nanmean([[im[0:, index[1] % 360, index[0] % 180]],
                                                            [im[0:, (index[1] + 1) % 360, index[0] % 180]],
                                                            [im[0:, (index[1] - 1) % 360, index[0] % 180]]], axis=0))
                else:
                    for index in indices:
                        image = np.append(image, im[0:, index[1], index[0]])

                image = np.reshape(image, (len(image) // len(t), len(t)))

                if conjugate:
                    image = conjugate_img(image)

            elif lonline is None:  # latitude
                lat_ind, lon_ind = np.round(A.convert(latline, range(-180, 180), 'apex', 'geo'))
                indices = indexmake(np.array(list(zip(lat_ind + 90, lon_ind + 180))))
                indices = list(map(tuple, indices))
                y = range(-180, 180)

                for index in indices:
                    mask[index[0] % 180, index[1] % 360] = True

                mask = np.rot90(mask)

                if average:
                    for index in indices:
                        image = np.append(image, np.nanmean([[im[0:, index[1] % 360, index[0] % 180]],
                                                             [im[0:, index[1] % 360, (index[0] + 1) % 180]],
                                                             [im[0:, index[1] % 360, (index[0] - 1) % 180]]], axis=0))
                else:
                    for index in indices:
                        image = np.append(image, im[0:, index[1] % 360, index[0] % len(t)])
                image = np.reshape(image, (len(image) // len(t), len(t)))

    t = list(map(datetime.fromtimestamp, t))

    if skip is not None:
        image = image[::skip]

    if not ax:
        if figsize is None:
            fig = plt.figure()
        else:
            fig = plt.figure(figsize=figsize)
        ax = fig.gca()

    if time is not None:
        sl = np.squeeze(image[:, time])
    else:
        sl = np.squeeze(image[:, 0])
        print('No time entered (default 0)')
    nanmask = np.isfinite(sl)

    if latline is None:
        x_ax = lat[nanmask]
        plt.xlabel('Latitude')
    else:
        x_ax = lon[nanmask]
        plt.xlabel('Longitude')
    plt.plot(x_ax, sl[nanmask])
    plt.plot(x_ax, sl[nanmask], 'rx')
    plt.ylabel('TECu')

    if 'fig' in locals():
        return fig, ax, x_ax, sl[nanmask]
    else:
        return ax, x_ax, sl[nanmask]
Esempio n. 5
0
def plotCartoMap(latlim=None, lonlim=None, parallels=None, meridians=None,
                 pole_center_lon=0, figsize=(12, 8), terrain=False, ax=False,
                 projection='stereo', title='', resolution='110m',
                 states=True, grid_linewidth=0.5, grid_color='black',
                 grid_linestyle='--', background_color=None, border_color='k',
                 figure=False, nightshade=False, ns_dt=None, ns_alpha=0.1,
                 apex=False, igrf=False, date=None,
                 mlat_levels=None, mlon_levels=None, alt_km=0.0,
                 mlon_colors='blue', mlat_colors='red', mgrid_width=1,
                 mgrid_labels=True, mgrid_fontsize=12, mlon_cs='mlon',
                 incl_levels=None, decl_levels=None, igrf_param='incl',
                 mlon_labels=True, mlat_labels=True, mgrid_style='--',
                 label_colors='k',
                 decl_colors='k', incl_colors='k'):

    if lonlim is None:
        if projection in ['southpole', 'northpole']:
            lonlim = [-180, 180]
        else:
            lonlim = [-40, 40]
    if latlim is None:
        if projection is'southpole':
            latlim = [-90, 0]
        elif projection is 'northpole':
            latlim = [90, 0]
        else:
            latlim = [0, 75]

    STATES = cfeature.NaturalEarthFeature(
        category='cultural',
        name='admin_1_states_provinces_lines',
        scale='50m',
        facecolor='none')

    if not ax:
        if figsize is None:
            fig = plt.figure()
        else:
            fig = plt.figure(figsize=figsize)

        if projection == 'stereo':
            ax = plt.axes(projection=ccrs.Stereographic(central_longitude=(sum(lonlim) / 2)))
        elif projection == 'merc':
            ax = plt.axes(projection=ccrs.Mercator())
        elif projection == 'plate':
            ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=(sum(lonlim) / 2)))
        elif projection == 'lambert':
            ax = plt.axes(projection=ccrs.LambertConformal(central_longitude=(sum(lonlim) / 2),
                                                           central_latitude=(sum(latlim) / 2)))
        elif projection == 'mollweide':
            ax = plt.axes(projection=ccrs.Mollweide(central_longitude=(sum(lonlim) / 2)))
        elif projection == 'northpole':
            ax = plt.axes(projection=ccrs.NorthPolarStereo())
            ax.set_boundary(circle, transform=ax.transAxes)
            # polarLim(ax, projection)
        elif projection == 'southpole':
            ax = plt.axes(projection=ccrs.SouthPolarStereo())
            ax.set_boundary(circle, transform=ax.transAxes)
            # polarLim(ax, projection)
    if background_color is not None:
        ax.background_patch.set_facecolor(background_color)
    ax.set_title(title)
    ax.coastlines(color=border_color, resolution=resolution)  # 110m, 50m or 10m
    if states:
        ax.add_feature(STATES, edgecolor=border_color)
    ax.add_feature(cfeature.BORDERS, edgecolor=border_color)
    if terrain:
        ax.stock_img()
    if nightshade:
        assert ns_dt is not None
        assert ns_alpha is not None
        ax.add_feature(Nightshade(ns_dt, ns_alpha))
    # Draw Parallels
    if projection == 'merc' or projection == 'plate':
        if isinstance(meridians, np.ndarray):
            meridians = list(meridians)
        if isinstance(parallels, np.ndarray):
            parallels = list(parallels)

        gl = ax.gridlines(crs=ccrs.PlateCarree(), color=grid_color, draw_labels=False,
                          linestyle=grid_linestyle, linewidth=grid_linewidth)
        if meridians is None:
            gl.xlines = False
        else:
            if len(meridians) > 0:
                gl.xlocator = mticker.FixedLocator(meridians)
                gl.xlabels_bottom = True
            else:
                gl.ylines = False

        if parallels is None:
            gl.ylines = False
        else:
            if len(parallels) > 0:
                gl.ylocator = mticker.FixedLocator(parallels)
                #                ax.yaxis.set_major_formatter(LONGITUDE_FORMATTER)
                gl.ylabels_left = True
            else:
                gl.ylines = False
    else:
        gl = ax.gridlines(crs=ccrs.PlateCarree(), color=grid_color, draw_labels=False,
                          linestyle=grid_linestyle, linewidth=grid_linewidth)
        if meridians is None:
            gl.xlines = False
        else:
            #            if isinstance(meridians, np.ndarray):
            #                meridians = list(meridians)
            #            ax.xaxis.set_major_formatter(LONGITUDE_FORMATTER)
            #            ax.yaxis.set_major_formatter(LATITUDE_FORMATTER)
            #            if isinstance(meridians, np.ndarray):
            #                meridians = list(meridians)
            gl.xlocator = mticker.FixedLocator(meridians)
        #        else:
        #            gl.xlines = False
        if parallels is not None:
            if isinstance(parallels, np.ndarray):
                parallels = list(parallels)
            gl.ylocator = mticker.FixedLocator(parallels)
        else:
            gl.ylines = False

    # Geomagnetic coordinates @ Apex
    if apex:
        if date is None:
            date = datetime(2017, 12, 31, 0, 0, 0)
        assert isinstance(date, datetime)

        A = ap.Apex(date=date)
        # Define levels and ranges for conversion
        if mlon_cs == 'mlt':
            if mlon_levels is None:
                mlon_levels = np.array([])
                mlon_range = np.arange(0, 24.1, 0.1)
            elif isinstance(mlon_levels, bool):
                if mlon_levels == False:
                    mlon_levels = np.array([])
                    mlon_range = np.arange(0, 24.1, 0.1)
            else:
                mlon_range = np.arange(mlon_levels[0], mlon_levels[-1] + 0.1, 0.1)
        else:
            if mlon_levels is None:
                mlon_levels = np.array([])
                mlon_range = np.arange(-180, 180, 0.5)
            elif isinstance(mlon_levels, bool):
                if mlon_levels == False:
                    mlon_levels = np.array([])
                    mlon_range = np.arange(-180, 181, 0.1)
            else:
                mlon_range = np.arange(mlon_levels[0], mlon_levels[0] + 362, 0.1)
        if mlat_levels is None:
            mlat_levels = np.arange(-90, 90.1, 5)
        mlat_range = np.arange(mlat_levels[0], mlat_levels[-1] + 0.1, 0.1)
        # Do meridans
        for mlon in mlon_levels:
            MLON = mlon * np.ones(mlat_range.size)
            if mlon_cs == 'mlt':
                y, x = A.convert(mlat_range, MLON, 'mlt', 'geo', datetime=date)
            else:
                y, x = A.convert(mlat_range, MLON, 'apex', 'geo')
            # Plot meridian
            inmap = np.logical_and(x >= lonlim[0], x <= lonlim[1])
            if np.sum(inmap) > 10:
                ax.plot(np.unwrap(x, 180), np.unwrap(y, 90), c=mlon_colors,
                        lw=mgrid_width, linestyle=mgrid_style,
                        transform=ccrs.PlateCarree())

            # Labels
            if mlon_labels:
                ix = np.argmin(abs(y - np.mean(latlim)))
                mx = x[ix] - 1 if mlon >= 10 else x[ix] - 0.5
                my = np.mean(latlim)
                if np.logical_and(mx >= lonlim[0], mx <= lonlim[1]):
                    if mlon_cs == 'mlt' and mlon != 0:
                        ax.text(mx, my, str(int(mlon)), color=label_colors,
                                fontsize=14, backgroundcolor='white',
                                transform=ccrs.PlateCarree())
                    elif mlon_cs != 'mlt' and mlon != 360:
                        ax.text(mx, my, str(int(mlon)), color=label_colors,
                                fontsize=14, backgroundcolor='white',
                                transform=ccrs.PlateCarree())
        # Do parallels
        for mlat in mlat_levels:
            MLAT = mlat * np.ones(mlon_range.size)
            if mlon_cs == 'mlt':
                gy, gx = A.convert(MLAT, mlon_range, 'mlt', 'geo', datetime=date)
            else:

                gy, gx = A.convert(MLAT, mlon_range, 'apex', 'geo', datetime=date)
            inmap = np.logical_and(gy >= latlim[0], gy <= latlim[1])
            if np.sum(inmap) > 2:
                ax.plot(np.unwrap(gx, 180), np.unwrap(gy, 90), c=mlat_colors,
                        lw=mgrid_width, linestyle=mgrid_style,
                        transform=ccrs.PlateCarree())

            # Labels
            if mlat_labels:
                ix = np.argmin(abs(gx - np.mean(lonlim)))
                mx = np.mean(lonlim)
                my = gy[ix] - 0.5
                if np.logical_and(mx >= lonlim[0], mx <= lonlim[1]) and \
                        np.logical_and(my >= latlim[0], my <= latlim[1]):
                    ax.text(mx, my, str(int(mlat)), color=label_colors,
                            fontsize=14, backgroundcolor='white',
                            transform=ccrs.PlateCarree())

    if igrf:
        glon = np.arange(lonlim[0] - 40, lonlim[1] + 40.1, 0.5)
        glat = np.arange(-90, 90 + 0.1, 0.5)
        longrid, latgrid = np.meshgrid(glon, glat)
        mag = igrf12.gridigrf12(t=date, glat=latgrid, glon=longrid, alt_km=alt_km)
        if decl_levels is not None:
            z = mag.decl.values
            for declination in decl_levels:
                ax.contour(longrid, latgrid, z, levels=declination,
                           colors=decl_colors, transform=ccrs.PlateCarree())
        if incl_levels is not None:
            z = mag.incl.values
            for inclination in incl_levels:
                ax.contour(longrid, latgrid, z, levels=declination,
                           colors=incl_colors, transform=ccrs.PlateCarree())
    # Set Extent

    ax.set_extent([lonlim[0], lonlim[1], latlim[0], latlim[1]], crs=ccrs.PlateCarree())

    if 'fig' in locals():
        return fig, ax
    else:
        return ax
Esempio n. 6
0
def plotKeogram(im=None, t=None, latline=None, lonline=None, line=None, skip=None, average=False, magnetic=False, parallels=None,
                meridians=None, mlat_levels=None, mlon_levels=None, ax=False, figsize=None,
                conjugate=True, height=350):

    # pass entire im and t from .h5 file
    # for mlat or mlon set linetype = 'm'

    def conjugate_img(img):
        nanind = np.where(np.isnan(img))
        nanindices = list(zip(nanind[0], nanind[1]))
        conj = img
        for nanindex in nanindices:
            conj[nanindex] = np.flipud(img)[nanindex]
        return conj

    im = np.array(im)
    A = ap.Apex(date=t[0])

    with warnings.catch_warnings():
        warnings.simplefilter("ignore", category=RuntimeWarning)
        if magnetic is False:  # geo
            if latline is None:
                y = range(-90, 90)
                lonline += 180
                if average:
                    image = np.nanmean(np.array([[im[0:, lonline % 360, 0:]], [im[0:, ((lonline+1) % 360), 0:]],
                                       [im[0:, ((lonline-1) % 360), 0:]]]), axis=0)
                    image = np.squeeze(image)  # remove singular dimension
                else:
                    image = np.array(im)[0:, lonline % 360, 0:]
            elif lonline is None:
                y = range(-180, 180)
                latline += 90
                if average:
                    image = np.nanmean(np.array([[im[0:, 0:, latline % 180]], [im[0:, 0:, (latline+1) % 180]],
                                       [im[0:, 0:, (latline-1) % 180]]]), axis=0)
                    image = np.squeeze(image)
                else:
                    image = np.array(im)[0:, 0:, latline % 180]
            image = np.flipud(np.rot90(image))

        else:  # magnetic
            indexmake = np.vectorize(lambda x: int(round(x)))
            image = np.array([])
            mask = np.zeros((im.shape[2], im.shape[1]), dtype=bool)

            if latline is None:  # longitude
                lonline += 90
                y = range(-90, 90)
                lat_ind, lon_ind = np.round(A.convert(range(-90, 90), lonline, 'apex', 'geo'))
                indices = indexmake(np.array(list(zip(lat_ind + 90, lon_ind + 180))))
                indices = list(map(tuple, indices))

                for index in indices:
                    mask[index[0] % 180, index[1] % 360] = True
                mask = np.rot90(mask)

                if average:
                    for index in indices:
                        image = np.append(image, np.nanmean([[im[0:, index[1] % 360, index[0] % 180]],
                                                            [im[0:, (index[1] + 1) % 360, index[0] % 180]],
                                                            [im[0:, (index[1] - 1) % 360, index[0] % 180]]], axis=0))
                else:
                    for index in indices:
                        image = np.append(image, im[0:, index[1], index[0]])

                image = np.reshape(image, (len(image) // len(t), len(t)))

                if conjugate:
                    image = conjugate_img(image)

            elif lonline is None:  # latitude
                lat_ind, lon_ind = np.round(A.convert(latline, range(-180, 180), 'apex', 'geo'))
                indices = indexmake(np.array(list(zip(lat_ind + 90, lon_ind + 180))))
                indices = list(map(tuple, indices))
                y = range(-180, 180)

                for index in indices:
                    mask[index[0] % 180, index[1] % 360] = True

                mask = np.rot90(mask)

                if average:
                    for index in indices:
                        image = np.append(image, np.nanmean([[im[0:, index[1] % 360, index[0] % 180]],
                                                             [im[0:, index[1] % 360, (index[0] + 1) % 180]],
                                                             [im[0:, index[1] % 360, (index[0] - 1) % 180]]], axis=0))
                else:
                    for index in indices:
                        image = np.append(image, im[0:, index[1] % 360, index[0] % len(t)])
                image = np.reshape(image, (len(image) // len(t), len(t)))

    t = list(map(datetime.fromtimestamp, t))
    mt = mdates.date2num((t[0], t[-1]))

    image = np.flipud(image)

    if skip is not None:
        image = image[::skip]

    if not ax:
        if figsize is None:
            fig = plt.figure()
        else:
            fig = plt.figure(figsize=figsize)
        ax = fig.gca()

    # fig.suptitle(f'{t[0].strftime("%Y-%m-%d")}')
    ax.imshow(image, extent=[mt[0], mt[1], y[0], y[-1]], aspect='auto', cmap='gist_ncar')

    if latline is None:
        if mlat_levels is not None:
            for level in mlat_levels:
                glat, _ = A.convert(level, lonline, 'geo', 'apex', height=height)
                ax.axhline(glat, linestyle='--', linewidth=1, color='firebrick')
        if parallels is not None:
            for level in parallels:
                ax.axhline(level, linestyle='--', linewidth=1, color='cornflowerblue')
    elif lonline is None:
        if mlon_levels is not None:
            for level in mlon_levels:
                _, glon = A.convert(latline, level, 'geo', 'apex', height=height)
                ax.axhline(glon, linestyle='--', linewidth=1, color='firebrick')
        if meridians is not None:
            for level in meridians:
                ax.axhline(level, linestyle='--', linewidth=1, color='cornflowerblue')

    ax.xaxis_date()
    ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M:%S'))
    # fig.autofmt_xdate()

    if 'fig' in locals():
        return fig, ax
    else:
        return ax
Esempio n. 7
0
def add_quasi_dipole_coordinates(inst,
                                 glat_label='glat',
                                 glong_label='glong',
                                 alt_label='alt'):
    """ 
    Uses Apexpy package to add quasi-dipole coordinates to instrument object.
    
    The Quasi-Dipole coordinate system includes both the tilt and offset of the 
    geomagnetic field to calculate the latitude, longitude, and local time
    of the spacecraft with respect to the geomagnetic field.
    
    This system is preferred over AACGM near the equator for LEO satellites.
    
    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)
    glong_label : string
        label used in inst to identify WGS84 geodetic longitude (degrees)
    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, 'qd_lat'
        for magnetic latitude, 'qd_long' for longitude, and 'mlt' for magnetic local time.
        
    """

    import apexpy
    ap = apexpy.Apex(date=inst.date)

    qd_lat = []
    qd_lon = []
    mlt = []
    for lat, lon, alt, time in zip(inst[glat_label], inst[glong_label],
                                   inst[alt_label], inst.data.index):
        # quasi-dipole latitude and longitude from geodetic coords
        tlat, tlon = ap.geo2qd(lat, lon, alt)
        qd_lat.append(tlat)
        qd_lon.append(tlon)
        mlt.append(ap.mlon2mlt(tlon, time))

    inst['qd_lat'] = qd_lat
    inst['qd_long'] = qd_lon
    inst['mlt'] = mlt

    inst.meta['qd_lat'] = {
        'units': 'degrees',
        'long_name': 'Quasi dipole latitude'
    }
    inst.meta['qd_long'] = {
        'units': 'degrees',
        'long_name': 'Quasi dipole longitude'
    }
    inst.meta['qd_mlt'] = {'units': 'hrs', 'long_name': 'Magnetic local time'}

    return
Esempio n. 8
0
def plotCartoMap(latlim=[0, 75],
                 lonlim=[-40, 40],
                 parallels=None,
                 meridians=None,
                 pole_center_lon=0,
                 figsize=(12, 8),
                 terrain=False,
                 ax=False,
                 projection='stereo',
                 title='',
                 resolution='110m',
                 lon0=None,
                 lat0=None,
                 states=True,
                 grid_linewidth=0.5,
                 grid_color='black',
                 grid_linestyle='--',
                 background_color=None,
                 border_color='k',
                 figure=False,
                 nightshade=False,
                 ns_alpha=0.1,
                 apex=False,
                 igrf=False,
                 date=None,
                 mlat_levels=None,
                 mlon_levels=None,
                 alt_km=0.0,
                 mlon_colors='blue',
                 mlat_colors='red',
                 mgrid_width=1,
                 mgrid_labels=True,
                 mgrid_fontsize=12,
                 mlon_cs='mlon',
                 incl_levels=None,
                 decl_levels=None,
                 igrf_param='incl',
                 mlon_labels=True,
                 mlat_labels=True,
                 mgrid_style='--',
                 label_colors='k',
                 apex_alt=0,
                 decl_colors='k',
                 incl_colors='k',
                 terminator=False,
                 terminator_altkm=350,
                 polarization_terminator=False,
                 pt_hemisphere='north',
                 ter_color='red',
                 ter_style='--',
                 ter_width=2,
                 midnight=False,
                 midnight_colors='m',
                 midnight_width=2,
                 midnight_style='--'):
    if lonlim is None or lonlim == []:
        lonlim = [-180, 180]
    STATES = cfeature.NaturalEarthFeature(
        category='cultural',
        name='admin_1_states_provinces_lines',
        scale='50m',
        facecolor='none')

    if not ax:
        if figsize is None:
            fig = plt.figure()
        else:
            fig = plt.figure(figsize=figsize)

        if projection == 'stereo':
            ax = plt.axes(projection=ccrs.Stereographic(
                central_longitude=(sum(lonlim) / 2)))
        elif projection == 'merc':
            ax = plt.axes(projection=ccrs.Mercator())
        elif projection == 'plate':
            ax = plt.axes(projection=ccrs.PlateCarree(
                central_longitude=(sum(lonlim) / 2)))
        elif projection == 'lambert':
            ax = plt.axes(projection=ccrs.LambertConformal(
                central_longitude=(sum(lonlim) / 2),
                central_latitude=(sum(latlim) / 2)))
        elif projection == 'mollweide':
            ax = plt.axes(projection=ccrs.Mollweide(
                central_longitude=(sum(lonlim) / 2)))
        elif projection == 'north':
            if lon0 is None:
                lon0 = 0
            ax = plt.axes(projection=ccrs.NorthPolarStereo(
                central_longitude=lon0))
        elif projection == 'south':
            if lon0 is None:
                lon0 = 0
            ax = plt.axes(projection=ccrs.SouthPolarStereo(
                central_longitude=lon0))
        elif projection == 'ortographic':
            if lon0 is None:
                lon0 = 0
            if lat0 is None:
                lat0 = 0
            ax = plt.axes(projection=ccrs.Orthographic(central_longitude=lon0,
                                                       central_latitude=lat0))
        else:
            print("Projection is invalid. Please enter the right one. \n \
                   'stereo', 'merc', 'plate', 'lambret', mollweide', 'north, 'south', 'ortographic'"
                  )
            return 0
    if background_color is not None:
        ax.background_patch.set_facecolor(background_color)
    ax.set_title(title)
    ax.coastlines(color=border_color,
                  resolution=resolution)  # 110m, 50m or 10m
    if states:
        ax.add_feature(STATES, edgecolor=border_color)
    ax.add_feature(cfeature.BORDERS, edgecolor=border_color)
    if terrain:
        ax.stock_img()
    if nightshade:
        assert date is not None
        assert ns_alpha is not None
        ax.add_feature(Nightshade(date, ns_alpha))
    # Draw Parralels
    if projection == 'merc' or projection == 'plate':
        if isinstance(meridians, np.ndarray):
            meridians = list(meridians)
        if isinstance(parallels, np.ndarray):
            parallels = list(parallels)

        gl = ax.gridlines(crs=ccrs.PlateCarree(),
                          color=grid_color,
                          draw_labels=False,
                          linestyle=grid_linestyle,
                          linewidth=grid_linewidth)
        if meridians is None:
            gl.xlines = False
        else:
            if len(meridians) > 0:
                gl.xlocator = mticker.FixedLocator(meridians)
                gl.xlabels_bottom = True
            else:
                gl.ylines = False

        if parallels is None:
            gl.ylines = False
        else:
            if len(parallels) > 0:
                gl.ylocator = mticker.FixedLocator(parallels)
                gl.ylabels_left = True
            else:
                gl.ylines = False
    else:
        gl = ax.gridlines(crs=ccrs.PlateCarree(),
                          color=grid_color,
                          draw_labels=False,
                          linestyle=grid_linestyle,
                          linewidth=grid_linewidth)
        if meridians is None:
            gl.xlines = False
        else:
            gl.xlocator = mticker.FixedLocator(meridians)
        if parallels is not None:
            if isinstance(parallels, np.ndarray):
                parallels = list(parallels)
            gl.ylocator = mticker.FixedLocator(parallels)
        else:
            gl.ylines = False

    # Geomagnetic coordinates @ Apex
    if apex:
        if date is None:
            date = datetime(2017, 12, 31, 0, 0, 0)
        assert isinstance(date, datetime)

        A = ap.Apex(date=date)
        # Define levels and ranges for conversion
        if mlon_cs == 'mlt':
            if mlon_levels is None:
                mlon_levels = np.array([])
                mlon_range = np.arange(0, 24.01, 0.01)
            elif isinstance(mlon_levels, bool):
                if mlon_levels == False:
                    mlon_levels = np.array([])
                    mlon_range = np.arange(0, 24.01, 0.01)
            else:
                mlon_range = np.arange(mlon_levels[0], mlon_levels[-1] + 0.1,
                                       0.01)
        else:
            if mlon_levels is None:
                mlon_levels = np.array([])
                mlon_range = np.arange(-180, 180, 0.5)
            elif isinstance(mlon_levels, bool):
                if mlon_levels == False:
                    mlon_levels = np.array([])
                    mlon_range = np.arange(-180, 181, 0.1)
            else:
                mlon_range = np.arange(mlon_levels[0], mlon_levels[0] + 362,
                                       0.1)
        if mlat_levels is None:
            mlat_levels = np.arange(-90, 90.1, 1)
        mlat_range = np.arange(mlat_levels[0], mlat_levels[-1] + 0.1, 0.1)

        # Do meridans
        for mlon in mlon_levels:
            MLON = mlon * np.ones(mlat_range.size)
            if mlon_cs == 'mlt':
                y, x = A.convert(mlat_range,
                                 MLON,
                                 'mlt',
                                 'geo',
                                 datetime=date,
                                 height=apex_alt)
            else:
                y, x = A.convert(mlat_range,
                                 MLON,
                                 'apex',
                                 'geo',
                                 height=apex_alt)
            mlat_mask_extent = (y >= latlim[0] + 0.2) & (y <= latlim[1] - 0.2)
            # Plot meridian
            inmap = np.logical_and(x >= lonlim[0], x <= lonlim[1])
            if np.sum(inmap) > 10:
                ax.plot(np.unwrap(x[mlat_mask_extent], 180),
                        np.unwrap(y[mlat_mask_extent], 90),
                        c=mlon_colors,
                        lw=mgrid_width,
                        linestyle=mgrid_style,
                        zorder=90,
                        transform=ccrs.PlateCarree())

            # Labels
            if mlon_labels:
                ix = abs(y - np.mean(latlim)).argmin()
                mx = x[ix] - 1 if mlon >= 10 else x[ix] - 0.5
                my = np.mean(latlim)
                if np.logical_and(mx >= lonlim[0], mx <= lonlim[1]):
                    if mlon_cs == 'mlt' and mlon != 0:
                        ax.text(mx,
                                my,
                                str(int(mlon)),
                                color=label_colors,
                                fontsize=14,
                                backgroundcolor='white',
                                transform=ccrs.PlateCarree())
                    elif mlon_cs != 'mlt' and mlon != 360:
                        ax.text(mx,
                                my,
                                str(int(mlon)),
                                color=label_colors,
                                fontsize=14,
                                backgroundcolor='white',
                                transform=ccrs.PlateCarree())
        # Do parallels
        for mlat in mlat_levels:
            MLAT = mlat * np.ones(mlon_range.size)
            if mlon_cs == 'mlt':
                gy, gx = A.convert(MLAT,
                                   mlon_range,
                                   'mlt',
                                   'geo',
                                   datetime=date,
                                   height=apex_alt)
            else:

                gy, gx = A.convert(MLAT,
                                   mlon_range,
                                   'apex',
                                   'geo',
                                   datetime=date,
                                   height=apex_alt)
            inmap = np.logical_and(gy >= latlim[0], gy <= latlim[1])
            if np.sum(inmap) > 20:
                ax.plot(np.unwrap(gx, 180),
                        np.unwrap(gy, 90),
                        c=mlat_colors,
                        lw=mgrid_width,
                        linestyle=mgrid_style,
                        zorder=90,
                        transform=ccrs.PlateCarree())

            # Labels
            if mlat_labels:
                ix = abs(gx - np.mean(lonlim)).argmin()
                mx = np.mean(lonlim)
                my = gy[ix] - 0.5
                if np.logical_and(mx >= lonlim[0], mx <= lonlim[1]) and \
                np.logical_and(my >= latlim[0], my <= latlim[1]):
                    ax.text(mx,
                            my,
                            str(int(mlat)),
                            color=label_colors,
                            fontsize=14,
                            backgroundcolor='white',
                            transform=ccrs.PlateCarree())
    if igrf:
        glon = np.arange(lonlim[0] - 40, lonlim[1] + 40.1, 0.5)
        glat = np.arange(-90, 90 + 0.1, 0.5)
        longrid, latgrid = np.meshgrid(glon, glat)
        mag = igrf12.gridigrf12(t=date,
                                glat=latgrid,
                                glon=longrid,
                                alt_km=alt_km)
        if decl_levels is not None:
            z = mag.decl.values
            for declination in decl_levels:
                ax.contour(longrid,
                           latgrid,
                           z,
                           levels=declination,
                           zorder=90,
                           colors=decl_colors,
                           transform=ccrs.PlateCarree())
        if incl_levels is not None:
            z = mag.incl.values
            for inclination in incl_levels:
                ax.contour(longrid,
                           latgrid,
                           z,
                           levels=declination,
                           zorder=90,
                           colors=incl_colors,
                           transform=ccrs.PlateCarree())
    # Terminators
    if terminator:
        assert date is not None
        if not isinstance(terminator_altkm, list):
            terminator_altkm = [terminator_altkm]
        for takm in terminator_altkm:
            try:
                glon_ter, glat_ter = ter.get_terminator(date, alt_km=takm)
                if glon_ter is not None and glat_ter is not None:
                    if isinstance(glon_ter, list):
                        for i in range(len(glon_ter)):
                            ax.plot(np.unwrap(glon_ter[i], 180),
                                    np.unwrap(glat_ter[i], 90),
                                    c=ter_color,
                                    lw=ter_width,
                                    ls=ter_style,
                                    zorder=90,
                                    transform=ccrs.PlateCarree())
                    else:
                        ax.plot(np.unwrap(glon_ter, 180),
                                np.unwrap(glat_ter, 90),
                                c=ter_color,
                                lw=ter_width,
                                ls=ter_style,
                                zorder=90,
                                transform=ccrs.PlateCarree())
            except:
                pass
    if midnight:
        mlat_range = np.arange(-89.9, 90.1, 0.1)
        MLON = 0 * np.ones(mlat_range.size)
        if mlon_cs == 'mlt':
            y, x = A.convert(mlat_range,
                             MLON,
                             'mlt',
                             'geo',
                             datetime=date,
                             height=apex_alt)
        else:
            y, x = A.convert(mlat_range, MLON, 'apex', 'geo', height=apex_alt)
        mlat_mask_extent = (y >= latlim[0] + 0.2) & (y <= latlim[1] - 0.2)
        # Plot meridian
        inmap = np.logical_and(x >= lonlim[0], x <= lonlim[1])
        if np.sum(inmap) > 10:
            ax.plot(np.unwrap(x[mlat_mask_extent], 180),
                    np.unwrap(y[mlat_mask_extent], 90),
                    c=midnight_colors,
                    lw=midnight_width,
                    linestyle=midnight_style,
                    zorder=90,
                    transform=ccrs.PlateCarree())
    # Set Extent
    if projection == 'north' or projection == 'south':
        import matplotlib.path as mpath
        ax.set_extent([-180, 181, latlim[0], latlim[1]],
                      crs=ccrs.PlateCarree())
        theta = np.linspace(0, 2 * np.pi, 100)
        center, radius = [0.5, 0.5], 0.5
        verts = np.vstack([np.sin(theta), np.cos(theta)]).T
        circle = mpath.Path(verts * radius + center)
        ax.set_boundary(circle, transform=ax.transAxes)
    elif lonlim[0] != -180 and lonlim[1] != 180:
        ax.set_extent([lonlim[0], lonlim[1], latlim[0], latlim[1]],
                      crs=ccrs.PlateCarree())  #ccrs.PlateCarree())

    if 'fig' in locals():
        return fig, ax
    else:
        return ax
Esempio n. 9
0
    def test_apexpy_v_OMMBV(self):
        """Comparison with apexpy along magnetic equator"""
        # generate test values
        glongs = np.arange(99) * 3.6 - 180.
        glats = np.zeros(99) + 10.
        alts = np.zeros(99) + 450.
        # date of run
        date = self.inst.date
        # map to the magnetic equator
        ecef_x, ecef_y, ecef_z, eq_lat, eq_long, eq_z = OMMBV.apex_location_info(
            glats, glongs, alts, [date] * len(alts), return_geodetic=True)
        idx = np.argsort(eq_long)
        eq_long = eq_long[idx]
        eq_lat = eq_lat[idx]
        eq_z = eq_z[idx]
        # get apex basis vectors
        apex = apexpy.Apex(date=self.inst.date)
        apex_vecs = apex.basevectors_apex(eq_lat, eq_long, eq_z, coords='geo')
        apex_fa = apex_vecs[8]
        apex_mer = apex_vecs[7]
        apex_zon = apex_vecs[6]

        # normalize into unit vectors
        apex_mer[0, :], apex_mer[1, :], apex_mer[
            2, :] = OMMBV.normalize_vector(-apex_mer[0, :], -apex_mer[1, :],
                                           -apex_mer[2, :])

        apex_zon[0, :], apex_zon[1, :], apex_zon[
            2, :] = OMMBV.normalize_vector(apex_zon[0, :], apex_zon[1, :],
                                           apex_zon[2, :])
        apex_fa[0, :], apex_fa[1, :], apex_fa[2, :] = OMMBV.normalize_vector(
            apex_fa[0, :], apex_fa[1, :], apex_fa[2, :])

        # calculate mag unit vectors in ECEF coordinates
        out = OMMBV.calculate_mag_drift_unit_vectors_ecef(
            eq_lat, eq_long, eq_z, [self.inst.date] * len(eq_z))
        zx, zy, zz, fx, fy, fz, mx, my, mz = out

        # convert into north, east, and up system
        ze, zn, zu = OMMBV.ecef_to_enu_vector(zx, zy, zz, eq_lat, eq_long)
        fe, fn, fu = OMMBV.ecef_to_enu_vector(fx, fy, fz, eq_lat, eq_long)
        me, mn, mu = OMMBV.ecef_to_enu_vector(mx, my, mz, eq_lat, eq_long)

        # create inputs straight from IGRF
        igrf_n = []
        igrf_e = []
        igrf_u = []
        for lat, lon, alt in zip(eq_lat, eq_long, eq_z):
            out = OMMBV.igrf.igrf13syn(0, date.year, 1, alt,
                                       np.deg2rad(90 - lat), np.deg2rad(lon))
            out = np.array(out)
            # normalize
            out /= out[-1]
            igrf_n.append(out[0])
            igrf_e.append(out[1])
            igrf_u.append(-out[2])

        # dot product of zonal and field aligned
        dot_apex_zonal = apex_fa[0, :] * apex_zon[0, :] + apex_fa[
            1, :] * apex_zon[1, :] + apex_fa[2, :] * apex_zon[2, :]
        dot_apex_mer = apex_fa[0, :] * apex_mer[0, :] + apex_fa[
            1, :] * apex_mer[1, :] + apex_fa[2, :] * apex_mer[2, :]

        dotmagvect_zonal = ze * fe + zn * fn + zu * fu
        dotmagvect_mer = me * fe + mn * fn + mu * fu

        assert np.all(dotmagvect_mer < 1.E-8)
        assert np.all(dotmagvect_zonal < 1.E-8)

        try:
            plt.figure()
            plt.plot(eq_long,
                     np.log10(np.abs(dot_apex_zonal)),
                     label='apex_zonal')
            plt.plot(eq_long, np.log10(np.abs(dot_apex_mer)), label='apex_mer')
            plt.plot(eq_long,
                     np.log10(np.abs(dotmagvect_zonal)),
                     label='magv_zonal')
            plt.plot(eq_long,
                     np.log10(np.abs(dotmagvect_mer)),
                     label='magv_mer')
            plt.ylabel('Log Dot Product Magnitude')
            plt.xlabel('Geodetic Longitude (Degrees)')
            plt.legend()
            plt.savefig('dot_product.pdf')
            plt.close()

            plt.figure()
            plt.plot(eq_long, fe, label='fa_e', color='r')
            plt.plot(eq_long, fn, label='fa_n', color='k')
            plt.plot(eq_long, fu, label='fa_u', color='b')

            plt.plot(eq_long,
                     apex_fa[0, :],
                     label='apexpy_e',
                     color='r',
                     linestyle='dotted')
            plt.plot(eq_long,
                     apex_fa[1, :],
                     label='apexpy_n',
                     color='k',
                     linestyle='dotted')
            plt.plot(eq_long,
                     apex_fa[2, :],
                     label='apexpy_u',
                     color='b',
                     linestyle='dotted')

            plt.plot(eq_long,
                     igrf_e,
                     label='igrf_e',
                     color='r',
                     linestyle='-.')
            plt.plot(eq_long,
                     igrf_n,
                     label='igrf_n',
                     color='k',
                     linestyle='-.')
            plt.plot(eq_long,
                     igrf_u,
                     label='igrf_u',
                     color='b',
                     linestyle='-.')

            plt.legend()
            plt.xlabel('Longitude')
            plt.ylabel('Vector Component')
            plt.title('Field Aligned Vector')
            plt.savefig('comparison_field_aligned.pdf')
            plt.close()

            f = plt.figure()
            plt.plot(eq_long, ze, label='zonal_e', color='r')
            plt.plot(eq_long, zn, label='zonal_n', color='k')
            plt.plot(eq_long, zu, label='zonal_u', color='b')

            plt.plot(eq_long,
                     apex_zon[0, :],
                     label='apexpy_e',
                     color='r',
                     linestyle='dotted')
            plt.plot(eq_long,
                     apex_zon[1, :],
                     label='apexpy_n',
                     color='k',
                     linestyle='dotted')
            plt.plot(eq_long,
                     apex_zon[2, :],
                     label='apexpy_u',
                     color='b',
                     linestyle='dotted')

            plt.legend()
            plt.xlabel('Longitude')
            plt.ylabel('Vector Component')
            plt.title('Zonal Vector')
            plt.savefig('comparison_zonal.pdf')
            plt.close()

            f = plt.figure()
            plt.plot(eq_long, me, label='mer_e', color='r')
            plt.plot(eq_long, mn, label='mer_n', color='k')
            plt.plot(eq_long, mu, label='mer_u', color='b')

            plt.plot(eq_long,
                     apex_mer[0, :],
                     label='apexpy_e',
                     color='r',
                     linestyle='dotted')
            plt.plot(eq_long,
                     apex_mer[1, :],
                     label='apexpy_n',
                     color='k',
                     linestyle='dotted')
            plt.plot(eq_long,
                     apex_mer[2, :],
                     label='apexpy_u',
                     color='b',
                     linestyle='dotted')

            plt.legend()
            plt.xlabel('Longitude')
            plt.ylabel('Vector Component')
            plt.title('Meridional Vector')
            plt.savefig('comparison_meridional.pdf')
            plt.close()
        except:
            pass
Esempio n. 10
0
import h5py
from pandas.plotting import register_matplotlib_converters
import cartopy.crs as ccrs

register_matplotlib_converters()

if __name__ == '__main__':
    # use local file location
    fn = 'C:\\Users\\mrina\\Desktop\\data\\conv_0428T0000-0429T0000.h5'
    with h5py.File(fn, 'r') as f:
        lat = f['GPSTEC']['lat']
        lon = f['GPSTEC']['lon']
        t = f['GPSTEC']['time']
        im = f['GPSTEC']['im']

        A = ap.Apex(date=t[0])
        fig = plt.Figure()
        ax1 = plt.subplot(211)
        ax2 = plt.subplot(212, projection=ccrs.PlateCarree())

        cm.plotKeogram(im=im,
                       t=t,
                       latline=0,
                       magnetic=False,
                       mlat_levels=[-90, -60, -30, 0, 30, 60, 90],
                       parallels=[],
                       ax=ax1,
                       average=True,
                       conjugate=False)
        """
        Parameters:
Esempio n. 11
0
import apexpy
import datetime
from geopy.distance import geodesic
import numpy as np
import scipy.io as sio

# using apexpy to get the magnetic footpoints
teb_time = datetime.datetime(2018, 9, 16, 13, 14, 45)
A = apexpy.Apex(teb_time, refh=0)

teb_escape_alt = 45.0  # km
sat_alt = 402.5  # km
sat_lat, sat_lon = 6.281, -95.709

mlat, mlon = A.geo2apex(sat_lat, sat_lon,
                        sat_alt)  # magnetic latitude and longitude of the ISS

foot1 = A.map_to_height(sat_lat,
                        sat_lon,
                        sat_alt,
                        teb_escape_alt,
                        conjugate=False,
                        precision=1e-10)
foot2 = A.map_to_height(sat_lat,
                        sat_lon,
                        sat_alt,
                        teb_escape_alt,
                        conjugate=True,
                        precision=1e-10)

print('footpoint #1 (lat lon error): ', foot1)
Esempio n. 12
0
latlim = [-0, 60]
lonlim = [-140, 0]
date = datetime(2017, 8, 21, 6)

fig = gm.plotCartoMap(
    projection='plate',
    title='Geomagnetic coordinates: MLAT/MLT',
    latlim=latlim,
    lonlim=lonlim,
    parallels=[0, 10, 20, 40, 60, 80, 90],
    meridians=[-220, -180, -160, -140, -120, -100, -80, -60, -40, 0],
    grid_linewidth=1,
    figure=True,
    states=False)
A = ap.Apex(date=date)

#glon = np.arange(lonlim[0]-40, lonlim[1] + 40.1, 1)
#glat = np.arange(latlim[0], latlim[1] + 0.1, 1)

#longrid, latgrid = np.meshgrid(glon, glat)

mlat_levels = np.arange(-90, 90.1, 10)
#mlat_levels = np.array([40,50,60,70])
# mlon
#mlat, mlon = A.convert(latgrid, longrid, 'geo', 'apex')
#mlon_levels = np.arange(-180,180,20)
# mlt
#mlat, mlon = A.convert(latgrid, longrid, 'geo', 'mlt', datetime=date)
mlon_levels = np.arange(0, 24.2, 2)