Worker.py 6.7 KB

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