# BepiColombo First Venus Swingby Hands-On Lesson¶

Virtual SPICE Training for BepiColombo, July 21-22, 2020

## Overview¶

In this lesson you will develop a series of simple programs that demonstrate the usage of SpiceyPy to compute a variety of different geometric quantities applicable to experiments carried out by BepiColombo MPO during the first Venus swingby.

You may find it useful to consult the permuted index, the headers of various source modules, and several Required Reading documents available at the NAIF site.

## Find the time of the Venus Swingby using WebGeocalc¶

First of all exercise the usage of WebGeocalc by finding the closest approach of BEPICOLOMBO MPO to Venus. Use the ESA SPCIE Service WebGeocalc instance for this purpose.

- Use an extended Time Window from "2020-07-10" UTC to "2024-10-10" UTC. Is this the first Venus swingby according to the current kernels?
- If not find a way using the same Calculation to obtan the closest approach of the first Venus swingby. Once you have obtained it, save the resulting time.
- With the resulting time, compute the distance to Venus using Cosmographia and cross check with your own program if the distance is correct.

In [2]:

    import spiceypy

    #
    # We load the meta-kernel to use the complete scenario
    #
    spiceypy.furnsh('../kernels/mk/bc_training_class.tm')

    #
    # We obtain the distance at the given time
    #
    et_ca = spiceypy.utc2et('2020-10-15 03:57:49.054612')
    [pos, ltime] = spiceypy.spkpos('VENUS',et_ca,'J2000','NONE','MPO')
    dist = spiceypy.vnorm( pos )

    print( ' Distance between MPO and Venus body centers at first Venus Flyby Closest Approach: {} km'.format(dist))

    spiceypy.kclear()

     Distance between MPO and Venus body centers at first Venus Flyby Closest Approach: 16714.791951616557 km

## Visualize the Venus swingby using SPICE-Enhanced Cosmographia and SPOT¶

Start SPICE-enhanced Cosmographia and load the BepiColombo Scenario. Then choose the time of the Venus Closest Approach for the first Venus Swingby and display the MPO-Venus distance, does it correspond to the distance that you have obtained with WebGeocalc and with your program?

You can also use the public instance of SPOT to visualize the first Venus swingby, you can access it from here: http://bepicolombo.esac.esa.int/itl-viewer/venus_flyby_1/, is the distance the same as well?

## Visualize the Venus MERTIS Observation with Cosmographia and SPOT¶

Using SPOT access "Sensors FoV" and activate "MERTIS_TIR" then click on "View", you will now see the visualization using a view direction parallel to the MERTIS TIR Field-of-View, use the time slider to check when Venus will be in the Field-of-View.

Afterwards using Cosmographia, load the MERTIS TIR sensor configuration file (on top of the appropriate BepiColombo scenario) and try to replicate the same view-point in the same way that it has been shown during the WebGeocalc and Cosmographia lecture.

## Intersecting Vectors with an Ellipsoid (bis)¶

Write a program given an input UTC time string that computes the intersection of the MPO MERTIS TIR boresight and field of view (FOV) boundary vectors with the surface of Venus.
The program presents each point of intersection as

- Planetocentric (latitudinal) coordinates in the IAU_VENUS frame.

For each of the sensor FOV boundary and boresight vectors, if an intersection is found, the program displays the results of the above computations, otherwise it indicates no intersection exists.

Use this program to compute values at the following times:

- "2020 OCT 13 15:45" UTC
- "2020 OCT 14 05:05" UTC
- "2020 OCT 14 22:15" UTC

Can you explain the different results?

In [9]:

    #
    # We will have to handle errors
    #
    from spiceypy.utils.support_types import SpiceyError

    spiceypy.furnsh('../kernels/mk/bc_training_class.tm')

    def mertis_tir_intersections(et):

        #
        # Now we need to obtain the FOV configuration of
        # MERTIS using the planet channel
        #
        lnonid = spiceypy.bodn2c('MPO_MERTIS_TIR_SPACE')

        #
        # Now retrieve the field of view parameters.
        #
        [shape,insfrm,bsight,n,bounds ] = spiceypy.getfov(lnonid,4)

        #
        # `bounds' is a numpy array. We'll convert it to a list.
        #
        # Rather than treat BSIGHT as a separate vector,
        # copy it into the last slot of BOUNDS.
        #
        bounds = bounds.tolist()
        bounds.append( bsight )

        #
        # Set vector names to be used for output.
        #
        vecnam = [ 'Boundary Corner 1',
                   'Boundary Corner 2',
                   'Boundary Corner 3',
                   'Boundary Corner 4',
                   'MPO_MERTIS Boresight' ]

        #
        # Now perform the same set of calculations for each
        # vector listed in the BOUNDS array.
        #
        for i  in  range(5):
            #
            # Call sincpt to determine coordinates of the
            # intersection of this vector with the surface
            # of Mars.
            #
            print( ' Vector: {:s}\n'.format( vecnam[i] ) )

            try:

                [point,trgepc,srfvec] = spiceypy.sincpt('ELLIPSOID','VENUS',et,
                                                        'IAU_VENUS', 'LT+S','MPO',
                                                         insfrm, bounds[i])

                #
                # Display the planetocentric latitude and longitude of the intercept.
                #
                [radius,lon,lat] = spiceypy.reclat( point )

                print( ' Planetocentric coordinates of the intercept (degrees):')
                print( '     LAT = {:.3f}'.format(lat * spiceypy.dpr() )  )
                print( '     LON = {:.3f}\n'.format(lon * spiceypy.dpr() )  )

            except SpiceyError as exc:
                #
                # Display a message if an exception was thrown.
                # For simplicity, we treat this as an indication
                # that the point of intersection was not found,
                # although it could be due to other errors.
                # Otherwise, continue with the calculations.
                #
                print( 'Exception message is: {:s}'.format(exc.value ))

        return

    utc = '2020-10-13T15:45:00'
    print(f'Computing intersections for {utc}')
    et = spiceypy.utc2et(utc)
    mertis_tir_intersections(et)
    print('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -')

    utc = '2020-10-14T05:05:00'
    print(f'Computing intersections for {utc}')
    et = spiceypy.utc2et(utc)
    mertis_tir_intersections(et)
    print('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -')

    utc = '2020-10-14T22:15:00'
    print(f'Computing intersections for {utc}')
    et = spiceypy.utc2et(utc)
    mertis_tir_intersections(et)
    print('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -')

    spiceypy.kclear()

    Computing intersections for 2020-10-13T15:45:00
     Vector: Boundary Corner 1

    Exception message is: Spice returns not found for function: sincpt
     Vector: Boundary Corner 2

    Exception message is: Spice returns not found for function: sincpt
     Vector: Boundary Corner 3

    Exception message is: Spice returns not found for function: sincpt
     Vector: Boundary Corner 4

    Exception message is: Spice returns not found for function: sincpt
     Vector: MPO_MERTIS Boresight

     Planetocentric coordinates of the intercept (degrees):
         LAT = 12.759
         LON = -138.028

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Computing intersections for 2020-10-14T05:05:00
     Vector: Boundary Corner 1

    Exception message is: Spice returns not found for function: sincpt
     Vector: Boundary Corner 2

    Exception message is: Spice returns not found for function: sincpt
     Vector: Boundary Corner 3

    Exception message is: Spice returns not found for function: sincpt
     Vector: Boundary Corner 4

    Exception message is: Spice returns not found for function: sincpt
     Vector: MPO_MERTIS Boresight

    Exception message is: Spice returns not found for function: sincpt
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Computing intersections for 2020-10-14T22:15:00
     Vector: Boundary Corner 1

     Planetocentric coordinates of the intercept (degrees):
         LAT = -65.243
         LON = -124.104

     Vector: Boundary Corner 2

    Exception message is: Spice returns not found for function: sincpt
     Vector: Boundary Corner 3

    Exception message is: Spice returns not found for function: sincpt
     Vector: Boundary Corner 4

     Planetocentric coordinates of the intercept (degrees):
         LAT = -21.912
         LON = -124.295

     Vector: MPO_MERTIS Boresight

     Planetocentric coordinates of the intercept (degrees):
         LAT = -12.802
         LON = 172.149

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

## Getting serious: Compute the time intervals when Venus is in the MERTIS TIR Field-of-View.¶

Compute the time intervals when Venus is visible by the MERTIS_TIR_SPACE Field-of-View in the time frame of the first Venus swingby using the Geometry Finder Sub-System. Print the resulting time windows. If you feel lost you might find it useful to search for documentation either in the header of the corresponding SPICE API or in the documentation of SpiceyPy: https://spiceypy.readthedocs.io/en/master/event_finding.html

Double-check you results with WebGeocalc and with Cosmographia and/or SPOT, do you see any differences? If so, can you explain why?

In [7]:

    import spiceypy
    import spiceypy.utils.support_types as stypes

    #
    # We load the appropriate meta-kernel
    #
    spiceypy.furnsh('../kernels/mk/bc_training_class.tm')

    #
    # Initialize the "confinement" window with the interval
    # over which we'll conduct the search.
    #
    interval = [spiceypy.utc2et('2020-10-13T00:00:00'),
                spiceypy.utc2et('2020-10-15T12:00:00')]

    #
    # We define the parameters for the "confinement" window
    #
    MAXIVL = 10000
    MAXWIN = 2 * MAXIVL

    cnfine = stypes.SPICEDOUBLE_CELL(2)
    spiceypy.wninsd(interval[0], interval[1], cnfine)

    #
    # In the call below, the maximum number of window
    # intervals gfsep can store internally is set to MAXIVL.
    # We set the cell size to MAXWIN to achieve this.
    #
    riswin = stypes.SPICEDOUBLE_CELL(MAXWIN)

    #
    #   We will use the Geometry Function GFTFOV to compute time intervals when
    #   the angular separation between the position vectors of two target
    #   bodies relative to an observer satisfies a numerical relationship.
    #
    #     VARIABLE         I/O  DESCRIPTION
    #   ---------------  ---  ------------------------------------------------
    #   SPICE_GF_MARGIN   P   Minimum complement of FOV cone angle.
    #   SPICE_GF_CNVTOL   P   Convergence tolerance.
    #   SPICE_GF_MAXVRT   P   Maximum number of FOV boundary vertices.
    #   inst              I   Name of the instrument.
    #   target            I   Name of the target body.
    #   tshape            I   Type of shape model used for target body.
    #   tframe            I   Body-fixed, body-centered frame for target body.
    #   abcorr            I   Aberration correction flag.
    #   obsrvr            I   Name of the observing body.
    #   step              I   Step size in seconds for finding FOV events.
    #   cnfine           I-O  SPICE window to which the search is restricted.
    #   result            O   SPICE window containing results.
    inst = 'MPO_MERTIS_TIR_SPACE'
    target = 'VENUS'
    tshape = 'ELLIPSOID'
    tframe = 'IAU_VENUS'
    abcorr = 'NONE'
    obsrvr = 'MPO'
    step = 60 * 60

    spiceypy.gftfov(inst, target, tshape, tframe, abcorr,
                    obsrvr, step, cnfine, riswin)

    #
    # The function wncard returns the number of intervals
    # in a SPICE window.
    #
    winsiz = spiceypy.wncard(riswin)

    dist_list = []

    x, y, z = [], [], []

    if winsiz == 0:
        print('No events were found.')
    else:

        for i in range(winsiz):
            #
            # Fetch the start and stop times of the ith interval from the
            # search result window riswin.
            #
            tfov_time = spiceypy.wnfetd(riswin, i)

            #
            # Generate a Time Window with the rise and set times
            #
            utc_start = spiceypy.et2utc(tfov_time[0], 'ISOC', 3)
            utc_finish = spiceypy.et2utc(tfov_time[1], 'ISOC', 3)

            #
            # We print the resulting intervals
            #
            print(f'Venus in FOV interval {i} from {utc_start} to {utc_finish}')

    spiceypy.kclear()

    Venus in FOV interval 0 from 2020-10-13T03:40:11.475 to 2020-10-14T05:16:56.573
    Venus in FOV interval 1 from 2020-10-14T16:14:43.051 to 2020-10-14T23:56:12.679

## Extra Credit: Compute the Solar Electrical Propulsion arcs (time intervals when the SEP is on)¶

One of the latest features added to the BepiColombo SPICE Kernel Dataset is the possibility to compute the intervals when the Solar Electrical Propulsion is ON. This is not a straightforward computation with SPICE nor you have the kernels available in the GitHub repository, therefore in order to do so follow these steps:

- Identify and download/retrieve the appropriate kernels to compute the SEP intervals and add them to the meta-kernel or FURNSH them
- Identify a kernel that will provide you with indications on how to compute the SEP periods.
- Write a program to obtain the time intervals as suggested by the before-mentioned kernel.
- Double-check your results using WebGeocalc

TIP: The Solar Electrical Propulsion frames are mounted on MTM, not on MPO nor MMO.