-
-
Notifications
You must be signed in to change notification settings - Fork 39
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
extract turning movements #358
base: develop
Are you sure you want to change the base?
Conversation
- improving reading iterations
- improved creation of index for final turn movement df
- using aequilibrae project to retrieve required data
back up to speed
# Conflicts: # aequilibrae/paths/traffic_assignment.py
diff --git a/aequilibrae/paths/results/__init__.py b/aequilibrae/paths/results/__init__.py
index c7ac6c4..3fb353c 100644
--- a/aequilibrae/paths/results/__init__.py
+++ b/aequilibrae/paths/results/__init__.py
@@ -14,3 +14,4 @@ __date__ = "$Date: 2016-07-02$"
from .assignment_results import AssignmentResults
from .path_results import PathResults
from .skim_results import SkimResults
+from .turn_volumes_results import TurnVolumesResults
--
2.40.0 |
def turning_volumes( | ||
self, | ||
turns_df: pd.DataFrame, | ||
classes: Optional[list[str]] = None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This type hint indicates that a str
is ok, but the TurnVolumesResults.from_traffic_class
expects a traffic class object
- classes: Optional[list[str]] = None,
+ classes: Optional[list[TrafficClass]] = None,
Thank you both for your work on this. I've been attempting to get a mwe with the def get_turns_ods(
self, turns_w_links: pd.DataFrame, formatted_paths: pd.DataFrame, node_to_index_df
) -> pd.DataFrame:
index_to_node = node_to_index_df.reset_index()
turns_w_od_idx = formatted_paths.merge(turns_w_links, on=["id", "id_next"])
turns_w_od = turns_w_od_idx.merge(index_to_node, left_on="origin_idx", right_on="node_index", how="left").merge(
index_to_node,
left_on="destination_idx",
right_on="node_index",
how="left",
suffixes=("_origin", "_destination"),
)
turns_w_od.rename(columns={"index_origin": "origin", "index_destination": "destination"}, inplace=True)
return turns_w_od[TURNING_VOLUME_OD_COLUMNS] The line This dataframe is also indexed by entirely ones? Additionally should the Heres the setup code I am working with, from os.path import join
import pandas as pd
from aequilibrae.project import Project
from aequilibrae.paths import TurnVolumesResults
from aequilibrae.paths.traffic_assignment import TrafficAssignment, TrafficClass
from aequilibrae.matrix import AequilibraeData, AequilibraeMatrix
fldr = './models/sioux_falls_2020_02_15/'
dt_fldr = '0_tntp_data'
prj_fldr = '1_project'
project = Project()
project.load(join(fldr, prj_fldr))
# project.load(fldr)
project.network.build_graphs()
graph = project.network.graphs['c']
assig = TrafficAssignment()
# Creates the assignment class
demand = AequilibraeMatrix()
demand.load(join(fldr, dt_fldr, 'demand.omx'))
#demand = project.matrices.get_matrix("demand_omx")
demand.computational_view(["matrix"])
assigclass = TrafficClass("car", graph, demand)
# The first thing to do is to add at list of traffic classes to be assigned
assig.set_classes([assigclass])
assig.set_vdf("BPR") # This is not case-sensitive # Then we set the volume delay function
assig.set_vdf_parameters({"alpha": "b", "beta": "power"}) # And its parameters
assig.set_capacity_field("capacity") # The capacity and free flow travel times as they exist in the graph
assig.set_time_field("distance")
# And the algorithm we want to use to assign
assig.set_algorithm('bfw')
# since I haven't checked the parameters file, let's make sure convergence criteria is good
assig.max_iter = 2
assig.rgap_target = 0.00001
assig.set_save_path_files(True)
assig.execute() # we then execute the assignment
turn_abc = pd.DataFrame(
[
[1, 2, 3],
[4, 5, 6],
],
columns=["a", "b", "c"]
)
turning_volumes = assig.turning_volumes(turn_abc, classes=[assigclass]) |
Thanks Jake,I’ll have a look over the weekend.Cheers,AndreaOn 28 Apr 2023, at 15:15, Jake Moss ***@***.***> wrote:
Thank you both for your work on this. I've been attempting to get a mwe with the sioux_falls_2020_02_15, and just running into a few issues.
https://github.com/ziocolaandrea/aequilibrae/blob/0a569e8fe2e11dd4be2594dbcad9fe93445ed39d/aequilibrae/paths/results/turn_volumes_results.py#L286-L299
def get_turns_ods(
self, turns_w_links: pd.DataFrame, formatted_paths: pd.DataFrame, node_to_index_df
) -> pd.DataFrame:
index_to_node = node_to_index_df.reset_index()
turns_w_od_idx = formatted_paths.merge(turns_w_links, on=["id", "id_next"])
turns_w_od = turns_w_od_idx.merge(index_to_node, left_on="origin_idx", right_on="node_index", how="left").merge(
index_to_node,
left_on="destination_idx",
right_on="node_index",
how="left",
suffixes=("_origin", "_destination"),
)
turns_w_od.rename(columns={"index_origin": "origin", "index_destination": "destination"}, inplace=True)
return turns_w_od[TURNING_VOLUME_OD_COLUMNS]
The line turns_w_od_idx = formatted_paths.merge(turns_w_links, on=["id", "id_next"]) seems to be creating an empty Dataframe which is causing issues later on. Both Dataframes that are being merged are non-empty and have the required columns however there is no 11 or 11.0 entry in formatted_paths.id_next
This dataframe is also indexed by entirely ones? Additionally should the destination_idx and id_next columns be floating points?
Heres the setup code I am working with, sioux_falls_2020_02_15 refers to the example project available at https://www.aequilibrae.com/python/latest/usageexamples.html#sample-data
from os.path import join
import pandas as pd
from aequilibrae.project import Project
from aequilibrae.paths import TurnVolumesResults
from aequilibrae.paths.traffic_assignment import TrafficAssignment, TrafficClass
from aequilibrae.matrix import AequilibraeData, AequilibraeMatrix
fldr = './models/sioux_falls_2020_02_15/'
dt_fldr = '0_tntp_data'
prj_fldr = '1_project'
project = Project()
project.load(join(fldr, prj_fldr))
# project.load(fldr)
project.network.build_graphs()
graph = project.network.graphs['c']
assig = TrafficAssignment()
# Creates the assignment class
demand = AequilibraeMatrix()
demand.load(join(fldr, dt_fldr, 'demand.omx'))
#demand = project.matrices.get_matrix("demand_omx")
demand.computational_view(["matrix"])
assigclass = TrafficClass("car", graph, demand)
# The first thing to do is to add at list of traffic classes to be assigned
assig.set_classes([assigclass])
assig.set_vdf("BPR") # This is not case-sensitive # Then we set the volume delay function
assig.set_vdf_parameters({"alpha": "b", "beta": "power"}) # And its parameters
assig.set_capacity_field("capacity") # The capacity and free flow travel times as they exist in the graph
assig.set_time_field("distance")
# And the algorithm we want to use to assign
assig.set_algorithm('bfw')
# since I haven't checked the parameters file, let's make sure convergence criteria is good
assig.max_iter = 2
assig.rgap_target = 0.00001
assig.set_save_path_files(True)
assig.execute() # we then execute the assignment
turn_abc = pd.DataFrame(
[
[1, 2, 3],
[4, 5, 6],
],
columns=["a", "b", "c"]
)
turning_volumes = assig.turning_volumes(turn_abc, classes=[assigclass])
—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you authored the thread.Message ID: ***@***.***>
|
Hi Jake,
I introduced some warnings (not errors) so that the process continues to the end for valid turns. For case scenario 2, I'm removing the turns from the DataFrame, however another solution could be to have a record with 0 volume. It looks like I can't solve the conflicts in the documentation. Could you or Pedro help? I looks like the project you used was created with an older version and I couldn't get it to run. However, I had another Sioux Falls project with a consistent network as yours. Cheers, |
@Jake-Moss just checking if you saw my last commits that should solve the issues you found. |
Hi Andrea, very sorry for the delay, I have seen your changes (thank you) and I've been meaning to meet with @pedrocamargo to discuss these changes. I'll try to schedule something today. As for the merge conflicts we'll be able to resolve those manually |
class TestTurnVolumes(TestCase): | ||
def setUp(self) -> None: | ||
ensure_spatialite_binaries() | ||
os.environ["PATH"] = os.path.join(gettempdir(), "temp_data") + ";" + os.environ["PATH"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably not needed after ensure_spatialite_binaries()
self.assignment.set_save_path_files(True) | ||
self.assignment.execute() | ||
turning_movements = self.assignment.turning_volumes(TURNS_DF) | ||
self.assertEqual(turning_movements.at[0, "volume"], 150) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All test results seem to indicate the same values, which maybe tells me that not everything is being tested. Is this assignment converging after 1 iteration and that's why the results are like this? Maybe we need something with a minimum of congestion to show that it picks up the right results
Hi Andrea, I've constructed another demo script based on the tests you've implemented but I've not sure what going wrong here, could you please take a look? It doesn't seem to be converging, but ignoring that the import zipfile
import os
import pandas as pd
from aequilibrae.project import Project
from aequilibrae.utils import create_example
from aequilibrae.paths import TurnVolumesResults
from aequilibrae.paths.traffic_assignment import TrafficAssignment, TrafficClass
from aequilibrae.matrix import AequilibraeData, AequilibraeMatrix
import numpy as np
from tempfile import gettempdir
import uuid
def _create_assign_matrix():
zones = 24
mat_file = join(gettempdir(), f"Aequilibrae_matrix_{uuid.uuid4()}.aem")
args = {
"file_name": mat_file,
"zones": zones,
"matrix_names": ["mat1", "mat2"],
"index_names": ["my_indices"],
"memory_only": False,
}
matrix = AequilibraeMatrix()
matrix.create_empty(**args)
trips = np.zeros((zones, zones))
trips[0, 5] = 100
trips[0, 7] = 50
matrix.index[:] = np.arange(matrix.zones) + 1
matrix.matrices[:, :, 0] = trips
matrix.matrices[:, :, 1] = matrix.mat1 * 2
matrix.setName("test_turn_volumes")
matrix.setDescription("test turn movements")
matrix.matrix_hash = {zone: idx for idx, zone in enumerate(np.arange(matrix.zones) + 1)}
return matrix
proj_path = os.path.join(gettempdir(), "test_traffic_assignment_path_files" + uuid.uuid4().hex)
os.mkdir(proj_path)
zipfile.ZipFile("/home/jake/Software/aequilibrae/tests/data/sioux_falls_single_class.zip").extractall(proj_path)
project = Project()
project.load(proj_path)
project.network.build_graphs()
graph = project.network.graphs['c']
assig = TrafficAssignment()
matrix_1 = _create_assign_matrix()
matrix_1.computational_view(["mat1"])
matrix_2 = _create_assign_matrix()
matrix_2.computational_view(["mat2"])
assigclass_1 = TrafficClass("car", graph, matrix_1)
assigclass_2 = TrafficClass("truck", graph, matrix_2)
assig.set_classes([assigclass_1, assigclass_2])
assig.set_vdf("BPR")
assig.set_vdf_parameters({"alpha": "b", "beta": "power"})
assig.set_capacity_field("capacity")
assig.set_time_field("free_flow_time")
assig.set_algorithm('bfw')
assig.max_iter = 5
assig.rgap_target = 0.001
assig.set_save_path_files(True)
assig.execute() # we then execute the assignment
assig.save_results("demo")
turn_abc = pd.DataFrame([[1, 2, 6]], columns=["a", "b", "c"])
turning_volumes = assig.turning_volumes(turn_abc)
class_to_matrix = {
"car": matrix_1,
"truck": matrix_2
}
turning_movements = TurnVolumesResults.calculate_from_result_table(
project=project,
turns_df=turn_abc,
asgn_result_table_name="demo",
class_to_matrix=class_to_matrix,
) |
Hi @Jake-Moss, thank you for looking into this again. @pedrocamargo I'll look into improving the bfw test |
@pedrocamargo @Jake-Moss I've improved the test by building a matrix with 0 trips to and from centroid 2. This way the turning volumes for turn 1,2,6 should be the same as the volumes on links 1-2 and 2-6. |
@Jake-Moss @pedrocamargo thank you very much for your reviews. There was indeed an error in how the volume by iteration was calculated. Thanks again! |
No description provided.