Пример #1
0
def get_telescope_states_for_request(request_dict, is_staff=False):
    # TODO: update to support multiple instruments in a list
    instrument_type = request_dict['configurations'][0]['instrument_type']
    site_intervals = {}
    only_schedulable = not (is_staff and ConfigDB.is_location_fully_set(
        request_dict.get('location', {})))
    # Build up the list of telescopes and their rise set intervals for the target on this request
    site_data = configdb.get_sites_with_instrument_type_and_location(
        instrument_type=instrument_type,
        site_code=request_dict['location']['site']
        if 'site' in request_dict['location'] else '',
        enclosure_code=request_dict['location']['enclosure']
        if 'enclosure' in request_dict['location'] else '',
        telescope_code=request_dict['location']['telescope']
        if 'telescope' in request_dict['location'] else '',
        only_schedulable=only_schedulable)

    for site, details in site_data.items():
        if site not in site_intervals:
            site_intervals[site] = get_filtered_rise_set_intervals_by_site(
                request_dict, site=site, is_staff=is_staff).get(site, [])

    # If you have no sites, return the empty dict here
    if not site_intervals:
        return {}

    # Retrieve the telescope states for that set of sites
    min_window_time = min(
        [window['start'] for window in request_dict['windows']])
    max_window_time = max(
        [window['end'] for window in request_dict['windows']])
    telescope_states = TelescopeStates(
        start=min_window_time,
        end=max_window_time,
        sites=list(site_intervals.keys()),
        instrument_types=[instrument_type],
        location_dict=request_dict.get('location', {}),
        only_schedulable=only_schedulable).get()
    # Remove the empty intervals from the dictionary
    site_intervals = {
        site: intervals
        for site, intervals in site_intervals.items() if intervals
    }

    # Filter the telescope states list with the site intervals
    filtered_telescope_states = filter_telescope_states_by_intervals(
        telescope_states, site_intervals, min_window_time, max_window_time)

    return filtered_telescope_states
Пример #2
0
def get_filtered_rise_set_intervals_by_site(request_dict,
                                            site='',
                                            is_staff=False):
    intervals = {}
    site = site if site else request_dict['location'].get('site', '')
    only_schedulable = not (is_staff and ConfigDB.is_location_fully_set(
        request_dict.get('location', {})))
    telescope_details = configdb.get_telescopes_with_instrument_type_and_location(
        request_dict['configurations'][0]['instrument_type'], site,
        request_dict['location'].get('enclosure', ''),
        request_dict['location'].get('telescope', ''), only_schedulable)
    if not telescope_details:
        return intervals

    intervals_by_site = get_rise_set_intervals_by_site(request_dict)
    intervalsets_by_telescope = intervals_by_site_to_intervalsets_by_telescope(
        intervals_by_site, telescope_details.keys())
    filtered_intervalsets_by_telescope = filter_out_downtime_from_intervalsets(
        intervalsets_by_telescope)
    filtered_intervals_by_site = intervalsets_by_telescope_to_intervals_by_site(
        filtered_intervalsets_by_telescope)
    return filtered_intervals_by_site
Пример #3
0
def get_airmasses_for_request_at_sites(request_dict, is_staff=False):
    # TODO: Change to work with multiple instrument types and multiple constraints and multiple targets
    data = {'airmass_data': {}}
    instrument_type = request_dict['configurations'][0]['instrument_type']
    constraints = request_dict['configurations'][0]['constraints']
    target = request_dict['configurations'][0]['target']
    target_type = str(target.get('type', '')).upper()
    only_schedulable = not (is_staff and ConfigDB.is_location_fully_set(request_dict.get('location', {})))

    if target_type in ['ICRS', 'ORBITAL_ELEMENTS'] and TARGET_TYPE_HELPER_MAP[target_type](target).is_valid():
        site_data = configdb.get_sites_with_instrument_type_and_location(
            instrument_type=instrument_type,
            site_code=request_dict['location'].get('site'),
            enclosure_code=request_dict['location'].get('enclosure'),
            telescope_code=request_dict['location'].get('telescope'),
            only_schedulable=only_schedulable
        )
        rs_target = get_rise_set_target(target)
        for site_id, site_details in site_data.items():
            night_times = []
            site_lat = Angle(degrees=site_details['latitude'])
            site_lon = Angle(degrees=site_details['longitude'])
            site_alt = site_details['altitude']
            intervals = get_filtered_rise_set_intervals_by_site(request_dict, site_id, is_staff=is_staff).get(site_id, [])
            for interval in intervals:
                night_times.extend(
                    [time for time in date_range_from_interval(interval[0], interval[1], dt=timedelta(minutes=10))])

            if len(night_times) > 0:
                if site_id not in data:
                    data['airmass_data'][site_id] = {}
                data['airmass_data'][site_id]['times'] = [time.strftime('%Y-%m-%dT%H:%M') for time in night_times]
                data['airmass_data'][site_id]['airmasses'] = calculate_airmass_at_times(
                    night_times, rs_target, site_lat, site_lon, site_alt
                )
                data['airmass_limit'] = constraints['max_airmass']

    return data
Пример #4
0
def get_airmasses_for_request_at_sites(request_dict, is_staff=False):
    data = {
        'airmass_data': {},
    }
    instrument_type = request_dict['configurations'][0]['instrument_type']
    constraints = request_dict['configurations'][0]['constraints']
    target = request_dict['configurations'][0]['target']
    target_type = str(target.get('type', '')).upper()
    only_schedulable = not (is_staff and ConfigDB.is_location_fully_set(
        request_dict.get('location', {})))

    if target_type in [
            'ICRS', 'ORBITAL_ELEMENTS'
    ] and TARGET_TYPE_HELPER_MAP[target_type](target).is_valid():
        site_data = configdb.get_sites_with_instrument_type_and_location(
            instrument_type=instrument_type,
            site_code=request_dict['location'].get('site'),
            enclosure_code=request_dict['location'].get('enclosure'),
            telescope_code=request_dict['location'].get('telescope'),
            only_schedulable=only_schedulable)
        rs_target = get_rise_set_target(target)
        for site_id, site_details in site_data.items():
            night_times = []
            site_lat = Angle(degrees=site_details['latitude'])
            site_lon = Angle(degrees=site_details['longitude'])
            site_alt = site_details['altitude']
            intervals = get_filtered_rise_set_intervals_by_site(
                request_dict, site_id, is_staff=is_staff).get(site_id, [])
            for interval in intervals:
                night_times.extend([
                    time for time in date_range_from_interval(
                        interval[0], interval[1], dt=timedelta(minutes=10))
                ])

            if len(night_times) > 0:
                if site_id not in data:
                    data['airmass_data'][site_id] = {
                        'times': [
                            time.strftime('%Y-%m-%dT%H:%M')
                            for time in night_times
                        ],
                    }

                # Need to average airmass values for set of unique targets in request
                unique_targets_constraints = set([
                    json.dumps((configuration['target'],
                                configuration['constraints']))
                    for configuration in request_dict['configurations']
                ])
                unique_count = len(unique_targets_constraints)
                max_airmass = 0.0
                for target_constraints in unique_targets_constraints:
                    (target, constraints) = json.loads(target_constraints)
                    rs_target = get_rise_set_target(target)
                    airmasses = calculate_airmass_at_times(
                        night_times, rs_target, site_lat, site_lon, site_alt)
                    if 'airmasses' in data['airmass_data'][site_id]:
                        for index, airmass_value in enumerate(airmasses):
                            data['airmass_data'][site_id]['airmasses'][
                                index] += airmass_value
                    else:
                        data['airmass_data'][site_id]['airmasses'] = airmasses
                    max_airmass += constraints['max_airmass']
                # Now we need to divide out the number of unique constraints/targets
                data['airmass_limit'] = max_airmass / unique_count
                data['airmass_data'][site_id]['airmasses'] = [
                    val / unique_count
                    for val in data['airmass_data'][site_id]['airmasses']
                ]

    return data
Пример #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