Esempio n. 1
0
    def __get_pixel_values(self, et, pixel_vector):
        try:
            spoint, trgepc, srfvec = \
                self.__compute_pixel_surface_intercept(et, pixel_vector)
            trgepc, srfvec, phase, solar, emission = \
                self.__compute_illumination_angles(et, spoint)
        except spiceypy.utils.exceptions.NotFoundError:
            return np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, \
                   np.nan

        rpoint, colatpoint, lonpoint = spice.recsph(spoint)

        if lonpoint < 0:
            lonpoint += 2 * np.pi

        hr, mn, sc, time, ampm = spice.et2lst(
            et, self.__body, lonpoint, 'planetocentric', timlen=256,
            ampmlen=256)

        latitude = np.degrees(np.pi / 2 - colatpoint)
        longitude = np.degrees(lonpoint)
        local_time = hr + mn / 60 + sc / 3600
        solar_zenith_angle = np.degrees(solar)
        emission_angle = np.degrees(emission)
        phase_angle = np.degrees(phase)
        map_lat = int(np.round(np.degrees(colatpoint), 1) * 10)
        map_lon = int(np.round(np.degrees(lonpoint), 1) * 10)
        if map_lat == 1800:
            map_lat = 1799
        if map_lon == 3600:
            map_lon = 3599
        geography_map = self.__geography_map[map_lat, map_lon]
        field_map = self.__field_map[map_lat, map_lon]
        return latitude, longitude, local_time, solar_zenith_angle, \
               emission_angle, phase_angle, geography_map, field_map
    def vector_params(self, vector) : 

        ret = np.full(shape = [len(self.keys)], fill_value = -1000.0)
        
        # Calculate the distance of the boresight and the center of the target
        origin = np.array([0.0, 0.0, 0.0])
        nearpoint, rayradius = spice.nplnpt(self.scloc, vector, origin)

        # Get the intercept to calculate the radius of of the target 
        normal = spice.surfpt(origin, 1000.0 * nearpoint, self.radii[0], self.radii[1], self.radii[2])
        ret[self.map['limb_distance']] = rayradius - spice.vnorm(normal)
    
        # Calculate the 'occultation' latitude and longitude 
        ret[self.map['bodyintercept']], ret[self.map['limb_lat']], ret[self.map['limb_lon']] = spice.reclat(nearpoint) 

        # Test if the boresight intersects with our target surface 
        try: 
            point = spice.surfpt(self.scloc, vector, self.radii[0], self.radii[1], self.radii[2])
            intercept = True
        except: 
            intercept = False
    
        if (intercept) : 
        
            # Get some angles 
            ret[self.map['phase']], ret[self.map['incidence']], ret[self.map['emission']] = spice.illum(self.target, self.et , self.abcorr, self.spacecraft, point)

            # Calculate the planetocentric coordinates 
            distance, ret[self.map['lon']], ret[self.map['lat']] = spice.reclat(point)
            ret[self.map['losdist']] = spice.vnorm(self.scloc - point)
            
             # Calculate the planetographic coordinates
            ret[self.map['lon_graphic']], ret[self.map['lat_graphic']], bodyintercept = spice.recpgr(self.target, point, self.radii[0], self.flattening)
            
            # Get the localtime, and convert to decimal hours 
            hr, min, sc, time, ampm = spice.et2lst(self.et, self.target_id, ret[self.map['lon']], 'PLANETOCENTRIC')
            ret[self.map['localtime']] = hr + min / 60.0 + sc / 3600.0
            
        # For the angles, convert radians to degrees
        for key in self.angles : 
            if (ret[self.map[key]] != -1000.0) : 
                    ret[self.map[key]] = np.rad2deg(ret[self.map[key]])

        # Makes sure longitudes wrap 0 to 360, spice returns the Earth-like -180 to 180. 
        longitudes = ['lon', 'limb_lon', 'lon_graphic']
        for key in longitudes : 
            ret[self.map[key]] = ret[self.map[key]] % 360

        return np.array(ret)
Esempio n. 3
0
def localST(et,lon):
    """
    Local Solar time and hour angle of the sun

    et: Ephemeris time
    lon: Longitude (in degrees)
    """
    import spiceypy as sp

    # Local solar time
    lst=sp.et2lst(et,399,lon*DEG,"PLANETOGRAPHIC",51,51)

    # Hour angle
    hsun=numpy.mod((s2d(lst[0],lst[1],lst[2])-12.0)/SIDFAC*15,360)

    return lst,hsun
    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
Esempio n. 5
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
Esempio n. 6
0
    def highres_swath_geometry(self, hdul, map_data, res=200):
        """
        Generates an artificial high-resolution slit, calculates viewing geometry and surface-intercept map.
        Parameters
        ----------
        hdul : HDUList
            Opened FITS file.
        res : int, optional
            The desired number of artificial elements along the slit. Defaults to 200.

        Returns
        -------
        latitude : array
            Array of latitudes for the centers of each high-resolution artificial pixel. NaNs if pixel doesn't intercept
            the surface of Mars.
        longitude : array
            Array of longitudes for the centers of each high-resolution artificial pixel. NaNs if pixel doesn't intercept
            the surface of Mars.
        sza : array
            Array of solar zenith angles for the centers of each high-resolution artificial pixel. NaNs if pixel doesn't
            intercept the surface of Mars.
        ea
        pa
        local_time : array
            Array of local times for the centers of each high-resolution artificial pixel. NaNs if pixel doesn't intercept
            the surface of Mars.
        x : array
            Horizontal coordinate edges in angular space. Has shape (n+1, m+1) for geometry arrays with shape (n,m).
        y : array
            Vertical coordinate edges in angular space. Has shape (n+1, m+1) for geometry arrays with shape (n,m).
        cx : array
            Horizontal coordinate centers in angular space. Same shape as geometry arrays.
        cy : array
            Vertical coordinate centers in angular space. Same shape as geometry arrays.
        context_map : array
            High-resolution image of the Mars surface as intercepted by the swath. RGB tuples with shape (n,m,3).
        """
        # get swath vectors, ephemeris times, and mirror angles
        vec = hdul['pixelgeometry'].data['pixel_vec']
        et = hdul['integration'].data['et']
        # get dimensions of the input data
        n_int = hdul['integration'].data.shape[0]
        n_spa = len(hdul['binning'].data['spapixlo'][0])
        # set the high-resolution slit width and calculate the number of high-resolution integrations
        hifi_spa = res
        hifi_int = int(hifi_spa / n_spa * n_int)
        # make arrays of ephemeris time and array to hold the new swath vector calculations

        # here thru 481 just interpolate et_arr and vec_arr onto new grid (int, pos) and (int, pos, 3) adn they're all just center values

        et_arr = np.expand_dims(et, 1) * np.ones((n_int, n_spa))
        et_arr = resize(et_arr, (hifi_int, hifi_spa), mode='edge')
        vec_arr = np.zeros((hifi_int + 1, hifi_spa + 1, 3))
        # make an artificially-divided swath and create new array of swath vectors
        if self.__flip:
            lower_left = vec[0, :, 0, 0]
            upper_left = vec[-1, :, 0, 1]
            lower_right = vec[0, :, -1, 2]
            upper_right = vec[-1, :, -1, 3]
        else:
            lower_left = vec[0, :, 0, 1]
            upper_left = vec[-1, :, 0, 0]
            lower_right = vec[0, :, -1, 3]
            upper_right = vec[-1, :, -1, 2]
        for e in range(3):
            a = np.linspace(lower_left[e], upper_left[e], hifi_int + 1)
            b = np.linspace(lower_right[e], upper_right[e], hifi_int + 1)
            vec_arr[:, :, e] = np.array(
                [np.linspace(i, j, hifi_spa + 1) for i, j in zip(a, b)])
        # resize array to extract centers
        vec_arr = resize(vec_arr, (hifi_int, hifi_spa, 3), anti_aliasing=True)
        # make empty arrays to hold geometry calculations
        latitude = np.zeros((hifi_int, hifi_spa)) * np.nan
        longitude = np.zeros((hifi_int, hifi_spa)) * np.nan
        sza = np.zeros((hifi_int, hifi_spa)) * np.nan
        phase_angle = np.zeros((hifi_int, hifi_spa)) * np.nan
        emission_angle = np.zeros((hifi_int, hifi_spa)) * np.nan
        local_time = np.zeros((hifi_int, hifi_spa)) * np.nan
        context_map = np.zeros((hifi_int, hifi_spa, 4)) * np.nan

        # calculate intercept latitude and longitude using SPICE, looping through each high-resolution pixel
        target = 'Mars'
        frame = 'IAU_Mars'
        abcorr = 'LT+S'
        observer = 'MAVEN'
        body = 499  # Mars IAU code
        for i in range(hifi_int):
            for j in range(hifi_spa):
                et = et_arr[i, j]
                los_mid = vec_arr[i, j, :]
                # try to perform the SPICE calculations and record the results
                try:
                    # calculate surface intercept
                    spoint, trgepc, srfvec = spice.sincpt(
                        'Ellipsoid', target, et, frame, abcorr, observer,
                        frame, los_mid)
                    # calculate illumination angles
                    trgepc, srfvec, phase_for, solar, emissn = spice.ilumin(
                        'Ellipsoid', target, et, frame, abcorr, observer,
                        spoint)
                    # convert from rectangular to spherical coordinates
                    rpoint, colatpoint, lonpoint = spice.recsph(spoint)
                    # convert longitude from domain [-pi,pi) to [0,2pi)
                    if lonpoint < 0.:
                        lonpoint += 2 * np.pi
                    # convert ephemeris time to local solar time
                    hr, mn, sc, time, ampm = spice.et2lst(et,
                                                          body,
                                                          lonpoint,
                                                          'planetocentric',
                                                          timlen=256,
                                                          ampmlen=256)
                    # convert spherical coordinates to latitude and longitude in degrees
                    latitude[i, j] = np.degrees(np.pi / 2 - colatpoint)
                    longitude[i, j] = np.degrees(lonpoint)
                    # convert illumination angles to degrees and record
                    sza[i, j] = np.degrees(solar)
                    phase_angle[i, j] = np.degrees(phase_for)
                    emission_angle[i, j] = np.degrees(emissn)
                    # convert local solar time to decimal hour
                    local_time[i, j] = hr + mn / 60 + sc / 3600
                    # convert latitude and longitude to pixel coordinates
                    map_lat = int(np.round(np.degrees(colatpoint), 1) * 10)
                    map_lon = int(np.round(np.degrees(lonpoint), 1) * 10)
                    # make a corresponding magnetic field topology map
                    context_map[i, j] = map_data[map_lat, map_lon]
                # if the SPICE calculation fails, this (probably) means it didn't intercept the planet
                except:
                    # This pixel (or the vector) didn't intercept the planet
                    pass
        # get mirror angles
        angles = hdul['integration'].data[
            'mirror_deg'] * 2  # convert from mirror angles to FOV angles
        dang = np.diff(angles)[0]
        # create an meshgrid of angular coordinates for the high-resolution pixel edges
        x, y = np.meshgrid(
            np.linspace(0, self.__slit_width, hifi_spa + 1),
            np.linspace(angles[0] - dang / 2, angles[-1] + dang / 2,
                        hifi_int + 1))
        # calculate the angular separation between pixels
        dslit = self.__slit_width / hifi_spa
        # create an meshgrid of angular coordinates for the high-resolution pixel centers
        cx, cy = np.meshgrid(
            np.linspace(0 + dslit, self.__slit_width - dslit, hifi_spa),
            np.linspace(angles[0], angles[-1], hifi_int))
        # beta-flip the coordinate arrays if necessary
        if self.__flip:
            x = np.fliplr(x)
            y = (np.fliplr(y) - 90) / (-1) + 90
            cx = np.fliplr(cx)
            cy = (np.fliplr(cy) - 90) / (-1) + 90
        # convert longitude to [-180,180)
        longitude[np.where(longitude > 180)] -= 360
        # return the geometry and coordinate arrays
        # cx, cy is for a lat/lon grid on top of the map (50, 1) --> (200, 4)
        # all but x, y, context_map is (n_integrations, n_positions)
        # the context map has shape (n_integrations, n_positions, 4)
        # x, y, cx, cy are (n_int +1, n_pos + 1)
        return latitude, longitude, sza, emission_angle, phase_angle, \
               local_time, x, y, cx, cy, context_map
Esempio n. 7
0
        #calculate surface tangent point using pointing vectors and tgo position vs time
        print("Calculating tangent points")
        tangent_coords = np.asfarray([
            sp.npedln(mars_axes[0], mars_axes[1], mars_axes[2], line_point,
                      line_vector)[0] for line_point, line_vector in zip(
                          list(line_points), list(line_vectors))
        ])
        tangent_lonlats1 = np.asfarray([
            sp.reclat(tangent_coord) for tangent_coord in list(tangent_coords)
        ])
        tangent_lonlats = np.asfarray(
            [[tangent_lonlat[1] * sp.dpr(), tangent_lonlat[2] * sp.dpr()]
             for tangent_lonlat in list(tangent_lonlats1)])
        tangent_lsts = [
            sp.et2lst(time, 499, (tangent_lonlat[0] / sp.dpr()),
                      "PLANETOCENTRIC")[3]
            for time, tangent_lonlat in zip(list(times), list(tangent_lonlats))
        ]
        tangent_lsts_hours = np.asfarray([
            np.float(tangent_lst[0:2]) + np.float(tangent_lst[3:5]) / 60.0 +
            np.float(tangent_lst[6:8]) / 3600.0 for tangent_lst in tangent_lsts
        ])

        nadir_lonlats = np.asfarray(
            [sp.reclat(mars2tgo)
             for mars2tgo in list(mars2tgo_pos)])[:, 1:3] * sp.dpr()
        nadir_lsts = [
            sp.et2lst(time, 499, (nadir_lonlat[0] / sp.dpr()),
                      "PLANETOCENTRIC")[3]
            for time, nadir_lonlat in zip(list(times), list(nadir_lonlats))
        ]
Esempio n. 8
0
typein = "PLANETOCENTRIC"
body = 499

etStart = sp.utc2et("2018MAR24-11:50:00 UTC")
etEnd = sp.utc2et("2020MAR24-11:50:00 UTC")

ets = np.linspace(etStart, etEnd, num=180)

writeOutput("UTC Time, LSubS, Longitude, Latitude, Local Solar Time")
for et in list(ets):

    lSubS = lsubs(et)
    terminatorPoints = sp.edterm(trmtyp, source, target, et, ref, abcorr,
                                 observer, npts)

    terminatorLatLonsRad = np.asfarray([
        sp.reclat(terminatorPoint)[1:3]
        for terminatorPoint in terminatorPoints[2]
    ])

    terminatorLatLonsDeg = terminatorLatLonsRad * sp.dpr()

    terminatorLSTs = [
        sp.et2lst(et, body, terminatorLatLonRad[0], typein)[3]
        for terminatorLatLonRad in list(terminatorLatLonsRad)
    ]

    for index, terminatorLST in enumerate(terminatorLSTs):
        writeOutput("%s,%0.2f,%0.2f,%0.2f,%s" %
                    (et2utc(et), lSubS, terminatorLatLonsDeg[index, 0],
                     terminatorLatLonsDeg[index, 1], terminatorLST))
Esempio n. 9
0
def highres_swath_geometry(hdul, res=200, twilight='discrete'):
    """
    Generates an artificial high-resolution slit, calculates viewing geometry and surface-intercept map.

    Parameters
    ----------
    hdul : HDUList
        Opened FITS file.
    res : int, optional
        The desired number of artificial elements along the slit. Defaults to 200.
    twilight : str
        The appearance of the twilight zone. 'discrete' has a partially transparent zone with sharp edges while
        'continuous' smoothes it with a cosine function. The discrete option does not always work on all systems, but
        I cannot yet say why that is. In those cases you get the continuous appearance.

    Returns
    -------
    latitude : array
        Array of latitudes for the centers of each high-resolution artificial pixel. NaNs if pixel doesn't intercept
        the surface of Mars.
    longitude : array
        Array of longitudes for the centers of each high-resolution artificial pixel. NaNs if pixel doesn't intercept
        the surface of Mars.
    sza : array
        Array of solar zenith angles for the centers of each high-resolution artificial pixel. NaNs if pixel doesn't
        intercept the surface of Mars.
    local_time : array
        Array of local times for the centers of each high-resolution artificial pixel. NaNs if pixel doesn't intercept
        the surface of Mars.
    x : array
        Horizontal coordinate edges in angular space. Has shape (n+1, m+1) for geometry arrays with shape (n,m).
    y : array
        Vertical coordinate edges in angular space. Has shape (n+1, m+1) for geometry arrays with shape (n,m).
    cx : array
        Horizontal coordinate centers in angular space. Same shape as geometry arrays.
    cy : array
        Vertical coordinate centers in angular space. Same shape as geometry arrays.
    context_map : array
        High-resolution image of the Mars surface as intercepted by the swath. RGB tuples with shape (n,m,3).
    """

    # calculate beta-flip state
    flipped = beta_flip(hdul)

    # get swath vectors, ephemeris times, and mirror angles
    vec = hdul['pixelgeometry'].data['pixel_vec']
    et = hdul['integration'].data['et']

    # get dimensions of the input data
    n_int = hdul['integration'].data.shape[0]
    n_spa = len(hdul['binning'].data['spapixlo'][0])

    # set the high-resolution slit width and calculate the number of high-resolution integrations
    hifi_spa = res
    hifi_int = int(hifi_spa / n_spa * n_int)

    # make arrays of ephemeris time and array to hold the new swath vector calculations
    et_arr = np.expand_dims(et, 1) * np.ones((n_int, n_spa))
    et_arr = resize(et_arr, (hifi_int, hifi_spa), mode='edge')
    vec_arr = np.zeros((hifi_int + 1, hifi_spa + 1, 3))

    # make an artificially-divided slit and create new array of swath vectors
    if flipped:
        lower_left = vec[0, :, 0, 0]
        upper_left = vec[-1, :, 0, 1]
        lower_right = vec[0, :, -1, 2]
        upper_right = vec[-1, :, -1, 3]
    else:
        lower_left = vec[0, :, 0, 1]
        upper_left = vec[-1, :, 0, 0]
        lower_right = vec[0, :, -1, 3]
        upper_right = vec[-1, :, -1, 2]

    for e in range(3):
        a = np.linspace(lower_left[e], upper_left[e], hifi_int + 1)
        b = np.linspace(lower_right[e], upper_right[e], hifi_int + 1)
        vec_arr[:, :, e] = np.array([np.linspace(i, j, hifi_spa + 1) for i, j in zip(a, b)])

    # resize array to extract centers
    vec_arr = resize(vec_arr, (hifi_int, hifi_spa, 3), anti_aliasing=True)

    # make empty arrays to hold geometry calculations
    latitude = np.zeros((hifi_int, hifi_spa))*np.nan
    longitude = np.zeros((hifi_int, hifi_spa))*np.nan
    sza = np.zeros((hifi_int, hifi_spa))*np.nan
    phase_angle = np.zeros((hifi_int, hifi_spa))*np.nan
    emission_angle = np.zeros((hifi_int, hifi_spa))*np.nan
    local_time = np.zeros((hifi_int, hifi_spa))*np.nan
    context_map = np.zeros((hifi_int, hifi_spa, 3))*np.nan

    # load Mars surface map and switch longitude domain from [-180,180) to [0, 360)
    mars_surface_map = plt.imread(os.path.join(pkg_resources.resource_filename('maven_iuvs', 'ancillary/'),
                                               'mars_surface_map.jpg'))
    offset_map = np.zeros_like(mars_surface_map)
    offset_map[:, :1800, :] = mars_surface_map[:, 1800:, :]
    offset_map[:, 1800:, :] = mars_surface_map[:, :1800, :]
    mars_surface_map = offset_map

    # calculate intercept latitude and longitude using SPICE, looping through each high-resolution pixel
    target = 'Mars'
    frame = 'IAU_Mars'
    abcorr = 'LT+S'
    observer = 'MAVEN'
    body = 499  # Mars IAU code

    for i in range(hifi_int):
        for j in range(hifi_spa):
            et = et_arr[i, j]
            los_mid = vec_arr[i, j, :]

            # try to perform the SPICE calculations and record the results
            # noinspection PyBroadException
            try:

                # calculate surface intercept
                spoint, trgepc, srfvec = spice.sincpt('Ellipsoid', target, et, frame, abcorr, observer, frame, los_mid)

                # calculate illumination angles
                trgepc, srfvec, phase_for, solar, emissn = spice.ilumin('Ellipsoid', target, et, frame, abcorr,
                                                                        observer, spoint)

                # convert from rectangular to spherical coordinates
                rpoint, colatpoint, lonpoint = spice.recsph(spoint)

                # convert longitude from domain [-pi,pi) to [0,2pi)
                if lonpoint < 0.:
                    lonpoint += 2 * np.pi

                # convert ephemeris time to local solar time
                hr, mn, sc, time, ampm = spice.et2lst(et, body, lonpoint, 'planetocentric', timlen=256, ampmlen=256)

                # convert spherical coordinates to latitude and longitude in degrees
                latitude[i, j] = np.degrees(np.pi / 2 - colatpoint)
                longitude[i, j] = np.degrees(lonpoint)

                # convert illumination angles to degrees and record
                sza[i, j] = np.degrees(solar)
                phase_angle[i, j] = np.degrees(phase_for)
                emission_angle[i, j] = np.degrees(emissn)

                # convert local solar time to decimal hour
                local_time[i, j] = hr + mn / 60 + sc / 3600

                # convert latitude and longitude to pixel coordinates
                map_lat = int(np.round(np.degrees(colatpoint), 1) * 10)
                map_lon = int(np.round(np.degrees(lonpoint), 1) * 10)

                # instead of changing an alpha layer, I just multiply an RGB triplet by a scaling fraction in order to
                # make it darker; determine that scalar here based on solar zenith angle
                if twilight == 'discrete':
                    if (sza[i, j] > 90) & (sza[i, j] <= 102):
                        twilight = 0.7
                    elif sza[i, j] > 102:
                        twilight = 0.4
                    else:
                        twilight = 1
                else:
                    if (sza[i, j] > 90) & (sza[i, j] <= 102):
                        tsza = (sza[i, j]-90)*np.pi/2/12
                        twilight = np.cos(tsza)*0.6 + 0.4
                    elif sza[i, j] > 102:
                        twilight = 0.4
                    else:
                        twilight = 1

                # place the corresponding pixel from the high-resolution Mars map into the swath context map with the
                # twilight scaling
                context_map[i, j, :] = mars_surface_map[map_lat, map_lon, :] / 255 * twilight

            # if the SPICE calculation fails, this (probably) means it didn't intercept the planet
            except:
                pass

    # get mirror angles
    angles = hdul['integration'].data['mirror_deg'] * 2  # convert from mirror angles to FOV angles
    dang = np.diff(angles)[0]

    # create an meshgrid of angular coordinates for the high-resolution pixel edges
    x, y = np.meshgrid(np.linspace(0, slit_width_deg, hifi_spa + 1),
                       np.linspace(angles[0] - dang / 2, angles[-1] + dang / 2, hifi_int + 1))

    # calculate the angular separation between pixels
    dslit = slit_width_deg / hifi_spa

    # create an meshgrid of angular coordinates for the high-resolution pixel centers
    cx, cy = np.meshgrid(
        np.linspace(0 + dslit, slit_width_deg - dslit, hifi_spa),
        np.linspace(angles[0], angles[-1], hifi_int))

    # beta-flip the coordinate arrays if necessary
    if flipped:
        x = np.fliplr(x)
        y = (np.fliplr(y) - 90) / (-1) + 90
        cx = np.fliplr(cx)
        cy = (np.fliplr(cy) - 90) / (-1) + 90

    # convert longitude to [-180,180)
    longitude[np.where(longitude > 180)] -= 360

    # return the geometry and coordinate arrays
    return latitude, longitude, sza, local_time, x, y, cx, cy, context_map
Esempio n. 10
0
 def local_soltime(self):
     return spice.et2lst(self.et, self.target_id, self.coords.lon.value,
                         "PLANETOGRAPHIC")[3]
clearanceangle = np.ones([winsiz - 1, 1])
Rx = np.ones([winsiz - 1, 1])
MexNadirTGOAngle = np.ones([winsiz - 1, 1])
# grazingangle = np.ones([winsiz-1,1]) # HERE

for i in tqdm(range(winsiz - 1)):

    # try to plot the location on a map with cartopy
    lon[i], lat[i], dist[i], nearestpoint, alt, speed, date_time[
        i], ingress_date_time[i], veldopp[i], MexNadirTGOAngle[
            i] = main.Location(occs.Time[i], occs.Ingress[i], sv,
                               0)  # FUNCTION NEEDS NEW NAME
    sza[i] = main.SolarZenithAngles(occs.Time[i], nearestpoint, sv)
    clearanceangle[i] = main.earlyclearance(occs.Time[i], sv)
    hour, minute, sec, _, _ = spice.et2lst(
        occs.Time[i], 499, (lon[i] * (math.pi / 180)),
        'PLANETOCENTRIC')  # 499 = spice code for Mars
    localtimevect = [hour, minute, sec]
    localtime[i] = "%d:%d:%d" % (localtimevect[0], localtimevect[1],
                                 localtimevect[2])
    # angle[i] = main.grazingangle(occs.Time[i], sv) # this process is probably slow because this function is forming the entire profile.
    Rx[i] = main.expectedpower(occs.Time[i], sv)

    # progess = (i/(winsiz-1)) *100
    # print('%.2f' %progess)

# plot all of the tangent points onto the surface of mars
#main.charter(lon, lat, start, stop,here)

# Add to dataframe
occs['Julian'] = date_time
Esempio n. 12
0
 def _get_local_soltime(self):
     try:
         return spice.et2lst(self.et, self.target_id, self.coords.lon, "PLANETOCENTRIC")
     except SPointNotSetError:
         raise