Access Closest Facilty Layer Routes in Python from the command line

2145
2
07-12-2013 02:25 PM
MathewSchmidtlein
New Contributor
Hello, all.

I've got a python code that I'm trying to get ready for use with multiprocessing (using StacyR's helpful code here).  I've got a list of roads in an area threatened by wildfire, and I'm trying to see which are the most critical to protect by seeing how many residents will loose access to critical facilities if a given road is set as non-traversable.  So, I'm running through a list of the pertinent roads (around 20,000, which is why I'm trying to get multiprocessing to work), and in each run, I set the selected road as non-traversable, solve the closest facility problem, and generate a summary statistics table to determine the number of pop who no longer have access.

The code below is the function that is called for each road in the list of 20,000.  It solves the analysis, does some calculations, generates a summary statistics table, and writes it out to a workspace.  It all works perfect if I run it as an in-process script tool in ArcMap, but when I try to run it through the command line, or not in process (out process?) through ArcMap, it fails when I try to use MakeTableView (in the 4th line) to get the information from the closest facilities layer routes.  Does anyone have any idea what could be causing this?

EDIT

I forgot to note: when it hits that line, it says path\analysis_layer.lyr\Routes does not exist (where path\analysis_layer.lyr is the path and name of the closest facility layer saved to disk), even though it just used that layer file to solve the closest facility problem in the previous line.

END EDIT

def findRoadImportance(current_road,analysis_layer,table_view,OWS):
    arcpy.UpdateAnalysisLayerAttributeParameter_na(analysis_layer, "Drop_list", "Dropped Road", current_road)
    arcpy.Solve_na(analysis_layer,"SKIP", "TERMINATE", "")
    arcpy.MakeTableView_management(analysis_layer + "\\Routes", table_view, "", "", "Name Name VISIBLE NONE;Total_Length Total_Length VISIBLE NONE")
    arcpy.DeleteRows_management(analysis_layer + "\\Routes")
    arcpy.AddField_management(table_view, "Pop", "LONG")
    arcpy.AddField_management(table_view, "PW","DOUBLE")
    arcpy.CalculateField_management(table_view, "Pop", "getPop( !Name!)", "PYTHON_9.3", "def getPop(field):\\n  return field[:field.find(\" \")]")
    arcpy.CalculateField_management(table_view,"PW", "calcMean( !Pop!, !Total_Length!)", "PYTHON_9.3", 
    "def calcMean(field1,field2):\\n  return field1 * field2")
    out_table = OWS + "\\" + str(int(current_road)) + "_result.dbf"
    arcpy.Statistics_analysis(table_view, out_table, [["Pop","SUM"],["PW","SUM"]])
    arcpy.AddField_management(out_table, "Road_ID","LONG")
    arcpy.CalculateField_management(out_table, "Road_ID", current_road)
    arcpy.AddMessage("    Output table written with drop road ID %s..."%(current_road))
    return


Also, I'm wondering if multiprocessing will actually work with this approach.  Since I'm using UpdateAnalysisLayerAttributeParameter to iteratively set roads as non-traversable in the same underlying Closest Facilities layer, can this truly be split apart between cores?  Or will the results be messed up because changes made in the underlying layer by one job will influence the results in other jobs?

Thanks for any help you all can give,

matt
Tags (2)
0 Kudos
2 Replies
MathewSchmidtlein
New Contributor
In case anyone is interested, I figured this out.  You can access the sublayers in a Network Analyst layer in a python script launched from command line using the GetNAClassNames function.

I also got the multiprocessing thing running successfully, but it keeps bailing out part way through for no apparent reason that I can figure out.  It sort of looks like one of the jobs is failing to add a field to the output table, and this ends the whole thing.  Frustrating.
0 Kudos
StacyRendall1
Occasional Contributor III
What is this line supposed to be doing?
arcpy.DeleteRows_management(analysis_layer + "\\Routes")

I am not sure that it is necessary, and it may cause other problems.

Also, you can just access Python directly in these lines, with:
    arcpy.CalculateField_management(table_view, "Pop", Name[:Name.find(\" \")])
    arcpy.CalculateField_management(table_view,"PW", Pop*Total_Length)


I am still a bit dubious as to whether or not your code will even work with multiple processes. It seems like this line:
arcpy.UpdateAnalysisLayerAttributeParameter_na(analysis_layer, "Drop_list", "Dropped Road", current_road)

makes a change to the base analysis layer that is used by all processes, not just by this function. This would definitely cause issues, such as race conditions.

I suggest that you test if it will work with Multiprocessing at all by stripping everything back and running it with just something like this (haven't tested, last line might be CopyFeatures or something else):
def findRoadImportance(current_road,analysis_layer,table_view,OWS):
    arcpy.UpdateAnalysisLayerAttributeParameter_na(analysis_layer, "Drop_list", "Dropped Road", current_road)
    arcpy.Solve_na(analysis_layer,"SKIP", "TERMINATE", "")
    arcpy.Copy_management(analysis_layer + "\\Routes", OWS + "\\" + str(int(current_road)) + "_result.shp")


Then you can manually check that the outputs are consistent with what you might expect, i.e. the dropped road is in fact missing from the routes. If you need to, just make a tiny test dataset with, say, four roads in it to test...

If it turns out that there are issues you might be able to copy the input analysis layer (and drop the roads) before the layer is passed to the function for each process.
0 Kudos