Skip to content

Commit fc64909

Browse files
committed
Merge remote-tracking branch 'origin/helmet5-experimental' into feat/park-and-ride-choice-model
2 parents bfc2ffb + 97c2224 commit fc64909

File tree

4 files changed

+115
-30
lines changed

4 files changed

+115
-30
lines changed

Scripts/assignment/emme_bindings/mock_project.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,9 @@ def id(self):
712712
def outgoing_segments(self, include_hidden=False):
713713
return (s for s in self.network.transit_segments(include_hidden)
714714
if s.i_node is self)
715+
716+
def incoming_links(self):
717+
return (l for l in self.network.links() if l.j_node is self)
715718

716719
class Link(NetworkObject):
717720
def __init__(self,
@@ -825,6 +828,7 @@ def __init__(self, network: Network, line: TransitLine, link: Link):
825828
self, network, network._extra_attr["TRANSIT_SEGMENT"])
826829
self.line = line
827830
self.link = link
831+
self.loop_index = 1
828832
self.allow_alightings = False
829833
self.allow_boardings = False
830834
self.transit_time_func = 0

Scripts/datahandling/zonedata.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ def __init__(self, data_dir: str, zone_numbers: numpy.array):
8383
self.nr_zones = len(self.zone_numbers)
8484
self.nr_zones_hs15 = len(self.zone_numbers_hs15)
8585
self["population_density"] = pop / landdata["builtar"]
86+
# Filter indexes where population_density > 50000
87+
high_population_density = self["population_density"].index[self["population_density"] > 50000]
88+
if len(high_population_density) > 0:
89+
log.warn(f"Zone(s) {list(high_population_density)} have an abnormally high population density. Make sure that the builtar values in the .lnd file are calculated correctly.")
8690
wp = workdata.pop("total")
8791
self["workplaces"] = wp
8892
ShareChecker({})["Workplace shares"] = workdata.sum(axis="columns")

Scripts/utils/modify_network.py

Lines changed: 85 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,94 @@
1+
import pandas as pd
12
import parameters.assignment as param
23

4+
# Fallback logger for use within EMME
5+
try:
6+
import utils.log as log
7+
except ImportError:
8+
class FallbackLogger:
9+
def info(self, message):
10+
print(f"[INFO] {message}")
11+
12+
def debug(self, message):
13+
print(f"[DEBUG] {message}")
14+
15+
def warn(self, message):
16+
print(f"[WARN] {message}")
17+
18+
log = FallbackLogger()
19+
320
# Utility functions that modify a network. Functions take a network as input and return the modified network
421

522
def add_bus_stops(network):
23+
# Initialize an empty dictionary to store line IDs and maximum stop distances
24+
data = {"line_id": [], "maximum_stop_distance": [], "is_motorway": [], "loops": []}
25+
high_distance_lines = []
26+
looped_lines = []
27+
628
for line in network.transit_lines():
7-
if line.mode.id in param.stop_codes:
8-
stop_codes = param.stop_codes[line.mode.id]
9-
for segment in line.segments():
10-
is_stop = segment.i_node.data2 in stop_codes
11-
if line.mode.id in "de":
12-
# Non-HSL bus lines
13-
not_hsl = segment.i_node.label not in param.hsl_area
14-
if line.id[-1] == '1':
15-
# Line starts in HSL area
16-
segment.allow_alightings = not_hsl and is_stop
17-
segment.allow_boardings = is_stop
18-
elif line.id[-1] == '2':
19-
# Line ends in HSL area
20-
segment.allow_alightings = is_stop
21-
segment.allow_boardings = not_hsl and is_stop
22-
elif line.id[-1] == '3':
23-
#Line is circular and possibly goes through HSL area
24-
#not perfect solution, out-in-in-out allows for in-in routes as well
25-
segment.allow_alightings = is_stop
26-
segment.allow_boardings = is_stop
27-
else:
28-
raise ValueError(
29-
"Unknown direction code for line " + line.id)
30-
else:
29+
if line.mode.id in param.stop_codes:
30+
stop_codes = param.stop_codes[line.mode.id]
31+
stop_distance = 0
32+
max_stop_distance = 0
33+
is_motorway = 0
34+
loop = 0
35+
36+
for segment in line.segments():
37+
if segment.loop_index > 1 and loop == 0:
38+
loop = 1
39+
looped_lines.append(line.id)
40+
segment_length = segment.link.length
41+
linktype = segment.link.type % 100
42+
if linktype in param.roadclasses and is_motorway == 0:
43+
# Car link with standard attributes
44+
roadclass = param.roadclasses[linktype]
45+
if roadclass.type == "motorway":
46+
is_motorway = 1
47+
48+
stop_distance += segment_length
49+
is_stop = segment.i_node.data2 in stop_codes
50+
51+
if is_stop:
52+
if stop_distance > max_stop_distance:
53+
max_stop_distance = stop_distance
54+
stop_distance = 0
55+
56+
if line.mode.id in "de":
57+
58+
not_hsl = segment.i_node.label not in param.hsl_area
59+
if line.id[-1] == '1':
60+
segment.allow_alightings = not_hsl and is_stop
61+
segment.allow_boardings = is_stop
62+
elif line.id[-1] == '2':
63+
segment.allow_alightings = is_stop
64+
segment.allow_boardings = not_hsl and is_stop
65+
elif line.id[-1] == '3':
3166
segment.allow_alightings = is_stop
3267
segment.allow_boardings = is_stop
68+
else:
69+
raise ValueError(
70+
"Unknown direction code for line " + line.id)
71+
else:
72+
segment.allow_alightings = is_stop
73+
segment.allow_boardings = is_stop
74+
75+
# Append data for the current line
76+
data["line_id"].append(line.id)
77+
data["maximum_stop_distance"].append(max_stop_distance)
78+
data["is_motorway"].append(is_motorway)
79+
data["loops"].append(loop)
80+
81+
if line.mode.id in "bg" and max_stop_distance > 3 and not is_motorway: # and int(line.id[0]) < 6
82+
log.debug(f"Line: {line.id},\t Maximum distance between consecutive stops: {max_stop_distance:.2f}")
83+
high_distance_lines.append(line.id)
84+
85+
# TODO: Print to results folder
86+
max_stop_distances = pd.DataFrame(data)
87+
88+
if high_distance_lines:
89+
log.info(f"{len(high_distance_lines)} HSL line(s) have a maximum stop distance greater than 3 km and no motorway sections.")
3390

34-
return network
91+
if looped_lines:
92+
log.warn(f"Line(s) {looped_lines} traverse over the same links multiple times.")
93+
94+
return network

Scripts/utils/validate_network.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,23 @@ def validate(network, fares=None):
6262
unofficial_nodes = set()
6363
nr_links = 0
6464
nr_zero_gradients = 0
65+
66+
# Make sure that cars, pedestrians cyclists can access all centroids
67+
unaccessible_centroids = []
68+
69+
required_modes = {'a', 'f', 'c'} # Modes for pedestrians, cyclists, and cars
70+
71+
for centroid in network.centroids():
72+
accessible_modes = {mode.id for link in centroid.incoming_links() for mode in link.modes}
73+
if not required_modes.issubset(accessible_modes):
74+
unaccessible_centroids.append(centroid.id)
75+
76+
if unaccessible_centroids:
77+
msg = f"Centroids {unaccessible_centroids} are not accessible by pedestrians, cyclists and/or passenger cars."
78+
log.error(msg)
79+
raise ValueError(msg)
80+
81+
6582
for link in network.links():
6683
nr_links += 1
6784
if not link.modes:
@@ -132,13 +149,13 @@ def validate(network, fares=None):
132149
raise ValueError(msg)
133150

134151
try:
135-
if link['@kaltevuus'] == 0:
152+
if link['@kaltevuus'] == 0 and not link.i_node.is_centroid and not link.j_node.is_centroid:
136153
nr_zero_gradients += 1
137154
except KeyError:
138-
raise ValueError("Gradients not defined. Use an extra_links file with @kaltevuus,\
139-
or create extra attribute @kaltevuus with zeros.\
140-
@kaltevuus is used to model the effect of hills on bicycle route choice,\
141-
setting @kaltevuus to 0 on links will ignore hills.")
155+
raise ValueError("Gradients not defined. Use an extra_links file with @kaltevuus, " +
156+
"or create extra attribute @kaltevuus with zeros. " +
157+
"@kaltevuus is used to model the effect of hills on bicycle route choice, " +
158+
"setting @kaltevuus to 0 on links will ignore hills.")
142159
zero_gradient_ratio = (nr_zero_gradients/nr_links)*100
143160
if zero_gradient_ratio > 20:
144161
msg = "{} % of links have a gradient of 0.".format(zero_gradient_ratio)

0 commit comments

Comments
 (0)