Event Finding

To use the events system, first load the relevent modules:

In [1]:
import godot.core.events as events

# optionally avoid verbose logging messages
import godot.core.util as util
util.suppressLogger()

Now we want to construct a frames system. We do this by creating a universe with the necessary frames pre-built. The universe is generated with a yaml file. Loading this text into the system is easy. We import the cosmos module, and the yaml module and then construct our universe.

In [2]:
import godot.cosmos as cosmos
import ruamel.yaml as yaml

uniConfig = cosmos.util.load_yaml('universe.yml')
uni = cosmos.Universe(uniConfig)

we want to find the visibility periods of the Sun and Moon from New Norcia, so we creat a Python function for the elevation from each:

In [3]:
import godot.core.astro as astro 

def moonElev( epo ):
    x = uni.frames.vector3('New_Norcia', 'Moon', 'New_Norcia', epo)
    return astro.sphericalFromCart(x)[2]

def sunElev( epo ):
    x = uni.frames.vector3('New_Norcia', 'Sun', 'New_Norcia', epo)
    return astro.sphericalFromCart(x)[2]

This is only approximate, because it does not consider the visibility mask from New Norcia or the finite angular shape of the bodies, but it is good enough for this test. Users should feel free to adapt the functions to make the computation more accurate. Now we can compute the event interval sets. There are a few numerical values to be selected for this process.

First choose the span of the search:

In [4]:
import godot.core.tempo as tempo
epoch1 = tempo.parseEpoch("2018-06-05T14:00:00.000 UTC")
epoch2 = tempo.parseEpoch("2018-06-14T14:00:00.000 UTC")
rng    = tempo.EpochRange( epoch1, epoch2 )

We set the tolerance for the event search in the independent variable (time) in seconds.

In [5]:
xtol = 1e-9

We set the step size for the search. This should be so that there is at most one maximum or minimum of the function in every step. For visibility it is okay to set this anywhere up to 0.5 days

In [6]:
step = 43200.0

Now we generate a grid of epochs

In [7]:
grid = rng.createGrid(step)

Finally, we set an epsilon for computing function derivatives by numerical differences to help with the search

In [8]:
eps = 1e-6

Now we can compute the event intervals when the bodies are visible from New Norcia

In [9]:
moon_visible = events.generateEventIntervalSet( moonElev, eps, grid, xtol )
print(moon_visible)
2018-06-05T15:12:45.261350 TAI  -6.275335366e-15 +++ {} - 2018-06-06T04:25:25.903861 TAI  -1.223915366e-13 +++ {}
2018-06-06T16:07:16.772555 TAI   1.498038444e-13 +++ {} - 2018-06-07T04:59:37.560494 TAI   1.214002346e-13 +++ {}
2018-06-07T17:02:51.884194 TAI  -1.673542069e-13 +++ {} - 2018-06-08T05:33:23.571110 TAI  -6.997985242e-15 +++ {}
2018-06-08T18:00:01.610420 TAI   1.782716324e-13 +++ {} - 2018-06-09T06:07:49.648439 TAI  -4.299120266e-15 +++ {}
2018-06-09T18:59:23.598767 TAI   2.849943791e-14 +++ {} - 2018-06-10T06:44:09.292930 TAI  -6.196732690e-14 +++ {}
2018-06-10T20:01:30.222833 TAI   4.494861205e-14 +++ {} - 2018-06-11T07:23:44.335835 TAI  -4.799728481e-14 +++ {}
2018-06-11T21:06:29.875503 TAI   3.224203514e-14 +++ {} - 2018-06-12T08:08:00.925409 TAI   1.117429748e-13 +++ {}
2018-06-12T22:13:42.285018 TAI  -8.265896783e-14 +++ {} - 2018-06-13T08:58:14.685427 TAI   2.994068482e-14 +++ {}
2018-06-13T23:21:20.062236 TAI   1.731037573e-13 +++ {} - 2018-06-14T09:55:00.536755 TAI   1.628140721e-13 +++ {}


In [10]:
sun_visible = events.generateEventIntervalSet( sunElev, eps, grid, xtol )
print(sun_visible)
2018-06-05T23:12:33.275527 TAI   3.598863358e-14 +++ {} - 2018-06-06T09:16:16.658122 TAI   1.227995443e-14 +++ {}
2018-06-06T23:13:02.092672 TAI  -1.584284681e-14 +++ {} - 2018-06-07T09:16:10.383827 TAI   6.419799428e-14 +++ {}
2018-06-07T23:13:30.086761 TAI   2.150099238e-14 +++ {} - 2018-06-08T09:16:05.552351 TAI  -1.432024730e-14 +++ {}
2018-06-08T23:13:57.225849 TAI   2.777742874e-14 +++ {} - 2018-06-09T09:16:02.154978 TAI   5.112896235e-14 +++ {}
2018-06-09T23:14:23.477487 TAI  -2.756480074e-14 +++ {} - 2018-06-10T09:16:00.180843 TAI   2.992959319e-14 +++ {}
2018-06-10T23:14:48.808625 TAI  -2.300069396e-14 +++ {} - 2018-06-11T09:15:59.616686 TAI   3.090608903e-14 +++ {}
2018-06-11T23:15:13.185500 TAI  -4.757168349e-14 +++ {} - 2018-06-12T09:16:00.446707 TAI   1.888566787e-14 +++ {}
2018-06-12T23:15:36.573558 TAI  -3.540527513e-14 +++ {} - 2018-06-13T09:16:02.652592 TAI   3.168199622e-14 +++ {}
2018-06-13T23:15:58.937487 TAI  -3.402970712e-14 +++ {} - 2018-06-14T09:16:06.213867 TAI  -9.793308045e-16 +++ {}


Suppose we were astronomers and wanted to view Mars from a telescope. To plan our observations we want to find the times when our target (say, Mars) is visible but the Sun and Moon are below the horizon. This is easy.

First compute the visibility periods for Mars:

In [11]:
def marsElev( epo ):
    x = uni.frames.vector3('New_Norcia', 'MarsBarycenter', 'New_Norcia', epo)
    return astro.sphericalFromCart(x)[2]

mars_visible = events.generateEventIntervalSet( marsElev, eps, grid, xtol )
print(mars_visible)
2018-06-05T14:00:37.000000 TAI   1.966520217e-01 +++ {} - 2018-06-06T02:53:07.474875 TAI  -3.859229612e-14 +++ {}
2018-06-06T13:01:02.482549 TAI  -2.533744620e-14 +++ {} - 2018-06-07T02:50:13.844144 TAI  -2.106413113e-14 +++ {}
2018-06-07T12:58:05.847373 TAI   2.852732079e-14 +++ {} - 2018-06-08T02:47:18.333909 TAI  -2.059237081e-14 +++ {}
2018-06-08T12:55:06.321604 TAI   4.220996794e-14 +++ {} - 2018-06-09T02:44:20.904608 TAI   8.229181786e-15 +++ {}
2018-06-09T12:52:03.839259 TAI   4.659333705e-14 +++ {} - 2018-06-10T02:41:21.516774 TAI  -2.145031196e-14 +++ {}
2018-06-10T12:48:58.335782 TAI  -2.538290256e-14 +++ {} - 2018-06-11T02:38:20.131666 TAI  -3.407455031e-14 +++ {}
2018-06-11T12:45:49.748840 TAI  -2.684502396e-14 +++ {} - 2018-06-12T02:35:16.712009 TAI  -2.247157409e-14 +++ {}
2018-06-12T12:42:38.019215 TAI  -1.179110441e-14 +++ {} - 2018-06-13T02:32:11.222719 TAI  -2.155654267e-14 +++ {}
2018-06-13T12:39:23.091673 TAI  -4.848461807e-14 +++ {} - 2018-06-14T02:29:03.631376 TAI  -2.080583394e-14 +++ {}
2018-06-14T12:36:04.915640 TAI   7.801150004e-14 +++ {} - 2018-06-14T14:00:37.000000 TAI   2.961441255e-01 +++ {}


We can combine event interval sets to find the times when at least one of the confitions are true:

In [12]:
sun_or_moon_visible = events.merge( [ sun_visible , moon_visible ])
print(sun_or_moon_visible)
2018-06-05T15:12:45.261350 TAI  -6.275335366e-15 +++ {} - 2018-06-06T09:16:16.658122 TAI   1.227995443e-14 +++ {}
2018-06-06T16:07:16.772555 TAI   1.498038444e-13 +++ {} - 2018-06-07T09:16:10.383827 TAI   6.419799428e-14 +++ {}
2018-06-07T17:02:51.884194 TAI  -1.673542069e-13 +++ {} - 2018-06-08T09:16:05.552351 TAI  -1.432024730e-14 +++ {}
2018-06-08T18:00:01.610420 TAI   1.782716324e-13 +++ {} - 2018-06-09T09:16:02.154978 TAI   5.112896235e-14 +++ {}
2018-06-09T18:59:23.598767 TAI   2.849943791e-14 +++ {} - 2018-06-10T09:16:00.180843 TAI   2.992959319e-14 +++ {}
2018-06-10T20:01:30.222833 TAI   4.494861205e-14 +++ {} - 2018-06-11T09:15:59.616686 TAI   3.090608903e-14 +++ {}
2018-06-11T21:06:29.875503 TAI   3.224203514e-14 +++ {} - 2018-06-12T09:16:00.446707 TAI   1.888566787e-14 +++ {}
2018-06-12T22:13:42.285018 TAI  -8.265896783e-14 +++ {} - 2018-06-13T09:16:02.652592 TAI   3.168199622e-14 +++ {}
2018-06-13T23:15:58.937487 TAI  -3.402970712e-14 +++ {} - 2018-06-14T09:55:00.536755 TAI   1.628140721e-13 +++ {}


/local/scratch/gvarga/godottut/env/lib64/python3.6/site-packages/ipykernel_launcher.py:1: DeprecationWarning: The merge(list()) function is deprecated and it will be soon removed, please use the "any" function instead
  """Entry point for launching an IPython kernel.

Or when all the conditions are true:

In [13]:
sun_and_moon_visible = events.overlap( [ sun_visible , moon_visible ])
print(sun_and_moon_visible)
2018-06-05T23:12:33.275527 TAI   3.598863358e-14 +++ {} - 2018-06-06T04:25:25.903861 TAI  -1.223915366e-13 +++ {}
2018-06-06T23:13:02.092672 TAI  -1.584284681e-14 +++ {} - 2018-06-07T04:59:37.560494 TAI   1.214002346e-13 +++ {}
2018-06-07T23:13:30.086761 TAI   2.150099238e-14 +++ {} - 2018-06-08T05:33:23.571110 TAI  -6.997985242e-15 +++ {}
2018-06-08T23:13:57.225849 TAI   2.777742874e-14 +++ {} - 2018-06-09T06:07:49.648439 TAI  -4.299120266e-15 +++ {}
2018-06-09T23:14:23.477487 TAI  -2.756480074e-14 +++ {} - 2018-06-10T06:44:09.292930 TAI  -6.196732690e-14 +++ {}
2018-06-10T23:14:48.808625 TAI  -2.300069396e-14 +++ {} - 2018-06-11T07:23:44.335835 TAI  -4.799728481e-14 +++ {}
2018-06-11T23:15:13.185500 TAI  -4.757168349e-14 +++ {} - 2018-06-12T08:08:00.925409 TAI   1.117429748e-13 +++ {}
2018-06-12T23:15:36.573558 TAI  -3.540527513e-14 +++ {} - 2018-06-13T08:58:14.685427 TAI   2.994068482e-14 +++ {}
2018-06-13T23:21:20.062236 TAI   1.731037573e-13 +++ {} - 2018-06-14T09:16:06.213867 TAI  -9.793308045e-16 +++ {}


/local/scratch/gvarga/godottut/env/lib64/python3.6/site-packages/ipykernel_launcher.py:1: DeprecationWarning: The overlap(list()) function is deprecated and it will be soon removed, please use the "all" function instead
  """Entry point for launching an IPython kernel.

We can also take the complement. Now we want to find the times when the Sun and Moon are not visible

In [14]:
no_sun_or_moon_visible = sun_or_moon_visible.complement()
print(sun_or_moon_visible)
2018-06-05T15:12:45.261350 TAI  -6.275335366e-15 +++ {} - 2018-06-06T09:16:16.658122 TAI   1.227995443e-14 +++ {}
2018-06-06T16:07:16.772555 TAI   1.498038444e-13 +++ {} - 2018-06-07T09:16:10.383827 TAI   6.419799428e-14 +++ {}
2018-06-07T17:02:51.884194 TAI  -1.673542069e-13 +++ {} - 2018-06-08T09:16:05.552351 TAI  -1.432024730e-14 +++ {}
2018-06-08T18:00:01.610420 TAI   1.782716324e-13 +++ {} - 2018-06-09T09:16:02.154978 TAI   5.112896235e-14 +++ {}
2018-06-09T18:59:23.598767 TAI   2.849943791e-14 +++ {} - 2018-06-10T09:16:00.180843 TAI   2.992959319e-14 +++ {}
2018-06-10T20:01:30.222833 TAI   4.494861205e-14 +++ {} - 2018-06-11T09:15:59.616686 TAI   3.090608903e-14 +++ {}
2018-06-11T21:06:29.875503 TAI   3.224203514e-14 +++ {} - 2018-06-12T09:16:00.446707 TAI   1.888566787e-14 +++ {}
2018-06-12T22:13:42.285018 TAI  -8.265896783e-14 +++ {} - 2018-06-13T09:16:02.652592 TAI   3.168199622e-14 +++ {}
2018-06-13T23:15:58.937487 TAI  -3.402970712e-14 +++ {} - 2018-06-14T09:55:00.536755 TAI   1.628140721e-13 +++ {}


and find the overlap of that with the Mars visibility times.

In [15]:
mars_visible_without_sun_and_moon = events.overlap( [ no_sun_or_moon_visible , mars_visible ])
print("Mars Visible without Sun and Moon:")
print(mars_visible_without_sun_and_moon)
Mars Visible without Sun and Moon:
2018-06-05T14:00:37.000000 TAI  -1.031662988e+00 +++ {} - 2018-06-05T15:12:45.261350 TAI  -6.275335366e-15 +++ {}
2018-06-06T13:01:02.482549 TAI  -2.533744620e-14 +++ {} - 2018-06-06T16:07:16.772555 TAI   1.498038444e-13 +++ {}
2018-06-07T12:58:05.847373 TAI   2.852732079e-14 +++ {} - 2018-06-07T17:02:51.884194 TAI  -1.673542069e-13 +++ {}
2018-06-08T12:55:06.321604 TAI   4.220996794e-14 +++ {} - 2018-06-08T18:00:01.610420 TAI   1.782716324e-13 +++ {}
2018-06-09T12:52:03.839259 TAI   4.659333705e-14 +++ {} - 2018-06-09T18:59:23.598767 TAI   2.849943791e-14 +++ {}
2018-06-10T12:48:58.335782 TAI  -2.538290256e-14 +++ {} - 2018-06-10T20:01:30.222833 TAI   4.494861205e-14 +++ {}
2018-06-11T12:45:49.748840 TAI  -2.684502396e-14 +++ {} - 2018-06-11T21:06:29.875503 TAI   3.224203514e-14 +++ {}
2018-06-12T12:42:38.019215 TAI  -1.179110441e-14 +++ {} - 2018-06-12T22:13:42.285018 TAI  -8.265896783e-14 +++ {}
2018-06-13T12:39:23.091673 TAI  -4.848461807e-14 +++ {} - 2018-06-13T23:15:58.937487 TAI  -3.402970712e-14 +++ {}
2018-06-14T12:36:04.915640 TAI   7.801150004e-14 +++ {} - 2018-06-14T14:00:37.000000 TAI  -1.029701885e+00 +++ {}


/local/scratch/gvarga/godottut/env/lib64/python3.6/site-packages/ipykernel_launcher.py:1: DeprecationWarning: The overlap(list()) function is deprecated and it will be soon removed, please use the "all" function instead
  """Entry point for launching an IPython kernel.

Of course the whole computation could be made more complex quite easily. Suppose you had a Mars orbiter and wanted to ensure it was visible from New Norcia, or you wanted to compute times when you though Mars was goind to be hit by an Asteroid, or you wanted to observe Phobos or Deimos. All of these computations could be done in the same way and combined with each other to find the interval you wanted.

In [ ]: