134 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			134 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/env python
 | |
| 
 | |
| from threading import Thread, Lock
 | |
| import sys
 | |
| import time
 | |
| 
 | |
| from aman.com import Weather
 | |
| from aman.config.Airport import Airport
 | |
| from aman.sys.aco.Configuration import Configuration
 | |
| from aman.sys.WeatherModel import WeatherModel
 | |
| from aman.sys.RecedingHorizonControl import RecedingHorizonControl
 | |
| from aman.types.Inbound import Inbound
 | |
| from aman.types.PerformanceData import PerformanceData
 | |
| 
 | |
| class Worker(Thread):
 | |
|     def __init__(self):
 | |
|         Thread.__init__(self)
 | |
|         self.StopThread = None
 | |
|         self.Icao = None
 | |
|         self.Configuration = None
 | |
|         self.PerformanceData = None
 | |
|         self.UpdateLock = None
 | |
|         self.ReportQueue = {}
 | |
|         self.WeatherModel = None
 | |
|         self.RecedingHorizonControl = None
 | |
| 
 | |
|     def __del__(self):
 | |
|         self.release()
 | |
| 
 | |
|     def acquire(self, icao : str, configuration : Airport, weather : Weather, performance : PerformanceData):
 | |
|         self.StopThread = None
 | |
|         self.Icao = icao
 | |
|         self.Configuration = configuration
 | |
|         self.sequencingConfiguration = configuration.DefaultSequencing
 | |
|         self.PerformanceData = performance
 | |
|         self.UpdateLock = Lock()
 | |
|         self.ReportQueue = {}
 | |
|         self.WeatherModel = WeatherModel(configuration.GaforId, weather)
 | |
|         self.RecedingHorizonControl = RecedingHorizonControl(configuration.RecedingHorizonControl)
 | |
| 
 | |
|         # merge the constraint information with the GNG information
 | |
|         for runway in self.Configuration.GngData.ArrivalRoutes:
 | |
|             for star in self.Configuration.GngData.ArrivalRoutes[runway]:
 | |
|                 for name in self.Configuration.ArrivalRouteConstraints:
 | |
|                     if name == star.Name:
 | |
|                         for constraint in self.Configuration.ArrivalRouteConstraints[name]:
 | |
|                             foundWaypoint = False
 | |
| 
 | |
|                             for waypoint in star.Route:
 | |
|                                 if constraint.Name == waypoint.Name:
 | |
|                                     waypoint.Altitude = constraint.Altitude
 | |
|                                     waypoint.Speed = constraint.Speed
 | |
|                                     waypoint.BaseTurn = constraint.BaseTurn
 | |
|                                     waypoint.FinalTurn = constraint.FinalTurn
 | |
|                                     foundWaypoint = True
 | |
|                                     break
 | |
| 
 | |
|                             if False == foundWaypoint:
 | |
|                                 sys.stderr.write('Unable to find ' + constraint.Name + ' in ' + name)
 | |
|                                 sys.exit(-1)
 | |
|                         break
 | |
| 
 | |
|         self.start()
 | |
| 
 | |
|     def acquireLock(self):
 | |
|         if None != self.UpdateLock:
 | |
|             self.UpdateLock.acquire()
 | |
| 
 | |
|     def release(self):
 | |
|         self.StopThread = True
 | |
|         self.join()
 | |
| 
 | |
|     def releaseLock(self):
 | |
|         if None != self.UpdateLock:
 | |
|             self.UpdateLock.release()
 | |
| 
 | |
|     def run(self):
 | |
|         counter = 0
 | |
| 
 | |
|         while None == self.StopThread:
 | |
|             time.sleep(1)
 | |
|             counter += 1
 | |
|             if 0 != (counter % 10):
 | |
|                 continue
 | |
| 
 | |
|             self.acquireLock()
 | |
| 
 | |
|             # perform some book-keeping
 | |
|             self.RecedingHorizonControl.cleanupWindows()
 | |
| 
 | |
|             # update the aircraft information in RHC
 | |
|             for callsign in self.ReportQueue:
 | |
|                 report = self.ReportQueue[callsign]
 | |
| 
 | |
|                 if 0 != report.distanceToIAF and '' != report.initialApproachFix:
 | |
|                     inbound = Inbound(report, self.sequencingConfiguration, self.Configuration.GngData, self.PerformanceData, self.WeatherModel)
 | |
|                     if None != inbound.PlannedRunway and None != inbound.PlannedStar:
 | |
|                         self.RecedingHorizonControl.update(inbound)
 | |
|                     else:
 | |
|                         print('Unable to find all data of ' + report.aircraft.callsign)
 | |
| 
 | |
|             self.ReportQueue.clear()
 | |
| 
 | |
|             if 0 != len(self.RecedingHorizonControl.Windows):
 | |
|                 print('FCFS run:')
 | |
|                 for window in self.RecedingHorizonControl.Windows:
 | |
|                     for inbound in window.Inbounds:
 | |
|                         print('    ' + inbound.Report.aircraft.callsign + ': ' + str(inbound.EstimatedArrivalTime) + '; ' + str(inbound.EarliestArrivalTime))
 | |
| 
 | |
|             # get the last landing aircrafts per runway before the RHC stage to check for constraints
 | |
|             # this is required to handle the overlap between windows
 | |
|             preceedingInbounds = {}
 | |
|             for runway in self.sequencingConfiguration.ActiveArrivalRunways:
 | |
|                 inbound = self.RecedingHorizonControl.lastFixedInboundOnRunway(runway.Runway.Name)
 | |
|                 if None != inbound:
 | |
|                     preceedingInbounds[runway.Runway.Name] = inbound
 | |
| 
 | |
|             # search the ACO relevant aircrafts
 | |
|             relevantInbounds = self.RecedingHorizonControl.optimizationRelevantInbounds()
 | |
|             if None != relevantInbounds:
 | |
|                 print('Relevant inbounds: ' + str(len(relevantInbounds)))
 | |
| 
 | |
|                 # configure the ACO run
 | |
|                 acoConfig = Configuration(self.sequencingConfiguration, 5 * len(relevantInbounds), 5 * len(relevantInbounds))
 | |
|                 if 0 != len(preceedingInbounds):
 | |
|                     acoConfig.PreceedingInbounds = preceedingInbounds
 | |
|                 acoConfig.Inbounds = relevantInbounds
 | |
|                 # TODO perform the ACO run
 | |
|                 # TODO update the RHC stages based on the ACO run result
 | |
|             else:
 | |
|                 print('No relevant inbounds found for the optimization in ' + self.Icao)
 | |
| 
 | |
|             self.releaseLock()
 |