adapt the code to split up predictions form the inbounds

This commit is contained in:
Sven Czarnian
2021-11-13 22:55:04 +01:00
parent eba9e2deab
commit 8b34f622a3
9 changed files with 280 additions and 267 deletions

View File

@@ -1,48 +1,57 @@
#!/usr/bin/env python
from datetime import datetime as dt
from datetime import datetime, timedelta
import numpy as np
import pytz
import random
import sys
import pytz
import time
from aman.sys.aco.Ant import Ant
from aman.sys.aco.Configuration import Configuration
from aman.sys.aco.Node import Node
from aman.sys.aco.RunwayManager import RunwayManager
from aman.types.Inbound import Inbound
# This class implements the ant colony of the following paper:
# https://sci-hub.mksa.top/10.1109/cec.2019.8790135
class Colony:
def associateInbound(rwyManager : RunwayManager, inbound : Inbound, earliestArrivalTime : datetime, useITA : bool):
rwy, eta, _ = rwyManager.selectArrivalRunway(inbound, useITA, earliestArrivalTime)
def associateInbound(rwyManager : RunwayManager, node : Node, earliestArrivalTime : datetime, useITA : bool):
rwy, eta, _ = rwyManager.selectArrivalRunway(node, useITA, earliestArrivalTime)
eta = max(earliestArrivalTime, eta)
inbound.PlannedRunway = rwy
inbound.PlannedStar = inbound.ArrivalCandidates[rwy.Name].Star
inbound.PlannedArrivalRoute = inbound.ArrivalCandidates[rwy.Name].ArrivalRoute
inbound.PlannedArrivalTime = eta
inbound.InitialArrivalTime = inbound.ArrivalCandidates[rwy.Name].InitialArrivalTime
inbound.PlannedTrackmiles = inbound.ArrivalCandidates[rwy.Name].Trackmiles
rwyManager.RunwayInbounds[rwy.Name] = inbound
node.Inbound.PlannedRunway = rwy
node.Inbound.PlannedStar = node.ArrivalCandidates[rwy.Name].Star
node.Inbound.PlannedArrivalRoute = node.ArrivalCandidates[rwy.Name].ArrivalRoute
node.Inbound.PlannedArrivalTime = eta
node.Inbound.InitialArrivalTime = node.ArrivalCandidates[rwy.Name].InitialArrivalTime
node.Inbound.PlannedTrackmiles = node.ArrivalCandidates[rwy.Name].Trackmiles
rwyManager.RunwayInbounds[rwy.Name] = node
def calculateInitialCosts(rwyManager : RunwayManager, inbounds, earliestArrivalTime : datetime):
def calculateInitialCosts(rwyManager : RunwayManager, nodes, earliestArrivalTime : datetime):
overallDelay = timedelta(seconds = 0)
# assume that the inbounds are sorted in FCFS order
for inbound in inbounds:
Colony.associateInbound(rwyManager, inbound, earliestArrivalTime, False)
overallDelay += inbound.PlannedArrivalTime - inbound.InitialArrivalTime
# assume that the nodes are sorted in FCFS order
for node in nodes:
Colony.associateInbound(rwyManager, node, earliestArrivalTime, False)
overallDelay += node.Inbound.PlannedArrivalTime - node.Inbound.InitialArrivalTime
return overallDelay
def __init__(self, configuration : Configuration):
def __init__(self, inbounds, configuration : Configuration):
self.Configuration = configuration
self.ResultDelay = None
self.Result = None
self.Nodes = []
# create the new planning instances
currentTime = dt.utcfromtimestamp(int(time.time())).replace(tzinfo = pytz.UTC)
for inbound in inbounds:
self.Nodes.append(Node(inbound, currentTime, self.Configuration.WeatherModel, self.Configuration.NavData, self.Configuration.RunwayConstraints))
rwyManager = RunwayManager(self.Configuration)
delay = Colony.calculateInitialCosts(rwyManager, self.Configuration.Inbounds, self.Configuration.EarliestArrivalTime)
delay = Colony.calculateInitialCosts(rwyManager, self.Nodes, self.Configuration.EarliestArrivalTime)
self.FcfsDelay = delay
# run the optimization in every cycle to ensure optimal spacings based on TTG
@@ -50,8 +59,8 @@ class Colony:
delay = timedelta(seconds = 1.0)
# initial value for the optimization
self.Configuration.ThetaZero = 1.0 / (len(self.Configuration.Inbounds) * (delay.total_seconds() / 60.0))
self.PheromoneMatrix = np.ones(( len(self.Configuration.Inbounds), len(self.Configuration.Inbounds) ), dtype=float) * self.Configuration.ThetaZero
self.Configuration.ThetaZero = 1.0 / (len(self.Nodes) * (delay.total_seconds() / 60.0))
self.PheromoneMatrix = np.ones(( len(self.Nodes), len(self.Nodes) ), dtype=float) * self.Configuration.ThetaZero
def optimize(self):
# FCFS is the best solution
@@ -64,12 +73,12 @@ class Colony:
# run the optimization loops
for _ in range(0, self.Configuration.ExplorationRuns):
# select the first inbound
index = random.randint(1, len(self.Configuration.Inbounds)) - 1
index = random.randint(1, len(self.Nodes)) - 1
candidates = []
for _ in range(0, self.Configuration.AntCount):
# let the ant find a solution
ant = Ant(self.PheromoneMatrix, self.Configuration)
ant = Ant(self.PheromoneMatrix, self.Configuration, self.Nodes)
ant.findSolution(index)
# fallback to check if findSolution was successful
@@ -111,8 +120,8 @@ class Colony:
# finalize the sequence
rwyManager = RunwayManager(self.Configuration)
for i in range(0, len(bestSequence[1])):
self.Result.append(self.Configuration.Inbounds[bestSequence[1][i]])
Colony.associateInbound(rwyManager, self.Result[-1], self.Configuration.EarliestArrivalTime, True)
self.Result.append(self.Nodes[bestSequence[1][i]].Inbound)
Colony.associateInbound(rwyManager, self.Nodes[bestSequence[1][i]], self.Configuration.EarliestArrivalTime, True)
# the idea behind the TTL/TTG per waypoint is that the TTL and TTG needs to be achieved in the
# first 2/3 of the estimated trackmiles and assign it with a linear function to the waypoints