RunwayManager.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. #!/usr/bin/env python
  2. from datetime import datetime, timedelta
  3. from aman.config.RunwaySequencing import RunwayAssignmentType
  4. from aman.sys.aco.Configuration import Configuration
  5. from aman.sys.aco.Constraints import SpacingConstraints
  6. from aman.sys.aco.Node import Node
  7. class RunwayManager:
  8. def __init__(self, configuration : Configuration):
  9. self.Spacings = SpacingConstraints()
  10. self.Configuration = configuration
  11. # initialize the tracker which inbound arrives at which runway
  12. self.RunwayInbounds = {}
  13. if None != configuration.PreceedingInbounds:
  14. for runway in configuration.PreceedingInbounds:
  15. self.RunwayInbounds[runway] = configuration.PreceedingInbounds[runway]
  16. for runway in configuration.RunwayConstraints.ActiveArrivalRunways:
  17. if not runway.Runway.Name in self.RunwayInbounds:
  18. self.RunwayInbounds[runway.Runway.Name] = None
  19. def calculateEarliestArrivalTime(self, runway : str, node : Node, useETA : bool, earliestArrivalTime : datetime):
  20. constrainedETA = None
  21. if None != self.RunwayInbounds[runway]:
  22. # get the WTC based ETA
  23. if None == self.RunwayInbounds[runway].Inbound.WTC or None == node.Inbound.WTC:
  24. spacingWTC = 3
  25. else:
  26. spacingWTC = self.Spacings[self.RunwayInbounds[runway].Inbound.WTC][node.Inbound.WTC]
  27. # get the runway time spacing
  28. spacingRunway = self.Configuration.RunwayConstraints.findRunway(runway).Spacing
  29. constrainedETA = self.RunwayInbounds[runway].Inbound.PlannedArrivalTime + timedelta(minutes = max(spacingWTC, spacingRunway) / (node.Inbound.PerformanceData.SpeedApproach / 60))
  30. # calculate the arrival times for the dependent inbounds
  31. for dependentRunway in self.Configuration.RunwayConstraints.findDependentRunways(runway):
  32. if None != self.RunwayInbounds[dependentRunway.Runway.Name]:
  33. # TODO staggered spacing variabel
  34. candidate = self.RunwayInbounds[dependentRunway.Runway.Name].Inbound.PlannedArrivalTime + timedelta(minutes = 3 / (node.Inbound.PerformanceData.SpeedApproach / 60))
  35. if None == constrainedETA or candidate > constrainedETA:
  36. constrainedETA = candidate
  37. # get the arrival time on the runway of the inbound
  38. if True == useETA:
  39. arrivalTime = node.ArrivalCandidates[runway].EarliestArrivalTime
  40. else:
  41. arrivalTime = node.ArrivalCandidates[runway].InitialArrivalTime
  42. if None == constrainedETA:
  43. return max(arrivalTime, earliestArrivalTime), timedelta(seconds = 0)
  44. else:
  45. eta = max(constrainedETA, earliestArrivalTime)
  46. if eta < arrivalTime:
  47. return arrivalTime, arrivalTime - eta
  48. else:
  49. return eta, timedelta(seconds = 0)
  50. def selectShallShouldMayArrivalRunway(self, node : Node, runways, useETA : bool, earliestArrivalTime : datetime):
  51. candidate = None
  52. delay = None
  53. for runway in runways:
  54. if True == useETA:
  55. reference = node.ArrivalCandidates[runway.Runway.Name].EarliestArrivalTime
  56. else:
  57. reference = node.ArrivalCandidates[runway.Runway.Name].InitialArrivalTime
  58. eta, _ = self.calculateEarliestArrivalTime(runway.Runway.Name, node)
  59. if None == delay:
  60. delay = eta - reference
  61. candidate = runway
  62. elif delay > (eta - reference):
  63. delay = eta- reference
  64. candidate = runway
  65. return candidate
  66. def executeShallShouldMayAssignment(self, node : Node, useETA : bool, earliestArrivalTime : datetime):
  67. shallRunways = []
  68. shouldRunways = []
  69. mayRunways = []
  70. for runway in self.Configuration.RunwayConstraints.ActiveArrivalRunways:
  71. # test the shall assignments
  72. if RunwayAssignmentType.AircraftType in runway.ShallAssignments:
  73. if node.Inbound.Report.aircraft.type in runway.ShallAssignments[RunwayAssignmentType.AircraftType]:
  74. shallRunways.append(runway)
  75. if RunwayAssignmentType.GateAssignment in runway.ShallAssignments:
  76. if node.Inbound.Report.plannedGate in runway.ShallAssignments[RunwayAssignmentType.GateAssignment]:
  77. shallRunways.append(runway)
  78. # test the should assignments
  79. if RunwayAssignmentType.AircraftType in runway.ShouldAssignments:
  80. if node.Inbound.Report.aircraft.type in runway.ShouldAssignments[RunwayAssignmentType.AircraftType]:
  81. shouldRunways.append(runway)
  82. if RunwayAssignmentType.GateAssignment in runway.ShouldAssignments:
  83. if node.Inbound.Report.plannedGate in runway.ShouldAssignments[RunwayAssignmentType.GateAssignment]:
  84. shouldRunways.append(runway)
  85. if True == useETA:
  86. reference = node.ArrivalCandidates[runway.Runway.Name].EarliestArrivalTime
  87. else:
  88. reference = node.ArrivalCandidates[runway.Runway.Name].InitialArrivalTime
  89. # test the may assignments
  90. if RunwayAssignmentType.AircraftType in runway.MayAssignments:
  91. if node.Inbound.Report.aircraft.type in runway.MayAssignments[RunwayAssignmentType.AircraftType]:
  92. eta, _ = self.calculateEarliestArrivalTime(runway.Runway.Name, node, useETA, earliestArrivalTime)
  93. if (eta - reference) <= self.Configuration.MaxDelayMay:
  94. mayRunways.append(runway)
  95. if RunwayAssignmentType.GateAssignment in runway.MayAssignments:
  96. if node.Inbound.Report.plannedGate in runway.MayAssignments[RunwayAssignmentType.GateAssignment]:
  97. eta, _ = self.calculateEarliestArrivalTime(runway.Runway.Name, node, useETA, earliestArrivalTime)
  98. if (eta - reference) <= self.Configuration.MaxDelayMay:
  99. mayRunways.append(runway)
  100. runway = self.selectShallShouldMayArrivalRunway(node, shallRunways, useETA, earliestArrivalTime)
  101. if None != runway:
  102. return [ runway ]
  103. runway = self.selectShallShouldMayArrivalRunway(node, shouldRunways, useETA, earliestArrivalTime)
  104. if None != runway:
  105. return [ runway ]
  106. runway = self.selectShallShouldMayArrivalRunway(node, mayRunways, useETA, earliestArrivalTime)
  107. if None != runway:
  108. return [ runway ]
  109. return self.Configuration.RunwayConstraints.ActiveArrivalRunways
  110. def selectArrivalRunway(self, node : Node, useETA : bool, earliestArrivalTime : datetime):
  111. availableRunways = self.Configuration.RunwayConstraints.ActiveArrivalRunways
  112. if True == self.Configuration.RunwayConstraints.UseShallShouldMay:
  113. availableRunways = self.executeShallShouldMayAssignment(node, useETA, earliestArrivalTime)
  114. else:
  115. availableRunways = self.Configuration.RunwayConstraints.ActiveArrivalRunways
  116. if 0 == len(availableRunways):
  117. runway = self.Configuration.RunwayConstraints.ActiveArrivalRunways[0]
  118. return runway, self.calculateEarliestArrivalTime(runway.Runway.Name, node, useETA, earliestArrivalTime)
  119. # start with the beginning
  120. selectedRunway = None
  121. lostTime = None
  122. eta = None
  123. # get the runway with the earliest ETA
  124. for runway in availableRunways:
  125. candidate, delta = self.calculateEarliestArrivalTime(runway.Runway.Name, node, useETA, earliestArrivalTime)
  126. if None == eta or eta > candidate:
  127. selectedRunway = runway.Runway
  128. lostTime = delta
  129. eta = candidate
  130. return selectedRunway, eta, lostTime