From ff8ac2e5d9063f8de4da64f833898e6ab14098b9 Mon Sep 17 00:00:00 2001 From: Jens West Date: Tue, 20 Jun 2023 11:45:36 +0300 Subject: [PATCH 1/9] Make handling of EMME matrices less error-prone and more flexible --- Scripts/assignment/assignment_period.py | 102 +++---- Scripts/assignment/datatypes/car.py | 30 ++- .../assignment/datatypes/car_specification.py | 72 ++--- Scripts/assignment/datatypes/transit.py | 62 ++--- Scripts/assignment/emme_assignment.py | 58 ++-- Scripts/assignment/mock_assignment.py | 1 - Scripts/parameters/assignment.py | 254 ++---------------- 7 files changed, 168 insertions(+), 411 deletions(-) diff --git a/Scripts/assignment/assignment_period.py b/Scripts/assignment/assignment_period.py index fc5a19a3..3aa91490 100644 --- a/Scripts/assignment/assignment_period.py +++ b/Scripts/assignment/assignment_period.py @@ -12,23 +12,20 @@ from assignment.abstract_assignment import Period +emme_matrices = {} + + class AssignmentPeriod(Period): def __init__(self, name, emme_scenario, emme_context, - demand_mtx=param.emme_demand_mtx, - result_mtx=param.emme_result_mtx, save_matrices=False, - separate_emme_scenarios=False): + save_matrices=False, separate_emme_scenarios=False): self.name = name self.emme_scenario = emme_context.modeller.emmebank.scenario( emme_scenario) self.emme_project = emme_context self._separate_emme_scenarios = separate_emme_scenarios - if save_matrices: - self.demand_mtx = copy.deepcopy(demand_mtx) - self.result_mtx = copy.deepcopy(result_mtx) - else: - # Refer to the same matrices for all time periods - self.demand_mtx = demand_mtx - self.result_mtx = result_mtx + # Refer to the same matrices for all time periods + # if not `save_matrices` + self.emme_matrices = {} if save_matrices else emme_matrices self.dist_unit_cost = param.dist_unit_cost def extra(self, attr): @@ -91,7 +88,7 @@ def assign(self, matrices, iteration): if iteration=="init": self._assign_pedestrians() self._set_bike_vdfs() - self._assign_bikes(self.result_mtx["dist"]["bike"]["id"], "all") + self._assign_bikes(self.emme_matrices["bike"]["dist"], "all") self._set_car_and_transit_vdfs() if not self._separate_emme_scenarios: self._calc_background_traffic() @@ -123,7 +120,7 @@ def assign(self, matrices, iteration): self._assign_transit() elif iteration=="last": self._set_bike_vdfs() - self._assign_bikes(self.result_mtx["dist"]["bike"]["id"], "all") + self._assign_bikes(self.emme_matrices["bike"]["dist"], "all") self._set_car_and_transit_vdfs() self._calc_background_traffic() self._assign_cars(param.stopping_criteria_fine) @@ -186,11 +183,7 @@ def calc_transit_cost(self, fares, peripheral_cost, mapping): tc = "transit_work" spec = TransitSpecification( self._segment_results[tc], self.extra("hw"), - self.demand_mtx[tc]["id"], - self.result_mtx["time"][tc]["id"], - self.result_mtx["dist"][tc]["id"], - self.result_mtx["trip_part_"+tc], - count_zone_boardings=True) + self.emme_matrices[tc], count_zone_boardings=True) is_in_transit_zone_attr = param.is_in_transit_zone_attr.replace( "ui", "data") for transit_zone in transit_zones: @@ -205,7 +198,7 @@ def calc_transit_cost(self, fares, peripheral_cost, mapping): self.emme_project.matrix_results( spec.transit_result_spec, self.emme_scenario) nr_visits = self._get_matrix( - "trip_part_transit_work", "board_cost") + tc, "actual_total_boarding_costs") # If the number of visits is less than 1, there seems to # be an easy way to avoid visiting this transit zone has_visited[transit_zone] = (nr_visits > 0.99) @@ -243,7 +236,7 @@ def calc_transit_cost(self, fares, peripheral_cost, mapping): cost[l:u, :u] = peripheral_cost cost[:u, l:u] = peripheral_cost.T # Calculate distance-based cost from inv-distance - dist = self._get_matrix("dist", "transit_work") + dist = self._get_matrix(tc, "dist") dist_cost = fares.start_fare + fares.dist_fare*dist cost[cost>=maxfare] = dist_cost[cost>=maxfare] # Reset boarding penalties @@ -403,19 +396,15 @@ def _set_emmebank_matrices(self, matrices, is_last_iteration): else: self._set_matrix(mtx, matrices[mtx]) - def _set_matrix(self, mtx_label, matrix, result_type=None): + def _set_matrix(self, ass_class, matrix, matrix_type="demand"): if numpy.isnan(matrix).any(): - msg = ("NAs in demand matrix {}. ".format(mtx_label) - + "Would cause infinite loop in Emme assignment.") + msg = ("NAs in demand matrix {} ".format(ass_class) + + "would cause infinite loop in Emme assignment.") log.error(msg) raise ValueError(msg) - elif result_type is None: - self.emme_project.modeller.emmebank.matrix( - self.demand_mtx[mtx_label]["id"]).set_numpy_data( - matrix, scenario_id=self.emme_scenario.id) else: self.emme_project.modeller.emmebank.matrix( - self.result_mtx[result_type][mtx_label]["id"]).set_numpy_data( + self.emme_matrices[ass_class][matrix_type]).set_numpy_data( matrix, scenario_id=self.emme_scenario.id) def _get_matrices(self, mtx_type, is_last_iteration=False): @@ -435,44 +424,45 @@ def _get_matrices(self, mtx_type, is_last_iteration=False): Subtype (car_work/truck/inv_time/...) : numpy 2-d matrix Matrix of the specified type """ - last_iteration_classes = param.freight_classes + ("transit_leisure",) + last_iter_classes = param.freight_classes + ("transit_leisure",) matrices = {} - for subtype in self.result_mtx[mtx_type]: - if is_last_iteration or subtype not in last_iteration_classes: - if mtx_type == "time" and subtype in param.assignment_modes: - mtx = self._extract_timecost_from_gcost(subtype) - elif mtx_type == "time" and subtype in param.transit_classes: - mtx = self._damp_travel_time(subtype) + for ass_class, mtx_types in self.emme_matrices.items(): + if (mtx_type in mtx_types and + (is_last_iteration or ass_class not in last_iter_classes)): + if mtx_type == "time" and ass_class in param.assignment_modes: + mtx = self._extract_timecost_from_gcost(ass_class) + elif mtx_type == "time" and ass_class in param.transit_classes: + mtx = self._damp_travel_time(ass_class) else: - mtx = self._get_matrix(mtx_type, subtype) - matrices[subtype] = mtx + mtx = self._get_matrix(ass_class, mtx_type) + matrices[ass_class] = mtx if not is_last_iteration: matrices["transit_leisure"] = matrices["transit_work"] return matrices - def _get_matrix(self, assignment_result_type, subtype): + def _get_matrix(self, ass_class, matrix_type): """Get matrix with type pair (e.g., demand, car_work). Parameters ---------- - assignment_result_type : str - Type (demand/time/transit/...) - subtype : str - Subtype (car_work/truck/inv_time/...) + ass_class : str + Assignment class (car_work/transit_leisure/truck/...) + matrix_type : str + Type (demand/time/cost/...) Return ------ numpy 2-d matrix Matrix of the specified type """ - emme_id = self.result_mtx[assignment_result_type][subtype]["id"] + emme_id = self.emme_matrices[ass_class][matrix_type] return (self.emme_project.modeller.emmebank.matrix(emme_id) .get_numpy_data(scenario_id=self.emme_scenario.id)) def _damp_travel_time(self, demand_type): """Reduce the impact from first waiting time on total travel time.""" - travel_time = self._get_matrix("time", demand_type) - fw_time = self._get_matrix("trip_part_"+demand_type, "fw_time") + travel_time = self._get_matrix(demand_type, "time") + fw_time = self._get_matrix(demand_type, "actual_first_waiting_times") wt_weight = param.waiting_time_perception_factor return travel_time + wt_weight*((5./3.*fw_time)**0.8 - fw_time) @@ -483,9 +473,9 @@ def _extract_timecost_from_gcost(self, ass_class): To get travel time, monetary cost is removed from generalized cost. """ vot_inv = param.vot_inv[param.vot_classes[ass_class]] - gcost = self._get_matrix("gen_cost", ass_class) - cost = self._get_matrix("cost", ass_class) - dist = self._get_matrix("dist", ass_class) + gcost = self._get_matrix(ass_class, "gen_cost") + cost = self._get_matrix(ass_class, "cost") + dist = self._get_matrix(ass_class, "dist") if ass_class in ("trailer_truck", "truck"): # toll costs are not applied to freight time = gcost - vot_inv*param.freight_dist_unit_cost[ass_class]*dist @@ -552,24 +542,20 @@ def _calc_boarding_penalties(self, extra_penalty=0, is_last_iteration=False): self.emme_scenario.publish_network(network) def _specify(self): - self._car_spec = CarSpecification( - self.extra, self.demand_mtx, self.result_mtx) + self._car_spec = CarSpecification(self.extra, self.emme_matrices) self._transit_specs = {tc: TransitSpecification( self._segment_results[tc], self.extra("hw"), - self.demand_mtx[tc]["id"], - self.result_mtx["time"][tc]["id"], - self.result_mtx["dist"][tc]["id"], - self.result_mtx["trip_part_"+tc]) + self.emme_matrices[tc]) for tc in param.transit_classes} self.bike_spec = { "type": "STANDARD_TRAFFIC_ASSIGNMENT", "classes": [ { "mode": param.main_mode, - "demand": self.demand_mtx["bike"]["id"], + "demand": self.emme_matrices["bike"]["demand"], "results": { "od_travel_times": { - "shortest_paths": self.result_mtx["time"]["bike"]["id"], + "shortest_paths": self.emme_matrices["bike"]["time"], }, "link_volumes": None, # This is defined later }, @@ -592,7 +578,7 @@ def _specify(self): self.walk_spec = { "type": "STANDARD_TRANSIT_ASSIGNMENT", "modes": param.aux_modes, - "demand": self.demand_mtx["bike"]["id"], + "demand": self.emme_matrices["bike"]["demand"], "waiting_time": { "headway_fraction": 0.01, "effective_headways": "hdw", @@ -606,7 +592,7 @@ def _specify(self): "perception_factor": 1, }, "od_results": { - "transit_times": self.result_mtx["time"]["walk"]["id"], + "transit_times": self.emme_matrices["walk"]["time"], }, "strategy_analysis": { "sub_path_combination_operator": "+", @@ -622,7 +608,7 @@ def _specify(self): }, }, "results": { - "od_values": self.result_mtx["dist"]["walk"]["id"], + "od_values": self.emme_matrices["walk"]["dist"], }, }, } diff --git a/Scripts/assignment/datatypes/car.py b/Scripts/assignment/datatypes/car.py index 436ece27..78aa4691 100644 --- a/Scripts/assignment/datatypes/car.py +++ b/Scripts/assignment/datatypes/car.py @@ -3,14 +3,32 @@ class Car: - def __init__(self, ass_class, extra, demand_mtx, result_mtx, + """Car assignment class definition. + + Parameters + ---------- + ass_class : str + Assignment class (car_work/car_leisure/van/truck/trailer_truck) + extra : assignment_period.AssignmentPeriod.extra() + Function for generating extra attribute name + for specific assignment period + emme_matrices : dict + key : str + Impedance type (time/cost/dist/...) + value : str + Emme matrix id + link_costs : str + Link attribute where link cost is found + value_of_time_inv : float (optional) + Inversed value of time [min/eur], default is param.vot_inv + """ + def __init__(self, ass_class, extra, emme_matrices, link_costs, value_of_time_inv=None): - od_travel_times = result_mtx["gen_cost"][ass_class]["id"] if value_of_time_inv is None: value_of_time_inv = param.vot_inv[param.vot_classes[ass_class]] self.spec = { "mode": param.assignment_modes[ass_class], - "demand": demand_mtx[ass_class]["id"], + "demand": emme_matrices["demand"], "generalized_cost": { "link_costs": link_costs, "perception_factor": value_of_time_inv, @@ -18,14 +36,14 @@ def __init__(self, ass_class, extra, demand_mtx, result_mtx, "results": { "link_volumes": extra(ass_class), "od_travel_times": { - "shortest_paths": od_travel_times + "shortest_paths": emme_matrices["gen_cost"] } }, "path_analyses": [] } - self.add_analysis("length", result_mtx["dist"][ass_class]["id"]) + self.add_analysis("length", emme_matrices["dist"]) if ass_class not in ("trailer_truck", "truck"): - self.add_analysis(extra("toll_cost"), result_mtx["cost"][ass_class]["id"]) + self.add_analysis(extra("toll_cost"), emme_matrices["cost"]) def add_analysis (self, link_component, od_values): analysis = PathAnalysis(link_component, od_values) diff --git a/Scripts/assignment/datatypes/car_specification.py b/Scripts/assignment/datatypes/car_specification.py index df0d4bfe..c3708d35 100644 --- a/Scripts/assignment/datatypes/car_specification.py +++ b/Scripts/assignment/datatypes/car_specification.py @@ -7,44 +7,30 @@ class CarSpecification: Parameters ---------- - demand_mtx : dict + extra : assignment_period.AssignmentPeriod.extra() + Function for generating extra attribute name + for specific assignment period + emme_matrices : dict key : str - Assignment class (transit_work/transit_leisure) - value : dict - id : str - Emme matrix id - description : dict - Matrix description - result_mtx : dict - key : str - Impedance type (time/cost/dist) + Assignment class (car_work/transit_leisure/...) value : dict key : str - Assignment class (transit_work/transit_leisure) - value : dict - id : str - Emme matrix id - description : dict - Matrix description + Impedance type (time/cost/dist/...) + value : str + Emme matrix id """ - def __init__(self, extra, demand_mtx, result_mtx): - self.car_work = Car( - "car_work", extra, demand_mtx, result_mtx, - link_costs=extra("total_cost")) - self.car_leisure = Car( - "car_leisure", extra, demand_mtx, result_mtx, - link_costs=extra("total_cost")) - self.van = Car( - "van", extra, demand_mtx, result_mtx, - link_costs=extra("total_cost")) - self.truck = Car( - "truck", extra, demand_mtx, result_mtx, - value_of_time_inv=param.freight_dist_unit_time, - link_costs="length") - self.trailer_truck = Car( - "trailer_truck", extra, demand_mtx, result_mtx, - value_of_time_inv=param.freight_dist_unit_time, - link_costs="length") + def __init__(self, extra, emme_matrices): + self._modes = {} + self._freight_modes = list(param.freight_dist_unit_cost) + for mode in param.assignment_modes: + if mode in self._freight_modes: + kwargs = { + "link_costs": "length", + "value_of_time_inv": param.freight_dist_unit_time, + } + else: + kwargs = {"link_costs": extra("total_cost")} + self._modes[mode] = Car(mode, extra, emme_matrices[mode], **kwargs) self._spec = { "type": "SOLA_TRAFFIC_ASSIGNMENT", "background_traffic": { @@ -55,19 +41,7 @@ def __init__(self, extra, demand_mtx, result_mtx): "stopping_criteria": None, # This is defined later } - def spec (self, lightweight=False): - if lightweight: - self._spec["classes"] = [ - self.car_work.spec, - self.car_leisure.spec, - self.van.spec, - ] - else: - self._spec["classes"] = [ - self.car_work.spec, - self.car_leisure.spec, - self.trailer_truck.spec, - self.truck.spec, - self.van.spec, - ] + def spec(self, lightweight=False): + self._spec["classes"] = [self._modes[mode].spec for mode in self._modes + if not lightweight or mode not in self._freight_modes] return self._spec diff --git a/Scripts/assignment/datatypes/transit.py b/Scripts/assignment/datatypes/transit.py index e7c927e0..52767557 100644 --- a/Scripts/assignment/datatypes/transit.py +++ b/Scripts/assignment/datatypes/transit.py @@ -21,26 +21,16 @@ class TransitSpecification: Extra attribute name (@transit_work_vol_aht/...) headway_attribute : str Line attribute where headway is stored - demand_mtx_id : str - Emme matrix id for demand matrix - time_mtx_id : str - Emme matrix id for time matrix - dist_mtx_id : str - Emme matrix id for distance matrix - trip_part : dict + emme_matrices : dict key : str - Impedance type (inv_time/aux_time/num_board/...) - value : dict - id : str - Emme matrix id - description : dict - Matrix description + Impedance type (time/cost/dist/...) + value : str + Emme matrix id count_zone_boardings : bool (optional) Whether assignment is performed only to count fare zone boardings """ def __init__(self, segment_results, headway_attribute, - demand_mtx_id, time_mtx_id, dist_mtx_id, trip_part, - count_zone_boardings=False): + emme_matrices, count_zone_boardings=False): no_penalty = dict.fromkeys(["at_nodes", "on_lines", "on_segments"]) no_penalty["global"] = { "penalty": 0, @@ -49,7 +39,7 @@ def __init__(self, segment_results, headway_attribute, self.transit_spec = { "type": "EXTENDED_TRANSIT_ASSIGNMENT", "modes": param.transit_assignment_modes, - "demand": demand_mtx_id, + "demand": emme_matrices["demand"], "waiting_time": { "headway_fraction": param.standard_headway_fraction, "effective_headways": headway_attribute, @@ -88,38 +78,26 @@ def __init__(self, segment_results, headway_attribute, "type": "EXTENDED_TRANSIT_NETWORK_RESULTS", "on_segments": segment_results, } + subset = "by_mode_subset" + self.transit_result_spec = { + "type": "EXTENDED_TRANSIT_MATRIX_RESULTS", + subset: { + "modes": param.transit_modes, + "distance": emme_matrices["dist"], + }, + } if count_zone_boardings: jlevel1 = JourneyLevel( headway_attribute, boarded=False, count_zone_boardings=True) jlevel2 = JourneyLevel( headway_attribute, boarded=True, count_zone_boardings=True) - mtx_results_spec = { - "type": "EXTENDED_TRANSIT_MATRIX_RESULTS", - "by_mode_subset": { - "modes": param.transit_modes, - "distance": dist_mtx_id, - "actual_total_boarding_costs": trip_part["board_cost"]["id"], - }, - } + bcost = "actual_total_boarding_costs" + self.transit_result_spec[subset][bcost] = emme_matrices[bcost] else: jlevel1 = JourneyLevel(headway_attribute, boarded=False) jlevel2 = JourneyLevel(headway_attribute, boarded=True) - mtx_results_spec = { - "type": "EXTENDED_TRANSIT_MATRIX_RESULTS", - "total_impedance": time_mtx_id, - "total_travel_time": trip_part["total_time"]["id"], - "actual_first_waiting_times": trip_part["fw_time"]["id"], - "actual_total_waiting_times": trip_part["tw_time"]["id"], - "by_mode_subset": { - "modes": param.transit_assignment_modes, - "distance": dist_mtx_id, - "avg_boardings": trip_part["num_board"]["id"], - "actual_total_boarding_times": trip_part["board_time"]["id"], - "actual_in_vehicle_times": trip_part["inv_time"]["id"], - "actual_aux_transit_times": trip_part["aux_time"]["id"], - }, - } - + for trip_part, matrix_id in emme_matrices["total"].items(): + self.transit_result_spec[trip_part] = matrix_id + for trip_part, matrix_id in emme_matrices[subset].items(): + self.transit_result_spec[subset][trip_part] = matrix_id self.transit_spec["journey_levels"] = [jlevel1.spec, jlevel2.spec] - self.transit_result_spec = mtx_results_spec - diff --git a/Scripts/assignment/emme_assignment.py b/Scripts/assignment/emme_assignment.py index c6add812..8405ecbc 100644 --- a/Scripts/assignment/emme_assignment.py +++ b/Scripts/assignment/emme_assignment.py @@ -76,28 +76,37 @@ def prepare_network(self, car_dist_unit_cost=None): tp, scen_id, self.emme_project, save_matrices=self.save_matrices, separate_emme_scenarios=self.separate_emme_scenarios)) + mtx_types = tuple({mtx_type for ass_class + in param.emme_matrices.values() for mtx_type in ass_class}) + id_ten = {result_type: 10*i for i, result_type + in enumerate(mtx_types + param.transit_classes)} for i, ap in enumerate(self.assignment_periods): tag = ap.name if self.save_matrices else "" id_hundred = 100*i + self.first_matrix_id - for ass_class in ap.demand_mtx: - mtx = ap.demand_mtx[ass_class] - mtx["id"] = "mf{}".format(id_hundred + mtx["id"]) - self.emme_project.create_matrix( - matrix_id=mtx["id"], - matrix_name="demand_{}_{}".format(ass_class, tag), - matrix_description="{} {}".format(mtx["description"], tag), - default_value=0, overwrite=True) - for mtx_type in ap.result_mtx: - mtx = ap.result_mtx[mtx_type] - for ass_class in mtx: - mtx[ass_class]["id"] = "mf{}".format( - id_hundred + mtx[ass_class]["id"]) + for j, ass_class in enumerate(param.emme_matrices, start=1): + matrix_ids = {} + for mtx_type in param.emme_matrices[ass_class]: + matrix_ids[mtx_type] = "mf{}".format( + id_hundred + id_ten[mtx_type] + j) + description = f"{mtx_type}_{ass_class}_{tag}" + default_value = 0 if mtx_type == "demand" else 999999 self.emme_project.create_matrix( - matrix_id=mtx[ass_class]["id"], - matrix_name="{}_{}_{}".format(mtx_type, ass_class, tag), - matrix_description="{} {}".format( - mtx[ass_class]["description"], tag), - default_value=999999, overwrite=True) + matrix_id=matrix_ids[mtx_type], + matrix_name=description, matrix_description=description, + default_value=default_value, overwrite=True) + if ass_class in param.transit_classes: + for subset, parts in param.transit_impedance_matrices.items(): + matrix_ids[subset] = {} + for mtx_type, longer_name in parts.items(): + id = f"mf{id_hundred + id_ten[ass_class] + j}" + matrix_ids[subset][longer_name] = id + matrix_ids[longer_name] = id + description = f"{mtx_type}_{ass_class}_{tag}" + self.emme_project.create_matrix( + matrix_id=id, matrix_name=description, + matrix_description=description, + default_value=999999, overwrite=True) + ap.emme_matrices[ass_class] = matrix_ids if not self.save_matrices: break self._create_attributes(self.day_scenario, self._extra) @@ -159,7 +168,8 @@ def aggregate_results(self, resultdata): if res != "transit_volumes": self._node_24h( transit_class, param.segment_results[res]) - ass_classes = list(param.emme_demand_mtx) + ["bus", "aux_transit"] + ass_classes = list(param.emme_matrices) + ["bus", "aux_transit"] + ass_classes.remove("walk") for ass_class in ass_classes: self._link_24h(ass_class) @@ -279,16 +289,16 @@ def calc_transit_cost(self, fares, peripheral_cost, default_cost=None): cost = default_cost for ap in self.assignment_periods: for transit_class in param.transit_classes: - idx = ap.result_mtx["cost"][transit_class]["id"] + idx = ap.emme_matrices[transit_class]["cost"] emmebank.matrix(idx).set_numpy_data(cost, ap.emme_scenario.id) if not self.save_matrices: break def _copy_matrix(self, mtx_type, ass_class, ass_period_1, ass_period_2): - from_mtx = ass_period_1.result_mtx[mtx_type][ass_class] - to_mtx = ass_period_2.result_mtx[mtx_type][ass_class] + from_mtx = ass_period_1.emme_matrices[ass_class][mtx_type] + to_mtx = ass_period_2.emme_matrices[ass_class][mtx_type] self.emme_project.copy_matrix( - from_mtx["id"], to_mtx["id"], + from_mtx, to_mtx, "{}_{}_{}".format(mtx_type, ass_class, ass_period_2.name), "{} {}".format(to_mtx["description"], ass_period_2.name)) @@ -345,7 +355,7 @@ def _create_attributes(self, scenario, extra): (e.g., self._extra) """ # Create link attributes - for ass_class in list(param.emme_demand_mtx) + ["bus"]: + for ass_class in list(param.emme_matrices) + ["bus"]: self.emme_project.create_extra_attribute( "LINK", extra(ass_class), ass_class + " volume", overwrite=True, scenario=scenario) diff --git a/Scripts/assignment/mock_assignment.py b/Scripts/assignment/mock_assignment.py index 1c23c421..a1dbac5c 100644 --- a/Scripts/assignment/mock_assignment.py +++ b/Scripts/assignment/mock_assignment.py @@ -11,7 +11,6 @@ class MockAssignmentModel(AssignmentModel): def __init__(self, matrices, time_periods=param.time_periods): self.matrices = matrices log.info("Reading matrices from " + str(self.matrices.path)) - self.result_mtx=param.emme_result_mtx self.time_periods = time_periods self.assignment_periods = [MockPeriod(tp, matrices) for tp in time_periods] diff --git a/Scripts/parameters/assignment.py b/Scripts/parameters/assignment.py index e91d094c..d4610c65 100644 --- a/Scripts/parameters/assignment.py +++ b/Scripts/parameters/assignment.py @@ -450,237 +450,29 @@ # Hard-coded in Emme congested transit assignment congestion_cost = "ccost" uncongested_transit_time = "base_timtr" -# Emme matrix IDs -emme_demand_mtx = { - "car_work": { - "id": 1, - "description": "car work demand", - }, - "car_leisure": { - "id": 2, - "description": "car leisure demand", - }, - "transit_work": { - "id": 3, - "description": "transit demand", - }, - "transit_leisure": { - "id": 4, - "description": "transit demand", - }, - "bike": { - "id": 5, - "description": "bicyclist demand", - }, - "trailer_truck": { - "id": 7, - "description": "trailer truck demand", - }, - "truck": { - "id": 8, - "description": "truck demand", - }, - "van": { - "id": 9, - "description": "van demand", - }, -} -emme_result_mtx = { - "time": { - "car_work": { - "id": 11, - "description": "car work travel time", - }, - "car_leisure": { - "id": 12, - "description": "car leisure travel time", - }, - "transit_work": { - "id": 13, - "description": "transit travel time", - }, - "transit_leisure": { - "id": 14, - "description": "transit travel time", - }, - "bike": { - "id": 15, - "description": "bike travel time", - }, - "walk": { - "id": 16, - "description": "walk travel time", - }, - "trailer_truck": { - "id": 17, - "description": "trailer truck time", - }, - "truck": { - "id": 18, - "description": "truck time", - }, - "van": { - "id": 19, - "description": "van time", - }, - }, - "dist": { - "car_work": { - "id": 21, - "description": "car work travel distance", - }, - "car_leisure": { - "id": 22, - "description": "car leisure travel distance", - }, - "transit_work": { - "id": 23, - "description": "transit in-vehicle distance", - }, - "transit_leisure": { - "id": 24, - "description": "transit in-vehicle distance", - }, - "bike": { - "id": 25, - "description": "bike travel distance", - }, - "walk": { - "id": 26, - "description": "walk travel distance", - }, - "trailer_truck": { - "id": 27, - "description": "trailer truck distance", - }, - "truck": { - "id": 28, - "description": "truck distance", - }, - "van": { - "id": 29, - "description": "van distance", - }, - }, - "cost": { - "car_work": { - "id": 31, - "description": "car work travel cost", - }, - "car_leisure": { - "id": 32, - "description": "car leisure travel cost", - }, - "transit_work": { - "id": 33, - "description": "transit travel cost", - }, - "transit_leisure": { - "id": 34, - "description": "transit travel cost", - }, - "trailer_truck": { - "id": 37, - "description": "trailer truck cost", - }, - "truck": { - "id": 38, - "description": "truck cost", - }, - "van": { - "id": 39, - "description": "van cost", - }, - }, - "gen_cost": { - "car_work": { - "id": 41, - "description": "car work travel generalized cost", - }, - "car_leisure": { - "id": 42, - "description": "car leisure travel generalized cost", - }, - "trailer_truck": { - "id": 47, - "description": "trailer truck travel generalized cost", - }, - "truck": { - "id": 48, - "description": "truck travel generalized cost", - }, - "van": { - "id": 49, - "description": "van travel generalized cost", - }, - }, - "trip_part_transit_work":{ - "inv_time": { - "id": 51, - "description": "transit in-vehicle time", - }, - "aux_time": { - "id": 52, - "description": "transit auxilliary time", - }, - "tw_time": { - "id": 53, - "description": "transit total waiting time", - }, - "fw_time": { - "id": 54, - "description": "transit first waiting time", - }, - "board_time": { - "id": 55, - "description": "transit boarding time", - }, - "total_time": { - "id": 56, - "description": "transit unweighted travel time", - }, - "num_board": { - "id": 57, - "description": "transit trip number of boardings", - }, - "board_cost": { - "id": 58, - "description": "transit boarding cost", - }, - }, - "trip_part_transit_leisure":{ - "inv_time": { - "id": 61, - "description": "transit in-vehicle time", - }, - "aux_time": { - "id": 62, - "description": "transit auxilliary time", - }, - "tw_time": { - "id": 63, - "description": "transit total waiting time", - }, - "fw_time": { - "id": 64, - "description": "transit first waiting time", - }, - "board_time": { - "id": 65, - "description": "transit boarding time", - }, - "total_time": { - "id": 66, - "description": "transit unweighted travel time", - }, - "num_board": { - "id": 67, - "description": "transit trip number of boardings", - }, - "board_cost": { - "id": 68, - "description": "transit boarding cost", - }, +emme_matrices = { + "car_work": ("demand", "time", "dist", "cost", "gen_cost"), + "car_leisure": ("demand", "time", "dist", "cost", "gen_cost"), + "transit_work": ("demand", "time", "dist", "cost"), + "transit_leisure": ("demand", "time", "dist", "cost"), + "bike": ("demand", "time", "dist"), + "walk": ("time", "dist"), + "trailer_truck": ("demand", "time", "dist", "cost", "gen_cost"), + "truck": ("demand", "time", "dist", "cost", "gen_cost"), + "van": ("demand", "time", "dist", "cost", "gen_cost"), +} +transit_impedance_matrices = { + "total": { + "total_time": "total_travel_time", + "fw_time": "actual_first_waiting_times", + "tw_time": "actual_total_waiting_times", + }, + "by_mode_subset": { + "num_board": "avg_boardings", + "board_time": "actual_total_boarding_times", + "board_cost": "actual_total_boarding_costs", + "inv_time": "actual_in_vehicle_times", + "aux_time": "actual_aux_transit_times", }, } background_traffic_attr = "ul3" From 312ab097672f9a13ff28a8db7aae58788918bb4d Mon Sep 17 00:00:00 2001 From: Jens West Date: Tue, 20 Jun 2023 16:54:43 +0300 Subject: [PATCH 2/9] Refactor matrix creation Also add docstrings and remove deprecated imports --- Scripts/assignment/assignment_period.py | 38 +++++++--- Scripts/assignment/datatypes/transit.py | 1 - Scripts/assignment/emme_assignment.py | 95 +++++++++++++++---------- 3 files changed, 88 insertions(+), 46 deletions(-) diff --git a/Scripts/assignment/assignment_period.py b/Scripts/assignment/assignment_period.py index 3aa91490..91b92730 100644 --- a/Scripts/assignment/assignment_period.py +++ b/Scripts/assignment/assignment_period.py @@ -1,7 +1,5 @@ -import os import numpy import pandas -import copy import utils.log as log import parameters.assignment as param @@ -12,20 +10,42 @@ from assignment.abstract_assignment import Period -emme_matrices = {} - - class AssignmentPeriod(Period): + """ + EMME assignment period definition. + + This typically represents an hour of the day, which may or may not + have a dedicated EMME scenario. In case it does not have its own + EMME scenario, assignment results are stored only in extra attributes. + + Parameters + ---------- + name : str + Time period name (aht/pt/iht) + emme_scenario : int + EMME scenario linked to the time period + emme_context : assignment.emme_bindings.emme_project.EmmeProject + Emme project to connect to this assignment + emme_matrices : dict + key : str + Assignment class (car_work/transit_leisure/...) + value : dict + key : str + Matrix type (demand/time/cost/dist/...) + value : str + EMME matrix id + separate_emme_scenarios : bool (optional) + Whether separate scenarios have been created in EMME + for storing time-period specific network results. + """ def __init__(self, name, emme_scenario, emme_context, - save_matrices=False, separate_emme_scenarios=False): + emme_matrices, separate_emme_scenarios=False): self.name = name self.emme_scenario = emme_context.modeller.emmebank.scenario( emme_scenario) self.emme_project = emme_context self._separate_emme_scenarios = separate_emme_scenarios - # Refer to the same matrices for all time periods - # if not `save_matrices` - self.emme_matrices = {} if save_matrices else emme_matrices + self.emme_matrices = emme_matrices self.dist_unit_cost = param.dist_unit_cost def extra(self, attr): diff --git a/Scripts/assignment/datatypes/transit.py b/Scripts/assignment/datatypes/transit.py index 52767557..9a331c73 100644 --- a/Scripts/assignment/datatypes/transit.py +++ b/Scripts/assignment/datatypes/transit.py @@ -1,5 +1,4 @@ import parameters.assignment as param -from assignment.datatypes.path_analysis import PathAnalysis from assignment.datatypes.journey_level import JourneyLevel diff --git a/Scripts/assignment/emme_assignment.py b/Scripts/assignment/emme_assignment.py index 8405ecbc..688b1227 100644 --- a/Scripts/assignment/emme_assignment.py +++ b/Scripts/assignment/emme_assignment.py @@ -1,4 +1,3 @@ -import numpy import pandas from math import log10 @@ -62,6 +61,10 @@ def prepare_network(self, car_dist_unit_cost=None): overwrite=True, copy_paths=False, copy_strategies=False) else: self.day_scenario = self.mod_scenario + matrix_types = tuple({mtx_type for ass_class + in param.emme_matrices.values() for mtx_type in ass_class}) + id_ten = {result_type: 10*i for i, result_type + in enumerate(matrix_types + param.transit_classes)} self.assignment_periods = [] for i, tp in enumerate(self.time_periods): if self.separate_emme_scenarios: @@ -72,43 +75,12 @@ def prepare_network(self, car_dist_unit_cost=None): overwrite=True, copy_paths=False, copy_strategies=False) else: scen_id = self.mod_scenario.number + if i == 0 or self.save_matrices: + emme_matrices = self._create_matrices( + tp, 100*i + self.first_matrix_id, id_ten) self.assignment_periods.append(AssignmentPeriod( - tp, scen_id, self.emme_project, - save_matrices=self.save_matrices, + tp, scen_id, self.emme_project, emme_matrices, separate_emme_scenarios=self.separate_emme_scenarios)) - mtx_types = tuple({mtx_type for ass_class - in param.emme_matrices.values() for mtx_type in ass_class}) - id_ten = {result_type: 10*i for i, result_type - in enumerate(mtx_types + param.transit_classes)} - for i, ap in enumerate(self.assignment_periods): - tag = ap.name if self.save_matrices else "" - id_hundred = 100*i + self.first_matrix_id - for j, ass_class in enumerate(param.emme_matrices, start=1): - matrix_ids = {} - for mtx_type in param.emme_matrices[ass_class]: - matrix_ids[mtx_type] = "mf{}".format( - id_hundred + id_ten[mtx_type] + j) - description = f"{mtx_type}_{ass_class}_{tag}" - default_value = 0 if mtx_type == "demand" else 999999 - self.emme_project.create_matrix( - matrix_id=matrix_ids[mtx_type], - matrix_name=description, matrix_description=description, - default_value=default_value, overwrite=True) - if ass_class in param.transit_classes: - for subset, parts in param.transit_impedance_matrices.items(): - matrix_ids[subset] = {} - for mtx_type, longer_name in parts.items(): - id = f"mf{id_hundred + id_ten[ass_class] + j}" - matrix_ids[subset][longer_name] = id - matrix_ids[longer_name] = id - description = f"{mtx_type}_{ass_class}_{tag}" - self.emme_project.create_matrix( - matrix_id=id, matrix_name=description, - matrix_description=description, - default_value=999999, overwrite=True) - ap.emme_matrices[ass_class] = matrix_ids - if not self.save_matrices: - break self._create_attributes(self.day_scenario, self._extra) for ap in self.assignment_periods: if car_dist_unit_cost is not None: @@ -343,6 +315,57 @@ def _add_bus_stops(self): segment.allow_boardings = is_stop self.mod_scenario.publish_network(network) + def _create_matrices(self, time_period, id_hundred, id_ten): + """Create EMME matrices for storing demand and impedance. + + Parameters + ---------- + time_period : str + Time period name (aht, pt, iht) + id_hundred : int + A new hundred in the matrix id space marks new assignment period + id_ten : int + A new ten in the matrix id space marks new type of matrix + + Returns + ------- + dict + key : str + Assignment class (car_work/transit_leisure/...) + value : dict + key : str + Matrix type (demand/time/cost/dist/...) + value : str + EMME matrix id + """ + tag = time_period if self.save_matrices else "" + emme_matrices = {} + for j, ass_class in enumerate(param.emme_matrices, start=1): + matrix_ids = {} + for mtx_type in param.emme_matrices[ass_class]: + matrix_ids[mtx_type] = "mf{}".format( + id_hundred + id_ten[mtx_type] + j) + description = f"{mtx_type}_{ass_class}_{tag}" + default_value = 0 if mtx_type == "demand" else 999999 + self.emme_project.create_matrix( + matrix_id=matrix_ids[mtx_type], + matrix_name=description, matrix_description=description, + default_value=default_value, overwrite=True) + if ass_class in param.transit_classes: + for subset, parts in param.transit_impedance_matrices.items(): + matrix_ids[subset] = {} + for mtx_type, longer_name in parts.items(): + id = f"mf{id_hundred + id_ten[ass_class] + j}" + matrix_ids[subset][longer_name] = id + matrix_ids[longer_name] = id + description = f"{mtx_type}_{ass_class}_{tag}" + self.emme_project.create_matrix( + matrix_id=id, matrix_name=description, + matrix_description=description, + default_value=999999, overwrite=True) + emme_matrices[ass_class] = matrix_ids + return emme_matrices + def _create_attributes(self, scenario, extra): """Create extra attributes needed in assignment. From d8fc46be2dbf9dfdfefca6dabed3e37ce8f89336 Mon Sep 17 00:00:00 2001 From: Jens West Date: Wed, 21 Jun 2023 16:59:52 +0300 Subject: [PATCH 3/9] Fix transit trip part matrix ids and expand matrix id space when needed --- Scripts/assignment/emme_assignment.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/Scripts/assignment/emme_assignment.py b/Scripts/assignment/emme_assignment.py index 688b1227..3932b93c 100644 --- a/Scripts/assignment/emme_assignment.py +++ b/Scripts/assignment/emme_assignment.py @@ -61,10 +61,12 @@ def prepare_network(self, car_dist_unit_cost=None): overwrite=True, copy_paths=False, copy_strategies=False) else: self.day_scenario = self.mod_scenario - matrix_types = tuple({mtx_type for ass_class + matrix_types = tuple({mtx_type: None for ass_class in param.emme_matrices.values() for mtx_type in ass_class}) - id_ten = {result_type: 10*i for i, result_type + ten = max(10, len(param.emme_matrices)) + id_ten = {result_type: i*ten for i, result_type in enumerate(matrix_types + param.transit_classes)} + hundred = max(100, ten*len(matrix_types + param.transit_classes)) self.assignment_periods = [] for i, tp in enumerate(self.time_periods): if self.separate_emme_scenarios: @@ -77,7 +79,7 @@ def prepare_network(self, car_dist_unit_cost=None): scen_id = self.mod_scenario.number if i == 0 or self.save_matrices: emme_matrices = self._create_matrices( - tp, 100*i + self.first_matrix_id, id_ten) + tp, i*hundred + self.first_matrix_id, id_ten) self.assignment_periods.append(AssignmentPeriod( tp, scen_id, self.emme_project, emme_matrices, separate_emme_scenarios=self.separate_emme_scenarios)) @@ -324,8 +326,11 @@ def _create_matrices(self, time_period, id_hundred, id_ten): Time period name (aht, pt, iht) id_hundred : int A new hundred in the matrix id space marks new assignment period - id_ten : int - A new ten in the matrix id space marks new type of matrix + id_ten : dict + key : str + Matrix type (demand/time/cost/dist/...) + value : int + A new ten in the matrix id space marks new type of matrix Returns ------- @@ -340,11 +345,11 @@ def _create_matrices(self, time_period, id_hundred, id_ten): """ tag = time_period if self.save_matrices else "" emme_matrices = {} - for j, ass_class in enumerate(param.emme_matrices, start=1): + for i, ass_class in enumerate(param.emme_matrices, start=1): matrix_ids = {} for mtx_type in param.emme_matrices[ass_class]: matrix_ids[mtx_type] = "mf{}".format( - id_hundred + id_ten[mtx_type] + j) + id_hundred + id_ten[mtx_type] + i) description = f"{mtx_type}_{ass_class}_{tag}" default_value = 0 if mtx_type == "demand" else 999999 self.emme_project.create_matrix( @@ -352,9 +357,11 @@ def _create_matrices(self, time_period, id_hundred, id_ten): matrix_name=description, matrix_description=description, default_value=default_value, overwrite=True) if ass_class in param.transit_classes: + j = 0 for subset, parts in param.transit_impedance_matrices.items(): matrix_ids[subset] = {} for mtx_type, longer_name in parts.items(): + j += 1 id = f"mf{id_hundred + id_ten[ass_class] + j}" matrix_ids[subset][longer_name] = id matrix_ids[longer_name] = id From 7c527f06e25b9990dcd2bf05c96528f69408bd47 Mon Sep 17 00:00:00 2001 From: Jens West Date: Mon, 26 Jun 2023 09:22:26 +0300 Subject: [PATCH 4/9] Add matrix name and description length check --- .../assignment/emme_bindings/mock_project.py | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/Scripts/assignment/emme_bindings/mock_project.py b/Scripts/assignment/emme_bindings/mock_project.py index 181cc573..aaae5f17 100644 --- a/Scripts/assignment/emme_bindings/mock_project.py +++ b/Scripts/assignment/emme_bindings/mock_project.py @@ -60,11 +60,14 @@ def import_scenario(self, scenario_dir, scenario_id, scenario_title): def create_matrix(self, matrix_id, matrix_name, matrix_description, default_value=0, overwrite=False): try: - self.modeller.emmebank.create_matrix(matrix_id, default_value) + mtx = self.modeller.emmebank.create_matrix( + matrix_id, default_value) except ExistenceError: if overwrite: - self.modeller.emmebank.matrix(matrix_id).set_numpy_data( - default_value) + mtx = self.modeller.emmebank.matrix(matrix_id) + mtx.set_numpy_data(default_value) + mtx.name = matrix_name + mtx.description = matrix_description def create_extra_attribute(self, extra_attribute_type, extra_attribute_name, @@ -464,6 +467,32 @@ class Matrix: def __init__(self, idx, dim, default_value): self.id = idx self._data = numpy.full((dim, dim), default_value, dtype=float) + self._name = "" + self._description = "" + + @property + def name(self): + return self._name + + @name.setter + def name(self, matrix_name): + if len(matrix_name) > 40: + raise ArgumentError( + "matrix_name: expected a string with maximum length 40") + else: + self._name = matrix_name + + @property + def description(self): + return self._description + + @description.setter + def description(self, matrix_description): + if len(matrix_description) > 80: + raise ArgumentError( + "matrix_description: expected a string with maximum length 80") + else: + self._description = matrix_description def get_numpy_data(self, scenario_id=None): return self._data From c90a919e8aaf99bbe34a9ed7cb85ffaf7489e29b Mon Sep 17 00:00:00 2001 From: Jens West Date: Thu, 29 Jun 2023 12:41:45 +0300 Subject: [PATCH 5/9] Fix reference --- Scripts/helmet_validate_inputfiles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/helmet_validate_inputfiles.py b/Scripts/helmet_validate_inputfiles.py index a7ac7adb..ae96ad16 100644 --- a/Scripts/helmet_validate_inputfiles.py +++ b/Scripts/helmet_validate_inputfiles.py @@ -132,7 +132,7 @@ def main(args): } nr_transit_classes = len(param.transit_classes) nr_segment_results = len(param.segment_results) - nr_vehicle_classes = len(param.emme_demand_mtx) + 1 + nr_vehicle_classes = len(param.emme_matrices) nr_new_attr = { "nodes": nr_transit_classes * (nr_segment_results-1), "links": nr_vehicle_classes + 4, From e67fdfabf1c4f9fc2916e63085b7de89d8de045e Mon Sep 17 00:00:00 2001 From: Jens West Date: Thu, 29 Jun 2023 15:02:24 +0300 Subject: [PATCH 6/9] Remove extra attribute @walk --- Scripts/assignment/emme_assignment.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Scripts/assignment/emme_assignment.py b/Scripts/assignment/emme_assignment.py index 3932b93c..643abf52 100644 --- a/Scripts/assignment/emme_assignment.py +++ b/Scripts/assignment/emme_assignment.py @@ -385,7 +385,9 @@ def _create_attributes(self, scenario, extra): (e.g., self._extra) """ # Create link attributes - for ass_class in list(param.emme_matrices) + ["bus"]: + ass_classes = list(param.emme_matrices) + ["bus"] + ass_classes.remove("walk") + for ass_class in ass_classes: self.emme_project.create_extra_attribute( "LINK", extra(ass_class), ass_class + " volume", overwrite=True, scenario=scenario) From 108c2514c08c62b88ffa101333721e23b34bd0a2 Mon Sep 17 00:00:00 2001 From: Jens West Date: Tue, 1 Aug 2023 16:27:39 +0300 Subject: [PATCH 7/9] Fix missing transit time matrix problem --- Scripts/assignment/datatypes/transit.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Scripts/assignment/datatypes/transit.py b/Scripts/assignment/datatypes/transit.py index 9a331c73..be464a76 100644 --- a/Scripts/assignment/datatypes/transit.py +++ b/Scripts/assignment/datatypes/transit.py @@ -95,6 +95,7 @@ def __init__(self, segment_results, headway_attribute, else: jlevel1 = JourneyLevel(headway_attribute, boarded=False) jlevel2 = JourneyLevel(headway_attribute, boarded=True) + self.transit_result_spec["total_impedance"] = emme_matrices["time"] for trip_part, matrix_id in emme_matrices["total"].items(): self.transit_result_spec[trip_part] = matrix_id for trip_part, matrix_id in emme_matrices[subset].items(): From 43b598f24b422cb2ee3c6631dad7c09ee52c5332 Mon Sep 17 00:00:00 2001 From: Jens West Date: Thu, 17 Aug 2023 10:55:46 +0300 Subject: [PATCH 8/9] Fix description in matrix copying --- Scripts/assignment/emme_assignment.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Scripts/assignment/emme_assignment.py b/Scripts/assignment/emme_assignment.py index 643abf52..d73997ee 100644 --- a/Scripts/assignment/emme_assignment.py +++ b/Scripts/assignment/emme_assignment.py @@ -271,10 +271,9 @@ def calc_transit_cost(self, fares, peripheral_cost, default_cost=None): def _copy_matrix(self, mtx_type, ass_class, ass_period_1, ass_period_2): from_mtx = ass_period_1.emme_matrices[ass_class][mtx_type] to_mtx = ass_period_2.emme_matrices[ass_class][mtx_type] + description = f"{mtx_type}_{ass_class}_{ass_period_2.name}" self.emme_project.copy_matrix( - from_mtx, to_mtx, - "{}_{}_{}".format(mtx_type, ass_class, ass_period_2.name), - "{} {}".format(to_mtx["description"], ass_period_2.name)) + from_mtx, to_mtx, description, description) def _extra(self, attr): """Add prefix "@" and suffix "_vrk". From b0178115f95a0c1339f3c5cf87352f21cde7ec9b Mon Sep 17 00:00:00 2001 From: Jens West Date: Fri, 18 Aug 2023 16:02:49 +0300 Subject: [PATCH 9/9] Change matrix description for transit impedance matrices --- Scripts/assignment/emme_assignment.py | 6 +++--- Scripts/parameters/assignment.py | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Scripts/assignment/emme_assignment.py b/Scripts/assignment/emme_assignment.py index d73997ee..1314dfdb 100644 --- a/Scripts/assignment/emme_assignment.py +++ b/Scripts/assignment/emme_assignment.py @@ -364,10 +364,10 @@ def _create_matrices(self, time_period, id_hundred, id_ten): id = f"mf{id_hundred + id_ten[ass_class] + j}" matrix_ids[subset][longer_name] = id matrix_ids[longer_name] = id - description = f"{mtx_type}_{ass_class}_{tag}" self.emme_project.create_matrix( - matrix_id=id, matrix_name=description, - matrix_description=description, + matrix_id=id, + matrix_name=f"{mtx_type}_{ass_class}_{tag}", + matrix_description=longer_name, default_value=999999, overwrite=True) emme_matrices[ass_class] = matrix_ids return emme_matrices diff --git a/Scripts/parameters/assignment.py b/Scripts/parameters/assignment.py index d4610c65..7830e5b0 100644 --- a/Scripts/parameters/assignment.py +++ b/Scripts/parameters/assignment.py @@ -464,15 +464,15 @@ transit_impedance_matrices = { "total": { "total_time": "total_travel_time", - "fw_time": "actual_first_waiting_times", "tw_time": "actual_total_waiting_times", + "fw_time": "actual_first_waiting_times", }, "by_mode_subset": { - "num_board": "avg_boardings", - "board_time": "actual_total_boarding_times", - "board_cost": "actual_total_boarding_costs", "inv_time": "actual_in_vehicle_times", "aux_time": "actual_aux_transit_times", + "board_time": "actual_total_boarding_times", + "num_board": "avg_boardings", + "board_cost": "actual_total_boarding_costs", }, } background_traffic_attr = "ul3"