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
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
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')
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]
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
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
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
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
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
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:
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)
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)