Skip to content

Commit

Permalink
Merge pull request #44 from LCOGT/release_fixes_4
Browse files Browse the repository at this point in the history
Allow multiple targets for direct submissions, protect against when t…
  • Loading branch information
eheinrich committed Jul 1, 2019
2 parents a2fe3df + b5dfd69 commit c621c83
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 25 deletions.
34 changes: 24 additions & 10 deletions observation_portal/blocks/conversion.py
Expand Up @@ -113,34 +113,39 @@ def convert_pond_block_to_observation(block):
config_extra_params['self_guiding'] = True

instrument_extra_params = {}
if 'rot_angle' in pointing and pointing['rot_angle'] is not None and float(pointing['rot_angle']):
if pointing.get('rot_angle') not in [None, ''] and float(pointing['rot_angle']):
instrument_extra_params['rotator_angle'] = float(pointing['rot_angle'])
if 'defocus' in molecule and float(molecule['defocus']):
if molecule.get('defocus') not in [None, ''] and float(molecule['defocus']):
instrument_extra_params['defocus'] = float(molecule['defocus'])
if 'expmeter_mode' in molecule and not molecule['expmeter_mode'] in ['OFF', 'EXPMETER_OFF']:
instrument_extra_params['expmeter_mode'] = molecule['expmeter_mode']
if 'expmeter_snr' in molecule and float(molecule['expmeter_snr']):
if molecule.get('expmeter_snr') not in [None, ''] and float(molecule['expmeter_snr']):
instrument_extra_params['expmeter_snr'] = float(molecule['expmeter_snr'])

instrument_optical_elements = {}
if molecule.get('filter') and 'NRES' not in block.get('instrument_class').upper():
if molecule.get('filter') and 'NRES' not in str(block.get('instrument_class')).upper():
instrument_optical_elements['filter'] = molecule['filter']
if molecule.get('spectra_slit') and 'NRES' not in block.get('instrument_class').upper():
if molecule.get('spectra_slit') and 'NRES' not in str(block.get('instrument_class')).upper():
instrument_optical_elements['slit'] = molecule['spectra_slit']
if molecule.get('spectra_lamp'):
instrument_optical_elements['lamp'] = molecule['spectra_lamp']

instrument_configs = [{
'mode': molecule.get('readout_mode', ''),
'rotator_mode': pointing.get('rot_mode', ''),
'exposure_time': float(molecule.get('exposure_time', 0.01)),
'exposure_count': molecule.get('exposure_count', 1),
'bin_x': molecule.get('bin_x', 1),
'bin_y': molecule.get('bin_y', 1),
'optical_elements': instrument_optical_elements,
'extra_params': instrument_extra_params
}]

if molecule.get('exposure_time') not in [None, '']:
exposure_time = float(molecule['exposure_time'])
else:
exposure_time = 0.01
instrument_configs[0]['exposure_time'] = exposure_time

if molecule.get('sub_x1') and molecule.get('sub_x2') and molecule.get('sub_y1') and molecule.get('sub_y2'):
instrument_configs[0]['rois'] = [{'x1': float(molecule['sub_x1']),
'x2': float(molecule['sub_x2']),
Expand All @@ -156,18 +161,27 @@ def convert_pond_block_to_observation(block):
ag_extra_params['ag_strategy'] = molecule['ag_strategy']

(guide_mode, guide_optional) = pond_ag_mode_to_guiding_mode(molecule.get('ag_mode', 'OPT'))
if block.get('instrument_class').upper() in ['1M0-NRES-SCICAM', '1M0-NRES-COMMISIONING', '2M0-FLOYDS-SCICAM']:
if molecule.get('type').upper() not in ['ARC', 'LAMP_FLAT']:
if str(block.get('instrument_class')).upper() in [
'1M0-NRES-SCICAM',
'1M0-NRES-COMMISIONING',
'2M0-FLOYDS-SCICAM'
]:
if str(molecule.get('type')).upper() not in ['ARC', 'LAMP_FLAT']:
guide_optional = False

guiding_config = {
'mode': guide_mode,
'optional': guide_optional,
'exposure_time': float(molecule.get('ag_exp_time', 10)),
'optical_elements': ag_optical_elements,
'extra_params': ag_extra_params
}

if molecule.get('ag_exp_time') not in [None, '']:
ag_exp_time = float(molecule['ag_exp_time'])
else:
ag_exp_time = 10
guiding_config['exposure_time'] = ag_exp_time

acquire_mode = molecule.get('acquire_mode', 'OFF')
acquire_extra_params = {}
if not acquire_mode == 'OFF':
Expand All @@ -183,7 +197,7 @@ def convert_pond_block_to_observation(block):
'extra_params': acquire_extra_params
}

if float(molecule.get('acquire_exp_time', 0)):
if molecule.get('acquire_exp_time') not in [None, ''] and float(molecule['acquire_exp_time']):
acquisition_config['exposure_time'] = float(molecule['acquire_exp_time'])

configuration = {
Expand Down
33 changes: 27 additions & 6 deletions observation_portal/common/rise_set_utils.py
Expand Up @@ -151,6 +151,28 @@ def filter_out_downtime_from_intervalsets(intervalsets_by_telescope: dict) -> di
return filtered_intervalsets_by_telescope


def get_proper_motion(target_dict):
# The proper motion fields are sometimes not present in HOUR_ANGLE targets
pm = {'pmra': None, 'pmdec': None}
if 'proper_motion_ra' in target_dict and target_dict['proper_motion_ra'] is not None:
pm['pmra'] = ProperMotion(
Angle(
degrees=(target_dict['proper_motion_ra'] / 1000.0 / cos(radians(target_dict['dec']))) / 3600.0,
units='arc'
),
time='year'
)
if 'proper_motion_dec' in target_dict and target_dict['proper_motion_dec'] is not None:
pm['pmdec'] = ProperMotion(
Angle(
degrees=(target_dict['proper_motion_dec'] / 1000.0) / 3600.0,
units='arc'
),
time='year'
)
return pm


def get_rise_set_target(target_dict):
# This is a hack to protect against poorly formatted or empty targets that are submitted directly.
# TODO: Remove this check when target models are updated to handle when there is no target
Expand All @@ -164,14 +186,13 @@ def get_rise_set_target(target_dict):
dec=Angle(degrees=0),
)
if target_dict['type'] in ['ICRS', 'HOUR_ANGLE']:
pmra = (target_dict['proper_motion_ra'] / 1000.0 / cos(radians(target_dict['dec']))) / 3600.0
pmdec = (target_dict['proper_motion_dec'] / 1000.0) / 3600.0
pm = get_proper_motion(target_dict)
if target_dict['type'] == 'ICRS':
return make_ra_dec_target(
ra=Angle(degrees=target_dict['ra']),
dec=Angle(degrees=target_dict['dec']),
ra_proper_motion=ProperMotion(Angle(degrees=pmra, units='arc'), time='year'),
dec_proper_motion=ProperMotion(Angle(degrees=pmdec, units='arc'), time='year'),
ra_proper_motion=pm['pmra'],
dec_proper_motion=pm['pmdec'],
parallax=target_dict['parallax'],
rad_vel=0.0,
epoch=target_dict['epoch']
Expand All @@ -180,8 +201,8 @@ def get_rise_set_target(target_dict):
return make_hour_angle_target(
hour_angle=Angle(degrees=target_dict['hour_angle']),
dec=Angle(degrees=target_dict['dec']),
ra_proper_motion=ProperMotion(Angle(degrees=pmra, units='arc'), time='year'),
dec_proper_motion=ProperMotion(Angle(degrees=pmdec, units='arc'), time='year'),
ra_proper_motion=pm['pmra'],
dec_proper_motion=pm['pmdec'],
parallax=target_dict['parallax'],
epoch=target_dict['epoch']
)
Expand Down
6 changes: 5 additions & 1 deletion observation_portal/requestgroups/duration_utils.py
Expand Up @@ -169,7 +169,11 @@ def get_request_duration(request_dict):
duration += change_overhead

# Now add in the slew time between targets (configurations). Only Sidereal can be calculated based on position.
if not previous_target or 'ra' not in previous_target or 'ra' not in configuration['target']:
if (
not previous_target
or previous_target['type'].upper() != 'ICRS'
or configuration['target']['type'].upper() != 'ICRS'
):
duration += request_overheads['maximum_slew_overhead']
elif previous_target != configuration['target']:
duration += min(max(get_slew_distance(previous_target, configuration['target'], start_time)
Expand Down
17 changes: 9 additions & 8 deletions observation_portal/requestgroups/serializers.py
Expand Up @@ -510,17 +510,10 @@ def validate_configurations(self, value):
if not value:
raise serializers.ValidationError(_('You must specify at least 1 configuration'))

target = value[0]['target']
constraints = value[0]['constraints']
# Set the relative priority of molecules in order
for i, configuration in enumerate(value):
configuration['priority'] = i + 1
# TODO: Remove this once we support multiple targets/constraints
if configuration['target'] != target:
raise serializers.ValidationError(_(
'Currently only a single target per Request is supported. This restriction will be lifted in '
'the future.'
))
if configuration['constraints'] != constraints:
raise serializers.ValidationError(_(
'Currently only a single constraints per Request is supported. This restriction will be '
Expand Down Expand Up @@ -726,12 +719,20 @@ def validate(self, data):
# Don't do any time accounting stuff if it is a directly scheduled observation
return data
else:
# for non-DIRECT observations, don't allow HOUR_ANGLE targets
for request in data['requests']:
target = request['configurations'][0]['target']
for config in request['configurations']:
# for non-DIRECT observations, don't allow HOUR_ANGLE targets
if config['target']['type'] == 'HOUR_ANGLE':
raise serializers.ValidationError(_('HOUR_ANGLE Target type not supported in scheduled observations'))

# For non-DIRECT observations, only allow a single target
# TODO: Remove this check once we support multiple targets/constraints
if config['target'] != target:
raise serializers.ValidationError(_(
'Currently only a single target per Request is supported. This restriction will be lifted '
'in the future.'
))
try:
total_duration_dict = get_total_duration_dict(data)
for tak, duration in total_duration_dict.items():
Expand Down

0 comments on commit c621c83

Please sign in to comment.