#!/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.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 = {} self.WeatherModel = WeatherModel(configuration.GaforId, weather) 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 % 10): continue # request the current configuration from the server and update it, if useful newConfig = self.WebUi.requestConfiguration(self.Icao, self.Configuration.GngData) if None != newConfig: self.sequencingConfiguration = newConfig 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.PerformanceData) Node(inbound, inbound.ReportTime, self.WeatherModel, self.Configuration.GngData, 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] = inbound # configure the ACO run acoConfig = Configuration(constraints = self.SequencingConfiguration, nav = self.Configuration.GngData, 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 inbound in aco.Result: self.RecedingHorizonControl.resequenceInbound(inbound) print('Delays: FCFS=' + str(aco.FcfsDelay.total_seconds()) + ', ACO=' + str(aco.ResultDelay.total_seconds())) # measure the exuction time of the overall optimization process print('Execution time: ' + str(time.process_time() - start) + ' seconds') else: print('No relevant inbounds found for the optimization in ' + self.Icao) # send the sequence to the GUI and Euroscope sequence = self.RecedingHorizonControl.sequence() self.Euroscope.sendSequence(self.Icao, sequence, self.WeatherModel) self.releaseLock()