Add support for mission event files
📄 Examples of expected files
internal/geopipeline/output/crema_4_2b/Mission_Phases.csv
,Name,t_start,t_end
Jupiter_Phase_1,Approach and first ellipse,2031-01-19T18:50:41,2032-02-08T23:05:31
...
Ganymede_Phase_6_5,GCO500,2035-05-22T06:00:00,2035-10-05T16:01:00
Ganymede_Phase_all,All Ganymede phases,2034-12-19T12:00:00,2035-10-05T16:01:00
Mission_phase_all,All mission phases,2031-01-19T18:50:41,2035-10-05T16:01:00
internal/geopipeline/output/crema_4_2b/mission_timeline_event_file_4_2b.csv
Event name, event time [utc], contextual info
visibility_madrid_start,2031-07-17T18:24:30Z,
visibility_cebreros_start,2031-07-17T18:25:00Z,
Downlink_malargue_start,2031-07-17T20:00:01Z,
visibility_malargue_start,2031-07-17T20:00:01Z,
...
visibility_goldstone_start,2031-07-21T01:18:37Z,
PHASE_010,2031-07-21T01:39:01Z,
Downlink_malargue_end,2031-07-21T04:46:11Z,
visibility_canberra_start,2031-07-21T05:11:37Z,
FLYBY_GANYMEDE,2031-07-21T06:50:41Z,Crema name: 1G1;Time:21-JUL-2031_06:50:41;Altitude above ganymede [km] = 400.00066;Sub-SC lon/lat [deg]= 239.6/-0.2;Sub-SC phase [deg]= 84.8;Sub-SC loctime [hours]= 17.7;Jup-Moon-Sc angle [deg]=118.2;Flight direction: -1Y;Moon true anomalie: 108.3;Ground track velocity [km/s] = 7.2;Velocity wrt sub-sc point radial component [km/s] = -0.0;Velocity wrt sub-sc point tangential component [km/s] = 7.2;Energy generated over +-12h around CA [Wh] = 22379.6;Energy generated over +-1h around CA [Wh] = 880.6;Energy for science over +-12h around CA [Wh] = 8312.4;Energy for science over +-1h around CA [Wh] = -251.4;Relative energy amount for science compared to 6E1 +-12 h = 0.959;Relative energy amount for science compared to 6E1 +-1 h = 0.846;Optimum solar array orientation during pushbroom [deg] = -86.0;PEP-NIM FOV obstruction for optimum solar array [percent] = 0.0;Energy for science over +-1h around CA [Wh] with zero NIM obstruction [Wh] = -1129.5;Maximum sc2sun direction angle to YZ plane during pushbroom = 9.6;Malargue visibility: YES;Cebreros visibility:NO;Delta-time to closest perijove [h] = 13.77
GAN_OCC_EARTH_000_DESC,2031-07-21T07:05:31Z,
GAN_OCC_EARTH_000_ASCE,2031-07-21T08:08:51Z,
visibility_malargue_end,2031-07-21T08:15:41Z,
...
📊 Schema
Events file can have two main nature:
- Window based:
t_start
andt_end
- Single time based:
event time [utc]
In the second case, the name of the even can the suffuied by _start
/_stop
or _DESC
/_ASCE
.
Matching theses keys is important to reconstitute the event windows.
🔧 Proposition of implementation in the moon-coverage
tool
Add an EventsCSV
events parser, that will load the csv
file, extract data and search for t_start
/t_end
/event time [utc]
keywords:
>>> phases = EventsCSV('crema_4_2b/Mission_Phases.csv')
<EventsCollection> Mission_Phases.csv | start time: 2031-01-19 | stop time: 2035-10-05 | 13 events:
- Approach and first ellipse (2031-01-19 | 2032-02-08)
...
- GCO500 (2035-05-22 | 2035-10-05)
...
>>> timeline = EventsCSV('crema_4_2b/mission_timeline_event_file_4_2b.csv', primary_key='Event name')
<EventsCollection> mission_timeline_event_file_4_2b.csv | start time: 2031-07-17 | stop time: 2034-12-19 | 150 events:
- Downlink_malargue (1,255 events)
...
- FLYBY_GANYMEDE (12 events)
...
- By default, the column
name
should be treated as the primary key of anEvent
(but can be overridden by the user). - The output should be a
EventsCollection
(UserDict
object). - The key should be unique, if multiple occurrences are found, they will be grouped in a new
EventsCollection
. - If a temporal windows (
_start
/_end
) is found and it will be merged as anEventWindow
. - Otherwise, the value is considered to be an
Event
The user should be able to query an Event
/EventWindow
/EventsCollection
with its key:
>>> gco_500 = phases['GCO500']
<EventWindow> GCO500 | start time: 2035-05-22 | stop time: 2035-10-05
>>> downlinks = timeline['Downlink_malargue']
<EventsCollection> Downlink_malargue | start time: 2031-07-17 | stop time: 2034-12-19 | 1255 events
>>> downlinks[0]
<EventWindow> Downlink_malargue | start time: 2031-07-17 | stop time: 2031-07-17
>>> gan_flybys = timeline['FLYBY_GANYMEDE']
<EventsCollection> FLYBY_GANYMEDE | start time: 2031-07-21 | stop time: 2034-11-18 | 12 events:
- 1G1 (2031-07-21)
...
- 35G12 (2034-11-18)
>>> gan_1g1 = gan_flybys['1G1']
<Event> FLYBY_GANYMEDE 1G1 | time: 2031-07-21
- Time:21-JUL-2031_06:50:41
- Altitude above ganymede [km] = 400.00066
...
- An
Event
should be a child of aEventWindow
with the samestart
andstop
time. - In some cases, the contextual info can be very rich (cf. Ganymede flyby in the data above). It will be relevant to parses theses data as well a secondary attributes (here separated with
;
but the key/value separator is not consistent, see issues below). - When creating a
EventsCollection
, the primary key should not be required (if not present, the value should be queried aslist
items).
The Event
/EventWindow
should behave like a slice
with a start
and stop
attributes:
>>> gco_500.start, gco_500.stop
'2035-05-22T06:00:00', '2035-10-05T16:01:00'
>>> gan_1G1.start, gan_1G1.stop
2031-07-21T06:50:41, 2031-07-21T06:50:41
An Event
can be used as single time input for a Trajectory
or to search a Flyby
:
>>> tour = TourConfig(spacecraft='JUICE', mk='4.2', target='Ganymede', default_time_step='1h')
>>> tour[gan_1G1]
<SpacecraftTrajectory> Observer: JUICE | Target: GANYMEDE
- Start time: 2031-07-21T06:50:41.000
- Stop time: 2031-07-21T06:50:41.000
- Nb of pts: 1
>>> tour.flyby(gan_1G1)
<SpacecraftFlyby> Observer: JUICE | Target: GANYMEDE
- Altitude at CA: 10,922.5 km
- UTC at CA: 2031-07-20T00:59:24
- Duration: 1 day, 0:00:00
- Nb of pts: 2,041
An Event
should supports time operations:
>>> gan_1G1 + '1 h'
'2031-07-21T07:50:41.000'
>>> tour[gan_1G1 - '12 h' : gan_1G1 + '12 h' : '10 min']
<SpacecraftTrajectory> Observer: JUICE | Target: GANYMEDE
- Start time: 2031-07-20T18:50:41.000
- Stop time: 2031-07-21T18:50:41.000
- Nb of pts: 145
An EventWindow
could be used as a slice
input:
>>> tour[gco_500]
<SpacecraftTrajectory> Observer: JUICE | Target: GANYMEDE
- Start time: 2035-05-22T06:00:00.000
- Stop time: 2035-10-05T16:01:00.000
- Nb of pts: 3,276
>>> tour[gco_500(step='10 min')]
<SpacecraftTrajectory> Observer: JUICE | Target: GANYMEDE
- UTC start time: 2035-05-22T06:00:00.000
- UTC stop time: 2035-10-05T16:01:00.000
- Nb of pts: 19,646
- the time step can be configured with an optional
step
attribute on theEvent
itself (__call__
) or by thedefault_time_step
attribute inTourConfig
initialization (manualstart
/stop
/step
input is still possible, see notes below).
An EventWindow
/EventsCollection
should implement a contains
function similar to the ROI
object to perform Tranjectory
intersection and filtering:
>>> traj & gco_500
[True, ..., False, True]
>>> traj ^ downlinks
[False, ..., True, False]
>>> traj.where(traj ^ downlinks)
<MaskedTrajectory> ...
- this can be used to mask the downlink windows on the Trajectory.
- it should work on
EventWindow
andEventsCollection
but show throw an error on a singleEvent
. - this will require a slight change to the default behavior of
Trajectory.intersection()
that useself.lonlat
as default comparison input.
✏ Notes
-
Upper level implementation for the
Mission_phases
andmission_timeline_event_file
can be added with custom header specifics (likeStephan2020ROIsCollection
). -
A data custom parser could be used to extract secondary attributes(for example to extract the name of the flybys, currently stored as
Crema name: XXXX
). -
Manual trajectory temporal grid is always possible but less elegant:
>>> tour[gco_500.start : gco_500.stop : '10 min']
<SpacecraftTrajectory> Observer: JUICE | Target: GANYMEDE
- UTC start time: 2035-05-22T06:00:00.000
- UTC stop time: 2035-10-05T16:01:00.000
- Nb of pts: 19,646
❓ Questions
- Does
_DESC
/_ASCE
should be interpreted as_start
and_end
?
⚠ Potential issues
- Some files don't have header to defined their columns, for example:
internal/geopipeline/output/crema_4_2b/downlink_file_4_2b_MALARGUE.csv
:
DL_,2031-07-17T20:00:01Z,2031-07-18T05:00:01Z,,GENERIC
DL_,2031-07-18T19:55:03Z,2031-07-19T04:55:01Z,,GENERIC
...
- The name of the header is not consistent across the different file (
snakecased
names should be flavored). - Some fields are are not described in the header (eg. 'crema_4_2b/Mission_Phases.csv').
- The header should be prefix with a commented sign
#
to allow easier import fornumpy
(to avoid an unnecessaryskiprows
). - Keys are inconsistently cased (upper-case, lowercase, mixed).
- Secondary attributes should have a constant key/value separator to be corrected extracted (currently
:
and=
are mixed). - Secondary attributes are sometimes too complex to have a general matching pattern or type conversion:
Sub-SC lon/lat [deg]= 239.6/-0.2
should not stack 2 values with a mixed key. - Not all
EventCollection
have secondary keys. Additionalcontext info
may be required for an incremental value (when the key is not unique). - UTC time are not always suffixed with a
Z
(this is already handled by themoon-coverage
time parser, but it could improved for consistency, discarding theZ
should be flavored because it is not natively compatible with the SPICE time parser).
🔬 Data access
- The JUICE events files are not distributed publicly and need to be stored and managed by the user. Some of them may be provided through the DataLabs but it will be better to have an public archive available.
- No information regarding their creation is available to the end-user. No access to the pipeline input keys that will ensure the reproduction of the data (for example, the
metakernel version
is not provided). Outdated-check may be required to avoid mixing not-compatible metakernels inputs.