diff --git a/astroplan/plots/time_dependent.py b/astroplan/plots/time_dependent.py index 710c30cf..84280404 100644 --- a/astroplan/plots/time_dependent.py +++ b/astroplan/plots/time_dependent.py @@ -243,7 +243,7 @@ def plot_schedule_airmass(schedule, show_night=False): targ_to_color = {} color_idx = np.linspace(0, 1, len(targets)) # lighter, bluer colors indicate higher priority - for target, ci in zip(targets, color_idx): + for target, ci in zip(set(targets), color_idx): plot_airmass(target, schedule.observer, ts, style_kwargs=dict(color=plt.cm.cool(ci))) targ_to_color[target.name] = plt.cm.cool(ci) if show_night: @@ -267,7 +267,8 @@ def plot_schedule_airmass(schedule, show_night=False): fc=targ_to_color[block.target.name], lw=0, alpha=.6) else: plt.axvspan(block.start_time.plot_date, block.end_time.plot_date, - color='k', lw=0, alpha=.6) + color='k') + plt.axhline(3, color='k', label='Transitions') # TODO: make this output a `axes` object diff --git a/astroplan/scheduling.py b/astroplan/scheduling.py index 3de25705..35e55c49 100644 --- a/astroplan/scheduling.py +++ b/astroplan/scheduling.py @@ -15,6 +15,7 @@ from astropy.table import Table from .utils import time_grid_from_range, stride_array +from .constraints import AltitudeConstraint __all__ = ['ObservingBlock', 'TransitionBlock', 'Schedule', 'Slot', 'Scheduler', 'SequentialScheduler', 'PriorityScheduler', 'Transitioner', 'Scorer'] @@ -166,10 +167,10 @@ def __init__(self, components, start_time=None): start_time : `~astropy.units.Quantity` Start time of observation """ + self._components = None self.duration = None self.start_time = start_time self.components = components - self._components = None def __repr__(self): orig_repr = object.__repr__(self) @@ -203,8 +204,7 @@ def components(self, val): def from_duration(cls, duration): # for testing how to put transitions between observations during # scheduling without considering the complexities of duration - tb = TransitionBlock({None: 0*u.second}) - tb.duration = duration + tb = TransitionBlock({'duration': duration}) return tb @@ -232,14 +232,12 @@ def __init__(self, start_time, end_time, constraints=None): self.start_time = start_time self.end_time = end_time self.slots = [Slot(start_time, end_time)] - self.slew_duration = 4*u.min - # TODO: replace/overwrite slew_duration with Transitioner calls self.observer = None def __repr__(self): - return 'Schedule containing ' + str(len(self.observing_blocks)) + \ - ' observing blocks between ' + str(self.slots[0].start.iso) + \ - ' and ' + str(self.slots[-1].end.iso) + return ('Schedule containing ' + str(len(self.observing_blocks)) + + ' observing blocks between ' + str(self.slots[0].start.iso) + + ' and ' + str(self.slots[-1].end.iso)) @property def observing_blocks(self): @@ -261,6 +259,7 @@ def to_table(self, show_transitions=True, show_unused=False): durations = [] ra = [] dec = [] + config = [] for slot in self.slots: if hasattr(slot.block, 'target'): start_times.append(slot.start.iso) @@ -269,6 +268,7 @@ def to_table(self, show_transitions=True, show_unused=False): target_names.append(slot.block.target.name) ra.append(slot.block.target.ra) dec.append(slot.block.target.dec) + config.append(slot.block.configuration) elif show_transitions and slot.block: start_times.append(slot.start.iso) end_times.append(slot.end.iso) @@ -276,6 +276,9 @@ def to_table(self, show_transitions=True, show_unused=False): target_names.append('TransitionBlock') ra.append('') dec.append('') + changes = list(slot.block.components.keys()) + changes.remove('slew_time') + config.append(changes) elif slot.block is None and show_unused: start_times.append(slot.start.iso) end_times.append(slot.end.iso) @@ -283,9 +286,10 @@ def to_table(self, show_transitions=True, show_unused=False): target_names.append('Unused Time') ra.append('') dec.append('') - return Table([target_names, start_times, end_times, durations, ra, dec], + config.append('') + return Table([target_names, start_times, end_times, durations, ra, dec, config], names=('target', 'start time (UTC)', 'end time (UTC)', - 'duration (minutes)', 'ra', 'dec')) + 'duration (minutes)', 'ra', 'dec', 'configuration')) def new_slots(self, slot_index, start_time, end_time): # this is intended to be used such that there aren't consecutive unoccupied slots @@ -296,8 +300,8 @@ def insert_slot(self, start_time, block): # due to float representation, this will change block start time # and duration by up to 1 second in order to fit in a slot for j, slot in enumerate(self.slots): - if (slot.start < start_time or np.abs(slot.start-start_time) < 1*u.second) \ - and (slot.end > start_time): + if ((slot.start < start_time or abs(slot.start-start_time) < 1*u.second) + and (slot.end > start_time + 1*u.second)): slot_index = j if (block.duration - self.slots[slot_index].duration) > 1*u.second: print(self.slots[slot_index].duration.to(u.second), block.duration) @@ -305,14 +309,14 @@ def insert_slot(self, start_time, block): elif self.slots[slot_index].end - block.duration < start_time: start_time = self.slots[slot_index].end - block.duration - if np.abs((self.slots[slot_index].duration - block.duration) < 1 * u.second): + if abs((self.slots[slot_index].duration - block.duration) < 1 * u.second): block.duration = self.slots[slot_index].duration start_time = self.slots[slot_index].start end_time = self.slots[slot_index].end - elif np.abs(self.slots[slot_index].start - start_time) < 1*u.second: + elif abs(self.slots[slot_index].start - start_time) < 1*u.second: start_time = self.slots[slot_index].start end_time = start_time + block.duration - elif np.abs(self.slots[slot_index].end - start_time - block.duration) < 1*u.second: + elif abs(self.slots[slot_index].end - start_time - block.duration) < 1*u.second: end_time = self.slots[slot_index].end else: end_time = start_time + block.duration @@ -443,6 +447,7 @@ def __call__(self, blocks, schedule): objects with populated ``start_time`` and ``end_time`` or ``duration`` attributes """ self.schedule = schedule + self.schedule.observer = self.observer # these are *shallow* copies copied_blocks = [copy.copy(block) for block in blocks] schedule = self._make_schedule(copied_blocks) @@ -507,6 +512,12 @@ def _make_schedule(self, blocks): b._all_constraints = self.constraints else: b._all_constraints = self.constraints + b.constraints + # to make sure the scheduler has some constraint to work off of + # and to prevent scheduling of targets below the horizon + if b._all_constraints is None: + b._all_constraints = [AltitudeConstraint(min=0*u.deg)] + elif not any(isinstance(c, AltitudeConstraint) for c in b._all_constraints): + b._all_constraints.append(AltitudeConstraint(min=0*u.deg)) b._duration_offsets = u.Quantity([0*u.second, b.duration/2, b.duration]) b.observer = self.observer @@ -583,6 +594,12 @@ def _make_schedule(self, blocks): b._all_constraints = self.constraints else: b._all_constraints = self.constraints + b.constraints + # to make sure the scheduler has some constraint to work off of + # and to prevent scheduling of targets below the horizon + if b._all_constraints is None: + b._all_constraints = [AltitudeConstraint(min=0*u.deg)] + elif not any(isinstance(c, AltitudeConstraint) for c in b._all_constraints): + b._all_constraints.append(AltitudeConstraint(min=0*u.deg)) b._duration_offsets = u.Quantity([0 * u.second, b.duration / 2, b.duration]) _block_priorities[i] = b.priority _all_times.append(b.duration) @@ -615,11 +632,21 @@ def _make_schedule(self, blocks): # And then remove any times that are already scheduled constraint_scores[is_open_time == False] = 0 # Select the most optimal time + # need to leave time around the Block for transitions + if self.transitioner.instrument_reconfig_times: + max_config_time = sum([max(value.values()) for value in + self.transitioner.instrument_reconfig_times.values()]) + else: + max_config_time = 0*u.second + if self.transitioner.slew_rate: + buffer_time = (160*u.deg/self.transitioner.slew_rate + max_config_time) + else: + buffer_time = max_config_time # TODO: make it so that this isn't required to prevent errors in slot creation - total_duration = b.duration + self.gap_time + total_duration = b.duration + buffer_time # calculate the number of time slots needed for this exposure - _stride_by = np.int(np.ceil(total_duration / time_resolution)) + _stride_by = np.int(np.ceil(float(total_duration / time_resolution))) # Stride the score arrays by that number _strided_scores = stride_array(constraint_scores, _stride_by) @@ -644,10 +671,11 @@ def _make_schedule(self, blocks): if _is_scheduled: # set duration such that the Block will fit in the strided array - duration_indices = np.int(np.ceil(b.duration / time_resolution)) + duration_indices = np.int(np.ceil(float(b.duration / time_resolution))) b.duration = duration_indices * time_resolution + # add 1 second to the start time to allow for scheduling at the start of a slot slot_index = [q for q, slot in enumerate(self.schedule.slots) - if slot.start < new_start_time < slot.end][0] + if slot.start < new_start_time + 1*u.second < slot.end][0] slots_before = self.schedule.slots[:slot_index] slots_after = self.schedule.slots[slot_index + 1:] # this has to remake transitions between already existing ObservingBlocks @@ -656,14 +684,14 @@ def _make_schedule(self, blocks): # make a transition object after the previous ObservingBlock tb = self.transitioner(self.schedule.slots[slot_index - 1].block, b, self.schedule.slots[slot_index - 1].end, self.observer) - times_indices = np.int(np.ceil(tb.duration / time_resolution)) + times_indices = np.int(np.ceil(float(tb.duration / time_resolution))) tb.duration = times_indices * time_resolution start_idx = self.schedule.slots[slot_index - 1].block.end_idx end_idx = times_indices + start_idx # this may make some OBs get sub-optimal scheduling, but it closes gaps # TODO: determine a reasonable range inside which it gets shifted if (new_start_time - tb.start_time < tb.duration or - np.abs(new_start_time - tb.end_time) < self.gap_time): + abs(new_start_time - tb.end_time) < self.gap_time): new_start_time = tb.end_time start_time_idx = end_idx self.schedule.insert_slot(tb.start_time, tb) @@ -674,13 +702,13 @@ def _make_schedule(self, blocks): # change the existing TransitionBlock to what it needs to be now tb = self.transitioner(self.schedule.slots[slot_index - 2].block, b, self.schedule.slots[slot_index - 2].end, self.observer) - times_indices = np.int(np.ceil(tb.duration / time_resolution)) + times_indices = np.int(np.ceil(float(tb.duration / time_resolution))) tb.duration = times_indices * time_resolution start_idx = self.schedule.slots[slot_index - 2].block.end_idx end_idx = times_indices + start_idx self.schedule.change_slot_block(slot_index - 1, new_block=tb) if (new_start_time - tb.start_time < tb.duration or - np.abs(new_start_time - tb.end_time) < self.gap_time): + abs(new_start_time - tb.end_time) < self.gap_time): new_start_time = tb.end_time start_time_idx = end_idx is_open_time[start_idx: end_idx] = False @@ -691,7 +719,7 @@ def _make_schedule(self, blocks): # make a transition object after the new ObservingBlock tb = self.transitioner(b, self.schedule.slots[slot_index + 1].block, new_start_time + b.duration, self.observer) - times_indices = np.int(np.ceil(tb.duration / time_resolution)) + times_indices = np.int(np.ceil(float(tb.duration / time_resolution))) tb.duration = times_indices * time_resolution self.schedule.insert_slot(tb.start_time, tb) start_idx = end_time_idx @@ -729,7 +757,8 @@ def __init__(self, slew_rate=None, instrument_reconfig_times=None): If not None, gives a mapping from property names to another dictionary. The second dictionary maps 2-tuples of states to the time it takes to transition between those states (as an - `~astropy.units.Quantity`). + `~astropy.units.Quantity`), can also take a 'default' key + mapped to a default transition time. """ self.slew_rate = slew_rate self.instrument_reconfig_times = instrument_reconfig_times @@ -776,19 +805,25 @@ def __call__(self, oldblock, newblock, start_time, observer): if components: return TransitionBlock(components, start_time) else: - return None + return TransitionBlock.from_duration(0*u.second) def compute_instrument_transitions(self, oldblock, newblock): components = {} for conf_name, old_conf in oldblock.configuration.items(): - if conf_name in newblock: + if conf_name in newblock.configuration: conf_times = self.instrument_reconfig_times.get(conf_name, None) if conf_times is not None: - new_conf = newblock[conf_name] + new_conf = newblock.configuration[conf_name] ctime = conf_times.get((old_conf, new_conf), None) + def_time = conf_times.get('default', None) if ctime is not None: s = '{0}:{1} to {2}'.format(conf_name, old_conf, new_conf) components[s] = ctime + elif def_time and not old_conf == new_conf: + s = '{0}:{1} to {2}'.format(conf_name, old_conf, + new_conf) + components[s] = def_time + return components diff --git a/astroplan/target.py b/astroplan/target.py index 8d799eec..b45af735 100644 --- a/astroplan/target.py +++ b/astroplan/target.py @@ -162,6 +162,8 @@ def _from_name_mock(cls, query_name, name=None): "vega": {"ra": 279.23473479*u.deg, "dec": 38.78368896*u.deg}, "aldebaran": {"ra": 68.98016279*u.deg, "dec": 16.50930235*u.deg}, "polaris": {"ra": 37.95456067*u.deg, "dec": 89.26410897*u.deg}, + "deneb": {"ra": 310.35797975*u.deg, "dec": 45.28033881*u.deg}, + "m13": {"ra": 250.423475*u.deg, "dec": 36.4613194*u.deg}, "altair": {"ra": 297.6958273*u.deg, "dec": 8.8683212*u.deg} } diff --git a/astroplan/tests/test_scheduling.py b/astroplan/tests/test_scheduling.py index c1d73bcf..7aaafc5e 100644 --- a/astroplan/tests/test_scheduling.py +++ b/astroplan/tests/test_scheduling.py @@ -10,7 +10,8 @@ from ..utils import time_grid_from_range from ..observer import Observer from ..target import FixedTarget -from ..constraints import (AirmassConstraint, _get_altaz) +from ..constraints import (AirmassConstraint, AtNightConstraint, _get_altaz, + MoonIlluminationConstraint) from ..scheduling import (ObservingBlock, PriorityScheduler, SequentialScheduler, Transitioner, TransitionBlock, Schedule, Slot, Scorer) @@ -22,73 +23,207 @@ dec=89.26410897 * u.deg), name="Polaris") apo = Observer.at_site('apo') -targets = [vega, rigel, polaris] +targets = [vega, polaris, rigel] +default_time = Time('2016-02-06 03:00:00') +only_at_night = [AtNightConstraint()] + + +def test_observing_block(): + block = ObservingBlock(rigel, 1*u.minute, 0, configuration={'filter': 'b'}) + assert(block.configuration['filter'] == 'b') + assert(block.target == rigel) + times_per_exposure = [1*u.minute, 4*u.minute, 15*u.minute, 5*u.minute] + numbers_of_exposures = [100, 4, 3, 12] + readout_time = 0.5*u.minute + for index in range(len(times_per_exposure)): + block = ObservingBlock.from_exposures(vega, 0, times_per_exposure[index], + numbers_of_exposures[index], readout_time) + assert(block.duration == numbers_of_exposures[index] * + (times_per_exposure[index] + readout_time)) + + +def test_slot(): + start_time = Time('2016-02-06 03:00:00') + end_time = start_time + 24 * u.hour + slot = Slot(start_time, end_time) + slots = slot.split_slot(start_time, start_time+1*u.hour) + assert len(slots) == 2 + assert slots[0].end == slots[1].start + + +def test_schedule(): + start_time = Time('2016-02-06 03:00:00') + end_time = start_time + 24 * u.hour + schedule = Schedule(start_time, end_time) + assert schedule.slots[0].start == start_time + assert schedule.slots[0].end == end_time + assert schedule.slots[0].duration == 24*u.hour + schedule.new_slots(0, start_time, end_time) + assert len(schedule.slots) == 1 + new_slots = schedule.new_slots(0, start_time+1*u.hour, start_time+4*u.hour) + assert np.abs(new_slots[0].duration - 1*u.hour) < 1*u.second + assert np.abs(new_slots[1].duration - 3*u.hour) < 1*u.second + assert np.abs(new_slots[2].duration - 20*u.hour) < 1*u.second + + +def test_schedule_insert_slot(): + start = Time('2016-02-06 03:00:00') + schedule = Schedule(start, start + 5*u.hour) + # testing for when float comparison doesn't work, does it start/end at the right time + duration = 2*u.hour + 1*u.second + end_time = start + duration + block = TransitionBlock.from_duration(duration) + schedule.insert_slot(end_time - duration, block) + assert not end_time - duration == start + assert len(schedule.slots) == 2 + assert schedule.slots[0].start == start + schedule = Schedule(start, start + 5*u.hour) + # testing for when float evaluation does work + duration = 2*u.hour + end_time = start + duration + block = TransitionBlock.from_duration(duration) + schedule.insert_slot(end_time - duration, block) + assert end_time - duration == start + assert len(schedule.slots) == 2 + assert schedule.slots[0].start == start + + +def test_schedule_change_slot_block(): + start = Time('2016-02-06 03:00:00') + schedule = Schedule(start, start + 5 * u.hour) + duration = 2 * u.hour + block = TransitionBlock.from_duration(duration) + schedule.insert_slot(start, block) + # check that it has the correct duration + assert np.abs(schedule.slots[0].end - duration - start) < 1*u.second + new_duration = 1*u.minute + new_block = TransitionBlock.from_duration(new_duration) + schedule.change_slot_block(0, new_block) + # check the duration changed properly, and slots are still consecutive/don't overlap + assert np.abs(schedule.slots[0].end - new_duration - start) < 1*u.second + assert schedule.slots[1].start == schedule.slots[0].end def test_transitioner(): blocks = [ObservingBlock(t, 55 * u.minute, i) for i, t in enumerate(targets)] slew_rate = 1 * u.deg / u.second trans = Transitioner(slew_rate=slew_rate) - start_time = Time('2016-02-06 00:00:00') - transition = trans(blocks[0], blocks[1], start_time, apo) + start_time = Time('2016-02-06 03:00:00') + transition = trans(blocks[0], blocks[2], start_time, apo) aaz = _get_altaz(Time([start_time]), apo, - [blocks[0].target, blocks[1].target])['altaz'] + [blocks[0].target, blocks[2].target])['altaz'] sep = aaz[0].separation(aaz[1])[0] assert isinstance(transition, TransitionBlock) assert transition.duration == sep/slew_rate -transitioner = Transitioner(slew_rate=1 * u.deg / u.second) + blocks = [ObservingBlock(vega, 10*u.minute, 0, configuration={'filter': 'v'}), + ObservingBlock(vega, 10*u.minute, 0, configuration={'filter': 'i'}), + ObservingBlock(rigel, 10*u.minute, 0, configuration={'filter': 'i'})] + trans = Transitioner(slew_rate, instrument_reconfig_times={'filter': {('v', 'i'): 2*u.minute, + 'default': 5*u.minute}}) + transition1 = trans(blocks[0], blocks[1], start_time, apo) + transition2 = trans(blocks[0], blocks[2], start_time, apo) + transition3 = trans(blocks[1], blocks[0], start_time, apo) + assert np.abs(transition1.duration - 2*u.minute) < 1*u.second + assert np.abs(transition2.duration - 2*u.minute - transition.duration) < 1*u.second + # to test the default transition + assert np.abs(transition3.duration - 5*u.minute) < 1*u.second + assert transition1.components is not None + +default_transitioner = Transitioner(slew_rate=1 * u.deg / u.second) def test_priority_scheduler(): constraints = [AirmassConstraint(3, boolean_constraint=False)] blocks = [ObservingBlock(t, 55*u.minute, i) for i, t in enumerate(targets)] - start_time = Time('2016-02-06 00:00:00') - end_time = start_time + 24*u.hour - scheduler = PriorityScheduler(transitioner=transitioner, - constraints=constraints, observer=apo) + start_time = Time('2016-02-06 03:00:00') + end_time = start_time + 18*u.hour + scheduler = PriorityScheduler(transitioner=default_transitioner, + constraints=constraints, observer=apo, + time_resolution=2*u.minute) schedule = Schedule(start_time, end_time) scheduler(blocks, schedule) assert len(schedule.observing_blocks) == 3 assert all(np.abs(block.end_time - block.start_time - block.duration) < 1*u.second for block in schedule.scheduled_blocks) + assert all([schedule.observing_blocks[0].target == polaris, + schedule.observing_blocks[1].target == rigel, + schedule.observing_blocks[2].target == vega]) + # polaris and rigel both peak just before the start time + assert schedule.slots[0].block.target == polaris + assert schedule.slots[2].block.target == rigel def test_sequential_scheduler(): constraints = [AirmassConstraint(2.5, boolean_constraint=False)] blocks = [ObservingBlock(t, 55 * u.minute, i) for i, t in enumerate(targets)] - start_time = Time('2016-02-06 00:00:00') - end_time = start_time + 24 * u.hour + start_time = Time('2016-02-06 03:00:00') + end_time = start_time + 18 * u.hour scheduler = SequentialScheduler(constraints=constraints, observer=apo, - transitioner=transitioner) + transitioner=default_transitioner) schedule = Schedule(start_time, end_time) scheduler(blocks, schedule) assert len(schedule.observing_blocks) > 0 assert all(np.abs(block.end_time - block.start_time - block.duration) < 1*u.second for block in schedule.scheduled_blocks) + assert all([schedule.observing_blocks[0].target == rigel, + schedule.observing_blocks[1].target == polaris, + schedule.observing_blocks[2].target == vega]) + # vega rises late, so its start should be later + assert schedule.observing_blocks[2].start_time > start_time + 8*u.hour -def test_slot(): - start_time = Time('2016-02-06 00:00:00') - end_time = start_time + 24 * u.hour - slot = Slot(start_time, end_time) - slots = slot.split_slot(start_time, start_time+1*u.hour) - assert len(slots) == 2 - assert slots[0].end == slots[1].start +def test_scheduling_target_down(): + lco = Observer.at_site('lco') + block = [ObservingBlock(FixedTarget.from_name('polaris'), 1 * u.min, 0)] + start_time = Time('2016-02-06 03:00:00') + end_time = start_time + 3*u.day + scheduler1 = SequentialScheduler(only_at_night, lco, default_transitioner, + gap_time=2*u.hour) + schedule = Schedule(start_time, end_time) + schedule1 = scheduler1(block, schedule) + assert len(schedule1.observing_blocks) == 0 + scheduler2 = PriorityScheduler(only_at_night, lco, default_transitioner, + time_resolution=30 * u.minute) + schedule = Schedule(start_time, end_time) + schedule2 = scheduler2(block, schedule) + assert len(schedule2.observing_blocks) == 0 -def test_schedule(): - start_time = Time('2016-02-06 00:00:00') - end_time = start_time + 24 * u.hour +def test_scheduling_during_day(): + block = [ObservingBlock(FixedTarget.from_name('polaris'), 1 * u.min, 0)] + day = Time('2016-02-06 03:00:00') + start_time = apo.midnight(day) + 10*u.hour + end_time = start_time + 6*u.hour + scheduler1 = SequentialScheduler(only_at_night, apo, default_transitioner, + gap_time=30*u.minute) schedule = Schedule(start_time, end_time) - assert schedule.slots[0].start == start_time - assert schedule.slots[0].end == end_time - assert schedule.slots[0].duration == 24*u.hour - schedule.new_slots(0, start_time, end_time) - assert len(schedule.slots) == 1 - new_slots = schedule.new_slots(0, start_time+1*u.hour, start_time+4*u.hour) - assert np.abs(new_slots[0].duration - 1*u.hour) < 1*u.second - assert np.abs(new_slots[1].duration - 3*u.hour) < 1*u.second - assert np.abs(new_slots[2].duration - 20*u.hour) < 1*u.second + schedule1 = scheduler1(block, schedule) + assert len(schedule1.observing_blocks) == 0 + scheduler2 = PriorityScheduler(only_at_night, apo, default_transitioner, + time_resolution=2 * u.minute) + schedule = Schedule(start_time, end_time) + schedule2 = scheduler2(block, schedule) + assert len(schedule2.observing_blocks) == 0 +# bring this back when MoonIlluminationConstraint is working properly + + +def test_scheduling_moon_up(): + block = [ObservingBlock(FixedTarget.from_name('polaris'), 30 * u.min, 0)] + # on february 23 the moon was up between the start/end times defined below + day = Time('2016-02-23 03:00:00') + start_time = apo.midnight(day) - 2 * u.hour + end_time = start_time + 6 * u.hour + constraints = [AtNightConstraint(), MoonIlluminationConstraint(max=0)] + scheduler1 = SequentialScheduler(constraints, apo, default_transitioner, + gap_time=30*u.minute) + schedule = Schedule(start_time, end_time) + schedule1 = scheduler1(block, schedule) + assert len(schedule1.observing_blocks) == 0 + scheduler2 = PriorityScheduler(constraints, apo, default_transitioner, + time_resolution=20*u.minute) + schedule = Schedule(start_time, end_time) + schedule2 = scheduler2(block, schedule) + assert len(schedule2.observing_blocks) == 0 def test_scorer(): 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..c6e880fa --- /dev/null +++ b/docs/tutorials/scheduling.rst @@ -0,0 +1,359 @@ +.. _scheduling_tutorial: + +.. doctest-skip-all + +*************************** +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 +================ + +We want to observe Deneb and M13 in the B, V and R filters. We are scheduled +for the first half-night on July 6 2016 and want to know the order we should +schedule the targets in. + +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), +any object that is in SIMBAD can be called by an identifier. + +.. code-block:: python + + >>> from astroplan import FixedTarget + + >>> Deneb = FixedTarget.from_name('Deneb') + >>> M13 = FixedTarget.from_name('M13') + + >>> Deneb + + + >>> M13 + + +We also need to define bounds within which our blocks will be scheduled +using `~astropy.time.Time` objects. Our bounds will be from the noon +before our observation, to the noon after (19:00 UTC). Later we will +account for only being able to use the first half of the night. + +.. code-block:: python + + >>> from astropy.time import Time + + >>> noon_before = Time('2016-07-06 19:00') + >>> noon_after = Time('2016-07-07 19: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 3, 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 = 3, boolean_constraint = False), + ... AtNightConstraint.twilight_civil()] + +Now that we have constraints that we will apply to every target, we need to +create an `~astroplan.ObservingBlock` for each target+configuration +combination. An observing block needs a target, a duration, and a priority; +configuration information can also be given (i.e. filter, instrument, etc.). +For each filter we want 16 exposures per target (100 seconds for M13 and 60 +seconds for Deneb) and the instrument has a read-out time of 20 seconds. +The half night goes from 7PM local time to 1AM local time, in UTC this will +be from 2AM to 8AM, so we use `~astroplan.constraints.TimeConstraint`. + +.. code-block:: python + + >>> from astroplan import ObservingBlock + >>> from astroplan.constraints import TimeConstraint + >>> from astropy import units as u + + >>> rot = 20 * u.second + >>> blocks = [] + + >>> first_half_night = TimeConstraint(Time('2016-07-07 02:00'), Time('2016-07-07 08:00')) + >>> for priority, bandpass in enumerate(['B', 'G', 'R']): + ... # We want each filter to have separate priority (so that target + ... # and reference are both scheduled) + ... blocks.append(ObservingBlock.from_exposures(Deneb, priority, 60*u.second, 16, rot, + ... configuration = {'filter': bandpass}, + ... constraints = [first_half_night])) + ... blocks.append(ObservingBlock.from_exposures(M13, priority, 100*u.second, 16, rot, + ... configuration = {'filter': bandpass}, + ... constraints = [first_half_night])) + +.. _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':{('B','G'): 10*u.second, + ... ('G','R'): 10*u.second, + ... 'default': 30*u.second}}) + +The transitioner now knows that it takes 10 seconds to go from 'B' to 'G', +or from 'G' to 'R' 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, input our list +of blocks and the schedule to put them in. 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 + >>> from astroplan.scheduling import Schedule + + >>> seq_scheduler = SequentialScheduler(constraints = global_constraints, + ... observer = apo, + ... transitioner = transitioner) + >>> sequential_schedule = Schedule(noon_before, noon_after) + + >>> seq_scheduler(blocks, sequential_schedule) + +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). + +.. code-block:: python + + >>> from astroplan.scheduling import PriorityScheduler + + >>> prior_scheduler = PriorityScheduler(constraints = global_constraints, + ... observer = apo, + ... transitioner = transitioner) + >>> priority_schedule = Schedule(noon_before, noon_after) + + >>> prior_scheduler(blocks, priority_schedule) + +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 + + >>> priority_schedule.to_table() + target start time (UTC) end time (UTC) duration (minutes) ra dec configuration + str15 str23 str23 float64 str32 str32 object + --------------- ----------------------- ----------------------- ------------------ --------------- -------------- ----------------- + M13 2016-07-07 03:49:20.019 2016-07-07 04:21:20.019 32.0 250d25m24.51s 36d27m40.7498s {'filter': 'R'} + TransitionBlock 2016-07-07 04:21:20.019 2016-07-07 04:22:00.019 0.666666666667 ['filter:R to B'] + M13 2016-07-07 04:25:20.021 2016-07-07 04:57:20.021 32.0 250d25m24.51s 36d27m40.7498s {'filter': 'B'} + TransitionBlock 2016-07-07 04:57:20.021 2016-07-07 04:57:40.021 0.333333333333 ['filter:B to G'] + M13 2016-07-07 04:57:40.021 2016-07-07 05:29:40.021 32.0 250d25m24.51s 36d27m40.7498s {'filter': 'G'} + TransitionBlock 2016-07-07 05:29:40.021 2016-07-07 05:31:00.021 1.33333333333 ['filter:G to R'] + Deneb 2016-07-07 06:44:00.026 2016-07-07 07:05:20.026 21.3333333333 310d21m28.7271s 45d16m49.2197s {'filter': 'R'} + TransitionBlock 2016-07-07 07:05:20.026 2016-07-07 07:06:00.026 0.666666666667 ['filter:R to G'] + Deneb 2016-07-07 07:09:20.027 2016-07-07 07:30:40.027 21.3333333333 310d21m28.7271s 45d16m49.2197s {'filter': 'G'} + TransitionBlock 2016-07-07 07:30:40.027 2016-07-07 07:31:20.027 0.666666666667 ['filter:G to B'] + Deneb 2016-07-07 07:34:40.028 2016-07-07 07:56:00.028 21.3333333333 310d21m28.7271s 45d16m49.2197s {'filter': 'B'} + +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 + + >>> plt.figure(figsize = (14,6)) + >>> plot_schedule_airmass(priority_schedule) + >>> plt.legend(loc = "upper right") + >>> plt.show() + +.. plot:: + + # first import everything we will need for the scheduling + import astropy.units as u + from astropy.time import Time + from astroplan import (Observer, FixedTarget, ObservingBlock, Transitioner, PriorityScheduler, + Schedule) + from astroplan.constraints import AtNightConstraint, AirmassConstraint, TimeConstraint + from astroplan.plots import plot_schedule_airmass + import matplotlib.pyplot as plt + + # Now we define the targets, observer, start time, and end time of the schedule. + Deneb = FixedTarget.from_name('Deneb') + M13 = FixedTarget.from_name('M13') + + noon_before = Time('2016-07-06 19:00') + noon_after = Time('2016-07-07 19:00') + apo = Observer.at_site('apo') + + # Then define the constraints (global and specific) and make a list of the + # observing blocks that you want scheduled + global_constraints = [AirmassConstraint(max = 3, boolean_constraint = False), + AtNightConstraint.twilight_civil()] + rot = 20 * u.second + blocks = [] + first_half_night = TimeConstraint(Time('2016-07-07 02:00'), Time('2016-07-07 08:00')) + for priority, bandpass in enumerate(['B', 'G', 'R']): + # We want each filter to have separate priority (so that target + # and reference are both scheduled) + blocks.append(ObservingBlock.from_exposures(Deneb, priority, 60*u.second, 16, rot, + configuration = {'filter': bandpass}, + constraints = [first_half_night])) + blocks.append(ObservingBlock.from_exposures(M13, priority, 100*u.second, 16, rot, + configuration = {'filter': bandpass}, + constraints = [first_half_night])) + + # Define how the telescope transitions between the configurations defined in the + # observing blocks (target, filter, instrument, etc.). + transitioner = Transitioner(.8*u.deg/u.second, + {'filter':{('B','G'): 10*u.second, + ('G','R'): 10*u.second, + 'default': 30*u.second}}) + + # Initialize the scheduler + prior_scheduler = PriorityScheduler(constraints = global_constraints, + observer = apo, transitioner = transitioner) + # Create a schedule for the scheduler to insert the blocks into, and run the scheduler + priority_schedule = Schedule(noon_before, noon_after) + prior_scheduler(blocks, priority_schedule) + + # To get a plot of the airmass vs where the blocks were scheduled + plt.figure(figsize = (14,6)) + plot_schedule_airmass(priority_schedule) + plt.legend(loc="upper right") + plt.show() + +We want to check if there is any way that we could observe Alpha +Centauri A as well during our time slot. So we create a new block +for it with priority over the others, add it to our list of blocks +and run the priority scheduler again. + +.. code-block:: python + + >>> alf_cent = FixedTarget.from_name('Alpha Centauri A') + >>> blocks.append(ObservingBlock(alf_cent, 20*u.minute, -1)) + >>> schedule = Schedule(start_time, end_time) + >>> prior_scheduler(blocks, schedule) + + >>> plt.figure(figsize = (14,6)) + >>> plot_schedule_airmass(priority_schedule) + >>> plt.legend(loc = "upper right") + >>> plt.show() + +.. plot:: + + # first import everything we will need for the scheduling + import astropy.units as u + from astropy.time import Time + from astroplan import (Observer, FixedTarget, ObservingBlock, Transitioner, PriorityScheduler, + Schedule) + from astroplan.constraints import AtNightConstraint, AirmassConstraint, TimeConstraint + from astroplan.plots import plot_schedule_airmass + import matplotlib.pyplot as plt + + # Now we define the targets, observer, start time, and end time of the schedule. + Deneb = FixedTarget.from_name('Deneb') + M13 = FixedTarget.from_name('M13') + + noon_before = Time('2016-07-06 19:00') + noon_after = Time('2016-07-07 19:00') + apo = Observer.at_site('apo') + + # Then define the constraints (global and specific) and make a list of the + # observing blocks that you want scheduled + global_constraints = [AirmassConstraint(max = 3, boolean_constraint = False), + AtNightConstraint.twilight_civil()] + rot = 20 * u.second + blocks = [] + first_half_night = TimeConstraint(Time('2016-07-07 02:00'), Time('2016-07-07 08:00')) + for priority, bandpass in enumerate(['B', 'G', 'R']): + # We want each filter to have separate priority (so that target + # and reference are both scheduled) + blocks.append(ObservingBlock.from_exposures(Deneb, priority, 60*u.second, 16, rot, + configuration = {'filter': bandpass}, + constraints = [first_half_night])) + blocks.append(ObservingBlock.from_exposures(M13, priority, 100*u.second, 16, rot, + configuration = {'filter': bandpass}, + constraints = [first_half_night])) + # add the new target's block + alf_cent = FixedTarget.from_name('Alpha Centauri A') + blocks.append(ObservingBlock(alf_cent, 20*u.minute, -1)) + + # Define how the telescope transitions between the configurations defined in the + # observing blocks (target, filter, instrument, etc.). + transitioner = Transitioner(.8*u.deg/u.second, + {'filter':{('B','G'): 10*u.second, + ('G','R'): 10*u.second, + 'default': 30*u.second}}) + + # Initialize the scheduler + prior_scheduler = PriorityScheduler(constraints = global_constraints, + observer = apo, transitioner = transitioner) + # Create a schedule for the scheduler to insert the blocks into, and run the scheduler + priority_schedule = Schedule(noon_before, noon_after) + prior_scheduler(blocks, priority_schedule) + + # To get a plot of the airmass vs where the blocks were scheduled + plt.figure(figsize = (14,6)) + plot_schedule_airmass(priority_schedule) + plt.legend(loc="upper right") + plt.show() + +Nothing new shows up because Alpha Centauri isn't visible from APO. \ 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": [ - "