Browse Source

simulator works now

rparedis 2 years ago
parent
commit
7189d3d282
5 changed files with 281 additions and 142 deletions
  1. BIN
      de2/__pycache__/elements.cpython-38.pyc
  2. 140 51
      de2/elements.py
  3. BIN
      figures/fuel.jpg
  4. 2 2
      mapper.py
  5. 139 89
      parquet/ct2de.py

BIN
de2/__pycache__/elements.cpython-38.pyc


+ 140 - 51
de2/elements.py

@@ -1,11 +1,37 @@
 from pypdevs.DEVS import AtomicDEVS, CoupledDEVS
 from pypdevs.infinity import INFINITY
-import pandas as pd
 
 from dataclasses import dataclass
+import pandas as pd
 
 from de2.routing import get_graph, get_closest_vertex
 
+
+@dataclass
+class Footprint:
+	usage_time: float = 0.0
+	idle_time: float = 0.0
+	idle_since: float = 0.0
+	fuel_usage: float = 0.0
+
+	@staticmethod
+	def get_fuel_efficiency(velocity):
+		"""
+		Computes how efficient fuel is being used at a certain velocity.
+
+		Function based on the figure from Pieter (see figures/fuel.jpg) and an
+		online curve fitter (https://mycurvefit.com/).
+		"""
+		return 32.89402 + (1.114886 - 32.89402) / (1 + (velocity / 12.20228) ** 6.449555)
+
+	@staticmethod
+	def get_fuel(distance, velocity):
+		# TODO: find the right value here
+		fuel = 5  # litres/meter for 100% efficient fuel usage
+		efficiency = Footprint.get_fuel_efficiency(velocity)
+		return distance * fuel * efficiency
+
+
 @dataclass
 class Vessel:
 	mmsi: str
@@ -17,8 +43,7 @@ class Vessel:
 	total_distance: float = 0.0
 	time_until_departure: float = 0.0
 
-	usage_time: float = 0.0
-	idle_time: float = 0.0
+	footprint: Footprint = Footprint()
 
 
 class Pool(AtomicDEVS):
@@ -44,9 +69,10 @@ class Pool(AtomicDEVS):
 				vessel = self.state["waiting"][request["mmsi"]]
 			else:
 				print("VESSEL %s DOES NOT EXIST IN POOL" % str(request["mmsi"]))
-				vessel = Vessel(request["mmsi"], request["name"])
+				# print("\t", request)
+				vessel = Vessel(request["mmsi"])
 
-			vessel.idle_time += self.state["time"] - vessel.time_until_departure
+			vessel.footprint.idle_time += self.state["time"] - vessel.footprint.idle_since
 
 			# vessel.time_until_departure = (request["end"] - request["start"]) / 1000
 			# vessel.velocity = request["distance"] / vessel.time_until_departure
@@ -62,8 +88,8 @@ class Pool(AtomicDEVS):
 				vessel.distance_left = request["distance"]
 				vessel.total_distance = vessel.distance_left
 				vessel.time_until_departure = vessel.distance_left / vessel.velocity
-				vessel.source = (request["source_lon"], request["source_lat"])
-				vessel.target = (request["target_lon"], request["target_lat"])
+				vessel.source = request["source_lon"], request["source_lat"]
+				vessel.target = request["target_lon"], request["target_lat"]
 				vessel.task = request["task"]
 
 				self.state["should_exit"].append(vessel)
@@ -78,10 +104,10 @@ class Pool(AtomicDEVS):
 				vessel.source = vessel.target
 				vessel.target = None
 				if vessel.velocity > 0:
-					vessel.usage_time += vessel.total_distance / vessel.velocity
+					vessel.footprint.fuel_usage += Footprint.get_fuel(vessel.total_distance, vessel.velocity)
+					vessel.footprint.usage_time += vessel.total_distance / vessel.velocity
 
-				# temporarily use this variable to store the "idle from" time
-				vessel.time_until_departure = self.state["time"]
+				vessel.footprint.idle_since = self.state["time"]
 
 				self.state["waiting"][vessel.mmsi] = vessel
 		return self.state
@@ -119,16 +145,19 @@ class Sailer(AtomicDEVS):
 
 	def extTransition(self, inputs):
 		self.state["time"] += self.elapsed
-		for vessel in self.state["vessels"]:
-			x = vessel.velocity * self.elapsed
-			vessel.distance_left = max(0.0, vessel.distance_left - x)
-			vessel.time_until_departure = round(vessel.time_until_departure - self.elapsed, 6)
+		self.update_vessels(self.elapsed)
 		if self.vessel_in in inputs:
 			vessel = inputs[self.vessel_in]
 			self.state["vessels"].append(vessel)
 		self.state["vessels"].sort(key=lambda v: v.time_until_departure)
 		return self.state
 
+	def update_vessels(self, elapsed):
+		for vessel in self.state["vessels"]:
+			x = vessel.velocity * elapsed
+			vessel.distance_left = max(0.0, vessel.distance_left - x)
+			vessel.time_until_departure = round(max(0.0, vessel.time_until_departure - elapsed), 6)
+
 	def timeAdvance(self):
 		if len(self.state["vessels"]) > 0:
 			v = self.state["vessels"][0]
@@ -146,10 +175,7 @@ class Sailer(AtomicDEVS):
 		elapsed = self.timeAdvance()
 		self.state["time"] += elapsed
 		self.state["vessels"].pop(0)
-		for vessel in self.state["vessels"]:
-			x = vessel.velocity * elapsed
-			vessel.distance_left = max(0.0, vessel.distance_left - x)
-			vessel.time_until_departure = round(max(0.0, vessel.time_until_departure - elapsed), 6)
+		self.update_vessels(elapsed)
 		if len(self.state["vessels"]) > 0:
 			self.state["vessels"].sort(key=lambda v: v.time_until_departure)
 		return self.state
@@ -159,12 +185,6 @@ class Tracer(AtomicDEVS):
 	def __init__(self, name, ivef):
 		super(Tracer, self).__init__(name)
 
-		# self.berths = {}
-		# berths = pd.read_csv("berths.csv", index_col=0)
-		# for _, row in berths.iterrows():
-		# 	self.berths[row["lpl_id"]] = row["center_lon"], row["center_lat"]
-
-		# self.ivef = pd.read_csv(ivef, usecols=["mmsi", "start", "source", "target", "task"])
 		self.ivef = pd.read_csv(ivef, usecols=["mmsi", "name", "start",
 		                                       "source_lon", "source_lat", "target_lon", "target_lat",
 		                                       "distance", "task", "velocity"],
@@ -176,23 +196,41 @@ class Tracer(AtomicDEVS):
 		# self.ivef["start"] -= self.starting_time
 		# self.ivef["end"] -= self.starting_time
 
-		# # obtain the coordinates
-		# self.ivef["source_lon"] = [self.berths[k][0] for k in self.ivef["source"]]
-		# self.ivef["source_lat"] = [self.berths[k][1] for k in self.ivef["source"]]
-		# self.ivef["target_lon"] = [self.berths[k][0] for k in self.ivef["target"]]
-		# self.ivef["target_lat"] = [self.berths[k][1] for k in self.ivef["target"]]
-		#
-		# # TODO: obtain distances using theoretical map
-		# self.graph = get_graph()
-		# self.ivef["distance"] = \
-		# 	self.graph.distances([get_closest_vertex(self.graph, self.berths[k][0], self.berths[k][1]).index for k in self.ivef["source"]],
-		# 	                     [get_closest_vertex(self.graph, self.berths[k][0], self.berths[k][1]).index for k in self.ivef["target"]],
-		# 	                     weights="distance", mode="all")
-		#
-		# # sample velocities
-		# self.ivef["velocity"] = 5.0
-		#
-		# self.ivef["end"] = self.ivef["start"] + self.ivef["distance"] / self.ivef["velocity"]
+		self.state = {
+			"index": 0,
+			"time": 0.0
+		}
+
+		self.reqs = self.addOutPort("reqs")
+
+	def timeAdvance(self):
+		if self.state["index"] < len(self.ivef):
+			start = self.ivef.iloc[self.state["index"]]["start"] - self.starting_time
+			return round(start / 1000 - self.state["time"], 6)
+		return INFINITY
+
+	def intTransition(self):
+		self.state["time"] += self.timeAdvance()
+		self.state["index"] += 1
+		return self.state
+
+	def outputFnc(self):
+		if self.state["index"] < len(self.ivef):
+			return {
+				self.reqs: self.ivef.iloc[self.state["index"]]
+			}
+		return {}
+
+
+class Scheduler(AtomicDEVS):
+	def __init__(self, name, ivef):
+		super(Scheduler, self).__init__(name)
+
+		self.ivef = pd.read_csv(ivef, usecols=["mmsi", "start", "ETA", "source", "target", "task"])
+		self.ivef.sort_values(by=["start"])
+		self.starting_time = self.ivef.iloc[0]["start"]
+		# self.ivef["start"] -= self.starting_time
+		# self.ivef["end"] -= self.starting_time
 
 		self.state = {
 			"index": 0,
@@ -220,6 +258,57 @@ class Tracer(AtomicDEVS):
 		return {}
 
 
+class Planner(AtomicDEVS):
+	def __init__(self, name):
+		super(Planner, self).__init__(name)
+
+		self.graph = get_graph()
+
+		self.state = {
+			"request": None
+		}
+
+		self.req_in = self.addInPort("req_in")
+		self.req_out = self.addOutPort("req_out")
+
+	def timeAdvance(self):
+		if self.state["request"] is None:
+			return INFINITY
+		return 0.0
+
+	def extTransition(self, inputs):
+		if self.req_in in inputs:
+			request = inputs[self.req_in]
+
+			request["source_lon"], request["source_lat"] = eval(request["source"])
+			request["target_lon"], request["target_lat"] = eval(request["target"])
+
+			src_vertex, _ = get_closest_vertex(self.graph, request["source_lon"], request["source_lat"])
+			tgt_vertex, _ = get_closest_vertex(self.graph, request["target_lon"], request["target_lat"])
+
+			request["distance"] = self.graph.distances([src_vertex.index], [tgt_vertex.index], weights="distance", mode="all")[0][0]
+
+			# TODO: check this value with PoAB
+			# TODO: make this a distribution instead?
+			# request["velocity"] = 6.17  # about 12 knots
+			request["velocity"] = request["distance"] / ((request["ETA"] - request["start"]) / 1000)
+
+			# UNUSED!
+			# request["end"] = request["start"] + request["distance"] / request["velocity"]
+
+			self.state["request"] = request
+		return self.state
+
+	def outputFnc(self):
+		if self.state["request"] is None:
+			return {}
+		return { self.req_out: self.state["request"] }
+
+	def intTransition(self):
+		self.state["request"] = None
+		return self.state
+
+
 class Clock(AtomicDEVS):
 	def __init__(self, name, interval=1):
 		super(Clock, self).__init__(name)
@@ -241,11 +330,15 @@ class Port(CoupledDEVS):
 		super(Port, self).__init__(name)
 
 		self.clock = self.addSubModel(Clock("clock"))
-		self.tracer = self.addSubModel(Tracer("tracer", ivef))
+		self.scheduler = self.addSubModel(Scheduler("scheduler", ivef))
+		self.planner = self.addSubModel(Planner("planner"))
+		# self.tracer = self.addSubModel(Tracer("tracer", ivef))
 		self.pool = self.addSubModel(Pool("pool"))
 		self.sailer = self.addSubModel(Sailer("sailer"))
 
-		self.connectPorts(self.tracer.reqs, self.pool.req_in)
+		# self.connectPorts(self.tracer.reqs, self.pool.req_in)
+		self.connectPorts(self.scheduler.reqs, self.planner.req_in)
+		self.connectPorts(self.planner.req_out, self.pool.req_in)
 		self.connectPorts(self.pool.vessel_out, self.sailer.vessel_in)
 		self.connectPorts(self.sailer.vessel_out, self.pool.vessel_in)
 
@@ -261,13 +354,9 @@ class Port(CoupledDEVS):
 	def print_statistics(self):
 		print("TOTAL USAGES:")
 		S = 0
-		for vessel in self.pool.state["waiting"].values():
-			if vessel.usage_time > 0:
-				print("\t%s: %f" % (vessel.mmsi, vessel.usage_time))
-				S += vessel.usage_time
-		for vessel in self.sailer.state["vessels"]:
-			if vessel.usage_time > 0:
-				print("\t%s: %f" % (vessel.mmsi, vessel.usage_time))
-				S += vessel.usage_time
+		for vessel in list(self.pool.state["waiting"].values()) + self.sailer.state["vessels"]:
+			if vessel.footprint.usage_time > 0:
+				print("\t%s: %f" % (vessel.mmsi, vessel.footprint.usage_time))
+				S += vessel.footprint.usage_time
 		print("-------------")
 		print("OVERALL: %f" % (S / 36))

BIN
figures/fuel.jpg


+ 2 - 2
mapper.py

@@ -92,7 +92,7 @@ class PoABLayer(BaseLayer):
         else:
             model = self.sim.model
             time = model.clock.state["time"]
-            ts = int(time + model.tracer.starting_time / 1000)
+            ts = int(time + model.scheduler.starting_time / 1000)
             ui_manager.info("TIME: %s" % epoch_to_str(ts))
 
             for vessel in model.sailer.state["vessels"]:
@@ -150,7 +150,7 @@ if __name__ == '__main__':
     from de2.elements import Port
     from pypdevs.simulator import Simulator
 
-    port = Port("PoAB", "results-de/IVEF.csv")
+    port = Port("PoAB", "results-de2/IVEF.csv")
 
     sim = Simulator(port)
     sim.setClassicDEVS()

+ 139 - 89
parquet/ct2de.py

@@ -5,6 +5,7 @@ from geoplotlib.utils import haversine
 import matplotlib.path as mplPath
 from os.path import exists
 import random
+import json
 
 from de2.routing import get_graph, pathfinder, find_percentage_point_in_path as fpp
 
@@ -16,6 +17,9 @@ tmap = {}
 for _, row in tugs.iterrows():
 	tmap[row["MMSI"]] = row["NAME"]
 
+with open("paths/endpointsWGS84.json", 'r') as file:
+	endpoints = json.load(file)["features"]
+
 @dataclass
 class Vessel:
 	mmsi: str
@@ -40,6 +44,17 @@ def get_dock(lon, lat):
 			return pid
 	return ""
 
+def get_closest_endpoint(lon, lat):
+	dist = float('inf')
+	point = None
+	for p in endpoints:
+		D = haversine(lon, lat, p["geometry"]["x"], p["geometry"]["y"])
+		if D < dist:
+			dist = D
+			point = p
+	return point, dist
+
+
 def analyze(fname):
 	if not exists(fname):
 		print(fname, "does not exist!")
@@ -47,112 +62,147 @@ def analyze(fname):
 	df = pd.read_csv(fname, dtype={"mmsi": str})
 	df.sort_values(by=["ts"], inplace=True)
 
-	res = pd.DataFrame(columns=["mmsi", "name", "start", "end", "location", "source_lon", "source_lat",
-	                            "target_lon", "target_lat", "distance", "task"])
+	# res = pd.DataFrame(columns=["mmsi", "name", "start", "end", "location", "source_lon", "source_lat",
+	#                             "target_lon", "target_lat", "distance", "task"])
+	res = pd.DataFrame(columns=["mmsi", "start", "ETA", "source", "target", "task"])
 
-	graph = get_graph()
+	# graph = get_graph()
 
 	task = random.choice([0, 1])
 	tasks = ["tugging", "sailing"]
 
 	first = df.iloc[0]
-	vessel = Vessel(first["mmsi"], tmap[str(first["mmsi"])], first["ts"], -1, get_dock(first["lon"], first["lat"]),
+	vessel = Vessel(first["mmsi"], tmap[str(first["mmsi"])], first["ts"], -1, (first["lon"], first["lat"]),
 	                (first["lon"], first["lat"]), (first["lon"], first["lat"]), 0.0, tasks[task])
 
 	# if exists("../results-de/%s-de.csv" % str(vessel.mmsi)):
 	# 	print("Already done %s" % str(vessel.mmsi))
 	# 	return None
 
-	in_dock = get_dock(first["lon"], first["lat"]) != ""
-	time = first["ts"]
+	# in_dock = get_dock(first["lon"], first["lat"]) != ""
+	# time = first["ts"]
+	# new_loc = get_dock(first["lon"], first["lat"])
 	for _, row in df.iloc[1:].iterrows():
-		# Check if you are at a new location
-		new_loc = get_dock(row["lon"], row["lat"])
-
-		# dd = haversine(vessel.lonlat_t[0], vessel.lonlat_t[1], row["lon"], row["lat"])
-		# delta = (row["ts"] - time) / 1000
-		# # cutoff point:
-		# if dd / delta > 6:
-		# 	print("Weird velocity:", dd, delta, dd/delta)
-
-		if new_loc != vessel.location:
-			# fix for teleportation issue
-			# add intermediate points on which dock/sailing transition is assumed
-			# it is assumed that these points lie on the theoretical trajectory => APPROXIMATION
-
-			# path = [vessel.lonlat_t, (row["lon"], row["lat"])]
-			# dists = [haversine(*vessel.lonlat_t, row["lon"], row["lat"])]
-
-			path, dists = pathfinder(graph, vessel.lonlat_t, (row["lon"], row["lat"]))
-			tot_dist = sum(dists)
-
-			if in_dock and new_loc != "":
-				# check hidden movement to the next dock: divide the trajectory in 3 equal parts
-				pa1, pb1, percentage = fpp(path, dists, 1/3)
-				center = pa1[0] + (pb1[0] - pa1[0]) * percentage, pa1[1] + (pb1[1] - pa1[1]) * percentage
-				pa2, pb2, percentage = fpp(path, dists, 2/3)
-				p2 = pa2[0] + (pb2[0] - pa2[0]) * percentage, pa2[1] + (pb2[1] - pa2[1]) * percentage
-
-				d1 = d2 = d3 = tot_dist / 3
-				t1 = (row["ts"] + 2 * time) / 3
-				t2 = (2 * row["ts"] + time) / 3
-
-				# add a movement to the next dock
-				res.loc[len(res.index) + 1.5] = [vessel.mmsi, vessel.name, t1, t2, None,
-				                                 center[0], center[1], p2[0], p2[1], d3, vessel.task]
-			else:
-				# from dock to free or vice-versa: divide the trajectory in 2 equal parts
-				pa1, pb1, percentage = fpp(path, dists, 1 / 2)
-				center = p2 = pa1[0] + (pb1[0] - pa1[0]) * percentage, pa1[1] + (pb1[1] - pa1[1]) * percentage
-
-				d1 = d2 = tot_dist / 2
-				t1 = t2 = (row["ts"] + time) / 2
-
-			# store previous trajectory
-			res.loc[len(res.index)] = [vessel.mmsi, vessel.name, vessel.start, t1, vessel.location,
-			                           vessel.lonlat_s[0], vessel.lonlat_s[1],
-			                           center[0], center[1], vessel.distance + d1, vessel.task]
-
-			if new_loc != "":
-				# Randomly pick tugging or sailing
-				task = random.choice([0, 1])
-				vessel.task = tasks[task]
-
-			# store beginning of new trajectory
-			vessel.start = t2
-			vessel.end = -1
-			vessel.location = new_loc
-			vessel.distance = d2
-			vessel.lonlat_s = p2
-			vessel.lonlat_t = row["lon"], row["lat"]
-		else:
-			# find the distance between the previous point and the current point
-			vessel.distance += haversine(vessel.lonlat_t[0], vessel.lonlat_t[1], row["lon"], row["lat"])
-			vessel.lonlat_t = row["lon"], row["lat"]
-
-		time = row["ts"]
-		in_dock = new_loc != ""
-
-	if vessel.end != -1:
-		res.loc[len(res.index)] = [vessel.mmsi, vessel.name, vessel.start, df.iloc[-1]["ts"], vessel.location,
-		                           vessel.lonlat_s[0], vessel.lonlat_s[1], vessel.lonlat_t[0], vessel.lonlat_t[1],
-		                           vessel.distance, vessel.task]
+		# Check if you are at a new task start
+		loc, dloc = get_closest_endpoint(row["lon"], row["lat"])
+		if dloc < 5:  # New location is less than 5 meters away
+			# new_loc = get_dock(loc["geometry"]["x"], loc["geometry"]["y"])
+			new_loc = loc["geometry"]["x"], loc["geometry"]["y"]
+			# if vessel.location == "":
+			# 	vessel.location = vessel.lonlat_s
+			# if new_loc == "":
+			# 	new_loc = loc["geometry"]["x"], loc["geometry"]["y"]
+			if new_loc != vessel.location:
+				res.loc[len(res.index)] = [vessel.mmsi, vessel.start, row["ts"], str(vessel.location), str(new_loc), vessel.task]
+				vessel.location = new_loc
+				vessel.lonlat_s = row["lon"], row["lat"]
+				vessel.start = row["ts"]
+				vessel.task = tasks[random.choice([0, 1])]
+		vessel.lonlat_t = row["lon"], row["lat"]
+
+		# # Check if you are at a new location
+		# new_loc = get_dock(row["lon"], row["lat"])
+		#
+		# # dd = haversine(vessel.lonlat_t[0], vessel.lonlat_t[1], row["lon"], row["lat"])
+		# # delta = (row["ts"] - time) / 1000
+		# # # cutoff point:
+		# # if dd / delta > 6:
+		# # 	print("Weird velocity:", dd, delta, dd/delta)
+		#
+		# if new_loc != vessel.location:
+		# 	# fix for teleportation issue
+		# 	# add intermediate points on which dock/sailing transition is assumed
+		# 	# it is assumed that these points lie on the theoretical trajectory => APPROXIMATION
+		#
+		# 	# path = [vessel.lonlat_t, (row["lon"], row["lat"])]
+		# 	# dists = [haversine(*vessel.lonlat_t, row["lon"], row["lat"])]
+		#
+		# 	path, dists = pathfinder(graph, vessel.lonlat_t, (row["lon"], row["lat"]))
+		# 	tot_dist = sum(dists)
+		#
+		# 	if in_dock and new_loc != "":
+		# 		# check hidden movement to the next dock: divide the trajectory in 3 equal parts
+		# 		pa1, pb1, percentage = fpp(path, dists, 1/3)
+		# 		center = pa1[0] + (pb1[0] - pa1[0]) * percentage, pa1[1] + (pb1[1] - pa1[1]) * percentage
+		# 		pa2, pb2, percentage = fpp(path, dists, 2/3)
+		# 		p2 = pa2[0] + (pb2[0] - pa2[0]) * percentage, pa2[1] + (pb2[1] - pa2[1]) * percentage
+		#
+		# 		d1 = d2 = d3 = tot_dist / 3
+		# 		t1 = (row["ts"] + 2 * time) / 3
+		# 		t2 = (2 * row["ts"] + time) / 3
+		#
+		# 		# add a movement to the next dock
+		# 		res.loc[len(res.index) + 1.5] = [vessel.mmsi, vessel.name, t1, t2, None,
+		# 		                                 center[0], center[1], p2[0], p2[1], d3, vessel.task]
+		# 	else:
+		# 		# from dock to free or vice-versa: divide the trajectory in 2 equal parts
+		# 		pa1, pb1, percentage = fpp(path, dists, 1 / 2)
+		# 		center = p2 = pa1[0] + (pb1[0] - pa1[0]) * percentage, pa1[1] + (pb1[1] - pa1[1]) * percentage
+		#
+		# 		d1 = d2 = tot_dist / 2
+		# 		t1 = t2 = (row["ts"] + time) / 2
+		#
+		# 	# store previous trajectory
+		# 	res.loc[len(res.index)] = [vessel.mmsi, vessel.name, vessel.start, t1, vessel.location,
+		# 	                           vessel.lonlat_s[0], vessel.lonlat_s[1],
+		# 	                           center[0], center[1], vessel.distance + d1, vessel.task]
+		#
+		# 	if new_loc != "":
+		# 		# Randomly pick tugging or sailing
+		# 		task = random.choice([0, 1])
+		# 		vessel.task = tasks[task]
+		#
+		# 	# store beginning of new trajectory
+		# 	vessel.start = t2
+		# 	vessel.end = -1
+		# 	vessel.location = new_loc
+		# 	vessel.distance = d2
+		# 	vessel.lonlat_s = p2
+		# 	vessel.lonlat_t = row["lon"], row["lat"]
+		# else:
+		# 	# find the distance between the previous point and the current point
+		# 	vessel.distance += haversine(vessel.lonlat_t[0], vessel.lonlat_t[1], row["lon"], row["lat"])
+		# 	vessel.lonlat_t = row["lon"], row["lat"]
+		#
+		# time = row["ts"]
+		# in_dock = new_loc != ""
+	# loc = get_dock(*vessel.lonlat_t)
+	# if loc == "":
+	# 	loc = vessel.lonlat_t
+	# if vessel.location == "":
+	# 	vessel.location = vessel.lonlat_s
+	res.loc[len(res.index)] = [vessel.mmsi, vessel.start, df.iloc[-1]["ts"], str(vessel.location), str(vessel.lonlat_t), vessel.task]
+	#
+	# if vessel.end != -1:
+	# 	res.loc[len(res.index)] = [vessel.mmsi, vessel.name, vessel.start, df.iloc[-1]["ts"], vessel.location,
+	# 	                           vessel.lonlat_s[0], vessel.lonlat_s[1], vessel.lonlat_t[0], vessel.lonlat_t[1],
+	# 	                           vessel.distance, vessel.task]
 	# print("AVG dt:", sum(dts) / len(dts), max(dts), min(dts))
 	# res.sort_values(by=["start"], inplace=True)
-	res = res.sort_index().reset_index(drop=True)
-	res["velocity"] = res["distance"] / ((res["end"] - res["start"]) / 1000)
-	res.to_csv("results-de/%s-de.csv" % str(vessel.mmsi), index=False)
+	# res = res.sort_index().reset_index(drop=True)
+	# res["velocity"] = res["distance"] / ((res["end"] - res["start"]) / 1000)
+	res.to_csv("results-de2/%s-de.csv" % str(vessel.mmsi), index=False)
 
 if __name__ == '__main__':
 	# print(get_dock(4.242435, 51.27712))
 	# import sys
 	# analyze(sys.argv[2])
-	analyze("results/205627000.csv")
-
-	# TFILE = "tugs.csv"
-	# tugs = pd.read_csv(TFILE)
-	# mmsi = tugs["MMSI"].dropna().astype(np.int32)
-	# for idx in mmsi:
-	# 	print("checking", idx)
-	# 	analyze("results/%s.csv" % str(idx))
-	# 	print(idx, "done")
+	# analyze("results/205627000.csv")
+
+	df = pd.DataFrame()
+
+	TFILE = "tugs.csv"
+	tugs = pd.read_csv(TFILE)
+	mmsi = tugs["MMSI"].dropna().astype(np.int32)
+	for idx in mmsi:
+		# print("checking", idx)
+		# analyze("results/%s.csv" % str(idx))
+		# print(idx, "done")
+		fname = "results-de2/%s-de.csv" % str(idx)
+		if not exists(fname):
+			print(fname, "does not exist")
+			continue
+		tug = pd.read_csv(fname)
+		df = pd.concat([df, tug], ignore_index=True)
+	df.sort_values(by=["start"], inplace=True)
+	df.to_csv("results-de2/IVEF.csv", index=False)