From dc32a3e29b34fb9a2ff5f4143d6a69675601841c Mon Sep 17 00:00:00 2001 From: hsl-petrhaj <127391244+hsl-petrhaj@users.noreply.github.com> Date: Wed, 22 Nov 2023 09:23:27 +0200 Subject: [PATCH] Network validation vol2 (#534) *Reorganizing validation tests *Adjusting the testing data so that it passes through the validation checks --------- Co-authored-by: Jens West --- Scripts/assignment/emme_assignment.py | 1 + .../assignment/emme_bindings/mock_project.py | 67 +++-- Scripts/tests/emme_only/__init__.py | 0 .../integration/test_network_validation.py | 279 ++++++++++++------ .../test_data/Network/base_network_test.txt | 2 +- .../Results/test/Matrices/cost_aht.omx | Bin 28468 -> 28393 bytes .../Results/test/Matrices/cost_iht.omx | Bin 28468 -> 28393 bytes .../Results/test/Matrices/cost_pt.omx | Bin 28468 -> 28393 bytes .../Results/test/Matrices/dist_aht.omx | Bin 39322 -> 39457 bytes .../Results/test/Matrices/dist_iht.omx | Bin 39322 -> 39461 bytes .../Results/test/Matrices/dist_pt.omx | Bin 39327 -> 39465 bytes .../Results/test/Matrices/time_aht.omx | Bin 41843 -> 41664 bytes .../Results/test/Matrices/time_iht.omx | Bin 41859 -> 41682 bytes .../Results/test/Matrices/time_pt.omx | Bin 41842 -> 41657 bytes Scripts/utils/validate_loaded_network.py | 15 + Scripts/utils/validate_network.py | 2 +- 16 files changed, 258 insertions(+), 108 deletions(-) create mode 100644 Scripts/tests/emme_only/__init__.py create mode 100644 Scripts/utils/validate_loaded_network.py diff --git a/Scripts/assignment/emme_assignment.py b/Scripts/assignment/emme_assignment.py index ec663627..a5c20762 100644 --- a/Scripts/assignment/emme_assignment.py +++ b/Scripts/assignment/emme_assignment.py @@ -336,6 +336,7 @@ def _add_bus_stops(self): else: segment.allow_alightings = is_stop segment.allow_boardings = is_stop + self.mod_scenario.publish_network(network) def _create_matrices(self, time_period, id_hundred, id_ten): diff --git a/Scripts/assignment/emme_bindings/mock_project.py b/Scripts/assignment/emme_bindings/mock_project.py index b10731a4..76681c2d 100644 --- a/Scripts/assignment/emme_bindings/mock_project.py +++ b/Scripts/assignment/emme_bindings/mock_project.py @@ -1,5 +1,5 @@ from __future__ import annotations -from typing import Dict, Iterable, List, Optional, Union +from typing import Dict, Iterable, List, Optional, Tuple, Union import numpy # type: ignore from collections import namedtuple import copy @@ -241,10 +241,7 @@ def transit_line_transaction(self, transaction_file, revert_on_error=True, vehicle_id = int(rec[3]) headway = float(rec[4]) itinerary = [] - ttf = [] - data1 = [] - data2 = [] - data3 = [] + segment_data = [] while True: segrec = f.readline().replace("'", " ").split() if not segrec or segrec[0] in "amd": @@ -253,21 +250,24 @@ def transit_line_transaction(self, transaction_file, revert_on_error=True, elif segrec[0] not in ("c", "path=no"): itinerary.append(segrec[0]) try: - ttf.append(int(segrec[2][4:])) - data1.append(float(segrec[3][4:])) - data2.append(float(segrec[4][4:])) - data3.append(float(segrec[5][4:])) + symbol = segrec[1][4] + segment_data.append({ + "allow_alightings": symbol in ">+", + "allow_boardings": symbol in "<+", + "transit_time_func": int(segrec[2][4:]), + "data1": float(segrec[3][4:]), + "data2": float(segrec[4][4:]), + "data3": float(segrec[5][4:]), + }) except IndexError: pass line = network.create_transit_line( line_id, vehicle_id, itinerary) - for i, segment in enumerate(line.segments()): - segment.transit_time_func = ttf[i] - segment.data1 = data1[i] - segment.data2 = data2[i] - segment.data3 = data3[i] + for data, segment in zip(segment_data, line.segments()): + segment.__dict__.update(data) elif rec[0] == "m": line = network.transit_line(idx=rec[1]) + vehicle_id = int(rec[3]) headway = float(rec[4]) else: raise SyntaxError("Unknown update code") @@ -532,7 +532,6 @@ def __init__(self): self._links = {} self._vehicles = {} self._lines = {} - self._segments = [] self._objects = { "NODE": self.nodes, "LINK": self.links, @@ -614,8 +613,9 @@ def transit_line(self, idx) -> 'TransitLine': def transit_lines(self) -> Iterable['TransitLine']: return iter(self._lines.values()) - def transit_segments(self) -> Iterable: - return iter(self._segments) + def transit_segments(self, include_hidden=False) -> Tuple['Segment']: + return (segment for line in self.transit_lines() + for segment in line.segments(include_hidden)) def create_transit_line(self, idx: str, transit_vehicle_id: int, itinerary: List[List[str]]) -> 'TransitLine': line = TransitLine(self, idx, transit_vehicle_id) @@ -623,9 +623,10 @@ def create_transit_line(self, idx: str, transit_vehicle_id: int, itinerary: List for i in range(len(itinerary) - 1): link = self.link(itinerary[i], itinerary[i + 1]) segment = TransitSegment(self, line, link) - self._segments.append(segment) line._segments.append(segment) link._segments.append(segment) + line._segments.append( + HiddenSegment(self, line, self.node(itinerary[-1]))) return line @@ -700,6 +701,9 @@ def __init__(self, def id(self): return str(self.number) + def outgoing_segments(self, include_hidden=False): + return (s for s in self.network.transit_segments(include_hidden) + if s.i_node is self) class Link(NetworkObject): def __init__(self, @@ -766,8 +770,11 @@ def mode(self) -> Mode: def segment(self, idx) -> 'TransitSegment': return self._segments[idx] - def segments(self) -> Iterable: - return iter(self._segments) + def segments(self, include_hidden=False) -> Iterable: + if include_hidden: + return iter(self._segments) + else: + return iter(self._segments[:-1]) class TransitSegment(NetworkObject): @@ -776,6 +783,8 @@ def __init__(self, network: Network, line: TransitLine, link: Link): self, network, network._extra_attr["TRANSIT_SEGMENT"]) self.line = line self.link = link + self.allow_alightings = False + self.allow_boardings = False self.transit_time_func = 0 self.dwell_time = 0.01 @@ -792,6 +801,24 @@ def j_node(self) -> Node: return self.link.j_node +class HiddenSegment(TransitSegment): + def __init__(self, network, line, node): + TransitSegment.__init__(self, network, line, None) + self._node = node + + @property + def id(self): + return "{}-{}".format(self.line, self.i_node) + + @property + def i_node(self): + return self._node + + @property + def j_node(self): + return None + + class ExistenceError(Exception): pass diff --git a/Scripts/tests/emme_only/__init__.py b/Scripts/tests/emme_only/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/Scripts/tests/integration/test_network_validation.py b/Scripts/tests/integration/test_network_validation.py index 54aeb045..a276c1df 100644 --- a/Scripts/tests/integration/test_network_validation.py +++ b/Scripts/tests/integration/test_network_validation.py @@ -1,16 +1,15 @@ +from argparse import ArgumentTypeError import unittest, os, pandas -from assignment.emme_bindings.mock_project import MockProject +from assignment.emme_bindings.mock_project import MockProject, MODE_TYPES from assignment.datatypes.transit_fare import TransitFareZoneSpecification +from assignment.mock_assignment import MockAssignmentModel +from datahandling.matrixdata import MatrixData from utils.validate_network import validate +from utils.validate_loaded_network import validate_loaded +from parameters.assignment import time_periods +import parameters.zone as zone_param import copy -MODE_TYPES = { - "1": "AUTO", - "2": "TRANSIT", - "3": "AUX_TRANSIT", - "4": "AUX_AUTO", -} - class EmmeAssignmentTest(unittest.TestCase): def test_assignment(self): context = MockProject() @@ -27,7 +26,12 @@ def test_assignment(self): "start": 35, }, })) + + # mock_result_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), + # "..", "test_data", "Results","test") + #ass_model = MockAssignmentModel(MatrixData(mock_result_path)) network0 = context.modeller.emmebank.scenario(scenario_id).get_network() + #ass_model.prepare_network(network = network0) #the number is the car cost per km #Mode check network1 = copy.deepcopy(network0) @@ -36,100 +40,203 @@ def test_assignment(self): network1, fares) - #Link check, link type should not be one - network2 = copy.deepcopy(network0) - node1 = network2.create_node(800900, False) - node2 = network2.create_node(800901, False) - link = network2.create_link(800900, 800901, "haf") + #Link check cases + cases = [#Link check, link type should not be one + {"node1_centroid":False, + "node2_centroid":False, + "link_modes":"haf", + "link_type":1, + "link_length":1.0}, + #Link check, link modes must not be empty + {"node1_centroid":False, + "node2_centroid":False, + "link_modes":"", + "link_type":142, + "link_length":1.0}, + #Link check, link modes must not be just h + {"node1_centroid":False, + "node2_centroid":False, + "link_modes":"h", + "link_type":142, + "link_length":1.0}, + #Link check, if link type is not 70 (vaihtokävely), then length must not be zero + {"node1_centroid":False, + "node2_centroid":False, + "link_modes":"haf", + "link_type":142, + "link_length":0}, + #Link check, link should not have type 100 + {"node1_centroid":False, + "node2_centroid":False, + "link_modes":"haf", + "link_type":100, + "link_length":1.0}, + #Link check, link should not have type 999 + {"node1_centroid":False, + "node2_centroid":False, + "link_modes":"haf", + "link_type":999, + "link_length":1.0}, + #Link check, link must not directly connect two centroids + {"node1_centroid":True, + "node2_centroid":True, + "link_modes":"haf", + "link_type":142, + "link_length":1.0}, + ] + node1_id = 800900 + node2_id = 800901 + for case in cases: + self.link_check_network(network0, fares, + node1_id, case["node1_centroid"], + node2_id, case["node2_centroid"], + case["link_modes"], + case["link_type"], + case["link_length"]) + + # #Link check, link must have VDF if car link + # network = copy.deepcopy(network0) + # node1 = network.create_node(node1_id, False) + # node2 = network.create_node(node2_id, False) + # link = network.create_link(node1_id, node2_id, "hc") + # #Check if link type equals 1 + # link.type = 142 + # link.length = 1.0 + # link.volume_delay_func = 0 + # self.assertRaises(ValueError, validate, + # network, + # fares) + + #Link check, tram link must have right AHT speed + network = copy.deepcopy(network0) + node1 = network.create_node(node1_id, False) + node2 = network.create_node(node2_id, False) + link = network.create_link(node1_id, node2_id, "pt") #Check if link type equals 1 - link.type = 1 + link.type = 2 link.length = 1.0 + link.data1 = 1122 #meaning 001122 - aappii format, refer to network description self.assertRaises(ValueError, validate, - network2, - fares) + network, + fares) - #Link check, link modes must be h at minimum - network3 = copy.deepcopy(network0) - node1 = network3.create_node(800902, False) - node2 = network3.create_node(800903, False) - link2 = network3.create_link(800902, 800903, "") - link2.type = 142 - link2.length = 1.0 - + #Link check, tram link must have right PT speed + network = copy.deepcopy(network0) + node1 = network.create_node(node1_id, False) + node2 = network.create_node(node2_id, False) + link = network.create_link(node1_id, node2_id, "pt") + #Check if link type equals 1 + link.type = 2 + link.length = 1.0 + link.data1 = 220022 self.assertRaises(ValueError, validate, - network3, - fares) + network, + fares) - #Link check, link modes must be h at minimum - network4 = copy.deepcopy(network0) - node1 = network4.create_node(800904, False) - node2 = network4.create_node(800905, False) - link3 = network4.create_link(800904, 800905, "h") - link3.type = 142 - link3.length = 1.0 - + #Link check, tram link must have right IHT speed + network = copy.deepcopy(network0) + node1 = network.create_node(node1_id, False) + node2 = network.create_node(node2_id, False) + link = network.create_link(node1_id, node2_id, "pt") + #Check if link type equals 1 + link.type = 2 + link.length = 1.0 + link.data1 = 221100 self.assertRaises(ValueError, validate, - network4, - fares) + network, + fares) - #Link check, if link type is not 70 (vaihtokävely), then length must not be zero - network5 = copy.deepcopy(network0) - node1 = network5.create_node(800906, False) - node2 = network5.create_node(800907, False) - link4 = network5.create_link(800906, 800907, "haf") - link4.type = 142 - link4.length = 0.0 - - self.assertRaises(ValueError, validate, - network5, - fares) - - #Link check, link should not have only mode h, because it is removed later during the assignment - network6 = copy.deepcopy(network0) - node1 = network6.create_node(800909, False) - node2 = network6.create_node(800910, False) - link5 = network6.create_link(800909, 800910, "h") - link5.type = 142 - link5.length = 1.0 - - self.assertRaises(ValueError, validate, - network6, - fares) + #Segment check, train or metro travel time us1=0 before stopping (noalin=0 or noboan=0) + # Check line encoding, if row's @ccost=1 + # only if mode is type mr + network = copy.deepcopy(network0) + itinerary = [] + node1_id = "802118" + node2_id = "802119" + node3_id = "802120" + itinerary.append(node1_id) + itinerary.append(node2_id) + itinerary.append(node3_id) + node1 = network.create_node(node1_id, False) + node2 = network.create_node(node2_id, False) + node3 = network.create_node(node3_id, False) + link = network.create_link(node1_id, node2_id, "mr") + link = network.create_link(node2_id, node3_id, "mr") + line = network.create_transit_line( + '3002A3', 5, itinerary) + hdw_attrs = [f"@hw_{tp}" for tp in time_periods] + for hdwy in hdw_attrs: + line[hdwy] = 5.0 + line._segments[0].data1 = 0 + line._segments[1].data1 = 0 + line._segments[0].allow_boardings = 0 + line._segments[0].allow_alightings = 0 + line._segments[1].allow_boardings = 1 + line._segments[1].allow_alightings = 1 + self.assertRaises(ValueError, validate_loaded, + network, + fares) - #Link check, link should not have type 100 - network7 = copy.deepcopy(network0) - node1 = network7.create_node(800911, False) - node2 = network7.create_node(800912, False) - link6 = network7.create_link(800911, 800912, "haf") - link6.type = 100 - link6.length = 1.0 + #Segment check, train or metro travel time us1 is not 0 before stopping (noalin=1 and noboan=1) + # Check line encoding, if row's @ccost=1 + # only if mode is type mr + network = copy.deepcopy(network0) + itinerary = [] + node1_id = "802121" + node2_id = "802122" + node3_id = "802123" + itinerary.append(node1_id) + itinerary.append(node2_id) + itinerary.append(node3_id) + node1 = network.create_node(node1_id, False) + node2 = network.create_node(node2_id, False) + node3 = network.create_node(node3_id, False) + link = network.create_link(node1_id, node2_id, "mr") + link = network.create_link(node2_id, node3_id, "mr") + line = network.create_transit_line( + '3002A4', 5, itinerary) + hdw_attrs = [f"@hw_{tp}" for tp in time_periods] + for hdwy in hdw_attrs: + line[hdwy] = 5.0 + line._segments[0].data1 = 5 + line._segments[1].data1 = 0 + line._segments[0].allow_boardings = 0 + line._segments[0].allow_alightings = 0 + line._segments[1].allow_boardings = 0 + line._segments[1].allow_alightings = 0 + self.assertRaises(ValueError, validate_loaded, + network, + fares) + #Line check, headway should not be 0,1 + network = copy.deepcopy(network0) + itinerary = [] + itinerary.append("802113") + itinerary.append("802114") + line = network.create_transit_line( + '3002A2', 5, itinerary) + hdw_attrs = [f"@hw_{tp}" for tp in time_periods] + for hdwy in hdw_attrs: + line[hdwy] = 0.001 self.assertRaises(ValueError, validate, - network7, - fares) + network, + fares) - #Link check, link should not have type 999 - network8 = copy.deepcopy(network0) - node1 = network8.create_node(800913, False) - node2 = network8.create_node(800914, False) - link7 = network8.create_link(800913, 800914, "haf") - link7.type = 999 - link7.length = 1.0 - self.assertRaises(ValueError, validate, - network8, - fares) - #Link check, link must not directly connect two centroids - network9 = copy.deepcopy(network0) - node1 = network9.create_node(800915, True) - node2 = network9.create_node(800916, True) - link8 = network9.create_link(800915, 800916, "haf") - link8.type = 142 - link8.length = 1.0 + def link_check_network(self, network0, fares, node1_id, + node1_iscentroid, node2_id, node2_iscentroid, + link_modes, link_type, link_length): + network = copy.deepcopy(network0) + node1 = network.create_node(node1_id, node1_iscentroid) + node2 = network.create_node(node2_id, node2_iscentroid) + link = network.create_link(node1_id, node2_id, link_modes) + #Check if link type equals 1 + link.type = link_type + link.length = link_length self.assertRaises(ValueError, validate, - network9, + network, fares) diff --git a/Scripts/tests/test_data/Network/base_network_test.txt b/Scripts/tests/test_data/Network/base_network_test.txt index 0caa23ba..39f20602 100644 --- a/Scripts/tests/test_data/Network/base_network_test.txt +++ b/Scripts/tests/test_data/Network/base_network_test.txt @@ -1019,7 +1019,7 @@ a 197037 185295 .420000 hcvky 123 2.0 1 2000 97 90.9356 a 197037 197038 .220000 hcvkyhbgde 129 1.0 7 1850 81 0 a 179244 183602 .220000 hcvkyhbgde 129 1.0 7 1850 81 0 a 197038 185294 .070000 hbgdehaf 629 1.0 7 1850 81 0 -a 197038 197068 .102800 hcvkybgdeaf 129 1.0 0 0 0 0 +a 197038 197068 .102800 hcvkybgdeaf 129 1.0 7 0 0 0 a 197046 196982 .190000 hcvkybgdeaf 131 2.0 2 1600 73 167.939 a 197046 198844 .173900 haf 70 1.0 0 0 0 0 a 197048 280062 .672500 hcvkybgdeaf 324 3.0 6 2000 97 101.269 diff --git a/Scripts/tests/test_data/Results/test/Matrices/cost_aht.omx b/Scripts/tests/test_data/Results/test/Matrices/cost_aht.omx index ec74747e32cf3c03b54b7b28b495e2666833831f..dede410ed54ad5e947a0b4a2f06662e160178201 100644 GIT binary patch delta 719 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 Vv~Li4``J37i;uoydR6ng{{aKv1qJ{B diff --git a/Scripts/tests/test_data/Results/test/Matrices/dist_iht.omx b/Scripts/tests/test_data/Results/test/Matrices/dist_iht.omx index d1d89ce532624ff4c88c1b4b0aaccb2a96017efd..670874a4e419d368daad252af6d3d3dfa36185e6 100644 GIT binary patch delta 928 zcmZuvO>7cT5Z?Eog()te8*`aZ3v|CJnJh zR4}`pLG4Sw2g(S1Fn?7vYMQjRfH25^j+{Ws^5 zuxJ{Ejw6Q;?2NiFo9KS!{lRy<-vFaf64wix!~5a++$J4bfI@GpY<1 z-Co8xe)ps(9j7^+6QES|GRD;erbKB6gmnQzS2)~ol6{Zch8KKLWxYn-07QHO<`0v7 z-+Ko4CI-2K2?6&WXk2Z2kh3NP^pLpE&oXpdztb3uuyNX$x&W=niT*wt`VpxcsdQ5D zmlAwDlT59w@@lBYg*$xO$jkGIR3^#C^Ze?P0?KiAC6(`MjM&f^d25NRTB4B1sI~MT z0A5F@a61a$qI1xj=J3p8t*zqxU|UMdpDG&1CI-1T83A7tG_H{uUw2ydE+*;O%-&%zEOtw&ExS|p%$A*`0Noows1YyX|*Xu;}}V zGmv9@SYekX@u_M%At(SJ+HSC}E*{v%k0BoH!VNeRj5F)$R}vJ1b;1W#wI74fewY5a zzvQ7ay9EZeW<`>W!m;vgvKEDRiI`R2DE9{#B0O-p)_}`3 z5^J!P=J0pAIdIBPI4?xS0&YT8+;17b7gO_NlAJA1$rE;i$jI~Kx#<~s+=NQ9RG7|{ z{?|CUQ*%8xVHTF9yy>Cyx%{}CEy*)u2H?b5sbKm!BTiWx!p-y%!kvbf=}S zPzB=De~S*Zcl=dO0hMuzV#ZQ=#lS$s#+<~n#D&CJkRDO)cU`bXS)wxC7)g%TCx&dU4K>sZT*F$VC8u8 z;p3ivx#MRJSG(HG2^oSaEOKo~5_jD@O+mYy7QL<$*jCRq)|q#=$lcX)S<9cy=;?e` zo0`_`(2i#x={Ya2q-V5zR!^7o=}8MT^(t329#tiv9Hzb-kPoN4CX=Lx<;9Il>k=G1r*lqU*40Cwf!O$n*6 zFstLuxxcge0xew9J>S-l**G{V3pjk+^rQ(FUr$^3TN6*^EWGIAM>7U}WjAwoRKbPU kW;1_^kgV{G4=?)I4%t9#`}wku-KdxYSqZhVQ!hW`-%h6S@Bjb+ delta 950 zcmY*W-)j>=5Z>J!B$pn&r&rsP2x4}r6SZ~ zL2IjA9H{X@+t-4E*A*(&hxiAGsZYTN$)C_i5wYG+kM43iH{Un&?d;6z2eM3w5+}>A zYR8h14ulaxLG9C5r?&OQxeSBqwb`S%s;D{qyPnPn2B{rgnz*iS=a;7|cS}XCG+yQSowXKS> zR<2Mre=gEZW*d`u8h(VXLEIf2{K%M$E!wtxf59psq z3obgjXOMxdDS^bpa8kZUR>JTu7BSCYd7Q< zh}8&9g?J3*BOF1U^!M~%mMVu2V7vlvW1J-)Ymmh*g9C;CL{fdu)mxbcNzFN2dte8L zztYWtGhV{EAuJSe3+9DGrs#ViIWrQ7KoECP#F@wo_u!(6h&zG%tiZ>Enbu3$N2xpd9ANjRof&jjPT( znz0pVO><=LbB7-m9lmp*fxpp9;)a)?aR*k0wYI%5Q?$Wh1y0Bk@!WSJnsSo0YC%iMQ;`aDIV0_%&u+3S$1aLd;k5}KYzc!BlWkW z)J^Ko)zbrh5n+Uoq`ms^XpcT*OKU+fHGc|+>5KaWmspRb51%=t3A#fc;oiR9K5fOw z_TMZy*tUkeWg~gG<kxBHRD%CG1$)e#RrDAJE!-v zXrR4^D$Qv9tm2PsXz{g3#tZug>aA>y%H()OYx6GwnyXf3^(T6{RN)e)yB!2W5JbX0<8s2baZznd1}Z7c@`B~+x=aM_Lw#)g;bmw2!2|ME;B8A<+l(_a)}#gthHTA#b3+hRLYN(= zvtR?rvYjT*s6Y<>5gY}Q2)+c?JhKF^Ry!gHWDhRbB@kwG9`@7lG2r3g1M30L!2_q^ zR`P+!p#)(#sMRZBz;fJ&mgnc#phA}{n?m&sFe>FB-W0G}wi{7VKm*O)EYZtW+T$SW zlt`RH^&+D6L6|fn!kg=W^b0UVu+C%x@a66(i_Cz5lOGj~`w>D70pD^r0}+J^-$m71u!eM7 zW;F!l*;FLE6q|vT2=iwsr$8OzQ(+zrlsd}~3(;38!9=(KtdfZl{N5Q-FJlszmX_tf zgX|6t$?*v5i1DGkE&e`+5$&>|l4K(iSrAi(A;7>iQ4xh|Aux~&!1+KbjG~iRdC1x9 znX9lTLME!vvTTHi(!f5O%wKptn@G1_MJ5J~Rlis_TFpMaj+YWmyttwKaqiQ@B^w_d znOkNMgRgPQh#b2)sYiH9MP5|+id~0~?Od?@l4^w~Y5VpdYFSj_>Ln+8n|Hi*96Qih ziHhbulkBV>AJ1Q$s-OI6;ufJUejyJ@gx5hQLlTJ{jIipw=iSUmw0-pv|M_$Z7Hp{Fn%3)QqBP)S6rrO zRaSrC;BEFB{lsW?cHB0_nu7;4ZBvqKo#ULGrGZtNkp}7GN@k_cfqFw)eOTV1u1mk? zi`&p2E310Mk)K@YrnL_WL-Ut?+;}tQ1pR4V@6p;OwQHx>%VmmZEoTHF>vNm(J=-@Y z#B^NYx*wAlwCrbYJ4{JV>xsrkB5@LzzyY54VNaIwJNx7J)OQCaG8n-5KdxGtt(oz>|rlnUiZ>xS87x5Tw{~(jsz^y)HN0T_Wm$P3JvP8 z4V7+xQuEaZZ{l;`4vi0$onyV+s_4GD_4+q?IrHlNdQ~tLt*O}T6;^X^A@OXnzi^kPI=d!Z{*^G85SO!~BTW3TpLU^S^fpgzVqQATeJ&Yk--p|x2$JT=(} rekk3DkB%|;`h*N9(Pqa>2uf9{5cH)R8%FO}a$)q>O6)`fGMoPZ%_vl- diff --git a/Scripts/tests/test_data/Results/test/Matrices/time_iht.omx b/Scripts/tests/test_data/Results/test/Matrices/time_iht.omx index b285d41321865310234b24bc418483f666fcf3a6..8cd7de814d34a6bd6193180b65e7a18bde7d5e9a 100644 GIT binary patch delta 959 zcmZuvL1+^}6y2GPZFZB;ps1T1%oam!1(QgiL{Mo3ZQ{j9DfE`c8Zk|bb(=OxMQo{o z2$k&mrNn|-q!(`)#zXW_f*^WqdkQ_Zpr{9-c#z;lceA^u6=&I*dGG)CXa4`Q@BweW z$8s;;e5srad3Xjf3?rz&Hk|6G4UugvOjMaafdb^!eT-z<#|F`<1FAt&Xd~bY`hx0; zn2!HO$-{=l@2VKV11*g@<@HU8kT2+Qr+~M^;O@*^n6&7;8NFiQT8GZ-H)EJ6x8E;s z;EGKlKcQ~5@@*wd*gwKDcLX_saDJ}o(4|&Fx-hQU;Fs+N_g4=|`)@P=Nk<-9n5rdoROA__&!s z;EHia=2|k9(DvhTDV9zor>3PAY~kE(DP{U)rFb%(kYZVBdR!w_oS8~yO%1$=xV$E3 z>P+96c%~I57f+|)b;OSw5%?S#hI&!NUeFWDkL*pTj#rm-UWo7Ky~{dZOYh}ZKrH}T zrDtvp@hA-QISJPbZHKDRZ|`6Rj9k`-)V^?01396);Nfo?s2bC3##3gZu#xxhbB1kq zM(bzEK+Oe(WYm6E(Kk9c`5tPsg6jgl(7~;r4a$42}#QE-u!p}x#yny?!E6`7qYJ# zsi7kKT5Emi?u#H8f*>cuXI!?1ZCn)GoPp|V_pXAas#9_V?!#8&0^tlJVN@6w%`afi zT0;?Y7KZE~f?+2nq-8}X#YQq?W3p0FCS#5?91e!$#{3q&P$te3@F{`1Pvm7e5OlR1`dMP61Rar^riq6Jtp_V8)P@$!}^1g6fG2 zP2kgyw1aV7Onsu4&X4peL1dH^)ndT%|NIwAVjhYX?6i;yxdI^og~N_ z4_T(<#Hdv*Cs`hZ?qx&-Qyq}b(SV4SnM?qd)E$d(roq5AfPz4_*raTRh}C$y!f-Qa z^P-s3dufsV4hHTr35f`pzjlnNg$FSIfDRHe5H|1Dc{RhOV3)T$oQ>ISgh}AuhB$;` z1zZ?>xDQk^R+_S&XVB$2EK!z3AmW;no^Q2BfC(_L= zOM!>8J1CP9kce{QLs8BCKAI8bnNdC0h=gWDmlzPB88m6kS`{A*IM;ylVH8+{eK3@V zoK(zTWqcwW)}X+VFe<3T$qSUXa}#`{U3ylFsup94#zGCpJ_Wpq59ulLX7O8(>d;WJ z@?f;*OC{%2VBzn*yxT*LgD=$U%3JOR1ag})hLgN!ugNr}#e4jwO7yZ4Wz0@ZD(#=4 zlM@|n_Rfyt((SiJ)qc&>w>Iwz?^CUL)%Im&}W5ICZme{-9 zuHE4odTChF*~HNC_Eo_e+0@I-7KvL}%J}v1{1=BGKUaPjmNa!u($rVZs-vq!Y~`@x zacXbxvcaRCqw2&}%Z~(k9y%tB>)79AHNv0OfB)}?oD<^o_`h2>3AhJWb}+4*TwkSL zccbf^vHL#X=quHnqvR3M9&>=X9)hfj{tW zR4)x)qM>DReyTfD=`vEM?OWgFU~j+PJ3pq39+c;;P$VonXG0P*+S#XjhVq4vGc!83 zzQ|8FaDVHz%uIGT)sgJu^JCjzad#eFOHtTF0=p$>lx>9eJ%0a3|Aq%Kt(#|F#raP! zC*N`<%Ts3b;ZMJq?Le*fJ)?ZgbgOWB`0Fpp>uzSJCZkM;nOOTtfgAn#`)Qd!h&+sv l%F6C6nnsoip3$*OHth%&(AaRaZB5!9<)&s zA{tnK(qK&^@#c-mcmNNEi^e0|NKYIzdTe?yjR$p?-L=#>o1K~W-hY4g&)@w|xc(8B z#&G?Oawg>E7{o9PufE!FsgE`UOLt+S%I0YlAa5UHRHEaSAUbTa z@4s1OXj%R4vXMN{^{A7qZ}NnELofPy+zErHKXo~6)p;{}*}%0vo!7sNVWRBOIN88u zyFz|I!)D_Sov`Hi4BPApF#Kq!w2X7(L4e!7j>uW%$Oc{9dVDCoar-T z*W#&en)P^c8Qw+wxE+D7ky&Wu1Uw9SLGoO0K@I$BOXvCcQGRe+=WEGcz5?n6paMOA zcZNe@*j$%zBYPN7euaH~(zKboh@j62Jx1Zr_0bJ6G04yqU2k)mt!RXZD*Lf}mz} zWt`T6^`Ok|Bf+KuRrdGbG{8rLQKpkwVz1FSBM9UO&N*bGHl2^-M_37bh=K4Jh#~sm zFK}CVKtyat=tPZX6AYNn#n{oh8XP8ERgP0@hQLcH2MKTo;j#jx-5qpOz0Hy_*(OIk zWSx>LN3HQ9SRaHzH6nX+9njcX146AcSpYn_H^y|M!+;b@K_C*gRJ4p@^?n{O+z!rA zDVFq9EmFPO!1WUlW~lAjm&saKkA;K|5DJf$t4l$(4-}+HA0|ws|RNzDDZh~(NG?8 zvch(i;fau?Hta|RLcrRZ+S6=ldN}>jRvv<-8bHfXp1oPVI-!=5GSO>({ zlj@hf$2HAmN3?t3w(^GZtRRPkOSD64NgHG1j^9*zo#azhjw*V3gtD`8E^_8Wk!YdC z!Slv5<%9VN)$;Sf9(L?!8?Qc6Jcw*yTAWb`i9HHU7q739X^e1T+R48(F=qJ3)R{8h(Id`< zwV8?GdB0^84fl*})$7*7ZKdD?fNu3Vs zVl6qc%AU{NZ&9UOV~w`#8At*li$mn0{qn|3{x6Q{ZV!zYFWja{zbf^r0qXj%ftKv7 zIIw%}dR0SSNav0ZaozZ?-oKOGW%Ey;hbsz7BXep)=AO*bh|+6Y%O^;8JA#A0@P67f z%0>fm2@@q#Y?pQ81ON0~?W}Hm!aKc(-7%}&Pwu(JC#M{ktoy`+sM943MvY5H(W$8^ zoo@MfH`O=w{ooJVQIzodO?r^eX2DDrI?;Kj01fU~AOThb2hhoQ)*tcA!_`x{eF0VP z?~p_Kv)??c;!7Xrw?(YEF!u1$+uozQdIl?}lso%=-HdHhEB-v68IrzcT~GDnzrqCt qk%}GG-kebVJfeWm#JkDZMdv;Qb8Bx$u(4JyjNNW!TaLCS3GP4SM@|F) diff --git a/Scripts/utils/validate_loaded_network.py b/Scripts/utils/validate_loaded_network.py new file mode 100644 index 00000000..520fcb73 --- /dev/null +++ b/Scripts/utils/validate_loaded_network.py @@ -0,0 +1,15 @@ +import utils.log as log + +def validate_loaded(network, fares=None): + for line in network.transit_lines(): + if str(line.vehicle.mode) in "mr": + segments = list(line.segments()) + for seg1,seg2 in zip(segments[:-1],segments[1:]): + if seg1.data1 == 0 and (seg2.allow_boardings == 1 or seg2.allow_alightings ==1): + msg = "Segment id {} must not have zero speed if the next segment has boarding/alighting allowed".format(seg1.id) + log.error(msg) + raise ValueError(msg) + if seg1.data1 != 0 and (seg2.allow_boardings == 0 and seg2.allow_alightings ==0): + msg = "Segment id {} must not have non-zero speed if the next segment has boarding/alighting disallowed".format(seg1.id) + log.error(msg) + raise ValueError(msg) \ No newline at end of file diff --git a/Scripts/utils/validate_network.py b/Scripts/utils/validate_network.py index be059741..87aa4888 100644 --- a/Scripts/utils/validate_network.py +++ b/Scripts/utils/validate_network.py @@ -95,7 +95,7 @@ def validate(network, fares=None): log.error(msg) raise ValueError(msg) if network.mode('t') in link.modes or network.mode('p') in link.modes: - speedstr = str(int(link.data1)) + speedstr = str(int(link.data1)).zfill(6) speed = { "aht": int(speedstr[:-4]), "pt": int(speedstr[-4:-2]),