Exemple #1
0
 def sensor_orientation(self):
     if not hasattr(self, '_sensor_orientation'):
         current_et = self.starting_ephemeris_time
         qua = np.empty((self.number_of_ephemerides, 4))
         for i in range(self.number_of_quaternions):
             # Find the rotation matrix
             camera2bodyfixed = spice.pxform(self.instrument_id,
                                             self.reference_frame,
                                             current_et)
             q = spice.m2q(camera2bodyfixed)
             qua[i,:3] = q[1:]
             qua[i,3] = q[0]
             current_et += getattr(self, 'dt_quaternion', 0)
         self._sensor_orientation = qua
     return self._sensor_orientation.tolist()
Exemple #2
0
    def _sensor_orientation(self):
        if not hasattr(self, '_orientation'):
            ephem = self.ephemeris_time

            qua = np.empty((len(ephem), 4))
            for i, time in enumerate(ephem):
                # Find the rotation matrix
                camera2bodyfixed = spice.pxform(self.instrument_id,
                                                self.reference_frame,
                                                time)
                q = spice.m2q(camera2bodyfixed)
                qua[i,:3] = q[1:]
                qua[i,3] = q[0]
            self._orientation = qua
        return self._orientation.tolist()
Exemple #3
0
    def _sensor_orientation(self):
        if not hasattr(self, '_orientation'):
            ephem = self.ephemeris_time

            qua = np.empty((len(ephem), 4))
            for i, time in enumerate(ephem):
                instrument = self.label.get("INSTRUMENT_ID")
                # Find the rotation matrix
                camera2bodyfixed = spice.pxform(
                    "LISM_{}_HEAD".format(instrument), self.reference_frame,
                    time)
                q = spice.m2q(camera2bodyfixed)
                qua[i, :3] = q[1:]
                qua[i, 3] = q[0]
            self._orientation = qua
        return self._orientation.tolist()
Exemple #4
0
    def frame_chain(self):
        if not hasattr(self, '_frame_chain'):
            nadir = self._props.get('nadir', False)
            self._frame_chain = FrameChain.from_spice(
                sensor_frame=self.sensor_frame_id,
                target_frame=self.target_frame_id,
                center_ephemeris_time=self.center_ephemeris_time,
                ephemeris_times=self.ephemeris_time,
                nadir=nadir)

            if nadir:
                # Logic for nadir calculation was taken from ISIS3
                #  SpiceRotation::setEphemerisTimeNadir
                rotation = self._frame_chain.compute_rotation(
                    self.target_frame_id, 1)
                p_vec, v_vec, times = self.sensor_position
                rotated_positions = rotation.apply_at(p_vec, times)
                rotated_velocities = rotation.rotate_velocity_at(
                    p_vec, v_vec, times)

                p_vec = rotated_positions
                v_vec = rotated_velocities

                velocity_axis = 2
                # Get the default line translation with no potential flipping
                # from the driver
                trans_x = np.array(
                    list(spice.gdpool('INS{}_ITRANSL'.format(self.ikid), 0,
                                      3)))

                if (trans_x[0] < trans_x[1]):
                    velocity_axis = 1

                quats = [
                    spice.m2q(
                        spice.twovec(-p_vec[i], 3, v_vec[i], velocity_axis))
                    for i, time in enumerate(times)
                ]
                quats = np.array(quats)[:, [1, 2, 3, 0]]

                rotation = TimeDependentRotation(quats, times, 1,
                                                 self.sensor_frame_id)
                self._frame_chain.add_edge(rotation)

        return self._frame_chain
def get_isd(label):
    """
    TODO: This function (and all like it) needs to open with some robust method to make sure this is
          in fact an MDIS label.

    """

    instrument_name = {
        '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'
    }

    metakernel_dir = config.mdis
    mks = sorted(glob(os.path.join(metakernel_dir, '*.tm')))

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

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

    spice.furnsh(messenger_mk)

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

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

    isd = {}

    rad = spice.bodvrd(target_name, 'RADII', 3)
    isd['radii'] = {}
    isd['radii']['semimajor'] = rad[1][0]
    isd['radii']['semiminor'] = rad[1][1]

    isd['optical_distortion'] = {}
    odk_mssgr_x = spice.gdpool('INS{}_OD_T_X'.format(ikid), 0, 10)
    odk_mssgr_y = spice.gdpool('INS{}_OD_T_Y'.format(ikid), 0, 10)

    isd['optical_distortion']['x'] = list(odk_mssgr_x)
    isd['optical_distortion']['y'] = list(odk_mssgr_y)

    isd['focal2pixel_samples'] = list(
        spice.gdpool('INS{}_TRANSX'.format(ikid), 0, 3))
    isd['focal2pixel_lines'] = list(
        spice.gdpool('INS{}_TRANSY'.format(ikid), 0, 3))

    # Load information from the IK kernel
    isd['focal_length_model'] = {}

    focal_legnth_coeffs = spice.gdpool('INS{}_FL_TEMP_COEFFS '.format(ikid), 0,
                                       5)
    isd['focal_length_model']['focal_length'] = focal_length_from_temp(
        label['FOCAL_PLANE_TEMPERATURE'].value, focal_legnth_coeffs)

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

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

    isd['starting_detector_sample'] = int(
        spice.gdpool('INS{}_FPUBIN_START_SAMPLE'.format(ikid), 0, 1)[0])
    isd['starting_detector_line'] = int(
        spice.gdpool('INS{}_FPUBIN_START_LINE'.format(ikid), 0, 1)[0])

    # 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_id, reference_frame, et)
    quat = spice.m2q(camera2bodyfixed)

    isd['sensor_orientation'] = list(quat)

    # Get the Sensor Position
    loc, _ = spice.spkpos(target_name, et, reference_frame, 'LT+S',
                          spacecraft_name)

    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]
    isd['sensor_velocity']['y'] = v_state[4]
    isd['sensor_velocity']['z'] = v_state[5]
    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)

    # Get the sun position, convert to meters
    xpos, ypos, zpos = [e.value for e in label['SC_SUN_POSITION_VECTOR']]
    xvel, yvel, zvel = [e.value for e in label['SC_SUN_VELOCITY_VECTOR']]

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

    isd['sun_velocity'] = {}
    isd['sun_velocity']['x'] = sun_state[3]
    isd['sun_velocity']['y'] = sun_state[4]
    isd['sun_velocity']['z'] = sun_state[5]
    return isd
Exemple #6
0
    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
Exemple #7
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
Exemple #8
0
def create_ck(kernels, frames_to_convert, fks, stop_ets, output_ck):
    """
  Create CK from FKs and times at which the FKs end being valid

  """

    ### FURNSH any kernels
    for kernel in kernels:
        sp.furnsh(kernel)

    ### Set last ET to None so it will be initialized in loop's first pass
    last_et = None

    ### Do not overwrite existing output CK
    assert (not sp.exists(output_ck)
            ) or dict()['Cannot overwrite existing CK[{}]'.format(output_ck)]

    ### Initialize CK handle to None
    ck_handle = None

    ### Loop over CKs
    while fks:

        ### Get FK and corresponding stop ET
        fk = fks.pop()
        stop_et = stop_ets.pop()

        ### Loop over reference frames (reffrms)
        for reffrm in frames_to_convert:

            ### Get reffrm ID, SCLK ID; N.B. latter comes from new FK
            reffrm_id = sp.gipool('FRAME_{}'.format(reffrm.upper()), 0, 1)[0]
            sclk_id = sp.gipool('CK_{}_{}'.format(reffrm_id, 'SCLK'), 0, 1)[0]

            ### Set start DP-SCLK of window for this old FK (outer loop)
            ### - Set to zero for first window
            ### - Covnert ET to DP-SCLK for subsequent windows
            if last_et is None: begtim = 0.0
            else: begtim = sp.sce2t(sclk_id, last_et)

            ### Load old FK, get RELATIVE frame name, get time-invariant
            ### matrix, and unload old FK
            sp.furnsh(fk)
            relative_reffrm = sp.gcpool(
                'TKFRAME_{}_{}'.format(reffrm_id, 'RELATIVE'), 0, 1, 99)[0]
            mtx = sp.pxform(relative_reffrm, reffrm, 0.0)
            sp.unload(fk)

            ### Covnert matrix to quaternion
            quat = sp.m2q(mtx)

            ### Calculate tick rate:  seconds per tick
            rate = (sp.sct2e(sclk_id, 1e3) - sp.sct2e(sclk_id, 0.)) / 1e3

            if doVerbose:
                ### if VERBOSE environment variable is present, log information
                print((
                    relative_reffrm,
                    reffrm,
                    fk,
                    last_et,
                    stop_et,
                    '{:010.3f}'.format(1. / rate),
                    quat,
                ))

            ### Set stop DP-SCLK of window
            if stop_et < -1e30:
                ### Use end of encoded DP_SCLK for final window
                endtim = sp.gdpool('SCLK_PARTITION_END_{}'.format(-sclk_id), 0,
                                   999)[-1]
            else:
                ### Else convert stop ET to DP-SCLK
                endtim = sp.sce2t(sclk_id, stop_et)

            if doDebug:
                ### Debug output
                pprint.pprint(
                    dict(fk=fk,
                         reffrm=reffrm,
                         reffrm_id=reffrm_id,
                         relative_reffrm=relative_reffrm,
                         rate=rate,
                         begtim=begtim,
                         endtim=endtim,
                         diff=endtim - begtim,
                         mtx=mtx,
                         quat=quat))

            ### Open CK, once
            if ck_handle is None:
                ck_handle = sp.ckopn(output_ck, 'ORX FK REPLACEMENT', 0)

            ### Write Type 2 CK segment with one record; angular velocity = 0
            sp.ckw02(ck_handle, begtim, endtim, reffrm_id, relative_reffrm,
                     '{}[{}]'.format(os.path.basename(fk), reffrm)[:40], 1,
                     [begtim], [endtim], [quat], [[0., 0., 0.]], [rate])

        ### Save stop ET for start ET of next pass
        last_et = stop_et

    ### Close CK
    if not (ck_handle is None): sp.ckcls(ck_handle)
Exemple #9
0
def test_ck(kernels, frames_to_convert, fks, stop_ets, output_ck):
    """
  Text CK against FKs at times at which the FKs are valid

  """

    ### Load base kernels (LSK, new FK, SCLK)
    for kernel in kernels + [output_ck]:
        sp.furnsh(kernel)

    ### Set last ET to None so it will be initialized in loop's first pass
    last_et = None

    ### Create dict of info; keys will be new FK filenames
    dt = dict()

    while fks:

        ### Pop FK and stop ET off of lists
        fk = fks.pop()
        stop_et = stop_ets.pop()

        ### Create dict for this FK
        dt[fk] = dict()

        ### Loop over refernce frames
        for reffrm in frames_to_convert:

            ### Get reffrm ID, SCLK ID; N.B. latter comes from new FK
            reffrm_id = sp.gipool('FRAME_{}'.format(reffrm.upper()), 0, 1)[0]
            sclk_id = sp.gipool('CK_{}_{}'.format(reffrm_id, 'SCLK'), 0, 1)[0]

            ### Set start DP-SCLK of window for this old FK (outer loop)
            ### - Set to zero for first window
            ### - Covnert ET to DP-SCLK for subsequent windows
            if last_et is None: et_lo = sp.sct2e(sclk_id, 0.)
            else: et_lo = last_et

            ### Load old FK, get RELATIVE frame name, get time-invariant
            ### matrix, and unload old FK
            sp.furnsh(fk)
            relative_reffrm = sp.gcpool(
                'TKFRAME_{}_{}'.format(reffrm_id, 'RELATIVE'), 0, 1, 99)[0]
            sp.unload(fk)

            ### Get ETs at which to do the tests:
            ### - 10s after start of window
            ### - 10s before end of window, or 1e6s after start if last window
            if stop_et < -1e30:
                et_test_lo = et_lo + 10.
                et_test_hi = et_lo + 1e6
            else:
                et_delta = min([10., (stop_et - et_lo) / 3.])
                et_test_lo = et_lo + et_delta
                et_test_hi = stop_et - et_delta

            ### Save the relative reffrm, the reffrm, the window, and an empty
            ### dict for this reffrm under this FK
            dt[fk][reffrm] = (relative_reffrm, et_test_lo, et_test_hi, dict())

        ### For next pass
        last_et = stop_et

    ### Clear all kernels, and test
    sp.kclear()
    assert 0 == sp.ktotal('all')

    ### Load base kernels including new FK and new CK
    for kernel in kernels + [output_ck]:
        sp.furnsh(kernel)

    ### Loop over old FKs, reffrms, and ETs
    for fk in dt:

        for reffrm in dt[fk]:

            ### Retrieve relative reffrm, ETs and quat dict
            relative_reffrm, et_test_lo, et_test_hi, dtquat = dt[fk][reffrm]

            for et in (
                    et_test_lo,
                    et_test_hi,
            ):

                ### Lookup CK-based matrix, convrt to and save quat at each ET
                dtquat[et] = sp.m2q(sp.pxform(relative_reffrm, reffrm, et))

    ### Loop over the old FKs again
    for fk in dt:

        ### Clear all kernels, and test
        sp.kclear()
        assert 0 == sp.ktotal('all')

        ### Load only the old FK
        sp.furnsh(fk)

        ### Loop over reffrms, and ETs
        for reffrm in dt[fk]:

            relative_reffrm, et_test_lo, et_test_hi, dtquat = dt[fk][reffrm]

            for et in (
                    et_test_lo,
                    et_test_hi,
            ):

                ### Calculate norm of difference of CK-based and FK-based quats
                quat_error = round(
                    sp.vnorm(dtquat[et] -
                             sp.m2q(sp.pxform(relative_reffrm, reffrm, et))),
                    16)

                ### Output that norm as an error for each case, which norm
                ### should be zero
                print(
                    dict(fk=fk,
                         quat_error=quat_error,
                         relative_reffrm=relative_reffrm,
                         reffrm=reffrm,
                         et='{:015.4f}'.format(et)))
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
for p in iFiles:

    # getting positions and quaternion in the camera frame
    et1Str = getImageTime(p)
    target = 'HAYABUSA'
    et1 = spiceypy.utc2et(et1Str)
    frame = 'ITOKAWA_FIXED'
    center = 'ITOKAWA'
    state1 = spiceypy.spkezr(target, spiceypy.utc2et(et1Str), frame, 'none',
                             center)[0]
    stateSun = spiceypy.spkezr('SUN', spiceypy.utc2et(et1Str), frame, 'none',
                               center)[0]
    frame2 = 'HAYABUSA_AMICA'
    frame1 = 'ITOKAWA_FIXED'
    rot1 = spiceypy.pxform(frame1, frame2, et1)
    quat1 = spiceypy.m2q(rot1)

    # SPICE data are in km
    s.setObjectPosition(
        'camera', vec3(state1[0] * 1000, state1[1] * 1000, state1[2] * 1000))

    # opposite convetion is used between SurRender and JPL
    s.setObjectAttitude('camera',
                        vec4(quat1[0], -quat1[1], -quat1[2], -quat1[3]))

    # SPICE data are in km
    s.setObjectPosition(
        'sun', vec3(stateSun[0] * 1000, stateSun[1] * 1000,
                    stateSun[2] * 1000))
    s.setObjectPosition('asteroid', vec3(0, 0, 0))
    s.printState(s.getState())
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)