def validate(self, data): # Target special validation if configdb.is_spectrograph(data['molecules'][0]['instrument_name'] ) and 'rot_mode' not in data['target']: data['target']['rot_mode'] = 'VFLOAT' # check if the instrument specified is allowed valid_instruments = configdb.get_active_instrument_types( data['location']) for molecule in data['molecules']: if molecule['instrument_name'] not in valid_instruments: msg = _( "Invalid instrument name '{}' at site={}, obs={}, tel={}. \n" ).format(molecule['instrument_name'], data['location'].get('site', 'Any'), data['location'].get('observatory', 'Any'), data['location'].get('telescope', 'Any')) msg += _("Valid instruments include: ") for inst_name in valid_instruments: msg += inst_name + ', ' raise serializers.ValidationError(msg) # 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 = get_rise_set_intervals(data) largest_interval = timedelta(seconds=0) for interval in rise_set_intervals: largest_interval = max((interval[1] - interval[0]), largest_interval) for molecule in data['molecules']: if molecule.get('fill_window'): molecule_duration = get_molecule_duration( molecule_dict=molecule) num_exposures = get_num_exposures( molecule, largest_interval - timedelta(seconds=duration - molecule_duration)) molecule['exposure_count'] = num_exposures duration = get_request_duration(data) # delete the fill window attribute, it is only used for this validation try: del molecule['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
def get_request_duration(request_dict): # calculate the total time needed by the request, based on its instrument and exposures request_overheads = configdb.get_request_overheads( request_dict['molecules'][0]['instrument_name']) duration = sum( [get_molecule_duration(m) for m in request_dict['molecules']]) if configdb.is_spectrograph( request_dict['molecules'][0]['instrument_name']): duration += get_num_mol_changes( request_dict['molecules'] ) * request_overheads['config_change_time'] for molecule in request_dict['molecules']: if molecule['acquire_mode'].upper() != 'OFF' and molecule[ 'type'].upper() in ['SPECTRUM', 'NRES_SPECTRUM']: duration += request_overheads[ 'acquire_exposure_time'] + request_overheads[ 'acquire_processing_time'] else: duration += get_num_filter_changes( request_dict['molecules'] ) * request_overheads['filter_change_time'] duration += request_overheads['front_padding'] duration = ceil(duration) return duration
def get(self, request): info = {} for instrument_type in configdb.get_active_instrument_types({}): filters = configdb.get_filters(instrument_type) filter_map = configdb.get_filter_map() info[instrument_type] = { 'type': 'SPECTRA' if configdb.is_spectrograph(instrument_type) else 'IMAGE', 'class': instrument_type[0:3], 'name': configdb.get_instrument_name(instrument_type), 'filters': {filter: filter_map[filter] for filter in filters}, 'binnings': configdb.get_binnings(instrument_type), 'default_binning': configdb.get_default_binning(instrument_type), } return Response(info)
def validate(self, data): # set special defaults if it is a spectrograph if configdb.is_spectrograph(data['instrument_name']): if 'ag_mode' not in data: data['ag_mode'] = 'ON' if 'acquire_mode' not in data: data['acquire_mode'] = 'WCS' if data['acquire_mode'] == 'BRIGHTEST' and not data.get( 'acquire_radius_arcsec'): raise serializers.ValidationError({ 'acquire_radius_arcsec': 'Acquire radius must be positive.' }) types_that_require_filter = [ 'expose', 'auto_focus', 'zero_pointing', 'standard', 'sky_flat' ] types_that_require_slit = ['spectrum', 'arc', 'lamp_flat'] types_that_require_ag_mode_on = [ 'spectrum', 'nres_spectrum', 'nres_test', 'nres_expose' ] # Spectrum and NRES_SPECTRUM obs must have ag_mode 'ON' if data['type'].lower() in types_that_require_ag_mode_on: if data['ag_mode'] is not 'ON': raise serializers.ValidationError({ 'ag_mode': _('Autoguiding must be on for {} observations.'.format( data['type'])) }) # check that the filter is available in the instrument type specified available_filters = configdb.get_filters(data['instrument_name']) if configdb.is_spectrograph(data['instrument_name']): if (data['type'].lower() in types_that_require_slit and data.get( 'spectra_slit', '').lower() not in available_filters): raise serializers.ValidationError({ 'spectra_slit': _("Invalid spectra slit {} for instrument {}. Valid slits are: {}" ).format(data.get('spectra_slit', ''), data['instrument_name'], ", ".join(available_filters)) }) elif data['type'].lower() in types_that_require_filter: if not data.get('filter'): raise serializers.ValidationError({ 'filter': _("You must specify a filter for {} exposures.").format( MOLECULE_TYPE_DISPLAY[data['type']]) }) elif data['filter'].lower() not in available_filters: raise serializers.ValidationError({ 'filter': _("Invalid filter {} for instrument {}. Valid filters are: {}" ).format(data['filter'], data['instrument_name'], ", ".join(available_filters)) }) # check that the binning is available for the instrument type specified if 'bin_x' not in data and 'bin_y' not in data: data['bin_x'] = configdb.get_default_binning( data['instrument_name']) data['bin_y'] = data['bin_x'] elif 'bin_x' in data and 'bin_y' in data: available_binnings = configdb.get_binnings(data['instrument_name']) if data['bin_x'] not in available_binnings: msg = _( "Invalid binning of {} for instrument {}. Valid binnings are: {}" ).format(data['bin_x'], data['instrument_name'].upper(), ", ".join([str(b) for b in available_binnings])) raise serializers.ValidationError(msg) else: raise serializers.ValidationError( _("Missing one of bin_x or bin_y. Specify both or neither.")) # check that the molecule type matches the instruemnt imager_only_types = ['EXPOSE', 'SKY_FLAT', 'AUTO_FOCUS'] spec_only_types = ['SPECTRUM', 'ARC', 'LAMP_FLAT'] if configdb.is_spectrograph( data['instrument_name']) and data['type'] in imager_only_types: raise serializers.ValidationError( _('Invalid type {0} for a spectrograph.'.format(data['type']))) if not configdb.is_spectrograph( data['instrument_name']) and data['type'] in spec_only_types: raise serializers.ValidationError( _('Invalid type {0} for an imager.'.format(data['type']))) return data