Worker.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #!/usr/bin/env python
  2. from threading import Thread, Lock
  3. import sys
  4. import time
  5. from aman.com import Weather
  6. from aman.com.Euroscope import Euroscope
  7. from aman.com.WebUI import WebUI
  8. from aman.config.Airport import Airport
  9. from aman.sys.aco.Colony import Colony
  10. from aman.sys.aco.Configuration import Configuration
  11. from aman.sys.WeatherModel import WeatherModel
  12. from aman.sys.RecedingHorizonControl import RecedingHorizonControl
  13. from aman.types.Inbound import Inbound
  14. from aman.types.PerformanceData import PerformanceData
  15. class Worker(Thread):
  16. def __init__(self):
  17. Thread.__init__(self)
  18. self.StopThread = None
  19. self.Icao = None
  20. self.Configuration = None
  21. self.PerformanceData = None
  22. self.UpdateLock = None
  23. self.ReportQueue = {}
  24. self.WeatherModel = None
  25. self.RecedingHorizonControl = None
  26. self.WebUi = None
  27. def __del__(self):
  28. self.release()
  29. def acquire(self, icao : str, configuration : Airport, weather : Weather,
  30. performance : PerformanceData, webui : WebUI, euroscope : Euroscope):
  31. self.StopThread = None
  32. self.Icao = icao
  33. self.Configuration = configuration
  34. self.sequencingConfiguration = configuration.DefaultSequencing
  35. self.PerformanceData = performance
  36. self.UpdateLock = Lock()
  37. self.ReportQueue = {}
  38. self.WeatherModel = WeatherModel(configuration.GaforId, weather)
  39. self.RecedingHorizonControl = RecedingHorizonControl(configuration.RecedingHorizonControl)
  40. self.WebUi = webui
  41. self.Euroscope = euroscope
  42. # merge the constraint information with the GNG information
  43. for runway in self.Configuration.GngData.ArrivalRoutes:
  44. for star in self.Configuration.GngData.ArrivalRoutes[runway]:
  45. for name in self.Configuration.ArrivalRouteConstraints:
  46. if name == star.Name:
  47. for constraint in self.Configuration.ArrivalRouteConstraints[name]:
  48. foundWaypoint = False
  49. for waypoint in star.Route:
  50. if constraint.Name == waypoint.Name:
  51. waypoint.Altitude = constraint.Altitude
  52. waypoint.Speed = constraint.Speed
  53. waypoint.BaseTurn = constraint.BaseTurn
  54. waypoint.FinalTurn = constraint.FinalTurn
  55. foundWaypoint = True
  56. break
  57. if False == foundWaypoint:
  58. sys.stderr.write('Unable to find ' + constraint.Name + ' in ' + name)
  59. sys.exit(-1)
  60. break
  61. self.start()
  62. def acquireLock(self):
  63. if None != self.UpdateLock:
  64. self.UpdateLock.acquire()
  65. def release(self):
  66. self.StopThread = True
  67. self.join()
  68. def releaseLock(self):
  69. if None != self.UpdateLock:
  70. self.UpdateLock.release()
  71. def run(self):
  72. counter = 0
  73. while None == self.StopThread:
  74. time.sleep(1)
  75. counter += 1
  76. if 0 != (counter % 10):
  77. continue
  78. self.acquireLock()
  79. # perform some book-keeping
  80. self.RecedingHorizonControl.cleanupWindows()
  81. # update the aircraft information in RHC
  82. for callsign in self.ReportQueue:
  83. report = self.ReportQueue[callsign]
  84. if 0 != report.distanceToIAF and '' != report.initialApproachFix:
  85. inbound = Inbound(report, self.sequencingConfiguration, self.Configuration.GngData, self.PerformanceData, self.WeatherModel)
  86. if None != inbound.PlannedRunway and None != inbound.PlannedStar:
  87. self.RecedingHorizonControl.updateReport(inbound)
  88. else:
  89. print('Unable to find all data of ' + report.aircraft.callsign)
  90. self.ReportQueue.clear()
  91. # search the ACO relevant aircrafts
  92. relevantInbounds, earliestArrivalTime = self.RecedingHorizonControl.optimizationRelevantInbounds()
  93. if None != relevantInbounds:
  94. start = time.process_time()
  95. # get the last landing aircrafts per runway before the RHC stage to check for constraints
  96. # this is required to handle the overlap between windows
  97. preceedingInbounds = {}
  98. for runway in self.sequencingConfiguration.ActiveArrivalRunways:
  99. inbound = self.RecedingHorizonControl.lastFixedInboundOnRunway(runway.Runway.Name)
  100. if None != inbound:
  101. preceedingInbounds[runway.Runway.Name] = inbound
  102. # configure the ACO run
  103. acoConfig = Configuration(constraints = self.sequencingConfiguration, inbounds = relevantInbounds,
  104. earliest = earliestArrivalTime, weather = self.WeatherModel,
  105. preceeding = None if 0 == len(preceedingInbounds) else preceedingInbounds,
  106. ants = 5 * len(relevantInbounds), generations = 5 * len(relevantInbounds))
  107. # perform the ACO run
  108. aco = Colony(acoConfig)
  109. aco.optimize()
  110. if None != aco.Result:
  111. for inbound in aco.Result:
  112. self.RecedingHorizonControl.resequenceInbound(inbound)
  113. print('Delays: FCFS=' + str(aco.FcfsDelay.total_seconds()) + ', ACO=' + str(aco.ResultDelay.total_seconds()))
  114. # measure the exuction time of the overall optimization process
  115. print('Execution time: ' + str(time.process_time() - start) + ' seconds')
  116. else:
  117. print('No relevant inbounds found for the optimization in ' + self.Icao)
  118. # send the sequence to the GUI and Euroscope
  119. sequence = self.RecedingHorizonControl.sequence()
  120. self.WebUi.sendSequence(self.Icao, sequence)
  121. self.Euroscope.sendSequence(self.Icao, sequence)
  122. self.releaseLock()