Exemple #1
0
def expand_cadence_request(request_dict, is_staff=False):
    '''
    Takes in a valid cadence request (valid request with cadence block), and expands the request into a list of requests
    with their windows determined by the cadence parameters. Only valid requests that pass rise-set are returned, with
    failing requests silently left out of the returned list.
    :param request_dict: a valid request dictionary with cadence information.
    :return: Expanded list of requests with valid windows within the cadence.
    '''
    cadence = request_dict['cadence']
    # now expand the request into a list of requests with the proper windows from the cadence block
    cadence_requests = []
    half_jitter = timedelta(hours=cadence['jitter'] / 2.0)
    request_duration = get_request_duration(request_dict)
    request_window_start = cadence['start']

    while request_window_start < cadence['end']:
        window_start = max(request_window_start - half_jitter, cadence['start'])
        window_end = min(request_window_start + half_jitter, cadence['end'])

        # test the rise_set of this window
        request_dict['windows'] = [{'start': window_start, 'end': window_end}]
        intervals_by_site = get_filtered_rise_set_intervals_by_site(request_dict, is_staff=is_staff)
        largest_interval = get_largest_interval(intervals_by_site)
        if largest_interval.total_seconds() > request_duration and window_end > timezone.now():
            # this cadence window passes rise_set and is in the future so add it to the list
            request_copy = request_dict.copy()
            del request_copy['cadence']
            cadence_requests.append(request_copy)

        request_window_start += timedelta(hours=cadence['period'])
    return cadence_requests
Exemple #2
0
 def _visible_targets(self, instrument_type, windows):
     '''Return a list of targets that are currently visible in the window'''
     site_details = configdb.get_sites_with_instrument_type_and_location(
         instrument_type)
     visible_targets = []
     for target in TARGET_LIST:
         intervals_by_site = {}
         for site in site_details:
             rise_set_site = get_rise_set_site(site_details[site])
             rise_set_target = get_rise_set_target(target)
             intervals_by_site[site] = []
             for window in windows:
                 visibility = get_rise_set_visibility(
                     rise_set_site, window['start'], window['end'],
                     site_details[site])
                 try:
                     intervals_by_site[site].extend(
                         visibility.get_observable_intervals(
                             rise_set_target,
                             airmass=2.0,
                             moon_distance=Angle(degrees=0.0)))
                 except MovingViolation:
                     pass
         largest_interval = get_largest_interval(intervals_by_site)
         if largest_interval > timedelta(minutes=15):
             visible_targets.append(target)
     return visible_targets
def get_request_duration_dict(request_dict, is_staff=False):
    req_durations = {'requests': []}
    for req in request_dict:
        req_info = {'duration': get_request_duration(req)}
        conf_durations = [
            get_configuration_duration(conf) for conf in req['configurations']
        ]
        req_info['configurations'] = conf_durations
        rise_set_intervals = get_filtered_rise_set_intervals_by_site(
            req, is_staff=is_staff)
        req_info['largest_interval'] = get_largest_interval(
            rise_set_intervals).total_seconds()
        req_info['largest_interval'] -= (PER_CONFIGURATION_STARTUP_TIME +
                                         PER_CONFIGURATION_GAP)
        req_durations['requests'].append(req_info)
    req_durations['duration'] = sum(
        [req['duration'] for req in req_durations['requests']])

    return req_durations
Exemple #4
0
def get_request_duration_dict(request_dict, is_staff=False):
    req_durations = {'requests': []}
    for req in request_dict:
        req_info = {'duration': get_total_request_duration(req)}
        conf_durations = []
        for conf in req['configurations']:
            request_overheads = configdb.get_request_overheads(
                conf['instrument_type'])
            conf_durations.append(
                get_configuration_duration(conf, request_overheads))
        req_info['configurations'] = conf_durations
        rise_set_intervals = get_filtered_rise_set_intervals_by_site(
            req, is_staff=is_staff)
        req_info['largest_interval'] = get_largest_interval(
            rise_set_intervals).total_seconds()
        req_durations['requests'].append(req_info)
    req_durations['duration'] = sum(
        [req['duration'] for req in req_durations['requests']])

    return req_durations
Exemple #5
0
    def validate(self, data):
        is_staff = False
        only_schedulable = True
        request_context = self.context.get('request')
        if request_context:
            is_staff = request_context.user.is_staff
            only_schedulable = not (is_staff and ConfigDB.is_location_fully_set(data.get('location', {})))
        # check if the instrument specified is allowed
        # TODO: Check if ALL instruments are available at a resource defined by location
        if 'location' in data:
            # Check if the location is fully specified, and if not then use only schedulable instruments
            valid_instruments = configdb.get_instrument_types(data.get('location', {}),
                                                              only_schedulable=only_schedulable)
            for configuration in data['configurations']:
                if configuration['instrument_type'] not in valid_instruments:
                    msg = _("Invalid instrument type '{}' at site={}, enc={}, tel={}. \n").format(
                        configuration['instrument_type'],
                        data.get('location', {}).get('site', 'Any'),
                        data.get('location', {}).get('enclosure', 'Any'),
                        data.get('location', {}).get('telescope', 'Any')
                    )
                    msg += _("Valid instruments include: ")
                    for inst_name in valid_instruments:
                        msg += inst_name + ', '
                    msg += '.'
                    if is_staff and not only_schedulable:
                        msg += '\nStaff users must fully specify location to schedule on non-SCHEDULABLE instruments'
                    raise serializers.ValidationError(msg)

        if 'acceptability_threshold' not in data:
            data['acceptability_threshold'] = max(
                [configdb.get_default_acceptability_threshold(configuration['instrument_type'])
                 for configuration in data['configurations']]
            )

        # check that the requests window has enough rise_set visible time to accomodate the requests duration
        if data.get('windows'):
            duration = get_request_duration(data)
            rise_set_intervals_by_site = get_filtered_rise_set_intervals_by_site(data, is_staff=is_staff)
            largest_interval = get_largest_interval(rise_set_intervals_by_site)
            for configuration in data['configurations']:
                if 'REPEAT' in configuration['type'].upper() and configuration.get('fill_window'):
                    max_configuration_duration = largest_interval.total_seconds() - duration + configuration.get('repeat_duration', 0) - 1
                    configuration['repeat_duration'] = max_configuration_duration
                    duration = get_request_duration(data)

                # delete the fill window attribute, it is only used for this validation
                try:
                    del configuration['fill_window']
                except KeyError:
                    pass
            if largest_interval.total_seconds() <= 0:
                raise serializers.ValidationError(
                    _(
                        'According to the constraints of the request, the target is never visible within the time '
                        'window. Check that the target is in the nighttime sky. Consider modifying the time '
                        'window or loosening the airmass or lunar separation constraints. If the target is '
                        'non sidereal, double check that the provided elements are correct.'
                    )
                )
            if largest_interval.total_seconds() <= duration:
                raise serializers.ValidationError(
                    (
                        'According to the constraints of the request, the target is visible for a maximum of {0:.2f} '
                        'hours within the time window. This is less than the duration of your request {1:.2f} hours. '
                        'Consider expanding the time window or loosening the airmass or lunar separation constraints.'
                    ).format(
                        largest_interval.total_seconds() / 3600.0,
                        duration / 3600.0
                    )
                )
        return data
Exemple #6
0
    def test_get_largest_rise_set_interval_only_uses_one_site(self):
        configdb_patcher = patch(
            'observation_portal.common.configdb.ConfigDB.get_sites_with_instrument_type_and_location'
        )
        mock_configdb = configdb_patcher.start()
        mock_configdb.return_value = {
            'tst': {
                'latitude': -30.1673833333,
                'longitude': -70.8047888889,
                'horizon': 15.0,
                'altitude': 100.0,
                'ha_limit_pos': 4.6,
                'ha_limit_neg': -4.6,
                'zenith_blind_spot': 0.0
            },
            'abc': {
                'latitude': -32.3805542,
                'longitude': 20.8101815,
                'horizon': 15.0,
                'altitude': 100.0,
                'ha_limit_pos': 4.6,
                'ha_limit_neg': -4.6,
                'zenith_blind_spot': 0.0
            }
        }
        configdb_patcher2 = patch(
            'observation_portal.common.configdb.ConfigDB.get_telescopes_with_instrument_type_and_location')
        mock_configdb2 = configdb_patcher2.start()
        mock_configdb2.return_value = {
            '1m0a.doma.tst': {
                'latitude': -30.1673833333,
                'longitude':-70.8047888889,
                'horizon': 15.0,
                'altitude': 100.0,
                'ha_limit_pos': 4.6,
                'ha_limit_neg': -4.6,
                'zenith_blind_spot': 0.0
            },
            '1m0a.doma.abc': {
                'latitude': -32.3805542,
                'longitude': 20.8101815,
                 'horizon': 15.0,
                 'altitude': 100.0,
                 'ha_limit_pos': 4.6,
                 'ha_limit_neg': -4.6,
                 'zenith_blind_spot': 0.0
            }
        }

        request_dict = {'location': {'telescope_class': '1m0'},
                        'windows': [
                            {
                                'start': datetime(2016, 9, 4),
                                'end': datetime(2016, 9, 5)
                            }
                        ],
                        'configurations': [
                            {
                                'instrument_type': '1M0-SCICAM-SINISTRO',
                                'instrument_configs': [
                                    {
                                        'exposure_time': 6000,
                                        'exposure_count': 5
                                    }
                                ],
                                'target': {
                                    'type': 'ICRS',
                                    'ra': 35.0,
                                    'dec': -53.0,
                                    'proper_motion_ra': 0.0,
                                    'proper_motion_dec': 0.0,
                                    'epoch': 2000,
                                    'parallax': 0.0
                                },
                                'constraints': {
                                    'max_airmass': 2.0,
                                    'min_lunar_distance': 30.0
                                }
                            }
                        ]}
        filtered_intervals = rise_set_utils.get_filtered_rise_set_intervals_by_site(request_dict)
        largest_interval = rise_set_utils.get_largest_interval(filtered_intervals)
        duration = timedelta(seconds=30000)
        self.assertGreater(duration, largest_interval)  # The duration is greater than the largest interval at a site

        combined_intervals = Intervals().union(
            [Intervals(timepoints=fi) for fi in filtered_intervals.values()]).toTupleList()
        largest_combined_interval = rise_set_utils.get_largest_interval({'tst': combined_intervals})
        self.assertLess(duration, largest_combined_interval)  # The duration is less then combined largest intervals

        configdb_patcher.stop()
        configdb_patcher2.stop()