In [55]:
import json
import math

import numpy as np
import pvl
import spiceypy as spice

In [56]:
# Utility Func
def find_in_dict(obj, key):
    """
    Recursively find an entry in a dictionary

    Parameters
    ----------
    obj : dict
          The dictionary to search
    key : str
          The key to find in the dictionary

    Returns
    -------
    item : obj
           The value from the dictionary
    """
    if key in obj:
        return obj[key]
    for k, v in obj.items():
        if isinstance(v,dict):
            item = find_in_dict(v, key)
            if item is not None:
                return item
# OLD FURNISH THAT WAS NOT 100% IDENTICAL TO ISIS # Furnish the IK Kernel spice.furnsh("../../tests/data/msgr_mdis_v160.ti") ikid = 236820 spice.furnsh('../../tests/data/msgr_v231.tf') # Frames Kernel mapping between frames spice.furnsh('../../tests/data/pck00010_msgr_v23.tpc') # PC Kernel with planetary attitude and body information spice.furnsh('../../tests/data/msgr_dyn_v600.tf') spice.furnsh('../../tests/data/msgr_de405_de423s.bsp') spice.furnsh('../../tests/data/msgr_040803_150430_150430_od431sc_2.bsp') spice.furnsh('../../tests/data/msgr_mdis_sc050727_100302_sub_v1.bc') spice.furnsh('../../tests/data/msgr_mdis_gm040819_150430v1.bc') # MDIS Instrument Pointing (236890) spice.furnsh('../../tests/data/msgr_1304_v02.bc') #Bus and Spacecraft Panels position spice.furnsh('../../tests/data/naif0011.tls') spice.furnsh('../../tests/data/messenger_2548.tsc')

In [57]:
ikid = 236820
# Load kernels same order ISIS Spice::init() does
# Frame
# TargetAttitudeShape
spice.furnsh('../../tests/data/pck00010_msgr_v23.tpc')
# Instrument
spice.furnsh("../../tests/data/msgr_mdis_v160.ti")
# InstrumentAddendum
spice.furnsh('../../tests/data/mdisAddendum009.ti')
# LeapSecond
spice.furnsh('../../tests/data/naif0012.tls')
# SpacecraftClock
spice.furnsh('../../tests/data/messenger_2548.tsc')
# Extra
# TargetPosition
spice.furnsh('../../tests/data/de423s.bsp')
# InstrumentPointing
spice.furnsh('../../tests/data/msgr20130404.bc')
spice.furnsh('../../tests/data/msgr20130405.bc')
spice.furnsh('../../tests/data/msgr20130406.bc')
spice.furnsh('../../tests/data/msgr20130407.bc')
spice.furnsh('../../tests/data/msgr20130408.bc')
spice.furnsh('../../tests/data/msgr20130409.bc')
spice.furnsh('../../tests/data/msgr20130410.bc')
spice.furnsh('../../tests/data/msgr20130411.bc')
spice.furnsh('../../tests/data/1072683119_1965_mdis_atthist.bc')
spice.furnsh('../../tests/data/1072716050_291010_mdis_pivot_pvtres.bc')
spice.furnsh('../../tests/data/msgr_v231.tf')
# InstrumentPosition
spice.furnsh('../../tests/data/msgr_20040803_20150430_od431sc_2.bsp')

In [58]:
# Create the ISD object
isd = {}

# Load information from the IK kernel
isd['focal_length'] = spice.gdpool('INS-{}_FOCAL_LENGTH'.format(ikid), 0, 1)
isd['focal_length_epsilon'] = spice.gdpool('INS-{}_FL_UNCERTAINTY'.format(ikid), 0, 1)
isd['nlines'] = spice.gipool('INS-{}_PIXEL_LINES'.format(ikid), 0, 1)
isd['nsamples'] = spice.gipool('INS-{}_PIXEL_SAMPLES'.format(ikid), 0, 1)
isd['original_half_lines'] = isd['nlines'] / 2.0
isd['original_half_samples'] = isd['nsamples'] / 2.0
isd['pixel_pitch'] = spice.gdpool('INS-{}_PIXEL_PITCH'.format(ikid), 0, 1)
isd['ccd_center'] = spice.gdpool('INS-{}_CCD_CENTER'.format(ikid), 0, 2)
isd['ifov'] = spice.gdpool('INS-{}_IFOV'.format(ikid), 0, 1)
isd['boresight'] = spice.gdpool('INS-{}_BORESIGHT'.format(ikid), 0, 3)
isd['transx'] = spice.gdpool('INS-{}_TRANSX'.format(ikid), 0, 3)
isd['transy'] = spice.gdpool('INS-{}_TRANSY'.format(ikid), 0, 3)
isd['itrans_sample'] = spice.gdpool('INS-{}_ITRANSS'.format(ikid), 0, 3)
isd['itrans_line'] = spice.gdpool('INS-{}_ITRANSL'.format(ikid), 0, 3)
isd['odt_x'] = spice.gdpool('INS-{}_OD_T_X'.format(ikid), 0, 10)
isd['odt_y'] = spice.gdpool('INS-{}_OD_T_Y'.format(ikid), 0, 10)
isd['starting_detector_sample'] = spice.gdpool('INS-{}_FPUBIN_START_SAMPLE'.format(ikid), 0, 1)
isd['starting_detector_line'] = spice.gdpool('INS-{}_FPUBIN_START_LINE'.format(ikid), 0, 1)

In [59]:
def distort_focal_length(coeffs, t):
    """
    Compute the distorted focal length
    
    Parameters
    ----------
    coeffs : iterable
             of coefficient values
    t : float
        temperature in C
        
    Returns
    -------
    focal_length : float
                   the temperature adjusted focal length
    """
    focal_length = coeffs[0]
    for i in range(1, len(coeffs[1:])):
        focal_length += coeffs[i]*t**i
    return focal_length

In [60]:
# Load the ISIS Cube header
header = pvl.load('../../tests/data/EN1007907102M.cub')

isd['instrument_id'] = find_in_dict(header, 'InstrumentId')
isd['spacecraft_name'] = find_in_dict(header, 'SpacecraftName')
isd['target_name'] = find_in_dict(header, 'TargetName')

# Get the radii from SPICE
rad = spice.bodvrd(isd['target_name'], 'RADII', 3)
radii = rad[1]
isd['semi_major_axis'] = rad[1][0]
isd['semi_minor_axis'] = rad[1][1]

# Get temperature from SPICE and adjust focal length
spice.gdpool('INS-{}_FOCAL_LENGTH'.format(ikid), 0, 1)
temp_coeffs = spice.gdpool('INS-{}_FL_TEMP_COEFFS'.format(ikid), 0, 6)
temp = find_in_dict(header, 'FocalPlaneTemperature').value
isd['focal_length'] = distort_focal_length(temp_coeffs, temp)

Now we need to compute time. - This has been verified as correct using campt.


In [61]:
# Here convert the sclock
sclock = find_in_dict(header, 'SpacecraftClockCount')
exposure_duration = find_in_dict(header, 'ExposureDuration')
exposure_duration = exposure_duration.value * 0.001  # Scale to seconds

# Get the instrument id, and, since this is a framer, set the time to the middle of the exposure
spacecraft_id = spice.bods2c('MESSENGER')
et = spice.scs2e(spacecraft_id, sclock)
et += (exposure_duration / 2.0)

isd['ephemeris_time'] = et

In [62]:
# Comparing spacecraft position direct to Mercury body-fixed frame with J2000 to Mercury body-fixed
loc_direct, _ = spice.spkpos(isd['target_name'], isd['ephemeris_time'], 'IAU_MERCURY', 'LT+S', 'MESSENGER')
print(loc_direct * -1000)

# Target=Mercury, Observer=Messenger, go to J2000 first (to match ISIS3)
loc, ltc = spice.spkpos(isd['target_name'], isd['ephemeris_time'], 'J2000', 'LT+S', 'MESSENGER')
# Get the transformation from J2000 to Mercury body-fixed frame
rotation = spice.pxform('J2000', 'IAU_MERCURY', isd['ephemeris_time'])
loc = spice.mxv(rotation, loc)

# Scale to meters and reverse direction (since target=Mercury and observer=messenger)
# we want vector from Mercury origin to spacecraft position
isd['x_sensor_origin'] = loc[0] * -1000
isd['y_sensor_origin'] = loc[1] * -1000
isd['z_sensor_origin'] = loc[2] * -1000


[ 1728181.06360082 -2088202.56686554  2082707.60899282]

In [63]:
print(isd['x_sensor_origin'])
print(isd['y_sensor_origin'])
print(isd['z_sensor_origin'])


1728181.03408
-2088202.5913
2082707.60899

In [64]:
# Get the rotation angles from MDIS NAC frame to Mercury body-fixed frame
camera2bodyfixed = spice.pxform('MSGR_MDIS_NAC','IAU_MERCURY', isd['ephemeris_time'])
opk = spice.m2eul(camera2bodyfixed, 3, 2, 1)

isd['omega'] = opk[2]
isd['phi'] = opk[1]
isd['kappa'] = opk[0]

In [65]:
camera2bodyfixed


Out[65]:
array([[ 0.56851361,  0.56123674, -0.60150278],
       [ 0.81726217, -0.30156832,  0.49105916],
       [ 0.09420626, -0.77075928, -0.63012325]])

In [70]:
# Get the sun's position relative to a Mercury-fixed frame.
target = "SUN"
et = isd['ephemeris_time']
reference_frame = "IAU_MERCURY"
light_time_correction = "LT+S"
observer = "MERCURY"

sun_state, lt = spice.spkezr(target,
                             et,
                             reference_frame,
                             light_time_correction,
                             observer)

# Convert to meters
isd['x_sun_position'] = sun_state[0] * 1000
isd['y_sun_position'] = sun_state[1] * 1000
isd['z_sun_position'] = sun_state[2] * 1000
print("SUN POSITION (m): {} {} {}".format(sun_state[0]*1000,
                                          sun_state[1]*1000,
                                          sun_state[2]*1000))

# Get velocity of mdis nac (right now it is getting velocity of spacecraft)
target = "MESSENGER"
et = isd['ephemeris_time']
reference_frame = "IAU_MERCURY"
light_time_correction = "LT+S"
observer = "MERCURY"
messenger_state, lt = spice.spkezr(target,
                                   et,
                                   reference_frame,
                                   light_time_correction,
                                   observer)
print("MESSENGER VELOCITY (m/s): {} {} {}".format(messenger_state[3]*1000,
                                                  messenger_state[4]*1000,
                                                  messenger_state[5]*1000))

v,_ = spice.spkezr(observer, et, reference_frame, light_time_correction, target)
print(v)


SUN POSITION (m): -31648725087.588726 -60633907522.72863 -38729485.77334732
MESSENGER VELOCITY (m/s): 1998.2873093664398 -1800.8962292264728 -1674.7631538476487
[ -1.72818106e+03   2.08820257e+03  -2.08270761e+03  -1.99769080e+00
   1.80028686e+00   1.67474034e+00]

In [67]:
class NumpyAwareJSONEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, np.ndarray) and obj.ndim == 1:
            lobj = obj.tolist()
            if len(lobj) == 1:
                return lobj[0]
            else:
                return lobj
        return json.JSONEncoder.default(self, obj)

with open('isd.isd', 'w') as f:
    f.write(json.dumps(isd, f, cls=NumpyAwareJSONEncoder, sort_keys=True, indent=4))

In [68]:
!cat isd.isd


{
    "boresight": [
        0.0,
        0.0,
        1.0
    ],
    "ccd_center": [
        512.5,
        512.5
    ],
    "ephemeris_time": 418855170.49264956,
    "focal_length": 549.2347965210602,
    "focal_length_epsilon": 0.5,
    "ifov": 25.44,
    "instrument_id": "MDIS-NAC",
    "itrans_line": [
        0.0,
        0.0,
        71.42857143
    ],
    "itrans_sample": [
        0.0,
        71.42857143,
        0.0
    ],
    "kappa": -0.963008015000929,
    "nlines": 1024,
    "nsamples": 1024,
    "odt_x": [
        0.0,
        1.001854269623802,
        0.0,
        0.0,
        -0.0005094440474941111,
        0.0,
        1.004010471468856e-05,
        0.0,
        1.004010471468856e-05,
        0.0
    ],
    "odt_y": [
        0.0,
        0.0,
        1.0,
        0.0009060010594996751,
        0.0,
        0.0003574842626620758,
        0.0,
        1.004010471468856e-05,
        0.0,
        1.004010471468856e-05
    ],
    "omega": 2.25613869898165,
    "original_half_lines": 512.0,
    "original_half_samples": 512.0,
    "phi": 0.09434616179037647,
    "pixel_pitch": 0.014,
    "semi_major_axis": 2439.4,
    "semi_minor_axis": 2439.4,
    "spacecraft_name": "Messenger",
    "starting_detector_line": 1.0,
    "starting_detector_sample": 9.0,
    "target_name": "Mercury",
    "transx": [
        0.0,
        0.014,
        0.0
    ],
    "transy": [
        0.0,
        0.0,
        0.014
    ],
    "x_sensor_origin": 1728181.0340792781,
    "x_sun_position": -31648725087.588726,
    "y_sensor_origin": -2088202.591297346,
    "y_sun_position": -60633907522.72863,
    "z_sensor_origin": 2082707.608992824,
    "z_sun_position": -38729485.77334732
}
# Get the camera position in lat, lon, height # lat/lon are in raddians _, radii = spice.bodvrd("MERCURY", "RADII", 3) radii *= 1000 flattening = (radii[0] - radii[2]) / radii[0] lon, lat, height = spice.recgeo(loc * 1000, radii[0], flattening) # Can I use X, Y, Z body fixed in meters, or do I need to use lat, lon, height # in rectangular coordinates? #isd['x_sensor_origin'] = lon #isd['y_sensor_origin'] = lat #isd['z_sensor_origin'] = height

In [ ]:

# This needs to go from object space to image space - right now, it goes from object space (Mercury) # to sensor position space (MDIS_NAC) camera2bodyfixed = spice.pxform('MSGR_MDIS_NAC', 'IAU_MERCURY', isd['ephemeris_time']) camopk = spice.m2eul(camera2bodyfixed, 3, 2, 1) isd['omega'] = camopk[2] isd['phi'] = camopk[1] isd['kappa'] = camopk[0] # Rotation around Y, Z from camera to focal plane focal = np.zeros((3,3)) focal[0][0] = 1 focal[1][1] = -1 focal[2][2] = -1 focalrot = spice.mxmt(focal, camera2bodyfixed) # np.dot().T # Get the length of the vector xyzlength = loc[0]**2 + loc[1]**2 xylength = math.sqrt(xyzlength) xyzlength = math.sqrt(xyzlength + loc[2]**2) slon = loc[1] / xylength clon = loc[0] / xylength slat = loc[2] / xyzlength clat = xylength / xyzlength #Ocentric to ographic rotation oo = np.zeros((3,3)) oo[:,0] = -slon, clon, 0.0 oo[:,1] = -slat * clon, -slat * slon, clat oo[:,2] = clat*clon, clat*slon, slat rotter = spice.mxm(focalrot, oo) # np.dot print('R', rotter) opk = spice.m2eul(rotter, 3, 2, 1) print(opk) print(list(map(math.degrees, opk))) #isd['omega'] = opk[2] #isd['phi'] = opk[1] #isd['kappa'] = opk[0]

In [69]:
%matplotlib notebook
from mpl_toolkits.mplot3d import Axes3D
from itertools import product, combinations

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.set_aspect('equal')

u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)

x = 1 * np.outer(np.cos(u), np.sin(v))
y = 1 * np.outer(np.sin(u), np.sin(v))
z = 1 * np.outer(np.ones(np.size(u)), np.cos(v))
#for i in range(2):
#    ax.plot_surface(x+random.randint(-5,5), y+random.randint(-5,5), z+random.randint(-5,5),  rstride=4, cstride=4, color='b', linewidth=0, alpha=0.5)
elev = 10.0
rot = 80.0 / 180 * np.pi
ax.plot_surface(x, y, z,  rstride=4, cstride=4, color='b', linewidth=0, alpha=0.5)

# Plot the origin of the body fixed coordinate system
ax.scatter(0, 0, 0, 'ko', s=50)

# Plot the spacecraft position, normalized to the radius of the sphere

x = isd['x_sensor_origin'] / radii[0]
y = isd['y_sensor_origin'] / radii[0]
z = isd['z_sensor_origin'] / radii[0]

delta = 0.075
px = float(x + delta)
py = float(y + delta)
pz = float(z + delta)
nx = float(x - delta)
ny = float(y - delta)
nz = float(z - delta)

coords = np.array([(px, py, pz), 
                   (px, py, nz),
                   (px, ny, nz),
                   (px, ny, pz),
                   (px, py, pz),
                   (nx, py, pz),
                   (nx, py, nz),
                   (nx, ny, nz),
                   (nx, ny, pz),
                   (nx, py, pz),
                   (nx, ny, pz),
                  (px, ny, pz),
                  (px, ny, nz), 
                  (nx, ny, nz),
                  (nx, py, nz),
                  (px, py, nz)])
          
ax.plot_wireframe(coords[:,0], coords[:,1], coords[:,2],color= 'r')

#print(isd['boresight'])

ax.quiver(x, y, z, 0,0,1, color='green', pivot='tail')  # Boresight

print(camera2bodyfixed.dot(np.array([0, 0, isd['focal_length']])))
ax.quiver(x, y, z, *camera2bodyfixed.dot(np.array([0, 0, isd['focal_length']])), color='black', pivot='tail')


---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-69-9fe8051f3d6e> in <module>()
      3 from itertools import product, combinations
      4 
----> 5 fig = plt.figure()
      6 ax = fig.add_subplot(111, projection='3d')
      7 ax.set_aspect('equal')

NameError: name 'plt' is not defined

In [ ]:


In [ ]:
spice.spkez(-236820, isd['ephemeris_time'], 'IAU_MERCURY', "NONE", 199 )

In [ ]:


In [ ]:
!cat isd.isd

In [14]:
# This is hard coded in Anne's script
isisFocalPlan2SocetPlate = np.eye(3)
isisFocalPlan2SocetPlate[1,1] = -1.0
isisFocalPlan2SocetPlate[2,2] = -1.0

# Grab the body fixed coordinates from SPICE

# The mercury Naif ID code is 199
nid = 199

In [15]:
# OPK
isd['x_sensor_origin'] = 
isd['y_sensor_origin'] = 
isd['z_sensor_origin'] = 
isd['omega'] = 
isd['phi'] =
isd['kappa'] =


  File "<ipython-input-15-69367ee46c92>", line 2
    isd['x_sensor_origin'] =
                             ^
SyntaxError: invalid syntax

In [16]:
# ISD Search Information - totally fabricated.
isd['min_elevation'] = -1.0
isd['max_elevation'] = 1.0

In [ ]:


In [17]:
isd


Out[17]:
{'boresight': array([ 0.,  0.,  1.]),
 'ccd_center': array([ 512.5]),
 'ephemeris_time': 418855170.49264956,
 'focal_length': array([ 549.11781954]),
 'focal_length_epsilon': array([ 0.5]),
 'ifov': array([ 25.44]),
 'instrument_id': 'MDIS-NAC',
 'itrans_line': array([  0.        ,   0.        ,  71.42857143]),
 'itrans_sample': array([  0.        ,  71.42857143,   0.        ]),
 'kappa': -0.9630375478615623,
 'max_elevation': 1.0,
 'min_elevation': -1.0,
 'nlines': array([1024]),
 'nsamples': array([1024]),
 'odt_x': array([  0.00000000e+00,   1.00185427e+00,   0.00000000e+00,
          0.00000000e+00,  -5.09444047e-04,   0.00000000e+00,
          1.00401047e-05,   0.00000000e+00,   1.00401047e-05]),
 'odt_y': array([  0.00000000e+00,   0.00000000e+00,   1.00000000e+00,
          9.06001059e-04,   0.00000000e+00,   3.57484263e-04,
          0.00000000e+00,   1.00401047e-05,   0.00000000e+00]),
 'omega': 2.256130940792258,
 'original_half_lines': array([ 512.]),
 'original_half_samples': array([ 512.]),
 'phi': 0.09433201631102328,
 'pixel_pitch': array([ 0.014]),
 'semi_major_axis': 2439.4000000000001,
 'semi_minor_axis': 2439.4000000000001,
 'spacecraft_name': 'Messenger',
 'starting_detector_line': array([ 1.]),
 'starting_detector_sample': array([ 9.]),
 'target_name': 'Mercury',
 'transx': array([ 0.   ,  0.014,  0.   ]),
 'transy': array([ 0.   ,  0.   ,  0.014]),
 'x_sensor_origin': 1728357.7031238307,
 'y_sensor_origin': -2088409.0061042644,
 'z_sensor_origin': 2082873.9280557402}

In [ ]:

# Get the sun's position relative to a Mercury-fixed frame. target = "SUN" et = isd['ephemeris_time'] reference_frame = "IAU_MERCURY" light_time_correction = "LT+S" observer = "MERCURY" sun_state, lt = spice.spkezr(target, et, reference_frame, light_time_correction, observer) isd['x_sun_position'] = sun_state[0] * 1000 isd['y_sun_position'] = sun_state[1] * 1000 isd['z_sun_position'] = sun_state[2] * 1000 print("SUN POSITION (m): {} {} {}".format(sun_state[0]*1000, sun_state[1]*1000, sun_state[2]*1000)) # Get velocity of mdis nac (right now it is getting velocity of spacecraft, not sensor) target = "MESSENGER" et = isd['ephemeris_time'] reference_frame = "IAU_MERCURY" light_time_correction = "LT+S" observer = "MERCURY" messenger_state, lt = spice.spkezr(target, et, reference_frame, light_time_correction, observer) print("MESSENGER VELOCITY (m/s): {} {} {}".format(messenger_state[3]*1000, messenger_state[4]*1000, messenger_state[5]*1000))

In [ ]: