#!/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.InitialArrivalTime) + '; ' + str(inbound.EarliestArrivalTime)) # search the ACO relevant aircrafts relevantInbounds, earliestArrivalTime = self.RecedingHorizonControl.optimizationRelevantInbounds() if None != relevantInbounds: # 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 print('Relevant inbounds: ' + str(len(relevantInbounds))) # configure the ACO run acoConfig = Configuration(earliestArrivalTime, 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()