Пример #1
0
    def spacecraft_direction(self):
        """
        Returns the x axis of the first velocity vector relative to the
        spacecraft. This indicates of the craft is moving forwards or backwards.

        From LROC Frame Kernel: lro_frames_2014049_v01.tf
        "+X axis is in the direction of the velocity vector half the year. The
        other half of the year, the +X axis is opposite the velocity vector"

        Hence we rotate the first velocity vector into the sensor reference
        frame, but the X component of that vector is inverted compared to the
        spacecraft so a +X indicates backwards and -X indicates forwards

        The returned velocity is also slightly off from the spacecraft velocity
        due to the sensor being attached to the craft with wax.

        Returns
        -------
        direction : double
                    X value of the first velocity relative to the sensor
        """
        frame_chain = self.frame_chain
        lro_bus_id = spice.bods2c('LRO_SC_BUS')
        time = self.ephemeris_start_time
        state, _ = spice.spkezr(self.spacecraft_name, time, 'J2000', 'None',
                                self.target_name)
        position = state[:3]
        velocity = state[3:]
        rotation = frame_chain.compute_rotation(1, lro_bus_id)
        rotated_velocity = spice.mxv(rotation._rots.as_matrix()[0], velocity)
        return rotated_velocity[0]
Пример #2
0
 def ikid(self):
     """
     Returns
     -------
     : int
       Naif ID used to for indentifying the instrument in Spice kernels
     """
     return spice.bods2c(self.instrument_id)
Пример #3
0
    def _tc_id(self):
        """
        Returns ikid of LISM_TC1 or LISM_TC2, depending which camera was used
        for capturing the image.

        Some keys are stored in the IK kernel under a general ikid for TC1/TC2
        presumably because they are not affected by the addtional parameters encoded in
        the ikid returned by self.ikid. This method exists for those gdpool calls.
        """
        return spice.bods2c("LISM_{}".format(super().instrument_id))
Пример #4
0
    def ikid(self):
        """
        Returns the Naif ID code for HRSC SRC. 

        Returns
        -------
        : int
          Naif ID used to for indentifying the instrument in Spice kernels
        """
        return spice.bods2c("MEX_HRSC_SRC")
Пример #5
0
    def ikid(self):
        """
            Returns the Naif ID code for the HRSC head instrument

            This would be the Naif ID code for the base (or "head") instrument.

            Returns
            -------
            : int
              Naif ID used to for indentifying the instrument in Spice kernels
            """
        return spice.bods2c("MEX_HRSC_HEAD")
Пример #6
0
def utc2scs_spice(tais, sc):
    res = {}
    try:
        scid = sp.bods2c(sc)
        for tai in tais:
            et = sp.unitim(tai, 'tai', 'et')
            obt = sp.sce2s(scid, et)
            utc = sp.et2utc(et, 'isoc', 3)

            res[utc] = obt
    except sp.stypes.SpiceyError as ex:
        raise GeometrySpiceError(ex.value)
    else:
        return res
Пример #7
0
def state_internal(func_spice, utc, utc_end, deltat, kind, observer, target, ref, abcorr):
    try:
        tgt = sp.bods2c(target)
        obs = sp.bods2c(observer)
    except sp.stypes.SpiceyError as ex:
        raise GeometrySpiceError(ex.value)

    if abcorr is None:
        abcorr = 'NONE'
    if kind is not None:
        kind = kind.lower()

    try:
        xfunc = _POSITION_KIND[kind]
    except KeyError:
        raise ValidationError(kind)

    kwargs = {'observer': obs,
              'target': tgt,
              'ref': ref,
              'abcorr': abcorr}

    tais = utc2tai(utc, utc_end, deltat)
    return wrap_result(distribute_work(func_spice, xfunc, tais, **kwargs))
Пример #8
0
    def fikid(self):
        """
            Naif ID code of the filter dependent instrument codes.

            Expects filter_number to be defined. This should be an integer containing
            the filter number from the pds3 label.
            Expects ikid to be defined. This should be the integer Naid ID code for
            the instrument.

            Returns
            -------
            : int
              Naif ID code used in calculating focal length
            """
        return spice.bods2c(self.instrument_id)
Пример #9
0
    def __init__(self, obj, kernel=None):
        State.__init__(self, name=obj)
        
        if not core._spice_setup:
            core._setup_spice()

        if kernel is None:
            kernel = core.find_kernel(obj)
        core.load_kernel(kernel)
        self.kernel = kernel

        if isinstance(obj, int):
            obj = str(obj)

        naifid = spice.bods2c(obj)

        self.obj = obj
        self.naifid = naifid
Пример #10
0
def scs2utc_spice(scs, sc, deltat):
    res = {}
    try:
        scid = sp.bods2c(sc)
        et = sp.scs2e(scid, scs)

        if deltat is not None:
            tai = sp.unitim(et, 'et', 'tai')
            tai += deltat
            et = sp.unitim(tai, 'tai', 'et')

        utc = sp.et2utc(et, 'isoc', 3)

        res[scs] = utc
    except sp.stypes.SpiceyError as ex:
        raise GeometrySpiceError(ex.value)
    else:
        return res
Пример #11
0
    def _tc_id(self):
        """
        Returns ikid of LISM_TC1 or LISM_TC2, depending which camera was used
        for capturing the image.

        Some keys are stored in the IK kernel under a general ikid for TC1/TC2
        presumably because they are not affected by the addtional parameters encoded in
        the ikid returned by self.ikid. This method exists for those gdpool calls.

        Expects instrument_id to be defined in the Pds3Label mixin. This should be
        a string containing either TC1 or TC2

        Returns
        -------
        : int
          ikid of LISM_TC1 or LISM_TC2
        """
        return spice.bods2c("LISM_{}".format(super().instrument_id))
Пример #12
0
 def target_id(self):
     return spice.bods2c(self.target_name)
Пример #13
0
 def spacecraft_id(self):
     return spice.bods2c(self.spacecraft_name)
Пример #14
0

all_boresight_vectors, all_boresight_names = readBoresightFile(BORESIGHT_VECTOR_FILE_PATH)

for fileName, realBoresightUsed in fileNames_in.items():

    hdf5file_path = os.path.join(
            r"C:\Users\iant\Documents\DATA\hdf5_copy\hdf5_level_0p3a",
            fileName[0:4], fileName[4:6], fileName[6:8],
            fileName+".h5")
    
    hdf5FileIn = h5py.File(hdf5file_path, "r")
    observationDTimes = hdf5FileIn["Geometry/ObservationDateTime"][...]
    
    dref = "TGO_NOMAD_SO"
    channelId = sp.bods2c(dref) #find channel id number
    [channelShape, name, boresightVector, nvectors, boresightVectorbounds] = sp.getfov(channelId, 4) 
    
    SPICE_REFERENCE_FRAME = "TGO_SPACECRAFT"
    SPICE_ABERRATION_CORRECTION = "None"
    SPICE_OBSERVER = "-143"
    
    
    observationDTimesStart = [str(observationDTime[0]) for observationDTime in observationDTimes]
    observationDTimesEnd = [str(observationDTime[1]) for observationDTime in observationDTimes]
    obsTimesStart = [sp.utc2et(datetime.strip("<b>").strip("'")) for datetime in observationDTimesStart]
    obsTimesEnd = [sp.utc2et(datetime.strip("<b>").strip("'")) for datetime in observationDTimesEnd]
    
    #find times in occultation
    obsTimeMids = [obsTimesStart[0], np.mean([obsTimesStart[0],obsTimesStart[-1]]), obsTimesStart[-1]]
Пример #15
0
def get_isd(label):

    mission_name = {"CASSINI-HUYGENS": "CASSINI"}

    instrument_names = {"ISSNA": "CASSINI_ISS_NAC", "ISSWA": "CASSINI_ISS_WAC"}

    metakernal_dir = config.cassini
    mks = sorted(glob(metakernal_dir + '/*.tm'))

    instrument_name = instrument_names[label['INSTRUMENT_ID']]
    spacecraft_name = mission_name[label['MISSION_NAME']]
    target_name = label['TARGET_NAME']
    time = label['START_TIME']

    cassini_mk = None
    for mk in mks:
        if str(time.year) in os.path.basename(mk):
            cassini_mk = mk

    spice.furnsh(cassini_mk)

    # Spice likes ids over names, so grab the ids from the names
    spacecraft_id = spice.bods2c(spacecraft_name)
    instrument_id = spice.bods2c(instrument_name)

    # Load the instrument and target metadata into the ISD
    reference_frame = 'IAU_{}'.format(target_name)

    isd = {}

    rad = spice.bodvrd(target_name, 'RADII', 3)
    isd['semimajor'] = rad[1][0] * 1000
    isd['semiminor'] = rad[1][1] * 1000

    # transx and transy are unavailable so fill in with pixel_size after conversion to millimeters from microns
    # assuming pixels are square
    pixel_size = int(
        spice.gipool('INS{}_PIXEL_SIZE'.format(instrument_id), 0,
                     1)[0]) * 0.001
    isd['focal2pixel_samples'] = [0.0, pixel_size, 0.0]
    isd['focal2pixel_lines'] = [0.0, 0.0, pixel_size]

    # unavailable so default to 0
    isd['starting_detector_sample'] = 0.0
    isd['starting_detector_line'] = 0.0

    isd['image_lines'] = float(
        spice.gipool('INS{}_PIXEL_LINES'.format(instrument_id), 0, 1)[0])
    isd['image_samples'] = float(
        spice.gipool('INS{}_PIXEL_SAMPLES'.format(instrument_id), 0, 1)[0])

    isd['focal_length_model'] = {}
    isd['focal_length_model']['focal_length'] = float(
        spice.gdpool('INS{}_FOCAL_LENGTH'.format(instrument_id), 0, 1)[0])
    isd['focal_length_model']['focal_length_epsilon'] = float(
        spice.gdpool('INS{}_FL_UNCERTAINTY'.format(instrument_id), 0, 1)[0])

    # this following part is ripped from the mdis driver. Since they are both framers this code should be able to be applied to both
    # Now time
    sclock = label['SPACECRAFT_CLOCK_START_COUNT']
    exposure_duration = label['EXPOSURE_DURATION'].value
    exposure_duration = exposure_duration * 0.001  # Scale to seconds

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

    end_et = spice.scs2e(
        spacecraft_id,
        label['SPACECRAFT_CLOCK_STOP_COUNT']) + (exposure_duration / 2.0)
    del_et = end_et - start_et
    et = (start_et + end_et) / 2

    isd['starting_ephemeris_time'] = start_et
    isd['dt_ephemeris'] = del_et
    isd['number_of_ephemerides'] = 1
    isd['interpolation_method'] = 'lagrange'
    isd['center_ephemeris_time'] = et

    # Get the rotation angles from MDIS NAC frame to Mercury body-fixed frame
    camera2bodyfixed = spice.pxform(instrument_name, reference_frame, et)
    quat = spice.m2q(camera2bodyfixed)
    # cassini follows spice style for quaternions so no transformation is needed
    isd['sensor_orientation'] = list(quat)

    # Get the Sensor Position
    loc, _ = spice.spkpos(target_name, et, reference_frame, 'None',
                          spacecraft_name)
    loc *= -1000

    isd['sensor_location'] = {}
    isd['sensor_location']['x'] = loc[0]
    isd['sensor_location']['y'] = loc[1]
    isd['sensor_location']['z'] = loc[2]
    isd['sensor_location']['unit'] = 'm'

    # Get the velocity
    v_state, lt = spice.spkezr(spacecraft_name, et, reference_frame, 'NONE',
                               target_name)

    isd['sensor_velocity'] = {}
    isd['sensor_velocity']['x'] = v_state[3] * 1000
    isd['sensor_velocity']['y'] = v_state[4] * 1000
    isd['sensor_velocity']['z'] = v_state[5] * 1000
    isd['sensor_velocity']['unit'] = 'm'
    isd['reference_height'] = {}
    isd['reference_height']['minheight'] = label.get('min_valid_height', -8000)
    isd['reference_height']['maxheight'] = label.get('max_valid_height', 8000)
    isd['reference_height']['unit'] = 'KM'

    # Get the sun position
    sun_state, lt = spice.spkezr("SUN", et, reference_frame, 'NONE',
                                 target_name)

    # lighttime should always be off
    isd['sun_position'] = {}
    isd['sun_position']['x'] = sun_state[0] * 1000
    isd['sun_position']['y'] = sun_state[1] * 1000
    isd['sun_position']['z'] = sun_state[2] * 1000

    isd['sun_velocity'] = {}
    isd['sun_velocity']['x'] = sun_state[3] * 1000
    isd['sun_velocity']['y'] = sun_state[4] * 1000
    isd['sun_velocity']['z'] = sun_state[5] * 1000

    # cassini has no optical distortion model
    isd['optical_distortion'] = None

    return isd
Пример #16
0
def get_isd(label):

    metakernel_dir = config.mro
    mks = sorted(glob(os.path.join(config.mro, '*.tm')))
    time = label['START_TIME']

    mro_mk = None
    for mk in mks:
        if str(time.year) in os.path.basename(mk):
            mro_mk = mk
    spice.furnsh(mro_mk)

    isd = {}

    instrument_name = label['INSTRUMENT_NAME']
    spacecraft_name = label['SPACECRAFT_NAME']
    target_name = label['TARGET_NAME']

    # Spice likes ids over names, so grab the ids from the names
    spacecraft_id = spice.bods2c(
        'MRO')  # Label specifies: MARS_RECONNAISSANCE_ORBITER
    ikid = spice.bods2c('MRO_CTX')  # Label specifies: CONTEXT CAMERA

    # Load the instrument and target metadata into the ISD
    reference_frame = 'IAU_{}'.format(target_name)

    # Instrument / Spacecraft Metadata
    isd['OPTICAL_DIST_COEF'] = [
        0, 0, 0
    ]  # spice.gdpool('INS{}_OD_K'.format(ikid),0, 3)
    isd['ITRANSL'] = spice.gdpool('INS{}_ITRANSL'.format(ikid), 0, 3)
    isd['ITRANSS'] = spice.gdpool('INS{}_ITRANSS'.format(ikid), 0, 3)
    isd['DETECTOR_SAMPLE_ORIGIN'] = spice.gdpool(
        'INS{}_BORESIGHT_SAMPLE'.format(ikid), 0, 1)
    isd['DETECTOR_LINE_ORIGIN'] = spice.gdpool(
        'INS{}_BORESIGHT_LINE'.format(ikid), 0, 1)
    isd['DETECTOR_SAMPLE_SUMMING'] = label['SAMPLING_FACTOR']
    isd['STARTING_SAMPLE'] = 0  # label['SAMPLE_FIRST_PIXEL']
    isd['TOTAL_LINES'] = nlines = label['IMAGE']['LINES']
    isd['TOTAL_SAMPLES'] = label['IMAGE'][
        'LINE_SAMPLES']  # spice.gdpool('INS{}_PIXEL_SAMPLES'.format(ikid), 0, 1)
    isd['SENSOR_TYPE'] = 'USGSAstroLineScanner'
    isd['MOUNTING_ANGLES'] = np.zeros(3)
    isd['ISIS_Z_DIRECTION'] = 1
    isd['STARTING_LINE'] = 1.0
    isd['DETECTOR_LINE_OFFSET'] = 0.0
    # Body Parameters
    target_name = label['TARGET_NAME']
    rad = spice.bodvrd(target_name, 'RADII', 3)
    a = rad[1][1]
    b = rad[1][2]
    isd['SEMI_MAJOR_AXIS'] = a * 1000  # Scale to meters
    isd['ECCENTRICITY'] = np.sqrt(1 - (b**2 / a**2))  # Standard eccentricity

    isd['FOCAL'] = spice.gdpool('INS{}_FOCAL_LENGTH'.format(ikid), 0, 1)

    isd['ABERR'] = 0
    isd['ATMREF'] = 0
    isd['PLATFORM'] = 1

    # It really is hard coded this way...
    isd['TRI_PARAMETERS'] = np.zeros(18)
    isd['TRI_PARAMETERS'][15] = isd['FOCAL']

    # Time
    sclock = label['SPACECRAFT_CLOCK_START_COUNT']
    et = spice.scs2e(spacecraft_id, sclock)
    isd['STARTING_EPHEMERIS_TIME'] = et

    half_lines = nlines / 2
    isd['INT_TIME'] = line_rate = label['LINE_EXPOSURE_DURATION'][
        0] * 0.001  # Scale to seconds
    center_sclock = et + half_lines * line_rate
    isd['CENTER_EPHEMERIS_TIME'] = center_sclock
    isd['SCAN_DURATION'] = line_rate * nlines
    # The socetlinekeywords code is pushing ephemeris and quaternion off of either side of the image.  Therefore,
    # the code needs to know when the start time is.  Since we are not pushing off the edge of the image, the start-time
    # should be identical to the actual image start time.
    isd['T0_QUAT'] = isd['T0_EPHEM'] = isd['STARTING_EPHEMERIS_TIME'] - isd[
        'CENTER_EPHEMERIS_TIME']
    isd['DT_EPHEM'] = 80 * isd['INT_TIME']  # This is every 300 lines

    # Determine how many ephemeris points to compute
    n_ephemeris = int(isd['SCAN_DURATION'] / isd['DT_EPHEM'])
    if n_ephemeris % 2 == 0:
        n_ephemeris += 1
    isd['NUMBER_OF_EPHEM'] = n_ephemeris
    eph = np.empty((n_ephemeris, 3))
    eph_rates = np.empty(eph.shape)
    current_et = et
    for i in range(n_ephemeris):
        loc_direct, _ = spice.spkpos(target_name, current_et, 'IAU_MARS',
                                     'NONE', 'MRO')
        state, _ = spice.spkezr(target_name, current_et, 'IAU_MARS', 'NONE',
                                'MRO')
        eph[i] = loc_direct
        eph_rates[i] = state[3:]
        current_et += isd[
            'DT_EPHEM']  # Increment the time by the number of lines being stepped
    eph *= -1000  # Reverse to be from body center and convert to meters
    eph_rates *= -1000  # Same, reverse and convert
    isd['EPHEM_PTS'] = eph.flatten()
    isd['EPHEM_RATES'] = eph_rates.flatten()

    # Why should / should not the n_quaternions equal the number of ephemeris pts?
    n_quaternions = n_ephemeris
    isd['NUMBER_OF_QUATERNIONS'] = n_quaternions

    isd['DT_QUAT'] = isd['SCAN_DURATION'] / n_quaternions
    qua = np.empty((n_quaternions, 4))
    current_et = et
    for i in range(n_quaternions):
        # Find the rotation matrix
        camera2bodyfixed = spice.pxform('MRO_CTX', 'IAU_MARS', current_et)
        q = spice.m2q(camera2bodyfixed)
        qua[i, :3] = q[1:]
        qua[i, 3] = q[0]
        current_et += isd['DT_QUAT']
    isd['QUATERNIONS'] = qua.flatten()

    # Now the 'optional' stuff
    isd['REFERENCE_HEIGHT'] = label.get('reference_height', 30)
    isd['MIN_VALID_HT'] = label.get('min_valid_height', -8000)
    isd['MAX_VALID_HT'] = label.get('max_valid_height', 8000)
    isd['IMAGE_ID'] = label.get('image_id', 'UNKNOWN')
    isd['SENSOR_ID'] = label.get('sensor_id', 'USGS_LINE_SCANNER')
    isd['PLATFORM_ID'] = label.get('platform_id', 'UNKNOWN')
    isd['TRAJ_ID'] = label.get('traj_id', 'UNKNOWN')
    isd['COLL_ID'] = label.get('coll_id', 'UNKNOWN')
    isd['REF_DATE_TIME'] = label.get('ref_date_time', 'UNKNOWN')

    spice.unload(mro_mk)

    return isd
Пример #17
0
 def ikid(self):
     return spice.bods2c(self.instrument_id)
Пример #18
0
def ctx_isd_from_json(data, meta):
    time = parser.parse(data['START_TIME'])
    for k in meta:
        if k.year.year == time.year:
            obs_kernels = k.path

    # Load the meta kernel
    spice.furnsh(obs_kernels)

    isd = {}
    spacecraft_name = data['SPACECRAFT_NAME']
    spacecraft_id = spice.bods2c('MRO')

    # Need to map CONTEXT CAMERA to what spice wants - MRO_CTX
    instrument_name = data['INSTRUMENT_NAME']
    ikid = isd['IKCODE'] = spice.bods2c('MRO_CTX')

    # Instrument / Spacecraft Metadata
    isd['OPTICAL_DIST_COEF'] = spice.gdpool('INS{}_OD_K'.format(ikid), 0, 3)
    isd['ITRANSL'] = spice.gdpool('INS{}_ITRANSL'.format(ikid), 0, 3)
    isd['ITRANSS'] = spice.gdpool('INS{}_ITRANSS'.format(ikid), 0, 3)
    isd['DETECTOR_SAMPLE_ORIGIN'] = spice.gdpool(
        'INS{}_BORESIGHT_SAMPLE'.format(ikid), 0, 1)
    isd['DETECTOR_LINE_ORIGIN'] = spice.gdpool(
        'INS{}_BORESIGHT_LINE'.format(ikid), 0, 1)
    isd['DETECTOR_SAMPLE_SUMMING'] = data['SAMPLING_FACTOR']
    isd['DETECTOR_SAMPLE_SUMMING'] = data['SAMPLING_FACTOR']
    isd['STARTING_SAMPLE'] = data['SAMPLE_FIRST_PIXEL']
    isd['TOTAL_LINES'] = nlines = data['IMAGE']['LINES']
    isd['TOTAL_SAMPLES'] = spice.gdpool('INS{}_PIXEL_SAMPLES'.format(ikid), 0,
                                        1)
    isd['SENSOR_TYPE'] = 'USGSAstroLineScanner'
    isd['MOUNTING_ANGLES'] = np.zeros(3)
    isd['ISIS_Z_DIRECTION'] = 1
    isd['STARTING_LINE'] = 1.0
    isd['DETECTOR_LINE_OFFSET'] = 0.0

    # Body Parameters
    target_name = find_in_dict(data, 'TARGET_NAME')
    rad = spice.bodvrd(target_name, 'RADII', 3)
    a = rad[1][1]
    b = rad[1][2]
    isd['SEMI_MAJOR_AXIS'] = a * 1000  # Scale to meters
    isd['ECCENTRICITY'] = sqrt(1 - (b**2 / a**2))  # Standard eccentricity

    isd['FOCAL'] = spice.gdpool('INS{}_FOCAL_LENGTH'.format(ikid), 0, 1)

    isd['ABERR'] = 0
    isd['ATMREF'] = 0
    isd['PLATFORM'] = 1

    # It really is hard coded this way...
    isd['TRI_PARAMETERS'] = np.zeros(18)
    isd['TRI_PARAMETERS'][15] = isd['FOCAL']

    # Time
    sclock = find_in_dict(data, 'SPACECRAFT_CLOCK_START_COUNT')
    et = spice.scs2e(spacecraft_id, sclock)
    isd['STARTING_EPHEMERIS_TIME'] = et

    half_lines = nlines / 2
    isd['INT_TIME'] = line_rate = data['LINE_EXPOSURE_DURATION'][
        0] * 0.001  # Scale to seconds
    center_sclock = et + half_lines * line_rate
    isd['CENTER_EPHEMERIS_TIME'] = center_sclock
    isd['SCAN_DURATION'] = line_rate * nlines
    # The socetlinekeywords code is pushing ephemeris and quaternion off of either side of the image.  Therefore,
    # the code needs to know when the start time is.  Since we are not pushing off the edge of the image, the start-time
    # should be identical to the actual image start time.
    isd['T0_QUAT'] = isd['T0_EPHEM'] = isd['STARTING_EPHEMERIS_TIME'] - isd[
        'CENTER_EPHEMERIS_TIME']
    isd['DT_EPHEM'] = 80 * isd['INT_TIME']  # This is every 300 lines

    # Determine how many ephemeris points to compute
    n_ephemeris = int(isd['SCAN_DURATION'] / isd['DT_EPHEM'])
    if n_ephemeris % 2 == 0:
        n_ephemeris += 1
    isd['NUMBER_OF_EPHEM'] = n_ephemeris
    eph = np.empty((n_ephemeris, 3))
    eph_rates = np.empty(eph.shape)
    current_et = et
    for i in range(n_ephemeris):
        loc_direct, _ = spice.spkpos(target_name, current_et, 'IAU_MARS',
                                     'LT+S', 'MRO')
        state, _ = spice.spkezr(target_name, current_et, 'IAU_MARS', 'LT+S',
                                'MRO')
        eph[i] = loc_direct
        eph_rates[i] = state[3:]
        current_et += isd[
            'DT_EPHEM']  # Increment the time by the number of lines being stepped
    eph *= -1000  # Reverse to be from body center and convert to meters
    eph_rates *= -1000  # Same, reverse and convert
    isd['EPHEM_PTS'] = eph.flatten()
    isd['EPHEM_RATES'] = eph_rates.flatten()

    # Why should / should not the n_quaternions equal the number of ephemeris pts?
    n_quaternions = n_ephemeris
    isd['NUMBER_OF_QUATERNIONS'] = n_quaternions

    isd['DT_QUAT'] = isd['SCAN_DURATION'] / n_quaternions
    qua = np.empty((n_quaternions, 4))
    current_et = et
    for i in range(n_quaternions):
        # Find the rotation matrix
        camera2bodyfixed = spice.pxform('MRO_CTX', 'IAU_MARS', current_et)
        q = spice.m2q(camera2bodyfixed)
        qua[i][:3] = q[1:]
        qua[i][-1] = q[0]
        current_et += isd['DT_QUAT']
    isd['QUATERNIONS'] = qua.flatten()

    # Now the 'optional' stuff
    isd['REFERENCE_HEIGHT'] = data.get('reference_height', 30)
    isd['MIN_VALID_HT'] = data.get('min_valid_height', -8000)
    isd['MAX_VALID_HT'] = data.get('max_valid_height', 8000)
    isd['IMAGE_ID'] = data.get('image_id', 'UNKNOWN')
    isd['SENSOR_ID'] = data.get('sensor_id', 'USGS_LINE_SCANNER')
    isd['PLATFORM_ID'] = data.get('platform_id', 'UNKNOWN')
    isd['TRAJ_ID'] = data.get('traj_id', 'UNKNOWN')
    isd['COLL_ID'] = data.get('coll_id', 'UNKNOWN')
    isd['REF_DATE_TIME'] = data.get('ref_date_time', 'UNKNOWN')

    spice.unload(obs_kernels)

    return json.dumps(isd, cls=NumpyEncoder)
Пример #19
0
 def body_code(self):
     '''Spice body code'''
     return spice.bods2c(self.targ)
Пример #20
0
def isd_from_json(data, meta):
    instrument_name = {
        'IMAGING SCIENCE SUBSYSTEM NARROW ANGLE': 'CASSINI_ISS_NAC',
        'IMAGING SCIENCE SUBSYSTEM WIDE ANGLE': 'CASSINI_ISS_WAC',
        'IMAGING SCIENCE SUBSYSTEM - NARROW ANGLE': 'CASSINI_ISS_NAC',
        'MDIS-NAC': 'MSGR_MDIS_NAC',
        'MERCURY DUAL IMAGING SYSTEM NARROW ANGLE CAMERA': 'MSGR_MDIS_NAC',
        'MERCURY DUAL IMAGING SYSTEM WIDE ANGLE CAMERA': 'MSGR_MDIS_WAC'
    }

    spacecraft_names = {'CASSINI ORBITER': 'CASSINI', 'MESSENGER': 'MESSENGER'}

    # This is the return dict
    isd = {}

    # Meta kernels are keyed by body, spacecraft, and year - grab from the data
    spacecraft_name = spacecraft_names[data['spacecraft_id']]
    target_name = data['target_name']
    time = parser.parse(data['capture_date'])

    for k in meta:
        if k.year.year == time.year:
            obs_kernels = k.path

    # Load the meta kernel
    spice.furnsh(obs_kernels)
    path, tpe, handle, found = spice.kdata(0, 'TEXT')
    if not found:
        directory = os.path.dirname(path)
        directory = os.path.abspath(os.path.join(directory, '../iak'))
        additional_ik = glob.glob(directory + '/*.ti')
        spice.furnsh(additional_ik)

    # Spice likes ids over names, so grab the ids from the names
    instrument_name = instrument_name[data['instrument']]
    spacecraft_id = spice.bods2c(spacecraft_name)
    ikid = spice.bods2c(instrument_name)

    # Load the instrument and target metadata into the ISD
    isd['instrument_id'] = instrument_name
    isd['target_name'] = target_name
    isd['spacecraft_name'] = spacecraft_name

    # Prepend IAU to all instances of the body name
    reference_frame = 'IAU_{}'.format(target_name)

    # 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)
    try:
        isd['odt_x'] = spice.gdpool('INS-{}_OD_T_X'.format(ikid), 0, 10)
    except:
        isd['odt_x'] = np.zeros(10)
        isd['odt_x'][1] = 1
    try:
        isd['odt_y'] = spice.gdpool('INS-{}_OD_T_Y'.format(ikid), 0, 10)
    except:
        isd['odt_y'] = np.zeros(10)
        isd['odt_y'][2] = 1
    try:
        isd['starting_detector_sample'] = spice.gdpool(
            'INS{}_FPUBIN_START_SAMPLE'.format(ikid), 0, 1)
    except:
        isd['starting_detector_sample'] = 0
    try:
        isd['starting_detector_line'] = spice.gdpool(
            'INS{}_FPUBIN_START_LINE'.format(ikid), 0, 1)
    except:
        isd['starting_detector_line'] = 0

    # Get temperature from SPICE and adjust focal length
    if 'focal_plane_temperature' in data.keys():
        try:  # TODO: Remove once WAC temperature dependent is working
            temp_coeffs = spice.gdpool('INS-{}_FL_TEMP_COEFFS'.format(ikid), 0,
                                       6)
            temp = data['focal_plane_temperature']
            isd['focal_length'] = distort_focal_length(temp_coeffs, temp)
        except:
            isd['focal_length'] = spice.gdpool(
                'INS-{}_FOCAL_LENGTH'.format(ikid), 0, 1)
    else:
        isd['focal_length'] = spice.gdpool('INS-{}_FOCAL_LENGTH'.format(ikid),
                                           0, 1)

    # 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 time
    sclock = data['spacecraft_clock_count']
    exposure_duration = data['exposure_duration']
    exposure_duration = exposure_duration * 0.001  # Scale to seconds

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

    isd['ephemeris_time'] = et

    # Get the Sensor Position
    loc, _ = spice.spkpos(isd['target_name'], et, reference_frame, 'LT+S',
                          spacecraft_name)
    loc *= -1000
    isd['x_sensor_origin'] = loc[0]
    isd['y_sensor_origin'] = loc[1]
    isd['z_sensor_origin'] = loc[2]

    # Get the rotation angles from MDIS NAC frame to Mercury body-fixed frame
    camera2bodyfixed = spice.pxform(instrument_name, reference_frame, et)
    opk = spice.m2eul(camera2bodyfixed, 3, 2, 1)

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

    # Get the sun position
    sun_state, lt = spice.spkezr("SUN", et, reference_frame,
                                 data['lighttime_correction'], target_name)

    # 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

    # Get the velocity
    v_state, lt = spice.spkezr(spacecraft_name, et, reference_frame,
                               data['lighttime_correction'], target_name)

    isd['x_sensor_velocity'] = v_state[3] * 1000
    isd['y_sensor_velocity'] = v_state[4] * 1000
    isd['z_sensor_velocity'] = v_state[5] * 1000

    # Misc. insertion
    # A lookup here would be smart - similar to the meta kernals, what is the newest model, etc.
    if 'model_name' not in data.keys():
        isd['model_name'] = 'ISIS_MDISNAC_USGSAstro_1_Linux64_csm30.so'
    isd['min_elevation'] = data['min_elevation']
    isd['max_elevation'] = data['max_elevation']

    spice.unload(obs_kernels)  # Also unload iak
    return isd