RunwayManager.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. #!/usr/bin/env python
  2. from datetime import timedelta
  3. from aman.sys.aco.Configuration import Configuration
  4. from aman.sys.aco.Constraints import SpacingConstraints
  5. from aman.types.Inbound import Inbound
  6. class RunwayManager:
  7. def __init__(self, configuration : Configuration):
  8. self.Spacings = SpacingConstraints()
  9. self.Configuration = configuration
  10. # initialize the tracker which inbound arrives at which runway
  11. self.RunwayInbounds = {}
  12. if None != configuration.PreceedingInbounds:
  13. for runway in configuration.PreceedingInbounds:
  14. self.RunwayInbounds[runway] = configuration.PreceedingInbounds[runway]
  15. for runway in configuration.RunwayConstraints.ActiveArrivalRunways:
  16. if not runway.Runway.Name in self.RunwayInbounds:
  17. self.RunwayInbounds[runway.Runway.Name] = None
  18. def validateWtc(inbound : Inbound):
  19. wtc = inbound.Report.aircraft.wtc.upper()
  20. if 'L' == wtc or 'M' == wtc or 'H' == None or 'J' == None:
  21. return wtc
  22. else:
  23. return None
  24. def calculateEarliestArrivalTime(self, runway : str, inbound : Inbound):
  25. if None == self.RunwayInbounds[runway]:
  26. return inbound.ArrivalCandidates[runway].EarliestArrivalTime
  27. preceedingInbound = self.RunwayInbounds[runway]
  28. # get the WTC constrained ETA
  29. wtcPre = RunwayManager.validateWtc(preceedingInbound)
  30. wtcThis = RunwayManager.validateWtc(inbound)
  31. if None == wtcPre or None == wtcThis:
  32. spacing = 3
  33. else:
  34. spacing = self.Spacings[wtcPre][wtcThis]
  35. delay = timedelta(minutes = spacing / (inbound.PerformanceData.SpeedApproach / 60))
  36. wtcEarliestArrivalTime = preceedingInbound.PlannedArrivalTime + delay
  37. # get the staggered time spacing
  38. dependentRunway = self.Configuration.RunwayConstraints.findDependentRunway(runway)
  39. if None != dependentRunway and None != self.RunwayInbounds[dependentRunway.Runway.Name]:
  40. # check if the one on the same runway lands before the one on the parallel runway
  41. if preceedingInbound.PlannedArrivalTime < self.RunwayInbounds[dependentRunway.Runway.Name].PlannedArrivalTime:
  42. delay = timedelta(minutes = 3 / (inbound.PerformanceData.SpeedApproach / 60))
  43. staggeredEarliestArrivalTime = self.RunwayInbounds[dependentRunway.Runway.Name].PlannedArrivalTime + delay
  44. # landing on the same runway
  45. else:
  46. staggeredEarliestArrivalTime = wtcEarliestArrivalTime
  47. # no neighbor or no dependent runway (IPA)
  48. else:
  49. staggeredEarliestArrivalTime = wtcEarliestArrivalTime
  50. # get the runway time spacing
  51. spacing = self.Configuration.RunwayConstraints.findRunway(runway).Spacing
  52. delay = timedelta(minutes = spacing / (inbound.PerformanceData.SpeedApproach / 60))
  53. runwayEarliestArrivalTime = preceedingInbound.PlannedArrivalTime + delay
  54. # the candidate with the latest ETA is used -> ensure all safety and procedure constraints
  55. candidate = max(max(wtcEarliestArrivalTime, staggeredEarliestArrivalTime), runwayEarliestArrivalTime)
  56. # check if inbound comes later than the latest possible ETA
  57. if candidate < inbound.ArrivalCandidates[runway].EarliestArrivalTime:
  58. return inbound.ArrivalCandidates[runway].EarliestArrivalTime
  59. # candidate fits into earliest arrival time or is later than this
  60. else:
  61. return candidate
  62. def selectArrivalRunway(self, inbound : Inbound):
  63. availableRunways = []
  64. for runway in self.Configuration.RunwayConstraints.ActiveArrivalRunways:
  65. availableRunways.append(runway)
  66. #if 1 < len(availableRunways):
  67. # TODO filter based on type
  68. # TODO filter based on airline
  69. # ensure that at least one runway is available
  70. # fallback to check if we have available runways
  71. if 0 == len(availableRunways):
  72. runway = self.Configuration.RunwayConstraints.ActiveArrivalRunways[0]
  73. return runway, self.calculateEarliestArrivalTime(runway.Runway.Name, inbound)
  74. # start with the beginning
  75. selectedRunway = None
  76. eta = None
  77. # get the runway with the earliest ETA
  78. for runway in availableRunways:
  79. candidate = self.calculateEarliestArrivalTime(runway.Runway.Name, inbound)
  80. if None == eta or eta > candidate:
  81. selectedRunway = runway.Runway
  82. eta = candidate
  83. return selectedRunway, eta