RunwayManager.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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. 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. # get the arrival time on the runway of the inbound
  37. if True == useETA:
  38. arrivalTime = node.ArrivalCandidates[runway].EarliestArrivalTime
  39. else:
  40. arrivalTime = node.ArrivalCandidates[runway].InitialArrivalTime
  41. if None == constrainedETA:
  42. eta = max(arrivalTime, earliestArrivalTime)
  43. else:
  44. eta = max(arrivalTime, max(constrainedETA, earliestArrivalTime))
  45. return eta, eta - arrivalTime
  46. def selectShallShouldMayArrivalRunway(self, node : Node, runways, useETA : bool, earliestArrivalTime : datetime):
  47. candidate = None
  48. delay = None
  49. for runway in runways:
  50. if True == useETA:
  51. reference = node.ArrivalCandidates[runway.Runway.Name].EarliestArrivalTime
  52. else:
  53. reference = node.ArrivalCandidates[runway.Runway.Name].InitialArrivalTime
  54. eta, _ = self.calculateEarliestArrivalTime(runway.Runway.Name, node, useETA, earliestArrivalTime)
  55. if None == delay:
  56. delay = eta - reference
  57. candidate = runway
  58. elif delay > (eta - reference):
  59. delay = eta- reference
  60. candidate = runway
  61. return candidate
  62. def executeShallShouldMayAssignment(self, node : Node, useETA : bool, earliestArrivalTime : datetime):
  63. shallRunways = []
  64. shouldRunways = []
  65. mayRunways = []
  66. for runway in self.Configuration.RunwayConstraints.ActiveArrivalRunways:
  67. # test the shall assignments
  68. if RunwayAssignmentType.AircraftType in runway.ShallAssignments:
  69. if node.Inbound.Report.aircraft.type in runway.ShallAssignments[RunwayAssignmentType.AircraftType]:
  70. shallRunways.append(runway)
  71. if RunwayAssignmentType.GateAssignment in runway.ShallAssignments:
  72. if node.Inbound.Report.plannedGate in runway.ShallAssignments[RunwayAssignmentType.GateAssignment]:
  73. shallRunways.append(runway)
  74. # test the should assignments
  75. if RunwayAssignmentType.AircraftType in runway.ShouldAssignments:
  76. if node.Inbound.Report.aircraft.type in runway.ShouldAssignments[RunwayAssignmentType.AircraftType]:
  77. shouldRunways.append(runway)
  78. if RunwayAssignmentType.GateAssignment in runway.ShouldAssignments:
  79. if node.Inbound.Report.plannedGate in runway.ShouldAssignments[RunwayAssignmentType.GateAssignment]:
  80. shouldRunways.append(runway)
  81. if True == useETA:
  82. reference = node.ArrivalCandidates[runway.Runway.Name].EarliestArrivalTime
  83. else:
  84. reference = node.ArrivalCandidates[runway.Runway.Name].InitialArrivalTime
  85. # test the may assignments
  86. if RunwayAssignmentType.AircraftType in runway.MayAssignments:
  87. if node.Inbound.Report.aircraft.type in runway.MayAssignments[RunwayAssignmentType.AircraftType]:
  88. eta, _ = self.calculateEarliestArrivalTime(runway.Runway.Name, node, useETA, earliestArrivalTime)
  89. if (eta - reference) <= self.Configuration.AirportConfiguration.MaxDelayMay:
  90. mayRunways.append(runway)
  91. if RunwayAssignmentType.GateAssignment in runway.MayAssignments:
  92. if node.Inbound.Report.plannedGate in runway.MayAssignments[RunwayAssignmentType.GateAssignment]:
  93. eta, _ = self.calculateEarliestArrivalTime(runway.Runway.Name, node, useETA, earliestArrivalTime)
  94. if (eta - reference) <= self.Configuration.AirportConfiguration.MaxDelayMay:
  95. mayRunways.append(runway)
  96. runway = self.selectShallShouldMayArrivalRunway(node, shallRunways, useETA, earliestArrivalTime)
  97. if None != runway:
  98. return [ runway ]
  99. runway = self.selectShallShouldMayArrivalRunway(node, shouldRunways, useETA, earliestArrivalTime)
  100. if None != runway:
  101. return [ runway ]
  102. runway = self.selectShallShouldMayArrivalRunway(node, mayRunways, useETA, earliestArrivalTime)
  103. if None != runway:
  104. return [ runway ]
  105. return self.Configuration.RunwayConstraints.ActiveArrivalRunways
  106. def selectArrivalRunway(self, node : Node, useETA : bool, earliestArrivalTime : datetime):
  107. availableRunways = self.Configuration.RunwayConstraints.ActiveArrivalRunways
  108. if True == self.Configuration.RunwayConstraints.UseShallShouldMay:
  109. availableRunways = self.executeShallShouldMayAssignment(node, useETA, earliestArrivalTime)
  110. else:
  111. availableRunways = self.Configuration.RunwayConstraints.ActiveArrivalRunways
  112. if 0 == len(availableRunways):
  113. runway = self.Configuration.RunwayConstraints.ActiveArrivalRunways[0]
  114. return runway, self.calculateEarliestArrivalTime(runway.Runway.Name, node, useETA, earliestArrivalTime)
  115. # start with the beginning
  116. selectedRunway = None
  117. lostTime = None
  118. eta = None
  119. # get the runway with the earliest ETA
  120. for runway in availableRunways:
  121. candidate, delta = self.calculateEarliestArrivalTime(runway.Runway.Name, node, useETA, earliestArrivalTime)
  122. if None == eta or eta > candidate:
  123. selectedRunway = runway.Runway
  124. lostTime = delta
  125. eta = candidate
  126. return selectedRunway, eta, lostTime