RunwayManager.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. #!/usr/bin/env python
  2. import copy
  3. from datetime import datetime, timedelta
  4. from aman.config.RunwaySequencing import RunwayAssignmentType
  5. from aman.sys.aco.Configuration import Configuration
  6. from aman.sys.aco.Constraints import SpacingConstraints
  7. from aman.sys.aco.Node import Node
  8. class RunwayManager:
  9. def __init__(self, configuration : Configuration):
  10. self.Spacings = SpacingConstraints()
  11. self.Configuration = configuration
  12. self.RunwayInbounds = copy.deepcopy(configuration.PreceedingRunwayInbounds)
  13. self.IafInbounds = copy.deepcopy(configuration.PreceedingIafInbounds)
  14. def calculateEarliestArrivalTime(self, runway : str, node : Node, earliestArrivalTime : datetime):
  15. constrainedETA = None
  16. if None != self.RunwayInbounds[runway]:
  17. # get the WTC based ETA
  18. if None == self.RunwayInbounds[runway].Inbound.WTC or None == node.Inbound.WTC:
  19. spacingWTC = 3
  20. else:
  21. if self.RunwayInbounds[runway].Inbound.WTC not in self.Spacings.WtcSpacing:
  22. spacingWTC = 3
  23. elif node.Inbound.WTC not in self.Spacings.WtcSpacing[self.RunwayInbounds[runway].Inbound.WTC]:
  24. spacingWTC = self.Spacings.WtcSpacing[self.RunwayInbounds[runway].Inbound.WTC]['L']
  25. else:
  26. spacingWTC = self.Spacings.WtcSpacing[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. candidate = self.RunwayInbounds[dependentRunway.Runway.Name].Inbound.PlannedArrivalTime + timedelta(minutes = 3 / (node.Inbound.PerformanceData.SpeedApproach / 60))
  34. if None == constrainedETA or candidate > constrainedETA:
  35. constrainedETA = candidate
  36. if None == constrainedETA:
  37. eta = max(node.ArrivalCandidates[runway].InitialArrivalTime, earliestArrivalTime)
  38. else:
  39. eta = max(node.ArrivalCandidates[runway].InitialArrivalTime, max(constrainedETA, earliestArrivalTime))
  40. return eta, eta - node.ArrivalCandidates[runway].InitialArrivalTime
  41. def selectShallShouldMayArrivalRunway(self, node : Node, runways, earliestArrivalTime : datetime):
  42. candidate = None
  43. delay = None
  44. for runway in runways:
  45. eta, _ = self.calculateEarliestArrivalTime(runway.Runway.Name, node, earliestArrivalTime)
  46. if None == delay:
  47. delay = eta - node.ArrivalCandidates[runway.Runway.Name].InitialArrivalTime
  48. candidate = runway
  49. elif delay > (eta - node.ArrivalCandidates[runway.Runway.Name].InitialArrivalTime):
  50. delay = eta- node.ArrivalCandidates[runway.Runway.Name].InitialArrivalTime
  51. candidate = runway
  52. return candidate
  53. def executeShallShouldMayAssignment(self, node : Node, earliestArrivalTime : datetime):
  54. shallRunways = []
  55. shouldRunways = []
  56. mayRunways = []
  57. for runway in self.Configuration.RunwayConstraints.ActiveArrivalRunways:
  58. # test the shall assignments
  59. if RunwayAssignmentType.AircraftType in runway.ShallAssignments:
  60. if node.Inbound.Report.aircraft.type in runway.ShallAssignments[RunwayAssignmentType.AircraftType]:
  61. shallRunways.append(runway)
  62. if RunwayAssignmentType.GateAssignment in runway.ShallAssignments:
  63. if node.Inbound.Report.plannedGate in runway.ShallAssignments[RunwayAssignmentType.GateAssignment]:
  64. shallRunways.append(runway)
  65. # test the should assignments
  66. if RunwayAssignmentType.AircraftType in runway.ShouldAssignments:
  67. if node.Inbound.Report.aircraft.type in runway.ShouldAssignments[RunwayAssignmentType.AircraftType]:
  68. shouldRunways.append(runway)
  69. if RunwayAssignmentType.GateAssignment in runway.ShouldAssignments:
  70. if node.Inbound.Report.plannedGate in runway.ShouldAssignments[RunwayAssignmentType.GateAssignment]:
  71. shouldRunways.append(runway)
  72. # test the may assignments
  73. if RunwayAssignmentType.AircraftType in runway.MayAssignments:
  74. if node.Inbound.Report.aircraft.type in runway.MayAssignments[RunwayAssignmentType.AircraftType]:
  75. eta, _ = self.calculateEarliestArrivalTime(runway.Runway.Name, node, earliestArrivalTime)
  76. if (eta - node.ArrivalCandidates[runway.Runway.Name].InitialArrivalTime) <= self.Configuration.AirportConfiguration.MaxDelayMay:
  77. mayRunways.append(runway)
  78. if RunwayAssignmentType.GateAssignment in runway.MayAssignments:
  79. if node.Inbound.Report.plannedGate in runway.MayAssignments[RunwayAssignmentType.GateAssignment]:
  80. eta, _ = self.calculateEarliestArrivalTime(runway.Runway.Name, node, earliestArrivalTime)
  81. if (eta - node.ArrivalCandidates[runway.Runway.Name].InitialArrivalTime) <= self.Configuration.AirportConfiguration.MaxDelayMay:
  82. mayRunways.append(runway)
  83. runway = self.selectShallShouldMayArrivalRunway(node, shallRunways, earliestArrivalTime)
  84. if None != runway:
  85. return [ runway ]
  86. runway = self.selectShallShouldMayArrivalRunway(node, shouldRunways, earliestArrivalTime)
  87. if None != runway:
  88. return [ runway ]
  89. runway = self.selectShallShouldMayArrivalRunway(node, mayRunways, earliestArrivalTime)
  90. if None != runway:
  91. return [ runway ]
  92. return self.Configuration.RunwayConstraints.ActiveArrivalRunways
  93. def selectArrivalRunway(self, node : Node, earliestArrivalTime : datetime):
  94. availableRunways = self.Configuration.RunwayConstraints.ActiveArrivalRunways
  95. if 0 == len(availableRunways):
  96. return None, None, None
  97. if True == self.Configuration.RunwayConstraints.UseShallShouldMay and None == node.Inbound.RequestedRunway:
  98. availableRunways = self.executeShallShouldMayAssignment(node, earliestArrivalTime)
  99. elif None != node.Inbound.RequestedRunway:
  100. for runway in availableRunways:
  101. if node.Inbound.RequestedRunway == runway.Runway.Name:
  102. availableRunways = [ runway ]
  103. break
  104. if 0 == len(availableRunways):
  105. runway = self.Configuration.RunwayConstraints.ActiveArrivalRunways[0]
  106. eta, delta = self.calculateEarliestArrivalTime(runway.Runway.Name, node, earliestArrivalTime)
  107. return runway, eta, delta
  108. # start with the beginning
  109. selectedRunway = None
  110. lostTime = None
  111. eta = None
  112. # get the runway with the earliest ETA
  113. for runway in availableRunways:
  114. candidate, delta = self.calculateEarliestArrivalTime(runway.Runway.Name, node, earliestArrivalTime)
  115. if None == eta or eta > candidate:
  116. selectedRunway = runway.Runway
  117. lostTime = delta
  118. eta = candidate
  119. return selectedRunway, eta, lostTime
  120. def registerNode(self, node : Node, runway : str):
  121. self.RunwayInbounds[runway] = node
  122. # find the corresponding IAF
  123. iaf = node.ArrivalCandidates[runway].ArrivalRoute[0].Waypoint.Name
  124. if iaf in self.IafInbounds:
  125. delta = 100000.0
  126. targetLevel = None
  127. # find the planned level
  128. for level in self.IafInbounds[iaf]:
  129. difference = abs(level - node.ArrivalCandidates[runway].ArrivalRoute[0].Altitude)
  130. if difference < delta:
  131. delta = difference
  132. targetLevel = level
  133. if targetLevel in self.IafInbounds[iaf]:
  134. self.IafInbounds[iaf][targetLevel] = node