Extracting intermediate assignment results

58 views
Skip to first unread message

seriangelo agriesti

unread,
Feb 11, 2025, 3:37:06 PMFeb 11
to AequilibraE
Hello,
First of all, thank you for your work.
I am at the beginning of a new research project and am trying to find a traffic assignment simulator that allows me to extract results for each iteration of the assignment algorithm. Aequilibrae seems pretty near and, from what I read at https://www.aequilibrae.com/docs/python/V.1.1.4/traffic_assignment/traffic_assignment_validation.html, it seems like it could do the trick. Still, before learning how to set it up and use it, I would need to make sure. Is it possible to export flow and travel time values for each path and at each iteration of, for example, the Frank Wolfe assignment?

Best Regards,
Serio Agriesti

Pedro Camargo

unread,
Feb 11, 2025, 10:01:43 PMFeb 11
to AequilibraE
Hi Serio,

          The development of the original code of AequilibraE was motivated for s similar need, so AequilibraE does support saving path files (includes all paths for each class and iteration). The support is a bit clunky and could use a refresh, but it is definitely there.

I am not sure what do you mean by saving the flows at each iteration, but the algebra to obtain the flow from the path files plus the line search values is quite trivial for FW and simple enough for BFW.  Travel times at each particular iteration cannot be saved out of the box, but altering the software to obtain that result should also be trivial.

This pull request shows how to extract turn movements in post from a set of path files, for example: https://github.com/AequilibraE/aequilibrae/pull/358


Cheers,
Pedro




---- On Wed, 12 Feb 2025 06:24:29 +1000 seriangelo agriesti <seria...@gmail.com> wrote ---

--
You received this message because you are subscribed to the Google Groups "AequilibraE" group.
To unsubscribe from this group and stop receiving emails from it, send an email to aequilibrae...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/aequilibrae/ce4c6f3c-2378-4ec2-b418-7b4c73e4bf18n%40googlegroups.com.


Pedro Camargo

unread,
Feb 17, 2025, 8:20:43 PMFeb 17
to Aequilibrae
Serio,

The place to alter would be in the LinearApproximation class, somewhere around line 605.

Cheers,
Pedro



---- On Thu, 13 Feb 2025 22:30:13 +1000 seriangelo agriesti <seria...@gmail.com> wrote ---

Thank you! Is there a specific part of the code where you would suggest adding the data extraction function(s)?
Best,
Serio

Il giorno mer 12 feb 2025 alle ore 22:52 Pedro Camargo <c...@margo.co> ha scritto:

Serio,
          If it is flows you want, I would alter AequilibraE to extract that data. It would be a LOT faster and considerably easier.

Cheers,
Pedro



---- On Wed, 12 Feb 2025 20:39:30 +1000 seriangelo agriesti <seria...@gmail.com> wrote ---

Thank you for your quick reply!
Yes, I kinda misspoke, I meant obtaining the flows and travel times from each link, not path, and at each iteration. If the exported paths are loaded for each od pair, it should indeed be easy. Thank you again :) I'll give it a try!

seriangelo agriesti

unread,
Feb 18, 2025, 4:27:47 AMFeb 18
to AequilibraE
Thank you! 

seriangelo agriesti

unread,
Feb 20, 2025, 11:33:38 AMFeb 20
to AequilibraE
Hello, 
Indeed saving flows at each iteration has been simple. I also managed (I think) to save and read the paths generated through the assignment. Based on the code for turn volumes, I now run:
def read_paths_from_folder(paths_dir: Path, iteration: int) -> pd.DataFrame:
    path_file_regex = re.compile("^o([0-9]+).feather$")
    print(path_file_regex)

    files = {
        int(re.match(path_file_regex, p_file.name).groups()[0]): p_file
        for p_file in paths_dir.glob("*.feather")
        if re.match(path_file_regex, p_file.name) is not None
    }
    path_list = []
    for origin in files.keys():
        o_paths_df = pd.read_feather(paths_dir / f"o{origin}.feather")
        o_idx_paths_df = pd.read_feather(paths_dir / f"o{origin}_indexdata.feather")

        # looks like the indices dataframe is ffilled for missing destinations
        # grab destinations only from first index
        path_starts = o_idx_paths_df.reset_index().groupby("data", as_index=False).first().set_index("index")
        # looks like indices are offset by 1
        path_starts["data"] -= 1
        # only keeping destinations with indices > 0
        path_starts = path_starts[path_starts["data"] > 0].copy()

        # add info to paths df
        o_paths_df["origin_idx"] = origin
        o_paths_df.loc[path_starts["data"], "destination_idx"] = path_starts.index.values
        o_paths_df["destination_idx"] = o_paths_df["destination_idx"].bfill()

        path_list.append(o_paths_df)

    all_paths = pd.concat(path_list)
    all_paths[["network mode", "class_name", "iteration"]] = ["c", "tc_car", iteration]
    return all_paths

And I obtain a table with "data, origin_idx, destination_idx, network mode, class_name and iteration". Hoping it is not a nuisance, I have the following questions:
- What does the data column exactly represent? Also, I expected a list of links on each path, is there an additional item I should try to retrieve like o_paths_df["links"]?
- I am trying to obtain the route choice (or more precisely, the volume load on each path) at each iteration. Am I checking in the right place? Or should I try to modify/use other classes?

I hope the many questions are not a nuisance. Hopefully I am almost ready to run the experiments, as the rest of the code is set.
Thank you again :)
Best,
Serio
















Pedro Camargo

unread,
Feb 23, 2025, 8:42:01 PMFeb 23
to AequilibraE
Hi Serio,

Were you able to deduct this from the turn movement PR?

Cheers,
Pedro



---- On Fri, 21 Feb 2025 02:33:37 +1000 seriangelo agriesti <seria...@gmail.com> wrote ---

seriangelo agriesti

unread,
Feb 24, 2025, 2:53:57 AMFeb 24
to AequilibraE
Hi,
Indeed, from the turn movement discussion I could find the turn_volumes_results.py (https://github.com/ziocolaandrea/aequilibrae/blob/0a569e8fe2e11dd4be2594dbcad9fe93445ed39d/aequilibrae/paths/results/turn_volumes_results.py#L286-L299), where I found the function read_paths_from_folder(). 

Best,
Serio

seriangelo agriesti

unread,
Feb 25, 2025, 8:05:48 AMFeb 25
to AequilibraE
I thought it would be useful to visually show the results I am trying to extract (attached). This kind of reading for each iteration is what we are aiming for. 
To do so though, I need to figure out precisely where the tables that will become the feathers file are being written. My hypothesis now is that there are more entries for each od couple because Aequilibrae is already writing multiple paths, if I am correct, I then need to add volumes being assigned and list of links making up each of these paths.
paths_per_it.png

Pedro Camargo

unread,
Feb 25, 2025, 8:30:11 AMFeb 25
to AequilibraE
AequilibraE writes out a single path per class per iteration per OD.

Cheers,
Pedro



---- On Tue, 25 Feb 2025 23:05:48 +1000 seriangelo agriesti <seria...@gmail.com> wrote ---

seriangelo agriesti

unread,
Feb 25, 2025, 8:32:26 AMFeb 25
to AequilibraE
Hello Pedro, 
Thank you for your reply. I understand. Could you by chance point me to the part of the code where this happens? I am really struggling to find the specific part where the path is calculated and then written. 

Best,
Serio

Pedro Camargo

unread,
Feb 25, 2025, 5:17:41 PMFeb 25
to AequilibraE
Serio,

Chers,
Pedro




---- On Tue, 25 Feb 2025 23:32:26 +1000 seriangelo agriesti <seria...@gmail.com> wrote ---

seriangelo agriesti

unread,
Feb 26, 2025, 8:07:10 AMFeb 26
to AequilibraE
Thank you again Pedro!
Reply all
Reply to author
Forward
0 new messages