I am quite new to scripting for ArcGIS, so don't mind the styling and layout.
I am trying to calculate 600.000 routes by looping a network analyst route analysis. The script extracts two pointID's from a database, selects their spatial component from a feature dataset based on this pointID, calculates the route and writes it to a layer file by using an append.
When I run the file (in ArcGIS Python Window), I get an out of memory error after 400+ files. When I examine the memory-use of the process, I can see a definite build-up until 2.5GB usage until the error.
This is my code:
# step 1: centroids geographical area
arcpy.AddMessage("Performing Feature to Point")
arcpy.FeatureToPoint_management(geographicalArea, outGeographicalAreaCentroids)
arcpy.MakeFeatureLayer_management(outGeographicalAreaCentroids, outGeographicalAreaCentroidsLyr)
# step 2: create new empty feature class to append routes into
arcpy.CreateFeatureclass_management(outLocation, routesFC, "POLYLINE", templateRoute)
# step 3: go through table and perform routing for each row
cursor = arcpy.SearchCursor(dbf)
for row in cursor:
outRouteLayer = arcpy.na.MakeRouteLayer(networkDataset, outRouteLayerName, "Minutes", hierarchy = "USE_HIERARCHY")
outRouteLayer = outRouteLayer.getOutput(0)
subLayerNames = arcpy.na.GetNAClassNames(outRouteLayer)
stopsLayerName = subLayerNames["Stops"]
herkomst = row.getValue("Herkomstzo")
expression1 = "\"Z\" = %d" % herkomst
arcpy.SelectLayerByAttribute_management(outGeographicalAreaCentroidsLyr, "NEW_SELECTION", expression1)
bestemming = row.getValue("Bestemming")
expression2 = "\"Z\" = %d" % bestemming
arcpy.SelectLayerByAttribute_management(outGeographicalAreaCentroidsLyr, "ADD_TO_SELECTION", expression2)
arcpy.CopyFeatures_management(outGeographicalAreaCentroidsLyr, outGeographicalAreaCentroidsSelection)
arcpy.MakeFeatureLayer_management(outGeographicalAreaCentroidsSelection, outGeographicalAreaCentroidsSelectionLyr)
arcpy.na.AddLocations(outRouteLayer, stopsLayerName, outGeographicalAreaCentroidsSelectionLyr)
if herkomst == bestemming:
arcpy.AddMessage("Origin zone is equal to the destination zone")
else:
arcpy.na.Solve(outRouteLayer)
outputRoute = "C:\Users\Koos\Documents\Werk\Onderzoek\Data\WORKSPACE\Routes\outRouteRoutes"
arcpy.MakeFeatureLayer_management(r"route\Routes", outputRoute)
arcpy.AddField_management(outputRoute, "Orig", "DOUBLE")
arcpy.CalculateField_management(outputRoute, "Orig", herkomst)
arcpy.AddField_management(outputRoute, "Dest", "DOUBLE")
arcpy.CalculateField_management(outputRoute, "Dest", bestemming)
arcpy.Append_management(outputRoute, routesFCLocation, "NO_TEST")
# delete layers from memory
arcpy.Delete_management(outRouteLayer)
arcpy.Delete_management(herkomst)
arcpy.Delete_management(expression1)
arcpy.Delete_management(bestemming)
arcpy.Delete_management(expression2)
arcpy.Delete_management(outGeographicalAreaCentroidsSelection)
arcpy.Delete_management(outGeographicalAreaCentroidsSelectionLyr)
arcpy.Delete_management(outputRoute)
del row
del cursor
There are more steps, but they are not relevant.
I read a lot of topics about the out of memory problems and memory leaks, etc. But I can't seem to solve this problem.
First I tried to remove every file made in the proces with the arcpy.Delete_management function. This seems to drop the memory use a little bit every step, but not enough, so the memory usage still builds up. Next, I tried to run my script in PythonWin and IDLE (thinking the memory issue would maybe not occur), but then I got errors saying the spatial network analyst (solve tool) is not licensed (a whole other issue).
Are there any suggestions as to how I can solve this issue and calculate the routes? I read on one topic that it is possible to extract the code in the loop to a seperate script and then summon this script in the loop, would this be an option? And if yes, how is this done?
Edits:
For a similar 'out of memory'-problem when calculating service areas, chunking the calculation has proved a valuable solution (the memory resets after every chunk). However, this still not resolves the routing issue, since chunking the route calculation will not help. Is there a possibility to partition the loop, thus resetting the memory after every 'loop-chunk'?
Code used to check license:
class LicenseError(Exception):
pass
try:
if arcpy.CheckExtension("Spatial") == "Available":
arcpy.CheckOutExtension("Spatial")
print "Checked out \"Spatial\" Extension"
else:
raise LicenseError
except LicenseError:
print "Spatial license is unavailable"
except:
print arcpy.GetMessages(2)
Code used to determine input variables (example):
inputMap = "C://Users//Koos//Documents//Werk//Data script//Inputs"
facility = inputMap + "//Totale_opvang_Vlaanderen.shp"
geographicalArea = inputMap + "//BASISZONERING_OVL.shp"
networkDataset = inputMap + "//belbel________nw_ND.nd"
Best Answer
Couple of general suggestions. Not really a Network Analyst expert, but hopefully these apply.
Append
operation inside your looping? This is a relatively expensive operation. In the past, I've created a numpy array within a loop and then usedarcpy.da.numpyArrayToFeatureClass
to ingest all of that information at once (see my response to another question for an example).arcpy.na.Solve
operation is pretty expensive. Does this need to be solved iteratively or can it be done once all thearcpy.na.AddLocations
operations are done? For that matter, if you collect all the locations within the loop, can thearcpy.na.AddLocations
be done below the loop (could use numpy arrays, or even just a list of point geometries)?outGeographicalAreaCentroidsSelection
? Can the selection on the original feature layer be used as input toAddLocations
instead?SelectLayerByAttribute_management
operations be merged into one?