141 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			141 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/env python
 | |
| 
 | |
| from threading import Thread, Lock
 | |
| import sys
 | |
| import time
 | |
| 
 | |
| from aman.com import Weather
 | |
| from aman.com.Euroscope import Euroscope
 | |
| from aman.config.Airport import Airport
 | |
| from aman.config.AirportSequencing import AirportSequencing
 | |
| from aman.sys.aco.Colony import Colony
 | |
| from aman.sys.aco.Configuration import Configuration
 | |
| from aman.sys.aco.Node import Node
 | |
| 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, icao : str, configuration : Airport, weather : Weather,
 | |
|                  performance : PerformanceData, euroscope : Euroscope):
 | |
|         Thread.__init__(self)
 | |
|         self.StopThread = None
 | |
|         self.Icao = icao
 | |
|         self.Configuration = configuration
 | |
|         self.SequencingConfiguration = configuration.DefaultSequencing
 | |
|         self.PerformanceData = performance
 | |
|         self.UpdateLock = Lock()
 | |
|         self.ReportQueue = {}
 | |
|         if None != weather:
 | |
|             self.WeatherModel = WeatherModel(configuration.GaforId, weather)
 | |
|         else:
 | |
|             self.WeatherModel = WeatherModel(0, None)
 | |
|         self.RecedingHorizonControl = RecedingHorizonControl(configuration.RecedingHorizonControl)
 | |
|         self.Euroscope = euroscope
 | |
| 
 | |
|         # 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.setDaemon(True)
 | |
|         self.start()
 | |
| 
 | |
|     def acquireLock(self):
 | |
|         if None != self.UpdateLock:
 | |
|             self.UpdateLock.acquire()
 | |
| 
 | |
|     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 % 60):
 | |
|                 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 '' != report.initialApproachFix:
 | |
|                     inbound = Inbound(report, self.PerformanceData)
 | |
|                     Node(inbound, inbound.ReportTime, self.WeatherModel, self.Configuration, self.SequencingConfiguration)
 | |
|                     if None != inbound.InitialArrivalTime:
 | |
|                         self.RecedingHorizonControl.updateReport(inbound)
 | |
|                     else:
 | |
|                         print('Unable to find all data of ' + report.aircraft.callsign)
 | |
| 
 | |
|             self.ReportQueue.clear()
 | |
| 
 | |
|             # search the ACO relevant aircrafts
 | |
|             relevantInbounds, earliestArrivalTime = self.RecedingHorizonControl.optimizationRelevantInbounds()
 | |
|             if None != relevantInbounds:
 | |
|                 start = time.process_time()
 | |
| 
 | |
|                 # 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] = Node(inbound, None, None, None, None)
 | |
| 
 | |
|                 # configure the ACO run
 | |
|                 acoConfig = Configuration(constraints = self.SequencingConfiguration, config = self.Configuration,
 | |
|                                           earliest = earliestArrivalTime, weather = self.WeatherModel,
 | |
|                                           preceeding = None if 0 == len(preceedingInbounds) else preceedingInbounds,
 | |
|                                           ants = 5 * len(relevantInbounds), generations = 5 * len(relevantInbounds))
 | |
| 
 | |
|                 # perform the ACO run
 | |
|                 aco = Colony(relevantInbounds, acoConfig)
 | |
|                 aco.optimize()
 | |
|                 if None != aco.Result:
 | |
|                     for node in aco.Result:
 | |
|                         self.RecedingHorizonControl.resequenceInbound(node.Inbound)
 | |
| 
 | |
|                 # measure the exuction time of the overall optimization process
 | |
|                 executionTime = time.process_time() - start
 | |
|                 if 60.0 <= executionTime:
 | |
|                     print('Optimized ' + str(len(aco.Result)) + ' inbounds in ' + str(executionTime) + ' seconds')
 | |
| 
 | |
|             self.releaseLock()
 | |
| 
 | |
|     def inboundSequence(self):
 | |
|         self.acquireLock()
 | |
|         sequence = self.RecedingHorizonControl.sequence()
 | |
|         self.releaseLock()
 | |
|         return sequence
 | |
| 
 | |
|     def configure(self, configuration : AirportSequencing):
 | |
|         self.acquireLock()
 | |
|         self.SequencingConfiguration = configuration
 | |
|         self.releaseLock()
 |