def nearest_moon(dt, target='CASSINI'): """ :param dt: :param target: :return: """ et = spice.datetime2et(dt) moondict = {} NAIFIDS = range(601, 654, 1) for x in NAIFIDS: moon = spice.bodc2s(x) frame = 'IAU_' + moon.upper() observ = moon.upper() corrtn = 'NONE' state, ltime = spice.spkpos(target, et, frame, corrtn, observ) # TODO do full calculation of altitude lon, lat, alt = spice.recpgr( moon.upper(), state, spice.bodvrd(moon.upper(), 'RADII', 3)[1][0], 2.64e-4) moondict[moon] = alt sorteddict = OrderedDict(sorted(moondict.items(), key=lambda t: t[1])) return sorteddict
def cassini_titan_altlatlon(tempdatetime): et = spice.datetime2et(tempdatetime) state, ltime = spice.spkezr('CASSINI', et, 'IAU_TITAN', 'NONE', 'TITAN') lon, lat, alt = spice.recpgr('TITAN', state[:3], spice.bodvrd('TITAN', 'RADII', 3)[1][0], 2.64e-4) return alt, lat * spice.dpr(), lon * spice.dpr()
def find_sub_pt(self): ''' Finds the sub-observer point in the IAU_[target] frame and also the in the J2000 frame as seen from Earth. Also creates a vector from Earth to the sub-obs point in the J2000 frame for future use. ''' ## get the position of the sub-obs point in the J2000 frame self.subptvec, self.subptep, self.subpntobsvec = \ spiceypy.subpnt('INTERCEPT/ELLIPSOID', self.target, \ self.et, self.target_frame, 'CN', 'EARTH') ## convert to lat/lon self.subptlon, self.subptlat, _ = \ spiceypy.recpgr(self.target, self.subptvec, \ self.radii[0], self.flattening) ## convert the line of sight vector to J2000 px1 = spiceypy.pxfrm2(self.target_frame, 'J2000', \ self.subptep, self.et) self.subptJ2000 = np.matmul(px1, self.subpntobsvec) ## get the RA/DEC of the sub-obs point self.subRA, self.subDec = spiceypy.recrad(self.subptJ2000)[1:] self.RADec0 = np.array([self.subRA, self.subDec])
def cassini_altlatlon(utc, target='TITAN', output=False): state = cassini_phase(utc) lon, lat, alt = spice.recpgr(target, state[:3], spice.bodvrd(target, 'RADII', 3)[1][0], 2.64e-4) if output: print("ALtitude", alt) print("Latitude", lat * spice.dpr()) print("Longtitude", lon * spice.dpr()) return alt, lat * spice.dpr(), lon * spice.dpr()
def cassini_altitude(dt, moon, target='CASSINI'): """ :param dt: :param moon: :param target: :return: """ et = spice.datetime2et(dt) frame = 'IAU_' + moon.upper() observ = moon.upper() corrtn = 'NONE' state, ltime = spice.spkpos(target, et, frame, corrtn, observ) # TODO do full calculation of altitude lon, lat, alt = spice.recpgr(moon.upper(), state, spice.bodvrd(moon.upper(), 'RADII', 3)[1][0], 2.64e-4) return alt
def bodyHA(body,et,qlon): import spiceypy as sp # SUB POINT POSITION pos=sp.subpnt("Intercept: ellipsoid", "EARTH",et,"IAU_EARTH","NONE", body) lpos=sp.recpgr("EARTH",pos[0],REARTH,FEARTH); # LATITUDE AND LONGITUDE lon=lpos[0]*RAD lat=lpos[1]*RAD # print d2s(lon),d2s(lat) # DIFFERENCE IN LONGITUDE dlon=numpy.mod(qlon-lon,360) # HOUR ANGLE # H = LST - ALPHA ha=dlon return ha
def f(p): return spiceypy.recpgr(body, p, r, e)
def __Geometry(self, boresight=''): #if self.geometry_flag is True and \ # self.time.window.all() == self.previous_tw.all(): # return distance = [] altitude = [] boresight_latitude = [] boresight_longitude = [] latitude = [] longitude = [] subpoint_xyz = [] subpoint_pgc = [] subpoint_pcc = [] zaxis_target_angle = [] myaxis_target_angle = [] yaxis_target_angle = [] xaxis_target_angle = [] beta_angle = [] qs, qx, qy, qz = [], [], [] ,[] x, y, z = [],[],[] tar = self.target time = self.time for et in time.window: try: # # Compute the distance # ptarg, lt = spiceypy.spkpos(tar.name, et, tar.frame, time.abcorr, self.name) x.append(ptarg[0]) y.append(ptarg[1]) z.append(ptarg[2]) vout, vmag = spiceypy.unorm(ptarg) distance.append(vmag) # # Compute the geometric sub-observer point. # if tar.frame == 'MARSIAU': tar_frame = 'IAU_MARS' else: tar_frame = tar.frame spoint, trgepc, srfvec = spiceypy.subpnt(tar.method, tar.name, et, tar_frame, time.abcorr, self.name) subpoint_xyz.append(spoint) # # Compute the observer's altitude from SPOINT. # dist = spiceypy.vnorm(srfvec) altitude.append(dist) # # Convert the sub-observer point's rectangular coordinates to # planetographic longitude, latitude and altitude. # spglon, spglat, spgalt = spiceypy.recpgr(tar.name, spoint, tar.radii_equ, tar.flat) # # Convert radians to degrees. # spglon *= spiceypy.dpr() spglat *= spiceypy.dpr() subpoint_pgc.append([spglon, spglat, spgalt]) # # Convert sub-observer point's rectangular coordinates to # planetocentric radius, longitude, and latitude. # spcrad, spclon, spclat = spiceypy.reclat(spoint) # # Convert radians to degrees. # spclon *= spiceypy.dpr() spclat *= spiceypy.dpr() subpoint_pcc.append([spclon, spclat, spcrad]) latitude.append(spclat) #TODO: Remove with list extraction longitude.append(spclon) # TODO: Remove with list extraction # # Compute the geometric sub-boresight point. # if tar.frame == 'MARSIAU': tar_frame = 'IAU_MARS' else: tar_frame = tar.frame if boresight: try: id = spiceypy.bodn2c(boresight) (shape,framen, bsight, n, bounds) = spiceypy.getfov(id, 80) mat = spiceypy.pxform(framen,tar_frame,et) except: framen = boresight bsight = 0,0,1 else: bsight = self.name try: if tar.method == 'INTERCEPT/ELLIPSOID': method = 'ELLIPSOID' else: method = tar.method spoint, trgepc, srfvec = spiceypy.sincpt(method, tar.name, et, tar_frame, time.abcorr, self.name, framen, bsight) # # Convert the sub-observer point's rectangular coordinates to # planetographic longitude, latitude and altitude. # spglon, spglat, spgalt = spiceypy.recpgr(tar.name, spoint, tar.radii_equ, tar.flat) # # Convert radians to degrees. # spglon *= spiceypy.dpr() spglat *= spiceypy.dpr() # # Convert sub-observer point's rectangular coordinates to # planetocentric radius, longitude, and latitude. # spcrad, spclon, spclat = spiceypy.reclat(spoint) # # Convert radians to degrees. # spclon *= spiceypy.dpr() spclat *= spiceypy.dpr() boresight_latitude.append(spclat) boresight_longitude.append(spclon) except: pass # # Compute the angle between the observer's S/C axis and the # geometric sub-observer point # obs_tar, ltime = spiceypy.spkpos(tar.name, et, 'J2000', time.abcorr, self.name) obs_zaxis = [0, 0, 1] obs_myaxis = [0, -1, 0] obs_yaxis = [0, 1, 0] obs_xaxis = [1, 0, 0] # # We need to account for when there is no CK attitude available. # try: matrix = spiceypy.pxform(self.frame, 'J2000', et) z_vecout = spiceypy.mxv(matrix, obs_zaxis) zax_target_angle = spiceypy.vsep(z_vecout, obs_tar) zax_target_angle *= spiceypy.dpr() zaxis_target_angle.append(zax_target_angle) my_vecout = spiceypy.mxv(matrix, obs_myaxis) myax_target_angle = spiceypy.vsep(my_vecout, obs_tar) myax_target_angle *= spiceypy.dpr() myaxis_target_angle.append(myax_target_angle) y_vecout = spiceypy.mxv(matrix, obs_myaxis) yax_target_angle = spiceypy.vsep(y_vecout, obs_tar) yax_target_angle *= spiceypy.dpr() yaxis_target_angle.append(yax_target_angle) x_vecout = spiceypy.mxv(matrix, obs_myaxis) xax_target_angle = spiceypy.vsep(x_vecout, obs_tar) xax_target_angle *= spiceypy.dpr() xaxis_target_angle.append(xax_target_angle) quat = spiceypy.m2q(spiceypy.invert(matrix)) qs.append(quat[0]) qx.append(-1*quat[1]) qy.append(-1*quat[2]) qz.append(-1*quat[3]) except: zaxis_target_angle.append(0.0) myaxis_target_angle.append(0.0) yaxis_target_angle.append(0.0) xaxis_target_angle.append(0.0) qs.append(0.0) qx.append(0.0) qy.append(0.0) qz.append(0.0) beta_angle.append(spiops.beta_angle(self.name, self.target.name, et)) except: boresight_latitude = 0 boresight_longitude = 0 distance = 0 altitude = 0 latitude = 0 longitude = 0 subpoint_xyz = [0,0,0] subpoint_pgc = [0,0,0] subpoint_pcc = [0,0,0] zaxis_target_angle = 0 myaxis_target_angle = 0 yaxis_target_angle = 0 xaxis_target_angle = 0 beta_angle = 0 (qx, qy, qz, qs) = 0, 0, 0, 0 (x, y, z) = 0, 0, 0 self.boresight_latitude = boresight_latitude self.boresight_longitude = boresight_longitude self.distance = distance self.altitude = altitude self.latitude = latitude self.longitude = longitude self.subpoint_xyz = subpoint_xyz self.subpoint_pgc = subpoint_pgc self.subpoint_pcc = subpoint_pcc self.zaxis_target_angle = zaxis_target_angle self.myaxis_target_angle = myaxis_target_angle self.yaxis_target_angle = yaxis_target_angle self.xaxis_target_angle = xaxis_target_angle self.beta_angle = beta_angle self.quaternions = [qx, qy, qz, qs] self.trajectory = [x,y,z] self.geometry_flag = True self.previous_tw = self.time.window return
def cassini_titan_test(flyby, anodes=False): times = [] states = [] lons, lats, alts = [], [], [] crossvecs_lonlatalts = [] crossvecs_lonlatalts_spicenormal = [] cmats = [] vecs = [] anode_vecs = [] anode_seps = [[], [], [], [], [], [], [], []] anodes1, anodes8 = [], [] crossvecs = [] angularseparations = [] beamanodes = [] spiceplanenormals = [] windsdf = pd.read_csv("crosswinds_full.csv", index_col=0, parse_dates=True) tempdf = windsdf[windsdf['Flyby'] == flyby] for tempdatetime, negwindspeed, poswindspeed in zip( pd.to_datetime(tempdf['Bulk Time']), tempdf["Negative crosstrack velocity"], tempdf["Positive crosstrack velocity"]): print("---------") print(tempdatetime) times.append(tempdatetime) beamanodes.append(np.mean(ELS_ramanodes(tempdatetime)) + 1) states.append(cassini_phase( tempdatetime.strftime('%Y-%m-%dT%H:%M:%S'))) # print(states[-1]) lon, lat, alt = spice.recpgr("TITAN", states[-1][:3], spice.bodvrd("TITAN", 'RADII', 3)[1][0], 1.44e-4) lons.append(lon * spice.dpr()) lats.append(lat * spice.dpr()) alts.append(alt) # vecs.append(cassini_act_2_titan(tempdatetime)) crossvec = caps_crosstrack(tempdatetime, np.mean([negwindspeed, poswindspeed])) print("crossvec", crossvec) testspicenormal, anode1, anode8 = caps_crosstrack_spice( tempdatetime, np.mean([negwindspeed, poswindspeed])) anodes1.append(anode1) anodes8.append(anode8) spiceplanenormals.append(testspicenormal) print("test spice normal", testspicenormal) jacobian = spice.dpgrdr("TITAN", states[-1][0], states[-1][1], states[-1][2], spice.bodvrd('TITAN', 'RADII', 3)[1][0], 1.44e-4) # print("jacobian", jacobian) crossvec_lonlatalt = spice.mxv(jacobian, spice.vhat(crossvec)) crossvec_lonlatalt_spicenormal = spice.mxv(jacobian, testspicenormal) # print("recpgr", lon, lat, alt) # print("crossvec latlon", crossvec_lonlatalt) # print("crossvec latlon vhat", spice.vhat(crossvec_latlon)) crossvecs.append(crossvec) crossvecs_lonlatalts.append(crossvec_lonlatalt) crossvecs_lonlatalts_spicenormal.append(crossvec_lonlatalt_spicenormal) # print("Time", tempdatetime) # print("position", states[-1][:3]) # print("velocity", spice.vhat(states[-1][3:])) # print("direction", spice.vhat(vecs[-1])) # if anodes: # anode_vecs.append(caps_all_anodes(tempdatetime)) # print("anode vecs 1 & 8", anode_vecs[-1][0], anode_vecs[-1][7]) # # spiceplanenormal = spice.psv2pl(states[-1][:3],anode_vecs[-1][0],anode_vecs[-1][7]) # # print("SPICE NORMAL", spice.pl2nvp(spiceplanenormal)) # # # # spiceplanenormals.append(-1*spice.pl2nvp(spiceplanenormal)[0]) # # print("Crossvec", crossvec) # for anodecounter, i in enumerate(anode_vecs[-1]): # # print(anodecounter,anode_vecs[-1][anodecounter]) # anode_seps[anodecounter].append( # spice.vsep(spice.vhat(states[-1][3:]), spice.vhat(anode_vecs[-1][anodecounter])) * spice.dpr()) # print("anodeseps",anode_seps) # print("Angular Separation", spice.vsep(spice.vhat(states[-1][3:]), spice.vhat(vecs[-1])) * spice.dpr()) x, y, z, u, v, w = [], [], [], [], [], [] for i in states: x.append(i[0]) y.append(i[1]) z.append(i[2]) # CAPS direction for i in vecs: u.append(i[0]) v.append(i[1]) w.append(i[2]) # Crosstrack u2, v2, w2 = [], [], [] for j in crossvecs: u2.append(j[0]) v2.append(j[1]) w2.append(j[2]) # SPICE plane normal u3, v3, w3 = [], [], [] for j in spiceplanenormals: u3.append(j[0]) v3.append(j[1]) w3.append(j[2]) # Ram Direction u1, v1, w1 = [], [], [] for i in states: u1.append(i[3]) v1.append(i[4]) w1.append(i[5]) fig = plt.figure() u = np.linspace(0, 2 * np.pi, 50) v = np.linspace(0, np.pi, 50) x_sphere = 2574.7 * np.outer(np.cos(u), np.sin(v)) y_sphere = 2574.7 * np.outer(np.sin(u), np.sin(v)) z_sphere = 2574.7 * np.outer(np.ones(np.size(u)), np.cos(v)) ax = fig.add_subplot(111, projection='3d') # Plot the surface # ax.plot_wireframe(x_sphere, y_sphere, z_sphere, color='b') # ax.plot(x, y, z, alpha=0.5, color='k') if anodes: for timecounter, (i, j) in enumerate(zip(anodes1, anodes8)): X = x[timecounter] Y = y[timecounter] Z = z[timecounter] # print(i) # for anodecounter, j in enumerate(i): # if anodecounter in [0, 7]: # ax.quiver(X, Y, Z, j[0], j[1], j[2], length=20, color='C' + str(anodecounter)) # print(timecounter, i, j) ax.quiver(X, Y, Z, i[0], i[1], i[2], length=30, color='C1') ax.quiver(X, Y, Z, j[0], j[1], j[2], length=30, color='C2') ax.quiver(x, y, z, u2, v2, w2, length=30, color='m') ax.quiver(x, y, z, u1, v1, w1, length=5, color='k') ax.quiver(x, y, z, u3, v3, w3, length=30, color='r') ax.set_xlabel("X") ax.set_ylabel("Y") ax.set_zlabel("Z") ax.set_xlim(min(x), max(x)) ax.set_ylim(min(y), max(y)) ax.set_zlim(min(z), max(z)) dlat, dlon = [], [] for i in crossvecs_lonlatalts: dlat.append(i[1]) dlon.append(i[0]) dlat_spicenormal, dlon_spicenormal = [], [] for i in crossvecs_lonlatalts_spicenormal: dlat_spicenormal.append(i[1]) dlon_spicenormal.append(i[0]) fig2, ax2 = plt.subplots() ax2.plot(lons, lats) ax2.quiver(lons, lats, dlon, dlat) ax2.quiver(lons, lats, dlon_spicenormal, dlat_spicenormal, color='r') ax2.set_xlabel("Longitude") ax2.set_ylabel("Latitude") ax2.grid()
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()
def vector_params(self, vector) : ret = np.full(shape = [len(self.keys)], fill_value = -1000.0) # Calculate the distance of the boresight and the center of the target origin = np.array([0.0, 0.0, 0.0]) nearpoint, rayradius = spice.nplnpt(self.scloc, vector, origin) # Get the intercept to calculate the radius of of the target normal = spice.surfpt(origin, 1000.0 * nearpoint, self.radii[0], self.radii[1], self.radii[2]) ret[self.map['limb_distance']] = rayradius - spice.vnorm(normal) # Calculate the 'occultation' latitude and longitude ret[self.map['bodyintercept']], ret[self.map['limb_lat']], ret[self.map['limb_lon']] = spice.reclat(nearpoint) # Test if the boresight intersects with our target surface try: point = spice.surfpt(self.scloc, vector, self.radii[0], self.radii[1], self.radii[2]) intercept = True except: intercept = False if (intercept) : # Get some angles ret[self.map['phase']], ret[self.map['incidence']], ret[self.map['emission']] = spice.illum(self.target, self.et , self.abcorr, self.spacecraft, point) # Calculate the planetocentric coordinates distance, ret[self.map['lon']], ret[self.map['lat']] = spice.reclat(point) ret[self.map['losdist']] = spice.vnorm(self.scloc - point) # Calculate the planetographic coordinates ret[self.map['lon_graphic']], ret[self.map['lat_graphic']], bodyintercept = spice.recpgr(self.target, point, self.radii[0], self.flattening) # Get the localtime, and convert to decimal hours hr, min, sc, time, ampm = spice.et2lst(self.et, self.target_id, ret[self.map['lon']], 'PLANETOCENTRIC') ret[self.map['localtime']] = hr + min / 60.0 + sc / 3600.0 # For the angles, convert radians to degrees for key in self.angles : if (ret[self.map[key]] != -1000.0) : ret[self.map[key]] = np.rad2deg(ret[self.map[key]]) # Makes sure longitudes wrap 0 to 360, spice returns the Earth-like -180 to 180. longitudes = ['lon', 'limb_lon', 'lon_graphic'] for key in longitudes : ret[self.map[key]] = ret[self.map[key]] % 360 return np.array(ret)