def _lookup_airport_and_runway(self, _slice, precise, lowest_lat, lowest_lon, lowest_hdg, appr_ils_freq, land_afr_apt=None, land_afr_rwy=None, hint='approach', ac_type=aeroplane): handler = api.get_handler(settings.API_HANDLER) kwargs = {} airport, runway, match = None, None, None # A1. If we have latitude and longitude, look for the nearest airport: if lowest_lat not in (None, np.ma.masked) and lowest_lon not in ( None, np.ma.masked): kwargs.update(latitude=lowest_lat, longitude=lowest_lon) try: airports = handler.get_nearest_airport(**kwargs) except (ValueError, TypeError): self.warning('No coordinates for looking up approach airport.') except api.NotFoundError: msg = 'No approach airport found near coordinates (%f, %f).' self.warning(msg, lowest_lat, lowest_lon) # No airport was found, so fall through and try AFR. else: airport_info = self._evaluate_airports(airports, lowest_lat, lowest_lon, lowest_hdg, appr_ils_freq) if land_afr_apt and land_afr_apt.value['id'] in airport_info: # use afr airprot match = airport_info[land_afr_apt.value['id']] elif land_afr_apt and precise and ac_type != helicopter: # raise error as afr and flight data do not match msg = "'%s' provided by AFR is not in list of aiports within range of %s, %s. Aircraft has precise positioning"\ % (land_afr_apt.value['code'], lowest_lat, lowest_lon) raise AFRMissmatchError(self.name, msg) elif not land_afr_apt and precise: # filter by runway coordinates filtered = [ x for x in airport_info.values() if x['min_rwy_start_dist'] is not None ] if filtered: match = min(filtered, key=itemgetter('min_rwy_start_dist')) else: # filter by runway heading airport = None potential_airports = [ x for x in airport_info.values() if x['heading_match'] ] if appr_ils_freq: # filter by ils frequency ils_airports = [ x for x in airport_info.values() if x['ils_match'] ] if len(ils_airports) == 1: potential_airports = [ils_airports[0]] elif len(ils_airports) > 1: potential_airports = ils_airports if len(potential_airports) == 1: match = potential_airports[0] elif len(potential_airports) > 1: # filter by runway distances filtered = [ x for x in potential_airports if x['min_rwy_start_dist'] is not None ] if filtered: match = min(filtered, key=itemgetter('min_rwy_start_dist')) else: # filter by airport distances if airports: airport = min(airports, key=itemgetter('distance')) if match: airport = match['airport'] if airport: self.debug('Detected approach airport: %s', airport) else: self.warning( 'Unable to locate Airport from provided coordinates') else: # No suitable coordinates, so fall through and try AFR. self.warning('No coordinates for looking up approach airport.') # return None, None # A2. If and we have an airport in achieved flight record, use it: # NOTE: AFR data is only provided if this approach is a landing. if not airport and land_afr_apt: airport = handler.get_airport(land_afr_apt.value['id']) self.debug('Using approach airport from AFR: %s', airport['name']) # A3. After all that, we still couldn't determine an airport... if not airport: self.error('Unable to determine airport on approach!') return None, None if lowest_hdg is not None: # R1. If we have airport and heading, look for the nearest runway: if appr_ils_freq: kwargs['ilsfreq'] = appr_ils_freq # We already have latitude and longitude in kwargs from looking up # the airport. If the measurments are not precise, remove them. if not precise: kwargs['hint'] = hint runway = nearest_runway(airport, lowest_hdg, **kwargs) if not runway: msg = 'No runway found for airport #%d @ %03.1f deg with %s.' self.warning(msg, airport['id'], lowest_hdg, kwargs) # No runway was found, so fall through and try AFR. if 'ilsfreq' in kwargs: # This is a trap for airports where the ILS data is not # available, but the aircraft approached with the ILS # tuned. A good prompt for an omission in the database. self.warning('Fix database? No runway but ILS was tuned.') else: self.debug('Detected approach runway: %s', runway) # R2. If we have a runway provided in achieved flight record, use it: if not runway and land_afr_rwy: runway = land_afr_rwy.value self.debug('Using approach runway from AFR: %s', runway) # R3. After all that, we still couldn't determine a runway... if not runway: self.error('Unable to determine runway on approach!') return airport, runway
def _find_nearest_airport(self, precise, lowest_lat, lowest_lon, lowest_hdg, appr_ils_freq, ac_type, land_afr_apt): ''' Find the nearest airport from lowest lat and lon. Returns None if no suitable airport found. ''' handler = api.get_handler(settings.API_HANDLER) airport, match = None, None if lowest_lat in (None, np.ma.masked) or lowest_lon in (None, np.ma.masked): self.warning('No coordinates for looking up approach airport.') return try: airports = handler.get_nearest_airport(latitude=lowest_lat, longitude=lowest_lon) except (ValueError, TypeError): self.warning('No coordinates for looking up approach airport.') return except api.NotFoundError: msg = 'No approach airport found near coordinates (%f, %f).' self.warning(msg, lowest_lat, lowest_lon) return airport_info = self._evaluate_airports(airports, lowest_lat, lowest_lon, lowest_hdg, appr_ils_freq) if land_afr_apt and land_afr_apt.value['id'] in airport_info: match = airport_info[land_afr_apt.value['id']] elif land_afr_apt and precise and ac_type != helicopter: # raise error as afr and flight data do not match msg = "'%s' provided by AFR is not in list of aiports within range of %s, %s. Aircraft has precise positioning"\ % (land_afr_apt.value['code'], lowest_lat, lowest_lon) raise AFRMissmatchError(self.name, msg) elif precise: if ac_type != helicopter: # filter by runway coordinates filtered = [ x for x in airport_info.values() if x['min_rwy_start_dist'] is not None ] match = min(filtered, key=itemgetter('min_rwy_start_dist'), default=None) else: # Helicopter can arrive with any heading. Filter by airport distance. match = min(airport_info.values(), key=itemgetter('distance'), default=None) else: # Non-precise # filter by runway heading potential_airports = [ x for x in airport_info.values() if x['heading_match'] ] if appr_ils_freq: # filter by ils frequency ils_airports = [ x for x in airport_info.values() if x['ils_match'] ] if ils_airports: potential_airports = ils_airports if len(potential_airports) == 1: match = potential_airports[0] elif len(potential_airports) > 1: # filter by runway distances filtered = [ x for x in potential_airports if x['min_rwy_start_dist'] is not None ] match = min(filtered, key=itemgetter('min_rwy_start_dist'), default=None) else: # filter by airport distances if airports: airport = min(airports, key=itemgetter('distance')) if match: airport = match['airport'] if airport: self.debug('Detected approach airport: %s', airport) else: self.warning('Unable to locate Airport from provided coordinates') return airport