1

I am trying to write a script to iterate the process of (1) creating an OD Cost Matrix (ODCM), (2) adding origins, (3) adding destinations (same data as used in origins), (4) adding point barriers, (5) solving the ODCM, and (6) copying the resulting ODLines to a feature class in a gdb in ArcGIS 10.3.1 (with the Network Analyst extension) . The way I have it written right now, it goes through each of these six steps for each origin/destination pair. However, the point barrier layer (dams) is the same for each iteration (and it takes a while for the arcpy.AddLocations_na(outNALayer, barriersLayerName, dams, barrFieldMappings, searchTolerance) line to run, so I was wondering if there is a way to delete origin/destination locations (something like the opposite of the arcpy.AddLocations_na) so that for each iteration, I could leave the barriers layer as it is and just remove and replace the origins and destinations and run it again. I have looked through the help files and searched the internet and in here and haven't found anything that does this, but I'm hoping I have just missed it. The only way I know to remove locations is to do it from within ArcMap by right-clicking on Origins or Destinations and selecting 'Delete'.

Edit: Below is what I have so far; however, I'm still debugging it. It works if I run it line-by-line in the Python window inside ArcMap, but I'm still having some difficulty converting the resulting Lines layer to a feature class. That is probably a question for a separate topic, though.

I'm basically just trying to find out if there is a way that I don't have to repeat the steps where I create the ODCM layer initially and where point barrier locations are added by deleting the Origins and Destinations after the resulting lines layer is copied to a feature class and before it starts back at the beginning of the loop for the next species (i.e., point fc used as the Origins/Destinations).

## create ODCM layer
fcs = arcpy.ListFeatureClasses()
for fc in fcs:
    out_odcm = "ODCM_" + sp_abb
    if sepdist != None:
        cutoff = sepdist * 1000
        try:
            outNALayer = arcpy.MakeODCostMatrixLayer_na(in_network_dataset=network_ds, out_network_analysis_layer=out_odcm, impedance_attribute="Length")
        except arcpy.ExecuteError:
            for i in xrange(0, arcpy.GetMessageCount()):
                msgsCreateODCM = '{0}: {1}'.format(arcpy.GetSeverity(i), arcpy.GetMessage(i))
            log_line = "\tError making ODCM layer :" + "\n\t\t" + msgsCreateODCM + "\n\t" +  sp_abb + " skipped"
            write_log(log_file, log_line)
            print(log_line)
            continue
        log_line = "ODCM :\n" + "\tODCM layer created"
        write_log(log_file, log_line)
        print log_line
        ## get layer object from result object
        outNALayer = outNALayer.getOutput(0)

        ## get the names of all the sublayers within the OD cost matrix layer
        subLayerNames = arcpy.na.GetNAClassNames(outNALayer)

        ## store the layer names for later use
        originsLayerName = subLayerNames["Origins"]
        destinationsLayerName = subLayerNames["Destinations"]
        barriersLayerName = subLayerNames['Barriers']
        linesLayerName = subLayerNames['ODLines']

        ## load fish points as origins
        origFieldMappings = arcpy.na.NAClassFieldMappings(outNALayer, originsLayerName) # create field mapping object
        origFieldMappings['Name'].mappedFieldName = 'unique_id' # assign field mapping
        origFieldMappings['Cutoff_Length'].defaultValue = cutoff
        arcpy.AddLocations_na(outNALayer, originsLayerName, fc, origFieldMappings, searchTolerance)
        log_line = "\t" + originsLayerName +  " added" # see if can use GetCount on sublayers, and if so add to message the number of features added to each sublayer
        write_log(log_file, log_line)
        print log_line

        ## load fish points as destinations
        destFieldMappings = arcpy.na.NAClassFieldMappings(outNALayer, destinationsLayerName)
        destFieldMappings['Name'].mappedFieldName = 'unique_id'
        arcpy.AddLocations_na(outNALayer, destinationsLayerName, fc, destFieldMappings, searchTolerance)
        log_line = "\t" + destinationsLayerName + " added"
        write_log(log_file, log_line)
        print log_line

        ## load dams as barriers
        barrFieldMappings = arcpy.na.NAClassFieldMappings(outNALayer, barriersLayerName)
        barrFieldMappings['Name'].mappedFieldName = 'OBJECTID'
        arcpy.AddLocations_na(outNALayer, barriersLayerName, dams, barrFieldMappings, searchTolerance)
        log_line = "\t" + barriersLayerName + " added"
        write_log(log_file, log_line)
        print log_line

        # solve ODCM
        try:
            arcpy.na.Solve(outNALayer, ignore_invalids="SKIP") # the SKIP parameter tells the solver to skip over invalid network locations
        except arcpy.ExecuteError:
            for i in xrange(0, arcpy.GetMessageCount()):
                msgsSolveODCM = '{0}: {1}'.format(arcpy.GetSeverity(i), arcpy.GetMessage(i))
            log_line = "\tError solving the OD Cost Matrix :" + "\n\t\t" + msgsSolveODCM + "\n\t" + sp_abb + " skipped"
            write_log(log_file, log_line)
            print log_line
            continue           
        log_line = "\tODCM solved"
        write_log(log_file, log_line)
        print log_line            

        # convert ODCM NA layer to feature class
        out_ds = r"C:\Users\username\Documents\GIS_files\FoTX\EOanal.gdb\ODCM_results_fc"
        out_fc = out_ds + "\\" + sp_abb + "_fc"
        try:
            lyrs = arcpy.mapping.ListLayers(outNALayer)
            for lyr in lyrs:
                if lyr.name == 'Lines':
                    arcpy.CopyFeatures_management(linesLayerName, out_fc)
        except arcpy.ExecuteError:
            for i in xrange(0, arcpy.GetMessageCount()):
                msgsConvertToFC = '{0}: {1}'.format(arcpy.GetSeverity(i), arcpy.GetMessage(i))
            log_line = "Error converting to feature class: " + "\n" + "\tODCM line layer not converted to feature class"
            write_log(log_file, log_line)
            print log_line
            continue            
        log_line = "Convert to feature class: " + "\n" + "\tODCM line layer converted to feature class"
        write_log(log_file, log_line)
        print log_line
        del log_line, out_ds, out_fc, sp_abb
        del sepdist, cutoff, outNALayer
        del out_fc
  • 1
    Could you post your script so far? – Emil Brundage Jun 26 '17 at 22:00
  • I added the code although I know that the step in which resulting line features are converted to feature classes still needs work, but that is probably a topic for separate question. – Laura Jun 27 '17 at 18:00
1

As far as I know, you can run your analysis on a selection set as implied in this support page. That means if you populate your all possible origins and destination in a feature class with some identifiers (i.e., in a field, specify the sets, say Scenario 1 origins/destinations) and introduce them to the analysis layer as you did, you can make selections to play with the results without adding removing any network constituents.

  • Thanks for this. However, I don't want to restrict analysis to just those origins and destinations with the same IDs. I want to identify all points in the destination that are within the cutoff distance specified for the origins that don't have barriers between them. Also, this model has to be run inside ArcMap. The idea of selecting points from one main input fc is interesting; however, I think that if I tried to do this in my script, I will still have the same problem of needing to somehow delete the origins so that I can add a different selection of points for the next round. – Laura Jun 27 '17 at 17:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.