Batch Solving Many Routes

10396
23
03-14-2012 06:06 AM
ShaharLevenson
New Contributor III
Hello all,

I periodically need to calculate the shortest walking distance for over 1.8 million routes (2 points per route).
With such a large amount of routes I cannot use the desktop ArcGIS - loading that many locations isn't realistic.

What would be the best practice? Creating a python script? Using ArcObjects? Something else?

I have been doing the calculations in smaller pieces (100K, more or less) in version 9.x but now, in version 10, I want to improve the process and do it in one "chunk".

I have access to a strong workstation (20 GB RAM, 24 cores). How can I utilize all the processing potential?

I have no need for hierarchy, restrictions or preserving stop order and all I want is the distance - not the actual routes layer.

Any thoughts?

Thanks,
Shahar.
Tags (2)
23 Replies
JaySandhu
Esri Regular Contributor

Francis,

The "operation attempted on empty geometry" error message may not have anything to do with the SDE network dataset. It could be that you have run out of some computer resource (memory or disk space). 

In ArcGIS Pro, Closest Facility computes the shortest route and then generates the route geometry to write to the output Routes feature class and also generates the driving directions and writes them to the output directions feature class. It is will generate a lot of data for 2.5 million routes.

Also, for a 2.5 million to 1 case, it will be solving 2.5 million routes. At a minimum, you could flip these so that you have a 1 to 2.5 million case and switch the default "Towards Facility" to "Away from Facilities" to get the same answer but the solver will only need to do ONE route solve.

So let me ask, do you need the output route geometry and directions? Or do you simply need the shortest time/distance between these locations? If you do not need the actual route geometry, then use the Origin-Destination Cost Matrix solver. It will be much quicker with less overhead.

OD cost matrix analysis layer—ArcGIS Pro | ArcGIS Desktop 

Jay Sandhu

0 Kudos
FrancisSenyah
Occasional Contributor

Hi Jay, Very helpful.  Based on this I'm thinking it's a memory issue.  I'll switch the solve direction in the 1st instance as the geometry and directions would be helpful for quality assurance more than anything.  But if this proves inpractical - the Cost Matrix will also be suitable for us so I will give that a go next.  Many Thanks, I'll report back with anything of note.

0 Kudos
zhaojunwang
New Contributor II

Hi Jay,

Thanks for you replies.

I tried to get the distances for 36 shipping routes (36 origin ports and 36 destinations), I get a reasonable map, but only get one route solved, from port 1 to port 72. Do you know why?

Also, can CF or OD matrix do the same thing for every port pair? instead of the closest one/all the combinations between those ports, but to the designated port within each port pair?

Best,

Zhaojun

0 Kudos
JaySandhu
Esri Regular Contributor

CF and OD return routes to locations within the specified distance cutoff or number specified. They do not honor "pairs". To find routes between pairs of locations, you can either solve each pair independently OR better way is to load them into a single route but set a common ID as the ROUTENAME property. That way you can load in 72 stops as 36 route pairs and solve in one route solver. More details here:

Route analysis—Help | ArcGIS Desktop 

Jay Sandhu

0 Kudos
zhaojunwang
New Contributor II

Thanks Jay,

I tried Newroute, and set common ID for origin ports and destination ports, but the routes solved to be only 1, not 36, do you know the possible reason?

Thanks.

Best,

Zhaojun

0 Kudos
zhaojunwang
New Contributor II

And there is an error:

Warning: The output geometry for "Location 1 - Location 86" in "Routes" has no M values because the maximum M value is larger than the largest M value that can be supported by the M domain.

0 Kudos
JohnFix2
New Contributor III

I could use some help on the python above. I am being asked to run 2000 routes from an input file and record info about each trip. The above appears to be exactly what I need....but.....the script fails around:

rows = arcpy.SearchCursor(lyrName + "\\Routes")

I think this occurs this "lyrName" is actually set at "layer1" further up in the script. But when I make such an adjustment it still fails. Seems the field "row.Total_TravelTime" does not exists in the array.

BTW, when I step through this script, I can load stops and solve the route. I just can't figure out how to get the results back out so I can write out.

Any help offered to get this to work, and run a batch of routes would be greatly appreciated!

Thanks.

John

ArcGIS 10.6.1

0 Kudos
MelindaMorang
Esri Regular Contributor

First, I encourage you to use arcpy.da.SearchCursor instead of the old arcpy.SearchCursor, which is deprecated and slow.

SearchCursor—Help | Documentation 

With arcpy.da.SearchCursor, you specify explicitly which fields you want to retrieve from the data.

for row in arcpy.da.SearchCursor(<your layer>, [python list of field names]):
print(row)

The field name to retrieve depends on your network dataset and the output you care about.  In the example script you're looking at, I guess the impedance attribute being used for the analysis was called "TravelTime", so the output field in the output routes sublayer was "Total_TravelTime".  Basically you need to retrieve a field called "Total_[name of impedance attribute]".

Let's say you solved using an impedance attribute called TravelTime.  Then do this:

for row in arcpy.da.SearchCursor(<your layer>, ["Total_TravelTime"]):
print(row[0])

Let's say you additionally accumulated a field called "Miles".  Then you can also do this:

for row in arcpy.da.SearchCursor(<your layer>, ["Total_TravelTime", "Total_Miles"]):
travel_time = row[0]
travel_distance = row[1]

An explanation of all input and output fields for a Route analysis is here: Route analysis—Help | Documentation 

0 Kudos
JohnFix2
New Contributor III

Melinda,

Thank you! This is exactly what I needed. Now I can get the routes' total miles and total minutes into variables and write to an output file. Whoot!

John

layer1 = "MyRouteLayer" #an open in-memory layer  

for row in arcpy.da.SearchCursor(layer1 + "\\Routes", ["Total_Minutes", "Total_Miles"]):
     travel_minutes = row[0]
     travel_miles = row[1]

print travel_miles

0 Kudos
ShaharLevenson
New Contributor III
Hello Anna,

Thank you very much! I changed a few lines in the code and it works.  🙂
I'm learning now how to run it outside of ArcMap, as you suggested.

A question:
Since I have many routes, there may be a case in which a route between two points isn't possible.
How can I make the code "skip" the problematic route instead of stopping with an exception?
0 Kudos