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 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 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_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 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 run(): # Discount incurred on formation trajectory by follower alpha = .15 # The formation hub hub = Waypoint('AMS') # The end point of trunk route (midpoint of the destinations) mid = Waypoint('JFK') # The actual destination of current participant des = Waypoint('SFO') # The trunk route itself trunk = Segment(hub, mid) hookoff = get_hookoff(trunk, des, alpha) print 'The trunk length = %d NM' % trunk.get_length() print 'The hookoff distance = %d NM' % d(hub, hookoff) print 'Therefore, Q = %.2f' % (d(hub, hookoff) / trunk.get_length())
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 handle_arrive(event): global vars, hubs aircraft = event.sender # Temporarily use one model for everything model = copy.deepcopy(config.model) # Also calculate the direct distance segment = Segment(aircraft.origin, aircraft.destination) direct = segment.get_length() #direct = 3193 #temp overwrite for validation p('validate', 'Distance direct for %s is %dNM' % ( aircraft, direct )) p('validate', 'Getting the benchmark fuel') vars['distance_direct'] += direct vars['fuel_direct'] += get_fuel_burned_during_cruise(direct, model) p('validate', 'OK, we have the benchmark fuel now') hub = aircraft.hub assert hub in config.hubs # Sometimes (especially with very low Z and high L) aircraft are excluded # from formation flight due to the origin being within the lock area. if hasattr(aircraft, 'is_excluded') and aircraft.is_excluded: vars['distance_solo'] += direct vars['fuel_actual'] += get_fuel_burned_during_cruise(direct, model) return #key = 'flight_count_%s' % hub #if key not in vars: # vars[key] = 0 #vars[key] = vars[key] + 1 # Aircraft always fly solo to the hub segment = Segment(aircraft.origin, hub) origin_to_hub = segment.get_length() p('Distance origin_to_hub for %s is %dNM' % ( aircraft, origin_to_hub )) vars['distance_solo'] += origin_to_hub # If in formation if hasattr(aircraft, 'formation'): segment = Segment(hub, aircraft.hookoff_point) hub_to_hookoff = segment.get_length() p('Distance hub_to_hookoff for %s is %dNM' % ( aircraft, hub_to_hookoff )) vars['distance_formation'] += hub_to_hookoff segment = Segment(aircraft.hookoff_point, aircraft.destination) hookoff_to_destination = segment.get_length() p('Distance hookoff_to_destination for %s is %dNM' % ( aircraft, hookoff_to_destination )) vars['distance_solo'] += hookoff_to_destination # Collect all hub delays # The calibration aircraft was never delayed if hasattr(aircraft, 'hub_delay'): vars['hub_delay_sum'] = vars['hub_delay_sum'] +\ aircraft.hub_delay if aircraft.incurs_benefits: discount = config.alpha else: discount = 0 p('validate', 'Discount = %s for %s' % (discount, aircraft)) fuel_formation = formationburn( int(origin_to_hub), int(hub_to_hookoff), int(hookoff_to_destination), model = model, discount = discount ) p('validate', 'Fuel burn formation = %d for %s' % ( fuel_formation, aircraft )) vars['fuel_actual'] += fuel_formation # If fully solo else: p('validate', 'Discount = false for %s' % (aircraft)) segment = Segment(hub, aircraft.destination) hub_to_destination = segment.get_length() p('Distance hub_to_destination for %s is %dNM' % ( aircraft, hub_to_destination )) vars['distance_solo'] += hub_to_destination fuel_solo = get_fuel_burned_during_cruise( origin_to_hub + hub_to_destination, model = model, ) p('validate', 'Fuel burn solo = %d for %s' % ( fuel_solo, aircraft )) vars['fuel_actual'] += fuel_solo
def handle_arrive(event): global vars, hubs aircraft = event.sender # Temporarily use one model for everything model = copy.deepcopy(config.model) # Also calculate the direct distance segment = Segment(aircraft.origin, aircraft.destination) direct = segment.get_length() #direct = 3193 #temp overwrite for validation p('validate', 'Distance direct for %s is %dNM' % (aircraft, direct)) p('validate', 'Getting the benchmark fuel') vars['distance_direct'] += direct vars['fuel_direct'] += get_fuel_burned_during_cruise(direct, model) p('validate', 'OK, we have the benchmark fuel now') hub = aircraft.hub assert hub in config.hubs # Sometimes (especially with very low Z and high L) aircraft are excluded # from formation flight due to the origin being within the lock area. if hasattr(aircraft, 'is_excluded') and aircraft.is_excluded: vars['distance_solo'] += direct vars['fuel_actual'] += get_fuel_burned_during_cruise(direct, model) return #key = 'flight_count_%s' % hub #if key not in vars: # vars[key] = 0 #vars[key] = vars[key] + 1 # Aircraft always fly solo to the hub segment = Segment(aircraft.origin, hub) origin_to_hub = segment.get_length() p('Distance origin_to_hub for %s is %dNM' % (aircraft, origin_to_hub)) vars['distance_solo'] += origin_to_hub # If in formation if hasattr(aircraft, 'formation'): segment = Segment(hub, aircraft.hookoff_point) hub_to_hookoff = segment.get_length() p('Distance hub_to_hookoff for %s is %dNM' % (aircraft, hub_to_hookoff)) vars['distance_formation'] += hub_to_hookoff segment = Segment(aircraft.hookoff_point, aircraft.destination) hookoff_to_destination = segment.get_length() p('Distance hookoff_to_destination for %s is %dNM' % (aircraft, hookoff_to_destination)) vars['distance_solo'] += hookoff_to_destination # Collect all hub delays # The calibration aircraft was never delayed if hasattr(aircraft, 'hub_delay'): vars['hub_delay_sum'] = vars['hub_delay_sum'] +\ aircraft.hub_delay if aircraft.incurs_benefits: discount = config.alpha else: discount = 0 p('validate', 'Discount = %s for %s' % (discount, aircraft)) fuel_formation = formationburn(int(origin_to_hub), int(hub_to_hookoff), int(hookoff_to_destination), model=model, discount=discount) p('validate', 'Fuel burn formation = %d for %s' % (fuel_formation, aircraft)) vars['fuel_actual'] += fuel_formation # If fully solo else: p('validate', 'Discount = false for %s' % (aircraft)) segment = Segment(hub, aircraft.destination) hub_to_destination = segment.get_length() p('Distance hub_to_destination for %s is %dNM' % (aircraft, hub_to_destination)) vars['distance_solo'] += hub_to_destination fuel_solo = get_fuel_burned_during_cruise( origin_to_hub + hub_to_destination, model=model, ) p('validate', 'Fuel burn solo = %d for %s' % (fuel_solo, aircraft)) vars['fuel_actual'] += fuel_solo
def calibrate(self): """Determines the trunk route and hookoff points""" # Determine formation trunk route destinations = [] for aircraft in self: destinations.append(aircraft.destination) arrival_midpoint = midpoint(destinations) p('destinations: %s' % destinations) p('midpoint = %s' % arrival_midpoint) hub_to_midpoint = Segment(aircraft.hub, arrival_midpoint) # Determine hookoff point for each aircraft, except the last for aircraft in self: hub_to_destination = Segment(aircraft.hub, aircraft.destination) p('flight %s hub %s to destination: %s' % ( aircraft, '%s{%d, %d}' % ( aircraft.hub, aircraft.hub.lat, aircraft.hub.lon ), aircraft.destination )) p('flight %s hub %s to midpoint: %s' % ( aircraft, '%s{%d, %d}' % ( aircraft.hub, aircraft.hub.lat, aircraft.hub.lon ), arrival_midpoint )) aircraft.hookoff_point = get_hookoff( hub_to_midpoint, aircraft.destination, config.alpha ) hub_to_hookoff = Segment(aircraft.hub, aircraft.hookoff_point) aircraft.Q = hub_to_hookoff.get_length() /\ hub_to_midpoint.get_length() p('flight %s, hub %s to hook-off point: %s' % ( aircraft, '%s{%d, %d}' % ( aircraft.hub, aircraft.hub.lat, aircraft.hub.lon ), aircraft.hookoff_point )) aircraft.hookoff_point.name = 'hookoff-%s' % aircraft.hookoff_point # Place aircraft in order, ascending with Q, to fulfill LIFO condition. formation = sorted(self, key = lambda item: item.Q) # All aircraft at the front of the formation having the same destination # should hook off where the previous buddy (having a different # destination) hooked off. # Example: formation AMS-SFO, BRU-SFO, LHR-ATL. # AMS-SFO and BRU-SFO should hook off where LHR-ATL hooked off. # @todo Let AMS-SFO and BRU-SFO continue together along a new average # formation trajectory (in this case directly to the destination) # First find the leading set of aircraft having the same destination formation.reverse() leading_destination = formation[0].destination leaders = [] for aircraft in formation: # Start with always incurring benefits aircraft.incurs_benefits = True if not aircraft.destination.coincides(leading_destination): aircraft.is_leader = False continue aircraft.is_leader = True # Only the first leader incurs no benefits at all if len(leaders) == 0: aircraft.incurs_benefits = False leaders.append(aircraft) p('Leaders of formation %s are %s' % ( formation, leaders )) # Then find the buddy just before the set of leading aircraft, if # it exists. try: # The leaders: same hookoff point as last buddy. last_buddy = formation[len(leaders)] for aircraft in leaders: aircraft.Q = last_buddy.Q #aircraft.P = last_buddy.P aircraft.hookoff_point = last_buddy.hookoff_point except IndexError: pass # Change reversed formation back to normal formation.reverse() for aircraft in formation: p('Adjusting waypoints of %s. Initial waypoints: %s' % ( aircraft, aircraft.route.waypoints )) aircraft.route.waypoints = [ #aircraft.hub, aircraft.hookoff_point, aircraft.destination] aircraft.route.init_segments() p('Adjusted waypoints of %s. New waypoints: %s' % ( aircraft, aircraft.route.waypoints )) p('Need to calibrate aircraft %s (%s) in formation %s' % ( aircraft, aircraft.route, formation )) aircraft.controller.calibrate()
def execute(): models = { '777': { 'V': 500, 'c_T': .56, 'L_D': 19.26, 'MTOW': 200000 }, '767': { 'V': 500, 'c_T': .54, 'L_D': 17, 'MTOW': 190000 }, '330': { 'V': 500, 'c_T': .54, 'L_D': 17, 'MTOW': 190000 }, '340': { 'V': 500, 'c_T': .54, 'L_D': 17, 'MTOW': 250000 } } formation = [{ 'aircraft': '777', 'route': Route([Waypoint('DUS'), Waypoint('IAD')]), 'discount': 0, }, { 'aircraft': '777', 'route': Route([Waypoint('BRU'), Waypoint('ORD')]), 'discount': config.alpha }, { 'aircraft': '777', 'route': Route([Waypoint('AMS'), Waypoint('IAH')]), 'discount': config.alpha }] solo = [{ 'aircraft': '777', 'route': Route([Waypoint('LHR'), Waypoint('ATL')]) }, { 'aircraft': '777', 'route': Route([Waypoint('FRA'), Waypoint('SFO')]) }] hub = get_hub(formation + solo) benchmark = copy.deepcopy(formation) + copy.deepcopy(solo) trunk_route = get_trunk_route(hub, formation) print trunk_route # Origin to TOC d_0 = 100 # Exit to TOD d_3 = 0 # TOD to Destination d_4 = 150 F_formation = 0 for flight in formation: # Direct great circle connection d_direct = flight['route'].get_length() # Distance from origin to hub origin_to_hub = Route([flight['route'].waypoints[0], hub]) d_origin_to_hub = origin_to_hub.get_length() # TOC to hub d_1 = d_origin_to_hub - d_0 # Hub to exit exit_point = get_exit(hub, trunk_route, flight) hub_to_exit = Segment(hub, exit_point) d_2 = hub_to_exit.get_length() # Exit to TOD exit_to_dest = Segment(exit_point, flight['route'].waypoints[-1]) d_3 = exit_to_dest.get_length() - d_4 flight['f'] = fuel_per_stage(d_1, d_2, models[flight['aircraft']], flight['discount']) flight['d'] = [d_0, d_1, d_2, d_3, d_4] F_formation += sum(flight['f']) print 'formation fuel burn: %.2f' % (F_formation) # Origin to TOC d_0 = 100 # Exit to TOD d_3 = 0 # TOD to Destination d_4 = 150 F_solo = 0 for flight in solo: # Total route length full_route = Route([ flight['route'].waypoints[0], hub, flight['route'].waypoints[-1], ]) d_total = full_route.get_length() # Distance from origin to hub origin_to_hub = Route([flight['route'].waypoints[0], hub]) d_origin_to_hub = origin_to_hub.get_length() # TOC to hub d_1 = d_origin_to_hub - d_0 # Hub to TOD (not to exit point) d_2 = d_total - d_0 - d_1 - d_4 flight['f'] = fuel_per_stage(d_1, d_2, models[flight['aircraft']]) flight['d'] = [d_0, d_1, d_2, d_3, d_4] F_solo += sum(flight['f']) print 'solo fuel burn: %.2f' % (F_solo) F_b = 0 for flight in benchmark: # In the benchmark scenario, fly directly from origin to destination d_1 = flight['route'].get_length() - d_0 - d_4 d_2 = 0 flight['f'] = fuel_per_stage(d_1, d_2, models[flight['aircraft']]) flight['d'] = [d_0, d_1, d_2, d_3, d_4] F_b += sum(flight['f']) #def temp(): print 'benchmark fuel burn: %.2f' % (F_b) F_s = 100 * (F_b - (F_formation + F_solo)) / F_b print 'fuel saved: %.2f%%' % F_s print '--DISTANCE: formation flying scenario--' for i in [0, 1, 2, 3, 4]: row = r'$d_i^%d$' % i for flight in formation + solo: row += ' & %d' % flight['d'][i] row += r' \\' print row print r'\hline' row = r'$\sum$' for flight in formation + solo: row += ' & %d' % sum(flight['d']) row += r' \\' print row print '--DISTANCE: benchmark scenario--' for i in [0, 1, 2, 3, 4]: row = r'$F_i^%d$' % i for flight in benchmark: row += ' & %d' % flight['d'][i] row += r' \\' print row print r'\hline' row = r'$\sum$' for flight in benchmark: row += ' & %d' % sum(flight['d']) row += r' \\' print row print '--FUEL: formation flying scenario--' for i in [0, 1, 2, 3, 4]: row = r'$F_i^%d$' % i for flight in formation + solo: row += ' & %d' % flight['f'][i] row += r' \\' print row print r'\hline' row = r'$\sum$' for flight in formation + solo: row += ' & %d' % sum(flight['f']) row += r' \\' print row print '--FUEL: benchmark scenario--' for i in [0, 1, 2, 3, 4]: row = r'$F_i^%d$' % i for flight in benchmark: row += ' & %d' % flight['f'][i] row += r' \\' print row print r'\hline' row = r'$\sum$' for flight in benchmark: row += ' & %d' % sum(flight['f']) row += r' \\' print row S_d = ( formation[0]['d'][2] +\ formation[1]['d'][2] +\ formation[2]['d'][2] )/( sum(formation[0]['d']) +\ sum(formation[1]['d']) +\ sum(formation[2]['d']) +\ sum(solo[0]['d']) +\ sum(solo[1]['d']) ) F_s = 1 - ( sum(formation[0]['f']) +\ sum(formation[1]['f']) +\ sum(formation[2]['f']) +\ sum(solo[0]['f']) +\ sum(solo[1]['f']) )/( sum(benchmark[0]['f']) +\ sum(benchmark[1]['f']) +\ sum(benchmark[2]['f']) +\ sum(benchmark[3]['f']) +\ sum(benchmark[4]['f']) ) p_tot = ( sum(formation[0]['d']) +\ sum(formation[1]['d']) +\ sum(formation[2]['d']) +\ sum(solo[0]['d']) +\ sum(solo[1]['d']) )/( sum(benchmark[0]['d']) +\ sum(benchmark[1]['d']) +\ sum(benchmark[2]['d']) +\ sum(benchmark[3]['d']) +\ sum(benchmark[4]['d']) ) - 1 print '--ANALYTICAL OUTPUT RESULTS--' print r'$S_f$ & 0.6 & 0.6 \\' print r'$S_d$ & %.4f & %.4f \\' % (S_d, S_d) print r'$F_s$ & FILLIN & FILLIN \\' print r'$F^{rel}_s$ & %.4f & %.4f \\' % (F_s, F_s) print r'$p_{tot}$ & %.4f & %.4f \\' % (p_tot, p_tot)
def execute(): models = { '777' : { 'V' : 500, 'c_T' : .56, 'L_D' : 19.26, 'MTOW' : 200000 }, '767' : { 'V' : 500, 'c_T' : .54, 'L_D' : 17, 'MTOW' : 190000 }, '330' : { 'V' : 500, 'c_T' : .54, 'L_D' : 17, 'MTOW' : 190000 }, '340' : { 'V' : 500, 'c_T' : .54, 'L_D' : 17, 'MTOW' : 250000 } } formation = [{ 'aircraft' : '777', 'route' : Route([Waypoint('DUS'), Waypoint('IAD')]), 'discount' : 0, },{ 'aircraft' : '777', 'route' : Route([Waypoint('BRU'), Waypoint('ORD')]), 'discount' : config.alpha },{ 'aircraft' : '777', 'route' : Route([Waypoint('AMS'), Waypoint('IAH')]), 'discount' : config.alpha }] solo = [{ 'aircraft' : '777', 'route' : Route([Waypoint('LHR'), Waypoint('ATL')]) },{ 'aircraft' : '777', 'route' : Route([Waypoint('FRA'), Waypoint('SFO')]) }] hub = get_hub(formation + solo) benchmark = copy.deepcopy(formation) + copy.deepcopy(solo) trunk_route = get_trunk_route(hub, formation) print trunk_route # Origin to TOC d_0 = 100 # Exit to TOD d_3 = 0 # TOD to Destination d_4 = 150 F_formation = 0 for flight in formation: # Direct great circle connection d_direct = flight['route'].get_length() # Distance from origin to hub origin_to_hub = Route([flight['route'].waypoints[0], hub]) d_origin_to_hub = origin_to_hub.get_length() # TOC to hub d_1 = d_origin_to_hub - d_0 # Hub to exit exit_point = get_exit(hub, trunk_route, flight) hub_to_exit = Segment(hub, exit_point) d_2 = hub_to_exit.get_length() # Exit to TOD exit_to_dest = Segment(exit_point, flight['route'].waypoints[-1]) d_3 = exit_to_dest.get_length() - d_4 flight['f'] = fuel_per_stage( d_1, d_2, models[flight['aircraft']], flight['discount'] ) flight['d'] = [d_0, d_1, d_2, d_3, d_4] F_formation += sum(flight['f']) print 'formation fuel burn: %.2f' % (F_formation) # Origin to TOC d_0 = 100 # Exit to TOD d_3 = 0 # TOD to Destination d_4 = 150 F_solo = 0 for flight in solo: # Total route length full_route = Route([ flight['route'].waypoints[0], hub, flight['route'].waypoints[-1], ]) d_total = full_route.get_length() # Distance from origin to hub origin_to_hub = Route([flight['route'].waypoints[0], hub]) d_origin_to_hub = origin_to_hub.get_length() # TOC to hub d_1 = d_origin_to_hub - d_0 # Hub to TOD (not to exit point) d_2 = d_total - d_0 - d_1 - d_4 flight['f'] = fuel_per_stage( d_1, d_2, models[flight['aircraft']] ) flight['d'] = [d_0, d_1, d_2, d_3, d_4] F_solo += sum(flight['f']) print 'solo fuel burn: %.2f' % (F_solo) F_b = 0 for flight in benchmark: # In the benchmark scenario, fly directly from origin to destination d_1 = flight['route'].get_length() - d_0 - d_4 d_2 = 0 flight['f'] = fuel_per_stage( d_1, d_2, models[flight['aircraft']] ) flight['d'] = [d_0, d_1, d_2, d_3, d_4] F_b += sum(flight['f']) #def temp(): print 'benchmark fuel burn: %.2f' % (F_b) F_s = 100 * (F_b - (F_formation + F_solo)) / F_b print 'fuel saved: %.2f%%' % F_s print '--DISTANCE: formation flying scenario--' for i in [0,1,2,3,4]: row = r'$d_i^%d$' % i for flight in formation + solo: row += ' & %d' % flight['d'][i] row += r' \\' print row print r'\hline' row = r'$\sum$' for flight in formation + solo: row += ' & %d' % sum(flight['d']) row += r' \\' print row print '--DISTANCE: benchmark scenario--' for i in [0,1,2,3,4]: row = r'$F_i^%d$' % i for flight in benchmark: row += ' & %d' % flight['d'][i] row += r' \\' print row print r'\hline' row = r'$\sum$' for flight in benchmark: row += ' & %d' % sum(flight['d']) row += r' \\' print row print '--FUEL: formation flying scenario--' for i in [0,1,2,3,4]: row = r'$F_i^%d$' % i for flight in formation + solo: row += ' & %d' % flight['f'][i] row += r' \\' print row print r'\hline' row = r'$\sum$' for flight in formation + solo: row += ' & %d' % sum(flight['f']) row += r' \\' print row print '--FUEL: benchmark scenario--' for i in [0,1,2,3,4]: row = r'$F_i^%d$' % i for flight in benchmark: row += ' & %d' % flight['f'][i] row += r' \\' print row print r'\hline' row = r'$\sum$' for flight in benchmark: row += ' & %d' % sum(flight['f']) row += r' \\' print row S_d = ( formation[0]['d'][2] +\ formation[1]['d'][2] +\ formation[2]['d'][2] )/( sum(formation[0]['d']) +\ sum(formation[1]['d']) +\ sum(formation[2]['d']) +\ sum(solo[0]['d']) +\ sum(solo[1]['d']) ) F_s = 1 - ( sum(formation[0]['f']) +\ sum(formation[1]['f']) +\ sum(formation[2]['f']) +\ sum(solo[0]['f']) +\ sum(solo[1]['f']) )/( sum(benchmark[0]['f']) +\ sum(benchmark[1]['f']) +\ sum(benchmark[2]['f']) +\ sum(benchmark[3]['f']) +\ sum(benchmark[4]['f']) ) p_tot = ( sum(formation[0]['d']) +\ sum(formation[1]['d']) +\ sum(formation[2]['d']) +\ sum(solo[0]['d']) +\ sum(solo[1]['d']) )/( sum(benchmark[0]['d']) +\ sum(benchmark[1]['d']) +\ sum(benchmark[2]['d']) +\ sum(benchmark[3]['d']) +\ sum(benchmark[4]['d']) ) - 1 print '--ANALYTICAL OUTPUT RESULTS--' print r'$S_f$ & 0.6 & 0.6 \\' print r'$S_d$ & %.4f & %.4f \\' % (S_d, S_d) print r'$F_s$ & FILLIN & FILLIN \\' print r'$F^{rel}_s$ & %.4f & %.4f \\' % (F_s, F_s) print r'$p_{tot}$ & %.4f & %.4f \\' % (p_tot, p_tot)
def calibrate(self): """Determines the trunk route and hookoff points""" # Determine formation trunk route destinations = [] for aircraft in self: destinations.append(aircraft.destination) arrival_midpoint = midpoint(destinations) p('destinations: %s' % destinations) p('midpoint = %s' % arrival_midpoint) hub_to_midpoint = Segment(aircraft.hub, arrival_midpoint) # Determine hookoff point for each aircraft, except the last for aircraft in self: hub_to_destination = Segment(aircraft.hub, aircraft.destination) p('flight %s hub %s to destination: %s' % (aircraft, '%s{%d, %d}' % (aircraft.hub, aircraft.hub.lat, aircraft.hub.lon), aircraft.destination)) p('flight %s hub %s to midpoint: %s' % (aircraft, '%s{%d, %d}' % (aircraft.hub, aircraft.hub.lat, aircraft.hub.lon), arrival_midpoint)) aircraft.hookoff_point = get_hookoff(hub_to_midpoint, aircraft.destination, config.alpha) hub_to_hookoff = Segment(aircraft.hub, aircraft.hookoff_point) aircraft.Q = hub_to_hookoff.get_length() /\ hub_to_midpoint.get_length() p('flight %s, hub %s to hook-off point: %s' % (aircraft, '%s{%d, %d}' % (aircraft.hub, aircraft.hub.lat, aircraft.hub.lon), aircraft.hookoff_point)) aircraft.hookoff_point.name = 'hookoff-%s' % aircraft.hookoff_point # Place aircraft in order, ascending with Q, to fulfill LIFO condition. formation = sorted(self, key=lambda item: item.Q) # All aircraft at the front of the formation having the same destination # should hook off where the previous buddy (having a different # destination) hooked off. # Example: formation AMS-SFO, BRU-SFO, LHR-ATL. # AMS-SFO and BRU-SFO should hook off where LHR-ATL hooked off. # @todo Let AMS-SFO and BRU-SFO continue together along a new average # formation trajectory (in this case directly to the destination) # First find the leading set of aircraft having the same destination formation.reverse() leading_destination = formation[0].destination leaders = [] for aircraft in formation: # Start with always incurring benefits aircraft.incurs_benefits = True if not aircraft.destination.coincides(leading_destination): aircraft.is_leader = False continue aircraft.is_leader = True # Only the first leader incurs no benefits at all if len(leaders) == 0: aircraft.incurs_benefits = False leaders.append(aircraft) p('Leaders of formation %s are %s' % (formation, leaders)) # Then find the buddy just before the set of leading aircraft, if # it exists. try: # The leaders: same hookoff point as last buddy. last_buddy = formation[len(leaders)] for aircraft in leaders: aircraft.Q = last_buddy.Q #aircraft.P = last_buddy.P aircraft.hookoff_point = last_buddy.hookoff_point except IndexError: pass # Change reversed formation back to normal formation.reverse() for aircraft in formation: p('Adjusting waypoints of %s. Initial waypoints: %s' % (aircraft, aircraft.route.waypoints)) aircraft.route.waypoints = [ #aircraft.hub, aircraft.hookoff_point, aircraft.destination ] aircraft.route.init_segments() p('Adjusted waypoints of %s. New waypoints: %s' % (aircraft, aircraft.route.waypoints)) p('Need to calibrate aircraft %s (%s) in formation %s' % (aircraft, aircraft.route, formation)) aircraft.controller.calibrate()