diff --git a/docs/faq/terminology.rst b/docs/faq/terminology.rst index a44113f1..edd6f270 100644 --- a/docs/faq/terminology.rst +++ b/docs/faq/terminology.rst @@ -1,4 +1,4 @@ -.. _Observation_Terminology: +.. _terminology: *********** Terminology diff --git a/docs/tutorials/constraints.rst b/docs/tutorials/constraints.rst index 48f4f95e..4d7fa6e9 100644 --- a/docs/tutorials/constraints.rst +++ b/docs/tutorials/constraints.rst @@ -1,5 +1,7 @@ .. doctest-skip-all +.. _constraints: + ****************************** Defining Observing Constraints ****************************** diff --git a/docs/tutorials/index.rst b/docs/tutorials/index.rst index a69971ef..6d8896e0 100644 --- a/docs/tutorials/index.rst +++ b/docs/tutorials/index.rst @@ -21,4 +21,5 @@ We currently have the following tutorials: summer_triangle plots - constraints \ No newline at end of file + constraints + scheduling \ No newline at end of file diff --git a/docs/tutorials/scheduling.rst b/docs/tutorials/scheduling.rst new file mode 100644 index 00000000..0cf361c2 --- /dev/null +++ b/docs/tutorials/scheduling.rst @@ -0,0 +1,275 @@ +.. doctest-skip-all + +.. _scheduling_tutorial: + +*************************** +Scheduling an Observing Run +*************************** + +.. note:: + + Some terms used have been defined in :ref:`Terminology `. + +Contents +======== + +* :ref:`scheduling-defining_targets` + +* :ref:`scheduling-creating_constraints_and_observing_blocks` + +* :ref:`scheduling-creating_a_transitioner` + +* :ref:`scheduling-scheduling` + +.. _scheduling-defining_targets: + +Defining Targets +================ + +Say we want to observe Vega, Arcturus, Deneb, and Polaris, as well as a few +other stars in Ursa Minor. For this we will be using the Apache Point Observatory. + +First we define our `~astroplan.Observer` object (where we are observing from): + +.. code-block:: python + + >>> from astroplan import Observer + + >>> apo = Observer.at_site('apo') + +Now we want to define our list of targets (`~astroplan.FixedTarget` objects), +Most stars can be called by an identifier, but some targets may require coordinates. + +.. code-block:: python + + >>> from astroplan import FixedTarget + + >>> targets = [FixedTarget.from_name('vega'), + >>> FixedTarget.from_name('Arcturus'), + >>> FixedTarget.from_name('Deneb'), + >>> FixedTarget.from_name('Polaris'), + >>> FixedTarget.from_name('eta umi'), + >>> FixedTarget.from_name('NLTT 42620'), + >>> FixedTarget.from_name('eps umi') + >>> ] + + >>> from astropy.coordinates import SkyCoord + + >>> coords = SkyCoord('05h28m51.016s', '89d26m59.58s') + >>> interesting_target = FixedTarget(coords, name = 'UMi target') + >>> targets.append(interesting_target) + + >>> targets + [, + , + , + , + , + , + , + ] + +We also need to define when we will be observing the targets, `~astropy.time.Time` +objects for the start and end of our observing window. Here we will take an entire +night from 8PM local time to 7AM local time, in UTC this will be from 3AM to 2PM + +.. code-block:: python + + >>> from astropy.time import Time + + >>> start_time = Time('2015-06-16 03:00') + >>> end_time = Time('2015-06-16 14:00') + +:ref:`Return to Top ` + +.. _scheduling-creating_constraints_and_observing_blocks: + +Creating Constraints and Observing Blocks +========================================= + +An in-depth tutorial on creating and using constraints can be found in +the :ref:`constraint tutorial `. + +Constraints, when evaluated, take targets and times, and give scores that +indicate how well the combination of target and time fulfill the constraint. +We want to make sure that our targets will be high in the sky while observed +and that they will be observed during the night. We don't want any object to +be observed at an airmass greater than 2.5, but we prefer a better airmass. +Usually constraints scores are boolean, but with ``boolean_constraint = False`` +the constraint will output floats instead, indicated when it is closer to ideal. + +.. code-block:: python + + >>> from astroplan.constraints import AtNightConstraint, AirmassConstraint + + >>> global_constraints = [AirmassConstraint(max = 2.5, boolean_constraint = False), + >>> AtNightConstraint()] + +Now that we have constraints that we will apply to every target, we need to +create an `~astroplan.ObservingBlock` for each target. An observing block needs +a target, a duration, and a priority; configuration information can also be +given (i.e. filter, instrument, etc.). We want all of the targets in the 'g' +filter, and also want 'r' and 'i' for our UMi target. We also want to make sure +that our observations of the UMi target occur between 10PM and 3AM local time +(5AM and 10 AM UTC).For each target we want 7 exposures (with length depending +on the target) and the instrument has a read-out time of 1 minute. + +.. code-block:: python + + >>> from astroplan import ObservingBlock + >>> from astroplan.constraints import TimeConstraint + >>> from astropy import units as u + + >>> rot = 1 * u.minute + >>> blocks = [] + >>> # first we will make the blocks for our UMi target + >>> time_constraint = TimeConstraint(start_time + 2*u.hour, end_time - 4*u.hour) + >>> for filter in ['g', 'r', 'i']: + >>> blocks.append(ObservingBlock.from_exposures(targets[-1], 0, 8*u.minute, 7, rot, + >>> configuration = {'filter': filter}, + >>> constraints = [time_constraint])) + >>> for target in targets[4:7]: + >>> blocks.append(ObservingBlock.from_exposures(target, 1, 4*u.minute, 7, rot, + >>> configuration = {'filter': 'g'})) + >>> for target in targets[:4]: + >>> blocks.append(ObservingBlock.from_exposures(target, 2, 2*u.minute, 7, rot, + >>> configuration = {'filter': 'g'})) + +.. _scheduling-creating_a_transitioner: + +Creating a Transitioner +======================= + +Now that we have observing blocks, we need to define how the telescope +transitions between them. The first parameter needed is the slew_rate +of the telescope (degrees/second) and the second is a dictionary that +tells how long it takes to transition between two configurations. You +can also give a default duration if you aren't able to give one for +each pair of configurations. + +.. code-block:: python + + >>> from astroplan.scheduling import Transitioner + + >>> transitioner = Transitioner(.8*u.deg/u.second, + >>> {'filter':{('g','i'): 10*u.second, + >>> 'default': 30*u.second}}) + +The transitioner knows that it takes 10 seconds to go from 'g' to 'i' +but has to use the default transition time of 30 seconds for any other +transition between filters. Non-transitions, like 'g' to 'g', will not +take any time though. + +.. _scheduling-scheduling: + +Scheduling +========== + +Now all we have left is to initialize the scheduler, and run it on our +list of blocks. There are currently two schedulers to chose from in +astroplan. + +The first is a sequential scheduler. It starts at the start_time and +scores each block (constraints and target) at that time and then +schedules it, it then moves to where the first observing block stops +and repeats the scoring and scheduling on the remaining blocks. + +.. code-block:: python + + >>> from astroplan.scheduling import SequentialScheduler + + >>> seq_scheduler = SequentialScheduler(start_time, end_time, + >>> constraints = global_constraints, + >>> observer = apo, + >>> transitioner = transitioner) + + >>> sequential_schedule = seq_scheduler(blocks) + +The second is a priority scheduler. It sorts the blocks by their +priority (multiple blocks with the same priority will stay in the +order they were in), then schedules them one-by-one at the best +time for that block (highest score). + + >>> from astroplan.scheduling import PriorityScheduler + + >>> prior_scheduler = PriorityScheduler(start_time, end_time, + >>> constraints = global_constraints, + >>> observer = apo, + >>> transitioner = transitioner) + + >>> priority_schedule = prior_scheduler(blocks) + +Now that you have a schedule there are a few ways of viewing it. +One way is to have it print a table where you can show, or hide, +unused time and transitions with ``show_transitions`` and +``show_unused`` (default is showing transitions and not unused). + +.. code-block:: python + + >>> sequential_schedule.to_table() + +The other way is to plot the schedule against the airmass of the +targets. + +.. code-block:: python + + >>> from astroplan.plots import plot_schedule_airmass + >>> import matplotlib.pyplot as plt + + >>> plot_schedule_airmass(priority_schedule) + >>> plt.legend(loc=0) + >>> plt.show() + +.. plot:: + + import astropy.units as u + from astropy.coordinates import SkyCoord + from astropy.time import Time + from astroplan import (Observer, FixedTarget, ObservingBlock, Transitioner, PriorityScheduler) + from astroplan.constraints import AtNightConstraint, AirmassConstraint, TimeConstraint + from astroplan.plots import plot_schedule_airmass + import matplotlib.pyplot as plt + + targets = [FixedTarget.from_name('vega'), + FixedTarget.from_name('Arcturus'), + FixedTarget.from_name('Deneb'), + FixedTarget.from_name('Polaris'), + FixedTarget.from_name('eta umi'), + FixedTarget.from_name('NLTT 42620'), + FixedTarget.from_name('eps umi')] + + coords = SkyCoord('05h28m51.016s', '89d26m59.58s') + interesting_target = FixedTarget(coords, name = 'UMi target') + targets.append(interesting_target) + + start_time = Time('2015-06-16 03:00') + end_time = Time('2015-06-16 14:00') + apo = Observer.at_site('apo') + + global_constraints = [AirmassConstraint(max = 2.5, boolean_constraint = False), + AtNightConstraint()] + rot = 1 * u.minute + blocks = [] + time_constraint = TimeConstraint(start_time + 2*u.hour, end_time - 4*u.hour) + for filter in ['g', 'r', 'i']: + blocks.append(ObservingBlock.from_exposures(targets[-1], 0, 8*u.minute, 7, rot, + configuration = {'filter': filter}, + constraints = [time_constraint])) + for target in targets[4:7]: + blocks.append(ObservingBlock.from_exposures(target, 1, 4*u.minute, 7, rot, + configuration = {'filter': 'g'})) + for target in targets[:4]: + blocks.append(ObservingBlock.from_exposures(target, 2, 2*u.minute, 7, rot, + configuration = {'filter': 'g'})) + + transitioner = Transitioner(.8*u.deg/u.second, + {'filter':{('g','i'): 10*u.second, + 'default': 30*u.second}}) + + prior_scheduler = PriorityScheduler(start_time, end_time, constraints = global_constraints, + observer = apo, transitioner = transitioner) + priority_schedule = prior_scheduler(blocks) + + plot_schedule_airmass(priority_schedule) + plt.legend(loc=0) + plt.show() \ No newline at end of file diff --git a/examples/priority_scheduling_example.ipynb b/examples/priority_scheduling_example.ipynb deleted file mode 100644 index b77ebba5..00000000 --- a/examples/priority_scheduling_example.ipynb +++ /dev/null @@ -1,320 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "import numpy as np\n", - "from matplotlib import pyplot as plt\n", - "%matplotlib inline" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "# if you have made changes to a local copy of astroplan you have changed use:\n", - "import sys\n", - "#sys.path.insert(0,'directorypath')\n", - "sys.path.insert(0,'/home/karl/Astroplan/astroplan/')" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "# import the parts of astropy and astroplan needed\n", - "from astropy import units as u\n", - "from astropy.coordinates import SkyCoord\n", - "from astropy.time import Time\n", - "import astroplan\n", - "import astroplan.constraints\n", - "from astroplan import Observer, FixedTarget, ObservingBlock\n", - "from astroplan import PriorityScheduler, Transitioner\n", - "from astroplan import plots\n", - "color_cycle = plots.mplstyles.astropy_mpl_style['axes.color_cycle']" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2016-07-28 05:12:20.757045 2016-07-30 05:12:20.757045\n" - ] - } - ], - "source": [ - "# define the start and end time of the schedule\n", - "start_time = Time.now()\n", - "end_time = start_time+48*u.hour\n", - "print(start_time,end_time)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "# define the observer (in this example we use mdm)\n", - "mdm = Observer.at_site('mdm')" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ]" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# now we create a list of the targets so that we can iterate when making their blocks\n", - "targets = [FixedTarget.from_name('Vega'),\n", - " FixedTarget.from_name('Deneb'),\n", - " FixedTarget.from_name('Arcturus'),\n", - " FixedTarget.from_name('Altair'),\n", - " FixedTarget.from_name('Aldebaran'),\n", - " FixedTarget.from_name('Sirius'),\n", - " FixedTarget.from_name('Betelgeuse'),\n", - " FixedTarget.from_name('Rigel'),\n", - " FixedTarget.from_name('Castor'),\n", - " FixedTarget.from_name('Pollux'),\n", - " FixedTarget.from_name('Polaris')\n", - " ]\n", - "targets" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "# an observing block requires a target, a duration, and a priority\n", - "# this uses .from_exposures to input exposure time, read-out time,\n", - "# and the number of exposures as the duration\n", - "etime = 5*u.min\n", - "n = 10\n", - "rot = 55*u.second\n", - "# Constraints can also be added to the ObservingBlock:\n", - "constraint = [astroplan.constraints.AtNightConstraint()]\n", - "# The scheduler needs a list of blocks:\n", - "blocks = []\n", - "for i,t in enumerate(targets):\n", - " #i is used as the priority in this case\n", - " blocks.append(ObservingBlock.from_exposures(t, i, etime, n, rot, constraints = constraint))" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "# constraints that apply to every ObservingBlock can also be given directly to the Scheduler\n", - "global_constraints = [astroplan.constraints.AirmassConstraint(3, boolean_constraint=False)]\n", - "# Soon, this should be able to handle a vector input (e.g. AirmassConstraint([3,3,3,3,2,2,3,3,3,2,2]))\n", - "\n", - "# define how long it takes the telescope to transition (e.g. 1 degree/second)\n", - "trans = Transitioner(slew_rate=1*u.deg/u.second)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false, - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "could not schedule Sirius\n", - "could not schedule Betelgeuse\n", - "could not schedule Rigel\n", - "could not schedule Castor\n", - "could not schedule Pollux\n" - ] - }, - { - "data": { - "text/html": [ - "<Table length=18>\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
idxtargetstart time (UTC)end time (UTC)duration (minutes)radec
0Unused Time2016-07-28 05:12:20.7572016-07-28 07:03:00.761110.666734355
1Deneb2016-07-28 07:03:00.7612016-07-28 08:03:00.76160.0310d21m28.7271s45d16m49.2197s
2TransitionBlock2016-07-28 08:03:00.7612016-07-28 08:04:00.7611.0
3Unused Time2016-07-28 08:04:00.7612016-07-28 11:24:00.771200.000159457
4Polaris2016-07-28 11:24:00.7712016-07-28 12:24:00.77160.037d57m16.4184s89d15m50.7923s
5TransitionBlock2016-07-28 12:24:00.7712016-07-28 12:25:20.7711.33333333333
6Unused Time2016-07-28 12:25:20.7712016-07-29 02:21:40.804836.333881761
7Arcturus2016-07-29 02:21:40.8042016-07-29 03:21:40.80460.0213d54m55.0811s19d10m56.673s
8TransitionBlock2016-07-29 03:21:40.8042016-07-29 03:22:40.8041.0
9Unused Time2016-07-29 03:22:40.8042016-07-29 04:55:00.80992.333427012
10Vega2016-07-29 04:55:00.8092016-07-29 05:55:00.80960.0279d14m05.0452s38d47m01.2802s
11TransitionBlock2016-07-29 05:55:00.8092016-07-29 05:55:40.8090.666666666667
12Unused Time2016-07-29 05:55:40.8092016-07-29 06:08:40.81213.0000450065
13Altair2016-07-29 06:08:40.8122016-07-29 07:08:40.81260.0297d41m44.9783s8d52m05.9563s
14TransitionBlock2016-07-29 07:08:40.8122016-07-29 07:11:00.8122.33333333333
15Unused Time2016-07-29 07:11:00.8122016-07-29 11:24:40.823253.666859726
16Aldebaran2016-07-29 11:24:40.8232016-07-29 12:24:40.82360.068d58m48.586s16d30m33.4885s
17Unused Time2016-07-29 12:24:40.8232016-07-30 05:12:20.7571007.66555935
\n", - "\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# The PriorityScheduler schedules the block with priority closest to 0 first\n", - "# and proceeds according to the priority.\n", - "# create the scheduler object\n", - "scheduler = PriorityScheduler(start_time, end_time,transitioner=trans,\n", - " constraints=global_constraints, observer=mdm)\n", - "# run the scheduler, this scheduler will also print unschedulable targets\n", - "schedule = scheduler(blocks)\n", - "# to print a table of the output schedule (showing unused slots):\n", - "schedule.to_table(show_unused=True).show_in_notebook()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false, - "scrolled": false - }, - "outputs": [], - "source": [ - "# We can also plot the airmass of the targets compared to when they were scheduled\n", - "plt.figure(figsize=(15,10))\n", - "# show_night makes the graphs much slower, but gives useful information if\n", - "# \"AtNight\" was a constraint.\n", - "plots.plot_schedule_airmass(schedule, \n", - " show_night=True\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "anaconda-cloud": {}, - "kernelspec": { - "display_name": "Python [Root]", - "language": "python", - "name": "Python [Root]" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.5.2" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} diff --git a/examples/s4_experiments.ipynb b/examples/s4_experiments.ipynb deleted file mode 100644 index 3b409a7b..00000000 --- a/examples/s4_experiments.ipynb +++ /dev/null @@ -1,384 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "import numpy as np\n", - "%matplotlib inline\n", - "from matplotlib import pyplot as plt" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "import sys\n", - "#replace the '/home/karl/Astroplan/astroplan' with wherever the directory is\n", - "sys.path.insert(0,'/home/karl/Astroplan/astroplan')" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "from astropy import units as u\n", - "from astropy.coordinates import SkyCoord\n", - "from astropy.time import Time\n", - "\n", - "import pytz\n", - "\n", - "import astroplan\n", - "from astroplan import Observer, FixedTarget, ObservingBlock, SequentialScheduler, Transitioner\n", - "\n", - "from astroplan import plots\n", - "color_cycle = plots.mplstyles.astropy_mpl_style['axes.color_cycle']" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - ">" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# define the observer (telscope) and timezone\n", - "pal = Observer.at_site('Palomar', timezone=pytz.timezone('US/Pacific'))\n", - "pal" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "