Basic trip over a real-world graph#
In this notebook, we set up a basic simulation where one vessel moves over a real-world graph. The vessel will sail from a location in the Maasvlakte, to a location in the Port of Moerdijk.
0. Import libraries#
# package(s) used for creating and geo-locating the graph
import networkx as nx
import shapely
# package(s) related to the simulation (creating the vessel, running the simulation)
import datetime
import simpy
import opentnsim
import opentnsim.fis as fis
from opentnsim.core.logutils import logbook2eventtable
from opentnsim.core.plotutils import generate_vessel_gantt_chart
# package(s) needed for inspecting the output
import pandas as pd
import geopandas as gpd
# plot libraries
import folium
print("This notebook is executed with OpenTNSim version {}".format(opentnsim.__version__))
This notebook is executed with OpenTNSim version 0.1.dev1+gcb6bdda4a
1. Define object classes#
# make your preferred Vessel class out of available mix-ins.
Vessel = type(
"Vessel",
(
opentnsim.core.Identifiable, # allows to give the object a name and a random ID,
opentnsim.core.Movable, # allows the object to move, with a fixed speed, while logging this activity
),
{}
)
2. Create graph#
Next we create a network (a graph) along which the vessel can move. For this case we use the Fairway Information System graph, and make the vessel sail from a container terminal at the Maasvlakte to an container terminal at the Port of Moerdijk.
# load the processed version from the Fairway Information System graph provided by Rijkswaterstaat
FG = fis.load_network(version="0.3")
---------------------------------------------------------------------------
KeyboardInterrupt Traceback (most recent call last)
Cell In[3], line 2
1 # load the processed version from the Fairway Information System graph provided by Rijkswaterstaat
----> 2 FG = fis.load_network(version="0.3")
File ~/work/OpenTNSim/OpenTNSim/opentnsim/fis.py:53, in load_network(network, version)
51 for n in graph.nodes:
52 node = graph.nodes[n]
---> 53 node["geometry"] = shapely.geometry.shape(node["geometry"])
55 return graph
File /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages/shapely/geometry/geo.py:101, in shape(context)
99 return _empty_shape_for_no_coordinates(geom_type)
100 elif geom_type == "point":
--> 101 return Point(ob["coordinates"])
102 elif geom_type == "linestring":
103 return LineString(ob["coordinates"])
File /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages/shapely/geometry/point.py:81, in Point.__new__(self, *args)
79 if not np.issubdtype(coords.dtype, np.number):
80 coords = [float(c) for c in coords]
---> 81 geom = shapely.points(coords)
82 if not isinstance(geom, Point):
83 raise ValueError("Invalid values passed to Point constructor")
File /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages/shapely/decorators.py:173, in deprecate_positional.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
171 @wraps(func)
172 def wrapper(*args, **kwargs):
--> 173 result = func(*args, **kwargs)
175 n = len(args)
176 if n > warn_from:
File /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages/shapely/decorators.py:88, in multithreading_enabled.<locals>.wrapped(*args, **kwargs)
86 for arr in array_args:
87 arr.flags.writeable = False
---> 88 return func(*args, **kwargs)
89 finally:
90 for arr, old_flag in zip(array_args, old_flags):
File /opt/hostedtoolcache/Python/3.13.11/x64/lib/python3.13/site-packages/shapely/creation.py:124, in points(coords, y, z, indices, handle_nan, out, **kwargs)
122 handle_nan = HandleNaN.get_value(handle_nan)
123 if indices is None:
--> 124 return lib.points(coords, np.intc(handle_nan), out=out, **kwargs)
125 else:
126 return simple_geometries_1d(
127 coords, indices, GeometryType.POINT, handle_nan=handle_nan, out=out
128 )
KeyboardInterrupt:
maasvlakte = shapely.Point(4.0566946, 51.9471624)
moerdijk = shapely.Point(4.5944738, 51.6829037)
nodes_gdf = gpd.GeoDataFrame(FG.nodes.values(), index=FG.nodes.keys())
distances, idx = nodes_gdf.sindex.nearest(maasvlakte)
maasvlakte_node = nodes_gdf.iloc[idx[0]]
distances, idx = nodes_gdf.sindex.nearest(moerdijk)
moerdijk_node = nodes_gdf.iloc[idx[0]]
route = nx.shortest_path(FG, maasvlakte_node.name, moerdijk_node.name, weight='length_m')
# Create a map centered between the two points
m = folium.Map(location=[51.83, 4.33], zoom_start = 10, tiles="cartodb positron")
for edge in FG.edges(data = True):
points_x = list(edge[2]["geometry"].coords.xy[0])
points_y = list(edge[2]["geometry"].coords.xy[1])
line = []
for i, _ in enumerate(points_x):
line.append((points_y[i], points_x[i]))
if edge[0] in route and edge[1] in route:
folium.PolyLine(line, color = "red", weight = 3, popup = edge[2]["Name"]).add_to(m)
else:
folium.PolyLine(line, color = "black", weight = 3, popup = edge[2]["Name"]).add_to(m)
for node in FG.nodes(data = True):
point = list(node[1]["geometry"].coords.xy)
folium.CircleMarker(location=[point[1][0],point[0][0]], color='black',fill_color = "black", fill=True, radus = 1, popup = node[0]).add_to(m)
# Add round marker for Maasvlakte with popup
folium.CircleMarker(
location=[maasvlakte_node.Y, maasvlakte_node.X],
radius=8,
color='green',
fill=True,
fill_color='green',
fill_opacity=0.7,
popup='Maasvlakte'
).add_to(m)
# Add round marker for Moerdijk with popup
folium.CircleMarker(
location=[moerdijk_node.Y, moerdijk_node.X],
radius=8,
color='blue',
fill=True,
fill_color='blue',
fill_opacity=0.7,
popup='Moerdijk'
).add_to(m)
# Display the map
m
Make this Notebook Trusted to load map: File -> Trust Notebook