diff --git a/aman/sys/aco/Ant.py b/aman/sys/aco/Ant.py index 324897c..fd2d1f5 100644 --- a/aman/sys/aco/Ant.py +++ b/aman/sys/aco/Ant.py @@ -27,6 +27,9 @@ class Ant: # Implements function (5) def heuristicInformation(self, current : int): _, eta, _ = self.RunwayManager.selectArrivalRunway(self.Nodes[current], self.Configuration.EarliestArrivalTime) + if None == eta: + return -1.0 + inboundDelay = eta - self.Nodes[current].Inbound.InitialArrivalTime # calculate the fraction with a mix of the unused runway time and the delay of single aircrafts @@ -54,6 +57,10 @@ class Ant: if False == self.InboundSelected[i]: weights.append(self.heuristicInformation(i) / (pheromoneScale or 1)) + # something was wrong in the runway selection + if -1.0 in weights: + return None + total = sum(weights) cumdist = list(itertools.accumulate(weights)) + [total] candidateIndex = bisect.bisect(cumdist, random.random() * total) diff --git a/aman/sys/aco/Colony.py b/aman/sys/aco/Colony.py index 346e594..5502a4e 100644 --- a/aman/sys/aco/Colony.py +++ b/aman/sys/aco/Colony.py @@ -19,6 +19,8 @@ from aman.types.Inbound import Inbound class Colony: def associateInbound(rwyManager : RunwayManager, node : Node, earliestArrivalTime : datetime): rwy, eta, _ = rwyManager.selectArrivalRunway(node, earliestArrivalTime) + if None == eta: + return False eta = max(earliestArrivalTime, eta) node.Inbound.PlannedRunway = rwy @@ -29,12 +31,15 @@ class Colony: node.Inbound.PlannedTrackmiles = node.ArrivalCandidates[rwy.Name].Trackmiles rwyManager.RunwayInbounds[rwy.Name] = node + return True + def calculateInitialCosts(rwyManager : RunwayManager, nodes, earliestArrivalTime : datetime): overallDelay = timedelta(seconds = 0) # assume that the nodes are sorted in FCFS order for node in nodes: - Colony.associateInbound(rwyManager, node, earliestArrivalTime) + if False == Colony.associateInbound(rwyManager, node, earliestArrivalTime): + return None overallDelay += node.Inbound.PlannedArrivalTime - node.Inbound.InitialArrivalTime return overallDelay @@ -42,6 +47,7 @@ class Colony: def __init__(self, inbounds, configuration : Configuration): self.Configuration = configuration self.ResultDelay = None + self.FcfsDelay = None self.Result = None self.Nodes = [] @@ -52,6 +58,8 @@ class Colony: rwyManager = RunwayManager(self.Configuration) delay = Colony.calculateInitialCosts(rwyManager, self.Nodes, self.Configuration.EarliestArrivalTime) + if None == delay: + return self.FcfsDelay = delay # run the optimization in every cycle to ensure optimal spacings based on TTG @@ -74,9 +82,8 @@ class Colony: current.PTA = prev.PTA + (current.ETA - prev.ETA) def optimize(self): - # FCFS is the best solution - if None != self.Result: - return + if None == self.FcfsDelay: + return False # define the tracking variables bestSequence = None @@ -95,7 +102,7 @@ class Colony: # fallback to check if findSolution was successful if None == ant.SequenceDelay or None == ant.Sequence: sys.stderr.write('Invalid ANT run detected!') - sys.exit(-1) + break candidates.append( [ @@ -142,3 +149,5 @@ class Colony: self.ResultDelay = self.FcfsDelay for node in self.Nodes: self.sequenceAndPredictInbound(rwyManager, node) + + return True diff --git a/aman/sys/aco/RunwayManager.py b/aman/sys/aco/RunwayManager.py index 0aeeb11..590debb 100644 --- a/aman/sys/aco/RunwayManager.py +++ b/aman/sys/aco/RunwayManager.py @@ -117,6 +117,8 @@ class RunwayManager: def selectArrivalRunway(self, node : Node, earliestArrivalTime : datetime): availableRunways = self.Configuration.RunwayConstraints.ActiveArrivalRunways + if 0 == len(availableRunways): + return None, None, None if True == self.Configuration.RunwayConstraints.UseShallShouldMay and None == node.Inbound.RequestedRunway: availableRunways = self.executeShallShouldMayAssignment(node, earliestArrivalTime)