Example #1
0
    def spice_positions(self, et: float):
        """Calculate MAVEN spacecraft position, Mars solar longitude, and the
        subsolar position for a given ephemeris time.

        Parameters
        ----------
        et
            Input epoch in ephemeris seconds past J2000.

        Returns
        -------
        et : array
            The input ephemeris times. Just givin'em back.
        subsc_lat : array
            Sub-spacecraft latitudes in degrees.
        subsc_lon : array
            Sub-spacecraft longitudes in degrees.
        sc_alt_km : array
            Sub-spacecraft altitudes in kilometers.
        ls : array
            Mars solar longitudes in degrees.
        subsolar_lat : array
            Sub-solar latitudes in degrees.
        subsolar_lon : array
            Sub-solar longitudes in degrees.
        mars_sun_km: array

        """
        spoint, trgepc, srfvec = \
            spice.subpnt('Intercept: ellipsoid', self.__target, et, 'IAU_MARS',
                         self.__abcorr, self.__observer)
        _, _, srvec_sun = \
            spice.subpnt('Intercept: ellipsoid', self.__target, et, 'IAU_MARS',
                         self.__abcorr, 'SUN')
        rpoint, colatpoint, lonpoint = spice.recsph(spoint)
        if lonpoint > np.pi:
            lonpoint -= 2 * np.pi
        subsc_lat = 90 - np.degrees(colatpoint)
        subsc_lon = np.degrees(lonpoint)
        sc_alt_km = np.sqrt(np.sum(srfvec**2))
        mars_sun_km = np.sqrt(np.sum(srvec_sun**2))

        # calculate subsolar position
        sspoint, strgepc, ssrfvec = \
            spice.subslr('Intercept: ellipsoid', self.__target, et, 'IAU_MARS',
                         self.__abcorr, self.__observer)
        srpoint, scolatpoint, slonpoint = spice.recsph(sspoint)
        if slonpoint > np.pi:
            slonpoint -= 2 * np.pi
        subsolar_lat = 90 - np.degrees(scolatpoint)
        subsolar_lon = np.degrees(slonpoint)

        ls = np.degrees(spice.lspcn(self.__target, et, self.__abcorr))

        return et, subsc_lat, subsc_lon, sc_alt_km, ls, subsolar_lat, \
            subsolar_lon, mars_sun_km
    def find_sub_pt(self):
        '''
            Finds the sub-observer point in the IAU_[target] frame
            and also the in the J2000 frame as seen from Earth.
            Also creates a vector from Earth to the sub-obs point in the 
            J2000 frame for future use.
        '''

        ## get the position of the sub-obs point in the J2000 frame
        self.subptvec, self.subptep, self.subpntobsvec = \
            spiceypy.subpnt('INTERCEPT/ELLIPSOID', self.target, \
                            self.et, self.target_frame, 'CN', 'EARTH')

        ## convert to lat/lon
        self.subptlon, self.subptlat, _ = \
            spiceypy.recpgr(self.target, self.subptvec, \
                            self.radii[0], self.flattening)

        ## convert the line of sight vector to J2000
        px1    = spiceypy.pxfrm2(self.target_frame, 'J2000', \
                                 self.subptep, self.et)

        self.subptJ2000 = np.matmul(px1, self.subpntobsvec)

        ## get the RA/DEC of the sub-obs point
        self.subRA, self.subDec = spiceypy.recrad(self.subptJ2000)[1:]
        self.RADec0 = np.array([self.subRA, self.subDec])
Example #3
0
def get_pixel_size_km(probe: str, body: str, time: datetime,
                      fov_full_angle_deg: float, fov_full_px: int) -> float:
    """ Calculates size of one pixel on body's surface in km at given time.

    :param probe: SPICE name of probe
    :param body: SPICE name of target body
    :param time: datetime of computation
    :param fov_full_angle_deg: full angle of one FOV dimension
    :param fov_full_px: full pixel count of the same FOV dimension
    :return: length of square covered by one pixel in kilometers
    """
    if fov_full_angle_deg <= 0.0:
        raise ValueError("fov_full_angle_deg must be positive.")
    if fov_full_angle_deg > 90.0:
        raise ValueError(
            f"with fov_full_angle_deg = {fov_full_angle_deg} the calculation would be wildly inaccurate."
        )
    if fov_full_px < 1:
        raise ValueError("fov_full_px must be at least 1")

    et = datetime2et(time)
    nadir_vec = spy.subpnt("INTERCEPT/ELLIPSOID", body, et, f"IAU_{body}",
                           "LT+S", probe)[2]
    nadir_dist = spy.vnorm(nadir_vec)
    half_angle_rad = 0.5 * fov_full_angle_deg * np.pi / 180
    fov_half_px = fov_full_px / 2
    half_angle_km = np.tan(half_angle_rad) * nadir_dist
    return half_angle_km / fov_half_px
Example #4
0
def spice_positions(et):
    """
    Calculates MAVEN spacecraft position, Mars solar longitude, and subsolar position for a given ephemeris time.

    Parameters
    ----------
    et : float
        Input epoch in ephemeris seconds past J2000.

    Returns
    -------
    et : array
        The input ephemeris times. Just givin'em back.
    subsc_lat : array
        Sub-spacecraft latitudes in degrees.
    subsc_lon : array
        Sub-spacecraft longitudes in degrees.
    sc_alt_km : array
        Sub-spacecraft altitudes in kilometers.
    ls : array
        Mars solar longitudes in degrees.
    subsolar_lat : array
        Sub-solar latitudes in degrees.
    subsolar_lon : array
        Sub-solar longitudes in degrees.
    """

    # do a bunch of SPICE stuff only Justin understands...
    target = 'Mars'
    abcorr = 'LT+S'
    observer = 'MAVEN'
    spoint, trgepc, srfvec = spice.subpnt('Intercept: ellipsoid', target, et, 'IAU_MARS', abcorr, observer)
    rpoint, colatpoint, lonpoint = spice.recsph(spoint)
    if lonpoint > np.pi:
        lonpoint -= 2 * np.pi
    subsc_lat = 90 - np.degrees(colatpoint)
    subsc_lon = np.degrees(lonpoint)
    sc_alt_km = np.sqrt(np.sum(srfvec ** 2))

    # calculate subsolar position
    sspoint, strgepc, ssrfvec = spice.subslr('Intercept: ellipsoid', target, et, 'IAU_MARS', abcorr, observer)
    srpoint, scolatpoint, slonpoint = spice.recsph(sspoint)
    if slonpoint > np.pi:
        slonpoint -= 2 * np.pi
    subsolar_lat = 90 - np.degrees(scolatpoint)
    subsolar_lon = np.degrees(slonpoint)

    # calculate solar longitude
    ls = spice.lspcn(target, et, abcorr)
    ls = np.degrees(ls)

    # return the position information
    return et, subsc_lat, subsc_lon, sc_alt_km, ls, subsolar_lat, subsolar_lon
Example #5
0
def get_nadir_point_surface_velocity_kps(probe: str,
                                         body: str,
                                         time: datetime,
                                         delta_s: float = 10.0) -> float:
    """ Computes surface velocity of nadir point of given probe at given time on given body.

    :param probe: SPICE name of probe
    :param body: SPICE name of target body
    :param time: datetime of computation
    :param delta_s: delta time used for computation of derivative
    :return: Velocity of nadir point across surface [km/s]
    """
    if delta_s <= 0.0:
        raise ValueError("delta_s must be positive.")
    start = datetime2et(time)
    end = datetime2et(time + timedelta(seconds=delta_s))
    nadir_points = [
        spy.subpnt("INTERCEPT/ELLIPSOID", body, et, f"IAU_{body}", "LT+S",
                   probe)[0] for et in (start, end)
    ]
    distance = spy.vdist(*nadir_points)
    return distance / delta_s
    def sc_pos(self, timestr):

        # Convert the timestring to ephemeris time
        self.et = spice.str2et(str(timestr))
        self.et = self.et + self.time_offset

        self.data['sc_wrt_planet'], self.data['target_light_time'] = spice.spkpos(self.spacecraft, self.et, self.iref, 'NONE', self.target)
        self.data['target_distance'] = spice.vnorm(self.data['sc_wrt_planet'])
        self.data['sc_wrt_sun'], light_times = spice.spkpos(self.spacecraft, self.et, self.iref, 'NONE', 'SUN')

        #self.ticks = spice.sce2t(self.sc_id, self.et)

        # Retrieve the position of the spacecraft relative to the target 
        state, self.ltcorr = spice.spkezr(self.target, self.et, self.iref, self.abcorr, self.spacecraft)
        scloc = state[0:3]

        # Get the sub-spacecraft coordinates
        point, epoch, vector = spice.subpnt('NEAR POINT/ELLIPSOID', self.target, self.et, self.framestring, self.abcorr, self.spacecraft)
        self.distance, self.data['lon_sc'], self.data['lat_sc'] = spice.reclat(point)

        # Get the localtime of the spaceship        
        hr, min, sc, time, ampm = spice.et2lst(self.et, self.target_id, self.data['lon_sc'], 'PLANETOCENTRIC')
        self.data['localtime_sc'] = hr + min / 60.0 + sc / 3600.0
        
        # Get the subsolar coordinates
        point, epoch, vector = spice.subslr('NEAR POINT/ELLIPSOID', self.target, self.et, self.framestring, self.abcorr, self.spacecraft)
        distance, self.data['lon_sun'], self.data['lat_sun'] = spice.reclat(point)

        # Convert angles from radians to degrees
        for key in ['lat_sc', 'lon_sc', 'lat_sun', 'lon_sun'] : self.data[key] = np.rad2deg(self.data[key])
        for key in ['lon_sc', 'lon_sun'] : self.data[key] = self.data[key] % 360
	
        state_planet = spice.spkssb(self.target_id, self.et, self.iref)
        inert2p = spice.pxform(self.iref, self.framestring, self.et)
        self.scloc = np.matmul(-inert2p, scloc) 

        self.i2p = spice.pxform(self.instrument, self.framestring, self.et)
        
        return self.data
Example #7
0
def bodyHA(body,et,qlon):
    import spiceypy as sp

    # SUB POINT POSITION
    pos=sp.subpnt("Intercept:  ellipsoid",
                  "EARTH",et,"IAU_EARTH","NONE",
                  body)
    lpos=sp.recpgr("EARTH",pos[0],REARTH,FEARTH);

    # LATITUDE AND LONGITUDE
    lon=lpos[0]*RAD
    lat=lpos[1]*RAD

    # print d2s(lon),d2s(lat)
    
    # DIFFERENCE IN LONGITUDE
    dlon=numpy.mod(qlon-lon,360)

    # HOUR ANGLE
    # H = LST - ALPHA
    ha=dlon

    return ha
Example #8
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
Example #9
0
def geometry(et, bsight, target, frame, sensor, observer=''):

    if not observer:
        observer = sensor

    # Time tag [UTC]
    # pixel id [(x,y)]
    # corner id [(x,y)]

    # Requested geometry

    # lat lon intersection (planetocentric)
    # lat lon subspacecraft
    # lat lon subsolar
    # target distance intersection
    # target angular diameter
    # local solar time intersection
    # phase angle intersection
    # emission angle intersection
    # incidence angle intersection

    #
    # We retrieve the camera information using GETFOV. More info available:
    #
    #   https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/getfov_c.html
    #
    sensor_id = spiceypy.bodn2c(sensor)
    (shape, sensor_frame, ibsight, vectors,
     bounds) = spiceypy.getfov(sensor_id, 100)

    visible = spiceypy.fovtrg(sensor, target, 'ELLIPSOID', frame, 'LT+S',
                              observer, et)

    if not visible:
        return 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

    tarid = spiceypy.bodn2c(target)

    n, radii = spiceypy.bodvrd(target, 'RADII', 3)
    re = radii[0]
    rp = radii[2]
    f = (re - rp) / re

    try:
        #
        # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/sincpt_c.html
        #
        # For each pixel we compute the possible intersection with the target, if
        # the target is intersected we then compute the illumination angles. We
        # use the following SPICE APIs: SINCPT and ILLUMF
        #
        #   https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/sincpt_c.html
        #   https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/illumf_c.html
        #
        (spoint, trgepc, srfvec) = \
            spiceypy.sincpt('ELLIPSOID', target, et, frame, 'LT+S', observer, sensor_frame, bsight)

        (tarlon, tarlat, taralt) = spiceypy.recgeo(spoint, re, f)
        tardis = spiceypy.vnorm(srfvec)

        #
        # Angular diameter
        #
        tarang = np.degrees(
            2 * np.arctan(max(radii) / spiceypy.vnorm(spoint + srfvec)))

        #
        # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/illumf_c.html
        #
        (trgenpc, srfvec, phase, incdnc, emissn, visiblef, iluminatedf) = \
             spiceypy.illumf('ELLIPSOID', target, 'SUN', et, frame, 'LT+S', observer, spoint)

        phase *= spiceypy.dpr()
        incdnc *= spiceypy.dpr()
        emissn *= spiceypy.dpr()

        #
        # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/et2lst_c.html
        #
        #    VARIABLE  I/O  DESCRIPTION
        #    --------  ---  --------------------------------------------------
        #    et         I   Epoch in seconds past J2000 epoch.
        #    body       I   ID-code of the body of interest.
        #    lon        I   Longitude of surface point (RADIANS).
        #    type       I   Type of longitude "PLANETOCENTRIC", etc.
        #    timlen     I   Available room in output time string.
        #    ampmlen    I   Available room in output `ampm' string.
        #    hr         O   Local hour on a "24 hour" clock.
        #    mn         O   Minutes past the hour.
        #    sc         O   Seconds past the minute.
        #    time       O   String giving local time on 24 hour clock.
        #    ampm       O   String giving time on A.M./ P.M. scale.
        (hr, mn, sc, ltime, ampm) = \
            spiceypy.et2lst(et, tarid, tarlon, 'PLANETOCENTRIC', 80, 80)

        #
        # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/subpnt_c.html
        #
        #    Variable  I/O  Description
        #    --------  ---  --------------------------------------------------
        #    method     I   Computation method.
        #    target     I   Name of target body.
        #    et         I   Epoch in TDB seconds past J2000 TDB.
        #    fixref     I   Body-fixed, body-centered target body frame.
        #    abcorr     I   Aberration correction flag.
        #    obsrvr     I   Name of observing body.
        #    spoint     O   Sub-observer point on the target body.
        #    trgepc     O   Sub-observer point epoch.
        #    srfvec     O   Vector from observer to sub-observer point
        #
        (spoint, trgepc, srfev) = \
            spiceypy.subpnt('INTERCEPT/ELLIPSOID', target, et, frame, 'LT+S', observer)

        (sublon, sublat, subalt) = spiceypy.recgeo(spoint, re, f)

        #
        # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/subslr_c.html
        #
        #    Variable  I/O  Description
        #    --------  ---  --------------------------------------------------
        #    method     I   Computation method.
        #    target     I   Name of target body.
        #    et         I   Epoch in ephemeris seconds past J2000 TDB.
        #    fixref     I   Body-fixed, body-centered target body frame.
        #    abcorr     I   Aberration correction.
        #    obsrvr     I   Name of observing body.
        #    spoint     O   Sub-solar point on the target body.
        #    trgepc     O   Sub-solar point epoch.
        #    srfvec     O   Vector from observer to sub-solar point.
        #
        (spoint, trgepc, srfev) = \
            spiceypy.subslr('INTERCEPT/ELLIPSOID', target, et, frame, 'LT+S', observer)

        (sunlon, sunlat, sunalt) = spiceypy.recgeo(spoint, re, f)

        return tarlon, tarlat, sublon, sublat, sunlon, sunlat, tardis, tarang, ltime, phase, emissn, incdnc

    except:
        return 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
Example #10
0
def rotated_transform(et):
    """
    Calculate the rotated pole transform for a particular orbit to replicate the viewing geometry at MAVEN apoapse.

    Parameters
    ----------
    et : obj
        MAVEN apoapsis ephemeris time.

    Returns
    -------
    transform : ???
        A Cartopy rotated pole transform.
    """

    # calculate various parameters using SPICE
    target = 'Mars'
    frame = 'MAVEN_MME_2000'
    abcorr = 'LT+S'
    observer = 'MAVEN'
    state, ltime = spice.spkezr(target, et, frame, abcorr, observer)
    spoint, trgepc, srfvec = spice.subpnt('Intercept: ellipsoid', target, et,
                                          'IAU_MARS', abcorr, observer)
    rpoint, colatpoint, lonpoint = spice.recsph(spoint)
    if lonpoint < 0.:
        lonpoint += 2 * np.pi
    G = 6.673e-11 * 6.4273e23
    r = 1e3 * state[0:3]
    v = 1e3 * state[3:6]
    h = np.cross(r, v)
    n = h / np.linalg.norm(h)
    ev = np.cross(v, h) / G - r / np.linalg.norm(r)
    evn = ev / np.linalg.norm(ev)
    b = np.cross(evn, n)

    # get the sub-spacecraft latitude and longitude, and altitude (converted to meters)
    sublat = 90 - np.degrees(colatpoint)
    sublon = np.degrees(lonpoint)
    if sublon > 180:
        sublon -= 360
    alt = np.sqrt(np.sum(srfvec**2)) * 1e3

    # north pole unit vector in the IAU Mars basis
    polar_vector = [0, 0, 1]

    # when hovering over the sub-spacecraft point unrotated (the meridian of the point is a straight vertical line,
    # this is the exact view when using cartopy's NearsidePerspective or Orthographic with central_longitude and
    # central latitude set to the sub-spacecraft point), calculate the angle by which the planet must be rotated
    # about the sub-spacecraft point
    angle = np.arctan2(np.dot(polar_vector, -b), np.dot(polar_vector, n))

    # first, rotate the pole to a different latitude given the subspacecraft latitude
    # cartopy's RotatedPole uses the location of the dateline (-180) as the lon_0 coordinate of the north pole
    pole_lat = 90 + sublat
    pole_lon = -180

    # convert pole latitude to colatitude (for spherical coordinates)
    # also convert to radians for use with numpy trigonometric functions
    phi = pole_lon * np.pi / 180
    theta = (90 - pole_lat) * np.pi / 180

    # calculate the Cartesian vector pointing to the pole
    polar_vector = [
        np.cos(phi) * np.sin(theta),
        np.sin(phi) * np.sin(theta),
        np.cos(theta)
    ]

    # by rotating the pole, the observer's sub-point in cartopy's un-transformed coordinates is (0,0)
    # the rotation axis is therefore the x-axis
    rotation_axis = [1, 0, 0]

    # rotate the polar vector by the calculated angle
    rotated_polar_vector = np.dot(rotation_matrix(rotation_axis, -angle),
                                  polar_vector)

    # get the new polar latitude and longitude after the rotation, with longitude offset to dateline
    rotated_polar_lon = np.arctan(
        rotated_polar_vector[1] / rotated_polar_vector[0]) * 180 / np.pi - 180
    if sublat < 0:
        rotated_polar_lat = 90 - np.arccos(
            rotated_polar_vector[2] /
            np.linalg.norm(rotated_polar_vector)) * 180 / np.pi
    else:
        rotated_polar_lat = 90 + np.arccos(
            rotated_polar_vector[2] /
            np.linalg.norm(rotated_polar_vector)) * 180 / np.pi

    # calculate a RotatedPole transform for the rotated pole position
    transform = ccrs.RotatedPole(pole_latitude=rotated_polar_lat,
                                 pole_longitude=rotated_polar_lon,
                                 central_rotated_longitude=0)

    # transform the viewer (0,0) point
    tcoords = transform.transform_point(0, 0, ccrs.PlateCarree())

    # find the angle by which the planet needs to be rotated about it's rotated polar axis and calculate a new
    # RotatedPole transform including this angle rotation
    rot_ang = sublon - tcoords[0]
    transform = ccrs.RotatedPole(pole_latitude=rotated_polar_lat,
                                 pole_longitude=rotated_polar_lon,
                                 central_rotated_longitude=rot_ang)

    return transform, alt
        RSOLAR = RSOLAR_l11
        
    if hdulist[0].header['SFORMAT'] == '4X4':
        RSOLAR = RSOLAR_l44
                
if IS_MVIC:
    exptime = 10   # Tod's MVIC Pan Frame mosaics are all 10 sec exposures, and averaged (not summed).
    RSOLAR = RSOLAR_mpf
    FSOLAR = FSOLAR_MPF

#==============================================================================
# Dummy check: Calculate sub-sc latitude using SPICE, rather than from FITS header [concl: working fine]
#==============================================================================

(vec,ltime) = sp.spkezr('Pluto', et, 'J2000', 'LT+S', 'New Horizons')
(subpnt_rec, junk, junk) = sp.subpnt('Intercept: ellipsoid', 'Pluto', et, 'IAU_PLUTO', 'LT+S', 'New Horizons')
(rad_spice, lon_subsc_spice, lat_subsc_spice) = sp.reclat(subpnt_rec)

print("Sub-sc lat = {} [FITS]; {} [SPICE]".format(lat_subsc, hbt.r2d * lat_subsc_spice))

#==============================================================================
# Convert from DN to irradiance (ergs/cm2/s/sr/A). From Hal's writeup.
#==============================================================================
 
dn = dn_median_clean_arr
   
I = dn / exptime / RSOLAR   

# Convert from irradiance to I/F. From Hal's writeup.

iof = math.pi * I * dist_au**2 / FSOLAR
Example #12
0
def mrotat():
    #
    # Convert our UTC string to seconds past J2000 TDB.
    #
    timstr = '2007 JAN 1 00:00:00'
    et = spiceypy.str2et(timstr)

    #
    # Look up the apparent position of the Earth relative
    # to the Moon's center in the IAU_MOON frame at ET.
    #
    [imoonv, ltime] = spiceypy.spkpos('earth', et, 'iau_moon', 'lt+s', 'moon')

    #
    #Express the Earth direction in terms of longitude
    #and latitude in the IAU_MOON frame.
    #
    [r, lon, lat] = spiceypy.reclat(imoonv)

    print('\n'
          'Moon-Earth direction using low accuracy\n'
          'PCK and IAU_MOON frame:\n'
          'Earth lon (deg):        {0:15.6f}\n'
          'Earth lat (deg):        {1:15.6f}\n'.format(lon * spiceypy.dpr(),
                                                       lat * spiceypy.dpr()))
    #
    # Look up the apparent position of the Earth relative
    # to the Moon's center in the MOON_ME frame at ET.
    #
    [mmoonv, ltime] = spiceypy.spkpos('earth', et, 'moon_me', 'lt+s', 'moon')
    #
    # Express the Earth direction in terms of longitude
    # and latitude in the MOON_ME frame.
    #
    [r, lon, lat] = spiceypy.reclat(mmoonv)

    print('Moon-Earth direction using high accuracy\n'
          'PCK and MOON_ME frame:\n'
          'Earth lon (deg):        {0:15.6f}\n'
          'Earth lat (deg):        {1:15.6f}\n'.format(lon * spiceypy.dpr(),
                                                       lat * spiceypy.dpr()))
    #
    # Find the angular separation of the Earth position
    # vectors in degrees.
    #
    sep = spiceypy.dpr() * spiceypy.vsep(imoonv, mmoonv)

    print('For IAU_MOON vs MOON_ME frames:')
    print('Moon-Earth vector separation angle (deg):     '
          '{:15.6f}\n'.format(sep))
    #
    # Look up the apparent position of the Earth relative
    # to the Moon's center in the MOON_PA frame at ET.
    #
    [pmoonv, ltime] = spiceypy.spkpos('earth', et, 'moon_pa', 'lt+s', 'moon')
    #
    # Express the Earth direction in terms of longitude
    # and latitude in the MOON_PA frame.
    #
    [r, lon, lat] = spiceypy.reclat(pmoonv)

    print('Moon-Earth direction using high accuracy\n'
          'PCK and MOON_PA frame:\n'
          'Earth lon (deg):        {0:15.6f}\n'
          'Earth lat (deg):        {1:15.6f}\n'.format(lon * spiceypy.dpr(),
                                                       lat * spiceypy.dpr()))
    #
    # Find the angular separation of the Earth position
    # vectors in degrees.
    #
    sep = spiceypy.dpr() * spiceypy.vsep(pmoonv, mmoonv)

    print('For MOON_PA vs MOON_ME frames:')
    print('Moon-Earth vector separation angle (deg):     '
          '{:15.6f}\n'.format(sep))
    #
    # Find the apparent sub-Earth point on the Moon at ET
    # using the MOON_ME frame.
    #
    [msub, trgepc, srfvec] = spiceypy.subpnt('near point: ellipsoid', 'moon',
                                             et, 'moon_me', 'lt+s', 'earth')
    #
    # Display the sub-point in latitudinal coordinates.
    #
    [r, lon, lat] = spiceypy.reclat(msub)

    print('Sub-Earth point on Moon using high accuracy\n'
          'PCK and MOON_ME frame:\n'
          'Sub-Earth lon (deg):   {0:15.6f}\n'
          'Sub-Earth lat (deg):   {1:15.6f}\n'.format(lon * spiceypy.dpr(),
                                                      lat * spiceypy.dpr()))
    #
    # Find the apparent sub-Earth point on the Moon at
    # ET using the MOON_PA frame.
    #
    [psub, trgepc, srfvec] = spiceypy.subpnt('near point: ellipsoid', 'moon',
                                             et, 'moon_pa', 'lt+s', 'earth')
    #
    # Display the sub-point in latitudinal coordinates.
    #
    [r, lon, lat] = spiceypy.reclat(psub)

    print('Sub-Earth point on Moon using high accuracy\n'
          'PCK and MOON_PA frame:\n'
          'Sub-Earth lon (deg):   {0:15.6f}\n'
          'Sub-Earth lat (deg):   {1:15.6f}\n'.format(lon * spiceypy.dpr(),
                                                      lat * spiceypy.dpr()))
    #
    # Find the distance between the sub-Earth points
    # in km.
    #
    dist = spiceypy.vdist(msub, psub)

    print('Distance between sub-Earth points (km): ' '{:15.6f}\n'.format(dist))
Example #13
0
 def subpnt(self):
     "output = (spoint, trgepoch, srfvec)"
     output = spice.subpnt(self.method, self.target, self.et, self.ref_frame, self.corr, self.obs)
     return output
Example #14
0
 def SC(self, utc, method='INTERCEPT/ELLIPSOID', abcorr='CN+S'):
     '''Sub-spacecraft point'''
     et = spice.str2et(utc)
     pos, _, _ = spice.subpnt(method, self.targ, et,
                           self.ref, abcorr, self.obs)
     return lonlat( pos )