In [1]:
import json
import math

import numpy as np
import pvl
import spiceypy as spice

In [2]:
# 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

In [3]:
# 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')
res = spice.ckobj('tests/data/msgr_mdis_sc050727_100302_sub_v1.bc') for i in res: print(i) print() res = spice.ckobj('tests/data/msgr_mdis_gm040819_150430v1.bc') for i in res: print(i) print() res = spice.ckobj('tests/data//msgr_1304_v02.bc') for i in res: print(i)
spice.bodn2c('MESSENGER')

In [4]:
# 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, 1)
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, 9)
isd['odt_y'] = spice.gdpool('INS-{}_OD_T_Y'.format(ikid), 0, 9)
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)

What is the minimum information needed to convert to and from the MDIS-NAC frame?

236: The code for the messenger spacecraft 4: Indicates that the frame is a TK Frame 236820: The code for the MDIS-NAC Frame


In [5]:
# Type 4 is TK - the mdis-nac is constant w.r.t. another frame
print(spice.frinfo(-236820))

# Verify that this is messenger
print(spice.bods2c('MESSENGER'))


(-236, 4, -236820)
-236

In [6]:
# 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]
print(isd['semi_major_axis']) print(isd['semi_minor_axis'])

Now we need to compute time.


In [7]:
# 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)
print(et)
et += (exposure_duration / 2.0)

isd['ephemeris_time'] = et


418855170.48464954

In [36]:
# This needs to be sensor origin - like the comment below says...
# This is almost there - position w.r.t. the spacecraft, but not the camera yet.
loc, ltc = spice.spkpos('MESSENGER', isd['ephemeris_time'], 'IAU_MERCURY', 'NONE', isd['target_name'])
loc *= 1000
isd['x_sensor_origin'] = loc[0]
isd['y_sensor_origin'] = loc[1]
isd['z_sensor_origin'] = loc[2]
print(isd['x_sensor_origin']) print(isd['y_sensor_origin']) print(isd['z_sensor_origin'])

In [31]:
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 [34]:
camera2bodyfixed


Out[34]:
array([[ 0.56849023,  0.56123475, -0.60152673],
       [ 0.81728005, -0.30155688,  0.49103641],
       [ 0.09419218, -0.7707652 , -0.63011811]])

In [30]:
print(isd['omega'], isd['phi'], isd['kappa'])


2.256130940792258 0.09433201631102328 -0.9630375478615623

In [32]:
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))

In [33]:
!cat isd.isd


{"itrans_line": [0.0, 0.0, 71.42857143], "itrans_sample": [0.0, 71.42857143, 0.0], "z_sensor_origin": 2082873.9280557402, "target_name": "Mercury", "ccd_center": 512.5, "omega": 2.256130940792258, "ifov": 25.44, "starting_detector_line": 1.0, "boresight": [0.0, 0.0, 1.0], "transy": [0.0, 0.0, 0.014], "original_half_samples": 512.0, "focal_length_epsilon": 0.5, "kappa": -0.9630375478615623, "semi_major_axis": 2439.4, "ephemeris_time": 418855170.49264956, "instrument_id": "MDIS-NAC", "semi_minor_axis": 2439.4, "x_sensor_origin": 1728357.7031238307, "phi": 0.09433201631102328, "y_sensor_origin": -2088409.0061042644, "odt_y": [0.0, 0.0, 1.0, 0.0009060010594996751, 0.0, 0.0003574842626620758, 0.0, 1.004010471468856e-05, 0.0], "odt_x": [0.0, 1.001854269623802, 0.0, 0.0, -0.0005094440474941111, 0.0, 1.004010471468856e-05, 0.0, 1.004010471468856e-05], "nlines": 1024, "original_half_lines": 512.0, "nsamples": 1024, "spacecraft_name": "Messenger", "pixel_pitch": 0.014, "transx": [0.0, 0.014, 0.0], "starting_detector_sample": 9.0, "focal_length": 549.1178195372703}

In [ ]:
# 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 [ ]:
# OPK
isd['x_sensor_origin'] = 
isd['y_sensor_origin'] = 
isd['z_sensor_origin'] = 
isd['omega'] = 
isd['phi'] =
isd['kappa'] =

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

In [ ]:


In [ ]:
isd

In [ ]: