RunwayManager.py 4.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. #!/usr/bin/env python
  2. from datetime import datetime, timedelta
  3. from aman.sys.aco.Configuration import Configuration
  4. from aman.sys.aco.Constraints import SpacingConstraints
  5. from aman.sys.aco.Node import Node
  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 calculateEarliestArrivalTime(self, runway : str, node : Node, useETA : bool, earliestArrivalTime : datetime):
  19. constrainedETA = None
  20. if None != self.RunwayInbounds[runway]:
  21. # get the WTC based ETA
  22. if None == self.RunwayInbounds[runway].Inbound.WTC or None == node.Inbound.WTC:
  23. spacingWTC = 3
  24. else:
  25. spacingWTC = self.Spacings[self.RunwayInbounds[runway].Inbound.WTC][node.Inbound.WTC]
  26. # get the runway time spacing
  27. spacingRunway = self.Configuration.RunwayConstraints.findRunway(runway).Spacing
  28. constrainedETA = self.RunwayInbounds[runway].Inbound.PlannedArrivalTime + timedelta(minutes = max(spacingWTC, spacingRunway) / (node.Inbound.PerformanceData.SpeedApproach / 60))
  29. # calculate the arrival times for the dependent inbounds
  30. for dependentRunway in self.Configuration.RunwayConstraints.findDependentRunways(runway):
  31. if None != self.RunwayInbounds[dependentRunway.Runway.Name]:
  32. # TODO staggered spacing variabel
  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. return max(arrivalTime, earliestArrivalTime), timedelta(seconds = 0)
  43. else:
  44. eta = max(constrainedETA, earliestArrivalTime)
  45. if eta < arrivalTime:
  46. return arrivalTime, arrivalTime - eta
  47. else:
  48. return eta, timedelta(seconds = 0)
  49. def selectArrivalRunway(self, node : Node, useETA : bool, earliestArrivalTime : datetime):
  50. availableRunways = self.Configuration.RunwayConstraints.ActiveArrivalRunways
  51. #if 1 < len(availableRunways):
  52. # TODO filter based on type
  53. # TODO filter based on airline
  54. # ensure that at least one runway is available
  55. # fallback to check if we have available runways
  56. if 0 == len(availableRunways):
  57. runway = self.Configuration.RunwayConstraints.ActiveArrivalRunways[0]
  58. return runway, self.calculateEarliestArrivalTime(runway.Runway.Name, node, useETA, earliestArrivalTime)
  59. # start with the beginning
  60. selectedRunway = None
  61. lostTime = None
  62. eta = None
  63. # get the runway with the earliest ETA
  64. for runway in availableRunways:
  65. candidate, delta = self.calculateEarliestArrivalTime(runway.Runway.Name, node, useETA, earliestArrivalTime)
  66. if None == eta or eta > candidate:
  67. selectedRunway = runway.Runway
  68. lostTime = delta
  69. eta = candidate
  70. return selectedRunway, eta, lostTime