CostFunction.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. #!/usr/bin/env python
  2. from datetime import timedelta
  3. from aman.sys.aco.Colony import Colony
  4. from aman.sys.aco.Constraints import SpacingConstraints
  5. from aman.types.Inbound import Inbound
  6. class CostFunction:
  7. def __init__(self, colony : Colony):
  8. self.Spacings = SpacingConstraints()
  9. self.Colony = colony
  10. # initialize the tracker which inbound arrives at which runway
  11. self.RunwayInbounds = {}
  12. for runway in self.Colony.Configuration.PreceedingInbounds:
  13. self.RunwayInbounds[runway] = self.Colony.Configuration.PreceedingInbounds[runway]
  14. for runway in self.Colony.Configuration.RunwayConstraints.ActiveArrivalRunways:
  15. if not runway in self.RunwayInbounds:
  16. self.RunwayInbounds[runway] = None
  17. return
  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 calculateEta(self, runway : str, inbound : Inbound):
  25. if None == self.RunwayInbounds[runway]:
  26. return inbound.EstimatedArrivalTime
  27. preceedingInbound = self.RunwayInbounds[runway]
  28. # get the WTC constrained ETA
  29. wtcPre = CostFunction.validateWtc(preceedingInbound)
  30. wtcThis = CostFunction.validateWtc(inbound)
  31. if None == wtcPre or None == wtcThis:
  32. spacing = 3
  33. else:
  34. spacing = self.Spacings[wtcPre][wtcThis]
  35. delay = timedelta(seconds = round(spacing / inbound.PerformanceData.speedApproach + 0.5))
  36. wtcETA = self.RunwayInbounds[runway].EstimatedArrivalTime + delay
  37. # get the staggered time spacing
  38. dependentRunway = self.Colony.Configuration.RunwayConstraints.findDependentRunway(runway)
  39. if None != dependentRunway and None != self.RunwayInbounds[dependentRunway.Runway.name]:
  40. if preceedingInbound.EstimatedArrivalTime < self.RunwayInbounds[dependentRunway.Runway.name].EstimatedArrivalTime:
  41. delay = timedelta(seconds = round(3 / inbound.PerformanceData.speedApproach + 0.5))
  42. staggeredETA = self.RunwayInbounds[dependentRunway.Runway.name].EstimatedArrivalTime + delay
  43. else:
  44. staggeredETA = wtcETA
  45. else:
  46. staggeredETA = wtcETA
  47. # get the runway time spacing
  48. spacing = self.Colony.Configuration.RunwayConstraints.findRunway(runway).Spacing
  49. delay = timedelta(seconds = round(spacing / inbound.PerformanceData.speedApproach + 0.5))
  50. runwayETA = self.RunwayInbounds[runway].EstimatedArrivalTime + delay
  51. # get the biggest ETA to define the maximum but ensure that we are not earlier than the ITA
  52. # TODO model the TTG-concept depending on the distance to the IAF
  53. candidate = max(max(wtcETA, staggeredETA), runwayETA)
  54. if candidate < inbound.InitialArrivalTime:
  55. return inbound.InitialArrivalTime
  56. else:
  57. return candidate
  58. def selectArrivalRunway(self, inbound : Inbound):
  59. availableRunways = []
  60. for runway in self.Colony.Configuration.RunwayConstraints.ActiveArrivalRunways:
  61. availableRunways.append(runway)
  62. #if 1 < len(availableRunways):
  63. # TODO filter based on type
  64. # TODO filter based on airline
  65. # ensure that at least one runway is available
  66. # fallback to check if we have available runways
  67. if 0 == len(availableRunways):
  68. return self.Colony.Configuration.RunwayConstraints.ActiveArrivalRunways[0]
  69. # start with the beginning
  70. selectedRunway = self.Colony.Configuration.RunwayConstraints.findRunway(availableRunways[0])
  71. eta = self.calculateEta(availableRunways[0], inbound)
  72. # get the runway with the earliest ETA
  73. for runway in availableRunways:
  74. candidate = self.calculateEta(runway, inbound)
  75. if eta > candidate:
  76. selectedRunway = self.Colony.Configuration.RunwayConstraints.findRunway(runway)
  77. eta = candidate
  78. return selectedRunway