Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add reduce_memory_delele_vehicle_route_pref to World arg #149

Merged
merged 3 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 94 additions & 1 deletion tests/test_other_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -782,4 +782,97 @@ def veh_user_function(veh):
link1 = W.get_link("link1")
print("average speed of link1:", np.nanmean(link1.user_attribute["speed_record"]))

assert equal_tolerance(np.nanmean(link1.user_attribute["speed_record"]), 15.89)
assert equal_tolerance(np.nanmean(link1.user_attribute["speed_record"]), 15.89)

def test_reduce_memory_delele_vehicle_route_pref():
W = World(
name="",
deltan=10,
tmax=3000,
print_mode=1, save_mode=1, show_mode=0,
reduce_memory_delele_vehicle_route_pref=False,
random_seed=0,
)

n_nodes = 4
imax = n_nodes
jmax = n_nodes
nodes = {}
for i in range(imax):
for j in range(jmax):
nodes[i,j] = W.addNode(f"n{(i,j)}", i, j, flow_capacity=1.6)

links = {}
for i in range(imax):
for j in range(jmax):
if i != imax-1:
links[i,j,i+1,j] = W.addLink(f"l{(i,j,i+1,j)}", nodes[i,j], nodes[i+1,j], length=1000)
if i != 0:
links[i,j,i-1,j] = W.addLink(f"l{(i,j,i-1,j)}", nodes[i,j], nodes[i-1,j], length=1000)
if j != jmax-1:
links[i,j,i,j+1] = W.addLink(f"l{(i,j,i,j+1)}", nodes[i,j], nodes[i,j+1], length=1000)
if j != 0:
links[i,j,i,j-1] = W.addLink(f"l{(i,j,i,j-1)}", nodes[i,j], nodes[i,j-1], length=1000)


area_dict = {
"areaN": [nodes[0,i] for i in range(n_nodes)],
"areaS": [nodes[n_nodes-1,i] for i in range(n_nodes)],
"areaNW": [nodes[0,0]],
"areaSE": [nodes[n_nodes-1, n_nodes-1]]
}

W.adddemand_nodes2nodes(area_dict["areaN"], area_dict["areaS"], 0, 3000, volume=7000)

W.exec_simulation()
W.analyzer.print_simple_stats()

df1 = W.analyzer.area_to_pandas(list(area_dict.values()), list(area_dict.keys()), border_include=True)
print(df1)

W = World(
name="",
deltan=10,
tmax=3000,
print_mode=1, save_mode=1, show_mode=0,
reduce_memory_delele_vehicle_route_pref=True,
random_seed=0,
)

n_nodes = 4
imax = n_nodes
jmax = n_nodes
nodes = {}
for i in range(imax):
for j in range(jmax):
nodes[i,j] = W.addNode(f"n{(i,j)}", i, j, flow_capacity=1.6)

links = {}
for i in range(imax):
for j in range(jmax):
if i != imax-1:
links[i,j,i+1,j] = W.addLink(f"l{(i,j,i+1,j)}", nodes[i,j], nodes[i+1,j], length=1000)
if i != 0:
links[i,j,i-1,j] = W.addLink(f"l{(i,j,i-1,j)}", nodes[i,j], nodes[i-1,j], length=1000)
if j != jmax-1:
links[i,j,i,j+1] = W.addLink(f"l{(i,j,i,j+1)}", nodes[i,j], nodes[i,j+1], length=1000)
if j != 0:
links[i,j,i,j-1] = W.addLink(f"l{(i,j,i,j-1)}", nodes[i,j], nodes[i,j-1], length=1000)


area_dict = {
"areaN": [nodes[0,i] for i in range(n_nodes)],
"areaS": [nodes[n_nodes-1,i] for i in range(n_nodes)],
"areaNW": [nodes[0,0]],
"areaSE": [nodes[n_nodes-1, n_nodes-1]]
}

W.adddemand_nodes2nodes(area_dict["areaN"], area_dict["areaS"], 0, 3000, volume=7000)

W.exec_simulation()
W.analyzer.print_simple_stats()

df2 = W.analyzer.area_to_pandas(list(area_dict.values()), list(area_dict.keys()), border_include=True)
print(df2)

assert df1["total_travel_time"][0] == df2["total_travel_time"][0]
48 changes: 33 additions & 15 deletions uxsim/uxsim.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,13 @@ def __init__(s, W, name, x, y, signal=[0], signal_offset=0, flow_capacity=None,
s.id = len(s.W.NODES)
s.name = name
s.auto_rename = auto_rename
if s.name in [n.name for n in s.W.NODES]:
if s.name in s.W.NODES_NAME_DICT.keys():
if auto_rename:
s.name = s.name+"_renamed"+"".join(s.W.rng.choice(list(string.ascii_letters + string.digits), size=8))
else:
raise ValueError(f"Node name {s.name} already used by another node. Please specify a unique name.")
s.W.NODES.append(s)
s.W.NODES_NAME_DICT[s.name] = s

def __repr__(s):
return f"<Node {s.name}>"
Expand Down Expand Up @@ -554,12 +555,13 @@ def __init__(s, W, name, start_node, end_node, length, free_flow_speed=20, jam_d
s.id = len(s.W.LINKS)
s.name = name
s.auto_rename = auto_rename
if s.name in [l.name for l in s.W.LINKS]:
if s.name in s.W.LINKS_NAME_DICT.keys():
if auto_rename:
s.name = s.name+"_renamed"+"".join(s.W.rng.choice(list(string.ascii_letters + string.digits), size=8))
else:
raise ValueError(f"Link name {s.name} already used by another link. Please specify a unique name.")
s.W.LINKS.append(s)
s.W.LINKS_NAME_DICT[s.name] = s
s.start_node.outlinks[s.name] = s
s.end_node.inlinks[s.name] = s

Expand Down Expand Up @@ -1084,6 +1086,9 @@ def end_trip(s):

s.record_log(enforce_log=1)

if s.W.reduce_memory_delele_vehicle_route_pref:
s.route_pref = None

def carfollow(s):
"""
Drive withing a link.
Expand Down Expand Up @@ -1420,7 +1425,16 @@ class World:
World (i.e., simulation environment). A World object is consistently referred to as `W` in this code.
"""

def __init__(W, name="", deltan=5, reaction_time=1, duo_update_time=600, duo_update_weight=0.5, duo_noise=0.01, eular_dt=120, eular_dx=100, random_seed=None, print_mode=1, save_mode=1, show_mode=0, route_choice_principle="homogeneous_DUO", route_choice_update_gradual=False, show_progress=1, show_progress_deltat=600, tmax=None, vehicle_logging_timestep_interval=1, instantaneous_TT_timestep_interval=5, hard_deterministic_mode=False, meta_data={}, user_attribute=None, user_function=None):
def __init__(W, name="", deltan=5, reaction_time=1,
duo_update_time=600, duo_update_weight=0.5, duo_noise=0.01, route_choice_principle="homogeneous_DUO", route_choice_update_gradual=False, instantaneous_TT_timestep_interval=5,
eular_dt=120, eular_dx=100,
random_seed=None,
print_mode=1, save_mode=1, show_mode=0, show_progress=1, show_progress_deltat=600,
tmax=None,
vehicle_logging_timestep_interval=1,
reduce_memory_delele_vehicle_route_pref=False,
hard_deterministic_mode=False,
meta_data={}, user_attribute=None, user_function=None):
"""
Create a World.

Expand Down Expand Up @@ -1469,6 +1483,8 @@ def __init__(W, name="", deltan=5, reaction_time=1, duo_update_time=600, duo_upd
If it is longer than the DUO update timestep interval, it is substituted by DUO update timestep interval to maintain reasonable route choice behavior.
hard_deterministic_mode : bool, optional
If True, the simulation will not use any random variables. At a merging node, a link with higher merge_priority will be always prioritized, and vehicles always choose the shortest path. This may be useful for analysis that need strict predictability. Be aware that the simulation results will be significantly different from ones with `hard_deterministic_mode=False`.
reduce_memory_delele_vehicle_route_pref : bool, optional
If True, the simulation will delete the route preference of vehicles after its ends. This is useful when the route preference is not needed after the simulation ends.
meta_data : dict, optinal
Meta data for simulation scenario. Can store arbitrary data, such as licences and simulation explanation.
user_attribute : any, optinal
Expand Down Expand Up @@ -1513,6 +1529,9 @@ def __init__(W, name="", deltan=5, reaction_time=1, duo_update_time=600, duo_upd
W.NODES = []
W.LINKS = []

W.NODES_NAME_DICT = {} #map from name to node object
W.LINKS_NAME_DICT = {}

W.vehicle_logging_timestep_interval = vehicle_logging_timestep_interval

W.route_choice_principle = route_choice_principle
Expand All @@ -1529,6 +1548,9 @@ def __init__(W, name="", deltan=5, reaction_time=1, duo_update_time=600, duo_upd
W.show_progress = show_progress
W.show_progress_deltat_timestep = int(show_progress_deltat/W.DELTAT)

## memory setting
W.reduce_memory_delele_vehicle_route_pref = reduce_memory_delele_vehicle_route_pref

## system setting
W.name = name

Expand Down Expand Up @@ -2059,13 +2081,11 @@ def get_node(W, node):
if node in W.NODES:
return node
else:
for n in W.NODES:
if n.name == node.name:
return n
if node.name in W.NODES_NAME_DICT:
return W.NODES_NAME_DICT[node.name]
elif type(node) is str:
for n in W.NODES:
if n.name == node:
return n
if node in W.NODES_NAME_DICT:
return W.NODES_NAME_DICT[node]
raise Exception(f"'{node}' is not Node in this World")

def get_link(W, link):
Expand All @@ -2089,13 +2109,11 @@ def get_link(W, link):
if link in W.LINKS:
return link
else:
for l in W.LINKS:
if l.name == link.name:
return l
if link.name in W.LINKS_NAME_DICT:
return W.LINKS_NAME_DICT[link.name]
elif type(link) is str:
for l in W.LINKS:
if l.name == link:
return l
if link in W.LINKS_NAME_DICT:
return W.LINKS_NAME_DICT[link]
raise Exception(f"'{link}' is not Link in this World")

def get_nearest_node(W, x, y):
Expand Down