diff --git a/aman/config/AirportSequencing.py b/aman/config/AirportSequencing.py index 92fc199..7275574 100644 --- a/aman/config/AirportSequencing.py +++ b/aman/config/AirportSequencing.py @@ -74,16 +74,16 @@ class AirportSequencing: return runway return None - def findDependentRunway(self, identifier : str): + def findDependentRunways(self, identifier : str): # runway is unknown index = self.runwayIndex(identifier) if 0 > index: - return None + return [] # search the dependency pair + dependencies = [] for dependency in self.RunwayDependencies: - if index == dependency[0]: - return self.ActiveArrivalRunways[dependency[1]] + if index == dependency[0] and not self.ActiveArrivalRunways[dependency[1]] in dependencies: + dependencies.append(self.ActiveArrivalRunways[dependency[1]]) - # no dependencies found - return None + return dependencies diff --git a/aman/sys/aco/RunwayManager.py b/aman/sys/aco/RunwayManager.py index 3c65e5b..fb6ee22 100644 --- a/aman/sys/aco/RunwayManager.py +++ b/aman/sys/aco/RunwayManager.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -from datetime import timedelta +from datetime import datetime, timedelta from aman.sys.aco.Configuration import Configuration from aman.sys.aco.Constraints import SpacingConstraints @@ -22,57 +22,52 @@ class RunwayManager: def validateWtc(inbound : Inbound): wtc = inbound.Report.aircraft.wtc.upper() - if 'L' == wtc or 'M' == wtc or 'H' == None or 'J' == None: + if 'L' == wtc or 'M' == wtc or 'H' == wtc or 'J' == wtc: return wtc else: return None - def calculateEarliestArrivalTime(self, runway : str, inbound : Inbound): - if None == self.RunwayInbounds[runway]: - return inbound.ArrivalCandidates[runway].EarliestArrivalTime + def calculateEarliestArrivalTime(self, runway : str, inbound : Inbound, useITA : bool, earliestArrivalTime : datetime): + earliestArrivalTimes = [] - preceedingInbound = self.RunwayInbounds[runway] - - # get the WTC constrained ETA - wtcPre = RunwayManager.validateWtc(preceedingInbound) - wtcThis = RunwayManager.validateWtc(inbound) - if None == wtcPre or None == wtcThis: - spacing = 3 - else: - spacing = self.Spacings[wtcPre][wtcThis] - delay = timedelta(minutes = spacing / (inbound.PerformanceData.SpeedApproach / 60)) - wtcEarliestArrivalTime = preceedingInbound.PlannedArrivalTime + delay - - # get the staggered time spacing - dependentRunway = self.Configuration.RunwayConstraints.findDependentRunway(runway) - if None != dependentRunway and None != self.RunwayInbounds[dependentRunway.Runway.Name]: - # check if the one on the same runway lands before the one on the parallel runway - if preceedingInbound.PlannedArrivalTime < self.RunwayInbounds[dependentRunway.Runway.Name].PlannedArrivalTime: - delay = timedelta(minutes = 3 / (inbound.PerformanceData.SpeedApproach / 60)) - staggeredEarliestArrivalTime = self.RunwayInbounds[dependentRunway.Runway.Name].PlannedArrivalTime + delay - # landing on the same runway + if None != self.RunwayInbounds[runway]: + # get the WTC based ETA + wtcPre = RunwayManager.validateWtc(self.RunwayInbounds[runway]) + wtcThis = RunwayManager.validateWtc(inbound) + if None == wtcPre or None == wtcThis: + spacing = 3 else: - staggeredEarliestArrivalTime = wtcEarliestArrivalTime - # no neighbor or no dependent runway (IPA) + spacing = self.Spacings[wtcPre][wtcThis] + delay = timedelta(minutes = spacing / (inbound.PerformanceData.SpeedApproach / 60)) + earliestArrivalTimes.append(self.RunwayInbounds[runway].PlannedArrivalTime + delay) + + # get the runway time spacing + spacing = self.Configuration.RunwayConstraints.findRunway(runway).Spacing + delay = timedelta(minutes = spacing / (inbound.PerformanceData.SpeedApproach / 60)) + earliestArrivalTimes.append(self.RunwayInbounds[runway].PlannedArrivalTime + delay) + + # calculate the arrival times for the dependent inbounds + for dependentRunway in self.Configuration.RunwayConstraints.findDependentRunways(runway): + if None != self.RunwayInbounds[dependentRunway.Runway.Name]: + delay = timedelta(minutes = 3 / (inbound.PerformanceData.SpeedApproach / 60)) + earliestArrivalTimes.append(self.RunwayInbounds[dependentRunway.Runway.Name].PlannedArrivalTime + delay) + + # get the arrival time on the runway of the inbound + if True == useITA: + arrivalTime = inbound.ArrivalCandidates[runway].EarliestArrivalTime else: - staggeredEarliestArrivalTime = wtcEarliestArrivalTime + arrivalTime = inbound.ArrivalCandidates[runway].InitialArrivalTime - # get the runway time spacing - spacing = self.Configuration.RunwayConstraints.findRunway(runway).Spacing - delay = timedelta(minutes = spacing / (inbound.PerformanceData.SpeedApproach / 60)) - runwayEarliestArrivalTime = preceedingInbound.PlannedArrivalTime + delay - - # the candidate with the latest ETA is used -> ensure all safety and procedure constraints - candidate = max(max(wtcEarliestArrivalTime, staggeredEarliestArrivalTime), runwayEarliestArrivalTime) - - # check if inbound comes later than the latest possible ETA - if candidate < inbound.ArrivalCandidates[runway].EarliestArrivalTime: - return inbound.ArrivalCandidates[runway].EarliestArrivalTime - # candidate fits into earliest arrival time or is later than this + if 0 == len(earliestArrivalTimes): + return arrivalTime, timedelta(seconds = 0) else: - return candidate + eta = max(earliestArrivalTimes) + if eta < arrivalTime: + return arrivalTime, arrivalTime - eta + else: + return eta, timedelta(seconds = 0) - def selectArrivalRunway(self, inbound : Inbound): + def selectArrivalRunway(self, inbound : Inbound, useITA : bool, earliestArrivalTime : datetime): availableRunways = [] for runway in self.Configuration.RunwayConstraints.ActiveArrivalRunways: availableRunways.append(runway) @@ -85,17 +80,19 @@ class RunwayManager: # fallback to check if we have available runways if 0 == len(availableRunways): runway = self.Configuration.RunwayConstraints.ActiveArrivalRunways[0] - return runway, self.calculateEarliestArrivalTime(runway.Runway.Name, inbound) + return runway, self.calculateEarliestArrivalTime(runway.Runway.Name, inbound, useITA, earliestArrivalTime) # start with the beginning selectedRunway = None + lostTime = None eta = None # get the runway with the earliest ETA for runway in availableRunways: - candidate = self.calculateEarliestArrivalTime(runway.Runway.Name, inbound) + candidate, delta = self.calculateEarliestArrivalTime(runway.Runway.Name, inbound, useITA, earliestArrivalTime) if None == eta or eta > candidate: selectedRunway = runway.Runway + lostTime = delta eta = candidate - return selectedRunway, eta + return selectedRunway, eta, lostTime