141 lines
6.0 KiB
Python
141 lines
6.0 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.EnrouteArrivalTime:
|
|
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
|
|
runways, iafs = self.RecedingHorizonControl.latestFixedInbounds(self.Configuration, self.SequencingConfiguration)
|
|
|
|
# configure the ACO run
|
|
acoConfig = Configuration(constraints = self.SequencingConfiguration, config = self.Configuration,
|
|
earliest = earliestArrivalTime, weather = self.WeatherModel,
|
|
preceedingRunways = runways, preceedingIafs = iafs,
|
|
ants = 5 * len(relevantInbounds), generations = 5 * len(relevantInbounds))
|
|
|
|
# run the optimizer outside the locking functions
|
|
self.releaseLock()
|
|
# perform the ACO run
|
|
aco = Colony(relevantInbounds, acoConfig)
|
|
aco.optimize()
|
|
self.acquireLock()
|
|
|
|
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()
|