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')
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'))
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]
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
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]
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]:
In [30]:
print(isd['omega'], isd['phi'], isd['kappa'])
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
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 [ ]: