def rank_origins(origins, destinations): p('debug', 'Ranking origins: %s' % origins) midpoint_origins = midpoint(origins) midpoint_destinations = midpoint(destinations) hub_route = Segment(midpoint_origins, midpoint_destinations) for origin in origins: AC = Segment(midpoint_origins, origin) orthogonal_heading = hub_route.get_initial_bearing() + 90 (a, b) = project_segment( abs(orthogonal_heading - AC.get_initial_bearing()), AC.get_length() ) projection = midpoint_origins.get_position( orthogonal_heading, a ) midpoint_to_projection = Segment( midpoint_origins, projection ) angle = abs( hub_route.get_initial_bearing() - midpoint_to_projection.get_initial_bearing() ) if abs(angle - 90) < 0.1: distance = -1 * midpoint_to_projection.get_length() else: distance = midpoint_to_projection.get_length() origin.distance_to_midpoint = distance return sorted(origins, key = lambda point: point.distance_to_midpoint)
def rank_origins(origins, destinations): p('debug', 'Ranking origins: %s' % origins) midpoint_origins = midpoint(origins) midpoint_destinations = midpoint(destinations) hub_route = Segment(midpoint_origins, midpoint_destinations) for origin in origins: AC = Segment(midpoint_origins, origin) orthogonal_heading = hub_route.get_initial_bearing() + 90 (a, b) = project_segment( abs(orthogonal_heading - AC.get_initial_bearing()), AC.get_length()) projection = midpoint_origins.get_position(orthogonal_heading, a) midpoint_to_projection = Segment(midpoint_origins, projection) angle = abs(hub_route.get_initial_bearing() - midpoint_to_projection.get_initial_bearing()) if abs(angle - 90) < 0.1: distance = -1 * midpoint_to_projection.get_length() else: distance = midpoint_to_projection.get_length() origin.distance_to_midpoint = distance return sorted(origins, key=lambda point: point.distance_to_midpoint)
def is_valid_formation(aircraft_list): # Get the segments segments = map(lambda aircraft: aircraft.route.segments[0], aircraft_list) # Find the reference point collection of segments midpoints = map(lambda x: x.midpoint, segments) reference = util.midpoint (midpoints) deviation_sum = 0 for segment in segments: crosstrack = Segment(segment.start, reference) deviation = util.cross_track_distance ( crosstrack.get_length(), crosstrack.get_initial_bearing(), segment.get_initial_bearing() ) deviation_sum = deviation_sum + abs(deviation) if abs(deviation) > config.max_deviation: return False #print '%s (ref = %s) crosstrack distance: %.1f' %\ #(segment, reference, d_x) return deviation_sum
def get_exit(hub, trunk_route, flight): dest = flight['route'].waypoints[-1] hub_to_dest = Segment(hub, dest) theta = abs(hub_to_dest.get_initial_bearing() - trunk_route.get_initial_bearing()) (a, b) = project_segment(theta, hub_to_dest.get_length()) Q = get_hookoff_quotient(a, b, config.alpha) d_hub_to_exit = a * Q # Exit to destination must be long enough to allow for safe descent # TOD is at 150NM out of dest, so exit->dest must be longer than 150NM d_exit_to_dest = 0 while d_exit_to_dest < 150: exit_point = hub.get_position( trunk_route.get_initial_bearing(), d_hub_to_exit ) d_hub_to_exit -= 1 exit_dest = Segment(exit_point, dest) d_exit_to_dest = exit_dest.get_length() assert exit_dest.get_length() > 150 print 'For flight %s, the exit point is %dNM away from dest' % ( flight['route'], d_exit_to_dest ) return exit_point
def get_hub(flights): o = [] d = [] for flight in flights: o.append(flight['route'].waypoints[0]) d.append(flight['route'].waypoints[-1]) mid_o = midpoint(o) mid_d = midpoint(d) trunk_route = Segment(mid_o, mid_d) return mid_o.get_position(trunk_route.get_initial_bearing(), trunk_route.get_length() * config.Z)
def heading_filter(buddy): segment = Segment(buddy.hub, buddy.destination) buddy_heading = segment.get_initial_bearing() phi_obs = abs(leader_heading - buddy_heading) p( 'debug', 'delta phi observed for %s (phi: %.2f) against %s (phi: %.2f)' ': %.2f degrees' % (aircraft, leader_heading, buddy, buddy_heading, phi_obs)) return phi_obs <= (config.phi_max / 2)
def handle_alive(event): global vars formation = event.sender # We should have a hookoff point for each participant, and it should be # the current segment for aircraft in formation: assert aircraft.hookoff_point # The remaining segment should be hookoff-destination #debug.print_object(aircraft) assert len(aircraft.route.segments) > 0 # Let the aircraft know in which formation it belongs aircraft.formation = formation #assert aircraft.route.segments[0].end.coincides( # aircraft.hookoff_point #) vars["formation_count"] += 1 vars['formation_aircraft_count'] += len(formation) formation_phi = 0 for aircraft in formation: hub_to_dest = Segment(aircraft.hub, aircraft.destination) hub_to_hookoff = Segment(aircraft.hub, aircraft.hookoff_point) bearing = hub_to_dest.get_initial_bearing() formation_bearing = hub_to_hookoff.get_initial_bearing() phi_obs = abs(bearing - formation_bearing) p('debug', 'Aircraft %s, phi_obs: %.2f' % (aircraft, phi_obs)) #assert phi_obs <= config.phi_max formation_phi += phi_obs #print aircraft.route.segments[0].initial_bearing() vars['phi_obs_sum'] += formation_phi for aircraft in formation: vars['Q_sum'] = vars['Q_sum'] + aircraft.Q
def heading_filter(buddy): segment = Segment(buddy.hub, buddy.destination) buddy_heading = segment.get_initial_bearing() phi_obs = abs(leader_heading - buddy_heading) p( 'debug', 'delta phi observed for %s (phi: %.2f) against %s (phi: %.2f)' ': %.2f degrees' % ( aircraft, leader_heading, buddy, buddy_heading, phi_obs ) ) return phi_obs <= (config.phi_max/2)
def get_hub(flights): o = [] d = [] for flight in flights: o.append(flight['route'].waypoints[0]) d.append(flight['route'].waypoints[-1]) mid_o = midpoint(o) mid_d = midpoint(d) trunk_route = Segment(mid_o, mid_d) return mid_o.get_position( trunk_route.get_initial_bearing(), trunk_route.get_length() * config.Z )
def construct_hub(origins, destinations, Z): midpoint_origins = midpoint(origins) midpoint_destinations = midpoint(destinations) hub_route = Segment(midpoint_origins, midpoint_destinations) hub = hub_route.start.get_position(hub_route.get_initial_bearing(), hub_route.get_length() * Z) hub.origins = origins hub.destinations = destinations p('debug', 'Constructed hub at %s' % (hub)) return hub
def construct_hub(origins, destinations, Z): midpoint_origins = midpoint(origins) midpoint_destinations = midpoint(destinations) hub_route = Segment(midpoint_origins, midpoint_destinations) hub = hub_route.start.get_position( hub_route.get_initial_bearing(), hub_route.get_length() * Z ) hub.origins = origins hub.destinations = destinations p('debug', 'Constructed hub at %s' % (hub)) return hub
def get_exit(hub, trunk_route, flight): dest = flight['route'].waypoints[-1] hub_to_dest = Segment(hub, dest) theta = abs(hub_to_dest.get_initial_bearing() - trunk_route.get_initial_bearing()) (a, b) = project_segment(theta, hub_to_dest.get_length()) Q = get_hookoff_quotient(a, b, config.alpha) d_hub_to_exit = a * Q # Exit to destination must be long enough to allow for safe descent # TOD is at 150NM out of dest, so exit->dest must be longer than 150NM d_exit_to_dest = 0 while d_exit_to_dest < 150: exit_point = hub.get_position(trunk_route.get_initial_bearing(), d_hub_to_exit) d_hub_to_exit -= 1 exit_dest = Segment(exit_point, dest) d_exit_to_dest = exit_dest.get_length() assert exit_dest.get_length() > 150 print 'For flight %s, the exit point is %dNM away from dest' % ( flight['route'], d_exit_to_dest) return exit_point
def allocate(self, aircraft): p('debug', 'Starting formation allocation for %s' % aircraft) # Do not perform allocation if no hub exists in the flight route. if len(aircraft.route.segments) == 0: return self.formations = [] intervals = [] candidates = self.aircraft_queue hub = aircraft.route.waypoints[0] # This is bad. We don't want to filter anything. # @todo: pre-process at a higher level. # Only consider other aircraft flying to the same hub candidates = filter(lambda a: a.route.waypoints[0] is hub, candidates) p('debug', 'Full candidate set: %s' % candidates) # Only consider aircraft having a maximum heading difference between # the hub and their destination segment = Segment(aircraft.hub, aircraft.destination) leader_heading = segment.get_initial_bearing() def heading_filter(buddy): segment = Segment(buddy.hub, buddy.destination) buddy_heading = segment.get_initial_bearing() phi_obs = abs(leader_heading - buddy_heading) p( 'debug', 'delta phi observed for %s (phi: %.2f) against %s (phi: %.2f)' ': %.2f degrees' % ( aircraft, leader_heading, buddy, buddy_heading, phi_obs ) ) return phi_obs <= (config.phi_max/2) candidates = filter(heading_filter, candidates) # Other interesting filters if 'same-airline' in config.restrictions: airline = aircraft.label[0:2] candidates = filter(lambda a: a.label[0:2] == airline, candidates) if 'same-aircraft-type' in config.restrictions: aircraft_type = aircraft.aircraft_type candidates = filter(lambda a: a.aircraft_type == aircraft_type, candidates) p('debug', 'Reduced candidate set: %s' % candidates) for candidate in candidates: # Quick and dirty: recalc position. Instead, pull eta from var. candidate.controller.update_position() tth = candidate.time_to_waypoint() # time to hub hub_eta = sim.time + tth # From the moment the aircraft enters the lock area, the slack # decreases linearly to zero upon hub arrival. if tth < config.lock_time: slack = tth * config.etah_slack / config.lock_time else: slack = config.etah_slack p('Time = %s, Hub (= %s) eta %s for candidate %s' %\ (sim.time, hub, hub_eta, candidate)) intervals.append(Interval( candidate, int(hub_eta) - slack, int(hub_eta) + slack )) for interval_group in group(intervals): formation = Formation() for interval in interval_group: formation.append(interval.obj) self.formations.append(formation)
def allocate(self, aircraft): p('debug', 'Starting formation allocation for %s' % aircraft) # Do not perform allocation if no hub exists in the flight route. if len(aircraft.route.segments) == 0: return self.formations = [] intervals = [] candidates = self.aircraft_queue hub = aircraft.route.waypoints[0] # This is bad. We don't want to filter anything. # @todo: pre-process at a higher level. # Only consider other aircraft flying to the same hub candidates = filter(lambda a: a.route.waypoints[0] is hub, candidates) p('debug', 'Full candidate set: %s' % candidates) # Only consider aircraft having a maximum heading difference between # the hub and their destination segment = Segment(aircraft.hub, aircraft.destination) leader_heading = segment.get_initial_bearing() def heading_filter(buddy): segment = Segment(buddy.hub, buddy.destination) buddy_heading = segment.get_initial_bearing() phi_obs = abs(leader_heading - buddy_heading) p( 'debug', 'delta phi observed for %s (phi: %.2f) against %s (phi: %.2f)' ': %.2f degrees' % (aircraft, leader_heading, buddy, buddy_heading, phi_obs)) return phi_obs <= (config.phi_max / 2) candidates = filter(heading_filter, candidates) # Other interesting filters if 'same-airline' in config.restrictions: airline = aircraft.label[0:2] candidates = filter(lambda a: a.label[0:2] == airline, candidates) if 'same-aircraft-type' in config.restrictions: aircraft_type = aircraft.aircraft_type candidates = filter(lambda a: a.aircraft_type == aircraft_type, candidates) p('debug', 'Reduced candidate set: %s' % candidates) for candidate in candidates: # Quick and dirty: recalc position. Instead, pull eta from var. candidate.controller.update_position() tth = candidate.time_to_waypoint() # time to hub hub_eta = sim.time + tth # From the moment the aircraft enters the lock area, the slack # decreases linearly to zero upon hub arrival. if tth < config.lock_time: slack = tth * config.etah_slack / config.lock_time else: slack = config.etah_slack p('Time = %s, Hub (= %s) eta %s for candidate %s' %\ (sim.time, hub, hub_eta, candidate)) intervals.append( Interval(candidate, int(hub_eta) - slack, int(hub_eta) + slack)) for interval_group in group(intervals): formation = Formation() for interval in interval_group: formation.append(interval.obj) self.formations.append(formation)