def _get_illum_angles(self): "Ilumin returns (trgepoch, srfvec, phase, solar, emission)" if self.obs is not None: output = spice.ilumin("Ellipsoid", self.target, self.et, self.ref_frame, self.corr, self.obs, self.spoint) return IllumAngles.fromtuple(output[2:]) else: solar = spice.vsep(self.sun_direction, self.snormal) # leaving at 0 what I don't have return IllumAngles.fromtuple((0, solar, 0))
def illum_angles(self): """Ilumin returns (trgepoch, srfvec, phase, solar, emission) """ if self.obs is not None: output = spice.ilumin( "Ellipsoid", self.target, self.et, self.ref_frame, self.corr, self.obs, self.spoint, ) return IllumAngles.fromtuple(output[2:]) else: solar = spice.vsep(self.sun_direction, self.snormal) # leaving at 0 what I don't have return IllumAngles.fromtuple((0, solar, 0))
def highres_swath_geometry(self, hdul, map_data, res=200): """ Generates an artificial high-resolution slit, calculates viewing geometry and surface-intercept map. Parameters ---------- hdul : HDUList Opened FITS file. res : int, optional The desired number of artificial elements along the slit. Defaults to 200. Returns ------- latitude : array Array of latitudes for the centers of each high-resolution artificial pixel. NaNs if pixel doesn't intercept the surface of Mars. longitude : array Array of longitudes for the centers of each high-resolution artificial pixel. NaNs if pixel doesn't intercept the surface of Mars. sza : array Array of solar zenith angles for the centers of each high-resolution artificial pixel. NaNs if pixel doesn't intercept the surface of Mars. ea pa local_time : array Array of local times for the centers of each high-resolution artificial pixel. NaNs if pixel doesn't intercept the surface of Mars. x : array Horizontal coordinate edges in angular space. Has shape (n+1, m+1) for geometry arrays with shape (n,m). y : array Vertical coordinate edges in angular space. Has shape (n+1, m+1) for geometry arrays with shape (n,m). cx : array Horizontal coordinate centers in angular space. Same shape as geometry arrays. cy : array Vertical coordinate centers in angular space. Same shape as geometry arrays. context_map : array High-resolution image of the Mars surface as intercepted by the swath. RGB tuples with shape (n,m,3). """ # get swath vectors, ephemeris times, and mirror angles vec = hdul['pixelgeometry'].data['pixel_vec'] et = hdul['integration'].data['et'] # get dimensions of the input data n_int = hdul['integration'].data.shape[0] n_spa = len(hdul['binning'].data['spapixlo'][0]) # set the high-resolution slit width and calculate the number of high-resolution integrations hifi_spa = res hifi_int = int(hifi_spa / n_spa * n_int) # make arrays of ephemeris time and array to hold the new swath vector calculations # here thru 481 just interpolate et_arr and vec_arr onto new grid (int, pos) and (int, pos, 3) adn they're all just center values et_arr = np.expand_dims(et, 1) * np.ones((n_int, n_spa)) et_arr = resize(et_arr, (hifi_int, hifi_spa), mode='edge') vec_arr = np.zeros((hifi_int + 1, hifi_spa + 1, 3)) # make an artificially-divided swath and create new array of swath vectors if self.__flip: lower_left = vec[0, :, 0, 0] upper_left = vec[-1, :, 0, 1] lower_right = vec[0, :, -1, 2] upper_right = vec[-1, :, -1, 3] else: lower_left = vec[0, :, 0, 1] upper_left = vec[-1, :, 0, 0] lower_right = vec[0, :, -1, 3] upper_right = vec[-1, :, -1, 2] for e in range(3): a = np.linspace(lower_left[e], upper_left[e], hifi_int + 1) b = np.linspace(lower_right[e], upper_right[e], hifi_int + 1) vec_arr[:, :, e] = np.array( [np.linspace(i, j, hifi_spa + 1) for i, j in zip(a, b)]) # resize array to extract centers vec_arr = resize(vec_arr, (hifi_int, hifi_spa, 3), anti_aliasing=True) # make empty arrays to hold geometry calculations latitude = np.zeros((hifi_int, hifi_spa)) * np.nan longitude = np.zeros((hifi_int, hifi_spa)) * np.nan sza = np.zeros((hifi_int, hifi_spa)) * np.nan phase_angle = np.zeros((hifi_int, hifi_spa)) * np.nan emission_angle = np.zeros((hifi_int, hifi_spa)) * np.nan local_time = np.zeros((hifi_int, hifi_spa)) * np.nan context_map = np.zeros((hifi_int, hifi_spa, 4)) * np.nan # calculate intercept latitude and longitude using SPICE, looping through each high-resolution pixel target = 'Mars' frame = 'IAU_Mars' abcorr = 'LT+S' observer = 'MAVEN' body = 499 # Mars IAU code for i in range(hifi_int): for j in range(hifi_spa): et = et_arr[i, j] los_mid = vec_arr[i, j, :] # try to perform the SPICE calculations and record the results try: # calculate surface intercept spoint, trgepc, srfvec = spice.sincpt( 'Ellipsoid', target, et, frame, abcorr, observer, frame, los_mid) # calculate illumination angles trgepc, srfvec, phase_for, solar, emissn = spice.ilumin( 'Ellipsoid', target, et, frame, abcorr, observer, spoint) # convert from rectangular to spherical coordinates rpoint, colatpoint, lonpoint = spice.recsph(spoint) # convert longitude from domain [-pi,pi) to [0,2pi) if lonpoint < 0.: lonpoint += 2 * np.pi # convert ephemeris time to local solar time hr, mn, sc, time, ampm = spice.et2lst(et, body, lonpoint, 'planetocentric', timlen=256, ampmlen=256) # convert spherical coordinates to latitude and longitude in degrees latitude[i, j] = np.degrees(np.pi / 2 - colatpoint) longitude[i, j] = np.degrees(lonpoint) # convert illumination angles to degrees and record sza[i, j] = np.degrees(solar) phase_angle[i, j] = np.degrees(phase_for) emission_angle[i, j] = np.degrees(emissn) # convert local solar time to decimal hour local_time[i, j] = hr + mn / 60 + sc / 3600 # convert latitude and longitude to pixel coordinates map_lat = int(np.round(np.degrees(colatpoint), 1) * 10) map_lon = int(np.round(np.degrees(lonpoint), 1) * 10) # make a corresponding magnetic field topology map context_map[i, j] = map_data[map_lat, map_lon] # if the SPICE calculation fails, this (probably) means it didn't intercept the planet except: # This pixel (or the vector) didn't intercept the planet pass # get mirror angles angles = hdul['integration'].data[ 'mirror_deg'] * 2 # convert from mirror angles to FOV angles dang = np.diff(angles)[0] # create an meshgrid of angular coordinates for the high-resolution pixel edges x, y = np.meshgrid( np.linspace(0, self.__slit_width, hifi_spa + 1), np.linspace(angles[0] - dang / 2, angles[-1] + dang / 2, hifi_int + 1)) # calculate the angular separation between pixels dslit = self.__slit_width / hifi_spa # create an meshgrid of angular coordinates for the high-resolution pixel centers cx, cy = np.meshgrid( np.linspace(0 + dslit, self.__slit_width - dslit, hifi_spa), np.linspace(angles[0], angles[-1], hifi_int)) # beta-flip the coordinate arrays if necessary if self.__flip: x = np.fliplr(x) y = (np.fliplr(y) - 90) / (-1) + 90 cx = np.fliplr(cx) cy = (np.fliplr(cy) - 90) / (-1) + 90 # convert longitude to [-180,180) longitude[np.where(longitude > 180)] -= 360 # return the geometry and coordinate arrays # cx, cy is for a lat/lon grid on top of the map (50, 1) --> (200, 4) # all but x, y, context_map is (n_integrations, n_positions) # the context map has shape (n_integrations, n_positions, 4) # x, y, cx, cy are (n_int +1, n_pos + 1) return latitude, longitude, sza, emission_angle, phase_angle, \ local_time, x, y, cx, cy, context_map
]) nadir_lonlats = np.asfarray( [sp.reclat(mars2tgo) for mars2tgo in list(mars2tgo_pos)])[:, 1:3] * sp.dpr() nadir_lsts = [ sp.et2lst(time, 499, (nadir_lonlat[0] / sp.dpr()), "PLANETOCENTRIC")[3] for time, nadir_lonlat in zip(list(times), list(nadir_lonlats)) ] nadir_lsts_hours = np.asfarray([ np.float(nadir_lst[0:2]) + np.float(nadir_lst[3:5]) / 60.0 + np.float(nadir_lst[6:8]) / 3600.0 for nadir_lst in nadir_lsts ]) nadir_incidence_angles = np.asfarray([ sp.ilumin(shape, target, time, "IAU_MARS", abcorr, observer, mars2tgo)[3] * sp.dpr() for time, mars2tgo in zip(list(times), list(mars2tgo_pos)) ]) print("Calculating altitudes") #calculate tangent point altitude altitudes = np.asfarray([ sp.npedln(mars_axes[0], mars_axes[1], mars_axes[2], line_point, line_vector)[1] for line_point, line_vector in zip( list(line_points), list(line_vectors)) ]) print("Checking if occultations real or not") #check that tgo is really behind mars as seen from sun: calculate angle between tgo-sun vector and tgo-mars centre vector sep_angles = np.asfarray([ sp.vsep(sp.vsub(line_coord, line_point), line_vector)
method = "Ellipsoid" target = "MARS" fixref = "IAU_MARS" abcorr = "None" obsrvr = "SUN" spoint = sp.latrec(3390, -24.6 / sp.dpr(), 18.3 / sp.dpr()) et = sp.utc2et("2003 OCT 28, 00:00:00") step = 60 for loop in range(100): time = et + step * loop time_string = sp.et2utc(time, "C", 0) sza = sp.ilumin(method, target, time, fixref, abcorr, obsrvr, spoint)[3] * sp.dpr() def writeLog(file_name, lines_to_write): """function to append log file""" # global LOG_PATHS logFile = open(file_name + ".csv", 'w') for line_to_write in lines_to_write: logFile.write(line_to_write + '\n') logFile.close() # print(line_to_write) utcstring_start = '2016 MAR 17 12:00:00' utcstring_end = '2017 JAN 17 12:00:00'
def get_sol_incidence(date, r): et = spice.str2et(str(date)) _, _, _, sol_incidence, _ = spice.ilumin('ellipsoid', 'moon', et, 'iau_moon', 'lt+s', 'sun', r) return np.degrees(sol_incidence)
def highres_swath_geometry(hdul, res=200, twilight='discrete'): """ Generates an artificial high-resolution slit, calculates viewing geometry and surface-intercept map. Parameters ---------- hdul : HDUList Opened FITS file. res : int, optional The desired number of artificial elements along the slit. Defaults to 200. twilight : str The appearance of the twilight zone. 'discrete' has a partially transparent zone with sharp edges while 'continuous' smoothes it with a cosine function. The discrete option does not always work on all systems, but I cannot yet say why that is. In those cases you get the continuous appearance. Returns ------- latitude : array Array of latitudes for the centers of each high-resolution artificial pixel. NaNs if pixel doesn't intercept the surface of Mars. longitude : array Array of longitudes for the centers of each high-resolution artificial pixel. NaNs if pixel doesn't intercept the surface of Mars. sza : array Array of solar zenith angles for the centers of each high-resolution artificial pixel. NaNs if pixel doesn't intercept the surface of Mars. local_time : array Array of local times for the centers of each high-resolution artificial pixel. NaNs if pixel doesn't intercept the surface of Mars. x : array Horizontal coordinate edges in angular space. Has shape (n+1, m+1) for geometry arrays with shape (n,m). y : array Vertical coordinate edges in angular space. Has shape (n+1, m+1) for geometry arrays with shape (n,m). cx : array Horizontal coordinate centers in angular space. Same shape as geometry arrays. cy : array Vertical coordinate centers in angular space. Same shape as geometry arrays. context_map : array High-resolution image of the Mars surface as intercepted by the swath. RGB tuples with shape (n,m,3). """ # calculate beta-flip state flipped = beta_flip(hdul) # get swath vectors, ephemeris times, and mirror angles vec = hdul['pixelgeometry'].data['pixel_vec'] et = hdul['integration'].data['et'] # get dimensions of the input data n_int = hdul['integration'].data.shape[0] n_spa = len(hdul['binning'].data['spapixlo'][0]) # set the high-resolution slit width and calculate the number of high-resolution integrations hifi_spa = res hifi_int = int(hifi_spa / n_spa * n_int) # make arrays of ephemeris time and array to hold the new swath vector calculations et_arr = np.expand_dims(et, 1) * np.ones((n_int, n_spa)) et_arr = resize(et_arr, (hifi_int, hifi_spa), mode='edge') vec_arr = np.zeros((hifi_int + 1, hifi_spa + 1, 3)) # make an artificially-divided slit and create new array of swath vectors if flipped: lower_left = vec[0, :, 0, 0] upper_left = vec[-1, :, 0, 1] lower_right = vec[0, :, -1, 2] upper_right = vec[-1, :, -1, 3] else: lower_left = vec[0, :, 0, 1] upper_left = vec[-1, :, 0, 0] lower_right = vec[0, :, -1, 3] upper_right = vec[-1, :, -1, 2] for e in range(3): a = np.linspace(lower_left[e], upper_left[e], hifi_int + 1) b = np.linspace(lower_right[e], upper_right[e], hifi_int + 1) vec_arr[:, :, e] = np.array([np.linspace(i, j, hifi_spa + 1) for i, j in zip(a, b)]) # resize array to extract centers vec_arr = resize(vec_arr, (hifi_int, hifi_spa, 3), anti_aliasing=True) # make empty arrays to hold geometry calculations latitude = np.zeros((hifi_int, hifi_spa))*np.nan longitude = np.zeros((hifi_int, hifi_spa))*np.nan sza = np.zeros((hifi_int, hifi_spa))*np.nan phase_angle = np.zeros((hifi_int, hifi_spa))*np.nan emission_angle = np.zeros((hifi_int, hifi_spa))*np.nan local_time = np.zeros((hifi_int, hifi_spa))*np.nan context_map = np.zeros((hifi_int, hifi_spa, 3))*np.nan # load Mars surface map and switch longitude domain from [-180,180) to [0, 360) mars_surface_map = plt.imread(os.path.join(pkg_resources.resource_filename('maven_iuvs', 'ancillary/'), 'mars_surface_map.jpg')) offset_map = np.zeros_like(mars_surface_map) offset_map[:, :1800, :] = mars_surface_map[:, 1800:, :] offset_map[:, 1800:, :] = mars_surface_map[:, :1800, :] mars_surface_map = offset_map # calculate intercept latitude and longitude using SPICE, looping through each high-resolution pixel target = 'Mars' frame = 'IAU_Mars' abcorr = 'LT+S' observer = 'MAVEN' body = 499 # Mars IAU code for i in range(hifi_int): for j in range(hifi_spa): et = et_arr[i, j] los_mid = vec_arr[i, j, :] # try to perform the SPICE calculations and record the results # noinspection PyBroadException try: # calculate surface intercept spoint, trgepc, srfvec = spice.sincpt('Ellipsoid', target, et, frame, abcorr, observer, frame, los_mid) # calculate illumination angles trgepc, srfvec, phase_for, solar, emissn = spice.ilumin('Ellipsoid', target, et, frame, abcorr, observer, spoint) # convert from rectangular to spherical coordinates rpoint, colatpoint, lonpoint = spice.recsph(spoint) # convert longitude from domain [-pi,pi) to [0,2pi) if lonpoint < 0.: lonpoint += 2 * np.pi # convert ephemeris time to local solar time hr, mn, sc, time, ampm = spice.et2lst(et, body, lonpoint, 'planetocentric', timlen=256, ampmlen=256) # convert spherical coordinates to latitude and longitude in degrees latitude[i, j] = np.degrees(np.pi / 2 - colatpoint) longitude[i, j] = np.degrees(lonpoint) # convert illumination angles to degrees and record sza[i, j] = np.degrees(solar) phase_angle[i, j] = np.degrees(phase_for) emission_angle[i, j] = np.degrees(emissn) # convert local solar time to decimal hour local_time[i, j] = hr + mn / 60 + sc / 3600 # convert latitude and longitude to pixel coordinates map_lat = int(np.round(np.degrees(colatpoint), 1) * 10) map_lon = int(np.round(np.degrees(lonpoint), 1) * 10) # instead of changing an alpha layer, I just multiply an RGB triplet by a scaling fraction in order to # make it darker; determine that scalar here based on solar zenith angle if twilight == 'discrete': if (sza[i, j] > 90) & (sza[i, j] <= 102): twilight = 0.7 elif sza[i, j] > 102: twilight = 0.4 else: twilight = 1 else: if (sza[i, j] > 90) & (sza[i, j] <= 102): tsza = (sza[i, j]-90)*np.pi/2/12 twilight = np.cos(tsza)*0.6 + 0.4 elif sza[i, j] > 102: twilight = 0.4 else: twilight = 1 # place the corresponding pixel from the high-resolution Mars map into the swath context map with the # twilight scaling context_map[i, j, :] = mars_surface_map[map_lat, map_lon, :] / 255 * twilight # if the SPICE calculation fails, this (probably) means it didn't intercept the planet except: pass # get mirror angles angles = hdul['integration'].data['mirror_deg'] * 2 # convert from mirror angles to FOV angles dang = np.diff(angles)[0] # create an meshgrid of angular coordinates for the high-resolution pixel edges x, y = np.meshgrid(np.linspace(0, slit_width_deg, hifi_spa + 1), np.linspace(angles[0] - dang / 2, angles[-1] + dang / 2, hifi_int + 1)) # calculate the angular separation between pixels dslit = slit_width_deg / hifi_spa # create an meshgrid of angular coordinates for the high-resolution pixel centers cx, cy = np.meshgrid( np.linspace(0 + dslit, slit_width_deg - dslit, hifi_spa), np.linspace(angles[0], angles[-1], hifi_int)) # beta-flip the coordinate arrays if necessary if flipped: x = np.fliplr(x) y = (np.fliplr(y) - 90) / (-1) + 90 cx = np.fliplr(cx) cy = (np.fliplr(cy) - 90) / (-1) + 90 # convert longitude to [-180,180) longitude[np.where(longitude > 180)] -= 360 # return the geometry and coordinate arrays return latitude, longitude, sza, local_time, x, y, cx, cy, context_map
def __compute_illumination_angles(self, et, spoint): return spice.ilumin( self.__method, self.__target, et, self.__frame, self.__abcorr, self.__observer, spoint)
def project(self, get_illum=True, use_full_image=False): ''' retrieve the planetographic coordinates of the center of each pixel in the image Parameters ---------- get_illum : bool flag to also retrieve illumination angles (incidence, emission and phase), and get a Lambertian correction [default: True] use_full_image : bool flag to process the full image, or use a bounding box of 1.2*(planetary radius) around the center to speed up computation. Turn off if bounding box produces errors. [default: False] ''' if not use_full_image: maxsize = np.max([self.obsa, self.obsb])*self.platecal.scale xstart, ystart = np.asarray(self.R2P0 - 1.2*maxsize, dtype=int) xend, yend = np.asarray(self.R2P0 + 1.2*maxsize, dtype=int) xstart = max([xstart, 0]) ystart = max([ystart, 0]) xend = min([xend, self.nx]) yend = min([yend, self.ny]) else: xstart = 0 xend = self.nx ystart = 0 yend = self.ny ## create the empty arrays to hold the values imgshape = self.img.shape[:2] self.lat = -1000.*np.ones(imgshape) self.lon = -1000.*np.ones(imgshape) if get_illum: self.incidence = np.zeros(imgshape) self.emission = np.zeros(imgshape) self.phase = np.zeros(imgshape) self.solar_corr = np.zeros(imgshape) for j in range(ystart, yend): if(j%10 == 0): print("\r %3d/%3d"%(j, yend), end='') for i in range(xstart, xend): ## find the vector that refers to this pixel pix = np.array([i,j], dtype=float) RADeci = self.pix2radec(pix) veci = spiceypy.radrec(1., RADeci[0], RADeci[1]) ## check for the intercept try: spoint, ep, srfvec = \ spiceypy.sincpt(\ "Ellipsoid", self.target, self.et,\ self.target_frame, "CN", "EARTH",\ "J2000", veci) except Exception as e: continue ## if the intercept works, determine the planetographic ## lat/lon values loni, lati, alt = \ spiceypy.recpgr(self.target, spoint, \ self.radii[0], self.flattening) self.lat[j,i] = np.degrees(lati) self.lon[j,i] = np.degrees(loni) if get_illum: _, _, phasei, inci, emissi = \ spiceypy.ilumin("Ellipsoid", self.target, \ self.et, self.target_frame, "CN",\ "EARTH", spoint) ## apply Lambertian correction mu = np.cos(emissi); mu0 = np.cos(inci) self.solar_corr[j,i] = 1./mu0 ## save the self.phase[j,i] = phasei self.incidence[j,i] = inci self.emission[j,i] = emissi img = self.img.copy() if get_illum: if(len(img.shape) > 2): for i in range(img.shape[2]): img[:,:,i] *= self.solar_corr ## plot them out fig = plt.figure(figsize=(8,15)) ax1 = fig.add_subplot(311) ax2 = fig.add_subplot(312) ax3 = fig.add_subplot(313) ax1.imshow(self.lon, vmin=0., vmax=360.) ax1.contour(self.lon, np.arange(0., 360., 15.), colors='k') ax2.imshow(self.lat, vmin=-90., vmax=90.) ax2.contour(self.lat, np.arange(-90, 90., 15.), colors='k') ax3.imshow(img) ax3.contour(self.lon, np.arange(0., 360., 30.), colors='k', linewidths=0.5) ax3.contour(self.lat, np.arange(-90, 90., 30.), colors='k', linewidths=0.5) ax1.set_title("Longitude") ax2.set_title("Latitude") plt.tight_layout() plt.show()
# Pluto-Charon angle vec_psurf_charon = vec_pluto_charon - vec_pluto_psurf ang = sp.vsep(vec_psurf_charon, vec_pluto_psurf) ang_pluto_charon[j, i] = ang # Pluto-SC angle vec_psurf_sc = vec_pluto_sc - vec_pluto_psurf ang = sp.vsep(vec_psurf_sc, vec_pluto_psurf) ang_pluto_sc[j, i] = ang # Now, do this all a second way, just to validate. (trgepc, srfvec, phase, solar, emmisn) = sp.ilumin('ELLIPSOID', 'PLUTO', et, 'IAU_PLUTO', abcorr, 'Charon', vec_pluto_psurf_iau) ang_pluto_sun_2[ j, i] = solar # Solar incidence angle, from normal, at point. THIS MATCHES -- GOOD! ang_pluto_charon_2[ j, i] = emmisn # Angle from surface normal, to observer. 0 .. pi. THIS MATCHES (trgepc, srfvec, phase, solar, emmisn) = sp.ilumin('ELLIPSOID', 'PLUTO', et, 'IAU_PLUTO', abcorr, 'New Horizons', vec_pluto_psurf_iau) ang_pluto_sc_2[ j, i] = emmisn # Angle from surface normal, to observer. 0 .. pi. THIS MATCHES
def _get_srfvec(self): if self.obs is None: raise ObserverNotSetError else: output = spice.ilumin("Ellipsoid", self.target, self.et, self.ref_frame, self.corr, self.obs, self.spoint) return output[1]